pax_global_header00006660000000000000000000000064144507554550014530gustar00rootroot0000000000000052 comment=255fe6b2d26cef4e89ea64d931dd738bea8f8624 java-algebra-system-2.7.200/000077500000000000000000000000001445075545500155365ustar00rootroot00000000000000java-algebra-system-2.7.200/.gitattributes000066400000000000000000000000151445075545500204250ustar00rootroot00000000000000README ident java-algebra-system-2.7.200/.gitignore000066400000000000000000000005221445075545500175250ustar00rootroot00000000000000/*.class /*.old /*.orig /*.jar /*.tar /*.gz /*.tgz /*.out /*.out* /*.jad /*.txt /*.log /edu /source /classes /DTD /application /arith /kern /module /poly /ring /structure /ufd /util /vector /test /temp /ps /NOTES* *~ all_jruby.sh all_jython.sh jython/classes/ jython/jsr.out doc/git_change.log .jython_cache/ versuch* jacoco.exec report/ java-algebra-system-2.7.200/COPYING000066400000000000000000000430761445075545500166030ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. java-algebra-system-2.7.200/COPYING.jas000066400000000000000000000445321445075545500173550ustar00rootroot00000000000000 This is the Java Computer Algebra System (JAS) Copyright (C) 2000-2023, Heinz Kredel See Java Algebra System at http://krum.rz.uni-mannheim.de/jas/. 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 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. java-algebra-system-2.7.200/COPYING.lgpl000066400000000000000000000635001445075545500175320ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! java-algebra-system-2.7.200/COPYING.lgpl.jas000066400000000000000000000652041445075545500203110ustar00rootroot00000000000000 This is the Java Computer Algebra System (JAS) Copyright (C) 2000-2023, Heinz Kredel See Java Algebra System at http://krum.rz.uni-mannheim.de/jas/. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! java-algebra-system-2.7.200/GBManifest.MF000066400000000000000000000004711445075545500177430ustar00rootroot00000000000000Manifest-Version: 1.0 Class-Path: lib/log4j-core-2.17.1.jar lib/log4j-api-2.17.1.jar lib/junit-4.13.1.jar lib/hamcrest-core-1.3.jar Main-Class: edu.jas.application.RunGB Implementation-Vendor: JAS Implementation-Title: Java Algebra System Implementation-Version: 2.7 Implementation-Vendor-Id: java-algebra-system java-algebra-system-2.7.200/Makefile000066400000000000000000000513231445075545500172020ustar00rootroot00000000000000# # $Id$ # # Makefile with default rules for the Java-Algebra-System # by Heinz kredel # # created 2.6.2000 hk # modified 1.1.2003 hk # todo # set this to your jdk binaries path #JDK=/usr/lib/jvm/java/bin #JDK=/usr/java/jdk1.6.0_02/bin #JDK=/usr/lib/java/bin #JDK=/usr/java/latest/bin JDK=/usr/lib64/jvm/java/bin #JDK=/usr/lib/jvm/java-1.5.0-sun-1.5.0/bin #JASPATH=$(HOME)/jas SVNREPO=/home/SUBVERSION LIBPATH=$(HOME)/java/lib #JUNITPATH=$(LIBPATH)/junit.jar JUNITPATH=$(LIBPATH)/junit-4.13.1.jar:$(LIBPATH)/hamcrest-core-1.3.jar #LOG4JPATH=$(LIBPATH)/log4j-1.2.17.jar #LOG4JPATH=$(LIBPATH)/log4j-core-2.5.jar:$(LIBPATH)/log4j-api-2.5.jar:$(LIBPATH)/log4j-1.2-api-2.5.jar LOG4JPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar #LOG4JPATH=$(LIBPATH)/mylog.jar #LOG4JPATH=$(LIBPATH)/nolog.jar JOMPPATH=$(LIBPATH)/jomp1.0b.jar TNJPATH=$(LIBPATH)/tnj.jar LINTPATH=$(LIBPATH)/lint4j.jar PYPATH=$(LIBPATH)/jython.jar # --- syncing ---------- DRY=--dry-run DELETE= RSYNC=rsync -e ssh -avuz $(DRY) $(DELETE) --exclude=*~ --include=doc/git_change.log --include=jdepend-report.txt --exclude=*.log* --exclude=*.out* --exclude=*.txt* --exclude=.svn --exclude=build/ --exclude=target/ --exclude=reports/ --exclude=.gradle/ --exclude=*.exec ####--exclude=./test ####--exclude=*.ps --exclude=*.pdf --exclude=spin* ####--exclude=*/.jxta/ PART=jas.j18 VERSION=jas-2.7 DEBVERSION=jas-java_2.7 #SVNVERSION=`grep committed-rev .svn/entries |head -1|awk -F = '{ print $2 }'|sed 's/"//g'` all: usage home: $(RSYNC) krum:java/$(PART)/ . heinz: $(RSYNC) ./ heinz@heinz2:$(PART) krum: $(RSYNC) -e 'ssh' ./ krum:java/$(PART) pub: $(RSYNC) --exclude=*ufd* --exclude=DTD --exclude=lisa* --exclude=*xml ./ krum:htdocs/$(PART) compute: $(RSYNC) ./ compute:java/$(VERSION) # --- end syncing ---------- # no need to change below this line # command line arguments, cl is deprecated, use args cl= args=$(cl) #.EXPORT_ALL_VARIABLES : #DEFS=$(JASPATH)/arith:$(JASPATH)/poly:$(JASPATH)/ps:$(JASPATH)/vector:$(JASPATH)/gb:$(JASPATH)/ufd:$(JASPATH)/gbmod:$(JASPATH)/util:$(JASPATH)/application:$(JASPATH)/root DOCCLASSES=$(JUNITPATH):$(LOG4JPATH):$(JOMPPATH) #:$(TNJPATH) #DOCOPTS=-package #DOCOPTS=-package -version -author DOCOPTS=-public -protected -package -author -version #MYCLASSPATH = .:$(DEFS):$(JUNITPATH):$(JOMPPATH) #MYCLASSPATH = $(LOG4JPATH):.:$(DEFS):$(JUNITPATH):$(JOMPPATH):$(PYPATH) MYCLASSPATH = $(LOG4JPATH):.:$(JUNITPATH):$(JOMPPATH):$(PYPATH) #:$(TNJPATH) #JAVA_MEM=-Xms1500M -Xmx2900M #JAVA_MEM=-Xms800M -Xmx1500M JAVA_MEM= #SOPTS="-J-cp ../lib/log4j-core-2.5.jar:../lib/log4j-api-2.5.jar:../lib/junit.jar-4.13.1.jar:../lib/hamcrest-core-1.3.jar:. -J-verbose:gc -J-Xms500M -J-Xmx900M" SOPTS="-J-cp ../lib/log4j-core-2.17.1.jar:../lib/log4j-api-2.17.1.jar:../lib/junit.jar-4.13.1.jar:../lib/hamcrest-core-1.3.jar:. " #SOPTS="-J-verbose:gc -J-Xms1500M -J-Xmx2900M" #SOPTS="-J-verbose:gc -J-Xms500M -J-Xmx900M" JAVAC=$(JDK)/javac -classpath $(MYCLASSPATH) -d . -Xlint:unchecked # -verbose:class #-Djava.util.logging.config.file=logging.properties #JAVA=$(JDK)/java -classpath $(MYCLASSPATH) -verbose:gc JAVA=$(JDK)/java -classpath $(MYCLASSPATH) -server $(JAVA_MEM) -XX:+AggressiveHeap -XX:+UseParallelGC -XX:ParallelGCThreads=2 -verbose:gc #-Xrunhprof:cpu=samples,heap=sites,force=n #-Xbatch #JAVA=$(JDK)/java -classpath $(MYCLASSPATH) -verbose:gc -Xrunhprof:cpu=times,format=a #JAVA=$(JDK)/java -classpath $(MYCLASSPATH) -verbose:gc -verbose:class -verbose:jni DOC=$(JDK)/javadoc -classpath $(DOCCLASSES) usage: echo; echo "usage: make args='cmd'"; echo FIX = fixm2j GETC = getc.pl #JOPT = -prof:gb.prof -tm #-mx100000000 .SUFFIXES : .SUFFIXES : .class .java .PRECIOUS : %.java %.class edu/jas/arith/%.class edu/jas/poly/%.class edu/jas/ps/%.class edu/jas/gb/%.class edu/jas/vector/%.class edu/jas/ufd/%.class edu/jas/fd/%.class edu/jas/gbmod/%.class edu/jas/structure/%.class edu/jas/util/%.class edu/jas/application/%.class edu/jas/kern/%.class edu/jas/root/%.class edu/jas/%.class .PHONY : clean doc all: $(JAVAC) src/edu/jas/*/*.java src/edu/mas/*/*.java trc/edu/jas/*/*.java trc/edu/mas/*/*.java %.class: %.java $(JAVAC) $< edu/jas/%.class: src/edu/jas/%.java $(JAVAC) $< edu/jas/arith/%Test.class: trc/edu/jas/arith/%Test.java $(JAVAC) $< edu/jas/arith/%.class: src/edu/jas/arith/%.java $(JAVAC) $< edu/jas/poly/%Test.class: trc/edu/jas/poly/%Test.java $(JAVAC) $< edu/jas/poly/%.class: src/edu/jas/poly/%.java $(JAVAC) $< edu/jas/ps/%Test.class: trc/edu/jas/ps/%Test.java $(JAVAC) $< edu/jas/ps/%.class: src/edu/jas/ps/%.java $(JAVAC) $< edu/jas/gb/%Test.class: trc/edu/jas/gb/%Test.java $(JAVAC) $< edu/jas/gb/%.class: src/edu/jas/gb/%.java $(JAVAC) $< edu/jas/ufd/%Test.class: trc/edu/jas/ufd/%Test.java $(JAVAC) $< edu/jas/ufd/%.class: src/edu/jas/ufd/%.java $(JAVAC) $< edu/jas/fd/%Test.class: trc/edu/jas/fd/%Test.java $(JAVAC) $< edu/jas/fd/%.class: src/edu/jas/fd/%.java $(JAVAC) $< edu/jas/vector/%Test.class: trc/edu/jas/vector/%Test.java $(JAVAC) $< edu/jas/vector/%.class: src/edu/jas/vector/%.java $(JAVAC) $< edu/jas/gbmod/%Test.class: trc/edu/jas/gbmod/%Test.java $(JAVAC) $< edu/jas/gbmod/%.class: src/edu/jas/gbmod/%.java $(JAVAC) $< edu/jas/gbufd/%Test.class: trc/edu/jas/gbufd/%Test.java $(JAVAC) $< edu/jas/gbufd/%.class: src/edu/jas/gbufd/%.java $(JAVAC) $< edu/jas/structure/%Test.class: trc/edu/jas/structure/%Test.java $(JAVAC) $< edu/jas/structure/%.class: src/edu/jas/structure/%.java $(JAVAC) $< edu/jas/util/%Test.class: trc/edu/jas/util/%Test.java $(JAVAC) $< edu/jas/util/%.class: src/edu/jas/util/%.java $(JAVAC) $< edu/jas/application/%Test.class: trc/edu/jas/application/%Test.java $(JAVAC) $< edu/jas/application/%.class: src/edu/jas/application/%.java $(JAVAC) $< edu/jas/root/%Test.class: trc/edu/jas/root/%Test.java $(JAVAC) $< edu/jas/root/%.class: src/edu/jas/root/%.java $(JAVAC) $< edu/jas/kern/%Test.class: trc/edu/jas/kern/%Test.java $(JAVAC) $< edu/jas/kern/%.class: src/edu/jas/kern/%.java $(JAVAC) $< edu/jas/integrate/%Test.class: trc/edu/jas/integrate/%Test.java $(JAVAC) $< edu/jas/integrate/%.class: src/edu/jas/integrate/%.java $(JAVAC) $< edu/mas/kern/%Test.class: trc/edu/mas/kern/%Test.java $(JAVAC) $< edu/mas/kern/%.class: src/edu/mas/kern/%.java $(JAVAC) $< edu.jas.%: edu/jas/%.class $(JAVA) $@ $(args) edu.jas.arith.%: edu/jas/arith/%.class $(JAVA) $@ $(args) edu.jas.poly.%: edu/jas/poly/%.class $(JAVA) $@ $(args) edu.jas.ps.%: edu/jas/ps/%.class $(JAVA) $@ $(args) edu.jas.gb.%: edu/jas/gb/%.class $(JAVA) $@ $(args) edu.jas.ufd.%: edu/jas/ufd/%.class $(JAVA) $@ $(args) edu.jas.fd.%: edu/jas/fd/%.class $(JAVA) $@ $(args) edu.jas.gbufd.%: edu/jas/gbufd/%.class $(JAVA) $@ $(args) edu.jas.vector.%: edu/jas/vector/%.class $(JAVA) $@ $(args) edu.jas.gbmod.%: edu/jas/gbmod/%.class $(JAVA) $@ $(args) edu.jas.structure.%: edu/jas/structure/%.class $(JAVA) $@ $(args) edu.jas.util.%: edu/jas/util/%.class $(JAVA) $@ $(args) edu.jas.application.%: edu/jas/application/%.class $(JAVA) $@ $(args) edu.jas.root.%: edu/jas/root/%.class $(JAVA) $@ $(args) edu.jas.kern.%: edu/jas/kern/%.class $(JAVA) $@ $(args) edu.jas.integrate.%: edu/jas/integrate/%.class $(JAVA) $@ $(args) edu.mas.kern.%: edu/mas/kern/%.class $(JAVA) $@ $(args) FILES=$(wildcard src/edu/jas/structure/*.java src/edu/jas/arith/*.java src/edu/jas/poly/*.java src/edu/jas/ps/*.java src/edu/jas/gb/*.java src/edu/jas/application/*.java src/edu/jas/vector/*.java src/edu/jas/gbmod/*.java src/edu/jas/gbufd/*.java src/edu/jas/util/*.java src/edu/jas/ufd/*.java src/edu/jas/fd/*.java src/edu/jas/kern/*.java src/edu/jas/root/*.java src/edu/jas/integrate/*.java) TESTFILES=$(wildcard trc/edu/jas/structure/*.java trc/edu/jas/arith/*.java trc/edu/jas/poly/*.java trc/edu/jas/ps/*.java trc/edu/jas/gb/*.java trc/edu/jas/application/*.java trc/edu/jas/vector/*.java trc/edu/jas/gbmod/*.java trc/edu/jas/gbufd/*.java trc/edu/jas/util/*.java trc/edu/jas/ufd/*.java trc/edu/jas/fd/*.java trc/edu/jas/kern/*.java trc/edu/jas/root/*.java trc/edu/jas/integrate/*.java) LIBS=$(subst :,, $(JUNITPATH)) $(subst :,, $(LOG4JPATH)) $(JOMPPATH) $(TNJPATH) CLASSES=edu/jas/structure/ edu/jas/arith/ edu/jas/poly/ edu/jas/ps/ edu/jas/gb/ edu/jas/gbufd edu/jas/application/ edu/jas/vector/ edu/jas/gbmod/ edu/jas/util/ edu/jas/ufd/ edu/jas/fd/ edu/jas/kern/ edu/jas/root/ edu/jas/integrate/ PYS=$(wildcard *.py) EXAMPY=$(wildcard examples/*.py) EXAMRB=$(wildcard examples/*.rb) EXAMJAS=$(subst examples/,, $(wildcard examples/*.jas)) DOCU=$(wildcard doc/jas-log.html index.html doc/problems.html doc/design.html COPYING* sample.jythonrc doc/overview.html) # */package.html doc: $(FILES) $(TESTFILES) $(DOC) $(DOCOPTS) -d doc/api $(FILES) $(TESTFILES) epydoc: examples/jas.py # epydoc -o doc/jython -n "Python to JAS" -u ../../index.html `find examples -name "*.py"|grep -v versuch` # --exclude-parse=java.lang --exclude-parse=com.xhaus.jyson epydoc --check -o doc/jython -n "Python to JAS" -u ../../index.html examples/jas.py examples/basic_sigbased_gb.py examples/sdjas.py rdoc: examples/jas.rb jrdoc -o doc/jruby -C -U -N -t "Ruby to JAS" examples/jas.rb examples/sdjas.rb texdoc: $(FILES) $(TESTFILES) mkdir -p doc/tex rm -f doc/tex/* $(DOC) $(DOCOPTS) -doclet TexGen -docletpath ~/java/lib/texgen.jar -dest doc/tex $(FILES) $(TESTFILES) ls doc/tex/* | grep -v Test | grep -v allclasses | xargs cat > doc/tex/allclasses.tex sed -i -f doc/totex.sed doc/tex/allclasses.tex cd doc; pdflatex jas_texgen.tex ALLJAR=$(FILES) $(TESTFILES) $(DOCU) Makefile build.xml $(PYS) #log4j2.properties jas-all.jar: $(ALLJAR) $(JDK)/jar -cvf jas.jar $(ALLJAR) edu/ cp jas.jar $(LIBPATH)/ mv jas.jar /tmp/jas-`date +%Y%j`.jar jas.tgz: $(FILES) $(TESTFILES) *.html doc/*.html doc/TODO README tar -cvzf jas.tgz $(FILES) $(TESTFILES) *.html doc/*.html doc/TODO README cp jas.tgz /tmp/jas-`date +%Y%j`.tgz # cp jas.jar ...../jas-`date +%Y%j`.jar #jas-run.jar: GBManifest.MF $(TOJAR) # $(JDK)/jar -cvfm jas-run.jar GBManifest.MF $(TOJAR) TOJAR=$(FILES) $(TESTFILES) $(CLASSES) Makefile build.xml $(EXAMPY) examples/machines.test $(wildcard COPYING*) #log4j2.properties jas.jar: $(FILES) $(TESTFILES) Makefile build.xml $(EXAMPY) #log4j2.properties $(JDK)/jar -cf jas.jar $(TOJAR) cp jas.jar $(LIBPATH)/ # $(JDK)/jar -cf jas.jar $(filter-out %/ufd/, $(filter-out src/edu/jas/ufd/%.java, $(TOJAR))) jas-doc.jar: $(DOCU) doc/ $(JDK)/jar -cvf jas-doc.jar $(DOCU) doc/ dist: jas.jar jas-run.jar jas-doc.jar $(LIBS) tar -cvzf jas-dist.tgz jas.jar jas-run.jar jas-doc.jar $(LIBS) # jars: jas-run.jar jas-doc.jar #jars: jas.jar jas-run.jar jas-doc.jar lint: $(JDK)/java -jar $(LINTPATH) -v 3 -classpath $(DOCCLASSES):jas.jar -sourcepath src edu.jas.* # $(JDK)/java -jar $(LINTPATH) -v 5 -exact -classpath $(DOCCLASSES) -sourcepath src edu.jas.* clean: find . -name "*~" -follow -print -exec rm {} \; #rm -f application/application arith/arith kern/kern gbmod/gbmod poly/poly ps/ps gb/gb structure/structure ufd/ufd util/util vector/vector testp: find examples -name "*.py"|grep -v jas.py |grep -v sdexam.py |grep -v plot|grep -v versuch|sort|xargs -L 1 echo "time jython $(SOPTS)" | awk '{ printf "echo %s\n", $$0; printf "%s\n", $$0 }' > ./all_jython.sh time bash -i all_jython.sh 2>&1 | tee tjy.out -egrep '(Error|ERROR|File|Exception)' tjy.out testr: find examples -name "*.rb"|grep -v jas.rb |grep -v sdexam.rb |grep -v versuch|sort|xargs -L 1 echo "time jruby $(SOPTS) -I." | awk '{ printf "echo %s\n", $$0; printf "%s\n", $$0 }' > ./all_jruby.sh time bash -i ./all_jruby.sh 2>&1 | tee tjr.out -egrep -i '(error|__file__|exception|failed)' tjr.out tests: ant test 2>&1 | tee t.out ant exam 2>&1 | tee e.out make edu.jas.application.RunGB cl="seq examples/trinks6.jas" 2>&1 | tee tr.out make edu.jas.application.RunGB cl="seq+ examples/trinks6.jas" 2>&1 | tee -a tr.out make edu.jas.application.RunGB cl="par examples/trinks6.jas 4" 2>&1 | tee -a tr.out make edu.jas.application.RunGB cl="par+ examples/trinks6.jas 4" 2>&1 | tee -a tr.out cd jython; make tests 2>&1 | tee jsr.out cd jython; make exam 2>&1 | tee -a jsr.out cd mpj; make tests 2>&1 | tee mpj.out #cd mpi; make tests 2>&1 | tee mpi.out cd jlinalg_adapter; make tests 2>&1 | tee ja.out cd commons-math_adapter; make tests 2>&1 | tee ja.out echo "--------------------" -grep FAIL t.out -grep Exception e.out | grep -v GCDProxy | grep -v GBProxy -egrep '(Exception|Usage|Error|ERROR)' tr.out -egrep '(Error|ERROR|File|Exception)' tjy.out -egrep -i '(error|__file__|exception|failed)' tjr.out -egrep -i '(Error|File|Exception)' jython/jsr.out mpj/mpj.out jlinalg_adapter/ja.out #-grep -i error mpi/mpi.out metrics: ant jdepend ../java/javancss-32.53/bin/javancss -all -recursive -out test/javanccs-`date +%Y-%m-%d`.out src findbugs: cd ~/java/findbugs; bin/fb analyze -sortByClass -medium -html -nested:false /home/kredel/jas/edu/jas/ > jas.findbugs-report.medium_`date +"%Y-%m-%d"`_.html findbugs-low: cd ~/java/findbugs; bin/fb analyze -sortByClass -low -html -nested:false /home/kredel/jas/edu/jas/ > jas.findbugs-report.low_`date +"%Y-%m-%d"`_.html #svn copy file:///$(SVNREPO)/jas/trunk file:///$(SVNREPO)/jas/tags/$(VERSION) #SVNREV=svnlook youngest $(SVNREPO)/jas #SVNDATE=svnlook date $(SVNREPO)/jas # new numbering in git: #SVNDATE=git log -r HEAD --date=iso .|grep Date:|head -1|awk '{print $2}' # Jan 2008 SVNSRT=1584 # Jun 2008 SVNSRT=1882 # Sep 2008 SVNSRT=2118r # jan 2009 SVNSRT=2288 # jun 2009 SVNSRT=2668 # jan 2010 SVNSRT=2978 # jun 2010 SVNSRT=3188 # jan 2011 SVNSRT=3458 # jul 2011 SVNSRT=3688 # dec 2011 SVNSRT=3838 # jul 2012 SVNSRT=4008 # aug 2013 SVNSRT=4588 # jan 2014 SVNSRT=4742 # jan 2015 SVNSRT=5055 # jan 2018 SVNSRT=5787 # jan 2019 SVNSRT=5966 # jan 2020 SVNSRT=5990 SVNREV=200 GITREV=$(SVNREV) GITSINCE=2021-01-01 #GITSINCE=2019-01-01 #GITSINCE=2016-03-26 # git archive --format=tar --prefix=$(VERSION)/ HEAD | (cd ~/jas-versions/ && tar -xf -) #svn export --quiet file:///$(SVNREPO)/jas/trunk ~/jas-versions/$(VERSION) #svn log -v -r HEAD:$(SVNSRT) file:///$(SVNREPO)/jas/trunk src trc examples jython mpj mpi jlinalg_adapter commons-math_adapter > ~/jas-versions/$(VERSION)/doc/git_change.log export: rm -rf ~/jas-versions/$(VERSION) git archive --format=tar --prefix=$(VERSION)/ HEAD | (cd ~/jas-versions/ && tar -xf -) cd ~/jas-versions/$(VERSION); jas_dosed $(VERSION) $(GITREV) doc/download.html $(DEBVERSION) cd ~/jas-versions/$(VERSION); jas_dosed $(VERSION) $(GITREV) doc/Dockerfile $(DEBVERSION) git log -r --since $(GITSINCE) --name-status --date=iso . src trc examples jython mpj mpi jlinalg_adapter commons-math_adapter > ~/jas-versions/$(VERSION)/doc/git_change.log cd ~/jas-versions/; jar -cfM $(VERSION).$(GITREV)-src.zip $(VERSION)/ cd ~/jas-versions/$(VERSION)/; ant compile > ant_compile.out cd ~/jas-versions/$(VERSION)/; jar -cfm ../$(VERSION).$(GITREV)-bin.jar GBManifest.MF edu/ COPYING* #log4j2.properties cd ~/jas-versions/$(VERSION)/; jar -uf ../$(VERSION).$(GITREV)-bin.jar -C ~/jas-versions/$(VERSION)/examples jas.rb -C ~/jas-versions/$(VERSION)/examples jas.py jar -uf ~/jas-versions/$(VERSION).$(GITREV)-bin.jar -C ~/jas/NOTES COPYING.APACHE-2.0 -C ~/jas/NOTES COPYING.apache.jas cd ~/jas-versions/$(VERSION)/; ant doc > ant_doc.out cd ~/jas-versions/$(VERSION)/; epydoc -v -o doc/jython -n "Python to JAS" -u ../../index.html examples/jas.py examples/basic_sigbased_gb.py examples/sdjas.py > epydoc.out cd ~/jas-versions/$(VERSION)/; jrdoc -o doc/jruby -U -N -t "Ruby to JAS" examples/jas.rb examples/sdjas.rb > rdoc.out 2>&1 cd ~/jas-versions/$(VERSION)/; ant test > ant_test.out cd ~/jas-versions/$(VERSION)/; sh ./jython_tests.sh >jython_tests.out 2>&1 cd ~/jas-versions/$(VERSION)/; sh ./jruby_tests.sh >jruby_tests.out 2>&1 cp ~/jas-versions/$(VERSION).$(GITREV)-bin.jar $(LIBPATH)/jas.jar cp ~/jas-versions/$(VERSION).$(GITREV)-bin.jar ~/jas-versions/$(VERSION)/jas.jar cd ~/jas-versions/$(VERSION)/jython; make all doc > ~/jas-versions/$(VERSION)/make_jython.out 2>&1 cd ~/jas-versions/$(VERSION)/mpi; make all doc > ~/jas-versions/$(VERSION)/make_mpi.out 2>&1 cd ~/jas-versions/$(VERSION)/mpj; make all doc > ~/jas-versions/$(VERSION)/make_mpj.out 2>&1 cd ~/jas-versions/$(VERSION)/meditor; jas_dosed $(VERSION) $(GITREV) manifest.mf cd ~/jas-versions/$(VERSION)/meditor; make > ~/jas-versions/$(VERSION)/make_meditor.out 2>&1 #cd ~/jas-versions/log4j_adapter; make > ~/jas-versions/$(VERSION)/make_mylog.out #cp ~/java/lib/mylog.jar ~/jas-versions/$(VERSION)/ #cd ~/jas-versions/log4j_droid_adapter; make > ~/jas-versions/$(VERSION)/make_droidlog.out #cp ~/java/lib/droidlog.jar ~/jas-versions/$(VERSION)/ #cd ~/jas-versions/log4j_null_adapter; make > ~/jas-versions/$(VERSION)/make_nolog.out #cp ~/java/lib/nolog.jar ~/jas-versions/$(VERSION)/ cd ~/jas-versions/$(VERSION)/jlinalg_adapter; make all doc > ~/jas-versions/$(VERSION)/make_jlinalg.out 2>&1 cd ~/jas-versions/$(VERSION)/commons-math_adapter; make all doc > ~/jas-versions/$(VERSION)/make_commons-math.out 2>&1 cd ~/jas-versions/$(VERSION)/; jar -cfM ../$(VERSION).$(GITREV)-doc.zip doc/ images/ *.html doc/*.html *.css doc/*.css mv ~/jas-versions/$(VERSION).$(GITREV)-*.jar ~/jas-versions/$(VERSION)/ mv ~/jas-versions/$(VERSION).$(GITREV)-*.zip ~/jas-versions/$(VERSION)/ cd ~/jas-versions/$(VERSION)/; chmod -v +r *.jar *.zip >chmod.out 2>&1 deploy: $(RSYNC) -e 'ssh' --delete-after --exclude=DTD --exclude=*xml ~/jas-versions/$(VERSION)/ krum:htdocs/$(VERSION) m2-deploy: $(RSYNC) -e 'ssh' ~/jas-versions/tmp/$(subst jas-,,$(VERSION)).$(GITREV)/ krum:htdocs/maven-repository/de/uni-mannheim/rz/krum/$(subst -,/,$(VERSION)).$(GITREV) # $(RSYNC) -e 'ssh' ~/jas-versions/tmp/$(subst jas-,,$(VERSION)).$(GITREV)/ https://oss.sonatype.org/content/groups/public/de/uni-mannheim/rz/krum/$(subst -,/,$(VERSION)).$(GITREV) git-export: #cd ~/jas-versions/jas-git/jas; git svn rebase > ~/jas-versions/$(VERSION)/git_svn.out #cd ~/jas-versions/jas-git/jas; git push -v deploy > ~/jas-versions/$(VERSION)/git_push.out cd ~/jas; git push -v deploy > ~/jas-versions/$(VERSION)/git_push.out svn-export: cd ~/jas; git svn dcommit > ~/jas-versions/$(VERSION)/git_svn.out git-deploy: $(RSYNC) -e 'ssh' --delete-after ~/jas-versions/jas-git/jas.git/ krum:htdocs/jas.git #cd ~/jas-versions/jas-git/jas.git; git push -v $(DRY) google >> ~/jas-versions/$(VERSION)/git_push.out cd ~/jas-versions/jas-git/jas.git; git push -v $(DRY) github >> ~/jas-versions/$(VERSION)/git_push.out jas-bin.jar: jar -cfm $(VERSION).$(GITREV)-bin.jar GBManifest.MF edu/ COPYING* #log4j2.properties jar -uf $(VERSION).$(GITREV)-bin.jar -C examples jas.rb -C examples jas.py #jar -ufm ../$(VERSION)-gbb-bin.jar ~/java/lib/log4j.dir/META-INF/MANIFEST.MF -C ~/java /lib/log4j.dir/ org/ #echo "EXAMJAS" $(EXAMJAS) mkbench: jar -cfm $(VERSION)-gbb-bin.jar GBManifest.MF edu/ COPYING* #log4j2.properties #jar -ufe $(VERSION)-gbb-bin.jar edu.jas.application.RunMPJGB -C mpj/classes/ edu/ jar -uf $(VERSION)-gbb-bin.jar -C mpj/classes/ edu/ jar -uf $(VERSION)-gbb-bin.jar -C ~/java/lib/log4j.dir/ org/ cd examples; jar -cf examples.jar $(EXAMJAS) runbench: java -jar $(VERSION)-gbb-bin.jar seq katsura5.jas #echo youngest revision `svnlook youngest $(SVNREPO)/jas` young: echo youngest revision `git rev-list -n1 HEAD` subst: cd ~/jas-versions/$(VERSION); jas_dosed $(VERSION) $(GITREV) doc/download.html $(DEBVERSION) svn-logs: svn log -v -r HEAD:$(SVNSRT) file:///$(SVNREPO)/jas/trunk src trc examples jython mpj mpi jlinalg_adapter commons-math_adapter > doc/svn_change.log git-logs: git log -r --since $(GITSINCE) --name-status --date=iso . src trc examples jython mpj mpi jlinalg_adapter commons-math_adapter > doc/git_change.log # lines of code and number of classes loc: young (find src -name "*.java"; find trc -name "*.java")| wc -l find src -name "*.java" | grep -v Test | wc -l find trc -name "*.java" | grep Test | wc -l (find src -name "*.java"; find trc -name "*.java") | xargs cat | wc find src -name "*.java" | grep -v Test | xargs cat | wc find trc -name "*.java" | grep Test | xargs cat | wc find trc -name "*.java" | grep Test | xargs cat | grep "void test" | wc -l find ~/jas-versions/log4j_adapter -name "*.java" | wc -l find ~/jas-versions/log4j_adapter -name "*.java" | xargs cat | wc find jlinalg_adapter -name "*.java" | wc -l find jlinalg_adapter -name "*.java" | xargs cat | wc find commons-math_adapter -name "*.java" | wc -l find commons-math_adapter -name "*.java" | xargs cat | wc find jython -name "*.java" | wc -l find jython -name "*.java" | xargs cat | wc find mpi -name "*.java" | wc -l find mpi -name "*.java" | xargs cat | wc find mpj -name "*.java" | wc -l find mpj -name "*.java" | xargs cat | wc cat examples/jas.py | wc find examples -name "*.py" | grep -v jas.py | xargs cat | wc cat examples/jas.rb | wc find examples -name "*.rb" | grep -v jas.rb | xargs cat | wc # -eof- java-algebra-system-2.7.200/README000066400000000000000000000104071445075545500164200ustar00rootroot00000000000000 JAS: Java Algebra System ======================== Version 2.7, 2023 by Heinz Kredel, University of Mannheim, kredel at rz.uni-mannheim.de Copyright (c) 2000-2023 by Heinz Kredel. Programms released under GPL or LGPL, see COPYING.jas or COPYING.lgpl.jas. Web home-page: http://krum.rz.uni-mannheim.de/jas/ Requirements ------------ A Java JDK 1.11. Documentation see index.html. Required libraries are log4j-core-2.17.1.jar, log4j-api-2.17.1.jar (from Apache Log4j2 or jars from some other compatible logging framework like SLF4J) and junit-4.12.jar, hamcrest-core-1.3.jar (from Junit 4 for tests in trc) Usage ----- > java -cp {other_jar_files}:jas--bin.jar:. for example > java -cp ../lib/log4j-core-2.17.1.jar:../lib/log4j-api-2.17.1.jar:jas-2.6.5428-bin.jar edu.jas.application.RunGB seq examples/trinks7.jas or > jruby examples/.rb or > jas examples/.rb for example > ./jas examples/all_rings.rb or > jython examples/.py or > jas -py examples/.py The shell script "jas" figures out the Java, jruby, jython and JAS environment and runs the respective scripting interpreter. See > man -l doc/jas.1 for more information. Compilation of your own Java files using the JAS library can be done with the "javac" command. > javac -cp {other_jar_files}:jas--bin.jar:. Versions and jar files ---------------------- JAS is distributed in 3 jar files: jas--bin.jar: or jas-.jar: the Java class files jas--src.zip: the java source code jas--doc.zip: the Java doc, epydoc, jrdoc and more info files optional jar files which require further installed packages: jas-meditor.jar: the interface to meditor jas-jython.jar: an interface for Java scripting jas-mpj.jar: MPI Java depending code mylog.jar: a substitute for log4j to use Java logging nolog.jar: a substitute for log4j to disable any logging droidlog.jar: a substitute for log4j to use Android logging jlinalg_adapter.jar: an adaptor to parts of JLinAlg commons-math_adapter.jar: an adaptor to parts of Apache commons.math pre packaged JAS versions: jas-java_-all.deb a Debian 10 (buster) package usable in MathLibre ruboto-irb-jas-release.apk an Android App based on Ruboto (defunct) There are GIT repositories for the scource code, which can be cloned with > git clone http://krum.rz.uni-mannheim.de/jas.git jas or > git clone https://github.com/kredel/java-algebra-system.git jas There is a Maven compatible repository for bytecode, source and javadocs at https://oss.sonatype.org/ groupId: de.uni-mannheim.rz.krum, artifactId: jas, version (for example): 2.7.50 The version is specified by a two digit major.minor number and a revision number. The revision number was the subversion revision number, but with git it is just a consecutive number. For example in jas-2.7.80-bin.jar "2.7" is the JAS version number and "80" is the git revision number The jas-*-bin.jar and jas-*-doc.jar can be generated from jas-*-src.jar. The fastest way to get a complete JAS install, is > jar -xf jas--src.zip > cd > jar -xf jas--bin.jar > jar -xf jas--doc.zip If you have a working Ant with Ivy, the last two steps can be replaced by > ant resolve > ant compile > ant doc provided you have setup build.xml, ivy.xml for the required libraries. Directory structure ------------------- . main directory, entry to html documentation +doc html documentation, javadocs, jython docs, jruby docs +edu Java class files +examples examples for jython, jruby and jas +images images for html docs +jython JSR 233 scripting interface +meditor JSR 233 scripting interface for meditor +mpj MPI Java versions of distributed Groebner bases +mpi OpenMPI Java versions of distributed Groebner bases +jlinalg_adaper some adapter classes to JLinAlg +commons-math_adaper some adapter classes to Apache Commons Math3 +src source code +trc junit test sources +test junit test output and log4j output ../lib directory for required libraries, not included $Id: 1cce2e100633f66aec4569b73fe887068886aab4 $ java-algebra-system-2.7.200/build.gradle000066400000000000000000000100441445075545500200140ustar00rootroot00000000000000/* * This build file was generated and modified * by 'kredel' * * $Id$ */ apply plugin: 'java' apply plugin: 'ivy-publish' apply plugin: 'maven-publish' //apply plugin: 'build-dashboard' repositories { flatDir { dirs "/home/kredel/java/lib" } mavenCentral() } //final LOG4J = "log4j:log4j:1.2.17@jar" //final JUNIT = "junit:junit:3.8@jar" final LOG4Ja = "org.apache.logging.log4j:log4j-api:2.5@jar" final LOG4Jc = "org.apache.logging.log4j:log4j-core:2.5@jar" final LOG4J1 = "org.apache.logging.log4j:log4j-1.2-api:2.5@jar" final JUNIT = "junit:junit:4.12@jar" //println LOG4J //println JUNIT sourceSets { main { java { srcDir 'src' } //output.classesDir = file('build/classes') } test { java { srcDir 'trc' } //output.classesDir = file('build/classes') } } dependencies { compile LOG4Ja, LOG4Jc, LOG4J1, JUNIT //testCompile JUNIT //test LOG4J, JUNIT //publish javadoc } version = "2.6." + "svnlook youngest /home/SUBVERSION/jas".execute().text.trim() //println "version = " + version description = "Java Algebra System (JAS), version " + version javadoc { title "Java Algebra System (JAS)" } test { //useJUnit() ignoreFailures = true forkEvery = 1 //reports.html.enabled = true //scanForTestClasses = false //testLogging.showStandardStreams = false //jvmArgs '-disableassertions' //jvmArgs '-XX:MaxPermSize=256m' beforeSuite { descriptor -> if ((""+descriptor).indexOf("class")>=0) println("Running class suite: " + descriptor) } //beforeTest { descriptor -> // println("Running test: " + descriptor) //} //println "test classpath = " + compileTestJava.classpath.getAsPath() //println "classpath = " + classpath.getAsPath() //println "test classes = " + relativePath(testClassesDir) //println "test results = " + relativePath(testResultsDir) //println "test report = " + relativePath(testReportDir) //include 'edu/jas/arith/**' // ok //include '**/poly/*Test.class' // ok //include '**/arith/*Test.class' // ok //include '**/*Test.class' include 'edu/*/*/*Test.class' // ok //filter { // not ok // includeTestsMatching "*Test" //} } task sourceZip(type: Zip) { baseName "jas-src" from sourceSets.main.java, sourceSets.test.java classifier "source" } task docZip(type: Zip) { baseName "jas-doc" from javadoc.destinationDir classifier "javadoc" } task classesJar(type: Jar) { baseName "jas-bin" from sourceSets.main.output, sourceSets.test.output classifier "classes" } group = 'JavaAlgebraSystem' publishing { publications { final version = project.version ivyClasses(IvyPublication) { from components.java artifact classesJar } ivySource(IvyPublication) { from components.java artifact sourceZip } ivyDoc(IvyPublication) { from components.java artifact docZip } mavenClasses(MavenPublication) { from components.java artifact classesJar } mavenSource(MavenPublication) { from components.java artifact sourceZip } mavenDoc(MavenPublication) { from components.java artifact docZip } } repositories { ivy { url "$buildDir/repo/ivy" } maven { url "$buildDir/repo/maven" } } } task show << { println compileJava.classpath.getAsPath() println relativePath(compileJava.destinationDir) println relativePath(compileTestJava.destinationDir) println relativePath(processResources.destinationDir) sourceSets.all { println name } } task listJars << { configurations.testCompile.each { File file -> println file.name } } // ------- old ------------------- //ant.importBuild 'build.xml' //ant.taskdef(name: 'junit', // classname: 'org.apache.tools.ant.taskdefs.optional.junit.JUnitTask', // classpath: '/usr/share/ant/lib/ant-junit.jar') java-algebra-system-2.7.200/build.xml000066400000000000000000000400151445075545500173570ustar00rootroot00000000000000 java-algebra-system-2.7.200/buildfile000066400000000000000000000074001445075545500174210ustar00rootroot00000000000000# # Generated by Buildr 1.4.21, changed by kredel to his liking # # $Id$ # #ENV['JAVA_OPTS'] ||= '-Xms1g -Xmx1g' require 'buildr/groovy' # Version number for this release VERSION_NUMBER = "2.6." + `svnlook youngest /home/SUBVERSION/jas`.to_s.chomp # Group identifier for your projects GROUP = "JavaAlgebraSystem" COPYRIGHT = "Copyright (c) 2005-2023 by Heinz Kredel" # Specify Maven 2.0 remote repositories here, like this: #repositories.remote << "http://repo1.maven.org/maven2" #repositories.remote << "file:/home/kredel/java/lib" #repositories.local = "/home/kredel/java/lib" #LOG4J = "log4j:log4j:jar:1.2.17" #url1 = "file:/home/kredel/java/lib/log4j.jar" #download(artifact(LOG4J)=>url1) LOG4Ja = "org.apache.logging.log4j:log4j-api:jar:2.5" LOG4Jc = "org.apache.logging.log4j:log4j-core:jar:2.5" LOG4J1 = "org.apache.logging.log4j:log4j-1.2-api:jar:2.5" url1a = "file:/home/kredel/java/lib/log4j-api.jar" download(artifact(LOG4Ja)=>url1a) url1c = "file:/home/kredel/java/lib/log4j-core.jar" download(artifact(LOG4Jc)=>url1c) url11 = "file:/home/kredel/java/lib/log4j-1.2-api.jar" download(artifact(LOG4J1)=>url11) #JUNIT = "junit:junit:jar:3.8" JUNIT = "junit:junit:jar:4.12" url2 = "file:/home/kredel/java/lib/junit.jar" download(artifact(JUNIT)=>url2) jas_layout = Layout.new jas_layout[:source, :main, :java] = 'src' jas_layout[:source, :test, :java] = 'trc' #jas_layout[:target, :main, :classes] = 'classes' #jas_layout[:target, :test, :classes] = 'classes' #jas_layout[:reports, :target, :test] = 'test' desc "The Java Algebra System (JAS) project" define "jas", :layout=>jas_layout do project.version = VERSION_NUMBER project.group = GROUP manifest["Implementation-Vendor"] = COPYRIGHT puts "running buildr for: " + project.group + "-" + project.version compile.with LOG4Ja, LOG4Jc, LOG4J1, JUNIT #test.compile.with JUNIT #test.with LOG4Ja, LOG4Jc, LOG4J1, JUNIT test.using :junit, :fail_on_failure=>false #test.include '*Test' test.include 'edu.jas.arith.*Test' run.using :main => [ "edu.jas.application.RunGB" , "seq", "examples/trinks7.jas", "2", "nolog" ] repositories.release_to[:url] = 'file:/home/kredel/jas/target/repo' package(:jar).with(:manifest=>_('GBManifest.MF')).tap do |path| path.include _('README') path.include _('COPYING*') path.include( _('../lib/log4j-api.jar'), :as => "lib/log4j-api.jar") path.include( _('../lib/log4j-core.jar'), :as => "lib/log4j-core.jar") path.include( _('../lib/log4j-1.2-api.jar'), :as => "lib/log4j-1.2-api.jar") path.include( _('../lib/junit.jar'), :as => "lib/junit.jar") #meta_inf << file('DISCLAIMER') << file('NOTICE') end package(:zip, :classifier=>'javadoc').tap do |path| path.include( _('target/doc'), :as=> "doc" ) path.include _('*.html') path.include _('*.css') path.include _('images') path.include _('README') path.include _('COPYING*') end package(:zip, :classifier=>'sources').tap do |path| path.include _(:source, :main, :java) path.include _(:source, :test, :java) path.include _('README') path.include _('COPYING*') end #puts 'com dep ' + compile.dependencies.map{ |d| d.to_hash}.join(" : ") #puts 'test dep ' + test.dependencies.map{ |d| d.to_hash}.join(" : ") #puts 'Compiling from ' + compile.source.to_s #puts 'Compiling to ' + compile.target.to_s #puts 'ComTesting from ' + test.compile.source.to_s #puts 'ComTesting to ' + test.compile.target.to_s #puts 'Testing to ' + path_to(:reports).to_s #compile do # puts "running compile" # #system "ant compile" #end #define "commons-math_adapter" do #end #define "jlinalg_adapter" do #end #define "jython" do #end #define "meditor" do #end #define "mpi" do #end #define "mpj" do #end end java-algebra-system-2.7.200/commons-math_adapter/000077500000000000000000000000001445075545500216405ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/.gitignore000066400000000000000000000000461445075545500236300ustar00rootroot00000000000000/test /classes /*.jar /*.out /*.class java-algebra-system-2.7.200/commons-math_adapter/Makefile000066400000000000000000000037231445075545500233050ustar00rootroot00000000000000# # $Id: $ # # Makefile for the Apache Commons Math Adapter parts # by Heinz Kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib CMJAR=$(LIBPATH)/commons-math3-3.3.jar CLASSPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar:$(LIBPATH)/junit.jar:$(CMJAR):$(JASPATH) #CLASSPATH=$(LIBPATH)/log4j.jar:$(LIBPATH)/junit.jar:$(CMJAR):$(JASPATH) #$(LIBPATH)/jas.jar #LOG4JPATH=$(LIBPATH)/log4j-core-2.13.2.jar:$(LIBPATH)/log4j-api-2.13.2.jar #DOCOPTS=-package DOCOPTS=-package -author -version -linksource -Xdoclint:none -overview overview.html DOCCLASSES=$(CLASSPATH) DOC=javadoc -classpath $(DOCCLASSES) .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/commons/*/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) all: clean commons-math_adapter-bin.jar $(CLASSES): $(FILES) Makefile -mkdir classes javac -classpath $(CLASSPATH) -d classes src/edu/jas/commons/*/*.java #compile: $(HOME)/java/lib/commons-math_adapter.jar commons-math_adapter-bin.jar: $(CLASSES) -mkdir classes/META-INF cp -a manifest.mf classes/META-INF/MANIFEST.MF jar cfM commons-math_adapter-bin.jar -C classes . cp -f commons-math_adapter-bin.jar $(LIBPATH) cp -f commons-math_adapter-bin.jar .. jar cf commons-math_adapter-src.jar -C src . tests: java -cp $(CLASSPATH):commons-math_adapter-bin.jar -Xms500M -Xmx600M -verbose:gc edu.jas.commons.math.CMFieldElementTest java -cp $(CLASSPATH):commons-math_adapter-bin.jar -Xms500M -Xmx600M -verbose:gc edu.jas.commons.math.MatrixExamples clean: -rm -rf classes find . -name "*~" -follow -print -exec rm {} \; -rm -f $(HOME)/java/lib/commons-math_adapter*.jar -rm -f commons-math_adapter*.jar doc: $(FILES) $(DOC) $(DOCOPTS) -d ../doc/commons-math_adapter $(FILES) jar cf commons-math_adapter-doc.jar -C ../doc/commons-math_adapter . #JARS=$(LIB)/junit.jar:$(LIB)/log4j.jar:$(LIB)/commons-math-2.1.jar:$(JAS):$(LIB)/jas.jar java-algebra-system-2.7.200/commons-math_adapter/manifest.mf000066400000000000000000000000671445075545500237750ustar00rootroot00000000000000Manifest-Version: 1.0 Created-By: 1.7.0_0 (IceTea) java-algebra-system-2.7.200/commons-math_adapter/overview.html000066400000000000000000000043371445075545500244030ustar00rootroot00000000000000 Java Algebra System, Apache Commons Math-Adapter

Java algebra system, Apache Commons Math-Adapter.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

This package contains adapters to some Apache Commons Math classes.

See introduction for a general overview.

For a discussion of the design and comparison to the JLinAlg adapter see Heinz Kredel, Fostering Interoperability in Java-Based Computer Algebra Software, Proceedings FINA Workshop AINA-2012, March 26-29, 2012, Fukuoka, Japan (slides)


Heinz Kredel

Last modified: Sat Jun 28 17:28:54 CEST 2014

$Id$

java-algebra-system-2.7.200/commons-math_adapter/src/000077500000000000000000000000001445075545500224275ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/src/edu/000077500000000000000000000000001445075545500232045ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/000077500000000000000000000000001445075545500237615ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/000077500000000000000000000000001445075545500254345ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/000077500000000000000000000000001445075545500263655ustar00rootroot00000000000000java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/CMField.java000066400000000000000000000105511445075545500304750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import org.apache.commons.math3.Field; import edu.jas.structure.ElemFactory; import edu.jas.structure.Element; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Class that wraps a JAS RingFactory in a commons-math * Field. * @author Heinz Kredel * @param JAS ring element type */ public class CMField> implements Field> { public final RingFactory fac; /** * @param f */ public CMField(ElemFactory f) { this((RingFactory) f); } /** * @param f */ public CMField(RingFactory f) { fac = f; } /** * get runtime class */ @SuppressWarnings({"unchecked","cast"}) @Override public Class> getRuntimeClass() { return (Class>) (Class) CMFieldElement.class; //getClass(); } /** * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { // System.out.println("factory equals, this = " + this + ", obj = " + obj); if (!(obj instanceof Field)) { return false; } Field other = (Field) obj; CMField fother = (CMField) other; RingFactory ofac = fother.fac; // System.out.println("factory equals, this = " + fac.getClass() + // ", obj = " + ofac.getClass()); if (!fac.getClass().getName().equals(ofac.getClass().getName())) { return false; } RingFactory ofac1 = null; try { ofac1 = (RingFactory) ((RingElem) ofac).factory(); } catch (ClassCastException e) { } if ( /* fac */ofac.equals(ofac1)) { // case BigInteger etc return true; } // System.out.println("factory equals, this = " + ofac + ", obj = " + // ofac1); // if (fac.characteristic().equals(ffac.characteristic())) { // return true; // } return fac.equals(ofac); } public CMFieldElement get(int i) { return new CMFieldElement(fac.fromInteger(i)); } public CMFieldElement get(long i) { return new CMFieldElement(fac.fromInteger(i)); } public CMFieldElement get(Object o) { if (o == null) { return null; } String s = o.toString(); return new CMFieldElement(fac.parse(s)); } @SuppressWarnings("unchecked") public CMFieldElement[] getArray(int size) { CMFieldElement[] arr = new CMFieldElement[size]; for (int i = 0; i < arr.length; i++) { arr[i] = getZero(); } return arr; } @SuppressWarnings("unchecked") public CMFieldElement[][] getArray(int rows, int columns) { CMFieldElement[][] arr = new CMFieldElement[rows][columns]; for (int i = 0; i < arr.length; i++) { arr[i] = getArray(columns); } return arr; } @Override public CMFieldElement getOne() { return new CMFieldElement(fac.getONE()); } @Override public CMFieldElement getZero() { return new CMFieldElement(fac.getZERO()); } /** * @see java.lang.Object#hashCode() */ @SuppressWarnings("unchecked") @Override public int hashCode() { RingFactory fac1 = null; try { fac1 = (RingFactory) ((RingElem) fac).factory(); } catch (ClassCastException e) { } if (fac.equals(fac1)) { // case BigInteger etc // int h = fac.getClass().getSimpleName().hashCode(); // h = h * 37 + fac.characteristic().hashCode(); return fac.getClass().getName().hashCode(); } return fac.hashCode(); } /** * Get the string representation. * * @see java.lang.Object#toString() */ @SuppressWarnings("unchecked") @Override public String toString() { StringBuffer s = new StringBuffer(); String f = null; try { f = ((Element) fac).toScriptFactory(); } catch (Exception ignored) { f = fac.toScript(); } if (f != null) { s.append(f); } return s.toString(); } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/CMFieldElement.java000066400000000000000000000050561445075545500320130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import org.apache.commons.math3.Field; import org.apache.commons.math3.FieldElement; import edu.jas.structure.RingElem; /** * Class that wraps a JAS RingElem in a commons-math * FieldElement. * @param JAS ring element type * @author Heinz Kredel */ public class CMFieldElement> implements FieldElement>, Comparable> { public final C val; public CMFieldElement(C v) { val = v; } @Override public CMFieldElement add(CMFieldElement other) { return new CMFieldElement(val.sum(other.val)); } @Override public CMFieldElement negate() { return new CMFieldElement(val.negate()); } @Override public int compareTo(CMFieldElement other) { return val.compareTo(other.val); } @Override public CMFieldElement divide(CMFieldElement other) throws ArithmeticException { return new CMFieldElement(val.divide(other.val)); } @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (!(obj instanceof CMFieldElement)) { return false; } CMFieldElement other = (CMFieldElement) obj; return this.compareTo(other) == 0; } @Override public Field> getField() { return new CMField(val.factory()); } @Override public int hashCode() { return val.hashCode(); } @Override public CMFieldElement multiply(CMFieldElement other) { return new CMFieldElement(val.multiply(other.val)); } @Override public CMFieldElement multiply(int n) { return new CMFieldElement(val.multiply(val.factory().fromInteger(n))); } @Override public CMFieldElement subtract(CMFieldElement other) { return new CMFieldElement(val.subtract(other.val)); } @Override public CMFieldElement reciprocal() { return new CMFieldElement(val.inverse()); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); // s.append("JLAdapter("); s.append(val.toString()); // s.append(")"); return s.toString(); } public boolean isOne() { return val.isONE(); } public boolean isZero() { return val.isZERO(); } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/CMFieldElementTest.java000066400000000000000000000143641445075545500326550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import java.util.Arrays; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * CMFieldElementTest tests with JUnit * @author Heinz Kredel */ public class CMFieldElementTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a CMFieldElementTest object. * @param name String. */ public CMFieldElementTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(CMFieldElementTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. */ public void testConstruction() { BigRational z = new BigRational(0); CMFieldElement a = new CMFieldElement(z); //System.out.println("a = " + a); assertTrue("isZero( a )", a.isZero()); BigRational o = new BigRational(1); CMFieldElement b = new CMFieldElement(o); //System.out.println("b = " + b); assertTrue("isOne( b )", b.isOne()); CMFieldElement c = b.subtract(b); //System.out.println("c = " + c); assertTrue("isZero( c )", c.isZero()); assertEquals("a == c ", a, c); c = new CMFieldElement(new BigRational(1, 2)); //System.out.println("c = " + c); assertTrue("!isZero( c )", !c.isZero()); // CMFieldElement d = c.invert(); // //System.out.println("d = " + d); // assertTrue("!isZero( d )", !d.isZero()); // // assertTrue("isOne( 1/2 * 2 ) ", d.multiply(c).isOne()); // // CMFieldElement e = b.divide(d); // //System.out.println("e = " + e); // assertEquals("1/2 == 1 / (2) ", c, e); } /** * Test factory and toString. */ public void testFactory() { RingFactory z = new BigRational(0); CMField fac = new CMField(z); //System.out.println("fac = " + fac); CMFieldElement a = fac.getZero(); //System.out.println("a = " + a); assertTrue("isZero( a )", a.isZero()); CMFieldElement b = fac.getOne(); //System.out.println("b = " + b); assertTrue("isOne( b )", b.isOne()); } /** * Test matrix solve. * */ // public void testGenMatrixSolv() { // MatrixExamples gms = new MatrixExamples(); // gms.main(null); // } /** * Test vector conversions. */ public void testVectorConversion() { RingFactory z = new BigRational(0); CMField fac = new CMField(z); CMFieldElement[] vec1 = fac.getArray(ll); //System.out.println("vec1 =" + Arrays.toString(vec1)); RingElem[] v1 = CMFieldElementUtil. fromCMFieldElement(vec1); //System.out.println("v1 =" + Arrays.toString(v1)); CMFieldElement[] vec2 = CMFieldElementUtil. toCMFieldElementRE(v1); //System.out.println("vec2 =" + Arrays.toString(vec2)); assertTrue("v1[] == v2[] ", Arrays.equals(vec1, vec2)); BigRational[] v2 = new BigRational[ll]; for (int i = 0; i < v2.length; i++) { v2[i] = z.random(kl); } //System.out.println("v2 =" + Arrays.toString(v2)); CMFieldElement[] vec3 = CMFieldElementUtil. toCMFieldElement(v2); //System.out.println("vec3 =" + Arrays.toString(vec3)); RingElem[] v3 = CMFieldElementUtil. fromCMFieldElement(vec3); //System.out.println("v3 =" + Arrays.toString(v3)); assertTrue("v2[] == v3[] ", Arrays.equals(v2, v3)); } /** * Test matrix conversions. */ public void testMatrixConversion() { RingFactory z = new BigRational(0); CMField fac = new CMField(z); CMFieldElement[][] vec1 = fac.getArray(ll, ll); //System.out.println("vec1 =" + matrixToString(vec1)); RingElem[][] v1 = CMFieldElementUtil. fromCMFieldElement(vec1); //System.out.println("v1 =" + matrixToString(v1)); CMFieldElement[][] vec2 = CMFieldElementUtil. toCMFieldElementRE(v1); //System.out.println("vec2 =" + matrixToString(vec2)); assertMatrixEquals(vec1, vec2); BigRational[][] v2 = new BigRational[ll][]; for (int i = 0; i < v2.length; i++) { v2[i] = new BigRational[ll]; for (int j = 0; j < v2.length; j++) { v2[i][j] = z.random(kl); } } //System.out.println("v2 =" + matrixToString(v2)); CMFieldElement[][] vec3 = CMFieldElementUtil. toCMFieldElement(v2); //System.out.println("vec1 =" + matrixToString(vec3)); RingElem[][] v3 = CMFieldElementUtil. fromCMFieldElement(vec3); //System.out.println("v3 =" + matrixToString(v3)); //v3[0][0] = v3[1][1]; assertMatrixEquals(v2, v3); } public String matrixToString(Object[][] m) { StringBuffer s = new StringBuffer("["); for (int i = 0; i < m.length; i++) { if (i != 0) { s.append(", "); } s.append(Arrays.toString(m[i])); } s.append("]"); return s.toString(); } public void assertMatrixEquals(Object[][] m1, Object[][] m2) { for (int i = 0; i < m1.length; i++) { assertTrue("m1[][] == m2[][] ", Arrays.equals(m1[i], m2[i])); } } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/CMFieldElementUtil.java000066400000000000000000000320321445075545500326430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import java.util.ArrayList; import java.util.List; import org.apache.commons.math3.linear.ArrayFieldVector; import org.apache.commons.math3.linear.BlockFieldMatrix; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.FieldVector; import edu.jas.structure.RingElem; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Conversion methods from JAS to commons-math and vice versa. * @author Heinz Kredel */ public class CMFieldElementUtil { public static > C[] toArray(GenVector a) { if (a == null) { return null; } return toArray(a.val); } @SuppressWarnings("unchecked") public static > C[] toArray(List a) { if (a == null) { return null; } C[] av = (C[]) new RingElem[a.size()]; int i = 0; for (C e : a) { av[i++] = e; } return av; } public static > ArrayList toList(C[] a) { if (a == null) { return null; } ArrayList av = new ArrayList(a.length); for (int i = 0; i < a.length; i++) { av.add(a[i]); } return av; } public static > ArrayList> toList(C[][] a) { if (a == null) { return null; } ArrayList> av = new ArrayList>(a.length); for (int i = 0; i < a.length; i++) { av.add(CMFieldElementUtil. toList(a[i])); } return av; } public static > C[][] toArray(GenMatrix a) { if (a == null) { return null; } return toArrayFromMatrix(a.matrix); } @SuppressWarnings("unchecked") public static > C[][] toArrayFromMatrix(List> a) { // Array // only // once if (a == null) { return null; } C[][] av = (C[][]) new RingElem[a.size()][]; int i = 0; for (List e : a) { av[i++] = toArray(e); } return av; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v array of ring elements * @return array of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[] toCMFieldElement(C[] v) { if (v == null) { return null; } CMFieldElement[] va = (CMFieldElement[]) new CMFieldElement[v.length]; for (int i = 0; i < v.length; i++) { va[i] = new CMFieldElement(v[i]); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v array of ring elements * @return array of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[] toCMFieldElementRE(RingElem[] v) { if (v == null) { return null; } CMFieldElement[] va = (CMFieldElement[]) new CMFieldElement[v.length]; for (int i = 0; i < v.length; i++) { va[i] = new CMFieldElement((C) v[i]); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v JAS vector of ring elements * @return array of CMFieldElement objects */ public static > CMFieldElement[] toCMFieldElement(GenVector v) { if (v == null) { return null; } CMFieldElement[] va = CMFieldElementUtil. toCMFieldElement(v.val); return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v list of ring elements * @return array of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[] toCMFieldElement(List v) { if (v == null) { return null; } CMFieldElement[] va = (CMFieldElement[]) new CMFieldElement[v.size()]; for (int i = 0; i < v.size(); i++) { va[i] = new CMFieldElement(v.get(i)); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v JAS vector of ring elements * @return commons-math vector of CMFieldElementr objects */ public static > FieldVector> toCMFieldElementVector(GenVector v) { if (v == null) { return null; } return new ArrayFieldVector>(CMFieldElementUtil. toCMFieldElement(v.val)); } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v matrix of ring elements * @return matrix of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[][] toCMFieldElement(C[][] v) { if (v == null) { return null; } CMFieldElement[][] va = (CMFieldElement[][]) new CMFieldElement[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = CMFieldElementUtil. toCMFieldElement(v[i]); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v matrix of ring elements * @return matrix of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[][] toCMFieldElementRE(RingElem[][] v) { if (v == null) { return null; } CMFieldElement[][] va = (CMFieldElement[][]) new CMFieldElement[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = CMFieldElementUtil. toCMFieldElementRE(v[i]); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v JAS matrix of ring elements * @return matrix of CMFieldElement objects */ public static > CMFieldElement[][] toCMFieldElement(GenMatrix v) { if (v == null) { return null; } CMFieldElement[][] va = CMFieldElementUtil. toCMFieldElementFromMatrix(v.matrix); return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v list of lists of ring elements * @return array of CMFieldElement objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > CMFieldElement[][] toCMFieldElementFromMatrix( List> v) { if (v == null) { return null; } CMFieldElement[][] va = (CMFieldElement[][]) new CMFieldElement[v.size()][]; for (int i = 0; i < v.size(); i++) { va[i] = CMFieldElementUtil. toCMFieldElement(v.get(i)); } return va; } /** * Convert JAS RingElem to commons-math * FieldElement. * @param ring element type * @param v JAS vector of ring elements * @return commons-math FieldMatrix of CMFieldElement objects */ public static > FieldMatrix> toCMFieldMatrix(GenMatrix v) { if (v == null) { return null; } FieldMatrix> va = new BlockFieldMatrix>( CMFieldElementUtil. toCMFieldElementFromMatrix(v.matrix)); return va; } /** * Convert commons-math FieldElement to JAS * RingElem to. * @param ring element type * @param v array of CMFieldElement objects * @return array of ring elements */ @SuppressWarnings("unchecked") public static > C[] fromCMFieldElement(CMFieldElement[] v) { if (v == null) { return null; } C[] va = (C[]) new RingElem[v.length]; for (int i = 0; i < v.length; i++) { if (v[i] != null) { va[i] = v[i].val; } else { va[i] = null; } } return va; } /** * Convert commons-math FieldElement to JAS * RingElem to. * @param ring element type * @param v matrix of CMFieldElement objects * @return matrix of ring elements */ @SuppressWarnings("unchecked") public static > C[][] fromCMFieldElement(CMFieldElement[][] v) { if (v == null) { return null; } C[][] va = (C[][]) new RingElem[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = CMFieldElementUtil. fromCMFieldElement(v[i]); } return va; } /** * Convert commons-math FieldElement to JAS * RingElem to. * @param ring element type * @param v Commons-math vector of CMFieldElement objects * @return array of ring elements */ @SuppressWarnings("unchecked") public static > C[] fromCMFieldVector(FieldVector> v) { if (v == null) { return null; } C[] va = (C[]) new RingElem[v.getDimension()]; for (int i = 0; i < va.length; i++) { CMFieldElement e = v.getEntry(i); if (e != null) { va[i] = e.val; } else { va[i] = null; } } return va; } /** * Convert commons-math FieldElement to JAS * RingElem to. * * @param ring element type * @param v commons-math vector of CMFieldElement objects * @return Java list of ring elements */ public static > ArrayList listFromCMFieldVector(FieldVector> v) { if (v == null) { return null; } ArrayList vv = new ArrayList(v.getDimension()); for (int i = 0; i < v.getDimension(); i++) { CMFieldElement e = v.getEntry(i); if (e != null) { vv.add(e.val); } else { vv.add(null); } } return vv; } /** * Convert commons-math FieldElement to JAS * RingElem to. * * @param ring element type * @param v commons-math FieldVector of CMFieldElement objects * @return JAS vector of ring elements */ public static > GenVector vectorFromCMFieldVector(GenVectorModul fac, FieldVector> v) { if (v == null) { return null; } List list = listFromCMFieldVector(v); GenVector vv = new GenVector(fac, list); return vv; } /** * Convert commons-math FieldElement to JAS * RingElem to. * @param ring element type * @param v commons-math FieldMatrix of CMFieldElement objects * @return java.util.List of ring elements */ public static > List> listFromCMFieldMatrix(FieldMatrix> v) { if (v == null) { return null; } ArrayList> vv = new ArrayList>(v.getRowDimension()); for (int i = 0; i < v.getRowDimension(); i++) { FieldVector> e = v.getRowVector(i + 1); List l = listFromCMFieldVector(e); vv.add(l); } return vv; } /** * Convert commons-math FieldMatrix to JAS * RingElem to. * @param ring element type * @param v commons-math FieldMatrix of CMFieldElement objects * @return JAS matrix of ring elements */ public static > GenMatrix matrixFromCMFieldMatrix(GenMatrixRing fac, FieldMatrix> v) { if (v == null) { return null; } List> list = listFromCMFieldMatrix(v); GenMatrix vv = new GenMatrix(fac, list); return vv; } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/GaussElimination.java000066400000000000000000000061331445075545500325060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import org.apache.commons.math3.linear.FieldDecompositionSolver; import org.apache.commons.math3.linear.FieldLUDecomposition; import org.apache.commons.math3.linear.FieldMatrix; import org.apache.commons.math3.linear.FieldVector; import edu.jas.structure.RingElem; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenVector; /** * Algorithms related to Gaussian elimination. Conversion to commons-math * classes and delegation to commons-math algorithms. * @param ring element type * @author Heinz Kredel */ public class GaussElimination> { /** * Determinant of a matrix. * @param a matrix * @return determinant of a */ public C determinant(GenMatrix a) { FieldMatrix> am = CMFieldElementUtil. toCMFieldMatrix(a); final FieldLUDecomposition> lu = new FieldLUDecomposition>(am); CMFieldElement dm = lu.getDeterminant(); C d = dm.val; return d; } /** * Inverse of a matrix. * @param a matrix * @return inverse matrix of a */ public GenMatrix inverse(GenMatrix a) { FieldMatrix> am = CMFieldElementUtil. toCMFieldMatrix(a); final FieldLUDecomposition> lu = new FieldLUDecomposition>(am); FieldDecompositionSolver> fds = lu.getSolver(); FieldMatrix> bm = fds.getInverse(); GenMatrix g = CMFieldElementUtil. matrixFromCMFieldMatrix(a.ring, bm); return g; } /** * Test if n is a null space for the linear system: a * n = 0. * @param a matrix * @param n matrix * @return true, if n is a nullspace of a, else false */ public boolean isNullSpace(GenMatrix a, GenMatrix n) { GenMatrix z = a.multiply(n); // .transpose(n.ring) better not transpose // here // System.out.println("z = " + z); return z.isZERO(); } /** * Solve a linear system: a x = b. * @param a matrix * @param b vector of right hand side * @return a solution vector x */ public GenVector solve(GenMatrix a, GenVector b) { FieldMatrix> am = CMFieldElementUtil. toCMFieldMatrix(a); FieldVector> bv = CMFieldElementUtil. toCMFieldElementVector(b); final FieldLUDecomposition> lu = new FieldLUDecomposition>(am); FieldDecompositionSolver> fds = lu.getSolver(); FieldVector> xv = fds.solve(bv); GenVector xa = CMFieldElementUtil. vectorFromCMFieldVector(b.modul, xv); return xa; } /** * Trace of a matrix. * @param a matrix * @return trace of a */ public C trace(GenMatrix a) { FieldMatrix> am = CMFieldElementUtil. toCMFieldMatrix(a); CMFieldElement dm = am.getTrace(); C d = dm.val; return d; } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/MatrixExamples.java000066400000000000000000000064001445075545500321730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import java.math.MathContext; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Examples that compute solutions of linear equation systems. * @author Heinz Kredel */ public class MatrixExamples { public static void main(String[] argv) { example1(); example2(); } public static void example1() { BigRational r1, r2, r3, r4, r5, r6, fac; r1 = new BigRational(1, 10); r2 = new BigRational(6, 5); r3 = new BigRational(1, 9); r4 = new BigRational(1, 1); r5 = r2.sum(r3); r6 = r1.multiply(r4); fac = new BigRational(); BigRational[][] aa = new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 }, { r2, r1, r3 } }; GenMatrixRing mfac = new GenMatrixRing(fac, aa.length, aa[0].length); GenMatrix a = new GenMatrix(mfac, CMFieldElementUtil. toList(aa)); System.out.println("system = " + a); BigRational[] ba = new BigRational[] { r1, r2, r3 }; GenVectorModul vfac = new GenVectorModul(fac, ba.length); GenVector b = new GenVector(vfac, CMFieldElementUtil. toList(ba)); System.out.println("right hand side = " + b); GaussElimination ge = new GaussElimination(); GenVector x = ge.solve(a, b); System.out.println("solution = " + x); } public static void example2() { BigRational cfac = new BigRational(); GenPolynomialRing pfac = new GenPolynomialRing(cfac, new String[] { "x" }); GenPolynomial p = pfac.parse("(x^2 + 2)(x^2 - 3)"); // (x^2 - 2) System.out.println("p = " + p); //p = p.multiply(p); // not square-free to fail complexRoots //System.out.println("p = " + p); Roots rf = new Roots(); List> r = rf.complexRoots(p); System.out.println("r = " + r); if (r.size() != p.degree(0)) { System.out.println("#r != deg(p)"); } ComplexRing cc = new ComplexRing(new BigDecimal(0.0, MathContext.DECIMAL64)); GenPolynomialRing> dfac = new GenPolynomialRing>(cc, new String[] { "x" }); GenPolynomial> cp = dfac.parse(p.toString()); //System.out.println("cp = " + cp); for (Complex cd : r) { //System.out.println("cd = " + cd); Complex ev = PolyUtil.> evaluateMain(cc, cp, cd); if (ev.isZERO()) { System.out.println("ev = " + ev + " == 0.0: " + ev.isZERO()); } } } } java-algebra-system-2.7.200/commons-math_adapter/src/edu/jas/commons/math/Roots.java000066400000000000000000000053701445075545500303430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.commons.math; import java.math.MathContext; import java.util.ArrayList; import java.util.List; import org.apache.commons.math3.linear.Array2DRowRealMatrix; import org.apache.commons.math3.linear.EigenDecomposition; import org.apache.commons.math3.linear.RealMatrix; import edu.jas.arith.BigDecimal; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.ps.UnivPowerSeries; import edu.jas.ps.UnivPowerSeriesRing; import edu.jas.structure.RingElem; /** * Algorithms related to polynomial roots. Conversion to commons-math classes * and delegation to commons-math algorithms. * @param ring element type * @author Heinz Kredel */ public class Roots & Rational> { /** * Complex root approximation using companion matrix. * @param a squarefree univariate polynomial * @return list of approximations of complex roots of the polynomial */ public List> complexRoots(GenPolynomial a) { List> r = new ArrayList>(); ComplexRing cr = new ComplexRing(new BigDecimal(0.0, MathContext.DECIMAL64)); Complex cc = new Complex(cr); if (a == null || a.isZERO()) { r.add(cc); return r; } if (a.isConstant()) { return r; } a = a.monic(); UnivPowerSeriesRing pr = new UnivPowerSeriesRing(a.ring); UnivPowerSeries ps = pr.fromPolynomial(a); // Construct the companion matrix int N = (int) a.degree(); RealMatrix A = new Array2DRowRealMatrix(N, N); for (int i = 0; i < N; i++) { A.setEntry(i, N - 1, -ps.coefficient(i).getRational().doubleValue()); } for (int i = 1; i < N; i++) { A.setEntry(i, i - 1, 1.0); } //System.out.println("A = " + A); // compute eigenvalues EigenDecomposition ed = new EigenDecomposition(A); double[] realValues = ed.getRealEigenvalues(); double[] imagValues = ed.getImagEigenvalues(); //RealMatrix V = ed.getV(); //System.out.println("V = " + V); //RealMatrix D = ed.getD(); //System.out.println("D = " + D); // construct root list for (int i = 0; i < N; i++) { cc = new Complex(cr, new BigDecimal(realValues[i], MathContext.DECIMAL64), new BigDecimal(imagValues[i], MathContext.DECIMAL64)); //System.out.println("cc = " + cc + ", re = " + realValues[i] + ", im = " + imagValues[i]); r.add(cc); } return r; } } java-algebra-system-2.7.200/doc/000077500000000000000000000000001445075545500163035ustar00rootroot00000000000000java-algebra-system-2.7.200/doc/.gitignore000066400000000000000000000000401445075545500202650ustar00rootroot00000000000000/api /jython /jruby /jas-jython java-algebra-system-2.7.200/doc/COPYING000066400000000000000000000430761445075545500173500ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. java-algebra-system-2.7.200/doc/COPYING.jas000066400000000000000000000445321445075545500201220ustar00rootroot00000000000000 This is the Java Computer Algebra System (JAS) Copyright (C) 2000-2023, Heinz Kredel See Java Algebra System at http://krum.rz.uni-mannheim.de/jas/. 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 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. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy 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. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. java-algebra-system-2.7.200/doc/COPYING.lgpl000066400000000000000000000635001445075545500202770ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! java-algebra-system-2.7.200/doc/COPYING.lgpl.jas000066400000000000000000000652041445075545500210560ustar00rootroot00000000000000 This is the Java Computer Algebra System (JAS) Copyright (C) 2000-2023, Heinz Kredel See Java Algebra System at http://krum.rz.uni-mannheim.de/jas/. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! java-algebra-system-2.7.200/doc/Dockerfile000066400000000000000000000005551445075545500203020ustar00rootroot00000000000000FROM openjdk:11 MAINTAINER Heinz Kredel kredel@rz.uni-mannheim.de RUN apt-get -y update && apt-get -y upgrade RUN apt-get -y install junit4 liblog4j2-java jython jruby wget vim-tiny RUN wget -c http://krum.rz.uni-mannheim.de/jas/@DEBVERSION@.@SVNREV@-all.deb RUN dpkg -i @DEBVERSION@.@SVNREV@-all.deb RUN useradd -m mathlibre ENTRYPOINT su - mathlibre -c /bin/bash java-algebra-system-2.7.200/doc/TODO000066400000000000000000000163431445075545500170020ustar00rootroot00000000000000List of things to be resolved or accomplished: issues to consider: - implement Berlekamp-Zassenhaus for modular factorization - implement Musers multivariate factorization, evtl. with sparse Hensel lifting - implement real roots with other methods, e.g. after Uspensky or Rolle - implement complex roots with other methods, e.g. after Collins and Krandick - implement involutive bases computation - implement univariate power series composition and power - setup unit tests for JRuby and Jython methods and examples - make polynomial chinese remainder generic (?) - check / test caching results of gcd computation - algebraic number theory - algebraic topology - group theory, permutation groups - use further util.concurrent algorithms where possible, e.g. in DHT - remove unnecessary @see since JavaDoc 7 - implement matrices to vector - refactor from BasicLinAlg to GenMatrix and GenVector - implement Boolean with RingElem interface (?) - refactor method names for groovy operator overloading, make examples for usage partially resolved and completed issues: - rework parallel GB algorithms - rework distributed parallel GB algorithms - parallel modular algorithms - check solvable polynomials with integral domain coefficients - implement quaternion integers for non-commutative coefficients - implement other term orders for multivariate power series - implement multivariate Hensel lifting for multivariate polynomial factorization - implement 0-dim ideal complex root selection - implement absolute polynomial factorization - implement univaiate and multivariate polynomial factorization - implement signature based GB computation, only iterative done - implement Word ideal intersection, if possible - provide all Jython examples also for JRuby - provide a Sage Python like interface in Jython - implement parallel proxys for GB computation - refactor BigDecimal to RingElem and RingFactory, precision is now variable via context - check the 693 exceptions (including 473 runtime exceptions) that are thrown, reduce number of runtime exceptions - check for safe publication in constructors, check wrt. the (new) Java memory model - check and fix Findbugs warnings - make use of gcd in pseudo reduction, needs other coefficient type - add product category to applications - implement direct products of ring elements - define FieldElem and Field factory interfaces and use them for GB coefficients - check correct term order in recursive algorithms, in GCD ModEval only univariate cases are used, so term order is not a problem in polynomial factorization we force / convert to invlex term order - add assertions to check for number of polynomial variables and term order, nvar in GenPolynomial and GenSolvablePolynomial, done - use record classes and lambda expressions - make final variables public (?) - make hashCode to reuse computed value --> not immutable - add method bitLength() to Element - implement IDEALDIV2 with extGB - use Maven/Gradle/Buildr configuration management, Ivy done - make QuotSolvablePolynomial(Ring), LocalSolvablePolynomial(Ring) and ResidueSolvablePolynomial(Ring) unsused, except self tests. Only use QLRSolvablePolynomial(Ring) instead done - rework SPIN model checking with TLA+ parallel model checker https://en.wikipedia.org/wiki/TLA%2B https://lamport.azurewebsites.net/tla/tla.html resolved and completed issues: - implement TOP term orders for module Gröbner bases, done for some combinations - implement FGLM GB algorithm, done - implement Groebner Walk GB computation, done - implement squarefree decomposition over fields of characteristic p - implement AlgebraicNumber primitive element computation, done - design factories for (solvable) Gröbner bases, GCD computation, squarefree decomposition, factorization, extension fields - check inseparable field extension, done - implement prime and primary ideal decomposition for non-zero-dimensional ideals, done - implement prime and primary ideal decomposition for zero-dimensional ideals, done - implement multivariate power series, done - implement univariate power series, done - implement d- and e-reductions and d-/e-Groebner bases, done - implement Groebner bases for regular rings, done - implement comprehensive GB, done - refactor package structure to reduce circular dependences, done - implement term order optimization from MAS, also for coefficients and solvable polynomials, done - implement complex roots, done - implement construction of univariate polynomials in zero-dimensional ideals done - implement RealAlgebraicNumber and RealAlgebraicNumberRing, done - implement real roots with Sturm sequence, done - implement multivariate polynomial greatest common divisors, done - design and implement free non-commuative polynomials GenWordPolynomial, done - implement Mora's standard base algorithm for GenWordPolynomial - add methods to GenPolynomialRing to construct x_i polynomials, done - refactor univPoly in solvable implementations, done - develop modifiable polynomial constructor or put method and iterators - refactor unit tests to a different source code tree to avoid circular dependencies - provide scripting interfaces for JAS, done - rework junit tests to stop failing in case of zero polynomials - using git to publish the repository, done - rename divideAndRemainder to quotientRemainder - refactor the Quotient class to edu.jas.ufd package, done - implement ModLong for faster modular arithmetic, done - implement a global variable name generator in edu.jas.kern and use it in extend() and contract() done in GenPolynomialRing, undone in 2020 to avoid memory waste - add missing comments in edu.jas.Algebra*, done - let inverse() throw a runtime exception, done; throw a checked exception (?, no) - refactor Power with Java 8 features, use lambdas and default implementations, done - let arith implementations extend Power as abstract class add divide, subtract, abs, remainder to Power, name e.g RingElemAbstract clean structure of compareTo, signum and equals - is not possible -> but in Java 8 with default implentations, see next - define power(n) in MonoidElem with default implementation in edu.jas.structure.Power class, done - split ModInteger to ModIntegerRing factory, done - make logger variables also final, done - rename getval() to getVal() in ExpVector, done - refactor ExpVector for different array element types, done - incorporate gcd() in the Quotient class in edu.jas.application - implement BigDecimal with RingElem interface, done - make examples with rational function field coefficients, e.g. Raksanyi example - replace thread-and-network-programming algorithms with util.concurrent, done - add version information in jas jar-file names, done - split RingFactory to ElemFactory, done - split AlgebraicNumber to AlgebraicNumberRing factory, done - obsolete: check usage SDP (Socked Direct Protokol) with Java 7 and InfiniBand - refactor Hensel lifting to ufd package, not possible because of coefficient replacement trick is now in ufd package (must be done some how) - define quotientRemainder in MonoidElem interface with default implementation, done - completely switch from svn to git - remove @usage doc tag - extend mod integer factory interface by Iterable $Id$ java-algebra-system-2.7.200/doc/acknowledge.html000066400000000000000000000027251445075545500214620ustar00rootroot00000000000000 Acknowledgements

Acknowledgements

Since 2008 the development of the API design and the Jython scripting interface was done in cooperation with Raphael Jolly. Our joint developments have also been incorporated in a successor "ScAS" of his system jscl-meditor.

The development of JAS would not have been possible without various discussions with our colleagues, their constant support and their encouragement of our work. In particular we are indebted to Thomas Becker, Wolfgang K. Seiler, Thomas Sturm, Axel Kramer, Youssef Elbarbary, Jaime Gutierrez, Sherm Ostrowsky, Ted Kosan, Yosuke Sato, Peter Horn, Dongming Wang and Georg Thimm for various discussions on the design of and the requirements of typed object oriented computer algebra software.


Heinz Kredel

Last modified: Thu Jun 28 23:11:13 CEST 2018

java-algebra-system-2.7.200/doc/algo-ca-book.html000066400000000000000000000430631445075545500214320ustar00rootroot00000000000000 JAS - Algorithms for Computer Algebra book

Algorithms for Computer Algebra book and JAS methods

Summary of algorithms from the Algorithms for Computer Algebra book and corresponding JAS classes and methods.

Algorithms for Computer Algebra book

The JAS base package edu.jas name is omitted in the following table. JAS also contains improved versions of the algorithms which may be located through the links. A short explanation of code organization with interfaces and several implementing classes can be found in the API guide.

Algorithms for Computer Algebra JAS interfaces, classes and methods remarks
2.1 Euclidean Algorithm, Euclid structure.RingElem.gcd all classes which implement this interface
2.2 Extended Euclidean Algorithm, EEA structure.RingElem.egcd all classes which implement this interface
2.3 Primitive Euclidean Algorithm, PrimitiveEuclidean ufd.GreatestCommonDivisorPrimitive
 
4.1 Multiprecision Integer Multiplication, BigIntegerMultiply BigInteger.multiply adapter for native Java implementation in java.math.BigInteger.multiply
4.2 Karatsuba's Multiplication Algorithm, Karatsuba implemented in java.math.BigInteger.multiply
4.3 Polynomial Trial Division Algorithm, TrialDivision not implemented see GenPolynomial.divide and PolyUtil.basePseudoDivide
4.4 Fast Fourier Transform, FFT not implemented
4.5 Fast Fourier Polynomial Multiplication, FFT_Multiply not implemented
4.6 Newtons's Method for Power Series Inversion, FastNewtonInversion not implemented see UnivPowerSeries.inverse() and MultiVarPowerSeries.inverse()
4.7 Newtons's Method for Solving P(y) = 0, NewtonSolve not implemented see UnivPowerSeriesRing.solveODE()
 
5.1 Garner's Chinese Remainder Algorithm, IntegerCRA ModIntegerRing.chineseRemainder() only for two moduli
5.2 Newtons Interpolation Algorithm, NewtonInterp not implemented see PolyUtil.chineseRemainder() and PolyUtil.interpolate()
 
6.1 Univariate Hensel Lifting Algorithm, UnivariateHensel HenselUtil.liftHensel()
6.2 Multivariate Polynomial Diophantine Equantions, MultivariateDiophant HenselMultUtil.liftDiophant()
6.3 Univariate Polynomial Diophantine Equantions, UnivariateDiophant HenselUtil.liftDiophant()
6.4 Multivariate Hensel Lifting Algorithm, MultivariateHensel HenselMultUtil.liftHensel()
 
7.1 Modular GCD Algorithm, MGCD GreatestCommonDivisorModular. baseGcd()
7.2 Multivariate GCD Reduction Algorithm, PGCD GreatestCommonDivisorModEval.gcd()
GreatestCommonDivisorSubres.gcd() many more algorithms, for example using polynomial remainder sequences (PRS), in particular a sub-resultant PRS
7.3 Extended Zassenhaus GCD Algorithm, EZ-GCD GreatestCommonDivisorHensel. recursiveUnivariateGcd() not complete in all cases
7.4 GCD Heuristic Algorithm, GCDHEU not implemented
 
8.1 Square-Free Factorization, SquareFree SquarefreeFieldChar0. squarefreeFactors()
8.2 Yun's Square-Free Factorization, SquareFree2 SquarefreeFieldChar0Yun. squarefreeFactors()
8.3 Finite Field Square-Free Factorization, SquareFreeFF SquarefreeFiniteFieldCharP. squarefreeFactors()
SquarefreeInfiniteFieldCharP. squarefreeFactors() Algorithm for infinite fields of characteristic p, not in the book.
8.4 Berlekamp's Factorization Algorithm, Berlekamp FactorModularBerlekamp. baseFactorsSquarefree() The method baseFactorsSquarefreeSmallPrime() contains the implementation.
8.5 Form Q Matrix, FormMatrixQ PolyUfdUtil.constructQmatrix()
8.6 Null Space Basis Algorithm, NullSpaceBasis LinAlg.nullSpaceBasis()
8.7 Big Prime Berlekamp Factoring Algorithm, BigPrimeBerlekamp FactorModularBerlekamp. baseFactorsSquarefree() The method baseFactorsSquarefreeBigPrime() contains the implementation.
8.8 Distinct Degree Factorization I, PartialFactorDD FactorModular. baseDistinctDegreeFactors()
8.9 Distinct Degree Factorization II, SplitDD FactorModular. baseEqualDegreeFactors()
FactorInteger.factorsSquarefree() Algorithm of P. Wang, not presented in the book.
8.10 Factorization over Algebraic Number Fields, AlgebraicFactorization FactorAlgebraic. baseFactorsSquarefree()
 
9.1 Fraction-Free Gaussian Elimination, FractionFreeElim LinAlg. fractionfreeGaussElimination() see also GroebnerBasePseudoSeq.GB()
9.2 Nonlinear Elimination Algorithm, NonlinearElim not implemented Based on iterated resultant computations. See also the characteristic set method CharacteristicSetSimple.characteristicSet()
9.3 Solution of Nonlinear System of Equations, NonlinearSolve not implemented Based on resultant computations and algebraic root substitution. See also the ideal complex and real root computation and decomposition methods PolyUtilApp.complexAlgebraicRoots()
 
10.1 Full Reduction Algorithm, Reduce Reduction.normalform() all classes which implement this interface
10.2 Buchbergers's Algorithm for Gröbner Bases, Gbasis not implemented
10.3 Construction of a Reduced Ideal Basis, ReduceSet GroebnerBase.minimalGB() all classes which implement this interface
10.4 Improved Construction of a Reduced Gröbner Basis, Gbasis GroebnerBaseSeq.GB() can be parametrized also with different strategies, e.g. Gebauer & Möller
10.5 Solution of System P in Variable x, Solve1 Ideal.constructUnivariate() univariate polynomials of minimal degree in the ideal
10.6 Complete Solution of System P, GröbnerSolve Ideal.zeroDimDecomposition(), univariate polynomials in the ideal are irreducible
10.7 Solution of P using Lexicographic Gröbner Basis, LexSolve Ideal.zeroDimRootDecomposition() additionally to 10.6, the ideal basis consists of maximally bi-variate polynomials
 
11.1 Hermite's Method for Rational Functions, HermiteReduction ElementaryIntegration. integrateHermite()
11.2 Horowitz's Reduction for Rational Functions, HorowitzReduction ElementaryIntegration.integrate()
11.3 Rothstein/Trager method, LogarithmicPartIntegral ElementaryIntegration. integrateLogPart() using resultants
11.4 Lazard/Rioboo/Trager improvement, LogarithmicPartIntegral ElementaryIntegrationLazard. integrateLogPart() using sub-resultants
11.x Czichowski variant, LogarithmicPartIntegral ElementaryIntegrationCzichowski. integrateLogPart() using Gröbner bases
11.y Bernoulli variant, LogarithmicPartIntegral ElementaryIntegrationBernoulli. integrateLogPart() using absolute factorization into linear factors


Heinz Kredel

Last modified: Sat Aug 7 19:41:34 CEST 2021

java-algebra-system-2.7.200/doc/contribute.html000066400000000000000000000060661445075545500213570ustar00rootroot00000000000000 Contributing to JAS

Contributing to JAS

Follow these guidelines if you'd like to contribute to the JAS project.

If you have any questions about using or developing for this project, send me an email [1].

Issues and Bugs

Submit an issue [2] or pull request [3] with a fix if you find any bugs in the project. See below (submitting pull requests) for instructions on sending in pull requests.

When submitting an issue or pull request, make sure you're as detailed as possible and fill in all answers to questions asked in the templates. For example, an issue that simply states "xyz isn't working!" will be ignored.

Feature Requests

Submit an issue [2] to request a new feature. Features fall into one of two categories:

  • Major: Major changes should be discussed with me via email [1]. I'm always open to suggestions and will get back to you as soon as I can!
  • Minor: A minor feature can simply be added via a pull request [3].

Submitting Pull Requests

Before you do anything, make sure you check the current list of pull requests [4] to ensure you aren't duplicating anyone's work. Then, do the following:

  1. Fork the repository and make your changes in a git branch: `git checkout -b my-branch master`
  2. Make sure your feature or fix doesn't break the project! Test thoroughly.
  3. Commit your changes, and be sure to leave a detailed commit message.
  4. Push your branch to your forked repo on any Git server: `git push origin my-branch`
  5. Submit a pull request [3] and hold tight!
  6. If any changes are requested by the project maintainers, make them and follow this process again until the changes are merged.
  1. mail to me
  2. new issue
  3. new pull request
  4. pull requests

Heinz Kredel

Last modified: Sat Aug 4 12:59:45 CEST 2018

java-algebra-system-2.7.200/doc/design.html000066400000000000000000001447541445075545500204610ustar00rootroot00000000000000 JAS - API Design

API usage and design overview

In ths document we give an overview on the structure of the interfaces, classes and packages of JAS. In the first section we show how to compute Legendre polynomials with the JAS API. In the next three sections we focus on the structure of the required types and the creation of the corresponding objects. In the following three sections we focus on the functional aspects of the types, i.e. their constructors and methods. For a discussion of other design alternatives see the problems document. Further programming issues and bugs are listed in the Findbugs report.

1. Getting started

You can use whatever environment for programming in Java you like. The next picture shows the usage of Eclipse, but any text editor and a Java compiler will do as well.

JAS in Eclipse IDE
 
JAS program to compute Legendre polynomials in the Eclipse IDE

1.1. Computation of the Legendre polynomials

At first we present an example for the usage of the JAS API with the computation of the Legendre polynomials. The Legendre polynomials can be defined by the following recursion
  • P[0](x) = 1
  • P[1](x) = x
  • P[n](x) = 1/n ( (2n-1) x P[n-1] - (n-1) P[n-2] ).
The first 10 Legendre polynomials are:
P[0] = 1 
P[1] = x
P[2] = 3/2 x^2 - 1/2 
P[3] = 5/2 x^3 - 3/2 x
P[4] = 35/8 x^4 - 15/4 x^2 + 3/8 
P[5] = 63/8 x^5 - 35/4 x^3 + 15/8 x
P[6] = 231/16 x^6 - 315/16 x^4 + 105/16 x^2 - 5/16 
P[7] = 429/16 x^7 - 693/16 x^5 + 315/16 x^3 - 35/16 x
P[8] = 6435/128 x^8 - 3003/32 x^6 + 3465/64 x^4 - 315/32 x^2 + 35/128 
P[9] = 12155/128 x^9 - 6435/32 x^7 + 9009/64 x^5 - 1155/32 x^3 + 315/128 x

The polynomials have been computed with the following Java program. First we need a polynomial ring ring over the rational numbers, in one variable "x" and a list P to store the computed polynomials. The polynomial factory object itself needs at least a factory for the creation of coefficients and the number of variables. Additionally the term order and names for the variables can be specified. With this information the polynomial ring factory can be created by new GenPolynomialRing <BigRational>(fac,1,var), where fac is the coefficient factory, 1 is the number of variables, and var is an String array of names.

    BigRational fac = new BigRational();
    String[] var = new String[]{ "x" };
    GenPolynomialRing<BigRational> ring
        = new GenPolynomialRing<BigRational>(fac,1,var);

    int n = 10;
    List<GenPolynomial<BigRational>> P 
       = new ArrayList<GenPolynomial<BigRational>>(n);
    GenPolynomial<BigRational> t, one, x, xc;
    BigRational n21, nn;

    one = ring.getONE();
    x   = ring.univariate(0);

    P.add( one );
    P.add( x );
    for ( int i = 2; i < n; i++ ) {
        n21 = new BigRational( 2*i-1 );
        xc = x.multiply( n21 );
        t = xc.multiply( P.get(i-1) );  // (2n-1) x P[n-1]
        nn = new BigRational( i-1 );
        xc = P.get(i-2).multiply( nn ); // (n-1) P[n-2]
        t = t.subtract( xc );
        nn = new BigRational(1,i);      
        t = t.multiply( nn );           // 1/n t
        P.add( t );
    }
    for ( int i = 0; i < n; i++ ) {
        System.out.println("P["+i+"] = " + P.get(i).toString(var) );
        System.out.println();
    }

The polynomials for the recursion base are one and x. Both are generated from the polynomial ring factory with method ring.getONE() and ring.univariate(0), respectively. The polynomial (2n-1)x is produced in the for-loop by n21 = new BigRational( 2*i-1 ); and xc = x.multiply( n21 );. The polynomial (n-1) P[n-2] is computed by nn = new BigRational( i-1 ); and xc = P.get(i-2).multiply( nn ). Finally we have to multiply the difference of the intermediate polynomials by 1/i as nn = new BigRational( 1, i ); and t = t.multiply( nn ). Then, in the for-loop, the polynomials P[i] are computed using the definition, and stored in the list P for further use. In the last for-loop, the polynomials are printed, producing the output shown above. The string representation of the polynomial object can be created, as expected, by toString(), or by using names for the variables with toString(var). The imports required are

import java.util.ArrayList;
import java.util.List;
import edu.jas.arith.BigRational;
import edu.jas.poly.GenPolynomial;
import edu.jas.poly.GenPolynomialRing;

To use other coefficient rings, one simply changes the generic type parameter, say, from BigRational to BigComplex and adjusts the coefficient factory. The factory would then be created as c = new BigComplex(), followed by new GenPolynomialRing<BigComplex> (c,1,var). This small example shows that this library can easily be used, just as any other Java package or library.

In the following sections we describe the central classes and interfaces for the polynomial API.

1.2. Algebraic structures overview

To get an idea of the scope of JAS we summarize the implemented algebraic structures and of the implemented algebraic algorithms.

class factory structure methods
BigInteger self ring of arbitrary precision integers, a facade for java.math.BigInteger arithmetic, gcd, primality test
BigRational self ring of arbitrary precision rational numbers, i.e. fractions of integers, with Henrici optimizations for gcds arithmetic
ModInteger, ModLong, ModInt ModIntegerRing, ModLongRing, ModIntRing ring of integers modulo some fixed (long) integer or an arbitrary precision integer n, if n is a prime number, the ring is a field arithmetic, chinese remainder
BigDecimal self ring of arbitrary precision floating point numbers, a facade for java.math.BigDecimal arithmetic, compareTo() with given precision
BigComplex self ring of arbitrary precision complex numbers, i.e. pairs of rational numbers arithmetic
BigDecimalComplex self ring of arbitrary precision complex floating point numbers, i.e. pairs of BigDecimal numbers arithmetic, compareTo() with given precision
BigQuaternion self ring of arbitrary precision quaternion numbers, i.e. quadruples of rational numbers arithmetic
BigOctonion self ring of arbitrary precision octonion numbers, i.e. implemented as pairs of quaternion numbers arithmetic
GenPolynomial GenPolynomialRing ring of polynomials in r variables over any implemented coefficient ring with respect to any implemented term ordering arithmetic, univariate gcd, norms, chinese remainders for coefficients, evaluation
AlgebraicNumber AlgebraicNumberRing ring of algebraic numbers, represented as univariate polynomials over any implemented coefficient field arithmetic
RealAlgebraicNumber RealAlgebraicRing ring of real algebraic numbers, represented as algebraic number and an isolating interval for a real root over rational numbers or real algebraic numbers arithmetic, real sign, magnitude
ComplexAlgebraicNumber ComplexAlgebraicRing ring of complex algebraic numbers, represented as algebraic number and an isolating rectangle for a complex root over rational numbers as base ring arithmetic, sign invariant rectangle, magnitude
GenSolvablePolynomial GenSolvablePolynomialRing ring of non-commutative, solvable polynomials in r variables over any implemented coefficient ring with respect to any implemented term ordering (compatible with the multiplication) arithmetic
GenWordPolynomial GenWordPolynomialRing ring of free non-commutative polynomials in r letters over any implemented coefficient ring with respect to a graded term ordering arithmetic
RecSolvable Polynomial, QuotSolvable Polynomial, ResidueSolvable Polynomial, LocalSolvable Polynomial, QLRSolvablePolynomial RecSolvable PolynomialRing, QuotSolvable PolynomialRing, ResidueSolvable PolynomialRing, LocalSolvable PolynomialRing, QLRSolvablePolynomialRing ring of recursive, solvable polynomials in r variables over a solvable polynomial coefficient ring over any implemented coefficient ring with respect to any implemented term ordering (compatible with the multiplication). The other variants have coefficient rings SolvableQuotient, SolvableResidue and SolvableLocal which are all based on solvable polynomials. The QLRSolvablePolynomial is a unification of the others. arithmetic
Quotient QuotientRing ring of rational functions, i.e. fractions of multivariate polynomials over any implemented commutative unique factorization coefficient domain arithmetic
SolvableQuotient SolvableQuotientRing ring of rational functions, i.e. fractions of multivariate solvable polynomials (satisfying the left-, right-Ore condition) over some implemented coefficient domains arithmetic
Residue ResidueRing ring of polynomials modulo a given polynomial ideal, over any implemented commutative coefficient ring arithmetic
SolvableResidue SolvableResidueRing ring of polynomials modulo a given polynomial ideal, over some implemented coefficient domains arithmetic
Local LocalRing ring of polynomials fractions localized with respect to a given polynomial ideal, over any implemented commutative coefficient ring arithmetic
SolvableLocal SolvableLocalRing ring of solvable polynomials fractions localized with respect to a given solvable polynomial ideal, over some implemented coefficient rings arithmetic
SolvableLocalResidue SolvableLocalResidueRing ring of solvable polynomials fractions localized with respect to a given solvable polynomial ideal and modulo the given polynomial ideal, over some implemented coefficient rings arithmetic
Product ProductRing (finite) direct product of fields and rings over any implemented coefficient ring arithmetic, idempotent elements
GenVector GenVectorModule tuples (vectors) of any implemented ring elements arithmetic, scalar product
GenMatrix GenMatrixModule matrices of any implemented ring elements arithmetic, scalar product
UnivPowerSeries UnivPowerSeriesRing ring of univariate power series over any implemented coefficient ring arithmetic, gcd, evaluation, integration, fixed points
MultiVarPowerSeries MultiVarPowerSeriesRing ring of multivatiate power series over any implemented coefficient ring arithmetic, evaluation, integration, fixed points
Quotient QuotientRing ring of fractions over any implemented (unique factorization domain) ring arithmetic
Residue ResidueRing ring of elements modulo a given (main) ideal, over any implemented ring arithmetic
Local LocalRing ring of fractions localized with respect to a given (main) ideal, over any implemented ring arithmetic
Complex ComplexRing ring of complex numbers over any implemented ring (with gcd) arithmetic

"Arithmetic" means implementation of the methods defined in the interface RingElem. As of 2021-03 there are 36 rings implemented (9 explicit, others generic). To be continued.

1.3. Algebraic algorithms overview

The following table contains an overview of implemented algebraic algorithms.

class / interface algorithm                                                                  methods
Reduction, ReductionAbstract, ReductionSeq, ReductionPar, PseudoReduction Iterated subtraction of polynomials to eliminate terms from a given polynomial, i.e. reduction of polynomial(s) wrt. a set of polynomials. Coefficients of polynomials must be from a field and for the Pseudo* version from a ring with gcd. For *Par the list of polynomials can concurrently be modified. normalform, S-polynomial, criterions, extended normalform
DReduction, EReduction, DReductionSeq, EReductionSeq Reduction of polynomial(s) wrt. a set of polynomials. Coefficients of polynomials must be from a principial ideal domain (PID) or from an Euclidean domain. normalform, S-polynomial, G-polynomial, criterions, extended normalform
SolvableReduction, SolvableReductionAbstract, SolvableReductionSeq, SolvableReductionPar, SolvablePseudoReduction Left and right reduction of solvable polynomial(s) wrt. a set of solvable polynomials. Coefficients of polynomials must be from a field and for the Pseudo* version from a ring with gcd. left/right normalform, left/right S-polynomial, criterions, extended left normalform
RReduction, RPseudoReduction, RReductionSeq, RPseudoReductionSeq Iterated subtraction of polynomials to eliminate terms from a given polynomial, i.e. reduction of polynomial(s) wrt. a set of polynomials. Coefficients of polynomials must be from a regular ring and for the Pseudo* version from a regular ring with gcd. Boolean closure and boolean remainder of polynomials. normalform, S-polynomial, boolean closure
CReductionSeq, Condition, ColorPolynomial Iterated subtraction of polynomials to eliminate terms from a given polynomial, i.e. reduction of polynomial(s) wrt. a set of polynomials. Coefficients of polynomials must be from a polynomial ring. Case distinction and determination of polynomaials with respect to conditions leading to colored polynomials. normalform, S-polynomial, color, determine
GroebnerBase, GroebnerBaseAbstract, GroebnerBaseSeq, GroebnerBaseParallel, GroebnerBaseDistributed, GroebnerBasePseudoSeq etc. Buchberger algorithm to compute Groebner bases of sets of polynomials. Coefficients of polynomials must be from a field. *Parallel is a multi-threaded and *Distributed is a message passing implementation. The *Pseudo versions are for coefficient domains with gcd. GB, isGB, extended GB, minimal GB
DGroebnerBaseSeq, EGroebnerBaseSeq Algorithm to compute D- and E- Groebner bases of sets of polynomials. Coefficients of polynomials must be from a principial ideal domain (PID) or from an Euclidean domain. GB, isGB, minimal GB
SolvableGroebnerBase, SolvableGroebnerBaseAbstract, SolvableGroebnerBaseSeq, SolvableGroebnerBaseParallel, SolvableGroebnerBasePseudoSeq Algorithm to compute left, right and two-sided Groebner bases of sets of solvable polynomials. Coefficients of polynomials must be from a field. Parallel is a multi-threaded implementation. The *Pseudo versions are for coefficient domains with gcd. left, right, two-sided versions of GB, isGB, extended GB, minimal GB
WordGroebnerBase, WordGroebnerBaseAbstract, WordGroebnerBaseSeq, WordGroebnerBasePseudoSeq Algorithm to compute two-sided Groebner bases of sets of free non-commutative polynomials. Coefficients of polynomials must be from a field. The *Pseudo versions are for coefficient domains with gcd. two-sided versions of GB, isGB, minimal GB
RGroebnerBaseSeq, RGroebnerBasePseudoSeq Algorithm to compute Groebner bases in polynomial rings over regular rings. Coefficients of polynomials must be from a product of fields or Euclidean domains. GB, isGB, minimal GB
ComprehensiveGroebnerBaseSeq, GroebnerSystem, ColoredSystem Algorithm to compute comprehensive Groebner bases in polynomial rings over parameter rings. Coefficients of polynomials must be from a polynomial ring. Computation is done via Groebner systems (lists of colored systems). GBsys, isGBsys, GB, isGB, minimalGB
Syzygy, SyzygyAbstract, ModGroebnerBase, ModGroebnerBaseAbstract Algorithm to compute syzygies of lists of polynomials or Groebner Bases, free resolutions. Groebner Bases for modules over polynomial rings. Coefficients of polynomials must be from a field. zeroRelations, isZeroRelation, resolution, zeroRelationsArbitrary, GB, isGB
SolvableSyzygy, SolvableSyzygyAbstract, ModSolvableGroebnerBase, ModSolvableGroebnerBaseAbstract Algorithm to compute left and right syzygies of lists of solvable polynomials or Groebner Bases, free left resolutions. Left, right and two-sided Groebner Bases for modules over solvable polynomial rings. Coefficients of polynomials must be from a field. leftZeroRelations, rightZeroRelations, isLeftZeroRelation, isRightZeroRelation, (left) resolution, zeroRelationsArbitrary, leftOreCond, rightOreCont(ition), left, right, two-sided GB, isGB
ReductionSeq, StandardBaseSeq, etc. Mora's tangent cone reduction algorithm and computation of standard bases of sets of multivariate power series. Coefficients of polynomials must be from a field. STD, isSTD, minimalSTD, normalForm, SPolynomial
Ideal Algorithms to compute sums, products, intersections, containment and (infinite) quotients of polynomial ideals. Coefficients of polynomials must be from a field. Prime, primary, irreducible and radical decomposition of zero dimensional ideals. Prime, primary, irreducible and radical decomposition of non-zero dimensional ideals. Univariate polynomials of minimal degree in ideal as well as elimination, extension and contraction ideals. sum, product, intersect, contains, quotient, infiniteQuotient, inverse modulo ideal, zeroDimRadicalDecomposition, zeroDimPrimeDecomposition, zeroDimPrimaryDecomposition, zeroDimDecomposition, zeroDimRootDecomposition, radicalDecomposition, primeDecomposition, decomposition, primaryDecomposition
SolvableIdeal Algorithms to compute sums, products, intersections, containment and (infinite) quotients of solvable polynomial ideals. Coefficients of solvable polynomials must be from a field. sum, product, intersect, contains, quotient, infiniteQuotient, inverse modulo ideal, univariate polynomials of minimal degree in ideal
WordIdeal Algorithms to compute sums, products, and containment word polynomial ideals (free algebra twosided ideals). Coefficients of word polynomials must be from a field. sum, product, contains
GreatestCommonDivisor, GCDFactory, GreatestCommonDivisorAbstract, GreatestCommonDivisorSimple, GreatestCommonDivisorPrimitive, GreatestCommonDivisorSubres, GreatestCommonDivisorModular, GreatestCommonDivisorModEval, GCDProxy Algorithms to compute greatest common divisors of polynomials via different polynomial remainder sequences (PRS) and modular methods. Coefficients of polynomials must be from a unique factorization domain (UFD). GCDFactory helps with the optimal selection of an algorithm and GCDProxy uses multi-threading to compute with several implementations in parallel. gcd, lcm, content, primitivePart, resultant, coPrime
Squarefree, SquarefreeFactory, SquarefreeAbstract, SquarefreeFieldChar0, SquarefreeFieldCharP, SquarefreeFiniteFieldCharP, SquarefreeInfiniteFieldCharP, Squarefree- InfiniteAlgebraicFieldCharP, SquarefreeRingChar0 Algorithms to compute squarefree decomposition of polynomials over fields of characteristic zero, finite and infinite fields of characteristic p and other coefficients from unique factorization domains (UFD). SquarefreeFactory helps with the optimal selection of an algorithm. squarefreePart, squarefreeFactors, isFactorization, isSquarefree, coPrimeSquarefree
Factorization, FactorFactory, FactorAbstract, FactorAbsolute, FactorModular, FactorInteger, FactorRational, FactorAlgebraic Algorithms to compute factorizations of polynomials as products of irreducible polynomials over different ground rings. FactorFactory helps with the correct selection of an algorithm. Reduction of the multivariate factorization to an univariate factorization is done with Kronecker's algorithm in the general case and with Wang's algorithm over the integers. squarefreeFactors, factors, baseFactors, isIrreducible, isReducible, isSquarefree, isFactorization, isAbsoluteIrreducible, factorsAbsolute
RealRoots, RealRootsAbstract, RealRootsSturm Algorithms to compute isolating intervals for real roots and for refinement of isolating intervals to any prescribed precision. Algorithms to compute the sign of a real algebraic numer and the magnitude of a real algebraic number to a given precision. Coefficients of polynomials must be from a real field, for example from BigRational or RealAlgebricNumber. realRoots, refineInterval, algebraicSign, algebraicMagnitude
ComplexRoots, ComplexRootsAbstract, ComplexRootsSturm Algorithms to compute isolating rectangles for complex roots and for refinement of isolating rectangles to any prescribed precision. Coefficients of polynomials must be of type Complex field. complexRoots, complexRootCount, complexRootRefinement
ElementaryIntegration Algorithms to compute elementary integrals of univariate rational functions. integrate, integrateHermite, integrateLogPart, isIntegral
CharacteristicSet, CharacteristicSetSimple, CharacteristicSetWu Algorithms to compute simple or Wu-Ritt characteristic sets. characteristicSet, isCharacteristicSet, characteristicSetReduction

1.4. Packages and components overview

Package and component structure overview

More details can be found in the JDepend report.txt.

2. Recursive ring element design

The next figure gives an overview of the central interfaces and classes. The interface RingElem defines a recursive type which defines the functionality (see next section) of the polynomial coefficients and is also implemented by the polynomials itself. So polynomials can be taken as coefficients for other polynomials, thus defining a recursive polynomial ring structure.

Since the construction of constant ring elements has been difficult in previuos designs, we separated the creational aspects of ring elements into ring factories with sufficient context information. The minimal factory functionality is defined by the interface RingFactory. Constructors for polynomial rings will then require factories for the coefficients so that the construction of polynomials over these coefficient rings poses no problem. The ring factories are additionaly required because of the Java generic type design. I.e. if C is a generic type name it is not possible to construct an new object with new C(). Even if this would be possible, one can not specify constructor signatures in Java interfaces, e.g. to construct a one or zero constant ring element. Recursion is again achieved by using polynomial factories as coefficient factories in recursive polynomial rings. Constructors for polynomials will always require a polynomial factory parameter which knows all details about the polynomial ring under consideration.

JAS type overview
UML diagram of JAS types

3. Coefficients and polynomials

We continue the discussion of the next layer of classes in the the above figure.

Elementary coefficient classes, such as BigRational or BigInteger, implement both the RingElem and RingFactory interfaces. This is convenient, since these factories do not need further context information. In the implementation of the interfaces the type parameter C extends RingElem<C> is simultaneously bound to the respective class, e.g. BigRational. Coefficient objects can in most cases created directly via the respective class constructors, but also via the factory methods. E.g. the object representing the rational number 2 can be created by new BigRational(2) or by fac = new BigRational(), fac.fromInteger(2) and the object representing the rational number 1/2 can be created by new BigRational(1,2) or by fac.parse("1/2").

Generic polynomials are implemented in the GenPolynomial class, which has a type parameter C extends RingElem<C> for the coefficient type. So all operations on coefficients required in polynomial arithmetic and manipulation are guaranteed to exist by the RingElem interface. The constructors of the polynomials always require a matching polynomial factory. The generic polynomial factory is implemented in the class GenPolynomialRing, again with type parameter C extends RingElem<C> (not RingFactory). The polynomial factory however implements the interface RingFactory<C extends RingElem<C>> so that it can also be used recursively. The constructors for GenPolynomialRing require at least parameters for a coefficient factory and the number of variables of the polynomial ring.

Having generic polynomial and elementary coefficient implementations one can attempt to construct polynomial objects. The type is first created by binding the type parameter C extends RingElem<C> to the desired coefficient type, e.g. BigRational. So we arrive at the type GenPolynomial<BigRational>. Polynomial objects are then created via the respective polynomial factory of type GenPolynomialRing<BigRational>, which is created by binding the generic coefficient type of the generic polynomial factory to the desired coefficient type, e.g. BigRational. A polynomial factory object is created from a coefficient factory object and the number of variables in the polynomial ring as usual with the new operator via one of its constructors. Given an object coFac of type BigRational, e.g. created with new BigRational(), a polynomial factory object pfac of the above described type could be created by new GenPolynomialRing<BigRational>(coFac,5). I.e. we specified a polynomial ring with 5 variables over the rational numbers. A polynomial object p of the above described type can then be created by any method defined in RingFactory, e.g. by pfac.getONE(), pfac.fromInteger(1), pfac.random(3) or pfac.parse("(1)").

Since GenPolynomial itself implements the RingElem interface, they can also be used recursively as coefficients. We continue the polynomial example and are going to use polynomials over the rational numbers as coefficients of a new polynomial. The type is then GenPolynomial<GenPolynomial<BigRational>> and the polynomial factory has type GenPolynomialRing<GenPolynomial<BigRational>>. Using the polynomial coefficient factory pfac from above a recursive polynomial factory rfac could be created by new GenPolynomialRing<GenPolynomial<BigRational>>(pfac,3). The creation of a recursive polynomial object r of the above described type is then as a easy as before e.g. by rfac.getONE(), rfac.fromInteger(1) or rfac.random(3).

4. Solvable polynomials

We turn now to the last layer of classes in the the above figure.

The generic polynomials are intended as super class for further types of polynomial rings. As one example we take so called solvable polynomials, which are like normal polynomials but are equipped with a new non-commutative multiplication. They are implemented in the class GenSolvablePolynomial which extends GenPolynomial and inherits all methods except clone() and multiply(). The class also has a type parameter C extends RingElem<C> for the coefficient type. Note, that the inherited methods are in fact creating solvable polynomials since they employ the solvable polynomial factory for the creation of any new polynomial internally. Only the formal method return type is that of GenPolynomial, the run-time type is GenSolvablePolynomial to which they can be casted at any time. The factory for solvable polynomials is implemented by the class GenSolvablePolynomialRing which also extends the generic polynomial factory. So this factory can also be used in the constructors of GenPolynomial via super() to produce in fact solvable polynomials internally. The data structure is enhanced by a table of non-commutative relations defining the new multiplication. The constructors delegate most things to the corresponding super class constructors and additionally have a parameter for the RelationTable to be used. Also the methods delegate the work to the respective super class methods where possible and then handle the non-commutative multiplication relations separately.

The construction of solvable polynomial objects follows directly that of polynomial objects. The type is created by binding the type parameter C extends RingElem<C> to the desired coefficient type, e.g. BigRational. So we have the type GenSolvablePolynomial<BigRational>. Solvable polynomial objects are then created via the respective solvable polynomial factory of type GenSolvablePolynomialRing<BigRational>, which is created by binding the generic coefficient type of the generic polynomial factory to the desired coefficient type, e.g. BigRational. A solvable polynomial factory object is created from a coefficient factory object, the number of variables in the polynomial ring and a table containing the defining non-commutative relations as usual with the new operator via one of its constructors. Given an object coFac of type BigRational as before, a polynomial factory object spfac of the above described type could be created by new GenSolvablePolynomialRing<BigRational>(coFac,5). I.e. we specified a polynomial ring with 5 variables over the rational numbers with no commutator relations. A solvable polynomial object p of the above described type can then be created by any method defined in RingFactory, e.g. by spfac.getONE(), spfac.fromInteger(1), spfac.random(3) or spfac.parse("(1)"). Some care is needed to create RelationTable objects since its constructor requires the solvable polynomial ring which is under construction as parameter. It is most convenient to first create a GenSolvablePolynomialRing with an empty relation table and then to add the defining relations.

5. Ring element and factory functionality

The following sections and the next figure gives an overview of the functionality of the main interfaces and polynomial classes.

The RingElem interface has a generic type parameter C which is constrained to a type with the same functionality C extends RingElem<C>. It defines the usual methods required for ring arithmetic such as C sum(C S); C subtract(C S); C negate(); C abs(); C multiply(C S); C divide(C S); C remainder(C S); C inverse(); Although the actual ring may not have inverses for every element or some division algorithm we have included these methods in the definition. In a case where there is no such function, the implementation may deliberately throw a RuntimeException or choose some other meaningful element to return. The method isUnit() can be used to check if an element is invertible.

Besides the arithmetic method there are following testing methods boolean isZERO(); boolean isONE(); boolean isUnit(); int signum(); boolean equals(Object b); int hashCode(); int compareTo(C b); The first three test if the element is 0, 1 or a unit in the respective ring. The signum() method defines the sign of the element (in case of an ordered ring). equals(), hashCode() and compareTo() are required to keep Javas object machinery working in our sense. They are used when an element is put into a Java collection class, e.g. Set, Map or SortedMap. The last method C clone() can be used to obtain a copy of the actual element. As creational method one should better use the method C copy(C a) from the ring factory, but in Java it is more convenient to use the clone() method.

As mentioned before, the creational aspects of rings are separated into a ring factory. A ring factory is intended to store all context information known or required for a specific ring. Every ring element should also know its ring factory, so all constructors of ring element implementations require a parameter for the corresponding ring factory. Unfortunately constructors and their signature can not be specified in a Java interface. The RingFactory interface also has a generic type parameter C which is constrained to a type with the ring element functionality C extends RingElem<C>. The defined methods are C getZERO(); C getONE(); C fromInteger(long a); C fromInteger(java.math.BigInteger a); C random(int n); C copy(C c); C parse(String s); C parse(Reader r); The first two create 0 and 1 of the ring. The second two are used to embed a natural number into the ring and create the corresponding ring element. The copy() method was intended as the main means to obtain a copy of a ring element, but it is now no more used in our implmentation. Instead the clone() method is used from the ring element interface. The random(int n) method creates a random element of the respective ring. The parameter n specifies an appropriate maximal size for the created element. In case of coefficients it usually means the maximal bit-length of the element, in case of polynomials it influences the coefficient size and the degrees. For polynomials there are random() methods with more parameters. The two methods C parse(String s) and C parse(Reader r) create a ring element from some external string representation. For coefficients this is mostly implemented directly and for polynomials the class GenPolynomialTokenizer is employed internally. In the current implementation the external representation of coefficients may never contain white space and must always start with a digit. In the future the ring factory will be enhanced by methods that test if the ring is commutative, associative or has some other important property or the value of a property, e.g. is an euclidean ring, is a field, an integal domain, a uniqe factorization domain, its characteristic or if it is noetherian.

JAS type functionality
UML diagram of JAS type functionality

6. Polynomial and polynomial factory functionality

We continue the discussion of the above figure with the generic polynomial and factory classes.

The GenPolynomial class has a generic type parameter C which is constrained to a type with the functionality of ring elements C extends RingElem<C>. Further the class implements a RingElem over itself RingElem<GenPolynomial<C>> so that it can be used for the coefficients of an other polynomial ring. The functionality of the ring element methods has already been explained in the previous section. There are two public and one protected constructors, each requires at least a ring factory parameter GenPolynomialRing<C> r. The first creates a zero polynomial GenPolynomial(. r), the second creates a polynomial of one monomial with given coefficient and exponent tuple GenPolynomial(. r, C c, ExpVector e), the third creates a polynomial from the internal sorted map of an other polynomial GenPolynomial(. r, SortedMap<ExpVector,C> v). Further there are methods to access parts of the polynomial like leading term, leading coefficient (still called leading base coefficient from the Aldes/SAC-2 tradition) and leading monomial. The toString() method creates as usual a string representation of the polynomials consisting of exponent tuples and coefficients. One variant of it takes an array of variable names and creates a string consisting of coefficients and products of powers of variables. The method extend() is used to embed the polynomial into the 'bigger' polynomial ring specified in the first parameter. The embeded polynomial can also be multiplied by a power of a variable. The contract() method returns a map of exponents and coefficients. The coefficients are polynomials belonging to the 'smaller' polynomial ring specified in the first parameter. If the polynomial actually belongs to the smaller polynomial ring the map will contain only one pair, mapping the zero exponent vector to the polynomial with variables removed. A last group of methods computes (extended) greatest common divisors. They work correct for univariate polynomials over a field but not for arbitrary multivatiate polynomials. These methods will be moved to a new separate class in the future.

The GenPolynomialRing class has a generic type parameter C which is constrained to a type with the functionality of ring elements C extends RingElem<C>. Further the class implements a RingFactory over GenPolynomial<C> so that it can be used as coefficient factory of a different polynomial ring. The constructors require at least a factory for the coefficents as first parameter of type RingFactory<C> and the number of variables in the second parameter. A third parameter can optionally specify a TermOrder and a fourth parameter can specify the names for the variables of the polynomial ring. Besides the methods required by the RingFactory interface there are additional random() methods which provide more control over the creation of random polynomials. They have the following parameters: the bitsize of random coefficients to be used in the random() method of the coefficient factory, the number of terms (i.e. the length of the polynomial), the maximal degree in each variable and the density of nozero exponents, i.e. the ratio of nonzero to zero exponents. The toString() method creates a string representation of the polynomial ring consisting of the coefficient factory string representation, the tuple of variable names and the string representation of the term order. The extend() and contract() methods create 'bigger' respectively 'smaller' polynomial rings. Both methods take a parameter of how many variables are to be added or removed form the actual polynomial ring. extend() will setup an elimination term order consisting of two times the actual term order when ever possible.

7. Solvable polynomial and solvable polynomial factory functionality

We continue the discussion of the above figure with the generic solvable polynomial and factory classes.

The GenSolvablePolynomial class has a generic type parameter C which is constrained to a type with the functionality of ring elements C extends RingElem<C>. The class extends the GenPolynomial class. It inherits all additive functionality and overwrites the multiplicative functionality with a new non-commutative multiplication method. Unfortunately it cannot implement a RingElem over itself RingElem<GenSolvablePolynomial<C>> but can only inherit the implementation of RingElem<GenPolynomial<C>> from its super class. By this limitation a solvable polynomial can still be used as coefficent in another polynomial, but only with the type of its super class. The limitation comes form the erasure of template parameters in RingElem<...> to RingElem for the code generated. I.e. the generic interfaces become the same after type erasure and it is not allowed to implement the same interface twice. There are two public and one protected constructors as in the super class. Each requires at least a ring factory parameter GenSolvablePolynomialRing<C> r which is stored in a variable of this type shadowing the variable with the same name of the super factory type. The rest of the initialization work is delegated to the super class constructor.

The GenSolvablePolynomialRing class has a generic type parameter C which is constrained to a type with the functionality of ring elements C extends RingElem<C>. The class extends the GenPolynomialRing class. It overwrites most methods to implement the new non-commutative methods. Also this class cannot implement a RingFactory over GenSolvablePolynomial<C>. It only implements RingFactory over GenPolynomial<C> by inheritance by the same reason of type erasure as above. But it can be used as coefficient factory with the type of its super class for a different polynomial ring. One part of the constructors just restate the super class constructors with the actual solvable type. A solvable polynomial ring however must know how to perform the non-commutative multiplication. To this end a data structure with the respective commutator relations is required. It is implemented in the RelationTable class. The other part of the constructors additionaly takes a parameter of type RelationTable to set the initial commutator relation table. Some care is needed to create relation tables and solvable polynomial factories since the relation table requires a solvable polynomial factory as parameter in the constructor. So it is most advisable to create a solvable polynomial factory object with empty relation table and to fill it with commutator relations after the constructor is completed but before the factory will be used. There is also a new method isAssociative() which tries to check if the commutator relations indeed define an associative algebra. This method should be extracted to the RingFactory interface together with a method isCommutative(), since both are of general importance and not always fulfilled in our rings. E.g. BigQuaternion is not commutative and so is a polynomial ring over these coefficents is not commutative. The same applies to associativity and the (not jet existing) class BigOctonion.

This concludes the discussion of the main interfaces and classes of the Java algebra system.


Heinz Kredel

Last modified: Wed Mar 31 22:45:31 CEST 2021

java-algebra-system-2.7.200/doc/download.html000066400000000000000000000474071445075545500210140ustar00rootroot00000000000000 JAS Download

Download, installation and unit tests

Download jar-files or clone repository

  • This is JAS version: @VERSION@, subversion revision: @SVNREV@ (export at @SVNDATE@).

  • The JAS classes jar-file @VERSION@.@SVNREV@-bin.jar can be used the same way as any other Java archive during compilation and execution of your Java programs. It is compiled using Java 11 from OpenJDK. The bytecode is dual licenced also under the Apache 2.0 licence to allow usage in Android projects.
    The source code is in @VERSION@.@SVNREV@-src.zip current version should compile on Java 8 and 11 (aka Java 1.8 and 1.11). (right click on the link and chose "save link as")
    The Javadoc API documentation is in @VERSION@.@SVNREV@-doc.zip for current version.

  • A JAS Maven compatible repository is at http://krum.rz.uni-mannheim.de/maven-repository/ and at https://repo1.maven.org/maven2/de/uni-mannheim/rz/krum/.
    groupId: de.uni-mannheim.rz.krum, artifactId: jas, version (for example): 2.7.@SVNREV@.

  • The JAS Git repository is available with

     git clone http://krum.rz.uni-mannheim.de/jas.git  jas
    

    or from GitHub

     git clone https://github.com/kredel/java-algebra-system jas
    
  • Required libraries:
    lib/log4j-api.jar, lib/log4j-core.jar (from Apache Log4j version 2.17.1),
    lib/junit-4.12.jar, lib/hamcrest-core-1.3.jar (from Junit 4),
    In case you already have these jars, just ensure they are in the correct location (e.g. ../lib/) or in the class path or accessible via Maven.

    The jar libraries can be downloaded from the above links or with the Ivy "resolve" target of ant, or the Maven dependencies, when installing the JAS source code.

  • Optional libraries and files:

    • There is a docker specification to create a docker image containing a runnable JAS in Dockerfile.
    • A Debian package libjas-java,
      an inofficial Debian package which can be used with MathLibre @DEBVERSION@.@SVNREV@-all.deb,
      and an Ubuntu package libjas-java are also avalilable.
    • jas-mpj.jar
      This JAR contains implementations of distributed Gröbner bases using the MPJ middle-ware (MPI Java). It requires an MPJ implementation such as MPJ Express or FastMPJ.
      The Javadocs can be found here.
    • jas-mpi.jar
      This JAR contains implementations of distributed Gröbner bases using the Open-MPI middle-ware (with Java support). It requires an MPI implementation such as Open-MPI.
      The Javadocs can be found here.
    • jas-meditor.jar
      This JAR contains the interface for JAS as an meditor engine, see jscl-meditor.
      Sample script to call meditor with the JAS engine meditor.
    • jlinalg_adapter.jar
      This JAR contains an adapter for JAS to the linear algebra library JLinAlg version 0.6.
      The Javadocs can be found here.
    • commons-math_adapter-bin.jar
      This JAR contains an adapter for JAS to the Apache Commons Math 3.3 linear algebra library Commons-Math version 3.3.
    • jas-jython.jar
      This JAR contains a scripting interface to use the jython interpreter with JAS.
    • Android JAS App Ruboto-IRB_with_JAS.
      You must allow "installation from untrusted sources".
      The JAS App uses its JRuby scripting interface and runs within the Ruby IRB Android App Ruboto.

     

  • For latest developments see JAS Weblog and the Git change log.

Installation

  • Add the JAS jar-file and the other required jar-files to the classpath. Start using it in your applications. For example

    javac -classpath log4j-api-2.17.1.jar:log4j-core-2.17.1.jar:junit.jar:jas.jar:. -d . src/edu/jas/application/Examples.java
    
    java  -classpath log4j-api-2.17.1.jar:log4j-core-2.17.1.jar:junit.jar:jas.jar:.      edu.jas.application.Examples
    

    Make sure that you use the actual jars as described above, for example log4j-api-2.17.1.jar:log4j-core-2.17.1.jar:junit-4.12.jar:hamcrest-core-1.3.jar

  • If you want to develop with JAS, then extract the jar-file in a new directory jar -xvf jas-[version]-src.jar

  • JAS is currently developed for Java 11 (OpenJDK). It may eventually not compile under Java 8 (OpenJDK 1.8). It will no more compile under Java 6 (OpenJDK 1.6) or older versions.

  • Among the extracted files, there is an Ant build script build.xml and also a Gnu make file Makefile.
    To use Ant, you must edit the build.xml file and adjust the lib property to point to the directory where you downloaded the jar files. Also be sure to use the correct JDK version, e.g. via setting the JAVA_HOME environment variable.
    To use the Gnu make file, you must edit the Makefile and adjust the JDK and the LIBPATH variables.

  • Most useful Ant targets:
    ant resolve fetch the required libraries (log4j2, junit) with Ivy,
    ant compile changed Java files are compiled,
    ant recompile all Java files are compiled,
    ant test run all JUnit tests,
    ant run -Dclass=edu.jas.'package'.'class' run the respective class,
    ant clean remove backup files,
    ant distclean remove all class files,
    ant doc create the Javadocs.

  • Most useful make-file targets:
    make "class" run the main() method of the class,
    e.g. make edu.jas.poly.Examples run the class Examples.

Unit tests with JUnit

  • Unit tests can be run with the "test" target for ant, e.g. ant test

  • The output of the unit tests is collected in the directory test for inspection.

  • The test units work mainly with generated random polynomials. The parameters are choosen such that the resulting Groebner bases are not to hard to compute. However some random polynomials may be to big and the running time may occasionally be several minutes (but not hours).
    On the other hand random polynomials may sometimes be zero or one. If such input does not make sense the test will fail. I.e. some tests will fail from time to time, but not for repeated execution of the test. So if a test fails rerun the test a few times.

Documentation

  • The JAS documentation is contained in the jar files jas-[version]-src.jar and jas-[version]-doc.jar. Extract the jar files and start exploring with any browser from the index.html file in the main directory.

  • The JAS javadoc API documents and the jython documents can also be browsed online: API Javadocs, Epydoc of jas.py and Rdoc of jas.rb.

  • README and licencing: COPYING.jas (GPL) or COPYING.lgpl.jas (LGPL)

Logging

  • JAS uses Apache Log4j to track progress in computations and inform about problematic or erroneous program states. Since JAS 2.6 it uses Log4j 2.x.

  • The configuration is in file log4j2.properties. Per deault the logging level is at ERROR so that only minimal logs are produced. To obtain more detailed information or store the logs to files, please configure the desired properties in the above file.

    This configuration file is no more contained in the binary jars jas-bin.jar or jas-[version].jar to allow usage of other compatible logging frameworks.

    The old configuration of Log4j version 1 via BasicConfigurator.configure() is no more supported.

Usage with the Eclipse IDE

The JAS source distribution can also be compiled and used from the Eclipse integrated development environment.

Instructions to install the JAS source:

  1. Download the JAS source jar and unpack to some directory, or git clone the repository to some directory
  2. Download the Log4j2 and the Junit jar files
  3. Start eclipse
  4. Create a new project from "existing source"
  5. Specify the source directory src contained the directory from 1.
  6. Add the jars from 2. to the project libraries as "external JARs"
  7. Create a new project or use your default project
  8. In the project properties add as "required project" the JAS project from 4.

Instructions to install the JAS binary:

  1. Download the JAS binary jar file
  2. Download the Log4j2 and the Junit jar files
  3. Start eclipse
  4. In your projects properties add the jar files from 1. and 2. to the project libraries as "external JARs"

Create and edit a sample java programm which uses the JAS API. E.g. the following sample computes the first ten Legendre polynomials.

import java.util.List;
import java.util.ArrayList;

import edu.jas.arith.BigRational;
import edu.jas.poly.GenPolynomial;
import edu.jas.poly.GenPolynomialRing;

public class mytests {

    public static void main(String[] args) {
         BigRational fac = new BigRational();
         String[] var = new String[]{ "x" };
         GenPolynomialRing<BigRational> ring
             = new GenPolynomialRing<BigRational>(fac,1,var);

         int n = 10;
         List<GenPolynomial<BigRational>> P 
             = new ArrayList<GenPolynomial<BigRational>>(n);
         GenPolynomial<BigRational> t, one, x, xc;
         BigRational n21, nn;

         one = ring.getONE();
         x   = ring.univariate(0);

         P.add( one );
         P.add( x );
         for ( int i = 2; i < n; i++ ) {
             n21 = new BigRational( 2*i-1 );
             xc = x.multiply( n21 );
             t = xc.multiply( P.get(i-1) );  // (2n-1) x P[n-1]
             nn = new BigRational( i-1 );
             xc = P.get(i-2).multiply( nn ); // (n-1) P[n-2]
             t = t.subtract( xc );
             nn = new BigRational(1,i);      
             t = t.multiply( nn );           // 1/n t
             P.add( t );
         }
         for ( int i = 0; i < n; i++ ) {
             System.out.println("P["+i+"] = " + P.get(i) );
         }
    }
}

Using the Jython interpreter

  • Be sure you have downloaded the above libraries log4j-api.jar, log4j-core.jar, junit-4.12.jar, hamcrest-core-1.3.jar, and jas*-bin.jar. JAS-@VERSION@ is using and has been tested with Jython 2.7.0.

  • The main file to interface to the JAS library is jas.py. It must be imported by other Python files. HTML documents of the interface can be found here.

  • Start using JAS, e.g.

     jython -J-cp log4j-api.jar:log4j-core.jar:junit-4.12.jar:hamcrest-core-1.3.jar:. examples/trinks.py
        

    The examples/trinks.py contains an Groebner base example named after its proposer Mr. Trinks. The file runs a sequential, a parallel and a distributed version of the Groebner base algorithms.

  • For further discussion of the JAS jython interface see User guide.

Using the JRuby interpreter

  • Be sure you have downloaded the above libraries log4j-api.jar, log4j-core.jar, junit-4.12.jar, hamcrest-core-1.3.jar, and jas*-bin.jar. JAS-@VERSION@ is using and has been tested with JRuby 1.7.23 (Ruby 1.9.3 compatible)

  • The main file to interface to the JAS library is jas.rb. It must be required by other Ruby files. HTML documents of the interface can be found here.

  • Start using JAS, e.g.

     jruby -J-cp log4j-api.jar:log4j-core.jar:junit-4.12.jar:hamcrest-core-1.3.jar:. examples/trinks.rb
        

    The examples/trinks.rb contains an Groebner base example named after its proposer Mr. Trinks. The file runs a sequential, a parallel and a distributed version of the Groebner base algorithms.

  • For further discussion of the JAS scripting interface see User guide.

Using the Ruboto-IRB-JAS Android application

The App has been developed for JAS version 2.5 on Android 5 and is not working on current Android versions (since 2019).

  • Be sure you have installed the above Android application package ruboto-irb-jas-release.apk. It contains all required libraries and scripts. JAS-2.5 has been tested with Android 2.3 and 4.1 and is using JRuby 1.6.4 (Ruby 1.8.7 & 1.9.2 compatible)

  • The JAS app uses the Ruby IRB Ruboto for Android. This is just a Ruby interpreter running on Android together with a text editor. So all JAS JRuby scripts can be run in this environment. The JAS Java programs are included in compiled and transformed Dalvik "dex" format. Up to now, no functional problems have been encountered, i.e. all JAS Java code runs. However, due to limitations in CPU speed and memory on mobile phones or tablets eventually not all examples and problems will execute. In 2012, comparison of a two year old Android tablet (1 GHz, 0.5 GB) and a three year old PC (3 GHz, 4 GB) show that the examples run about 5 times slower than on the PC.

  • The main Ruboto screen with the "trinks.rb" example and its output looks as follows. Also the arbitrary precision numbers arithmetic works on Android.

    screen shot   screen shot   screen shot

    The list of examples can be accessed via the "scripts" button.

    screen shot

  • For further discussion of the JAS scripting interface see User guide.


Heinz Kredel

Last modified: Mon May 30 10:33:32 CEST 2022

java-algebra-system-2.7.200/doc/faq.html000066400000000000000000000101331445075545500177360ustar00rootroot00000000000000 Frequently asked questions

Frequently asked questions

In this page we give answers to frequently asked questions about JAS.

  1. When using the bytecode from *-bin.jar, I get "Bad version number in .class"
  2. When trying to compile JAS with "ant compile", I get NoClassDefFoundError: org/apache/tools/ant/launch/Launcher
  3. When compiling a sample code I get '(' or '[' expected errors
  4. After compiling a sample code I get NoClassDefFoundError: org/apache/log4j/Logger
  5. I can not use Apache log4j in my project for some reason.
  6. I want to use JAS on Android.
  7. I do not want to compile and install JAS myself.

When using the bytecode from *-bin.jar I get "Bad version number in .class"

This error occurs if your Java virtual maschine is older than the Java used in compiling the classes. Use the JAS source to compile the .class files with your version of the Java VM. See e.g. Eclipse.

When trying to compile JAS with "ant compile", I get NoClassDefFoundError: org/apache/tools/ant/launch/Launcher

Ant uses a wrong Java version. Define the Java home directory in the environment. E.g. in Linux use
export JAVA_HOME=/usr/java/jdk1.6.0_02
or the directory of your installed Java version.

When compiling a sample code I get '(' or '[' expected errors

JAS uses the new generic type parameters, which where introduced in Java version 5. So you must use at least a Java Development Kit 5 or later. See Java.sun.com for the latest Java releases.

After compiling a sample code I get NoClassDefFoundError: org/apache/log4j/Logger

You must include the Log4j classes in the classpath. e.g.
java -cp log4j.jar:. mysample

I can not use Apache log4j in my project for some reason.

Eventually consider SLF4J for interfacing to other logging systems.
The old adapter package for Java logging with mylog.jar is discontinued.

I want to use JAS on Android.

JAS is no more compiling with Java 1.6, so JAS can at the moment not compiled and dexed for Android.

I do not want to compile JAS and install all dependencies myself.

For the core of JAS you can use the Debian package or the Android application, see download page.
There are optional parts of JAS which depend on external tools and libraries. Since it requires some understanding of these tools they must be installed by yourself.


Heinz Kredel

Last modified: Sun Nov 21 22:10:23 CET 2021

java-algebra-system-2.7.200/doc/findbugs.html000066400000000000000000000765541445075545500210130ustar00rootroot00000000000000 FindBugs Report

FindBugs Report

Project Information

Project:

FindBugs version: 3.0.1

Code analyzed:

  • /home/kredel/jas/edu/jas/



Metrics

113838 lines of code analyzed, in 1016 classes, in 16 packages.

Metric Total Density*
High Priority Warnings 1 0.01
Medium Priority Warnings 37 0.33
Total Warnings 38 0.33

(* Defects per Thousand lines of non-commenting source statements)



Contents

Summary

Warning Type Number
Bad practice Warnings 22
Malicious code vulnerability Warnings 1
Dodgy code Warnings 15
Total 38

Warnings

Click on a warning row to see full context information.

Bad practice Warnings

Code Warning
Nm The class name edu.jas.application.FactorFactory shadows the simple name of the superclass edu.jas.ufd.FactorFactory
Nm The method name edu.jas.application.GBAlgorithmBuilder.Arri() doesn't start with a lower case letter
OS edu.jas.application.RunGB.getReader(String) may fail to close stream
RV edu.jas.poly.PolynomialComparator.compare(GenPolynomial, GenPolynomial) negates the return value of edu.jas.poly.GenPolynomial.compareTo(GenPolynomial)
RV edu.jas.poly.TermOrder$11.compare(ExpVector, ExpVector) negates the return value of edu.jas.poly.TermOrder$EVComparator.compare(ExpVector, ExpVector)
RV edu.jas.poly.TermOrder$71.compare(ExpVector, ExpVector) negates the return value of edu.jas.poly.TermOrder$EVComparator.compare(ExpVector, ExpVector)
RV edu.jas.poly.Word.gradInvlexCompareTo(Word) negates the return value of edu.jas.poly.Word.compareTo(Word)
SnVI edu.jas.fd.SGCDParallelProxy is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GBProxy is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseDistributedEC is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseDistributedHybridEC is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseParIter is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseSeqPairDistributed is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.GroebnerBaseSeqPairParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.SGBProxy is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.SolvableGroebnerBaseParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gb.SolvableGroebnerBaseSeqPairParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gbufd.GroebnerBasePseudoParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.gbufd.GroebnerBasePseudoRecParallel is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.poly.GenPolynomial is Serializable; consider declaring a serialVersionUID
SnVI edu.jas.ufd.GCDProxy is Serializable; consider declaring a serialVersionUID

Malicious code vulnerability Warnings

Code Warning
MS edu.jas.kern.ComputerThreads.NO_THREADS isn't final and can't be protected from malicious code

Dodgy code Warnings

Code Warning
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableLocalResidueRing.create(GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableLocalResidueRing.create(GenPolynomial, GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableLocalRing.create(GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableLocalRing.create(GenPolynomial, GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableResidueRing.create(GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.application.SolvableResidueRing.create(GenPolynomial, GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.fd.SolvableQuotientRing.create(GenPolynomial)
BC Unchecked/unconfirmed cast from edu.jas.poly.GenPolynomial<C> to edu.jas.poly.GenSolvablePolynomial in edu.jas.fd.SolvableQuotientRing.create(GenPolynomial, GenPolynomial)
BC instanceof will always return true for all non-null values in edu.jas.poly.RecSolvablePolynomial.evalAsRightRecursivePolynomial(), since all edu.jas.poly.RecSolvablePolynomial are instances of edu.jas.poly.RecSolvablePolynomial
BC instanceof will always return true for all non-null values in edu.jas.poly.RecSolvablePolynomial.isRightRecursivePolynomial(GenSolvablePolynomial), since all edu.jas.poly.RecSolvablePolynomial are instances of edu.jas.poly.RecSolvablePolynomial
BC instanceof will always return true for all non-null values in edu.jas.poly.RecSolvablePolynomial.rightRecursivePolynomial(), since all edu.jas.poly.RecSolvablePolynomial are instances of edu.jas.poly.RecSolvablePolynomial
DB edu.jas.application.RingFactoryTokenizer.nextCoefficientRing() uses the same code for two branches
DB edu.jas.poly.GenPolynomialTokenizer.nextCoefficientRing() uses the same code for two branches
SF Switch statement found in edu.jas.poly.GenPolynomialTokenizer.nextPolynomial() where one case falls through to the next case
UCF Useless control flow in edu.jas.fd.GCDLeftRightTest.testBaseQR()

Details

BC_VACUOUS_INSTANCEOF: instanceof will always return true

This instanceof test will always return true (unless the value being tested is null). Although this is safe, make sure it isn't an indication of some misunderstanding or some other logic error. If you really want to test the value for being null, perhaps it would be clearer to do better to do a null test rather than an instanceof test.

BC_UNCONFIRMED_CAST: Unchecked/unconfirmed cast

This cast is unchecked, and not all instances of the type casted from can be cast to the type it is being cast to. Check that your program logic ensures that this cast will not fail.

DB_DUPLICATE_BRANCHES: Method uses the same code for two branches

This method uses the same code to implement two branches of a conditional branch. Check to ensure that this isn't a coding mistake.

MS_CANNOT_BE_FINAL: Field isn't final and can't be protected from malicious code

A mutable static field could be changed by malicious code or by accident from another package. Unfortunately, the way the field is used doesn't allow any easy fix to this problem.

NM_SAME_SIMPLE_NAME_AS_SUPERCLASS: Class names shouldn't shadow simple name of superclass

This class has a simple name that is identical to that of its superclass, except that its superclass is in a different package (e.g., alpha.Foo extends beta.Foo). This can be exceptionally confusing, create lots of situations in which you have to look at import statements to resolve references and creates many opportunities to accidentally define methods that do not override methods in their superclasses.

NM_METHOD_NAMING_CONVENTION: Method names should start with a lower case letter

Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

OS_OPEN_STREAM: Method may fail to close stream

The method creates an IO stream object, does not assign it to any fields, pass it to other methods that might close it, or return it, and does not appear to close the stream on all paths out of the method.  This may result in a file descriptor leak.  It is generally a good idea to use a finally block to ensure that streams are closed.

RV_NEGATING_RESULT_OF_COMPARETO: Negating the result of compareTo()/compare()

This code negatives the return value of a compareTo or compare method. This is a questionable or bad programming practice, since if the return value is Integer.MIN_VALUE, negating the return value won't negate the sign of the result. You can achieve the same intended result by reversing the order of the operands rather than by negating the results.

SF_SWITCH_FALLTHROUGH: Switch statement found where one case falls through to the next case

This method contains a switch statement where one case branch will fall through to the next case. Usually you need to end this case with a break or return.

SE_NO_SERIALVERSIONID: Class is Serializable, but doesn't define serialVersionUID

This class implements the Serializable interface, but does not define a serialVersionUID field.  A change as simple as adding a reference to a .class object will add synthetic fields to the class, which will unfortunately change the implicit serialVersionUID (e.g., adding a reference to String.class will generate a static field class$java$lang$String). Also, different source code to bytecode compilers may use different naming conventions for synthetic variables generated for references to class objects or inner classes. To ensure interoperability of Serializable across versions, consider adding an explicit serialVersionUID.

UCF_USELESS_CONTROL_FLOW: Useless control flow

This method contains a useless control flow statement, where control flow continues onto the same place regardless of whether or not the branch is taken. For example, this is caused by having an empty statement block for an if statement:

    if (argv.length == 0) {
    // TODO: handle this case
    }
java-algebra-system-2.7.200/doc/gb-book.html000066400000000000000000000420551445075545500205170ustar00rootroot00000000000000 JAS - Gröbner bases book

Gröbner bases book algorithms and JAS methods

Summary of algorithms from the Gröbner bases book and corresponding JAS classes and methods.

Gröbner bases book algorithms

The JAS base package edu.jas name is omitted in the following table. JAS also contains improved versions of the algorithms which may be located through the links. A short explanation of code organization with interfaces and several implementing classes can be found in the API guide.

GB book algorithm JAS interfaces, classes and methods remarks
0.1 DIVINT arith.BigInteger.divideAndRemainder adapter for java.math.BigInteger.divideAndRemainder
 
2.1 DIV structure.MonoidElem.divide and structure.MonoidElem.remainder all classes which implement this interface
2.2 DIVPOL poly.GenPolynomial. divideAndRemainder for univariate polynomials over fields
2.3 EXTEUC poly.GenPolynomial.egcd for univariate polynomials over fields
 
3.1 LINDEP not implemented But see vector.LinAlg. rowEchelonForm and other classes in the vector package.
3.2 EXCHANGE not implemented
 
4.1 EQUIV structure.Residue.equals or application.Residue.equals arbitrary residue class rings and residue class rings modulo polynomial ideals
 
5.1 REDPOL gb.Reduction.normalform, gb.ReductionAbstract.normalform, gb.ReductionSeq.normalform interface and sequential computation class, the method exists also for polynomial lists and with a reduction recording matrix (this is exactly REDPOL)
5.2 REDUCTION gb.Reduction.irreducibleSet
5.3 GRÖBNERTEST gb.GroebnerBase.isGB provided by all classes which implement this interface
5.4 GRÖBNER not implemented
5.5 REDGRÖBNER gb.GroebnerBase.GB with gb.OrderedMinPairlist provided by all classes which implement the interface and allow the selection of the pair-list in a constructor
5.6 GRÖBNERNEW1 gb.GroebnerBase.GB with gb.OrderedPairlist provided by all classes which implement the interface and allow the selection of the pair-list in a constructor
5.7 UPDATE, 5.8 GRÖBNERNEW2 gb.GroebnerBase.GB with gb.OrderedSyzPairlist provided by all classes which implement the interface and allow the selection of the pair-list in a constructor
5.9 EXTGRÖBNER gb.GroebnerBase.extGB provided by some classes which implement the interface
 
6.1 ELIMINATION application.Ideal.eliminate the version with the String[] parameter computes a Gröbner base wrt. the corresponding elimination order
6.2 PROPER application.Ideal.isONE proper ideal test is ! id.isONE()
6.3 INTERSECTION application.Ideal.intersect for lists of ideals a simple iterative algorithm is used and for a pair of ideals it is the same algorithm
6.4 CRT gbufd.PolyGBUtil.chineseRemainderTheorem
6.5 IDEALDIV1 application.Ideal.quotient for an ideal a simple iterative algorithm is used and for one polynomial it is an algorithm without computing syzygies
6.6 IDEALDIV2 application.Ideal. infiniteQuotientRab and application.Ideal. infiniteQuotientExponent the exponent is computed in a separate step at the moment
6.7 RADICALMEMTEST application.Ideal.isRadicalMember the exponent is not computed
6.8 SUBRINGMEMTEST gbufd.PolyGBUtil.subRingAndMember
 
8.1 PREDEC application.Ideal. zeroDimDecomposition univariate polynomials of minimal degree in the ideal are irreducible and not a power of an irreducible polynomial as specified in PREDEC
8.2 ZRADICALTEST application.Ideal.isZeroDimRadical will also work in characteritsic p > 0
8.3 ZRADICAL application.Ideal.radical ZRADICAL is containted as special case, see also application.Ideal. zeroDimRadicalDecomposition
8.4 NORMPRIMDEC application.Ideal. zeroDimPrimaryDecomposition contains all preprocessing steps, see ZPRIMDEC
8.5 NORMPOS application.Ideal.normalPositionFor one step of NORMPOS as explained for the modified algorithm on page 383ff
8.6 ZPRIMDEC application.Ideal. zeroDimPrimaryDecomposition returns a list of PrimaryComponent containers
8.7 CONT application.Ideal.contraction more complicated since the permutation of variables must be considered also, see application.Ideal.permContraction, the polynomial f is returned in the IdealWithUniv container
8.8 EXTCONT application.Ideal.extension only EXT, the combination EXTCONT is not implemented explicitly, the polynomial f is returned in the IdealWithUniv container
8.9 RADICAL application.Ideal.radical for ideals with arbitrary dimension
8.10 PRIMDEC application.Ideal. primaryDecomposition for ideals with arbitrary dimension
8.11 VARSIGN root.RootUtil.signVar
8.12 STURMSEQ root.RealRootsSturm.sturmSequence
8.13 ISOLATE root.RealRoots.realRoots could also be used for real root isolations not using Sturm sequences
8.14 ISOREC root.RealRootsSturm.realRoots interval bi-section until a root is isolated
8.15 ISOREFINE root.RealRoots.refineInterval also for real root isolations not using Sturm sequences
8.16 SQUEEZE root.RealRoots. invariantMagnitudeInterval see also root.RealRoots. realMagnitude
8.17 REALZEROS application.PolyUtilApp. realAlgebraicRoots different algorithm and different result data structure with RealAlgebraicNumbers
 
9.1 REDTERMS gbufd.GroebnerBaseFGLM.redTerms
9.2 UNIVPOL application.Ideal. constructUnivariate
9.3 CONVGRÖBNER gbufd.GroebnerBaseFGLM. convGroebnerToLex See also gbufd.GroebnerBaseFGLM.GB. It computes a Gröbner base with respect to a graded term order and then uses FGLM to convert to a lexicographic term order. See also gbufd.GroebnerBaseWalk.GB. It computes a Gröbner base with respect to a term order t1 and then uses Gröbner Walk to convert to a GB with term order t2.
9.4 LMINTERM gbufd.GroebnerBaseFGLM.lMinterm
9.5 STRCONST not implemented
9.6 DIMENSION application.Ideal.dimension
 
10.1 D-GRÖBNER gb.DGroebnerBaseSeq.GB and gb.EGroebnerBaseSeq.GB


Heinz Kredel

Last modified: Thu Jul 8 17:47:59 CEST 2021

java-algebra-system-2.7.200/doc/guide.html000066400000000000000000001001401445075545500202620ustar00rootroot00000000000000 JAS project users guide

Interactive scripting guide

This document contains first information on how-to use the interactive scripting of the JAS project. It can be used via the Java Python interpreter jython, or the Java Ruby interpreter jruby or the jruby Android App Ruboto-IRB.
The usage of JAS as an ordinary Java library, adding jas.jar to the classpath and creating and using objects from JAS classes, is introduced in the API guide.

JAS can be started with the script "jas" in the JAS home directory. By default the JRuby interactive shell ist used. For the Jython shell use "jas -py". When started from a desktop, like MathLibre, the shells will look as in the following picture. The upper right terminal shows a Jython shell and the lower left terminal shows a JRuby shell.

JAS in MathLibre
 
JAS jython and jruby interface in MathLibre

Getting started

As first example we will discus how to compute a Groebner base with jruby. The jruby script will be placed into a file, e.g. getstart-gb.rb. This script file is executed by calling

  jruby getstart-gb.rb

If you start jruby (or jas -rb) without a file name, then an interactive shell is opened and you can type commands and expressions as desired. The script file first imports the desired mathematical classes from the jas.rb script which does all interfacing to the Java library. For the Rdoc of it see here.

  require "examples/jas"

In our case we need PolyRing to define an appropriate polynomial ring and later Ideal to define sets of polynomials and have methods to compute Groebner bases. PolyRing takes arguments for required definitions of the polynomial ring: the type of the coefficient ring, the names of the used variables and the desired term order.

  r = PolyRing.new( QQ(), "B,S,T,Z,P,W", PolyRing.lex)

The ring definition is stored in the variable r for later use. The string "QQ()" defines the coefficient ring to be the rational numbers, the polynomial ring consists of the variables B, S, T, Z, P, W and the term order PolyRing.lex means a lexicographic term order. For some historical reason the term order orders the variables as B < S < T < Z < P < W and not the other way. I.e. the highest or largest variable is always on the right of the list of variables not on the left as in some other algebra systems. With

  puts "PolyRing: " + r.to_s

you can print out the ring definition. r.to_s is the usual Ruby way of producing string representations of objects, which in our case calls the respective Java method toScript() of the JAS object. It produces

  PolyRing: PolyRing.new(QQ(),"B,S,T,Z,P,W",PolyRing.lex)

i.e. the same expression as defined above. In general the string from r.to_s of an JAS object can be used via cut-and-past as new input. Next we need to enter the generating polynomials for the ideal. We do this in three steps, first define the Ruby variables for the polynomial ring, next define the polynomials and then the creation of the ideal using the ring definition from before and the polynomial list.

  one,B,S,T,Z,P,W = r.gens()
Small letter variables for polynomials are defined automatically but because of Ruby handling capital letter variables as constant they must be defined by hand. The method r.gens() returns a list of all generators (variables and values) of the polynomial ring.
ff = [
 45 * P + 35 * S - 165 * B - 36, 
 35 * P + 40 * Z + 25 * T - 27 * S, 
 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2, 
 - 9 * W + 15 * T * P + 20 * S * Z, 
 P * W + 2 * T * Z - 11 * B**3, 
 99 * W - 11 * B * S + 3 * B**2,
 B**2 + 33/50 * B + 2673/10000
];

The polynomial list can be generated by any means Ruby allows for polynomial expressions. In our example we use Ruby brackets [ ... ] for the creation of the list. The polynomials in the list are delimited by commas, and may be enclosed in parentheses. The syntax for polynomials is the Ruby expression syntax including literals from the coefficient ring QQ(), variables and operators +, -, *, ** (for summation, subtraction, multiplication, and exponentiation). The ideal is then defined with

  f = r.ideal( "", ff )

It is contained the the polynomial ring r by construction and consists of the polynomials from the list ff, the first parameter is the empty string. Ideals can be printed with

  puts "Ideal: " + f.to_s

In this example it produces the following output.

Ideal: SimIdeal.new(PolyRing.new(QQ(),"B,S,T,Z,P,W",PolyRing.lex),
       "",[( B**2 + 33/50 * B + 2673/10000 ), 
           ( 45 * P + 35 * S - 165 * B - 36 ), 
           ( 35 * P + 40 * Z + 25 * T - 27 * S ), 
           ( 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2 ), 
           ( ( -9 ) * W + 15 * T * P + 20 * S * Z ), 
           ( 99 * W - 11 * B * S + 3 * B**2 ), 
           ( P * W + 2 * T * Z - 11 * B**3 )])

The polynomial terms are now sorted with respect to the lexicographical term order. The highest term is first in a polynomial. Also the polynomials are sorted with respect to the term order, but with smallest polynomial first in the list. Finaly we can go to the computation of the Groebner basis of this ideal.

  g = f.GB()

The ideal f has a method GB() which computes the Groebner base. The computed Groebner base is stored in the variable g which is also an ideal. It can be printed in the same was as the ideal f

  puts "Groebner base: " + g.to_s

The output first shows the output from calling the GB() method and the the ideal basis.

sequential(field) GB executed in 37 ms

Groebner base: SimIdeal.new(PolyRing.new(QQ(),"B,S,T,Z,P,W",PolyRing.lex),
               "",[( B**2 + 33/50 * B + 2673/10000 ), 
                   ( S - 5/2 * B - 9/200 ), 
                   ( T - 37/15 * B + 27/250 ), 
                   ( Z + 49/36 * B + 1143/2000 ), 
                   ( P - 31/18 * B - 153/200 ), 
                   ( W + 19/120 * B + 1323/20000 )])

The Groebner base was computed with the sequential algorithm or polynomial rings over fields in 37 ms and consists of six polynomials. The polynomials are now monic, i.e. the leading coefficient is 1 and omitted during print out. This concludes the first getting started section.

Overview of Ruby and Python classes and methods in jas.rb and jas.py

The jruby and the jython interface to the JAS library constain the following classes. The class and method names are almost identical, except where name clashes with scripting language occur, e.g. Ideal in jython, but SimIdeal in jruby. The class constructors in Ruby are used with the .new() method and in Python the class name is use like a function name. For example the construction of a polynomial ring is done in Ruby by PolyRing.new(...) and in Python by PolyRing(...). For the Rdoc of them see here and for the Epydoc of them see here.

  • PolyRing, Ideal/SimIdeal and ParamIdeal
    define polynomial rings, ideals and ideals over rings with coefficient parameters.
    Ideal has methods for sequential, parallel and distributed Groebner bases computation, for example GB(), isGB(), parGB(), distGB(), NF() and intersect().
    ParamIdeal has methods for comprehensive Groebner bases computation, for example CGB(), CGBsystem(), regularGB(),

  • SolvPolyRing and SolvableIdeal/SolvIdeal
    define solvable polynomial rings and left, right and two-sided ideals.
    SolvableIdeal has methods for left, right and two-sided Groebner bases computation, e.g. leftGB(), rightGB(), twosidedGB(), intersect().

  • Module and SubModule
    define modules over polynomial rings and sub modules.
    Module has a method for sequential Groebner bases computation, e.g. GB().

  • SolvableModule and SolvableSubModule
    define modules over solvable polynomial rings and sub modules.
    SolvableModule has methods for left, right and two-sided Groebner bases computation, e.g. leftGB(), rightGB(), twosidedGB().

Ruby has support for rational numbers, so a literal, like 2/3, is recognized as rational number 2/3. Python has no support for rational number literals and 2/3 is recognized as interger division, resulting in the integer 0 (zero). To allow rational numbers in JAS, the Python tuple or list notation must be used to express rational numbers, so (2,3) is recognized as rational number 2/3.

For example in the construction of Legendre polynomials a rational number r = 1/n appears. As tuple literal it is written (1,n) and as list literal it can be written as [1,n].

  p = (2*n-1) * x * P[n-1] - (n-1) * P[n-2];
  r = (1,n); # no rational numbers in Python, use tuple notation
  p = r * p; 

In the same way complex rational numbers can be written as nested tuples. For example 1/n + 1/2 i can be written as ((1,n),(1,2)). If the second list element is omited it is asumed to be one as rational number and zero as complex number. To avoid ambiguities use a trailing comma, as in ((1,2),).


Overview of some mathematical capabilities of JAS

In this section we summarize some mathematical constructions which are possible with JAS: real root computation, power series and non-commutative polynomial rings.

Real roots of zero dimensional ideals

Besides the computation of Gröbner bases JAS is able to use them to solve various other problems. In this sub-section we present the computation of real roots of systems of (algebraic) equations. When the system of equations has only finitely many real roots, such systems define so called zero dimensional ideals, they can be computed (using jython) as follows.

  r = PolyRing(QQ(),"x,y,z",PolyRing.lex);
  print "Ring: " + str(r);
  print;

  [one,x,y,z] = r.gens(); # is also automatic

  f1 = (x**2 - 5)*(x**2 - 3)**2;
  f2 = y**2 - 3;
  f3 = z**3 - x * y;

  F = r.ideal( list=[f1,f2,f3] );

  R = F.realRoots();
  F.realRootsPrint()

In the above example we compute the real roots of the equations defined by the polynomials f1, f2, f3. First we define the polynomial ring and then construct the ideal F from the given polynomials. The method F.realRoots() computes the real roots and method F.realRootsPrint() prints a decimal approximation of tuples of real roots. The output of the last method call looks as follows.

[-1.7320508076809346675872802734375, -1.7320508076809346675872802734375, 1.4422495705075562000274658203125]
[1.7320508076809346675872802734375, 1.7320508076809346675872802734375, 1.4422495705075562000274658203125]

[1.7320508076809346675872802734375, -1.7320508076809346675872802734375, -1.4422495705075562000274658203125]
[-1.7320508076809346675872802734375, 1.7320508076809346675872802734375, -1.4422495705075562000274658203125]

[0.50401716955821029841899871826171875, 2.236067977384664118289947509765625, -1.7320508076809346675872802734375, -1.5704178023152053356170654296875]
[-0.50401716955821029841899871826171875, -2.236067977384664118289947509765625, 1.7320508076809346675872802734375, -1.5704178023152053356170654296875]
[-3.96811878503649495542049407958984375, -2.236067977384664118289947509765625, -1.7320508076809346675872802734375, 1.5704178023152053356170654296875]
[3.96811878503649495542049407958984375, 2.236067977384664118289947509765625, 1.7320508076809346675872802734375, 1.5704178023152053356170654296875]

The roots in the tuples [-1.732..., -1.732..., 1.442...] correspond to the roots in the variables [x, y, z]. The last four tuples have four entries [0.504..., 2.236..., -1.732..., -1.570...], where the first entry stems from an internal field extension, which was needed to correctly identify the roots of the ideal and are to be ignored. That is the tuple [2.236..., -1.732..., -1.570...] without the first entry is a real root of the ideal. That is, the decimal approximation of the real roots are the following 8 tuples.

  [-1.73205..., -1.73205...,  1.44224...]
  [ 1.73205...,  1.73205...,  1.44224...]

  [ 1.73205..., -1.73205..., -1.44224...]
  [-1.73205...,  1.73205..., -1.44224...]

  [ 2.23606..., -1.73205..., -1.57041...]
  [-2.23606...,  1.73205..., -1.57041...]
  [-2.23606..., -1.73205...,  1.57041...]
  [ 2.23606...,  1.73205...,  1.57041...]

More details and further examples can be found in the jython file 0dim_real_roots.py.

Power series

Univariate power series can be constructed via the SeriesRing class and an multivariate power series with the MultiSeriesRing class. There are short cut methods PS(coeff, name, truncate, function) and MPS(coeff, names, truncate, function) to construct a power series with a given coefficient generator 'function'. In the following example (using jython) we create a new power series ring pr in the variable y over the rational numbers. The creation of power series is done in the same way as polynomials are created. There are additional methods like r.exp() or r.sin() to create the exponential power series or the power series for the sinus function.

  pr = SeriesRing("Q(y)");
  print "pr:", pr;

  one = pr.one();
  r1 = pr.random(4);
  r2 = pr.random(4);

  print "one:", one;
  print "r1:", r1;
  print "r2:", r2;

  r4 = r1 * r2 + one;
  e = pr.exp();
  r5 = r1 * r2 + e;

  print "e:", e;
  print "r4:", r4;
  print "r5:", r5;

Once power series are created, for example r1, r2, e above, it is possible to use arithmetic operators to built expressions of power series like 'r1 * r2 + one' or 'r1 * r2 + e'.

pr: PS(QQ(),"y",11)

one: 1
r1:  (13,5) - (14,5) * y**3 - y**4 + 14 * y**5 - (12,7) * y**6 - 4 * y**7 - (9,14) * y**8 + 3 * y**9 + (1,15) * y**10

r2:  - (9,16) * y + (5,6) * y**3 + (2,3) * y**5 + (5,6) * y**9 + (5,2) * y**10

e: 1 + y + (1,2) * y**2 + (1,6) * y**3 + (1,24) * y**4 + (1,120) * y**5 + (1,720) * y**6 + (1,5040) * y**7 + (1,40320) * y**8 
   + (1,362880) * y**9 + (1,3628800) * y**10

r4: 1 - (117,80) * y + (13,6) * y**3 + (63,40) * y**4 + (551,240) * y**5 - (245,24) * y**6 + (11,84) * y**7 + (241,20) * y**8 + (97,224) * y**9 + (173,16) * y**10

r5: 1 - (37,80) * y + (1,2) * y**2 + (7,3) * y**3 + (97,60) * y**4 + (553,240) * y**5 - (7349,720) * y**6 + (661,5040) * y**7 + (485857,40320) * y**8 
    + (157141,362880) * y**9 + (39236401,3628800) * y**10

It is also possible to create power series by defining a generating function or by defining a fixed point with respect to a map between power series.

  def g(a):
      return a+a;
  ps1 = pr.create(g);

  class coeff( Coefficients ):
      def generate(self,i):
          ...
  ps6 = pr.create( clazz=coeff( pr.ring.coFac ) );

  class cosmap( PowerSeriesMap ):
      def map(self,ps):
          ...
  ps8 = pr.fixPoint( cosmap( pr.ring.coFac ) );

More details and further examples can be found in the jython file powerseries.py and powerseries_multi.py and their Ruby counter parts.

Solvable polynomial rings

Solvable polynomial rings are non commutative polynomial rings where the non commutativity is expressed by commutator relations. Commutator relations are stored in a data structure called relation table. In the definition of a solvable polynomial ring this relation table must be defined. E.g the definition for the ring of a solvable polynomial ring (in jruby) is

  require "examples/jas"
  # WA_32 solvable polynomial example

  p = PolyRing.new(QQ(),"a,b,e1,e2,e3");
  relations = [e3, e1, e1*e3 - e1,
               e3, e2, e2*e3 - e2];

  puts "relations: = " + relations.join(", ") { |r| r.to_s };

relations: = e3, e1, ( e1 * e3 - e1 ), e3, e2, ( e2 * e3 - e2 )

The relation table must be build from triples of (commutative) polynomials. A triple p1, p2, p3 is interpreted as non commutative multiplication relation p1 .*. p2 = p3. p1 and p2 must be a single term, single variable polynomials. The term order must be choosen such that leadingTerm(p1 p2) equals leadingTerm(p3) and p1 > p2 for each triple. The polynomial p3 is in commutative form, i.e. multiplication operators occuring in it are commutative. Variables for which there are no commutator relations are assumed to commute with each other and with all other variables, e.g. the variables a, b in the example.

  rp = SolvPolyRing.new(QQ(), "a,b,e1,e2,e3", PolyRing.lex, relations);
  puts "SolvPolyRing: " + rp.to_s;

  puts "gens = " + rp.gens().join(", ") { |r| r.to_s };
  one,a,b,e1,e2,e3 = rp.gens();

  f1 = e1 * e3**3 + e2**10 - a;
  f2 = e1**3 * e2**2 + e3;
  f3 = e3**3 + e3**2 - b;

  F = [ f1, f2, f3 ];
  puts "F = " + F.join(", ") { |r| r.to_s };

  I = rp.ideal( "", F );
  puts "SolvableIdeal: " + I.to_s;

After the definition of the variables e1, e2, e3 as non-commutative as elements of the ring rp, the expressions for the polynomials f1, f2, f3 use non-cummutative multiplication with the * operator.

A complete example is contained in the jRuby script solvablepolynomial.rb. Running the script computes a left, right and twosided Groebner base for the following ideal I generated by the polynomial list F.

ring is associative
SolvPolyRing: SolvPolyRing.new(QQ(),"a,b,e1,e2,e3",PolyRing.lex,rel=[e3, e2, ( e2 * e3 - e2 ), e3, e1, ( e1 * e3 - e1 )])

gens = 1, a, b, e1, e2, e3
F = ( e1 * e3**3 + e2**10 - a ), ( e3 + e1**3 * e2**2 ), ( e3**3 + e3**2 - b )

SolvableIdeal: SolvIdeal.new(SolvPolyRing.new(QQ(),"a,b,e1,e2,e3",PolyRing.lex,
                      rel=[e3, e2,  ( e2 * e3 - e2 ), e3, e1,  ( e1 * e3 - e1 )]),
                  "",[( e3 + e1**3 * e2**2 ), ( e3**3 + e3**2 - b ), ( e1 * e3**3 + e2**10 - a )])

The left Groebner base is

sequential(field|nocom) leftGB executed in 29 ms

seq left GB: SolvIdeal.new(SolvPolyRing.new(QQ(),"a,b,e1,e2,e3",PolyRing.lex,rel=[e3, e2,  ( e2 * e3 - e2 ), e3, e1,  ( e1 * e3 - e1 )]),
             "",[a, b, e1**3 * e2**2, e2**10, e3])

the twosided Groebner base is

sequential(field|nocom) twosidedGB executed in 28 ms
seq twosided GB: SolvIdeal.new(SolvPolyRing.new(QQ(),"a,b,e1,e2,e3",PolyRing.lex,rel=[e3, e2,  ( e2 * e3 - e2 ), e3, e1,  ( e1 * e3 - e1 )]),
                 "",[a, b, e1, e2, e3])

and the right Groebner base is

sequential(field|nocom) rightGB executed in 16 ms
seq right GB: SolvIdeal.new(SolvPolyRing.new(QQ(),"a,b,e1,e2,e3",PolyRing.lex,rel=[e3, e2,  ( e2 * e3 - e2 ), e3, e1,  ( e1 * e3 - e1 )]),
              "",[a, b, e1, e2**10, e3])

Using the internal polynomial parser

The internal polynomial parser has a simpler syntax than the Ruby or Python expression syntax. For example the multiplication operator * can be omitted and ^ can be used for exponentiation **. Moreover, 2/3 will work for rational numbers also in Python.

An example using the internal polynomial parser will be discused in the following. The jython script is be placed into a file, e.g. getstart.py. This script file is executed by calling

  jython getstart.py

If you start jython (or jas -py) without a file name, then an interactive shell is opened and you can type commands and expressions as desired. The script file first imports the desired mathematical classes from the jas.py script which does all interfacing to the Java library. For the Epydoc of it see here.

  from jas import Ring, Ideal

In our case we need Ring to define an appropriate polynomial ring and Ideal to define sets of polynomials and have methods to compute Groebner bases. Ring takes a string argument which contains required definitions of the polynomial ring: the type of the coefficient ring, the names of the used variables and the desired term order.

  r = Ring( "Rat(B,S,T,Z,P,W) L" );

The ring definition is stored in the variable r for later use. The string "Rat(B,S,T,Z,P,W) L" defines the coefficient ring to be the rational numbers Rat, the polynomial ring consists of the variables B, S, T, Z, P, W and the term order L means a lexicographic term order. For some historical reason the term order orders the variables as B < S < T < Z < P < W and not the other way. I.e. the highest or largest variable is always on the right of the list of variables not on the left as in some other algebra systems. With

  print "Ring: " + str(r);

you can print out the ring definition. str(r) is the usual Python way of producing string representations of objects, which in our case calls the respective Java method toString() of the JAS ring object. It produces

Ring: BigRational(B, S, T, Z, P, W) INVLEX

i.e. the coefficients are from the jas class BigRational and the term order is INVLEX (INV because the largest variable is on the right). Next we need to enter the generating polynomials for the ideal. We do this in two steps, first define a Python string with the polynomials and then the creation of the ideal using the ring definition from before and the polynomial string.

ps = """
( 
 ( 45 P + 35 S - 165 B - 36 ), 
 ( 35 P + 40 Z + 25 T - 27 S ), 
 ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), 
 ( - 9 W + 15 T P + 20 S Z ), 
 ( P W + 2 T Z - 11 B**3 ), 
 ( 99 W - 11 B S + 3 B**2 ),
 ( B**2 + 33/50 B + 2673/10000 )
) 
""";

The polynomial string can be generated by any means Python allows for string manipulation. In our example we use Python multiline strings, which are delimited by triple quotes """ ... """. The list of polynomials is delimited by parenthesis ( ... ), as well as every polynomial is delimited by parenthesis, e.g. ( B**2 + 33/50 B + 2673/10000 ). The polynomials are separated by commas. The syntax for polynomials is a sequence of monimals consisting of coefficients and terms (as products of powers of variables). The terms can optionally be written with multiplication sign, i.e. 25 S P can be written 25*S*P. Variable names must be delimited by white space or some operator, i.e. you can not write 25 SP because SP is not a listed variable name in the polynomial ring definition. Coefficients may not contain white space, i.e. the / separating the nominator from the denominator may not be surrounded by spaces, i.e. writing 33 / 50 is not allowed. Powers of variables can be written with ** or ^, i.e. the square of B is written as B**2 or B^2. The ideal is the defined with

  f = Ideal( r, ps );

The ideal is contained the the polynomial ring r and consists of the polynomials from the string ps. Ideals can be printed with

  print "Ideal: " + str(f);

In this example it produces the following output.

Ideal: BigRational(B, S, T, Z, P, W) INVLEX
(
( B^2 + 33/50 B + 2673/10000  ),
( 45 P + 35 S - 165 B - 36  ),
( 35 P + 40 Z + 25 T - 27 S ),
( 15 W + 25 S * P + 30 Z - 18 T - 165 B^2 ),
( -9 W + 15 T * P + 20 S * Z ),
( 99 W - 11 B * S + 3 B^2 ),
( P * W + 2 T * Z - 11 B^3 )
)

The polynomial terms are now sorted with respect to the lexicographical term order. The highest term is first in a polynomial. Also the polynomials are sorted with respect to the term order, but with smallest polynomial first in the list. Finaly we can go to the computation of the Groebner basis of this ideal.

  g = f.GB();

The ideal f has a method GB() which computes the Groebner base. The computed Groebner base is stored in the variable g which is also an ideal. It can be printed in the same way as the ideal f

  print "Groebner base:", g;

The output first shows the output from calling the GB() method and the the ideal basis.

sequential executed in 136 ms

Groebner base: BigRational(B, S, T, Z, P, W) INVLEX
(
( B^2 + 33/50 B + 2673/10000  ),
( S - 5/2 B - 9/200  ),
( T - 37/15 B + 27/250  ),
( Z + 49/36 B + 1143/2000  ),
( P - 31/18 B - 153/200  ),
( W + 19/120 B + 1323/20000  )
)

I.e. the Groebner base was computed in 135 ms and consists of six polynomials. The polynomials are now monic, i.e. the leading coefficient is 1 and omitted during print out. This concludes the getting started section.

Solvable polynomial rings and the internal parser

Solvable polynomial rings are non commutative polynomial rings where the non commutativity is expressed by commutator relations. Commutator relations are stored in a data structure called relation table. In the definition of a solvable polynomial ring this relation table must be defined. E.g the definition for the ring of a solvable polynomial ring is

Rat(a,b,e1,e2,e3) L
RelationTable
(
 ( e3 ), ( e1 ), ( e1 e3 - e1 ),
 ( e3 ), ( e2 ), ( e2 e3 - e2 )
)

The relation table must be build from triples of (commutative) polynomials. A triple p1, p2, p3 is interpreted as non commutative multiplication relation p1 .*. p2 = p3. Currently p1 and p2 must be single term, single variable polynomials. The term order must be choosen such that leadingTerm(p1 p2) equals leadingTerm(p3) and p1 > p2 for each triple. Polynomial p3 must be in commutative form, i.e. multiplication operators occuring in it are commutative. Variables for which there are no commutator relations are assumed to commute with each other and with all other variables, e.g. the variables a, b in the example. Polynomials in the generating set of an ideal are also assumed to be in commutative form. If you need non-commutative multiplication in the polynomial expresions, please use the jython or jruby interface, as discussed above.

A complete example is contained in the Python script solvable.py. Running the script computes a left, right and twosided Groebner base for the following ideal

(
 ( e1 e3^3 + e2^10 - a ),
 ( e1^3 e2^2 + e3 ),
 ( e3^3 + e3^2 - b )
)

The left Groebner base is

(
 ( a ), ( b ),
 ( e1^3 * e2^2 ), ( e2^10 ), ( e3 )
)

the twosided Groebner base is

(
 ( a ), ( b ), ( e1 ), ( e2 ), ( e3 )
)

and the right Groebner base is

(
 ( a ), ( b ), ( e1 ), ( e2^10 ), ( e3 )
)

A module example is in armbruster.py and a solvable module example is in solvablemodule.py.


Overview of JAS Android App

The App has been developed for JAS version 2.5 on Android 5 and is not working on current Android versions (since 2019).

The JAS application uses the Ruboto-IRB Android application. Ruboto provides an jruby scripting interpreter together with an editor application. The Ruboto App is enhanced with the JAS jruby interface and the JAS Java classes.

For the Android app the main screen with the "trinks.rb" example and its output looks as follows.

   

The JAS jruby interface on Android has the same functionality as the general JAS jruby scripting interface (only some functionality of the power series is not avaliable).


Heinz Kredel

Last modified: Mon Feb 28 10:39:28 CET 2022

java-algebra-system-2.7.200/doc/html.css000066400000000000000000000011131445075545500177550ustar00rootroot00000000000000 body { background-color: #FFFFF5; margin-right: 1em; margin-left: 0.5em; } body.main { margin-top: 2.5em; } pre { background-color: silver; margin-left: 1em; margin-right: 1em; padding: 1em; } code { font-family: Courier, monospace; white-space: pre; /* font-size: larger; */ /* background: silver; */ } dt { font-weight: bolder; margin-top: 1em; } nav { line-height: 1.4em; } h1 { text-align: center; } .center { text-align: center; } .note { color: maroon; } java-algebra-system-2.7.200/doc/index.html000066400000000000000000000050151445075545500203010ustar00rootroot00000000000000 API, jython, jruby, MPJ, OpenMPI and more Documentation

API, jython, jruby, MPJ, OpenMPI and more Documentation

This is an intermediate page to the JAS javadoc API documents and more documents. Further JAS documentation consists of Web overview and summary pages, and of published papers on specific topics of JAS, see intro.


Heinz Kredel

Last modified: Sat Apr 15 17:03:29 CEST 2023

java-algebra-system-2.7.200/doc/jas-log.html000066400000000000000000003225521445075545500205360ustar00rootroot00000000000000 JAS project web-log

JAS project web-log

For a detailed list of the latest changes see the Git change log.

2023, July
More tests with BigQuaternion polynomial coefficients. Fixed a left-right bug in solvable polynomials monic() method. (left and right monic must be distinguished although the inverse of the leading base coefficient is a left and right inverse.) Fix to leftMonic() where required. Adjust polynomial reverse() method with using conjugate() on coefficients. More tests for Ore conditions for polynomials with quaternion coefficients. Fixed default implementations in interface MonoidElem for left, right and two-sided operations by throwing exceptions when not correctly overriden.
2023, May
This release adds exterior derivations for polynomials and rational functions. The weak or strong term order for index lists are now selectable. Explicit k-forms and improved random index lists. More non-commutative unit tests (quotient remainder, Ore conditions, common divisors) for solvable polynomials with quaternion coefficients. Exterior algebra provided within Jruby and Jython interfaces. Renamed inner*Product() to interior*Product() since this seems to be the correct translation. Remove and cleanup unsued experimental code and small bug fixes. Add file with simple NCSS report summary.
2023, March
This release adds exterior algebra polynomials / vectors in classes GenExteriorPolynomial and GenExteriorPolynomialRing. With exterior multiplication and inner left / right multiplication methods. Also included are determinant and resultant methods via exterior algebra algorithms. Add new characteristic polynomial method charPolynomial() using Faddeev-LeVerrier algorithm in class GenPolynomialRing. Add trace()method in class GenMatrix. Fixed many spelling errors, small bug fixes and cleanups.
2023, January
Added more unit test cases to improve code coverage of statement and expression tests together with eventual fixes, for example: exponent vector storage units, polynomial conversions, complex constants, runGB distributed cases, ideal decomposition mod prime, and right solvable multiplicaton. Ensure compatibility with JRuby version 9.4.0.0 (Ruby 3.1.0 compatible). Adjust for year 2023. Further cleanups and small bug fixes.
2022, November
Introduce some right- and two-sided operations in SolvableIdeal to represent such ideals. Time-limited stop for long running or infinite word Groebner Base computations. Additionally counter stop configuration for long running Kronecker factorization algorithm cases, using Pull request 32. Fix bugs in ExpVector subclasses, in methods setVal(), this resolves issue 30. Fix in SquarefreeFieldCharP for polynomial 1. Fixes in SquarefreeFieldChar0 and SquarefreeRingChar0 for recursion to polynomial content. Fix in PolyUfdUtilTest of evaluationPoints() to ensure squarefree input. Added more unit test cases to improve code coverage of statement and expression tests. Further cleanups and bug fixes (see Git log).
2022, September
Tried to improve code in Gen*PolynomialRing constructors and method getZERO() with respect to Java memory model for problems appearing with Java OpenJDK version "11.0.15", 2022-04-19 and still in "17.0.4", 2022-07-22. Added some unit tests to improve test coverage, for example RunGB, RunSGB, IntegerProgram, StandardBaseSeq, jas.kern utilities or GenMatrix and more. Added selectable Quotient normalizations, but only QuoNorm.normDenLead works in other parts of JAS. Other normalizations must be checked and code fixed (see issue 29). Fix bug in UnivPowerSeries method reductum(). Fix bug in ExpVector constructor with respect to hashCode(). Verified again that JAS can be compiled and run with Java 17(.0.3) and jruby 9.2.14 and jython 2.7.2.
2022, July
Fix spelling of names of derivative methods. Taylor series expansion for polynomial quotients. Some code moved from edu.jas.ps and edu.jas.vector to edu.jas.ufd to clear package dependency cycles. Pade approximation from Taylor series, in particular for polynomial quotients.
2022, May
New methods extGB() and inverse() for d- and e-Groebner Bases in classes DGroebnerBaseSeq and via new reduction methods automatically in EGroebnerBasesSeq. Tests can reuse methods isReductionMatrix() and isMinReductionMatrix() from GroebnerBaseAbstract. Added missing methods for normalform, S-polynomial, G-Polynomial with recording in DReduction, EReduction interfaces and DReductionSeq, EReductionSeq classes. For scripting the respective methods eExtGB, iseExtGB, eInverse and iseInverse have been added to Ideal respectively SimIdeal. JAS can be compiled and run with Java 17, but no switch to Java 17 class files at the moment. The JAS debian package is build on Debian 11 bullseye with Java 17 and Jython 2.7.2, so jas.py and jas -py scripts can be used again in Debian.
2022, March
Fix multiplicities of complex roots in ComplexRootsAbstract. complexRoots(). Revisit recursive solvable polynomial algorithms and activate some missing test cases, resolve commutator table related todos, add missing right-multiply using methods from to do list (SolvablePseudoReduction. rightNormalform, rightNormalformRecursive, rightNormalformFactor). Related fixes and extensions in scripting frameworks. Update and revision of JAS web documentation.
2022, January
Continue changes for Log4J version 2 API. Adjust year 2022. Improve maximal ideal check. Further cleanups and small fixes.
2021, December
Continue changes for Log4J version 2 API. Update Log4j version because of potential CVE-2021-44228 vulnerability.
2021, November,
Improved logging dependencies for JAS in Maven POM (see README or download). Started using the Log4J version 2 API. Small fixes and cleanups.
2021, September
Fraction free Gauss elimination. Some matrix concatination operations. Choice of evaluation points for Hensel lifting. Some more polynomial utilities: reciprocal transformation, translation and evaluation. Missing algebraic number Jython examples. Cleanups and small bug fixes.
2021, August
Factorization now provides Berlekamp, Cantor and Zassenhaus algorithms. Corresponding methods are contained in classes ufd.PolyUfdUtil and ufd.FactorModularBerlekamp and are called contructQmatrix and baseFactorsSquarefree. There are sub-methods for the small and big primes algorithm variants. Berlekamp factorization algorithm is now the default for polynomials over finite fields (algebraic extensions of prime fields), defined in FactorFactory for this case. GenMatrix is equiped with an inverse method with the help of LinAlg.decomposeLU. The extension field builder has a new method matrixExtension to provide matrix extension rings. A sparser form of a given row echelon matrix is computed by rowEchelonFormSparse. Some other small fixes and improvements.
2021, July
Linear algebra package extended by LU decomposition, solution of systems of equations, matrix inversion, determinants, null space basis and row echelon form computation. Methods are called decompositionLU, solveLU, determinantLU, inverseLU, nullSpaceBasis, rowEchelonForm and rankRE. They are contained in class vector.LinAlg. Corresponding methods and examples for JRuby and Jython created. Methods contFrac and contFracApprox for continued fraction computation for JRuby and Jython. Further cleanups, improvements and small bug fixes.
2021, June
New methods chineseRemainderTheorem, isChineseRemainder and CRTInterpolation in class PolyGBUtil for computing Chinese remainders for polynomials, polynomial interpolation and test. Together with corresponding methods and examples for JRuby and Jython. New class SquarefreeFieldChar0Yun with Yun's square-free decomposition algorithm. This is now the default algorithm in square-free factory methods since it is slightly faster. Other small fixes and improvements. Fix github deployment.
2021, May
New method factors in class PolyUfdUtil for rational functions of class Quotient. New methods subRing and subRingMember in class PolyGBUtil for computing GB generators for polynomial subrings and membership tests. Together with analogous methods and examples for JRuby and Jython. More small improvements and fixes.
2021, March
Methods for continued fractions of rational and real algebraic numbers. Improved heuristics for polynomial factorization. New real root methods related to Thom's lemma. Minimal root and root separation bounds. Some interval arithmetic, reimplement excludeZero method. Squarefree part fix in edu.jas.root. ComplexRootsAbstract. Delegate compareTo from edu.jas.arith. BigDecimal to java.math. BigDecimal. More unit tests for missing cases. Further code cleanup by Eclipse rules, small fixes and improvements.
2021, February
In this release the source and classes are switched to Java 11, Log4j 2.13.2, JRuby 9.2.14.0 and Jython 2.7.2 with some fixes. For example the deprecated JRuby mathn module for rational number input had to be replaced. JavaDoc is now generated in HTML5, tags and entities in method descriptions fixed. Internal calls to deprecated PseudoRemainder methods are replaced. Termination detection in GreatestCommonDivisorModEval was fixed. A new parsing method for WordPolynomials was added. The SymbolicData test are deactivated as its servers have been terminated. Further cleanups, improvements and small bug fixes.
2021, January
Switch from SVN to Git, so the SVN revision number will no more be part of the JAS version. Several small fixes for some issues found by LGTM. For example, hashCode, potential int, long overflows and parameter typos in Javadoc. Note: From JAS version 2.7 on, the deprecated methods and classes might be removed.
2020, December, 13th
Undo error in selection of evaluation points in factorization of polynomials with integer coeffcients. Fix in Debian package.
2020, December
In polynomial factorization check and force INVLEX term ordering. Improve special case of polynomials with positive degree of trailing term in squarefree decomposition.
2020, May
Cleanup auto generated variable names. Some new tests and examples. Reduce heap memory requirements, see issue #12. Fix / improve Debian lintian errors. Remove Javadoc reserved @usage tag from source and cleanup comments. Further cleanups and bug fixes.
2020, March
Fixed/improved issue #12. Further improvements, cleanups and small bug fixes.
2019, April
Improve factorization of multivariate polynomials with algebraic number coefficients by avoiding Kronecker reduction from multivariate polynomials to univariate polynomials. Do not use ModEval greatest common divisor computations for too small field coefficients of polynomials. New finite field constructors FF(p,n) in JAS scripting interfaces. Update to Jruby 9.1.7 in JRuby interface to JAS. Installation of configparser necessary, require mathn and require Matrix in some place. Other small improvements and bug fixes.
2018, November
New mapOnStream() methods implemented operating on (parallel) stream map methods of polynomial monomials. Performance seems to be worse by factors compared to non stream method variants. Provide a spliterator over monomials for polynomials via a new spliterator() method and class PolySpliterator. Polynomial absolute norm implemented and some improvements for square roots. Converted the usages of edu.jas.util.ThreadPool to java.util.concurrent.ThreadpoolExecutor. Checked that JAS compiles and runs with Java 11 (without module definition). Bug fixes and other small improvements.
2018, October
New smaller modular coefficients in ModInt and ModIntRing based on int integers. Performance improvements for polynomial sum() method for polynomials with unbalanced size. sqrt() approximation for BigRational and tests fixed for complex abs() methods. Further small improvements and bug fixes.
2018, August
New term order for module Gröbner bases and module reduction. Besides the (default) POT module term order there is now the TOP term order implemented for IGRLEX and INVLEX block term order combinations. (POT is "Position over Term" and TOP is "Term over Position".) Fixed issue #6. Further bug fixes and small improvements.
2018, July
Source refactored to use Apache Log4j version 2 API. The dependency to Log4j version 1 API can be removed. The helper logging jars mylog.jar, nolog.jar and droidlog.jar are no more working and obsolet. Add further missing methods for non-commutative WordIdeal. Small improvements and bug fixes.
2018, June
New algorithms of Lazard-Rioboo-Trager and Czichowski for the integration of rational functions developed by Youssef Elbarbary. Improved partial fraction and Bernoulli algorithm. Removed deprecated and unused package edu.mas. Cleanup todo comments. Improve types of return values. Checked that JAS compiles and runs with Java 10. Bug fixes and other small improvements.
2018, March
Improvements in parallel algorithms according to the Java memory model. Other bug fixes and small improvements.
2017, December
This release fixed missing factorization of polynomial content, and added generation of random irreducible polynomials. Checked that JAS compiles and runs with Java 9. Small bug fixes and improvements.
2017, June
This release improved performance of polynomial factoring methods over integers and rational numbers. The affected classes are FactorRational, GreatestCommonDivisorModular and GreatestCommonDivisorModEval. Thanks to Stanislav Poslavsky from the Redberry project for pointing out these issues. Several Findbugs issues have been fixed, for example, insufficient synchronization. Other bug fixes and small improvements.
2017, February
This release adds left and right methods in MonoidElem with commutative default implementations. The Ore condition for StarRingElem classes can be computed. Quaternion classes are refactored for separate Ring and integral quaternion classes. Bug fixes and small improvements. There is now a Maven compatible repository with JAS at http://krum.rz.uni-mannheim.de/maven-repository/.
2017, January
Support Java 8 lambda expressions for the generation of matrix entries and power series coefficients. Factorization for rational functions (quotients of polynomials). Factorization for BigInteger elements. Quaternion implementation extended to handle integral quaternions. Some tests and improvements for (commutative) polynomials with non-commutative coefficients. Other small improvements and bug fixes.
2016, November
New class with integer factorization, partly from previous SAC2/Aldes and MAS codes, mixed with probable prime test from java.math. Main method is factors() in class PrimeInteger. Cyclotomic polynomial construction and decomposition, similar to Sympy. Improvements in Gröbner walk implementation to make source and target term order selectable. Small improvements and bug fixes.
2016, October
New Gröbner walk algorithm in class GroebnerBaseWalk. Extensions to existing code for marked polynomials used in Gröbner walk. Bug fixes and small improvements, more use of Java 8 features.
2016, August
Improved methods to handle real and complex algebraic roots of univariate polynomials based on RootFactory methods. New methods in class RootFactory to compute both the real and complex algebraic roots with algebraicRoots(), method rootsOfUnity() to filter roots of unity, and methods rootRefine() and decimalRoots() to compute approximations of real and complex roots. The method rootReduce() in RootFactoryApp helps to construct common field extensions via primitive element computations. The algorithms are also accessible via the scripting interfaces under the same names. Dockerfile to construct a standalone JAS scripting application.
2016, July
Mostly improvements and bug fixes in package edu.jas.fd. Use (Java 8) method power() from MonoidElem where possible. Further bug fixes and small improvements.
2016, May
Improvements in package edu.jas.fd. New class SGCDFactory with methods getImplementation() and getProxy() to obtian suitable common divisor implementations based on the coefficient ring of the polynomials. New class SGCDParallelProxy to run two common divisor implementations in parallel and take the result of the first finished one (compare to GCDProxy). The solvable left and right common divisor algorithms are now used in SolvableLocalResidue, SolvableLocal and SolvableQuotient to reduce the fractions to lower terms. Refactoring some classes to edu.jas.fd package. Bug fixes, small improvements and use of more Java 8 features.
2016, March
New signature-based Gröbner base algorithms, F5, GGV and Arri, after the paper "Signature-based Algorithms to Compute Gröbner bases" by Eder and Perry, ISSAC 2011. The classes are GroebnerBaseF5SigSeqIter, GroebnerBaseGGVSigSeqIter, GroebnerBaseArriSigSeqIter and are selectable via GBAlgorithmBuilder methods F5(), GGV() and Arri(). Some of the new methods use Java 8 constructions. GBAlgorithmBuilder expressions can be used in RunGB using the parameter build=string. Started with new methods bitLength() for coefficient arithmetic classes and polynomials. Some bug fixes and small improvements. Debian package improved.
2016, February
This is release 2.6 of JAS. We have switched to latest versions of used packages, for example to Apache Log4j version 2.5, JRuby version 1.7.23 and Jython version 2.7.0. Junit 4.12 is already used since the last JAS version. At the moment all old versions of these packages will still work, but this may change in the next JAS versions. From then on we will eventually also make use of Java 8 features. The old version will be kept here: JAS 2.5.
We removed some long time deprecated classes GBDist, GBDistHybrid, GroebnerBaseDistributed, GroebnerBaseDistributedHybrid, the method divideAndRemainder of several classes and some other unused methods. Code cleanup and unified logger declaration. New class IntegerProgram to solve integer optimization problems via Gröbner bases. Tests and some fixes for compatibility of term orders with Sage, Singular and Mathematica. Several small bug fixes and improvements. Print JAS version in jython and jruby modules. Iterative Gröbner base algorithms selectable in GBAlgorithmBuilder.
2016, January
New parallel iterative Gröbner base algorithm in class GreoebnerBaseParIter. Names for Sage, Singular and Mathematica term orders defined in class TermOrderByName. Better separation of ExpVector from TermOrder. Missing polynomial methods weightDegree() and leadingWeightPolynomial() added. Switched to Junit 4.12 and use the timeout option on long running tests. Small improvements, changes and bug fixes.
2015, December
New iterative Gröbner base algorithm in class GreoebnerBaseSeqIter. Term orders with weight matrix are now usable from jython and jruby via the PolyRing constructors. More names for defined and implemented term orders in class TermOrderByName. Improved unit tests and further small changes and bug fixes.
2015, November
Extensions to experimental classes for solvable polynomials with non-commutative word polynomials and non-commutative residue classes as coefficients. Fixed bugs spotted by new findbugs version. Small improvements and bug fixes. The distributed byte code is now Java 8. But no Java 8 features have been used and the sources still compile with Java 7.
2015, July
Refactoring of the intefaces and classes in package edu.jas.gbmod to the packages edu.jas.gb and edu.jas.gbufd to cut the package dependency cycles. Changes to the organization and contents of the Web pages. Note: The next release will eventually use Java 8 features and drop Java 7 support, moreover many deprecated methods and classes may be removed.
2015, May
New experimental classes for solvable polynomials with non-commutative word polynomials as coefficients. Adjustments for solvable left multiplication with word polynomial coefficients and corresponding changes for Gröbner bases (might not be computable in all cases). More valueOf methods in polynomial ring classes to construct polynomials from coefficients and exponents or words. Check for missing Ore condition usage in solvable reduction algorithms. Use Ore condition in solvable pseudo reduction algorithms for solvable polynomial coefficients. There is a new class GreatestCommonDivisorFake in which gcd methods always return 1. Bugfix in two-sided Gröbner bases right coefficient multipliers. Fixed the polynomial parser to accept some more ASCIIMath expressions. Small improvements and refactoring of the HTML documentation.
2015, April
New two-sided Gröbner bases for solvable polynomial rings with parametric coefficients and commutator relations between coeficient variables and main variables. Addition of this methods also to SolvableIdeal. New right module Gröbner bases and right module syzygies. Syzygy methods added to scripting interfaces. Performance improvements for solvable polynomial multiplication and polynomial reduction. Small bug fixes and improvements. Moved one JAS repository from Google code to GitHub since Google code will be discontinued.
2015, March
Small modifications to comprehensive Gröbner bases implementation to allow computation of left comprehensive Gröbner bases in case of solvable polynomials with commutative parameter coefficients. Shared memory parallel versions for module Gröbner bases. Refactoring to remove package dependecy cycles. Code cleanup, small fixes and improvements.
2015, February
Parallel versions for module Gröbner bases. Refactor syzygy computation classes into abstract and sequential classes. Disable some correctness checks in syzygy computation depending on disabled Java assertions. Improve solvable relation table updates. Proxy and factory for solvable Gröbner bases SGBProxy and SGBFactory. Refactor term order optimization methods to naturally / better suited classes. Make use of ModLong classes and the improved RingFactory parser in the scripting interfaces. Remove the dependency on Junit from the src-tree. Some more small fixes and improvements. Ivy resolve task for log4j and junit libraries.
2015, January
Integer and (commutative) polynomial coefficients in solvable and word Gröbner bases. New classes WordResidue and WordResidueRing for residue classes modulo twosided ideals WordIdeal in word polynomial rings (free non-commutative algebas). Fix missing critical pairs to consider in word Gröbner bases. Code cleanup and small fixes and improvements.
2014, December
Added some jython and jruby scripts to access the SymbolicData data base of polynomial systems. Small improvements and corrections. The code now compiles and runs with Java 8.
2014, October
Improved issues spotted by code-spotter.com. Cleanup and improvements of the RingElem class in the jython and Ruby script interface. Small improvements for recursive pseudo division Gröbner bases and corrections, new Junit test cases.
2014, September
Use of automatic variables in Jython and JRuby examples where possible. By this, the variables of a polynomial ring PolyRing(QQ(),"x,y") are directly available as script variables x, y with out calling r.gens(). Improved jas script to run also under Debian with MathLibre. Small updates, new diagrams and pictures.
2014, August
New class BigDecimalComplex for complex floating point arithmetic. Some fixes and other small improvements for floating point calculations. The Java bytecode of JAS is now dual licenced under the Apache 2.0 licence to allow its usage in Android projects.
2014, June
Small bug fixes, code optimizations, some new UML class diagrams and code cosmetic. Added Apache Commons Math3 adapter to the repository.
2014, April
The solvable polynomial common divisor package edu.jas.fd is now in a usable condition. The definition of greatest common divisor has changed slightly and left and right gcds are now distinguished. Various improvements, refactorings and bug fixes. Detection of wrong method dispatching by JRE in GenSolvablePolynomial and GenPolynomial. Cleanup of Gröbner base packages. Completion of GB class constructors with PairList parameters. New parallel recursive polynomial Gröbner base computation. Refactoring of Quotient coefficient cases. Handle more cases in GBAlgorithmBuilder and GBFactory. jython scripting GB with selectable sig-based GB algorithm. Unit tests for the new algorithms.
2014, March
Small improvements in solvable polynomial common divisor computation, more cases working. New method for right pseudo division. Performance improvements in PrimeList. Restore and keep MPJ Express compatibility and test cases.
2014, January
New package edu.jas.fd for solvable polynomial common divisor computation. It will contain algorithms for (non-unique) factorization domains. There are methods for polynomial pseudo remainder computation over Ore domains in class FDUtil. Further, methods for common divisors are included, but not yet finished. Converge and cleanup MPJ and MPI implementations. Added Javadocs for JLinAlg adapter.
2013, November
New solvable local residue ring SolvableLocalResidue as solvable quotient field modulo an ideal. New generic solvable polynomials QLRSolvablePolynomial with abstracted generic coefficients from solvable quotient, local or local-residue rings. Implemented corresponding interfaces QuotPair and QuotPairFactory in respective classes. Adjust and extend scripting examples for the new classes. Removed differences and clean-up different versions of Run*GB stand alone Gröbner base programs.
2013, October
Android version of JAS based on Ruboto (JRuby for Android) now with signed code and installable from download. Least common multiple for solvable polynomials and trial greatest common divisor for solvable polynomials. Apel-Lassner canonical simplifier to obtain "smaller" solvable quotients in method leftSimplifier(). Some code refactoring to break package dependency cycles. Fixed, cleaned and worked-around some more Findbugs and Eclipse issues. Dropped Java-5 compatibility in most places.
2013, September
New distributed Gröbner base algorithms based on the Java bindings of OpenMPI similarly to the MPJ version. Both OpenMPI and MPJ are not thread-safe for all devices (in particular not for the ibvdev InfiniBand device), MPJ is thread-safe for niodev Java NewIO device. As work-around the transport layer of both versions is split to allow selection of TCP/IP sockets or MPI/MPJ channels for transport. The channels and distributed hash tables have been simplified for both MPJ and MPI. Socket based distributed hash table now implements the clear() method. This caused unspecific errors in iterated distributed Gröbner base computations. Simplified solvable multiplication. Fixes and improvements to Jython and JRuby scripts.
2013, August
New algorithms for solvable polynomial rings over solvable local rings in classes LocalSolvablePolynomialRing and LocalSolvablePolynomial. New scripting examples for solvable polynomials with solvable local coefficients. Refactoring for non-commutative relation handling of solvable polynomials with interface RelationGenerator. Fixed and cleanup some more Findbugs and Eclipse issues. Several fixes and improvements for jruby of Android.
2013, July
New algorithms for solvable polynomial rings over solvable residue rings in classes ResidueSolvablePolynomialRing and ResidueSolvablePolynomial. Methods to compute annihilators with respect to ideals and solvable ideals. New scripting examples for solvable polynomials with solvable residue coefficients. Fixed associativity of solvable multiplication by considering all Ore conditions.
2013, May - June
New algorithms for recursive solvable polynomial rings in classes RecSolvablePolynomialRing and RecSolvablePolynomial. New solvable polynomial rings with solvable quotient coefficients are avaliable in classes QuotSolvablePolynomialRing and QuotSolvablePolynomial. This rings feature non-commutative multiplication of variables with coefficients. New scripting examples for recursive solvable polynomial rings and solvable polynomials with solvable quotient coefficients.
2013, April - May
New algorithms for ideals in solvable polynomial rings in class SolvableIdeal, and new structures for solvable polynomial rings in classes SolvableQuotient, SolvableResidue and the corresponding factories SolvableQuotientRing, SolvableResidueRing. There is a new theme for Ruby rdoc documentation and the scripts have been adapted to a newer version of jruby (1.7.3). Further small fixes and improvements.
2013, January
New version number 2.5. The JAS Java API will be more stable from now on. Fixed a race condition in distributed (hybrid) Gröbner bases implementations. Improved MPJ version of GBs. Refactoring of GBFactory and added new option to select Gebauer & Möller critical pair handling in GBAlgorithmBuilder. Switch to DECIMAL128 as default in BigDecimal. Improved GreatestCommonDivisorHensel by using integer evaluation points and other optimizations.
2012, December
Mostly performance optimizations and small improvements and fixes. The optimizations include combined methods for polynomials like scaleSubtractMultiple(b, g, a, e, S) to compute the expression b xg this - a xe S in one rush. There is now first version of an Android App. The JAS App uses its JRuby scripting interface and runs within the Ruby IRB Android App Ruboto.
2012, November
New distributed Gröbner base algorithms based on MPI as communication middle-ware. The implementation uses the MPJ (MPI Java) API and can be run with both MPJ Express or FastMPJ. The implementing classes are GroebnerBaseDistributedMPJ for the pure distributed version and GroebnerBaseDistributedHybridMPJ for the distributed and multi-threaded version.
2012, October
New parts for free non-commutative Gröbner base computation and polynomial reduction. New interface WordGroebnerBase and new classes WordGroebnerBaseAbstract and WordGroebnerBaseSeq. jython and jruby access to non-commutative polynomials in WordPolyRing and WordIdeal. Improved selection of (commutative) Gröbner base algorithm implementations in class GBAlgorithmBuilder. For example in case of rational number coefficients a fraction free algorithm with optimization of the variable order can be requested by gbab.fractionFree() .optimize() .build().
2012, September
Refactorings to further reduce Findbugs issues. Removed Clonable from Element and renamed clone() to copy(). New classes for free non-commutative associative rings in GenWordPolynomial and GenWordPolynomialRing.
2012, August
Fixed most severe and many medium Findbugs issues. Remaining programming issues and possible bugs are listed in the Findbugs report.
2012, July
More JRuby examples. Bug fixes for right module Gröbner bases and multiple roots computation. Bug fixes for meaningful problems spotted by findbugs.
2012, June
Improved root bounds for real root computation. Added missing methods for real root computation. Fixed complex root selection of zero dimensional ideals. Small fixes and more missing methods.
2012, May
More, refactored and fixed algorithms for Wu-Ritt characteristic sets in class CharacteristicSetWu. Unit tests are in CharSetTest. jython and jruby script access to characteristic set algorithms in methods CS(), isCS(), csReduction(). Small fixes and improvements.
2012, March
The Jython and JRuby scripting classes PolyRing are now injecting the polynomial ring variables into the top level interpreter environment by default. New class GroebnerBaseFGLM to compute a Gröbner base according to the "FGLM" algorithm. It computes a Gröbner base with respect to a graded term order and then constructs the Gröbner base with respect to the requested term order via linear algebra in the residue class ring. Changes from '{}' to '()' in GenPolynomial to string conversion. New launcher shell script jas. Small fixes, improvements and a missing method implemented and in PolyUtilApp.
2012, February
Refactorings to simplify type parameters and loosen type conditions. New package edu.jas.ufdroot to remove cyclic package dependencies again. Improved selection of factorization implementations in FactorFactory classes and better suited constructors of the factorization implementations. Small fixes and improvements.
2012, January
Some algorithms for Wu-Ritt characteristic sets and unit tests in class PolyGBUtil. Small fixes and improvements.
2011, Sylvester
Modular variants and parallel proxy versions of resultant algorithms implemented. Cleanup and filled missing methods in GreatestCommonDivisor* classes in the edu.jas.ufd package. Fixed ModLong to ModInteger conversion. Small fixes, improvements and refactorings of methods to right classes.
2011, December
Switched to Java 7 for development. JAS will still compile and run on Java 6 and Java 5. A new online repositoriy for JAS on Google code which contains a bug-tracker. Definition of variables for polynomial ring generators in the jython and jruby scripting interface. More JRuby examples.
2011, October
Separated test classes to new test source tree (trc). New scripting classes for Gröbner base computations according to Eder and Perry (F5, Arri, GGV) and adapted jas.py in JAS for the required methods. More JRuby examples. Small improvements and fixes.
2011, September - October
Release 2.4 updates all depending packages to the latest version and prepares for JAS 3.0. Updates for Jython 2.5.2 and JRuby 1.6.4. A new index of all algorithms from the book Algorithms for Computer Algebra by Geddes & Czapor & Labahn to their JAS equivalents. Small improvements and fixes again in multivariate integral polynomial factorization.
2011, September
Bug fixes and missing cases for multivariate integral polynomial factorization with multivariate Hensel lifting. Further improvements and fixes.
2011, August
Experimental multivariate integral polynomial factorization with multivariate Hensel lifting in method factorsSquarefreeHensel() in class FactorInteger. Improved multivariate Hensel lifting in class HenselMultUtil. Small improvements and fixes.
2011, June
Experimental ideal complex root computation in method complexAlgebraicRoots() in class PolyUtilApp. Simple isolating interval refinement for real and complex roots. Alternative factoring of univariate polynomials over algebraic number fields via prime ideal decomposition in class FactorAlgebraicPrim. Improved parsing of complex numbers. Forced term orders in some situations and further small improvements and fixes.
2011, May
Complex roots represented by ideal real roots, uses new class RealAlgebraicNumber and RealAlgebraicRing in package edu.jas.application. New experimental RootFactory with methods to compute complex roots for polynomials with coefficients in some complex algebraic extension field of the rational numbers. Uses the respective classes form package edu.jas.root in a recursive setting. New generic factorization classes FactorRealAlgebraic and FactorRealReal. Small improvement for reduced / minimal Gröbner base computation.
2011, April
Multivariate algebraic ring / field extensions using class ResidueRing. Jruby and Jython versions and examples of the extension field builder. Small improvements and bug fixes for latest Eclipse and Java 1.7 version.
2011, March
Easy to use construction of towers of extension fields in class ExtensionFieldBuilder with methods for algebraic and transcendental field extensions. Improvements in real and complex algebraic numbers. Improved polynomial parser for recursive representations. Small bug fixes.
2011, February
New class HenselMultUtil for multivariate Hensel lifting. Will be used in polyomial factorization in the future. Some parts of greatest common divisor using multivariate Hensel lifting. The JAS source (r3408) compiles on Apache Harmony 6.0 (r991881). The unit tests pass with the exception of test cases involving object serialization.
2011, January
New scripting interface to Ruby (JRuby). Ruby allows rational number literals as p/q, which are better than the Python tuple form (p,q). Some toScript() methods rewritten to reflect the Ruby language requirements and to differentiate between Ruby and Python. More precise exceptions for modular computations to return also the discovered factors.
2010, December, 28
Cleanup of package structure so that all cyclic dependencies have been removed, see diagram. Split factory parsing parts from GenPolynomialTokenizer to RingFactoryTokenizer. Some artificial code was required to use solvable polynomials as ring elements since solvable polynomials cannot implement RingElem<GenSolvablePolynomial<C>>. This resulted in some cases in wrong method dispatch for the multiply() method due to compiler optimizations. A work around to detect and repair this is now implemented in class GenPolynomial.
2010, December, 18
New critial pair selection for Gröbner base computation with syzygy based algorithm after Gebauer and Möller in class OrderedSyzPairlist. Refactoring of Gröbner base classes to optionally use the new pair selection. Back port of some JDK 1.6 constructs to be again compatible with JDK 1.5. Small improvements in Kronecker factor combination in class FactorAbstract. Fixed race condition in ThreadPool and improved termination detection in Terminator. Fixes in parallel reduced Gröbner base computations. Fixed univariate polynomial construction in Ideal.
2010, October
Multivariate Taylor series expansion interface and implementation. Improved multivariate power series for standard base computation. Refactored methods to better suited classes and moved classes to decouple packages, e.g. Quotient* to package edu.jas.ufd. Fixed small bugs and cosmetic.
2010, September
Multivariate power series in classes MultiVarPowerSeries and MultiVarPowerSeriesRing. Mora's tangent cone reduction algorithm and standard base computation for power series in package edu.jas.ps. Iterator over exponent vectors.
2010, August, 28
Iterators for finite and some infinite structures and finite and infinite cartesian products of them. Fixed constructors to comply with the (new) Java memory model. Small bug fixes and improvements. More meaningful exceptions and some renamings.
2010, August, 8
Improved the polynomial parser to accept rational numbers denoted with decimal points and to accept BigDecimal coefficients. Removed the use of the underscore for algebraic number coefficients in the polynomial parser. Now every recursive call of parse() from a ring factory is triggered by braces which can be nested to any depth. Fixed synchronization bug in solvable polynomial relation tables and a parallelization bug in parallel solvable polynomial Gröbner base computation. Use of unbounded thread pools to avoid dead-locks. Added remaining parts for the square-free decomposition in polynomial rings of characteristic p > 0. Changed the script representation of AN (AlgebraicNumbers).
2010, July
Downgraded for Java 5 language and run-time system for use with systems relying on older Java versions, for example MathPiper and GeoGebra. New class edu.jas.kern.TimeStatus to provide user feedback for long running tasks via method checkTime(). Implemented some missing extGB() methods. GBFactory for the selection of appropriate Gröbner base implementations. New method isFinite() for all ElemFactorys and usage in SquarefreeFactory. Added some missing parts for the factorization in polynomial rings of characteristic p > 0 and ideal decomposition.
2010, June
Factory for Gröbner base algorithm implementations in class GBFactory. New GBProxy like GCDProxy to run a sequential and a parallel Gröbner base computation concurrently. Primitive element computation via normalPositionFor() in methods primitiveElement() together with several conversion methods convertToPrimitiveElem(). A new index of all algorithms from the book Gröbner bases to their JAS equivalents.
2010, May, 28
Implementation of arbitrary dimensional ideal radical-, irreducible-, prime- and primary-decomposition in class Ideal with methods radicalDecomposition(), decomposition(), primeDecomposition() and primaryDecomposition(). Computation of extension and contraction ideals. Unit tests for the decomposition methods. Fixed a bug in multivariate polynomial factorization in Kronecker's method. Fixed a bug in squarefree decomposition in inseparable case. Added NO_THREADS flag to edu.jas.kern.ComputerThreads to avoid (some) thread creation for usage in Google app engine.
2010, May, 8
Implementation of zero dimensional ideal radical-, prime-, primary- and root-decomposition in class Ideal with methods zeroDimRadicalDecomposition(), zeroDimDecomposition(), zeroDimPrimeDecomposition(), zeroDimPrimaryDecomposition() and zeroDimRootDecomposition(). Exact 0-dim ideal real root computation and approximation in methods PolyUtilApp.realAlgebraicRoots() and decimalApproximation(). Small enhancements to Javadoc comments.
2010, April
Some more documentation for package edu.jas.ufd, simplified and improved the factory classes. Refactorings of parallel Gröbner bases computations for solvable polynomial rings. Improved logging for distributed Gröbner bases and distributed middle-ware.
2010, March
Decimal approximations for real and complex roots based on Newton-Raphson iteration restricted to isolating intervals or rectangles. Small enhancements for partial Gröbner bases. Added some Mersenne primes to PrimeList. Construction of minimal univariate polynomials in zero dimensional ideals. Supersets of complex and real roots of zero dimensional ideals. More unit tests for real and complex roots of univariate polynomials and zero dimensional ideal roots. Minor enhancements and fixes.
2010, February
Gröbner bases for sub-sets of variables in class GroebnerBasePartial. Small enhancements: polynomial recursive coefficient parser and a matrix parser. Book-keeping of all used polynomial variable names. New and improved unit tests.
2010, January
Factorization for polynomials with Complex coefficients via algebraic coefficients in Q(i). New classes ModLong and ModLongRing for faster modular arithmetic. New interfaces Modular and ModularRingFactory implemented also by ModInteger to make both interchangable. Improved factorization and serveral refactorings. Factorization mod p = 2 is now implemented.
2009, December
Added a Git repository and a link to Ohloh code analysis of JAS. Cosmetic, small updates and a simple Java scripting interface. New classes for complex root isolation ComplexRoots, ComplexRootsAbstract, ComplexRootsSturm. The implementation provides an exact infallible method which follows the numeric method of Wilf. It uses Sturm sequences following the Routh-Hurwitz Method to count the number of complex roots within a rectangle in the complex plane.
2009, November
New package for the elementary integration of rational functions developed together with Axel Kramer during the computer algebra seminar 2009. The implementation is based on the book Bronstein: Symbolic Integration I. New adapter (commons-math_adapter.jar) for JAS to the Apache Commons Math library version 2.0 by Axel Kramer. Cosmetic, small updates and a jython example for integration.
2009, September
Improved comprehensive Gröbner bases with explicit classes for several alternative implementations of multiplicative sets. Base class is MultiplicativeSet, in sub-classes polynomials made co-prime in MultiplicativeSetCoPrime, polynomials made co-prime and squarefree in MultiplicativeSetSquarefree and polynomials made irreducible in MultiplicativeSetFactors. New distributed hybrid Gröbner base computation with new class TaggedMesageChannel to handle multiple message types and partners over one socket connection. Improved object serialization in distributed hash table. Adapter updated for JLinAlg version 0.6.
2009, August
New adaptor classes (jlinalg_adapter.jar) to use the linear algebra library JLinAlg from JAS. Improvements in the distributed Gröbner bases algorithms. Minor fixes and improvements.
2009, July
Code and output cosmetic, minor fixes and improvements. New interface ToRational used for BigRational and RealAlgebraicNumber to remove type case distinctions in Interval. clone() removed from Element interface because of compiler changes.
2009, June and July
Improved absolute factorization for splitting fields. Fixes and further improvements. Implemented factorization over inseparable field extensions. Fixed squarefree factorization and added unit test. Refactored squarefree tests to separate classes. Refactored squarefree algorithms to separate classes. Interface is Squarefree, abstract class is SquarefreeAbstract. Other main classes are SquarefreeFieldChar0, SquarefreeFiniteFieldCharP and SquarefreeInfiniteFieldCharP.
2009, June
Improved algebraic and absolute factorization. FactorAlgebraic can now also handle factorizations over multiple algebraic extensions like for example Q(i)(sqrt(2)). Class FactorAbsolute is now also extended by FactorAlgebraic, so that absolute factorizations can be computed over algebraic extensions of Q. Added new containers for absolute factorization results and tests for correct absolute factorizations. More toScript() methods and improvements in Jython script interface. Minor additions and fixes.
2009, May
Improved Jython script interface to handle most of the implemented rings, developed in cooperation with Raphael Jolly. New or improved Python functions ZZ, ZM, QQ, DD, CC, Quat, Oct, PolyRing, AN, RealN, RF, RC, LC, SolvPolyRing and RR, PS, Vec, Mat for the construction of rings and elements. Added generic Complex class and ComplexRing factory. Fixed a programming bug in factorization code.
2009, April
Added factory() method to Element interface to have an uniform way to obtain a corresponing ring object. Improved RealAlgebraicNumber so that it can be used as polynomial coefficients, for example GenPolynomial<RealAlgebricNumber<BigRational>>. Real root isolation can now also be used for polynomials with real algebraic coefficients, for example RealRootsSturm<RealAlgebraicNumber<BigRational>>.
2009, March
Implemented univariate polynomial real root isolation algorithms and real algebraic numbers in package edu.jas.root during CISIS/ECDS 2009. Reached 100.000 lines of Java code.
2009, February
Finished first version of polynomial factorization algorithms. Refactored package names edu.jas.ring to edu.jas.gb and edu.jas.module to edu.jas.gbmod.
2009, January
Switch to version 2.3 with experimental factorization of polynomials. Factorization interface with FactorAbstract class for common codes. Factorization of univariate polynomials with several coefficient rings: modulo primes in class FactorModular, over integers in class FactorInteger, over rational numbers in class FactorRational and over algebraic numbers in class FactorAlgebraic<C> (where C can be ModInteger or BigRational). Multivatiate polynomials are reduced to the univariate polynomials via Kronecker substitution and are therefore not very efficient. Refactorings and fixes.
2008, December
Fixed squarefree part and factor computation for modular coefficients. Fixed polynomial compareTo to be transitive as required by Javas SortedMap implementations. Implemented an adaptor package for Apache Log4j to delegate logging calls to native Java logging.
2008, September
Implemented univariate power series during ADG2008 as RingElem and RingFactory types in package edu.jas.ps in classes UnivPowerSeries and UnivPowerSeriesRing. The implementation follows the "Infinite Streams in Java" paper of D. Gruntz in PPPJ2006.
2008, August, 11
Added jython html documentation generated by epydoc. Added jython module to allow native polynomial expression input.
2008, August, 8
New release 2.2. Implemented interface to use JAS as an meditor engine, see jscl-meditor.
2008, July
Finished implementation of comprehensive Groebner bases via Groebner systems. Object oriented class layout uses Condition and ColoredSystem classes. Conditions consist of an ideal (with lazy Groebner base computation) for the conditions equal to zero and a multiplicative set for the conditions not equal to zero. Non-zero condition polynomials are reduced modulo the ideal of condition zero polynomials. The squarefree part from both condition polynomials is used. It differs from the MAS implementation by Schoenfeld, Pesch and others by the ideal used to store the zero conditions and some more details.
2008, June
Added dimension computation to Ideal. Added term order optimization method to Ideal. Refactored ExpVector for different storage unit implementations of the exponent arrays. Supported storage units are long, int (now the default, as seems to be the fastest), short and byte. The respective classes are ExpVectorLong, ExpVectorInteger, ExpVectorShort and ExpVectorByte.
2008, January and February
Added Groebner bases for polynomial rings over regular rings RGroebnerBaseSeq and RGroebnerBasePseudoSeq. Refactorings and fixes.
2007, November and December
Added von Neuman regular rings as (finite) direct products of rings, Product and RegularRingElem. Added fraction free pseudo reduction and Groebner bases GroebnerBasePseudoSeq. Minor refactorings and fixes.
2007, October
Added Groebner bases in polynomial rings over principal ideal domains and Euclidean domains, so called D- and E-Groebner bases, DGroebnerBaseSeq and EGroebnerBaseSeq. Added test methods for reducibility and refactored sequential Groebner base implementations.
2007, September
Minor refactorings and fixes. Modular rational functions and related conversions.
2007, August, 19
Added term order optimization for polynomial and rational function coefficients.
2007, August, 12
Cleanup of UFD code and subversion exports. Term order optimization also available in jython.
2007, July, 28
Added term order optimization class from old DIP/MAS system. This introduced a dependency on JDK 1.6. Refactored source tree to allow fully functional subversion exports.
2007, July, 12
New global class edu.jas.kern.ComputerThreads to represent a thread pool. To stop JAS, when the pool has been started, it is required to call ComputerThreads.terminate().
2007, July, 11
New preemptive cancellation handling. Introduced class PreemptingException as runtime exception and a global class PreemptStatus to allow or deny preemption cancellation. GenPolynomialRing queries PreemptStatus upon creation. GenPolynomial checks preempt cancellation handling and thread interrupt status on construction. If preemption is requested, it throws PreemptingException. This allows e.g. GCDProxy to ignore the respective sub-task and get the thread free. Removed explicit isInterrupted() checks in edu.jas.ufd package.
2007, July, 10
Refactored generation of (lists of) univariate polynomials from SolvableGroebnerBase* to GenSolvablePolynomialRing and GenPolynomialRing. Implemented generic Power class in edu.jas.structure, refactored power() in subresultant PRS.
2007, July, 9
Added unit tests for distributive law in arith and poly packages. Review of all documentation comments.
2007, July, 8
Added assertions to check for number of polynomial variables in GenPolynomial. In ModInteger and AlgebraicNumber inverse() now throws a NotInvertibleExecption, which extends runtime exception. Fixed some correctness bugs detected by Findbugs.
2007, July, 7
Refactored ModInteger for ModIntegerRing factory. Changed all depending classes. Refactored GenPolynomial.getMap() to return unmodifiable SortedMap. Refactored GenPolynomial.val using methods from jas.ufd package to jas.poly package. ExpVector.getVal() renamed and made package private. Logger variables now also final.
2007, June, 10
Improved InterruptedException handling. Refactored use of edu.ky.parallel package to use edu.jas.util and java.util.concurrent. Refactored project web-site.
2007, April and May
Implementation of greatest common divisor algorithms. Using recursive types. Implemented remainder sequences: primitive, monic, subresultant. Implemented modular methods with chinese remaindering for ModIntegers and evaluation in finite fields to reduce the number of variables. Implemented Hensel lifting: linear and quadratic; mod ideal is still missing. Factory classes to select "best" implementations. Proxy classes to run probable good implementations in parallel, taking the result of the first terminating algorithm. Refactored many classes to fit for the new requirements. New method characteristic() in RingFactory and implementing classes. Changed Quotient (rational function) to use new gcd algorithms. Can compute GBs for polynomials with rational function coefficients.
2006, March
Refactored ring package to separate application package with more application of Groebner bases oriented classes. The ring package could now be renamed to gb package. Cosmetic and documentation improvements, e.g. javadoc package descriptions and type parameter tags, removed all tabs in all java files. Implemented generic Quotient(Ring), Residue(Ring) and Local(Ring).
2006, February, 27
Implemented parallel solvable Groebner base algorithms and tests. New class distributed ThreadPool. Cosmetic and code improvements spotted by eclipse, lint4j and jdepend. Refactored module package to separate vector package with basic linear algebra and list handling classes. Refactored to allow different Groebner base or reduction engines where appropriate. Split Syzygy etc. to an interface and a class. Factored basic linear algebra out of Syzygy etc. Adapted jython files to Jave code refactorings. Reorganized jar files and documentation.
2006, February, 12
Moved old examples to MAS subdirectory and new examples to examples directory. Implemented some right version algorithms using opposite rings. Switched to subversion from cvs. Fixed bugs in new left syzygy algorithm.
2006, January
More documentation and cosmetic. Implementation of an extended Groebner Base algorithm and arbitrary base syzygy computation. GenPolynomialTokenizer enhanced to parse algebraic number and Galois field coefficients. Fixed an error in leftNormalform.
2005, 12, 30
New classes CriticalPair and CriticalPairList replace OrderedPairlist. Reworked GB parallel and distributed versions to better respect sequential version critical pair sequences. Fixed some race conditions in parallel and distributed algorithms.
2005, 12, 28
Refactored all classes to remove static methods. So to use any method at first an appropriate object is required. Also class organization has changed to interfaces, abstract classes and concrete classes, e.g. GroebnerBase, GroebnerBaseAbstract, GroebnerBaseSeq, GroebnerBaseParallel and GroebnerBaseDistributed.
2005, 12, 27
Implemented new Ideal class with some ideal operations like sum, product, intersection and quotient. Added TermOrder extension and contraction.
2005, 11-12
Updated documentation comments.
2005, 7, 24
Updated old Java JDK 1.4 branch. Bugfixes (in twoSidedGB), minor changes and cosmetic.
Updated documentation for new Java JDK 1.5 branch.
2005, 5-7
Working through all classes to introduce type parameters and making all implied modifications.
2005, 5, 5
Switched to Java 1.5. Now using covariant returns for implemented interfaces.
2005, 3, 25-29
Some module algorithms implemented. Activated project web pages.
2005, 3, 12-19
Some Syzygy algorithms implemented. Cosmetic on comments and forked web-log.
2005, 3, 5
For the python languege and interpreter exists also a Java version named jython. This system can directly access Java classes and execute Java methods. Added some jython modules Ring, Ideal, SolvRing and SolvIdeal, to access jas GB algorithms from jython.
2005, 2, 25-28
Penality of commutative GB computed as non-commutative left GB is about 24% for (graded) Katsura 6 to 74% for (graded) Katsura 5. Commutative GB computed as non-commutative twosided GB is about a factor of 4 for (graded) Katsura 5 to a factor of 9 for (graded) Katsura 5. Penality for weighted degree term order compated to graded Term order is not measurable or sometimes better. Fixed error in polynomial getONE() to correct term order. Parser for non-commutative problems with relation tables (but only commutative representations) and RunSGB main routine.
2005, 2, 14-21
New TermOrder with direct generation of Comparators for ExpVector comparisons. Split term orders (elimination orders) and weighted degree orders.
2005, 2, 4-8
New unit test case for TermOrder. Fixed weak point in polynomial getONE() to correct number of variables, e.g. correct exponent vector size. Polynomial constant ONE still has wrong exponent vector size. Deleted many old polynomial classes.

Implemented noncommutative product for solvable polynomials, together with relation tables. SolvableOrderedMapPolynomial extends OrderedMapPolynomial. RatSolvableOrderedMapPolynomial extends SolvableOrderedMapPolynomial. Interface SolvablePolynomial extends Ordered Polynomial. Some more left multiplication methods, left reduction and left Groebner Bases, twosided Groebner Base test and computation. Pairlist class changed to avoid usage of criterion 4 if running for SolvablePolynomials, also criterion4() method itself checks for SolvablePolynomials.

RelationTable timings I, U(sl_3)
run / n 2 3 4 5 6 7 8 9 10 11 12 13 14 15
first 3 13 32 92 128 188 274 420 683 1126 1795 2793 4380 6741
second 0 1 2 3 4 5 6 8 10 13 16 21 27 35

Timings in ms on AMD XP 2800+. Computation of (Y^n) * (X^n) with respect to the relation Y * X = X Y - H. In the first run the relation table is populated with the products Y^i * X^i, i = 2,...,n. In the second run the relations are reused, showing almost no computing time anymore for the products.

RelationTable timings II, U(sl_3)
run / n 2 3 4 5 6 7
first 28 94 303 1234 5185 24647
second 1 12 107 782 4569 23897

Second example shows the computation of ( Xa + Xb + Xc + Ya + Yb + Yc + Ha + Hb )^n in U(sl_3). Since in the relation table only products of two variables are stored, the improvement is minimal (for low n).

2005, 1, 24-31
Removed old deprecated classes. Todo: let DistHashTable implement Map Interface. Reimplemented Reduction.Normalform so that asynchronous update of the polynomial list is possible and respected. In case a new polynomial arrives, the reduction is restarted from the beginning. Continuing with the done work and rereducing so far irreducible terms would be an alternative. Todo: use JDK 1.5 java.util.concurrent with interference free Lists, BlockingQueues.
Distributed computation timings, Katsura 6 (G)
# Threads
CPUs
# JVMs time (sec) #put #remove % total
1, seq 1 160.2 70 327 13.5
1, par 1 157.0 70 327 13.5
2, par 1 82.2 72 329 12.7
1, dist 1 177.2 77 334 11.4
2, dist 2 92.2 90 347 8.6
4, dist 2 56.2 112 369 5.9
8, dist 2 58.9 255 516 1.5
4, dist 4 51.2 117 374 5.5
6, dist 4 43.7 129 386 4.6
8, dist 4 62.9 259 519 1.5

Timings taken on a 16 CPU Intel Xeon SMP computer running at 2.7 GHz and with 32 GB RAM. JVM 1.4.2 started with AggressiveHeap and UseParallelGC.
#JVMs = number of distinct Java virtual machines. #put = number of polynomials put to pair list. #remove = number of pairs removed from pair list, i.e. after application of criterions, but including nulls up to now. % total = per cent of removed pairs from total pairs generated, #remove / ( #put * (#put-1) / 2 ) * 100.

Distributed computation timings, Katsura 7 (G)
# Threads
CPUs
# JVMs time (sec) #put #remove % total
1, dist 1 24726.2 140 781 8.0
2, dist 2 12356.1 165 806 5.9
4, dist 4 6859.3 218 859 3.6
8, dist 4 7465.1 411 1054 1.2
8, dist 8 6412.9 344 986 1.6
8, dist 8 7173.3 399 1041 1.3

Overhead for distributed variant is about 10% in Katsura 6 (G). Distributed 1 means one distributed process is running for the reduction of S-polynomials. There is always a master process handling polynomial input / output, setup and management of distributed workers and handling of the pair list. Communication between master and workers is always via TCP/IP with object serialization, even if running on one computer.

2005, 1, 15-16
Further things to improve in GB algorithms (from tsp): local work queues, i.e. local Pairlists, improve data locality in polynomials and lists, communication using message types, reduce object serialization in DL-broadcast by using MarshalledObjects, reduce communication in Pair send by not sending polynomials but indicies (requires distributed hashtable instead of DL), interleave communication and computation by adding a communication thread in the distributed client.

New classes implementing a distributed hash table to hold the polynomials in distributed GB. Index of polynomials in Pairlist is used as hash key. Communication is now using message types GBTransportMess. Now polynomials are only transported once to each reducer since only polynomial hash indexes are transported. Distributed list is asynchronous and late updated, so some duplicate H-polynomials (head terms) could be (are) produced. Solution by local put to hash table with dummy index? Timings are not dramatically better.

Todo: check reduction algorithm to use later arriving polynomials.

2005, 1, 9-14
Introduced all direct improvements in util classes found so far. (ChannelFactory and others) On parallel computers the following JVM options (1.4.2) must be used:
  -Xms200M -Xmx400M -XX:+AggressiveHeap -XX:+UseParallelGC
Memory must be adjusted with respect to your situation.

Seperated versions with Pair Sequence Respecting Order (PS) and normal versions. PS versions try to keep the order of reduced polynomials added to the ideal base the same as in the sequential version. Normal versions now running OK on parallel computer with the right JVM options. Refactoring with Eclipse (organize imports, static methods).

Parallel computation timings, Katsura examples
# Threads
CPUs
Katsura 6 TO(G)
load*
Katsura 6 TO(G)
empty*
Katsura 7 TO(G)
load*
Katsura 7 TO(G)
empty*
seq 184.5 153.3
1 181.5 4% / 159.7 28418.6
2 118.6 s2.02 / p2.11 / 75.6 p2.06 / 13760.0
4 76.8 s3.79 / p3.95 / 40.4 6256.9 p4.56 / 6225.1
8 43.2 s7.19 / p7.49 / 21.3 3240.7 p8.56/ 3318.8
10 42.5
12 40.5 2288.1 p9.90 / 2868.4
14 31.2
16 51.9 s8.19 / p8.54 / 18.7 5376.4 p12.59 / 2256.1

Timings taken on a 16 CPU Intel Xeon SMP computer running at 2.7 GHz and with 32 GB RAM. JVM 1.4.2 started with AggressiveHeap and UseParallelGC.
*) timing taken with other load on the CPUs. +) timing taken with no other load on the CPUs.
Speedup: s = relative to sequential, p = relative to parallel with one thread / CPU.
Scaling from 8 to 16 CPUs is bad, but also observed on non CA / GB Examples (Java and C/FORTRAN).

2004, 10, 3
Generator for Katsura examples (from POSSO / FRISCO examples). Timings on an AMD Athlon XP 2800 (2086MHz) with log level INFO. Log level WARN would gain 10-20 %.
Timings Katsura examples
N
vars = N+1
TermOrder Seconds TermOrder Seconds
7 G 32044.204 L
6 G 112.641 L
5 G 4.195 L
4 G 0.431 L 11.650
3 G 0.153 L 0.310
2 G 0.031 L 0.032
2004, 9, 20-26
Changed OrderedPairlist to record the sequence of pairs taken from the list. New methods putParallel(), removeParallel() and helper methods. Sequence numbers are generated and reduced polynomials are only put to the pair list if corresponding pair number is in correct (sequential) sequence. The ordered list / queue pairsequence (TreeMap/SortedMap) keeps track of the polynomials not yet put to the pairlist.
Parallelism is possible as long there are pairs to be reduced. But non zero reduced polynomials are only put into the pairlist if the polynomial would be put into the pairlist in the sequential Buchberger algorithm. GroebnerBase algorithms had to be modified to record that a polynomial reduced to zero.
2004, 9, 19
Changed order of Pair inserts for pairs with same LCM of HTs. Added sequence number to each Pair and indicator if Pair did not reduce to zero.
2004, September
Implemented Java server (ExecutableServer) for remote execution of objects implementing the RemoteExecutable interface.

New setup for the distributed computation of GBs: the GB master now sends the client code to some ExecutableSevers based on a maschine file with host and port infos about the distributed environment.

Improved the PolynomialTokenizer so that it can read almost unedited old MAS GB input files: ** exponents and parenthesis around polynomials. Lines starting with # are treated as comments. Comments (* *) and parenthesis within polynomials are still not supported.

Implemented a common driver for GB computations RunGB. Sequential, thread parallel and distributed computation can be selected by command line parameters. The input is taken from a file. The number of threads respectively the number of distributed clients can be specified. For distributed execution the host and port information is taken from a maschines file.

Usage: RunGB [seq|par|dist|cli] <file> #procs [machinefile]

Added methods putCount() and remCount() in OrderedPairlist to count the number of polynomials put and get from the pair data structure.

pairlist put and remove, trinks6
# Threads 1 seq 1 par 2 par 2 par 3 par 4 par 5 par 1 dist 2 dist 3 dist 4 dist 4 dist 4 dist 5 dist
# put 22 22 43 26 28 28 28 22 25 28 37 40 33 27
# remove 25 25 61 30 32 32 41 26 33 42 47 61 54 69

Timings @ 500 MHz on one CPU and one maschine and log4j level INFO are:
ca. 2.5 - 3.5 seconds for sequential GB,
ca. 2.5 - 6 seconds for parallel GB,
ca. 5.5 - 9 seconds plus 5 seconds sync time for distributed GB.
Network shuffling of polynomials seems to account for 3 seconds in this example.

Problem uncovered: the distributed version of GB needs an avarage of 5 seconds to sync with all clients (on one maschine). This is way to much for execution times in the range of 2 to 8 seconds.

Redesign of DistributedList, now using TreeMap to keep the list entries in proper sequence. As key a natural number is used, which is assigned by the server to successive add() requests. The server now also holds a copy of the list by itself. So the retransmission of list elements to late arriving clients is possible. This doubles the space required to store polynomials, but removes initial delays to sync all clients to receive all list elements.
By retransmission the DistributedList synchronization delay during DistributedGB could be removed. However the problem of about 5 seconds delay in startup of DistributedGB still remains. It is not visible where and why this delay occurs.
Further improvements would be the removal of list elements or the clearing of the list. Next steps could be distributed HashMap or TreeMap.
An important improvement would be to keep serialized copies of the list elements (polynomials) at the server and to avoid many time serialization during broadcast.

2004, 2, 26
Ideas to implement: a distributed task launcher like mpirun, a daemon to run on a distributed system to work with the launcher, solvable polynomials and non-commutative GBs.
2004, 2, 1
Parallel computations with the Rose example are at ?? h with 3 threads on 2 Pentium 4 @ 3.0 GHz hyperthreading CPUs.

With one thread the time is 30.6 h. Besides the better CPU speed, this makes a 5 % improvement on JDK 1.4 compared to the older timings from a JDK 1.3 and the new polynomial implementation.

2004, 1, 25
SPIN model checker: Setup a Promela description of parallel and distributed GB algorithm. Used to verify the safety and liveness properties of the algorithms.
2004, 1, 17
New (minimal) class DistributedList in preparation of a distributed GB algorithm. Made all mutually transported objects Serializable. Fixed ChannelFactory and other classes in edu.unima.ky.parallel to be interuptable. Moved Semaphore back to edu.unima.ky.parallel. First version of a distributed memory GB. One problem was inner class Pair results in serialization of outer class OrderedPairlist, which is not intented. So Pair is now a proper class. Distributed version mainly working. Problem with signaling and termination if 1 in GB.
2004, 1, 10
Refactored Groebner base for new OrderedPolynomials and split sequential and parallel GB implementations. New unit tests for sequential and parallel GBs. GB now works for arbitrary Coefficients.
2004, 1, 5
New coefficient domains BigComplex and BigQuaternion. New test unit for all coefficients. Based on these coefficients are new polynomials, e.g. ComplexOrderedMapPolynomial and QuatOrderedMapPolynomial together with unit tests. Problem: RatPolynomial requires DEFAULT_EVORD be set correctly in ExpVector. This is now solved for the new OrderedMapPolynomials.
2003, 12, 29
New organization of polynomials:
2 interfaces: UnorderedPolynomial and OrderedPolynomial. Ordered polynomials have a term order and are implemented using some SortedMap (e.g. TreeMap). Unodered polynomials are implemented using some HashMap (e.g. LinkedHashMap).
2 abstract classes: UnorderedMapPolynomial and OrderedMapPolynomial. Both implement all algorithms which do not need an explicit coeficient domain, i.e. they are formulated in terms of the Coefficient interface from jas.arith.
2 or more classes which extend the respective abstract classes: RatUnorderedMapPolynomial and RatOrderedMapPolynomial both need explicitly coefficients from BigRational or others.

Multiplication with ordered polynomials is about 8-10 times faster than the multiplication with unordered polynomials. Also the multiplication with semi-ordered polynomials (LinkedHashMap) with orderpreserving addition is about 7-8 times slower than multiplication with ordered polynomials.

All implementations are based on Map interface and classes. The Map maps exponent vectors (from some monoid) to coefficients (from some domain). This is in sync with the mathematical definition of multivariate polynomials as mappings from some monoid to some domain. Term orders are represented by a TermOrder class which provides the desired Comparator classes for the SortedMap implementation.

2003, 12, 28
Things to do: refactor and test HashPolynomial, check performance. Improve the parallel GB algorithm, e.g. parallelize the reduction algorithm. Develop a distributed memory version of the parallel GB algorithm.
2003, 12, 27
Using ArgoUML to produce class diagramms for jas. Refactoring GB from edu.jas.poly to edu.jas.ring.
2003, 12, 21
Setup for JUnit version 3.8.1. Added JUnit testing with Apache Ant version 1.6.0 to build.xml.
2003, September
Experimented with LinkedHashMap instead of TreeMap (SortedMap) for the representation of polynomials. Algorithms which work also with LinkedHashMap have 1 or 2 in their names (now in new class HashPolynomial). LinkedHashMap has the property of using the insertion order for the iterator order. With LinkedHashMap the add() and subtract() can be reformulated to use a merging algorithm as in the original DIP implementation. Assuming the Map insertion order is the the same as the polynomial term order.

However the merging add/subtact implementation is a factor of 2 slower than the TreeMap implementation. Complexity for a+b is
2*(length(a)+length(b)) for access and merging pre sorted polynomials and
2*length(a)+length(b)+length(b)*log2(length(a+b)) for TreeMap clone, access and insertion.

The merging multiplication implementation is by a factor of 10 slower than the TreeMap implementation. Polynomial size was ~100 terms and the product contained ~8000 terms. Complexity for a*b is
lab = length(a)*length(b) coefficient multiplications for both implementations
plus 2*length(a*b)*length(b) for merging summands, respectively
plus length(a)*length(b)*log2(length(a*b)) for TreeMap insertion. Since for sparse polynomials length(a*b) = lab, the TreeMap complexity is asymptotically better in this case:
2*length(a)*length(b)*length(b) =>= length(a)*length(b)*log2(length(a*b))
For dense polynomials with length(a*b) ~ length(a)[+length(b)], then the LinkedHashMap complexity is asymptotically better:
2*length(a)*length(b) =<= length(a)*length(b)*log2(length(a*b))

2003, 3, 15
Some testing with new AMD Athlon XP 2200+ @ 1.8 GHz, 133x2 MHz memory access.
Trinks 6: 1.013 sec with log4j level WARN, parallel 1.058 - 1.740 sec.
Trinks 7: 0.553 sec with log4j level WARN.
2003, 2, 2
Replacing all System.out.println by Log4j logging calls. adding some Junit tests.
2003, 1, 28
Some testing with gcj (Gnu Java Compiler). this compiler gernerates native executable binaries. the timings are not better than with a jit, often worser.

Parallel computations with the Rose example are at 18 h with 4 threads on 2 Pentium 4 @ 2.4 GHz hyperthreading CPUs. With one thread the time is 40 h.

2003, 1, 26
timings with JDK 1.3 (from IBM) are 30% to 40% faster than with JDK 1.4.1 (from Sun). timings on PowerPC 604 @ 200MHz JDK 1.3 (from IBM) JDK 1.2 (from Sun) are a factor 3.5-4.5 slower than on Intel PIII @ 450 MHz. on PowerPC not using jit is faster than using a jit, ca. 20% - 30%.
2003, 1, 12
General differences between sequential and parallel GB algorithms
  • The parallelization is achieved by doing the normal form reductions in parallel.
  • Since the reductions may require different times to complete the normal forms may be entered into the list of polynomials in different (time) order than in the sequential case. So the pairs may be generated in different order. However since the list of pairs is ordered wrt. the lcm of the head terms this seems not to be a big issue.
  • Since several reductions are scheduled in parallel the pairs are taken from the list of pairs in different order than in the sequential case. One should not take more pairs from the list than can be reduced in parallel.

Does this influence the validity of criterion 3? Access to pairlist is synchronized. Pairs are marked as reduced as soon they are taken from the list. But the algorithm terminates only after all reductions of pairs have terminated. So criterion 3 holds.

New implementation of parallel version of GB. Removal of pairs is now also in parallel. But ordering of pair insertion is no more preserved

Timings are more stable and slightly better than that of sequential GB.

Todo: unit tests, comments, ...

2003, 1, 7-11
Renamed jas to mas2jas, new cvs repository for jas, import and checkout.

Improved parallel version of GB.

  • The sequence of polynomials added to the pair list is kept stable. i.e. a pair scheduled for reduction at time t will (if non zero) enter the list before any pair scheduled at time t+x.
  • This limits the parallelism since polynomials which reduce to zero keep a reducer thread occupied until older polynomials are finally reduced. One could eventualy hand over the blocking object to the next thread.
  • The number of pairs scheduled for reduction is now also limited to the number of parallel reduction threads. this avoids that to many pairs with high lcm will be scheduled before eventually new created pairs with lower lcm.
  • The limiting of scheduled pairs could also be implemented using a BoundedBuffer/Queue for the ThreadPool workpile. then addJob() would block until free Threads are avalilable.
  • The sequencing and limiting could eventually also achieved when the reducing threads take the pairs by themselves instead of the master thread. The main thread should then simply wait until all threads are idle.
  • The final reduction of the GB to a minimal GB is now also parallelized.

Todo: CVS, comments, polynomial implementation using LinkedList, parallel GB simplify

With the improved algorithm the running time of the parallel GB becomes more stable and not slower than the sequential GB. However there is still no significant speedup.

parallel GB on one cpu
# Threads 1 2 3 4 5 6 7 8 16
# Reductions 25 25 27 25 25 25 25 25 25

parallel GB on 4 cpus
# Threads 1 2 3 4 5 6 7 8 16
# Reductions 22 24 30, 28, 24, 29 28 29 42 32 32 37

2003, 1, 6
implemented parallel version of GB using ThreadPool from tnj

parallel results:
Trinks 7: mas 0.598 sec, jas 0.918 sec, jas par 0.955 sec
Trinks 6: mas 26.935 sec, jas 3.211 sec, jas par 3.656 sec
mas: including startup and gc time, jas: excluding startup of jvm and including gc time, jas par on single processor timing on P-3@450

this make for a penality of 12 percent, all tests with output to files,
2003, 1, 5
timing benchmarks between BigRational and Coefficient versions of the algorithms, the difference seems to be less than 1 percent with no clear advantage of one side
the sum and product algorithms have not jet optimal complexity, sum has 2 l log(l) instead of 2 l because of TreeMap.remove() and because of TreeMap.put(), prod has l^2 log(l^2/2) instead of l^2 because of TreeMap.put()
TreeMap cannot used for this, some kind of SortedLinkedList or SortedHashMap would be required, the last would in turn require a hashValue() of an ExpVector

implemented edu.jas.arith.BigInteger which implements Coefficient, tested with IntPolynomial which extends Polynomial

todo: alternative Implementations, cleanup RatPolynomial, parallel GB, conversion RatPolynomial <--> IntPolynomial
2003, 1, 4
added reading of PolynomialLists and Variable Lists to PolynomialTokenizer, implemented PolynomialList
refactoring RatPolynomial to extend Polynomial, implementing IntPolynomial extends Polynomial
to make BigInteger implement Coefficient will require a delegation extension of BigInteger
2003, 1, 3
implemented PolynomialTokenizer to read RatPolynomials
2003, 1, 2
file RatPolynomial split into RatGBase, criterion 3 implemented with BitSet

second results (with new criterion 3 in jas):
Trinks 7: mas 0.598 sec, jas 1.159 sec
Trinks 6: mas 26.935 sec, jas 6.468 sec
mas: including startup and gc time, jas: excluding startup of jvm and including gc time

implemented DIGBMI, H-polynomal was not monic in DIRPGB

third results (with new criterion 3 in jas and GBminimal):
Trinks 7: mas 0.598 sec, jas 0.918 sec
Trinks 6: mas 26.935 sec, jas 3.211 sec
mas: including startup and gc time, jas: excluding startup of jvm and including gc time timing on P-3@450

this makes for a factor of 8-9 better, all tests with output to files, startup of JVM is approx. 1.0-1.2 sec, most time is spent in BigInteger:

java -Xrunhprof:cpu=times,format=a

CPU TIME (ms) BEGIN (total = 136) Thu Jan  2 18:33:53 2003
rank   self  accum   count trace method
   1 15,44% 15,44%  596610    21 java.math.MutableBigInteger.rightShift
   2 13,24% 28,68%  582132    15 java.math.MutableBigInteger.difference
   3 12,50% 41,18%  612760    19 java.math.MutableBigInteger.getLowestSetBit
   4  9,56% 50,74%       2     9 java.lang.Object.wait
   5  9,56% 60,29%    5271    22 java.math.MutableBigInteger.binaryGCD
   6  6,62% 66,91%  612760    23 java.math.BigInteger.trailingZeroCnt
   7  5,88% 72,79%  592152    18 java.math.BigInteger.bitLen
   8  5,88% 78,68%    6018    20 java.math.MutableBigInteger.binaryGCD
   9  5,15% 83,82%  578887    25 java.math.MutableBigInteger.normalize
  10  4,41% 88,24%  550992    24 java.math.MutableBigInteger.primitiveRightShift
  11  4,41% 92,65%       1    10 java.lang.Object.wait
  12  3,68% 96,32%  582132    12 java.math.MutableBigInteger.compare
  13  0,74% 97,06%   35965    13 edu.jas.poly.ExpVector.EVILCP
  14  0,74% 97,79%   11612    14 java.math.BigInteger.divide
  15  0,74% 98,53%    5866    11 java.math.MutableBigInteger.divide
  16  0,74% 99,26%    9032    16 java.math.MutableBigInteger.divide
  17  0,74% 100,00%   9032    17 java.math.BigInteger.divide
CPU TIME (ms) END
2003, 1, 1
renaming packages to edu.jas, renaming to arith, poly and ring, new Makefile, project dokumentation in XHTML, using JDK 1.4 with JIT

first results (without criterion 3 in jas):
Trinks 7: mas 0.598 sec, jas 1.373 sec
Trinks 6: mas 26.935 sec, jas 30.935 sec
mas: including startup and gc time, jas: excluding startup of jvm and including gc time. timing on P-3@450

2002, 12, 31
starting with extraction of relevant files in new directory
2000, 7, 21
keySet/get replaced by entrySet/getval.
Implemented S-Polynomial, normal form, irreducible set. Implemented Groebner base with criterion 4. Criterion 3 left to to.
2000, 7, 16
Implemented and tested BigRational based on Javas BigInteger.
With and without I/O BigRational addition, multiplication and comparison is approx. 10 times faster than respective SACRN functions.

Implemented and testet ExpVector based on Javas int arrays.

Implemented and testet RatPolynomial based on Javas TreeMap.
static methods: DIRPDF, DIRPWR via toString, DIRPON, DIRPMC, DIRPPR, DIRPSM, DIRRAS.
Consider replacing keySet/get by entrySet/getval where appropriate. Can there be an generic Polynomial class?

2000, 7, 15
Some testing with Javas builtin BigInteger class.
Without I/O builtin multiplication is approx. 15 times faster than SAC product.
With much I/O builtin multiplication is approx. 3 times faster than SAC product.
Builtin uses also twos-complement representation, which is bad for decimal printing.

This will be the end of list processing for Jas.

DIPRNGB needs DIRPDF, DIRPWR, DIRPON, DIRPMC, DIRPPR, DIRPSM.
These need RNDIF, RNDWR, RNINT, RNSIGN, ISRNONE, RNONE, RNZERO, RNINV (and DIRPRP), RNPROD, RNSUM.

2000, 7, 14
Class BigInteger based on SACI with toString().
Class List based on MASSTOR with toString().
Problem with Modula-2 module initialization with main(args) method: initialization of static variables.
2000, 7, 5
Finished testing most of masarith.
2000, 7, 2
Finished porting masarith. Testing needs still to be done. MASAPF is ok.
2000, 6, 24
Perl script getc.pl to grab comments in Modula-2 source and add to Java source. Comments grabbed on most working files so far. Generated new documentation.
2000, 6, 22
Future directions:
  • Parallel GB.
  • Move to Java without Modula-2.
  • Develop an applet version.
  • Implement more of Mas.
  • Replace SACI by Java BigInteger.
  • Setup for real objects:
    implement constructor,
    implement methods: a.method(b) as STATIC_METHOD(a,b),
    use real objects instead of only Cell objects
    define interfaces e.g. for ring, polynomial ring, module, group, field
  • Small additions:
    toString equivalents of xWRITEs
Problems identified:
  • LISTs over Beta-Integers are diffrent to LISTs over LISTs, when implementing LISTs as Java Types LISTs over other types will require also special handling.
2000, 6, 22
GB running on Trinks (small and big). Jas ist about 5-8 times slower than MAS in GB computation. Using JDK 1.1.7 without JIT on Linux, PII-300. Using JDK 1.2.2-RC3 without JIT on Linux, PII-300 is about 6-9 times slower. Using JDK 1.2.2-RC4 with JIT (sunwjit) on Linux, PII-300 is about 2-4 times slower. Implemented Java input via BufferedReader.
2000, 6, 21
Got GB running. Problem was in EQUAL.
2000, 6, 17
Placed under control of CVS. Begining with a clean version from Uni Passau. Incorporated Java specific changes up to now.
2000, 6, 10
Transformation of DIPRNGB finished. Important parts of maspoly finished.
2000, 6, 4
Transformation of SACPRIM finished. Most of maskern finished. Important parts of masarith finished.
2000, 5, 29
MASSTOR: Mapping MAS list direkt to a Java list class and using of the garbage collector from Java. Data types LIST and GAMMAINT are now distinct. Buying the MHC Compiler (UK Pound 59).
2000, 5, 28
MASSTOR: First attempt to use list class with own garbage collection. Using the constructor to record list pointers.
2000, 5, 27:
Beginning of the first tests. Conversion of .md to .def, .mi to .mod.
2000, 5, 26:
Discovery of the MHC Modula-2 to Java compiler. Mill Hill & Canterbury Corporation, Ltd, URL http://www.mhccorp.com

Done bevore 2003

  • JUnit checker for every class.
  • Switching to Java and abandoning Modula-2.
  • Removal of the mas prefix in directory names.
  • Improved Makefiles.

Heinz Kredel

Last modified: Tue Jul 4 09:58:27 CEST 2023

java-algebra-system-2.7.200/doc/jas.1000066400000000000000000000064421445075545500171500ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2000-2023 Heinz Kredel , .\" $Id$ .\" .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH JAS 1 "January 4, 2018" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME jas \- program to interactively use the Java Algebra System (JAS) from Jython or JRuby. .SH SYNOPSIS .B jas .RI [ -py | -jy | -rb | -jr ] [ -d ] [ -v ] [ -h | --help ] [ -- ] " files" ... .br .SH DESCRIPTION This manual page documents briefly the .B jas command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBjas\fP is a program that runs an interpreter to access the JAS library. The interface to JAS provides Sage like scripting constructions to define polynomial rings, construct polynomials and use various operations from commutative, solvable and non-commutative algebra on these objects. The Java Algebra System (\fBJAS\fP) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through a jython (Java Python) or jruby (Java Ruby) front end, there is also an Android App based on Ruboto (jruby for Android). The focus of JAS is at the moment on commutative, solvable and non-commutative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core CPU ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android to compute clusters (using MPJ a Java Message Passing Interface (MPI) or OpenMPI). This programm \fBjas\fP will determine the JRuby or Jython environment and then call the requested script interpreter with all JAS related environment information (jar files, Java options etc). .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. .TP .B \-rb, \-jr Use Ruby scripting with JRruby (this is the default). .TP .B \-py, \-jy Use Python scripting with Jython. .TP .B \-h, \-\-help Show summary of options. .TP .B \-v Verbose option for scripting language. .TP .B \-d Debug this script. .TP .B \-\- Pass remaining arguments through to Jython or JRuby. .SH SEE ALSO .BR jython (1), .BR jruby (1), .BR Sage (1). The \fBjas\fP program uses the JAS Jython and JRuby interfaces which are fully documented at the .br URL .IR http://krum.rz.uni-mannheim.de/jas java-algebra-system-2.7.200/doc/javancss-summary.txt000066400000000000000000000041541445075545500223530ustar00rootroot00000000000000Nr. Classes Functions NCSS Javadocs Package 1 58 1080 10249 1094 edu.jas.application 2 33 892 5294 914 edu.jas.arith 3 27 271 3918 274 edu.jas.fd 4 112 738 10273 780 edu.jas.gb 5 8 48 253 56 edu.jas.gbmod 6 56 459 8036 476 edu.jas.gbufd 7 9 42 995 51 edu.jas.integrate 8 8 45 222 43 edu.jas.kern 9 179 1707 14936 1644 edu.jas.poly 10 109 401 2829 302 edu.jas.ps 11 32 362 2911 366 edu.jas.root 12 25 86 348 103 edu.jas.structure 13 64 528 10920 556 edu.jas.ufd 14 1 4 50 5 edu.jas.ufdroot 15 49 281 2585 316 edu.jas.util 16 7 162 1648 168 edu.jas.vector --------- --------- --------- --------- 777 7106 75467 7148 Total Packages Classes Functions NCSS Javadocs | per ------------------------------------------------------------- 16.00 777.00 7106.00 75467.00 7148.00 | Project 48.56 444.13 4716.69 446.75 | Package 9.15 97.13 9.20 | Class 10.62 1.01 | Function Nr. NCSS Functions Classes Javadocs Class 1 124 26 0 27 edu.jas.application.SolvableResidueRing ... 777 344 12 0 13 edu.jas.vector.LinAlg Average Object NCSS: 93.09 Average Object Functions: 9.15 Average Object Inner Classes: 0.29 Average Object Javadoc Comments: 9.20 Program NCSS: 75,467.00 Nr. NCSS CCN JVDC Function 1 2 1 1 edu.jas.application.SolvableResidueRing.SolvableResidueRing(C) ... 7106 48 15 1 edu.jas.vector.LinAlg.fractionfreeGaussElimination(C) Average Function NCSS: 9.85 Average Function CCN: 3.95 Average Function JVDC: 0.93 Program NCSS: 75,467.00 java-algebra-system-2.7.200/doc/jdepend-report.txt000066400000000000000000001314751445075545500220010ustar00rootroot00000000000000 -------------------------------------------------- - Package: edu.jas.application -------------------------------------------------- Stats: Total Classes: 103 Concrete Classes: 103 Abstract Classes: 0 Ca: 0 Ce: 12 A: 0 I: 1 D: 0 Abstract Classes: Concrete Classes: edu.jas.application.AlgebraicRootsPrimElem edu.jas.application.CGBSeqTest edu.jas.application.CPair edu.jas.application.CReductionSeq edu.jas.application.CReductionSeq$1 edu.jas.application.CoeffConvertAlg edu.jas.application.CoeffRecConvertAlg edu.jas.application.CoeffToComplexReal edu.jas.application.ColorPolynomial edu.jas.application.ColoredSystem edu.jas.application.ComplexRootTest edu.jas.application.ComprehensiveGroebnerBaseSeq edu.jas.application.Condition edu.jas.application.Condition$1 edu.jas.application.Condition$Color edu.jas.application.Dimension edu.jas.application.EvaluateToComplexReal edu.jas.application.Examples edu.jas.application.ExamplesGeoTheorems edu.jas.application.ExtensionFieldBuilder edu.jas.application.ExtensionFieldBuilderTest edu.jas.application.FactorAlgebraicPrim edu.jas.application.FactorAlgebraicPrimTest edu.jas.application.FactorFactory edu.jas.application.FactorRealReal edu.jas.application.FactorRealRealTest edu.jas.application.FactorTest edu.jas.application.GBAlgorithmBuilder edu.jas.application.GBAlgorithmBuilderTest edu.jas.application.GroebnerSystem edu.jas.application.HenselMultUtilTest edu.jas.application.Ideal edu.jas.application.IdealTest edu.jas.application.IdealWithComplexAlgebraicRoots edu.jas.application.IdealWithComplexRoots edu.jas.application.IdealWithRealAlgebraicRoots edu.jas.application.IdealWithRealRoots edu.jas.application.IdealWithUniv edu.jas.application.IntegerProgram edu.jas.application.IntegerProgramExamples edu.jas.application.IntegerProgramTest edu.jas.application.Local edu.jas.application.LocalResidueSolvablePolynomialQLRTest edu.jas.application.LocalRing edu.jas.application.LocalSolvablePolynomial edu.jas.application.LocalSolvablePolynomialQLRTest edu.jas.application.LocalSolvablePolynomialRing edu.jas.application.LocalSolvablePolynomialRing$1 edu.jas.application.LocalSolvablePolynomialTest edu.jas.application.LocalTest edu.jas.application.OrderedCPairlist edu.jas.application.PolyUtilApp edu.jas.application.PolyUtilAppTest edu.jas.application.PrimaryComponent edu.jas.application.PrimitiveElement edu.jas.application.QuotientSolvablePolynomialQLRTest edu.jas.application.ReAlgFromRealCoeff edu.jas.application.RealAlgebraicNumber edu.jas.application.RealAlgebraicRing edu.jas.application.RealAlgebraicTest edu.jas.application.RealFromReAlgCoeff edu.jas.application.ReductionTest edu.jas.application.Residue edu.jas.application.ResidueRing edu.jas.application.ResidueSolvablePolynomial edu.jas.application.ResidueSolvablePolynomialQLRTest edu.jas.application.ResidueSolvablePolynomialRing edu.jas.application.ResidueSolvablePolynomialRing$1 edu.jas.application.ResidueSolvablePolynomialTest edu.jas.application.ResidueSolvableWordPolynomial edu.jas.application.ResidueSolvableWordPolynomialRing edu.jas.application.ResidueSolvableWordPolynomialRing$1 edu.jas.application.ResidueSolvableWordPolynomialTest edu.jas.application.ResidueTest edu.jas.application.RingFactoryTokenizer edu.jas.application.RingFactoryTokenizer$1 edu.jas.application.RingFactoryTokenizer$coeffType edu.jas.application.RingFactoryTokenizer$polyType edu.jas.application.RingFactoryTokenizerTest edu.jas.application.RootFactoryApp edu.jas.application.RunGB edu.jas.application.RunGBTest edu.jas.application.RunSGB edu.jas.application.RunSGBTest edu.jas.application.SolvableIdeal edu.jas.application.SolvableIdeal$Side edu.jas.application.SolvableIdealTest edu.jas.application.SolvableLocal edu.jas.application.SolvableLocalResidue edu.jas.application.SolvableLocalResidueRing edu.jas.application.SolvableLocalResidueTest edu.jas.application.SolvableLocalRing edu.jas.application.SolvableLocalTest edu.jas.application.SolvableResidue edu.jas.application.SolvableResidueRing edu.jas.application.SolvableResidueTest edu.jas.application.WordIdeal edu.jas.application.WordIdeal$1 edu.jas.application.WordIdeal$2 edu.jas.application.WordIdealTest edu.jas.application.WordResidue edu.jas.application.WordResidueRing edu.jas.application.WordResidueTest Depends Upon: edu.jas.arith edu.jas.fd edu.jas.gb edu.jas.gbufd edu.jas.kern edu.jas.poly edu.jas.root edu.jas.structure edu.jas.ufd edu.jas.ufdroot edu.jas.util edu.jas.vector Used By: Not used by any packages. -------------------------------------------------- - Package: edu.jas.arith -------------------------------------------------- Stats: Total Classes: 52 Concrete Classes: 49 Abstract Classes: 3 Ca: 12 Ce: 2 A: 0,06 I: 0,14 D: 0,8 Abstract Classes: edu.jas.arith.Modular edu.jas.arith.ModularRingFactory edu.jas.arith.Rational Concrete Classes: edu.jas.arith.ArithTest edu.jas.arith.ArithUtil edu.jas.arith.BigComplex edu.jas.arith.BigComplexTest edu.jas.arith.BigDecimal edu.jas.arith.BigDecimalComplex edu.jas.arith.BigDecimalComplexTest edu.jas.arith.BigDecimalTest edu.jas.arith.BigInteger edu.jas.arith.BigIntegerIterator edu.jas.arith.BigIntegerTest edu.jas.arith.BigOctonion edu.jas.arith.BigOctonionTest edu.jas.arith.BigQuaternion edu.jas.arith.BigQuaternionInteger edu.jas.arith.BigQuaternionIntegerTest edu.jas.arith.BigQuaternionRing edu.jas.arith.BigQuaternionRing$1 edu.jas.arith.BigQuaternionTest edu.jas.arith.BigRational edu.jas.arith.BigRational$1 edu.jas.arith.BigRationalIterator edu.jas.arith.BigRationalTest edu.jas.arith.BigRationalUniqueIterator edu.jas.arith.Combinatoric edu.jas.arith.ModInt edu.jas.arith.ModIntIterator edu.jas.arith.ModIntRing edu.jas.arith.ModIntTest edu.jas.arith.ModInteger edu.jas.arith.ModIntegerIterator edu.jas.arith.ModIntegerRing edu.jas.arith.ModIntegerTest edu.jas.arith.ModLong edu.jas.arith.ModLongIterator edu.jas.arith.ModLongRing edu.jas.arith.ModLongTest edu.jas.arith.ModularNotInvertibleException edu.jas.arith.PowerTest edu.jas.arith.PrimeInteger edu.jas.arith.PrimeList edu.jas.arith.PrimeList$1 edu.jas.arith.PrimeList$2 edu.jas.arith.PrimeList$Range edu.jas.arith.PrimeTest edu.jas.arith.Product edu.jas.arith.ProductRing edu.jas.arith.ProductTest edu.jas.arith.Roots Depends Upon: edu.jas.kern edu.jas.structure Used By: edu.jas.application edu.jas.fd edu.jas.gb edu.jas.gbufd edu.jas.integrate edu.jas.poly edu.jas.ps edu.jas.root edu.jas.ufd edu.jas.ufdroot edu.jas.util edu.jas.vector -------------------------------------------------- - Package: edu.jas.fd -------------------------------------------------- Stats: Total Classes: 37 Concrete Classes: 35 Abstract Classes: 2 Ca: 1 Ce: 7 A: 0,05 I: 0,88 D: 0,07 Abstract Classes: edu.jas.fd.GreatestCommonDivisor edu.jas.fd.GreatestCommonDivisorAbstract Concrete Classes: edu.jas.fd.FDUtil edu.jas.fd.FDUtilTest edu.jas.fd.GCDFakeTest edu.jas.fd.GCDLeftRightTest edu.jas.fd.GCDPrimitiveTest edu.jas.fd.GCDSimpleTest edu.jas.fd.GCDSyzygyTest edu.jas.fd.GCDcoFactors edu.jas.fd.GreatestCommonDivisorFake edu.jas.fd.GreatestCommonDivisorLR edu.jas.fd.GreatestCommonDivisorPrimitive edu.jas.fd.GreatestCommonDivisorSimple edu.jas.fd.GreatestCommonDivisorSyzygy edu.jas.fd.QuotSolvablePolynomial edu.jas.fd.QuotSolvablePolynomialRing edu.jas.fd.QuotSolvablePolynomialRing$1 edu.jas.fd.QuotSolvablePolynomialTest edu.jas.fd.SGCDFactory edu.jas.fd.SGCDFactoryTest edu.jas.fd.SGCDParallelProxy edu.jas.fd.SGCDParallelProxy$1 edu.jas.fd.SGCDParallelProxy$10 edu.jas.fd.SGCDParallelProxy$11 edu.jas.fd.SGCDParallelProxy$12 edu.jas.fd.SGCDParallelProxy$2 edu.jas.fd.SGCDParallelProxy$3 edu.jas.fd.SGCDParallelProxy$4 edu.jas.fd.SGCDParallelProxy$5 edu.jas.fd.SGCDParallelProxy$6 edu.jas.fd.SGCDParallelProxy$7 edu.jas.fd.SGCDParallelProxy$8 edu.jas.fd.SGCDParallelProxy$9 edu.jas.fd.SolvableQuotient edu.jas.fd.SolvableQuotientRing edu.jas.fd.SolvableQuotientTest Depends Upon: edu.jas.arith edu.jas.gb edu.jas.gbufd edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.ufd Used By: edu.jas.application -------------------------------------------------- - Package: edu.jas.gb -------------------------------------------------- Stats: Total Classes: 139 Concrete Classes: 121 Abstract Classes: 18 Ca: 6 Ce: 6 A: 0,13 I: 0,5 D: 0,37 Abstract Classes: edu.jas.gb.AbstractPair edu.jas.gb.DReduction edu.jas.gb.EReduction edu.jas.gb.GroebnerBase edu.jas.gb.GroebnerBaseAbstract edu.jas.gb.PairList edu.jas.gb.Reduction edu.jas.gb.ReductionAbstract edu.jas.gb.SigReduction edu.jas.gb.SolvableGroebnerBase edu.jas.gb.SolvableGroebnerBaseAbstract edu.jas.gb.SolvableReduction edu.jas.gb.SolvableReductionAbstract edu.jas.gb.WordGroebnerBase edu.jas.gb.WordGroebnerBaseAbstract edu.jas.gb.WordPairList edu.jas.gb.WordReduction edu.jas.gb.WordReductionAbstract Concrete Classes: edu.jas.gb.CriticalPair edu.jas.gb.CriticalPairComparator edu.jas.gb.CriticalPairList edu.jas.gb.Cyclic edu.jas.gb.DGroebnerBaseSeq edu.jas.gb.DGroebnerBaseSeqTest edu.jas.gb.DReductionSeq edu.jas.gb.EGroebnerBaseSeq edu.jas.gb.EGroebnerBaseSeqTest edu.jas.gb.EReductionSeq edu.jas.gb.ExtendedGB edu.jas.gb.GBClientSP edu.jas.gb.GBDistSP edu.jas.gb.GBExerClient edu.jas.gb.GBHybridExerClient edu.jas.gb.GBOptimized edu.jas.gb.GBProxy edu.jas.gb.GBProxy$1 edu.jas.gb.GBProxy$2 edu.jas.gb.GBProxyTest edu.jas.gb.GBSPTransportMess edu.jas.gb.GBSPTransportMessEnd edu.jas.gb.GBSPTransportMessPair edu.jas.gb.GBSPTransportMessPairIndex edu.jas.gb.GBSPTransportMessPoly edu.jas.gb.GBSPTransportMessReq edu.jas.gb.GBTransportMess edu.jas.gb.GBTransportMessEnd edu.jas.gb.GBTransportMessPair edu.jas.gb.GBTransportMessPairIndex edu.jas.gb.GBTransportMessPoly edu.jas.gb.GBTransportMessReq edu.jas.gb.GroebnerBaseArriSigSeqIter edu.jas.gb.GroebnerBaseDistECTest edu.jas.gb.GroebnerBaseDistHybridECTest edu.jas.gb.GroebnerBaseDistributedEC edu.jas.gb.GroebnerBaseDistributedHybridEC edu.jas.gb.GroebnerBaseF5zSigSeqIter edu.jas.gb.GroebnerBaseGGVSigSeqIter edu.jas.gb.GroebnerBaseParIter edu.jas.gb.GroebnerBaseParIterTest edu.jas.gb.GroebnerBaseParSyzPairTest edu.jas.gb.GroebnerBaseParTest edu.jas.gb.GroebnerBaseParallel edu.jas.gb.GroebnerBaseSeq edu.jas.gb.GroebnerBaseSeqIter edu.jas.gb.GroebnerBaseSeqIterTest edu.jas.gb.GroebnerBaseSeqPairDistTest edu.jas.gb.GroebnerBaseSeqPairDistributed edu.jas.gb.GroebnerBaseSeqPairParTest edu.jas.gb.GroebnerBaseSeqPairParallel edu.jas.gb.GroebnerBaseSeqPairSeq edu.jas.gb.GroebnerBaseSeqPairSeqTest edu.jas.gb.GroebnerBaseSeqTest edu.jas.gb.GroebnerBaseSigSeqIter edu.jas.gb.GroebnerBaseSigSeqIterTest edu.jas.gb.HybridReducerClientEC edu.jas.gb.HybridReducerReceiverEC edu.jas.gb.HybridReducerServerEC edu.jas.gb.JunitSeqPairClient edu.jas.gb.Katsura edu.jas.gb.LeftSolvableReducer edu.jas.gb.LeftSolvableReducerSeqPair edu.jas.gb.MiReducer edu.jas.gb.MiReducerClient edu.jas.gb.MiReducerClientEC edu.jas.gb.MiReducerClientSeqPair edu.jas.gb.MiReducerIter edu.jas.gb.MiReducerSeqPair edu.jas.gb.MiReducerServer edu.jas.gb.MiReducerServerEC edu.jas.gb.MiReducerServerSeqPair edu.jas.gb.ModGroebnerBaseTest edu.jas.gb.ModSolvableGroebnerBaseTest edu.jas.gb.OrderedDPairlist edu.jas.gb.OrderedMinPairlist edu.jas.gb.OrderedPairlist edu.jas.gb.OrderedSyzPairlist edu.jas.gb.OrderedWordPairlist edu.jas.gb.Pair edu.jas.gb.PairListTest edu.jas.gb.Reducer edu.jas.gb.ReducerClientEC edu.jas.gb.ReducerClientSeqPair edu.jas.gb.ReducerIter edu.jas.gb.ReducerSeqPair edu.jas.gb.ReducerServerEC edu.jas.gb.ReducerServerSeqPair edu.jas.gb.ReductionPar edu.jas.gb.ReductionSeq edu.jas.gb.ReductionTest edu.jas.gb.SGBProxy edu.jas.gb.SGBProxy$1 edu.jas.gb.SGBProxy$2 edu.jas.gb.SGBProxy$3 edu.jas.gb.SGBProxy$4 edu.jas.gb.SGBProxy$5 edu.jas.gb.SGBProxy$6 edu.jas.gb.SGBProxyTest edu.jas.gb.SigPair edu.jas.gb.SigPoly edu.jas.gb.SigReductionSeq edu.jas.gb.SolvableExtendedGB edu.jas.gb.SolvableGroebnerBaseParTest edu.jas.gb.SolvableGroebnerBaseParallel edu.jas.gb.SolvableGroebnerBaseSeq edu.jas.gb.SolvableGroebnerBaseSeqPairParTest edu.jas.gb.SolvableGroebnerBaseSeqPairParallel edu.jas.gb.SolvableGroebnerBaseSeqTest edu.jas.gb.SolvableMiReducer edu.jas.gb.SolvableMiReducerSeqPair edu.jas.gb.SolvableReductionPar edu.jas.gb.SolvableReductionSeq edu.jas.gb.SolvableReductionTest edu.jas.gb.TwosidedSolvableReducer edu.jas.gb.TwosidedSolvableReducerSeqPair edu.jas.gb.WordGroebnerBaseSeq edu.jas.gb.WordGroebnerBaseSeqTest edu.jas.gb.WordPair edu.jas.gb.WordReductionSeq edu.jas.gb.WordReductionTest Depends Upon: edu.jas.arith edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.util edu.jas.vector Used By: edu.jas.application edu.jas.fd edu.jas.gbmod edu.jas.gbufd edu.jas.integrate edu.jas.ufd -------------------------------------------------- - Package: edu.jas.gbmod -------------------------------------------------- Stats: Total Classes: 8 Concrete Classes: 4 Abstract Classes: 4 Ca: 0 Ce: 4 A: 0,5 I: 1 D: 0,5 Abstract Classes: edu.jas.gbmod.ModGroebnerBase edu.jas.gbmod.ModGroebnerBaseAbstract edu.jas.gbmod.ModSolvableGroebnerBase edu.jas.gbmod.ModSolvableGroebnerBaseAbstract Concrete Classes: edu.jas.gbmod.ModGroebnerBasePar edu.jas.gbmod.ModGroebnerBaseSeq edu.jas.gbmod.ModSolvableGroebnerBasePar edu.jas.gbmod.ModSolvableGroebnerBaseSeq Depends Upon: edu.jas.gb edu.jas.gbufd edu.jas.poly edu.jas.structure Used By: Not used by any packages. -------------------------------------------------- - Package: edu.jas.gbufd -------------------------------------------------- Stats: Total Classes: 84 Concrete Classes: 74 Abstract Classes: 10 Ca: 4 Ce: 8 A: 0,12 I: 0,67 D: 0,21 Abstract Classes: edu.jas.gbufd.CharacteristicSet edu.jas.gbufd.PseudoReduction edu.jas.gbufd.RPseudoReduction edu.jas.gbufd.RReduction edu.jas.gbufd.SolvablePseudoReduction edu.jas.gbufd.SolvableSyzygy edu.jas.gbufd.SolvableSyzygyAbstract edu.jas.gbufd.Syzygy edu.jas.gbufd.SyzygyAbstract edu.jas.gbufd.WordPseudoReduction Concrete Classes: edu.jas.gbufd.CharSetTest edu.jas.gbufd.CharacteristicSetSimple edu.jas.gbufd.CharacteristicSetWu edu.jas.gbufd.Examples edu.jas.gbufd.GBFactory edu.jas.gbufd.GBFactory$1 edu.jas.gbufd.GBFactory$Algo edu.jas.gbufd.GBFactoryTest edu.jas.gbufd.GroebnerBaseFGLM edu.jas.gbufd.GroebnerBaseFGLMExamples edu.jas.gbufd.GroebnerBaseFGLMTest edu.jas.gbufd.GroebnerBasePartTest edu.jas.gbufd.GroebnerBasePartial edu.jas.gbufd.GroebnerBasePseudoParTest edu.jas.gbufd.GroebnerBasePseudoParallel edu.jas.gbufd.GroebnerBasePseudoRecParTest edu.jas.gbufd.GroebnerBasePseudoRecParallel edu.jas.gbufd.GroebnerBasePseudoRecSeq edu.jas.gbufd.GroebnerBasePseudoRecSeqTest edu.jas.gbufd.GroebnerBasePseudoSeq edu.jas.gbufd.GroebnerBasePseudoSeqTest edu.jas.gbufd.GroebnerBaseQuotient edu.jas.gbufd.GroebnerBaseQuotientTest edu.jas.gbufd.GroebnerBaseRational edu.jas.gbufd.GroebnerBaseRationalTest edu.jas.gbufd.GroebnerBaseWalk edu.jas.gbufd.GroebnerBaseWalkTest edu.jas.gbufd.MultiplicativeSet edu.jas.gbufd.MultiplicativeSetCoPrime edu.jas.gbufd.MultiplicativeSetFactors edu.jas.gbufd.MultiplicativeSetSquarefree edu.jas.gbufd.MultiplicativeSetTest edu.jas.gbufd.OrderedRPairlist edu.jas.gbufd.PolyGBUtil edu.jas.gbufd.PolyGBUtilTest edu.jas.gbufd.PolyModUtil edu.jas.gbufd.PseudoMiReducer edu.jas.gbufd.PseudoMiReducerRec edu.jas.gbufd.PseudoReducer edu.jas.gbufd.PseudoReducerRec edu.jas.gbufd.PseudoReductionEntry edu.jas.gbufd.PseudoReductionPar edu.jas.gbufd.PseudoReductionSeq edu.jas.gbufd.RGroebnerBasePseudoSeq edu.jas.gbufd.RGroebnerBasePseudoSeqTest edu.jas.gbufd.RGroebnerBaseSeq edu.jas.gbufd.RGroebnerBaseSeqTest edu.jas.gbufd.RPseudoReductionSeq edu.jas.gbufd.RReductionSeq edu.jas.gbufd.ReductionTest edu.jas.gbufd.ResPart edu.jas.gbufd.ResPolPart edu.jas.gbufd.SGBFactory edu.jas.gbufd.SGBFactory$1 edu.jas.gbufd.SGBFactoryTest edu.jas.gbufd.SolvResPart edu.jas.gbufd.SolvResPolPart edu.jas.gbufd.SolvableGroebnerBasePseudoRecSeq edu.jas.gbufd.SolvableGroebnerBasePseudoRecSeqTest edu.jas.gbufd.SolvableGroebnerBasePseudoSeq edu.jas.gbufd.SolvableGroebnerBasePseudoSeqTest edu.jas.gbufd.SolvablePseudoReductionSeq edu.jas.gbufd.SolvablePseudoReductionTest edu.jas.gbufd.SolvableSyzygySeq edu.jas.gbufd.SolvableSyzygyTest edu.jas.gbufd.SyzygySeq edu.jas.gbufd.SyzygyTest edu.jas.gbufd.WordGroebnerBasePseudoRecSeq edu.jas.gbufd.WordGroebnerBasePseudoRecSeqTest edu.jas.gbufd.WordGroebnerBasePseudoSeq edu.jas.gbufd.WordGroebnerBasePseudoSeqTest edu.jas.gbufd.WordPseudoReductionEntry edu.jas.gbufd.WordPseudoReductionSeq edu.jas.gbufd.WordPseudoReductionTest Depends Upon: edu.jas.arith edu.jas.gb edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.ufd edu.jas.util edu.jas.vector Used By: edu.jas.application edu.jas.fd edu.jas.gbmod edu.jas.integrate -------------------------------------------------- - Package: edu.jas.integrate -------------------------------------------------- Stats: Total Classes: 13 Concrete Classes: 13 Abstract Classes: 0 Ca: 0 Ce: 7 A: 0 I: 1 D: 0 Abstract Classes: Concrete Classes: edu.jas.integrate.ElementaryIntegration edu.jas.integrate.ElementaryIntegrationAbsoluteTest edu.jas.integrate.ElementaryIntegrationBernoulli edu.jas.integrate.ElementaryIntegrationCzichowski edu.jas.integrate.ElementaryIntegrationCzichowskiTest edu.jas.integrate.ElementaryIntegrationLazard edu.jas.integrate.ElementaryIntegrationLazardTest edu.jas.integrate.ElementaryIntegrationTest edu.jas.integrate.Examples edu.jas.integrate.ExamplesMore edu.jas.integrate.Integral edu.jas.integrate.LogIntegral edu.jas.integrate.QuotIntegral Depends Upon: edu.jas.arith edu.jas.gb edu.jas.gbufd edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.ufd Used By: Not used by any packages. -------------------------------------------------- - Package: edu.jas.kern -------------------------------------------------- Stats: Total Classes: 16 Concrete Classes: 16 Abstract Classes: 0 Ca: 13 Ce: 0 A: 0 I: 0 D: 1 Abstract Classes: Concrete Classes: edu.jas.kern.ComputerThreads edu.jas.kern.KernUtilTest edu.jas.kern.LocalTimeStatus edu.jas.kern.LocalTimeStatus$TSCall edu.jas.kern.PreemptStatus edu.jas.kern.PreemptingException edu.jas.kern.PrettyPrint edu.jas.kern.Scripting edu.jas.kern.Scripting$CAS edu.jas.kern.Scripting$Lang edu.jas.kern.StringUtil edu.jas.kern.TSCallMock edu.jas.kern.TimeExceededException edu.jas.kern.TimeStatus edu.jas.kern.TimeStatus$TSCall edu.jas.kern.TimeStatusTest Depends Upon: Not dependent on any packages. Used By: edu.jas.application edu.jas.arith edu.jas.fd edu.jas.gb edu.jas.gbufd edu.jas.integrate edu.jas.poly edu.jas.ps edu.jas.root edu.jas.ufd edu.jas.ufdroot edu.jas.util edu.jas.vector -------------------------------------------------- - Package: edu.jas.poly -------------------------------------------------- Stats: Total Classes: 234 Concrete Classes: 228 Abstract Classes: 6 Ca: 10 Ce: 5 A: 0,03 I: 0,33 D: 0,64 Abstract Classes: edu.jas.poly.ExpVector edu.jas.poly.Polynomial edu.jas.poly.PolynomialRing edu.jas.poly.RelationGenerator edu.jas.poly.TermOrder$EVComparator edu.jas.poly.WordFactory$WordComparator Concrete Classes: edu.jas.poly.ANumGenPolynomialTest edu.jas.poly.AlgToPoly edu.jas.poly.AlgebToCompl edu.jas.poly.AlgebraicNotInvertibleException edu.jas.poly.AlgebraicNumber edu.jas.poly.AlgebraicNumberIterator edu.jas.poly.AlgebraicNumberModTest edu.jas.poly.AlgebraicNumberRing edu.jas.poly.AlgebraicNumberRing$1 edu.jas.poly.AlgebraicNumberTest edu.jas.poly.AnyToComplex edu.jas.poly.CoeffToAlg edu.jas.poly.CoeffToRecAlg edu.jas.poly.CompRatToDec edu.jas.poly.ComplToAlgeb edu.jas.poly.Complex edu.jas.poly.ComplexGenPolynomialTest edu.jas.poly.ComplexRing edu.jas.poly.ComplexTest edu.jas.poly.DecGenPolynomialTest edu.jas.poly.DistToRec edu.jas.poly.EvalAllPol edu.jas.poly.EvalMain edu.jas.poly.EvalMainPol edu.jas.poly.Examples edu.jas.poly.ExpVector$1 edu.jas.poly.ExpVector$StorUnit edu.jas.poly.ExpVectorByte edu.jas.poly.ExpVectorInteger edu.jas.poly.ExpVectorLong edu.jas.poly.ExpVectorPair edu.jas.poly.ExpVectorShort edu.jas.poly.ExpVectorTest edu.jas.poly.FromInteger edu.jas.poly.FromIntegerPoly edu.jas.poly.GFGenPolynomialTest edu.jas.poly.GaloisFieldTest edu.jas.poly.GenMatrixTest edu.jas.poly.GenPolynomial edu.jas.poly.GenPolynomialIterator edu.jas.poly.GenPolynomialMonomialIterator edu.jas.poly.GenPolynomialRing edu.jas.poly.GenPolynomialRing$1 edu.jas.poly.GenPolynomialTest edu.jas.poly.GenPolynomialTokenizer edu.jas.poly.GenPolynomialTokenizer$1 edu.jas.poly.GenPolynomialTokenizer$coeffType edu.jas.poly.GenPolynomialTokenizer$polyType edu.jas.poly.GenPolynomialTokenizerTest edu.jas.poly.GenSolvablePolynomial edu.jas.poly.GenSolvablePolynomialRing edu.jas.poly.GenSolvablePolynomialRing$1 edu.jas.poly.GenSolvablePolynomialTest edu.jas.poly.GenVectorTest edu.jas.poly.GenWordPolynomial edu.jas.poly.GenWordPolynomialRing edu.jas.poly.GenWordPolynomialRing$1 edu.jas.poly.GenWordPolynomialTest edu.jas.poly.ImagPart edu.jas.poly.ImagPartComplex edu.jas.poly.IntGenPolynomialTest edu.jas.poly.InvalidExpressionException edu.jas.poly.Local edu.jas.poly.LocalRing edu.jas.poly.LocalTest edu.jas.poly.ModGenPolynomialTest edu.jas.poly.ModGenSolvablePolynomialTest edu.jas.poly.ModSymToInt edu.jas.poly.ModToInt edu.jas.poly.ModuleList edu.jas.poly.ModuleList$1 edu.jas.poly.ModuleListTest edu.jas.poly.Monomial edu.jas.poly.Multiply edu.jas.poly.OptimizedModuleList edu.jas.poly.OptimizedPolynomialList edu.jas.poly.OrderedModuleList edu.jas.poly.OrderedModuleList$1 edu.jas.poly.OrderedPolynomialList edu.jas.poly.OrderedPolynomialList$1 edu.jas.poly.OrderedPolynomialList$2 edu.jas.poly.Overlap edu.jas.poly.OverlapList edu.jas.poly.PolyIterator edu.jas.poly.PolySpliterator edu.jas.poly.PolySpliterator$1 edu.jas.poly.PolySpliterator$2 edu.jas.poly.PolyToAlg edu.jas.poly.PolyUtil edu.jas.poly.PolyUtil$1 edu.jas.poly.PolyUtil$2 edu.jas.poly.PolyUtil$3 edu.jas.poly.PolyUtil$4 edu.jas.poly.PolyUtil$5 edu.jas.poly.PolyUtilTest edu.jas.poly.PolynomialComparator edu.jas.poly.PolynomialList edu.jas.poly.PolynomialList$1 edu.jas.poly.PolynomialListTest edu.jas.poly.QLRSolvablePolynomial edu.jas.poly.QLRSolvablePolynomialRing edu.jas.poly.QLRSolvablePolynomialRing$1 edu.jas.poly.QuatGenPolynomialTest edu.jas.poly.QuatGenSolvablePolynomialTest edu.jas.poly.Quotient edu.jas.poly.QuotientRing edu.jas.poly.QuotientTest edu.jas.poly.RatGenPolynomialTest edu.jas.poly.RatGenSolvablePolynomialTest edu.jas.poly.RatNumer edu.jas.poly.RatPolyGenPolynomialTest edu.jas.poly.RatToCompl edu.jas.poly.RatToDec edu.jas.poly.RatToInt edu.jas.poly.RatToIntFactor edu.jas.poly.RatToIntPoly edu.jas.poly.RealPart edu.jas.poly.RealPartComplex edu.jas.poly.RecSolvablePolynomial edu.jas.poly.RecSolvablePolynomialRing edu.jas.poly.RecSolvablePolynomialRing$1 edu.jas.poly.RecSolvablePolynomialTest edu.jas.poly.RecSolvableWordPolynomial edu.jas.poly.RecSolvableWordPolynomialRing edu.jas.poly.RecSolvableWordPolynomialRing$1 edu.jas.poly.RecSolvableWordPolynomialTest edu.jas.poly.RecToDist edu.jas.poly.RelationTable edu.jas.poly.RelationTableTest edu.jas.poly.Residue edu.jas.poly.ResidueRing edu.jas.poly.ResidueTest edu.jas.poly.SolvableModuleListTest edu.jas.poly.TableRelation edu.jas.poly.TermOrder edu.jas.poly.TermOrder$1 edu.jas.poly.TermOrder$10 edu.jas.poly.TermOrder$11 edu.jas.poly.TermOrder$12 edu.jas.poly.TermOrder$13 edu.jas.poly.TermOrder$14 edu.jas.poly.TermOrder$15 edu.jas.poly.TermOrder$16 edu.jas.poly.TermOrder$17 edu.jas.poly.TermOrder$18 edu.jas.poly.TermOrder$19 edu.jas.poly.TermOrder$2 edu.jas.poly.TermOrder$20 edu.jas.poly.TermOrder$21 edu.jas.poly.TermOrder$22 edu.jas.poly.TermOrder$23 edu.jas.poly.TermOrder$24 edu.jas.poly.TermOrder$25 edu.jas.poly.TermOrder$26 edu.jas.poly.TermOrder$27 edu.jas.poly.TermOrder$28 edu.jas.poly.TermOrder$29 edu.jas.poly.TermOrder$3 edu.jas.poly.TermOrder$30 edu.jas.poly.TermOrder$31 edu.jas.poly.TermOrder$32 edu.jas.poly.TermOrder$33 edu.jas.poly.TermOrder$34 edu.jas.poly.TermOrder$35 edu.jas.poly.TermOrder$36 edu.jas.poly.TermOrder$37 edu.jas.poly.TermOrder$38 edu.jas.poly.TermOrder$39 edu.jas.poly.TermOrder$4 edu.jas.poly.TermOrder$40 edu.jas.poly.TermOrder$41 edu.jas.poly.TermOrder$42 edu.jas.poly.TermOrder$43 edu.jas.poly.TermOrder$44 edu.jas.poly.TermOrder$45 edu.jas.poly.TermOrder$46 edu.jas.poly.TermOrder$47 edu.jas.poly.TermOrder$48 edu.jas.poly.TermOrder$49 edu.jas.poly.TermOrder$5 edu.jas.poly.TermOrder$50 edu.jas.poly.TermOrder$51 edu.jas.poly.TermOrder$52 edu.jas.poly.TermOrder$53 edu.jas.poly.TermOrder$54 edu.jas.poly.TermOrder$55 edu.jas.poly.TermOrder$56 edu.jas.poly.TermOrder$57 edu.jas.poly.TermOrder$58 edu.jas.poly.TermOrder$59 edu.jas.poly.TermOrder$6 edu.jas.poly.TermOrder$60 edu.jas.poly.TermOrder$61 edu.jas.poly.TermOrder$62 edu.jas.poly.TermOrder$63 edu.jas.poly.TermOrder$64 edu.jas.poly.TermOrder$65 edu.jas.poly.TermOrder$66 edu.jas.poly.TermOrder$67 edu.jas.poly.TermOrder$68 edu.jas.poly.TermOrder$69 edu.jas.poly.TermOrder$7 edu.jas.poly.TermOrder$70 edu.jas.poly.TermOrder$71 edu.jas.poly.TermOrder$72 edu.jas.poly.TermOrder$73 edu.jas.poly.TermOrder$74 edu.jas.poly.TermOrder$75 edu.jas.poly.TermOrder$76 edu.jas.poly.TermOrder$77 edu.jas.poly.TermOrder$8 edu.jas.poly.TermOrder$9 edu.jas.poly.TermOrderByName edu.jas.poly.TermOrderByNameCompatTest edu.jas.poly.TermOrderByNameTest edu.jas.poly.TermOrderOptimization edu.jas.poly.TermOrderOptimizationTest edu.jas.poly.TermOrderTest edu.jas.poly.ToComplex edu.jas.poly.WeylRelations edu.jas.poly.WeylRelationsIterated edu.jas.poly.Word edu.jas.poly.WordFactory edu.jas.poly.WordFactory$1 edu.jas.poly.WordFactory$2 edu.jas.poly.WordMonomial edu.jas.poly.WordPolyIterator edu.jas.poly.WordTest Depends Upon: edu.jas.arith edu.jas.kern edu.jas.structure edu.jas.util edu.jas.vector Used By: edu.jas.application edu.jas.fd edu.jas.gb edu.jas.gbmod edu.jas.gbufd edu.jas.integrate edu.jas.ps edu.jas.root edu.jas.ufd edu.jas.ufdroot -------------------------------------------------- - Package: edu.jas.ps -------------------------------------------------- Stats: Total Classes: 116 Concrete Classes: 110 Abstract Classes: 6 Ca: 1 Ce: 6 A: 0,05 I: 0,86 D: 0,09 Abstract Classes: edu.jas.ps.Coefficients edu.jas.ps.MultiVarCoefficients edu.jas.ps.MultiVarPowerSeriesMap edu.jas.ps.TaylorFunction edu.jas.ps.TaylorFunctionAdapter edu.jas.ps.UnivPowerSeriesMap Concrete Classes: edu.jas.ps.Examples edu.jas.ps.Examples$1 edu.jas.ps.Examples$10 edu.jas.ps.Examples$11 edu.jas.ps.Examples$12 edu.jas.ps.Examples$13 edu.jas.ps.Examples$14 edu.jas.ps.Examples$15 edu.jas.ps.Examples$16 edu.jas.ps.Examples$2 edu.jas.ps.Examples$2$1 edu.jas.ps.Examples$3 edu.jas.ps.Examples$4 edu.jas.ps.Examples$5 edu.jas.ps.Examples$6 edu.jas.ps.Examples$7 edu.jas.ps.Examples$8 edu.jas.ps.Examples$9 edu.jas.ps.Examples$Odds edu.jas.ps.Examples$Sum edu.jas.ps.ExamplesMulti edu.jas.ps.ExpVectorIterable edu.jas.ps.ExpVectorIterator edu.jas.ps.IteratorsTest edu.jas.ps.MultiVarPowerSeries edu.jas.ps.MultiVarPowerSeries$1 edu.jas.ps.MultiVarPowerSeries$10 edu.jas.ps.MultiVarPowerSeries$11 edu.jas.ps.MultiVarPowerSeries$12 edu.jas.ps.MultiVarPowerSeries$13 edu.jas.ps.MultiVarPowerSeries$14 edu.jas.ps.MultiVarPowerSeries$15 edu.jas.ps.MultiVarPowerSeries$16 edu.jas.ps.MultiVarPowerSeries$17 edu.jas.ps.MultiVarPowerSeries$18 edu.jas.ps.MultiVarPowerSeries$19 edu.jas.ps.MultiVarPowerSeries$2 edu.jas.ps.MultiVarPowerSeries$20 edu.jas.ps.MultiVarPowerSeries$21 edu.jas.ps.MultiVarPowerSeries$22 edu.jas.ps.MultiVarPowerSeries$23 edu.jas.ps.MultiVarPowerSeries$24 edu.jas.ps.MultiVarPowerSeries$3 edu.jas.ps.MultiVarPowerSeries$4 edu.jas.ps.MultiVarPowerSeries$5 edu.jas.ps.MultiVarPowerSeries$6 edu.jas.ps.MultiVarPowerSeries$7 edu.jas.ps.MultiVarPowerSeries$8 edu.jas.ps.MultiVarPowerSeries$9 edu.jas.ps.MultiVarPowerSeriesRing edu.jas.ps.MultiVarPowerSeriesRing$1 edu.jas.ps.MultiVarPowerSeriesRing$10 edu.jas.ps.MultiVarPowerSeriesRing$11 edu.jas.ps.MultiVarPowerSeriesRing$12 edu.jas.ps.MultiVarPowerSeriesRing$13 edu.jas.ps.MultiVarPowerSeriesRing$14 edu.jas.ps.MultiVarPowerSeriesRing$15 edu.jas.ps.MultiVarPowerSeriesRing$2 edu.jas.ps.MultiVarPowerSeriesRing$3 edu.jas.ps.MultiVarPowerSeriesRing$4 edu.jas.ps.MultiVarPowerSeriesRing$5 edu.jas.ps.MultiVarPowerSeriesRing$6 edu.jas.ps.MultiVarPowerSeriesRing$7 edu.jas.ps.MultiVarPowerSeriesRing$8 edu.jas.ps.MultiVarPowerSeriesRing$9 edu.jas.ps.MultiVarPowerSeriesTest edu.jas.ps.Multiply edu.jas.ps.Negate edu.jas.ps.Ones edu.jas.ps.OrderedPairlist edu.jas.ps.PSUtil edu.jas.ps.PSUtil$1 edu.jas.ps.PSUtil$2 edu.jas.ps.Pair edu.jas.ps.PolynomialTaylorFunction edu.jas.ps.ReductionSeq edu.jas.ps.ReductionSeq$1 edu.jas.ps.STDMultiPSTest edu.jas.ps.StandardBaseSeq edu.jas.ps.Subtract edu.jas.ps.Sum edu.jas.ps.UnivPowerSeries edu.jas.ps.UnivPowerSeries$1 edu.jas.ps.UnivPowerSeries$10 edu.jas.ps.UnivPowerSeries$11 edu.jas.ps.UnivPowerSeries$12 edu.jas.ps.UnivPowerSeries$2 edu.jas.ps.UnivPowerSeries$3 edu.jas.ps.UnivPowerSeries$4 edu.jas.ps.UnivPowerSeries$5 edu.jas.ps.UnivPowerSeries$6 edu.jas.ps.UnivPowerSeries$7 edu.jas.ps.UnivPowerSeries$8 edu.jas.ps.UnivPowerSeries$9 edu.jas.ps.UnivPowerSeriesRing edu.jas.ps.UnivPowerSeriesRing$1 edu.jas.ps.UnivPowerSeriesRing$10 edu.jas.ps.UnivPowerSeriesRing$11 edu.jas.ps.UnivPowerSeriesRing$12 edu.jas.ps.UnivPowerSeriesRing$2 edu.jas.ps.UnivPowerSeriesRing$3 edu.jas.ps.UnivPowerSeriesRing$4 edu.jas.ps.UnivPowerSeriesRing$5 edu.jas.ps.UnivPowerSeriesRing$6 edu.jas.ps.UnivPowerSeriesRing$7 edu.jas.ps.UnivPowerSeriesRing$8 edu.jas.ps.UnivPowerSeriesRing$9 edu.jas.ps.UnivPowerSeriesTest edu.jas.ps.Vars edu.jas.ps.Zeros Depends Upon: edu.jas.arith edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.util edu.jas.vector Used By: edu.jas.ufd -------------------------------------------------- - Package: edu.jas.root -------------------------------------------------- Stats: Total Classes: 37 Concrete Classes: 33 Abstract Classes: 4 Ca: 2 Ce: 5 A: 0,11 I: 0,71 D: 0,18 Abstract Classes: edu.jas.root.ComplexRoots edu.jas.root.ComplexRootsAbstract edu.jas.root.RealRoots edu.jas.root.RealRootsAbstract Concrete Classes: edu.jas.root.AlgFromRealCoeff edu.jas.root.AlgebraicRoots edu.jas.root.Boundary edu.jas.root.CoeffToComplex edu.jas.root.CoeffToComplexFromComplex edu.jas.root.CoeffToReAlg edu.jas.root.CoeffToReal edu.jas.root.CoeffToRecReAlg edu.jas.root.ComplexAlgebraicNumber edu.jas.root.ComplexAlgebraicRing edu.jas.root.ComplexAlgebraicTest edu.jas.root.ComplexRootTest edu.jas.root.ComplexRootsAbstract$1 edu.jas.root.ComplexRootsSturm edu.jas.root.DecimalRoots edu.jas.root.Interval edu.jas.root.InvalidBoundaryException edu.jas.root.NoConvergenceException edu.jas.root.PolyToReAlg edu.jas.root.PolyUtilRoot edu.jas.root.RealAlgebraicNumber edu.jas.root.RealAlgebraicRing edu.jas.root.RealAlgebraicTest edu.jas.root.RealArithUtil edu.jas.root.RealFromAlgCoeff edu.jas.root.RealRootTest edu.jas.root.RealRootTuple edu.jas.root.RealRootsAbstract$1 edu.jas.root.RealRootsSturm edu.jas.root.Rectangle edu.jas.root.RootFactory edu.jas.root.RootUtil edu.jas.root.RootUtilTest Depends Upon: edu.jas.arith edu.jas.kern edu.jas.poly edu.jas.structure edu.jas.ufd Used By: edu.jas.application edu.jas.ufdroot -------------------------------------------------- - Package: edu.jas.structure -------------------------------------------------- Stats: Total Classes: 28 Concrete Classes: 3 Abstract Classes: 25 Ca: 13 Ce: 0 A: 0,89 I: 0 D: 0,11 Abstract Classes: edu.jas.structure.AbelianGroupElem edu.jas.structure.AbelianGroupFactory edu.jas.structure.AlgebraElem edu.jas.structure.AlgebraFactory edu.jas.structure.BinaryFunctor edu.jas.structure.ElemFactory edu.jas.structure.Element edu.jas.structure.FieldElem edu.jas.structure.FieldFactory edu.jas.structure.GcdRingElem edu.jas.structure.ModulElem edu.jas.structure.ModulFactory edu.jas.structure.MonoidElem edu.jas.structure.MonoidFactory edu.jas.structure.NoncomRingElem edu.jas.structure.QuotPair edu.jas.structure.QuotPairFactory edu.jas.structure.RegularRingElem edu.jas.structure.RingElem edu.jas.structure.RingFactory edu.jas.structure.Selector edu.jas.structure.StarRingElem edu.jas.structure.UnaryFunctor edu.jas.structure.Value edu.jas.structure.ValueFactory Concrete Classes: edu.jas.structure.NotDivisibleException edu.jas.structure.NotInvertibleException edu.jas.structure.Power Depends Upon: Not dependent on any packages. Used By: edu.jas.application edu.jas.arith edu.jas.fd edu.jas.gb edu.jas.gbmod edu.jas.gbufd edu.jas.integrate edu.jas.poly edu.jas.ps edu.jas.root edu.jas.ufd edu.jas.util edu.jas.vector -------------------------------------------------- - Package: edu.jas.ufd -------------------------------------------------- Stats: Total Classes: 106 Concrete Classes: 98 Abstract Classes: 8 Ca: 6 Ce: 8 A: 0,08 I: 0,57 D: 0,35 Abstract Classes: edu.jas.ufd.FactorAbsolute edu.jas.ufd.FactorAbstract edu.jas.ufd.Factorization edu.jas.ufd.GreatestCommonDivisor edu.jas.ufd.GreatestCommonDivisorAbstract edu.jas.ufd.Squarefree edu.jas.ufd.SquarefreeAbstract edu.jas.ufd.SquarefreeFieldCharP Concrete Classes: edu.jas.ufd.BackSubstKronecker edu.jas.ufd.CycloUtil edu.jas.ufd.EvalPoints edu.jas.ufd.EvalPoints$1 edu.jas.ufd.Examples edu.jas.ufd.ExamplesPartialFraction edu.jas.ufd.FactorAlgebraic edu.jas.ufd.FactorAlgebraicTest edu.jas.ufd.FactorComplex edu.jas.ufd.FactorComplexTest edu.jas.ufd.FactorFactory edu.jas.ufd.FactorFraction edu.jas.ufd.FactorFractionTest edu.jas.ufd.FactorGenericTest edu.jas.ufd.FactorInteger edu.jas.ufd.FactorIntegerTest edu.jas.ufd.FactorModular edu.jas.ufd.FactorModularBerlekamp edu.jas.ufd.FactorModularTest edu.jas.ufd.FactorMoreTest edu.jas.ufd.FactorQuotient edu.jas.ufd.FactorQuotientTest edu.jas.ufd.FactorRational edu.jas.ufd.FactorRationalTest edu.jas.ufd.FactorTest edu.jas.ufd.Factors edu.jas.ufd.FactorsList edu.jas.ufd.FactorsMap edu.jas.ufd.GCDFactory edu.jas.ufd.GCDFactoryTest edu.jas.ufd.GCDHenselTest edu.jas.ufd.GCDModEvalTest edu.jas.ufd.GCDModLongEvalTest edu.jas.ufd.GCDModLongTest edu.jas.ufd.GCDModularTest edu.jas.ufd.GCDPartFracRatTest edu.jas.ufd.GCDPrimitiveTest edu.jas.ufd.GCDProxy edu.jas.ufd.GCDProxy$1 edu.jas.ufd.GCDProxy$10 edu.jas.ufd.GCDProxy$11 edu.jas.ufd.GCDProxy$12 edu.jas.ufd.GCDProxy$2 edu.jas.ufd.GCDProxy$3 edu.jas.ufd.GCDProxy$4 edu.jas.ufd.GCDProxy$5 edu.jas.ufd.GCDProxy$6 edu.jas.ufd.GCDProxy$7 edu.jas.ufd.GCDProxy$8 edu.jas.ufd.GCDProxy$9 edu.jas.ufd.GCDProxyTest edu.jas.ufd.GCDSimpleTest edu.jas.ufd.GCDSubresRatTest edu.jas.ufd.GCDSubresTest edu.jas.ufd.GCDTimingTest edu.jas.ufd.GenMatrixFFTest edu.jas.ufd.GreatestCommonDivisorFake edu.jas.ufd.GreatestCommonDivisorHensel edu.jas.ufd.GreatestCommonDivisorModEval edu.jas.ufd.GreatestCommonDivisorModular edu.jas.ufd.GreatestCommonDivisorPrimitive edu.jas.ufd.GreatestCommonDivisorSimple edu.jas.ufd.GreatestCommonDivisorSubres edu.jas.ufd.HenselApprox edu.jas.ufd.HenselMultUtil edu.jas.ufd.HenselMultUtilTest edu.jas.ufd.HenselUtil edu.jas.ufd.HenselUtilTest edu.jas.ufd.NoLiftingException edu.jas.ufd.PartialFraction edu.jas.ufd.PolyUfdUtil edu.jas.ufd.PolyUfdUtilTest edu.jas.ufd.QuotIntPolynomialTest edu.jas.ufd.Quotient edu.jas.ufd.Quotient$1 edu.jas.ufd.QuotientIntTest edu.jas.ufd.QuotientRatTest edu.jas.ufd.QuotientRing edu.jas.ufd.QuotientRing$QuoNorm edu.jas.ufd.QuotientTaylorFunction edu.jas.ufd.SquarefreeAlgModTest edu.jas.ufd.SquarefreeAlgQuotModTest edu.jas.ufd.SquarefreeFactory edu.jas.ufd.SquarefreeFieldChar0 edu.jas.ufd.SquarefreeFieldChar0Yun edu.jas.ufd.SquarefreeFiniteFieldCharP edu.jas.ufd.SquarefreeInfiniteAlgebraicFieldCharP edu.jas.ufd.SquarefreeInfiniteFieldCharP edu.jas.ufd.SquarefreeIntTest edu.jas.ufd.SquarefreeModLongTest edu.jas.ufd.SquarefreeModTest edu.jas.ufd.SquarefreeQuotModTest edu.jas.ufd.SquarefreeRatTest edu.jas.ufd.SquarefreeRingChar0 edu.jas.ufd.SquarefreeTest edu.jas.ufd.SubstKronecker edu.jas.ufd.TrialParts edu.jas.ufd.UnivPowerSeriesTaylorTest Depends Upon: edu.jas.arith edu.jas.gb edu.jas.kern edu.jas.poly edu.jas.ps edu.jas.structure edu.jas.util edu.jas.vector Used By: edu.jas.application edu.jas.fd edu.jas.gbufd edu.jas.integrate edu.jas.root edu.jas.ufdroot -------------------------------------------------- - Package: edu.jas.ufdroot -------------------------------------------------- Stats: Total Classes: 2 Concrete Classes: 2 Abstract Classes: 0 Ca: 1 Ce: 5 A: 0 I: 0,83 D: 0,17 Abstract Classes: Concrete Classes: edu.jas.ufdroot.FactorRealAlgebraic edu.jas.ufdroot.FactorRealAlgebraicTest Depends Upon: edu.jas.arith edu.jas.kern edu.jas.poly edu.jas.root edu.jas.ufd Used By: edu.jas.application -------------------------------------------------- - Package: edu.jas.util -------------------------------------------------- Stats: Total Classes: 69 Concrete Classes: 67 Abstract Classes: 2 Ca: 6 Ce: 3 A: 0,03 I: 0,33 D: 0,64 Abstract Classes: edu.jas.util.DHTTransport edu.jas.util.RemoteExecutable Concrete Classes: edu.jas.util.ArrayUtil edu.jas.util.Broadcaster edu.jas.util.CartesianOneProductInfiniteIterator edu.jas.util.CartesianProduct edu.jas.util.CartesianProductInfinite edu.jas.util.CartesianProductIterator edu.jas.util.CartesianProductLong edu.jas.util.CartesianProductLongIterator edu.jas.util.CartesianTwoProductInfiniteIterator edu.jas.util.CartesianTwoProductInfiniteIteratorList edu.jas.util.CatReader edu.jas.util.ChannelFactory edu.jas.util.Counter edu.jas.util.DHTBroadcaster edu.jas.util.DHTListener edu.jas.util.DHTTransport$1 edu.jas.util.DHTTransport$Stor edu.jas.util.DHTTransportClear edu.jas.util.DHTTransportMarshal edu.jas.util.DHTTransportPlain edu.jas.util.DHTTransportTerminate edu.jas.util.DistFastWorker edu.jas.util.DistHashTable edu.jas.util.DistHashTableServer edu.jas.util.DistHashTableTest edu.jas.util.DistPoolThread edu.jas.util.DistSlowWorker edu.jas.util.DistThreadPool edu.jas.util.DistThreadPoolTest edu.jas.util.DistributedList edu.jas.util.DistributedListServer edu.jas.util.DistributedListTest edu.jas.util.Executable edu.jas.util.ExecutableChannels edu.jas.util.ExecutableChannelsTest edu.jas.util.ExecutableServer edu.jas.util.ExecutableServerTest edu.jas.util.Executor edu.jas.util.FastWorker edu.jas.util.IteratorsTest edu.jas.util.KsubSet edu.jas.util.KsubSetIterator edu.jas.util.ListUtil edu.jas.util.ListUtilTest edu.jas.util.Listener edu.jas.util.LongIterable edu.jas.util.LongIterator edu.jas.util.MapEntry edu.jas.util.Multiply edu.jas.util.OneSubSetIterator edu.jas.util.PoolThread edu.jas.util.PowerSet edu.jas.util.PowerSetIterator edu.jas.util.PowerSetIterator$Mode edu.jas.util.PowerSetTest edu.jas.util.ShutdownRequest edu.jas.util.SlowWorker edu.jas.util.SocketChannel edu.jas.util.SocketChannelTest edu.jas.util.StrategyEnumeration edu.jas.util.TaggedMessage edu.jas.util.TaggedSocketChannel edu.jas.util.TaggedSocketChannelTest edu.jas.util.Terminator edu.jas.util.ThreadPool edu.jas.util.ThreadPoolTest edu.jas.util.ZeroSubSetIterator Depends Upon: edu.jas.arith edu.jas.kern edu.jas.structure Used By: edu.jas.application edu.jas.gb edu.jas.gbufd edu.jas.poly edu.jas.ps edu.jas.ufd -------------------------------------------------- - Package: edu.jas.vector -------------------------------------------------- Stats: Total Classes: 9 Concrete Classes: 9 Abstract Classes: 0 Ca: 6 Ce: 3 A: 0 I: 0,33 D: 0,67 Abstract Classes: Concrete Classes: edu.jas.vector.BasicLinAlg edu.jas.vector.Examples edu.jas.vector.GenMatrix edu.jas.vector.GenMatrixRing edu.jas.vector.GenMatrixTest edu.jas.vector.GenVector edu.jas.vector.GenVectorModul edu.jas.vector.GenVectorTest edu.jas.vector.LinAlg Depends Upon: edu.jas.arith edu.jas.kern edu.jas.structure Used By: edu.jas.application edu.jas.gb edu.jas.gbufd edu.jas.poly edu.jas.ps edu.jas.ufd -------------------------------------------------- - Package Dependency Cycles: -------------------------------------------------- -------------------------------------------------- - Summary: -------------------------------------------------- Name, Class Count, Abstract Class Count, Ca, Ce, A, I, D, V: edu.jas.application,103,0,0,12,0,1,0,1 edu.jas.arith,52,3,12,2,0,06,0,14,0,8,1 edu.jas.fd,37,2,1,7,0,05,0,88,0,07,1 edu.jas.gb,139,18,6,6,0,13,0,5,0,37,1 edu.jas.gbmod,8,4,0,4,0,5,1,0,5,1 edu.jas.gbufd,84,10,4,8,0,12,0,67,0,21,1 edu.jas.integrate,13,0,0,7,0,1,0,1 edu.jas.kern,16,0,13,0,0,0,1,1 edu.jas.poly,234,6,10,5,0,03,0,33,0,64,1 edu.jas.ps,116,6,1,6,0,05,0,86,0,09,1 edu.jas.root,37,4,2,5,0,11,0,71,0,18,1 edu.jas.structure,28,25,13,0,0,89,0,0,11,1 edu.jas.ufd,106,8,6,8,0,08,0,57,0,35,1 edu.jas.ufdroot,2,0,1,5,0,0,83,0,17,1 edu.jas.util,69,2,6,3,0,03,0,33,0,64,1 edu.jas.vector,9,0,6,3,0,0,33,0,67,1 java-algebra-system-2.7.200/doc/overview.html000066400000000000000000000045521445075545500210450ustar00rootroot00000000000000 Java Algebra System

Java algebra system.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

Static package and component structure overview
Package and component structure overview

See design for an overview on the design of the package and class structure.

See introduction as starting point for further information.

See weblog for the latest changes.

See Package Dependencies for a list of package dependencies with classes.

See more API documents: MPJ, JSR223, Findbugs, Jdepend, Licence etc.


Heinz Kredel

Last modified: Tue Jul 19 14:26:32 CEST 2022

$Id$

java-algebra-system-2.7.200/doc/packages.html000066400000000000000000000167621445075545500207630ustar00rootroot00000000000000 JAS Packages

Java Algebra System (JAS) Packages

The JAS software library contains at the moment of the following packages. The relations and dependencies between the packages are shown in figure 1.

edu.jas.structure:
contains interfaces for the most general algebraic structures like RingElem and RingFactory.
edu.jas.arith:
contains classes for arithmetic in the basic coefficient rings like BigRational, BigInteger, ModInteger, BigDecimal or BigComplex.
edu.jas.poly:
contains classes for commutative polynomial, solvable polynomial and free non-commutative polynomial arithmetic like GenPolynomial, GenSolvablePolynomial, GenWordPolynomial and others such as AlgebraicNumber and a polynomial parser GenPolynomialTokenizer.
edu.jas.vector:
contains classes for vectors and lists of polynomials and solvable polynomials like GenVector or GenMatrix.
edu.jas.gb:
contains classes for polynomial and solvable polynomial reduction, Gröbner bases over fields and ideal arithmetic as well as thread parallel and distributed versions of Buchbergers algorithm like ReductionSeq, GroebnerBaseAbstract, GroebnerBaseSeq, GroebnerBaseParallel and GroebnerBaseDistributedHybridEC. There are also Gröbner bases in polynomial rings over principal ideal domains and Euclidean domains, so called D- and E-Gröbner bases, e.g. EGroebnerBaseSeq. New are Gröbner bases in free non-commutative polynomial rings over (skew) fields, see WordGroebnerBaseSeq.
edu.jas.gbmod:
contains classes for module Gröbner bases and syzygies over polynomials and solvable polynomials like ModGroebnerBase or SolvableSyzygy.
edu.jas.application:
contains classes with applications of Gröbner bases such as ideal intersections and ideal quotients implemented in Ideal or SolvableIdeal. Comprehensive Gröbner bases for polynomial rings over parameter rings are contained in class ComprehensiveGroebnerBaseSeq. Latest additions are zero and arbitrary dimensional radical-, irreducible-, prime- and primary-decomposition implemented in class Ideal.
edu.jas.ufd:
contains classes for unique factorization domains. Like the interface GreatestCommonDivisor, the abstract class GreatestCommonDivisorAbstract and various implementations, e.g. polynomial remainder sequences and modular algorithms. The package now contains factorization algorithms for univariate polynomials over several coefficient rings: modulo primes in class FactorModular, over integers in class FactorInteger, over rational numbers in class FactorRational and over algebraic numbers in class FactorAlgebraic<C>.
edu.jas.gbufd:
contains classes for Gröbner base computation using classes from the edu.jas.ufd package for polynomial coefficients. The main classes deal with pseudo reduction PseudoReduction, PseudoReductionSeq and greatest common divisors computation on coefficients GroebnerBasePseudoSeq. Multiplicative sets of polynomials with several simplifications, e.g. maintaining co-prime factors or co-prime and squarefree factors, are contained in classes MultiplicativeSet, MultiplicativeSetCoPrime or MultiplicativeSetSquarefree. Also contained are Gröbner bases for polynomial rings over regular rings (direct products of fields or integral domains) in RGroebnerBaseSeq and RGroebnerBasePseudoSeq.
edu.jas.root:
contains classes for real root computations. Like the interface RealRoots, the abstract class RealRootsAbstract and at the moment of a single implementation based on Sturm sequences RealRootsSturm. The package further contains an implementation for real algebraic numbers RealAlgebraicNumber with a corresponding factory RealAlgebraicRing. For complex root isolation there are ComplexRoots interface, ComplexRootsAbstract and ComplexRootsSturm classes. The implementation provides an exact infallible method which follows the numeric method of Wilf. It uses Sturm sequences following the Routh-Hurwitz Method to count the number of complex roots within a rectangle in the complex plane. There is also an implementation for complex algebraic numbers ComplexAlgebraicNumber with a corresponding factory ComplexAlgebraicRing.
edu.jas.ufdroot:
contains classes for factorization in structures used in root computation, for example FactorRealAlgebraic.
edu.jas.ps:
contains univariate and multivariate power series arithmetic in classes UnivPowerSeries and MultiVarPowerSeries. There is an initial implementation of Mora's tangent cone reduction algorithm in class ReductionSeq and a standard bases computation in StandardBaseSeq with method STD().
edu.jas.integrate:
contains methods for the elementary integration of univariate rational functions. The main class is ElementaryIntegration with method integrate().
edu.jas.util:
contains further utilities for parallel and distributed computations like ThreadPool, DistThreadPool or DistHashTable. Part of this package has become obsolete with JDK 1.5.
edu.jas.fd:
contains classes for solvable polynomials rings as (non-unique) factorization domains. There are methods for polynomial pseudo remainder computation over Ore domains in class FDUtil. Further, methods for common divisors are included, but not yet finished.

Static package and component structure overview
Figure 1: Package and component structure overview


Heinz Kredel

Last modified: Mon Mar 28 23:49:24 CEST 2016

java-algebra-system-2.7.200/doc/problems.html000066400000000000000000000516131445075545500210220ustar00rootroot00000000000000 JAS - Designs, Problems and Solutions

JAS - Designs, Problems and Solutions

In ths document we discus some design alternatives, some problems and present our implemented solutions.

1. Designs

Note: In this section 'base ring' and 'extension ring' mean object oriented concepts not the mathematical concepts. I.e. 'base ring' is the super class of all considered ring classes and 'extension ring' is some subclass of the 'base ring' class.

The first question is which classes or which objects implement the arithmetic of polynomials. Are polynomials only passive containers which are transformed by ring methods? Or are polynomials active objects with methods.

1.1. Ring is object with methods

One design was proposed e.g. by M. Conrad in 2002 (see ring.perisic.com). It starts with an abstract Ring with abstract methods for the ring operations and some real implementations, e.g. for powers. The method parameters are RingElts, which serve mostly as containers for the different ring implementations. The concrete rings, e.g. rational numbers or polynomials, extend Ring and implement the algortihms for the respective (extended) RingElt data structures. RingElt structures are moreover mostly private classes within their corresponding Ring extension.

Type resolution of the parameters of the methods is completely dynamic during runtime. There is no compile time type checking. The type resolution, by means of a RingX.map(RingElt) method, is moreover able to coerce elements from one ring to some other ring, e.g. form rational to polynomial over rationals, similar to Scratchpad. The base Ring knows about all extension rings, like in a closed world.

Creation of extension rings is mainly at initialization time of the base ring (since it knows all extensions) into ring properties. Creation of ring elements is mostly dynamic using direct constructors in the various map() methods.

1.2. Polynomial is object with methods

An other design, e.g. used in our approach, takes polynomials as the primary players. A Polynomial is implemented as a class with the usual algebraic operations as methods. Each polynomial has a reference to a corresponding Ring object, which is a container for the ring characteristics. E.g. for polynomial rings these are the number of variables, the type information of the coefficent ring, the term order, the names of the variables and eventualy the commutator relations. There is one proposal by V. Niculescu, from 2003, [ref: A design proposal for an object oriented algebraic library] to view and implement the Ring as a factory class for polynomials and to make the polynomial constructors unavailable.

Creation of ring elements was in our first design by employing the prototype creational pattern (via clone()) and directly using element constructors. In the new design it will use the factory pattern (via getZERO(), getONE() etc.) of the RingFactory

Type resolution of the coefficient or polynomial method parameters are to the respective interface during compile time with a dynamic upcast to the actual polynomial or coefficient during runtime. There is currently no mapping of elements from one ring to another. However there are conversions / constructor / parser methods from long, java.math.BigInteger, String and java.io.Reader in the new design.

1.3. Template, generics and type parameter approaches

These approaches may not be completely covered by Java, C++ or C#. For polynomials they mean the usage of a type parameter (eventually restricted to some unterface) for the coefficient ring.

The creation problem is difficult to solve in Java, since type parameters can not be used in new or class.newInstance(). I.e. new objects can not be generated only from a type parameter but only from an object or class.

2. Problems

During the development and refactorings some problems have been detected. Consider the following interface and class definitions.

interface ModulElem {
  ModulElem sum(ModulElem other);
  ...
}

interface RingElem extends ModulElem {
  // RingElem sum(RingElem other); no override
  RingElem multiply(RingElem other);
  ...
}

class Rational implements RingElem { // jdk 1.5

  /*ModulElem*/ Rational sum(ModulElem other) {
  ...
  }

  /*RingElem*/  Rational multiply(RingElem other) {
     if ( other instanceof Rational ) {
        return multiply( (Rational)other );
     } else { 
        return // coerce to suitable ring extension
     }
  }

  Rational multiply(Rational other) {
  ...
  }

}

class Complex implements RingElem {
  ...
}

  void usageOK() {
    Rational a = new Rational();
    Rational b = new Rational();
    Rational c;
    c = a.sum(b);       // jdk 1.5
    c = a.multiply(b);  // jdk 1.5
  }

  void usageProblem1() {
    RingElem a = new Rational();
    RingElem b = new Rational();
    RingElem c;
    c = (RingElem) a.sum(b); // must cast
    c = a.multiply(b);       // no cast
  }

  void usageProblem2() {
    RingElem a = new Rational();
    RingElem b = new Complex();
    RingElem c;
    c = a.multiply(b); // runtime failiure
  }

One problem is the cast in c = (RingElem)a.sum(b) which is not expected since a and b are RingElems. One sulution would be to redefine sum() for RingElem, but then sum() in ModulElem is not overriden. Then RingElem is no longer an extension of ModulElem and the relation between the interfaces is broken.

The other problem is 'up cast' in return multiply( (Rational)other ) which defeates compile time type safety. multiply( ) is at first not meaningful defined between Rational and Complex. One could as in Scratchpad coerce Rational to Complex (here extend) and multiply to Complex objects, but this may not be expected by the application.

This problems exist also if abstract classes are used instead of interfaces.

3. Solutions

Reflecting on the mentioned designs and problems our design proposal is as follows.

  1. We do not distinguish between interfaces for modules, rings or fields. There is only one interface for rings, wich also defines inverse() and quotient() together with a method isUnit() to see if a certain element is invertible or can be used as divisor.

  2. To separate the creation process of ring elements from the implementation of the ring element abstract data type we distinguish two interfaces: RingElem<C extends RingElem> and RingFactory<C extends RingElem>.

  3. RingElem uses a type parameter C which is itself recursively reqired to extend RingElem: C extends RingElem. Also the interface RingFactory depends on the same type parameter.

  4. Basic data types, such as rational numbers, can directly implement both interfaces but more complex data types, such as polynomials will implement the interfaces in two different classes. e.g.

    BigRational implements RingElem<BigRational>, RingFactory<BigRational>
    

    or for generic polynomials

    GenPolynomial<C extends RingElem<C> > implements RingElem< GenPolynomial<C> >
    
    GenPolynomialRing<C extends RingElem<C> > implements RingFactory< GenPolynomial<C> >
    
  5. Constructors for basic data types can be implemented in any appropriate way. Constructors for more complex data types should always require one parameter to be of the respective factory type. This is to avoid the creation of elements with no knowledge of is corresponding ring factory. Constructors which require more preconditions, which are only provided by type (internal) methods should not be declared public. It seems best to declare them as protected.

  6. Basic arithmetic is implemented using the java.math.BigInteger class, which is itself implemented like GnuMP. At the moment the following classes are implemented BigInteger, BigRational, ModInteger, BigComplex, BigQuaternion and AlgebraicNumber.

  7. Generic polynomials are implemented as sorted maps from exponent vectors to coefficients. For sorted map the Java class java.util.TreeMap is used. The older alternative implementation using Map, implemented with java.util.LinkedHashMap, has been abandoned. There is only one implementation of exponent vectors ExpVector as dense Java array of longs. Other implementations, e.g. sparse representation or bigger numbers or ints are not considered at the moment. The comparators for SortedMap<ExpVector,C> are created from a TermOrder class which implements most used term orders in practice.

  8. Non commutative polynomials with respect to certain commutator relations, so called solvable polynomials, are extended from GenPolynomial respectively GenPolynomialRing. The relations are stored in RelationTable objects, which are inteded to be internal to the GenSolvablePolynomialRing. The class GenSolvablePolynomial implements the non commutative multiplication and uses the commutative methods from its super class GenPolynomial. As mentioned before, some casts are eventualy required, e.g. GenSolvablePolynomial<C> p.sum(q). The respective objects are however correctly buildt using the methods from the solvable ring factory.
    The class design allows solvable polynomial objects to be used in all algorithms where GenPolynomials can be used as parameters as long as no distinction between left and right multiplication is required.

3.1. Interfaces

The interface definition for ring elements with the usual arithmetic operations and some status, comparison methods and a clone method is as follows.

public interface RingElem<C extends RingElem> 
                 extends Cloneable, 
                         Comparable<C>, 
                         Serializable {
    public C clone();

    public boolean isZERO();
    public boolean isONE();
    public boolean isUnit();
    public boolean equals(Object b);
    public int     hashCode();
    public int     compareTo(C b);
    public int     signum();

    public C sum(C S);
    public C subtract(C S);
    public C negate();
    public C abs();
    public C multiply(C S);
    public C divide(C S);
    public C remainder(C S);
    public C inverse();
}

The interface definition for a ring factory for the creation respectively the reference to the ring constants 0 and 1 is given in the following code. Moreover there are often used casts / conversions from the basic Java types long and BigInteger, as well as a method to create a random element of the ring, a counter part to clone and some parsing methods to obtain a ring element from some external String or Reader.

public interface RingFactory<C extends RingElem> 
                 extends Serializable {
    public C getZERO();
    public C getONE();

    public C fromInteger(long a);
    public C fromInteger(BigInteger a);

    public C random(int n);
    public C copy(C c);

    public C parse(String s);
    public C parse(Reader r);
}

3.2. Some constructors

Constructors for BigRational:

    protected BigRational(BigInteger n, BigInteger d)
              // assert gcd(n,d) == 1
    public BigRational(BigInteger n)
    public BigRational(long n, long d)
    public BigRational(long n)
    public BigRational()
    public BigRational(String s) throws NumberFormatException

Constructors for GenPolynomial

    public GenPolynomial(GenPolynomialRing< C > r) 
    public GenPolynomial(GenPolynomialRing< C > r, SortedMap<ExpVector,C> v) 
    public GenPolynomial(GenPolynomialRing< C > r, C c, ExpVector e)

Constructors for GenPolynomialRing

    public GenPolynomialRing(RingFactory< C > cf, int n) 
    public GenPolynomialRing(RingFactory< C > cf, int n, TermOrder t) {
    public GenPolynomialRing(RingFactory< C > cf, int n, TermOrder t, String[] v)

3.3. Polynomial examples

Example of a random polynomial in 7 variables over the rational numbers with default term order and with 10 non zero coefficients:

   BigRational cfac = new BigRational();
   GenPolynomialRing<BigRational> fac;
                fac = new GenPolynomialRing<BigRational>(cfac,7);

   GenPolynomial<BigRational> a = fac.random(10);

a = GenPolynomial[ 31/5 (0,0,0,1,2,1,2), 19/15 (2,0,0,0,0,0,2), 
    13/5 (0,2,1,1,0,0,0), 2/3 (0,0,2,0,0,0,0), 217/18 (0,0,0,2,0,0,0), 
    18/5 (0,0,0,0,2,0,0), 11/32 (1,0,0,0,0,0,0), 63/4 (0,0,0,0,0,0,0) ] 
    :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ]

Example of a random polynomial in 3 variables over a polynomial ring in 7 variables over the rational numbers, both with default term order and with 10 non zero coefficients:

   BigRational cfac = new BigRational();
   GenPolynomialRing<BigRational> fac;
                fac = new GenPolynomialRing<BigRational>(cfac,7);

   GenPolynomialRing<GenPolynomial<BigRational>> gfac;
               gfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac,3);

   GenPolynomial<GenPolynomial<BigRational>> a = gfac.random(10);

a = GenPolynomial[ 
       GenPolynomial[ 10/3 (2,0,1,1,0,0,2), 8/7 (1,0,2,0,0,0,0), 
         9/5 (0,1,0,0,0,0,0), 1/4 (0,0,1,0,0,0,0), 3/14 (0,0,0,0,0,0,0) ] 
         :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ] (2,1,0), 
       GenPolynomial[ 26/23 (0,2,2,0,1,0,2), 9/4 (1,0,0,0,0,1,1), 
         29/17 (0,0,2,0,1,0,0), 24/19 (2,0,0,0,0,0,0), 28/13 (1,0,0,1,0,0,0), 
         11/32 (0,0,1,0,1,0,0), 18/11 (1,0,0,0,0,0,0), 5/11 (0,0,0,0,1,0,0), 
         475/32 (0,0,0,0,0,0,0) ] 
         :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ] (2,0,0), 
       GenPolynomial[ 14/15 (2,0,0,1,1,0,2), 19/5 (1,1,0,0,0,0,0), 
         4/29 (0,0,2,0,0,0,0), 23/27 (0,0,0,2,0,0,0), 20/13 (0,0,0,0,0,0,0) ] 
         :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ] (0,0,2), 
       GenPolynomial[ 13/8 (2,0,0,1,1,0,0), 8/7 (2,0,0,0,0,0,2), 
         21/2 (0,0,1,0,0,0,2), 23/22 (0,1,0,0,0,1,0), 9/11 (0,0,0,2,0,0,0), 
         21/2 (0,0,0,0,2,0,0), 23/13 (0,0,0,0,0,2,0), 5/2 (0,1,0,0,0,0,0), 
         367/62 (0,0,0,0,0,0,0) ] 
         :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ] (1,0,0), 
       GenPolynomial[ 4/3 (0,1,0,1,2,1,1), 17/2 (2,1,0,0,2,0,0), 
         10/29 (1,0,0,0,0,2,2), 3/2 (0,0,2,2,0,0,1), 11/8 (2,0,0,0,0,0,2), 
         26/31 (0,2,1,0,0,0,0), 10/9 (0,0,1,2,0,0,0), 4/5 (0,0,1,0,0,2,0), 
         1/8 (2,0,0,0,0,0,0), 1161/406 (0,2,0,0,0,0,0), 31/6 (0,0,0,2,0,0,0), 
         19 (0,0,1,0,0,0,0), 2 (0,0,0,0,0,1,0), 7/19 (0,0,0,0,0,0,1), 
         20227/2520 (0,0,0,0,0,0,0) ] 
         :: GenPolynomialRing[ BigRational, 7, IGRLEX(4),  ] (0,0,0) ] 
    :: GenPolynomialRing[ GenPolynomialRing, 3, IGRLEX(4),  ]

3.4. Algebraic number examples

Example of algebraic numbers

  AlgebraicNumber<C extends RingElem<C> > 
                 implements RingElem< AlgebraicNumber<C> >, 
                            RingFactory< AlgebraicNumber<C> >

over rational numbers (so defining an algebraic extension Q(alpha))

   BigRational cfac = new BigRational();

   GenPolynomialRing<BigRational> mfac;
       mfac = new GenPolynomialRing<BigRational>( cfac, 1 );

   GenPolynomial<BigRational> modul = mfac.random(8).monic();
       // assume !modul.isUnit()

   AlgebraicNumber<BigRational> fac;
       fac = new AlgebraicNumber<BigRational>( modul );

   AlgebraicNumber< BigRational > a = fac.random(15);

modul = GenPolynomial[ 1 (2), 13/12 (1), 55/21 (0) ] 
        :: GenPolynomialRing[ BigRational, 1, IGRLEX(4),  ]

a = AlgebraicNumber[ 
       GenPolynomial[ 1 (1), -175698982/14106209 (0) ] 
       :: GenPolynomialRing[ BigRational, 1, IGRLEX(4),  ] 
       mod 
       GenPolynomial[ 1 (2), 13/12 (1), 55/21 (0) ] 
       :: GenPolynomialRing[ BigRational, 1, IGRLEX(4),  ] ]

or modular integers (so defining a Galois field GF(p,n)).

   long prime = getPrime(); // 2^60-93
   ModInteger cfac = new ModInteger(prime,1);

   GenPolynomialRing<ModInteger> mfac;
       mfac = new GenPolynomialRing<ModInteger>( cfac, 1 );

   GenPolynomial<ModInteger> modul = mfac.random(8).monic();
       // assume !modul.isUnit()

   AlgebraicNumber<ModInteger> fac;
       fac = new AlgebraicNumber<ModInteger>( modul );

   AlgebraicNumber< ModInteger > a = fac.random(12);

modul = GenPolynomial[                  1 mod(1152921504606846883) (2), 
                       123527304065019309 mod(1152921504606846883) (1), 
                       452933448238404135 mod(1152921504606846883) (0) ] 
        :: GenPolynomialRing[ ModInteger, 1, IGRLEX(4),  ]

a = AlgebraicNumber[ 
       GenPolynomial[                  1 mod(1152921504606846883) (1), 
                      384307168202282226 mod(1152921504606846883) (0) ] 
       :: GenPolynomialRing[ ModInteger, 1, IGRLEX(4),  ] 
       mod 
       GenPolynomial[                  1 mod(1152921504606846883) (2), 
                      123527304065019309 mod(1152921504606846883) (1), 
                      452933448238404135 mod(1152921504606846883) (0) ] 
       :: GenPolynomialRing[ ModInteger, 1, IGRLEX(4),  ] ]

3.5. Solvable polynomial examples

Example for the creation of a solvable polynomial ring factory. The relation table is created internally.

     BigRational fac = new BigRational(0);
     TermOrder tord = new TermOrder(TermOrder.INVLEX);
     String[] vars = new String[]{ "x", "y", "z" };
     int nvar = vars.length;
     spfac = new GenSolvablePolynomialRing<BigRational>(fac,nvar,tord,vars);

spfac = GenSolvablePolynomialRing[ BigRational, 3, 
                                   INVLEX(2), x y z , 
                                   #rel = 0 ]
spfac.table = RelationTable[]

A non empty relation table looks as follows.

f = GenSolvablePolynomialRing[ BigRational, 3, INVLEX(2), x y z , #rel = 1 ]

f.ring.table = RelationTable[
               [0, 1]=[ExpVectorPair[(1,0,0),(0,1,0)], 
                       GenSolvablePolynomial[ 1 (1,1,0), -1 (0,0,0) ] 
                       :: GenSolvablePolynomialRing[ BigRational, 3, 
                                                     INVLEX(2), x y z , 
                                                     #rel = 1 ]
                      ]
               ]

Example of a solvable polynomial over Z_19.

d = GenSolvablePolynomial[ 3 mod(19) (1,1,0), 1 mod(19) (0,0,1) ] 
    :: GenSolvablePolynomialRing[ ModInteger, 3, INVLEX(2), x y z , #rel = 1 ]


Heinz Kredel

Last modified: Sun Mar 12 14:29:09 CET 2006

$Id$

java-algebra-system-2.7.200/doc/publications.html000066400000000000000000000310511445075545500216650ustar00rootroot00000000000000 JAS Project Publications

Java Algebra System (JAS) Project Publications

This page lists published papers and talks about the JAS design and mathematical contents.

The development of common divisors for solvable polynomials is presented in Heinz Kredel Common Divisors of Solvable Polynomials in JAS, Proc. International Congress on Mathematical Software (ICMS) 2016, Berlin, Germany. LNCS 9725, pp. 173 - 180, 2016, Springer-Verlag Berlin Heidelberg (slides)

The design of parametric solvable polynomial rings and parametric skew field coefficients with a summary of its mathematical definitions are contained in Heinz Kredel, Parametric solvable polynomial rings and applications, at the Conference on Computer Algebra in Scientific Computing CACS 2015, Aachen, Germany, 2015 (slides)

The versions of the Comprehensive Gröbner Bases from 2010 are presended in Heinz Kredel, Comprehensive Gröbner Bases in a Java Computer Algebra System, Computer Mathematics ASCM2009, ASCM2012, Contributed Papers and Invited Talks (eds. Feng, Ruyong and Lee, Wen-shin and Sato, Yosuke), pp. 93-108, 2014, Springer Berlin Heidelberg

An Overview on Groebner Bases implementations is given in Heinz Kredel Generic and Parallel Groebner Bases in JAS (Extended Abstract), proceedings of the International Congress on Mathematical Software (ICMS) August 5-9, 2014, Seoul, Korea. LNCS 8592, pp. 390 - 397, 2014, Springer-Verlag Berlin Heidelberg (slides)

Design and experiences using MPJ and high speed InfiniBand networking for algebraic computations are described in Heinz Kredel, Distributed Gröbner bases computation with MPJ, proceedings of the EOOPS Workshop at AINA-2013, March 25-28, 2013, Barcelona, Spain (slides)

Some ideas on categories and mixin composition in ScAS and JAS are presented in the poster Raphael Jolly, Heinz Kredel, Categories as classes and mixin composition, Poster at CASC 2012, September 3-6, 2012, Maribor, Slovenia

A comparison of API interfaces for computer algebra is presented in the paper Heinz Kredel, Fostering Interoperability in Java-Based Computer Algebra Software, Proceedings FINA Workshop AINA-2012, March 26-29, 2012, Fukuoka, Japan (slides)

The design of algebraic extension structures in JAS and ScAS is presented in the talk Raphael Jolly, Heinz Kredel, Algebraic Structures as Typed Objects, at the Conference on Computer Algebra in Scientific Computing CACS 2011, Kassel, Germany, 2011 (slides)

An early description of the JAS package for unique factorization domains (greatest common divisors, square-free decomposition, factorization) is contained in the article Heinz Kredel, Unique Factorization Domains in the Java Computer Algebra System, Special issue on Automated Deduction in Geometry, Lecture Notes in Computer Science volume 6301, pages 86-115, Springer, 2011

The design of JAS and ScAS is presented together with examples in the talk Raphael Jolly, Heinz Kredel, Generic, Type-safe and Object Oriented Computer Algebra Software, at the Conference on Computer Algebra in Scientific Computing CACS 2010, Tsakhkadzor, Armenia, 2010 (slides)

Performance meassurements for the distributed hybrid Gröbner bases implementation are contained in the paper Parallel and distributed Gröbner bases computation in JAS, avaliable as arxiv:1008.0011, 2010.

The new distributed hybrid Gröbner bases implementation is explained in the talk Distributed hybrid Groebner bases computation, at the CISIS 2010 Workshop on Engineering Complex Distributed Systems (ECDS 2010), Krakow. (slides)

A description of the JAS comprehensive Gröbner bases package is be contained in the talk Comprehensive Gröbner bases in a Java Computer Algebra System, at the Asian Symposium on Computers and Mathematics (ASCM 2009), Fukuoka.

Some unique factorization domain algorithms in JAS are contained in the seminar presentation Tools for the integration of rational functions in Java, during the Computer-Algebra Seminar, University of Mannheim, FMI 2009

More background information on the python scripting interface for JAS and ScAS can be found in the article Raphael Jolly, Heinz Kredel, Symbolic Script Programming for Java, avaliable as arXiv:0906.2315v2, 2009.

The parallel and distributed Gröbner bases implementations are explained in the talk Distributed parallel Groebner bases computation, at the CISIS 2009 Workshop on Engineering Complex Distributed Systems (ECDS 2009), Fukuoka (slides)

The Gröbner bases implementation of JAS is explained in the seminar presentation Gröbner bases and applications in Java, during the Computer-Algebra Seminar, University of Mannheim, FMI 2008

A description of the JAS greatest common divisor package is contained in the talk Multivariate Greatest Common Divisors in the Java Computer Algebra System, at the International Workshop on Automated Deduction in Geometry (ADG 2008), Shanghai.

Some background information on the python scripting interface for JAS can be found in the article Raphael Jolly, Heinz Kredel, How to turn a scripting language into a domain specific language for computer algebra, avaliable as arXiv:0811.1061v1, 2008. Previous title was Computer algebra in Java: libraries and scripting.

A comparison of JAS to other Computer Algebra Systems is contained in the talk Evaluation of a Java Computer Algebra System, at the Asian Symposium on Computer Mathematics (ASCM 2007), Singapore.
It has been published as paper in Heinz Kredel, Evaluation of a Java Computer Algebra System, Special issue Computer Mathematics of ASCM 2007 Revised and Invited Papers in Lecture Notes in Computer Science, volume 5081/2008, pages 121-138, Springer Berlin / Heidelberg

An article On a Java Computer Algebra System, its Performance and Applications, in Science of Computer Programming (2008).

At the PPPJ 2006 conference in Mannheim I presented the design of the JAS types, classes and implementation "On the Design of a Java Computer Algebra System" (slides).

At the A3L conference in Passau, 2005 I gave some background information on the development from MAS to JAS "A Systems Perspective on A3L" (slides).

The JAS project is also listed in the swMATH index of mathematical software JAS.

The history of the JAS project can be found in the Web-Log. See also the related projects and credits.


Heinz Kredel

Last modified: Tue Jul 19 00:20:53 CEST 2016

java-algebra-system-2.7.200/doc/related.html000066400000000000000000000451421445075545500206170ustar00rootroot00000000000000 Related projects

Related projects

  • MathLibre is a project to archive free mathematical software and free mathematical documents and offer them on Live Linux system. You can experience a wonderful world of opensource mathematical software systems.

Computer Algebra Systems using Java

  • ScAS is a computer algebra system developed in Scala. Scala has some more features than Java to optimally support the implementation of a computer algebra system. The basic structure of ScAS is developed in cooperation with the basic structure of JAS, see the co-authored papers in the Documentation section. ScAS is also a successor of jscl-meditor.

  • jscl-meditor Java symbolic computing library and mathematical editor. The goal of this project is to provide a Java symbolic computing library and a mathematical editor acting as a front-end to the former. There are several computer algebra systems available on the market, most of them developed in other languages, mainly C/C++ and Lisp. But the benefits of using Java in symbolic computation are great. Aside from being widely used and to comply with various standards, this language has two features of concern: readability and portability.

  • Symja - a symbolic math system written in Java based on the MathEclipse, JAS, Apache Commons Math, Apfloat, Rubi and other libraries. Features: arbitrary precision integers, rationals and complex numbers, polynomials, differentiation, integration, pattern matching and linear algebra. Its symbolic parser can handle Mathematica like expressions. Symja features a web application Symja-Web and an optimized library for Android Symja_Android_Library.

  • MathEclipse is a Java Computer Algebra system. MathEclipse has functions for arbitrary-precision integer arithmetic, matrices, vectors, finite sets, derivatives, pattern-matching rewriting rules and functional programming.

  • GeoGebra is dynamic mathematics software for all levels of education that joins arithmetic, geometry, algebra and calculus. On the one hand, GeoGebra is an interactive geometry system. You can do constructions with points, vectors, segments, lines, conic sections as well as functions and change them dynamically afterwards. On the other hand, equations and coordinates can be entered directly. Thus, GeoGebra has the ability to deal with variables for numbers, vectors and points, finds derivatives and integrals of functions and offers commands like Root or Extremum. These two views are characteristic of GeoGebra: an expression in the algebra view corresponds to an object in the graphics view and vice versa.

  • MathPiper is a new mathematics-oriented programming language which is simple enough to be learned as a first programming language and yet powerful enough to be useful in any science, mathematics, or engineering related career. MathPiper is also a Computer Algebra System (CAS) which is similar in function to the CAS which is included in the TI 89 and TI 92 calculators.

  • Jasymca: Programmable Java calculator. CAS (Computer Algebra System), provides exact and symbolic datatypes, interactive graphics display of functions. The user interface can be selected from either a Matlab/Octave/SciLab-style, or a GNU-Maxima-style. Runs on any Java SE- and ME-platform: Windows, MacOS, Linux, Cellphone, PDA and others.

  • JGEX: Java Geometry Expert is an ongoing developing system which initially began in early 2004 in Wichita State Univerisity. JGEX is a system which combines our approach for visually dynamic presentation of proofs (VDDP), dynamic geometry software (DGS), automated geometry theorem prover (GTP). The VDDP part is the most distinctive part of JGEX. It is based on our work on DGS and GTP. JGEX can be used to create proofs either manually and automatically. It provides a seris of visual effects for presenting of these proofs. With the applet version of JGEX, the user may create beautiful examples and put them on the web to share with others

  • JLinAlg is an open source and easy-to-use Java-library for linear algebra that is licensed under the GNU General Public License (GPL).

  • The Apache Commons Mathematics Library is a library of lightweight, self-contained mathematics and statistics components addressing the most common problems not available in the Java programming language or Commons Lang.

  • java.symcomp.org Java Library for SCSCP and OpenMath. The libraries org.symcomp.openmath and org.symcomp.scscp were developed in the SCIEnce Project, an Integrated Infrastructure Initiative, funded by the European Commission under the Research Infrastructures Action of Framework 6. WUPSI is a Universal Popcorn SCSCP Interface - The SCSCP Swiss Army Knife.

  • The Orbital Library is a Java class library providing object-oriented representations and algorithms for logic, mathematics, and artificial intelligence. It comprises theorem proving, computer algebra, search and planning, as well as machine learning algorithms.

  • Redberry is an open source Java framework providing capabilities for manipulation with tensors. The framework contains wide spectrum of algorithms required by tensor algebra. It is designed to find analytical solutions of complicated mathematical and physical problems.

  • Apfloat is a high performance arbitrary precision arithmetic library. You can perform calculations with a precision of millions of digits with it. It's as simple to use as Java's BigDecimal or BigInteger classes, but performs a lot better with extreme precision numbers (more than a few hundred digits). Also, a full suite of mathematical functions for arbitrary precision numbers are available: all those existing in java.lang.Math and more.

  • Jscience is a set of Java Tools and Libraries for the Advancement of Sciences. The system is not limited to computer algebra.

Other Open Source Computer Algebra Systems

  • Singular is a Computer Algebra System for polynomial computations with special emphasis on the needs of commutative algebra, algebraic geometry, and singularity theory.

  • CoCoA Computations in Commutative Algebra.

  • Risa/Asir is an open source general computer algebra system.

  • Mathemagix is a free computer algebra and analysis system under development. Standard libraries are available for algebraic computation (large numbers, polynomials, power series, matrices, etc. based on FFT and other fast algorithms) for exact and approximate computation. This should make Mathemagix particularly suitable as a bridge between symbolic computation and numerical analysis. The packages are written in C++. They can both be used from the new compiler mmc, from the old interpreter Mmx-light, or as standalone C++ libraries.

  • Pari/GP is a widely used computer algebra system designed for fast computations in number theory (factorizations, algebraic number theory, elliptic curves...), but also contains a large number of other useful functions to compute with mathematical entities such as matrices, polynomials, power series, algebraic numbers, etc., and a lot of transcendental functions.

  • Reduce is an interactive system for general algebraic computations of interest to mathematicians, scientists and engineers. It has been produced by a collaborative effort involving many contributors. Its capabilities include: expansion and ordering of polynomials and rational functions; substitutions and pattern matching in a wide variety of forms; automatic and user controlled simplification of expressions; calculations with symbolic matrices; arbitrary precision integer and real arithmetic; facilities for defining new functions and extending program syntax; analytic differentiation and integration; factorization of polynomials; facilities for the solution of a variety of algebraic equations; facilities for the output of expressions in a variety of formats; facilities for generating optimized numerical programs from symbolic input; calculations with a wide variety of special functions; Dirac matrix calculations of interest to high energy physicists.

  • FLINT is a C library for doing number theory. FLINT provides types and functions for computing over various base rings. FLINT uses many new algorithms and is sometimes orders of magnitude faster than other available software. FLINT is written in ANSI C and runs on many platforms, but is currently mostly optimised for x86 and x86-64 architectures. It is designed to be threadsafe. FLINT depends on the MPIR (GMP) and MPFR libraries.

  • Maxima is a system for the manipulation of symbolic and numerical expressions, including differentiation, integration, Taylor series, Laplace transforms, ordinary differential equations, systems of linear equations, polynomials, and sets, lists, vectors, matrices, and tensors. Maxima yields high precision numeric results by using exact fractions, arbitrary precision integers, and variable precision floating point numbers. Maxima can plot functions and data in two and three dimensions.

  • Macaulay 2 is a software system devoted to supporting research in algebraic geometry and commutative algebra, whose creation has been funded by the National Science Foundation since 1992. Macaulay2 includes core algorithms for computing Gröbner bases and graded or multi-graded free resolutions of modules over quotient rings of graded or multi-graded polynomial rings with a monomial ordering. The core algorithms are accessible through a versatile high level interpreted user language with a powerful debugger supporting the creation of new classes of mathematical objects and the installation of methods for computing specifically with them. Macaulay2 can compute Betti numbers, Ext, cohomology of coherent sheaves on projective varieties, primary decomposition of ideals, integral closure of rings, and more.

  • Axiom is a general purpose Computer Algebra system. It is useful for research and development of mathematical algorithms. It defines a strongly typed, mathematically correct type hierarchy. It has a programming language and a built-in compiler. In 2007, Axiom was forked into two different open source projects: OpenAxiom, and FriCAS.
    FriCAS is an advanced computer algebra system. Its capabilities range from calculus (integration and differentiation) to abstract algebra. It can plot functions and has integrated help system.
    OpenAxiom is an open source platform for symbolic, algebraic, and numerical computations. It offers an interactive environment, an expressive programming language, a compiler, a large set of mathematical libraries of interest to researchers and practitioners of computational sciences.

  • The Modula-2 Algebra System (MAS) is an experimental computer algebra system, developed at the University of Passau. MAS combines imperative programming facilities with algebraic specification capabilities for design and study of algebraic algorithms. It contains a large library of implemented Groebner basis algorithms for nearly all algebraic structures where such methods exist. MAS further includes algorithms for real quantifier elimination, parametric real root counting, and for computing in (noncommutative) polynomial rings.
    Starting point for the development of MAS was the requirement for a computer algebra system with an up to date language and design which makes the existing ALDES / SAC-2 algorithm libraries available. At this time there have been about 650 algorithms in ALDES / SAC-2 and additional 450 algorithms related to Gröbner bases developed on top of ALDES / SAC-2. The tension of reusing existing software in an interactive environment with specification capabilities contributes most to the evolution of MAS.
    The resulting view of the software has many similarities with the model theoretic view of algebra. The abstract specification capabilities are realized in a way that an interpretation in an example structure (a model) can be denoted. This means that is is not only possible to compute in term models modulo some congruence relation, but it is moreover possible to exploit an fast interpretation in some optimized (or just existing) piece of software.
    MAS is a predecessor to JAS with respect to the main concepts, however JAS was rewritten from scratch.

  • More open source mathematical programs.

  • to be continued

Computer Algebra Systems using other Object Oriented Programing Languages

  • Sage is an Open Source Mathematics Software creating a viable free open source alternative to Magma, Maple, Mathematica, and Matlab. Sage is written in Python and Cython as an interface to other open source CAS Singular, PARI/GP, GAP, gnuplot, Magma, and Maple.

  • SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python and does not require any external libraries.

  • GiNaC has been developed to become a replacement engine for xloops which in the past was powered by the Maple CAS. Its design is revolutionary in a sense that contrary to other CAS it does not try to provide extensive algebraic capabilities and a simple programming language but instead accepts a given language (C++) and extends it by a set of algebraic capabilities. The name GiNaC is an iterated and recursive abbreviation for GiNaC is Not a CAS, where CAS stands for Computer Algebra System.

  • Cadabra is a computer algebra system (CAS) designed specifically for the solution of problems encountered in field theory. It has extensive functionality for tensor polynomial simplification including multi-term symmetries, fermions and anti-commuting variables, Clifford algebras and Fierz transformations, implicit coordinate dependence, multiple index types and many more. The input format is a subset of TeX. Both a command-line and a graphical interface are available.


Heinz Kredel

Last modified: Wed Mar 31 22:42:35 CEST 2021

java-algebra-system-2.7.200/examples/000077500000000000000000000000001445075545500173545ustar00rootroot00000000000000java-algebra-system-2.7.200/examples/.gitignore000066400000000000000000000000341445075545500213410ustar00rootroot00000000000000/*.txt /*.out /*.class /edu java-algebra-system-2.7.200/examples/0dim_primary-decomp.py000066400000000000000000000014111445075545500235640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing from jas import terminate from jas import startLog from jas import QQ # polynomial examples: zero dimensional ideals prime and primary decomposition r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = y**2 - 5; f3 = z**3 - y * x ; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); Q = F.primaryDecomp(); t = System.currentTimeMillis() - t; print "Q = ", Q; print; print "primary decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_primary-decomp.rb000066400000000000000000000012731445075545500235450ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: zero dimensional ideals prime and primary decomposition r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #is automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)**2; f2 = y**2 - 5; f3 = z**3 - y * x ; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", [f1,f2,f3] ); puts "F = ", F; puts; startLog(); t = System.currentTimeMillis(); Q = F.primaryDecomp(); t = System.currentTimeMillis() - t; puts "Q = " + str(Q); puts; puts "primary decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_prime-decomp.py000066400000000000000000000014061445075545500232210ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing from jas import terminate from jas import startLog from jas import QQ # polynomial examples: zero dimensional ideals prime and primary decomposition r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = y**3 - x; f3 = z**2 - y * x; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; print "P = ", P; print; print "prime decomp time =", t1, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_prime-decomp.rb000066400000000000000000000012771445075545500232020ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: zero dimensional ideals prime and primary decomposition r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #is automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)**2; f2 = y**3 - x; f3 = z**2 - y * x; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", [f1,f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "prime decomp time = " + str(t1) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_radical.py000066400000000000000000000014101445075545500222320ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing from jas import terminate from jas import startLog from jas import QQ # polynomial examples: zero dimensional ideals radical decomposition r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = (y**2 - 3)**3 * (y**2 - 5); f3 = z**3 - x * y; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_radical.rb000066400000000000000000000013001445075545500222030ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: zero dimensional ideals radical decomposition r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #is automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)**2; f2 = (y**2 - 3)**3 * (y**2 - 5); f3 = z**3 - x * y; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", [f1,f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_real_roots.py000066400000000000000000000014531445075545500230130ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing from jas import terminate from jas import startLog from jas import QQ # polynomial examples: real roots over Q for zero dimensional ideals r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)*(x**2 - 3)**2; f2 = y**2 - 3; f3 = z**3 - x * y; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "real roots = "; F.realRootsPrint() print "real roots time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/0dim_real_roots.rb000066400000000000000000000013501445075545500227620ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: real roots over Q for zero dimensional ideals r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #is automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)*(x**2 - 3)**2; f2 = y**2 - 3; f3 = z**3 - x * y; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", [f1,f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "real roots = "; F.realRootsPrint() puts; puts "real roots time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/ChineseRemainder.py000066400000000000000000000035111445075545500231330ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, ZZ, GF, CC, ZM from jas import terminate, startLog # polynomial examples: Chines remainder theorem for polynomials #r = PolyRing( ZM(1152921504606846883), "(x,y,z)", PolyRing.lex ); #r = PolyRing( CC(), "(x,y,z)", PolyRing.lex ); ##r = PolyRing( ZZ(), "(x,y,z)", PolyRing.lex ); r = PolyRing( QQ(), "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x,y,z] = r.gens(); a = r.random(3,4); b = r.random(3,3); c = abs( r.random(3,3) ); print "a = ", a; print "b = ", b; print "c = ", c; print; ff = [[a,b,c], [a+1,b,c], [a,b+1,c], [a,b,c+1]]; print "ff = " + str([ str([ str(a) for a in f ]) for f in ff ]); print; ar = x; br = 3*one; cr = z - y; dr = 27*one; rr = [ar, br, cr, dr]; print "rr = " + str([ str(a) for a in rr]); print; t = System.currentTimeMillis(); dd = r.CRT("", ff, rr); t = System.currentTimeMillis() - t; print "if existing, Chinese remainder = " + str(dd); print; print "Chinese remainder time = " + str(t) + " milliseconds" ; print; # now, used for interpolation cr = r.ring.coFac; print "cr = " + str(cr.toScriptFactory()); print; a = cr.random(3); b = cr.random(4); c = cr.random(3).abs(); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); print; oo = cr.getONE(); ff = [[a,b,c], [a.sum(oo),b,c], [a,b.sum(oo),c], [a,b,c.sum(oo)]]; print "ff = " + str([ str([ str(a) for a in f ]) for f in ff ]); print; a1 = (2,3); b1 = (3,7); c1 = 5; d1 = (1,27); rr = [a1, b1, c1, d1]; print "rr = " + str([ str(a) for a in rr]); print; t = System.currentTimeMillis(); dd = r.CRTinterpol("", ff, rr); t = System.currentTimeMillis() - t; print "if existing, interpolated polynomial = " + str(dd); print; print "CRT interpolation time = " + str(t) + " milliseconds" ; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/ChineseRemainder.rb000066400000000000000000000033141445075545500231070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: Chines remainder theorem for polynomials #r = PolyRing.new( ZM(1152921504606846883), "(x,y,z)", PolyRing.lex ); #r = PolyRing.new( CC(), "(x,y,z)", PolyRing.lex ); ##r = PolyRing.new( ZZ(), "(x,y,z)", PolyRing.lex ); r = PolyRing.new( QQ(), "x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts; #one,x,y,z = r.gens(); a = r.random(3,4); b = r.random(2,3); c = r.random(3,3).abs(); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts; ff = [[a,b,c], [a+1,b,c], [a,b+1,c], [a,b,c+1]]; puts "ff = " + str(ff.map{ |f| f.map{ |a| a.to_s } }); puts; ar = x; br = 3*one; cr = z - y; dr = 27*one; rr = [ar, br, cr, dr]; puts "rr = " + str(rr.map{ |f| f.to_s }); puts; t = System.currentTimeMillis(); dd = r.CRT("", ff, rr); t = System.currentTimeMillis() - t; puts "if existing, Chinese remainder = " + str(dd); puts; puts "Chinese remainder time = " + str(t) + " milliseconds" ; puts; # now, used for interpolation cr = r.ring.coFac; puts "cr = " + str(cr.toScriptFactory()); a = cr.random(3); b = cr.random(4); c = cr.random(3).abs(); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts; oo = cr.getONE(); ff = [[a,b,c], [a.sum(oo),b,c], [a,b.sum(oo),c], [a,b,c.sum(oo)]]; puts "ff = " + str(ff.map{ |f| f.map{ |a| a.to_s } }); puts; a1 = 2/3; b1 = 3/7; c1 = 5; d1 = 1/27; rr = [a1, b1, c1, d1]; puts "ff = " + str(rr.map{ |f| f.to_s }); puts; t = System.currentTimeMillis(); dd = r.CRTinterpol("", ff, rr); t = System.currentTimeMillis() - t; puts "if existing, interpolated polynomial = " + str(dd); puts; puts "CRT interpolation time = " + str(t) + " milliseconds" ; puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/RingElemTest.py000066400000000000000000000045551445075545500223010ustar00rootroot00000000000000# # jython unit tests for jas. # $Id$ # from java.lang import System from java.lang import Integer from jas import PolyRing, Order, ZZ, QQ, ZM, GF from jas import terminate, startLog import unittest # some unit tests: class RingElemTest (unittest.TestCase): def testRingZZ(self): r = PolyRing( ZZ(), "(t,x)", Order.INVLEX ); self.assertEqual(str(r),'PolyRing(ZZ(),"t,x",Order.INVLEX)'); [one,x,t] = r.gens(); self.assertTrue(one.isONE()); self.assertTrue(len(x)==1); self.assertTrue(len(t)==1); # f = 11 * x**4 - 13 * t * x**2 - 11 * x**2 + 2 * t**2 + 11 * t; f = f**2 + f + 3; #print "f = " + str(f); self.assertEqual(str(f),'( 4 * x**4 - 52 * t**2 * x**3 + 44 * x**3 + 213 * t**4 * x**2 - 330 * t**2 * x**2 + 123 * x**2 - 286 * t**6 * x + 528 * t**4 * x - 255 * t**2 * x + 11 * x + 121 * t**8 - 242 * t**6 + 132 * t**4 - 11 * t**2 + 3 )'); #end def testRingQQ(self): r = PolyRing( QQ(), "(t,x)", Order.INVLEX ); self.assertEqual(str(r),'PolyRing(QQ(),"t,x",Order.INVLEX)'); [one,x,t] = r.gens(); self.assertTrue(one.isONE()); self.assertTrue(len(x)==1); self.assertTrue(len(t)==1); # f = 11 * x**4 - 13 * t * x**2 - 11 * x**2 + 2 * t**2 + 11 * t; f = f**2 + f + 3; #print "f = " + str(f); self.assertEqual(str(f),'( 4 * x**4 - 52 * t**2 * x**3 + 44 * x**3 + 213 * t**4 * x**2 - 330 * t**2 * x**2 + 123 * x**2 - 286 * t**6 * x + 528 * t**4 * x - 255 * t**2 * x + 11 * x + 121 * t**8 - 242 * t**6 + 132 * t**4 - 11 * t**2 + 3 )'); #end def testRingZM(self): r = PolyRing( GF(17), "(t,x)", Order.INVLEX ); self.assertEqual(str(r),'PolyRing(GFI(17),"t,x",Order.INVLEX)'); [one,x,t] = r.gens(); self.assertTrue(one.isONE()); self.assertTrue(len(x)==1); self.assertTrue(len(t)==1); # f = 11 * x**4 - 13 * t * x**2 - 11 * x**2 + 2 * t**2 + 11 * t; f = f**2 + f + 3; #print "f = " + str(f); self.assertEqual(str(f),'( 4 * x**4 + 16 * t**2 * x**3 + 10 * x**3 + 9 * t**4 * x**2 + 10 * t**2 * x**2 + 4 * x**2 + 3 * t**6 * x + t**4 * x + 11 * x + 2 * t**8 + 13 * t**6 + 13 * t**4 + 6 * t**2 + 3 )'); #end if __name__ == '__main__': #print str(__name__) + ": " + str(sys.modules[__name__]) unittest.main() java-algebra-system-2.7.200/examples/algNum.py000066400000000000000000000075731445075545500211650ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, AN, QQ, ZZ, terminate # multiple algebraic field extensions print "------- multiple algebraic field extensions QQ(alpha)(beta)(gamma)(delta) ---------"; r = PolyRing(QQ(),"alpha",PolyRing.lex); print "r = " + str(r); e,a = r.gens(); print "e = " + str(e); print "a = " + str(a); ap = a**5 - a + 1; print "ap = " + str(ap); x = r.factors(ap); print "x = " + str( [ str(p)+"**"+str(e)+"," for (p,e) in x.iteritems() ] ); qs2 = AN(ap,0,len(x)==1); # and e==1 print "qs2 = " + str(qs2.factory()); one,alpha = qs2.gens(); print "one = " + str(one); print "alpha = " + str(alpha); b = alpha**2 - 1; print "b = " + str(b); c = 1 / b; print "c = " + str(c); print "b*c = " + str(b*c); print ar = PolyRing(qs2,"beta",PolyRing.lex); print "ar = " + str(ar); e,a,b = ar.gens(); print "e = " + str(e); print "a = " + str(a); print "b = " + str(b); bp = b**2 - a; print "bp = " + str(bp); x = ar.factors(bp); print "x = " + str( [ str(p)+"**"+str(e)+"," for (p,e) in x.iteritems() ] ); qs3 = AN(bp,0,len(x)==1); # and e==1 print "qs3 = " + str(qs3.factory()); one,alpha,beta = qs3.gens(); print "one = " + str(one); print "alpha = " + str(alpha); print "beta = " + str(beta); c = -alpha + beta**3; print "c = " + str(c); d = 1 / c; print "d = " + str(d); e = c * d; print "e = " + str(e); print br = PolyRing(qs3,"gamma",PolyRing.lex); print "br = " + str(br); e,a,b,c = br.gens(); print "e = " + str(e); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); cp = c**2 - b*c - a; print "cp = " + str(cp); x = br.factors(cp); print "x = " + str( [ str(p)+"**"+str(e)+"," for (p,e) in x.iteritems() ] ); qs4 = AN(cp,0,len(x)==1); # and e==1 print "qs4 = " + str(qs4.factory()); one,alpha,beta,gamma = qs4.gens(); print "one = " + str(one); print "alpha = " + str(alpha); print "beta = " + str(beta); print "gamma = " + str(gamma); d = -alpha*gamma + beta; print "d = " + str(d); e = 1 / d; print "e = " + str(e); f = e * d; print "f = " + str(f); print cr = PolyRing(qs4,"delta",PolyRing.lex); print "cr = " + str(cr); e,a,b,c,d = cr.gens(); print "e = " + str(e); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); print "d = " + str(d); dp = d**2 + c*d - b + a; # irreducible #dp = (d**2 + b) * ( c**2 - a ); # = b * c * ( d**2 + b ) #dp = (d + b * c) * ( d + c - a**2 ); print "dp = " + str(dp); x = cr.factors(dp); print "x = " + str( [ str(p)+"**"+str(e)+"," for (p,e) in x.iteritems() ] ); qs5 = AN(dp,0,len(x)==1); # and e==1 print "qs5 = " + str(qs5.factory()); one,alpha,beta,gamma,delta = qs5.gens(); print "one = " + str(one); print "alpha = " + str(alpha); print "beta = " + str(beta); print "gamma = " + str(gamma); print "delta = " + str(delta); #e = -alpha*gamma + beta*delta; # ok #e = alpha**3 - gamma; # 1/e does fail not because it is a unit e = delta**2 + beta; # 1/e fails e = delta + beta*gamma; # 1/e fails print "e = " + str(e); f = 1 / e; print "f = " + str(f); g = e * f; print "g = " + str(g); print f = ( ( ( ( (3,82) * alpha**4 - (12,41) * alpha**3 - (13,82) * alpha**2 - (19,82) * alpha - (15,82) ) * beta + ( (3,82) * alpha**4 - (12,41) * alpha**3 - (13,82) * alpha**2 - (19,82) * alpha - (15,82) ) ) * gamma - ( ( (21,82) * alpha**4 - (45,82) * alpha**3 - (25,41) * alpha**2 - (51,82) * alpha - (32,41) ) * beta - ( (45,82) * alpha**4 + (25,41) * alpha**3 + (51,82) * alpha**2 + (43,82) * alpha + (21,82) ) ) ) * delta - ( ( ( (39,82) * alpha**4 + (8,41) * alpha**3 - (5,82) * alpha**2 - (1,82) * alpha - (31,82) ) * beta ) * gamma + ( (11,82) * alpha**4 - (3,41) * alpha**3 + (7,82) * alpha**2 - (15,82) * alpha + (27,82) ) ) ); print "f = " + str(f); e = 1 / f; print "e = " + str(e); g = e * f; print "g = " + str(g); print terminate(); java-algebra-system-2.7.200/examples/algNum.rb000066400000000000000000000072271445075545500211340ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # multiple algebraic field extensions puts "------- multiple algebraic field extensions QQ(alpha)(beta)(gamma)(delta) ---------"; r = PolyRing.new(QQ(),"alpha",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); ap = a**5 - a + 1; puts "ap = " + str(ap); x = r.factors(ap); puts "x = " + str( x.map{ |p,e| str(p)+"**"+str(e)+"," }); qs2 = AN(ap,x.size==1); # and e==1 puts "qs2 = " + str(qs2.factory()); one,alpha = qs2.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); b = alpha**2 - 1; puts "b = " + str(b); c = 1 / b; puts "c = " + str(c); puts "b*c = " + str(b*c); puts ar = PolyRing.new(qs2,"beta",PolyRing.lex); puts "ar = " + str(ar); e,a,b = ar.gens(); puts "e = " + str(e); puts "a = " + str(a); puts "b = " + str(b); bp = b**2 - a; puts "bp = " + str(bp); x = ar.factors(bp); puts "x = " + str( x.map{ |p,e| str(p)+"**"+str(e)+"," }); qs3 = AN(bp,x.size==1); # and e==1 puts "qs3 = " + str(qs3.factory()); one,alpha,beta = qs3.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); puts "beta = " + str(beta); c = -alpha + beta**3; puts "c = " + str(c); d = 1 / c; puts "d = " + str(d); e = c * d; puts "e = " + str(e); puts br = PolyRing.new(qs3,"gamma",PolyRing.lex); puts "br = " + str(br); e,a,b,c = br.gens(); puts "e = " + str(e); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); cp = c**2 - b*c - a; puts "cp = " + str(cp); x = br.factors(cp); puts "x = " + str( x.map{ |p,e| str(p)+"**"+str(e)+"," }); qs4 = AN(cp,x.size==1); # and e==1 puts "qs4 = " + str(qs4.factory()); one,alpha,beta,gamma = qs4.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); puts "beta = " + str(beta); puts "gamma = " + str(gamma); d = -alpha*gamma + beta; puts "d = " + str(d); e = 1 / d; puts "e = " + str(e); f = e * d; puts "f = " + str(f); puts cr = PolyRing.new(qs4,"delta",PolyRing.lex); puts "cr = " + str(cr); e,a,b,c,d = cr.gens(); puts "e = " + str(e); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts "d = " + str(d); dp = d**2 + c*d - b + a; # irreducible #dp = (d**2 + b) * ( c**2 - a ); # = b * c * ( d**2 + b ) #dp = (d + b * c) * ( d + c - a**2 ); puts "dp = " + str(dp); x = cr.factors(dp); puts "x = " + str( x.map{ |p,e| str(p)+"**"+str(e)+", " }); qs5 = AN(dp,x.size==1); # and e==1 puts "qs5 = " + str(qs5.factory()); one,alpha,beta,gamma,delta = qs5.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); puts "beta = " + str(beta); puts "gamma = " + str(gamma); puts "delta = " + str(delta); #e = -alpha*gamma + beta*delta; # ok #e = alpha**3 - gamma; # 1/e does fail not because it is a unit e = delta**2 + beta; # 1/e fails e = delta + beta*gamma; # 1/e fails puts "e = " + str(e); f = 1 / e; puts "f = " + str(f); g = e * f; puts "g = " + str(g); puts f = ( ( ( ( 3/82 * alpha**4 - 12/41 * alpha**3 - 13/82 * alpha**2 - 19/82 * alpha - 15/82 ) * beta + ( 3/82 * alpha**4 - 12/41 * alpha**3 - 13/82 * alpha**2 - 19/82 * alpha - 15/82 ) ) * gamma - ( ( 21/82 * alpha**4 - 45/82 * alpha**3 - 25/41 * alpha**2 - 51/82 * alpha - 32/41 ) * beta - ( 45/82 * alpha**4 + 25/41 * alpha**3 + 51/82 * alpha**2 + 43/82 * alpha + 21/82 ) ) ) * delta - ( ( 39/82 * alpha**4 + 8/41 * alpha**3 - 5/82 * alpha**2 - 1/82 * alpha - 31/82 ) * beta * gamma + ( 11/82 * alpha**4 - 3/41 * alpha**3 + 7/82 * alpha**2 - 15/82 * alpha + 27/82 ) ) ); puts "f = " + str(f); e = 1 / f; puts "e = " + str(e); g = e * f; puts "g = " + str(g); puts terminate(); java-algebra-system-2.7.200/examples/alg_stat_1.py000066400000000000000000000021051445075545500217420ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Ideal from jas import QQ, ZZ from jas import startLog, terminate # example: Algebraic Statistics # Drton, Sturmfels, Sullivant, example 2.1.3 #r = PolyRing(QQ(),"l1,l2",PolyRing.grad); r = PolyRing(QQ(),"l1,l2",PolyRing.lex); print "Ring: " + str(r); print; print one,l1,l2; u0 = 3; u1 = 5; u2 = 7; u12 = 11; f1 = (u1+u12)*(l1+l2+2)*(l1+1)*(l1+l2+1)\ + (u12)*l1*(l1+1)*(l1+l2+1)\ - (u2+u12)*l1*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l1*(l1+l2+2)*(l1+1) ; f2 = (u2+u12)*(l1+l2+2)*(l2+1)*(l1+l2+1)\ + (u12)*l2*(l2+1)*(l1+l2+1)\ - (u1+u12)*l2*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l2*(l1+l2+2)*(l2+1) ; print f1; print f2; print h = l1*l2*(l1+1)*(l2+1)*(l1+l2+1)*(l1+l2+2); print h; print F = r.ideal(list=[f1,f2]); print F; print H = r.ideal(list=[h]); print H; print G = F.GB(); print G; print #startLog(); Q = G.sat(H); print Q; print #D = Q.radicalDecomp(); #print D; #print R = Q.realRoots(); print R; print print; #startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/alg_stat_1.rb000066400000000000000000000022221445075545500217150ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" #startLog(); # example: Algebraic Statistics # Drton, Sturmfels, Sullivant, example 2.1.3 #r = PolyRing(QQ(),"l1,l2",PolyRing.grad); r = PolyRing.new(QQ(),"l1,l2",PolyRing.lex); puts "Ring: " + r.to_s; puts; puts "gens: " + one.to_s + "," + l1.to_s + ", " + l2.to_s; puts; u0 = 3; u1 = 5; u2 = 7; u12 = 11; f1 = (u1+u12)*(l1+l2+2)*(l1+1)*(l1+l2+1)\ + (u12)*l1*(l1+1)*(l1+l2+1)\ - (u2+u12)*l1*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l1*(l1+l2+2)*(l1+1) ; f2 = (u2+u12)*(l1+l2+2)*(l2+1)*(l1+l2+1)\ + (u12)*l2*(l2+1)*(l1+l2+1)\ - (u1+u12)*l2*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l2*(l1+l2+2)*(l2+1) ; puts "f1: " + str(f1); puts; puts "f2: " + str(f2); puts h = l1*l2*(l1+1)*(l2+1)*(l1+l2+1)*(l1+l2+2); puts "h: " + str(h); puts F = r.ideal("",[f1,f2]); puts "F = " + str(F); puts H = r.ideal("",[h]); puts "H = " + str(H); puts G = F.GB(); puts "G = " + str(G); puts #startLog(); Q = G.sat(H); puts "Q = " + str(Q); puts #D = Q.radicalDecomp(); #puts "D = " + str(D); #puts R = Q.realRoots(); puts "R = " + str(R); puts #startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/alg_stat_1p.py000066400000000000000000000024441445075545500221300ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Ideal from jas import QQ, ZZ, RF from jas import startLog, terminate # example: Algebraic Statistics # Drton, Sturmfels, Sullivant, example 2.1.3 r = PolyRing(RF(PolyRing(QQ(),"u0,u1,u2,u12",PolyRing.lex)),"l1,l2",PolyRing.grad); print "Ring: " + str(r); print; print one,u0,u1,u2,u12,l1,l2; f1 = (u1+u12)*(l1+l2+2)*(l1+1)*(l1+l2+1)\ + (u12)*l1*(l1+1)*(l1+l2+1)\ - (u2+u12)*l1*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l1*(l1+l2+2)*(l1+1) ; f2 = (u2+u12)*(l1+l2+2)*(l2+1)*(l1+l2+1)\ + (u12)*l2*(l2+1)*(l1+l2+1)\ - (u1+u12)*l2*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l2*(l1+l2+2)*(l2+1) ; print f1; print f2; print #h = l1*l2*(l1+1)*(l2+1)*(l1+l2+1)*(l1+l2+2); h = l1*l2*(l1+1); hp = (l2+1); hpp = (l1+l2+1)*(l1+l2+2); print h; print hp; print hpp; print F = r.ideal(list=[f1,f2]); print F; print H = r.ideal(list=[h]); print H; print Hp = r.ideal(list=[hp]); print Hp; print Hpp = r.ideal(list=[hpp]); print Hpp; print startLog(); G = F.GB(); print G; print #startLog(); Q = G.sat(H); print Q; print Q = Q.sat(Hp); print Q; print Q = Q.sat(Hpp); print Q; print D = Q.radicalDecomp(); print D; print #Di = Q.decomposition(); #print Di; #print #startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/alg_stat_1p.rb000066400000000000000000000025621445075545500221040ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" #startLog(); # example: Algebraic Statistics # Drton, Sturmfels, Sullivant, example 2.1.3 r = PolyRing.new(RF(PolyRing.new(QQ(),"u0,u1,u2,u12",PolyRing.lex)),"l1,l2",PolyRing.grad); puts "Ring: " + str(r); puts; puts one, u0, u1, u2, u12, l1 ,l2; puts; f1 = (u1+u12)*(l1+l2+2)*(l1+1)*(l1+l2+1)\ + (u12)*l1*(l1+1)*(l1+l2+1)\ - (u2+u12)*l1*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l1*(l1+l2+2)*(l1+1) ; f2 = (u2+u12)*(l1+l2+2)*(l2+1)*(l1+l2+1)\ + (u12)*l2*(l2+1)*(l1+l2+1)\ - (u1+u12)*l2*(l1+l2+2)*(l1+l2+1)\ - (u0+u1+u2+u12)*l2*(l1+l2+2)*(l2+1) ; puts "f1 = " + str(f1); puts; puts "f2 = " + str(f2); puts #h = l1*l2*(l1+1)*(l2+1)*(l1+l2+1)*(l1+l2+2); h = l1*l2*(l1+1); hp = (l2+1); hpp = (l1+l2+1)*(l1+l2+2); puts "h = " + str(h); puts F = r.ideal("",[f1,f2]); puts "F = " + str(F); puts H = r.ideal("",[h]); puts "H = " + str(H); puts Hp = r.ideal("",[hp]); puts "Hp = " + str(Hp); puts Hpp = r.ideal("",[hpp]); puts "Hpp = " + str(Hpp); puts startLog(); G = F.GB(); puts "G = " + str(G); puts Q = G.sat(H); puts "Q = " + str(Q); puts Qp = Q.sat(Hp); puts "Qp = " + str(Qp); puts Qpp = Q.sat(Hpp); puts "Qpp = " + str(Qpp); puts D = Qpp.radicalDecomp(); puts "D = " + str(D); puts #Di = Qpp.decomposition(); #puts "Di = " + str(Di); #puts #startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/alg_surface.py000066400000000000000000000012621445075545500222020ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from java.lang import Integer from jas import Ring from jas import PolyRing from jas import Ideal from jas import QQ, AN, RF, EF from jas import terminate from jas import startLog # polynomial examples: Yr = EF(QQ()).extend("x,y").extend("z","z^2 + x^2 + y^2 - 1").build(); #print "Yr = " + str(Yr); #print [one,x,y,z] = Yr.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); print; f = (1+z)*(1-z); # / ( x**2 + y**2 ); print "f = " + str(f); print; g = f / (1 - z); print "g = " + str(g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/alg_surface.rb000066400000000000000000000010251445075545500221520ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: Yr = EF.new(QQ()).extend("x,y").extend("z","z^2 + x^2 + y^2 - 1").build(); #puts "Yr = " + str(Yr); #puts one,x,y,z = Yr.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts; f = (1+z)*(1-z); # / ( x**2 + y**2 ); puts "f = " + str(f); puts; g = one / (1 - z); puts "g = " + str(g); puts; g = f / (1 - z); puts "g = " + str(g); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/all_rings.py000066400000000000000000000625771445075545500217210ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, SolvPolyRing from jas import Ideal from jas import Module, SubModule, SolvableModule, SolvableSubModule from jas import startLog from jas import terminate from jas import ZZ, QQ, ZM, GF, DD, CC, Quat, Oct, AN, RealN, RF, RC, LC, RR, PS, MPS, Vec, Mat from edu.jas.arith import BigDecimal print "------- ZZ = BigInteger ------------"; z1 = ZZ(12345678901234567890); print "z1 = " + str(z1); z2 = z1**2 + 12345678901234567890; print "z2 = " + str(z2); print; print "------- QQ = BigRational ------------"; r1 = QQ(1,12345678901234567890); print "r1 = " + str(r1**3); r2 = r1**2 + (1,12345678901234567890); print "r2 = " + str(r2); print; print "------- ZM = ModInteger ------------"; m1 = ZM(19,12345678901234567890); print "m1 = " + str(m1); m2 = m1**2 + 12345678901234567890; print "m2 = " + str(m2); print; print "------- GF = ModInteger ------------"; m1 = GF(19,12345678901234567890); print "m1 = " + str(m1); m2 = m1**2 + 12345678901234567890; print "m2 = " + str(m2); print; print "------- DD = BigDecimal ------------"; d1 = DD(12345678901234567890); print "d1 = " + str(d1); d2 = (1/d1)**2; print "d2 = " + str(d2); print; print "------- CC = BigComplex ------------"; c1 = CC((1,2),(5,)); print "c1 = " + str(c1); c2 = (1/c1)**2; print "c2 = " + str(c2); c3 = CC(0,(1,)); c3 = 1/c3; print "c3 = " + str(c3); [one,I] = CC().gens(); print "one = " + str(one); print "I = " + str(I); c4 = c3 + 5 * I; print "c4 = " + str(c4); c5 = (-396,10201)-(80,10201)*I; print "c5 = " + str(c5); print; print "------- Quat = BigQuaternion ------------"; [oneQ,IQ,JQ,KQ] = Quat().gens(); print "oneQ = " + str(oneQ); print "IQ = " + str(IQ); print "JQ = " + str(JQ); print "KQ = " + str(KQ); q1 = 2 + 3 * IQ + 4 * JQ + 5 * KQ; print "q1 = " + str(q1); q2 = (1/q1)**2; print "q2 = " + str(q2); q3 = q2 * q1 * q1; print "q3 = " + str(q3); q4 = (-23,1458) + (-1,243)*IQ + (-4,729)*JQ + (-5,729)*KQ print "q4 = " + str(q4); q5 = q2 - q4; print "q5 = " + str(q5); print; print "------- Oct = BigOctonion ------------"; #print [ str(g) for g in Oct().gens() ]; #no: [oneOR,IOR,JOR,KOR,oneOI,IOI,JOI,KOI] = Oct().gens(); [oneOR,oneOI,IOR,IOI,JOR,JOI,KOR,KOI] = Oct().gens(); print "oneOR = " + str(oneOR); print "IOR = " + str(IOR); print "JOR = " + str(JOR); print "KOR = " + str(KOR); print "oneOI = " + str(oneOI); print "IOI = " + str(IOI); print "JOI = " + str(JOI); print "KOI = " + str(KOI); o1 = 2 * oneOR + 3 * IOR + 4 * JOR + 5 * KOR + 6 * oneOI + 7 * IOI + 8 * JOI + 9 * KOI; print "o1 = " + str(o1); o2 = (1/o1)**2; print "o2 = " + str(o2); o3 = o2 * o1 * o1; print "o3 = " + str(o3); o4 = (-69,20164)*oneOR + (-3,20164)*IOR + (-1,5041)*JOR + (-5,20164)*KOR + (-3,10082)*oneOI + (-7,20164)*IOI + (-2,5041)*JOI + (-9,20164)*KOI; print "o4 = " + str(o4); o5 = o2 - o4; print "o5 = " + str(o5); print; print "------- PolyRing(ZZ(),\"x,y,z\") ---------"; r = PolyRing(ZZ(),"x,y,z",PolyRing.grad); print "r = " + str(r); [one,x,y,z] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); p1 = 2 + 3 * x + 4 * y + 5 * z + ( x + y + z )**2; print "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 5 * z + 4 * y + 3 * x + 2; print "p2 = " + str(p2); p3 = p1 - p2; print "p3 = " + str(p3); print "p3.factory() = " + str(p3.factory()); print; print "------- PolyRing(QQ(),\"x,y,z\") ---------"; r = PolyRing(QQ(),"x,y,z",PolyRing.grad); print "r = " + str(r); [one,x,y,z] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); s1 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; print "s1 = " + str(s1); s2 = (1,2) + (2,3) * x + (2,5) * y + ( x + y + z )**2; print "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + (2,5) * y + (2,3) * x + (1,2); print "s3 = " + str(s3); s4 = s1 - s3; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); print; print "------- PolyRing(ZM(11),\"x,y,z\") ---------"; r = PolyRing(ZM(11),"x,y,z",PolyRing.grad); print "r = " + str(r); [one,x,y,z] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); p1 = 12 + 13 * x + 14 * y + 15 * z + ( x + y + z )**2; print "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 4 * z + 3 * y + 2 * x + 1; print "p2 = " + str(p2); p3 = p1 - p2; print "p3 = " + str(p3); print "p3.factory() = " + str(p3.factory()); print; print "------- PolyRing(DD(),\"x,y,z\") ---------"; r = PolyRing(DD(),"x,y,z",PolyRing.grad); print "r = " + str(r); [one,x,y,z] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); p1 = 0.2 + 0.3 * x + 0.4 * y + 0.5 * z + ( x + y + z )**2; print "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 0.5 * z + 0.40000000000000002220446049250313080847263336181641 * y + 0.29999999999999998889776975374843459576368331909180 * x + 0.200000000000000011102230246251565404236316680908203125; print "p2 = " + str(p2); p3 = p1 - p2; print "p3 = " + str(p3); print "p3.factory() = " + str(p3.factory()); print; print "------- PolyRing(CC(),\"x,y,z\") ---------"; r = PolyRing(CC(),"x,y,z",PolyRing.grad); print "r = " + str(r); [one,I,x,y,z] = r.gens(); print "one = " + str(one); print "I = " + str(I); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); s1 = CC((1,2)) + CC((2,3)) * x + 3 * I * y + ( x + y + z )**2; print "s1 = " + str(s1); #print "s1.factory() = " + str(s1.factory()); #print "s1.coefficients() = " + str(s1.coefficients()); s2 = ((1,2),) + ((2,3),) * x + 3 * I * y + ( x + y + z )**2; print "s2 = " + str(s2); #print "s2.factory() = " + str(s2.factory()); #print "s2.coefficients() = " + str(s2.coefficients()); s3 = z**2 + ((2,),) * y * z + ((2,),) * x * z + y**2 + ((2,),) * x * y + x**2 + ((0,),(3,)) * y + (( 2,3),) * x + ((1,2),); print "s3 = " + str(s3); #print "s3.factory() = " + str(s3.factory()); #print "s3.coefficients() = " + str(s3.coefficients()); s4 = s3 - s1; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); print; print "------- PolyRing(Quat(),\"x,y,z\") ---------"; r = PolyRing(Quat(),"x,y,z",PolyRing.grad); print "r = " + str(r); [oneQ,IQ,JQ,KQ,x,y,z] = r.gens(); print "oneQ = " + str(oneQ); print "IQ = " + str(IQ); print "JQ = " + str(JQ); print "KQ = " + str(KQ); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); s1 = Quat((1,2)) + Quat((2,3)) * x + Quat((2,5)) * y + ( x + y + z )**2; print "s1 = " + str(s1); s2 = ((1,2),) + ((2,3),) * x + ((2,5),) * y + ( x + y + z )**2; print "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + (2,5) * y + (2,3) * x + (1,2); print "s3 = " + str(s3); s4 = s3 - s1; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); print; print "------- PolyRing(Oct(),\"x,y,z\") ---------"; r = PolyRing(Oct(),"x,y,z",PolyRing.grad); print "r = " + str(r); [oneOR,IOR,JOR,KOR,oneOI,IOI,JOI,KOI,x,y,z] = r.gens(); print "oneOR = " + str(oneOR); print "IOR = " + str(IOR); print "JOR = " + str(JOR); print "KOR = " + str(KOR); print "oneOI = " + str(oneOI); print "IOI = " + str(IOI); print "JOI = " + str(JOI); print "KOI = " + str(KOI); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); s1 = Oct(Quat((1,2))) + Oct(Quat((2,3))) * x + Oct(Quat((2,5))) * y + ( x + y + z )**2; print "s1 = " + str(s1); s2 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; print "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + (2,5) * y + (2,3) * x + (1,2); print "s3 = " + str(s3); s4 = s3 - s1; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); print; print "------- AN(alpha**2 - 2) ---------"; r = PolyRing(QQ(),"alpha",PolyRing.lex); print "r = " + str(r); [e,a] = r.gens(); print "e = " + str(e); print "a = " + str(a); sqrt2 = a**2 - 2; print "sqrt2 = " + str(sqrt2); Qs2 = AN(sqrt2); print "Qs2 = " + str(Qs2.factory()); [one,alpha] = Qs2.gens(); print "one = " + str(one); print "alpha = " + str(alpha); b = alpha**2 - 2; print "b = " + str(b); c = 1 / alpha; print "c = " + str(c); Qs2x = AN(alpha**2 - 2); print "Qs2x = " + str(Qs2x.factory()); print; print "------- GF_17(alpha**2 - 2) ---------"; r = PolyRing(GF(17),"alpha",PolyRing.lex); print "r = " + str(r); [e,a] = r.gens(); print "e = " + str(e); print "a = " + str(a); sqrt2 = a**2 - 2; print "sqrt2 = " + str(sqrt2); Qs2 = AN(sqrt2); print "Qs2 = " + str(Qs2.factory()); [one,alpha] = Qs2.gens(); print "one = " + str(one); print "alpha = " + str(alpha); b = alpha**2 - 2; print "b = " + str(b); c = 1 / alpha; print "c = " + str(c); Qs2x = AN(alpha**2 - 2); print "Qs2x = " + str(Qs2x.factory()); print; print "------- RealN(alpha**2 - 2,(1,2) ---------"; r = PolyRing(QQ(),"alpha",PolyRing.lex); print "r = " + str(r); [e,a] = r.gens(); print "e = " + str(e); print "a = " + str(a); sqrt2 = a**2 - 2; print "sqrt2 = " + str(sqrt2); Qs2r = RealN(sqrt2,(1,2)); print "Qs2r = " + str(Qs2r.factory()); [one,alpha] = Qs2r.gens(); print "one = " + str(one); print "alpha = " + str(alpha); b = 7 * alpha - 10; print "b = " + str(b); print "b.factory() = " + str(b.factory()); print "sign(b) = " + str(b.signum()); print "magnitude(b) = " + str(BigDecimal(b.elem.magnitude())); c = 1 / b; print "c = " + str(c); print "sign(c) = " + str(c.signum()); print "magnitude(c) = " + str(BigDecimal(c.elem.magnitude())); Qs2rx = RealN( alpha**2 - 2, ( 1, 2 ) ); print "Qs2rx = " + str(Qs2rx.factory()); print; print "------- PolyRing(PolyRing(QQ(),\"a,b,c\"),\"x,y,z\") ---------"; r = PolyRing(QQ(),"a,b,c",PolyRing.grad); print "r = " + str(r); pr = PolyRing(r,"x,y,z",PolyRing.lex); print "pr = " + str(pr); [one,a,b,c,x,y,z] = pr.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); s1 = QQ(1,2) + ( QQ(2,3) - c ) * x + ( QQ(2,5) + a + b )**2 * y + ( x + y + z )**2; print "s1 = " + str(s1); s2 = (1,2) + ( (2,3) - c ) * x + ( (2,5) + a + b )**2 * y + ( x + y + z )**2; print "s2 = " + str(s2); s3 = z**2 + ( 2 ) * y * z + ( 2 ) * x * z + y**2 + ( 2 ) * x * y + ( b**2 + 2 * a * b + a**2 + (4,5) * b + (4,5) * a + (4,25) ) * y + x**2 - ( c - (2,3) ) * x + ( (1,2) ); print "s3 = " + str(s3); s4 = s1 + s2 - 2 * s3; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); x = PolyRing(PolyRing(QQ(),"a, b, c",PolyRing.grad),"x, y, z",PolyRing.lex); print "x = " + str(x); print; print "------- RF(PolyRing(ZZ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing(ZZ(),"a,b,c",PolyRing.lex); print "r = " + str(r); rf = RF(r); print "rf = " + str(rf.factory()); [one,a,b,c] = rf.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); q1 = a / b; print "q1 = " + str(q1); q2 = ( -2 * c**2 + 4 * b**2 + 4 * a**2 - 7 ); print "q2 = " + str(q2); q3 = ( -7 * b + 4 * a + 12 ); print "q3 = " + str(q3); q4 = q2 / q3; print "q4 = " + str(q4); q5 = ( 2 * c**2 - 4 * b**2 - 4 * a**2 + 7 ) / (7 * b - 4 * a - 12 ); print "q5 = " + str(q5); q6 = q4 - q5; print "q6 = " + str(q6); print "q6.factory() = " + str(q6.factory()); x = RF(PolyRing(ZZ(),"a, b, c",PolyRing.lex)); print "x = " + str(x.factory()); print; print "------- RC(PolyRing(QQ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing(QQ(),"a,b,c",PolyRing.lex); print "r = " + str(r); [pone,pa,pb,pc] = r.gens(); print "pone = " + str(pone); print "pa = " + str(pa); print "pb = " + str(pb); print "pc = " + str(pc); g1 = pa**2 - 2; print "g1 = " + str(g1); g2 = pb**3 - 2; print "g2 = " + str(g2); g3 = pc**2 - pa*pb; print "g3 = " + str(g3); F = Ideal(r,list=[g1,g2,g3]); print "F = " + str(F); rc = RC(F); print "rc.factory() = " + str(rc.factory()); [one,a,b,c] = rc.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); r1 = a*b + c; print "r1 = " + str(r1); r2 = r1*r1*r1 - r1*r1 + one; print "r2 = " + str(r2); r3 = r2**3 - r1 + one; print "r3 = " + str(r3); r4 = ( -120 * a * b**2 * c + 606 * b**2 * c + 1917 * a * b * c + 400 * b * c - 132 * a * c - 673 * c + 432 * a * b**2 + 2130 * b**2 + 1436 * a * b - 72 * b + 100 * a - 1950 ); print "r4 = " + str(r4); r5 = r3 - r4; print "r5 = " + str(r5); print "r5.factory() = " + str(r5.factory()); r6 = 1/r2; print "r6 = " + str(r6); r7 = r6 * r2; print "r7 = " + str(r7); #F1 = Ideal(PolyRing(QQ(),"a, b, c",PolyRing.lex),list=[( pa**2 - 2 ), ( pb**3 - 2 ), ( pc**2 - pa * pb )]); #print "F1 = " + str(F1); rc1 = RC(Ideal(PolyRing(QQ(),"a, b, c",PolyRing.lex),list=[( a**2 - 2 ), ( b**3 - 2 ), ( c**2 - a * b )])); print "rc1.factory() = " + str(rc1.factory()); print; print "------- LC(PolyRing(QQ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing(QQ(),"a,b,c",PolyRing.lex); print "r = " + str(r); [pone,pa,pb,pc] = r.gens(); print "pone = " + str(pone); print "pa = " + str(pa); print "pb = " + str(pb); print "pc = " + str(pc); g1 = pa**2 - 2; print "g1 = " + str(g1); g2 = pb**3 - 2; print "g2 = " + str(g2); g3 = pc**2 - pa*pb; print "g3 = " + str(g3); F = Ideal(r,list=[g1,g2,g3]); print "F = " + str(F); lc = LC(F); print "lc.factory() = " + str(lc.factory()); print "gens = " + str([ str(x) for x in lc.gens() ]); [one,a,a1,b,b1,c,c1] = lc.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); #F1 = Ideal(PolyRing(QQ(),"a, b, c",PolyRing.lex),list=[( pa**2 - 2 ), ( pb**3 - 2 ), ( pc**2 - pa * pb )]); #print "F1 = " + str(F1); lc1 = LC(Ideal(PolyRing(QQ(),"a, b, c",PolyRing.lex),list=[( a**2 - 2 ), ( b**3 - 2 ), ( c**2 - a * b )])); print "lc1.factory() = " + str(lc1.factory()); l1 = a*b + c; print "l1 = " + str(l1); l2 = l1*l1*l1 - l1*l1 + one; print "l2 = " + str(l2); l3 = 1/l2; print "l3 = " + str(l3); l4 = l3 * l2; print "l4 = " + str(l4); l5 = a**2 - 2 + 1; print "l5 = " + str(l5); l6 = 1/l5; print "l6 = " + str(l6); l7 = (l1 * l2) / l2; print "l7 = " + str(l7); print; print "------- PolyRing( RF(PolyRing(ZZ(),\"a,b,c\",PolyRing.lex)), \"x,y,z\") ---------"; r = PolyRing(ZZ(),"a,b,c",PolyRing.lex); print "r = " + str(r); rf = RF(r); print "rf = " + str(rf.factory()); pf = PolyRing(rf, "x,y,z"); print "pf = " + str(pf); [one,a,b,c,x,y,z] = pf.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "c = " + str(c); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); q1 = a / b + x; print "q1 = " + str(q1); q2 = ( -2 * c**2 + 4 * b**2 + 4 * a**2 - 7 ) * y**2 - x / c; print "q2 = " + str(q2); q3 = ( -7 * b + 4 * a + 12 ) + z; print "q3 = " + str(q3); q4 = q2 / q3; print "q4 = " + str(q4); q5 = ( 2 * c**2 - 4 * b**2 - 4 * a**2 + 7 + x * z ) / (7 * b - 4 * a - 12 ) + y**2; print "q5 = " + str(q5); print "q5.factory() = " + str(q5.factory()); q6 = q5.monic(); print "q6 = " + str(q6); print; print "------- RR( [QQ(),ZM(19),DD()] ) ---------"; r = RR( [QQ(),ZM(19),DD()] ); print "r = " + str(r); print "r.factory() = " + str(r.factory()); rc1 = RR( [ QQ(), ZM(19), DD() ] ); print [ str(x) for x in r.gens() ]; print "rc1.factory() = " + str(rc1.factory()); [pg0,pg1,pg2] = r.gens(); print "pg0 = " + str(pg0); print "pg1 = " + str(pg1); print "pg2 = " + str(pg2); r1 = pg1 + pg2 + pg0; print "r1 = " + str(r1); r2 = r1 * r1 + 7 * r1; print "r2 = " + str(r2); r3 = r2**3; print "r3 = " + str(r3); r4 = 1/r3; print "r4 = " + str(r4); r5 = r4 - r1; print "r5 = " + str(r5); r6 = ( (-511,512)*pg0 + 17*pg1 - 0.998046875*pg2 ); print "r6 = " + str(r6); print; print "------- PS(QQ(),\"x\") ---------"; r = PS(QQ(),"x"); print "r = " + str(r); print "r.factory() = " + str(r.factory()); [one,x] = r.gens(); print "one = " + str(one); print "x = " + str(x); p1 = x**2 - 2; print "p1 = " + str(p1); p2 = x**3 - 2; print "p2 = " + str(p2); p3 = x**2 - p1 * p2; print "p3 = " + str(p3); p4 = - 4 + 3 * x**2 + 2 * x**3 - x**5; print "p4 = " + str(p4); def g1(i): return r.ring.coFac.fromInteger( 2*i ); def g2(i): #print "2*QQ(i) = " + str(QQ(2)*QQ(i)) return 2*QQ(i); r = PS(QQ(),"x",g2); print "r = " + str(r); print "r.factory() = " + str(r.factory()); [one,x] = r.gens(); print "one = " + str(one); print "x = " + str(x); p1 = x**2 - r; print "p1 = " + str(p1); p2 = x**3 - r/2; print "p2 = " + str(p2); print; print "------- MPS(QQ(),\"x,y\") ---------"; r = MPS(QQ(),"x,y"); print "r = " + str(r); print "r.factory() = " + str(r.factory()); one,x,y = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); p1 = x**2 - 2*y; print "p1 = " + str(p1); p2 = x**3 * y - y**2; print "p2 = " + str(p2); p3 = x**2 * y**2 - p1 * p2; print "p3 = " + str(p3); p4 = - 4 + 3 * x**2 + 2 * x**3 - x**5; print "p4 = " + str(p4); def g1(i): return r.ring.coFac.fromInteger( i.getVal(0)*i.getVal(1) ); def g2(i): #print "QQ(i.0)*QQ(i.1) = " + str(QQ(i.0)*QQ(i.1)) return QQ(i.getVal(0)) * QQ(i.getVal(1)); r = MPS(QQ(),"x,y",g2); print "r = " + str(r); print "r.factory() = " + str(r.factory()); one,x,y = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); p1 = x**2 - r; print "p1 = " + str(p1); p2 = y**3 + r/2; print "p2 = " + str(p2); print; print "------- Vec(QQ(),7) ---------"; r = Vec(QQ(),7); print "r = " + str(r); print "r.factory() = " + str(r.factory()); #print [ str(g) for g in r.gens() ]; [e1,e2,e3,e4,e5,e6,e7] = r.gens(); print "e1 = " + str(e1); print "e2 = " + str(e2); print "e3 = " + str(e3); print "e4 = " + str(e4); print "e5 = " + str(e5); print "e6 = " + str(e6); print "e7 = " + str(e7); v1 = e1 + e3; print "v1 = " + str(v1); #v2 = v1 + 5 * e7; #print "v2 = " + str(v2); v3 = v1 - e1 - e3; print "v3 = " + str(v3); print; print "------- Mat(QQ(),3,3) ---------"; r = Mat(QQ(),3,3); print "r = " + str(r); print "r.factory() = " + str(r.factory()); #print [ str(g) for g in r.gens() ]; [e11,e12,e13,e21,e22,e23,e31,e32,e33] = r.gens(); print "e11 = " + str(e11); print "e12 = " + str(e12); print "e13 = " + str(e13); print "e21 = " + str(e21); print "e22 = " + str(e22); print "e23 = " + str(e23); print "e31 = " + str(e31); print "e32 = " + str(e32); print "e33 = " + str(e33); m1 = e11 + e31; print "m1 = " + str(m1); m2 = m1 * m1 + 5*e22 + 9*e33; print "m2 = " + str(m2); m3 = m2**3 - 125*e21 - 125*e23; print "m3 = " + str(m3); m4 = 1/m2; print "m4 = " + str(m4); mi = m2*m4; print "mi = " + str(mi) + ", isONE: " + str(mi.isONE()); m5 = ( ( 1, 0, 0 ), ( -125, 125, -125 ), ( 1, 0, 0 ) ); # is PyTuple! print "m5 = " + str(m5); m6 = m3 * m5; print "m6 = " + str(m6); print; print "------- Mat(PolyRing(QQ(),\"x,y,z\",PolyRing.lex),3,3) ---------"; r = Mat(PolyRing(QQ(),"x,y,z",PolyRing.lex),3,3); print "r = " + str(r); print "r.factory() = " + str(r.factory()); #print [ str(g) for g in r.gens() ]; for g in r.gens(): print "g = " + str(g); print; m1 = r.random(5); print "m1 = " + str(m1); m2 = r.one(); #r.random(3); print "m2 = " + str(m2); m3 = m1*m2 - m2*m1; print "m3 = " + str(m3) + ", isZERO?: " + str(m3.isZERO()); print; print "------- PolyRing(Mat(QQ(),3,3),\"x,y,z\",PolyRing.lex) ---------"; r = PolyRing(Mat(QQ(),3,3),"x,y,z",PolyRing.lex); print "r = " + str(r); for g in r.gens(): print "g = " + str(g); print; m1 = r.random(5); print "m1 = " + str(m1); m2 = m1.monic(); print "m2 = " + str(m2); m3 = m2.lc(); print "m3 = " + str(m3) + ", isONE?: " + str(m3.isONE()); print; print "------- SolvPolyRing(QQ(),\"x,y,z\") ---------"; r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "r = " + str(r); [pone,px,py,pz] = r.gens(); print "pone = " + str(pone); print "px = " + str(px); print "py = " + str(py); print "pz = " + str(pz); rel = ( py, px, px * py - 1 , pz, py, py * pz - 1 ); #print "rel = " + str(rel); sr = SolvPolyRing(QQ(),"x,y,z",PolyRing.lex,rel); print "sr = " + str(sr); [one,x,y,z] = sr.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); print "one.factory() = " + str(one.factory()); s1 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; print "s1 = " + str(s1); s2 = (1,2) + (2,3) * x + (2,5) * y + ( x + y + z )**2; print "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + (2,5) * y + (2,3) * x + (1,2); print "s3 = " + str(s3); s4 = s1 - s3; print "s4 = " + str(s4); print "s4.factory() = " + str(s4.factory()); sr1 = SolvPolyRing(QQ(),"x, y, z",PolyRing.lex,(( z ), ( y ), ( y * z - 1 ),( y ), ( x ), ( x * y - 1 ))); print "sr1 = " + str(sr1); s5 = z * y; print "s5 = " + str(s5); s6 = s5**3; print "s6 = " + str(s6); s7 = ( z * y )**3; print "s7 = " + str(s7); s8 = s7 - s6; print "s8 = " + str(s8); s9 = y**3 * z**3 - 3 * y**2 * z**2 + 3 * y * z - 1; print "s9 = " + str(s9); s10 = s9 - s7; print "s10 = " + str(s10); print; print "------- SubModule(PolyRing(QQ(),\"u, v, l\",PolyRing.lex) ---------"; p = PolyRing(QQ(),"u, v, l",PolyRing.lex); print "p = " + str(p); [one,u,v,l] = p.gens(); print "one = " + str(one); print "u = " + str(u); print "v = " + str(v); print "l = " + str(l); m = Module(ring=p,cols=4); print "m = " + str(m); for g in m.gens(): print "g =", str(g); m1 = ( 0, 1, l + v, 0 ) m2 = ( 0, v, u * l**2, 0 ) m3 = ( 0, l + 3 * v, 0, u ) m4 = ( 0, v * l + v**2, u**2, 0 ) m5 = ( 0, l**2, u, 0 ) m6 = ( 1, 0, 0, l**2 ) m7 = ( 1, 0, l + 3 * v, 0 ) m8 = ( 1, 2, 0, l**2 ) m9 = ( u, 0, 0, v * l + v**2 ) m10 = ( l + v, 0, 0, u ) m11 = ( l**2, 0, 0, v ) m12 = ( l**2, 0, 2 * u,v ) ml = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12]; #ml=[ ( 0, 1, l + v, 0 ), ( 0, v, u * l**2, 0 ), ( 0, l + 3 * v, 0, u ), ( 0, v * l + v**2, u**2, 0 ), ( 0, l**2, u, 0 ), ( 1, 0, 0, l**2 ), ( 1, 0, l + 3 * v, 0 ), ( 1, 2, 0, l**2 ), ( u, 0, 0, v * l + v**2 ), ( l + v, 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, 2 * u,v ) ]; #print "ml = " + str(ml); #print; sm = m.submodul(list=ml); #sm = SubModule(m,list=ml); print "sm = " + str(sm); xm = SubModule(PolyRing(QQ(),"u, v, l",PolyRing.lex),list=[ ( 0, 1, ( l + v ), 0 ), ( 0, v, u * l**2, 0 ), ( 0, ( l + 3 * v ), 0, u ), ( 0, ( v * l + v**2 ), u**2, 0 ), ( 0, l**2, u, 0 ), ( 1, 0, 0, l**2 ), ( 1, 0, ( l + 3 * v ), 0 ), ( 1, 2, 0, l**2 ), ( u, 0, 0, ( v * l + v**2 ) ), ( ( l + v ), 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, 2 * u, v ) ]) # SubModule(PolyRing(QQ(),"u, v, l",PolyRing.lex),list=[ ( 0, 1, ( l + v ), 0 ), ( 0, v, u * l**2, 0 ), ( 0, ( l + 3 * v ), 0, u ), ( 0, ( v * l + v**2 ), u**2, 0 ), ( 0, l**2, u, 0 ), ( 1, 0, 0, l**2 ), ( 1, 0, ( l + 3 * v ), 0 ), ( 1, 2, 0, l**2 ), ( u, 0, 0, ( v * l + v**2 ) ), ( ( l + v ), 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, 2 * u, v ) ]) # SubModule(PolyRing(QQ(),"u, v, l",PolyRing.lex),list=[ ( 0, (1,), l + v, 0 ), ( 0, v, u * l**2, 0 ), ( 0, l + (3,) * v, 0, u ), ( 0, v * l + v**2, u**2, 0 ), ( 0, l**2, u, 0 ), ( (1,), 0, 0, l**2 ), ( (1,), 0, l + (3,) * v, 0 ), ( (1,), (2,), 0, l**2 ), ( u, 0, 0, v * l + v**2 ), ( l + v, 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, (2,) * u, v ) ]); # SubModule(PolyRing(QQ(),"u, v, l",PolyRing.lex),list=[ ( 0, (1,), l + v, 0 ), ( 0, v, u * l**2, 0 ), ( 0, l + (3,) * v, 0, u ), ( 0, v * l + v**2, u**2, 0 ), ( 0, l**2, u, 0 ), ( (1,), 0, 0, l**2 ), ( (1,), 0, l + (3,) * v, 0 ), ( (1,), (2,), 0, l**2 ), ( u, 0, 0, v * l + v**2 ), ( l + v, 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, (2,) * u, v ) ]); print "xm = " + str(xm); print; ## rg = sm.GB(); ## print "rg: " + str(rg); ## print "isGB: " + str(rg.isGB()); ## print; print "------- SolvableSubModule(SolvPolyRing(CC(),\"X,Y,x,y\")) ---------"; r = PolyRing(CC(),"X,Y,x,y",PolyRing.lex); print "r = " + str(r); [pone,pi,pX,pY,px,py] = r.gens(); print "pone = " + str(pone); print "pi = " + str(pi); print "pX = " + str(pX); print "pY = " + str(pY); print "px = " + str(px); print "py = " + str(py); #rel = ( py, px, px * py - 1 , pz, py, py * pz - 1 ); rel = [ py, px, pi * px * py, pY, pX, pi * pY * pX ]; print "rel = " + str([ str(x) for x in rel ]); sr = SolvPolyRing(CC(),"X,Y,x,y",PolyRing.lex,rel); print "sr = " + str(sr); [one,i,X,Y,x,y,] = sr.gens(); print "one = " + str(one); print "i = " + str(i); print "X = " + str(X); print "Y = " + str(Y); print "x = " + str(x); print "y = " + str(y); m1 = ( ( x + 1 ), ( y ) ) m2 = ( ( x * y ), ( 0 ) ) m3 = ( ( x - X ), ( x - X ) ) m4 = ( ( y - Y ), ( y - Y ) ) ml = [m1,m2,m3,m4]; #print "ml = " + str(ml); ssm = SolvableSubModule( sr, list=ml ); print "ssm: " + str(ssm); print; xsm = SolvableSubModule(SolvPolyRing(CC(),"X, Y, x, y",PolyRing.lex,rel=[y, x, ( ((0,),(1,)) * x * y ), Y, X, ( ((0,),(1,)) * X * Y )]),list=[ ( x - X, x - X ), ( x + ((1,),), y ), ( y - Y, y - Y ), ( x * y, 0 ) ]); # SolvableSubModule(SolvPolyRing(CC(),"X, Y, x, y",PolyRing.lex,rel=[y, x, ( ((0,),(1,)) * x * y ), Y, X, ( ((0,),(1,)) * X * Y )]),list=[ ( x - X, x - X ), ( x + ((1,),), y ), ( y - Y, y - Y ), ( x * y, 0 ) ]); # SolvableSubModule(SolvPolyRing(CC(),"X, Y, x, y",PolyRing.lex,(( y ), ( x ), ( ((0,),(1,)) * x * y ),( Y ), ( X ), ( ((0,),(1,)) * X * Y ))),list=[ ( x - X, x - X ), ( x + ((1,),), y ), ( y - Y, y - Y ), ( x * y, 0 ) ]); print "xsm: " + str(xsm); print; mlg = ssm.leftGB(); print "mlg: " + str(mlg); print; mtg = ssm.twosidedGB(); print "mtg: " + str(mtg); print; #print "------------------------------------"; #print "globals() = " + str(globals()); terminate(); sys.exit(); print "globals() = " + str(globals()); print "locals() = " + str(locals()); print "vars() = " + str(vars()); java-algebra-system-2.7.200/examples/all_rings.rb000066400000000000000000000621531445075545500216620ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" puts "------- ZZ = BigInteger ------------"; z1 = ZZ(12345678901234567890); puts "z1 = " + str(z1); z2 = z1**2 + 12345678901234567890; puts "z2 = " + str(z2); puts; puts "------- QQ = BigRational ------------"; r1 = QQ(1,12345678901234567890); puts "r1 = " + str(r1**3); r2 = r1**2 + 1/12345678901234567890; puts "r2 = " + str(r2); puts; puts "------- ZM = ModInteger ------------"; m1 = ZM(19,12345678901234567890); puts "m1 = " + str(m1); m2 = m1**2 + 12345678901234567890; puts "m2 = " + str(m2); puts; puts "------- DD = BigDecimal ------------"; d1 = DD(12345678901234567890); puts "d1 = " + str(d1); d2 = (1/d1)**2; puts "d2 = " + str(d2); puts; puts "------- CC = BigComplex ------------"; c1 = CC(1/2,5); puts "c1 = " + str(c1); c2 = (1/c1)**2; puts "c2 = " + str(c2); c3 = CC(0,1); c3 = 1/c3; puts "c3 = " + str(c3); one,I = CC().gens(); puts "one = " + str(one); puts "I = " + str(I); c4 = c3 + 5 * I; puts "c4 = " + str(c4); c5 = -396/10201 - 80/10201*I; puts "c5 = " + str(c5); puts; puts "------- Quat = BigQuaternion ------------"; oneQ,IQ,JQ,KQ = Quat().gens(); puts "oneQ = " + str(oneQ); puts "IQ = " + str(IQ); puts "JQ = " + str(JQ); puts "KQ = " + str(KQ); q1 = 2 + 3 * IQ + 4 * JQ + 5 * KQ; puts "q1 = " + str(q1); q2 = (1/q1)**2; puts "q2 = " + str(q2); q3 = q2 * q1 * q1; puts "q3 = " + str(q3); q4 = -23/1458 + -1/243*IQ + -4/729*JQ + -5/729*KQ puts "q4 = " + str(q4); q5 = q2 - q4; puts "q5 = " + str(q5); puts; puts "------- Oct = BigOctonion ------------"; #puts [ str(g) for g in Oct().gens() ]; oneOR,oneOI,IOR,IOI,JOR,JOI,KOR,KOI = Oct().gens(); puts "oneOR = " + str(oneOR); puts "IOR = " + str(IOR); puts "JOR = " + str(JOR); puts "KOR = " + str(KOR); puts "oneOI = " + str(oneOI); puts "IOI = " + str(IOI); puts "JOI = " + str(JOI); puts "KOI = " + str(KOI); o1 = 2 * oneOR + 3 * IOR + 4 * JOR + 5 * KOR + 6 * oneOI + 7 * IOI + 8 * JOI + 9 * KOI; puts "o1 = " + str(o1); o2 = (1/o1)**2; puts "o2 = " + str(o2); o3 = o2 * o1 * o1; puts "o3 = " + str(o3); o4 = -69/20164*oneOR + -3/20164*IOR + -1/5041*JOR + -5/20164*KOR + -3/10082*oneOI + -7/20164*IOI + -2/5041*JOI + -9/20164*KOI; puts "o4 = " + str(o4); o5 = o2 - o4; puts "o5 = " + str(o5); puts; puts "------- PolyRing(ZZ(),\"x,y,z\") ---------"; r = PolyRing.new(ZZ(),"x,y,z",PolyRing::grad); puts "r = " + str(r); one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); p1 = 2 + 3 * x + 4 * y + 5 * z + ( x + y + z )**2; puts "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 5 * z + 4 * y + 3 * x + 2; puts "p2 = " + str(p2); p3 = p1 - p2; puts "p3 = " + str(p3); puts "p3.factory() = " + str(p3.factory()); puts; puts "------- PolyRing(QQ(),\"x,y,z\") ---------"; r = PolyRing.new(QQ(),"x,y,z",PolyRing.grad); puts "r = " + str(r); one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); s1 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; puts "s1 = " + str(s1); s2 = 1/2 + 2/3 * x + 2/5 * y + ( x + y + z )**2; puts "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 2/5 * y + 2/3 * x + 1/2; puts "s3 = " + str(s3); s4 = s1 - s3; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); puts; puts "------- PolyRing(ZM(11),\"x,y,z\") ---------"; r = PolyRing.new(ZM(11),"x,y,z",PolyRing.grad); puts "r = " + str(r); one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); p1 = 12 + 13 * x + 14 * y + 15 * z + ( x + y + z )**2; puts "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 4 * z + 3 * y + 2 * x + 1; puts "p2 = " + str(p2); p3 = p1 - p2; puts "p3 = " + str(p3); puts "p3.factory() = " + str(p3.factory()); puts; puts "------- PolyRing(DD(),\"x,y,z\") ---------"; r = PolyRing.new(DD(),"x,y,z",PolyRing.grad); puts "r = " + str(r); one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); p1 = 0.2 + 0.3 * x + 0.4 * y + 0.5 * z + ( x + y + z )**2; puts "p1 = " + str(p1); p2 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + 0.5 * z + 0.40000000000000002220446049250313080847263336181641 * y + 0.29999999999999998889776975374843459576368331909180 * x + 0.200000000000000011102230246251565404236316680908203125; puts "p2 = " + str(p2); p3 = p1 - p2; puts "p3 = " + str(p3); puts "p3.factory() = " + str(p3.factory()); puts; puts "------- PolyRing(CC(),\"x,y,z\") ---------"; r = PolyRing.new(CC(),"x,y,z",PolyRing.grad); puts "r = " + str(r); one,I,x,y,z = r.gens(); puts "one = " + str(one); puts "I = " + str(I); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); s1 = CC(1/2) + CC(2/3) * x + 3 * I * y + ( x + y + z )**2; puts "s1 = " + str(s1); #puts "s1.factory() = " + str(s1.factory()); #puts "s1.coefficients() = " + str(s1.coefficients()); s2 = CC(1/2) + CC(2/3) * x + 3 * I * y + ( x + y + z )**2; puts "s2 = " + str(s2); #puts "s2.factory() = " + str(s2.factory()); #puts "s2.coefficients() = " + str(s2.coefficients()); s3 = z**2 + CC(2) * y * z + CC(2) * x * z + y**2 + CC(2) * x * y + x**2 + CC(0,3) * y + CC(2/3) * x + CC(1/2); puts "s3 = " + str(s3); #puts "s3.factory() = " + str(s3.factory()); #puts "s3.coefficients() = " + str(s3.coefficients()); s4 = s3 - s1; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); puts; puts "------- PolyRing(Quat(),\"x,y,z\") ---------"; r = PolyRing.new(Quat(),"x,y,z",PolyRing.grad); puts "r = " + str(r); oneQ,IQ,JQ,KQ,x,y,z = r.gens(); puts "oneQ = " + str(oneQ); puts "IQ = " + str(IQ); puts "JQ = " + str(JQ); puts "KQ = " + str(KQ); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); s1 = Quat(1/2) + Quat(2/3) * x + Quat(2/5) * y + ( x + y + z )**2; puts "s1 = " + str(s1); s2 = Quat(1/2) + Quat(2/3) * x + Quat(2/5) * y + ( x + y + z )**2; puts "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + Quat(2/5) * y + Quat(2/3) * x + Quat(1/2); puts "s3 = " + str(s3); s4 = s3 - s1; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); puts; puts "------- PolyRing(Oct(),\"x,y,z\") ---------"; r = PolyRing.new(Oct(),"x,y,z",PolyRing.grad); puts "r = " + str(r); oneOR,IOR,JOR,KOR,oneOI,IOI,JOI,KOI,x,y,z = r.gens(); puts "oneOR = " + str(oneOR); puts "IOR = " + str(IOR); puts "JOR = " + str(JOR); puts "KOR = " + str(KOR); puts "oneOI = " + str(oneOI); puts "IOI = " + str(IOI); puts "JOI = " + str(JOI); puts "KOI = " + str(KOI); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); s1 = Oct(Quat(1/2)) + Oct(Quat(2/3)) * x + Oct(Quat(2/5)) * y + ( x + y + z )**2; puts "s1 = " + str(s1); s2 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; puts "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + QQ(2,5) * y + QQ(2,3) * x + QQ(1,2); puts "s3 = " + str(s3); s4 = s3 - s1; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); puts; puts "------- AN(alpha**2 - 2) ---------"; r = PolyRing.new(QQ(),"alpha",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); sqrt2 = a**2 - 2; puts "sqrt2 = " + str(sqrt2); Qs2 = AN(sqrt2); puts "Qs2 = " + str(Qs2.factory()); one,alpha = Qs2.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); b = alpha**2 - 2; puts "b = " + str(b); c = 1 / alpha; puts "c = " + str(c); Qs2x = AN(alpha**2 - 2); puts "Qs2x = " + str(Qs2x.factory()); puts; puts "------- GF_17(alpha**2 - 2) ---------"; r = PolyRing.new(ZM(17),"alpha",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); sqrt2 = a**2 - 2; puts "sqrt2 = " + str(sqrt2); Qs2 = AN(sqrt2); puts "Qs2 = " + str(Qs2.factory()); one,alpha = Qs2.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); b = alpha**2 - 2; puts "b = " + str(b); c = 1 / alpha; puts "c = " + str(c); Qs2x = AN(alpha**2 - 2); puts "Qs2x = " + str(Qs2x.factory()); puts; puts "------- FF(17,5) ---------"; r = FF(17,5); puts "ring = " + str(r.ring.toScript()); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); s = a**5 - 2**5; puts "s = " + str(s); i = 1/ s; puts "1/s = " + str(i); t = i*s; puts "i*s = " + str(t); puts; puts "------- RealN(alpha**2 - 2,(1,2) ---------"; r = PolyRing.new(QQ(),"alpha",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); sqrt2 = a**2 - 2; puts "sqrt2 = " + str(sqrt2); Qs2r = RealN(sqrt2,[1,2]); puts "Qs2r = " + str(Qs2r.factory()); one,alpha = Qs2r.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); b = 7 * alpha - 10; puts "b = " + str(b); puts "b.factory() = " + str(b.factory()); puts "sign(b) = " + str(b.signum()); puts "magnitude(b) = " + str(BigDecimal.new(b.elem.magnitude())); c = 1 / b; puts "c = " + str(c); puts "sign(c) = " + str(c.signum()); puts "magnitude(c) = " + str(BigDecimal.new(c.elem.magnitude())); Qs2rx = RealN( alpha**2 - 2, [1,2] ); puts "Qs2rx = " + str(Qs2rx.factory()); puts; puts "------- PolyRing(PolyRing(QQ(),\"a,b,c\"),\"x,y,z\") ---------"; r = PolyRing.new(QQ(),"a,b,c",PolyRing.grad); puts "r = " + str(r); pr = PolyRing.new(r,"x,y,z",PolyRing.lex); puts "pr = " + str(pr); one,a,b,c,x,y,z = pr.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); s1 = QQ(1,2) + ( QQ(2,3) - c ) * x + ( QQ(2,5) + a + b )**2 * y + ( x + y + z )**2; puts "s1 = " + str(s1); s2 = 1/2 + ( 2/3 - c ) * x + ( 2/5 + a + b )**2 * y + ( x + y + z )**2; puts "s2 = " + str(s2); s3 = z**2 + ( 2 ) * y * z + ( 2 ) * x * z + y**2 + ( 2 ) * x * y + ( b**2 + 2 * a * b + a**2 + QQ(4,5) * b + QQ(4,5) * a + QQ(4,25) ) * y + x**2 - ( c - QQ(2,3) ) * x + ( QQ(1,2) ); puts "s3 = " + str(s3); s4 = s1 + s2 - 2 * s3; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); x = PolyRing.new(PolyRing.new(QQ(),"a, b, c",PolyRing.grad),"x, y, z",PolyRing.lex); puts "x = " + str(x); puts; puts "------- RF(PolyRing(ZZ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing.new(ZZ(),"a,b,c",PolyRing.lex); puts "r = " + str(r); rf = RF(r); puts "rf = " + str(rf.factory()); one,a,b,c = rf.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); q1 = a / b; puts "q1 = " + str(q1); q2 = ( -2 * c**2 + 4 * b**2 + 4 * a**2 - 7 ); puts "q2 = " + str(q2); q3 = ( -7 * b + 4 * a + 12 ); puts "q3 = " + str(q3); q4 = q2 / q3; puts "q4 = " + str(q4); q5 = ( 2 * c**2 - 4 * b**2 - 4 * a**2 + 7 ) / (7 * b - 4 * a - 12 ); puts "q5 = " + str(q5); q6 = q4 - q5; puts "q6 = " + str(q6); puts "q6.factory() = " + str(q6.factory()); x = RF(PolyRing.new(ZZ(),"a, b, c",PolyRing.lex)); puts "x = " + str(x.factory()); puts; puts "------- RC(PolyRing(QQ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing.new(QQ(),"a,b,c",PolyRing.lex); puts "r = " + str(r); pone,pa,pb,pc = r.gens(); puts "pone = " + str(pone); puts "pa = " + str(pa); puts "pb = " + str(pb); puts "pc = " + str(pc); g1 = pa**2 - 2; puts "g1 = " + str(g1); g2 = pb**3 - 2; puts "g2 = " + str(g2); g3 = pc**2 - pa*pb; puts "g3 = " + str(g3); F = r.ideal("",list=[g1,g2,g3]); puts "F = " + str(F); rc = RC(F,0); puts "rc.factory() = " + str(rc.factory()); one,a,b,c = rc.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); r1 = a*b + c; puts "r1 = " + str(r1); r2 = r1*r1*r1 - r1*r1 + one; puts "r2 = " + str(r2); r3 = r2**3 - r1 + one; puts "r3 = " + str(r3); r4 = ( -120 * a * b**2 * c + 606 * b**2 * c + 1917 * a * b * c + 400 * b * c - 132 * a * c - 673 * c + 432 * a * b**2 + 2130 * b**2 + 1436 * a * b - 72 * b + 100 * a - 1950 ); puts "r4 = " + str(r4); r5 = r3 - r4; puts "r5 = " + str(r5); puts "r5.factory() = " + str(r5.factory()); r6 = 1/r2; puts "r6 = " + str(r6); r7 = r6 * r2; puts "r7 = " + str(r7); #F1 = SimIdeal.new(PolyRing.new(QQ(),"a, b, c",PolyRing.lex),"",list=[( pa**2 - 2 ), ( pb**3 - 2 ), ( pc**2 - pa * pb )]); #puts "F1 = " + str(F1); pr1 = PolyRing.new(QQ(),"a, b, c",PolyRing.lex); one,a,b,c = pr1.gens(); ff1 = [( a**2 - 2 ), ( b**3 - 2 ), ( c**2 - a * b )]; rc1 = RC(SimIdeal.new(pr1,"",ff1)); puts "rc1.factory() = " + str(rc1.factory()); puts; puts "------- LC(PolyRing(QQ(),\"a,b,c\",PolyRing.lex)) ---------"; r = PolyRing.new(QQ(),"a,b,c",PolyRing.lex); puts "r = " + str(r); pone,pa,pb,pc = r.gens(); puts "pone = " + str(pone); puts "pa = " + str(pa); puts "pb = " + str(pb); puts "pc = " + str(pc); g1 = pa**2 - 2; puts "g1 = " + str(g1); g2 = pb**3 - 2; puts "g2 = " + str(g2); g3 = pc**2 - pa*pb; puts "g3 = " + str(g3); ff = r.ideal("",list=[g1,g2,g3]); puts "ff = " + str(ff); lc = LC(ff,0,1); puts "lc.factory() = " + str(lc.factory()); one,a,b,c = lc.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); #F1 = SimIdeal.new(PolyRing.new(QQ(),"a, b, c",PolyRing.lex),"",list=[( pa**2 - 2 ), ( pb**3 - 2 ), ( pc**2 - pa * pb )]); #puts "F1 = " + str(F1); pr1 = PolyRing.new(QQ(),"a, b, c",PolyRing.lex); one, a, b, c = pr1.gens(); ff1 = [( a**2 - 2 ), ( b**3 - 2 ), ( c**2 - a * b )]; lc1 = LC(SimIdeal.new(pr1,"",ff1)); puts "lc1.factory() = " + str(lc1.factory()); l1 = a*b + c; puts "l1 = " + str(l1); l2 = l1*l1*l1 - l1*l1 + one; puts "l2 = " + str(l2); l3 = 1/l2; puts "l3 = " + str(l3); l4 = l3 * l2; puts "l4 = " + str(l4); l5 = a**2 - 2 + 1; puts "l5 = " + str(l5); l6 = 1/l5; puts "l6 = " + str(l6); l7 = (l1 * l2) / l2; puts "l7 = " + str(l7); puts; puts "------- PolyRing( RF(PolyRing(ZZ(),\"a,b,c\",PolyRing.lex)), \"x,y,z\") ---------"; r = PolyRing.new(ZZ(),"a,b,c",PolyRing.lex); puts "r = " + str(r); rf = RF(r); puts "rf = " + str(rf.factory()); pf = PolyRing.new(rf, "x,y,z"); puts "pf = " + str(pf); one,a,b,c,x,y,z = pf.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); q1 = a / b + x; puts "q1 = " + str(q1); q2 = ( -2 * c**2 + 4 * b**2 + 4 * a**2 - 7 ) * y**2 - x / c; puts "q2 = " + str(q2); q3 = ( -7 * b + 4 * a + 12 ) + z; puts "q3 = " + str(q3); q4 = q2 / q3; puts "q4 = " + str(q4); q5 = ( 2 * c**2 - 4 * b**2 - 4 * a**2 + 7 + x * z ) / (7 * b - 4 * a - 12 ) + y**2; puts "q5 = " + str(q5); puts "q5.factory() = " + str(q5.factory()); q6 = q5.monic(); puts "q6 = " + str(q6); puts; puts "------- RR( [QQ(),ZM(19),DD()] ) ---------"; r = RR( [ QQ(),ZM(19),DD() ] ); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); rc1 = RR( [ QQ(), ZM(19), DD() ] ); print "gens = " , r.gens().map { |x| str(x) + ", " }, "\n"; puts "rc1.factory() = " + str(rc1.factory()); pg0,pg1,pg2 = r.gens(); puts "pg0 = " + str(pg0); puts "pg1 = " + str(pg1); puts "pg2 = " + str(pg2); r1 = pg1 + pg2 + pg0; puts "r1 = " + str(r1); r2 = r1 * r1 + 7 * r1; puts "r2 = " + str(r2); r3 = r2**3; puts "r3 = " + str(r3); r4 = 1/r3; puts "r4 = " + str(r4); r5 = r4 - r1; puts "r5 = " + str(r5); r6 = -511/512 * pg0 + 17 * pg1; #TODO - 0.998046875 * pg2; puts "r6 = " + str(r6); puts; puts "------- PS(QQ(),\"x\") ---------"; r = PS(QQ(),"x"); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); one,x = r.gens(); puts "one = " + str(one); puts "x = " + str(x); p1 = x**2 - 2; puts "p1 = " + str(p1); p2 = x**3 - 2; puts "p2 = " + str(p2); p3 = x**2 - p1 * p2; puts "p3 = " + str(p3); p4 = - 4 + 3 * x**2 + 2 * x**3 - x**5; puts "p4 = " + str(p4); def g1(i) return r.ring.coFac.fromInteger( 2*i ); end def g2(i) #puts "2*QQ(i) = " + str(QQ(2)*QQ(i)) return 2*QQ(i); end g3 = Proc.new { |i| 2*QQ(i) } r = PS(QQ(),"x",&g3); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); one,x = r.gens(); puts "one = " + str(one); puts "x = " + str(x); p1 = x**2 - r; puts "p1 = " + str(p1); p2 = x**3 + r/2; puts "p2 = " + str(p2); puts; puts "------- MPS(QQ(),\"x,y\") ---------"; r = MPS(QQ(),"x,y"); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); one,x,y = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); p1 = x**2 - 2*y; puts "p1 = " + str(p1); p2 = x**3 * y - y**2; puts "p2 = " + str(p2); p3 = x**2 * y**2 - p1 * p2; puts "p3 = " + str(p3); p4 = - 4 + 3 * x**2 + 2 * x**3 - x**5; puts "p4 = " + str(p4); def g1(i) return r.ring.coFac.fromInteger( i.getVal(0)*i.getVal(1) ); end def g2(i) #puts "QQ(i.0)*QQ(i.1) = " + str(QQ(i.getVal(0))*QQ(i.getVal(1))) return QQ(i.getVal(0))*QQ(i.getVal(1)); end g3 = Proc.new { |i| QQ(i.getVal(0))*QQ(i.getVal(1)) } r = MPS(QQ(),"x,y",&g3); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); one,x,y = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); p1 = x**2 - r; puts "p1 = " + str(p1); p2 = y**3 + r/2; puts "p2 = " + str(p2); puts; puts "------- Vec(QQ(),7) ---------"; r = Vec(QQ(),7); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); #puts [ str(g) for g in r.gens() ]; e1,e2,e3,e4,e5,e6,e7 = r.gens(); puts "e1 = " + str(e1); puts "e2 = " + str(e2); puts "e3 = " + str(e3); puts "e4 = " + str(e4); puts "e5 = " + str(e5); puts "e6 = " + str(e6); puts "e7 = " + str(e7); v1 = e1 + e3; puts "v1 = " + str(v1); #v2 = v1 + 5 * e7; #puts "v2 = " + str(v2); v3 = v1 - e1 - e3; puts "v3 = " + str(v3); puts; puts "------- Mat(QQ(),3,3) ---------"; r = Mat(QQ(),3,3); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); #puts [ str(g) for g in r.gens() ]; e11,e12,e13,e21,e22,e23,e31,e32,e33 = r.gens(); puts "e11 = " + str(e11); puts "e12 = " + str(e12); puts "e13 = " + str(e13); puts "e21 = " + str(e21); puts "e22 = " + str(e22); puts "e23 = " + str(e23); puts "e31 = " + str(e31); puts "e32 = " + str(e32); puts "e33 = " + str(e33); m1 = e11 + e31; puts "m1 = " + str(m1); m2 = m1 * m1 + 5*e22 + 9*e33; puts "m2 = " + str(m2); m3 = m2**3 - 125*e21 - 125*e23; puts "m3 = " + str(m3); m4 = 1/m2; puts "m4 = " + str(m4); mi = m2*m4; puts "mi = " + str(mi) + ", isONE: " + str(mi.one?); m5 = Mat(QQ(),3,3,v=[ [ 1, 0, 0 ], [ -125, 125, -125 ], [ 1, 0, 0 ] ]); puts "m5 = " + str(m5); m6 = m3 * m5; puts "m6 = " + str(m6); puts; puts "------- Mat(PolyRing(QQ(),\"x,y,z\",PolyRing.lex),3,3) ---------"; r = Mat(PolyRing.new(QQ(),"x,y,z",PolyRing.lex),3,3); puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); #puts [ str(g) for g in r.gens() ]; for g in r.gens() print "g = ", str(g), "\n"; end puts; m1 = r.random(5); puts "m1 = " + str(m1); m2 = r.one; #r.random(3); puts "m2 = " + str(m2); m3 = m1*m2 - m2*m1; puts "m3 = " + str(m3) + ", isZERO?: " + str(m3.zero?); puts; puts "------- PolyRing(Mat(QQ(),3,3),\"x,y,z\",PolyRing.lex) ---------"; r = PolyRing.new(Mat(QQ(),3,3),"x,y,z",PolyRing.lex); puts "r = " + str(r); for g in r.gens() print "g = ", str(g), "\n"; end puts; m1 = r.random(5); puts "m1 = " + str(m1); m2 = m1.monic(); puts "m2 = " + str(m2); m3 = m2.lc(); puts "m3 = " + str(m3) + ", isONE?: " + str(m3.one?); puts; puts "------- SolvPolyRing(QQ(),\"x,y,z\") ---------"; r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "r = " + str(r); pone,px,py,pz = r.gens(); puts "pone = " + str(pone); puts "px = " + str(px); puts "py = " + str(py); puts "pz = " + str(pz); rel = [ py, px, px * py - 1 , pz, py, py * pz - 1 ]; #puts "rel = " + str(rel); sr = SolvPolyRing.new(QQ(),"x,y,z",PolyRing.lex,rel); puts "sr = " + str(sr); one,x,y,z = sr.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts "one.factory() = " + str(one.factory()); s1 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; puts "s1 = " + str(s1); s2 = QQ(1,2) + QQ(2,3) * x + QQ(2,5) * y + ( x + y + z )**2; puts "s2 = " + str(s2); s3 = z**2 + 2 * y * z + 2 * x * z + y**2 + 2 * x * y + x**2 + QQ(2,5) * y + QQ(2,3) * x + QQ(1,2); puts "s3 = " + str(s3); s4 = s1 - s3; puts "s4 = " + str(s4); puts "s4.factory() = " + str(s4.factory()); sr1 = SolvPolyRing.new(QQ(),"x, y, z",PolyRing.lex,[( z ), ( y ), ( y * z - 1 ), ( y ), ( x ), ( x * y - 1 )]); puts "sr1 = " + str(sr1); s5 = z * y; puts "s5 = " + str(s5); s6 = s5**3; puts "s6 = " + str(s6); s7 = ( z * y )**3; puts "s7 = " + str(s7); s8 = s7 - s6; puts "s8 = " + str(s8); s9 = y**3 * z**3 - 3 * y**2 * z**2 + 3 * y * z - 1; puts "s9 = " + str(s9); s10 = s9 - s7; puts "s10 = " + str(s10); puts; puts "------- SubModule(PolyRing(QQ(),\"u, v, l\",PolyRing.lex) ---------"; p = PolyRing.new(QQ(),"u, v, l",PolyRing.lex); puts "p = " + str(p); one,u,v,l = p.gens(); puts "one = " + str(one); puts "u = " + str(u); puts "v = " + str(v); puts "l = " + str(l); m = CommutativeModule.new("",ring=p,cols=4); puts "m = " + str(m); for g in m.gens() print "g = ", str(g), "\n"; end m1 = [ 0, 1, l + v, 0 ] m2 = [ 0, v, u * l**2, 0 ] m3 = [ 0, l + 3 * v, 0, u ] m4 = [ 0, v * l + v**2, u**2, 0 ] m5 = [ 0, l**2, u, 0 ] m6 = [ 1, 0, 0, l**2 ] m7 = [ 1, 0, l + 3 * v, 0 ] m8 = [ 1, 2, 0, l**2 ] m9 = [ u, 0, 0, v * l + v**2 ] m10 = [ l + v, 0, 0, u ] m11 = [ l**2, 0, 0, v ] m12 = [ l**2, 0, 2 * u,v ] ml = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12]; #ml= [ [ 0, 1, l + v, 0 ], [ 0, v, u * l**2, 0 ], [ 0, l + 3 * v, 0, u ], [ 0, v * l + v**2, u**2, 0 ], [ 0, l**2, u, 0 ], [ 1, 0, 0, l**2 ], [ 1, 0, l + 3 * v, 0 ], [ 1, 2, 0, l**2 ], [ u, 0, 0, v * l + v**2 ], [ l + v, 0, 0, u ], [ l**2, 0, 0, v ], [ l**2, 0, 2 * u,v ] ]; #puts "ml = " + str(ml); #puts; sm = m.submodul("",list=ml); #sm = SubModule(m,list=ml); puts "sm = " + str(sm); xm = SubModule.new(PolyRing.new(QQ(),"u, v, l",PolyRing.lex),"",list=[ [ 0, 1, ( l + v ), 0 ], [ 0, v, u * l**2, 0 ], [ 0, ( l + 3 * v ), 0, u ], [ 0, ( v * l + v**2 ), u**2, 0 ], [ 0, l**2, u, 0 ], [ 1, 0, 0, l**2 ], [ 1, 0, ( l + 3 * v ), 0 ], [ 1, 2, 0, l**2 ], [ u, 0, 0, ( v * l + v**2 ) ], [ ( l + v ), 0, 0, u ], [ l**2, 0, 0, v ], [ l**2, 0, 2 * u, v ] ]) # SubModule(PolyRing.new(QQ(),"u, v, l",PolyRing.lex),list=( ( 0, 1, ( l + v ), 0 ), ( 0, v, u * l**2, 0 ), ( 0, ( l + 3 * v ), 0, u ), ( 0, ( v * l + v**2 ), u**2, 0 ), ( 0, l**2, u, 0 ), ( 1, 0, 0, l**2 ), ( 1, 0, ( l + 3 * v ), 0 ), ( 1, 2, 0, l**2 ), ( u, 0, 0, ( v * l + v**2 ) ), ( ( l + v ), 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, 2 * u, v ) )) # SubModule(PolyRing.new(QQ(),"u, v, l",PolyRing.lex),list=( ( 0, (1,), l + v, 0 ), ( 0, v, u * l**2, 0 ), ( 0, l + (3,) * v, 0, u ), ( 0, v * l + v**2, u**2, 0 ), ( 0, l**2, u, 0 ), ( (1,), 0, 0, l**2 ), ( (1,), 0, l + (3,) * v, 0 ), ( (1,), (2,), 0, l**2 ), ( u, 0, 0, v * l + v**2 ), ( l + v, 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, (2,) * u, v ) )); # SubModule(PolyRing.new(QQ(),"u, v, l",PolyRing.lex),list=( ( 0, (1,), l + v, 0 ), ( 0, v, u * l**2, 0 ), ( 0, l + (3,) * v, 0, u ), ( 0, v * l + v**2, u**2, 0 ), ( 0, l**2, u, 0 ), ( (1,), 0, 0, l**2 ), ( (1,), 0, l + (3,) * v, 0 ), ( (1,), (2,), 0, l**2 ), ( u, 0, 0, v * l + v**2 ), ( l + v, 0, 0, u ), ( l**2, 0, 0, v ), ( l**2, 0, (2,) * u, v ) )); puts "xm = " + str(xm); puts; ## rg = sm.GB(); ## puts "rg: " + str(rg); ## puts "isGB: " + str(rg.isGB()); ## puts; puts "------- SolvableSubModule(SolvPolyRing(CC(),\"X,Y,x,y\")) ---------"; r = PolyRing.new(CC(),"X,Y,x,y",PolyRing.lex); puts "r = " + str(r); pone,pi,pX,pY,px,py = r.gens(); puts "pone = " + str(pone); puts "pi = " + str(pi); puts "pX = " + str(pX); puts "pY = " + str(pY); puts "px = " + str(px); puts "py = " + str(py); #rel = ( py, px, px * py - 1 , pz, py, py * pz - 1 ); rel = [ py, px, pi * px * py, pY, pX, pi * pY * pX ]; print "rel = ", rel.map { |z| z.to_s + ", " }, "\n"; #print "rel = ", rel.to_s, "\n"; sr = SolvPolyRing.new(CC(),"X,Y,x,y",PolyRing.lex,rel); puts "sr = " + str(sr); one,i,X,Y,x,y = sr.gens(); puts "one = " + str(one); puts "i = " + str(i); puts "X = " + str(X); puts "Y = " + str(Y); puts "x = " + str(x); puts "y = " + str(y); m1 = [ ( x + 1 ), ( y ) ] m2 = [ ( x * y ), ( 0 ) ] m3 = [ ( x - X ), ( x - X ) ] m4 = [ ( y - Y ), ( y - Y ) ] ml = [m1,m2,m3,m4]; #puts "ml = " + str(ml); ssm = SolvableSubModule.new( sr, "", list=ml ); puts "ssm: " + str(ssm); puts; xsm = SolvableSubModule.new(SolvPolyRing.new(CC(),"X, Y, x, y",PolyRing.lex,rel=[y, x, ( CC(0,1) * x * y ), Y, X, ( CC(0,1) * X * Y )]),"",list=[ [ x - X, x - X ], [ x + CC(1), y ], [ y - Y, y - Y ], [ x * y, 0 ] ]); # SolvableSubModule(SolvPolyRing.new(CC(),"X, Y, x, y",PolyRing.lex,rel=(y, x, ( ((0,),(1,)) * x * y ), Y, X, ( ((0,),(1,)) * X * Y )]),list=[ ( x - X, x - X ), ( x + ((1,),), y ), ( y - Y, y - Y ), ( x * y, 0 ) )); # SolvableSubModule(SolvPolyRing.new(CC(),"X, Y, x, y",PolyRing.lex,(( y ), ( x ), ( ((0,),(1,)) * x * y ),( Y ), ( X ), ( ((0,),(1,)) * X * Y ))),list=( ( x - X, x - X ), ( x + ((1,),), y ), ( y - Y, y - Y ), ( x * y, 0 ) )); puts "xsm: " + str(xsm); puts; mlg = ssm.leftGB(); puts "mlg: " + str(mlg); puts; mtg = ssm.twosidedGB(); puts "mtg: " + str(mtg); puts; #puts "------------------------------------"; #puts "globals() = " + str(globals()); terminate(); #puts "globals() = " + str(globals()); #puts "locals() = " + str(locals()); #puts "vars() = " + str(vars()); #terminate(); #__END__ #to_skip = < gmul*tau.lm(): p = self.new_pair(rmul*sigma,r,g,G) else: p = self.new_pair(gmul*tau,g,r,G) if p[0].degree() == sigma.degree(): S.append(p) else: P.add(p) G.append((sigma,r)) Done.append((sigma,r)) elif r == 0: #print "zero reduction at", (sigma,r.lm()) self.update_Syz(Syz,sigma,r) Done.append((sigma,r)) #else: #print "sig-redundant at", sigma return list(self.subset(G,lambda x: x[1] != 0)) class ggv(sigbased_gb): # the plugin implementation of ggv def new_pair(self,sig,p,q,G): # creates a new critical pair from p and q, with signature sig # it needs G for the sake of F5; see derived class below i = -1; j = -1; k = 0 up,uq = self.spoly_multipliers(p,q) while (i<0 or j<0) and k < len(G): if p == G[k][1]: i = k elif q == G[k][1]: j = k k += 1; if (i == -1): i=len(G) elif (j == -1): j = len(G) return (sig,i,j) def initialize_Syz(self,F,G): # recognize trivial syzygies return set([f.lm() for f in F]) def spoly(self,s,G): # ggv only computes part of an S-polynomial # (as if it were computing a row of the Macaulay matrix # and not subsequently triangularizing) f = G[s[1]][1]; g = G[s[2]][1] tf = f.lm(); tg = g.lm() tfg = tf.lcm(tg) uf = self.R.monomial_quotient(tfg,tf) return uf*f def prune_P(self,P,Syz): # remove any pair whose signature is divisible by an element of Syz result = set() R = self.R for p in P: if not any(R.monomial_divides(t,p[0]) for t in Syz): result.add(p) return result def prune_S(self,S,Syz,Done,G): # watch out for new syzygies discovered, and allow only one polynomial # per signature result = list() R = self.R for s in S: if not any(R.monomial_divides(t,s[0]) for t in Syz): if not any(s[0].lm()==sig[0].lm() and s[1]sig[1].lm() for sig in S): for (sig,f) in Done: if self.R.monomial_divides(sig,s[0]): u = self.R.monomial_quotient(s[0],sig) if u*f.lm() < s[1].lm(): break else: result.append(s) return result def new_pair(self,sig,p,q,G): # in arri's algorithm, each pair is (sigma,s) where s is the s-polynomial # and sigma is its natural signature tp = p.lm(); tq = q.lm() tpq = tp.lcm(tq) R = p.parent() #JAS tpq.parent() up = R.monomial_quotient(tpq,tp); uq = R.monomial_quotient(tpq,tq) return (sig,up*p-uq*q) def spoly(self,s,G): return s[1] class f5(coeff_free_sigbased_gb): # the plugin implementation of arri's algorithm def initialize_Syz(self,F,G): # recognize trivial syzygies return set([f.lm() for f in F]) def update_Syz(self,Syz,sigma,r): # recognize trivial syzygies # see class f5z for a more thorough update_Syz in line w/arri and ggv return Syz def prune_P(self,P,Syz): # remove any pair whose signature is divisible by an element of Syz result = set() for p in P: if not any(self.R.monomial_divides(t,p[0]) for t in Syz): result.add(p) return result def prune_S(self,S,Syz,Done,G): # watch out for new syzygies discovered, and apply faugere's rewritable criterion: # for any (sigma,p,q) in S, if there exists (tau,g) such that tau divides sigma # but g was generated after p, discard (sigma,p,q) result = list() for (sig,u,j,v,k) in S: if not any(self.R.monomial_divides(t,sig) for t in Syz): if G[j][0] == 0 or not any(self.R.monomial_divides(Done[i][0],G[j][0]*u) and Done[i][0] > G[j][0] for i in xrange(len(Done))): result.append((sig,u,j,v,k)) return result def new_pair(self,sig,p,q,G): # it's easier to deal with faugere's criterion if one creates pairs # using indices rather than polynomials # note that this while look gives f5 a disadvantage i = -1; j = -1; k = 0 up,uq = self.spoly_multipliers(p,q) while (i<0 or j<0) and k < len(G): if p == G[k][1]: i = k elif q == G[k][1]: j = k k += 1; if (i == -1): i=len(G) elif (j == -1): j = len(G) return (sig,up,i,uq,j) def spoly(self,s,G): # since s has the structure (sigma,up,i,uq,j) # we have to compute the s-polynomial by looking up f and g f = G[s[2]][1]; g = G[s[4]][1] uf = s[1]; ug = s[3] return uf*f - ug*g class f5z(f5): def update_Syz(self,Syz,sigma,r): # recognize trivial syzygies if r == 0: Syz.add(sigma.lm()) return Syz class min_size_mons(arris_algorithm): # the plugin implementation of arri's algorithm def prune_S(self,S,Syz,Done,G): # watch out for new syzygies discovered, and apply the minimal "number of monomials" criterion: # for any s-polynomial of a given signature, if there exists another polynomial # in Done of identical signature but fewer monomials, replace this s-polynomial # by the multiple of the polynomial with fewer monomials result = list() R = G[0][1].parent() for (sigma,s) in S: if not any(R.monomial_divides(tau,sigma) for tau in Syz): if not any(tau == sigma for (tau,g) in result): for (tau,g) in Done: if tau.divides(sigma) and len(g.monomials()) < len(s.monomials()): u = R.monomial_quotient(sigma,tau) result.append((u*tau,u*g)) break else: result.append((sigma,s)) return result java-algebra-system-2.7.200/examples/boolean_cgb.py000066400000000000000000000021261445075545500221610ustar00rootroot00000000000000import sys; from jas import Ring, PolyRing, ParamIdeal, QQ, ZM, RR from jas import startLog, terminate # Boolean coefficient boolean GB # see S. Inoue and A. Nagai "On the Implementation of Boolean Groebner Bases" in ASCM 2009 # Z_2 regular ring coefficent example r = PolyRing(RR(ZM(2),3),"a,x,y",PolyRing.lex); print "r = " + str(r); #print len(r.gens()) [s1,s2,s3,a,x,y] = r.gens(); one = r.one(); print "one = " + str(one); print "s1 = " + str(s1); print "s2 = " + str(s2); print "s3 = " + str(s3); print "a = " + str(a); print "x = " + str(x); print "y = " + str(y); #brel = [ a**2 - a, x**2 - x, y**2 - y ]; brel = [ x**2 - x, y**2 - y ]; #print "brel = " + str(brel[0]) + ", " + str(brel[1]) + ", " + str(brel[2]); print "brel = " + str(brel[0]) + ", " + str(brel[1]); pl = [ ( one + s1 + s2 ) * ( x*y + x + y ), s1 * x + s1, a * y + a, x * y ]; pl = pl + brel; startLog(); f = ParamIdeal(r,list=pl); print "Ideal: " + str(f); gb = f.regularGB(); print "boolean GB: " + str(gb); #ss = gb.stringSlice(); #print "regular string slice: " + str(ss); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/boolean_cgb.rb000066400000000000000000000020401445075545500221270ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Boolean coefficient boolean GB # see S. Inoue and A. Nagai "On the Implementation of Boolean Groebner Bases" in ASCM 2009 # Z_2 regular ring coefficent example r = PolyRing.new(RR(ZM(2),3),"a,x,y",PolyRing.lex); puts "r = " + str(r); #puts len(r.gens()) s1,s2,s3,a,x,y = r.gens(); one = r.one(); puts "one = " + str(one); puts "s1 = " + str(s1); puts "s2 = " + str(s2); puts "s3 = " + str(s3); puts "a = " + str(a); puts "x = " + str(x); puts "y = " + str(y); #brel = [ a**2 - a, x**2 - x, y**2 - y ]; brel = [ x**2 - x, y**2 - y ]; #puts "brel = " + str(brel[0]) + ", " + str(brel[1]) + ", " + str(brel[2]); puts "brel = " + str(brel[0]) + ", " + str(brel[1]); pl = [ ( one + s1 + s2 ) * ( x*y + x + y ), s1 * x + s1, a * y + a, x * y ]; pl = pl + brel; startLog(); f = ParamIdeal.new(r,"",pl); puts "Ideal: " + str(f); gb = f.regularGB(); puts "boolean GB: " + str(gb); #ss = gb.stringSlice(); #puts "regular string slice: " + str(ss); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/boolean_gb.py000066400000000000000000000020061445075545500220130ustar00rootroot00000000000000import sys; from jas import Ring, PolyRing, ParamIdeal, QQ, ZM, RR from jas import startLog, terminate # Boolean coefficient boolean GB # see S. Inoue and A. Nagai "On the Implementation of Boolean Groebner Bases" in ASCM 2009 # Z_2 regular ring coefficent example r = PolyRing(RR(ZM(2),3),"x,y",PolyRing.lex); print "r = " + str(r); #print len(r.gens()) [s1,s2,s3,x,y] = r.gens(); one = r.one(); print "one = " + str(one); print "s1 = " + str(s1); print "s2 = " + str(s2); print "s2 = " + str(s3); print "x = " + str(x); print "y = " + str(y); brel = [ x**2 - x, y**2 - y ]; print "brel = " + str(brel[0]) + ", " + str(brel[1]); pl = [ ( one + s1 + s2 ) * ( x*y + x +y ), s1 * x + s1, s2 * y + s2, x * y ]; #pl = [ ( one ) * ( x*y + x +y ), s1 * x + s1, s2 * y + s2, x * y ]; pl = pl + brel; startLog(); f = ParamIdeal(r,list=pl); print "Ideal: " + str(f); gb = f.regularGB(); print "boolean GB: " + str(gb); #ss = gb.stringSlice(); #print "regular string slice: " + str(ss); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/boolean_gb.rb000066400000000000000000000017231445075545500217730ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Boolean coefficient boolean GB # see S. Inoue and A. Nagai "On the Implementation of Boolean Groebner Bases" in ASCM 2009 # Z_2 regular ring coefficent example r = PolyRing.new(RR(ZM(2),3),"x,y",PolyRing.lex); puts "r = " + str(r); #puts len(r.gens()) s1,s2,s3,x,y = r.gens(); one = r.one(); puts "one = " + str(one); puts "s1 = " + str(s1); puts "s2 = " + str(s2); puts "s2 = " + str(s3); puts "x = " + str(x); puts "y = " + str(y); brel = [ x**2 - x, y**2 - y ]; puts "brel = " + str(brel[0]) + ", " + str(brel[1]); pl = [ ( one + s1 + s2 ) * ( x*y + x + y ), s1 * x + s1, s2 * y + s2, x * y ]; #pl = [ ( one ) * ( x*y + x + y ), s1 * x + s1, s2 * y + s2, x * y ]; pl = pl + brel; startLog(); f = ParamIdeal.new(r,"",pl); puts "Ideal: " + str(f); gb = f.regularGB(); puts "boolean GB: " + str(gb); #ss = gb.stringSlice(); #puts "regular string slice: " + str(ss); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/bueso_quantum.py000066400000000000000000000021171445075545500226160ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import PolyRing, SolvPolyRing, QQ, RF, terminate # Bueso, Torrecillas, Lobillo, Castro: example 4.4.9, SAC Newsletter 1996 r = PolyRing(QQ(),"q"); #is automatic: one,q = r.gens(); rq = RF(r); print "r = " + str(r); print "rq = " + str(rq); # f < k < l < e rp = PolyRing(rq,"f,k,l,e", PolyRing.lex); print "rp = " + str(rp); relations = [ e, k, one/(q**2) * k * e, e, l, q**2 * l * e, k, f, one/(q**2) * f * k, l, f, q**2 * f * l, e, f, f * e + (k**2 - l**2)/(q**2 - one/(q**2)) ]; #commutative l, k, k * l print "relations = ", [ str(f) for f in relations ]; rs = SolvPolyRing(rq, "f,k,l,e", PolyRing.lex, relations); print "rs: " + str(rs); print "gens() = ", [ str(f) for f in rs.gens() ]; p = k * l - 1; pl = [p]; ts = rs.ideal("", pl); print "ts = " + str(ts); tsg = ts.twosidedGB(); print "twosided GB: " + str(tsg); print "isTwosidedGB: " + str(tsg.isTwosidedGB()); d = tsg.dimension(); print "d = " + str(d); print; terminate(); #exit; java-algebra-system-2.7.200/examples/bueso_quantum.rb000066400000000000000000000021341445075545500225700ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Bueso, Torrecillas, Lobillo, Castro: example 4.4.9, SAC Newsletter 1996 r = PolyRing.new(QQ(),"q"); #is automatic: one,q = r.gens(); rq = RF(r); puts "r = " + str(r); puts "rq = " + str(rq); # f < k < l < e rp = PolyRing.new(rq,"f,k,l,e", PolyRing.lex); puts "rp = " + str(rp); relations = [ e, k, one/(q**2) * k * e, e, l, q**2 * l * e, k, f, one/(q**2) * f * k, l, f, q**2 * f * l, e, f, f * e + (k**2 - l**2)/(q**2 - one/(q**2)) ]; #commutative l, k, k * l puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; rs = SolvPolyRing.new(rq, "f,k,l,e", PolyRing.lex, relations); puts "rs: " + str(rs); puts "gens = " + rs.gens().join(", ") { |r| r.to_s }; #p = (k * l)**2 - k * l - 1; p = k * l - 1; pl = [p]; ts = rs.ideal("", pl); puts "ts = " + str(ts); tsg = ts.twosidedGB(); puts "twosided GB: " + str(tsg); puts "isTwosidedGB: " + str(tsg.isTwosidedGB()); d = tsg.dimension(); puts "d = " + str(d); puts; terminate(); #exit; java-algebra-system-2.7.200/examples/cgb_0.py000066400000000000000000000017571445075545500207120ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import ZZ, Ring, PolyRing from jas import ParamIdeal from jas import startLog from jas import terminate # simple example for comprehensive GB # integral/rational function coefficients #r = Ring( "IntFunc(u,v) (x,y) L" ); r = PolyRing( PolyRing(ZZ(),"(u,v)",PolyRing.lex),"(x,y)", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( { v } x y + x ), ( { u } y^2 + x^2 ) ) """; p1 = v * x * y + x; p2 = u * y**2 + x**2; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); print "ParamIdeal: " + str(f); print; #sys.exit(); #startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); #startLog(); gs = f.CGB(); print "CGB: " + str(gs); print; #startLog(); bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cgb_0.rb000066400000000000000000000014701445075545500206550ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # simple example for comprehensive GB # integral/rational function coefficients #r = Ring( "IntFunc(u,v) (x,y) L" ); r = PolyRing.new( PolyRing.new(ZZ(),"(u,v)",PolyRing.lex),"(x,y)", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( { v } x y + x ), ( { u } y^2 + x^2 ) ) """; p1 = v * x * y + x; p2 = u * y**2 + x**2; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); #startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); #bg = gs.isCGBsystem(); #puts "isCGBsystem: " + str(bg); #puts; #sys.exit(); #startLog(); gs = f.CGB(); puts "CGB: " + str(gs); puts; #startLog(); #bg = gs.isCGB(); #puts "isCGB: " + str(bg); #puts; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cgb_2.py000066400000000000000000000021401445075545500206770ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import ZZ, Ring, PolyRing from jas import ParamIdeal from jas import startLog from jas import terminate # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients #r = Ring( "IntFunc(a2, a1, a0, b2, b1, b0) (x) L" ); r = PolyRing( PolyRing(ZZ(),"(a2, a1, a0, b2, b1, b0)",PolyRing.lex),"(x)", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( { a2 } x^2 + { a1 } x + { a0 } ), ( { b2 } x^2 + { b1 } x + { b0 } ) ) """; p1 = a2 * x**2 + a1 * x + a0; p2 = b2 * x**2 + b1 * x + b0; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); print "ParamIdeal: " + str(f); print; #sys.exit(); #startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; terminate(); sys.exit(); bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cgb_2.rb000066400000000000000000000016541445075545500206630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients #r = Ring.new( "IntFunc(a2, a1, a0, b2, b1, b0) (x) L" ); r = PolyRing.new( PolyRing.new(ZZ(),"(a2, a1, a0, b2, b1, b0)",PolyRing.lex),"(x)", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( { a2 } x^2 + { a1 } x + { a0 } ), ( { b2 } x^2 + { b1 } x + { b0 } ) ) """; p1 = a2 * x**2 + a1 * x + a0; p2 = b2 * x**2 + b1 * x + b0; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); #startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); puts "isCGBsystem: " + str(bg); puts; #sys.exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; terminate(); #sys.exit(); #bg = gs.isCGB(); #puts "isCGB: " + str(bg); #puts; #terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cgb_3.py000066400000000000000000000022431445075545500207040ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import ZZ, Ring, PolyRing from jas import ParamIdeal from jas import startLog from jas import terminate # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients #r = Ring( "IntFunc(a3, b3, a2, b2, a1, b1, a0, b0) (x) L" ); r = PolyRing( PolyRing(ZZ(),"(a3, b3, a2, b2, a1, b1, a0, b0)",PolyRing.lex),"(x)", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( { a3 } x^3 + { a2 } x^2 + { a1 } x + { a0 } ), ( { b3 } x^3 + { b2 } x^2 + { b1 } x + { b0 } ) ) """; p1 = a3 * x**3 + a2 * x**2 + a1 * x + a0; p2 = b3 * x**3 + b2 * x**2 + b1 * x + b0; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); print "ParamIdeal: " + str(f); print; #sys.exit(); # long run time startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; terminate(); sys.exit(); bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/cgb_3.rb000066400000000000000000000017411445075545500206610ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients #r = Ring.new( "IntFunc(a3, b3, a2, b2, a1, b1, a0, b0) (x) L" ); r = PolyRing.new( PolyRing.new(ZZ(),"(a3, b3, a2, b2, a1, b1, a0, b0)",PolyRing.lex),"(x)", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( { a3 } x^3 + { a2 } x^2 + { a1 } x + { a0 } ), ( { b3 } x^3 + { b2 } x^2 + { b1 } x + { b0 } ) ) """; p1 = a3 * x**3 + a2 * x**2 + a1 * x + a0; p2 = b3 * x**3 + b2 * x**2 + b1 * x + b0; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2] ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); # long run time startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); puts "isCGBsystem: " + str(bg); puts; #sys.exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; #sys.exit(); #bg = gs.isCGB(); #puts "isCGB: " + str(bg); #puts; terminate(); java-algebra-system-2.7.200/examples/cgb_4.py000066400000000000000000000021441445075545500207050ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, ParamIdeal, QQ from jas import startLog from jas import terminate # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients rp = PolyRing(QQ(), "a" ); r = PolyRing( rp, "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; #is automatic: one,a,x,y,z = r.gens(); #f1 = x * ( x**2 + a * y + b ); #f2 = x * ( y**2 + b * x + a ); f1 = ( x**2 + a * y**2 - x ); f2 = ( a * x**2 + y**2 - y ); f3 = ( x - y ) * z - 1; print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); f = r.paramideal( "", list=[f1,f2,f3] ); print "ParamIdeal: " + str(f); print; #sys.exit(); # long run time startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; terminate(); sys.exit(); bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/cgb_4.rb000066400000000000000000000015441445075545500206630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # 2 univariate polynomials of degree 2 example for comprehensive GB # integral/rational function coefficients r = PolyRing.new( PolyRing.new(QQ(),"a",PolyRing.lex),"x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts; #puts "gens: " + str(r.gens()); f1 = ( x**2 + a * y**2 - x ); f2 = ( a * x**2 + y**2 - y ); f3 = ( x - y ) * z - 1; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); f = r.paramideal( "", list=[f1,f2,f3] ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); # long run time startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); puts "isCGBsystem: " + str(bg); puts; #sys.exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; #sys.exit(); #bg = gs.isCGB(); #puts "isCGB: " + str(bg); #puts; terminate(); java-algebra-system-2.7.200/examples/cgbmmn15.py000066400000000000000000000026761445075545500213520ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, PolyRing from jas import startLog from jas import terminate # rational function coefficients # IP (alpha,beta,gamma,epsilon,theta,eta) # (c3,c2,c1) /G/ #r = Ring( "IntFunc(alpha,beta,gamma,epsilon,theta,eta)(c3,c2,c1) G" ); # ( { alpha } c1 - { beta } c1**2 - { gamma } c1 c2 + { epsilon } c3 ), # ( - { gamma } c1 c2 + { epsilon + theta } c3 - { gamma } c2 ), # ( { gamma } c2 c3 + { eta } c2 - { epsilon + theta } c3 ) #r = Ring( "IntFunc(a,b,g,e,t,eta)(c3,c2,c1) G" ); r = PolyRing( PolyRing(QQ(),"(a,b,g,e,t,eta)", PolyRing.lex), "(c3,c2,c1)", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( { a } c1 - { b } c1**2 - { g } c1 c2 + { e } c3 ), ( - { g } c1 c2 + { e + t } c3 - { g } c2 ), ( { g } c2 c3 + { eta } c2 - { e + t } c3 ) ) """; p1 = a * c1 - b * c1**2 - g * c1 * c2 + e * c3; p2 = - g * c1 * c2 + (e + t) * c3 - g * c2; p3 = g * c2 * c3 + eta * c2 - (e + t) * c3; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2,p3] ); print "ParamIdeal: " + str(f); print; #sys.exit(); startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; terminate(); sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cgbmmn15.rb000066400000000000000000000024441445075545500213160ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # rational function coefficients # IP (alpha,beta,gamma,epsilon,theta,eta) # (c3,c2,c1) /G/ #r = Ring( "IntFunc(alpha,beta,gamma,epsilon,theta,eta)(c3,c2,c1) G" ); # ( { alpha } c1 - { beta } c1**2 - { gamma } c1 c2 + { epsilon } c3 ), # ( - { gamma } c1 c2 + { epsilon + theta } c3 - { gamma } c2 ), # ( { gamma } c2 c3 + { eta } c2 - { epsilon + theta } c3 ) #r = Ring.new( "IntFunc(a,b,g,e,t,eta)(c3,c2,c1) G" ); r = PolyRing.new( PolyRing.new(QQ(),"(a,b,g,e,t,eta)", PolyRing.lex), "(c3,c2,c1)", PolyRing.grad ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } c1 - { b } c1**2 - { g } c1 c2 + { e } c3 ), ( - { g } c1 c2 + { e + t } c3 - { g } c2 ), ( { g } c2 c3 + { eta } c2 - { e + t } c3 ) ) """; p1 = a * c1 - b * c1**2 - g * c1 * c2 + e * c3; p2 = - g * c1 * c2 + (e + t) * c3 - g * c2; p3 = g * c2 * c3 + eta * c2 - (e + t) * c3; #f = r.paramideal( ps ); f = r.paramideal( "", [p1,p2,p3] ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); #bg = gs.isCGBsystem(); #puts "isCGBsystem: " + str(bg); #puts; #sys.exit(); #gs = f.CGB(); #puts "CGB: " + str(gs); #puts; #bg = gs.isCGB(); #puts "isCGB: " + str(bg); #puts; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/charset.py000066400000000000000000000017241445075545500213630ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Ideal from jas import QQ, ZZ from jas import startLog, terminate # characteristic set example Circle of Apollonius, from CLO IVA r = PolyRing( QQ(), "u1,u2,x1,x2,x3,x4,x5,x6,x7,x8", PolyRing.lex ); print "Ring: " + str(r); print; #[one,u1,u2,x1,x2,x3,x4,x5,x6,x7,x8] = r.gens(); h1 = 2 * x1 - u1; h2 = 2 * x2 - u2; h3 = 2 * x3 - u1; h4 = 2 * x4 - u2; h5 = u2 * x5 + u1 * x6 - u1 * u2; h6 = u1 * x5 - u2 * x6; h7 = x1**2 - x2**2 - 2 * x1 * x7 + 2 * x2 * x8; h8 = x1**2 - 2 * x1 * x7 - x3**2 + 2 * x3 * x7 - x4**2 + 2 * x4 * x8; g = ( ( x5 - x7 )**2 + ( x6 - x8 )**2 - ( x1 - x7 )**2 - x8**2 ); L = [h1,h2,h3,h4,h5,h6,h7,h8]; #print "L = ", str(L); f = r.ideal( list=L ); print "Ideal: " + str(f); print; #sys.exit(); startLog(); c = f.CS(); print "seq char set:", c; print "is char set:", c.isCS(); print; print "g:", g; print; h = c.csReduction(g); print "h:", h; print; #sys.exit(); java-algebra-system-2.7.200/examples/charset.rb000066400000000000000000000016561445075545500213420ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # characteristic set example Circle of Apollonius, from CLO IVA r = PolyRing.new( QQ(),"u1,u2,x1,x2,x3,x4,x5,x6,x7,x8",PolyRing.lex ); puts "Ring: " + str(r); puts; #one,u1,u2,x1,x2,x3,x4,x5,x6,x7,x8 = r.gens(); #h3 = 2 * x3 - u3; typo #h4 = 2 * x4 - u4; h1 = 2 * x1 - u1; h2 = 2 * x2 - u2; h3 = 2 * x3 - u1; h4 = 2 * x4 - u2; h5 = u2 * x5 + u1 * x6 - u1 * u2; h6 = u1 * x5 - u2 * x6; h7 = x1**2 - x2**2 - 2 * x1 * x7 + 2 * x2 * x8; h8 = x1**2 - 2 * x1 * x7 - x3**2 + 2 * x3 * x7 - x4**2 + 2 * x4 * x8; g = ( ( x5 - x7 )**2 + ( x6 - x8 )**2 - ( x1 - x7 )**2 - x8**2 ); L = [h1,h2,h3,h4,h5,h6,h7,h8]; #print "L = ", str(L); f = r.ideal( "", L ); puts "Ideal: " + str(f); puts; startLog(); cc = f.CS(); puts "seq char set: " + str(cc); puts "is char set: " + str(cc.isCS()); puts; puts "g: " + str(g); puts; h = cc.csReduction(g); puts "h: " + str(h); puts; #sys.exit(); java-algebra-system-2.7.200/examples/chebyshev.py000066400000000000000000000010701445075545500217040ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, ZZ from jas import startLog # chebyshev polynomial example # T(0) = 1 # T(1) = x # T(n) = 2 * x * T(n-1) - T(n-2) #r = Ring( "Z(x) L" ); r = PolyRing(ZZ(), "(x)", PolyRing.lex ); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring #is automatic: [one,x] = r.gens(); x2 = 2 * x; N = 10; T = [one,x]; for n in range(2,N+1): t = x2 * T[n-1] - T[n-2]; T.append( t ); for n in range(0,N+1): print "T[%s] = %s" % (n,T[n]); print; #sys.exit(); java-algebra-system-2.7.200/examples/chebyshev.rb000066400000000000000000000007731445075545500216700ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # chebyshev polynomial example # T(0) = 1 # T(1) = x # T(n) = 2 * x * T(n-1) - T(n-2) #r = Ring.new( "Z(x) L" ); r = PolyRing.new( ZZ(), "(x)", PolyRing.lex ); puts "Ring: " + str(r); puts; # sage like: with generators for the polynomial ring #is automatic: one,x = r.gens(); x2 = 2 * x; N = 10; T = [one,x]; for n in 2..N t = x2 * T[n-1] - T[n-2]; T[n] = t; end for n in 0..N puts "T[#{n}] = #{T[n]}"; end puts; #sys.exit(); java-algebra-system-2.7.200/examples/contFrac.py000066400000000000000000000020511445075545500214630ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, ZZ, QQ, RealN, CC, ZM, RF, terminate from edu.jas.root import RealArithUtil from edu.jas.arith import ArithUtil # example for rational and real algebraic numbers # # # continued fractions: r = PolyRing(QQ(),"alpha",PolyRing.lex); print "r = " + str(r); e,a = r.gens(); print "e = " + str(e); print "a = " + str(a); sqrt2 = a**2 - 2; print "sqrt2 = " + str(sqrt2); Qs2r = RealN(sqrt2,[1,[3,2]],a-1); #Qs2r = RealN(sqrt2,[-2,-1],a+1); print "Qs2r = " + str(Qs2r.factory()) + " :: " + str(Qs2r.elem); one,alpha = Qs2r.gens(); print "one = " + str(one); print "alpha = " + str(alpha); cf = Qs2r.contFrac(20); print "cf = " + str(cf); nb = Qs2r.contFracApprox(cf); print "nb = " + str(nb) + " ~= " + str(nb.elem.getDecimal()); cf = nb.contFrac(0); print "cf = " + str(cf); nb = nb.contFracApprox(cf); print "nb = " + str(nb) + " ~= " + str(nb.elem.getDecimal()); nb = nb.contFracApprox(None); print "nb = " + str(nb.signum() == 0); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/contFrac.rb000066400000000000000000000016331445075545500214430ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example for rational and real algebraic numbers # # # continued fractions: r = PolyRing.new(QQ(),"alpha",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); sqrt2 = a**2 - 2; puts "sqrt2 = " + str(sqrt2); Qs2r = RealN(sqrt2,[1,3/2],a-1); #Qs2r = RealN(sqrt2,[-2,-1],a+1); puts "Qs2r = " + str(Qs2r.factory()) + " :: " + str(Qs2r.elem); one,alpha = Qs2r.gens(); puts "one = " + str(one); puts "alpha = " + str(alpha); cf = Qs2r.contFrac(20); puts "cf = " + str(cf); nb = Qs2r.contFracApprox(cf); puts "nb = " + str(nb) + " ~= " + str(nb.elem.getDecimal()); cf = nb.contFrac(0); puts "cf = " + str(cf); nb = nb.contFracApprox(cf); puts "nb = " + str(nb) + " ~= " + str(nb.elem.getDecimal()); nb = nb.contFracApprox(nil); puts "nb = " + str(nb.signum == 0); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/cyclic.py000066400000000000000000000051041445075545500211740ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, RingElem, Ideal, PolyRing, GF, Order; from basic_sigbased_gb import ggv_first_implementation, arris_algorithm, f5z; from staggered_linear_basis import staglinbasis from edu.jas.gb import Cyclic; # cyclic examples knum = 5; tnum = 2; k = Cyclic(knum); #r = Ring( "", k.ring ); #r = PolyRing( GF(23), k.ring.vars, Order.IGRLEX ); r = PolyRing( GF(32003), k.ring.vars, Order.IGRLEX ); #r = PolyRing( GF(536870909), k.ring.vars, Order.IGRLEX ); #r = PolyRing( GF(4294967291), k.ring.vars, Order.IGRLEX ); #r = PolyRing( GF(9223372036854775783), k.ring.vars, Order.IGRLEX ); #r = PolyRing( GF(170141183460469231731687303715884105727), k.ring.vars, Order.IGRLEX ); print "Ring: " + str(r); print; ps = k.polyList(); #ps = k.cyclicPolys(); print "ps = " + str(ps); f = r.ideal( ps ); print "Ideal: " + str(f); print; if False: rg = f.parGB(tnum); for th in range(tnum,0,-1): rg = f.parGB(th); #print "par Output:", rg; #print; rg = f.GB(); #print "seq Output:", rg; print; arri = arris_algorithm(); ggv1 = ggv_first_implementation(); ff5 = f5z(); F = [ RingElem(e) for e in f.list ]; print "F:", str([ str(e) for e in F]); print; if False: ##gg = staglinbasis(F); #gg = staglinbasis(F); t = System.currentTimeMillis(); gg = staglinbasis(F); t = System.currentTimeMillis() - t; print "stag executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "stag no GB"; print "stag Output:" + str([ str(ggg) for ggg in gg]); print; if False: #gg = ff5.basis_sig(F); t = System.currentTimeMillis(); gg = ff5.basis_sig(F); t = System.currentTimeMillis() - t; print "f5 executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "f5 no GB"; print "f5 Output:" + str([ str(ggg) for ggg in gg]); print; if True: #gg = ggv1.basis_sig(F); t = System.currentTimeMillis(); gg = ggv1.basis_sig(F); t = System.currentTimeMillis() - t; print "ggv executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "ggv1 no GB"; print "ggv1 Output:" + str([ str(ggg) for ggg in gg]); print; if False: #gg = arri.basis_sig(F); t = System.currentTimeMillis(); gg = arri.basis_sig(F); t = System.currentTimeMillis() - t; print "arri executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "arri no GB"; print "arri Output:" + str([ str(ggg) for ggg in gg]); print; java-algebra-system-2.7.200/examples/cyclic.rb000066400000000000000000000020211445075545500211420ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ require "examples/jas" java_import "edu.jas.gb.Cyclic"; # cyclic examples knum = 5; tnum = 2; k = Cyclic.new(knum); #r = Ring.new( "", k.ring ); #r = PolyRing.new( GF(23), k.ring.vars, Order::IGRLEX ); r = PolyRing.new( GF(32003), k.ring.vars, Order::IGRLEX ); #r = PolyRing.new( GF(536870909), k.ring.vars, Order::IGRLEX ); #r = PolyRing.new( GF(4294967291), k.ring.vars, Order::IGRLEX ); #r = PolyRing.new( GF(9223372036854775783), k.ring.vars, Order::IGRLEX ); #r = PolyRing.new( GF(170141183460469231731687303715884105727), k.ring.vars, Order::IGRLEX ); puts "Ring: " + str(r); puts; ps = k.polyList(); #ps = k.cyclicPolys(); puts "ps : " + ps.to_s; puts; #exit(); f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #puts "Range: " + Range.new(tnum,2,-1).to_s; #puts "Range: " + (tnum...2).to_s; #puts; rg = f.parGB(tnum); for th in tnum.downto(2) do rg = f.parGB(th); #puts "par(#{th}) Output:" + rg.to_s; #puts; end rg = f.GB(); #puts "seq Output:", rg; puts; terminate(); java-algebra-system-2.7.200/examples/cyclic5.jas000066400000000000000000000005551445075545500214130ustar00rootroot00000000000000#Cyclic equations for N = 5: Mod 32003 (x0,x1,x2,x3,x4) G ( ( x4 + x3 + x2 + x1 + x0 ), ( x3 * x4 + x0 * x4 + x2 * x3 + x1 * x2 + x0 * x1 ), ( x2 * x3 * x4 + x0 * x3 * x4 + x0 * x1 * x4 + x1 * x2 * x3 + x0 * x1 * x2 ), ( x1 * x2 * x3 * x4 + x0 * x2 * x3 * x4 + x0 * x1 * x3 * x4 + x0 * x1 * x2 * x4 + x0 * x1 * x2 * x3 ), ( x0 * x1 * x2 * x3 * x4 - 1 ) ) java-algebra-system-2.7.200/examples/cyclic5_complex_roots.py000066400000000000000000000020611445075545500242350ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from java.lang import Integer from jas import Ring, PolyRing from jas import terminate from jas import startLog from jas import QQ, DD # polynomial examples: complex roots over Q for zero dimensional ideal `cyclic5' r = PolyRing(QQ(),"a,b,c,d,e",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,a,b,c,d,e] = r.gens(); f1 = a + b + c + d + e; f2 = a*b + b*c + c*d + d*e + e*a; f3 = a*b*c + b*c*d + c*d*e + d*e*a + e*a*b; f4 = a*b*c*d + b*c*d*e + c*d*e*a + d*e*a*b + e*a*b*c; f5 = a*b*c*d*e - 1; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print "f4 = ", f4; print "f5 = ", f5; print; F = r.ideal( list=[f1,f2,f3,f4,f5] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.complexRoots(); #R = F.realRoots(); t = System.currentTimeMillis() - t; print; print "R = ", R; print; print "complex roots: "; F.complexRootsPrint() print "complex roots time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/cyclic5_complex_roots.rb000066400000000000000000000017021445075545500242110ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: complex roots over Q for zero dimensional ideal `cyclic5' r = PolyRing.new(QQ(),"a,b,c,d,e",PolyRing.lex); puts "Ring: " + str(r); puts; #one,q,w,s,x = r.gens(); f1 = a + b + c + d + e; f2 = a*b + b*c + c*d + d*e + e*a; f3 = a*b*c + b*c*d + c*d*e + d*e*a + e*a*b; f4 = a*b*c*d + b*c*d*e + c*d*e*a + d*e*a*b + e*a*b*c; f5 = a*b*c*d*e - 1; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts "f4 = " + str(f4); puts "f5 = " + str(f5); puts; F = r.ideal( "", list=[f1,f2,f3,f4,f5] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.complexRoots(); #R = F.realRoots(); t = System.currentTimeMillis() - t; puts "complex decomposition = " + str(R); puts; puts "complex roots = "; F.complexRootsPrint() puts "complex roots time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/cyclic5_real_roots.py000066400000000000000000000017611445075545500235170ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing from jas import terminate from jas import startLog from jas import QQ, DD # polynomial examples: real roots over Q for zero dimensional ideal `cyclic5' r = PolyRing(QQ(),"a,b,c,d,e",PolyRing.lex); print "Ring: " + str(r); print; #is automatic: [one,a,b,c,d,e] = r.gens(); f1 = a + b + c + d + e; f2 = a*b + b*c + c*d + d*e + e*a; f3 = a*b*c + b*c*d + c*d*e + d*e*a + e*a*b; f4 = a*b*c*d + b*c*d*e + c*d*e*a + d*e*a*b + e*a*b*c; f5 = a*b*c*d*e - 1; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print "f4 = ", f4; print "f5 = ", f5; print; F = r.ideal( list=[f1,f2,f3,f4,f5] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; print; print "R = ", R; print; print "real roots: "; F.realRootsPrint() print "real roots time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/cyclic5_real_roots.rb000066400000000000000000000016131445075545500234660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: real roots over Q for zero dimensional ideal `cyclic5' r = PolyRing.new(QQ(),"a,b,c,d,e",PolyRing.lex); puts "Ring: " + str(r); puts; #one,q,w,s,x = r.gens(); f1 = a + b + c + d + e; f2 = a*b + b*c + c*d + d*e + e*a; f3 = a*b*c + b*c*d + c*d*e + d*e*a + e*a*b; f4 = a*b*c*d + b*c*d*e + c*d*e*a + d*e*a*b + e*a*b*c; f5 = a*b*c*d*e - 1; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts "f4 = " + str(f4); puts "f5 = " + str(f5); puts; F = r.ideal( "", list=[f1,f2,f3,f4,f5] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "real roots = "; F.realRootsPrint() puts "real roots time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/cyclic6.jas000066400000000000000000000007631445075545500214150ustar00rootroot00000000000000#Cyclic equations for N = 6: #Mod 32003 (x6,x5,x4,x3,x2,x1) G Mod 32003 (x1,x2,x3,x4,x5,x6) G #Z (x1,x2,x3,x4,x5,x6) G #Q (x1,x2,x3,x4,x5,x6) G ( x1 + x2 + x3 + x4 + x5 + x6, x1*x2 + x1*x6 + x2*x3 + x3*x4 + x4*x5 + x5*x6, x1*x2*x3 + x1*x2*x6 + x1*x5*x6 + x2*x3*x4 + x3*x4*x5 + x4*x5*x6, x1*x2*x3*x4 + x1*x2*x3*x6 + x1*x2*x5*x6 + x1*x4*x5*x6 + x2*x3*x4*x5 + x3*x4*x5*x6, x1*x2*x3*x4*x5 + x1*x2*x3*x4*x6 + x1*x2*x3*x5*x6 + x1*x2*x4*x5*x6 + x1*x3*x4*x5*x6 + x2*x3*x4*x5*x6, x1*x2*x3*x4*x5*x6 - 1 ) java-algebra-system-2.7.200/examples/cyclic6_opt.py000066400000000000000000000026641445075545500221540ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, GF, PolyRing from jas import startLog # example cyclic6, optimize term order # optimal is no change #r = Ring( "Rat (x6,x5,x4,x3,x2,x1) G" ); #r = Ring( "Mod 19 (x6,x5,x4,x3,x2,x1) G" ); #r = Ring( "Mod 3 (x6,x5,x4,x3,x2,x1) G" ); #r = PolyRing( QQ(), "(x6,x5,x4,x3,x2,x1)", PolyRing.grad ); r = PolyRing( GF(3), "(x6,x5,x4,x3,x2,x1)", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( x1 + x2 + x3 + x4 + x5 + x6, x1*x2 + x1*x6 + x2*x3 + x3*x4 + x4*x5 + x5*x6, x1*x2*x3 + x1*x2*x6 + x1*x5*x6 + x2*x3*x4 + x3*x4*x5 + x4*x5*x6, x1*x2*x3*x4 + x1*x2*x3*x6 + x1*x2*x5*x6 + x1*x4*x5*x6 + x2*x3*x4*x5 + x3*x4*x5*x6, x1*x2*x3*x4*x5 + x1*x2*x3*x4*x6 + x1*x2*x3*x5*x6 + x1*x2*x4*x5*x6 + x1*x3*x4*x5*x6 + x2*x3*x4*x5*x6, x1*x2*x3*x4*x5*x6 - 1 ) """; F = [ x1 + x2 + x3 + x4 + x5 + x6, x1*x2 + x1*x6 + x2*x3 + x3*x4 + x4*x5 + x5*x6, x1*x2*x3 + x1*x2*x6 + x1*x5*x6 + x2*x3*x4 + x3*x4*x5 + x4*x5*x6, x1*x2*x3*x4 + x1*x2*x3*x6 + x1*x2*x5*x6 + x1*x4*x5*x6 + x2*x3*x4*x5 + x3*x4*x5*x6, x1*x2*x3*x4*x5 + x1*x2*x3*x4*x6 + x1*x2*x3*x5*x6 + x1*x2*x4*x5*x6 + x1*x3*x4*x5*x6 + x2*x3*x4*x5*x6, x1*x2*x3*x4*x5*x6 - 1 ]; #f = r.ideal( ps ); f = r.ideal( "", F ); print "Ideal: " + str(f); print; startLog(); o = f.optimize(); print "optimized Ideal: " + str(o); print; rg = f.GB(); print "Output:", rg; print; #org = o.GB(); #print "opt Output:", org; #print; java-algebra-system-2.7.200/examples/cyclic7.jas000066400000000000000000000017021445075545500214100ustar00rootroot00000000000000#Cyclic equations for N = 7: Mod 32003 (x7,x6,x5,x4,x3,x2,x1) G #Mod 536870909 (x7,x6,x5,x4,x3,x2,x1) G #Mod 9223372036854775783 (x7,x6,x5,x4,x3,x2,x1) G ( ( x7 + x6 + x5 + x4 + x3 + x2 + x1 ), ( x6 * x7 + x1 * x7 + x5 * x6 + x4 * x5 + x3 * x4 + x2 * x3 + x1 * x2 ), ( x5 * x6 * x7 + x1 * x6 * x7 + x1 * x2 * x7 + x4 * x5 * x6 + x3 * x4 * x5 + x2 * x3 * x4 + x1 * x2 * x3 ), ( x4 * x5 * x6 * x7 + x1 * x5 * x6 * x7 + x1 * x2 * x6 * x7 + x1 * x2 * x3 * x7 + x3 * x4 * x5 * x6 + x2 * x3 * x4 * x5 + x1 * x2 * x3 * x4 ), ( x3 * x4 * x5 * x6 * x7 + x1 * x4 * x5 * x6 * x7 + x1 * x2 * x5 * x6 * x7 + x1 * x2 * x3 * x6 * x7 + x1 * x2 * x3 * x4 * x7 + x2 * x3 * x4 * x5 * x6 + x1 * x2 * x3 * x4 * x5 ), ( x2 * x3 * x4 * x5 * x6 * x7 + x1 * x3 * x4 * x5 * x6 * x7 + x1 * x2 * x4 * x5 * x6 * x7 + x1 * x2 * x3 * x5 * x6 * x7 + x1 * x2 * x3 * x4 * x6 * x7 + x1 * x2 * x3 * x4 * x5 * x7 + x1 * x2 * x3 * x4 * x5 * x6 ), ( x1 * x2 * x3 * x4 * x5 * x6 * x7 - 1 ) ) java-algebra-system-2.7.200/examples/cyclic8.jas000066400000000000000000000025251445075545500214150ustar00rootroot00000000000000#Cyclic equations for N = 8: Mod 32003 (x8,x7,x6,x5,x4,x3,x2,x1) G #Mod 536870909 (x8,x7,x6,x5,x4,x3,x2,x1) G #Mod 9223372036854775783 (x8,x7,x6,x5,x4,x3,x2,x1) G ( ( x8 + x7 + x6 + x5 + x4 + x3 + x2 + x1 ), ( x7 * x8 + x1 * x8 + x6 * x7 + x5 * x6 + x4 * x5 + x3 * x4 + x2 * x3 + x1 * x2 ), ( x6 * x7 * x8 + x1 * x7 * x8 + x1 * x2 * x8 + x5 * x6 * x7 + x4 * x5 * x6 + x3 * x4 * x5 + x2 * x3 * x4 + x1 * x2 * x3 ), ( x5 * x6 * x7 * x8 + x1 * x6 * x7 * x8 + x1 * x2 * x7 * x8 + x1 * x2 * x3 * x8 + x4 * x5 * x6 * x7 + x3 * x4 * x5 * x6 + x2 * x3 * x4 * x5 + x1 * x2 * x3 * x4 ), ( x4 * x5 * x6 * x7 * x8 + x1 * x5 * x6 * x7 * x8 + x1 * x2 * x6 * x7 * x8 + x1 * x2 * x3 * x7 * x8 + x1 * x2 * x3 * x4 * x8 + x3 * x4 * x5 * x6 * x7 + x2 * x3 * x4 * x5 * x6 + x1 * x2 * x3 * x4 * x5 ), ( x3 * x4 * x5 * x6 * x7 * x8 + x1 * x4 * x5 * x6 * x7 * x8 + x1 * x2 * x5 * x6 * x7 * x8 + x1 * x2 * x3 * x6 * x7 * x8 + x1 * x2 * x3 * x4 * x7 * x8 + x1 * x2 * x3 * x4 * x5 * x8 + x2 * x3 * x4 * x5 * x6 * x7 + x1 * x2 * x3 * x4 * x5 * x6 ), ( x2 * x3 * x4 * x5 * x6 * x7 * x8 + x1 * x3 * x4 * x5 * x6 * x7 * x8 + x1 * x2 * x4 * x5 * x6 * x7 * x8 + x1 * x2 * x3 * x5 * x6 * x7 * x8 + x1 * x2 * x3 * x4 * x6 * x7 * x8 + x1 * x2 * x3 * x4 * x5 * x7 * x8 + x1 * x2 * x3 * x4 * x5 * x6 * x8 + x1 * x2 * x3 * x4 * x5 * x6 * x7 ), ( x1 * x2 * x3 * x4 * x5 * x6 * x7 * x8 - 1 ) ) java-algebra-system-2.7.200/examples/cyclic9.jas000066400000000000000000000035331445075545500214160ustar00rootroot00000000000000#Cyclic equations for N = 9: Mod 32003 (x9,x8,x7,x6,x5,x4,x3,x2,x1) G #Mod 536870909 (x9,x8,x7,x6,x5,x4,x3,x2,x1) G #Mod 9223372036854775783 (x9,x8,x7,x6,x5,x4,x3,x2,x1) G ( ( x9 + x8 + x7 + x6 + x5 + x4 + x3 + x2 + x1 ), ( x8 * x9 + x1 * x9 + x7 * x8 + x6 * x7 + x5 * x6 + x4 * x5 + x3 * x4 + x2 * x3 + x1 * x2 ), ( x7 * x8 * x9 + x1 * x8 * x9 + x1 * x2 * x9 + x6 * x7 * x8 + x5 * x6 * x7 + x4 * x5 * x6 + x3 * x4 * x5 + x2 * x3 * x4 + x1 * x2 * x3 ), ( x6 * x7 * x8 * x9 + x1 * x7 * x8 * x9 + x1 * x2 * x8 * x9 + x1 * x2 * x3 * x9 + x5 * x6 * x7 * x8 + x4 * x5 * x6 * x7 + x3 * x4 * x5 * x6 + x2 * x3 * x4 * x5 + x1 * x2 * x3 * x4 ), ( x5 * x6 * x7 * x8 * x9 + x1 * x6 * x7 * x8 * x9 + x1 * x2 * x7 * x8 * x9 + x1 * x2 * x3 * x8 * x9 + x1 * x2 * x3 * x4 * x9 + x4 * x5 * x6 * x7 * x8 + x3 * x4 * x5 * x6 * x7 + x2 * x3 * x4 * x5 * x6 + x1 * x2 * x3 * x4 * x5 ), ( x4 * x5 * x6 * x7 * x8 * x9 + x1 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x9 + x3 * x4 * x5 * x6 * x7 * x8 + x2 * x3 * x4 * x5 * x6 * x7 + x1 * x2 * x3 * x4 * x5 * x6 ), ( x3 * x4 * x5 * x6 * x7 * x8 * x9 + x1 * x4 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x6 * x9 + x2 * x3 * x4 * x5 * x6 * x7 * x8 + x1 * x2 * x3 * x4 * x5 * x6 * x7 ), ( x2 * x3 * x4 * x5 * x6 * x7 * x8 * x9 + x1 * x3 * x4 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x4 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x5 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x6 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x7 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x6 * x8 * x9 + x1 * x2 * x3 * x4 * x5 * x6 * x7 * x9 + x1 * x2 * x3 * x4 * x5 * x6 * x7 * x8 ), ( x1 * x2 * x3 * x4 * x5 * x6 * x7 * x8 * x9 - 1 ) ) java-algebra-system-2.7.200/examples/e-gb.py000066400000000000000000000014541445075545500205440ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #import sys; from jas import Ring, PolyRing from jas import ZZ from jas import startLog # e-gb and d-gb example to compare with hermit normal form r = PolyRing( ZZ(), "x4,x3,x2,x1", PolyRing.lex ); print "Ring: " + str(r); print; #is automatic: [one,x4,x3,x2,x1] = r.gens(); f1 = x1 + 2 * x2 + 3 * x3 + 4 * x4 + 3; f2 = 3 * x2 + 2 * x3 + x4 + 2; f3 = 3 * x3 + 5 * x4 + 1; f4 = 5 * x4 + 4; L = [f1,f2,f3,f4]; #print "L = ", str(L); f = r.ideal( list=L ); print "Ideal: " + str(f); print; #startLog(); g = f.eGB(); print "seq e-GB:", g; print "is e-GB:", g.iseGB(); print; #sys.exit(); d = f.dGB(); print "seq d-GB:", d; print "is d-GB:", d.isdGB(); print; #startLog(); print "d-GB == e-GB:", g.pset.equals(d.pset); java-algebra-system-2.7.200/examples/e-gb.rb000066400000000000000000000014011445075545500205070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # e-gb and d-gb example to compare with hermit normal form r = PolyRing.new( ZZ(), "x4,x3,x2,x1", PolyRing.lex ); puts "Ring: " + str(r); puts; #is automatic: one,x4,x3,x2,x1 = r.gens(); f1 = x1 + 2 * x2 + 3 * x3 + 4 * x4 + 3; f2 = 3 * x2 + 2 * x3 + x4 + 2; f3 = 3 * x3 + 5 * x4 + 1; f4 = 5 * x4 + 4; L = [f1,f2,f3,f4]; #puts "L = " + str(L); f = r.ideal( "", L ); puts "Ideal: " + str(f); puts; #startLog(); g = f.eGB(); puts "seq e-GB: " + str(g); puts "is e-GB: " + str(g.iseGB()); puts; #sys.exit(); d = f.dGB(); puts "seq d-GB: " + str(d); puts "is d-GB: " + str(d.isdGB()); puts; #startLog(); puts "d-GB == e-GB:" + str(g.pset.equals(d.pset)); java-algebra-system-2.7.200/examples/eliminate.py000066400000000000000000000013421445075545500216750ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, PolyRing from jas import startLog from jas import terminate # ideal elimination example #r = Ring( "Rat(x,y,z) G" ); r = PolyRing( QQ(), "(x,y,z)", PolyRing.grad ); print "Ring: " + str(r); print; ps1 = """ ( ( x^2 - 2 ), ( y^2 - 3 ), ( z^3 - x * y ) ) """; ff = [ x**2 - 2, y**2 - 3, z**3 - x * y ] #F1 = r.ideal( ps1 ); F1 = r.ideal( "", ff ); print "Ideal: " + str(F1); print; #e = Ring( "Rat(z) G" ); e = PolyRing( QQ(), "(x,z)", PolyRing.grad ); print "Ring: " + str(e); print; #startLog(); rg1 = F1.eliminateRing(e); print "rg1 = ", rg1; print; rg2 = rg1.intersectRing(e); print "rg2 = ", rg2; print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/eliminate.rb000066400000000000000000000011561445075545500216530ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # ideal elimination example r = PolyRing.new( QQ(), "(x,y,z)", PolyRing.grad ); puts "Ring: " + str(r); puts; ps1 = """ ( ( x^2 - 2 ), ( y^2 - 3 ), ( z^3 - x * y ) ) """; ff = [ x**2 - 2, y**2 - 3, z**3 - x * y ] #F1 = r.ideal( ps1 ); F1 = r.ideal( "", ff ); puts "Ideal: " + str(F1); puts; e = PolyRing.new( QQ(), "(x,z)", PolyRing.grad ); puts "Ring: " + str(e); puts; #startLog(); rg1 = F1.eliminateRing(e); puts "rg1 = " + str(rg1); puts; rg2 = rg1.intersectRing(e); puts "rg2 = " + str(rg2); puts; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/exterior.py000066400000000000000000000055261445075545500215770ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras rs = """ # exterior calculus example: Rat(a,b,c,f,g,h,u,v,w,x,y,z) L #Int(a,b,c,f,g,h,u,v,w,x,y,z) L RelationTable ( ( b ), ( a ), ( - a b ), ( c ), ( a ), ( - a c ), ( f ), ( a ), ( - a f ), ( g ), ( a ), ( - a g ), ( h ), ( a ), ( - a h ), ( u ), ( a ), ( - a u ), ( v ), ( a ), ( - a v ), ( w ), ( a ), ( - a w ), ( x ), ( a ), ( - a x ), ( y ), ( a ), ( - a y ), ( z ), ( a ), ( - a z ), ( c ), ( b ), ( - b c ), ( f ), ( b ), ( - b f ), ( g ), ( b ), ( - b g ), ( h ), ( b ), ( - b h ), ( u ), ( b ), ( - b u ), ( v ), ( b ), ( - b v ), ( w ), ( b ), ( - b w ), ( x ), ( b ), ( - b x ), ( y ), ( b ), ( - b y ), ( z ), ( b ), ( - b z ), ( f ), ( c ), ( - c f ), ( g ), ( c ), ( - c g ), ( h ), ( c ), ( - c h ), ( u ), ( c ), ( - c u ), ( v ), ( c ), ( - c v ), ( w ), ( c ), ( - c w ), ( x ), ( c ), ( - c x ), ( y ), ( c ), ( - c y ), ( z ), ( c ), ( - c z ), ( g ), ( f ), ( - f g ), ( h ), ( f ), ( - f h ), ( u ), ( f ), ( - f u ), ( v ), ( f ), ( - f v ), ( w ), ( f ), ( - f w ), ( x ), ( f ), ( - f x ), ( y ), ( f ), ( - f y ), ( z ), ( f ), ( - f z ), ( h ), ( g ), ( - g h ), ( u ), ( g ), ( - g u ), ( v ), ( g ), ( - g v ), ( w ), ( g ), ( - g w ), ( x ), ( g ), ( - g x ), ( y ), ( g ), ( - g y ), ( z ), ( g ), ( - g z ), ( u ), ( h ), ( - h u ), ( v ), ( h ), ( - h v ), ( w ), ( h ), ( - h w ), ( x ), ( h ), ( - h x ), ( y ), ( h ), ( - h y ), ( z ), ( h ), ( - h z ), ( v ), ( u ), ( - u v ), ( w ), ( u ), ( - u w ), ( x ), ( u ), ( - u x ), ( y ), ( u ), ( - u y ), ( z ), ( u ), ( - u z ), ( w ), ( v ), ( - v w ), ( x ), ( v ), ( - v x ), ( y ), ( v ), ( - v y ), ( z ), ( v ), ( - v z ), ( x ), ( w ), ( - w x ), ( y ), ( w ), ( - w y ), ( z ), ( w ), ( - w z ), ( y ), ( x ), ( - x y ), ( z ), ( x ), ( - x z ), ( z ), ( y ), ( - y z ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; # ( a b + c f + g h ), # ( u v + w x + y z ), # ( a v + w x + y z ), ps = """ ( ( a b + c f + g h ), ( u v + w x + y z ), ( a v + w x + y z ), ( a^2 ), ( b^2 ), ( c^2 ), ( f^2 ), ( g^2 ), ( h^2 ), ( u^2 ), ( v^2 ), ( w^2 ), ( x^2 ), ( y^2 ), ( z^2 ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; lg = f.leftGB(); print "seq left GB:", lg; print; tg = f.twosidedGB(); print "seq twosided GB:", tg; print; rg = f.rightGB(); print "seq right GB:", rg; print; print "left == right GB: " + str(lg == rg); print "left == twosided GB: " + str(lg == tg); print "two sided == right GB: " + str(tg == rg); print "is left GB: " + str(lg.isLeftGB()); print "is twosided GB: " + str(tg.isTwosidedGB()); print "is right GB: " + str(rg.isRightGB()); print java-algebra-system-2.7.200/examples/exterior.rb000066400000000000000000000055421445075545500215500ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras rs = """ # exterior calculus example: Rat(a,b,c,f,g,h,u,v,w,x,y,z) L #Int(a,b,c,f,g,h,u,v,w,x,y,z) L RelationTable ( ( b ), ( a ), ( - a b ), ( c ), ( a ), ( - a c ), ( f ), ( a ), ( - a f ), ( g ), ( a ), ( - a g ), ( h ), ( a ), ( - a h ), ( u ), ( a ), ( - a u ), ( v ), ( a ), ( - a v ), ( w ), ( a ), ( - a w ), ( x ), ( a ), ( - a x ), ( y ), ( a ), ( - a y ), ( z ), ( a ), ( - a z ), ( c ), ( b ), ( - b c ), ( f ), ( b ), ( - b f ), ( g ), ( b ), ( - b g ), ( h ), ( b ), ( - b h ), ( u ), ( b ), ( - b u ), ( v ), ( b ), ( - b v ), ( w ), ( b ), ( - b w ), ( x ), ( b ), ( - b x ), ( y ), ( b ), ( - b y ), ( z ), ( b ), ( - b z ), ( f ), ( c ), ( - c f ), ( g ), ( c ), ( - c g ), ( h ), ( c ), ( - c h ), ( u ), ( c ), ( - c u ), ( v ), ( c ), ( - c v ), ( w ), ( c ), ( - c w ), ( x ), ( c ), ( - c x ), ( y ), ( c ), ( - c y ), ( z ), ( c ), ( - c z ), ( g ), ( f ), ( - f g ), ( h ), ( f ), ( - f h ), ( u ), ( f ), ( - f u ), ( v ), ( f ), ( - f v ), ( w ), ( f ), ( - f w ), ( x ), ( f ), ( - f x ), ( y ), ( f ), ( - f y ), ( z ), ( f ), ( - f z ), ( h ), ( g ), ( - g h ), ( u ), ( g ), ( - g u ), ( v ), ( g ), ( - g v ), ( w ), ( g ), ( - g w ), ( x ), ( g ), ( - g x ), ( y ), ( g ), ( - g y ), ( z ), ( g ), ( - g z ), ( u ), ( h ), ( - h u ), ( v ), ( h ), ( - h v ), ( w ), ( h ), ( - h w ), ( x ), ( h ), ( - h x ), ( y ), ( h ), ( - h y ), ( z ), ( h ), ( - h z ), ( v ), ( u ), ( - u v ), ( w ), ( u ), ( - u w ), ( x ), ( u ), ( - u x ), ( y ), ( u ), ( - u y ), ( z ), ( u ), ( - u z ), ( w ), ( v ), ( - v w ), ( x ), ( v ), ( - v x ), ( y ), ( v ), ( - v y ), ( z ), ( v ), ( - v z ), ( x ), ( w ), ( - w x ), ( y ), ( w ), ( - w y ), ( z ), ( w ), ( - w z ), ( y ), ( x ), ( - x y ), ( z ), ( x ), ( - x z ), ( z ), ( y ), ( - y z ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; # ( a b + c f + g h ), # ( u v + w x + y z ), # ( a v + w x + y z ), ps = """ ( ( a b + c f + g h ), ( u v + w x + y z ), ( a v + w x + y z ), ( a^2 ), ( b^2 ), ( c^2 ), ( f^2 ), ( g^2 ), ( h^2 ), ( u^2 ), ( v^2 ), ( w^2 ), ( x^2 ), ( y^2 ), ( z^2 ) ) """; f = r.ideal(ps); puts "SolvableIdeal: " + str(f); puts; #startLog(); lg = f.leftGB(); puts "seq left GB: " + str(lg); puts; tg = f.twosidedGB(); puts "seq twosided GB: " + str(tg); puts; rg = f.rightGB(); puts "seq right GB: " + str(rg); puts; puts "left == right GB: " + str(lg == rg); puts "left == twosided GB: " + str(lg == tg); puts "two sided == right GB: " + str(tg == rg); puts "is left GB: " + str(lg.isLeftGB()); puts "is twosided GB: " + str(tg.isTwosidedGB()); puts "is right GB: " + str(rg.isRightGB()); puts java-algebra-system-2.7.200/examples/exteriorPlanes.py000066400000000000000000000063071445075545500227400ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import ExtPolyRing, RingElem, ZZ # exterior calculus plane intersection example # after Blonski, 1983. print; #r = ExtPolyRing( ZZ(), 4, "E" ); r = ExtPolyRing( ZZ(), 4 ); print; print "ExtPolyRing: " + str(r); gg = r.gens(); #for g in gg # print "gens(): " + str(g); #end #print; # constant names (upper case) need explicit assignment one = gg[0]; e1 = gg[1]; e2 = gg[2]; e3 = gg[3]; e4 = gg[4]; # variable names (lower case) are implicitly assigned print "one: " + str(one); #print "r.E1: " + str(r.E1); #print "r.e1: " + str(r.e1); print "E1: " + str(E1); print "e1: " + str(e1); print "e2: " + str(e2); print "e3: " + str(e3); print "e4: " + str(e4); print; print "E1*E1: " + str(E1*E1); print "e1*e1: " + str(e1*e1); print "e2*e1: " + str(e2*e1); print; # define points in 4-space as polynomials #p1 = ("1 E(1) + 5 E(2) - 2 E(3) + 1 E(4)"); #p2 = ("4 E(1) + 3 E(2) + 6 E(3) + 1 E(4)"); p1 = e1 + 5*e2 - 2* e3 + e4; p2 = 4 * e1 + 3 * e2 + 6 * e3 + e4; print "p1: " + str(p1); print "p2: " + str(p2); #q1 = ("3 E(1) - 2 E(2) - 1 E(3) + 1 E(4)"); #q2 = ("1 E(2) + 5 E(3) + 1 E(4)"); q1 = 3 * e1 - 2 * e2 - e3 + e4; q2 = e2 + 5 * e3 + e4; print "q1: " + str(q1); print "q2: " + str(q2); #s = ("1 E(3) + 1 E(4)"); s = e3 + e4; print "s: " + str(s); print; # compute line(gerade) p1..p2 and q1..q2 #g1 = p1.multiply(p2).abs(); #g2 = q1.multiply(q2).abs().divide(new BigInteger(3)); g1 = abs((p1 * p2)); g2 = (q1 * q2).cpp(); print "g1 = p1 /\\ p2 = " + str(g1); print "g2 = q1 /\\ q2 = " + str(g2); #print "cpp(g2) = " + str(g22); print; # compute plane g1..s and g2..s #e1 = g1.multiply(s).abs().divide(new BigInteger(17)); #e2 = g2.multiply(s); plane1 = (g1 * s).cpp(); plane2 = g2 * s; print "plane1 = g1 /\\ s = " + str(plane1); print "plane2 = g2 /\\ s = " + str(plane2); print; #emax = r.ring.ixfac.imax; emax = RingElem( r.ring.getIMAX() ); print "emax = " + str(emax); # compute dual planes of e1, e2 as e1..emax and e2..emax e1dual = abs(plane1.interiorRightProduct(emax)); e2dual = abs(plane2.interiorRightProduct(emax)); print "e1dual = plane1 |_ emax = " + str(e1dual); print "e2dual = plane2 |_ emax = " + str(e2dual); print; # compute intersection of plane plane1, plane2 via dual planes sum q = (e1dual * e2dual).cpp(); print "q = e1dual /\\ e2dual = " + str(q); qs = q.interiorRightProduct(emax).cpp(); print "qs = (e1dual /\\ e2dual) |_ emaxd = " + str(qs); qt = plane1.interiorLeftProduct(e2dual).cpp(); print "qt = plane1 _| e2dual = " + str(qt); print; # compute dual line(gerade) of g1, g2 g1dual = g1.interiorRightProduct(emax).cpp(); g2dual = g2.interiorRightProduct(emax).cpp(); print "g1dual = g1 |_ emax = " + str(g1dual); print "g2dual = g2 |_ emax = " + str(g2dual); # compute intersection of g1..e2 and g2..e1 s1 = plane2.interiorLeftProduct(g1dual).cpp(); print "s1 = plane2 _| g1dual = " + str(s1); s2 = plane1.interiorLeftProduct(g2dual).cpp(); print "s2 = plane1 _| g2dual = " + str(s2); print # check intersection of s..qs, qs..e1 and qs..e2 print " s /\\ qs = s \\in qs = " + str( s * qs); print "qs /\\ plane1 = qs \\in plane1 = " + str(qs * plane1); print "qs /\\ plane2 = qs \\in plane2 = " + str(qs * plane2); print java-algebra-system-2.7.200/examples/exteriorPlanes.rb000066400000000000000000000062171445075545500227130ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # exterior calculus plane intersection example # after Blonski, 1983. puts; #r = ExtPolyRing.new( ZZ, 4, "E" ); r = ExtPolyRing.new( ZZ, 4 ); puts; puts "ExtPolyRing: " + str(r); gg = r.gens(); #for g in gg # puts "gens(): " + str(g); #end #puts; # constant names (upper case) need explicit assignment one = gg[0]; E1 = gg[1]; E2 = gg[2]; E3 = gg[3]; E4 = gg[4]; # variable names (lower case) are implicitly assigned puts "one: " + str(one); puts "r.E1: " + str(r.E1); puts "r.e1: " + str(r.e1); puts "E1: " + str(E1); puts "e1: " + str(e1); puts "e2: " + str(e2); puts "e3: " + str(e3); puts "e4: " + str(e4); puts; puts "E1*E1: " + str(E1*E1); puts "e1*e1: " + str(e1*e1); puts "e2*e1: " + str(e2*e1); puts; # define points in 4-space as polynomials #p1 = ("1 E(1) + 5 E(2) - 2 E(3) + 1 E(4)"); #p2 = ("4 E(1) + 3 E(2) + 6 E(3) + 1 E(4)"); p1 = r.e1 + 5*e2 - 2* e3 + e4; p2 = 4 * r.e1 + 3 * e2 + 6 * e3 + e4; puts "p1: " + str(p1); puts "p2: " + str(p2); #q1 = ("3 E(1) - 2 E(2) - 1 E(3) + 1 E(4)"); #q2 = ("1 E(2) + 5 E(3) + 1 E(4)"); q1 = 3 * e1 - 2 * e2 - e3 + e4; q2 = e2 + 5 * e3 + e4; puts "q1: " + str(q1); puts "q2: " + str(q2); #s = ("1 E(3) + 1 E(4)"); s = e3 + e4; puts "s: " + str(s); puts; # compute line(gerade) p1..p2 and q1..q2 #g1 = p1.multiply(p2).abs(); #g2 = q1.multiply(q2).abs().divide(new BigInteger(3)); g1 = (p1 * p2).abs(); g2 = (q1 * q2).cpp(); puts "g1 = p1 /\\ p2 = " + str(g1); puts "g2 = q1 /\\ q2 = " + str(g2); #puts "cpp(g2) = " + str(g22); puts; # compute plane g1..s and g2..s #e1 = g1.multiply(s).abs().divide(new BigInteger(17)); #e2 = g2.multiply(s); plane1 = (g1 * s).cpp(); plane2 = g2 * s; puts "plane1 = g1 /\\ s = " + str(plane1); puts "plane2 = g2 /\\ s = " + str(plane2); puts; #emax = r.ring.ixfac.imax; emax = RingElem.new( r.ring.getIMAX() ); puts "emax = " + str(emax); # compute dual planes of e1, e2 as e1..emax and e2..emax e1dual = plane1.interiorRightProduct(emax).abs(); e2dual = plane2.interiorRightProduct(emax).abs(); puts "e1dual = plane1 |_ emax = " + str(e1dual); puts "e2dual = plane2 |_ emax = " + str(e2dual); puts; # compute intersection of plane plane1, plane2 via dual planes sum q = (e1dual * e2dual).cpp(); puts "q = e1dual /\\ e2dual = " + str(q); qs = q.interiorRightProduct(emax).cpp(); puts "qs = (e1dual /\\ e2dual) |_ emaxd = " + str(qs); qt = plane1.interiorLeftProduct(e2dual).cpp(); puts "qt = plane1 _| e2dual = " + str(qt); puts; # compute dual line(gerade) of g1, g2 g1dual = g1.interiorRightProduct(emax).cpp(); g2dual = g2.interiorRightProduct(emax).cpp(); puts "g1dual = g1 |_ emax = " + str(g1dual); puts "g2dual = g2 |_ emax = " + str(g2dual); # compute intersection of g1..e2 and g2..e1 s1 = plane2.interiorLeftProduct(g1dual).cpp(); puts "s1 = plane2 _| g1dual = " + str(s1); s2 = plane1.interiorLeftProduct(g2dual).cpp(); puts "s2 = plane1 _| g2dual = " + str(s2); puts # check intersection of s..qs, qs..e1 and qs..e2 puts " s /\\ qs = s \\in qs = " + str( s * qs); puts "qs /\\ plane1 = qs \\in plane1 = " + str(qs * plane1); puts "qs /\\ plane2 = qs \\in plane2 = " + str(qs * plane2); puts java-algebra-system-2.7.200/examples/factors.py000066400000000000000000000044321445075545500213720ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import ZZ, PolyRing from jas import startLog, terminate # polynomial examples: factorization over Z #r = Ring( "Z(x) L" ); r = PolyRing( ZZ(), "(x)", PolyRing.lex ); print "Ring: " + str(r); print; #is automatic: [one,x] = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**15 + 122 * x**10 - 122 * x**5 - 1; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; f = f * (x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8); # Swinnerton-Dyer: #f = x**8 - 236 * x**6 + 11678 * x**4 - 210428 * x**2 + 1261129; print "f = ", f; print; #startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); #G = r.factors(f); G = f.factors(); t = System.currentTimeMillis() - t; print "G = ", [ str(h)+"**"+str(i) for (h,i) in G.iteritems() ]; #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h, ""; h = h**i; g = g*h; #print "g = ", g; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; startLog(); terminate(); java-algebra-system-2.7.200/examples/factors.rb000066400000000000000000000045551445075545500213530ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Z r = PolyRing.new( ZZ(), "x", PolyRing.lex ); puts "Ring: " + str(r); puts; #is automatic: one,x = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**15 + 122 * x**10 - 122 * x**5 - 1; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = f * (x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8); f = (x**258 - 1); #f = (x**258 - 1)/(x - 1); #f = (x**100 - 1); #*(x - 1); #f = (x**100 - 1)/(x - 1); # Swinnerton-Dyer: #f = x**8 - 236 * x**6 + 11678 * x**4 - 210428 * x**2 + 1261129; puts "f = ", f; puts; #startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); #G = r.factors(f); G = f.factors(); t = System.currentTimeMillis() - t; puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); #puts "G = ", G; #puts "factor time =", t, "milliseconds"; puts; puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end puts; #puts "g = ", g; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs.py000066400000000000000000000037201445075545500222160ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import QQ, GF, ZZ, PolyRing from jas import terminate, startLog # polynomial examples: absolute factorization over Q #r = PolyRing( GF(19), "x", PolyRing.lex ); r = PolyRing( QQ(), "x", PolyRing.lex ); print "Ring: " + str(r); print; #is automatic: [one,x] = r.gens(); #f = x**5 - 1; #f = x**6 - 1; f = x**3 - 2; f = f*f; #f = x**7 - 1; #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**2 + 1; #f = x**3 - x**2 + x - 1; #f = x**6 - 5 * x**4 + 5 * x**2 + 4; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**4 + 2 * x**2 - 4 * x + 2; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); #G = r.factorsAbsolute(f); G = f.factorsAbsolute(); t = System.currentTimeMillis() - t; print "G = ", G.toScript(); print print "factor time =", t, "milliseconds"; print #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs.rb000066400000000000000000000036221445075545500221720ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: absolute factorization over Q #r = PolyRing.new( GF(19), "x", PolyRing.lex ); r = PolyRing.new( QQ(), "x", PolyRing.lex ); puts "Ring: " + str(r); puts; #is automatic: one,x = r.gens(); #f = x**5 - 1; #f = x**6 - 1; f = x**3 - 2; f = f*f; #f = x**7 - 1; #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**2 + 1; #f = x**3 - x**2 + x - 1; #f = x**6 - 5 * x**4 + 5 * x**2 + 4; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**4 + 2 * x**2 - 4 * x + 2; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; puts "f = " + str(f); puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); #G = r.factorsAbsolute(f); G = f.factorsAbsolute(); t = System.currentTimeMillis() - t; puts "G = " + str(G.toScript()); puts puts "factor time = " + str(t) + " milliseconds"; puts #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs_complex.py000066400000000000000000000033111445075545500237410ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing from jas import QQ, AN from jas import terminate, startLog # polynomial examples: absolute factorization over Q(i) Qr = PolyRing(QQ(),"i",PolyRing.lex); print "Qr = " + str(Qr); [e,a] = Qr.gens(); print "e = " + str(e); print "a = " + str(a); print; imag = a**2 + 1; print "imag = " + str(imag); Qi = AN(imag,field=True); print "Qi = " + str(Qi.factory()); [one,i] = Qi.gens(); print "one = " + str(one); print "i = " + str(i); print; r = PolyRing(Qi,"x",PolyRing.lex) print "r = " + str(r); #is automatic: [one,i,x] = r.gens(); print "one = " + str(one); print "i = " + str(i); print "x = " + str(x); print; #f = x**7 - 1; #f = x**6 + x**5 + x**4 + x**3 + x**2 + x + 1; #f = x**2 - i; #f = x**3 - i; #f = x**2 + 1; #f = x**5 - 1; #f = x**4 + x**3 + x**2 + x + (1,); #f = ( x**2 - i - 1 ) * ( x**2 + i + 1 ); f = ( x**2 - i ) * ( x**2 + i + 1 ); print "f = ", f; print; #startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; #print "factor time =", t, "milliseconds"; f2 = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; f2 = f2*h; #print "f2 = ", f2; print; if cmp(f,f2) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,f2); print; startLog(); t = System.currentTimeMillis(); G = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; print "G = ", G.toScript(); print print "factor time =", t, "milliseconds"; print #sys.exit(); #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs_complex.rb000066400000000000000000000030101445075545500237100ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: absolute factorization over Q(i) Qr = PolyRing.new(QQ(),"i",PolyRing.lex); puts "Qr = " + str(Qr); e,a = Qr.gens(); puts "e = " + str(e); puts "a = " + str(a); puts; imag = a**2 + 1; puts "imag = " + str(imag); Qi = AN(imag,true); puts "Qi = " + str(Qi.factory()); one,i = Qi.gens(); puts "one = " + str(one); puts "i = " + str(i); puts; r = PolyRing.new(Qi,"x",PolyRing.lex) puts "r = " + str(r); #is automatic: one,i,x = r.gens(); puts "one = " + str(one); puts "i = " + str(i); puts "x = " + str(x); puts; #f = x**7 - 1; #f = x**6 + x**5 + x**4 + x**3 + x**2 + x + 1; #f = x**2 - i; #f = x**3 - i; #f = x**2 + 1; #f = x**5 - 1; #f = x**4 + x**3 + x**2 + x + (1,); #f = ( x**2 - i - 1 ) * ( x**2 + i + 1 ); f = ( x**2 - i ) * ( x**2 + i + 1 ); puts "f = " + str(f); puts; #startLog(); t = System.currentTimeMillis(); g = r.factors(f); t = System.currentTimeMillis() - t; #puts "G = " + str(g); #puts "factor time = " + str(t) + " milliseconds"; f2 = one; for h, i in g puts "h**i = (" + str(h) + ")**" + str(i); h = h**i; f2 = f2*h; end #puts "f2 = " + str(f2); puts; puts "factor time = " + str(t) + " milliseconds, " + "isFactors(f,g): " + str( f==f2 ); puts; startLog(); t = System.currentTimeMillis(); g = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; puts "G = " + g.toScript(); puts puts "factor time = " + str(t) + " milliseconds"; puts #sys.exit(); #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs_mult.py000066400000000000000000000012211445075545500232510ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import QQ, Ring, PolyRing from jas import terminate, startLog # polynomial examples: absolute factorization over Q #r = Ring( "Q(x,y) L" ); r = PolyRing( QQ(), "(x,y)", PolyRing.lex ); print "Ring: " + str(r); print; #is automatic: [one,x,y] = r.gens(); f1 = x**2 + y**2; f2 = x**3 + y**2; f3 = x**4 + 4; f = f1**3 * f2**1 * f3**2; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; print "G = ", G.toScript(); print print "factor time =", t, "milliseconds"; print #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_abs_mult.rb000066400000000000000000000011201445075545500232220ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: absolute factorization over Q #r = Ring.new( "Q(x,y) L" ); r = PolyRing.new( QQ(), "(x,y)", PolyRing.lex ); puts "Ring: " + str(r); puts; #is automatic: one,x,y = r.gens(); f1 = x**2 + y**2; f2 = x**3 + y**2; f3 = x**4 + 4; f = f1**3 * f2**1 * f3**2; puts "f = " + str(f); puts; startLog(); t = System.currentTimeMillis(); G = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; puts "G = " + G.toScript(); puts puts "factor time = " + str(t) + " milliseconds"; puts #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb.py000066400000000000000000000057041445075545500225270ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, AN, QQ from jas import terminate, startLog # polynomial examples: factorization over Q(i) #r = Ring( "AN[ (i) (i^2 + 1) ] (x) L" ); #r = Ring( "AN[ (a) (4 a^2 + 1) ] (x) L" ); #r = Ring( "AN[ (a) (a^4 + 2 a^2 - 4 a + 2) ] (x) L" ); Qr = PolyRing(QQ(),"i",PolyRing.lex); print "Qr = " + str(Qr); [e,a] = Qr.gens(); print "e = " + str(e); print "a = " + str(a); imag = a**2 + 1; print "imag = " + str(imag); Qi = AN(imag,field=True); print "Qi = " + str(Qi.factory()); [one,i] = Qi.gens(); print "one = " + str(one); print "i = " + str(i); b = i**2 + 1; print "b = " + str(b); c = 1 / i; print "c = " + str(c); #Qix = AN(i**2 + 1); #print "Qix = " + str(Qix.factory()); print; r = PolyRing(Qi,"x",PolyRing.lex) print "r = " + str(r); #is automatic: [one,i,x] = r.gens(); print "one = " + str(one); print "i = " + str(i); print "x = " + str(x); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11) + 3 * x**(2*11) - x**(11); #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 + 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; f = x**6 - 5 * x**4 + 5 * x**2 + 4; # == f = ( x**3 + 2 * i * x**2 - 3 * x - 4 * i ) * ( x**3 - 2 * i * x**2 - 3 * x + 4 * i ); #f = ( x**3 + ( 2 * i ) * x**2 - ( 3 ) * x - ( 4 * i ) ) * ( x**3 - ( 2 * i ) * x**2 - ( 3 ) * x + ( 4 * i ) ); #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = ", h, "**" + str(i); h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb.rb000066400000000000000000000054251445075545500225020ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Q(i) #r = Ring( "AN[ (i) (i^2 + 1) ] (x) L" ); #r = Ring( "AN[ (a) (4 a^2 + 1) ] (x) L" ); #r = Ring( "AN[ (a) (a^4 + 2 a^2 - 4 a + 2) ] (x) L" ); Qr = PolyRing.new(QQ(),"i",PolyRing.lex); puts "Qr = " + str(Qr); e,a = Qr.gens(); puts "e = " + str(e); puts "a = " + str(a); imag = a**2 + 1; puts "imag = " + str(imag); Qi = AN(imag,true); puts "Qi = " + str(Qi.factory()); one,i = Qi.gens(); puts "one = " + str(one); puts "i = " + str(i); b = i**2 + 1; puts "b = " + str(b); c = 1 / i; puts "c = " + str(c); #Qix = AN(i**2 + 1); #puts "Qix = " + str(Qix.factory()); puts; r = PolyRing.new(Qi,"x",PolyRing.lex) puts "r = " + str(r); #is automatic: one,i,x = r.gens(); puts "one = " + str(one); puts "i = " + str(i); puts "x = " + str(x); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11) + 3 * x**(2*11) - x**(11); #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 + 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; f = x**6 - 5 * x**4 + 5 * x**2 + 4; # == f = ( x**3 + 2 * i * x**2 - 3 * x - 4 * i ) * ( x**3 - 2 * i * x**2 - 3 * x + 4 * i ); #f = ( x**3 + ( 2 * i ) * x**2 - ( 3 ) * x - ( 4 * i ) ) * ( x**3 - ( 2 * i ) * x**2 - ( 3 ) * x + ( 4 * i ) ); #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; puts "f = " + str(f); puts; startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; puts "#G = " + str(G.size); #puts "factor time =", t, "milliseconds"; puts; g = one; for h, i in G puts "h**i = " + str(h) + "**" + str(i); h = h**i; g = g*h; end #puts "g = ", g; puts; puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_2.py000066400000000000000000000032051445075545500227420ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import QQ, AN, Ring, PolyRing from jas import terminate, startLog # polynomial examples: factorization over Q(i)(sqrt2) Q = PolyRing(QQ(),"i",PolyRing.lex); print "Q = " + str(Q); #is automatic: Q.inject_variables(); print "i = " + str(i); imag = i**2 + 1; print "imag = " + str(imag); Qi = AN(imag,field=True); print "Qi = " + str(Qi.factory()); #is automatic: Qi.inject_variables(); print "i = " + str(i); print; Wr = PolyRing(Qi,"w2",PolyRing.lex) print "Wr = " + str(Wr); #is automatic: Wr.inject_variables(); print "i = " + str(i); print "w2 = " + str(w2); w2p = w2**2 - 2; print "w2p = " + str(w2p); Qw2 = AN(w2p,field=True); print "Qw2 = " + str(Qw2.factory()); #is automatic: Qw2.inject_variables(); print "i = " + str(i); print "w2 = " + str(w2); print; Qiw2 = PolyRing(Qw2,"x",PolyRing.lex) print "Qiw2 = " + str(Qiw2); #is automatic: Qiw2.inject_variables(); print "i = " + str(i); print "w2 = " + str(w2); print "x = " + str(x); print; #sys.exit(); f = ( x**2 + 1 ) * ( x**2 - 2 ); print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = Qiw2.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_2.rb000066400000000000000000000027461445075545500227260ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Q(i)(sqrt2) Q = PolyRing.new(QQ(),"i",PolyRing.lex); puts "Q = " + str(Q); e,a = Q.gens(); puts "e = " + str(e); puts "a = " + str(a); imag = a**2 + 1; puts "imag = " + str(imag); Qi = AN(imag,true); puts "Qi = " + str(Qi.factory()); one,i = Qi.gens(); puts "one = " + str(one); puts "i = " + str(i); puts; Wr = PolyRing.new(Qi,"w2",PolyRing.lex) puts "Wr = " + str(Wr); e,a,b = Wr.gens(); puts "e = " + str(e); puts "a = " + str(a); puts "b = " + str(b); w2 = b**2 - 2; puts "w2 = " + str(w2); Qw2 = AN(w2,true); puts "Qw2 = " + str(Qw2.factory()); one,i,w2 = Qw2.gens(); puts "one = " + str(one); puts "i = " + str(i); puts "w2 = " + str(w2); puts; Qiw2 = PolyRing.new(Qw2,"x",PolyRing.lex) puts "Qiw2 = " + str(Qiw2); one,i,w2,x = Qiw2.gens(); puts "one = " + str(one); puts "i = " + str(i); puts "w2 = " + str(w2); puts "x = " + str(x); puts; #sys.exit(); f = ( x**2 + 1 ) * ( x**2 - 2 ); puts "f = " + str(f); puts; startLog(); t = System.currentTimeMillis(); G = Qiw2.factors(f); t = System.currentTimeMillis() - t; #puts "G = ", G; #puts "factor time =", t, "milliseconds"; puts; g = one; for h, i in G puts "h**i = (" + str(h) + ")**" + str(i); h = h**i; g = g*h; end #puts "g = ", g; puts; puts "factor time = " + str(t) + " milliseconds," + "isFactors(f,g): " + str(f==g); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans.py000066400000000000000000000055141445075545500237350ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import QQ, AN, RF, Ring, PolyRing from jas import terminate, startLog # polynomial examples: factorization over Q(sqrt(2))(x)(sqrt(x))[y] Q = PolyRing(QQ(),"w2",PolyRing.lex); print "Q = " + str(Q); [e,a] = Q.gens(); print "e = " + str(e); print "a = " + str(a); root = a**2 - 2; print "root = " + str(root); Q2 = AN(root,field=True); print "Q2 = " + str(Q2.factory()); [one,w2] = Q2.gens(); #print "one = " + str(one); #print "w2 = " + str(w2); print; Qp = PolyRing(Q2,"x",PolyRing.lex); print "Qp = " + str(Qp); [ep,wp,ap] = Qp.gens(); #print "ep = " + str(ep); #print "wp = " + str(wp); #print "ap = " + str(ap); print; Qr = RF(Qp); print "Qr = " + str(Qr.factory()); [er,wr,ar] = Qr.gens(); #print "er = " + str(er); #print "wr = " + str(wr); #print "ar = " + str(ar); print; Qwx = PolyRing(Qr,"wx",PolyRing.lex); print "Qwx = " + str(Qwx); [ewx,wwx,ax,wx] = Qwx.gens(); #print "ewx = " + str(ewx); print "ax = " + str(ax); #print "wwx = " + str(wwx); print "wx = " + str(wx); print; rootx = wx**2 - ax; print "rootx = " + str(rootx); Q2x = AN(rootx,field=True); print "Q2x = " + str(Q2x.factory()); [ex2,w2x2,ax2,wx] = Q2x.gens(); #print "ex2 = " + str(ex2); #print "w2x2 = " + str(w2x2); #print "ax2 = " + str(ax2); #print "wx = " + str(wx); print; Yr = PolyRing(Q2x,"y",PolyRing.lex) print "Yr = " + str(Yr); #is automatic: [e,w2,x,wx,y] = Yr.gens(); print "e = " + str(one); print "w2 = " + str(w2); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print; f = ( y**2 - x ) * ( y**2 - 2 ); #f = ( y**2 - x )**2 * ( y**2 - 2 )**3; #f = ( y**4 - x * 2 ); #f = ( y**7 - x * 2 ); #f = ( y**2 - 2 ); #f = ( y**2 - x ); #f = ( w2 * y**2 - 1 ); #f = ( y**2 - 1/x ); #f = ( y**2 - (1,2) ); #f = ( y**2 - 1/x ) * ( y**2 - (1,2) ); print "f = ", f; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; #print "factor time =", t, "milliseconds"; #sys.exit(); print "f = ", f; g = one; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h; h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; terminate(); sys.exit(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; print "2 factor time =", t, "milliseconds"; t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; print "3 factor time =", t, "milliseconds"; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans.rb000066400000000000000000000046571445075545500237170ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Q(sqrt(2))(x)(sqrt(x))[y] Q = PolyRing.new(QQ(),"w2",PolyRing.lex); puts "Q = " + str(Q); e,a = Q.gens(); #puts "e = " + str(e); puts "a = " + str(a); root = a**2 - 2; puts "root = " + str(root); Q2 = AN(root,field=true); puts "Q2 = " + str(Q2.factory()); one,w2 = Q2.gens(); #puts "one = " + str(one); #puts "w2 = " + str(w2); puts; Qp = PolyRing.new(Q2,"x",PolyRing.lex); puts "Qp = " + str(Qp); ep,wp,ap = Qp.gens(); #puts "ep = " + str(ep); #puts "wp = " + str(wp); #puts "ap = " + str(ap); puts; Qr = RF(Qp); puts "Qr = " + str(Qr.factory()); er,wr,ar = Qr.gens(); #puts "er = " + str(er); #puts "wr = " + str(wr); #puts "ar = " + str(ar); puts; Qwx = PolyRing.new(Qr,"wx",PolyRing.lex); puts "Qwx = " + str(Qwx); ewx,wwx,ax,wx = Qwx.gens(); #puts "ewx = " + str(ewx); puts "ax = " + str(ax); #puts "wwx = " + str(wwx); puts "wx = " + str(wx); puts; rootx = wx**2 - ax; puts "rootx = " + str(rootx); Q2x = AN(rootx,field=true); puts "Q2x = " + str(Q2x.factory()); ex2,w2x2,ax2,wx = Q2x.gens(); #puts "ex2 = " + str(ex2); #puts "w2x2 = " + str(w2x2); #puts "ax2 = " + str(ax2); #puts "wx = " + str(wx); puts; Yr = PolyRing.new(Q2x,"y",PolyRing.lex) puts "Yr = " + str(Yr); #is automatic: e,w2,x,wx,y = Yr.gens(); puts "e = " + str(one); puts "w2 = " + str(w2); puts "x = " + str(x); puts "wx = " + str(wx); puts "y = " + str(y); puts; f = ( y**2 - x ) * ( y**2 - 2 ); #f = ( y**2 - x )**2 * ( y**2 - 2 )**3; #f = ( y**4 - x * 2 ); #f = ( y**7 - x * 2 ); #f = ( y**2 - 2 ); #f = ( y**2 - x ); #f = ( w2 * y**2 - 1 ); #f = ( y**2 - 1/x ); #f = ( y**2 - (1,2) ); #f = ( y**2 - 1/x ) * ( y**2 - (1,2) ); puts "f = " + str(f); puts; #sys.exit(); startLog(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #puts "G = ", G; #puts "factor time =", t, "milliseconds"; #exit(); puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end #puts "g = " + str(g); puts; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans_algeb_charp.py000066400000000000000000000051641445075545500262450ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import Ring, PolyRing from jas import ZM, QQ, AN, RF, GF from jas import terminate, startLog # polynomial examples: factorization over Z_p(sqrt(2))(x)(sqrt(x))[y] Q = PolyRing(GF(5),"w2",PolyRing.lex); print "Q = " + str(Q); [e,a] = Q.gens(); #print "e = " + str(e); print "a = " + str(a); root = a**2 - 2; print "root = " + str(root); Q2 = AN(root,field=True); print "Q2 = " + str(Q2.factory()); [one,w2] = Q2.gens(); #print "one = " + str(one); #print "w2 = " + str(w2); print; Qp = PolyRing(Q2,"x",PolyRing.lex); print "Qp = " + str(Qp); [ep,wp,ap] = Qp.gens(); #print "ep = " + str(ep); #print "wp = " + str(wp); #print "ap = " + str(ap); print; Qr = RF(Qp); print "Qr = " + str(Qr.factory()); [er,wr,ar] = Qr.gens(); #print "er = " + str(er); #print "wr = " + str(wr); #print "ar = " + str(ar); print; Qwx = PolyRing(Qr,"wx",PolyRing.lex); print "Qwx = " + str(Qwx); [ewx,wwx,ax,wx] = Qwx.gens(); #print "ewx = " + str(ewx); print "ax = " + str(ax); #print "wwx = " + str(wwx); print "wx = " + str(wx); print; #rootx = wx**5 - ax; # difficult rootx = wx**2 - ax; # simple print "rootx = " + str(rootx); Q2x = AN(rootx,field=True); print "Q2x = " + str(Q2x.factory()); [ex2,w2x2,ax2,wx] = Q2x.gens(); #print "ex2 = " + str(ex2); #print "w2x2 = " + str(w2x2); #print "ax2 = " + str(ax2); #print "wx = " + str(wx); print; Yr = PolyRing(Q2x,"y",PolyRing.lex) print "Yr = " + str(Yr); [e,w2,x,wx,y] = Yr.gens(); print "e = " + str(e); print "w2 = " + str(w2); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print; #f = ( y**5 - x ) * ( y**2 - 2 ); f = ( y**2 - x ) * ( y**2 - 2 ); #f = ( y**2 - x )**5 * ( y**2 - 2 )**3; #f = ( y**4 - x * 2 ); #f = ( y**7 - x * 2 ); #f = ( y**2 - 2 ); #f = ( y**2 - x ); #f = ( w2 * y**2 - 1 ); #f = ( y**2 - 1/x ); #f = ( y**2 - 3 ); # 1/2 = 3 mod 5 #f = ( y**2 - 1/x ) * ( y**2 - 3 ); # 1/2 = 3 mod 5 print "f = ", f; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; #print "factor time =", t, "milliseconds"; #sys.exit(); print "f = ", f; g = e; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h; h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans_build.py000066400000000000000000000026551445075545500251170ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import QQ, AN, RF, EF, Ring, PolyRing from jas import terminate, startLog # polynomial examples: factorization over Q(sqrt(2))(x)(sqrt(x))[y] Yr = EF(QQ()).extend("w2","w2^2 - 2").extend("x").extend("wx","wx^2 - x").polynomial("y").build(); print "Yr = " + str(Yr); print #is automatic: [one,w2,x,wx,y] = Yr.gens(); print "one = " + str(one); print "w2 = " + str(w2); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print; f = ( y**2 - x ) * ( y**2 - 2 ); #f = ( y**2 - x )**2 * ( y**2 - 2 )**3; #f = ( y**4 - x * 2 ); #f = ( y**7 - x * 2 ); #f = ( y**2 - 2 ); #f = ( y**2 - x ); #f = ( w2 * y**2 - 1 ); #f = ( y**2 - 1/x ); #f = ( y**2 - (1,2) ); #f = ( y**2 - 1/x ) * ( y**2 - (1,2) ); print "f = ", f; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #print "G = ", G; #print "factor time =", t, "milliseconds"; #sys.exit(); print "f = ", f; g = one; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h; h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans_build.rb000066400000000000000000000025441445075545500250670ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Q(sqrt(2))(x)(sqrt(x))[y] Yr = EF.new(QQ()).extend("w2","w2^2 - 2").extend("x").extend("wx","wx^2 - x").polynomial("y").build(); puts "Yr = " + str(Yr); puts #is automatic: one,w2,x,wx,y = Yr.gens(); puts "one = " + str(one); puts "w2 = " + str(w2); puts "x = " + str(x); puts "wx = " + str(wx); puts "y = " + str(y); puts; f = ( y**2 - x ) * ( y**2 - 2 ); #f = ( y**2 - x )**2 * ( y**2 - 2 )**3; #f = ( y**4 - x * 2 ); #f = ( y**7 - x * 2 ); #f = ( y**2 - 2 ); #f = ( y**2 - x ); #f = ( w2 * y**2 - 1 ); #f = ( y**2 - 1/x ); #f = ( y**2 - (1,2) ); #f = ( y**2 - 1/x ) * ( y**2 - (1,2) ); puts "f = ", f; puts; #exit(); startLog(); t = System.currentTimeMillis(); G = Yr.factors(f); t = System.currentTimeMillis() - t; #puts "G = ", G; #puts "factor time =", t, "milliseconds"; #exit(); puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end #puts "g = " + str(g); puts; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algeb_trans_charp.py000066400000000000000000000042601445075545500251070ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import Ring, PolyRing from jas import ZM, QQ, AN, RF from jas import terminate, startLog # polynomial examples: factorization over Z_p(x)(sqrt{3}(x))[y] Q = PolyRing(ZM(5),"x",PolyRing.lex); print "Q = " + str(Q); [e,a] = Q.gens(); #print "e = " + str(e); print "a = " + str(a); Qr = RF(Q); print "Qr = " + str(Qr.factory()); [er,ar] = Qr.gens(); #print "er = " + str(er); #print "ar = " + str(ar); print; Qwx = PolyRing(Qr,"wx",PolyRing.lex); print "Qwx = " + str(Qwx); [ewx,ax,wx] = Qwx.gens(); #print "ewx = " + str(ewx); print "ax = " + str(ax); print "wx = " + str(wx); print; rootx = wx**3 - ax; print "rootx = " + str(rootx); Q2x = AN(rootx,field=True); print "Q2x = " + str(Q2x.factory()); [ex2,ax2,wx] = Q2x.gens(); #print "ex2 = " + str(ex2); #print "w2x2 = " + str(w2x2); #print "ax2 = " + str(ax2); #print "wx = " + str(wx); print; #Yr = PolyRing(Q2x,"y,z,c0,c1,c2",PolyRing.lex) Yr = PolyRing(Q2x,"y,z",PolyRing.lex) print "Yr = " + str(Yr); #[e,x,wx,y,z,c0,c1,c2] = Yr.gens(); [e,x,wx,y,z] = Yr.gens(); print "e = " + str(e); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print "z = " + str(z); print; #f = ( y**2 - x ); #f = ( y**2 - ( wx**2 + wx + 2 ) ); f = ( y**2 - ( wx**2 + wx + 2 ) + z**2 + y * wx ); #f = wx**3; print "f = ", f; print; f = f**5; print "f = ", f; print; #g = ( y**2 + ( c0 + c1 * wx + c2 * wx**2 ) ); #print "g = ", g; #g = g**5; #print "g = ", g; #print; #sys.exit(); startLog(); t = System.currentTimeMillis(); #ok: G = Yr.factors(f); G = Yr.squarefreeFactors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; #sys.exit(); print "f = ", f; g = e; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h; h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_algebp_trans_charp.py000066400000000000000000000045041445075545500252700ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import Ring, PolyRing from jas import ZM, QQ, AN, RF from jas import terminate, startLog # polynomial examples: factorization over Z_p(x)(sqrt{p}(x))[y] Q = PolyRing(ZM(5),"x",PolyRing.lex); print "Q = " + str(Q); [e,a] = Q.gens(); #print "e = " + str(e); print "a = " + str(a); Qr = RF(Q); print "Qr = " + str(Qr.factory()); [er,ar] = Qr.gens(); #print "er = " + str(er); #print "ar = " + str(ar); print; Qwx = PolyRing(Qr,"wx",PolyRing.lex); print "Qwx = " + str(Qwx); [ewx,ax,wx] = Qwx.gens(); #print "ewx = " + str(ewx); print "ax = " + str(ax); print "wx = " + str(wx); print; #rootx = wx**5 - 2; # not working #rootx = wx**5 - 1/ax; #rootx = wx**5 - ax; #rootx = wx**5 - ( ax**2 + 3 * ax ); rootx = wx**5 - ( ax**2 + 3 / ax ); print "rootx = " + str(rootx); Q2x = AN(rootx,field=True); print "Q2x = " + str(Q2x.factory()); [ex2,ax2,wx] = Q2x.gens(); #print "ex2 = " + str(ex2); #print "w2x2 = " + str(w2x2); #print "ax2 = " + str(ax2); #print "wx = " + str(wx); print; #Yr = PolyRing(Q2x,"y,z,c0,c1,c2",PolyRing.lex) Yr = PolyRing(Q2x,"y,z",PolyRing.lex) print "Yr = " + str(Yr); #[e,x,wx,y,z,c0,c1,c2] = Yr.gens(); [e,x,wx,y,z] = Yr.gens(); print "e = " + str(e); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print "z = " + str(z); print; #f = ( y**2 - x ); f = ( y**2 - ( wx ) ); #f = ( y**2 - ( 1 / wx ) ); #f = ( y**2 - ( wx**2 + wx + 2 ) + z**2 + y * wx ); #f = wx**3; print "f = ", f; print; f = f**5; print "f = ", f; print; #g = ( y**2 + ( c0 + c1 * wx + c2 * wx**2 ) ); #print "g = ", g; #g = g**5; #print "g = ", g; #print; #sys.exit(); startLog(); t = System.currentTimeMillis(); #ok: G = Yr.factors(f); G = Yr.squarefreeFactors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; #sys.exit(); print "f = ", f; g = e; for h, i in G.iteritems(): if i > 1: print "h**i = ", h, "**" + str(i); else: print "h = ", h; h = h**i; g = g*h; #print "g = ", g; print; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_compl.py000066400000000000000000000020741445075545500225640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing from jas import ZM, QQ, AN, RF, CR from jas import terminate, startLog # polynomial examples: complex factorization via algebraic factorization r = PolyRing( CR(QQ()), "x", PolyRing.lex ); print "Ring: " + str(r); print; [one,I,x] = r.gens(); f1 = x**3 - 2; f2 = ( x - I ) * ( x + I ); f3 = ( x**3 - 2 * I ); #f = f1**2 * f2 * f3; f = f1 * f2 * f3; #f = f1 * f2; #f = f1 * f3; #f = f2 * f3; #f = f3; #f = f**3; print "f = ", f; print; #startLog(); t = System.currentTimeMillis(); R = r.factors(f); t = System.currentTimeMillis() - t; #print "R = ", R; #print "complex factor time =", t, "milliseconds"; g = one; for h, i in R.iteritems(): print "h**i = "+ str(h) + "**" + str(i); h = h**i; g = g*h; #print "g = ", g; print if cmp(f,g) == 0: print "complex factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "complex factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_compl_algeb.py000066400000000000000000000045051445075545500237170ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing from jas import ZM, QQ, AN, RF, CR from jas import terminate, startLog # polynomial examples: factorization over Q(i) Qr = PolyRing(QQ(),"i",PolyRing.lex); print "Qr = " + str(Qr); [e,a] = Qr.gens(); print "e = " + str(e); print "a = " + str(a); imag = a**2 + 1; print "imag = " + str(imag); Qi = AN(imag,field=True); print "Qi = " + str(Qi.factory()); [one,i] = Qi.gens(); print "one = " + str(one); print "i = " + str(i); b = i**2 + 1; print "b = " + str(b); c = 1 / i; print "c = " + str(c); #Qix = AN(i**2 + 1); #print "Qix = " + str(Qix.factory()); print; r = PolyRing(Qi,"x",PolyRing.lex) print "r = " + str(r); [one,i,x] = r.gens(); print "one = " + str(one); print "i = " + str(i); print "x = " + str(x); #f = x**7 - 1; f = x**6 + x**5 + x**4 + x**3 + x**2 + x + 1; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", str(len(G)); #print "factor time =", t, "milliseconds"; ## f2 = one; ## for h, i in G.iteritems(): ## print "h**i = (", h, ")**" + str(i); ## h = h**i; ## f2 = f2*h; #print "f2 = ", f2; print; ## if cmp(f,f2) == 0: ## print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; ## else: ## print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,f2); ## print; r2 = PolyRing(Qi,"a,b",PolyRing.lex) print "r2 = " + str(r2); [one,i,a,b] = r2.gens(); print "one = " + str(one); print "i = " + str(i); print "a = " + str(a); print "b = " + str(b); y = a + i * b; #g = y**7 - 1; g = y**6 + y**5 + y**4 + y**3 + y**2 + y + 1; g = - g; print "g = ", g; print; #sys.exit(); #startLog(); t = System.currentTimeMillis(); G = r2.factors(g); t = System.currentTimeMillis() - t; print "#G = ", str(len(G)); #print "factor time =", t, "milliseconds"; ## g2 = one; ## for h, i in G.iteritems(): ## print "h**i = (", h, ")**" + str(i); ## h = h**i; ## g2 = g2*h; print "g = ", g; print; ## if cmp(g,g2) == 0: ## print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; ## else: ## print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(g,g2); ## print; #sys.exit(); #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_me.py000066400000000000000000000043511445075545500220530ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing from jas import ZZ, ZM, QQ, AN, RF, CR from jas import terminate, startLog # polynomial examples: factorization #r = Ring( "Z(x) L" ); r = PolyRing( ZZ(), "(x)", PolyRing.lex ); print "Ring: " + str(r); print; [one,x] = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; #f = (-1+x)*(1+x)*(1+x+x**2)*(1-x+x**2); f = x**16 - 1; # == #f = (-1+x)*(1+x)*(1+x**2)*(1+x**4)*(1+x**8); print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; print "g = ", g; print if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #d = g / c; #m = g % c; #print "d = ", d; #print "m = ", m; #print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mod.py000066400000000000000000000041511445075545500222270ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import GF, PolyRing from jas import terminate, startLog # polynomial examples: factorization over Z_p #r = Ring( "Mod 1152921504606846883 (x) L" ); #r = Ring( "Mod 19 (x) L" ); r = PolyRing( GF(19), "x", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x] = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**2 + 1; f = x**19 + x; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #print "g = ", g; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mod.rb000066400000000000000000000043331445075545500222040ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Z_p #r = Ring( "Mod 1152921504606846883 (x) L" ); #r = Ring( "Mod 19 (x) L" ); r = PolyRing.new( GF(19), "x", PolyRing.lex ); puts "Ring: " + str(r); puts #one,x = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**2 + 1; f = x**19 + x; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; #f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; puts "f = ", f; puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; #puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); puts "#G = ", G.size(); #puts "factor time =", t, "milliseconds"; puts; puts "f = " + str(f); puts g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end puts; #puts "g = ", g; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mod_abs.py000066400000000000000000000015121445075545500230520ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, ZM, GF, QQ from jas import terminate, startLog # polynomial examples: absolute factorization over Z_p #r = PolyRing(GF(19),"x",PolyRing.lex ); #r = PolyRing(GF(23),"x",PolyRing.lex ); r = PolyRing(GF(1152921504606846883),"(x)",PolyRing.lex); #r = PolyRing(GF(32003),"(x)",PolyRing.lex); #r = PolyRing(GF(65413),"(x)",PolyRing.lex); #r = PolyRing(GF(536870909),"(x)",PolyRing.lex); print "Ring: " + str(r); print; #[one,x] = r.gens(); #f = x**4 - 1; #f = x**3 + 1; f = x**3 - x - 1; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; print "G = ", G.toScript(); print "factor time =", t, "milliseconds"; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mod_abs.rb000066400000000000000000000014541445075545500230320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: absolute factorization over Z_p #r = PolyRing.new( GF(19), "x", PolyRing.lex ); #r = PolyRing.new( GF(23), "x", PolyRing.lex ); r = PolyRing.new( GF(1152921504606846883), "x", PolyRing.lex ); #r = PolyRing.new(GF(32003),"(x)",PolyRing.lex); #r = PolyRing.new(GF(65413),"(x)",PolyRing.lex); #r = PolyRing.new(GF(536870909),"(x)",PolyRing.lex); puts "Ring: " + str(r); puts #one,x = r.gens(); #f = x**4 - 1; #f = x**3 + 1; f = x**3 - x - 1; puts "f = ", f; puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); #G = r.factors(f); G = r.factorsAbsolute(f); t = System.currentTimeMillis() - t; puts "G = ", G.toScript(); puts "factor time = " + str(t) + " milliseconds"; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mod_ins.py000066400000000000000000000031661445075545500231050ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import PolyRing, ZM, QQ, RF, GF from jas import terminate, startLog # polynomial examples: factorization over Z_p, with p-th root p = 5; cr = PolyRing(GF(p),"u",PolyRing.lex ); print "Ring cr: " + str(cr); #[one,u] = cr.gens(); fu = (u**2+u+1)**p; print "fu = ", fu; print; t = System.currentTimeMillis(); G = cr.squarefreeFactors(fu); t = System.currentTimeMillis() - t; #print "G = ", G; #.toScript(); print "factor time =", t, "milliseconds"; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; print; qcr = RF(cr); print "Ring qcr: " + str(qcr.factory()); #not ok#r = PolyRing(cr,"x",PolyRing.lex ); r = PolyRing(qcr,"x",PolyRing.lex ); print "Ring r: " + str(r); #qr = RF(r); #print "Ring qr: " + str(qr.factory()); print; #[one,u,x] = r.gens(); print "one = " + str(one); print "u = " + str(u); print "x = " + str(x); #f = x**3 - u; #f = (x - u)**3; #f = (x - u**3)**3; #f = (x - u**9)**3; #f = x**p - u; #f = (x - u)**p; p2 = p * 2; fu = (u**2+u+1)**p; #f = x**p + 1/fu; f = x**p + fu; #f = x**p2 - fu * x**p - fu; #f = x**p2 + x**p + 1; #f = x**p2 + 1; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.squarefreeFactors(f); #G = r.factorsAbsolute(f); #G = None; t = System.currentTimeMillis() - t; #print "G = ", G; #.toScript(); print "factor time =", t, "milliseconds"; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; print; gu = u**2+u+1; #g = (x + 1/gu); g = (x + gu); print "g = ", g; g = g**p; print "g**p = ", g; print; terminate(); java-algebra-system-2.7.200/examples/factors_mod_ins.rb000066400000000000000000000025101445075545500230500ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Z_p, with p-th root p = 5; cr = PolyRing.new( GF(p), "u", PolyRing.lex ); puts "Ring: " + str(cr); puts #one,u = r.gens(); fu = (u**2+u+1)**p; puts "fu = ", fu; puts; startLog(); t = System.currentTimeMillis(); G = cr.squarefreeFactors(fu); #G = cr.factors(fu); t = System.currentTimeMillis() - t; puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); #puts "G = ", G; puts "factor time = " + str(t) + " milliseconds"; qcr = RF(cr); puts "Ring qcr: " + str(qcr.factory()); #not ok#r = PolyRing(cr,"x",PolyRing.lex ); r = PolyRing.new(qcr,"x",PolyRing.lex ); puts "Ring r: " + str(r); #f = x**3 - u; #f = (x - u)**3; #f = (x - u**3)**3; #f = (x - u**9)**3; #f = x**p - u; #f = (x - u)**p; p2 = p * 2; fu = (u**2+u+1)**p; #f = x**p + 1/fu; f = x**p + fu; #f = x**p2 - fu * x**p - fu; #f = x**p2 + x**p + 1; #f = x**p2 + 1; puts "f = ", f; puts; t = System.currentTimeMillis(); G = r.squarefreeFactors(f); #G = r.factors(f); t = System.currentTimeMillis() - t; #puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); puts "#G = ", G.size(); puts "factor time = " + str(t) + " milliseconds"; gu = u**2+u+1; #g = (x + 1/gu); g = (x + gu); puts "g = " + str(g); gp = g**p; puts "g**p = " + str(gp); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mult.py000066400000000000000000000030541445075545500224320ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, ZZ, GF, QQ from jas import terminate, startLog # polynomial examples: multivariate factorization #r = Ring( "Mod 1152921504606846883 (x,y,z) L" ); #r = Ring( "Rat(x,y,z) L" ); #r = Ring( "C(x,y,z) L" ); #r = Ring( "Mod 3 (x,y,z) L" ); #r = Ring( "Z(x,y,z) L" ); r = PolyRing( ZZ(), "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x,y,z] = r.gens(); #f = z * ( y + 1 )**2 * ( x**2 + x + 1 )**3; #f = z * ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + z**2 ) * ( x**2 + x + 1 ); #f = x**4 * y + x**3 + z + x + z**2 + y * z**2; ## f = x**3 + ( ( y + 2 ) * z + 2 * y + 1 ) * x**2 \ ## + ( ( y + 2 ) * z**2 + ( y**2 + 2 * y + 1 ) * z + 2 * y**2 + y ) * x \ ## + ( y + 1 ) * z**3 + ( y + 1 ) * z**2 + ( y**3 + y**2 ) * z + y**3 + y**2; #f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + z**2 ); f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + 1 ); #f = ( x + y ) * ( x - y); print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #print "g = ", g; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_mult.rb000066400000000000000000000027771445075545500224200ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: multivariate factorization r = PolyRing.new( ZZ(), "x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts #one,x,y,z = r.gens(); #f = z * ( y + 1 )**2 * ( x**2 + x + 1 )**3; #f = z * ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + z**2 ) * ( x**2 + x + 1 ); #f = x**4 * y + x**3 + z + x + z**2 + y * z**2; ## f = x**3 + ( ( y + 2 ) * z + 2 * y + 1 ) * x**2 \ ## + ( ( y + 2 ) * z**2 + ( y**2 + 2 * y + 1 ) * z + 2 * y**2 + y ) * x \ ## + ( y + 1 ) * z**3 + ( y + 1 ) * z**2 + ( y**3 + y**2 ) * z + y**3 + y**2; #f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + z**2 ); f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + 1 ); #f = ( x + y ) * ( x - y); puts "f = ", f; puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); #puts "G = ", G; #puts "factor time =", t, "milliseconds"; puts; puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end puts; #puts "g = ", g; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_poly.py000066400000000000000000000026771445075545500224460ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, QQ from jas import terminate, startLog # polynomial examples: recursive factorization cr = PolyRing(QQ(),"x",PolyRing.lex ); print "Ring cr: " + str(cr); print; r = PolyRing(cr,"y,z",PolyRing.lex ); print "Ring: " + str(r); print; [one,x,y,z] = r.gens(); #f = z * ( y + 1 )**2 * ( x**2 + x + 1 )**3; #f = z * ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + z**2 ) * ( x**2 + x + 1 ); #f = x**4 * y + x**3 + z + x + z**2 + y * z**2; ## f = x**3 + ( ( y + 2 ) * z + 2 * y + 1 ) * x**2 \ ## + ( ( y + 2 ) * z**2 + ( y**2 + 2 * y + 1 ) * z + 2 * y**2 + y ) * x \ ## + ( y + 1 ) * z**3 + ( y + 1 ) * z**2 + ( y**3 + y**2 ) * z + y**3 + y**2; f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + z**2 ); #f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + 1 ); #f = ( x + y ) * ( x - y); print "f = ", f; print; startLog(); t = System.currentTimeMillis(); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #print "g = ", g; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_poly.rb000066400000000000000000000031061445075545500224050ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: recursive factorization cr = PolyRing.new( QQ(), "x", PolyRing.lex ); puts "Ring: " + str(cr); puts; r = PolyRing.new( cr, "y,z", PolyRing.lex ); puts "Ring: " + str(r); puts #one,x,y,z = r.gens(); #f = z * ( y + 1 )**2 * ( x**2 + x + 1 )**3; #f = z * ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + 1 ) * ( x**2 + x + 1 ); #f = ( y + z**2 ) * ( x**2 + x + 1 ); #f = x**4 * y + x**3 + z + x + z**2 + y * z**2; ## f = x**3 + ( ( y + 2 ) * z + 2 * y + 1 ) * x**2 \ ## + ( ( y + 2 ) * z**2 + ( y**2 + 2 * y + 1 ) * z + 2 * y**2 + y ) * x \ ## + ( y + 1 ) * z**3 + ( y + 1 ) * z**2 + ( y**3 + y**2 ) * z + y**3 + y**2; f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + z**2 ); #f = ( x + y * z + y + z + 1 ) * ( x**2 + ( y + z ) * x + y**2 + 1 ); #f = ( x + y ) * ( x - y); puts "f = ", f; puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); #puts "G = ", G; #puts "factor time =", t, "milliseconds"; puts; puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end puts; #puts "g = ", g; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_rat.py000066400000000000000000000040531445075545500222370ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, QQ from jas import terminate, startLog # polynomial examples: factorization over Q #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing( QQ(), "x", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x] = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; print "#G = ", len(G); #print "factor time =", t, "milliseconds"; g = one; for h, i in G.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #print "g = ", g; if cmp(f,g) == 0: print "factor time =", t, "milliseconds,", "isFactors(f,g): true" ; else: print "factor time =", t, "milliseconds,", "isFactors(f,g): ", cmp(f,g); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/factors_rat.rb000066400000000000000000000041401445075545500222070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: factorization over Q r = PolyRing.new( QQ(), "x", PolyRing.lex ); puts "Ring: " + str(r); puts #one,x = r.gens(); #f = x**15 - 1; #f = x * ( x + 1 )**2 * ( x**2 + x + 1 )**3; #f = x**6 - 3 * x**5 + x**4 - 3 * x**3 - x**2 - 3 * x+ 1; #f = x**(3*11*11) + 3 * x**(2*11*11) - x**(11*11); #f = x**(3*11*11*11) + 3 * x**(2*11*11*11) - x**(11*11*11); #f = (x**2+1)*(x-3)*(x-5)**3; #f = x**4 + 1; #f = x**12 + x**9 + x**6 + x**3 + 1; #f = x**24 - 1; #f = x**20 - 1; #f = x**22 - 1; #f = x**8 - 40 * x**6 + 352 * x**4 - 960 * x**2 + 576; #f = 362408718672000 * x**9 + 312179013226080 * x**8 - 591298435728000 * x**6 - 509344705789920 * x**5 - 1178946881112000 * x**2 - 4170783473878580 * x - 2717923400363451; #f = 292700016000 * x**8 + 614670033600 * x**7 - 417466472400 * x**6 - 110982089400 * x**5 + 1185906158780 * x**4 - 161076194335 * x**3 + 204890011200 * x**2 - 359330651400 * x - 7719685302; #f = x**10 - 212 * x**9 - 1760 * x**8 + 529 * x**7 - 93699 * x**6 - 726220 * x**5 + 37740 * x**4 + 169141 * x**3 + 24517680 * x**2 - 9472740; #f = x**4 - 1; #f = x**3 - x**2 + x - 1; #f = x**8 + 4 * x**6 + 8 * x**4 - 8 * x**2 + 4; #f = x**16 + 272 * x**12 - 7072 * x**8 + 3207424 * x**4 + 12960000; #f = x**16 + 16 * x**12 + 96 * x**8 + 256 * x**4 + 256; f = x**24 + 272 * x**20 - 7072 * x**16 + 3207424 * x**12 + 12960000 * x**8; puts "f = ", f; puts; startLog(); t = System.currentTimeMillis(); #G = r.squarefreeFactors(f); G = r.factors(f); t = System.currentTimeMillis() - t; puts "G = ", str(G.map{ |h,i| str(h)+"**"+str(i)+" " }); #puts "G = ", G; #puts "factor time =", t, "milliseconds"; puts; puts "f = " + str(f); g = one; for h, i in G do if i > 1 then puts "h**i = " + str(h) + "**" + str(i); else puts "h = " + str(h); end h = h**i; g = g*h; end puts; #puts "g = ", g; if f == g then puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): true" ; else puts "factor time = " + str(t) + " milliseconds," + " isFactors(f,g): " + str(f==g); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/finitefield.py000066400000000000000000000031301445075545500222050ustar00rootroot00000000000000# jython examples for jas. # $Id$ # import sys, operator from java.lang import System from jas import FF, GF, PolyRing from jas import terminate # finite fields and algebraic field extensions #print "------- finite field GF(17,5) ---------"; r = FF(17,5); print "r = " + str(r.ring.toScript()); e,a = r.gens(); print "e = " + str(e); print "a = " + str(a); ap = a**5 - a + 1; print "ap = " + str(ap); ai = 1/ap; print "ai = " + str(ai) + ", ai*ap = " + str(ai*ap); q = FF(17,5); print "q = " + str(q.ring.toScript()); qe,qa = q.gens(); print "qe = " + str(qe); print "qa = " + str(qa); qap = qa**5 - qa + 1; print "qap = " + str(qap); s = ap - qap; print "s = " + str(s); ar = PolyRing(r,"beta",PolyRing.lex); print "ar = " + str(ar); e,a,b = ar.gens(); print "e = " + str(e); print "a = " + str(a); print "b = " + str(b); p = a**5 - a + beta**5 - (a**3 + a)*beta; #p = p*p; print "p = " + str(p); x = p.factors(); print "x = " + ", ".join([ str(pp)+"**"+str(i) for (pp,i) in x.iteritems() ]); g = reduce(operator.mul, [ pp**i for (pp,i) in x.iteritems() ], e); print "g = " + str(g); #print "p-g: " + str(p-g); print "isFactors(p,x): " + str(p == g); print; #mod = r.ring.modul; #print "mod = " + str(mod); pg = r.gens()[1]; #pg = RingElem(r.ring.modul.ring.generators()[1]); print "pg = " + str(pg); pol = pg**(17**5) - pg; print "pg**(17**5) - pg = " + str(pol); pol = pg**(17**5-1); print "pg**(17**5-1) = " + str(pol); print "17**5 = " + str(17**5); print terminate(); java-algebra-system-2.7.200/examples/finitefield.rb000066400000000000000000000033541445075545500221700ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # finite fields and algebraic field extensions startLog(); #puts "------- finite field GF(17,5) ---------"; r = FF(17,5); puts "r = " + str(r.ring.toScript); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); ap = a**5 - a + 1; puts "ap = " + str(ap); ai = 1/ap; puts "ai = " + str(ai) + ", ai*ap = " + str(ai*ap); q = FF(17,5); puts "q = " + str(q.ring.toScript); qe,qa = q.gens(); puts "qe = " + str(qe); puts "qa = " + str(qa); qap = qa**5 - qa + 1; puts "qap = " + str(qap); s = ap - qap; puts "s = " + str(s); ar = PolyRing.new(r,"beta",PolyRing.lex); puts "ar = " + str(ar); e,a,b = ar.gens(); puts "e = " + str(e); puts "a = " + str(a); puts "b = " + str(b); p = a**5 - a + beta**5 - (a**3 + a)*beta; #p = p*p; puts "p = " + str(p); x = p.factors(); puts "x = " + x.map{ |p,i| str(p)+"**"+str(i) }.join(", "); g = x.map{ |p,i| p**i }.reduce(e, :*); puts "g = " + str(g); puts "isFactors(p,x): " + str(p==g); puts; #mod = r.ring.modul; #puts "mod = " + str(mod); pg = r.gens()[1]; #pg = RingElem.new(r.ring.modul.ring.generators()[1]); puts "pg = " + str(pg); pol = pg**(17**5) - pg; puts "pg**(17**5) - pg = " + str(pol); pol = pg**(17**5-1); puts "pg**(17**5-1) = " + str(pol); puts "17**5 = " + str(17**5); puts r = EF.new(ZM(17)).extend("",5).build(); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); pg = r.gens()[1]; puts "pg = " + str(pg); pol = pg**(17**5) - pg; puts "pg**(17**5) - pg = " + str(pol); pol = pg**(17**5-1); puts "pg**(17**5-1) = " + str(pol); puts "17**5 = " + str(17**5); puts terminate(); java-algebra-system-2.7.200/examples/freealg-C_417_X.py000066400000000000000000000054341445075545500224030ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # from java.lang import System from jas import WordRing, WordPolyRing, WordIdeal from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # non-commutative polynomial examples: C_4_1_7_X example #r = WordPolyRing(QQ,"x4,x3,x2,x1"); #r = WordPolyRing(GF(19),"x4,x3,x2,x1"); #r = WordPolyRing(QQ(),"x1,x2,x3,x4"); #r = WordPolyRing(ZZ(),"x1,x2,x3,x4"); #r = WordPolyRing(GF(19),"x1,x2,x3,x4"); #r = WordPolyRing(GF(32003),"x1,x2,x3,x4"); r = WordPolyRing(GF(2**29-3),"x1,x2,x3,x4"); #r = WordPolyRing(GF(2**63-25),"x1,x2,x3,x4"); #r = WordPolyRing(GF(170141183460469231731687303715884105727),"x1,x2,x3,x4"); #r = WordPolyRing(GF(259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071),"x1,x2,x3,x4"); print "WordPolyRing: " + str(r); print; #one,x4,x3,x2,x1 = r.gens(); one,x1,x2,x3,x4 = r.gens(); print "one = " + str(one); print "x4 = " + str(x4); print "x3 = " + str(x3); print "x2 = " + str(x2); print "x1 = " + str(x1); print; f1 = x4*x4 - 25*x4*x2 - x1*x4 - 6*x1*x3 - 9*x1*x2 + x1*x1; f2 = x4*x4 - 4*x4*x3 + 13*x4*x2 + 12*x4*x1 - 9*x3*x4 + 4*x3*x2 + 41*x3*x1 - 7*x1*x4 - x1*x2; f3 = x4*x4 + 12*x4*x3 - 4*x3*x3 - 9*x3*x2 + 9*x1*x4 + x1*x1; f4 = x4*x4 - 14*x4*x3 - 17*x4*x2 - 5*x2*x2 - 42*x1*x4; f5 = x4*x4 - 2*x4*x3 + 2*x4*x2 - 7*x4*x1 - x2*x2 - 13*x2*x1 - 4*x1*x3 + 2*x1*x2 - x1*x1; f6 = x4*x4 + 7*x4*x2 - 15*x4*x1 - 9*x3*x4 + 4*x2*x2 + 15*x2*x1 + x1*x2; print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); print "f4 = " + str(f4); print "f5 = " + str(f5); print "f6 = " + str(f6); print ff = r.ideal( "", [f1,f2,f3,f4,f5,f6] ); #]) # print "ff = " + str(ff); print; startLog(); gg = ff.GB(); print "gg = " + str(gg); print print "isGB(gg) = " + str(gg.isGB()); print #hh = gg.sum(gg); #hh = hh.GB(); #print "hh = " + str(hh); #print #print "gg == hh: " + (gg === hh).to_s; #print #print "isGB(hh) = " + str(hh.isGB()); #print java-algebra-system-2.7.200/examples/freealg-C_417_X.rb000066400000000000000000000053011445075545500223470ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # non-commutative polynomial examples: C_4_1_7_X example #r = WordPolyRing.new(QQ,"x4,x3,x2,x1"); #r = WordPolyRing.new(GF(19),"x4,x3,x2,x1"); #r = WordPolyRing.new(QQ,"x1,x2,x3,x4"); #r = WordPolyRing.new(ZZ,"x1,x2,x3,x4"); #r = WordPolyRing.new(GF(19),"x1,x2,x3,x4"); #r = WordPolyRing.new(GF(32003),"x1,x2,x3,x4"); r = WordPolyRing.new(GF(2**29-3),"x1,x2,x3,x4"); #r = WordPolyRing.new(GF(2**63-25),"x1,x2,x3,x4"); #r = WordPolyRing.new(GF(170141183460469231731687303715884105727),"x1,x2,x3,x4"); #r = WordPolyRing.new(GF(259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071),"x1,x2,x3,x4"); puts "WordPolyRing: " + str(r); puts; #one,x4,x3,x2,x1 = r.gens(); one,x1,x2,x3,x4 = r.gens(); puts "one = " + str(one); puts "x4 = " + str(x4); puts "x3 = " + str(x3); puts "x2 = " + str(x2); puts "x1 = " + str(x1); puts; f1 = x4*x4 - 25*x4*x2 - x1*x4 - 6*x1*x3 - 9*x1*x2 + x1*x1; f2 = x4*x4 - 4*x4*x3 + 13*x4*x2 + 12*x4*x1 - 9*x3*x4 + 4*x3*x2 + 41*x3*x1 - 7*x1*x4 - x1*x2; f3 = x4*x4 + 12*x4*x3 - 4*x3*x3 - 9*x3*x2 + 9*x1*x4 + x1*x1; f4 = x4*x4 - 14*x4*x3 - 17*x4*x2 - 5*x2*x2 - 42*x1*x4; f5 = x4*x4 - 2*x4*x3 + 2*x4*x2 - 7*x4*x1 - x2*x2 - 13*x2*x1 - 4*x1*x3 + 2*x1*x2 - x1*x1; f6 = x4*x4 + 7*x4*x2 - 15*x4*x1 - 9*x3*x4 + 4*x2*x2 + 15*x2*x1 + x1*x2; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts "f4 = " + str(f4); puts "f5 = " + str(f5); puts "f6 = " + str(f6); puts ff = r.ideal( "", [f1,f2,f3,f4,f5,f6] ); #]) # puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts puts "isGB(gg) = " + str(gg.isGB()); puts #hh = gg.sum(gg); #hh = hh.GB(); #puts "hh = " + str(hh); #puts #puts "gg == hh: " + (gg === hh).to_s; #puts #puts "isGB(hh) = " + str(hh.isGB()); #puts java-algebra-system-2.7.200/examples/gbisc97.rb000066400000000000000000000016671445075545500211620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # jruby examples for jas. # $Id$ # require "examples/jas" # GB examples, ISSAC system challenge 1997 #r = PolyRing.new( QQ(), "w,z,y,x", PolyRing.grad ); r = PolyRing.new( ZZ(), "w,z,y,x", PolyRing.grad ); #r = PolyRing.new( ZZ(), "w,z,y,x", PolyRing.lex ); puts "Ring: " + str(r); puts; f1 = 8*w**2 + 5*w*x - 4*w*y + 2*w*z + 3*w + 5*x**2 + 2*x*y - 7*x*z - 7*x + 7*y**2 - 8*y*z - 7*y + 7*z**2 - 8*z + 8; f2 = 3*w**2 - 5*w*x - 3*w*y - 6*w*z + 9*w + 4*x**2 + 2*x*y - 2*x*z + 7*x + 9*y**2 + 6*y*z + 5*y + 7*z**2 + 7*z + 5; f3 = - 2*w**2 + 9*w*x + 9*w*y - 7*w*z - 4*w + 8*x**2 + 9*x*y - 3*x*z + 8*x + 6*y**2 - 7*y*z + 4*y - 6*z**2 + 8*z + 2; f4 = 7*w**2 + 5*w*x + 3*w*y - 5*w*z - 5*w + 2*x**2 + 9*x*y - 7*x*z + 4*x - 4*y**2 - 5*y*z + 6*y - 4*z**2 - 9*z + 2; ff = [f1,f2,f3,f4]; f = r.ideal( "", ff ); puts "Ideal: " + str(f); puts; #startLog(); #exit(0) rg = f.GB(); puts "seq GB:", rg; puts; #terminate(); java-algebra-system-2.7.200/examples/gbks.jas000066400000000000000000000031311445075545500207770ustar00rootroot00000000000000#(*example 7.5.90, ks, hk, uni passau. *) #(*coefficients: rational numbers or integers mod 3. *) #(*variables: *) (a4k1,a4k3,a5k1,a5k2,a5k3,a6k2,a6k3,a7k1,a7k2, a7k3,a8k1,a8k2,a9k1,a9k2,a9k3, a10k1,a10k2,a10k3,a11k1,a11k2, a11k3,a12k1,a12k2,a12k3) G #(*polynomials: *) ( ( -a9k3 - a9k2*a4k3 - 1 ), ( a8k2*a9k3 + a9k2 +1 ), ( a7k3 + a7k1*a6k3 +1 ), ( a7k1 + a8k1*a7k3 +1 ), ( a4k1*a5k2 + a5k1 +1 ), ( a5k1*a6k2 + a5k2 +1 ), ( a4k1*a5k2*a10k3 - a4k1*a10k2*a5k3 + a5k1*a10k3 + a5k1*a10k2*a4k3 - a10k1*a5k3 - a10k1*a5k2*a4k3 -1 ), ( a4k1*a9k2*a10k3 - a4k1*a10k2*a9k3 + a9k1*a10k3 + a9k1*a10k2*a4k3 - a10k1*a9k3 - a10k1*a9k2*a4k3 +1 ), ( a5k1*a6k2*a11k3 - a5k1*a11k2*a6k3 + a5k2*a11k3 - a11k2*a5k3 + a11k1*a5k2*a6k3 - a11k1*a6k2*a5k3 -1 ), ( a5k1*a10k2*a11k3 - a5k1*a11k2*a10k3 - a10k1*a5k2*a11k3 + a10k1*a11k2*a5k3 + a11k1*a5k2*a10k3 - a11k1*a10k2*a5k3 +1 ), ( -a7k2*a11k3 + a11k2*a7k3 - a7k1*a6k2*a11k3 + a7k1*a11k2*a6k3 + a11k1*a6k2*a7k3 - a11k1*a7k2*a6k3 -1 ), ( a7k1*a8k2*a12k3 + a7k1*a12k2 - a8k1*a7k2*a12k3 + a8k1*a12k2*a7k3 - a12k1*a7k2 - a12k1*a8k2*a7k3 -1 ), ( a7k1*a11k2*a12k3 - a7k1*a12k2*a11k3 - a11k1*a7k2*a12k3 + a11k1*a12k2*a7k3 + a12k1*a7k2*a11k3 - a12k1*a11k2*a7k3 +1 ), ( a8k1*a9k2*a12k3 - a8k1*a12k2*a9k3 - a9k1*a8k2*a12k3 - a9k1*a12k2 + a12k1*a8k2*a9k3 + a12k1*a9k2 -1 ), ( a9k1*a10k2*a12k3 - a9k1*a12k2*a10k3 - a10k1*a9k2*a12k3 + a10k1*a12k2*a9k3 + a12k1*a9k2*a10k3 - a12k1*a10k2*a9k3 -1 ), ( a10k1*a11k2*a12k3 - a10k1*a12k2*a11k3 - a11k1*a10k2*a12k3 + a11k1*a12k2*a10k3 + a12k1*a10k2*a11k3 - a12k1*a11k2*a10k3 +1 ) ) #(*wanted Groebner base. *) #(* -EOF- *) java-algebra-system-2.7.200/examples/gbs.py000066400000000000000000000025111445075545500205000ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, QQ, ZZ, RingElem from jas import startLog, terminate # GB examples #r = Ring( "Z(t,x,y,z) L" ); #r = Ring( "Mod 11(t,x,y,z) L" ); #r = Ring( "Rat(t,x,y) L" ); r = PolyRing( QQ(), "t,x,y", PolyRing.lex ); #r = PolyRing( ZZ(), "t,x,y", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( t - x - 2 y ), ( x^4 + 4 ), ( y^4 + 4 ) ) """; # ( y^4 + 4 x y^3 - 2 y^3 - 6 x y^2 + 1 y^2 + 6 x y + 2 y - 2 x + 3 ), # ( x^2 + 1 ), # ( y^3 - 1 ) # ( y^2 + 2 x y + 2 y + 2 x + 1 ), # ( y^4 + 4 x - 2 y^3 - 6 x + 1 y^2 + 6 x + 2 y - 2 x + 3 ), # ( t - x - 2 y ), # ( 786361/784 y^2 + 557267/392 y + 432049/784 ), # ( x^7 + 3 y x^4 + 27/8 x^4 + 2 y x^3 + 51/7 x^3 + 801/28 y + 1041/56 ) # ( x**2 + 1 ), # ( y**2 + 1 ) f = r.ideal( ps ); print "Ideal: " + str(f); print; startLog(); rg = f.GB(); print "seq GB:", rg; print; #p = t**16 + 272 * t**12 - 7072 * t**8 + 3207424 * t**4 + 12960000; p = t - x - 2*y; #p = p * (y**4 + 4); p = abs(p); n = f.reduction(p); print "p = %s, n = %s " % (p,n); print; n = rg.reduction(p); print "p = %s, n = %s " % (p,n); print; N = rg.lift(p); print "p = %s, N = %s " % (p,[ str(a) for a in N ]); print; pp = sum([ ci * RingElem(ni) for ci, ni in zip( N, rg.pset.list ) ]) print "N * rg == p:", pp == p #terminate(); java-algebra-system-2.7.200/examples/gbs.rb000066400000000000000000000024311445075545500204540ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # GB examples #r = Ring.new( "Z(t,x,y,z) L" ); #r = Ring.new( "Mod 11(t,x,y,z) L" ); #r = Ring.new( "Rat(t,x,y) L" ); r = PolyRing.new( QQ(), "t,x,y", PolyRing.lex ); #r = PolyRing.new( ZZ(), "t,x,y", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( t - x - 2 y ), ( x^4 + 4 ), ( y^4 + 4 ) ) """; # ( y^4 + 4 x y^3 - 2 y^3 - 6 x y^2 + 1 y^2 + 6 x y + 2 y - 2 x + 3 ), # ( x^2 + 1 ), # ( y^3 - 1 ) # ( y^2 + 2 x y + 2 y + 2 x + 1 ), # ( y^4 + 4 x - 2 y^3 - 6 x + 1 y^2 + 6 x + 2 y - 2 x + 3 ), # ( t - x - 2 y ), # ( 786361/784 y^2 + 557267/392 y + 432049/784 ), # ( x^7 + 3 y x^4 + 27/8 x^4 + 2 y x^3 + 51/7 x^3 + 801/28 y + 1041/56 ) # ( x**2 + 1 ), # ( y**2 + 1 ) f = r.ideal( ps ); puts "Ideal: " + str(f); puts; startLog(); rg = f.GB(); puts "seq GB:", rg; puts; #p = t**16 + 272 * t**12 - 7072 * t**8 + 3207424 * t**4 + 12960000; p = t - x - 2*y; #p = p * (y**4 + 4); p = p.abs(); n = f.reduction(p); puts "p = #{p}, n = #{n} "; puts; n = rg.reduction(p); puts "p = #{p}, n = #{n} "; puts; nn = rg.lift(p); ns = nn.map { |x| x.to_s } puts "p = #{p}, ns = #{ns} "; puts; pp = nn.zip(rg.pset.list).map{ |ci,ni| ci*RingElem.new(ni) }.reduce(:+); puts "N * rg == p: " + str(pp == p) puts; #terminate(); java-algebra-system-2.7.200/examples/gcd.py000066400000000000000000000017771445075545500204770ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, ZZ, GF from jas import terminate, startLog # polynomial examples: gcd #r = Ring( "Mod 1152921504606846883 (x,y,z) L" ); #r = Ring( "Rat(x,y,z) L" ); #r = Ring( "C(x,y,z) L" ); #r = Ring( "Z(x,y,z) L" ); r = PolyRing( QQ(), "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x,y,z] = r.gens(); a = r.random(); b = r.random(); c = abs(r.random()); #c = 1; #a = 0; print "a = ", a; print "b = ", b; print "c = ", c; print; ac = a * c; bc = b * c; print "ac = ", ac; print "bc = ", bc; print; t = System.currentTimeMillis(); #d = r.gcd(ac,bc); d = ac.gcd(bc); t = System.currentTimeMillis() - t; #d = d.monic(); print "d = " + str(d); print "d = " + str(d.monic()); m = d % c; ## print "m = ", m; ## print; if m.isZERO(): print "gcd time =", t, "milliseconds,", "isGcd(c,d): true" ; else: print "gcd time =", t, "milliseconds,", "isGcd(c,d): ", str(m); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/gcd.rb000066400000000000000000000020311445075545500204320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: gcd #r = PolyRing.new( ZM(1152921504606846883), "(x,y,z)", PolyRing.lex ); #r = PolyRing.new( CC(), "(x,y,z)", PolyRing.lex ); #r = PolyRing.new( ZZ(), "(x,y,z)", PolyRing.lex ); r = PolyRing.new( QQ(), "x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts; #one,x,y,z = r.gens(); a = r.random(); b = r.random(); c = r.random().abs(); #c = 1; #a = 0; puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts; ac = a * c; bc = b * c; puts "ac = " + str(ac); puts "bc = " + str(bc); puts; #startLog(); t = System.currentTimeMillis(); #d = r.gcd(ac,bc); d = ac.gcd(bc); t = System.currentTimeMillis() - t; #d = d.monic(); puts "d = " + str(d); puts "d = " + str(d.monic()); puts; puts "gcd time = " + str(t) + " milliseconds" ; if r.ring.coFac.isField() m = d % c; #puts "m = " + str(m); #puts; if m.isZERO() puts "isGcd(c,d): true" ; else puts "isGcd(c,d): " + str(m); end end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/gens_define.rb000066400000000000000000000007661445075545500221600ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # test auto defined generators startLog(); r = PolyRing.new( CC(), "(b,s,t,z,p,w)", PolyRing.lex ); puts "Ring: " + r.to_s; puts; puts "1 = " + str(r.one); puts "I = " + str(r.I); puts "b = " + str(r.b); puts "s = " + str(r.s); puts "t = " + str(r.t); puts "z = " + str(r.z); puts "p = " + str(r.p); puts "w = " + str(r.w); puts; x = r.b * r.w + ( r.s - r.t + r.one )**2 + r.z**5; puts "x = " + str(x**2); puts java-algebra-system-2.7.200/examples/getstart-factor.py000066400000000000000000000011111445075545500230310ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import operator from jas import PolyRing, QQ from jas import startLog, terminate # simple factorization example r = PolyRing( QQ(), "x,y,z", PolyRing.lex); # or PolyRing.grad print "PolyRing: " + str(r); print; p = (x+y+z)**11*(x+1)**5*(y+z)**3; #print "p: " + str(p); #print; #startLog(); f = r.factors( p ); print "factors: " + ", ".join( [ str(k) + "**" + str(v) for k,v in f.items() ] ); print; mp = reduce(operator.mul, [ k**v for k,v in f.items() ] ); #print str(mp); print "p == mp: " + str(p == mp); print; startLog(); terminate(); java-algebra-system-2.7.200/examples/getstart-factor.rb000066400000000000000000000007061445075545500230150ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # simple factorization example r = PolyRing.new( QQ(), "x,y,z", PolyRing.lex); # or PolyRing.grad puts "PolyRing: " + str(r); puts; p = (x+y+z)**11*(x+1)**5*(y+z)**3; #puts "p: " + p.to_s; #puts; f = r.factors( p ); puts "factors: " + f.map{ |k,v| k.to_s + "**" + v.to_s }.join(", "); puts; mp = f.map{ |k,v| k**v }.reduce(:*) puts "p == mp: " + (p==mp).to_s puts startLog() terminate() java-algebra-system-2.7.200/examples/getstart-gb.py000066400000000000000000000011511445075545500221470ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import PolyRing, QQ from jas import startLog # trinks 7 example r = PolyRing( QQ(), "B,S,T,Z,P,W", PolyRing.lex); # or PolyRing.grad print "PolyRing: " + str(r); print; ff = [ 45 * P + 35 * S - 165 * B - 36, 35 * P + 40 * Z + 25 * T - 27 * S, 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2, - 9 * W + 15 * T * P + 20 * S * Z, P * W + 2 * T * Z - 11 * B**3, 99 * W - 11 * B * S + 3 * B**2, B**2 + (33,50) * B + (2673,10000) ]; f = r.ideal( "", ff ); print "Ideal: " + str(f); print; #startLog(); g = f.GB(); print "Groebner base: " + str(g); print; java-algebra-system-2.7.200/examples/getstart-gb.rb000066400000000000000000000012231445075545500221220ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # trinks 7 example r = PolyRing.new( QQ(), "B,S,T,Z,P,W", PolyRing.lex); # or PolyRing.grad puts "PolyRing: " + r.to_s; puts; one,B,S,T,Z,P,W = r.gens(); # capital letter variables not automaticaly defined ff = [ 45 * P + 35 * S - 165 * B - 36, 35 * P + 40 * Z + 25 * T - 27 * S, 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2, - 9 * W + 15 * T * P + 20 * S * Z, P * W + 2 * T * Z - 11 * B**3, 99 * W - 11 * B * S + 3 * B**2, B**2 + 33/50 * B + 2673/10000 ]; f = r.ideal( "", ff ); puts "Ideal: " + f.to_s; puts; #startLog() g = f.GB(); puts "Groebner base: " + g.to_s; puts; java-algebra-system-2.7.200/examples/getstart.py000066400000000000000000000011111445075545500215550ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import PolyRing, QQ from jas import startLog # trinks 7 example r = PolyRing( QQ(), "B,S,T,Z,P,W", PolyRing.lex); # or PolyRing.grad print "PolyRing: " + str(r); print; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( B**2 + 33/50 B + 2673/10000 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; startLog(); g = f.GB(); print "Groebner base:", g; print; java-algebra-system-2.7.200/examples/getstart.rb000066400000000000000000000010551445075545500215370ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # trinks 7 example r = PolyRing.new( QQ(), "B,S,T,Z,P,W", PolyRing.lex); # or PolyRing.grad puts "PolyRing: " + str(r); puts; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( B**2 + 33/50 B + 2673/10000 ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; startLog() g = f.GB(); puts "Groebner base: " + str(g); puts; java-algebra-system-2.7.200/examples/hawes2.py000066400000000000000000000021251445075545500211170ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, QQ, ZZ, RF from jas import startLog, terminate #startLog(); # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "RatFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing( RF(PolyRing(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); rg = f.GB(); print "GB:", rg; print; bg = rg.isGB(); print "isGB:", bg; print; startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2.rb000066400000000000000000000020571445075545500210760ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} require "examples/jas" # Hawes & Gibson example 2 # rational function coefficients #r = Ring.new( "RatFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing.new( RF(PolyRing.new(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.grad ); puts "Ring: " + str(r); puts; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; rg = f.GB(); rg = f.GB(); puts "GB: " + str(rg); #puts "GB: " + str(rg.pset); puts; bg = rg.isGB(); puts "isGB: " + str(bg); puts; startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2_c.py000066400000000000000000000026611445075545500214260ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, QQ from jas import startLog, terminate # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "IntFunc(a, c, b) (y2, y1, z1, z2, x) L" ); #r = Ring( "IntFunc(b, c, a) (y2, y1, z2, z1, x) G" ); r = PolyRing( PolyRing(QQ(),"b, c, a",PolyRing.lex), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/hawes2_gens.py000066400000000000000000000024101445075545500221300ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, QQ from jas import startLog, terminate # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "IntFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing( PolyRing(QQ(),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; #[one,a,c,b,y2,y1,z1,z2,x] = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; F = [p1,p2,p3,p4,p5]; g = r.ideal( list=F ); print "Ideal: " + str(g); print; rg = g.GB(); rg = g.GB(); rg = g.GB(); rg = g.GB(); print "GB:", rg; print; bg = rg.isGB(); print "isGB:", bg; print; #p7 = ( x + 1 ) / ( x**2 - x + 1 ); #print "p7 = ", p7; #p8 = ( x + 1 ) % ( x**2 - x + 1 ); #print "p8 = ", p8; startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2_gens.rb000066400000000000000000000023421445075545500221070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} require "examples/jas" # Hawes & Gibson example 2 # rational function coefficients #r = Ring.new( "IntFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing.new( PolyRing.new(QQ(),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x", PolyRing.grad ); puts "Ring: " + str(r); puts; #one,a,c,b,y2,y1,z1,z2,x = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; F = [p1,p2,p3,p4,p5]; g = r.ideal( "", F ); puts "Ideal: " + str(g); puts; rg = g.GB(); rg = g.GB(); rg = g.GB(); rg = g.GB(); puts "GB: " + str(rg); puts; bg = rg.isGB(); puts "isGB: " + str(bg); puts; #p7 = ( x + 1 ) / ( x**2 - x + 1 ); #puts "p7 = " + str(p7); #p8 = ( x + 1 ) % ( x**2 - x + 1 ); #puts "p8 = " + str(p8); startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2_gens_quot.py000066400000000000000000000024201445075545500232010ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, RF, ZZ from jas import startLog, terminate # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "RatFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing( RF(PolyRing(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; [one,a,c,b,y2,y1,z1,z2,x] = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; p6 = ( ( p5 / a ) / b ) / c; print "p6 = ", p6; F = [p1,p2,p3,p4,p5]; g = r.ideal( list=F ); print "Ideal: " + str(g); print; rg = g.GB(); rg = g.GB(); rg = g.GB(); rg = g.GB(); print "GB:", rg; print; bg = rg.isGB(); print "isGB:", bg; print; p7 = 1 / b; print "p7 = ", p7; p8 = p7 * b; print "p8 = ", p8; startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2_int.py000066400000000000000000000027061445075545500217760ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, QQ, ZZ, RF from jas import startLog, terminate # Hawes & Gibson example 2 # integral function coefficients, lexi #r = Ring( "IntFunc(a, c, b) (y2, y1, z1, z2, x) L" ); #r = PolyRing( RF(PolyRing(QQ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.lex ); r = PolyRing( RF(PolyRing(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; F = [p1,p2,p3,p4,p5]; f = r.ideal( list=F ); #f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); rgl = f.GB(); print "GB:", rgl; print; bg = rgl.isGB(); print "isGB:", bg; print; startLog(); terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2mod.py000066400000000000000000000025741445075545500216270ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, RF, ZZ, QQ from jas import startLog, terminate from edu.jas.arith import ModIntegerRing #startLog(); # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "RatFunc(a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing( RF(PolyRing(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; f = r.paramideal( ps ); print "Ideal: " + str(f); print; fi = f.toIntegralCoeff(); print "Ideal: " + str(fi); print; #mf = ModIntegerRing( str(2**60-93), True ); mf = ModIntegerRing( str(19), True ); fm = fi.toModularCoeff(mf); print "Ideal: " + str(fm); print; fmq = fm.toQuotientCoeff(); print "Ideal: " + str(fmq); print; rg = fmq.GB(); print "GB:", rg; print; bg = rg.isGB(); print "isGB:", bg; print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/hawes2modpars.py000066400000000000000000000021341445075545500225050ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, ZM, GF from jas import startLog, terminate # Hawes & Gibson example 2 # modular rational function coefficients, token parsing #r = Ring( "ModFunc 17 (a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing( PolyRing(GF(17),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); rg = f.GB(); rg = f.GB(); print "GB:", rg; print; bg = rg.isGB(); print "isGB:", bg; print; startLog(); terminate(); java-algebra-system-2.7.200/examples/hawes2modpars.rb000066400000000000000000000021711445075545500224610ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} require "examples/jas" #startLog(); # Hawes & Gibson example 2 # modular rational function coefficients, ruby expresion #r = Ring.new( "ModFunc 17 (a, c, b) (y2, y1, z1, z2, x) G" ); r = PolyRing.new( PolyRing.new(GF(17),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x", PolyRing.grad ); puts "Ring: " + str(r); puts; #one,a,c,b,y2,y1,z1,z2,x = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; f = [p1,p2,p3,p4,p5]; g = r.ideal( "", f ); puts "Ideal: " + str(g); puts; rg = g.GB(); rg = g.GB(); rg = g.GB(); puts "GB: " + str(rg); puts; bg = rg.isGB(); puts "isGB: " + str(bg); puts; startLog(); terminate(); java-algebra-system-2.7.200/examples/hawes2opt.py000066400000000000000000000023301445075545500216400ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} import sys; from jas import Ring, PolyRing, RF, ZZ from jas import startLog, terminate # Hawes & Gibson example 2 # rational function coefficients #r = Ring( "RatFunc(a, c, b) (y2, y1, z1, z2, x) L" ); r = PolyRing( RF(PolyRing(ZZ(),"a, c, b",PolyRing.lex)), "y2, y1, z1, z2, x", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 ), ( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 ), ( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } ), ( 3 z1^2 + y1^2 + { b } ), ( 3 z2^2 + y2^2 + { b } ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; startLog(); o = f.optimize(); print "optimized Ideal: " + str(o); print; p = o.paramideal(); p = p.optimizeCoeffQuot(); print "optimized coeff Ideal: " + str(p); print; #rg = p.GB(); #print "GB:", rg; #print; #rg = p; #bg = rg.isGB(); #print "isGB:", bg; #print; terminate(); java-algebra-system-2.7.200/examples/hermite.py000066400000000000000000000010601445075545500213600ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, ZZ from jas import startLog, terminate # hermite polynomial example # H(0) = 1 # H(1) = 2 * x # H(n) = 2 * x * H(n-1) - 2 * (n-1) * H(n-2) r = PolyRing( ZZ(), "x", PolyRing.lex ); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring #auto: [one,x] = r.gens(); x2 = 2 * x; N = 10; H = [one,x2]; for n in range(2,N+1): h = x2 * H[n-1] - 2 * (n-1) * H[n-2]; H.append( h ); for n in range(0,N+1): print "H[%s] = %s" % (n,H[n]); print; java-algebra-system-2.7.200/examples/hermite.rb000066400000000000000000000007361445075545500213440ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # hermite polynomial example # H(0) = 1 # H(1) = 2 * x # H(n) = 2 * x * H(n-1) - 2 * (n-1) * H(n-2) r = PolyRing.new( ZZ(), "x", PolyRing.lex ); puts "Ring: " + str(r); puts; # sage like: with generators for the polynomial ring #auto: one,x = r.gens(); x2 = 2 * x; N = 10; H = [one,x2]; for n in 2..N h = x2 * H[n-1] - 2 * (n-1) * H[n-2]; H << h; end for n in 0..N puts "H[#{n}] = #{H[n]}"; end puts; java-algebra-system-2.7.200/examples/ideal_one.jas000066400000000000000000000000461445075545500217720ustar00rootroot00000000000000# one ideal (a,b,c) L ( ( 99 ) ) java-algebra-system-2.7.200/examples/ideal_zero.jas000066400000000000000000000000461445075545500221700ustar00rootroot00000000000000# zero ideal (a,b,c) L ( ( 0 ) ) java-algebra-system-2.7.200/examples/igcd.py000066400000000000000000000014321445075545500206340ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import QQ, ZZ, GF, ZM from jas import terminate, startLog # integer examples: gcd r = ZZ(); #r = QQ(); # = GF(19); # = ZM(19*61); print "Ring: " + str(r); print; a = r.random(251); b = r.random(171); c = abs(r.random(211)); #c = 1; #a = 0; print "a = ", a; print "b = ", b; print "c = ", c; print; ac = a * c; bc = b * c; print "ac = ", ac; print "bc = ", bc; print; t = System.currentTimeMillis(); d = ac.gcd(bc); t = System.currentTimeMillis() - t; print "d = " + str(d); m = d % c; ## print "m = ", m; ## print; if m.isZERO(): print "gcd time =", t, "milliseconds,", "isGcd(c,d): true" ; else: print "gcd time =", t, "milliseconds,", "isGcd(c,d): ", str(m); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/igcd.rb000066400000000000000000000014151445075545500206100ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # integer examples: gcd r = ZZ(); #r = QQ(); #r = GF(19); #r = ZM(19*61); puts "Ring: " + str(r); puts; #one,x,y,z = r.gens(); a = r.random(251); b = r.random(171); c = r.random(211).abs(); #c = 1; #a = 0; puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts; ac = a * c; bc = b * c; puts "ac = " + str(ac); puts "bc = " + str(bc); puts; #startLog(); t = System.currentTimeMillis(); #d = r.gcd(ac,bc); d = ac.gcd(bc); t = System.currentTimeMillis() - t; puts "d = " + str(d); puts; puts "gcd time = " + str(t) + " milliseconds" ; m = d % c; #puts "m = " + str(m); #puts; if m.isZERO() puts "isGcd(c,d): true" ; else puts "isGcd(c,d): " + str(m); end puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/integrate.py000066400000000000000000000020701445075545500217070ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import Ring, RF, QQ, PolyRing from jas import terminate, startLog # elementary integration r = PolyRing(QQ(),"x",PolyRing.lex); print "r = " + str(r); rf = RF(r); print "rf = " + str(rf.factory()); [one,x] = rf.gens(); print "one = " + str(one); print "x = " + str(x); print; #f = 1 / ( 1 + x**2 ); #f = x**2 / ( x**2 + 1 ); #f = 1 / ( x**2 - 2 ); #f = 1 / ( x**3 - 2 ); #f = ( x + 3 ) / ( x**2- 3 * x - 40 ); f = ( x**7 - 24 * x**4 - 4 * x**2 + 8 * x - 8 ) / ( x**8 + 6 * x**6 + 12 * x**4 + 8 * x**2 ); print "f = ", f; print; startLog(); t = System.currentTimeMillis(); e1 = r.integrate(f); t = System.currentTimeMillis() - t; print "e1 = ", e1; ## print "e1.toScript() = "; ## for a in e1.logarithm: ## print a.toScript(); print "integration time =", t, "milliseconds"; print t = System.currentTimeMillis(); e2 = f.integrate(); t = System.currentTimeMillis() - t; print "e2 = ", e2; print "integration time =", t, "milliseconds"; print #startLog(); terminate(); java-algebra-system-2.7.200/examples/integrate.rb000066400000000000000000000015651445075545500216720ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # elementary integration r = PolyRing.new( QQ(), "x", PolyRing.lex ); puts "Ring: " + str(r); puts rf = RF(r); puts "Ring: " + str(rf.factory()); puts one,x = rf.gens(); #f = 1 / ( 1 + x**2 ); #f = x**2 / ( x**2 + 1 ); #f = 1 / ( x**2 - 2 ); #f = 1 / ( x**3 - 2 ); #f = ( x + 3 ) / ( x**2- 3 * x - 40 ); f = ( x**7 - 24 * x**4 - 4 * x**2 + 8 * x - 8 ) / ( x**8 + 6 * x**6 + 12 * x**4 + 8 * x**2 ); puts "f = " + str(f); puts; startLog(); t = System.currentTimeMillis(); e1 = r.integrate(f); t = System.currentTimeMillis() - t; puts "e1 = " + str(e1); puts "integration time = " + str(t) + " milliseconds"; puts; t = System.currentTimeMillis(); e2 = f.integrate(); t = System.currentTimeMillis() - t; puts "e2 = " + str(e2); puts "integration time = " + str(t) + " milliseconds"; puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/integro-differential-tab1.rb000066400000000000000000000022131445075545500246250ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # non-commutative polynomial examples: # rewrite rules for integro-differential algebra, # RR, JSC 2008, table 1 w = WordPolyRing.new(QQ(),"fg,hf,df,lf,ef,d,l,f,g,h,p,e"); puts "WordPolyRing: " + str(w); puts; one,fg,hf,df,lf,ef,d,l,f,g,h,p,e = w.gens(); puts "one = " + str(one); puts "fg = " + str(fg); puts "hf = " + str(hf); puts "df = " + str(df); puts "lf = " + str(lf); puts "ef = " + str(ef); puts "d = " + str(d); puts "l = " + str(l); puts "f = " + str(f); puts "g = " + str(g); puts "h = " + str(h); puts "p = " + str(p); puts "e = " + str(e); puts; e = 1 - l*d; puts "e = " + str(e); r1 = f * g - fg; r2 = h * p - p; r3 = h * f - hf*h; r4 = d * f - ( df + f * d ); r5 = d * h - 0; r6 = d * l - 1; r7 = l * f * l - ( lf * l - l * lf ); r8 = l * f * d - ( f - l * df - ef * e ); r9 = l * f * h - ( lf*h ); r10 = d * lf - f; r11 = l * df - f; r12 = d * p - 0; r13 = p * h - h; #ww = w.ideal("",[r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13]); ww = w.ideal("",[r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11]); puts "ww = " + str(ww); startLog() tt = ww.GB(); puts "tt = " + str(tt); puts; java-algebra-system-2.7.200/examples/intersect.py000066400000000000000000000012541445075545500217300ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, QQ from jas import startLog, terminate # ideal intersection example #r = Ring( "Rat(x,y,z) L" ); r = PolyRing( QQ(), "(x,y,z)", PolyRing.lex ); print "Ring: " + str(r); print; ps1 = """ ( ( x - 1 ), ( y - 1 ), ( z - 1 ) ) """; ps2 = """ ( ( x - 2 ), ( y - 3 ), ( z - 3 ) ) """; F1 = r.ideal( ps1 ); #print "Ideal: " + str(F1); #print; F2 = r.ideal( ps2 ); #print "Ideal: " + str(F2); #print; #startLog(); rg1 = F1.GB(); print "rg1 = ", rg1; print; rg2 = F2.GB(); print "rg2 = ", rg2; print; #startLog(); ig = F1.intersect(F2); print "rg1 intersect rg2 = ", ig; print; terminate(); java-algebra-system-2.7.200/examples/intersect.rb000066400000000000000000000011731445075545500217030ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # ideal intersection example #r = Ring.new( "Rat(x,y,z) L" ); r = PolyRing.new( QQ(), "(x,y,z)", PolyRing.lex ); puts "Ring: " + str(r); puts; ps1 = """ ( ( x - 1 ), ( y - 1 ), ( z - 1 ) ) """; ps2 = """ ( ( x - 2 ), ( y - 3 ), ( z - 3 ) ) """; F1 = r.ideal( ps1 ); #puts "Ideal: " + str(F1); #puts; F2 = r.ideal( ps2 ); #puts "Ideal: " + str(F2); #puts; #startLog(); rg1 = F1.GB(); puts "rg1 = " + str(rg1); puts; rg2 = F2.GB(); puts "rg2 = " + str(rg2); puts; #startLog(); ig = F1.intersect(F2); puts "rg1 intersect rg2 = " + str(ig); puts; terminate(); java-algebra-system-2.7.200/examples/intprog.py000066400000000000000000000011411445075545500214050ustar00rootroot00000000000000# # jython for jas example integer programming. # $Id$ # # CLO2, p370 # 4 A + 5 B + C = 37 # 2 A + 3 B + D = 20 # # max: 11 A + 15 B # import sys; from jas import Ring r = Ring( "Rat(w1,w2,w3,w4,z1,z2) W( (0,0,0,0,1,1),(1,1,2,2,0,0) )" ); print "Ring: " + str(r); print; ps = """ ( ( z1^4 z2^2 - w1 ), ( z1^5 z2^3 - w2 ), ( z1 - w3 ), ( z2 - w4 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; pf = """ ( ( z1^37 z2^20 ) ) """; fp = r.ideal( pf ); print "Ideal: " + str(fp); print; nf = fp.NF(rg); print "NFs: " + str(nf); print; java-algebra-system-2.7.200/examples/intprog.rb000066400000000000000000000011351445075545500213630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # # CLO2, p370 # 4 A + 5 B + C = 37 # 2 A + 3 B + D = 20 # # max: 11 A + 15 B # require "examples/jas" r = Ring.new( "Rat(w1,w2,w3,w4,z1,z2) W( (0,0,0,0,1,1),(1,1,2,2,0,0) )" ); puts "Ring: " + str(r); puts; ps = """ ( ( z1^4 z2^2 - w1 ), ( z1^5 z2^3 - w2 ), ( z1 - w3 ), ( z2 - w4 ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #startLog(); rg = f.GB(); puts "seq Output: " + str(rg); puts; pf = """ ( ( z1^37 z2^20 ) ) """; fp = r.ideal( pf ); puts "Ideal: " + str(fp); puts; nf = fp.NF(rg); puts "NFs: " + str(nf); puts; terminate() java-algebra-system-2.7.200/examples/intprog2.py000066400000000000000000000012271445075545500214740ustar00rootroot00000000000000# # jython for jas example 2 integer programming. # $Id$ # # CLO2, p372 # 3 A - 2 B + C = -1 # 4 A + B - C - D = 5 # # max: A + 1000 B + C + 100 D # import sys; from jas import Ring r = Ring( "Rat(w1,w2,w3,w4,t,z1,z2) W( (0,0,0,0,1,1,1),(1,1,2,2,0,0,0) )" ); print "Ring: " + str(r); print; ps = """ ( ( z1^3 z2^4 - w1 ), ( t^2 z2^3 - w2 ), ( t z1^2 - w3 ), ( t z1 - w4 ), ( t z1 z2 - 1 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; pf = """ ( ( t z2^6 ) ) """; fp = r.ideal( pf ); print "Ideal: " + str(fp); print; nf = fp.NF(rg); print "NFs: " + str(nf); print; java-algebra-system-2.7.200/examples/intprog3.py000066400000000000000000000014661445075545500215020ustar00rootroot00000000000000# # jython for jas example 3 integer programming. # $Id$ # # CLO2, p374,a,b # 3 A + 2 B + C + D = 10 # 4 A + B + C = 5 # # max: 2 A + 3 B + C + 5 D # import sys; from jas import Ring #r = Ring( "Rat(w1,w2,w3,w4,z1,z2) W( (0,0,0,0,1,1),(-2,-3,-1,-5,0,0) )" ); #r = Ring( "Rat(w1,w2,w3,w4,z1,z2) W( (0,0,0,0,1,1),( 7, 3, 2, 1,0,0)*6 )" ); r = Ring( "Rat(w1,w2,w3,w4,z1,z2) W( (0,0,0,0,1,1),(40,15,11, 1,0,0) )" ); print "Ring: " + str(r); print; ps = """ ( ( z1^3 z2^4 - w1 ), ( z1^2 z2 - w2 ), ( z1 z2 - w3 ), ( z1 - w4 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; pf = """ ( ( z1^10 z2^5 ), ( z1^20 z2^14 ) ) """; fp = r.ideal( pf ); print "Ideal: " + str(fp); print; nf = fp.NF(rg); print "NFs: " + str(nf); print; java-algebra-system-2.7.200/examples/intprog4.py000066400000000000000000000020531445075545500214740ustar00rootroot00000000000000# # jython for jas example 3 integer programming. # $Id$ # # CLO2, p374,c # 3 A + 2 B + C + D = 45 # A + 2 B + 3 C + E = 21 # 2 A + B + C + F = 18 # # max: 3 A + 4 B + 2 C # import sys; from jas import Ring #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),(-3,-4,-2,0,0,0,0,0,0) )" ); #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 6, 5, 5,1,1,1,0,0,0)*2 )" ); #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 3, 1, 3,1,1,1,0,0,0) )" ); r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 9, 6, 8,2,2,2,0,0,0) )" ); print "Ring: " + str(r); print; ps = """ ( ( z1^3 z2 z3^2 - w1 ), ( z1^2 z2^2 z3 - w2 ), ( z1 z2^3 z3 - w3 ), ( z1 - w4 ), ( z2 - w5 ), ( z3 - w6 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; pf = """ ( ( z1^45 z2^21 z3^18 ) ) """; fp = r.ideal( pf ); print "Ideal: " + str(fp); print; nf = fp.NF(rg); print "NFs: " + str(nf); print; java-algebra-system-2.7.200/examples/intprog4a.py000066400000000000000000000020531445075545500216350ustar00rootroot00000000000000# # jython for jas example 3 integer programming. # $Id$ # # CLO2, p374,c # 3 A + 2 B + C + D = 45 # A + 2 B + 3 C + E = 21 # 2 A + B + C + F = 18 # # max: 3 A + 4 B + 2 C # import sys; from jas import Ring r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),(-3,-4,-2,0,0,0,0,0,0) )" ); #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 6, 5, 5,1,1,1,0,0,0)*2 )" ); #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 3, 1, 3,1,1,1,0,0,0) )" ); #r = Ring( "Rat(w1,w2,w3,w4,w5,w6,z1,z2,z3) W( (0,0,0,0,0,0,1,1,1),( 9, 6, 8,2,2,2,0,0,0) )" ); print "Ring: " + str(r); print; ps = """ ( ( z1^3 z2 z3^2 - w1 ), ( z1^2 z2^2 z3 - w2 ), ( z1 z2^3 z3 - w3 ), ( z1 - w4 ), ( z2 - w5 ), ( z3 - w6 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; pf = """ ( ( z1^45 z2^21 z3^18 ) ) """; fp = r.ideal( pf ); print "Ideal: " + str(fp); print; nf = fp.NF(rg); print "NFs: " + str(nf); print; java-algebra-system-2.7.200/examples/jas.groovy000066400000000000000000000045041445075545500214030ustar00rootroot00000000000000/* * groovy interface to jas. * $Id: $ */ package edu.jas.groovy import java.lang.System import java.io.StringReader import edu.jas.structure.* import edu.jas.arith.* import edu.jas.poly.* import edu.jas.gb.* import edu.jas.gbmod.* import edu.jas.vector.* import edu.jas.application.* import edu.jas.util.* import edu.jas.ufd.* //import edu.jas.* //import edu.* //PrettyPrint.setInternal(); import edu.jas.kern.ComputerThreads; import org.apache.log4j.BasicConfigurator; //t = new ComputerThreads() //println "t = " + t //p = t.getPool() //println "p = " + p //l = new BasicConfigurator() //println "l = " + l //l.configure() def startLog = { BasicConfigurator.configure(); } //startLog(); def terminate = { ComputerThreads.terminate(); } class Ring { def ring; def pset; def Ring(ringstr="",ring=null) { if ( ring == null ) { def sr = new StringReader( ringstr ); def tok = new GenPolynomialTokenizer(sr); this.pset = tok.nextPolynomialSet(); this.ring = this.pset.ring; } else { this.ring = ring; } } String toString() { return ring.toString(); } def ideal(ringstr="",list=null) { return new Ideal(this,ringstr,list); } } class Ideal { def ring; def list; def pset; def Ideal(ring,ringstr="",list=null) { this.ring = ring; if ( list == null ) { def sr = new StringReader( ringstr ); def tok = new GenPolynomialTokenizer(ring.pset.ring,sr); this.list = tok.nextPolynomialList(); } else { this.list = list; } this.pset = new OrderedPolynomialList(ring.ring,this.list); } String toString() { return pset.toString(); } def GB() { def s = this.pset; def F = s.list; def t = System.currentTimeMillis(); def G = new GroebnerBaseSeq().GB(F); t = System.currentTimeMillis() - t; println "sequential executed in ${t} ms"; return new Ideal(this.ring,"",G); } def isGB() { def s = this.pset; def F = s.list; def t = System.currentTimeMillis(); def b = new GroebnerBaseSeq().isGB(F); t = System.currentTimeMillis() - t; println "isGB executed in ${t} ms"; return b; } } java-algebra-system-2.7.200/examples/jas.py000066400000000000000000004754411445075545500205220ustar00rootroot00000000000000'''jython interface to JAS. ''' # $Id$ from java.lang import System from java.io import StringReader from java.util import ArrayList, List, Collections from edu.jas.structure import RingElem, RingFactory, Power from edu.jas.arith import BigInteger, BigRational, BigComplex, BigDecimal,\ ModInteger, ModIntegerRing, ModLong, ModLongRing, ModInt, ModIntRing,\ BigQuaternion, BigQuaternionRing, BigOctonion,\ Product, ProductRing, ArithUtil, PrimeList, PrimeInteger from edu.jas.poly import GenPolynomial, GenPolynomialRing, Monomial,\ IndexFactory, GenExteriorPolynomial, GenExteriorPolynomialRing,\ GenSolvablePolynomial, GenSolvablePolynomialRing,\ RecSolvablePolynomial, RecSolvablePolynomialRing,\ RecSolvableWordPolynomial, RecSolvableWordPolynomialRing,\ QLRSolvablePolynomial, QLRSolvablePolynomialRing,\ GenWordPolynomial, GenWordPolynomialRing,\ ExpVector,\ Word, WordFactory,\ GenPolynomialTokenizer, OrderedPolynomialList, PolyUtil,\ TermOrderOptimization, TermOrder, TermOrderByName,\ PolynomialList, AlgebraicNumber, AlgebraicNumberRing,\ OrderedModuleList, ModuleList,\ Complex, ComplexRing from edu.jas.ps import UnivPowerSeries, UnivPowerSeriesRing,\ UnivPowerSeriesMap, Coefficients, \ MultiVarPowerSeries, MultiVarPowerSeriesRing,\ MultiVarPowerSeriesMap, MultiVarCoefficients,\ StandardBaseSeq from edu.jas.gb import EReductionSeq, DGroebnerBaseSeq, EGroebnerBaseSeq,\ GroebnerBaseDistributedEC, GroebnerBaseDistributedHybridEC,\ GroebnerBaseSeq, GroebnerBaseSeqIter, GroebnerBaseSeqPairSeq,\ OrderedPairlist, OrderedSyzPairlist, ReductionSeq,\ GroebnerBaseParallel, GroebnerBaseSeqPairParallel,\ SolvableGroebnerBaseParallel, SolvableGroebnerBaseSeq,\ SolvableReductionSeq, WordGroebnerBaseSeq from edu.jas.gbufd import GroebnerBasePseudoRecSeq, GroebnerBasePseudoSeq,\ SolvableGroebnerBasePseudoSeq, SolvablePseudoReductionSeq,\ PseudoReductionSeq, GroebnerBasePseudoParallel,\ WordGroebnerBasePseudoSeq, WordPseudoReductionSeq,\ SolvableGroebnerBasePseudoRecSeq, WordGroebnerBasePseudoRecSeq,\ RGroebnerBasePseudoSeq, RGroebnerBaseSeq, RReductionSeq,\ GroebnerBaseFGLM, GroebnerBaseWalk,\ CharacteristicSetWu, PolyGBUtil,\ SolvableSyzygySeq, SyzygySeq #from edu.jas.gbmod import ModGroebnerBaseSeq, ModSolvableGroebnerBaseSeq from edu.jas.vector import GenVector, GenVectorModul, BasicLinAlg,\ GenMatrix, GenMatrixRing, LinAlg from edu.jas.application import FactorFactory, PolyUtilApp, RingFactoryTokenizer,\ Residue, ResidueRing, Ideal,\ Local, LocalRing, IdealWithRealAlgebraicRoots,\ SolvableIdeal, SolvableResidue, SolvableResidueRing,\ SolvableLocal, SolvableLocalRing,\ SolvableLocalResidue, SolvableLocalResidueRing,\ ResidueSolvablePolynomial, ResidueSolvablePolynomialRing,\ LocalSolvablePolynomial, LocalSolvablePolynomialRing,\ WordIdeal, WordResidue, WordResidueRing,\ AlgebraicRootsPrimElem, RootFactoryApp,\ ComprehensiveGroebnerBaseSeq, ExtensionFieldBuilder from edu.jas.kern import ComputerThreads, StringUtil, Scripting from edu.jas.ufd import GreatestCommonDivisor, PolyUfdUtil, GCDFactory,\ SquarefreeFactory, Quotient, QuotientRing from edu.jas.fd import SolvableQuotient, SolvableQuotientRing,\ QuotSolvablePolynomial, QuotSolvablePolynomialRing from edu.jas.root import RealRootsSturm, Interval, RealAlgebraicNumber, RealAlgebraicRing,\ ComplexRootsSturm, Rectangle, RealArithUtil, RootFactory from edu.jas.integrate import ElementaryIntegration from edu.jas.util import ExecutableServer #from edu.jas import structure, arith, poly, ps, gb, gbmod, vector,\ # application, util, ufd from edu import jas #PrettyPrint.setInternal(); from org.python.core import PyInstance, PyList, PyTuple,\ PyInteger, PyLong, PyFloat, PyString # not suitable PySequence # set output to Python scripting Scripting.setLang(Scripting.Lang.Python); def startLog(): '''Configure the log4j system and start logging. BasicConfigurator from log4j version 1 is no more supported, please use log4j2 configuration. ''' #print "BasicConfigurator from log4j version 1 is no more supported, please use log4j2 configuration"; print "Java Algebra System (JAS) version 2.7" def terminate(): '''Terminate the running thread pools. ''' ComputerThreads.terminate(); def noThreads(): '''Turn off automatic parallel threads usage. ''' print "nt = ", ComputerThreads.NO_THREADS; ComputerThreads.setNoThreads(); #NO_THREADS = #0; #1; #True; print "nt = ", ComputerThreads.NO_THREADS; auto_inject = True '''Define variables automatically in the global namespace. ''' def inject_variable(name, value): '''Inject a variable into the main global namespace INPUT: - "name" - a string - "value" - anything Found in Sage. AUTHORS: - William Stein ''' assert type(name) is str import sys depth = 0 redef = None while True: G = sys._getframe(depth).f_globals #print "G = `%s` " % G; depth += 1 if depth > 100: print "depth limit %s reached " % depth; break if G is None: continue # orig: if G["__name__"] == "__main__" and G["__package__"] is None: try: if G["__name__"] is None: break except: #print "G[__name__] undefined"; break if G["__name__"] == "__main__": try: if G["__package__"] is None: break except: break if G is None: print "error at G no global environment found for `%s` = `%s` " % (name, value); return if name in G: redef = name; #print "redefining global variable `%s` from `%s` " % (name, G[name]); G[name] = value return redef def inject_generators(gens): '''Inject generators as variables into the main global namespace INPUT: - "gens" - generators ''' for v in gens: #print "vars = " + str(v); redef = []; s = str(v); if s.find("/") < 0 and s.find("(") < 0 and s.find(",") < 0 and s.find("{") < 0 and s.find("[") < 0 and s.find("|") < 0: if s[0:1] == "1": s = "one" + s[1:] #print "var = " + s; rd = inject_variable(s,v) if rd != None: redef.append(rd); if redef != []: print "WARN: redefined variables " + ", ".join(redef); def nameFromValue(v): '''Get a meaningful name from a value. INPUT: - "v" - the given value. ''' import re; ri = re.compile(r'\A[0-9].*'); vs = str(v); vs = vs.replace(" ",""); vs = vs.replace("\n",""); if vs.find("(") >= 0: vs = vs.replace("(",""); vs = vs.replace(")",""); if vs.find("{") >= 0: vs = vs.replace("{",""); vs = vs.replace("}",""); if vs.find("[") >= 0: vs = vs.replace("[",""); vs = vs.replace("]",""); if vs.find(",") >= 0: vs = vs.replace(",",""); #if vs.find("|") >= 0: # vs = vs.replace("|","div"); # case "1"? if vs.find("/") >= 0: vs = vs.replace("/","div"); if vs[0:1] == "1" and not ri.match(vs): vs = 'one' + vs[1:]; if vs == "1": vs = "one"; if vs == "0i1" or vs == "0I1": vs = "I"; if vs.find("|") >= 0 or ri.match(vs): #print "0vs = " + str(vs); return None; return vs; class Ring: '''Represents a JAS polynomial ring: GenPolynomialRing. Methods to create ideals and ideals with parametric coefficients. ''' def __init__(self,ringstr="",ring=None,fast=False): '''Ring constructor. ringstr string representation to be parsed. ring JAS ring object. ''' if ring == None: sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #plist = tok.nextPolynomialList(); #self.pset = PolynomialList(pfac,plist); self.ring = pfac; else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; if fast: return; self.engine = Ring.getEngineGcd(self.ring); self.sqf = Ring.getEngineSqf(self.ring); self.factor = Ring.getEngineFactor(self.ring); self.variable_generators(); def getEngineGcd(r): '''Get the polynomial gcd engine implementation. r is the given polynomial ring. ''' if isinstance(r,RingElem): r = r.elem; if not isinstance(r,GenPolynomialRing): return None; try: i = GCDFactory.getProxy(r.coFac); except: i = None return i; getEngineGcd = staticmethod(getEngineGcd); def getEngineSqf(r): '''Get the polynomial squarefree engine implementation. r is the given polynomial ring. ''' if isinstance(r,RingElem): r = r.elem; if not isinstance(r,GenPolynomialRing): return None; try: i = SquarefreeFactory.getImplementation(r.coFac); except: i = None return i; getEngineSqf = staticmethod(getEngineSqf); def getEngineFactor(r): '''Get the polynomial factorization engine implementation. r is the given polynomial ring. ''' if isinstance(r,RingElem): r = r.elem; if not isinstance(r,GenPolynomialRing): return None; try: i = FactorFactory.getImplementation(r.coFac); except: i = None return i; getEngineFactor = staticmethod(getEngineFactor); def variable_generators(self): '''Define instance variables for generators. ''' vns = [] redef = [] #print "dict: " + str(self.__dict__) for v in self.gens(): #ring.generators(): #vr = RingElem(v); #print "vars = " + str(v); vs = nameFromValue(v); if vs is None: #print "0vs = " + str(vs); continue; try: if self.__dict__[vs] is None: self.__dict__[vs] = v; else: print vs + " not redefined to " + str(v); except: self.__dict__[vs] = v; if auto_inject: rd = inject_variable(vs,v) vns.append(vs) if rd != None: redef.append(rd); if auto_inject: print "globally defined variables: " + ", ".join(vns) if redef != []: print "WARN: redefined global variables: " + ", ".join(redef); #print "dict: " + str(self.__dict__) def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); def __eq__(self,other): '''Test if two rings are equal. ''' if not isinstance(other, Ring): return False; s = self.ring; t = other.ring; return s.equals(t) def ideal(self,ringstr="",list=None): '''Create an ideal. ''' return Ideal(self,ringstr,list=list); def paramideal(self,ringstr="",list=None,gbsys=None): '''Create an ideal in a polynomial ring with parameter coefficients. ''' return ParamIdeal(self,ringstr,list,gbsys); def powerseriesRing(self): '''Get a power series ring from this ring. ''' pr = MultiVarPowerSeriesRing(self.ring); return MultiSeriesRing(ring=pr); def gens(self): '''Get list of generators of the polynomial ring. ''' L = self.ring.generators(); N = [ RingElem(e) for e in L ]; return N; def inject_variables(self): '''Inject generators as variables into the main global namespace ''' inject_generators(self.gens()); def one(self): '''Get the one of the polynomial ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the polynomial ring. ''' return RingElem( self.ring.getZERO() ); def random(self,k=5,l=7,d=3,q=0.3): '''Get a random polynomial. ''' r = self.ring.random(k,l,d,q); if self.ring.coFac.isField(): r = r.monic(); return RingElem( r ); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); I = Ideal(self, "( " + poly + " )"); list = I.pset.list; if len(list) > 0: return RingElem( list[0] ); def gcd(self,a,b): '''Compute the greatest common divisor of a and b. ''' if isinstance(a,RingElem): a = a.elem; else: a = self.element( a ); a = a.elem; if isinstance(b,RingElem): b = b.elem; else: b = self.element( b ); b = b.elem; return RingElem( self.engine.gcd(a,b) ); def squarefreeFactors(self,a): '''Compute squarefree factors of polynomial. ''' if isinstance(a,RingElem): a = a.elem; else: a = self.element( a ); a = a.elem; cf = self.ring.coFac; if isinstance(cf,GenPolynomialRing): e = self.sqf.recursiveSquarefreeFactors( a ); else: e = self.sqf.squarefreeFactors( a ); L = {}; for a in e.keySet(): i = e.get(a); L[ RingElem( a ) ] = i; return L; def factors(self,a): '''Compute irreducible factorization for modular, integer, rational number and algebriac number coefficients. ''' if isinstance(a,RingElem): a = a.elem; else: a = self.element( a ); a = a.elem; try: cf = self.ring.coFac; if isinstance(cf,GenPolynomialRing) and cf.isCommutative(): e = self.factor.recursiveFactors( a ); else: e = self.factor.factors( a ); L = {}; for a in e.keySet(): i = e.get(a); L[ RingElem( a ) ] = i; return L; except Exception, e: print "error " + str(e) return None def factorsAbsolute(self,a): '''Compute absolute irreducible factorization for (modular,) rational number coefficients. ''' if isinstance(a,RingElem): a = a.elem; else: a = self.element( a ); a = a.elem; try: L = self.factor.factorsAbsolute( a ); ## L = {}; ## for a in e.keySet(): ## i = e.get(a); ## L[ RingElem( a ) ] = i; return L; except Exception, e: print "error in factorsAbsolute " + str(e) return None def realRoots(self,a,eps=None): '''Compute real roots of univariate polynomial. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.realRoots(eps); def complexRoots(self,a,eps=None): '''Compute complex roots of univariate polynomial. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.complexRoots(eps); def algebraicRoots(self,a,eps=None): '''Algebraic real and Compute complex roots of univariate polynomial. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.algebraicRoots(eps); def rootRefine(self,a,eps=None): '''Compute algebraic roots refinement. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.rootRefine(eps); def decimalRoots(self,a,eps=None): '''Compute decimal approximation of real and complex roots of univariate polynomial. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.decimalRoots(eps); def rootsOfUnity(self,a): '''Roots of unity of real and complex algebraic numbers. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.rootsOfUnity(); def rootReduce(self,a, b): '''Root reduce of real and complex algebraic numbers. Compute an extension field with a primitive element. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.rootReduce(b); def integrate(self,a): '''Integrate rational function or power series. ''' if not isinstance(a,RingElem): a = RingElem(a); return a.integrate(); def subring(self,polystr="",list=None): '''Sub ring generators as Groebner base. ''' if list == None: sr = StringReader( polystr ); tok = GenPolynomialTokenizer(self.ring,sr); self.list = tok.nextPolynomialList(); else: self.list = pylist2arraylist(list,rec=1); sr = PolyGBUtil.subRing(self.list); srr = [ RingElem(a) for a in sr ]; return srr; def subringmember(self, list, a): '''Sub ring member test. list is a Groebner base. Test if a \in K[list]. ''' sr = [ p.elem for p in list]; if isinstance(a,RingElem): a = a.elem; b = PolyGBUtil.subRingMember(sr, a); return b; def CRT(self,polystr="", list=None, rem=None): '''Chinese remainder theorem. ''' if list == None: sr = StringReader( polystr ); tok = GenPolynomialTokenizer(self.ring,sr); self.list = tok.nextPolynomialList(); else: self.list = pylist2arraylist(list,rec=2); if rem == None: raise ValueError, "No remainders given." else: self.remlist = pylist2arraylist(rem,rec=1); #print "list = " + str(self.list); #print "remlist = " + str(self.remlist); #print h = PolyGBUtil.chineseRemainderTheorem(self.list, self.remlist); if h != None: h = RingElem(h); return h; def CRTinterpol(self,polystr="", list=None, rem=None): '''Chinese remainder theorem, interpolation. ''' if list == None: sr = StringReader( polystr ); tok = GenPolynomialTokenizer(self.ring,sr); self.list = tok.nextPolynomialList(); else: self.list = pylist2arraylist(list,rec=2); if rem == None: raise ValueError, "No remainders given." else: self.remlist = pylist2arraylist(rem,rec=1); #print "ring = " + str(self.ring); #print "list = " + str(self.list); #print "remlist = " + str(self.remlist); #print h = PolyGBUtil.CRTInterpolation(self.ring, self.list, self.remlist); if h != None: h = RingElem(h); return h; class Ideal: '''Represents a JAS polynomial ideal: PolynomialList and Ideal. Methods for Groebner bases, ideal sum, intersection and others. ''' def __init__(self,ring,polystr="",list=None): '''Ideal constructor. ''' self.ring = ring; if list == None: sr = StringReader( polystr ); tok = GenPolynomialTokenizer(ring.ring,sr); self.list = tok.nextPolynomialList(); else: self.list = pylist2arraylist(list,rec=1); self.pset = OrderedPolynomialList(ring.ring,self.list); self.roots = None; self.croots = None; self.prime = None; self.primary = None; def __str__(self): '''Create a string representation. ''' return str(self.pset.toScript()); def __eq__(self,other): '''Test if two ideals are equal. ''' o = other; if isinstance(other,Ideal): o = other.pset; return self.pset.equals(o) def paramideal(self): '''Create an ideal in a polynomial ring with parameter coefficients. ''' return ParamIdeal(self.ring,"",self.list); def GB(self): '''Compute a Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; kind = ""; t = System.currentTimeMillis(); if cofac.isField(): G = GroebnerBaseSeq(ReductionSeq(),OrderedSyzPairlist()).GB(F); #G = GroebnerBaseSeqIter(ReductionSeq(),OrderedSyzPairlist()).GB(F); #G = GroebnerBaseSeq().GB(F); kind = "field" else: if isinstance(cofac,GenPolynomialRing) and cofac.isCommutative(): G = GroebnerBasePseudoRecSeq(cofac).GB(F); kind = "pseudorec" else: G = GroebnerBasePseudoSeq(cofac).GB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) GB executed in %s ms" % (kind, t); return Ideal(self.ring,"",G); def isGB(self): '''Test if this is a Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); if cofac.isField(): b = GroebnerBaseSeq().isGB(F); else: if isinstance(cofac,GenPolynomialRing) and cofac.isCommutative(): b = GroebnerBasePseudoRecSeq(cofac).isGB(F); else: b = GroebnerBasePseudoSeq(cofac).isGB(F); t = System.currentTimeMillis() - t; #print "isGB executed in %s ms" % t; return b; def eGB(self): '''Compute an e-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); G = EGroebnerBaseSeq().GB(F) t = System.currentTimeMillis() - t; print "sequential e-GB executed in %s ms" % t; return Ideal(self.ring,"",G); def iseGB(self): '''Test if this is an e-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); b = EGroebnerBaseSeq().isGB(F) t = System.currentTimeMillis() - t; print "is e-GB test executed in %s ms" % t; return b; def eExtGB(self): '''Compute an extended e-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); G = EGroebnerBaseSeq().extGB(F) t = System.currentTimeMillis() - t; print "sequential extended e-GB executed in %s ms" % t; return G; #Ideal(self.ring,"",G); def iseExtGB(self, eg): '''Test if eg is an extended e-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); b = EGroebnerBaseSeq().isMinReductionMatrix(eg) t = System.currentTimeMillis() - t; print "sequential test extended e-GB executed in %s ms" % t; return b; def dGB(self): '''Compute an d-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); G = DGroebnerBaseSeq().GB(F) t = System.currentTimeMillis() - t; print "sequential d-GB executed in %s ms" % t; return Ideal(self.ring,"",G); def isdGB(self): '''Test if this is a d-Groebner base. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); b = DGroebnerBaseSeq().isGB(F) t = System.currentTimeMillis() - t; print "is d-GB test executed in %s ms" % t; return b; def parNewGB(self,th): '''Compute in parallel a Groebner base. ''' s = self.pset; F = s.list; bbpar = GroebnerBaseSeqPairParallel(th); t = System.currentTimeMillis(); G = bbpar.GB(F); t = System.currentTimeMillis() - t; bbpar.terminate(); print "parallel-new %s executed in %s ms" % (th, t); return Ideal(self.ring,"",G); def parGB(self,th): '''Compute in parallel a Groebner base. ''' s = self.pset; F = s.list; cofac = s.ring.coFac; if cofac.isField(): bbpar = GroebnerBaseParallel(th); else: bbpar = GroebnerBasePseudoParallel(th,cofac); t = System.currentTimeMillis(); G = bbpar.GB(F); t = System.currentTimeMillis() - t; bbpar.terminate(); print "parallel %s executed in %s ms" % (th, t); return Ideal(self.ring,"",G); def distGB(self,th=2,machine="examples/machines.localhost",port=55711): '''Compute on a distributed system a Groebner base. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); #old: gbd = GBDist(th,machine,port); gbd = GroebnerBaseDistributedEC(machine,th,port); #gbd = GroebnerBaseDistributedHybridEC(machine,th,port); t1 = System.currentTimeMillis(); G = gbd.GB(F); t1 = System.currentTimeMillis() - t1; gbd.terminate(); t = System.currentTimeMillis() - t; print "distributed %s executed in %s ms (%s ms start-up)" % (th,t1,t-t1); return Ideal(self.ring,"",G); def distClient(self,port=4711): #8114 '''Client for a distributed computation. ''' e1 = ExecutableServer( port ); e1.init(); e2 = ExecutableServer( port+1 ); e2.init(); self.exers = [e1,e2]; return None; def distClientStop(self): '''Stop client for a distributed computation. ''' for es in self.exers: es.terminate(); return None; def eReduction(self,p): '''Compute a e-normal form of p with respect to this ideal. ''' s = self.pset; G = s.list; if isinstance(p,RingElem): p = p.elem; t = System.currentTimeMillis(); n = EReductionSeq().normalform(G,p); t = System.currentTimeMillis() - t; print "sequential eReduction executed in %s ms" % t; return RingElem(n); def eReductionRec(self,row,p): '''Compute a e-normal form with recording of p with respect to this ideal. ''' s = self.pset; G = s.list; row = pylist2arraylist(row,None,rec=1); if isinstance(p,RingElem): p = p.elem; t = System.currentTimeMillis(); n = EReductionSeq().normalform(row,G,p); t = System.currentTimeMillis() - t; print "sequential eReduction recording executed in %s ms" % t; return row, RingElem(n); def iseReductionRec(self, row, p, n): '''Test if n is a e-normal form with recording of p with respect to this ideal. ''' s = self.pset; G = s.list; row = pylist2arraylist(row,None,rec=1); if isinstance(p,RingElem): p = p.elem; if isinstance(n,RingElem): n = n.elem; t = System.currentTimeMillis(); b = EReductionSeq().isReductionNF(row,G,p,n); t = System.currentTimeMillis() - t; return b; def reduction(self,p): '''Compute a normal form of p with respect to this ideal. ''' s = self.pset; G = s.list; if isinstance(p,RingElem): p = p.elem; if self.ring.ring.coFac.isField(): n = ReductionSeq().normalform(G,p); else: n = PseudoReductionSeq().normalform(G,p); #F = PseudoReductionSeq().normalformFactor(G,p); #print "F.multiplicator = " + str(F.multiplicator) #n = F.pol return RingElem(n); def NF(self,reducer): '''Compute a normal form of this ideal with respect to reducer. ''' s = self.pset; F = s.list; G = reducer.list; t = System.currentTimeMillis(); N = ReductionSeq().normalform(G,F); t = System.currentTimeMillis() - t; print "sequential NF executed in %s ms" % t; return Ideal(self.ring,"",N); def lift(self,p): '''Represent p as element of this ideal. ''' G = self.pset.list; z = self.ring.ring.getZERO(); R = [ z for x in G]; if isinstance(p,RingElem): p = p.elem; if self.ring.ring.coFac.isField(): n = ReductionSeq().normalform(R,G,p); else: n = PseudoReductionSeq().normalform(R,G,p); if not n.isZERO(): raise ValueError, "p ist not a member of the ideal" return [ RingElem(f) for f in R ]; def interreduced_basis(self): '''Compute a interreduced ideal basis of this. Compatibility method for Sage/Singular. ''' F = self.pset.list; if self.ring.ring.coFac.isField(): N = ReductionSeq().irreducibleSet(F); else: N = PseudoReductionSeq().irreducibleSet(F); #N = GroebnerBaseSeq().minimalGB(F); return [ RingElem(n) for n in N ]; def intersectRing(self,ring): '''Compute the intersection of this and the given polynomial ring. ''' s = jas.application.Ideal(self.pset); N = s.intersect(ring.ring); return Ideal(ring,"",N.getList()); def intersect(self,id2): '''Compute the intersection of this and the given ideal id2. ''' s1 = jas.application.Ideal(self.pset); s2 = jas.application.Ideal(id2.pset); N = s1.intersect(s2); return Ideal(self.ring,"",N.getList()); def eliminateRing(self,ring): '''Compute the elimination ideal of this and the given polynomial ring. ''' s = jas.application.Ideal(self.pset); N = s.eliminate(ring.ring); r = Ring( ring=N.getRing() ); return Ideal(r,"",N.getList()); def sat(self,id2): '''Compute the saturation of this with respect to given ideal id2. ''' s1 = jas.application.Ideal(self.pset); s2 = jas.application.Ideal(id2.pset); #Q = s1.infiniteQuotient(s2); Q = s1.infiniteQuotientRab(s2); return Ideal(self.ring,"",Q.getList()); def sum(self,other): '''Compute the sum of this and the ideal. ''' s = jas.application.Ideal(self.pset); t = jas.application.Ideal(other.pset); N = s.sum( t ); return Ideal(self.ring,"",N.getList()); def univariates(self): '''Compute the univariate polynomials in each variable of this ideal. ''' s = jas.application.Ideal(self.pset); L = s.constructUnivariate(); N = [ RingElem(e) for e in L ]; return N; def inverse(self,p): '''Compute the inverse polynomial modulo this ideal, if it exists. ''' s = jas.application.Ideal(self.pset); if isinstance(p,RingElem): p = p.elem; i = s.inverse(p); return RingElem(i); def eInverse(self,p): '''Compute the e-inverse polynomial modulo this e-ideal, if it exists. ''' if isinstance(p,RingElem): p = p.elem; i = EGroebnerBaseSeq().inverse(p, self.list); return RingElem(i); def iseInverse(self,i,p): '''Test if i is a e-inverse of p modulo this e-ideal. ''' if isinstance(i,RingElem): i = i.elem; if isinstance(p,RingElem): p = p.elem; r = EReductionSeq().normalform(self.list, i.multiply(p)); return r.abs().isONE(); def optimize(self): '''Optimize the term order on the variables. ''' p = self.pset; o = TermOrderOptimization.optimizeTermOrder(p); r = Ring("",o.ring); return Ideal(r,"",o.list); def dimension(self): '''Compute the dimension of the ideal. ''' I = jas.application.Ideal(self.pset); d = I.dimension(); return d; def realRoots(self): '''Compute real roots of 0-dim ideal. ''' I = jas.application.Ideal(self.pset); self.roots = jas.application.PolyUtilApp.realAlgebraicRoots(I); for R in self.roots: R.doDecimalApproximation(); return self.roots; def realRootsPrint(self): '''Print decimal approximation of real roots of 0-dim ideal. ''' if self.roots == None: I = jas.application.Ideal(self.pset); self.roots = jas.application.PolyUtilApp.realAlgebraicRoots(I); for R in self.roots: R.doDecimalApproximation(); for Ir in self.roots: for Dr in Ir.decimalApproximation(): print str(Dr); print; def radicalDecomp(self): '''Compute radical decomposition of this ideal. ''' I = jas.application.Ideal(self.pset); self.radical = I.radicalDecomposition(); return self.radical; def decomposition(self): '''Compute irreducible decomposition of this ideal. ''' I = jas.application.Ideal(self.pset); self.irrdec = I.decomposition(); return self.irrdec; def complexRoots(self): '''Compute complex roots of 0-dim ideal. ''' I = jas.application.Ideal(self.pset); self.croots = jas.application.PolyUtilApp.complexAlgebraicRoots(I); for R in self.croots: R.doDecimalApproximation(); return self.croots; def complexRootsPrint(self): '''Print decimal approximation of complex roots of 0-dim ideal. ''' if self.croots == None: I = jas.application.Ideal(self.pset); self.croots = jas.application.PolyUtilApp.realAlgebraicRoots(I); for R in self.croots: R.doDecimalApproximation(); for Ic in self.croots: for Dc in Ic.decimalApproximation(): print str(Dc); print; def primeDecomp(self): '''Compute prime decomposition of this ideal. ''' I = jas.application.Ideal(self.pset); self.prime = I.primeDecomposition(); return self.prime; def primaryDecomp(self): '''Compute primary decomposition of this ideal. ''' I = jas.application.Ideal(self.pset); ## if self.prime == None: ## self.prime = I.primeDecomposition(); self.primary = I.primaryDecomposition(); return self.primary; def toInteger(self): '''Convert rational coefficients to integer coefficients. ''' p = self.pset; l = p.list; r = p.ring; ri = GenPolynomialRing( BigInteger(), r.nvar, r.tord, r.vars ); pi = PolyUtil.integerFromRationalCoefficients(ri,l); r = Ring("",ri); return Ideal(r,"",pi); def toModular(self,mf): '''Convert integer coefficients to modular coefficients. ''' p = self.pset; l = p.list; r = p.ring; if isinstance(mf,RingElem): mf = mf.ring; rm = GenPolynomialRing( mf, r.nvar, r.tord, r.vars ); pm = PolyUtil.fromIntegerCoefficients(rm,l); r = Ring("",rm); return Ideal(r,"",pm); def CS(self): '''Compute a Characteristic Set. ''' s = self.pset; cofac = s.ring.coFac; F = s.list; t = System.currentTimeMillis(); if cofac.isField(): G = CharacteristicSetWu().characteristicSet(F); else: print "CS not implemented for coefficients %s" % cofac.toScriptFactory(); G = None; t = System.currentTimeMillis() - t; print "sequential CS executed in %s ms" % t; return Ideal(self.ring,"",G); def isCS(self): '''Test for Characteristic Set. ''' s = self.pset; cofac = s.ring.coFac; F = s.list.clone(); Collections.reverse(F); # todo t = System.currentTimeMillis(); if cofac.isField(): b = CharacteristicSetWu().isCharacteristicSet(F); else: print "isCS not implemented for coefficients %s" % cofac.toScriptFactory(); b = False; t = System.currentTimeMillis() - t; return b; def csReduction(self,p): '''Compute a normal form of p with respect to this characteristic set. ''' s = self.pset; F = s.list.clone(); Collections.reverse(F); # todo if isinstance(p,RingElem): p = p.elem; t = System.currentTimeMillis(); n = CharacteristicSetWu().characteristicSetReduction(F,p); t = System.currentTimeMillis() - t; #print "sequential char set reduction executed in %s ms" % t; return RingElem(n); def syzygy(self): '''Syzygy of generating polynomials. ''' p = self.pset; l = p.list; t = System.currentTimeMillis(); s = SyzygySeq(p.ring.coFac).zeroRelations( l ); t = System.currentTimeMillis() - t; print "executed syzygy in %s ms" % t; m = Module("",p.ring); #cols=s[0].size() return SubModule(m,"",s); def isSyzygy(self,m): '''Test if this is a syzygy of the module in m. ''' p = self.pset; g = p.list; l = m.list; t = System.currentTimeMillis(); z = SyzygySeq(p.ring.coFac).isZeroRelation( l, g ); t = System.currentTimeMillis() - t; print "executed isSyzygy in %s ms" % t; return z; class ParamIdeal: '''Represents a JAS polynomial ideal with polynomial coefficients. Methods to compute comprehensive Groebner bases. ''' def __init__(self,ring,polystr="",list=None,gbsys=None): '''Parametric ideal constructor. ''' self.ring = ring; if list == None and polystr != None: sr = StringReader( polystr ); tok = GenPolynomialTokenizer(ring.ring,sr); self.list = tok.nextPolynomialList(); else: self.list = pylist2arraylist(list,rec=1); self.gbsys = gbsys; self.pset = OrderedPolynomialList(ring.ring,self.list); def __str__(self): '''Create a string representation. ''' if self.gbsys == None: return self.pset.toScript(); else: # return self.gbsys.toString(); # toScript() not available return self.pset.toScript() + "\n" + self.gbsys.toScript(); def optimizeCoeff(self): '''Optimize the term order on the variables of the coefficients. ''' p = self.pset; o = TermOrderOptimization.optimizeTermOrderOnCoefficients(p); r = Ring("",o.ring); return ParamIdeal(r,"",o.list); def optimizeCoeffQuot(self): '''Optimize the term order on the variables of the quotient coefficients. ''' p = self.pset; l = p.list; r = p.ring; q = r.coFac; c = q.ring; rc = GenPolynomialRing( c, r.nvar, r.tord, r.vars ); #print "rc = ", rc; lp = PolyUfdUtil.integralFromQuotientCoefficients(rc,l); #print "lp = ", lp; pp = PolynomialList(rc,lp); #print "pp = ", pp; oq = TermOrderOptimization.optimizeTermOrderOnCoefficients(pp); oor = oq.ring; qo = oor.coFac; cq = QuotientRing( qo ); rq = GenPolynomialRing( cq, r.nvar, r.tord, r.vars ); #print "rq = ", rq; o = PolyUfdUtil.quotientFromIntegralCoefficients(rq,oq.list); r = Ring("",rq); return ParamIdeal(r,"",o); def toIntegralCoeff(self): '''Convert rational function coefficients to integral function coefficients. ''' p = self.pset; l = p.list; r = p.ring; q = r.coFac; c = q.ring; rc = GenPolynomialRing( c, r.nvar, r.tord, r.vars ); #print "rc = ", rc; lp = PolyUfdUtil.integralFromQuotientCoefficients(rc,l); #print "lp = ", lp; r = Ring("",rc); return ParamIdeal(r,"",lp); def toModularCoeff(self,mf): '''Convert integral function coefficients to modular function coefficients. ''' p = self.pset; l = p.list; r = p.ring; c = r.coFac; #print "c = ", c; if isinstance(mf,RingElem): mf = mf.ring; cm = GenPolynomialRing( mf, c.nvar, c.tord, c.vars ); #print "cm = ", cm; rm = GenPolynomialRing( cm, r.nvar, r.tord, r.vars ); #print "rm = ", rm; pm = PolyUfdUtil.fromIntegerCoefficients(rm,l); r = Ring("",rm); return ParamIdeal(r,"",pm); def toQuotientCoeff(self): '''Convert integral function coefficients to rational function coefficients. ''' p = self.pset; l = p.list; r = p.ring; c = r.coFac; #print "c = ", c; q = QuotientRing(c); #print "q = ", q; qm = GenPolynomialRing( q, r.nvar, r.tord, r.vars ); #print "qm = ", qm; pm = PolyUfdUtil.quotientFromIntegralCoefficients(qm,l); r = Ring("",qm); return ParamIdeal(r,"",pm); def GB(self): '''Compute a Groebner base. ''' I = Ideal(self.ring,"",self.pset.list); g = I.GB(); return ParamIdeal(g.ring,"",g.pset.list); def isGB(self): '''Test if this is a Groebner base. ''' I = Ideal(self.ring,"",self.pset.list); return I.isGB(); def CGB(self): '''Compute a comprehensive Groebner base. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); if self.gbsys == None: self.gbsys = ComprehensiveGroebnerBaseSeq(self.ring.ring.coFac).GBsys(F); G = self.gbsys.getCGB(); t = System.currentTimeMillis() - t; print "sequential comprehensive executed in %s ms" % t; return ParamIdeal(self.ring,"",G,self.gbsys); def CGBsystem(self): '''Compute a comprehensive Groebner system. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); S = ComprehensiveGroebnerBaseSeq(self.ring.ring.coFac).GBsys(F); t = System.currentTimeMillis() - t; print "sequential comprehensive system executed in %s ms" % t; return ParamIdeal(self.ring,None,F,S); def isCGB(self): '''Test if this is a comprehensive Groebner base. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); b = ComprehensiveGroebnerBaseSeq(self.ring.ring.coFac).isGB(F); t = System.currentTimeMillis() - t; print "isCGB executed in %s ms" % t; return b; def isCGBsystem(self): '''Test if this is a comprehensive Groebner system. ''' s = self.pset; S = self.gbsys; t = System.currentTimeMillis(); b = ComprehensiveGroebnerBaseSeq(self.ring.ring.coFac).isGBsys(S); t = System.currentTimeMillis() - t; print "isCGBsystem executed in %s ms" % t; return b; def regularRepresentation(self): '''Convert Groebner system to a representation with regular ring coefficents. ''' if self.gbsys == None: return None; G = PolyUtilApp.toProductRes(self.gbsys.list); ring = Ring(None,G[0].ring); return ParamIdeal(ring,None,G); def regularRepresentationBC(self): '''Convert Groebner system to a boolean closed representation with regular ring coefficents. ''' if self.gbsys == None: return None; G = PolyUtilApp.toProductRes(self.gbsys.list); ring = Ring(None,G[0].ring); res = RReductionSeq(); G = res.booleanClosure(G); return ParamIdeal(ring,None,G); def regularGB(self): '''Compute a Groebner base over a regular ring. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); G = RGroebnerBasePseudoSeq(self.ring.ring.coFac).GB(F); t = System.currentTimeMillis() - t; print "sequential regular GB executed in %s ms" % t; return ParamIdeal(self.ring,None,G); def isRegularGB(self): '''Test if this is Groebner base over a regular ring. ''' s = self.pset; F = s.list; t = System.currentTimeMillis(); b = RGroebnerBasePseudoSeq(self.ring.ring.coFac).isGB(F); t = System.currentTimeMillis() - t; print "isRegularGB executed in %s ms" % t; return b; def stringSlice(self): '''Get each component (slice) of regular ring coefficients separate. ''' s = self.pset; b = PolyUtilApp.productToString(s); return b; class SolvableRing(Ring): '''Represents a JAS solvable polynomial ring: GenSolvablePolynomialRing. Has a method to create solvable ideals. ''' def __init__(self,ringstr="",ring=None): '''Solvable polynomial ring constructor. ''' if ring == None: sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextSolvablePolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #plist = tok.nextSolvablePolynomialList(); #self.pset = PolynomialList(pfac,plist); self.ring = pfac; else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; if not self.ring.isAssociative(): print "warning: ring is not associative"; else: print "ring is associative"; Ring.__init__(self,ring=self.ring) def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); def ideal(self,ringstr="",list=None): '''Create a solvable ideal. ''' return SolvableIdeal(self,ringstr,list); def one(self): '''Get the one of the solvable polynomial ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the solvable polynomial ring. ''' return RingElem( self.ring.getZERO() ); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); I = SolvableIdeal(self, "( " + poly + " )"); list = I.pset.list; if len(list) > 0: return RingElem( list[0] ); class SolvableIdeal: '''Represents a JAS solvable polynomial ideal. Methods for left, right two-sided Groebner basees and others. ''' def __init__(self,ring,ringstr="",list=None): '''Constructor for an ideal in a solvable polynomial ring. ''' self.ring = ring; if list == None: sr = StringReader( ringstr ); tok = GenPolynomialTokenizer(ring.ring,sr); self.list = tok.nextSolvablePolynomialList(); else: self.list = pylist2arraylist(list,rec=1); self.pset = OrderedPolynomialList(ring.ring,self.list); #self.pset = PolynomialList(ring.ring,self.list); def __str__(self): '''Create a string representation. ''' return str(self.pset.toScript()); def __cmp__(self,other): '''Compare two ideals. ''' t = False; if not isinstance(other,SolvableIdeal): return t; t = self.pset.compareTo(other.pset); return t; def __eq__(self,other): '''Test if two ideals are equal. ''' if not isinstance(other, SolvableIdeal): return False; s = self.pset; t = other.pset; return s.equals(t) def leftGB(self): '''Compute a left Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): #and cofac.isCommutative(): G = SolvableGroebnerBasePseudoRecSeq(cofac).leftGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): G = SolvableGroebnerBaseSeq().leftGB(F); kind = "field|nocom" else: G = SolvableGroebnerBasePseudoSeq(cofac).leftGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) left GB executed in %s ms" % (kind, t); return SolvableIdeal(self.ring,"",G); def isLeftGB(self): '''Test if this is a left Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): #and cofac.isCommutative(): b = SolvableGroebnerBasePseudoRecSeq(cofac).isLeftGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): b = SolvableGroebnerBaseSeq().isLeftGB(F); kind = "field|nocom" else: b = SolvableGroebnerBasePseudoSeq(cofac).isLeftGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) isLeftGB executed in %s ms" % (kind, t); return b; def twosidedGB(self): '''Compute a two-sided Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): # and cofac.isCommutative(): G = SolvableGroebnerBasePseudoRecSeq(cofac).twosidedGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): G = SolvableGroebnerBaseSeq().twosidedGB(F); kind = "field|nocom" else: G = SolvableGroebnerBasePseudoSeq(cofac).twosidedGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) twosided GB executed in %s ms" % (kind, t); return SolvableIdeal(self.ring,"",G); def isTwosidedGB(self): '''Test if this is a two-sided Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): # and cofac.isCommutative(): b = SolvableGroebnerBasePseudoRecSeq(cofac).isTwosidedGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): b = SolvableGroebnerBaseSeq().isTwosidedGB(F); kind = "field|nocom" else: b = SolvableGroebnerBasePseudoSeq(cofac).isTwosidedGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) isTwosidedGB executed in %s ms" % (kind, t); return b; def rightGB(self): '''Compute a right Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): # and cofac.isCommutative(): G = SolvableGroebnerBasePseudoRecSeq(cofac).rightGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): G = SolvableGroebnerBaseSeq().rightGB(F); kind = "field|nocom" else: G = SolvableGroebnerBasePseudoSeq(cofac).rightGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) right GB executed in %s ms" % (kind, t); return SolvableIdeal(self.ring,"",G); def isRightGB(self): '''Test if this is a right Groebner base. ''' cofac = self.ring.ring.coFac; F = self.pset.list; kind = ""; t = System.currentTimeMillis(); if isinstance(cofac,GenPolynomialRing): # and cofac.isCommutative(): b = SolvableGroebnerBasePseudoRecSeq(cofac).isRightGB(F); kind = "pseudorec" else: if cofac.isField() or not cofac.isCommutative(): b = SolvableGroebnerBaseSeq().isRightGB(F); kind = "field|nocom" else: b = SolvableGroebnerBasePseudoSeq(cofac).isRightGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) isRightGB executed in %s ms" % (kind, t); return b; def intersectRing(self,ring): '''Compute the intersection of this and the polynomial ring. ''' s = jas.application.SolvableIdeal(self.pset); N = s.intersect(ring.ring); return SolvableIdeal(self.ring,"",N.getList()); def intersect(self,other): '''Compute the intersection of this and the other ideal. ''' s = jas.application.SolvableIdeal(self.pset); t = jas.application.SolvableIdeal(other.pset); N = s.intersect( t ); return SolvableIdeal(self.ring,"",N.getList()); def sum(self,other): '''Compute the sum of this and the other ideal. ''' s = jas.application.SolvableIdeal(self.pset); t = jas.application.SolvableIdeal(other.pset); N = s.sum( t ); return SolvableIdeal(self.ring,"",N.getList()); def univariates(self): '''Compute the univariate polynomials in each variable of this twosided ideal. ''' s = jas.application.SolvableIdeal(self.pset); L = s.constructUnivariate(); N = [ RingElem(e) for e in L ]; return N; def toQuotientCoefficients(self): '''Convert to polynomials with SolvableQuotient coefficients. ''' if isinstance(self.pset.ring.coFac,SolvableResidueRing): cf = self.pset.ring.coFac.ring; else: if isinstance(self.pset.ring.coFac,GenSolvablePolynomialRing): cf = self.pset.ring.coFac; #else: if @pset.ring.coFac.getClass().getSimpleName() == "GenPolynomialRing" # cf = @pset.ring.coFac; # puts "cf = " + cf.toScript(); else: return self; rrel = self.pset.ring.table.relationList(); rrel.addAll(self.pset.ring.polCoeff.coeffTable.relationList()); #print "rrel = " + str(rrel); qf = SolvableQuotientRing(cf); qr = QuotSolvablePolynomialRing(qf,self.pset.ring); #print "qr = " + str(qr); qrel = [ RingElem(qr.fromPolyCoefficients(r)) for r in rrel ]; qring = SolvPolyRing(qf,self.ring.ring.getVars(),self.ring.ring.tord,qrel); #print "qring = " + str(qring); qlist = [ qr.fromPolyCoefficients(self.ring.ring.toPolyCoefficients(r)) for r in self.list ]; qlist = [ RingElem(r) for r in qlist ]; return SolvableIdeal(qring,"",qlist); def inverse(self,p): '''Compute the inverse polynomial modulo this ideal, if it exists. ''' s = jas.application.SolvableIdeal(self.pset); if isinstance(p,RingElem): p = p.elem; i = s.inverse(p); return RingElem(i); def leftReduction(self,p): '''Compute a left normal form of p with respect to this ideal. ''' s = self.pset; G = s.list; if isinstance(p,RingElem): p = p.elem; n = SolvableReductionSeq().leftNormalform(G,p); return RingElem(n); def rightReduction(self,p): '''Compute a right normal form of p with respect to this ideal. ''' s = self.pset; G = s.list; if isinstance(p,RingElem): p = p.elem; n = SolvableReductionSeq().rightNormalform(G,p); return RingElem(n); def parLeftGB(self,th): '''Compute a left Groebner base in parallel. ''' s = self.pset; F = s.list; bbpar = SolvableGroebnerBaseParallel(th); t = System.currentTimeMillis(); G = bbpar.leftGB(F); t = System.currentTimeMillis() - t; bbpar.terminate(); print "parallel %s leftGB executed in %s ms" % (th, t); return SolvableIdeal(self.ring,"",G); def parTwosidedGB(self,th): '''Compute a two-sided Groebner base in parallel. ''' s = self.pset; F = s.list; bbpar = SolvableGroebnerBaseParallel(th); t = System.currentTimeMillis(); G = bbpar.twosidedGB(F); t = System.currentTimeMillis() - t; bbpar.terminate(); print "parallel %s twosidedGB executed in %s ms" % (th, t); return SolvableIdeal(self.ring,"",G); def leftSyzygy(self): '''left Syzygy of generating polynomials. ''' p = self.pset; l = p.list; t = System.currentTimeMillis(); s = SolvableSyzygySeq(p.ring.coFac).leftZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; print "executed left syzygy in %s ms" % t; m = SolvableModule("",p.ring); return SolvableSubModule(m,"",s); def isLeftSyzygy(self,m): '''Test if this is a left syzygy of the module in m. ''' p = self.pset; g = p.list; l = m.list; t = System.currentTimeMillis(); z = SolvableSyzygySeq(p.ring.coFac).isLeftZeroRelation( l, g ); t = System.currentTimeMillis() - t; print "executed isLeftSyzygy in %s ms" % t; return z; def rightSyzygy(self): '''right Syzygy of generating polynomials. ''' p = self.pset; l = p.list; t = System.currentTimeMillis(); s = SolvableSyzygySeq(p.ring.coFac).rightZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; print "executed right syzygy in %s ms" % t; m = SolvableModule("",p.ring); return SolvableSubModule(m,"",s); def isRightSyzygy(self,m): '''Test if this is a right syzygy of the module in m. ''' p = self.pset; g = p.list; l = m.list; t = System.currentTimeMillis(); z = SolvableSyzygySeq(p.ring.coFac).isRightZeroRelation( l, g ); t = System.currentTimeMillis() - t; print "executed isRightSyzygy in %s ms" % t; return z; def dimension(self): '''Compute the dimension of the ideal. ''' I = jas.application.SolvableIdeal(self.pset); d = I.dimension(); return d; class Module: '''Represents a JAS module over a polynomial ring. Method to create sub-modules. ''' def __init__(self,modstr="",ring=None,cols=0): '''Module constructor. ''' if ring == None: sr = StringReader( modstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #mlist = tok.nextSubModuleList(); #self.mset = ModuleList(pfac,mlist); #if self.mset.cols >= 0: # self.cols = self.mset.cols; #else: self.ring = pfac else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; self.mset = ModuleList(self.ring,None); # because of toScript if cols < 0: cols = 0; self.cols = cols; def __str__(self): '''Create a string representation. ''' return str(self.mset.toScript()); def submodul(self,modstr="",list=None): '''Create a sub-module. ''' return SubModule(self,modstr,list); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); I = SubModule(self, "( " + poly + " )"); list = I.mset.list; if len(list) > 0: return RingElem( list[0] ); def gens(self): '''Get the generators of this module. ''' gm = GenVectorModul(self.ring,self.cols); L = gm.generators(); #for g in L: # print "g = ", str(g); N = [ RingElem(e) for e in L ]; # want use val here, but can not return N; def inject_variables(self): '''Inject generators as variables into the main global namespace ''' inject_generators(self.gens()); class SubModule: '''Represents a JAS sub-module over a polynomial ring. Methods to compute Groebner bases. ''' def __init__(self,module,modstr="",list=None): '''Constructor for a sub-module. ''' self.module = module; if list == None: sr = StringReader( modstr ); tok = GenPolynomialTokenizer(module.ring,sr); self.list = tok.nextSubModuleList(); else: if isinstance(list,PyList) or isinstance(list,PyTuple): if len(list) != 0: if isinstance(list[0],RingElem): list = [ re.elem for re in list ]; self.list = pylist2arraylist(list,self.module.ring,rec=2); else: self.list = list; #print "list = ", str(list); #e = self.list[0]; #print "e = ", e; self.mset = OrderedModuleList(module.ring,self.list); self.cols = self.mset.cols; self.rows = self.mset.rows; #print "list = %s" % self.list; #print "cols = %s" % self.cols; #print "mset = %s" % self.mset.toString(); #print "mset = %s" % self.mset.toScript(); self.pset = self.mset.getPolynomialList(); def __str__(self): '''Create a string representation. ''' return str(self.mset.toScript()); # + "\n\n" + str(self.pset); def GB(self): '''Compute a Groebner base. ''' t = System.currentTimeMillis(); #G = ModGroebnerBaseSeq(self.module.ring.coFac).GB(self.mset); G = GroebnerBaseSeq().GB(self.mset); t = System.currentTimeMillis() - t; print "executed module GB in %s ms" % t; return SubModule(self.module,"",G.list); def isGB(self): '''Test if this is a Groebner base. ''' t = System.currentTimeMillis(); #b = ModGroebnerBaseSeq(self.module.ring.coFac).isGB(self.mset); b = GroebnerBaseSeq().isGB(self.mset); t = System.currentTimeMillis() - t; print "module isGB executed in %s ms" % t; return b; def isSyzygy(self,g): '''Test if this is a syzygy of the vectors in g. ''' l = self.list; if isinstance(g,Ideal): s = g.pset.list; else: if isinstance(g,SubModule): s = g.mset; l = self.mset; else: raise ValueError, "unknown type %s" % g.getClass().getName(); #print "l = %s" % l; #print "s = %s" % s; t = System.currentTimeMillis(); z = SyzygySeq(self.module.ring.coFac).isZeroRelation( l, s ); t = System.currentTimeMillis() - t; print "executed isSyzygy in %s ms" % t; return z; def syzygy(self): '''Compute syzygys of this module. ''' l = self.mset; t = System.currentTimeMillis(); p = SyzygySeq(self.module.ring.coFac).zeroRelations( l ); t = System.currentTimeMillis() - t; print "executed module syzygy in %s ms" % t; #print "p = " + str(p.ring.toScript()); m = Module("",p.ring,p.cols); return SubModule(m,"",p.list); class SolvableModule(Module): '''Represents a JAS module over a solvable polynomial ring. Method to create solvable sub-modules. ''' def __init__(self,modstr="",ring=None,cols=0): '''Solvable module constructor. ''' if ring == None: sr = StringReader( modstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextSolvablePolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #mlist = tok.nextSolvableSubModuleList(); #self.mset = PolynomialList(pfac,mlist); #if self.mset.cols >= 0: # self.cols = self.mset.cols; self.ring = pfac; else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; self.mset = ModuleList(self.ring,None); if cols < 0: cols = 0; self.cols = cols; def __str__(self): '''Create a string representation. ''' return str(self.mset.toScript()); def submodul(self,modstr="",list=None): '''Create a solvable sub-module. ''' return SolvableSubModule(self,modstr,list); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); I = SolvableSubModule(self, "( " + poly + " )"); list = I.mset.list; if len(list) > 0: return RingElem( list[0] ); class SolvableSubModule: '''Represents a JAS sub-module over a solvable polynomial ring. Methods to compute left, right and two-sided Groebner bases. ''' def __init__(self,module,modstr="",list=None): '''Constructor for sub-module over a solvable polynomial ring. ''' self.module = module; if list == None: sr = StringReader( modstr ); tok = GenPolynomialTokenizer(module.ring,sr); self.list = tok.nextSolvableSubModuleList(); else: if isinstance(list,PyList) or isinstance(list,PyTuple): self.list = pylist2arraylist(list,self.module.ring,rec=2); else: self.list = list; self.mset = OrderedModuleList(module.ring,self.list); self.cols = self.mset.cols; self.rows = self.mset.rows; def __str__(self): '''Create a string representation. ''' return str(self.mset.toScript()); # + "\n\n" + str(self.pset); def leftGB(self): '''Compute a left Groebner base. ''' t = System.currentTimeMillis(); #G = SolvableGroebnerBaseSeq(self.module.ring.coFac).leftGB(self.mset); G = SolvableGroebnerBaseSeq().leftGB(self.mset); t = System.currentTimeMillis() - t; print "executed left module GB in %s ms" % t; return SolvableSubModule(self.module,"",G.list); def isLeftGB(self): '''Test if this is a left Groebner base. ''' t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq(self.module.ring.coFac).isLeftGB(self.mset); b = SolvableGroebnerBaseSeq().isLeftGB(self.mset); t = System.currentTimeMillis() - t; print "module isLeftGB executed in %s ms" % t; return b; def twosidedGB(self): '''Compute a two-sided Groebner base. ''' t = System.currentTimeMillis(); #G = SolvableGroebnerBaseSeq(self.module.ring.coFac).twosidedGB(self.mset); G = SolvableGroebnerBaseSeq().twosidedGB(self.mset); t = System.currentTimeMillis() - t; print "executed twosided module GB in %s ms" % t; return SolvableSubModule(self.module,"",G.list); def isTwosidedGB(self): '''Test if this is a two-sided Groebner base. ''' t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq(self.module.ring.coFac).isTwosidedGB(self.mset); b = SolvableGroebnerBaseSeq().isTwosidedGB(self.mset); t = System.currentTimeMillis() - t; print "module isTwosidedGB executed in %s ms" % t; return b; def rightGB(self): '''Compute a right Groebner base. ''' t = System.currentTimeMillis(); #G = SolvableGroebnerBaseSeq(self.module.ring.coFac).rightGB(self.mset); G = SolvableGroebnerBaseSeq().rightGB(self.mset); t = System.currentTimeMillis() - t; print "executed right module GB in %s ms" % t; return SolvableSubModule(self.module,"",G.list); def isRightGB(self): '''Test if this is a right Groebner base. ''' t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq(self.module.ring.coFac).isRightGB(self.mset); b = SolvableGroebnerBaseSeq().isRightGB(self.mset); t = System.currentTimeMillis() - t; print "module isRightGB executed in %s ms" % t; return b; def isLeftSyzygy(self,g): '''Test if this is a syzygy of the vectors in g. ''' l = self.list; if isinstance(g,SolvableIdeal): s = g.pset.list; else: if isinstance(g,SolvableSubModule): s = g.mset; l = self.mset; else: raise ValueError, "unknown type %s" % g.getClass().getName(); #print "l = %s" % l; #print "g = %s" % g; t = System.currentTimeMillis(); z = SolvableSyzygySeq(self.module.ring.coFac).isLeftZeroRelation( l, s ); t = System.currentTimeMillis() - t; print "executed isLeftSyzygy in %s ms" % t; return z; def leftSyzygy(self): '''Compute left syzygys of this module. ''' l = self.mset; t = System.currentTimeMillis(); p = SolvableSyzygySeq(self.module.ring.coFac).leftZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; print "executed left module syzygy in %s ms" % t; #print "p = " + str(p.ring.toScript()); m = SolvableModule("",p.ring,p.cols); return SolvableSubModule(m,"",p.list); def isRightSyzygy(self,g): '''Test if this is a syzygy of the vectors in g. ''' l = self.list; if isinstance(g,SolvableIdeal): s = g.pset.list; else: if isinstance(g,SolvableSubModule): s = g.mset; l = self.mset; else: raise ValueError, "unknown type %s" % g.getClass().getName(); #print "l = %s" % l; #print "g = %s" % g; t = System.currentTimeMillis(); z = SolvableSyzygySeq(self.module.ring.coFac).isRightZeroRelation( l, s ); t = System.currentTimeMillis() - t; print "executed isRightSyzygy in %s ms" % t; return z; def rightSyzygy(self): '''Compute right syzygys of this module. ''' l = self.mset; t = System.currentTimeMillis(); # no: p = SolvableSyzygySeq(self.module.ring.coFac).rightZeroRelations( l ); p = SolvableSyzygySeq(self.module.ring.coFac).rightZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; print "executed right module syzygy in %s ms" % t; #print "p = " + str(p.ring.toScript()); m = SolvableModule("",p.ring,p.cols); return SolvableSubModule(m,"",p.list); class SeriesRing: '''Represents a JAS power series ring: UnivPowerSeriesRing. Methods for univariate power series arithmetic. ''' def __init__(self,ringstr="",truncate=None,ring=None,cofac=None,name="z"): '''Ring constructor. ''' if ring == None: if len(ringstr) > 0: sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #plist = tok.nextPolynomialList(); #pset = PolynomialList(pfac,plist); ring = pfac; vname = ring.vars; name = vname[0]; cofac = ring.coFac; if isinstance(cofac,RingElem): cofac = cofac.elem; if truncate == None: self.ring = UnivPowerSeriesRing(cofac,name); else: self.ring = UnivPowerSeriesRing(cofac,truncate,name); else: self.ring = ring; def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); def gens(self): '''Get the generators of the power series ring. ''' L = self.ring.generators(); N = [ RingElem(e) for e in L ]; return N; def inject_variables(self): '''Inject generators as variables into the main global namespace ''' inject_generators(self.gens()); def one(self): '''Get the one of the power series ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the power series ring. ''' return RingElem( self.ring.getZERO() ); def random(self,n): '''Get a random power series. ''' return RingElem( self.ring.random(n) ); def exp(self): '''Get the exponential power series. ''' return RingElem( self.ring.getEXP() ); def sin(self): '''Get the sinus power series. ''' return RingElem( self.ring.getSIN() ); def cos(self): '''Get the cosinus power series. ''' return RingElem( self.ring.getCOS() ); def tan(self): '''Get the tangens power series. ''' return RingElem( self.ring.getTAN() ); def create(self,ifunc=None,jfunc=None,clazz=None): '''Create a power series with given generating function. ifunc(int i) must return a value which is used in RingFactory.fromInteger(). jfunc(int i) must return a value of type ring.coFac. clazz must implement the Coefficients abstract class. ''' class coeff( Coefficients ): def __init__(self,cofac): self.coFac = cofac; def generate(self,i): if jfunc == None: return self.coFac.fromInteger( ifunc(i) ); else: return jfunc(i); if clazz == None: ps = UnivPowerSeries( self.ring, coeff(self.ring.coFac) ); else: ps = UnivPowerSeries( self.ring, clazz ); return RingElem( ps ); def fixPoint(self,psmap): '''Create a power series as fixed point of the given mapping. psmap must implement the UnivPowerSeriesMap interface. ''' ps = self.ring.fixPoint( psmap ); return RingElem( ps ); def gcd(self,a,b): '''Compute the greatest common divisor of a and b. ''' if isinstance(a,RingElem): a = a.elem; if isinstance(b,RingElem): b = b.elem; return RingElem( a.gcd(b) ); def fromPoly(self,a): '''Convert a GenPolynomial to a power series. ''' if isinstance(a,RingElem): a = a.elem; return RingElem( self.ring.fromPolynomial(a) ); class MultiSeriesRing: '''Represents a JAS power series ring: MultiVarPowerSeriesRing. Methods for multivariate power series arithmetic. ''' def __init__(self,ringstr="",truncate=None,ring=None,cofac=None,names=None): '''Ring constructor. ''' if ring == None: if len(ringstr) > 0: sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer(pfac,sr); #plist = tok.nextPolynomialList(); #pset = PolynomialList(pfac,plist); ring = pfac; names = ring.vars; cofac = ring.coFac; if isinstance(cofac,RingElem): cofac = cofac.elem; if truncate == None: self.ring = MultiVarPowerSeriesRing(cofac,names); else: self.ring = MultiVarPowerSeriesRing(cofac,len(names),truncate,names); else: self.ring = ring; def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); def gens(self): '''Get the generators of the power series ring. ''' L = self.ring.generators(); N = [ RingElem(e) for e in L ]; return N; def inject_variables(self): '''Inject generators as variables into the main global namespace ''' inject_generators(self.gens()); def one(self): '''Get the one of the power series ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the power series ring. ''' return RingElem( self.ring.getZERO() ); def random(self,n): '''Get a random power series. ''' return RingElem( self.ring.random(n) ); def exp(self,r): '''Get the exponential power series, var r. ''' return RingElem( self.ring.getEXP(r) ); def sin(self,r): '''Get the sinus power series, var r. ''' return RingElem( self.ring.getSIN(r) ); def cos(self,r): '''Get the cosinus power series, var r. ''' return RingElem( self.ring.getCOS(r) ); def tan(self,r): '''Get the tangens power series, var r. ''' return RingElem( self.ring.getTAN(r) ); def create(self,ifunc=None,jfunc=None,clazz=None): '''Create a power series with given generating function. ifunc(int i) must return a value which is used in RingFactory.fromInteger(). jfunc(int i) must return a value of type ring.coFac. clazz must implement the Coefficients abstract class. ''' class coeff( MultiVarCoefficients ): def __init__(self,r): MultiVarCoefficients.__init__(self,r); self.coFac = r.coFac; def generate(self,i): if jfunc == None: return self.coFac.fromInteger( ifunc(i) ); else: return jfunc(i); #print "ifunc" if clazz == None: ps = MultiVarPowerSeries( self.ring, coeff(self.ring) ); else: ps = MultiVarPowerSeries( self.ring, clazz ); #print "ps ", ps.toScript(); return RingElem( ps ); def fixPoint(self,psmap): '''Create a power series as fixed point of the given mapping. psmap must implement the UnivPowerSeriesMap interface. ''' ps = self.ring.fixPoint( psmap ); return RingElem( ps ); def gcd(self,a,b): '''Compute the greatest common divisor of a and b. ''' if isinstance(a,RingElem): a = a.elem; if isinstance(b,RingElem): b = b.elem; return RingElem( a.gcd(b) ); def fromPoly(self,a): '''Convert a GenPolynomial to a power series. ''' if isinstance(a,RingElem): a = a.elem; return RingElem( self.ring.fromPolynomial(a) ); class PSIdeal: '''Represents a JAS power series ideal. Method for Standard bases. ''' def __init__(self,ring,polylist,ideal=None,list=None): '''PSIdeal constructor. ''' if isinstance(ring,Ring) or isinstance(ring,PolyRing): ring = MultiVarPowerSeriesRing(ring.ring); if isinstance(ring,MultiSeriesRing): ring = ring.ring; self.ring = ring; #print "ring = ", ring.toScript(); if ideal != None: polylist = ideal.pset.list; if list == None: self.polylist = pylist2arraylist( [ a.elem for a in polylist ] ); #print "polylist = ", self.polylist; self.list = self.ring.fromPolynomial(self.polylist); else: self.polylist = None; self.list = pylist2arraylist( [ a.elem for a in list ] ); def __str__(self): '''Create a string representation. ''' ll = [ e.toScript() for e in self.list ] return "( " + ", ".join(ll) + " )"; def STD(self,trunc=None): '''Compute a standard base. ''' pr = self.ring; if trunc != None: pr.setTruncate(trunc); #print "pr = ", pr.toScript(); F = self.list; #print "F = ", F; tm = StandardBaseSeq(); t = System.currentTimeMillis(); S = tm.STD(F); t = System.currentTimeMillis() - t; print "sequential standard base executed in %s ms" % t; #Sp = [ RingElem(a.asPolynomial()) for a in S ]; Sp = [ RingElem(a) for a in S ]; #return Sp; return PSIdeal(self.ring,None,list=Sp); def pylist2arraylist(list,fac=None,rec=1): '''Convert a Python list to a Java ArrayList. If list is a Python list, it is converted, else list is left unchanged. ''' #print "list type(%s) = %s" % (list,type(list)); if isinstance(list,PyList) or isinstance(list,PyTuple): L = ArrayList(); for e in list: t = True; if isinstance(e,RingElem): t = False; e = e.elem; if isinstance(e,PyList) or isinstance(e,PyTuple): if rec <= 1: e = makeJasArith(e); else: t = False; e = pylist2arraylist(e,fac,rec-1); try: #n = e.getClass().getSimpleName(); if isinstance(e,ArrayList) or isinstance(e,LinkedList): t = False; except: pass; if t and fac != None: #print "e.p(%s) = %s :: %s" % (e,e,fac); e = fac.parse( str(e) ); #or makeJasArith(e) ? L.add(e); list = L; #print "list type(%s) = %s" % (list,type(list)); return list def arraylist2pylist(list,rec=1): '''Convert a Java ArrayList to a Python list. If list is a Java ArrayList list, it is converted, else list is left unchanged. ''' #print "list type(%s) = %s" % (list,type(list)); if isinstance(list,List): L = []; for e in list: if not isinstance(e,RingElem): e = RingElem(e); L.append(e); list = L; #print "list type(%s) = %s" % (list,type(list)); return list def makeJasArith(item): '''Construct a jas.arith object. If item is a python tuple or list then a BigRational, BigComplex is constructed. If item is a python float then a BigDecimal is constructed. Otherwise, item is returned unchanged. ''' #print "item type(%s) = %s" % (item,type(item)); if isinstance(item,PyInteger) or isinstance(item,PyLong): return BigInteger( item ); if isinstance(item,PyFloat): # ?? what to do ?? return BigDecimal( str(item) ); if isinstance(item,PyTuple) or isinstance(item,PyList): if len(item) > 2: print "len(item) > 2, remaining items ignored"; #print "item[0] type(%s) = %s" % (item[0],type(item[0])); isc = isinstance(item[0],PyTuple) or isinstance(item[0],PyList) if len(item) > 1: isc = isc or isinstance(item[1],PyTuple) or isinstance(item[1],PyList); if isc: if len(item) > 1: re = makeJasArith( item[0] ); if not re.isField(): re = BigRational( re.val ); im = makeJasArith( item[1] ); if not im.isField(): im = BigRational( im.val ); jasArith = BigComplex( re, im ); else: re = makeJasArith( item[0] ); jasArith = BigComplex( re ); else: if len(item) > 1: jasArith = BigRational( item[0] ).divide( BigRational( item[1] ) ); else: jasArith = BigRational( item[0] ); #print "makeJasArith: type(%s) = %s" % (jasArith,type(jasArith)); return jasArith; #print "makeJasArith: unknown item type(%s) = %s" % (item,type(item)); return item; def ZZ(z=0): '''Create JAS BigInteger as ring element. ''' if isinstance(z,RingElem): z = z.elem; r = BigInteger(z); return RingElem(r); def ZM(m,z=0,field=False): '''Create JAS ModInteger as ring element. ''' if isinstance(m,RingElem): m = m.elem; if isinstance(z,RingElem): z = z.elem; if z != 0 and ( z == False or z == True ): # never true field = z; z = 0; if m < ModLongRing.MAX_LONG: if m < ModIntRing.MAX_INT: if field: mf = ModIntRing(m,field); else: mf = ModIntRing(m); r = ModInt(mf,z); else: if field: mf = ModLongRing(m,field); else: mf = ModLongRing(m); r = ModLong(mf,z); else: if field: mf = ModIntegerRing(m,field); else: mf = ModIntegerRing(m); r = ModInteger(mf,z); return RingElem(r); def ZML(m,z=0,field=False): '''Create JAS ModLong as ring element. ''' return ZM(m,z,field); def ZMI(m,z=0,field=False): '''Create JAS ModInt as ring element. ''' return ZM(m,z,field); def GF(m,z=0): '''Create JAS ModInteger as field element. ''' #print "m = %s" % m return ZM(m,z,True); def GFL(m,z=0): '''Create JAS ModLong as field element. ''' #print "m = %s" % m return ZM(m,z,True); def GFI(m,z=0): '''Create JAS ModInt as field element. ''' return ZM(m,z,True); def QQ(d=0,n=1): '''Create JAS BigRational as ring element. ''' if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if n == 1: if d == 0: r = BigRational(); else: r = BigRational(d); else: d = BigRational(d); n = BigRational(n); r = d.divide(n); # BigRational(d,n); only for short integers return RingElem(r); def CC(re=BigRational(),im=BigRational()): '''Create JAS BigComplex as ring element. ''' if re == 0: re = BigRational(); if im == 0: im = BigRational(); if isinstance(re,PyTuple) or isinstance(re,PyList): if isinstance(re[0],PyTuple) or isinstance(re[0],PyList): if len(re) > 1: im = QQ( re[1] ); re = QQ( re[0] ); else: re = QQ(re); # re = makeJasArith( re ); if isinstance(im,PyTuple) or isinstance(im,PyList): im = QQ( im ); # im = makeJasArith( im ); if isinstance(re,RingElem): re = re.elem; if isinstance(im,RingElem): im = im.elem; if im.isZERO(): if re.isZERO(): c = BigComplex(); else: c = BigComplex(re); else: c = BigComplex(re,im); return RingElem(c); def CR(re=BigRational(),im=BigRational(),ring=None): '''Create JAS generic Complex as ring element. ''' if re == 0: re = BigRational(); if im == 0: im = BigRational(); if isinstance(re,PyTuple) or isinstance(re,PyList): if isinstance(re[0],PyTuple) or isinstance(re[0],PyList): if len(re) > 1: im = QQ( re[1] ); re = QQ( re[0] ); else: re = QQ(re); # re = makeJasArith( re ); if isinstance(im,PyTuple) or isinstance(im,PyList): im = QQ( im ); # im = makeJasArith( im ); if isinstance(re,RingElem): re = re.elem; if isinstance(im,RingElem): im = im.elem; if ring == None: ring = re.factory(); r = ComplexRing(ring); #print "d type(%s) = %s" % (r,type(r)); if im.isZERO(): if re.isZERO(): c = Complex(r); else: c = Complex(r,re); else: c = Complex(r,re,im); #print "d type(%s) = %s" % (c,type(c)); return RingElem(c); def DD(d=0): '''Create JAS BigDecimal as ring element. ''' if isinstance(d,RingElem): d = d.elem; if isinstance(d,PyFloat): d = str(d); #print "d type(%s) = %s" % (d,type(d)); if d == 0: r = BigDecimal(); else: r = BigDecimal(d); return RingElem(r); def Quat(re=BigRational(),im=BigRational(),jm=BigRational(),km=BigRational()): '''Create JAS BigQuaternion as ring element. ''' if re == 0: re = BigRational(); if im == 0: im = BigRational(); if jm == 0: jm = BigRational(); if km == 0: km = BigRational(); if isinstance(re,PyTuple) or isinstance(re,PyList): if isinstance(re[0],PyTuple) or isinstance(re[0],PyList): if len(re) > 1: im = QQ( re[1] ); re = QQ( re[0] ); else: re = QQ(re); # re = makeJasArith( re ); if isinstance(im,PyTuple) or isinstance(im,PyList): im = QQ( im ); if isinstance(jm,PyTuple) or isinstance(jm,PyList): jm = QQ( jm ); if isinstance(km,PyTuple) or isinstance(km,PyList): kim = QQ( km ); # im = makeJasArith( im ); if isinstance(re,RingElem): re = re.elem; if isinstance(im,RingElem): im = im.elem; if isinstance(jm,RingElem): jm = jm.elem; if isinstance(km,RingElem): km = km.elem; cf = BigQuaternionRing(); c = BigQuaternion(cf, re,im,jm,km); return RingElem(c); def Oct(ro=0,io=0): '''Create JAS BigOctonion as ring element. ''' cf = BigQuaternionRing(); if ro == 0: ro = BigQuaternion(cf); if io == 0: io = BigQuaternion(cf); if isinstance(ro,PyTuple) or isinstance(ro,PyList): if isinstance(ro[0],PyTuple) or isinstance(ro[0],PyList): if len(ro) > 1: io = QQ( ro[1] ); ro = QQ( ro[0] ); else: ro = QQ(ro); # re = makeJasArith( re ); if isinstance(io,PyTuple) or isinstance(io,PyList): io = QQ( io ); # im = makeJasArith( im ); if isinstance(ro,RingElem): ro = ro.elem; if isinstance(io,RingElem): io = io.elem; c = BigOctonion(ro,io); return RingElem(c); def AN(m,z=0,field=False,pr=None): '''Create JAS AlgebraicNumber as ring element. ''' if isinstance(m,RingElem): m = m.elem; if isinstance(z,RingElem): z = z.elem; # if (z == True or z == False): # not working # field = z; # z = 0; #print "m.getClass() = " + str(m.getClass().getName()); #print "field = " + str(field); if isinstance(m,AlgebraicNumber): mf = AlgebraicNumberRing(m.factory().modul,m.factory().isField()); else: if field: mf = AlgebraicNumberRing(m,field); else: mf = AlgebraicNumberRing(m); #print "mf = " + mf.toString(); if z == 0: r = AlgebraicNumber(mf); else: r = AlgebraicNumber(mf,z); return RingElem(r); _finiteFields = {}; '''List of already constructed FiniteFields.''' def FF(p,n,z=0): '''Create JAS Field element as ring element. FF has pn elements. ''' if isinstance(p,RingElem): p = p.elem; if isinstance(n,RingElem): n = n.elem; if isinstance(z,RingElem): z = z.elem; if (p == 0): raise "p =="; if (n == 0): raise "n =="; field = True; if not PrimeInteger.isPrime(p): field = False; raise ValueError, str(p) + " not prime."; mf = _finiteFields.get( (p,n) ); if mf == None: cf = GF(p).ring; mf = PolyUfdUtil.algebraicNumberField(cf,n); _finiteFields[ (p,n) ] = mf; #print "mf = " + mf.toScript(); if z == 0: r = AlgebraicNumber(mf); else: r = AlgebraicNumber(mf,z); return RingElem(r); def RealN(m,i,r=0): '''Create JAS RealAlgebraicNumber as ring element. ''' if isinstance(m,RingElem): m = m.elem; if isinstance(r,RingElem): r = r.elem; if isinstance(i,PyTuple) or isinstance(i,PyList): i = pylist2arraylist(i,BigRational(),1); i = Interval(i[0],i[1]); #print "m.getClass() = " + str(m.getClass().getName()); if isinstance(m,RealAlgebraicNumber): mf = RealAlgebraicRing(m.factory().algebraic.modul,i); else: mf = RealAlgebraicRing(m,i); if r == 0: rr = RealAlgebraicNumber(mf); else: rr = RealAlgebraicNumber(mf,r); return RingElem(rr); def RF(pr,d=0,n=1): '''Create JAS rational function Quotient as ring element. ''' if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if isinstance(pr,RingElem): pr = pr.elem; if isinstance(pr,Ring): pr = pr.ring; qr = QuotientRing(pr); if d == 0: r = Quotient(qr); else: if n == 1: r = Quotient(qr,d); else: r = Quotient(qr,d,n); return RingElem(r); def RC(ideal,r=0): '''Create JAS polynomial Residue as ring element. ''' if ideal == None: raise ValueError, "No ideal given." if isinstance(ideal,Ideal): ideal = jas.application.Ideal(ideal.pset); #ideal.doGB(); #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; if isinstance(ideal.getList().get(0).ring,ResidueRing): rc = ResidueRing( ideal.getList().get(0).ring.ideal ); else: rc = ResidueRing(ideal); if isinstance(r,RingElem): r = r.elem; if r == 0: r = Residue(rc); else: r = Residue(rc,r); return RingElem(r); def LC(ideal,d=0,n=1): '''Create JAS polynomial Local as ring element. ''' if ideal == None: raise ValueError, "No ideal given." if isinstance(ideal,Ideal): ideal = jas.application.Ideal(ideal.pset); #ideal.doGB(); #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; if isinstance(ideal.getList().get(0).ring,LocalRing): lc = LocalRing( ideal.getList().get(0).ring.ideal ); else: lc = LocalRing(ideal); if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if d == 0: r = Local(lc); else: if n == 1: r = Local(lc,d); else: r = Local(lc,d,n); return RingElem(r); def SRF(pr,d=0,n=1): '''Create JAS rational function SolvableQuotient as ring element. ''' if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if isinstance(pr,RingElem): pr = pr.elem; if isinstance(pr,Ring): pr = pr.ring; qr = SolvableQuotientRing(pr); if d == 0: r = SolvableQuotient(qr); else: if n == 1: r = SolvableQuotient(qr,d); else: r = SolvableQuotient(qr,d,n); return RingElem(r); def SRC(ideal,r=0): '''Create JAS polynomial SolvableResidue as ring element. ''' #print "ideal = " + str(ideal); if ideal == None: # does not work print "ideal = " + str(ideal); if False: raise ValueError, "No ideal given." if isinstance(ideal,SolvableIdeal): ideal = jas.application.SolvableIdeal(ideal.pset); #ideal.doGB(); #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; if isinstance(ideal.getList().get(0).ring,SolvableResidueRing): rc = SolvableResidueRing( ideal.getList().get(0).ring.ideal ); else: rc = SolvableResidueRing(ideal); if isinstance(r,RingElem): r = r.elem; if r == 0: r = SolvableResidue(rc); else: r = SolvableResidue(rc,r); return RingElem(r); def SLC(ideal,d=0,n=1): '''Create JAS polynomial SolvableLocal as ring element. ''' if ideal == None: #print "ideal = " + str(ideal); if False: raise ValueError, "No ideal given." if isinstance(ideal,SolvableIdeal): ideal = jas.application.SolvableIdeal(ideal.pset); #ideal.doGB(); #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; if isinstance(ideal.getList().get(0).ring,SolvableLocalRing): lc = SolvableLocalRing( ideal.getList().get(0).ring.ideal ); else: lc = SolvableLocalRing(ideal); if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if d == 0: r = SolvableLocal(lc); else: if n == 1: r = SolvableLocal(lc,d); else: r = SolvableLocal(lc,d,n); return RingElem(r); def SLR(ideal,d=0,n=1): '''Create JAS polynomial SolvableLocalResidue as ring element. ''' if ideal == None: #print "ideal = " + str(ideal); if False: raise ValueError, "No ideal given." if isinstance(ideal,SolvableIdeal): ideal = jas.application.SolvableIdeal(ideal.pset); #ideal.doGB(); #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; cfr = ideal.getList().get(0).ring; if isinstance(cfr,SolvableLocalResidueRing): lc = SolvableLocalResidueRing( cfr.ideal ); else: lc = SolvableLocalResidueRing(ideal); if isinstance(d,PyTuple) or isinstance(d,PyList): if n != 1: print "%s ignored" % n; if len(d) > 1: n = d[1]; d = d[0]; if isinstance(d,RingElem): d = d.elem; if isinstance(n,RingElem): n = n.elem; if d == 0: r = SolvableLocalResidue(lc); else: if n == 1: r = SolvableLocalResidue(lc,d); else: r = SolvableLocalResidue(lc,d,n); return RingElem(r); def RR(flist,n=1,r=0): '''Create JAS regular ring Product as ring element. ''' if not isinstance(n,PyInteger): r = n; n = 1; if flist == None: raise ValueError, "No list given." if isinstance(flist,PyList) or isinstance(flist,PyTuple): flist = pylist2arraylist( [ x.factory() for x in flist ], rec=1); ncop = 0; else: ncop = n; if isinstance(flist,RingElem): flist = flist.elem; flist = flist.factory(); ncop = n; #print "flist = " + str(flist); #print "ncop = " + str(ncop); if ncop == 0: pr = ProductRing(flist); else: pr = ProductRing(flist,ncop); #print "r type(%s) = %s" % (r,type(r)); if isinstance(r,RingElem): r = r.elem; try: #print "r.class() = %s" % r.getClass().getSimpleName(); if isinstance(r,Product): #print "r.val = %s" % r.val; r = r.val; except: pass; #print "r = " + str(r); if r == 0: r = Product(pr); else: r = Product(pr,r); return RingElem(r); def PS(cofac,name,f=None,truncate=None): '''Create JAS UnivPowerSeries as ring element. ''' cf = cofac; if isinstance(cofac,RingElem): cf = cofac.elem.factory(); if isinstance(cofac,Ring): cf = cofac.ring; if isinstance(truncate,RingElem): truncate = truncate.elem; if truncate == None: ps = UnivPowerSeriesRing(cf,name); else: ps = UnivPowerSeriesRing(cf,truncate,name); if f == None: r = ps.getZERO(); else: class Coeff( Coefficients ): def __init__(self,cofac): self.coFac = cofac; def generate(self,i): a = f(i); if isinstance(a,RingElem): a = a.elem; #print "a = " + str(a); return a; r = UnivPowerSeries(ps,Coeff(cf)); return RingElem(r); def MPS(cofac,names,f=None,truncate=None): '''Create JAS MultiVarPowerSeries as ring element. ''' cf = cofac; if isinstance(cofac,RingElem): cf = cofac.elem.factory(); if isinstance(cofac,Ring): cf = cofac.ring; vars = names; if isinstance(vars,PyString): vars = GenPolynomialTokenizer.variableList(vars); nv = len(vars); if isinstance(truncate,RingElem): truncate = truncate.elem; if truncate == None: ps = MultiVarPowerSeriesRing(cf,nv,vars); else: ps = MultiVarPowerSeriesRing(cf,nv,vars,truncate); if f == None: r = ps.getZERO(); else: class MCoeff( MultiVarCoefficients ): def __init__(self,r): MultiVarCoefficients.__init__(self,r); self.coFac = r.coFac; def generate(self,i): a = f(i); if isinstance(a,RingElem): a = a.elem; return a; r = MultiVarPowerSeries(ps,MCoeff(ps)); #print "r = " + str(r); return RingElem(r); def Vec(cofac,n,v=None): '''Create JAS GenVector ring element. ''' cf = cofac; if isinstance(cofac,RingElem): cf = cofac.elem.factory(); if isinstance(cofac,Ring): cf = cofac.ring; if isinstance(n,RingElem): n = n.elem; if isinstance(v,RingElem): v = v.elem; if isinstance(v,PyList) or isinstance(v,PyTuple): v = pylist2arraylist(v,cf,rec=1); vr = GenVectorModul(cf,n); if v == None: r = GenVector(vr); else: r = GenVector(vr,v); return RingElem(r); def Mat(cofac,n,m,v=None): '''Create JAS GenMatrix ring element. ''' cf = cofac; if isinstance(cofac,RingElem): cf = cofac.elem.factory(); if isinstance(cofac,Ring): cf = cofac.ring; if isinstance(n,RingElem): n = n.elem; if isinstance(m,RingElem): m = m.elem; if isinstance(v,RingElem): v = v.elem; #print "cf type(%s) = %s" % (cf,type(cf)); if isinstance(v,PyList) or isinstance(v,PyTuple): v = pylist2arraylist(v,cf,rec=2); mr = GenMatrixRing(cf,n,m); if v == None: r = GenMatrix(mr); else: r = GenMatrix(mr,v); return RingElem(r); def coercePair(a,b): '''Coerce type a to type b or type b to type a. ''' #print "a type(%s) = %s" % (a,type(a)); #print "b type(%s) = %s" % (b,type(b)); try: if not a.isPolynomial() and b.isPolynomial(): s = b.coerce(a); o = b; else: if not a.isAlgNum() and b.isAlgNum(): s = b.coerce(a); o = b; else: s = a; o = a.coerce(b); except: s = a; o = a.coerce(b); return (s,o); def isJavaInstance(a): '''Test if a is a Java instance. ''' #print "a type(%s) = %s" % (a,type(a)); try: c = a.getClass(); except: return False; return True; class RingElem: '''Proxy for JAS ring elements. Methods to be used as + - * ** / %. ''' def __init__(self,elem): '''Constructor for ring element. ''' if isinstance(elem,RingElem): self.elem = elem.elem; else: self.elem = elem; try: self.ring = self.elem.factory(); except: self.ring = self.elem; def __str__(self): '''Create a string representation. ''' try: return str(self.elem.toScript()); except: return str(self.elem); def zero(self): '''Zero element of this ring. ''' return RingElem( self.ring.getZERO() ); def isZERO(self): '''Test if this is the zero element of the ring. ''' return self.elem.isZERO(); def one(self): '''One element of this ring. ''' return RingElem( self.ring.getONE() ); def isONE(self): '''Test if this is the one element of the ring. ''' return self.elem.isONE(); def signum(self): '''Get the sign of this element. ''' return self.elem.signum(); def __abs__(self): '''Absolute value. ''' return RingElem( self.elem.abs() ); def __neg__(self): '''Negative value. ''' return RingElem( self.elem.negate() ); def __pos__(self): '''Positive value. ''' return self; def coerce(self,other): '''Coerce other to self. ''' #print "self type(%s) = %s" % (self,type(self)); #print "other type(%s) = %s" % (other,type(other)); #print "self.elem class(%s) = %s" % (self.elem,self.elem.getClass()); if isinstance(self.elem,GenVector): #print "self, other = %s, %s " % (self,other); if isinstance(other,PyTuple) or isinstance(other,PyList): o = pylist2arraylist(other,self.elem.factory().coFac,rec=1); o = GenVector(self.elem.factory(),o); return RingElem( o ); if isinstance(self.elem,GenMatrix): #print "self, other = %s, %s " % (type(self),type(other)); #print "o type(%s) = %s, str = %s" % (o,type(o),str(o)); if isinstance(other,PyTuple) or isinstance(other,PyList): o = pylist2arraylist(other,self.elem.factory().coFac,rec=2); o = GenMatrix(self.elem.factory(),o); return RingElem( o ); if isinstance(other,GenVector): o = other; return RingElem( o ); if isinstance(self.elem,GenPolynomial) or isinstance(self.elem,AlgebraicNumber): #print "self, other = %s, %s " % (type(self),type(other)); #print "o type(%s) = %s, str = %s" % (other,type(other),str(other)); if isinstance(other,PyInteger) or isinstance(other,PyLong): o = self.ring.fromInteger(other); return RingElem( o ); if isinstance(other,PyList) or isinstance(other,PyTuple): #print "self, other = %s, %s " % (type(self),type(other)); o = self.ring.parse( str(makeJasArith(other)) ); return RingElem( o ); if isinstance(other,RingElem): o = other.elem; else: o = other; if o == None: return RingElem( GenPolynomial(self.ring) ) if isJavaInstance(o): #print "self.elem, o = %s, %s " % (type(self.ring.coFac),type(o)); if isinstance(o,ExpVector): # want startsWith or substring(0,8) == "ExpVector": #o = GenPolynomial(self.ring,o); o = self.ring.valueOf(o); return RingElem( o ); #o = self.ring.parse( str(makeJasArith(o)) ); #o = self.ring.valueOf( makeJasArith(o) ); if isinstance(self.elem,GenPolynomial): if self.ring.coFac.getClass().getSimpleName() == o.getClass().getSimpleName(): #o = GenPolynomial(self.ring,o); o = self.ring.valueOf(o); return RingElem( o ); else: # AlgebraicNumber if self.ring.ring.coFac.getClass().getSimpleName() == o.getClass().getSimpleName(): o = self.ring.valueOf(o); return RingElem( o ); if isinstance(other,RingElem): if self.isPolynomial() and not other.isPolynomial(): #print "parse self.ring = %s" % (self.ring); o = self.ring.parse( other.elem.toString() ); # not toScript() #print "o type(%s) = %s, str = %s" % (o,type(o),str(o)); return RingElem( o ); return other; #print "--1"; if isinstance(other,PyTuple) or isinstance(other,PyList): # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this o = makeJasArith(other); #print "other class(%s) = %s" % (o,o.getClass()); if self.isPolynomial(): #print "other type(%s) = %s" % (o,type(o)); o = self.ring.parse( o.toString() ); # not toScript(); #o = o.elem; if isinstance(self.elem,BigComplex): #print "other type(%s) = %s" % (o,type(o)); o = CC( o ); o = o.elem; if isinstance(self.elem,BigQuaternion): #print "other type(%s) = %s" % (o,type(o)); o = Quat( o ); o = o.elem; if isinstance(self.elem,BigOctonion): #print "other type(%s) = %s" % (o,type(o)); o = Oct( Quat(o) ); o = o.elem; if isinstance(self.elem,Product): #print "other type(%s) = %s" % (o,type(o)); o = RR(self.ring, self.elem.multiply(o) ); # valueOf #print "o = %s" % o; o = o.elem; return RingElem(o); #print "--2"; # test if self.elem is a factory itself if self.isFactory(): if isinstance(other,PyInteger) or isinstance(other,PyLong): o = self.elem.fromInteger(other); else: if isinstance(other,PyFloat): # ?? what to do ?? o = self.elem.fromInteger( int(other) ); else: print "coerce_1: unknown other type(%s) = %s" % (other,type(other)); o = self.elem.parse( str(other) ); return RingElem(o); #print "--3"; #print "other type(%s) = %s" % (other,type(other)); # self.elem has a ring factory if isinstance(other,PyInteger) or isinstance(other,PyLong): o = self.elem.factory().fromInteger(other); else: if isinstance(other,PyFloat): # ?? what to do ?? #print "other type(%s) = %s" % (other,type(other)); #print "self type(%s) = %s" % (self.elem,self.elem.getClass().getName()); o = BigDecimal(other); if isinstance(self.elem,Product): o = RR(self.ring, self.elem.idempotent().multiply(o) ); # valueOf o = o.elem; else: o = self.elem.factory().getZERO().sum( o ); else: print "coerce_2: unknown other type(%s) = %s" % (other,type(other)); print "coerce_2: self type(%s) = %s" % (self,type(self)); o = self.elem.factory().parse( str(other) ); #print "--4"; return RingElem(o); def isFactory(self): '''Test if this is itself a ring factory. ''' f = self.elem.factory(); if self.elem == f: return True; else: return False; def isPolynomial(self): '''Test if this is a polynomial. ''' try: nv = self.elem.ring.nvar; except: return False; return True; def isAlgNum(self): '''Test if this is an algebraic number. ''' try: nv = self.elem.ring.ring.nvar; except: #print "isAlgNum fail: type(%s) = %s" % (self.elem,type(self.elem)); return False; #print "isAlgNum true: type(%s) = %s" % (self.elem,type(self.elem)); return True; def __cmp__(self,other): '''Compare two ring elements. ''' [s,o] = coercePair(self,other); return s.elem.compareTo( o.elem ); def __hash__(self): '''Hash value. ''' return self.elem.hashCode(); def __len__(self): '''Length of the element. ''' return self.elem.length(); def __mul__(self,other): '''Multiply two ring elements. ''' [s,o] = coercePair(self,other); #print "self type(%s) = %s" % (s,type(s)); #print "other type(%s) = %s" % (o,type(o)); if isinstance(s.elem,GenMatrix) and isinstance(o.elem,GenVector): return RingElem( BasicLinAlg().rightProduct(o.elem, s.elem) ); if isinstance(s.elem,GenVector) and isinstance(o.elem,GenMatrix): return RingElem( BasicLinAlg().leftProduct(s.elem, o.elem) ); return RingElem( s.elem.multiply( o.elem ) ); def __rmul__(self,other): '''Reverse multiply two ring elements. ''' [s,o] = coercePair(self,other); return o.__mul__(s); def __add__(self,other): '''Add two ring elements. ''' [s,o] = coercePair(self,other); return RingElem( s.elem.sum( o.elem ) ); def __radd__(self,other): '''Reverse add two ring elements. ''' [s,o] = coercePair(self,other); return o.__add__(s); def __sub__(self,other): '''Subtract two ring elements. ''' [s,o] = coercePair(self,other); return RingElem( s.elem.subtract( o.elem ) ); def __rsub__(self,other): '''Reverse subtract two ring elements. ''' [s,o] = coercePair(self,other); return o.__sub__(self); def __div__(self,other): '''Divide two ring elements. ''' [s,o] = coercePair(self,other); return RingElem( s.elem.divide( o.elem ) ); def __rdiv__(self,other): '''Reverse divide two ring elements. ''' [s,o] = coercePair(self,other); return o.__div__(s); def __mod__(self,other): '''Modular remainder of two ring elements. ''' [s,o] = coercePair(self,other); return RingElem( s.elem.remainder( o.elem ) ); def __xor__(self,other): '''Can not be used as power. ''' return None; def __pow__(self,other,n=None): '''Power of this to other. ''' #print "self type(%s) = %s" % (self,type(self)); #print "pow other type(%s) = %s" % (other,type(other)); if isinstance(other,PyInteger) or isinstance(other,PyLong): n = other; else: if isinstance(other,RingElem): n = other.elem; #if isinstance(n,BigRational): # does not work if isinstance(n,BigRational): n = n.numerator().intValue() / n.denominator().intValue(); #if isinstance(n,BigInteger): # does not work if isinstance(n,BigInteger) or isinstance(n,Long) or isinstance(n,Integer): n = n.intValue(); if n == None: n = other; if self.isFactory(): p = Power(self.elem).power( self.elem, n ); else: p = Power(self.ring).power( self.elem, n ); return RingElem( p ); def __eq__(self,other): '''Test if two ring elements are equal. ''' if other == None: return False; [s,o] = coercePair(self,other); return s.elem.equals(o.elem) def __ne__(self,other): '''Test if two ring elements are not equal. ''' if other == None: return False; [s,o] = coercePair(self,other); return not self.elem.equals(o.elem) def __float__(self): '''Convert to Python float. ''' #print "self type(%s) = %s" % (self,type(self)); e = self.elem; if isinstance(e,BigInteger): e = BigRational(e); if isinstance(e,BigRational): e = BigDecimal(e); if isinstance(e,BigDecimal): e = e.toString(); e = float(e); return e def __getitem__(self,i): '''Matrix or vector entry. ''' if isinstance(i,RingElem): i = i.elem; if isinstance(self.elem,GenMatrix): e = self.elem.getRow(i); return RingElem( e ); if isinstance(self.elem,GenVector): e = self.elem.get(i); return RingElem( e ); raise ValueError, "no matrix or vector " + str(self.ring) def factory(self): '''Get the factory of this element. ''' fac = self.elem.factory(); try: nv = fac.nvar; except: return RingElem(fac); #return PolyRing(fac.coFac,fac.getVars(),fac.tord); return RingElem(fac); def gens(self): '''Get the generators for the factory of this element. ''' L = self.elem.factory().generators(); #print "L = %s" % L; N = [ RingElem(e) for e in L ]; #print "N = %s" % N; return N; def inject_variables(self): '''Inject generators as variables into the main global namespace ''' inject_generators(self.gens()); def monic(self): '''Monic polynomial. ''' return RingElem( self.elem.monic() ); def homogenize(self,var='h'): '''homogenize polynomial. INPUT: - "var" - variable name to use for homogenization ''' if not self.isPolynomial(): return self if var in self.ring.vars: r = self.ring.extend(1); print "WARN: case for variable %s not implemented, new name %s" % (var,r.vars[-1]) else: r = self.ring.extend([var]); h = self.elem; h = h.homogenize(r); return RingElem(h); def evaluate(self,a): '''Evaluate at a for power series or polynomial. ''' #print "self type(%s) = %s" % (self,type(self)); #print "a type(%s) = %s" % (a,type(a)); x = None; if isinstance(a,RingElem): x = a.elem; if isinstance(a,PyTuple) or isinstance(a,PyList): # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this #x = makeJasArith(a); x = pylist2arraylist(a); else: x = pylist2arraylist([a]); try: if isinstance(self.elem,UnivPowerSeries): e = self.elem.evaluate(x[0]); else: if isinstance(self.elem,MultiVarPowerSeries): e = self.elem.evaluate(x); else: x = [ p.leadingBaseCoefficient() for p in x ]; #puts "x = " + x[0].getClass().getSimpleName().to_s; e = PolyUtil.evaluateAll(self.ring.coFac, self.elem, x); except: e = 0; return RingElem( e ); def integrate(self,a=0,r=None): '''Integrate a power series or rational function with constant a. a is the integration constant, r is for partial integration in variable r. ''' #print "self type(%s) = %s" % (self,type(self)); #print "a type(%s) = %s" % (a,type(a)); x = None; if isinstance(a,RingElem): x = a.elem; if isinstance(a,PyTuple) or isinstance(a,PyList): # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this x = makeJasArith(a); # power series try: if r != None: e = self.elem.integrate(x,r); else: e = self.elem.integrate(x); return RingElem( e ); except: pass; cf = self.elem.ring; try: cf = cf.ring; except: pass; # rational function integrator = ElementaryIntegration(cf.coFac); ei = integrator.integrate(self.elem); return ei; def differentiate(self,r=None): '''Differentiate a power series. r is for partial differentiation in variable r. ''' try: if r != None: e = self.elem.differentiate(r); else: e = self.elem.differentiate(); except: e = self.elem.factory().getZERO(); return RingElem( e ); def random(self,n=3): '''Random element. n size for random element will be less than 2**n. ''' if isinstance(n,RingElem): n = n.elem; return RingElem( self.elem.factory().random(n) ); def gcd(self,b): '''Compute the greatest common divisor of this/self and b. ''' a = self.elem; if isinstance(b,RingElem): b = b.elem; else: b = element( b ); b = b.elem; if self.isPolynomial(): engine = Ring.getEngineGcd(self.ring); return RingElem( engine.gcd(a,b) ); else: return RingElem( a.gcd(b) ); def squarefreeFactors(self): '''Compute squarefree factors of polynomial. ''' a = self.elem; if self.isPolynomial(): sqf = Ring.getEngineSqf(self.ring); if sqf == None: raise ValueError, "squarefreeFactors not implemented for " + self.ring.to_s; cf = self.ring.coFac; if isinstance(cf,GenPolynomialRing): e = sqf.recursiveSquarefreeFactors( a ); else: e = sqf.squarefreeFactors( a ); L = {}; for a in e.keySet(): i = e.get(a); L[ RingElem( a ) ] = i; return L; else: raise ValueError, "squarefreeFactors not implemented for " + a.to_s; def factors(self): '''Compute irreducible factorization for modular, integer, rational number and algebriac number coefficients. ''' a = self.elem; if self.isPolynomial(): factor = Ring.getEngineFactor(self.ring); if factor == None: raise ValueError, "factors not implemented for " + self.ring.to_s; cf = self.ring.coFac; if isinstance(cf,GenPolynomialRing): e = factor.recursiveFactors( a ); else: e = factor.factors( a ); L = {}; for a in e.keySet(): i = e.get(a); L[ RingElem( a ) ] = i; return L; else: raise ValueError, "factors not implemented for " + a.to_s; def factorsAbsolute(self): '''Compute absolute irreducible factorization for (modular,) rational number coefficients. ''' a = self.elem; if self.isPolynomial(): factor = Ring.getEngineFactor(self.ring); if factor == None: raise ValueError, "factors not implemented for " + self.ring.to_s; try: L = factor.factorsAbsolute( a ); ## L = {}; ## for a in e.keySet(): ## i = e.get(a); ## L[ RingElem( a ) ] = i; return L; except Exception, e: raise ValueError, "error in factorsAbsolute " + str(e); else: raise ValueError, "factors not implemented for " + a.to_s; def realRoots(self,eps=None): '''Compute real roots of univariate polynomial. ''' a = self.elem; if isinstance(eps,RingElem): eps = eps.elem; try: if eps == None: #R = RealRootsSturm().realRoots( a ); R = RootFactory.realAlgebraicNumbers( a ); else: R = RootFactory.realAlgebraicNumbers( a, eps ); R = [ RingElem(r) for r in R ]; #R = [ RingElem(BigDecimal(r.getRational())) for r in R ]; return R; except Exception, e: print "error " + str(e) return None def complexRoots(self,eps=None): '''Compute complex roots of univariate polynomial. ''' a = self.elem; if isinstance(eps,RingElem): eps = eps.elem; cmplx = False; try: x = a.ring.coFac.getONE().getRe(); cmplx = True; except Exception, e: pass; try: if eps == None: if cmplx: R = RootFactory.complexAlgebraicNumbersComplex(a); else: R = RootFactory.complexAlgebraicNumbers(a); # R = ComplexRootsSturm(a.ring.coFac).complexRoots( a ); # R = [ r.centerApprox() for r in R ]; # R = [ r.ring.getRoot() for r in R ]; R = [ RingElem(r) for r in R ]; else: if cmplx: R = RootFactory.complexAlgebraicNumbersComplex(a,eps); else: R = RootFactory.complexAlgebraicNumbers(a,eps); R = [ RingElem(r) for r in R ]; # R = [ r.decimalMagnitude() for r in R ]; # R = ComplexRootsSturm(a.ring.coFac).complexRoots( a, eps ); # R = ComplexRootsSturm(a.ring.coFac).approximateRoots( a, eps ); return R; except Exception, e: print "error " + str(e) return None def algebraicRoots(self,eps=None): '''Compute algebraic roots, i.e. the real and complex roots of univariate polynomial. ''' a = self.elem; if isinstance(eps,RingElem): eps = eps.elem; try: if eps == None: R = RootFactory.algebraicRoots(a); else: R = RootFactory.algebraicRoots(a, eps); #R = [ RingElem(r) for r in R ]; return RingElem(R); except Exception, e: print "error " + str(e) return None def rootRefine(self,eps=None): '''Compute algebraic roots refinement. ''' a = self.elem; if isinstance(eps,RingElem): eps = eps.elem; try: RootFactory.rootRefine(a, eps); #R = [ RingElem(r) for r in R ]; return RingElem(a); except Exception, e: print "error " + str(e) return None def decimalRoots(self,eps=None): '''Compute decimal approximation of real and complex roots of univariate polynomial. ''' a = self.elem; if isinstance(eps,RingElem): eps = eps.elem; try: R = RootFactory.decimalRoots(a, eps); #R = [ RingElem(r) for r in R ]; return RingElem(R); except Exception, e: print "error " + str(e) return None def rootsOfUnity(self): '''Roots of unity of real and complex algebraic numbers. ''' a = self.elem; try: if isinstance(a,AlgebraicRootsPrimElem): R = RootFactoryApp.rootsOfUnity(a); else: R = RootFactory.rootsOfUnity(a); #R = [ RingElem(r) for r in R ]; return RingElem(R); except Exception, e: print "error " + str(e) return None def rootReduce(self, other): '''Root reduce of real and complex algebraic numbers. Compute an extension field with a primitive element. ''' a = self.elem; b = other; if isinstance(b,RingElem): b = b.elem; try: R = RootFactoryApp.rootReduce(a, b); #R = [ RingElem(r) for r in R ]; return RingElem(R); except Exception, e: print "error " + str(e) return None def contFrac(self, prec): '''Continued fraction computation of rational and real algebraic numbers. ''' a = self.elem; if isinstance(a,RealAlgebraicNumber): b = prec; if isinstance(b,RingElem): b = b.elem; if b < 1: b = 1; d = RealArithUtil.continuedFraction(a, b); return d; if isinstance(a,BigRational): d = ArithUtil.continuedFraction(a); return d; raise ValueError, "type " + str(type(a)) + " not supported"; def contFracApprox(self, lst): '''Continued fraction expansion to approximate fraction. ''' if lst == None: d = BigRational.ZERO; return RingElem( d ); nb = ArithUtil.continuedFractionApprox(lst); return RingElem( nb ); def solve(self, b): '''Solve system of linear equations. ''' if isinstance(b,RingElem): b = b.elem; x = LinAlg().solve(self.elem, b); return RingElem( x ); def decompLU(self): '''Decompose to LU matrix. this is modified. ''' p = LinAlg().decompositionLU(self.elem); uu = self.elem.getUpper(); ll = self.elem.getLower(); return [ RingElem(ll), RingElem(uu), RingElem(p) ]; def solveLU(self, p, b): '''Solve with LU matrix. ''' if isinstance(b,RingElem): b = b.elem; if isinstance(p,RingElem): p = p.elem; x = LinAlg().solveLU(self.elem, p, b); return RingElem(x); def determinant(self, p=None): '''Determinant from LU matrix. ''' a = self.elem; if p == None: p = LinAlg().decompositionLU(a); if isinstance(p,RingElem): p = p.elem; if p.isEmpty(): d = self.ring.coFac.getZERO(); d = LinAlg().determinantLU(a, p); return RingElem(d); def rowEchelon(self): '''Row echelon form matrix. ''' re = LinAlg().rowEchelonForm(self.elem); res = LinAlg().rowEchelonFormSparse(re); return RingElem(res); def rank(self): '''Rank from row echelon form matrix. ''' r = LinAlg().rankRE(self.elem); return r; def nullSpace(self): '''Null space basis. {v_i} with v_i * self = 0. ''' r = LinAlg().nullSpaceBasis(self.elem); return r; def coefficients(self): '''Get the coefficients of a polynomial. ''' a = self.elem; #L = [ c.toScriptFactory() for c in a.coefficientIterator() ]; L = [ RingElem(c) for c in a.coefficientIterator() ]; return L def cpp(self): '''(exterior) polynomial coefficient primitive part. ''' a = self.elem; r = a.coeffPrimitivePart(); p = RingElem(r); return p def interiorLeftProduct(self,other): '''Inner left product of two exterior vectors / polynomials. ''' [s,o] = coercePair(self,other); #print "self type(%s) = %s" % (s,type(s)); #print "other type(%s) = %s" % (o,type(o)); return RingElem( s.elem.interiorLeftProduct( o.elem ) ); def interiorRightProduct(self,other): '''Inner right product of two exterior vectors / polynomials. ''' [s,o] = coercePair(self,other); #print "self type(%s) = %s" % (s,type(s)); #print "other type(%s) = %s" % (o,type(o)); return RingElem( s.elem.interiorRightProduct( o.elem ) ); #---------------- # Compatibility methods for Sage/Singular: # Note: the meaning of lt and lm is swapped compared to JAS. #---------------- def parent(self): '''Parent in Sage is factory in JAS. Compatibility method for Sage/Singular. ''' return self.factory(); def __call__(self,num): '''Apply this to num. ''' if num == 0: return self.zero(); if num == 1: return self.one(); return RingElem( self.ring.fromInteger(num) ); def lm(self): '''Leading monomial of a polynomial. Compatibility method for Sage/Singular. Note: the meaning of lt and lm is swapped compared to JAS. ''' ev = self.elem.leadingExpVector(); return ev; def lc(self): '''Leading coefficient of a polynomial. Compatibility method for Sage/Singular. ''' c = self.elem.leadingBaseCoefficient(); return RingElem(c); def lt(self): '''Leading term of a polynomial. Compatibility method for Sage/Singular. Note: the meaning of lt and lm is swapped compared to JAS. ''' ev = self.elem.leadingMonomial(); return Monomial(ev); def degree(self): '''Degree of a polynomial. ''' try: ev = self.elem.degree(); #ev = self.elem.totalDegree(); except: return None; return ev; def base_ring(self): '''Coefficient ring of a polynomial. ''' try: ev = self.elem.ring.coFac; except: return None; return RingElem(ev); def is_field(self): '''Test if this RingElem is field. ''' return self.elem.isField(); def monomials(self): '''All monomials of a polynomial. Compatibility method for Sage/Singular. ''' ev = self.elem.getMap().keySet(); return ev; def divides(self,other): '''Test if self divides other. Compatibility method for Sage/Singular. ''' [s,o] = coercePair(self,other); return o.elem.remainder( s.elem ).isZERO(); def ideal(self,list): '''Create an ideal. Compatibility method for Sage/Singular. ''' r = Ring("",ring=self.ring,fast=True); return r.ideal("",list=list); def monomial_quotient(self,a,b,coeff=False): '''Quotient of ExpVectors. Compatibility method for Sage/Singular. ''' if isinstance(a,RingElem): a = a.elem; if isinstance(b,RingElem): b = b.elem; if coeff == False: if isinstance(a,GenPolynomial): return RingElem( a.divide(b) ); else: return RingElem( GenPolynomial(self.ring, a.subtract(b)) ); else: # assume JAS Monomial c = a.coefficient().divide(b.coefficient()); e = a.exponent().subtract(b.exponent()) return RingElem( GenPolynomial(self.ring, c, e) ); def monomial_divides(self,a,b): '''Test divide of ExpVectors. Compatibility method for Sage/Singular. ''' #print "JAS a = " + str(a) + ", b = " + str(b); if isinstance(a,RingElem): a = a.elem; if isinstance(a,GenPolynomial): a = a.leadingExpVector(); if not isinstance(a,ExpVector): raise ValueError, "No ExpVector a given " + str(a) + ", " + str(b) if b == None: return False; if isinstance(b,RingElem): b = b.elem; if isinstance(b,GenPolynomial): b = b.leadingExpVector(); if not isinstance(b,ExpVector): raise ValueError, "No ExpVector b given " + str(a) + ", " + str(b) return a.divides(b); def monomial_pairwise_prime(self,e,f): '''Test if ExpVectors are pairwise prime. Compatibility method for Sage/Singular. ''' if isinstance(e,RingElem): e = e.elem; if isinstance(f,RingElem): f = f.elem; # assume JAS ExpVector c = e.gcd(f); return c.isZERO(); def monomial_lcm(self,e,f): '''Lcm of ExpVectors. Compatibility method for Sage/Singular. ''' if isinstance(e,RingElem): e = e.elem; if isinstance(f,RingElem): f = f.elem; # assume JAS ExpVector c = e.lcm(f); return c; def reduce(self,F): '''Compute a normal form of self with respect to F. Compatibility method for Sage/Singular. ''' s = self.elem; Fe = [ e.elem for e in F ]; if self.ring.coFac.isField(): n = ReductionSeq().normalform(Fe,s); else: n = PseudoReductionSeq().normalform(Fe,s); return RingElem(n); #---------------- # End of compatibility methods #---------------- class Order(TermOrderByName): '''Collection of JAS and other CAS term order names. Defines names for TermOrders. See U{TermOrderByName}. ''' # empty class PolyRing(Ring): '''Represents a JAS polynomial ring: GenPolynomialRing. Provides more convenient constructor. Then returns a Ring. Example of the construction a polynomial ring over the rational numbers QQ() in the variables 'x' and 'y', together with the input of a polynomial (x+y)**3. >>> from jas import PolyRing, QQ >>> r = PolyRing(QQ(),"x,y") globally defined variables: one, x, y The example works with p = (x+y)**3, but in doctests the full notation r.x and r.y must be used for x respectively y. >>> p = (r.x+r.y)**3 >>> print p ( y**3 + 3 * x * y**2 + 3 * x**2 * y + x**3 ) ''' def __init__(self,coeff,vars,order=Order.IGRLEX): '''Ring constructor. coeff = factory for coefficients, vars = string with variable names, order = term order or weight matrix. ''' if coeff == None: raise ValueError, "No coefficient given." cf = coeff; if isinstance(coeff,RingElem): cf = coeff.elem.factory(); if isinstance(coeff,Ring): cf = coeff.ring; if vars == None: raise ValueError, "No variable names given." names = vars; if isinstance(vars,PyString): names = GenPolynomialTokenizer.variableList(vars); nv = len(names); to = Order.IGRLEX; if isinstance(order,TermOrder): to = order; if isinstance(order,PyList) or isinstance(order,PyTuple): #print "order = " + str(order); to = TermOrder.reverseWeight(order); tring = GenPolynomialRing(cf,nv,to,names); self.ring = tring; Ring.__init__(self,ring=tring) def __str__(self): '''Create a string representation. ''' return self.ring.toScript(); lex = Order.INVLEX '''Abreviation for INVLEX. ''' grad = Order.IGRLEX '''Abreviation for IGRLEX. ''' class SolvPolyRing(SolvableRing): '''Represents a JAS solvable polynomial ring: GenSolvablePolynomialRing. Provides more convenient constructor. Then returns a Ring. ''' def __init__(self,coeff,vars,order=Order.IGRLEX,rel=[]): '''Ring constructor. coeff = factory for coefficients, vars = string with variable names, order = term order, rel = triple list of relations. (e,f,p,...) with e * f = p as relation and e, f and p are commutative polynomials. ''' if coeff == None: raise ValueError, "No coefficient given." cf = coeff; if isinstance(coeff,RingElem): cf = coeff.elem.factory(); if isinstance(coeff,Ring): cf = coeff.ring; if vars == None: raise ValueError, "No variable names given." names = vars; if isinstance(vars,PyString): names = GenPolynomialTokenizer.variableList(vars); nv = len(names); #to = PolyRing.lex; to = Order.IGRLEX; if isinstance(order,TermOrder): to = order; L = []; for x in rel: if isinstance(x,RingElem): x = x.elem; L.append(x); constSolv = False; for i in range(0,len(L),3): #print "L[i+1] = " + str(L[i+1]); if L[i+1].isConstant(): constSolv = True; cfs = cf.toScript(); if cfs[0] == "0": cfs = cf.toScriptFactory(); recSolv = isinstance(cf,GenPolynomialRing); recSolvWord = isinstance(cf,GenWordPolynomialRing); resWord = isinstance(cf,WordResidueRing); quotSolv = isinstance(cf,SolvableQuotientRing); resSolv = isinstance(cf,SolvableResidueRing); locSolv = isinstance(cf,SolvableLocalRing); locresSolv = isinstance(cf,SolvableLocalResidueRing); if recSolv and not constSolv: recSolv = False; #print "cf = " + str(cf.getClass().getSimpleName()) + ", quotSolv = " + str(quotSolv) + ", recSolv = " + str(recSolv); if recSolv: ring = RecSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.coeffTable; else: if resSolv: #ring = ResidueSolvablePolynomialRing(cf,nv,to,names); ring = QLRSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; else: if recSolvWord: print "RecSolvableWordPolynomialRing: " + cfs; ring = RecSolvableWordPolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.coeffTable; else: if resWord: print "ResWordSolvablePolynomialRing: " + cfs; #ring = GenSolvablePolynomialRing(cf,nv,to,names); # ?? #ring = RecSolvableWordPolynomialRing(cf,nv,to,names); ring = ResidueSolvableWordPolynomialRing(cf,nv,to,names); #print "ring = " + str(ring.toScript()); table = ring.table; coeffTable = ring.polCoeff.coeffTable; #coeffTable = ring.coeffTable; else: if quotSolv: #ring = QuotSolvablePolynomialRing(cf,nv,to,names); ring = QLRSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; else: if locSolv: #ring = LocalSolvablePolynomialRing(cf,nv,to,names); ring = QLRSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; else: if locresSolv: #ring = LocalResidueSolvablePolynomialRing(cf,nv,to,names); ring = QLRSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; else: ring = GenSolvablePolynomialRing(cf,nv,to,names); table = ring.table; coeffTable = table; #print "rel = " + str(L); for i in range(0,len(L),3): print "adding relation: " + str(L[i]) + " * " + str(L[i+1]) + " = " + str(L[i+2]); if L[i+1].isConstant(): if recSolv or recSolvWord: coeffTable.update( L[i], L[i+1], L[i+2] ); else: if resSolv or resWord or quotSolv or locSolv or locresSolv: coeffTable.update(ring.toPolyCoefficients(L[i]), ring.toPolyCoefficients(L[i+1]), ring.toPolyCoefficients(L[i+2]) ); else: #print "L[i], L[i+1], L[i+2]: " + str(L[i]) + ", " + str(L[i+1]) + ", " + str(L[i+2]); table.update( L[i], L[i+1], L[i+2] ); if locresSolv or locSolv or quotSolv or resSolv or resWord: #print "ring.polCoeff.table " + str(ring.polCoeff.table.toScript()); ring.polCoeff.table.update( ring.toPolyCoefficients(L[i]), ring.toPolyCoefficients(L[i+1]), ring.toPolyCoefficients(L[i+2]) ); self.ring = ring; SolvableRing.__init__(self,ring=self.ring) def __str__(self): '''Create a string representation. ''' return self.ring.toScript(); class EF: '''Extension field builder. Construction of extension field towers according to the builder pattern. ''' def __init__(self,base): '''Constructor to set base field. ''' if isinstance(base,RingElem): #factory = base.elem; factory = base.ring; else: factory = base; try: factory = self.factory.factory(); except: pass print "extension field factory: " + factory.toScript(); # + " :: " + factory.toString(); #print "d type(%s) = %s" % (factory,type(factory)); if isinstance(factory,ExtensionFieldBuilder): self.builder = factory; else: self.builder = ExtensionFieldBuilder(factory); def __str__(self): '''Create a string representation. ''' return str(self.builder.toScript()); def extend(self,vars,algebraic=None): '''Create an extension field. If algebraic is given as string expression, then an algebraic extension field is constructed, else a transcendental extension field is constructed. ''' if algebraic == None: ef = self.builder.transcendentExtension(vars); else: if isinstance(algebraic,PyInteger) or isinstance(algebraic,PyLong): ef = self.builder.finiteFieldExtension(algebraic); else: ef = self.builder.algebraicExtension(vars,algebraic); return EF(ef.build()); def realExtend(self,vars,algebraic,interval): '''Create a real extension field. Construct a real algebraic extension field with an isolating interval for a real root. ''' ef = self.builder.realAlgebraicExtension(vars,algebraic,interval); return EF(ef.build()); def complexExtend(self,vars,algebraic,rectangle): '''Create a complex extension field. Construct a complex algebraic extension field with an isolating rectangle for a complex root. ''' ef = self.builder.complexAlgebraicExtension(vars,algebraic,rectangle); return EF(ef.build()); def polynomial(self,vars): '''Create a polynomial ring extension. ''' ef = self.builder.polynomialExtension(vars); return EF(ef.build()); def matrix(self,n): '''Create a matrix ring extension. ''' ef = self.builder.matrixExtension(n); return EF(ef.build()); def build(self): '''Get extension field tower. ''' rf = self.builder.build(); if isinstance(rf,GenPolynomialRing): return PolyRing(rf.coFac,rf.getVars(),rf.tord); else: return Ring("", rf); #------------------------------------ class ExtRing(Ring): '''Represents a JAS exterior form / vector / polynomial ring: GenExteriorPolynomialRing. ''' def __init__(self,ringstr="",ring=None): '''Exterior vector / polynomial ring constructor. ''' print "ExtRing: "; if ring == None: #raise ValueError, "parse of exterior polynomials not implemented" sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); wfac = GenExteriorPolynomialRing(pfac); list = tok.nextExteriorPolynomialList(wfac); self.ring = wfac; else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; Ring.__init__(self,ring=self.ring) def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); # def ideal(self,ringstr="",list=None): # '''Create a word ideal. # ''' # return ExtPolyIdeal(self,ringstr,list); def one(self): '''Get the one of the exterior vector / polynomial ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the exterior vector / polynomial ring. ''' return RingElem( self.ring.getZERO() ); def random(self,n): '''Get a random exterior vector / polynomial. ''' return RingElem( self.ring.random(n) ); def random(self,k,l,d): '''Get a random exterior vector / polynomial. ''' return RingElem( self.ring.random(k,l,d) ); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); sr = StringReader(poly); top = GenPolynomialTokenizer(sr); ep = tok.nextExteriorPolynomial(self.ring); if ep != None: return RingElem( ep ); class ExtPolyRing(ExtRing): '''Represents a JAS exterior form / vector / polynomial ring: GenExteriorPolynomialRing. Provides more convenient constructor. Then returns a Ring. ''' def __init__(self,coeff,s,var="E"): '''Ring constructor. coeff = factory for coefficients, s = size of index list, var = string with one variable name. ''' print "ExtPolyRing: "; if coeff == None: raise ValueError, "No coefficient given." cf = coeff; if isinstance(coeff,RingElem): cf = coeff.elem.factory(); if isinstance(coeff,Ring): cf = coeff.ring; if s == None: raise ValueError, "No variable size given." names = var; if not isinstance(var,PyString): names = GenPolynomialTokenizer.variableList(var); wf = IndexFactory(s, names); ring = GenExteriorPolynomialRing(cf,wf); self.ring = ring; Ring.__init__(self,ring=self.ring) def __str__(self): '''Create a string representation. ''' return self.ring.toScript(); #------------------------------------ class WordRing(Ring): '''Represents a JAS free non-commutative polynomial ring: GenWordPolynomialRing. Has a method to create word ideals. Note: watch your step: check that jython does not reorder multiplication. ''' def __init__(self,ringstr="",ring=None): '''Word polynomial ring constructor. ''' if ring == None: #raise ValueError, "parse of word polynomials not implemented" sr = StringReader( ringstr ); tok = RingFactoryTokenizer(sr); pfac = tok.nextPolynomialRing(); wfac = GenWordPolynomialRing(pfac); #list = tok.nextWordPolynomialList(wfac); self.ring = wfac; else: if isinstance(ring,Ring): self.ring = ring.ring; else: self.ring = ring; def __str__(self): '''Create a string representation. ''' return str(self.ring.toScript()); def ideal(self,ringstr="",list=None): '''Create a word ideal. ''' return WordPolyIdeal(self,ringstr,list); def one(self): '''Get the one of the word polynomial ring. ''' return RingElem( self.ring.getONE() ); def zero(self): '''Get the zero of the word polynomial ring. ''' return RingElem( self.ring.getZERO() ); def random(self,n): '''Get a random word polynomial. ''' return RingElem( self.ring.random(n) ); def random(self,k,l,d): '''Get a random word polynomial. ''' return RingElem( self.ring.random(k,l,d) ); def element(self,poly): '''Create an element from a string or object. ''' if not isinstance(poly,str): try: if self.ring == poly.ring: return RingElem(poly); except Exception, e: pass poly = str(poly); I = WordPolyIdeal(self, "( " + poly + " )"); # should work list = I.list; if len(list) > 0: return RingElem( list[0] ); class WordPolyRing(WordRing): '''Represents a JAS free non-commutative polynomial ring: GenWordPolynomialRing. Provides more convenient constructor. Then returns a Ring. Note: watch your step: check that jython does not reorder multiplication. ''' def __init__(self,coeff,vars): '''Ring constructor. coeff = factory for coefficients, vars = string with variable names. ''' if coeff == None: raise ValueError, "No coefficient given." cf = coeff; if isinstance(coeff,RingElem): cf = coeff.elem.factory(); if isinstance(coeff,Ring): cf = coeff.ring; if vars == None: raise ValueError, "No variable names given." names = vars; if isinstance(vars,PyString): names = GenPolynomialTokenizer.variableList(vars); wf = WordFactory(names); ring = GenWordPolynomialRing(cf,wf); self.ring = ring; def __str__(self): '''Create a string representation. ''' return self.ring.toScript(); class WordPolyIdeal: '''Represents a JAS word polynomial ideal. Methods for two-sided Groebner basees and others. Note: watch your step: check that jython does not reorder multiplication. ''' def __init__(self,ring,ringstr="",list=None): '''Constructor for an ideal in a word polynomial ring. ''' self.ring = ring; if list == None: #raise ValueError, "parse of word polynomials not implemented" sr = StringReader( ringstr ); tok = GenPolynomialTokenizer(sr); self.list = tok.nextWordPolynomialList(ring.ring); else: if isinstance(list,WordPolyIdeal): self.list = list.list; self.ideal = list; else: self.list = pylist2arraylist(list,rec=1); self.ideal = jas.application.WordIdeal(ring.ring, self.list); def __str__(self): '''Create a string representation. ''' #ll = [ e.toScript() for e in self.list ] #return "( " + ", ".join(ll) + " )"; return self.ideal.toScript(); def GB(self): '''Compute a two-sided Groebner base. ''' return self.twosidedGB(); def twosidedGB(self): '''Compute a two-sided Groebner base. ''' cofac = self.ring.ring.coFac; F = self.ideal.list; kind = ""; t = System.currentTimeMillis(); if cofac.isField() or not cofac.isCommutative(): G = self.ideal.GB(); kind = "field|nocom" else: if isinstance(cofac,GenPolynomialRing): # and cofac.isCommutative(): G = WordGroebnerBasePseudoRecSeq(cofac).GB(F); self.ideal = WordIdeal(self.ring.ring, G); kind = "pseudorec" else: G = WordGroebnerBasePseudoSeq(cofac).GB(F); self.ideal = WordIdeal(self.ring.ring, G); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) twosidedGB executed in %s ms" % (kind, t); return self; def isGB(self): '''Test if this is a two-sided Groebner base. ''' return self.isTwosidedGB(); def isTwosidedGB(self): '''Test if this is a two-sided Groebner base. ''' cofac = self.ring.ring.coFac; F = self.ideal.list; kind = ""; t = System.currentTimeMillis(); if cofac.isField() or not cofac.isCommutative(): b = self.ideal.isGB(); kind = "field|nocom" else: if isinstance(cofac,GenPolynomialRing): b = WordGroebnerBasePseudoRecSeq(cofac).isGB(F); kind = "pseudorec" else: b = WordGroebnerBasePseudoSeq(cofac).isGB(F); kind = "pseudo" t = System.currentTimeMillis() - t; print "sequential(%s) isTwosidedGB executed in %s ms" % (kind, t); return b; def __cmp__(self, other): '''Compare two ideals. ''' if not isinstance(other, WordPolyIdeal): return False; s = self.ideal; t = other.ideal; return s.compareTo(t); def __eq__(self,other): '''Test if two ideals are equal. ''' if not isinstance(other, WordPolyIdeal): return False; s = self.ideal; t = other.ideal; return s.equals(t) def sum(self,other): '''Compute the sum of this and the other ideal. ''' s = self.ideal; t = other.ideal; N = s.sum(t); return WordIdeal(self.ring, "", N); def WRC(ideal,r=0): '''Create JAS polynomial WordResidue as ring element. ''' #print "ideal = " + str(ideal); if ideal == None: # does not work print "ideal = " + str(ideal); if False: raise ValueError, "No ideal given." if isinstance(ideal,WordPolyIdeal): ideal = ideal.ideal #ideal.doGB(); if not isinstance(ideal,WordIdeal): raise ValueError, "No ideal given." #print "ideal.getList().get(0).ring.ideal = %s" % ideal.getList().get(0).ring.ideal; if isinstance(ideal.getList().get(0).ring,WordResidueRing): rc = WordResidueRing( ideal.getList().get(0).ring.ideal ); else: rc = WordResidueRing(ideal); if isinstance(r,RingElem): r = r.elem; if r == 0: r = WordResidue(rc); else: r = WordResidue(rc,r); return RingElem(r); # doctest: if __name__ == '__main__': import doctest, sys doctest.testmod(sys.modules[__name__]) java-algebra-system-2.7.200/examples/jas.rb000066400000000000000000005146771445075545500205020ustar00rootroot00000000000000# $Id$ =begin rdoc Enhance Ruby Integer class by rational number construction. Replace / by quo from Numeric to get Rational number. =end if 1.class == Integer #puts "1.class == Integer: redefine :/" class Integer remove_method :/ # integer division alias / quo # rational construction end else #puts "require mathn" require "mathn" end =begin rdoc jruby interface to JAS. =end module JAS module_function require "java" #require "mathn" java_import "java.lang.System" java_import "java.io.StringReader" java_import "java.util.ArrayList" java_import "java.util.Collections" #java_import "org.apache.logging.log4j.Logger"; =begin rdoc Configure the log4j system and start logging. BasicConfigurator from log4j version 1 is no more supported, please use log4j2 configuration. =end def startLog() #puts "BasicConfigurator from log4j version 1 is no more supported, please use log4j2 configuration"; end #startLog(); =begin rdoc Mimic Python str() function. =end def str(s) return s.to_s; end java_import "edu.jas.kern.ComputerThreads"; =begin rdoc Terminate the running thread pools. =end def terminate() ComputerThreads.terminate(); end puts "Java Algebra System (JAS) version 2.7" =begin rdoc Turn off automatic parallel threads usage. =end def noThreads() puts "nt = ", ComputerThreads.NO_THREADS; ComputerThreads.setNoThreads(); #NO_THREADS = #0; #1; #true; puts "\nnt = ", ComputerThreads.NO_THREADS; puts end =begin rdoc Inject variables for generators in given environment. =end def inject_gens(env) env.class.instance_eval( "attr_accessor :generators;" ) if env.generators == nil env.generators = {}; end #puts "existing generators(#{env}): " + env.generators.keys().join(", "); redef = [] for i in self.gens() begin ivs = nameFromValue(i); if ivs == nil next end; #puts "string2: #{ivs} = " + ivs.class.to_s; #puts "string3: #{ivs} = " + (env.instance_eval( "#{ivs};" )); if env.generators[ ivs ] != nil #puts "redefining global variable #{ivs}"; redef << ivs; end env.generators[ ivs ] = i; env.instance_eval( "def #{ivs}; @generators[ '#{ivs}' ]; end" ) #puts "def #{ivs}; @generators[ '#{ivs}' ]; end" #puts "@generators[ '#{ivs}' ] = #{i}" if self.class.auto_lowervar first = ivs.slice(0,1); if first.count('A-Z') > 0 first = first.downcase ivl = first + ivs.slice(1,ivs.length); puts "warning: '" + str(ivs) + "' additionaly defined as '" + str(ivl) + "' to avoid constant semantics" if env.generators[ ivl ] != nil #puts "redefining global variable #{ivl}"; redef << ivl; end env.generators[ ivl ] = i; env.instance_eval( "def #{ivl}; @generators[ '#{ivs}' ]; end" ) end end rescue => e #puts "error: #{ivs} = " + i.to_s + ", class = " + i.class.to_s; puts "error: #{ivs} = " + i.to_s + ", e = " + e.to_s; end end puts "globally(#{env}) defined variables: " + env.generators.keys().join(", "); if redef.size > 0 puts "WARN: redefined variables: " + redef.join(", "); end end =begin rdoc Get a meaningful name from a value. i ist the given value. =end def nameFromValue(i) ivs = i.to_s #puts "string1: #{ivs} = " + ivs.class.to_s; ivs = ivs.gsub(" ",""); ivs = ivs.gsub("\n",""); ivs = ivs.gsub(",",""); ivs = ivs.gsub("(",""); ivs = ivs.gsub(")",""); ivs = ivs.gsub("+",""); #ivs = ivs.gsub("*",""); ivs = ivs.gsub("/","div"); #ivs = ivs.gsub("|","div"); ivs = ivs.gsub("{",""); ivs = ivs.gsub("}",""); ivs = ivs.gsub("[",""); ivs = ivs.gsub("]",""); i = ivs.index("BigO"); if i #and i > 0 ivs = ivs[0,i]; #puts "BigO index = #{i}"; end if ivs == "1" ivs = "one" end if ivs[0] == "1"[0] and not ivs.match(/\A[0-9].*/) r = ivs[1,ivs.size-1].to_s; ivs = "one" if r != nil ivs = ivs + r end end #if ivs[0,2] == "0i1"[0,2] or ivs[0,2] == "0I1"[0,2] if ivs == "0i1" or ivs == "0I1" ivs = "i" end #puts "string: #{ivs} of " + i.to_s; if ivs.include?("|") or ivs.match(/\A[0-9].*/) #puts "string2: #{ivs} = " + ivs.class.to_s; ivs = nil end return ivs end # set output to Ruby scripting java_import "edu.jas.kern.Scripting"; Scripting.setLang(Scripting::Lang::Ruby); java_import "edu.jas.util.ExecutableServer"; java_import "edu.jas.structure.Power"; java_import "edu.jas.arith.ArithUtil"; java_import "edu.jas.arith.BigInteger"; java_import "edu.jas.arith.BigRational"; java_import "edu.jas.arith.ModInteger"; java_import "edu.jas.arith.ModIntegerRing"; java_import "edu.jas.arith.ModLong"; java_import "edu.jas.arith.ModLongRing"; java_import "edu.jas.arith.ModInt"; java_import "edu.jas.arith.ModIntRing"; java_import "edu.jas.arith.BigDecimal"; java_import "edu.jas.arith.BigComplex"; java_import "edu.jas.arith.BigQuaternion"; java_import "edu.jas.arith.BigQuaternionRing"; java_import "edu.jas.arith.BigQuaternionInteger"; java_import "edu.jas.arith.BigOctonion"; java_import "edu.jas.arith.Product"; java_import "edu.jas.arith.ProductRing"; java_import "edu.jas.arith.PrimeList"; =begin rdoc Create JAS BigInteger as ring element. =end def ZZ(z=0) if z.is_a? RingElem z = z.elem; end if z == 0 r = Java::EduJasArith::BigInteger.new(); else #puts "z = #{z} : #{z.class} " r = Java::EduJasArith::BigInteger.new(z); end return RingElem.new(r); end =begin rdoc Create JAS ModInteger as ring element. =end def ZM(m,z=0,field=false) if m.is_a? RingElem m = m.elem; end if z.is_a? RingElem z = z.elem; end if z != 0 and ( z == true or z == false ) field = z; z = 0; end if m < ModLongRing::MAX_LONG if m < ModIntRing::MAX_INT if field mf = ModIntRing.new(m,field); else mf = ModIntRing.new(m); end r = ModInt.new(mf,z); else if field mf = ModLongRing.new(m,field); else mf = ModLongRing.new(m); end r = ModLong.new(mf,z); end else if field mf = ModIntegerRing.new(m,field); else mf = ModIntegerRing.new(m); end r = ModInteger.new(mf,z); end return RingElem.new(r); end =begin rdoc Create JAS ModLong as ring element. =end def ZML(m,z=0,field=false) return ZM(m,z,field); end =begin rdoc Create JAS ModInt as ring element. =end def ZMI(m,z=0,field=false) return ZM(m,z,field); end =begin rdoc Create JAS ModInteger as field element. =end def GF(m,z=0) return ZM(m,z,true); end =begin rdoc Create JAS ModLong as field element. =end def GFL(m,z=0) return ZM(m,z,true); end =begin rdoc Create JAS ModInt as field element. =end def GFI(m,z=0) return ZM(m,z,true); end =begin rdoc Create JAS BigRational as ring element. =end def QQ(d=0,n=1) if d.is_a? Rational if n != 1 puts "#{n} ignored\n"; end if d.denominator != 1 n = d.denominator; end d = d.numerator; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if n == 1 if d == 0 r = BigRational.new(); else r = BigRational.new(d); end else d = BigRational.new(d); n = BigRational.new(n); r = d.divide(n); # BigRational.new(d,n); only for short integers end return RingElem.new(r); end =begin rdoc Create JAS BigComplex as ring element. =end def CC(re=BigRational.new(),im=BigRational.new()) if re == 0 re = BigRational.new(); end if im == 0 im = BigRational.new(); end if re.is_a? Array if re[0].is_a? Array if re.size > 1 im = QQ( re[1] ); end re = QQ( re[0] ); else re = QQ(re); # re = makeJasArith( re ); end end if im.is_a? Array im = QQ( im ); # im = makeJasArith( im ); end if re.is_a? Numeric re = QQ(re); end if im.is_a? Numeric im = QQ(im); end if re.is_a? RingElem re = re.elem; end if im.is_a? RingElem im = im.elem; end if im.isZERO() if re.isZERO() c = BigComplex.new(); else c = BigComplex.new(re); end else c = BigComplex.new(re,im); end return RingElem.new(c); end =begin rdoc Create JAS generic Complex as ring element. =end def CR(re=BigRational.new(),im=BigRational.new(),ring=nil) if re == 0 re = BigRational.new(); end if im == 0 im = BigRational.new(); end if re.is_a? Array if re[0].is_a? Array if re.size > 1 im = QQ( re[1] ); end re = QQ( re[0] ); else re = QQ(re); # re = makeJasArith( re ); end end if im.is_a? Array im = QQ( im ); # im = makeJasArith( im ); end if re.is_a? RingElem re = re.elem; end if im.is_a? RingElem im = im.elem; end if ring == nil ring = re.factory(); end r = ComplexRing.new(ring); if im.isZERO() if re.isZERO() c = Complex.new(r); else c = Complex.new(r,re); end else c = Complex.new(r,re,im); end return RingElem.new(c); end =begin rdoc Create JAS BigDecimal as ring element. =end def DD(d=0) if d.is_a? RingElem d = d.elem; end if d.is_a? Float d = d.to_s; end #puts "d type(#{d}) = #{d.class}"; if d == 0 r = BigDecimal.new(); else r = BigDecimal.new(d); end return RingElem.new(r); end =begin rdoc Create JAS BigQuaternion as ring element. =end def Quat(re=BigRational.new(),im=BigRational.new(),jm=BigRational.new(),km=BigRational.new()) if re == 0 re = BigRational.new(); end if im == 0 im = BigRational.new(); end if jm == 0 jm = BigRational.new(); end if km == 0 km = BigRational.new(); end if re.is_a? Numeric re = QQ(re); # re = makeJasArith( re ); end if im.is_a? Numeric im = QQ( im ); end if jm.is_a? Numeric jm = QQ( jm ); end if km.is_a? Numeric kim = QQ( km ); # im = makeJasArith( im ); end if re.is_a? RingElem re = re.elem; end if im.is_a? RingElem im = im.elem; end if jm.is_a? RingElem jm = jm.elem; end if km.is_a? RingElem km = km.elem; end cf = BigQuaternionRing.new(); c = BigQuaternion.new(cf, re,im,jm,km); return RingElem.new(c); end =begin rdoc Create JAS BigOctonion as ring element. =end def Oct(ro=0,io=0) cf = BigQuaternionRing.new(); if ro == 0 ro = BigQuaternion.new(cf); end if io == 0 io = BigQuaternion.new(cf); end if ro.is_a? Array if ro[0].is_a? Array if ro.size > 1 io = QQ( ro[1] ); end ro = QQ( ro[0] ); else ro = QQ(ro); # re = makeJasArith( re ); end end if io.is_a? Array io = QQ( io ); # im = makeJasArith( im ); end if ro.is_a? RingElem ro = ro.elem; end if io.is_a? RingElem io = io.elem; end c = BigOctonion.new(ro,io); return RingElem.new(c); end =begin rdoc Proxy for JAS ring elements. Methods to be used as + - * ** / %. =end class RingElem include Comparable # the Java element object attr_reader :elem # the Java factory object attr_reader :ring =begin rdoc Constructor for ring element. =end def initialize(elem) if elem.is_a? RingElem @elem = elem.elem; else @elem = elem; end begin @ring = @elem.factory(); rescue @ring = @elem; end @elem.freeze @ring.freeze self.freeze end =begin rdoc Create a string representation. =end def to_s() begin return @elem.toScript(); rescue return @elem.to_s(); end end =begin rdoc Convert to float. =end def to_f() e = @elem; if e.is_a? BigInteger e = BigRational(e); end if e.is_a? BigRational e = BigDecimal(e); end if e.is_a? BigDecimal e = e.toString(); end e = e.to_f(); return e; end =begin rdoc Zero element of this ring. =end def zero() return RingElem.new( @elem.factory().getZERO() ); end =begin rdoc Test if this is the zero element of the ring. =end def isZERO() return @elem.isZERO(); end =begin rdoc Test if this is the zero element of the ring. =end def zero?() return @elem.isZERO(); end =begin rdoc One element of this ring. =end def one() return RingElem.new( @elem.factory().getONE() ); end =begin rdoc Test if this is the one element of the ring. =end def isONE() return @elem.isONE(); end =begin rdoc Test if this is the one element of the ring. =end def one?() return @elem.isONE(); end =begin rdoc Get the sign of this element. =end def signum() return @elem.signum(); end =begin rdoc Absolute value. =end def abs() return RingElem.new( @elem.abs() ); end =begin rdoc Negative value. =end def -@() return RingElem.new( @elem.negate() ); end =begin rdoc Positive value. =end def +@() return self; end =begin rdoc Coerce other to self =end def coerce(other) s,o = coercePair(self,other); return [o,s]; # keep order for non-commutative end =begin rdoc Coerce type a to type b or type b to type a. =end def coercePair(a,b) #puts "a type(#{a}) = #{a.class}\n"; #puts "b type(#{b}) = #{b.class}\n"; begin if not a.isPolynomial() and b.isPolynomial() #puts "b = " + str(b.isPolynomial()); s = b.coerceElem(a); o = b; else if not a.isAlgNum() and b.isAlgNum() #puts "b = " + str(b.isAlgNum()); s = b.coerceElem(a); o = b; else s = a; o = a.coerceElem(b); end end rescue => e #puts "e #{e.message}, a = #{a}"; s = a; o = a.coerceElem(b); end #puts "s type(#{s}) = #{s.class}\n"; #puts "o type(#{o}) = #{o.class}\n"; return [s,o]; end =begin rdoc Coerce other to self =end def coerceElem(other) #puts "self type(#{self}) = #{self.class}\n"; #puts "other type(#{other}) = #{other.class}\n"; #not ok: if other.is_a? RingElem other = other.elem; end if @elem.is_a? GenVector if other.is_a? Array o = rbarray2arraylist(other,@elem.factory().coFac,rec=1); o = GenVector.new(@elem.factory(),o); return RingElem.new( o ); end end if @elem.is_a? GenMatrix #puts "other #{@ring} #{other.factory()}\n"; if other.is_a? Array o = rbarray2arraylist(other,@elem.factory().coFac,rec=2); o = GenMatrix.new(@elem.factory(),o); return RingElem.new( o ); end if other.is_a? RingElem and other.elem.is_a? GenVector #puts "other vec #{other.factory()} #{other}\n"; #o = rbarray2arraylist(other,other.factory().coFac,rec=1); #o = GenVector.new(other.factory().coFac, o); o = other; return o; #RingElem.new( o ); end end if other.is_a? RingElem if (isPolynomial() and not other.isPolynomial()) or (isAlgNum() and not other.isAlgNum()) #puts "other pol.parse(#{@ring})\n"; o = @ring.parse( other.elem.toString() ); # not toScript() return RingElem.new( o ); end #puts "other type(#{other}) = #{other.class}\n"; return other; end #puts "--1"; if other.is_a? Array # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this puts "other type(#{other})_3 = #{other.class}\n"; o = makeJasArith(other); puts "other type(#{o})_4 = #{o.class}\n"; ##o = BigRational.new(other[0],other[1]); if isPolynomial() o = @ring.parse( o.toString() ); # not toScript(); #o = o.elem; elsif @elem.is_a? BigComplex o = CC( o ); o = o.elem; elsif @elem.is_a? BigQuaternion o = Quat( o ); o = o.elem; elsif @elem.is_a? BigOctonion o = Oct( Quat(o) ); o = o.elem; elsif @elem.is_a? Product o = RR(@ring, @elem.multiply(o) ); # valueOf #puts "o = #{o}"; o = o.elem; end puts "other type(#{o})_5 = #{o.class}\n"; return RingElem.new(o); end # test if @elem is a factory itself if isFactory() if other.is_a? Integer o = @elem.fromInteger(other); elsif other.is_a? Rational o = @elem.fromInteger( other.numerator ); o = o.divide( @elem.fromInteger( other.denominator ) ); elsif other.is_a? Float # ?? what to do ?? o = @elem.parse( other.to_s ); ##o = @elem.fromInteger( other.to_i ); else puts "unknown other type(#{other})_1 = #{other.class}\n"; o = @elem.parse( other.to_s ); end return RingElem.new(o); end # @elem has a ring factory if other.is_a? Integer o = @elem.factory().fromInteger(other); elsif other.is_a? Rational o = @elem.factory().fromInteger( other.numerator ); o = o.divide( @elem.factory().fromInteger( other.denominator ) ); elsif other.is_a? Float # ?? what to do ?? o = @elem.factory().parse( other.to_s ); if @elem.is_a? Product o = RR(@ring, @elem.idempotent().multiply(o) ); # valueOf o = o.elem; end else puts "unknown other type(#{other})_2 = #{other.class}\n"; o = @elem.factory().parse( other.to_s ); end return RingElem.new(o); end =begin rdoc Test if this is itself a ring factory. =end def isFactory() f = @elem.factory(); if @elem == f return true; else return false; end end =begin rdoc Test if this is a polynomial. =end def isPolynomial() begin nv = @elem.ring.coFac; #nvar; rescue return false; end return true; end =begin rdoc Test if this is an algebraic number. =end def isAlgNum() begin nv = @elem.ring.ring.nvar; #coFac rescue return false; end return true; end =begin rdoc Compare two ring elements. =end def <=>(other) #s,o = coercePair(other); s,o = self, other return s.elem.compareTo( o.elem ); end =begin rdoc Test if two ring elements are equal. =end def ==(other) if not other.is_a? RingElem return false; end return (self <=> other) == 0; end =begin rdoc Length of an element. =end def len() return self.elem.length(); end =begin rdoc Hash value. =end def object_id() return @elem.hashCode(); end =begin rdoc Multiply two ring elements. =end def *(other) #puts "* self type(#{self.elem}) = #{self.elem.class}\n"; #puts "* other type(#{other.elem}) = #{other.elem.class}\n"; s,o = coercePair(self,other); #puts "* s = #{s}, o = #{o}, s*o = #{s.elem.multiply(o.elem)}\n"; if s.elem.is_a? GenMatrix and o.elem.is_a? GenVector return RingElem.new( BasicLinAlg.new().rightProduct(o.elem, s.elem) ); end; if s.elem.is_a? GenVector and o.elem.is_a? GenMatrix return RingElem.new( BasicLinAlg.new().leftProduct(s.elem, o.elem) ); end; return RingElem.new( s.elem.multiply( o.elem ) ); end =begin rdoc Add two ring elements. =end def +(other) #puts "+ self type(#{self}) = #{self.elem.class}\n"; #puts "+ other type(#{other}) = #{other.elem.class}\n"; s,o = coercePair(self,other); return RingElem.new( s.elem.sum( o.elem ) ); end =begin rdoc Subtract two ring elements. =end def -(other) #puts "+ self type(#{self}) = #{self.elem.class}\n"; #puts "+ other type(#{other}) = #{other.elem.class}\n"; s,o = coercePair(self,other); return RingElem.new( s.elem.subtract( o.elem ) ); end =begin rdoc Divide two ring elements. =end def /(other) s,o = coercePair(self,other); return RingElem.new( s.elem.divide( o.elem ) ); end =begin rdoc Modular remainder of two ring elements. =end def %(other) s,o = coercePair(self,other); return RingElem.new( s.elem.remainder( o.elem ) ); end =begin rdoc Matrix entry. =end def [](i,j) return get(i,j); end =begin rdoc Matrix entry. =end def get(i,j) if not elem.is_a? GenMatrix raise "no matrix " + ring.to_s end if i.is_a? RingElem i = i.elem; end if j.is_a? RingElem j = j.elem; end e = elem.get(i,j); return RingElem.new( e ); end =begin rdoc Can not be used as power. =end def ^(other) return nil; end =begin rdoc Power of this to other. =end def **(other) #puts "pow other type(#{other}) = #{other.class}"; if other.is_a? Integer n = other; else if other.is_a? RingElem n = other.elem; if n.is_a? BigRational #puts "#{n.numerator()} / #{n.denominator()}, other.elem = #{n}" #todo (x**n.n)/(x**(-n.d)) if n.numerator().is_a? BigInteger n = n.numerator().intValue() / n.denominator().intValue(); else n = n.numerator() / n.denominator(); end end if n.is_a? BigInteger n = n.intValue(); end end end if isFactory() p = Power.new(@elem).power( @elem, n ); else p = Power.new(@elem.factory()).power( @elem, n ); #puts "@elem**#{n} = #{p}, @elem = #{@elem}" #puts "@elem.ring = #{@elem.ring.toScript()}"; end return RingElem.new( p ); end =begin rdoc Test if two ring elements are equal. =end def equal?(other) o = other; if other.is_a? RingElem o = other.elem; end return @elem.equals(o) end =begin rdoc Get the factory of this element. =end def factory() fac = @elem.factory(); begin nv = fac.nvar; rescue return RingElem.new(fac); end #return PolyRing(fac.coFac,fac.getVars(),fac.tord); return RingElem.new(fac); end =begin rdoc Get the generators for the factory of this element. =end def gens() ll = @elem.factory().generators(); #puts "L = #{ll}"; nn = ll.map {|e| RingElem.new(e) }; return nn; end =begin rdoc Monic polynomial. =end def monic() return RingElem.new( @elem.monic() ); end =begin rdoc Evaluate at a for power series or polynomial. =end def evaluate(a) #puts "self type(#{@elem}) = #{@elen.class}"; #puts "a type(#{a}) = #{a.class}"; x = nil; if a.is_a? RingElem x = a.elem; end if a.is_a? Array # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this #x = makeJasArith(a); x = rbarray2arraylist(a); else x = rbarray2arraylist([a]); end begin if @elem.is_a? UnivPowerSeries e = @elem.evaluate(x[0]); else if @elem.is_a? MultiVarPowerSeries e = @elem.evaluate(x); else #puts "x = " + x[0].getClass().getSimpleName().to_s; x = x.map{ |p| p.leadingBaseCoefficient() }; e = PolyUtil.evaluateAll(@ring.coFac, @elem, x); end end rescue => e raise RuntimeError, e.to_s; e = 0; end return RingElem.new( e ); end =begin rdoc Integrate a power series or rational function with constant a. a is the integration constant, r is for partial integration in variable r. =end def integrate(a=0,r=nil) #puts "self type(#{@elem}) = #{@elem.class}"; #puts "a type(#{a}) = #{a.class}"; x = nil; if a.is_a? RingElem x = a.elem; end if a.is_a? Array # assume BigRational or BigComplex # assume self will be compatible with them. todo: check this x = makeJasArith(a); end # power series begin if r != nil e = @elem.integrate(x,r); else e = @elem.integrate(x); end return RingElem.new( e ); rescue #pass; end cf = @elem.ring; begin cf = cf.ring; rescue #pass; end # rational function integrator = ElementaryIntegration.new(cf.coFac); ei = integrator.integrate(@elem); return ei; end =begin rdoc Differentiate a power series. r is for partial differentiation in variable r. =end def differentiate(r=nil) begin if r != nil e = @elem.differentiate(r); else e = @elem.differentiate(); end rescue e = @elem.factory().getZERO(); end return RingElem.new( e ); end =begin rdoc Random element. n size for random element will be less than 2**n. =end def random(n=3) if n.is_a? RingElem n = n.elem end return RingElem.new( @elem.factory().random(n) ); end =begin rdoc Compute the greatest common divisor of this/self and b. =end def gcd(b) a = @elem; if b.is_a? RingElem b = b.elem; else b = element( b ); b = b.elem; end if isPolynomial() engine = Ring.getEngineGcd(@ring); return RingElem.new( engine.gcd(a,b) ); else return RingElem.new( a.gcd(b) ); end end =begin rdoc Compute squarefree factors of polynomial. =end def squarefreeFactors() a = @elem; if isPolynomial() sqf = Ring.getEngineSqf(@ring); if sqf == nil raise NotImplementedError, "squarefreeFactors not implemented for " + @ring.to_s; end cf = @ring.coFac; if cf.is_a? GenPolynomialRing e = sqf.recursiveSquarefreeFactors( a ); else e = sqf.squarefreeFactors( a ); end ll = {}; for k in e.keySet() i = e.get(k); ll[ RingElem.new( k ) ] = i; end return ll; else raise NotImplementedError, "squarefreeFactors not implemented for " + a.to_s; end end =begin rdoc Compute irreducible factorization for modular, integer, rational number and algebriac number coefficients. =end def factors() a = @elem; if isPolynomial() factor = Ring.getEngineFactor(@ring); if factor == nil raise NotImplementedError, "factors not implemented for " + @ring.to_s; end cf = @ring.coFac; if cf.is_a? GenPolynomialRing e = factor.recursiveFactors( a ); else e = factor.factors( a ); end ll = {}; for k in e.keySet() i = e.get(k); ll[ RingElem.new( k ) ] = i; end return ll; else raise NotImplementedError, "factors not implemented for " + a.to_s; end end =begin rdoc Compute absolute irreducible factorization for (modular,) rational number coefficients. =end def factorsAbsolute() a = @elem; if isPolynomial() factor = Ring.getEngineFactor(@ring); if factor == nil raise NotImplementedError, "factors not implemented for " + @ring.to_s; end begin ll = factor.factorsAbsolute( a ); ## ll = {}; ## for a in e.keySet() ## i = e.get(a); ## ll[ RingElem.new( a ) ] = i; return ll; rescue => e raise RuntimeError, "error factorsAbsolute " + @ring.to_s; end else raise NotImplementedError, "factors not implemented for " + a.to_s; end end =begin rdoc Compute real roots of univariate polynomial. =end def realRoots(eps=nil) a = @elem; if eps.is_a? RingElem eps = eps.elem; end begin if eps == nil #rr = RealRootsSturm.new().realRoots( a ); rr = RootFactory.realAlgebraicNumbers( a ) else rr = RootFactory.realAlgebraicNumbers( a, eps ); ## rr = RealRootsSturm.new().realRoots( a, eps ); ## rr = [ r.toDecimal() for r in rr ]; #rr = RealRootsSturm.new().approximateRoots(a,eps); end rr = rr.map{ |e| RingElem.new(e) }; return rr; rescue => e puts "error " + str(e) return nil end end =begin rdoc Compute complex roots of univariate polynomial. =end def complexRoots(eps=nil) a = @elem; if eps.is_a? RingElem eps = eps.elem; end cmplx = false; begin x = a.ring.coFac.getONE().getRe(); cmplx = true; rescue => e #pass; end begin if eps == nil #rr = ComplexRootsSturm.new(a.ring.coFac).complexRoots( a ); if cmplx rr = RootFactory.complexAlgebraicNumbersComplex( a ); else rr = RootFactory.complexAlgebraicNumbers( a ); end #R = [ r.centerApprox() for r in R ]; else ## rr = ComplexRootsSturm.new(a.ring.coFac).complexRoots( a, eps ); ## rr = [ r.centerApprox() for r in rr ]; ##rr = ComplexRootsSturm.new(a.ring.coFac).approximateRoots( a, eps ); if cmplx rr = RootFactory.complexAlgebraicNumbersComplex( a, eps ); else rr = RootFactory.complexAlgebraicNumbers( a, eps ); end end rr = rr.map{ |y| RingElem.new(y) }; return rr; rescue => e puts "error " + str(e) return nil end end =begin rdoc Compute algebraic roots, i.e. real and complex algebraic roots of univariate polynomial. =end def algebraicRoots(eps=nil) a = @elem; if eps.is_a? RingElem eps = eps.elem; end begin if eps == nil ar = RootFactory.algebraicRoots( a ); else ar = RootFactory.algebraicRoots( a, eps ); end #no: ar = ar.map{ |y| RingElem.new(y) }; return RingElem.new(ar); #?? rescue => e puts "error " + str(e) return nil end end =begin rdoc Compute algebraic roots refinement. =end def rootRefine(eps=nil) r = @elem; if eps.is_a? RingElem eps = eps.elem; end begin RootFactory.rootRefine( r, eps ); #no: ar = ar.map{ |y| RingElem.new(y) }; return RingElem.new(r); # ?? rescue => e puts "error " + str(e) return nil end end =begin rdoc Compute decimal approximation of real and complex roots of univariate polynomial. =end def decimalRoots(eps=nil) a = @elem; if eps.is_a? RingElem eps = eps.elem; end if a.is_a? Java::EduJasRoot::AlgebraicRoots a = a.p; end begin d = RootFactory.decimalRoots( a, eps ); return RingElem.new(d); # ?? rescue => e puts "error " + str(e) return nil end end =begin rdoc Roots of unity of real and complex algebraic numbers. =end def rootsOfUnity() a = @elem; begin #Java::EduJasApplication:: if a.is_a? AlgebraicRootsPrimElem d = RootFactoryApp.rootsOfUnity( a ); else d = RootFactory.rootsOfUnity( a ); end return RingElem.new(d); # ?? rescue => e puts "error " + str(e) return nil end end =begin rdoc Root reduce of real and complex algebraic numbers. Compute an extension field with a primitive element. =end def rootReduce(other) a = @elem; b = other; if b.is_a? RingElem b = b.elem; end begin #Java::EduJasApplication:: d = RootFactoryApp.rootReduce( a, b ); return RingElem.new(d); # ?? rescue => e puts "error " + str(e) return nil end end =begin rdoc Continued fraction computation of rational and real algebraic numbers. =end def contFrac(prec) a = @elem; if a.is_a? RealAlgebraicNumber b = prec; if b.is_a? RingElem b = b.elem; end if b < 1 b = 1; end d = RealArithUtil.continuedFraction(a, b); return d; end if a.is_a? BigRational d = ArithUtil.continuedFraction(a); return d; end raise ArgumentError, "type " + str(a.class) + " not supported" end =begin rdoc Continued fraction expansion to approximate fraction. =end def contFracApprox(lst) if lst == nil d = BigRational::ZERO; return RingElem.new( d ); end nb = ArithUtil.continuedFractionApprox(lst); return RingElem.new( nb ); end =begin rdoc Solve system of linear equations. =end def solve(b) a = @elem; if b.is_a? RingElem b = b.elem; end x = LinAlg.new().solve(a,b); return RingElem.new(x); end =begin rdoc Decompose to LU matrix. this is modified. =end def decompLU() a = @elem; p = LinAlg.new().decompositionLU(a); uu = a.getUpper(); ll = a.getLower(); return [ RingElem.new(ll), RingElem.new(uu), RingElem.new(p) ]; end =begin rdoc Solve with LU matrix. =end def solveLU(p, b) a = @elem; if b.is_a? RingElem b = b.elem; end if p.is_a? RingElem p = p.elem; end x = LinAlg.new().solveLU(a,p,b); return RingElem.new(x); end =begin rdoc Determinant from LU matrix. =end def determinant(p=nil) a = @elem; la = LinAlg.new(); if p == nil p = la.decompositionLU(a); end; if p.is_a? RingElem p = p.elem; end if p.isEmpty() d = @ring.coFac.getZERO(); else d = la.determinantLU(a,p); end; return RingElem.new(d); end =begin rdoc Row echelon form matrix. =end def rowEchelon() a = @elem; la = LinAlg.new(); re = la.rowEchelonForm(a); res = la.rowEchelonFormSparse(re); return RingElem.new(res); end =begin rdoc rank from row echelon form matrix. =end def rank() a = @elem; r = LinAlg.new().rankRE(a); return r; end =begin rdoc Null space basis. {v_i} with v_i * self = 0. =end def nullSpace() a = @elem; r = LinAlg.new().nullSpaceBasis(a); return r; end =begin rdoc Get the coefficients of a polynomial. =end def coefficients() a = @elem; ll = a.coefficientIterator().map { |c| RingElem.new(c) }; return ll end =begin rdoc (exterior) polynomial coefficient primitive part. =end def cpp() a = @elem; r = a.coeffPrimitivePart(); return RingElem.new(r); end =begin rdoc Inner left product of two exterior vectors / polynomials. =end def interiorLeftProduct(other) #puts "* self type(#{self.elem}) = #{self.elem.class}\n"; #puts "* other type(#{other.elem}) = #{other.elem.class}\n"; s,o = coercePair(self,other); #puts "* s = #{s}, o = #{o}, s*o = #{s.elem.multiply(o.elem)}\n"; return RingElem.new( s.elem.interiorLeftProduct( o.elem ) ); end =begin rdoc Inner right product of two exterior vectors / polynomials. =end def interiorRightProduct(other) #puts "* self type(#{self.elem}) = #{self.elem.class}\n"; #puts "* other type(#{other.elem}) = #{other.elem.class}\n"; s,o = coercePair(self,other); #puts "* s = #{s}, o = #{o}, s*o = #{s.elem.multiply(o.elem)}\n"; return RingElem.new( s.elem.interiorRightProduct( o.elem ) ); end #---------------- # Compatibility methods for Sage/Singular: # Note: the meaning of lt and lm is swapped compared to JAS. #---------------- =begin rdoc Parent in Sage is factory in JAS. Compatibility method for Sage/Singular. =end def parent() return factory(); end =begin rdoc Apply this to num. Call syntax is ringElem.(num). Only for interger num. =end def call(num) if num == 0 return zero(); end if num == 1 return one(); end return RingElem.new( @ring.fromInteger(num) ); end =begin rdoc Leading monomial of a polynomial. Compatibility method for Sage/Singular. Note: the meaning of lt and lm is swapped compared to JAS. =end def lm() ev = @elem.leadingExpVector(); return ev; end =begin rdoc Leading coefficient of a polynomial. Compatibility method for Sage/Singular. =end def lc() c = @elem.leadingBaseCoefficient(); return RingElem.new(c); end =begin rdoc Leading term of a polynomial. Compatibility method for Sage/Singular. Note: the meaning of lt and lm is swapped compared to JAS. =end def lt() ev = @elem.leadingMonomial(); return Monomial.new(ev); end =begin rdoc Degree of a polynomial. =end def degree() begin ev = @elem.degree(); rescue return nil; end return ev; end =begin rdoc Coefficient ring of a polynomial. =end def base_ring() begin ev = @elem.ring.coFac; rescue return nil; end return RingElem.new(ev); end =begin rdoc Test if this RingElem is field. =end def is_field() return @ring.isField(); end =begin rdoc All monomials of a polynomial. Compatibility method for Sage/Singular. =end def monomials() ev = @elem.getMap().keySet(); return ev; end =begin rdoc Test if self divides other. Compatibility method for Sage/Singular. =end def divides(other) s,o = coercePair(self,other); return o.elem.remainder( s.elem ).isZERO(); end =begin rdoc Create an ideal. Compatibility method for Sage/Singular. =end def ideal(list) r = Ring.new("",ring=self.ring); #,fast=true return r.ideal("",list=list); end =begin rdoc Quotient of ExpVectors. Compatibility method for Sage/Singular. =end def monomial_quotient(a,b,coeff=false) if a.is_a? RingElem a = a.elem; end if b.is_a? RingElem b = b.elem; end if coeff == false if a.is_a? GenPolynomial return RingElem.new( a.divide(b) ); else return RingElem.new( GenPolynomial.new(@ring, a.subtract(b)) ); end else # assume JAS Monomial c = a.coefficient().divide(b.coefficient()); e = a.exponent().subtract(b.exponent()) return RingElem.new( GenPolynomial.new(@ring, c, e) ); end end =begin rdoc Test divide of ExpVectors. Compatibility method for Sage/Singular. =end def monomial_divides(a,b) #print "JAS a = " + str(a) + ", b = " + str(b); if a.is_a? RingElem a = a.elem; end if a.is_a? GenPolynomial a = a.leadingExpVector(); end if not a.is_a? ExpVector raise ArgumentError, "No ExpVector given " + str(a) + ", " + str(b) end if b == nil return False; end if b.is_a? RingElem b = b.elem; end if b.is_a? GenPolynomial b = b.leadingExpVector(); end if not b.is_a? ExpVector raise ArgumentError, "No ExpVector given " + str(a) + ", " + str(b) end return a.divides(b); end =begin rdoc Test if ExpVectors are pairwise prime. Compatibility method for Sage/Singular. =end def monomial_pairwise_prime(e,f) if e.is_a? RingElem e = e.elem; end if f.is_a? RingElem f = f.elem; end # assume JAS ExpVector c = e.gcd(f); return c.isZERO(); end =begin rdoc Lcm of ExpVectors. Compatibility method for Sage/Singular. =end def monomial_lcm(e,f) if e.is_a? RingElem e = e.elem; end if f.is_a? RingElem f = f.elem; end # assume JAS ExpVector c = e.lcm(f); return c; end =begin rdoc Compute a normal form of self with respect to ff. Compatibility method for Sage/Singular. =end def reduce(ff) s = @elem; fe = ff.map {|e| e.elem }; n = ReductionSeq.new().normalform(fe,s); return RingElem.new(n); end #---------------- # End of compatibility methods #---------------- end java_import "edu.jas.poly.GenPolynomial"; java_import "edu.jas.poly.GenPolynomialRing"; java_import "edu.jas.poly.IndexFactory"; java_import "edu.jas.poly.GenWordPolynomialRing"; java_import "edu.jas.poly.GenExteriorPolynomialRing"; java_import "edu.jas.poly.GenSolvablePolynomial"; java_import "edu.jas.poly.GenSolvablePolynomialRing"; java_import "edu.jas.poly.RecSolvablePolynomial"; java_import "edu.jas.poly.RecSolvablePolynomialRing"; java_import "edu.jas.poly.GenWordPolynomial"; java_import "edu.jas.poly.GenWordPolynomialRing"; java_import "edu.jas.poly.RecSolvableWordPolynomial"; java_import "edu.jas.poly.RecSolvableWordPolynomialRing"; java_import "edu.jas.poly.QLRSolvablePolynomial"; java_import "edu.jas.poly.QLRSolvablePolynomialRing"; java_import "edu.jas.poly.GenPolynomialTokenizer"; java_import "edu.jas.poly.TermOrder"; java_import "edu.jas.poly.TermOrderByName"; java_import "edu.jas.poly.OrderedPolynomialList"; java_import "edu.jas.poly.PolyUtil"; java_import "edu.jas.poly.TermOrderOptimization"; java_import "edu.jas.poly.PolynomialList"; java_import "edu.jas.poly.WordFactory"; java_import "edu.jas.poly.AlgebraicNumber"; java_import "edu.jas.poly.AlgebraicNumberRing"; java_import "edu.jas.poly.OrderedModuleList"; java_import "edu.jas.poly.ModuleList"; java_import "edu.jas.poly.Complex"; java_import "edu.jas.poly.ComplexRing"; java_import "edu.jas.application.RingFactoryTokenizer"; java_import "edu.jas.ufd.GreatestCommonDivisor"; java_import "edu.jas.ufd.GCDFactory"; java_import "edu.jas.application.FactorFactory"; java_import "edu.jas.ufd.SquarefreeFactory"; java_import "edu.jas.integrate.ElementaryIntegration"; java_import "edu.jas.gbufd.PolyGBUtil"; =begin rdoc Represents a JAS polynomial ring: GenPolynomialRing. Methods to create ideals and ideals with parametric coefficients. =end class Ring # the Java factoy object, gcd engine, sqf engine, factorization engine attr_reader :ring, :engine, :sqf, :factor #:pset, @auto_inject = true @auto_lowervar = false class << self # means add to class # inject variables into environment attr_accessor :auto_inject # avoid capital letter variables attr_accessor :auto_lowervar end =begin rdoc Ring constructor. ringstr string representation to be parsed. ring JAS ring object. =end def initialize(ringstr="",ring=nil) if ring == nil sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #@pset = tok.nextPolynomialSet(); @ring = pfac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end # parameter ",fast=false" not possible w/o keyword params #if fast == true # return #end @engine = Ring.getEngineGcd(@ring); @sqf = Ring.getEngineSqf(@ring); @factor = Ring.getEngineFactor(@ring); variable_generators() #puts "self.class.auto_inject = " + self.class.auto_inject.to_s #puts "self.class.superclass.auto_inject = " + self.class.superclass.auto_inject.to_s if self.class.auto_inject or self.class.superclass.auto_inject # sic! inject_variables(); end end =begin rdoc Get the polynomial gcd engine implementation. r is the given polynomial ring. =end def Ring.getEngineGcd(r) if r.is_a? RingElem r = r.elem; end if not r.is_a? GenPolynomialRing return nil; end begin i = GCDFactory.getProxy(r.coFac); #i = GCDFactory.getImplementation(r.coFac); rescue => e i = nil end #puts "gcd engine: #{i}"; return i; end =begin rdoc Get the polynomial squarefree engine implementation. r is the given polynomial ring. =end def Ring.getEngineSqf(r) if r.is_a? RingElem r = r.elem; end if not r.is_a? GenPolynomialRing return nil; end begin i = SquarefreeFactory.getImplementation(r.coFac); rescue => e i = nil end #puts "sqf engine: #{i}"; return i; end =begin rdoc Get the polynomial factorization engine implementation. r is the given polynomial ring. =end def Ring.getEngineFactor(r) if r.is_a? RingElem r = r.elem; end if not r.is_a? GenPolynomialRing return nil; end begin i = FactorFactory.getImplementation(r.coFac); rescue => e i = nil end #puts "factor engine: #{i}"; return i; end =begin rdoc Define instance variables for generators. =end def variable_generators() Ring.instance_eval( "attr_accessor :generators;" ) @generators = {}; for i in self.gens() begin ivs = nameFromValue(i); if ivs != nil #puts "string: #{ivs} = " + ivs.class.to_s; if @generators[ ivs ] != nil puts "redefining local variable #{ivs}"; end @generators[ ivs ] = i; self.instance_eval( "def #{ivs}; @generators[ '#{ivs}' ]; end" ) end rescue => e puts "ring error: #{ivs} = " + i.to_s + ", e = " + str(e); #pass end end #puts "locally defined generators: " + @generators.keys().join(", "); end =begin rdoc Inject variables for generators in top level environment. =end def inject_variables() begin require "irb/frame" # must be placed here bin = IRB::Frame.bottom(0); env = eval "self", bin; #puts "inject_gens: env1 = " + str(env) inject_gens(env) #puts "inject_gens: env2 = " + str(env) rescue => e puts "error: 'irb/frame' not found, e = " + str(e); end end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end =begin rdoc Test if two rings are equal. =end def ==(other) if not other.is_a? Ring return false; end return @ring.equals(other.ring); end =begin rdoc Create an ideal. =end def ideal(ringstr="",list=nil) return JAS::SimIdeal.new(self,ringstr,list); end =begin rdoc Create an ideal in a polynomial ring with parameter coefficients. =end def paramideal(ringstr="",list=nil,gbsys=nil) return ParamIdeal.new(self,ringstr,list,gbsys); end =begin rdoc Get a power series ring from this ring. =end def powerseriesRing() pr = MultiVarPowerSeriesRing.new(@ring); return MultiSeriesRing.new("",nil,pr); end =begin rdoc Get list of generators of the polynomial ring. =end def gens() ll = @ring.generators(); n = ll.map{ |e| RingElem.new(e) }; return n; end =begin rdoc Get the one of the polynomial ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the polynomial ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Get a random polynomial. =end def random(k=5,l=7,d=3,q=0.3) r = @ring.random(k,l,d,q); if @ring.coFac.isField() r = r.monic(); end return RingElem.new( r ); end =begin rdoc Create an element from a string or an object. =end def element(poly) if not poly.is_a? String begin if @ring == poly.ring return RingElem.new(poly); end rescue => e # pass end poly = str(poly); end i = SimIdeal.new( self, "( " + poly + " )" ); list = i.pset.list; if list.size > 0 return RingElem.new( list[0] ); end end =begin rdoc Compute the greatest common divisor of a and b. =end def gcd(a,b) if a.is_a? RingElem a = a.elem; else a = element( a ); a = a.elem; end if b.is_a? RingElem b = b.elem; else b = element( b ); b = b.elem; end cf = @ring.coFac; if cf.is_a? GenPolynomialRing e = @engine.recursiveGcd( a, b ); else e = @engine.gcd( a, b ); end return RingElem.new( e ); end =begin rdoc Compute squarefree factors of polynomial. =end def squarefreeFactors(a) if a.is_a? RingElem a = a.elem; else a = element( a ); a = a.elem; end cf = @ring.coFac; if cf.is_a? GenPolynomialRing e = @sqf.recursiveSquarefreeFactors( a ); else e = @sqf.squarefreeFactors( a ); end ll = {}; for a in e.keySet() i = e.get(a); ll[ RingElem.new( a ) ] = i; end return ll; end =begin rdoc Compute irreducible factorization for modular, integer, rational number and algebriac number coefficients. =end def factors(a) if a.is_a? RingElem a = a.elem; else a = element( a ); a = a.elem; end begin cf = @ring.coFac; if cf.is_a? GenPolynomialRing e = @factor.recursiveFactors( a ); else e = @factor.factors( a ); end ll = {}; for a in e.keySet() i = e.get(a); ll[ RingElem.new( a ) ] = i; end return ll; rescue => e puts "error " + str(e) return nil end end =begin rdoc Compute absolute irreducible factorization for (modular,) rational number coefficients. =end def factorsAbsolute(a) if a.is_a? RingElem a = a.elem; else a = element( a ); a = a.elem; end begin ll = @factor.factorsAbsolute( a ); ## ll = {}; ## for a in e.keySet() ## i = e.get(a); ## ll[ RingElem.new( a ) ] = i; return ll; rescue => e puts "error in factorsAbsolute " + str(e) return nil end end =begin rdoc Compute real roots of univariate polynomial. =end def realRoots(a,eps=nil) if not a.is_a? RingElem a = RingElem.new(a); end return a.realRoots(eps); end =begin rdoc Compute complex roots of univariate polynomial. =end def complexRoots(a,eps=nil) if not a.is_a? RingElem a = RingElem.new(a); end return a.complexRoots(eps); end =begin rdoc Compute algebraic real and complex roots of univariate polynomial. =end def algebraicRoots(a,eps=nil) if not a.is_a? RingElem a = RingElem.new(a); end return a.algebraicRoots(eps); end =begin rdoc Compute algebraic real and complex roots refinement. =end def rootRefine(a,eps=nil) if not a.is_a? RingElem a = RingElem.new(a); end return a.rootRefine(eps); end =begin rdoc Compute deximal approximation of algebraic real and complex roots. =end def decimalRoots(a,eps=nil) if not a.is_a? RingElem a = RingElem.new(a); end return a.decimalRoots(eps); end =begin rdoc Roots of unity of real and complex algebraic numbers. =end def rootsOfUnity(a) if not a.is_a? RingElem a = RingElem.new(a); end return a.rootsOfUnity(); end =begin rdoc Root reduce of real and complex algebraic numbers. Compute an extension field with a primitive element. =end def rootReduce(a, b) if not a.is_a? RingElem a = RingElem.new(a); end return a.rootReduce(b); end =begin rdoc Integrate rational function or power series. =end def integrate(a) if not a.is_a? RingElem a = RingElem.new(a); end return a.integrate(); end =begin rdoc Sub ring generators as Groebner base. =end def subring(polystr="", list=nil) if list == nil sr = StringReader.new( polystr ); tok = GenPolynomialTokenizer.new(@ring,sr); @list = tok.nextPolynomialList(); else @list = rbarray2arraylist(list,rec=1); end sr = PolyGBUtil.subRing(@list); srr = sr.map { |a| RingElem.new(a) }; return srr; end =begin rdoc Sub ring member test. list is a Groebner base. Test if a \in K[list]. =end def subringmember(list, a) sr = list.map { |p| p.elem }; if a.is_a? RingElem a = a.elem; end b = PolyGBUtil.subRingMember(sr, a); return b; end =begin rdoc Chinese remainder theorem. =end def CRT(polystr="", list=nil, rem=nil) if list == nil sr = StringReader.new( polystr ); tok = GenPolynomialTokenizer.new(@ring,sr); @list = tok.nextPolynomialList(); else @list = rbarray2arraylist(list,nil,rec=2); end if rem == nil raise ArgumentError, "No remainders given." else @remlist = rbarray2arraylist(rem,nil,rec=1); end #puts "list = " + str(@list); #puts "remlist = " + str(@remlist); #puts h = PolyGBUtil.chineseRemainderTheorem(@list, @remlist); if h != nil h = RingElem.new(h); end return h; end =begin rdoc Chinese remainder theorem, interpolation. =end def CRTinterpol(polystr="", list=nil, rem=nil) if list == nil sr = StringReader.new( polystr ); tok = GenPolynomialTokenizer.new(@ring,sr); @list = tok.nextPolynomialList(); else @list = rbarray2arraylist(list,nil,rec=2); end if rem == nil raise ArgumentError, "No remeinders given." else @remlist = rbarray2arraylist(rem,nil,rec=1); end #puts "ring = " + str(@ring.toScript()); #puts "list = " + str(@list); #puts "remlist = " + str(@remlist); #puts h = PolyGBUtil.CRTInterpolation(@ring, @list, @remlist); if h != nil h = RingElem.new(h); end return h; end end =begin rdoc Collection of JAS and other CAS term order names. Defines names for term orders. See {TermOrderByName}[http://krum.rz.uni-mannheim.de/jas/doc/api/edu/jas/poly/TermOrderByName.html]. =end class Order < TermOrderByName end =begin rdoc Represents a JAS polynomial ring: GenPolynomialRing. Provides more convenient constructor. Then returns a Ring. =end class PolyRing < Ring # class instance variables != class variables @lex = Order::INVLEX @grad = Order::IGRLEX class << self # means add to class # the Java term orderings attr_reader :lex, :grad end =begin rdoc Ring constructor. coeff = factory for coefficients, vars = string with variable names, order = term order or weight matrix. =end def initialize(coeff,vars,order=Order::IGRLEX) if coeff == nil raise ArgumentError, "No coefficient given." end cf = coeff; if coeff.is_a? RingElem cf = coeff.elem.factory(); end if coeff.is_a? Ring cf = coeff.ring; end if vars == nil raise ArgumentError, "No variable names given." end names = vars; if vars.is_a? String names = GenPolynomialTokenizer.variableList(vars); end nv = names.size; to = Order::IGRLEX; #self.class.grad; if order.is_a? TermOrder to = order; end if order.is_a? Array to = TermOrder.reverseWeight(order); end @ring = GenPolynomialRing.new(cf,nv,to,names); #@ring = tring; super("",@ring) end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end end =begin rdoc Create JAS AlgebraicNumber as ring element. =end def AN(m,z=0,field=false,pr=nil) if m.is_a? RingElem m = m.elem; end if z.is_a? RingElem z = z.elem; end if z != 0 and ( z == true or z == false ) field = z; z = 0; end #puts "m.getClass() = " + str(m.getClass().getName()); #puts "field = " + str(field); if m.is_a? AlgebraicNumber mf = AlgebraicNumberRing.new(m.factory().modul,m.factory().isField()); else if field mf = AlgebraicNumberRing.new(m,field); else mf = AlgebraicNumberRing.new(m); end end #puts "mf = " + mf.toString(); if z == 0 r = AlgebraicNumber.new(mf); else r = AlgebraicNumber.new(mf,z); end return RingElem.new(r); end java_import "edu.jas.arith.PrimeInteger"; java_import "edu.jas.ufd.PolyUfdUtil"; $finiteFields = Hash.new; =begin rdoc Create JAS Finite Field element as ring element. FF has pn elements. =end def FF(p,n,z=0) if p.is_a? RingElem p = p.elem; end if n.is_a? RingElem n = n.elem; end if z.is_a? RingElem z = z.elem; end if z.is_a? AlgebraicNumber z = z.val; #puts "z = " + z.ring.toScript(); end if p == 0 raise ArgumentError, "No finite ring." end if n == 0 raise ArgumentError, "No finite ring." end field = true; if !PrimeInteger.isPrime(p) field = false; #raise ArgumentError, "{p} not prime." end mf = $finiteFields[ [p,n] ]; if mf == nil cf = GF(p).ring; mf = PolyUfdUtil.algebraicNumberField(cf,n); $finiteFields[ [p,n] ] = mf; #puts "mf = " + mf.toScript(); end if z == 0 r = AlgebraicNumber.new(mf); else r = AlgebraicNumber.new(mf,z); #puts "r = " + r.toScript(); end return RingElem.new(r); end java_import "edu.jas.root.RealArithUtil"; java_import "edu.jas.root.RealRootsSturm"; java_import "edu.jas.root.Interval"; java_import "edu.jas.root.RealAlgebraicNumber"; java_import "edu.jas.root.RealAlgebraicRing"; java_import "edu.jas.root.ComplexRootsSturm"; java_import "edu.jas.root.Rectangle"; java_import "edu.jas.root.RootFactory"; java_import "edu.jas.application.AlgebraicRootsPrimElem"; java_import "edu.jas.application.RootFactoryApp"; =begin rdoc Create JAS RealAlgebraicNumber as ring element. =end def RealN(m,i,r=0) if m.is_a? RingElem m = m.elem; end if r.is_a? RingElem r = r.elem; end if i.is_a? Array i = rbarray2arraylist(i,BigRational.new(0),1); i = Interval.new(i[0],i[1]); end #puts "m.getClass() = " + m.getClass().getName().to_s; if m.is_a? RealAlgebraicNumber mf = RealAlgebraicRing.new(m.factory().algebraic.modul,i); else mf = RealAlgebraicRing.new(m,i); end if r == 0 rr = RealAlgebraicNumber.new(mf); else rr = RealAlgebraicNumber.new(mf,r); end return RingElem.new(rr); end java_import "edu.jas.ufd.Quotient"; java_import "edu.jas.ufd.QuotientRing"; java_import "edu.jas.fd.SolvableQuotient"; java_import "edu.jas.fd.SolvableQuotientRing"; java_import "edu.jas.fd.QuotSolvablePolynomial"; java_import "edu.jas.fd.QuotSolvablePolynomialRing"; java_import "edu.jas.application.ResidueSolvablePolynomial"; java_import "edu.jas.application.ResidueSolvablePolynomialRing"; java_import "edu.jas.application.LocalSolvablePolynomial"; java_import "edu.jas.application.LocalSolvablePolynomialRing"; java_import "edu.jas.application.ResidueSolvableWordPolynomial"; java_import "edu.jas.application.ResidueSolvableWordPolynomialRing"; =begin rdoc Create JAS rational function Quotient as ring element. =end def RF(pr,d=0,n=1) if d.is_a? Array if n != 1 puts "#{} ignored\n"; end if d.size > 1 n = d[1]; end d = d[0]; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if pr.is_a? RingElem pr = pr.elem; end if pr.is_a? Ring pr = pr.ring; end qr = QuotientRing.new(pr); if d == 0 r = Quotient.new(qr); else if n == 1 r = Quotient.new(qr,d); else r = Quotient.new(qr,d,n); end end return RingElem.new(r); end =begin rdoc Create JAS rational function SolvableQuotient as ring element. =end def SRF(pr,d=0,n=1) if d.is_a? Array if n != 1 puts "#{} ignored\n"; end if d.size > 1 n = d[1]; end d = d[0]; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if pr.is_a? RingElem pr = pr.elem; end if pr.is_a? Ring pr = pr.ring; end qr = SolvableQuotientRing.new(pr); #puts "qr is associative: " + qr.isAssociative().to_s; #if not qr.isAssociative() # puts "warning: qr is not associative"; #end if d == 0 r = SolvableQuotient.new(qr); else if n == 1 r = SolvableQuotient.new(qr,d); else r = SolvableQuotient.new(qr,d,n); end end return RingElem.new(r); end java_import "edu.jas.application.PolyUtilApp"; java_import "edu.jas.application.Residue"; java_import "edu.jas.application.ResidueRing"; java_import "edu.jas.application.Ideal"; java_import "edu.jas.application.SolvableResidue"; java_import "edu.jas.application.SolvableResidueRing"; java_import "edu.jas.application.SolvableIdeal"; java_import "edu.jas.application.Local"; java_import "edu.jas.application.LocalRing"; java_import "edu.jas.application.SolvableLocal"; java_import "edu.jas.application.SolvableLocalRing"; java_import "edu.jas.application.SolvableLocalResidue"; java_import "edu.jas.application.SolvableLocalResidueRing"; java_import "edu.jas.application.IdealWithRealAlgebraicRoots"; java_import "edu.jas.application.ComprehensiveGroebnerBaseSeq"; java_import "edu.jas.application.WordIdeal"; java_import "edu.jas.application.WordResidue"; java_import "edu.jas.application.WordResidueRing"; =begin rdoc Create JAS polynomial Residue as ring element. =end def RC(ideal,r=0) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? SimIdeal #puts "ideal.pset = " + str(ideal.pset) + "\n"; #ideal = Java::EduJasApplication::Ideal.new(ideal.ring,ideal.list); ideal = Ideal.new(ideal.pset); #ideal.doGB(); end #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if ideal.getList().get(0).ring.is_a? ResidueRing rc = ResidueRing.new( ideal.getList().get(0).ring.ideal ); else rc = ResidueRing.new(ideal); end if r.is_a? RingElem r = r.elem; end if r == 0 r = Residue.new(rc); else r = Residue.new(rc,r); end return RingElem.new(r); end =begin rdoc Create JAS polynomial Local as ring element. =end def LC(ideal,d=0,n=1) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? SimIdeal ideal = Ideal.new(ideal.pset); #ideal.doGB(); end #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if ideal.getList().get(0).ring.is_a? LocalRing lc = LocalRing.new( ideal.getList().get(0).ring.ideal ); else lc = LocalRing.new(ideal); end if d.is_a? Array if n != 1 puts "#{n} ignored\n"; end if d.size > 1 n = d[1]; end d = d[0]; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if d == 0 r = Local.new(lc); else if n == 1 r = Local.new(lc,d); else r = Local.new(lc,d,n); end end return RingElem.new(r); end =begin rdoc Create JAS polynomial SolvableResidue as ring element. =end def SRC(ideal,r=0) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? SolvIdeal #puts "ideal.pset = " + str(ideal.pset) + "\n"; #ideal = Java::EduJasApplication::Ideal.new(ideal.ring,ideal.list); ideal = SolvableIdeal.new(ideal.pset); #ideal.doGB(); end #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if ideal.getList().get(0).ring.is_a? SolvableResidueRing rc = SolvableResidueRing.new( ideal.getList().get(0).ring.ideal ); else rc = SolvableResidueRing.new(ideal); end if r.is_a? RingElem r = r.elem; end if r == 0 r = SolvableResidue.new(rc); else r = SolvableResidue.new(rc,r); end return RingElem.new(r); end =begin rdoc Create JAS polynomial SolvableLocal as ring element. =end def SLC(ideal,d=0,n=1) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? SolvIdeal ideal = SolvableIdeal.new(ideal.pset); #ideal.doGB(); end #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if ideal.getList().get(0).ring.is_a? SolvableLocalRing lc = SolvableLocalRing.new( ideal.getList().get(0).ring.ideal ); else lc = SolvableLocalRing.new(ideal); end if d.is_a? Array if n != 1 puts "#{n} ignored\n"; end if d.size > 1 n = d[1]; end d = d[0]; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if d == 0 r = SolvableLocal.new(lc); else if n == 1 r = SolvableLocal.new(lc,d); else r = SolvableLocal.new(lc,d,n); end end return RingElem.new(r); end =begin rdoc Create JAS polynomial SolvableLocalResidue as ring element. =end def SLR(ideal,d=0,n=1) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? SolvIdeal ideal = SolvableIdeal.new(ideal.pset); #ideal.doGB(); end cfr = ideal.getList().get(0).ring; #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if n == true isfield = true; n = 1; end if cfr.is_a? SolvableLocalResidueRing lc = SolvableLocalResidueRing.new( cfr.ideal ); else lc = SolvableLocalResidueRing.new(ideal); end if d.is_a? Array if n != 1 puts "#{n} ignored\n"; end if d.size > 1 n = d[1]; end d = d[0]; end if d.is_a? RingElem d = d.elem; end if n.is_a? RingElem n = n.elem; end if d == 0 r = SolvableLocalResidue.new(lc); else if n == 1 r = SolvableLocalResidue.new(lc,d); else r = SolvableLocalResidue.new(lc,d,n); end end return RingElem.new(r); end =begin rdoc Create JAS regular ring Product as ring element. =end def RR(flist,n=1,r=0) if not n.is_a? Integer r = n; n = 1; end if flist == nil raise ArgumentError, "No list given." end if flist.is_a? Array flist = rbarray2arraylist( flist.map { |x| x.factory() }, rec=1); ncop = 0; else ncop = n; end if flist.is_a? RingElem flist = flist.elem; flist = flist.factory(); ncop = n; end #puts "flist = " + str(flist); #puts "ncop = " + str(ncop); if ncop == 0 pr = ProductRing.new(flist); else pr = ProductRing.new(flist,ncop); end #puts "r type(#{r}) = #{r.class}\n"; if r.is_a? RingElem r = r.elem; end begin #puts "r.class() = #{r.class}\n"; if r.is_a? Product #puts "r.val = #{r.val}\n"; r = r.val; end rescue #pass; end #puts "r = " + r.to_s; if r == 0 r = Product.new(pr); else r = Product.new(pr,r); end return RingElem.new(r); end =begin rdoc Convert a Ruby array to a Java ArrayList. If list is a Ruby array, it is converted, else list is left unchanged. =end def rbarray2arraylist(list,fac=nil,rec=1) #puts "list type(#{list}) = #{list.class}\n"; if list.is_a? Array ll = ArrayList.new(); for e in list t = true; if e.is_a? RingElem t = false; e = e.elem; end if e.is_a? Array if rec <= 1 e = makeJasArith(e); else t = false; e = rbarray2arraylist(e,fac,rec-1); end end begin #n = e.getClass().getSimpleName(); if e.is_a? ArrayList t = false; end rescue #pass; end if t and fac != nil #puts "e.p(#{e}) = #{e.class}, #{fac.toScriptFactory()}\n"; e = fac.parse( str(e) ); #or makeJasArith(e) ? end ll.add(e); end list = ll; end #puts "list type(#{list}) = #{list.class}\n"; return list end =begin rdoc Construct a jas.arith object. If item is an ruby array then a BigComplex is constructed. If item is a ruby float then a BigDecimal is constructed. Otherwise, item is returned unchanged. =end def makeJasArith(item) #puts "item type(#{item}) = #{item.class}\n"; if item.is_a? Integer return BigInteger.new( item ); end if item.is_a? Rational return BigRational.new( item.numerator ).divide( BigRational.new( item.denominator ) ); end if item.is_a? Float # ?? what to do ?? return BigDecimal.new( item.to_s ); end if item.is_a? Array if item.size > 2 puts "len(item) > 2, remaining items ignored\n"; end puts "item[0] type(#{item[0]}) = #{item[0].class}\n"; if item.size > 1 re = makeJasArith( item[0] ); if not re.isField() re = BigRational.new( re.val ); end im = makeJasArith( item[1] ); if not im.isField() im = BigRational.new( im.val ); end jasArith = BigComplex.new( re, im ); else re = makeJasArith( item[0] ); if not re.isField() re = BigRational.new( re.val ); end jasArith = BigComplex.new( re ); end return jasArith; end puts "unknown item type(#{item}) = #{item.class}\n"; return item; end java_import "edu.jas.gb.DGroebnerBaseSeq"; java_import "edu.jas.gb.EGroebnerBaseSeq"; java_import "edu.jas.gb.EReductionSeq"; java_import "edu.jas.gb.GroebnerBaseDistributedEC"; java_import "edu.jas.gb.GroebnerBaseDistributedHybridEC"; #java_import "edu.jas.gb.GBDist"; java_import "edu.jas.gb.GroebnerBaseParallel"; java_import "edu.jas.gb.GroebnerBaseSeq"; java_import "edu.jas.gb.GroebnerBaseSeqIter"; java_import "edu.jas.gb.GroebnerBaseSeqPairSeq"; java_import "edu.jas.gb.ReductionSeq"; java_import "edu.jas.gb.OrderedPairlist"; java_import "edu.jas.gb.OrderedSyzPairlist"; java_import "edu.jas.gb.GroebnerBaseSeqPairParallel"; java_import "edu.jas.gb.SolvableGroebnerBaseParallel"; java_import "edu.jas.gb.SolvableGroebnerBaseSeq"; java_import "edu.jas.gb.SolvableReductionSeq"; java_import "edu.jas.gb.WordGroebnerBaseSeq"; java_import "edu.jas.gbufd.GroebnerBasePseudoRecSeq"; java_import "edu.jas.gbufd.GroebnerBasePseudoSeq"; java_import "edu.jas.gbufd.SolvableGroebnerBasePseudoRecSeq"; java_import "edu.jas.gbufd.SolvableGroebnerBasePseudoSeq"; java_import "edu.jas.gbufd.WordGroebnerBasePseudoSeq"; java_import "edu.jas.gbufd.WordGroebnerBasePseudoRecSeq"; java_import "edu.jas.gbufd.RGroebnerBasePseudoSeq"; java_import "edu.jas.gbufd.GroebnerBasePseudoParallel"; java_import "edu.jas.gbufd.PseudoReductionSeq"; java_import "edu.jas.gbufd.RGroebnerBaseSeq"; java_import "edu.jas.gbufd.RReductionSeq"; java_import "edu.jas.gbufd.CharacteristicSetWu"; java_import "edu.jas.gbufd.GroebnerBaseFGLM"; java_import "edu.jas.gbufd.GroebnerBaseWalk"; java_import "edu.jas.gbufd.SyzygySeq"; java_import "edu.jas.gbufd.SolvableSyzygySeq"; =begin rdoc Represents a JAS polynomial ideal: PolynomialList and Ideal. Methods for Groebner bases, ideal sum, intersection and others. =end class SimIdeal include Comparable # the Java polynomial list, polynomial ring, and ideal decompositions attr_reader :pset, :ring, :list, :roots, :prime, :primary #, :ideal =begin rdoc SimIdeal constructor. =end def initialize(ring,polystr="",list=nil) @ring = ring; if list == nil sr = StringReader.new( polystr ); tok = GenPolynomialTokenizer.new(ring::ring,sr); @list = tok.nextPolynomialList(); else @list = rbarray2arraylist(list,rec=1); end #@list = PolyUtil.monic(@list); @pset = OrderedPolynomialList.new(@ring.ring,@list); #@ideal = Ideal.new(@pset); @roots = nil; @croots = nil; @prime = nil; @primary = nil; #super(@ring::ring,@list) # non-sense, JRuby extends application.Ideal end =begin rdoc Create a string representation. =end def to_s() return @pset.toScript(); end =begin rdoc Compare two ideals. =end def <=>(other) s = Ideal.new(@pset); o = Ideal.new(other.pset); return s.compareTo(o); end =begin rdoc Test if two ideals are equal. =end def ==(other) if not other.is_a? SimIdeal return false; end return (self <=> other) == 0; end =begin rdoc Test if ideal is one. =end def isONE() s = Ideal.new(@pset); return s.isONE(); end =begin rdoc Test if ideal is zero. =end def isZERO() s = Ideal.new(@pset); return s.isZERO(); end =begin rdoc Create an ideal in a polynomial ring with parameter coefficients. =end def paramideal() return ParamIdeal.new(@ring,"",@list); end =begin rdoc Compute a Groebner base. =end def GB() #if @ideal != nil # return SimIdeal.new(@ring,"",nil,@ideal.GB()); #end cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.isField() #gg = GroebnerBaseSeq.new().GB(ff); #gg = GroebnerBaseSeq.new(ReductionSeq.new(),OrderedPairlist.new()).GB(ff); gg = GroebnerBaseSeq.new(ReductionSeq.new(),OrderedSyzPairlist.new()).GB(ff); #gg = GroebnerBaseSeqIter.new(ReductionSeq.new(),OrderedSyzPairlist.new()).GB(ff); kind = "field" else if cofac.is_a? GenPolynomialRing and cofac.isCommutative() gg = GroebnerBasePseudoRecSeq.new(cofac).GB(ff); kind = "pseudoRec" else gg = GroebnerBasePseudoSeq.new(cofac).GB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "sequential(#{kind}) GB executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Test if this is a Groebner base. =end def isGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() b = GroebnerBaseSeq.new().isGB(ff); else if cofac.is_a? GenPolynomialRing and cofac.isCommutative() b = GroebnerBasePseudoRecSeq.new(cofac).isGB(ff); else b = GroebnerBasePseudoSeq.new(cofac).isGB(ff); end end t = System.currentTimeMillis() - t; puts "isGB = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute an e-Groebner base. =end def eGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() gg = GroebnerBaseSeq.new().GB(ff); else gg = EGroebnerBaseSeq.new().GB(ff) end t = System.currentTimeMillis() - t; puts "sequential e-GB executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Test if this is an e-Groebner base. =end def iseGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() b = GroebnerBaseSeq.new().isGB(ff); else b = EGroebnerBaseSeq.new().isGB(ff) end t = System.currentTimeMillis() - t; puts "is e-GB = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute an extended e-Groebner base. =end def eExtGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() gg = GroebnerBaseSeq.new().extGB(ff); else gg = EGroebnerBaseSeq.new().extGB(ff) end t = System.currentTimeMillis() - t; puts "sequential extended e-GB executed in #{t} ms\n"; return gg; #SimIdeal.new(@ring,"",gg); end =begin rdoc Test if eg is an extended e-Groebner base. =end def iseExtGB(eg) s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() b = GroebnerBaseSeq.new().isMinReductionMatrix(eg); else b = EGroebnerBaseSeq.new().isMinReductionMatrix(eg) end t = System.currentTimeMillis() - t; #puts "sequential test extended e-GB executed in #{t} ms\n"; return b; end =begin rdoc Compute an d-Groebner base. =end def dGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() gg = GroebnerBaseSeq.new().GB(ff); else gg = DGroebnerBaseSeq.new().GB(ff) end t = System.currentTimeMillis() - t; puts "sequential d-GB executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Test if this is a d-Groebner base. =end def isdGB() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() b = GroebnerBaseSeq.new().isGB(ff); else b = DGroebnerBaseSeq.new().isGB(ff) end t = System.currentTimeMillis() - t; puts "is d-GB = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute in parallel a Groebner base. =end def parUnusedGB(th) s = @pset; ff = s.list; bbpar = GroebnerBaseSeqPairParallel.new(th); t = System.currentTimeMillis(); gg = bbpar.GB(ff); t = System.currentTimeMillis() - t; bbpar.terminate(); puts "parallel-old #{th} executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Compute in parallel a Groebner base. =end def parGB(th) s = @pset; ff = s.list; cofac = s.ring.coFac; if cofac.isField() bbpar = GroebnerBaseParallel.new(th); else bbpar = GroebnerBasePseudoParallel.new(th,cofac); end t = System.currentTimeMillis(); gg = bbpar.GB(ff); t = System.currentTimeMillis() - t; bbpar.terminate(); puts "parallel #{th} executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Compute on a distributed system a Groebner base. =end def distGB(th=2,machine="examples/machines.localhost",port=55711) s = @pset; ff = s.list; t = System.currentTimeMillis(); # old: gbd = GBDist.new(th,machine,port); gbd = GroebnerBaseDistributedEC.new(machine,th,port); #gbd = GroebnerBaseDistributedHybridEC.new(machine,th,3,port); t1 = System.currentTimeMillis(); gg = gbd.GB(ff); t1 = System.currentTimeMillis() - t1; gbd.terminate(false); t = System.currentTimeMillis() - t; puts "distributed #{th} executed in #{t1} ms (#{t-t1} ms start-up)\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Client for a distributed computation. =end def distClient(port=4711) s = @pset; e1 = ExecutableServer.new( port ); e1.init(); e2 = ExecutableServer.new( port+1 ); e2.init(); @exers = [e1,e2]; return nil; end =begin rdoc Client for a distributed computation. =end def distClientStop() for es in @exers; es.terminate(); end return nil; end =begin rdoc Compute a normal form of p with respect to this ideal. =end def reduction(p) s = @pset; gg = s.list; if p.is_a? RingElem p = p.elem; end #t = System.currentTimeMillis(); if @ring.ring.coFac.isField() n = ReductionSeq.new().normalform(gg,p); else n = PseudoReductionSeq.new().normalform(gg,p); #ff = PseudoReductionSeq.New().normalformFactor(gg,p); #print "ff.multiplicator = " + str(ff.multiplicator) end #t = System.currentTimeMillis() - t; #puts "sequential reduction executed in " + str(t) + " ms"; return RingElem.new(n); end =begin rdoc Compute a e-normal form of p with respect to this ideal. =end def eReduction(p) s = @pset; gg = s.list; if p.is_a? RingElem p = p.elem; end t = System.currentTimeMillis(); n = EReductionSeq.new().normalform(gg,p); t = System.currentTimeMillis() - t; puts "sequential eReduction executed in " + str(t) + " ms"; return RingElem.new(n); end =begin rdoc Compute a e-normal form with recording in row of p with respect to this ideal. =end def eReductionRec(row, p) s = @pset; gg = s.list; row = rbarray2arraylist(row,nil,rec=1) if p.is_a? RingElem p = p.elem; end #puts "p = " + str(p); #puts "gg = " + str(gg); #puts "row_1 = " + str(row); t = System.currentTimeMillis(); n = EReductionSeq.new().normalform(row,gg,p); t = System.currentTimeMillis() - t; #puts "row_2 = " + str(row); puts "sequential eReduction recording executed in " + str(t) + " ms"; #row = row.map{|a| RingElem.new(a) }; return row, RingElem.new(n); end =begin rdoc Test if n is a e-normalform with recording in row of p with respect to this ideal. =end def iseReductionRec(row, p, n) s = @pset; gg = s.list; row = rbarray2arraylist(row,nil,rec=1) if p.is_a? RingElem p = p.elem; end if n.is_a? RingElem n = n.elem; end b = EReductionSeq.new().isReductionNF(row,gg,p,n); return b; end =begin rdoc Compute a normal form of this ideal with respect to reducer. =end def NF(reducer) s = @pset; ff = s.list; gg = reducer.list; t = System.currentTimeMillis(); nn = ReductionSeq.new().normalform(gg,ff); t = System.currentTimeMillis() - t; puts "sequential NF executed in #{t} ms\n"; return SimIdeal.new(@ring,"",nn); end =begin rdoc Represent p as element of this ideal. =end def lift(p) gg = @pset.list; z = @ring.ring.getZERO(); rr = gg.map { |x| z }; if p.is_a? RingElem p = p.elem; end #t = System.currentTimeMillis(); if @ring.ring.coFac.isField() n = ReductionSeq.new().normalform(rr,gg,p); else n = PseudoReductionSeq.new().normalform(rr,gg,p); end if not n.isZERO() raise StandardError, "p ist not a member of the ideal" end #t = System.currentTimeMillis() - t; #puts "sequential reduction executed in " + str(t) + " ms"; return rr.map { |x| RingElem.new(x) }; end =begin rdoc Compute a interreduced ideal basis of this. =end def interreduced_basis() ff = @pset.list; nn = ReductionSeq.new().irreducibleSet(ff); return nn.map{ |x| RingElem.new(x) }; end =begin rdoc Compute the intersection of this and the given polynomial ring. =end def intersectRing(ring) s = Ideal.new(@pset); nn = s.intersect(ring.ring); return SimIdeal.new(ring,"",nn.getList()); end =begin rdoc Compute the intersection of this and the given ideal. =end def intersect(id2) s1 = Ideal.new(@pset); s2 = Ideal.new(id2.pset); nn = s1.intersect(s2); return SimIdeal.new(@ring,"",nn.getList()); end =begin rdoc Compute the elimination ideal of this and the given polynomial ring. =end def eliminateRing(ring) s = Ideal.new(@pset); nn = s.eliminate(ring.ring); r = Ring.new( "", nn.getRing() ); return SimIdeal.new(r,"",nn.getList()); end =begin rdoc Compute the saturation of this and the given ideal. =end def sat(id2) s1 = Ideal.new(@pset); s2 = Ideal.new(id2.pset); #nn = s1.infiniteQuotient(s2); nn = s1.infiniteQuotientRab(s2); mm = nn.getList(); #PolyUtil.monicRec(nn.getList()); return SimIdeal.new(@ring,"",mm); end =begin rdoc Compute the sum of this and the ideal. =end def sum(other) s = Ideal.new(@pset); t = Ideal.new(other.pset); nn = s.sum( t ); return SimIdeal.new(@ring,"",nn.getList()); end =begin rdoc Compute the univariate polynomials in each variable of this ideal. =end def univariates() s = Ideal.new(@pset); ll = s.constructUnivariate(); nn = ll.map {|e| RingElem.new(e) }; return nn; end =begin rdoc Compute the inverse polynomial modulo this ideal, if it exists. =end def inverse(p) if p.is_a? RingElem p = p.elem; end s = Ideal.new(@pset); i = s.inverse(p); return RingElem.new(i); end =begin rdoc Compute the e- inverse polynomial modulo this e-ideal, if it exists. =end def eInverse(p) if p.is_a? RingElem p = p.elem; end i = EGroebnerBaseSeq.new().inverse(p, @list); return RingElem.new(i); end =begin rdoc Test if i is a e-inverse of p modulo this e-ideal. =end def iseInverse(i, p) if i.is_a? RingElem i = i.elem; end if p.is_a? RingElem p = p.elem; end r = EReductionSeq.new().normalform(@list, i.multiply(p)); #puts "r = " + str(r); return r.isONE(); end =begin rdoc Optimize the term order on the variables. =end def optimize() p = @pset; o = TermOrderOptimization.optimizeTermOrder(p); r = Ring.new("",o.ring); return SimIdeal.new(r,"",o.list); end =begin rdoc Compute the dimension of the ideal. =end def dimension() ii = Ideal.new(@pset); d = ii.dimension(); return d; end =begin rdoc Compute real roots of 0-dim ideal. =end def realRoots() ii = Ideal.new(@pset); @roots = PolyUtilApp.realAlgebraicRoots(ii); for r in @roots r.doDecimalApproximation(); end return @roots; end =begin rdoc Print decimal approximation of real roots of 0-dim ideal. =end def realRootsPrint() if @roots == nil ii = Ideal.new(@pset); @roots = PolyUtilApp.realAlgebraicRoots(ii); for r in @roots r.doDecimalApproximation(); end end for ir in @roots for dr in ir.decimalApproximation() puts dr.to_s; end puts; end end =begin rdoc Compute radical decomposition of this ideal. =end def radicalDecomp() ii = Ideal.new(@pset); @radical = ii.radicalDecomposition(); return @radical; end =begin rdoc Compute irreducible decomposition of this ideal. =end def decomposition() ii = Ideal.new(@pset); @irrdec = ii.decomposition(); return @irrdec; end =begin rdoc Compute complex roots of 0-dim ideal. =end def complexRoots() ii = Ideal.new(@pset); @croots = PolyUtilApp.complexAlgebraicRoots(ii); for r in @croots r.doDecimalApproximation(); end return @croots; end =begin rdoc Print decimal approximation of complex roots of 0-dim ideal. =end def complexRootsPrint() if @croots == nil ii = Ideal.new(@pset); @croots = PolyUtilApp.complexAlgebraicRoots(ii); for r in @croots r.doDecimalApproximation(); end end for ic in @croots for dc in ic.decimalApproximation() puts dc.to_s; end puts; end end =begin rdoc Compute prime decomposition of this ideal. =end def primeDecomp() ii = Ideal.new(@pset); @prime = ii.primeDecomposition(); return @prime; end =begin rdoc Compute primary decomposition of this ideal. =end def primaryDecomp() ii = Ideal.new(@pset); ## if @prime == nil: ## @prime = I.primeDecomposition(); @primary = ii.primaryDecomposition(); return @primary; end =begin rdoc Convert rational coefficients to integer coefficients. =end def toInteger() p = @pset; l = p.list; r = p.ring; ri = GenPolynomialRing.new( BigInteger.new(), r.nvar, r.tord, r.vars ); pi = PolyUtil.integerFromRationalCoefficients(ri,l); r = Ring.new("",ri); return SimIdeal.new(r,"",pi); end =begin rdoc Convert integer coefficients to modular coefficients. =end def toModular(mf) p = @pset; l = p.list; r = p.ring; if mf.is_a? RingElem mf = mf.ring; end rm = GenPolynomialRing.new( mf, r.nvar, r.tord, r.vars ); pm = PolyUtil.fromIntegerCoefficients(rm,l); r = Ring.new("",rm); return SimIdeal.new(r,"",pm); end =begin rdoc Compute a Characteristic Set. =end def CS() s = @pset; cofac = s.ring.coFac; ff = s.list; t = System.currentTimeMillis(); if cofac.isField() gg = CharacteristicSetWu.new().characteristicSet(ff); else puts "CS not implemented for coefficients #{cofac.toScriptFactory()}\n"; gg = nil; end t = System.currentTimeMillis() - t; puts "sequential char set executed in #{t} ms\n"; return SimIdeal.new(@ring,"",gg); end =begin rdoc Test for Characteristic Set. =end def isCS() s = @pset; cofac = s.ring.coFac; ff = s.list.clone(); Collections.reverse(ff); # todo t = System.currentTimeMillis(); if cofac.isField() b = CharacteristicSetWu.new().isCharacteristicSet(ff); else puts "isCS not implemented for coefficients #{cofac.toScriptFactory()}\n"; b = false; end t = System.currentTimeMillis() - t; #puts "sequential is char set executed in #{t} ms\n"; return b; end =begin rdoc Compute a normal form of polynomial p with respect this characteristic set. =end def csReduction(p) s = @pset; ff = s.list.clone(); Collections.reverse(ff); # todo if p.is_a? RingElem p = p.elem; end t = System.currentTimeMillis(); nn = CharacteristicSetWu.new().characteristicSetReduction(ff,p); t = System.currentTimeMillis() - t; #puts "sequential char set reduction executed in #{t} ms\n"; return RingElem.new(nn); end =begin rdoc Syzygy of generating polynomials. =end def syzygy() p = @pset; l = p.list; t = System.currentTimeMillis(); s = SyzygySeq.new(p.ring.coFac).zeroRelations( l ); t = System.currentTimeMillis() - t; puts "executed Syzygy in #{t} ms\n"; m = CommutativeModule.new("",p.ring); return SubModule.new(m,"",s); end =begin rdoc Test if this is a syzygy of the module in m. =end def isSyzygy(m) p = @pset; g = p.list; l = m.list; #puts "l = #{l}"; #puts "g = #{g}"; t = System.currentTimeMillis(); z = SyzygySeq.new(p.ring.coFac).isZeroRelation( l, g ); t = System.currentTimeMillis() - t; puts "executed isSyzygy in #{t} ms\n"; return z; end end =begin rdoc Represents a JAS polynomial ideal with polynomial coefficients. Methods to compute comprehensive Groebner bases. =end class ParamIdeal =begin rdoc Parametric ideal constructor. =end def initialize(ring,polystr="",list=nil,gbsys=nil) @ring = ring; if list == nil and polystr != nil sr = StringReader.new( polystr ); tok = GenPolynomialTokenizer.new(ring.ring,sr); @list = tok.nextPolynomialList(); else @list = rbarray2arraylist(list,rec=1); end @gbsys = gbsys; @pset = OrderedPolynomialList.new(ring.ring,@list); end =begin rdoc Create a string representation. =end def to_s() if @gbsys == nil return @pset.toScript(); else return @pset.toScript() + "\n" + @gbsys.toScript(); # return @pset.toScript() + "\n" + @gbsys.to_s; end end =begin rdoc Optimize the term order on the variables of the coefficients. =end def optimizeCoeff() p = @pset; o = TermOrderOptimization.optimizeTermOrderOnCoefficients(p); r = Ring.new("",o.ring); return ParamIdeal.new(r,"",o.list); end =begin rdoc Optimize the term order on the variables of the quotient coefficients. =end def optimizeCoeffQuot() p = @pset; l = p.list; r = p.ring; q = r.coFac; c = q.ring; rc = GenPolynomialRing.new( c, r.nvar, r.tord, r.vars ); #puts "rc = ", rc; lp = PolyUfdUtil.integralFromQuotientCoefficients(rc,l); #puts "lp = ", lp; pp = PolynomialList.new(rc,lp); #puts "pp = ", pp; oq = TermOrderOptimization.optimizeTermOrderOnCoefficients(pp); oor = oq.ring; qo = oor.coFac; cq = QuotientRing.new( qo ); rq = GenPolynomialRing.new( cq, r.nvar, r.tord, r.vars ); #puts "rq = ", rq; o = PolyUfdUtil.quotientFromIntegralCoefficients(rq,oq.list); r = Ring.new("",rq); return ParamIdeal.new(r,"",o); end =begin rdoc Convert rational function coefficients to integral function coefficients. =end def toIntegralCoeff() p = @pset; l = p.list; r = p.ring; q = r.coFac; c = q.ring; rc = GenPolynomialRing.new( c, r.nvar, r.tord, r.vars ); #puts "rc = ", rc; lp = PolyUfdUtil.integralFromQuotientCoefficients(rc,l); #puts "lp = ", lp; r = Ring.new("",rc); return ParamIdeal.new(r,"",lp); end =begin rdoc Convert integral function coefficients to modular function coefficients. =end def toModularCoeff(mf) p = @pset; l = p.list; r = p.ring; c = r.coFac; #puts "c = ", c; if mf.is_a? RingElem mf = mf.ring; end cm = GenPolynomialRing.new( mf, c.nvar, c.tord, c.vars ); #puts "cm = ", cm; rm = GenPolynomialRing.new( cm, r.nvar, r.tord, r.vars ); #puts "rm = ", rm; pm = PolyUfdUtil.fromIntegerCoefficients(rm,l); r = Ring.new("",rm); return ParamIdeal.new(r,"",pm); end =begin rdoc Convert integral function coefficients to rational function coefficients. =end def toQuotientCoeff() p = @pset; l = p.list; r = p.ring; c = r.coFac; #puts "c = ", c; q = QuotientRing.new(c); #puts "q = ", q; qm = GenPolynomialRing.new( q, r.nvar, r.tord, r.vars ); #puts "qm = ", qm; pm = PolyUfdUtil.quotientFromIntegralCoefficients(qm,l); r = Ring.new("",qm); return ParamIdeal.new(r,"",pm); end =begin rdoc Compute a Groebner base. =end def GB() ii = SimIdeal.new(@ring,"",@pset.list); g = ii.GB(); return ParamIdeal.new(g.ring,"",g.pset.list); end =begin rdoc Test if this is a Groebner base. =end def isGB() ii = SimIdeal.new(@ring,"",@pset.list); return ii.isGB(); end =begin rdoc Compute a comprehensive Groebner base. =end def CGB() s = @pset; ff = s.list; t = System.currentTimeMillis(); if @gbsys == nil @gbsys = ComprehensiveGroebnerBaseSeq.new(@ring.ring.coFac).GBsys(ff); end gg = @gbsys.getCGB(); t = System.currentTimeMillis() - t; puts "sequential comprehensive executed in #{t} ms\n"; return ParamIdeal.new(@ring,"",gg,@gbsys); end =begin rdoc Compute a comprehensive Groebner system. =end def CGBsystem() s = @pset; ff = s.list; t = System.currentTimeMillis(); ss = ComprehensiveGroebnerBaseSeq.new(@ring.ring.coFac).GBsys(ff); t = System.currentTimeMillis() - t; puts "sequential comprehensive system executed in #{t} ms\n"; return ParamIdeal.new(@ring,nil,ff,ss); end =begin rdoc Test if this is a comprehensive Groebner base. =end def isCGB() s = @pset; ff = s.list; t = System.currentTimeMillis(); b = ComprehensiveGroebnerBaseSeq.new(@ring.ring.coFac).isGB(ff); t = System.currentTimeMillis() - t; puts "isCGB = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Test if this is a comprehensive Groebner system. =end def isCGBsystem() s = @pset; ss = @gbsys; t = System.currentTimeMillis(); b = ComprehensiveGroebnerBaseSeq.new(@ring.ring.coFac).isGBsys(ss); t = System.currentTimeMillis() - t; puts "isCGBsystem = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Convert Groebner system to a representation with regular ring coefficents. =end def regularRepresentation() if @gbsys == nil return nil; end gg = PolyUtilApp.toProductRes(@gbsys.list); ring = Ring.new(nil,gg[0].ring); return ParamIdeal.new(ring,nil,gg); end =begin rdoc Convert Groebner system to a boolean closed representation with regular ring coefficents. =end def regularRepresentationBC() if @gbsys == nil return nil; end gg = PolyUtilApp.toProductRes(@gbsys.list); ring = Ring.new(nil,gg[0].ring); res = RReductionSeq.new(); gg = res.booleanClosure(gg); return ParamIdeal.new(ring,nil,gg); end =begin rdoc Compute a Groebner base over a regular ring. =end def regularGB() s = @pset; ff = s.list; t = System.currentTimeMillis(); gg = RGroebnerBasePseudoSeq.new(@ring.ring.coFac).GB(ff); t = System.currentTimeMillis() - t; puts "sequential regular GB executed in #{t} ms\n"; return ParamIdeal.new(@ring,nil,gg); end =begin rdoc Test if this is Groebner base over a regular ring. =end def isRegularGB() s = @pset; ff = s.list; t = System.currentTimeMillis(); b = RGroebnerBasePseudoSeq.new(@ring.ring.coFac).isGB(ff); t = System.currentTimeMillis() - t; puts "isRegularGB = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Get each component (slice) of regular ring coefficients separate. =end def stringSlice() s = @pset; b = PolyUtilApp.productToString(s); return b; end end =begin rdoc Represents a JAS solvable polynomial ring: GenSolvablePolynomialRing. Has a method to create solvable ideals. =end class SolvableRing < Ring =begin rdoc Solvable polynomial ring constructor. =end def initialize(ringstr="",ring=nil) if ring == nil sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextSolvablePolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #@pset = tok.nextSolvablePolynomialSet(); @ring = pfac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end if @ring.isAssociative() puts "ring is associative"; else puts "warning: ring is not associative"; end #puts "SolvableRing to super()"; super("",@ring) end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); #.to_s; end =begin rdoc Create a solvable ideal. =end def ideal(ringstr="",list=nil) return SolvIdeal.new(self,ringstr,list); end =begin rdoc Get the one of the solvable polynomial ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the solvable polynomial ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Create an element from a string or object. =end def element(poly) if not poly.is_a? String begin if @ring == poly.ring return RingElem.new(poly); end rescue => e # pass end poly = str(poly); end ii = SolvIdeal.new(self, "( " + poly + " )"); list = ii.pset.list; if list.size > 0 return RingElem.new( list[0] ); end end end =begin rdoc Represents a JAS solvable polynomial ring: GenSolvablePolynomialRing. Provides more convenient constructor. Then returns a Ring. =end class SolvPolyRing < SolvableRing @auto_inject = true @auto_lowervar = false class << self # means add to class # inject variables into environment attr_accessor :auto_inject # avoid capital letter variables attr_accessor :auto_lowervar end =begin rdoc Ring constructor. coeff = factory for coefficients, vars = string with variable names, order = term order, rel = triple list of relations. (e,f,p,...) with e * f = p as relation. =end def initialize(coeff,vars,order,rel=[]) if coeff == nil raise ArgumentError, "No coefficient given." end cf = coeff; if coeff.is_a? RingElem cf = coeff.elem.factory(); end if coeff.is_a? Ring cf = coeff.ring; end if vars == nil raise ArgumentError, "No variable names given." end names = vars; if vars.is_a? String names = GenPolynomialTokenizer.variableList(vars); end nv = names.size; #to = PolyRing.lex; to = PolyRing.grad; if order.is_a? TermOrder to = order; end if order.is_a? Array # ruby has no keyword params rel = order; end ll = []; for x in rel if x.is_a? RingElem x = x.elem; end ll << x; end constSolv = false; (0..ll.size-1).step(3) { |i| #puts "ll[i+1] = #{ll[i+1]}" if ll[i+1].isConstant() constSolv = true; end } #puts "constSolv = #{constSolv}" cfs = cf.toScript(); if cfs[0] == "0" cfs = cf.toScriptFactory(); end #puts "cf = #{cfs}" recSolv = cf.is_a? GenPolynomialRing recSolvWord = cf.is_a? GenWordPolynomialRing resWord = cf.is_a? WordResidueRing quotSolv = cf.is_a? SolvableQuotientRing resSolv = cf.is_a? SolvableResidueRing locSolv = cf.is_a? SolvableLocalRing locresSolv = cf.is_a? SolvableLocalResidueRing if recSolv and not constSolv recSolv = false; end #puts "cf = " + cf.getClass().to_s + ", quotSolv = " + quotSolv.to_s + ", recSolv = " + recSolv.to_s; if recSolv puts "RecSolvablePolynomialRing: " + cfs; ring = RecSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.coeffTable; elsif recSolvWord puts "RecSolvableWordPolynomialRing: " + cfs; ring = RecSolvableWordPolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.coeffTable; elsif resWord puts "ResWordSolvablePolynomialRing: " + cfs; #ring = RecSolvableWordPolynomialRing.new(cf,nv,to,names); ring = ResidueSolvableWordPolynomialRing.new(cf,nv,to,names); #puts "ring = #{ring.toScript()}"; table = ring.table; coeffTable = ring.polCoeff.coeffTable; elsif resSolv puts "ResidueSolvablePolynomialRing: " + cfs; #ring = ResidueSolvablePolynomialRing.new(cf,nv,to,names); ring = QLRSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; elsif quotSolv puts "QuotSolvablePolynomialRing: " + cfs; #ring = QuotSolvablePolynomialRing.new(cf,nv,to,names); ring = QLRSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; elsif locSolv puts "LocalSolvablePolynomialRing: " + cfs; #ring = LocalSolvablePolynomialRing.new(cf,nv,to,names); ring = QLRSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; elsif locresSolv puts "LocalResidueSolvablePolynomialRing: " + cfs; #puts "QLRSolvablePolynomialRing: " + cfs; ring = QLRSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = ring.polCoeff.coeffTable; else puts "GenSolvablePolynomialRing: " + cfs; ring = GenSolvablePolynomialRing.new(cf,nv,to,names); table = ring.table; coeffTable = table; end #puts "ll = " + str(ll); (0..ll.size-1).step(3) { |i| puts "adding relation: " + str(ll[i]) + " * " + str(ll[i+1]) + " = " + str(ll[i+2]); if ll[i+1].isConstant() if recSolv or recSolvWord #puts "r coeff type " + str(ll[i].class); #coeffTable.update( ll[i], ll[i+1].leadingBaseCoefficient(), ll[i+2] ); coeffTable.update( ll[i], ll[i+1], ll[i+2] ); elsif resWord or resSolv or quotSolv or locSolv or locresSolv #puts "rw coeff type " + str(ll[i].class); coeffTable.update( ring.toPolyCoefficients(ll[i]), ring.toPolyCoefficients(ll[i+1]), ring.toPolyCoefficients(ll[i+2]) ); end else # no coeff relation #puts "ll[i], ll[i+1], ll[i+2]: " + str(ll[i]) + ", " + str(ll[i+1]) + ", " + str(ll[i+2]); #puts "poly type " + str(ll[i].class); table.update( ll[i], ll[i+1], ll[i+2] ); if locresSolv or locSolv or quotSolv or resSolv or resWord #puts "ring.polCoeff.table " + str(ring.polCoeff.table.toScript()); ring.polCoeff.table.update( ring.toPolyCoefficients(ll[i]), ring.toPolyCoefficients(ll[i+1]), ring.toPolyCoefficients(ll[i+2]) ); end end } #puts "ring " + ring.toScript(); #puts "isAssoc " + str(ring.isAssociative()); @ring = ring; #puts "SolvPolyRing to super()"; super("",@ring) # puts "ai = " + self.class.auto_inject.to_s # done in super(): #if self.class.auto_inject or self.class.superclass.auto_inject # inject_variables(); #end end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end end =begin rdoc Represents a JAS solvable polynomial ideal. Methods for left, right two-sided Groebner basees and others. =end class SolvIdeal include Comparable # the Java ordered polynomial list, polynomial ring, and polynomial list attr_reader :pset, :ring, :list #, :ideal =begin rdoc Constructor for an ideal in a solvable polynomial ring. =end def initialize(ring,ringstr="",list=nil) @ring = ring; if list == nil sr = StringReader.new( ringstr ); tok = GenPolynomialTokenizer.new(ring.ring,sr); @list = tok.nextSolvablePolynomialList(); else @list = rbarray2arraylist(list,rec=1); end @pset = OrderedPolynomialList.new(ring.ring,@list); #@ideal = SolvableIdeal.new(@pset); end =begin rdoc Create a string representation. =end def to_s() return @pset.toScript(); end =begin rdoc Compare two ideals. =end def <=>(other) s = SolvableIdeal.new(@pset); o = SolvableIdeal.new(other.pset); return s.compareTo(o); end =begin rdoc Test if two ideals are equal. =end def ==(other) if not other.is_a? SolvIdeal return false; end s, o = self, other; return (s <=> o) == 0; end =begin rdoc Test if ideal is one. =end def isONE() s = SolvableIdeal.new(@pset); return s.isONE(); end =begin rdoc Test if ideal is zero. =end def isZERO() s = SolvableIdeal.new(@pset); return s.isZERO(); end =begin rdoc Compute a left Groebner base. =end def leftGB() #if ideal != nil # return SolvIdeal.new(@ring,"",@ideal.leftGB()); #end cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() gg = SolvableGroebnerBasePseudoRecSeq.new(cofac).leftGB(ff); kind = "pseudoRec" else if cofac.isField() or not cofac.isCommutative() gg = SolvableGroebnerBaseSeq.new().leftGB(ff); kind = "field|nocom" else gg = SolvableGroebnerBasePseudoSeq.new(cofac).leftGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "sequential(#{kind}) leftGB executed in #{t} ms\n"; return SolvIdeal.new(@ring,"",gg); end =begin rdoc Test if this is a left Groebner base. =end def isLeftGB() cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() b = SolvableGroebnerBasePseudoRecSeq.new(cofac).isLeftGB(ff); kind = "pseudoRec" else if cofac.isField() or not cofac.isCommutative() b = SolvableGroebnerBaseSeq.new().isLeftGB(ff); kind = "field|nocom" else b = SolvableGroebnerBasePseudoSeq.new(cofac).isLeftGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "isLeftGB(#{kind}) = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute a two-sided Groebner base. =end def twosidedGB() cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() gg = SolvableGroebnerBasePseudoRecSeq.new(cofac).twosidedGB(ff); kind = "pseudoRec" else #puts "two-sided: " + cofac.to_s if cofac.is_a? WordResidue #Ring gg = SolvableGroebnerBasePseudoSeq.new(cofac).twosidedGB(ff); kind = "pseudo" else if cofac.isField() or not cofac.isCommutative() gg = SolvableGroebnerBaseSeq.new().twosidedGB(ff); kind = "field|nocom" else gg = SolvableGroebnerBasePseudoSeq.new(cofac).twosidedGB(ff); kind = "pseudo" end end end t = System.currentTimeMillis() - t; puts "sequential(#{kind}) twosidedGB executed in #{t} ms\n"; return SolvIdeal.new(@ring,"",gg); end =begin rdoc Test if this is a two-sided Groebner base. =end def isTwosidedGB() cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() b = SolvableGroebnerBasePseudoRecSeq.new(cofac).isTwosidedGB(ff); kind = "pseudoRec" else if cofac.isField() or not cofac.isCommutative() b = SolvableGroebnerBaseSeq.new().isTwosidedGB(ff); kind = "field|nocom" else b = SolvableGroebnerBasePseudoSeq.new(cofac).isTwosidedGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "isTwosidedGB(#{kind}) = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute a right Groebner base. =end def rightGB() cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() gg = SolvableGroebnerBasePseudoRecSeq.new(cofac).rightGB(ff); kind = "pseudoRec" else if cofac.isField() or not cofac.isCommutative() gg = SolvableGroebnerBaseSeq.new().rightGB(ff); kind = "field|nocom" else gg = SolvableGroebnerBasePseudoSeq.new(cofac).rightGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "sequential(#{kind}) rightGB executed in #{t} ms\n"; return SolvIdeal.new(@ring,"",gg); end =begin rdoc Test if this is a right Groebner base. =end def isRightGB() cofac = @ring.ring.coFac; ff = @pset.list; kind = ""; t = System.currentTimeMillis(); if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() b = SolvableGroebnerBasePseudoRecSeq.new(cofac).isRightGB(ff); kind = "pseudoRec" else if cofac.isField() or not cofac.isCommutative() b = SolvableGroebnerBaseSeq.new().isRightGB(ff); kind = "field|nocom" else b = SolvableGroebnerBasePseudoSeq.new(cofac).isRightGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "isRightGB(#{kind}) = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compute the intersection of this and a polynomial ring. =end def intersectRing(ring) s = SolvableIdeal.new(@pset); nn = s.intersect(ring.ring); return SolvIdeal.new(@ring,"",nn.getList()); end =begin rdoc Compute the intersection of this and the other ideal. =end def intersect(other) s = SolvableIdeal.new(@pset); t = SolvableIdeal.new(other.pset); nn = s.intersect( t ); return SolvIdeal.new(@ring,"",nn.getList()); end =begin rdoc Compute the sum of this and the other ideal. =end def sum(other) s = SolvableIdeal.new(@pset); t = SolvableIdeal.new(other.pset); nn = s.sum( t ); return SolvIdeal.new(@ring,"",nn.getList()); end =begin rdoc Compute the univariate polynomials in each variable of this twosided ideal. =end def univariates() s = SolvableIdeal.new(@pset); ll = s.constructUnivariate(); nn = ll.map {|e| RingElem.new(e) }; return nn; end =begin rdoc Convert to polynomials with SolvableQuotient coefficients. =end def toQuotientCoefficients() if @pset.ring.coFac.is_a? SolvableResidueRing cf = @pset.ring.coFac.ring; elsif @pset.ring.coFac.is_a? GenSolvablePolynomialRing cf = @pset.ring.coFac; #elsif @pset.ring.coFac.is_a? GenPolynomialRing # cf = @pset.ring.coFac; # puts "cf = " + cf.toScript(); else return self; end rrel = @pset.ring.table.relationList() + @pset.ring.polCoeff.coeffTable.relationList(); #puts "rrel = " + str(rrel); qf = SolvableQuotientRing.new(cf); qr = QuotSolvablePolynomialRing.new(qf,@pset.ring); #puts "qr = " + str(qr); qrel = rrel.map { |r| RingElem.new(qr.fromPolyCoefficients(r)) }; #puts "qrel = " + str(qrel); qring = SolvPolyRing.new(qf,@ring.ring.getVars(),@ring.ring.tord,qrel); #puts "qring = " + str(qring); qlist = @list.map { |r| qr.fromPolyCoefficients(@ring.ring.toPolyCoefficients(r)) }; qlist = qlist.map { |r| RingElem.new(r) }; return SolvIdeal.new(qring,"",qlist); end =begin rdoc Compute the inverse polynomial with respect to this twosided ideal. =end def inverse(p) if p.is_a? RingElem p = p.elem; end s = SolvableIdeal.new(@pset); i = s.inverse(p); return RingElem.new(i); end =begin rdoc Compute a left normal form of p with respect to this ideal. =end def leftReduction(p) s = @pset; gg = s.list; if p.is_a? RingElem p = p.elem; end n = SolvableReductionSeq.new().leftNormalform(gg,p); return RingElem.new(n); end =begin rdoc Compute a right normal form of p with respect to this ideal. =end def rightReduction(p) s = @pset; gg = s.list; if p.is_a? RingElem p = p.elem; end n = SolvableReductionSeq.new().rightNormalform(gg,p); return RingElem.new(n); end =begin rdoc Compute a left Groebner base in parallel. =end def parLeftGB(th) s = @pset; ff = s.list; bbpar = SolvableGroebnerBaseParallel.new(th); t = System.currentTimeMillis(); gg = bbpar.leftGB(ff); t = System.currentTimeMillis() - t; bbpar.terminate(); puts "parallel #{th} leftGB executed in #{t} ms\n"; return SolvIdeal.new(@ring,"",gg); end =begin rdoc Compute a two-sided Groebner base in parallel. =end def parTwosidedGB(th) s = @pset; ff = s.list; bbpar = SolvableGroebnerBaseParallel.new(th); t = System.currentTimeMillis(); gg = bbpar.twosidedGB(ff); t = System.currentTimeMillis() - t; bbpar.terminate(); puts "parallel #{th} twosidedGB executed in #{t} ms\n"; return SolvIdeal.new(@ring,"",gg); end =begin rdoc Left Syzygy of generating polynomials. =end def leftSyzygy() p = @pset; l = p.list; t = System.currentTimeMillis(); s = SolvableSyzygySeq.new(p.ring.coFac).leftZeroRelationsArbitrary( l ); m = SolvableModule.new("",p.ring); t = System.currentTimeMillis() - t; puts "executed leftSyzygy in #{t} ms\n"; return SolvableSubModule.new(m,"",s); end =begin rdoc Right Syzygy of generating polynomials. =end def rightSyzygy() p = @pset; l = p.list; t = System.currentTimeMillis(); s = SolvableSyzygySeq.new(p.ring.coFac).rightZeroRelationsArbitrary( l ); m = SolvableModule.new("",p.ring); t = System.currentTimeMillis() - t; puts "executed rightSyzygy in #{t} ms\n"; return SolvableSubModule.new(m,"",s); end =begin rdoc Test if this is a left syzygy of the module in m. =end def isLeftSyzygy(m) p = @pset; g = p.list; l = m.list; #puts "l = #{l}"; #puts "g = #{g}"; t = System.currentTimeMillis(); z = SolvableSyzygySeq.new(p.ring.coFac).isLeftZeroRelation( l, g ); t = System.currentTimeMillis() - t; puts "executed isLeftSyzygy in #{t} ms\n"; return z; end =begin rdoc Test if this is a right syzygy of the module in m. =end def isRightSyzygy(m) p = @pset; g = p.list; l = m.list; #puts "l = #{l}"; #puts "g = #{g}"; t = System.currentTimeMillis(); z = SolvableSyzygySeq.new(p.ring.coFac).isRightZeroRelation( l, g ); t = System.currentTimeMillis() - t; puts "executed isRightSyzygy in #{t} ms\n"; return z; end =begin rdoc Compute the dimension of the ideal. =end def dimension() ii = SolvableIdeal.new(@pset); d = ii.dimension(); return d; end end =begin rdoc Represents a JAS module over a polynomial ring. Method to create sub-modules. =end class CommutativeModule # the Java polynomial ring, number of columns, module list attr_reader :ring, :cols, :mset =begin rdoc Module constructor. =end def initialize(modstr="",ring=nil,cols=0) if ring == nil sr = StringReader.new( modstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #@mset = tok.nextSubModuleSet(); #if @mset.cols >= 0 # @cols = @mset.cols; #else #end @ring = pfac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end @mset = ModuleList.new(@ring,nil); if cols < 0 cols = 0; end @cols = cols; end =begin rdoc Create a string representation. =end def to_s() return @mset.toScript(); end =begin rdoc Create a sub-module. =end def submodul(modstr="",list=nil) return SubModule.new(self,modstr,list); end =begin rdoc Create an element from a string. =end def element(mods) if not mods.is_a? String begin if @ring == mods.ring return RingElem.new(mods); end rescue => e # pass end mods = str(mods); end ii = SubModule.new( "( " + mods + " )"); list = ii.mset.list; if list.size > 0 return RingElem.new( list[0] ); end end =begin rdoc Get the generators of this module. =end def gens() gm = GenVectorModul.new(@ring,@cols); ll = gm.generators(); nn = ll.map { |e| RingElem.new(e) }; # want use val here, but can not return nn; end end =begin rdoc Represents a JAS sub-module over a polynomial ring. Methods to compute Groebner bases. =end class SubModule # the Java module, module list, polynomial list, number of columns and rows, module list attr_reader :modu, :mset, :pset, :cols, :rows, :list =begin rdoc Constructor for a sub-module. =end def initialize(modu,modstr="",list=nil) @modu = modu; if list == nil sr = StringReader.new( modstr ); tok = GenPolynomialTokenizer.new(modu.ring,sr); @list = tok.nextSubModuleList(); else if list.is_a? Array if list.size != 0 if list[0].is_a? RingElem list = list.map { |re| re.elem }; end end @list = rbarray2arraylist(list,@modu.ring,rec=2); else @list = list; end end #puts "list = ", str(list); #e = @list[0]; #puts "e = ", e; @mset = OrderedModuleList.new(modu.ring,@list); @cols = @mset.cols; @rows = @mset.rows; @pset = @mset.getPolynomialList(); end =begin rdoc Create a string representation. =end def to_s() return @mset.toScript(); # + "\n\n" + str(@pset); end =begin rdoc Compute a Groebner base. =end def GB() t = System.currentTimeMillis(); #gg = ModGroebnerBaseSeq.new(@modu.ring.coFac).GB(@mset); gg = GroebnerBaseSeq.new().GB(@mset); t = System.currentTimeMillis() - t; puts "executed module GB in #{t} ms\n"; return SubModule.new(@modu,"",gg.list); end =begin rdoc Test if this is a Groebner base. =end def isGB() t = System.currentTimeMillis(); #b = ModGroebnerBaseSeq.new(@modu.ring.coFac).isGB(@mset); b = GroebnerBaseSeq.new().isGB(@mset); t = System.currentTimeMillis() - t; puts "module isGB executed in #{t} ms\n"; return b; end =begin rdoc Test if this is a syzygy of the polynomials in g. =end def isSyzygy(g) l = @list; if g.is_a? SimIdeal s = g.pset.list; # not g.list else if g.is_a? SubModule s = g.mset; l = @mset; else raise "unknown type #{g.getClass().getName()}"; end end #puts "l = #{l}"; #puts "s = #{s}"; t = System.currentTimeMillis(); z = SyzygySeq.new(@modu.ring.coFac).isZeroRelation( l, s ); t = System.currentTimeMillis() - t; puts "executed isSyzygy in #{t} ms\n"; return z; end =begin rdoc Compute syzygys of this module. =end def syzygy() l = @mset; t = System.currentTimeMillis(); p = SyzygySeq.new(@modu.ring.coFac).zeroRelations( l ); t = System.currentTimeMillis() - t; puts "executed module syzygy in #{t} ms\n"; m = CommutativeModule.new("",p.ring,p.cols); return SubModule.new(m,"",p.list); end end =begin rdoc Represents a JAS module over a solvable polynomial ring. Method to create solvable sub-modules. =end class SolvableModule < CommutativeModule # the Java polynomial ring, number of columns, module list attr_reader :ring, :cols, :mset =begin rdoc Solvable module constructor. =end def initialize(modstr="",ring=nil,cols=0) if ring == nil sr = StringReader.new( modstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextSolvablePolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #@mset = tok.nextSolvableSubModuleSet(); #if @mset.cols >= 0 # @cols = @mset.cols; #end @ring = pfac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end @mset = ModuleList.new(@ring,nil); if cols < 0 cols = 0; end @cols = cols; end =begin rdoc Create a string representation. =end def to_s() return @mset.toScript(); end =begin rdoc Create a solvable sub-module. =end def submodul(modstr="",list=nil) return SolvableSubModule.new(self,modstr,list); end =begin rdoc Create an element from a string. =end def element(mods) if not mods.is_a? String begin if @ring == mods.ring return RingElem.new(mods); end rescue => e # pass end mods = str(mods); end ii = SolvableSubModule.new( "( " + mods + " )"); list = ii.mset.list; if list.size > 0 return RingElem.new( list[0] ); end end end =begin rdoc Represents a JAS sub-module over a solvable polynomial ring. Methods to compute left, right and two-sided Groebner bases. =end class SolvableSubModule # the Java module, module list, number of columns and rows, module list attr_reader :modu, :mset, :cols, :rows, :list =begin rdoc Constructor for sub-module over a solvable polynomial ring. =end def initialize(modu,modstr="",list=nil) @modu = modu; if list == nil sr = StringReader.new( modstr ); tok = GenPolynomialTokenizer.new(modu.ring,sr); @list = tok.nextSolvableSubModuleList(); else if list.is_a? Array @list = rbarray2arraylist(list,@modu.ring,rec=2); else @list = list; end end @mset = OrderedModuleList.new(modu.ring,@list); @cols = @mset.cols; @rows = @mset.rows; end =begin rdoc Create a string representation. =end def to_s() return @mset.toScript(); # + "\n\n" + str(@pset); end =begin rdoc Compute a left Groebner base. =end def leftGB() t = System.currentTimeMillis(); #gg = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).leftGB(@mset); gg = SolvableGroebnerBaseSeq.new().leftGB(@mset); t = System.currentTimeMillis() - t; puts "executed left module GB in #{t} ms\n"; return SolvableSubModule.new(@modu,"",gg.list); end =begin rdoc Test if this is a left Groebner base. =end def isLeftGB() t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).isLeftGB(@mset); b = SolvableGroebnerBaseSeq.new().isLeftGB(@mset); t = System.currentTimeMillis() - t; puts "module isLeftGB executed in #{t} ms\n"; return b; end =begin rdoc Compute a two-sided Groebner base. =end def twosidedGB() t = System.currentTimeMillis(); #gg = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).twosidedGB(@mset); gg = SolvableGroebnerBaseSeq.new().twosidedGB(@mset); t = System.currentTimeMillis() - t; puts "executed twosided module GB in #{t} ms\n"; return SolvableSubModule.new(@modu,"",gg.list); end =begin rdoc Test if this is a two-sided Groebner base. =end def isTwosidedGB() t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).isTwosidedGB(@mset); b = SolvableGroebnerBaseSeq.new().isTwosidedGB(@mset); t = System.currentTimeMillis() - t; puts "module isTwosidedGB executed in #{t} ms\n"; return b; end =begin rdoc Compute a right Groebner base. =end def rightGB() t = System.currentTimeMillis(); #gg = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).rightGB(@mset); gg = SolvableGroebnerBaseSeq.new().rightGB(@mset); t = System.currentTimeMillis() - t; puts "executed right module GB in #{t} ms\n"; return SolvableSubModule.new(@modu,"",gg.list); end =begin rdoc Test if this is a right Groebner base. =end def isRightGB() t = System.currentTimeMillis(); #b = SolvableGroebnerBaseSeq.new(@modu.ring.coFac).isRightGB(@mset); b = SolvableGroebnerBaseSeq.new().isRightGB(@mset); t = System.currentTimeMillis() - t; puts "module isRightGB executed in #{t} ms\n"; return b; end =begin rdoc Test if this is a left syzygy of the vectors in g. =end def isLeftSyzygy(g) l = @list; if g.is_a? SolvIdeal s = g.pset.list; # not g.list else if g.is_a? SolvableSubModule s = g.mset; l = @mset; else raise "unknown type #{g.getClass().getName()}"; end end #puts "l = #{l}"; #puts "s = #{s}"; t = System.currentTimeMillis(); z = SolvableSyzygySeq.new(@modu.ring.coFac).isLeftZeroRelation( l, s ); t = System.currentTimeMillis() - t; puts "executed isLeftSyzygy in #{t} ms\n"; return z; end =begin rdoc Compute left syzygys of this module. =end def leftSyzygy() l = @mset; t = System.currentTimeMillis(); p = SolvableSyzygySeq.new(@modu.ring.coFac).leftZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; puts "executed left module syzygy in #{t} ms\n"; m = SolvableModule.new("",p.ring,p.cols); return SolvableSubModule.new(m,"",p.list); end =begin rdoc Test if this is a right syzygy of the vectors in g. =end def isRightSyzygy(g) l = @list; if g.is_a? SolvIdeal s = g.pset.list; # not g.list else if g.is_a? SolvableSubModule s = g.mset; l = @mset; else raise "unknown type #{g.getClass().getName()}"; end end #puts "l = #{l}"; #puts "s = #{s}"; t = System.currentTimeMillis(); z = SolvableSyzygySeq.new(@modu.ring.coFac).isRightZeroRelation( l, s ); t = System.currentTimeMillis() - t; puts "executed isRightSyzygy in #{t} ms\n"; return z; end =begin rdoc Compute right syzygys of this module. =end def rightSyzygy() l = @mset; t = System.currentTimeMillis(); #no: p = SolvableSyzygySeq.new(@modu.ring.coFac).rightZeroRelations( l ); p = SolvableSyzygySeq.new(@modu.ring.coFac).rightZeroRelationsArbitrary( l ); t = System.currentTimeMillis() - t; puts "executed right module syzygy in #{t} ms\n"; m = SolvableModule.new("",p.ring,p.cols); return SolvableSubModule.new(m,"",p.list); end end java_import "edu.jas.ps.UnivPowerSeries"; java_import "edu.jas.ps.UnivPowerSeriesRing"; java_import "edu.jas.ps.UnivPowerSeriesMap"; java_import "edu.jas.ps.Coefficients"; java_import "edu.jas.ps.MultiVarPowerSeries"; java_import "edu.jas.ps.MultiVarPowerSeriesRing"; java_import "edu.jas.ps.MultiVarPowerSeriesMap"; java_import "edu.jas.ps.MultiVarCoefficients"; java_import "edu.jas.ps.StandardBaseSeq"; =begin rdoc Represents a JAS power series ring: UnivPowerSeriesRing. Methods for univariate power series arithmetic. =end class SeriesRing # the Java polynomial ring attr_reader :ring =begin rdoc Ring constructor. =end def initialize(ringstr="",truncate=nil,ring=nil,cofac=nil,name="z") if ring == nil if ringstr.size > 0 sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #pset = tok.nextPolynomialSet(); ring = pfac; vname = ring.vars; name = vname[0]; cofac = ring.coFac; end if cofac.is_a? RingElem cofac = cofac.elem; end if truncate == nil @ring = UnivPowerSeriesRing.new(cofac,name); else @ring = UnivPowerSeriesRing.new(cofac,truncate,name); end else @ring = ring; end end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end =begin rdoc Get the generators of the power series ring. =end def gens() ll = @ring.generators(); nn = ll.map { |e| RingElem.new(e) }; return nn; end =begin rdoc Get the one of the power series ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the power series ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Get a random power series. =end def random(n) return RingElem.new( @ring.random(n) ); end =begin rdoc Get the exponential power series. =end def exp() return RingElem.new( @ring.getEXP() ); end =begin rdoc Get the sinus power series. =end def sin() return RingElem.new( @ring.getSIN() ); end =begin rdoc Get the cosinus power series. =end def cos() return RingElem.new( @ring.getCOS() ); end =begin rdoc Get the tangens power series. =end def tan() return RingElem.new( @ring.getTAN() ); end =begin rdoc (Inner) class which extends edu.jas.ps.Coefficients =end class Ucoeff < Coefficients =begin rdoc Constructor. ifunc(int i) must return a value which is used in ((RingFactory)cofac).fromInteger(). jfunc(int i) must return a value of type ring.coFac. =end def initialize(ifunc,jfunc,cofac=nil) #puts "ifunc = " + ifunc.to_s + ","; #puts "jfunc = " + jfunc.to_s + ","; #puts "cofac = " + cofac.to_s + ","; super(); if jfunc == nil && cofac == nil raise "invalid arguments" end @coFac = cofac; @ifunc = ifunc; @jfunc = jfunc; end =begin rdoc Generator for a coefficient. long i parameter. returns a value of type ring.coFac. =end def generate(i) if @jfunc == nil return @coFac.fromInteger( @ifunc.call(i) ); else return @jfunc.call(i); end end end =begin rdoc Create a power series with given generating function. ifunc(int i) must return a value which is used in RingFactory.fromInteger(). jfunc(int i) must return a value of type ring.coFac. clazz must implement the Coefficients abstract class. =end def create(ifunc,jfunc=nil,clazz=nil) if clazz == nil #puts "ifunc = " + ifunc.to_s + "."; #puts "jfunc = " + jfunc.to_s + "."; #puts "clazz = " + clazz.to_s + "."; cf = Ucoeff.new(ifunc,jfunc,@ring.coFac); #puts "cf = " + cf.to_s + "."; ps = UnivPowerSeries.new( @ring, cf ); else ps = UnivPowerSeries.new( @ring, clazz ); end return RingElem.new( ps ); end =begin rdoc Create a power series as fixed point of the given mapping. psmap must implement the UnivPowerSeriesMap interface. =end def fixPoint(psmap) ps = @ring.fixPoint( psmap ); return RingElem.new( ps ); end =begin rdoc Compute the greatest common divisor of a and b. =end def gcd(a,b) if a.is_a? RingElem a = a.elem; end if b.is_a? RingElem b = b.elem; end return RingElem.new( a.gcd(b) ); end =begin rdoc Convert a GenPolynomial to a power series. =end def fromPoly(a) if a.is_a? RingElem a = a.elem; end return RingElem.new( @ring.fromPolynomial(a) ); end end =begin rdoc Represents a JAS power series ring: MultiVarPowerSeriesRing. Methods for multivariate power series arithmetic. =end class MultiSeriesRing # the Java polynomial ring attr_reader :ring =begin rdoc Ring constructor. =end def initialize(ringstr="",truncate=nil,ring=nil,cofac=nil,names=nil) if ring == nil if ringstr.size > 0 sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); #tok = GenPolynomialTokenizer.new(sr); #pset = tok.nextPolynomialSet(); ring = pfac; names = ring.vars; cofac = ring.coFac; end if cofac.is_a? RingElem cofac = cofac.elem; end if names.is_a? String names = GenPolynomialTokenizer.variableList(names); end if truncate == nil @ring = MultiVarPowerSeriesRing.new(cofac,names); else nv = names.size; @ring = MultiVarPowerSeriesRing.new(cofac,names.size,truncate,names); end else @ring = ring; end end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end =begin rdoc Get the generators of the power series ring. =end def gens() ll = @ring.generators(); nn = ll.map { |e| RingElem.new(e) }; return nn; end =begin rdoc Get the one of the power series ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the power series ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Get a random power series. =end def random(n) return RingElem.new( @ring.random(n) ); end =begin rdoc Get the exponential power series, var r. =end def exp(r) return RingElem.new( @ring.getEXP(r) ); end =begin rdoc Get the sinus power series, var r. =end def sin(r) return RingElem.new( @ring.getSIN(r) ); end =begin rdoc Get the cosinus power series, var r. =end def cos(r) return RingElem.new( @ring.getCOS(r) ); end =begin rdoc Get the tangens power series, var r. =end def tan(r) return RingElem.new( @ring.getTAN(r) ); end =begin (Inner) class which extends edu.jas.ps.MultiVarCoefficients =end class Mcoeff < MultiVarCoefficients =begin Constructor ring must be a polynomial or multivariate power series ring. ifunc(ExpVector i) must return a value which is used in ((RingFactory)cofac).fromInteger(). jfunc(ExpVector i) must return a value of type ring.coFac. =end def initialize(ring,ifunc=nil,jfunc=nil) super(ring); @coFac = ring.coFac; @ifunc = ifunc; @jfunc = jfunc; end =begin rdoc Generator for a coefficient. long i parameter. returns a value of type ring.coFac. =end def generate(i) if @jfunc == nil return @coFac.fromInteger( @ifunc.call(i) ); else return @jfunc.call(i); end end end =begin rdoc Create a power series with given generating function. ifunc(ExpVector i) must return a value which is used in RingFactory.fromInteger(). jfunc(ExpVector i) must return a value of type ring.coFac. clazz must implement the MultiVarCoefficients abstract class. =end def create(ifunc=nil,jfunc=nil,clazz=nil) #puts "ifunc " #puts "jfunc " #puts "clazz " + str(clazz) if clazz == nil clazz = Mcoeff.new(@ring,ifunc,jfunc); end ps = MultiVarPowerSeries.new( @ring, clazz ); #puts "ps ", ps.toScript(); return RingElem.new( ps ); end =begin rdoc Create a power series as fixed point of the given mapping. psmap must implement the MultiVarPowerSeriesMap interface. =end def fixPoint(psmap) ps = @ring.fixPoint( psmap ); return RingElem.new( ps ); end =begin rdoc Compute the greatest common divisor of a and b. =end def gcd(a,b) if a.is_a? RingElem a = a.elem; end if b.is_a? RingElem b = b.elem; end return RingElem.new( a.gcd(b) ); end =begin rdoc Convert a GenPolynomial to a power series. =end def fromPoly(a) if a.is_a? RingElem a = a.elem; end return RingElem.new( @ring.fromPolynomial(a) ); end end =begin rdoc Represents a JAS power series ideal. Method for Standard bases. =end class PSIdeal # the Java powerseries ring, powerseries list attr_reader :ring, :list =begin rdoc PSIdeal constructor. =end def initialize(ring,polylist,ideal=nil,list=nil) if ring.is_a? Ring or ring.is_a? PolyRing ring = MultiVarPowerSeriesRing.new(ring.ring); elsif ring.is_a? MultiSeriesRing ring = ring.ring; end @ring = ring; #puts "ring = ", ring.toScript(); if ideal != nil polylist = ideal.pset.list; end if list == nil @polylist = rbarray2arraylist( polylist.map { |a| a.elem } ); #puts "polylist = ", @polylist; @list = @ring.fromPolynomial(@polylist); else @polylist = nil; @list = rbarray2arraylist( list.map { |a| a.elem } ); end end =begin rdoc Create a string representation. =end def to_s() return "( " + @list.map { |a| a.toScript() }.join(", ") + " )"; end =begin rdoc Compute a standard base. =end def STD(trunc=nil) pr = @ring; if trunc != nil pr.setTruncate(trunc); end #puts "pr = ", pr.toScript(); ff = @list; #puts "ff = ", ff; tm = StandardBaseSeq.new(); t = System.currentTimeMillis(); ss = tm.STD(ff); t = System.currentTimeMillis() - t; puts "sequential standard base executed in #{t} ms\n"; #Sp = [ RingElem.new(a.asPolynomial()) for a in S ]; sp = ss.map { |a| RingElem.new(a) }; #return sp; return PSIdeal.new(@ring,nil,nil,sp); end end =begin rdoc (Was interior) class which extends edu.jas.ps.Coefficients =end class Coeff < Coefficients =begin rdoc Constructor. cof RingFactory for coefficients. f(int i) must return a value of type cof. =end def initialize(cof,&f) super() # this is important in jruby 1.5.6! #puts "cof type(#{cof}) = #{cof.class}\n"; @coFac = cof; #puts "f type(#{f}) = #{f.class}\n"; @func = f end =begin rdoc Generator for a coefficient. long i parameter. returns a value of type cof. =end def generate(i) #puts "f_3 type(#{@func}) = #{@func.class}\n"; #puts "f_3 type(#{i}) = #{i.class}\n"; #return @coFac.getZERO() c = @func.call(i) #puts "f_3 type(#{c}) = #{c.class}\n"; if c.is_a? RingElem c = c.elem end return c end end =begin rdoc Create JAS UnivPowerSeries as ring element. =end def PS(cofac,name,truncate=nil,&f) #=nil,truncate=nil) cf = cofac; if cofac.is_a? RingElem cf = cofac.elem.factory(); end if cofac.is_a? Ring cf = cofac.ring; end if truncate.is_a? RingElem truncate = truncate.elem; end if truncate == nil ps = UnivPowerSeriesRing.new(cf,name); else ps = UnivPowerSeriesRing.new(cf,truncate,name); end #puts "ps type(#{ps}) = #{ps.class}\n"; #puts "f type(#{f}) = #{f.class}\n"; if f == nil r = ps.getZERO(); else #Bug in JRuby 1.5.6? move outside method r = UnivPowerSeries.new(ps,Coeff.new(cf,&f)); end return RingElem.new(r); end =begin rdoc (Was interior) class which extends edu.jas.ps.MultiVarCoefficients =end class MCoeff < MultiVarCoefficients =begin rdoc Constructor. r polynomial RingFactory. f(ExpVector e) must return a value of type r.coFac. =end def initialize(r,&f) super(r) # this is important in jruby 1.5.6! @coFac = r.coFac; @func = f end =begin rdoc Generator for a coefficient. ExpVector e parameter. returns a value of type r.coFac =end def generate(i) a = @func.call(i); if a.is_a? RingElem a = a.elem; end #puts "f_5 type(#{a}) = #{a.class}\n"; return a; end end =begin rdoc Create JAS MultiVarPowerSeries as ring element. =end def MPS(cofac,names,truncate=nil,&f) cf = cofac; if cofac.is_a? RingElem cf = cofac.elem.factory(); elsif cofac.is_a? Ring cf = cofac.ring; end vars = names; if vars.is_a? String vars = GenPolynomialTokenizer.variableList(vars); end nv = vars.size; if truncate.is_a? RingElem truncate = truncate.elem; end if truncate == nil ps = MultiVarPowerSeriesRing.new(cf,nv,vars); else ps = MultiVarPowerSeriesRing.new(cf,nv,vars,truncate); end if f == nil r = ps.getZERO(); else r = MultiVarPowerSeries.new(ps,MCoeff.new(ps,&f)); #puts "r = " + str(r); end return RingElem.new(r); end java_import "edu.jas.vector.GenVector"; java_import "edu.jas.vector.GenVectorModul"; java_import "edu.jas.vector.GenMatrix"; java_import "edu.jas.vector.GenMatrixRing"; java_import "edu.jas.vector.LinAlg"; java_import "edu.jas.vector.BasicLinAlg"; =begin rdoc Create JAS GenVector ring element. =end def Vec(cofac,n,v=nil) cf = cofac; if cofac.is_a? RingElem cf = cofac.elem.factory(); elsif cofac.is_a? Ring cf = cofac.ring; end if n.is_a? RingElem n = n.elem; end if v.is_a? RingElem v = v.elem; end if v.is_a? Array v = rbarray2arraylist(v,cf,rec=1); end vr = GenVectorModul.new(cf,n); if v == nil r = GenVector.new(vr); else r = GenVector.new(vr,v); end return RingElem.new(r); end =begin rdoc Create JAS GenMatrix ring element. =end def Mat(cofac,n,m,v=nil) cf = cofac; if cofac.is_a? RingElem cf = cofac.elem.factory(); elsif cofac.is_a? Ring cf = cofac.ring; end if n.is_a? RingElem n = n.elem; end if m.is_a? RingElem m = m.elem; end if v.is_a? RingElem v = v.elem; end #puts "cf type(#{cf}) = #{cf.class}"; if v.is_a? Array v = rbarray2arraylist(v,cf,rec=2); end mr = GenMatrixRing.new(cf,n,m); if v == nil r = GenMatrix.new(mr); else r = GenMatrix.new(mr,v); end return RingElem.new(r); end java_import "edu.jas.application.ExtensionFieldBuilder"; =begin rdoc Extension ring and field builder. Construction of extension ring and field towers using the builder pattern. =end class EF # the Java extension field builder attr_reader :builder =begin rdoc Constructor to set base field. =end def initialize(base) if base.is_a? RingElem #factory = base.elem; factory = base.ring; else factory = base; end begin factory = factory.factory(); rescue #pass end puts "extension field factory: " + factory.toScript(); # + " :: " + factory.toString(); if factory.is_a? ExtensionFieldBuilder @builder = factory; else @builder = ExtensionFieldBuilder.new(factory); end end =begin rdoc Create a string representation. =end def to_s() return @builder.toScript(); #return @builder.toString(); end =begin rdoc Create an extension field. If algebraic is given as string expression, then an algebraic extension field is constructed, else a transcendental extension field is constructed. =end def extend(vars,algebraic=nil) if algebraic == nil ef = @builder.transcendentExtension(vars); else if algebraic.is_a? Integer ef = @builder.finiteFieldExtension(algebraic); else ef = @builder.algebraicExtension(vars,algebraic); end end return EF.new(ef.build()); end =begin rdoc Create a real extension field. Construct a real algebraic extension field with an isolating interval for a real root. =end def realExtend(vars,algebraic,interval) ef = @builder.realAlgebraicExtension(vars,algebraic,interval); return EF.new(ef.build()); end =begin rdoc Create a complex extension field. Construct a complex algebraic extension field with an isolating rectangle for a complex root. =end def complexExtend(vars,algebraic,rectangle) ef = @builder.complexAlgebraicExtension(vars,algebraic,rectangle); return EF.new(ef.build()); end =begin rdoc Create a polynomial ring extension. =end def polynomial(vars) ef = @builder.polynomialExtension(vars); return EF.new(ef.build()); end =begin rdoc Create a matrix ring extension. =end def matrix(n) ef = @builder.matrixExtension(n); return EF.new(ef.build()); end =begin rdoc Get extension ring or field tower. =end def build() rf = @builder.build(); if rf.is_a? GenPolynomialRing return PolyRing.new(rf.coFac,rf.getVars(),rf.tord); else return Ring.new("", rf); end end end #------------------------------------ =begin rdoc Represents a JAS exterior vector / polynomial ring: GenExteriorPolynomialRing. =end class ExtRing < Ring #@auto_inject = true #@auto_lowervar = false #class << self # means add to class # # inject variables into environment # attr_accessor :auto_inject # # avoid capital letter variables # attr_accessor :auto_lowervar #end =begin rdoc Exterior form / vector / polynomial ring constructor. =end def initialize(ringstr="",ring=nil) #puts "ExtRing.new" if ring == nil #raise "parse of ext polynomial rings not implemented" sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); efac = GenExtPolynomialRing.new(pfac); @list = tok.nextExteriorPolynomialList(wfac); @ring = efac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end super("",@ring) #puts "ExtRing.new: self.class.auto_inject = " + self.class.auto_inject.to_s #inject_variables(); #puts "ExtRing.new: self.class.superclass.auto_inject = " + self.class.superclass.auto_inject.to_s end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); #.to_s; end #=begin rdoc #Create a exterior ideal. #=end # def ideal(ringstr="",list=nil) # return ExtPolyIdeal.new(self, ringstr, list); # end =begin rdoc Get the one of the exterior vector / polynomial ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the exterior vector / polynomial ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Get a random exterior vector / polynomial. =end def random(n=5) r = @ring.random(n); if @ring.coFac.isField() r = r.monic(); end return RingElem.new( r ); end =begin rdoc Get a random exterior vector / polynomial. =end def random(k=5,l=7,d=3) r = @ring.random(k,l,d); if @ring.coFac.isField() r = r.monic(); end return RingElem.new( r ); end =begin rdoc Create an element from a string or object. =end def element(poly) if not poly.is_a? String begin if @ring == poly.ring return RingElem.new(poly); end rescue => e # pass end poly = str(poly); end sr = StringReader.new(poly); tok = GenPolynomialTokenizer.new(sr); ep = tok.nextExteriorPolynomial(@ring); if ep != nil return RingElem.new( ep ); end end end =begin rdoc Represents a JAS exterior form / vector / polynomial ring: GenExteriorPolynomialRing. Provides more convenient constructor. Then returns a Ring. =end class ExtPolyRing < ExtRing @auto_inject = true @auto_lowervar = true class << self # means add to class # inject variables into environment attr_accessor :auto_inject # avoid capital letter variables attr_accessor :auto_lowervar end =begin rdoc Ring constructor. coeff = factory for coefficients, s = size of index list, var = string with one variable name. =end def initialize(coeff, s, var="E") #puts "ExtPolyRing.new" if coeff == nil raise ArgumentError, "No coefficient given." end cf = coeff; if coeff.is_a? RingElem cf = coeff.elem.factory(); end if coeff.is_a? Ring cf = coeff.ring; end if s == nil raise ArgumentError, "No variable size given." end names = var; if not var.is_a? String names = GenPolynomialTokenizer.variableList(var); end wf = IndexFactory.new(s, names); @ring = GenExteriorPolynomialRing.new(cf, wf); super("",@ring) #puts "ExtPolyRing.new: self.class.auto_inject = " + self.class.auto_inject.to_s #inject_variables(); #puts "ExtPolyRing.new: self.class.superclass.auto_inject = " + self.class.superclass.auto_inject.to_s end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end end #------------------------------------ =begin rdoc Represents a JAS non-commutative polynomial ring: GenWordPolynomialRing. Has a method to create non-commutative ideals. Note: watch your step: check that jruby does not reorder multiplication. =end class WordRing < Ring =begin rdoc Word polynomial ring constructor. =end def initialize(ringstr="",ring=nil) if ring == nil #raise "parse of word polynomial rings not implemented" sr = StringReader.new( ringstr ); tok = RingFactoryTokenizer.new(sr); pfac = tok.nextPolynomialRing(); wfac = GenWordPolynomialRing.new(pfac); #@list = tok.nextWordPolynomialList(wfac); @ring = wfac; else if ring.is_a? Ring @ring = ring.ring else @ring = ring; end end end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); #.to_s; end =begin rdoc Create a word ideal. =end def ideal(ringstr="",list=nil) return WordPolyIdeal.new(self, ringstr, list); end =begin rdoc Get the one of the word polynomial ring. =end def one() return RingElem.new( @ring.getONE() ); end =begin rdoc Get the zero of the word polynomial ring. =end def zero() return RingElem.new( @ring.getZERO() ); end =begin rdoc Get a random word polynomial. =end def random(n=5) r = @ring.random(n); if @ring.coFac.isField() r = r.monic(); end return RingElem.new( r ); end =begin rdoc Get a random word polynomial. =end def random(k=5,l=7,d=3) r = @ring.random(k,l,d); if @ring.coFac.isField() r = r.monic(); end return RingElem.new( r ); end =begin rdoc Create an element from a string or object. =end def element(poly) if not poly.is_a? String begin if @ring == poly.ring return RingElem.new(poly); end rescue => e # pass end poly = str(poly); end ii = WordPolyIdeal.new(self, "( " + poly + " )"); # should work list = ii.list; if list.size > 0 return RingElem.new( list[0] ); end end end =begin rdoc Represents a JAS non-commutative polynomial ring: GenWordPolynomialRing. Provides more convenient constructor. Then returns a Ring. Note: watch your step: check that jruby does not reorder multiplication. =end class WordPolyRing < WordRing =begin rdoc Ring constructor. coeff = factory for coefficients, vars = string with variable names. =end def initialize(coeff,vars) if coeff == nil raise ArgumentError, "No coefficient given." end cf = coeff; if coeff.is_a? RingElem cf = coeff.elem.factory(); end if coeff.is_a? Ring cf = coeff.ring; end if vars == nil raise ArgumentError, "No variable names given." end names = vars; if vars.is_a? String names = GenPolynomialTokenizer.variableList(vars); end wf = WordFactory.new(names); @ring = GenWordPolynomialRing.new(cf, wf); end =begin rdoc Create a string representation. =end def to_s() return @ring.toScript(); end end =begin rdoc Represents a JAS non-commutative polynomial ideal. Methods for two-sided Groebner bases and others. Note: watch your step: check that jruby does not reorder multiplication. =end class WordPolyIdeal # the Java word polynomial ring, word polynomial list, word ideal attr_reader :ring, :list, :ideal =begin rdoc Constructor for an ideal in a non-commutative polynomial ring. =end def initialize(ring,ringstr="",list=nil) @ring = ring; if list == nil #raise "parse of non-commutative polynomials not implemented" sr = StringReader.new( ringstr ); tok = GenPolynomialTokenizer.new(sr); @list = tok.nextWordPolynomialList(ring.ring); @ideal = WordIdeal.new(ring.ring, @list); else if list.is_a? WordIdeal @list = list.list; @ideal = list; else @list = rbarray2arraylist(list, rec=1); @ideal = WordIdeal.new(ring.ring, @list); end end end =begin rdoc Create a string representation. =end def to_s() # return "( " + @list.map{ |e| e.toScript() }.join(", ") + " )"; #return "( " + @list.map{ |e| e.toScript() }.join(",\n") + " )"; return @ideal.toScript(); end =begin rdoc Compute a two-sided Groebner base. =end def GB() return twosidedGB(); end =begin rdoc Compute a two-sided Groebner base. =end def twosidedGB() cofac = @ring.ring.coFac; kind = ""; t = System.currentTimeMillis(); if cofac.isField() or not cofac.isCommutative() gg = @ideal.GB(); kind = "field|nocom" else #puts "is ring: " + str(cofac.is_a? GenPolynomialRing) if cofac.is_a? GenPolynomialRing #and cofac.isCommutative() ff = @ideal.list; fg = WordGroebnerBasePseudoRecSeq.new(cofac).GB(ff); @ideal = WordIdeal.new(ring.ring, fg); kind = "pseudoRec" else ff = @ideal.list; fg = WordGroebnerBasePseudoSeq.new(cofac).GB(ff); @ideal = WordIdeal.new(ring.ring, fg); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "executed(#{kind}) twosidedGB in #{t} ms\n"; return self; end =begin rdoc Test if this is a two-sided Groebner base. =end def isGB() return isTwosidedGB(); end =begin rdoc Test if this is a two-sided Groebner base. =end def isTwosidedGB() cofac = @ring.ring.coFac; kind = ""; t = System.currentTimeMillis(); if cofac.isField() or not cofac.isCommutative() b = @ideal.isGB(); kind = "field|nocom" else if cofac.is_a? GenPolynomialRing ff = @ideal.list; b = WordGroebnerBasePseudoRecSeq.new(cofac).isGB(ff); kind = "pseudoRec" else ff = @ideal.list; b = WordGroebnerBasePseudoSeq.new(cofac).isGB(ff); kind = "pseudo" end end t = System.currentTimeMillis() - t; puts "isTwosidedGB(#{kind}) = #{b} executed in #{t} ms\n"; return b; end =begin rdoc Compare two ideals. =end def <=>(other) s = @ideal; o = other.ideal; return s.compareTo(o); end =begin rdoc Test if two ideals are equal. =end def ==(other) if not other.is_a? WordPolyIdeal return false; end s = @ideal; t = other.ideal; return s.equals(t); end =begin rdoc Compute the sum of this and the ideal. =end def sum(other) s = @ideal; t = other.ideal; nn = s.sum( t ); return WordPolyIdeal.new(@ring,"",nn); end end =begin rdoc Create JAS polynomial WordResidue as ring element. =end def WRC(ideal,r=0) if ideal == nil raise ArgumentError, "No ideal given." end if ideal.is_a? WordPolyIdeal #puts "ideal = " + str(ideal) + "\n"; #ideal = Java::EduJasApplication::WordIdeal.new(ideal.ring,ideal.list); ideal = ideal.ideal; #ideal.doGB(); end if not ideal.is_a? WordIdeal raise ArgumentError, "No word ideal given." end #puts "ideal.getList().get(0).ring.ideal = #{ideal.getList().get(0).ring.ideal}\n"; if ideal.getList().get(0).ring.is_a? WordResidueRing rc = WordResidueRing.new( ideal.getList().get(0).ring.ideal ); else rc = WordResidueRing.new(ideal); end if r.is_a? RingElem r = r.elem; end if r == 0 r = WordResidue.new(rc); else r = WordResidue.new(rc,r); end return RingElem.new(r); end # define some shortcuts # big integers ZZ = ZZ(); # big rational numbers QQ = QQ(); # complex big rational numbers CC = CC(); #generic complex numbers CR = CR(); #big decimal numbers DD = DD(); #no GF = GF(); end include JAS java-algebra-system-2.7.200/examples/katsura.py000066400000000000000000000010021445075545500213710ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring from jas import Ideal from edu.jas.gb import Katsura; # katsura examples knum = 4 tnum = 2; k = Katsura(knum); r = Ring( k.varList("Rat","G") ); #r = Ring.new( k.varList("Mod 23","G") ); print "Ring: " + str(r); print; ps = k.polyList(); f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.parGB(tnum); for th in range(tnum,0,-1): rg = f.parGB(th); #print "par Output:", rg; #print; rg = f.GB(); #print "seq Output:", rg; print; java-algebra-system-2.7.200/examples/katsura.rb000066400000000000000000000017351445075545500213610ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ require "examples/jas" java_import "edu.jas.gb.Katsura"; # katsura examples knum = 4; tnum = 2; k = Katsura.new(knum); r = Ring.new( k.varList("Rat","G") ); #r = Ring.new( k.varList("Mod 23","G") ); #r = Ring.new( k.varList("Mod 32003","G") ); #r = Ring.new( k.varList("Mod 536870909","G") ); #r = Ring.new( k.varList("Mod 4294967291","G") ); #r = Ring.new( k.varList("Mod 9223372036854775783","G") ); #r = Ring.new( k.varList("Mod 170141183460469231731687303715884105727","G") ); #r = Ring.new( k.varList("Mod 1152921504606846883","G") ); puts "Ring: " + str(r); puts; ps = k.polyList(); puts "ps : " + ps; puts; #exit(); f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #puts "Range: " + Range.new(tnum,2,-1).to_s; #puts "Range: " + (tnum...2).to_s; #puts; rg = f.parGB(tnum); for th in tnum.downto(2) do rg = f.parGB(th); #puts "par(#{th}) Output:" + rg.to_s; #puts; end rg = f.GB(); #puts "seq Output:", rg; puts; terminate(); java-algebra-system-2.7.200/examples/katsura10m.jas000066400000000000000000000060731445075545500220510ustar00rootroot00000000000000#Katsura equations for N = 10: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 #Mod 3 #Mod 23 Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 #Rat (u10,u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u10*u10 + u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 + u10*u10 - u0, u10*0 + u9*u10 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 + u10*u9 - u1, u10*0 + u9*0 + u8*u10 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 + u10*u8 - u2, u10*0 + u9*0 + u8*0 + u7*u10 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 + u10*u7 - u3, u10*0 + u9*0 + u8*0 + u7*0 + u6*u10 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 + u10*u6 - u4, u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*u10 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 + u10*u5 - u5, u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u10 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 + u10*u4 - u6, u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u10 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 + u10*u3 - u7, u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u10 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 + u10*u2 - u8, u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u10 + u0*u9 + u1*u8 + u2*u7 + u3*u6 + u4*u5 + u5*u4 + u6*u3 + u7*u2 + u8*u1 + u9*u0 + u10*u1 - u9, u10 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 + u10 - 1 ) java-algebra-system-2.7.200/examples/katsura11m.jas000066400000000000000000000067041445075545500220530ustar00rootroot00000000000000#Katsura equations for N = 11: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 Mod 3 #Mod 23 #Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 #Rat (u11,u10,u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u11*u11 + u10*u10 + u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 + u10*u10 + u11*u11 - u0, u11*0 + u10*u11 + u9*u10 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 + u10*u9 + u11*u10 - u1, u11*0 + u10*0 + u9*u11 + u8*u10 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 + u10*u8 + u11*u9 - u2, u11*0 + u10*0 + u9*0 + u8*u11 + u7*u10 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 + u10*u7 + u11*u8 - u3, u11*0 + u10*0 + u9*0 + u8*0 + u7*u11 + u6*u10 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 + u10*u6 + u11*u7 - u4, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*u11 + u5*u10 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 + u10*u5 + u11*u6 - u5, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*u11 + u4*u10 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 + u10*u4 + u11*u5 - u6, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u11 + u3*u10 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 + u10*u3 + u11*u4 - u7, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u11 + u2*u10 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 + u10*u2 + u11*u3 - u8, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u11 + u1*u10 + u0*u9 + u1*u8 + u2*u7 + u3*u6 + u4*u5 + u5*u4 + u6*u3 + u7*u2 + u8*u1 + u9*u0 + u10*u1 + u11*u2 - u9, u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u11 + u0*u10 + u1*u9 + u2*u8 + u3*u7 + u4*u6 + u5*u5 + u6*u4 + u7*u3 + u8*u2 + u9*u1 + u10*u0 + u11*u1 - u10, u11 + u10 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 + u10 + u11 - 1 ) java-algebra-system-2.7.200/examples/katsura12m.jas000066400000000000000000000075631445075545500220600ustar00rootroot00000000000000#Katsura equations for N = 12: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 Mod 3 #Mod 23 #Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 #Rat (u12,u11,u10,u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u12*u12 + u11*u11 + u10*u10 + u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 + u10*u10 + u11*u11 + u12*u12 - u0, u12*0 + u11*u12 + u10*u11 + u9*u10 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 + u10*u9 + u11*u10 + u12*u11 - u1, u12*0 + u11*0 + u10*u12 + u9*u11 + u8*u10 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 + u10*u8 + u11*u9 + u12*u10 - u2, u12*0 + u11*0 + u10*0 + u9*u12 + u8*u11 + u7*u10 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 + u10*u7 + u11*u8 + u12*u9 - u3, u12*0 + u11*0 + u10*0 + u9*0 + u8*u12 + u7*u11 + u6*u10 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 + u10*u6 + u11*u7 + u12*u8 - u4, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*u12 + u6*u11 + u5*u10 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 + u10*u5 + u11*u6 + u12*u7 - u5, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*u12 + u5*u11 + u4*u10 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 + u10*u4 + u11*u5 + u12*u6 - u6, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*u12 + u4*u11 + u3*u10 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 + u10*u3 + u11*u4 + u12*u5 - u7, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u12 + u3*u11 + u2*u10 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 + u10*u2 + u11*u3 + u12*u4 - u8, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u12 + u2*u11 + u1*u10 + u0*u9 + u1*u8 + u2*u7 + u3*u6 + u4*u5 + u5*u4 + u6*u3 + u7*u2 + u8*u1 + u9*u0 + u10*u1 + u11*u2 + u12*u3 - u9, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u12 + u1*u11 + u0*u10 + u1*u9 + u2*u8 + u3*u7 + u4*u6 + u5*u5 + u6*u4 + u7*u3 + u8*u2 + u9*u1 + u10*u0 + u11*u1 + u12*u2 - u10, u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u12 + u0*u11 + u1*u10 + u2*u9 + u3*u8 + u4*u7 + u5*u6 + u6*u5 + u7*u4 + u8*u3 + u9*u2 + u10*u1 + u11*u0 + u12*u1 - u11, u12 + u11 + u10 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 + u10 + u11 + u12 - 1 ) java-algebra-system-2.7.200/examples/katsura13m.jas000066400000000000000000000105111445075545500220440ustar00rootroot00000000000000#Katsura equations for N = 13: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 Mod 3 #Mod 23 #Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 #Rat (u13,u12,u11,u10,u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u13*u13 + u12*u12 + u11*u11 + u10*u10 + u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 + u10*u10 + u11*u11 + u12*u12 + u13*u13 - u0, u13*0 + u12*u13 + u11*u12 + u10*u11 + u9*u10 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 + u10*u9 + u11*u10 + u12*u11 + u13*u12 - u1, u13*0 + u12*0 + u11*u13 + u10*u12 + u9*u11 + u8*u10 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 + u10*u8 + u11*u9 + u12*u10 + u13*u11 - u2, u13*0 + u12*0 + u11*0 + u10*u13 + u9*u12 + u8*u11 + u7*u10 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 + u10*u7 + u11*u8 + u12*u9 + u13*u10 - u3, u13*0 + u12*0 + u11*0 + u10*0 + u9*u13 + u8*u12 + u7*u11 + u6*u10 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 + u10*u6 + u11*u7 + u12*u8 + u13*u9 - u4, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*u13 + u7*u12 + u6*u11 + u5*u10 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 + u10*u5 + u11*u6 + u12*u7 + u13*u8 - u5, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*u13 + u6*u12 + u5*u11 + u4*u10 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 + u10*u4 + u11*u5 + u12*u6 + u13*u7 - u6, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*u13 + u5*u12 + u4*u11 + u3*u10 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 + u10*u3 + u11*u4 + u12*u5 + u13*u6 - u7, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*u13 + u4*u12 + u3*u11 + u2*u10 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 + u10*u2 + u11*u3 + u12*u4 + u13*u5 - u8, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u13 + u3*u12 + u2*u11 + u1*u10 + u0*u9 + u1*u8 + u2*u7 + u3*u6 + u4*u5 + u5*u4 + u6*u3 + u7*u2 + u8*u1 + u9*u0 + u10*u1 + u11*u2 + u12*u3 + u13*u4 - u9, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u13 + u2*u12 + u1*u11 + u0*u10 + u1*u9 + u2*u8 + u3*u7 + u4*u6 + u5*u5 + u6*u4 + u7*u3 + u8*u2 + u9*u1 + u10*u0 + u11*u1 + u12*u2 + u13*u3 - u10, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u13 + u1*u12 + u0*u11 + u1*u10 + u2*u9 + u3*u8 + u4*u7 + u5*u6 + u6*u5 + u7*u4 + u8*u3 + u9*u2 + u10*u1 + u11*u0 + u12*u1 + u13*u2 - u11, u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u13 + u0*u12 + u1*u11 + u2*u10 + u3*u9 + u4*u8 + u5*u7 + u6*u6 + u7*u5 + u8*u4 + u9*u3 + u10*u2 + u11*u1 + u12*u0 + u13*u1 - u12, u13 + u12 + u11 + u10 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 + u10 + u11 + u12 + u13 - 1 ) java-algebra-system-2.7.200/examples/katsura14m.jas000066400000000000000000000115031445075545500220470ustar00rootroot00000000000000#Katsura equations for N = 13: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 Mod 3 #Mod 23 #Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 #Rat (u14,u13,u12,u11,u10,u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u14*u14 + u13*u13 + u12*u12 + u11*u11 + u10*u10 + u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 + u10*u10 + u11*u11 + u12*u12 + u13*u13 + u14*u14 - u0, u14*0 + u13*u14 + u12*u13 + u11*u12 + u10*u11 + u9*u10 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 + u10*u9 + u11*u10 + u12*u11 + u13*u12 + u14*u13 - u1, u14*0 + u13*0 + u12*u14 + u11*u13 + u10*u12 + u9*u11 + u8*u10 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 + u10*u8 + u11*u9 + u12*u10 + u13*u11 + u14*u12 - u2, u14*0 + u13*0 + u12*0 + u11*u14 + u10*u13 + u9*u12 + u8*u11 + u7*u10 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 + u10*u7 + u11*u8 + u12*u9 + u13*u10 + u14*u11 - u3, u14*0 + u13*0 + u12*0 + u11*0 + u10*u14 + u9*u13 + u8*u12 + u7*u11 + u6*u10 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 + u10*u6 + u11*u7 + u12*u8 + u13*u9 + u14*u10 - u4, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*u14 + u8*u13 + u7*u12 + u6*u11 + u5*u10 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 + u10*u5 + u11*u6 + u12*u7 + u13*u8 + u14*u9 - u5, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*u14 + u7*u13 + u6*u12 + u5*u11 + u4*u10 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 + u10*u4 + u11*u5 + u12*u6 + u13*u7 + u14*u8 - u6, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*u14 + u6*u13 + u5*u12 + u4*u11 + u3*u10 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 + u10*u3 + u11*u4 + u12*u5 + u13*u6 + u14*u7 - u7, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*u14 + u5*u13 + u4*u12 + u3*u11 + u2*u10 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 + u10*u2 + u11*u3 + u12*u4 + u13*u5 + u14*u6 - u8, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*u14 + u4*u13 + u3*u12 + u2*u11 + u1*u10 + u0*u9 + u1*u8 + u2*u7 + u3*u6 + u4*u5 + u5*u4 + u6*u3 + u7*u2 + u8*u1 + u9*u0 + u10*u1 + u11*u2 + u12*u3 + u13*u4 + u14*u5 - u9, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u14 + u3*u13 + u2*u12 + u1*u11 + u0*u10 + u1*u9 + u2*u8 + u3*u7 + u4*u6 + u5*u5 + u6*u4 + u7*u3 + u8*u2 + u9*u1 + u10*u0 + u11*u1 + u12*u2 + u13*u3 + u14*u4 - u10, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u14 + u2*u13 + u1*u12 + u0*u11 + u1*u10 + u2*u9 + u3*u8 + u4*u7 + u5*u6 + u6*u5 + u7*u4 + u8*u3 + u9*u2 + u10*u1 + u11*u0 + u12*u1 + u13*u2 + u14*u3 - u11, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u14 + u1*u13 + u0*u12 + u1*u11 + u2*u10 + u3*u9 + u4*u8 + u5*u7 + u6*u6 + u7*u5 + u8*u4 + u9*u3 + u10*u2 + u11*u1 + u12*u0 + u13*u1 + u14*u2 - u12, u14*0 + u13*0 + u12*0 + u11*0 + u10*0 + u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u14 + u0*u13 + u1*u12 + u2*u11 + u3*u10 + u4*u9 + u5*u8 + u6*u7 + u7*u6 + u8*u5 + u9*u4 + u10*u3 + u11*u2 + u12*u1 + u13*u0 + u14*u1 - u13, u14 + u13 + u12 + u11 + u10 + u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 + u10 + u11 + u12 + u13 + u14 - 1 ) java-algebra-system-2.7.200/examples/katsura2.jas000066400000000000000000000002431445075545500216060ustar00rootroot00000000000000#Katsura equations for N = 2: (u2,u1,u0) L ( u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 - u0, u2*0 + u1*u2 + u0*u1 + u1*u0 + u2*u1 - u1, u2 + u1 + u0 + u1 + u2 - 1 ) java-algebra-system-2.7.200/examples/katsura3.jas000066400000000000000000000004111445075545500216040ustar00rootroot00000000000000#Katsura equations for N = 3: (u3,u2,u1,u0) L ( u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 - u0, u3*0 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 - u1, u3*0 + u2*0 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 - u2, u3 + u2 + u1 + u0 + u1 + u2 + u3 - 1 ) java-algebra-system-2.7.200/examples/katsura4.jas000066400000000000000000000006171445075545500216150ustar00rootroot00000000000000#Katsura equations for N = 4: (u4,u3,u2,u1,u0) L ( u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 - u0, u4*0 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 - u1, u4*0 + u3*0 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 - u2, u4*0 + u3*0 + u2*0 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 - u3, u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 - 1 ) java-algebra-system-2.7.200/examples/katsura5.jas000066400000000000000000000010641445075545500216130ustar00rootroot00000000000000#Katsura equations for N = 5: (u5,u4,u3,u2,u1,u0) G ( u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 - u0, u5*0 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 - u1, u5*0 + u4*0 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 - u2, u5*0 + u4*0 + u3*0 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 - u3, u5*0 + u4*0 + u3*0 + u2*0 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 - u4, u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 - 1 ) java-algebra-system-2.7.200/examples/katsura5s.jas000066400000000000000000000010701445075545500217730ustar00rootroot00000000000000#Katsura equations for N = 5: (u0,u1,u2,u3,u4,u5) G|1| ( u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 - u0, u5*0 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 - u1, u5*0 + u4*0 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 - u2, u5*0 + u4*0 + u3*0 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 - u3, u5*0 + u4*0 + u3*0 + u2*0 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 - u4, u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 - 1 ) java-algebra-system-2.7.200/examples/katsura5w.jas000066400000000000000000000011011445075545500217720ustar00rootroot00000000000000#Katsura equations for N = 5: (u5,u4,u3,u2,u1,u0) W(1,1,1,2,2,1) ( u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 - u0, u5*0 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 - u1, u5*0 + u4*0 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 - u2, u5*0 + u4*0 + u3*0 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 - u3, u5*0 + u4*0 + u3*0 + u2*0 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 - u4, u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 - 1 ) java-algebra-system-2.7.200/examples/katsura6.jas000066400000000000000000000013701445075545500216140ustar00rootroot00000000000000#Katsura equations for N = 6: (u6,u5,u4,u3,u2,u1,u0) G ( u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 - u0, u6*0 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 - u1, u6*0 + u5*0 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 - u2, u6*0 + u5*0 + u4*0 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 - u3, u6*0 + u5*0 + u4*0 + u3*0 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 - u4, u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 - u5, u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 - 1 ) java-algebra-system-2.7.200/examples/katsura6w.jas000066400000000000000000000014101445075545500217760ustar00rootroot00000000000000#Katsura equations for N = 6: (u6,u5,u4,u3,u2,u1,u0) W(1,1,1,1,1,1,1) ( u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 - u0, u6*0 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 - u1, u6*0 + u5*0 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 - u2, u6*0 + u5*0 + u4*0 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 - u3, u6*0 + u5*0 + u4*0 + u3*0 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 - u4, u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 - u5, u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 - 1 ) java-algebra-system-2.7.200/examples/katsura7.jas000066400000000000000000000017331445075545500216200ustar00rootroot00000000000000#Katsura equations for N = 7: (u7,u6,u5,u4,u3,u2,u1,u0) G ( u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 - u0, u7*0 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 - u1, u7*0 + u6*0 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 - u2, u7*0 + u6*0 + u5*0 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 - u3, u7*0 + u6*0 + u5*0 + u4*0 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 - u4, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 - u5, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 - u6, u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 - 1 ) java-algebra-system-2.7.200/examples/katsura7i.jas000066400000000000000000000017351445075545500217730ustar00rootroot00000000000000#Katsura equations for N = 7: Z (u7,u6,u5,u4,u3,u2,u1,u0) G ( u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 - u0, u7*0 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 - u1, u7*0 + u6*0 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 - u2, u7*0 + u6*0 + u5*0 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 - u3, u7*0 + u6*0 + u5*0 + u4*0 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 - u4, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 - u5, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 - u6, u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 - 1 ) java-algebra-system-2.7.200/examples/katsura7m.jas000066400000000000000000000474461445075545500220100ustar00rootroot00000000000000#Katsura equations for N = 7: Mod 536870909 #Mod 1152921504606846883 #= 2^60-93 #Mod 170141183460469231731687303715884105727 = Mersenne prime 12 #Mod 359334085968622831041960188598043661065388726959079837 = Bell prime #Mod 1363005552434666078217421284621279933627102780881053358473 = Padovan Prime #Mod 1558877695141608507751098941899265975115403618621811951868598809164180630185566719 = Padovan Prime #Mod 1 11 = repunit primes #Mod 2 1111111111111111111 #Mod 3 11111111111111111111111 #Mod 4 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 #Mod 5 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 #Mod Mersenne primes #Mod 2^3217-1: 969 digits #Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 2^4253-1: 1281 digits #Mod 190797007524439073807468042969529173669356994749940177394741882673528979787005053706368049835514900244303495954950709725762186311224148828811920216904542206960744666169364221195289538436845390250168663932838805192055137154390912666527533007309292687539092257043362517857366624699975402375462954490293259233303137330643531556539739921926201438606439020075174723029056838272505051571967594608350063404495977660656269020823960825567012344189908927956646011998057988548630107637380993519826582389781888135705408653045219655801758081251164080554609057468028203308718724654081055323215860189611391296030471108443146745671967766308925858547271507311563765171008318248647110097614890313562856541784154881743146033909602737947385055355960331855614540900081456378659068370317267696980001187750995491090350108417050917991562167972281070161305972518044872048331306383715094854938415738549894606070722584737978176686422134354526989443028353644037187375385397838259511833166416134323695660367676897722287918773420968982326089026150031515424165462111337527431154890666327374921446276833564519776797633875503548665093914556482031482248883127023777039667707976559857333357013727342079099064400455741830654320379350833236245819348824064783585692924881021978332974949906122664421376034687815350484991 #Mod 2^9689-1: 2917 digits #Mod 4782202788054612029528392986600059097414971724022365008513345109918378950942662970278927686112707894586824720981524256319306585052676834087480834429433264797425893247623688331021633208954847354805799943341309825989013743806187109581043148680813778321530496715601563282624414040398143207622036272190408590790537203475256105564071579263867875240985573356522656108542128577321057879052328865035355873615679363655889925711574420153832091752422843046918811427400662135559303516853703976812686385750376227787949580582081831261725701003498206512329872677233489510953469375683037038373999696771585788905639115522613405495707184524158219208223766442059014593330657009722153962376853423770486138578089775621301167811299166407361746606697808186757966914671246073712904200588408923186387737887675292886953797066980967406053530122853539036965490224784924649007954898678503314655546475504501686187354866964374552614120640782949622452027788962138602665933147687696322089504278791624651519312327831756553779377194524673395819281486668576384019590720179413349582970319393884388810494546040342087536563628332152073181614300721769371426238517540520845214665313301183551962591849558938499025348780376716477073930634436840084468255937443451690315999349137664638968972614199015304906547819056227171224947070739716300953775743441307920501863532234466545645695774331885044978250148663467372130392099894852145190998232878772486650513010816769902892518719250066947215706536216248696240569256865554296221552211560427778662545936998801070186162601476474293459830183651273363462732675883060701410359254829149774339297173680765610959599911309189788238350131635672661435969218239977196933874395403996623675580528211207136396370858056051160781770985452576988032333812939272752101944629527490313835551985197095928885236415301789218675141014541203096191270934369039522098280317668942061325572349643638403056487349290884223786292887472231219032385281034091824306618947740727265524284893304474861454942076799041739447165838281671410435831206790501914527326287370339974707206016882562827404270170322606727980343479326425730091839813077719322455394763960606588214326603156141490740557698055166263044447583756711516490181193442236859424151843795389335765432129944054855345155859273424561825146813714720606287781021240923708021492298349635179527270302962970156927686511635050080407282674252362644695710769768866137302789313609674382719017385508484663373476120843567983065059558072935110637544240807350667082987233779768874938983584523095638996120616318634391967112086464384649470963230072729200912586147267999762496709852769503535733924416202657720741248683592202828983311140833923302433917797976990311425843619350936754483811194408812763388084204451804912454383884180800945275626668057628954763384641305107753773247082495804533355717481965025070819730466422826105697510564289798951182192885976352229053898948737614642139910911535864505818992696826225754111 #Mod 2^19937-1: 6002 digits #Mod 43154247973881626480552355163379198390539350432267115051652505414033306801376580911304513629318584665545269938257648835317902217334584413909528269154609168019007875343741396296801920114486480902661414318443276980300066728104984095451588176077132969843762134621790396391341285205627619600513106646376648615994236675486537480241964350295935168662363909047948347692313978301377820785712419054474332844529183172973242310888265081321626469451077707812282829444775022680488057820028764659399164766265200900561495800344054353690389862894061792872011120833614808447482913547328367277879565648307846909116945866230169702401260240187028746650033445774570315431292996025187780790119375902863171084149642473378986267503308961374905766340905289572290016038000571630875191373979555047468154333253474991046248132504516341796551470575481459200859472614836213875557116864445789750886277996487304308450484223420629266518556024339339190844368921018424844677042727664601852914925277280922697538426770257333928954401205465895610347658855386633902546289962132643282425748035786233580608154696546932563833327670769899439774888526687278527451002963059146963875715425735534475979734463100678367393327402149930968778296741391514599602374213629898720611431410402147238998090962818915890645693934483330994169632295877995848993366747014871763494805549996163051541225403465297007721146231355704081493098663065733677191172853987095748167816256084212823380168625334586431254034670806135273543270714478876861861983320777280644806691125713197262581763151313596429547763576367837019349835178462144294960757190918054625114143666384189433852576452289347652454631535740468786228945885654608562058042468987372436921445092315377698407168198376538237748614196207041548106379365123192817999006621766467167113471632715481795877005382694393400403061700457691135349187874888923429349340145170571716181125795888889277495426977149914549623916394014822985025331651511431278802009056808456506818877266609831636883884905621822262933986548645669080672191704740408891349835685662428063231198520436826329415290752972798343429446509992206368781367154091702655772727391329424277529349082600585884766523150957417077831910016168475685658673192860882070179760307269849987354836042371734660257694347235506301744118874141292438958141549100609752216882230887611431996472330842380137110927449483557815037586849644585749917772869926744218369621137675101083278543794081749094091043084096774144708436324279476892056200427227961638669149805489831121244676399931955371484012886360748706479568669048574782855217054740113945929622177502575565811067452201448981991968635965361551681273982740760138899638820318776303668762730157584640042798880691862640268612686180883874939573818125022279689930267446255773959542469831637863000171279227151406034129902181570659650532600775823677398182129087394449859182749999007223592423334567850671186568839186747704960016277540625331440619019129983789914712515365200336057993508601678807687568562377857095255541304902927192220184172502357124449911870210642694565061384919373474324503966267799038402386781686809962015879090586549423504699190743519551043722544515740967829084336025938225780730880273855261551972044075620326780624448803490998232161231687794715613405793249545509528052518010123087258778974115817048245588971438596754408081313438375502988726739523375296641615501406091607983229239827240614783252892479716519936989519187808681221191641747710902480633491091704827441228281186632445907145787138351234842261380074621914004818152386666043133344875067903582838283562688083236575482068479639546383819532174522502682372441363275765875609119783653298312066708217149316773564340379289724393986744139891855416612295739356668612658271234696438377122838998040199739078061443675415671078463404673702403777653478173367084844734702056866636158138003692253382209909466469591930161626097920508742175670306505139542860750806159835357541032147095084278461056701367739794932024202998707731017692582046210702212514120429322530431789616267047776115123597935404147084870985465426502772057300900333847905334250604119503030001704002887892941404603345869926367501355094942750552591581639980523190679610784993580896683299297681262442314008657033421868094551740506448829039207316711307695131892296593509018623094810557519560305240787163809219164433754514863301000915916985856242176563624771328981678548246297376249530251360363412768366456175077031977457534912806433176539995994343308118470147158712816149394421276614228262909950055746981053206610001560295784656616193252269412026831159508949671513845195883217147982748879261851417819979034417285598607727220866677680426090308754823803345446566305619241308374452754668143015487710877728011086004325892262259413968285283497045571062757701421761565262725153407407625405149931989494459106414660534305378576709862520049864880961144869258603473714363659194013962706366851389299692869491805172556818508298824954954815796063169517658741420159798754273428026723452481263569157307213153739781041627653715078598504154797287663122946711348158529418816432825044466692781137474494898385064375787507376496345148625306383391555145690087891955315994462944493235248817599907119135755933382121706191477185054936632211157222920331148502487563303118018805685073569841580518118710778653953571296014372940865270407021924383167290323231567912289419486240594039074452321678019381871219092155460768444573578559513613304242206151356457513937270939009707237827101245853837678338161023397586854894230696091540249987907453461311923963852950754758058205625956600817743007191746812655955021747670922460866747744520875607859062334750627098328593480067789456169602494392813763495657599847485773553990957557313200809040830036446492219409934096948730547494301216165686750735749555882340303989874672975455060957736921559195480815514035915707129930057027117286252843197413312307617886797506784260195436760305990340708481464607278955495487742140753570621217198252192978869786916734625618430175454903864111585429504569920905636741539030968041471 #Mod 43154247973881626480552355163379198390539350432267115051652505414033306801376580911304513629318584665545269938257648835317902217334584413909528269154609168019007875343741396296801920114486480902661414318443276980300066728104984095451588176077132969843762134621790396391341285205627619600513106646376648615994236675486537480241964350295935168662363909047948347692313978301377820785712419054474332844529183172973242310888265081321626469451077707812282829444775022680488057820028764659399164766265200900561495800344054353690389862894061792872011120833614808447482913547328367277879565648307846909116945866230169702401260240187028746650033445774570315431292996025187780790119375902863171084149642473378986267503308961374905766340905289572290016038000571630875191373979555047468154333253474991046248132504516341796551470575481459200859472614836213875557116864445789750886277996487304308450484223420629266518556024339339190844368921018424844677042727664601852914925277280922697538426770257333928954401205465895610347658855386633902546289962132643282425748035786233580608154696546932563833327670769899439774888526687278527451002963059146963875715425735534475979734463100678367393327402149930968778296741391514599602374213629898720611431410402147238998090962818915890645693934483330994169632295877995848993366747014871763494805549996163051541225403465297007721146231355704081493098663065733677191172853987095748167816256084212823380168625334586431254034670806135273543270714478876861861983320777280644806691125713197262581763151313596429547763576367837019349835178462144294960757190918054625114143666384189433852576452289347652454631535740468786228945885654608562058042468987372436921445092315377698407168198376538237748614196207041548106379365123192817999006621766467167113471632715481795877005382694393400403061700457691135349187874888923429349340145170571716181125795888889277495426977149914549623916394014822985025331651511431278802009056808456506818877266609831636883884905621822262933986548645669080672191704740408891349835685662428063231198520436826329415290752972798343429446509992206368781367154091702655772727391329424277529349082600585884766523150957417077831910016168475685658673192860882070179760307269849987354836042371734660257694347235506301744118874141292438958141549100609752216882230887611431996472330842380137110927449483557815037586849644585749917772869926744218369621137675101083278543794081749094091043084096774144708436324279476892056200427227961638669149805489831121244676399931955371484012886360748706479568669048574782855217054740113945929622177502575565811067452201448981991968635965361551681273982740760138899638820318776303668762730157584640042798880691862640268612686180883874939573818125022279689930267446255773959542469831637863000171279227151406034129902181570659650532600775823677398182129087394449859182749999007223592423334567850671186568839186747704960016277540625331440619019129983789914712515365200336057993508601678807687568562377857095255541304902927192220184172502357124449911870210642694565061384919373474324503966267799038402386781686809962015879090586549423504699190743519551043722544515740967829084336025938225780730880273855261551972044075620326780624448803490998232161231687794715613405793249545509528052518010123087258778974115817048245588971438596754408081313438375502988726739523375296641615501406091607983229239827240614783252892479716519936989519187808681221191641747710902480633491091704827441228281186632445907145787138351234842261380074621914004818152386666043133344875067903582838283562688083236575482068479639546383819532174522502682372441363275765875609119783653298312066708217149316773564340379289724393986744139891855416612295739356668612658271234696438377122838998040199739078061443675415671078463404673702403777653478173367084844734702056866636158138003692253382209909466469591930161626097920508742175670306505139542860750806159835357541032147095084278461056701367739794932024202998707731017692582046210702212514120429322530431789616267047776115123597935404147084870985465426502772057300900333847905334250604119503030001704002887892941404603345869926367501355094942750552591581639980523190679610784993580896683299297681262442314008657033421868094551740506448829039207316711307695131892296593509018623094810557519560305240787163809219164433754514863301000915916985856242176563624771328981678548246297376249530251360363412768366456175077031977457534912806433176539995994343308118470147158712816149394421276614228262909950055746981053206610001560295784656616193252269412026831159508949671513845195883217147982748879261851417819979034417285598607727220866677680426090308754823803345446566305619241308374452754668143015487710877728011086004325892262259413968285283497045571062757701421761565262725153407407625405149931989494459106414660534305378576709862520049864880961144869258603473714363659194013962706366851389299692869491805172556818508298824954954815796063169517658741420159798754273428026723452481263569157307213153739781041627653715078598504154797287663122946711348158529418816432825044466692781137474494898385064375787507376496345148625306383391555145690087891955315994462944493235248817599907119135755933382121706191477185054936632211157222920331148502487563303118018805685073569841580518118710778653953571296014372940865270407021924383167290323231567912289419486240594039074452321678019381871219092155460768444573578559513613304242206151356457513937270939009707237827101245853837678338161023397586854894230696091540249987907453461311923963852950754758058205625956600817743007191746812655955021747670922460866747744520875607859062334750627098328593480067789456169602494392813763495657599847485773553990957557313200809040830036446492219409934096948730547494301216165686750735749555882340303989874672975455060957736921559195480815514035915707129930057027117286252843197413312307617886797506784260195436760305990340708481464607278955495487742140753570621217198252192978869786916734625618430175454903864111585429504569920905636741539030968041471 (u0,u1,u2,u3,u4,u5,u6,u7) G ( u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 - u0, u7*0 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 - u1, u7*0 + u6*0 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 - u2, u7*0 + u6*0 + u5*0 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 - u3, u7*0 + u6*0 + u5*0 + u4*0 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 - u4, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 - u5, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 - u6, u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 - 1 ) java-algebra-system-2.7.200/examples/katsura8.jas000066400000000000000000000023351445075545500216200ustar00rootroot00000000000000#Katsura equations for N = 8: (u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 - u0, u8*0 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 - u1, u8*0 + u7*0 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 - u2, u8*0 + u7*0 + u6*0 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 - u3, u8*0 + u7*0 + u6*0 + u5*0 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 - u4, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 - u5, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 - u6, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 - u7, u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 - 1 ) java-algebra-system-2.7.200/examples/katsura8m.jas000066400000000000000000000046521445075545500220010ustar00rootroot00000000000000#Katsura equations for N = 8: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 #Mod 23 Mod 32003 #Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 (u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 - u0, u8*0 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 - u1, u8*0 + u7*0 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 - u2, u8*0 + u7*0 + u6*0 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 - u3, u8*0 + u7*0 + u6*0 + u5*0 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 - u4, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 - u5, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 - u6, u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 - u7, u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 - 1 ) java-algebra-system-2.7.200/examples/katsura9m.jas000066400000000000000000000053121445075545500217740ustar00rootroot00000000000000#Katsura equations for N = 9: #Mod 2^127-1: 39 digits, Mersenne prime 12: Mod 170141183460469231731687303715884105727 #Mod 2^3217-1: 969 digits Mersenne prime 18: Mod 259117086013202627776246767922441530941818887553125427303974923161874019266586362086201209516800483406550695241733194177441689509238807017410377709597512042313066624082916353517952311186154862265604547691127595848775610568757931191017711408826252153849035830401185072116424747461823031471398340229288074545677907941037288235820705892351068433882986888616658650280927692080339605869308790500409503709875902119018371991620994002568935113136548829739112656797303241986517250116412703509705427773477972349821676443446668383119322540099648994051790241624056519054483690809616061625743042361721863339415852426431208737266591962061753535748892894599629195183082621860853400937932839420261866586142503251450773096274235376822938649407127700846077124211823080804139298087057504713825264571448379371125032081826126566649084251699453951887789613650248405739378594599444335231188280123660406262468609212150349937584782292237144339628858485938215738821232393687046160677362909315071 #Mod 170141183460469231731687303715884105727 #Mod 23 #Mod 32003 Mod 536870909 #Mod 4294967291 #Mod 9223372036854775783 (u9,u8,u7,u6,u5,u4,u3,u2,u1,u0) G ( u9*u9 + u8*u8 + u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 + u8*u8 + u9*u9 - u0, u9*0 + u8*u9 + u7*u8 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 + u8*u7 + u9*u8 - u1, u9*0 + u8*0 + u7*u9 + u6*u8 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 + u8*u6 + u9*u7 - u2, u9*0 + u8*0 + u7*0 + u6*u9 + u5*u8 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 + u8*u5 + u9*u6 - u3, u9*0 + u8*0 + u7*0 + u6*0 + u5*u9 + u4*u8 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 + u8*u4 + u9*u5 - u4, u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*u9 + u3*u8 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 + u8*u3 + u9*u4 - u5, u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*u9 + u2*u8 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 + u8*u2 + u9*u3 - u6, u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u9 + u1*u8 + u0*u7 + u1*u6 + u2*u5 + u3*u4 + u4*u3 + u5*u2 + u6*u1 + u7*u0 + u8*u1 + u9*u2 - u7, u9*0 + u8*0 + u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u9 + u0*u8 + u1*u7 + u2*u6 + u3*u5 + u4*u4 + u5*u3 + u6*u2 + u7*u1 + u8*u0 + u9*u1 - u8, u9 + u8 + u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 + u8 + u9 - 1 ) java-algebra-system-2.7.200/examples/katsura_opt.py000066400000000000000000000030631445075545500222640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, QQ, GF from jas import startLog # example katsura, optimize term order # optimal is (u1, u2, u3, u4, u5, u6, u0, u7) # better is (u7,u6,u5,u4,u3,u2,u1,u0) #r = Ring( "Mod 13 (u0,u1,u2,u3,u4,u5,u6,u7) G" ); #r = Ring( "Rat (u7,u6,u5,u4,u3,u2,u1,u0) G" ); r = Ring( "Mod 5 (u7,u6,u5,u4,u3,u2,u1,u0) G" ); print "Ring: " + str(r); print; ps = """ ( u7*u7 + u6*u6 + u5*u5 + u4*u4 + u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 + u4*u4 + u5*u5 + u6*u6 + u7*u7 - u0, u7*0 + u6*u7 + u5*u6 + u4*u5 + u3*u4 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 + u4*u3 + u5*u4 + u6*u5 + u7*u6 - u1, u7*0 + u6*0 + u5*u7 + u4*u6 + u3*u5 + u2*u4 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 + u4*u2 + u5*u3 + u6*u4 + u7*u5 - u2, u7*0 + u6*0 + u5*0 + u4*u7 + u3*u6 + u2*u5 + u1*u4 + u0*u3 + u1*u2 + u2*u1 + u3*u0 + u4*u1 + u5*u2 + u6*u3 + u7*u4 - u3, u7*0 + u6*0 + u5*0 + u4*0 + u3*u7 + u2*u6 + u1*u5 + u0*u4 + u1*u3 + u2*u2 + u3*u1 + u4*u0 + u5*u1 + u6*u2 + u7*u3 - u4, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*u7 + u1*u6 + u0*u5 + u1*u4 + u2*u3 + u3*u2 + u4*u1 + u5*u0 + u6*u1 + u7*u2 - u5, u7*0 + u6*0 + u5*0 + u4*0 + u3*0 + u2*0 + u1*u7 + u0*u6 + u1*u5 + u2*u4 + u3*u3 + u4*u2 + u5*u1 + u6*u0 + u7*u1 - u6, u7 + u6 + u5 + u4 + u3 + u2 + u1 + u0 + u1 + u2 + u3 + u4 + u5 + u6 + u7 - 1 ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; startLog(); o = f.optimize(); print "optimized Ideal: " + str(o); print; rg = f.GB(); print "Output:", rg; print; #org = o.GB(); #print "opt Output:", org; #print; java-algebra-system-2.7.200/examples/kw_18.jas000066400000000000000000000002741445075545500210070ustar00rootroot00000000000000# solvable polynomials, example 1.8 from KW: (x,y,z) L RelationTable ( ( y ), ( x ), ( x y + x ), ( z ), ( y ), ( y z + z ) ) ( ( y**3 + x**2 y + x y ), ( x**2 + z ), ( z**2 + z ) ) java-algebra-system-2.7.200/examples/legendre.py000066400000000000000000000014751445075545500215220ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, QQ from jas import startLog, terminate from edu.jas.arith import BigRational # Legendre polynomial example # P(0) = 1 # P(1) = x # P(n) = 1/n [ (2n-1) * x * P(n-1) - (n-1) * P(n-2) ] r = PolyRing( QQ(), "x", PolyRing.lex ); #r = Ring( "Q(x) L" ); #r = Ring( "C(x) L" ); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring #auto: [one,x] = r.gens(); N = 10; P = [one,x]; for n in range(2,N): p = (2*n-1) * x * P[n-1] - (n-1) * P[n-2]; r = (1,n); # no rational numbers in python #r = [(1,n)]; # no complex rational numbers in python #r = ((1,n),(0,1)); # no complex rational numbers in python p = r * p; P.append( p ); for n in range(0,N): print "P[%s] = %s" % (n,P[n]); print; java-algebra-system-2.7.200/examples/legendre.rb000066400000000000000000000010311445075545500214610ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ require "examples/jas" # Legendre polynomial example # P(0) = 1 # P(1) = x # P(n) = 1/n [ (2n-1) * x * P(n-1) - (n-1) * P(n-2) ] r = PolyRing.new( QQ(), "x", PolyRing.lex ); #r = Ring.new( "C(x) L" ); puts "Ring: " + str(r); puts; # sage like: with generators for the polynomial ring #auto: one,x = r.gens(); N = 10; P = [one,x]; for n in 2...N do p = (2*n-1) * x * P[n-1] - (n-1) * P[n-2]; p = 1/n * p; P << p; #.monic(); end for n in 0...N do puts "P[#{n}] = #{P[n]}"; end puts; java-algebra-system-2.7.200/examples/lewis.py000066400000000000000000000031501445075545500210500ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, RF, ZZ, ZM, GF from jas import startLog, terminate #startLog(); # Lewis example # integral function coefficients #r = Ring( "IntFunc(a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3) (t1,t2,t3) G" ); #r = Ring( "RatFunc(a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3) (t1,t2,t3) G" ); #r = PolyRing( RF(PolyRing(ZZ(),"a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3",PolyRing.lex)), "t1,t2,t3", PolyRing.grad ); #r = PolyRing( RF(PolyRing(GF(163),"a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3",PolyRing.grad)), "t1,t2,t3", PolyRing.grad ); r = PolyRing( PolyRing(GF(163),"a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3",PolyRing.grad), "t1,t2,t3", PolyRing.grad ); #no: r = PolyRing( RF(PolyRing(GF(5),"a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,e1,e2,e3",PolyRing.grad)), "t1,t2,t3", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( { a1 } * t1^2 * t2^2 + { b1 } * t1^2 + { 2 c1 } * t1 * t2 + { d1 } * t2^2 + { e1 } ), ( { a2 } * t2^2 * t3^2 + { b2 } * t2^2 + { 2 c2 } * t2 * t3 + { d2 } * t3^2 + { e2 } ), ( { a3 } * t1^2 * t3^2 + { b3 } * t1^2 + { 2 c3 } * t1 * t3 + { d3 } * t3^2 + { e3 } ) ) """; #a1 = e2 + s22 #+ s27 #- s25 #- 2e * s2 + 2e * s7 - 2s2 * s7 f = r.ideal( ps ); print "ParamIdeal: " + str(f); print; # is optimized #o = f.optimize(); #print "optimized Ideal: " + str(o); #print; #p = o.paramideal(); #p = p.optimizeCoeffQuot(); #print "optimized coeff Ideal: " + str(p); #print; sys.exit(); startLog(); rg = f.GB(); #rg = f.GB(); print "GB:", rg; print; #bg = rg.isGB(); #print "isGB:", bg; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/lie_field.rb000066400000000000000000000034461445075545500216240ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Lie field example, Apel + Lassner, 1987 r = PolyRing.new(QQ(),"q,p"); #is automatic: [one,p,q] = p.gens(); relations = [p, q, q * p + 1 ]; puts "relations: = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "q,p", PolyRing.lex, relations); puts "SolvPolyRing: " + str(rp); puts; puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #is automatic: one,x,y,z,t = rp.gens(); f1 = p * ( q * p - 1 ); f2 = q * p * p; f3 = ( q * p - 1 ) * q; f4 = q * q * p; f5 = f2 - f1; f6 = f3 - f4; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts "f4 = " + str(f4); puts "f5 = " + str(f5); puts "f6 = " + str(f6); puts ff = [ f1, f2, f3, f4 ]; #ff = [ f1 ]; puts "ff = [" + ff.join(", ") { |r| r.to_s } + "]"; puts ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts; scp = SRF(rp, p); puts "SolvableQuotient: " + str(scp); puts "SolvableQuotient: " + str(scp / scp); puts; scq = SRF(rp, q); scqi = 1 / scq; #scqi = SRF(rp,one) / scq; puts "SolvableQuotient: " + str(scq); puts "SolvableQuotient: " + str(scqi); puts "SolvableQuotient: " + str(scqi * scq); puts "SolvableQuotient: " + str(scq * scqi); puts; sca = SRF(rp, p**2, q*p+2); scb = SRF(rp, q*p-1, q**2); puts "SolvableQuotient: " + str(sca); puts "SolvableQuotient: " + str(scb); puts "SolvableQuotient: " + str(sca == scb); puts "SolvableQuotient: " + str(sca - scb); puts; terminate(); java-algebra-system-2.7.200/examples/linalg.py000066400000000000000000000030741445075545500212000ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Mat, Vec, QQ, GF, DD, RingElem from jas import terminate #from edu.jas.arith import BigRational # example for linear algebra # # p = 11 N = 6; r = Mat(QQ(),N,N); #r = Mat(GF(p),N,N); #print "r = " + str(r); print "r.factory() = " + str(r.factory()); #print; #print r.gens().map{ |g| str(g) + ", " }; #print; v = Vec(QQ(),N); #v = Vec(GF(p),N); #print "v = " + str(v); print "v.factory() = " + str(v.factory()); print; #print v.gens().map{ |g| str(g) + ", " }; #print; #print "one: " + str(r.one); #print "zero: " + str(r.zero); #print; #print "zero: " + str(v.zero); #print; a = r.random(11); print "a: " + str(a); b = v.random(7); print "b: " + str(b); c = a * b; print "c: " + str(c); x = a.solve(c); print "x: " + str(x); print "x == b: " + str(x == b); print; L, U, P = a.decompLU(); print "P: " + str(P); print; if P.elem.size() != 0: print "L: " + str(L); print; print "U: " + str(U); print; Us = RingElem(a.elem.getUpperScaled()); print "scale(U): " + str(Us); print; x = a.solveLU(P, c); print "x: " + str(x); print "x == b: " + str(x == b); print; d = a.determinant(P) print "det(A): " + str(d) + " ~= " + str(d.elem.getDecimal()); #print "det(A): " + str(d) + " ~= " + str(d.elem.getSymmetricVal()); print; r = Mat(QQ(), 2*N, N); a = r.random(11); #print "b: " + str(b); B = a.rowEchelon(); print "B: " + str(B); print "rank(B): " + str(B.rank()); #print "B: " + str(B); print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/linalg.rb000066400000000000000000000026021445075545500211470ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example for linear algebra # # p = 11 N = 6; r = Mat(QQ(),N,N); #r = Mat(GF(p),N,N); #puts "r = " + str(r); puts "r.factory() = " + str(r.factory()); #puts; #puts r.gens().map{ |g| str(g) + ", " }; #puts; v = Vec(QQ(),N); #v = Vec(GF(p),N); #puts "v = " + str(v); puts "v.factory() = " + str(v.factory()); puts; #puts v.gens().map{ |g| str(g) + ", " }; #puts; #puts "one: " + str(r.one); #puts "zero: " + str(r.zero); #puts; #puts "zero: " + str(v.zero); #puts; a = r.random(11); puts "a: " + str(a); b = v.random(7); puts "b: " + str(b); c = a * b; puts "c: " + str(c); x = a.solve(c); puts "x: " + str(x); puts "x == b: " + str(x == b); puts; L, U, P = a.decompLU(); puts "P: " + str(P); puts; if P.elem.size() != 0 puts "L: " + str(L); puts; puts "U: " + str(U); puts; Us = RingElem.new(a.elem.getUpperScaled()); puts "scale(U): " + str(Us); puts; x = a.solveLU(P, c); puts "x: " + str(x); puts "x == b: " + str(x == b); puts; d = a.determinant(P) puts "det(A): " + str(d) + " ~= " + str(d.elem.getDecimal()); #puts "det(A): " + str(d) + " ~= " + str(d.elem.getSymmetricVal()); puts; end r = Mat(QQ(),N,N+2); A = r.random(11); #puts "A: " + str(A); B = A.rowEchelon(); puts "B: " + str(B); puts "rank(B): " + str(B.rank()); #puts "B: " + str(B); puts; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/logic.py000066400000000000000000000010171445075545500210220ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring, PolyRing, GF # logic example from Kreutzer JdM 2008 #r = Ring( "Mod 2 (a,f,p,u) G" ); r = PolyRing( GF(2), "(a,f,p,u)", PolyRing.grad ); print "Ring: " + str(r); print; ks = """ ( ( a^2 - a ), ( f^2 - f ), ( p^2 - p ), ( u^2 - u ) ) """; ps = """ ( ( p f + p ), ( p u + p + u + 1 ), ( a + u + 1 ), ( a + p + 1 ) ) """; k = r.ideal( ks ); p = r.ideal( ps ); f = k.sum( p ); print "Ideal: " + str(f); print; rg = f.GB(); print "Output:", rg; print; java-algebra-system-2.7.200/examples/logic.rb000066400000000000000000000010121445075545500207700ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # logic example from Kreutzer JdM 2008 #r = Ring.new( "Mod 2 (a,f,p,u) G" ); r = PolyRing.new( GF(2), "(a,f,p,u)", PolyRing.grad ); puts "Ring: " + str(r); puts; ks = """ ( ( a^2 - a ), ( f^2 - f ), ( p^2 - p ), ( u^2 - u ) ) """; ps = """ ( ( p f + p ), ( p u + p + u + 1 ), ( a + u + 1 ), ( a + p + 1 ) ) """; k = r.ideal( ks ); p = r.ideal( ps ); f = k.sum( p ); puts "Ideal: " + str(f); puts; rg = f.GB(); puts "Output:" + str(rg); puts; java-algebra-system-2.7.200/examples/machines.localhost000066400000000000000000000004141445075545500230540ustar00rootroot00000000000000# maschines file for jas for junit tests localhost:4712 # first host is master on different local port localhost:4711 # second host with port #localhost:4711 # third host with port #localhost:4711 # last host with port #localhost:4711 # ignored host # eof java-algebra-system-2.7.200/examples/machines.test000066400000000000000000000004121445075545500220410ustar00rootroot00000000000000# maschines file for jas for junit tests localhost:4712 # first host is master on different local port localhost:4711 # second host with port localhost:4711 # third host with port localhost:4711 # last host with port #localhost:4711 # ignored host # eof java-algebra-system-2.7.200/examples/mark.py000066400000000000000000000011461445075545500206620ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #import sys; from jas import Ring, PolyRing, ZZ from jas import startLog # mark, d-gb diplom example r = PolyRing( ZZ(), "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( z + x y**2 + 4 x**2 + 1 ), ( y**2 z + 2 x + 1 ), ( x**2 z + y**2 + x ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); eg = f.eGB(); print "seq e-GB:", eg; print "is e-GB:", eg.isGB(); print; dg = f.dGB(); print "seq d-GB:", dg; print "is d-GB:", dg.isGB(); print; print "d-GB == e-GB:", eg.list.equals(dg.list); print "d-GB == e-GB:", eg == dg; java-algebra-system-2.7.200/examples/mark.rb000066400000000000000000000012001445075545500206240ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # mark, d-gb diplom example r = PolyRing.new( ZZ(), "x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( z + x y**2 + 4 x**2 + 1 ), ( y**2 z + 2 x + 1 ), ( x**2 z + y**2 + x ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #startLog(); eg = f.eGB(); puts "seq e-GB: " + str(eg); puts "is e-GB: " + str(eg.isGB()); puts; dg = f.dGB(); puts "seq d-GB: " + str(dg); puts "is d-GB: " + str(dg.isGB()); puts; puts "d-GB == e-GB: " + str(eg.list.equals(dg.list)); puts "d-GB == e-GB: " + str(eg<=>dg); puts "d-GB == e-GB: " + str(eg===dg); puts java-algebra-system-2.7.200/examples/mark_kr.py000066400000000000000000000024441445075545500213600ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #import sys; from jas import Ring, PolyRing, ZZ from jas import startLog # mark, d-gb diplom example, due to kandri-rody 1984 # # The MAS DIIPEGB implementation contains an error because the output e-GB # is not correct. Also the cited result from k-r contains this error. # The polynomial # # ( 2 x * y^2 - x^13 + 2 x^11 - x^9 + 2 x^7 - 2 x^3 ), # # is in the DIIPEGB output, but it must be # # ( 2 x * y^2 - x^13 + 2 x^11 - 3 x^9 + 2 x^7 - 2 x^3 ), # # Test by adding the polynomials to the input. # Frist polynomial produces a different e-GB. # Second polynomial reproduces the e-GB with the second polynomial. #r = Ring( "Z(x,y) L" ); r = PolyRing( ZZ(), "x,y", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( y**6 + x**4 y**4 - x**2 y**4 - y**4 - x**4 y**2 + 2 x**2 y**2 + x**6 - x**4 ), ( 2 x**3 y**4 - x y**4 - 2 x**3 y**2 + 2 x y**2 + 3 x**5 - 2 x** 3 ), ( 3 y**5 + 2 x**4 y**3 - 2 x**2 y**3 - 2 y**3 - x**4 y + 2 x**2 y ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); eg = f.eGB(); print "seq e-GB:", eg; print "is e-GB:", eg.isGB(); print; #startLog(); dg = f.dGB(); print "seq d-GB:", dg; print "is d-GB:", dg.isGB(); print; print "d-GB == e-GB:", eg.list.equals(dg.list); print "d-GB == e-GB:", eg == dg; java-algebra-system-2.7.200/examples/mark_kr.rb000066400000000000000000000023441445075545500213320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # mark, d-gb diplom example, due to kandri-rody 1984 # # The MAS DIIPEGB implementation contains an error because the output e-GB # is not correct. Also the cited result from k-r contains this error. # The polynomial # # ( 2 x * y^2 - x^13 + 2 x^11 - x^9 + 2 x^7 - 2 x^3 ), # # is in the DIIPEGB output, but it must be # # ( 2 x * y^2 - x^13 + 2 x^11 - 3 x^9 + 2 x^7 - 2 x^3 ), # # Test by adding the polynomials to the input. # Frist polynomial produces a different e-GB. # Second polynomial reproduces the e-GB with the second polynomial. #r = Ring.new( "Z(x,y) L" ); r = PolyRing.new( ZZ(), "x,y", PolyRing.lex ); puts "Ring: " + str(r); puts; ps = """ ( ( y**6 + x**4 y**4 - x**2 y**4 - y**4 - x**4 y**2 + 2 x**2 y**2 + x**6 - x**4 ), ( 2 x**3 y**4 - x y**4 - 2 x**3 y**2 + 2 x y**2 + 3 x**5 - 2 x** 3 ), ( 3 y**5 + 2 x**4 y**3 - 2 x**2 y**3 - 2 y**3 - x**4 y + 2 x**2 y ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #startLog(); eg = f.eGB( ); puts "seq e-GB: " + str(eg); puts "is e-GB: " + str(eg.isGB()); puts; #startLog(); dg = f.dGB(); puts "seq d-GB: " + str(dg); puts "is d-GB: " + str(dg.isGB()); puts; puts "d-GB == e-GB: "+ str(eg===dg); puts java-algebra-system-2.7.200/examples/mkplot.py000066400000000000000000000344571445075545500212510ustar00rootroot00000000000000# # read output of jas GB runs and prepare input for gnuplot # $Id$ # from sys import argv from sys import exit from time import strftime import re; import os from os import system hpat = re.compile(r'(m|d) = (\d+), ppn = (\d+), time = (\d+) milliseconds, (\d+) start-up'); dpat = re.compile(r'(m|d) = (\d+), time = (\d+) milliseconds, (\d+) start-up'); #hpat = re.compile(r'd = (\d+), ppn = (\d+), time = (\d+) milliseconds, (\d+) start-up'); #dpat = re.compile(r'd = (\d+), time = (\d+) milliseconds, (\d+) start-up'); ppat = re.compile(r'time = (\d+) milliseconds'); fpat = re.compile(r'p = (\d+), time = (\d+) milliseconds'); spat = re.compile(r'seq,'); ####fpat = re.compile(r'_p(\d+)\.'); ####spat = re.compile(r'_s\.'); #r0pat = re.compile(r'Pairlist\(#put=(\d+), #rem=(\d+), size=(\d+)\)'); rpat = re.compile(r'Pairlist\(#put=(\d+), #rem=(\d+)\)'); ####r1pat = re.compile(r'pairlist #put = (\d+) #rem = (\d+)'); res = {}; pairs = None; hybrid = False; dist = False; para = False; for fname in argv[1:]: dn = -1; print "file =", fname f = open(fname,"r"); for line in f: pm = rpat.search(line); # pairlist results if pm: print "pair: ", line, np = pm.group(1); nr = pm.group(2); if pairs == None: pairs = ( np, nr ); #print "put = " + np + ", rem = " + nr; continue; ## pm = r0pat.search(line); # pairlist results ## if pm: ## print "pair0: ", line, ## np = pm.group(1); ## nr = pm.group(2); ## if pairs != None: ## pairs = ( np, nr ); ## #print "put = " + np + ", rem = " + nr; ## continue; ma = hpat.search(line); # distributed hybrid results if ma: print "h: ", line, d_h = ma.group(1) print "d_h: ", d_h, dn = int( ma.group(2) ); pp = int( ma.group(3) ); tm = long( ma.group(4) ); su = long( ma.group(5) ); hybrid = True; if not dn in res: res[ dn ] = {}; if pp in res[ dn ]: if 't' in res[ dn ][ pp ]: tx = res[ dn ][ pp ][ 't' ]; if tx < tm: # minimum or maximum tm = tx; su = res[ dn ][ pp ][ 's' ] if 'p' in res[ dn ][ pp ] or 'r' in res[ dn ][ pp ]: pairs = ( res[ dn ][ pp ]['p'], res[ dn ][ pp ]['r'] ); res[ dn ][ pp ] = { 't': tm, 's': su }; if pairs != None: res[ dn ][ pp ]['p'] = pairs[0]; res[ dn ][ pp ]['r'] = pairs[1]; pairs = None; continue; ma = dpat.search(line); # distributed results if ma: print "d: ", line, d_h = ma.group(1) print "d_h: ", d_h, dn = int( ma.group(2) ); pp = 1; tm = long( ma.group(3) ); su = long( ma.group(4) ); dist = True; if not dn in res: res[ dn ] = {}; if pp in res[ dn ]: if 't' in res[ dn ][ pp ]: tx = res[ dn ][ pp ][ 't' ]; if tx < tm: # minimum or maximum tm = tx; su = res[ dn ][ pp ][ 's' ] if 'p' in res[ dn ][ pp ] or 'r' in res[ dn ][ pp ]: pairs = ( res[ dn ][ pp ]['p'], res[ dn ][ pp ]['r'] ); res[ dn ][ pp ] = { 't': tm, 's': su }; if pairs != None: res[ dn ][ pp ]['p'] = pairs[0]; res[ dn ][ pp ]['r'] = pairs[1]; pairs = None; continue; ma = ppat.search(line); # parallel and sequential results if ma: print "p: ", line, tm = long( ma.group(1) ); fm = fpat.search(line); if fm: #print fname dn = 1; pp = int( fm.group(1) ); para = True; else: sm = spat.search(line); if sm: dn = 1; pp = 0; else: print "invalid: ", line, dn = -1; pp = -1; if not dn in res: res[ dn ] = {}; if pp in res[ dn ]: if 't' in res[ dn ][ pp ]: tx = res[ dn ][ pp ][ 't' ]; if tx < tm: # minimum or maximum tm = tx; if 'p' in res[ dn ][ pp ] or 'r' in res[ dn ][ pp ]: pairs = ( res[ dn ][ pp ]['p'], res[ dn ][ pp ]['r'] ); res[ dn ][ pp ] = { 't': tm, 's': '0' }; if pairs != None: res[ dn ][ pp ]['p'] = pairs[0]; res[ dn ][ pp ]['r'] = pairs[1]; pairs = None; print "\nres = ", res; ks = res.keys(); #print "ks = ", ks; ks.sort(); print "ks = ", ks; kpp = []; for d in ks: kdd = res[d].keys(); for dd in kdd: if dd not in kpp: kpp.append(dd); kpp.sort(); print "kpp = ", kpp; for d in ks: rd = res[d].keys(); rd.sort(); for p in rd: print " " + str(d) + "," + str(p) + " & " + str(res[d][p]['t']) + " & " + str(res[d][p]['s']) s1 = ks[0]; if s1 == 0: rxx = res.keys(); rxr = rxx[1]; rk = res[rxr].keys(); rk.sort(); p1 = rk[0]; st = int( res[ rxr ][ p1 ]['t'] ); else: rk = res[s1].keys(); rk.sort(); p1 = rk[0]; st = int( res[ s1 ][ p1 ]['t'] ); print "s1 = ", s1; print "p1 = ", p1; print "st = ", st; speed = {}; for k in ks: speed[k] = {}; rk = res[k].keys(); rk.sort(); for p in rk: speed[k][p] = st / float(res[k][p]['t']); print "speed = ", speed; bname = "kat_"; tag = argv[1]; bname = tag; i = tag.find("/"); if i >= 0: bname = tag[:i]; i = bname.find(".out"); if i >= 0: bname = tag[:i]; print "bname = " + bname; # LaTex output: summary = "\n% run = " + tag + "\n"; summary += r"\begin{tabular}{|r|r|r|r|r|r|}" + "\n"; summary += r"\hline" + "\n"; summary += " nodes & ppn & time & speedup & put & rem \n"; summary += r"\\ \hline" + "\n"; for d in ks: rd = res[d].keys(); rd.sort(); for p in rd: #if res[d][p]['s'] != "0": # summary += " " + str(d) + " & " + str(p) + " & " + str(res[d][p]['t']) + " & " + str(res[d][p]['s']) + " & " + str(speed[d][p])[:4]; #else: # summary += " " + str(d) + " & " + str(p) + " & " + str(res[d][p]['t']) + " & " + " & " + str(speed[d][p])[:4]; summary += " " + str(d) + " & " + str(p) + " & " + str(res[d][p]['t']) + " & " + str(speed[d][p])[:4]; if 'p' in res[d][p] and 'r' in res[d][p]: summary += " & " + str(res[d][p]['p']) + " & " + str(res[d][p]['r']) + "\n" else: summary += " & " + " & " + "\n" summary += r"\\ \hline" + "\n"; summary += r"\end{tabular}" + "\n"; print summary; tname = bname+".tex"; tt=open(tname,"w"); tt.write(summary); tt.close(); # output for 2-d gnuplot: oname = bname+".po"; o=open(oname,"w"); ploting = "\n#nodes #ppn time speedup ideal\n"; for k in ks: rk = res[k].keys(); rk.sort(); for p in rk: ideals = k*p; if ideals == 0: ideals = 1; ploting += str(k) + " " + str(p) + " " + str(res[k][p]['t']) + " " + str(speed[k][p]) + " " + str(ideals) + "\n"; ploting += "\n"; print ploting; o.write(ploting); o.close(); # output for 1-d gnuplot, colums for nodes: oname = bname+"_p.po"; o=open(oname,"w"); ploting = "\n#ppn time p, time d1, time d2, ... \n"; for p in kpp: ploting += str(p); for k in ks: #print "p = " + str(p) + ", k = " + str(k) if res[k]: if p in res[k]: #ploting += " " + str(float(res[k][p]['t'])/1000.0); ploting += " " + str(speed[k][p]); else: ploting += " -"; ploting += "\n"; #ploting += "\n"; print ploting; o.write(ploting); o.close(); # output for 1-d gnuplot, colums for ppn: oname = bname+"_d.po"; o=open(oname,"w"); ploting = "\n#nodes time ppn1, time ppn2, time ppn3, ... \n"; for k in ks: ploting += str(k); for p in kpp: #print "p = " + str(p) + ", k = " + str(k) if res[k]: if p in res[k]: #ploting += " " + str(float(res[k][p]['t'])/1000.0); ploting += " " + str(speed[k][p]); else: ploting += " -"; ploting += "\n"; #ploting += "\n"; print ploting; o.write(ploting); o.close(); #exit(); #--------------------------------------- pscript_2d = """ set grid set terminal x11 set title "Groebner bases on a grid cluster, distributed hybrid version" set time set xlabel "number of nodes" set ylabel "threads per node" set xrange [0:7] set yrange [0:7] #reverse #set clip two set xtics 1.0 set ytics 1.0 set style data lines #set contour base #set surface #set pm3d set dgrid3d set hidden3d set multiplot set size 0.95,0.95 #set size 0.95,0.5 #set origin 0,0.5 set origin 0,0 set datafile missing "-" ##set zlabel "milliseconds" set zlabel "seconds" splot "%s.po" using 1:2:($3/1000) title '%s computing time', "%s.po" using 1:2:( (%s/1000)/($1*$2) ) every ::2 title '%s ideal' #set size 0.95,0.45 #set origin 0,0 #set zlabel "speedup" #splot "%s.po" using 1:2:4 title '%s speedup', "%s.po" using 1:2:(($1*$2)) title '%s ideal' ## every ::2 start from the second line ## smooth acsplines ##with linespoints ##with linespoints ## smooth bezier unset multiplot pause mouse set terminal postscript set output "%s.ps" replot """ #--------------------------------------- #--------------------------------------- pscript_1d = """ set grid set terminal x11 set title "Groebner bases on a grid cluster, distributed version" set time set xlabel "number of nodes" #set xrange [0:8] set xtics 1.0 set style data lines set multiplot set size 0.95,0.5 set origin 0,0.5 #set origin 0,0 ##set ylabel "milliseconds" set ylabel "seconds" # smooth acsplines plot "%s.po" using 1:($3/1000) title '%s computing time', "%s.po" using 1:( (%s/1000)/($5) ) title '%s ideal' #set size 0.95,0.45 set origin 0,0 set ylabel "speedup" # smooth bezier plot "%s.po" using 1:4 title '%s speedup', "%s.po" using 1:(($5)) title '%s ideal' #with linespoints #with linespoints unset multiplot pause mouse set terminal postscript set output "%s.ps" replot """ #--------------------------------------- #--------------------------------------- pscript_1p = """ set grid set terminal x11 set title "Groebner bases on a multi-core computer" set time set xlabel "number of threads" #set xrange [0:8] set xtics 1.0 set style data lines set multiplot set size 0.95,0.5 set origin 0,0.5 #set origin 0,0 ##set ylabel "milliseconds" set ylabel "seconds" # smooth acsplines plot "%s.po" using 2:($3/1000) title '%s computing time', "%s.po" using 2:( (%s/1000)/($5) ) title '%s ideal' #set size 0.95,0.45 set origin 0,0 set ylabel "speedup" # smooth bezier plot "%s.po" using 2:4 title '%s speedup', "%s.po" using 2:(($5)) title '%s ideal' #with linespoints #with linespoints unset multiplot pause mouse set terminal postscript set output "%s.ps" replot """ #--------------------------------------- #--------------------------------------- pscript_d = """ set grid set terminal x11 set title "Groebner bases on a grid cluster, distributed hybrid version" set time set xlabel "number of threads" #set xrange [0:8] set xtics 1.0 set style data lines #set multiplot #set size 0.95,0.5 #set origin 0,0.5 set origin 0,0 ##set ylabel "milliseconds" #set ylabel "seconds" set ylabel "speedup" # smooth acsplines plot "%s.po" using 1:2 title '%s, parallel, n = 1',\ "%s.po" using 1:3 title 'distributed, n = 2',\ "%s.po" using 1:4 title 'distributed, n = 3',\ "%s.po" using 1:5 title 'distributed, n = 4',\ "%s.po" using 1:6 title 'distributed, n = 5',\ "%s.po" using 1:7 title 'distributed, n = 6',\ "%s.po" using 1:8 title 'distributed, n = 7' #with linespoints #unset multiplot pause mouse set terminal postscript set output "%s.ps" replot """ #--------------------------------------- #--------------------------------------- pscript_dp = """ set grid set terminal x11 set title "Groebner bases on a grid cluster, distributed hybrid version" set time set xlabel "number of nodes" #set xrange [0:8] set xtics 1.0 set style data lines #set multiplot #set size 0.95,0.5 #set origin 0,0.5 set origin 0,0 ##set ylabel "milliseconds" #set ylabel "seconds" set ylabel "speedup" # smooth acsplines # 1:2 ignored plot "%s.po" using 1:3 title '%s, ppn = 1',\ "%s.po" using 1:4 title 'ppn = 2',\ "%s.po" using 1:5 title 'ppn = 3',\ "%s.po" using 1:6 title 'ppn = 4',\ "%s.po" using 1:7 title 'ppn = 5',\ "%s.po" using 1:8 title 'ppn = 6',\ "%s.po" using 1:9 title 'ppn = 7',\ "%s.po" using 1:10 title 'ppn = 8' #with linespoints #unset multiplot pause mouse set terminal postscript set output "%s.ps" replot """ #--------------------------------------- exam = bname; psname = bname + ".ps"; pname = "plotin.gp" p=open(pname,"w"); print p; sqt = st; print "seq time = ", sqt; #print "args: %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s. " % ("x11",bname,exam,bname,str(sqt),exam,bname,exam,bname,exam,bname); hyb2d = False; #hyb2d = True t2n = True; # thread to nodes #t2n = False if hybrid: if hyb2d: pscript = pscript_2d % (bname,exam,bname,str(sqt),exam,bname,exam,bname,exam,bname); else: if t2n: oname = bname+"_p"; pscript = pscript_d % (oname,exam,oname,oname,oname,oname,oname,oname,bname); else: oname = bname+"_d"; pscript = pscript_dp % (oname,exam,oname,oname,oname,oname,oname,oname,oname,bname); else: if dist: pscript = pscript_1d % (bname,exam,bname,bname,str(sqt),exam,bname,exam,bname,exam); else: if para: pscript = pscript_1p % (bname,exam,bname,bname,str(sqt),exam,bname,exam,bname,exam); p.write(pscript); p.close(); cmd = "gnuplot " + pname; print "cmd: " + cmd; os.system(cmd); # convert to pdf, better use pstopdf, embed all fonts #cmd = "ps2pdf " + psname; cmd = "epstopdf --autorotate=All --embed " + psname; print "cmd: " + cmd; os.system(cmd); java-algebra-system-2.7.200/examples/mkplotold.py000066400000000000000000000067071445075545500217450ustar00rootroot00000000000000# # read output of jas runnings and prepare input for gnuplot # import re; import os; exam = "kat_6"; runs = "t16"; #bname = exam + "_" + runs; bname = "k6seqpair-3" fname = bname + ".out"; oname = bname + ".po"; f=open(fname,"r"); print f; o=open(oname,"w"); print o; res = {}; resold = {}; for line in f: if line.find("executed in") > 0: print line, if line.find("sequential") >= 0: s = re.search(".*in (\d+)",line); if s != None: t = ('0', s.group(1)); res[ int( t[0] ) ] = float( t[1] ); resold[ int( t[0] ) ] = float( t[1] ); else: if line.find("-old") >= 0: s = re.search("(\d+).*in (\d+)",line); if s != None: t = s.groups(); t0 = int( t[0] ); if resold.has_key( t0 ): resold[ t0 ] = ( resold[ t0 ] + float(t[1]) )/2.0; else: resold[ t0 ] = float( t[1] ); else: s = re.search("(\d+).*in (\d+)",line); if s != None: t = s.groups(); t0 = int( t[0] ); if res.has_key( t0 ): res[ t0 ] = ( res[ t0 ] + float(t[1]) )/2.0; else: res[ t0 ] = float( t[1] ); # print "t = ", t, "\n"; print "\nres = ", res; print "resold = ", resold; ks = res.keys(); #print "ks = ", ks; ks.sort(); #print "ks = ", ks; s1 = ks[0]; st = res[ s1 ]; #print "s1 = ", s1; #print "st = ", st; kso = resold.keys(); #print "kso = ", kso; kso.sort(); #print "kso = ", kso; s1o = kso[0]; sto = resold[ s1o ]; #print "s1o = ", s1o; #print "sto = ", sto; speed = {}; speedold = {}; for k in ks: speed[ k ] = st / res[ k ]; for k in kso: speedold[ k ] = sto / resold[ k ]; print "speed = ", speed; print "speedold = ", speedold; print; o.write("\n#threads time speedup timeold speedupold\n"); print "#threads time speedup timeold speedupold"; for k in ks: o.write(str(k) + " " + str(res[k]) + " " + str(speed[k]) + " " + str(resold[k]) + " " + str(speedold[k]) +"\n"); print(str(k) + " " + str(res[k]) + " " + str(speed[k]) + " " + str(resold[k]) + " " + str(speedold[k])); f.close(); o.close(); #--------------------------------------- pscript = """ set grid set term %s set output "%s.ps" set title "GBs of Katsuras example on compute" set time set xlabel "#CPUs" set multiplot set size 0.75,0.5 set origin 0,0.5 set ylabel "milliseconds" # smooth acsplines plot "%s.po" title '%s computing time' with linespoints, \ "%s.po" using 1:4 title '%s-old computing time' with linespoints, \ "%s.po" using 1:( %s/$1 ) title '%s ideal' with linespoints set size 0.75,0.5 set origin 0,0 set ylabel "speedup" # smooth bezier plot "%s.po" using 1:3 title '%s speedup' with linespoints, \ "%s.po" using 1:5 title '%s-old speedup' with linespoints, \ "%s.po" using 1:1 title '%s ideal' with linespoints unset multiplot pause mouse """; #--------------------------------------- psname = bname + ".ps"; pname = "plotin.gp" p=open(pname,"w"); print p; pscript = pscript % ("x11",bname,bname,exam,bname,exam,bname,str(res[0]),exam,bname,exam,bname,exam,bname,exam); #pscript = pscript % ("postscript",bname,bname,exam,bname,exam,bname,str(res[0]),exam,bname,exam,bname,exam,bname,exam); p.write(pscript); p.close(); os.system("gnuplot plotin.gp"); cmd = "ps2pdf " + psname; print "cmd: " + cmd; #os.system(cmd); java-algebra-system-2.7.200/examples/mkplotold2.py000066400000000000000000000055001445075545500220150ustar00rootroot00000000000000# # read output of jas runnings and prepare input for gnuplot # import re; import os; exam = "kat_6"; runs = "t16"; #bname = exam + "_" + runs; bname = "k6seqpair-2" fname = bname + ".out"; oname = bname + ".po"; f=open(fname,"r"); print f; o=open(oname,"w"); print o; res = {}; resold = {}; for line in f: if line.find("executed in") > 0: print line, if line.find("sequential") >= 0: s = re.search(".*in (\d+)",line); if s != None: t = ('0', s.group(1)); res[ int( t[0] ) ] = float( t[1] ); else: if line.find("-old") >= 0: s = re.search("(\d+).*in (\d+)",line); if s != None: t = s.groups(); t0 = int( t[0] ); if resold.has_key( t0 ): resold[ t0 ] = ( resold[ t0 ] + float(t[1]) )/2.0; else: resold[ t0 ] = float( t[1] ); else: s = re.search("(\d+).*in (\d+)",line); if s != None: t = s.groups(); t0 = int( t[0] ); if res.has_key( t0 ): res[ t0 ] = ( res[ t0 ] + float(t[1]) )/2.0; else: res[ t0 ] = float( t[1] ); # print "t = ", t, "\n"; print "\nres = ", res; ks = res.keys(); #print "ks = ", ks; ks.sort(); #print "ks = ", ks; s1 = ks[0]; st = res[ s1 ]; #print "s1 = ", s1; #print "st = ", st; speed = {}; speedold = {}; for k in ks: speed[ k ] = st / res[ k ]; #print "speed = ", speed; print; o.write("\n#threads time speedup\n"); print "#threads time speedup"; for k in ks: o.write(str(k) + " " + str(res[k]) + " " + str(speed[k]) +"\n"); print(str(k) + " " + str(res[k]) + " " + str(speed[k])); f.close(); o.close(); #--------------------------------------- pscript = """ set grid set term %s set output "%s.ps" set title "GBs of Katsuras example on compute" set time set xlabel "#CPUs" set multiplot set size 0.75,0.5 set origin 0,0.5 set ylabel "milliseconds" # smooth acsplines plot "%s.po" title '%s computing time' with linespoints, \ "%s.po" using 1:( %s/$1 ) title '%s ideal' with linespoints set size 0.75,0.5 set origin 0,0 set ylabel "speedup" # smooth bezier plot "%s.po" using 1:3 title '%s speedup' with linespoints, \ "%s.po" using 1:1 title '%s ideal' with linespoints unset multiplot pause mouse """; #--------------------------------------- psname = bname + ".ps"; pname = "plotin.gp" p=open(pname,"w"); print p; pscript = pscript % ("x11",bname,bname,exam,bname,str(res[0]),exam,bname,exam,bname,exam); #pscript = pscript % ("postscript",bname,bname,exam,bname,str(res[0]),exam,bname,exam,bname,exam); p.write(pscript); p.close(); os.system("gnuplot plotin.gp"); cmd = "ps2pdf " + psname; print "cmd: " + cmd; #os.system(cmd); java-algebra-system-2.7.200/examples/mmt.rb000066400000000000000000000011751445075545500205020ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example form Moeller, Mora, Traverso #r = PolyRing.new(QQ(),"t,z,y,x",PolyRing.grad); r = PolyRing.new(QQ(),"z,y,x",PolyRing.grad); #r = PolyRing.new(QQ(),"x,y,z",PolyRing.grad); print "Ring: " + str(r); print; #auto: one,z,y,x = r.gens(); f0 = x**2 * y - z**2; f1 = x * z**2 - y**2; f2 = y * z**3 - x**2; #f0h = x**2 * y - z**2 * t; #f1h = x * z**2 - y**2 * t; #f2h = y * z**3 - x**2 * t**2; f = r.ideal("",[f0,f1,f2]); #f = r.ideal("",[f0h,f1h,f2h]); print "Ideal: " + str(f); print; startLog(); rg = f.GB(); print "seq Output: ", rg; print "\n"; #terminate(); java-algebra-system-2.7.200/examples/module.py000066400000000000000000000007711445075545500212200ustar00rootroot00000000000000# # jython examples for jas. from jas import PolyRing, QQ, Module #, SubModule # module example p = PolyRing(QQ(),"u,v,l", PolyRing.lex); #r = Module( "Rat(u,v,l) L", cols=4 ); r = Module( "", p, cols=4 ); print "Module: " + str(r); print; G = r.gens(); print "gens() = ", [str(e) for e in G]; L = [ e.elem.val for e in G ] print "gens() = ", [str(e) for e in L]; M = r.submodul( list=L ); print "M = ", M; P = M.mset.getPolynomialList(); print "P = ", P.toScript(); print "M.isGB(): ", M.isGB(); java-algebra-system-2.7.200/examples/module.rb000066400000000000000000000011141445075545500211630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # module example p = PolyRing.new(QQ(),"u,v,l", PolyRing.lex); #r = CommutativeModule.new( "Rat(u,v,l) L", nil, 4 ); r = CommutativeModule.new( "", p, 4 ); puts "Module: " + str(r); puts; G = r.gens(); puts "gens() = " + str( G.map { |e| str(e) }.join(", ") ); puts L = G.map { |e| e.elem.val } puts "gens() = " + str( L.map { |e| str(e) }.join(", ") ); puts M = r.submodul("", L ); puts "M = " + str(M); puts P = M.mset.getPolynomialList(); puts "P = " + str(P.toScript()); puts puts "M.isGB(): " + str(M.isGB()); puts java-algebra-system-2.7.200/examples/montes_ex111.py000066400000000000000000000022361445075545500221550ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 11.1 # integral function coefficients r = PolyRing( PolyRing(QQ(),"c, b, a",PolyRing.lex), "z,y,x", PolyRing.lex ); print "Ring: " + str(r); print; #automatic: [one,c,b,a,z,y,x] = r.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; f1 = x + c * y + b * z + a; f2 = c * x + y + a * z + b; f3 = b * x + a * y + z + c; F = [f1,f2,f3]; print "F: ", [ str(f) for f in F ]; print; #startLog(); If = r.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; ## G = If.GB(); ## print "GB: " + str(G); ## print; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; terminate(); sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #------------------------------------------ #sys.exit(); java-algebra-system-2.7.200/examples/montes_ex111.rb000066400000000000000000000021251445075545500221250ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 11.1 # integral function coefficients r = PolyRing.new( PolyRing.new(QQ(),"c, b, a",PolyRing.lex), "z,y,x", PolyRing.lex ); puts "Ring: " + str(r); puts; #automatic: one,c,b,a,z,y,x = r.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; f1 = x + c * y + b * z + a; f2 = c * x + y + a * z + b; f3 = b * x + a * y + z + c; F = [f1,f2,f3]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; #startLog(); If = r.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; ## G = If.GB(); ## puts "GB: " + str(G); ## puts; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; terminate(); exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); #------------------------------------------ #exit(); java-algebra-system-2.7.200/examples/montes_ex112.py000066400000000000000000000027461445075545500221640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 11.2 # integral function coefficients r = PolyRing( PolyRing(QQ(),"f, e, d, c, b, a",PolyRing.lex), "y,x", PolyRing.lex ); #r = PolyRing( PolyRing(QQ(),"f, e, d, c, b, a",PolyRing.grad), "y,x", PolyRing.lex ); #r = PolyRing( PolyRing(QQ(),"f, e, d, c, b, a",PolyRing.lex), "y,x", PolyRing.grad ); #r = PolyRing( PolyRing(QQ(),"e, d, c, b, f, a",PolyRing.lex), "y,x", PolyRing.grad ); print "Ring: " + str(r); print; #[one,e,d,c,b,f,a,y,x] = r.gens(); #automatic: [one,f,e,d,c,b,a,y,x] = r.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; f1 = x**2 + b * y**2 + 2 * c * x * y + 2 * d * x + 2 * e * y + f; f2 = x + c * y + d; f3 = b * y + c * x + e; F = [f1,f2,f3]; print "F: ", [ str(f) for f in F ]; print; #startLog(); If = r.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; G = If.GB(); print "GB: " + str(G); print; ## sys.exit(); startLog(); GS = If.CGBsystem(); #GS = If.CGBsystem(); #GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; terminate(); sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #------------------------------------------ #sys.exit(); java-algebra-system-2.7.200/examples/montes_ex112.rb000066400000000000000000000026621445075545500221340ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 11.2 # integral function coefficients r = PolyRing.new( PolyRing.new(QQ(),"f, e, d, c, b, a",PolyRing.lex), "y,x", PolyRing.lex ); #r = PolyRing.new( PolyRing.new(QQ(),"f, e, d, c, b, a",PolyRing.grad), "y,x", PolyRing.lex ); #r = PolyRing.new( PolyRing.new(QQ(),"f, e, d, c, b, a",PolyRing.lex), "y,x", PolyRing.grad ); #r = PolyRing.new( PolyRing.new(QQ(),"e, d, c, b, f, a",PolyRing.lex), "y,x", PolyRing.grad ); puts "Ring: " + str(r); puts; #one,e,d,c,b,f,a,y,x = r.gens(); #automatic: one,f,e,d,c,b,a,y,x = r.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; f1 = x**2 + b * y**2 + 2 * c * x * y + 2 * d * x + 2 * e * y + f; f2 = x + c * y + d; f3 = b * y + c * x + e; F = [f1,f2,f3]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; #startLog(); If = r.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; G = If.GB(); puts "GB: " + str(G); puts; ## sys.exit(); startLog(); GS = If.CGBsystem(); #GS = If.CGBsystem(); #GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; terminate(); exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); #------------------------------------------ #exit(); java-algebra-system-2.7.200/examples/montes_ex113.py000066400000000000000000000023251445075545500221560ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 11.3 # integral function coefficients R = PolyRing( PolyRing(QQ(),"r, l, z",PolyRing.lex), "c1, c2, s1, s2", PolyRing.lex ); print "Ring: " + str(R); print; #automatic: [one,r,l,z,c1,c2,s1,s2] = R.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; f1 = r - c1 + l * ( s1 * s2 - c1 * c2 ); f2 = z - s1 - l * ( s1 * c2 + s2 * c1 ); f3 = s1**2 + c1**2 - 1; f4 = s2**2 + c2**2 - 1; F = [f1,f2,f3,f4]; print "F: ", [ str(f) for f in F ]; print; startLog(); If = R.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; ## G = If.GB(); ## print "GB: " + str(G); ## print; ## sys.exit(); GS = If.CGBsystem(); #GS = If.CGBsystem(); #GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #terminate(); #sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #------------------------------------------ #sys.exit(); java-algebra-system-2.7.200/examples/montes_ex113.rb000066400000000000000000000022131445075545500221250ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 11.3 # integral function coefficients R = PolyRing.new( PolyRing.new(QQ(),"r, l, z",PolyRing.lex), "c1, c2, s1, s2", PolyRing.lex ); puts "Ring: " + str(R); puts; #automatic: one,r,l,z,c1,c2,s1,s2 = R.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; f1 = r - c1 + l * ( s1 * s2 - c1 * c2 ); f2 = z - s1 - l * ( s1 * c2 + s2 * c1 ); f3 = s1**2 + c1**2 - 1; f4 = s2**2 + c2**2 - 1; F = [f1,f2,f3,f4]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; startLog(); If = R.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; ## G = If.GB(); ## puts "GB: " + str(G); ## puts; ## sys.exit(); GS = If.CGBsystem(); #GS = If.CGBsystem(); #GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #terminate(); #exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); #------------------------------------------ #exit(); java-algebra-system-2.7.200/examples/montes_ex114.py000066400000000000000000000030661445075545500221620ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 11.4 # integral function coefficients R = PolyRing( PolyRing(QQ(),"Q2, P2, Q1, P1",PolyRing.lex), "f3, e3, f2, e2", PolyRing.lex ); print "Ring: " + str(R); print; #automatic: [one, Q2, P2, Q1, P1, f3, e3, f2, e2] = R.gens(); print "gens: ", [ str(f) for f in R.gens() ]; print; fp1 = 14 - 12 * e2 - 110 * f2 - 2 * e3 - 10 * f3 - P1; fp2 = 2397 - 2200 * e2 + 240 * f2 - 200 * e3 + 40 * f3 - 20 * Q1; fp3 = 16 * e2**2 - 4 * e2 * e3 - 20 * e2 * f3 + 20 * e3 * f2 + 16 * f2**2 - 4 * f2 * f3 - 12 * e2 + 110 * f2 - P2; fp4 = 2599 * e2**2 - 400 * e2 * e3 + 80 * e2 * f3 - 80 * e3 * f2 + 2599 * f2**2 - 400 * f2 * f3 - 2200 * e2 - 240 * f2 - 20 * Q2; print "fp1: " + str(fp1); print "fp2: " + str(fp2); print "fp3: " + str(fp3); print "fp4: " + str(fp4); print; F = [fp1,fp2,fp3,fp4]; print "F: ", [ str(f) for f in F ]; print; startLog(); If = R.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; ## G = If.GB(); ## print "GB: " + str(G); ## print; GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; terminate(); sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #------------------------------------------ #sys.exit(); java-algebra-system-2.7.200/examples/montes_ex114.rb000066400000000000000000000030041445075545500221250ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 11.4 # integral function coefficients R = PolyRing.new( PolyRing.new(QQ(),"Q2, P2, Q1, P1",PolyRing.lex), "f3, e3, f2, e2", PolyRing.lex ); puts "Ring: " + str(R); puts; #not automatic, since capital letters : one, Q2, P2, Q1, P1, f3, e3, f2, e2 = R.gens(); puts "gens: " + R.gens().each{ |f| str(f) }.join(","); puts; fp1 = 14 - 12 * e2 - 110 * f2 - 2 * e3 - 10 * f3 - P1; fp2 = 2397 - 2200 * e2 + 240 * f2 - 200 * e3 + 40 * f3 - 20 * Q1; fp3 = 16 * e2**2 - 4 * e2 * e3 - 20 * e2 * f3 + 20 * e3 * f2 + 16 * f2**2 - 4 * f2 * f3 - 12 * e2 + 110 * f2 - P2; fp4 = 2599 * e2**2 - 400 * e2 * e3 + 80 * e2 * f3 - 80 * e3 * f2 + 2599 * f2**2 - 400 * f2 * f3 - 2200 * e2 - 240 * f2 - 20 * Q2; puts "fp1: " + str(fp1); puts "fp2: " + str(fp2); puts "fp3: " + str(fp3); puts "fp4: " + str(fp4); puts; F = [fp1,fp2,fp3,fp4]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; startLog(); If = R.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; ## G = If.GB(); ## puts "GB: " + str(G); ## puts; GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; terminate(); exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); #------------------------------------------ #exit(); java-algebra-system-2.7.200/examples/montes_ex51.py000066400000000000000000000022511445075545500220750ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 5.1 # integral function coefficients r = PolyRing( PolyRing(QQ(),"a, b",PolyRing.lex), "u,z,y,x", PolyRing.lex ); print "Ring: " + str(r); print; #automatic: [one,a,b,u,z,y,x] = r.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; f1 = a * x + 2 * y + 3 * z + u - 6; f2 = x + 3 * y - z + 2 * u - b; f3 = 3 * x - a * y + z - 2; f4 = 5 * x + 4 * y + 3 * z + 3 * u - 9; F = [f1,f2,f3,f4]; print "F: ", [ str(f) for f in F ]; print; #startLog(); If = r.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; ## G = If.GB(); ## print "GB: " + str(G); ## print; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #terminate(); #sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/montes_ex51.rb000066400000000000000000000021421445075545500220470ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 5.1 # integral function coefficients r = PolyRing.new( PolyRing.new(QQ(),"a, b",PolyRing.lex), "u,z,y,x", PolyRing.lex ); puts "Ring: " + str(r); puts; #automatic: one,a,b,u,z,y,x = r.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; f1 = a * x + 2 * y + 3 * z + u - 6; f2 = x + 3 * y - z + 2 * u - b; f3 = 3 * x - a * y + z - 2; f4 = 5 * x + 4 * y + 3 * z + 3 * u - 9; F = [f1,f2,f3,f4]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; #startLog(); If = r.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; ## G = If.GB(); ## puts "GB: " + str(G); ## puts; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #terminate(); #exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/montes_ex51s.py000066400000000000000000000025221445075545500222610ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog from jas import terminate # Montes JSC 2002, 33, 183-208, example 5.1, simplified # integral function coefficients r = PolyRing( PolyRing(QQ(),"a, b",PolyRing.lex), "u,z,y,x", PolyRing.lex ); print "Ring: " + str(r); print; #automatic: [one,a,b,u,z,y,x] = r.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; f1 = 756 * x - 39 * a * b - 4 * b - 155 - 117 * a + ( 117 * a + 51 ) * u; f2 = 189 * y + 6 * a * b - 107 - 43 * b + 18 * a - ( 18 * a - 123 ) * u; f3 = 756 * z - 1439 + 236 * b + 99 * a + 33 * a * b - ( 99 * a - 15 ) * u; f4 = ( 9 * a**2 - 30 * a + 21 ) * u - 9 * a**2 - 3 * a**2 * b + 11 * a * b + 22 * a - 49 + 28 * b; F = [f1,f2,f3,f4]; print "F: ", [ str(f) for f in F ]; print; #startLog(); If = r.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; ## G = If.GB(); ## print "GB: " + str(G); ## print; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; terminate(); sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/montes_ex51s.rb000066400000000000000000000025021445075545500222320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Montes JSC 2002, 33, 183-208, example 5.1, simplified # integral function coefficients r = PolyRing.new( PolyRing.new(QQ(),"a, b",PolyRing.lex), "u,z,y,x", PolyRing.lex ); puts "Ring: " + str(r); puts; #automatic: one,a,b,u,z,y,x = r.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; f1 = 756 * x - 39 * a * b - 4 * b - 155 - 117 * a + ( 117 * a + 51 ) * u; f2 = 189 * y + 6 * a * b - 107 - 43 * b + 18 * a - ( 18 * a - 123 ) * u; f3 = 756 * z - 1439 + 236 * b + 99 * a + 33 * a * b - ( 99 * a - 15 ) * u; f4 = ( 9 * a**2 - 30 * a + 21 ) * u - 9 * a**2 - 3 * a**2 * b + 11 * a * b + 22 * a - 49 + 28 * b; F = [f1,f2,f3,f4]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; #startLog(); If = r.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; ## G = If.GB(); ## puts "GB: " + str(G); ## puts; ## sys.exit(); GS = If.CGBsystem(); GS = If.CGBsystem(); GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; terminate(); exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); #------------------------------------------ #exit(); java-algebra-system-2.7.200/examples/nabeshima_cgbF0.py000066400000000000000000000014101445075545500226520ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example Ex-4.8 # integral function coefficients r = Ring( "IntFunc(a, b, c) (y,x) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^2 + { b } y^2 ), ( { c } x^2 + y^2 ), ( { 2 a } x - { 2 c } y ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF0.rb000066400000000000000000000012761445075545500226370ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example Ex-4.8 # integral function coefficients r = Ring.new( "IntFunc(a, b, c) (y,x) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^2 + { b } y^2 ), ( { c } x^2 + y^2 ), ( { 2 a } x - { 2 c } y ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF00.py000066400000000000000000000013501445075545500227350ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example Ex-Fig-2 # integral function coefficients r = Ring( "IntFunc(a, b, c) (x) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^3 ), ( { b } x^2 ), ( { c } x ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF00.rb000066400000000000000000000012361445075545500227130ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example Ex-Fig-2 # integral function coefficients r = Ring.new( "IntFunc(a, b, c) (x) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^3 ), ( { b } x^2 ), ( { c } x ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF01.py000066400000000000000000000013621445075545500227410ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example Ex-4.3 # integral function coefficients r = Ring( "IntFunc(a, b) (y,x) L" ); print "Ring: " + str(r); print; ps = """ ( ( x y + x ), ( { a } x^2 + y + 2 ), ( { b } x y + y ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF01.rb000066400000000000000000000012501445075545500227100ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example Ex-4.3 # integral function coefficients r = Ring.new( "IntFunc(a, b) (y,x) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( x y + x ), ( { a } x^2 + y + 2 ), ( { b } x y + y ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF1.py000066400000000000000000000015131445075545500226570ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F1 # integral function coefficients r = Ring( "IntFunc(a, b) (y,x) G" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^4 y + x y^2 + { b } x ), ( x^3 + 2 x y ), ( { b } x^2 + x^2 y ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF1.rb000066400000000000000000000014011445075545500226260ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F1 # integral function coefficients r = Ring.new( "IntFunc(a, b) (y,x) G" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^4 y + x y^2 + { b } x ), ( x^3 + 2 x y ), ( { b } x^2 + x^2 y ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF2.py000066400000000000000000000015251445075545500226630ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F2 # integral function coefficients r = Ring( "IntFunc(b, a) (x,y) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^2 y^3 + { b } y + y ), ( x^2 y^2 + x y + 2 ), ( { a } x^2 + { b } y + 2 ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF2.rb000066400000000000000000000014131445075545500226320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F2 # integral function coefficients r = Ring.new( "IntFunc(b, a) (x,y) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^2 y^3 + { b } y + y ), ( x^2 y^2 + x y + 2 ), ( { a } x^2 + { b } y + 2 ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF3.py000066400000000000000000000015301445075545500226600ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F3 # integral function coefficients r = Ring( "IntFunc(c, b, a, d) (x) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^4 + { c } x^2 + { b } ), ( { b } x^3 + x^2 + 2 ), ( { c } x^2 + { d } x ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF3.rb000066400000000000000000000014271445075545500226400ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F3 # integral function coefficients r = Ring.new( "IntFunc(c, b, a, d) (x) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^4 + { c } x^2 + { b } ), ( { b } x^3 + x^2 + 2 ), ( { c } x^2 + { d } x ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; terminate(); exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF4.py000066400000000000000000000016011445075545500226600ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F4 # integral function coefficients r = Ring( "IntFunc(a, b, c, d) (y, x) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^3 y + { c } x y^2 ), ( x^4 y + { 3 d } y ), ( { c } x^2 + { b } x y ), ( x^2 y^2 + { a } x^2 ), ( x^5 + y^5 ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF4.rb000066400000000000000000000015001445075545500226310ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F4 # integral function coefficients r = Ring.new( "IntFunc(a, b, c, d) (y, x) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^3 y + { c } x y^2 ), ( x^4 y + { 3 d } y ), ( { c } x^2 + { b } x y ), ( x^2 y^2 + { a } x^2 ), ( x^5 + y^5 ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; terminate(); exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF5.py000066400000000000000000000015441445075545500226670ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F5 # integral function coefficients r = Ring( "IntFunc(b, a, c) (x,y) L" ); print "Ring: " + str(r); print; ps = """ ( ( { a } x^2 y + { b } x + y^2 ), ( { a } x^2 y + { b } x y ), ( y^2 + { b } x^2 y + { c } x y ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF5.rb000066400000000000000000000014261445075545500226410ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F5 # integral function coefficients r = Ring.new( "IntFunc(b, a, c) (x,y) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( { a } x^2 y + { b } x + y^2 ), ( { a } x^2 y + { b } x y ), ( y^2 + { b } x^2 y + { c } x y ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF6.py000066400000000000000000000015241445075545500226660ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F6 # integral function coefficients r = Ring( "IntFunc(a, b,c, d) (x) G" ); print "Ring: " + str(r); print; ps = """ ( ( x^4 + { a } x^3 + { b } x^2 + { c } x + { d } ), ( 4 x^3 + { 3 a } x^2 + { 2 b } x + { c } ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF6.rb000066400000000000000000000014121445075545500226350ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F6 # integral function coefficients r = Ring.new( "IntFunc(a, b,c, d) (x) G" ); puts "Ring: " + str(r); puts; ps = """ ( ( x^4 + { a } x^3 + { b } x^2 + { c } x + { d } ), ( 4 x^3 + { 3 a } x^2 + { 2 b } x + { c } ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF7.py000066400000000000000000000014531445075545500226700ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F7 # integral function coefficients r = Ring( "IntFunc(a, b) (z,y,x) G" ); print "Ring: " + str(r); print; ps = """ ( ( x^3 - { a } ), ( y^4 - { b } ), ( x + y - { a } z ) ) """; #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF7.rb000066400000000000000000000013411445075545500226370ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F7 # integral function coefficients r = Ring.new( "IntFunc(a, b) (z,y,x) G" ); puts "Ring: " + str(r); puts; ps = """ ( ( x^3 - { a } ), ( y^4 - { b } ), ( x + y - { a } z ) ) """; #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; #exit(); gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF8.py000066400000000000000000000025741445075545500226760ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog from jas import terminate # Nabashima, ISSAC 2007, example F8 # modified, take care # integral function coefficients #r = Ring( "IntFunc(d, b, a, c) (y,x,w,z) L" ); r = Ring( "IntFunc(d, b, a, c) (y,x,w,z) G" ); #r = Ring( "IntFunc(d, b, c, a) (w,z,y,x) G" ); #r = Ring( "IntFunc(b, c, a) (w,x,z,y) L" ); #r = Ring( "IntFunc(b, c) (z,y,w,x) L" ); #r = Ring( "IntFunc(b) (z,y,w,x) L" ); #r = Ring( "IntFunc(c) (z,y,w,x) L" ); #r = Ring( "IntFunc(c) (z,y,w,x) G" ); print "Ring: " + str(r); print; ps = """ ( ( { c } w^2 + z ), ( { a } x^2 + { b } y ), ( ( x - z )^2 + ( y - w)^2 ), ( { 2 d } x w - { 2 b } y ) ) """; ## ( { 1 } x^2 + { 1 } y ), ## ( { 1 } w^2 + z ), ## ( { 2 } x w - { 2 1 } y ) # ( { 1 } x^2 + { b } y ), # ( { c } w^2 + z ), # ( { a } x^2 + { b } y ), # ( { 2 d } x w - { 2 b } y ) #startLog(); f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; #startLog(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; terminate(); sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/nabeshima_cgbF8.rb000066400000000000000000000025151445075545500226440ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Nabashima, ISSAC 2007, example F8 # modified, take care # integral function coefficients #r = Ring.new( "IntFunc(d, b, a, c) (y,x,w,z) L" ); r = Ring.new( "IntFunc(d, b, a, c) (y,x,w,z) G" ); #r = Ring.new( "IntFunc(d, b, c, a) (w,z,y,x) G" ); #r = Ring.new( "IntFunc(b, c, a) (w,x,z,y) L" ); #r = Ring.new( "IntFunc(b, c) (z,y,w,x) L" ); #r = Ring.new( "IntFunc(b) (z,y,w,x) L" ); #r = Ring.new( "IntFunc(c) (z,y,w,x) L" ); #r = Ring.new( "IntFunc(c) (z,y,w,x) G" ); puts "Ring: " + str(r); puts; ps = """ ( ( { c } w^2 + z ), ( { a } x^2 + { b } y ), ( ( x - z )^2 + ( y - w)^2 ), ( { 2 d } x w - { 2 b } y ) ) """; ## ( { 1 } x^2 + { 1 } y ), ## ( { 1 } w^2 + z ), ## ( { 2 } x w - { 2 1 } y ) # ( { 1 } x^2 + { b } y ), # ( { c } w^2 + z ), # ( { a } x^2 + { b } y ), # ( { 2 d } x w - { 2 b } y ) #startLog(); f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; #startLog(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; terminate(); exit(); bg = gs.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/ncmat.rb000066400000000000000000000010301445075545500207750ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" require "matrix" # matrix and polynomial examples: # conditions for (non) commuting matrices r = PolyRing.new(ZZ(), "a,b,c,d,e,f,g,h") puts "r = " + r.to_s puts x = Matrix[[a,b],[c,d]] y = Matrix[[e,f],[g,h]] puts "x = " + x.to_s + ", y = " + y.to_s puts com = x*y - y*x puts "commutator = " + com.to_s puts ff = r.ideal("", [ com[0,0], com[0,1], com[1,0], com[1,1] ] ) puts "ff = " + ff.to_s puts gg = ff.GB(); puts "gg = " + gg.to_s puts #startLog(); #terminate(); java-algebra-system-2.7.200/examples/ncmatj.py000066400000000000000000000012531445075545500212030ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, Ideal, QQ, ZZ, EF, Mat # matrix and polynomial examples: # conditions for (non) commuting matrices r = EF(QQ()).polynomial("a,b,c,d,e,f,g,h").build(); print "r = " + str(r); #one, a, b, c, d, e, f, g, h = r.gens(); print "h = " + str(h); print x = Mat(r,2,2,[[a,b],[c,d]]) y = Mat(r,2,2,[[e,f],[g,h]]) print "x = " + str(x) + ", y = " + str(y) #+ ", x y = " + str(x*y) print com = x*y - y*x print "commutator = " + str(com) print ff = r.ideal("", [ com[0][0], com[0][1], com[1][0], com[1][1] ] ) print "ff = " + str(ff) print gg = ff.GB(); print "gg = " + str(gg) print #startLog(); #terminate(); java-algebra-system-2.7.200/examples/ncmatj.rb000066400000000000000000000012261445075545500211560ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # matrix and polynomial examples: # conditions for (non) commuting matrices r = EF.new(QQ()).polynomial("a,b,c,d,e,f,g,h").build() puts "r = " + str(r) #one, a, b, c, d, e, f, g, h = r.gens(); puts "h = " + str(h) puts x = Mat(r,2,2,[[a,b],[c,d]]) y = Mat(r,2,2,[[e,f],[g,h]]) z = Mat(r,2,2,[[one,0],[0,one]]) puts "x = " + str(x) + ", y = " + str(y) + ", z = " + str(z) puts com = x*y - y*x #+ z puts "commutator = " + com.to_s puts ff = r.ideal("", [ com[0,0], com[0,1], com[1,0], com[1,1] ] ) puts "ff = " + str(ff) puts gg = ff.GB(); puts "gg = " + str(gg) puts #startLog(); #terminate(); java-algebra-system-2.7.200/examples/optimize.py000066400000000000000000000020641445075545500215700ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import Ideal from jas import startLog # example from rose (modified) # optimal is # Rat(A46, U3, U4) # r = Ring( "Rat(U3,U4,A46) G" ); print "Ring: " + str(r); print; ps = """ ( ( U4^4 - 20/7 A46^2 ), ( A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216 ), ( A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) ) """; f = Ideal( r, ps ); print "Ideal: " + str(f); print; startLog(); o = f.optimize(); print "optimized Ideal: " + str(o); print; #rg = f.GB(); #print "Output:", rg; #print; org = o.GB(); print "opt Output:", org; print; java-algebra-system-2.7.200/examples/orderexam.py000066400000000000000000000032711445075545500217170ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, QQ, ZZ, Order, Scripting from jas import startLog, terminate # examples: from Mathematica # check("GroebnerBasis({x^2 + y^2 + z^2 - 1, x - z + 2, z^2 - x*y}, # {x, y, z})", # "{12-28*z+27*z^2-12*z^3+3*z^4, -6+4*y+11*z-6*z^2+3*z^3, 2+x-z}"); Scripting.setCAS(Scripting.CAS.Math); #Scripting.setCAS(Scripting.CAS.Sage); #Scripting.setCAS(Scripting.CAS.Singular); r = PolyRing(ZZ(),"x,y,z",Order.Lexicographic); print "Ring: " + str(r); print; ff = [ x**2 + y**2 + z**2 - 1, x - z + 2, z**2 - x*y] F = r.ideal( "", ff ); print "F = " + str(F); print; #startLog(); G = F.GB(); print "G = " + str(G); print; print "Ma: " + str( r.ideal("",[12-28*z+27*z**2-12*z**3+3*z**4,-6+4*y+11*z-6*z**2+3*z**3,2+x-z] )); print; # check("GroebnerBasis({x^2 + y^2 + z^2 - 1, x - z + 2, z^2 - x*y}, # {x, y, z}, MonomialOrder -> DegreeReverseLexicographic)", # "{16+23*x+12*x^2+3*x^3+4*y,3+4*x+2*x^2+y^2,-4-4*x-x^2+x*y,-2-x+z}"); #r = PolyRing(QQ(),"x,y,z",Order.DegreeReverseLexicographic.blockOrder(1,3)); #r = PolyRing(QQ(),"x,y,z",Order.DegreeReverseLexicographic.blockOrder(1)); #r = PolyRing(QQ(),"x,y,z",Order.DegreeReverseLexicographic.blockOrder(1, Order.DegreeLexicographic)); r = PolyRing(ZZ(),"x,y,z",Order.DegreeReverseLexicographic); print "Ring: " + str(r); print; ff = [ x**2 + y**2 + z**2 - 1, x - z + 2, z**2 - x*y] F = r.ideal( "", ff ); print "F = " + str(F); print; #startLog(); G = F.GB(); print "G = " + str(G); print; print "Ma: " + str(r.ideal("", [ 16+23*x+12*x**2+3*x**3+4*y, 3+4*x+2*x**2+y**2, -4-4*x-x**2+x*y, -2-x+z]) ); print; java-algebra-system-2.7.200/examples/orderexam.rb000066400000000000000000000032111445075545500216640ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # examples: from Mathematica # check("GroebnerBasis({x^2 + y^2 + z^2 - 1, x - z + 2, z^2 - x*y}, # {x, y, z})", # "{12-28*z+27*z^2-12*z^3+3*z^4, -6+4*y+11*z-6*z^2+3*z^3, 2+x-z}"); Scripting.setCAS(Scripting::CAS::Math); #Scripting.setCAS(Scripting::CAS::Sage); #Scripting.setCAS(Scripting::CAS::Singular); r = PolyRing.new(ZZ(),"x,y,z",Order::Lexicographic); puts "Ring: " + str(r); puts; ff = [ x**2 + y**2 + z**2 - 1, x - z + 2, z**2 - x*y] F = r.ideal( "", ff ); puts "F = " + str(F); puts; #startLog(); G = F.GB(); puts "G = " + str(G); puts; puts "Ma: " + str( r.ideal("",[12-28*z+27*z**2-12*z**3+3*z**4,-6+4*y+11*z-6*z**2+3*z**3,2+x-z] )); puts; # check("GroebnerBasis({x^2 + y^2 + z^2 - 1, x - z + 2, z^2 - x*y}, # {x, y, z}, MonomialOrder -> DegreeReverseLexicographic)", # "{16+23*x+12*x^2+3*x^3+4*y,3+4*x+2*x^2+y^2,-4-4*x-x^2+x*y,-2-x+z}"); #r = PolyRing.new(ZZ(),"x,y,z",TermOrderByName::DegreeReverseLexicographic.blockOrder(1,3)); #r = PolyRing.new(ZZ(),"x,y,z",TermOrderByName::DegreeReverseLexicographic.blockOrder(1)); #r = PolyRing.new(ZZ(),"x,y,z",Order::DegreeReverseLexicographic.blockOrder(1, Order::DegreeLexicographic)); r = PolyRing.new(ZZ(),"x,y,z",Order::DegreeReverseLexicographic); puts "Ring: " + str(r); puts; ff = [ x**2 + y**2 + z**2 - 1, x - z + 2, z**2 - x*y] F = r.ideal( "", ff ); puts "F = " + str(F); puts; #startLog(); G = F.GB(); puts "G = " + str(G); puts; puts "Ma: " + str(r.ideal("", [ 16+23*x+12*x**2+3*x**3+4*y, 3+4*x+2*x**2+y**2, -4-4*x-x**2+x*y, -2-x+z]) ); puts; java-algebra-system-2.7.200/examples/ordermon.rb000066400000000000000000000135741445075545500215400ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # examples: from Mathematica term orders Scripting.setCAS(Scripting::CAS::Math); #Scripting.setCAS(Scripting::CAS::Sage); #Scripting.setCAS(Scripting::CAS::Singular); r = PolyRing.new(ZZ(),"x,y,z",Order::Lexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -10*x**5*y**4*z**2, 7*x**2*y**5*z**3, -10*x**2*y*z**5, -7*x*y**5*z**4, 6*x*y**4*z**3, 6*x*y**3*z**3, 3*x*y**2*z, y**4*z, -7*y**2*z, 2*z**5 ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::NegativeLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ 2*z**5, -7*y**2*z, y**4*z, 3*x*y**2*z, 6*x*y**3*z**3, 6*x*y**4*z**3, -7*x*y**5*z**4, -10*x**2*y*z**5, 7*x**2*y**5*z**3, -10*x**5*y**4*z**2 ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::DegreeLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -10*x**5*y**4*z**2, 7*x**2*y**5*z**3, -7*x*y**5*z**4, -10*x**2*y*z**5, 6*x*y**4*z**3, 6*x*y**3*z**3, y**4*z, 2*z**5, 3*x*y**2*z, -7*y**2*z ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::NegativeDegreeReverseLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -7*y**2*z,3*x*y**2*z, y**4*z, 2*z**5, 6*x*y**3*z**3, 6*x*y**4*z**3, -10*x**2*y*z**5, 7*x**2*y**5*z**3, -7*x*y**5*z**4, -10*x**5*y**4*z**2 ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::DegreeReverseLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -10*x**5*y**4*z**2, 7*x**2*y**5*z**3, -7*x*y**5*z**4, 6*x*y**4*z**3, -10*x**2*y*z**5, 6*x*y**3*z**3, y**4*z, 2*z**5, 3*x*y**2*z, -7*y**2*z ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::NegativeDegreeLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -7*y**2*z, 3*x*y**2*z, y**4*z, 2*z**5, 6*x*y**3*z**3, -10*x**2*y*z**5, 6*x*y**4*z**3, 7*x**2*y**5*z**3, -7*x*y**5*z**4, -10*x**5*y**4*z**2 ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::NegativeReverseLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -7 * y**2 * z, 3 * x * y**2 * z, y**4 * z, -10 * x**5 * y**4 * z**2, 6 * x * y**3 * z**3, 6 * x * y**4 * z**3, 7 * x**2 * y**5 * z**3, -7 * x * y**5 * z**4, 2 * z**5, -10 * x**2 * y * z**5 ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; r = PolyRing.new(ZZ(),"x,y,z",Order::ReverseLexicographic); puts "Ring: " + str(r); puts; ff = -10*x**5*y**4*z**2 + 7*x**2*y**5*z**3 + -10*x**2*y*z**5 + -7*x*y**5*z**4 + 6*x*y**4*z**3 + 6*x*y**3*z**3 + 3*x*y**2*z + y**4*z + -7*y**2*z + 2*z**5; puts "ff = " + str(ff); puts; fm = ff.elem.iterator().map{ |a| RingElem.new(r.ring.valueOf(a)) }; mm = [ -10 * x**2 * y * z**5, 2 * z**5, -7 * x * y**5 * z**4, 7 * x**2 * y**5 * z**3, 6 * x * y**4 * z**3, 6 * x * y**3 * z**3, -10 * x**5 * y**4 * z**2, y**4 * z, 3 * x * y**2 * z, -7 * y**2 * z ] puts "mm = " + mm.map{ |a| a.to_s }.join(", "); puts; puts "mm == fm: " + (mm == fm).to_s; puts; java-algebra-system-2.7.200/examples/ore_t.jas000066400000000000000000000003201445075545500211560ustar00rootroot00000000000000# solvable polynomials, Ore extension Q[x,y][z;d][t,e]: Rat(x,y,z,t) L RelationTable ( ( z ), ( y ), ( y z + x ), ( t ), ( y ), ( y t + y ), ( t ), ( z ), ( z t - z ) ) ( ( x^2 + y^2 + z^2 + t^2 + 1 ) ) java-algebra-system-2.7.200/examples/perfAnaly.rb000066400000000000000000000063471445075545500216340ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # performance analysis of multi-core clusters #startLog(); Scripting.setPrecision(3); # first ring with variables q,p,r,v,x,b,l1 ring = PolyRing.new(QQ(),"q,p,r,v,x,b,l1",PolyRing.lex); puts "ring = " + str(ring); qring = RF(ring); puts "qring = " + str(qring.factory()); one,q,p,r,v,x,b,l1 = qring.gens(); # required for RF puts "one = " + str(one); def sa(z) return z/(1+z) end def so(z) # does not work #return z-1; puts "z-1: " + str(z-1); if z-1 then return 1 else return z end end #x = a/as; puts "x = " + str(x); puts "q = " + str(q); puts "x/q = " + str(x/q); s = sa(x/q) puts "s = " + str(s); # alt: q\, p\, l_c \cdot # \frac{s(\frac{x}{q})}{1 + \frac{q\, p}{\beta(p)} \cdot \frac{s(\frac{x}{q})}{v\, r\, \frac{x}{q}}} #l_{cl}(q,p) & \le & # q\, p\, l_c \cdot # \frac{s(\frac{x}{q})}{1 + \frac{q^2\, p}{\beta(q,p)} \cdot \frac{s(\frac{x}{q})}{v\, r\, x}} lcl = q * p * l1 * ( s / ( 1 + (q*q*(p/b)) * ( s / (v*r*x)) )); puts "lcl = " + str(lcl); etacl = lcl / (q*p*l1); puts "etacl = " + str(etacl); Scl = lcl / (l1); puts "Scl = " + str(Scl); puts # second ring with variables q,p,wp,lp,n,ln ringq = PolyRing.new(QQ(),"q,p,wp,lp,n,ln",PolyRing.lex); puts "ringq = " + str(ringq); qringq = RF(ringq); puts "qringq = " + str(qringq.factory()); one,q,p,wp,lp,n,ln = qringq.gens(); # required for RF puts "one = " + str(one); puts w = 8 c = 2*w b = 1 #b = 1/p #b = 1/q #b = p/q #b = p #b = 1/(p*q) if false puts "scalar-prod:" hashb = 2*n*w hashop = 2*n - 1 hashx = p*w end if true puts "mat-mult:" b = p hashb = 2*n**2*w hashop = 2*n**3 - n**2 hashx = 2*n**2*wp*w end if false puts "linpack:" hashb = 2*n**2*w hashop = 2/3*n**3 hashx = 1*(1 + 1/12 * lp)*n**2*w end if false puts "1-dim FFT:" hashb = n*c hashop = n*ln hashx = (n/p)*lp*c end if false puts "2-dim FFT:" hashb = n**2*c hashop = 2*n**2*ln # hashx = (n*ln)*lp*c # hashx = (n/p)*lp*c hashx = (n**2/p)*lp*c end if false puts "2-dim FFTW:" hashb = n**2*c hashop = 2*n**2*ln hashx = n*lp*c end puts "w = " + str(w); puts "b = " + str(b); puts "#b = " + str(hashb); puts "#op = " + str(hashop); puts "#x = " + str(hashx); puts a = hashop / hashb r = hashb / hashx puts "a = " + str(a); puts "r = " + str(r); puts if false puts "bwGRiD:" l1 = 8.5 bm = 6 bcl = 1.4 #* (140/2)/4 end if true puts "bwUniCluster:" l1 = 15.4 bm = 77 bcl = 5.4 #* (128/2) end if false puts "bwForHLR1:" l1 = 19.1 bm = 95 bcl = 5.4 end if false puts "bwForCluster:" l1 = 33 bm = 81 bcl = 3 #* 128/2 end puts "l1 = " + str(l1); puts "bm = " + str(bm); puts "bcl = " + str(bcl); puts #as = lm / bcl as = one * l1 / bm v = one * bcl / bm puts "as = " + str(as); puts "v = " + str(v); puts x = a / as puts "a/as = " + str(x); rvxq = r * v * x / q; puts "rvxq = " + str(rvxq); puts etacl = r * v * x * b / ( r * v * x * b + q * r * v * b + q**2 * p ) #etacl = r * v * x * b / ( r * v * x * b + q * r * v + q**2 * p ) #etacl = r * v * x * b / ( r * v * x * b + q**2 * p ) puts "etacl = " + str(etacl); puts speedcl = q * p * etacl puts "speedcl = " + str(speedcl); puts #puts terminate(); java-algebra-system-2.7.200/examples/polynomial.py000066400000000000000000000021021445075545500221040ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from java.lang import Integer from jas import Ring from jas import Ideal from jas import terminate from jas import startLog # polynomial examples: gcd #r = Ring( "Mod 1152921504606846883 (x,y,z) L" ); #r = Ring( "Rat(x,y,z) L" ); #r = Ring( "C(x,y,z) L" ); r = Ring( "Z(x,y,z) L" ); print "Ring: " + str(r); print; [one,x,y,z] = r.gens(); a = r.random(); b = r.random(); c = abs(r.random()); #c = 1; #a = 0; f = x * a + b * y**2 + one * z**7; print "a = ", a; print "b = ", b; print "c = ", c; print "f = ", f; print; ac = a * c; bc = b * c; print "ac = ", ac; print "bc = ", bc; print; t = System.currentTimeMillis(); g = r.gcd(ac,bc); t = System.currentTimeMillis() - t; print "g = ", g; #print "gcd time =", t, "milliseconds"; d = r.gcd(g,c); if cmp(c,d) == 0: print "gcd time =", t, "milliseconds,", "isGcd(c,d): true" ; else: print "gcd time =", t, "milliseconds,", "isGcd(c,d): ", cmp(c,d); print; #d = g / c; #m = g % c; #print "d = ", d; #print "m = ", m; #print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/polynomial.rb000066400000000000000000000017631445075545500220730ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: gcd #r = Ring( "Mod 1152921504606846883 (x,y,z) L" ); #r = Ring( "Rat(x,y,z) L" ); #r = Ring( "C(x,y,z) L" ); r = Ring.new( "Z(x,y,z) L" ); puts "Ring: " + str(r); puts; one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts; a = r.random(); b = r.random(); c = r.random().abs(); #c = one; #a = 0; f = x * a + b * y**2 + one * z**7; puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); #puts "f = " + str(f); puts; ac = a * c; bc = b * c; puts "ac = " + str(ac); puts "bc = " + str(bc); puts; t = System.currentTimeMillis(); g = r.gcd(ac,bc); t = System.currentTimeMillis() - t; puts "g = " + str(g); #puts "gcd time =", t, "milliseconds"; d = r.gcd(g,c); puts "gcd time = " + str(t) + " milliseconds," + " isGcd(c,d): " + str(c==d); puts; #d = g / c; #m = g % c; #puts "d = ", d; #puts "m = ", m; #puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/polypower.py000066400000000000000000000022311445075545500217640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from java.lang import Integer from jas import PolyRing, SolvPolyRing, ZZ, QQ, GF, ZM # sparse polynomial powers #r = Ring( "Mod 1152921504606846883 (x,y,z) G" ); #r = Ring( "Rat(x,y,z) G" ); #r = Ring( "C(x,y,z) G" ); #r = Ring( "Z(x,y,z) L" ); r = PolyRing( ZZ(), "(x,y,z)", PolyRing.lex ); #r = SolvPolyRing( ZZ(), "(x,y,z)", PolyRing.lex ); print "Ring: " + str(r); print; ps = """ ( ( 1 + x^2147483647 + y^2147483647 + z^2147483647 ) ( 1 + x + y + z ) ( 10000000001 + 10000000001 x + 10000000001 y + 10000000001 z ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; pset = f.pset; print "pset:", pset; print; plist = pset.list; print "plist:", plist; print; #p = plist[1]; p = plist[0]; #p = plist[2]; print "p:", p; print; q = p; for i in range(1,20): q = q.multiply(p); print "q:", q.length(); print; q1 = q.sum( r.ring.getONE() ); #print "q1:", q1; print "q1:", q1.length(); print; t = System.currentTimeMillis(); q2 = q.multiply(q1); t = System.currentTimeMillis() - t; print "q2:", q2.length(); print "t:",t; print; print "Integer.MAX_VALUE = ", Integer.MAX_VALUE; java-algebra-system-2.7.200/examples/polypower.rb000066400000000000000000000030001445075545500217320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # sparse polynomial powers #r = Ring( "Mod 1152921504606846883 (x,y,z) G" ); #r = Ring( "Rat(x,y,z) G" ); #r = Ring( "C(x,y,z) G" ); r = PolyRing.new( ZZ(), "(x,y,z)", PolyRing.lex ); #r = SolvPolyRing.new( ZZ(), "(x,y,z)", PolyRing.lex ); puts "Ring: " + str(r); puts; #automatic: one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts; p1 = ( 1 + x**2147483647 + y**2147483647 + z**2147483647 ); p2 = ( 1 + x + y + z ); p3 = ( 10000000001 + 10000000001 * x + 10000000001 * y + 10000000001 * z ); puts "p1 = " + str(p1); puts "p2 = " + str(p2); puts "p3 = " + str(p3); puts; # unused: ps = """ ( ( 1 + x^2147483647 + y^2147483647 + z^2147483647 ) ( 1 + x + y + z ) ( 10000000001 + 10000000001 x + 10000000001 y + 10000000001 z ) ) """; #f = Ideal.new( r, ps ); f = r.ideal( ps ); puts "Ideal: " + str(f); puts; plist = f.pset.list; puts "plist: " + str(plist); puts; p = plist[0]; #p = plist[2]; p = p2; #p = p1; #p = p3; puts "p: " + str(p); puts; q = p; for i in 1..19 q = q * p; end puts "q: " + str(q.elem.length()); puts; q1 = q + one; #puts "q1:", q1; puts "q1: " + str(q1.elem.length()); puts; t = System.currentTimeMillis(); q2 = q * q1; t = System.currentTimeMillis() - t; puts "q2: " + str(q2.elem.length()); puts "time " + str(t) + " milliseconds"; puts; puts "creations: " + str(r.ring.getCreations); puts; #puts "Integer.MAX_VALUE = " +str(Integer::MAX_VALUE); java-algebra-system-2.7.200/examples/powerseries.py000066400000000000000000000072261445075545500223040ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, DD, Ring, SeriesRing from jas import startLog from edu.jas.ps import Coefficients from edu.jas.ps import UnivPowerSeriesMap # example for power series # # rational number examples # psr = SeriesRing("Q(y)"); print "psr:", psr; print; one = psr.one(); print "one:", one; print; zero = psr.zero(); print "zero:", zero; print; r1 = psr.random(4); print "r1:", r1; print; print "r1:", r1; print; print "r1-r1:", r1-r1; print; r2 = psr.random(4); print "r2:", r2; print; print "r2:", r2; print; print "r2-r2:", r2-r2; print; #sys.exit(); r3 = r1 + r2; print "r3:", r3; print; r4 = r1 * r2 + one; print "r4:", r4; print; e = psr.exp(); print "e:", e; print; r5 = r1 * r2 + e; print "r5:", r5; print; #print "psr.gens: ", [ str(i) for i in psr.gens() ]; [one,y] = psr.gens(); print "y:", y; print; r6 = one - y; print "r6:", r6; print; r7 = one / r6; print "r7:", r7; print; s = psr.sin(); print "s:", s; print; r8 = psr.gcd(y,s); print "r8:", r8; print; s1 = s.evaluate( QQ(0) ); print "s1:", s1; print; c = psr.cos(); print "c:", c; print; c1 = c.evaluate( QQ(0) ); print "c1:", c1; print; s2c2 = s*s+c*c; # sin^2 + cos^2 = 1 print "s2c2:", s2c2; print; # # floating point examples # dr = SeriesRing(cofac=DD()); print "dr:", dr; print; de = dr.exp(); print "de:", de; print; d0 = de.evaluate( DD(0) ); print "d0:", d0; print; d1 = de.evaluate( DD(0.5) ); print "d1:", d1; print; d01 = de.evaluate( DD(0.000000000000000001) ); print "d01:", d01; print; def f(a): return a*a; ps = psr.create(f); print "ps:", ps; print; def g(a): return a+a; ps1 = psr.create(g); print "ps1:", ps1; print; ps2 = ps * ps1; print "ps2:", ps2; print; def h(a): return psr.ring.coFac.fromInteger( 2*a ); ps3 = psr.create(jfunc=h); print "ps3:", ps3; print; ps4 = ps3 * ps1; print "ps4:", ps4; print; # does not work, since get() is not known def k(a): if a > 0: return get(a-1).multiply( psr.ring.coFac.fromInteger( 2*a ) ); else: return psr.ring.coFac.fromInteger( 2*a ); #no#ps5 = psr.create(jfunc=k); #no#print "ps5:", ps5; #no#print; class coeff( Coefficients ): def __init__(self,cofac): self.coFac = cofac; def generate(self,i): if i == 0: return self.coFac.getZERO(); else: if i == 1: return self.coFac.getONE(); else: c = self.get( i-2 ).negate(); return c.divide( self.coFac.fromInteger(i) ).divide( self.coFac.fromInteger(i-1) ); ps6 = psr.create( clazz=coeff(psr.ring.coFac) ); print "ps6:", ps6; print; ps7 = ps6 - s; print "ps7:", ps7; print; class cosmap( UnivPowerSeriesMap ): def __init__(self,cofac): self.coFac = cofac; def map(self,ps): return ps.negate().integrate( self.coFac.getZERO() ).integrate( self.coFac.getONE() ); ps8 = psr.fixPoint( cosmap( psr.ring.coFac ) ); print "ps8:", ps8; print; ps9 = ps8 - c; print "ps9:", ps9; print; # conversion from polynomials pr = Ring("Q(y) L"); print "pr:", pr; print; [one,yp] = pr.gens(); p1 = one; p2 = one - yp; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; print "p1:", p1; print "p2:", p2; print "ps1:", ps1; print "ps2:", ps2; print "ps3:", ps3; print; p1 = one * 2 + yp**3 - yp**5; p2 = one - yp**2 + yp**4; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; ps4 = ps3.integrate( QQ(1) ); ps5 = ps3.differentiate(); print "p1:", p1; print "p2:", p2; print "ps1:", ps1; print "ps2:", ps2; print "ps3:", ps3; print "ps4:", ps4; print "ps5:", ps5; print; #sys.exit(); java-algebra-system-2.7.200/examples/powerseries.rb000066400000000000000000000077551445075545500222660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # examples for power series # rational number examples # #psr = SeriesRing.new("", nil, nil, QQ(), "y"); psr = SeriesRing.new("Q(y)"); puts "psr: " + str(psr); puts; one = psr.one(); puts "one: " + str(one); #puts; zero = psr.zero(); puts "zero: " + str(zero); puts; r1 = psr.random(4); puts "r1: " + str(r1); #puts; #puts "r1: " + str(r1); #puts; puts "r1-r1: " + str(r1-r1); puts; r2 = psr.random(4); puts "r2: " + str(r2); #puts; #puts "r2: " + str(r2); #puts; puts "r2-r2: " + str(r2-r2); puts; #exit(); r3 = r1 + r2; puts "r3: " + str(r3); puts; r4 = r1 * r2 + one; puts "r4: " + str(r4); puts; e = psr.exp(); puts "e: " + str(e); puts; r5 = r1 * r2 + e; puts "r5: " + str(r5); puts; #puts "psr.gens: ", [ str(i) for i in psr.gens() ]; one,y = psr.gens(); puts "y: " + str(y); puts; r6 = one - y; puts "r6: " + str(r6); puts; r7 = one / r6; puts "r7: " + str(r7); puts; s = psr.sin(); puts "s: " + str(s); puts; r8 = psr.gcd(y,s); puts "r8: " + str(r8); puts; s1 = s.evaluate( QQ(0) ); puts "s1: " + str(s1); puts; c = psr.cos(); puts "c: " + str(c); puts; c1 = c.evaluate( QQ(0) ); puts "c1: " + str(c1); puts; s2c2 = s*s+c*c; # sin^2 + cos^2 = 1 puts "s2c2: " + str(s2c2); puts; # # floating point examples # dr = SeriesRing.new("",nil,nil,DD()); puts "dr: " + str(dr); puts; de = dr.exp(); puts "de: " + str(de); puts; d0 = de.evaluate( DD(0) ); puts "d0: " + str(d0); #puts; d1 = de.evaluate( DD(0.5) ); puts "d1: " + str(d1); #puts; d01 = de.evaluate( DD(0.000000000000000001) ); puts "d01: " + str(d01); puts; #def f(a) # return a*a; #end # use lambdas: f = lambda { |a| a*a }; ps = psr.create(f); puts "ps: " + str(ps); puts; g = lambda { |a| a+a }; ps1 = psr.create(g); puts "ps1: " + str(ps1); puts; ps2 = ps * ps1; puts "ps2: " + str(ps2); puts; #exit(); h = lambda { |a| psr.ring.coFac.fromInteger( 3*a ) }; ps3 = psr.create(nil,h); puts "ps3: " + str(ps3); puts; ps4 = ps3 * ps1; puts "ps4: " + str(ps4); puts; # does not work, since get() is not known #def k(a) # if a > 0 # return get(a-1).multiply( psr.ring.coFac.fromInteger( 2*a ) ); # else # return psr.ring.coFac.fromInteger( 2*a ); # end #end #no#ps5 = psr.create(jfunc=k); #no#puts "ps5: ", ps5; #no#puts; class Mcoeff < Coefficients def initialize(cofac) super(); @coFac = cofac; end def generate(i) if i == 0 return @coFac.getZERO(); else if i == 1 return @coFac.getONE(); else c = get( i-2 ).negate(); return c.divide( @coFac.fromInteger(i) ).divide( @coFac.fromInteger(i-1) ); end end end end ps6 = psr.create(nil,nil, Mcoeff.new(psr.ring.coFac) ); puts "ps6: " + str(ps6); puts; ps7 = ps6 - s; puts "ps7: " + str(ps7); puts; #exit(); class Cosmap include UnivPowerSeriesMap # for interfaces use Module notations def initialize(cofac) @coFac = cofac; end def map(ps) return ps.negate().integrate( @coFac.getZERO() ).integrate( @coFac.getONE() ); end end ps8 = psr.fixPoint( Cosmap.new( psr.ring.coFac ) ); puts "ps8: " + str(ps8); puts; ps9 = ps8 - c; puts "ps9: " + str(ps9); puts; #exit(); # conversion from polynomials pr = Ring.new("Q(y) L"); puts "pr: " + str(pr); puts; one,yp = pr.gens(); p1 = one; p2 = one - yp; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; puts "p1: " + str(p1); puts "p2: " + str(p2); puts "ps1: " + str(ps1); puts "ps2: " + str(ps2); puts "ps3: " + str(ps3); puts; p1 = one * 2 + yp**3 - yp**5; p2 = one - yp**2 + yp**4; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; ps4 = ps3.integrate( QQ(1) ); ps5 = ps3.differentiate(); puts "p1: " + str(p1); puts "p2: " + str(p2); puts "ps1: " + str(ps1); puts "ps2: " + str(ps2); puts "ps3: " + str(ps3); puts "ps4: " + str(ps4); puts "ps5: " + str(ps5); puts; #exit(); java-algebra-system-2.7.200/examples/powerseries_multi.py000066400000000000000000000077351445075545500235230ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, DD, Ring from jas import MultiSeriesRing, MPS from jas import startLog from edu.jas.ps import MultiVarCoefficients from edu.jas.ps import MultiVarPowerSeriesMap # example for power series # # rational number examples # psr = MultiSeriesRing("Q(x,y,z)",truncate=4); print "psr:", psr; print; one = psr.one(); print "one:", one; print; zero = psr.zero(); print "zero:", zero; print; r1 = psr.random(4); print "r1:", r1; print; print "r1:", r1; print; print "r1-r1:", r1-r1; print; r2 = psr.random(4); print "r2:", r2; print; print "r2:", r2; print; print "r2-r2:", r2-r2; print; #sys.exit(); r3 = r1 + r2; print "r3:", r3; print; r4 = r1 * r2 + one; print "r4:", r4; print; e = psr.exp(1); print "e:", e; print; r5 = r1 * r2 + e; print "r5:", r5; print; #print "psr.gens: ", [ str(i) for i in psr.gens() ]; [one,x,y,z] = psr.gens(); print "x:", x; print "y:", y; print "z:", z; print; r6 = one - y; print "r6:", r6; print; r7 = one / r6; print "r7:", r7; print; s = psr.sin(1); print "s:", s; print; r8 = psr.gcd(y,s); print "r8:", r8; print; ## s1 = s.evaluate( QQ(0) ); ## print "s1:", s1; ## print; r9 = psr.random(4); print "r9: " + str(r9); print; e = r9.evaluate( [QQ(0), QQ(0), QQ(0)] ); print "e: " + str(e); print; c = psr.cos(1); print "c:", c; print; ## c1 = c.evaluate( QQ(0) ); ## print "c1:", c1; ## print; s2c2 = s*s+c*c; # sin^2 + cos^2 = 1 print "s2c2:", s2c2; print; #sys.exit(); # conversion from polynomials pr = Ring("Q(x,y,z) L"); print "pr:", pr; print; [one,xp,yp,zp] = pr.gens(); p1 = one; p2 = one - yp; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; print "p1:", p1; print "p2:", p2; print "ps1:", ps1; print "ps2:", ps2; print "ps3:", ps3; print; p1 = one * 2 + yp**3 - yp**5; p2 = one - yp**2 + yp**4; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; ps4 = ps3.integrate( QQ(1), 1 ); ps5 = ps3.differentiate(1); print "p1:", p1; print "p2:", p2; print "ps1:", ps1; print "ps2:", ps2; print "ps3:", ps3; print "ps4:", ps4; print "ps5:", ps5; print; #sys.exit(); # # floating point examples # dr = MultiSeriesRing(cofac=DD(),names=psr.ring.polyRing().getVars(),truncate=psr.ring.truncate()); print "dr:", dr; print; de = dr.exp(1); print "de:", de; print; def f(a): return a.totalDeg(); ps = psr.create(f); print "ps:", ps; print; def g(a): return a.maxDeg(); ps1 = psr.create(g); print "ps1:", ps1; print; ps2 = ps * ps1; print "ps2:", ps2; print; def h(a): return psr.ring.coFac.fromInteger( 2*a.maxDeg() ); ps3 = psr.create(jfunc=h); print "ps3:", ps3; print; ps4 = ps3 * ps1; print "ps4:", ps4; print; def k(a): if a.signum() > 0: r = psr.ring.coFac.fromInteger( 2*a.totalDeg() ); else: r = psr.ring.coFac.getONE(); #print "r: ", r; return r; ps5 = MPS(psr.ring.coFac,psr.ring.getVars(),f=k); print "ps5:", ps5; print; #sys.exit(); class coeff( MultiVarCoefficients ): def __init__(self,r): MultiVarCoefficients.__init__(self,r); self.coFac = r.coFac; def generate(self,i): #print "i: ", i; if i.signum() < 0: return self.coFac.getZERO(); else: if i.isZERO(): return self.coFac.getONE(); else: c = self.coFac.getONE(); #self.get( i-1 ).negate(); return c.divide( self.coFac.fromInteger(i.totalDeg()) ).divide( self.coFac.fromInteger(i.totalDeg()-1) ); ps6 = psr.create( clazz=coeff(psr.ring) ); print "ps6:", ps6; print; ps7 = ps6 - s; print "ps7:", ps7; print; #sys.exit(); class cosmap( MultiVarPowerSeriesMap ): def __init__(self,cofac): self.coFac = cofac; def map(self,ps): return ps.negate().integrate( self.coFac.getZERO(), 1 ).integrate( self.coFac.getONE(), 1 ); ps8 = psr.fixPoint( cosmap( psr.ring.coFac ) ); print "ps8:", ps8; print; ps9 = ps8 - c; print "ps9:", ps9; print; java-algebra-system-2.7.200/examples/powerseries_multi.rb000066400000000000000000000111741445075545500234660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # examples for power series # rational number examples # psr = MultiSeriesRing.new("Q(x,y,z)",truncate=4); puts "psr: " + str(psr); puts; one = psr.one(); puts "one: " + str(one); #puts; zero = psr.zero(); puts "zero: " + str(zero); puts; r1 = psr.random(4); puts "r1: " + str(r1); #puts; puts "r1: " + str(r1); #puts; puts "r1-r1: " + str(r1-r1); puts; r2 = psr.random(4); puts "r2: " + str(r2); #puts; puts "r2: " + str(r2); #puts; puts "r2-r2: " + str(r2-r2); puts; #sys.exit(); r3 = r1 + r2; puts "r3: " + str(r3); puts; r4 = r1 * r2 + one; puts "r4: " + str(r4); puts; e = psr.exp(1); puts "e: " + str(e); puts; r5 = r1 * r2 + e; puts "r5: " + str(r5); puts; #puts "psr.gens: ", [ str(i) for i in psr.gens() ]; one,x,y,z = psr.gens(); puts "x: " + str(x); puts "y: " + str(y); puts "z: " + str(z); puts; r6 = one - y; puts "r6: " + str(r6); puts; r7 = one / r6; puts "r7: " + str(r7); puts; s = psr.sin(1); puts "s: " + str(s); puts; r8 = psr.gcd(y,s); puts "r8: " + str(r8); puts; ## s1 = s.evaluate( QQ(0) ); ## puts "s1: " + str(s1); ## puts; r9 = psr.random(4); puts "r9: " + str(r9); puts; e = r9.evaluate( [QQ(1), QQ(0), QQ(1,2)] ); puts "e: " + str(e); puts; c = psr.cos(1); puts "c: " + str(c); puts; ## c1 = c.evaluate( QQ(0) ); ## puts "c1: " + str(c1); ## puts; s2c2 = s*s + c*c; # sin^2 + cos^2 = 1 puts "s2c2: " + str(s2c2); puts "s2c2 == 1: " + str(s2c2.isONE()); puts; # conversion from polynomials pr = Ring.new("Q(x,y,z) L"); puts "pr: " + str(pr); puts; one,xp,yp,zp = pr.gens(); p1 = one; p2 = one - yp; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; puts "p1: " + str(p1); puts "p2: " + str(p2); puts "ps1: " + str(ps1); puts "ps2: " + str(ps2); puts "ps3: " + str(ps3); puts; p1 = one * 2 + yp**3 - yp**5; p2 = one - yp**2 + yp**4; ps1 = psr.fromPoly(p1); ps2 = psr.fromPoly(p2); # rational function as power series: ps3 = ps1 / ps2; ps4 = ps3.integrate( QQ(1), 1 ); ps5 = ps3.differentiate(1); puts "p1: " + str(p1); puts "p2: " + str(p2); puts "ps1: " + str(ps1); puts "ps2: " + str(ps2); puts "ps3: " + str(ps3); puts "ps4: " + str(ps4); puts "ps5: " + str(ps5); puts; #exit(); # # floating point examples # #dr = MultiSeriesRing.new(cofac=DD(),names=psr.ring.polyRing().getVars(),truncate=psr.ring.truncate()); dr = MultiSeriesRing.new("",psr.ring.truncate(),nil,DD(),psr.ring.polyRing().getVars()); puts "dr: " + str(dr); puts; de = dr.exp(1); puts "de: " + str(de); puts; # use lambdas: # type(a) == ExpVector f = lambda { |a| a.getVal(0) * a.getVal(1) * a.getVal(2) }; ps = psr.create(f); puts "ps: " + str(ps); puts; # type(a) == ExpVector g = lambda { |a| a.totalDeg() }; ps1 = psr.create(g); puts "ps1: " + str(ps1); puts; ps2 = ps * ps1; puts "ps2: " + str(ps2); puts; h = lambda { |a| psr.ring.coFac.fromInteger( 3 * a.totalDeg() ) }; ps3 = psr.create(nil,h); puts "ps3: " + str(ps3); puts; ps4 = ps3 * ps1; puts "ps4: " + str(ps4); puts; #exit(); # does not work, since get() is not known #def k(a) # if a > 0 # return get(a-1).multiply( psr.ring.coFac.fromInteger( 2*a ) ); # else # return psr.ring.coFac.fromInteger( 2*a ); # end #end #no#ps5 = psr.create(jfunc=k); #no#puts "ps5: ", ps5; #no#puts; class Mycoeff < MultiVarCoefficients def initialize(ring,ifunc=nil,jfunc=nil) super(ring); @coFac = ring.coFac; @ifunc = ifunc; @jfunc = jfunc; end def generate(i) # type(i) == ExpVector if i.signum() <= 0 return @coFac.getONE(); else dep = i.dependencyOnVariables(); #if dep.length == 0 # return @coFac.getZERO(); #end i1 = i.subst( dep[0], i.getVal(dep[0])-1 ); # 0 <= i1 < i c = get( i1 ).negate(); c = c.divide( @coFac.fromInteger(i.maxDeg()) ).sum( @coFac.fromInteger(i.totalDeg()-1) ); #puts "c: " + str(c) + " i: " + str(i); return c; end end end ps6 = psr.create(nil,nil, Mycoeff.new(psr.ring) ); puts "ps6: " + str(ps6); puts; ps7 = ps6*2 + s - ps6 - ps6; puts "ps7: " + str(ps7); puts "ps7 == s: " + str(ps7 == s); puts; #exit(); class Cosmap include MultiVarPowerSeriesMap # for interfaces use Module notations def initialize(cofac) @coFac = cofac; end def map(ps) return ps.negate().integrate( @coFac.getZERO(), 1 ).integrate( @coFac.getONE(), 1 ); end end ps8 = psr.fixPoint( Cosmap.new( psr.ring.coFac ) ); puts "ps8: " + str(ps8); puts; ps9 = ps8 - c; puts "ps9: " + str(ps9); puts "ps9 == 0: " + str(ps9.isZERO()); puts; #exit(); java-algebra-system-2.7.200/examples/pppj2006.py000066400000000000000000000012321445075545500212050ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, ZZ from jas import startLog # pppj 2006 paper examples #r = Ring( "Z(x1,x2,x3) L" ); r = PolyRing( ZZ(), "x1,x2,x3", PolyRing.lex ); print "Ring: " + str(r); print; #unused: ps = """ ( ( 3 x1^2 x3^4 + 7 x2^5 - 61 ) ) """; f = 3 * x1**2 * x3**4 + 7 * x2**5 - 61; print "f = " + str(f); print; #id = r.ideal( ps ); id = r.ideal( "", [f] ); print "Ideal: " + str(id); print; #startLog(); pps = """ 3 x1^2 x3^4 + 7 x2^5 - 61 """; ri = r.ring; print "ri = " + str(ri); print pol = id.pset; print "pol = " + str(pol); print pol = ri.parse( pps ); print "pol = " + str(pol); print java-algebra-system-2.7.200/examples/pppj2006.rb000066400000000000000000000007131445075545500211630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # pppj 2006 paper examples r = PolyRing.new( ZZ(), "x1,x2,x3", PolyRing.lex ); puts "Ring: " + str(r); puts; f = 3 * x1**2 * x3**4 + 7 * x2**5 - 61; puts "f = " + str(f); puts; id = r.ideal( "", [f] ); puts "Ideal: " + str(id); puts; ri = r.ring; puts "ri = " + str(ri); pol = id.pset; puts "pol = " + str(pol); puts pol = ri.parse( str(f) ); puts "pol = " + str(pol); puts; #startLog(); java-algebra-system-2.7.200/examples/preimage.py000066400000000000000000000020461445075545500215210ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring from edu.jas import application rs = """ # polynomial ring: Rat(x1,x2,x3,y1,y2) G|3| """; ps = """ ( ( y1 + y2 - 1 ), ( x1 - y1^2 - y1 - y2 ), ( x2 - y1 - y2^2 ), ( x3 - y1 y2 ) ) """; r = Ring( rs ); print "Ring: " + str(r); i = r.ideal( ps ); print "Ideal: " + str(i); g = i.GB(); print "seq GB:", g; rsi = """ # polynomial ring: Rat(x1,x2,x3) G """; ri = Ring( rsi ); print "Ring: " + str(ri); y = application.Ideal(g.pset).intersect(ri.ring); len = y.list.size(); print "seq intersect y: ", y; rs = """ # polynomial ring: Rat(y1,y2,x1,x2,x3) G|2| """; ps = """ ( ( y1 + y2 - 1 ), ( x1 - y1^2 - y1 - y2 ), ( x2 - y1 - y2^2 ), ( x3 - y1 y2 ) ) """; r = Ring( rs ); print "Ring: " + str(r); i = r.ideal( ps ); print "Ideal: " + str(i); g = i.GB(); print "seq GB:", g; rsb = """ # polynomial ring: Rat(y1,y2) G """; rb = Ring( rsb ); print "Ring: " + str(rb); print y = application.Ideal(g.pset).intersect(rb.ring); len = y.list.size(); print "seq intersect y: ", y; print java-algebra-system-2.7.200/examples/primary-decomp-charp.py000066400000000000000000000015701445075545500237540ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD, RF, GF from jas import terminate, startLog # polynomial examples: ideal primary decomposition cr = PolyRing(GF(5),"c",PolyRing.lex); print "coefficient Ring: " + str(cr); rf = RF(cr); print "coefficient quotient Ring: " + str(rf.ring); r = PolyRing(rf,"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,c,x,y,z] = r.gens(); f1 = (x**2 - 2); #**2 f2 = (y**2 - c)**5; f3 = (z**2 - 2 * c); #**5 print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); Q = F.primaryDecomp(); t = System.currentTimeMillis() - t; print "Q = ", Q; print; print "primary decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/primary-decomp-charp.rb000066400000000000000000000017261445075545500237320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal prime decomposition in char p > 0, inseparable cases cr = PolyRing.new(GF(5),"c",PolyRing.lex); puts "coefficient Ring: " + str(cr); rf = RF(cr); puts "coefficient quotient Ring: " + str(rf.ring); r = PolyRing.new(rf,"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,c,x,y,z = r.gens(); puts one,c,x,y,z; #exit(); f1 = (x**2 - 2); #**2; f2 = (y**2 - c)**5; f3 = (z**2 - 2 * c); #**5; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f1,f2,f3] ); #F = r.ideal( "", list=[f1,f3] ); #F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); P = F.primaryDecomp(); t = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/primary-decomp.py000066400000000000000000000014041445075545500226550ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: ideal primary decomposition #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = (y**2 - x)**2; f3 = z**2 - x ; #print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); Q = F.primaryDecomp(); t = System.currentTimeMillis() - t; print "Q = ", Q; print; print "primary decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/primary-decomp.rb000066400000000000000000000014421445075545500226320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal primary decomposition in char 0 r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,x,y,z = r.gens(); puts one,x,y,z; #exit(); f1 = (x**2 - 2)**2; f2 = (y**2 - x)**2; f3 = (z**2 - x); puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f1,f2,f3] ); #F = r.ideal( "", list=[f1,f3] ); #F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); P = F.primaryDecomp(); t = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp-charp.py000066400000000000000000000020161445075545500234010ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, ZM, RF, GF from jas import terminate, startLog # polynomial examples: ideal prime decomposition in char p > 0, inseparable cases cr = PolyRing(GF(5),"c",PolyRing.lex); print "coefficient Ring: " + str(cr); rf = RF(cr); print "coefficient quotient Ring: " + str(rf.ring); r = PolyRing(rf,"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,c,x,y,z] = r.gens(); print one,c,x,y,z; #sys.exit(); f1 = (x**2 - 2); #**2; f2 = (y**2 - c)**5; f3 = (z**2 - 2 * c); #**5; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; #print "f4 = ", f4; print; F = r.ideal( list=[f1,f2,f3] ); #F = r.ideal( list=[f1,f3] ); #F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t = System.currentTimeMillis() - t; print "P = ", P; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp-charp.rb000066400000000000000000000017301445075545500233560ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal prime decomposition in char p > 0, inseparable cases cr = PolyRing.new(GF(5),"c",PolyRing.lex); puts "coefficient Ring: " + str(cr); rf = RF(cr); puts "coefficient quotient Ring: " + str(rf.ring); r = PolyRing.new(rf,"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic one,c,x,y,z = r.gens(); puts one,c,x,y,z; #sys.exit(); f1 = (x**2 - 2); #**2; f2 = (y**2 - c)**5; f3 = (z**2 - 2 * c); #**5; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f1,f2,f3] ); #F = r.ideal( "", list=[f1,f3] ); #F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp-h.py000066400000000000000000000026131445075545500225360ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import PolyRing, EF, QQ, ZZ, RF, ZM from jas import terminate, startLog # polynomial examples: ideal prime decomposition # TRANSACTIONS OF THE AMERICAN MATHEMATICAL SOCIETY # Volume 296, Number 2. August 1986 # ON THE DEPTH OF THE SYMMETRIC ALGEBRA # J. HERZOG M. E. ROSSI AND G. VALLA #r = PolyRing(QQ(),"x,t,z,y",PolyRing.lex); #r = PolyRing(QQ(),"x,y,t,z",PolyRing.lex); #r = EF(QQ()).extend("x").polynomial("y,z,t").build(); #,PolyRing.lex); #c = PolyRing(QQ(),"t,y",PolyRing.lex); #c = PolyRing(ZM(32003,0,True),"t",PolyRing.lex); #c = PolyRing.new(GF(32003),"t",PolyRing.lex); c = PolyRing(ZZ(),"t",PolyRing.lex); r = PolyRing(RF(c),"z,y,x",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,t,z,y,x] = r.gens(); print "one = ", one; print "x = ", x; print "y = ", y; print "z = ", z; print "t = ", t; f1 = x**3 - y**7; f2 = x**2 * y - x * t**3 - z**6; f3 = z**2 - t**3; #f3 = z**19 - t**23; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); P = F.radicalDecomp(); #P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; print "P = ", P; print; print "prime/radical decomp time =", t1, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp-h.rb000066400000000000000000000025721445075545500225150ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal prime decomposition # TRANSACTIONS OF THE AMERICAN MATHEMATICAL SOCIETY # Volume 296, Number 2. August 1986 # ON THE DEPTH OF THE SYMMETRIC ALGEBRA # J. HERZOG M. E. ROSSI AND G. VALLA #r = PolyRing.new(QQ(),"x,t,z,y",PolyRing.lex); #r = PolyRing.new(QQ(),"x,y,t,z",PolyRing.lex); #r = EF.new(QQ()).extend("x").polynomial("y,z,t").build(); #,PolyRing.lex); #c = PolyRing.new(QQ(),"t,y",PolyRing.lex); #c = PolyRing.new(ZM(32003,0,True),"t",PolyRing.lex); #c = PolyRing.new(GF(32003),"t",PolyRing.lex); c = PolyRing.new(ZZ(),"t",PolyRing.lex); r = PolyRing.new(RF(c),"z,y,x",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,t,z,y,x = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts "t = " + str(t); f1 = x**3 - y**7; f2 = x**2 * y - x * t**3 - z**6; f3 = z**2 - t**3; #f3 = z**19 - t**23; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", list=[f1,f2,f3] ); puts "F = " + str(F); puts; #sys.exit(); startLog(); t = System.currentTimeMillis(); P = F.radicalDecomp(); #P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "prime/radical decomp time = " + str(t1) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp.py000066400000000000000000000013761445075545500223160ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: ideal prime decomposition #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = y**3 - x; f3 = z**2 - y * x; #print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; print "P = ", P; print; print "prime decomp time =", t1, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp.rb000066400000000000000000000013021445075545500222560ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" #startLog(); # polynomial examples: ideal prime decomposition r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)**2; f2 = y**3 - x; f3 = z**2 - y * x; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; #F = r.ideal( "", [f1,f2,f3] ); F = r.ideal( "", [f2,f3] ); puts "F = ", F; puts; startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); t1 = System.currentTimeMillis() - t; puts "P = " + str(P); puts; puts "prime decomp time = " + str(t1) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp_algeb_trans-plain.py000066400000000000000000000020401445075545500257450ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import PolyRing, QQ, AN, RF from jas import terminate, startLog # polynomial examples: prime/primary decomposition in Q[w2,x,wx,y,z] Q = PolyRing(QQ(),"w2,x,wx,y,z",PolyRing.lex); print "Q = " + str(Q); [e,w2,x,wx,y,z] = Q.gens(); print "e = " + str(e); print "w2 = " + str(w2); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print "z = " + str(z); print; w1 = w2**2 - 2; w2 = wx**2 - x; f1 = ( y**2 - x ) * ( y**2 - 2 ); #f1 = ( y**2 - x )**3 * ( y**2 - 2 )**2; f2 = ( z**2 - y**2 ); print "w1 = ", w1; print "w2 = ", w2; print "f1 = ", f1; print "f2 = ", f2; print; F = Q.ideal( list=[w1,w2,f1,f2] ); print "F = ", F; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); #P = F.primaryDecomp(); t1 = System.currentTimeMillis() - t; print "P = ", P; print; print "prime/primary decomp time =", t1, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp_algeb_trans-plain.rb000066400000000000000000000017431445075545500257310ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" #startLog(); # polynomial examples: prime / primary decomposition in Q[w2,x,wx,y,z] Q = PolyRing.new(QQ(),"w2,x,wx,y,z",PolyRing.lex); puts "Q = " + str(Q); e,w2,x,wx,y,z = Q.gens(); puts "e = " + str(e); puts "w2 = " + str(w2); puts "x = " + str(x); puts "wx = " + str(wx); puts "y = " + str(y); puts "z = " + str(z); w1 = w2**2 - 2; w2 = wx**2 - x; f1 = ( y**2 - x ) * ( y**2 - 2 ); #f1 = ( y**2 - x ) * ( y**2 - 2 )**2; f2 = ( z**2 - y**2 ); puts "w1 = " + str(w1); puts "w2 = " + str(w2); puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts; #sys.exit(); startLog(); F = Q.ideal( "", [w1,w2,f1,f2] ); puts "F = ", F; puts; #sys.exit(); t = System.currentTimeMillis(); P = F.primeDecomp(); #P = F.primaryDecomp(); t1 = System.currentTimeMillis() - t; puts "P = ", P; puts; puts "prime/primary decomp time = " + str(t1) + " milliseconds"; puts; puts "F = ", F; puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp_algeb_trans.py000066400000000000000000000042021445075545500246460ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import PolyRing, QQ, AN, RF from jas import terminate, startLog # polynomial examples: prime/primary decomposition in Q(sqrt(2))(x)(sqrt(x))[y,z] Q = PolyRing(QQ(),"w2",PolyRing.lex); print "Q = " + str(Q); [e,a] = Q.gens(); #print "e = " + str(e); print "a = " + str(a); root = a**2 - 2; print "root = " + str(root); Q2 = AN(root,field=True); print "Q2 = " + str(Q2.factory()); [one,w2] = Q2.gens(); #print "one = " + str(one); #print "w2 = " + str(w2); print; Qp = PolyRing(Q2,"x",PolyRing.lex); print "Qp = " + str(Qp); [ep,wp,ap] = Qp.gens(); #print "ep = " + str(ep); #print "wp = " + str(wp); #print "ap = " + str(ap); print; Qr = RF(Qp); print "Qr = " + str(Qr.factory()); [er,wr,ar] = Qr.gens(); #print "er = " + str(er); #print "wr = " + str(wr); #print "ar = " + str(ar); print; Qwx = PolyRing(Qr,"wx",PolyRing.lex); print "Qwx = " + str(Qwx); [ewx,wwx,ax,wx] = Qwx.gens(); #print "ewx = " + str(ewx); print "ax = " + str(ax); #print "wwx = " + str(wwx); print "wx = " + str(wx); print; rootx = wx**2 - ax; print "rootx = " + str(rootx); Q2x = AN(rootx,field=True); print "Q2x = " + str(Q2x.factory()); [ex2,w2x2,ax2,wx] = Q2x.gens(); #print "ex2 = " + str(ex2); #print "w2x2 = " + str(w2x2); #print "ax2 = " + str(ax2); #print "wx = " + str(wx); print; Yr = PolyRing(Q2x,"y,z",PolyRing.lex) print "Yr = " + str(Yr); [e,w2,x,wx,y,z] = Yr.gens(); print "e = " + str(e); print "w2 = " + str(w2); print "x = " + str(x); print "wx = " + str(wx); print "y = " + str(y); print "z = " + str(z); print; f1 = ( y**2 - x ) * ( y**2 - 2 ); #f1 = ( y**2 - x )**3 * ( y**2 - 2 )**2; f2 = ( z**2 - y**2 ); print "f1 = ", f1; print "f2 = ", f2; print; F = Yr.ideal( list=[f1,f2] ); print "F = ", F; print; #sys.exit(); startLog(); t = System.currentTimeMillis(); P = F.primeDecomp(); #P = F.primaryDecomp(); t1 = System.currentTimeMillis() - t; print "P = ", P; print; print "prime/primary decomp time =", t1, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/prime-decomp_algeb_trans.rb000066400000000000000000000040141445075545500246220ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: prime / primary decomposition in Q(sqrt(2))(x)(sqrt(x))[y,z] Q = PolyRing.new(QQ(),"w2",PolyRing.lex); puts "Q = " + str(Q); e,a = Q.gens(); #puts "e = " + str(e); puts "a = " + str(a); root = a**2 - 2; puts "root = " + str(root); Q2 = AN(root,field=true); puts "Q2 = " + str(Q2.factory()); one,w2 = Q2.gens(); #puts "one = " + str(one); #puts "w2 = " + str(w2); puts; Qp = PolyRing.new(Q2,"x",PolyRing.lex); puts "Qp = " + str(Qp); ep,wp,ap = Qp.gens(); #puts "ep = " + str(ep); #puts "wp = " + str(wp); #puts "ap = " + str(ap); puts; Qr = RF(Qp); puts "Qr = " + str(Qr.factory()); er,wr,ar = Qr.gens(); #puts "er = " + str(er); #puts "wr = " + str(wr); #puts "ar = " + str(ar); puts; Qwx = PolyRing.new(Qr,"wx",PolyRing.lex); puts "Qwx = " + str(Qwx); ewx,wwx,ax,wx = Qwx.gens(); #puts "ewx = " + str(ewx); puts "ax = " + str(ax); #puts "wwx = " + str(wwx); puts "wx = " + str(wx); puts; rootx = wx**2 - ax; puts "rootx = " + str(rootx); Q2x = AN(rootx,field=true); puts "Q2x = " + str(Q2x.factory()); ex2,w2x2,ax2,wx = Q2x.gens(); #puts "ex2 = " + str(ex2); #puts "w2x2 = " + str(w2x2); #puts "ax2 = " + str(ax2); #puts "wx = " + str(wx); puts; Yr = PolyRing.new(Q2x,"y,z",PolyRing.lex) puts "Yr = " + str(Yr); e,w2,x,wx,y,z = Yr.gens(); puts "e = " + str(e); puts "w2 = " + str(w2); puts "x = " + str(x); puts "wx = " + str(wx); puts "y = " + str(y); puts "z = " + str(z); puts; f1 = ( y**2 - x ) * ( y**2 - 2 ); #f1 = ( y**2 - x ) * ( y**2 - 2 )**2; f2 = ( z**2 - y**2 ); puts "f1 = ", f1; puts "f2 = ", f2; puts; #sys.exit(); startLog(); F = Yr.ideal( "", [f1,f2] ); puts "F = ", F; puts; #sys.exit(); t = System.currentTimeMillis(); P = F.primeDecomp(); #P = F.primaryDecomp(); t1 = System.currentTimeMillis() - t; puts "P = ", P; puts; puts "prime/primary decomp time = " + str(t1) + " milliseconds"; puts; puts "F = ", F; puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/primes.py000066400000000000000000000016571445075545500212360ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #import sys; #from jas import startLog, terminate from edu.jas.arith import PrimeList # example for prime numbers # pl = PrimeList(PrimeList.Range.small); print "pl: " + str(pl); print; pp = ""; for i in range(0,pl.size()+10): pp = pp + " " + str(pl.get(i)) print "pp: " + pp; print; pl = PrimeList(PrimeList.Range.low); print "pl: " + str(pl); print; pp = ""; for i in range(0,pl.size()+10): pp = pp + " " + str(pl.get(i)) print "pp: " + pp; print; pl = PrimeList(PrimeList.Range.medium); print "pl: " + str(pl); print; pp = ""; for i in range(0,pl.size()+10): pp = pp + " " + str(pl.get(i)) print "pp: " + pp; print; pl = PrimeList(PrimeList.Range.large); print "pl: " + str(pl); print; pp = ""; for i in range(0,pl.size()+10): pp = pp + " " + str(pl.get(i)) print "pp: " + pp; print; #pl = PrimeList(PrimeList.Range.mersenne); #print "pl: " + str(pl); #print; java-algebra-system-2.7.200/examples/primes.rb000066400000000000000000000015651445075545500212070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example for prime numbers # pl = PrimeList.new(PrimeList::Range.small); puts "pl: " + str(pl); puts; pp = ""; for i in 0..pl.size()+10 do pp = pp + " " + str(pl.get(i)) end puts "pp: " + pp; puts; pl = PrimeList.new(PrimeList::Range.low); puts "pl: " + str(pl); puts; pp = ""; for i in 0..pl.size()+10 do pp = pp + " " + str(pl.get(i)) end puts "pp: " + pp; puts; pl = PrimeList.new(PrimeList::Range.medium); puts "pl: " + str(pl); puts; pp = ""; for i in 0..pl.size()+10 do pp = pp + " " + str(pl.get(i)) end puts "pp: " + pp; puts; pl = PrimeList.new(PrimeList::Range.large); puts "pl: " + str(pl); puts; pp = ""; for i in 0..pl.size()+10 do pp = pp + " " + str(pl.get(i)) end puts "pp: " + pp; puts; #pl = PrimeList.new(PrimeList::Range.mersenne); #puts "pl: " + str(pl); #puts; java-algebra-system-2.7.200/examples/quantumplane_rgb.py000066400000000000000000000025541445075545500233000ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableModule from jas import SolvableSubModule # Quantum plane example rsan = """ # not with twosidedGB, because of field AN[ (i) (i^2 + 1) ] (Y,X,x,y) G RelationTable ( ( y ), ( x ), ( {i} x y ) ( X ), ( Y ), ( {i} Y X ) ) """; rsc = """ # not supported for rightGB C(Y,X,x,y) G |2| C(Y,X,x,y) G RelationTable ( ( y ), ( x ), ( 0i1 x y ) ( X ), ( Y ), ( 0i1 Y X ) ) """; r = SolvableModule( rsc ); #r = SolvableModule( rsan ); print "SolvableModule: " + str(r); print; ps = """ ( ( ( x + 1 ), ( y ) ), ( ( x y ), ( 0 ) ), ( ( x - X ), ( x - X ) ), ( ( y - Y ), ( y - Y ) ) ) """; f = SolvableSubModule( r, ps ); print "SolvableSubModule: " + str(f); print; flg = f.leftGB(); print "seq left GB:", flg; print; if flg.isLeftGB(): print "is left GB"; else: print "is not left GB"; ftg = f.twosidedGB(); print "seq twosided GB:", ftg; print; if ftg.isLeftGB(): print "twosided GB is left GB"; else: print "twosided GB is not left GB"; if ftg.isRightGB(): print "twosided GB is right GB"; else: print "twosided GB is not right GB"; if ftg.isTwosidedGB(): print "is twosided GB"; else: print "is not twosided GB"; from jas import startLog startLog(); frg = f.rightGB(); print "seq right GB:", frg; print; if frg.isRightGB(): print "is right GB"; else: print "is not right GB"; java-algebra-system-2.7.200/examples/quantumplane_syz.py000066400000000000000000000023471445075545500233530ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableModule from jas import SolvableSubModule # Quantum plane example rsan = """ AN[ (i) (i^2 + 1) ] (Y,X,x,y) G RelationTable ( ( y ), ( x ), ( {i} x y ) ( X ), ( Y ), ( {i} Y X ) ) """; rsc = """ C(Y,X,x,y) G RelationTable ( ( y ), ( x ), ( 0i1 x y ) ( X ), ( Y ), ( 0i1 Y X ) ) """; r = SolvableModule( rsc ); #r = SolvableModule( rsan ); print "SolvableModule: " + str(r); print; ps = """ ( ( ( x + 1 ), ( y ) ), ( ( x y ), ( 0 ) ), ( ( x - X ), ( x - X ) ), ( ( y - Y ), ( y - Y ) ) ) """; # ( ( y^2 x ) ), # ( ( y^3 x^2 ) ) # ( ( x + 1 ) ), # ( ( x + 1 ), ( y ) ), # ( ( x y ), ( 0 ) ) f = SolvableSubModule( r, ps ); print "SolvableSubModule: " + str(f); print; #flg = f.leftGB(); #print "seq left GB Output:", flg; #print; ftg = f.twosidedGB(); print "seq twosided GB Output:", ftg; print; from edu.jas.gbufd import SolvableSyzygySeq; #from edu.jas.gbmod import ModSolvableGroebnerBase; s = SolvableSyzygySeq(r.ring.coFac).leftZeroRelations( ftg.mset ); #sl = ModuleList(f.pset.vars,f.pset.tord,s,f.pset.table); print "leftSyzygy:", s; print; if SolvableSyzygySeq(r.ring.coFac).isLeftZeroRelation(s,ftg.mset): print "is Syzygy"; else: print "is not Syzygy"; java-algebra-system-2.7.200/examples/radical-decomp.py000066400000000000000000000014121445075545500225700ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: ideal radical decomposition #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing(QQ(),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y,z] = r.gens(); f1 = (x**2 - 5)**2; f2 = (y**2 - 3)**3 * (y**2 - 5); f3 = z**3 - x * y; #print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp.rb000066400000000000000000000013441445075545500225470ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition #r = Ring.new( "Rat(x) L" ); #r = Ring.new( "Q(x) L" ); r = PolyRing.new(QQ(),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,x,y,z = r.gens(); f1 = (x**2 - 5)**2; f2 = (y**2 - 3)**3 * (y**2 - 5); f3 = z**3 - x * y; #puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp.py000066400000000000000000000015371445075545500237550ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, ZM, GF from jas import terminate, startLog # polynomial examples: ideal radical decomposition, dim > 0, char p separable r = PolyRing(GF(5),"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y,z] = r.gens(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; f2 = y**6 + 2 * x * y**4 + 3 * x**2 * y**2 + 4 * x**3; f2 = f2**5; f3 = z**10 - x**5; f4 = (y**2 - x)**3; #print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; #print "f4 = ", f4; print; F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp.rb000066400000000000000000000014621445075545500237250ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition, dim > 0, char p separable r = PolyRing.new(GF(5),"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,x,y,z = r.gens(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; f2 = y**6 + 2 * x * y**4 + 3 * x**2 * y**2 + 4 * x**3; f2 = f2**5; f3 = z**10 - x**5; f4 = (y**2 - x)**3; #puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_ex816.py000066400000000000000000000032741445075545500247100ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, ZM, GF, RF, AN from jas import terminate, startLog, noThreads # polynomial examples: ideal radical decomposition, modified from example 8.16 in GB book # noThreads(); # must be called very early prime = 5; cf = GF(prime); #cf = QQ(); ca = PolyRing(cf,"a",PolyRing.lex); #print "ca = " + str(ca); [ea,aa] = ca.gens(); print "ea = " + str(ea); print "aa = " + str(aa); print; #!#roota = aa**prime + 2; roota = aa**2 + 2; print "roota = " + str(roota); Q3a = AN(roota,field=True); print "Q3a = " + str(Q3a.factory()); ## Q3a = RF(ca); #print Q3a.gens(); [ea2,aa2] = Q3a.gens(); print "ea2 = " + str(ea2); print "aa2 = " + str(aa2); print; #cr = PolyRing(QQ(),"t",PolyRing.lex); cr = PolyRing(Q3a,"t",PolyRing.lex); print "coefficient Ring: " + str(cr); rf = RF(cr); print "coefficient quotient Ring: " + str(rf.ring.toScript()); r = PolyRing(rf,"x,y",PolyRing.lex); print "Ring: " + str(r); #print; #automatic: [one,a,t,x,y] = r.gens(); print "one = " + str(one); print "a = " + str(a); print "t = " + str(t); print "x = " + str(x); print "y = " + str(y); print; #f1 = x**prime - t; #f2 = y**prime - t; ##f1 = x**4 + t; ##f2 = y**4 + t; f1 = x**3 + t; f2 = y**3 + t; #f2 = f2**2; f3 = (y-x); f3 = f3**prime; print "f1 = ", f1; print "f2 = ", f2; #print "f3 = ", f3; print; F = r.ideal( list=[f1,f2] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); #R = F.primeDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_ex816.rb000066400000000000000000000031631445075545500246600ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition, modified from example 8.16 in GB book # noThreads(); # must be called very early prime = 5; cf = GF(prime); #cf = QQ(); ca = PolyRing.new(cf,"a",PolyRing.lex); #puts "ca = " + str(ca); ea,aa = ca.gens(); puts "ea = " + str(ea); puts "aa = " + str(aa); puts; #!#roota = aa**prime + 2; roota = aa**2 + 2; puts "roota = " + str(roota); Q3a = AN(roota,field=true); puts "Q3a = " + str(Q3a.factory()); ## Q3a = RF(ca); #puts Q3a.gens(); ea2,aa2 = Q3a.gens(); puts "ea2 = " + str(ea2); puts "aa2 = " + str(aa2); puts; #cr = PolyRing.new(QQ(),"t",PolyRing.lex); cr = PolyRing.new(Q3a,"t",PolyRing.lex); puts "coefficient Ring: " + str(cr); rf = RF(cr); puts "coefficient quotient Ring: " + str(rf.ring.toScript()); r = PolyRing.new(rf,"x,y",PolyRing.lex); puts "Ring: " + str(r); #puts; #automatic: one,a,t,x,y = r.gens(); #puts one,a,t,x,y; puts "one = " + str(one); puts "a = " + str(a); puts "t = " + str(t); puts "x = " + str(x); puts "y = " + str(y); puts; #f1 = x**prime - t; #f2 = y**prime - t; ##f1 = x**4 + t; ##f2 = y**4 + t; f1 = x**3 + t; f2 = y**3 + t; #f2 = f2**2; f3 = (y-x); f3 = f3**prime; puts "f1 = " + str(f1); puts "f2 = " + str(f2); #puts "f3 = " + str(f3); puts; F = r.ideal( "", list=[f1,f2] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); #R = F.primeDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_ex816_algeb.py000066400000000000000000000037301445075545500260370ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, ZM, RF, AN, GF from jas import terminate, startLog, noThreads # polynomial examples: ideal radical decomposition, example 8.16 in GB book, base field with p-th root # noThreads(); # must be called very early prime = 5; cf = GF(prime); #cf = QQ(); ca = PolyRing(cf,"t",PolyRing.lex); print "ca = " + str(ca); [ea,ta] = ca.gens(); print "ea = " + str(ea); print "ta = " + str(ta); print; Qpt = RF(ca); #print Qpt.gens(); [ea2,ta2] = Qpt.gens(); print "ea2 = " + str(ea2); print "ta2 = " + str(ta2); print; cr = PolyRing(Qpt,"wpt",PolyRing.lex); print "polynomial quotient ring: " + str(cr); [et2,t,wpt] = cr.gens(); print "et2 = " + str(et2); print "t = " + str(t); print "wpt = " + str(wpt); print; root = wpt**prime - ta2; af = AN(root,field=True); print "coefficient algebraic quotient ring: " + str(af.ring.toScript()); #print af.gens(); ##xx = AN(( wpt**5 + 4 * t ),True,PolyRing(RF(PolyRing(ZM(5),"t",PolyRing.lex)),"wpt",PolyRing.lex)) ##print "xx: " + str(xx.ring.toScript()); [one,t,wpt] = af.gens(); print "one = " + str(one); print "t = " + str(t); print "wpt = " + str(wpt); #print one,t,wpt; print; #sys.exit(); r = PolyRing(af,"x,y",PolyRing.lex); print "polynomial ring: " + str(r); #print; #automatic: [one,t,wpt,x,y] = r.gens(); #print one,t,wpt,x,y; print "one = " + str(one); print "t = " + str(t); print "wpt = " + str(wpt); print "x = " + str(x); print "y = " + str(y); print; f1 = x**prime - t; f2 = y**prime - t; f2 = f2**3; f3 = (y-x); f3 = f3**prime; print "f1 = ", f1; print "f2 = ", f2; #print "f3 = ", f3; print; F = r.ideal( list=[f1,f2] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); #R = F.primeDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_ex816_algeb.rb000066400000000000000000000035351445075545500260150ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition, example 8.16 in GB book, base field with p-th root # noThreads(); # must be called very early prime = 5; cf = GF(prime); #cf = QQ(); ca = PolyRing.new(cf,"t",PolyRing.lex); puts "ca = " + str(ca); ea,ta = ca.gens(); puts "ea = " + str(ea); puts "ta = " + str(ta); puts; Qpt = RF(ca); #puts Qpt.gens(); ea2,ta2 = Qpt.gens(); puts "ea2 = " + str(ea2); puts "ta2 = " + str(ta2); puts; cr = PolyRing.new(Qpt,"wpt",PolyRing.lex); puts "polynomial quotient ring: " + str(cr); et2,t,wpt = cr.gens(); puts "et2 = " + str(et2); puts "t = " + str(t); puts "wpt = " + str(wpt); puts; root = wpt**prime - ta2; af = AN(root,field=true); puts "coefficient algebraic quotient ring: " + str(af.ring.toScript()); #puts af.gens(); ##xx = AN(( wpt**5 + 4 * t ),True,PolyRing(RF(PolyRing(ZM(5),"t",PolyRing.lex)),"wpt",PolyRing.lex)) ##puts "xx: " + str(xx.ring.toScript()); one,t,wpt = af.gens(); puts "one = " + str(one); puts "t = " + str(t); puts "wpt = " + str(wpt); #puts one,t,wpt; puts; r = PolyRing.new(af,"x,y",PolyRing.lex); puts "polynomial ring: " + str(r); puts; #automatic: one,t,wpt,x,y = r.gens(); #puts one,t,wpt,x,y; puts "one = " + str(one); puts "t = " + str(t); puts "wpt = " + str(wpt); puts "x = " + str(x); puts "y = " + str(y); puts; f1 = x**prime - t; f2 = y**prime - t; f2 = f2**3; f3 = (y-x); f3 = f3**prime; puts "f1 = " + str(f1); puts "f2 = " + str(f2); #puts "f3 = " + str(f3); puts; F = r.ideal( "", list=[f1,f2] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); #R = F.primeDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_infin.py000066400000000000000000000021521445075545500251320ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, ZM, RF, GF from jas import terminate, startLog, noThreads # polynomial examples: ideal radical decomposition, inseparable cases, dim > 0 #noThreads(); # must be called very early cr = PolyRing(GF(5),"c",PolyRing.lex); print "coefficient Ring: " + str(cr); rf = RF(cr); print "coefficient quotient Ring: " + str(rf.ring); r = PolyRing(rf,"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,c,x,y,z] = r.gens(); print one,c,x,y,z; #sys.exit(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; f1 = (x**2 + 2)**2; f2 = (y**2 - x)**5; #f2 = f2**5; f3 = (z**2 - c)**5; f4 = (y**2 - x)**3; #print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; #print "f4 = ", f4; print; #F = r.ideal( list=[f1,f2,f3] ); F = r.ideal( list=[f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_infin.rb000066400000000000000000000020461445075545500251070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition, inseparable cases, dim > 0 #noThreads(); # must be called very early cr = PolyRing.new(GF(5),"c",PolyRing.lex); puts "coefficient Ring: " + str(cr); rf = RF(cr); puts "coefficient quotient Ring: " + str(rf.ring); r = PolyRing.new(rf,"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,c,x,y,z = r.gens(); puts one,c,x,y,z; #sys.exit(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; f1 = (x**2 + 2)**2; f2 = (y**2 - x)**5; #f2 = f2**5; f3 = (z**2 - c)**5; f4 = (y**2 - x)**3; #puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; #F = r.ideal( "", list=[f1,f2,f3] ); F = r.ideal( "", list=[f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_infin_0dim.py000066400000000000000000000021751445075545500260500ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, ZM, GF, RF from jas import terminate, startLog # polynomial examples: ideal radical decomposition, inseparable case, 0-dim cr = PolyRing(GF(5),"c",PolyRing.lex); print "coefficient Ring: " + str(cr); rf = RF(cr); print "coefficient quotient Ring: " + str(rf); r = PolyRing(rf,"x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,c,x,y,z] = r.gens(); print one,c,x,y,z; #sys.exit(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; #f2 = y**6 + 2 * x * y**4 + 4 * x**2 * y**2 + 4 * x**3; #f2 = y**6 + 2 * x * y**4 + 3 * x**2 * y**2 + 4 * x**3; f1 = (x**2 + 2)**2; f2 = (y**2 + 2)**3; #f2 = f2**5; f3 = z**10 - c**5; f4 = (y**2 - x)**3; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; #print "f4 = ", f4; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "decomp time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/radical-decomp_charp_infin_0dim.rb000066400000000000000000000021001445075545500260070ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: ideal radical decomposition, inseparable case, 0-dim cr = PolyRing.new(GF(5),"c",PolyRing.lex); puts "coefficient Ring: " + str(cr); rf = RF(cr); puts "coefficient quotient Ring: " + str(rf); r = PolyRing.new(rf,"x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,c,x,y,z = r.gens(); puts one,c,x,y,z; #sys.exit(); #f1 = (x**2 - 5)**2; #f1 = (y**10 - x**5)**3; #f2 = y**6 + 2 * x * y**4 + 4 * x**2 * y**2 + 4 * x**3; #f2 = y**6 + 2 * x * y**4 + 3 * x**2 * y**2 + 4 * x**3; f1 = (x**2 + 2)**2; f2 = (y**2 + 2)**3; #f2 = f2**5; f3 = z**10 - c**5; f4 = (y**2 - x)**3; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); #puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f1,f2,f3] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.radicalDecomp(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "decomp time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/raksanyi.py000066400000000000000000000012711445075545500215500ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, RF, ZZ from jas import terminate # Raksanyi & Walter example # rational function coefficients #r = Ring( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) G" ); r = PolyRing( RF(PolyRing(ZZ(),"a1, a2, a3, a4",PolyRing.lex)), "x1, x2, x3, x4", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); rg = f.GB(); rg = f.GB(); print "GB:", rg; print; terminate(); java-algebra-system-2.7.200/examples/raksanyi.rb000066400000000000000000000012171445075545500215230ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Raksanyi & Walter example # rational function coefficients #r = Ring.new( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) G" ); r = PolyRing.new( RF(PolyRing.new(ZZ(),"a1, a2, a3, a4",PolyRing.lex)), "x1, x2, x3, x4", PolyRing.grad ); puts "Ring: " + str(r); puts; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; rg = f.GB(); rg = f.GB(); rg = f.GB(); puts "GB:" + str(rg); puts; terminate(); java-algebra-system-2.7.200/examples/raksanyi_c.py000066400000000000000000000022251445075545500220520ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ from jas import startLog, terminate # Raksanyi & Walter example # integral/rational function coefficients #nono: r = Ring( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); #r = Ring( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) G" ); r = PolyRing( PolyRing(QQ(),"a1, a2, a3, a4",PolyRing.lex), "x1, x2, x3, x4", PolyRing.grad ); print "Ring: " + str(r); print; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; #sys.exit(); #startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #sys.exit(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); print "2-CGBsystem: " + str(gs); print; gs = f.CGB(); print "CGB: " + str(gs); print; bg = gs.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/raksanyi_c.rb000066400000000000000000000021201445075545500220170ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Raksanyi & Walter example # integral/rational function coefficients #nono: r = Ring.new( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); #r = Ring.new( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) G" ); #r = Ring.new( "IntFunc(a1, a2, a3, a4) (x4, x3, x2, x1) L" ); r = PolyRing.new( PolyRing.new(QQ(),"a1, a2, a3, a4",PolyRing.lex), "x1, x2, x3, x4", PolyRing.grad ); puts "Ring: " + str(r); puts; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); #startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); puts "isCGBsystem: " + str(bg); puts #sys.exit(); gs = f.CGBsystem(); gs = f.CGBsystem(); gs = f.CGBsystem(); puts "2-CGBsystem: " + str(gs); puts; gs = f.CGB(); puts "CGB: " + str(gs); puts; bg = gs.isCGB(); puts "isCGB: " + str(bg); puts; terminate(); java-algebra-system-2.7.200/examples/raksanyi_cr.py000066400000000000000000000027051445075545500222370ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ from jas import startLog, terminate # Raksanyi & Walter example # integral/rational function coefficients #r = Ring( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); #r = Ring( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); r = PolyRing( PolyRing(QQ(),"a1, a2, a3, a4",PolyRing.lex), "x1, x2, x3, x4", PolyRing.lex); print "Ring: " + str(r); print; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); print "ParamIdeal: " + str(f); print; #sys.exit(); #startLog(); gs = f.CGBsystem(); print "CGBsystem: " + str(gs); print; #sys.exit(); bg = gs.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; rs = gs.regularRepresentation(); print "regular representation: " + str(rs); print; rs = gs.regularRepresentationBC(); print "boolean closed regular representation: " + str(rs); print; startLog(); bg = rs.isRegularGB(); if bg: print "pre isRegularGB: true"; else: print "pre isRegularGB: false"; print; rsg = rs.regularGB(); print "regular GB: " + str(rsg); print; bg = rsg.isRegularGB(); if bg: print "post isRegularGB: true"; else: print "post isRegularGB: false"; print; ss = rsg.stringSlice(); print "regular string slice: " + str(ss); terminate(); java-algebra-system-2.7.200/examples/raksanyi_cr.rb000066400000000000000000000025611445075545500222120ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Raksanyi & Walter example # integral/rational function coefficients #r = Ring.new( "RatFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); #r = Ring.new( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); #r = PolyRing.new( PolyRing.new(QQ(),"a1, a2, a3, a4",PolyRing.lex), "x1, x2, x3, x4", PolyRing.grad); r = PolyRing.new( PolyRing.new(QQ(),"a1, a2, a3, a4",PolyRing.lex), "x1, x2, x3, x4", PolyRing.lex); puts "Ring: " + str(r); puts; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); puts "ParamIdeal: " + str(f); puts; #sys.exit(); #startLog(); gs = f.CGBsystem(); puts "CGBsystem: " + str(gs); puts; #sys.exit(); bg = gs.isCGBsystem(); puts "isCGBsystem: " + str(bg); puts; rs = gs.regularRepresentation(); puts "regular representation: " + str(rs); puts; rs = gs.regularRepresentationBC(); puts "boolean closed regular representation: " + str(rs); puts; startLog(); bg = rs.isRegularGB(); puts "pre isRegularGB: " + str(bg); puts; rsg = rs.regularGB(); puts "regular GB: " + str(rsg); puts; bg = rsg.isRegularGB(); puts "post isRegularGB: " + str(bg); puts; ss = rsg.stringSlice(); puts "regular string slice: " + str(ss); puts; terminate(); java-algebra-system-2.7.200/examples/raksanyi_int.py000066400000000000000000000012601445075545500224200ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog, terminate # Raksanyi & Walter example # rational function coefficients r = Ring( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); print "Ring: " + str(r); print; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); rg = f.GB(); rg = f.GB(); print "Ideal: " + str(rg); print; bg = rg.isGB(); if bg: print "isGB: true"; else: print "isGB: false"; print; terminate(); java-algebra-system-2.7.200/examples/raksanyi_int.rb000066400000000000000000000011741445075545500223770ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Raksanyi & Walter example # rational function coefficients r = Ring.new( "IntFunc(a1, a2, a3, a4) (x1, x2, x3, x4) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( x4 - { a4 - a2 } ), ( x1 + x2 + x3 + x4 - { a1 + a3 + a4 } ), ( x1 x3 + x1 x4 + x2 x3 + x3 x4 - { a1 a4 + a1 a3 + a3 a4 } ), ( x1 x3 x4 - { a1 a3 a4 } ) ) """; f = r.paramideal( ps ); puts "Ideal: " + str(f); puts; #startLog(); rg = f.GB(); rg = f.GB(); rg = f.GB(); puts "Ideal: " + str(rg); puts; bg = rg.isGB(); if bg puts "isGB: true"; else puts "isGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/real_roots_ideal.py000066400000000000000000000017131445075545500232370ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: real roots over Q for zero dimensional ideals r = PolyRing(QQ(),"q,w,s,x",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,q,w,s,x] = r.gens(); # EF(QQ()).realExtend("q","q^3 - 3", "[1,2]").realExtend("w", "w^2 - q", "[1,2]").realExtend("s", "s^5 - 2", "[1,2]").polynomial("x").build(); f1 = q**3 - 3; f2 = w**2 - q; #f3 = s**5 - 2; f3 = s**3 - 2; f4 = x**2 - w * s; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print "f4 = ", f4; print; F = r.ideal( list=[f1,f2,f3,f4] ); print "F = ", F; print; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "real roots = "; F.realRootsPrint() print "real roots time =", t, "milliseconds"; print; print "F = ", F; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/real_roots_ideal.rb000066400000000000000000000016441445075545500232150ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: real roots over Q for zero dimensional ideals r = PolyRing.new(QQ(),"q,w,s,x",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,q,w,s,x = r.gens(); # EF.new(QQ()).realExtend("q","q^3 - 3", "[1,2]").realExtend("w", "w^2 - q", "[1,2]").realExtend("s", "s^5 - 2", "[1,2]").polynomial("x").build(); f1 = q**3 - 3; f2 = w**2 - q; #f3 = s**5 - 2; f3 = s**3 - 2; f4 = x**2 - w * s; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts "f4 = " + str(f4); puts; F = r.ideal( "", list=[f1,f2,f3,f4] ); puts "F = " + str(F); puts; startLog(); t = System.currentTimeMillis(); R = F.realRoots(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "real roots = "; F.realRootsPrint() puts "real roots time = " + str(t) + " milliseconds"; puts; puts "F = " + str(F); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_complex.py000066400000000000000000000024571445075545500226330ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import PolyRing, QQ, DD, CR from jas import terminate, startLog # polynomial examples: complex roots over Q #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing( CR(QQ()), "x", PolyRing.lex ); print "Ring: " + str(r); print; #automatic: [one,I,x] = r.gens(); print "one = ", one; print "I = ", I; print "x = ", x; print; f1 = x**3 - 2; f2 = ( x - I ) * ( x + I ) * ( x - 2 * I ) * ( x + (1,2) * I ); f3 = ( x**3 - 2 * I ); #f = f1 * f2 * f3; #f = f1 * f2; #f = f1 * f3; #f = f2 * f3; f = f2; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); #R = r.complexRoots(f); R = f.complexRoots(); t = System.currentTimeMillis() - t; #print "R = ", [ a.elem.ring for a in R ]; print "R = ", [ a.elem.ring.getRoot() for a in R ]; print "complex roots time =", t, "milliseconds"; print #terminate(); #sys.exit(); #eps = QQ(1,10) ** (DD().elem.DEFAULT_PRECISION-3); # not too big eps = QQ(1,10) ** 10; print "eps = ", eps; t = System.currentTimeMillis(); R = r.complexRoots(f,eps); t = System.currentTimeMillis() - t; #print "R = ", [ str(a) for a in R ]; print "R = ", [ a.elem.decimalMagnitude() for a in R ]; print "complex root refinement time =", t, "milliseconds"; print #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_complex.rb000066400000000000000000000023111445075545500225730ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: complex roots over Q r = PolyRing.new(CR(QQ()),"x",PolyRing.lex); puts "Ring: " + str(r); puts; one,I,x = r.gens(); puts "one = " + one.to_s; puts "I = " + I.to_s; puts "x = " + x.to_s; puts; f1 = x**3 - 2; f2 = ( x - I ) * ( x + I ) * ( x - 2 * I ) * ( x + 1/2 * I ); f3 = ( x**3 - 2 * I ); #f = f1 * f2 * f3; #f = f1 * f2; #f = f1 * f3; #f = f2 * f3; f = f2; puts "f = " + f.to_s; puts; startLog(); t = System.currentTimeMillis(); #rr = r.complexRoots(f); rr = f.complexRoots(); t = System.currentTimeMillis() - t; #puts "rr = " + str(rr); puts "rr = " + str(rr.map{ |a| str(a.elem.ring.getRoot()) }.join(",\n ")); puts "complex roots time = " + str(t) + " milliseconds"; puts #eps = QQ(1,10) ** (BigDecimal::DEFAULT_PRECISION-3); eps = QQ(1,10) ** 10; puts "eps = " + str(eps); t = System.currentTimeMillis(); #rr = r.complexRoots(f,eps); rr = f.complexRoots(eps); t = System.currentTimeMillis() - t; #puts "rr = ", [ str(r) for r in rr ]; puts "rr = " + str(rr.map{ |a| str(a.elem.decimalMagnitude()) }.join(",\n ")); puts "complex roots refinement time = " + str(t) + " milliseconds"; puts #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_complex_ideal.py000066400000000000000000000025411445075545500237630ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: complex roots over Q r = PolyRing(QQ(),"I,x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,I,x,y,z] = r.gens(); f1 = z - x - y * I; f2 = I**2 + 1; #f3 = z**3 - 2; f3 = z**3 - 2*I; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); G = F.GB(); print "G = ", G; print; #terminate(); #sys.exit(); r = PolyRing(QQ(),"x,y",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y] = r.gens(); # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 - 2 * I = z**3 - 2 #fr = y**3 - 3 * x**2 * y; #fi = -3 * x * y**2 + x**3 - 2; # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 + 2 = z**3 - 2 I fr = y**3 - 3 * x**2 * y - 2; fi = -3 * x * y**2 + x**3; print "fr = ", fr; print "fi = ", fi; print; F = r.ideal( list=[fr,fi] ); print "F = ", F; print; G = F.GB(); print "G = ", G; print; t = System.currentTimeMillis(); R = G.complexRoots(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "complex roots: "; G.complexRootsPrint() print; print "complex roots time =", t, "milliseconds"; print; print "G = ", G; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_complex_ideal.rb000066400000000000000000000024711445075545500237400ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: complex roots over Q r = PolyRing.new(QQ(),"I,x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; one,I,x,y,z = r.gens(); f1 = z - x - y * I; f2 = I**2 + 1; #f3 = z**3 - 2; f3 = z**3 - 2*I; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; ff = r.ideal( "", list=[f1,f2,f3] ); puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts; #terminate(); #sys.exit(); r = PolyRing.new(QQ(),"x,y",PolyRing.lex); puts "Ring: " + str(r); puts; one,x,y = r.gens(); # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 - 2 * I = z**3 - 2 #fr = y**3 - 3 * x**2 * y; #fi = -3 * x * y**2 + x**3 - 2; # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 + 2 = z**3 - 2 I fr = y**3 - 3 * x**2 * y - 2; fi = -3 * x * y**2 + x**3; puts "fr = " + str(fr); puts "fi = " + str(fi); puts; ff = r.ideal( "", list=[fr,fi] ); puts "ff = " + str(ff); puts; gg = ff.GB(); puts "gg = " + str(gg); puts; t = System.currentTimeMillis(); rr = gg.complexRoots(); t = System.currentTimeMillis() - t; puts "rr = " + str(rr); puts; puts "complex roots: "; gg.complexRootsPrint() puts; puts "complex roots time = " + str(t) + " milliseconds"; puts; puts "gg = " + str(gg); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_rat.py000066400000000000000000000025101445075545500217400ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: real roots over Q #r = Ring( "Rat(x) L" ); #r = Ring( "Q(x) L" ); r = PolyRing(QQ(),"x",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x] = r.gens(); f1 = x * ( x - 1 ) * ( x - 2 ) * ( x - 3 ) * ( x - 4 ) * ( x - 5 ) * ( x - 6 ) * ( x - 7 ) ; f2 = ( x - (1,2) ) * ( x - (1,3) ) * ( x - (1,4) ) * ( x - (1,5) ) * ( x - (1,6) ) * ( x - (1,7) ) ; f3 = ( x - (1,2**2) ) * ( x - (1,2**3) ) * ( x - (1,2**4) ) * ( x - (1,2**5) ) * ( x - (1,2**6) ) * ( x - (1,2**7) ) ; #f = f1 * f2 * f3; f = f1 * f2; #f = f1 * f3; #f = f2 * f3; #f = f3; #f = ( x**2 - 2 ); print "f = ", f; print; #startLog(); t = System.currentTimeMillis(); #R = r.realRoots(f); R = f.realRoots(); t = System.currentTimeMillis() - t; #print "R = ", R; print "R = ", [ a.elem.ring.getRoot() for a in R ]; print "real roots time =", t, "milliseconds"; print eps = QQ(1,10) ** (DD().elem.DEFAULT_PRECISION-3); print "eps = ", eps; t = System.currentTimeMillis(); R = r.realRoots(f,eps); t = System.currentTimeMillis() - t; #print "R = ", [ str(r) for r in R ]; print "R = ", [ a.elem.decimalMagnitude() for a in R ]; print "real roots time =", t, "milliseconds"; print startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_rat.rb000066400000000000000000000023661445075545500217240ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: real roots over Q r = PolyRing.new(QQ(),"x",PolyRing.lex); puts "Ring: " + str(r); puts; #automatic: one,x = r.gens(); f1 = x * ( x - 1 ) * ( x - 2 ) * ( x - 3 ) * ( x - 4 ) * ( x - 5 ) * ( x - 6 ) * ( x - 7 ) ; f2 = ( x - 1/2 ) * ( x - 1/3 ) * ( x - 1/4 ) * ( x - 1/5 ) * ( x - 1/6 ) * ( x - 1/7 ) ; f3 = ( x - 1/2**2 ) * ( x - 1/2**3 ) * ( x - 1/2**4 ) * ( x - 1/2**5 ) * ( x - 1/2**6 ) * ( x - 1/2**7 ) ; #f = f1 * f2 * f3; f = f1 * f2; #f = f1 * f3; #f = f2 * f3; #f = f3; #f = ( x**2 - 2 ); puts "f = " + f.to_s; puts; #startLog(); t = System.currentTimeMillis(); #rr = r.realRoots(f); rr = f.realRoots(); t = System.currentTimeMillis() - t; #puts "rr = " + str(rr); puts "rr = " + rr.map{ |a| str(a.elem.ring.getRoot()) }.join(",\n "); puts "real roots time = " + str(t) + " milliseconds"; puts eps = QQ(1,10) ** (BigDecimal::DEFAULT_PRECISION-3); puts "eps = " + str(eps); t = System.currentTimeMillis(); rr = r.realRoots(f,eps); t = System.currentTimeMillis() - t; #puts "rr = ", [ str(r) for r in rr ]; puts "rr = " + rr.map{ |a| str(a.elem.decimalMagnitude())}.join(",\n "); puts "real roots time = " + str(t) + " milliseconds"; puts startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_real_ideal.py000066400000000000000000000025121445075545500232350ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, DD from jas import terminate, startLog # polynomial examples: real roots over Q r = PolyRing(QQ(),"I,x,y,z",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,I,x,y,z] = r.gens(); f1 = z - x - y * I; f2 = I**2 + 1; #f3 = z**3 - 2; f3 = z**3 - 2*I; print "f1 = ", f1; print "f2 = ", f2; print "f3 = ", f3; print; F = r.ideal( list=[f1,f2,f3] ); print "F = ", F; print; startLog(); G = F.GB(); print "G = ", G; print; #terminate(); #sys.exit(); r = PolyRing(QQ(),"x,y",PolyRing.lex); print "Ring: " + str(r); print; #automatic: [one,x,y] = r.gens(); # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 - 2 * I = z**3 - 2 #fr = y**3 - 3 * x**2 * y; #fi = -3 * x * y**2 + x**3 - 2; # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 + 2 = z**3 - 2 I fr = y**3 - 3 * x**2 * y - 2; fi = -3 * x * y**2 + x**3; print "fr = ", fr; print "fi = ", fi; print; F = r.ideal( list=[fr,fi] ); print "F = ", F; print; G = F.GB(); print "G = ", G; print; t = System.currentTimeMillis(); R = G.realRoots(); t = System.currentTimeMillis() - t; print "R = ", R; print; print "real roots: "; G.realRootsPrint() print "real roots time =", t, "milliseconds"; print; print "G = ", G; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_real_ideal.rb000066400000000000000000000024551445075545500232160ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: complex roots over Q r = PolyRing.new(QQ(),"I,x,y,z",PolyRing.lex); puts "Ring: " + str(r); puts; one,I,x,y,z = r.gens(); f1 = z - x - y * I; f2 = I**2 + 1; #f3 = z**3 - 2; f3 = z**3 - 2*I; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; ff = r.ideal( "", list=[f1,f2,f3] ); puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts; #terminate(); #sys.exit(); r = PolyRing.new(QQ(),"x,y",PolyRing.lex); puts "Ring: " + str(r); puts; one,x,y = r.gens(); # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 - 2 * I = z**3 - 2 #fr = y**3 - 3 * x**2 * y; #fi = -3 * x * y**2 + x**3 - 2; # y**3 - 3 * I * x * y**2 - 3 * x**2 * y + I * x**3 + 2 = z**3 - 2 I fr = y**3 - 3 * x**2 * y - 2; fi = -3 * x * y**2 + x**3; puts "fr = " + str(fr); puts "fi = " + str(fi); puts; ff = r.ideal( "", list=[fr,fi] ); puts "ff = " + str(ff); puts; gg = ff.GB(); puts "gg = " + str(gg); puts; t = System.currentTimeMillis(); R = gg.realRoots(); t = System.currentTimeMillis() - t; puts "R = " + str(R); puts; puts "real roots: "; gg.realRootsPrint() puts; puts "real roots time = " + str(t) + " milliseconds"; puts; puts "gg = " + str(gg); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_real_tower.py000066400000000000000000000022401445075545500233150ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import Ring, PolyRing, QQ, DD, EF from jas import terminate, startLog # polynomial examples: real root tower over Q r = EF(QQ()).realExtend("q","q^3 - 3", "[1,2]").realExtend("w", "w^2 - q", "[1,2]").realExtend("s", "s^5 - 2", "[1,2]").polynomial("x").build(); print "Ring: " + str(r); print; #automatic: [one,q,w,s,x] = r.gens(); print "one = " + str(one); print "q = " + str(q); print "w = " + str(w); print "s = " + str(s); print "x = " + str(x); print; f = x**2 - w * s; print "f = ", f; print; startLog(); t = System.currentTimeMillis(); R = r.realRoots(f); t = System.currentTimeMillis() - t; #print "R = ", R; print "R = ", [ a.elem.ring.getRoot() for a in R ]; print "real roots time =", t, "milliseconds"; #sys.exit(); eps = QQ(1,10) ** (DD().elem.DEFAULT_PRECISION); print "eps = ", eps; t = System.currentTimeMillis(); R = r.realRoots(f,eps); t = System.currentTimeMillis() - t; #print "R = ", [ str(r) for r in R ]; print "R = ", [ a.elem.decimalMagnitude() for a in R ]; print "real roots time =", t, "milliseconds"; print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_real_tower.rb000066400000000000000000000017351445075545500233000ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: real roots tower over Q r = EF.new(QQ()).realExtend("q","q^3 - 3", "[1,2]").realExtend("w", "w^2 - q", "[1,2]").realExtend("s", "s^5 - 2", "[1,2]").polynomial("x").build(); puts "Ring: " + str(r); puts; #automatic: one,q,w,s,x = r.gens(); f = x**2 - w * s; puts "f = " + f.to_s; puts; startLog(); t = System.currentTimeMillis(); rr = r.realRoots(f); t = System.currentTimeMillis() - t; #puts "rr = " + str(rr); puts "rr = " + str(rr.map{ |a| str(a.elem.ring.getRoot())+"," }); puts "real roots time = " + str(t) + " milliseconds"; eps = QQ(1,10) ** (BigDecimal::DEFAULT_PRECISION); puts "eps = " + str(eps); t = System.currentTimeMillis(); rr = r.realRoots(f,eps); t = System.currentTimeMillis() - t; #puts "rr = ", [ str(r) for r in rr ]; puts "rr = " + str(rr.map{ |a| str(a.elem.decimalMagnitude())+"," }); puts "real roots time = " + str(t) + " milliseconds"; #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_simplify.py000066400000000000000000000043211445075545500230100ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from java.lang import System from jas import PolyRing, QQ, DD, AN, BigDecimal from jas import terminate, startLog # roots simplification r = PolyRing( QQ(), "I", PolyRing.lex ); print "Ring: " + str(r); #print; #automatic: [one,I] = r.gens(); print "one = ", one; print "I = ", I; eps = QQ(1,10) ** (BigDecimal.DEFAULT_PRECISION); #-3 #eps = QQ(1,10) ** 7; #eps = nil; print "eps = " + str(eps); ip = (I**2 + 1); # I iq = AN( ip, 0, True); print "iq = " + str(iq.factory()); print iroot = ip.algebraicRoots(); print "algebraic roots: iroot = " + str(iroot); print "unity algebraic roots: iroot = " + str(iroot.rootsOfUnity()); iroot = iroot.rootRefine(eps); print "algebraic roots refined: iroot = " + str(iroot.elem.toDecimalScript()); idroot = ip.decimalRoots(eps); print "decimal roots: idroot = " + str(idroot); print r2 = PolyRing( QQ(), "w_3_2", PolyRing.lex ); print "Ring: " + str(r2); #print; e,a = r2.gens(); print "e = " + str(e); print "a = " + str(a); w3p = (a**3 - 2); # root{3}(2) w3q = AN( w3p, 0, True); print "w3q = " + str(w3q.factory()); print #w3root = RootFactory.algebraicRoots(w3p.elem); w3root = w3p.algebraicRoots(); print "algebraic roots: w3root = " + str(w3root); print "unity algebraic roots: w3root = " + str(w3root.rootsOfUnity()); w3root = w3root.rootRefine(eps); print "algebraic roots refined: w3root = " + str(w3root.elem.toDecimalScript()); w3droot = w3p.decimalRoots(eps); print "decimal roots: w3droot = " + str(w3droot); print print "with intermediate primitive element" print #rootred = Java::EduJasApplication::RootFactory.rootReduce(iroot.elem, w3root.elem); rootred = iroot.rootReduce(w3root); #rootred = r.rootReduce(iroot,w3root); print "algebraic roots: rootred = " + str(rootred); print "unity algebraic roots: rootred = " + str(rootred.rootsOfUnity()); # somewhat slow: #rootred.rootRefine(eps); #print "algebraic roots refined: rootred = " + str(rootred.toDecimalScript()); ##print #decroot = RootFactory.decimalRoots(rootred.p, eps.elem); decroot = rootred.decimalRoots(eps); print "decimal roots: decroot = " + str(decroot); print #startLog(); terminate(); java-algebra-system-2.7.200/examples/roots_simplify.rb000066400000000000000000000051041445075545500227630ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # roots simplification #startLog(); r = PolyRing.new(QQ(),"I",PolyRing.lex); puts "r = " + str(r); e,a = r.gens(); puts "e = " + str(e); puts "a = " + str(a); eps = QQ(1,10) ** (BigDecimal::DEFAULT_PRECISION); #-3 #eps = QQ(1,10) ** 7; #eps = nil; puts "eps = " + str(eps); ip = (a**2 + 1); # I iq = AN( ip, 0, true); puts "iq = " + str(iq.factory()); puts #iroot = RootFactory.algebraicRoots(ip.elem); iroot = ip.algebraicRoots(); puts "algebraic roots: iroot = " + str(iroot); puts "unity algebraic roots: iroot = " + str(iroot.rootsOfUnity()); #RootFactory.rootRefine(iroot, eps.elem); iroot = iroot.rootRefine(eps); puts "algebraic roots refined: iroot = " + str(iroot.elem.toDecimalScript()); idroot = ip.decimalRoots(eps); puts "decimal roots: idroot = " + str(idroot); puts r2 = PolyRing.new(QQ(),"w_3_2",PolyRing.lex); puts "r2 = " + str(r2); e,a = r2.gens(); puts "e = " + str(e); puts "a = " + str(a); w3p = (a**3 - 2); # root{3}(2) w3q = AN( w3p, 0, true); puts "w3q = " + str(w3q.factory()); puts #w3root = RootFactory.algebraicRoots(w3p.elem); w3root = w3p.algebraicRoots(); puts "algebraic roots: w3root = " + str(w3root); puts "unity algebraic roots: w3root = " + str(w3root.rootsOfUnity()); w3root = w3root.rootRefine(eps); puts "algebraic roots refined: w3root = " + str(w3root.elem.toDecimalScript()); w3droot = w3p.decimalRoots(eps); puts "decimal roots: w3droot = " + str(w3droot); puts puts "with intermediate primitive element" puts #rootred = Java::EduJasApplication::RootFactory.rootReduce(iroot.elem, w3root.elem); rootred = iroot.rootReduce(w3root); #rootred = r.rootReduce(iroot,w3root); puts "algebraic roots: rootred = " + str(rootred); puts "unity algebraic roots: rootred = " + str(rootred.rootsOfUnity()); # somewhat slow: #rootred.rootRefine(eps); #puts "algebraic roots refined: rootred = " + str(rootred.toDecimalScript()); ##puts #decroot = RootFactory.decimalRoots(rootred.p, eps.elem); decroot = rootred.decimalRoots(eps); puts "decimal roots: decroot = " + str(decroot); puts ##puts "primitive element: primElem = " + str(rootred.elem.pelem.primitiveElem.toScript()); #puts "primitive element: A = " + str(rootred.elem.pelem.A.toScript()); #puts "primitive element: B = " + str(rootred.elem.pelem.B.toScript()); #puts "primitive element: Aring = " + str(rootred.elem.pelem.Aring.toScript()); #puts "primitive element: Bring = " + str(rootred.elem.pelem.Bring.toScript()); #puts terminate(); java-algebra-system-2.7.200/examples/rose.jas000066400000000000000000000011321445075545500210200ustar00rootroot00000000000000# of rose (U3,U4,A46) L ( U4^4 - 20/7 A46^2, A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216, A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) java-algebra-system-2.7.200/examples/rose.py000066400000000000000000000024761445075545500207070ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog # example from rose (modified) #r = Ring( "Mod 19 (U3,U4,A46) L" ); #r = Ring( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring( "Quat(U3,U4,A46) L" ); #r = Ring( "Z(U3,U4,A46) L" ); #r = Ring( "C(U3,U4,A46) L" ); r = Ring( "Rat(A46,U3,U4) G" ); print "Ring: " + str(r); print; ps = """ ( ( U4^4 - 20/7 A46^2 ), ( A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216 ), ( A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); #print "seq Output:", rg; #print; #sys.exit(); rg = f.parNewGB(2); #print "par-new Output:", rg; #print; rg = f.parGB(2); #print "par Output:", rg; #print; f.distClient(); # starts in background rg = f.distGB(2); #print "dist Output:", rg; #print; sys.exit(); java-algebra-system-2.7.200/examples/rose.rb000066400000000000000000000024101445075545500206460ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example from rose (modified) #r = Ring.new( "Mod 19 (U3,U4,A46) L" ); #r = Ring.new( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring.new( "Quat(U3,U4,A46) L" ); #r = Ring.new( "Z(U3,U4,A46) L" ); #r = Ring.new( "C(U3,U4,A46) L" ); r = Ring.new( "Rat(A46,U3,U4) G" ); puts "Ring: " + str(r); puts; ps = """ ( ( U4^4 - 20/7 A46^2 ), ( A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216 ), ( A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #startLog(); rg = f.GB(); #puts "seq Output:", rg; #puts; #exit(); rg = f.parGB(2); #puts "par Output:", rg; #puts; f.distClient(); # starts in background rg = f.distGB(2); #puts "dist Output:", rg; #puts; f.distClientStop(); # stops them terminate(); java-algebra-system-2.7.200/examples/rose_fac.py000066400000000000000000001763141445075545500215230ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog, terminate # output gb of rose #r = Ring( "Mod 19 (U3,U4,A46) L" ); #r = Ring( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring( "Quat(U3,U4,A46) L" ); #r = Ring( "Z(U3,U4,A46) L" ); #r = Ring( "C(U3,U4,A46) L" ); #r = Ring( "Rat(A46,U3,U4) G" ); rz = Ring( "Int(A46) G" ); print "Ring: " + str(rz); print; r = Ring( "Rat(A46) G" ); print "Ring: " + str(r); print; ps = """ ( ( A46^34 + 347/70 A46^33 - 56411/58800 A46^32 - 441350327/6174000 A46^31 - 992593010489/3457440000 A46^30 - 217625706587/329280000 A46^29 - 373467217691021/355622400000 A46^28 - 38574512982739/31752000000 A46^27 - 968821009058023/952560000000 A46^26 - 5992612680961049/10886400000000 A46^25 - 13843426727931961/244944000000000 A46^24 + 1486519769228381881/5598720000000000 A46^23 + 61199280870444808261/167961600000000000 A46^22 + 513991046707657214269/1679616000000000000 A46^21 + 37908065080289396962277/201553920000000000000 A46^20 + 27223946509678338655459/335923200000000000000 A46^19 + 668594689016343141054373/48372940800000000000000 A46^18 - 36250135997129945800663817/2418647040000000000000000 A46^17 - 5712667240922865693346483691/290237644800000000000000000 A46^16 - 42053436689365696671983799179/2902376448000000000000000000 A46^15 - 561895388992743685886859196463/69657034752000000000000000000 A46^14 - 704377755966878925481768484749/193491763200000000000000000000 A46^13 - 2531676547158421516985730163481/1857520926720000000000000000000 A46^12 - 4750291847118917831874464404117/11145125560320000000000000000000 A46^11 - 1835783859800409552862056700927/16511297126400000000000000000000 A46^10 - 9916637291915563585725849353/412782428160000000000000000000 A46^9 - 252376016954713294866494065459/59440669655040000000000000000000 A46^8 - 178806028363626133639831815853/297203348275200000000000000000000 A46^7 - 31482408916666847417595615109/475525357240320000000000000000000 A46^6 - 3818476405879526813756500117/713288035860480000000000000000000 A46^5 - 896701239882765996997050397/3170169048268800000000000000000000 A46^4 - 4844358439974218651958787/760840571584512000000000000000000 A46^3 + 171452325388464998728627/730406948721131520000000000000000 A46^2 + 15230552381256429497/811563276356812800000000000000 A46 + 79792266297612001/259700248434180096000000000000 ) ) """; ps1=""" ( ( A46^33 * U3 + 129/28 A46^32 * U3 - 75613/29400 A46^31 * U3 - 871585543/12348000 A46^30 * U3 - 12095701697/46099200 A46^29 * U3 - 124924301563/219520000 A46^28 * U3 - 378293923381/444528000 A46^27 * U3 - 1617620272123/1764000000 A46^26 * U3 - 82886347203347/119070000000 A46^25 * U3 - 668049914090789/2177280000000 A46^24 * U3 + 99688309115142847/1959552000000000 A46^23 * U3 + 231138576685539839/933120000000000 A46^22 * U3 + 11659387634813949601/41990400000000000 A46^21 * U3 + 70151923964052383971/335923200000000000 A46^20 * U3 + 23176161047838396328367/201553920000000000000 A46^19 * U3 + 164454230781271289566939/4031078400000000000000 A46^18 * U3 - 55282700662490687816927/120932352000000000000000 A46^17 * U3 - 747149106093593978873861/50388480000000000000000 A46^16 * U3 - 841282928607636046387355983/58047528960000000000000000 A46^15 * U3 - 54661970877464131720410138953/5804752896000000000000000000 A46^14 * U3 - 830787778268485831652841532151/174142586880000000000000000000 A46^13 * U3 - 274531406380976793484077680017/139314069504000000000000000000 A46^12 * U3 - 750317990428317888436020594041/1114512556032000000000000000000 A46^11 * U3 - 1416119253746536814898928216649/7430083706880000000000000000000 A46^10 * U3 - 33046099809889641357330063959/743008370688000000000000000000 A46^9 * U3 - 25135248767946559916964025799/2972033482752000000000000000000 A46^8 * U3 - 38214637789543687723872942433/29720334827520000000000000000000 A46^7 * U3 - 3604383688017858128502121387/23776267862016000000000000000000 A46^6 * U3 - 10419538500903067530134609/792542262067200000000000000000 A46^5 * U3 - 268160889047530270882049141/356644017930240000000000000000000 A46^4 * U3 - 4494450124912371106208621/228252171475353600000000000000000 A46^3 * U3 + 19160001876330286653661/36520347436056576000000000000000 A46^2 * U3 + 4148034694905888017/81156327635681280000000000000 A46 * U3 + 11398895185373143/12985012421709004800000000000 U3 ) ) """; ps2=""" ( ( A46^32 * U3^2 + 149/35 A46^31 * U3^2 - 119419/29400 A46^30 * U3^2 - 17080619/246960 A46^29 * U3^2 - 32939303767/138297600 A46^28 * U3^2 - 29988193601/61740000 A46^27 * U3^2 - 3784045943831/5556600000 A46^26 * U3^2 - 2693634126319/3969000000 A46^25 * U3^2 - 21841275550799/47628000000 A46^24 * U3^2 - 21239300351867/145152000000 A46^23 * U3^2 + 100022001638857211/979776000000000 A46^22 * U3^2 + 296696864208881153/1399680000000000 A46^21 * U3^2 + 17088141121241394989/83980800000000000 A46^20 * U3^2 + 19261885997631012911/139968000000000000 A46^19 * U3^2 + 13468170505032365821223/201553920000000000000 A46^18 * U3^2 + 35088518623022364409189/2015539200000000000000 A46^17 * U3^2 - 99017698968245042551237/15116544000000000000000 A46^16 * U3^2 - 3789770743783848575384507/302330880000000000000000 A46^15 * U3^2 - 2933051673126807110607585563/290237644800000000000000000 A46^14 * U3^2 - 948072476821568942948806667/161243136000000000000000000 A46^13 * U3^2 - 18896655281197310848727704481/6965703475200000000000000000 A46^12 * U3^2 - 2845096388251912350859674973/2786281390080000000000000000 A46^11 * U3^2 - 39111610674783351035074010869/123834728448000000000000000000 A46^10 * U3^2 - 1486938573940216107905934971/18575209267200000000000000000 A46^9 * U3^2 - 2445791954945323169329394873/148601674137600000000000000000 A46^8 * U3^2 - 333946045138720738819094237/123834728448000000000000000000 A46^7 * U3^2 - 406526799915645826522761061/1188813393100800000000000000000 A46^6 * U3^2 - 6322467405069477857023283/198135565516800000000000000000 A46^5 * U3^2 - 490026291814312040719379/247669456896000000000000000000 A46^4 * U3^2 - 169501103784936018875857/2853152143441920000000000000000 A46^3 * U3^2 + 2012646248526699378523/1826017371802828800000000000000 A46^2 * U3^2 + 5217570099427357/37572373905408000000000000 A46 * U3^2 + 1628413597910449/649250621085450240000000000 U3^2 ) ) """; ps3=""" ( ( U3^4 + 36097228800000000000000000/282475249 A46^33 + 1161224847360000000000000000/1977326743 A46^32 - 4677045387264000000000000000/13841287201 A46^31 - 874485621920563200000000000000/96889010407 A46^30 - 22660530808584929280000000000000/678223072849 A46^29 - 48947976962992465920000000000000/678223072849 A46^28 - 212357741794443264000000000000/1977326743 A46^27 - 33417694635162617446400000000000/290667031221 A46^26 - 1195585718651671592960000000000/13841287201 A46^25 - 4622243456144475926528000000000/124571584809 A46^24 + 57492745364488210585600000000/7626831723 A46^23 + 5064235904207031314222080000000/160163466183 A46^22 + 796549541441999106994688000000/22880495169 A46^21 + 1776805509375610240638745600000/68641485507 A46^20 + 6571948331935947500408320000/466948881 A46^19 + 15900562307775474505007648000/3268642167 A46^18 - 781823011269699906939632000/4202539929 A46^17 - 23911885581267405621130949120/12607619787 A46^16 - 66484142665897834547281936/36756909 A46^15 - 31344755225898717841650588049/27016328115 A46^14 - 748245898727397783769699627/1286491815 A46^13 - 61180345995024957255947775667/257298363000 A46^12 - 1772332138625205728147155697/22054145400 A46^11 - 1763442424064055410851226129/78414739200 A46^10 - 72564573592100205725791837/14002632000 A46^9 - 65329613048147169962793719/67212633600 A46^8 - 87361765982805204782291/600112800 A46^7 - 6483564254536224014425081/384072192000 A46^6 - 23648026104539505065429/16460236800 A46^5 - 880685511246977438581/10973491200 A46^4 - 31439956654789887473/15676416000 A46^3 + 17918243525346457327/300987187200 A46^2 + 10074090036167/1866240 A46 + 34829612499283/382205952 ) ) """; ps4=""" ( ( A46 * U4 + 7/20 U4 + 2806378846741861368786614566878031251136601782233486293371124444033709909300049715978016727056150885946954243402645730462178807446021415693833183139081658586984935909957265108287928306576671117507805428087796888020739324547730219269915178825763993883433817341952000000000000000/193099928700513998070936429904026968056396066087989232333196930214044975387024916636846108968424103894255784064885243976305160746405290836679402752295622754790839675018341679885489238996414850488675112243144046216420956878738117538991288033099828416943500600350187 A46^32 * U3 + 140608368210259054916983904673796347993009087108223449480869140637168687474157820242084293427769280716150829987371903694486407125016157557573489507333502558345102130864385866957396552184077632209367448052303724048297487583320428452817989972383673573195382911926272000000000000000/1351699500903597986496555009328188776394772462615924626332378511498314827709174416457922762778968727259790488454196707834136125224837035856755819266069359283535877725128391759198424672974903953420725785702008323514946698151166822772939016231698798918604504202451309 A46^31 * U3 + 2973132530031750926781836728171190368295908349443863657109054185698567452354483691980282671132312007156981877065422976124734148815655910511834380182331303177950358622308259910423832682100194502857004946063777788209711503282994815361158167402207667989232295462169477120000000000000/28385689518975557716427655195891964304290221714934417152979948741464611381892662745616378018358343272455600257538130864516858629721577752991872204587456544954253432227696226943166918132472983021835241499742174793813880661174503278231719340865674777290694588251477489 A46^30 * U3 - 738219222373037292445012084441369194910728746958545194778441077198902948054263364937417682200010729210575746685991736931724571115099030702915394756575817790642985569814303481715585979651308619587706574566955474220298898070223241914619143731590342509740953174566721552384000000000000/596099479898486712044980759113731250390094656013622760212578923570756839019745917657943938385525208721567605408300748154854031224153132812829316296336587444039322076781620765806505280781932643458540071494585670670091493884664568842866106158179170323104586353281027269 A46^29 * U3 - 26263613198277033357242907881790564317638488547844618743001644843010275951255995601618105986940603997061861718415452159942810394664057894925733725044191873926510994765442061292542368154720543459005227757920995136654748098710382908816433885918895473973271287136201940664320000000000000/4172696359289406984314865313796118752730662592095359321488052464995297873138221423605607568698676461050973237858105237083978218569071929689805214074356112108275254537471345360645536965473528504209780500462099694690640457192651981900062743107254192261732104472967190883 A46^28 * U3 - 9560261987467874294850640971728702760731659080417859619462176031496681069887590878558384729317157715276514804678872739436230630658282680026803340746414284932116802254277874675348065517256502425989246849745315895036906790401640417642341755791726718494097465403286844184985600000000000/596099479898486712044980759113731250390094656013622760212578923570756839019745917657943938385525208721567605408300748154854031224153132812829316296336587444039322076781620765806505280781932643458540071494585670670091493884664568842866106158179170323104586353281027269 A46^27 * U3 - 144636713736027890114035034090555770840107473490985685648308419164337400894146263765715981457017308677715082713471432001864714782421560684446718632104959754377888118909536279270581334669935787514862899283922492256748522286708189406470339423887947462918232309558821679529984000000000000/5364895319086380408404826832023581253510851904122604841913210312136811551177713258921495445469726878494108448674706733393686281017378195315463846667029286996353898691034586892258547527037393791126860643451271036030823444961981119585794955423612532907941277179529245421 A46^26 * U3 - 24532425560872733727048401118804283865911311477564921900335177229012489937286467620463606284515609505035616190873825110294676684892007020876691541110492442185186251334711679953191506232457944676021905960044901546391272864711217070545467913465760834235337077332640608895369216000000000/766413617012340058343546690289083036215835986303229263130458616019544507311101894131642206495675268356301206953529533341955183002482599330780549523861326713764842670147798127465506789576770541589551520493038719432974777851711588512256422203373218986848753882789892203 A46^25 * U3 - 61280378855985472962083715267099870468639547774190782208008687497788816915947177474302623147240238616774447758611668598585355022788830824893247197811650042416494226679277235085459349523493402070913785423068849805945203419134911827923486496461119063853055966658119121257129574400000000/2299240851037020175030640070867249108647507958909687789391375848058633521933305682394926619487025805068903620860588600025865549007447797992341648571583980141294528010443394382396520368730311624768654561479116158298924333555134765536769266610119656960546261648369676609 A46^24 * U3 - 1484357436021657507567420650984058019197004585757942514498995263423808522091214018761612749478663033895612373062807866818414484967623858841053321992327465827514651989711202442802087572810894125998644840666538477463088224296505304638389800637458850650417392471695314042172211200000000/109487659573191436906220955755583290887976569471889894732922659431363501044443127733091743785096466908043029564789933334565026143211799904397221360551618101966406095735399732495072398510967220227078788641862674204710682550244512644608060314767602712406964840398556029 A46^23 * U3 - 142706740914560864457369678713491100078718980040431434176679594896408407693192038718320939423503224607224793619606860312440116490102586591426353170601317496666073657735251911434293391435267804199376695206269942247915428218586358462081096742118453704497075161839492889751191552000000/2956166808476168796467965805400748853975367375741027157788911804646814528199964448793477082197604606517161798249328200033255705866718597418724976734893688753092964584855792777366954759796114946131127293330292203527188428856601841404417628498725273234988050690761012783 A46^22 * U3 + 3437067913738929851828191102489541091985420513352095924549529468703404236611368673420787140580385095687914414418203044807769960408456154049568142240000401501441029724428786621410870408162134547736165823446770365996810358019535793543622855984068400287198402234509017467116735692800000/422309544068024113781137972200106979139338196534432451112701686378116361171423492684782440313943515216737399749904028576179386552388371059817853819270526964727566369265113253909564965685159278018732470475756029075312632693800263057773946928389324747855435812965858969 A46^21 * U3 + 12665325755293011964582773351828201837497408957482566179025807264260205331500166852839160281570134088487784028319208757397082649585467393387792231298887791806004696105674306391612545456300491907001838309111269128096161395643695348999989978496685257886403350330750962195611697479680000/1266928632204072341343413916600320937418014589603297353338105059134349083514270478054347320941830545650212199249712085728538159657165113179453561457811580894182699107795339761728694897055477834056197411427268087225937898081400789173321840785167974243566307438897576907 A46^20 * U3 + 472460708046707276929317308260575825818443603966144032149144933738614980186931958850077619729999743406167265787440681567111099352622569281813602576458470534069879413676204407012264193237661238006825286040265059435939142815940360874733243831244058419301704863623227097616300687360000/60329934866860587683019710314300997019905456647776064444671669482588051595917641812111777187706216459533914249986289796597055221769767294259693402752932423532509481323587607701366423669308468288390352925108004153616090384828609008253420989769903535407919401852265567 A46^19 * U3 + 49390047765871082949860891586805882007616506646541386751626133624251152479425727198070508507708042448289532261339277046519001543624931425618731092311111454034423497441761556818193037978230663070411942523132669576228611039810197751659696742852563815776238111135652689883724583731200/11081008444933577329534232506708346391411206323060909795960102558026376823739975026714408054884815268077657719385236901415785652978120523435453890301559016567195619018618132026781588020893392134602309720938204844541730887009336348454709977712839424870842339115722247 A46^18 * U3 + 129068221133437408101386032010227938242790415417408002956440388834868112181036866325987181792617952620211570225145421401636968642407417865428308813969801472080155460044151903911373059980563777215433387329713871436510348502082703071326443785803142144287247590693723735936473435504640/77567059114535041306739627546958424739878444261426368571720717906184637766179825187000856384193706876543604035696658309910499570846843664048177232110913115970369333130326924187471116146253744942216168046567433911792116209065354439182969843989875974095896373810055729 A46^17 * U3 + 12783978249076530856412299581616499812448814070864143616141639515320829793115590125926560504059268257844159130491162326200688965203538567110804552270764562224831755709762903109729453955480299083281536877866482795304181415809809747877796974966623540360991948948407257749615539560448/232701177343605123920218882640875274219635332784279105715162153718553913298539475561002569152581120629630812107089974929731498712540530992144531696332739347911107999390980772562413348438761234826648504139702301735376348627196063317548909531969627922287689121430167187 A46^16 * U3 - 1810442970097170462121122653290427291604967782620000014180906504389275928944428879269826615110693111930022066722356506712480414023024345146923757896554522544082287653722476697782328057603177530844114988866728376051365543251948667665657844199641256470495166203610372754104633985024/3392145442326605304959458930625003997370777445834972386518398742252972497063257661239104506597392429003364607975072520841567036625955262276159354173946637724651720107740244497994363679865324122837441751307613727920938026635511127077972442156991660674747654831343545 A46^15 * U3 - 270639555533122280020486247514756020301825934358369840608010596756492667631965814059407427090369596575058017999403434671889521831726503036761805006306129032875224481365310003762906407037966481686173976406974516397321267076580148872307324693442737067092534607150395172934720327272832/498645380022010979829040462801875587613504284537740940818204615111186957068298876202148362469816687063494597372335660563710354384015423554595425063570155745523802855837815941205171460940202646057103937442219218004377889915420135680461948997077774119187905260207501115 A46^14 * U3 - 1435948341205771592618056822768583583847960643508655403782679773815551216480844799951609196462939014609390424305428592870359320910647059517420727369800472093539593358295705161364370776721823709904982580674821197915654942789644804770077615722633391761110116425814824933514747954464/4038268383722149172570784441220242854012830292660681412521903264586872020313401977665600603092133844051624533303657762906627424554708645566856374016603140148394904890166957735707575809363481098616002084890016342763021460280370389378538621615466262708032922418266125 A46^13 * U3 - 24031158593232439577778424195027450454772002899626269270999618447601656149784654839122276071971243436018537991067130120319932291937910513510530154436517553834823319688270120213094719167314095473720221761127649325967639043315665428464820334187025317629951306324495868404822629086296/134236911348351843098270045621466866730124986864072399717750703996191750825995749157075115524896810946741187375897970359936383987082400454395753337285576744128805506776152891566359869240901645564547003977625417625011994772636432792658457195911102149817275285411208125 A46^12 * U3 - 55342608527391903114377714171300343766958416997314322747423256743530874483390328684036373961531616542340488099823707750319655515404839491476271584066825595064560837447788507941963050626463472192927052092190464771899480038023820496414639119032434176994304931597908860375406025786078/763232724523486193615878259390625899408424925312868786966639717006918811839232973778798513984413296525757036794391317189352583240839934012135854689137993488046637024241555012048731827969697927638424394044213088782211055992990003592543799485323123651818222337052297625 A46^11 * U3 - 2029624852259950049380302093920186872530375028355631473518046159913882812276759452807058944803805569580457303136641881139738479285051882346521262597896200616610534853804143612625821026733823701571937719332556063675018717208715246680768950536936393557501213975920703061913308587814/84803636058165132623986473265625099934269436145874309662959968556324312426581441530977612664934810725084115199376813021039175915648881556903983854348665943116293002693506112449859091996633103070936043782690343198023450665887778176949311053924791516868691370783588625 A46^10 * U3 - 1168942911153266036621765763524847385999721254478313573544681811727225087201633669304728449000690805131434160354788200355429868149616777944697604839445821146293319865569802164294050791015324448927695484221067203620046595245414313118308514802029950573572440600781377894978809819943/181722077267496712765685299854910928430577363169730663563485646906409240914103088994952027139146022982323103998664599330798234104961889050508536830747141306677770720057513098106840911421356649437720093820050735424335965712616667522034237972695981821861481508821975625 A46^9 * U3 - 101409764297139370497431870913772400890980479461654448912068336828050482388546012701358058370032729748116854879439321035194274795413256750973689666942448462456840973308098467386964329640348557236019188613852479460195591937286545711022988218130783801374434056440021146855389791263/72688830906998685106274119941964371372230945267892265425394258762563696365641235597980810855658409192929241599465839732319293641984755620203414732298856522671108288023005239242736364568542659775088037528020294169734386285046667008813695189078392728744592603528790250 A46^8 * U3 - 3322794676291853666085201130675181837616673614933545069242421946525758427676251695684072633966150401809622984292825237098582373428490919709859723984671293905443481868170729806447368393045191340333060166403807452609937752781689646834959249508572627032878032237058297511762260717/13845491601333082877385546655612261213758275289122336271503668335726418355360235351996344924887316036748426971326826615679865455616143927657793282342639337651639673909143855093854545632103363766683435719622913175187502149532698477869275274110170043570398591148341000 A46^7 * U3 - 235997802096027015525218011390431135161602429335194555350491794738198772970078394908866958050373633238495091699843397584952514894044850979218568026142058202580747771909113137749719827302612618129281900176792733050978935129822521807364852652110897499832909022097494923166043147/7417227643571294398599399994077997078799076047744108716876965179853438404657268938569470495475347876829514448925085686971356494080077104102389258397842502313378396737041350943136363731483944875008983421226560629564733294392517041715683182559019666198427816686611250 A46^6 * U3 - 3496748794132449388555216753002710407113019869328151832331519672134490805457467271923368355368145123271002659562187642206698039955131848140898636455957544259518289841694390481218777439807140629994396001816472151472171553970751649445797629489197230923775536860056783627934479/1130244212353721051215146665764266221531287778703864185428870884549095375947774314448681218358148247897830773169536866586111465764583177767983125089195047971562422359930110619906493520988029695239464140377380667362245073431240692070961246866136330087379476828436000 A46^5 * U3 - 25797731568499728113711563609522696636972574369245543976139702215108120141166264492184554278639511568603311186805558250985505155379498427020368472760296798230482403566780044258141402965693251712985897771176010862913999745411179857703742819398871451136186089552354116699661/129170767126139548710302476087344711032147174709013049763299529662753757251174207365563567812359799759752088362232784752698453230238077459198071438765148339607133983992012642275027830970060536598795901757414933412828008392141793379538428213272723438557654494678400 A46^4 * U3 - 105307750747592845167925795351809474019566402815312738506184953133174877999878727791254675413428352747128321422294719175016172361719591143541377238760546940146607913162164819516842775340285454038918138509577296566880300576934730064221978046439482447941555635234543414413987/16607670059075084834181746925515748561276065319730249255281368099496911646579540947001030147303402826253839932287072325346943986744895673325466327841233357949488655084687339721075006839007783276988044511667634295935029650418230577369226484563635870671698435030080000 A46^3 * U3 + 6729992771983469644834688420302244188161700009523433301108672306478446515336817887911228386552702182506838452635857560083522640089937561680000956097567263329228552440470166784211722333574861459688985916960390707820563713605127900163322847651117899308325942825648612997/67786408404388101364007130308227545148065572733592854103189257548966986312569554885718490397156746229607509927702336021824261170387329278879454399351972889589749612590560570290102068730644013375461406170071976718102161838441757458649904018627085186415095653184000 A46^2 * U3 + 97004104716134687567531815774189859076177884454360758941608137811927278665332561915062791777635759119435458822688898910056883442317958132684946302161704171063308484365878439710058473575123783245727688981281817771384031307613137609700123391407537243830931947114431/6831585629064056574855845836052158745080934515857178544035198543609673601669897191808363859627789995425297044867960294464526195050373321126677188143307925380675194012654126509458510328107232388557460939286669359345141026801890396437380097619257766330571494400 A46 * U3 + 91815250260603771367686439814867337622922814376622703580092567517752668189839523750475603039746288206705982958930474905045662465449513750706031249185792777351062825505761724720085638243587008740273119957261765515541418363044444151757419729917247863640658968103/351338689494722909564014928711253878318448060815512039407524496528497499514451855578715855638000628336158133736066529429604204316876342229371969675941550448149009977793640791915009102588371951411526562591885852766321538521240077531065262163276113697000819712 U3 ) ) """; ps5=""" ( ( U3^2 * U4 + 535179163636213160230552332612905761790726203364450534489129686242659247983859225063689303002742332435127911688744222034136908867349929123331100864371658990936252805314758914346647230739008414163809378439226935298947238851749778443095061790353887385009084423995392000000000000000/348416638018627423852659631690165992696423968578095238206531661082875150589988624585082662615359891459868853047741275214579945040097279766315202366058735323894271720291427837740051083562531195231732794190712907389828879861536476746186614041056457073638389583231854077 A46^31 * U3^3 + 117444957438518475167713581434975737067164998391805610491814809960560346257088363610575217412650923824342320317819214071400331125353389211274396241076281078058047842081052040344628591911420714970389327499109713526665438238583003654833271274497439548231330310580181401600000000000000/2438916466130391966968617421831161948874967780046666667445721627580126054129920372095578638307519240219081971334188926502059615280680958364206416562411147267259902042039994864180357584937718366622129559334990351728802159030755337223306298287395199515468727082622978539 A46^30 * U3^3 + 2401741581776741318484092416102407292900015435135593836159021006355478379624893489598800836632769384261155218893078011625298104568085745627327942804937416501911688374548247994274079800109905304371024073616832343444568942958320613360649846757743965134232833554270042193920000000000000/17072415262912743768780321952818133642124774460326666672120051393060882378909442604669050468152634681533573799339322485514417306964766708549444915936878030870819314294279964049262503094564028566354906915344932462101615113215287360563144088011766396608281089578360849773 A46^29 * U3^3 - 805568218873790937813389084592233191792825630736851320718859307972639139165702967980087508722852747263747190017939561005107936647865901266983449666943346565871280018184856673037268657368899455757140347277745038838145391480304288946439289988670652938164442307992695603200000000000000/2072374107058772364996455265949022002801273200386473989101277914764615780098834073399133293821996117411589883156796371074004412984162432829701405980777102013220841619536874248754407890091587282621115868336668102336034204494341240299572403747093030802161288330321259221 A46^28 * U3^3 - 7685682775116980037756417525104129020857901100253508944433808002299072796987780826355035229956095427761674994214377901743588098560205258976689072899389795364550488078379086807213438803727723516868672038614031636269842625366221371250239578203300336002844575259786307614801920000000000000/2509645043648173334010707327064265645392341845668020000801647554779949709699688062886350418818437298185435348502880405370619344123820706156768402642721070538010439201259154715241587954900912199254171316555705071928937421642647242002782180937729660301417320168019044916631 A46^27 * U3^3 - 1034113844705967884541016548705263783711258150109052467551058076026319678448759166131211515280654219796468782344958028728719356943011812509405877602376788836215237969187146349036450163464263286874467724055879617971867571915156566751269616939474200904886354631269920338765414400000000000/119506906840389206381462253669726935494873421222286666704840359751426176652366098232683353277068442770735016595375257398600921148753366959846114411558146216095735200059959748344837521661948199964484348407414527234711305792507011523942008616082364776257967627048525948411 A46^26 * U3^3 - 48658714056579159584588250657320626399886844717677219117243540154602424522685502681521979204132079896072758913281262740708279626890869807641530459145331943833017069929236863886983924086820489878464574416932681640220499275442882030223770711661291180467191894819368336275978321920000000000/3226686484690508572299480849082627258361582373001740001030689713288506769613884652282450538480847954809845448075131949762224871016340907915845089112069947834584850401618913205310613084872601399041077407000192235337205256397689311146434232634223848958965125930310200607097 A46^25 * U3^3 - 8255947206923045970115261594812428132415296386179673138598668698030130733176457946142061749654776338102806089384084736737962150165972226111226766639416349566788039796025933969548991539844303719591225974525365272074129459969218772790071341578178550260218707253120429402938146816000000000/460955212098644081757068692726089608337368910428820000147241387612643824230554950326064362640121136401406492582161707108889267288048701130835012730295706833512121485945559029330087583553228771291582486714313176476743608056812758735204890376317692708423589418615742943871 A46^24 * U3^3 - 19945713493372992010989573088745323542756396319972931197979116120090053547915047057950693601445545496940530403318628583782260656315550176840007325651552659987878417938292973350492923084265613272190430226035072662253316611695490659970858884921554483178528771682266082834119655424000000000/1382865636295932245271206078178268825012106731286460000441724162837931472691664850978193087920363409204219477746485121326667801864146103392505038190887120500536364457836677087990262750659686313874747460142939529430230824170438276205614671128953078125270768255847228831613 A46^23 * U3^3 - 435093775488421369600147732183313564461463032259212791823425518543075036047179553289353390602878450300140400400876508808029170501403708143242207930225443742617112912856658164191471704385406656699565008229508861688289615831997614509046870265598882388184233731177202498351136768000000000/65850744585520583108152670389441372619624130061260000021034483944663403461507850046580623234303019485915213226023101015555609612578385875833573247185100976216017355135079861332869654793318395898797498102044739496677658293830394105029270053759670386917655631230820420553 A46^22 * U3^3 + 1666712214493918375843073715679404854923553599857383781647492939009113706816140218151303957915155518916011997458056804212971047568027330977305056462875462122879154305439206460319912215754500114817599379012537086490342649170430864147520080485377840240561213239361225941393442471936000000/1777970103809055743920122100514917060729851511654020000567931066505911893460711951257676827326181526119710757102623727420001459539616418647506477673997726357832468588647156255987480679419596689267532448755207966410296773933420640835790291451511100446776702043232151354931 A46^21 * U3^3 + 1284088025543201778701542120995051734041815978306710257005722604826526562109618762971947126682732875656141515493855498879095407124008034223158582017519436364169634168807052804122297828912887489492802203539147042679430553728949689548527311377444129568517124121118716963986204576972800000/253995729115579391988588871502131008675693073093431428652561580929415984780101707322525261046597360874244393871803389631428779934230916949643782524856818051118924084092450893712497239917085241323933206965029709487185253419060091547970041635930157206682386006176021622133 A46^20 * U3^3 + 4254014381230883330619305014989375799554837810367142599761760649672291739447040860678177727995158715416431102910496713847267271580162773653334863631889973825919344031375754538234961810569091573254261817527160589941054559827804400510444074230128005539082809168028853708352942800568320000/761987187346738175965766614506393026027079219280294285957684742788247954340305121967575783139792082622733181615410168894286339802692750848931347574570454153356772252277352681137491719751255723971799620895089128461555760257180274643910124907790471620047158018528064866399 A46^19 * U3^3 + 745516437593004300883570660646246938247823802410590380979420190673989967797085587628924839737460064182360717893802831288295892815613347860630889607237862285660785165032805451166314560759396503899171227181213064059364949918934022222627542591929187087049764507673930916328360804352000/182337206830997409898484473440151477871997898846684442679512979848826981177388160317677861483558765882443929556212052858168542666353852799457130312172877280056657633950072429082912591469551501309356214619547530141554381492505449783180216536920428719800707829272090181 A46^18 * U3^3 + 100659132205313930529625050503119312070810564089441017863641173372860790994172383194397174444036783482169409680952402366953488358200797270823652786371161310119627780987982282462009952616082069316251196025335382901954198189565730812891991210118588783206461023328312986396596201321267200/46652276776330908732597955990187328124106890976344548119858249558464160469814599304137292845293392813636725405025112381282837130777107194832531484157374744083067688914939960069642350188852391263579568626229946640503413893296751508810823973946355405309009674603759073453 A46^17 * U3^3 + 31840686398285739366370901635863389542030022459808048577847041429885472147377770155737274410841071887893024815380774859603070679264257251115288897069582531630147721152091634280145756325435744966628395355333013175929902375331398691019183890365382567317614167783255315159428074691624960/46652276776330908732597955990187328124106890976344548119858249558464160469814599304137292845293392813636725405025112381282837130777107194832531484157374744083067688914939960069642350188852391263579568626229946640503413893296751508810823973946355405309009674603759073453 A46^16 * U3^3 - 13828528445690452987305064022092959448876463072880660857470397879545100109724829810338301593203092974158319894346856522064022294423111854351244636838712011841678369295025322372766599272518628248765532325453911764768121252460833528916104395772737785984090513826255228303325154466127872/139956830328992726197793867970561984372320672929033644359574748675392481409443797912411878535880178440910176215075337143848511392331321584497594452472124232249203066744819880208927050566557173790738705878689839921510241679890254526432471921839066215927029023811277220359 A46^15 * U3^3 - 33610752624740506302912013993814981775024007915215935211163351291344044163786135068634072771353605827815789041344588941769903151215762730402577426802629600007206325972644549999333779030662823436337121030730985687375264611402234685156485004573481758060166931327023163395774356304113664/99969164520709090141281334264687131694514766377881174542553391910994629578174141366008484668485841743507268725053812245606079565950943988926853180337231594463716476246299914434947893261826552707670504199064171372507315485635896090308908515599333011376449302722340871685 A46^14 * U3^3 - 440458073572699732774489360478761084951279455207275623193025208264809731530938512938804891081421616585621742589211241713795773058743821672163780025900276255331592774249357759549304463610560721287707008918417645237050696497113058739332361880620366592325582276896858182823540813585536384/1499537467810636352119220013970306975417721495668217618138300878664919443672612120490127270027287626152609030875807183684091193489264159833902797705058473916955747143694498716524218398927398290615057562985962570587609732284538441354633627733989995170646739540835113075275 A46^13 * U3^3 - 6996214565149446678253694413083490264717525678004855498090489246100920822500988095095030219926214938120572903557109272761916802518646083631510656210142715036721759509042764836946925860045014447394355560737664073350497528956878636493202886375323607681733788379035427399732074066732736/39670303381233765929079894549479020513696335864238561326410076155156599038957992605558922487494381644248916160735639780002412526171009519415417928705250632723697014383452346997995195738820060598281946110739750544645760113347577813614646236348941671181130675683468599875 A46^12 * U3^3 - 52720968043649456846417369507000756940194406072631641273516890434262149856954069120692268860993592166109579882175849063584157212108249084107098488501914404760103187541211164434424785557474548152913921719930232076831591869022033755032242197725738904601218545055852510881677688297536184/642658914775987008051094291701560132321880641000664693487843233713536904431119480210054544297408982636832441803917364436039082923970354214529770445025060250123891633011928021367522170968884981692167526993983958823261313836230760580557269028852855073134316946072191317975 A46^11 * U3^3 - 560521169089131499065785274068646758491670755018612288505863123339558028653018546907577396130067320298156818038178669090843281588218301520813686567954392296875641272535840128326520911631312236737399924421960962557597703529589857661762970259131745451459708625790997896125768972935928/18361683279313914515745551191473146637768018314304705528224092391815340126603413720287272694211685218195212622969067555315402369256295834700850584143573150003539760943197943467643490599110999476919072199828113109236037538178021730873064829395795859232409055602062609085 A46^10 * U3^3 - 4197422272012614585634130742038816517252315110924247183388171916467791237166762578598405913589164581591069795124771062594877274429670076994003284050036156103051961891924620808585164846207763280779766288975531255051754977759088637973954664073448069462858272840556659782286260872647812/459042081982847862893638779786828665944200457857617638205602309795383503165085343007181817355292130454880315574226688882885059231407395867521264603589328750088494023579948586691087264977774986922976804995702827730900938454450543271826620734894896480810226390051565227125 A46^9 * U3^3 - 4106654994410345218350715474180779469031652386352768990088763404863224321126834681787202405252012606245929498654531112676402813452159609458415502006915204469860173111678951294367642751272844986752033113410832855341088770049302498143130605877209294548098061602991987492963051239744/1873641150950399440382199101170729248751838603500480155941233917532177563939123849008905376960376042672980879894802811766877792781254677010290875933017668367708138871754892190575866387664387701726435938757970725432248728385512421517659676468958761146164189347149245825 A46^8 * U3^3 - 10861509873129061552037235599451402972763702999367178857883272454799214845428691114656489287350714907124422743117360275388527760856063819431352503904308954737409956132586217400390831701855393788768594250812823801249588131220343764676215839452260384917296536245871426396362711599029/26230976113305592165350787416390209482525740449006722183177274845450485895147733886124675277445264597421732318527239364736289098937565478144072263062247357147913944204568490668062129427301427824170103142611590156051482197397173901247235470565422656046298650860089441550 A46^7 * U3^3 - 1124486478466758794641936904982948237084283820279761242642612077110909965390094116007619021675739939209813695144499796429672334602667319111431706473000996398421642195295148270757273990731860799515046565486145747844982383328993615581180179952020178830599171027345719008701601415523/18736411509503994403821991011707292487518386035004801559412339175321775639391238490089053769603760426729808798948028117668777927812546770102908759330176683677081388717548921905758663876643877017264359387579707254322487283855124215176596764689587611461641893471492458250 A46^6 * U3^3 - 13634406027258739162572410843253056158384774240138183339467954043156022885658076072571122964861139837559116738714581975870696472208621260986499059519385686842525264750880868543070223665506121563803996657564834448591138230910580178478122708511083518804685049985931165670484826297/2141304172514742217579656115623690570002101261143405892504267334322488644501855827438749002240429763054835291308346070590717477464291059440332429637734478134523587282005591074943847300187871659115926787151966543351141403869157053163039630250238584167044787825313423800 A46^5 * U3^3 - 275610949766603790350543874491973128402944565236452331621829945535128551051089218509229304570354572863614983692536142099515347666278429222971179578469228299012270654864962841491251938427241318189542247237765029951590277176611163743592667595081103539096197325545120410752450853/611801192147069205022758890178197305714886074612401683572647809806425327000530236411071143497265646587095797516670305883062136418368874125809265610781279467006739223430168878555384942910820474033121939186276155243183258248330586618011322928639595476298510807232406800 A46^4 * U3^3 - 57091321219446868547123718685194170669561742150029307684083906984399449382980015516422277491250022223527057750658840237853760266613003361978501494129695368914676980282464037464506358216208278225667602395223784571111874119085762583994232092883441120694085505220223346971423259/3496006812268966885844336515303984604085063283499438191843701770322430440003029922348977962841517980497690271523830319331783636676393566433195803490178739811467081276743822163173628245204688423046411081064435172818190047133317637817207559592226259864562918898470896000 A46^3 * U3^3 + 2096019020134284361588278549962801625099190206781628224639171740828930915568065430755481920106589988497979688771818295815492190569468006618308754762164717538084498525703860854191800473065932573287633087040724218118612995977781646506334852358874110328385808128162955638079/14269415560281497493242189858383610628918625646936482415688578654377267102053183356526440664659257063255878659280940078905239333373034965033452259143586693108028903170382947604790319368182401726720045228834429276808938967891092399253908406498882693324746607748860800 A46^2 * U3^3 + 144724249725887284436232581781817786550817001839619049910175696311756292310832604781793691600419996522748911371809754829004775699207861014225518336712102081581627568566107942347420832194840104563187671858359656942129120425684588448408665047033556866808539561866776501/4314260184514436127964380909564205783497694829005739203533961800265235707347901241580178583419276511944332172118198058625922700944228258513515422265634676676652729605557958459498206914038519040580512540841853144915778977442507150190146154648188267067194741571840 A46 * U3^3 + 34523752399540034716636145000935730218516677827634880256328110824710605643763228906652973946423825292328221117422519494495751855171799684110699308767573648503790821554402991388888863972166596620407299382152069987750344858727174998460595722071373991687451348757265/52827675728748197485278133586500478981604426477621296369803613880798804579770219284655247960236038921767332719814670105623543276868101124655290884885322571550849750272138266850998452008634927027516480091941058917336069111540903879879340669161488984496262141696 U3^3 ) ) """; ps6=""" ( ( U3 * U4^3 + 41822330490195068041017320363097809729090890052699731534033293673080362045613806875773900749189755394694179768458994485940692483615892634922652342251410719603257617491056399521754985563535628528166060660260046980535041591378337983957604595139759378622893247460686601951641600000000000000000/356450080441422916364430404818046149990025416021600380113859661592463002937141992302140913567282244477259049192463045797202514832886802745887131987012951584257301943346187289394823441396232477000190857226368174895516164344503923290523438801001095804385269931852430936453389 A46^33 + 454125157206527413523601969987620494847328162420135984302287459170369832878272220272886380031914311891233003000504439954565744301327926677967038692247319542412616194634678505272858478303439697166808691979442683766268105374119197842122316902319990742401536311538368167952547840000000000000000/831716854363320138183670944575441016643392637383734220265672543715747006853331315371662131656991903780271114782413773526805867943402539740403307969696887029933704534474437008587921363257875779667112000194859074756204383470509154344554690535669223543565629840989005518391241 A46^32 - 14740085336461820800966266074682241729581054272188710537515241908189807762813569534360041532382661570106035157724159025403425541339461211407295309969242948500584368294316900034869383665586431029071989963112162284745485647807851469068632801796651905968443260670347124770482847744000000000000000/52398161824889168705571269508252784048533736155175255876737370254092061431759872868414714294390489938157080231292067732188769680434360003645408402090903882885823385671889531541039045885246174119028056012276121709640876158642076723706945503747161083244634679982307347658648183 A46^31 - 9149331424499552779979794487803049109145854134654822152707377782056977306922942650458296507280354954701791394660220920473087273186333364153948147270760935725093184452955662120588287066833595316280317830971486425063174196982668087569045226676196390232025049390929919119574244207001600000000000000/1100361398322672542816996659673308465019208459258680373411484775335933290066957330236709000182200288701298684857133422375964163289121560076553576443908981540602291099109680162361819963590169656499589176257798555902458399331483611197845855578690382748137328279628454300831611843 A46^30 - 79973012198225026539332842880094613358418060119022835029835910425124670099764459027277518388837201641732137026202824480404214035628958792843162201239309141530235969873589550508448718782972837671619969580166184326037129487506541556889887126810734028550977167372000415444560765391994880000000000000/2567509929419569266572992205904386418378153071603587537960131142450511010156233770552321000425134006969696931333311318877249714341283640178625011702454290261405345897922587045510913248377062531832374744601529963772402931773461759461640329683610893078987099319133060035273760967 A46^29 - 8299397433438618012971050717608586981007096658561248516910138778913485394953866129982359922925735316581762478702897711207576975054100165652131628929716109958379944654693325699234875749400905318226733372296404518054930456353699133199857710268046545544970469824348289708598182344299520000000000000/122262377591408060312999628852589829446578717695408930379053863926214810007439703359634333353577809855699853873014824708440462587680173341839286271545442393400254566567742240262424440398907739611065464028644283989162044370164845688649539508743375860904147586625383811203512427 A46^28 - 1009095872071060606887382314527808282304198676274688330469220230071145794033535363745528418711512251257265245188164841956986767644719780200297491853553606313847573922892151658199998953665772946824914444133907829818800088800411900616394966638527678678559806341695040379358176887422246912000000000000/9903252584904052885352969937059776185172876133328123360703362978023399610602615972130381001639802598311688163714200801383677469602094040688982187995180833865420619891987121461256379672311526908496302586320187003122125593983352500780612700208213444733235954516656088707484506587 A46^27 - 17315208871659672382889994991298216489948823684300447200387695359236475124436480420376202114747618244141605164691824173316146543744310447948881287127831116503491247576077521276794352818587011612296482326427954766142441690371899121755561881707409211508579604162112995865737896762901299200000000000/157194485474667506116713808524758352145601208465525767630212110762276184295279618605244142883171469814471240693876203196566309041303080010936225206272711648657470157015668594623117137655738522357084168036828365128922628475926230171120836511241483249733904039946922042975944549 A46^26 - 355912103283291653350342202441876054749468980229513306853575234001898259812970951366303068842390266228175806871138615053043787098181575854719444584002263604429051532090218493757283996626942336013246526185261992049786421446412979193448620795644178642889464382438869086312841888992127016960000000000/4244251107816022665151272830168475507931232628569195726015726990581456975972549702341591857845629684990723498734657486307290344115183160295278080569363214513751694239423052054824162716704940103641272536994365858480910968850008214620262585803520047742815409078566895160350502823 A46^25 - 22500215142403543279349306218081169611665243245444094081053540155023353065879988896297915009225132894908494486994564419892386896801934687727963175381359248310045430450423575265267918061375611015895078661355902220676428093155477822434762767854058633074606376473106078760663121039247968256000000000/606321586830860380735896118595496501133033232652742246573675284368779567996078528905941693977947097855817642676379640901041477730740451470754011509909030644821670605631864579260594673814991443377324648142052265497272995550001173517180369400502863963259344154080985022907214689 A46^24 + 32673087924159313144791905275717518339829777902894646782455060134934567490559434999059780860378598405024654197705939033389093954547300991047620772736355387222770403567834688718752714161637753797576326177011424906610337687450739278051783922665936466482962665445318545262436466728042148326400000000/5456894281477743426623065067359468510197299093874680219163077559319016111964706760153475245801523880702358784087416768109373299576664063236786103589181275803395035450686781213345352064334922990395921833278470389475456959950010561654623324604525775669334097386728865206164932201 A46^23 + 1104476613898878470428452483404305645696373154435799116198630014006790595031027352442953347316486180518984682424499974769238555293892978509198039261572798669589819427036166245573413843280166968329333248039556067221899335330112207191529323373567807146257408223366473003726728025624000104960000000/37121729805971043718524252158907949048961218325678096729000527614415075591596644626894389427221250889131692408757937198022947616167782743107388459790348814989081873814195790566975184111121925104734162131146057071261611972449051439827369555132828405913837397188631736096360083 A46^22 + 78113480257566589843454213154883751458293793164562951385751797138539577840045698708433870322843582703179960018071553825115618374965480805851557122788075034745129320776152687748718547900383557327895464091642273092813119121008016975113831330943443029648706513051422069517463619351777438820096000000/2338668977776175754267027886011200790084556754517720093927033239708149762270588611494346533914938806015296621751750043475445699818570312815765472966791975344312158050294334805719436599000681281598252214262201595489481554264290240709124281973368189572571756022883799374070685229 A46^21 + 8395276376303141598390829139882556608548753795333152128887172440477769331506706983960503595713255764449491015079245760485357931286228197098907656335096624996307325605986758954601108746818602104646481755620539840786476094323961082674609265938980034638463288197875497334999695180183262425971200000/334095568253739393466718269430171541440650964931102870561004748529735680324369801642049504844991258002185231678821434782206528545510044687966496138113139334901736864327762115102776657000097325942607459180314513641354507752041462958446325996195455653224536574697685624867240747 A46^20 + 1980830687381076339084629170133609739180380880215294749410365337574729337777957070632004952411058046327505217385303454420099905980785666056543363976205429431407119959330949327855470437048628780012191977441692141470352845169941328389007388270439665640289698273307474532663228874959149967256320000/143183814965888311485736401184359232045993270684758373097573463655601005853301343560878359219281967715222242148066329192374226519504304866271355487762774000672172941854755192186904281571470282546831768220134791560580503322303484125048425426940909565667658532013293839228817463 A46^19 + 702091132949191502045640382611695646026178320839883517672739200609357661071215369230485179018215789550721046578374598929240937327355327668355522069483080934376708869486654867322142997232774287348753757914178992350603911472387418363244015679942880338944525806103128925167085917623892484556464000/143183814965888311485736401184359232045993270684758373097573463655601005853301343560878359219281967715222242148066329192374226519504304866271355487762774000672172941854755192186904281571470282546831768220134791560580503322303484125048425426940909565667658532013293839228817463 A46^18 - 26433410235178253131164568590264182053663342966938907183003177081908265950075927144928504095882195140380650366718219667766773538150084001651408286437201753129205947322295717753544109541401358911647830600006212366636193412718513659512611675534262638709507230297656780911489899859088163252104000/429551444897664934457209203553077696137979812054275119292720390966803017559904030682635077657845903145666726444198987577122679558512914598814066463288322002016518825564265576560712844714410847640495304660404374681741509966910452375145276280822728697002975596039881517686452389 A46^17 - 36588941424973786825226031379192323188694220080503719244669152016528167903934256688892636045811947246452459444223170684913020286311345813411596839167079667051478933505562383477365997492491009488269523510100891279267477520527793501298375191462023458969167972627835965786511419141962714020174080/20454830709412615926533771597765604577999038669251196156796209093657286550471620508696908459897423959317463164009475598910603788500614980895907926823253428667453277407822170312414897367352897506690252602876398794368643331757640589292632203848701366523951218859041977032688209 A46^16 - 321333621660414138288318264757386991534769910679354013783840583853994409935788586791159864436843010390611984538928952685258511624721739694382405481016998808554437914129696961450517494564423154689101019268062664959334760483746323046684415109519127596246390980123789139075174901071183005966554488/184093476384713543338803944379890441201991348023260765411165881842915578954244584578272176139076815633857168476085280390195434096505534828063171341409280858007079496670399532811734076306176077560212273425887589149317789985818765303633689834638312298715560969731377793294193881 A46^15 - 297844721921145322765306527355860406934008939169980445647884079222865480952075045050385650004580591246687712266033786754423786883489838690861527534993455211693991394970866545156968100893505892393812058175717385845665650930957741425381878068688495541752226534683879631214290521382589457098661971/262990680549590776198291349114129201717130497176086807730236974061307969934635120826103108770109736619795954965836114843136334423579335468661673344870401225724399280957713618302477251865965825086017533465553698784739699979741093290905271192340446141022229956759111133277419830 A46^14 - 451879932351907431338340841430894291445765587061006243890312609075513994394090487211287876791443241336702645913369115324679497644368945637845627225355027484550118544624707338874219923703785680226085214156696766542732612750915702425388991747367656078911167375594394305408128145699286227195203039/788972041648772328594874047342387605151391491528260423190710922183923909803905362478309326310329209859387864897508344529409003270738006405985020034611203677173197842873140854907431755597897475258052600396661096354219099939223279872715813577021338423066689870277333399832259490 A46^13 - 5320311585057193929116580887725053048673711797951597468291152199479233897939064740829295546757123058099231381384546836150171434463598328526972269844562130162789158735497528507679194843684312884543346736256634246332090848994957191293298207019966632338305847326064328022091724095239631394444614337/22542058332822066531282115638353931575754042615093154948306026348112111708683010356523123608866548853125367568500238415125971522021085897313857715274605819347805652653518310140212335874225642150230074297047459895834831426834950853506166102200609669230476853436495239995207414000 A46^12 - 362392746608515719372641040156549702648285106850030418671446645004524075469397447508371929006539117538692298420067983710297061362768282375139330712098123029408339164065434243491074476680334774441684136089288247838831323010949142346356824849579571331534045674787558012078606230561135787887949871/4508411666564413306256423127670786315150808523018630989661205269622422341736602071304624721773309770625073513700047683025194304404217179462771543054921163869561130530703662028042467174845128430046014859409491979166966285366990170701233220440121933846095370687299047999041482800 A46^11 - 155718157831390278974558432491864519634779570729825416271843627583866505195625371450767361228547485547131717071612734991086436233519540316144548267366374648257565699340887077601451758110896914837331994622765481537988675137980472319274860288480400497182597917963360319541332897673699613001900139/6869960634764820276200263813593579146896470130314104365198027077519881663598631727702285290321233936190588211352453612228867511473092844895651875131308440182188389380119865947493283314049719512451070261957321111111567672940175498211403002575423899194050088666360454093777497600 A46^10 - 45201548094888346900126189229758597421851803521277808642167463508827660396693637290758710792553278488070609212455021345000119146078696472196451660991329985879243486243508404638669646114695294849026046972039432309027960523963229014364806077507073721111320914116188285819616980932331878040743049/8587450793456025345250329766991973933620587662892630456497533846899852079498289659627856612901542420238235264190567015286084389341366056119564843914135550227735486725149832434366604142562149390563837827446651388889459591175219372764253753219279873992562610832950567617221872000 A46^9 - 1953129387759091287411246093721824623775778716719168388328766612507051710224152064386589191585418322171515414473927996208486195431232117229550712885298021138550712056198139675205800600486010459477444720900066414100009247618626937808864666954121404483671145377185645585361795757512848953771727/1962845895647091507485789661026736899113277180089744104342293450719966189599609065057795797234638267483025203243558174922533574706597955684471964323230982909196682680034247413569509518299919860700305789130663174603305049411478713774686572164406828341157168190388701169650713600 A46^8 - 376134847222603342228005080394985602907218977535587514699426664550583601459354985670099124083557791013853499761803409404040812308856476452671356746803998334683915044848315929579536086205259194433291389544619656281935845620125586677702558497845124290906144446668089290971220577745466063821/2503629968937616718731874567636144003971016811338959316763129401428528303060725848288004843411528402401817861280048692503231600391068821026112199391876253710710054438819193129552945814158061046811614526952376498218501338535049379814651240005620954516782102283659057614350400 A46^7 - 574485486982304350778070191971122027743291593240873280940414570314432804154563998121312928497476285147145839708807365153231143249845428378451535410210139619924467103332329351315189638465205694465434576925840400070753365257384354164688588108696337944766401214964460997424273537531595188679/32700473063674993877314280067084329847784709372590489035273526875801185999160500875598430607824044439533947575902676800042208658169062152177791992057159232139886425323352726590079292266554266733865985658153488956323282789029216389415852930685661446749807050235546874962944000 A46^6 - 11511257781723192579987461460171218665430662046039138877189380600683547596344289008862892439158437560118751792069494864896646099764172740280826359491156661557991789303166781418829521172671095190437798106362980957418171493748387515586895216124868996215985307716367044170468765302175191523/7630110381524165238039998682319676964483098853604447441563822937686943399804116870972967141825610369224587767710624586676515353572781168841484798146670487499306832575448969537685168195529328904568729986902480756475432650773483824197032350493321004241621645054960937491353600 A46^5 - 1671303995297463181793089014042140921533205745175671854516004230292597522756847916940561516331382516496857206868368002684300205049090986725992113164539129267661714078303721803021367606163396471932149786832020402699788845934151506635865863054320744139050271729184411228168473604636972839/19620283838204996326388568040250597908670825623554293421164116125480711599496300525359058364694426663720368545541606080025325194901437291306675195234295539283931855194011635954047575359932560040319591394892093373793969673417529833649511758411396868049884230141328124977766400 A46^4 - 60908092525844337290393747162251644298087521040833441461527761929200066595412859133091070618059209993364079718454967764919058787501486800829921561765930651085782549124215742770618379064496572773262751298821893631502246026461480269869465295797601392220253848115075799372526327938111547/28028976911721423323412240057500854155244036605077562030234451607829587999280429321941511949563466662457669350773722971464750278430624701866678850334707913262759793134302337077210821942760800057599416278417276248277099533453614048070731083444852668642691757344754464253952000 A46^3 + 45086394754577700869380844548742167538951281901932651744568905863102388384166263647335650948182916349574945031051918658847888488603435323077118198631600514293001349841754886818523071957433889642885763744141389343414660044929152119754129057333007696856923108253108183335928470691323/732185519326600445999340148440838639157395241928556722422450980775956584470998970042553781539617088325424832020211538846426129722269379967129569967927063856659847657385856968547548001770078042320964343599471706077442600057563795541439505853253294201278478559209912535613440 A46^2 + 3731272476720292507686304261693030416127583479257486748224902831742134747688100663209642453477726001478166688384847374161566164080254468319618379882752444074260128081142704326346717896603236118487929226426342553598574093896870131278947045099476660390852113706889521422745255/648548681376311336096354298151253046305799356866989727202426109672580591403591774768418528149462415254238265324025243450986863770434187187437615121817481448997172315569955506437383079799176270479879130881051326953517042284548430007652623523644145232141509494765016064 A46 + 9280862118536625477466695256284609672515130143361639412543372050128009110823486812077779222084224626376141852085219762625785282075028284601725310082870373135311800354168551231605316413369320027988216942534660872550537108296929260273306523538001567960935496614750288886518875/94873407104191829737523828758126159916734077347399640093612048043531789371039711051837224689292787602905711955971692756258649785846372525705159697820157286253300635877662062655982896244908071567342318574599508400057350185625370332548040926887372102530415103234196635648 ), ( U4^4 - 20/7 A46^2 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.isGB(); print "is GB output:", rg; print; ri = f.toInteger(); print "integer Output:", ri; print; rip = ri.list.get(0); print "integer polynomial:", rip; print; startLog(); rfi = rz.squarefreeFactors(rip); print "#squarefree Output:", str(len(rfi)); print; for h, i in rfi.iteritems(): print "h**i = ", h, "**" + str(i); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/rose_fac.rb000066400000000000000000001763201445075545500214730ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # output gb of rose #r = Ring.new( "Mod 19 (U3,U4,A46) L" ); #r = Ring.new( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring.new( "Quat(U3,U4,A46) L" ); #r = Ring.new( "Z(U3,U4,A46) L" ); #r = Ring.new( "C(U3,U4,A46) L" ); #r = Ring.new( "Rat(A46,U3,U4) G" ); rz = Ring.new( "Int(A46) L" ); puts "Ring: " + str(rz); puts; r = Ring.new( "Rat(A46) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( A46^34 + 347/70 A46^33 - 56411/58800 A46^32 - 441350327/6174000 A46^31 - 992593010489/3457440000 A46^30 - 217625706587/329280000 A46^29 - 373467217691021/355622400000 A46^28 - 38574512982739/31752000000 A46^27 - 968821009058023/952560000000 A46^26 - 5992612680961049/10886400000000 A46^25 - 13843426727931961/244944000000000 A46^24 + 1486519769228381881/5598720000000000 A46^23 + 61199280870444808261/167961600000000000 A46^22 + 513991046707657214269/1679616000000000000 A46^21 + 37908065080289396962277/201553920000000000000 A46^20 + 27223946509678338655459/335923200000000000000 A46^19 + 668594689016343141054373/48372940800000000000000 A46^18 - 36250135997129945800663817/2418647040000000000000000 A46^17 - 5712667240922865693346483691/290237644800000000000000000 A46^16 - 42053436689365696671983799179/2902376448000000000000000000 A46^15 - 561895388992743685886859196463/69657034752000000000000000000 A46^14 - 704377755966878925481768484749/193491763200000000000000000000 A46^13 - 2531676547158421516985730163481/1857520926720000000000000000000 A46^12 - 4750291847118917831874464404117/11145125560320000000000000000000 A46^11 - 1835783859800409552862056700927/16511297126400000000000000000000 A46^10 - 9916637291915563585725849353/412782428160000000000000000000 A46^9 - 252376016954713294866494065459/59440669655040000000000000000000 A46^8 - 178806028363626133639831815853/297203348275200000000000000000000 A46^7 - 31482408916666847417595615109/475525357240320000000000000000000 A46^6 - 3818476405879526813756500117/713288035860480000000000000000000 A46^5 - 896701239882765996997050397/3170169048268800000000000000000000 A46^4 - 4844358439974218651958787/760840571584512000000000000000000 A46^3 + 171452325388464998728627/730406948721131520000000000000000 A46^2 + 15230552381256429497/811563276356812800000000000000 A46 + 79792266297612001/259700248434180096000000000000 ) ) """; ps1=""" ( ( A46^33 * U3 + 129/28 A46^32 * U3 - 75613/29400 A46^31 * U3 - 871585543/12348000 A46^30 * U3 - 12095701697/46099200 A46^29 * U3 - 124924301563/219520000 A46^28 * U3 - 378293923381/444528000 A46^27 * U3 - 1617620272123/1764000000 A46^26 * U3 - 82886347203347/119070000000 A46^25 * U3 - 668049914090789/2177280000000 A46^24 * U3 + 99688309115142847/1959552000000000 A46^23 * U3 + 231138576685539839/933120000000000 A46^22 * U3 + 11659387634813949601/41990400000000000 A46^21 * U3 + 70151923964052383971/335923200000000000 A46^20 * U3 + 23176161047838396328367/201553920000000000000 A46^19 * U3 + 164454230781271289566939/4031078400000000000000 A46^18 * U3 - 55282700662490687816927/120932352000000000000000 A46^17 * U3 - 747149106093593978873861/50388480000000000000000 A46^16 * U3 - 841282928607636046387355983/58047528960000000000000000 A46^15 * U3 - 54661970877464131720410138953/5804752896000000000000000000 A46^14 * U3 - 830787778268485831652841532151/174142586880000000000000000000 A46^13 * U3 - 274531406380976793484077680017/139314069504000000000000000000 A46^12 * U3 - 750317990428317888436020594041/1114512556032000000000000000000 A46^11 * U3 - 1416119253746536814898928216649/7430083706880000000000000000000 A46^10 * U3 - 33046099809889641357330063959/743008370688000000000000000000 A46^9 * U3 - 25135248767946559916964025799/2972033482752000000000000000000 A46^8 * U3 - 38214637789543687723872942433/29720334827520000000000000000000 A46^7 * U3 - 3604383688017858128502121387/23776267862016000000000000000000 A46^6 * U3 - 10419538500903067530134609/792542262067200000000000000000 A46^5 * U3 - 268160889047530270882049141/356644017930240000000000000000000 A46^4 * U3 - 4494450124912371106208621/228252171475353600000000000000000 A46^3 * U3 + 19160001876330286653661/36520347436056576000000000000000 A46^2 * U3 + 4148034694905888017/81156327635681280000000000000 A46 * U3 + 11398895185373143/12985012421709004800000000000 U3 ) ) """; ps2=""" ( ( A46^32 * U3^2 + 149/35 A46^31 * U3^2 - 119419/29400 A46^30 * U3^2 - 17080619/246960 A46^29 * U3^2 - 32939303767/138297600 A46^28 * U3^2 - 29988193601/61740000 A46^27 * U3^2 - 3784045943831/5556600000 A46^26 * U3^2 - 2693634126319/3969000000 A46^25 * U3^2 - 21841275550799/47628000000 A46^24 * U3^2 - 21239300351867/145152000000 A46^23 * U3^2 + 100022001638857211/979776000000000 A46^22 * U3^2 + 296696864208881153/1399680000000000 A46^21 * U3^2 + 17088141121241394989/83980800000000000 A46^20 * U3^2 + 19261885997631012911/139968000000000000 A46^19 * U3^2 + 13468170505032365821223/201553920000000000000 A46^18 * U3^2 + 35088518623022364409189/2015539200000000000000 A46^17 * U3^2 - 99017698968245042551237/15116544000000000000000 A46^16 * U3^2 - 3789770743783848575384507/302330880000000000000000 A46^15 * U3^2 - 2933051673126807110607585563/290237644800000000000000000 A46^14 * U3^2 - 948072476821568942948806667/161243136000000000000000000 A46^13 * U3^2 - 18896655281197310848727704481/6965703475200000000000000000 A46^12 * U3^2 - 2845096388251912350859674973/2786281390080000000000000000 A46^11 * U3^2 - 39111610674783351035074010869/123834728448000000000000000000 A46^10 * U3^2 - 1486938573940216107905934971/18575209267200000000000000000 A46^9 * U3^2 - 2445791954945323169329394873/148601674137600000000000000000 A46^8 * U3^2 - 333946045138720738819094237/123834728448000000000000000000 A46^7 * U3^2 - 406526799915645826522761061/1188813393100800000000000000000 A46^6 * U3^2 - 6322467405069477857023283/198135565516800000000000000000 A46^5 * U3^2 - 490026291814312040719379/247669456896000000000000000000 A46^4 * U3^2 - 169501103784936018875857/2853152143441920000000000000000 A46^3 * U3^2 + 2012646248526699378523/1826017371802828800000000000000 A46^2 * U3^2 + 5217570099427357/37572373905408000000000000 A46 * U3^2 + 1628413597910449/649250621085450240000000000 U3^2 ) ) """; ps3=""" ( ( U3^4 + 36097228800000000000000000/282475249 A46^33 + 1161224847360000000000000000/1977326743 A46^32 - 4677045387264000000000000000/13841287201 A46^31 - 874485621920563200000000000000/96889010407 A46^30 - 22660530808584929280000000000000/678223072849 A46^29 - 48947976962992465920000000000000/678223072849 A46^28 - 212357741794443264000000000000/1977326743 A46^27 - 33417694635162617446400000000000/290667031221 A46^26 - 1195585718651671592960000000000/13841287201 A46^25 - 4622243456144475926528000000000/124571584809 A46^24 + 57492745364488210585600000000/7626831723 A46^23 + 5064235904207031314222080000000/160163466183 A46^22 + 796549541441999106994688000000/22880495169 A46^21 + 1776805509375610240638745600000/68641485507 A46^20 + 6571948331935947500408320000/466948881 A46^19 + 15900562307775474505007648000/3268642167 A46^18 - 781823011269699906939632000/4202539929 A46^17 - 23911885581267405621130949120/12607619787 A46^16 - 66484142665897834547281936/36756909 A46^15 - 31344755225898717841650588049/27016328115 A46^14 - 748245898727397783769699627/1286491815 A46^13 - 61180345995024957255947775667/257298363000 A46^12 - 1772332138625205728147155697/22054145400 A46^11 - 1763442424064055410851226129/78414739200 A46^10 - 72564573592100205725791837/14002632000 A46^9 - 65329613048147169962793719/67212633600 A46^8 - 87361765982805204782291/600112800 A46^7 - 6483564254536224014425081/384072192000 A46^6 - 23648026104539505065429/16460236800 A46^5 - 880685511246977438581/10973491200 A46^4 - 31439956654789887473/15676416000 A46^3 + 17918243525346457327/300987187200 A46^2 + 10074090036167/1866240 A46 + 34829612499283/382205952 ) ) """; ps4=""" ( ( A46 * U4 + 7/20 U4 + 2806378846741861368786614566878031251136601782233486293371124444033709909300049715978016727056150885946954243402645730462178807446021415693833183139081658586984935909957265108287928306576671117507805428087796888020739324547730219269915178825763993883433817341952000000000000000/193099928700513998070936429904026968056396066087989232333196930214044975387024916636846108968424103894255784064885243976305160746405290836679402752295622754790839675018341679885489238996414850488675112243144046216420956878738117538991288033099828416943500600350187 A46^32 * U3 + 140608368210259054916983904673796347993009087108223449480869140637168687474157820242084293427769280716150829987371903694486407125016157557573489507333502558345102130864385866957396552184077632209367448052303724048297487583320428452817989972383673573195382911926272000000000000000/1351699500903597986496555009328188776394772462615924626332378511498314827709174416457922762778968727259790488454196707834136125224837035856755819266069359283535877725128391759198424672974903953420725785702008323514946698151166822772939016231698798918604504202451309 A46^31 * U3 + 2973132530031750926781836728171190368295908349443863657109054185698567452354483691980282671132312007156981877065422976124734148815655910511834380182331303177950358622308259910423832682100194502857004946063777788209711503282994815361158167402207667989232295462169477120000000000000/28385689518975557716427655195891964304290221714934417152979948741464611381892662745616378018358343272455600257538130864516858629721577752991872204587456544954253432227696226943166918132472983021835241499742174793813880661174503278231719340865674777290694588251477489 A46^30 * U3 - 738219222373037292445012084441369194910728746958545194778441077198902948054263364937417682200010729210575746685991736931724571115099030702915394756575817790642985569814303481715585979651308619587706574566955474220298898070223241914619143731590342509740953174566721552384000000000000/596099479898486712044980759113731250390094656013622760212578923570756839019745917657943938385525208721567605408300748154854031224153132812829316296336587444039322076781620765806505280781932643458540071494585670670091493884664568842866106158179170323104586353281027269 A46^29 * U3 - 26263613198277033357242907881790564317638488547844618743001644843010275951255995601618105986940603997061861718415452159942810394664057894925733725044191873926510994765442061292542368154720543459005227757920995136654748098710382908816433885918895473973271287136201940664320000000000000/4172696359289406984314865313796118752730662592095359321488052464995297873138221423605607568698676461050973237858105237083978218569071929689805214074356112108275254537471345360645536965473528504209780500462099694690640457192651981900062743107254192261732104472967190883 A46^28 * U3 - 9560261987467874294850640971728702760731659080417859619462176031496681069887590878558384729317157715276514804678872739436230630658282680026803340746414284932116802254277874675348065517256502425989246849745315895036906790401640417642341755791726718494097465403286844184985600000000000/596099479898486712044980759113731250390094656013622760212578923570756839019745917657943938385525208721567605408300748154854031224153132812829316296336587444039322076781620765806505280781932643458540071494585670670091493884664568842866106158179170323104586353281027269 A46^27 * U3 - 144636713736027890114035034090555770840107473490985685648308419164337400894146263765715981457017308677715082713471432001864714782421560684446718632104959754377888118909536279270581334669935787514862899283922492256748522286708189406470339423887947462918232309558821679529984000000000000/5364895319086380408404826832023581253510851904122604841913210312136811551177713258921495445469726878494108448674706733393686281017378195315463846667029286996353898691034586892258547527037393791126860643451271036030823444961981119585794955423612532907941277179529245421 A46^26 * U3 - 24532425560872733727048401118804283865911311477564921900335177229012489937286467620463606284515609505035616190873825110294676684892007020876691541110492442185186251334711679953191506232457944676021905960044901546391272864711217070545467913465760834235337077332640608895369216000000000/766413617012340058343546690289083036215835986303229263130458616019544507311101894131642206495675268356301206953529533341955183002482599330780549523861326713764842670147798127465506789576770541589551520493038719432974777851711588512256422203373218986848753882789892203 A46^25 * U3 - 61280378855985472962083715267099870468639547774190782208008687497788816915947177474302623147240238616774447758611668598585355022788830824893247197811650042416494226679277235085459349523493402070913785423068849805945203419134911827923486496461119063853055966658119121257129574400000000/2299240851037020175030640070867249108647507958909687789391375848058633521933305682394926619487025805068903620860588600025865549007447797992341648571583980141294528010443394382396520368730311624768654561479116158298924333555134765536769266610119656960546261648369676609 A46^24 * U3 - 1484357436021657507567420650984058019197004585757942514498995263423808522091214018761612749478663033895612373062807866818414484967623858841053321992327465827514651989711202442802087572810894125998644840666538477463088224296505304638389800637458850650417392471695314042172211200000000/109487659573191436906220955755583290887976569471889894732922659431363501044443127733091743785096466908043029564789933334565026143211799904397221360551618101966406095735399732495072398510967220227078788641862674204710682550244512644608060314767602712406964840398556029 A46^23 * U3 - 142706740914560864457369678713491100078718980040431434176679594896408407693192038718320939423503224607224793619606860312440116490102586591426353170601317496666073657735251911434293391435267804199376695206269942247915428218586358462081096742118453704497075161839492889751191552000000/2956166808476168796467965805400748853975367375741027157788911804646814528199964448793477082197604606517161798249328200033255705866718597418724976734893688753092964584855792777366954759796114946131127293330292203527188428856601841404417628498725273234988050690761012783 A46^22 * U3 + 3437067913738929851828191102489541091985420513352095924549529468703404236611368673420787140580385095687914414418203044807769960408456154049568142240000401501441029724428786621410870408162134547736165823446770365996810358019535793543622855984068400287198402234509017467116735692800000/422309544068024113781137972200106979139338196534432451112701686378116361171423492684782440313943515216737399749904028576179386552388371059817853819270526964727566369265113253909564965685159278018732470475756029075312632693800263057773946928389324747855435812965858969 A46^21 * U3 + 12665325755293011964582773351828201837497408957482566179025807264260205331500166852839160281570134088487784028319208757397082649585467393387792231298887791806004696105674306391612545456300491907001838309111269128096161395643695348999989978496685257886403350330750962195611697479680000/1266928632204072341343413916600320937418014589603297353338105059134349083514270478054347320941830545650212199249712085728538159657165113179453561457811580894182699107795339761728694897055477834056197411427268087225937898081400789173321840785167974243566307438897576907 A46^20 * U3 + 472460708046707276929317308260575825818443603966144032149144933738614980186931958850077619729999743406167265787440681567111099352622569281813602576458470534069879413676204407012264193237661238006825286040265059435939142815940360874733243831244058419301704863623227097616300687360000/60329934866860587683019710314300997019905456647776064444671669482588051595917641812111777187706216459533914249986289796597055221769767294259693402752932423532509481323587607701366423669308468288390352925108004153616090384828609008253420989769903535407919401852265567 A46^19 * U3 + 49390047765871082949860891586805882007616506646541386751626133624251152479425727198070508507708042448289532261339277046519001543624931425618731092311111454034423497441761556818193037978230663070411942523132669576228611039810197751659696742852563815776238111135652689883724583731200/11081008444933577329534232506708346391411206323060909795960102558026376823739975026714408054884815268077657719385236901415785652978120523435453890301559016567195619018618132026781588020893392134602309720938204844541730887009336348454709977712839424870842339115722247 A46^18 * U3 + 129068221133437408101386032010227938242790415417408002956440388834868112181036866325987181792617952620211570225145421401636968642407417865428308813969801472080155460044151903911373059980563777215433387329713871436510348502082703071326443785803142144287247590693723735936473435504640/77567059114535041306739627546958424739878444261426368571720717906184637766179825187000856384193706876543604035696658309910499570846843664048177232110913115970369333130326924187471116146253744942216168046567433911792116209065354439182969843989875974095896373810055729 A46^17 * U3 + 12783978249076530856412299581616499812448814070864143616141639515320829793115590125926560504059268257844159130491162326200688965203538567110804552270764562224831755709762903109729453955480299083281536877866482795304181415809809747877796974966623540360991948948407257749615539560448/232701177343605123920218882640875274219635332784279105715162153718553913298539475561002569152581120629630812107089974929731498712540530992144531696332739347911107999390980772562413348438761234826648504139702301735376348627196063317548909531969627922287689121430167187 A46^16 * U3 - 1810442970097170462121122653290427291604967782620000014180906504389275928944428879269826615110693111930022066722356506712480414023024345146923757896554522544082287653722476697782328057603177530844114988866728376051365543251948667665657844199641256470495166203610372754104633985024/3392145442326605304959458930625003997370777445834972386518398742252972497063257661239104506597392429003364607975072520841567036625955262276159354173946637724651720107740244497994363679865324122837441751307613727920938026635511127077972442156991660674747654831343545 A46^15 * U3 - 270639555533122280020486247514756020301825934358369840608010596756492667631965814059407427090369596575058017999403434671889521831726503036761805006306129032875224481365310003762906407037966481686173976406974516397321267076580148872307324693442737067092534607150395172934720327272832/498645380022010979829040462801875587613504284537740940818204615111186957068298876202148362469816687063494597372335660563710354384015423554595425063570155745523802855837815941205171460940202646057103937442219218004377889915420135680461948997077774119187905260207501115 A46^14 * U3 - 1435948341205771592618056822768583583847960643508655403782679773815551216480844799951609196462939014609390424305428592870359320910647059517420727369800472093539593358295705161364370776721823709904982580674821197915654942789644804770077615722633391761110116425814824933514747954464/4038268383722149172570784441220242854012830292660681412521903264586872020313401977665600603092133844051624533303657762906627424554708645566856374016603140148394904890166957735707575809363481098616002084890016342763021460280370389378538621615466262708032922418266125 A46^13 * U3 - 24031158593232439577778424195027450454772002899626269270999618447601656149784654839122276071971243436018537991067130120319932291937910513510530154436517553834823319688270120213094719167314095473720221761127649325967639043315665428464820334187025317629951306324495868404822629086296/134236911348351843098270045621466866730124986864072399717750703996191750825995749157075115524896810946741187375897970359936383987082400454395753337285576744128805506776152891566359869240901645564547003977625417625011994772636432792658457195911102149817275285411208125 A46^12 * U3 - 55342608527391903114377714171300343766958416997314322747423256743530874483390328684036373961531616542340488099823707750319655515404839491476271584066825595064560837447788507941963050626463472192927052092190464771899480038023820496414639119032434176994304931597908860375406025786078/763232724523486193615878259390625899408424925312868786966639717006918811839232973778798513984413296525757036794391317189352583240839934012135854689137993488046637024241555012048731827969697927638424394044213088782211055992990003592543799485323123651818222337052297625 A46^11 * U3 - 2029624852259950049380302093920186872530375028355631473518046159913882812276759452807058944803805569580457303136641881139738479285051882346521262597896200616610534853804143612625821026733823701571937719332556063675018717208715246680768950536936393557501213975920703061913308587814/84803636058165132623986473265625099934269436145874309662959968556324312426581441530977612664934810725084115199376813021039175915648881556903983854348665943116293002693506112449859091996633103070936043782690343198023450665887778176949311053924791516868691370783588625 A46^10 * U3 - 1168942911153266036621765763524847385999721254478313573544681811727225087201633669304728449000690805131434160354788200355429868149616777944697604839445821146293319865569802164294050791015324448927695484221067203620046595245414313118308514802029950573572440600781377894978809819943/181722077267496712765685299854910928430577363169730663563485646906409240914103088994952027139146022982323103998664599330798234104961889050508536830747141306677770720057513098106840911421356649437720093820050735424335965712616667522034237972695981821861481508821975625 A46^9 * U3 - 101409764297139370497431870913772400890980479461654448912068336828050482388546012701358058370032729748116854879439321035194274795413256750973689666942448462456840973308098467386964329640348557236019188613852479460195591937286545711022988218130783801374434056440021146855389791263/72688830906998685106274119941964371372230945267892265425394258762563696365641235597980810855658409192929241599465839732319293641984755620203414732298856522671108288023005239242736364568542659775088037528020294169734386285046667008813695189078392728744592603528790250 A46^8 * U3 - 3322794676291853666085201130675181837616673614933545069242421946525758427676251695684072633966150401809622984292825237098582373428490919709859723984671293905443481868170729806447368393045191340333060166403807452609937752781689646834959249508572627032878032237058297511762260717/13845491601333082877385546655612261213758275289122336271503668335726418355360235351996344924887316036748426971326826615679865455616143927657793282342639337651639673909143855093854545632103363766683435719622913175187502149532698477869275274110170043570398591148341000 A46^7 * U3 - 235997802096027015525218011390431135161602429335194555350491794738198772970078394908866958050373633238495091699843397584952514894044850979218568026142058202580747771909113137749719827302612618129281900176792733050978935129822521807364852652110897499832909022097494923166043147/7417227643571294398599399994077997078799076047744108716876965179853438404657268938569470495475347876829514448925085686971356494080077104102389258397842502313378396737041350943136363731483944875008983421226560629564733294392517041715683182559019666198427816686611250 A46^6 * U3 - 3496748794132449388555216753002710407113019869328151832331519672134490805457467271923368355368145123271002659562187642206698039955131848140898636455957544259518289841694390481218777439807140629994396001816472151472171553970751649445797629489197230923775536860056783627934479/1130244212353721051215146665764266221531287778703864185428870884549095375947774314448681218358148247897830773169536866586111465764583177767983125089195047971562422359930110619906493520988029695239464140377380667362245073431240692070961246866136330087379476828436000 A46^5 * U3 - 25797731568499728113711563609522696636972574369245543976139702215108120141166264492184554278639511568603311186805558250985505155379498427020368472760296798230482403566780044258141402965693251712985897771176010862913999745411179857703742819398871451136186089552354116699661/129170767126139548710302476087344711032147174709013049763299529662753757251174207365563567812359799759752088362232784752698453230238077459198071438765148339607133983992012642275027830970060536598795901757414933412828008392141793379538428213272723438557654494678400 A46^4 * U3 - 105307750747592845167925795351809474019566402815312738506184953133174877999878727791254675413428352747128321422294719175016172361719591143541377238760546940146607913162164819516842775340285454038918138509577296566880300576934730064221978046439482447941555635234543414413987/16607670059075084834181746925515748561276065319730249255281368099496911646579540947001030147303402826253839932287072325346943986744895673325466327841233357949488655084687339721075006839007783276988044511667634295935029650418230577369226484563635870671698435030080000 A46^3 * U3 + 6729992771983469644834688420302244188161700009523433301108672306478446515336817887911228386552702182506838452635857560083522640089937561680000956097567263329228552440470166784211722333574861459688985916960390707820563713605127900163322847651117899308325942825648612997/67786408404388101364007130308227545148065572733592854103189257548966986312569554885718490397156746229607509927702336021824261170387329278879454399351972889589749612590560570290102068730644013375461406170071976718102161838441757458649904018627085186415095653184000 A46^2 * U3 + 97004104716134687567531815774189859076177884454360758941608137811927278665332561915062791777635759119435458822688898910056883442317958132684946302161704171063308484365878439710058473575123783245727688981281817771384031307613137609700123391407537243830931947114431/6831585629064056574855845836052158745080934515857178544035198543609673601669897191808363859627789995425297044867960294464526195050373321126677188143307925380675194012654126509458510328107232388557460939286669359345141026801890396437380097619257766330571494400 A46 * U3 + 91815250260603771367686439814867337622922814376622703580092567517752668189839523750475603039746288206705982958930474905045662465449513750706031249185792777351062825505761724720085638243587008740273119957261765515541418363044444151757419729917247863640658968103/351338689494722909564014928711253878318448060815512039407524496528497499514451855578715855638000628336158133736066529429604204316876342229371969675941550448149009977793640791915009102588371951411526562591885852766321538521240077531065262163276113697000819712 U3 ) ) """; ps5=""" ( ( U3^2 * U4 + 535179163636213160230552332612905761790726203364450534489129686242659247983859225063689303002742332435127911688744222034136908867349929123331100864371658990936252805314758914346647230739008414163809378439226935298947238851749778443095061790353887385009084423995392000000000000000/348416638018627423852659631690165992696423968578095238206531661082875150589988624585082662615359891459868853047741275214579945040097279766315202366058735323894271720291427837740051083562531195231732794190712907389828879861536476746186614041056457073638389583231854077 A46^31 * U3^3 + 117444957438518475167713581434975737067164998391805610491814809960560346257088363610575217412650923824342320317819214071400331125353389211274396241076281078058047842081052040344628591911420714970389327499109713526665438238583003654833271274497439548231330310580181401600000000000000/2438916466130391966968617421831161948874967780046666667445721627580126054129920372095578638307519240219081971334188926502059615280680958364206416562411147267259902042039994864180357584937718366622129559334990351728802159030755337223306298287395199515468727082622978539 A46^30 * U3^3 + 2401741581776741318484092416102407292900015435135593836159021006355478379624893489598800836632769384261155218893078011625298104568085745627327942804937416501911688374548247994274079800109905304371024073616832343444568942958320613360649846757743965134232833554270042193920000000000000/17072415262912743768780321952818133642124774460326666672120051393060882378909442604669050468152634681533573799339322485514417306964766708549444915936878030870819314294279964049262503094564028566354906915344932462101615113215287360563144088011766396608281089578360849773 A46^29 * U3^3 - 805568218873790937813389084592233191792825630736851320718859307972639139165702967980087508722852747263747190017939561005107936647865901266983449666943346565871280018184856673037268657368899455757140347277745038838145391480304288946439289988670652938164442307992695603200000000000000/2072374107058772364996455265949022002801273200386473989101277914764615780098834073399133293821996117411589883156796371074004412984162432829701405980777102013220841619536874248754407890091587282621115868336668102336034204494341240299572403747093030802161288330321259221 A46^28 * U3^3 - 7685682775116980037756417525104129020857901100253508944433808002299072796987780826355035229956095427761674994214377901743588098560205258976689072899389795364550488078379086807213438803727723516868672038614031636269842625366221371250239578203300336002844575259786307614801920000000000000/2509645043648173334010707327064265645392341845668020000801647554779949709699688062886350418818437298185435348502880405370619344123820706156768402642721070538010439201259154715241587954900912199254171316555705071928937421642647242002782180937729660301417320168019044916631 A46^27 * U3^3 - 1034113844705967884541016548705263783711258150109052467551058076026319678448759166131211515280654219796468782344958028728719356943011812509405877602376788836215237969187146349036450163464263286874467724055879617971867571915156566751269616939474200904886354631269920338765414400000000000/119506906840389206381462253669726935494873421222286666704840359751426176652366098232683353277068442770735016595375257398600921148753366959846114411558146216095735200059959748344837521661948199964484348407414527234711305792507011523942008616082364776257967627048525948411 A46^26 * U3^3 - 48658714056579159584588250657320626399886844717677219117243540154602424522685502681521979204132079896072758913281262740708279626890869807641530459145331943833017069929236863886983924086820489878464574416932681640220499275442882030223770711661291180467191894819368336275978321920000000000/3226686484690508572299480849082627258361582373001740001030689713288506769613884652282450538480847954809845448075131949762224871016340907915845089112069947834584850401618913205310613084872601399041077407000192235337205256397689311146434232634223848958965125930310200607097 A46^25 * U3^3 - 8255947206923045970115261594812428132415296386179673138598668698030130733176457946142061749654776338102806089384084736737962150165972226111226766639416349566788039796025933969548991539844303719591225974525365272074129459969218772790071341578178550260218707253120429402938146816000000000/460955212098644081757068692726089608337368910428820000147241387612643824230554950326064362640121136401406492582161707108889267288048701130835012730295706833512121485945559029330087583553228771291582486714313176476743608056812758735204890376317692708423589418615742943871 A46^24 * U3^3 - 19945713493372992010989573088745323542756396319972931197979116120090053547915047057950693601445545496940530403318628583782260656315550176840007325651552659987878417938292973350492923084265613272190430226035072662253316611695490659970858884921554483178528771682266082834119655424000000000/1382865636295932245271206078178268825012106731286460000441724162837931472691664850978193087920363409204219477746485121326667801864146103392505038190887120500536364457836677087990262750659686313874747460142939529430230824170438276205614671128953078125270768255847228831613 A46^23 * U3^3 - 435093775488421369600147732183313564461463032259212791823425518543075036047179553289353390602878450300140400400876508808029170501403708143242207930225443742617112912856658164191471704385406656699565008229508861688289615831997614509046870265598882388184233731177202498351136768000000000/65850744585520583108152670389441372619624130061260000021034483944663403461507850046580623234303019485915213226023101015555609612578385875833573247185100976216017355135079861332869654793318395898797498102044739496677658293830394105029270053759670386917655631230820420553 A46^22 * U3^3 + 1666712214493918375843073715679404854923553599857383781647492939009113706816140218151303957915155518916011997458056804212971047568027330977305056462875462122879154305439206460319912215754500114817599379012537086490342649170430864147520080485377840240561213239361225941393442471936000000/1777970103809055743920122100514917060729851511654020000567931066505911893460711951257676827326181526119710757102623727420001459539616418647506477673997726357832468588647156255987480679419596689267532448755207966410296773933420640835790291451511100446776702043232151354931 A46^21 * U3^3 + 1284088025543201778701542120995051734041815978306710257005722604826526562109618762971947126682732875656141515493855498879095407124008034223158582017519436364169634168807052804122297828912887489492802203539147042679430553728949689548527311377444129568517124121118716963986204576972800000/253995729115579391988588871502131008675693073093431428652561580929415984780101707322525261046597360874244393871803389631428779934230916949643782524856818051118924084092450893712497239917085241323933206965029709487185253419060091547970041635930157206682386006176021622133 A46^20 * U3^3 + 4254014381230883330619305014989375799554837810367142599761760649672291739447040860678177727995158715416431102910496713847267271580162773653334863631889973825919344031375754538234961810569091573254261817527160589941054559827804400510444074230128005539082809168028853708352942800568320000/761987187346738175965766614506393026027079219280294285957684742788247954340305121967575783139792082622733181615410168894286339802692750848931347574570454153356772252277352681137491719751255723971799620895089128461555760257180274643910124907790471620047158018528064866399 A46^19 * U3^3 + 745516437593004300883570660646246938247823802410590380979420190673989967797085587628924839737460064182360717893802831288295892815613347860630889607237862285660785165032805451166314560759396503899171227181213064059364949918934022222627542591929187087049764507673930916328360804352000/182337206830997409898484473440151477871997898846684442679512979848826981177388160317677861483558765882443929556212052858168542666353852799457130312172877280056657633950072429082912591469551501309356214619547530141554381492505449783180216536920428719800707829272090181 A46^18 * U3^3 + 100659132205313930529625050503119312070810564089441017863641173372860790994172383194397174444036783482169409680952402366953488358200797270823652786371161310119627780987982282462009952616082069316251196025335382901954198189565730812891991210118588783206461023328312986396596201321267200/46652276776330908732597955990187328124106890976344548119858249558464160469814599304137292845293392813636725405025112381282837130777107194832531484157374744083067688914939960069642350188852391263579568626229946640503413893296751508810823973946355405309009674603759073453 A46^17 * U3^3 + 31840686398285739366370901635863389542030022459808048577847041429885472147377770155737274410841071887893024815380774859603070679264257251115288897069582531630147721152091634280145756325435744966628395355333013175929902375331398691019183890365382567317614167783255315159428074691624960/46652276776330908732597955990187328124106890976344548119858249558464160469814599304137292845293392813636725405025112381282837130777107194832531484157374744083067688914939960069642350188852391263579568626229946640503413893296751508810823973946355405309009674603759073453 A46^16 * U3^3 - 13828528445690452987305064022092959448876463072880660857470397879545100109724829810338301593203092974158319894346856522064022294423111854351244636838712011841678369295025322372766599272518628248765532325453911764768121252460833528916104395772737785984090513826255228303325154466127872/139956830328992726197793867970561984372320672929033644359574748675392481409443797912411878535880178440910176215075337143848511392331321584497594452472124232249203066744819880208927050566557173790738705878689839921510241679890254526432471921839066215927029023811277220359 A46^15 * U3^3 - 33610752624740506302912013993814981775024007915215935211163351291344044163786135068634072771353605827815789041344588941769903151215762730402577426802629600007206325972644549999333779030662823436337121030730985687375264611402234685156485004573481758060166931327023163395774356304113664/99969164520709090141281334264687131694514766377881174542553391910994629578174141366008484668485841743507268725053812245606079565950943988926853180337231594463716476246299914434947893261826552707670504199064171372507315485635896090308908515599333011376449302722340871685 A46^14 * U3^3 - 440458073572699732774489360478761084951279455207275623193025208264809731530938512938804891081421616585621742589211241713795773058743821672163780025900276255331592774249357759549304463610560721287707008918417645237050696497113058739332361880620366592325582276896858182823540813585536384/1499537467810636352119220013970306975417721495668217618138300878664919443672612120490127270027287626152609030875807183684091193489264159833902797705058473916955747143694498716524218398927398290615057562985962570587609732284538441354633627733989995170646739540835113075275 A46^13 * U3^3 - 6996214565149446678253694413083490264717525678004855498090489246100920822500988095095030219926214938120572903557109272761916802518646083631510656210142715036721759509042764836946925860045014447394355560737664073350497528956878636493202886375323607681733788379035427399732074066732736/39670303381233765929079894549479020513696335864238561326410076155156599038957992605558922487494381644248916160735639780002412526171009519415417928705250632723697014383452346997995195738820060598281946110739750544645760113347577813614646236348941671181130675683468599875 A46^12 * U3^3 - 52720968043649456846417369507000756940194406072631641273516890434262149856954069120692268860993592166109579882175849063584157212108249084107098488501914404760103187541211164434424785557474548152913921719930232076831591869022033755032242197725738904601218545055852510881677688297536184/642658914775987008051094291701560132321880641000664693487843233713536904431119480210054544297408982636832441803917364436039082923970354214529770445025060250123891633011928021367522170968884981692167526993983958823261313836230760580557269028852855073134316946072191317975 A46^11 * U3^3 - 560521169089131499065785274068646758491670755018612288505863123339558028653018546907577396130067320298156818038178669090843281588218301520813686567954392296875641272535840128326520911631312236737399924421960962557597703529589857661762970259131745451459708625790997896125768972935928/18361683279313914515745551191473146637768018314304705528224092391815340126603413720287272694211685218195212622969067555315402369256295834700850584143573150003539760943197943467643490599110999476919072199828113109236037538178021730873064829395795859232409055602062609085 A46^10 * U3^3 - 4197422272012614585634130742038816517252315110924247183388171916467791237166762578598405913589164581591069795124771062594877274429670076994003284050036156103051961891924620808585164846207763280779766288975531255051754977759088637973954664073448069462858272840556659782286260872647812/459042081982847862893638779786828665944200457857617638205602309795383503165085343007181817355292130454880315574226688882885059231407395867521264603589328750088494023579948586691087264977774986922976804995702827730900938454450543271826620734894896480810226390051565227125 A46^9 * U3^3 - 4106654994410345218350715474180779469031652386352768990088763404863224321126834681787202405252012606245929498654531112676402813452159609458415502006915204469860173111678951294367642751272844986752033113410832855341088770049302498143130605877209294548098061602991987492963051239744/1873641150950399440382199101170729248751838603500480155941233917532177563939123849008905376960376042672980879894802811766877792781254677010290875933017668367708138871754892190575866387664387701726435938757970725432248728385512421517659676468958761146164189347149245825 A46^8 * U3^3 - 10861509873129061552037235599451402972763702999367178857883272454799214845428691114656489287350714907124422743117360275388527760856063819431352503904308954737409956132586217400390831701855393788768594250812823801249588131220343764676215839452260384917296536245871426396362711599029/26230976113305592165350787416390209482525740449006722183177274845450485895147733886124675277445264597421732318527239364736289098937565478144072263062247357147913944204568490668062129427301427824170103142611590156051482197397173901247235470565422656046298650860089441550 A46^7 * U3^3 - 1124486478466758794641936904982948237084283820279761242642612077110909965390094116007619021675739939209813695144499796429672334602667319111431706473000996398421642195295148270757273990731860799515046565486145747844982383328993615581180179952020178830599171027345719008701601415523/18736411509503994403821991011707292487518386035004801559412339175321775639391238490089053769603760426729808798948028117668777927812546770102908759330176683677081388717548921905758663876643877017264359387579707254322487283855124215176596764689587611461641893471492458250 A46^6 * U3^3 - 13634406027258739162572410843253056158384774240138183339467954043156022885658076072571122964861139837559116738714581975870696472208621260986499059519385686842525264750880868543070223665506121563803996657564834448591138230910580178478122708511083518804685049985931165670484826297/2141304172514742217579656115623690570002101261143405892504267334322488644501855827438749002240429763054835291308346070590717477464291059440332429637734478134523587282005591074943847300187871659115926787151966543351141403869157053163039630250238584167044787825313423800 A46^5 * U3^3 - 275610949766603790350543874491973128402944565236452331621829945535128551051089218509229304570354572863614983692536142099515347666278429222971179578469228299012270654864962841491251938427241318189542247237765029951590277176611163743592667595081103539096197325545120410752450853/611801192147069205022758890178197305714886074612401683572647809806425327000530236411071143497265646587095797516670305883062136418368874125809265610781279467006739223430168878555384942910820474033121939186276155243183258248330586618011322928639595476298510807232406800 A46^4 * U3^3 - 57091321219446868547123718685194170669561742150029307684083906984399449382980015516422277491250022223527057750658840237853760266613003361978501494129695368914676980282464037464506358216208278225667602395223784571111874119085762583994232092883441120694085505220223346971423259/3496006812268966885844336515303984604085063283499438191843701770322430440003029922348977962841517980497690271523830319331783636676393566433195803490178739811467081276743822163173628245204688423046411081064435172818190047133317637817207559592226259864562918898470896000 A46^3 * U3^3 + 2096019020134284361588278549962801625099190206781628224639171740828930915568065430755481920106589988497979688771818295815492190569468006618308754762164717538084498525703860854191800473065932573287633087040724218118612995977781646506334852358874110328385808128162955638079/14269415560281497493242189858383610628918625646936482415688578654377267102053183356526440664659257063255878659280940078905239333373034965033452259143586693108028903170382947604790319368182401726720045228834429276808938967891092399253908406498882693324746607748860800 A46^2 * U3^3 + 144724249725887284436232581781817786550817001839619049910175696311756292310832604781793691600419996522748911371809754829004775699207861014225518336712102081581627568566107942347420832194840104563187671858359656942129120425684588448408665047033556866808539561866776501/4314260184514436127964380909564205783497694829005739203533961800265235707347901241580178583419276511944332172118198058625922700944228258513515422265634676676652729605557958459498206914038519040580512540841853144915778977442507150190146154648188267067194741571840 A46 * U3^3 + 34523752399540034716636145000935730218516677827634880256328110824710605643763228906652973946423825292328221117422519494495751855171799684110699308767573648503790821554402991388888863972166596620407299382152069987750344858727174998460595722071373991687451348757265/52827675728748197485278133586500478981604426477621296369803613880798804579770219284655247960236038921767332719814670105623543276868101124655290884885322571550849750272138266850998452008634927027516480091941058917336069111540903879879340669161488984496262141696 U3^3 ) ) """; ps6=""" ( ( U3 * U4^3 + 41822330490195068041017320363097809729090890052699731534033293673080362045613806875773900749189755394694179768458994485940692483615892634922652342251410719603257617491056399521754985563535628528166060660260046980535041591378337983957604595139759378622893247460686601951641600000000000000000/356450080441422916364430404818046149990025416021600380113859661592463002937141992302140913567282244477259049192463045797202514832886802745887131987012951584257301943346187289394823441396232477000190857226368174895516164344503923290523438801001095804385269931852430936453389 A46^33 + 454125157206527413523601969987620494847328162420135984302287459170369832878272220272886380031914311891233003000504439954565744301327926677967038692247319542412616194634678505272858478303439697166808691979442683766268105374119197842122316902319990742401536311538368167952547840000000000000000/831716854363320138183670944575441016643392637383734220265672543715747006853331315371662131656991903780271114782413773526805867943402539740403307969696887029933704534474437008587921363257875779667112000194859074756204383470509154344554690535669223543565629840989005518391241 A46^32 - 14740085336461820800966266074682241729581054272188710537515241908189807762813569534360041532382661570106035157724159025403425541339461211407295309969242948500584368294316900034869383665586431029071989963112162284745485647807851469068632801796651905968443260670347124770482847744000000000000000/52398161824889168705571269508252784048533736155175255876737370254092061431759872868414714294390489938157080231292067732188769680434360003645408402090903882885823385671889531541039045885246174119028056012276121709640876158642076723706945503747161083244634679982307347658648183 A46^31 - 9149331424499552779979794487803049109145854134654822152707377782056977306922942650458296507280354954701791394660220920473087273186333364153948147270760935725093184452955662120588287066833595316280317830971486425063174196982668087569045226676196390232025049390929919119574244207001600000000000000/1100361398322672542816996659673308465019208459258680373411484775335933290066957330236709000182200288701298684857133422375964163289121560076553576443908981540602291099109680162361819963590169656499589176257798555902458399331483611197845855578690382748137328279628454300831611843 A46^30 - 79973012198225026539332842880094613358418060119022835029835910425124670099764459027277518388837201641732137026202824480404214035628958792843162201239309141530235969873589550508448718782972837671619969580166184326037129487506541556889887126810734028550977167372000415444560765391994880000000000000/2567509929419569266572992205904386418378153071603587537960131142450511010156233770552321000425134006969696931333311318877249714341283640178625011702454290261405345897922587045510913248377062531832374744601529963772402931773461759461640329683610893078987099319133060035273760967 A46^29 - 8299397433438618012971050717608586981007096658561248516910138778913485394953866129982359922925735316581762478702897711207576975054100165652131628929716109958379944654693325699234875749400905318226733372296404518054930456353699133199857710268046545544970469824348289708598182344299520000000000000/122262377591408060312999628852589829446578717695408930379053863926214810007439703359634333353577809855699853873014824708440462587680173341839286271545442393400254566567742240262424440398907739611065464028644283989162044370164845688649539508743375860904147586625383811203512427 A46^28 - 1009095872071060606887382314527808282304198676274688330469220230071145794033535363745528418711512251257265245188164841956986767644719780200297491853553606313847573922892151658199998953665772946824914444133907829818800088800411900616394966638527678678559806341695040379358176887422246912000000000000/9903252584904052885352969937059776185172876133328123360703362978023399610602615972130381001639802598311688163714200801383677469602094040688982187995180833865420619891987121461256379672311526908496302586320187003122125593983352500780612700208213444733235954516656088707484506587 A46^27 - 17315208871659672382889994991298216489948823684300447200387695359236475124436480420376202114747618244141605164691824173316146543744310447948881287127831116503491247576077521276794352818587011612296482326427954766142441690371899121755561881707409211508579604162112995865737896762901299200000000000/157194485474667506116713808524758352145601208465525767630212110762276184295279618605244142883171469814471240693876203196566309041303080010936225206272711648657470157015668594623117137655738522357084168036828365128922628475926230171120836511241483249733904039946922042975944549 A46^26 - 355912103283291653350342202441876054749468980229513306853575234001898259812970951366303068842390266228175806871138615053043787098181575854719444584002263604429051532090218493757283996626942336013246526185261992049786421446412979193448620795644178642889464382438869086312841888992127016960000000000/4244251107816022665151272830168475507931232628569195726015726990581456975972549702341591857845629684990723498734657486307290344115183160295278080569363214513751694239423052054824162716704940103641272536994365858480910968850008214620262585803520047742815409078566895160350502823 A46^25 - 22500215142403543279349306218081169611665243245444094081053540155023353065879988896297915009225132894908494486994564419892386896801934687727963175381359248310045430450423575265267918061375611015895078661355902220676428093155477822434762767854058633074606376473106078760663121039247968256000000000/606321586830860380735896118595496501133033232652742246573675284368779567996078528905941693977947097855817642676379640901041477730740451470754011509909030644821670605631864579260594673814991443377324648142052265497272995550001173517180369400502863963259344154080985022907214689 A46^24 + 32673087924159313144791905275717518339829777902894646782455060134934567490559434999059780860378598405024654197705939033389093954547300991047620772736355387222770403567834688718752714161637753797576326177011424906610337687450739278051783922665936466482962665445318545262436466728042148326400000000/5456894281477743426623065067359468510197299093874680219163077559319016111964706760153475245801523880702358784087416768109373299576664063236786103589181275803395035450686781213345352064334922990395921833278470389475456959950010561654623324604525775669334097386728865206164932201 A46^23 + 1104476613898878470428452483404305645696373154435799116198630014006790595031027352442953347316486180518984682424499974769238555293892978509198039261572798669589819427036166245573413843280166968329333248039556067221899335330112207191529323373567807146257408223366473003726728025624000104960000000/37121729805971043718524252158907949048961218325678096729000527614415075591596644626894389427221250889131692408757937198022947616167782743107388459790348814989081873814195790566975184111121925104734162131146057071261611972449051439827369555132828405913837397188631736096360083 A46^22 + 78113480257566589843454213154883751458293793164562951385751797138539577840045698708433870322843582703179960018071553825115618374965480805851557122788075034745129320776152687748718547900383557327895464091642273092813119121008016975113831330943443029648706513051422069517463619351777438820096000000/2338668977776175754267027886011200790084556754517720093927033239708149762270588611494346533914938806015296621751750043475445699818570312815765472966791975344312158050294334805719436599000681281598252214262201595489481554264290240709124281973368189572571756022883799374070685229 A46^21 + 8395276376303141598390829139882556608548753795333152128887172440477769331506706983960503595713255764449491015079245760485357931286228197098907656335096624996307325605986758954601108746818602104646481755620539840786476094323961082674609265938980034638463288197875497334999695180183262425971200000/334095568253739393466718269430171541440650964931102870561004748529735680324369801642049504844991258002185231678821434782206528545510044687966496138113139334901736864327762115102776657000097325942607459180314513641354507752041462958446325996195455653224536574697685624867240747 A46^20 + 1980830687381076339084629170133609739180380880215294749410365337574729337777957070632004952411058046327505217385303454420099905980785666056543363976205429431407119959330949327855470437048628780012191977441692141470352845169941328389007388270439665640289698273307474532663228874959149967256320000/143183814965888311485736401184359232045993270684758373097573463655601005853301343560878359219281967715222242148066329192374226519504304866271355487762774000672172941854755192186904281571470282546831768220134791560580503322303484125048425426940909565667658532013293839228817463 A46^19 + 702091132949191502045640382611695646026178320839883517672739200609357661071215369230485179018215789550721046578374598929240937327355327668355522069483080934376708869486654867322142997232774287348753757914178992350603911472387418363244015679942880338944525806103128925167085917623892484556464000/143183814965888311485736401184359232045993270684758373097573463655601005853301343560878359219281967715222242148066329192374226519504304866271355487762774000672172941854755192186904281571470282546831768220134791560580503322303484125048425426940909565667658532013293839228817463 A46^18 - 26433410235178253131164568590264182053663342966938907183003177081908265950075927144928504095882195140380650366718219667766773538150084001651408286437201753129205947322295717753544109541401358911647830600006212366636193412718513659512611675534262638709507230297656780911489899859088163252104000/429551444897664934457209203553077696137979812054275119292720390966803017559904030682635077657845903145666726444198987577122679558512914598814066463288322002016518825564265576560712844714410847640495304660404374681741509966910452375145276280822728697002975596039881517686452389 A46^17 - 36588941424973786825226031379192323188694220080503719244669152016528167903934256688892636045811947246452459444223170684913020286311345813411596839167079667051478933505562383477365997492491009488269523510100891279267477520527793501298375191462023458969167972627835965786511419141962714020174080/20454830709412615926533771597765604577999038669251196156796209093657286550471620508696908459897423959317463164009475598910603788500614980895907926823253428667453277407822170312414897367352897506690252602876398794368643331757640589292632203848701366523951218859041977032688209 A46^16 - 321333621660414138288318264757386991534769910679354013783840583853994409935788586791159864436843010390611984538928952685258511624721739694382405481016998808554437914129696961450517494564423154689101019268062664959334760483746323046684415109519127596246390980123789139075174901071183005966554488/184093476384713543338803944379890441201991348023260765411165881842915578954244584578272176139076815633857168476085280390195434096505534828063171341409280858007079496670399532811734076306176077560212273425887589149317789985818765303633689834638312298715560969731377793294193881 A46^15 - 297844721921145322765306527355860406934008939169980445647884079222865480952075045050385650004580591246687712266033786754423786883489838690861527534993455211693991394970866545156968100893505892393812058175717385845665650930957741425381878068688495541752226534683879631214290521382589457098661971/262990680549590776198291349114129201717130497176086807730236974061307969934635120826103108770109736619795954965836114843136334423579335468661673344870401225724399280957713618302477251865965825086017533465553698784739699979741093290905271192340446141022229956759111133277419830 A46^14 - 451879932351907431338340841430894291445765587061006243890312609075513994394090487211287876791443241336702645913369115324679497644368945637845627225355027484550118544624707338874219923703785680226085214156696766542732612750915702425388991747367656078911167375594394305408128145699286227195203039/788972041648772328594874047342387605151391491528260423190710922183923909803905362478309326310329209859387864897508344529409003270738006405985020034611203677173197842873140854907431755597897475258052600396661096354219099939223279872715813577021338423066689870277333399832259490 A46^13 - 5320311585057193929116580887725053048673711797951597468291152199479233897939064740829295546757123058099231381384546836150171434463598328526972269844562130162789158735497528507679194843684312884543346736256634246332090848994957191293298207019966632338305847326064328022091724095239631394444614337/22542058332822066531282115638353931575754042615093154948306026348112111708683010356523123608866548853125367568500238415125971522021085897313857715274605819347805652653518310140212335874225642150230074297047459895834831426834950853506166102200609669230476853436495239995207414000 A46^12 - 362392746608515719372641040156549702648285106850030418671446645004524075469397447508371929006539117538692298420067983710297061362768282375139330712098123029408339164065434243491074476680334774441684136089288247838831323010949142346356824849579571331534045674787558012078606230561135787887949871/4508411666564413306256423127670786315150808523018630989661205269622422341736602071304624721773309770625073513700047683025194304404217179462771543054921163869561130530703662028042467174845128430046014859409491979166966285366990170701233220440121933846095370687299047999041482800 A46^11 - 155718157831390278974558432491864519634779570729825416271843627583866505195625371450767361228547485547131717071612734991086436233519540316144548267366374648257565699340887077601451758110896914837331994622765481537988675137980472319274860288480400497182597917963360319541332897673699613001900139/6869960634764820276200263813593579146896470130314104365198027077519881663598631727702285290321233936190588211352453612228867511473092844895651875131308440182188389380119865947493283314049719512451070261957321111111567672940175498211403002575423899194050088666360454093777497600 A46^10 - 45201548094888346900126189229758597421851803521277808642167463508827660396693637290758710792553278488070609212455021345000119146078696472196451660991329985879243486243508404638669646114695294849026046972039432309027960523963229014364806077507073721111320914116188285819616980932331878040743049/8587450793456025345250329766991973933620587662892630456497533846899852079498289659627856612901542420238235264190567015286084389341366056119564843914135550227735486725149832434366604142562149390563837827446651388889459591175219372764253753219279873992562610832950567617221872000 A46^9 - 1953129387759091287411246093721824623775778716719168388328766612507051710224152064386589191585418322171515414473927996208486195431232117229550712885298021138550712056198139675205800600486010459477444720900066414100009247618626937808864666954121404483671145377185645585361795757512848953771727/1962845895647091507485789661026736899113277180089744104342293450719966189599609065057795797234638267483025203243558174922533574706597955684471964323230982909196682680034247413569509518299919860700305789130663174603305049411478713774686572164406828341157168190388701169650713600 A46^8 - 376134847222603342228005080394985602907218977535587514699426664550583601459354985670099124083557791013853499761803409404040812308856476452671356746803998334683915044848315929579536086205259194433291389544619656281935845620125586677702558497845124290906144446668089290971220577745466063821/2503629968937616718731874567636144003971016811338959316763129401428528303060725848288004843411528402401817861280048692503231600391068821026112199391876253710710054438819193129552945814158061046811614526952376498218501338535049379814651240005620954516782102283659057614350400 A46^7 - 574485486982304350778070191971122027743291593240873280940414570314432804154563998121312928497476285147145839708807365153231143249845428378451535410210139619924467103332329351315189638465205694465434576925840400070753365257384354164688588108696337944766401214964460997424273537531595188679/32700473063674993877314280067084329847784709372590489035273526875801185999160500875598430607824044439533947575902676800042208658169062152177791992057159232139886425323352726590079292266554266733865985658153488956323282789029216389415852930685661446749807050235546874962944000 A46^6 - 11511257781723192579987461460171218665430662046039138877189380600683547596344289008862892439158437560118751792069494864896646099764172740280826359491156661557991789303166781418829521172671095190437798106362980957418171493748387515586895216124868996215985307716367044170468765302175191523/7630110381524165238039998682319676964483098853604447441563822937686943399804116870972967141825610369224587767710624586676515353572781168841484798146670487499306832575448969537685168195529328904568729986902480756475432650773483824197032350493321004241621645054960937491353600 A46^5 - 1671303995297463181793089014042140921533205745175671854516004230292597522756847916940561516331382516496857206868368002684300205049090986725992113164539129267661714078303721803021367606163396471932149786832020402699788845934151506635865863054320744139050271729184411228168473604636972839/19620283838204996326388568040250597908670825623554293421164116125480711599496300525359058364694426663720368545541606080025325194901437291306675195234295539283931855194011635954047575359932560040319591394892093373793969673417529833649511758411396868049884230141328124977766400 A46^4 - 60908092525844337290393747162251644298087521040833441461527761929200066595412859133091070618059209993364079718454967764919058787501486800829921561765930651085782549124215742770618379064496572773262751298821893631502246026461480269869465295797601392220253848115075799372526327938111547/28028976911721423323412240057500854155244036605077562030234451607829587999280429321941511949563466662457669350773722971464750278430624701866678850334707913262759793134302337077210821942760800057599416278417276248277099533453614048070731083444852668642691757344754464253952000 A46^3 + 45086394754577700869380844548742167538951281901932651744568905863102388384166263647335650948182916349574945031051918658847888488603435323077118198631600514293001349841754886818523071957433889642885763744141389343414660044929152119754129057333007696856923108253108183335928470691323/732185519326600445999340148440838639157395241928556722422450980775956584470998970042553781539617088325424832020211538846426129722269379967129569967927063856659847657385856968547548001770078042320964343599471706077442600057563795541439505853253294201278478559209912535613440 A46^2 + 3731272476720292507686304261693030416127583479257486748224902831742134747688100663209642453477726001478166688384847374161566164080254468319618379882752444074260128081142704326346717896603236118487929226426342553598574093896870131278947045099476660390852113706889521422745255/648548681376311336096354298151253046305799356866989727202426109672580591403591774768418528149462415254238265324025243450986863770434187187437615121817481448997172315569955506437383079799176270479879130881051326953517042284548430007652623523644145232141509494765016064 A46 + 9280862118536625477466695256284609672515130143361639412543372050128009110823486812077779222084224626376141852085219762625785282075028284601725310082870373135311800354168551231605316413369320027988216942534660872550537108296929260273306523538001567960935496614750288886518875/94873407104191829737523828758126159916734077347399640093612048043531789371039711051837224689292787602905711955971692756258649785846372525705159697820157286253300635877662062655982896244908071567342318574599508400057350185625370332548040926887372102530415103234196635648 ), ( U4^4 - 20/7 A46^2 ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; rg = f.isGB(); puts "is GB output: " + str(rg); puts; ri = f.toInteger(); puts "integer Output: " + str(ri); puts; rip = ri.list.get(0); puts "integer polynomial: " + str(rip); puts; startLog(); rfi = rz.squarefreeFactors(rip); #rfi = rz.factors(rip); puts "#squarefree Output: " + str(rfi.size); puts; rfi.each{ |h,i| puts "h**i = " + str(h) + "**" + str(i) }; puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/rose_modular.py000066400000000000000000000035401445075545500224230ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, GF #from edu.jas.arith import ModIntegerRing # example from rose (modified) modular computation #r = Ring( "Mod 19 (U3,U4,A46) L" ); #r = Ring( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring( "Quat(U3,U4,A46) L" ); #r = Ring( "Z(U3,U4,A46) L" ); #r = Ring( "C(U3,U4,A46) L" ); r = Ring( "Rat(A46,U3,U4) G" ); print "Ring: " + str(r); print; ps = """ ( ( U4^4 - 20/7 A46^2 ), ( A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216 ), ( A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; fi = f.toInteger(); print "Ideal: " + str(fi); print; # "1152921504606846883" #mf = ModIntegerRing( str(2**60-93), True ); #mf = ModIntegerRing( str(19), True ); mf = GF( 2**60-93); fm = fi.toModular( mf ); print "Ideal: " + str(fm); #sys.exit(); rm = fm.GB(); #print "seq Output:", rm; #print; #rg = f.GB(); #print "seq Output:", rg; #print; #rgm = rg.toInteger().toModular(mf); #print "seq Output:", rgm; #print; #e = rm == rgm; #print "e = " + str(e); sys.exit(); #for i in range(1,9): for i in range(1,3): rg = f.parGB(i); #print "par Output:", rg; #print; rg = f.parOldGB(i); #print "par-old Output:", rg; #print; #f.distClient(); # starts in background #rg = f.distGB(i); #print "dist Output:", rg; #print; #sys.exit(); java-algebra-system-2.7.200/examples/rose_part.py000066400000000000000000000052501445075545500217260ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, QQ from jas import startLog, terminate # example from rose (modified) #r = Ring( "Mod 19 (U3,U4,A46) L" ); #r = Ring( "Mod 1152921504606846883 (U3,U4,A46) L" ); # 2^60-93 #r = Ring( "Quat(U3,U4,A46) L" ); #r = Ring( "Z(U3,U4,A46) L" ); #r = Ring( "C(U3,U4,A46) L" ); r = Ring( "Rat(A46,U3,U4) L" ); print "Ring: " + str(r); print; ps = """ ( %s ( U4^4 - 20/7 A46^2 ), ( A46^2 U3^4 + 7/10 A46 U3^4 + 7/48 U3^4 - 50/27 A46^2 - 35/27 A46 - 49/216 ), ( A46^5 U4^3 + 7/5 A46^4 U4^3 + 609/1000 A46^3 U4^3 + 49/1250 A46^2 U4^3 - 27391/800000 A46 U4^3 - 1029/160000 U4^3 + 3/7 A46^5 U3 U4^2 + 3/5 A46^6 U3 U4^2 + 63/200 A46^3 U3 U4^2 + 147/2000 A46^2 U3 U4^2 + 4137/800000 A46 U3 U4^2 - 7/20 A46^4 U3^2 U4 - 77/125 A46^3 U3^2 U4 - 23863/60000 A46^2 U3^2 U4 - 1078/9375 A46 U3^2 U4 - 24353/1920000 U3^2 U4 - 3/20 A46^4 U3^3 - 21/100 A46^3 U3^3 - 91/800 A46^2 U3^3 - 5887/200000 A46 U3^3 - 343/128000 U3^3 ) ) """; pp1 = """ ( 20 A46 + 7 ), """; pp2 = """ ( 5480334637123239936000000000000000000 A46^32 + 23330567455181792870400000000000000000 A46^31 - 22260410953422455439360000000000000000 A46^30 - 379039147753503876710400000000000000000 A46^29 - 1305289515920841108357120000000000000000 A46^28 - 2661894008686715272062566400000000000000 A46^27 - 3732109213267597335472373760000000000000 A46^26 - 3719328899522099347074318336000000000000 A46^25 - 2513175000419852400394764288000000000000 A46^24 - 801907472074794268996141056000000000000 A46^23 + 559468735767998648283977220096000000000 A46^22 + 1161692745234469227508358814105600000000 A46^21 + 1115120737963786660933876454522880000000 A46^20 + 754183677763034219243933188227072000000 A46^19 + 366205139138005719200006792439398400000 A46^18 + 95407136698255889087520898673541120000 A46^17 - 35897763757636362165902256717692928000 A46^16 - 68696958358719191677546842722559590400 A46^15 - 55382563098545072682320366954843996160 A46^14 - 32223104574376823941781148035505979392 A46^13 - 14867126462105106300205537184606126080 A46^12 - 5596017809975575801376014016653721600 A46^11 - 1730893404306213749794640488178116608 A46^10 - 438698743729822786570094575456788480 A46^9 - 90199241991532353478039712103521280 A46^8 - 14778859703096558479650421488297984 A46^7 - 1874056025467134008603806670325120 A46^6 - 174876413639867324175892636604160 A46^5 - 10843113615171040141214782270464 A46^4 - 325577720150105105056746125600 A46^3 + 6040454553390756509792153750 A46^2 + 761038687880048862537750000 A46 + 13745464623924567359765625 ), """; pp = ps % pp1; f = r.ideal( pp ); print "Ideal: " + str(f); print; startLog(); rg = f.GB(); print "seq Output:", rg; print; #sys.exit(); java-algebra-system-2.7.200/examples/sd.ini000066400000000000000000000006471445075545500204720ustar00rootroot00000000000000# # $Id$ # [DEFAULT] sdhost = symbolicdata.uni-leipzig.de [sparql] #local = http://localhost:8890/sparql local = http://localhost:8890 #symbolicdata.org = http://symbolicdata.uni-leipzig.de:8890/sparql symbolicdata.org = %(sdhost)s:8890 path = /sparql [symbolicdata] sd = http://symbolicdata.org/Data/Model# ideal = http://symbolicdata.org/Data/Ideal/ [queries] list_ideals = SELECT ?ideal WHERE { ?ideal a sd:Ideal . } java-algebra-system-2.7.200/examples/sdexam.py000066400000000000000000000015561445075545500212160ustar00rootroot00000000000000# # $Id$ # import sdjas; from jas import terminate, startLog, auto_inject #startLog() auto_inject = False sd = sdjas.SymbolicData() print #sd.list_ideals() #print #exit(); bb87 = sd.get_ideal('Buchberger-87') #bb87 = sd.get_ideal('Buchberger-87.Homog') print print "bb87 = " + str(bb87) print G = bb87.GB() print "G = " + str(G) print startLog() #terminate() #exit(); cz86c = sd.get_ideal('Czapor-86c') #cz86c = sd.get_ideal('Czapor-86c.Flat') #cz86c = sd.get_ideal('Czapor-86c.Flat.Homog') print print "cz86c = " + str(cz86c) print G = cz86c.GB() print "G = " + str(G) print #startLog() terminate() exit(); ids = sd.get_ideals() for id in ids: print "id = " + str(id) if 'Curves' in id: #.find('Curves') >= 0: print "'Curves' = " + str(id) continue F = sd.get_ideal(id) print "F = " + str(F) G = F.GB(); print "G = " + str(G) java-algebra-system-2.7.200/examples/sdexam.rb000066400000000000000000000010721445075545500211620ustar00rootroot00000000000000# # $Id$ # require "examples/jas" require "examples/sdjas" startLog() sd = SymbolicData.new() puts #sd.list_ideals() #puts #exit(); bb87 = sd.get_ideal('Buchberger-87') #bb87 = sd.get_ideal('Buchberger-87.Homog') puts puts "bb87 = " + str(bb87) puts gg = bb87.GB() puts "gg = " + str(gg) puts #startLog() #terminate() #exit(); cz86c = sd.get_ideal('Czapor-86c') #cz86c = sd.get_ideal('Czapor-86c.Flat') #cz86c = sd.get_ideal('Czapor-86c.Flat.Homog') puts puts "cz86c = " + str(cz86c) puts gg = cz86c.GB() puts "gg = " + str(gg) puts #startLog() terminate() java-algebra-system-2.7.200/examples/sdjas.py000066400000000000000000000420511445075545500210340ustar00rootroot00000000000000''' Access to the database of ideals as provided by the SymbolicData Project (http://symbolicdata.org). Adapted from the Symbolicdata and Sage code ''' # # $Id$ # # adapted from the Symbolicdata and Sage code # # communicate with the SPARQL endpoint (http request) #import requests import httplib, urllib # easily handle URLs from os.path import split as pathsplit from urlparse import urlsplit # for nice output of dictionaries: json.dumps(dict, indent = 4) # mostly for debugging reasons (will be removed later) # for old jython versions it must be loaded from an # external library jyson-1.0.2.jar #import json from com.xhaus.jyson import JysonCodec as json # parse the sd.ini file from ConfigParser import SafeConfigParser # parse the xml of the resource files from xml.dom.minidom import parse, parseString # output lists nicely (there might be a better way) from textwrap import wrap as textwrap # not needed #from jas import * # Some internal helper functions that are not meant to be # called by the user def _uri_to_name(uri): """ Converts a uri to a name or key by only taking everything after the last / or (if present) #. Examples: - http://example.com/test -> test - http://example.com/model#testedBy -> testedBy """ usplit = urlsplit(uri) if usplit.fragment != '': return usplit.fragment else: return pathsplit(usplit.path)[-1] def _pprint(l): """ Formats a list l to be displayed in a tabular layout. It is possible to pass an integer width to the textwrap function. The width of the terminal window could be obtained via the Python console module. However, since it is not included in Jas, we decided not to use it. The default width that textwrap uses is set to 70. There might be a better way to do this. """ col = max([len(x) for x in l]) + 3 padded = ''.join([x.ljust(col) for x in l]) print '\n'.join(textwrap(padded)) def get_value_for_URI(sd, URI, predicate): """ A quick convienience function to retrieve a single value of a given triple (object, predicate, ...) The parameter sd is a SymbolicData object that contains information about the SPARQL endpoint. """ result = None query = '''SELECT * WHERE { <%s> <%s> ?x }''' % (URI, predicate) try: result = SPARQL(sd, query).json['results']['bindings'][0]['x']['value'] except: pass return result # Class definitions start here class SymbolicData: """ Access to the database of ideals as provided by the SymbolicData Project (http://symbolicdata.org). """ def __init__(self, sparql = 'symbolicdata.org'): """ The constructor parses the sd.ini file and sets up some variables. An optional parameter can be passed to select the SPARQL endpoint that should be used. The keywords for different SPARQL endpoints are defined in the sd.ini file. The default SPARQL endpoint is the one from symbolicdata.org """ self._sparql = sparql self._ideals = None self._parser = SafeConfigParser() self._parser.read(['sd.ini','examples/sd.ini']) self.sd = self._parser.get('symbolicdata', 'sd') try: self.url = self._parser.get('sparql', self._sparql) except: raise ValueError("The SPARQL endpoint referenced by '%s' was not found in the sd.ini file." % self._sparql) self.sdhost = self._parser.get('DEFAULT', 'sdhost') self.sqpath = self._parser.get('sparql', 'path') #print "SymbolicData() initialized" #print "url = " + str(self.url) #print "sdhost = " + str(self.sdhost) def get_ideals(self, force_reload = False): """ Returns a Python list of ideals. """ if self._ideals == None or force_reload == True: self.list_ideals(False, force_reload) return self._ideals def list_ideals(self, output = True, force_reload = False): """ Lists all the available ideals. """ if self._ideals == None or force_reload == True: r = SPARQL(self, self._parser.get('queries', 'list_ideals')) self._ideals = [_uri_to_name(x['ideal']['value']) for x in r.json['results']['bindings']] if output: _pprint(self._ideals) def get_ideal(self, uri): """ Returns an ideal as a Jas object that is ready to be used by Jas. """ return SD_Ideal(self, uri).get_ideal(); def get_sd_ideal(self, uri): """ Returns an internal object that represents the SymbolicData database object. (See below for details) """ return SD_Ideal(self, uri) class SPARQL: """ This is a 'wrapper' class for SPARQL queries. A class might be a slight overkill. It was made with the idea, that one can store the query and the result together, to re-evaluate both without having to access the server. However, in the end this feature was not really needed. """ def __init__(self, sd, query, output = 'json'): """ Execute the query and store the results. """ self._sd = sd; self._query = query; self._data = { 'output' : output, 'query' : query } #self.response = requests.get(self._sd.url, params = self._data) #print "url = " + str(self._sd.url) conn = httplib.HTTPConnection(self._sd.url) #print "conn = " + str(conn) #print "query = " + str(query) _path = self._sd.sqpath + "?" + urllib.urlencode(self._data) #print "path = " + str(_path) conn.request("GET", _path ); response = conn.getresponse(); if response.status != 200: print response.status, response.reason, "\n" raise IOError, "HTTP GET %s not successful" % _path head = response.msg #print "head = " + str(head) self.text = response.read() #print "body = " + str(self.text) self.json = json.loads(self.text) #print "json = " + str(self.json) conn.close() class SD_Ideal: """ This class represents a SymbolicData database object. The constructor takes a complete URI or a name SUBJ (the latter of which will be prefixed with the 'ideal' value from the sd.ini) Any triple of the form (SUBJ, PRED, OBJ) will yield a field PRED* for the SD_Ideal object with the value OBJ, where PRED* is the ending piece of PRED URI as defined by the function _uri_to_name() A SPARQL endpoint is needed. As a future improvement, it could be nice to directly parse an RDF in a convienient serialization. """ def __init__(self, sd, name): """ sd is a SymbolicData object, the name can be a complete URI or shortened name as defined by _uri_to_name(). The latter will be prefixed with the 'ideal' value from the sd.ini. Namespaces like "sd:Wu-90" are not (yet) supported. Appart from retrieving the information from the SPARQL endpoint, the resource data (XML files) is needed as well. While the SPARQL endpoint can be substituted by another SPARQL endpoint, the links to the resource files are 'hard-coded' into the RDF data. The possibility to use a (possibly 'hand-filled') cache will be included in the next update. """ self._sd = sd # quick test, if the given name already is an uri if name[:7] == 'http://': self.uri = name else: self.uri = "%s%s" % (self._sd._parser.get("symbolicdata", "ideal"), name) self.hasXMLResource = False self.hasLengthsList = '' self.hasDegreeList = '' self.hasParameters = '' # we set up the query to get all predicate values # of the URI/polynomial system/ideal query = ''' PREFIX sd: <%s> SELECT ?p ?o WHERE { <%s> ?p ?o }''' % (self._sd.sd, self.uri) self._request = SPARQL(self._sd, query) if len(self._request.json['results']['bindings']) == 0: raise ValueError("No data found for <%s>.\nMaybe the name was misspelled or the SPARQL endpoint is unavailable." % self.uri) # append the keys to the self.__dict__. for t in self._request.json['results']['bindings']: uri = t['p']['value'] obj = t['o']['value'] self.__dict__[_uri_to_name(uri)] = obj # Next we need a resource file with the actual expressions that are # used to generate the ideal. # # There are four cases that need to be dealt with # (1) the ideal is constructed direclty # from an IntPS with related XML resource # (2) the ideal is a flat variant of another # ideal # (3) the ideal is obtained by homogenizing # another ideal # (4) the ideal is obtained by parameterizing another # ideal # Please note: While it might seem that only one of (2) and (4) # should be included, both are needed to map the actual history # of how these ideals were obtained. # case 1 if 'relatedPolynomialSystem' in self.__dict__.keys(): self.__addXMLResource(get_value_for_URI(self._sd, self.relatedPolynomialSystem, self._sd.sd+'relatedXMLResource')) self.hasXMLResource = True #print "relatedPolynomialSystem " + str(name) # case 2 if 'flatten' in self.__dict__.keys(): parent_name = self.flatten parent = SD_Ideal(self._sd, parent_name) self.variablesCSV = self.hasVariables self.variables = map(lambda x: str(x).strip(), self.variablesCSV.rsplit(",")) self.basis = parent.basis #print "flatten " + str(parent_name) + ", name = " + str(name) # case 3 if 'homogenize' in self.__dict__.keys(): parent_name = self.homogenize if 'homogenizedWith' in self.__dict__.keys(): hv = self.homogenizedWith parent = SD_Ideal(self._sd, parent_name) self.variablesCSV = parent.variablesCSV + "," + hv self.variables = parent.variables self.variables.append(hv) self.basis = parent.jas_homogenize(hv) #print "homogenize " + str(parent_name) + ", name = " + str(name) # case 4 if 'parameterize' in self.__dict__.keys(): parent_name = self.parameterize parent = SD_Ideal(self._sd, parent_name) self.variablesCSV = self.hasVariables self.variables = map(lambda x: str(x).strip(), self.variablesCSV.rsplit(",")) self.basis = parent.basis #print "parameterize " + str(parent_name) + ", name = " + str(name) # now we got the variables, the parameters and # the strings/expressions for the polynomials self.__constructJasObject() def get_ideal(self): """ Return the ideal as a Jas objects. """ #return ideal(self.sageBasis) #print "jasRing = " + str(self.jasRing) return self.jasRing.ideal(list=self.jasBasis) def __addXMLResource(self, link): #xml = requests.get(link).text #print "link = " + str(link) #url = link[0:23] path = link[23:] # hack for lost domain #print "url = " + str(url) #url = self._sd.url[:-5] url = self._sd.sdhost #print "url = " + str(url) conn = httplib.HTTPConnection(url) #print "conn = " + str(conn) #print "path = " + str(path) conn.request("GET", path ); xml = conn.getresponse().read(); print _uri_to_name(link) + " = " + str(xml) xmlTree = parseString(xml) # Code snipped borrowed from Albert Heinle if (xmlTree.getElementsByTagName("vars") == []): # Check, if vars are there raise IOERROR("The given XMLString does not contain variables for the IntPS System") if (xmlTree.getElementsByTagName("basis") == []): # Check, if we have a basis raise IOERROR("The given XMLString does not contain a basis for the IntPS System") # -------------------- Input Check finished -------------------- # From here, we can assume that the input is given correct self.variablesCSV = (xmlTree.getElementsByTagName("vars")[0]).firstChild.data self.variables = map(lambda x: str(x).strip(), self.variablesCSV.rsplit(",")) polynomials = xmlTree.getElementsByTagName("basis")[0] self.basis = map(lambda poly: str(poly.firstChild.data).strip(),polynomials.getElementsByTagName("poly")) def __constructJasObject(self): #from types import StringType from jas import PolyRing, ZZ # set up the polynomial ring (Jas syntax) if 'hasParameters' in self.__dict__ and self.hasParameters != '': #K = 'K.<%s> = PolynomialRing(ZZ)' % self.hasParameters #R = K + '; R.<%s> = PolynomialRing(K)' % self.hasVariables K = PolyRing(ZZ(), str(self.hasParameters) ) R = PolyRing(K, str(self.hasVariables)) gens = '%s,%s' % (self.hasParameters, self.hasVariables) else: #R = 'R.<%s> = PolynomialRing(ZZ)' % (self.hasVariables) R = PolyRing(ZZ(), str(self.hasVariables) ) gens = str(self.hasVariables) # translate Jas syntax to pure Python and execute #exec(preparse(R)) Rg = "(one," + gens + ") = R.gens();" #print str(R) exec(str(Rg)) # safe here since R did evaluate #print "R = " + str(R) self.jasRing = R; # avoid XSS: check if polynomials are clean from edu.jas.poly import GenPolynomialTokenizer vs = GenPolynomialTokenizer.expressionVariables(str(gens)) vs = sorted(vs) #print "vs = " + str(vs) vsb = set() [ vsb.update(GenPolynomialTokenizer.expressionVariables(str(s))) for s in self.basis] vsb = sorted(list(vsb)) #print "vsb = " + str(vsb) if vs != vsb: raise ValueError("invalid variables: expected " + str(vs) + ", got " + str(vsb)) # construct polynomials in the constructed ring from # the polynomial expressions self.jasBasis = [] for ps in self.basis: #print "ps = " + str(ps) ps = str(ps) ps = ps.replace('^', '**') #exec(preparse("symbdata_ideal = %s" % ps)) #exec("symbdata_poly = %s" % ps) pol = eval(ps) self.jasBasis.append(pol) #print "jasBasis = " + str([ str(p) for p in self.jasBasis]) # the following functions will all use Jas to # calculate metadata def jas_hasLengthsList(self): """ This is the implementation of the predicate "sd:hasLengthsList". The lengths lists is the sorted list of the number of monomials of the generator of the ideal. Along with the output, there will also be generated a field FROM_JAS_hasLengthsList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well. """ try: LL = sorted(map(lambda x : len(x.monomials()), self.jasBasis)) self.FROM_JAS_hasLengthsList = ",".join(map(lambda x: str(x), LL)) except: self.FROM_JAS_hasLengthsList = '' return self.FROM_JAS_hasLengthsList def jas_hasDegreeList(self): """ This is the implementation of the predicate "sd:hasDegreeList". The degree list is the sorted list of the degree of the generator of the ideal. Along with the output, there will also be generated a field FROM_JAS_hasDegreeList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well. """ try: LL = sorted(map(lambda x : x.degree(), self.jasBasis)) self.FROM_JAS_hasDegreeList = ",".join(map(lambda x: str(x), LL)) except: self.FROM_JAS_hasDegreeList = '' return self.FROM_JAS_hasDegreeList def jas_hasVariables(self): """ This is the implementation of the predicate "sd:hasVariables". This is actually not needed. """ #K = [] #DL = map(lambda m : K.extend(map(lambda l : str(l), m.variables())), self.sageBasis) K = self.jasRing.ring.vars return ",".join(sorted(list(set(K)))) def jas_homogenize(self, hv): """ Homogenize a basis, which here means actually nothing more than homogenizing every element of the basis. """ homBasis = map(lambda x : x.homogenize(hv), self.jasBasis) return homBasis java-algebra-system-2.7.200/examples/sdjas.rb000066400000000000000000000455261445075545500210210ustar00rootroot00000000000000# # $Id$ # # adapted from the Symbolicdata, Sage and JAS Python code # # communicate with the SPARQL endpoint (http request) #import requests require "net/http" # easily handle URLs #from os.path import split as pathsplit #from urlparse import urlsplit require "uri" # for nice output of dictionaries: json.dumps(dict, indent = 4) # mostly for debugging reasons (will be removed later) require "json" # parse the sd.ini file #from ConfigParser import SafeConfigParser require "configparser" # parse the xml of the resource files #from xml.dom.minidom import parse, parseString require "rexml/document" # output lists nicely (there might be a better way) #from textwrap import wrap as textwrap # not needed #require "examples/jas" # Some internal helper functions that are not meant to be # called by the user =begin rdoc Converts a uri to a name or key by only taking everything after the last / or (if present) #. Examples: http://example.com/test -> test http://example.com/model#testedBy -> testedBy =end def _uri_to_name(uri) usplit = URI(uri) #urlsplit(uri) if usplit.fragment != nil return usplit.fragment else #return pathsplit(usplit.path)[-1] return usplit.path.split('/')[-1] end end =begin rdoc Formats a list l to be displayed in a tabular layout. It is possible to pass an integer width to the textwrap function. The width of the terminal window could be obtained via the Python console module. However, since it is not included in Jas, we decided not to use it. The default width that textwrap uses is set to 70. There might be a better way to do this. =end def _pprint(l) col = l.map{ |x| x.length }.max + 3 # [len(x) for x in l]) + 3 padded = l.map{|x| x.ljust(col) } #.join('') #print textwrap(padded).join('\n') line = '' num = 70 padded.each{|x| line.length < num ? line+=x : begin puts line; line=x end } end =begin rdoc A quick convienience function to retrieve a single value of a given triple (object, predicate, ...) The parameter sd is a SymbolicData object that contains information about the SPARQL endpoint. =end def get_value_for_URI(sd, uri, predicate) result = nil query = "SELECT * WHERE { <#{uri}> <#{predicate}> ?x }" begin qj = SPARQL.new(sd, query) #puts "qj.json = " + str(qj.json) result = qj.json['results']['bindings'][0]['x']['value'] rescue #pass end return result end # Class definitions start here =begin rdoc Access to the database of ideals as provided by the SymbolicData Project (http://symbolicdata.org). =end class SymbolicData # The variables from the sd.ini file attr_reader :_parser, :url, :sqpath, :sd, :sdhost =begin rdoc The constructor parses the sd.ini file and sets up some variables. An optional parameter can be passed to select the SPARQL endpoint that should be used. The keywords for different SPARQL endpoints are defined in the sd.ini file. The default SPARQL endpoint is the one from symbolicdata.org =end def initialize(sparql = 'symbolicdata.org') @_sparql = sparql @_ideals = nil #@_parser = SaveConfigParser.new(['sd.ini','examples/sd.ini']) @_parser = ConfigParser.new('examples/sd.ini') if File.file?('examples/sd.ini') @_parser = ConfigParser.new('sd.ini') if File.file?('sd.ini') @sd = @_parser['symbolicdata']['sd'] begin @url = @_parser['sparql'][@_sparql] rescue raise ArgumentError, "The SPARQL endpoint referenced by '#{@_sparql}' was not found in the sd.ini file." end @sdhost = @_parser['DEFAULT']['sdhost'] sh, sp, port = @url.partition(':') # hack for subst and GI host error @url = @sdhost + sp + port @sqpath = @_parser['sparql']['path'] #puts "SymbolicData() initialized" #puts "url = " + str(@url) #puts "sdhost = " + str(@sdhost) end =begin rdoc Returns a Python list of ideals. =end def get_ideals(force_reload = false) if @_ideals == nil or force_reload == true list_ideals(false, force_reload) end return @_ideals end =begin rdoc Lists all the available ideals. =end def list_ideals(output = true, force_reload = false) if @_ideals == nil or force_reload == true r = SPARQL.new(self, @_parser['queries']['list_ideals']) ids = r.json['results']['bindings'] @_ideals = ids.map{ |x| _uri_to_name(x['ideal']['value']) } end if output _pprint(@_ideals) end end =begin rdoc Returns an ideal as a Jas object that is ready to be used by Jas. =end def get_ideal(uri) return SD_Ideal.new(self, uri).get_ideal(); end =begin rdoc Returns an internal object that represents the SymbolicData database object. (See below for details) =end def get_sd_ideal(uri) return SD_Ideal.new(self, uri) end end =begin rdoc This is a 'wrapper' class for SPARQL queries. A class might be a slight overkill. It was made with the idea, that one can store the query and the result together, to re-evaluate both without having to access the server. However, in the end this feature was not really needed. =end class SPARQL # The json representation of the query result attr_reader :json =begin rdoc Perform the SPARQL query. =end def initialize(sd, query, output = 'json') @_sd = sd; @_query = query; @_data = { 'query' => query, 'output' => output } #self.response = requests.get(self._sd.url, params = self._data) #puts "url = " + str(self._sd.url) uri = URI("http://" + @_sd.url.to_s) #puts "uri = " + uri.to_s #puts "uri.host = " + uri.host.to_s #puts "uri.port = " + uri.port.to_s Net::HTTP.start( uri.host, uri.port ) do |conn| #puts "conn = " + str(conn) #puts "query = " + str(query) #_path = @_sd.sqpath + "?" + URI.encode_www_form(@_data) uri.path = @_sd.sqpath uri.query = URI.encode_www_form(@_data) #puts "uri = ", uri #puts "uri = " + str(uri) #puts "uri.path = " + uri.path.to_s #puts "uri.query = " + uri.query.to_s req = Net::HTTP::Get.new(uri.request_uri) #puts "req = " + str(req) response = conn.request( req ); if not response.is_a?(Net::HTTPSuccess) puts "response = " + response.to_s + "\n" raise RuntimeError, "HTTP GET #{uri} not successful" end #head = response.code.to_s + " " + response.msg #puts "head = " + str(head) + "\n" @text = response.body() #puts "body = " + str(@text) @json = JSON.load(@text) #puts "json = " + str(@json) end end end =begin rdoc This class represents a SymbolicData database object. The constructor takes a complete URI or a name SUBJ (the latter of which will be prefixed with the 'ideal' value from the sd.ini) Any triple of the form (SUBJ, PRED, OBJ) will yield a field PRED* for the SD_Ideal object with the value OBJ, where PRED* is the ending piece of PRED URI as defined by the function _uri_to_name() A SPARQL endpoint is needed. As a future improvement, it could be nice to directly parse an RDF in a convienient serialization. =end class SD_Ideal # the ideal basis attr_reader :basis =begin rdoc sd is a SymbolicData object, the name can be a complete URI or shortened name as defined by _uri_to_name(). The latter will be prefixed with the 'ideal' value from the sd.ini. Namespaces like "sd:Wu-90" are not (yet) supported. Appart from retrieving the information from the SPARQL endpoint, the resource data (XML files) is needed as well. While the SPARQL endpoint can be substituted by another SPARQL endpoint, the links to the resource files are 'hard-coded' into the RDF data. The possibility to use a (possibly 'hand-filled') cache will be included in the next update. =end def initialize(sd, name) @dict = {} # mimic python @_sd = sd # quick test, if the given name already is an uri if name[0,7] == 'http://' @uri = name else @uri = @_sd._parser["symbolicdata"]["ideal"] + name end @dict["hasXMLResource"] = false @dict["hasLengthsList"] = '' @dict["hasDegreeList"] = '' @dict["hasParameters"] = '' @basis = [] # we set up the query to get all predicate values # of the URI/polynomial system/ideal query = " PREFIX sd: <#{@_sd.sd}> SELECT ?p ?o WHERE { <#{@uri}> ?p ?o }" #puts "query = " + query.to_s + "\n" @_request = SPARQL.new(@_sd, query) if @_request.json['results']['bindings'].size == 0 raise ArgumentError, "No data found for <#{@uri}>.\nMaybe the name was misspelled or the SPARQL endpoint is unavailable." end #puts "@_request.json = " + str(@_request.json) # append the keys to the @dict. for t in @_request.json['results']['bindings'] uri = t['p']['value'] obj = t['o']['value'] @dict[_uri_to_name(uri)] = obj end #puts "@dict = " + str(@dict) # Next we need a resource file with the actual expressions that are # used to generate the ideal. # # There are four cases that need to be dealt with # (1) the ideal is constructed direclty # from an IntPS with related XML resource # (2) the ideal is a flat variant of another # ideal # (3) the ideal is obtained by homogenizing # another ideal # (4) the ideal is obtained by parameterizing another # ideal # Please note: While it might seem that only one of (2) and (4) # should be included, both are needed to map the actual history # of how these ideals were obtained. # case 1 if @dict.include?( 'relatedPolynomialSystem' ) link = get_value_for_URI(@_sd, @dict["relatedPolynomialSystem"], @_sd.sd+'relatedXMLResource') __addXMLResource(link) @dict["hasXMLResource"] = true #puts "relatedPolynomialSystem " + str(name) end # case 2 if @dict.include?( 'flatten' ) parent_name = @dict["flatten"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = @dict["hasVariables"] @variables = @variablesCSV.split(",").map{ |x| x.to_s.strip() } @basis = parent.basis #puts "flatten " + str(parent_name) + ", name = " + str(name) end # case 3 if @dict.include?( 'homogenize' ) parent_name = @dict["homogenize"] if @dict.include?( 'homogenizedWith' ) hv = @dict["homogenizedWith"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = parent.variablesCSV + "," + hv @variables = parent.variables @variables.append(hv) @basis = parent.jas_homogenize(hv) #puts "homogenize " + str(parent_name) + ", name = " + str(name) end end # case 4 if @dict.include?( 'parameterize' ) parent_name = @dict["parameterize"] parent = SD_Ideal.new(@_sd, parent_name) @variablesCSV = @dict["hasVariables"] @variables = @variablesCSV.split(",").map{ |x| x.to_s.strip() } @basis = parent.basis #puts "parameterize " + str(parent_name) + ", name = " + str(name) end # now we got the variables, the parameters and # the strings/expressions for the polynomials __constructJasObject() end =begin rdoc Return the ideal as a Jas object. =end def get_ideal() #return ideal(@sageBasis) return @jasRing.ideal("",@jasBasis) end =begin rdoc Fill internal objects. =end def __addXMLResource(link) #xml = requests.get(link).text #puts "link_xml = " + str(link) #url = link[0:23] path = link[23,link.length-23] # hack for lost domain #puts "url = " + str(url) #url = @_sd.url[:-5] url = URI("http://" + @_sd.sdhost.to_s) #puts "url = " + str(url) xml = nil Net::HTTP.start( url.host, url.port ) do |conn| #puts "path = " + str(path) url.path = path #puts "path = " + str(url.request_uri) #conn.request("GET", path ); req = Net::HTTP::Get.new(url.request_uri) response = conn.request( req ); if not response.is_a?(Net::HTTPSuccess) puts "response = " + response.to_s + "\n" raise RuntimeError, "HTTP GET #{url} not successful" end #puts "head = " + response.code.to_s + " " + response.msg + "\n" xml = response.body(); end puts _uri_to_name(link).to_s + " = " + xml.to_s #xmlTree = parseString(xml) xmlTree = REXML::Document.new(xml) #puts "xmlTree = " + str(xmlTree) # Code snipped borrowed from Albert Heinle if xmlTree.elements.to_a("*/vars").empty? # Check, if vars are there raise ArgumentError, "The given XMLString does not contain variables for the IntPS System" end if xmlTree.elements.to_a("*/basis").empty? # Check, if we have a basis raise ArgumentError, "The given XMLString does not contain a basis for the IntPS System" end # -------------------- Input Check finished -------------------- # From here, we can assume that the input is given correct @variablesCSV = xmlTree.elements.to_a("*/vars")[0].text #puts "@variablesCSV = " + @variablesCSV.to_s @variables = @variablesCSV.split(",").map{|x| x.to_s.strip() } #polynomials = xmlTree.elements.to_a("*/basis")[0] @basis = xmlTree.elements.to_a("*/basis/poly").map{ |poly| poly.text.to_s.strip() } #puts "@basis = " + @basis.to_s end =begin rdoc Construct the ideal as a Jas object. =end def __constructJasObject() #require "jas" # set up the polynomial ring (Jas syntax) if @dict.include?('hasParameters') and @dict['hasParameters'] != '' #K = 'K.<%s> = PolynomialRing(ZZ)' % @hasParameters #R = K + '; R.<%s> = PolynomialRing(K)' % @hasVariables kk = PolyRing.new(ZZ(), @dict['hasParameters'].to_s ) rr = PolyRing.new(kk, @dict['hasVariables'].to_s ) gens = '%s,%s' % [@dict['hasParameters'], @dict['hasVariables']] else #R = 'R.<%s> = PolynomialRing(ZZ)' % (@hasVariables) rr = PolyRing.new(ZZ(), @dict['hasVariables'].to_s ) gens = '%s' % @dict['hasVariables'] end # execute remaining JAS semantic constructs #exec(preparse(R)) ##rr = rr + "; " + gens + " = rr.gens();" #puts "rr = " + str(rr) rv = "one," + gens + " = rr.gens();" #puts "rv = " + str(rv) myb = binding #pr = eval(rr.to_s, myb) pr = eval(rv.to_s, myb) # safe here since rr did evaluate @jasRing = rr; #puts "pr = " + str(pr) # avoid XSS: check if polynomials are clean vs = GenPolynomialTokenizer.expressionVariables(gens.to_s) vs = vs.sort #puts "vs = " + str(vs) vsb = [] @basis.each{ |s| vsb += GenPolynomialTokenizer.expressionVariables(s.to_s) } vsb = vsb.sort.uniq #puts "vsb = " + str(vsb) if vs != vsb raise SyntaxError, "invalid variables: expected " + vs.to_s + ", got " + vsb.to_s end # construct polynomials in the constructed ring from # the polynomial expressions @jasBasis = [] for ps in @basis #puts "ps = " + str(ps) ps = ps.to_s ps = ps.gsub('^', '**') #exec(preparse("symbdata_ideal = %s" % ps)) pol = eval("symbdata_poly = %s" % ps, myb) #puts "pol = " + str(pol) @jasBasis.push(pol) end #puts "jasBasis = " + str(@jasBasis) end # the following functions will all use Jas to # calculate metadata =begin rdoc This is the implementation of the predicate "sd:hasLengthsList". The lengths lists is the sorted list of the number of monomials of the generator of the ideal. Along with the output, there will also be generated a field FROM_JAS_hasLengthsList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well. =end def jas_hasLengthsList() begin ll = @jasBasis.map{|x| x.size() }.sort @FROM_JAS_hasLengthsList = ll.map{|x| x.to_s}.join(",") rescue @FROM_JAS_hasLengthsList = '' end return @FROM_JAS_hasLengthsList end =begin rdoc This is the implementation of the predicate "sd:hasDegreeList". The degree list is the sorted list of the degree of the generator of the ideal. Along with the output, there will also be generated a field FROM_JAS_hasDegreeList which can be used to later access the data without recalculating. The main reason for this is that the SymbolicData properties are converted into field, not getter functions. So to have some symmetry, the Jas calculations will end up in fields as well. =end def jas_hasDegreeList() begin ll = @jasBasis.map{|x| x.degree() }.sort @FROM_JAS_hasDegreeList = ll.map{|x| x.to_s}.join(",") rescue @FROM_JAS_hasDegreeList = '' end return @FROM_JAS_hasDegreeList end =begin rdoc This is the implementation of the predicate "sd:hasVariables". This is actually not needed. =end def jas_hasVariables() #K = [] #DL = map(lambda m : K.extend(map(lambda l : str(l), m.variables())), @sageBasis) kk = @jasRing.ring.vars #return sorted(list(set(kk))).join(",") return kk.sort().uniq().join(",") end =begin rdoc Homogenize a basis, which here means actually nothing more than homogenizing every element of the basis. =end def jas_homogenize(hv) homBasis = @jasBasis.map{ |x| x.homogenize(hv) } return homBasis end end to_skip = <> reduction to zero: (9, 12, x1*x2*x3^3*x4^2) x2 # >> reduction to zero: (7, 12, x1*x2*x3^3*x4^2) x2 # >> reduction to zero: (5, 12, x1^2*x3^3*x4^2) x1 # ... [more omitted] # >> 32 reductions to zero # sage: len(B) # >> 42 # minimal_pair # used to select a minimal critical pair from a list; # form of the list is (i,j,t) where t=lcm(lt(g[i]),lt(g[j])); # chosen by smallest lcm # inputs: list of pairs P # outputs: minimal pair in P def minimal_pair(P): result = P.pop() P.add(result) for p in P: if p[2] < result[2]: result = p return result # spol # compute the s-polynomial corresponding to the critical pair p # inputs: critical pair p, basis G # outputs: s-polynomial def spol(p,G): i,j,tij = p R = G[i].parent() # JAS ti = R.monomial_quotient(tij,G[i].lm()) tj = R.monomial_quotient(tij,G[j].lm()) return ti*G[i] - tj*G[j] # monid_quotient # computes the quotient I:J of the monomial ideals I and J # for each tI in I, and for each tJ in J, it computes lcm(tI,tJ)/tJ # this corresponds to computing the u's such that uv is in I for each v in J # note that the ideals must be simplified for this to work correctly # (see below) # inputs: lists of monomials I and J (generators of ideals) # outputs: list of monomials that generate I:J def monid_quotient(I,J,R): # JAS result = set() for tI in I: # R = tI.parent() #JAS for tJ in J: u = R.monomial_quotient(tI.lcm(tJ),tJ).lm() # JAS if not any(R.monomial_divides(t,u) for t in result): result.add(u) return result # monid_add # expands the monomial ideal I by the monomial t # simplifies the result # inputs: list of monomials I (generators of ideal), monomial t # outputs: simplified I+(t) def monid_add(I,t): result = set() R = t.parent() for u in I: if not(R.monomial_divides(t,u)) and not(R.monomial_divides(u,t)): result.add(u) if not any(R.monomial_divides(u,t) for u in result): result.add(t) return result # simplify_monid # simplifies the list of generators of the monomial ideal I # by pruning redundant elements # inputs: list of monomials I (generators of ideal) # outputs: simplified I def simplify_monid(I,R): # JAS result = set() for t in I: #R = t.parent() #JAS if not any(u != t and R.monomial_divides(u,t) for u in I): result.add(t) return result # staglinbasis # computes the Groebner Basis of a polynomial ideal using the # Staggered Linear Basis algorithm of Gebauer-Moeller # inputs: list of polynomials F # outputs: Groebner basis of F def staglinbasis(F): # tracks the number of zero reductions num_zrs = 0 # get polynomial ring R = F[0].parent() G = list(F) # JAS m = len(G) # Z is the set of monomial used to detect principal syzygies # in general, Z should be simplified anytime you modify it Z = [set([G[j].lm() for j in xrange(i)]) for i in xrange(m)] Z = [simplify_monid(ZI,R) for ZI in Z] # JAS # initial set of critical pairs P = set() for i in xrange(m-1): for j in xrange(i+1,m): tij = G[i].lm().lcm(G[j].lm()) tj = R.monomial_quotient(tij,G[j].lm()) # JAS if not any(R.monomial_divides(t,tj) for t in Z[j]): P.add((i,j,tij)) # main loop while len(P) != 0: # choose the pair w/smallest lcm p = minimal_pair(P) P.remove(p) # compute S-polynomial, reduce it s = spol(p,G) i,j,tij = p r = s.reduce(G) if r == 0: print "reduction to zero:", p, R.monomial_quotient(tij,G[j].lm()) num_zrs += 1 else: # new polynomial; add to basis r = r.monic() # JAS #r *= r.lc()**(-1) G.append(r) # update ideals here, also below # need new ideal for G[-1]=r, essentially # Znew = (Z[j] + t[i])):(lcm(t[i],t[j])/t[j]) + (t[1], ..., t[m]) # where t[i] = lm(g[i]) Znew = Z[j].copy() # JAS Znew.update([G[i].lm()]) Znew = simplify_monid(Znew,R) #JAS tj = R.monomial_quotient(tij,G[j].lm()).lm() # JAS Znew = monid_quotient(Znew,[tj],R) # JAS Znew.update([g.lm() for g in G[:-1]]) Znew = simplify_monid(Znew,R) Z.append(Znew) # compute new critical pairs w/new polynomial m = len(G) - 1 for i in xrange(m): tim = G[i].lm().lcm(G[m].lm()) tm = R.monomial_quotient(tim,G[m].lm()) # don't add pairs detected by Z[m] if not any(R.monomial_divides(t,tm) for t in Z[m]): P.add((i,m,tim)) # update Z[j] Z[j].add(R.monomial_quotient(tij,G[j].lm()).lm()) # JAS Z[j] = simplify_monid(Z[j],R) # JAS # prune pairs detected by new Z[j] Q = set() for (i,j,tij) in P: tj = R.monomial_quotient(tij,G[j].lm()) if any(R.monomial_divides(t,tj) for t in Z[j]): Q.add((i,j,tij)) P.difference_update(Q) print num_zrs, "reductions to zero" return G java-algebra-system-2.7.200/examples/std.py000066400000000000000000000015171445075545500205240ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Ideal, PSIdeal, QQ, ZM from jas import startLog, terminate # example from CLO(UAG), 4.4 #R = PolyRing( GF(32003), "x,y,z" ); R = PolyRing( QQ(), "x,y,z" ); print "Ring: " + str(R); print; #automatic: [one,x,y,z] = R.gens(); f1 = x**5 - x * y**6 - z**7; f2 = x * y + y**3 + z**3; f3 = x**2 + y**2 - z**2; L = [f1,f2,f3]; #print "L = ", str(L); F = R.ideal( list=L ); print "Ideal: " + str(F); print; PR = R.powerseriesRing(); print "Power series ring: " + str(PR); print; Fp = PSIdeal(PR,L); print "Power series ideal: " + str(Fp); print; startLog(); #9+5 # truncate at total degree 9 S = Fp.STD(); #print "std: " + str(S); print; for p in S.list: #print "p = ", str(p.asPolynomial()); print "p = ", str(p); print; #sys.exit(); #terminate(); java-algebra-system-2.7.200/examples/std.rb000066400000000000000000000013731445075545500204770ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # example from CLO(UAG), 4.4 #R = PolyRing( GF(32003), "x,y,z" ); R = PolyRing.new( QQ(), "x,y,z" ); puts "Ring: " + str(R); puts; #automatic: one,x,y,z = R.gens(); f1 = x**5 - x * y**6 - z**7; f2 = x * y + y**3 + z**3; f3 = x**2 + y**2 - z**2; L = [f1,f2,f3]; #puts "L = ", str(L); F = R.ideal( "", L ); puts "Ideal: " + str(F); puts; PR = R.powerseriesRing(); puts "Power series ring: " + str(PR); puts; Fp = PSIdeal.new(PR,L); puts "Power series ideal: " + str(Fp); puts; startLog(); #9+5 # truncate at total degree 9 S = Fp.STD(); #puts "std: " + str(S); puts; for p in S.list do #puts "p = ", str(p.asPolynomial()); puts "p = " + str(p); end puts; #sys.exit(); #terminate(); java-algebra-system-2.7.200/examples/subring.py000066400000000000000000000016251445075545500214030ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import Ring, PolyRing, QQ, ZZ, GF, CC, ZM from jas import terminate, startLog # polynomial examples: subring #r = PolyRing( ZM(1152921504606846883), "(x,y,z)", PolyRing.lex ); #r = PolyRing( CC(), "(x,y,z)", PolyRing.lex ); #r = PolyRing( ZZ(), "(x,y,z)", PolyRing.lex ); r = PolyRing( QQ(), "x,y,z", PolyRing.lex ); print "Ring: " + str(r); print; #[one,x,y,z] = r.gens(); a = r.random(3,4); b = r.random(2,3); c = abs( r.random(3,3) ); print "a = ", a; print "b = ", b; print "c = ", c; print; t = System.currentTimeMillis(); dd = r.subring("", [a,b,c]); t = System.currentTimeMillis() - t; print "sub ring = " + str([ str(x) for x in dd]); print; print "subring time = " + str(t) + " milliseconds" ; print; cc = a + b * c; tt = r.subringmember(dd, cc); print "sub ring member = " + str(tt); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/subring.rb000066400000000000000000000015131445075545500213520ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # polynomial examples: subring #r = PolyRing.new( ZM(1152921504606846883), "(x,y,z)", PolyRing.lex ); #r = PolyRing.new( CC(), "(x,y,z)", PolyRing.lex ); #r = PolyRing.new( ZZ(), "(x,y,z)", PolyRing.lex ); r = PolyRing.new( QQ(), "x,y,z", PolyRing.lex ); puts "Ring: " + str(r); puts; #one,x,y,z = r.gens(); a = r.random(3,4); b = r.random(2,3); c = r.random(3,3).abs(); puts "a = " + str(a); puts "b = " + str(b); puts "c = " + str(c); puts; t = System.currentTimeMillis(); dd = r.subring("", [a,b,c]); t = System.currentTimeMillis() - t; puts "sub ring = " + str(dd.map{ |a| a.elem.to_s }); puts; puts "subring time = " + str(t) + " milliseconds" ; puts; cc = a + b * c; tt = r.subringmember(dd, cc); puts "sub ring member = " + str(tt); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/suzukiSato_ex1.py000066400000000000000000000027021445075545500226650ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ, RF from jas import startLog, terminate # Suzuki and Sato, ISSAC 2006, example 1 # integral function coefficients #r = PolyRing( QQ(),"b,a,z,y,x", PolyRing.lex ); #r = PolyRing( RF( PolyRing(QQ(),"a, b",PolyRing.lex) ), "z,y,x", PolyRing.lex ); r = PolyRing( PolyRing(QQ(),"b, a",PolyRing.lex), "z,y,x", PolyRing.lex ); print "Ring: " + str(r); print; #automatic: [one,b,a,z,y,x] = r.gens(); print "gens: ", [ str(f) for f in r.gens() ]; print; #f1 = x**2 - a; #f2 = y**3 - b; f1 = x**3 - a; f2 = y**4 - b; f3 = x + y - z; F = [f1,f2,f3]; print "F: ", [ str(f) for f in F ]; print; startLog(); ## If = r.ideal( "", list = F ); ## print "Ideal: " + str(If); ## print; ## G = If.GB(); ## print "GB: " + str(G); ## print; ## E = G.eliminateRing( PolyRing(QQ(),"b, a",PolyRing.lex) ); ## print "E: " + str(E); ## print; ## sys.exit(); If = r.paramideal( "", list = F ); print "ParamIdeal: " + str(If); print; G = If.GB(); print "GB: " + str(G); print; terminate(); sys.exit(); GS = If.CGBsystem(); print "CGBsystem: " + str(GS); print; bg = GS.isCGBsystem(); if bg: print "isCGBsystem: true"; else: print "isCGBsystem: false"; print; #terminate(); #sys.exit(); CG = If.CGB(); print "CGB: " + str(CG); print; bg = CG.isCGB(); if bg: print "isCGB: true"; else: print "isCGB: false"; print; terminate(); #------------------------------------------ #sys.exit(); java-algebra-system-2.7.200/examples/suzukiSato_ex1.rb000066400000000000000000000021351445075545500226400ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Suzuki and Sato, ISSAC 2006, example 1 # integral function coefficients #r = PolyRing.new( QQ(),"b,a,z,y,x", PolyRing.lex ); #r = PolyRing.new( RF( PolyRing.new(QQ(),"a, b",PolyRing.lex) ), "z,y,x", PolyRing.lex ); r = PolyRing.new( PolyRing.new(QQ(),"b, a",PolyRing.lex), "z,y,x", PolyRing.lex ); puts "Ring: " + str(r); puts; #one,b,a,z,y,x = r.gens(); puts "gens: " + r.gens().each{ |f| str(f) }.join(","); puts; #f1 = x**2 - a; #f2 = y**3 - b; f1 = x**3 - a; f2 = y**4 - b; f3 = x + y - z; F = [f1,f2,f3]; puts "F: " + F.each{ |f| str(f) }.join(","); puts; startLog(); If = r.paramideal( "", list = F ); puts "ParamIdeal: " + str(If); puts; G = If.GB(); puts "GB: " + str(G); puts; terminate(); exit(); GS = If.CGBsystem(); puts "CGBsystem: " + str(GS); puts; bg = GS.isCGBsystem(); if bg puts "isCGBsystem: true"; else puts "isCGBsystem: false"; end puts; terminate(); exit(); CG = If.CGB(); puts "CGB: " + str(CG); puts; bg = CG.isCGB(); if bg puts "isCGB: true"; else puts "isCGB: false"; end puts; terminate(); java-algebra-system-2.7.200/examples/sys-bio.py000066400000000000000000000017041445075545500213150ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import PolyRing, ZM, GF from jas import terminate, startLog # system biology examples: GB in Z_2 # see: Informatik Spektrum, 2009, February, # Laubenbacher, Sturmfels: Computer Algebra in der Systembiologie r = PolyRing(GF(2),"M, B, A, L, P",PolyRing.lex); print "PolyRing: " + str(r); print; #automatic: [one,M,B,A,L,P] = r.gens(); f1 = M - A; f2 = B - M; f3 = A - A - L * B - A * L * B; f4 = P - M; f5 = L - P - L - L * B - L * P - L * B * P; ## t1 = M - 1; ## t2 = B - 1; ## t3 = A - 1; ## t4 = L - 1; ## t5 = P - 1; # ## t1 = M; ## t2 = B; ## t3 = A; ## t4 = L; ## t5 = P; # ## t1 = M; ## t2 = B; ## t3 = A; ## t4 = L - 1; ## t5 = P; # t1 = M; t2 = B; t3 = A - 1; t4 = L - 1; t5 = P; F = [f1,f2,f3,f4,f5]; #F = [f1,f2,f3,f4,f5,t1,t2,t3,t4,t5]; I = r.ideal( "", list=F ); print "Ideal: " + str(I); print; G = I.GB(); print "GB: " + str(G); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/sys-bio.rb000066400000000000000000000016261445075545500212730ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # system biology examples: GB in Z_2 # see: Informatik Spektrum, 2009, February, # Laubenbacher, Sturmfels: Computer Algebra in der Systembiologie r = PolyRing.new(GF(2),"M, B, A, L, P",PolyRing.lex); puts "PolyRing: " + str(r); puts; #automatic not possible, since capital letters one,M,B,A,L,P = r.gens(); f1 = M - A; f2 = B - M; f3 = A - A - L * B - A * L * B; f4 = P - M; f5 = L - P - L - L * B - L * P - L * B * P; ## t1 = M - 1; ## t2 = B - 1; ## t3 = A - 1; ## t4 = L - 1; ## t5 = P - 1; # ## t1 = M; ## t2 = B; ## t3 = A; ## t4 = L; ## t5 = P; # ## t1 = M; ## t2 = B; ## t3 = A; ## t4 = L - 1; ## t5 = P; # t1 = M; t2 = B; t3 = A - 1; t4 = L - 1; t5 = P; F = [f1,f2,f3,f4,f5]; #F = [f1,f2,f3,f4,f5,t1,t2,t3,t4,t5]; I = r.ideal( "", list=F ); puts "Ideal: " + str(I); puts; G = I.GB(); puts "GB: " + str(G); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/sys-bio2.py000066400000000000000000000116121445075545500213760ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys from java.lang import System from jas import PolyRing, QQ, RF, DD from jas import terminate, startLog # system biology examples: GB in RF() # see: Informatik Spektrum, 2009, February, # Laubenbacher, Sturmfels: Computer Algebra in der Systembiologie # example from: http://theory.bio.uu.nl/rdb/books/tb.pdf # ------------ input rational expression -------------------- r = PolyRing(RF(PolyRing(QQ(),"A",PolyRing.lex)),"L, M, R",PolyRing.lex); print "PolyRing: " + str(r); print; #automatic: [one,A,L,M,R] = r.gens(); c = 1; gamma = 1; v = 1; c0 = QQ(5,100); # 0.05 h = 2; n = 5; delta = QQ(2,10); # 0.2 f1 = R - 1/(1+A**n); f2 = M * L - delta * A - ( v * M * A ) / ( h + A ); f3 = c0 + c * ( 1 - 1 / ( 1 + A**n ) - gamma * M); F = [f1,f2,f3]; print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); print; I = r.ideal( "", list=F ); print "Ideal: " + str(I); print; #sys.exit(); G = I.GB(); print "GB: " + str(G); print; # ------------ GB and CGB -------------------- r2 = PolyRing(PolyRing(QQ(),"L",PolyRing.lex),"A, M, R",PolyRing.lex); #r2 = PolyRing(RF(PolyRing(QQ(),"L",PolyRing.lex)),"A, M, R",PolyRing.lex); print "PolyRing: " + str(r2); print; #automatic: [one,L,A,M,R] = r2.gens(); fi1 = ( (21,20) * A**6 + (21,10) * A**5 + (1,20) * A + (1,10) ) * L - ( (1,5) * A**7 + (29,20) * A**6 + (1,5) * A**2 + (9,20) * A ); fi2 = ( A**5 + 1 ) * M - ( (21,20) * A**5 + (1,20) ); fi3 = ( A**5 + 1 ) * R - ( 1 ); #fi4 = L - 1; Fi = [fi1,fi2,fi3]; print "fi1 = " + str(fi1); print "fi2 = " + str(fi2); print "fi3 = " + str(fi3); #print "fi4 = " + str(fi4); print; Ii = r2.ideal( "", list=Fi ); print "Ideal: " + str(Ii); print; Gi = Ii.GB(); print "GB: " + str(Gi); print; Ipi = r2.paramideal( "", list=Gi.list ); print "ParamIdeal: " + str(Ipi); print; cgb = Ipi.CGB(); print "CGB: " + str(cgb); print; #sys.exit(); # ------------ real roots -------------------- r3 = PolyRing(QQ(),"A",PolyRing.lex); print "PolyRing: " + str(r3); print; eps = QQ(1,10) ** DD().elem.DEFAULT_PRECISION; print "eps = ", eps; [one,A] = r3.gens(); plot={}; plotd={}; br = 1; for i in range(1,30): L = QQ(-1) + (i,10); #L = QQ(9,10) + (i,100); fr = QQ(5) * ( (1,5) ) * A**7 - ( (21,20) * L - (29,20) ) * A**6 - ( (21,10) * L ) * A**5 + ( (1,5) ) * A**2 - ( (1,20) * L - (9,20) ) * A - ( (1,10) * L ); print "L = " + str(DD(L)); #print "fr = " + str(fr); #print; t = System.currentTimeMillis(); R = r3.realRoots(fr); t = System.currentTimeMillis() - t; # print "R = " + str([ str(DD(r.elem.getRational())) for r in R ]); print "R = " + str([ r.elem.decimalMagnitude() for r in R ]); plot[float(DD(L))] = R; #print "real roots time =", t, "milliseconds"; if len(R) != br: br = len(R); print "#(real roots) = %s" % br; b = L - (11,100); for j in range(1,12): L = b + (j,100); fri = QQ(5) * ( (1,5) ) * A**7 - ( (21,20) * L - (29,20) ) * A**6 - ( (21,10) * L ) * A**5 + ( (1,5) ) * A**2 - ( (1,20) * L - (9,20) ) * A - ( (1,10) * L ); R = r3.realRoots(fri); print "L = %s, Ri = %s" %(DD(L),[ r.elem.decimalMagnitude() for r in R ]); plot[float(DD(L))] = R; R = r3.realRoots(fri,eps); plotd[float(DD(L))] = [ r.elem.decimalMagnitude() for r in R ]; t = System.currentTimeMillis(); R = r3.realRoots(fr,eps); plotd[float(DD(L))] = [ r.elem.decimalMagnitude() for r in R ]; t = System.currentTimeMillis() - t; print "R = " + str([ r.elem.decimalMagnitude() for r in R ]); print "real roots time =", t, "milliseconds"; print; print "real algebraic numbers:"; pk = plot.keys(); pk.sort(); for l in pk: print "%s, %s" %(l,[ str(p.elem) for p in plot[l]]); print; print "real root approxmations:"; pk = plotd.keys(); pk.sort(); for l in pk: print "%s, %s" %(l,[ str(p) for p in plotd[l]]); print; # ------------ factor polynomial -------------------- r5 = PolyRing(QQ(),"L",PolyRing.lex); print "PolyRing: " + str(r5); print; [one,L] = r5.gens(); frl = L**5 + (5,31) * L**4 - (10,31) * L**3 + (10,31) * L**2 - (5,31) * L + (1,31); #frl = (1,4) * L - (1,4); print "frl = " + str(frl); print; t = System.currentTimeMillis(); R = r5.realRoots(frl); t = System.currentTimeMillis() - t; print "R = " + str([ r.elem.decimalMagnitude() for r in R ]); print "real roots time =", t, "milliseconds"; t = System.currentTimeMillis(); R = r5.realRoots(frl,eps); t = System.currentTimeMillis() - t; print "R = " + str([ r.elem.decimalMagnitude() for r in R ]); print "real roots time =", t, "milliseconds"; t = System.currentTimeMillis(); fk = r5.squarefreeFactors(frl); #fk = r5.factors(frl); t = System.currentTimeMillis() - t; #print "fk = " + str(fk); #print "factor time =", t, "milliseconds"; g = one; for h, i in fk.iteritems(): print "h**i = (", h, ")**" + str(i); h = h**i; g = g*h; #startLog(); terminate(); java-algebra-system-2.7.200/examples/syz.py000066400000000000000000000035301445075545500205540ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring # trinks 7 example r = Ring( "Rat(B,S,T,Z,P,W) L" ); print "Ring: " + str(r); print; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( B**2 + 33/50 B + 2673/10000 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; #Katsura equations for N = 3: #r = Ring( "Rat(u0,u1,u2,u3) L" ); #print "Ring: " + str(r); #print; ps = """ ( u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 - u0, u3*0 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 - u1, u3*0 + u2*0 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 - u2, u3 + u2 + u1 + u0 + u1 + u2 + u3 - 1 ) """; #f = Ideal( r, ps ); #print "Ideal: " + str(f); #print; rg = f.GB(); print "seq Output:", rg; print; from edu.jas.gbufd import SyzygySeq; from edu.jas.gb import GroebnerBaseSeq; from edu.jas.poly import ModuleList; s = SyzygySeq(r.ring.coFac).zeroRelations( rg.list ); sl = ModuleList(rg.pset.ring,s); print "syzygy:", sl; print; z = SyzygySeq(r.ring.coFac).isZeroRelation( s, rg.list ); print "is Syzygy ?", if z: print "true" else: print "false" print; zg = sl; for i in range(1,len(r.ring.vars)+1): print "\n %s. resolution" % i; sl = zg; #mg = ModGroebnerBaseSeq(r.ring.coFac).GB(sl); mg = GroebnerBaseSeq().GB(sl); print "Mod GB: ", mg; print; zg = SyzygySeq(r.ring.coFac).zeroRelations(mg); print "syzygies of Mod GB: ", zg; print; #if ModGroebnerBaseSeq(r.ring.coFac).isGB( mg ): if GroebnerBaseSeq().isGB( mg ): print "is GB"; else: print "is not GB"; if SyzygySeq(r.ring.coFac).isZeroRelation(zg,mg): print "is Syzygy"; else: print "is not Syzygy"; if not zg: break; java-algebra-system-2.7.200/examples/syz.rb000066400000000000000000000037011445075545500205270ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # trinks 7 example r = Ring.new( "Rat(B,S,T,Z,P,W) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( B**2 + 33/50 B + 2673/10000 ) ) """; #f = SimIdeal.new( r, ps ); f = r.ideal( ps ); puts "Ideal: " + str(f); puts; #Katsura equations for N = 3: #r = Ring.new( "Rat(u0,u1,u2,u3) L" ); #puts "Ring: " + str(r); #puts; ps = """ ( u3*u3 + u2*u2 + u1*u1 + u0*u0 + u1*u1 + u2*u2 + u3*u3 - u0, u3*0 + u2*u3 + u1*u2 + u0*u1 + u1*u0 + u2*u1 + u3*u2 - u1, u3*0 + u2*0 + u1*u3 + u0*u2 + u1*u1 + u2*u0 + u3*u1 - u2, u3 + u2 + u1 + u0 + u1 + u2 + u3 - 1 ) """; #f = r.ideal( ps ); #puts "Ideal: " + str(f); #puts; rg = f.GB(); puts "seq Output:" + str(rg); puts; #startLog(); java_import "edu.jas.poly.ModuleList"; java_import "edu.jas.gbufd.SyzygySeq"; java_import "edu.jas.gb.GroebnerBaseSeq"; s = SyzygySeq.new(r.ring.coFac).zeroRelations( rg.list ); sl = ModuleList.new(rg.pset.ring,s); puts "syzygy:" + str(sl); puts; z = SyzygySeq.new(r.ring.coFac).isZeroRelation( s, rg.list ); print "is Syzygy ? " if z puts "true" else puts "false" end puts; zg = sl; for i in 1..(r.ring.nvar) puts "\n #{i}. resolution"; sl = zg; #mg = ModGroebnerBaseSeq.new(r.ring.coFac).GB(sl); mg = GroebnerBaseSeq.new().GB(sl); puts "Mod GB: " + str(mg); puts; zg = SyzygySeq.new(r.ring.coFac).zeroRelations(mg); puts "syzygies of Mod GB: " + str(zg); puts; #if ModGroebnerBaseSeq.new(r.ring.coFac).isGB( mg ) if GroebnerBaseSeq.new().isGB( mg ) puts "is GB"; else puts "is not GB"; end if SyzygySeq.new(r.ring.coFac).isZeroRelation(zg,mg) puts "is Syzygy"; else puts "is not Syzygy"; end if not zg break; end end terminate(); java-algebra-system-2.7.200/examples/syz_script.py000066400000000000000000000020421445075545500221350ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, QQ from jas import startLog, terminate # trinks 7 example r = PolyRing(QQ(), "B,S,T,Z,P,W", PolyRing.lex ); print "Ring: " + str(r); print; #one,B,S,T,Z,P,W = r.gens(); # capital letter variables automaticaly included in Python f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 *B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; f = r.ideal( "", [f1,f2,f3,f4,f5,f6,f7] ); print "Ideal: " + str(f); print; #exit() rg = f.GB(); print "GB: " + str(rg); print; #startLog(); s = rg.syzygy(); print "syzygy: " + str(s); print; #print "is syzygy: " + str(rg.isSyzygy(s)); print "is syzygy: " + str(s.isSyzygy(rg)); print; sg = s.GB(); print "seq module GB: sg = " + str(sg); print sm = sg.syzygy(); print "syzygy: sm = " + str(sm); print; print "is syzygy: " + str(sm.isSyzygy(sg)); print; java-algebra-system-2.7.200/examples/syz_script.rb000066400000000000000000000017341445075545500221170ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # trinks 7 example r = PolyRing.new(QQ(), "B,S,T,Z,P,W", PolyRing.lex ); puts "Ring: " + str(r); puts; one,B,S,T,Z,P,W = r.gens(); # capital letter variables not automaticaly included f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 * B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; f = r.ideal( "", [f1,f2,f3,f4,f5,f6,f7] ); puts "Ideal: " + str(f); puts; #exit() rg = f.GB(); puts "GB: " + str(rg); puts; #startLog(); s = rg.syzygy(); puts "syzygy: " + str(s); puts; t = rg.isSyzygy(s); puts "is syzygy: " + str(t); puts "is syzygy: " + str(s.isSyzygy(rg)); puts; sg = s.GB(); puts "seq module GB: sg = " + str(sg); puts sm = sg.syzygy(); puts "syzygy: sm = " + str(sm); puts; puts "is syzygy: " + str(sm.isSyzygy(sg)); puts; java-algebra-system-2.7.200/examples/syzsolv.py000066400000000000000000000011731445075545500214610ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # ? example rs = """ Rat(a,b,e1,e2,e3) L RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 - e2 ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) """; f = r.ideal( ps ); print "SolvIdeal: " + str(f); print; from edu.jas.gbufd import SolvableSyzygySeq; R = SolvableSyzygySeq(r.ring.coFac).resolution( f.pset ); for i in range(0,R.size()): print "\n %s. resolution" % (i+1); print "\n", R[i]; java-algebra-system-2.7.200/examples/syzsolv.rb000066400000000000000000000012251445075545500214320ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # ? example rs = """ Rat(a,b,e1,e2,e3) L RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 - e2 ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; ps = """ ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) """; f = r.ideal( ps ); puts "SolvIdeal: " + str(f); puts; java_import "edu.jas.gbufd.SolvableSyzygySeq"; #startLog(); R = SolvableSyzygySeq.new(r.ring.coFac).resolution( f.pset ); for i in 0..R.size() puts "\n #{i+1}. resolution"; puts "\n" + str(R[i]); end #terminate(); java-algebra-system-2.7.200/examples/syzy2.py000066400000000000000000000024321445075545500210270ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring # ? example r = Ring( "Rat(x,y,z) L" ); print "Ring: " + str(r); print; ps = """ ( ( z^3 - y ), ( y z - x ), ( y^3 - x^2 z ), ( x z^2 - y^2 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; rg = f.GB(); print "seq Output:", rg; print; from edu.jas.gbufd import SyzygySeq; from edu.jas.poly import ModuleList; from edu.jas.gb import GroebnerBaseSeq; s = SyzygySeq(r.ring.coFac).zeroRelations( rg.list ); sl = ModuleList(rg.pset.ring,s); print "syzygy:", sl; print; z = SyzygySeq(r.ring.coFac).isZeroRelation( s, rg.list ); print "is zero s ?", if z: print "true" else: print "false" print; zg = sl; for i in range(1,len(r.ring.vars)+1): print "\n %s. resolution" % i; sl = zg; #mg = ModGroebnerBaseSeq(r.ring.coFac).GB(sl); mg = GroebnerBaseSeq().GB(sl); print "Mod GB: ", mg; print; zg = SyzygySeq(r.ring.coFac).zeroRelations(mg); print "syzygies of Mod GB: ", zg; print; #if ModGroebnerBaseSeq(r.ring.coFac).isGB( mg ): if GroebnerBaseSeq().isGB( mg ): print "is GB"; else: print "is not GB"; if SyzygySeq(r.ring.coFac).isZeroRelation(zg,mg): print "is Syzygy"; else: print "is not Syzygy"; if not zg.list: break; java-algebra-system-2.7.200/examples/syzy2.rb000066400000000000000000000025431445075545500210050ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # ? example r = Ring.new( "Rat(x,y,z) L" ); puts "Ring: " + str(r); puts; ps = """ ( ( z^3 - y ), ( y z - x ), ( y^3 - x^2 z ), ( x z^2 - y^2 ) ) """; f = r.ideal( ps ); puts "Ideal: " + str(f); puts; rg = f.GB(); puts "seq Output:" + str(rg); puts; #startLog(); java_import "edu.jas.poly.ModuleList"; java_import "edu.jas.gbufd.SyzygySeq"; java_import "edu.jas.gb.GroebnerBaseSeq"; s = SyzygySeq.new(r.ring.coFac).zeroRelations( rg.list ); sl = ModuleList.new(rg.pset.ring,s); puts "syzygy:" + str(sl); puts; z = SyzygySeq.new(r.ring.coFac).isZeroRelation( s, rg.list ); print "is Syzygy ? " if z puts "true" else puts "false" end puts; zg = sl; for i in 1..(r.ring.nvar) puts "\n #{i}. resolution"; sl = zg; #mg = ModGroebnerBaseSeq.new(r.ring.coFac).GB(sl); mg = GroebnerBaseSeq.new().GB(sl); puts "Mod GB: " + str(mg); puts; zg = SyzygySeq.new(r.ring.coFac).zeroRelations(mg); puts "syzygies of Mod GB: " + str(zg); puts; #if ModGroebnerBaseSeq.new(r.ring.coFac).isGB( mg ) if GroebnerBaseSeq.new().isGB( mg ) puts "is GB"; else puts "is not GB"; end if SyzygySeq.new(r.ring.coFac).isZeroRelation(zg,mg) puts "is Syzygy"; else puts "is not Syzygy"; end if not zg break; end end terminate(); java-algebra-system-2.7.200/examples/syzy3.py000066400000000000000000000007041445075545500210300ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import Ring # ? example r = Ring( "Rat(x,y,z) L" ); print "Ring: " + str(r); print; ps = """ ( ( z^3 - y ), ( y z - x ), ( y^3 - x^2 z ), ( x z^2 - y^2 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; from edu.jas.gbufd import SyzygySeq; R = SyzygySeq(r.ring.coFac).resolution( f.pset ); for i in range(0,R.size()): print "\n %s. resolution" % (i+1); print "\n ", R[i]; java-algebra-system-2.7.200/examples/syzy3.rb000066400000000000000000000007511445075545500210050ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # ? example r = Ring.new( "Rat(x,y,z) L" ); print "Ring: " + str(r); print; ps = """ ( ( z^3 - y ), ( y z - x ), ( y^3 - x^2 z ), ( x z^2 - y^2 ) ) """; f = r.ideal( ps ); print "Ideal: " + str(f); print; java_import "edu.jas.gbufd.SyzygySeq"; #startLog(); R = SyzygySeq.new(r.ring.coFac).resolution( f.pset ); for i in 0..R.size() puts "\n #{i+1}. resolution"; puts "\n" + str(R[i]); end #terminate(); java-algebra-system-2.7.200/examples/testunit.py000066400000000000000000000005531445075545500216100ustar00rootroot00000000000000# # test functionality of the jython interface to jas. # $Id$ # # test ideal Groebner bases execfile("examples/trinksTest.py") # test module Groebner bases execfile("examples/armbruster.py") # test solvable Groebner bases execfile("examples/wa_32.py") # test solvable module Groebner bases execfile("examples/solvablemodule.py") import sys; sys.exit(); java-algebra-system-2.7.200/examples/trinks.groovy000066400000000000000000000016021445075545500221340ustar00rootroot00000000000000/* * groovy trinks example. * $Id: $ */ import edu.jas.groovy.Ring import edu.jas.groovy.Ideal def r = new Ring( "Rat(B,S,T,Z,P,W) L" ); println "Ring: " + r.toString(); println ""; def ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ) , ( B**2 + 33/50 B + 2673/10000 ) ) """; // ( B**2 + 33/50 B + 2673/10000 ) def f = r.ideal( ps ); println "Ideal: " + f println "" def rg = f.GB(); println "seq Output: " + rg println "" //terminate() a = new edu.jas.arith.BigRational(2,3) println "a = " + a b = a.fromInteger(5) println "b = " + b c = a.sum(b) println "c = " + c pp = new edu.jas.structure.Power(a) d = pp.positivePower(c,10) println "d = " + d d = pp.power(c,10) println "d = " + d //println "plus = " + (a+b) java-algebra-system-2.7.200/examples/trinks.py000066400000000000000000000031651445075545500212450ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing, Ideal, QQ, ZZ, GF, ZM, CC from jas import startLog, terminate # trinks 6/7 example # QQ = rational numbers, ZZ = integers, CC = complex rational numbers, GF = finite field #QQ = QQ(); ZZ = ZZ(); CC = CC(); #r = PolyRing( GF(19),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing( GF(1152921504606846883),"B,S,T,Z,P,W", PolyRing.lex); # 2^60-93 #r = PolyRing( GF(2**60-93),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing( CC(),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing( ZZ(),"B,S,T,Z,P,W", PolyRing.lex); # not for parallel r = PolyRing( QQ(),"B,S,T,Z,P,W", PolyRing.lex); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring #[one,I,B,S,T,Z,P,W] = r.gens(); # is automaticaly included #[one,B,S,T,Z,P,W] = r.gens(); # is automaticaly included f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 *B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; F = [ f1, f2, f3, f4, f5, f6, f7 ]; # smaller, faster #F = [ f1, f2, f3, f4, f5, f6 ]; # bigger, needs more time #print "F = ", [ str(f) for f in F ]; #print; I = r.ideal( "", list=F ); print "Ideal: " + str(I); print; rg = I.GB(); print "seq Output:", rg; print; #startLog(); rg = I.parGB(2); #print "par Output:", rg; #print; #sys.exit(); # if using ZZ coefficients I.distClient(); # starts in background rg = I.distGB(2); #print "dist Output:", rg; #print; I.distClientStop(); # stops them terminate(); java-algebra-system-2.7.200/examples/trinks.rb000066400000000000000000000031651445075545500212200ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # trinks 6/7 example # QQ = rational numbers, ZZ = integers, CC = complex rational numbers, GF = finite field #r = PolyRing.new( GF(19),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing.new( GF(1152921504606846883),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing.new( GF(2**60-93),"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing.new( CC,"B,S,T,Z,P,W", PolyRing.lex); #r = PolyRing.new( ZZ,"B,S,T,Z,P,W", PolyRing.lex); r = PolyRing.new( QQ,"B,S,T,Z,P,W", PolyRing.lex); puts "Ring: " + r.to_s; puts; # sage like: with generators for the polynomial ring one,B,S,T,Z,P,W = r.gens(); # capital letter variables not automaticaly included #one,I,B,S,T,Z,P,W = r.gens(); f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 * B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; #f7 = B**2 + 33/50 * B + 2673/10000; # fractions work with ruby #puts "f1 = " + f1.to_s; F = [ f1, f2, f3, f4, f5, f6, f7 ]; # smaller, faster #F = [ f1, f2, f3, f4, f5, f6 ]; # bigger, needs more time puts "F = " + F.map { |f| f.to_s }.join(","); puts f = r.ideal( "", F ); puts "Ideal: " + f.to_s; puts; #startLog(); rg = f.GB(); puts "seq Output:", rg; puts; rg = f.parGB(2); puts "par Output:", rg; puts; terminate(); return # if using ZZ coefficients f.distClient(); # starts in background, needs socket permission rg = f.distGB(2); #puts "dist Output:", rg; #puts; f.distClientStop(); # stops them terminate(); java-algebra-system-2.7.200/examples/trinks6.jas000066400000000000000000000003411445075545500214510ustar00rootroot00000000000000# trinks6 (B,S,T,Z,P,W) L ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B^2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B^3 ), ( 99 W - 11 B S + 3 B^2 ) ) java-algebra-system-2.7.200/examples/trinks7.jas000066400000000000000000000004061445075545500214540ustar00rootroot00000000000000# trinks 7 (B,S,T,Z,P,W) L ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( B**2 + 33/50 B + 2673/10000 ) ) java-algebra-system-2.7.200/examples/trinksTest.py000066400000000000000000000020601445075545500220760ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog, terminate # trinks 6/7 example #r = Ring( "Mod 19 (B,S,T,Z,P,W) L" ); #r = Ring( "Mod 1152921504606846883 (B,S,T,Z,P,W) L" ); # 2^60-93 #r = Ring( "Quat(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "C(B,S,T,Z,P,W) L" ); r = Ring( "Rat(B,S,T,Z,P,W) L" ); print "Ring: " + str(r); print; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( 10000 B**2 + 6600 B + 2673 ) ) """; # ( 10000 B**2 + 6600 B + 2673 ) # ( B**2 + 33/50 B + 2673/10000 ) #f = Ideal( r, ps ); #print "Ideal: " + str(f); #print; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); #print "seq Output:", rg; #print; rg = f.parGB(2); #print "par Output:", rg; #print; f.distClient(); # starts in background rg = f.distGB(2); #print "dist Output:", rg; #print; terminate(); sys.exit(); java-algebra-system-2.7.200/examples/trinks_s.py000066400000000000000000000035631445075545500215710ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring from jas import startLog, terminate #import rational; # trinks 6/7 example #r = Ring( "Mod 19 (B,S,T,Z,P,W) L" ); #r = Ring( "Mod 1152921504606846883 (B,S,T,Z,P,W) L" ); # 2^60-93 #r = Ring( "Quat(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "C(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "IntFunc(e,f)(B,S,T,Z,P,W) L" ); r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "Q(B,S,T,Z,P,W) L" ); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring print "r.gens() = ", [ str(f) for f in r.gens() ]; print; #[one,e,f,B,S,T,Z,P,W] = r.gens(); #automatic: [one,B,S,T,Z,P,W] = r.gens(); f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 *B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; #all ok: #f7 = f7 + e * f6**0; #f7 = f7 + 5959345574908321469098512640906154241024000000**2 * f6; #f7 = f7 + 35555./332 * f1; F = [ f1, f2, f3, f4, f5, f6, f7 ]; #F = [ f1, f2, f3, f4, f5, f6 ]; #print "F = ", [ str(f) for f in F ]; I = r.ideal( "", list=F ); print "Ideal: " + str(I); print; #sys.exit(); rg = I.GB(); print "seq Output:", rg; print; terminate(); sys.exit(); ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( 10000 B**2 + 6600 B + 2673 ) ) """; # ( 10000 B**2 + 6600 B + 2673 ) # ( B**2 + 33/50 B + 2673/10000 ) #f = Ideal( r, ps ); #print "Ideal: " + str(f); #print; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); #print "seq Output:", rg; #print; terminate(); #sys.exit(); java-algebra-system-2.7.200/examples/trinks_sigbased_gb.py000066400000000000000000000076451445075545500235650ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System, Integer from jas import PolyRing, ZZ, QQ, ZM from jas import terminate, startLog from basic_sigbased_gb import sigbased_gb from basic_sigbased_gb import ggv, ggv_first_implementation from basic_sigbased_gb import coeff_free_sigbased_gb from basic_sigbased_gb import arris_algorithm, min_size_mons from basic_sigbased_gb import f5, f5z from staggered_linear_basis import staglinbasis #r = PolyRing( QQ(), "(B,S,T,Z,P,W)", PolyRing.lex ); #r = PolyRing( ZZ(), "(B,S,T,Z,P,W)", PolyRing.lex ); r = PolyRing( ZM(32003), "(B,S,T,Z,P,W)", PolyRing.lex ); #r = PolyRing( ZM(19), "(B,S,T,Z,P,W)", PolyRing.lex ); print "Ring: " + str(r); print; [one,B,S,T,Z,P,W] = r.gens(); p1 = 45 * P + 35 * S - 165 * B - 36; p2 = 35 * P + 40 * Z + 25 * T - 27 * S; p3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; p4 = -9 * W + 15 * T * P + 20 * S * Z; p5 = P * W + 2 * T * Z - 11 * B**3; p6 = 99 * W - 11 * B * S + 3 * B**2; p7 = 10000 * B**2 + 6600 * B + 2673; F = [p1,p2,p3,p4,p5,p6,p7]; #F = [p1,p2,p3,p4,p5,p6]; f = r.ideal( list=F ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); rg = f.GB(); if not rg.isGB(): print "seq Output:", rg; print; #------------------- sbgb = sigbased_gb(); arri = arris_algorithm(); arrm = min_size_mons(); ggv = ggv(); ggv1 = ggv_first_implementation(); f5 = f5(); ff5 = f5z(); if True: gg = staglinbasis(F); gg = staglinbasis(F); t = System.currentTimeMillis(); gg = staglinbasis(F); t = System.currentTimeMillis() - t; print "stag executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "stag Output:" + str([ str(ggg) for ggg in gg]); print; if True: gg = sbgb.basis_sig(F); t = System.currentTimeMillis(); gg = sbgb.basis_sig(F); t = System.currentTimeMillis() - t; print "sbgb executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "sbgb Output:" + str([ str(ggg) for ggg in gg]); print; if True: gg = ff5.basis_sig(F); t = System.currentTimeMillis(); gg = ff5.basis_sig(F); t = System.currentTimeMillis() - t; print "f5 executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "f5 Output:" + str([ str(ggg) for ggg in gg]); print; if True: gg = ggv1.basis_sig(F); t = System.currentTimeMillis(); gg = ggv1.basis_sig(F); t = System.currentTimeMillis() - t; print "ggv executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "ggv Output:" + str([ str(ggg) for ggg in gg]); print; if True: gg = arri.basis_sig(F); t = System.currentTimeMillis(); gg = arri.basis_sig(F); t = System.currentTimeMillis() - t; print "arri executed in " + str(t) + " milliseconds"; if not r.ideal(list=gg).isGB(): print "arri Output:" + str([ str(ggg) for ggg in gg]); print; ## Output: for Z_32003 and Trinks 7 ## sequential GB executed in 44 ms ## stag executed in 99 milliseconds ## sbgb executed in 1180 milliseconds ## f5 executed in 128 milliseconds ## ggv executed in 110 milliseconds ## arri executed in 116 milliseconds ## Output: for Z_32003 and Trinks 6 ## sequential GB executed in 302 ms ## stag executed in 213 milliseconds ## sbgb executed in 28849 milliseconds ## f5 executed in 1248 milliseconds ## ggv executed in 237 milliseconds ## arri executed in 410 milliseconds ## Output: for Q and Trinks 7 ## sequential GB executed in 104 ms ## stag executed in 223 milliseconds ## sbgb executed in 1155 milliseconds ## f5 executed in 226 milliseconds ## ggv executed in 98 milliseconds ## arri executed in 111 milliseconds ## Output: for Q and Trinks 6 ## sequential GB executed in 779 ms ## stag executed in 196 milliseconds ## sbgb executed in 740980 milliseconds ## f5 executed in 1435 milliseconds ## ggv executed in 717 milliseconds ## arri executed in 562 milliseconds java-algebra-system-2.7.200/examples/trinks_str.py000066400000000000000000000022301445075545500221250ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import QQ, Ring, PolyRing, Ideal from jas import startLog, terminate # trinks 6/7 example #r = Ring( "Mod 19 (B,S,T,Z,P,W) L" ); #r = Ring( "Mod 1152921504606846883 (B,S,T,Z,P,W) L" ); # 2^60-93 #r = Ring( "Quat(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "C(B,S,T,Z,P,W) L" ); #r = Ring( "Rat(B,S,T,Z,P,W) L" ); r = PolyRing( QQ(),"B,S,T,Z,P,W", PolyRing.lex); print "Ring: " + str(r); print; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( 10000 B**2 + 6600 B + 2673 ) ) """; # ( 10000 B**2 + 6600 B + 2673 ) # ( B**2 + 33/50 B + 2673/10000 ) #f = Ideal( r, ps ); #print "Ideal: " + str(f); #print; f = r.ideal( ps ); print "Ideal: " + str(f); print; #startLog(); rg = f.GB(); #print "seq Output:", rg; #print; rg = f.parGB(2); #print "par Output:", rg; #print; f.distClient(); # starts in background rg = f.distGB(2); #print "dist Output:", rg; #print; terminate(); sys.exit(); # required because of distClient java-algebra-system-2.7.200/examples/trinks_str.rb000066400000000000000000000021621445075545500221040ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # trinks 6/7 example #r = Ring.new( "Mod 19 (B,S,T,Z,P,W) L" ); #r = Ring.new( "Mod 1152921504606846883 (B,S,T,Z,P,W) L" ); # 2^60-93 #r = Ring.new( "Quat(B,S,T,Z,P,W) L" ); #r = Ring.new( "Z(B,S,T,Z,P,W) L" ); #r = Ring.new( "C(B,S,T,Z,P,W) L" ); #r = Ring.new( "Rat(B,S,T,Z,P,W) L" ); r = PolyRing.new( QQ(),"B,S,T,Z,P,W", PolyRing.lex); puts "Ring: " + r.to_s; puts; ps = """ ( ( 45 P + 35 S - 165 B - 36 ), ( 35 P + 40 Z + 25 T - 27 S ), ( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), ( - 9 W + 15 T P + 20 S Z ), ( P W + 2 T Z - 11 B**3 ), ( 99 W - 11 B S + 3 B**2 ), ( 10000 B**2 + 6600 B + 2673 ) ) """; # ( 10000 B**2 + 6600 B + 2673 ) # ( B**2 + 33/50 B + 2673/10000 ) #f = Ideal.new( r, ps ); #puts "Ideal: " + str(f); #puts; f = r.ideal( ps ); puts "Ideal: " + f.to_s; puts; #startLog(); rg = f.GB(); #puts "seq Output:", rg; #puts; rg = f.parGB(2); #puts "par Output:", rg; #puts; f.distClient(); # starts in background rg = f.distGB(2); #puts "dist Output:", rg; #puts; f.distClientStop(); # stops them terminate(); java-algebra-system-2.7.200/examples/trinks_sym.py000066400000000000000000000040521445075545500221310ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import Ring, PolyRing from jas import startLog, terminate from jas import ZZ, QQ, ZM, DD, RF, CC #r = Ring( "Mod 19 (B,S,T,Z,P,W) L" ); #r = Ring( "Mod 1152921504606846883 (B,S,T,Z,P,W) L" ); # 2^60-93 #r = Ring( "Quat(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "C(B,S,T,Z,P,W) L" ); #r = Ring( "IntFunc(e,f)(B,S,T,Z,P,W) L" ); #r = Ring( "Z(B,S,T,Z,P,W) L" ); #r = Ring( "Q(B,S,T,Z,P,W) L" ); #print "Ring: " + str(r); #print; #r = PolyRing(ZZ(),"B,S,T,Z,P,W",PolyRing.lex); #r = PolyRing(QQ(),"B,S,T,Z,P,W",PolyRing.lex); #r = PolyRing(CC(),"B,S,T,Z,P,W",PolyRing.lex); #r = PolyRing(DD(),"B,S,T,Z,P,W",PolyRing.lex); #r = PolyRing(ZM(19),"B,S,T,Z,P,W",PolyRing.lex); #r = PolyRing(ZM(1152921504606846883),"B,S,T,Z,P,W",PolyRing.lex); # 2^60-93 #rc = PolyRing(ZZ(),"e,f",PolyRing.lex); #rc = PolyRing(QQ(),"e,f",PolyRing.lex); #r = PolyRing(rc,"B,S,T,Z,P,W",PolyRing.lex); rqc = PolyRing(ZZ(),"e,f",PolyRing.lex); print "Q-Ring: " + str(rqc); print "rqc.gens() = ", [ str(f) for f in rqc.gens() ]; print; [pone,pe,pf] = rqc.gens(); r = PolyRing(RF(rqc),"B,S,T,Z,P,W",PolyRing.lex); print "Ring: " + str(r); print; # sage like: with generators for the polynomial ring print "r.gens() = ", [ str(f) for f in r.gens() ]; print; [one,e,f,B,S,T,Z,P,W] = r.gens(); #[one,B,S,T,Z,P,W] = r.gens(); #[one,I,B,S,T,Z,P,W] = r.gens(); f1 = 45 * P + 35 * S - 165 * B - 36; f2 = 35 * P + 40 * Z + 25 * T - 27 * S; f3 = 15 * W + 25 * S * P + 30 * Z - 18 * T - 165 * B**2; f4 = - 9 * W + 15 * T * P + 20 * S * Z; f5 = P * W + 2 * T * Z - 11 * B**3; f6 = 99 * W - 11 *B * S + 3 * B**2; f7 = 10000 * B**2 + 6600 * B + 2673; #all ok: f1 = f1 + e; #f7 = f7 + e * f6**0; #f7 = f7 + 5959345574908321469098512640906154241024000000**2 * f6; #f7 = f7 + 35555./332 * f1; F = [ f1, f2, f3, f4, f5, f6, f7 ]; #F = [ f1, f2, f3, f4, f5, f6 ]; #print "F = ", [ str(f) for f in F ]; I = r.ideal( "", list=F ); print "Ideal: " + str(I); print; #sys.exit(); rg = I.GB(); print "seq Output:", rg; print; terminate(); sys.exit(); java-algebra-system-2.7.200/examples/tuzun.py000066400000000000000000000010641445075545500211140ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import PolyRing, Ideal, ZZ from jas import startLog, terminate # tuzun, e-gb example r = PolyRing(ZZ(), "(t)" ); print "Ring: " + str(r); #automatic: [one,t] = r.gens(); print "one: " + str(one); print "t: " + str(t); print; f1 = 2 * t + 1; f2 = t**2 + 1; F = [f1,f2]; I = r.ideal( list=F ); print "Ideal: " + str(I); print; #startLog(); G = I.eGB(); print "seq e-GB:", G; print "is e-GB:", G.iseGB(); print; p = f1 + 2*f2 - f1*f2 + f1**4; print "p:", p; n = G.eReduction(p); print "n:", n; java-algebra-system-2.7.200/examples/tuzun.rb000066400000000000000000000011511445075545500210640ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # tuzun, e-gb example r = PolyRing.new(ZZ(),"t",PolyRing.lex) puts "Ring: " + str(r); puts; #automatic: one,t = r.gens(); f1 = 2 * t + 1; f2 = t**2 + 1; ff = r.ideal( "", [f1,f2] ); puts "ideal: " + str(ff); puts; #t = System.currentTimeMillis(); gg = ff.eGB(); #t = System.currentTimeMillis() - t; puts "seq e-GB: " + str(gg); puts; puts "is e-GB: " + str(gg.iseGB()); #puts "e-GB time = " + str(t) + " milliseconds"; puts; p = f1 + 2*f2 - f1*f2 + f1**4; puts "p: " + str(p); n = gg.eReduction(p); puts "n: " + str(n); #startLog(); terminate(); java-algebra-system-2.7.200/examples/u_2_wa_1.py000066400000000000000000000033641445075545500213300ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing from edu.jas.application import Ideal # U_t, dim 2 and WA_1 example rs1 = """ # solvable polynomials, U_t, dim_2 and Weyl algebra A_1: Rat(D,X,a,b) G|2| RelationTable ( ( b ), ( a ), ( a b + %s a ) ( X ), ( D ), ( D X + 1 ) ) """; rs1c = """ # solvable polynomials, Weyl algebra A_1: Rat(D,X) G RelationTable ( ( X ), ( D ), ( D X + 1 ) ) """; rs2 = """ # solvable polynomials, U_t, dim_2 and Weyl algebra A_1: Rat(a,b,D,X) G|2| RelationTable ( ( b ), ( a ), ( a b + %s a ) ( X ), ( D ), ( D X + 1 ) ) """; rs2c = """ # solvable polynomials, U_t, dim_2: Rat(a,b) G RelationTable ( ( b ), ( a ), ( a b + %s a ) ) """; ps = """ ( ( a - X^%s ), ( b - D X + %s ) ) """; for t in (2,3,5,7,11,13,17,19,23,27,31,37,43): #for t in (5,7): r1 = SolvableRing( rs1 % t ); r1c = SolvableRing( rs1c ); #print "SolvableRing: " + str(r1); #print "SolvableRing: " + str(r1c); #print; it = r1.ideal( ps % (t,t) ); #print "SolvableIdeal: " + str(it); #print; # compute I_{\phi_t} \cap WA_1^opp x = it.leftGB(); print "seq left x:", x; y = Ideal(x.pset).intersect(r1c.ring); len = y.list.size(); print "seq left y: ", y; print "seq left y len: ", len; #print; #------------------------------------- r2 = SolvableRing( rs2 % t ); r2c = SolvableRing( rs2c % t ); #print "SolvableRing: " + str(r2); #print "SolvableRing: " + str(r2c); #print; ikt = r2.ideal( ps % (t,t) ); #print "SolvableIdeal: " + str(ikt); print; # compute ker(\phi_t) x = ikt.leftGB(); print "seq left x:", x; y = Ideal(x.pset).intersect(r2c.ring); len = y.list.size(); print "seq left y: ", y; print "seq left y len: ", len; #print; #------------------------------------- java-algebra-system-2.7.200/examples/u_sl_2.py000066400000000000000000000011121445075545500211040ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # U(sl_2) example rs = """ # solvable polynomials, U(sl_2): Rat(e,f,h) G RelationTable ( ( f ), ( e ), ( e f - h ), ( h ), ( e ), ( e h + 2 e ), ( h ), ( f ), ( f h - 2 f ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( e^2 + f^3 ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; rg = f.leftGB(); print "seq left GB:", rg; print; rg = f.twosidedGB(); print "seq twosided GB:", rg; print; #rg = f.rightGB(); #print "seq right GB:", rg; #print; java-algebra-system-2.7.200/examples/u_sl_2.rb000066400000000000000000000011331445075545500210620ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # U(sl_2) example rs = """ # solvable polynomials, U(sl_2): Rat(e,f,h) G RelationTable ( ( f ), ( e ), ( e f - h ), ( h ), ( e ), ( e h + 2 e ), ( h ), ( f ), ( f h - 2 f ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; ps = """ ( ( e^2 + f^3 ) ) """; f = r.ideal( ps ); puts "SolvableIdeal: " + str(f); puts; #startLog(); rg = f.leftGB(); puts "seq left GB: " + str(rg); puts; rg = f.twosidedGB(); puts "seq twosided GB: " + str(rg); puts; rg = f.rightGB(); puts "seq right GB: " + str(rg); puts; java-algebra-system-2.7.200/examples/u_sl_2_e.py000066400000000000000000000007271445075545500214230ustar00rootroot00000000000000# # jython examples for jas. from jas import SolvableRing # U(sl_2_e) example rs = """ # solvable polynomials, U(sl_2_e): Rat(e,h) G RelationTable ( ( h ), ( e ), ( e h + 2 e ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( e^2 + h^3 ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; rg = f.leftGB(); print "seq left Output:", rg; print; rg = f.twosidedGB(); print "seq twosided Output:", rg; print; java-algebra-system-2.7.200/examples/u_sl_2_e.rb000066400000000000000000000010341445075545500213660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # U(sl_2_e) example rs = """ # solvable polynomials, U(sl_2_e): Rat(e,h) G RelationTable ( ( h ), ( e ), ( e h + 2 e ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; ps = """ ( ( e^2 + h^3 ) ) """; f = r.ideal( ps ); puts "SolvableIdeal: " + str(f); puts; rg = f.leftGB(); puts "seq left Output: " + str(rg); puts; rg = f.twosidedGB(); puts "seq twosided Output: " + str(rg); puts rg = f.rightGB(); puts "seq right GB: " + str(rg); puts; java-algebra-system-2.7.200/examples/u_sl_2_f.py000066400000000000000000000007301445075545500214160ustar00rootroot00000000000000# # jython examples for jas. from jas import SolvableRing # U(sl_2_f) example rs = """ # solvable polynomials, U(sl_2_f): Rat(f,h) G RelationTable ( ( h ), ( f ), ( f h - 2 f ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( h^2 + f^3 ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; rg = f.leftGB(); print "seq left Output:", rg; print; rg = f.twosidedGB(); print "seq twosided Output:", rg; print; java-algebra-system-2.7.200/examples/u_sl_2_wa_1.py000066400000000000000000000034531445075545500220250ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing from jas import startLog, terminate from edu.jas.application import Ideal # U_sl_2 and WA_1 example rs1 = """ # solvable polynomials, U_sl_2 and Weyl algebra A_1: Rat(D,X,e,f,h) G|3| RelationTable ( ( f ), ( e ), ( e f - h ), ( h ), ( e ), ( e h + 2 e ), ( h ), ( f ), ( f h - 2 f ), ( X ), ( D ), ( D X + 1 ) ) """; rs1c = """ # solvable polynomials, Weyl algebra A_1: Rat(D,X) G RelationTable ( ( X ), ( D ), ( D X + 1 ) ) """; rs2 = """ # solvable polynomials, U_sl_2 and Weyl algebra A_1: Rat(e,f,h,D,X) G|2| RelationTable ( ( f ), ( e ), ( e f - h ), ( h ), ( e ), ( e h + 2 e ), ( h ), ( f ), ( f h - 2 f ), ( X ), ( D ), ( D X + 1 ) ) """; rs2c = """ # solvable polynomials, U_sl_2: Rat(e,f,h) G RelationTable ( ( f ), ( e ), ( e f - h ), ( h ), ( e ), ( e h + 2 e ), ( h ), ( f ), ( f h - 2 f ) ) """; ps = """ ( ( e - X ), ( f + D^2 X ), ( h - 2 D X ) ) """; startLog(); r1 = SolvableRing( rs1 ); r1c = SolvableRing( rs1c ); #print "SolvableRing: " + str(r1); #print "SolvableRing: " + str(r1c); print; it = r1.ideal( ps ); print "SolvableIdeal: " + str(it); print; # compute I_{\phi_t} \cap WA_1^opp x = it.leftGB(); print "seq left x:", x; y = Ideal(x.pset).intersect(r1c.ring); len = y.list.size(); print "seq left y: ", y; print "seq left y len: ", len; print; #------------------------------------- r2 = SolvableRing( rs2 ); r2c = SolvableRing( rs2c ); #print "SolvableRing: " + str(r2); #print "SolvableRing: " + str(r2c); print; ikt = r2.ideal( ps ); print "SolvableIdeal: " + str(ikt); print; # compute ker(\phi_t) x = ikt.leftGB(); print "seq left x:", x; y = Ideal(x.pset).intersect(r2c.ring); len = y.list.size(); print "seq left y: ", y; print "seq left y len: ", len; print; #------------------------------------- java-algebra-system-2.7.200/examples/u_sl_3.jas000066400000000000000000000002201445075545500212310ustar00rootroot00000000000000# solvable polynomials in U(sl_3): #(a,x,y) L #RelationTable #( # ( y ), ( x ), ( x y + a ) #) #( # ( y**3 + x**2 y + x y ), # ( x**2 + x ) #) java-algebra-system-2.7.200/examples/u_sl_3.py000066400000000000000000000022511445075545500211120ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # U(sl_3) example rs = """ # solvable polynomials, U(sl_3): Rat(Xa,Xb,Xc,Ya,Yb,Yc,Ha,Hb) G RelationTable ( ( Xb ), ( Xa ), ( Xa Xb - Xc ), ( Ya ), ( Xa ), ( Xa Ya - Ha ), ( Yc ), ( Xa ), ( Xa Yc + Yb ), ( Ha ), ( Xa ), ( Xa Ha + 2 Xa ), ( Hb ), ( Xa ), ( Xa Hb - Xa), ( Yb ), ( Xb ), ( Xb Yb - Hb ), ( Yc ), ( Xb ), ( Xb Yc - Ya ), ( Ha ), ( Xb ), ( Xb Ha - Xb ), ( Hb ), ( Xb ), ( Xb Hb + 2 Xb ), ( Ya ), ( Xc ), ( Xc Ya + Xb ), ( Yb ), ( Xc ), ( Xc Yb - Xa ), ( Yc ), ( Xc ), ( Xc Yc - Ha - Hb ), ( Ha ), ( Xc ), ( Xc Ha + Xc ), ( Hb ), ( Xc ), ( Xc Hb + Xc ), ( Yb ), ( Ya ), ( Ya Yb + Yc ), ( Ha ), ( Ya ), ( Ya Ha - 2 Ya ), ( Hb ), ( Ya ), ( Ya Hb + Ya ), ( Ha ), ( Yb ), ( Yb Ha + Yb ), ( Hb ), ( Yb ), ( Yb Hb - 2 Yb ), ( Ha ), ( Yc ), ( Yc Ha - Yc ), ( Hb ), ( Yc ), ( Yc Hb - Yc ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( Xa + Hb ), ( Xb + Ha Hb ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; rg = f.leftGB(); print "seq left Output:", rg; print; rg = f.twosidedGB(); print "seq twosided Output:", rg; print; java-algebra-system-2.7.200/examples/u_sl_3.rb000066400000000000000000000023601445075545500210660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # U(sl_3) example rs = """ # solvable polynomials, U(sl_3): Rat(Xa,Xb,Xc,Ya,Yb,Yc,Ha,Hb) G RelationTable ( ( Xb ), ( Xa ), ( Xa Xb - Xc ), ( Ya ), ( Xa ), ( Xa Ya - Ha ), ( Yc ), ( Xa ), ( Xa Yc + Yb ), ( Ha ), ( Xa ), ( Xa Ha + 2 Xa ), ( Hb ), ( Xa ), ( Xa Hb - Xa), ( Yb ), ( Xb ), ( Xb Yb - Hb ), ( Yc ), ( Xb ), ( Xb Yc - Ya ), ( Ha ), ( Xb ), ( Xb Ha - Xb ), ( Hb ), ( Xb ), ( Xb Hb + 2 Xb ), ( Ya ), ( Xc ), ( Xc Ya + Xb ), ( Yb ), ( Xc ), ( Xc Yb - Xa ), ( Yc ), ( Xc ), ( Xc Yc - Ha - Hb ), ( Ha ), ( Xc ), ( Xc Ha + Xc ), ( Hb ), ( Xc ), ( Xc Hb + Xc ), ( Yb ), ( Ya ), ( Ya Yb + Yc ), ( Ha ), ( Ya ), ( Ya Ha - 2 Ya ), ( Hb ), ( Ya ), ( Ya Hb + Ya ), ( Ha ), ( Yb ), ( Yb Ha + Yb ), ( Hb ), ( Yb ), ( Yb Hb - 2 Yb ), ( Ha ), ( Yc ), ( Yc Ha - Yc ), ( Hb ), ( Yc ), ( Yc Hb - Yc ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; ps = """ ( ( Xa + Hb ), ( Xb + Ha Hb ) ) """; f = r.ideal( ps ); puts "SolvableIdeal: " + str(f); puts; #startLog(); rg = f.leftGB(); puts "seq left Output:" + str(rg); puts; rg = f.twosidedGB(); puts "seq twosided Output:" + str(rg); puts; rg = f.rightGB(); puts "seq right GB: " + str(rg); puts; java-algebra-system-2.7.200/examples/u_sl_3_prod.py000066400000000000000000000046341445075545500221450ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # U(sl_3) example rs = """ # solvable polynomials, U(sl_3): Rat(Xa,Xb,Xc,Ya,Yb,Yc,Ha,Hb) G RelationTable ( ( Xb ), ( Xa ), ( Xa Xb - Xc ), ( Ya ), ( Xa ), ( Xa Ya - Ha ), ( Yc ), ( Xa ), ( Xa Yc + Yb ), ( Ha ), ( Xa ), ( Xa Ha + 2 Xa ), ( Hb ), ( Xa ), ( Xa Hb - Xa), ( Yb ), ( Xb ), ( Xb Yb - Hb ), ( Yc ), ( Xb ), ( Xb Yc - Ya ), ( Ha ), ( Xb ), ( Xb Ha - Xb ), ( Hb ), ( Xb ), ( Xb Hb + 2 Xb ), ( Ya ), ( Xc ), ( Xc Ya + Xb ), ( Yb ), ( Xc ), ( Xc Yb - Xa ), ( Yc ), ( Xc ), ( Xc Yc - Ha - Hb ), ( Ha ), ( Xc ), ( Xc Ha + Xc ), ( Hb ), ( Xc ), ( Xc Hb + Xc ), ( Yb ), ( Ya ), ( Ya Yb + Yc ), ( Ha ), ( Ya ), ( Ya Ha - 2 Ya ), ( Hb ), ( Ya ), ( Ya Hb + Ya ), ( Ha ), ( Yb ), ( Yb Ha + Yb ), ( Hb ), ( Yb ), ( Yb Hb - 2 Yb ), ( Ha ), ( Yc ), ( Yc Ha - Yc ), ( Hb ), ( Yc ), ( Yc Hb - Yc ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( Xb + Yb ) ) """; # ( Xa + Xb + Xc + Ya + Yb + Yc + Ha + Hb ) f = r.ideal( ps ); print "SolvIdeal: " + str(f); print; fl = f.list; print "fl: ", fl; p = fl[0]; print "p: ", p; print; from java.lang import System p2 = p; n = 15; t = System.currentTimeMillis(); for i in range(1,n): p2 = p2.multiply(p); t1 = System.currentTimeMillis() -t; print "one product in %s ms" % t1; print "p^%s.length: " % n, p2.length(); print; p2 = p; t = System.currentTimeMillis(); for i in range(1,n): p2 = p2.multiply(p); t1 = System.currentTimeMillis() -t; print "one product in %s ms" % t1; print "p^%s.length: " % n, p2.length(); print; ps = """ ( ( Xa ), ( Xb ), ( Xc ), ( Ya ), ( Yb ), ( Yc ), ( Ha ), ( Hb ) ) """; f = r.ideal( ps ); #print "SolvableIdeal: " + str(f); #print; fl = f.list; Yb = fl[4]; p1 = Yb; Xb = fl[1]; p2 = Xb; n = 10; t = System.currentTimeMillis(); for i in range(1,n): p1 = p1.multiply(Yb); p2 = p2.multiply(Xb); p = p1.multiply(p2); t1 = System.currentTimeMillis() -t; print "products in %s ms" % t1; print "Xb^%s * Yb^%s: " % (n,n); #, p; print; pp = p; p1 = Yb; p2 = Xb; t = System.currentTimeMillis(); for i in range(1,n): p1 = p1.multiply(Yb); p2 = p2.multiply(Xb); p = p1.multiply(p2); t1 = System.currentTimeMillis() -t; print "products in %s ms" % t1; print "Xb^%s * Yb^%s: " % (n,n); #, p; print; print "pp == p: ", (pp == p); print; #print "SolvIdeal: " + str(f); #print; java-algebra-system-2.7.200/examples/u_sl_3_prod.rb000066400000000000000000000047241445075545500221200ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # U(sl_3) example rs = """ # solvable polynomials, U(sl_3): #Rat(Xa,Xb,Xc,Ya,Yb,Yc,Ha,Hb) G Int(Xa,Xb,Xc,Ya,Yb,Yc,Ha,Hb) G RelationTable ( ( Xb ), ( Xa ), ( Xa Xb - Xc ), ( Ya ), ( Xa ), ( Xa Ya - Ha ), ( Yc ), ( Xa ), ( Xa Yc + Yb ), ( Ha ), ( Xa ), ( Xa Ha + 2 Xa ), ( Hb ), ( Xa ), ( Xa Hb - Xa), ( Yb ), ( Xb ), ( Xb Yb - Hb ), ( Yc ), ( Xb ), ( Xb Yc - Ya ), ( Ha ), ( Xb ), ( Xb Ha - Xb ), ( Hb ), ( Xb ), ( Xb Hb + 2 Xb ), ( Ya ), ( Xc ), ( Xc Ya + Xb ), ( Yb ), ( Xc ), ( Xc Yb - Xa ), ( Yc ), ( Xc ), ( Xc Yc - Ha - Hb ), ( Ha ), ( Xc ), ( Xc Ha + Xc ), ( Hb ), ( Xc ), ( Xc Hb + Xc ), ( Yb ), ( Ya ), ( Ya Yb + Yc ), ( Ha ), ( Ya ), ( Ya Ha - 2 Ya ), ( Hb ), ( Ya ), ( Ya Hb + Ya ), ( Ha ), ( Yb ), ( Yb Ha + Yb ), ( Hb ), ( Yb ), ( Yb Hb - 2 Yb ), ( Ha ), ( Yc ), ( Yc Ha - Yc ), ( Hb ), ( Yc ), ( Yc Hb - Yc ) ) """; r = SolvableRing.new( rs ); puts "SolvableRing: " + str(r); puts; ps = """ ( ( Xb + Yb ) ) """; # ( Xa + Xb + Xc + Ya + Yb + Yc + Ha + Hb ) f = r.ideal( ps ); puts "SolvIdeal: " + str(f); puts; #startLog(); fl = f.list; puts "fl: " + str(fl); p = fl[0]; puts "p: " + str(p); puts; #from java.lang import System p2 = p; n = 15; t = System.currentTimeMillis(); for i in 1..n p2 = p2.multiply(p); t1 = System.currentTimeMillis() -t; puts "one product in #{t1} ms"; end puts "p^#{n}.length: " + str(p2.length()); puts; p2 = p; t = System.currentTimeMillis(); for i in 1..n p2 = p2.multiply(p); t1 = System.currentTimeMillis() -t; puts "one product in #{t1} ms"; end puts "p^#{n}.length: " + str(p2.length()); puts; ps = """ ( ( Xa ), ( Xb ), ( Xc ), ( Ya ), ( Yb ), ( Yc ), ( Ha ), ( Hb ) ) """; f = r.ideal( ps ); #puts "SolvableIdeal: " + str(f); #puts; fl = f.list; Yb = fl[4]; p1 = Yb; Xb = fl[1]; p2 = Xb; #n = 10; t = System.currentTimeMillis(); for i in 1..n p1 = p1.multiply(Yb); p2 = p2.multiply(Xb); p = p1.multiply(p2); t1 = System.currentTimeMillis() -t; puts "products in #{t1} ms"; end puts "Xb^#{n} * Yb^#{n} .length(): " + str(p.length); puts; pp = p; p1 = Yb; p2 = Xb; t = System.currentTimeMillis(); for i in 1..n p1 = p1.multiply(Yb); p2 = p2.multiply(Xb); p = p1.multiply(p2); t1 = System.currentTimeMillis() -t; puts "products in #{t1} ms"; end puts "Xb^#{n} * Yb^#{n} .length(): " + str(p.length()); puts; puts "pp == p: " + str(pp == p); puts; #puts "SolvIdeal: " + str(f); #puts; java-algebra-system-2.7.200/examples/u_so_3.py000066400000000000000000000017771445075545500211310ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # U(so_3) example rs = """ # solvable polynomials, U(so_3): Rat(x,y,z) G RelationTable ( ( y ), ( x ), ( x y - z ), ( z ), ( x ), ( x z + y ), ( z ), ( y ), ( y z - x ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( x^2 + y^3 ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; rg = f.leftGB(); print "seq left GB:", rg; print; if rg.isLeftGB(): print "is left GB"; else: print "is not left GB"; rg = f.twosidedGB(); print "seq twosided GB:", rg; print; if rg.isLeftGB(): print "twosided GB is left GB"; else: print "twosided GB is not left GB"; if rg.isRightGB(): print "twosided GB is right GB"; else: print "twosided GB is not right GB"; if rg.isTwosidedGB(): print "is twosided GB"; else: print "is not twosided GB"; rg = f.rightGB(); print "seq right GB:", rg; print; if rg.isRightGB(): print "is right GB"; else: print "is not right GB"; java-algebra-system-2.7.200/examples/vw.jas000066400000000000000000000002321445075545500205040ustar00rootroot00000000000000#Weispfenning-94, from SymbolicData: (x, y, z) L ( y^4+x*y^2*z+x^2-2*x*y+y^2+z^2, x*y^4+y*z^4-2*x^2*y-3, -x^3*y^2+x*y*z^3+y^4+x*y^2*z-2*x*y ) java-algebra-system-2.7.200/examples/wa_1.jas000066400000000000000000000002061445075545500207000ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_1: (a,b,x,y) L RelationTable ( ( y ), ( x ), ( x y - 1 ), ) ( ( x y^2 - a ), ( y^3 - b ) ) java-algebra-system-2.7.200/examples/wa_1.py000066400000000000000000000011421445075545500205530ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing # WA_1 example rs = """ # solvable polynomials, Weyl algebra A_1: Rat(p,t,x,d) G RelationTable ( ( d ), ( x ), ( x d + 1 ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( x^7 ), ( x d + 7 ) ) """; i7 = r.ideal( ps ); print "SolvableIdeal: " + str(i7); print; i7rg = i7.leftGB(); print "seq left i7 Output:", i7rg; print; ps = """ ( ( d^7 ), ( x d - 7 + 1 ) ) """; j7 = r.ideal( ps ); print "SolvableIdeal: " + str(j7); print; j7rg = j7.leftGB(); print "seq left i7 Output:", j7rg; print; java-algebra-system-2.7.200/examples/wa_1r.jas000066400000000000000000000006551445075545500210720ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_1, right GB: Rat (a,b,x,y) L RelationTable ( #( y^3 ), ( x ), ( x * y^3 - 3 y^2 ), #( y^2 ), ( x^2 ), ( x^2 * y^2 - 4 x * y + 2 ), #( y^2 ), ( x ), ( x * y^2 - 2 y ), #( y ), ( x^4 ), ( x^4 * y - 4 x^3 ), #( y ), ( x^3 ), ( x^3 * y - 3 x^2 ), #( y ), ( x^2 ), ( x^2 * y - 2 x ), ( y ), ( x ), ( x * y - 1 ) ) ( ( y - 1/48 a^3 * x^2 + 1/12 a^2 * x - 1/2 a ), ( b - 1/24 a^3 ), ( a^4 ) ) java-algebra-system-2.7.200/examples/wa_32.jas000066400000000000000000000003311445075545500207630ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_3,2: (a,b,e1,e2,e3) L RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 - e2 ) ) ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) java-algebra-system-2.7.200/examples/wa_32.py000066400000000000000000000032211445075545500206370ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # import sys; from jas import SolvableRing from jas import startLog, terminate # WA_32 example rs = """ # solvable polynomials, Weyl algebra A_3,2: Rat(a,b,e1,e2,e3) G RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 - e2 ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; startLog(); rg = f.leftGB(); print "seq left GB:", rg; print; if rg.isLeftGB(): print "is left GB"; else: print "is not left GB"; threads = 2; rg = f.parLeftGB(threads); # 2 threads print "par left GB:", rg; print; if rg.isLeftGB(): print "is left GB"; else: print "is not left GB"; #sys.exit(); rg = f.twosidedGB(); print "seq twosided GB:", rg; print; if rg.isLeftGB(): print "twosided GB is left GB"; else: print "twosided GB is not left GB"; if rg.isRightGB(): print "twosided GB is right GB"; else: print "twosided GB is not right GB"; if rg.isTwosidedGB(): print "is twosided GB"; else: print "is not twosided GB"; rg = f.parTwosidedGB(threads); print "par twosided GB:", rg; print; if rg.isLeftGB(): print "twosided GB is left GB"; else: print "twosided GB is not left GB"; if rg.isRightGB(): print "twosided GB is right GB"; else: print "twosided GB is not right GB"; if rg.isTwosidedGB(): print "is twosided GB"; else: print "is not twosided GB"; rg = f.rightGB(); print "seq right GB:", rg; print; if rg.isRightGB(): print "is right GB"; else: print "is not right GB"; terminate(); java-algebra-system-2.7.200/examples/wa_32_syz.py000066400000000000000000000030321445075545500215440ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from jas import SolvableRing from edu.jas.poly import ModuleList; from edu.jas.gbufd import SolvableSyzygySeq; # WA_32 example rs = """ # solvable polynomials, Weyl algebra A_3,2: Rat(a,b,e1,e2,e3) G RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 - e2 ) ) """; r = SolvableRing( rs ); print "SolvableRing: " + str(r); print; ps = """ ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) """; f = r.ideal( ps ); print "SolvableIdeal: " + str(f); print; Z = SolvableSyzygySeq(r.ring.coFac).leftZeroRelationsArbitrary( f.list ); Zp = ModuleList( r.ring, Z ); print "seq left syz Output:", Zp; print; if SolvableSyzygySeq(r.ring.coFac).isLeftZeroRelation( Zp.list, f.list ): print "is left syzygy"; else: print "is not left syzygy"; Zr = SolvableSyzygySeq(r.ring.coFac).rightZeroRelationsArbitrary( f.list ); Zpr = ModuleList( r.ring, Zr ); print "seq right syz Output:", Zpr; print; if SolvableSyzygySeq(r.ring.coFac).isRightZeroRelation( Zpr.list, f.list ): print "is right syzygy"; else: print "is not right syzygy"; rg = f.leftGB(); print "seq left Output:", rg; print; if rg.isLeftGB(): print "is left GB"; else: print "is not left GB"; g = rg.list; rg = f.twosidedGB(); print "seq twosided Output:", rg; print; if rg.isTwosidedGB(): print "is twosided GB"; else: print "is not twosided GB"; rgb = rg.rightGB(); print "seq right Output:", rgb; print; if rgb.isRightGB(): print "is right GB"; else: print "is not right GB"; java-algebra-system-2.7.200/examples/wa_34.jas000066400000000000000000000003311445075545500207650ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_3,4: (a,b,e1,e2,e3) L RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e1 ), ( e3 ), ( e2 ), ( e2 e3 + e2 ) ) ( ( e1 e3^3 + e2^10 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) java-algebra-system-2.7.200/examples/wa_39.jas000066400000000000000000000003711445075545500207760ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_3,9: (a,b,e1,e2,e3) G RelationTable ( ( e3 ), ( e1 ), ( e1 e3 - e3 ), ( e3 ), ( e2 ), ( e2 e3 - e1 ), ( e3 ), ( e1 ), ( e1 e3 + e2 ) ) ( ( e1 e3^3 + e2^2 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) java-algebra-system-2.7.200/examples/wa_41.jas000066400000000000000000000003331445075545500207650ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_4,1: (a,b,e1,e2,e3,e4) G RelationTable ( ( e4 ), ( e2 ), ( e2 e4 - e1 ), ( e4 ), ( e3 ), ( e3 e4 - e2 ) ) ( ( e1 e3^3 + e2^2 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) java-algebra-system-2.7.200/examples/wa_61.jas000066400000000000000000000004021445075545500207640ustar00rootroot00000000000000# solvable polynomials, Weyl algebra A_6,1: (a,b,e1,e2,e3,e4,e5,e6) G RelationTable ( ( e2 ), ( e1 ), ( e1 e2 - e3 ), ( e3 ), ( e1 ), ( e1 e3 - e4 ), ( e5 ), ( e1 ), ( e1 e5 - e6 ) ) ( ( e1 e3^3 + e2^2 - a ), ( e1^3 e2^2 + e3 ), ( e3^3 + e3^2 - b ) ) java-algebra-system-2.7.200/examples/weyl_iter.py000066400000000000000000000042421445075545500217330ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #from java.lang import System #from java.lang import Integer from jas import SolvableRing, SolvPolyRing, PolyRing from jas import QQ, startLog, SRC, SRF # Weyl coefficient field example r = PolyRing(QQ(),"p1,q1"); #is automatic: [one,p1,q1] = p.gens(); relations = [q1, p1, p1 * q1 + 1 ]; print "relations: = " + str([ str(f) for f in relations ]); print; rp = SolvPolyRing(QQ(), "p1,q1", PolyRing.lex, relations); print "SolvPolyRing: " + str(rp); print; print "gens =" + str([ str(f) for f in rp.gens() ]); #is automatic: one,p1,q1 = rp.gens(); scp = SRF(rp); print "scp = " + str(scp); r2 = PolyRing(scp,"p2,q2"); #is automatic: [one,p1,q1,p2,q2] = r2.gens(); relations2 = [q2, p2, p2 * q2 + 1 ]; print "relations: = " + str([ str(f) for f in relations2 ]); print; rp2 = SolvPolyRing(scp, "p2,q2", PolyRing.lex, relations2); print "SolvPolyRing: " + str(rp2); print; print "gens =" + str([ str(f) for f in rp2.gens() ]); #is automatic: one,q1,p1,q2,p2 = rp2.gens(); f1 = p2 + p1; f2 = q2 - q1; print "f1 = " +str(f1); print "f2 = " +str(f2); f3 = f1 * f2; print "f3 = " +str(f3); f4 = f2 * f1; print "f4 = " +str(f4); ff = [ f4 , f3 ]; print "ff = [" + str([ str(f) for f in ff ]); print #exit(0); ii = rp2.ideal( "", ff ); print "SolvableIdeal: " + str(ii); print; rgl = ii.leftGB(); print "seq left GB: " + str(rgl); print "isLeftGB: " + str(rgl.isLeftGB()); print; rgr = ii.rightGB(); print "seq right GB: " + str(rgr); print "isRightGB: " + str(rgr.isRightGB()); print; #startLog(); rgt = ii.twosidedGB(); print "seq twosided GB: " + str(rgt); print "isTwosidedGB: " + str(rgt.isTwosidedGB()); print; #urgt = rgt.univariates(); #print "univariate polynomials: " + str([ str(f) for f in urgt ]); #print; #h = q1; #h = q2; #h = p2; #h = q2 - p2; #h = q1 * q2 + p1 * p2 - p1 + q1**2 + 1; h = q1 * q2 + p1 * p2 + q1; print "polynomial: " + str(h); #hi = rgt.inverse(h); #print "inverse polynomial: " + str(hi); print; exit(); hhi = h * hi; print "h * hi: " + str(hhi); print "h * hi left-mod rgt: " + str(rgt.leftReduction(hhi)); print "h * hi right-mod rgt: " + str(rgt.rightReduction(hhi)); print; java-algebra-system-2.7.200/examples/weyl_iter.rb000066400000000000000000000041371445075545500217110ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl coefficient field example r = PolyRing.new(QQ(),"p1,q1"); #is automatic: one,p1,q1 = r.gens(); relations = [q1, p1, p1 * q1 + 1 ]; puts "relations: = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "p1,q1", PolyRing.lex, relations); puts "SolvPolyRing: " + str(rp); puts; puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #is automatic: one,,p1,q1 = rp.gens(); scp = SRF(rp); puts "scp = " + str(scp); r2 = PolyRing.new(scp,"p2,q2"); #is not okay: one,p1,q1,p2,q2 = r2.gens(); puts "gens r2 =" + r2.gens().join(", ") { |r| r.to_s }; relations2 = [q2, p2, p2 * q2 + 1 ]; puts "relations2: = [" + relations2.join(", ") { |r| r.to_s } + "]"; puts; rp2 = SolvPolyRing.new(scp, "p2,q2", PolyRing.lex, relations2); puts "SolvPolyRing: " + str(rp2); puts; puts "gens rp2 =" + rp2.gens().join(", ") { |r| r.to_s }; #is not okay: one,q1,p1,q2,p2 = rp2.gens(); f1 = p2 + p1; f2 = q2 - q1; puts "f1 = " + str(f1); puts "f2 = " + str(f2); f3 = f1 * f2; puts "f3 = " + str(f3); f4 = f2 * f1; puts "f4 = " + str(f4); ff = [ f4 , f3 ]; puts "ff = [" + ff.join(", ") { |r| r.to_s } + "]"; puts #exit(0); ii = rp2.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts; #urgt = rgt.univariates(); #puts "univariate polynomials: " + urgt.join(", ") { |r| r.to_s }; #puts; #h = q1; #h = q2; #h = p2; #h = q2 - p2; #h = q1 * q2 + p1 * p2 - p1 + q1**2 + 1; h = q1 * q2 + p1 * p2 + q1; puts "polynomial: " + str(h); #hi = rgt.inverse(h); #puts "inverse polynomial: " + str(hi); puts; exit; hhi = h * hi; puts "h * hi: " + str(hhi); puts "h * hi left-mod rgt: " + str(rgt.leftReduction(hhi)); puts "h * hi right-mod rgt: " + str(rgt.rightReduction(hhi)); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E.rb000066400000000000000000000025021445075545500226660ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E #r = PolyRing.new(QQ(),"x2,x1,d2,d1",Order::IGRLEX); r = PolyRing.new(QQ(),"x2,x1,d2,d1",Order::IGRLEX.blockOrder(2)); #r = PolyRing.new(QQ(),"x2,x1,d2,d1"); puts "PolynomialRing: " + str(r); #is not automatic for constants: one,x2,x1,d2,d1 = r.gens(); relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; #puts "order = " + Order.blockOrder(Order::IGRLEX,x1.lm(),2).toScript(); puts; rp = SolvPolyRing.new(QQ(), "x2,x1,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; puts "gens = " + rp.gens().join(", ") { |r| r.to_s }; #is not automatic for constants: one,x2,x1,d2,d1 = rp.gens(); ff = [ x1 * d1 + 1, x2 * d2, x1 * d2 + d2] ; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; exit(0); #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E1.rb000066400000000000000000000024051445075545500227510ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E1 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens = " + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ d1*d6 + x1*d1, d1*d3 + x3*d4 + x2, x3*d3 + x3*d5, x4*d4*d5 + x2**2] ; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E2.rb000066400000000000000000000024401445075545500227510ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E2 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ x3*d4 + x1*d6 + x1**2, x3*d2 - x2*d4 + x3*d5, d2*d3 + x4*d3 + x1**2 - x1*x5 ]; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E3.rb000066400000000000000000000024411445075545500227530ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E3 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ x6*d6 + x1**2 - x5, d4*d6 + x1*d1 + x4**2, d3*d4 + d6**2 - x1*d5 ]; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; #exit(0); rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E4.rb000066400000000000000000000024241445075545500227550ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E4 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ d1*d4 - d2*d6 - x1*d3 - x4*d4 + x2, d3*d5 + x3*d5 + x2*x3 - x1*x4 + x5 ]; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E5.rb000066400000000000000000000024371445075545500227620ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E5 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ x3*d4 + x5*d6 + x2**2 + x4*x6, d1**2 - d1*d4 - x2*d6, x4*d2 - x5*d2 + x2**2 ]; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E6.rb000066400000000000000000000030201445075545500227500ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E6 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); #r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); #rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX, relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ d2*d6 + x4*d2 + x6*d5 + x1*x6, d1*d3 + d4**2 - d6**2 + x1*d2 + x3*x5, d4**2 - d6**2 # not in original example ]; # d5 + x1 # d1 + x5 ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/weyl_sunwang_E7.rb000066400000000000000000000024551445075545500227640ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # Weyl example from Sun, Wang et al, ISSAC 2012, E7 r = PolyRing.new(QQ(),"x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(6)); puts "PolynomialRing: " + str(r); puts relations = [d1, x1, x1 * d1 + 1, d2, x2, x2 * d2 + 1, d3, x3, x3 * d3 + 1, d4, x4, x4 * d4 + 1, d5, x5, x5 * d5 + 1, d6, x6, x6 * d6 + 1 ]; puts "relations = [" + relations.join(", ") { |r| r.to_s } + "]"; puts; rp = SolvPolyRing.new(QQ(), "x6,x5,x4,x3,x2,x1, d6,d5,d4,d3,d2,d1",Order::IGRLEX.blockOrder(2), relations); puts "SolvPolyRing: " + str(rp); puts; #puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; #exit(0); ff = [ d2**2 + d2*d3, d1*d4 + d3*d6 - d4*d6, d1*d2 - x2*d3 + x2*d5, x6*d3 + x1*x3 ]; ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgl = ii.leftGB(); puts "seq left GB: " + str(rgl); puts "isLeftGB: " + str(rgl.isLeftGB()); puts; #exit(0); rgr = ii.rightGB(); puts "seq right GB: " + str(rgr); puts "isRightGB: " + str(rgr.isRightGB()); puts; #startLog(); rgt = ii.twosidedGB(); puts "seq twosided GB: " + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts "isONE: " + str(rgt.isONE()); puts; java-algebra-system-2.7.200/examples/word_evans.py000066400000000000000000000021751445075545500221020ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # non-commutative polynomial examples: evans example r = WordPolyRing(QQ(),"x,y,z"); print "WordPolyRing: " + str(r); print; [one,x,y,z] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print "z = " + str(z); print; f1 = x * y - z; f2 = y * z + 2 * x + z; f3 = y * z + x; print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); print; F = r.ideal( list=[f1,f2,f3] ); print "F = " + str(F); print; startLog(); G = F.GB(); print "G = " + str(G); print "isGB(G) = " + str(G.isGB()); print; #exit(0); c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; print "c1 = " + str(c1); print "c2 = " + str(c2); print "s = " + str(s); print; Fa = r.ideal( list=[f1,f2,f3,c1,c2,s] ); print "Fa = " + str(Fa); print; Ga = Fa.GB(); print "Ga = " + str(Ga); print "isGB(Ga) = " + str(Ga.isGB()); #print; #print "G = " + str(G); print "G == Ga: " + str(cmp(G,Ga)); print "G == Ga: " + str(G.list == Ga.list); print; java-algebra-system-2.7.200/examples/word_evans.rb000066400000000000000000000017051445075545500220530ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # non-commutative polynomial examples: evans example r = WordPolyRing.new(QQ(),"x,y,z"); puts "WordPolyRing: " + str(r); puts; one,x,y,z = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts "z = " + str(z); puts; f1 = x * y - z; f2 = y * z + 2 * x + z; f3 = y * z + x; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; ff = r.ideal( "", [f1,f2,f3] ); puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts "isGB(gg) = " + str(gg.isGB()); puts; #exit(0); c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; puts "c1 = " + str(c1); puts "c2 = " + str(c2); puts "s = " + str(s); puts; ff = r.ideal( "", [f1,f2,f3,c1,c2,s] ); puts "ff = " + str(ff); puts; gga = ff.GB(); puts "gga = " + str(gga); puts "isGB(gga) = " + str(gga.isGB()); puts "gg == gga: " + str(gg.list == gga.list); puts; java-algebra-system-2.7.200/examples/word_exterior.py000066400000000000000000000054021445075545500226230ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras r = WordPolyRing(QQ(), "a,b,c,f,g,h,u,v,w,x,y,z"); #r = WordPolyRing(ZZ(), "a,b,c,f,g,h,u,v,w,x,y,z"); print "WordPolyRing: " + str(r); print; one,a,b,c,f,g,h,u,v,w,x,y,z = r.gens(); print "a = %s" % a; print "z = %s" % z; print; # exterior algebra relations rs = [ b * a - a * b , c * a - a * c , f * a - a * f , g * a - a * g , h * a - a * h , u * a - a * u , v * a - a * v , w * a - a * w , x * a - a * x , y * a - a * y , z * a - a * z , c * b - b * c , f * b - b * f , g * b - b * g , h * b - b * h , u * b - b * u , v * b - b * v , w * b - b * w , x * b - b * x , y * b - b * y , z * b - b * z , f * c - c * f , g * c - c * g , h * c - c * h , u * c - c * u , v * c - c * v , w * c - c * w , x * c - c * x , y * c - c * y , z * c - c * z , g * f - f * g , h * f - f * h , u * f - f * u , v * f - f * v , w * f - f * w , x * f - f * x , y * f - f * y , z * f - f * z , h * g - g * h , u * g - g * u , v * g - g * v , w * g - g * w , x * g - g * x , y * g - g * y , z * g - g * z , u * h - h * u , v * h - h * v , w * h - h * w , x * h - h * x , y * h - h * y , z * h - h * z , v * u - u * v , w * u - u * w , x * u - u * x , y * u - u * y , z * u - u * z , w * v - v * w , x * v - v * x , y * v - v * y , z * v - v * z , x * w - w * x , y * w - w * y , z * w - w * z , y * x - x * y , z * x - x * z , z * y - y * z , a * a , b * b , c * c , f * f , g * g , h * h , u * u , v * v , w * w , x * x , y * y , z * z ]; # ( a*b + c*f + g*h ), # ( u*v + w*x + y*z ), # ( a*v + w*x + y*z ) ff = [ ( a*b + c*f + g*h ), ( u*v + w*x + y*z ) ]; fi = r.ideal("", ff + rs); print "WordPolyIdeal: " + str(fi); print; #startLog(); gi = fi.GB(); print "seq GB: " + str(gi); print; # from exterior.rb # ee = [ ( g * h + c * f + a * b ), ( y * z + w * x + u * v ), ( c * f * g + a * b * g ), ( c * f * h + a * b * h ), ( w * x * y + u * v * y ), ( w * x * z + u * v * z ), a * b * c * g, a * b * f * g, a * b * c * h, a * b * f * h, a * b * c * f, u * v * w * y, u * v * x * y, u * v * w * z, u * v * x * z, u * v * w * x ]; ei = r.ideal("", ee + rs); print "WordPolyIdeal: " + str(ei); print; hi = ei.GB(); print "seq GB: " + str(hi); print; print "gi == hi: " + str(gi == hi); print java-algebra-system-2.7.200/examples/word_exterior.rb000066400000000000000000000051751445075545500226050ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras r = WordPolyRing.new(QQ(), "a,b,c,f,g,h,u,v,w,x,y,z"); #r = WordPolyRing.new(ZZ(), "a,b,c,f,g,h,u,v,w,x,y,z"); puts "WordPolyRing: " + str(r); puts; one,a,b,c,f,g,h,u,v,w,x,y,z = r.gens(); puts "a = %s" % a; puts "z = %s" % z; puts; # exterior algebra relations rs = [ b * a - a * b , c * a - a * c , f * a - a * f , g * a - a * g , h * a - a * h , u * a - a * u , v * a - a * v , w * a - a * w , x * a - a * x , y * a - a * y , z * a - a * z , c * b - b * c , f * b - b * f , g * b - b * g , h * b - b * h , u * b - b * u , v * b - b * v , w * b - b * w , x * b - b * x , y * b - b * y , z * b - b * z , f * c - c * f , g * c - c * g , h * c - c * h , u * c - c * u , v * c - c * v , w * c - c * w , x * c - c * x , y * c - c * y , z * c - c * z , g * f - f * g , h * f - f * h , u * f - f * u , v * f - f * v , w * f - f * w , x * f - f * x , y * f - f * y , z * f - f * z , h * g - g * h , u * g - g * u , v * g - g * v , w * g - g * w , x * g - g * x , y * g - g * y , z * g - g * z , u * h - h * u , v * h - h * v , w * h - h * w , x * h - h * x , y * h - h * y , z * h - h * z , v * u - u * v , w * u - u * w , x * u - u * x , y * u - u * y , z * u - u * z , w * v - v * w , x * v - v * x , y * v - v * y , z * v - v * z , x * w - w * x , y * w - w * y , z * w - w * z , y * x - x * y , z * x - x * z , z * y - y * z , a * a , b * b , c * c , f * f , g * g , h * h , u * u , v * v , w * w , x * x , y * y , z * z ]; # ( a*b + c*f + g*h ), # ( u*v + w*x + y*z ), # ( a*v + w*x + y*z ) ff = [ ( a*b + c*f + g*h ), ( u*v + w*x + y*z ) ]; fi = r.ideal("", ff + rs); puts "WordPolyIdeal: " + str(fi); puts; #startLog(); gi = fi.GB(); puts "seq GB: " + str(gi); puts; # from exterior.rb # ee = [ ( g * h + c * f + a * b ), ( y * z + w * x + u * v ), ( c * f * g + a * b * g ), ( c * f * h + a * b * h ), ( w * x * y + u * v * y ), ( w * x * z + u * v * z ), a * b * c * g, a * b * f * g, a * b * c * h, a * b * f * h, a * b * c * f, u * v * w * y, u * v * x * y, u * v * w * z, u * v * x * z, u * v * w * x ]; ei = r.ideal("", ee + rs); puts "WordPolyIdeal: " + str(ei); puts; hi = ei.GB(); puts "seq GB: " + str(hi); puts; puts "gi == hi: " + (gi === hi).to_s; puts java-algebra-system-2.7.200/examples/word_hawes2.py000066400000000000000000000024551445075545500221600ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal, PolyRing, SolvPolyRing, RingElem from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM, WRC # Hawes & Gibson example 2 # rational function coefficients r = WordPolyRing( PolyRing(ZZ(),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x" ); print "Ring: " + str(r); print; one,a,c,b,y2,y1,z1,z2,x = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; F = [p1,p2,p3,p4,p5]; # make all variables commute cm = [ RingElem(q) for q in r.ring.commute() ]; print "commute: " + str( [ str(q) for q in cm] ); print; g = r.ideal( "", F + cm ); print "Ideal: " + str(g); print; startLog(); rg = g.GB(); print "GB: " + str(rg); print; bg = rg.isGB(); print "isGB: " + str(bg); print; #startLog(); terminate(); java-algebra-system-2.7.200/examples/word_hawes2.rb000066400000000000000000000022001445075545500221170ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # ## \begin{PossoExample} ## \Name{Hawes2} ## \Parameters{a;b;c} ## \Variables{x;y[2];z[2]} ## \begin{Equations} ## x+2y_1z_1+3ay_1^2+5y_1^4+2cy_1 \& ## x+2y_2z_2+3ay_2^2+5y_2^4+2cy_2 \& ## 2 z_2+6ay_2+20 y_2^3+2c \& ## 3 z_1^2+y_1^2+b \& ## 3z_2^2+y_2^2+b \& ## \end{Equations} ## \end{PossoExample} require "examples/jas" # Hawes & Gibson example 2 # rational function coefficients r = WordPolyRing.new( PolyRing.new(ZZ(),"a, c, b",PolyRing.lex), "y2, y1, z1, z2, x" ); puts "Ring: " + str(r); puts; one,a,c,b,y2,y1,z1,z2,x = r.gens(); p1 = x + 2 * y1 * z1 + 3 * a * y1**2 + 5 * y1**4 + 2 * c * y1; p2 = x + 2 * y2 * z2 + 3 * a * y2**2 + 5 * y2**4 + 2 * c * y2; p3 = 2 * z2 + 6 * a * y2 + 20 * y2**3 + 2 * c; p4 = 3 * z1**2 + y1**2 + b; p5 = 3 * z2**2 + y2**2 + b; F = [p1,p2,p3,p4,p5]; # make all variables commute cm = r.ring.commute().map {|q| RingElem.new(q) }; puts "commute: " + str(cm.map{|q| q.to_s}); puts; g = r.ideal( "", F + cm ); puts "Ideal: " + str(g); puts; startLog(); rg = g.GB(); puts "GB: " + str(rg); puts; bg = rg.isGB(); puts "isGB: " + str(bg); puts; #startLog(); terminate(); java-algebra-system-2.7.200/examples/word_residu_exterior.py000066400000000000000000000050041445075545500241740ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM, WRC # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras r = WordPolyRing(QQ(), "a,b,c,f,g,h,u,v,w,x,y,z"); print "WordPolyRing: " + str(r); print; one,a,b,c,f,g,h,u,v,w,x,y,z = r.gens(); print "a = %s" % a; print "z = %s" % z; print; # exterior algebra relations rs = [ b * a - a * b , c * a - a * c , f * a - a * f , g * a - a * g , h * a - a * h , u * a - a * u , v * a - a * v , w * a - a * w , x * a - a * x , y * a - a * y , z * a - a * z , c * b - b * c , f * b - b * f , g * b - b * g , h * b - b * h , u * b - b * u , v * b - b * v , w * b - b * w , x * b - b * x , y * b - b * y , z * b - b * z , f * c - c * f , g * c - c * g , h * c - c * h , u * c - c * u , v * c - c * v , w * c - c * w , x * c - c * x , y * c - c * y , z * c - c * z , g * f - f * g , h * f - f * h , u * f - f * u , v * f - f * v , w * f - f * w , x * f - f * x , y * f - f * y , z * f - f * z , h * g - g * h , u * g - g * u , v * g - g * v , w * g - g * w , x * g - g * x , y * g - g * y , z * g - g * z , u * h - h * u , v * h - h * v , w * h - h * w , x * h - h * x , y * h - h * y , z * h - h * z , v * u - u * v , w * u - u * w , x * u - u * x , y * u - u * y , z * u - u * z , w * v - v * w , x * v - v * x , y * v - v * y , z * v - v * z , x * w - w * x , y * w - w * y , z * w - w * z , y * x - x * y , z * x - x * z , z * y - y * z , a * a , b * b , c * c , f * f , g * g , h * h , u * u , v * v , w * w , x * x , y * y , z * z ]; fi = r.ideal("", rs); print "WordPolyIdeal: " + str(fi); print; ff = [ ( a*b + c*f + g*h ), ( u*v + w*x + y*z ), ( a*v + w*x + y*z ) ]; r1 = WRC(fi,ff[0]); print "r1: " + str(r1); r2 = WRC(fi,ff[1]); print "r2: " + str(r2); r3 = WRC(fi,ff[2]); print "r3: " + str(r3); print; r4 = r1*r2 + r3; print "r4 = r1*r2 + r3: " + str(r4); r5 = r2*r1 + r3; print "r5 = r2*r1 + r3: " + str(r5); print; print "r4 == r5: " + str(r4 == r5); print; r6 = r4**3; print "r6 = r4**3: " + str(r6); print; r7 = r6/r4; print "r7 = r6 / r4: " + str(r7); r8 = r6 % r4; print "r8 = r6 % r4: " + str(r8); print; java-algebra-system-2.7.200/examples/word_residu_exterior.rb000066400000000000000000000045541445075545500241600ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # require "examples/jas" # exterior calculus example # Hartley and Tuckey, 1993, # GB in Clifford and Grassmann algebras r = WordPolyRing.new(QQ(), "a,b,c,f,g,h,u,v,w,x,y,z"); puts "WordPolyRing: " + str(r); puts; one,a,b,c,f,g,h,u,v,w,x,y,z = r.gens(); puts "a = %s" % a; puts "z = %s" % z; puts; # exterior algebra relations rs = [ b * a - a * b , c * a - a * c , f * a - a * f , g * a - a * g , h * a - a * h , u * a - a * u , v * a - a * v , w * a - a * w , x * a - a * x , y * a - a * y , z * a - a * z , c * b - b * c , f * b - b * f , g * b - b * g , h * b - b * h , u * b - b * u , v * b - b * v , w * b - b * w , x * b - b * x , y * b - b * y , z * b - b * z , f * c - c * f , g * c - c * g , h * c - c * h , u * c - c * u , v * c - c * v , w * c - c * w , x * c - c * x , y * c - c * y , z * c - c * z , g * f - f * g , h * f - f * h , u * f - f * u , v * f - f * v , w * f - f * w , x * f - f * x , y * f - f * y , z * f - f * z , h * g - g * h , u * g - g * u , v * g - g * v , w * g - g * w , x * g - g * x , y * g - g * y , z * g - g * z , u * h - h * u , v * h - h * v , w * h - h * w , x * h - h * x , y * h - h * y , z * h - h * z , v * u - u * v , w * u - u * w , x * u - u * x , y * u - u * y , z * u - u * z , w * v - v * w , x * v - v * x , y * v - v * y , z * v - v * z , x * w - w * x , y * w - w * y , z * w - w * z , y * x - x * y , z * x - x * z , z * y - y * z , a * a , b * b , c * c , f * f , g * g , h * h , u * u , v * v , w * w , x * x , y * y , z * z ]; fi = r.ideal("", rs); puts "WordPolyIdeal: " + str(fi); puts; ff = [ ( a*b + c*f + g*h ), ( u*v + w*x + y*z ), ( a*v + w*x + y*z ) ]; r1 = WRC(fi,ff[0]); puts "r1: " + str(r1); r2 = WRC(fi,ff[1]); puts "r2: " + str(r2); r3 = WRC(fi,ff[2]); puts "r3: " + str(r3); puts; r4 = r1*r2 + r3; puts "r4 = r1*r2 + r3: " + str(r4); r5 = r2*r1 + r3; puts "r5 = r2*r1 + r3: " + str(r5); puts; puts "r4 == r5: " + str(r4 == r5); puts; r6 = r4**3; puts "r6 = r4**3: " + str(r6); puts; r7 = r6/r4; puts "r7 = r6 / r4: " + str(r7); r8 = r6 % r4; puts "r8 = r6 % r4: " + str(r8); puts; java-algebra-system-2.7.200/examples/word_simple.py000066400000000000000000000045471445075545500222640ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # non-commutative polynomial examples: simple test r = WordPolyRing(QQ(),"x,y"); print "WordPolyRing: " + str(r); print; [one,x,y] = r.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print; f1 = x*y - (1,10); f2 = y*x + x + y; print "f1 = " + str(f1); print "f2 = " + str(f2); print; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; print "c1 = " + str(c1); print "c2 = " + str(c2); print "s = " + str(s); print; F = r.ideal( list=[f1,f2] ); print "F = " + str(F); print; startLog(); G = F.GB(); print "G = " + str(G); print "isGB(G) = " + str(G.isGB()); print; F = r.ideal( list=[f1,f2,c1,c2,s] ); print "F = " + str(F); print; G = F.GB(); print "G = " + str(G); print "isGB(G) = " + str(G.isGB()); print; p = r.random(3,6,4); print "p = " + str(p); print; pp = p**5; print "#pp = " + str(len(pp)); print "p == pp: " + str(p == pp); print "pp == pp: " + str(pp == pp); print "pp-pp == 0: " + str(pp-pp == 0); print; #exit(0); ri = WordPolyRing(ZZ(),"x,y"); print "WordPolyRing: " + str(ri); print; [one,x,y] = ri.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print; f1 = x*y - 10; f2 = y*x + x + y; print "f1 = " + str(f1); print "f2 = " + str(f2); print; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; print "c1 = " + str(c1); print "c2 = " + str(c2); print "s = " + str(s); print; Fi = ri.ideal( list=[f1,f2] ); print "Fi = " + str(Fi); print; #not implemented: #Gi = Fi.GB(); #print "Gi = " + str(Gi); #print "isGB(Gi) = " + str(Gi.isGB()); #print; #exit(0); rp = WordPolyRing(GF(23),"x,y"); print "WordPolyRing: " + str(rp); print; [one,x,y] = rp.gens(); print "one = " + str(one); print "x = " + str(x); print "y = " + str(y); print; f1 = x*y - 10; f2 = y*x + x + y; print "f1 = " + str(f1); print "f2 = " + str(f2); print; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; s1 = 22 * y*x*x*y + x*y*y*x + 22 * y*x*y + x*y*y + x*y*x + 22 * x*x*y; print "c1 = " + str(c1); print "c2 = " + str(c2); print "s = " + str(s); print "s1 = " + str(s1); print "s == s1: " + str(s==s1); print; Fp = rp.ideal( list=[f1,f2] ); print "Fp = " + str(Fp); print; Gp = Fp.GB(); print "Gp = " + str(Gp); print "isGB(Gp) = " + str(Gp.isGB()); print; java-algebra-system-2.7.200/examples/word_simple.rb000066400000000000000000000043641445075545500222340ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # non-commutative polynomial examples: simple test r = WordPolyRing.new(QQ(),"x,y"); puts "WordPolyRing: " + str(r); puts; one,x,y = r.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts; f1 = x*y - 1/10; f2 = y*x + x + y; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; puts "c1 = " + str(c1); puts "c2 = " + str(c2); puts "s = " + str(s); puts; ff = r.ideal( "", [f1,f2] ); puts "ff = " + str(ff); puts; #startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts "isGB(gg) = " + str(gg.isGB()); puts; ff = r.ideal( "", [f1,f2,c1,c2,s] ); puts "ff = " + str(ff); puts; gg = ff.GB(); puts "gg = " + str(gg); puts "isGB(gg) = " + str(gg.isGB()); puts; p = r.random(3,6,4); puts "p = " + str(p); puts; pp = p**5; puts "#pp = " + str(pp.to_s.length); puts "p == pp: " + str(p == pp); puts "pp == pp: " + str(pp == pp); puts "(pp-pp).isZERO: " + str((pp-pp).isZERO()); puts; #exit(0); ri = WordPolyRing.new(ZZ(),"x,y"); puts "WordPolyRing: " + str(ri); puts; one,x,y = ri.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts; f1 = x*y - 10; f2 = y*x + x + y; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; puts "c1 = " + str(c1); puts "c2 = " + str(c2); puts "s = " + str(s); puts; fi = ri.ideal( "", [f1,f2] ); puts "fi = " + str(fi); puts; #not implemented: #Gi = Fi.GB(); #puts "Gi = " + str(Gi); #puts "isGB(Gi) = " + str(Gi.isGB()); #puts; #exit(0); rp = WordPolyRing.new(GF(23),"x,y"); puts "WordPolyRing: " + str(rp); puts; one,x,y = rp.gens(); puts "one = " + str(one); puts "x = " + str(x); puts "y = " + str(y); puts; f1 = x*y - 10; f2 = y*x + x + y; puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts; c1 = f1 * f2; c2 = f2 * f1; s = c1 - c2; s1 = 22 * y*x*x*y + x*y*y*x + 22 * y*x*y + x*y*y + x*y*x + 22 * x*x*y; puts "c1 = " + str(c1); puts "c2 = " + str(c2); puts "s = " + str(s); puts "s1 = " + str(s1); puts "s == s1: " + str(s==s1); puts; fp = rp.ideal( "", [f1,f2] ); puts "fp = " + str(fp); puts; gp = fp.GB(); puts "gp = " + str(gp); puts "isGB(gp) = " + str(gp.isGB()); puts; java-algebra-system-2.7.200/examples/word_solvable.py000066400000000000000000000042621445075545500225740ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal, PolyRing, SolvPolyRing from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # non-commutative polynomial examples: solvable polynomials example #r = WordPolyRing(QQ(),"a,b,e1,e2,e3"); r = WordPolyRing(QQ(),"a,b,e,f,g"); print "WordPolyRing: " + str(r); print; [one,a,b,e,f,g] = r.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "e = " + str(e); print "f = " + str(f); print "g = " + str(g); print; r1 = g * e - (e*g - e); r2 = g * f - (f*g - f); r3 = e * a - a * e; r4 = e * b - b * e; r5 = f * a - a * f; r6 = f * b - b * f; r7 = g * a - a * g; r8 = g * b - b * g; f1 = e * g**3 + f**10 - a; f2 = e**3 * f**2 + g; f3 = g**3 + g**2 - b; print "r1 = " + str(r1); print "r2 = " + str(r2); print "r3 = " + str(r3); print "r4 = " + str(r4); print "r5 = " + str(r5); print "r6 = " + str(r6); print "r7 = " + str(r7); print "r8 = " + str(r8); print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); print; F = r.ideal( list=[r1,r2,r3,r4,r5,r6,r7,r8,f1,f2,f3] ); #F = r.ideal( list=[r1,r2,f1,f2,f3] ); print "F = " + str(F); print; startLog(); G = F.GB(); print "G = " + str(G); print "isGB(G) = " + str(G.isGB()); print; # now as solvable polynomials p = PolyRing(QQ(),"a,b,e1,e2,e3"); #is automatic: [one,a,b,e1,e2,e3] = p.gens(); relations = [e3, e1, e1*e3 - e1, e3, e2, e2*e3 - e2]; print "relations: =", [ str(f) for f in relations ]; print; #rp = SolvPolyRing(QQ(), "a,b,e1,e2,e3", rel=relations); rp = SolvPolyRing(QQ(), "a,b,e1,e2,e3", PolyRing.lex, relations); print "SolvPolyRing: " + str(rp); print; print "gens =", [ str(f) for f in rp.gens() ]; #[one,a,b,e1,e2,e3] = rp.gens(); #[one,I,J,K,a,b,e1,e2,e3] = rp.gens(); f1 = e1 * e3**3 + e2**10 - a; f2 = e1**3 * e2**2 + e3; f3 = e3**3 + e3**2 - b; F = [ f1, f2, f3 ]; print "F =", [ str(f) for f in F ]; print I = rp.ideal( list=F ); print "SolvableIdeal: " + str(I); print; rgt = I.twosidedGB(); print "seq twosided GB:" + str(rgt); print "isTwosidedGB: " + str(rgt.isTwosidedGB()); print print "rgt: ", [ str(f) for f in rgt.list ]; print; java-algebra-system-2.7.200/examples/word_solvable.rb000066400000000000000000000037421445075545500225510ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # non-commutative polynomial examples: solvable polynomials example #r = WordPolyRing.new(QQ(),"a,b,e1,e2,e3"); r = WordPolyRing.new(QQ(),"a,b,e,f,g"); puts "WordPolyRing: " + str(r); puts; one,a,b,e,f,g = r.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "e = " + str(e); puts "f = " + str(f); puts "g = " + str(g); puts; r1 = g * e - (e*g - e); r2 = g * f - (f*g - f); r3 = e * a - a * e; r4 = e * b - b * e; r5 = f * a - a * f; r6 = f * b - b * f; r7 = g * a - a * g; r8 = g * b - b * g; f1 = e * g**3 + f**10 - a; f2 = e**3 * f**2 + g; f3 = g**3 + g**2 - b; puts "r1 = " + str(r1); puts "r2 = " + str(r2); puts "r3 = " + str(r3); puts "r4 = " + str(r4); puts "r5 = " + str(r5); puts "r6 = " + str(r6); puts "r7 = " + str(r7); puts "r8 = " + str(r8); puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; ff = r.ideal( "", [r1,r2,r3,r4,r5,r6,r7,r8,f1,f2,f3] ); puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts "isGB(gg) = " + str(gg.isGB()); puts; #exit(0); # now as solvable polynomials p = PolyRing.new(QQ(),"a,b,e1,e2,e3"); #is automatic: [one,a,b,e1,e2,e3] = p.gens(); relations = [e3, e1, e1*e3 - e1, e3, e2, e2*e3 - e2]; puts "relations: = " + relations.join(", ") { |r| r.to_s }; puts; rp = SolvPolyRing.new(QQ(), "a,b,e1,e2,e3", PolyRing.lex, relations); puts "SolvPolyRing: " + str(rp); puts; puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; one,a,b,e1,e2,e3 = rp.gens(); #one,I,J,K,a,b,e1,e2,e3 = rp.gens(); f1 = e1 * e3**3 + e2**10 - a; f2 = e1**3 * e2**2 + e3; f3 = e3**3 + e3**2 - b; F = [ f1, f2, f3 ]; puts "F = " + F.join(", ") { |r| r.to_s }; puts I = rp.ideal( "", F ); puts "SolvableIdeal: " + str(I); puts; rgt = I.twosidedGB(); puts "seq twosided GB:" + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts puts "rgt: " + rgt.list.join(", ") { |r| r.to_s }; puts; java-algebra-system-2.7.200/examples/word_solvable_trans.py000066400000000000000000000042701445075545500240020ustar00rootroot00000000000000# # jython examples for jas. # $Id$ # #from java.lang import System from jas import WordRing, WordPolyRing, WordPolyIdeal, PolyRing, SolvPolyRing from jas import terminate, startLog from jas import QQ, ZZ, GF, ZM # non-commutative polynomial examples: solvable polynomials example r = WordPolyRing(QQ(),"a,b,e1,e2,e3"); print "WordPolyRing: " + str(r); print; [one,a,b,e1,e2,e3] = r.gens(); print "one = " + str(one); print "a = " + str(a); print "b = " + str(b); print "e1 = " + str(e1); print "e2 = " + str(e2); print "e3 = " + str(e3); print; r1 = e3 * e1 - (e1 * e3 - e1); r2 = e3 * e2 - (e2 * e3 - e2); r3 = e1 * a - a * e1; r4 = e1 * b - b * e1; r5 = e2 * a - a * e2; r6 = e2 * b - b * e2; r7 = e3 * a - a * e3; r8 = e3 * b - b * e3; f1 = e1 * e3**3 + e2**10 - a; f2 = e1**3 * e2**2 + e3; f3 = e3**3 + e3**2 - b; print "r1 = " + str(r1); print "r2 = " + str(r2); print "r3 = " + str(r3); print "r4 = " + str(r4); print "r5 = " + str(r5); print "r6 = " + str(r6); print "r7 = " + str(r7); print "r8 = " + str(r8); print "f1 = " + str(f1); print "f2 = " + str(f2); print "f3 = " + str(f3); print; F = r.ideal( list=[r1,r2,r3,r4,r5,r6,r7,r8,f1,f2,f3] ); #F = r.ideal( list=[r1,r2,f1,f2,f3] ); print "F = " + str(F); print; startLog(); G = F.GB(); print "G = " + str(G); print "isGB(G) = " + str(G.isGB()); print; # now as solvable polynomials p = PolyRing(QQ(),"a,b,e1,e2,e3"); #is automatic: [one,a,b,e1,e2,e3] = p.gens(); relations = [e3, e1, e1*e3 - e1, e3, e2, e2*e3 - e2]; print "relations: =", [ str(f) for f in relations ]; print; #rp = SolvPolyRing(QQ(), "a,b,e1,e2,e3", rel=relations); rp = SolvPolyRing(QQ(), "a,b,e1,e2,e3", PolyRing.lex, relations); print "SolvPolyRing: " + str(rp); print; print "gens =", [ str(f) for f in rp.gens() ]; #[one,a,b,e1,e2,e3] = rp.gens(); #[one,I,J,K,a,b,e1,e2,e3] = rp.gens(); f1 = e1 * e3**3 + e2**10 - a; f2 = e1**3 * e2**2 + e3; f3 = e3**3 + e3**2 - b; F = [ f1, f2, f3 ]; print "F =", [ str(f) for f in F ]; print I = rp.ideal( list=F ); print "SolvableIdeal: " + str(I); print; rgt = I.twosidedGB(); print "seq twosided GB:" + str(rgt); print "isTwosidedGB: " + str(rgt.isTwosidedGB()); print print "rgt: ", [ str(f) for f in rgt.list ]; print; java-algebra-system-2.7.200/examples/word_solvable_trans.rb000066400000000000000000000043031445075545500237520ustar00rootroot00000000000000# # jruby examples for jas. # $Id$ # #load "examples/jas.rb" require "examples/jas" # non-commutative polynomial examples: solvable polynomials example r = WordPolyRing.new(QQ(),"a,b,e1,e2,e3"); puts "WordPolyRing: " + str(r); puts; one,a,b,e1,e2,e3 = r.gens(); puts "one = " + str(one); puts "a = " + str(a); puts "b = " + str(b); puts "e1 = " + str(e1); puts "e2 = " + str(e2); puts "e3 = " + str(e3); puts; r1 = e3 * e1 - (e1 * e3 - e1); r2 = e3 * e2 - (e2 * e3 - e2); r3 = e1 * a - a * e1; r4 = e1 * b - b * e1; r5 = e2 * a - a * e2; r6 = e2 * b - b * e2; r7 = e3 * a - a * e3; r8 = e3 * b - b * e3; f1 = e1 * e3**3 + e2**10 - a; f2 = e1**3 * e2**2 + e3; f3 = e3**3 + e3**2 - b; puts "r1 = " + str(r1); puts "r2 = " + str(r2); puts "r3 = " + str(r3); puts "r4 = " + str(r4); puts "r5 = " + str(r5); puts "r6 = " + str(r6); puts "r7 = " + str(r7); puts "r8 = " + str(r8); puts "f1 = " + str(f1); puts "f2 = " + str(f2); puts "f3 = " + str(f3); puts; ff = r.ideal( "", [r1,r2,r3,r4,r5,r6,r7,r8,f1,f2,f3] ); puts "ff = " + str(ff); puts; startLog(); gg = ff.GB(); puts "gg = " + str(gg); puts "isGB(gg) = " + str(gg.isGB()); puts; #exit(0); # now as solvable polynomials p = PolyRing.new(QQ(),"a,b,e1,e2,e3"); #is automatic: ? one,a,b,e1,e2,e3 = p.gens(); relations = [e3, e1, e1*e3 - e1, e3, e2, e2*e3 - e2]; puts "relations: = " + relations.join(", ") { |r| r.to_s }; puts; rp = SolvPolyRing.new( QQ(), "a,b,e1,e2,e3", PolyRing.grad, relations); puts "SolvPolyRing: " + str(rp); puts; puts "gens =" + rp.gens().join(", ") { |r| r.to_s }; one,a,b,e1,e2,e3 = rp.gens(); #one,I,J,K,a,b,e1,e2,e3 = rp.gens(); f1 = - a + e2**10 + e1 * e3**3; #puts "f1 = " + f1.to_s; f2 = e1**3 * e2**2 + e3; #puts "f2 = " + f2.to_s; f3 = e3**3 + e3**2 - b; #puts "f3 = " + f3.to_s; #puts "+ f3 type(#{f3}) = #{f3.elem.class}\n"; #puts "+ f3.val = " + f3.elem.getMap().map { |e,c| c.to_s + " " + e.to_s }.join(", "); ff = [ f1, f2, f3 ]; puts "ff = " + ff.join(", ") { |r| r.to_s }; puts ii = rp.ideal( "", ff ); puts "SolvableIdeal: " + str(ii); puts; rgt = ii.twosidedGB(); puts "seq twosided GB:" + str(rgt); puts "isTwosidedGB: " + str(rgt.isTwosidedGB()); puts puts "rgt: " + rgt.list.join(", ") { |r| r.to_s }; puts; java-algebra-system-2.7.200/html.css000066400000000000000000000011051445075545500172110ustar00rootroot00000000000000 body { background-color: #FFFFF5; margin-right: 1em; margin-left: 0.5em; } body.main { margin-top: 2.5em; } pre { background-color: silver; margin-left: 1em; margin-right: 1em; padding: 1em; } code { font-family: Courier, monospace; white-space: pre; font-size: larger; /* background: silver; */ } dt { font-weight: bolder; margin-top: 1em; } nav { line-height: 1.4em; } h1 { text-align: center; } .center { text-align: center; } .note { color: maroon; } java-algebra-system-2.7.200/images/000077500000000000000000000000001445075545500170035ustar00rootroot00000000000000java-algebra-system-2.7.200/images/PackageOverview.png000066400000000000000000000642731445075545500226070ustar00rootroot00000000000000‰PNG  IHDRR¦ ¾ç+ pHYsëëqÍ• IDATxœìÝy\gº7ü«fDƒâ–íc€`rŽQCDÔ@Œ:¸D£QrÄñäyÑ OòÎxÔD3’19Oœ‰KoÆè‰†¨q4NIKd‚Ù5'æILPYYDºëýã–²ìênºé¥îªú}?~’¦ª»¶¾«®¾®º«Ê  J/ChÚ†æÐÍOéð¥@“ÒK aHQz À·Ðü@÷퀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎 쀎ð˜Yáü9Ÿ:§ù½Í¯w4ß0t Ù¢؆¡E{ #xººÏqõxkÐÛ¾Ñüœ¤·†¡'Èö@Gö@Gö@Gö@Gö@Gö@GöÔÁ`H1¸Þ£ºwŸê“é))Ùêš2¸„‡è³ö Ú†ëöÀ&O^¥º)€>!ìi™€k“AQhÀ!9•tôhy\\fppjBÂÒ¢¢2é¨#GÊ—§ÆÇg=Z.%/õØ+þH‡wu™×­{;6v~@À”~ýfÌž½î§ŸjÙ¨úú¦ŒŒW£¢ÒÆ©C†ÌËÎÞÞÖÖ.Ÿš½·‰³gÇ^”FF¦''?ïÌ2;öÙü{PPjxøô)SVÿýϦlo:òù’à êjV‹œ:hÐœŠŠ‹Ž×Å^küì³óii/†…M‹ˆ˜±xqNCCs› 4Bß ºùO0±Ÿ~šà/~þþ~¥¥ÛØ(“i«ŸŸŸtT÷—e>‹Ó±9D>|ýú§­¾úÉ“`£¦M{ÈjÔ3ÏÌ”OÍÞÛd-Ê$]ìÇÛã2—•íבùÅ/v0e{Ó‘Ï×ÁF¾ùïÖ÷¢i²æ§Æ(N­°0'0ÐòÅ»z\y«`C‚‚ŒÒ9ΟŸ¢Ç†¡KÈöóúëïuu™ßc{{qAÁ&³Ù²eK¾8Êb±¤§'ÕÔÖÔΘ1ÁýÙíÞý!åå½ÜÙyüË/wÑ©SçÙ¨’’ÓDtúôÛÛ·o8pB>{o³{ˆè¹çfµ¶ËÍ]Ýã²½öÚ{f³å—¿œ^__TX˜CDŸ|rÖÁ”“Î×ÁFÕµ@æÀóçoáÀßüË¿ÜÓãº0òÖ˜œœøÝwû®];Æâqqñî¯#¨ž·ç+âLºßÑѳëê®Jß2xð€K— ˆ(22½¡¡¹ª*ذADTQqñ®»Qw`U#i±9üÚµöââ/Nž<÷ÑGŸŸ;W)Ž3fÙ™3Æ š>}ܤIc¦O*_o³šûóÛoß½÷ÞX{K(•~åJsmíös¼ ާ#Ÿ¯ƒÜýù”›/´½#Èš©°²©ùûû™Í–¸¸_½Ç™u±×+*Þ5*†ˆšš®õë7Ã`0X,Kf–Ò½Å4Ý0t Ùžbäçêë›Ø‹¦¦V"2d ûsøðAò‹¿W:::™]IÉW±±óçÌY¿eK>;âˆöí[Ÿ0êÂ…š;‹žzê7C‡Î?x°T>'ß&:t “Ë|õj+EF†;³"¦#Ÿ¯ƒ ªkŒÙl üŸÿùñðá¿;³.Œ¼5²ˆND¡ÒÕÍCØSLDDÕÕO'tvg£ '¢ªªËìÏ jäoiic/ª«ë™ÝŠ[[²²æ9òZUÕmõŸøø‘gÏî.+Û±vmFZÚØ––¶•+·Ê§àäÛD!!N.s¿~aDtéRƒ3+â`:òù:ØÈ ºȬ^=ÿ÷¿_AD›6ý·3ëÂÈ[£ô\ è žbÆ¿ˆ^yeO[[ûþý&ƒ!%>>“JJŠ'¢U«vÔÖ6ÖÖ6fgo—~‰mÛ ®_¿QYy1+ëMgfÇ:¼-X0yÒ¤1û÷›Ø@³ÙBDAA©CJUU͆ K6nÌ$¢æækò)8xë/pùrCcc‹ø~iŸÇËãÞ{c?ÿüÛ¿þõó×…‘¶ Ð;åzÓ茬+݉[­º/æå½ÌF•—ÿAúSÔh èþ²L‚`Z¸pŠôSb‡4{=Ùë©S”~Šýœ¯¬ÌÓܹÉV­bÉ’iò)8x›X/š5+Éf¿>ÇËüÉ'Û­6ÅæÍÿËæ”_÷7²¾:ìÙêÉ©º(}]P°‰ˆ’’â{\y«pfˆ^†.áb’“Ü”˜xg` 166:7wµx47nôáÛãâFãâF°Î¢ÜÜÕ©¡}ú'''o±9}AˆÈÐÝ—aïÞµ3gN êß¿ï³Ï¦—–n#¢œœw‰hÏž5YYsbb¢üýý¢£û/_>û­·lÜÅÁÛÞx㹘˜¨  css›Í…q¼Ì<’PX˜?Òh ˆ‰‰Z¿þé_ýj¡Í);¹îÎldP] ”š3gâÃÇ—•}ýñǧ¯ €ôäô[]é¼Çl¶œ?_•°444¸µõ˜æ¨V:é°çÛæGh:iº„lO›/ÎIHXJDqq#•^Ð#´@àîÉ©MÕFcÀèÑÃ{,xZ p EN_ñy• œ¢“ZšŸ«tÒ0t ENЄ=Є=МÛóñä ðIÛ;š_¯i»aè²=Є=_ÁoFžiþÛÑü z ¶›¡È©röŠWÞûZ­æ¨€ž ÛS-ƒA6ò9úlpv <wiQéæ[A¤}àd{êa/½„›‘ÀÛñÀ^XõF¸½uWÁz½4ÝÀ›í©–~’›•Uý¬>x²=’&@,ôA$M¿¤Kb5Ö«ó•Î9ô žz°ã¾ƒ,ÇfdògbŒ—âUdµŠ|~à"„=5óýA_P}_lDyÜ€°§ZÒ˜çÕH ®öòNo‡a拾 {ê¤H̳7#Ÿr³ o6çÛcÉÀ„=•óÙqßñŒ~@%öTHñ~>ë>jsÖnÀu{jã³ò¦«³ðêÂèá4àÈöT uE×!ÛSÇf¡½>,lõq‹p²=õðqy@‹öT1O çù ·öTÂgYà™ž×<çöTÇ}ÂF· Ûã zRˆyà„=5À£<EN¾!ÚÙ„{R@o!Ûãzox¯ó¼a{ˆy  .BØãŽæŽá§ôº´ð‡ÿò&ŸKàd{Ctq@Ü8ÈŒÀ{œÁAÀ›öxÂy“Qðéê6ñ³$À=„=n¨%æñ[ \‡°Çͼa⣅ÀyèØ.BØã "€7!ìq™ŠG`3€p¹ºÒØÁšý©^/`£€+ö…Þ›:ÄmeBG!9•ƒ˜çqÜMD<·Rž—Ísíq1Ï}úØ]À}{ Áa@ç“ÒK aHQz |EN% ¼éq¸€œƒ°§(Ä<ßBØó91AÌó$|`žoáˆì=øN@—ÒÌ)=U/<è²=% lx :¶@Oö@GPäô!Í$yªè•c0p½x d{Þ‡‚›/!Ô€C{>ÈÀ„=/"Ÿïa›€ ž7iæŠu75¶9È K‹OàøëcØà`²=¯A… €?¿‹½AÛåMU\ÀÀà2à ~ÛäÃýÙžh;æ©…Ápó‹ÀQ€>ÜOö¼ 1OAØø` º´xr pWOWWÏìŽlÏ£PÞä îL 2{Þ˜À%„=ÏAJÁ3|;@D{ž„›ƒpßÜ]Zöº©éÚ¡CeÍÍm%%¿'¢§Ÿ~õØ±ÏØ¨‹ë·m;xýú]»^t¦ü@¶×+ˆyª#ø¦€[¯¿þ^W—ùý÷7¶·l2›-[¶ä‹£,KzzRMMaMMáŒÜŸÝîÝQ^ÞËÇ¿ür:už*)9MD§O¿ÝÑñ·}ûÖÑ'\š¸XÒoåMÙž{p$·••}MDO>¹Q"Æ!öbûö磣ûÑï~—eUí…êê×®µ±fÍ®>úœˆÄJæèÑÃΜ©˜5kÝôéã&MÓÔt$<<ÔÍÙñaÏu8¥§jìëÃïàICC³Õúú&ö¢©©•ˆ† Èþ>|üã‚  "êèètfv%%_Í›·¡±±E>jß¾õ‹m:w®rç΢;‹úöíóÎ;kžx"Ùæt\/'PätÊ›ª†Ÿ,À¥ˆˆ0"ª«;Ä ƒ‚`êì<ÎF NDUU—ÙŸ.ÔÈ?ÞÒÒÆ^TW×;3»+¶66¶deÍ9r䵪ª|鍸ø‘gÏî.+Û±vmFZÚØ––¶•+·Ú›Ž«óåÂ^o!怇Œ½òÊž¶¶öýûMCJ||&•”OD«Ví¨­m¬­mÌÎÞ.ý`¿~aD´m[Áõë7*+/fe½éÌì**.Ñ‚“'M³¿‰ 4›-D”j0¤TUÕlذdãÆL"jn¾&Ÿ‚ãùúûûÑåË 6Jå à<¢[ÿôLÕAÕ p«šÄ'Nle¡B”—÷2U^þ‡€q¸ÑÐ}è6 ‚iáÂ)ÒO¥cí½ž:õAé§XBYY™'¦¹s­ë™K–L“OÁñ|‡ »Y‰5+ÉÁbÜüçó]Ù^¯ ÕÏINN&ßÌÐl¶œ?_•°444¸µõ˜ofêñJv_íèÉé"(ÑÃãÄ•èÃâÅ9ùù%D7Réeáž”êòŽ£3¸­¢¢Úh =z¸Ír¥¡ÈÙkbü‡=õ6U×iAÕ|^ä䊜üRðøÈÕîáó6 àAèÉérÍã?¥BسD Ãï½B‘Óts¯âétº‚l¯'ˆyš‡´@OölÁqPØ<‡| íÍ&n9ePÞÔ|¿ 4åÒY›LÿHIÉVf©ØƒgQÐ"ýÛÓMÌS»É“W)½ Aú{ìg;žs宎WpÖ¶ h6£ƒ"§XªÒJÍêèÑò¸¸ÌààÔ„„¥EEeÒQGŽ”'&. NÏ5S`3*((ŒLON~^:kq¬òÆÎ¬¬7#"fDE¥/[öŸÍÍלÚd®B¨Ð0AóˆnþS[Knÿ}úin@€¿øõùûû•–nc£L¦­~~~ÒQÝ_±IÌ¢¤“’‘_¿þi«3yòlÔ´iYzæ™™ò©9˜‚t9{l¬tÖ²VzsÈ‚S¤Ã32Ro›¿kõ6pHëÙžV2<Ñ믿×Õe~ÿýííÅ›ÌfË–-ùâ(‹Å’žžTSSXSS8cÆ÷g·{÷‡D”—÷rgçñ/¿ÜED§Ng£JJNÑéÓowtümß¾uDtàÀ —¦À<÷ܬÖÖc¹¹«¥­¢¯8¼±±¥¢â½ë×?ú?ÿç9":rä¶ŒÖ+4ׄtNÓÏÛSû Yn=Î$‹Žž]WwUú®Áƒ\ºT@D‘‘é ÍUUùÆ "¢ŠŠ‹wݵˆºC+JCˆ|ˆÍá×®µqòä¹>úüܹJqÔ˜1ËΜ©6lÐôéã&M3}ú¸ððP›ëao lFß~ûî½÷ÆÊgmµìÏŠŠ÷FŠ!¢¶¶öÐÐiƒÁbùX²è)Ý[Ì_7žÀ EúèÒ¢¡ÃVCC³Õúú&ö¢©©•ˆ† Èþ>|üã‚  "êèètfv%%_Í›·¡±±E>jß¾õ‹m:w®rç΢;‹úöíóÎ;kžx"Ùù)0C‡tfI˜#³}ú‘–´€wh·È©ÑÚTDDÕÕOhuvg£ '¢ªªËìÏ jäoiic/ª«ë™ÝŠ[[²²æ9òZUU¾tT|üȳgw—•íX»6#-mlKKÛÊ•[]šèÌ’0Ò“—^‡;Sh‘FÞÚË›ö½òÊž¶¶öýûMCJ||&•”OD«Ví¨­m¬­mÌÎÞ.ý`¿~aD´m[Áõë7*+/fe½éÌì**.Ñ‚“'M³¿‰ 4›-D”j0¤TUÕlذdãÆL"²Ù¯ÒÁ{‘Œuu¹|¹ÁA¦à2…»ÔxƒØOíkg«'ç‰[Å.šL^ÞËlTyù¤<Æ€î¯Ø$¦… oëd”޵÷zêÔ¥Ÿb eeež ˜æÎµ®g.Y2Í¥)Hß&ÿ ;CID³f%9ÛÕãß»fÚtÓh¶Çh+Ïc’“Ü”˜xg` 166:7wµÏÆ}øð游Ƹ¸……9Òææ®ÎÈHˆíÓ'899±¸x‹Íé ‚@D†îtyïÞµ3gN êß¿ï³Ï¦—–n#¢œœw‰hÏž5YYsbb¢üýý¢£û/_>û­·lÜWÅÁ{ãçbb¢‚‚ŒÍÍmÎoÓbÐ9ÍõäÔRyÓVON¯2›-çÏW%$, nm=æ›™z’g{rÞœ&úshж²=-Å<%,^œ“°”ˆââF*½,Ü@ÇmÑÖ ‚€Ûoº£¢¢Úh =z¸Ír¥~¡9hˆæŠœZâó"§êy£È Ú¢­"'€W¡Î  ~š(r¢Óx€V Ûpâ€Ê©ÿÜž†{oâÛkÞh (*h‚ʳ= Ç<ð5‡=ÍÇMÐD— ‡¯ë|0/eg £Ú°‡_Ü®r¼Å” ?*½½€Á ¾e"RkØÓ|yÓƒœù} ø6TKoñ6@ Zj>·GÜ%gómµÑ”Ú†6çk0 ®€W©0ìá°è˜ƒ³hìŸÕ@¥°:¡|‘8‡Ž-*§¶°‡ò¦=,ObÛǪfhZ”=^ÛüÖTü@µTu¹:bžMÎT2m¾ÙÇÛP-'ðz„v fªêÒÂ1èDÇôâ’¯=[ÔLUaÑùñÚÁ×ñ–á3æ©ôP-•„=dxä¹+¾ùÙ’â©îûU×Ò€„JÂ!-ÑÀ¦@µ|N aOŸGFyMR ½ x|†Iq¥T—ð1*]lãþ>ÏHy•ƒK¶µÝÑ_u¿o¬.5à;ìé*æI/¼“ÒüŠósM!耊œ¤éC¯{fªŽƒÕQûI>”:ԃ㰧êã 3ð,›TBÔ­t‰×"§æË›6‹™Ú>uçJ༆=‘f€թ;ézé9ÚI©1òáÎÔjÃe‘ScG3‡²!xaO3åM¾Ý¤¢“| œ=A1O?=3½GuwäÑÌÃ%t€¿lQãáÅLOÁ¯á,ì‰R—žx.QW©S]K  K\öäTÅÃ^·LBÏLÏQËÝ¿ðu¨7ÙžŠ~&£˜é{*jÀ7>º´¨¢' *™ŠPEÛ`T×@—8Èö8?®¡g¦²Tt%Ú€(öxŽy(fò¥Np›ÒaOÄÏá ÑŽ7Ò„ÿȇR'ßíÉÉUñÊÁÇ虩8µÜ®“çe"R2Ûã§¼‰ôNTt’Ô•èEN¥Žè«¢^ÜuÅf]R¨È©à= ­*¢–R'pL‰°§ÔË^´Óùó]Õ…ÿ¯ Oàà[€Â;§*8u§1($€¸¼''ã½Cr; PÅ7ˆð ÀŽÃžÇ¡˜©œŸäCàXwONÁ¤äRX1¤xrj8i‡1ø¦§l4FzëÞ c ¯ö@µ8/u—ö@ÍTù¸]0]BØ•ãöÜ-·  o{ !|æUˆ~â?K{ Mˆ4`Âh'½(qgjnð«Ø‹s(Kcÿ.Ä…Q|Iô Ùž7á§½²ø 0hŠBØ}P<Øðƒô‡Ë§«k€g½&·=±@÷z~ xƒUòñ÷H#'€”ƒ°ç¼võFŒ|ÊÆ0€þàÜž—qÒDø:ô ÙžBPãò1NNò±ÅÀ· „=ßÂñNAœÔÑ…"§o±š'_ÃW Wn…=ƒ!ÅàzOýÞ}ÊgL¦¤¤d+½àœ<™¿~”ƒ"§µÉ“WykÒ6‹ll _>#~ Øæº¤@Øtui¼U¨c‡Z{Áp,ö Å72'Tè’"çÑ£åqq™ÁÁ© K‹ŠÊ¤£Ž)OL\œŸyôh¹t”¼ti¯˜)ÞÕe^·îíØØùSúõ›1{öºŸ~ªe£êë›22^ŠJ7§2/;{{[[»Õ¤8a0¤ÌŸ¿A2þƒ!åÀ=®Ë±cŸ=ðÀ¿¥†‡OŸ2eõ÷ßÿÌ–M¾ß|óã/~ñaaÓÂçϞ½îŸÿ¬¶Z—‚‚ÒÈÈôääçå+kµæ7_8¸?j_^%°‚‰ýûôÓÜ€q¬¿¿_ié66ÊdÚêçç'us ‚ILàÄéØ"¾~ýÓVË3yòlÔ´iYzæ™™V“jkûkß¾}úô nm=&¦ÖÖc!!Aaa!mmu¼.ee;Äåg~ñ‹‡åi¨ ˜*+óúõ “8°ß… ïK×…Mê±ÇÆÞZ¶[VáÖŸâ+Ò7ôøfð·3¾e…Xg{¯¿þ^W—ùý÷7¶·l2›-[¶ä‹£,KzzRMMaMMáŒÈm»wHDyy/wvÿòË]DtêÔy6ª¤ä4>ývGÇßöí[GDb' š5+©­­ý/ù”ˆþûõë7ÒÓ“BB‚¯Ëk¯½g6[~ùËéõõE……9DôÉ'gIR€£Ú¦Mÿ}õjkZÚØK— .]*HKwuãÆ=ÒÅxî¹Y­­ÇrsWÛ]Ï{R‚íbú>ø†ï·0j› é~Þ^÷á>:zv]ÝUé;péREF¦744WUå6ˆˆ**.Þu×"ê¬$(M˜äCl¿v­½¸ø‹“'Ï}ôÑççÎUŠ£ÆŒYvæLŰaƒ¦O7iÒ˜éÓÇ…‡‡ÊWàÈ‘ò™3×Ì›|ðàoæÎ}©°ð“C‡^MOOr¼.QQéW®4×Ö~0p`?Ç‹7x𜚚Æï¾Ûw÷ÝC‰èûï¾çžŒ;xñ øæo¿}÷Þ{coŸJÊÍöžã£ž½Ð§àYUœÐP‚u—–††f«!õõMìESS+ 2ý9|ø ùäA0 DÔÑÑéÌìKJ¾š7oCcc‹|Ô¾}ë-Útî\åÎE;wõíÛçwÖ<ñD²ÕÛÒÒþuÀ€ð?"zå•=mmíû÷› †”øøL6*))žˆV­ÚQ[ÛX[Û˜½]úAH¶m+¸~ýFeåŬ¬7™}EÅE"Z°`ò¤Icöï7±f³…ˆ‚‚R †”ªªš –lܘIDÍÍ×lNä©§¦Ѿ}ÅlRά˄ qDôÚkº~ýFAA©Á2räB6ŠõO¹|¹å S¦Ùn5jóæÿÅF±3—D4kV’ ˜¾ùfoXXˆôƒ¸xñ ãÞªÞí¤g¯Û'úºC©mˆïÀ·¬Ó”ääă7%&ÞhŒÎÍ]-ƳqãF>¼9.nD` 1.në)ÊÍ]‘‘Ú§Oprrbqñ²E"2tÿ¦Þ»wíÌ™BB‚ú÷ïûì³é¥¥Ûˆ('ç]"Ú³gMVÖœ˜˜(¿èèþË—Ï~ë-Û÷Oñóó{òÉÉD4wîD1;^—GI(,̉i4ÄÄD­_ÿô¯~u3Û{ãçbb¢‚‚ŒÍÍmD4zôð¿ÿý­™3'„†‡……Ì™3±¬l‹²Šq2"ùs6 €¦Y÷äô*³Ùrþ|UBÂÒÐÐàÖÖc>˜£blöäôâìì©qöÈ%ÎwµUûLţO`X¼8'!a)ÅÅôå|µ¯ç AN‘“|øâ|˧÷䬨¨6Fn¯\ nq|Ï3ÂÖ J=“_ €¯ø´È©#>.r:&?Žó°TÜBÕ@Óðà!]ÂýA` ¶ €F!ì銟®RðFeŠÌ@O|Ú¥†{¾ô‚o6 B€¯°·yχ3ÜðÚ1g`¨<ø²=s|§4$JÝ´ [À›íy“º~¶KûqXyÕµ"žåË$ €÷`ƒ›´ô|!<@# öd°÷à²?ð œÛÎØ|àƒƒ à d{À+?À ö€oŽ{~:~€ ¨’?p¨J=_BØuB'èô䕳wÃk[ðtuÐ$®ÂtÙ€¾á‡è Â躴€Fqõtu>¹úÌwM@Ø;¬êŸ8 š€°D„“| {º‡€z‚°v ª Z„°u u¸€tÙÀ-C  .^üлOyƒ»KbóN§Èÿ@[í@7›}[ ôy-A¶à.ò<·‚Kô¬†à¡¾ Èö@ûŽ-‹Ë NMHXZTT&uäHybâ²ààÔøøÌ£GË¥£ †Ãí÷1‘‘ïê2¯[÷vlìü€€)ýú͘={ÝO?Õ²QõõM¯FE¥S‡ ™—½½­­ÝÞÔ*‹‹Ë ²±`ß|óã/~ñaaÓÂçϞ½îŸÿ¬¶šB}}SPPjddúõë7Äׯ߈ŒLN½r¥ÙÁ¶ºí±½ò Ç2?$ j€*¹öO0±Ÿ~šà/6x¿ÒÒml”É´ÕÏÏO:ª{§0‰ œ8›CäÃׯÚj›<ù6jÚ´‡¬F=óÌL{S3oUbüýýÊÊv°±••yýú…I'2p`¿ Þ·Z’ùóSˆh×®ÅÉþ×½@DO?vk^·¶•l ;¹ñTÙhÜ믿×Õe~ÿýííÅ›ÌfË–-ùâ(‹Å’žžTSSXSS8cÆ÷g·{÷‡D”—÷rgçñ/¿ÜED§Ng£JJNÑéÓowtümß¾uDtàÀ {Óyì±±—.ÔÔΘ1Þl¶lÞü'6|Ó¦ÿ¾zµ5-mì¥K—.¤¥­«»ºqã«?óÌL"Ú¾½@Â^?ûlºÝE—ævòš§ƒä@Uð¼=P W¯Ý©Otô캺«Ò1ƒ¸t©€ˆ"#Óš«ªò‡ DDïºkuŸ«“÷Š´×OÒjøµkíÅÅ_œ?w®R5f̲3g*† 4}ú¸I“ÆLŸ>.<<ÔÖŠ¦Ñ?æ~k©"#Ãë니hðà955ß}·ïÑ÷ßÿ|Ï=wÜyñâAé’‚0jÔS?þxùøñßM™òàñã_=úèÿ¾ÿþ;Ïœù£dN)ÝÛÊNÀ³wp°ùƒgþ@íJˆ ‡Õ¿ž44XŸÊª¯ob/ššZ‰hÈìOfd³½9‹ŽŽNg³¤ä«ØØùsæ¬ß²%ŸÅ<Ѿ}ëF]¸P³sgÑSOýfèÐù–Ú›ÎС·-USÓ5ög]]Ãþ9òé‰ òe3ˆhÛ¶ƒâ¥z"gB’?P3„=иˆˆ0"ª«;$žÓêì<ÎF NDUU—ÙŸ.ÔÈ?ÞÒÒÆ^TW×;3»+¶66¶deÍ9r䵪ª|鍸ø‘gÏî.+Û±vmFZÚØ––¶•+·Ú›Î÷ßÿÌ^°1lQ‰hàÀ"ª¬¼Èþd/ ê/ŸÂÒ¥ûûû>üéñã_ýå/Ÿ†……dd¤:³ .°#Ñíø†°7~ü}DôÊ+{ÚÚÚ÷ï7 )ññ™lTRR<­Zµ£¶¶±¶¶1;{»ôƒ¬çȶmׯߨ¬¼˜•õ¦3³«¨¸HD Lž4iÌþý&6Ðl¶QPPªÁRUU³aÃ’3‰¨¹ùš½é¬Xñfuuý•+Í/¼KD'ÞφO™ò ­\¹õò冚šÆçŸßFD6ÏJõøãã,ËO¼d±X/NíÛ·3«à|&Ý?à“Â]jzÁ™®†Ý¹Ý‰[Å.šL^ÞËlTyù¤<ÅΓlìÂ…S¤Ÿ 2JÇÚ{=uêƒÒO±,­²2OLsç&[í}K–L³7µÀ@£ø¶À@ã—_îbc¿ùfoXXˆt"ƒ¸xñ Í¾¦|ðªø¶üãÖ½F½Ô!Ý>oÈö@UÄÂé4"99ñàÁM‰‰wcc£ssW‹ñlܸчoŽ‹hŒ‹QX˜#ý`nîꌌԈˆÐ>}‚““‹‹·Øœ¾ Ddè^ž½{×Μ9!$$¨ÿ¾Ï>›^ZºˆrrÞ%¢={Öde͉‰‰ò÷÷‹Žî¿|ùì·ÞZeo±ûÏøø‘Ƹûرÿ|ðÁ{ØðÑ£‡ÿýïoÍœ9!448,,dΜ‰ee;î¸#ÒæDfÌÏF_bâNn1wÙË‘üГTB~Ä”ß@RzoŸÜ9Ål¶œ?_•°444¸µõ˜G¦é©;|vvvýßÿûÓ¤IÙ Ío¿ýÿ².·Ï)åæ ¯|qJÀÍÉ@ ä—‘Ùå[‹çäç—Q\ÜHæÀÀGÙ‹Áƒ<õÔTÅ–ƒ}Yöîö‰>‡"'ðM^³w TâZQQm4ÜÿÊ•Jéß¿o@€ÿ¿üË=EE¿íÓ'Xá¥+ŸV_*Ÿàs(r¯œ)ŽÉ¯›öm‘SÝ|Sä´;w[ч#ð>d{À%›7Çr‡KÕA·PÎígÐB?l>ÕVüß;xÂpæ¶Þ˜=øpdÔ›Ý^œo®À¹=àƒ´SŸ;?öQ"ë®8ç^†l”†ª&HÙ¼S„kÀmèÒŠ’Æ<$j8&ºŠÛ-&ïÇ$Þ 9=¸ENPˆ~’<'¯;„©·Íp§Õ²= a|N½¯^À™*ϲ?xÞ¤ÜÆ<†çMç8·¾…ÔÜaïVg¸æœ†°¾¢«$±÷3ý2Üäø‚?âµiquç ñ=úƒ°>$¼ÁÁ}®ì@ONð>}Æ<›™‡½4ÜáàqðØÎ ƒ°Þ'z¼µ¦f8s´ÅÙãl60vÁ¶6tCØï°:Ðè'àY‘¯µ>·ƒ/98ó‡à8·ž‡#‹ó[}[¼ ·ú[íçà×4Ùz 7O‡×§ý°ñu Ùxˆ>û­8ÐãqÌõ%<äº!Û·É5ã ܲ×ítٸϊó[ÛJA.øÃ W­C؃ÞÒá]W@cì¥}èö¢i{à:<Ð œùÓ"„=p´;ŽÎÀVR ×<àKÔ ti§É»æã@š„»½hÂ8AÜÛ¹( @pÁŸFá1³ÐôÕtjÂÐëSÚˆ‘ 7Ù؇ òDVÉŸôúw6gp³•Ð¥ì@À³·# Û‹z ì ®OèÇÕl®ž®îKœ=Éa$ð\eóöªHþ8†°ÝPÕèÇ÷¹ΠK b€'èöqʪ‚°§oòSØoÜÄv"ìG¼B‘SÇáx•ƒç<€ríé’ôJ#ì“ '{úƒ$@= †ƒëôîS:"§žàúÐ=„=}@ÀÐA·—Æ;ENW5óuôhy\\fppjBÂÒ¢¢2é¨#GÊ—§ÆÇg=Z.%/]Ú+fJ‡wu™×­{;6v~@À”~ýfÌž½î§ŸjÙ¨úú¦ŒŒW£¢ÒÆ©C†ÌËÎÞÞÖÖnoj‡•ÅÅeY/˜“ážÀ iHò8'0èÙ­oßÄþ_^þÍĉ+»ºÌìO¿?~sâÄû‰èĉ3S¦¬¶X,â(³ÙBÝÙ‹dÒLN>D>ü¥—þ˜“ó®tìäÉ””üžˆüWÇŽ}&õÌ33wízÑæÔŒÆ€ÎÎ.qÁJK·=üp¼S3íÙžv!Éã.ä‰×_¯«ËüþûÛÛ‹ 6™Í–-[òÅQ‹%==©¦¦°¦¦pÆŒ îÏn÷î‰(/ïåÎÎã_~¹‹ˆN:ÏF•”œ&¢Ó§ßîèøÛ¾}ëˆèÀö¦óØcc/]*¨©)œ1c¼ÙlÙ¼ùO½˜íin  8Y¶=»®îªô-ƒ¸t©€ˆ"#Óš«ªò‡ DDïºk¹—íѵkíÅÅ_œ?w®R5f̲3g*† 4}ú¸I“ÆLŸ>.<<ÔÖ¤Ñ?æ~k©"#Ãë닜šgÙž¶XÅ9ƒ“v _²°0…•.EþÇÅQ]]%þþ~DÔÕe6§ÒíaÏbùØ`0QGGgPP*õöJJ¾š7oCcc‹ô lÔ×_ÿ°hÑ&‰¨oß>ï¼³æ‰'’mNÍj©Äeîy"œ…=95gò¸Åî€;ED„Q]Ý!A0±,~Ñ€áDTUu™ýyáBüã--mìEuu½3³[±bkccKVÖœ#G^«ªÊ—ŽŠyöìî²²k×f¤¥mii[¹r«½é|ÿýÏìëÃÕÕ‰ðaO¬©8¼plüøûˆè•Wö´µµïßo2Râã3Ù¨¤¤x"ZµjGmmcmmcvövéûõ #¢mÛ ®_¿QYy1+ëMgfWQq‘ˆ,˜¼9.nD` 1.nDaaŽôƒ¹¹«32R#"Bûô NNN,.Þbsú‚ ‘¡ûø°wïÚ™3'„„õïß÷ÙgÓKK·»¤aÏž5YYsbb¢üýý¢£û/_>û­·VÙ[ìcÇþ3>~d` ñî>vì?|ð6Ü¥‰ð]ZÔ §ñÔ×í陬K‹W™Í–óç«–††·¶óÈ4íõuúó)7_ðÑþ‘í©¼g’<è¶xqNBÂR"Š‹©ô²p ÷äT<<ª¨¨6FÎy¥QA(rªŠ4ìá‹S9õÌ·EN¡È ½Ç ªš½…"'ßäY€œ{Ü^û¬íÀífP³žÎíq~ðÕjäC×Á¹==ãü(êK|´99ƒ ò<‹·#â€Òœ{\õA²õ4aÕCÀó8ÞbžŽ¡‚ÀuSôn<²=> ª  aØ£y‚°§4$y>€ZtCØS’<ßÂåꊒÆ9Ä<ïC¶çs,ÃÃåçJ@¶ç[bU=»”€lÏWç8€°ç}è« À „=/C_Mž ìy ’<þ ìy’<.!ìy’<Ž!ìygpÝž§±P'ˆyr:Ûãóþ¹¾¼Î^“?A €WÈöœ&±ÃmqA:÷ ‚ãÔ‡r)é¶B_Mþ¡õÚƒæ :¦Î§«û˜U}5AíðlwÐ1ôät’<5CØsbžJé¹Va…Ͼi>„°×+xê„°ç"<Ð${ÝÐàAsö\Chº¹‚^áº=Ðïf{C  .v(èݧzÇ—óà* Èö5OÐÞ ˜~â †ƒëÝý{÷©Þ9qâ̸qÏ…„¤……MKK{ÑÝ…±ºÙ€Fõ&ì=Z—œš°´¨¨L:êÈ‘òÄÄeÁÁ©ññ™G–KGÉ÷@{û¤txW—yݺ·ccçLé×oÆìÙë~ú©–ª¯oÊÈx5**Ýhœ:dȼììímmí6¸¨¨ì¾û–„„¤¥¦¾PUU#ŸïÑ£åññ™ÁÁ©‰‰Ë>üð” Û@9ÿöo¿ýì³óíí×®µ‡‡‡zf¢~ uNß“³;ý*/ÿfâÄ•]]fö§¿¿ßÇ¿9qâýDtâÄ™)SV[,q”Ùl¡î3gò³höΫI‡¿ôÒsrÞ•Ž<ù’’ßÑãÿêØ±Ï¤£žyfæ®]Ö¿yOž<—’’Í–„ˆî¹'ö»ï~²Z*qQÙk“ië#$H(¥{#àü‡ªÈZ¯‹ŸN!¾ÏûúùM¡ª*?&&ª½½#,,Äê 6VAþC“µji¨C;Ms9Û{ýõ÷ººÌï¿¿±½½¸ `“ÙlÙ²%_e±XÒÓ“jj kj g̘àþòíÞý!åå½ÜÙyüË/wÑ©SçÙ¨’’ÓDtúôÛÛ·o8pÂæ›Í–9s&ÖÕºt©`Ô¨;äï—9==Él¶lÞü'÷—ø¤®Z…ƒù )ì7ëðá ŒÆ©,æ9Xkblc=!Ò*à!ó-r9Û‹Žž]WwUú–Áƒ\ºT@D‘‘é ÍUUùÆ "¢ŠŠ‹wݵˆÜËöˆèÚµöââ/Nž<÷ÑGŸŸ;W)Ž3fÙ™3Æ š>}ܤIc¦Og³Î•~åJó?üyĈÁDôý÷?ßsO†ÕR]¸ð~ll4UV^¼óÎE„_¹R$Y ”î€_Áª¢þZ…ƒùZ…CA09^…îϧˆè9ÃÃÝø@‹\Îöš­†Ô×7±MM­D4dÈ@öçðáƒä£lGG§3³+)ù*6vþœ9ë·lÉg1O´oßú„„Q.ÔìÜYôÔS¿:tþÁƒ¥ò)\½ÚJD,ªÑÈ‘6²½˜˜¨îeLDÍÍלY6PÕÕ*ƒ™ØÌåUp5Œ!ùMp9ìED„Q]Ý!¶³ ‚©³ó85`@8UU]f^¸P#ÿxKK{Q]]ïÌìV¬ØÚØØ’•5çȑתªò¥£âãGž=»»¬lÇÚµiic[ZÚV®Ü*ŸB¿~aÒ…©¬¼(Ï?ÿYÍ^°[О²²¯‰èÉ'7§ÎûIâ{±}ûóÑÑý££ûÿîwYîÏ®ºú@kë±ààÀ5kvef¾FDb%sôèaD4kÖºçŸßæïïßÔt¤¡á°›³sklÆ3yÙ“ü@õ\{ãÇßGD¯¼²§­­}ÿ~“ÁŸÉF%%ÅѪU;jkkk³³·K?ÈÂ϶mׯߨ¬¼˜•õ¦3³«¨¸HD Lž4iÌþý&6•n‚‚R †”ªªš –lܘIv²´‡Ž'¢^Ƚr¥¹ºº~ùòßËß³bÅ›?ÿ\×ÐÐü ¹âŠ€ö¨®VáÒ|Yù¤o½vp[N?ЗÃÞ¯ý”¿¿ßŽ…¡¡Óž|r#­_ÿolÔš5‹üþû As šó׿~.ýà´iÑK/ý±OŸÇî¼sQIÉWÒ±ö:Lœ˜@DÉÉχ…M{ñÅ?°<Œ¥n3gN ¢E‹6¥>üpÍ›—"ŸÚ¯½Èß߯°ð“¨¨ô¡CçµµÝÏåĉ3±±ó##Ó Jü׬YäêfUP]­Â¥ù:³ 68YêDð­p9ì%''<¸)1ñÎÀ@clltnîê… §°QãÆ>|xs\܈À@c\܈ÂÂéssWgd¤FD„ö霜œX\¼ÅæôÙ[C÷¾´wïÚ™3'„„õïß÷ÙgÓKK·ë&°gÏš¬¬911Qþþ~ÑÑý—/ŸýÖ[«äLJŠÏÏßx÷ÝCCB‚æÏO9tèU" 2JßóÁ9 £Øb>¼ù¡‡F»ºY@TW«pi¾ŽWÁ3ì?õp¹'§W™Í–óç«–††·¶s‚‚ >ÚÕe.*úí´iµ·wìÝûו+·Þ{oì·ß¾ÛóçôäT)Yë--=3eÊjñM"ÊË{™ýn;uêü#¬;y]ÔÝsä©§~óç?—ˆŸ 2Þ¸ÑI¶úyJ_?úèÿ>~üVUcÀ€ð††æÊʼ‘#ïx≗ n«j.Y2mÏž5VSp~¾=®B÷6IéÞ&n7æ[›û¨ _7'[¼8'!a)ÅÅôÈ «…¦§¯ |4<|:+%ef>î‘郺¨®Váä|Yϳw’?à_ÙÞØ±ÿÏ™3£Gÿãõ¯ÿz¯G¦ÙÜ|mýú?>ü÷êêzAbb¢žzjjNβ€g'lO¥T^«ð ¯6f\çjÀWØãžJù¶õ.\ø›üü"zè¡Ñ§NýÁsì _†=ïÍÀ xº:€gTTT£G·Y®Ôùí=Å?ü€{žñùçÿ¥ô"ðÁênŸÒ×~À„=ðyò‡ÎŸÀ§Ãž¯žœ šb³ò  ¾.`m²y;!‚zêÉIh—ÝP–Q4]xhÏx¶-(Á‰"§Ç›£÷.îqp˜ÃNÀ3ôy_q"Ûóð ½ye3¿î±_é >›øÙ p©øœ¶Âž½éÛ„] 'ÛL¯Œ§Ê®†pµp?ð!ßvi±·ßzõ'¹½sé s.Ý@Òƒ±ª×­]ÃÍO5ÒÍu{6/¡¯4ïMV¤ö¶›¼€Oø0ìI¯T•¿6<ܲٔåÓÄþr^ Êž=ŸÍ¦¦¶ëüÀË|Uät¦{¤¡K³:-ýc…5«òš—N2y*,Ù›‚öš7®ó¯ñùåꊤ_bB à€g/#³*i°,¶K—Pyžœüw á©~à.Ÿ„=稷›2v°ÇK1ÏÍ÷8¦¥Ú¦3ä§ý°Gƒë¼öœ9šx»‰j'ôHl$Vç–Ü */oXå‹Vm[ÛÍ>Á|Xät¼·{û¡—ˆ|Ð#O]ë¢HyCœ”æ›7‚¸G‹08ÓSÜãGA¥<Þ?ÞÉò†4JydîVÓt0wmPÑÕÜÆcÞ6”¯x?Û³yRÚÍwözI¤ìeH©pz¯¼a¯_Œ¼ë‡æñŸùñ³$r)«à§ç†¡?{ÝÐÃEÃR}¸Dø…'BÙS—öì@»×NBtÞ½SÎÞ¥~Ø2…°'#£fà7»c(x: ­H‹D[Œ IDATön‡R§XÝš‹†aD>›p©Ÿ ìÉ ò©šã‡€"Ÿ=~š†°g "ŸJ!æ¹ÊêøŽÖ.…à§Q{vàX :ˆy½†Öî®óÓƒ ÈÑÁ#ñô\欜ÇÕCÇOWw4ÔÞŠ8‡ëÙ]…©Èö\Íd¾„È× ~|CØs.ìUê̾‡È×;~¼ÂÓÕ]‡È§Ü=@)¸‡h²½^Á!À÷ó‡fïsCŠÁâ›O¹?5“é))Ùžš¯“z1S\·×[¸‹/©=æ©q™m²jö¤¡U·Mž¼J3EØs"Ÿo¨=æiŒÕÚhùü-í۰i3/Îihhf£äïw°¦EEe÷Ý·$$$-5õ…ªªù\ J##Ó““Ÿw°®Îô&AD7ÿiƒ¸:šY#NhfÃjc-¬hlu¼äÖWobÿ>ý47 À_<ûûû•–nc£L¦­~~~ÒQÝGi“˜r‰Ó±9D>|ýú§­Žù“'?ÀFM›öÕ¨gž™éxjìuPQú©ùóSä¡ã5ýä“íâÚÑ=÷ÄÊçÂÞðØcc¬…K3½ùÙžgàv!Þ€~äÙ³»ËÊv¬]›‘–6¶¥¥måÊ­ÎLSzòÌkÚ¯_IV°²ò¢üã!!ά…ó3!ìyvxw \¦^ˆ|Î?þ>"zå•=mmíû÷› †”øøL6*))žˆV­ÚQ[ÛX[Û˜½]úA*¶m+¸~ýFeåŬ¬7™]EÅE"Z°`ò¤Icöï7±f³…ˆ‚‚R †”ªªš –lܘIDÍÍ×ÜY5Ö åòå––9XÓ‡Ž'¢^Ƚr¥¹ºº~ùòß˧&íÝã`-œŸé-J÷nÒ"Íô?ô1 o1ý´iã×ÃúöHÖ“óĉ­ÒNŒD”—÷2U^þi"e4t¥M‚`Z¸pŠôSbwJ{ý-Ùë©S”~Š%”••y‚`š;׺ž¹dÉ4ÇS“¾–‹Ÿ³f%9^Ó“'wHGM˜çx.ÖÂù™¢'§7áb¾^À=¦µwïìIrrâÁƒ›ï 4ÆÆFçæ®ãÙ¸q£Þ7"0Ð7¢°0GúÁÜÜÕ©¡}ú'''o±9}AˆÈнå÷î];sæ„ þýû>ûlzié6"ÊÉy—ˆöìY“•5'&&Êßß/:ºÿòå³ßzË­Û¬¼ñÆs11QAAÆææ6Çkš”ŸŸ¿ñ†„ÍŸŸrèЫ$».BÊÁZ8?Szrz êuÎÓü¶ÒCƒ·¢ùïÔI²žœ^e6[Ο¯JHXÜÚzÌsìAíê2ývÚ´‡ÚÛ;öîýëÊ•[ï½7öÛoßõúìѓӋpë2gXeØJšîJX¼8'?¿„ˆââF*½,v †™3'|ðÁÉôôµÒá™™ûfðtuoBµÇ1ÄhfoGÌ` IÕûð aˆ|ˆyàqèÞ ž†°ÇU‡ Ä<ð tï¯ÁÓÕ¹¤ê-£ê…~ òw ÛãŒz àf›àqˆ|à{SÅY Ô6Á«Ð½< OWç•*ne‰îvàˆ|à9ÈöxÅÿ~ÎçRVáîà!{ã9ò¡¶éôáòœêO@ØãŸ‘1”"moh{Ð+{Üã-ò!æ²Ðg܃°§œD>«*8î8}¸< çùÀ {*¡x䳚)bp‘œ†°§ F>Ä<àÒ>pN€Ò  ¾ßßœœ£û! 1x&·5QƒMC¶ç <ÿÆtsÙ󀸰\°¡¿8¨"8 ENLJ/„!Å3ÓaE$Ä<àk¢Ò»ú¡Ñ‚-ÈöÀ 8|€Z(Þ縇l<„Ã0à ¿Û@Ùx‡1OÄó²Ï)”íáÇ(ENð(Mvì A‘tD¡lO,µ£Ú >„ltçö¼U n ÛAØA‘ÀûЇ €Èö@Gö@GPäô(>o ¡Æ¢Þl¸¤ÆP j€°:‚"§Gqu^•â³P ZltÙxŸù:og‹ÑiK9Èö|Ž·0¬'xº:芜àQèØåŸE`=A‘tD¡°g0ÜüDCŠÁõ€½ûTï¸3¯'ÎŒ÷\HHZXØ´´´=;qW¡È ÞõoÿöÛ jØëððPeaO­•œAùé§Z"ªªÊ‰‰joïPzq‚>\ÜÀ¹=o9z´<..3885!aiQQ™tÔ‘#剉˂ƒSãã3-—Ž’WüìեûºÌëÖ½;? `J¿~3fÏ^Ç‚ Õ×7ed¼•n4N2d^vöö¶¶v› \TTvß}KBBÒRS_¨ªª‘Ï÷èÑòøøÌààÔÄÄe~xÊ™e6RA ¢áÃSÃÂB¯>€·E~‡jì©›·VÇÄþ_^þÍĉ+»ºÌìO¿?~sâÄû‰èĉ3S¦¬¶X,â(³ÙBÝÙ‹ÒLN>D>ü¥—þ˜“ó®tìäÉ””üžˆüWÇŽ}&õÌ33wí²>Çvòä¹””l¶$DtÏ=±ß}÷“ÕR‰‹Ê^›L[y$Áñ2[…CA09^}"I?7m´ ýí`Z¸ÒíyÅ믿×Õe~ÿýííÅ›ÌfË–-ùâ(‹Å’žžTSSXSS8cÆ÷g·{÷‡D”—÷rgçñ/¿ÜED§Ng£JJNÑéÓowtümß¾uDtàÀ › l6[æÌ™XWwèÒ¥‚Q£î¿G\æôô$³Ù²yóŸz\01˜ ‚‰½öÆê«úp9ÿ¾]®2™þ‘’’­ôR€5d{ž û=»®îªô-ƒ¸t©€ˆ"#Óš«ªò‡ DDïºk¹—íѵkíÅÅ_œ?w®R5f̲3g*† 4}ú¸I“ÆLŸ>Îf¿’¨¨ô+WšøáÏ#F &¢ï¿ÿùž{2¬–êÂ…÷cc£‰¨²òâw.0 üÊ•¢—Ùj¬ãÕ'Òèoa5x›ÜÎöì5uo|Ê7l/›&[¸ª K‹W444[ ©¯ob/ššZ‰hÈìÏáÃÉ?.‚Á` ¢ŽŽNgfWRòÕ¼y[ä£öí[¿hѦsç*wî,Ú¹³¨oß>ï¼³æ‰'’­Þvõj+±¨FD#GÚÈöbb¢º—y057_ëÅ2;³úÎã3àÏPäôŠˆˆ0"ª«;ÄŠ{‚`êì<ÎF NDUU—ÙŸbç~©––6ö¢ººÞ™Ù­X±µ±±%+kΑ#¯UUåKGÅÇ<{vwYÙŽµk3ÒÒÆ¶´´­\¹U>…~ý¤ SYyQþžþ³š½`ýeØŠ¸ºÌά>h‰ºúv±©”FF¦''?Ï~óÍ¿øÅ„…M Ÿ>{ö:qGp/qQ‰( ÀÿÔ©?¸ºÌ=®¾ ˜´Ö6M®”Ù^ ¦Ù³!"±oÍš•ÄF=þø8º½Ÿ”ƒfcsˆ|8«ÃKûvõéÌFéö¾]ýû÷µ7µ+æ´¶«¨xOLK—>NDiic/]*¸t© -m,ýò—ÓÙûµ½Ìzh |C¶çÉɉnJL¼30Л»ZŒ ãÆ>|xs\܈À@c\܈ÂÂéssWgd¤FD„ö霜œX\¼ÅæôA "Cw'‚½{×Μ9!$$¨ÿ¾Ï>›^ZºˆØ% {ö¬ÉÊšåïïÝùòÙo½µJ>Á¤¤øüüwß=4$$hþü”C‡^%Ic>ø '!a[ìÇ7?ôÐh—–Ù™Õ)+ûšˆž|rcppêܹ/‘¤1{±}ûóÑÑý££ûÿîwYîÏ®ºú@kë±ààÀ5kvef¾FDb%sôèaD4kÖºçŸßæïïßÔt¤¡á°½é¬X1744xÔ¨"bÕ×;²0xð€;²‰H¼nÕñXàzrz‚o¯X2›-çÏW%$, nm=æþA |´«Ë\TôÛiÓjoïØ»÷¯+Wn½÷ÞØo¿}·çÏ{–&û¹i¬ÁÛdk/˜"^ëÙ=ÄŸçf£ººJX™¡«Ël4N¥Û;[,‹ý¤‚‚Rű·Ï6En³oõõ×?°¾]l ½¾]lj­­ÇBCƒÙÿ)‹õrëq,zrò Ùžú,^œ“°”ˆââFzd‚ƒaæÌ D”ž¾60ðÑððé¬ÛKfæã™>è–êúv1!!âë#HÒÉ‹½4¨¿3cO{êSQQm4Üÿ6Ë•½³wï¬\9wĈÁFc@@€ÿ°aƒ~ýëE/¾¸ÀSÓ}R]ß.ÆÏïÖqÊ”‰håÊ­—/7ÔÔ4>ÿü6"o³àx,K/_n°yq(E¡"§Æà¶L¤É^‹œ¥¥g¦LY-­sæå½ÌÎsŸ:uþ‘GVˆ7ð3:;»¨»$øÔS¿ùóŸKÄOoÜè¤ÛK ò×>ú¿ÿJüÔ€á Í••y#GÞñÄ/”J—wÉ’i{ö¬q05æüùª‡z¶µõº8dðà_}õÿÝqGdc‡_À²ØY³’>øàÕî •Ò½¡´Ûø†l¼Eu}»äFþ÷¿¿5sæ„ÐÐà°°9s&–•í`Q­Ç±o¼ñ\LLTP±¹¹ÍÕMÞƒlÏíy& ë5Ûó*÷íòM¶pUÁÓÕ@•<Þ· t÷äô(Ü‚ÀWX߮ѣ‡{°oè®Ûó¤­Þ ¶¡(õ; EN¥¡K‹' ùz6)xŠœâ‘ô«Y£obƒ½¥BdB¶§6ŒâQ’œ‡>\ÜÀ¹=5°y¸ôÙ¦sò`¯Ò=4xuWi¸1ð Ùß쥾Üaäó²9wd3 {à"óáæ?Á%Ø\ÊA—¾ ÂÍJ|AŠî0ö2?äy@J´LTàÁu{üãÃg\±¹¾áÒî€Æ ·C‘“'Μãa’·` :ÇÃÞÜC¶Ç !„·è"­¸ 8Ö€’¤Í·=¸„lV»«½@¢T€çkóü"Ž5àcbªÛ!~“ žҬ ›òî‘ÜP€V;€} 9Ñ.'“à·ûpOW÷9—b?D_D>PxÛ ç Ûó9é%ÞšÙW5³"  òsÒQò{>!Om5¼O"á“ã¼R­.¸[¸aÏûä;§&š\)à B¸ aÏˤ{©æ÷Xœe¯r¦d‚Äz‚›“y~ªšRVgYt²Ö= '÷és‡/@¶çØEÙÐ|‚ ¾ <Ùž§éäL€Ïà&,àQÈöpbxž‡èêgàvpbxž' ɳ ‘ܘÞ°ç Ò}û§"¸ûxžä9Ûz—‚w ìõÎäõ>p v+ð„=×I{¯à8î ”:ÁIº}0 øAÀï)— Éë5=÷PÀ]Zz„= |ÙžÓp‰‚›ó=سÀ‡öœƒÞ+ñÿ·wïAQ\ùÀ A@^"n™‚ºe”1 dÁhi)[b\o劽¦²‰º‘䪻k­ø –•kdƒrñŠ¥aÃJЀ‹Ù¯R«[ˆ¨€Ãû¡ˆÀÌÜ?Nh;Ó0 3ÝÓßOñÇtŸîÓ§ÏÐý›sút7ÿ]ƒ b˜—…N&­>–C \`vx&§Q8&‡ê88¾Àö†crXI«Åÿ‚ä°ƒ…ã ,aÏ8 ‡^Ë'CrÖ –†!-Ï‚cr˜``§l!æE¡µÇÃŽFŒ64½^.OV=ºÆ!楡µ×^±,T»Làg%Xž‡dQèê”!Üö %û°‡ûÐ-‘OðãDCÞaC¨E‘Ϻá ˆ‰\ÞÁoO4ò,‘ÏZa ˆŒ,Gr¢‘`8Ð@”âýOŽƒDØŒÀ¡(*ÖÚ2á ˆy V"îäîž.tlо뀘"&ËNNÂq(bøj¤1Ä­/ìéK,Y аáÊG äà‰Ò‚˜¢'×ÖH†tJ‹µ^šë"âk{ s¸ÙKZó@"ö@¬p'Ÿ´àa› { bˆ|Ò‚ÑÑ { nÖùX<°Ê Ý/ä aDÏ:"ŸUb_¾„=x.ˆv M{ Roð±GŸK±äÁ¸M,„=©G>«!|{ €¤ ìt òYÂÒ‡°’‚ÈgAˆy`ö@jp[´E æµ@ØiÂiלóÀŠ ì¡«ÓœóÀºˆøíêÖç‹!'•·–K¥œý’táÐÚ3#´K†êvø°h‡˜Öa¤ çâმóÀJ‰òíêÖgøÞ¼‡}qÛD•‚ÕAk$Ã[†ª¬ÂH"ßBß&X;„=° ˆ|C1da¬"ß BÌy°{ö"R¡×‹4à‰<Šà†t´öÀJ‰3þ‰bÈÌ …=…"L1ø¡ùÏ·Öó1ç¶Ä°]@Wçà æü µVG„¯hçÛÕó@–,pmO[ãa¸á >X¨1~Z{çΕ«T‰ŽŽAA« ÊøIgÏ–¯qtŒP«Ï+ç' »õêèãÏïíÕnÙòy@ÀR;»pw÷踸-÷îÕ³¤ÆÆ¶„„O½¼b•ÊùþþKRRövvvõ»e¯¼²ÊÉ)2"bSuµF¸ÝsçÊÕêDGLjàà5_}uÙ $gÎ\ Zíè–R[Ûxþü*U∠Þ|ó¿¸ÂÑw-úÈÅe¡«kT\Ü–¬1±fDJ„Íb€á×÷†¾Xyù9s’{{µlÒÖÖæ›ovÏ™ó*]¸p-<|£N§ã’´ZõµÞX¤á·ä„s„óÿð‡ÿIOÿ’Ÿ:oÞ´ââ¿Ñ[o}PXø?iíÚ˜ƒß7È­´´",,…•„ˆ&O¸uëžA©¸¢²Ï%%o¼Ä¥ÚØØp;õë_Oþ׿îtuu³É fþ‰ˆ~ú©núôµ­­¹íz{»_¹r0 Àç™5CÄ{8Î/f&’·ˆ¤ 9òfØÚÛ¹óho¯öرԮ®¢¼¼4­V·kW.—¤Óébcgk4ùM~ttÈ‹oþС¯ˆ('çãžžóW®$¢Ë—o²¤ââ«DtõêçÝÝÏÎÞBD'N\æ°sçQ­V?§¡át]]Þ„ c„ËpeŽ­Õê¶o?ÂO}ç·ÚÚÎæå¥Ñ•+·–. km={äÈV"*-­`ˤ¥ýµµõad䌺º¼ºº¼ÈÈ ­©©‡‡¯f`ˆ‰íºš¥pÛ+ÃÖžO\CC+ __ºº<"òôŒmnn¯®Î;v4UVÖ¾üò z±Ö=zÔUTô}iiÅ×_ÿ³¢¢ŠKš:u͵k•cÇŽŽŠš9wîÔ¨¨™®®ÎÂðòŠmjjÿé§ÿ?Þ—ˆnß¾?yr‚A©îÞ=ÆšeUUµ'®ððpmj*àRkjNøùyuw÷88Dp ?yÒãèÁåãë¯Ñ´Üº•=iÒKÜVÆŒñ¬­=ùÌš!BkÏ¢Äp¶HZ{b¨ K3ÒÒÜÜn0§±±}hk{HDþþÞlrܸÑÂìôz½B¡ ¢îîS6_\üÃ’%ÛZZ:„IÙÙ[W¬H«¨¨:p àÀ‚‘#G|ñŇo¿j°ëxdQˆûiíùùyõ•Ù—ˆÚÛñS}}=ˆÈÞ^É&ýý½ˆÈÁAÉ_¦¡¡ˆ&LðãoeP5ÿ‡]Îý{ˆyD$ìätss!¢††Óz} ûëé9Ï’<<\‰¨ºú›¼{W#Ì®££“}¨©i4eóë×g´´t$%ÅŸ=»£º:—Ÿ¤V^¿~¨¬lßæÍ ‘‘3:::““3„9¸»»ð SUU+\†~†¨°áØØØ™d¼½Ýø™³£Gb“¦Ô XnæCÌècxŠŸ5ë"úä“Ã]Ç—(aju"Kš=[MD6쫯o©¯oIIÙË_‘…Ÿ={ò?~RUU›”´Û”ÍWVÖѲeóæÎzüx ›Éƃ88D(aÕÕšmÛV¥¦&’ •Ƽþºšˆ6mÊljj¯©i\·î/ÂeÖ¯ß}ÿ~Cssû¦M™ÜŽ Jxøt"JNÎxð Y£iyï½=DÄ]Ã3^3†˜À§g}m» 2lm sr>fIååŸÙÙÙró•ÊŸ;HYêòåáüµ¸NB–:Ðçùó§ó×bͦªª½¾dñbÃþÌU« s(-ÝÇ/pHˆJ¸-®¨Ddgg{ùògÂ|ŒOÞ¸‘åââÄ/Œ¯¯GmíISjF¯/Ñ?­g°î[0ÿaÁ î5€(¶öBCƒOžL žho¯ ðÉÌÜÈų™3§œ9³]¥oo¯T©Æçç§óWÌÌܘáææp߀\Ì›·ÁÒE°<„=)½Ôî‹òK®†:9A¤Î+W©#‚‚V”ñ“Ξ-^ãè¡V'ž;WÎOvÜ Ô•ÇŸß۫ݲåó€€¥vváîîÑqq[îÝ«gIm ŸzyÅ*•óýý—¤¤ìíììæf$¶¡Ó§ËTªDÃ2O5²#……ßM›ö;‡Wרðð·oß7^ag©A†7nÜY´è#—…®®Qqq[~ü±Æ`Óß}w32ò}—…nnÑ+W¦77·÷[N±ÓˆÑÏú½¾äÿÈ´³³åþKmmm.^ÜÃ’JJ2llløI}ÿÉ%\ó…}hŽpþÖ­¿58.æÍ›Æ’.|Í iíÚanFr`“JåÓž[[›²²}¦§ ?—•íãvœY´èuã%1˜iaUUŽ»» oo÷»wñ7íà ä/°tiØÓxúõˆZ{ F;wííÕ;–ÚÕU”——¦ÕêvíÊå’t:]lìl&_£ÉŽyñÍ:ôåä|ÜÓsþÊ•ƒDtùòM–T\|•ˆ®^ý¼»ûïÙÙ[ˆèĉ ƒÊY°`F]]žF“=K«Õmß~ÄôT¡;ŽjµºwÞ‰jl,ÈÏO'¢o¿½n¼$ýQNZÚ_[[FFΨ«Ë««Ë‹ŒœÑÐКšz˜¿Lhhð­[Ù²ÈZTô½ñBˆÞ·âÀ½³F_BD>>q ­üt__ºº<"òôŒmnn¯®Î;v4UVÖ¾üò ê;­³^;þi]8§ßùu}_ZZñõ×ÿ¬¨¨â’¦N]síZ娱££¢fÎ;5*j¦««s¿{0PlCwîäŽ÷´Àžž®&¦ wÍË+¶©©½¾þ”··û`KÂí2Ò×7^£i¹u+{Ò¤—ˆèöíû“''ŒãY[{’[²²òè„ ~DÔÖöÈÝ=Z¡PètßôÕfØÏp>ÑÃ#áu£ÆÆ6ö¡­í!ùû{³I- èõz…BADÝÝ=¦l®¸ø‡%K¶µ´t“²³·®X‘VQQuà@Á#GŽøâ‹ß~;Ôô˜—^úEÛÚ™ž*ÔÚúˆ<=]µ/F44´‹jD8†xuΰßDäææLDøÅ …NN#77"jh8Í]=êé9Ï’<<\‰¨ºú›¼{W#\½££“}¨©i4esë×g´´t$%ÅŸ=»£º:—Ÿ¤V^¿~¨¬lßæÍ ‘‘3:::““3•à 9aLØ^˜˜*Ä®ÃÕÕ5?GIúåííFDUUµl’}=zþÕVéBØ1š5ë"úä“Ã]Ç—(aju"Kš=[MD6쫯o©¯oIIÙË_‘Ń={ò?~RUU›”´Û”ÍUVÖѲeóæÎzüx ›©ÕêˆÈÁ!B¡«®ÖlÛ¶*55‘ˆÚÛûiŠÉY¿~wMMcSSû¦M™D4gΫüÕ§ …„¨ˆhÇŽ#?ÉË»¨P„.fIØ(˜š…mÁððéD”œœñàA³FÓòÞ{{ˆhH®›ˆŽ…‡Ô0¿ÉyáB†ÁHÅœœYRyùgüf7’¥._Î_‹|h|`äüùÓùk±ÆVUUŽ^_²x±aæªU •›coÿt¤½½òÊ•ƒüLŒ§ ?ûí^ƒúÙ¾ý?žY®—ò7¿™máY..Nü}}=jkOš:>#9A:ÐÚ1 >y2-8x¢½½2 À'3s#ÏfΜræÌv•j¼½½R¥ÏÆ1r237&$D¸¹9á\T´«ßüõz=)úÆÑdemމ qrr5jä»ïÆ^¼¸‡ˆÒÓ¿$¢Ã‡?LJŠ÷óó²µµññµn]Üþýý<ëÄHLaáÕê@{{å´i“ ÿ8}údþêÆS…Þx#(??]­T*íüü¼¶nýí,fIþüçÿôóórpP¶·wd8eʸK—öÇÄ„8;;º¸8ÅÇÏ)+Û7fŒ§ñbHFr‚8ür$ç°Òju7oV­vvv|ø°p¸77ÐPRSR%#9A:ÐÚÙY¹2=(h5©T–. ˜n`Ù©¬¬Q*í¦L×ow%X7tr‚8˜±“†:9A:ÐÉ 2‚°2‚°2‚k{ ܵ=4œO@ôÐÚù‰;gkÃQ«IEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-examples-thumb.png000066400000000000000000000262631445075545500255140ustar00rootroot00000000000000‰PNG  IHDRÈU%µ7àsBITÛáOà pHYsÄÄ•+ IDATxœíÝyxSUÚðsoö­iÒ´MÒ%mÒ}/¥-¥”ta_díÊ"8lNÅTú øß£#ú}*££ãȰŒ#Ì¢,Ö" ËÐÖRºÓ½MWš4MÚìËýþ¸N¦)¨¨] ¼¿?xš›÷ž{NžÃMrï›÷ À(  L¡xzzšÍf×¹\n6›ív;BˆÉdÊd2­V;¦}cH X­V‚@Eà’Ó¢î&öŸÚuØãàààÈÈÈ®®®’’r‹D"Y·nA†QXXØØØ8#÷6›ZZZJP(Û^ ó󽕖}ý½—û®_BñSfRxž}…G]{yNkÐ"'AúÒ<½nü BÚ®R©äñx&--͵1''Çßß_.—‹D¢ªªª¡O‰„F£I$•JE>¤àøæÔ0.ã?§]QÝK<ôND…Íc+bh^ƒU׃ýºâsd°ÛÄjkk Žýâ‹/\­VëöíÛÏž=ÛÚÚúÏþ³««k´GÆŽãAAAMMM®-A|ÓÒcs8`/Cí·Þm°t·Ñ}ýBÌÀ0Kw+ù”Û[ass3B($$dè¬Vëk¯½f±X‚x÷ÝwoÞ¼9‚ã÷ˆ   ææf‚ \[œºÔ|Kk² sp"’z?ÿˆé¯`ú)B•æŠÄ† ###44ôÃ?tma2™ñññ!ÔßßãÆ “É4ÂÃãÊËËËÓÓÓb± „˜LfSS“ä3r1*¨ïú7¦®Öñî#!„0Ç< ˜°†xGM{d;q§íCiÚnÖ~s|tº&‚áWÞBlÿX³!„¨8F äp~÷ “E§š­vò>_ Á¹ÃÄrØ,ÂZ<5$À>ðe—• &ú›Dï'¾h0ÛBN»uÌ» î'wšXV‹Óe‚©Çö£î®ÇÂi4Òµnzbõ¦7ºh³ÝùÓïJ‚Êðì„bŽŸ€½Mj'ÚÛ0‘ˆððÀ¼¼.— ¹šîÄyÓÏ×v4}Í7ÈxòšªÅbp5²råÊÊÊÊa-cØðnr¹Üf³¥¦¦’-à8®T*¥Riww·ÃáÑ‘‚1u‡‹X›%‘muªoi zWþ¹úôéÞãÇ5gÏê««y5¡"¦ÓasÅçåå ¼öÚkÞÞÞÀÃÃC (•Ê)S¦°X,ÇSRR¼½½“““ß|óMƒEî»téÒ   W ±±±J¥’ÃáäççÑ FÇß cêKú³gã6þ»oÖï>NѺ¶>ëñòK±+6}cÿÏÄ¢Óé‰Ä`0$&&²X,½^Ïçóår¹¯¯ïîÝ»Õjukkëo~ó›C‡ñx¼¸¸¸eË–Æ‹/ž?~X v»=,,ŒJ¥¶··þØÁ(ºãËlµZÌvûþVsïú­V*Õ‚ÃÏïò’õ§ëz,v»ÍazÆ2›ÍÍÍÍ, Ã0ÇÉ÷»›7ož8qÂÛÛ;44ôèÑ£ ‡C¥R…‡‡Ÿ:uêÓO?jg·‘ü£´zphŒÓöCgàþïøãx÷L@د85Tê¾ÞÞ&Ì@&ÈOt˜LæxwadL˜L‰î50±À¨€‰FÅR“GŠX,–H$ …B¯×'%%™L¦Ñ+ú@§Ó­Öû}NOMMõôôôõõõööÖjµ2™,,,L&“ ÆÅÅY,…BáëëÛÛÛ;Ruz¤B£ÑRSSu:]@@€H$b0ÑÑÑäX˜Lftt´^¯—Éd&“)>>^§Óàk8б6mÚ”’’ÒÖÖF„T*u8yyy£t,.—;88øãqwG*•¾öÚkû÷ïߺukqq±^¯ŒŒ,++KKK«­­µÙlIII§­­íĉ×®]©ã¢ÈêÕ«úûûcbbº»»F#A^^^B¡°²²ÒápÄÄÄ\¹r%--­®®ŽËåÖ××;vlDÆà­0 Àd2ñùüû+†ËåR©T‹ÅrñâÅÀÀ@„PYYYKK ›Í¾|ù²Óé¤ÓéR©ô‡S€ÆWyy¹ÝnŒŒlooÿôÓONgpp°Ñø]VB¡øì³ÏÈA]¸pÁn·‹Åâ<ú(¾zxx †Ã‡‹Åb‡ÃQUUuãÆQ:ÖȾR©Ô“Éd4ÃÂÂ>L¡Pêêêp?wîÜš5k®]»ÖÞÞþñÇs¹Ü‘MÏÁH$’ÈÈÈË—/óùüðððòòò“'OŠD¢öööæææ3gΔ––ÒétÇ CddduuuCCÈzâàr¹ãÝ…‘1aß Á¨€‰FL,0*`bQÉX÷n̺ÿx÷bP61NZÄÄøOâ=púCãÝ‹€‰æ®ï>ŒKW+C"ï^Œ §pÂÇ»Àh¢Ñh4íÇã†Äÿ’cýì}G¶0˜LæÎ;ûÛߺ’7þçþgéÒ¥ç.[øIÁüòÊ+·—U—FÀ/çöóÈéÓ§WVVÆyóæ9Žàà`çt:BO<ñ„P(¬­­ˆˆøàƒ:::È]òòò¼¼¼>ûì³àà`™LÖÒÒr{0“É\¹reUUUuuõ‚ p?räHlllUU™%öðÃÇÅÅÑh´-[¶`öî»ï>þøã‡ãý÷ßß´iNçw{챡Í&%%÷÷÷8p!´téR™LÆf³·mÛæÚÆ‹Ûý²æ±N§óòòš={6Y&”¬ªðöÛoÏŸ?ÿèÑ£«Wÿçbý¤I“^}õÕÇ\©Tþõ¯MMM½=X$¯[·ÎÏÏO§Ó]¸pañâŹ¹¹‡cýúõiii[·nÝ·o_ww÷ìÙ³CCC_|ñÅÖÖÖÒÒÒµk×vtt”––®\¹rX³999~øaRR’P(D‘@8p !!ÁËËkl_IàÆmb ¡P( õz½Íf#•¨n04MÿÀÀ›Ívíb³Ù…BAõõõÝ1xÙ²e‡ƒ\±¯¯¯¸¸8))©££C­VŸ={¶ººšF£9›ÍF£Ñ:;;<ØÜÜl·ÛÕjµÝn·ÛíV«•J¥ÞÞ§Ói4Ùl6•J%‚ìA&“‰Á`ŒÉ îÌ-ç½££cþüù~~~}ô‘P(ÌÉɹqãFGGGmm-‡Ã©¨¨555t:=...&&ÆÛÛ{Μ9 …âÓO?Õëõžžž·777'''755•––Æ®®®”””£Gvuu X,–îîîM›6i4šƒ¦§§+ŠcÇŽÍž=[¡P>|xîܹr¹üƒ>Ölppphh¨N§«««‹ˆˆ0 l6{ÆŒ:¾¯×ü|ÁÁÁÁÁÁ‰ä¿þë¿~ê¾ÑÑѯ¾úê/ïC~~>|N !D¥R'L½/0îÌf³ÝëKp_Â0,33sÆŒ®[%>úèèåc=úè£?£“£Ñqn7¡'Ožœžž.X,AÑÑÑ3gÎÝÓÓ³råÊI“&i4šÇ|pppæÌ™qqq~~~3gÎ,--Ý·oy¬/¿ü!ôá‡,[¶ìêÕ«¿þõ¯Éàá–åp8¨T*…B¡R©¦  Àfûn‰^•Juâĉ¶¶¶óçÏûûÿ§j…J¥úꫯ„B!†aŸ}öÙƒ#""Äbñõë×CBB²³³ýüü\»ž <{öìž={‚‚‚Μ9ÓÚÚ*‹ËÊÊ.]ºtýúõšš___ױȣ455UUU555º6‚{„ÛÄ*))Y¼xñªU«N:E£Ñ^xá…ÁÁA“ÉDæÓ!„ ƒÃá0™Lžžžžžž\.7<<ü¥—^*//'×{¾cðçŸ.¬VkIIÉššš\»ž:wîÜ®]»^|ñÅÂÂÂÝ»w ‚††«ÕjµZm6›Ùlv8®c-Y²„Çã‘G‘H$ùùùãñê»F§ÓÉÜKÇY,Ö÷…mܸqÓ¦M .|ã7î¦l&‡Ã!³LICw=åúÔÏápî˜hõ}Çš0u;ÁLÈcüFäcp_ãr¹<Ïõ0111..ŽN§ÿ¤F½¼¼ärùíOݾ=1ÊšO@n7¡~ÿûßïÝ»744”F£q8œõë×c†aƒÁàñx eØ9ƒÁd2)Šk:òx<×^!.—KÞ $×,%†î»aÃU&·Âk 'Nœ0Ó¦MÛ¼ysww7F[°`J¥zûí·ëëë}}}ûûû É]>~èáÈ}«««_yå•)S¦ŒÑˆÁ˜p›X---ׯ_ …™™™Cs]ìv;AN§sèF‚ pÏÉÉinnÆ0L­VϘ1C&ûnY›ÎÎΜœœÜÜÜåË————»öJHH`0dU·   ¥R9000ºckø'›ääd*•zõêU…BØÜÜŒã¸J¥’Éd !!!*•J"‘äææâ8ÞÖÖV\\ÜÐД”äp8 CWW×ôéÓÛÛÛ[ZZ8NÿôéÓ+**È úÎÎÎööv‡Ãd2ÛÛÛÉ6£¢¢d2Ùµk×\w€!„0 #keðË9N‚ ¨! Ã~êM¾Õju8ãÝ €‡Ãa³Ù?#§åçí5ìпdw0¾Ü®2°ÙìÝ»wïÙ³‡Ïç“[víÚ•=t¹¯»´cÇ@ð£aQQQßW(f×®]?õ àÞáV+;;ûÖ­[ qqq sçÎõööîììlhhxê©§fÍš¼lÙ²–––þþ~r—;vøùù…‡‡¯\¹²­­mÆŒ¹¹¹jµzÒ¤IW¯^% ÂDFFnܸÑh4®^½:33³¬¬lÁ‚+V¬Ðét/¼ð‚T*5™L›6mâp8õõõ®6³²²""", ¹X&¸¿¸±˜LæàààÀÀ€——WFFÆ[o½EĤI“˜Lfhhè›o¾©T*>¼bÅ ×.'OžÜ²e‹J¥"«6ÖÖÖ®Y³fh³¾¾¾]]]~~~ W®\Y»víÌ™3_y啼¼¼ââ⯾ú*''§®®Î•qìØ1Fóûßÿ~Æ £þ€Qà6±ôz½X,öõõÕh4A ½jj2™´Z­^¯7 CË 8ξ¾¾’’’ƒ.Y²d``€JuKLEét:‚ h4…B!‚Ìu&ÂápÐéôo¿ý¶»»{É’%d#²MÇ Ü¸O¹½vvvfffz{{:tˆÅbMŸ>½¤¤¤­­­¾¾žF£ÕÔÔ°Ùì›7o"„RRRâââÄbqwwwEE…ÕjMKKkoo§P(L&³®®®¥¥Ål6Ïž=;..Îét¶´´\»v-;;Ûßßÿƒ>°Ûí‹-:pà@CCCrrr[[[FFÆ¥K—üüüºººÈcùùù)•ÊcÇŽÁ[áýèg~qóóóCY,µZý}1L&“\˜¹¿¿Ÿ¬÷øù ðaPx €‰aÛ¶m?ð,Žãà e¹R¸B,+77wXm™ØØØ´´´‘í$¸g¹å`6uêÔŒŒ Ãâââ0 S*•S§N•J¥ßEãxfffrrrFFÆÿþïÿr82ÞÛÛûÀ®R}䯔J%ùP$¥§§ÇÇǧ§§Ïš5kh±0Q¹M,ooïøøø¥K—FGG#„âãã³²²’““]Å«bccçÏŸŸ‘‘A¥RÍf³@ ã …Ãáp•"²Z­dÊ)&&fîܹƒƒƒ</<<|öìÙc5:0nÜ&–X,–J¥,ËÓÓ!xåÊ•¡u­ZZZjjjd2™F£Q«ÕB¡Œ§R©z½¾··÷ûóí·ßö÷÷———_¸p!,,lôÆînyT*U 8N»ÝÞ××W\\¼gχÃñÍ7ß«ªúúú’U!ûûûår¹P(tÅ÷ôô(•ÊÆÆF„P¿Íf#O`k×®­¯¯7‹E©Tfggïß¿\† ÆÒð|,&“i6›]}ôÑØØØ‹/’Õ‹‹‹››› ‚°Ûí Ãb±¸â)J``àÔ©SɰºººÛ†ã8NÚ>x@) WÝGp—  Œ0ÈÇ`b˜6mÚÏÞÇq__ß¡ jk}MxÃk¹ðx<„Y“ˆÏçóx¼¡egø|>‡Ã Ú²e ŽãdX zs›Xñññ Å`0oR*•*++‹Ì„!I$’–––ˆˆ>ŸïïšêŠ'" àöÈd²9sæôõõ¥¦¦2™LrñËàààyóæiµÚQ7nùX4-%%¥««K­V ‚ÖÖÖ%K–Lš4©§§‡¬a\XXH„Åb©¬¬LII©ªªJHH ã…B¡\.ONNFÔÔÔðx¼[·n½ÿþû,++ãñx===‰D¥RÉårÿ²²2½^?>ããkíÚµ<òÈ/Yi'++kûp_øn!ÌÛ hðóØíöÿ,„ ÁÁHÁ0Œ¼¨ÆÊݬ68›Í‰DwÉ`0†.ó&¤ïý2øòË/ÿ¤†~÷»ßEEEÝMdjjêŒ3~Rãà¾ãvùŠÍf?ýôÓT*õµ×^#Ï+/¾ø¢Ñh<þü¿þõ/„ŸÏòÉ'-KAA•J5™Ll6{Þ¼yƒ!--íäÉ“;wî$w_¶lYHHÈ'Ÿ|yøðáÚÚÚ˜˜˜åË—«Õ길¸´´´×_]£ÑŒÓÀÁ辦J¥"˯!„ÒÓÓ+++ËÊÊ\ý$‰§§g[[›¿¿¿D"‰D‰ÄßßÿøC}}}ee%¹{jjê”)S^}õU©Tº~ýúÎÎÎU«V!„D"QcccUUÕ… NŸ>½dÉ’±0ng¬É“'{{{ ²š#A,Ëáp¸®wÙl¶3gÎäææ~ýõ×\.—Á`X­VƒÁàt:‡îŽã8•Jåñx‡C­V_ºtÉh4zyya688HÇc±XpmsKMÖëõIIIMMMUUUz½þ«¯¾ÊÌÌŒu:QQQ‰‰‰ƒ!..N¥R;v,%%!TVV¦ÕjÉ…w¯]»Fî^^^~ëÖ­œœœK—.©Tª©S§ªTª˜˜˜úúzN§V«årù_ÿúW‹Å2N£ëGÂܹs§§§ç[o½EVK0™LcÒ1€;(¼F^`bxþùç‡>\¶lYN-66önvOLLÌÈÈ®û€[v†a3fÌ P(gÏž Ç0lîܹV«µ®®îÙgŸ¥R©IIIL&³¸¸899Y¥REGGóù|•J%¾üòK„¯¯o||¼T*õóó‰D'Ož„/Ÿ ·ìŸ”””´´´®®®ÔÔÔŽŽŽôôt6›Íçó½¼¼¼½½»»»ù|~NNÎÙ³gŸþù¾¾¾I“&ùùùñùü”””ÚÚZN—œœœžžÞÔÔäãヒJ¥7oÞ§Ñqã–èçïï/“Éèt:Y-R*•^¿~œAìÛ·oëÖ­äß …ÌÙjll¼qãF]]]kk«P($Û©¨¨¨««+**"k¸ÛIJÛíÀn·[,–ÎÎÎk×®-^¼xÅŠAtvv¶µµ?~\«Õž;wn÷îÝ|>ß`0èõúƒÁÐ××g6›×®]k4õz½Ñhœ:uêÆOŸ>=^c÷a¥°6oÞüæ›oÆÅÅýpØaöK k‰Ìßß_,w/î3Fäc01̘1C,GGGß¾ýîQ*•#Ú)pß^xM(zyy!„V®\”––æzÊÓÓÓËËK­V3 OOOòV›Í‹Å<Çq×ÍA2877×ßߊÈ?€†/„ùä“OΛ7¯¢¢"33³´´ÔÇǧ´´”|öoû[{{ûÊ•+u:ÝÆ322ººº¶oß. —.]©T*/_¾ì ^´hAÓ¦M»zõê8 Œ·3F³Z­\.W&“ݪR© Øl6•J½råÊÉ“' Bè½÷Þ£Óé555>>>---Cƒkjjöïßûû)˜ðÜ&Vdd$N·X,w³PAd µåË—3™Ì¨¨¨ŠŠŠ9sæddd¸j×Êåò_ýêW½½½£Òwps«E¥RcbbnݺÕßßïááÑßßÏ`06oÞŒaX[[[aaá­[·Äb±^¯ÇqÜétâ86yòäüüüÈÈÈææf …¢Õj½¼¼nݺ%•JÅbñÍ›7 ÃxÜ—’““×®]ëëë;Þ¸‡`!²zöx÷Lv»ÝétRÑ¿/ŒwÀs `œ¸.©³X,.—;ìÙ;nýÀB˜¤äädiÓ¦%''gggßþìí@Ãò±x<ÞK/½4sæÌ¢¢¢—_~Y({{{oÛ¶­ººzÖ¬Y999åå僃ƒñññO=õ›ÍÎÌÌÌÈȸqãÜfC¹±¨TªJ¥ …±±±žžžŸ|òITTTQQQqq±N§»xñâÙ³gÉÕäAEEEUUUAAÁ§Ÿ~ KZ‚aÜ&VJJЇ‡ÇÀÀ…B1›Íä•.‡ÃÁf³q·Z­‹…J¥J$ ÃL&AÞÞÞB¡–ø½jµÚ¸¸¸ÚÚÚššFÓÔÔd³ÙÊÊÊBCC+**zzzÔju___XXX}}½V«ííí‰Dþþþ‡²Ùlã5?^# ¯0=÷Üs†ýpŒ¿¿ÿ<;yò䬬¬í¸¹Ý„Æqü¡‡ŠŽŽ¾yóæÜ¹s###322h4Ú¬Y³ššš/^Ìf³}||ìv{NNŽŽãG$EDDdee™L¦wß}÷úõë‰dÞ¼yÍÍÍ999ÍÍÍ~~~999ÁÁÁ R©´¶¶ÖétŽ×°ÁhsK›ñòòâóùéééñññëׯ///_½zuiiésÏ=×ÖÖöè£"„jkk~øá¤¤¤ððp¿mÛ6F¨Õj;::víÚe±X~ó›ßí „BCCÃÃÃ;;;u:†a .—ƒ±á6±‚ƒƒår9…Báp8]]]½½½jµº¬¬¬»»»¾¾ž\ç²®®®««K ÔÕÕ :N¡P0 ;tèPBB‚‡‡‡Ùl¶Ùl4Í`0œ={–l‡l¿®®Îd2µµµUVVŒÃZª[ JIDATpÁXq›XƒƒƒÀf³ÆÖÖV„ë_‹ÅÒÑÑQWW·}ûv&“Y]]­ÕjËËË322233ûúúRRRX,–V«­¯¯‰‰¹páBll,›Í&[X·nÝÀÀ€V«˜?--íĉGŽÉÌÌDá8^PPÐÚÚúå—_Ÿ?88Èf³·nÝŠa˜J¥:}ú´@ èíí5 …¢¯¯Ïf³‘‘:N hµZ©TJ¥RÛÚÚ<==M&†aAðù|×ÔÔ‹dðã¾[óû~øÀOeµZN'†Â0lèoø%œN'|͸÷øùùwÀ=ê{¿ .]ºôGw~æ™g~´x0¹M >Ÿ¿cÇvðàÁýû÷?ûì³)))‰äôéÓ  E(þö·¿EmÛ¶Ïç‹D¢îînƒ±{÷îñé>¸W¹±0 kmmåóù\.·¾¾þÚµk½½½*•jáÂ…!!!ï¼óާ§'yŠR(¯¾ú*Bèõ×_§Ñh®ìPHn+--Á`èt:²Ç[´hQss3…B!Ân·;²0$AV«• ˆOOOX ã–šÜÛÛuãÆ›7o¶µµ±X¬îîn„Ð7ª««[[[F£^¯‰D­­­­­­Z­622²¼¼œ, à~…×ÀƒÂkÜ¿RSSg̘ñ}ÏÆÇÇçææþìÆóóóïr#˜ÜnB‡††Îž=[.—WVVNš4iÙ²e4mÆ l6ðÀÀÀÖÖÖ 6Ék×®e0†Íœ93##£ªªŠüž‰ãøªU«¢££kkkW¯^i±XV¬X!•JÕjµV«E-_¾<((hÆŒC7‚ cxi{{{__ß²eË6oÞüücçÎÛ·o?uêÔŠ+B(??¿§§çù矈ˆ¨««{ê©§ …H$˜>}:ÙHvv6ƒÁ°Z­Ë—/çñx8ŽÇÆÆbvìØ±çž{ŽŒÉÍͽtéÒ°`Â>±zzzFcWW‹Åòðð g—ËEñù|£Ñø§?ý)++ËÃÃü uOOOgg'Y!$ ÛÛÛ¯\¹‚ãxss3™{£ÕjÉ]ÒëõÃ6‚ Ãí­ÐÓÓ“,†öÞ{ï‰D¢E‹}þùç%%%[¶léïï¿|ù2…B¹zõjvv6•J%“·¯]»f·Ûõz=ŸÏ÷õõ•Éd---K—.MJJúç?ÿ¹víÚ„„„††‰D¢T*ÏŸ?ÙÞÞPTT”Mn¬©©¯—Œ×Ïí)ʰ?†=öÃ|¡P˜–––––æëë‹a™Äüì³Ïîß¿Ÿ,<¬;6À]ár¹®·H€äcùXÜ¿är¹kY¯Û$''ÿÔ6.\x—ÁDâv³/000%%%$$!Äápbbb( †aQQQ|>_*•ÆÇÇ“¹\.ù‡‡‡‡Ã‹Å¡¡¡C›’Éd~~~<oΜ9ÑÑÑ®:ò‰$ `ØF0ñ¸Ý&3¢L&ÓöíÛ-ËÂ… ccc}}}7nÜXYYéåå5uêTooïGy„F£oÞ¼Y­V¯[·.11Q¯×“KZ*Šgžy&::šÅbÍ™3§§§gÉ’%çÏŸGýýï///_ºtéÐ`âžUXXxäÈ‘™3g †Ã‡‡„„ÄÇÇôÑG---¡´´4???NG§ÓÅb±ŸŸŽãW¯^={ö¬«üZttô‰'Î;‡ãxmmíáÇÉ}B—/_¶L<Ã'Ö¬Y³{ì±ÂÂB6›ýÄOTUU•””<óÌ3mmm¡o¾ùÆ`0ÔÕÕ%%%™L&WæÌÐÅjjjV¬X±hÑ"„PHHH^^žJ¥š7o‡Ã!\Çbˆ`<¸Õ ¥P(l6›ËåvuuÑétŸÎÎN„D"éëë³Z­ Ån·K$NgµZ½¼¼t:Åb!¶Œˆˆ —/((Éd“'O>{ölII‰P(ìîî¦R©‹…Á`˜ÍfrAòîîn¸ö~šìììiÓ¦AMe<˜0„…Ba0ãÝ0AX,‡Ãñ݇kXŒ§Ó9Þ]x`) .—ëãã3tcPPÐ8uÜ~üËàŽ;¢££‡¥æ=õÔS£Ö%0P‡> …ùùùN§óí·ßÎËË£Ñh»wïÆqÜUá!ôç?ÿ¹   ::ú¿ÿû¿ËÊÊŽ=:Ý÷:·3Ö¬Y³¾øâ‹ÿû¿ÿÃ0¬¥¥…ÇãEEE ÛÁl6üñÇuuuùùùsçÎî‚û‰Û«§§'**ÊÓÓS(¡Ñh†¦'utt8„X, ±ÙlcÝ_pŸpKMnmm•H$‹å‹/¾ +**ª¯¯ommmhh¸uë–‡‡‡Z­îíííèèP«Õ }ô‘N§¯®øÅ ðaPx € fï޽ö,\¸pçÎ?dn7¡qÿõ¯PQQ±y󿏏8³Ùœ››+—ËÕjµF£!Þzê©={öìܹóÔ©S¡µk×Êåò¬¬¬aaàA6<Ë`0tvv®X±Âf³ét:rqÔwß}÷™gžq…Ùl6£Ñèºô5gΜS§NÝdn‹Çãi4šÊÊJ ú»»ûûûBƒƒƒd™5W…BÁqÜ•Œ¥V«-ËíaàAæöVØÖÖ¶fÍšøøø¿ÿýïkÖ¬ILLlhh3gÎ<}útHHHXX˜P(´Ûí¿úÕ¯>ùä“”””öövŸÒÒÒ´´42¬¾¾~¼î/½ôÒ{ï½§P(BdiLLLll¬\.wmªaG¥RaíS€Ÿò±Àƒ|,&˜åË—Û"‘HfΜÉf³8 <Ȇ^ –Éd¡   OOϬ¬¬¤¤¤¡…àwïÞm±XvîÜI> $󱆅™ÛÝÀØØØ 6$''S(”5kÖ„‡‡³X¬Ù³g766>üðÃ………dØ_|!•JÙlvII Bèã?.**ÊÍÍdng¬„„„Ï?ÿü…^`2™'Nœøúë¯1 «­­ýÇ?þáëëë ‹Å<òÈûï¿O>¬¯¯/**º= <ÈÜ&Ö¥K—Ö¬YóÎ;ïh4šuëÖ­X±!ú /455¹Â>øà­V»jժŋs¹\rãíaàA6<ƒŠÅb9N‹Å²dÉ’äääS§N]¾|™Ïç÷÷÷oß¾Ã0•JõñÇ“ÁAA®‚‰a6æC÷•)S¦$&&Žw/ÿöÿŽ÷×0ø·¿IEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-examples.png000066400000000000000000001274001445075545500243720ustar00rootroot00000000000000‰PNG  IHDRX² °+sBITÛáOà pHYsÄÄ•+ IDATxœìÝyXGÞðêîîC¹TTPGAQÐ&Ä5çÆxd“]MÖh<Ö+Fã.Ù¼‰k²ÆÕõH>>¿ûÝïz÷î]]]•““S__ϻƲ޽{¿öÚk‡ª©©ñôô •WºººŽ5êǬ©©éÚµëØ±c›}¾—¤¤$­VÛú­B,ÜPw§ÝišÚj†aîëÝ=»ö~ÁÊ®ÝlÕ„«îŒÒÂû_{o~ÿmìa9ò9ü®æZšt»¹õ8wµ6RJyžOHH¸|ùrhhè³Ï>[QQqÛdÕ6gYö™gž:th]]¼Ð”RÊ0ŒB¡7n\```uuµ‹‹‹“““\¾•5@Dz¶¶2dHFFF~~¾YŠ”öîb—VÂÿ”]ÄÞÿñÌíÂë9O¦äΣöÎc^uzzbÉÎÏoäÆîžõ%ù¦Æ7ï&¤$Iò·À°,kz!¨1NWWWgcc£P(ºwïN¡”–––²,ëîîîææÖ³gO9.Bêêêä;¨ð€Y[[‡††äää˜=&¡¤²¦î»tM«Hh+ÇÀ1¬¥µ6ö°^W¡K5¤[{ú8=5¾*-Îx¾Ð­WUÊYÓ‡avkÝÝÝŸ{î¹.]ºŒ;ÖÞÞ¾5›h4yQ¨q¢‹‹‹———››[]]a*!DÅK—.ݸqƒB€Œã¸ÁƒWVVfff6;íÕò¼•|'7«kkêô”£7TtðÅüWOPú«rŠÖÂJjaÙß,3lذ¾}ûrççççááqåÊ•{ÎÊó‹™™™¡¡¡]»v•W²,kgggggG)­««E±¾¾^„Ó§O_¸p¡õs³Ð!X–2dˆ¥¥e||¼$I,Ûx¤$GÁÞÁÄÊ4É»÷=Òä‰ý¨$?o"«Ñãe?ü÷æ‘TüUúå™OQB‰É8ev ¬®®–ø«««kýauuõÏ?ÿãêêêäädoo¯T*å^–$©¡¡¡ººº¢¢¢¼¼¼¾¾cA€¯W¯^={öÔëõÏ<óLK×a9½Q®x»¦<á$kaÙì÷HK õú{½z‚ŠÍ|áKKY´¥¨F%Úä OM˜=™igg÷ì³Ïöïß?666>>Þôû›ße #kÄ?€‡ÈÒÒ’ã¸{.Ú—ß‘ÐøŠÍ0-úˆ¿’°-«zX–e†RÚÊ'àÑÁX[[?ì6t¸¶|é6!äíUß9ØÙvlSLÛ0ï÷R+Þ¦`óÞGhPS[§Ñ6B aî¾}ØS?R£ȯ&w·5Þ°QÊ/‰ô;<à7«J’$"6Ào^›¡H%¶c›ðàµ}Dhú…ò.v–”Šêº{V¥êáXs»¡H[Ó¶–´G[!•¨ÔtòOþÈ ìÕå³??­ÅßœK¾QNi³“„2)¤ßäßùV×éç‡/×Õ57eHŒ>t°6ÞÞ”$‰J"•D*Iô—Ÿå¢‡‹©«©Þðùì|-ÌÝÆÅD*‰}Ül_5àæ'Ël„Šb“2¿*ß±‡ kÏ­Ñæ³ºØXø÷qªÓKœ»»eZÒú©£ŠµUra‰Rãª>n·öì²3¦¤B7ØÃùÔå¬ €¬=‹eš¹ÛimÁýãµçÂU›¿!”j££­GŽt·´$ C†ÈwH†aÂ0µUUõVAA\FÆœ7Þ°µà~HÌ¥Tjî‰ €û¢P’$"ÝùÙ ,ûá†9Ý,,ýËlZSC!”Þ¾z•ˆ-ÜØä8¢×ߺpr+6ö­Ï¿àúý…ë”JÍ—èhmœ#¼;5(QI"ò©´èe?±¦dö,}uµ(I¢$‰”ºóÝ”)"¥wRîþ³{ã ÷}ûD–•?VŸ9S<ç/“‚ûMÙ‡Pj\ÿ½Ü\Û6óùü­yÂB)¥³ž<¼›MéÛSÅòò;©„PBê²³k“’¤[·Œ)! %%µ)) EE¿¤ÞNNœ9…cIz^!’\³¬0é(¾^:\ÛˉæNlúóï{¹Vüu±Ä²LwR)%„ÔB77"IÆ3Š’(Öåæ’®] % ¥·³³K-·zµRÁDýœI)}0S„ááá}ûö}ñÅÅ–îâÀcªÍs„âÑ !¶VÊgüú(m¬º‡‡wÀ aË>?Ôk\VUM}+ŸüÇ?þñ /0̰YYYYPPðõ×_Ÿ;wÎôƒÿ2µZíëëkØü™Ghc©˜5vøP÷. Cº¯YSü׿ÖÄÄ´y\hä¶j•TW÷b`?¯îŽ«¿¿]¯—g!ï †ÙºuëáÇåx0hР~øaáÂ…ááá·oßn[{ZÃÑѱÿþ=zôhÛæð=‚a˜/¿üòèÑ£r &üç?ÿy÷Ýw=ŠûºmÐæo–¹ó…/!z ¸U–÷Ç×®=óÌ­”×åË•C†H #bî?eÿþ.+VÜJJÊ}å•Üçžóª©ØP‘Jb+¨$I¼+---99ÙÉÉiРA Ã|øá‡Ÿþ9Ëþr¼ÿûßׯ_oœÒ§OŸÕ«W8p`Û¶m¿ûÝïŒC”½½ýûï¿ÿÍ7ßìß¿åÊ•}ûö•sÿþ÷¿¿òÊ+,Ënܸ1$$DNo©|;¢iï¾û®²²ÒÃã••@#í}|b˜OO݇Ê˪«µß}'ÔÖ»­Y£ôõF$¤õÿ*•Ë_èôTûÝwõ<_¯ÓiáÓ‹H´mOPJmll(¥ååå”Ò—_~ù7Þ0{/½ô’q Ã0û÷ï饗zôè1~üøÝ»wO˜0AŽ=®®®‡ú¿ÿû¿þýû»»»OŸ>ýرcAAA à 8°_¿~ ÃtïÞ}ذa®®®¦Ë·ó(šðóóëÒ¥K^^ž¹5€¬­Þ*Œ¾¶FÒ髪êõúrœWý[9p`ëÇ…Š¾}]¿X8ESWß ¯­5Ô¦ä~Ù‘Yͳµµ}ï½÷Ž?^ /[m2 Ø(…a˜S§Nùùù¿óÎ;Ç-^¼X“ü±¿¿DDD@@@ppð»ï¾ëää´jÕ*–e§NºfÍI’~øá‡'Ÿ|òûï¿§”š(ßΣ=÷Üs‹-Z¼xñgŸ}¶k×®’’’eË–™;= ²öÎJ’$ÉKH) ‘Dñûs™’¨éß«Ë/ªË̤”š)½¼\×}þã%ÍwqYO òEQ¢”P*±¬$;[=ã¸yóæ/¾ø‚a…BqâĉY³fµræL’¤°°°††BÈfΜÃzKooïãÇ/X°`ãÆm¸mXQQAéÖ­›!äÖ­[ƹUUU„++«¦š[¾ G!Š¢^¯—Ÿ#ܳgÏíÛ··oßþöÛoŸwî\Ó,yóK—.g™.o¢…¦¢ÙÐí#4]Fbî^¶)%éDÒu‰JÃxHwC›$ŠkÞSóítÏ™(`nFi¾¶?G(IÔ°Æ’RÊ0Œ|Ýÿ%QEæ—åž’$I¢^"T~d^¢$Q"RÚL ”ë$'p?µãÖ诧 ?~¨½]GºXÊß—F8N¢´®¡^%‰ªTJz=!„r\mm=•ŒfÅŒ^cÿKý…p´÷í&þ¥dåsýp={Š„Ø?ÿ|þM¡‚¯®ÔݺV\nûÌ3"Ë*¼¼”ÞÞi9ò÷ÑÜùG›«­uÔ˜«s„F÷_FmwRøªš‰WC—}¢¬­Ñ2ŠÏ\’D‘z,>ã/Žõ|饅òÄååÂ-ú«¡óë é@ÇkããCžŸR]wïÈÄ0Œ¥×˵«¦¸B÷… CX–õìîTR©«½ÝÐÊ)Àë§wb²:\Ûç[•(%µ·ÅœüRúëDI’®”!¬ÀCמ[£­ dÍ–C€GA{^Ãd¼€¥Ù[¬´IzÓ”Fé-¸/Úskôê0‚€û¡Ã/†atdÂJhfØAÍÃnÀC£`¸6>Sð` ÕT*ôñÏ-Áy÷ û°!\­à~Ày÷ !tj„Щ!@§†@!tj„Щ!@§†@!tj„Щ!@§†@!tjŠ‡Ý€GŽZ­ž?þÿþ÷?A&MšÄ0L}}ýµk×¾þúkABCC_ýu†aêêê®]»©Õjv“áa6lØŒ3Xö—¿)¿þú놆†wÞy‡eYI’ŠŠŠŽ9’˜˜H)íիׇ~˜žž¾eË–¥K—vïÞݸ*Fó¯ýK’¤?ÿùÏÏ<󌅅Ejjê–-[´Z­a/’$•——ÿïÿ‹‹‹£”>ðÃ…ûÎÝÝ}Ö¬Y>>>·nÝ:|øðä_ôŒ3BBB†ILLŒˆˆ¨««ké¬0>͆j8?AHLLüæ›o(¥Ë–-köôëÞ½{³{‡ÎåÙgŸÕjµüñŒ3xžÏÈÈHIIÑjµgΜ±µµ}çwäÄÔÔTžçÏž=keeõ°›üÈñööî?srrAøê«¯X–möôëÖ­[³{ؽܳÏ>ËóüÒ¥KgΜ)ÂÌ™3•JåêÕ«yžñÅ7nÜ(“O>ùØÿÏi®ÎpÁ2˜8q"Ïó7nT*•ÇqÇ0Œœ¸eË¥Réãã“––VRR¢R©|}}yžß·ow×'Ÿ|"œ9säÍGŽY^^~âÄ ŽãÖ¬YÃóü’%Kþð‡?öâççWVVËqÜÃ>úª3œW“&Mây~ýúõJ¥ÒÕÕ5''çìÙ³£G®¬¬üþûï-,,8Ž;xð  4>÷ŒÏŠÁƒN3ã2¶¶¶'Ož¡ÿþ …¢éé×ìÞ;Ãi†P’$‰¢¨Ó醡”Êw $IR(NNN¢(–——?ì6ÂçP(<<<<<<\]] ·’(¥¢(fggÿðÃÖÖÖO?ý´ñu\EQ g”ü188X©T9r¤ººZů¾úŠ`\aee¥aCxÌh4I’ž|òÉçž{®¼¼¼ÿþ¡¡¡C‡å8îäÉ“z½^ÅU«V-Z´èÖ­[ò&­9+ä2·nÝ*,,dÆÕÕµÙÓ¯Ù½‹¢øàŽÿ!A ¼‡yóæÅÄÄÌŸ?ÿþýÇ—Ï›+Väåå;öСCYYY¸$Áo¼‘˜˜˜œœüÕW_5ú šR*ÿµäààpÏz\\\!‚ È )¥NNNr}î¹çNž’$)00ða·¾¢¢¢èè訨¨'N4 N¾¾¾ Ã\»vížqëúõë„þýû˃ƒƒ !FÞ0..nÊ”)òz®?ýéOý„Y'ôÎ;ïìÝ»W¥R­[·îé§Ÿ.**zá…4 !¤_¿~r™O>ù$%%eĈò К³bïÞ½>>>¾¾¾¯½öZBBBKça³{ï §F„÷ ß[/..f¦k×®µµµ„¡C‡Îš5+00㸜œœ‡ÝFxøúôé3sæLùúròäI9ÑÓÓsöìÙ~~~/¾øbrrò‘#G `ºžƒ.^¼øOúSIIIYYÙ‚ äå|äîÙÈó¼V«uuuí W¨Î¦¡¡a̘1ööö®®®ÎÎÎ7nÜøñÇ—¡ŽËx IDAT,Yòúë¯ççç×ÔÔLž<™ã¸«W¯öìÙ“´î¬ ”êõú{ìšÝû}9ÎG a«äææJ’4pàÀäädBÈ›o¾)I’¼.ë‹/¾xìïÀ=…††>õÔSòÏsçέ©©!„<ùä“!!!åååøøã w8Mày~îܹ«W¯þàƒ†)-- ;wîÜøñã‹•––ªTªÀÀÀóçÏãîèã$22²_¿~S¦LÙ¶m!$;;ûƒ>(++›;wîgŸ}öé§Ÿ²,›ŸŸ¿téRN×h[ÃYa˜Mì½ãúÖ1 £P(X–eYVþ¡i¢ž°iVgXæn ŸÆ†1Nä8ÎpžÈ鯫iŒO3CŽãT*Õ!CšžrŽãä=À}ø:ÉyŲ,Çq èÝ»·ü4¹{VôîÝ»o߾Ɖ͞ƧY£2M÷Õ(·Ù½€Ù:Éë¾’/g»–Nu^=Ü#í<ý,íQ€Gnxvr÷èl§îì@§†@!tj„Щ!@§†@!tj„Щ!@§†@!tj„Щ!t¨Îöx0p^t<ü…¿þû¯1Þ¢  §üf0œ:Ë@§†@šÂnð» 𸩾o§A°Æ:Tõåø‡Ýx<)|V|ó°Û›ä }½—ïÂ\t¬ä }vàñÄàjŽŠzœWÐáp^t˜ÈÈÈpGùôÓOOœ8áëëË0ÌClÒ#Ò ³wãc <<üرcÍáÀc€5«tHHÈ¡C‡4MaaáÏ?ÿÝÒm®FWðGdðˆ4£õî+3®G#FŒÈÏÏ?|ø°(Š„„„„ÔÔÔáÇ»ºº–””Búõë7þ|//¯›7onß¾Ý8äÌœ9ÓÏÏoݺuׯ_§”†……Y[[GDDÌ;W­VWUUEEE?~<((èí·ßvrrº|ùòš5kA0ݤ°°°êêê£GΙ3ÇËË«²²2**êäÉ“”R9ׯÆfëÖ­‹/vwwŸ4iÒôéÓÛÙ ''§Ù³goú jô+Óûôé3{öl•Jezs€GKEEÅ™3gŒÇ;wîÔétAAA èTªŒŒ ARSS ‹ŠŠ C™]»v ‚"_ÖÏœ9“ŸŸŸ˜˜˜”””œœ,Bqqñ¼yóòòò®^½*‘#GâÌ™3W®\IKK»xñ¢V«---?~¼ñ^ä!È¥K—8Žkg3úõë—””¤ÕjcccãããyžÏÈÈðòò24Æxwÿ÷ÿÇóüÆYöÎDì¿ÿýožç—/_nHiÊt7ºººžûŒçù¥K—²,+[¹r¥œ5yòäÊÊʳgÏ÷Rë;ÁtŸ7û 2þÈ)6l7Ÿ8qbEE…¡14Ó0'''77×ÞÞ^ÎbYÖxr«iâyÞÂÂB.ìëëËó|zzºR©”S,X BXX˜‰ÁSÓz†ùé§ŸA×%ʹÆkDÛÙ Ÿ'žxÂÖÖVÎ ày~ß¾}†K|£ÝíÛ·O§Ó=ÿüó ÃjµÚŸ~úɰzÈÇHïÞ½åMLt£R©Ôh4ÙÙÙ†æ 0€çùèèh+++F“™™iÈêÖ­Û¹sçV¯^Ͳìõë׳²²lll ½tðàAAä_œ¹`ºÏ›ý÷‰œbèC†aä@k¡<`³fÁÍÍÍÅÅ%!!Á0)ebÌÀPæêÕ«”Ržç )rµ­Ù»a+Jé¥K—|||äDC“ÚߌììlOOÏyóæyxxØÙÙY[[³,k Mw÷Ýwß=ûì³ãÇ?~üø„ X–ýá‡äÊ—.]:iÒ$Ã¥?&&f„ ÎÎÎ&ºqàÀŽŽŽuuuqqq†D–e{ôè1`ÀGGÇôôtCùÒÒÒQ£FQJèääWgè¥ôôôÐÐÐ!C†ÄÄÄ˜Û ­éóFšþ Œ“––¬R©Î;×ìæ÷•°¥å z½ÞÃÃÂó|ÛQ__ßì¾L›%_µ»uëÖ†áÅ=›1}úôeË–BRRRªªª c¦–ìÛ·ïã?~ú駆yúé§kjjvîÜ)‡èèèóçÏYRR"I’én”Ÿú¨¬¬”c•œ˜™™™››+gÕÖÖ——×4ÙÙÙBnݺeœUUUE±²²jC'4eÜçmXóÒÎÍÚÉŒ@¨Óé=ŠÞ¥KJiqq±N§£”:::vtóÌæììL)))éðKªR©üàƒ$Izå•W’““)¥ƒ =z´‰Mêëë=:uêÔ)S¦¨Õê'N”——ËY±±±±±±Æ…)¥¹¹¹&º±°°RZ^^>mÚ49È6tww§”ººº6ÝJ£ÑH’Ô½{wãDwww†aJKK;¤—ÚÙç...„Žj €¹Ìr]¾|ÙÓÓsذaò8ÆÍÍM­Vk4FS^^^PPàëëk˜ërvv~0_àÂ0Œ<’=õÔS’$¥¦¦vøŽœœœrrr’““õz½(Šò›é­¢¢¢$IZ¼x±B¡Ø¿¿ñÅF!¦»±   ;;{À€ÞÞÞ’$‰¢(Š¢•••$IYYYjµÚÛÛ[n’¯¯oyyùöíÛoÞ¼™‘‘1hР!C†ÈY¶¶¶£G®­­móC íìs†aFeèºQ£F‰¢˜’’Ò†–´Ÿ0""B’¤ˆˆˆéÓ§Ož<9**ÊÙÙyÛ¶mòÅtÇŽÖÖÖ»wïž3gδiÓöíÛ÷`ˆ ÃDGGO:õõ×_ß¿¿J¥:vì˜ñÍÃŽRQQ¡Ñhüüü–.]:sæÌmÛ¶-\¸eYÓφËO[öéÓ§´´tÿþý÷l•énÜ´i“R©ŒŠŠš5kÖK/½´dÉ’øøø×_a˜ððp¥R9mÚ´)S¦|õÕW,Ë8p@’$ùޝ¿þzÖ¬YS¦LÙ»w¯‡‡ÇŽ; ÚÖ&ú|ùòåçÏŸ0ñ'B}}}xxø{ï½7uêÔo¿ýV­VÿôÓOÀCaÆ­ÑC‡ýío [³f !¤ªªjõêÕ7n”G9«W¯öòòzíµ×V¬X!IÒÑ£G80f̘ûÕð»$IºpáªU«,-- !çÏŸ_²d‰^¯¿ûúÇ?þ±råÊ B®^½:cƌݻwwëÖÍÄ&”ÒüÑßßÿĉ†"&˜îÆÈÈH;;»… ®\¹’R*IRbb¢F£!„lß¾½k×® ,X»v-!¤¸¸xÑ¢E¤”îÙ³ÇÁÁaÉ’%+W®$„ÔÔÔlݺ5,,¬5 šše¢Ï{÷î=pà@âÐf¥¤¤ÄÅŽÿþûr±‹/Þ¿_@cYÖÊÊ*$$dôèÑŽŽŽP°,ëééùÌ3Ïøøø( ãÑÇq …Â0J?o«P(ŒÌ`F®RTT¤mÎSO=uöìYy)Ïž=ŸyæµZm\mÓ½´§òG++«‘#GŽ9R®Ç¸|ÓÚdááá:nôèÑ­\¿c¢å\Žã‚‚‚ž}öÙ>}úpg¨–eY[[Û§žz* Àø0ÉÝ_\ppðèÑ£qæv‚áñ }n¢‡9Ž“¿¢¯GcÆŒ‘¿£§5ÝpŸ´åÉ-ù2×Ò,Ó¹m ?ëÝ4}×®]ÑÑѾ¾¾...z½¾Ã÷Û³v$¯‘)((6kÐÓæNn[VëÅÄÄtTŸ?°_€ mùcÜô•«Ã¯kŸþy³éîì=°ëiëw´sçΡC‡ÚÚÚ®_¿Þxgû÷b"·mYmÓÎ àQð¸+eb*+99™çùGózêææ¦R©´ZíÆwíÚõh6² å>ètä ³‡ÝŠæÃvC:Ò#ÞçÐ95~¡J¥jåûc~‹rrrŒ_¡Ó8æ! Àã /’€–EFF8p€ã8BȧŸ~zâÄ __߇ûâßG¡ÆÝò?vìØcs8Ð ±f• 9tèF£),,üùçŸÇg"¢øùùùûûËT*U`` ƒƒC{ÛÛ>B3Œ»å1 V«›Ã0ÅßßÿÆùùù7n\»vmNNNYY™‰X˜ššš——§P(!Ý»w÷öö¶¶¶~°MnìQh†q·<bbbxžlÀ”¨¨(AÆÏq˲eee§OŸné¶X£+þ#2hxèÍ@ x¤˜qý1bD~~þáÇEQ$„$$$¤¦¦>ÜÕÕµ¤¤„Ò¯_¿ùóç{yyݼysûöíÆ!gæÌ™~~~ëÖ­»~ý:¥4,,ÌÚÚ:""bîܹjµºªª***êøñãAAAo¿ý¶““Óå˗׬Y#‚é&………UWW=ztΜ9^^^•••QQQ'Ož¤”ʹ666[·n]¼x±»»û¤I“¦OŸÞÎfØÛÛÏ™3gĈ”Ò”””M›6iµZÓ4Ñ-¦+tvvž={¶¿¿CCCJJʆ jjj [Íš5kĈJ¥2+++""âÆ†£6ë L÷aÓoÔ¥rzŸ>}fÏž­R©LoðÛVQQqæÌãñßÎ;u:]PPÃ0*•*##C„ÔÔÔ„„„¢¢"ÃÐg×®]‚ „„„ÈaàÌ™3ùùù‰‰‰IIIÉÉÉ‚ Ï›7////!!áêÕ«‚ 9räžK0Μ9“‘‘qåÊ•´´´‹/jµÚÒÒÒñãÇïE²\ºt‰ã¸v6ÃÕÕõäÉ“Z­öÂ… ‰‰‰<ÏŸ8qÂt#Mw‹‰ {õêuîÜ9­V›œœ|ážçcbbÜÜÜä­N:Åó|jjj|||yyyNNNpppÛÊt6íðF]#BZZÚ•+Wâãã+**ÊÊÊ&NœøÐGÞO«Õ6º­ÓéBCC†Y¿~½N§[¾|¹R©ä8nΜ9•••†+þîÝ»u:!ÅÄÄètºE‹É…×­['Ïó .T*•¶¶¶GŽaìØ±¦¯§r=K—.•ëyë­·xž74RÎݶm[Ïž=å”v6cÓ¦M‚ ,[¶L.¿aÃAf̘Á²-®92Ý-&*üòË/Aøè£ä¬Ï>ûŒçù¥K—²,+[¹r¥œ5yòäÊÊʳgÏuëÊt6ÛáÆ]*§lذAÞ|âĉ†Æ::šã¸îÝ»ûéÝ»·\ÆD·˜¨ÐÊÊJ£Ñdff²ºuëvîܹիW³,{ýúõ¬¬,ÃQyò䨨(ggçmÛ¶Éß;vX[[ïÞ½{Μ9Ó¦MÛ·o߃ 2 =uêÔ×_}ÿþý*•êØ±cÆ7;ЦM›”JeTTÔ¬Y³^zé¥%K–ÄÇÇ¿þúë&nÚ‡+•ÊÈÈÈiÓ¦M™2嫯¾bYöÀ’$mܸ‘eÙ¯¿þzÖ¬YS¦LÙ»w¯‡‡ÇŽ; Úv\&úpùòåçÏŸ0qŒõõõáááï½÷ÞÔ©S¿ýö[µZýÓO?edd`D¿ fÜ=tèÐßþö·°°°5kÖBªªªV¯^½qãFyH´zõj//¯×^{mÅŠ’$=zôÀcÆŒ¹_ ¿K’¤ .¬ZµÊÒÒ’rþüù%K–èõúû±¯ÈÈH;;»… ®\¹R¾#š˜˜¨ÑhLlbº[LT¸}ûö®]».X°`íÚµ„âââE‹ìÝ»÷À ‹B›•’’÷þûïËÅ.^¼xÿ~μ%,ËZXX >ÜÂÂ"))©ªªÊøâ˲lïÞ½½½½óòò®_¿.I˲ò‘ã8†aDQ”G òGãk¥B¡ ”¦Ê†á8N’$I’ŠŠŠšývÐñãÇöÙgƒvsssuu8p`QQQVV–¡Ú¦{iO3 ÇÈ0̈#ììì²³³óóó%I2=ô1Ñ-¦+dYÖÚÚzøðá555)))†f~Æ ³´´¼té’V«5´ÐÜƒŠ‰‰ñõõ5݇&zL~œ†RÚ­[7µZ]ZZ𙙉(¿!myÒK¾KÖÒÕßtnÈφ7MßµkWtt´¯¯¯‹‹‹^¯ïðýšÐ†}µ¹ÓÚ–Õzr ì>|¿€ŽÒ–çM_é:ü:øùçŸ7›ÞèNàƒ¼þ¶a_mî´¶eµM;+D€ß¢ßÀKLL}%''ó<ëo{ ~ÃX–ÅwZ¶úßG¨R©ä·Ê<–rrrŒ_¹Ó8æ! Àã /ž€–EFF8p€ã8BȧŸ~zâÄ __ßGíÅ¿÷£‘æÖ~ìØ1¹ ð€±f• 9tèF£),,üùçŸÇgâZïçççïï/P©TímoG»4·µZø¨ý‰ÐI˜ýýý£¢¢†zèС={öxxxlݺõå—_né Î0Œ!ë½÷Þ HJJ¢”v@«;Îýh¤q÷£<<QQQ‚ Œ?žã8–eËÊÊNŸ>ÝÒ=½ÔÔÔ¼¼<…B!|4¯õ÷£‘»wïÖét!!!­¬-&&†çyCàA2ãâ;bĈüüüÇ‹¢HIHHHMM>|¸««kII !¤_¿~óçÏ÷òòºyóæöíÛÃÀÌ™3ýüüÖ­[wýúuJiXX˜µµuDDÄܹsÕjuUUUTTÔñãǃ‚‚Þ~ûm''§Ë—/¯Y³FÓM ³±±ÙºuëâÅ‹ÝÝÝ'Mš$Š¢““ÓìÙ³¬P(²²²6oÞ\TTdؤõ$„8;;Ïž=Ûßß¿¡¡!%%eÆ 555raÓ{1«ÍrzŸ>}fÏž­R©*++£¢¢Nž<ù¨ž:»ŠŠŠ3gÎÿvîÜ©Óé‚‚‚†Q©T‚ ¤¦¦&$$[»víÁ0H:sæL~~~bbbRRRrr² ÅÅÅóæÍËËËKHH¸zõª G޹çú¹yDuéÒ%Žãúõë—””¤ÕjcccãããyžÏÈÈðòò’Ë›ÕÈ^½z;wN«Õ&''_¸pçù˜˜777Bˆé½˜6msLLŒ iiiW®\‰¯¨¨(++›8qâ£9†x̘1GȲl£1ŠüÑ‚²`Á‚^½zmܸ1 `äȑ˗/·²²2”l4 Æ0Œ££cttôÈ‘#¶mÛfccóÏþsíÚµAAAÆ ‹‹‹ ~ñÅM¹žìììAƒùûû‹¢8wîÜ~ýúýãÿxú駃ƒƒ×¯_ß³gÏ¿üå/,ËšÛÈ?þX­V¯]»vĈAAA›7oöõõ•«2½Óš¶YNÓÇÇç‰'ž°µµ•?ð<¿oß>¹Ù­o¤R©Ôh4™™™†&uëÖíܹs«W¯fYÖô^L›¶YN1ÔÆ0Ì‘#GAÆ à~ë˜nnn... †)4I’¡ÌÕ«W)¥<ÏR***äj[³wÃN !ÙÙÙžžžóæÍóðð°³³³¶¶fYVޏf5rÀ€ŽŽŽééé†2¥¥¥£F¢”J’db/­dÜfY]]ü¥4---88X¥R;w®õu@˜[Z»¡×ë=<<!<Ï·­õõõÍî« ÷§OŸ¾lÙ2BHJJJUU•a<<üË/¿¬¬¬|ùå—Õjõ±cÇ2220"x„0 3}úôììlAA(((øøã W–e·lÙR^^.‚V«Ý½{÷¶mÛ4‰U£Æ‘C«Õž={Ö°$õ7ÞáóÏ?oͪQãz&L˜ ?†(Â… ~÷»ß•••%&&Ê5›ÕH†a-Z”››+×–™™9uêT¹=¦÷Ò¨žÈ–wßú IDATÈHA £Æ¦mމ‰9~üø²eËŠŠŠä:Oœ8ѧOŸöÿÊàžÌ»¡'¯>|¸……ERRRUU•ñÂK–e{÷îííí——wýúuI’X–Õëõ„Žã†EQâÈå,™B¡ ”V£0 Ãqœ$I’$Y[[7mÌøñããââ!Æõ0 cii9dÈBHbb¢(ŠÇ×ÜúFÊ…­­­‡^SS“’’bÈ2½—fÖıËá“RÚ­[7µZ]ZZš™™i\ÌlÉ#›–îÚ™ÎmƒE‹5»,s×®]yyymkƒYl©p‡é}ªLø <¯ÝÒÝÑÖ<ª¯Æ¯aR©Tò+ñK999Ư}móàñ†—Ÿ@Ë"##8Àq!äÓO?=qℯ¯ï#ûâßG¿…÷~ìØ1¹Ã •X³J‡„„:tH£ÑþüóÏãÆ36üüüüýýå*•*00ÐÁÁ¡½í½oýÞ“Z­ üír€‡ÂŒ@èïï5tèÐC‡íÙ³ÇÃÃcëÖ­/¿ürKW^†a Yï½÷^@@@RR¥´Z}·ö7n\||üßþö7–5ï/’f=”Cø­S´¾èâÅ‹œœÞzë­~øRºk׮Ç/^¼øðáâ(šÞ¶¤¤¤´´ô‘‚‹££cÿþý{ôèñ°Ðy™GŒ‘ŸŸo{ ©©©Ã‡wuu-))!„ôë×oþüù^^^7oÞܾ}»ñèdæÌ™~~~ëÖ­»~ý:¥4,,ÌÚÚ:""bîܹjµºªª***êøñãAAAo¿ý¶““Óå˗׬Y#‚é&………ÙØØlݺuñâÅîîî“&MEÑÞÞ~Μ9#FŒ ”¦¤¤lÚ´I«ÕÊ圜fÏž=xð`…B‘••µy󿢢"³ú«¥=Κ5kĈJ¥2+++""âÆ†¨ßRîßÿþ÷ÀÀ@–e7nÜG)õööž5k–——WuuõÙ³gÿóŸÿH’Ôš–Èé}úô™={¶J¥ª¬¬ŒŠŠ:yò$þþègΜ1^‹±sçNNÄ0ŒJ¥ÊÈÈ!555!!¡°°°¨¨(//O¡PBvíÚ%BHHˆÏœ9“ŸŸŸ˜˜˜”””œœ,Bqqñ¼yóòòò®^½*‘#Gî¹îC®'&&†çùK—.qçêêzòäI­V{áÂ…ÄÄDžçOœ8!×Ó¯_¿¤¤$­VÏó|FF†———\ÕîÝ»u:¡…fíñÔ©S<ϧ¦¦ÆÇÇ———çääËõ˜ÈݱcÇ¥K—ªªª®]»vþüù &0 3jÔ¨ÜÜÜÒÒÒS§N]¾|Y„o¿ý¶Ù~hÚ’˜˜AÒÒÒ®\¹_QQQVV6qâDÜ/èZ­öôéÓÆåèèhNÊ0Ìúõëu:ÝòåË•J%ÇqsæÌ©¬¬4ÂFa&&&F§Ó-Z´H.¼nÝ:Axž_¸p¡R©´µµ=räˆ cÇŽ5}—ëÙ¶m[Ïž=å†mÚ´I„eË–É5oذA„3f°,»víZAÞ}÷]9ë“O>aÕªUòü\+aÓ=Ê»X¹r¥\íäÉ“+++Ïž={Ï\Žãþüç? ‚ðÅ_(•Jy¿{÷îÕét/¼ð‚B¡°²²úî»ïAøãÿØ´UM["§lذAÞ×ĉ+** -€ö2srrrssíííå,–eSSSMBžç-,,ä¾¾¾<ϧ§§+•J9eÁ‚‚ „……™^E"×cXê©T*5Mvv¶¡žð<ÍqœÏOùˆZ÷H¹~ýzVV–ü‘a˜ƒ ‚ w‹éÜ7ß|S„Ï?ÿÜp˜ò_Æ “›áïï?kÖ,Ãâ[Ó-‘S È0Œ\›ax M™1Gh‚›››‹‹KBBBMMœÒì´V#†2W¯^¥”ò.....îСC[·n•$©¥y>CK Œ÷•––¬R©Î;׆Ãè Ì„-]‹õz½‡‡!„çù¶5¢¾¾¾Ù}™ûPµµ5!¤²²Rެrbfffnn.¥túôéË–-#„¤¤¤TUUFíaggG¹uë–qbUU!ÄÊÊÊtn³îÙ³';;ûwÞ zþùçÃÂÂ"##?øàƒ¶-x‘ÿžèÖ­Ã0X2Ð,3¡N§kô¼y—.](¥ÅÅÅ:ŽRêèèØÑÍ3Oaa!¥´¼¼|Ú´iÆOtPJ9Žûàƒ$Iúöî=ª©3ßÿ¾$rkâ%•K jÃÅ¢¢”rÊxY«vfÚŠg—N§ÚÖ¶ P´0mÑ9=/=mg†VQ¤rqÄUíÒê©G¤#Cäl¡ d %H’½ƒÚ#%{ÿx~“Ã%o}¿þ"Ï~.Ÿ®å§Ïeg¯X±¢ªªJÅàààE‹rDƒÁ Âc=Ö¿ÐÇLJ¦i£Ñèøê™IÅÊÊÊ„„š¦,X°cÇŽ¸¸8½^Ÿ••5’Iö“&M¢( ®8àÄ”«®®ÎÏÏϾ}5eÊ•Je0 Cwww{{{hhèŒ3Hå‰'Þû_iioo×ëõ³gÏ Áf³Ùl6WWWAd2™\.ojjªªªêëë³Ùld—n”#vvvÖ××Ï™3‡ôæáá±hÑ¢üñüù󮊢H²µ}âëååÕÜÜ|öìYš¦m6[yyynn.MÓ¡¡¡#Œ‡œ;µßWtt´Íf«®®åm<œH„û÷ïaÿþýëÖ­{饗òòò&Nœ˜••Ef¹¹¹nnnùùù6lxíµ×Ž;v_&ˆ{÷î•J¥yyyqqq¿þõ¯ßyç­V»zõj³Ùl0¶nÝúæ›ofeemÚ´‰ar–g4öìÙÃ0Ì_|÷»ßýîË/¿ôõõÍÍÍmoo¿ãUòTeTTÔš5küýý{zzêêê.\¨V«ccc׬Y³~ýzТЋ‹EQܹsgyyùüùóäïÞÞ^µZýöÛo¿òÊ+ÇW©Tß~ûm}}=f„c€¦éuëÖéõzžçyžoooÿ¯ÿú/{"aæóÏ?ïîîæyÞb±äççgee §Fû'!‹ÅÒÿ ÿoûÛÇ)‡4¸š¦HÇ™ÍæsçΑc“Ë—/'O(ò<_QQ±xñâ®®.Nw§FŒøæ›oÚ¿–~ø!==Ý^áŽW³³³É¥5kÖÐ4=}úôœœ“ÉÄqÏóW¯^MNN&æä䨛‰F£9wî\ZZZGGé³°°ÐßßßñV€Ÿ9çÖÉ1ËyóæM˜0¡²²²§§§ÿÆÃ03fÌ jmmmnna˜¾¾>Š¢X–%Ë}djB>’K„D"±/REÓ4˲‚ ‚ÐÑÑANÁ ðâ‹/’Ó¡ýû!a 6OOO½^ßÖÖFN]Ò4íââ2gΊ¢t:ÍfcYÖ>hÿïbÄ &Ì;×ÅÅ¥¦¦Æb± øZ\eY6$$ÄÍÍ­¢¢‚”³,+“ÉBBBnÞ¼YSSC¾„‘|‡$_Š¢¨P(T*•Ñhlhh* p7›ddF2Üj›ã«wÿüsRyÍš5ׯ_ïééqœ¿üòK«ÕºlÙ2‰DâêêúÕW_ñ<¿råJ‰D²víZžçwíÚ%•JÉâaYvpý;I"Ôh4V«5++kÚ´id7‘”ddd0bccM&Ó… pŽà¡àÄ¡Z­~öÙg333úé'›Íöõ×_‹¢øøã™6~õ«_õöö~ôÑG¤rnnn}}ýW ===EQìêê²Ùlÿ÷ÿ·}ûöwß}W¯×Ûl6² J–1I?â²þXaÓ¦M×®]# ª¤$55•„qâÄ‰ŠŠŠÐÐÐ… bRðàsbP¯×ûùù%&&úúúzzzº¹¹1 3a„!+ûøø´¶¶¶··“¢(Ž$eggÏ›7ïäÉ“¥¥¥¥¥¥§NÊÌÌaȶNÅ3¶nݺ5 äöíÛäQkkk£¢¢”JeYYÙ=FÉáºuëJJJ’’’üýý]\\¤Rép5år¹»»»Õju6š£G>÷Üs§OŸž5kVZZZIIɇ~8ܼjäñÜc&“‰¢(…B!Àƒo¤3B©TºyófAV¬XQUU%Šbppð¢E‹†¬l6›oܸáíííl4¢(VVV&$$Ð4½`Á‚;vÄÅÅéõú¬¬¬ÑÄsMš4‰¢(£Ñˆƒ£¾‘Îe2™\.ojjªªªêëë³Ùl111f<---sçÎ%u<<<&Nœèx†äååÕÜÜ|öìY²ÉW^^ž››KÓthh(EQdCÎþtüãP\Ñ4m=::Úf³UWW߃¡`”F:#4™Lƒ!,,lëÖ­mmm‘‘‘111 à w ôСCéééÌÊʲX,«W¯öóós1}úôœœ“ÉÄqÏóW¯^MNN&ýÓ4MF_³f MÓŽã\ÿŽ78äã999<ÏÛ§›ä Âþw¡ÑhÎ;—––ÖÑÑA†+,,ô÷÷¿»/î1'NsÐ4íââ2gΊ¢t:ÍfcYÖþ³,,Ë’%Mû4ˆa…B|íÚ5½^_VVöøã+ŠÖÖV77·Áý¿øâ‹†a™LróæÍššAì¿DòlHHˆ››[EE… ŽãP¿½½ÝÁ $f†a†ð¸Å€û"ûúúúW (JE…B¡R©ŒFcCCCÿ ð súX#™dÑÏßßß`0¿/^œŸŸßÒÒI\ÿÈ‘#­­­ŽG\î8ûÕäää;:z#ÿrà1Žçû­Vkgg'™·I¥ÒM›6‘ó/CÖwü¤£4Ü©™q|ãø3` ÃL™2eúôé‰äÒ¥K)))§OŸ‡7~‘Pÿ|¢ÿ ¾qœ2 Óò7ÜÄŒÒÀÝV*•#y™;ÀCª©©é_Þk;à2² <Úð*$ø§íÛ·†††âÕ¾ý©Õê‚‚–eïw 04f¬:R*•2™l¬:¼g¢¢¢²³³Ïœ9sñâÅæææ•+WŽa.W©TøŸ€Ö˜%Bš¦ÇõŸû^xA«Õ¾÷Þ{ 3¢˜G^Ú´isæÌñññ™2eÊäÉ“Çvö6Þ_ ŒÒ˜%Âñæíí=kÖ¬©S§ŽyýcÇŽÍ›7oîܹ§NEqtaÀCFâTm¹\"‘H®\¹²oß¾ŽŽŽá*Ϙ1#))I©Tr—››+“É–.]š””$‚ƒ!‚‚‚ââânܸqáÂ…ƒ ‚°eË–ˆˆ†a"""öìÙsøðáÒÒRQ‡‹g¸úCŽ(Š¢Íf# ¾šššzãÆ³gÏnذ! Àl6çåå?~¸Êîîî™™™)))>>>«V­"åþþþñññJ¥Òqsx VVVZ,–’’­VËq\}}}@@¹šŸŸoµZŸ~úi²èãã£Óéxž¯­­½xñbgggII Ïó‰£ÔÝÒÒb4‹ŠŠêêêxž?~ü8˲¹¹¹555===W¯^-//_¾|9MÓâ²þo0##Ãjµ®^½ºåâââúúúË—/“±X,F£ñÅ_²Ãâââ¶¶6FÃq\MM ˲†| —/_Öjµ&“©««+66륟ôôtžç7nÜ(•JY–ݶmÏóŸ|ò Ù„ÓÒÒ8ŽûüóÏIå5kÖ\¿~½§§Çq"üòË/­Vë²eË$‰««ëW_}ÅóüÊ•+%ÉÚµkyžßµk—T*%C8ˆ‡eÙÁõïhÈD¨Ñh¬VëÖ­[í7ÂqÜßÿþ÷!·I嬬¬iÓ¦‘ ¤$##ƒ45™L.\À9R€„{„jµúÙgŸÍÌÌüé§Ÿl6Û×_-Šâã?>dšùÕ¯~ÕÛÛûÑG‘ʹ¹¹õõõw\ôôôE±««Ëf³ýßÿýßöíÛß}÷]½^o³ÙÈ‚*YÆ$ý8ˆgÈúwM„ÿþïÿ¶ßˆN§{òÉ'çÎ;ä ‚°iÓ¦k×®‘åVR’ššJšŸ8q¢¢¢"44táÂ…˜<œØ#Ôëõ~~~‰‰‰¾¾¾žžžnnn ÃL˜0aÈÊ>>>­­­íííä£(Š#ÉFÙÙÙóæÍ;yòdiiiiié©S§233A²­SñŒ’}_SÅšššùóçÏœ9ó»ï¾²ò­[·”ܾ}ÛÞ¼¶¶6**J©T–••G¨à'f„ëÖ­+))IJJò÷÷wqq‘J¥ÃÕ”ËåîîîV«ÕÙhŽ=úÜsÏ>}zÖ¬Yiii%%%~øáp3§‘Ç3¶L&EQ …âî¦t£lck¤3B©TºyófAV¬XQUU%Šbppð¢E‹†¬l6›oܸáíííl4¢(VVV&$$Ð4½`Á‚;vÄÅÅéõú¬¬¬ÑÄ3¶&NœHQTggçÝ­¸Nš4‰¢(£Ñˆƒ£‚‘Îe2™\.ojjªªªêëë³Ùl111æ4---ö4‰':žyyy577Ÿ={–lò•——çææÒ4JQÙr³?ÇxÔ š¦}}}íŸyæA.]º4òæÑÑÑöØ¢££m6[uuõè€ÑéŒÐd2 †°°°­[·¶µµEFFÆÄÄ0 3Ü)ÐC‡¥§§1}úôœœ“ÉÄqÏóW¯^MNN&ýÓ4MF_³f MÓŽã\ÿŽ78ÜãÇíÚµ‹Ü ÏógÏžµOsrrxž·OFIåþ÷¨ÑhÎ;—––ÖÑÑAšúûû;ÿõÀ¸pâ¼MÓ...sæÌ¡(J§ÓÙl6–eí?˲,YÒ´Ot†Q(ÁÁÁ×®]Óëõeee?þ¸B¡hmmussÜÿ‹/¾¨Ñh†‘Éd!!!7oÞ¬©©Á~b“eÙ77·ŠŠ AÇ3 ~{{»ƒAIÌ Ã0 3àq FJ~†ô‰'žèèè¸råJ__Ÿ}ˆþwM>Ú¯’Š¢DQT(*•Êh4644ô¯÷—ÓÉÔg$Ëzþþþƒü½xñâüüü–––ÈÈHòüàúGŽimmu<ÊàrÇñد&''ßqÐ!‘D8iÒ¤¾¾¾‘ß»ã`î®9Œ‡q<ÁߨØhµZ;;;ɼM*•nÚ´‰œ²¾ãß ¥áNÍÜqÐþ‰pâ€ûlè‹a˜)S¦LŸ>]"‘\ºt)%%åôéÓâðÆ/êŸOôßÅ áááV«5??39€GÒ8Άé?ùîbpä.ìûŽðø£ÛJ¥r$/sxH555ýË{m\F€GÛÃø*$Û·o/,, }p^ívôèÑÚÚÚòòr–eï}jµº  à¾ #$«Ž”JeDD„L&«GÉÕÕõ/ùKPPPQQQ[[Û}y±J¥z þϳDHÓôõ/þ‚ fΜù·¿ýmõêÕ}}}‚ Üû´ïcîwãÅ××—a˜öööû•à¡àÜŒP.—ÇÇLJ„„H$’+W®ìÛ·¯££c¸Ê3fÌHJJR*•ÇåææÊd²¥K—&%%9NKAAAqqq7nܸpáÂÁƒIý?üá“'ONNN¶7ß²eËc=¶iÓ&ARSSÝÝÝ333SRR|||ª««çÏŸOÓôüùó÷ìÙ£V«kkkñ‹_8~âĉñññááá?ýôSuuuFFÆ­[·È%//¯ 6,X°@Åêêê½{÷Z,–Á‘ˆaÕªU¤Üßß?>>^©TšÍæ¼¼¼óçÏß—uZ­ÀÀÀÊÊJ‹ÅRRR¢Õj9Ž«¯¯ Wóóó­VëÓO?M}||t:Ïóµµµ/^ììì,))áy^"q”z£££[ZZŒFcQQQ]]ÏóÇ'‡MÊËË»ººú7/))éîî&%ÅÅÅmmm†ã¸ššš¼¼¼šššžžž«W¯–——?óÌ3J¥ÒAðÓ§O/++³X,UUUÇi4š)S¦P5yòäóçÏ[,–ŠŠ NÇq\aaáç_ÄÀ²¬F£!ßÀåË—µZ­ÉdêêêŠÅz)ÀC)==çù7J¥R–e·mÛÆóü'Ÿ|Â0 5(¦¥¥q÷ù矓ÊkÖ¬¹~ýzOOãDøå—_Z­ÖeË–I$WWׯ¾úŠçù•+WÒ4­Õj¯_¿Þ¿yii©Éd"%ÆjµfeeM›6eY–e×®]Ëóü®]»¤R)MÓŽƒ?pàÏóï¿ÿ>¹úá‡r·uëV†aöîÝËó|ZZ¹”‘‘Áóüo¼Aö7 {IFFik2™.\¸€s¤¥™3gFFFzxxóçÏç8îØ±cäŸõ‰ðâÅ‹]]]~~~¤2MÓÿûß­V«ãDxæÌžççÎK: ‹‹ I"ä8®ÿ™Õ—_~™çùÏ>ûŒd,ÁK¥RƒÁÐÐÐ •JÉU…BQVVö§?ýÉÅÅÅ`0èõzû¥Ù³gswøðáÁÉlp ¤Ä>(MÓ䣢¢0)x@8±G¨×ëýüü}}}===ÝÜ܆ڞìS IDAT™0a•}||Z[[ÛÛÛÉGQG²1–=oÞ¼“'O––––––ž:u*33S„nªÙwõœ ~öìÙÞÞÞßÿ½}÷Ñh4FGG‹¢âíí}ûöíÒÒR{W ÃL:uä1ܾ}›ü!ŠbmmmTT”R©,++ÉÀxs"®[·.--¢¨êêêžžû$i0¹\îîînµZæèÑ£z½þõ×_ê©§ž}öÙÔÔÔœœœÍ›7þt‰ƒàÝÝÝ)ŠúñÇû×·ÙlE¹¹¹Qe6›í1444´´´Ü]H&“‰¢(…BAÓ4ŽÌ<Fš¥RéæÍ›AX±bEUU•(ŠÁÁÁ‹-²²Ùl¾qㆷ··³Ñˆ¢XYY™@Óô‚ vìØ§×ë³²²úúú$‰T*íëës¶[ÇÁ_»vMÅÉ“'nH.uww¿öÚk$5Úã¼»G2&MšDQ”ÑhDx@Œô9B™L&—Ë›ššªªªúúúl6[LLŒƒ®–––€€ûnŸ‡‡ÇĉoŒyyy577Ÿ={–¦i›ÍV^^ž››KÓthh(EQF£‘eY²_HQ”\.Ÿ4iÒwÚßÞÞ~åÊ•JD CCC»»»:ôÃ?èõúÙ³g ‚`³Ùl6›««ëȳ MÓÑÑÑö±¢££m6[uuõ›ÀxéŒÐd2 †°°°­[·¶µµEFFÆÄÄ0 3Üá—C‡¥§§}ºD"¹téRJJÊéÓ§Åá_$ÃÇ!ÙZ³ùÄ8eàn+•Êá^“ðhjjêÿˆ9YmxüÓöíÛ CCCÞWûªÕê‚‚–eïw pï0cÕ‘R©ŒˆˆÉd#©üþûïWTT¼÷Þ{ ó/ìØ±£¢¢"22ò¾dS•Jñð&r¸ c–išy yì±ÇfÍš•””4`9mÚ´Y³fyzzŽUTNqêàÑ0f‰ÐY4MËd²?üpÀ¤©î%‰Sµåry|||HHˆD"¹råʾ}û:::†«>^©TšÍæ¼¼¼óçÏ‹¢èÔ·¦ÀÀÀÊÊJ‹ÅRRR¢Õj9Ž«¯¯ Wóóó­VëÓO?M¦t>>>:ŽçùÚÚÚ‹/vvv–””ðûlffæO?ýd³Ù¾þúkQüñ!Ó̯~õ«ÞÞÞ>úˆTÎÍÍ­¯¯¼Æø—¿üE£Ñ,_¾ü׿þõ]L¼Aسg"++KÅööö½{÷þôÓO7oÞ>>­­­íííä£(ŠCî´ ‚ðŸÿùŸÿó?ÿ³uëÖ¢¢¢»Ë…䯯FQ9޳—˜L&Š¢¦L™â ù­[·”ܾ}ÛsmmmTT”R©,++s60x(81#\·n]IIIRR’¿¿¿‹‹‹T*®¦\.www·Z­#éöÒ¥K ܲeËh!{{{”Ô;š>I*U(˜<ªF:#”J¥›7oaÅŠUUU¢(/Z´hÈÊf³ùÆÞÞÞ#éYÅ>úhÙ²e¯¾újMMMÿK}}}‰D*•öõõ0α5iÒ$Š¢ŒF#Ž<ªF:[’Édr¹¼©©©ªªª¯¯Ïf³ÅÄÄ8˜'µ´´Ì;—Ôñðð˜8qâpõoß¾ýþûï³,;`7Îh4²,N årù¤I“ÆurFÓttt´}ˆèèh›ÍV]]=~#Àý5Ò¡Éd2 aaa[·nmkk‹ŒŒŒ‰‰a¦ÿ³ ý:t(==ýàÁƒYYY‹eõêÕ~~~úÿöÛo=úòË/(\²dÉÎ;³³³]]]_zé%//¯<ØÎ;—,Y’˜˜¨Ó醛áõööªÕê˜ÍæçŸ^¥R yÌ N–ùàƒ>þøã¤¤$Š¢ßxãüü|…B1då/¾øböìÙk×®MKKE±¨¨¨¡¡aöìÙÃu.Š"y0Ã×××^øùçŸÏš5륗^ÚµkWooï‘#GL&Ó¿ýÛ¿<æþf̘ñÄOxxx8¨S]]]ZZúûßÿžT»xñâ;ï¼s¿fàÁBÓ´««ëÂ… .\(‘Hhš–H$öçÿX–%…öú ÃL:uéÒ¥O<ñ„D"¹xñ¢Éd"3H2•¼È9d'“'Oþå/À0 ©Ð¿rÿæýã!K$ûa™nβ,˲$ì%K–ÐÅ¢‘ÿ2µ¿¿?ýOK–,¹~ýúÅ‹ïî%G÷þÐ&~€àgÂéÏÈwËΞ=kµZ;;;]\\æÌ™Ã²lFFÆ¿):†ƒŽl üLŒãKh†™2eÊôéÓ%É¥K—RRRNŸ>”q\ýc¦ÿê¢ È‚0þè¶R©Ä{øàÖÔÔÔÿ%s² <Úð*$ø§íÛ·†††’Wûøx×ýÜ/jµº  €eÙûÜ’±êH©TFDDÈd²!?Þu?÷‹J¥ºïÉîf¬:¢iºÚðqäÞ~ûíùóçWVVŠ¢8V±Ý…»Ž.c6#+F£ñþfAøùp.Êåòøøø‰DråÊ•}ûöuttŒføÔÔTww÷ÌÌÌ””ŸU«V­[·.,,ìÓO?mnnE155ÕÍÍí³Ï>{ë­·ž|òIŽãNž<ùõ×_Û3åŒ3’’’”J%Çq¹¹¹2™léÒ¥III‚ PpãÆ . €\ÍÏÏ·Z­O?ý4YQðq8ÅÅÅmmm†ã¸šš–e9Âó¼½aqqñ?þñ¿ýíouuuZ­öúõëf³ù•W^!W}||t:Ïóµµµ/^ììì,))áy^"‘PÝÒÒb4‹ŠŠêêêxž?~üøç_‡¡ÑhH·—/_Öjµ&“©««+66ë¥'ö?øàƒ_þò—QQQ»wïž6mÚúõëæî7išöööÖëõÁÁÁááá6›mð^ãĉ¿ýöÛ'Ÿ|2**êå—_áõ×_'ƒÆÅÅþõ¯;wnddä»ï¾;sæL{<7n”Ëåk×®]ºté¼yó¾ýöÛ¥K—þû¿ÿûàd68 RXTTõú믳,›’’2𛀇ÛÌ™3###=<<ÈÇùóçswìØ12Ǻ»!™„õ?#: !©0aÂr•¦éÊÊÊÖÖV2ç»xñbWW—ŸŸŸýêßÿþw«ÕJ®ž9s†çù¹sç’®ÂÃÃãââÂÃÇ48 Rb¿Yš¦IoQQQ˜ŸÖÖÖöövûÕþ{xÙÙÙóæÍ;yòdiiiiié©S§233AnŸop·oß¶÷\[[¥T*ËÊÊœ¼?xp9±Ð·nݺ’’’¤¤$©T:~a„\.www·Z­ÃU8zôèsÏ=wúôéY³f¥¥¥•””|øá‡w=Ÿ3™LE) Ì%#J¥ÒÍ›7 ‚°bÅŠªª*Qƒƒƒ-Z4®Á9f6›oܸáíí=\Q+++hš^°`ÁŽ;âââôz}VVÖgG›4iEQx´à3Ò¡L&“ËåMMMUUU}}}6›-&&æ¾ÏZZZ컀'N${yy577Ÿ={–¦i›ÍV^^ž››KÓthhè;§i:::Ú~ÑÑÑ6›­ººzœîî‹‘ÎM&“Á` Ûºuk[[[dddLL Ã0äXÊýrèСôôôƒfeeY,–Õ«WÛ·{zzêêêžyæµZýÍ7ßÈd²õë×SU\\,ŠâÎ;—,Y’˜˜¨Ó醛áõööªÕê˜ÍæçŸ^¥RÔ××cFð(q"}ðÁüqRREQo¼ñF~~¾B¡·Øîì‹/¾˜={öÚµkÓÒÒDQ,**jhh˜={6¹º~ýú?üpÅŠÿñÿAÓtwwwZZÚ‰'DQœ1cÆO,#ôÐ?Î0Lÿ§8üp <ªþè¶R©ìÿÖ˜¦¦¦þ¯g˜óàц—Àð¶oß^XX:ÜË~ÕjuAA˲w×ÿ(›P%¿®•JeDD„L&®‚J¥r&ïh”Í(ŠbƯë·ß~{þüù•••¢(Rõ /hµÚ÷Þ{aþ¿AišMesj\g„F£‘dAŠ¢¼½½gÍš5uêÔñÀYÎ%B¹\"‘H®\¹²oß¾ŽŽr)55ÕÝÝ=333%%ÅÇÇgÕªUëÖ­ ûôÓO›››7oÞÁ0LDDÄž={>\ZZJz{{oذ!<<œçù“'Ož!yK£ÑX­Ö¬¬¬iÓ¦‘“œùùùV«•$B–e×®]Ëóü®]»¤R)ÉU¤É{ï½G:|î¹çL&SyyùA÷OJ222HóØØX“Étáœ#€q1sæÌÈÈHòqþüùÇ;vÌž–8ŽëF´"¤(êå—_æyþ³Ï>³OøH“ &4M÷ÝwÉ ¶ƒû'%öxhš>sæ ÏóQQQ˜À9±G¨×ëýüü}}}===ÝÜ܆±§1âÖ­[ÎF ùCÅ7nxzz:¨<¸ÿÛ·oÛ›×ÖÖFEE)•ʲ²2gÀŸ''áºuëÒÒÒ(Šª®®îéé‘J¥ãÕ]2™LE) š¦qdFb¤‰P*•nÞ¼Y„+VTUU‰¢¼hÑ¢q ÎY“&M¢(ªÿ3Žôz™L&—Ë›ššªªªúúúl6[LLŒS[q6›¢¨!O„Þ5𦣣£íaDGGÛl¶êêê1m#šL&ƒÁ¶uëÖ¶¶¶ÈÈȘ˜†a†<Ø2¤ææfQ£¢¢Ö¬YSTTÔÒÒâ¸þÎ;—,Y’˜˜¨Ó醛áõööªÕê˜ÍæçŸ^¥RÔ××cF#äÄá|ðñÇ'%%QÕØØøÆoäçç+Š6×jµ'Ož\¾|ù®]»Þzë-ƒÁà¸þŒ3žxâ û¡Ð!UWW—––þþ÷¿'Õ.^¼øÎ;ïôõõ0$'Ö6išvqq™3gEQ:Îf³±,+Š"YódY–¦éþIˆ”Øl6ûüŒeÙ77·ŠŠ A†kBJ4²2EQ¢(* •Je4`|=˜¿”à€Ÿ•ïðS*•x±<šššìoŒ§'BdAx´õÏ‚££V« X–½ßŒÖ#s#pO[,‰Dr¿­GæF~˜ûÀÿ¦iš¦ïÁ@/¼ð‚V«}ï½÷f\nÿžÝŒÞ”ïooïY³fM:õ~÷ŸsËwr¹<>>>$$D"‘\¹reß¾}äRjjª»»{fffJJŠÏªU«Þyç77·ýû÷'$$¨Tªžžž¼¼¼sçÎ=õÔS¯¾úª\.¯««ûóŸÿÌó|ÿ!üýýããã•J¥ÙlÎËË;þ¼(ŠCöŸšš:yòääädAHÛ-[¶<öØc›6m"%AAAqqq7nܸpáÂÁƒAزeKDDÃ0{öì9|øpii©(Š^^^6lX°`(ŠÕÕÕ{÷îµX,CŽk³Ùú<¸‚〇U```ee¥Åb)))ÑjµÇÕ×׫ÅÅÅmmm†ã¸šš–eI‰N§«¬¬¬ªªâyþ‡~HLLlmmýî»ïyž?sæŒýP‰F£áy¾¶¶öòåËZ­Öd2uuuÅÆÆ’eÆÁý———wuuõߊ+))éîî&%ÑÑÑ---F£±¨¨¨®®Žçùãdz,›››[SSÓÓÓsõêÕòòòåË—Ó4=yòäóçÏ[,–ŠŠ NÇq\aa! l𸾖Áß<¬ÒÓÓyžß¸q£T*eYvÛ¶m<ÏòÉ'd§M£ÑX­Ö¬¬¬iÓ¦‘lAJ’““IýO?ý”çyŽã6mÚ$•J=<<Μ9Ãóüo~ó’!HýŒŒ R?66Öd2]¸p¡oýû×jµ×¯_ïŸKKKM&)ùòË/­Vë²eË$‰««ëW_}ÅóüÊ•+%ÉÚµkyžßµk—T*%CïÝ»—çù´´42tFFÏóo¼ñÃ0ƒÇ`¸îFàa5sæÌÈÈHòqþüùÇ;vÌþ¯?Çq2™Ì^Ÿ”L˜0| å8îûï¿—J¥¤$))‰çùÔÔT{*å8ÎÞ?MÓ$SFEEÑ4=¸lj´;w.Iuáááqqqááá4M¿üòË<ÏöÙgd\©Tj0ôz½=°Ù³gswøða2½0îÃÝøp7rß<Œ'öõz½ŸŸ_bb¢¯¯¯§§§››Ã0ö›ššš““³yóæÁ‰ÐÍÍ¢(³ÙLR5)lhhhii«ã-ýoGf(#M„R©tóæÍ‚ ¬X±¢ªªJÅàààE‹kp“&M¢(Êh4™<úúú$‰T*íëë|UÅÊÊÊ„„š¦,X°cÇŽ¸¸8½^Ÿ••5 æµk×DQìîî~íµ×úŸEÑ>y×€ûh¤ÏÊd2¹\ÞÔÔTUUÕ××g³ÙbbbÆ|Ç‹¦éèèh{·ÑÑÑ6›­ººzÈÊF£‘eY²íGQ”\.Ÿ4iùÛËË«¹¹ùìÙ³4MÛl¶òòòÜÜ\š¦CCC)Š"ÙÎ>moo×ëõ³gÏ Áf³Ùl6WW×ÑdA§nÎM&“Á` Ûºuk[[[dddLL Ã0cûCb½½½jµúÀf³ùùçŸW©TõõõCN¤¾ýöÛ%K–ìܹ3;;ÛÕÕõ¥—^òòò"—zzzêêêžyæµZýÍ7ßÈd²õë×SU\\,Šbss³(ŠQQQkÖ¬)**jiiÙ»wï®]»òòòöïßßÖÖ¦R©Ö®]»sçÎüüüÁãîܹsÉ’%‰‰‰:n¸žS7‡åË—“‡ÿxž¯¨¨X¼xqWW—N§ëj´^\b±Xú?EðÛßþ¶ÿéMFsîܹ´´´ŽŽ2Jaa¡¿¿ÿp½1 ³{÷n“ÉÄóüõë×wïÞ}âÄ û©ÑéÓ§çää˜L&Žãxž¿zõjrr2š¦éììl2Äš5kÈ/¢%$$èõzò€‡Ùl>wî\ÿÓªýÇÍÉÉáyÞ>!òÆÜ>^©TšÍæ¼¼¼óçÏÙ,•••‹¥¤¤D«ÕrW__@®FGG·´´Æ¢¢¢ºº:žç?NN…LŸ>½¬¬Ìb±TUUUTTp§Ñh¦L™BQTqqq[[›N§«¬¬¬ªªâyþ‡~HLLlmmýî»ïyž?sæÌO—(•Êúúzžç/]ºôÝwß]»v­£££µµU"‘P5yòäóçÏ[,–ŠŠ NÇq\aa!éÓÙ&Ož\TTÄqÜ¥K—´ZmwwwSSSTTÔ ž¤sFÃq\MM ˲†çùÚÚÚË—/kµZ“ÉÔÕÕ‹õR€‡@zz:Ïó7n”J¥,ËnÛ¶çùO>ù„aŠ¢¾üòK«ÕºlÙ2‰DâêêúÕW_ñ<¿råJš¦8Àóüûï¿O~øá‡Çmݺ•aFcµZ“““É¥O?ý”çyŽã6mÚ$•J=<<Μ9Ãóüo~óÇ©b÷îÝV«uçΤŸ 6˜Íf{"Ü»w/ÏóiiiäjFFÏóo¼ñÆ]@Ú~üñǤþK/½d6›/\¸0dª&geeM›6T %¤yll¬Éd®9Ο?Ÿã¸cÇŽ‘ÄI˜;w.Iáááqqqááá&L0 R©”4T(eeeúÓŸHâ8n„ äRhh(Çqßÿ½½rRRÏó©©©$ݧ©©©¥¥ÅËË‹|dæÒ¥K$J¥RƒÁ ×ëí}Ξ=›ã¸Ã‡“)šS477_¹rÅÝÝ\¥iú믿æy>&&fpª&Ëd²%öï¦iò½ 7§€ñæÄ¡^¯÷óóKLLôõõõôôtsscÆžB²³³çÍ›wòäÉÒÒÒÒÒÒS§Neff ‚âííýý÷ßÛ÷ Fctt´(Šöû¢(rg/1™LE‘uÔáL™2eÒ¤Iß}÷Ùwìß!EQO<ñ„··÷íÛ·KKKí… ÃL:Õþq„Ëåò’’’Û·o“«¢(~ÿý÷111sæÌÑh4CnõÙ£²ëß¼¶¶6**J©T–••9¸G'N$ÂuëÖ¥¥¥QU]]ÝÓÓcŸ3GÕëõ¯¿þúSO=õì³Ï¦¦¦æäälÞ¼™Lž~üñÇþ•m6ÛCôöö(!©ÅñtÐ××—¢(Žã†¼êææFQ”Ùl&IŽ644´´´ Î[Žðôô¤(êæÍ›ý+ôôôPåêêê BH¢U(4MãÈ À½7ÒD(•J7oÞ,Š+ªªªDQ ^´h‘½‚(Š••• 4M/X°`ÇŽqqqz½þìÙ³¢(Nž>>$$D"‘\¹reß¾}EmÙ²%""‚a˜ˆˆˆ={ö>|¸´´TÅáêS•ššêææöÙgŸ½õÖ[O>ù$Çq'Ožüúë¯EQûÌ~XÆq}2½›0a¹JÓteeekkëAIe™L6 ÄÞ9MÓgΜáy>** “B9'öõz½ŸŸ_bb¢¯¯¯§çÿkïþƒ¢¸ïÇïN:¨\ƒ&¢ž{hˆ?ÂPd†jòG;£ä/Ód””6¥ ¥L3f:©¥©™icíjDÇZ¦Úi2c~4f ‘‹!=9ÁàÁ‘ÈoáäîvÅ!án¿ìwvîƒp?4©<qûÚ÷ûõÞýƒ×¼wß»;?66V’$£’MmÿP(¤ÿ¡iÚ7–-[aÃÃÃc¶ŒŒŒÍ›››³²²,K]]]ô˜å&QóóóKKKAp:CCC&“if÷Ÿ&¯×+‚ÙlE‘%3€(E[M&Ó /¼ …žxâ‰ÆÆFMÓÒÒÒ6oÞôÐC{÷îíîîÎÌÌÌÉÉ‘$ÉXÛòùçŸkš–••µsçÎ?ü°££#òþ‘íÛ·ïÑG-,,t8Íð¾øâ‹òòò#GŽø|¾­[·Z­Öªªª––f„€;bûöí­­­ªªªªj·Û·lÙâñx‡¾ TÅ×^{MîܹSÅÈûëË>Ãë¢Ífóz½ú–ŠŠ UUIä¸;Ÿ={¶´´´¯¯OOQ]]ššz—Ï àÝ$®UŠ¢8wîÜôôtAG0”eYÓ4ý¢¨ ²,¯Y³&66Ön·‡B¡Èû˲,Šâèè¨Ñøýï`0¨OïÆÝYMÓÌf³Õjp¹\á;pGD~Ûõ­Ñ»ðvl^À ˜mÆ~ÆÏb±ðm?À=¬½½]ÿê»nlÍ£ îmáUÜëÊËË«ªªdYžñž_zé¥êêêµk×þo}xš'äÎO@ôb¢ßÕjµÞ¡Ze±Xyä‘„„„ïùŽšæ ¹sç=)ú]EQ¼Cÿµï\ÏwÔ4‡ý?zÔp™D!àÞ3‰K£ºÔÔÔ‚‚‹ÅâóùNœ8QSS£išZ°`ÁO~ò“ŒŒ “ÉÔÖÖvøðá+W®DcÁ‚?ûÙÏ2224Ms:ôûýz())©  `Íš5111mmm¯¾új__ŸÚ³gOllìŸÿüçŸÿüç?ü°¢(o½õÖÛo¿=QÃÂ… Ö­[÷å—_:β²²ááa=tÿý÷Y,EQ*++{ì±¢¢¢P(tÛnÏž=qqqG-))IIIÙ±cǤš¾z6›MUÕæææË—/×××{½^Ç“››«_ß[¼xñ‡~¨(ÊÅ‹ëëëÛÛÛ³²²¢‰ž:u*lÚ´ÉØ¹¦¦Æï÷Ûív‡Ã¡(Juuµ¾¨dåÊ•.\ðûýçÏŸ¯¯¯W¥¥¥eùòåúkkk¯\¹òÁ|úé§õõõ×®]óù|yyy‘¯@.]º´®®Îï÷766ÚívEQl6[rr² )))‡C?ꆆ†þþþóçÏ«ªsÛ2Fmmmww·ÍfS¥©©I–åI5|õl6[ (++3™L²,çææz½Þ>úH/Qeeeªªþþ÷¿×£O=õ”Ïç‹2:¦±ûüóÏÛÚÚâââŒèÛo¿­ªjNNÎm£á…Ðd2uvvºÝn“ɤï¼zõjEQ^ýuY–|ðÁÌÌLc 7nTå7Þ0J‹¢(sæÌ1²\¸p¡««K¯[ãÒÓ¹\.#Ùl®««Û¿¿$I gÙ²eF‡çÎ F!ŒpBÆ={á+c'Õp‡LúáÈȈþ‡¦iÍÍÍYYY‹ehh())éüùóáÑK—.åä䤧§û|¾Q›ÍÞÿ·¾õ­ÄÄÄ‘‘‘?þØØ(IÒ}÷Ý'‚Ûí^¶lYaaá<0þüØØXI’ŒÊ§3îÞišvãÆ £ŒkõêÕ‰‰‰—.]2Z dggkš …RRRºººzzzŒo½7î ©««7qëqjÍ3nÒ…0œ×ëÁl6ÏŸ?_„7n„G‡††A˜7o^äè˜>cccAðù|­­­FÕq¹\š¦åçç—–– ‚àt:‡††ŒiÜ”é“Ô›7o†o ƒ‚ $%%ÅÅÅè{3Nˆ(ŠSXó2Íæ€)˜V!\´h‘ ¡Pè›ßüfx4%%EÅÛFÇüÇïííÕ4mppð‡?ü¡^tš¦É²ü /„B¡'žx¢±±QÓ´´´´Í›7Oçôt‹/¾5äóù®_¿ž˜˜}oÆ ™Z›fsÀLî9BQ³³³;XÙÙÙÁ`Ðét^½zµ¥¥%---==]ÆÇÇoÞ¼ùæÍ›555}}}¢cþé÷ôô¸ÝîÕ«W¯Zµ* ƒÁ`08oÞ¼P(”””ÔÞÞÞØØ8:: õ[ŒÓ9þžžž¶¶6«ÕºjÕ*½«µk×?~\–厎ŽåË—¯_¿ÞöÂ… Ã3NtB¦y>§sD€;Åf³]»vÍårçåå½ù曪ªþûßÿÖWŽìرÃï÷_¼x±  àé§Ÿ~ï½÷€¾ää¶Ñ1«FwíÚ¥(JcccAAÁ÷¿ÿý_þò——.]zòÉ'EQt:^¯÷¥—^zöÙg;öÙgŸ ½÷Þ{á‹eÂ—ÆØl6¯×a±Œ Ï<óŒ¢(v»=??ÿé§Ÿþä“O|>ßöíÛEQÌÏÏWUµ©©i÷îÝ»vízÿý÷@øªÑ'dß¾}Ÿ|òÉÆõƒwlš¾vl6ÛÙ³gKKKûúúTUUUµºº:55UŠ¢øì³ÏºÝn=tõêÕÿÓ#GÇBQŸ{î9}gEQ|>ßÙ³gõµ”Û·oommÕ;±Ûí[¶lñx<‡c:…PÅââ⎎½[—Ë•——§WhI’^yåÇ£äôéÓv»=|Õh„RQQa,‹hlšîŽI\WÔ‹¦if³Ùjµ ¸\®ÑÑQc}çúõëçÎÛÔÔä÷û¥˜‘£²,‹¢ ˤ’$‰¢˜‘‘1þ|·ÛÝÝÝ …4MEqîܹééé‚ 8Ž`0(˲¦iúÝD½Ÿð![úúúôe8clÛ¶Íf³‰¢»aÆááa§Ó9f$f³9--­··×ív×ÕÕ­X±Âl6ŽŽF>!cjܱE>Ÿ€»`Š7ØôYθk:"„nrçIu¢+..w‰éÉ“'»ºº"t›ššÚÙÙ©ÿ½eË–S§Nuttdff†/ä™Úf°9`Êf˃Ûú¥Î[…ÏYÇÕÚÚúûûõ™¨ÉdÚ½{wee%E î ³åm^ÚnÛP’¤äää¥K—ÆÄÄ\¼x±¤¤äÝwߥ À=c¶Ì§L¿[iüÔoU~…ãÀ­Æ¾tÛb±„¿c€{L{{{øçÆÖ<ª àÞÆG„˜MÊËË«ªªdYžñž_zé¥êêêµk×~ ? <Í£¾s' 0#b¢ßÕjµÞ¡Ze±Xyä‘„„„ïyú¦yÔwî¤f„ý®¢(Þ¡èw®çé›æØ¾Î‡&U¸÷LâÒ¨.55µ  Àb±ø|¾'NÔÔÔhš¦‡,Xð“Ÿü$##Ãd2µµµ>|øÊ•+QFÇX°`ÁÏ~ö³ŒŒ MÓœNçÁƒý~¿JJJ*((X³fMLLL[[Û«¯¾Ú××§‡öìÙûç?ÿùç?ÿùÃ?¬(Ê[o½õöÛoO”Åpÿý÷Y,EQ*++{ì±¢¢¢P(tÛ£·gÏž¸¸¸£G–””¤¤¤ìرcRÍ_k6›MUÕæææË—/×××{½^Ç“››«_ú[¼xñ‡~¨(ÊÅ‹ëëëÛÛÛ³²²¢‰ž:u*lÚ´ÉØ¹¦¦Æï÷Ûív‡Ã¡(Juuµ¾ÞdåÊ•.\ðûýçÏŸ¯¯¯W¥¥¥eùòåúkkk¯\¹òÁ|úé§õõõ×®]óù|yyy‘/N¦¤¤8ýÐúûûÏŸ?¯ªjLLÌmzŒÚÚÚîîn›Í¦(JSS“,Ë“jøZ³Ùl@ ¬¬Ìd2ɲœ››ëõz?úè#½D•••©ªúûßÿ^>õÔS>Ÿ/Êè˜BxðàAUUKKKõõ¶?þñ%I:pà€ªª¿øÅ/ôÐoû[UUÿð‡?H’dŒðW¿ú•ýîw¿;88hd™Hii©¢(‡Ò[íܹóÚµkCCCF!ŒpÔ㞢cÇŽ-Y²DßaRÍ_kúD'>>^ÿ)Šâ™3gTUÕ'vŸþy[[[\\œ}ûí·UUÍÉɹm4¼šL¦ÎÎN·Ûm2™ôW¯^­(Ê믿.Ëòƒ>˜™™iŒaãÆŠ¢¼ñÆFÕQeΜ9F– .tuué%m" gÙ²eF«sçΣF8êqOQøò×I5Ü}“^,322¢ÿ¡iZss³ ‹eÍš5IIIn·;_kk«Q\.WGG‡¦iùùù¥¥¥‚ 8Ρ¡!cÖ8eIIIqqq@ ú&ÆQ‹¢8…5/Ól˜YÓ*„‹-a`` ³³3 }ó›ß ¦¤¤ˆ¢xÛè˜bÐÛÛ«iÚàààøÃ`0hl×4M–å^x! =ñÄ𦥥¥mÞ¼y:‡àóù®_¿ž˜˜}㨧VƦÙ0³&wiTÅììlãbfvvv0t:W¯^miiIKK3.uÆÇÇoÞ¼ùæÍ›555}}}¢cêAOOÛí^½zõªU«B¡P0 ƒóæÍ …B IIIííí£££Á`P¿Å8ÍSÐÑѱ|ùòõë×c[¸pax·õ4OÚ4‡ ˜“›~ñÅåååGŽñù|[·nµZ­UUU---š¦ýío;tèÐ?þñC‡]¿~ý?øÁù¤±pæ¶G½oß¾G}´°°ÐápL4ËÐ|:ÃÜm6›íìÙ³¥¥¥}}}ªªªªZ]]ššªGEQ|öÙgÝn·ºzõêŒ9:æñ QŸ{î9}gEQ|>ßÙ³gõe–Û·oommÕ;±Ûí[¶lñx<‡#|Õhx]´Ùl^¯7r¥”$é•W^ñx<22RXX(IÒéÓ§;;;z衽{÷vwwgffæääH’Uçûöí{ôÑG ÇD3¼/¾ø¢¼¼üÈ‘#>ŸoëÖ­V«µªªª¥¥…!àîE±¸¸¸££CUUUU].W^^žþ ÃöíÛ[[[õív»}Ë–-ÇápD³j´¢¢BUUc©¯ /¢6›íìÙ³¥¥¥}}}zŠêêêÔÔÔ¯ä$î1“»€)IRllì† †‡‡Ng0Ôçd¢(Î;7==]‡Ã eYÖ4M_M#˲(ŠÆÎÑü5’êÕTÓ4³ÙlµZ\.WøÜU½û.¼›p Üúa^‹ÅÂÿ÷°öövýSðº±5*¸·…WA€ ”——WUUɲ|Ï'`µµµ~¿?&&f² 7mÚôÎ;ïtvvööö~ðÁ?þ¸(Šw:)`V‘îBQ£/`†uëÖ8qâá‡~çwþõ¯=ðÀGݺuk”]M-)3Ïf³)Š2ÙÉÙ‰'TUݶm›,Ë’$=òÈ#çܹsQ^íœZRÀl3¹:±pá‚‚‚uëÖ}ùå—N§³¬¬lxxXÝÿýEEE‹EQ”ÊÊÊ„„„Ç{¬¨¨( é;¤¦¦X,ŸÏwâĉššMÓ"äÊÈÈèîîþÏþ Aøïÿ{ñâÅ 6,^¼¸¿¿ÌÎ{ö쉋‹;zôhIIIJJÊŽ;¦–€ -]º´®®Îï÷766ÚívEQl6[rr² )))‡CUÕæææ†††þþþóçÏ«ªªOÈl6›º|ùr}}½×ëõx<¹¹¹‘/]z½ÞÚÚÚðùß?ÿùÏ@ ðíoûÖ†µµµÝÝÝú,°©©I–å©%`BGŽQUõÅ_4™L²,¿üòËŠ¢ìÝ»W’¤ÒÒREQ:¤‡vîÜyíÚµ¡¡!£²²2=š››ëõz?úè£È9ý~ÿ˜ ¡¯¿þz ÈÉɹµ˜é)Ž;¶dɽÉÔ’0>“ÉÔÙÙér¹L&“¾Ål6×ÕÕíß¿_’¤††dzlÙ2=$Šâ¹sç€QE‰7¢gΜQU5+++Âül²…PQ”„„„1[&›0ÛD»jtõêÕ‰‰‰Ÿ}ö™qÏo`` ;;ûù矅B)))]]]===zHÓ´[oÅŒŒÑææfA,Ë Aã†åÝL øŸm!Œ‹‹áæÍ›áƒÁ`(JJJŠ‹‹ Ñgõz½‚ ˜Í擳‰VµŒŽŽFŸh²I³M´…°··WÓ´Å‹ßòù|ׯ_OLLŒ>ë¢E‹Aˆ°†3„_êáßø†¦iW¯^ÚÊÏh’f›h aOOO[[›Õj]µj•>£Z»víàààñãÇeYîèèX¾|ùúõëõP||üÂ… Ã'^¢(fgg[²³³ƒÁ ÓéŒñÓO?]¶l™Ñgrr²ÕjíìììììŒrÌSH À„žyæEQìv{~~þÓO?ýÉ'Ÿø|¾íÛ·‹¢˜ŸŸ¯ªjSSÓîÝ»wíÚõþûïðU£×®]s¹\ÅÅÅyyyo¾ù¦ªªÿþ÷¿#?íþøã^¸páG?úÑSO=UUUvïÞ-I’ ûöíûä“O6nܨ׹[ŸŸZR&$ŠbqqqGG‡ªªªªº\®¼¼<½,I’ôÊ+¯x<UUE9}ú´Ýn_5zöìÙÒÒÒ¾¾>½muuujjêmÓåçç»Ýn½IOOϯýk£ŒUTT¨ªj¬ ·N!)`¶™Ü²I’bcc7lØ0<<ìt:ƒÁ q¿M’$³Ùœ––ÖÛÛëv»ëêêV¬Xa6›GGGõG 4M3›ÍV«u``Àårék^úúúbccoM´mÛ6›Í&Šâœ9s6lØ0gΜ . kVeYEÑ€þ3|M„¤¦²~RŸ„Yr’ššjܽ۲eË©S§:::233õ¤MÔ¶¸¸Øx01ÜÉ“'»ºº"¤›þ€¦VÇÕÚÚúûûçΛžžn2™vïÞ]YY¹üèWVoeÌü¸£fì}c’$%''/]º4&&æâÅ‹%%%ï¾ûîm'aÚfjTD6c3BI’Ÿ—…BÔ3Üc_ºm±XÂß À=¦½½=ü³ckUpoããH åååUUU²,ßóIGmm­ß™lÃM›6½õÖ[W®\éî«ËÏÏ—$éN'Ì*w£Nˆ¢(Šâd[edd¼þúëóæÍ{ë­·ü~ÿ÷¾÷½?þñ¡Pèµ×^ …Bw()3Ïf³)Š2ÙÉYEEE xæ™gdY–$)--ÍãñÔÖÖFyµsjI³ÍäêÄÂ… Ö­[÷å—_:β²²ááa=tÿý÷Y,EQ*++{ì±¢¢"cö–ššZPP`±X|>߉'jjj4M‹kΜ9mmm•••Á`P„––ŸÏwß}÷»óž={âââŽ=ZRR’’’²cÇŽ©%`BK—.­««óûýv»]Q›Í–œœ,BJJŠÃáPUµ¹¹¹¡¡¡¿¿ÿüùóªªê2›Í¦‡._¾\__ïõz=OnnnäK—²,‡OþV®\988øÁŒ;#¬­­íîîÖgMMM²,O-):r䈪ª/¾ø¢Éd’eùå—_VeïÞ½’$•––*ŠrèÐ!=´sçÎk×® …0”••éÑÜÜ\¯×ûÑGMjIçÑ£G@^^Þ¸•LOqìØ±%K–èÝÎHRþ?“ÉÔÙÙér¹L&“¾Ål6×ÕÕíß¿_’¤††dzlÙ2=$Šâ¹sç€QE‰7¢gΜQU5+++ÊùÙÎ;ý~ÿ›o¾9Ñ=?=EBB˜-ÓI ˜ ¢}aõêÕ‰‰‰Ÿ}ö™qÏo`` ;;ûù矅B)))]]]===zHÓ´[oÅŒŒÑææfA,K4©7mÚô»ßýîêÕ«ÅÅÅ£££ö4nXN?)`–ˆ¶ÆÅÅ ‚póæÍðÁ`0 %%%ÅÅÅè³z½^AÌfóm'g+V¬(//—eù¹çžëêêŠ>Åt’fhWöööjš¶xñâ[C>Ÿïúõ뉉‰Ñg]´h‘ ‘×p.X°àèÑ£K–,)**:wîÜ4|F™0«D;#ìééikk³Z­«V­ÒgTk×®<~ü¸,ËË—/_¿~½Š_¸paøÄKÅììlcKvvv0t:‘“á»õ=2SK ˜m&·lD’¤ØØØ 6 ;Î`0hÌ®$I2›Íiii½½½n·»®®nÅŠf³yttTtOÓ4³ÙlµZ\.—¾þ³¯¯/66öÖDÛ¶mûøãÇC( …B²,‹¢h @ÿ¾¦4BR SY?©OÂÆ\`LMMíììÔÿÞ²eË©S§:::233õ¤MÔ¶¸¸Øx01ÜÉ“'§¹Fô¶@˜Z!Wkkk èïïŸ;wnzzºÉdÚ½{weeeäò3Ñg•¦°4€)˜±÷I’”œœ¼téÒ˜˜˜‹/–””¼ûî»·„i˜©QÙŒÍ%I ^" QÏî¸ÿ¿cü% â5@IEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out-big-part-thumb.png000066400000000000000000001452441445075545500275210ustar00rootroot00000000000000‰PNG  IHDRÈîóÏßâsBITÛáOà pHYsÄÄ•+ IDATxœì}w|T×™ö™{§÷ª®‘4Ò¨ŽzEÔ…M¢ˆbDµ1lc{ã²Á‰³Æë8Ž7¿¬cúabƒÁÓAt!$¡^Q¯£é½Ï÷ÇO´Â)» Áñ7Ï?ÒÜrÎ{Ê=õ}žƒÐ‡P(œù“H$FEEy~ÆÄÄà8޼øQƒÏç‘ĉN ß°——N ’ÿ§gþ ‘H•••W®\™œœT«Õ!:^YY‰¢P(‹Ån·šÍæ•/~hÁÁÁ†âýøËᾂ‘ÔÜÆ·ž5õ ,Xn×*u—ùó–8Í&mÝ„;%nìnÄ©t²¯Ø:1`h«ÃýôÓ¡¡¡AAA;wîÌÎÎ~ë­·Èd2BÃ0ØI°Ùl‹…@ ùûû{=sþÙq_ÅrÚV³Ån¿0¨¼^¾Ö!±"d%L‹—@Vht6§Ãé°ÍcaF$) ‰D"D"!têÔ©ãÇ—””LMM}üñÇQQQ÷îÝkkk“Éd‹ÅžŽã4 !tþüù?þ¸¤¤ä’|/î¯XŽA2-(šÖ\T×or‰Å”eËnÆŒL©î±D“R™^¯w»ÿìJÑÞÞ~âĉðððéééíÛ·»ÝŠeË–]¼xÑßßÛ¶mmmm*•*33³µµuçÎÁÁÁÏ„ÐàààÉ“'y<‘HÌÏÏŸ;w®Ç%È‹RÌ^ '/`Ɖ¸ÍîLÌ?ó™óñŸÐïÖëlÎÿtˆNF ØÎþˇmF BˆB¡¸Ýn»ÝÎd2m6›ŸŸŸZ­¶Z­à26::Êd2E"Ñðð0†a"‘hjjJ,OOO „‹Å2›Í$Él6³Ùl§ÓI£Ñ\.—V«õ¸îxñψû—N›ÅlC!»Ýf±ÙZ†äq&‹Ëér¹¬vûw®9ßu…0Géõz„ÐÐÐЬëƒêÓéGÍ•Ã[‡!¤ÓéBF£ñ'Ò‹== â‡#""B£Ñœ?~Á‚,kjjJ.—Ëd²ññq:n³ÙΟ?ëÖ­õCì ©T*‡Ã …$ Çq@ððâz° l6Ûív;ί¿þ:!!F£]¹rehhÈétÖÕÕŒŒˆÅâÀÀ@p—ýÁâÖ­[B¡066ö믿>räƒÁ DQ(:Î`0ÚÛÛ›››¯]»vãÆ 6›m·ÛTÔ+_Ün÷øøøàààôôtDD„Á`׫ 8ÎÉÉI@`4«««OŸ>œœìp8&''vïÞm±Xêêê.\¸››û¨ýk r8=öØØØXww÷éÓ§#""&''§§§ó›ß˜L&___£Ñép8X,Ö£6ù&“ù‹ Çqa¶WȃÂO¨ ý=šBVwèÝ’ÿ0ñÏå3 Öþ=6?Øty—¼x(ðV,/ ¼Ë‹‡%Pò¨mxp*'Ó£¶âðòŠëßBÊÉÑGmÃ@÷³KŒ] Ú /þ ¢ubðQÛð@ ”ÐÂÿ¶áÖ‰!Š_È}/¼ðb@ÒãQ[áÅž–——“H¤GhŠ?&ü¹bq8œGh‡?2x×±¼x(ðV,/ ¼Ë‹‡oÅòâ¡À[±¼x(ðV,/ 0ò§ïÑ©^<0„ÆPÅãh´¹]†»\.¯œš óˆ+BLî£6Ä‹œNbº44::º»»Ûd2%''›L&•JµbŊ矾ªªJ¡Pœ:u*..ŽD"I$’K—.•––:tˆF£%&& …ÂæææˆˆˆK—.ñx¼íÛ·Ûl¶±±±††† FÇ;VXXÈ`0†‡‡årybb"‰D2™L/^¬¨¨øøãBþþþeee C.—ŽŽjµÚ²²2‡ÃÑÙÙéçç' årùÙ³gSSS…B!Žã,//Ÿ˜˜àr¹ÓÓÓ±±±l6ûæÍ›óçÏ7›Í† ¤¤¤455ÕÔÔhµZ‹õÖ[oUUU}ôÑG›6m:tèÐÒ¥K/\¸°páB·Û][[ëëë«Ñh0 kkkËÉɉD÷îÝ«¯¯ONNæóù~øaEE…Ãáhnnh/¾Ĭ¬,‰466†‰DF£¨sÕÕÕ'**Êh4º\.—˼qãÆááá¼¼<>Ÿ:22"‘H@y[¯×üñôõõÍÉÉa³Ùt:H$‰D@Àf³5^¯ … ¥¾¾~ëÖ­ׯ_OII‰D,Ëívët:»Ý®T*‰D¢H$‹Å,K©T®_¿^©T:òx<½^Ïáp|||ìv;‰DJKKÓëõÙÙÙ‡Édâ8®ÑhBCCW¯^ ÁjµÚ±±±'Ÿ|˜04mçÎCCC›7ov8v»L&ûøø…˜˜˜þþþåË—Óh4‹¥Ñh( ŸÏ óñña±XµµµÞZõ7gÚ|/ˆDâ,JÐ̇ÿÊ‹á¯ÜEñx¼={ölß¾Ýs…B¡ÌzN@ñ\†û /¼àããó½aBŒ÷GíqÙ R©³Ì†À)ÊL·ljD"@ ‘H³¬"‰?ýª‡Çf³g]ôõõõóóCaF¥RÉd2Ç›U`l6›ËåÞOFãr¹Ð`ðx<¨H$‘H4ë*• Ðh4@€a„0ë.—;ËùÇq‘H"‘ˆ@ „††z(— ! …" ÙÌåþ·¡$‘Häñx ãþ<¡P(8ŽÓéôYóð —ËU½(Š@ €Xf½B§Óy<Ç›YwI$’P($‰\.—ÇãÍÊOò#""  B||ýꫯº\.·Ûýâ‹/šL¦þþ~Æf³ÍfóÎ;#"" ®_¿îy±´´4'''&&fÁ‚gppÐív¯]»¶¾¾>&&&&&¦££cëÖ­YYYN§sïÞ½t:½¹¹™@ èõúüüüÅ‹·¶¶Æœœ¹\ît:1 û¯ÿú¯­[·¦§§wuuFxE$åççïÙ³çìÙ³6›­  NÙøÉO~’m6›÷îÝK&“ÛÚÚ0 óõõ5 ¯½öšÅbéëëó÷jjj222AXXØÎ;ëëë D!‘H¶lÙ’žžÞÒÒB£ÑJKK[ZZ`h100P^^^RRÒÞÞþË_þÃ°ŽŽ0Æçž{N«Õ¾õÖ[t:Ýd2)Šüü|0$‘H»wïf±Xmmmn·¢‹ŒŒ¬©©ÉÌÌlll´Ûíp1::zçÎIIIjµZ.—'%%Ùív³Ù\XX˜›››””TTT” Õj§§§ “É,,,|þùç/_¾ g‹`B¡ûóæÍÛ²eKhh(tV«ÕÏÏ/22Òf³Á—D&“ßxãeË–!„Èd2F34mÇŽÏ=÷œL&S©TW¯^¥Ñh‚T*Å0ì¹çžƒ^¯££C"‘ÔÕÕ!„²³³BwîÜÑjµ %,,,##ÃÇÇG«ÕÆÆÆ"„Ö®]û¯ÿú¯ ýàããÃáp‚D"ÉÏÏ'‰ç΃ï#***"""88X¡P@G™‘‘ÑØØˆ:tèPpp°Åb1›Í±±±!55õÀ\.—@ Ðét—Ëåp8ÒÓÓ÷îÝ»mÛ6‰TVV¦P(F£iii –H$H$SSS‹åÀz½~Ñ¢EÏ=÷\UUBèÝwßµZ­J¥Òd2A,¹¹¹ï½÷“Élhhèéé9zô¨Ífó$ùàÁƒƒ¡§§§©©éòåËãããÑÑÑ T©T.—kppÐh4ö÷÷GDDÀ·×ÞÞŽºvíšÕjÅqÜh4ÆÅÅ„üüüwß}—Á`466nÙ²E«ÕÆÅÅõôôäååíÝ»wãÆ¡ßÿþ÷‹ettÔb±DGG‰Ä¸¸¸øúú* Ð××g6›¥RéBBB@HÃ0«ÕýÜsÏíܹ“Á`\¼xÑívÃéÒ¥K‘‘‘àÀIIIz½~llìèÑ£r¹ÜÇǧ¼¼;räÈåË—Bz½^¡PX­VK$$$Ä`0DGGËåòóçχ……Ùl¶wß}šÑÑÑ÷Þ{ï³Ï>3›Í}ôÑ·ß~ÛÖÖæããÃãñ´Z­V«=uê”X,v¹\Ÿ~úé±cÇBàóÏ?¯®®Fõ÷÷{š›Í688¨R©¨Tê·ß~+ 1 ;wîÜûï¿o·Ûm6Û7ß|ãv» †B¡èééq:óçÏ¿uëÇëìì E¹ÝnÈ —••²Ûí ¾$‹™L¦¯¯¯J¥šœœÜ·oßÄÄD```fffgg'Žã'Ož¬­­ýꫯB«W¯Ðh4“D"±³³óõ×_‡C„<ƒ&¤¨¨ˆ@ Œåää444@fîÛ·€7n„……‰D"H¤kfOêp8.^¼ÜÜÜüæ›oƆ†™LöÑGq¹\—ËU[[[[[ûá‡"„ÊÊʬVëÔÔÔ7´Z-NÙ·oŸR© ºråJtt4Çß·o¨M]¿~ýµ×^ëíííêê:qâħŸ~j4çÍ›W__Ïf³1 žžžÖh4ûöí`2™ÕÕÕW¯^%“Éz½¾½½Ý?ÀB=ýôÓÐÍ“Éä@PVV6«Ó ¿ÿE ÃrssètzYYäŽþþþ|>Ö[ð]FGGçääÉä°°°YqI¥Ò™9NYY™@  *,,$‘H7n¬©©‘J¥k×®E‰ÅâÒÒR2™œžžžšš:óu@pÿ€àççÇb±bbbæÌ™3³D}||Š‹‹aõdæóéééÅÅÅYYY‰‰‰³B»?£ââ⊋‹ÃÂfÍpŸ7o^zz:B(&&fùòå7nLOO_¸p!BˆD"‰Åb““#“Éf¾ˆa˜T*Åqüþèâãã‹‹‹ÃÂÂ’““333gÞ"‰óçÏŸ•3 FسÀf³ËÊÊ„Bahhè‚ f Y,VqqqQQÑý…ûßÀb±žêÐ̬„™Úƒ‚ŸŸŸ'pøÐ*f&äþYíÿ3e’`rH$’gòA&“Ñÿõ¯}öìÙŠŠŠ¥K—NNNªÕjè\ ÆæÍ›ËÊÊôzýÄÄ<Íáp^z饮®®ÀÀÀuëÖMOOWUUÍ;···Ö$Ýn7—Ë}ñÅ“““ÛÚÚ`Ù Ã0ÇwíÚ•™™YWWWYYi2™4MZZZdd$tˆ†íÚµ+%%åîÝ».— ‚*--5™L?þøôôt\\Üðð0—Ëu:.—+..nçΗ/_Þ´iÓ¼yóîÝ»g2™L&“ÃáH$Û¶m‹‹‹ó$Çívgee­\¹2++«¾¾Þív …B“É„*))Y¾|¹J¥ª¬¬ÌÎÎnnn†ñ;$ä‰'žHIIiiiñ\ \µjUUUUCCÊ+ÆÇÇFcaa!‡ÃÑét/½ôRbbâÄÄ„V«…ç¥RittôŠ+š››W¯^ÝÒÒB§ÓÉd²Ýn‡#BÅb1ŒŸ €¡‰âp8ÝÝÝ:Îår‘Éä•+Wæåå¹\®‘‘(*•úüóÏ+ .—»wïÞóçÏCÈO<‘‘‘A¡PFFFß¡¼¼|éÒ¥ …ðÊÊÊææf‰´}ûö†††ÂÂÂ¥K—ÂÂxVVVkk«Ãáûsss) ¬_æææöõõyjäÞ½{µZ-ƒÁøéOzîܹ™ „0•JE ÂÃÃN§ŸŸNÿùÏž™™©P(Μ9ÓÛÛÛØØH ¨T*@Ðjµ}}}T*µ¼¼!D$e2™Õj5›Í~~~o¾ù¦D"¡P(0‹–J¥o¾ùæœ9sÞ|óÍèèècÇŽ …B„ÐÉ“'W­Z…*--½tédS@@BˆÉd²X¬ˆˆˆýû÷à øêÕ«!ÙJ¥’Ïç?ýôÓóçÏ'‰P!™Ls‘Hôæ›oJ¥Òþþþúúú[·nÝ»w/55õõ×_g2™~~~°èàïïÿꫯÂzDWWWSSSbb"ƒÁÐëõ‰dÿþý~~~І†8©zÿþýb±xllìÊ•+###æêÕ«eee¡ììì;wîÀqžmmméééçÍ7ߌ+(((((ؼy³Óé¤R©+W®\¿~=N·Z­‡†a@eeåSO=E$=j2™Ž9‚ãø /¼PRRb³ÙŽ=ŠãxSS†a‹¥©©‰Íf÷õõÁYÚ†=þøãëÖ­CI$’ÉÉɤ¤¤ššš-[¶<öØcÛ¶mëèè€NMMÐh´äääÞÞ^‡Ã1gΜ3gÎTTTÀ¹¤žô*ŠeË–®Zµ ÎÀ›Ívç·300`4¡JmÙ²¥¦¦æO þp¹Üîî˜©j4š™ÍŸÏ¯®®†jp8gΜ©ªªúòË/'''ôz½R©„Ã,§§§¢££•J娨˜R©T©Tða™Íf†ã8‰D‚eôÊÊJ@099™˜˜«äjµZ§Óuvv–••½÷Þ{sçΦP(L&“ÍfÃgï~õÕW°oÀ¨ÜsW£Ñ¨ÕjDÇÇÇ?~\©TÒh4ƒsL‹Å’žž~éÒ%Èš™±[,–#GŽ,^¼˜Åbéõz¸H¡PÖ¬Y;Qz½žÉdÎìYÄb±Ãá8~ü¸Á`€Ü0›Í!!!\·nÝ7pg³Ù ªV«×¯_ÿÑGAŽ) 8`³Ù …J¥B­Y³æ›o¾1™Lt:}õêÕAAA÷w=.—kjjjzzÞmoo–Ëår¹®“Éä‘‘õÚívØK€ºrìØ±ŠŠ FÓÓÓ“™™év»=éÎÎÎ~ÿý÷ËÊÊ:::h4ÚªU«BBB<9ìÛíö€Ây<^ww7“É”H$W¯^U©T7oÞT*•!X5›ÍwïÞ…¾ƒÅbMLLŒ———×ÖÖ]¼xQ¯×_½zÕd2á8ž’’B&“/\¸pòäI­V{õêU‹ÅRUUåp8z{{Ùlvnn®Åbéìì´Z­­­­SSSÑÑÑããã°¨sõêU‡ÃaµZÉdòñãÇ1 »}û¶Á`èììlnn†M$>ŸßÙÙ™‘‘záÂ0Qh4­Z­†9,LÈ»»»Bjµº££ãîÝ»n·{Ñ¢EN§S§Óq8 …råʲ¾¼¼\­Vß¾}Ûh4B*¤Rixxx@@Àððpdd¤Ëåš3g‘Hlllt¹\&“éÂ… °wõêUøÌ˜Læ·ß~k³Ù.]ºd³Ùz{{ïÞ½«V«ÃÃÃãããqïëëlii"áñx]]]¡ÆÆÆññq*•ZTTD£ÑÇØØØÝ»wáã¡ÓéðÙðx¼ÎÎNh}¡«‹ÅAAA==='OžìîîîëëëììLOOŒŒ¬­­U«Õ°)§T*CCC[ZZ|||üýýO:%‰<åéµÛíT*¦ä7nÜ€MRhwh4|̺»»{zzî¯ôÿ ’Éd???6›=oÞ¼GfÇÿÅÅÅT*U øûû§¤¤óÌ3‹/Fùøødff’Éä]»v­ZµjçÎ+W®<{ölLLLkk+ŒTu½x Z­V#ß¾}»¸¸Øl6gddðù|G"‘ßÿýk×®Ùl¶uëÖ¹\."‘h·Û7mÚ;?N§vúvìØár¹`bµoß>µZ îVÿ\R°^<0|ïÂ+øÜýþ…ò™kb÷Zú Ìô‹ðºÅyá…^xá…^xáÅutÿ—Ç0ìŸhVñ½¦òù|ØÙ÷09xtt´B¡Ø±c¸"ynÀæ.8¥¤¤,_¾œÅb‰D"µZí9ÕN ¤§§ Ñét¹\îyÇã­^½úîÝ»%n™L–œœ¼jÕªÄÄDØ0žïâÅ‹,XîÎ3ãý{••%‘H,XPXX8::³bÅ @088¸sçÎìì캺:öì³Ï²X¬ŠŠŠ¨¨¨¶¶66›½eË™LÖÖÖ¿iÓ¦„„„¡¡¡ÔÔÔ’’’ää䯯Æ;v¤¤¤‰DFSTTL¥R SSSÁÄÄÄóÏ?Ÿ˜˜8:: ¾%%% ¶ý«««³³³ÙlvPPÐøøøýglÚ´©¿¿vÙ[·níííu¹\[·nŒŒ,))éèèX½zµÙl^´hQOO•Jݰa¸÷ìØ±£³³sçÎ àô ˆ¯®®NIIinnv¹\, 2377·²²R«Õ.]ºtΜ9@q@ÑéôÍ›7'''···{*•Jݽ{÷ôÝÄûf IDATô4Žã[·n5 sçÎ-**™ul 100pýúõ°ï½lÙ²ŽŽŽ   ‹uóæM·Û=þüË—/§¤¤ +•JpÅ/))áp8z½þüùóR©4---<<üèѣ˖-›šš2™LŸþ987/Y²D*•މݰ0«ÕZ[[àëëËãñÞxãÜÜܯ¿þ\ŸI$Ò­[·|||‚ƒƒY,–ŸŸßùóçËÊÊÚÛÛ‰DbQQ‘Á`hnnÎÊÊúä“Oª««Åb1¦}||,KKK …B‰DŸ|òI\\Ü{ï½·k×.ƒñÒK/½öÚkV«µ¡¡ÁÇÇ'!!¡§§gxx˜D"¹\®èèh2™ìïïÏåroß¾ îä)))—/_ç“àà`غ÷õõ}ï½÷jjjîܹ“••Å`0&&&ètúÍ›7§¦¦H$’Óélhh(-- v:ÑÑÑ‘‘‘b±X €ÊÈÈ8LëõúÉÉɨ¨¨îîî£G2Œààà]»vMNN’Éd ÃîܹSPPpòäɱ±1½^oµZTìp8p×ëõË–-»qãB(--mÑ¢E_~ùebbâñãÇBÑÑÑ«W¯þÕ¯~ÐÜÜœššêïï¯×ëŸ}öÙÏ>û¬££crrrbb ˜AAA[·n}ï½÷À íøñã$ÉSÑÁ!…Ïççææbæt:ÓÓÓá×gŸ}öСCàB‚HCCCqq±Ûíf³Ù E*•ÂZ(°jkku:Ý¢E‹„B!›Í®¯¯×ét§OŸ–ÉdL&“H$ž9sF&“ùûûÓét‹_$˜Âår¿ùæ‰DRTTd4årùÓO?íp8Èd²Ëå’H$R©ôìÙ³:®¯¯/,,lbb"&&Æßßßl6Ã'›Ínhh ÓééééŸ|ò ¸ês8œ¯¿þ:..nÞ¼yV«U¯×¯]»6;;Û`0é !D \.83* “˜L¦C‡õC­V‹ÅbµZ}êÔ©ªª*H¾Ûí†FE*•r¹Üúúz„OVVÖ|àt:­V«\. éïï?wî¸FGG …Â;wî j4ŸþþþŒŒ ƒ4§ÓéëëËáp._¾ |¸/¾øÂCHœ3g‰D¢Ë嚘˜àñxv»èG…±X,‹Å‚‰DZ­ÇñÍ›7ëtº¨¨¨÷Þ{/11‘B¡X,*• îh999õõõ###B¡0 <<üõ ‡Ã9tè™L 3›Í Åd2™Íæ#GŽ,Y²„Åb1™Ì'žxˆ!†]¼xqÍš5§NêèèÈÏÏ73« N  Æ‘#G$I___hh¨N§kjj2 111ƒƒƒIII±±±CCCP$&“Éív÷÷÷ã8>99I£ÑBBB.\¸Àår‡‡‡ù|¾Ífkmmu:@:§Ñh½½½@n¡ÓéCCC×®] mmm%_~ù¥R©œ3g‡Ã¹~ýºÑh„jd0Î;'‰¦§§'''!ÞŽŽŽòòr ÃÈd²Ñh!‰ccc‡ãìÙ³n·{rr²¶¶6&&æÒ¥K©©©sçεÙlׯ__ºtiDDÄùó烃ƒÇÆÆ222ºººX,V||¼Ëåâr¹àŒ«Õj9ŽÓéÄq|ll¬ºº\¯$IJJÊààà_|áv»×¬YÓÔÔ488¨T*oß¾­Ñh¢££“““ûúúÀ£0??ð††hì?îv»Oœ82===>>®R©ÈdòÀÀl¦‰òöíÛÁÁÁcccPq©TªÅbÉÌÌô8lmܸ‘N§···ÇÆÆÖÕÕÁ—<88xæÌ—ËuëÖ­… Z­Ök×®Á Ðn·›Ãá´´´@ç¨R©z{{oݺåt:çÌ™Ç]ÇÇÇs¹ÜÚÚZxÅb±Ðéô%K–ƺº:ƒÁpçÎpÃâp8àH¼téÒ¦¦&.—+“ÉΟ?¯Õj/\¸0ËEôO€‘à_Ù¢ù?bV |>Á‚÷?F¥RŸ|òÉ¿´{ñÌ3ÏdddüõÀçÌ™×’àá„-_¾¼²²’ËåÎb-z6²N§P(%%%>>>2™¬¨¨h¦³™L.**ºß«1---)) !<<„†ãøöíÛgn9GDDFpŒ7›Í6›M.—Q(”þþ~ ›"„JJJ BhÕªU}}}<Ãá¬]»633322ü˜ÃÂÂüýýB•••O?ý4Bˆ@ <öØcÈüùó_~ùåE‹a¶mÛ6àëë ©ár¹à'œŸŸ…Äf³×¯_?wî\±Xl6›Á`‘Hät:GGG³³³GGÿ|ž…B‰ŠŠZ¹r%8òCŽ‚×ööíÛ!÷ù|¾T*œœô”A```hh¨ÅbY¸páÔÔ”'[¡:BÔ,K&“„ŠŠŠüüü7ß|³ººJbÆ `C^^‰Dš?~uu5ŒŠH$Rjj*†a)))‰$99™F£‰D¸|Ô”¨â¥¥¥¾¾¾¡äädƒÁ°~ýúššš€€¨yiii8Ž›Íæžžžòòò™ÓL‡Ã±xñb°mÛ6*•šŸŸO ’’’¨TªÙl¶Z­áááu„ËåÊÊÊòññYµj°V¯^ít:ív;xéá8ÎçóSRRæÏŸ•––F&“ÓÒÒ˜L¦T*‚ÌÐÐÐÊ•+BØÜ¹sét:ðd¶lÙÂf³»ºº„B!èEDDTVV"„ôz=—ËõpØ¡ÒŒŽŽ‰Df±X”J¥F£a2™Z­ÖjµVVVböôÓOoÞ¼ //ïÎ;aëÖ­kÖ¬ÉÉÉ¡R©eeer¹<,,¬§§Çq Ã{ì±çž{Çq»Ý.•J;Æf³üñM›6EDDŒ+Š®®.…BãxEEŽãÏ?ÿ<¸ôïJ©T’H¤7FFFZ­Ö7nÈår­V;oÞ¼>ø!´mÛ¶]»v„/¾øbÙ²eà™ÞÝ݃‚BH"‘€ºShh(ˆ à `hhhݺu†•––¾þúëT*µ¹¹yݺu---‰d||<<ìãããããóöÛo'''Ûíö9sæ>|Ød2………mÚ´ ÔàË7 ùùù*•ŠB¡ìß¿¿¨¨Èf³MNNªT*N' 7oÞ,‰¬V+ðü‚ƒƒƒƒƒ×¬YÓßß?oÞ¼°°°ÀÀÀ·ß~Hýqqqb±øí·ß.,,|ûí·e2Ù­[·àÛóÈ ‘H„9óÇl³Ù`Rêv»»ºº˜L&|š0àg¬œœÐQ(`Œi`‚ã8°ÿ^zé%[æàÁƒP#ßÿ}“Étýúu6›}åÊ•5kÖœ;wnñâÅ&“Éétþö·¿%‰N§sÏž=r¹<##ãÆÿùŸÿÑ××' wïÞýé§Ÿ2™L Ãìv»Óé|æ™gfy}ÙíöC‡9"‘øÆo9r”®`‘fÿþý@š+..îîîŽ?}ú4(xAJ% ‘HÔjµÐwÆ™> Ãèt:¬8qâüùó@6Ù¶mÛ±cÇ€€uñâEXï@íÚµËb±ˆD"&“i·ÛÝnwccãâÅ‹ÕjuZZô¿ ¥££cñâņÏç×ÖÖ~ýõ×!¥RyðàÁææf“É´téRn€¾øøñãSSSK–,ÑétAAAK–,9|ø°@ úôÓO=ËQ!6›ÝÞÞîëëk±XV­Z‰J¥ò“O>™¹FØÙÙh±X˜L&”ïèè(Dl‹ááa°dɃÁpëÖ-«ÕzðàÁ#GŽx¨i!Äápf7 È£†a|>žÜÜÜ9sæ”””Àw ­ß¢E‹âââÐw‚8†ØÍÌ0ÿŠ)ÈS ‚Y2IÀКe†a‡ÅbÊÊýNc÷ërâ@¸ß"‘èëë ¦îܹt”6nÜk˜$içÎd2Y"‘¬X±Íßâñx÷Ò!!÷ÇrHd2ˆ_³î ‚YšM†ÍÊ=€GEˆJ¥ÎRÂq’9+CÀ”›5ÄÆ0ì~œ‡a˜Žã4mŤšX,Ö¬Ð<™\UU5K!„`äÁb±f鄤Îrôó¨7Íú ïÏ”ÿ œï í{$ Fu¾¾¾3­‚¤yþñëùÒâI)€B¡Àp÷þ·þÎTüýöï“t:ÚNÿ™µÒ‚ãø÷2 ÿw¶ýýøÞÝ$">gÎí–——;ŽÉÉÉ'Ÿ|²¾¾ÚÒäääM›6Éd²ºº:Èt»Ýþâ‹/:Žšššˆˆˆ±±1P•’ªªªÒÒÒæææ·ß~ÛÏÏÈ»Ðåååýò—¿är¹ êýÝ+¯¼3oÞ¼[·n!„RRR ›å•WJJJ€è‘’’rëÖ-øRív{iié¢E‹ÒÒÒnß¾aƒÁ°ÙlsæÌ©ªªZ±bÅÙ³gŸx≺º:àvÂÊŸŸ_YYYccãòåËõz½Á`Ø·o_^^žÓé\½zuLL °½)ŠÍf{ñʼnDâòåËÓÒÒººº ãp8ñññ¯½öÚ7ß|³fÍš¼¼¼Û·o#„Øl¶Õj¿þõ¯AˆÆ`0ÀE"‘ø‹_ü"''çÞ½{:ÎßߟÉd ™LúX·nÝÅ(‡Ã±gÏžŒŒŒ¤¤¤ææf*•êv»a Ë"½½½?þx]]H$A/„PdddZZZ{{{uuõÄÄ„ÝnÿÝï~k·ÛÇÆÆÀ†èèèüüü§žzª©©iûöíׯ_‰D|>_§ÓI¥ÒíÛ·ÃHÓ·K—.}å•Wpïêê±4"‘¸råÊmÛ¶9:…Byýõ×¾ûî»ï‚”…B!‰ê _C%%%µµµá8Îb±@J+---::ºµµ†c+W®µ*…BQVVæëë"—Ë ^}õU˜[?Þét‚¨4×999¿ýío™Lfmmmww÷Áƒ­VëŽ;`†H¡P¦¦¦@ÇRÓøÿ÷7 ñññ§Nb±Xd2¹²²òµ×^ƒEQ …rõêU„PYYÙþýûi4,÷ýö·¿u:ƒƒƒQQQ@$‡¤Í;÷æÍ›¡„„„ööv8‚Â*0¶B6lxñÅq7 yyy°éžû †µ¶¶B¥?wîL¾üüü>øàƒ¨¨(X­åóùT*•ÏçðÁ n·è©ÓÓÓ`÷îÝ{öìáóù]]]­­­ÐýÕÔÔ¼ð @‘‚ÁÖêÕ«_}õÕ5kÖìÛ·ïÒ¥K·oß¶Z­6›M­VÝ»wÏC§ËÎή¯¯' *Û °´Ëf³?øàƒ”””îînPxòÉ'»ºº¸\î®]»žyæŸ>úñ«««_yå‰ôõ×_÷ôô|ñÅ8Žÿüç?¯¬¬´ÛígΜ™ššºxñ"Lfy<žÕj½pá‘Hìïïïíí…Ök÷îÝO>ù䟛CQA›3Ûº3gΘÍf755}ûí·v»½µµ5<<¼®®vŸ\~ÏÆBhzzúÌ™3t:$`ÜZWWwîÜ9§ÓÙÖÖæïï2ÒýDFsøðaØzokkûâ‹/²³³u:ÝáÇ'&&h4ÚÍ›7‰DbRR’F£¹víÚÕ«WµZmdddoo/F#žH­Vë±cǨTjggç·ß~[__2Á2™¬¶¶!ª$/j ÍXŸ9|øð¹sçôzýáÇÇÇÇÝn·ÏÁƒóòòêêêt:Ý•+Wnܸ¡R©H$Ò¦M›>ýôS„PCCÃéÓ§gŽßm6ÛÉ“'[ZZÂæÍ›?ÿüsO•øÞ¬€âƒ¯€S©ÔyóæÝ¾};00&¨ Éb6›aç8%%åĉ*•J¡P "„ÔjuoooCCý{÷ …Ýn¿qãpÛ].¨Ó$$$ôöööõõét:íÚd2Á~bbþ1 }}}PêPɠ뉉‰a±XõõõQQQ7nܘ˜˜P( Z½ê¥K—@LæÞ½{¡6›Ð××·páÂÓ§OÓéôèèh©TÚÚÚªÕj333[[[CCCAR!##ãæÍ›r¹<99ùرcF.—£ïv<šššz{{U*•^¯Ÿšš‚f4¡´t:\.w8]]]‹ÅårâéÓ§Íf3t v»=""‚D"]ºt úH©ÅbÉÏÏû§¦¦ R·ÛóæMØa„Ɔ†‚òôäädAAÁùóçE"‘ŸŸŸL&knnv8R©´§§'22rddÄ`0¨Tª¡¡!Èê®®.ø˜åry]]]GGGww·Ëåîîîv8B¡P(r¹Üþþ~¹\%ëI#Bh``@¡PÉäÀÀ@§Ó9555>>HK £ÑE966öß”¤=3ÇAAÕÏÏVäÐwC3¨§\.÷~ÁÓÈd2tmb±˜Ëåz&‰°. ò8Ò¾ÿX,–D"AI$&“éч†=öC¤›?ñÄK—.yE <ñÄ0fÚºu+LVW®\9þü]»v­^½úYêÅ?0 –H$»w‹Û½{·P(lll„mµ¡¡¡ôôt¹\.‹AZ<–µÙ^üÐá8n³Ù¤R)(Ðét:§Ó "‚SSS°7l6›aIÐh4ÎZÐó‹ûAäóùƒáîÝ»7oÞt:?ùÉO$ɼyóà”¹àà`ÖBˆÉd~¿Ï^ÌÀ÷Ï1 ƒ¥š•+W~õÕW >>Þd2±Ùl·Û}öìÙ¬‘^xá…^xá…^xá…^üP0ó(ÏÿÄ‹D"Á–Ñý§­ÌrýyH§txñûûû›L&pMq»ÝÀårQ©Tð—‚Ó Y,ܺ·ããã¾¾¾&“éé§Ÿ¾zõjFFFuuõ¼yóÄbqIIIJJÊíÛ·=t:Ýívóù|“Éäççœ5ØÔ Õëõurrrzzz{{{rr2œCa6›Ýn÷Ö­[£¢¢”Jå“O>™••åçç·xñb à Żï¾{áœL&s8“É^Š3Åø½øÇƒ¸mÛ¶»wï–””ÀÉc&“ijj*00P«ÕŽŒŒÂácz½þîÝ»ÑÑÑ6› ŽÉ \„P^^Þ—_~)‘H¢££N'¸5.Y²$33s||\ Èår‘HÄápúûûÁý¼Y&''ýüü{ì1ðí·Ùl@ÉÍÍÍÍÍ5›ÍCCC'Nœ8wîÜ‚  Å7ÊÊʈD"# ü‹   'Ÿ|R$uttôôô544À‰j^<*`“““ÑÑÑT*õÎ;p <ŽãL&“ËåJ¥R¹\ÞÞÞ.—Ë»»»Õju?…B‰‹‹3›ÍàŒ‚F¢¸¸˜Åb]»v ~FGG÷õõ577ûúúŽŒŒ××׋Åâ'Nù˜Ç㎎ªT*vçΠáª,Fs»ÝçΛÙ' …B­Vëv»>E"‘d2™@ €³6;::FFF€ËßÞÞøh²Ó‹ï€'%%]¾|Y¥RÙíöúúú ¨T*¹\îr¹Ž?4:::ôÚÛÛÇÆÆ¨TêÝ»wÇÆÆ†‡‡ïÝ»———wïÞ½ææf¨O­­­R©T¡PÔ××cVWWçççwìØ±¢¢"psƒ£5üüüúúúìvûíÛ·ãââîÞ½ Q ŒŒŒFð…2›Í“““yyy­­­z½>((諯¾:qâÄèèèÝ»wN§Ùlž˜˜„ížžðÓòâ‡hµ^üx‘——§éy®Üt'•Jõv:^|/ðçŸÞår-^¼Î,!•Jµnݺ?üðñÇçñx:®´´ô™gža³Ù RÂf³srrV¯^m³ÙÀiØ /<À0 ‹ˆˆ˜?¾T*ÍÍͽtéR`` ˆ*©T*Ç###£ØÒÒÂd2¿üòË¢¢¢˜˜˜ÀÀ@¥RÙÜÜ|áÂ…G /~pÀùo³Ù:;;Fcrr²Z­®¯¯ÏÌÌÌÊÊjll´X,©©©p,P( ioob±¸¥¥E&“ÂÓ£Nˆ?0üItÀt ’=ž[!`Sá8¾víZ` zôa¿— î…8ÌÐb2™”J%4?À`0°X¬ÐÐPX·t»Ý­­­Ð€ }'8 †Á ° D„5Ç0Í`0ÂÂÂ0 ãr¹ Lø÷[L$ÓÒÒ´ZmDD„^¯w¹\R©Çq£Ñ—””488|: …Ä`0@OØGjµšF£I$Øc P(!!!G£Ñ€r)°ü`ËÉdÒh46›M£ÑL&“X, …f³–õ Fxx8(º°Ùl˜èÀ~ÃLuZ€X,&‘H3S ƒÓé,‹ËåÂIéÅÅÅ*•J h4š¤¤$­VËb±‚ƒƒ¡cñ¼Î`0BBBT*‡Ã i`¨TªD"Q*•,+<<ø®  $•J- $\£Ñøûûûúúêõz‰DB @XÐn·³Ùl( €€­VF"‘l6›T*5, ”5!X ÿý·ŠUUU•žž~ïÞ=ØT ‘J¥jµú©§žêéé)++‹Å°žn·ÛçÎ+—Ë7lØP[[Ëf³³²²¸\®Åb („PPPP(ŒˆˆàñxÕÕÕ*•jÙ²e###™™™“““k×®U«Õ8Ž/^¼8,,léÒ¥---.—+)))$$ØsL&sjjJ(¦§§Ã^ÐܹsA­ØÉÉÉÉ.—kíÚµf³¹¢¢B$I$’ÒÒÒÅ‹…„„ŒŒŒìÙ³G,WTTH$¹\®V«ö³ŸÑét­Vk³ÙŠ‹‹333ìSSSsæÌ™;vØíöU«V]½zÔ”«««ãââ222bccoÞ¼ù³ŸýL§Óh4š„„‹Å:t:½ªªJ(VVV¶µµ9Ž´´4…BQTTD&“§§§á,HH‚H$É“9sæ´µµmÛ¶mΜ9Ë—/`³Ù‡£°°°¶¶–Åb•••ݼy³¦¦†Ãá,Y²¤®®Îßßßn·P(”—_~ùÔ©SÏ>û¬H$"ãããñññ C£Ñp8œ×_ý믿†»0-›3gÇ ***ÊÌÌäóùB¡ð±Çs8N§3##cÑ¢E—/_ÞºukSSÓ;ï¼£P(rss“““q_²dɼyó„B¡¿¿zzzIIIpp0“É,//ÏÉɹ|ù2Žã¡¡¡žúM‘‘‘:nÙ²en·ûôéÓëׯ lCCCDDÄ /¼`2™Îœ9ëÑ  åÇU*¨ÿÕxáÂ…P]¶lÙrãÆE‹!„Ö¬Y£Óé&&& òEFFj4šÊÊJNÒ9k×®mnn†Ao”9 …¿¿ÿää¤Á`8yò¤Ãá8uêTzzzLLÌüÇáøîÝ»555—/_þÕ¯~J| ƒàr¹:;;Áôô´^¯ojjÒjµÀ´¬ªªúÕ¯~åp8H$¨ƒº\®±±±ììl‡ÃÁårñ‹_ç˜Á`)•ʵk×vuuùùù¹ÝîuëÖY­VH;ƒÁHLL.))!‘HR©tbbbݺuÿò/ÿ‚Ñ“ÉT[[›žžþì³Ï.\¸!ª]$I§Óeee‘H$ƒa2™bbb€Ûã8¾xñâ%K–|óÍ7K—.­©©…£Îoß¾599ùÔSOéõú}ûö)•JZ°Z­‰‰‰Ÿþ9‘H hll„T Òh´àà`•J•ššzéÒ¥©©)™L><<\XXzZ'Ož|ùå—/]º ºa`ä IDATÓéBCC8°uëV—Ë944tïÞ=ÙNJJzá…V¬XDYìöíÛ Ö†R*•--- I»Ñ.—K©Tž:u †ù 'J¡PÆÇÇA^·µµõøCRRP™Íf3™LV*•øøãN'N·Z­n·ûöíÛ~~~*•êÈ‘#ÐÎÁqíP‡ˆDbxx8‘H±X,&“éÎ;‡JMMíë뛜œ- …’››Ëb±úûûóóó³²²¦¦¦p'‰‡C&“ ‹Å222rîܹ¬¬¬„„2™¬ÕjSRR<+À /‰h4Zbb¢Õjýì³Ï~ó›ßÄÄÄ@&477ß×n·Ã³¿ÿýï¿úê+04ÐúúúH$’F£9tèR©„œœššÒét†¡Ôét*ŠãÇS(«Õ r 2™Ìd2FFÀçó=Z_V«òÇétÖÕÕÙl¶Û·o¿úê«gΜyùå—A· †ñññ###£££Ÿ~úé‡~8³[äóùüã}||N:¥ÓéjkkÇÇǧ¦¦¾úê+ ÃÆÆÆFGGÕj5¨ :ιsç^¿~Ä"""JKK[[[cccáXÓéé錌 ð¸zõ*•J‹Ål6ø8{öìñh)RSS tö,ËårA Z‰Úg.— {Éð•Àó f¡Óé@ŸD£ÑP©T8¤þâÅ‹ ¢!‰BCC›ššANN¨uÙív‹åt:- üc·Û7nÜ*uV«Õét2™L£Ñ(“ÉZ[[Aª„@ ˆÅb‰DrõêÕ¨¨(‹uõêU™LF¥R'''ËË˧§§ÛÚÚ"""Ž=ŠaXBBŒ‡(ŠZ­ær¹ §ÖÒÒB&“çÏŸßÜÜÌãñœNg||üùó硹Z½z5( ‚‰Z­æóùééé---"èÑ:::ØlvyyyGGGoo¯Édâñx‡¨r8Ž;ŽM›6Q(”÷ßD7ƒ‚‚(ŠV«5™™™:.88øóÏ?‡+x¸\®Ó§O«Õê­[·þîw¿ãóù …b¦ &BÈßßbbz:TÜW(J$’»wïÆÆÆ*•ÊéééÄÄÄŽŽƒáïïßÒÒÃОž™LRPþa³Ù.—‹Ãá…BªIz™LÖÙÙ ‚ÍÍÍááá‹ÅCíÿøKO³®ÿ•Ÿ@Ò¿_XFˆßû"‰DŠ‹‹ãóù3v :Þ8›Íöè`ýÒ5ëî_Ržu³ïµ‡B¡ÄÇÇ{ÄÖf½~¿úN.B¡Àì›ÇãyT¾þ¦y?(àÏ?ÿ}úôÂ… |>T!www Ãsþ;IIIOž<±ÿÙÔÔ$‘H²³³,Kyyùþþ~tt4‘Hqss›ššb2™&“éwÞ±G_Awtss355µ«« –ö‚|òÉ'ñññ ˆJ_d29$$ÄÁÁ@ ìííÙ=)`·h2™‚ÕjµZ­333°ÒëõÝÝÝ<ovvv~~~vvV,ÓéôÇûúúZ,°9å´Ëb±?~ P3™L644Äf³©TêÓ§OáŽ>×î¥K—âââl6›———ÕjžžÆáp ÖàÅgµZwvv233[[[í s¦Ñh„aÆÅÅ„ÐÐP¦ÑhÄ`0Ï “H$šÍf4Çãu:4êB“““:*• …BMLL,..NLL¨Õj¡P"€ÛÛÛƒá9­²ÿ &--mgg§­­íÉ“'f``€@ „„„´··ƒ'ÇÈȬQ(”ÅbY[[£R©³³³°3ZXXæp8·oßöõõ•Éd~øáÄÄÄ‚J¥ruu½{÷®³³³N§©àžžð'²Ùl:nii)77F/--Ùl¶ååe&“éâârõêUÐë¹téRWWׯÆFZZZss3¦?ýôS0éîîÎÎÎîèèØÜÜœ››Û0‹Åãñ::Ú`0…BµZýæ›o¶´´8::fdd€EVqqñèèh^^žÕjÕëõîîî€ÃÃõµµ!!!===©©©...'OžÔh4&;;êËÊÊU*ULLŒÑhŒ züøqEE¬“’’ˆDbxx8ŸÏïíí­¬¬|ôè‘H$b³Ùr¹üĉUUU:ÎÓÓ^—åååóóóR©Ôl6ƒë΂F£_ŒèèèÇçææ …Bpƒ|ÜTð qvvF¡P‰‰‰KKKÛÛÛyyy;;;x<Þ÷/ÅÏϯ¿¿¿¶¶öã?ÍY ãëë233sàÀ°°0@”À‚@ xyy­¬¬„„„(ŠššH]„……­­­Ñh´¬¬¬¤¤$.—ûäÉøúÄÄDZZš‹‹ ŸÏèíí­©©‰ŠŠzøða^^ž··7›Í˜šš*++ {ôèQaa!X…‡‡ËåòìììGùùùAò ´´taa¡¼¼<ñl6›H$òôôtuuÔh4l6Ò$_œ/†uÆØØXHH,!Lš‘‘qýúu¸Ä6›maaÁÍÍÍb±¤¤¤455iµZ“Éó¡¡¡"‘H¥R!bµZƒ‚‚¬Vë±cÇ$‰£££^¯Ÿžž†Àÿþþ~^^ÞÝ»w=z”˜˜øðáÃíímAž<8.,, ƒÁ¤§§çä䤦¦æååÁ]¬­­utt,)))((àp8‹%55õæÍ›8N©TÒh44¶X,0ÛÁ0FãÔÔ”¿¿ÿ‚···ŸŸßÂÂØB´‡Ãi4ƒÁÀápÀ•jb±xggÇf³ @ˆáéÓ§yyyd29::zpppff‡Ã-//CsCCCÅÅÅàZ¸»»Áçóñx¼‹‹Ëææ&pO¶··¹\®F£Êææ& _©Tr¹\N§Óé\]]777aî5°–wuu…ëŒÁ`bbb***íŒF£ãâ⪪ª"##kjjärùüü|]]ƒƒCIIIFFs~¾`aòÞÞPùl6›ƒƒ|X,Ûl¶_ýêW0T½^Ãá Ã;#B¡l6 …*++ S©TøÃœœœ H"‘vww§¦¦êëë'&&¢££aóЦÕj­®®Öëõ»»»óóóÇõòòÒh4ÕÕÕƒaqq±  Àf³577744,//»¸¸ÀùaààZ¨T*çææ¼½½% ÇÓéto¾ùæôô4“ÉÉjŸššŠŠŠJNN¾yóæÐÐPYYYÿáÇÁΤ°°°©©ÉžímhhJUMMMSSSYYt£ººZ¡Pètººº:àÕ9::Þºu ®³Édúä“O®^½jÏ †¦¦&pß¼uëVtttPPÈÊôÑG@œùŠ•‚üÅ,Òm_0³}‰ …zÎ9ãó¦#öz`±~áíñåçÎF©öz»ùà—ÕÓðóçùŠòe~¶?_6L{½½ÿö³Ù¯çW÷¾ç!‰ÏYÒA± Û‡ù\÷ì>ßœ½’˜ÏÕÛqxöëùµå«/—½``†wppÀ†Åb¯pª±Ùlð»$ƒÁ``2™‚J úÄ`0t:N‡@ øHÁñÀ1„Ä0Ô«Õjð*”ñx¼V«%‰h4O4 rm€‹1zƒÁ°¿¿S#d~ö÷÷]\\À ^»NNNðEhtýu:““‡3™L^â...z½\nöööX,–ÕjE¡P0^»Âûþþ>8ç<9‚T&¸DÁŸöúg?Àô| píÙã÷÷÷á¥ñµ‡=[oÿ>|¾¹ÿiý×–çü°¾¬`‹‹‹áÞ †Û·o‰Ä_üâ?ùÉO*++[ZZâããm6›L& … A~àÀ‡›7o&&& ''§éééÁÁÁS§Nݽ{ì* ܶ‘‘‘ŒŒ ÓÝ݈Á`~÷»ßݼy³ªªêèÑ£ "‘(**ê‡?üá /¼Æ óóó\.×jµŠÅb¡PH"‘666p8Üúúz__ßþð‡ÿøÇ………8n~~ÞÑÑÑh4zzzêõúááá””,;88Èf³1 N×jµOŸ>ÍÉÉA£ÑÞÞÞ …Béõz±XœžžnµZ;;;ƒƒƒI$’Z­†ñÞ¾}P&“é_ÿõ_'''Åbñðð°V«%“É:ŽD"}ôÑGÕÕÕà æÂå½ù& LÂX,ÖÅÅecc£¸¸xoooooÃáp¹\&“ÙØØ˜™™€ÇãWWWSRRt:Ý¥K—.\¸P__ÖÁÁÁL&smm->>~mmÍÑѱ­­-??zzÇonn&$$Èåòàà`<ßÝÝ »ÞÞ^‘HtáÂ///pg ›œœ\\\är¹ *ˆF£/_¾œššë±XìææÖmyyy)ÊÎÎƇÏùóç³²²°Xìõë×KJJ¤Réþþ>ŸÏ?þ|ZZ™Lnll¬¨¨X__W*•áááׯ_NNN—.]JJJ}÷ÝwQ(ÔÔÔTUU•ÍfS©T'Nœpqq©««sqq‰ŠŠB¡P]]]\.÷G?úQHHÈÀÀÀ—Í7ßÀ‚yýõ×/^¼H&“BCC-‹@ …MÌdðj_]]õõõåp8ÃÃÃ"‘¨³³S ÌÏÏ“ÉD"‘˜LfSSSHH‹5™L°Uï“ÖÖÖˆˆF´¸¸h6›i4ÚììliiiKKKEEESSSjj*‡Ãééé0Zkk+…Bqss¢¶³³³ÉdŠˆˆ˜››svvvqqY__‡¨ ™L¶X,°£¤ÓéË8ƒÁŽ~Ááp°qÓëõ{{{\.‡Ã-,,P(ÐGtÊÈÈÈââ"ø;@š2..îâÅ‹Àóöôô {úôéÌÌŒÕjíêêzÓòM/B¡Ífƒ9/‚ >>>h4:%%…Çã1ŒÌÌLP'&&âñøÔÔT~xxx âáᑚš 8ô0'vqqñððHIIË×   ‰”““pOOO,K¥RÁÃ<ÒÒÒáóù>>>D"‘Ãá‰ÄœœpYÎÌÌø!ÇÃb±ñññ`Ó™™ h™¤¤$Ø-C¢3++ `Lééé &** ̧³²²˜L&“ÉÌÌ̈¨¨(,›––8»ÌÌL»7‘H”ššúyu{//¯¿Þ îWþ—Ãz¾-§óƒü`oo/::º´´tggçСCB¡paaáôéÓh4ÚÕÕµ¡¡áÑ£Gßýîw322 Åñãǃ‚‚ ¨ˆ Httt\\ÜÜÜœ››ÛÁƒq8à¥üýýóóó¥ ô ‰Š‹‹———O:?33sæÌ«Õ ð6›½¶¶–œœlG#ýøÇ?KLL¬¨¨P©TEEEiiiSSSàzZ__B¡’““³²²VWWOœ8f4H$’P(„ÜÅñãÇ£££¡?ÎÎÎÅÅÅ …âСCqqq …âĉ\.—ËåBJª¬¬,99âõ°Þ¯©©1™Lr¹Ü®ÿvöìY¡Ph±X ¿õ555………Û'Øg]µ¾9 Iø±±1N.{T*533¢ýýý`¥÷øñc±ôööòx¼¥¥¥ÎÎNÈ©A¼¾¾¾žÍf÷ôô(•ÊŽŽŽžžžµµ5¡P(—˽½½³²²®^½ ÎÕ‚ÙÃÕÕ5##ƒ@ àñøææf“ÉÔÙÙ™žž¾´´tûöm ¥Óéðx|\\ÜÝ»wÁ$q~~>,,¬®®ŽÍfgee}üñÇYYY>>>Ož<©¯¯_YYqvv®¨¨hllLNN kii9xð ^¯'‰uuu—.]Љ‰‰‹‹ûì³ÏêêêÀ»±®®îÎ;!!! õUVVF£ÑÖÖÖêëëûúú€’õÉ'Ÿ¤¤¤888œ={¶¤¤AOOO­VüÒK/ÕÕÕ9s¦®®nppôë(ÊÑ£GkkkŸ³¥ý†t[[[QQ…B‘J¥V«uuurÌÏFù-®R©€_–››ÛÔÔ´¹¹¹´´túôi>ŸÏ`0ø|>`Ð?ûì3A||| ðx<•JššŠˆˆP«Õz½ž@ ´··çååh J¥âñxÀšŸŸ·“>ûì3ÀÄcqTT‡Ã hùþþ> …‚ðƒKHÂAç- $˜íV†6› êá„ö/BZÌíõ‚@½Íf3›Íkkk—Õét¾¾¾r¹|mm ê ‚L&c2™ð‹2Åßèæþ- ¦¶¶vdd„L&tvvr8™LvçÎìììÙÙÙÉÉI:>== q ‘‘È–Óh4 …>ŸîÜ9H ¥b~~¾¼¼|ooòS“““2™,  ½½]«Õòx¼¶¶6.—«Õj¯]»VXXøôéÓ••`·áñøÙÙÙ˜Íæ••4½²²B¥RÝÜÜnܸA$Y,Ö… Z[[5MOOO~~~{{;ð0)´±±ÑÚÚZRRòðáà ¡PØØØÈçóÕjõµk×*++ûûû%IRRÒ'Ÿ|âææf³ÙàÁ}úôéÓ§OÓÓÓoÞ¼ ?Œ+W®¤¥¥ÍÏÏ÷÷÷çääêk||6€¾¾¾gttôöíÛR©tzzZ"‘$$$p¹ÜlmmÍÍÍ=“ü¶|[¾-ÿï †ÍfƒnŒP(ÜÝÝçóùÛÛÛÅÅÅ §  `mm-<<<<<|qq‘B¡­¯¯óù| Ãf³ÓÓÓe2Ynn.ÇS*•ÅÅÅJ¥’Çã%%%-..¦¥¥µ  `jjŠÅb•””,--¥¤¤8;;ïììTTTìíí±Ùl8?ö÷÷çóùAAA6›-##ÃÏÏoss³¸¸èot:}}}N«Õj‹ŠŠÌ)‰–––ÒÓÓœœ4MIIÉηÃIIIYXXHIIÜ~yy¹V«äÉââ¢H$òööV(ÅÅÅ‹ÇçææÊd²ððp æåå988Øl¶‚‚¹\n7ÓF$333,,L.—? HKK“H$ ú[ÜÓÿóÓŸþ€çÏŸ¿{÷.Ç …ÃÃÃ@ Ð4‹õ÷÷—Éd]äwÞyG*•VWWwww›L¦êêêÞÞÞ¢¢¢§OŸ–””ˆD"Ø‘H¤ŒŒŒŽŽŽ†††{÷î}ÿûß3é´´´ÈÈH`PÜ»wïðáÃ111T*µ¤¤ÄÉÉixxxggG Ëår‰DB&“ããã·¶¶òóó{zzªªªÆÇÇËËË£¢¢ Ell¬‹‹‹P(ô÷÷¯ªªŠŽŽžššJNNö÷÷ òööž˜˜¨««ƒ €Y,V@@ÀÚÚZiiiDDÄððpAAAxx8رÆÌÌÌÐÐБ‘‘ÜÜÜ¡¡!@€F£5Í /¼0::š™™i6›I$PÎxB§ÓWVV’’’\\\€ŠøM+hƒÁÀ`0^|ñÅááaƒ177çááa4aáÜ×ׯÑh&&&ø|>ˆm>|X*•²Ùl''§ôôô¨¨¨‰‰‰cÇŽ1ŒÕÕUˆƒGEEܤAa©H4€òD3!!A«ÕîììÀ¶ÿ8ŽËå‚*ÄÕ«W™L&‹Å:räJaÇzæÌ‹À7‹Å²¹¹éíí­T*F£««ëêê*•är¹ÏÎÎŽV«õôô\]]…T¿\.÷ôô@©——Ü~‰´¶¶ÆápôzýÎÎÇ[__·Z­°I¤P( æôéÓÅÅÅ‚0 ‘Häààð /8pàøñãUUUííí‘‘‘CCC§¾¾þðáÃvQ‚oTÁ>}ú4""âÖ­[UUU ¥¼¼\£Ñ€q<‚ ÕÕÕ‹‡Ã>|X¥Ríìì<|ø0++ëÉ“'àÃ.•Jétº^¯çñxÀµ?|øðòò2Ȱ¸¸¸¼òÊ+7nÜ @‰™šš€y‘Éd…Bl0‹Å:'f³òü...ÛÛÛcccÁ›v°ý IDATÁÁ2™Ìf³Y­ÖååeHAsSSSÞÞÞÙÙÙwîÜ)..ÞßßôèQCCƒT*e0M@mssó‘#G`O€$POhnn®¬¬Ôh4»»»|üøqBBBdddKKKNNŽÅb™˜˜8tèÐüü¼Åb9sæ ì7- d£Ïž= è.›ÍöãÿØ`0xxxÌÏÏÿþ÷¿7fü¦È(?[a4ý…ˆ" ‰ P§@žÙ?<·Ô€BxÌþ'GGG`Y7ìÈOÏ6‘,ûl7¿à‡°Xì³ÇÛ?Øñg³×Ûñg€Ã|ö‹Ï ÿ¯¬ü¦´ƒƒ„pàÂY­V€æàñxÔ_ òŒÒ@€ãaÆ‚8ò   &•ð]ÀP b6›!ÔîííÙ[ /4³<öž@0ùÏF?×O{ý³Ú?<;®g?|~¼€ÌFþ"Ññ\r&*øQ¡P(˜zí1c‡ÃàƒýÙµƒæìh;ø@"‘`°ö_œz¶~QPWFC®ê‘¿ü†Q(ü8¡P§…z, ýÁãñpÍ¡ƒÁ@‡í?f8!0¡nå³ ¡~ÿûß_»v gîܹ£T*ó›ßœ9sæí·ß~饗òòò<=='&&"""ètúgŸ}VRRb±Xfff|||fgg½¼¼VWW;;;Ïœ9óàÁƒŽŽŽ7ÞxcppP loo_¿~ýÌ™3­­­*•*>>žÇãýèG?jiiùîw¿›’’RPPðÿðEEE}}}?ÿùÏOœ8qèÐ!GGlj‰‰””›ÍöÑG½üòËwïÞÅáp>>>b±8,, AÖÖÖÜÜ\«Õ:99éãã³²²âëë‹B¡ÚÛÛí¯ÂÐÐP»¾Òƒ*++inn‰Dðèãñø¾¾¾ÂÂBÀ즤¤¢œÁ`Œ'%%!òÛßþ^èJ¥2 ॗ^Òjµo¿ý¶R© V(ÛÛÛiii€ºÑh4ÍÍÍgÏžíèèØÙÙ9vìØµk×bccFã­[·NŸ>½¿¿ÿî»ïþú׿>vìXhhhCCÙ3gÜÜÜÞ{ï½³gϾþúëwïÞµZ­ÞÞÞ7nÜxùå—/^¼(‰rrr:;;¯_¿Îãñüüü~ùË_ÆÄÄ0Œ””<ÿñÇÇÅŹ¹¹­®®:99µµµ>|Øf³3Öd2œÓ“'Oòóóm6Û­[·RSSÍf3hÀLLLÄÇÇ#!L‹ÅøýÅÅE Š´µµìïï ñùü .— ·²²2AîÝ»¥ÓéÈd2ƒA«ÕjOOOˆ¼óùüºº:±X¬T*ë|õêU€Ä\ºt‰F£‚ˆ¹ûûûAAA</22ÒÉÉI( ¿u ­ƒÏïÈȈÅbùÕ¯~USS#‘H4Mww÷Í›7aTsss(ŠËå^ºtI ¨•Åb£æÊ•+ÓÓÓqíííÍÍÍíìì„ýÁG}±¶¶¶¼¼¼ÁÁAµZ˜˜/ …ÁÏ™™…B‘}þüy&“Éf³°¿²²"‹srr>ûì3 …âíí}éÒ¥ÄÄÄ‘‘P¶9wîǃŸ²‹‹ lô£½úê« ­nnnaaa C¦R©:0 ÎÎξ¾¾‰^ƒƒƒ‚´+QA>{ggÇÅŦsrr>| l](&“ÉÕÕU*•^¼x…Bíîî^¾|™Éd OOÏîînJqL&(=ÀÌÁb±L&S"‘8;;‰D¹\›JA8΂““™L–J¥nnnûûûf³™ÃáH¥RGGGGGG &#¢×ëAý‡D"æÑÆÆÆÛo¿ ëýÞÞÞæææ¨¨¨ùùù–––ÆÆF­V+—Ëýüü ÅãÇaNEdkkëüùó~~~ãããÍÍÍžžžt:Ęž}™tÛßßßÉÉ©±±‘Åbmmmuvv†‡‡wuuÍÎÎ&%%ŒÖÎÎÎåË—í¬gggàð¼úê«}ô‹e³Ù@ç¼rå °A×ÖÖt:ÀqÍf³««ëÒÒ•J¥Ñh0dHȉD"ƒÁX\\„XOÛÛÛ8ÎÙÙY"‘¸¸¸àñøõõuWWWN‡F£Y,–D"a0$I&“q¹\ Ô¸ºº"UUU^^^¡¡¡ÅÅÅ0ÓÀÔ¤««kUUF‹ŽŽÎÍÍ%‰ Ïf³«««™L¦¯¯oqq1hMÅÄÄÀ•ruu (++sppð …,‚ þþþ8. ÐQvQ],Ëáp*++†%‰°XlqqqPPPHHHeeedddXXXvv¶ƒƒCNNNHHF«¬¬„eAA‹ÍÈÈˆŠŠ"‘H•••À,++Ãb±ÉÉɱ±±8®²² §8.666)) ÈLÞÞÞ,«²²’L&GEEedd<» ‡-3HX=ûdP©Ôªª*‡ãîî^QQ³ˆ¹UUUyxxxzzVUUáñø„„„„„A ¶ —N\1¬££cUUƒÁˆˆˆb>‹åóùt:½ªª ~Q~~~¡¡¡nnn8®¢¢¢´´”H$Âöõõ=pàÏÈÈHKKƒ!»»»pÇ‹D¢ääd²}È‘‘‘ùùùNNN•••t:ÈÌYYYááá ¥²²ÒÅÅn=‹MMMŽŽ&•••ÇÃÃöàžQž½Xðç73{úmù¿RÐîîöÚköÇèàÁƒ Åóâ‹/b±Ø˜˜˜_|1++ëoÚÏoËßYA>|A‰D  …òõõ]YYsss‹%22ryy°lß–oË_YþóØÜÜ ‡8@¯éêêÚÙÙ)--E$&&æÐ¡Cßš|[¾¶ ———ñóóS©T•••°“B¡Póóó ç 鉉 A.^¼ø­+î·åë DWKKKi4x}ÇÄÄÀ«¨¨è¯'ª[¾-ÏLNNŽX,éú¹¹¹°°0СËÉÉ™™™Áb±III2™,00dd’““===5MFF¡ÂÃÃWVVRRRP(”ÅbÉÉÉÙÙÙñòò‰DJ¥2::šÁ`¨Tªüü| :'&&J$MmnnæææîììDFF†‡‡£Ñh777…B‘••^å™™™kkkAAAkkk©©©D"‡Ã …B©T* AX999*•ŠÍfGFF.--¡P¨ððp•J•››«T* FZZÚÒÒ’H$ A0Ÿnnn•¡P(±±±R©4!!˜ŒYYYëëë`cc#!!¼Crrr¶¶¶¸\®H$’ÉdIII>>> …,---EEEq¹\éÙÝÝANN—œœœžž®!$)77W£Ñ¨ÕêÂÂB¡P(‘H¶¶¶ªªª„ï§%‹CCCÝÝÝy<žD"©¯¯¿sçNdd¤V« „‡›ÉdæææúúúnooGFFfeeÁ„ŠÁ`ÊËË»»»Ož<ÙÖÖöâ‹/ÎÏÏ«T*OOÏÂÂBµZ­Óé*++æèèyâÄ &“999 D£ÑèççW\\<22"‘H0L\\܃BCCM&S}}}WW‹ÅJLL ÓjµÉÉÉÉÉÉ333‚$&&&%%ênn.‰D‹ë¢¢¢ÁÁÁÌÌÌ•••òòò„„¥RéïïÚ××wüøñŽŽŽÔÔTƒÁ\^^þàÁƒèèh U\\ (»¸¸„‡‡§§§ßºuËËËËÑÑ177wnnŽH$†……%&&úùù---•––ÆÅÅ;((H(zyy-//WWWÃL‘ ‰üýýÁS£²²8Ʊ±±`ÁÂd2ÿùŸÿyzz:!!a``àÀ*•*::Úd2½ýöÛŸ}öYmmm^^Þîî®Z­.((€ñ‚,ttt4¨~ÌÎΞ9sF*•¦§§ûøø$$$ íšDÙÙÙ[[[f³yxx˜ÅbÙl¶ÕÕU0Ìimm%‘HËËË"‘èÊ•+÷îÝñ.›Í&‘Hø|>µAÂh~~>&&žH"‘¨V«ssswwwÑhôââ"‡ÃyðàZ­žžžNOOwqqÙÙÙ±öövAÖÖÖ ÅS©T Æßß´k Âîî.¼æçç“’’ èìèèØ××ÇçóÛÛÛÕj5LŠÉÉÉ*•jqq1;;›Á`´¶¶Âœ*‹kkkQ(TJJÊ… ¶··===Y,VmmmBB•J}ùå—‘¦V«ççç322€3‚B¡>|ÜÙÙÙÕÕ• R©$ÉÑ£G]]]Åb1‰DÒëõiii6›mssS¥R¡Ñ¾Ô÷îÝËÊÊ2 ,ëèÑ£QQQR©Aõõõøøx6›Íf³8¯Pä mii™ŸŸOII‰‹‹ «››(öîïïÃ+eccC«Õúøø€äƒY\\ ÜÚÚÚÝÝ €_‘H„ÔEllìèèhyyùòò2ǃñÆììlµZ]WW7??âççg±X„B¡V«…ñjµZ0Càñx4í¥—^ @`³Ù|>ÿϱ+*•:33Ãd2ß~ûm°õöòò²Ùl}}}F£qvvö¿øHyzz*Š’’???0°X[[3ccc‰¤  ’öÀÆãñÛÛÛ‹´“Éd²V«-//çwÀ«\&“‰Åb‹ Š·ÞzkccÃÇÇG"‘€V ¸ÖìïïonnFFF È"CÏét:H⤥¥Ƥ¤¤””×ÕÕe2™–––ººº †X,Ѱ^xÒà"z5†ÉdÂ<½ººŠF£çææ@$§¢¢^p ©Tª\.G¡P999€J¥=ztuu•B¡€.ÜäädMMÍÆÆJ¬V«¿¿?—˵‹VÂñ€4Dd||¼¨¨Èd2=|øm+++ ÆÑÑQ&“® @N`¤b±X$‘Éä‘‘‘ššàVåææ¶··‡„„¸¸¸€ØâÆÆ†Z­®¨¨hoo÷öööôôìììÌÙúúzee¥L&C¡P{{{ŽŽŽ`ÞA ÍÕÕÕE¡PðxüÐГ“(oè?›ÍÞÚÚN7 z½¾¤¤¤¿¿ÿÑ£GR©ôÏ:IX,„H$‰D?1»¾9‚ D"êáx‰„Ãáðx<ÞAÎ Fƒƒƒ|‘B¡€ …ˆ 4„Á`àé´£nì Óƒa0@¥rttD¡PŽŽŽv‚ 8T*•H$b±XH¾ÂŒ ÷P%Ѓqrr‚‘gÿ9…-<^ÐŒ "öh‡ÃÙ;t(ŠN§Ã…²71»TÔè!F{öRÛ¢Ñh0R;b :÷ûÙ† d2€+t:P²Ï^jh9t:Á`°X,ûõ±×~Á‘ÿSLË~ga¼( pç‚@=‹…n€bb=—À±×Ùöh–=ÿ³ˆ½¾ø,àé¹>÷çsá±Ï'”žK4=×З}ÑÞçFdG’=×±gf_Ö“çêŸàWôä Ïóµåï1·†ýÞ÷¾g6›‡††JKKÏž=ëêêúïÿþïo¾ùfQQ‘Íf[ZZòõõíïï÷óó3 wîÜùÙÏ~ÖÙÙ¹¿¿2:: þMüñ믿¾··÷øñ㘘Èx»¸¸455“H¤÷ßÿ­·Þª©©9}ú4(Òœù$55šX,V[[[aa!™L~çwÞ|óÍÓ§OWTT¸ºº>|ø°¨¨FÿÇüÇO~ò“7Þx#33“Ë厌Œ0Œ¤¤¤ÿú¯ÿ"‰¥¥¥çÏŸÿáxâĉþð‡Ÿ~úimm­Åbiii‰‹‹suu¿ªÛ·oCr÷_þå_Þxãúúz³Ù|éÒ¥Ÿÿüçñññ©©©?ýéOWVVh4šJ¥ŠŒŒ55åëë›””ï¯ÖÖV€ëÜ¿‹Å‰D«†VWW®\¹2666??¿¿¿ýúõÕÕÕ–––k×®Q(”ááa±XL >üðÕ•µZýñÇS©TÐìG¡PÞÞÞ}ô¸«Îjoo/ …ruu«æææ‰‰‰¹¹¹¬¬,F3==½¸¸=‘Ëåccc ä«Õjß{ï=Psuumkkkii™ššC¤  @§Óéõú–––îîî•••ÀÀÀ>øÀÕÕÞSL&3 àƒ>HMMýàƒbccA5 A‡úÍÃ'æ¯,èññqûZÄÅÅÅÑÑ‘Ïç§¥¥I¥R°â¸{÷. ÕÑétçÎãr¹À~!A¼½½{zz CddäŸþô'www@ËI‰´½½m[Ã^O"‘\¹rÅjµ"F£¹¹¹?>((¨©©ikkk``@­V[,–°°0<yLAÔj5NÇb±ÞÞÞ~ø¡··wxxøÃ‡¹\nJJʳÐ.°xXÕææfttôèè(F …‚,--¹»»/--Ù‹@ FwþþøàƒÀY#<<|~~$œÂÂÂà¢F@®¯¯Ã’Èb±¸»»¯­­ýñã¼¼¼ÎÎN{ÇÀq)"""55Д°-E¤··÷Ñ£GÀöž™™¹páBssóââ"À£­Vë³î½ÿ› ¦°°°µµU©Tj4š………ÎÎN˜®RRRº»» …P(ÅÝÝ]àîõ÷÷÷ööÆÄÄ´´´ìîîªTªééiooïÉÉÉû÷ïÇÇÇß¹sÇjµr¹Ü;wîðùüùùy±X¬ÑhÖÖÖüüüÀ‡N§ËårP£ìè艈ˆhnnÉÙÙÙ¨¨¨7n´µµÖPh&''ù|þàà HÞ¾}ÖÂ]]]z½|S ! ‚ÄÁÁÁ‹‹‹£££YYYwïÞ¥ÑhdNÁÜP«Õ* ‰D" ?ýôS‹Åb6›ûûûµZíÆÆ†³³3‡Ã¹qã†Éd’Éd‰¤§§gnnnyyY£ÑÈåòÀÀÀÝÝÝ[·n±X¬™™©TªR© …¿¿ÿþþ~[[›Ùl^\\Üß߇ã?~<===66f4A_ÞìðÐøûûïîîvttLMMétºÙÙY sëÖ-¥R©×ë766ìú¨ß–oË7®`Ž=*‰p8>>îx …¢¡¡䪪ªär¹Á`8vìØòòrCCƒ‡‡‡N§«¯¯W*•’ÖétEEEZ­öÀ{{{Ç‹Å`0¹OOO??¿¢¢"©TZSS# !:.‘Hjkkårymm-ð m6[iiéÐÐPMM $@>ìéé‰Á`:d6›ãââçç竪ªÜÜÜvvvŽ=ªÓé"""€M&“:´¾¾~äȉÂ]Е••†† …âîî^TT~ÁÇ×étÅÅÅ@©ä¤$°¸>v옱Z­Öˆˆ°Þ8qâÄîîîÖÖVll,—Ë ‡\Pyy9xUTWW*©´´tee¥¤¤$66vmmíÅ_ìÊÊÊÜÜ\@Vê@ñ¨¨¨0J¥òøñã³³³555`G]WWg2™bbbÒÒÒÄbñáÇCCC1 Xi0™Ì¼¼<…BVr¹®›Í.--]]]5™L"‘4Ïfff>L¡Pœ«««Czüøñ‰‰ ‹•——g¯@ ÈÎÎ^^^>tèŸÏí1ƒÁ’ŸŸ/•J<èç燋ʼn¤¿¿´S@×¥¢¢¢··799¹¦¦Æh4Z,–‚‚P5ååå@d _[[c2™>>B¡Ðh4‚vkii©P(Šééiت/--‰Åâ„„pçsvvf2™‡ºÿ~zzzaaá½{÷òóóaF€ñ Îäz½><<<###//‡Ã544ØÇ ‚g ¯°—ÂÂB~JOOôèщ'P(THH:--íþýû‹Åf³) ³Ù Òç3?uêTQQŒF#ÄEGGG€˜©â{÷îa0˜½½=ÐÐа»»ëëë Äùêêj³ÙÌçóWWWAooïîî.ø‚‚tÑ©S§ Ñ{åÊOOO6›‘‘ÑÞÞÁñÝÝÝõõõ¤¤$•JÞ“ÓÓÓ·oßÎËˋř™™8N"‘$''³X¬ÁÁÁÇÐÝÝ=::šÃá¨Tªƒž;w®³³sbb¢   ±±”žAÒ£«««¼¼œÉd‚Žˆ´··(H$ªÙb±èõzxl6‰D²Ùl&“ 4é©©ÙÛÛóóó„‹ž••ÕÖÖvíÚµÚÚZ§¢R©ayyÙn›¸¼¼œ‘‘ÑØØ¸µµ•˜˜ˆ \¥¥¥‚‚‚¶¶¶êêjð¹\XXHKKc0{{{‹ìRÐh´Z­†rRRRww÷ƒ¦§§KJJ€YN$អÑhPÀ \[[ƒñòx¼ÉÉÉ¢¢"p–d2™•••V«µ¤¤„Çãyxx€"<‘HÜÙÙj ¨‹Q©Ô††Aööö L7??¿ááaA¼½½ð¤V«oß¾ Öccc©©©>eåùùù¼¼¼žžž¬¬¬¾¾>, zW>>>ýýýƒ¡¨¨h``àÂ… ¡··ÇÆîîîÅÅEPj0 :®  À`0,--edd¬¬¬üáØßß'‰]]]>>>CCC6› :ìš©©©’’pUc_PokjjŠŠŠ20_NMMÍÎκ¹¹=yòìXÀSiooJ¥FFFvww'$$ Ñè›7o–––J$™Lææævûöíëׯ“ÉäÇûûûÆÆÆMNN* '''xµmmm™L¦¨¨¨©©)0¸ò£^¯øðáÒÒ’V«€Ã­[·À¾V?ããã555ÛÛÛKKKÎÎÎb±\Uu:°y;;;ýýý²²²X,–V«mll$‰ð¢ìèè(,,éyvÿþ}Gxüø1Ç …·oßKœk×®•——‹Åb©Tš’’»¡¡¡®®.2™|÷îÝ”””ÍÍM 2MNN^¸pD"ݺu«§§‡ÃÙnvvvÄýýý>>>Z­ööíÛ………ÓÓÓ°Úiiia0φý¹<MF>öý|ý³T–ÏÿeåYÎñÖä« IDATÙñÏ5ôÅù¯éÀç¿øÕ=ÿŸ^¯îð×öð Ïö…gþ²+ð\‹_8Rpvýuï¹>ÁŸý“””d4!&¹¹¹i³ÙüüüÔjull,è#‚&,ØMqxŸˆD¢­­-ÐÄ(L¶±±±*•ÊÙÙ944,öœœœL&¬”]\\ÁÚÚZhh(ÇÛØØ[­P(ø|>ŠÀJÂ`0¸ººB¯%*Bàr¶³³Ãb±  )Ìf3hEEEùøøX,oooggg•JVD"Q Èåò€€‡£Óé„B¡B¡ R©`}}°C*•J(nmm cÞÞÞ:Îb±xxx`±XpúóðððññY__ #“Ét:xi "111žžžƒ!""¤áÍ"¼¼¼@Ân …Buˆ]#î“P(tpp€—ò³åkã_v€ÍfÛßßÎæÄ~ðW|ë øÂ?1<T¦^xá…ööv‘HôOÿôOÎÎΕ••€² ÁãñQQQëëë }†¸¥Ñháµ²²²¤¤$:N&““’’€mL£Ñ|||òóó?~üýïÿöíÛååå°õ8tèD"ñððpwwÏÏÏ ÃÄÊÊJFS(”¢¢¢'Ožüñä…H$²Z­`ÐèááÇãcbb\]]½¼¼ 2¯¼òJKK ···CBBòòò¶¶¶p8ðõˆD¢››ŸÏOII>uêÔãÇ¿óïh4šÐÐÐ’’//¯………šššÙÙÙ#GŽètºÈÈÈ………’’’©©©¼¼¼²²²Ç¿òÊ+÷ïßå•W( ‹ÅŠïëëƒø0(×CÿàÁƒ===¯¼òJ[[@¸råJGG‡Édª©©éíí5›Í`š*’’’&''ýüü¶··CCC©T*˜àutt|õcô¿ª Y,–Ùl–J¥°*/))Y[[[\\} äk4š¹¹9xÆår¹}û­R©Äb1h‡òx< £Õj“’’vww[[[a&˜››£Óé\EäòåËþþþccc2™¬¤¤ü,!Å‘˜˜¸»»»²²’m2™|}}¹\nuuµT*¥P(ÐWWWÐ2›ÍÉÉÉ»»»íííáááJ¥’Ãá\»v ìé@ PD cxxì™._¾044ÔßßïêêªÑhÀFšJ¥Žyxxàp8777µZ½´´„ ÈÖÖ–¿¿¿³³³^¯Ôepp0ˆnÄd2ñx¼€€€ååe­V«×ëÃÂÂþô§?ét:çèèH¥RïÞ½ r‚?~|||p}}}»»»¡¡¡ï½÷ž««+ì§€)þÞ{ïeff¾÷Þ{°½’zuuõ_é¿õ·-hô3~qadd„Éd¦¤¤€œPUUÕâââ³^g°âp8}}}@ìAÄÅÅeqqÑjµzzzöööº¸¸ÔÖÖÎÌÌx{{'&&‚yêÔ)NÖ•pKž²:ÞÞÞK¬|@£Ñ^^^°%ööö9€Uyxx@RÌÇÇàJd2…B¹»»;;;ƒ, ¼¼¼`_ ÏœŸÁ`¸¹¹Á» º@žÔ)  éX8‚ D": ¹¹¹r:ØCØ÷Úû Øÿ!ÂápX,4D"‘žíè5€l¹ÁnÎÍÍ pT †B¡ðx<„Ù‘[Ð4Äd2AêŒéÿ:;;'…J¥ÂªÖÞCÐc!“ÉÏ-“ÜÜÜ@‘À^ ×üïOðËöD_»·²OB_¸5@žÙ;·©ù|¾¬c_Ö“çzîRØ[ùÚKýµýùj Ø×îs¿zß÷µx2{±×¾b_¹xñâÍ›79’““£Ñhö÷÷ó›ßÌÍÍ>þá‡vuu½öÚk,kooïg?û …JOOÏÍÍÝÞÞ~íµ×‚‚‚”JåÏ~ö30œ®¨¨æÌ /¼ Õj_{í5X€×ÔÔ(•ʬ¬,Hh¼þúë±±±h4º¦¦†Íf§¤¤äçç †ï~÷»ñññz½þèÑ£|>?222''gww÷;ßùN^^xq§§§ûûû˜ÍæÊÊJooïÙÙÙäääÊÊJ'''è@FFFPPÐæææÏþs&“9>>þꫯ’H¤ÂÂÂÌÌL½^ÿï|'&&Æb±ÔÕÕùùù±ÙìÚÚÚ¾¾¾ú§JMMåÈæææ“'O_èìÙ³ ¹,ûÚk¯µµµÑh´÷Þ{obbâÔ©S ÂÁ`0rssóóówvvNž< Ú§ÕÕÕ',,¬¡¡ƒÁœ8q"%%E"‘¼ûî»7nÜ8~üxAAÁÎÎÎ?þã?ÍæèÑ£@vÊÏÏ7f³9++kccãÝwßœœ<}ú4nÕ×׫ÕêcÇŽegg¯­­ýô§?e2™ ¿’˜˜©P(¾ÿý罹¦‚¯G@@€¯¯ï¡C‡¡C‡²³³Ñsss‚øùù]¾|9>>¾¾¾^¯×¯®®^¼xÑÁÁ!>>¦ö•H$SSSW¯^E£Ñ`ßE úúú\]] …zúô)¸Ê_¿~}gg§­­í7¿ùÍfûó$H=‰Äåra;vôèÑ>ú(!!tj¼½½ÝÝݽ¼¼€ÚÁãñnܸÁáp°X,™LÆãñ&“ 2S‚@ÎçÁƒ‡D"988øûû_»v px<>$$D,äú»ßýN œ?žÏç †Ï>ûL§Óáp¸ÿüÏÿ òòòºyó&Ç‹ŠŠ÷À?þñ<O¯×wtt$''Cÿõz=…BÁb±@ù —ÉdêèèÀYxxøµk× †Ífstt„õ»B¡ÈÌÌD¡Pááá(ÊÑÑQ«Õ.//onnVUU988„……EEE=yò<>çççýüü>øàôôtA éK¡P†††@<ÍÏÏobbˆ‚@ä ÇÛµàÏ;·O?ý0·°x…ÿB€ÆÍÍM$©T*À6ºººB”J¥J¥2&&¦­­M.—»¹¹µµµAº÷ÓO?}úôéää¤\.÷ðð¸ÿ>H¥­¬¬¤§§ß¿cc·l6[.—CòG&“yxxP©Ô[·nÚ{zz:,,ìöíÛ›››‹e~~¾££cyy<ÏÆÆÆärylll[[Nwtt¼qã†ÏÌÌ d”ïÞ½«×ë×××e2™»»;èà™Íæåå娨( ZvÛÛÛ7oÞLOOïêê‰DCCCÛÛÛ³³³2™lmmÍÝÝJ¥®¬¬$&&677ƒ tww7Œ2r+++»»»AAAþþþT*U*•&''ß¿_¥R)•Jp¢°oS¾-ß–ÿËó½ï}¯¯¯O ,--B„½¶¶F3™ÌÒÒRN÷ÿ´÷æamgÞÿÑŽ6„‹„„„@,fß÷͈Ý6Øx‰í8qâ4i’6igúΤ3WṲ̂K¦í´M[O´®c;66ì˜}cfǬ’h—ôþq·ºòºãÎLßù]ýuÞ>ø²ÎyÎsŽtžç¾¿÷ç››››™™i2™¤R)Hx«ªª´ZmJJJ`` Íf«¨¨HII1›Íµµµ£££™™™yyyr¹¼¾¾^¯×c±Øúúz»ÝÎçóKKKWWW+**@$tîÜ9ˆcI¥RÇÇÇ/--=zÞ,ÙÙÙ·IMMµX,%%%IIIpƱ±1àÖ-..‰Ä¢¢"ðÄ õòòÊËË[YY©©©…Ù‰'œNg`` ø VUUa0“Étüøq€úô¬¬,°µNLL8 ¤ŒÒÓÓ ÅÉ“'777ýýý«««µZmBBBjjêÊÊ  ðív{CCƒÕj -..^[[«¬¬‹Å‚J$6›‘‘A¥RÇíüùób±X.—»-UBUUUff&”›þYŽÿ›ö»j»ÊÊJ(˜000..ÎÏÏ/66–Íf ‚••ƒÁàééùòË/C¡Î_JÃ*•J—Ë533sôèч–——ët:˜…)ŠŒŒ ƒ1:: Ðl4ít:wwwgffêëë?~l·ÛI@  )ì¿3g΀5!@‚»ºº¦¦¦NŸ>½··ι;;;€¯YYYÉÉÉñôôœœœ""B§Ó9sfssÓf³½õÖ[Ÿþ9Ç«««[YY9zô¨R©ŒŽŽÎÈÈX[[+)) 5›Íb±øÒ¥KƒƒƒÑÑÑ)))SSS·nÝjll”H$ÿëý/´F£™šš¢R©ýýý"‘¨ªªÊ ýÙÏ~¥;h4¦™0…_XXðöö¾qãÆ“'Oìv;“ÉŒ×ëõkkk~~~—/_«ðGAº&""‡ÃUUU …B¡PXZZªP(@> ¬‹Åk2™jjjÖÖÖ´Z­ÏÏþóééi*•ÚÔÔ„Åb9ŽÑh„ò뀀€žž›ÍfµZ››k±Xèt:¨¶­V«Éd²Z­wïÞíéé!‰ œv8ÎáÇ!¼nµZŸ>} %™Læp8,‹§§'‡Ãyøð!—Ë…¹@µ¸H$¢R©eee@"‘ˆÅbè …Òëõ™™™W®\ñöö^ZZuž×ÔÔxzzöõõ±ÙìÝÝݾ¾¾••PÅ„††úúúæååáp¸€€ˆ°Àï ‹‡¡Fdgg'''§¿¿|€wŸ¿µµt(p'œ…2,—˵³³ö/h4\'år¹Ëåjoo7 ¯„–––f-@é0™LIII³³³PBÙÙÙùŤ ´‰‰‰……¥Ryøðá¹¹9‰tçÎ›ÍæÖ¯¬¬0L.—«T*//¯õõu§Óypp°°°àéé ˶µµ¥Óé …V«ƒäääµµµääd™Læ>ãêêêöö6‡Ã±X, \.îÄVH„ ZP(Áûd}}ÝÓÓsccÃápÉäÝÝ]j6@ V«Õj5‘H ÐjµF£ˆ•$Éf³ †ååeX̺½õ‰ŒŒ\ZZrwzE£Ñ^zé%ò­®®r¹\˜®˜Ífˆ'À§¸\."‹§§§D"Ù+` àOØØXö!âÆV“ÀZ‚Àbªð&†‡O"‘°X,4ãååE¡Pâââ¾ÎGpx¯ê‹€²8Aág/22’Íf{xxH$"‘èïï¦ -ã@y‡?iWÊáp °1&&ö„3B° ‡ÃÅÅÅÑh4м“H$¡P(ü |n/ år¹p"OOO0’a0!!!B¡†‚Á`ÀPÃUÃìžÁ``0jø‡U“É$‰Ð`‰¡P(‘HÄáp`DGGc0¡PCŠÇãétº{¨…B!LàC¥R!œ¿ý</,, ƒÁDFFÂ0Às_/œŽB¡˜* P(‹ÂÃá•ßèÕBÿî?ÿpûŸüÁçm^1ÌóÚxÞgzø¼þà ù·ÿ'uWBûË]Nb¾úÕ¯‡……•””Øíö¢¢¢3gÎèõú“'OŠD"__ßêêjWVV»±±qñâEXBBx°´´´¸¸x~~žËåž;wîàààøñã`"õÝï~÷ñãǯ¿þzFF†Á`8yò$‹ÅšŸŸÿÁ~0==}äȘS×ÕÕñx<‹URR"—Ëßzë­¨¨(NwöìÙèèèÑÑÑwÞyà §®®Ç×ÕÕ‘Éä>ø`nnî•W^‰ŠŠzôèQCCè±  ÅÙ³g}}}±XìéÓ§fffÜËÉÉ@PP™L~ñÅ›ø­o} *ǃƒƒaÑh4ï¿ÿþÔÔÔÅ‹“’’¨Tjuu5‡+---**R*•çÏŸOOO7 §NpVV–F£©­­=wîœB¡xûí·1Ìâââw¾ó€‘ˆc}ðÁ111€fq:x<Þétž9sF,ƒ?ÈŸû9ù/7ôoû[&“uýúu¼ÌÍÍét:"‘Èb±Z[[ CKK D D"¬º“““¯^½š˜˜ØÖÖF"‘<==«««‰Dâƒètzqq1‹År:—/_&‰ Ì›Í6à¯yíÚµ°°°ÂÂB4íééÉf³Ñh´J¥‚b‡èèè°°0 uûöm¹\¾ºº ¥ÉÉÉÎÎN//¯²²2ooo@ —ËAp’àããÔÚÚZTT$‘H||| ¯\¹••ˆÃá._¾ŒF£³³³oݺ% ݤ#GŽH$±XüøñãÈÈÈÄÄDP/ ßh4ööö뻽½=!!ÅbA`½££¤ #//‹ÅÚíö;wîl ‡Ã¹\®´´4‡Çã‰Dâ?ýÓ?ò aAAAÿøÿXVVöÞ{ï•••¥§§.Ϙÿÿ¼¡ÏŸ?ùòe§Ó U999B¡pppæI0=¼qãÀÓGFF`®C$!¸²´´z¨&(++kjjÊÈÈ€™Yyyycc#ø2"RPP€ ˆD")))ioo‡í.—Ëh4~þùç%%%×®]s8 Õ„ß§Ó)‘H@M£Ñ"""ètz^^^{{{rr2•J5›Íƒd–N§ôUF£qnnÎËË 8œ.—˽C~~>›!Iò):.‹@2f” IDATwppàv”ôöö†¥«Óé¼~ý:À¨q8ÜØØXhh¨Óé´Z­h4º®®îêÕ«ûûûÅÅÅ¥¥¥mmmjµúûßÿ~fffqq±Ëå’H$f³ø‚¨Tªæææ¨¨(™L¶´´ü…­­-…BÇã%‰»(á/¢aÄb1‘Hœ˜˜HNN¾{÷.‡ƒÕP||üÄÄÄÆÆ†ÅbÙØØˆŽŽÀ_TTÔââbOOäì¸\.™L¾qãÆƒT*ÔÏ Ñè_üâJ¥rrr2)) D………¿þõ¯···=zD&“gffVVV êP&“Ó&È?úÍ•+W–——§¦¦P(”\.Ÿ››ëééQ*•D"”¥—/_V©Tb±xppðÖ­[“““‹‹‹›››t:Ýd2ݸqãðáÃÝÝÝŸ|òÉÖÖÖèèhFF‹íëëš\.ÇápÓÓÓ@ ›››ƒ£L&ËÎξ{÷î§Ÿ~ªV«¡ŸOŸ>ó„»wïZ,‹ÕÕÕ•’’"—Ëm6Dã@PuçÎ,;33ãr¹ÊËË®\¹²±±166¨ià­ &“ÙÑÑÑÕÕ¥V«§§§•J%$‹ÚÚÚ Pǽ$ÿkûkû·a.\¸066^\\¬V«KKKÚTRRB$E"QZZFƒ²ñÝÝÝêêj2™l±Xæ$‘HRSSFcqqq\\Üüü|XX•Jˆˆ …r¹\*•Býç±cÇe“œœ 9ÿÒÒÒ­­­#GŽ@%jRRÒüü|yy9@Ο‹‹‹ EXXÈ¡€ƒe±X*++÷ööÄbqZZðE322€&%“ÉÒÒÒ²³³•Jenn.—Ë]^^æóù±±±)))8.888&&F¥RÕÖÖÚív‹UXX¸¶¶f·ÛKJJÔj5Ä@‘ðþýý}°Hq¹\G‡ÒûŠŠ ·¿¿ôèQ0¿€ÅA||¼X, OXXOHHXXXHIIšÞúúz ZK¥R¥R™œœ 8‚ÊÊJooo<_TT455•ššš––C°¼¼ 7…ÏçC` ‰¡œÄn·:t(99‹Å¦¦¦J$`º ‚ÌÌ̈ˆˆƒƒƒ’’’ôôô¸¸8…BQSSC¡P<<>^SSWJ CC$•J‹ŠŠÀ‘ ¶¶¼ ¡èª‰ H•Íf‡††ªT*__ߥ¥¥¬¬¬¼¼<@,—Ë 777aÊH$=<<"""àÛB"‘Þx㨨(fµZÃÂÂ@‡œœ¬×ë+**º»»a¨¡Çét‡gvvªcžvìØðð0Ç›ŸŸŠÁÎÎ8| rpp`4'&&rrrôz}oo¯X,ÞØØ¨©©1™L6› îVGGÇÐÐV«u¹\ûûû«««¡¡¡x<^§Ó† ä6›í_ÿõ_•Jewww}}ýÆÆ†Óé„q²ŸÏ˜Ìòò²Á`\YYa2™Ä¾¾¾P®c±X”JåǬR©@ö6›=22D"‘ÚÛÛÛÛÛ¡šE.—»aËËËJ¥òÑ£G‹‹‹&“ixxø§?ýéÖÖ–Ífƒg=//ÏËËK¯×³Ù쥥%¨?3™LP3:: ÔZ2™üÒK/W 9,‹Ëå.,,ÀôÜh4ÚívHöííí,ô`¾U[[ uç&“ ;ðY™/}éKú-((Ðjµî¡~å•W@Ú`±XÅðõõüDHHˆÝnÏÉÉyðà‚ (Êd2-,,ÀPmm­^¯ªŠÙl^]]ÕëõCCCöÙÞÞ†Çq=‚î9__ß••w÷.^¼h0üýýò“Ÿü~¼ÏÐ’à+õ‡“2, Û^€ú½SÈs'q „Ÿ‡²xž%"t²1_<‘»ÐÜ;<ïÈî<ÓÐh4äÜòÇãnàìòG®È½ÝÝWéå¦f<3ÔîíÏ\évày홎Až©Üwwï™n|qÀÝv8_¼Þ?2PÿÇIÙl6‚ L&[­V???OOO«Õ oÈ:F:áA Ñ›Ívpp@¥Rív;€ Cg0Èd2“É4L&À“~~~‹F ƒð €âp8»ÝÊ!»Ý¿Ì s8$‰F£™L&È<îÛd2ÉÝh4úúú‚# $‡¿¿?·J___PlÂ*tc Æ×××h4º\.///‹Åâëë‹Çãm6[@@€Ífóôô„ ;/,ƒÁ@¥R¯èëëK¡PL&ÎäA—ËE£ÑètºÕjý"’ŠH$2ŒƒƒwÉ!4z#ò ¿ÊÝ@ÖöGn*Dó¿x@—ËsžgŽóïžî™¿¸Oç>ìó:öņ­¯¯¿wï@8uêÔßüÍßH$’ªªªÛ·o‹Åb‰tóæÍW^yåÒ¥K_ûÚ×l6Û¿üË¿dffJ$’‘‘‹uÿþýƒƒƒË—/¿þúë§OŸÆáp?ùÉOþþïÿþܹs_þò—÷÷÷?~œ˜˜Èáp:;;!Bít:¡ØáìÙ³~~~W¯^•H$~~~0u»wï^AAÅbyòäIii)‘H\ZZb2™€õöö¾ÿ~ll,‡Ã™DP?ŒŒ@ï~õ«ÄÄD(Þ—Ëå&“éÔ©Sl6»¹¹9""äoZ­v~~|ïÞ½›:54ýôéÓÙÙÙïÿûo¿ýv]]]KK —ËK•””6›ÝÒÒï¬?þøßøÆÙ³g¿ò•¯˜Íæžž:.•J¿üå/¿ùæ›ËËËW¯^¥Óé.—K§Ó½óÎ;###çÊ•+`*†Åbëêêinnþb¹Îÿ˜†v:2™L¯×›Íæ………ŽŽŽÕÕÕàà`‡Ã133“køEñöö‹Å€€¢R©©©©õõõ à†_,¹\¾¶¶†ÇãÑhtoo¯¿¿OO…B ojjòññ çp8÷îÝóòò’Édãããkkk@ ìëës:f³™Ïç9—D"ñùüÛ·oûûû¯¬¬ÌÎΦ¹¹9$$Äáp s¹\¨ Ÿ¥R©?ýéOE"ŸÏçñxííí0ˆˆ°Z­4­µµ5<<üÃ?4 •¦,¬Ž=º¼¼B$óóó!ä’’„´   ÑÑQ»Ý®R©är9„ìy<žB¡P«ÕP –`(ê7Þ¸té‚ 8ŽÏç‰Ä‹/¾ýöÛ/½ôÒ;ï¼SÐŒ„‡‡ÿ™Ÿ…ÿÖ††Eû훞žþøñã°°°¦¦&"‘/W𜜜‹ÅZ­¤½sss¡¡¡F£ÑÏÏ/%%åÑ£GV«Þ¾ ¨µX,`wwW¥RÁ¹¹¹999 Õ·§N Œááa··Jhhhkk+ßÝÝ ÊÌÌ|òä hx¬V«V«ŒŒT*•pϰX,T¬qssŠŒÃ °ìêÕ« ÃjµFDD(Н}ík`ÊÒØØH&“®_¿f­h4zee…B¡(•ÊÙÙYw…ŒR© ÂãñP)ööö   ”””ññqpé q¹\W®\¹zõ*‚ f³¹©©‰Á`\¿~ýòåËׯ_ÿÅ/~¡P(Ü—<99 Õÿ9-33t˜ðÕÈ8‡Ê>÷öððpˆ¾@B”H$æää DHÉÉÉÀNýÙl6pâââ"##á€^¼D"‰‰‰ñööÎÈȈe2™999ÀŸðññÁápAAA^^^999d29$$$)) Ç'''S(”¬¬, …Âår“’’°XlRR¨4¡ÛL&3;;ÇÇÆÆ‚pnn®ŸŸŸOVV‹MKKËÈÈðòò‚´´Onn.¼+았˜(@{ ,4àV2!Âçó!;#‚ ùÿâ ‹D¢ôôtgwc0pÉÿßßä?G{žêèO8Âò8ÿIÙÓxÀ?yûŸ¬<{^ûOöäOáÿð¼ÿ½'ú¯ì¿Û0ï¾û®¿¿?T.ììì?~ˆ~gÏže±XAAAR©”Ëå‚Uú… ˆD¢@ J¥áááÁÁÁ‰‰‰ …âwÞàìÉ“'AÆYYYÉ`0ÒÓÓ!ÃP[[K"‘âââ¤RéæææÅ‹SSSÁAXååår¹üÕW_}òä‰D"ÉËËóõõ=räˆÍf«¬¬LKK[]]}÷Ýw!ÄròäIFS]]]XX²*‘H„ ȉ'ètzjjjnnîÖÖÖùóçSSSwwwOŸ> L[©TªR©Nž< z¨%‘H§Nêëë{ýõ׳³³···/\¸B§Ó;vppP\\\PP!111F£ñí·ßnkk{á…ŠŠŠärù¥K—Àœì7Þp¹\!!!KKKà—ŒÅbÏ;Çáp‚ƒƒS°¹¹ùõ¯]­VWVV‚{ï™3g@›ÿo|caaáÂ… B¡B¡=zÔápH¥Ò´´4¥RyîÜ9(?{öìÞÞXžètºšššcÇŽéõú'Ng Üß|óÍŒŒ ¹\þî»ï„§OŸB²¨¡¡¡¯¯ï•W^ÉÉÉ늈ˆðòò‚ë-++ËË˃⎀€‰ÔÐЀÇãsss³²² úòË/ommýÝßýÝÇ«««ËËËI$RuuuFFÚétòx¼±±±ééip.»òðáÄ„„û÷ïÆŽŽŽÐÐP°– “É:4 àÙÊf³!(çr¹|}}oݺ–|---`•qëÖ­ôôôááá§OŸ‚¥F|A¨1²ÙlX,¶ºº‚œ‚„††‚ZœJ¥ÎÌ̉ÄââbA<<<ཷ²²²¹¹977ÇãñD"¨q>ýôS//¯Çƒ)Ífc±X ‰Æ`0<oxxÞJt:‚ô÷÷ïïï'‘HX,v``€ËåÎÎÎB˜¾Nadd„J¥BeŽÉd‚+Âb±]]]t:}ÿ7¿ù ŸÏ¿{÷®Ífëêꪯ¯åãÌÌLOOÏàà ÌP«ªª8NRR,J ®]»–žž.‰‡^¯¿víšOQQ&‘H%%%( Èæçç ¬'ººº P~ãÆ 2™Ìf³©TªÉdòññbwðùmjj‚EÒÐÐǃëõóóøŒ¯¯¯¿¿¿Ùl’|3A ÔÐЊNȲܺuËn·÷õõuuu ÇÇÇ©T*Žˆˆ€ˆÅ;wFC$étúÎÎÎÕ«W-K``àÐÐСC‡ f}}]¥R­®®ÆÆÆþèG?ŠŠŠããã€ßÔjµ6›­¨¨¨££ãêÕ«………ÀÍ Z^^ÖétƒÁ××jí­V냪««?ùä,{ìØ12™Éåre2™‡‡Ç“'OâââÜ1»Ý. X,vyyykk‹@ ÀØaikkëÈÈHjjjffæýû÷©T*°n===ÁÞ~±ù|þää¤{™B¥RB½°°€Ãáe2™¿¿?@€¥Á`€êY—Ë ÀÅÅE€Ñ#²¾¾þᇖ”” †®®®ŠŠ 8‘N§{ñÅùË_N ÇÇÇÇs8œ€€€´´´‘‘ØF£¸Ãá@€Ôétâp8§ÓyëÖ-¹\.‰JJJívûƒÊËË!P\\\\\ÜÑÑ!ÆÆÆ¾È#æÀööö|ŸŸ_XXøðáCø/—˶¸¸h±Xt:@Pe2ŸÏw¹\r¹œL&ÿð‡?”H$|>||œÉd655ÍÌÌœ8q‚Ï燆†Aooo›Í®¨6› SRRòäÉ¡PKn­V{pp ¤žžž§Ó¹ººš’’B¥R!êº(4½´´äááúðáÃÜÜ\…B1::7:: žJ¥ÒÏÏorr’L&Ãn‡²Z­Phª×ëgffŠŠŠ&&&ÆÆÆ ZZZ"##±XìÇÜÓÓUrýýý4M§Óý<Í%%%V«•N§÷÷÷ÕïííeeeÞK,. AF“››ûøñcOOO¡PØÑÑa2™ìv;˜ÂÏÎÎÎÏÏS©Ôééi˜û?|ø0** ¤`b±x``@$‰Ä‘‘‘¼¼¼ÕÕÕÉÉI*•:77&ÅÝÝÝM²Z­ƒƒƒOŸ>ÍÌÌljj‚ Èðx¼R©´X,óóóÍÍÍF£qtt”N§ÏÎÎB*öÉ“'÷îÝÕnffæâââàà`AAA{{{`` ›ÍMNNF£ÑÀ×Ëx04¤P(Ož<Ñëõ‰‰‰2™ jojjjœNçÆÆFYY™L&c2™½½½ð-ZXX¨ªªr8Z­6++kaaaffF,÷õõ!B"‘úûûᅼő‘:. ¯]»vûömƒÁ\»ùùyH|mnn–••A&ê¯í¯í¿¿aêêêÀ6(++kii)===<<\¡PÃH$%''‰D³²²’ŸŸÏd2ív{ii©R©4›Íéééjµº¤¤„@ 8ÎŠŠ ­V˜ššº¼¼œœœ ®vUUU€§‰DkkkyyyB¡P¥RUVVîïïs8@ eddDFF* ©TŠÇãA¼½½þi5¹úüü|\\\rròêêj^^¤M¤R)x´ddd(•J«Õš––¶³³S]]mµZwww¡.955U$)•Êòòr“ÉD£ÑJJJ h(\.W~~~hh(‹ÅJLL¤Ñh,+&&f}}½¨¨8õP JOO—Ëå Åh4VUU™L&6› B±üü|€ÎWWWh4š„„ i¹oCee%Èמ©› Ú_¢¥*üãâ⦧§###q8\||üîî®V«­­­½yó¦H$oœ03©««¬”Ífûæ7¿©P(ˆDbAAFÓëõYYYàß'‹óòòººº’’’(ÊôôôÞÞ^}}}wwwDDDzz:ŸÏmhhxøðaCCCgg§X,ŽŽŽÖëõ{{{555»»»ƒÔåÇÓÓ3>>~ppP£Ñ444´µµ]ºtÉf³ñx<ƒ‘=00P]]µ´´+ ÚÚÚ§OŸnmm?~|jjêW¿úÕ;w@„<99Y__¿··µ¬111x<^.—+•ʘ˜˜û÷ïCX+77ŒwÐhtZZ ìv»§§'H·333•J¥R©Ÿo·Û———!¹¸¸Èf³ù|~gg'Ô4?zôhvv688¯¼ò NßÚÚ¢ÓéÇ_[[ߎ   ³Ùœœœ ² µZÍápÂùóç!ýÚk¯íîîÂünee…ÅbK¥RoooNg·ÛN'///CýãÇãââL&Ó£G¨TªÁ`@£Ñ/^¬‹u¹\"‘ÈÃÃC£ÑX­Vpèóôô”Éd ¬¬,%%Ån·?}ú411±©©éµ×^óññ™ššÚÛÛ,..f2™### ¬ÝÛÛóððÈÊÊ‚µmDDÄÈÈüÚq¹Ü€‹FFFZ,@ /-- ¡P(“É€eªP(€::ع¹¹ØØØ{÷î]¼xqbbÂÇǃÁ|éK_JMMEص^^^/^ÌÍÍ}ùå—‹ŠŠŽ9 ‘¿D>Z X­V™Lf³Ùæææêëë÷÷÷ƒƒƒAìãã£Õj1 °¿———)ŠÙlž™™ihh˜››ôïþþþüüüôô´‡‡ˆ¢,Kiiiww·Ùlv:|>L­l6Têõú­­­ÉÉIØŽÃá AAAõõõd2lZNç7¾ñ “É,50}µÙl°h‚öøøx‰‰ F399éççG§ÓU*ÕÍ›7].Wlll^^žOcc#°q¾õ­o èÃäää‘#GvwwÁ¾kccƒÁ`ìîîzzzêõúýý}€“·¶¶¦§§Ã”ÿ!Ò`0LOOÏÌÌ€U|g¬VëÂÂ(õ¢¢¢JJJ FssóÞÞ`gëêêZ[[±Ûí |á…>ýôÓóçÏ_¿~ýÆ@³>Ö_X®ªÚÑh4¨m0 ¨sž ³¢Ñhˆ²@‚ùÑ;5ù¢šøLîÂ}¢?ÜîÖ}±‡î-î¸7BOܲ!wÜüâÇ¿øOØâî€{(þ]…™{p8œöwwÀ}ÔïùaÏŒÀ‰\»;ó?¦ýn° >b·Œë‹r3÷v»Ý$10ÒÁãñP®‰ú= |oÜûƒ¨Ž÷êø`b[€X¬‡ÃGóðð€ûDP™÷ FÌ > §ƒ=á°ny€æAFÛ!!H àQp÷¹L&?s"x€ÜûÃ#ŽF£!Ò[P(•J…§ ûû„þ£P(˜Q€‚»c`˜Z.Ø,wßkÁxA )À‰àƒp@ÅÃ_p8$^±X,œùýwv" \/ü/…B~€; Ý€+…£áp8 …Zp¸^w7~÷H|öÙgGu¹\wîÜyùå—¿þõ¯Ëd²_ýêWGŽáp8ÿüÏÿüñÇ¿ÿþûÕÕÕ$é»ßýnrrrbbâØØXppðúúztt4‚ ¿þõ¯_|ñÅO>ù„D"%''·´´;vÌétÞ¹s§¼¼ÜÛÛÀ=`ë%•J¿ùÍoJ¥ÒÇ_¾|922’B¡lnn²X¬±±±ùùù?üð+_ù øb±Ø€€€¦¦¦Ó§O“ÉäÆÆÆ‚‚"‘î+++‡R(ÝÝ݇ÊËËûì³ÏÙÈd2GgggYY …Œ–···Óélmm=wîœÃáøÍo~“––F¡Pž>}J£Ñ>|_\\|ûöíèèhPS‘ÉäéééÌÌL—ËuûöíââbpjŸs¦R©ÀñAîîn˜.--åää€Ë…Bùö·¿ýÃþ°¾¾¾¾¾‹ÅÞ½{÷½÷Þ“Éd+++111ÀÏñ÷÷¿{÷nyy¹——Wwwwll¬ËåúÎw¾óýïÿÎ;.—«©©éå—_îêêÚÙÙ‰ŒŒ4›Í`œÙÞÞ~áÂ:þÉ'Ÿœ:u ˆ³²²º»»+**=ztùò円†………ððpX«Q©Ô{÷îLxNçää$ŸÏ_]]…9_SSSvv6mdffÞ¾}ìÜoß¾][[ÛÕÕeµZ:FF£±©©éÝwßíééAOLL R[[»¶¶†F£Á’4 44Ôf³…$þö·¿­×ë=<<âââôz=Tâ+•JмêtºžžA`ÑŽ :ÎÛÛпt:4^}}}0³ljjX>¾ví„nëêêÀâÁ`0h%"" ¸óh ÿIDATâý÷ß7 sssÿöoÿS¹\. AJ “¼O>ù¤©©ixxX¥Rê8<<„ö ceeE(’H¤ÍÍM0Œ%‘HKKK Ð1<¯···¯¯ÏÃÃãþýûÀºY__ ÀŽ\.ÿ裴Zmkk«L&ÛÙÙ‰ˆˆàr¹©©©ž¡Õj½ÿ¾J¥jmmýæ7¿¹¿¿¿µµÐ"‰DB§ÓA@…BÆc )ýío ”^•J˜––f·ÛA¦ÛÛÛn±X‚ƒƒ;;;M& …‹Ål6ÛÛÛ»¹¹|+€þÚÚÚªÕj[ZZ‚ƒƒ1Œ··÷ÐÐÕjýîw¿ët:)ŠP(ÜÙÙ™ššŒ …ºyóæÂÂÂÖÖ¨Œäry?䬜N'üüü°˜””488Øß߯R©¢¢¢|}}£¢¢@oò»É ƒÁðòò‹ÅZ­lsÅb1dgÅbñ… º»»¬V«X,NLL „¶¶6 ¢R©†‡‡ù|þÏþs‰T#µZ}óæM«ÕúEóÙÂÂÂÞÞ^(EDû­[·à;B£ÑnÞ¼éãã–2‘‘‘gÏž@äâŋׯ_ÿøã!AîpkÇÆÆx<^^^^kkëG}D¡P¦¦¦š››­Vëµk×€fûãÿ˜J¥º\®õõu€[­V÷ôôDEE%''OLLììì`0˜>ú&ÚV«µ³³3$$äÒ¥KŸ~ú©H$JLLìêêÚÚÚc±X>>>P‰ù“ŸüÄÏÏ`T‚|õ«_½zõª{ ¥V«»ºº$I{{»F£T(z½~yy¹©© LVGGG!‡h2™À&üKX,–R©¼{÷.@‚··÷ÖÖÖððpJJ äÇ ™(‰ ÈçŸn4!! HppðÆÆÆââbss3étz@@@cc#Ž/­ÄÄÄþþþ¸¸8AL&“Z­þì³Ï /ÒØØ—ËZVVÖÒÒ¢T*{{{CCC¡,³½½½³³·r/J¥òÁƒ=š˜˜hkkƒl¬á»ºº&&&l6v¹\ÓÓÓ¡¿¿_«ÕªTªééi±X|÷î]??¿ÈGÎÌÌèt:‘Hôé§ŸZ,–íímF³··§P(vvv’’’Z[[×××ÃÃÃoܸÑÝÝ-“É ‘ÒÕÕÕßßÝØØˆàÖ2|Xâè¾··wgg@m.— h {{{}}}‡jiiÆÚoû[Ðòß½{×áplnn:tèóÏ?H$·oßÞÝÝÝØØX^^ êîîÆ`0t:ý³Ï>S«ÕX, ’ ©ìp8Boo/›Í¾~ý:Ÿ˜˜hoo‡¥x®Òh4ooïµµµ™™™˜˜˜[·nÁoÒÊÊJttô7àKçÎ4mµZ§§§Áÿg```lll|||ee‡Ãõôô€h`jj*!!¡©© R{¾¾¾333SSSïØßß—Ëåûûûpv 300Ti•Je2™"##oݺµ³³³··wïÞ=xŸÀE¡Pð¦êèèYXXˆ‹‹kll\ZZòöö?ÎååeF?~mmmŸ}ö™V«7Ý¿¶¿¶ÿþ†yóÍ7™L¦¼~üøñ˜˜p"ññña±Xµµµ½ù$:::&&ÆétB`†J¥VVV~þùç±±±7oÞ‚ ƒƒƒ!!!åååžÙßßg2™§N :|ø0L&222233q8ÜÐÐLf¯]»]]]m·Ûu:ݵk×ÀG¤®®N TUUÁ°òx<Ÿôôt˜Kòù|̓¼ Ð4F£yðàAll,8BMvXX˜N§›œœ‰D)))999D"ÑÏÏÇãUVV^½z8N§Ó`0‘ B²|>xxØËË‹N§3 NÇf³‡††BCC nܸ‘——£°°°ùùy>Ÿ/‰,KhhhEE…ÃáðññIHH@£ÑŸÐh4UUUàA¡PÞÿý¨¨(A`Â$‰þáþ!33ó½÷ÞKIIˆ}üå"üžiè‹/~ôÑGmmmà;¿··ú=/  …ÚÜÜ4›Í‡Úß߇p΃@5…B¡Àeäx÷ïß?uêTCCƒÝn‹Å€©Ðh4çÏŸÿå/i±XÚÚÚêëëKJJ>|XSSƒÅb£¢¢\.׃^zé%(A¦ÑhÝÝÝùùù¯¼òŠÉdŠ…í‚|ï{ßKOOßÛÛ«ªªºyó&‚ .—k||t°p.ooï3gÎX,–ÌÌL½^pp¡ õàÁƒ‡J¥RX¼öÚkàãêŠBƒÙÛÛƒÀl¿zõªV«»%A dˆN§ëtºééé’’’ÉÉI@Ìï{ß_'0Û1 f³æÑûûûCCC‰Äd2©T*£Ñh4¡‚™D"1™Ì_|ñ½ü_hÃ@‚ǧ¥¥}þùçL&s{{ûîÝ»³³³333ùùùP0Ãáp†††èØÛÛ+•J{{{³³³FãäääÍ›7m6[GGGUUUÿ‡~h³Ù=zTUU¥Ñh FC¶¿¹¹~„ÆÇÇá7ozzº¸¸øÞ½{6¹}ûv~~þÚÚÚ÷¾÷½ííí™™™ŒŒ <?44´g v@ŬP(lkkãr¹°ŒÊÊÊûðíV+d»õzýÍ›7=:::J"‘RRRZZZ …BùÑ~Ôß߯×ëX,ÖãÇÃÃÃ===ÇÇÇ> ÖŠEEEíííaaa7oÞLOOßÜÜœššŠŠŠš˜˜P©T dÃôôtuuõãÇWVV²³³›››u:]WW8xA2¾¿¿ÿ³Ï>ƒ/×;°r}üøñ_9XmmÏmÿB‚ž¾0íIEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out-big-part.png000066400000000000000000002265131445075545500264030ustar00rootroot00000000000000‰PNG  IHDRSÇ%ÔPêgAMA± üa=tEXtSoftwareXV version 3.10a-jumboFix+Enh of 20081216 (interim!)°à| IDATxœìÝyx ×ûðsfî¬DVI$BˆÄKÐPK©¥Ö¶¶¶J©VQÛê—j‹¢ö¢J-µÔNí‚Ø#„IDÙd¹7ËÝgæ÷Ça:½[î’¼Ÿ§O™;sæÌ™wι³Üy1L@QÇqÇéùHl#rrFäŒ4EV­ªàꙎ6wggg¥RiúüÁÁÁŸþùýû÷U*c­`oo?uêÔââ✜s« 4lØP¡P¨Õjí0åÐ$ðóÙnm»¹µíæÞ®»üE²²à%Ò7FV"ÓgÅׯ_È!üñGvv¶‰Keee999uìØñìÙ³,Ëš­C‡ÎÎÎz¿M¨Dc??¿àààÌÌLátÚÖÞ£Mº†] w/[·ºˆœôaÊ­õ;N> •"çÎ%F^R9•6ÌŒ‘ÏÙÙùã?nذa¯^½þúë/…BaÊ(%•J“’’Úµk÷äÉŠ¢jÖ¬ioooccƒbF&“åçç3 Ó¾}û¤¤$‰Dbù¦(nnnÁÁÁºg/´½£G×5\Ü1E#Šúwþö=8–QIòòßÕ;òa‘Xìâ)®å*v­£Ì|.OyújÔ4ú‘§¦í„+UK^*Ò’È̘9…†×¨ã£ÌN/Šâ4ÿ9O5cä«Y³fAAZ­V*•vvvîîîc™LöòåKC‹`Œ½¼¼ìììüýýgÍšeoo1Öš‡ã8¹\^£FÂÂBooï””8퀪ÃÅÅ¥}ûöOŸ>mРnŽ0FÅa #D½þ”¥(„8¤;ókµ;ôö›¾SB8ý·ùòÔþÒ¨‘þ³Z‘(pÁ„1ÿiÁ¥¿SVÏàX޲sZú·È¾fqÜ­:C¿a”%Of dJ ùeMù0ÆéééÑÑÑAAAQQQÅÅųfͲ±±yôèѶmÛX–Õ;\¹¸¸Œ92((H,“ó<½BmÚ´©]»öÆáVTb±¸M›6ÉÉÉÉÉɆfÓ°l—€:žs… õ–[‰ c¤Øük'$·þAnqà‰Öiä#!Ú¾&¦Dñ“zÉÓ^r,Dz¡ºC¿¦hqÜ×ÝY¥ ‹k4^q¼Î‡_ìø½>g¥ J`Œ}}}GŒŒ1Öh4!µZÍq\­Zµ\\\Œ,îçç(‹ÌÃ0 )P$ùûûׯ__Ïw  clccž——§çÁ¡^µº×làZóa–Tftf„bV©dU ³>ªÖ­v§¾d8ÕrA©%Ù£æ Çh¸×›kÏ9'ÿ`%˲JyÎÑíîïŽ,¥Œ|4M·k×®GC† qppà—ä8îöíÛR©ôñãÇF.NÚÙÙörrrNŸ>}ðàÁK—.) {{{ãUP8ŽkÙ²%ÆøáÇFžO$ìÅ´³=…PlFþåä,Ä•Ë Líw>pë5c !$®å†â4û!võcêÕ%L,¶Õ¬­Éý÷Iuî ÊÁ‰²±å§”rµ“a˜¤¤$¹\žœœÌ?Ò‚1¶µµ}ùòeIII©-‚1V©T¹¹¹â×lllD"¹G¸wïÞ˜˜F#‰²³³‡ biƒ(34M7jÔÈÁÁáÊ•+ÆÏöGÛš¶6%jŠåF· LxYx%9³Ô¥Ì•²b B˜c„Ø­.bÙàÍWh;,+³RžÎ¤–¼Ä"1Òz$†ÒîØ±£Q£Fï¾û®Oqqñ®]»U*U©W~ Ÿ¡C‡;vL&“ùùùEDDç<ÝÝÝ;uêtòäI™LV»ví¾}ûêýÙ€ ãææÖ±cÇèèè‚‚Ó—ÂÕÑ-¼\öƦ$cŒËýúÇrÌ¿c*;£(ÊÖ–•• Ž¥§UX\!̪þ=O+}äã8N"‘ܹsçÑ£G=zôÈËËS(ô=c`qŠ¢ºwïÞ¢E ¥RIå8c,‰ú÷ïV\\ìæææââBæ7u³”);;»æÍ›ÇÅÅ¥¥¥™µ Ãq>ÎŽ±Y’ó T…œÀøMXˆíRV~K.ÚÖoÄ©•¬BƱŒ"=É®A(ºz‚œçÙ+3ž Ì^ʳ<–eÉûV(Š2þ¸¦Paa!¹*‰êÔ©ãçççè蘑‘}ïÞ½ììlŒ±··w£F\]]ɳ0ä¢(€ fgg‘˜˜höI‡òeÊCSLT,"üUƒôþÕÚïôw é@Õ°shØÜsð„ÌýëÉY`ÆÎ¥}G× §jØ96ní1h|Æ®¥÷ï ¢÷Õ¼¼¼zöìéììÜ·oß;wš2D¥¤¤ÄÄÄ´mÛVxÏÍÍÍÞÞ^.—+•JròG®p2 óàÁƒääd8í€ FÓtHHH~~~||¼Þ;Y†oE‘gþÑËb9…1‡„wÔʸ3¯ýÎâÚî’¨SÇH®ŸÊØùKƒyÛ±Ø!.÷ì¾ìƒëÇ"„$·Îdüùkƒ¹Û±¸§Qeî]]uRxŸÏÔsRŒqß¾},‰Š‹‹×¬YóøñcSîó9::¶k×.""¢víÚäÙNŠ¢H rDz,Ã0*•J*•^¾|ùÖ­[¦ßPP&(ŠjÑ¢…½½ýÍ›7FÏ»WH§ýÞ{ï]¹rExÚcãâÑdâ®ëœìq¬ª ÷ñÚYFViDzˆÓ7Öê|D^iF~Õ@þÆ4EÛ;±J9«V!á„)J,¦íY1«Vk•oÆÛËŠ‹‹Éï”J¥é÷ùŠ‹‹/\¸påÊwww'''±XLQBˆeYµZ]\\œ———››«R©àl*^½zõ¼½½5M÷îÝ õÃdºÖ§ŒB–{ç"eSCï;™YµJSZ¢ŽÑ˜þ§uºÅ±œ†Õê{‡cY•RøT‹÷!{ôètíÚµ›7oÏ·§eN–aÀ€JT£F š¦K}´ž$Ðî±16<”pU3EŸyOà •ä*e9UP*lggWÙuð61;güè%‡j::”GU Y3ñ}–Õ“/ °€9Ù ™\™R FˆC¿Î·ËŸÂ?9Á?Ðÿ^/+\PkÊ¿«bŠ o,³G>ŽeY#o* F>†cu²ÎoKÎùŒ§Pws¬Á!”W¬?¼P`ÝZ2…:£@fn‹™?òq,ÇêÞÀ#â&õœ~ÚEÃ0‹þº~/9—ãôÞÀC¡;6ñnh±RóÍÆ³¹…J}·ýàO l˜}Ý’eYŽe8–áX–û÷ßäOÆ×Í)eÅkV~Ù+´†¿žA8ñL}‡!¿üq¾ƒq £3Ïæ/ÍPmYvµSÿGÎö6-ë»(5,íåU#6zõg2 ŠÈÌ,Ç ¯‘6òõ(Ù·Ç®[·¬¼Â_×KÒá Nò'\ô\À´³¡ÚÆõErÑú¿Çüù§]»v^5j Œƈ\ôÄcŒ0–©ââl;t ãâ¾>ÜÁ†>~÷9DZú~”%³G>–eûêßüè'¢¨9ƒ[¹¼|‘=áKN&C!ŽSßëÛ{,DzˆüŸc§ökæËȲ¾¯).fX–aY†ã¼þúËqäH†ã^MyýŸãðá^0Eþ,ŽŒÌüjÂÇá ¶«8NXþ«µe‡6w†íÞ+Q“›vBÇqãß iíiŸ=ú3&7÷ÕT„8„” òèh¶¤D8‘CH•%‰Qgdü;劎{aãFÒz˜š‡KJ&^Dÿ/rPV,y±áWƒÑ§ï6 ÷wÏ›9¥(\·î«©‡R¦§#„°‡bYá]A–a”ÏŸ£Úµù9Ç)²§Níÿë¯bÞu!žã¸Š¹Í·qãÆ€€€Þ½{3†.Ìx»XpŸyu¾‡ƒ­¸{³úb{Û:7–Áiƈ¢ÞkáÿwÔÓ"™ÊÄ_ñýðýzõÂøÕ8™ŸŸŸžž¾}ûöëׯÿÅ=Ê/^aFŒ1iÒ¤;w®_¿žeÙR·âçŸîÙ³'™ã¸¼¼¼„„„õë×?yòÄ”ÍÀ³èW ¯o½Ë”Gn=íß¶aöôiŠ[·Çá×Or"Á?þ3®gøï”¡¡žK–œ¸›\$Sr,‡à؆իW¯I“&‘‘‘‰!äììüþûï4è§Ÿ~Z½z5[ÚmB¬U=sôïßΜ9‡Zºti©+ÒR»ví   ·ÂÛÛ;((èÒ¥K………c#F <ø‹/¾8uê ~`:ËÏg_C4¾oë^Σ:Ë–eΜ)»rÅâ3?û<–,a•ÊÞa üëÔúõàM…JCî$–:øaŒûí·'N iӦǟ2eÊÆ …eõ1E­Zµ‚‚‚êÖ­kÙâZ#n©[1Þ¼yó?ÿüCf0`ÀÖ­['OžüÏ?ÿÀ¥Z0ïpyõj•Žë6.ÉIýphR÷î%11î ˆ›7g1f2÷?qPÛ¢E%ÑÑÏ zÞ³§¿,¯c“:ˆc8–1ñw,Ë2¯ÅÆÆÞ»wÏÅÅ¥iÓ¦ã9sæ¬\¹’¢þÝÒï¾ûnõêÕÂ)õë×ÿõ×_>¼mÛ¶wß}W8&999MŸ>ý¯¿þúûï¿/^@>ýî»ï DQTXXØÚµk;vìH¦šßÊ­ÐáСCùùù¾¾¾&€°üW ­y?¡ÎÍU:$•«<–-‡†23™þŸ(0ÐmÕªB WpèJ"Q=Ú¶Q=Är–ýªã8{{{Žãrss9ŽëׯßðáÃ…ã\Ÿ>}„S0ÆÿýwŸ>}êÖ­ûÁìÝ»wÀ€d°qww?vìØ÷ßäåå5f̘3gÎtèÐcܤI“ `ŒëÔ©ÓªU+wwwãó[¹º34kÖÌÙÙ955ÕÜ’ š3äã^ó‰EX#—‘“6MQ‘J£9|+ÑuÉRq“&¦Ÿù‰ÜW­>“¢T©5r9_š˜þwEfUÏÁÁáÛo¿mÓ¦ÍÙ³gÓÉÃ¥:wò´¦`Œ/]ºÔ¬Y³ððð±cÇÒ4=mÚ42.Î;·eË–›6mjÓ¦MxxøäÉ“]\\–,YBQÔgŸ}¶lÙ2–e?Þ¹sç#GŽpgd~+·‚èÙ³çÔ©S§M›¶páÂ={ödeeÍŸ?ßÜ[ŒPÍY~ŸeY–<èÉq B,ùÏ2š>KÍ™6UÏqœñ3±¿¿ûŠ•'¤ŠzÚ¾©/Ã0,Ç!Žc)Š%g–&ß5\¿~ýªU«0Æ5kÖ‰DçÎ?~¼‰w¿X–5k–Z­F>|xܸqáááíÚµ»~ýzŸ>}²³³çÏŸO>ݽ{÷G}Ñ©S§ÈÈH2äpÇ0 ©ªñùKÝœR·âóÏ?çÿMQÔ½{÷,¾ËÕ–ù÷ù^ŸŠ±,Ãh4üÙò,£9*ú™ëâ%t` kô²']¿¾ûòÿ|ˆjÞ¼¹î̦M›š5¿[1bÄ777WW×€€€/¾øÂÅÅeãÆÝºu«ø_eÀ›Ëò_5° ˼>áb†cY–å^{Œ×mÉÒìiSUÉÉèõ™Ÿð|ÇÆÏÏmé¯ç§¸ú”œ9±Ì«q”Cˆ¥(–áÌ:ç;pàÿTdÆ Ïž=;iÒ¤µk×Zp%0//!äéééèèˆ*))~ZTT„²µµÕ]ÐÜù-Ø †a4 ù=ß¾}û Åï¿ÿ>zôè‹/Âã`"‹žpáXŽcY–e_Ÿó1³ÿNg\»ð(Í}ñRQýúìë“<þìöñq_²äÂÓ]‰g _GYrÎ÷º4Ÿíä^UˆeYöéÓ§±±±nnncF#‰Äb±‰èææ†ÊÎÎNIIaY¶N:ÂO½¼¼0ÆÙÙÙº£²¹ó›µzg¾}û6B.x€Y,ù^]„LÍÌ…„‡YhoïÔì‚×9f–ÑüùðÒ“t·…¿Ð~~ÂGZhoo__NÈÜù˜Ñ¨9–!K¥dåÚ4mújžºuÓ²ó,ÎLËq9ñªY³&B(;;›¦é–-[’ñÃÅÅÅÍÍMë —N:ñS:uêÄ0LLLLfff\\\Ó¦Mùk•]»v•Ëå/^$·÷BüÕȬ¬,ãó[³z‘×¾ddd˜U2Ts–d)"§a—î%µÚaÌ©ÕÎî?u÷Õ‹ÍB9Ù×Pª4…ˆòX´(sæLuZBHìåå±xq!%–©›—RÙ«¹9tînâ7 {{ªF §¾}¯ì½Ì2ŒÅ/&!wÚ\]]BçÏŸïÖ­Û‚ vìØakk;bÄ'''áÌ*•jãÆ›7oÎÏÏïׯ_ppð™3gâââ8Ž[»ví† ¶oß¾aÆâââáÇûúúnÞ¼™÷*3íó¬‚_ojg#¾pàjBz.ûj¤â(ŒÿoxñÃÅîK܇z.\˜9kbÙ:‹!ŠRý±=¼ip«æï8ÇnñϳÖa;4i>¿ëÂó¬ò*k˶êÑ£Gýû÷ïß¿ÿ?ÿü³aÆ   #F¬ZµJ¥RíÙ³'//¯sçÎüÌ111QQQÓ§Owpp@ݾ}{ÆŒ!´oß¾š5kΘ1cñâÅ!™LöÛo¿Íš5‹Œ47oÞŠ¢(ŠâW œHn˜‘?]]]›6mš’’’’’B~ÏGÆ6š¦BÇyzzgggÇÇÇ“ø¢lllZµjU£F‡1š¦CBBìììnݺůËÈüFjh|+È¿…%9Ysž€,z¶“æd×Ûéz¹:*³³–E'ö ±Ltz>òí‚Õä$,1ÑÛÕ96)ƒ3§þÒJëÕùÁÃÈD–e_¾|©÷܈$2333++ ½Q„Ë*Šëׯë~Dðàð#ãó©¡ñ­Ð; X~ŸÏø<,~ÝOsò碟±Ûº±/ûz,c†¥Ìû¹º•J]‘‘ÌýÎàʲä÷|,ËñOBr‡1&ý¿Y†Áÿ>”ɲ,ËhXđߪ“1aY1§gä#e"?”‹®vþ÷¶ÿoþr…9× ¯"C4ÍrœR­b–å'³ Bˆ£i¹\ű‚;[‚Äíÿ–c€2ey®#ÿÅj‘øÜ£ä\i ÷Ÿ“;üßðÓá¼@™1ûW ÍßY¬,}(Â×°¡ë¹×NÉÌÓ¼Nï€1¢(ʯŽKV~¡\¡6ñ6޳˻ᆀ²bÉ}>S†!ŽCr“˜–Íýw"˲ÏÒs`PY,»ÚiêÈ¥w>öT"˲ Ÿ:Ñ{½”Ó™®;Ekº¡€²dÙÕÎ =mƒsDeÈìÓ,ŒqEEðx ð6Â­Ž¦Tv€Š#´Ù?fÞ\F>€7J`` Æf§;À8ˆ+P¶¨Ê®x«@÷ÊÄ([0ò¨^`äP½ÀÈ z‘@õ#€êF>Õ Œ|ªùT/0ò¨^`äP½ÀÈ z‘@õ#€êETÙ¨B‚ƒƒ¿ùæ›Ó§OK¥Ò?þc¬R©’’’¶oß.•J#""† †1V*•IIIüñGAAAeWT¦V­Z}ñÅõï×ÇíÛ·«Õê±cÇRŲlFFÆ©S§îÞ½Ëq\½zõæÌ™óðáà 6Ì›7¯N:¢RRR~ùå–e?ýôÓîÝ»ÛØØÜ¿Æ üZX–ÍÍÍ=}útTTÇq¾¹ Üyyy?¾Q£F%%%'Nœ8|ø0ÙÑ_|ñEÇŽ1ÆwïÞÝ´i“R©4Â0kÑ¢ŸR©ôîÝ»ýõÇqóçÏ×~uêÔÑ»vð–ëÑ£GAAÁܹs¿øâ ‰DSPPéàà0vìX2ñþýû‰äêÕ«¶¶¶•]å*§aÆÕ'¡ÌÀ ’““o¿öþûï4ˆL¼sçNFFFffæ7ß|CQTHHHAAÁþýûišÞ¿ÿíÛ· ãâânß¾½sçNš¦W¬X!‘H=ztûöm‰DrñâE[[[~-wîÜyñâE^^Þøñã…ÃmuPâÊÝÝýöíÛ/_¾<{öìÇ%É´iÓ(ŠÚ¼y³D"¹yóæÍ›7%ɾ}ûhš6Â0Ægbb¢T*ݲe EQzÃÏÓÓSïÚ+»U@ùëÑ£‡D"™7oÞ¸qã¤Ré¸qãÄbñ¯¿þ*‘Hz÷î-œ¸víZ©TÚ¹sç·þh4Wuè¡x”H$k×®‹Å4MÓ41&7lØ ‹5j›••*‘H8@¿öã?J¥Ò¯¾úŠ,Þ®]»ÜÜÜsçÎÕ¬Y“¦éeË–I$’3f <˜_K³fÍrrr®]»FÓteo}…ªqõñÇK$’Õ«W‹Åbww÷ÄÄÄ«W¯víÚ5??ÿÈ‘#6664M=zT*•6iÒD{¨ áÃL8ƒƒÃÅ‹¥RiPPH$Ò ?½k‹Ã †tƒX–e¦°°cÌq9ñgYV$¹¸¸0 “››[Ùu•O$ùúúúúúº»»óW‡8Žc&!!áøñãvvv]ºtvÜ Ã0 ÃGù3<<\,Ÿ:uª¸¸˜a˜-[¶ „Ú´i#,0??Ÿ_¼eRRRX–íܹsÏž=sssƒ‚‚"""Z´hAÓôÅ‹5 Ã0K–,™:ujII YÄ”¨ ó”””¼xñcìîî®7üô®a˜ŠÛþŠ#ŸA'N¼råÊ7ß|ó÷ߟ={–Ê¢E‹RSSûöí{ìØ±§OŸB†~÷îÝ{÷îmÙ²Eë;2ÇqäëQÍš5K-ÇÍÍ !$•JÉŸ/^¼à8ÎÅÅ… ™={ö¼xñâåË—e2¹#Xö[*Õ7-ZäîîþçŸÞ½{wêÔ©Ç9;;#„Š‹‹É<×®]Û¾}{jj*ùÓ”¨ úßÿþ·fÍš÷Þ{ïùóç䮳‰k/·m­|ð„‹A¹¹¹¾¾¾Íš5ã; ßÿýöíÛ]»v>|xTTÔ–-[ ªæÎž={äÈŽã²²²tƒÁÆÆ!dJ¨Õj„Hôê´µµÅk4ògIIIVV–½½}```Ë–-Ož<ùvwLÕÇqË–-Ûµk׈#† 2gÎ???ò͉¿ßÆ_|"t£B·ØæÍ›7jÔH&“]¹reÑ¢E …ÂôµOš4émíßàœÏ Ý»w>|ùòå½{÷&#ßÓ§O<ø¿ÿýeÙ°°°Ê®#¨|þùç®]»Î;§;…††bŒ“’’J¨ž={† "†‡‡#„RRRÈ‚QQQ#GŽ$a}ôÑGoýM¯jhìØ±û÷ï \±bE—.]222zõê•’’‚jР™çÇŒ‰‰iÛ¶- S¢bÿþý5 :tè;w š޵¿Åaç|·"Þ0 IDAT‘ëã™™™ãÚµkËår„P‹-ÆFÓtbbbe×T¾úõë7Žt(/^$ýüü¾üòËfÍšõîÝûÞ½{§Njܸ±ñrŽ=:mÚ´>ú(+++''gÒ¤Ijµšø@8[vvv```XXØ7à‚çÛä?þhРÁÈ‘#·mÛ†JHH˜={vNNÎ×_½páŸ~ú‰¢¨´´´yóæj-ËGG°LÖý[µ€1‰DEQEþ¡;‘¿tÑ«:<}Î#±!„1N¤iš2]øŒ0Ìøyhš lÞ¼¹n’yhš&+ªÀ ­|Õ$®(Š¢iºqãÆ>>>äG2èuTøøø'ê a˜iÍ£».­Oõ®PºjÒC•+ÒUv-ª–jW•»¥Õ¤áj'U \ìæ*7ªIøÁ%;Õ Œ|ªùT/0ò¨^`äP½ÀÈ z‘@õ#€êF>Õ Œ|ªùT/0ò¨^`ä°T5Iq*Ä€åp«£)•]ðö¸7°Çh*»`ŒÓœ@5O¸¨^`äP½À¥NPÆ›¶Cð$(SÅn:·…¸eF>PÆ.Ø7AÙº7 â ”! ÁÊÇh ¢@™ƒ¸€êŽ6þqíÚµÅb1Ã0ÇUL…€rUÊãRÎÎÎ*• !TTTT!õÊW)ïpyüø±½½½HÏxK”2òÑt)—C€7 ¼·@õ#€êF>Õ Œ|ªùT/0ò¨^`äP½ÀÈ z‘@õ#€êF>Õ Œ|ªùT/0ò¨^`äP½ÀÈ z‘@õ#€êF>Õ Œ|ªùT/0ò¨^`äP½ˆBhÒ:DQhõ׈eµ>nÒ¤‰\.×h4•P5 lMZ‡(J„B…(ý'yyyF&“UhÍ€ò@Q¯G>à *¦2@Åx=òù¢Iëâ*µ2@yòk„Ò’D!ôâ)¢(Da„peW (7iI(ý)F!LÁ Z€‹›ðV»|ù2MÓNNNr¹|Ú´iÔëŸ7ddd,_¾œ¢(­fÍšURR"‰Èô3gÎdddìÝ»—¦i²àÍ›7ãããçÌ™‚±öUT­Ò´þìÚµ«B¡èß¿¿î‚õëן7oÞºuërrrV®\I ~†qöìÙýû÷óJJJZ¼xqïÞ½ V¬Xqýúuš¦Ÿxðàƒ´³ÔÍ΃:uê‰+­é¥nîüb±8222..ÎÝÝÝÐö~ôÑG†¶‹5j”R©lÑ¢™¡I“&­Zµ6l˜B¡hÓ¦ ™Hb¯OŸ>5kÖ4´zc[¸±¦„“°@­e‰´´´ØØØC‡„PHHˆ]\\œÞ‘ïܹs!!!ááágΜ¹yóæóçÏgΜ™žž~ãÆ Žãzôè1hРo¿ý¶oß¾}ôQ\\œ•­¡+-- !Ô ASf¶ >Ïž=ã8î?þøä“OF5räÈéÓ§wëÖMo9¤—oܸ±î)õï¿ÿÎ0ÌâÅ‹œœvìØ¡·1­dÁÖ 2düøñ‹-ŠŒŒ$UÒ»½éé醶‹ ß½š5kFfèׯßÇLŠjݺ5™Ø¼ysôzPÔ«ÔØ.Ãpâ8Žy †=ÊåêêJ¾çZ†ã¸+VœýôÓ† úúúΘ1###ãÊ•+ÂE233Û·o?wî\OOÏaÆ%%%¥¤¤eëÕ«‡1NOO×[ò‘#Glmm4h°oß>†aΟ?ß­[·7nð½ Æ¸V­ZµjÕš4iR§NÊü²Ò­[·RRR&Mšäïï0lØ0¾ô¶‰¹õ9þ|bbâ·ß~ëáá!‹GE®¬ê-çÂ… 999³gÏöññiܸq¿~ýøò³²²ÎŸ??xðàÛ·o?~üØÊ‘¯¤¤Do\™µu 4X±bEddäÞ½{½¼¼|||\\\ônïÅ‹ mñÏ?ÿ<{ölÚ´innn7^¾|yDDÄéÓ§ãããg̘áíííëë;eÊ”èèèÛ·oÚv½±-ÜXswŸ¡†”+Ê××÷ùóçF¾/—ŠeÙ¯¾úª¤¤dóæÍOŸ>7oÞØ±c%ILLÌóçÏ-ZIJìÌ™3{÷îmh—.]ºyófRRR“&M¦M›VXXˆâÉÍÍýâ‹/êׯŸœœüüùsOOÏo¾ù†ºìííB%%%z;¬—/_Þ»w/66–Œ”°±±9wî™ùÔ©SÇŽ[¶lYffæûï¿þüy'''ËÁ¹\>uêTÿ'OžDGG ߉£Û&ÔG.—Oœ8±N:IIIyyy‹-ªW¯ÞéÓ§õ–#‘Hf̘š””tãÆ;wîmß¾}E:tÈú“ŒC‡‘¸jÚ´©ð~˜Y[7dÈ//¯ž={&&&>{öìÙ³gË–-S*•ºÛ+•JlBH¥RMž<9 555&&æÙ³góæÍcfâĉnnn ŽŽŽS¦LaÆP}bccõÆ6¿±©©©Ç7k÷ém(@¹«W¯^HH¹5bÊ}>áM½·v(в³³kÙ²¥ŸŸŸÞ›ˆzWäééÙ¦M±XÌÿZ·Fhšnذa£FD"‘° õ1Òko¥`ŒµÖNÓtƒ BBBD"‘Þ»S¦·€¡yÈJ›5kæää´hÑ¢‚‚ò‘Ö*L¯Ö‚¤qš5k&‹ÉG†Ê!•iݺµ‡‡MÓÂûa3fÌH$žžžºmhn0`ŒõÆ•Y[G–"óëÝ^#Û%l¥Ö­[ Ã’LlÑ¢EóæÍ…QdhõƶpcMÙ@­Øà—ÕÛÚ€òR_6-(³ÔEÈE}ú|þùç©©©gÏžÕûª•õÑ]ÊH9ZÓÝÜÜúöí›’’²{÷nãu3·J¦ÔÓâÂuË1%„¬¯’¡B,+ÍPð:thlllaaavvöñãÇ›4iRÕzº!C†H¥Òk×®ùúúVv] ÜU­.ø­„1¦(ŠŒväñÔòxrÒä¢yž°²ëoŽºuëVv@eJl@ü+A˜ %‹÷ïß/|ïFÕçæææææV¶eŠÅb+¯ê=,ªÔRC­g¨ªwïÞ=z´¡ð0?屛ʕ››[™?lºZµjU©H”G}Œe‡ªò#b·d…1t€WÄqTô_3gÎ4w[¶lÙýû÷õ>ˆÚ½{waa!ÿލÏ>ûL*•ò«ãß_eŠÄÄD²TaaaZZÚñãÇ[µjeîСC‡7nÈår•JÍ¿òÊšŠùøø:t¨¸¸X­Vgee-X°À¬6ܲeKrrrQQQjjªÖC‰K—.ÍÏÏW«Õ………“&M"Å–Iæçç?~üØÜªj=CU%˜››Û±cG½;Koü”Çn*“øáivppð•+Wd2YIIɉ'|||L,gÔ¨QÂ-"6nÜhÖ~iÑ¢Edd¤L&S*•wïÞµþp»råJaaa‘Ž:˜Òbzë3iÒ$Ý-ýôÓOMÜ¥e„™¡CÏâv;xð`LL ?sTTTll,ÿçµk×Î;gÖCde¾g‘ÕýU¹öÃwíܹ3<<¼ýk^^^fm@Ë–-‹ŠŠ†ªwË @~íËoؼyórrrÆŒ3zôèÑ£GðÁ¦7Yff&_Û?üðþýûñññÎÎκsöîÝ»[·nzK~üøqTTThhhHHHllìÕ«WIÄXS±Ã‡'%%uïÞÝÅÅeòäÉ2™lÆŒ¦ÓàÁƒ'Ož|îܹôôtáá÷í·ßJ¥Ò/¿üÒÙÙùwÞ .Ã6Œˆˆ˜7ož\.ÿî»ïL¯ª¡Ö3TUc|äÈ‘K—.霆â§{"ww÷víÚñàÏ?ÿ¬R©>üðCݵ©UTTÔýû÷[µjÕ¤I“ØØØ .XÙ\!!!¤>{öìIOOïØ±#ùÓÄoâzëS§Nö«W¯ÎÌÌÔ #J=Ê,3C‡žÅíöóÏ?+•JÒ_ûúú* †aÈ˃œœœŠŠŠÖ¯_¯{¸UäžEV÷WåÚWÀqôÊúõëi𯝙¸ñ¼ß~û-..Nï»(mmm>|xýúu–eùbýúõ÷ïß'¿2´Æþýûë­qff¦°¶}úôQ«ÕüË …®]»vâÄ Ý&óôôÜôx+=kbK_¼œúáŠ9ŽBˆã8CO^¹r…¼$…ˆÿä“O„OvîÜùÚµkzßúñý÷ß;99­ZµªmÛ¶üDÜÜÜñãÇ»»»_¾|ùÒ¥KÂE\\\ÜÝÝß{ï½Zµj]»vM©T’÷ ñµ-..Æët)ŠÒû&;;»wïÞüÓ•õë×ç_XlMÅÒÒÒºt阘Ȳì‡~ˆ2ý9Iî5áD'''??¿-[¶téÒ¥aÆ÷ïߊŠ"•Uzyyùúú;vÌÄgM µž‘ªòŽ?.‘Hú÷ïÏ¿“Ð?å´›„ÛŽ,ŠB7°É/UÈÛA9ŽKMMµ³³ Ž%ë2^1¾AV­Z%—ËgΜ©7x Õª¤¤$((ˆ±u```ZZš•Í¥Fº³êòxñâcÇŽ# FŒÓªñé§Ÿæççë>^Q&G™¹a†t=d]»]¼x‘\»KJJZ·nÝÏ?ÿLNhŽ?-¬XeíÙR[²²úár=Ž´ÅÅÅ9räðáÇþé§Ÿ´ ¢t?mذ¡F£ùꫯtWìØ±³gÏŠD"­Ú¯[·nöìÙb±ØÖÖöäÉ“YYY€ÃwíÚµ¨¨H¡P|ðÁZ窙™™ Ãh4µZŸŸ©uYãÇLMMMKKS(%%%iiiiii“'OÖªž¿¿ÿ?þ¸qãÆüüüU«V‘O­©ÆØÅÅeÊ”)çÎ+))¹sçN`` V»=zôÖkzƒ[ïÈ·uëV±XLÓôÊ•+É@Œ±•mxîܹ3fLŸ>}ñâÅééé‘‘‘Zó¯ªn멪pA¾G৉ŸòØMe?z»Ô#ÖxÅB5ÊÎÎÞ¾}»îG&F5B($$äÅ‹üñß&Ö4adä+5¤uëCœ?þï¿ÿÖ]õG2?̾‘Ïšvûõ×_óòòÚ·o¯ÑhúöíÛºukFÓ¯_¿”””ß~ûMX‡ÊÚ³¥¶deõÃåz¡ÿF,Ú°aé°hšÖmñgÏžåœ?Þ”6l˜J¥Z¹råŒ36mÚDÒßôìÙ“\Uçg3f Ã0Z/Ëþûï¿÷ìÙsâÄ Ýd³™™™7n´±±áßâ¨÷ü›oܸqúôé5jè}"_Ÿ~ú©¤¤„<.lMÅøµÓ4–žž®{cvܸqÓ_ó÷÷/uässsS©TS¦L!µêСƒF£9r¤õm¸aÃÒ,E½ÿþûjµškbUu[ÏHU… ^¸pÁ¬.©Ìw“õñc(°‡ª{ĶlÙÒôø9}útbb¢Þ'¼MŒj˜˜˜7nŸ5°>ªŒ|ÆãDo}BžžžEEES§NÕ»Ó­<Êùa†ô|Ö´¹Ÿ·uëÖÌÌLrôéÓ§Û¶mcf̘1ÂB*wÏoÉJ采 R~ÇúoÄŠÈ›; ½žæÌ™Â€(((Ι‘‘¡V«uWãëë{÷î]rÄÉÉ cܽ{÷¼¼¼sçÎmÛ¶íĉà8ÎÎÎŽã¸ÂÂBá…ïI“&i4;;;–eu¯Ò²,«Ñh Õ–eY>™'ÇqF«„ÐÐÐ ,X°àÖ­[Çñ©þrrr,®X×®]·nÝ:vìØ‹/²,{çÎ7niÕí·ß~ãÿmÊ]“ÜÜÜœœ>± z’êÁÊ6$· HCÅÇÇcŒ± °¡ªj=òõHoU…j×®Ígè% ÅOyì&ÂÊø1ØgΜAùùù]½z!äåå¥R©ž¨´„šVeÈœ03šv;{ölqqq÷îÝoݺEne]»v­[·n,Ëž>}ZXH¥ìY[²Rúá„„TnÇúoÄ"½OÙò°­žCõA}úé§ Ã„„„Y©5G™éa&ÜF­CÏÊv‹ŠŠbYö›o¾!k$·„=zd¨O¨È=kVUÁýpÅG¯˜¸ †lݺõáÇFzy­kµ;w~ôè‘L&S(qqq¦ô¹„é-Nú&½}ðÁ¤r¹üÉ“'ï½÷žõëØ±ãÅ‹ …D"‘ËåGµà… º‡Ÿ››Û±cÇȵògÏž 0 LÚ¿F_XX3lØ0ÓÀPëª*\V%÷  V«ßy猱¡ø)ÝT&ñÃÓ ìvíÚÅÄÄŠ]»vÍô÷’OŸ>\t!;…ÐÛ‘©Uqq1ùrÍ—0dÈŒ±5ÍEX6òªBh„ Ãøûû›U 2í(37ÌømÔ:ô¬l·5kÖÈåòzõê‘? vîÜi¨¼g­ì¯Êµ®€ãèk†=„PëÖ­‹‹‹u{:ÆX˜ù cLÓtPPPƒ DFóêé*“¼eØ@ª?k*F–õðð svv6÷l iÛx4M’|oeÕ†Bº×è3Ôz†ªÊÛ»wïåË—ÉΛ7ïÞ½{ä߆â§T*•R©tÛ¶m¦wÄež$¬ÌÓ˜Y'e’!Ìд8C².óY© Æ,*kªÂR͕ʚh±2ý¡¡È7ÒS•ªürd"‹‚ÄP?SúŸòhÿWô¦§ŠŽŽ¾ÿ~óæÍÛ¶m›˜˜xöìY+jeZ¯7(S¡¼Y6?U˜—äää3gÎÔ¯_РA¹¹¹ä÷¹¦Ô­Ì“„•y3+ã¤L2„ÚƒgCÖe>+5Á˜AezC骰Ts¥²&ZÌNÛö_†"ßÐtS”SŽLÂÜ 1ÔÏT|ÿ£Wy´ÿ+”¾ôT%%%óçÏ'?§X¿~}ZZšnéežÖ U¥LuºK §É›Å37U˜–aÆ‘W„íÚ¾}û“'Ot£¹’„¡rHcfbœ”_†0C{ÐÊ aVf>ã›ÅP‚1sƒÊĆªÜTs¥ÖÄÊh)µU0ù†¦›Rkz#©+yf‰¡~¦âû½Ê£ý Ÿ$I(55µU«V!‘H’šš*œ§œÒz¡ª‘©Nw)–euË1”7‹gnª0-îîîã§OŸ’e322êÔ©#Ü‹–$ÌÐ~±¦ýK“òÎf(󙕬Ì|Vj‚1Ë‚ÊHCU…Ts¥ÖÄÊh)µU0ù†¦›Ra æöIXÙ¦1ãËÔ'“!ŒîA+3„Y™ùŒ0ž`̬ *µ¡ªBª9Ó[Ʋh1¥UÓ|ãÓË»çÑ›ºRÈô 1ÔÏTXÿSñíolùåË—gggoܸqÓ¦M¹¹¹äD•ÿ—sZ¯ÊÍT§»”‘r e #ÌJ¦Õ,E]¾|ùŋ˗/ÿóÏ?óóóår¹é[WIÂÊ6_¦Þ8)uß•I†0¤³­Ì†­Ë|†JK0†Ì ªRªâ£ÈÐ!S~ÑRj«šÛ#•:½¼{½©+…LŒ±Þ~ÆÐt·ÑôÈ©øö7¸|xx¸R©üüóÏiš¦(jÖ¬YEEEZOiõ®Qn IDAT—_Z/ÝúT|¦:Ý¥ô–c(ϬTaºÍâìì¼pá£GnذaÕªUR©T«=+2I˜î~Aåœþ­2„éîAë3„!+2Ÿ¡ÒŒ!3ƒªÔ†2^ŸŠI5gbË K£™“¶Í”©ÔéÆëc}σõ¥®2+H õ3ÓÿT|ûz–ñ÷÷§iúáÇäjrbb¢···ðº|ù¥õÒUñ™êt—Ò[Ž¡ d<³R…é6‹D"ùþûï1ÆÇíÙ³'##C«­*2I˜^åšþ­\3„º{ðéÓ§ÈÒ aÖg>+5Á2?ÿœñ†2^ŸŠI5gJMJUViÛL鑬¬²¢ç1’ºRX¾YAb¨Ÿ©˜þUFû¿¢5rúûûK$’C‡¹¹¹yxxœ9s&##ƒ>>R©ôüùóÇ:l­<œ+…›››½½½L&+Ã2­?4ô~{pppðññ‘H$ÖÕNÇñãÇiZ{ü[´hQ~~¾H$2·´ììì+VPehŸC‡«Õꬬ¬ ð3Ÿ}ú””)‘H7mÚäææF>2·‘+Œ°MBóçÏÏÈÈÐh4r¹üòåËmÚ´¶‰ñOù¢˜››Û±cG­ö “H$£F’J¥“'O¦(Šß ùùù?†%ÏHèW®\),,,ÒÑ¡CR²F­O7nÜ(,§Ôx8xð`LL öQQQ±±±üŸ×®];wî\ûöíµ6ÐôòuU…x³àØ4qï·k×No[999©Õêÿû¿ÿã{­åšNìÞ½»°°ÑÏ>ûLׯ_×íÁ ±`ßéêСÃ7är¹J¥ŠŽŽnß¾½õ+õÐ0nË–-ÉÉÉEEE©©©ZýöÒ¥KóóóÕjuaa!HÖT•'²³³ÓŠ16·AM\pÍš5¡¡¡ ˆŽŽ5jÔ¢E‹$ɲeËX–íׯÇq,Ëš¸.{{{½\~•/-[¶7nÜ矞““ƒrpp8|øð† X–õõõ3gÎîÝ»IÏeq=íííI™EµnÝzÞ¼y666cÇŽeÆÜF®ZmòÓO?M:uÅŠ{÷îõ÷÷Ÿ?þ¡C‡ºté’œœÌqœñO…E>|ø³Ï>[°`A·n݆áW'‰E"‘ƒƒƒX,F‚½ ‹»té2kÖ¬’’’_~ùEØPFB—Ì0aÂGGG„ÐäÉ“;wîüÑG‘•>zôˆœ œ>}ºgÏžü¾ëÛ·ïÌ™3/\¸ }Ôju¿~ýH­úöí»víÚ5kÖ{L¾žãÆãW‡3fÌW_}EQTzz:_&EQÛ·oOHHÐÛȆ¶ë“O>Ù´iÓœ9sæÍ›W‘mâääôòåË­[·ŠD"Ò& 6ÌÏÏ_½z5EQÆ?Ei5ï AƒT*U—.]„qرcG‰DÒ¤I¥R†1¢¢¢N:¥õ½ÊHèøµÍ›7§¤¤ˆÅbÝþšŸ' ##cÇŽºk1¡=zh4šÑ£GcŒ'L˜ “Éòòò¾ÿþ{Š¢ú÷ï¯Ñh†Þ©S'­ 4±üªoHçØÔб>}úÌ›7¯víÚ!—¹sçöïßclÊÞ7ÔVäœoÆŒzãŠgh:BÈÖÖöáÇׯ_gY–?µZ¿~ýýû÷ùèÕ;œ÷ïßÿÃ?Ôý¨ÔØà]»víĉº'žžžgΜyÿý÷)ŠÂ/]ºôåË—¤òVVÌø¡a ›-[¶¤§§ [2>>~çÎä눰JÖTõ_üà±fÍ¥RyáÂ…+W®dggK¥RR‰™3gŸ8qâæÍ›¹¹¹:uÂ/Y²D*•=zôòåË …âÓO?%ëhVVÖªU«´‚øÖ­[>lذ!™Ÿ¦i¾²²²È '''¥Rúôé›7oj4š½{÷&&&ž8qâåË—QQQdáÈWæ•ç‘ÊÄÄÄœ;wîŸþQ(›7o&óè¾dÉ’ÜÜ\r½cǵZݺukŒñìÙ³‹‹‹½¼¼BOž<Ù¶m¿ÍüŸfàÀãï¾ûN&“9sæÂ… r¹œ¿Ã×sýúõEEE¤X''§ÜÜÜíÛ·ó=_æ>|HJ«‘õn×üùóU*UddäÅ‹†Ñ:°ËµMzõê¥Ñh>úè#>j1Æ.\ ûÝø§ºÍkcc“““³|ùrán þñÇkÕªµråJ²”p/x{{§§§“3CW ùŒ_o?vìXRR’î%2#ñÀoonn.™gÏž=÷ïߌŒ$ãô‚ d2™››[Ó¦Mµ6Дò«l¼¡ÿ›º1Ö¼yóüü|²¢åË—K$2†™²÷uƒÐù´âŠgh:BèçŸNIIùâ‹/†áG¾œ?þ믿þᇄ_» —   uëÖíÚµËÛÛ›¿hlblð®_¿®ûÕ 'ù÷þýû}ú`ŒŸ?þâÅ‹… ’/Aäb´ƒƒƒ\.Ÿ;w®päÛ²e‹ŸŸŸOçÎ###SRR\]]}||òòòÖ®]KÊߺukVV–»»»°žíÛ·W«ÕS¦L¡(j̘1 ÃôèÑcœžž~éÒ¥¹sçΟ?÷îÝùùùŸ}ö™Öènh»jÕª•••µk×.š¦·lÙ¢wä+¿66l˜F£éܹ³0 ÿúë/rˆÿT·yB111ÇŽÓ:9#3÷Bjjêõë×oÞ¼™““sïÞ=Ý1ÉHèj)uä›0a‚B¡{ö¬©©é×_…;ÕÄU‚ÿ+8p ¡¡á™3g¤R©L&ËÏχwT½½½íííCBBöïßÿé§Ÿ:;;æÎ7gΜ€€@`ffF7-•Jé·_cbb ¨¯¯¿oß¾øøxgggÆkÒÂÂB™L&“ɲ³³ ÓÒÒ¤Rijj*ÀÉɉ\³5œ§ŸŸÉÍÍ…©Æh<&&¦¨¨hèСcÇŽ577¿téÒˆ#0 sss‹‰‰Áq¼C‡zzz•••dã_ýunnn^^Þµk× {ÕÕÕ^^^ÆÆÆ'Ož„:{ö¬……Å€ȱJLL|úôé¸qã0 ›0aBffæýû÷aÛF5|øpooïêêê7oÞ(Ù®~ýúYXX\¸pA"‘Àà¿—˜¨£©·oßÂû`Ä“'r~fee]¾|ùÂ… ÇŽ³´´¼páå¼UùÔå¦k×®AAAaaaW¯^e\ Șä ÉÉÉÝ»wwwwïÔ©Ó­[·®\¹bjjêëëÛ«W/¸ú‘±Üö?ü|ƒ0æ|ú›‘‘qöìÙ¼¼¼ÀÀ@âÁžÂÞ玄-E9RwûöíÉÉÉǧtñóçσ‚‚úöíëâârïÞ=ʬ}þüy???### ‹Ù³g:tˆâwnxyy-[¶lÙ²evvvNNNK—.]¶leý ¦¦&)))))I ¤4qL™¡qýúõ¤wÐÆl<~ü¸ÿþýúõ;pàÀŠ+àe¥†1„üßÖÚÚž’SúÉÜÜžÁG÷iiiB¡P œ‹/ŽŠŠš?þ™3gž555}úé§ ÷IJJzóæM@@€££cçÎýýý‰ è&&UUU'Nœ€÷¢MMMû÷ïúôi“ƒâ8Îý+cxmll²³³qïÕ«×áÇ{ôèÁØ===;;;;;»þýûïܹ³±±1::ÚÕÕn‘ºÜfÉzöì¹yóæ‹/>}ú´cÇŽpwÖÖÖnnnÜ({‹Å/_¾´³³‹ŠŠ‚=ekk›••¯Õ8¶e³ÿ±ä[ŽíÞ½»°°pâĉ™™™ä…uJö>=VäB¶aËV¾cÇ///oooooïíÛ·Ëåò+VÀUþÎÎÎ+W®´±±±µµ;wnZZåžSaa¡P(|ýúu~~¾r!T¡Pèáá±eË+++kkkÿÜÜ\xkZmÇ”œÕå$”¼¿víÚôéÓ‡Ú®]»+VÇÇÇã8®•þ_~ˆD¢uëÖõêÕ+777!!8c‹ÅË—/oß¾}nnnUUÕ¶mÛ:vìqãÆ;w …ÂqãÆÝ½{×ÈȈnzýúõÄãSHmm­¿¿sssbbâÛ·ooß¾œœ¼zõjUïQÐócVQQñôéÓôôt˜O/^üä“Oˆ Ky|ÂŽãË—/·°°ÈÎÎÎÎÎnÛ¶íªU«uþüywùòe¶3Á/^˜››SV…p´kÍš5ŽŽŽ™™™)))ð$KÇ1Y½zõñãǃ‚‚ÊÊÊ=zÔ¦M›†††¿þú Þääþ•bjܸqæææ×®]ÃqÜÉÉiÞ¼ylk½ˆ'(÷îÝstt\²dÉ‹/:wî 7©««cK]n³¢Â¸qãLMMg̘‘“““÷Ž[·nuéÒ…ÛÙü799¹¹¹ùÊ•+°Ó¯]»VWW—’’¢Ì¶Œ|,ùƘcßÿ½§§g`` D"ùá‡>ûì³~øÇã)ßûD5Ê~Ù†-c9¼Ô€á7n455ÍÉÉÉÍÍ544\½z5c5¼Iëåå5aÂz÷UVV.Z´ÈÁÁ¬­­W¬X¡¡c­4«“’’nݺ% ]\\V®\ ß\ÔN ‰Çø† ‚~ýúYYYñù|b †a|>ßÍÍÍÝÝ]OOžLñù|'''WWW@@^ÃJ^Ïɸ¶Z³²²rww711!/"`Û–l:Iø çÉóxž|£çyäìR²÷cEy«ž¢¶rrTÉÁ„ÎwëÖÍÉɉ\® }§<Ð.]ºtíÚU[ŽqÌêÊCOiŸÏwvv†sµV\e…£ÿ(?ÑK´²#MЙóš˜Â0l×®]Ïž=SfM)·} ‹ &¼yóæìÙ³êe#cÇŽ]»víøñã¿þúë‚‚‚;wî¨j\[1¡ä:½é¿’Mùúú–——Ãw`;wî$ÞÝTÆM(ÿ*4«y%ëheÛ%ßæ˜z½OTƒG¾úúú°°0˜]l)ªÒpVÒùÖ†ÍsVo Wïø6ÛÎ;5<ƒ›6mZMMM\\œ½½½¶||ñÅéééµµµeeeáááÝ»w×A†i+&dSOŸ>]°`ù:CÕ†(³‰Â:šWP²NklKæãÊ·ääd5zŸ\ÍÇÇgøðá½zõ"î40¦¨Sø‡Ãçómll44o¤hñì›0 ï“ïûé­Ä„lÊÆÆMFZäãÊ7Í{{Q–¢ZL]Ä?¶Q)u´b ƒòøÇÀ6â´púÆ&õĦ«Ä¦›¥¤ž–*Y­!FÕªXXXðùü–––÷²wøÊGCCÃ{Ù;Öð‡CKL÷ù >x]SwÎ`›ÞãdÌ+++ƒ÷2ƒéT3OØR”uØ*”%ã€Mê °è*AØt³ØÊ)¨¤’ÕbTZQÉ" ÈwõèÑãáÇ PSI;Êh¿)¤OŸ>111ÍÍÍÉÉÉš‹Š)”¬S߀€zK•_Á¡PKL—ùɦL¦vÀ•QïSév¥ÖSh,çÖª2uïk²eÂ!Cà,ÍÍÍñññÄCG…h8ôt©™§Œ:&l) a¶§Nòôô:th`` X,Þ´i“ò{}õêì WW×ôôtø]ÀêÕ«kjj¾ùæ“!C†PÞÅ0ìÚµk< „†­œÌgŸ}VWW÷Å_PšÁVÎæa```yyù‚ æÏŸ?þ|???åGŽP(„Aóðð˜>}zjjjFFüÄ___øJ6S“&MjiiÁqœx>|òäIÏž==<<222Ο?¯dYZZ8ÐãÁÁÁ---Œ:^ÅÇǧ¦¦öíÛ·{÷îééé÷îÝÓ0\®®®ÐŸ°°°¢¢¢ÁƒÃß¡TÒŸöíÛ{Ø»w¯P(Tø†2ÁÕ«WsssGŽiff¶råÊÆÆFbå:D—ù9uêÔ•+WFEEQôYÔxpppss3œ¯íí훚šd2|ÅØÈȨ®®Žü±]¦P¢ ¸ÑÊd›t0aË„”””ÔÔÔÞ½{0 ''Gù…Ö=6Øæv­Ì¨ê†ØRÂ:lÊ’±Á!õĦ«DÀ¨›ÅQN ’JVë‰Qi¨’¡ËwuïÞ]"‘Ì›7:¼qãÆºº:zcÙ#Ú¦ýÆí•¡¡aNNÎ’%K`ÓöìÙ?sªI¸ˆú’ulpøC˜õôô¬ªªš>}:}œh¢%¦›üìÊdj\õ>åµ5R(-ç¦{™:Ý @FØ2¡¡¡áÇ„ -,,TÒM†‡¯cV§ IDAT?­¡™Ç­ŽIߊ\‘¢ŒÃVÞ}E­C‡ööö7nÜPòóeee¾¾¾Ä§hàg3ŒŒ:uêtøðáaÆuéÒ%555>>ž²mxx¸H$úüóÏá×ú–x{{ÇÅÅÑߨg,gó`eeUYY¹dÉKKËèèè7433³´´3fŒ±±q\\\ss3ýsìħçêëë1 c|C¾cËÀÍ›7íÙ³~ß×sCmqÇ zô葞ž÷Åí±={öˆÅâõë×3~FÍ«†††nݺáï>]ïìì\XX¨a¸(¨Ì÷ú”ñ‡0²}ûö7n\ºt‰ÜõÜQ*,,6lXçÎsrrärùôéÓ”@é&?‰€ÐM©ð¨¨(¨Nwâĉ!C†dgg×ÔÔÀ[=lii‰ŒŒ¤ïN—)”è‚Ö€l3ƒn #l™PPPзo_€@ puu-(( ×i¥¡ÇæÇÜ®­•|¢o%—ËévØR”€yØ*”%ã†.õÄ¡«D†®›Å]ØÕ°8T²=€J£|׌3Èâsð_òÓSe¤§Ø´ß”Ôî‚L›6M,Ï4ÄRF¬•Š?(ÑB·L+Zb:ËO@S&š\¡zQó}¥„Â.x_2u­:•ž >>>ÙÙÙ¯^½ÊÌÌ|ùò%å!Vk=Ýh汩cÒ·ò÷÷ç°Ã8K@†mTTÔºuëÖ®]»}ûö¢¢¢˜˜ʨæÖUrttüé§Ÿ8P]] ? £säÈ(¹{÷nxæHÙŸÙÊ]ºt‘J¥Ë–-£ô.[9›‡€7êéééëëÿý÷ߥ¥¥äÌÀ0ÌÇǧ®®®©©ÉÏÏâŒP(”ÉdR©T"‘TWWÇÄÄP®£úé§‚‚‚¦¦¦†††ÂÂÂÂÂBBárãÆ;wîòèR8ð¸tíÚµ¬¬ìرcôŸ”ñ âêêZ\\|òäI"&š„ Â1ü wÑýܽ{÷Ê•+ôÝqûƒa˜™™ÙªU«¢¢¢ž3L›6­õ P”ꀖ žžžÍÍÍ_ý5ŸÏçñx6l¨««£Üäh½¡G÷‡cn×pFe; Ñ·b´Ã6KЇ­ç”%ìºJlROyyylºJdØt³8ô´TUÉj 1*ˆ†*Ylò]‘‘‘€N:ÅÆÆ:tèÐÒÒB(.*tŒ[ûM¡WcÇŽN:•ü²ŽV±Øàîbôàêêj``ðòåKƧj‰ä'š\yõ¾÷’JvÁ{‘©ƒŠð­4êuŽŽŽ|>ÿùóç°srr lmmɲZoèÑi=Í<¶Ã}+F;l³ð%î˜÷ïßÿÊ•+µµµJ¾2baaQ^^~óæMkkkkk똘˜¬¬,xP )++óññi×®ÝßÿýæÍSSSÊæ¥¥¥»ví¢ŸˆåŒzZ™™™G¥oÅXÎáallllll‡lmm?~LyþAÀ¸I™E·=b\+ Ïv!³fÍ’J¥žžžðÔ5999&&ÆÆÆÆÑÑ1--qÍ£c=zô¨¬¬<}ú´ƒƒƒÝ;ŸÚ²y ©®®;v¬½½=´ ¯¯4 D½‡ lþæÎ+“É\]]9vJÿ©]»vñññ½{÷Æ0lÈ!ÅÅÅgΜ¡7GùI@¿æÓ0àñññPî>K~ñâÛRC]¦„ò]ÀÖ@Í ÛÌ ›È%E"ÑåË—-,,¬¬¬"##KJJàºJ…þmjë9`ŸÛ5œQ¹Cô­È%³Ãp&î˜×ÖÖ>{öÌßß_™”‚øùù½xñ¢±±Q,gffŽ3:daaqãÆ x“=//.á¯gé«ÃÉå“&M’H$C† !×9räÈóçÏé1e+góÐÛÛ–755½|ùrèСÊ?ŽV~àÁcwʳ„>{ö :§ü×{×®] ÅÀ`oBóëúúzxŽLX˜6m†aš„ ¢Þðcó°téR™Læè訒AÀàÁƒïß¿ßÔÔ$‰Äbñõë×á p2:ËO}~Ñ0àûöí‹Å;v„ÿ¶mÛöíÛ·§Nbs@Ç)¡Lp •È63è`r@É ÃæÌ™“——'‹ÅbqNNÎäÉ“u3ôýìs»†3ª&‡!ŽYÂ<œ$èw̹ÁX¤ž‹®Y7‹­œQOKU•,6±÷­’Eö³s§NTêâÙ¥CUr†n: I¸È›?„A5<Á”ÐÓY~’ÛBwRí€Ó ª‘ ĆZO eº€Û%Í ÷Ìð¾ G&¸¸¸èrèqlË8·k8£jrâ˜% lÃYS0 ct”­œ¢›ÅVÎ&¦†J–ª¾w>X¯>LÇÔƒ­-ºÏO?ð€kèá{oÇÌ {g8øÐ2á#šQÙ†ó{€¢›ÅVÎcÑÓâ!•,Dk‚òøÇÀ6œßlºYÊëiñ‘J¢Õ@ù‰@ücÐT¦é!´R¿C¼Pâ!Èðy<÷kêéQ°µµ­««ÓŽËók¡©›6•&2c­$Ÿ¦{õ;¶Üû@r’-ßW–j¥ßߣ"¦ª:m­*»øáð¡‰n*I+ŽíêÑ9räóçÏ›››kjjŽ=ª¤Fh¥1­k¡i¨€¥™16m*µeÆ€fòi UÊt©~Ç–{BN²e#‡.šB4Ô9ÓP6¡ÙÙÚþ«§ÓÖ‰§ÉÐ֙¢B4™ßZI­P“ÑAE»zcÌÌÌ^¿~éàà0eÊ”ÊÊJÆ·ƒѺҘֵÐ4TÀÒŠÌ›6•Ú2c@3ù4…*e˜®ÔïØrO÷9É[6²•+ƒ†:gÊ÷»ºw:ð_=6­'PehÓљ¢B4™ßZI­P“ÑAE»zcüýýáJàj×cÇŽeffÒ㮥1Ð ZhD}n¬Ö“cÓ¦ÒPfLCù4",l*eºQ¿cË=Ýç$#lÙÈV®Ð7 HçL™Í•éw ºîVüo%6ŽrU§A%‡öûUXT艆ó›Ây€ƒÖÚÕ£`ii‰aXVV4^RRÒ¾}{ʉ¹n”Æ@+h¡)TÀjm™16ù4 eÆ4”O#‚À¦R¦õ;¶ÜÓ}N2–lå }£X`”ÛÔ\¹–Š˜šøßº:m­ »Hn`Ú‚¢BO4œßδÞè à•””téÒ…ñihhhooŸŸŸ¯d9ììlÇGí›››S>:7zôèÇOž|xHHˆ\.‡Ÿ­#$4ئM%[·n¾¾þ“'Onܸ¿OIYeb²téÒQ£F­_¿¾¼¼œòSKK cÖ±•CTÍF¶ÜÓYN¶ #?a„¸¸¸ÄÄħOŸVTT‘çeÍû]™„ìÝ»7Ô½:tè÷߯¼lþÓ·3f ÝãX ×MâAmÍ{ÜaiÕù pÎZGµ¶hWoŒ"øÄãñ¢££‹‹‹ÿøã3gÎTWW‹ÅbÊÕ«Ž•Æ´«…FØdü2÷¶Ú’4m* eÆ0ÍäÓ€"•2 õ; Ãs­\ÉÖ)Ÿ“@-=6îr…Å-·©a¿«­{§¡ÿô­8ì¨¬ÓÆYÔšmÝÏ{lai½ù ´‚Z!w¹2mùÿhWoŒ.ødbbòË/¿\¿~}ÿþý{öì©©©¡x¬K¥1ƨ‘oh]|N2ctm*ÍeÆ€òi@‘JЕú[îé&'êúg ˹}ãÐ9SfsG¿+™“"¦†þ·žNw9P÷ÈÇ=´¹ã …Ee<¨7¿m«*,W¦-íêÑŸD"ÑæÍ›1 Ãq<,,¬¤¤„r—V—JcŒ´ªø\«ÊŒAèÚTYYY@]™1ÍåÓª”]©ß±åžnr¨®¦ ê霻֤ßÕÖ½#ßéúàtÚ8˺²‹ÜC›;ºQXTÆ…èR­PC(lllŸÏ¶ @ ZCA,n-.%±ø|þÍ›7“’’ø|¾’ZY@¨&‚XÜZ\˜Ò‚XáááðÈǶ @ ZCmA,e´¸”Ä"Ž|› ¡xàÝ7Ólll èÄêÖ­Û˜1c>ÿüó:XXXÐK ×­[·à—åèZ\€$|E9Œ±•sÿ„@ „(((xôèQbbbyyùÓ§O­­­_}õUmmmIIIQQQmmíÒ¥Kýýý)%ð¦hŸ>} Wyy¹¯¯/ýpõìÙ³7nÐï^’ËÉ×|› ¡9‚¬¬¬Û·oã8nii9sæÌ .øøøœ?¾¬¬ìúõëzzz_~ùexx¸\./--¥”jjj’’’¬¬¬ÆŽ M‘wðöí[SSSúŽÙʹB BS4ÄâÖâÊ bQ®ù8´²ÐÚ‚XÊhqµ±8~B BCj b)£Å”Ä¢ûÄñ@ 𢉠–B-.e±ÀÿÞídÛ@ í ¹ ‡—2‚Xà|l› ñ¡À¦Å¥¤ VNNNssóãÇù|>Û&@|()ˆåíí=|øð~ýúaƶ @ J baïàØ@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ >.]º´téRnevî:ŽŽŽúúú­ãÝ{`Á‚×®]ãóùäBe¢DÇÆÆ†^haaaaaA/·µµUÉ8@|,¨6u¶ôôôÄ0 ``` §§Ç]ßËË«k×®ôòàà`¡P˜••UUUíáámæääÔÕÕÕÕÕUWW¿zõjëÖ­ª3´ ¹½ qvvööö¦TV&J‡~ýúu]]]bb¢@ Ê ”PXXXRR’’’B„käȑϟ?ÏËË«©©9zô¨‘‘ÅàÙ³gkkkû÷ï¯dA%"""&&^Öðù|…‡¥òòòÝ»wSªmÛ¶­¡¡!00°cÇŽƒ züøqVV–‰‰ @(ž:uÊÓÓsèСb±xÓ¦MïñàGn¯B~ýõ×·oß’X@¹(L:uåÊ•QQQEEEd;¯^½ŠïÕ«—««kzzzll,ŸÏ733{ýúudd¤ƒƒÃ”)S*++wíÚEÞפI“ZZZp'Ž”ñ‘±`Á‚àà`gggb"›0aBhhèÖ­[?ûì3¢pñâÅüî»ïÜÜÜV­ZÅãñŒŒŒ ë 2dóæÍÄ,I1¢§§ؽ{÷åË—ïß¿ùòå°æŠ+^¾|™““óÓO?ÙØØ¬[·nìØ±ÄN'Ož¼gÏž?þøÃÇLJ(¤ùôõõËËËOž< ¯„0 >|¸T*ýüóÏ1  …¡¡¡|>Ã0ëÖ-ú‡âðøñãMMMfff[¶lÖØâ3uêÔÐÐÐß~û­oß¾†±‡Ò^Žhïß¿? à·ß~£ùˆ(±E• lõáÇÉG>kkëÈÈÈqãÆñx< ÃvìØQQQ!üýý¥R)¼$Å0ìØ±c™™™D¬ôõõŸ?þèÑ#¹\N9òAO\]]׬YsðàÁ%K–ðx¼#FüùçŸAAAVVVÜ)‡@ º£¢¢ââÅ‹iiiåååðþÕúõëëëëoÞ¼™˜˜XYYéåå…aؾ}ûšššnß¾ýðáÃׯ_ççç ;;»ææfb¶Ý¼yscc#œ[éFÚµk×ÜÜüìÙ³¨¨¨Û·o755:tˆÇã…††•––^½zµsçÎeeeÄEÆo¿ýVSSsýúõèè覦¦¹s牒~ä4hT*]°`QˆaXÏž=‰k¾ÐÐPø“­­mQQÑþýû)GºÃ½{÷®®®†ÎüñÇ"‘ÈÝÝ->ÁÁÁ±±±"‘hÔ¨QöööŒÁ¡´÷ûï¿gŒvssó½{÷>|XVVVSSC9ò•––BÇŒŒŒ£JïèC‡Q®ùà©üûÂ… iii|>? @&“Oþ¶nÝJÞ{ppð›7o-Z$“É(G>èIFFFDDDbb¢T*=wî\NNÎÍ›7+**âããááóܹsô”S9kBõôôLLLâãã×®]Û©S§ªªª;wêééñùü”””ÿþ÷¿:uª©© ……—.]zóæ <òI$’+VÀ©ö?ÿùOSS“@ °··§166–H$!!!°ðèÑ£%%%€Çãݹs'..î“O>Á0Œ|T;}úôš5k`ý¤¤¤ˆˆ8{Ò|cÇŽ•J¥“&M"O£ÄßB¡°  àÑ£G‰‰‰åååOŸ>µ¶¶&Ña@(‰Æ'‰~ùå>ŸÏXÓÉÉéíÛ·;v쀅qqq—/_îÔ©cpÈíe´£Mêܹs"‘ˆrä#"`ddÄUzGÓ|€>}úDDD¤¤¤”——ûúúbæëë+•Jýýýaô8@œÍôèÑ£ººzáÂ…3gΔJ¥ô#ŸD"Ù»w/ôäÙ³g}ûö .”J¥^^^””{¿Ï\Ä¿œÅ®_¿>dȹ\îïïolllooøôÓO=<< Ïœ9#•Jq¯ªªâ6êííM7gÉüü|™L&—ËsssÍÍÍr¹ÇqÇe2Žãd;sçÎíß¿ÿœ9sÚµk'ÌÌÌ”iÒüùó‰+¼µk×B²²²n߾㸥¥åÌ™3/\¸àãã#“É8ÆqüçŸöõõ={öl^^^`` L&c¬éííÝ®]»°°0Ÿ%K–ÈårF÷Èíe´F‰v~~>%,tèQU’ššš¤¤$+++‡±cÇÞ¾};"""..î÷ßwww·¶¶†‡CXyûöíÉÉÉÇŸ>}:›ÁÂÂBèIvv¶AZZšT*MMM899ÅÅŽzõŠ’rlB ˆVBpíÚµ©S§nÞ¼9!!aÁ‚ð±PÛ¶miiiB¡ÐÚÚÃ0e¦`ˆ¹¹9Ýe[¹\Î}²¯§§wúôéÑ£G'&&Ö××›››—••±U®««˜™™avåʕǷiÓ&>>ž¸ÄÉÎÎÞµkœd£££¯]»æïïæÌè›Ãr¹üÁƒîîî111ð0ÉXÞS---…Ö^¼xèØ±£zR5ÚdF•B~~~PP ¢¢bÍš5[·n-//÷óó[¿~½««kqqñ©S§æÍ›ð÷÷3fLhhèêÕ«áyÌäɓ۵kwçÎF?áaþÔÜÜ €×ô'N\½z59å^¿~­FKBm¿ýöÛ† ÜÜÜnÞ¼ùŸÿüçÊ•+8ŽŸÂq|Ò¤I8ŽwíÚµ¤¤„}ÇñððpŽ«™ÔÔÔššš!C†œ8qB$ÕÔÔXZZ’]…‡1xäËÈÈÀ0ÌÄÄÃ0X‡Ña¹\Þ§OŸÅ‹GEEÍŸ?ÿÌ™3Ož99yÀ€### ÃFŽYUU¥¼“NNN#Gޤ¤ÜÂ… ‰‹oм5kÖà8.‹qoii¹{÷nNNÎêÕ«­¬¬ôôôfÏž=qâÄû÷ï———¯[·ÎÔÔ´sçÎÄ»hMMM¯_¿9r¤‰‰I¯^½üýýᣎ… æææäå ÃŒ¼¼¼8®fêëë=:}úô5kÖ}úé§sæÌáñxµµµ°‚žžž]ÿþýwîÜÙØØMLÙlïÞ½»°°pâĉ™™™{öìáñxŒ5###óòò¾ûî; —?þøcèСÍÍÍŒÁ!·—#Ú7n´³³sqq™8qbk<  …[¶l±²²²¶¶ö÷÷ÏÍÍ}óæ ÀÝÝÝÜÜ\&“͘1cüøñׯ_Çq|ÇŽ^^^ÞÞÞÞÞÞÛ·o—Ëå+V¬Ø¹s§J÷* wîÜII9tÁ‡@ tMEEEmmmSSS\\œƒƒ`äÈ‘b±¸¡¡A(~ûí·<oæÌ™¥¥¥p…HAA¼‘8cÆŒŠŠŠæææŠŠŠ#GŽ477Ãrº‘víÚI$’uëÖÁy|ãÆ‰Vž={vCCCsssÏž=+**àÚ xßR*•¶´´Ü¹sçêÕ«ÄòzÆ÷ùx<ÞŽ;*++àN·oßí …B™L&•J%Immí³gÏÈÇ!Ýá 6´´´ÀU3£F‹Å[¶láñxŒññõõÍÍÍ‹ÅMMM‘‘‘p [pÈí5j[´%‰H$‚W±Ü+\£J¾ÂÅÏÏïÅ‹b±833s̘1ðìäСC555õõõ‡200 ˜š1cÛ “°°°ŒŒ Ø_nnnR©tÑ¢E|>ݺuô”C b``ðÙgŸuêÔ‰xg Ã0>Ÿïæææîî®§§'2 ÃAŸ>}ŒŒŒ> ×vÂrƒþýû›™™ñxŸïäääêê*ø|>á!¹øÀlàÀ®®®ÄNa}2äÕüt‡¡3°&l> Æøðùü~ýúQ"É¢½ÑîׯŸ••ŸÏ§ÉÈ`‹*=8”Ÿà®»téÒµkW¢¥°¦½½½»»{›6mã Ý£ÇÒwä8?ñx úòË/‰+< ÃîÝ»UÙØdüÈJu½zõjiiÉÊÊŠŠŠŠ•J¥¿þú+ÇSf[¨ê¿.ö^bˆ@ ˆ Môù#PÈÛÛÛ›|oó¿ÿý/;e“ñ#+ÕÁo›»8sæLee¥¥¥¥2Û’?‚@ 7­¢Ï§$te>BgîÌ™3_~ù¥»»ûóçÏ•ÙV*•jÅ%@üãáA}¾¤¤¤;wî888õùÚ¶m›––öàÁ…ŠqP¡}ûöäB33³ÆÆF•¼!ìçççÓ "¡9¼ß~ûÍÝÝÝÓÓ³[·nÿùÏ LèÉ“'çÌ™3{öìY³f­]»¶¨¨êó±-ÔLHH¨¯¯6lQÁÖÖÖÍÍ-55Çq6?ºuë(..Vc[@ ¸Ø¶mÇsqq)..>xð ¡¡aFFƃ:tè ¯¯?oÞzzzä$ªÜ¡µPÍõùnȱ#XNVôV[å@ …hGŸOá†Ü?á8.—Ë‹ŠŠàQµUîhZIŸÏç£;–hmÔ9€ÁWȵîJ+™U›úúú÷µ÷-Æ.ßEþ×¢a.ééémܸqذa¶¶¶/^¼Ph g7|€žž^ÇŽkjjÈ?\ºtÉÜÜ<%%Eãт ‚‚‚.\¸ ªm9 ==½óçÏ»ººÞ¹sG}iâ§ÎÚ¨*Œ1áV^dû•0µyóæ––ø!r-úIOÝ6B¾©a'::Z"‘¨Ýû†††7oÞ´³³«©©¹{÷.ŽãlÃVÃáÌ ãÕ‚Ïç·´´hݲ•••ý{ ¶¶¶uuut#ª–³aaaѦMU¿C¢Œ¶±ÅPÕú*pùòåúúz‰DRZZºuëVâ~ãßÿ üíÇÈÈÈððpú]ÐmÛ¶UWW³-‡á ¬¬l×®]:¸ÿ¹sçÎÔÔTkkk@NNN]]]]]]mmmaaaxxxß¾}¹Ñ(ô3++ Ú‰D999´°°€?©dAŽ P¤¼Èý+ajòäÉ•••ƒ¦ÄÓÝÝ]$Íž=»¦¦fåÊ•<è…êêêW¯^‘Ó’ÀÎÎŽ-u!>¬­­­£1hÐ èÜ#å×í(̇K—.={öŒHûøøøôôtâ߸¸¸¨¨(J•·OçCÈ75Ʀ’½?pà@ÆXÁpßÿ=1“PR”€±\™Œâàðáï_¿®««£¼ÍÕ£G‡666644À³ò6¹-2$99¹¹¹¹¹¹9>>¾W¯^0n#GŽ|þüysssMMÍÑ£GŒŒ`}UËçÍ›GNþGÁ¤4hPBB‚X,niiIIIñðð ÷—¡¡a^^ñ¾äìÙ³µµµÄ¨g³ÀÖ"¶ªZ_erssGŽiff¶råÊÆÆF¸º¨þÔ-66öîÝ»ô#߯¿þúöí[5Ž|ååå»wïní£ÂgŸ}VWWGô¥P(ÌG›”˜p+/rÿJ6…aصkׄ|Scl*Ùûl±"¯ý´%`+W&£8˜:uêÊ•+£¢¢ŠŠŠÈSÙÇŸßÌÌìõëב‘‘S¦L©¬¬„窖ËËË,X0þüùóçûùùA÷^½z3®®®ééé±±±ä-Y²$??_OO(™4iRKK ŽãÄŽÍc‹8b¨j}•ùóÏ?á–<ïÒ¥Kÿý7üwݺuð«(zzz®®®kÖ¬9xðà’%Kx<Þˆ#þüóÏ   +++h‡rä[¼xñþýû~ûí7ò‘o„ ¡¡¡[·nýì³ÏˆT˜ÎÔãÇ—H$'N„^M˜0áÏ?ÿÜ·oßèÑ£é~.^¼˜Ø`Á‚Ë–-ãñxEEE„MwìØ±ììlÆ ³µkΜ9üá‡:wî¨Ë˜ÁÀ41 ëÒ¥KuuõÞ½{y<÷¯Jx§L™ÒÒÒBþÊ`ðàÁ"‘¨{÷îðƒ†‘{ÇãÅÇÇߺu‹’ßB¡-u!Ø;àK8ð QÊìCÔéܹsIIɉ'è{áÈÀ¨Q£àLaØÒ¥K«ªª6oÞÌãñ>ÿüs©T:cÆ ///J•´ÿaæ MJŽ?>00ÐÔÔ`ff¶eË–Ï?ÿÃ0ezŸ-V”#%¯ØÊ¹3êóÏ?§œñPJàV‡&Ÿºwï.‘HæÍ›_ÄÚ¸qc]]ã)~\\ÜÍ›7'hFË€†††ü:ZXX( $ާ§'Ì–cÇŽeffòù|UË¡¡¡©©©Ä°…-µ¶¶ŽŒŒ7nlÑŽ;***È^Ý»w/44”èw}}ýçÏŸ?zôH.—Ã#‡ÆqÄPÕúdèJ‡7lØ0x†.—˧OŸ>qâD™Løî»ïÆŒƒa˜¾¾þ¦M›.^¼8zôè>}ú„„„œ={öàÁƒŽŽŽß~ûíÕ«Wé=ºoß¾}ûöuëÖí‹/¾˜;w.©õëן;w®S§N#G޼sç¼õñÛo¿?~ÜÑѱ_¿~·nÝš3g‡ÇЙ°°°I“&uîÜù÷ß'nOÑ»¹¹úé§€¥K—þúë¯pdN™2eíÚµµµµ8Ž{{{'$$Èårò^ðwÔ××c#»iÓ¦ÿþ÷¿]»víÙ³çµk×èwúôé³cÇø•m##£íÛ·»»»SlÊår###âa%ÈŒíúñÇÿúë¯îÝ»9222rË–-”ý¶jLljj 51pÏÉÉyöì¼¹Áý+€Þððp‘HçAÂÿ·oßîÝ»·¤¤dÿþýäGGР½½=ýké………l©KéDÆ)…{öì‹Åëׯ'[àÎHTT”H$‚sô!C²³³_¼x{àÀ---‘‘‘l üHó=ÇŠŠŠV®\ 7ܼyóš5k„B¡’½O›8ba¶åä˜3ÊÌ̬[·ncÆŒùüóÏ;tè`aaA/ï^»¢8Ó½{w Ãà‡Žq/((000 ¾×H†Çã±ÅÑ2    oß¾@àêêZPP€ã¸¥¥%†aYYYp%%%íÛ·Ç0LÕr€••Ueeå’%K‡ wZVVæëë{ëÖ-è’ƒƒƒP($|ëÞ½ûÀ?N”lÞ¼ÙÈÈèèÑ£D ‡ÆqÄPÕúÐÆîc&''§¦¦&<<ü믿þä“Oˆrâ´žmíÝ»*ç={ö¬±±±oß¾`áÂ…R©J××|ð)tHH¬îÜ9‘H$ìííéÊ|>ÿôéÓkÖ¬…IIIðPÊxÍ!Œ=z´¤¤„ÍøðáÃ¥Réøñã1 ËÏÏ/..þå—_àõ¼¯mhh(‹Éc[(>|¸S§NvvvÞÞÞ111oÞ¼177·³³«ªªúóÏ?¡ý#GŽ”––ZZZ’ýôððH$«V­âñx ,Éd£FÂ0¬¨¨èÁƒ[¶lùñÇÏž=[]]=oÞ<ØU” ÓÛell\ZZzúôéO>ù„Ïç>|X&“QÎqZ5&ÜʋܿÒà xöìÙ7(g°¹ =z”˜˜¿–Gœ3tèP¶Ô¥ÀýáÀÒ¥K›šš¦NJŸ³Øò\çþýûð–NnnnHHHpp0<Ï OII!®3È ThÿCÎ7²Æ"‘hܸq"‘è—_~!º[aï³ÅŠ|ÍǘW¶rÀžQ_}õUmmmII |™xéÒ¥þþþ”ÂÚ¡C‡ÈWf3fÌ '?ü—ü`lôèÑ6lظqcvvvZZÚ¦M›6nÜHÒI· ðññÉÎÎ~õêUffæË—/ᩤ¯¯¯T*õ÷÷‡8eºU-DGG777§§§ççç755‘o,÷éÓ'"""%%¥¼¼Ü××—ðö÷ß'œìÑ£GuuõÂ… ¡Î¹áŒ[ÄCUëÃ]Ó;”휃7`À€ÀÀ@}}ý}ûöÅÇÇ;;;3^rÊd2™L–]XX˜––&•JSSSNNNäš$Äüd2q¶îííM(ÿíß¿*ÿæÎ7gΜ€€@`ffÆè((ã'“Érssá4Äh<&&¦¨¨hèСcÇŽ577¿té¼Ûîææƒãx‡ôôô*++ÉÆ¿þúëÜÜܼ¼¼k×®A÷ª««½¼¼ŒOž< uöìY ‹c•˜˜øôéÓqãÆa6a„ÌÌÌû÷ïö;88Œ5jøðáÞÞÞÕÕÕoÞ¼Q²]ýúõ³°°¸pá‚D"Á/1QFSoß¾…÷Áài/€|ªž••uùòå .;vÌÒÒòÂ… ”[ 111J¦.7]»v »zõ*ãc>+$''wïÞÝÝݽS§N·nݺr助©©¯¯o¯^½àU c¹íøùaÌ1Çþù猌Œ³gÏæååWÒ {Ÿ;V¶åN]ÆŒ:þ¼ŸŸŸ‘‘‘……ÅìÙ³:tîÜ9J ‡'Üxyy-[¶lÙ²evvvNNNK—.]¶leý'Nl×®]ttôƒ¬¬¬à=ꈈˆ¸¸¸ßÿ}çÎgΜ!nè©ZxþüyPPPß¾}]\\îÝ»G>òÕÔÔ$%%%%% ² €ŸŸß¥K—ˆhlß¾=99™| HÀh±EªF@aÜèÊÖ}x{aß¾}}ûö½råÊÖ­[g̘ÁxÏÅiaká]¨ŠNT`ó377ÇÞ)ÿÒÒÒ„B¡@ 8yòäèÑ£ëëëÍÍÍËÊÊ6@.—Ãc4.—ËÜÝÝÛµk÷äÉ“sçÎ-Z´ÈÓÓÓÁÁ!<<œíFÊáÇÈãÇq([X\\ ·*--Ï8!8Ž_¾|ù‡~°µµ2dȱcLj ßºu Ú422ŠŽŽþñÇ}||8‚L´«C‡€ÂÂBb:Ž ›ò"œý¹eD™&²³³wíÚ}íÚ5ÿ3gÎï^ªšºŒìÝ»·®®nݺul2æ¹BLL̪U«-ZTQQqûöm©Tš——7yòäŽ;>zôHa{?ê|cÌ1ØŠ¸»»ÇÄÄPnAsl=Ø2* <<¼]»v³fÍ‚C€RÂfqI=ù­ž   Ÿ~ú +‰üüü ì¶ÂC©§§ç·ß~»téÒ'Nà8þúõë~øáäÉ“~~~ëׯwuu-..>uêÔ¼yó8Ž«TX±b@.—K$’K—.3ÆÙÙ933Çñüüü   @EEÅš5k¶nÝZ^^>uêT33³'N@çýýýÇŒºzõjxÆ9yòävíÚÁ7Ièœ[ÄC¶(Œ¹òÝ'>|øýû÷årù“'O 0ž&ÀÔwqq!ß#äååá8~òäÉ›7oÂrÇÇŽ;eÊ”E‹>}ÇñððpÊ­$%a4.—Ë£¢¢¶mÛfnn–˜˜˜ŸŸ¿~ýú¢¢¢„„xã["‘PîËår©TJÉÎÜÜ\Çûõë?ÛÖ»wo@FFÅãÇoذaûöíFFF°Ï`9Žã0éE"QRRyÁ7prrrzúôé{‰ ¡¼xéÒ%h*/ž;wÇqî_ÃkjjZ\\¬Ðyè*ì…ŒŒ ÃLLL0 ƒ{ñññ9räÈÂ… 5LÝU«V 6Ìßß¿ªªŠ­c>¹sçN}}ýÈ‘#“’’àq+..nĈr¹<""Bá\ÿQç[ŽõéÓgñâÅQQQóçÏ?sæÌ“'Oà¯Jö>7ŒyÅQa˨€€©Tj`` —ËáAš^ÂHVV S§N±±±€:´´´Àƒ¬@ì^*ÀËweèèèÈçóŸ?Ó)''ÇÀÀÀÖÖ¶°°P$mÞ¼„°°0â+’ª–=zôæÍ›/^ÄqÜÀÀÇñÚÚÚ^½zoݺ5)) Ž_}}ý¶mÛ–——Ïœ9óÎ;oß¾…ÚÛÛ'''0`dd„aØÈ‘#«ªªÊÊÊ~þùgº¶Á› ôNžÌ¸" §§gggggg׿ÿ;w666FGG»ººÂM’““cêr›%WèÙ³çæÍ›/^¼øôéÓŽ;ÂÝY[[»¹¹q[ ìE,¿|ùÒÎÎ.** öxTT”­­mVV¼VãØ–ÍþÇ’ol9¶{÷î‰'fff’åÔì}z¬È…lÖ{83fŽã………B¡ðõë×ùùù°&½„‘ôôôÔÔÔÅ‹·oßÞÑÑqΜ9<`û΃JÄÇÇ×××oذÁÜÜÜÊÊjñâÅåååðìÁÝÝÝÜÜ\&“͘1cüøñׯ_‡®j¹³³óÊ•+mlllmmçΛ––VVVVRRâáá±eË+++kkkÿÜÜÜ7oÞØØØŒ1âôéÓÄùÙŽ;¼¼¼¼½½½½½·oß.—ËW¬X±sçÎââbF l-JKKcŒ¡ªõÉÑS²ûÀýû÷›ššD"‘X,¾~ý:qG…ò0œXO–‘‘º¸¹¹I¥ÒE‹ñx<ò[ PÌO"‘ˆD¢'NÀ.€IùÏç_¹rE*•¶´´Ü¹sçêիĺ[ò —ÒÒR8~(ÎlܸQ"‘°‡ubbb ÍaÆI¥Ò CñÈ‘#ÏŸ?'ž!ÁÕÏŒGßaƽzõJ,777¿|ù®´•8Ó§O—J¥Ä۸ʜø÷›o¾‘H$ðý ¶ “ÛåççWTTƒy÷î]¹\ËuÞÿ*/&&&¾}ûöÑ£GP˜ûWŠ©qãÆI$¸®}Ò¤I‰dÈ!ŒëJd2™T*•H$µµµÏž=ó÷÷çñxäM̘ºt³”.Dx‡^rIÞ‘’’2uêTÂ[>Pö²oß>±XܱcGøkÛ¶mß¾}{êÔ)Æ…ìäm?Æ|£ø@ϱ 6´´´Lš4 ðQ£F«N”ì}ÆXA3ÂaJ^°•³eÇ®éÐס 8®øƒú¦på!}C>ŸÏýÎÅ2†asæÌÉËË‹Åb±8''gòäÉØ;œÆÆÆšššúúúC‡T*÷öö~ñâôüåË—C‡…öýüü`¹X,ÎÌÌ„+7mÚÄø®„²Ì„ÑG‹c¨j}å;ñzÅÊÊÊÝÝÝÄÄ„Ü=dÅ;òßä^Ä0Œø‰^Þ¯_?+++>ŸOîQºòŸÏwrrruud#lÿæý¯\Ý8‡Ã~ýúÕ××ÃQJ1NÚïÓ§OïÞ½ÉꃔMÖ­['‰Èk) ÏôÝq´K ¸¹¹mÛ¶x9Rg1$åE;;;>Ÿ?f̘'OžodrüJ1uîܹèèhè^``àÓ§O‡“àË#)›À¦ÑS—n–rXNßÙ[>PöBÙÜm²SÆ>øxòžcä=’³KÉÞgŒåPMOQ[9[F©½—aÛ¡¾©šS0»ånݺ¹¸¸{®§uwwoÓ¦ ¥—U*'ì;99‘íÃò.]ºtíÚ•(¿~ý:ãkÄ& -p´ˆ-†ªÖWM·WÅ&<¤s—h²S•La¶k×®gÏž)³¦”Û¾……Å„ Þ¼ysöìY5?+ÀÄØ±c×®];~üø¯¿þº  €ø–òh+&”ä£w"ýW²)__ßòòrø `çÎsçÎUÉ1ÆM(ÿ*4«y%ëheÛ%ßæ˜z½OTƒG¾úúú°°0˜]l)ªÒpÖ ­1y–sL­ª–³Ù'—óUÿô’–5ñP% À·ÙvîÜ©jïR˜6mZMMM\\œ½½½¶||ñÅéééµµµeeeáááê_Ý«‚¶bB6õôéSò=U‹1·)…›(¬£y%ë´Æ¶d>®|KNNV£÷ÉÕ|||†N|¿‘-Eµ˜ºÄ?>ŸŸKi¼ê×âÙ7aÞ1Vû.zh%&dS666h2Ò"W¾iÞûØ;ˆ¶Õbê"@ ØÚÚjnDÕs4•ê[YYq}ÀMéú†††„ ’(é§±±1å=en l1·°° ´”­¾¶Êu€ªËcÙ,³•«:T &›}¶äa³£¹ÿÿÔtýÓÑZh"[Å&þ¤<ŒòTtá4ø ›MΊMnŠM䉀".ÅQÇŽÕÕÕpU4ñù`¶ý²ù !Ë\õéÓ'&&¦±±±¹¹999™ð„Í[ÌÊVQZÊV_[åÊ ¡jšÂÎUˆªêhªª¦±¥‡ªÁd³Ï–<ªjžqäCº~héÍ1*ï‚ µe«8ÄŸ(¨*OÕ¾}{{÷î …ð¥W69+6¹)6‘']\Š­þêÕ«kjj¾ùæ“!C†oà²í—ÍOYæ*>>>55µo߾ݻwOOO¿wïÜ#£Ž˜sËVÑ[ÊV_[åÊ ¡jwçhK­\ 4•‚ÉaŸ-yTÒ|xذa]ºtIMMçÞ/›ŸàÌÕ† à÷½ºu놿û>½³³saa!ñýCº²à9æl²Uééé8ŽÓ[ÊV~|Vór¸_=‘èŸÒW/ý*++9:—ŒéÇfY¡jøßÀ˜ªŸm ±%G2¨êÿ¿$]?ÌôÆYæ@åÓÁ`„ Ÿ}öÇstt,.. ’Ëå£G>tèP}}½\.õêÕ÷ß/‰|ø7ß|ñ9[ÌõõõÁv# IDATIØZnÓ¦ [KÙêk«œp˜žH$7Píô;xð [ç»V;ýØ,3–s ÆôP5˜ö“‡£STõü;ÒõÃLoh‡mÔ|vý—#ÈÊʺ}û6<õ›9sæ… |||Ο?_VVvýúu==½/¿ü2<<\.——––RJ ø“»»»µµ5YÃâåå%1---e2ÙÒ¥KÊH·@æÌ™­ÌÇÝŸ?ñûï¿óùüË—/¯]»v÷îÝr¹Š<]¹rð©S§Ž;ŽaB\júôéd;ŒõáO?†ã|çÎ+V¬8vìXVVÛ~9\õóó;pॎ««ëž={.\¸@â¡Cn±Åœ[Kuc"‘+h’~l -k’~l–Ë9:…1=T¡ÂNW2yØÚÅmÿ_•®ªÒªé -°ÍšÏ®ÿrjËVáìâOµå© ÖÖÖPzT™Žd”›277gy]XXõ58šÉs6Ùª¯¾úб¥‰„±>›UËÉsËe©~fвÖÕÑ:v쨒j`IKUƒÉ=ÐèÉ£ªæ‡ÿÿ’týÓnÎ1j8»"¸²UlâOµå© ®®®/_¾TæÈÇ(7Õ¯_?>“ÈS§NÅ¥JJJë'$$”——Òó&&&(UŸ_‡)2WcÇŽN:U$)l)cÌÙ¤ÂFÍØÒÈÈHÆú°ƒ4/'G€[.KíôãÐ0ƒ{׺:šªiŒéÁ¦1ÆLŽFO¶d`Ó<ãðÿ_’®`zÃÍ9æ@ gW8|øp§N lÕ•+W >!y}¥>¹ÄÝÝÝÒÒ0kÖ¬úúúíÛ·3>k}ôèyQºü`îܹ2™ÌÕÕ•î½~llllll‡lmm?~œ’’ÂçóE"ÑåË—-,,¬¬¬"##KJJàçäùï˜5k\~ÆQRVVæããÓ®]»¿ÿþûÍ›7¦¦¦lûeóÓÆÆ¦¦¦f„ ä…„„TWW;ÖÞÞê‡Á§ l-eŒ9†aÉÉÉ111666ŽŽŽiiiÿý7üÎ,cKÙêk«œÞÅŒ·¹„B¡ÚéÇÑYTM?6Ë{dŒé¡F0Ùì3&›Uýÿ÷¤ë˜ÞŽ9@az#˜ÑD¶ŠMü‰Len;ô#ßÒ¥K᩽2õå¦0v‘'²¸G} ‹7n455544äåå2(l2WŒ~2Ê\Õ××ÃS6B"nÚ´i„zKÙb®P¶Š"£ÅV_[åÿ½÷®²ºòÿÏs¦PEš{ (,Á‚ *ø:(ÂbŒi c -.‘0PuùׂL—,TÚ!X¨Cá…iQ±´("…‚‰ ¿#"wˆ€$üHB’û|ÿ8Ÿ¬öQ{Ru½©¸%œ;~Í6×§ˆqJÈŒâtSÐXú7åGÃCç÷Y›×V8Þ‚|Z}ÿòÿIP²%?±õ7•Çgþ>æ mÇí7©} ŠÛÜ–g&âÜ!DUUÕ–-["‘HÏž=ï¸ãI™¢‰hþqz(€öØcEEE½{÷&ˆh,œž6ee%+ÍÓ®G|2„ë[·n뺈F¦­ßò̌Ľÿv“Æ?kvx|òÏÔq €ÇS× <®r½vüŒºnjšï%88=”Ÿ›G`lžv=×' Õoyf¦âêˆj¿=ÕBþ=<žhþ™:®èPôõQ‡­'®vxÐzÖ,ÖµE¸A‹ lUquÚ“q iÄ©§¤`ÕAÉÎΖ\±ššš½{÷Ž3Fþ¾)ADcáô´ùäAØ<ízº~©*¢‘ië·<3ƒq?j!ÿŒO4ÿL;®\<ž”ÿqE× ZâšÅº¶¨N‹ lmq?já5¤§žèk@ŽÀ|2ù®Nôƒ¯#PRþósó€Í£÷õë£ùg õ[ž™Á¸µœF OiÇ•>,?ÿ㊮=<è:£8«Y¬k‹êÔÆíµúã~dв©Eœ~?’Ÿ¨ú›ÊŸì—°@² !îG-çJ©—ÎÊÊ* ´˜+š™¤b«ê aŸÐz.ÿåaå'êä‚Ö?Zlq.¹ÀÉZÜZ0C­Iy€™•ÕE,-æŠ`&©Ø*Pgö ¡Ñ¸ü?”‡•?¶ŠÅùM³¢ØÐ¹¤,¬•Ç®R’fh¨d`feu+´xñbùǃñ˜+™4{öì‘#GÆ¿@b«–,Yâý½¡ää•••9²°°pøðá2ŽpVh½ ùRñ0”‡›Õ‰âŽã4Ëù‹÷Gà¿îÔžËsïúë¯ÿýïï6É´ÒfŽ’É·d¤dòIªVÎu¦­Å½@;w¾êª«ÆŒsçwvëÖMûÓ_ùÚ®]»fffVTT¸®«¾ åÑU‚äŸo£µ²²ŠWª|Ô&`®3I‹­Bœ<„}ŠD"Æâÿ¡} nŸ6l—óGK 6³@²Ö÷ O*À¬oß¾ÄP%`feu+$t˜«;wΙ3çÚk¯íÛ·ïúõëüqù餇­R/ÕÖ­[‡:dÈ… NŸ>½OŸ>ôÆêzÇq$L’y#‘ÈwÜÿ-L›'X~ÿByiÏ•ÿ% Höâ‹/¾ñÆÚoÁ%(XåVR+V¬ÈÎÎNKKKOO¿÷Þ{‹‹‹U€ÙÊ•+KJJ–.]‡KJJRRRÔW-_¾\ÍC·æ¦›n*,,,,,ìѣǕW^9uêÔÂÂBû[0VV´BZÌÕôéÓçÍ›W___[[ûöÛo‡ÃáÞ½{çåå3æ‹/¾xôÑGåûŠæääÜvÛm§NòPg+V¬øÁ~pÝu×!œUUU•v½’=ýôÓKö /<õÔSÝ»w—/”°?þØ»ÿñˆµø<(Žòs±U(ò‡~©ç†€d¯¿þzïÞ½«««—-[&ÏBÉÔÊÛ¬å³?ýéO“&MRK€ÙK/½ôôÓO?ôÐC7Þxc^^ž"áUjžf‡jΜ9W\qE¯^½ÊÊÊ>þøãÞ½{÷êÕë·¿ýmËfVV±Rµ˜+-3)33qì´¨³Ã‡ öéìÙ³Úõ½˜ü?„XCq”Ÿ $C 5šó‡ ›Y ÙoY’fÄ¥“»'`feu±J‹¹Ò2“B$ÇNE9û¤]ß‹ÏÿCˆ5V~T'Š£<„?R*7nœ|×çŸþÛo¿MMMEÔ7yxŽŽ‡ò£8A§Cû ÌÉ“Šçá¡ü輄ˆÛ‡â„ojÞÑ,·ï"‹'\ÉdpþÐåR–ógÕ”*9v}úô)//ß´i“âèÑ£cÇŽõþضgÏžÑhÔuÝxꛣ¾IÞâÅ‹òˆ8þ\ü–(?ŠK:üû_!„G§#öMH³ùóçË÷<ôê‘ÿÏÃCùÑyQ\`¾ 6Nû¦Ö)#’Û7sæLÂä<ªñçvìØáº®ê$Z/ÿ´ßƹqé³¢sçÎápx̘1—^zé'Ÿ|RWWwìØ±„+_Û­[·ÌÌÌÕ«W»®«¾*‹%DÐåRŸ–ógÕ”ªåØ5664è¹çž‹D"Ý»w/((ˆÅbˆúFððЮÚüt\¾0žNGìKsòTž6?:/Š ÌíÓÆ›õÍrûÚHÜkPR9èry[[ΟUÛQêÖ­[åãòÅ_œ>}úÒ¥Kå×UUU[¶l‰D"={ö¼ãŽ;Þÿ}úvÝu×eddŒ;6þ[+(ÚXÍ/£¸t:í¾Òìç?ÿ¹ºµ–‡§æGç%|ܾU«V9Ž“››{ÇwÈQÚx³¾!nßÂ… [ÈíÓvP+ÚI+³Z±bÅÑ£GKKKÛµk÷ÏÿüÏï¼óŽÊù“7"ççç—””Œ5JûªÿýßÿUó—릛nºÿþûå·4§N*„8{öì§Ÿ~j?òY]| ©;ùsæÌ),,|å•W|ðÁôôtPßÞXÍOÇU:Ú—FšiyxÚüè¼(ޏ}(Nûf¹}m'îý·›4Οº\Ârþ¬Ú˜RUŽÝÀŸ}öÙ¢¢¢-[¶¸®{äÈ‘öíÛÿèG?ª¬¬ÔRßm9pàÀ¢¢"5—.]оBG§Cû8@šiyxÚüPîPñÿP|óæÍ„o–Û×vâñ-Nç]:y¹„åüYµ5©»ôôôÊÊÊ5kÖdddddd|ôÑGûö퓿륥¾ ÌÉ“J`è üľˆN§Ý—Fš!Ο6?:¯6ޏ}wðÍrûÚN\½•ÚïB·„óG\®YΟU›–o—-ù|555{÷î3fŒŒ#êâäI©Ï_”ÅŽÞWèfZÎÊΫ;€Û‡â´o–Ûצâ~ÔBκ\ ²œ?«¶ ‡àØÉ·Ô:xð GÔ79yBGCùQœ Óû ÒLËùCùÑyiúâÿiy~¨~ËíkSq?j!ç].+«6*ùu +ÎÊcj_nS"Î˪§…çµÜ¾‹>~”ìËbeeeeeeeeeeeeeeeeeeeeeeÕªE ¾Œpø¸âòí ñó¸ô;T—ç‡ò³2hÅ%)ÇVÅ·»ÐãçAÄ0[Yµ9%Ð×P!¾Lqø¸õÀç»ÿþûãwŸ~ú©üEmDGCü<.ýÕÃåùùÅßóù´h‹¤ˆÖ·6¾Ý…÷£òùÈ¥•U[”J_Cq„ø2ÅáãÖƒø|³gÏ®¬¬œ«¶ T-ÇñíhÄ—*.‡í«|»p8|à 7D"‘´´´™3g>óÌ3/½ôAGC\=ýÕ€çG(ÏGgH üqIŠh}kãÛ]èqÏðdóùdí0[>ŸU›RHÒ׆ۣ²©C/_[¶lIMM½ãŽ;šýyZ¯£}‰z¶nÝ:tèÐ!C†,\¸púôé}úôqgçÎsæÌ¹öÚkûöí»~ýúÇœþ4VòóäW‡‘H$á\>éw¨ž÷ß_Rñ^|ñÅ7Þx#þ[Rô¾ZeggÇ#Úé ZŸÖ1Ö‰è ­kÅŠÙÙÙiiiééé÷Þ{oqq±Êç[¹reIIÉÒ¥KÃápIIIJJŠúªåË—£öØcEEEèD+´^ÿã?þ£v_TÏgŸ}æñíb±ØŠ+þå_þåºë®Û·oßôéÓ…±X¬¾¾þí·ß3fLïÞ½Mòó¦Núú믻®ûå—_þë¿þëþç:tHpèwñ¼½„z²³³Ÿ|òÉ|óÍ7Ë–-»ÿþûEÏí«UŸÎ ³gÏöpD…¬Å#åâlmÜ» %îý·ÛÄÕ»ä’K&MšôÎ;ï$,–|>Ùý 6üñÌËË{ã7^…òÃ|XëdkãÞ](ñøv'‰Ï'_N ³åóYµ-©ô5DekñÕBÚ—àí!¾ÝÆ7nÜØ­[·Ë/¿|ëÖ­Û·o'èh4?E¿Cõ°x~(¿Êç£3 ¡’"Zœ´ñVËçkv˜=Y>ŸU’Ê±ÓÆiÄWË9|Üzßîæ›o–ùkkkwíÚuë­·:˜Žæ`~—~‡êañüŸ*ŸÎ %rIŠh}kãÛ]èq?j!ŸfO–ÏgÕôŸ-&pì´q‡D|µœÃ‡ö%â_°wïÞ _}õ•OªœÊÏãÒïP=\žŸ6¿–ÏGdÐ’Q…ÜÑNÚ87îG-äóÑÃleeÕŒä×I-_ÏÍc*?Úô<ÔÓ’} >Ÿ©Žp×'²ñq++++++++++++++++++++++++3B<9BFø|ˆ6‡âˆÇåöòÉÉ3(䤖ëÆí‚´µ6^Ý…ÿÞÅ1rEå7²¯Á«ä³N.ïûÐkm#}ñĵ;Ä“ó”ÀÉ3ÅçC¼:€Gĵõ#žŸö\4ýNÍßìúxÞrqÝP§Ð‰¤­µñê.ô¸µ·'…-˜ F”‡‹ºDùiä¤ð}%ѹˆõ¬üþјګD\vîC¯µôE*ÇŽàÉI©œÄ«CqDCqT?âùiÏEÐï´ù›]ÏÛCNj¹nD§Ð‰¤­µñê.ô¸ùçíÌ<Ôh.ˆåá¢.Q~9éÿJr‘œÜüþјګD\vîC¯µôE*ÇŽàÉ ÀÉs ñùmÅmÅQýZž:——ÓQèw„?h½ø{ÞžvGÄu#:¥=‚´µ6^Ý…Ox\ãíÅ‹`æ¡Ñå‚Q.ê’¸29ɺ’,$g€üD"îªÒðNõ²sz­m¤/¾xªÊ±#xrðóÜ&ÅOI>¢ÍiãˆGPèPýZž:—ô;Ú´>·§Ýñð"‘ê”öDˆ8hy{­Š·'ÌdÈT¿–ç—€IJ¿£ýQ× …·‡„¸n®ëj;%„ N¤BÚZ¯îB{ÿíåíÉ!ñÃÌÓ6úرc,#ʳwï^ê%G"® ÷\Úõƒ6uåµWñµ—]pz­m¤/¾x(77W~Šáqì\ו<¹œœœiÓ¦uéÒEòä233%'/''GþVÅèÑ£ „>C8p`iié°aÃ\×Åb‡ïšk®ÑÆãis±X̣͡øñãǵô8D•#ê_²d‰Öí¹¤Túíº^(¼=$ùÀÊÊÊ’ÿ7žë¦í”‚8‘„´åçç{6”߯ƒÅã[]__ÿ¿ÿû¿ÁPdVVVVVVô—¿ü%áO…Çùãÿ¨Æã5xðàS§NIB£Ÿøÿ÷ÿÏÿüÏèÑ£;wîüË_þòìÙ³O<ñ„ýàgeeeeõ=èܹs#GŽLø@õ³ŸýL÷ôÚk¯iÿ Å£ÑèüÇÈ¥¡Pèí·ßFïvaeeeee•\UVV¾ôÒK _~ýÃ?üƒ6îiïÞ½K–6š$ IDAT,QÿÅ·lÙ²sçNïÝâ‰÷¤°²²²²²JªBGŽQñ%çÎÓÆ¥:v옙™YQQá3.„xâ‰'Ú·oÿ·¿ýmõêÕ¿øÅ/ä›);„••••••o…¾ûî»ø·²õ„âBˆnݺµk×N¥K£¸â£>’ØŽöíÛÿö·¿Ý´i“|·žø5¥¥¥[šÔìï×XYYYYYS*úÓ³ÀR×uOœ8ñ›ßüæ·¿ýíµ×^»jÕª¢¢¢{î¹'þ+?‰1“ÿ}äȃ»[YYYYYyJ½ì²ËÀÁR(.„8räH}}}zzºÏø¨Q£~÷»ß=øàƒþóŸc±Øßþö·Í›7_uÕU Ë^{í5ï¿%Œ}+++++«æêÚµëþýûÕ3^|àÀ‹/îß¿¿÷íÇ3gÎ:t¨gÏž /AñmÛ¶¥¦¦>ûì³×\sã87ß|ó7ÞøÅ_$,‹ÅÉ~س²²²²J–êëëÕ¿^7nœ¿ë®»êëëo¹å–ø5¿ûÝïvîÜ©þ~&Š1âÏþsmmíÉ“'kjjJKK#‘H’NdeeeeeEiÆ êŸß-_¾Ü‹Ïž=û³Ï>KX3dÈÓ§O«ÄWw'%%%‰\wÝu:u²Ò`eeeeõ½é¦›nJø(5vìØÊÊJ/þâ‹/¨É~ýë_—••uîÜÙO<~éXYYYYYq¤þÕù¶mÛ&OžìÅC¡öÕ|+–_|1!Š[YYYYYµRuíÚÕç­””-Å­¬¬¬¬¬¬¬¬¬¬¬¬¾i¿D‹D"êç !.½ôRíof¦§§k×_~ùåÚMQ$´Õ‰öEu"¡ü(žžžž––¦ÆQý¨N$®êGþ°¾”GyLù`ª¿\uìØñŠ+®P€â¦æ{ïÐ|rçY€y@õþhó£þ¢<¨~®P=zܿ΃ì'Ú·Eõå—_ž:uêСCñ¿½yË-·lÛ¶­®®®®®nÓ¦M”Ù ôÑG={¶®®nÛ¶mC‡•ño¼qóæÍ555çÎÛ¾}û 7Ü ã£GÞ¹sg]]]UUÕ’%K¼j´yf̘QUUuêï%¹í‹êDû¢:ï¿ÿþø­?ýôSùÛ§(?Š÷ïßÿã?>{öì™3gÖ¬YÓ£G⼨Nƒ>pãÈŸÅ‹kçù†ò°|ˆ×ý×UWW7»žÕ_äó#<‚üB<ÿüó'Nœ¨¯¯¯®®ž1c†÷smÜÔ¼qïÊæ“;ÏhP=È”Ÿ˜mmýÄ=âús¡Ç¥:vìxðàÁ„\ÂÍb9LÜPG‚âľ-¨_þò—~øááÇã'xûöíååå?ùÉO† vàÀuëÖÉÉØ´iSyyùµ×^Û¯_¿;v¬_¿^ÆwïÞ-Ë0`ÀŽ;6nܘ’’Ò¹sç/¿üòƒ>èÙ³çÏ~ö³cÇŽýú׿–õiótéÒå†8ýæ7¿‰F£ò/èѾÚ:‰}µu !fÏž]YY9yòäxàÈÎΖþ"Püã?þÛßþvõÕWßpà {öìY±báªÓ”âÈŸÜÜ\íœ ßP–Þ.wÝu×¹sç\ו÷ÁT‘Ï„ÿ>úhUUÕÃ?Ü©S§[n¹Å{{75o¬{GäGóÉg4¨ä6?Ñ_”G[?ÑG®?z\jÊ”)íÚµC7‹ë0‘ÅÑ„ 8Ú·å%B¡ÐâÅ‹&øÌ™3ÿöoÿ–’’â8΂ ¾þúëÔÔÔŽ;8p`Ê”)2>þüh4šššš‘‘ñÁŒ7NþèóÏ?ÿí·ß¦¦¦æåå544 >ÜqÇq–.]ºwïÞ”””Gá4iøðáÇÿùÏ …ˆõÚ:Ѿ¨N!Ä‚ ÊËËSSS½P¼_¿~õõõ÷ß¿ÌÿôÓOŸ:uŠð ÕiÊnœðÇqíœh}Cyø „hß¾ýÎ;?ýôÓX,&ïÁþj}&â{öìY¶l™|vÄçÑÆMÍ÷Þ¡üh>¹óŒæ¨GëÊOÌòÍ9ê#ËŸ =îÝÖõë×/X°ÀûœR½YFy´q4!Ää }[>Q©Ú· ;tèе×^+„HMM0`À¡C‡\×=sæÌUW]åºn,BôîÝû믿v]÷èÑ£cÇŽõòôìÙ3º®‡ÇÙ·oŸŒ9r¤K—.Žã <"îm²çÍ›·zõê·ß~;‹ëµu¢}QBˆH$rìØ±)S¦„Ãá 6üå/!|@ñ~ýú9Žóå—_Ê7=tèP‡ú÷ï¿cÇmý¨NS>pã„?n“æDëʃê'|B<óÌ3iiióçÏ6l˜Œì¯ÖgOKKËÊÊZ¼xñÈ‘#ûôéS^^¾iÓ&!Š›š7î½Cù‰ùäγvP=È”?‰hû‹òsŽúËòGRe.ܸìW¿~ý®¿þú™3gzž¨7+€ÃÚ<(Ž&„˜dí¾F&*ñÝ[¤ ‹‹‹wîÜ …ï»ï>91Za„ ?ýéO~øa/>hРçž{.‰tïÞ½   ‹É·ý¼í¶Û–/_îºîücï m”Gª  àꫯÎÏÏ÷–¡õÚ:é}Õ:…ápø†nˆD"iii3gÎ|æ™g^zé¥X,†|ÐÆÛ·o/„ð"]þáˆê'ê4âC€8ò ù†òp}èß¿aaá“O>YSSãÝ4ƒýE>kãáp¸]»vò^õíÛ÷å—_ž5kŠ>pçuïP~b>¹óŒ¤­ùƒò£þ>#ßPYþ\èqù'Ož\^^¾}ûv×Þ¬kóqâÉ k÷52Qú¿Ûû§ú§K.¹D~6‰Dî¸ãïsp!Ä€æÏŸ_RRòÆox§ªªª’h½ÔÔT¹þ½÷Þûä“O^xá…_|ñ7ÞøùÏŸåBÜwß}6lPIêzmô¾jBˆ;wΙ3çÚk¯íÛ·ïúõëüqù=äíRBýÍúÓB‚Õ¯õ ùFçñïüyó¶mÛöûßÿ>~< ö—öYߺuëСC‡ ²páÂéÓ§{ôf72o¨ïÁΫ*Ø«ñcÇŽUVV^yå•òÿÊ@ß}÷Š›š·÷N›Í'Ú—žgU¨äϾ}ûP~mQúy¥í/ËTç…w]7??ݺuß}÷ü't³Ž?Îr8++K›ÅÑÅѾ¨NÖD ¡|îÖ«W¯“'O®\¹2===‰|ðÁGŽ‘ßjå•WNœ8qÇwdfföèÑ£GíÛ·OOO¯¬¬\³fMFFFFFÆG}´oß>ù»X×]w]8BLš4éôéÓóæÍ“¥µyäî ˆÿ~…v=Q§v_¢Î7nܸ±[·n—_~ùÖ­[·oßž’’‚ò£¸ã8Û¶mû裺víÚ«W¯Ï?ÿüÝwß•ùÑy‘?F|àÆ ¤ÔÏñµ¾yX>„B¡”&Mš4Iþv1WÜþ>þ=ztÔ¨Q—\rÉ»ï¾ûÕW_]vÙe(njÞÜ;m~4ŸæY;tßUˆüÄsCÍCø†úÈòçBwíÚµªªjüøñžÄÍb9Œò 8š§oD 'J3ÁŽãÜwß}¬©©©©©9pà@NNŽtíôéÓ®ë644Ô7i„ ŽãdggñÅgÏž­©©Ù»wï˜1cäúâââ³gÏVUU>}º¸¸¸C‡r ”G1uêÔÆÆÆ^½zÅ?†ÐzT'ÚÕyóÍ7Ëxmmí®]»n½õVÇqP~bß믿¾¬¬Læùä“Oäïõ£:ø ~äúȧõÈÀ)ù ïw¦ô—ðÅÓÓÓW¯^][[{æÌ™ƒz4.72oî:¯v>Ì3šTòåGýÕæ!êG}dùs¡ÇgÍšµk×.E§½YÖæAq4!Ú8±oË'ÊMßõnhhðÊ•ßr•¿&{àÀÆÆFù½Õ>ùOr½|#™ƒzëC¡P÷îÝ322¾øâ‹ÚÚZïç«(WŒ÷éõ¨N´/ªÓËÓÐÐðÕW_©ñ„üt¼W¯^õõõ‡ö~OÕê4åC°¸êO|IÚ9Ñú¦æ àƒ·QJJŠñþ"Ÿ‰¸üT´}ûö{öì‰ÿWmÜÔ¼qï_Oî<Óó Â5?1Dµ~ÔÇ`þ\ ñÒÒÒmÛ¶Í;Wû{Ú 7+€Ã(6NO,1É꾦&J#ùQ—Záo=+Iq÷%Ö›Š7SqËÖy’z.Sûyü/&Ö›ª‡Ø7Ùó“Tÿøæ¿³õÉ Nn=­9.¿ý¨]‰tÜ ´/³R+++++++++++++++++++« AÉæ±™ÊOСX|A.—Ž[?—;È­‰Ë·˜¯Æå·q©]I«;#> <ú‚ÄÊÏå´™šŸV(ƒ-°ºHÄâ±yj!u‰Ë{C”&”Ç—Ž[?⨙âÿ¡<\¾ªŸËoÓúCpÑ´ûë¹}árìLù€òpù‹Ü~¡¾kë'öåÖÉz>ø9/¡È—œ8qb÷îÝEEE¬ß×höjXµQ±xlR-§.qyoˆÒ„ò˜âÒqëG5Sü?m.ߎ¨ŸËoÓúCpÑ´ûë¹}árìLù Í€¿ÈêÑwmýhßu²žÍž—V4]¶lÙðáÃo½õÖÙ³g×ÔÔÌš5Ëç¿f¯†UÛ‹Ç& Q—P~.'å1Â¥ãÖOðóŒðÿP.ßÕÏå·ÑþH©Ü;m¿´ë¹} À±3âÊÃå/rû…òÓ\=ußu²žôy=Ýyçê›¶ !¢Ñè‚ ¤ç¡PhÓ¦Mk×®õÆ[}U|„¾VmY©k×®u}óØ„!êÊÏåä¡›¼<ÜüßWSû~_õ)’È“lˆz’:Äú¤æ1%¢N#y.]ÄG³²²²²²²²²²²²²²²²²²²²²²‚2ÂëØ±£ü埛"ŽÊÃåq× &‡ŒË‡ À·ãŠÕG._åAý"æÁˆÏ\¡y0u Àäò#Ñ<³üäž­GüB¢_,Î%·NîœpŸ3ÄóÐȽFûrãþ…àC‘¸ŽömQ§Xü-LêùçŸ?qâ„üä3f$ü:²OÎÊÃåujëár ¹|8â¼ÚüZ>_Žê#—/HÀÏPßµqS>£:QÍ‹w€/ˆÎËT?×O.Ÿùƒø…¨_\Î%·N”ù€æ“;'\n%w>¹q©Ž;úhUUÕÃ?Ü©S§[n¹%ÊåŸó‡ò°8dŽã :Q=\N!—‡â(¿–ÏÇå¨}dñ‰<¨_(nÊgÄADqí±^Ë/$ú¥­­çÖIì‹úÈzΠzp+YóÉ{­_¿~ý‚ ¼Ïáü;€:Käa=á Çо-ïTªü›P?ü-.ìË/¿ÌÊÊZ¼xñÈ‘#ûôéS^^¾iÓ&/›Î_ZZš6—CF¯÷ÏECõsùp7N›_`Οö¼Ü>rù‚(ꊛò™ðGGó@CÝüóç¸\@îœÐóìßO.ŸX¯åýÒÖ‰Ösë$öÕúÀ}Π9 À­dͧ|#ÿq9ýúõ»þúëgΜÀÔYâFhãž„Ú}t*Uøæoqy`‘H¤]»v²Ž¾}û¾üò˳fÍŠÅb,Î_8ÖæárȈõ,.±žË‡Cq”qþ´çåö‘¨ŸÅDýBqâm5¸>#´q4y‡þù‚H¬9ivþ}úÉåóë Ž£¶_„êúA´¯Öîs†¾G,n%k>¹qù'Ož\^^¾}ûvg9@DÑ0ErÕîk¤S!᛿Œ¶uëÖ¡C‡2dáÂ…Ó§OïÓ§ã88jžf·6Åã®gñá´q”qþXçm¶>ù‚tm߉¸Ÿ‘?´oþý ÀŸãr r"Uiëçòùˆõ4¿P{/%¬ÌT÷%úèÿ9C×ÃâV²æ3˜²³³½/1ÓÇqPgQS$Wb¢ZØ©PFFưaÃ>þøãfgÑuÝììì×_½wïÞÕÕÕË–-;wîœBþo‚äoÑÄb±;v466666®X±â?øÁu×]———7f̘/¾øâÑG•﹜““sÛm·É#UTTÌ™3§°°ð•W^yðÁÓÓÓ«««µyêëëµûÊÿPÏ…ê¼ûzTÑõG"‘?üá_ýµ¦x¯RÏ…âDþéÓ§Ï›7¯¾¾¾¶¶öí·ß‡Ãò[Úórû(¥­_»¯B›õ ÅQ|Fþhãh?t=ÈÔw$ÿs‚êçú‰ú(¥ž ù3|øðiÓ¦=ýôÓÓ¦M›:uê /¼ðÔSOuïÞ]¾ Ý $u==·È5òáÔ©S¬ç ]ꣶNÖ|rãBˆÜÜÜÎ;¿þúëò#×ÔY”çž{îa=á‘ch_îGm§B,Žš„]åääL›6­K—. <0¹Æã;v¬²²òÊ+¯”qI ýî»ï<ŽWNNŽü©ãèÑ£ tÍ5×”––6ÌuÝX,æqÔP´¯ 8dh=ª}ä£×K>\~~~<N{.tÞ¬¬,”É’%¹¹¹r£x>Ÿö¼Ü>ÊRëB }µyP¿PÉõ™¨Sß¿?ší¹èz´|AmÑy¹sBÔÏõ“˜‚ç—°>ž+‹Å<~!Ñ/BÚõÜ:µyÇç>g´õÐ}×ÖÉšOTQg~~þºuë¼»Æuu=©PM2Š£}tŠÇQãòÀ^yå•£GŽ5ê’K.y÷Ýw¿úê«Ë.»,Ääü¡<ľBÇCëQ=Èb=‹‡âD~ÄçÓž—ÛGT?±/‘Gí7â3Q§6NÌOÞ¡¾ :/wNèùgùÉåói×üBÔ/4Ÿh=·Nmz®XÏm=¸•¬ù䯻víZUU5~üxoG®¨³(÷ âôDµ°S<þ—–žž¾zõêÚÚÚ3gÎízó Q¿Ph=·Nz_ÕîsÕÃåVr瓟5kÖ®]»´càÓ¢³(г&œØ·årXü­<0ù¡»}ûö{öìQwqüqþPb_í¹ˆõÚzh=—Gœ—ðGåó¡órûÈå ð3ÔwbLùLpµquš…º©sBÌ— èNèyöï'q^í¹èç€Ê/DýBu¢õÜ:é}Uó9CûàŸ[ÉOV¼´´tÛ¶msçÎÕþ>-ËD¦ÔæÑƃM¸v_#âIý~Z³qôO¬õDÜòëM‰{.nžõp׳ü7u^®LÍ©"[ÛüûYú›¼äÂÜœì;wßøÿ+¿ýè¿ ºSOî„·ªmeeeeeeeeeeeeeeeeeeeÕºÄå‡qó˜ÊOС´yÐz7U?—Æ­)Oñá´t+®oÜ}‘¸}áòQ=\PSœ?n~.§ÍÔü´B™ËY]jë÷s^B/9qâÄîÝ»‹ŠŠX¿¯Ñ,XΪŠÅ“j9u åGœ*DiByÐz7U?—Ç­“ËÉCýBõ#¾Ë7./0ߏ|DS>°8ˆÄyYýâò2¹¼=nѼ5{^ZÑhtÙ²eÇ¿õÖ[gÏž]SS3kÖ,ÿüh°œUÛ•~˜”êÊøjˆÒ„ò õÚ¸©úpãXu¢<Áxrjýß‹å›húmcÇ/­çö…ËG4åÊÃåÉqû€—©Ý7@¬ç}^OwÞy§öMð£Ñè‚ ¤ç¡PhÓ¦Mk×®õÆ[}UB„ËYµe¥®]»ÖÕq¤¤Ô¡.¡üˆ¯†èP(Z¯›ª?7ŽU'ÊCpË´ýBõ¼7–o‚É Dë¹}áòMù€òpyrÜ~qy™ˆ[ NÖó>¯¢sçÎápx̘1—^zé'Ÿ|RWWwìØ1uB\×íÖ­[ffæêÕ«]×U_%Ï’‡ËYµi 4è½÷ÞÛ¾}{ee娱cã?{RßU¨ÿþ'NœxðÁóóóÞ«åaåß°aC]]ÝŽ;***jkk=ZǨQ£öïß¿{÷î½{÷îÚµËûùʃÖyŒÔïi„ 555Þ3¸çBqmž±cÇ644äååÉ5 .<{ö¬¬Šè—Z¿|Ÿ¡›o¾Y®‰’x IDATÛ¡¾ ! Nœ8‘™™™`òM»>@_TÿY} 惚‡è :/«_(?Q¿vßu¢>Òõ£\]]=uêÔø¯£Ñè¡C‡>ýôÓ¿þõ¯•••Ÿ}öYFF†öUyyyjºeVmV!÷Ëu qªhî—*´žÈc‹æŸÇ­“ËÉãr¹~Òþøç#ëô…ÅG4僪<9V¿‚ñ2Õ}sïTà !V¬X‘–––žž~ï½÷'¼¹Ô¾}ûV®\YRR²téÒp8\RR’’’¢¾jùòåjžf[VZZº¥I#FŒ°ÛŠäwÏC¡ÐܹsÏœ9ÿëà ŸÓååå;wîå—_~â‰'-ZÔØØ8oÞ¼Ûo¿=þGjÿùEÓ›ÚÉÿž³êDç¥ë'ò!V­Zõæ›o®Y³F~T‹ÿ§h4úꫯ¦¦¦Êö7®¾¾~Ò¤IŽã¨¯JˆÐW^ꡇz¼I½zõ²ùÚˆR‡ ¶eË×u=*Ree¥v©GuB¤¥¥9Ž3zôèãÇ=ztîܹEEE yºtéòì³Ïªq”_±dÉ’5kÖ¼õÖ[®ëzœª!C†¤4Qš\×õ(MÞOÑÔ+Žê¿Å;u꤭3@ý¢‰–›››Àó.Tç×_­Íã6ѧÇq]÷Í7ßLàÉ%ôëÃ?ÔúæÑ­6nÜ(âèV999,ߤ?,^ výÀ‹ŠŠ¸}QýGyP¹> 9M<¹„¾ órû…ò£ú]ÌqdÕ‰D×Oç‘ØØ:Äb±ÆÆÆ„•?»•_îÙ³G~ªç8Žúª„q•¼2^{íµøìOÛŠüóÃB†¨K(¿œª^˜Ò¤ÍƒÖ£¸ÁúYÜ8n(Ä“SëwÝŠë›ÌÆâj×è ‹hÊâ\,ž·_(?ªŸè —{§­‡®ŸÈãIûOÑhtñâÅYYY=zô:tèªU«ª««ãÿ,O}•i¶eVmW,~˜§–P—ˆüZN•ÓJ}ri×yLÕÏâÆ¨“ËÉCýBõkéV|L^ ZÏí —hÊ”‡Ë“ãö‹ËËDû«Óÿó¡ÙóŠF£²§ÕÕÕeeeyyy>ÿž¯Ù–YµY9)))þùaÿ÷²–Q—P~§9¾š££CyÖÓñ–ׯ>|rãXu²8yÚ~Ѿ©t+®o‚É Dë¹}¡ýçΡP¢/„?þû…ò£úѾÁêôÿ|hö¼„z*¿óé? Ý2«6-ùùlòòpó_yLíû}Õcê“Y”'Ùþõ$uˆõIÍcJDFò\JöˆZYYYYYYYYYYYYYYYYYYYYY}Ÿbñɸ\:®>œ¶N.›Ÿ ýêØ±£ü% ŸëMqÝLÁɈúYóƒâh~çA+”‡ÛG´/7‘_['Áí3Â)Dë¹sK¬O*Ç‘ˆ³æ‰Ëqä>?MÕÙòJ’ý„ @ÜÔêïò°ødžøaˆ‹†ÖkãÇ A¶P\7³Ð/õ¼Ï?ÿü‰'äofϘ1CþZ6—·‡Ö³ø„Ï(ªŸË·Cq4?ÈSó€úE̿֔‡Ø—5Ü:‘o¦8…\^ wΓÍEqÖÜx^™âzrï—TÇŽ<8qâÄøá÷ù$çFµëiR£öF°ˆ›D~5`ñɤT~⢡õÚ8ÁñB-T'—ÇÆÍOC¿Ôó>úè£UUU?üp§Nn¹åNÆåí!΋ÿGøŒò ú¹|;×Îჩy@ýBy(Ú—5Ü: ßLq ¹¼@îœ'›Šâ¬¹ ð¼2ÅõäÞ/©)S¦TTTÄÿ!¿ÿ'9—0ª]O8†n‹¸IäWóˆ‡O&tü-‚K§]OÄ&%p¼´-Tg. +?ZOœkÏž=Ë–-“3ÿ Ö\Þâüàj}FyPýZ?‘o(Žæ‡ðÁÔhó . w¸uF"­o9…Úõܹ¥¹€Ú{Êò™0·¬ç:—ë¬Î~ýú]ýõ3gÎ$&ß a­×:†nD0⦚_›Gó=tùV“Þû8È\?üá…ýû÷/,,|òÉ'kjjâûç½Éì„ ~úÓŸ>üðÃòåh=ŠK\}õÕùùù^ÚÂÂÂâââ;wÊ·¸ï¾ûb±Qgccã Aƒž{î¹H$Ò½{÷‚‚õmMâÅͯ]·۵kWPP '²oß¾/¿üò¬Y³$Hó†nˆD"iii3gÎ|æ™g^zé¥ýû÷»®{Ûm·-_¾ÜuÝÿøÇÞ7(´ëQžX,†êD>kóõkÍD¾ÑýRç‡ðÁÔsãæVÊçóŠ8z~j} VçäÉ“ËËË·oß.ãÜ'9÷ ƒÖk#nª‡ždµ#j_oç‰æo©\4´žËñâòù“ÇfŠÿGœkëÖ­C‡2dÈÂ… §OŸÞ§OÇq¸¼=Äù Æ5T}FyPýt ¸J˜ÂSó€_¨õ!·ÒÿwîÜ#<"Otã7644HÀ˜¬P–Ñ,oO`>Ÿ6Nóä´¼4mžôôtT¿ÖOäÝ/-WO냩y@ýš8q¢6òžgu_ÂO­ÿÜ:‰ùaÝ ÚOu=ê1·Dj~³|P5lný?¯Ð¹¤üs=Ô™››{üøqï¸OrT ñ„A×:F?a¸ÄMD‚LÈ£ù Âã{Éÿëñ½<þVNNŽü¹ôèÑ£ $ë“\´üü|‹†ÖgeeyTŽW˜šÔ/”ù€æüšk®ÑîKø©õåGu¢ù8p ë^ÐýÒŠ;·h½V\Ÿ¹qä'íƒÿçýeŸvþµ¾¨3??ݺuÞå>ÉQ%Äu\ëý„Që¡'‘ 5çòÉ' aþ––‹†Öy„Žã… [¨N.›­§ý9zôè¨Q£.¹ä’wß}÷«¯¾ºì²Ë“·G¬À5ÔòÒP~T?k~PÍòÁÔ< ~Ñuª> <4GÐÿ<¨Së›)N!Z`n . šŸë37`nYÏ+Â7ד[g×®]«ªªÆïUÈ}’xÂ Ž£'ºˆ›(B}'¾—T qÑÐz"®r¼ ÙBu²xlÜüÄzt®ôôôÕ«W×ÖÖž9sæàÁƒwÝu—Œsy{h}®¡–—†ò£úµ~}Aq4?ZŒÏƒÚ/”‡öA̓öåηN4?F8…ÄzîÜÒ\ÉäñAQœ;·‚ù¼Bçbq=¹uΚ5k×®]ZU'FéIÖ>yÐ@ÜÔæWó8‚Ã'‹_ÇßRmUAk) oL—Åh9mˆ‡8j¸€¬üôK=—ü©}ûö{öì ÌÛC뛫uÒ>'äAõÓ~"ßÔ8šŸf}02j¿ˆù'|@y´û²æ['í[Ë9…h=wnÑz”Ÿës°¸ÿ¹Ìç:šú^û¬³´´tÛ¶msçÎÕþ~©Ï'9÷ CL²Ö1n]2(úÀ¯WÂç›ß»ägÚ8k}+Ìod_nÜTDV<@žd÷ËTžd÷‹7’?@=¬~qeÊgƒskäh-¬S~üåeЕ$õÉcj½•••••••••••••••••••ÕE+._MKE ÀÓŠË]LŽZOP©Xþ˜¢I¡õ(¿)n!#\1¢Ö¼qý†8‚¦Ä­Ý/.ßÍ —cgeu‹ÅåB\+Ì ‡OË»"òsùX\n‹&%0õ ­'8ˆ*ÝŠðÛ®ož|ò¹óÆõßG¦‹©ç%úË­ݯ|;-űC><òÈ#ÍúCèÀò%'NœØ½{wQQ‘ÿßËðÓ+«¿‹Ë¥¥"qy`9|ZÞ‘ŸËÇârËX4)©Wh=ʯ¥[>pûÂõMÊ?‘ËÕãúo„#HÔ¯=/Ñ_Vè~àÛ! ‹c‡|hÖZÑhtÙ²eÇ¿õÖ[gÏž]SS3kÖ,ŸüZ¸µU[TÈ7— Q‘‚ñÀ¤ZÂáM5¢r¼P~íz‚J¥]ÏåÌ>h)Vh=Q'ÁÏS}Юo‚Ã_äÎ×nðØÐyµýåÖ‰îW¾vN¸;zN?žî¼óNí›SG£Ñ HOB¡Ð¦M›Ö®]ë}"¥¾*!âgk++O<>Ÿ–Š„8[\Š’às×Ü&%œ å×®'¨TÚõD=\š”–b…Ö£:i~žêC€¾p}þ"wÞ¸þsû€Ç†Î«í/wÞÐýâòíМp9vôœ „;w‡ÃcÆŒ¹ôÒK?ù䓺ººcÇŽ‰¿—,»[·n™™™«W¯v]W}•Ä9%ä¡·¶²Jϧ¥"浜ÃGKÍ„(PZq9s„ˆbEpÅÔüÍòó´´*V_¸¾±ø‹Üy à?«xlè¼Dý׉î—oGSÐX|;ä¿ýöÛ‹‹‹OŸ>‹ÅvïÞýÔSO-Z´(>áøñã,ß…ä›o¾™3gN,S_uòäÉE‹ióø]«6.ö7T*R`˜)®¢4!i)PäŸ&EP¬ß´ù º•Ö‡t+ÿçåò ਙê#’Z?:/M)óY'º_øvÏIŽê#НX±";;;---==ýÞ{ï-..Nøx¿oß¾•+W–””,]º4—””¤¤¤¨¯Z¾|9ÊCŒViié–&1¢%«‹D,.—££"à™âð©õ£üè¼RˆÅõ‡E“’¹ b…|SóÓt+äƒÿ¾p}£é_j~î¼óß¹<6â¼Dý×)ðýbñíè9AóÀb~„«V­zóÍ7׬Y#?ªÅÿS4}õÕWSSSåvãÆ«¯¯—å©¯Òæ¡·~衇oR¯^½ìG¾6.ŸàÞ൜ÃG:(MHZ*•V\ÎზbEû¦æ§éVªÁèVþ}£é_j~î¼ÑóÐò>rylÄy J™ÿ:æÞ±øvhNÐ< Ž|9šz~f̘ñØcMŸ>ý‰'žP¿!)7’Ú³gã8:urG}•6½õk¯½öR“***’ñÍ« L>¹\)¬å>T?ÊO¬GT*–?(ზbEsÝ´uü<Õ‡t+–o!&‘;o\ÿ¹}¤çM­Ÿ8/Á;ô_§À;ßÍ —cGÏ 1?ž´ÿF/^œ••Õ£G¡C‡®ZµJ~?'t?[[YýŸüs¹)̇կÍO¬§ù‚þýáҤŠ­Gù nœÖ.Ý*˜o‘ð“ËQ3ÕG-^ çEýåÖ‰î—o‡æ„˱#| ý!F¥'ÕÕÕeeeyyy¬¿L¼µU”#ø|5•ŠâóÀ´%‡É]‹O•ÀñÒæGë ­GõpiRI½R×u"ná³ÿ¾óM(ô/ºÿóÆõŸÛGbÞÔó¢þrëD÷ ÅQArýsìh%x"¿óÉJxk+«¿ú¦ã8Úâ®'öeåÿ¾Ä­‡8+ÎÍoj}²ejÞ îk*¿‘T¦êLöZYYYYYYYYYYYYYYYYYYYYYY?<9#|2ÄãrÅq׳„êDç"øg,?§Ð”P~.‘[§©¾s¹}¨/Dý¨?˳Dù¹óÆz L͹`ž×à½02o¦tÎÛòÌI}2›"}ú’–†¸ež|r×౸b¸q¬: ®ª ÅY~ !§ÐÔ¹P~.­G\:S}çrûP_Pýh®¸ü<.Ï’ËÕCqä?—HÌ¡ÿ9vYýB÷íËåer}Fu²ÎKøIïÛ±cǃNœ8‘x° ÐYîj @ÊTãBË CÜ2)ÿÜ5-ŒË ÀcÕ‰âDˆs†â,?…ˆShä\æ rùˆh½–Kg°ï\nê ªÍ‹Ÿ'ø¢ã8(Ç¥›={öÈ‘#Íö]rãÖ®]+_Ò³9nê áQGçBur}àÎòÅ%/P} Ì9ëþè—÷ù€ú«]úÈõÕl>µ~ûöë×ïúë¯÷p"¬›K8Æê,ÊOL ê,Ú­‡ñ &ÔÔÔÈo•Êw`Jx¯zùÁ³ÿþ'NœxðÁóóóÞ•JQPPpâĉÌÌLù¯¸âІ††Ï?ÿ¼¼¼¼¬¬¬¶¶ö¹çž …BcÇŽmhhÈËË“¯]¸páÙ³gÞ«IûÝË„üÄzV(ŽêDçBñ~Ž5jÿþý»wïÞ»wï®]»âþÚòsùµq¢~”gÆ uuu;v쨨¨¨­­•t³}4hÐ{ï½·}ûöÊÊʱcÇu^yå•Ú¾>Ðõ$Äés©ur}àÎòŸˆ{Š Ì9=Ÿ>ÏKô Ý ú¼j‰õjø¬­3Ày‘ŸDý/¼ð¦M›¼Ã²nn³7Âÿ“™;Ü'Z¯ÆC‚Ã3 À]Sy`ï¿ÿ~®ÊoªN5NóÏçL¨q œ‹ÈÏå#¢õZ.]0ž:—Û§í—$—Oi–«§#. —HøÃšs)—‘Õ¯`|DU\^&×gâþ˜OÕO¢þìììø/ŒX7·Ùfùï,w¹O<´^W9aˆOÆå®<0WLÊ?7Ž['‘_[':W8ÖÆ'NœÈòsĈZN¡©s!"—ˆê˜;h°ïŽonêQ?Q6ÎåSáê¡yóvTýGq¡{ y@õ 9§çÓÿyÜ â¼Ú>ëµ}dùŒêD}¤çSë'ª'77÷øñãÞ0 ÎÒhcu–ÎßrÒ'ZÏ=÷¨ñÊ C|2.wàÆ±¸bRþ¹qÜ:‰üÚ:ѹPœë'âfee9ÊÏå#öìÙS»ÞÁ\:#}G<9T'ê :o€/û¸|J#\=â~!ÿY¼@äÏñãÇYsî®!÷¼îq^­¸¼L–Ïè¾#?éùÔú‰êÉÏÏ_·nÇì$2scu–¨P˜ }¢õÚ *'Ì|²“»&07ŽËCùµëÔ‰â¨Nt.mœë'âš:Êâ¨~´^`.‘¾ãö©}!ê'êÑÆ¹|J#\="Žügñ XsNϧÿó¸è¼h_./“å3Qg€ùÔú©Ý·k×®UUUãÇoö À1ngYÈ}â¡õÚ¸puœ0š‡'|s׌ËCù‰õ¬:QՉ΅â,?Ì)4r.”ŸØW[?±qéLõËíÓö¥YŸýäãò)MqõPùÏå"Ì9ëþë—ðÍGDûry™\ŸQΫõS»ï¬Y³víÚ•ð§Ü›‹ãv6±RuŒÞW»>1žpŒxžâá ßÜ5x`!>W åGë¹ujãDÚs¡8×Op M å§ãˆcGäIàÒ™ê»ÃäöÑ}A>£¹Rãè\¨Î>˜7Ä}ôÏ $üáÎ9÷þè—À÷(á¼h_Ú7._í«Öà¼ô½Žß·´´tÛ¶msçÎ3îÍ%:Åê,w Lj}µëâêKþnõϾ%?I^þd ÕIœËÈyQS2U²}@JvêáîËÍÏõÙÈy[aÔojßïËgŸyä·û’º#WÉÎoeeeeeeeeeeeeeeeeeeeÕ¶dŠÏgŠ#Åå~q¹Y\ T²ù…\ž‘'©ü0®oN+®\ÿô‘E#ø|¬:¹æÀ!:­h4ºlÙ²áÇßzë­³gÏ®©©™5k–ÿ^hT¬¬ôbñùœ&ù佡õˆÅâ~Ü,¡£4q)Ph½)~až—ƪǔoN»žë×ÿ}t8ÜGt^nx~Ú{‡ò}DóÆ½¿hÞâuçwjߤ;.X°@Ö …6mÚ´víZolÔW%DЬ¬´âñùÜ&ù佡õZJ—û%q!Zn–Ðј¸(´Þ¿0OŽËcÕcÊ7‚?§]Ïõë€>ºî#:/·ÎHX®ê[,ãú€úbÄ·ýû÷»®{Ûm·-_¾ÜuÝÿøÇÞ› j×s}à?·H¬ó«Sí#á'ºwh´> {çUîóþÆb1zÞn¿ýöâââÓ§OÇb±Ý»w?õÔS‹-ŠPŒ?~ðàÁò]`¾ùæ›9sæÄb1õU'Ož\´hQ|dݺuô¬¬ÄãóIù罡õ¥‰ËýÒr³hª—•T~!‹»Ìÿt+äƒv=ÁŸ£óûôXlª¬üx{D,žqï~¡ÖÄÿœûKû¿bÅŠììì´´´ôôô{ï½·¸¸8á#Ó¾}ûV®\YRR²téÒp8\RR’’’¢¾jùòåÚ<Ä„¥¥¥[š4bÄûíÐ6®P$ùÃþðõ×_Ϙ1C¾ÁÚ¹sçÔuuuuò?222† öñÇ{Ã=|øðiÓ¦=ýôÓÓ¦M›:uê /¼ðÔSOuïÞ­BLŸ>}Þ¼yõõõµµµo¿ýv8îÝ»wuuu,Û±cGcccccãŠ+~ðƒ\wÝuõõõD=sæÌ),,|å•W|ðÁôôô¼¼¼1cÆ|ñÅ>ú¨|GÔœœœÛn»Mκz^îzäÏÝwßMäQ}@yªªª´> ßd~®j=¦|Bdgg¿þúë²§Ë–-“'EëQ‘h=í?wÎUqÏlNÔ>º®«ÍOß;5Œ«> {'×û¿¿ôü!\×1cÆ;ï¼ó§?ýiÒ¤Iª9û÷ïÿõ¯ýÒK/=ýôÓ=ôÐ7Þ˜——'„Hx•š‡>‚Ô;ï¼óÿ5éÈ‘#¨ËVmD©’Š”››«òù6nÜ(|p¶zÅÑž\×õhOò§ˆ#µfÍš·ÞzËu]Ò„¸\‡ÖÖ3`À€¢¢¢¢¢¢-[¶ÈŸHn–GcB¤¥¥9Ž3zôèãÇøá‡®ëªçõ¨N>×#n¿ýv"êÊsöìY‚»¦ú6pàÀgŸ}–ëA·j¹o’?'`öæ›oJþZÿÁ°|@ó@ûÏsUÜórçäèÑ£sçÎUûXYY©Íî]§N´óPYY)š(hñ>œ?í}GsHÏ|¡üpÛ¡Cù-ú‡]וÄ8!Äž={ÇéÔ©“ã8ê«"ô¤^{íµø‚}ÑouñÈ?ŸO®÷Ï{CëIiòÏýBܬÉÁbQ ´ëQ=D­„Ï,îZ´õôMËŸCë¹>ðŸÕGoJýsµçåÖUÌ3 IDATÉåù¡{GäÑú@ÌëþÒó/íw£ÑèâÅ‹³²²zôè1tèÐU«VÉÏêâï ‘‡8‚••F.“ÏçŸ÷†Ö Liâr¿7ËS¥‰KBëMñ Y<9Â7®¨S¾Ñü9u=×®ÿÁúèŸûˆÎË­“Åó#îʃ|@>£9áòçü(666ÊÚª««ËÊÊòòòüÿ=q++Ul>Í…rZÀ‘’ÿ”Âá~9€›¿QJ¥‰K¢¹eZ´yhðä|òøõ˜ò-DòçÔõÁ|ðï°>jid¬órëD}¤ó#Êšš‡è£ÖgÁ¿¿ÚsùQBm.þÃ$t++ž¸Ÿ49ŽÃz ZOÄìkJ¦6åž‹ÿ¾`~Pœ5\‡>ró™S÷ÑÔúó VX’•••••••••••••••••••••UÒ¥åq¹bàX¬} N›).«S<Â|8T'‹ëÆíâºðŽ3ÅADçEþpù‚‚Ù$nh_Sý2u¯“=o„Ï, ò>µûšznø—lŠ*ä>I¸yL=I|‘Dµ2.ŸO0ù^ˆÆå´i9døsÜz¸£}MqÑy‘?\¾ «/ëDûrûÅâe¸×Éž74ÿ\Lñ>Ѿ9¦BˆŽ;I¸y¸Îp;«vPh9d\>—ï…øg\N›–C€?Ç­‡Ë#Dûrùp(Îåºqùˆë†øp\ŸÑ¾¦8ˆÚó"ðY}1U'±/·_,^f€{ìyC£}MqÑy‘?\¾ ·/¦êDûè‹—ɽ×Éž7Úgÿþä}"LqL¥Ö¯_¿`ÁÏy5C²©¶ÂOn®3ÜÉW;˜ªþ¹(âŠíرÃ[Ïë’p¬Å‹9²OŸ>ååå›6m’Ë´ëE÷ËϾ_~ù¥6¿äyõ÷ŒãÒ¡}E?lþüùò ½:ý׳cÇ‚Gè_Úgí[ jãȇx®›Âãºýò¸kápXDßNþe±"žÏ‡|`ùŒö¥ýAùUÿÑy‘?(Î=w>¹u¢}ôKë¿©{ìy£}öï‘GÛw¢N4çÜç†Ö©~ýú]ýõ3gÎ$27T[a€' +Og¸“¯vPóÎL\>_¾—VxuˆC†ö¥ùaþ}àòY\:º*­X\7¢_ÿOn”ÀçC>°|€÷fŠƒˆÎ‹üáò¹}1U'½¯üŸýbñ2¹÷ú<Ìí³Lñ>‘ŒpLåK&Ož\^^¾}ûöøz|@‰“j+ ð$aå à ·³jý¾-^¼´œ9ß+€P~‚CÆåÏù—Ghj_B,®›àóÿ„Žë†|àž—ÞWU¢zÞ÷ß_ëY¾ k>Yu6+ÿýbñ2ƒÝë¤Îí³PSÜGƒÓìììøo)¡ „´'ÕVàIÂÍÃu†–_kÂ;óN˜0¡¡¡áæ›o–{Ë7Ÿµþ ßœ‹5Ÿê$öõß/ä¿©{ìy£}öïÊC÷åQ÷¥ë×ú‰üÉÍÍ=~üx¨è'¹zR¢BÖ“„xBjóp†ÕYm5ŸY{\1ù›åóà{i…öEùXZZ:lØ0ù]C†öõøa999ò§¬£G4húôÕÓ³gÏ”&.Z,ó¸h2ÿ}÷ïßOøì_„’ë–““3mÚ´.]ºH®ѯ%K–äææÊƒxÜ5Yäºåçç{\·x>\¼ЧÏh_äÝGÖ|jýAqîüpç3@„ü÷Ëq­ÿ¦îu²çíšk®!|öïê=Ïj$Âä'ò'??ݺu B‚*ÿo<ÙT{R¢BÖ“„›'€3¬Îjo®ÊGN‡Éç|¾—”ÿ}µù ™vßPsü0Ÿõ .w_Úgµçr݈~ÜD•ë†|àúŒöEþÐùYó‰üañôÅTÈOV¿è¾·ü^'{ÞhŸýûcŠ÷‰öå>7?]»v­ªª?~|‚óþ  è¤D…¬' 7OgXÕvPÿzŸOp,‚ç_”ŸàÒ±øs¬z>팧ÆY\7ÂOÄ]C\7–Ïh_SDt^ä—/Èí‹©:ѾÜ~qy™¨~TO²çæSú÷Ç,ïSýLÚÇtÖ¬Y»víR ,¨ö¤D…¬' 7Oà'ªÿÎj:(t2‡ÉçL¾Wü?ùÜW›ßÁ\:b_øaþëq˜‘?„oÎÅšOVh_n¿ÿ¨¢~m=(©y#|à)Þ'1ç>ŸZJKK·mÛ6wî\íø$€¢“¢ ?I|æ öDõßYµƒ‚úÕ%-ùÑžõÖ¾(¿©}MÕc*€<ÈîzVI}`ÕŸìüÉÞ—»þ<øÔû•ìyKv¦ÔÂóÊoÀrwdU’ì'I²Ÿ¨VVVVVVVVVVVVVVVVVVVVmK7‹ÅQ#èJF8U\¾·.ÅÊGÐMêïeÄOâ\¬óšâr}#8mÚz¸¼7Sõsï—×xþyoVV¼´t%-ýˆ %!‹S_U Õ‰ÖsëáR¬Œp¦I!.×O”ÕÃ=¯A~!Ë7t^T—÷fp>ýß/¢~S¼7¢þfuàÀ™êĉ»wï.**býžš³²:ßÒÒ•´ô#‚–„¸Y,N•÷¯* Q Ðzn=\ЕޠÀ4)Äåâú‰ò z¸ç5Å/äú†Î‹êáòÞLÍ'ŠsçÐï ÕïGÑhtÙ²eÇ¿õÖ[gÏž]SS3kÖ,ÿühÔœ•Õùâo…N*–DЕ´y¸\7DBëYõp)V¦8‚M q¹¸~jó z¸ç5È/äòµùQ=xu¦æ“àÛùŸÃ}G>£úãuçwjß;.X°@î …6mÚ´víZïõU 5geuž•ZVV¦åoI%¬ö" ´$‚®¤ÍÃâº(ízn=\Š•)Ž A“B\.®ŸÚ<¨Gç•vÚr~!ê/ÁKÓæ'úÈåÕ™OšoÇšCnßÑ=E÷EªsçÎápx̘1—^zé'Ÿ|RWWwìØ±„5²Œnݺeff®^½Úu]õU?”‡@ÍYY}úüóÏËËËËÊÊjkkŸ{î¹ù~€R'NœðÞK[1jÔ¨ýû÷ïÞ½{ïÞ½»víJøùš­ïß¿ÿ‰'|ðÁüü|ï]‚®¸âІ†mÚõÜzäûÙ$¼£yüâÞ{ï½íÛ·WVVŽ;Öq´þÊ+¯DujóÄ[:a„ššï‡16l¨««Û±cGEEEmmm½Å¿ŸDTÿó¾Ñþ'ÌÑ_T§6?ÝG­Ï¨N#óIŸ‹;‡¬¾k}&î‹ÔÝwß]]]}äȑÇWWWO:5¾Úh4zèСO?ýô¯ýkeeågŸ}–‘‘¡}U^^žš‡i+«ó¬ÁßBRiI4]IU®›¶N´ž[!.÷+GP¥Iqyu¸k¨žœ3ÿõH±øŽþ)bÍVåŸ÷fj>‰¸™åD®X±";;;---==ýÞ{ï-..Nx¬}ûö­\¹²¤¤déÒ¥áp¸¤¤$%%E}ÕòåËÕ<ÍŽtiié–&1Â~;Ô*¹Bü-¾æSiI4]IÍÃ庅Ãa-êž{îÑ®§ùyj=\Š•YŽ –ï%WÊÿNà–ù÷“΃êñ^SüB®oè¼týóÞLÍ'Š£>Òõ³ú®õ¹Y¾ bÕªUo¾ùæš5käGµø‹F_}õÕÔÔTÙŽqãÆÕ××Ë㨯R#ôH !zè¡Ç›Ô«W/û‘Ï*©JEü-$•–Ô+Ž®äº®GWò~š’ ´Þã` !ÒÒÒÇ=zôñãÇ?üðCÄçÓ®?rä«bµqãFñ÷«¢¢¢¢¢¢-[¶¸®ëQ¬£<¦æ“æÛùŸÃ}×úìQÊÔú½53fÌhhhèСC,SßÕWþ¬T~!¸gÏÇq:uêä8Žú*5ÒìH¿öÚkñ¡S[Y™âo ð5ŸJK¢éJj´>Dr°Ô:Ñzn=“b…Ö£: ~â{!nËO”ÕÃ=/ŠÓþûçÒq)bt_üóÞLÍ'gÍa€¾k}&êOöë­h4ºxñ⬬¬=z :tÕªUò³¨ø_X%òÐ#meu¾…ø[|äSiINsœ6§J*áÇû'L]Ï­G0)VÄz.GѤ·Œë'ʃêáž×¿å‘ÕÉ⽜OznY\Lî= À§¤F¥‡ÕÕÕeeeyyyþK…i+«ó,ñ·àl(ÄiSóÐë…ŽFÔ©®V—b¥®Gu¢<ÍrÈT^ËO”‡>—ÿóÒqm‹å}^µžÿ¿½3Ž­²¼þøûÞ–dŒt.ÌVp*0cB *¢?ˆ¦ÓA˜¤V̺*üctÓh–¸lØh5˜ ʃR\Yf˜›”0ˆ(ÉA­A™ ( ¹ƒÐÆ6¤…Xîûûãïïî}Î÷ÜçûðÖêx¾éáÜóœsžó<÷öÞö~¼yu—?ŸÔùRæŠÚw¥Ï(ÿŠÊôмóéþp}¤ƒ‚FAæuî·ç;èOÅñð•zs´£u©|F:ϼÖýâ¸;{ÄE}R ú~ñ½nœÈ ûéOšK>,‡/Gn%T/ËCü9¶.$´®²_âþ¢|Øø¨^$ÔO–/ñ|;ÊŸµVþH,GЃ+ÉŠÊŸåG"¡º<ø‹¢ØýÊ¥ÏTd–ˆÉÞ¨9%Ù ùÿuEâ™!NX}}ýÁƒ/\¸ÐßßßÑÑaæLá„)°.›gæÁuCñ)žÙïÿ{´®X¯Ò7Ä{Cü9¶®TŽœB”?Ú_”Õ‹êBýdù‚,×õgí£•?uî”8â¾°\@Å_™CqÎY~$;o¨?¢=GŽ)Ëï47nܱcÇ/^¬t’=Yì„S7pÅŠìg ²v]‘È!C<3‘6~üøãÇ¿õÖ[“'O~àΞ=ûòË/ …†`]"Ï̃ë†âS<3dGõ*}C¼7ÄŸcë2rä*ù#ʇêEu¡~²|A–kÈú³öÑÊŸ:wJq_X. âÖEsÎò#Ùy£ø‹9rLY~§Ñã?~âÄ óld–ˆÉ’AY´ã,AÖ®+²ù^ Ï,–8aMMMæû ̯,oÚ´éóÏ?7õÄ—”á„!X—Â3㠟噉vT/ËSøsl]Ã)Ô÷ËÞ_%*¾R¯Xê'ËTêÊ‹+IÙG1sgÇÑïñ¡ùTΘ¿ǃIÍ›Òö¾¢ö˃ßi´{÷îuëÖ)dO–Çä³70{³¡ ;/×eó½nœÈ «­­ãøÈ‘#Æ~êÔ© &˜ü'L„ué<3;Žâ``,ÏL´£z•¾‰ë"þœG]Ã)Ô÷ËÞ_%*¾ÂÛëBýdù‚¨.}(Ê>Šù{œ;;Ž~?G. rîÄüÅ8üHjÞüø‹b]Ô~yð;M7î¼óÎeË–yDf‰˜Š½Ù› MˆØy±®Há{EÏÌ(ó-JóçÏnjj2>mmmƒƒƒåÏÃ6'L„uU䙹sÝ Œå™‰öŠõÚ}SÖµùsuQœÂŠùgöWÉÇ#¾ÈÛ«o³çÐ/ˆêª8îþ¬}´ò÷;wˆÓ)îKÄsѹ³×ãxð#©yóæ/^>ÇõYÉõêÕ{÷îÍ¡vЈ©ØÙ˜½ÙôºÄ‰ÊÔUPø^6ÏLÔÎ;÷ìÙ³zõê—^zióæÍ=ôPæéÓæ„)°.…gæÎuCñ=¸q¶½b½î¸óð¨º(NaÅüE‰ùxÄëÕámâæÂÌ‹+ÉÚG+¿s‡„î– ˆÎ-=Ž»<æÍƒ¿xùS”’ÿ¢E‹ÊÔf#G$“%ƒ²þ~;.NT¦®ñ½Dnœ‘ýLûãÿø…^èîî^¿~ýÚµkûûûÓµ9a€uéœ6Šë&Æg¹qŠ]©×gþ5Í6åϱu!îšR¯’¿½¿(¿øv½h̾£9ã(v»®¼¸’¬}´òG}ÖÏGÙ– ˆÎ½.гxñbŠ‰Îš7Ô¿xùS¥Ï(ÿÆÆÆÞÞ^û¨´'ÐcÂÙ˜ºÙôÉD•©«`ø^¥R)å{™¸†gÖÜÜ\ÎCúú믗/_ÞÐÐðä“ON˜0áÔ©SéS´Í ‹¢¨£££±±Ñ,”ºtž™;× ÅŸªÕ…úÉòźôyp÷gíJž#š¿Òg–#¨Ü,PñW~/#‡âGzÌ›ñò9¦J>bþ---‡Ûå™"b*±70u³é"N”PWUU•Í÷²Ûg£¿Ê9a…Báºë®»æšk>ýôÓóçÏ—¾jœÏφuUž™ù£ø©=v晉vT/êZ7ü9¶®òÆV9p •ý÷·b>ŽñQ½¨.½Ÿî|AT—2”¿Ÿ}ów?wbå~@ç(M ê¿¹€Š¿8‡bœØ—é8oJ¨ûŠÝ¯Š÷IyþÝÝÝûöí[±b…ýë-ld–ˆÉ’AÝýÑŽ£ºôΗ×õkæ ÖOl´.›çûRï·Ð÷ ù ø£µïlœ¼Ö­ýeýó:£%eÞý{1oŽqÌÛƒ—ÖŽ<êö¼ô}Ÿð                    YˆÆÄòÕXŽË¥c9[(…—&Æ÷àr‰Ô(¶Ïl–¶ÅrÈP>l?óâ8²ó†üÙ9gç‰åɱ|¸µµÕï÷5<–ºeÓ˜<øj,¯‹åÒ!ΖQ†Þ¤äèP(>ÅåŠ0 K¬×ƒ“Gõßß­‹ê§R/KçBùSþs.ÖÅòã8fyrÏåGzœ¶ÿ.*‹¯½öÚœ9sæÍ›÷ÜsÏ µ´´°O~~K]‰²iL,_åu±\:…³Iô&…?'Ò¡”ø\®‚EBõ²œ<¶ÿûEÕÅöS©—¢s)ùSþìœ+s"Î9²³<9–çÇò#ÙóÂö?sáÜÿýâ—¤‹ÅuëÖ™˜…BaïÞ½;vìHŸPíGÙ–ŠK¥ªÞ±cG†ÆÄòÕX^Ë¥Cü­$IbÓ›þœH‡Bñ?îÁå2*o1ª—åä±ýgýÙºØ~ÖÕÕ¡z):—2o”?;çúÚsŽæßƒ'GñüX~${^Øþ§?~|mmí}÷ÝwÕUWíÙ³çÂ… gÏžÍø˜Ú¯½öÚn¸aÛ¶mI’Ø2ŒL;޲tPPFÕ·Ür˪U«êêꮻK—–J¥£G&Iò‹_übëÖ­I’üä'?I¿\îâÅ‹3gÎÌø»qxðÁï¹çžßþö·åß#°téÒŸÿüçÍÍÍ©›§¶¶v̘1K—.5Ó?uêÔW^y¥¥¥Å|U]М±þð‡QÝ|óÍO<ñÄÿøÇ¡¡¡ôì)ù?ñÄííí4ä¿dÉ’R©„â×ÕÕ‰ù <2ˆX¯’'Gé?åïQÕO¥ÞÚÚڻ®®®¦¦fÙ²eË—/_³fM©T÷W©—ògç\™C#{ÎE;Š£ÄWö‘š+¶âþzôßèÞ{ïmoo?wî\©T:|øðŸþô§ 6”O×Â… o½õVó­+_}õÕóÏ?_*•ìG}ýõ×6lÈÄ™:uª²tPPF›ÆäÁW3rçu)qlÞ•’½HoRò÷àcyp¹D±}v“þűCþT]T?•zýè\vþ”¿÷œ#9òýäÎócù‘Þç…íÿ믿¾hÑ¢ššš«¯¾ú‘Giooϼ¨:räÈ›o¾ÙÙÙ¹iÓ¦ÚÚÚÎÎΪª*ûQ[·nµãT¹uww÷\ÒܹsÃ{¡Wºb‰ÆòÕ"†×…â âo)ô&1D“B/?.W¾G•í3Gé¿»?Ëicû‰ö%ò¢sÙù³þìœ+u)snÛQ=>ÚGv®Üû óäØþuuumÙ²eûöíæY­¼QÅbqýúõÕÕÕ¦œ |óÍ7füìGe,.K?öØc¸¤)S¦„g¾+\Õ³gÏîééI’$¥19sÆðÕâ8N’dË–-)_­µµµµµÕö.Ñž+òºPœcÇŽ‰¼«“'OFQ4iÒ¤wß}7*ãlÝ{fÞEQMMMÇõõõ½½½o¿ý¶˜ÿ”2šT’$)*å{eâzp¹l)}óôˆ#öŸõgëbû™$ ª·££cûöío¼ñF’$6ËÞß$IìüYÿègÑqΕºÄ97²í)7.Ǽ…hÛ§M›&æ3a„•+W²såÞ´¿æS=¶ÿÆçé§Ÿ;vl©Tʼ'E‘ùìÐü øÙgŸ™—JqÛÊX\–~õÕWË ïˆ^éy`,_âu±\ºp¶ ˜Þ$æèP(>ÊG±ÙLsT/ÅÉcûï±_T]ýDõ²t.1ÖŸs¥.qΑÅAvžÅdÏ‹Gÿ3Þ*‹7nœ4iÒõ×_?kÖ¬®®®ô/ÅG¥÷¥ƒ‚þ#‘ÆòÕX^Ë¥Cœ­Tz“˜ŒéP(¾—+’Þ¥Dõ²œ<¶ÿ¬?U—G?Q½,KçGºû³s®Ì!Åwdyr,ÏåG²ç…í¿‹ŠÅâÅ‹MÌýû÷755yü1»ÇÒAW âªª*›ÆT ùj,¯ ʼnTœÍÙ*XNoÒóGt(1>ËåŠ0ͽÏl–¶åÁ!SòqïgÅ}q¤séüHwvΕ9çÙQÝîÎóCuùõåwÚýwQ&¦yçÓã=I¥ƒ®PÅq,¾>B/šŽëRù(ñÙuY*¥ëÊeÝ‘öWú™Ëºy)¯9Éq]6ŸQ9/AAAAAAAAAAAAAAAAAAAAAAAß ‰Üµ‘V^|5Ä‹@]ˆ?ÇrÚX®Ë]c…êEýdùm¬ØøyÙŽ ʼnDby„,÷Žå)¢|”ó"J9§ÔùBbçÊã<¢8gу'šËù9±Â@Ù uÙ̉¨*r×Re`W,G Ùóâ«!~âÉE€?ÇrÚ(®ž§Pá²û"Ö‹úÉòÛÄu•zÙøyÙÑœPœH¥.–GÈrïXž"ÊG\×c¿Øó…æ“å5²çÔv]T/ògÏ‹~ߎ7îØ±c‹/VH(5!ʲ7Ê­ËÞ`Èß¶G"wÍȆ]±5dÏ…¯a~âɉü9–ÓÆrõ<8…ÈÎî âí¡~²ü6q]¥^*~^veN(N$ËÛË‘{ÇòçO\—Ý/ö|¡9ñà5²çÔj]¥^äÏžý¾}üñÇOœ81fÌÔ„(ÈÞ`(´.{ƒ¹U£‚Ä]‹ìŠâ¨!{^|µðÃ"Ì“ùs,§åê¥kÅnœB…_Èî‹X/ê§¿ ­+ÖËÆÏËŽæ„åD¢ºøàÐÐyKÚÃÿî»ï>zôèáÇ?ÿüóC‡e>/ÌÔõ³Ÿýlxxø“O>ù׿þµÿþóçϯZµªP(ÌŸ?xx¸©©É<¶­­mpp0}ÔÌ™3wîÜùÑG9sfþüùqëþb?–.]Ú××—~Û=Š¯Ø©}Aõ*ýíJ½h”zÝãçe×çÄîsžeê2_—•a,Üu×] ,ðÈÇ}_Pž(Ÿ8Žõu÷+5:ž/4'~sEGñ¼(ý¡ÖÕçD<¿ìyQüW¯^½wïÞÌ%ãÁ{BÄI n0T‘¸.{ƒ!Ñ.LpEÛ¶mÛµkWuuuæKðþò—¿<ûì³cÆŒùÁ~ðüãßÿþ·yòGv£iÓ¦}õÕWÿûßÓ¥Yÿ5kÖœ>}º­­mÆ gÏž]¾|¹òϦþ¿þõ¯cÆŒ©ªªzå•WÌk‡B¡`ðikÖ¬Ù¼ys__ßÐÐPù÷2ÿùÏnkkëëë[»v­ùù]ñûiôÎ;ïtuue~'ÈŽ¯Ø©}Aõ¦-µû)Ú•zÑ<(õºÇÏˮωÝçŠ}ËÔ…îe®ô¹uÜ”§r¯éë:îW*ÇóDZ8'~sEGñ¼(ý¡ÖÕçD<¿ìyQü=úÌ3Ïdž#xOˆ8 Ô †*×eo0äã7Úva‚Ø•ùBãV‘£ö›ßüfDùj:?Ì®Káϱ7®¯¯Ÿ9sfÇfa›£–ñŸ4iŠ]â„577Û|/Gÿ)eü°R©”òÃ2?ž§Røs†OÖÐÐðä“ON˜0!å´uwwÏž=Û¼¡œòÏ¿¸h*‘S(ÆŸ1c†hWú)î‹ÎÛ³û©ØQ½âº‰Ê«£âçbGs‚ú¬÷Máí™ÿµy„Žù 9G}Cy¢|&Ož¬¬Kí—(¥ohN¨¹bÏ#ºOR΢½_Ôº¨^%Oö¼ ÿæææ]»veØ™îPô ±'½ÁP>hÝÞÞ^êC;"Ú£ÈzíVÀ°+Š£¦ÄÉ…¯¦ðÃĺ"ÌŸcy„WÏÈSˆìì¾(õ*|>w~›²®X¯Gü\ìhNXN$ª+&y„,÷N·»ó,õóBí{¾ÐœPsÅžGt^”ýb×ëUüÙó"úOœ8±¿¿áÂ…™—øî<&„"€²Ð×eo0G¢*¼©2Ÿ'±5dÏ‹¯†øaèd"þËic¹zÉ)Dvv_P½¨Ÿ,ÇN™±^6~.veNXN$ª‹â*ù°ûBñ,õóBí{¾Ðœ°såwíó‚ö‹]Õ‹üÙó"ú·´´:tȾ®Ý#xLK¥: ¬ËÞ`Q5’¸k©âÿ†]Å$G Ùímóã«Å€f$ÖU%ñç $§ ù+ë£#§Ù=öE¬õÙõþˆëŠõ²ñó²£9Qú,öMßG›«ÇæÃî Ê壜j¿Êâr¾Ðœ°såw#p^”þ8®«×‹Îµûyý»»»÷íÛ·bÅ ñÚq‰à1!ú ì~ƒéùˆ“IÝ`Èß¶G2ÏÒ>±ù „õg¥ÄÏ«®\Reû“cü¼ìT<úŸK>¬òšç¼äÑç£ä™×º#=Wåþæƒ÷‡ë™Pþñ¿ óŽôýËÉS8v"í ÙY®KiBòà®Q´*6>ŠÃR¬Xz–B碸tyQ»X¾šÇ¾ˆü9eÎsÉ“¥¦9ÑÈ”×Üz軲 ú_“H9byZˆö„ìɵBþ,çÅAþ(Š¥ð·Ø|¸µµ•úý‹Š#4")G,O ÑžåZ±”&#›Ë…â ”E‡RèYlž,ÅŠ­ ѳP½,—Žå¢zY¾ÛÄŸC뢺Ø,*Âô,6OŠbÅÖ…öÕËré<¸ƒb½,_íOøsʺb]lž,5¦‘‘ÇTãǯ­­½ï¾û®ºêª={ö\¸páìÙ³ÑËä|íµ×Þpà ۶mK’Ä~T©TÊXô‘ qe¨KO 1/Ý0#ܹVœ9‘Ë¥ÄQ¸€ˆ>e¯ËrÝ<òd)Vl]:?,S¯—­‹òëeùj~ý‰¬oçRÖëbód©i¬€9yçö׿þõÀÀÀ©S§Nž<900ð»ßý®ü_‹Åâ—_~ùÞ{ï}ðÁgΜùøã¯¹æñQMMMbýˆ„ QM›6míÚµ›7o6/¸<øüóÏßvÛmS§Nݽ{·9!;wîܳgÏêÕ«_zé¥Í›7‹o}¸ëÃ?œ5kÖí·ßÞÖÖöÔSOÝtÓM&ZOOOOOOuuõ/ùËt ä/æÿâ‹/îÛ·ïoû›ýúQŒ£ø£|Äuõ<—,Yb@bi6Ï_ýêW?úÑÌ«õºººŠýaë÷]¯×–>'âº(O¥^QJþlX)sBå)ŠÝwdgûcþéõ×__´hQMMÍÕW_ýÈ#´··g¾7ëÈ‘#o¾ùfggç¦M›jkk;;;«ªªìGmݺUŒ£·®»»»ç’æÎžƒò‘H]2_gþ»"O ÑžåZ±”&Äå)M?ü°Î´óA}c¹nlž,ÅÊ£.´ïb½,—Î<Ê^õÕ«¬+æïןÈú™OYW¬‹Í“¥¦Q42…“§Ï­QWW×–-[¶oßnžÕÊ/b±¸~ýúêêj|Á‚ß|óy¸ý(1:bF=öØ.iÊ”)á™/(UÊQccc9«££cûöío¼ñF’$6O+Žã$I¶lÙb8X)ìÝwßÊhOæ[Amûàà âZ­\¹²µµµ§§'I’”êtìØ±Š”¦òüS.WE555q×××÷öö¾ýöÛh]ÑÿôéÓ+V¬°ó9s挸.ËucóœRÆuK’$¥X½ÿþûyÕ…ö]¬í;š“éÓ§·¶¶Úë¦ÜÁLž§NëMéböº›6m²óW8j¨ÿ
ÞiÓ¦‰u±y"ÿ††jßuNž{Êkú駇‡‡ÇŽ[*•ìoû5Ÿ›à>ûì3óÒ'ŽcûQ  sÄŒ^}õÕò…§€AùH¤Q<­О=â¹V¥© rþì8È_χ¢CE=‹Ís I±ò¨KáüÙõ*ûKñQž¨^e]ŠS¨ôß(ó3ZÕÅæ‰üÙ}Wì,Ç1#ñç­b±¸qãÆI“&]ýõ³fÍêêê24×ÔÙ~TjQF1(hd•H”#–§…xWÈÎr­XJSZ]æ×îšèòaéP gQyÆ<ÅŠ­ í;ª—âÒ)ëŠy*õ²|5¶?F6­‹êbód©iìòú£¨X,^¼xÑÌÆÀÀÀþýû›ššÜÿž¯âH„âÌ_Ïd¸wO Ñžl{Dr­?ËùCq?Êǃe>ɰW¤òŒIŠ[ÚwÎeï¯>'ÜÁXâê)t1GN¡ÒÿHâÏéë¢~ºçYÑß}ßõùaû£(3æO÷‡W‰  o[æõ¦hGþ¬Å§ì¬Ø8#íÏÆÉ«?9ÆaíyåÉúçµ/ìº#í?¢öoA£¸tPPPPPPPPPPPPPPÐÿ–þ#hÖ×?ˆ„1tIMEÜ  4óæ+/IEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out-big-thumb.png000066400000000000000000001400611445075545500265450ustar00rootroot00000000000000‰PNG  IHDRÈU%µ7àsBITÛáOà pHYsÄÄ•+ IDATxœì½y@SWÚ?~r³¯$@„@Ø÷}UYTÐÁ}«ZµjëÔ¶o§­Ó™÷7Ó}¦;íÌômíæØÚj]PQTD\d‘}„-@È’ûýãéÜÉ‹hÛùi·7Ÿ? yîyÎyžsNî=÷œgAÈ;ȳ¿“É|>ß`0¹\n0fffB C&“MLL|¯2Úñ=B ˜L&Glwo¢Íd:Ã8¦Ä-3ßµʬï^^^CCC7nÜŠ««ëÚµkq'‘H8ŽŸ;w®³³óh`Ç,Ë××·¶¶'“vý·Ÿ›ËHbÆ­ƒ/ªn]F9Ä- sùªs‡‰!nØ<†,@×^O¢Ré.2ãH¿æö„f[ojj*—ËOLL$ˆ™™™îîîr¹\(655Ù^²ãç*•êêêÚßß_ÉöH¼‡þï[ÏÔµ34'±ív@4ÃÝǪטF,ï°ñ³Ÿ°äÁPøM¬¾¾>//¯ÐÐЯ¾úŠ šL¦_þò—§OŸîííýì³Ï†††¶†v|ÿÀ0ÌÓÓ³««‹ à8~©gØl±Þ‡KÛrS]wYUyÔ)«‘€öõ¿ÿõ(ìîîFùøøØ6`2™^zé%£Ñˆãø_þò—ÖÖÖ¥Œ?xzzvwwã8NP¬8ºÜ=2¡7Ú# Àv@4ÕIÌ Š5OŒXõ:§¬R³j f5’’âëëû·¿ý 0Œððp@€šœœ¬¯¯×ëõA5;~0899ñù|£Ñˆb0]]]VI’µœD¡ ©n]ÒõÞ##«!„Èdd±|/"Ûñ$ þ¹”vØa‡vül1{ñŽJ.û%>Ýã}­-—Ž>‘ìø9`öÎ;Bˆåj° „#áY¬_¿a2iƒi¾`ÓöC;î‡9&–Ål´X ¡Ây>Ò™éò!Žã åÑHÑί:¦ f„uÆô½‹jÇO sM,“ÑjA‘2Á¼þ )‡6â¸U§£zxL¼ÛµsՖ׆¨ZÃŒõ»ŸJÚñ ³­Bî‘™nÖ.É >ÐG qää„s8¸£#g\™;ÿBËv|PÕ]åaOÕh4NOO•¬X±¢±±qVÍ$Ò쥛\.7›ÍñññP†a©©©‰D©TZì[m?e̱‰e1#Y&ëØÈø™3£GŽ?>vòäèÑ£ã§O«››¹w|… «ÅL”ß±cÇôôôK/½$‰Ç©©© L&ð¸¸8‘Hûúë¯ÓétŸ   à-..öôô$j MMMe³Ùÿõ_ÿõ=u€s? CÚo¨uxó.‡¿¼†›¾^NQ¥Ò¡mó^|:´tË¥™O,æêêªÕj###™L¦Z­vppËå...Ï?ÿüØØXooï£>úÁp¹Ü°°°¥K—êtº‹/^¸paV 333~~~ e``àáënÇCÄœw,ƒÉd4ÌÌü©×0º~›‰B1"dqs«*Z²mØ83c¶ÌØÞ± Cww7“É$‘H†Áó®µµõ‹/¾‰D¾¾¾‡îèè°X,ýýýþþþ'NœøüóÏcbbî®ðóçÏ8pÀöª?EÌýVØì!§b˜¦K}yF´tË#š/¿°¬Ûx¹Qe±Z§ò‹ïp«ÍK£Ñܾ}»³³S§Ó­\¹rjjª¢¢B.—?ýôÓíííÏ=÷œX,®¯¯ß¾}ûáÇwíÚe6›ÿô§?!„¬V+ŽãD b±855•Çã }`ÇCÀ¡¡ùÛÌÿZ7oèEãʱ%%̧öÜ^¿çlÛ0‰„pM+;µåwó2™L“Éën§V«B\.W«ÕZ­V6›­Õjét:†a÷2‘€ž­ý†?E̽ƲXB8B$="é1¬æNo—«7-毭slïX¶°.0«BÄÛ¢V«Eyƽ`ŸR?Ì1±fÌÿžX_ê8\¾Oos—~ÑŠÖÎA‹ùëí+û>–÷Ç\˨#ìQ•:øPÛ¬±-c5ßï®c‡vØa‡?¼žüó-ƒ?CæÜq°Ã;ì°ã¡B™ãõö§ˆŸ"?ƒñC‹ð`ð³Qäg2±ìø±Á>±ìx(°O,; æ0M~P‹Å®®®ÞÞÞjµ:::Z¯×?¼ 4Ídz`þ4->>žÏ绸¸ˆD¢‰‰ ™Læçç'“É4MXX˜Ñhôöövqq}PM?(E¨Tj||üÔÔ”T* …t:=88ta0ÁÁÁjµ:<<\&“éõúððð©©©؇qkË–-qqq}}}8ŽK$‹Å²cÇŽ‡Ô‡ÃÑh4ß\îÛA"‘¼ôÒKúÓŸ¶mÛvýúuµZXWW—˜˜ØÒÒb6›£££Ùlv__ß_|QSSó ÚET‘U«VI¥ÒÉÉÉ¥R©Óépwrrrttlll´X,!!!W®\ILLlkkãp8íííÿüç?HÓè{xJ¥R½^ïààðÓ²‡áp8 Åh4^¼xÑÃÃ!TWW×ÓÓÃb±ªªª¬V+F“H$÷7úaqûöí™™™ÀÀÀÏ?ÿÜjµzyyét_[x{{ùå— TeeåÌÌŒX,~€­?ÄG!ÇÓjµ‡‹Å‹¥©©©¾¾þ!µõ`… ÅÇÇG¯×ët:??¿C‡‘Éä¶¶6 Ã***V¯^]SS300ðñÇs8œkžÿquu ¬ªªrppð÷÷¿}ûö±cÇ„BáÀÀ@ww÷©S§jkki4†aZ­600°¹¹¹££ã4ýó‡Ãù¡Ex0øÙ(b+´ã¡À>±ìx(°O,; ìËŽ‡’cƲZ†MãUÓˆÝyúGRôWŠZ†€®ÿoÛÄåã?´øÏÃô’2~öð-É$ÌþÅ-Ä€q¨—î*û¡¥°ÃŽŸø|þ-‚?ü¯·ÂåË—ÿPrØñ3ƒ}»ÁއûIJã¡À>±ìx(°O,; ìËŽ‡ûIJã¡À>±ìxxˆËÿ?¬ vü›¾Žè”€Dî¡„wÊ*”?}ˆ¤èú)N·X­V‹…J¥Â •Š‘H8B3332QètºÑh¤Ñé8ŽÏÌÌàV+™L¦ÑézŽF§›ŒF„NÇ0 Çq³Ù ,f³j6›Í™LÆ0„Ùl&S($„‰dú—— F&Óét³ÉdÅq …‚pœL&[qÜl6ÓétËÌŒÙl¦ÑhPØh4R(”¯K"dµX¬8N¥Pà•JÅÈd„ã‹ÅŠã$‰D"Q©T„ !½^O£ÑŒF#N7šLtÍd2AÍ $JÕéõtͶ*B~£ÑÈ`0Hf4­ö¤,÷ù™gž‹Å&“iË–-b“É´eóæ¼¼¼ÌŒŒþþþÒÒR¡PØÙÙùÔSOUUUíß¿? @©T †ÐÐÐ;wVVVîß¿¿²²!´{÷îÌŒŒÝ=vùÒ¥]»vmÚ¸‘Œa&“é‘GQ*•óçÏ/**JNNV*•Ë—-‹ÍÊ̬ªªB±X¬ýû÷oÚ¸Ñh4r8œÕ«WGDDÄÆÆº¹¹mÚ¸ÑÍÍ­½½}ïÞ½K—.-//_¼x1—ÃY½zuRR’ƒƒƒÁؼyó¼yóB999…qqq<Éd®^½º·§çå—^rvv.++«©©Ù»woeeåóÏ?__W·oß¾ÆÆÆ}ûö%&&*•ÊÌÌÌÔÔÔÄÄÄÌÌL„PvvvaAA||<È¿téÒ .<ÿüó£##Ójõô úùÌårÙlvss3™LÁ0¬§§§©©‰Ëå ‚ÞÞ^ww÷©©©ööö„„«ÕÚÛÛK&“333U*Õµk×AKK BH«Õ¶¶¶NMMUWWÇÆÆ*Šºº:¨°»»Ûjµj4¥RÙÝÝ­V«½¼¼âããoÞ¼I¡Pt:”¿uë–J¥²Z­çÏŸhoo—H$ …âóÏ?/))ééé¹~ýº³³suu5“Éœ˜˜°Z­J¥r```||ÜËË«££cddD*•vtt ô÷÷[­Ö2™\[[ëààpâĉ¼¼<ÐŽJ¥fdd?~¼¨¨èÚµkcccÝÝÝ8Ž»¸¸LMMuvv …B‹Uü"‘¨¶¶–ÉdVVVÚgÕË–-Û°aÃwåZ±b…££ãÃÇŽ rRRR||<Žãccc¶–/_ÞÜÜŒJLL]¸pahh(Ü™R©4;;ÛÑѱ¯¯!«+„ÏÂ… »ºº²²²f±Ðh´¢¢"ƒ144ÔÜÜ|ëÖ-„££cQQQCCƒ³³ó’%Kz{{333çl‹J¥ž={–Áb±Š‹‹M&…BFwww¹\>44DÈaî%?¡rJJŠ»»;\øùù¥§§ûùùA=Kzzº··÷ØØØÒ¥K Æàà Á²dÉ’èèh¸ñD(O§ÓÓÒÒ<<<<œ‘‘áääD&“·oßK`¹\®V«“’’îfIJJ"‘HÞÞÞ¶3X«ÕFEE‘H¤­[·vwwÆ9ÛR«ÕkÖ¬±eôòòjll,++#»ººòóómå¿0÷’TvssKHHHOO§ÓéKOOO[[›\.‡É£>J&“I$—ËÍÈÈð÷÷—Ëå&$888$$!táÂ…›7obå{zzººº„B¡mù7ÖÔÔDGG#„ø|¾›› ÿØØÑQùùùfjjŠL&/Z´ˆÃáX­Ö’’’_ÿú׋-JHH ‘Hp¿ ‘Hr¹¼¡¡aÕªUws!„JJJÆÆÆ¤R©-¦ÈÊ•+më!z{ýúõ}}}yyy‹^¯?wî\tt4ῘLfnn®ƒƒB(((¶²ág´sçÎÚÚZggç7n¬X±‚J¥†„„<þøã0)))*•*...;;̹ª««µZíÝ,×®]c±X>>>!™L¶}ûv‹EdÐttttww_ºtéœmEGGS(‡C0¶¶¶zyy™L&‚‘9Bþûs/ùAeooï©©)­VËb±–™™™ÒÒÒ·Þz ~ÖÙÙÙÑÑÑ8Ž·´´ NMM544lÚ´ !TXXµ©Õj£Ñ³|óæÍ¡¡¡DyƒÁ°páÂ>úȶüÿüÏÿ‚x¾¾¾L&sff!DtÔíÛ·322¨Têž={"""ÆÇÇ===ËËËwíÚUUUåääTRR²bÅ @ÐÔÔ{ìØ±»¹H$Ò±cDz³³gff"BÈÇÇ'22²¼¼Ü¶¢·1 S*•NNN Žãyyy~ø¡Á` F‡2>>þî»ï¼ÿþûpKT(ÎÎÎmmmGŽ™ëéé Ù—jjj ÃÌÌ̱cÇ CuuõÁƒ;†ZµjÕÔÔBènxƒãñx¡ÞÞ^H†2 Ð_žžž7oÞœ?þÝmY­V½^O&“ ÆÄÄD¹\®×ë F„ŽãéééSSS ÿ}„¹—ü 2ÜÌpŸœœ$XŠ‹‹i4Zaaá'Ÿ|òþûïOMM]»v !ôâ‹/ž8q‚ÏçûúúŠâw¿û†a¶Ú!„þú׿Â(Ïb±0 ƒ Q>''G¥R‰D"„‹‹KOOOll,™L¶­J$9;;ß¹sÇ`0Âk„V«ýôÓO#"",ËŸþô'‹Å¢R©‚ƒƒ333GFFîæ¢ÑhZ­–Ëå* ¢ª›7o¾ýöÛÐ"QÑÛjµzÅŠåååD=   !444d;¬s€B¡lÛ¶Í–B&“ õ¾t:ý^,t:ýî¾ß†qN.(O|Édyyy T*•ÿ>uÞß^ b!BÈsåç†ôÑGuss“J¥«V­šõÊò-š%óÝ\†»ƒß‚ýn–94b0\.!ÄåráÑ$“Éäóù|>ß–‡(Ïd2†aL&Ó¶N‹åàà@üdT*ÕÉɉD"¹¹¹  †……h4AÉd …=+ê+™L†Ât:ÏçÃN)´H¡Pmõ"‹ÅšÕ#„T‡ÍfϺêèè8«]hnº°*B¹¹¹999ÍÙ°3™L …2+"2Ñô,!ù|>Hê@‹³ÜlGmÖtJfI$<¼î›D"9::’ÉäïÔÿÐ.1 w î¹çB¿ýío_|ñEÂÕÕÕjµ¾õÖ[YYY €(ÿÜsÏÅÆÆ8p›\.züÙgŸ]¼xñ–-[€7lذ~ýúøøø±±±GyFÀ“O>¹iÓ¦ððp„D"…çêÕ«:äãã³wï^„\.÷ôôD …·ß~›D"íÚµkÅŠÎÎÎ!±X Ý´yóæÇÜÝÝtAeggoÚ´éÀ°>ÍÈÈ€FAªùóç?û쳿úÕ¯à—,111ëׯ߷oÑ'!™L¶xñâ×^{ ê„i´víÚ‰‰ Û&ˆò;wîôññùøãKKKaý:«éøøxB_|ß¾} ¹‹‹ Ñâ+¯¼b;lÄ(lÛ¶máÂ…¶fggoÞ¼ùÀ@¿ÑÑÑK—.…>œ%v~~þ²e˶mÛömúŸ´KŒ‚íè=±jjj4 ‰Db±X ƒD"EGG¿ûî»<¯¶¶¶µµõÈ‘#&“)<<<11!å™L¦‡‡Grr²@ ˜˜˜ „NܳgBˆB¡ˆÅb6› øûöÛo›L&…B§"¡¤¤$‡•S©T•JåííÍf³ßy縸¸öövÿ±±±½{÷^½zÕÙÙyß¾}O<ñ„““Óððpcc#BÈd29;;;99\###çÏŸ¯®®îêê"tAÁ*Øb±$''ïÛ·oݺu¡ƒšL&³ÙÜÝÝ=<<Ìçó …BÁåraO„ ¶µµ‰D¢ „êëë###i4‰D²Z­¶Må¯\¹²gÏžÑÑшˆˆæææ»›V(÷—ܶÅY£€:wî ¤­¦ÀÉÉ)..îÝwßMOO÷ÝwÛÚÚÆÇÇ¡ä,±9Îè託—×7ö?LJøaC»Ä(ØŽþ× þÁFËðð0ƒÁèêê:pà‘Æ000ÐÕÕE|…,΃Çñ¯¾úÊÝÝ!ôé§ŸÂ;ŽN§ûç?ÿéââø»xñâééi•J…ÂqÜÃÃÃ0x:@åï¼óÇÕjµhooG9::¾óÎ;ááá×®]ùè£>üðC¢B]]]—.]òññ±å²½JèròäÉýû÷ëõúË—/_¸pá½÷ÞCåååMOOÃk?ÇÓh4‹\.ÿòË/áCáå¹°ƒÑQþÆQQQo¾ù¦‹‹‹Õj½»i•JuÉm[œ5 ÷ÒôâÅ‹½½½Pm]]Ýà5îÖ³Ä>zô¨V«U©Tߨÿ¡ææfÛη1úÿlÌÄÅÅÅÆÆÎ* —æ$ÇÆÆR©ÔE‹ÁM˜@pppFF†D"±%†„„dffzxxp8œ;w®ZµÊÕÕž‰??¿ÔÔÔYmy{{cæëë{/1Äbñ¢E‹lÖ!.— ûC„B¡í òn©"##m|!*•š••7c^^^pžˆzâ‰'‚ƒƒSRRöíÛG¥RïÕ„¯¯/‰D‚M–9›¾¿ä¶-Þ­þœšfffÂÆ:N Ó,±¹\nnn.ÇûNýO´;ç ù>0k] …qV·þ´ •JჃƒlþ$ðýˆMÞºukLL —Ëíéé!‘HpL±xñ⬬,‡;òb±žè{÷îMNN¾rå BˆL&ã8¿bÅŠ°°°›7o…L&Ëd²7ºººÞ¹sgÏž=ÕÕÕ¶Mêt:ØñCÁ&ÓOÄjÁh4þ˜£ÜÎÂ÷#6æéé9:: O 6ÀƱ··w__œyEDD8pÀÝÝð‹/³9$$äå—_æñx"‘Èd2„††¾üòËóæÍ{ùå—1 ûðÃáæßÕÕú¤·ãG Ìd2ÕÕÕÁtéïïW(¡ªªªññqØN…Í Ãà†;¶“““ƒƒƒ0÷»»»§¦¦ètúàà LǾ¾¾Gy6š'&&îµÕaÇÏdgggOOOÅÜÙÙ ïׯ_º}ûvoo/ CL}x 2Œ   µZ}êÔ©Ë—/ÝÏÏÏÃÃF£uvvfgg_¸pÁöxÒ;²²²~hì°Ã;ì°Ã;ì°Ã;ì¸'ˆÓ•Y‡b³(Άüýýÿö{!""‚Ãá899ÙÚNŒ`±Äb±Äb±­IÆ·…B a2™`KC&“]]]¡•ˆˆØ&‘H`LæääD(âìì ŸÙl¶““X,988€$!'''@@"‘( •J+.6›íàà@&“AfÛ\K¶ýàää–U³ºñ^&S!:ÎápX,“ÉÄ0lïÞ½  BH*•B°ufž2ÛÁ2‡N§ÏÉBŒ¸-ø|>tôÒœŒòÓO?}åÊ•øøøÂÂÂÛ·o‡„„ŒŽŽÆÇÇk4šõë×755‘Éd“Éô»ßýN&“ŒŒ…B …JîØ±ã>ì/^„‰Dããã 8ŽS©Tggg8ÅŒ/**¢R©MMMCCC[·níïïGΛ7¯¨¨¨®®ÎjµúúúB=‰‰‰†MMM‰D"ÇétzHHø^CfÔüüüööö'Ÿ|R Àñª‹‹Kqqqggç¼yóBCCëëë9ΡC‡˜LfLLL~~þ™3gbccóòòæÏŸéÒ¥   hµÚ®®®ØØXðÝmllŸËåzzzêõú¼¼<6›][[ëîîãàà°mÛ6p8€n¼råJqqñ³Ï> ¶kŸ}öŽã„<ôs?܃!É¥““Óèè¨^¯wqqqvvV«Õï¼óÎ /¼põêUBfggç'žxÂb±<÷Üs7oÞôôôtvvž“…q„PNNNKKKww÷ùóç%IddäÌÌLjj꜌ Þׯ¯ããã‹Åb±”——K¥R‹Å·}P•Á`h4š‰‰ 0ÆÐjµ mmm0uîÃ…B1::J£ÑZZZ>ýÙgŸ±X,ƒÁ@¡P4Í{ï½÷‡?üÇñ‰‰ ¸¯^¿~]&“ŽŽ9rD¡P`F"‘ ƒ1>>Žã¸L&#‘HMMM`[W^^þü#-- ¬óp÷ðð ÒQŠD"³Ù VÂ`“¤T*q¿råJ___lllPPÐÉ“'á~@<}}}wïÞ}êÔ)±XìááÑÜÜüúë¯×ÔÔxxx‚wÞyrà*•J™LF§ÓOž<ùôÓO›Í扉 èÀ£G>þøãG­¯¯ÿÇ?þp:®¾¾ÞÁÁA¯×Fâ º X,«ÕŠã¸§§§Á`˜žžžšš2›Í2™Œ00DÉd²ééi??¿¾¾¾êêj///­Vû«_ýª­­ !2_¼xqddäÃ?|ØÍÍ­§§gݺul6›ÃáLMM ôôôøøøˆÅb…BÑÛÛëååÕÙÙ‰úÅ/~qþüùééiFC¥RÓÒÒnß¾Í`0´ZíÎ;Ÿ{î9OOO¥RIØãŒŒ°ÙìÅ‹çää<ú裃A(êõúˆˆˆÞÞÞ//¯ÔÔT•Juøðaµâãããîî^RRrúôéŽŽŽ¦¦¦'žxâøƒÉd¢ÓéNNNìùâÅ‹Pàéé l –’’ÒÔÔ„ãøÝ,ĈÛú²r8:®R©ÒÒÒZZZ ‚Á,Æoñ„„£­Ç•J…"ˆ÷q>™„mÐ,ÏòÅ @§ÓçÍ›÷míïU¹T*“Wd#0¨À`0lÛSëÿÄünH¤ÐÐP??¿9¯:99Íòbx•y<Þýßl¾ë |×òl{‰¼}ûöèèhx¦Š‹‹óóó•Jeii©L&»sçN~~þÌÌŒJ¥Ú½{÷Õ«Waoݺµ¹¹ðM›6ÕÔÔ\;vì ¹~ý:BˆB¡X­Ö„„„+VÀúÆjµJ$ð½T«Õ/¼ð­[·}ôѸ¸80§P(ÃÃÃ!!!K–,Y¶l˜W,»wï–Édmmmû÷ïÇ0¬«« ”8ޝZµjݺud2ŽÒÁøâñÇONNÖétùùù .¼|ù²F£™žžÆqˆ‰‰±e9vì›Í.//·U¤…;%x@Ü¿£ |VV†al6Ûßßò³ÙìW_}6h\\\Øl¶——׫¯¾:oÞ¼W_}5<<D“=Vmm-a¾µ¶¶ŠÅ⎎'''‘H‘ÊB“““‚0‹Ü€ËÕÕõwÞqss£Óé“““½½½pU"‘|üñÇ{!o7K—.5 ÁÁÁ°š¶Z­‹P(ŒŽŽ†‰…1))©¼¼|ttôå—_ÎÎÎFõööÚ†ÜdeeÁrÊ#„bbbêêêlË×ÔÔ(•Ê¢¢"Ð zÇqð`!ôšå¶:22rwÓ½½½à‹ Ö‘ßR`["•Juss{ýõ×më¡ü+¬‰D¢ÑhðÄ X/^|õêU0Ç%øøøÜ¸qƒð>¿OG,Ë™3grssÏŸ?æÌ™¬¬,­VÛÝÝ ›£££§OŸŽŽŽîîîîïïïîîV©TD“!D …r¹¼±±±³³S¡PÀ144ÔÛÛ»¼¼œËå‚o‰NollÌÉÉéì쌊ŠjnnNMM……[hhhss3p;w.&&fzzúÆjµ~ô4­©© V¸jµúöíÛ­­­¡òòòñññóçÏCôŽ›7o,qqqL&S.—755)•ÊúúzØÜZ²d ‰DêééÉÏϯ©©ÐDÀ6› ·wŸÊwttÐét¸D”÷õõ ª©©Q(999çÏŸ7óæÍóòòjmmÕét WHHH[[¼Ã •JU\\<«i•J5::ÚÑÑÑÐРR©¾¥À¶DØ( 6¢ÇsrrÆÇÇ?ÿüóÂÂÂ+W®ô÷÷,YYY …Åb Šƒ´‰‰‰·nÝêêêºGAùÚÚÚüü|X±ÄÅÅ8qB£Ñ\½z~caaaçìÙ³'OžT«Õ@'z^Š ‡°o…””ØÈÈÈ`³Ù01#""`sög`tn^2™ÌÛÛ›Xhƒ^l6;!!á‡î'b’ „ÐÊ•+‰ , …$iÅŠ1$$dùòå¶Ûö...2™,%%Ã0päÅ0 ^¦œœœÖ®]‹ŠˆˆX¹r¥X,&¸œW®\YVVfÆH&“­\¹’p&œÐýýýËÊÊØlö‚ ÒÓÓm¥g0¥¥¥Ð.ÿ’’xÀƒð1®¹ººBm‹/NJJâñx¿øÅ/fy ÅÇÇ{xxxzzÎj"<<æYaaá¬HL ¬"î%'¡Z```YY™í™BhÕªUK–,™åƒ¿`ÁxtæååAyÛq™5X©©©Ë—/ŸuRt·.DD墣£×¬YSRRb{¼–••µbÅŠYªAc='0‹E¼–'$$ŒÅÄÄLNN%V®\966–‘‘A¡P ø|¾Ùl^¾|ù³Ï>›““…aØüùóçÍ›G"‘¦§§CBBH$Rnn®V«U«Õ×øøøÀÀ€ÉdêëëãóùùùùT*544T¡P¤¤¤À‘ÓŽ;`gU&“eggGEE%%%Aü`IHHÀ0 œ bwww[[øÍ±Ùl©TÚÝÝ“óu˜qB£Õ«W_¹rÅÕÕÕÛÛ;''gÍš5555ëׯGEDDÀûDAAÁ²eËJJJà €@OO¸Ýétº   ÛÖCCC§§§KKKm‰¶rÚªæêê:==@ô B(22ÒÍÍ-22²  @( …’’’B"‘nܸ±jÕ*Bµ9+==ýüùó$ñ^º0™Ì;wR©T8è„Ê ›ššüüüNŸ>m6›‰®\¹âèè8Ë™z€kÛÿ=±ºººà÷GÄaò÷÷wÛŒŒŒÂÂÂöööôôt‹E&“7nܨR©<==O:µsçΪª*GGÇ‚‚‚¢¢">Ÿo2™àÀèÖ­['33“à²X,:N¯×›Íf__ß-[¶À¯'%%Ö€QQQK–,A]¼xqÞ¼yõõõjµZ§Ó1™L‚¥¶¶!Œ"ˆ‹eùòåD¡mÉq8£Ñ866Æç󃃃¯\¹²téRXØ.\¸077!411Áãñèt:¬* BSSS°”&\mµ "“É<oN9mU«­­ 7 DÏÀlc2™nnn7n Ù¸qc@@@__¸(•JøÍÜg°ØlvNNÎÉ“'ï£KQQQFFFxx8ŽãDå„ÀƒÁd2©Õjlj ú{‚ø^DcmÛ"ŠX,îêêJMM­¬¬„ןþþ~±XÜÖÖod±±±îîîuuuF£qùòå°Ç:11qøðáÆÆF«Õúç?ÿÙb±À‹4& ]]]+**l¹Ìf3Ìý›7o.[¶ üÚ¾üòˆ†„PMMÍŸÿügèšmÛ¶iµZèkǧ¦¦–ððp‘H‹<‚XXXˆaD®‹ÅD¬¬ TUUÁpšÍæÆÆF ÃàŒ“^}õU˜…UUU¡¡¡F£¶ª¡ ÚœZ`Ëí9å´U­´´~]¶=c0Ìf3¼šÍæêêj³ÙüÁ”——ÃOÞøî3XJ¥òý÷ß9ï¥Ë‡~899yãÆ „Ð3Ï<• ÚÖ°{÷îúúúÄÄÄêêj"¾Ñw—ÿ7¶nÝ*‘H`»BDZñ¿ïi6§]Ä7âÛ^ºÈdòÝ[ð°p/–­[·"„d2Yvv6 4ò÷÷‡8Û„lß)ÐÔwŽäü®=S\\ át¾q°~DÎÎÎÄšŽˆdêææF"‘ÜÝÝá½/,, ð}ûö…‡‡ßë°åGoÖˆ2ÿÈ…Ÿ÷tüqjDþÕ¯~E¥RSSSÛÚÚ˜L&˜}-[¶,<<œJ¥¶µµíرãòåËaaažžžÝÝÝ¡¡¡¶~l°=4½›8çÕ9î/üS#ŒJ¥Êd2‹µcÇŽÝ»wÃß?þØÛÛ[§ÓÁ™9Bèúõë°—C|°ÃŽû€b0Ž?¾qãÆ¿üå/`GF&“ N:%•Jkkká— jˆÅžCÆŽoY¡PˆD¢¯¾új```bbbrrrbbbttT TTTp¹\ooïëׯgff666Ο?ß`0466ÚÆÈ·ÃŽï "º+lôñx¼YáÔì°Ã;ì°Ã;ì°Ã;ìø¿‰DâïïOXYÅÆÆzyy!„æÍ›WVVÆãñÖ¬YSXX8Ë®èþÚ~-))AÍ Érss/^ÌçóËÊÊÀˆ;##ã¡öÙñƒ¼`Á‚üüü‘‘‘ 6ÌÌÌ¥¦¦B¬ÑôôtWW×ââb‹ù-ž~úéÉÉI…B±téRpk6SSS›6m:r䈿¿zzºÙl6 ###`û“`ݺu333yyyþþþ^^^jµ:33ó™gž™˜˜X²dÉÄÄÄúõë}}}Ïœ9êààŸŸé¨u:ÝÊ•++++åryjjª——WEEÅš5kÚÚÚŸOQíܹ³¡¡A"‘`¾š}ôQaa¡T*3¿ß'0„—ËmiiÑét§OŸöðð jmm-..F]¿~½¯¯ïÎ;pgš˜˜pss£ÑhR©T£Ñ€ÑØØ‡Ã‰D@±Z­&“itt´½½½ºº:  ¿¿|Nž<éîîžžžÖ¡z½žÇãÕÕÕõõõ}ùå—«W¯ãµééið:'¢Àƒ%êÒ¥K'&&†††ÆÆÆnܸñÞ{ï) H»299 9H-‹Z­že:lÇ0‚Å …BÙ±c‰D"l°l1”ÝeQD"‘î^ë@oâ+Q?˜y@ýð.}£Õ‘@ðþë*¢ ;~¤H$¶’ [|ûuºÿ§@–H$¡¡¡ÃÃÃÉÉÉSSSAAAR©T¡P@šä´´´ÎÎNGGGGGÇÄÄÄððp.—ëââB"‘,‹‡‡ÇÞ½{ÇÇÇÁÀæ‡ÖÅŽ(7nÔh4QQQ‰$//Ï`0‚ëׯ'&&~ôÑGÞÞÞ‘‘‘ ¥¾¾žL&¯^½zzzz``àôéÓ+W®d³ÙÓÓÓvC;fëêê‰D"‘¨££ãüùó&“ °šššÒÓÓ[ZZø|¾««+øfX,“É455ÈápT*±ð²ÃŽC"‘€ãÞüùó]]]ÃÃÃÿøÇ?‚1u\\8ÐEDDDFFÒéôèèè7Þx#,,ŒF£%''{xx¸¹¹ßkÙ;þí@_mÝ—méÄUökvvw`§9çßz ¢wÌŠàBå{á?Žü4'æì‡{ýÆî¦ÏÔ*,,Ì6à·É'x¥fõÒÝö*ÿöì䢢¢´´4@ ‰†††X,–F£a0¡¡¡b±xjjjÏž=—/_æñx&“‰Á` 8H¡Ñhl6r<ÃæDŒ¡Ñh[¶láñxEEEóçÏ¿zõ*„åܽ{÷Í›7gff Æïÿ{ˆ[^¡ðæW;‹E¥RÍf3dzZ­ç—L&³X¬µk×:::Â&þðððc=6þü7nlÞ¼ÙÍÍÍd2mÞ¼9((hýúõQQQ°‹ñ¥Z[[ù|þÖ­[.\8<<ìêêZPP°bÅŠ3gÎìÚµ+,,,  ¡¡aëÖ­ttÁ‚‘‘‘AAA·oß~íµ×‚ƒƒ§§§a_ ÂXŒÑh´mÛ¶73ŸÏb2™8Ž“H$6›ã¸ÕjݳgOUUÇão¶}ûö«W¯r¹Ü×_BTWW?öØc7nÜ(++»víÚüùó…Baÿk¯½Z@PLf±XöíÛG¡Ph4Úúõë[ZZB°ùW ƦM› ©{vvöÀÀÀ¶mÛ¢££FcYY™““SlllVV–R©Ü²e †]¼x±B¡ÈÈÈ ËËËÙ¾}{rròðð0´•——§T*7nܘ@Ä}±]jSÄbñÈÈHwww^^ž£££§§gHHÈôô4¬· ´ABB™ …...—/_†EÕ“O>i4¯\¹RTTd0ÆÇÇ9Îõë×qçóù ¥££#**jÁ‚AAAz½žÁ`¬^½ºªª*%%…Ëå* WWט˜˜ôôt£ÑxéÒ¥ââb‡GyðW^yE¯×>|8''Çd2utt¤¥¥566*Š+W®,[¶ì©§ž:pà@qqñûï¿ïãã3oÞ<>ŸÿöÛoïÛ·ï7¿ùÍÕ«WFcvv¶N§ƒ¨¯b±üÇÇÆÆ*** O'BÈËË â®ˆD¢?þB!H$ÄÍ`0>ùäðÏÄ0¬©©)66våÊ•8ŽßºuK*•†„„H¥R‡SYY¡1=<< D†aǧÓ鉉‰999CCC<Ïl6wtt„……µ´´|þùçCCC0*F£1..2«¥¥¥AŽq‘H¤Óéd2Ù† >øàƒU«VõÔSD–M¬¾¾¾««kÙ²e\.—Åb>}zhh¨¹¹ÙÅÅE$uww·´´@‚uFÃçó‰XJt:ðcÇŽÅÄÄ…žžÇqßµkW}}=„†âr¹ï½÷žÏ‡~çÍååå¿ÿýïÏ;§×ë!R-ǃz¢¢¢ Åàà Ÿ‡¦!š²V«…´¿Z­ “ÉZ­žcÒ)2™L¿«T*;–žžîààpôèQ??????b•Á`¸ºº†††^ºt‰Éd’Éd6›ýÚk¯1™L"Þ•B¡hhhhoo§Óé cdd¤¢¢bpppddD ôõõk4‹Å244)–Y,Ö™3g üõ¹sçà6ŒŠ…ß084OMMñù|ÇËËËš››!„:ljW"Ð"&&¦©©©¯¯¯©©‰pó‡Ç¼oMMMFˆíð÷÷‡Ûä‘#G’““»»»{zz¤Ré¡C‡ÉdreeeyyùÂ… ) „mjmmÍÉɱZ­aaab±B¬©Õj2™ mñùü«W¯J¥R*•J¡P Šß;wlÔ“=<>þÚµk\^¡Pœ?šîïïÿðÃÍfó;w nQQ‘@ øûßÿž››ëááÑÑÑ!—ËGGG1 KNN†@•AAA\.·µµÕßßßÅÅ…L&÷ööFEEÁÙvvv6‹Å¢P(^^^)))7oÞ¼xñ¢^¯ä‘GNž<©T*ÛÚÚA°ÄÄÄÆÆÆªª*x#6 ×®]ƒ¸}ô‘V«­®®ær¹}}}D7 äææ* 6›=::ZQQ T*ÛÛÛ©Tª··wGGGDDlø‘Gqpp¨¨¨ ijj êììÔëõ EyyùÙ³gÕj5ä‹$“É:îÆK–,¹té„ ¸uëІ«mmm‰‰‰i‘Ëå;v,  ¾¾^¡P:uŠJ¥ÆÆÆ?~>>_|ñ…³³óÄÄD]]Ýôô4¤¹耘»wÓƒƒƒÁí}N@Ì–û#--í^B0 Y9]Y,qeûٶؽ>ßÍ5‹NG¼aaa[¶l¹WÞùóçϪV DEE PÅbÍŠô9333..bˆÔˆˆˆôôôööv‹ÅBDD …eeeµµµ‹-JHH “ÉÉÉÉf³Ùb±”••ÑétGGÇìììÎÎN‹ÅÝÛÛ»bÅ Xªôôôäåå‰ÅâÚÚZ¨rrrÊÉÉéêêZ²dIcccCCÃòåË5««ëÂ… ;;;­V+,MJJJŒF£‹‹‹ŸŸ_gggVV–\.úøøøÈÈHkk«ÕjMJJ²U „ ËÎÎniiÑëõ ”^¯'”òóóá³³³ÝÝÝÇÆÆ@ ooŒÁÁÁyóæÙ6'•JÓÓÓ›››ÝÝÝýýýîææ–ÝÕÕ•““ƒaØ‘#G<<<(JQQŽã¸ £££  Àd2 -]º„_°`AgggHHˆ««kMMMII‰F£™™™N˜¥¬‹‹ Ðmã`¯[·N.—wttÁß¹\nQQQ|||{{»Éd¢R©Ä¥‡>±6lØpñâÅââb“É$•J%‰T*…,#¾¾¾]]]R©´¯¯Ïd2A c…B___Ïf³!AM\\\uuuIIÉÈÈ—ˉ‰Y²d‰J¥"“ÉóçÏŽŽnllìééÙ¾}ûµk×::: ‹ s½^/‹ ƒ««kJJʹsçÖ¬Y~ñâÅ„„„ÀÀÀ%K–p¹Üëׯ—––=''ÇÃÃÃÃÃÃÏϯººº´´´²²2..N*• Ì©ÔâÅ‹A¼þþþ»•zä‘GàjVV–§§§§§çÙ³g׬Y#—ˇ†††††233m› «««óóó3›ÍÉÉɉäÚµk¥¥¥###þþþ®®®aaaçÏŸ_µj•B¡èëë+--ýꫯV®\ÙÚÚš˜˜Fputt¼õÖ[©©©¶­ÜKY¢sÚÛÛ—-[¦T*õzýÚµkÍfóÌÌLrr²J¥ÊÍÍhkkËÈȸpáFÛµkWCCÃ÷sø†ÁòžJ¥&%%ÍŸ?þÞ¹s'++‹Éd ‚œœœÜÜ\x‘{©™™×ßß!¿&''+++×­[g±Xär9‡ÃIKK#“É\.W.—F.—K£Ñ–/_~þüù¼¼<„Ôñœ®^½š˜˜XUUµUVV.[¶ Vô*•J*•Bmnnnccc|F¥R¹ººj40:B„GÍ©ˆg±X\.‡\)t:^>Þ¶•{) ô'NÀ–ر ‰499 ”k×®ÍÌÌlذ–þæ›ož9sæû™Xsv#¿}y”j–Mñ–¨³‚]‰D¢9k#Ö³³d ¾ÂÂŒçÛ‹z“/¸JX}b}VswwñÕÖÔì^:’̪än¥î¥ìÜ`‰Ìçó´Z­‹‹ —ËÕét^^^ƒÁÑÑÑÉÉ Çqø;33ãååe2™„B¡-Ýd2Éd2‹ÅÂd2ÔjµX,f³ÙZ­–N§Ã¡‡T*U©TÎÎÎ` 76™L699 iþLD ¥ IDAT´Z­««+•J5ñgffF  ‘HÄd2õz½———N§£ÑhnnnÎÎÎ ¤%èSSSGÊÃÝ‘PröéõzÛ,•J…HàV«è8Žóx<8¹²Z­ÐœX,f±X°bS©Tl6ÛÝÝ]¥Ræéé *K¥RÅbiµZgggƒÁâiµZ©T A\]]]A}—©©)Pß`0À9˜L&3Ð9ÓÓÓ®®®Ê”³sˆVîî„oI‡%€ÉdJ$Çm£ÂPR(Û­²{"“ÉÊÊÊöïß_VV&•J¿øâ‹ÀÀ@>Ÿ_QQ±hÑ¢ÊÊÊÐÐÐÞÞ^غËå³è}}}™™™Çg2™eee¿üå/Ÿzê)8ÁxôÑG὆N§755ÅÄÄH¥Ò={ö¬]»¶¾¾ÞÛÛ[*•ž8q¢¬¬ì·¿ýíöíÛi4ÚùóçE"ÑÿøÇÏ>û¬¬¬ ž_—.] …"‘ˆJ¥ŽŒŒô÷÷§§§ú+¯¼ U*Õã?~åÊ•ÂÂÂ>ø€x>®\¹R¡P(•JFãççgµZ;::AtttXX˜^¯²ÕjýÍo~óâ‹/®^½ú±ÇS«Õõõõ±±±R©ôÊ•+d2Y,«T*‹ÕÒÒ%•JOŸ> ê€x …Âb±”––¾øâ‹PÏO<1::ÚÖÖ–ššJ£Ñž|òÉï³sfÑŸyæ˜ÓÝÝÝ™™™îîîr¹ü©§žòððèëëóððàp8kÖ¬ùôÓOa{677r[Ì ¬¾¾^§ÓY­ÖòòrHôe0jjjL&See%<¡áŒÇñYôÐÐPØ€z [‹Å är¹t:ýïÿ;‹Åjoo‡ú©T*•J­®®†e pÁч»»{PPЉ'ø|þÚµkáM¾¯¯ott4!!è\.÷ìÙ³)))ß’Ž‚ˆ_psòõõ¥Óé¶‘Àüýý¥Ridd¤³³óž={vïÞíääÔÓÓ#‹_yå¨688”‡Ã³Ù499 JüR©ôðáÃjµè„:PL&:vìXoo/ÔcµZI$’‡‡¨)[¿·Î™Eçóù±±±W©T*<˜žž~ðàAGGDZ±1ðpÙ¸qã®]»æÍ›wÏG!úWÒ˜œœƒA¡PjjjîܹãååuãÆ ‰DÂår!&³ŸŸ_KK‹-]©Tbæééyþüù´´´ºººˆL o…<B¡´¶¶¦¥¥Aý·oߦR©Û·oÿì³Ï&''ÓÒÒNŸ>m0üüüjkk]\\„Báèèhppp[[[`` ‹Åjhh‰DB¡n3###ÞÞÞ߆é6ëêꦦ¦RSS;–ð׿þµ®®îÖ­[uuuwîÜ‹ÅW¯^˜˜¸uë+ÌËË;}útrr2ØÊ2 8MJJª¬¬\¼xñÙ³g!„:ƒÁ8tè<ûÜÝÝ[[[!ÙƒÁ€Ï„xãããQQQåååZ­6--­²²R¡P„††Þ¼y³££ÃÏÏÏh4666~o3‹^^^®V«kjjúûûýüüÆÆÆX,ÖÕ«WÏ;wçΚšF£Ñhüýý+++oݺ% >|¿Ç!œâÐh´ÄÄD¡PU!‹Åçó!p¹““Ó,:‰DŠ‹‹Óx¨'((BLÓh4‘H$—Ëcbb\\\ þÄÄD„ŸÏ‰‰  ¸bbbÜÝÝÉdr||<ÜiàÆÏÏÏÇLJ ;::ÆÅÅaö-é¶jzyyEGGÏÊsÌårï^ÔCY¨–L&J´"‘¸@)‹•””Äf³…B!púÝâ‰ÅbXƒC=Ô‡P‰ß[çÌ¢ÛªïààãëëkK¤P(0î7™lq/ÛšY®Ä×o7ömwæ¤Wû¡{xPt;þ3KJJòó󇇇÷ìÙxýúõœœœÐÐP™L–••ÕÝݽk×®ÄÄÄŽŽŽ;vèõúÌÌ̼¼>^UU¥T*8`4/^¼ˆÝ uuußô!þæ–•ÞÈJ‡dåöû—.R·ôèËɸ–­¬¹ë¿-ÒúëÚ¿r}i³§ÿƒ‹FŸÏ_ZZZ]]Åg tW‡Ëå.,,àa³N§óõõ5F£þf³ÙÙÙY§Ó¡¿-“ÉÄI'''6›m0mll¼¼¼fgg¡ï1ð·±±qssÓh4îîî,kyyY,k4½^„X,^XXðööæóùóóó Îb±ÀJ(º¸¸ÌÍÍ‘Ò"‘H4;; ᔥäè¯k·¬‡Ã±ÜLG„«««½½ýüüüÿÜ1ü›\4ƒQ[[ ÖO~ò“ááa©TZPP099ùÔSO577ïÝ»·  `zzö7nXú åääÈd²ŠŠ >Ÿ?==ýì³Ï&$$˜Íf Bööööóóc2™)))€ÍfÃÿСC...T*õé§ŸNJJjooûí·«ªª(ÊÁƒSSSÝÝÝ9޽½ýÓO?­V«ÓÓÓe2™@ xê©§ß|óM¹\âïžž˜˜ˆ »eee ÃÏÏï¯nçr¹£££~~~Z­Öl6ÿò—¿„îËåÎÍÍA0øÔSOáÛœ ˆ¢¢"rÏàÿµEݳgϽ{÷8Nii©L&ëêêB¯»wïB§ÕÜÜÌãñ0_nuuÕÊ“«‹ŠŠfggE"Qllìøø¸J¥¢R©Ê}ôÑG\.·¿¿¿½½ ˆø¯¬¬àc‰”:A¯’pãÆ £ÑªP(T*ÕÙ³gÅb1^V˜]XXuáÂÇáp.]º”””„èkÖ¬ù:ìR©”Íf¿ÿþûÐh8::ººº …Â÷ß?33óý÷߇&lëÖ­{î¹çöîÝûÍàojÑBBBÔjõòòr\\Üüü<6Ó]¾|:­¢¢"¨‘ŒF£ŸŸŸL&³ô¿~ýúÊÊŠ§§çÈÈÈôô4”¾l6Ûd2ݺu+ ÀÅÅ…N§÷ôô@Y699‰Þ¸G ‡ÒëêÕ«ëÖ­kiiÙ´iÓ™3g /]ºäèèÞÐЀ.žžžP}577ÇÅÅ--- …B@°ººjcc#—ËØlö;w\]]ÿêv…BÑ××ùÔÒÒRrr2žüþ÷¿ïíí½víÚÀÀÀO~ò“óçÏËåò‘‘@ðá‡~Ó‡ø›[NNN8}†ò:66›wÑÏý,í–þ %&&ròØØX:³­­m\\œP(ôööŽŒŒ„:›Ëå’þ"‘O %‰D"!ÃA èèègccãììŒÍ¥xé&‹% F‹‰‰qppàñxÑÑÑT*Ñ¿>»eÝÂÃÃCCC­®]""""##ÿ{ãÙÿw®GuHS,YMóþÊ9ÞV+¦¯[_õµê±¬RøÒ¿þ)±þÄ–WOþõO”Ç}Mv zM={¶¼¼Ü`0üêW¿*,,d0333 ¿øÅ/^~ùe›“'O(•J …âééyâĉ;v¬¬¬|øá‡{÷îmlltvvööö>~ü8•J}饗>üÜsÏ]¸pÁh4&$$¼ÿþûeee‘‘‘¯½öÚºuë †Ùl éèèèìì ‹mooŸšš***ár¹ÎÎÎGŽyæ™gd2YsssII zýˆD¢ÊÊʲ²²•••ÚÚÚ‘‘L-ø«Ûñ‹_®`ÉÉɉ‰‰KKKï¼óA¾¾¾ØÌˆž9sfÆ cccmmm?þñ<¸k×.Ø:„î&ÕùÏþó—^z©½½ýòåË(8ôß$Ngg' ØØØø¯ÿú¯o¼ñÆ÷¿ÿ}™LVUU|³ÙŒ‡ib±¸¹¹9<<<22ò³Ï>KJJ"Ó©S§6nÜø?P(+ûéÓ§©žžž¸ÿ å—ËMMMurrjiiAW††—‰‰‰îînwwwgggƒ®““Szz:AŽŽŽÙÙÙ4 9¨Tª››¾.377W]]ÝÝݽºº üÊÊJ´e*,,ìèèhjj²··ÏÉÉùôÓOÃÂÂüýý;::âââ<<<¨Têäää±cÇCBBNž‘Ëå(EWWFÃíÆÎÎÎÄÄDl+5÷ïß§Ñh–‡©ªª ‡éë.”•½ªªêËÏ7¿ÝYðíú u÷îÝAˆÅbòk‹J¥îÚµ‹ oooœBìØ±ãK;}»¾]_º¨AˆÅâááa¼‡‚X³fL&#bëÖ­_|ñAèlû¸þß®o×£‹:::ŠA•Ä¿øüüüÆÆÆ‚`³ÙÐå?~ÕÃÃo£ÕÕÕÂÂB6›=<<,‰‚Ðëõц¾V8çÿðÃïÞ½û ³þvýí/<%‹Åééé¸Ë@£ÑÐòÛÇÇ'##ƒ  …ò7ÞéÛõ·¶h2™ŒÏçOLL˜L&ƒÁ€n>7oÞ´µµè‘occ£×ë%ÉÒÒ’›››‹‹‹Ùl<O§Óa8€——š;:88 Ì’ðõõU«Õ"‘R*‰Db0pûN­Vã^ “Éôôôd³Ù+++°ÃߟÄqppÀñ™™>Ÿïåå….¦è–ž$‚ \]] ƒD"ÁþA???è›qÖˆ¸<yq8ÅÍf3N·ôG/n¨jIž–ùR(ÔÁ2_ËPŸ¹¹9àÓh4ø{{{ÛÚÚêõzØñ8½…B!”a–øÇõü³ìËËË<ú¹ÅÅEGGG77·¹¹9dg4a7›Í¨žT*]ZZÂQÓh48:OÈ‚æããsèÐ¡ÆÆÆÿøÇ Ð]ååå¹¹¹‰Åb//¯¼¼¼””µZ-•Jóóóe2Ùúõë1é9++kyy9,,,++kݺuB¡ÐÖÖ6333//O&“íÚµklllçÎNNN˜½^Ë^^^™™™h +‰òóóSRRîܹ’››+‰Äb1‹ÅÂ8 £Ñü„„'''‹•–––——×ÞÞþÓŸþ´ººú…^À‹M›6A+ žàC§ÓÝÜÜÞ|óMÆçó³³³===Åb±½½ýSO=µ°° R©BCCsss'&&Ö¯_¯×ë÷íÛ7>>îì윑‘1>>Ž^·¤?¶ágee‘8©©©–ùVTTp8@°oß>Ë|''':„†—yyy333Àß¿?‡ÃñóóC5 ìprrâr¹ ãСCSSSÛ¶m#ñ=<<6nܘ`ggçéé™™™™˜˜øgÙÛÚÚ8ÐÝÝ][[[SSóýï||ÜÏÏÙ‘ª»7ß|sppÐÏϯ¸¸ØÕÕY#;•Jõ¥Y455Q1?»ãY,ÖíÛ·q;ôôéÓááá³³³€vvvÂÞÕÕµººúÅ_üáÀ 訨(½^¿¼¼Œ6p—.]âóù4mzz:%%eii)""B§Ó_*•677;88à>roo/ðÇÇǽ½½ýë_Ã>88ÿùùyàgvvøjµêðÙ€>J|>Ÿä >>>>ëׯ—Ëå˜Éãáá¼fffRRRd2â"¯[·n¹»»—””ÄÆÆQZZjå¯ÓéÀ‡äo•/›Í¾råJPPU¾¨óêê*üCBB€???Ô´#_…B¡Õjëêê0ȃÄ_»víÄÄ„J¥‚ßÁÁáϵ¯]»¶­­mïÞ½===|>Y›L&d·oß¾žžl”ËåÝÝÝèÛ‹j dú¥YP(”ÿ|Îår Åì쬿¿ÿ¶mÛúúú¶lÙrõêU AÁÁƒ“›‚øéOzíÚµÐÐPtñ:yò$Z'%%©T*³ÙÜ×ׇÏÿ .DFF||<))I§Ómß¾]§ÓiµZà›ÍflW‡ÝÞÞþáááÀNPPðÉs>­V;00€áx*•Ê××<ÁG«Õzyyݺukvvvrr²¬¬ìêÕ«®®®F£‘F£!.Z6...NLL`¨Äì쬃ƒê@ú“ÝÏÀ“Á`Xåk0Ö¬Y£R©¬ò[ÒttøðÇnoµZ=88;òõõõMMMmoo_^^¶ÄG2¡PØÕÕü?××ÑÑ¡R©ÐnY‡……!;ØÃÂÂP½œœœ¹¹9&“‰j";²JVYüç“+ggg‚ üýýýýý¹\nhh(FóDEEÑétŒ#í¶¶¶hÑÊb±¢¢¢ð–Çÿ6??????‰&LÀ>F‹ˆˆàr¹o$ OÒ íð·±±>‰|ÒŸÇãEEE¡‰ŸŸÉ“äC„‹‹‹]LL ŒÇ××]¬CæåéééïïO¡P"""ø|¾•?ɇäi•¯ƒƒCDD]–ù’àOâ“þ¨i'óE“íGñ}||¼½½Iü?×NÎ …4 Y“Ù‘vTN§#:Y d÷¸,þóþɯ(ÊãûXÙ­üÕiYÙ­p§²²|¥ìq<­üåOþúgµæúJ}Ò,âú{|°FÙ¶m›X,®ªªZ¿~}{{û¥K—JJJðÈZ,WWW—––ÚÚÚþÛ¿ýÛüãìÙ³‡Çã9sfÿþý+++¿ÿýïaß½{·‡‡ÇÉ“'+**VVV0N¥RFK|¹\^RR¢P(h4š%ΩS§Ö¯_?>>N§Óy<^]]ÝÖ­[ Ã/ùK𙞞NLLüùÏþòË/£ã9ü±eôÒ¥Kè¥þÛßþöŸþéŸ8PZZzëÖ­ÈÈH[[Û'N€Ïòò²··wUUÕ† ,óÚ¾};ÎÀvïÞm™×þýûœœjkk׬YýÊ+¯ -øüêW¿zùå— C]]]aaáèèèòòrhhhwwwDD„Á`hllŒÇ©gbbâ[o½åèèøƒüàÓO?…ý7ÞÀ׺ÉdzñÅu:ÝÄÄĹsçÈ#´gÏ''§#GŽà™÷ßË¢^¼x:ªÆÆFlùJJJ …¤ýܹsNNNÚA„‡‡fU …BGGGÒŽovvv°Ý½{×ÕÕÕ _.—?~œÏç[á°X,&“ Toz½ÞÍÍÍÁÁ|ZZZ †««+𻺺Âø+++555·oßF»‚ *++ CSSø“|FFF †U^AAA'NœHMMµÊË××â}à›ÍfK>B¡<³³³?þøãĽ}û6ìwîÜQ©TŸþ9ü ‚صk—Ùlîêê‚ ˆC‡=ûì³A899ét:???Xð/àbB,é\Ö¿ÁEõõõÅì9üž yì¾¾¾¤ì •––* FCN¤/^D;Fƒ9<èok‰¿¼¼ e•NlllCCǃ=  §§ÇÙٙ䃗ã•M`` üIüüüüææf214yðqssãóù}}}VyÁf³íìì¬ò:zôhttôââ"ð­øLNN‚§^¯‡ˆ ~#Š· IDATq1„'UOOO‰DâääDÚïÞ½‹‡P>zxxܵX$‚ Lö·¹h"‘I¯×ÏÏÏ_½zµ££cll =OÏ;‡ º;wîP(”‘‘GGǘ˜˜Ó§OCèÓÙÙ ;z*×ÔÔàš¢»»;''çêÕ«AXâs84ž››³ÄihhHLL¼víÚââbLL ôa555àUÝýû÷=<<¦§§›ššào6›O¥RûúúVVVÀ‡ÅbÍÎÎbj©'»zõªH$¢P(ƒ—6d^Z­666öøñãŽŽŽ–yyyy±X¬³gÏ2™Ì¾¾¾žžK>###‘‘‘—.]š›››šš‚}``€J¥’ݳîÝ»×ÐÐ>¤}ll ?°Ùl‰DÒÞÞ~õêÕ‘‘ØI&“ippÐrHÛ·ëÛõnÑòóó“’’lmmÓÒÒL&…B)//_\\‰Dyyy©©©è* ‹ÝÝÝ FFF’““¡¨Ü¶m'>>Þßߟô÷ððˆ‹‹{ðàN/--œœÜ¶mF#qŠŠŠ‚ƒƒ{{{á/‹³³³srrÖ­[§Ñh***nܸ±fÍšÌÌ̇#îž={ †»»;ìééé!!!###«««^^^_øJ¥²¸¸8<<||||ëÖ­+++>>>À!¢´´*õ&“™ŸŸ?22²qãF“É´ºº 777ðÏËËó÷÷ŸÝ·o¦Œ–””ŒoذA$1™Là°ÙlàoذA*•’|Èúlذ!$$D¥R¡þqqq¨çš5kBBBîß¿ú°X¬õë×c¢¿¿¿F£¿··wAAZ­.,,DsáíÛ·ã,DZ  Àßߟ<^J¥2>>^&“•””Œ¡z*•jÇŽALNNÂŽjàU–YK¥ÒÁÁAT}bKKKE"Ñàà õâÅ‹l6Zdÿ­[·677———oÚ´©³³³¤¤dóæÍ333T*õСCØë7??ûæÍ›¯]»¶qãFàèõz<`³Ùðïí퉉!bË–-ùùùNNNØ—Èmãââh4ü333 ÃÄÄÄÙ³g&&&ÜÝÝ)JIIÉÐÐPzzºJ¥ŠŠŠò÷÷‰DÓÓÓ°geeOvv6&ù<..ðµZmZZÚôôô¦M›À8iiiððàÁÐÐ^¯ÏÈÈHÔ‡Ïçß¾};//öŒŒ ä‹­( ÅÛÛûÿý¿ÿçïïïìì¼nݺ‡‡ÄÇã)ðO …‚¼¶mÛ†ú£ž2™ v²>{öìQ*•ˆ»wï^øƒŸŸêæîîŽúà8îÚµ þ;wîD¾'<<líííQ½ÈÈHN—ŸŸ;‹ÅB5¬²ŽŒŒD999¨6¢..ðsrrêëëÑ«üãêê ‹•‘‘qöìÙÁÁA¼cP "¤R©àÆ!KKKT*<Ÿ{î¹þþ~\ ‡††šL&à€¿P(DûÑÑQðO³ÙŒ¼.\¸€ú£žr¹öÂÂBÔ³Öwî܉¸W®\?øº©T*ÔDZ—––È| ëëëÁ6 Õswwwtt\YYyþùçûûû###QÅÅEˬñ3NÇ8úƒR©T­V‹güxÎC …hš`0æçç5F£¹zõêÇËÊÊÐÊl6××ן9sfpp0??ŸF£ÉårØkjj***úúú€355…$uuuð'B©Têõú·ß~ûÁƒþþþ¾¾¾ÀÑh4ëׯW©T---ð …ÁÁÁÎÎθhR*•AŒŽŽêõú›7o>õÔSx²™””444422¢×ë1ÉÜl6Ÿ?>**jxxøqqI|‰D¢×ëÀ8---ð_\\ÄH0ðT«Õ¨O@@@TT”L&ƒýÞ½{ÈW«Õ‚ç»ï¾ÛÝÝ=999<<ÜÖÖf6›þmmm>d‚Èkii õ' ì¨O[[[||üÅ‹wddþ$OÔB¡ >8ާN‚UUòuuu•Ëå`;>>ŽêÉd2*•:33óë_ÿº»»{ll Õ‰D–Y+•JdÑÒÒ‚j?x𠬬ìòåËdÖ_rÚEnÇýG>Yu²ìnûŸx§Ø ÇÊnµðXãQ7ÒþhG«?1.^þ(þãø<ÚIëKóµzÕ£<·¾r{¾UÜÇ>$%ã¿Z̓ùÊê}eÿ0Àþׯ333~~~«««‹‹‹¸?É`0üýýgff0boiiI"‘LOO£ƒ^¯ÇG¢Ñh ˜žžŽJ¥òòò‚ Óš˜L¦%¾Ñh YZZâp8–8äÔ1ÒŽ3ß……;;;lìZ­ÖËË ýº‚ƒƒ1àÏßߟ%ŽŽŽKKK¾¾¾ÓÓÓ¾¾¾nnn«««ÎÎÎBE–y?n¹©T*Ü„4È—ÇãyyyÍÏÏãæäööö\.—ÏçkµZ±XÌ`0ôz}pp°Á`‰Dd\&“Éd2Åb1‡ÃAãVô?rssc0°[öÜòððÀAË–¸daÉr®¢å¯–?Xý OÒ?à‹›\f³öÇM#·Šò¨¿Õ¯´M›6Az†®>üÞ÷¾ççç'‹1X,11177;Ç«««Ÿþy;;»ÑÑÑïÿû ׯ_‡ýÅ_äóùvvv{÷î…®ËÓÓ³¸¸{|I|6›íëë[XXa‰á@VVìóóóÉÉÉMMMà3==}èСÖÖÖï~÷»ñññ E*•feeÛD8pãÆþð‡ÕÕÕžžžEEEƒ!99977W¥R‡‡DjIII–y½øâ‹ ÃÑÑq÷îÝ–y½üòËèÈJ§Ó8ÐÜÜü /|:;;:”œœÌ`0pÿ}||¼¨¨ˆÁ`äçç'''wvv‚çèèè¡C‡šššâãã_ýõ‹/eeeaz ‡ÃÑét/½ô’J¥*..ÆžU;;;‡óì³Ï¢°¸Fû{YÔÊÊʈˆˆùùùÎÎN‚ BCCqâ »V«½råŠ@ Ðh48qÁgRPP‡ÃÁMHØ—––pMûíÛ·ÑŒÚ ¿³³svv¶»»Û gaa!::#¼¼¼||| †··wXXøÜ¿Ýfe2ÙÌÌ …B?ð§§§õz}}}½L&Ü˾zõ*øwvv‚Ï'Ÿ|âìì|ïÞ=«¼X,Vkk«T*}4/.—+€ïëëkÉgyy</_¾Ìår÷Ê•+°Ëd2__ßwß}þ666è<­P(`'â¹çžûÎw¾CƒÁˆˆˆ Óé°à_[±7oÞl5‘ëovQËËËÛÚÚ\\\ð»R©ôòò‚ÝËË+%%eff†üîÔét¸Œ-öä# eˆˆ€=--M¯×3 +|//¯­[·Zᄆ†bx$ì4­¡¡A¥R‘|ðr•Jåáá! ]]]áO⧤¤à6ž*2 ðOIIŸŠŠ ½^Ïb±¬òÒëõ‰‰‰ÓÓÓVy9s†Á`ŒߊÏüüÿѼBBB [²ÌËÕÕ£I|+>àI¥RCCCq.…¸$²›ù´ö¶ñuss“H$x9¹ÈÂþúÿÐz\W§'_¼ŽØtZOÖÃ=öQžOÖ·=Y^ö(ÚŸå¿è¥¦¦®[·î­·Þzå•WVWWÿùŸÿ,[[[//¯ÊÊÊ™™™üàÿøÿûòòrxxø7’’’HÝÕøø8v TWW—””ܸqC©T–””Èd2L7©¬¬„Îéõ×_ŽÁ`ððð8~üøË/¿<::zëÖ­äää‘‘.—{æÌ™gŸ}vttôÊ•+À™››CÜ´´´ÑÑÑÊÊʽ{÷644p8Kþ555àC§ÓÑ_~ýúõ‹‹‹uuu–|ªªªÊÊÊ Æ~ô#ðÁÙwee%˜œ9svˆ¸««« †††ºººž{î¹óçÏ766>|øµ×^{öÙgÑ©ü †epcv|||rrrݺuÿò/ÿòòË//..ž>>B¡ð³Ï>Û¾}û7.^¼h²3ƒ=ÃjµÚd2¹¹¹UWW—••­®®Ö×ׯY³ÆÃÃcddÄÝÝýÔ©S¥¥¥7nܘœœ,..V*•4ËåVUUíØ±Ã²>ÇŽ«¨¨8räÈáÇ_yå•^xN§üñÇ`åéé ´½{÷ŽŽŽ^»v QnÞ¼‰£öüóÏÓéô'N€Dä7oÞŒ‰‰¡Ó鯿þ:µ¥¥ÅÆÆC°–––¼¼¼ø|~]]ÝÈÈNß¹s'š Á^YY©Óé@ ÈÌÌüøãƒƒƒ1ŒÅb566²Ùl&“Éb±„B¡D"9qâDrr2üy<pÒÓÓñ­áììlkkÝØØ¡•Éd‚Ä!ãž––¶ººêêêjÅÆ àþÎÎΚ‚›é–|êëëI>°geeEGG»¹¹ Ø‘—@ €ÝÍÍ :Ž»öB¶´´”žžþVu ëž|>| ß¥Óéb±øöíÛx!›Í&ëLâ€çÈÈt8à¹eËÄV©TGŽ,‹Á`g||üøñã\.—®YÕÇÇÇgaaYÐh´Ã‡Óh4œ Óét Õ†zìÈ‘#8j<þ$+òèÀN wñG“­­mrr2ôF¸G R©pR‚'µ8­1™L\.wrrR£Ñ`væêêj@@@kk+yVRWWñ®œá~Éááá8íÍÍÍ=rä—Ë=}ú´D"1›Í×®];wî\rr2ì111ÀÎÉd2Á¾²²rùòåääd+þ³³³àþMMM‹jÉgyy™ÃáhµÚ¼¼úõŒ‹‹³ªO^^Þùóç‘Exxø† ª««IV$ªÍ`0G-''þžžž`…£³¼¼ ;«««}}}nnnJ¥òäÉ“£££ effæèÑ£“““§OŸ†Ï|FGGáæÌ(àP円N7??ßÛÛ›””tõêÕžžž˜˜˜ãÇ ¥Rùù矧««+%%¥²²Óš†‡‡CCCkjjÌfsLLLmmmPPJ¥jllÎÌÌŒF£Q(ÑÑÑèÑ™™yåÊ|»‘üñQßÜÜìééI¡Pð|ãÆÖÖVK>•••QQQ“““'Nœ< ®¬¬´±±Y\\üä“OnÞ¼9::J„D"9wîž¶µµ¡ÔÑ£GÇÆÆ®^½êää¤T*GGGÁßÖÖÖ²à£P(ð`'::úÆ>,**º|ù²ÝÙ³g———ççç[[[Á‡Œ9aNNΕ+WîÝ»sìØ1Ô³§§‡øãó.‰DrþüyÄEËE6›­ÑhbbbNœ8Áçó-ëÃår»ºº._¾<66vëÖ­¸¸8;;»þþþÜÜÜË—/ã‘×ùóç¥R)º!ŠB¡ÀQÃíFô’¹råŠZ­ÆÑY»v-ÆM~éùÙ·ëÛõ—.Z\\Üš5kúúú6mÚ„GÛ·oÇ™cVVôC!!! %;;;,,ŒÅbá4¶°°000P£Ñinn.++Ëh4b²!žŽ9;;S(”¦¦&6›=:::66æçç'š››óóó­ðE"좄‡‡§¦¦NOOs¹\ĵ±±™˜˜ˆŽŽÞ´i“F£éëëC\øûøøÔÖÖr8ì‚§P(ðˆˆ(//ÏÎÎ&ýKKK;::Š‹‹ÁóæÍW®\)--%ýÁ“´oذ¡££#%%øƒáСC111ÐoMNNFDDh4ÄE}¶oߎÓ|ÒŽ©Ø«««ˆËãñêÓÓÓ| õÜ¿?ž¥êtºÜÜ\ýû÷ûùùíß¿tt‰|Óïÿæ¢bß7ƒÁ@+ˆ¹¹9‹zb)•J6›m6›322êëë©Tªƒƒº,F*•Jzd³Ù …»~‹‹‹=j…?66ûÈÈÔÖÖfddq{zzÖ¬YÓÞÞ¾°°žžîàà€¸ð§R©Ši4þ½½½Ø~Îf³áO¡PæææØl6ø£ƒ„.kÖ¬immO¨ïi4üíìì€ý“ϵk×ÔjuNNŽÉdêíí]^^F\ÔG£Ñ0™Ì°°0“É;“Éœ-//G\ìËÀ…›Ížššþêêª@ À¥A~áçç—œœìààœœ¼´´„D‚ÈÈÈÀ¸Ú¿£E%bjjjjjŠÇãÙØØ…˜˜˜ñññññqt›-))ÁAF³ºº:==M£Ñúúúà¯Õj§¦¦‚Àl‚ ôzýÜÜ\HHˆ¯¯/šW[â{zzž››‹ÝyR©T§Óyzz"î®]»fgg===¡Rš››C\ÒŸ „¸ðwssûéOÚÓÓc0àß××WVVÖÚÚ þ.\¨¨¨èííݹs': €gss3ìðÿâ‹/€ùòå'N À„úƒ655•––â|8(ŽŸŸriooýõ×kjjž{î9N'“É^~ùå‡òùüòòòÁÁÁ²²2:>66VVV–™™i2™WXX˜N§S«ÕO?ýtlllWW0¡ojjúÑ~dÉu¨¬¬üÁ~ R©är9—N§OLLçææÊår˸£££¯½öÚØØê|ðàA‡ƒÛÚûö훚šÚ´iÓàà J¥Ú·o_JJŠeõÈ(®®®óóó±±±B¡ÐÆÆQÒÒÒ\\\ÜÜÜ^{íµÆÆÆ€€€ŒŒŒ[·n-¢Ÿ>}šúé§Ÿº»»+•J¹\®V«“““mmmY,Voo/•Jíêêrwwß¼yóòò²»»»››ôàKKKËËËõõõr¹wóöïßçÎ*• ûàà```ào~óƒÁ€–,ÀÁ ­-[¶°X¬¶¶6©TZTT455¥×ëãâât:Ýãp°‘ŽØlv@@À_|aoo¿´´£Õj EVVFÂ>ʳµµ•Åb™L&Ä Ÿ••Ä…?A]]]A`$,ž*FGG«Õj;;;±X<;;‹|Ñ4&338,K¡PàÆ„···D"ùì³Ï Ÿ>ü!ÆR«Õ:y!.Z‹YòA›••5??¸À¸zõ*fvXÆ C=CCCQgÔM¡P ƒþëÖ­kmmÅ_Éê‘QpôÛÚÚP ‚ ð*¼[úûûezzY€-ǃN§SwïÞm00ÆÒÑÑ¡¯5 2™Ìd2µ··«Õj´éÆJNN¾yó&ùëÄċʼnD¤](êtºêêj›¾¾>à £m—^¯ONNžššêíí‰D‘‘‘/^Ä~¯/Åáñx---aaaÓÓÓsss###óóó---b±#q÷(ÏÄÄD£Ñˆ.†ÉÉÉwïÞ©TЏV§­­­ÀÙ¶mÛÍ›7™Lfcc#¾¸á022233Ã`0€C¥R'&&°¡E&“ÙÛÛ¿õÖ[·nÝ >ü———Qgìœ!ûf‘u&ùu@^äé&ð1Å0-㺻»£ž“““¨3ê&‹Q‡••øGGGß¾}›ü«U¨ÊÈj¯Â»…Ïç#н½=²[‰DBÚ WWW‡“*œýp¹\(»qæäåå…§Ehk©…|>'ãø• G¥R­ìÎÎθ6AR©b_‰D‚LÐÓ188/¾ÇÁÁ!88 ///*•Šy§¤ÝÓÓS$=Ž'F ²··'ã‚e\øc‰cooD£Ñ$ Tp³³³C\àP©Tà“þè Åd2Oú“u&ë†åƒ: /ÒÄ÷ôôôôô|4.êIÖ™¬ê@úGGG[VÕ* yôQ òUä»…ŒbuôI;A<¢["×ã9äeããܧ+úR´Çá<ª—z2½'ðÇãi%0úJbÓu=*Ûz² í+×_øòovQvîÜéééY[[»aÆ•••ººº5kÖ`¯««kSSSHHH||ü|PQQqîÜ9‹åêêzêÔ©çž{nee¥ºº÷ ÿýßÿýƒ>x饗¾óïÐéôýèG7n´±±ÁÈ]ÿg?ûìF£1""³‡VVV>úè£Ý»w744DEEÙÛÛWVVVTT0™Ì×^{ÍÒ¿½½½³³óÕW_ýÝï~WTT¤R©þð‡?|ðÁ?úÑž}öÙÅÅÅ·Þz þL&ÓÕÕµ²²²´´t`` ¿¿-h=jÉóÔ©S¹¹¹2™L&“¥¤¤üä'?qqqyõÕW=ºnݺ±±1;;;àhµÚW_}õÃ?D¾ÐÒ|öÙgO=õÔÊÊ ôReUUUEEECCC¨çèè(‡Ã9sæÌââ⫯¾ ‘;‹ÅÒëõééé  ‹Åâñx{öìihhÀˆ¨¿»E­©©swwW©T‹‹‹ÃÃÃjµú£>„m½^öìÙöövŒ®„ŠÁ`Ãff¦§§ÇÑÑ1''ÇÞÞžF£½÷Þ{ø"‹çñxVøÞÞÞ°CÁs÷î]Ø‹‹‹ÑmWVVΞ=‹‰À–þ;wî\ZZ=qâ›ÍF\GGG½^ïêêJú;v,+++**J$eee}üñÇR©ÔŠgzz:ì---ø$>Îù¢££“œœ ûÐÐòõòòêêꊎŽF;IÒŽ|íìì·»®ý>å IDAT»õtvvF^À!"""âðáÃ\.—Íf!‹aINN>|ø0Y‚ \]]IÎßË¢úøø°ÙìÎÎN;;;è{°QX(Ö××K$¨,T*Õo~ó›µk×b›n"ØÚÚº¹¹ ØÛÛ'&&ÒéôðððÍ›7WVV¢ÅHxx¸~RRì<BØ5MKKKRRÒõë×ëëëÓÓÓ¹\®F£Á³ÒÛ(¤R©££ã¾}û>ú裵k×Òétgg玎@€GàÐWÙÛÛkµÚþþ~|€q¹ÜÕÕUø“<`G9psA*•666úøøày ÎÌ`‹‹C¾Ÿ|ò v4Éåò™™™   Ø‘ïÝ»w—Üx}íÚµúúúM›6b›ææf< ¼qã†\.§ÓéÍÍ̓ƒƒÍÍÍ“““(A|>ÿQüßø¢EEEQ©ÔÙÙY*•Šk´ÕÕÕ±±±……©TzþüùÕÕÕ‡ÆÂ‹/vvvB…‡Ž÷îÝËÎÎniiùüóÏGGG;;;£££¡{¼~ýúðð°›››%>t]ÃÃó³³333£££ÎÎÎSSSçÏŸOKKkiiÑétÑÑÑÕÕÕ¡¡¡“““Ї‘þCCC.\Éd ÀÞÞþøↅ…µµµÕ××ú¥ªª**•j0Ž?ž››ÛÔÔtòäIKžMMM™™™MMMJ¥Òd2Ý¿øãããaaaÕÕÕ111G={ö¬L&ëííE¾¶¶¶vvv§OŸvttT*•]]]°»ºº"":ß¼yõĸòcÇŽÕÔÔÈd²û÷ï/,,twwÛ—/_¾sçÎüü|ww÷èèhzzzKK‹\.W©T“““ßô[åÛõíúX4ô£¹ÿ~YY™D"¡Óé999áááKKKh×Q\\œ––¦V«÷ìÙsýúõ¸¸8L™ËÈÈV«Õe Á …bË–-J¥ò©§ž²ôß´iSpp0…B~ww÷æÍ›‡‡‡7lØ ‘HÔj5üI>[·n S©TÛ¶m3|>Û¶nÝ111±cÇèÆ ‡††VVV,ã&''çää(м¼<‰DÒ××'•J}||¢¢¢À3,,,88xvvvûöíhÇÖ8 ¤,--mxx*møoÛ¶Íd2­¬¬Xñ)//ˆˆèëëÃ.’ØØXÄÍÈÈ0™Lsss°‚g~~~XX˜B¡Ø¹s'®ÿ¡W+++³Ä'í&“iË–-r¹vÔmûöí–uvppþòòrRRÒºuëÒÒÒ EYY•mÆ ÁÁÁ333VÕÆQ#í~~~………*•ª¨¨Èò]_XXUÜ–-[zzz¨èï+ Ñ2 µZ½sçN¨kkkY,Öèè(Ž—””´µµ•””lܸQ«Õr8œ[·neff666²X,xÜ»³ô/,,ŒŠŠŠ‰‰^J­Vûúú¾ð ¸ƒé.ð*•ªP(¢¢¢ÊËËÏ;·iÓ&ð1™LÉÉÉhqáÂ…œœœôôtœZÅMKK[\\¤ÓéÀçp8À– ¤þ$~AAA___jjªÎÊÊ Fb£‰‰‰h]Dúãñ¥ðÌÉÉ?Yø“vðÔjµccc¡¡¡¡¡¡z½>++ qCCC­ðI;x’vÔ «:vv6//o||Yäåå¡=6‰†W=Zm+;²Ãe¾å»‚B¡Œ………AÔÅÅEè¥qï5==ýܹs¶¶¶J¥rË–-))).\ uH ÏUæææRRR¨T*“É„ž‰Åb-//'''ãþ§¥?¶nÒh4üçž{nxx†þàC¡P¦§§íììËË˹\.ø”——WUU¥¤¤LLLlذáèÑ£4Åb¹»»[ÅmmmU(%%%Àß´i“ÉdòõõOµZ þ7oÞ>Äé®®®V8ããã|>ŸN§£,«¯¯1óóóq+Ÿ ˆ¡¡!K>L&<…B!ü•‚àp8°ƒgNN…Béééa±Xè«‹¸e‰»‹‹ xªÕjØQ7l9¶¬3ðsssÑÛ Y0Œùùy611axz¸‘ÕÞ¿¿•Ùa¹å»âþýûñññ÷ïß+G%B.—OMM988Ðét­V;33ƒÝ2ëÖ­ëêêâñxø‚@;×ÞÞÞÍ›7766¢£Ç‹‹‹²hll¬¨¨èééÉÊʲ³³Ç«ÔjµeµoÞ¼ie'³³zWTTT@ AVï¿Î¶½Óýd}©—úJ½‘•¿ÕzÜvÒnÕé¿Áóqø–žGïQü'§óhÜ?WößÓ‡‘ëQbèo`ÕvË*ŠU5¾Òþ•‹†!3*•*00peeݘЪ£   •••åå嘘½^¿¸¸èáὑ···R©d±XL&=gá¿´´¥ÓéX,p|||¸\îììldd$A666¡¡¡° …Â………ˆˆH4]\\Ð)žÏç/,,„……ÙØØP©Tà +ßìì,ðíìì¤R)$DÀÖÖüõz}TTú] …BtÿÖëõL&’#àÓËHžf³ÙÛÛ[«Õ‚çÊÊ p$ òBS@àìì ž–qgffPËÆQD£R©,K(‰ÑÒnÕÈêÑõ8ûãÌf3Úò>9Ê—ö»z‚ýÉ‹ö /h4š‰‰‰ÜÜ\4 òññIKKKLL´µµµ·· uttôðððööÎËËëè訮®®ªªzñÅ{{{'''_|ñEŸŒŒ K‰Dboo_PPàèèˆûÔ………111‹‹‹±±±hSëèèèä䔑‘199¹iÓ¦þþ~vàÀ¦¦¦×^{-66V.—Þ˜˜èèèèìì•““5bAAÁÚµkWVVÜÝÝ·oß{íÚ5±Xœ––†¶¹ØiŽs^ð_YYÁÞ¡ŒŒ Ò¾fÍð÷ððxå•WÆÇÇãã㇆†víÚeY2¯ÁÁAKždÜÛ·oWWWWVV...âªÙl6ÿð‡?„êP(j4©TªV«_ýõÉÉIôƒüß·¨>>>P’¡P(‚ƒƒß{ï=ƒÁ§ÕjaŸ››KHHXXX8pà@WW——'%%ácÆÊßÏÏïúõ맺º½–¡CBƒäíÛ·Ã>;;{âĉÙÙÙÕÕU\r÷÷÷ãj4PÊÏχ¿F£¹~ý:fƒßÎÎîæÍ›ðW*•à¼á???þð÷ññA\­V ;ø †ÂÂB…B žVõ!ó²âIÆE}0äâ½÷ÞKLL$ÂÝÝÝ—Þ{ャ¬,Øåry^^:“ïØ±ÃÎÎî›|#üµuxxX«ÕB#屃ƒƒåVq__ß––.—;22bgg'är¹Éd²±±™œœtww·òïëëËÎÎÆüA´\ÃèÛ›7oF;;;ØœœÞ~ûí;wîØØØ(•Jìa'þ¸‹|~~ž´ÃOý4M?ðu:]ZZÞµóóó˜8¬×ë‘—££#üÀþ>DÜ   ØÁ?((èîÝ»îîî2™ <­êCæeÅ“Œ‹ú¸»»ëõú½{÷âòÌÌL[[›‡‡ÇÞ½{¯\¹ûÂÂÂòò2…BQ*•gÏžµêÝøw¿˜L¦D"¡ÑhŽl{jooHÚét:>‚àr¹T*ÕÙÙ =¥?•Jõ÷÷g±Xv “&" Oß`GŸ*[[Û€€àƒ€H$òðð R©°“þîîîèã |6›Áyð'_Næ’?é¸ v’?AhñžVõ!ãZñ$,ÚÅ¢>–Eööööòò²:í±¯óØ~Ó˪ÓW6RzÜU ùªÇ]…Y†{4îã.7ÕKYù?®–ŸGeR_ªÇzœÿ£v+ÿÇ Âž \³Z¢ŽÍŠØãêÿä¸V}B•žLþQÛF?tè‹‹Ë™3g Æÿý÷ß~ûí]»v=óÌ3|>ÿìÙ³±±± ï¿ÿþÎ;ëëë1e©¡¡!333!!áwÞ)--=þ|LL ›Í>sæÌ3Ï<ƒ¾YkÖ¬ñòòêè舊ŠêêꊌŒ\ZZB£)µZM¥R]\\*++7nÜÈd2>¼{÷nKœ¥¥¥þð‡~ø!dÔ ƒÏç=ztÛ¶m7nܸÿþž={àïââRWW‡9Ê555¹¹¹Z­–B¡°ÙìÊÊÊ={öÐét<„ÖjµKKK"‘¨¶¶¶¸¸øÆÓÓÓÀHKK{óÍ7ß~ûí•••'NÀŽæ>$ÏÏ?ÿ8>´ô?|ø0êvðàAðß¶mÛƒÚÛÛþóŸïÚµk×®]"‘èÒ¥KAAA /¾ø"¶}/..FEEµµµEFFÞ¸q£©©ióæÍc8;;×ÖÖ¢ïÍÑ£GŸþùúúzŒœ¨ªª*..~ðàÁÍ›7Q7///त¤XòAܪªª}ûö >|xË–-¯¿þ:ùךšš 60™ÌãÇ[f}úôéýû÷¶¶¶’vË£ó³Ÿý Ù•––FEEµ··ÇÄÄ0™ÌW^y…Êår¡Ozçw(ŠL&ÃuŠH$ºs环¯o]]ݵk× Æêê*“ÉLIIa04 öððð••è¸Y,n™òx¼®®.¨ÿ*++çççÛÛÛ¡—´f2nMM@ @9,q***t:NG—ð‰ŒŒlhh°³³#ý±-›Ôc ööö ମ®"¯ØëêêÐÐ8$~KK þ«?i·âIâXù“uC\<<õööV(°WVVŽarøµkרTjLL —ËE}À‡ÏçÃîïïìØ±Í›7ãf}@@ê´ÁõööNKKCH+>ð'‚ÏçãÜÃÃc``Àò¯!¬²¦Óéxi·::r¹œÄAtàAutt¬­­E¬S§N‘Ÿiü1îççç_¼xz¬5kÖ` GÆÇ¾Ïƒìíí³víZäåëë {hhèÅ‹Ñ}” ˆððpàãW@þ °[ñ”J¥À±ò'ç"n|||?:˜Áýûýû÷Q·ÔÔTèÆø|¾Ñh$»“v³ÙÌårñ\‹Á`LNN¢þÀééé¾­­-êì°äCÆ=zô(‹ÅZ³fÍ;wÈ£Œ¿"»ØØXˬ¥R)^»ÕÑA3UüïB¿àØÚÚÒ´Z­T*=wîÔòƒƒƒz½~||ÜÛÛ›ÉdÖÕÕÑh´þþþ¥¥¥‚‚‚ææfè±NŸ>½²²Òßß¶0x‡EGGŸ###™™™–8IIIEEECCC%%%R©úªååe©Tš››«P( ömÛärùÎ;mmm'&&Êˡ‡‡Ñ— ýÀþ{WÕä•öïûf' ¶BJ@ ‚‚JÅwÀ•V§*µµué™™¶:Ö¶_§¶==ÓNg9gfìëÔãÌètµ–ÚZ-S[)âÎb‘}Q !I {òýñ´ï¤Ùx߈[›ß=örÏóÜ›ûn÷>‹ÕjO#¢F[´h‘B¡‹Ål6;??ÎŽ`\IIIÐåÊ•®r ýúõ륥¥IIIÇ òA›Íöðûf½’Ëå+V¬‰D­­­®¿ L¬kŒä=Ül6C7>ŸŸ““réÒ%x%ìîîNLL€qo†aÐKðáÆår …ÕjEq8›Í– P(˜L¦B¡(**‚‰E÷f~,Ú²eË Ô ›ÍÖjµfΜ9}}}999f³ydd$11NX¡‚ ¾øâ ¹\Ž:tèDûCŒ×ñãÇår9ì'­Zµªµµµ««+''çë¯¿Ž‰‰—1©TzåÊ7½gÏžMNN&Ú¯\¹R^^IlfΜIØ344ë*'%%…ËåÖÔÔ¤¥¥!„ªªª$ICCŸÏOKK;}útEEýæççëõúwß}—Çã]¸paÇŽýýý]]]P5^.— …ªª*HÒN—.]ŠŠŠb2™—/_.,,D;v Å“““…Ba]]]qq±Ñh¬®®NLL„O³Ù<<< ÷¹k×®A5²ììl³Ù<88öTUU©ÕêÏ>ûÌn·GGGCi´£G;v >:;;a› ¡¡¡³³³©©é®’[·äÝ€¼ú9Ž;ž{¸þý¨<ÕQÝÙ÷åÿDÖsÈï¸<õúU·ªŸ6hqqqÑÑÑàÝ!•JÇÆÆàn<<<œ`0 ]§ÓMŸ>Ýd2Á§©Á`ÉdÜ"77wllL(ÆÄÄ@þ§¤¤¤ÁÁAHcÂçó322T*Ujj*Üð¡¾2¸DBñ>¨˜››k4 ùr¹<>>^©TfggcF§Ó³²²T*è{FFF„BajjªÝn—Ëå±±±à§e2™¸\î”)S”JeZZ‡Ãƒþj}§¦¦BApjÀ0lÆŒðÚDÈ1 Pü‡è?<<zôhvvöîÝ»ÛÛÛ…B!d€ýøã;¶téÒÂÂBÈ7¼dÉ’k×®œ^x¡¡¡aþüùç&—Ë!D¤ººúÙgŸ…‚Ø ,ÿ» @)ÊÒÒRôèÑ;wöôôDEEegg···ÏŸ??,,,"""77·°°P$|…Ba³Ù`+å‘G+W®©T 5]ˆþðâ,Ö¯_Ÿ““£V«A/Ô¦S*•‚‹ÇãÑh´’’’ûî»ÏµÿÀÀÌTµˆˆˆX¿~}CCC^^‹Å*))™5kŽãð#¹Úã6?‘‘‘0Ï›6mù7nìééáñx ´´ì »wï¶Ùl ?++ Æ»`Áð³€ù™;wnXXXTTTYYYOOO___|||AAÁ´iÓl6[WWWffftt´^¯ä‘Gúûû‹‹‹›››}ôQ(Þ¹fÍ×Ñ…†††……‰D¢©S§.X°@¥Rµ>ú(ì‚–••544ˆD"è³×××·{÷•J…···›Íf&“Y\\¬V«!Œ744æ­µµææ9""ä`& !w#„²AX…íƒaÞ¼y½½½n£i±±± …F£AÿÐÐКššÈÈHEJJ ô‡ÙCAû÷¯¡Ä²G"©T 'M<z@z'±X Q\Ð.‹Åb1“É”Édàê r"##'MšÄ`0’““Á‡I*•â8.‘H ¿tƒ@"„H$‚°t7½111à¿Ù„B¡X,æñx JA»Êçóù†v†‡‡ƒ×!è%ì!Ú¡R¡’‚‚o|ˆ$%%Á©°kB>aŒ—èÏår]å¸Î›ëüz ù0^ÏvâwùÄxaÞˆù!Ú‰yuÐ 6£-¦Ã0·Ñ¹i!ú£ƒQý‰Ùƒöï_à}yÞ¸ùy~æøÊ;å%‚ŠZñ*Ç—nk<¿æ|Ù鿯äË OE¾¢•H&¸úI~6Ò6nÜXTT4<<¼{÷n™LÆb±zè!‰D’››»páÂáááíÛ·Ï;·££cÇŽ£££ .,**)//‡´§>úhzzú¥K—##ƒ°ç¥—^*,,„Øn™L6kÖ¬9sæ(•ÊíÛ·»Ê …7nô§Óéo¾ù¦Óéœ3gÈ!Ÿ/|Ébyà­0Àë˜IDATzÁ΢¢¢±±±˜˜˜–––k×®………=4 ¼‹æÎ{ðàAØÕ„rŠnò¿þúk§Ó)‰`¼ýýý äÏž=ôrÜì„´M‰‰‰nòáûü­·Þ‚× „l¯¿õÖ[o½õ–J¥E!±X,“Éîô’˜àõ»¹¹ùÈ‘#l6ûÃ?‰DV«Õáp„††BØ \|óÍ7¹¹¹YYY§NŠ‹‹kmmÅq<**jãÆ‡ÊÉÉa±Xéééо|ùrð+‚þ‰dݺuï¿ÿ¾^¯9áááf³9222""B.—³Ùlh‡š—)))¾ä€\.ô‚­­­UUU|>?%%¥©© ÎéX,Ö<þIpå8ŽsçÎ?~<''ÇM>L²Ùì„„ãt:CCCõz=èµX, ÇÍNƒö»É …ýýý«ººªÑVTT´¶¶VTTDGGƒ"„¼¢ÝÉå0q Abx‹ÅyªÀGç£>jii™6m€€§NAAAee¥Ñhÿ$»Ýn0úûûá–pðàÁööv¸Ÿ †Ã‡_¼x±­­Íd2ÿSjj*ŸÏÿꫯfÍšUYY©Õjººº¾üòËîînB~cccZZÚ§Ÿ~j³Ù¼Êý·ááa¨L^SS3mÚ´O>ù$++«ªªª­­mþüù•••ï¿ÿ~{{{uuuXX˜R©ØŠ«¬¬¬¯¯ùÉÉÉ*•ê“O>9---®v=ztΜ9IÀUþåË— ø'Y­Öôôt¨G|õêUh·Z­ ¨¿¿hhN±‚"ï Íž=»¤¤ò0edd€ßŽãÙÙÙÑÑÑP˜O£ÑlÙ²¥ªªjÖ¬YüÐC)Š–––Ç{Ìf³¥¤¤wwwCú(§Ó¹aÃ!“ÉÀOkñâÅr¹œÁ`,Z´(;;vŒ7lØ •J›ššÒÓÓe2™B¡ÿ§‚‚‚¬¬,F³nÝ:8çùóçχâ«eeel6›Ïç/_¾¼½½òiõ÷÷?ùä“UUU¡µk×¶··¯]»6##£¾¾äC~©ööö5kÖÀxŸxâ &“ÉårA΢E‹äryww7Œ+""Ú×­[g·ÛûûûAŽD"{`ß™_\\|ãÆ|6fyäÇ!Vkkë/~ñ ©TªÑh ww7ØYVVf·Ûm6ô—J¥ íÚµYYYv»æ-$$~¯+V@®˜‡¸¸¸üü|(ü”••U[[›“““PXX˜][[ëªÅn·ƒv©T ^kp†100à6ÛPw²®®FÝÓÓr–,YBü 8ŽO™2ä”””Èåòï¾û‡‚Õiii™™™¥¥¥'Ož,..>qâ‡ÃÖÙÙÉãñ0 +**:sæLII xA´»Ùl…¾æææÄÄÄÔÔÔ±±±‚‚‚ Ô××ÏŸ?ÅŠpóïèèèëëƒäúqqqà=B§Ó{챬¬,ÐÛÒÒÞ±«W¯>vìØŠ+@~FFÈáñxÇ/,,„<'v»ì×h4`gJJÊ–-[8´òÁþ¢¢"h—Éd"‘H­Vƒ Ã@>1.B>Œ‹F£°'-- ì$ä@û¼yó`\>ø Ì'ÌìJ+ŠäädèOØ ò‰ù'æsöìÙļÁï5wîܘ˜˜¤¤¤èèh˜‡Ë—/ƒôG€—s__Ÿ›ÂZ¨_§Óéà×t›m¹\¾víÚY³f£9|>fiÕªU`-È¡Óé`UHHÍn·K¥ÒúúzxUïéé³CBB”J%¤’·!­VK§Ó•J%±«T*ûúú$IKKKjj*µZ­CCC2™¬©©I£Ñ…BF£Ñh ‰mbbbmm-›ÍÆq¼§§'11ÑjµŽŽŽ*•ÊÁÁA½^zÇÆÆ0 kllÌÈÈÐjµ©©©­­­ƒÉdvuu‰ÅbHŽªR©¢££‡Z­K­V›žž~öìY­VËãñÔjµÅbùCCCJ¥’N§[,µZ}ýúõ®®®„„F£R©&MšvÂÑ“D"üŸPæÉjµ‚:x—Ãx1 S«Õ §µµ555õâÅ‹ÑÑÑV«µ³³泿¿_(vttðù|«ÕÚÖÖý؉‚tSÐä455ãdO©­­‘J¥W¯^5™LP¨&66¶¥¥Ål6C®W('®V«i4šN§Z b¬…ìyF£‘Á`\ºtÉu¶›ššX,VGGøŸ FEE={V§ÓA™8[Cµ··ŒŒ„……©Õj+¦L™r‡žÂAü”ñ}e="þi\ŒŽŽB– ëçÀB1™L’,¤L¢Cˆ)<žý€Åb3YLƒ^¯R© 3“ÉäpBôzR©¤Æ Ñ먱BÇjµööö’g±Ùl&‹e2oܸAžIfôz}__yŸÏÇpÜb6wwwßêÙ€lá:ŽÒôz=¡ !d2™HæÄÀ!ät:ݲry‚F§I$IuµWˆ2¬I±±a4N¤)'ÃFD0LˆÒ$Ï¢ÓéiS3šÿÑFÎÂ8‹Ål2)±“’Œcc®•Àɰpœ=44H‰•(±Ûm :ƒÒl$IecÆ1:…I²$IR“ÉÈ`þoæ¡ ¦–'èt:Ù2@½>Ý]],So0Pb©”J.—k³Z)±%c££ô'D&“‘Ádòîeåü#„Âb±##£(±†‡µ4M30@‰e³Ù8œ›ÝF‰e±Z˜ ›bÎ-“¡Ò²9lJ,¯ Ã]Žä½Îùˆÿõß_’$Åq“ɤÄJH”˜L&:A‰¥Ó°9l:N‰…ã4 aÄÈH² BÈAq6Øl¶Åb¦:‡˜™ÅdQb©ûûccã =%–ÑhŒŽ‰Öi ¥‡ §ÓI'Onüîªy\JwW'ŽãDbò,“ivIDF†5 V ºÞVɰzn\@W{{“:Ëd2uvt¸¶a57]c0™õš}úâÅ‹‡ãÀ”Ì»mÈËË;wîÜÛo¿=::J)AMkkëþýû‡‡‡!c…˜L&ðŵX,±±±###F£Ñõ«ŸÝõIIÀáp0 "¾Åõ¯Dg7–F£ÉËË;zôhiiimm­Û—¿WBÈjµêtºšššË—/kµZ2ºx½Vü³¼>úý³¢¢¢6lØðÏþÓs9úaÙív8eƒÛ0¥qQµÐb±°X, Ã`³€¼.Ç1 £Ñh6›Í‹xêõúmÛ¶ýñ„W(=>dž»<Þ·ªªªÊËË%‰×È$_sÑØØÿÍ7ß”––^»v$ëË/¿ÜºuëêÕ«”²%Ãò?,(¬uñâEâ,l\Vii)Ç[µjÕ²eËžþy’¬«W¯>ñÄ{öì±z;B˜Øq:ujÛ¶m)))£££P® ËétN™2eïÞ½4­¶¶– kdddûöíêÚÁó-ÜûéÅ‹»ººìvû믿îÕ&¯¬#GŽ@ÙÁgžyÆèrúæŸuíÚµçž{.<<|``Àש‘×A>ÿüóþ«9xeUTT\¸paÀ÷¹Š'ëСC‡ö%Ы¶¶öÿþïÿÌf³ÍfóµåèUà§Ÿ~ê?ÒГÕÜÜüüóχ……õ÷÷CÚ0’ºššš>úè#N÷£Bp~Y¸ÅyŸÛ 0õccc^o’ž,âg&*‚a!„t:ë.I–§2,›ÍÉ#ȳ|Mú¸º|EFøgùºZ&|M&Q&Ò+ø¼cxíµ×(ÝEȨ ²îÖ_|€’gƒÔó…ßÿuã AÖ]ÈòÿdøŽÜà‘NuKð³;Ò ²(±¼fÍ$C§#„,‹Íf#)‚xµ ²~¬2< ¾PäY<ŸÉbBumâ÷òO¡ 'ì¼ûïAIÜ­féuº&]£Wºxº”auuz/ð§Ó‰HŸõŽ#g<Øív·ðrºœÈ‰ÐD/&7Œ¿Ýp·­-¢gK¯×#¤wcM,œã¾¼ß%«jË–-pôä‡îŠÈÈÈíÛ·{u ÀB?¬¹sçΛ7* !”——·bÅ J¬ûî»oáÂ…éZ¾|9U–+¦OŸNõ#fü—wJ¸E¬ûî»Ï-i˜ ‹ŠŠbbb¼úq`¡Vrr²¯”ˆþuݸq£±±Ñ³ÝK&“AU[ªº$ ‘Èž< À`0vìØ±ÿ~Ï…éËjË!¤P(Š‹‹-Ë»ï¾ µeÉ //oÑ¢E:îÈ‘#~vÝZÂÂÂ6nÜÙ5}Iöd%&&æåå!„Äbñ7H²BCC7nÜh³ÙìvûçŸÞÕÕE†…Љ‰Ù½{·J¥‚j$Y‰‰‰ÉÉÉž¡¶þY¡¤¤¤ÒÒÒüãCCCäYþá‹%‹_}õÕ¼¼<«ÕÊ`0ÜN£g̘aØçŸî•KùK¡P|õÕWÓ§OðÁß|óM·ž¾žk›7o~ï½÷ ¤ ±)7.kÅŠáááGÍÏÏ÷¼¶|±úûû!>ýÚµkž£óÅ‚š|ðÁÎ;¿ýö[’ºB0¹»víªªªjmm%Éš4iÒ”)S¼N¾ƒÁØ´iScc£k<û¸,äû™àÿ×ß³gO^^ôÙ»w¯Ýn‡mø/Nï½÷|é¢üUh·Û.\êõŠñÅúôÓO‹ŠŠôzý¡C‡È³âãã/_¾ìÕCÚËh4êt: Ã(ì‹ÅâÆÆÆÚÚZ"CBH¥RÕÖÖšÍf·j%ãþҞ㲦NÊd2ÿò—¿Pb«Ëžzê©'Ÿ|ÜïÙ³Ç3ÊÄqÞ±ÜZTTtâĉëׯ“ߨd2™ÉÉÉûöíÓétóçÏ÷Õ ylªÕꤤ¤)S¦Ðh4ò,§Ë,“gi4©Tš’’B¤n#¯Ë¿Æ‰²ÐétÖÖÖ^¸páÑGX]NëÃd2ýþ÷¿úé§ɳ™¯B7 Ÿ:ujñâÅJ¥’|Õ³Ù ¹ói4ÚgŸ}æÇ·–£Gâ8^\\ ¥xI²B===¾Þ®üèr:ðõäkÊ<Û{{{áEó»ï¾ó}EIšÿ¿öõõuuu8pÀápLž<™¼L•Jå™óƒ$œNgeeåc=æ5ìÖ(»Í¼ýöÛ8ŽûzKõ%íĉ'OžôÚÁK¥R½òÊ+ˆâ!ôé§Ÿúú“/á¥Ñhv»Ýk(½WñêúÆoו˜˜¨P(Ôj5% Ož< ÿxíµ×ȳB§OŸöõ'’¿¾×HL?pv¤ãËWÕínû9½ñjXuó,«ÕJ&3I€—3&üt¢´¢ çÚÀX·Y]0‹ŒØqîX…îƺÍꂬ›gùA0®0ˆ[‚à ▀Žb±X111”hz½|ÂÃÃÁù‰ ºººššš‚,ƒát:ÛÚÚȳ€b³Ùîȸ(­Xß¿cùÏë â|†N§“?ž$¼ïBV—;6:z{X²ääÖ–J,§Ó™œ2¹éZ#%‡b·Û, %Vhh† ¹z’_!°6èofßêår¹âøø¡¡!•JEžÙÛÓCi[YÏãñ”}JJºB,&sÔ` º… Çq„0È«NžeµZ‰|ñäYÀh2Bæwò,:¥Õ»nù§¸Á9î!´&y•!\.“Ųºè‘aY­V›-ð© ωÐÿv )LJ`åÔŒ?.øF†…a˜ÓÅDòºœN'áG’e2­ U]cccLÎá°vÓ…B˜c@­Ö P7ß5ÔSM'×ÓãÏ Ë˜,–Ÿ´Û^Áf³ÅâøÖ÷Bþa·Û1 #¹‡IúS »ÝîäÇņG¼—”"À¿ )=2œN§Åb¦ÄòZ”’µ”XC?x‘“g™L¦¶Ö·;]mmÜ<‹F§ Ë­:IÖèèÿ|*~ Ý¬ÛÌ­û¥ï6,·2Ĭ*ôË0%–å‡ËìŽÌFðwÇzüñÇBÿûßýk½WI¬²²²ÐÐÐ?ýéOw­…·”å ?ËÃé'Ïû–-[ø|~HHȦM›() …ÊaaaanQŽ~Æ&Øl6F £TµÃá¸ÕÚ—åj¡[¾!?,:Î`0"##Y,y]‡Ãᄇ‡‡„„d ƒ!‰pçóùn‡¹wÉZwyxnÞ¼Y üá@íØ±cãÆï¼óIk^xá…sçÎ544¼ôÒK?þ¸g!S¯X½zµX,®¯¯/((xæ™gH¾¥¦¦¦>ûì³6›­­­Í«'¸WìÚµëÊ•+uuu{÷îݼy³¯0 Odff¾úê«¡;wú pÃúõë Žãç—¿ü¥[•,¯xóÍ7u:]LLLww7ŸÏŠŠÚµk—ÿØÛ 2Ë÷\Œååå<ò\Í8އ‡‡¯Y³¦¬¬ÌµÓnôêêê3fäææ677{-ë•õŸÿü'))顇:xð ×È>¯¬U«VÕÔÔìܹsllŒÍf“d;wnÚ´i …âÚµkž«Ê !ÔÔÔ´cÇ&“9cÆ ’,vãÆ_ýêW\.J)Ëb0Ÿ|òÉ¡C‡âããŸ~úi­V;mÚ4’úÁͰ\[Æ]@ñò(|ÿý÷KJJBBB a7—Ë]³fͱcÇHšræÌ™Lvß}÷}ýõ×ä066644Ä`0(Õ>år¹ƒaxxøã?&¿)_]]’’’}æÌòºB‹Åjµêõz>ŸO‰ÅåÈo1X,½^ïp8¬V«Édb0n6gßMÂu…\^^Þá&o2™öìÙãp8,‹×¸ó‡"7 jµº¹¹9%%åìÙ³n":{²-ZÄår¿þúëÍ›7¿üòË$Y555Ë–-999›7ový«ÖÀÀ@{{{rròË/¿LÞB„\.///‹‹khh ©Ëu®Ð!?,Ïþ®ÿð£+""¢¼¼üÏþ³[…Dÿ¬™3gfeey¾†{íLfy8ýl7¼òÊ+ðêM5R!ÔÙÙ922Bi¿qppðõ×_×h4Ó¦Mc³Ù$O¦***&Mšôá‡z>@ýàí·ß …”,<}útMMD"yùå—ÉÇØü÷¿ÿ…iÜ·od”û÷ïùû÷ïG>|˜¼GnDDDVVÕZ½½½T‘ã.ŸÛ Jм^…¡‡z¨°°ð·¿ý-ùk!TSSÿ¨¬¬$Ïr:ÕÕÕT-D¹eï ÂR¿uuu”Xà€|DzehXOçÏŸ'© !D£Ñöïßï¿X°'ëúõë¾¶<œ7¤ãÉ=uêÔ—_~é™ùAÖ¸¬ÆÆF_i·n›…€‰X%¹¿ÄO7ëÝ€¨,ç ëÞe‘°¼? ݪÔaæ+#~Àë2ȺwYÎךƒ}7Š÷;–Ífsýbb0žµV\?_IÆxW@uo±Ü€a Šâr¹L&Óøý­ˆÍfS ²X,°fq …$¹z½ö‚¬{‹…¨¬X>ŸqAq3 Mx¤bA „î±ê_AÜ+ #„p £të%žÙä¹7Éâñxne~†èëë#ÞnoÛÌÀ¢;N6›í?5ˆ'p‡ü$”¸7ÉJJJš4i%;z0™LpÔs;g>V€G:ì¶Qb±X¬èè„P¿ÊÕe*°m˜Ÿ$ÈLE¢Dât8¯_ï¾Õ¿—'ë.}ÇŠOHÀ0 ðظ¸;mË=ŒAƳ†ÅíÁ]šÜÖétr¹\»Ýn±NX­âŸ!È{]O8& ®ðV°0„™Íf›Ýe ‚O@WÜêÜ””ɇ£½½íftÝ¥w¬ŽŽv¡Ph2™Ì³•qóhkóé¬F·paA¢À¸‡C£ÑL¬=AÄ„<&øå=11133333³¸¸ø×¿þuRR%úŠ+Ž92±&QFãp8ÈÇäºêÊ݉DòÍ7ßÜNQQQ^ÛtÇŠÝ»w¯Åbùì³Ïžx≒’’íÛ·§§§WTTH$’´´´3gÎx-QGÀápÄÆÆŽŒŒ…í(Y¹lÙ²³gÏR¢L,"##GFFD"‘V«5Çh4Bí1ÇY,ŸÏW©TÐŽ‚»Ýn6›ïøùŽã´ø¶!++‹ÃáTTT¸[âú?Ï>ûlXXØÉ“'õz=†a_}õÕ‰'âããÿýï÷ôôø*ÕJ !!aúôér¹œÏç÷õõÅÆÆ’71<<|æÌ™·­îˆ/˜ÍæÁÁÁÐÐИ˜ƒ‰D°çp8ÂÃÃE"NŽŽÆ0ŒÁ`ÄÇÇßYËBjµúé§Ÿ¾ жnÝ_YY¹xñbÏ?ZXV«uÆŒ¯¿þ:±êÇ’%K<(“ÉΞ=›˜˜è__MMÍÅ‹¿ýöÛË—/ yøÁÂ… ;;;ÛÛÛÉSnˆ{-‹ÅÂqjjÚívxZ­VFŠ¢Óé:jùŽŽR½=ß  _á¾}áÂ… .Œ[5ÝûöíËÈȘ={6œÜxvpy§Óé°¥vá§Ó9oÞ<­V»råJ‹Å2{öìqo'yyy¡¡¡ …‚ËåŠÅb“ÉD>(´¨¨èŽß®l6[DD“ÉìïïçñxÇl6ÁíÊjµ²ÙlpÃq\¯×‹D"«Õ ‘gÄÉÝ P«Õ3gÎD“omݺuß¾}¡ðððÞÞ^ÏBˆËåRMnk0àÄÊ“ ïááánQV~X‘‘‘gΜ)**ò ¾#XYYY^óü¬P[[ {{”~5?3“¬Å‹×ÖÖºÖùÖÄo7À÷ÔÐП¢ÑžˆˆˆøÛßþF2¤3ˆ»'NœðÚ~·l677CDh? Ü¥‡ÐAÜë.¬ n ‚ +ˆ[‚»å+ˆ{Ä×:ñyHG œâæ‘3ˆ÷&YF£‘j‚žŸœN'‘øêvÎü¸,"`ÕápPÊ'DADAü?RˆÍ‡ÜÚ»VIEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out-big.png000066400000000000000000003074041445075545500254360ustar00rootroot00000000000000‰PNG  IHDRX² °+sBITÛáOà pHYsÄÄ•+ IDATxœìÝw\Gûð™Ý;¤*RQÁŽ5h,ÑXbMbKb4SÔØ~ójL¢FÝX£¾Fc‰%v]T숢ˆ"Eš”;ÊõÝýý1ºÙ\ã ¼ò|?ùä#{»³³³ÏÎÜ–Û!¨qpUWÀÿŠ¢8Žã8NÏGb;‘‹+"Ÿ`¤)‘°jU%WÏ´e‹¹ºº*•JÓç ýôÓOïß¿¯RkGGÇiÓ¦•––æååYV16Õ¸qc…B¡V«µ?À”KP³àOçx´ïáѾ‡g‡žò©Ê¢—HßY­ˆÌ]cܰaÃaÆýþûï¹¹¹&.•““ãââÒ¹sç³gϲ,kh¶N:¹ººfeeéý®  aŒBCC³³³…Ói{G¯vÝèZµ<}ì=ê#rJˆ)¶o¹ø5bTм;—yYÕTÚf„®®®~øaãÆûôéóçŸ* S-©Tš’’Ò¡C‡'OžPU»vmGGG;;;„Ã02™¬°°a˜Ž;¦¤¤H$K6€-yxx„††êžÌÐŽÎ^Ý×róÄ(êŸù;öâXF%)(||Wï@ˆEb±›·¸Ž»Ø½ž2û¹<íé«AÔèGZ\šw®T-y©ÈH!3cZäY«žŸ27³$>†ÓèœÅ"„,k×®]TT¤V«•J¥ƒƒƒ§§'ÆX&“½|ùÒÐ"c‡ÀÀÀÙ³g;::b¬}o’ã8¹\^«V­ââb__ß´´48)€êÃÍÍ­cÇŽOŸ>mÔ¨‘nŽ0FÅa #D½þ”¥(„8¤;óku;õ ˜±SB8ó·òô$þ:ª‘þµZ‘(xá„1ÿiÑ¥¿ÒÖÌäXŽrp Yö—ȱvi­zÿf”eOffÊŠu 1o ÄgffÆÆÆ†„„ÄÄÄ”––Ξ=ÛÎÎîÑ£GÛ¶mcYVïèåææ6zôè±XLÎõrvvFµk×®nݺ7n„Û„PMˆÅâvíÚ¥¦¦¦¦¦šMò݂êEy#Ì+Ô[n%+TŒ‘b ¯Üúq¸Õ'Z㥑„hÇÚ˜%Nî#ÏHzuÊȱË"„êÿ’¢Å _öd•2,®ÕtåñzïõbÇÏH猖Ò-WÆØßßÔ¨Q¡¡¡cFƒR«ÕÇÕ©SÇÍÍÍÉÉÉÈâÁÁÁb±ØÈ< ÃE"Q```Æ õ|ãP¹0Ævvv‘‘‘ zž‘àjåS·±gíFîµæHeFgF!–a•JV¥0ë£:=êvéOFGQ7„‘Z’Ë1jŽÑpŒ†{=ι÷•wòwFQƱ,«”çÝîùÎ(½#‹I!MÓ:tèÕ«×°aÜœœø‚8Ž»}û¶T*}üø±‘+™ÆGÁ¼¼¼Ó§O!½µî[]Â:Qµœ·ô:){ÿzrŽ˜µs™Wÿ±µÃ#©ZÎMÛz ™˜µkÇ鹄iöÝ8ŸÞ½{»ººöïßçΦŒXiiiqqqíÛ·Þüóððptt”ËåJ¥’œ’Ë¡ Ã~üØ”{„ÎÎÎ:tˆŠŠª[·.yj”¢(Ò DZ,Ë0ŒJ¥’J¥—/_¾uë–é÷fTŠ¢ZµjåèèxóæM†ÑóFÒi¿óÎ;W®\žÙ¹y5ûjQ-w/„uN9VU”ÿxÝ·Êü#«Æ´ˆcY¤ïtM÷#òÞ5òó ò7¦)ÚÑ…UÊYµê_/ŽÁ%ÓŽÎŒ¬”U«õ–,xÅZii)ùÁŸR©4ýaiié… ®\¹âéééæææââ"‹)ŠB±,«V«KKK òóóU*œ @åkР¯¯¯F£éÙ³§¡~˜L×ú”QÈòï\¤ìjé}4«ViÊK=Á1Ó?â´Î¾8–Ó°šb}õp,«Rê}@FÈì›™ÎÎνzõ ¹víÚÍ›7çÔ¿JgÖ0þ@ªU«MÓå>´Or$h÷ØP¸jž’Ð’§zÈUMrI³Â+°)ìààPÕu*œ%/ÝF]z¨¶³SÅVŸµ_½Ë²zòcÖ0;C=!“+ÓŠÔqá×Ù‡ù1Uø''øú÷¿Ñëe… jMùgbµÎáà–…!Dz,c€ÿy„ ÇR[ òY~Fh<¡¼‡s-¡‚Re¹Eׯ#S¨³Šd–Õ°†¥!Çr¬îÍ?ò'nÖÀuÑÇÝ4 ³øÏë÷Ró9NïÍ?„ú°s£Qo‡—*5_o<›_¬ÔwË þ*˜…—7Y–åX†cŽe¹þMþdü=œ‘RVºvÕç}Âk‰ð넳1Ë4ôrÖ¥éË8‰Ç0:óükþŠÝl€°æÒ¨þ\íZ7tSjXÚǧV|ìšOºd•™YŽ^PmâïU¶oC9Åaþî—e³¡*™5Ëè¹Úé`G?¼û‹Ô’õ"Ž+úã‡|jÕB#Œ¹BŠ1Æa,/)Q%$ØwêD'$|1r¤“}üîsŽcõýâ° B–eûêßü`(¢¨¹CÛ¸½|‘;ésN&C!ŽSŸ¨)-eX–aY†ã|þüÓyôh†ã^MyýŸóÈ‘>0Eþ,ŽÎþbÒ‡‘whˆ8NXþ«µ6@[¶Xãï”©É ?!Žã¸‰ï„µõvÌû “Ÿÿj*BBʤ$yl,[V&œÈ!¤ÎÉ‘ÇÅ©³²þ™òâ…âÞ½ˆ £i =L/@ˆ%%/bÿ†×˨p–?,ƒX„ð«±éã·›EzÌšÎR®_ÿÕTŽC)33BØË ±¬ðŽ"Ë0ÊçÏQݺüœˆãII¹Ó¦ üå±ïºÈq\åÜ"ܸqcPPPß¾}CWq¼¡,¾Gȼ:DÈÉ^ܳEC±£}½+ठcDQï´ ü+æi‰Le⯿ÿþû>}ú`üjØ,,,ÌÌÌܾ}ûõë×ÿðŸ ç¯4£FšuêÔ7* ËêcŠ:uê„„„Ô¯_߲ŵàr·c¼yóæ¿ÿþ›Ì0hР­[·N™2åï¿ÿ†ëº`‹ß,óê…/›ÖoZ–—þþð”ž=Ëââ<.·lÉbÌ"dîâÅ‹ËbcŸò¼wï@YAçfõÇp,câ*X–e^‹¿wïž››[óæÍ1ÆsçÎ]µjEý³½ß~ûíš5k„S6løË/¿>|xÛ¶mo¿ý¶pˆrqq™1cÆŸþù×_-Y²$((ˆ|úí·ß2„¢¨ˆˆˆuëÖuîÜ™L74¿•[¡;áC‡ ýýýM,€k>Ѧ‰oññêü|uiiÑ¡CR¹Êkùrqx8ƒ1ƒéÿ‰‚ƒ=V¯.ÖpE‡©$UqqÑÑ£í›4@,gÙÏ'8Žsttä8.??Ÿã¸Œ9R8ìõë×O8cü×_õëׯ~ýúï½÷ÞÞ½{ DÆOOÏcÇŽ}÷Ýw!!!>>>ãÆ;sæL§N0ÆÍš5kÔ¨Ƹ^½zmÚ´ñôô4>¿•[¡;C‹-\]]ÓÓÓÍ-aé@Ƚ:#‹°F.#§tš’•FsøV²ûÒeâfÍL?/y®^s".M©Rkär¾41ýϊ̪ž““Ó7ß|Ó®]»³gÏf’ÇVuîjMÁ_ºt©E‹‘‘‘ãǧizúôéd˜œ7o^ëÖ­7mÚÔ®]»ÈÈÈ)S¦¸¹¹-]º”¢¨O>ùdùòå,Ë?~¼k×®GŽá8ÎÈüVnÑ»wïiÓ¦MŸ>}Ñ¢E{öìÉÉÉY°`¹·'ÖÞ#dY–%rƒË0G®'²Œ¦ß²_ò¦OS&&rgüs_²”f^#¥6ô\±òïG¯>f4j†ÜþBˆAˆÅ˜_‹‰g„/^/ž Ùx,ûåüãŒWŸ’ó*–y5¬r±Å2œYg„àŸ·lܸñÙ³g'Ož¼nÝ: . „¼½½BeeeÂOKJJBöööº š;¿[Á0ŒF£!¿#Ü·oŸB¡øïÿ;vìØ‹/ƒ£`.+–áXŽcY–e_Ÿ2³ÿLg\M¸ð(ÃsÉ2QÆìëS@þÜ‘öóó\ºôÂÓ^Id _VYrFøº4Ÿå^UˆeYöéÓ§ñññÁÁÁcF#‰Äb±‰èááÊÍÍMKKcY¶^½zÂO}||0ƹ¹¹ºƒ´¹ó›µzg¾}û6B®Ž€e,_]±LÏÎ……‘çbh_ßôÜ¢×)v–ÑüýðÒ“LE?Ó§ch__¯Ÿ—\NÊÞý˜Ñ¨9–!K¥åäÛ5oþjžúõ3r ,NÌËq9-«]»6B(77—¦éÖ­[“áÄÍÍÍÃÃCëa™.]ºðSºtéÂ0L\\\vvvBBBóæÍù ›NNNÝ»w—Ëå/^$·Bü¥Ëœœãó[³z‘—Ñdee™U2Âò4Lä$íÒ½”Ãû"Œ9µÚuðàý§î¾zûB!ÇZJ•¦Q^‹gÏš¥ÎÈ@‰}|¼–,)¦Ä25ãæd÷R*{57‡ÎÝMþzÐ äèHÕªåÒ¿ÿ•½—Y†±øu)ä.»»;Bèüùó=zôX¸páŽ;ìííGåââ"œY¥RmܸqóæÍ………  =sæLBBÇqëÖ­Û°aÃöíÛ7lØPZZ:räHÿÍ›7“'9Ÿ={Æq\ddäG}téÒ¥çÏŸŸßš­ z÷DAAA P([·n…GÀ–Þ#ä^%æ}žS´ò¯ë‘ÍÃìÄ\MÊÌg_ \…ñÿì&~§Ø}‰{ÿ}ïE‹²gÏF,[oñbDQªß·G6m3¸Ó‚çøÁ.ñyίgØNÍÚ"„Ïïºð<§ˆ¼Û²J>zôhàÀüûï¿7lØ2jÔ¨Õ«W«Tª={ötíÚ•Ÿ9...&&fÆŒNNN¡Û·oÏœ9S£Ñ „öíÛW»ví™3g.Y²!$“É~ûí·Ù³g“çæÍ›GŽ4hÐêÕ«¿þúë´´4ãó[³d ÿÔ(˲·oß^µjÕåË—ák` Ÿ3ì8ì+©òŸ"0ƈCÜ¿_­Xols¯¬ÿ›…Æ.(¨ÞÏKØÒ„]Ç5sÒçL^¢iÿ_ýíVjü³îuf ŒF‚Ò^§©O<¾ÞÈBŠ¢(ŠâÀ œHn¶‘?ÝÝÝ›7ož–––––F~GH†:š¦BÇy{{‡††æææ&&&’ø¢ìììÚ´iS«V­ G5š¦ÃÂÂnݺůËÈüFjh|+È¿…%9Ys) dñS£Œ0C½Þ>ØÇÝY™›Ã°,â8ù³gˆeb3 –íê¬&ïIÑhdÉɾî®ñ)YüÛDõ—V^'Ï%F&²,ûòåK½gNüÖÙÙÙ999èõ#\V¡P\¿~]÷#²øƒ„ŸßH o…ÞXÃÚ{„Æçañën›ã–=ûŒåضMýÙ×CË0,eÞ¯æ­TÌ`îGp–ÕŸå¿#dYŽÆ’ã8Œ1é÷ÿ™È2 þçqO–eYFÃ"Žüdž  Ërˆá8=!)ÁpÀ–¬¸4úï[‚ü¿ùÈJäZ‹¼/ Ñ4ËqJµŠaX–CœXÌj4!ަårÇ îŠ ÒØÿS> …lÃÚìFþ‹{šA‡4¥}}„\Þy'㥴@RZX\–’ïÔ³'CQ¢À@qãÆñÉ™ä}4¯þãô•fÚêsYyPpúöÏYÛ«)’Ù¹»O¢ü –ËŠ°èdô–a8Ĺ™0´oÿ€~ýÔ"ñ¹G©ùÒ2î_§~øßÿà§ÃY!€ŠgáÏ'Z¾3ºTYþÈ„1®eG7𬛖] y°cDQT@=·œÂb¹Bmâ-Àg—wÃÍBÎò{„¦ŒJ‡ä &9#—û÷D–eŸeæÁ° ÊYsiÔÔLï|0 ¨¬IÃ$|€Eï%VNgºî­é†flšK£•zRglÁÂÓ/ŒqeLð¤ ,‚ÛM«ê:UF„i S¼0 „ÀdÁÁÁ[˜óC ®€PU]ð‚Þ ØÄ°Ôh0¨Ñ` P£Á@ Fƒ@!€ B5 „j4Ôh0¨Ñ` P£Á@ Fƒ@&ªê T;¡¡¡_ýõéÓ§¥Ré‡~ˆ1V©T)))Û·o—J¥QQQ#FŒÀ+•Ê”””ßÿ½¨¨¨ª« ªR›6m>ûì3Šúç;åöíÛÕjõøñã)ŠbY6++ëÔ©SwïÞå8®AƒsçÎ}øðᆠæÏŸ_¯^=aQiii?ÿü3˲üqÏž=íììîß¿¿aÆ¢¢"~-,ËæççŸ>}:&&†ã¸Jß\`s>>>'NlÒ¤IYYÙ‰'>LvôgŸ}Ö¹sgŒñÝ»w7mÚ¤T* E…0ÌZµjÅǧT*½{÷îŸþÉqÜ‚ ô†_½zõô®Ô,½zõ***š7oÞgŸ}&‘HâââŠŠŠ¢££œœÆO&Þ¿_"‘\½zÕÞÞ¾ª«\í4nܸædÌ}:EQ›7o–H$7oÞ¼yó¦D"Ù·oMÓ†¢BfÂøLNN–J¥[¶l¡(Joøy{{ë]{U· ¨t½zõ’H$óçÏŸ0a‚T*0a‚X,þå—_$Iß¾}…×­['•J»víúÆœæª oðàÁ‰dݺub±˜¦iš¦1Æd↠Äbq“&Mâããsrr‚ƒƒÃÃÃ%Éè×~øá©TúÅ_Å;t蟟îܹڵkÓ4½|ùr‰D2sæÌ¡C‡òkiÑ¢E^^Þµk×hš®ê­¯T5!®>üðC‰D²fͱXìé陜œ|õêÕîÝ»9rÄÎÎŽ¦é£GJ¥ÒfÍš cOaaa|˜ çqrrºxñ¢T* ‰Dºá§wí5!Ì`¨/˲ ÃcŒ9Ž#W X–‰Dnnn ÃäççWuAÕ‰Dþþþþþþžžžü¥$Žã†IJJ:~ü¸ƒƒC·nÝ„ý8Ã0 ÃðEþŒŒŒ‹Å§N*--efË–-¡víÚ ,,,äo˜´´4–e»víÚ»wïüüü¨¨¨V­ZÑ4}ñâEFÃ0ÌÒ¥K§M›VVVF1%*È} ]9räÝ»wïÝ»·eË­oÐÇ‘oKµk×.·„T*%¾xñ‚ã87772‚öîÝûâÅ‹—/_–ÉdänbÅo ¨R7nÜX¼x±§§çüq÷îÝiÓ¦qçêêŠ*--%ó\»vmûöíéééäOS¢"$$ä?ÿùÏÚµkßyççÏŸ“;Ö&®ÝfÛZÀÃ2å(**ÊÏÏ÷÷÷oÑ¢ßý÷¿ÿ½}ûv÷îÝG޳eËè’j¸³gÏ9r„㸜œÝ`°³³C™$jµ!$½:0ííí1ƆüYVV–““ãèèܺuë“'OÖ~ªæà8nùòå»ví5jÔ°aÃæÎ@¾Hñ÷êøKS„nTèÛ²eË&MšÈd²+W®,^¼X¡P˜¾öÉ“'¿ñýœ–c÷îÝ#GŽ\±bEPPPß¾}É@øôéÓƒþç?ÿaY6""¢ªëª^VVÖü±k×®sçÎéNáááã”””rÇ­gÏž!„BBBÈŸ‘‘‘¡´´4²`LLÌèÑ£Éó\|ðÁì?~üþýûƒƒƒW®\Ù­[·¬¬¬>}ú¤¥¥!„5jDæùá‡âââÚ·oOÀ”¨Ø¿¡*ªà IDAT“&MÂÃÇ~çÎCq¨wí5!ÌàŒ°äÚzvv6Ƹnݺr¹!ÔªU«‰'FDDÐ4œœ\ÕuU¯aÆ&L ýËÅ‹ÉÄ€€€Ï?ÿ¼E‹}ûö½wïÞ©S§š6mj¼œ£GNŸ>ýƒ>ÈÉÉÉËË›åOúc¦`P#pqlUW@Õ;uêÔåË—išvqq‘ËåÓ§O§^?Wš••µbŠТ´>š={vYY™H$"ÓÏœ9“••µwï^š¦É‚7oÞLLLœ;wnXXÆÚ—\µJÓú³{÷î …bàÀº 6lØpþüù¿þúk^^ÞªU«(Áó¯gϞݿ?_¡”””%K–ôíÛ·¨¨håʕׯ_§iúÉ“'‹-âKˆˆˆ7nÜ7ß|sûöm2ƒñJò-`J+½ýöÛ …bÀ€d‹¦OŸ®T*ɲ†èÖÇÈŠF¥P(öíÛ·yóæÍ›7?xðàÎ;dÝr† ¦P(:vìH*³hÑ¢—/_’ÊÄÄÄœ>}š¦éƒ>xð@«1ËÝLá<¸Қ^îÖéÎ/‹£££<== mï|`h»ˆ1cÆ(•ÊV­Z‘š5kÖ¦M›#F(ŠvíÚ‘‰$öúõëW»vmCÛ¨7¶…kJ8 ÔZ–ÈÈȈ?tèÐÁƒ<¸`ÁÊÀ¯›V!„hšæB‘H$<Þ„ ÿ1¶³³ã§»»»;;;ËårŽ{uóqðàÁß|óÍСC¿ûî»7nŒ7.55•ÿÔøŠ222D"Q½zõ0ÆÂEBiii?þø#B¨°°pÚ´i‹-ÊËËCy{{wìØqþüùZó·oßnß¾}:uâââöïßÿùçŸGFF:uŠã8±X¼k×®Þ½{ß¼y³´´ÔËË+77·ÜJjµ€ñVòññ‰D/^¼ Ó)Š22 šXá¿ÝÝÝÅb±H$rvvF=zô(;;[$íÞ½[·ooo±XœžžNÚJX™£GÎ;×××·[·nÛ·o×jLƒŸ®7®,Ø:„ÐÒ¥K[¶l9hРüü|CÛkd»ˆºuëŠD¢¼¼<2Cbb"B¨sçÎb±8;;›LÌËˉD^^^F¶Qolókâ 6”°µ¯^½:yòd–eBÇ‘*\Å|ÇÜ·oß?þ8zôè>úcܨQ£÷Þ{oéÒ¥‘‘‘!!!ÿùÏÊý>˹nܸ1B(++K؇‡‡=z´}ûö¤GÈÊʲ··'ý B(,,ÌÁÁ!!!Aï@xîܹ°°°ÈÈÈ3gÎܼyóùóç³fÍÊÌ̼qãÇq½zõ2dÈ7ß|Ó¿ÿ>ø !!¡BÚD(##!Ô¨Q#Sf¶ >Ïž=ã8î÷ßÿè£ÆŒ3zôè3fôèÑCo9¤ÓoÚ´©î ÷ÿû_†a–,Yâââ²cǽi% ¶nذa'N\¼xqtt4©’ÞíÍÌÌ4´]ù*Ö¢E 2À>üðCRTÛ¶mÉÄ–-[¢×c¤^åÆv†ÇqÌk0 `;B¨¬¬ÌÝÝ| ¶ Çq+W®mÚ4ŽãÈi¢J¥â8nÚ´i}úô1ÔO}üñÇ7ö÷÷Ÿ9sfVVÖ•+W„‹dggwìØqÞ¼y^^^ÞÞÞ#FŒHIIIKK#Ë6hÐcœ™™©·ä#GŽØÛÛ7jÔhß¾} Ü?¾G7nÜà;Œq:uêÔ©3yòä.]ºTø5¨[·n¥¥¥Mž<9000((hĈ|#èmsësþüùäääo¾ùÆËËK,3†\†Õ[Î… òòòæÌ™ãçç×´iÓðåçääœ?~èС·oß~üø±•¡¡¸2kë5j´råÊèèè½{÷úøøøùù¹¹¹éÝÞ‹/Ú.âï¿ÿ~öìÙôéÓ=<<š6mºbÅŠ¨¨¨Ó§O'&&Μ9Ó×××ßßêÔ©±±±·oß6´íNNNzc[¸±æî>ë@€5(„СC‡üýýŸ?näÛt¹X–ýâ‹/ÊÊÊ6oÞüôéÓùóç?^"‘ÄÅÅ=þ|ñâÅ,ËΚ5«oß¾†VqéÒ¥›7o¦¤¤4kÖlúôéÅÅÅ!~‘üüüÏ>û¬aÆ©©©ÏŸ?÷ööþúë¯ù‘ÌÑÑ!TVV¦·ÿzùòå½{÷âããÉÀyàÀ;;»sçΑ™O:uìØ±åË—ggg¿ûî»çÏŸwqq±¬ ‘ËåÓ¦M |òäIll¬ðM=ºmbA}ärùW_}U¯^½”””‚‚‚Å‹7hÐàôéÓzË‘H$3gÎ OII¹qãÆ;w„¶oß>Š¢:dý)WÍ›7ÞK3kë† æããÓ»wïääägÏž={ölùòåJ¥Rw{¥R©‘íB©Tª)S¦¥§§ÇÅÅ={ölþüù Ã|õÕWIIIIIIÎÎÎS§NeÆP}âããõÆ6¿±éééÇ7k÷ém(@¥Â7hÐ ,,ŒÜV1å¡ðŒÞÛBE988´nÝ: @ï H½+òöön×®X,æ»­Û*4M7nܸI“&"‘HØeúéD„·a0ÆZk§iºQ£Faaa"‘ÈÄ;¦†ZÀÐýôÓôôô³gÏê}ÀÕÊúè.e¤­éýû÷OKKÛ½{·ñº™[%Sêiqáºå˜BÖWÉP!–•f¨@xs ><>>¾¸¸877÷øñãÍš5«nß°aäRéµk×üýý«º.PyªW_üÃSE?òà«-žÉ´¹BHžT¬êºÀÿ¬úõëWu@5eJl@ü+A˜ª$‹÷ïß/|HõçáááááQ±eŠÅb+/-ê=Jœœ‚‚‚ªÕÕTC­g¨ªwïÞ;v¬¡ð0?¶ØM6åááQá›®N:Õê—¶¨‘£Ìâ0CÕ~€¬ä–¬4†ðÊ>Ž’““KþmÖ¬YæŽgË—/¿ÿ¾Þ§ B»wï...æ_dõÉ'ŸH¥R~uüK¶ÌªmqqqFFÆñãÇÛ´icîÑ©S§7nÈår•JË¿—ËšŠùùù:t¨´´T­Vçää,\¸Ð¬6ܲeKjjjIIIzzºÖãŽË–-+,,T«ÕÅÅÅ“'O&ÅVH>~üØÜªj=CU%œŸŸß¹sg½;KoüØb7UHüð´;44ôÊ•+2™¬¬¬ìĉ~~~&–3fÌá7n4k¿´jÕ*::Z&“)•Ê»wïZ¸]¹r¥¸¸¸DG§NLi1½õ™>žÿóÚµkçÎ3ëy´ ß³ÈêþʦýpÕGÙÙÙ;wŒìøšYÛÓºuë’’’áÇëmˆAƒ‘óÛ9þü¼¼¼qãÆ;vìØ±ï½÷žé-(¬íûï¿ÿþýÄÄDWWWÝ9ûöíÛ£G½%?~ü8&&&<<<,,,>>þêÕ«$€¬©ØáÇSRRzöìéææ6eÊ™L6sæLÓckèСS¦L9wî\ff¦ðhüæ›o¤RéçŸîêêúÖ[o…††V`FEEÍŸ?_.—ûí·¦WÕPëª*1>räÈ¥K—tUCñc‹ÝT!ñCèö•+WîܹӼyóŽ;&&&îÛ·ÏÄŽÉÓÓ³C‡üøÓO?©Tª÷ß_wíFjsÿþý6mÚ4kÖ,>>þÂ… V6WXX©Ïž={233;wîLþ4ñ{ºÞúÔ«W¯£Àš5k²³³µBňr2 ÂÌСgq»ýôÓOJ¥’tßþþþ …‚aòJ#—’’’õë×ën•¹g‘Õý•MûáJ8ŽôoÒúõëi𯝙²J¡ß~û-!!Aïû3ííí>|xýúu–eùþbýúõ÷ïß'¿Ù2´ÆêÝ­Úöë×O­VóﳺvíÚ‰'t[ÐÛÛûÌ™3ï¾û.yzeÙ²eüÛ™­¬ØºuëøŸQ©Q!G™¹a†t=d]»]¼x‘\èKIIùõ×_úé'rºsüøñØØXaŪjÏ–Û’UÕÛô82&;;;!!áÈ‘#‡>|øð?þ¨U.¥CøiãÆ5Í_|¡[›cÇŽ={V$im̯¿þ:gαXlooòäÉœœaüaŒ»wï^RR¢P(Þ{ï=­Ûììl†a4Z­.,,ŒŽŽÖºòÃ?¤§§gdd(в²²ŒŒŒŒŒŒ)S¦hU/00ð‡~ظqcaaáêիɧÖT cìææ6uêÔsçΕ••ݹs'88Xk7=zôÖkzc]ï@¸uëV±XLÓôªU«È×CŒ±•mxîܹ™3gΘ1cÉ’%™™™ÑÑÑZó¯ªn멪pA¾ƒà§‰[ì¦ ‰½]îl¼b¡&Mšäæænß¾]÷#£!öâÅ‹ßÿokš‹02–Òºõ!Ο?ÿ×_é®Îú£ ™fHß@hM»ýòË/;vÔh4ýû÷oÛ¶­F£0`@ZZÚo¿ý&¬CUíÙr[²ªúa›GÈHÄfggoذô_4Mëî€gÏžå œ?Þ”1b„J¥ZµjÕÌ™37mÚDòûôîÝ›\‘çg7nÃ0Zïûþ믿öìÙsâÄ Ý\»ÙÙÙ7n´³³ãß<©uðo§¼qãÆéÓ§kÕª¥÷µ|5~üñDz²2ò\²5ã×NÓtDDDff¦î=Þ &Ìx-00°ÜÐÃÃC¥RM:•ÔªS§NfôèÑַᆠH³Põî»ïªÕjR¬‰UÕm=#U.xá³z¨ ßMÖÇ¡À>|¸îܺukÓãçôéÓÉÉÉz%71ª½¼¼ââânܸ!|lÁú¨62½õAy{{—””L›6MïN·ò(Cæ‡Ò7ZÓnä^àÖ­[³³³É½Õ§OŸnÛ¶a˜qãÆ ©Ú=k¼%«¤6l˜íŽ#d b_íuò>C fÍš%Œ¢¢"áœYYYjµZw­þþþwïÞ%wP\\\0Æ={ö,((8wîܶmÛNœ8qàÀŽã8Ž+..^4ŸyòdZZZݺu­©*ú÷õývíÚýõ×_ÅÅÅááá¦\O7Òz†ª*”““³råJŠ¢ÂÃ÷lÙBž›×?¶ØM¨"âÇP`cŒïÞ½]¿~ýÀÀÀzlX·b¡¡¡ùùù»víjذ¡ßkzoܪBè×_-,,ìÓ§¿¿?)ÁÞÞY×\„e÷ Õ!ôñÇ3 fd¥Öe¦‡™pµ=+Û-&&†eÙ¯¿þš¬‘ÜN~ôè‘¡>¡2÷¬YýU%÷Õséaú&²uëÖ‡éôµ®óvíÚõÑ£G2™L¡P$$$DEE™~KÓôÚ’®JïGï½÷©€\.òäÉ;ï¼c}Å:wî|ñâE…B!‘HärùÑ£G-x „îÑèááqìØ1rýÙ³gƒ ª6ä¯ïÇÅÅ1Âô0Ôz†ªÊ#×`ɽ„Aƒ©Õê·Þz cl(~l±›*$~xZÝ¡C‡¸¸8R±k×®™þjõ3fK2d§zû5#µ*--%_½ù† †1¶¦¹ËBCõAMš4‰a˜ÀÀ@³ D¦e憿Z‡ž•í¶víZ¹\Þ Aò§³³sQQÑÎ; U ’÷¬•ý•MûáJ8Žô°>óYÛ¶mKKKu;>ÆX˜é cLÓtHHH£FDFóÚ¢¶|tSZS1²¬——WDD„«««¹ç‚%HSÇ£i:88˜ä·«¨6Ò½¾oœ¡Ö3TUÞÞ½{/_¾L6pþüù÷îÝ#ÿ6?¶ØM?ÂêV,88˜¤*4½bü ­ýbVetK °¦¹„Õ3w)Cõá ´ &¦e憙°Jºë²¸Ýt ´`Ÿò Vøžµ²¿ª„~¸ªŽ#ËaŒW®\çææfÖR ÈP¬¬˜-6ÊFUµ†¹UêÛ·o^^^—.]ȧ˗/çŸ7?ÕpÛ«¶µªž³Œ¡m±8ÌŒ¬¨š·[5ì¯Ì­€¡¼ò+c-Š¢<¸|ùò üº Þ$wïÞ7nÔë¤TüŸ?Àzf ŠÑ4]Í_ߪPýúõ÷>?ÀzfT/ T8*P.«èmò[éʯ úßÉÌg(O˜5©Ñ´øúúZ[ËŠóæB†ö 5Ñl”é­ƒª U·¤‰&2ùUuDÊägqêgªIÿcÛö7”Žë­·Þº{÷®R©T*•$Y†‰Ã•iÌþ‡2óÊFXMWÏž=>|¨T*¥Ré¶mÛLï—+<)Z…§m³2N*$#š¡=hqF4d]¦·rªYTÖ4T¥¥Ö+—5ÑbeºGC‘o¤§*—ír‚"‹‚ÄP?Sú[´¿†ÒqÅÆÆÞ¿¿eË–íÛ·ONN>{ö¬‰õ¶2ÙÿPf>CyÂl~j4-nnn©©©gΜiذá!CòóóÉÏ„M©[…'E«ð´mVÆI…dD3´-Έ†¬ËôVnB5 ‚Êô†ÒUi©õÊeM´X•¦Îpäšn å%Ì CýLå÷?zÙ¢ýõÀÒq•••-X°€üŒcýúõº+«ð4fFêSù™ùt—N1’'Œgnj4-#FŒ /.!Ûµ}ûö'Ožèw%$EC6HÛfbœØ.#š¡=heF4+3½ñÍb(¡š¹AebCUmj½rkbe´”ÛªFŠ|CÓM©5=‘T<³‚ÄP?Sùý^¶h-"d8Wzzz›6mB"‘(,,,==]8Ò˜ªO%gæÓ]ŠeYÝr å ã™›M‹§§'ÆøéÓ§dÙ¬¬¬zõê wj¥%E3´_¬iÿrãÄÖÑ ez³2#š•™ÞÊM¨fYPi¨êZ¯ÜšX-嶪†"ßÐtSê#,ÁÜžÇHªNžYAb¨Ÿ©üþ§’Û_Ý7 uïÞ=))éñãÇOžÝ¥Œ”c(ãaVj4­f¡(êòåË/^¼X±bÅüQXX(—ËMß:[$E«Ø´m|™zã¤Ü}W!Ñδ2#¶.Ó*/¡23¨Êm¨Ê"C‡Œí¢¥ÜV5·G*wº­{½©:…Lvî>Ð IDATŒ±Þ~ÆÐt·ÑôÈ©üö7H«¸ÈÈH¥Rùé§ŸÒ4MQÔìÙ³KJJ´·]3ÝúT~f>Ý¥ô–c(ãϬÔhºÍâêêºhÑ¢£GnذaõêÕR©T«=+3)šî~A6NwW Ñt÷ õÑ™ÞPy Õ™AUnC¯Oå¤Ö3±e¥Ñ‚,JS§µ^³:bãõ±¾çÁúRu ™$†ú™Êé*¿ýµ¼hHÓôÇÉ•èääd___á5}Û¥1ÓUù™ùt—Ò[Ž¡Œk<³R£é6‹D"ùî»ï0ÆÇíÙ³'++K«­*3)š^6MwgÓŒh„î|úô)²4#šõ™ÞÊM¨†ÌÏ·g¼¡Œ×§rRë™R“rÙ$MlÔóIÕ),߬ 1ÔÏTNÿƒª¢ýõÓW%É¡C‡<<<¼¼¼Îœ9“••EžØÔbäj{Þ#DU”™OïãgÂ*ʸƳ 5šPDD„§§'BhôèÑ¥¥¥K–,Ñ»”¡½PIш OÛ†LˆCûÎÊŒhÈÀÄVdD³2Ó›‰ ÕÌ *Óª¢È”CÆHMEÑbUš:ÁzÍ=#1Td]Ïc$U§YAb¨Ÿ©äþLjŠmSWƒ1þ裞={&—ËåryrròàÁƒÍ½Ã\±a5ÌÌg$ãaYj4­vÉdR©´´´tóæÍ&Ö¨À¤h|}*6m²4N*$#š¡=hqF4d]¦7Sª™TÖ'­„Ôz¦WÆ‚h±*M`½–uÄzÙ('(ÏÜ 1ÔÏTrÿcDŶ¿A”át\M›6Ub3#ËÒÕ,3ŸH‡Öâ–¥F¢(Êßß?""ÂÑÑÑ‚¾L·EÖ%è2'•ŸîΚÎ/DïÄ–fDã—µ,ÓeBB5sƒÊú†ªÀ(*÷± 2&.b¼U-^¯ÅÑkMσ ç%Ì CýLõé*¶ý͆1¶ k³Cõ©nõDš­ºmš®jØþÖ³r‹lÑ žoüï2tÐY“ûÓЊ*´â &Ôh ÂAPrA€jR£ AÊA*„ ¼Ù,hB‹X,nРT*µ¦GGG™LVQµ2]:uêÔ©SVV¦5ýòåËjµúÁƒò»Õ‘•™±¬É¾Æ3ž^˦õ·&§ €7•™±LϾf$K™ñôZ6­¿Å9¼!ŒgÆâY™} ÎRfJz-㨒œ‚Þÿôøº™±ø¬Ì¾Æ¾Y¨ÜôZÕ3§ €7„¡ÌX<+³¯™˜¥ÌHz­j˜SÀ›ÃPf,~l]ö5³”I¯e¼U’SÀ›ÃHf,~k²¯™˜¥ M¯UÝr x3¼:û1”«ÜÔƒ¦d_+7K™)鵪[NAoŽr3cñ¬Ì¾f(K™‰éµôVÀ”úß³r ê®Àÿ<+3c™ž}ÍH–²rÓkÙ®þfå4±Lÿ+0BHëñr™Ñôß {{îîîIII%%%z;aJ!AAAãgÏž1 cz¬¬¿îÓ1Zkß»woýúõ{ôè¡ÑhL,@Mdý S5Ìi§•Ù ¨Y´2{5K¹™½T*ºª+PÓÕ¯_¿´´´ªkQ½T`›Ô¯_ßÅÅZ¸Æ²2–Äbñœ9sºuëæëëûèÑ£r‹…Ãù”±pܸqßÿýþýû9Ž3«Ðƒº»»ÇÆÆ_P,7hÐ@*•Z°l¹l]yë‰Åâ}ûö………={Ö‚uYSÏJÛFsém“ÀÀ@Žã”J¥ÞE }ÊõÝwß©TªTàÆê Ý7[uˆ7 ʹ|ù²Z­¶xï;998qÂÏÏO*•ž?žã8C‡­•‡s•ðððptt”ÉdX¦õ‡†Þ/NNN~~~‰ÄºÚuæÌ™ãÇÓ´ö ¸xñâÂÂB‘Hdn¹¹¹+W®¤(ÊÐ ~~~‡*--U«Õ999 .äg>yòääÉ“,[啯(Ë—/¿ÿ¾··7B(99¹¤¤¤¤¤¤¸¸8##ãøñãmÚ´Á[SϧOŸ’2%Irrò¦M›<<<ÈGæ6r¥¶ BhÁ‚YYYF.—_¾|¹]»vÂ61þ)_ÔàÁƒóóó;wî¬Õž‰d̘1R©tÊ”)Eñ{¡°°ðñãǰä ]âÊ•+ÅÅÅ%::uêD*@Ö¨õéÆ…å”Œ‹‹ãÃ>&&&>>žÿóÚµkçÎëØ±£Öš^¾®êo›&îý:èm+µZýÿ÷|O¢¢ýôÓ¼¼<„““ÓáÇ7lØÀ²¬¿¿ÿܹswïÞM:2‹ëéèèHʤ(ªmÛ¶óçÏ·³³?~<Ã0æ6råÐj“üqÚ´i+W®Ü»wo``à‚ :Ô­[·ÔÔTŽãŒ*,êðáß|òÉÂ… {ôèÁ0 ¿:‘Häìì,‰œœœÄb1ì±XÜ­[·Ù³g—••ýüóφ2ºd†I“&9;;#„¦L™Òµk×>ø€¬ôÑ£GäDáôéÓ½{÷æ÷]ÿþýgÍšuáÂáiD¹ñðøñãþýûûøødddøûû·iÓF,7oÞ<>>ÞÙÙ¹E‹;wî¤iZkM/_Wuˆ7 ŽM÷¾n0±,K*¯¢¼zõê+VtïÞŸ˜——·jÕ*2nO›6­OŸ>Z᛽nÝ:²FŠ¢|ظqc2?MÓ|{åää«...J¥211ñôéÓ7oÞÔh4{÷îMNN>qâÄË—/cbbÈ"6­æƒ>àƒc|á²ߪۼvvvyyy+V¬îÖÐÐÐ~ø¡N:«V­"K ÷‚¯¯off&9¿11tµÐøÅùcÇŽ¥¤¤è^O3üöæçç“yöìÙsÿþýèèh2l/\¸P&“yxx4oÞ\kM)¿ÚÆú÷±©c-[¶,,,$+Z±b…D"!Cš){_7­P+®x†¦#„~úé§´´´Ï>ûŒa~ Ñì mW:urrrvíÚeggGÓô–-[ô„¶k“#Fh4š®]» ãûÏ?ÿ$G¬ñOu›!wìØ1­S72ƒp/¤§§_¿~ýæÍ›yyy÷îÝûöÎ; Š£ýã³wG"½‰‚`G¬(*¨Øk°Dób7¶è«X¢FŒ¯cŒ±kì}íŠ ˆ(( ÒiG<êWö÷ÇÄ}7Ûn;Nýe>ÁÜì³Ï<óÌÌÝîì~éKGêRP¹.Y²¤¾¾~Ê”)Œ_®ó\çþýûÑÑÑB¡0;;;888((~¯ MLL$~™‘¨ÒþÇœod;Œ9&‰$ÉØ±c%ÉÏ?ÿLt·ÊÞg‹y!dÌ+[9 K—. ,˜1c†\.'ÂÈÈȆ††”””ÜÜÜúúú5kÖý׿þUUUUTTTPPPUUµdÉò§*scäÈ‘ëׯ÷÷÷ÏÌÌLNNÞ°aƒ¿¿?ý.i=ÂÂÂKKKÇŒ£¹cü‡”…°]»vr¹<999))éùóçõõõ¿üò <©&®ÒùÛgýúõ344}úôîÝûÀË—/‡?:5Œ!…¿}ç²±±_Ø)Ýfaa¿1Á]ÉÉÉb±X$|7›‚\.‡c÷ÊöÙgä8êÌy€R©„Ag4®T*ãââÜÝÝŸ>}zîܹ… 0ÀÑÑ144”mkõáÇýüüÈÃÇqKKK à áQÅÅÅâþ(ÌË—/ÿý÷vvvƒ :vìÑå·nÝ‚6ŒŒ"##øáoooŽ í‚¾òóó‰Sè8&UUU€V­Z‘ ÍÍÍá€çþ”ž;Ú333wîÜ yíÚ5__ß3g·7!uÙ³gOuuõÚµkÙdÌr…¨¨¨•+W.\¸°¬¬ìöíÛr¹<''gÒ¤ImÚ´yôè‘Êö~ÒùƘc°C ÿ.**Rêª*¥R™’’›pþüùeË–¹»»gddhC [a2uêÔ þA”çääà8~òäÉ›7o§=zôäÉ“.\xúôiÇCCC)—nØðöö>räÈ‚ îß¿¯T*Ÿ>}×±cG>Çr ç)0W*•[¶l±°° yüøqnnîºuë âââp/**’Éd”ËÖJ¥’þë9;;ÇñÞ½{á8Þ½{w@ZZÅãǯ_¿~ëÖ­FFF'Nœ ÏÚ0$I||…Ÿòì}nóŠ£ÜÁÁ!!!¡oß¾### Æ^^^qôèÑ›7o^¼xÇqÇ«ªªÈ]æçç'—Ë ”J%ý›wn 9À÷ä ݺuÛ¼yóæÍ›ãããáxÑ××oÙ²eiii“ã94þøãâo⇠oß¾---%.þ™ššÞ½{Ð0†þviôÞ½{¥¥¥þþþööö:uš0aü¾v÷îݬ¬¬U«VY[[ëééÍš5 nRÂ0ÌÄÄÄÄÄÄÏÏÏÓÓ“ñ",}×hBB‚H$ rssÃ0ÌËË«ÿþä·64 Ý8OÍøµk×ôõõÏŸ?¯P(îÞ½;lذ¸¸8˜ µµµyyyŽŽŽ*uëÖ­´´´µk×ÚÙÙ988¬\¹211ñÉ“'”*..¾{÷î”)Sž}úœ>}ÚÔÔôàÁƒ8ŽsÊ^[[ÛÌÌLÇ»uëvøðá.]º06AOOÏÞÞÞÞÞ¾OŸ>Û·o¯««‹ŒŒtuu…‡p¤.·Yr…®]»nܸñâŋϞ=kÓ¦ <››·ÊY¤Ré«W¯ìíí#""`GDDØÙÙeddÀ_rDzÙÿTò-ÇvíÚ•ŸŸ?a„ôôtò=ž½O¹mز•oÛ¶ÍÓÓÓËËËËËkëÖ­J¥rùòåðq—+VØÚÚÚÙÙÍ™3'99™rE*??_,¿~ý:77—_Õ@,{xxlÚ´ÉÚÚÚÆÆÆ××7;;^Çn²c#&,@tt4åÖ #8Ž/[¶ÌÒÒ233333³eË–+W®d ÔùóçÁåË—Ù¾'¾|ùÒ‚²Á„£]«W¯vrrJOOOLL„_Át“U«V?~<00°¤¤äÑ£G-Z´¨­­ýã?àQîO)¦ÆŽkaaqíÚ5ÇçÎ˶‹Œ¸ûrïÞ=''§Å‹¿|ù²]»vðêêj¶Ôå6 *Œ;ÖÌÌlúôéYYY9ï¹uëVûöí¹-À®\¹;ýÚµkÕÕÕ‰‰‰|ŽeäSÉ7Æûî»ï  “ɾÿþûž={~ÿý÷€ïÕ(çe¶Œåð‡„¸ ÿð÷÷733ËÊÊÊÎÎ644\µjc5¼¢ëéé9~üxz÷½}ûváÂ…ŽŽŽp‘°±±Y¾|¹†Ž5Ó¬ˆ¿uë–X,îÔ©ÓŠ+à“Ú!yŸ+†a"‘¨wïÞÖÖÖB¡Ø½ƒa˜P(tsssww×ÓÓƒ_µ„B¡³³³«««H$"!ïeÜ5 ­Y[[»»»›šš’÷#°Kw’ðA7ΓÿÜÆ9†ôîÝ»¦¦fâĉpð0F‰l¿GÝ»w‡Í0víÚµ‰„¼Ë‘RúL?G»D"‘›››‘‘Ñ–-[ˆ‡2uhÓÌÌÌÃÃÃÞÞ^(Ž5êéÓ§Ä“ ŸRL;w.22ºðìÙ3ÆÍœ¢¿Cl1'–ºt³ä€+Àrú¹ÈØòrÊ)àl{ÖùØŸN¾ÑsŒ|Frvñì}ÆXQŸ §(„­œUr0¡ó;vtvv&—ó£ïøhß¾}‡´åǬÎzJ„B¡‹‹ œ«µâ*_8º“ò½D+'Ò9¯‰) ÃvîÜùüùs>»U¹í[ZZŽ?þÍ›7gÏžmZò12zôè5kÖŒ7î믿ÎËË»s玺ƵJêÓ;‘þ)ÙÔ˜1cJKKáÃ6€íÛ·ÏŒò„ñÊ¿*Íj^g­û©ä›ÊkZïÕàBXSS³‹-EÕέ|KHHhBï“«y{{:´[·nÄuÆÕbê"ÿ,„B¡­­­†FàU-~7'ÌÂËËä‹„:@+1!›²µµEs“ù´òMóÞÇÞC”°¥¨SñO-cÔÊ$­A è üD þß rÄiík›´›Ž›NOý°&¨‚5‡øV³bii) ?ÈÙá³%µµµäìtšÃí4Ýç'øèe]uÜ:ƒmfø€1¬­­ >È öÁ4Õ„-Ey [>2l°I[)›N[9µTÁšC|K+ª`¹².]º<|ø°®®®¶¶ê‚ò´ÃGëN%=zôˆŠŠª««khhHHHÐ\DM¥D_üñóó£·”ÿf•ÚiºÌO6%¶&œZ¡Z×6µž@cùºf•åûP- •ihhˆ%nXªDá§K@ —!¶…ð¶b±øÔ©S ÜÜÜ|ÅŠuuuÄyˆ.ósÊ”)+V¬ˆˆˆ Ð49àAAA púvpp¨¯¯W(ðIg##£êêj²|.Sðèn´2Ùf @FØ2!111))©{÷î}ûöÍÊÊâ¿…[Ã¡ÇæÛÜ®•µiË[ŠBø Û¿ \ XdØØà¶bÓ‘"`Ô ã('PK¬ùÄ·4TƒÐåÊ:wî,“ÉæÎ ö÷÷¯®®¦7–Í1¢-lZwÜ^fee-^¼6m÷îÝðÕ¬š„‹¨Ï!ÑLJ?„Ù”——O›6>l4ÑNÓM~v%¶&œXÆ©¹ IDATZ!ÿDmŽ”¼åët/˧›È[&ÔÖÖþðð±ûöíËÏÏçé&CßæÐä^†èG‘K8R”€{Øþ¯*|ó[ëÖ­nܸÁóü’’’1cÆïËqtt„¯ú422jÛ¶íáLJ Ò¾}û¤¤¤ØØXʱ¡¡¡‰ä‹/¾€ú*Ë ¼¼¼bbbèï`,gó`mmýöíÛÅ‹[YYEFF>xð€| ¹¹¹••Õ¨Q£LLLbbbè/˜'^—WSSƒaヺðQ_¶nܸÑÈÈh÷îÝð„¸q*­ã8ž——g``Ð¥K—””x.nLjˆíÞ½[*•®[·Žñål^ÕÖÖvìØÿ2~—üü| ÃEéD>ïäãadëÖ­7nܸté¹ë¹£”ŸŸ?dÈvíÚeee)•ÊiÓ¦(ÒM~¡›jrÀ#"" ߉' ”™™YYY ¯ õëׯ±±1<<œ~:]¦àÑÍ=ÙfÝ @FØ2!//¯W¯^‘Häêêš——G®ÓLCÍ޹][3*y¢¥T*évØR”@å°å%ÃÆ ]ÚŠCGŠ ]'Œ»°«q¨‚1z>U0F¹²éÓ§“Åöà¿ä;¯|¤¶Ø´îxj•A¾üòK©TJÜxÓ\ŒV- Pƒ†þL›V´Ót–Ÿ€¦Ä4 ¸JµB¢æ‡J •]ð¡dùšuòž ÞÞÞ™™™©©©ééé¯^½¢Ükî¡§@¶eˆ~”¯¯/‡ÆYÂ1lÿò ""bíÚµkÖ¬ÙºukAAATT¥6·Ž”““Ó?þxàÀŠŠ ø®[¬#GŽ@åÌ]»vÁï•”‰áJq‰­о}{¹\¾téRJg³•³yö÷÷×ÓÓÓ××ÿóÏ?‹‹‹É‰‚a˜··wuuu}}½Å±X¬P(är¹L&«¨¨ˆŠŠ¢üèþñÇóòòòóóëëëkkkóóóóóó ½oÈ7îܹ#‰ÈƒMå8äv СC‡’’’cÇŽÑ?âãÄÕÕµ°°ðäÉ“DL4 „c4ª*£û¹{÷î•+Wè§ãöÃ0ssó•+WFDDÔÖÖ>}ú”QVPgù ˜¦?MþÛo¿•——{xxÈåòñãÇ÷îÝ[.—O˜0áÍ›7üñÙ‡•*»@0Í Í:T§gÂŽ;JJJ8pðàÁ·oß«Ü<EØlòÐc\çv gTÆeˆ~‡¶YÂ1lÿò`ÿþýðv`ìØ±2™læÌ™äˆ,Z´hÍ{œœœèW¢á±?ýôSmm­µµµ¥¥ecc#”±ôïß_.—SlîÝ»Çè[9hêDC÷üýš ÔÚîÔ©ÙÃ+W®„„„ܼy“.Ð*‹8ðÙgŸ±=,xÿJɸ¸¸°°°Ï?ÿœò’@__ßÆÆÆ]»v­]»öàÁƒ …bëÖ­#GŽœ:u*}/ØTé ,,,++‹ñÍÂ*½‚X[[?þ<..޼û@“pA8F#w‚1ú°±±©®®^½z5c§«ôG …Bww÷‚‚Æ :ËOÀ4ýipx/ðÈ‘#b±ÞÊÈÈ8zô¨B¡˜?>ÙȇM î.hÖ¡Ï _~ùeó @ *Õ- ÐÐÐðõ×_ …B@°~ýúêêjÊ%æzt8æv gT¶eˆ~£¶Y‚€cØþÕ6œS† °ëH±I[åää°éH‘aÓ ãÐSW¬9Ä· ª‚±É•…‡‡Ú¶m hݺucc#!8©Ò1n­;•^AŽ;fhh8eÊòCBÚ£À-TÆèÀÕÕÕÀÀàÕ«WŒý5ÔN:ÉO4 8µÂ’<»àƒÈòeff‚f€@}M>'''¡PøâÅ ØYYYvvväÛ`Í7ôè4ŸF Û2D?ŠÑÛ,A B–’|µ½OŸ>W®\©ªªâù¨Š¥¥eiiéÍ›7mlllll¢¢¢222à’\RRâíímllü矾yóÆÌÌŒrxqqñÎ;é_ÓˆrFý°ôôô£GÒb,çð0:::::ºuëÖvvvOž<¡Ü;!`ŒÜãÄgwï£GwáÂï™3gÊåòÀ/¶ QQQ¶¶¶NNNÉÉÉŒ»éëÒ¥ËÛ·oOŸ>íèèhÿÆ;¾l^‚ƒƒ+**Fíàà-èëëÍÂiÚ 6sæÌQ(®®®'¥dllœ——Û½{w à TXXxæÌzstŸô_„<66jàÁ3ÂûÐ/_¾d»4¤Ë”àßl Ô|²Í º€P2ÁÉÉI"‘\¾|ÙÒÒÒÚÚ:<<¼¨¨îØTéÙ¦¶îö¹]Õ{¢E.á˜%؆óÿ< ®¶WUU=þÜ××—O†A|||^¾|YWW'•JÓÓÓGý³´´¼qã¼@Ÿ““C×(?~éûYÉå'N”Édƒ "×9räÈ‹/è!f+góÐËË –××׿zõjðàÁüïló‡p©ã®C¹ѯ_¿çÏŸCÇbbbø¿€xÍš5Pü ö&„19¼ª©©ß  _~ù%†aš„ Ò´ÑÈæ`É’% …ÂÉÉI-ƒ€Þ¿¿¾¾^"‘H¥Òëׯëådt–Ÿút£aÀ÷îÝ+•JÛ´iÿmÙ²å»wïN:Åæ€ŽS‚Op •È63è`r@É ÃfÏž““#•J¥RiVVÖ¤I“t3ôýìs»†3ª&ËÇ,aÎÿCôwèWÛ¹ÁX¤­‹ŽY'Œ­œQ?L]U06±­ Fö‹KÛ¶mÕêâ¾¥CÕr†n: I¸Èî©{›?„Á&x‚ñÐNÓY~’ÛBw²É§lB2j=%øt·Kš@î™áC @ŽLèÔ©“.‡DZŒs»†3ª&ËÇ,aÎZÃ0F¿ÙÊ):alålRpMPS×ÃÎGëÕÇéXÓ`k‹îó“ÃÃ<àzøÁ[Ç13èÞ>¶Lø„fT¶áüá¡è„±• XôÃH Ñœ üD þßÀ6œ?bË:íf#[îé,'›•‘?~|LLÌãÇŸ={VVVHž¦5ïw> Ù½{w¨ó7xðàï¾ûŽ¿lþÓ5jÝãX ×MâATmÍ{ÜaiÖù pÎZG“¶hY_"p%"## wìØqæÌ™ŠŠ ©TJù©«ce5íj¿6ßæÇ}¬¶dÕM‹KCY5L3¹8 J• èDíÃ0ÆÜc+çÙ:þ9 š¤?Ç]®2£¸åE5ì÷&ëüiè?ý(;MÓ¥Óî4¨rhë~Þc KóÍo Ô¹Ëù´…íê«Ñ®LMMþùçëׯïß¿÷îÝ•••”èRY h[û°ÉöZ[Ȫѵ¸4—UÈÅUªl@Wjl¹§›œê뽩,çö¼¨&ýÎ3!1&P ýon]:í&žÊ¡ÍÝ(JòñÒ´ù h[Qe9Ÿ¶ÐùËŠvõÕèW‰dãÆ†á8RTTD¹Â«Ke5FšUl¯YeÕ t-®ŒŒ ÐTY5ÍåâTª²]©ý±åžnr¨¯÷Ƈ¦éº§Ö¤ß›¬óG¾,öqêÒi]f’{hsÇA7Š’|èlÞS–æ˜ßøÌº¬4“¾™C‡ÕÕÕUVVÖÔÔ:tÈÀÀ@ ÿ´ª¬Fø£]í7ÐTÅ/­Èª±iq5YV h&ÇG•Mgjl¹§ãœä  8ÐP׿s$$›ÎŸüo².ÖÿÐfCŠ’üiÂüÖêŒ*Ë›N3é«‘îîî-Z´hBf´§¬Æfûpb{š¿]Dú5UV8¶irqªl:Sûc˽''Ù2§ÉE »Îúb„Q£T%úÏ6t–xšm-æ˜Ê°4Áž‡pÏM>oÓF+cÇŽÕ™¾ZVƒaØÇ鷺hØ¢æÈQ£dôäÿ_wk Í#óަGfñqñüùs¤¯†Ð1HíñA@‰‡`é«!tRûC|Pâ!iö ¶¶¶b±Xeù·ß~Û¢E‹ÂÂÂãÇÛØØ0‚@ ÄÇ‹¥¥%ãÃ4 óæÍc¼A. ‹Å? …l‡ Ñ,h(Æ­=ÆSL(Þ¼y3>>^(òÔC B;h(Æ­=†ñ … !Û!@4 š€ñÑã)F,„‡ ¡]þ÷³¾çÍÖÖªŠ@°Ž;Ž5ê‹/¾hݺµ¥¥%½jݺu ¾ ®=HB_”U­œû#@ ´È_?ÝÆß³gO@àääTXXH€:t¨¦¦F©T¦¦¦~÷Ýw‰äàÁƒä’ƒ*Š=züòË/ÖÖÖmÚ´™3gŽæ`ÜÚ`@h‹¿ÂŒŒŒÛ·oã8nee5cÆŒ .x{{Ÿ?¾¤¤äúõëzzz_}õUhh¨R©,..¦”*++ããã­­­G M‘OóîÝ;333úéÙʹ?B B[üµfffîܹ®j‘‘‘×®]óõõ=s挟Ÿ_hh¨±±ñÌ™3CCCq§”ÀÃssseee«W¯Þ¼y3E‰˜í-àoo&¡@ Èüµ6YŒöh’ÇG@h‹¿Â& €ñÑ<Àèžq|„@ „6ÑPL¥ö0ð÷Ç'ØA BûhEÀŒC{ŒøûBÈv@ )lÚc<À²²²žB.]º´dÉnzî:NNNúúúÍãÝ`þüù×®] …äB>Q¢ckkK/´´´´´´¤—ÛÙÙ©e@ >9Ô›C›•~ýú 0Ã0€žžw}OOÏ:Ð˃‚‚ÄbqFFFyyydd¤‡‡´™••U]]]]]]QQ‘ššºyófu—íBn¯J\\\¼¼¼(•ùD‰àðáï_¿®®®~üø±H$"Êû÷ï—ŸŸ_TT”˜˜H„køðá/^¼ÈÉÉ©¬¬uêÔ€ •J7lØð×Br{UòË/¿¼{÷޼€~Q"˜2eÊŠ+""" ÈvRSSccc»uëæêêš’’- ÍÍÍ_¿~îèè8yòä·oßîܹ“|®‰'666â8N,œñi3þüààà   b^?~ü¾}û6oÞܳgO¢pÑ¢EüöÛoÝÜÜV®\)ŒŒŒúöí ë 4hãÆÄ¤I1¢§§йsçeË–í߿ٲe°æòåË_½z•••õã?ÚÚÚ®]»vôèÑÄI'Mš´{÷î;vx{{…ô…P__¿´´ôäÉ“ðw†aC‡•Ëå_|ñ†ab±xß¾}B¡Ã0@{ëÖ-ú:DqxܸqfffssóM›6Aklñ™2eʾ}û~ýõ×^½zaÆJ{9¢½ÿ~??¿_ý•¾Qb‹*ØêÇ“B›ððð±cÇ  ömÛVVV&‰|}}år9üÁŠaرcÇÒÓÓ‰Xéëë¿xñâÑ£GJ¥’²BO\]]W¯^}ðàÁÅ‹ ‚aÆýþûïÖÖÖÜ)‡@ †sçΕ••]¼x199¹´´^ìZ·n]MMÍÍ›7?~üöí[OOO ÃöîÝ[__ûö퇾~ý:77W$ÙÛÛ744“ïÆëêêàTK7bllÜÐÐðüù󈈈۷o×××:tH ìÛ·¯   ¸¸øêÕ«íÚµ+))!~‚üú믕••ׯ_ŒŒ¬¯¯Ÿ3gœ7é aÿþýårùüùó‰B úvíJü"Ü·oüÈÎή  `ÿþý”ƒîp÷îÝ+** 3;vìH$îîîlñ ª«« ‹ŽŽ–H$#FŒppp` ¥½ß}÷c´îÝ»÷ðáÃ’’’ÊÊJÊBX\\ 322bŒ*½¯:DùE¿À¿/\¸œœ, ýüü q×póæÍä³½yófáÂ… …‚²BOÒÒÒÂÂÂ?~,—ËÏ;—••uóæÍ²²²ØØX¸š2¦œÚ‰‹@ ZA__¿®®. @OOÏÔÔ466vÍš5mÛ¶-//ß¾}»žžžP(LLLüïÿÛ¶mÛÊÊÊ}ûöÁÂK—.½yó.„2™lùòåpæýÏþS__/‰èFLLLd2Ypp0,qâDò¬Jü-‹óòò=zôøñãÒÒÒgÏžÙØØCÁè°H$ H$cÇŽ•H$?ÿü³P(d¬éììüîÝ»mÛ¶Á˜˜˜Ë—/·mÛ–18äö2ZƒÑ&uîÜ9‰DBY‰1F•ÞÝô…УG°°°ÄÄÄÒÒÒ1cÆ`6f̹\îëë £wàÀâËM—.]***,X0cÆ ¹\N_e2Ùž={ 'ÏŸ?¯««ëÕ«—H$Z°`\.÷ôô400 §Ü‡½_‹@ þɈêëëSSSá¤výúõAƒ)•J___‡àà`ÀçŸîâââááahhxæÌ¹\Žãxyy9·i///º8iæææ* ¥R™maaP*•8Žã8®P(p'Û™3gNŸ>}fÏžmll,‰ÌÍÍù4lÞ¼yÄï¿5kÖ@222n߾㸕•ÕŒ3.\¸àíí­P(8Æqü§Ÿ~3fÌÙ³gsrr cM///ccãŸÅ‹(•JF÷Èíe´F‰vnn.%,tèQåIeee||¼µµµ££ãèÑ£oß¾óÛo¿¹»»ÛØØÀÕVÞºukBBÂñãǧM›Æf0??z’™™i``œœ,—Ë“’’ÎÎÎ111ô”c @47À„ ®]»6eÊ”øøø;wî8::ZZZÂ[J-[¶lÙ²erròƒlll0 ã3#C,,,èF(Ç*•JîŸzzzgÏž ›:uêÀ¹ç÷êêj€¹¹9†aW®\qww÷òò …Ä ÌÌÌ;wîØ±ÃßßÑ¢Eýû÷'~ôp8¬T*}Úä@©m2*£J!77700péÒ¥ÁÁÁ ,°´´ÄqÜÇÇçĉ...UUU§NjlløúúŽ5êåË—«V­|¸©©i·nÝ|}}áÏF#_ükkk-,,È !†™˜˜˜˜˜øùùyzzrüÖ©©©9zôè´iÓV¯^mddôùçŸÏž=[ TUUÁ zzzöööööö}úôÙ¾}{]]]dd$1ƒ³9¼k×®üüü &¤§§ïÞ½[ 0Ö ÏÉÉùöÛo---;uê´cÇŽÁƒ7440‡Ü^ŽhûûûÛÛÛwêÔi„ ÍqM,{xxlÚ´ÉÚÚÚÆÆÆ××7;;ûÍ›7www …B1}úôqãÆ]¿~ÇñmÛ¶yzzzyyyyymݺU©T._¾|ûöíj]ØdL¹æ[ìB†­]»¶¬¬¬ªªª¾¾>&&ÆÑÑ0|øð´´4©TZ[[+‹ÿýï ‚3f×ÕÕÁÍ&yyyðªãôéÓËÊÊÊÊÊŽ9ÒÐÐËéFŒe2ÙÚµká´îïï/“É`åY³fÕÖÖ644tíÚµ¬¬ n9åryccã;w®^½Jìãg|ŽP lÛ¶ííÛ·µµµð¤[·n…öÅb±B¡Ëå2™¬ªªêùóçäe BwxýúõpΈ#¤Ré¦M›c|ÆŒ“-•JëëëÃÃÃáf¶àÛ;bĶhËd2‰Dãro–aŒ*úfŸ—/_ÖÕÕI¥ÒôôôQ£FÁ/+‡ª«««¬¬¬©©9tèÅÔôéÓÙ6Ëž„„„¤¥¥Áþrss“Ëå . …Œ)‡@  @```гg϶mÛÏŠa& ÝÜÜÜÝÝõôô༆a˜H$êÑ£‡‘‘ÑáÇá®QXn``ЧOsss@@̳ŒFàžIâÔäÊmÚ´quu……D¡Pèìììêê*‰„B!á!¹¥9-[¶ìׯŸ««+qRXŸ ù±ºÃÐX6Ÿc|„BaïÞ½)‘d Ñ^Žh÷îÝÛÚÚš|§“€¶¨ÒƒCùžº}ûö:t Z k:88¸»»·hÑ‚1ÎÐ=z )}GŽñcÊ!v&*Á IDATĆñ¢%|žš±æ¡C‡ˆ…ÛÍÝPi§Éû/øË>…”rþÖ´[“›õìhƒ øøß2Æx“†£°¢¢‚²k†í6Z·ø»Ñ;Z?VÝ q—k«íM@+}§­“"ħ@ @µ@ ⦹~Ò999á8Ÿ¡F âÄ?üPTT$—Ë¥Ridd$Ÿ÷)«¥Ì§ÅcÐ2?ýôSmmmPP««ë„ óòòÚµkǽP©¥Ì§Åcøký˜?þ‚  ——÷îÝ;X8~üø•+W0àÝ»w%%%°pÑ¢E‹-êØ±cmm­¯¯/|5üÈÈÈèÔ©S—.]Z³fMIIIFFƽ{÷þýï·hÑâöíÛ-[¶ô÷÷—J¥EEE€AƒÍš5+::zÙ²eðÅ+ð+YYYË—/Ÿ5k–¥¥err2ŽãFFF*MKK[¼x±‰‰Ivv¶®£ˆ@ ˆO õ ;P髯¾"~ÿavïÞ=¨BÇ&[HVæëÖ­[cccFFFDDDtt´\.ÿå—_Ÿc¡Š!|Ú #@ >I4×#$LAYs///ò…Ðÿþ÷¿Pë•M¶¬Ì_ÀFœâÌ™3oß¾µ²²âs,ùÅ%@ð¤õyBW"$tõΜ9óÕW_¹»»¿xñ‚ϱr¹\+.!⟃6õ¡ÈC«V­È…æææuuujùDØÏÍÍ¥D B‹\\\|||~ýõWww÷tìØñ?ÿùÏëׯ¡BÞìÙ³gÍš5sæÌ5kÖ@=B¶- qqq555C† !*ØÙÙ¹¹¹%%%á8Î&[ÈAÇŽ………M8@ ^tïÞ½®®nË–- S§N………444LKK{ðàAëÖ­õõõçÎëããcffVTTô矚››·k×îÅ‹„ ÁîÝ»«««W®\iffÖ§OŸû÷ï—””téÒ.¯^½Šˆˆ077ïÖ­Û«W¯ááW®\IMMµµµ…"><°²²²µµ}øða^^^Ë–-ù X½zõèÑ£Ñ3…P­è‚½{÷J$’ÆÆF™L–˜˜8dÈb‹Je>www¹\þàÁƒ·oßJ¥R±Xm²ª@ º ™ô…B!º¼‰@ Ñô• >É®EWšÕ,Olmmkjj>ÔÙ?N´¸1Eø‹†¹¤§§çïï?dÈ;;»—/_ª4‹†3‚'ÿ[õôôÚ´iSYYIþøÒ¥K‰‰‰.NóçÏ ¼pႺv´å€JôôôΟ?ïêêzçÎ&œK?uÖFuaŒ ·Ò$Û§„©7666Âw©kÑOzêþÿæcÈ·&؉ŒŒ”ÉdMî}CCÛ7oÚÛÛWVVÞ½{Çq¶a«ápæ†q}µ´´ …Z·lmmm``@-‰]uu5݈ºålXZZ¶hÑBÝסð±ÀÖ"¶ª[¿‰ØÛÛ_¾|¹¦¦F&“oÞ¼™¸8ùçŸúùùñ¿VJ¿dºeË–ŠŠ ¶5”””ìܹSK·oßž””dccÈÊʪ®®®®®®ªªÊÏÏ íÕ«÷~•~fdd@›‰$++ëàÁƒ–––ð#uƒ¬3È1ª”&¹?%LMš4éíÛ·¤ÄÓÝÝ]"‘Ìš5«²²rÅŠ€è…ŠŠŠÔÔTrZp¤.äáÇUUUÕ4ú÷ï€g¤|zàÀ²•ùpéÒ¥çÏŸi›’’BüáááAi ût>†|kÂØäÙûýúõcŒÜL÷Ýwß3 %E Ëùd‡~ýúuuu5å±±.]º<|ø°®®®¶¶®Óümr[4hPBBBCCCCCClll·nÝ`܆þâÅ‹†††ÊÊÊ£GÁúê–Ï;—œü=‚IÛ¿ÿ¸¸8©TÚØØ˜˜˜èááAî/CCÜœâÁ6ÈÙ³g«ªªˆQÏf­El1T·¾F\½z5;;{øðáæææ+V¬¨««ƒû6úw좣£ïÞ½K_ùå—wïÞ5a!,--ݵkWs/={ö¬®®&ºV,Ÿ:ujÀ€Ó¦MKJJJKK355ÕÄÏ‚‚hÓÓÓsÅŠÇŽƒú8o‹Rb­4Éý)Ù†a×®]{ðà%Iú÷ï/—ËçÍ›'—Ë׬Y#ˆ^}ú´k×®iiiçÏŸgÜ<1f̘aÆ1~¿a³œ˜˜˜””Ô½{÷¾}ûfeeݹsG(š››¿~ý:<<ÜÑÑqòäÉoß¾…_GÔ-”––Ο?Þ¼yóæÍóññ¦ÂUÇÕÕ5%%%::šÜ¢Å‹çææêéé%'NlllÄqœXðØ,0¶ˆ#†êÖ×±Xüûï¿CCàÒ¥Kþù'üwíÚµð]-zzz®®®«W¯>xðàâÅ‹Á°aÃ~ÿý÷ÀÀ@kkkhв.Z´hÿþý~~~¿þú+y!?~ü¾}û6oÞܳgO"3&Mš´{÷î;vx{{…Œƒ :Ó¹sçeË–íß¿Ÿgb4>sæÌo¾ùVðððøöÛoáß;v ìÔ©†aüñÇ«W¯÷Äbñ¾}û„B!œ¸Ç'“É&L˜½?~üï¿ÿ¾wïÞ‘#GÒý\´hq:Àüùó—.]* ›àرc™™™ŒAfk×ìÙ³<øý÷ß·k×. @—1122‚ï1€†bÖ¾}ûŠŠŠ={öîO”ðNž<¹±±‘ü*>ÀÀ%IçÎá{0 #÷‚@ ˆ½uë%Ý9R‚½>íŸL¥LFDvíÚ8q‚~Ž|Œ1N܆-Y²¤®®®¼¼|ãÆà‹/¾ËåÓ§O÷ôô¤4§ý3ßmlRrlܸqfffssóM›6}ñņñé}¶XQBJ^°•sgÔ_|AùD)G>|˜¼\uîÜY&“Í;>ñåïï_]]Íø?&&ææÍ›Œó5£e@mmí?üÞ·o_~~¾H$‚"? €ÙrìØ±ôôt¡P¨n9`ß¾}IIIİ…-µ±± ;v,lѶmÛÊÊÊÈ^Ý»woß¾}D¿ëëë¿xñâÑ£GJ¥.„[ÄCuë“¡w(@~~þ!Cà÷w¥R9mÚ´ &( À·ß~;jÔ( Ãôõõ7lØpñâÅ‘#GöèÑ#88øìÙ³trrú÷¿ÿ}õêUzïÝ»wïÞ½;vœ:uêœ9sˆÀ­[·îܹsmÛ¶>|ø;wàu’_ýõøñãNNN½{÷¾uëÖìÙ³9 ™8qb»ví~ûí7âZݸ››[PPÐçŸX²dÉ/¿üêäɓ׬YSUU…㸗—W\\œR©$ŸOMM †a0Ð6løïÿÛ¡C‡®]»^»v~‰©GÛ¶mƒ/ 722Úºu«»»;ŦR©422"n¤Q‚ÌØ®~øá?þèܹóðáÃÃÃÃ7mÚD9o³ÆdàÀfffáááPåÇñ¬¬¬çÏŸÃ+!ÜŸ(á •H$pZ$ü÷îÝž={ŠŠŠöïßO¾í ÚÚÚ:88Ð_øÎ‘º”Ndü—R¸{÷n©TºnÝ:²î|€DDDH$8e4(33óåË—0±ûõëרØÎÖÀO4ß(Ðs¬  `ÅŠðÀ7®^½Z,óì}ø-Š#VÆaËQNŽ 9£ÌÍÍ;vì8jÔ¨/¾ø¢uëÖ–––ôðþù.Š3;wÆ0 ¾œÇñ¼¼<⥒d[ -òòòzõê‰D®®®yyy8Ž[YYa–‘‘ÏXTTÔªU+ ÃÔ-X[[¿}ûvñâÅC† '-))3fÌ­[· KŽŽŽb±˜ð­sçÎýúõ;~ü8Q²qãF##££G%[ÄCuëC»O5ƒÎÊʪ¬¬ ýúë¯?ûì3â#âKü.¶gϨøüù󺺺^½z‰D¢ Èår¨ÜKü"„7´ƒƒƒaýsçÎI$‘Häàà@W: …§OŸ^½z5,Œ ƒ++ã/Bè aüèÑ£EEElƇ*—ËLJaXnnnaaáÏ?ÿ =Àkↆ†R©”<ÔÅbñáÇ۶mkooïååõæÍ {{ûòòòßÿÚ?räHqq±••ÙO™L¶råJ@0þ|…B1bÄ à ¼þ“¿‡††&&&¿BÈ TiÿcÎ7²Æ‰D‰dìØ±‰äçŸ&º[eï³ÅŠü‹1¯lå€=£þõ¯UUUÁ‡˜—,YâëëK)!¬:tˆü»múôéää‡ÿ’oª9rýúõþþþ™™™ÉÉÉ6lð÷÷§ß%¥[x{{gff¦¦¦¦§§¿zõ ~³3fŒ\.÷õõ…8UÊÕ-DFF644¤¤¤äææÖ×ד¯B÷èÑ#,,,11±´´t̘1„·¿ýö[ll,ád—.]***,X…üÈ g´ÀØ"Žª[žšÞ¡*/€ QQQ}ûö Ð××ß»woll¬‹‹ ã²üü|…B¡P(233óóó“““åryRRÀÙÙ™\³_¿~„x¡B¡ ¾Ë{yyJ‡û÷ï‡J‡€9sæÄÄÄÌž=ÛÏÏO$™››sû ÞË*Šììl8+1ŠŠ*((l»££ãˆ#†êååUQQñæÍžíêÝ»·¥¥å… d2 þ‰IÓ`4õîÝ;xÑŒ~)¿Ègdd\¾|ùÂ… ÇŽ³²²ºpáåÂÿÔå¦C‡!!!W¯^eüýÁ˜ä ;wvwwoÛ¶í­[·®\¹bff6f̘nݺÁß4Œ ä¶ÿñç„1Çpÿé§ŸÒÒÒΞ=›““@üÎVÙûܱ‚°¥(wê2fÔùóç}||ŒŒŒ,--gÍšuèСsçÎQJ8<áÆÓÓséÒ¥K—.µ··wvv^²dÉÒ¥K)[ÉØ˜0a‚±±qdd䃬­­áí°°°˜˜˜ß~ûmûöígΜ!®þ©[xñâE```¯^½:uêtïÞ=òBXYY/‰ÈJ>>>—.]"¢±uëÖ„„òDF Œ-R7*ãFïP•Ý'à8¯EìÝ»·W¯^W®\Ù¼yóôéÓ/A 6/l<¼ä5≠lâ…Ø{¥C@rr²X,‰D'Ož9räãÇkjj,,,JJJT¶–@©TÂþc4®T*ãââÜÝÝŸ>}zîܹ… 0ÀÑÑ144”íªËáÇýüüÈÃÇq(ÓXXX*..÷G!8Ž_¾|ùûï¿·³³4hбcLj>¸uë´iddùÃ?x{{s™hWëÖ­ùùùÄ)t6¥I¸pÊŸ&233wîÜ yíÚ5__ß3gÎ/uª›ºŒìÙ³§ººzíÚµl2æ¹BTTÔÊ•+.\XVVvûöm¹\ž““3iÒ¤6mÚØ2ÊÏÏ/44ÔØØxæÌ™pPJØ 2îÝ'?>øã?¢££%‰TW950àßÿþ÷’%KNœ8ãøëׯ¿ÿþû“'Oæååùøø¬[·ÎÕÕµ°°ðÔ©SsçÎà8®V9`ùòå¥R)“É.]º4jÔ(—ôôtÇssseee«W¯Þ¼ysiié”)SÌÍÍOœ8÷õõ5jÔ¾}ûV­Z¿€Nš4ÉØØ>²B·àââÂØ"¶²E@eÌùwhèСüñÇ‚ îß¿¯T*Ÿ>}…5Ž„N:‘¯/rrrp?yòäÍ›7a9Žã£Gžãxhh(åºO+•ʈˆˆ-[¶XXX„„„<~ü877wݺuqqqð¢¹L&£\GV*•r¹œ’¬ÙÙÙ8Ž÷îݾ[®{÷´4ŠÇ_¿~ýÖ­[ŒŒ`ÂrÇáH$ñññä½ÜÀ)ÉÙÙùÙ³g$&„Òä¥K— ¨4yîÜ9ǹ?e ¯™™Yaa¡Jç¡«°ÒÒÒ0 355Å0 žÅÛÛûÈ‘#š§îÊ•+‡ âëë[^^ÎV‡1Èܹs§¦¦føðáñññp‹‰‰6l˜R© S9õÒùÆ–c=zôX´hQDDļyóΜ9óôéSø)ÏÞç†1¯8Ê!låçç'—Ë ”J%\³é%ŒdddÚ¶m hݺucc#\K`âtð—üqϧNNNB¡ðÅ‹0²²² ìììòóó%ÉÆá@ !^u©nùÑ£GoÞ¼yñâEÇ p¯ªªêÖ­[PPÐæÍ›ãããáøÕ××oÙ²eiiéŒ3îܹóîÝ;衃ƒCBBBß¾}FFF† >¼¼¼¼¤¤ä§Ÿ~¢[`k¼ä@á¤I“ÔªOe<»@ðôéS‘Hw{{yyõïߟüÖ†¦qïÞ½ÒÒR{{ûN:M˜0~Ù¼{÷nVVÖªU«¬­­õôôfÍšwÇafbbbbbâçççééÉxIW¥Ü ›ñk×®éëë;;;Ÿ?^¡Pܽ{wذaÄíôÚÚÚ¼¼<(>ÅÍ­[·ÒÒÒÖ®]kggçàà°råÊÄÄÄ'OžP¦¹âââ»wïN™2åÉ“'©©©Œ“`}}=ܫ‡øøø7oÞøùù999µk׎¸Ü¯³˜”——Ÿ8q^¸†J“§OŸ655=xð ŽãÜŸ2†×ÖÖ633Çñnݺ>|˜qs@OOÏÞÞÞÞÞ¾OŸ>Û·o¯««‹ŒŒtuu…‡$$$°¥.·Yr…®]»nܸñâŋϞ=kÓ¦ <››·ÊY¤Ré«W¯ìíí#""`GDDØÙÙeddÀ_rDzÙÿTò-ÇvíÚ•ŸŸ?a„ôôt²>ÏÞ§ÇŠ\È6l¹‡3cFá8žŸŸ/‹_¿~›› kÒKIIIIJJZ´hQ«V­œœœfÏžýàÁ¶×M¨ElllMMÍúõë-,,¬­­-ZTZZ ¿L¸»»[XX(ŠéÓ§7îúõë°ÓÕ-wqqY±b…­­­Ýœ9s’““KJJŠŠŠ<<<6mÚdmmmccãëë›ýæÍ[[ÛaÆ>}šøº¶mÛ6OOO/////¯­[·*•ÊåË—oß¾½°°Ñ[‹’““c¨n}rôxvßß8pàýû÷ëëë%‰T*½~ý:qù…r_ظ’––oظ¹¹Éåò…  òãP¼P&“I$’'NÀÍ2€IéP(^¹rE.—766Þ¹sçêÕ«Ä_òf™ââb8œ(ÎøûûËd26ã°NTTT\\´9dȹ\>þ|bd9räÅ‹Äý'¸Íšq12dHjjªT*mhhxõêÜ” h›z¦M›&—ˉÇp;;ñï7ß|#“Éàƒ"lA&·ËÇǧ  óîÝ»J¥–ë,&‚¿+M>~üøÝ»w=‚’ÈÜŸRL;V&“Á ô'N”Édƒ bÜ¢¢P(är¹L&«ªªzþü¹¯¯¯@ –ºt³”Í2Dx9þ “½'11qÊ”)„¶| œeïÞ½R©´M›6ðÓ–-[¾{÷îÔ©SŒ;æÉÇ~ŠùFñžcëׯollœ8q"†a#FŒ 6°ðì}ÆXA™6ÂaJ^°•³eÇ©éз´ôë×n„z®pO#ý@¡PÈý¬Å2†a³gÏÎÉÉ‘J¥R©4++kÒ¤IØ{基ººÊÊÊšššC‡Ô*÷òòzùò%ôüÕ«Wƒ†ö}||`¹T*MOO‡{Œ7lØÀøP „²c…ÑG‹c¨n}þÈ †aB¡ÐÚÚÚÝÝÝÔÔ”Ü[d…?òßäNÅ0Œøˆ^Þ»wokkk¡PHî`ºÒ¡P(tvvvuu‰Dd#lÿü]žnœÃaHïÞ½kjjà ¥gŒU=ºwïNV[¤²víZ‰DBÞåH©}¦ŸŽ£]"‘ÈÍÍÍÈÈhË–-ÄC™:‹ )MÚÛÛ …ÂQ£F=}ú”x”ãSŠ©sçÎEFFB÷ž={Æ8ºDn¼¤–ºt³ä€+Àrú¹ÈØòrÊ)àlsûàÓÉ7zŽ‘ÏHÎ.ž½Ï+ÊÊMOQ[9[F©½—aÛ]\\ žk“gd6Ë;vìÔ©¹÷áN]ww÷-ZPzY­r¾³³3Ù>,oß¾}‡ˆòëׯ3>NJ¢ÒG‹Øb¨n}í esœ6á‚Ï]¢ÉIÕ2…aØÎ;Ÿ?Îg·*·}KKËñãÇ¿yóæìÙ³ZxÙÁ{F½fÍšqãÆ}ýõ×yyyÄø£­˜Pr‘Þ‰ôOɦƌSZZ ¶lß¾}Μ9j9Æxå_•f5¯À³ŽVŽýTòMeŽ5­÷‰jp!¬©© ÙÅ–¢j g­Ð“'a™Ñ8ÇÔªn9›}r¹Pýñ´¬‰‡jùƒP |Šnûöíêv6…/¿ü²²²2&&ÆÁÁA[¾¦Nš’’RUUURRªKªÐVLȦž={F¾+`Q`æ6¥ò•u4¯À³NsKæÓÊ·„„„&ô>¹š··÷СC‰wN²¥¨Søg! á=-M€—´øÝœ0 //7ù’NÓÐJLȦlmmÑܤE>­|Ó¼÷±÷%l)ªÅÔE @ðÀÎÎNs#ê~ƒS«¾µµ5ß—ÎqÖ744$txÂÓOÊãÒÜØbniiI¨+ð­¾¶Êu€ºËcÙ,³•«;Ô &›}¶äa³£¹ÿÿ_Óõ#Lo„.ÐP¦‹MìŠ?Œr\~~~t¡8xÏœM¾‹M^‹MÔŠ€"¦ÅQÛ¶mpû5ñd¶ó²ù !ËzõèÑ#**ª®®®¡¡!!!ð„Í[ÌUÊtQZÊV_[å|Ð0ýTv®JÔUƒSW%Ž-=Ô &›}¶äQWã{ ÿÒõcKoŽ9¿¾h"ÓÅ!vEA]9®V­ZyسgX,†ÏÞ²Éw±Ék±‰ZAèbZlõW­ZUYYùÍ7ߘšš4ˆx˜í¼l~BȲ^±±±III½zõêܹsJJʽ{÷à-pÄœ[¦‹ÞR¶úÚ*烆*qÜK -58¶ò&¨¾©LûlÉ£–Æ›ÊüOH×-½9æ@JMŽôFðE™.±+ Mã"nŒ0 ¼¼|Ú´iÒËééõ嵋¨üˆ.¦ÅQ?--íÔ©Sp. Ûg;/›ŸBÖËÐÐ0++kñâÅðŒ»wï†ï_e³Àsn™.zKÙêk«œÒ^6y0 Uâ8:—Œ¶ÔàØÊÕU}S7˜löÙ’G]7•ùÿ}º~œéÍ6òOoþ×ðUx­[·vpp¸qãŽãæææVVV£F211‰‰‰ihhP*•”kkkì½Ø€,vE>cËèþz9ücëÖ­7nÜ ÞzÎVŸ×²²²‚/,‡åŒ¢Vð#(¦µ{÷nøÆ<ŽúFFFmÛ¶=|øð!CÚ·oŸ””Ë}^6?Á{Y¯õë××uìØÿÆ}—üü|ât d1rÌÙdºRRRp§·”­>|®æåð¼z"ÑÅš–~oß¾åè\2MH?6Ë*UâÀßcz¨|¶Æ–<É ®ÿÿtý8Óg™ù§7‚ÿ“ŒïÙ³§@ prr*,, T*•#GŽ›uËÉs˃59ý84Û e­«ÁµiÓF-•8À’–ê“{ Ñ“G]7ÿÿ!éú¦7<œcÔpvEüµâÈt±‰]Aš,Çquu500xõꟅQ^«wïÞB&Q«¶mÛ2Ši1Ö‹‹+--uvv†ç255@i.Æór8L‘õ‚;vÌÐÐpÊ”)‰DeKcÎ&6räHÆ–†‡‡3Ö‡¤y99Üò`MN?Í6xv­«Á5A%Ž1=Ø4Õ8‚É1ÐèÉÖ loþÿCÒõ#Lox8ǨáìŠøb±øðáÃmÛ¶…2]W®\òŒäK”CÈ%îîîVVV€™3gÖÔÔlݺ•ñ¶í£GÈÛ¥èÐõMsæÌQ(®®®tèõ££££££[·nmgg÷äÉ“ÄÄD¡Pèää$‘H._¾liiimm^TT_/|ÏÌ™3áÆ6Žú€ààà’’oooccã?ÿüóÍ›7ffflçeóÓÖÖ¶²²rüøñäWTTŒ=ÚÁÁê¥Á;l-eŒ9†a QQQ¶¶¶NÿÇÞÛGW]]ùÿç“„o¡4Š4÷PXQÁè ‹1fCÐhq‰„ªËd\ f0]²|¨´#B°P‡:Â/ Ó >aiQ@ ‰ σˆÈ"D’ä~~òñzÏyïûÙŸœ Îû®º9wŸ}Þ{ŸOžï«[·Ï>ûìwÞ‘o•«=)Zo*®¶Xû=±æŒѬ8qÇe&vDA;ÌDùµÃƒòpë¿tƵŽ·ñ ô”p¼­«™˜.»Š“œl:úpòäÉò?ëµx-C­<Å´ˆõ+W®¬­­=uêÔ<Î ÂziëÔb½Nž<)?¡óxcÇŽõ’¨'Ež'ÄtÅaÃÐzSq?jÎøùi®wüPfbG.õk&ʆ‡ËxÓæ¿¤Æµ¥·ñ ô”p¼­h9Bˆ¸)—_ÈûÿYkJJJçÎ333?ÿüóÚÚÚÀßž–¿÷ólllTëQ×;Ž“’’Ò½{÷†††/¿üÒ{•wgÿþýj6ÇqRSSý¬—ŸS·nÝz÷îÝêú¸}µu–••mÙ²eöìÙ±F©–›D=)ò\VÒ­[·úúúÇ«}ÔžT]o*îGÍ¿„Íõ)bœâ2£8Ý4–þÍDùÑðÐù}ÖIk oA>­ZœüŠ”lÉO{ýÇMåñ™?•õBBÛq{ÁÍcj_ƒâ6·ù™‰87ZÏŠ#5³žKp\[àx[YYYYYYYYYYYYYYYYYYYYY%WZŠXFF‹Çf*?7 dqæÞ›Ï<–ß,~€1éS\ `Ž+?bxXy 6‹5䋨Òâ¿EìÆoܸqcMMÍ™3g¶nÝêý³–g¨Í ˜@.gÎS Ñ×?R–ßÖòyoRÚáñ)b\¹8@ñCÃ֣8«Y®-ªÓb[ZÜšy ³óœ ñØvíÚ%/^Ÿ>}¶oß¾nÝ:‚g¨Í Âr9sR* Ñ×?R–ßÖòyoÄðÄ ñÞˆqeáÑ0ëµãG Wg5‹{mQ‹Øã~ÔÌkˆ˜qJ.vÑÑQÄ233?øàƒÑ£GË÷€xî¹ç¾ùæ‚g&˜ø@"?+À˜@´ž…'Dô5¢~)Ëokf :-±Å*©ØEéz°‹ >þøcïq‹”‹Íƒâ(?Ó…ò èG’z.aÀöÚk¯uïÞ½ººzÉ’%ò,4€M­üR°5Øöç?ÿy„ êb l{ñÅŸzê©|ðÆoÌÏÏBĽJÍ“p¨fÍšuÕUWuëÖmÛ¶müq÷îÝ»uëö»ßýÎ °ÍÊê"ÖÙõk±^ZFTVVâöiÑn‡:ÌÕéÓ§µë»1y‡)‡â(?À†Àr4×µA r³¶ "Û²$ÛˆK'w?§À6+«‹Rë¥eD¥Ü>íæ`Ì•v}7>ï!åXùQ(ŽòþH©tí¹,€íB‰«JûÕs€m ‡ÊÓ¹¶YY]”BX¯„Œ¨8LB»!Ì•v½Ãç¢}¹ùY˜.ºN­?RÚ„ê¹,€íŠûQ3m¨5qJ°ÍÊê"–#ñöF”óCL—h7c®ˆõ,Þ!Bʱò£:鸮aìâ~¼§žËØ. ¸5Ÿ›¨m••Õ¹üê§ùëQb½©}¹q”Ÿµo3el\ÜÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊêÂÁÔ¾k"¢Ü¡<ÐòP~G4>b_–P~t^GœBo~ý–SxqÄÏÐå²²º¤¥åöÝxã7n¬©©9sæÌÖ­[½ßØF”;”ÑòP~G4>´¯§X„ÁÿCùÑyQq ~¡Z¿å^‚q?j&×].+«K]ˆÛ·k×.ù¼îÓ§ÏöíÛ×­[—ššJPîP--å'âˆÆ‡ö•ŠC¸ü?m~t^ÂÄ)Dqmý–Sx Æý¨™\Ct¹âd¹†V—œ´Ü¾ÌÌÌ>ø`ôèÑò½Hž{î¹o¾ù&-- QîPhy(?Š4>´¯À\@©XþÊÎKø€8…(Nø¦ÖéÍr /²xÜ­L×].õ™`¹†V—”Ò$·oá…Æ ëÑ£Gyyù† „G5j”÷7¿]»vD"®ëÆRî„åå1¼½ØQ~—4>ùgÈBÆGì+šnsçΕïÓèÕ#ÿO,ÿåGçEqyŠÚ8í›Z§ŒHNáôéÓ gó¨rÄÛÛ¾}»ëºª“h½|‡çÆ¥ÏBˆöíÛ‡B¡‘#G^~ùåëׯ¯««;vìXܽ•¯íÔ©SVVÖÊ•+]×U_Fã"èr©ÏË5´º¤”Fpû÷ïÿì³Ï†ÃáÎ;F£QD¹#øhom~:._Kã#ö¥¹€*ÿO›Åæjã }³œÂK$î5(©\Ct¹¼­-×ÐêÔÙïŠlÞ¼Y>=_xá…©S§.^¼X~ÅPUUµiÓ¦p8ܵk×;î¸ãý÷ß÷(w×]w]ffæ¨Q£b¿ƒò íÕür1Š @ãÓîë!Ü~ñ‹_¨[kùj~t^ÂÉ)\±b…ã8yyywÜq‡üˆ¥'ô q çÏŸßLN¡¶ƒZÑNZ™Õ²eËŽ=ZVVÖªU«ù—yûí·U®¡¼¡P¨   ´´tøðáÚWýßÿýŸš‡¸\7ÝtÓ}÷Ý'¿áÑØØ8yòd!ÄéÓ§?ùäûÐê"V âÊ>xðà¬Y³ŠŠŠ^~ùåx ##Ô;Äÿ£·WóÓq•Ƈö¥nZþŸ6?:/Š#N!ŠÓ¾YNá¥÷þ¿›4®¡º\Âr ­.U¥!n_ß¾}Ÿyæ™âââM›6¹®{äȑ֭[ÿä'?©¨¨ÐRîP´qß¾}‹‹‹Õü:t@û ¨Ÿ@¸iùÚüPýPñQ|ãÆ„o–SxéÄc[œ$®!ºtòr Ë5´º”¥åöeddTTT¬Zµ*33333ó£>Ú»w¯ü-2-ååñv‰ƒ¡üľˆÆ§Ý—F¸!®¡6?:¯6Ž8…g‘ðÍr /¸z1µß²n׸\q²\C«KNˆç—““#y„555{öì9r¤Œ#ÊÊ#¥>ŽQ~G4>z_¡C¸i¹†(?:¯6îN!ŠÓ¾YNá%÷£fr Ñ劓åZ]R:{nŸ|߯xqD¹Cy¤TZÊâØWènZ®!ÊÎKÓþïPË/Dõ[Ná%÷£fr Ñå²²²Â(·Ïÿ§·öåæ1%⼬zšy^Ë)¼èãç@ɾ,VVVVVVVVVVVVVVVVVVVVVVV­¤™î W\ž¢Á!^ —ö‡êáò Q~V­¸äH‚XÙ¢x~züˆf+«K]q´9GH3SÜAn=ðï»ï¾X¤ß'Ÿ|"#Ñà/KûCõpù…D~ñC¡6M4d‘#Ñú–Æó»Ðã~ÔL!õ´²²ÒÐæP!ÍLq¹õ áÌ™3+**&Nœxÿý÷ßÿý999IÑC¼@íÕ€_ˆòKÅòµ¢!—‰Ö·4žß…÷£fòÑ0ÇÉò­.Ei¹}Ú84sLp¹õÌó›7o^yyyZZšÓ$!AƒÓò¹´?TO~!Ê/åñé RqDC9­oi<¿ =×ßdð‰aŽ“åZ]R:{´Ü>mœ@š¹MŠÍÀårë!x~ápøØ±c“&M …Bk×®ýë_ÿ*0EoûöíZ^ —ö‡ê À/Ôæ—ŠåÒäúX¢!—‰Ö[áÇ#úhqq±GrÑ ­WãÿøÿȪçÓO?õx~ÑhtÙ²eÿú¯ÿzÝu×íÝ»wêÔ©Bˆh4Z__ÿÖ[o9²{÷îˆ'y“'O~íµ×\×ýâ‹/þíßþí¿þë¿:$8´¿X¾`\=999O<ñDŸ>}¾þúë%K–Üwß}¢‰_ˆöÕ*ŽGHgDÙ3gzÏ;¢BÖ‰bz±N¶4Îß…÷þ¿Ûļì²Ë&L˜ðöÛoÇ-–üðCÄó[´hѪU«Þ|óM×uÛ´iãºnuuõ¾}û„Ž—››«åÊ¢ø§ý\F¿ýðF(ß…?ïâ‚'¹"ŽòÙ×àÕFòY'—ïÈ}èµ´‘¾8ãˆÛ‡øyžâ¸€¦x„ˆÏ‡âÐòˆ¸¶~äƒö\4íOÍŸp},_9‰8v¨SèDJ×Òø|zܚɔBLð$ÊÃE{¢ü4bSø¾’è\ÄzV~ÿ(PíU".;÷¡×ÒFúb ¸}?OJåšâ">Š#ZŠ£ú¿P{.‚ö§ÍŸp},_9©åØB'BPº–Æç»Ðã~äŸ/H0Q£¹àI”‡‹öDùiĦÿ+ÉEróûGj¯qÙ¹½–6Òk\Àí#øypCß…{zã ÆŠ`¢Ñå‚'Q.Ú“¸2±Éº’,i€üD"æªÒ°Rõ²sz-m¤/Ö¸&-·àç À t›;4x„ˆ®§#ZAÝCõk}@ç€öGûƒÖÇñµ;"þ_8FÒž-_°Eñ…"‚¨m4ö²szöJž³«š&„Ðrû~â"qy„ˆ®§#ZAÝCõk}Hø¾ûq´¿„þ¨ë…ÂÔ qìˆN¡i¡t-Ïw¡Ç½Æã ƾîªÒ|Gõ²³z-m¤/Ö¸çRi´?êz¡ð‘ÇÎu]m§ˆÎº®«BéZŸïB{ÿß Ê”C⇨mô±cÇXàI”gÏž=,´'JŽD\î¹´ë `êÊk¯*â;j/»à<ôZÚH_¬q!¿"\´hQ^^žüÄãö¹®+ùy¹¹¹S¦LéСƒäçeeeI.`nn®ü#Fôïß}þÒ·oß²²²Áƒ»®F=î`¿~ý´ñXº^4õèz(~üøq--Qôˆú‘ÚsI©´?Úu½Pø‚Hòù•-ÿ3–c§íÑYÑ¥+((ð t(¿‹Ç¶xÚ´i>úèÔ©Süq‚/Fcù‚ò_£ÑhCCCCCƒüN üÿqŸ3iÍO¢<®ëjãÚ“8¸q¯$q.ízƒW^{UÕ«$¥^vô0D7äpKõ =~¶AZnŸü<‚ (ÕL!¢ëѼ@-]O'êG>hÏ%¥ÒþhÔõ*_íè`޶Sĉ´P:”߯Ï/_ÐÁ$ÍO¢<,´'}eÔx€+ÉBšºòÚ«JðÕËÎ}èµ´‘¾Xãg{‰¸}Z~^¬´¼Àfò@×Cqiy4uO­ù@Üj-íðG]¯ò‰Çu AéZŸïBû‘¾ |”k“ FsÁ“( íIä§ãÂ÷•ä"H¹ùµuj¯*ÁwÔ>X=Âa7ÿþïÿTnâçyrt¼Àæó@×Cqéz(®­ù€Î%0íù£®×òi'UŽê:‚Ò¡ü6,îGÍä ÒLð$ÊCÇÑÁµW†ˆ ΕԞ‹¾Â¬üjÚ«Jðµ‡`½–3Òkü#¢ý4Öÿç¶´ˆüç%έ3IJÅ|A$Tç:`ããçLɾÉ~D¬'W>ÀUåîÈuØÆÍÆ­¬¬¬¬¬¬¬¬¬¬¬¬.Aá¤$¶beeeee•<¥®[·®®®î³Ï>‹û™áÚµkëëëÕxœZµjµlÙ²>}úÄýA=ŠËêܹsUU•Ù“XYYYYY‘÷ :4î燹¹¹Úxœ^xá…òòòÌÌL?ñ.]º,_¾üäÉ“õõõÿ÷ÿ ½feeeeeeRŽã,-"ž IDATüéOúë_ÿ÷'J(«œ8qB*ýÄÿçþçÿ÷GŒѾ}û_ýêW§OŸ~üñÇíÇB++++«ó¬þç>sæÌ°aÃâ>n¡¸§W_}UûÇà(‰Dþó?ÿS~dMIIyë­·Ð{pXYYYYY;ý¿ÿ÷ÿ***^|ñŸ/ÎPÜÓž={-Z¤þ+ŠoÚ´iÇŽÞûßï”aeeeeeun”"„8sæÌ‘#GT> ŠKµmÛ6++ëàÁƒ>ãBˆÇ¼uëÖÿûßW®\ùË_þR¾Åƒ©“XYYYYYÐÙ/Ú¾ýöÛØwãõ„âBˆN:µjÕJem£¸â£>’\’Ö­[ÿîw¿Û°aƒ|K¡Ø5eee›š”ðWu¬¬¬¬¬¬š©³?ÆC#a–×êºneeåoûÛßýîw×^{íŠ+Š‹‹Çûu¡Ä¶Éÿäȃ»[YYYYY©:ûðŠ+®ˆÃ(Óq!Ä‘#Gêëë322|ƇþûßÿþøË_þFÿþ÷¿oܸñg?ûYܲW_}ÕûÿÀÆ:•••••Kg¿5Ú±cÇ}ûö©u¼xß¾}.\Ø»woï{•§N:tèP×®]ã^‚â[¶lIKK{æ™gúõëç8ÎÍ7ß|ã7~þùçqË¢1²­¬¬¬¬Î…F]__¯þ™Dlü®»îª¯¯¿å–[b×üþ÷¿ß±c‡ú›Ÿ(>tèпüå/µµµß}÷]MMMYYY8NÒ¡¬¬¬¬¬¬üjéÒ¥k×®Uÿì/6>sæÌO?ý4nÍÀOž<©oQÜqœÔÔÔp8|Ýu×µk×Îþí„••••Õù×èÑ£+**nºé¦¸Z£FŠ¿ð ………ê¶ßüæ7Û¶mkß¾½ŸxìÓç°²²²²² ¤mÛ¶Mœ8Qýã÷-[¶ÄÆSRR´½äļð qPÜÊÊÊÊʪe©cÇŽÚU(®*55U‹[Bq++++++++++++«–'ípápXý£@!Äå—_®ýÏŒŒ íú+¯¼R»)ʃ„Ö£:Ѿ¨N$”Å322ÒÓÓÕ8ªÕ‰Äõ!@ýÈÖú()Lõ—«¶mÛ^uÕUêÏ PÜÔ¼qïšOî< 0¨Âm~Ô_”ÕϪçBû×9p˜õäAûšš(±páÂ/¾øâĉ‡Šý½Ð[n¹eË–-uuuuuu6lèÛ·¯Ü¬ÿþ}ôÑéÓ§ëêê¶lÙ2hÐ ¿ñÆ7nÜXSSsæÌ™­[·Þpà 2>bĈ;vÔÕÕUUU-Z´È+N›gÚ´iUUU'~(ù{:h_T'ÚÕyß}÷ÅnýÉ'ŸÈßkEùQ¼wïÞüñéÓ§O:µjÕª.]ºçEuôGþ 9A¾¡<,bõßÿýßÕÕÕ ×³ú‹|~øá‡‘ÿBˆçž{®²²²¾¾¾ººzÚ´iÞ´qSóƽw(?šOî<£y@õ P~b´y´õ÷ˆëÏ…—jÛ¶íâyq7‹å0qCQMŠûšš(!„ÈËËûÕ¯~õá‡>|8v ·nÝZ^^þÿðƒÞ¿ÿêÕ«å lذ¡¼¼üÚk¯íÕ«×öíÛ׬Y#ã»ví’UöéÓgûöíëÖ­KMMmß¾ý_|ñÁtíÚUB€ó›ßÈrµy:tèpCŒ~ûÛßF"ù‡üh_mľÚ:…3gά¨¨˜8qâý÷ßÿý÷çääH»‘(þñÇÿýï¿æškn¸á†Ý»w/[¶Œð ÕiʇqäšäÊÃòÁÛå®»î:sæŒëºòz˜ê/ò™ðÿ‘G©ªªz衇ڵkwË-·xï2â¦æuïˆüh>¹óŒæÕƒüÑæ'ú‹òhë'úÈõçBKMš4éàÁƒ­ZµB7‹ë0‘ÅÑ„ 8Ú×ÔD•ã8))) .ŒèS§Nýû¿ÿ{jjªã8óæÍûꫯÒÒÒÚ¶m»ÿþI“&ɸܹs#‘HZZZffæ|0zôhùû¥Ï=÷Ü7ß|“–––ŸŸßÐÐ0dÈÇqÇY¼xñž={RSSQYÔ!CŽ?þ‹_ü"%%…X¯­í‹êBÌ›7¯¼¼<--Í+€ðÅ{õêU__ß}÷ÉüO=õÔ‰'ßP¦|àÆ Мh}Cyø „hݺõŽ;>ùä“h4*¯“Áþj}&â»wï^²d‰|”ÄæÑÆMÍ÷Þ¡üh>¹óŒæ¨GëÊOÌòÍ9ê#ËŸ =îÝÖ5kÖÌ›7Ïû Þ¬£<Ú8šbrо¦&JÈ÷u›$~¨C‡]{íµBˆ´´´>}ú:tÈuÝS§Nýìg?s]7 !ºwïþÕW_¹®{ôèÑQ£Fyï‹Öµk×H$âºn(rgïÞ½2~äÈ‘:8Žƒòˆ˜wúž3gÎÊ•+ßzë­h4J¬×Ö‰öEu !Âáð±cÇ&Mš …Ö®]û׿þ•ðÅ{õêå8Î_|!-=tèP›6mz÷î½}ûvmý¨NS>pã„?hN´¾¡<¨~Â!ÄÓO?žž>wîÜÁƒˈÁþj}Fñôôôììì… 6¬Gååå6lB ¸©yãÞ;”Ÿ˜Oî}ºç‰z³8¬ÍƒâhBˆIÖîkj¢dUñï&«¢¢¢’’’;v¤¤¤466Þ{ï½r€ûl8îܹsaaa4•oUzÛm·-]ºÔuÝŸþô§ÞWå(Taaá5×\SPPà-CëµuÒûªu !B¡Ð 7܇ÓÓÓ§OŸþôÓO¿øâ‹Ñhù ·nÝZáDšþãÿÕOÔićqäò åáúлw¢'žx¢¦¦Æ»xû‹|ÖÆC¡P«V­ å5ëÙ³çK/½4cÆ '|àÎëÞ¡üÄ|rçI[òåGý%|F¾¡þ²ü¹Ðãò?'NœX^^¾uëV×Þ¬kóqâÉ k÷55QRÔ_ þÓ?ýÓe—]&?W ‡ÃwÜq‡÷ñSѧOŸ¹sç–––¾þúëÞ!«ªª$J0--M®ï½÷Ö¯_ÿüóϿ𠯿þú/~ñ‹Ø$(âÞ{ï]»v­Ê¾P×kë¤÷UëBìØ±cÖ¬Y×^{mÏž=׬YóØcÉo hâêOèO3}V¿Ö$äÇ¿sæÌÙ²eËþð‡Øñ0Ø_Úgm|óæÍƒ 8pàüùó§NêÁ«QÜȼ¡¾;¯ª`ó¬ê»êÊ@÷Wë3]¿ÚG®?rrr¼/ˆ¸YR,‡Q"?šmœè¬©‰ú^%%%±ßë2dH]]äȧ¤¤LŸ>ýĉYYYò_Ãáð¶mÛ6nÜØ®]»Ø$òÇ)))³gÏ>uê”ü=ïvíÚýú׿.++{å•WæÎ[UUåí‚òdffž8qâÑGMu=Q'±¯¶N‘ &NœØØØØ³gÏ¡C‡jó£}ÇŽÛÐÐpóÍ7K—ÇßÐÐ0`ÀùŸÚóu6ßnœðG;'È7y^”Ç¿ùùùgΜy饗üñ 466Ι3çöÛowÇH¦Ÿäi}VãgΜyøá‡½ßmhh˜0aB(ÒÆ XóFøÆÊæíKϳv´õ ߯‡òkû‹òоiûËòçB;Ž“——wüøqï/ÐÍB“ŒFyÆn.ñdPãèIej¢ÎƒêÖ­[jjêŽ;$iÿþýmÚ´¹òÊ+eöÅ‹·mÛ¶  à»ï¾“ëûöí[VV6xð`×u£Ñè‘#GZ·ný“ŸüDñÝwß=ýôÓ¹¹¹S¦LéСÑ#G¼OÔ•P×uj÷%ê\´hQ^^ž<`›6m\×­®®îÚµ«6?Úwß¾}BˆììlY^§NΜ9³gÏyíy šï7Þ¯_?ä’Ö7Âg–YYY[¶lѾô<«Bõ öîÝ‹òkû‹òÐÏ+mYþ :/”¸ëº«W¯þöÛoå?¡›uüøq–ÃÙÙÙÚ<(Žž0(ŽöEur'*~‚ã>³ëÖ­Ûwß}·|ùòŒŒŒp8üÁ9rD~Sõå—_®¬¬¼ãŽ;²²²ºtéÒ¥K—Ö­[gddTTT¬Zµ*33333ó£>Ú»w¯üœë®». !&L˜pòäÉ9sæÈáÚ}úÄ~õª]OÔ©Ý—¨sݺuëÖ­ëÔ©Ó•W^¹yóæ­[·¦¦¦¢ü(î8Ζ-[>ú裎;vëÖí³Ï>{çwd~t^ä¸qÂíœ ßˆ<,RRRR›4aÂù{_Ä\qûKøLøôèÑáÇ_vÙeï¼óΗ_~yÅW ¸©y pï´ùÑ|˜gí<Ð}Wý!òÏ 5áê#ËŸ =Þ±cǪªª1cÆx7‹å0ʃâhBPœ¾F&êŠhÇqî½÷ÞÔÔÔÔÔÔìß¿?77WšxòäI×uê›4vìXÇqrrr>ÿüóÓ§O×ÔÔìÙ³gäÈ‘r}IIÉéÓ§«ªªNž£xFFÆÊ•+kkkO:uàÀ7†âFæ-À½CçÕÎg€yFó€êAþ ü¨¿Ú|Øû…`T?ªÓ”Áâª? çD뛚'€ÞF©©©Æû‹|&âòÕÖ­[ïÞ½;ö_µqSóƽwt~u>¹óLσv~ÔüÄ<yÔúQƒùsÆËÊʶlÙ2{ölío€Çݬ£<Ú8=±Ä$«ûšš¨Ä’“›¿ž•$€¸ûëMÅTܼõDž¤žËÔ¾Dÿ‹‰õ¦ê!öMöü$Õÿ¾ù/Æl=Fò¨“[OKŽËïUjW"]7íˬÔÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊêbW²ùs¦ò4,O‘ËáãÖÏå,rëDâòüæÉqyu\JYRç*·Ïˆ(O€¾ ±òs¹t¦æ§Ê` ¬.BqùsžšI™âò핊ËSärø¸õ#nœ)Þ!ÊÃåù¡ú¹¼:­?N»/±žÛ.·Ï”(—7Éíê»¶~b_n¬çƒŸóÚ¿¿|Ieeå®]»Š‹‹Y¿ú‘ðjXY±ùsRͧLqùvˆJÅå)r9|Üú7ÎïP›‡Ëó#êçòê´þ8í¾Äzn_¸Ü>S>hóàM²úEô][?Ú7@¬çCÂóÒŠD"K–,2dÈ­·Þ:sæÌššš3føüX˜Dge€?' Q¦P~.å1ÂáãÖOððQ.ÏÕÏåÕÑþH©œ?m¿´ë¹} Àí3âÊÃåMrû…òÓAußu²žôy=ÝyçÚwCŽD"óæÍ“ž§¤¤lذáÝwßõÆ[}Ul„¾VVBˆ´ü9aˆ2…òs¹€(·~‚h„wˆòpy~¨~.¯ŽöGæT9Ú~i×sû€ÛgÄ”‡Ë›äö å§9‚ê¾êd=èó !Ú·o …FŽyùå—¯_¿¾®®îرcꄸ®Û©S§¬¬¬•+Wº®«¾Jž%6Bƒè¬¬„ärùs¦(SH\N’)·~Ä3Â;Dy¸ÏO[¿ÃäÕÑþ ΟÖ7íú}árûŒø@œ‹Å›äö åGõ}ár1µõÐõy$ ùäÎ —ÓÉOn\ªmÛ¶7n\¬ >@%òhãÜ 'ö5Ò)!Hœþ™â‘G©ªªz衇ڵkwË-·ÄAÈüs QwÍqT'ª‡ËeäòðPå×ò ö‘ÅS$ò ~¡¸)Ÿ÷ŵóÀå;à)¢órçÍ3ËO.ðñQ¿X\ÏÜD´/š+Ös†ðËédÍg€¸Ô¤I“<ûþ@EyPœ;áh_S:+§I~xcøg»wï^²d‰´>î—Îýs Q.wX¯­ù€ÖsyxÄyQ=ˆkh¤\ž"{C}Gq#>þhãh‚ñUÿ¹DîœÐóïßO.X¯å5ýÒÖ‰Ösë$öE}d=gP=8¬ù䯽֝Y³fÞ¼yÞÿ ÎyXOxÂ1´¯‘NÉ:Ó“7ÆåŸ}ñÅÙÙÙ .6lX=ÊËË7lØàeóÏ5LOO׿ár×èõþ9p¨~.àäió Ì54ÒG.OåAýBqS>þhãhhˆÞ—ƒÈzžýûÉåëµ¼F¢_Ú:ÑznľZ¸Ï4'8¬ù”ïçà?.ç¡W¯^×_ýôéÓ8€:KÜm<À“P»¯©Nɪ¾ÿLÁ'oŒË? ‡Ã­Zµ*,,”eõìÙó¥—^š1cF4eq C¡6—»F¬gqàˆõ\Š£üˆkh¤Dý,"êŠoöÁõù££yÌwôÏSDbÍIÂù÷é'—GH¬'¸•Ú~>¨ëpѾZ¸Ïú±8¬ùäÆåNœ8±¼¼|ëÖ­2Îr€ §¢aŠ\«Ý×`§„Ç#¾ycÁøg›7o4hÐÀçÏŸ?uêÔ=z8Ž€k¨æI¸µ)Žw=‹‡§£üˆkÈ:oÂ>úä)Òy´}'âF|Fþоù÷'oËA4ÈÅT¥­ŸË#$ÖÓ¼Fí½ ·>07QÝ—è£ÿç ]‹ÓÉšÏ`ÊÉÉñ¾LÇAEyL‘k‰‰2Õ©³Fgff<øã?N8š®ëæää¼öÚkÝ»w¯®®^²dÉ™3g„òã$?'nß¾½±±±±±qÙ²e?úÑ®»îºüüü‘#G~þùç<òˆ|ÛèÜÜÜÛn»MwðàÁY³f½üòË<ð@FFFuuµ6O}}½v_t.TçÝwßMÔ£Š®?ÿñüꫯ$Æ{•z.'òO:uΜ9õõõµµµo½õV(’ß1ÒG)mýÚ}…Ú<¨_(Žê à3òGGó€ü¡ëAþ£¾#ùŸT?×OÔG)õ\ÈŸ!C†L™2å©§žš2eÊäÉ“Ÿþù'Ÿ|²sçÎòUè^ ©ëé¹Eþ«y'Nœ`=gèzPµu²æ“Bäååµoßþµ×^“¹ Î¢<ãÇg=á‘ch_îGºSg?²¸qî•››;eÊ”:ÄñÏävìØ±ŠŠŠ«¯¾ZÆ%(õÛo¿õ¸e¹¹¹ò˜#FŒèß¿¿~ýÊÊÊìºn4õ¸q(Ú×Ü5´Õƒ>Òë%¯   –‡§=:ovv6Ê¿hÑ¢¼¼<¹Q,ÐHå?©õ !оÚ<¨_(ŽŠäúLÔ©ïÛ·Íö\t=Zž¢¶¿è¼Ü9!êçúIÌÁ/Œ[ËÑŒF£¯‘è!íznÚ<ȇãÇsŸ3Úzè¾këdÍ'ª‡¨³  `õêÕÞ]ã:€:‹žT(Ž&ÅѾ¦:õƒcqã¸ü³—_~ùèѣÇ¿ì²ËÞyç/¿üòŠ+®Har Qb_í¹ÐzTòXÏâá¡8‘ñôÕOìKäQûEÄøLÔ©ó€ï蟧ˆÎËzþY~ry„Úõ¯õ Í'ZÏ­S›‡ž+ÖsF[ON'k>¹ñŽ;VUU3ÆÛ‘ëê,ÊÃ}£8=QÍ‹7ÆåŸedd¬\¹²¶¶öÔ©S¸ë®»âÓ>¹†(—»F¬×Öƒ|@ë¹<<š“§æG(—/€s©­ßÏy íß¿_¾¤²²r×®]ÅÅŬ_ýHÒ³²‚(.ŽK™Bù— Q©P´ÅMÕÏåäqëärQ¿PýˆgÆòËG ÀóCq.Ò”,î#q^V¿¸|P._ÛG4o ÏK+‰,Y²dÈ!·ÞzëÌ™3kjjf̘áÿc! Ò³²‚ü3Ñô×>yf(S(?âÉ!*ʃÖkã¦êÀÉcÕ‰òãç©õ<3–o¢éך|D´žÛ.Ò”(—ŸÇíW>¨vßu²žôy=ÝyçÚ÷ñD"óæÍ“ž§¤¤lذáÝwßõÆ[}U\„éYY !Ò¸¼4)#”)”ñä åAëµqSõàä±êDyN›¶_¨~‚oÇòM0ùˆh=·/\¤)P.?Û/.q:ÔÉz>ÐçB´oß> 9òòË/_¿~}]]ݱcÇÔ q]·S§NYYY+W®t]$,Pþ IDATW}•}ZVEôK­_¾ÒÍ7ß,׾7Rß„………•••YYYqæ ß´ëôEõŸÕÇ`>¨yˆ¾ ó²ú…òõk÷ P'ê#]?Ês÷ÝwWWW9räðáÃÕÕÕ“'OŽýz1‰:tè“O>ùÛßþVQQñé§Ÿfffj_•ŸŸ¯æ¡[feuvÔXœ3S”)$Äå¢9gªÐz"AœN·N.ËYäúIûãŸI¬ÐÒ”ªðóXý ÆU÷ ÌùS€×(„X¶lYNNNzzzFFÆ=÷ÜSRR÷X{÷î]¾|yiiéâÅ‹C¡Piiijjªúª¥K—ªy¶¬¬¬lS“†j?L^¢’ßyOII™={ö©S§bï<î3¾üüü3gμôÒK?þø‚ çÌ™sûí·ÇþCÍã?¿hz#>ùÿ'NœØØØØ³gÏ¡C‡ÖÕÕýò—¿”ï4}úô'NÄ~^—gÈ!Úõ(N×ɪ_‡·mÛ¶qãF  p.¢NmÇqÚµk÷ë_ÿº¬¬ì•W^™;wnUUUZZÝ/µþ±cǪ_I 0€öù“™™yâĉG}TýiÖ7´žÛ­ÿ¬>óA{.m_Ðy¹ýBùQýò?µ>³êDç¥ë'ò!V¬XñÆo¬ZµJ~‹ý§H$òÊ+¯¤¥¥Éö=º¾¾~„ Žã¨¯Š‹ÐW^êÁ|¬Iݺu³/5¥õë×ï™gž)..Þ´i“뺪¢¢Bûb%„HOOwgĈÇ?zôèìÙ³Õ<:t`åB,Z´hÕªUo¾ù¦ëº—kàÀ©MT*×u=*•÷¸8u‹¡XÅ®GñvíÚië P¿hâŸåååÅqòüŸ ÕùÕW_ió¸M´-Çq\×}ã7âøyqýúðõ¾y4¯uëÖ‰šWnn.Ë7鋨]ß·oßââbn_TÿQÔG®hE?/®/è¼Ü~¡ü¨~s+Yu"ÑõÓy$5·M›6Ñh´±±1î_åÏ}å—‰»wï–Ÿù9Ž£¾*.B\%¯ŒW_}5v#ûÄKN\^ZŠ!ÊÊ/—«¦Rió õ(n°~'['Ê#ñóÔú@óâú&³±øˆÚõúÂâAšò8‹ŸÇíÊê'úÂåüië¡ë'òxÒþS$Y¸pavvv—.] ´bÅŠêêêØ?T_åE¶ÌÊJ>/ÍSs(SD~-—ËIDÃRdÚõDSõ³8yêärQ¿PýZšWß“ˆÖsûÂåAšòåáòó¸ýâòAѾÁêôÿ|Hx^B‘H¤±±Qö´ººzÛ¶mùùù>ÿŽ0aˬ¬¾ÿÁž^Ú÷/ne åwñä ‹È·žŽ7¿~õ¡à““Ǫ“ÅÔö‹öM¥yq}L>"ZÏí í?wýû€ò}!üñß/”Õö V§ÿçCÂóŠë©ü6©ÿ$tˬ¬¾—ül7yy¸ùÏWSûž¯zL}ª‹ò$Û¢ž¤Î±>©yL‰¨ÓHž‹@ÉQ+++++++++++++++++++++« U,—ÃÇÁÃÓÖÉåÏqós!gmÛ¶•¿¯ás½)Ž)Q?k~PÍòÁàBqylR*/ qàÐzmœà–!¨ª“ËŸãæ§!gêyy䑪ªª‡z¨]»v·Ür‹cãò×Å;$|FyPýÜùAqíü>˜šÔ/”ù€ò }YóÀ­“ðÍ—‘ËGäÎy²y¨(ΚÛÏ+SSîý’š4iÒÁƒcßOÀÿ“œKTÕ®'C7‚E%òÓ¡Ø<6¡ã>íz"î4)Ž[¦…Š¡:pYùÑzâ\»wï^²d‰ÁØßäæò×0ÇQë3ʃêgÍŠ£ù!|05Ú~}G>hóû²æ['òÍ —Q»ž;·4Q{OY>sãܹå>¯Ð¹¸ÓuJ­Y³fÞ¼yÞ÷0XOrî­GŽioD0¨šŸþ•&ø<6×uUÞÁá€O†âˆ[¦…Šur9ˆÜüäL=WzzzvvöÂ… ‡ Ö£Gòòò 6Èâò×0ÇQë³6Q?k~ä5kýÔÎჩyÐö åùâ‹/Ú<ˆƒÈnápXë›A.£v=wni¢öž²|æÆÌ-ëy…ÎÅ嘫³W¯^×_ýôéÓ‰É7HTE뵎¡Œ0ªæ§?BAL³|{LïÝ%ä ~üã !z÷î]TTôÄOÔÔÔĶÓ{ŸÜ±cÇþüç?衇äËÑz—*,,¼æšk ¼´EEE%%%;vìoNqï½÷F£Q¢ÎÆÆÆþýû?ûì³áp¸sçÎ………ê›­ÄŠ›_»+ µjÕª°°PhÏž=_zé¥3fHŽè 7܇ÓÓÓ§OŸþôÓO¿øâ‹ûöís]÷¶Ûn[ºt©ëº?ýéO½ïfh×£<ÑhÕ‰|Öæ!êgÍÝ/u~L̓¶_(O8F>÷BÝ—;(?ª“ðu/?µâÎ-±‰å37`n¥|>¯ˆs¡ç§Ö·`uNœ8±¼¼|ëÖ­2Î}’sŸ0h½Ö1âF zèIV;‚òGÈÍS9ph=—[Æå &Îï8×æÍ› 4pàÀùóçO:µGŽãpù‚ˆkŒã¨úŒò úép7?„¦æ!¯QëCN§ÿyàÖIóp¹ûrçÉ Õ FžW‚Ã1  œœï VÁ’sŸ0tåZ2%ñ„áFùR›ç{ùä±Ñ¼1•‡Ö?žÅ-CP1𻿸æÏqó#.:o(:sæÌÃ?,Otã7644H š¬P–‘/(0P§ùyZ>œ6OFFªŸ5?t¿´A­¦æõkܸqÚ<ÈzžÕ} ?µþsë$æ‡u/h?Õõ¨_ÄÜuªùÍòPÕx°¹õÿ¼Bç’òÏ1 Pg^^Þñãǽ¿4à>ÉQ%Äu\ëý„áFùåŸYx<3ùŸÏÌãåææÊq1¢ÿþ²\É+((ð8ph}vv6‘Gå–ÅBŢѨÛ·oŸ¶Î>}ú”•• yl)˜7¦åÀ¡õD¡ã–!¨ª“ËŸãæGëiŽ=:|øðË.»ìwÞùòË/¯¸â Áä ëpµ|8”ÕÏšGóƒ|05¨_tª(ÍMô?êÔúfŠËˆÖ˜[‚ƒ¨æçú̘[ÖóŠðÅ1åÖÙ±cǪªª1cÆxrŸäž0¨ãèɃnDÂ(ʯ=×ä“Çû’8ÞâÀ¡õD\å–9*†êdñç¸ù‰õè\+W®¬­­=uêÔîºë.çòÑúG-åGõsçÅÑüh}0>j¿PÚ5Ú—;Ü:Ñüá2ë¹sKs4“ÇCEqîÜ æó ‹Å1åÖ9cÆŒ;wjmT4BT¥'YûäA7"aT›Ÿøõ}cäwZýðØb¤ÆðÆT—U°\ªÂWÓÆe1Z.âá!n\"+?9SÏ%?jݺõîÝ»óÑú„qµNÚç¸<¨~îü 8šŸ„>™µ_Äü> <Ú}YóÀ­“ö­ù\F´ž;·h=ÊÏõ9XÜÿÜ æó Í?}¯}ÖYVV¶eË–Ù³gksÕ瓜û„!&Yë˜7‚®Ç? 5áG(JqŸžwÉÏA´qÖú˜ßȾܸ©:‰<¬x€<Éî—©<Éî7n$€zXýâÊ”ÏçÖÈÑšY§üîzóË +Iê“ÇÔz+++++++++++++++++++++¸<9-*ÿL+.gN0¹eh=AábùcŠž…Ö£ü¦8y„ŒpÔˆzXóÆõ_â&š·Nt¿¸<üðà ý!´ÿ~ù’ÊÊÊ]»vûÿ?­±²‚ârÈ´(.ÿÌ wP[?‘ŸËãúâg LùBëQ~-Í‹ðÛ®oRþy“\Ž ×#ÜD¢~íy‰þ²êD÷+ÏQßXÜ>äCBhE"‘%K– 2äÖ[o9sfMMÍŒ3|~,læÖV—º‡ Q ‚ñϤšÃDõùµë ZËŸô,-µ ­'ê$xªúÂõMpx“ÜyãúÏícþ:¯¶¿Ü:Ñý ÀóÓÎ —ÛGÏ òÇÓwÞ©}íH$2oÞ<éIJJʆ Þ}÷]ïó*õUq?[[Y© Â#ÔR WŒK|Μ¶~"¿v=A«âúÃ¥gi©]h=ª“æª>è ×7ÁáMrçë?·øsè¼Úþrç Ý/.ÏÍ —ÛGÏ òGѾ}ûP(4räÈË/¿|ýúõuuuÇŽ?”,»S§NYYY+W®t]W}•äUÅå¡·¶²B Â#ÔR óϚϤ¥æG"hU\´yˆÚEpÔÔü yZ:«/\ßX¼Iî¼ðŸÕÇü9t^¢¿þëD÷‹Ëó£©o,žòŽß~ûí%%%'OžŒF£»vízòÉ',X›p̘1 ïòõ×_Ïš5+ª¯úî»ï,X Íãt­¬¤~ß@¥@柙âx!!*RZ•où§gÔ.Â7m~‚æ¥õ!ÍËÿy¹¼IB¸q¦úˆ¤ÖÎKSÙ|Ö‰îWžŸÀs€Û‡úˆâË–-ËÉÉIOOÏÈȸçž{JJJâ>üïÝ»wùò奥¥‹/…B¥¥¥©©©ê«–.]Šò£UVV¶©IC‡m΃Åêâ‹Cæè(Pøg¦¸ƒjý(?:¯¢UqýaѳdD.ˆ£v!ßÔü4Í ùà¿/\ßhÚ™šŸ;oÁü÷ßG.Ž8/Ñ_ÿu |¿Xþøãêw/åFR»wïv§]»vŽã¨¯Òæ¡·~õÕW_lÒÁƒ“ñ­« [>9d*ÿ¬ùÜAT?ÊO¬§iUþ9m\z––ÚEsì´u¼@Õ‡4/–o)LÞ$wÞ¸þsûHÏ›Z?q^‚ïè¿N¹},žš.·žb~µ~û !Ö¬Y3oÞ<ú ÀuŒÛYî"Çоh=O‘\´… Ê?Aõ¸hˆÓ&_)¹k‹-Šý«U·I±00É?Û¶mÛ°aÃŠŠŠ† "ÇrÔ\×ã¨iÿŠV›ŸXϪÅQè\(ÀO-—ÑÔ¹ˆü,¤ã8(Çá›9sæ°aÃÌö]ròÞ}÷]ù’®‰8…¨/„D=j ÕÉõ;oÈGÏäO€9gÝßýà^ PµëQ¹>£:ƒÍ§ÖObß^½z]ýõ …us ÇXEù‰ DEû¢õDü;vlMMü6«|›¨¸wß—B{÷î]YYùÀĽu–¢°°°²²2++KþçUW]ÕÐÐðÙgŸ•——oÛ¶­¶¶öÙgŸMII5jTCCC~~¾|íüùóOŸ>÷†RÚouÆå'Ö³êDqT':ŠðsøðáûöíÛµkמ={vîÜû³Û柋ȯõ£¯Ú_b½ÚÇ>kë p^ä'QÿóÏ?¿aÃï°¬››ðFø2s'ûÄCë‰(×gâþ˜OÕO¢þœœœØ/›X77a³üw–;Ü'ZOçBÇEC<6.gŽàŸ±8jRþ9yÜ:‰üÚ:ѹB¡6>nÜ8–ŸC‡ÕrM q¹"òçøñã¬9wÇ‘{Þ÷‚8¯V\>(Ëgtß‘Ÿô|jýDõ¬^½Úc”™¹Ž±:KT(LMÑzúÉ)à¢9€Ç–ÂäÌ ÌÉãrÔP~íúu¢8ªKçú‰¸Œ¦Î…ò£8ª­˜Ãg¤ïÁ8…j_ˆú‰z´q.ÓGˆ#ÿY|DÂÖœÓóéÿ¼î:/Ú—ËeùLÔ`>µ~j÷íØ±cUUÕ˜1c>8Æí,k¹O<´žÎ#æ¢Ñü?á›3‡øg\ŽÊO¬gÕ‰â¨Nt.gùé`.£‘s¡üľÚú‰õˆÃgªï\N¡¶/ }öÿËã4ÅDqä?—ˆü 0ç¬û¬_Â7íËåƒr}Fu8¯ÖOí¾3fÌØ¹sgÜ߇;wî\XX(—õîÝ»¨¨è‰'ž¨©©‰}œiÏË]OÔƒòh}@yÂá°ÖyÿUߢÑ(×Ô#¾íÛ·ÏuÝÛn»méÒ¥®ëþô§?õÞ Q»žëCÿƒÍ¹*ÖyƒÕ©ö‘ðÝ;4Zнó*÷y£Ñ(=o·ß~{IIÉÉ“'£Ñè®]»ž|òÉ Ä>(ÆŒ3`ÀùÞ4_ýõ¬Y³¢Ñ¨úªï¾ûnÁ‚±‘Õ«WÓG°²B Â#”òÏ·Cë *—s¦å„Ñô).õ*©¼F$g.˜þi^Èíz‚·—˜ æÃb±©>²òà u²ø…Ľ#xZïPpî/íÿ²eËrrrÒÓÓ322î¹çž’’’¸T{÷î]¾|yiiéâÅ‹C¡Piiijjªúª¥K—jóGB”••mjÒСCí÷N­¤Î>@ÃáðÿøÇ¯¾újÚ´iòMáΜ9£®®««“ÿ'33sðàÁü±7ëC† ™2eÊSO=5eʔɓ'?ÿüóO>ùdçÎÑz!ÄÔ©SçÌ™S___[[ûÖ[o…B¡îÝ»WWWG£ÑíÛ·766666.[¶ìG?úÑu×]W__OÔsðàÁY³f½üòË<ð@FFF~~þÈ‘#?ÿüóGyD¾©knnîm·Ý&G_=/w=òçî»ï&ò¨> ø€åšÚ➗;'G={¶ÚÇŠŠ m~tïÚµk§‡ŠŠ í}'¸†ÚûŽæžùBùÑ·M›6òûùqËŸ_Ê/ïvïÞí8N»víÇQ_¡ õꫯÆnì[V§Xð?Àœ çR{^n\~!ºwD­ļ±î/=o±Ò~[2‰,\¸0;;»K—.ƒ Z±b…ü$/ö¾yˆ#XY%P¡¾Z/0•ŠË9Cœ0Oqô).õ*Ù¼F?ðëªÇ”o4oO]Ïõë°>úç\¢órëdñ ‰{‡ò ÏhN¸¼=?ŠD"²¶êêêmÛ¶åççûÿ;BâVV„ˆGHs°œfp³ä?¥r8gà„Ån”CŸâR¯’Ík$ò>øç¥që1å[ ÉÛS×óÁ¿ÿÁú¨¥¯±ÎË­õ‘Ψrj¢ZŸÿþjÏåGqµÉo“²¾‰Ž`eÕ,q?¥r‡õ´žˆÙ×”LmÊ=7~¾`~Pœ5\ƒ>ró™S÷ÑÔús X’•••••••••••••••••••••U‹––»Æå¨€±ö%¸t¦8|¬zLñððP,Ž·_ˆcÀçÏ÷ùÃå) f_¸u¢}MõËÔ½Nö¼>³ü1È7Õîkê¹á_\’+ªû$áæ1õ$á’S!wË#Lžk_)-lLË] ÀÛãÖÃå/¢}¹<<çr쟈3‡8vˆ‡ÇõíkŠûˆÎ‹üáòY}1X'Ú—Û/4À½Nö¼¡ùçúcŠoŠö5ÈmB´mÛöÀãÆ{øá‡¹ÄStRä0÷IÂÍÃu†ÛYÔÁ³BÜ5.Ë3cí+0lLË] ÀÛãÖÃå/¢}¹<<çr츼CıC<<®Ïh_SÜGíy‘?xЬ¾˜ª“Ø—Û/4À½Nö¼!þ"×S|S´¯)n«Ô¤I“<تU«ÄStRm…ž$Ü<\g¸E<+GÇ] À#äò̸ûjó>´¯À|>V=\þ¢vß<(ªÕ“ìy£}öï—ëIÔ‰æÜ·UªW¯^×_ýôéÓ‰ H®Ú º*­X;¢_ïPnÇ#D>°|€ogŠûˆÎ‹üáò¹}1U'½¯ü?>ûÅâƒrïõ9˜7Úgÿþ˜â›"á¶Ê—Lœ8±¼¼|ëÖ­±õø$ž'ÕVàIÂÊÀng‰›ë÷MüTi¹z,žY¡üwËÛó/.ÑÔ¾„X;Áç ÇùÀ=/½¯ªÜGõ¼ï¿ÿ¾Ö³ýĉYYYÜ}ÇGø¬Öƒ|“ÒúЮ]»_ÿú×eee¯¼òÊܹs«ªªÒÒÒ?e™pâĉ={ö”õ„ÃámÛ¶mܸQ2n„C† ÑúÀõY4½¡eܾÈ:?k>µþ ßœ‹5Ÿê$öõß/ä¿©{ìy£}öïÊC÷åQ÷¥ë×ú‰üÉËË;~üxÜ_¨è'¹zR¢BÖ“„xBjóp†ÕYºƒð3n£&ÿ3!0ÏŒµ/Êß·oß²²²ÁƒËo {Ü5´¯ÇKËÍÍ•?°1bDÿþýÑ'¨ž®]»¦6qà¢Ñ¨Ç“yüï»oß>Âgÿ"|»ÜÜÜ)S¦tèÐArìˆ~-Z´(//OÄãÌÉz$Ç®  ÀãØÅòðb}ð8ˆ>}Fû"è>²æSëŠsç‡;Ÿê$ä¿_Žãhý7u¯“=oýúõ#|öïê=Ïj$Âä'ò§  `õêÕqÀE‚x*ÿ3–äª=)Q!ëIÂÍÀVgýÞܸ«“G(ø<3î¾ÚüwM»oJ"^šÏzº1ù‹h_Úgµçrìˆ~œH•c‡|àúŒöEþÐùYó‰üañôÅTÈOV¿è¾7ÿ^'{ÞhŸýûcŠoŠöå>7?;v¬ªª3fLœóþ‰§è¤D…¬' 7OgXMxsa:P00‚{ç_”Ÿàð±x{¬z>팇§ÆY;ÂOÄ™C;–Ïh_SÜGt^ä—§Èí‹©:ѾÜ~qù ¨~TO²çæqú÷Ç,ßTýÄÚ·uÆŒ;wîT ,â©ö¤D…¬' 7Oà'ªÿ΢ !¾ÿ7ùÙn,wÍaò“g`_m~søˆ}à¥ù¯ÇaòѾÄyµõÐuúçØÑ~ªœ9õÖÅòü´>ðq‘?Úü¬ùDþ¾8k>Yu¢}¹ýBþ£zˆúµõ <¦æð9€?¦ø¦Äœû|nhý)++Û²eËìÙ³µcà“xŠNŠ* ü$ñ™'ØÕgQ}IýR4ázîKXû¢ü¦ö5U©üò ¸ëY%ôU²ó'{_îúsàCRïW²ç-ÙušR3Ï+¿[ËÝ‘UI²Ÿ$É~¢ZYYYYYYYYYYYYYYYYYYYYùÁ cqãš”.—gÆ­‡Kí2ÅMdÓ³ ùIœ‹u^S¼F®o—N[—ogª~îýâò)Ï=ßÎÊêb“–&¥¥=t(DŸbq¹b«R©QÚ:Ñzn=\j—n¢Àô,Ä!ãú‰ò z¸ç5Èkdù†Î‹êáòí ΧÿûEÔoŠoGÔŸPû÷ï—©*++wíÚU\\Ìú• ­geu>…hRZÚA‡Bœ0—ËûW•…êDë¹õp©]F¸‰Ó³‡Œë'ʃêáž×¯‘ë:/ª‡Ë·35Ÿ¬ûEÔoŠo‡ê÷£H$²dÉ’!C†Üzë­3gά©©™1c†ÿ…4ZÏÊê|Šà¥žTŠ Iióp9v¨N´žU—ÚeŠ›Hг‡Œë§6ª‡{^ƒ¼F.oR›Õ€Ïgj>Y÷+ŸÒ3î™pçwjß×;‰Ì›7Oî•’’²aÆwß}×ûü@}U\„FëYY/¥Ñ¼1©¸×x‘8:A“Òæaqìˆ:µë¹õp©]¦¸‰= qȸ~jó zPWþõkóy¨¿N›Ÿè#—Ïgd>¹÷+ŸÒÓSûöíC¡ÐÈ‘#/¿üòõë××ÕÕ;v,n,£S§NYYY+W®t]W}•ä+Åå!ÐzVVçSW_}uCCÃgŸ}V^^¾mÛ¶ÚÚÚgŸ}6…|C©ÂÂÂÊÊJïÝÁ…Çß·oß®]»öìÙ³sçθŸ=¨yÐúÞ½{WVV>ðÀÞá\uÕU¨Nízn=òMwâÞ£=öÇxï½÷ÞÖ­[+**Få8ZOû©æ‰µtìØ±555ÞrÖ®][WW·}ûöƒÖÖÖÆáiüûIäAõø?/áíÜüýEujóÓ}ÔúŒê42Ÿô¹¸sÈê»Ögâ¾HÝ}÷ÝÕÕÕGŽ9|øpuuõäÉ“c«D"‡úä“Oþö·¿UTT|úé§™™™ÚWåçç«yè‘¶²:_JÌCRéP4MJU޶N´ž[!.ç,7Q¥gqù|8s¨ž\7ÿõH±x–þ©i «òÏ·35ŸD܈Ìr1—-[–“““žžž‘‘qÏ=÷”””Ľ‰×Þ½{—/_^ZZºxñâP(TZZšššª¾jéÒ¥jž„#]VV¶©IC‡µß;µ:G¢yc|E¨Ò¡hš”š‡Ë± …BÚ:ǯ]OóÕz¸Ô.³ÜD-ÏL®”ÿ?ŽÓæßO:ªÇÿyMñ¹¾¡óÒ}ôÏ·35Ÿ(ŽúH×Ïê»Öç„}ÕùÌ3Ϩy***D=+///–g¶hÑ¢U«V½ùæ›®ëÆqÚüûùÕW_ió z:tè £ó666jã¹¹¹„ÿþ9|¨Nt^T§÷‹õå15ŸÜû…æ0@ßµ>{T6µ~oÍ´iÓÚ´iFec%Î*¿Lܽ{·ã8íÚµsG}•I8Ò¯¾újìFèÔVVæEðÆøŠP¥CÑ4)5ZŸBr¿Ô:Ñzn=“Ú…Ö£: ^â™!NËO”ÕÃ=/ŠÓþûçðq©it_üóíLÍ'÷~õsû®õ™¨?NÚ¯Æ"‘ÈÂ… ³³³ÿöÞ=>ªâþÿŸ³—dws¿'ä¶á›`E-VEÅR´ÁRýÖKm­zQZ}hõ£V­ÖŠH[Q(¢ÒÊ£X+U˯(" B H ÙMBîÙì%»{æ÷ÇÀqÙ=3Ù9»É™÷óáÃÇ2™yÍ{fÎì9gÎyϘ1cóæÍäGUèVXF9ì! zÂðC”…0ÒJÈ—ŽË—‹¶S€­3,?¯ÄéÚÅÈÏë›HsÏ¢ù´ñÆ“VMo{ãå×È7Fù4\þvqŸ¼ó‹ËŸRCœiú£ÁétƒAÞžž,]º4ú /ì! zqzÒüÆÅWŒázEó¥‹,‡©¹F1tFæ×¦‡×µ+2?M'­œ}×"ýá¸âI+‡Ý®èÛËNçr㊻½‘z4ûóÅ>>¹æc\qõ;#Î4ýCr™4ú¯³‡4èù<ô嘟« ùuioÓiõré¡1Ø:ãUï”}f åëÈ0’ ç>4?3†Ožª/Zaaa\ôðúÆÑ§ Z{y}ïh~{¼í¢A«—Ñ_ªýKÓÃ[>­½4hñäõSDü~~\ùyÓõÒOƒ×7Qƒ&/\úyý2iÐÚ¥ÁoRÞþŠKœ¹Jæuå=¢ÆÑA“w„¨×Kó]£ù·Ñ|Ñ,XPQQáóùº»»_ýu2ì¾h s²Hÿ6 >v´ò¹üÛî½÷^Z½ªíeÄgšßo»¢ôe¤é§õ/Moù´öÒÚE‹'¯Ÿ"¯#o~Þt½ôsÍ;F9ªýÂëƒÈÈχªãœ×/“w¼Ñ⣚GßV^¿RBRRR]]Ý 7ÜÀˆ$ïÌâá\Gà[Ù㼎¹Œ#-Btß5š›ª/Zfff}}ýG}d·Û¿ÿýï·µµýá0 _4š9™ª›;Zù\þm´tZ{q£Å™æ·ÇÛ.B”¾Œ ý4ß;šÞòií¥µ‹O^?E^GÞü¼ézéçšwŒrTû…ב‘ŸV/mœóúeòŽ7.¿É8ú¶òú•î¸ãŽãÇ“W+ð–ÌëÊë„Ê›ŸÖ㼎¹´vFÕÏŒáß&©ù¢-]º”¼¥‚ì^»vmuu5©F:C˜/ÍœŒáߦZ-?­|^ÿ6ÕtZ{y}ï~{¼íB<¾ŒìþŠì_†®òíUm-ž¼~ŠŒvÅËG“+]Gýæ]d9ìãƒê<¢OƼSÕ¯ZŽ¿L®ñƈïñŠ«¿4ø•¶mÛ¶jÕ*F$yg–†‘Ï{æ=²ÑFˆjäíB™Åόᓧꋖ““#IRMM Iw8ùùùD.ÍMÕœŒíßY#?ÍüŒ×¿M5Ö^FÜTë¥ùíihâñed÷Wdÿ2ôp•ÏðTm-ž¼~Š´v±ÇW~®tõk˜w‘å°$O”>ˆŒy§ª_µ ~™\ãM›ß¤j»¸úKƒ_)‰ÆìÙ³xà %ó:€2ÒyÀ¼G6ÚQ<£]§aû™¡ÿ6BØ«ž®ºêª@ °téR’gõêÕn·;t•ŽôES5'п-z;šù¯›jú€íŒ£ÞH¿= íâòePXÿ2ôh(_Õ_p@³ºÈq½Ÿ"­]އèóó¦ë¥_Û¼£ù’ªö â÷A¤Í»ÈzUËÑà—É5Þ4ûMÆîÛJ‹3CÿsÏ=·sçΰB¸z0zPF:ï˜÷ÈÆn—ꈢÍ,ÈÏ,Ò¿M•­[·~þùçÏ=÷ÜóÏ?¿aÆüàa«i¤/ÜŒáß½­| >y‘é¶7zß;D÷ÿãj—/ã€úUQÕ£¡|Õö²ÍêTÇa\üãå£É›®—~móŽíøÀëƒH›w‘°Ë‰ ãMƒßdì¾­4= ý×]w]è‰8oɈÓ”× •7¿¶WQÔ™ÅöSõÉ#D®ÃéééO=õÔ–-[^}õÕ—^z©»»[ùk¤/¢˜“±}é¸|ìTËçõÉc¤3Ú½ïù«¢VñÛãmÍgŽÑ^†þÈþ¥éÑV~d{iãô;mª–ÃHlW¼|4yÓõÒO‹³6_RZ¿ðú Òæ]d½´rn¸á.¿LÚ<¢7Z|Ø~“±û¶2âLÓ¿dÉ’öööÈ'¸z0rjá¼G`®#{dÒFmfÊBüÌdYVüÌH5Ä¿mÙ²e¡>y4ººº~øáÅ‹ÿìg?ËÏÏw8Ê鋆zýõ×—,YB*RÌÉØþmÑûØÑÊ·ÛíŒöªê¤¥3Ú7Zœ§M›¶eË–Y³f‘‹õŠßo»Ÿ¹Å‹“-* ,˜>}:£ú#¡éá-êÔ©ªí¥µ ‡ø†Æ“V-ž´v±ÇôùyÓi:[?-ÎÚ|IidžbØødÏ»Hhå(>”$›âã¨ø;†¥cŒ¹Æ->¼Ç+ ýE‹3Mÿ²eË>þøãûŽV2mfñŽpI’xÀ\G6vÄ"#Ï8òœîšŸÍ'¹Ïœ93''!´|ùr—ËõÌ3Ï(«±ªÿÍœŒáß½­|F{iåÓÒiíåò½cûFß.¿/#£¿TûWUoùŒö2ÆCdìõzCoÕ’Ì4ÿÂHs2#Å¿MµZ~Zù´ö2ÊWM§µ—7Z½Åo·]¡5FáËÈè/ÕþPO”åÓÚKk;žÑû)ÒÚÅ\ùµ¥ë¨?úy§Zãø@›GŠãÙ>ˆŒüªãPµI«_f”ã®ão x< Õ¿eË–}ûö=ñÄ‘;exKæuåuB>?­ÇiíbGž6³¾É¶üjƒ·Z½¼zxË.í‚øD_ˆ=´òõêwÞrâU¯^ýË›?^óB/ã–>,Æ[”åk‰±Y²îéñb¸p€øCsiâõ“ãõÍâõáãõ£égøÃ©–¯Á‡LÕ%‹7μåðº‹ñú®ÑôðÆ3^¾•¼ã–ŸwœóŽC¼þy¼þ…¼~™¼óeü`( ¹4ñúÉñú“ñúðÑ|ÅÂܪhúinXŒò£÷!Ct_1Þ8ó–Ãë.Æë»Æë‡G‹'­½¼nd ý\ùyǹj»4øYòúçñúòúeòÎÞøGñcÇHˆ:::*++Ÿ|òIm[?4T ŒtT]š4øÉñú“ñúðÑ|ÅanU ý47,Zù\>dˆîþÅg®rhñן·]\ñd´—׌¦Ÿ+¿†q®Ú.^?KI’xýó¸ü yý25ÌÞøGƒÓé\¿~ýܹsçÏŸÿè£z<ž‡zˆw-ÔV50¢¡¹4ñúÉñú“ñúð1|Åš[ÃoOÕ ‹Q¾2C„KoœyËáuÓ໦ª‡7žŒör¹‘1ôsåççŒq¢:Îié¼þy¼þ…¼~™¼ó…7þa‡E‹©¾çÝét®ZµŠ”i0vîÜùá‡*ëkä·"S¬"1Ñ\šxýäxýÉx}øh~c‡ÂGºU1üöTݰhå×××kð!#„š7μåðº‹ñú®ÑôðÆ377—Ö^.72ÆxãÊÏ;ÎÙã0rœÓÆ¿ÿ<.ÿB^¿LÞùÂ…ÌÌÌœœœ+®¸"--íóÏ?÷ù|mmmayHÛGURRòþûïcŒ#¿E©šq·Z²dÉ€þd´rêêêTý½Nž<‰*--ݱc ñûîw¿KܪB)))’$-X° ½½ý“O>QÕ_âž…1Vܰ?³°òÝn·²HqSÕ©¡Õøóæçmo<1Æ´ö¾þúë|ðÁßÿþwŒq¤YdÿbŒ#õóæGg|%£çŒv©ŽsBdºâ“V¹Þ™>eÊU=ùùù\ó—Ô}hýKîòÆŸäùÅ/~¬V«,ËaBä¾#9M¬ªª"¿œ$IŠüVXJ4Uÿå/ ­.Ÿ§a¸4ñúÉqù“ñúðI_1Ý­JU?Í ‹V>M#éðÎg åp¹‹1ú‹«]âIk/¯™ª~Þü¼ãœÑ.ÕqNK§•CK×à_Èå—É;_4Ä? Õ³1§Óùç?ÿ¹´´´¸¸xÆŒ›7oîééQž\Tý–’}ՠͥ‰×OŽ×ŸŒ×‡æ+¦æV¥ª_¢»aÑÊ×àC†Ô.iòÆ™·^ß>^ß5U=âIk/¯Û/3úü¼ãœ1¹ü,yýóxý yý2yç oü£ÁétƒARfOOÏ–.]ªá™z U#™onÒÊáò•ÔàŸ—ù;xðŽ^ÇSÞÐêå=‚q;ÈÒ|æÂ̽x}ãhéñò“£ù¥1Ú¥ê·ÇëKÇå#¨Á—‘á×ÈÛ/ªí¥Å“ׯNµ^F{yËW:mœpùb2ÚÅë¿ÈëóÇëIÓ£Z¯†þâ_´ñÉëOÉ;ió…Þzií¥åÐ'‰ IDATç/ìãmRRR]]Ý 7ÜÀp¾¤•À5B#÷FÓC«—÷FËÏHGˆî3Gˆ4÷âõ£¥ÇÅOÑýÒhíRõÛãõ¥ãõÔàËHKçíš¿ -ž¼~uªõ2ÚËU~¼Òã„Ë“×_0Ž>¼þ‘4_CÕzyû‹w~ÑÆ‰JÞùH›/´øpÕËh/-?ï|aoï¸ãŽãÇ›Íf %pÆä=‚ÑôÐêå=‚ñ:ÈžF¢øÌ!й—o-=^~rˆâ—Æh—ªß¯/¯ R—/#ï‘·_TÛK‹§¿:Z½ªíå-?^é´qÂë‹Ik—ÿE.Ÿ?^ÿH†o"c¾Dß_¼ó‹6NxÇ•†ù¨:_ñ᪗Ö^F~®ùÂ>Þ"„¶mÛ¶jÕ*Ýù’Vïáu<ÕÚÈä:‚1F -&|ª¹—o-=^~rˆâ—FkÍo×—Ž×Gqú2ÒÒyû…Ö^Z<5øÕÑÆƒj{yËW:mœðúbÒÚ¥Á‘Ëç×?’á›È˜/Ñ÷ïü¢Þq¥a>ªÎF|¸ê¥µ—1¹æ #?iÅìÙ³xàFÒJà!¼Ž§" Z/Ÿ12Ï"òU^“&MêèèøÉO~²lÙ²Ð÷mß¾Ýçó:tèøñã^¯W±Ë¡å§¥+\ýõ‡\ÎÖÿÒK/=zôheeeuuõ‘#GÂî5†µkôèÑ@ààÁƒ_ýõ¼^ïÓO?m0®ºêª@ °téRòÝÕ«W»Ýnå[Ó§Oߺuëþýû[[[¯ºê*I’ØùUãIX±bEGG‡òþ~ZùŒt®~¡µ—OÕtF{iãÑÞèËW:{œDÆyÀ¸…µ‹¼Ó+Ì5bΜ9 .Ô 'ú~¡é¤é‘$‰]o”ý¥$F9¿hãD۸⚪ó…®zÙãDuþòÎFþçž{nçÎa™(KÐ#«_híUBOÕtF{iãÑÞèËW:{œDÆyÀ¸…µ‹vXaŒ+ö¸²_h:‡9v½Qö—B”óK’$Õq¢m\qÍGÕùˆW½ìq¢:yç #ÿÑ£GW®\v4²Í#Du$pÁh-R­—÷FË?fÌv9êšaîE^œH² èwÓM7 ªŸÛ/-²] ¿=^ÿE >‚Ñû2ÒÒyû…í/Hó/äòíS­W:s§Dµ½\åÇ%=N"ãÌŽ[ôþ‚´qÅëóGKçõïœ7o£^®þ"D?¿hãDøŠ~>Òæ -> ƉªNÞùBË¿dÉ’ööö°' ¢/6bÙ#„×ñ4úÐêå=‚is¥¾Ö]1÷Z¼x1¹½`Á‚éÓ§K’ôúë¯/Y²„|?Ò7.,ii)­tÆmÙ²e‘~fQæ/ ñK“eYñK _çÏÀðÛ#~l‹/þÙÏ~–ŸŸ¯øÒmÙ²eÖ¬Yäb´â÷FËO‹'AÕ—QµüiÓ¦©¦3â©Ú/lÁÈx2ÒiíU­3ýù¸ÊK:mœÐâÌŽÃ_ü3Ò1J=´qN‹M'MÝngÔËÕ_ª0âF'\ãŠw>ÒŽ'НddqÕKk/C'ï|¡å_¶lÙÇæ} ´°GHäHà=‚ÑôÐêmooç:‚Ñz$Z§Õ°_vº¹—o£œ¸øÉ1üÒTÛ…è~{¼þ‹\>‚„è}ié¼ýÂh/Ã0z¿:F½ªíÕP~\Òiã„דÖ.‰Ó‘1nyû…Ë¿“=_¸ú‹w~ÑÆ ׸â´ùÂè/ÞzUÛËÈÏ;_Tótww_sÍ5a¿ø£/AÃár<å»^Þ#˜Yê€V»ÅëGK—ŸÍ/Ö.šß¯/¯ âôe¤¥óö ­½´xòúö1ƃj{yËK:cœðúbÒÚÅå¿ÈÐÃÛ/\þìùÂÕ_¼ó‹6NxÇ•¶ù9_hýÅ[/­½´ü¼óE5ÿC=täÈ‘ÈÃuô%h!¼Ž§\`ÔË{Óà ûÍ•üz õ™SÎ6÷’8}ãh鑽¨ÍON¢ø¥1ÚeTóÛ3púÒÑò3ê%‰Qú2ÒÒ5ô‹j{iñ¤¥³ã£Z¯j{yËW:mœ0â¬7v?FúòêáíšNšÆ|áê¯Ð¯D3¿hã„w\i›ˆ2_ñ‰²^v{ió:úù¢šË–-ûöí{â‰'T;Ñ” a„°ÀÑÁØzTG&׌–Ÿ‘®²†ÇZJüàÕCËO+„7?/ŒòãÕ®¸HåOËW:W|4Ä?.zx‰×xŽâ<¨å0tÆ«ÞÁW¡ùÉ]’è¿ÎV•_Cù"DLs9ç>¼¾€ ß>Uw+Z:¯¯+ >s\î\¼åÓ •ÃëÚEƒ×-ŒáFÆåÃ/—2^?9 ý¢ê·ÇçqÑÉëÇí¾F!^ãVâ[÷ç24W'^ÿ0š»-qúxÑòóúÒÊ¡å§éárÃbøñêäuíâm­ßiíåõáãõY¤µ—×OŽ7>4¿=Z½´vñêäu‰c´‹ËpÀø08vì)­£££²²òÉ'ŸäÚÊ1à€A‡æêÄëFs·¢¥óúxñºR"}ÈØ®T‘ùiz¸Ü°na¼:y]»xÛEs £µ—ׇ×g‘Ö^^?9ÞøÐüöhõÒÚÅ«“×%Ž×}M[|Ø8Îõë×Ï;wþüù>ú¨Çãy衇¢_ ÙC†«—ÍÝŠázÅëãÅëJ…(¾} WªÈü4=ܰ”0†¹…ñêäríâm­ßiíåõáÓ೨Ú^^?9Þø 3O5…ùíÑꥵ‹W§A^÷5 ñQX´hÑ~ðƒÈ?9ÎU«VmƒaçÎ~ø¡²˜E~+4…=$`01üƸüÃhîVäéÈÈôúúz./^W*Ò¼H2¶+Ud~š^7,Dw ãÕÉåÚÅÛ.Z¿ÓÚËëçÁgQµ½¼~r¼ñA¿=F½ªíâÕÉë§Á}MC|B™™™999W\qEZZÚçŸîóùÚÚÚÐÙÍ£F*))yÿý÷1Ƒߒe9,…=$`¨ s™âò£™zÐÒ‰)Fô>^|õT}Èå0|in[‘õòúØiÐÉëÚÅÛ.¶_ZX{5øðÑê¥éTm/¯Ÿœ¶ø ˆWˆ1êUm¯N^—8 îkÚ|+o¼ñÆžž‡ÃqòäÉžžžŸþô§¡u: _|ñÅîÝ»[[[¿ú꫼¼<Õo-]ºTµö€Aå,—©—^ziÓ¦M6l ?Ç***{ì± .¸`„ Û¶m#fëÖ­ŸþùsÏ=÷üóÏoذAõ:Iô|ùå—3fÌøÖ·¾µzõê»ï¾{ܸq¤´îîî={öìÙ³Çd2]yå•J´üªúŸyæ™}ûö½ñÆ‘¿.UËaä§éQ­—­óG?ú1NSJàÕyíµ×¦¦¦’ßò¹¹¹Ƈ·]ªýÎno$ìq¢Z/M'£½ª0ôóƇÆ8áÒ© o¿ÓÒyãCþôÎ;ï\wÝu)))ÙÙÙ7ß|óš5kÂ^îUSSóÞ{ïmÚ´iíÚµ999›6m2‘ßzûí·UËa‡nË–-{Î0oÞ¡KÎæÍ›7nÜøÁE.ôât:_}õU“ÉD _¸p¡ßï'_ü–j9´)F¸ýöÛy†²²2XørzzW§%K–„ú½þúë|ðÁßÿþwŒq¤˜$Iã7ß/ÅÿlÇŽ(ÄÝ* ª¦»Ýnš×ï~÷»'Ÿ|rÏž=cÅŪ®®n@WªPýŠB(%%E’¤ ´··òÉ'´zUó·´´<ñÄ‘zZ[[Uëåõ±ãÕYâc‡1V\»víÚ¯vÑú]µ½´~§“©S§>ùä“‘õ*>‹a:‡j{7µÈz×®]©ŸáG‹¿ê "­½S¦LQm¯NZþÅ‹sõ;Û0úø„¶ý¿øE °Z­²,“y ¹LN着ªÈ/!I’"¿–BdŠþò—¿„VwøCsuâò“(îV´tÄïãÅåJe`úF–CËÏÖÃ内ÔÜÂxu–qºvihÃ×0²½Œþåòw¤é¤µ—Q/—/##þ„°3BZ½´vñê¤åçíwF:¯oeªgcN§óÏþsiiiqqñŒ36oÞLÌl•Ì‘ßRRC†š«¯Íß‹–ÎëãÅëJ¥40lGÕJ5?M¯¢¸…q锸]»xÛEëwZ{¹|øõªêd´—×OŽ7>„H¿=Z½´vñêäu‰ãu_ÓN§3 ’±ÑÓÓsàÀ¥K—Fÿá€C EáóÇåFs·ŠLGœ>^´ü¼¾†´rhùiz4¸a‘» 4¬(uJœ®]¼í¢õ;{œDö/{œhðY”Ô|njQú22âÔüöØõÒâ½ÎóGßïìñÃacƒ\&þë ÐòkT5–Ÿ7V>W:/¼å v~ÞrâŸ8–Û/¼ùãÕ/¼õvþAMt¬F.4Ÿ¹xùÀ1ˆ‹ß¯¯!­^Z{i¾zñò·£•Ï ­y}y}y}%4å¨ÂëçGƒ×çOƒ/ Wx}1yËáõ¥å×xFq:>ðÂë»Éˆ?WÿÆ…¸Ô¨a„ ª$ã§OªÏ—ÍoïÞ{ï¥ùðÅËï qúÒꥵ—æ«§Z/ÃwV/£|B¨O£|Z?jðäõ}äòM¤ÅAµ½Œrhùyýü4øóÅ%7¼¾˜´vÑÊáõ¥å§¥3â¬ÚÞxTëÕ0hõÒòÓô³ã””TWWwà 70Žœ¼£Õ¯Âë0ª!]uÅËéó44Ÿ9.8šßÇ/^~o¼¾†´zUÛËðÕãõT­—Q>!Ì'Q¾j?jðäõ}äõM¤Å_µ½Œrhùyýüxýùâ•Î^_LZ»TËáõ¥åg”CÓCko¼ŽªõòÎ#F½´ü4ýì8ÜqÇÇ7›ÍLykŒ×áuåM§Í x9}"Äôóãõ“Îæ·ÇH7Äì÷†ø} U륵—æ«G«—·½ŒòÝ'/²|Z?jðäõ}äõM¤ÅŸÖ^Z9ªù5øùñúóÅ++|1UÛE+‡×g”–Ÿ1žiqfŒó¸hõrÍ#Z½ŒøÓú—„жmÛV­ZÅ>rrEŒQc\Fˆ‡QÞtÕG§OÄö#äõSž óÛc¤G¾6×ïæ£Æ09S­—Ö^šÿ¢ßAÕziå“¿Ò|ò"˧õ#­üxù>òú&2âOk/­Õü¼~~ˆÓŸ/^é¼qàõŤµ‹V¯Ï(Ío’1žUõ°ÇyìÇF½\óˆQ/-þ´þeÄaâĉ³gÏ~à”"òFŒQc\Fˆ‡Q®tÚ Š£ÓgxÄÂüüx}àH!‘~{ìôýÞØ>j “³ÈWg©¶—濨ÁwPµ^Zùh Ÿ£´üŒrhzÛ’íûå<°êèó3ô\wÝu¡§}4…¼£ÕÇÂå0Ê›ŽÔf¶ÓÆ?@àÜÅÍIœ«Dë“ç$°#Sì7¨`øg„ÀˆB`Dþ†Ãâââ .¸@õÀCC Ø»w/ãñ;P8  0v@aì€ÂØ9Úl¶ôôô¡” GùçYáÃÛíöööö!Wõ ’$ÙívZXAa4€ÂØ…± cçPèóùB_‹(’$%&&bŒ•§Ã/†½Ô`0ämªÆ  C¬Ðl6‡ýÚPah‘x #…°X¬(ä©_†!šÂ°C O¡øG£ÑÈ¥cìõz…ZBcǪê¬]£Ê‹S‡€²Ñc²³³Mf³Ñht45Õ×Õ*U3Â:” 3³²ÊÊF[m6„ÛÝWW[ÛÕÙ)”¬¬ìR»Ý–”„òz½ -ÍN¡$I:ïüó“’’Oµ¶=óÒ^AŽ7.?ÿ,Ó¯öïs÷õ!a †1cÇæäæFŒqÓÉ“Çëëĉᘱãò#l`™Ñ"(D¥§§—“”œ,I’×ë=q¼¾µ¥…üI…iéé£GIJNFõôt×=Ú××'”Âä””ÑcƦ¦¦"„\½½uµÇzzzT(ÚJ¨lÝ6Ë¢eÀ·ÀéBbbâ¸òñ¶¤¤öö¶®®®ää”qãÊ…z OBBÂØòò¤ääŽöööö6«Õ:vìX2‘D£´´455Íh4Jâõµ%Ñb4û\®ž3½EEù„ £ ƒÁ@kKKG{»÷ì_²ºãñ¸;;:”ÿüýýdÁÖ[×YŒWž’šÚÝÝÕÖvÊjµŽ;.!!AoQß`6›ËÇOIMíìèèîîJOÏ+ØÑ!T>~BzzzggGWggjZÚ¸ñã gû*kt»ÅZ{ìB¨|ü„¼ü|½40ÈÊÎNHHèíé©®¬ÄÏžs¡ÕfKJJr¹\zK;Mb¢¥ÏåêðykÃO›>=--=55­O…[RÒ¨¢bY–ÅüÅC®•UWUz½^’"ÔA<)99;;' :xÐãv#Áä!„MMN‡ƒ|NOϘŸÏï÷›Íæ´ôt¯ÇcNHeÙ#ÒL1'$Hy}^r±ÎëõZ,Öä¤dqB›Í†òù|D¡ÇãNJJ²X­z늺-„‚ÓßßßßßO>—c0ÚÛÚ”AÀ§¤¤Nœ<Ùd2Æ“ gîb B~AAfVVÉãf³@W¢B1'$ŒÆÑcÆ’+QÙÙÙ¿> ί4£Áˆ²Ù’&Nšl00Æyyù_íß õ–NqI‰Ífs8š\½½zk9 ,ËuÇŽ;vÒä)!I’êëjÉéµ ø¼^ŒÍ–D®šÉ"Ô¹“…N_­•„’ $IBýpÔŒ@±“R»=77×ãñÔ;*ÎñQA–e·Ûíóy%IJÏÈÛ§/f³¹ÔnïíëBY(’ÁÐÓÓÝÕÙ¹ßÞ¯öíõûýiééÙ99zë AB¡€ß¸âÐýû|>¯-)©`Ô(½e©››‡1nv8ìë윜„„Ÿ×ër¹$IÊÎÉj¦´žju»ÝV«õ[3gΜ=‡œ~C ,„,ò ŠKJýþ@Uåå’Pôõ¹:¸ïÞŽŽöä䔂Q…ʯ6Ý))µ'&ZL&Ó´éÓ³s²B™e£Çˆ³ ËòáC‡üÚÝ×çr¹zzºB6[’81 !ŸÏ×ÕÙÙÓÓÓÕÙ…²X­âÄ–žn±Z}>Ÿ²×Qò ²²³û\®}{¿üú«ýímm©©©£ŠŠ01IJ|øÐÁ§Ãçõµ¶4÷öö"„0è÷„$iœÙØ0BËÁsãt…=>Á~`eP ­š½wèNÈÎ=z BèØÑš°‹õ"(ÌÍËUXØÛÓ[W{L¹i0BìÑY!ÆØçó£Ñb4šBF£1!!cQ¦¤¤”–•ùûý5ÕUc"2à÷c,³e ™Bò ¹ƒ16™M!¿? N Igžá «W… Býýýäaƒþ~BÈd4!‘bèñxª««BF£ñ[3g!„~B ÈÍËÇ÷öôÃŒÌ̼¼|¯×“žža±X\®ÞŽŽ½E}Cgg‡ÛíNJJ?q"Â(99ÅëñtèúF›ø ¡:6«ßɆ¡†¦j ‰¡¿¿¿öèÑR»<ÃãóùNÔ×»EÚF:VS3®¼<##SÊ”ˆÂÞ32 „d@H²@«ÐÛÓS_[[\RBü÷÷÷766´¶ïßfµeçäG0;::jе#c\S]5fì¸Üܰ_bb"y;€ cAç…PähЬMc,ÚŒ*"SübŒ=Ñê-a0Æ¡nâ÷ûE{B4 Œ±˜{cv#•]£ºïÌp—(P; 0v@aì w…C,&zBeÃ!0¢…ÑÀBŒhà9B†‹ÅzÆý »»{ˆÚs X~\wÝu , ûDžzê©úúz‘÷e‚¾k‰±Ï‡½ F(ŒP;ƒ¤P’$ƒÁ l˜dl\ÔKaÖ 5lj•$i:fàŒ8׸ᆈ—[CCî]»D8LqÇápTTTƒ¬Ëå‚^>g «`FFFbbâ€Ý–A’¤@ ÐÝÝÍûú7XsË/¿Üd2!„öïß¿{÷n8Dž“|úé§Ÿ}öù 7ÏŒFc0œ?þÓO?m±XHÏ’ÿ+'p‘‰JŠÑhìííýÉO~ât:¹ê……8×$‰œ(èþ 10xÄr-² ^tÑE/¾øbjjªrác É:G¼´~¿Ÿ¼¦œ$*K#¹ ÄE< .¸Àn·ƒÁ#GŽ;v,77·°°!ÔÛÛ{ìØ±¡µeee¡þþþÇ&“iêÔ©’$9NåWCIIIvv6BH–寿þZÇ –=uêÔ¬¬¬`0èp8<(Ô •’>;vì”)SZZZ¾øâ ŽJS¦L!ž!›Ívþùç»Ýî*1¼ŸÂä…¡×4 ¥¼¼<99=eBãÇ'ŽƒG`åææ’Ï•••BMBjjê´iÓrss%Ijoo?xð  ÎJÊ,îèè8qâDiiéÔ©SÇÞ½{õzß)YçÎûÇ?þ1555 ²¼I’ôì³ÏºÝîGycŒFcSSÓ£>zÓM7}ûÛ߃!’“|æÅ6¦µ ñ’’’[o½µ¤¤„ü¿öÚk?ýôSŒñüùó%I:vìØÓO?}ÉìßzÑ—3gΜï|ç;’$õ÷÷ÿâ¿èïïGþù·ß~»Á`Ø»wïêիɈE‹MŸ>]’¤S§NE³ÆKa(F£qÙ²esçÎ%¦—¤œÎÎÎM›6i¸¾7 B‹-"?#Èí·%K–˜L¦ýû÷kXCáí·ßž””¤ü?~|yyyssóÃ?¬¡À¸+¼õÖ[ÓÒÒhå&h^ýõ£G&îßüæ7J K—.-..FñsÆ!BhÞ¼y—_~99à<ùä“uuuÚJ$…?üáçÏŸo±X”Ëýýý;wî|ë­·xWš¸+TfqMMM}}ý‚ È­Œñµ×^ûÆoÔÔÔÄkF¹Y†¬‚sæÌyùå—ÓÒÒ‚Á Y•B‚Áà¦M›L&Ó¯~õ+£Ñèp8î¿ÿþššš¥K—’ÓAR‹fÙq8#´X,wÜq9ùSZuÉ%—¸\.£Ñˆô»BU]]½`ÁƒÁ`±XÊËËÉ/Ü)S¦­ãÛ8 IDATFI’Ƨä,(( Rt‘ŠºãŽ;f̘zR/IRVVÖ-·Üâõzõ=O •D¶êedd,^¼Øl6#„z„ñ85 aT.“Š@˜<Qú7,h$‰tµ9lרPÜvÛm^xaX_'&&^rÉ%YYY/¾ø¢¾75•Е•••——+:%I*((¸ýöÛŸzê©ö!t6%§q³fÍúÓŸþDVA²_FA–e²þ­[·!´|ùò{î¹§¾¾þù矟;w.É/˲riTƒ†8,„W]uÕ¨Q£Èg‡Ã±k×.“É4kÖ¬üüüØ …ŠŠŠþþ~‹Å‚*++;|ø0BhüøñdòdddL™2åСC‹%''‡|E¯kSóçÏWVA‡Ã±gÏ«ÕúíoÛf³%&&~ï{ß;xð  ‹ œÙôööú|>Þû҃ǻï¾k6›oºé&ɺºº/¾øBœ-…û÷ïWžGÆéÓ§“Á`ð“O>D' ]tÑœ9sÈliiÙµkW ˜={vQQ‘$IS§N½òÊ+?üðCú:11±££cÏž=}}}³fÍ"'ýYYY×\sͺuë†F!YófΜù§?ý)===r$ ¡,Ë÷Üs$Iëׯÿ׿þ…zöÙg/¼ðBr™Tɉt\/¸à²´x½Þ—_~¹¹¹!´}ûö'žxÂf³Å^¾f|>_CCøqã$I*,,$¿€”5!4}úôC‡7ŽœbŒ:¤Ë½øâ‹ÉÌq¹\øÃÚÚÚBn·û{ßûž$Iv»½¸¸øÄ‰C/ŒÁ?ÿùÏ-[¶„AÝùôÓOB7Þx# fggç¶mÛÈ•½¥!„кuëBÏ`V¬XA.I!„>ù䓽{÷ ¢ˆ…ùóç“á×ßßÿÇ?þÑáp „>ÿüóG}4--M’¤‹/¾xëÖ­"ôµßï饗Èe°;w>ú裩©©¡éÓ§¯_¿~hbŒ“’’{챌Œ eóK!r±ôºë®{ÿý÷O:uñÅ“UÐ`0(<–…0Ö 5ÉÉÉäsmmmKK ‘ÞÞÞîóùb,ùä“ûï¿ÿ¹çž³Ùl@ ôê(™N§ó¾ûî;~üøÓO?=oÞ¼?ýéO7n4?ÿùÏ•×Ðà¬c=# ½øÙ××ciq§¢¢‚ì«¶X,Ó¦M#?Öššš¾úê+µ .¸   @ùa®ËÐ ½od2™,gP¶"‘6)1’ðãÿ˜\ƒ ƒ6lÐå:0„Îå°':B¡ÙÄ¡··Wù<” 1ƃáÿûßÊ•+].Ù;CÎÉ*ˆ1~üñÇkjj~ÿûßÏ›7/Üu×]Ë—/÷ÝwÿñSÆÝ*õ\ß½þi±Xh%p•ÌÈÌ«°¿¿¿¡¡a„ ’$]~ùådc‘#GvïÞMž¬˜óÌ3IIIäiøÌs„7ÝtÓ÷¿ÿý9sæ›…¡[n¹%77wÖ¬YèÌŽŒ1×KJCeÇzi´µµU)+''gh^–ÊE}}ý„ B'N$çU{öì©««s:………cÇŽ%au:d‹ÊÐÓÜÜì÷ûÉùŸßï'¿q"³‰X@_|±È·•GÜB¯FÑÓÔÔ¤ìT5jTèñP¹/(Ëò‰'œÎäþáÔ©SC\;Y ?ûì³_ýêWÏ<óŒÍfSöȲúè£Ñ£G›L&£ÑxÛm·]|ñÅííí&“©   ¤¤¤ººú¹çžð'¤˜tww“ËÝååå÷ÜsOkkë[o½¥{ôÌfóüceEÁßqÇ¡úúú^xá}O«««çÍ›G&Å]wÝUYYi4ÇÇx!ÆG}4~üx³ÙœpÏ=÷9rÄï÷O™2…¼£cüßÿþW÷ÑH0›Í÷ßeee (//OOO'éû÷ï×K!yŽpçÎK—.µZ­¼×Æ$Iòûý]]]¼õÆa!|ÿý÷Ï;ï¼’’„Pzz:¹h‹ÎœêÆ^~Œ††åºè¾}ûHzuuu[[9bƒA}ŸXß»wïG}tå•W ³ÙÓ}4dYNJJš9s& QØÚÚºyóf‘[}Cü^V> Eø|¾—_~ùÀä„T’$¯×ûÞ{ïižØ˜‰†ëêêȇ¶¶¶#GŽà3{m•«¦N§“+îqWˆ1~÷Ýwß|óM²©Zy7˜×ë­¨¨xõÕWyï_Æ]aÜ<…ÿøÇ?öìÙC®:J’Dögê®p0Â÷U«V)WM$Iêìì\»víž={4ì‘61Æ›7o^»vmè\Fµ¶¶nܸqݺu¼kÌàÅÐçó½óÎ;}}}D¡,ËÕÕÕ/¿ürgg§¾ ‡fl„ŠŒûDkkëK/½”““SRRBn¿¹ÝîË.»,.…ÇÎßÿþ÷÷Þ{Ùƒ¤¤¿ñÆo¾ùfdº.`Œ·oßþé§ŸŒ5Êh4vuuÕÖÖ*O˜ê+ðÒK/)±ê1.—kõêÕv»Ý`0Ô×׋ Õétþ¿ÿ÷ÿ'U‚„´¹¹ù™gž)...((p¹\ÕÕÕäîŽ;ÈÖD"„6nÜøÎ;ïÏB½Õ!„1þì³ÏvìØQXX˜ŸŸo0ZZZÈcyBéD}üñÇŸ~úiyyybbbcccss³ ý;ÄÄ͆I–å–––ÖÖV$ÞþF|æ©Ì0Dër2OšššÈk™x‘-b4dYnoo'gùâÄpEïĉäÍ[JôÄ #6©ÌåÆÆÆ“'O"ñ¢§€1v»Ý_ý5XägcÞ‘Ê8aŒ ÆX€èÅ…aÆa!rPÚX€M¬¯XcðôÓO“ÇÕ}>ïÕ|š qî6ƒÂØ…± cg¤)|óÍ7ÉCÞq¼ÏÊP—òƒÐèÅùa(âøµ„¡tŸ.À¥Q`D !0¢…Ñ âfÍ0d€Â(…± cÆÎpW8Äb¢'T6œ#X€ ,„ÀˆB`D !0¢]£Z…± cÆ(ŒØ5 Ûð…Päœ cÆ(ŒP;â+œµbŒ=¾‘Å»ÝnÆ_Aá€€ÂØ…± cg¸+D!=²,‡þS*..Vþ1¶Z­eeeIIIC.ì4n·»¶¶ÖëõJ’ùWP  0v@aì€ÂØ9ö÷÷›Íf£Ñ8ôÚh¿ßŸ˜˜¨h>k!DƒA¿ß¶Z%ƒ5P8  0v@aì€ÂØ97ö÷÷ë¨0ƒÁªY***ÒQè ìF4°#X€Iß­· /pFŒh`!F4°#X€ ,„Àˆv#8#F4¦A-½´´tæÌ™&ÓàÖ ìÞ½»±±‘–A|…h8ˆ… cÆÎ€ SSSóòòT­$Î0ÆÍÍͽ½½JÊ öƸ¬¬ìÔ©SƒWÅ€H’TVVFëuñ¢á F(ŒP;*”$éäÉ“çö-3I’HcIÊà^ÕÝzƒt'£SÅWˆô) V›Mù§8a 3OQG!!!!Ál6‡¦ˆ¦0P;ç€BŸÏwn¯‚!Œ±×ë mæ n–Á‡.¹z!Ë2­â+DC.2-=}ÌØ±©©iƒ¡¯¯oÏ®/ˆ6ýÃ(Iç7=3+K×ן8q<ìïú+D!”˜˜8yêÔ´´t„ЩÖÖÇU‚(d cg¸+b1:Bºƒ|†Í2À7X,–)S¦fddvuv6lìho×[Ñ7äçdegW:xêÔ©»]’¤Q…Eßš9K÷ÃJv{YFFfwWWooo^~~!ø}ž£˜Íæüü‚ìì½…q@·{¶€€ä$Z,]¿>Í5Û¡Äl6cŒ»»º’““FCBB‚Ýnw8zë ‡\R>^_g±ZSSS-«$Iâ„Q!?¿cÜÒÒ¬·áJRRÒÄÉ“]®Þöö6ûàBà4¹yyÙ9¹’$I’4zÌX„PGG»8'…r08õ¼éV‹¥·§wÌØq@àĉ㢃z]½YÙÙEÅ%É)ɲ,ŸjmM¡Åj øýyùrPnoo“$Éï÷ë-jXB&‹Þ*€8 !pšÄ„D²¿Ãd6%%%!„z{{ôõ ®ÞÞƒ¿ÎÍÍíêìèíí8iòÁ¯`½·Dr²¡¡¨¨8'7×ßß_]UÙÝÝ¥·¢pìv{^~–eã ç]t²±ñx}h«uèV#ÑÖé’ÒÒää³Ù$IRb¢eâ¤É¡ÆÆ†Þæ À,„ÀiÜw¿Ïk³Ùú}ý]]!Ÿ×§·¨³èìèèêìD’4s欖æf“Ñ4v\¹»¯ÏáhÒ[ÚiL&Óä©ÓL&ÆØ`0ô÷÷[m¶é矪õTí±£z«;M]m­,ËÅ%¥¡Ç;šDÜ+ÑÅó•“­Ÿnïïï×WO(éé9¹¹äsBBBÁ¨Q¡¶S§`!¾ î®Q$ÆM&ö)‘¢!™œ””h±`Œ-VKVV6B¨ß×ßÙÙ1 È¡ #ƸlÌ“ÙÔÛÛ3iÊ”žî‹åx]­ ‹KJÒÓÒ:ÚÛÛÛÛF;aâ$§ÓaµZ1–Ù†2†ý~FffWW§ÅbµZ­aÛåEPˆr:š”…0 ¥°¾®ödc£Åj?a‚Çã>Z]ƒ1îééVªÖ]á€À®Qtö®Q8#NsâÄ ƒÑTVVæîs}à«ÐQ"É))¥¥öšêªÌ¬,Ÿ×{à«ýSÏ›ž••IBÝIHLD’äv÷5œ8‘XRZj·Ûe·´´ˆL,Ë';;;“lIHôØWUY©|MaOOB(##!$Ë2l–9€…8 Ƹµµ¥¸¤$#3sâäÉ·!\_'ÖÝ#»ÝÞÕÙét8ÒÒÒLf³Ùl6›LÁ@Po]§éîê5ª0/¿ ”Íf³,˃Áãîës¹ô–v'B¢© E¨QœóÀB|ƒ«·÷ÈáŠÑ£ÇäååKy<žúº:½EEuU•ÑhÄŸ¸Ýî'žx¢»»[óž‚áÛÑç¼ÂíÛ·úé§äsŒ—pGl ãÈ)4Á`0;;û‘G¹òÊ+Ib,« ÑhLOO—$©³³3ÆëØ¡kYF ‹…œ(tvvvww˲,Îñˆcù zk†r!7 ^xá…7n\¸p!éz24›––öú믿ùæ›999ñ+ð¥Ñ²²²I“&¥§§‡Ã±oß>·Û­·¨³˜1c†ÝnOLLìë뫯¯?xð €GðY³f•••ƒÁ¯¾úªN0+‰I“&%%%‘={!³Ù §—‡är¨ÉdúéOz×]w%&&âC¶Œ’Ørí%™M&Srr²Ùl6q,âBh·Ûo¾ùæ &(MÅ»\®þóŸ|ð#ræÌ™Ë–-ËËËSnùbŒOž<¹aƯ¿þZ…!»Ý~ÇwØív"rñâÅÿùÏ„ºG½|ùò²²2å:Innî}÷݇Z¿~ý‡~(B‹ŠŠî¼óN²‘!´xñâíÛ·»\®«¯¾Z’¤†††|P¡K/½téÒ¥ÉÉÉ!Œñõ×_ÿÆo|ñłț5kÖ7ÞH†ßË/¿,Ž0UV¬Xqá…µÛ·ogR È*XZZúØcÍ;c  ƒrË# ’Ýp\Q%™À`\4n!ÌÏÏÿå/™zÈ–$)55uÙ²e²,ë~ˆ<ï¼óîºë.›Íš(IRIIÉ=÷Üó /TTTè>m,ËÝwß]TT¤¤˜L¦… ê.,rñ$4…üSÕ:!!áî»ï.--UôÆK/½´§§‡üDD'B(99ùÇ?þ±rn-IÙ¤~üøq‡Ã¡¯6ékå<@o9,f̘1gÎÒÅ'Ož\¿~=\ÎåB–å«®ºêá‡ÎÍÍ ¤ßñÙÞOÙÙÙÊ9b”ÅJ’ÈÒpî/„×\s² ~øá‡‡*))ùÞ÷¾g±X ÃÂ… ·nݪïÑ|Ñ¢Eä±Öžžžµk×VWWÏœ9sùòåf³Ùf³]wÝu‡ð‰]´hQaa!ùìp8vîÜ™0oÞ¼¬¬,}……²eË–´´´E‹Ummmÿú׿0Æ‚ßÚµkE»##8ƒá±ÇûሠƒÊåPåtcl³Ù^ýõ°ttæ•7a™Ã> „¬V«Ç㉯lá^± kkkɦ uëÖɲ¼oß¾âââ¹sçJ’”“““››ët:ã"C›Âüü|rp¬©©ÙµkW0ܺukyy9ÙýÖµ1*Ô,rÆŒD¤×ëýýïON ¶oßþøã'%%i(9îaD}ñÅ¡Ë/¿œüÓëõþç?ÿQî¨ó–w…3fÌ úûûŸþù††„ÐþóŸgžy&55UCɃCBOOÏ£>ÚÕÕ…Ú¹sç3Ï<“˜˜ˆÎìÈAadQÚJT…ão¼±  €üsË–-‡æ=î1ŒM·¶¶³Ù¬\ÃŒ\ÛÈåÓÐ3E|æu3‘™qÈ›hdYöz½qyÔ8´±Â¾ñÆÊge†ÞZOKKknnŽ×xÒ€Ëå"/g™8qâ‚ >ûì3·ÛýòË/+t¿’’’¢œÖÔÔ8N®ÆÆFÇ£,„ºÙ‰qùdݺu¤„Ñ£G‡}Éñ½w‘‘1vìX²$ùå—ä­QãÇÿùÏž››+IÒùçŸÏ[,;¿‘¡÷Psssýnœ^aÔPK,ßÕCòÃ!”““C+A߆~EL…*ÒüÅc ÿú׿ƒÁË/¿\’¤¼¼¼›o¾ù•W^g³LdwF 5ŠSC–e£Ñ¸sçÎ[o½õᇾð 9ÐÆŠõе””åsWWé°äää &(éúžÝÿý+W®\¹rå\€1–e¹ªªJÙñOnjê¨!ÔÑÑÑÜÜL>Oœ8±¬¬ŒH*//g§Œà¸\.å ¼ &·#„Pii)ì@9W‘eyÆ Ê-á‹.ºˆlV×WÕ°†Ü t8÷ÜsÏŸÿügòŽ=o¾Š²8ššš”ÏW_}uZZš$I\pòÄ:{±z*++;;;Éië²e˲³³Ngaaá·¾õ-¢°©©)¾¿ª´±{÷îÅ‹K’”””ôàƒVWWK’4qâD¸R=»ví*))‘$Éb±üú׿®ªª’eyâĉäí-À9‰Ûí^·nÝÊ•+Íf³Á`X¶lYeee{{»Þº†1ä”: ®^½º¢¢â¡‡JJJá ŠXg„555G%1JOO¿úê«.\˜ŸŸ¿{÷n%pñ}×*/@`ݺuäqά¬¬¥K—Þwß}?üáÉ™V__ßÛo¿-BoÞ¼ùĉäsZZÚÌ™3g̘a³Ù”3E`@¶lÙRWWGz355uæÌ™³gÏNKKóûýzK‘ýû÷oß¾ô{vvöŠ+Dó Ž'>ûì³Ûo¿}ç΢g‹ÕÁãW^yåàÁƒäGyâäoûÛ† ”Í ÊËpõb÷îÝÏ>ûlUU9ë'·ý~ÿ¡C‡þïÿþO„÷«!„¼^ïóÏ?¿oß>òØ©É]»v‰‚µÊ IDAT oX@ž£ÿòË/•z<žM›6µµµ‘ ÉsŒñúõë• ¤³gϾä’KD;pGÈц††ßþö·B=;D»4Šr:O=õT~~¾Ýnïïï?vìyRxÅŠ$ŽÍÅ#v0Ƈ~ôÑG322ÊÊÊl6›ËåRìdÅ98677?ûì³¹¹¹v»= VVVöõõ!„Þ~ûm$@V®\IŽ2âHR8uêÔóÏ?Obˆ1®ªªêéé¹âŠ+È_u?5üío«ºßüæ7¢…4ô¤J¨[DÏ>û¬²È)ÂÜn÷}÷ݧ¤ b ¶nݺ¿ýíoä³ ’x!šûûûE?è»F5ü’’eÙáp_d¡{ºb‘_…ä‹íííÊ+obÜ Æøºf‘!òà*±4Š1’ƒFE¤¶/ªÊ`üIƒÂ¢¢"“ÉtâÄ %†W^y¥r÷:sÜÒB§9¤ƒ×ËyyyÊgò*8mŒäbŒãòbÈv2 A-*C¸3BA‚ÅDžÛÌŸ?ÿšk®q8>Ÿ/33S±d’eùóÏ?‡Ø²IIIYºt©ÙlVžîééäL  îBºSVVf4KJJSYåçüG}~­’••uÙe—)L¡mÛ¶ rµ`!*555ÙÙÙ………¡—³ÇÖ­[?úè#¡îu‰ yK0‰žÏçÛ¶m› Ûª ”A¼GHaг5ˆ¯0š CÀp£…ï¾ûî¦M›ìv{YY™Õju»ÝÇ?~ü¸æ]Q#-†Çå•WRRR\.WEEEGGG짃#-†ƒ¾÷axÜ#Ý! ^}}}}}}h¢Ž’†===ä5„â ,„0pˆ >b=PC ,„ÀˆB`D3¸»FE¸=0à{[†R MðØf6¬Ã £ÆÎ°V(‚¼!#´±pFŒh`!F4°#X€ ,„ÀˆvŠ® ‘ 0@aì€ÂØ]£„¡Û5*~XÅWˆ†ƒHP; 0v@! A\1Æ^¯WߎÇ{<Æ_Wˆ†ƒHP  0v@aì xÀñûýC&FGÂ<Ô¤´´´Aª cœšš:zôh›Í6HU ˆÇã9vìXooo¨Ÿœ‚ø Ñp £Æ(ŒJ’”””d2Ë~ ~¿ßív“Æ’”A\B²,˲¬ã/ I’ ƒÁ@=ñ_!"Aá€€ÂØ…±Â`0xn_•$Éh4†AJMMÕQè <>Œh`!F4°#X€ ,„Àˆfp_±‚g„ÀˆB`D !0¢…ÑÀf`DþŠñ¬¬¬ÒÒRö; ‡Y–ÚÚÚhìvû…^h6›‡RU(~¿çÎ'Nœ e… cÆ(Œê¾ÊD®)g-„c«ÕÚÔÔ$Ôi¢$I‹%Ô2#Œñرc[[[‡^˜‚$IcÆŒ¡u<(ŒP; 0v@aì ¨P÷U&rM1„ý¹¿¿_¨U!„1îïï§ýU’$Y–‡RO$ìˆÂh…±# BÉ`˜2uÚø‰ÉG(…ÓΛ>áŒ0¡ªr(Ô}•‰\Sº:¬í×C$ 0v@!/“&M.((èîêR„‰£°««³¤Ô>vÜ8®µP@aÜ…€A!;;»°¨ÈáhjinÖ[‹ 'N´µµÙíeÉÉ)zkQ!!!!'77==]o!TóòòG%f¹ß,€Ñhœ5gBh×Îbþ¶_!B¨¨¤D’¤Ç «ðdcCNNŽÝn¯¨8$šH«Õ:fÌX·»¯»»[4m¡Ì¬¬1cƘLf !ãf§ãĉꌒaóøCçÐ7A’¤¢ââQ……'›Nž$DP˜c=Úép4lŒÔ »B‹Åò­3îDíÛû¥ÇãAb(THII•$)L(ä"##Óår¹\.a¶¶´øýþôÌÌPUB)ÄgˆLd|eðu¡üü“ÉÜÐÐÐçr7.¿`”Ãáðù|Ñ(„P…pFȇÕj-.)5jT¢Å"IRcCƒÞŠÂÀYYYYYYcÆŽu: ^¯GoIg!I’êî_¡mý |«C|…6›Íl6÷ôôè-„ÆØçõ&§¤˜L&¿ß¯·œáDcà §ÉÔÙÙ‰1öz<)©©V«MY‡°r0¶¼¼Ì^f0=OCCƒÓÑÔÕÙ©·¨³hkk۽닂Q…¹99£ÇŒ±ÛíMަÊÇ9\z½ÞÏw|–(ˆ¶0ÄTŠà -„P@øÕÅð#„, ,„\(?q2³²lIIýýý½½Bÿèa !i©iF“©¯ÏÕÐÐà8yRÌ™ÓÕÙÙÝÕÕUP`/+KKKÏÊÌÒ[Ñ7X,–™³f‡~¹g7¹4 œKˆÞòsb¸¨Œ¬¬¬ÑcÆbŒëjkƒÁ Þr´ !ÇŽÖø|¾¼¼¼ &Ž;®£½½®®¶»«Ko]ß`±XF›››K~·:ÕØÐ Ô©C 6‡H ¼/BȤßûM¢„(ôŠ÷S,”½^¯àKJí&“éÈáŠîîn½µÄŰYfÈèîîî©8T]UYRZ:jTa^~þ©S­ÊB(‚ÂÔÔ´â’ŸÏ×ÐÐÐpâ„»/|Ÿ‚ŽÚB^¯w×;Ã…RH`ìÉD¡Õf›:mZ¿¯ÿë_‰©ÐíîëïïOLHˆü“ ·;„&Š °··çÀWûibDPˆjinF’¤º ¢l–ÑÆØï÷×ÕÖÖÕÖæåå{ÛŠâõzªŽi<ÙˆeYÌ(¦ª0$IJMMÓ[ “ј‘‘éóyõ¢»«+'7711ÑëTgvNNBB‚£©Io!*Øl¶’ÒR¯Ç#òc ÉÉÉ!²{Yo-1 ¡H¯77;õNOOàûô†âïÉ$0w´wè-„ÅÉ“Ù99ö²ÑÕU•bF²¨¨cÜÐ âJc6›322û\z a‘‘™yæ.ëðBPAÀ#c(iéi²,××׉¬³µ¥¥¹ÙYT\ÜÞvêÔ©SzË gTaQn^^cCC÷·º»»É}‘»xÏî]Hl…Q ! ?êjk×× {ÉQ¡òða“Ñ”“›×ÖÖ&Úá2??ßép{¶Š†Ã#¾Â(…† ?¡ðûý_íß' 1øJØ[éÀs.ì¡ "¼ôˆ (ŒP¨Œ1 1Gað좡QÈÐ0¬ B¨BpŸF4ƒµ‹WJËÁX\å!Š1>ž/€Á#55Õl6#„0ÆB? "0H‹KüBƒÁ Ëòƒ>(Ëò³Ï>+I’r‡…»ï¾{ÆŒ’$¹Ýî›o¾yX¿­›Á[\⼡¿üå/—/_.I’ßïÿÃþ@ã[œþÿöî=¬Š2ø;3ç~áp?wш„Ó­(5-Ónjfù¬mVú¸¹¦öÛ6{ÚjŸ.ÚZš‰nn[O»ÚšvÓÊ  â]¹ÊÁˆ€\œë̼¿?Þœ=¡ —3p¾Ÿ¿†sÆ3_çò~ç}ç}ß¡iš¦)Š¢ixZ@w4¹x²×¨è“O>‰1æyž,¼ûî»ýwH÷’‚{ÂË#ôHG;/߇öŸÇ{Dr^£îÒ4½qãÆM›6aŒŸ|òÉ矞¬à©mðƒ\<Ó4Ú)ÐÍ›7ðÁ<ÏÓ4=þüùóçcŒßÿ}h#Ðsƒ“\<IË–-}÷ÝwI­ó½÷ÞÃÏ›7oÞ¼yãuëÖI!¦¤¤®z,Ë=zT¨  †Ñ£G“޹­­­çÏŸ«‘!&&&00,×ÖÖVWW“常8ÿk?WHHÈ-·ÜÈqÜÅ‹‹ŠŠ¬V«ØA¡¤¤$­V‹ây¾¨¨èºG¹±±±¢¢B MIDddäm·Ý¦P(Ìfs~~¾fP‹7 ¡æææÒÒRµZ=qâD£Ñh±X Íf³(Q B[[Û¹sç|||222‚‚‚,K~~~]ݯ³á;6!!A&“•––ºŸ`¨´äÒßDH¶½téÒ'Ÿ|’¢((Ïó$ š¦ßÿ}îܹs1Æëׯ=Κ5+!!ô¾]¶lYeå¯3Ož:E­V?ýôÓwÜq‡L&#©… ؾ}û¾}ûÄ-;;;++‹DµlÙ2!áÝqÇä¢BmÛ¶­¢¢BÄ ÝÍ™3çFS<öØc6l8~ü¸¸»1''‡\,gϞݵk×Â… È^}ôÑG?ûì³;w~„<òHJJ EQ{öì™;w®Á`¢Ú¼yó/¿üBzä’1>vìØÛo¿ÝÑÑ1È¡‚>ÌäÒ¯¦U!]/X°€¦é-[¶¸Š" ëÖ­ËÍÍÅçää,^¼‰ý¼°¨¨ˆôÓcf„ ÂçÉÉÉ Ã^|û÷ï±:|øðÑ£GIñññãÆ£(êþûï÷÷÷'ý ¿ûî;)¼¥lÅŠwÞy§B¡ ;¸xñâI“&‰;£BAA‰‡¦é[o½Uø<>>že–e8 ú>$T*ÕìÙ³ …°CBB^|ñÅqöaHHÈsÏ=$kµZýÄO4)bT‹-òóósjþüùK—.MMMeFØŸ)))999ÐSa¨ääÒ÷Ó¢SºÞ¸qã;ï¼Ã²l§„LB_¿~ýÇÌó|NNÎïÿû>‡ë?ýô“Ãá ËIIIä2V*•qqqdÙd2‰Ûb†1Þºu+¹{¥izÆŒ*•ê®»î"áÕÔÔ|öÙg¢9›={ö¸qãÈq¬¬¬Ü¶mÛ®]»Hkž\.衇ÄM„yyyÂõ1cÆÁÄÆÆ’å’’’¦¦&Ñâû-š¦[ZZvîÜùüChŠðóó{衇$Rv8Ž;wnß¾]¸: ÅwÞ)âÖét---_|ñÅçŸÞØØ(|8~üøsçÎ}úé§?üðƒËåBQ•™™)“Ák†€ÁO.}>AF2 ~ñÅŸ~úiPPÓéliiq/£†ñõõU(_|ñ…^¯Ÿ5kÖO<1þðÃ{Õ²çÁ´ÔÒÒrúôi29&&F£Ñ´··§¥¥ét:²BQQQêמMœf³y×®]>ú(EQÉÉÉóçÏ "[ùç?ÿi³Ùúð›žpòäÉä„knn~å•WZ[[)Šjkk›3gEQ£Fºé¦›ªªªÄŠc|òäÉÉ“'SÅ0 ÏóÑÑÑd7"„ û°¹º=r¹\¯¿þzyy9Ïó_ýõºu낃ƒB¤P Z­ÖÕ«W×ÔÔ`ŒüñÇõë׫Õj„Pxxxoʃ:ŽÕ«W×××#„.^¼¸téRrN–””¬ZµŠã8Š¢”J%i$7 ÑÑÑ=yö/‘v‚n ã-¹¸¯ÐÇû#ŒñòåËç΋âyþ®»îÊÎΦiº¹¹yþüù—/_Öôõõýøãýüüxžw¹\dÈO<Á0Ì| ÖáÌÏÏ'EŒJ¥JOOß»wïøñãI‰ÃqÜ?þ(…óìóÏ?OKK‹ŒŒ”ÉdS¦L!áååå‰^XXXXXY>yòd[[9TPP””D #¥R)îSÌüü|ÒBëãã3nܸ#GŽyÅápˆÛú݉Ë媨¨ ¹Õj=~üøÝwßMQ”ŸŸ_DD„ð[D‡£¶¶–Ü ^¾|¹©©iäÈ‘!F#bTÇ544S\\,ì¥+W®ð~ü8y¶ŠŽŽ&g]ßÚEÅb.q«\à ¼GÊDL.}iÅ_[gâ8Ž r$q }ØÜ9tèyr={ölKK‹Ø¡ý*,,ìþûï'Ùl6µZMÓtNNÎÑ£GEjm2™È©‰®6“’Ã:sæLó®]»L&“¸q=z”e¹\~ï½÷ GÙ=‘KPHHˆ{˳¸Á –AK.˜t[¨’>ZÇ‘ÈX– @‘ר ¡Ýüþý&ÆøèÑ£¤ŠÐ©:??_µ·¿æñçÍ›G:²Úl¶uëÖ‘!öaaa=öXnnnoûµz6††† .ÄÄÄP•””4bĈšš„PFFFvv¶{õ³±1ÆÅÅÅ÷Üsé|K+((ÎQ&”J娱cIwÀÀ@Ò¥!d±XJKK{~¬.Ân~¼Wíá°WQá«3BwjµZhëîÔ²ç.BáAÌåË—›››ûö;žzD2 ÉÅ}}ª¡(Šã8F³aÃ÷ÈÈWiNè°ÿ~¡–€²X,ÒéI˜•••ššJb;tèP^^^vv6)ʧNzàÀÑçÛ½{÷’%K(ŠÒjµk×®=qâ„F£III!ÕĪª*‰ÌwèÐ!’›IG «ÕzðàA‰eÃ0úÓŸN:åp8âââHCB¨°°Pô) ͘1cΜ9dùÅ_¼pႤNÅäääeË–‘K877wÇŽRo’‹Çz|q×ÑÑAšìȤ-dê„Ífëèè:tIÇÙ³gÝ ëS§Nõm|žÇ©Õꜜrãc·Û¿üòKŽãvìØAÊD•Jµ`ÁÑûïÛ·oïÞ½ä¤ üÝï~—––F’M{{ûæÍ›¥p !„Nœ8áÞºxúôi Þ–ÕÖÖ*ŠÔÔÔÌÌL! 666nß¾ápB]ÓªSH‰¦ìÈIÁ $Õ[ZZ.\(—˯½n)Šr¹\}®eŒñ‘#GÂÃÃÉ!—Âøúè£7’e)ì7Á_þò¡çÆø§Ÿ~JLLT©T&“Él6Ka7®\¹R8åÜh½ð Bäƒ_gö[§¨~øa²àÕ7ß|óÝwß‘eѾpƒk2™$òìÀÝÁƒóòòȲèûJ0ÉÅ«g޻馛È\¡ãÇK§ ª«H¤¡€ÖeeeeeeHª3?Ip¿³ÙlGŽARÚÒ<»Úúuûž®QOEDD端¾’ÎQHj_ &/M„'N;vì¸qã|||B,ËîÞ½[‚çåP»ÎS`Ocjµ:44!TUU%ú{Ê€;/M„éééÂìPûöí½&`x «¨¨ iz×®]’m¥ðNG88<;nfĈB玃~ôÑGýìw4 c<"ì?ˆ°ÿ¼9Âòòò+VÜp74Ô÷¡D È8¡eÆ ÑÑÑv»½²²²ªª îÎmH¤ï䥉ðüùóÂÛXàÔo楉’B*ïD‰€WƒDÀ«A"àÕ¼t¡Ç õ‘=aO@„ýößPP"Ü#„!¯‰€WƒDÀ«y`@=Ïó6›­‡-ÂE©Õja¶k +=Ì/ýÌ,žI„õõõ=_?<<¼ÿ0ìõ<¿ô'³x f&—Ë…·EßEQ Ãô£î†V÷$i‚û"ì?ˆ°ÿ¤a¯ô0¿ô3³üføÆØårÉåò^ýÃ0©©©=¬“r×ÚÚÚÛw¹\®®Ž.ÆØn·«Õêž'cÃwSy‡{"ì?ˆ°ÿ Âþ»a„½Ê2=Ì/½Í,rÊo²(ÆX¥RùúúÊdšŒÛårµ´´8ŽëZŒ±¿¿TT”F£üØ›ÍV^^ÞÜÜ öDØaÿA„ýwÃEÏ2׿”ÎÕI’$%U¹&±vsƒƒ1¦(JĘÉÖ!Âþ€û"ì?ˆ°ÿz!5Ë\›S<ÿÄB`¯‰€WƒDÀ«A"àÕ ðjŒˆã.ÑA€WƒDÀ«A"àÕ ðjxµÎóÇÆÆJjRŽãÊÊÊ._¾ÜÕ ¢Ç<Ô#ŒˆˆÈÊÊ’Ô+G|,ËáØÑ#55fŒ±Ëå2™ª8Žs8Bº6BIí@¤ «{GI],â–‡S§Ýç¾-‹ÅrðÀþ–6Hªû†O y<ÏŸ9}*yÜø´ôÛëjk¬V›R¥T«Õ¥%P ˆŠòr÷”fw8D ¦ÿ õõõù‡GFFÞÎ02–u564Š`Ø*--éôɾí†D8LX,m§NtÿdHŸ—)fÅ $Âác˜š08 ×(¯‰€WƒDø? …B¯×Kªw/€æ]‰¦iæzd2BèÍ7ß½®®níÚµÒy ÊôéÓ†¡(ŠeÙ¯¾úJjyÚÄÅÅéõz___ò§Ýn¯©©)++Óétý¿»Ç·µµ ?Þ7 Ã@SÄ‘ÂGì(†%K–466~öÙgý¹ùë]"¼ï¾û|ðA£ÑØÚÚšŸŸ¿iÓ&»Ý>mÚ´¬¬,½^o³Ùž~úiŽã~ýu™ìÙgŸ½í¶Û|||Ìfó–-[ŠŠŠH¸jµzáÂ…ééé>>>—/_Þ¹sç®]»ô6–㸺ºº¶¶6’B0ÆätÄ«Õj«ÕJþ¤(êÊ•+/^¼|ù²ð‘‚¬¬,á™3gL&“Øáx#R„•••!„ÈMÙƒU¦IDAT}DD„Á`8}út§Dˆ1&'XÏ‹<£Ñ8f̘úúú+W®ôäwºßù’¢dÁka<%00ðÙgŸU©T¹¹¹}®ô">üðï¾úªL&kkk‹MMMŠŠZ¶lYzzú¬Y³ÈÕXSSãþO6mÚ”‘‘Á²¬ÕjÏÌÌ\°`Á‘#G0Æ~øazz:˲ííí£GÎÌÌôóóÛ¶mÛÀåB§Óù÷¿ÿ½«o)Š":îàÁƒyyy’jMHHˆ‹‹#;yÿþÎsúÁÔÒÒB^÷HQTcccLLLLLLUU• ­VkSS“Z­v8r¹<((ˆ8³ÙLÓthh(YeÙêêê   ½^_WWGÓt```}}½ÙlŽˆˆ jkkÓh4ƒÁ××WÈyíííÍÍÍ*•Êf³i4š€€÷tH¾U*•V«5((H£Ñ âî=RPPW±Güßÿý_rrò’%K Ïœ9Ó·½Ú‹ÆiÓ¦Éd²o¾ùf„ +W®DM™2ÅÇÇç_ÿú×’%Krss;E0iÒ¤ŒŒ Žãžzê©ÌÌÌcÇŽ©ÕjÒ%999-- c¼páÂÛo¿ýË/¿¤izÖ¬Y}+“É”J%ÏóÓ§O?yòä›o¾‰’Ëår¹œã¸âââ+W®œ;wŽçy™LFžÆIÄŒ3H9ër¹þûßÿJ'C{3Œ±ÅbinnÖëõ>>>äC›Í¦×ë§N:}úô™3g&%%ÙívòÕĉ322„Œåçç7uêÔØØX„Pvvöøñã)ŠJOOôÑGišîè舊ŠzðÁg̘1kÖ¬¨¨(¡•ÞjµúûûO:•|•@ÞfN°,;jÔ¨™3gNŸ>ýÞ{ï5 ’jØ!ŒñW_}‰Ð#xžßºu«V«}æ™gúܿ܋²þ7ÞÐétÕÕÕ.—ëÀc¹\zöìÙ3gÎøûûwZ_.—8p ®®®°°ã8“ÉtË-·"„.\¸ðÈ#pwæÌžçÏœ93kÖ,¡(8N§“¤“èèh¥RÏ0Œãêt±þóŸ_}õUÒ!Ðf³ t0½"´‹ž:uªººZìpÀÿttth4­VK•^¯=z4Çq¥¥¥&,,ŒeÙÆÆFŠ¢hšîTöÑ4MnþÌf³^¯×ét—.]"ï ‰ˆˆ ill´X,ƒ!**J£Ñ??¿ØØXŽãÊÊÊT*ÕÈ‘#Bõõõä Ñjµ:Îd21 3bĈ¨¨¨ .@CœDð<ïr¹*++‹‹‹!öÐ÷߯Óé^zé¥C‡]w§íÞ½{ÕªU'NÔh4Bw¶^éE"<þ<º:×üùó)Šª©©)--íªv²wïÞ}ûö!„xž7 &L (êôéÓ¡¶¶¶'N „f̘a0üqŠ¢öîÝ; g†R©|þùçCCC¿ûî;’ç:::âããüq›ÍFz둇.<Ï3 cµZßyç)dĤ¤¤èèhRÌýüóÏpýH ¹‘"7X<Ï5Êétž8q‚ôÉr:ÁÁÁ­­­¤5µ+ÍÍÍ2™L§ÓY­VòŒ0((¨½½ýäÉ“æÊ•+ Ãèt:ÒŸ9,, c|þüyré)Šèèè––’íœNgEE©r¨×뛚šaW€úøã7oÞŒ‚jzÏëõz¥RÙÕ ‡£¤¤$555--mß¾}}(!{‘…_ÿÃþ°`Á‡Ãñ׿þµ›ÃIדå5kÖ„††VVVnÙ²Eè«‚zå•WÈöS§N½óÎ;ÝâGnÀ…þ¢!rŸîþ9É7­ºLŸ>´Ó:Nh•r8Èi£ÑhT*•Ýn !ß* …B¡Õj[[[{õ³.—+888&&¦ººº®®®¥¥…t(Õh4J¥Òb±§ÁÅ‹„DK†aeÒdªP(<ðÿžo¤¤¤ „H[Ý¢E‹T*ù¼¨¨(??Ÿæäú"ƒß6=öØsÏ=×ÑÑñ /tUQíä…^˜>}zssóòåË;ï½÷žÁ`˜6mZbbâk¯½¶lÙ²;QÇ›o¾É0 ˲K—.EétºsçνôÒK]ý‰œµYYYdáÔ©S0\Zj„ÎÆ!¥RIQ”ŸŸŸû·r¹œ,÷ü­¬¬t¹\ááá±±±6›­ªªÊd2ùøøM8Ü^ÿær¹\.× # ÙÙÙûÛß:Ýý»\®””Ñ+¯î,Z´H¯×“å 6üòË/äš²X,¡>?_ëu"œ0aÏóû÷ïÏËËëIžxüñÇ-ZÄqÜš5kNž<Ù© ضm©nܸñž{îY±b…c _ð(“Ɇq¹\.\`Y¶¤¤„eYRH9Ž5kÖL™2eíÚµ»wïV©TdÄôÀÓCãÇŠŠ"eÙO?ýí¢’ÂqMÓr¹œ4¡“?kkkó>HrÔH«»ða7—ÆØl6[,N§×ëÂÃÃU*U]]i·woh%Täӆ††aT*U§SH‚sß¼öÚk¤ÄF={V(I³G÷w„Ýèu"\ºt)¹±íIÌÎÎ^±b…\.ë­·¾ÿþ{áŸÌš5ëücssóÌ™3m6·À0Œ\.ÐD($¶;v^[<Ï“-Ò4’’”°gϧÓ)ú}qß}÷‘ÓÚE%Âår‘‰œ9‰‰‰E577#„ÚÛÛe2yªGî[ív»Íf BÑ4-“É,‹J¥bYÖýÙºZèØív–e5Mffæ¥K—šššH_›Q£FÆúúz‹ÅBžVTTèt:Žã|}}“““Íf³žgƒ!ª½½½¢¢¢S"ìþÁ¶(vìØáþ§p‘Ë­¡¡¡oU…^'Â×_=55õûï¿ë­·º/”#""Ö®]«Ñh,Ëí·ßNÆK „/^|ìØ1…B³}ûöÊÊÊÌÌLš¦ ôJV( .Ôjµ$l2Bc¬R©vìØA¨tttdeeMš4©¡¡á“O>ú¾‹%33“TOœ8qéÒ%qƒèê™CúdÞtÓMJ¥²¤¤D¸üš››FclllUUEQF£1$$¤¢¢cl·ÛBCCkjj|}}Ýo`9ŽS*•*•êòåË2™ÌÇÇG«ÕÚl¶¦¦&ŸÀÀ@¡e•l"22Òd2i4šØØX¹\.ú‰ †´C‡M›6íÚÏ¥P¸a¯Q„PHHƘôÁìƒ^'Âàààððð€€€®d0Bz½>##Cø\¡PTUU­X±bÉ’%IIIcÇŽu¹\ß~ûí믿> ;a˜Q£F S¬ Ÿ“)Öt:ÙÅãÀÀÀ¨¨(µZ-zË@JJJdd$YþñÇ¡]T\Z­Ößßâĉ!Œ±Ëåjmm-++sÆg2™hšŽŽŽŽ‹‹CqGÆNÖNµZ˜˜HR`uuuLLŒÃá ß666Ž1bôèÑqqq………áááééé!Š¢,Kee%9ÈЈ›o¾9>>!d±XÊÊÊÈWƒÁý¦ža???§ÓÙ·À{`Œ¥ó®ë†½F#"""##+++KKKûvžÿæ):EQÝ?ZzWvª’î—ÈíBø¤²ù6$$$((¨¤¤Än·wÿȤ«y„{³{ð]}EQÔŽ;6mÚôöÛoÓ4Ý«™e<a'¯¼òJNNé1yòäúúú>üH÷Ru÷ÝwCŠžèj2³kWcF«ÕbŒÛÛÛÝ›@É‹M”JeGGÇqÂ$·:ŽeYÒ4BQihµÛíN§Ó}Cä+RetÿªÓ^÷Ð žç»ÇÕŸkÙƒ¨´ñ ÏF(ŒMê긬Y³fîܹo¼ñÆ'Ÿ|ÒÃB»S„½®vµ™ko(º¿Å ßšÍæšššÁ¼J¯{ÈLÖ&“)!!Ád2‘þƒR7„‰HŠ‹‹;õ¿ƒ¯‡'*ƘeÙ뎗À;áAx§$SÕ¸ÿI*×ý—ËÕÒÒrÃ!‚¡®ûªjZZÚÌ™3?¾uëÖÁ˜kt€ æ…ÚýnZ¾|ùêÕ«ÛÚÚ0ÆRè/š––FæœDÐ_®ç©§žª««[¾|yŸ»Œ")$Bé°Ûí’êq0eÊÒ–k·ÛwíÚýE “wß}÷Â… îÏéû¡t ýE;í¢p-÷Ñ„}‰P¢ŒFã±cÇHoà~øªƒp-<3‚D(QõõõÂÜoF^ð H„Òµ@09!¯‰€WƒDÀ«A"àÕ ðjx5H„¼$B^ !¯‰€WƒDÀ«A"àÕ ðjðö ÄB¡xæ™g(ŠÚ´iÓÂ… Ý>øàƒ®^é‰ Œ1EQbG0räHR ]»Ð•ß$BŒ1˲r¹|@£ì–e»z3­DbºbŒív»Z­†\¼ÆØf³u¿‚”¯e"ät:W®\‰âyþÚ…®"ì\ö©Õj???™LB5E—ËÕÜÜl·Û»ZAô˜‡z„QQQf£@Rl6[yyù•+WºYGâ×2‚{àÚ¡Bªƒ „ºªÇCÄÿDƒ-â•<äyIEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out-thumb.png000066400000000000000000001414241445075545500260120ustar00rootroot00000000000000‰PNG  IHDRÈU%µ7àsBITÛáOà pHYsÄÄ•+ IDATxœì}y\[ǵÿèj—І$bˆ}ßw0Æ€lã½^ã%v¼7q’_š¦M>yi>ïµNÛ´~mö8Ië$Þãƒm°›}»Bûvœ<•‡—$¯v¤úþÁg4wæÌ™;ýsg¾ç„\pá1€8ó7‘ÈårM&“3'00Ðd2Ùl6„Fó÷÷ÿ—êè¿<Ïb±à8búHý=E¤ÒÌ£C¸Ýö}åfü–H$¡¡¡ƒƒƒµµµãååµvíZÇ ŽãçÏŸïêêz=pᇃtûömœH Ùùz°·HšWwèUM]%Bˆ“4›ÈâjÎq& 7­È65ŽQèdw‘©¿Kß\ƒ¦ËÍÎÎf±Xccc©©©ÎÌY³fùøø ‚¦¦¦é—\ø)L&{yyõööÂO"†mIv£þãÑ3yó…ï9=Á ‰'2X i™Í§ùûŒ‘ …ÿ×ÄR©T‰$22òôéÓÎL‹Åòì³Ïž={V©T~ùå—ƒƒƒ»‡.üëaX@@@ww·3Çñ«=ÃV»ã!µô­·„ó7˜‡T‘¡³Á=·”èÆ…KÿëU¨P(B2™lz‹åÍ7ß4›Í8ŽÿùÏnkk{”rᇀ€…Bã¸3Ç£J…zÜhž^ÌYÌø‘SïÓ|¤4o©U£¦zIô-߬ 3ÈÌÌ z÷Ýw94-::šÇã!„&&&ŒFãcèš O |>ŸËåšÍf„Fëîîvâü¥ áHSwÕ8¨üN‚ˆDd·?^]]ø7ðo/å‚ .¸à‚ ?YÌ\¼#„2V=‹ß/:ÆTm­W=•\ø)`æÎ;Bˆái²#„ #àÙß|aÒ)$“Å?°)ׇ¡ Ã}&–Ýj¶Û¡…i2_ÛTù Çq…´=VøÌéÎ)“!ä°Yþ媺ðcÂý&–Åì°£X^Úço£¡Á8î0È~~ãït?³zóoÉz“ÍñýO%]ø·ÂLvBÈ'v–7±SlÃûTg³ |>îæ†»»» Åg]jÔ h PöTÍfóÔÔ”SÈòåËgH&f.Ý­Vkrr2HÀ0,;;[, Ù][m?fÜgËn5Ç2,ŽQõعs#ÇŽž:5úõ×#ÇŽ=«mnfuµ h»ÕY~ÇŽSSSo¾ù¦P(äñxl6›Çãegg§¤¤Ðét Ã’’’„Babbâï~÷;*•*“É niii@@€SBdddvv6“Éüÿïÿý‹n€ ÷FtÔjcø©œ?ÿ·|³œ"ûúnÛÇ~õ…Èe›¯Úþ1±(Š———^¯¥ÓéZ­–ÃáŠD¢_þò—£££J¥rûöíü1‹ÅŠŠŠZ¼x±Á`¸råÊ¥K—fH°ÙlÁÁÁ$©¯¯ïñ÷݅Ljû>±L‹Ùd³½­4¬ßf!‘ÌÙ½½¯-Zÿuû°Ùf³ÚmÓŸX&“I¡PÐét€a¼ïÚÚÚŽ?. ƒ‚‚Ž9ÒÙÙi·Û{{{årùW_}uôèÑ„„„{%`vñâÅ_ýêWÓ¯ºðcÄý¿ ›ýɦëÖVÚ„‹7oÑ8n_·±²Qcw8&KJ[L¸cÚK§Óݹs§««Ë`0¬X±brròÂ… /¼ðBGGG__ßË/¿ìééÙÐÐðôÓO9rdçÎV«õí·ßF9Ç<==³³³Ùlöððð¿î¸ðpŸÐÈ’mÖÿY7oå…cC£óËèÏï¹³~OEû0€pM uõß.¿·.N·X,°îf³ÙZ­!Äb±ôz½Ãá`2™z½žJ¥bö Š<ð¦ó7\ø1âþk,»!„#D0"‚Ãn´(ÓY,£Ùl·~ÃΙþÄšŽéÓfBÈùµ¨×ëB@Ïx\Sê§ûL,›õë„ÁÅ•)›»s–·u Ø­ßl_¹ö±\x8î7±Ì'u`ȉÛͺéeÖ‡=u\pÁ\páÇ‚ä¹?=i\ø ‚pß\pÁH¤û|Þþñ“éÈOÄD‡F£=i ~2ù‰L,~hpM, \Ë…Ç‚ûP“<==½¼¼¤R©V«7Ïé…B±X™}…BINNær¹"‘H(Žûûûûûûëtº¨¨(³Ù,•JE"ÑÈÈÈ£jÔÙô£ê™LNNNžœœôõõT*5<<úB£ÑÂÃõZmtt´¿¿¿ÑhŒŽŽžœœ|„÷ð1nbmÞ¼9))I¥Rá8.‹ívûŽ;S[nnn:îÛË}7ˆÅâ7ß|óí·ßÞ¶m[MMV« ­¯¯OMMmmmµZ­ñññL&S¥R?~üƪ]ôH;²zõj__߉‰‰ˆˆˆ¡¡!ƒÁ€ã8ŸÏwwwoll´ÛíUUU©©©ííínnnŸþù#iý ^…¾¾¾F£‘Ãáü¸ø0nnn$Él6_¹rÅÏÏ!T__ßÓÓÃ`0®]»æp8(ŠX,~8èÉâÎ;6›-44´¯¯ïèÑ£‡C"‘ ß° ¤Ré‰' S—/_¶Ùlžžž°õÇø*d³Ùz½þðáÞžžv»½©©©¡¡á1µõh_…$I&“FƒÁ|øða"‘ØÞÞŽaØ… Ö¬YsãÆ¾¾¾Ï>ûÌÍÍíÑÒóaG¼¼¼BCC¯]»Æápärù;wNž<)úúú Å™3gnß¾M¡P0 Óëõ¡¡¡ÍÍͤéŸÜÜÜž´ ?™Ž¸¾ ]x,pM, \Ë…Ç×Ärá±€àž·äIëð k¼nQ»Œ§@ ÄŸîÒ:<tÿǶñÊSOZ‹Gü§A½$UyÒ:< ‚•OZ‰Gó ’êåÿ¤µpÁ\pÁ\pÁ\pÁ\pÁ\pÁ~ˆH*zÒ¸ðBb!úÆ£_X ú.ü3¸Ïl°Z­QQQ±±±===†mß¾]&“ X­V"‘h·Ûi4šÝn§P(»wﮪª‚•¼žh4Žã >à'™LÆqÞP³fÍêéé¡R©6›J¥B›ÍF"‘t:·Ùl …H$j4h {ã7âââZZZ Á®]»233[ZZL&“X,Þ¼yó¬Y³FFFººº"## JKK/\¸€Úºuklll```ss3BhÆ nnnR©4//¯®®î_w³ÿ@*,,”Ëå§NÊÍÍ=yòäðððöíÛ¹\n[[Û¯ýk£ÑréÒ%_üâF£ñ³Ï>›7ožB¡—H$¡ØØØââbÇ5ŸŸ_?Ì?»Ý?1 ëëë‹///ߺukhh(“ɬ¨¨Ø¶mÛ±cÇââ⪫«u:]UUÕæÍ›y<^EEÅúõëmµµµ}úé§!OOO£ÑèááK:‰DrôèQèÆÀÀÀ¥K—¼¼¼ZZZBwïÞõööV©TpU,¿ûî»O=õ¬ÿ$‰——@˜ñ€tás86›ÍjµêõúW^y!$‰N:%‰¼½½GGG[[[i4ÚÀÀÀøøxffæÄÄNïîînllD¥¦¦~ðÁ`C¥Rñx¼³gϺ»»;–——{{{Ó¬©©I$}ôÑGéééÝÝÝÝÝÝ4íæÍ›!___¸4½-Nïå±±±ŠŠŠììl‰D¥R?ýôSxMñG"‘ŸÏOJJª¨¨€—5…B‘H$„Ÿ*•ŠJ¥„ÁÁÁ'rÓÿ@ìêꪩ©Ñëõ ãÏþ3BˆJ¥B0 «Õ:>>®T*U*ÕØØ˜Íf¼páBHHÈ­[·|}}q¯ªª^¶l™P(üâ‹/ÜÝÝ›››{zzBuuuΟžžžV«Öà°‰päÈÇGGGýýý …··woo/B(//.9Û2‰¤½½=::"s„‡‡·´´¥R™ÐÞÞN&“M&SaaaGGG\\N—H$YYY7oÞ¤R©åååz½~ëÖ­555ãããcccwïÞ…‡Ÿ ?Dp8œÍ›7gdd<&ùnnnÓÃC>ü§@ ˜^÷á?]x| fff&%%MMMÅÆÆ*•Êû‚2V«Õùÿ½xñbXÍøùùåææ¶··‘Éäï`¶„BaNNŽB¡pww_¸p¡ÙlÖh4Ë–-‹ˆˆhjj¢R©D"1''‡F£ „ 0ŒøøøÌÌL©TÚÙÙ™“““””{c+W®”Éd½½½T*•ÏçGDDôõõeddÈåò¡¡!‘HTTT$àÉŠ*--…î „V¬X¨P(222î{Cœ}H$’   ïÞñ7lØpúôé 6 s8œyóæñxŸÏ`0¢¢¢ŠŠŠ ÅŠ+òòòªªªBK—.µÙl¥¥¥,‹Ë庻»^ºtéIå NŸ;wîÔÔTbbbPPеk×ÒÓÓ ®\¹"“ÉàT„ÉdŸ={¶°°ðïÿûÒ¥KB‘‘‘‹/LKKc³Ù"‘ˆÍf …ÂÅ‹9r$::!䔹yóf@ñóŸÿ<''G&“±X,*•:44Ûñ†©ÕjNÒÕÕÕÕÕ%“É&&&öîÝ;>>M"‘X,Ö­[·H$œC›L&‹Å¢Õjq‰DD"¶d2Yllì™3g4M@@ÀÙ³gŸyæ™Ó§OïÝ»wbb!”™™©T* >ùä“ââbØq}á…Ìf³D"ÉÈÈILLŒŽŽ.//_°`››ƒÁ ¾ñg }q8„Sç%˜Z­~ûí·)ŠÑh4›Í‹E¯×k4šùóç#„²³³BÃÃÃ~øá… ÔjõÊ•+ëêê ÃÙ³g©TêÔÔÔÑ£G››› ‚ÕjššÒëõÍÍÍeeel6;++Ëb±€Ìºº:…BñÁà8n2™._¾l2™ÔjµH$Úµk—ÝnoiiÙ¶m›ómåééi2™²²²B‹Çq£Ñ8{öì””xœäçç3™Lˆ“¶`Á‚}ûöÆââ⬬¬ššš¿üå/ƒ!++K«Õ9rD­Vß½{!”ŸŸO¡PNœ8ñþûï×ÖÖ®^½zxxX¯×_½z5!!áÒ¥K7oÞüÓŸþýf³yllÌÇÇ'***88ØÓÓÓ`0@_„BáÉ“'“““qÿqÍ{bHJJzíµ×¢¢¢î½ä\)oÙ²%""â¾Õy<Þž={î=Q™¢=$$dÖ¬YJ¥z{{C‘HD£Ñ¶nݺmÛ6±Xìãóí?<’’’B …@ @Ú©0”ñöövV™^}FÉ{UŠŠŠÚ´iÓýoBkÖ¬yóÍ7§?–œŠ‹‹TÑ…'ƒ±µ0 ûŽD®'Ž‹ž.¸à‚ .¸à‚ .ü„0ý“mÆçÛÃó¿û΃Ä:A&“Âëš^}zIgzF$í[ÕpáŸVPP@£Ñh4Zbb"‰D¢ÑhD"qçÎ$ Ã0&“ ó†L&3Œ]»vQ©T"‘ˆaؾ}ûž}öY™L¶gÏØ2%“Éd2™@ Éd …œ*`  &&&:ÓT*Ú‚¯*(?kÖ¬°°0ȇ IÈG1Œ;wBÔu"‘(‘HF£R©‰D$Í™3¶ â3Ï<#‘H<<<˜L&ì¾Iä „0 M˜L&†aÓ#“ÉÝa0D"qΜ9¡§Ÿ~zëÖ­³fÍz2#ö#iݺuáááV«Ã0.—ä÷]»vݽ{755µººº¼¼üù矇ÃW_}õwÞÿÛßþ¶uëVFsûöíääd„ÐöíÛ™LæÍ›7 BTTŸÏ¯ªªò÷÷çp8v»ýܹs±±±YYYv»ýÂ… K–,áp8o¾ù¦V«U«Õ;wîäóùÕÕÕT*õüã±cÇ€³àååÅçó?žíáá±oß¾®®®ÚÚZ???µZýòË/ÃV-Žã›6mºqãF__ßÒ¥KGGGi4šŸŸŸN§‹‹‹ƒ³?Ÿ††„ÐÖ­[Ùlv{{»L&›œœ äªU«:;;áL=66vttÔÓÓÓn·766®]»öâÅ‹~~~·nÝŠˆˆ8þü½0°¶¶¶¡¡¡sçÎq8&“Y^^ÎãñX,–X,g0𪬬¼{÷nOOÁ`IOO///g³Ùƒƒƒnnn! 4ïÞ½»¥¥ÅÍÍM"‘0™ÌsçΑH¤ãǃa¤ûûûzzzFGG™L&”G„îîîÀÀ@Fc±X ?%%å½÷Þ›šššœœLNNîîî¦ÓéT*µ¿¿4mnn¦ÓéSSS``È`0Ìf3—Ë=xð`||¼B¡HOO9!±XüÎ;ïDGGðÁ¾¾¾ œ2™Ìööv»Ý¢àFknn†ƒ„[·nÁŽ® ‘N§3Œ––Ç{{{ÕjµÃáèîî¾sçƒÁpwwïììôööS\\œÕjU*•D"6͇‡‡óòòjkk …V«mmm¹yó&E×××;Úl6­VÛßßßÝÝ=99éïœ\SSC$ ”¯««³Z­ÀÄjoo÷ððP*•G]¼xqggg}}½»»û7¨T*”èíí…S—ŽŽŽ__ß–––ÞÞ^•Je·ÛƒƒƒÉdòÍ›7ù|þ©S§Š‹‹;;;ž““süøñ TUU©Õêîîn»Ý. GGG;::¸\.Ü•Júóx

Ÿ?55E¡PÄbqff&,’–,Yrùòåyóæ…††Z,¹\žŸŸM&“‹ŠŠ¤Riaa¡B¡ˆŽŽ.,,ìééYµjÕ¬Y³FGG¸víZ(o³ÙÖ­[§×ëW®\i6› ¢££Õjõ–-[är9‹Å‚oX&“i³Ù6mÚ;00àááñú믷··ŽŽnÞ¼(V]]]t:}éÒ¥)))T*µ´´tlllýúõr¹üܹs999 .Ù°a‘HLJJr*&‘Höïß?44TZZJ RRR m6Ûo¼qôèÑ;v|ýõ×ÁÁÁ`#éÂ}555ÙíöëׯÇÅÅÉd²ÊÊÊÔÔT7gΰYpwwGEDD\¼xñîÝ»$I«ÕªT*¥RÙÝÝííí ¶Ñ‘‘‘ÙÙÙÐjµB¡°¨¨H&“]¿~=22²¼¼<===>>ÒóçÏg04­½½}hhÃ0(Â0ŒB¡dffÒéôœœÈ_ºtéáÇ CxxxiiéÀÀ|Ü1™L>Ÿ/‘HŒFcCCCdd¤H$²Ùl ,@ùûû“H¤¡¡¡¦¦¦M›6¹»»¿ôÒK !”ŸŸÿé§Ÿ®_¿þðáÃ………N%Ølvssóøø8ˆ‚K~~~ ‹å£>*,,d³ÙOtà~èÀ&&&€Õ©ÓéL&“Ùlžšš‚I¨Õje2YvvöÄÄŽã~~~~~~B¡ÐÓÓóÅ_´X,©©©ÁÁÁZ­!ÔØØxùòe‰o0L&“Édšœœ4›Íf³Y§ÓAzddÄÛÛÛÉprssƒò@›˜˜¨­­5 ÍÍÍçÎÕ«WÛíö3gÎÉd‹Å%'''§¦¦L&“Ífãp8&“I.—S(N§ÓéÌf3‹Å*++ãr¹·nÝêéé9yò$ÈA©ÕêÕ«W×ÕÕ­^½zppCMNNMLLƒ(§þ‡D"Íž=[§Ó±X¬'¸ußñdz÷…X,~ÈGßt­¼¼¼œFô&‰3º0½Ìƒä<÷= ‚L‘HÄãñ¾UÈ¿3ˆ¿úÕ¯4X,f±XV«544ÇñÕ«WwttP(”ÄÄDب”J¥žžžÛ¶m°Ûí$içÎsæÌMNNž={veee`` ‡Ã±X,~~~|>ŸH$3™ÌˆˆˆÁÁA©TJ¡P áççg±X0 ³X,ááá`NC$ýýýÍfs\\Üää¤L&ãóùééé%%%ýýýF£±Ùl»Ýêááã8‹ÅÚ»w/lº¦§§Ã×@kk+™LŽŠŠ‰D‹%::zdd$--­¤¤äÒ¥KB¡0&&fxx8--M¯×{yy9sssÛ½{wgggtt´N§ƒK&“é…^¸téRZZÚþýû E__ß“¾.ˆ .¤ÓéD"155•ÍfÓéô’’ƒ‘––f2™233­VkOOÏ /¼P]]••%•Ju:Ý7âââ>ùäûÊÊÊ;vÌž=[*•ÆŒŒŒ²²2›Íæææ¶páÂÉÉI??¿ÌÌÌÔÔÔÉÉɰ°°‚‚‚””” .€öªU«ÊÊÊZZZ ÃÆÙlvrrrtt´ŸŸ_YYFs82™,::Z.—ß¹s'..ŽH$®[·.""Âh4bïéé©T*³²²òòò‡Ãá b±866váÂ…yyyýýý2™¬¢¢âùçŸ[°`F£Yºtirr2lÛnܸÇñ€€€®®®¤¤¤¼¼<¸$‘H‚ƒƒ¿þúëÎÎΨ¨¨Ã‡?é±ûAg§¡\kk«ÍfT‹¥··7**J"‘ètºÞÞ^«;]”× IDATÕj6›ÁŸÖK/½tæÌ™ôôô¾¾>8¾lnnž;wn[[[pp0úÂ\illç[f³Ùf³Ùn·Ãj†Ëå:Ë#„T*•Ñhloo¿}û6äÖŽã7nÜðóó7Z`#ޏt:Á`Àq<55Õn·;E„‚‚‚£GZ,–ŠŠŠááaƒÂq\§Ó9£Ñˆã8(ÆçóoÞ¼™ ÑhA\‚2.£‰ï‚¯¯/ŸÏokkF£Q¯×  ×ë)JHHHCCpz{{ãããGOOÙlމ‰A544ÄÇÇ·´´¨Õj‡C ¸\nOO¸]ÒétB¡pdd„ÉdÂüƒô¼yóæÌ™³cÇ“ɤ×ë¡|¿ÅbáñxCCC™™™mmmííí©©©===¡¡¡$éäÉ“îîîP!¤×ëÍfsXXØèèèØØœ‡- Ãär¹ÙlV©T‘‘‘µµµàE§§§G$Éåòëׯ§§§766ÒétP, @§Óéõz777¡P¨T*q‡K‰äöíÛàìÄéqÄ…oÁt×+rÃrßüïÎÇš^=,,L*•Î(ðp>N šÍ}ùX3º¼ïØ -ˆEEE$)>>¼Ê8Ž={öܸqƒ@ ¸¹¹Y­V„…B¡Óé;w­Åqœ@ ìß¿?++K­V¯]»ÖÏϯ©© ÈRà‹L&ƒã*• \(Øô‚ôÔÔ”Ó¼g‘H¤Y³fQ©TxC1™L«Õ ùv»ÝÍÍmÇŽgΜÁqÃ0‰DB$™Löóó£R©™™™@¥R¹¹¹Ùl¶={ö /$0 «Õ r®]»|,ȱÙld2£ÑhaΜ9J¥’Á`8/Ùíö¢¢¢ŽŽŽùóçÏŸ?ß××·©©é‰ŽÝ¤Õ«W‡„„X,‰äîîîççw|Ïž= ©©©UUUçÎ{þùç/^¼˜ðë_ÿúwÞÑh4‡~úé§Õju]]0ì¶oßîæævóæMÇ###…BaUU•¯¯/¼¶ÎŸ?—mµZ/_¾\ZZÊåró›ßkÇŽPžJ¥þá8~üx|||GG‡‡‡‡P(s挻»{?ð±Ba×®]---' €Á`TTT`vâĉ€€Øm:qâD||üÀÀ@¿R©>” ]]]þþþ###F£ò“’’>üðCN7>>ž””¤P(œ|,F|¬––ßàžN§›Ífww÷ƒÆÆÆvvv&''ƒ„——×ûï¿ùñÇûøø€bAAA …‚ÅbuttÀê>((.Q©Ô––«ÕZRRRUU‡ .<D*•J§Ó[ZZð±ìv{WWWCCNwwwooo‹Å£££]]]ÑÑѰ÷/† åååݼyS©TNNN¶¶¶×ÔÔDFF*І†¨P(¬VëÄÄD__ŸB¡÷óóKII>–^¯ŠŠR(õõõcccf³ùâÅ‹¡¡¡ííí@¡P;v¬´´´½½ýîÝ»\.÷Æ J €û.±XÜÞÞÞßßïëëÛÜܬR©€%“ɨTêõë×Á©S§ŠŠŠÚÛÛ[[[Gvvö±cÇæÏŸíÚµááaPR(ªÕêööv‡C§Ó›››•J%\âr¹ YYY°0èïïÒÃçÂ=X¸páŠ+¾o-x>}\xÄpòЦ“™–-[voI æ3™ ‹‹‹ÙlöêÕ«äÄa¾••˜˜åûÂîåc‰ÅâéòËÊÊÄÇš.çA¸/Ý 2sssËÊÊBCC¿UÈ¿3ˆï¼óNOLL‚@II‰@ ˆ‰‰¡ÓéL&sÍš5z½~xxxùòå^^^k×® …Z­–B¡xxxddd(ŠÑÑÑE‹]¾|yþüùaaaV«U.—Ïž=;&&†L&Ëd²ÂÂB¥R)‘Hbbb ½zõêüüü‘‘ØüÇZ$Éf³mܸQ§Ó­X±ÂjµÎ™3'&&øXAAAðz¢R©nnnv»ý©§žŠ‹‹‰D¯½öZggçèèè–-[ˆDbbbbww7F+++KKK>Öøøøúõ냂‚Î;———·páB`hU§b‰dß¾}ÃÃÃ¥¥¥p&QXXh·Û_ýõ£G®Y³æoûÛöíÛ+**žôðýp555Y­Öêêꘘ©TzõêÕääd7{öl FÁ«',, øX†kppv===!DxxxFFÆsÏ=711!æÌ™#•J«««ÃÃÃÏž=›šš éùóçS©T …Ÿàf Œ«€V‘‘qM É’%}ô‘Á` Y´hQ?°wh4Ç 0 ááá"‘Ö×!???‰4<<\__¿aÃ.—û /€„P^^Þ'Ÿ|²víÚ?þ¸  KOO÷õõe±XMMMµ¥¤¤.ùúú‹Édž:uêIŽÛØøø¸X,6™LSSSÀˆšœœìééQ(ÀÇ ÌÎÎÖh48Žûøøøúúë¹çž³ÙlÉÉÉ!!!ããã¡;w6°hÐétF£Ñd21K«ÕBzxxX,;ùX ʃ#5FsóæMƒÁÐÒÒùõõõkÖ¬±ÙlgΜÁ0ÌjµBɉ‰‰ÉÉIˆÂf³ ƒL&£P(Z­vjjÊh4º¹¹•––º»»×ÔÔ¨Tª'N€„ÐàààêÕ«oݺµfͰö1™L‡C«ÕJ¥ÒñññÂÂBåÔŸÍf“H¤þþþ?þøêÕ«Oxè~à€'ă®Î $Ý—åd)=¤â½X½zõ믿þ>pžœùÐÊæÍ›´¸ùV>œ®íÿ™å·Ã9Q¦Xddä½% ÂôEº@  …†ùùù}ÇC’oµ¹ðññyÏiºVÓ™[&‘H3ºð v×}{7÷%?B&›Í3n;ù! ¾úê«ãããÞÞÞL&Ón· nåÊ•]]] %99y||Ül6{yymݺuhh"”lÛ¶ øXqqqsæÌ©¬¬”Éd\.×b±xzz ß1™Ì¨¨¨‰DB§Ó! ¤ ³ÙL$-KTT”@  Ã0L*•šÍæ„„„ÉÉÉàà`@011‘••5oÞ¼àc±X,‡ÃfÊl6{ÿþý}}}ƒƒƒYYY:nÍš5mmmd2966ÖÓÓÓb±ÄÆÆªÕꌌŒyóæ]¼xQ$ÅÅÅ geeéõz Jƒb,kÏž=±±±:.™L¦_|ñÒ¥K/½ô’O\\\II‰ËúA –””À» -- 6ÙKJJ˜LfJJŠÑhLOO>Ö*++³²²$ÉÝ»w§¦¦€)ðé§Ÿ»»»WVVnß¾=??_&“étºôôô²²2«ÕJ£Ñ.\¨Ñhüýý322’““5Mxxx^^^RRÒùóç­V«Õj]±bEYYYss³Á`X»v-›Íß²>>>ÀÇ‚0™QQQr¹¼¾¾>..ðŸýìgaaaZ&R©ÌÌÌÌÍÍ>BÈÓÓ3**jÑ¢E¡¡¡ùùùÕ¬¢¢âÀCCC‹-^ºtiRRxÂ]·n°û;;;sssí(‘Hd2Ù×_šš Vã‡Ãå,ùAÀ4ÃáhkkƒßíííÀ¼ƒ`8}}}QQQR©T§Óõ÷÷Ûív8&‰/¿üò¹sç222à\!400ÐÔÔTXXØÞÞ |å¶¶60‹ÎŒÑhlnn†Íô?Äàc9ùÍ}}}ƒ¡³³øX4 Ã0›Í†ãøõë×}}}ƒE †††Àõ¼^¯7™LÀÇ‚ ¯ ŠH$:uÊd2]¸p¡¿¿ä „€pf³Ùìv»Ãá%ÝÝÝkkkÆÇÇ“““Aè >yq¿sçŽÃá0™LòÉ…û‚àíííîîÞÑÑÁçóLvƒÁ@&“® |¬þþþ˜˜‡Ã¡R©Ìf3¬Tššš¢££ÛÛÛGFF`ÍÁårU*UZZÚÄÄ8$ccc`Ë‚ôüùó €e0 ¼3R°Z­NMMíèèH$IIIJ¥üíž>}šÇãAI„|̆„„Œi4š¨¨(•JsÃ0™Lf6›ûûûÃÂÂêêꢢ¢”Jeoo¯P( ª­­MIIinn¦Ñh ˜¿¿¿^¯>Ð%p‡K T*•Á`À¼ü^þMá ¯:#=03fà»ó±¦‹•Ëå÷n²S(”‡˜ 1™Ìàà`§Û#gIgzF$íA½sá‚8oÞ¼þþ~ …;88ÿ‹»wïoDl6Ûb± „àßtçηoß>Ähmm…§Îàà ¼"8µ>ø¦b2™f³999yhhÒƒÁÉôÅqœN§“H¤¼¼<*•ª×ëq*Fƒíx6›½}ûöòòr‡ÃA$`—„L&ûúúR©Ôœœ§R©Øl¶Õjݽ{÷ÐЉD"‰d2]‹ä\»v |BŽÕj%“É (\TTÔÓÓœ0¸d·ÛçÎÛÑѱsçÎÈÈHLJ††žðèý€AZ¾|yPPÅb!“É|>ßÇLJD"9ùX)))N>ª^yåðuþüùuëÖÏx%«¦¦Æf³mLee%PŸM&йrssÍfseeå¢E‹8Îo¼¡ÕjGFF DJee%•Jýýïâĉ¸¸¸®®.@ ‰Nœ8‘œœ þ±º»»¯_¿ V«·nÝ |,»Ý»ÀÇš˜˜ R©Z­Núúú¼¼¼š››…B!øÇzúé§i4šR©ôññ1™L|>ßl6_ºtiÕªU­­­ééé&“)..nbbB$™ÍæÖÖÖU«V9sÆËËëÒ¥KÎ8<.ÜXGGð±X,Nb–›››H$S‡¡P«««›šš€599I"‘àläüùó³gÏFA€†;w¶¶¶r¹\àc„“'Oúûû³Ùl ÃNž< ¦ZÀxa2™Pý üªét:È?|ø°N§KLLT(4B¡ôõõÁêgll¬µµ•J¥Âw†L&CÑh4‹Å"~÷»ßEEEµ··;å „D"ч~þé§ŸŠÅbPL&“uvvr¹ÜÎÎN Ã@\¢P(­­­V«Õf³) “ÉôDî‡"ðn›››m6›J¥R«ÕV«µ«««¾¾øX---b±ÜGyJ¥Â0,%%E­VŸ8q¢°°°ººZ©TNLL´¶¶ ÔÖÖ†‡‡ƒ;+¨P(Ìfóøøxoo/ð±À?ÖÍ›7å,?66f4/^¼þ±ÀA×ñãÇ.\ØÚÚÚÔÔÄf³oÞ¼I"‘4Ñhìïï‡ÙéååÕÖÖÖ××çãã„D•Je³Ù$ F«®®öððm[[[ÛÛÛ­VkVVÖÑ£GKJJ*++‡†† LÄ¡¡¡¶¶6p@ÒØØ\`bçÎOå'=v?N<î¨CóçÏÿ.ô•€胮N×ù'5éGÝâ¬Y³ ÌÐÈȈ3ðU«VA\«Ù³g ,X° **jºù@``àܹsÅbqgg'BˆL&Æddd$„b›7oÞŒ* £¬¬ŒÃá¨Tª¶¶6¸$V­Zuûöm??¿ùóç÷ôôÜ[Úb±Xåååàº!Äáp`jR©T¨(‹ÃÃÃ{{{ú?D™éïìrAAD"™î¶‚ÿDGGC¼'g•âââˆ`E¥R§[H—––¦¥¥Iœ3ÊÃÇŠ\.ŸýP.—ÁáúêÕ«aŠ‹‹Á#&ܨ„„«îÜìðôô„ƒ¥R™––ÖÛÛK$ ؈/[¶ ¶|gÔ‚ž&&&¶··;ûŽZ¿~}ppp__œ‹€çÝ]]]`eƒb2™¥¥¥)))½½½°:BaÙÙÙÕÕÕ …îýJLLT«Õ!ooï_þò—L&3??rÁÒ¥K)JXX˜J¥JJJâóùT*u÷îÝà€…ÇãiµÚÄÄÄ{«$$$„§`GO 6nÜ800`±XîÛÖÔÔTiiéôŠ"‘¨¡¡aÁ‚Ί …V{Ný¢Ìƒô‡.ûøø„‡‡'&&Òh4g•®®.p!‰b±X»wï†ØÒ‹%999((¨ú¡¤¤¤ÔÔT„ÐÙ³g%IuuµSmgùÎÎÎîînØ=q–_¾|ymm-Æ‘ÉdXwÆÇÇŽŽ:oÔœ9sôzýää$™L.++ƒo£ÒÒÒçž{®¤¤$""ðÜÜܬ¬, ÃÄbquuuiié½µB%%%*•ÊÓÓszfPPPWW×’%K¦ËqÞíåË—ƒY²³ ø–ËåÓí0*•šžžÖ~~~ þÃvìØÑÜÜìããsñâÅyóæQ(??¿åË—ÃíÈÌÌìèè€=ÉŒŒŒÂÂB„Pcc£\.·Ùl÷V¹sçŽÁ`ˆ‹‹Cùûû?ýôÓ`€ÓÜÍÍL&/]ºô¾m‡ã¬ØÛÛ Žœ#çÔÿ!Êœ••ß­===pº ë9窭­Å0,??Ÿ@ ,]ºlzN:–m<¯¨¨ø½mmmyyyŸþù½µ0 ûâ‹/ á±™!©T »ÐN9λa˜F£a³ÙÎ*8Ž/Y²äƒ>°X,ÎÑ!õ÷÷òÉ'0$ï¿ÿ>l,)•J°MxçwÊÊÊàãÜPÕÕÕ­X±Âb±ÆãÇC ûššš?üáçÎC-Z´Èf³éõú{«DDD8ã¼)•Ê·ß~ÒœòÖ­[‘‘‘×®]ËÉɹ·-2™¬×ëív»³bBBBXXØØØXww7TD9ŽÂÂB§mÅC”yþÐeØëÇq|rrÒYeÁ‚8Ž—––~öÙgûÛßÀ9Bhß¾}.\`±Xqqqð|ë­·œ«"èBè/ù $ <ƒÁØôò999°s†‚×tjjª“×¢ø|¾··wEE…ÅbYµjL»ááá/¾ø"44´¹¹ÙápüéO²Ûíáááqqq*•ÊÝÝ}F-‰”››k2™€àUUUõþûïC‹N9λmµZËÊÊNŸ>í¬Âãñ²²² æòôa½ˆDâÆgä|÷øip_î[,HÿRÞ™ð÷÷ÏÏÏ®ÿ÷•éÄÿ!´Ý#!l9I`›6mòôôôòòZ²d ¼¤þɆî­á¾oõ‡œŽü\. 8a8½Iwwwÿé÷×YžÇã{tÿÝ~~~34f0ðøõõõu64=,%øõ›^LÓ`M6ƒYE¡PÀ‘ÍfûûûÃ6LYæïï/‘H¦;݃CÀzN×J$ …Âé—ØBNÏ„æÀÉ{BBdòùüû6jóxûì³PÒ´ÊËËÛµk×Þ½{á)U’’’æÎ qb™</&&æ…^@eff X±b…F£™Þ„³ü† ÂÃÃ?þøãeË–ÁÌh:--ÍÙ_Ð|õêÕ 9”‡ahî…ÒÒÒÜÜÜéΚ5«¨¨èÅ_„À0ð766611q×®]÷ª½xñâääämÛ¶}—ûï´ë…é£ÿÍÄjhhxƒ!‰‰‰‡b±X­­­===V«5>>Œ« à›—%‡Ã× 4­¥¥eïÞ½Ä‰ŽŽŽéoV؇-¥[·n¥§§Ã‚g›Ùl>þüÊ•+ÿøÇ?bª/]º>‘B8Ž9˜a ¼¿¿áÂ…z½~ïÞ½½½½!6›}èСßþö·555ƒá£>²ÙlÀÇŒŽŽzzzÖÖÖ:k91½/_}õÌãÊÊʯ¿þÖ§ Õàà —— 9«ÄÄÄTUU•””9rÄ™™žžN¡PØlöÀÀ•J…¨÷Î×™³ gùÛ·oËåò­[·îß¿Çñ{›¶Z­Óû{¯æÓ[œ1 êi]]]dd¤Z­±{÷î ÒÑ µÏ;—=<<üå—_>üþÃ|zSÈ9úÿØa†……Ýk§àååu¯(F"‘’““g,,$I||¼@ ˜žïááÁãñ¶lÙ²téR¡P¸mÛ6g??¿ØØØ{Û"÷Æ wªáîîž’’2ãv3Œ‹ ‡s_ÎS+çKÖ ‰”””4cÙáåå¾Áöïß’œœ¼gÏö &@ù{cï8›~¸æÓ[¼·û÷íi||üŒ¾Éä””¦j3Œôôt&“ù½î¿³ÝïHៃ’QQQ†q8NÞ‹BGŽY¾|98]¼xñG}ù999L&ó­·ÞŠŽŽ}ÜÜÜüüüÞzë­ôôô·Þz+&&æ½÷ÞƒG`PPÐ+¯¼뼂‚"‘ïG@PXXø­bÝÝÝY,ÖSO=µiÓ&&“©V«Aye³ÙŽ;ÖØØØÒÒÒÐÐ/èÔc’Ÿ0“ÉTYY +€ÖÖÖÖÖV„PSSSkk+’¨Õj½^?55Pt:¸jhhp¤ N×E›6mz÷ÝwBSSS‡ÍfO?æÐétË»êt:¾­À¯•^¯‡(s¡ãÇ'$$ÔÕÕAô¹ÑÑÑ‚‚‚Ó§O#„´Z­^¯‡C:½^öìYp½Çb±€döp±°Ù­ÑhÀϯÑhåAÔ¼yóŠ‹‹+** À¼;¦¦¦\‘)"‡Ã›¥RÙÓÓ‡ÄbqttôÕ«W‡††ÆÆÆnß¾=<<Œãxvv6¸ðó/„‘H ©¨¨¸yó&äzzzÒéô®®. ó‚;xm‘H¤îîn½^Ÿ˜˜øé§ŸzzzŽ?~¼¤¤äòåˉ‰‰Ç7™Lµµµ0wCCCY,ÖÙ³g/\¸ Õj!???ŸL&wuuMLLܾ}[©T"„4MNNΗ_~I¥R-ËgŸ}6oÞ¼o«Ñh::éw¬ IDAT:š››F£SùšššœœœcÇŽ‘Éäææf‰TPPP]]ÝÛÛ;wîÜŠŠ ×ïIÜ{›àÞï) °¯ .¸à‚ .¸à‚ .¸àÂONú½çDÓs<<<€•1ùÔw¬þ ¤¤¤xxx8©B3*2 ©T f´ß7> •J‰‰áñx`•q •””à3„ËåJ¥R8¥!2™ Ú …R©T*•B1Ð!58hƒL¡PèííM&“Açé'€ÓïC`` 0«ä£kÆMóõõ…ãZ6›- ƒ„aØ /¼DAô5*• çƒL&¨ñ^^^"‘¼W0 gþtù÷žzyyÝ{7¬šáû!bBÄçž{îÆ³fÍš3gN[[[RR¸n×ëõ+V¬hoo'‰f³ùÕW_e2™“““|>ŸÅbÅÇÇs877·M›6=¤ú•+WBVV–X,Â5)ár¹B¡0""¢¤¤dbbbùòå©©©*•jãÆ£££†-X°@&“-Z´¨¾¾Þn·ÇÇǃ…ãìÙ³Édòè訷·wLL @`2™III Ãl6 __ßyóæÝ½{wÿþýV«5!!!''Çn·¯\¹,@áe0‡¢R©‰dÑ¢EçÎKIIIKKKNN®®®öññ9pà€J¥êëë \°`“ÉlmmýÍo~ãp8¤R©^¯_¸páÏþ󦦦­[·®Y³¢FFFÎ;·¾¾>33Ó`0,_¾¢G…††îß¿ŸÏçƒK'•9!!A&“Á>ÜæÍ›;::’’’(ŠÃáàóù+V¬¸zõê²eËòóó###ƒƒƒëêê222¤RéíÛ·u:ݶmÛÊËËÙlöüÇ;vlß¾}<O$A”u˜———––ÆãñØl¶R©”J¥“““8Žÿæ7¿ñññg³ÙàT«ÕnÙ²¥   ¼¼!4oÞ¼ööv„жmÛˆDbooï‹/¾800.“É$!DÌÍÍõöö“ËåR©˜„0×®]_?@ñ¹|ùòªU«¦¦¦òòòìvûCª_¹r…D"íÚµK.—{xxÄÇÇ'%%EFFnÚ´‰Åb1Œººº„„³Ùl4gÍšÕÝݘ˜ÈçócccCBBt:8ßÒh4†-[¶L.—s¹\ÑóçÏ;Ž’’’ââb©T{f·nÝòôôüàƒ-ZÄf³ÿüç?C óºº:£Ñ(:::ÊËËy<^DD„»»û™3g ™R©ljj‚@b~ø¡Ýn×ét™™™‡B­Y³fll¬¥¥¥±±qÅŠZ­6''ç‹/¾øË_þ¢V«ƒƒƒÿeee8މÄèèh//¯„„ƒqåÊ•’’’„„pà“žž 1T²³³çÎ+•J-Ë/~ñ‹Ó§OÇÅÅ]ºt©£££ººº¶¶¶¾¾Þápddd¸»»Ÿ:uŠJ¥¦¦¦^½zÕh4FEE]¾|¹°°ðóÏ?_¸pa¿Õj•J¥Ÿ|òIvv6•JýüóÏSRRZZZ>ÜÕÕÕÛÛ»aûÝÞÓÓóæ›o¾þúëgΜ‰ŽŽ¾råJFFƾ}û(J}}=ÄÒf±X|>ÿïÿûƒÄ"„0„3ÀßÔÔÔ•+W¼½½q-ìmÒh4:®ÕjWc4»ºº îÃë{zzr8œ‘‘‘‰‰ 0ÏúòË/QI§Óu:FÓét|ðÁÿ÷Ûl6xä „ªªªÄb±F£ùüóÏ{{{Á¿Èq84H$Êår P(ìv;4ýÞ{ï%&&2Œšš»Ý>22³ßl6kµÚÔÔTooo0¼¡Ñh8ŽK¥RpÚ{÷îÝ¡¡¡”””¸¸¸›7o&''Ëår§oÒ¨¨¨gŸ}¶ººZ&“577H( Ü+çmg±X8ŽËår»Ýn0À] tÉ6›mÃd2%$$ܺuK,»»»C@$üž P( î]»À4r``à믿–Éd»víº~ý:äÿêW¿ºzõ*™L®¬¬üꫯ€=ÖÛÛÛÓÓÃår!leÿCÄ"„p¢Ó××QàÛÛÛ%ÉÀÀ‰´Z­F£Q"‘p¹Üúúz8ZÖjµà­|G=¤ºÍfƒcµ±±±øøøîîn"‘8::êîîn6›W­Zõå—_‚ÛtëÖ-¡P˜œœl6›«ªª¬V+‹Å²ÛíF£äX,–M›6ÑéôC‡Á£üSÊåòÛ·oóù|«ÕªÕjsssÕjõðð°···››Ûõë×cbbX,V}}ý’%K ÆÉ“'ÙlvMM ›Í–H$Îéôÿgï½£Ú¼²õá£.êÑ„h¢wÓD½ƒÁÝ÷—8vìÜÔ›6}™g’±3™rgfÅ3;qK\ÁØÆzII€ u!éûcßû^ý;N¦$ó Ϭ—£Söyë)Ï~ö… áááÓÓÓIIIgΜár¹ qßÞÞN¥RY,–^¯S(@S*•žžž“““¡õë×_¿~]¯× "‘Á¹ãûßÿ>Çß) ÍÍÍÑh´µk׿çç8pÀl63™L“É2999==íïž[^àBàáá±uëÖ .ÀöÚáÇ?n0x<žB¡`±Xþþþ f;22‚Ãá ÝqÓ6::d÷0ïS„ìÐ÷õõ9&º¸¸„……uttxyyQ©Ô‘‘‘'Tû€ÙrNÆq†G¦3¼Û–$>Khn {¯HŸ‚!ZDD„£°ìãèS+Véà7å‡:×{ÉDúCõå­< \]]Áà;åïï¿| 9™LæŠ"Ð0 :;;ƒ2ÞãZÇ~zÊKöÍøpKJŽ9ëááä倀míµ×²²²†††ž{î9ƒÁ’’²aÃggç 6äää455åçç“Éä©©©ƒ¶´´ÀmÿþýT*µ®®îîÝ»¡Ÿÿüç---o¾ùfhh(Ð[©TêââbFFÆÖ­[“’’îܹc³Ù°v·lÙRZZ:22ò /,)¡(Î;‡9Ú{yyýüç??wî\qqqnnîÇßxã (¨Óé–´ÄmN±¶mÛäíí Édò–-[ÚÚÚ°®!„rss]\\&&&öïßßÞÞ¥ââârrrär¹Z­†VBÇŽ 3 …‚ÃáP(بÎÉÉ …qqqEEE …bnnЏ¸¸ÔÕÕmܸ±©©iaaÁñ$”——ƒºSpp°ãIHKK{õÕW]]]{{{a+Ýb±¬_¿¾¼¼Ül6íÞ½»¹¹Ùd29ž4 Ì=Í%‹Å[¶l¹uëÖøÃ%çÏž=£££ï¼óL>¦§§—|äÈ(…÷ððXXX€ÏvVVÖ;ï¼Ç¿þõ¯AÍÌn·»ºº~öÙg ãyéÒ%xP.^¼XYY‰„—'@`0:N,ß¾}*Á-oooxУ££ß{ï=ƒÁd2¥R)èG†„„¼ýöÛ™™™¡ëׯ:¾¼ ø «4Ïç„ÉÉI-æçç?® “É„yœcÁñññ®®.///¬àôô4¼9°®!„ÒÒÒ@º†•òõõ%“ɨâرc0óÇãñ###!!! £¾¾þ™gžqqq¡Óé™™™  q ˆV«ýâ‹/=z499éx®^½ RMËûÒÜܬP(>þøc“ÉÄåradùM&Ó™3g:;;ÕjõŠ'íi.YSSŒ—7=11±oß¾°°°ÌÌÌG=Ù`¼Ñhljj>Öøø¸F£*fII hÂ666fgg3™L«Õ £r Qa»Z­b‰DøÐÒétð!ÉÏÏ·ÛíÑÑÑ¿ÿýïá ž™™ÁX+¡ãÇ«Õê¹¹9F@??¿{÷îùøø,/‚Ãáþú׿‚4NŠŠr¤ºkµÚË—/—””¬ØVgg' †°‚žžž‰„N§c±ª k@½¬kX©›7o^¼xQ,ëtº»wïb’*###§N2›ÍJ¥R¡PX,–‚‚«Õ Ä@ð~ÆŠàñø|ôÑG8Îñ$¸»»»ººvww?î¼|||À)Ë_RR á+ž´§¹d–7ÝÚÚZUUõþûï@À‘'L Óéð²•Éd³³³<€O@VV™L¾~ýzVVÖ­[·@”bbb"##¢Ó„‡‡[­Öþþ~`\EGG÷÷÷gffÞºuË`0ÄÇÇ÷ôô444€\V||üììlggçÂÂø±àp¸ááapH×ét<€ŸŸŸP(¼|ùrddä’"v»=//¯¯¯ÈÄÃÃÃ03Âãñ+J,öÙgËÛŠŒŒT*•wïÞÕjµPL&477wtt@A£Ñ˜’’rëÖ-èZzzú½{÷BBBd2™F£®‘H$(e6›×¬YsþüyƒÁÐÖÖ4e£Ñx÷î]›Í¶¸¸822Òßßo0úûûïß¿?66688˜˜˜øù矛L&(Â`0„B¡··÷ôô´R©ÄN‚H$²Ûí&“ æ­Ž}Áú‹R*•p±üf³¹¿¿¦ÉËOÚÓ\2¬~NwlÚ`0ÌÌÌ\¹rE§ÓŒŒ8^µå£oŒ¤¤$xšE"•J…G!44V¢¿uÆÒã|(–xX8Â××>…Ð5nS©Ô„„äеo+vái|Fþ™—ìÿÁ"""Š‹‹`8(**JLL$‰°"€¹!¬[·>º[¶l•ËåðF™™ÉÈȉDjµZ&“aõlÙ²ü ª««—È‚ãƒÁ€§Ð1¿Z­®©©¡=è9z;Ö××aï-ÀÚµkÃÃÃÖ®];55e4wìØÑÑÑ¿VTT¨T*£Ñ¸mÛ6ì©JLLÌÍÍV©Tð­±Ûí±±±£££"‘èÎ;avvV§Ó¹¹¹íܹóÞ½{)))KLòððذaCBB‚V«õy„PPPPyy9ŸÏ‡õkìÆÆÆ‚pWaa!ôë‚‹‹Ë–-[8Ž£¤VXXX~~~BBBgg'ôÈßß?&&Öë!–Bgg§ŸŸ_||üèèè† ¼½½5ͦM›ôz=P±'&&ìv{VV–\.g³Ùaaa:"0À öÐМü™™¬uè›Ív4i‰X×øôôtp®]¿~ýƒà‘ÅSRR.]º¡PY,ÖÑ£GaAO£Ñ$''oذ¡¥¥¢cbEnܸÁápeÜBJ¥2888..N§Ó•••9æÿâ‹/¼½½A+fIþüü|gggN———§d2¹®®F¬‘‘‘îîîÑÑÑuuu|>¿®®ŽÇãÍÏÏ'$$àp¸æææšš¨ Óˆ‰‰™™™INNvŒº[YY)‘HàÓ•ëtºªªª^x¡²²òóó³³³ Âüü¼¯¯/‡[nÒôôôðð°Z­õð𨭭¥P(¡¡¡=Š‹‹q‡#GŽ`òZ“““yyyB¡0&&†J¥bEâââ`#nVHÆÖlÁèè(8×#„°Áþ——ÇËÌ̬®®nll„ˇðüüüÊÊÊÊÊJmÂÐßߟ˜˜ˆ|ÇÖa‚õ­h§c×þçÆŠ‰‰ÁªO>ù$)) ¶H±DP8uêB(///11144!¤P(èt:‹Åš››ƒ·+V6ÑÀ)£¾¾v[áM@"‘<==afŽå‡ETX>X’Öyëëë[[[F#LŠŠŠ`ªÁ`0ŒF£¿¿QQ‘§§gQQ‘———V«²Ûí333°X%•JáÆÂ„¦ámš““SUUÕÝÝ]PPkñP¹Z­öóó;sæÌþýû›››™LfNNNnn.N‡åb„Ðr“l6›Éd2™L‹‹‹<¯¤¤æó}}}³³³áááIII999¡¶¶¶ÔÔÔ¶¶6ˆ~@¡P°"½½½˜j–ˆÃá*++ûÛß:öýï‡ëèMMM9;;GFF^»vmãÆðMÇN¸J¥¢Óé fipB:>;ØÁ±žžžv»Åb­h§c×Ä_ýêWp”žžŽÃáàm†%J¥Ò?ýéOpüé§ŸªTªööv"‘XYY933síÚµºº:xÉcEvìØ100ššzçÎ'N@¢ÑhÔjµ‹Ån·Ã§ËÂÞºKòwwwWWWK¥R.—ëëë{éÒ%‹Å²cǸ?ôz=…B™šš‚øûñÇ߸qÃÉɉB¡ÀûßÇÇgpp0//ïêի𠌎Žúøø 544 „’’’üýýïß¿ïXùøøøéÓ§ƒƒƒ!,ù‡~h³ÙàJ€µ+šf#„ººº¶oßn±X´ZíçŸÁQ|ˆÃáfffæææ`Œð7n„‡‡›Íf¸á$8^ˆ{[p‹eE;»¶ž^* ÓŽz*©$|Ýü_O“ɰ”¼cÇX{«¬¬är¹t÷8î Ÿ€¯kÒŠXQ… öFWŒÙÙÙð‚Çzäïï¯%Êaÿ <ÉN:¾äÌ‚œæ’œÞÞÞð¡LLL„üð…B˜\€.Ç …K<¸]]]Á³DÖÁ±r !!!!!!޶ñùü%BVþþþL&“J¥‚Û-: f8†ºÄápt:=""$V€x=zóÍ7±yÓwßxVøÏ~íÚµ)))0Õ †§çÅ_ܼysDDDpp0@€¿[¶l%³Ù 㸔”L‘bãÆ³³³ðù?xð §§ç‹/¾ˆâr¹p+9r¤¦¦fûöí í„-]‡UN €8F§Ó=êîîŽÃá°Ølvee%Ü» 233œœ^{í58­\.î݃úùùíÛ·j€ôµk×&''§§§ËårxСG ; ]û.‹³>þøc*• [T?øÁ òÞÞÞ,QçÂjxùå—›››ù|¾T*mjjÂô-–Ëo6››››+++;†Çãm6ǺŒþ÷ù&‰‹…@ ÀÁ?êdÿ[ÅbÅÅÅ-‡†‡‡ÁÙ11"""""‚H$ËêèÑ£B¡¦:D£Ñ ÆþýûÑc(+ ";£K~Â*wL\^IPPPDDÄF6Dò]1?ȵ/¡Á`]ær¹{öìAAÞÿý’’’Uµo ØÎ†ãÜÉÉ èJËæßY0 xx GNNNÿBƯb«XÅ*V±ŠU¬b«XÅß_oû" ÀÝÝD"Á&¥H$¢P(³³³ùùùb±xlllûöíB¡phhÈ‘šóä é_@*‹Å@3ÄÇÇ—””ŒŽŽÏÏÏïÚµ <5Vñ±¼¼<$$äÂ… eee---III4íæÍ›FA«ÕFEEõõõùùùMLLÔÔÔœ;wîæÍ›Ï>û,‡›œœÔëõÎÎοüå/a‘iddD(öôôìß¿_¯×ƒªgIIIkk+xhµÚÛ·o§¦¦ÖÔÔüæ7¿ ¹råJaa!ÌöÝÜÜÒÒÒbbb&&&Μ9C£ÑÆÇÇsss°¥A|Ün·ïرÃÇÇgfff~~^§Ó…„„üêW¿zœÂý*þ™ÀƒÈDuu5‰Dò@àóùt:=,,lëÖ­T*5##£±±1&&\ŽÜÜܘL&°ÆBà^‘’’íââ>?ÞÞÞ™™™¡¡¡*•*33ôBóòòÀ ív{GGÇúõë©Tê¡C‡@O!æëë -"„:;;!8ŠÁ`0›Íx<ÿQQQÇ;î7¯â[‡ÃQ©Ôû÷ïƒCާ§gxxxwwwUU•Ñh¼qã†B¡èíí5 J¥R.—{xx@ü¦™™™……£Ñ¨R© zÖÄÄ„N§srr×€¾¾¾ööö   ²6W¯^åñx¹¹¹ãããjµšB¡Ü¹sG¡Pœ:ujûöí𲙞žV«ÕÐ"BhÇŽjµt³)ŠZ­w„R©.µR©„ެbß`#Ö ñxüž={p8¶»â¸±ƒÃáGÃZÎûÁãñެ~ ÀOð~úJzVöÉYÅ¿±ðvð/BˆÁ`DEE==oi‰“8T²$8 —Ë wvvöóóD"122rõõó¯ BtttJJŠT*MJJòôô$qqqv»===]"‘ìܹ3((¨µµµ¸¸X­VoÙ²¥©©iË–- ´!•JSSSÝÜÜ<==aÌ”››«V«cccüd4ÃÃÃ_}õÕ””…BQXX˜››ÛÐÐ1ž×¬Y0¤R©¬°°Ãá899ݹs'&&&99™Ãá0 :ž””$‘H¾#¬£U<„Ç÷ôôˆD¢ààપ*ƒÁ`4H$Òëõ âÇçó££££¢¢ðx|SSSWWWAAÁ•+Wh4Ú÷¿ÿýøøx½^_^^Îáp¢¢¢rrr\]]M&S^^ÞØØXtt´»»{nn.ŸÏ/..nmm ½víÚŽ;œ¡àõë×…B¡———F£ÎÉÉéîîvuu ¼|ùòáÇgff|}}³³³9ÎÀÀx4¬â; <‘Häp84-44¾Yccc&“ #·hµÚ±±1Œu_WW“ÇÅÅÅ©©©3g΀Ùl»xñ"ÈÕY­Ö˜˜“É„Çãççç›››Š5?>>+^z½^&“ñx<±X¬R©nß¾=;; ä0ˆ811aµZår9xsÿ³ÏÓ*¾&po¿ýö§Ÿ~:00²°°0??o4]]]'''áÞš››‹ŒŒÃãñ333^^^t:}jjjnnÆC àß<66Æd2Íf³^¯‡©¢§§çôô´ŸŸßÐÐP`` B¡˜žžvuu5›ÍF£‘N§«T*ˆ|Ü××Ìw…B288ÆhµZàääd³Ù<=={{{W?…ßu¬(»$²ô*Vñu7™Lîîî%‹H$‚ÏBxx¸““Óã„ËV±Š¯î{ßûžÉdõ•®®®äää?ýéOEEE cnn®µµ8é«XÅ×Þjµ^»v­³³“B¡€ƒ,ÇUÖ‹/~툿«XB!bCCÃØØØôô´Á` Ñh\.÷Ñ£G ¤€íœ¬b|w&ó‹ÊêoéU|Ë ÇŽ+--­­­ŒŒ|\6ŒÚð8dfffeeAޝ„c…P„@ ìÚµ +î˜açÎ+Z¾mÛ6„PUU—ËýðߦÝUüƒ@HIIÑétÞÞÞnnn*•Š@ ÄÆÆòùü‹/nذÁËËk~~>::zçÎÉÉÉ8®¼¼ÜÇLJÁ`°Ùl8 …EEE {ðàÁ¨¨(@[@L&óàÁƒfãÆt:],³ÙìÑÑÑ£Góùüªª*WWלœîóžžž°¼°°ðÊ+¯°X¬äädÈ€µèæææââR[[»¸¸811±{÷n.—[[[ËçóÏœ9SSSq1¾íÓûï ¼N§ûùÏÎf³·oßOþøã´´4>ŸßÐЀÇãAŸ)99ù׿þµ¯¯oSS“P(ôññ¹råJbb"„:÷÷÷Ÿ˜˜èííÕjµXh‘Íf§¦¦FÕ|>¿±±±½½]¯×“Éäã¿3kÖ¬9wîœÝn—Ëå/^„í牉‰ßýîwqqq 6>>ŽÇãµZíÔÔ”B¡pww×ét …ŽçççU*Õýû÷CCCûûûM&Shh¨D"!“Éfjj*;;[&“ÆH¤„„:.“ÉRSSçççGFFx<žÉdJJJR*•F«ÕF777Àd2{{{!ì´¨R©`W"Ô»à”Ut IDATººR(”¶¶¶uëÖ‘H¤»wï ''§¦¦¦oûô®âÇãANÃWÒc’’’Þ|óMÐçÀÔž°R@áZ”˜UŽé¹¹¹°ç Eðx|]]Æ[Kª…Ìååå,ëðáÃOÑÝUüsÁårAn!¶~ýú?.õïkákQ‡—Ì £¢¢àöøúú†‡‡Ã±‹‹Kttttt4—ËÅápnnnÑÑÑ j 9£¢¢°()<týAdÿ<==½½½Adÿ‚‚‚***@ÍÝ݆ÒJ¥2==ÏçONNB„ÁÄÄÄ;wž;wŽJ¥VTTP( …’‘‘aµZAÇÌÅÅþéËÌÌLN÷£ýhhh(33S"‘™ÍæììlÖšššYYY‰$//ϱ- ,¿ýöÛnnn °Àö½ï}Ïjµêt:ˆ ’™™ÑÓÓ£Óé îÒæÍ›!èÞK/½$‘H¶oßZ†¯½öŸÏÏÏϹýUüÝA„§OŸ...¶Ûí¿üå/wîÜyóæM__ß­[·êtº™™ŸÜÜ\«Õ Ê“™™™˜xõúõë¥RéÆ]]]u:]NNιs窫«===áßóçÏÇÆÆ&''C`´;vœ?~Ë–-111ƒ!**jvv‘íÙ³çÂ… [¶l‰ˆˆÀÚ ÿÑ~„òôô„U\0ýÁƒ|>ÿÂ… !FÓßß4 „B¡Øµk×ücȉ©ÿz½žÇãÙl6Ì)cwàGFFZZZ4³³óàà BÈf³yxx@ÐŽ³gÏjµZ½^Ãáæçç ÊÅåË—ák‚Òëõ>>>d2Y¥RݹsG"‘LNNZ­Vì_ˆga2™€J¿¸¸ÈçóÕjõÌÌ LbccAÙl6ÃOŽmµ´´À'ozzúÖ­[ áááT*•ÇãiµÚèèh새Šˆˆ R©¹¹¹T*500xÕ Öõ»ßýþmkk3›Í:®««ë[9éÿø¿A @ΓÉèÀªÕj˜†‰=„ÃjD"a³Ù»wï¦P(ï½÷¸jµZ—ÅÅEì_ C4›™™Ÿƒ1T!¾Ïìì,NçóùðÖH½uttÚl6"‘èììÜÑÑq FGG…B!yyy.\`0\.×jµÆÅÅ>}b´"„Ö­[wúôi2™L¡P 0 Elÿ(} ›Bb˜ÎñŠøŸŒûþ¸²$Åb­Rðß„—_~922288ÂwC6Xæ† ¹f³ù•W^ KHHèîîvww×jµ‡†!yyy6lˆ‹‹Æáp …J¥FÄX,PñFxEÇÉÉ ÜaMǯY³¢z oÞ¼9))©µµ•Á`|üñÇ...¥¥¥"‘¨¹¹Y(îÞ½[$ݾ};--í­·Þrwwïíí---Ý´iŸÏïêê:~üxhh¨Åbqqq‰Dûöí{ðàÁÑ£GŸ}öÙ{÷î%$$lݺ5??ÿÎ;nnnF£ñùçŸïêê2™Lt:¾ ‚ÙÙY.—«ÕjY,–““í>ÜÚÚ }Y\\twwß´iè ®‘ÅbI¥R___^Î!ˆÍ7>>þàÁƒqçά¬¬C‡Æ®®.‰tôèQ8h2™|||‚ƒƒ ÅÞ½{FãéÓ§ccc¹\î›o¾Y\\ìîîÎd2I$‡Ã±Ûí­­­l6›ÅbÑh´'Nètº÷Þ{ï­·Þ¢P(¯¾úê;ï¼±ó|}}ccc»»»;æáááíí ápû¿¹¹977÷ã?¶ÛíçÏŸ_³f ¬øãñø±±1>ŸÿùçŸ×ÖÖz{{8p ¿¿ÿÊ•+111 …B(C Z‰´yóæööö„„ <2Œ´´´ââb•JÕÕÕUZZÊd2Ÿyæ»ÝN"‘^zé%·ñù矯.[,Þl6ß¾}ÛÉɉJ¥‚2…Ba±X·oß&“É0œ·Z­ãããï¾û.‹ÅúòË/AN]&“ÅÄÄÈd²¾¾>ˆ`H$e2ÙÔÔTXXLÖ\\\( Ô)îÝ»wõêÕÚÚZ'•Jñx¼^¯g³Ù\.×d2ÙívÈ7«Á`pvv&“É---V«õîÝ»-ÒÙÙùäÉ“6l`0Ø7‘ÅbmݺõÒ¥Ki]§Óµ´´œ;wÎÉÉÉËËë׿þuiiicccKK‹³³3@P©T¿øÅ/<==/\¸Ÿ¶óçÏÿøÇ?þòË/!h›Í†)—.]‚Ír¹œB¡À’,ô¥»»{Íš5˜cK@°X,===8îáljdjjJ«ÕÊd²ŠŠ ©TJ&“år¹Ùlîìì4›ÍsssiiiùË_t:ÝÄÄ‘H„@‡J¥â>ªÕj‰DrçÎÍ›7³ÙìÉÉÉññq¨óÎ;>>>W¯^ëíí½ÿ¾——×èè(ÄÖëõ§Nª¨¨ ‘Hׯ_ƒƒƒ 2b³Ù"""ÆÇÇCCCÛÛÛ333;::RRRúûûÁ‡g÷îÝz½žÉd†……yxxttttwwC(¬¶¶¶æææGÁ°¶¶¶··whhH©TŽŒŒTTT\½zu|||dd$>>þäÉ“z½ö&&&=z$•J§¦¦|||RRRš››q8ÜÂÂôÅh4þñ„`t·nÝú¶/å¿ÂÂÂjjj`5áq(**zœ§²‹‹KuuuDDÄ“[!“ÉKü¡1$%%%&&Â[Ð1ݱÅ‹,/¾¤”#BCC—-– ¨¨¨¸¸xÅŸ|||V?…«XÅ*V±ŠU¬b«XÅ*þuíÃ@H@jjêòœ8.99û700088˜H$®Y³æ)·ƒ›XOð®q´ÊÏÏ£ˆÁ1…Bq¬?%%E ¬H#[±wK°âö$ ‚ØØØåá€VáÂ{ï½§×ë…B!Bˆ@ ¤¦¦‰ÄŠŠ ¥RI¥R gggµZmbb¢Ï³Ï>«ÓéÌf3‰Dª¬¬ÌÉÉ™žžæp8ëÖ­»qãFll¬‡‡‡Édb¯¯/OJJb³Ù"‘H*•úúú‚p­T*ÍÌÌŒŒŒ4 D"Ñ`0ˆÅb___???¸}õz}^^žZ­Ž÷õõ™™Y»v­X,Öh4x<žF£999-..ŠÅb@°°°Àf³ßzë­ááa¥R¹víZ½^¿nݺþþ~2™œ-¬V«X,–Ëååååb±¸¡¡!00P,OLLTTTèõúÀÀ@Ì0WW×—_~yttT,ëõú   ´´4ƒÁðÃþðÒ¥K/¼ð‚L&«ªªºsçη}ù¾» ˆÅb ¸ˆÅb6;;[^^Î`0âãã§§§×¬Y£Õj¥RéóÏ?áÂ…5kÖp¹ÜÎÎι¹¹‡FDDüå/‰‹‹c±X·nÝÚ³gOFFFttôØØXrr2\`µZ]VVÖÛÛšššÝÛÛ›œœòå—_F«Õºnݺµk×öööêtºÒÒR.—q+]\\ÂÃÃCBBÂÂÂnß¾½fÍ<_ZZêççg6›M&S`` §§§T*‹Å‹‹‹V«H<oË–-^^^¥¥¥×®] ¿víÚÑ£GïÝ»WWW×ÚÚ «nà÷±víZ“ÉDûèèh±XÞÛÛ oÓK—.3 °*>ðàµZ-ƒÁËåð¿R©Z¦Á` ÓéJ¥266yóóó,‹Á`0™L—Ÿüä'ÙÙÙàÀƒ’ÉdÉÉÉ£££XT:¹\n2™&''á;ÇN§s¹\.—ëââÂb±£ØÍÎÎ* ¹\ÞÖÖé Ä ²oîîî@0Äápjµ„–M&™LÆãñࣆUE¥Rkjjúûû§§§[ZZº»»±(²f³900P¥R …Bˆ>?99Éd2µZm~~>T?áp8hÂb±ttt¬ ò<8‹åââ¢T*-‹Ùlvrr‚ ¶ÁËËK&“Á=1??âU333V«ÕÓÓ¤Þýüüär¹V«…˜4mnn.((H«Õ.,,˜ÍfgggNG"‘àþƒã7fee8p`qqÑl6C~F³¸¸H£Ñ„Báää$)¦§§§§§ •Jecc#F³Z­0бX,‹‹‹ ¨Óéø|>ðHÍf3ðßÁøÑÑQøunnÎÅÅÅÓÓóÑ£G éE"‘À0#4™Lª‚ŸÜÝÝe2‡ÃqvvV©T«‚òOÇqîãüòÓq88;<=;ʱ¸»»ûòV`ú ÅÝÜÜ QÇœØñ’.<®¶¿ÝëðïNûÿuuuà£' U*›Í¶Z­¼wï@àñx:x ãàÁƒ]]]v»‡Ã½ñÆùùùÓÓÓuuummmWrqqÑÙÙÙÉÉ >L&“@ ¸ºº.,,ÄÆÆÎÏÏÃ1üj³Ùp8œÍfº\ff&™L¶ÙlV«ÕÝÝÝ`00™L2™l2™<==÷ìÙãe"‘Á)¨T*Fsuu¥R©UUUÀ–ñòò2 Ï?ÿ¼L&#‘HÐÕl6»¹¹ét:¨çæÍ›ðÒjµ^^^F£¢`Â<€H$nÞ¼ùáÇnnnƒ~2›Íµµµ]]]uuu©©©¾¾¾ßöåû““Ãårõz=‹Åòòòâr¹l6ÛÉÉéå—_¾wï^bbbssóÕ«W_{íµÏ?ÿ<$$äõ×_?qâÄÌÌÌ/~ñ‹ÿøÿ9 Bhß¾}l6ûÁƒóóó‘‘‘\.—ÏçOMMµ··§¦¦–––NMMõöö–””°X¬ï}ï{Z­V¥Ríܹ¤lI$ÒÏ~ö³/¿üBžÉäÀÀÀsçÎr¹\ ]½zU(*Š}ûö †K—.Ƽ¼<¹\^UU f¼¢ÕjÙl¶T*µX,ðÆ:räˆN§ÏiçMMMuttÔÖÖÞ¿?55ull,!!Áf³q¹Ü©©©ñññ¼¼¼?ýéO!«Õ 1ÕWñ8à*ÓÔÔD¡PH$RSSP™L¦B¡˜œœôññ¡Óé&“©­­íÑ£Gccc&“I£ÑlÙ²åÓO? „Á`˜››«¯¯ïëëóôô„pNMMM‹åÊ•+T*Ž…B¡\.—ËåSSS†Á`@~„‡5¥±±1H¾pá‚Á`H$ÑÑÑ2™ŒH$‰Dà´H¤ÙÙÙÑÑQ<¥×ëAÖ‹D"™Í怀€wß}×××·¥¥ÅÛÛêAÑéô³gÏ‚J‹ÅÃø|~[[›ŸŸŸT*e³ÙPü„ÇãGGGAÏ·±±±¶¶öÛ½rßqŒF#™LÐh4‰dzz\©Z[[ñx¼»»{KK ðòÆÇÇA#d||‡Ã………Ñéôáááìì솆…BaNúúúzzz|}};;;;;;!~‰T*]XXËå>„»ÁÛÛ;%%åÖ­[8N£Ñ`ùgffæææCCCÈdrggç¹s犋‹ïß¿M···[­VÈ9::*•Jgffètzww÷Ðз·wkkëÈȈD"1™L‡Éd^»vÏçŸ>}:;;ûþýûR©tnn.55õäÉ“………W®\“J¥ d2<<ÜÓÓC (Jkkëðð0ØO"‘)JJJÊÅ‹U*Õ·}ùV± ………_·Taaáê’÷¿0?tGªgžyfyN¬Âþݺukuuµ»»{}}}ZZÚÓ´•••õä ™™™°°"öìÙƒ‡„„`ô:8 uìž={BCCW¤à9Öó8`§eyâ¦M›Ž9’ŸŸÿ••ü;ƒðá‡r8œääd2™Ìáp***ÀÿÄÜëêêìvûØØØÞ½{Ùlvuu5¬'‘H$«ÕšžžÞÝÝ=??Ÿ››{óæÍÚÚZ톆†–••‰D"*•ZZZWPP099–’’RXX(—ËŸ}öÙÒÒÒññq«yàÀ‘Hd4M&Ó‘#G Cuu5™L.))‰D*•jïÞ½>>>~~~@uçr¹6›í…^HMMU(o¼ñÆÔÔÔôôôÞ½{™L&Õœœ6lØPTTÄd2×­[g±X¶oßzIUUUUUU&“iûöíl6[,ƒaõõõB¡°¾¾~nnnýúõL&3;;»°°@ ¼ñƧOŸ(((øýïo³Ù¾íË÷ݾ§§G£Ñ466–ÈÕ«WCCCÙl6læØl6X âñx @>Êr¹œD"uuuÍÏÏ“H$Xéööö }å•W&&&\\\RRR<==½¼¼Îœ9äíí}æÌ™ÂÂBp·R($ ò#„ðx¼F£Y³f ‡ ‚ôòòò'N€ãkQQ‘T*uwwg±XöÂÃÃC­Vwttøúúzxxèõzxu¹»»Ûl6½^îܹõë×ãp¸úúz¨!”püøñŠŠŠ>ú(99 KHH “É$©··wvvª‚ŸÜÜÜ::: l}«î»",%ëõú‰‰ •J¥×ëÇÇÇ'''F£¿¿?,C@X^›ÍÆf³ ‹Å²Z­555­­­!!!ÉÉÉ ‹ÐÒÒB ²³³år9xR@…cccz½~nnnbb!¤×뇇‡ÓÒÒ@À îTÈ?77áUîß¿_PP0::099ÙÔÔ´sçι¹¹¦¦¦ÊÊJ«Õ 9ÇÇÇBsss‚E.—s82™<>>-R(”5kÖÌÍÍ]½z•F£=xðêA îÚµ«¡¡açÎ}}}4M¯×k4£ÑÈb±d2YJJ Te0ôzýìì,@ ‘H‹Ú]Å“€- ¯ˆ%âX+ªU­( õ•ªZ555¯¾úêò;4Dÿ»Ø½k×.ð.\̰Ç5 ŽŽö/i«÷¿XþÓ“;µŠÿlð!„ã®8ÇápŽL¦àààÐÐP"‘˜’’ò”›$ŽM¬ˆ   'xÖ;Z%0ug8¦R©Žõ‹D"ÿ Ÿfª–å‰áááIII°mºŠÇðþûï †ÐÐPX­NKK#‰eeeÓÓÓT*µ¤¤v[“““}}}ëëëF£Åb!‘HåååÀÇrqqY¿~ý7âããAñ‘ÏçÇÄÄðù|’’Âáp ú!8[Ãqvvvtt´^¯>VNNŸÏ‡«•––¦Óé A…‹ÏçÏÌ̬[·‚Ÿãñx'''ð&ÍÉÉñ÷÷W«ÕçwÞœššªªªÒëõ•••}}} %/// ÀjµæääLNNVVV¦§§744gggC„DƒÁŒæêêúê«¯ŽŽŽfggY-==Ýh4‚G«‹‹K^^xb~Û—ï» BzzºÅbQ*•ÙÙÙ4mjj øXqqqSSS ÀÇzî¹çΞ=›Àf³;::T*ÕèèhXXØ_ÿú×5kÖk÷îÝééé±±±V³¼¼\§Ó©Tª²²²ÎÎΰ°°ÔÔÔˆˆˆÎÎÎÔÔÔððð   /¾øÂ`0Øl¶ÊÊÊòòràc¤`TT—Ë-//wqqéîˆ onn>VQQ‘¯¯/D^^^R©4...33øX áææ¶uëVww÷òòò/¿ü2""¢¡¡áÈ‘#wîÜÙ¾}û­[·jjjÂÂÂ:;;ÃÃÃËËË!&YOOOTT„Lïìì d³Ù ä–––öÛßþöÛ¾vßiàa B1== |,¶+..Îh4j4.—Ëb±€•õ_ÿõ_½½½999ÿI*•¶··'&&:ò±¦¦¦@j f—pŒÇãY,–»»»››ƒÁXÂÇš››“Ëå …ãc©Õꈈ"‘ØØØèææ†ñ±4^¯‡ji4Úr>–““Ó¶mÛFFF”Jå½{÷ÚÛÛ¡(6== 1ñ”J%“ÉILL„ûª‚Ÿp84ñŸÿùŸ+.t­ŽÉdBÜy'''‹Åb±XÀWØb±Ê•F£Öìì¬Õj"ØœQ*•z½n*•ªV«ýýýµZ­V«… õz=¶*Ç›6m‹ÅÀDzX,aaÁjµR©TN P(ÜÜÜ´Zíì쬟Ÿ¼üÆÇÇ›šš¨T*äS­V+ÇÓh4ƒÁÛÛ6[€Åår5···L&ƒ_Õjµ“““‡‡‡L&ó÷÷Ÿœœ$‰`‡Ã1™L‹…B¡ï ³ÙÕÕu||ö@A¢òÛ»pÿ:pôbxœGƒãX›N>}ÔqÇjáå·$N_qÔŒíÚ%9±ã%]x\m«ÑPþ ìØ±V¨ƒ‚‚fgg1>Öýû÷AªÕjív;Ng±XÏ=÷\ww·ÝnÇãño½õð±jkk£¢¢Ç Åd2y{{ïÚµ«µµ„„àÝ £x.—K£ÑÖ¯_óññ1 ”J¥D"ô’Ìf³‡‡‡V«…znÞ¼I&“ùÁ0‡C ª««GFF€?™ÍæmÛ¶uttüçþ'¬Þ­jb=ÄÌÌL‹¥Óé8Ž——‡Ãquu¥Ñh¯¼òÊÝ»w׬Yƒñ±NŸ>- _ýõãÇÏÌ̼ûî»/½ôÒÐЯ¯/DÝ>V[[›J¥ŠŠŠ jhhàp8@¡PÀ˜½¬¬L¡P 3™LŒµcÇŽ   K—.9ò±à tîÜ9ðå:zô¨L&»té’P(T*• ÇuñâE£Ñ˜••ååå%—Ë+++a J(ÎÍÍ…†††„„ ‹KµK£Ñ›ÉdMx|­­­©©©£££ 8ŽÃáƒ(++ë¿ÿû¿¥R)ì¬âqÀ‰åư•qãÆ "‘H¡PètºB¡˜˜˜àóù Ãh4¶··;ò±jjjþú׿  æ€Ï<óL__Ÿ———››Th6›¯^½êîîŠßW¯^ >°t äGáp¸¡¡!6› ¼H ºxñ¢Á`xôèD§&‰A*•*•JàcI$~°÷L$Mÿî»ïz{{777{xx@=!—/¾øÂÇÇçòåË  óõõ½wï^@@€L&suu…ªà''‘H`DØÛÛû³ŸýìÛ½rßq`X:000???:::===??ß×××ÒÒ‚Ãá<<<àzŒŽŽNLLðx¼ÙÙYˆ€" étúÐÐX,¾víècõõõuww÷ööz{{···wvvBLr™L¦Ñh&''GFFd2™B¡ðòò‰D7oÞ„É–ffF¥R]¿~øXD"±½½ýìÙ³EEE÷îÝo¢öööÅÅEÈùèÑ#‰Dšá]]]ƒƒƒ^^^wîÜ>‹Åb³ÙW®\ñóó;uêTvv6hzÍÌÌ$''òÉ'………—.]’Éd2™l~~žÁ` vuutà;w†††À~"‘844¤ÕjûûûW÷ ¿£ÈÏÏÏËËû¥ž0º_Åw˜Ú˜#™éÙgŸ]ž“@ 82™jjjêêê<<<öîÝ›‘‘ñ4m}%K,ƒ动¯¯ÇŽ—ó±ÂÃûP__ÿ8>–c=Ê"lXRRSRRò•õüÛ‚ðÁ¸ºº&''S(àc @TwàcÉd²ýû÷ƒÎgpp0ÐÌM&SzzzWW—Z­ÎÉɹyóæ¶mÛ­VkXXXyyyZZ𱀑ššZXX2¸eeeàЧÕj<˜––¦×ëM&Ó‹/¾h4«««¡xZZÆÇL&Ç»ººÚl¶#GŽˆD"…BÁãñ^ýõ™™àc±X¬àà`¹\îää´qãFpÜX·nÝâââ¶mÛ`\µ~ýúªª*‹Å²mÛ6‡“••…ñ±BBBöìÙ3??¿aË•““|¬×_ýôéÓuuu~~~B¡088x5bÊã€ïé陟Ÿohhð÷÷çñx—/_ …l6;>>–+auÔÝÝøX*• øXNNN ¦+ŸžžžAAA¯¼òÊØØ˜³³sRRÇkhhàñxŸþy\\\@@€§§ççŸ^PPË¡ÀÇ"“É!„Çãçççãããív»@ €ô²²²ãÇ/,,0™Ì‚‚‰DâêêÊd2a¡í:::¼½½=<$$àc1 ±X,•JÁû\­VëæÍ›ïÝ»œšš:22‚º}û6@ÈÊÊR(L&s||‚šH¥R˜0Ž!„t:Ýàà H$Љ‰>–F£ü³³³ R©ôÁƒ………‰$00p||¼±±q×®]*•êÆÀÇ‚œ<”Z IDAT2™ !¤R©t:‡“Ëå°–&“É€AE&“cbbT*Äh9yò$Ôƒêïïß½{÷Õ«WwîÜÙÓÓC£Ñt:Ýüü<¨½K$’¤¤$¨Ê`0€ý°Ãsýúu¡Ph6›^¶ŠÇâ |¬å ¤å™Wd)}%u©¦¦æ•W^yB~XÐÇÒá`çÎ|>ÿɦ>®é%bÇ+ò±ÐJä³U>Ö×6Ér >¸â`‡Ã92™ÂÃÃa0›œœìããó4m}e|Ãàà`Ø‚\ŽV9r­à˜F£9ÖŸžž°"ëi¦+Î=ÁA(((H$=e—ÿmAøðÃFcxxøââ"‰DÊÌÌ$‘H@âR©eeeðщD|>¿¾¾Hß E,ètº¨¨¨ááá………5kÖxzzšL&??¿¸¸8@€ÇãÓÒÒ¸\nffæè託—çææÆÆÆêt:àcåçç ˆ–™™©×ë!\yrr²@ ˜ššÚ´i“H$Òét ¢ sss\.÷ûßÿþÀÀÀÔÔÔ† ôz}EEE?…B)((€èNyyyëׯ‰D×®] ÉËË_¿~½Á` …˜aîîúªD"ÉÍÍÕëõ!!!™™™ƒá§?ýé_|ñüóÏß¿_­V±b+‚ššj6›'''³³³©Tª\./++c2™±±±r¹<>>^£ÑH¥Òýû÷öÙgñññjkffÆb±äææ.,,P©T‘HtãÆ]»v¥¥¥ÅÅÅ=zô(11±¬¬L«Õ*•ÊÒÒÒ¶¶¶ˆˆˆ”””ððð¶¶¶´´´€€€óçÏkíÚµ £¥Óéòòò\]]Add$›Í.++£Óé<€˜?·nÝo‹¼¼Hw „p8œV«…‰!Äc>fBÈÙÙyÇŽ2™lrròÁƒ÷ï߇zB&“)..N©TBïÀ0ƒO…^¯/))ªà'MhµÚ÷ßuäþdàèt:FS©T@öµX,˜è@pss÷,„ÜXÓjµ²X,7== RŽƒn …²°°àëë lA¨Ð`0H$¸¢p¼yóæÌÌLàc-..B~N2nƒÁÏÏojjŠÃáÀdÍÇÇgnn®²²R"‘ܼyB‹ðrrww_XX0žžž°`±Xp8øiµZ»Rsss 4ÍÍÍm||œÏç+ ø"“H$‹e6›- ,‚@Uð‡Ã‘ËåÎÎΫÊXßËàô -ǰJXôï¯t°Á°„µ$Ð!—ËÅݘýOO[‚'û/}³œO“;0âD1 8WßlZúä3ðôu.ñ˜úŠÌo¾ùfpp°ÝnW(X*èÕßèücCCÃOúÓ€€€{÷î!„ètºÙlÎËË«®®.**jnn^\\ŒŽŽV*•¡;w–””¨Õê×^{mI‘°°°={ödffÞ¼yœžB^^^Ç?}úôÆÓÒÒ=zô¸¶Äb1PÎ111555111þþþPÐjµîÚµëîÝ»˜ýO0æqöC—oܸñꫯŠÅâëׯcE¢¢¢*++÷îÝ{îÜ9„Vä?øAAAT*}ë­·¬Vë£G ŒÕj­««{ñÅM&Óðð0f9䟙™©¬¬Ü¸qãÕ«W±ü½Q ôõõíÛ·ïîÝ»6›íàÁƒ@€µÿþôôt¹\®V«Á°±X|èС{÷îíÝ»÷Î;<ÏÉÉI§ÓEGGoß¾=***))iI)°D$=zôH£Ñ`‰¿ýíoAè`ll «;Ûñññyyy³³³ÓÓÓPÄÅÅ¥®®îèÑ£­­­Ø¸ïììl4'''BÜ»w/B""„ÊÊʬV+„¤‡8†±±±'Nœ`0T*unnŽH$’H¤øøø·Þz«²²!ôÙgŸAè¶åEÀµe¿‘Hœœœ³´´4ø<­Ø‡ƒ—V°¿¿‚übÕj5p­0ûŸ`Ìãì‡.{yyMNNªÕj‹…éîî6™L¿üå/BëÖ­{ûí·!ÈÔOúS«Õêêêj±X€A´ÿþƒ"„þð‡?<|øð‹/¾€'¨Aö->øàÇüF£ÇÃÐÛÛ =ºv¢@‡Ã9;;Ÿ8q">>~xx8>>žÉd>ÿüóçðáÇIÕO?ý‡Ã-/…²Ùl###333މ0Âqsss¬;Û~~~Ÿ|ò‰H$ŠhµÚÆÆÆÖÖÖ‰‰ ìêà Ãùóça1†;!ð÷…‡’F£EGGÿùÏÝ,…BqêÔ)pgúḰ°088822rãÆ „PBBÂ_|áï“ÉüãÿXUU¯S …âøE˜ŸŸ¿xñbVVÖŠmݼyS*•zyyaCBBúúú V!d·Û!Ô Øÿcg?t¼ûi4šÑhÄŠ€ø[__Bèúõë###¬pûöíþóŸggg?øà¸6·nÝZh(µX~„P(”J¥Žù5Í… ¶oߎ2™L4m¹†þÝ»wÏŸ?Ÿœœ¬ÓéN:%—Ëm6Çûè£ l¬Z­nmmmiiÑjµ$iÇŽøÃ–—¢R©---D"1..KDMMM]¸páìÙ³Žõ`gÛn·³X,{…"áÙgŸýýïKÊÿsYÑ2øúúBßàÃÒÒRÇ<û×ÙÙ¢¢¢¶mÛÆ`0–¡Óé555Ë9`ƒ¿¿ÿŽ;X,ÖŠmÕÔÔ”””8Þˆ,«®®.22+H&“_zé¥Ý»w …B°ÿ Æ<Î~¬ËÅÅÅŽEâââjjjÖ­[·¤ÈÎ;7oÞìîî¾mÛ¶åÁô–/ C~æºmÛ6„Ð /¼SXXøÚk¯AÇáD…‡‡oÛ¶mIпÔÔTÐÚ„¶‰òóóÛ¾}{nn «««—(µ:ŒÕƒí°°°ÚÚZÇè| zôTáõIðoÇòM•¿¼½½¹\.LÿqöcøÇuC$ñx¼¯¯ïß.È‹ám6€ ‰222º»»wíÚ !ÄB …"%%¥ººÈÇV«Ò±üUUU¡¡¡*•jÿþýd2Y"‘`•nذ!99Ùjµbôôôòòr©Têêê*‰†‡‡‰Dâ3Ï<ƒ¹$;epp†!>Ÿïçç—““388XRR244„Iâòx¼C‡ݼy377·¨¨H©Tj4š……ƒÁàîî^[[ Ò˜è^DDĺuëÂÃû»»B =îhUUUUxxxOOf0›ÍÞ¾}ûÛˆˆˆâââÌÌÌ»wïîß¿C[·nœœ plPRR"‘H¶nÝj³Ù\\\æçç—7 Rõ!OOÏÚÚÚÔÔT°\©TÚl¶ððp‘H”˜˜x÷î]¬Zì*ìÙ³ÇjµbÓ°pýúõ>>>Žfóx¼ºº:`ë/1›ÃáÔÖÖÚl¶°°°¯<ÿX…Ð.‡ƒ«°üÆÂß»w¸uáááàáïïäÈggç»wï:99}òÉ'0}@~‹b0<<<`ͳ¢¢ÆO°øžŸŸ)ðW§Ó=|ø044T"‘À' ==½··«977·½½d=z4  wìØ±uëVWWW‰TQQQZZJ"‘¦¦¦`DŸ––1…±R …¢½½]&“ c}ñ÷÷ïéé ùúë¯{zz"„´ZíÇ322\]]ýüüœœœ°"aaaÖ±°Äþþþ‘‘¸_çççaö¤R©›Àò3Œ­[·îÞ½»´´tnnnyÓ¡¡¡O¶Ü±Å%W!Ô××»òŽ=Õëõ°UzäÈ‘ÈÈÈ#GްX¬û÷ï‹D¢åfoذá³Ï>«¨¨øÊóïh´‹]Ç«ÿ?7–Åb±Ûí cqqÑn·CHw£Ñh³Ùl6<^999P òãñx¥RÃá>þøã­[·"„À§ê]\\äp8% h0#„@ÐÛÇÇ5¨üöíÛeeeD"vÉd2D8yòd}}ý­[·œ£££cbbh4šÍfƒyFSSÓàà`qq1VÊn·Ã’©ÍfÃú‚ÊÈÈhiiQ©T|>?(((&&!$•J[[[! L¡ÈèèhGGGYYBK¤P(%%%'OžDMNNzyyÁÂ2ôkËûöíúúúßýîwáááóóóË›nnn~²åŽ-.¹ !ì™wì)dàñxþþþV«ÕßßvvÖn·ÃXj‰ÙgΜٺu+NÿÊ󪯯…lh» K®>Bˆˆ’H$àA2›ÍCCC‡¹:‰DhhhÀÊH$³Ù¬P(¨TêÌÌLEE¼üAªLÆRÀ&ˆ/Òßßo³Ù6mÚ4>>044•'''/,,ܾ}Ûf³>| èîî>wîœÏÇívûñãÇm6˜ ¶±Ùì   3gÎ8–y„Ö•Juúôix™wwwÿìg?ƒÏÁ¦M›T*“É„]mF£Ñh “ÉLLL„…¬žœœF³iÓ¦“'O ‚žžžììl˜ë96å—Éd—/_>{ö,›Í^±i8!O°Ü±Å%WòÃË̱§AAAjµº½½½¥¥Åf³:t(,,,--mpp!´ÄlƒÁ Õj/_¾ BeO8ÿ¡'N@ëX»Øâx­ÿ|ãåã¯;‰‰‰8nóæÍKêüZUþ.#Л~rÍ›6mnØ5ÿÛmø‡ëËr³±Ÿ¾Ùù_!!!iiiŽ“m„›ÍÎÎÎ^’ˆŠŒŒ„7!‡“‘‘±D,ŠH$fffÂdsʼn‹‹suu¥Óé0%vuuMOO'¡¡¡!##ƒÍfCú’+ ¤‰%ÆDDD,1!äì윛›K£ÑüýýaCúëV‹UA322\\\Äb1Èw}ÿ¢7àkjjt:ÝsÏ=‡òòò‚ý©ƒNOOC¦êêj„‹‹«­­ÅápD"1&&‡Ã‰D".—{øða‰Tàèèh·oß>„Phh(L•KKKC±uëVwàÀƒQUUµaÆêêê7’Éä}ûöAzAA‡‹…}ë 6ˆD¢¸¸¸ØØX‰SSSkjjà! Bûöí3v»ýÀZ­¶²²ò+«…Ott4,AEEEñP•ÅbQ(‘‘‘‹eI§Vñ8ài4ZVV|&÷íÛ §OŸ®¬¬„‘õž={¶mÛ&‰l6[{{;„IJII9vì¼ÒœœÄbñ±cÇrss;6<µSEµk[@±S ;²ÉÙD÷-Æ%­v213vzÉ$éét2‰Ú.mH4£FÛ7PP”Ev•}¡ ¨¢ ¾?Þ™ûÕW 1dÒ3_=ä‡'÷œó¾çÞº÷,ïû<žžÃÃÃR©x³¨T*” *•úé§ŸB̪­­­@ `³ÙŸ~úéÒ¥K?ýôÓ   Ë—/kµÚU«V „««krr2ÇËÏÏwuuýÞfi4ÇÛ¼yó–-[Ølv]]M………1™ÌëׯWVVZZZ¤œú…nÙÿ ggg;::`³õ£>‚EDDD}}½ŸŸßÝ»w9233sÿþ} …’””411‡Y=q5­­­R©´¶¶ÖÜÜ<33óàÁƒ!33³ááa777½ÏL&KHH¸sçìn—””¼ñÆÀÁœÐÔÔ¤T*333¥R)Bhrr²¹¹™Ãá@ Èõ;vìܹsFFFwïÞ=uêÔ‰'BíííZ­V¥RÁ&PSSÓ÷6+ +**> ‚ "‘Œ‡¦ðx|```aa!d³Á«ÎÌÌ ø| x)LLL8ŽÞ¦>™L¶¶¶Æ"ï0°X,½£+2™Ìáp°ÝB8ô…WW×Í›7Ãep@¡P€1†ÉdBh—……çA¹nƒl6›Åbé=š‡Ãáè’H$+++H%ΣÚ,f<Ö¨áñxKKK¨Ý»w+~a`‡JD"Òÿ  {Rf€`€`€ÿàg][½¬q<ÿ?eM÷2;á¨ã{Y~A Î ÓÁ [’““ÜÒÒ¬zõšÕ‘Hܸq£D"ð½Šb±8--ÍÑÑ´0~PÒ•«««‡‡‡ÏÒ¥Kíìì222LMM{{{7nÜAA;vì R©qqq µµ•ÅbåççÃß¹¹¹ŽŽŽ­­­qqq<¯½½}Ïž=b±„¨ìì좣£[[[W¬XßÑÑagg—––&‹±È6Ýqسg»»{{{ûâÅ‹u‡ñeƒ& —,YòôéÓààà{{{;;»îîî>øRs;;;srrÌÌÌvíÚUZZ’˜˜ØÑÑ‘™™)‹‡‡‡W¯^M$íìì 211{ÄbñãÇ!†ŸŸïííýèÑ#„N‡ð,”””ŽŽŽeË–-Z´hllìÍ"„999ÀkaaajjšššªT*óòò¸\®­­-0|ÊåòM›6MOOK$’%K–$&&zyy¹»»»¸¸¼¢zYY@øðÃ6mÚäêêÊd2³²²„B¡……E__Ÿ¿¿ÿ‰' X,ÖòåË/^ìææÆd2úúú@÷{nnnÏž=ÁÁÁýýýÛ¶m‹Å>ŒŠŠJNNvtttvvNMMõõõ™™t‰DråÊ•¥K—~ùå—[¶lñòòúä“O fggÉd²Z­–Ë嘀¯¯ïÍ›7½¼¼¬¬¬::: Ç5**êßÿýßÕjugggdddqqñääd||üÍ›7ꪪòòò’““!UazzºªªÊÇǧ§§ÇËËK¥Råççóx<@ô¾ééé"‘¨··—L&ÛÛÛ/Y²$&&fxxxëÖ­ÉÉÉ7oÞDÅÇÇs¹ÜÔÔT *•tçÎ@0==­ÑhärùÀÀ€§§§‹‹Kaa¡V«}ã7®]»¦P(¢¢¢îܹ³nݺ .ddd@ ¸X,þÛßþ–‘‘!‰.\¸ÖÞÞ¾{÷îááá±±±U«V) ¹\ž——'“ÉòóóGFF^¼xª0 ãwÞimm•Éd;vìèëëëèèØ¾};ð_¹råeÍ"„ðàÌ_|!“É’’’Ôjµ›››\.Và'OžÀÆúñãÇcbb@’žÍf=}úÔÖÖöÕÕÑéGh4š¤¤$ȱÎÍÍuqq&‘‘cc㘘˜£Gzxx9r(i4ZTTTgg§@ 022b±X&&&ÐN\\Ü‘#G`Ÿ–Ãá\¿~ÝÞÞºV(»wïí …‚ÇãU*ÕÔÔb@ª••ÕÈÈȳgÏ,,,ärùÁƒ§¦¦ S—ÃáôööVWWCº„£A¼‘D"Ul„£££ƒƒÃ·ß~«T*…BáÉ“'ׯ_íÚµƒb_ååå_~ù%œ¨ÖÕÕ}øá‡MMML&ÓÆÆfjj †ñܹsÑÑÑãããºZàK[[Ûž={ÊËË!v­¼¼¼¤¤äÖ­[}„‚”],¬ 8ÌaÀ! B»¨TªJ¥‚P©Td2Y¥R™››Ã×snnîéÓ§®®®æææÂ’ Ökmmmgg‡W8®±±177wppÐÃÃN·^Ö,Bˆ ÊËË333ÇÆÆðx߯Æ8)à“daaå©©©ššà!‡ü"@P__Ï`0‚‚‚þã?þÃÝÝ}nnîüùóÍÍÍÃÃÃpÀ*•JoÞ¼ ¡¡¡Z­¶¶¶ö«¯¾zþü9”¿õÖ[`ÛÀÀ@WWDƒ€×7x<‘H<<\ïæ™˜˜DDD „ètzLL F{Y_z š$)**ŠÏçcmmmE"‘®kÐ>„ŠƒkX-@¡wr„Q’`033ÂúððpÝ€‘‘QDDDDD„Þa+—ËŠŠZpÜœ¡ŠîI.Ç‹ŠŠ255…ÿ¥Kî¥;h¯sËìíí!Êm~×ööö!‘HÄd2! öãW®\9>>Ñ2¡ÜÜ\„‡óóóËÊÊ ‰D*• ¨i9Ž››[VV‡ëëëƒøO‘H„ýbâããGGG]]]!¢†N§šššæååÁsM"‘¼½½ASÓØØ8;;L„~BÁÁÁt:=<<|~•ÐÐPxìt]Òjµ8nË–-@šº`_t:}ûöíºa.¸iÓ&¬bOOOVVBs !TPPàVkåÊ• k…Ãá0›””###ÈðôôÄBkvîÜ™””´uëV …¢bPE£Ñôôô¤§§CØ6‘‘‘ÀÐ9ßHpèííÅò¦BðhõôôÄÅÅAÈüüA{[633öÏï:>>>((èàÁƒ+V¬€·õ+ ÆS©Ô¨¨(°rݺu¹¹¹AAAZ­öÚµkccc¶¶¶d2yÓ¦MÏž=£Óéµµµ À9ÓÑÑ¿ïÖÖV‘®¼½½áfÀâÙÔÔ´««+33äXÿüç?ƒÞÞÞ@@’›› UEEEaaa f WåáǪ€²±±Y³f •J .„µµµ››[llì‚}-^¼˜F£aAœ\¥RaµZ-„c®!„8ÎÄÄæV«««K$I$*•ú§?ý fr666nnnÕÕÕ<oÓ¦M›7of³Ù gbbÁEÖÖÖXF#‹Ïž=+“ÉtáÌ™3ÕÕÕó}˜˜èì윛› …,\¸¾¢¢‚ËåÞ¸qC­V/8h¯sËúúú`27¿ëòòò;wÞ¿_,÷ôô¼Ú`üììlww7| 9òÍ7ßÀºãßþíߺ»»ÛÛÛi4šV«µ´´£P()))À”L&“aÄ`0fff|||@S!ôâÅ x·×ÔÔP(àq„’ªªªåË—ÃŽÔ•+W>ùä“ÙÙÙ»wï~óÍ7 -™ŸŸßÖÖÙ zUüüü¤R©££#Bh``à›o¾ÑÝ;ikk#Z­vÁ¾ž?.—˱ŠK–,¡Óé«ï?„¸!ÔÐæV zÑjµJ¥255µ¢¢!ÔÔÔôÙgŸµ¶¶ŽŒŒ:tèàÁƒ@2 Ù”“““IIIUÌÌÌòóóMLL¸\®î lݺU¥RøÔ|_0Ü¿XR°ëëêê^6h¯sË0Ìﺡ¡ÁÄÄ䨱cPôjƒFƒätôÿøÐðx<ǃ9/\zF¡åË—;88 „vïÞmggB›6m233322¾;ÉÕÂ@"‘¤×!“É|>Á*8ŽÇãÍć)‘H|YE`½Ò«­Í T´´´„gp æ‹/]p «E"‘àÍ=ß’ùÀápPEOÑA †Þ´ n …B™ïË‚½`×ëÅÕé æëÂÔ IDATÚkÞ2hÁ®!4í,XëPIáp8ˆI"ºÝ˜‚ºX¢ø€ëçO„¿×0¨ˆ‘+ë²,3 p[o"Uà÷ƒæ ø‚¹öSŸÀP,˜õêQ¸\®î cÁ žö`~½ì–ýÐ3¢WØI P($I£Ñ¬_¿Þ××W$555a…ptt ©ªªBùøø<{ö Ç8pÄÀsrrD"Qmm-T™™™ILLÌË˳´´„3À{ï½õš5kÜÝÝ>|ˆu‘——·oß¾©©)])¸^£ÑlÛ¶M.—uð ™™™Aàyaa¡¯¯/仩T*333µZý»ßý...îÆ‰„Ïç÷÷÷oÚ´éáÇ0‰Ü¾}ûÝ»w™LfJJ –Ú¿{÷îèèèÁÁA ŠT©TŽŽŽ‘‘‘»wï†<úÒÒRKKK699iiiyôèѳgÏnß¾]Ï$KKK˜¤÷õõŽŽB!°n,[¶ X¸`B6lˆW*•o¾ùfDD$ B±X¼víÚˆˆˆÒÒR¬¨¹¶mÛváÂð!´~ýúÊÊJ„›ÍRSSu÷Àaaa8.--ÍÉÉéÑ£GðéÐh4û÷ïg±X^^^Ë—//--Õjµ0Í Þ¸qcqq1 >p÷c^äääDFF[Ø‚vb®ý磹mÛ¶·Þz !411A¥Ra‚…R(”/^EIVVÖûï¿ïëë;77wæÌX†;v ~"X•+W®àñxH_”H$À@rõêUXaaÐØõ………Ož<)½ë!}ÞÉɉF£™˜˜‰Dccã#GŽøúúÂ/ÌÌÌŒÇã9r$,,ìÈ‘#>>>¿ùÍoà±+))EuCCäxA–óÌÌ ÆžåàààêêÊápZ[[ÝÝݱƟX%%% £V«Ïœ9³f͸+P8==]\\üá‡"„.]ºÔÒÒÒÔÔÓ ¡¡!¥RÉápàe€UY»víwß}³`PkÆ:óóó;vì$Na×ëBïúñññòòrOOÏšššK—.ùùù)ŠÂÂB –}úôéáÇàÑ„ò7žQYY9>>~ûöíââ≉ ̶êêêù&a,,,„ŒíÚÚÚýû÷Ëåòúúúææfø ùùùi4šúúzà€î;¨ÂårOœ8ÇJX!ˆøÁK¨BZ­–Íf/vžƒ¹ví™Lþæ›oh4Lرòä hÛvuu!R´ùÐõ¢¤¤¤³³øèæÛ©ëš>óòòôROõò9±¹a\\\\\FËÎΆ}3 ÉÉÉ™™™~~~º…G ˜™™ÁA¡^×@V6ÿz"‘¸råJ‘H”››«7ûÎÎÎNKKÓ›*æååeffõÔÒ¥KB»víòôô„·MYYYÁ"ó1==]oºàççG"‘°OxåèZ» I`¶n œ ÎÀ°°°+V899EGGÃ/cc㬬,Ø¿Ààáá±råJ nصkFÃÈÀŒŒŒ0òòòÀ€ÔÔÔ€€‹•——$ºFŠD"{{{H¾Õ¸¶ +W®\ºt©îtPÏÎù놌—MñàŸÿ ±A®®®0 yƒ61B¶.õ …ÿ Æ¿°eii©»œÄ&&&FDD˜››ëÎô7mÚ477§Õjõ«_Áì!ÌJYYY KóJ ÐŠŠŠ èííÉŒ'Ož€GÿôOÿD¥RÇÆÆþÁÙ¶Á5à‡y7B¨È´Z-üß_ø¡¡!¹\îàà@£ÑÞ}÷]`N²··§Óé...ï¾û®——×»ï¾ëììüàÁˆ“)**ÊÉÉA=þöBp8œ­­í‹/BCCaƒÎÙÙùܹsðJOO‡“__߸¸¸ØØXȵ±±Ù¿?“ÉÄápXã"‘è׿þ5NzÌÂÂB•J…µpõêUƒ]`¨««³²²Æ–îØõ]]]aaaPÿÅ\îîî†uxôìÙ3Ì5~$ð2™lffÆÔÔtÞ±I7d‘3 ¥RÉ`0€DHåär9¬A!ddd@KKKøÅÇÆÆþå/Aa‚†CCC4H$Bp…«««@ 077×jµXãsssG©TjµZ,ÆkañâÅ@-´aÄ^@’îõsss<vk sýSæö‡?Ä€€.—[YY©Õj÷ìÙÖää¤P(,//?qâV¾yóæúúzfjj ‹ {{ûúúúÄÄÄË—/Ãܶ¥¥ÅÑÑñéÓ§õõõ§OŸ†>NŸ> /’’’GGGµZ ¦ëׯŒŒ´¶¶"„ ñŽŽŽ·ß~Ì€$wÝ¢¢¢ ¦’â¡ý‰‰ ˜jÌ¿¾¯¯O,777ƒ1𥧧ƒË¡ÙÙYx¬@‚Å eò“ᇆéÄÇÇö{ZZÐö!„ÂÃÃáÀ<--íç0ò§të ðhݺu˜k`€`€`€,ƒ­›tÿþ»eu™9pŠ® ½Ð¥Ÿ¤/~V¨Tª¥¥%dÒÉd2‡í¾¨F£áóùfÆ r¹|zz”±‚ƒƒI$ÒÐÐÐïÿ{ …òÛßþÖ××·³³S*•B¤%Ä– „„B¡L&ƒ° Ug³ÙkÖ¬ill´¶¶–J¥yyyeee®®®“““ÐãÌÌ̦M›âã㧦¦Þ|óͨ¨(¹\žíææVSSÃd2­­­áxâ:t øAÜ·oŸT*suušš1Ï;wîTVVfffšššOLLtttØØØØØØÌÌÌÌÍÍ…‡‡»»»_¼x!ÄårŸ?"ˆ …Á`P©T:þñÇ«Tª¦¦&++«ªª*ÿééi##£þþ~‹uúôéàà`Ÿ>ø€L&ŒŒ @ÆNtt´P(466¶±±9pàÀÑ£GóóóA†J¥&$$|þùçGûë_ÿzdd„D"™ššªÕj©TúÕW_驃ð‹ßÐÐÀb±ÜÝÝ›››ëëë{{{!ƒt Æõë×ÇÆÆîß¿¯Õjž?dX¼ŠL&ãóùÃÃà Ož<ùâ‹/¢££i4(!Âçp8ÍÍÍuuuÏž=«««ƒXo©TÚßßoll|ýúu …RVVfÀ="„¦§§!’ŸF£ p¹\8½Q(÷îÝ{ôèÑÜÜ\ccã|ŠT~)ˆD"‡;v옓“SCCÃÜÜ\``àgŸ}|ïÞ½Û·o‹D¢ŠŠ •oii!‰ FFF÷ïßohhõ __ßÓ§OÓét&“yîܹññqµZ­Õjïß¿___)ó333jµºººÚÎήººzvv¶¨¨ÈÞÞþôéÓ!!!eee -ÛÙÙ9222222<<, ©Têää¤\.ïîî.** ‡œn©TÚÛÛ;:: ¿Š¿ô¨°þAz øß :¾sçÎ-[¶`K0ssóùëµùÁŸ€ÂåååÙÚÚÞºu+**ª¡¡d&Þ~ûí‚‚‚òòrÈ&ÀÉnee¥P(*++ëëëcbbbccOž}útvvÖÉɉÁ`@>t__BÈÝÝÝÍÍ­»»¨E"‘Z­f±XÖÖÖÀëåå%—Ë ÄþÓétkkk‡Ã`0ÆÇÇcbbÁÀÀìhèŽh ùùù-莮ïà&‘Ht:ÝÜÜ|dddïÞ½aaammm¦¦¦þþþ½½½111˜|||¬­­!Jƒ……EXXXww·••Õàà ŸÏ§P(ááá Þ¼dÉ’®®.ݩ˂ÿxöíÛwãÆààà©©)¶lÙ2GGG*•Êãñ@ÈþÆR©î›ÍÖh4CCC‘‘‘111íííqqq@V ¬Ë–-S©T333qqq]]]YYY*• ÓBBBbccår9:88@;ÉÉÉ‹/®««Ãáp«W¯vqqéîî.((022¢P(žžž|>ßÜÜœÉd¦¥¥oß¾D"Q©T‰‰‰äää«W¯&&&Ö××gffòùüÀÀ@HÎzçwÚÚÚ€bJ(òx¼êêê©©)2™SZZºeË–7nlß¾ýÖ­[ -åííÌf³3rãÆ­­­ááá¶¶¶ÎÎÎ, ØDÄbqBBBIIɆ zzzh4Zll,…Báñx±±±*•jtt4''§¶¶Øu‹‹‹ƒƒCOO‘H|÷ÝwŒŒìíí«ªª¢££šæñãÇ›7o¾zõªZ­Þ¸q#‹Y[[ŽŽúøøŒŽŽ†‡‡‡††Bn~~~>DGGk4P€ŒŒ,))Y³fÍäää’%Kjjj6lØÐÞÞîææÖÖÖ&‘HFFFæææ q".— ´P?ÄœœœÊÊJø•Ô××çççwttX[[«Õj ‹ööv`AÎÊÊššš’H$§N‚ÊçÏŸÏÉɉˆˆÉd<O¥R={¤ËÆÇÇ“’’._¾¼nÝ:µZ ØOŸ>urrb±XŸ|òIff&‰D:þ|zz:Øâp8`oo¯ÕjY,—˵¶¶†«´´´¯¯¯ªª*  ½½R„Ož<ùüùs'''FÓÕÕ•ŸŸ:tèV«=wîÜìì,¼ƒ‹‹‹ÃÃÃàN“H$¥R‰JKKƒTo`Ô…„6¹\Îd2çææ”JåÁƒá'ngg<Õ>>>A*•¶´´deeºXzzúää$ csssJJ ™L>{ö¬»»;亭ZµŠËå.[¶ŒÅbUTT´¶¶º¸¸”––®]»2G`T===!¯„ÅbA"šH$¶©÷Þ{ïøÃ¾}ûöïßçÎÈC *¼ãÇ_¿~ý·¿ýí©S§úúúâãã©T*pþæçç‰ÄÎÎθ¸8*•úÇ?þqÿþý°CÄãñÖ¯_?77·ÿþ,†OLLlkkÃ6E§¦¦¤R©R©$“Ér¹è\»ºº¤Ri]]‹‹ –Ò¬Ñh”J%Ø]TTÔÑÑñàÁggçêêjØýºråÊŸþô'˜à+ „ÐÍ›7¯_¿^WW÷ÙgŸ+!´£V«“““££#ŸÏ’cèúêÕ«|>ÿã?622a0ýýýðJ+++[·n]AAAOO@ P(ÓÓÓ‘‘‘i8==ÝÓÓ#‰BCCƒ‚‚”J¥“““D" ›yéÒ¥p¼}üøñóçÏGFFVUU)•J_œ››£Óé‰诪««••dö‘Éä²²2™LöÑG±X,˜ªNMMÍÍÍ©T*  ÝM8›ðàJ¥‚ÞÌÌŒD"Ùz­V‰R,©¼055]¶lÙ7–-[vïÞ½O?ýthhˆJ¥Þ½{÷ĉÀSµvíZxáš$¼ÂÉd2LLL¤¥¥544(•Jhk>Ä_~ùå_|ñÓ¶âñx&“‰Çã!@dy!£ÇW‹Å"‰fffÀõ—Áq§Ñht:Îøà¥½aà „^˜L&Ä ¸¹¹íܹ!u¡kgÕªU„=3(Ǻ†¿gû­·ÞÂáp,K$Á 4‹Å6lX¿~½P(Äè$á* E"…B155"‘º‹ŒŒ$‘Hp PhB­¨¨(° K¡†ZØ4F£áñx:þÇ?þQ×<Ýaô÷÷ÿ×ýW]_€ŒH$îÞ½ ÃîETT{‡ŸŸþøcƒÑÜÜŒå¾nܸ1>>žH$FFFîÝ»÷æÍ›ÙÙÙr¹üÈ‘#§OŸÞµkW@@°d1 àu9uê¥YXXÐét™Læëë»jÕ*??? `òºÊuëÖ%$$tww8p@­V/[¶,22R*•‚Á÷îÝ{…Áb±xùòå;vì8þ}ú!$•JûúúÀúàà`¨H `£•Á`”——÷Ýw0-{óÍ7áëI"‘Èd2·8;;ƒú<ƒÁm…øøø[·n½÷Þ{ …BÏNÌž;wîDGGƒa`|›fggËËË›››= s hÆáÅ‹7oÞ¼xñ"<@ííí° #‘H0=066>~ü8pìÉdƒaddÄår÷îÝ»gÏ‹UWW?~ttôòå˺3™L¹\Îãñ~Á¡>ø!´jÕª÷ß? !”ÝÛÛ+jkk-ZäêêÚÖÖŽH$¸ÑD"ÑÛÛûøñ㦦¦ði†Á Ü¿?F‡ü÷?XÁÁÁJ¥òéÓ§mmmÓÓÓ „_"""¾ýöÛE‹aŒ¨¡±±1“M.— 3JÖßßå¡ÙÙYø8jµZ.— sÝ##£ææf™L£0>>íà 4jLLLV¯^ýõ×_#„®_¿~íÚ5„\.ÿë_ÿ O¡\.Þ¦Ï?ÿœÇãÉår°sûöí………zv‚º‹.}í÷`íÃ8ˆD¢¸¸¸ÒÒÒ€€Œ!TWWwñâEЭ8tèìµ¶¶~þùçÑÑÑð]ºti||óˆÍf+•J`%Å ?|ø°‹‹ ÚkìââB¡PzzzB§Nª­­­®®æóù$I,ß¼y‡Ã)ŠèèèââbpD(b7zppðСCàæµk×ÚÚÚ¬¬¬|öŒ…„„Àill vq°öa.^¼(—Ë{zzÄb1Ú`£äééyáÂFÓÞÞ¯X‡Ãd2¿ûî;Pw‚ I.— ü“™™YOOfpSSShhèåË—kjj^ß``­µ³³{üøñÜÜ\YYÙìì¬B¡(--miiyþü¹Ï©S§h4Ú“'OÀ‘ .Èd2¸Ñ …ø  …››Û“'OµZmYYÙ˨Ø~`óDع°´´411Á”Ò ‡Ã9;;ÿ"æ=!0“fky<Þ|>c½?þ›ñ2ƒáŸ<ï5ceuIËÌÍÍçKüL „††FGG×ÕÕmÛ¶mnnnppÐÏÏÏÙÙÙÙÙ999ôÜ$IBB‚D"€‰§££crr2ˆåyzz>zô(33S*•Êd²¼¼¼ŠŠ ™L¦V«óóó{zz4ÍŠ+ªªªrssHi±±±ÐÑêÕ«Á€àà`2™ü«_ýª¸¸8...%%¥««K—³ê½÷Þóòòjiin-Ø?;;»k×.‰äää¤kHHˆ‡‡ÇÀÀˆG888$''wttàp¸ÈÈÈêêꤤ$°!äáááîîÞÙÙ Ûc D¸víZЃm!„ŒÞ£G¶nݺhÑ¢††]ã—.]š’’ÒÛÛ›••£„Yëåå•™™éààó$½ëêêrss===Á`3330¸··wddD"‘„……‰Åâ—ÝŽááa(ïééÙ¹sgEE…P(ŒŒŒ® ;;; bùY¿{÷.ðVUUYXX‰ÄÜÜ\''§îîn¹\nkk›””ÔÝÝ}çÎ++«ÔÔÔ3gÎDDD@pðêÕ«ŒŒ8ޱ±ñåË—aÆ700¯gmm=66[ÉgΜ½ XG`BÈßß¿³³S­Vãp8wwwØ8566>pàÐL …B¦§âÕA­îùóç¯c|||ww7LÒ1ûBÉÉÉ·nÝÂìÇãñùùùYYYñññCCCl6ûŸÿùŸÍ FÏÚÚZ£ÑÀGY×ø¾¾¾Çb£´hÑ¢ù—111±¶¶žšš&Îù âñøºº:{{{<êÔ)‰DòƒnGnn.”c·Üìéénà±Ã8X]±b…V«‹Åjµzrr’ÉdZXX€BiEE‡ƒ¹9‡ÁØ2Æãñ …6ŠFFF€Ü#Í277‡Í\&üòË/B‘‘‘À¨‰uXYYõ÷÷cV™˜˜ŒŒŒðù|…BA àg­T*kjj@; cÉ‚ê###}ôQffæëØà6ÂìGòfÿýû÷×®]{èÐ!È377‡ý$°Þ‹zÆC*„áÃ(MMMaR±°jáñxóÄãñr¹ÇŒŒlذá/ù˺Àu‹ÝÂíÀÖOàïÏþ`!„`KC*• :uêÃ?¼zõª···•••J¥‚ Ð.+..ÎÎή¬¬¬¬¬\¾|ùW_}ƒ%“É@.!äèè(—ËSRR¦¦¦`#®©© ‚jjjΞ= ’µ%%%°ûµ´´€qqqW®\«´Zmss³¥¥%Xøî»ïB€ÀÄÄ„““¼>ÜÐЀÙ?33“™™ùðáÃ×±ôB€" ìß²e ú/frÌþÁÁÁo¿ýöÊ•+ ØÚÚúûßÿ¶|°Ñ“ÉdEEEzƧ¤¤ ÃÁŒROOÏ;ï¼£Õj‡‡‡-,,@s~ƒsss111ýýýNNN8Î××÷ÝŽ“'OB9ܰۙÞÇê{ñúvll,œ0¤¤¤`ú"K–,ø m~ü´“åïµßÎÎ^x`¿µµ5BˆÉd‚Ì fÿkâçžéÿov7£¢¢ÂÂÂÀß_±±±ºÚv /caa‘œœüŠ£ =è­D A=-<‡¤¤$.—ëââÇv‰‰‰óù¢ øŸBtttBBÂãÇ“’’D"@ˆ‰‰!‰o¼ñFKKKff¦••U]]ݺuë¤R)lÆÅÅMMM …ÂÎÎÎÔÔT[[[;;;§Õjóòò¤RiTT”­­­………B¡ úàƒºººûúú@!ýÖ­[¶¶¶ÆÆÆñññFFF6lèíííêêÚ½{÷7àC••UZZì—ÏÀoIDAT/8ÇKHH=ß_zè xgÏžMIIár¹ ÓÒÒâàààââ¢R©@ÎÄÉɉÃḺºâñøÒÒÒǯZµ t‘÷îÝëèèÏ Çãp8ÑÑÑ ŒÛÝÝmccƒÇãcbbÈdrFFÆ_|áééyûöíU«V‘H¤ÆÆÆ¤¤¤ÒÒRçààÀáp|}}ÝÝÝétú7‚‚‚nß¾½zõꪪ**• 4$---Øa€ÿ˜ÀÓéô¤¤¤ÉÉIxnBÓÓÓk…}ìÚÚÚ&''±Ùå®]»Ôj50yô÷÷¹»»+ŠáááÉÉÉsçÎÙÛÛƒ |:ù|~WWWKKKqqqzzºî¿J¥‚w›Í¦P(ccc@ºüðáü¼~ó›ßXXXH$’¥K—R(”7ÞxVÑÑÑ&&&l6[÷\Ï^x™LvÿþýGi4š…BÊÇr¹¼¬¬l}_ x àÜÜ܆††Èd2—Ë¥P(\.·®®B2úúúÌÌÌ~òTF 0À øG!99Y©T …ÂE‹Aô´üxà›ššþüç?#„ׯ_ÿKÛcÀÿ„‡‡›˜˜GÅ/m‹`À+ñüi÷ HSóIEND®B`‚java-algebra-system-2.7.200/images/device-2012-11-18-jas-trinks-out.png000066400000000000000000003060631445075545500246770ustar00rootroot00000000000000‰PNG  IHDRX² °+sBITÛáOà pHYsÄÄ•+ IDATxœìÝwTWà;³» M:VEQ°7±÷Ó¬‰=1vÅÏ%&&¶X»&–Xc'öލ((EED:ìÒYvgæûct²ÙÆR~ÏÉÉagîܹwö:ïN} ¨r¨Ênü›Ð4ÍqÇqZfIŒÄV„ŸCe®ŒU¿ç敨l‹YYYÉårÃË»»»?þÁƒÅÅú6Š©©éœ9sòòòÒÒÒÊÖ0x§6lXTT¤P(ÔgP´…K×ñ íÚõ°k×þ}ÏÂ×/äÒt¢-d~PÄ¥]€¢(ggç?þø?þHMM5p©”” ‹N:]¾|™eY]Å:vìhee•””¤õ·T"Š¢êÕ«çîîžœœ¬:]TÍÔ¡MW‘±‰±}íjvµHHÑv­»X86`Š‹Òî0…ù•Óh”:ZYY}þùç 6ìÛ·ï‘#GŠŠŠ ZÙÙÙqqqíÛ·úô)MÓÕ«W755522"„0 SPP••Å0L‡âââd2YYºï’»»»æÁŒÈÔÜ¡Û0c{Ššþ»|‡^ËË2³ž„j „”X"±©!±´•ØÖ”'¿,Œö&ˆê¥‹I½†b Ûܨ`á”61³lé#2·,xñ¸ .’è8 +u ¬^½ºT*U(r¹ÜÄÄÄÞÞž¢¨‚‚‚ôôt]‹PU»vm“úõë/X°ÀÔÔ”¢Ô¯MrWXXhllœ““S§Nøøx|8lll:tèðìÙ³ hîà Ešæ(š"„~;—¥iB8¢Yø-ëŽýêÍû•¢iB¨Äß–&Ä1LÏ,­$6nëÏQ´(bx#ŽQBŒê6^†ÉÎ,x]g·yQ÷^ü4‰UjœÑ-m ¤(*111,,ÌÍÍ-(((//oÁ‚FFFQQQ»víbYVkô²±±=z´›››D"áµ277'„´iÓÆÚÚzÛ¶m¸LðH$mÚ´yñâÅ‹/\]]uS²lW—š>.5Åå)v†Ä3zªÍº}Vr‘pT‹cOÕ⥞YZ9M]A‹$ª%g¯/Š÷ݬR.±®ÑtG mŸéçöiTš€¢(''§Q£F¹»»S¥T* ! …‚ã8KKK333=‹×«WÏÕÕU"‘è)Ã0 _¡X,®_¿¾³³³–_ð~Qeddäåå•™™ùøñc-÷ȨàiQÛº¡}õ¶Õ¥dè-L!,ÃÊålqQ©fY¶íaÝy jÌ«ÞÂÛ¼Y‡ôsîÍÉO‘™…¹{»ÔãÛEDzřÉÒ s6]?¢(-QÏ @(‰Ú·oß«W¯?þØÌÌLQÇÝ»w/;;ûÉ“'zÎdš˜˜è‚iii.\8~üx@@@QQ‘‘‘‘©©©! €wŠã¸–-[RõèÑ#=·:òL%"G+SšÈ¤¬/R÷NŽg¬» ±ë;Ji”ĨÞÌŸv,‘'Ç —EæV„¦²¿¯Ù§Ä×pÔúÌ A§F†‰‹‹+,,|ñâ…pw EQÕªUKOOÏÏÏ/qQU\\œ‘‘!yËÈÈH,ó×>¡T*ÅbqjjêÇlÐÆ€wI$5jÔÈÌÌìæÍ›úyæÕªW3ÊW(‹Yn\טôœ›/’K\ª´â×Ï"„âØ7']k}2µ8#YxÚ¾ßh¡ŒR–A8RÍÑ¥àù#~ %6¦DÚCžAã¸ÄÄÄüüü—/_B(Š¢iºuëÖ-[¶´··ðàAvvv‰•ùÄÄÄ$===..Ž*‘a˜GõíÛwÊTºúõë7jÔ( À(H‘¯¸öÈÖÌxfç&‰Ò¼£^¾‹}9§rÜeTñƧӟLïÃýó.V^˜è_gôü‚gåi‰æîmí}ÉküÝЛeärù«W¯úôéãààÀ²¬¥¥e§N?~ìïïmÈÃõÖÖÖ …"77—BQ”‡‡‡H$"„©ž8566‹K}/+T,{{{WW×ÀÀ@Cux… æUv^çúöÅ fwh\ŽÜ ðYvUoúê´S¿%¾Ðœ™°ea½¯rßzPt~ô=Ù –­ºj­ÆÐ“““³wïÞFuïÞÝÑÑ1//oÿþý±±±ÅÅÅ%ž5æ9::~òÉ'§OŸ.((¨W¯ž©½½}çÎÏ;WPP`mm=pà@­ÏWÀ{cggשS§°°0©TjøR!ÆbQ‹Ú6‡#ã_Hó(Šz§g÷Ì·±ðô’X×0soC©VÓ‰’5\y4Ýÿwéí³lAÞËõ³â7úÒÕL˜¼\ÇIß1…yZŸE44r'“Éîß¿åããÓ«W¯ÌÌÌ¢"m·úèXœ¦éž={¶hÑB.—ó7šrGQ”X, 2 óðáÃ/^à à=‰DÍš5ËÊÊŠŽŽÖzÙK÷u+þi’žWHSGˆÊsë¼3·î2Dbm/ :ÏqÌ?žŽçÿ~;Ÿf=׈ͭ!òĸgÿ^ø*FkcJwèJQÔÀ‡.‹óòò6nÜøäÉC®š››·oßÞÇÇÇÚÚš¿k”¦i~ƒrDz,Ã0ÅÅÅÙÙÙ7nÜ 1üÚ,Tš¦[´hajjÌ0ZÞÃï´ûôésóæMÕ£ #‡&Ó~2¶u š«sl±4ãɦEòŒ=«¦DbŽe…ÇáõÏâß»&<>¡R”¦hŠZNQ”H$25',Çäq«ë%m¥~ÅZ^^ÿÀŸ\.7üa^^Þµk×nÞ¼iooocccaa!‘Hhš&„°,«P(òòò233322Š‹‹q,ðþÕ­[·N:J¥²gÏžºöÃütµ¹LQAÆýë´‘±Ö÷H³ŠbeI©'ø·ƒ8‹Óuôűœjpä8N©T攜šÔ3ÍÍÍ{õêåæævûöíàà`ýùµ¯RÇ‘5â@%266‰D%Þ´ÏçHPßcS”î€Â}à) ËrWV“?¥Yá €wŠ211©ì6T¸²¼t›2nõ‰êæfÛý6NëÏjfŸ(ŸRg¨çÊ㥠B8B¨· …˜ªú‘SùƒüóoòvYÕÕ¦ü=ñƒÎáÿZe „˲ büë•92KWlSÞ¿²êO(ognÌ’™'/±*×Z–EŠ$iAÙZPe „˱šÿøT“ºV?}ÑUÉ0+ŽÜ ‘ÁqZ/þBÈçŒêî‘'WNßv9#G®í’!QùPÁÊxz“eYŽe8–áX–ûûoþ#ãdgNäy7|Õ×ÃXL½- ZŒáXÆÙÁìãÎÓ¿_f&&Ãh”ùGùŠí6¯<§FµÏ²25jél#W²¢Úµ#Ã~ý²s²4—/Ìrœê ÕFNù2éÑ#%3§™“m@T"î €÷¬<7Ëh9Ûib$úî“6¶¯_än9B8Nzà€Iûöµ EŠ"üRŠ¢(ŠPTannñãÇÕ:v=~z4Ãqo¦¼ýÏ|äÈÚÇŽ14ÍÌ Lžúõç^ †µw&§Zÿ›µ¼¢²-Ö°}Ÿ|Á#„ã8nJŸf­k˜¦Žû’ÉÈx3•ŽyLLaX›Ÿ¯:‘#D‘’R¡HJú{Êë×Eáám'ÑäQB&!,_3ïuØE¼^*\Ùo–!,!Ô›ØôE÷&^õí3çÏeišªUëÍTŽ#„È !”ƒaYÕ+Š,ÃÈ_¾$ÖÖBIÂqE11©sæ þùg‰˜Ú-šã¸÷s‰pÛ¶m...ýúõctÅ€ÿ¨2_#dÞ bVMÒÓÓYbZ­æ¶mpÐFQ„¦û´¨2èYnA±O~÷Ýw}ûö¥¨7a3+++11q÷îÝwîÜÑÿà?ÏÝÝÝÃÃCXü½5jÔŒ3öíÛ·eË–eKìÅòåË{÷îÍà8.333&&fË–-OŸ>5¤› ©O¼½l—W ÷y6¸]ÃÔys‹BBÇQoï%*ü#̨øçc«WŸ }‘[ çXŽ•×zëV·nÝ&MšÊd2Bˆ••Uÿþý?úè£~øá×_eKºÄH©5¯4¼xñâ'N¬Y³¦Ä©±¶¶vssspp0°uêÔqss ÈÉÉ¡(ÊÁÁaÔ¨QÇŸ4iÒùóç Ê ¼Ïš‹§ lÝ¢¶E‘šk×&ÏŸ_póf™ M;vtX½š•ËûµmP¿¦åÏǃ‹Š•üUÈc!EQ¿ýöÛÙ³gùxдiÓ3gÎÌš5kÛ¶mEEEek!,--ÝÜÜjÕªU¶ÅÕp‰½ (jÇŽ/^ä :ô÷ߟ9sæÅ‹q^  Êüf™7/|éÔ¸Vãü´„O?‰ëÙ3?"ÂþÇ%Í›³ÅRÚÿ$nnv+V䇅½ü裗½{×/ÈìÔ¤&áŽe | ‚eYæ­ÈÈÈððp›¦M›Rµxñâ 6Ðôßý]´hѯ¿þª:ÅÙÙùçŸ>uêÔ®]»ºwﮢ,,,æÍ›wäÈ‘“'O®ZµÊÅÅ…Ÿ»hÑ¢>úˆ¦é¶mÛnÚ´©S§Nüt]åËÙ Í'NœÈÊÊrrr2°rPSÞÇ'Z5ª“sæ¬"#C‘—'=q"»°ØaíZ‰‡CQ !†ÿ'vuµûå—%'=q¢X&+ÎÉ‘þõW»Fu Ë•íñ ŽãLMM9ŽËÈÈà8nРA#GŽT { PBQÔÉ“' P«V­!C†>|xèС|ì±··?}úô·ß~ëææV»ví &\ºt©cÇŽE5iÒ¤AƒEÕ¬Y³U«VöööúË—³š<==­¬¬J[3ðʹ7G„1¥,,à锹¹ÅJå©XÛÕk$Mš~\(vq±ÿå׳ñòb…²°P¨M"ú{E¥jž™™ÙìÙ³Û´isùòåDþ¶U«€jS(Š ðôôôòòš8q¢H$š;w.&—.]Ú²eËíÛ··iÓÆËËkæÌ™666«W¯¦iúË/¿\»v-˲gΜñööö÷÷ç8NOùrö‚×»wï9sæÌ;÷§Ÿ~:tèPJJʲeËJ{yxå½FȲ,ËßBÊq !,Ãøß‰få€5?§Í#Žæ8Nÿq¤~}ûõÎ=Œ?ô¬CS'†aXŽ#ÇÒ4Ëw|ÅqË–-¿üò EQÕ«W‹ÅW®\™2eŠWÎX–]°`B¡ „œ:ujòäÉ^^^íÛ·¿sç΀RSS—-[ÆÏ=xðàgŸ}æããÓ¹sçÀÀ@>qÇ0 ßTýåKìN‰½?~¼ð7MÓáááe¾B e½Føö@eF©Ží–eå© èóaÏmW­¹º²zÏ‘Šœí×­¿õêø­'ŒRÁð—¿aa)JX‹G„ׯ_?~üø±cÇŽ=šššÚ­[·1cÆ~&—¿ÉžÈq\dd$!ÄÕÕµY³f666111ªs=zDiÞ¼¹æÙΦM›–ª|z1jÔ(;;;[[[—I“&ÙØØlÛ¶­Gïÿñ€ÿ€ò>>Á2,óöh…#„eŽeY–;~û !\ÕkRçÎ)~ñ‚¼=.T=2ªWÏnÍÏWŸ¼:vë\Å2oÂ*GKÓ,ÕêˆðرcÂý– 6¼|ùòŒ36mÚT†Ó†™™™„5j˜››BòóóUçæææBªU«¦¹`iË—¡ Ã(•Jþ9Â?ÿü³¨¨hÏž=ãÆ»~ý:n(­rÜ,ñDz,˾="d(Šý{:sìÖãkQ¯ìW­;;³o…cG‘££ýêÕמ½>r3ša”Bm|Xeù#·µx×(÷¦A,˲Ϟ=‹ŒŒ´³³suu¥(J©TŠÅb‰Db`íìì!©©©ñññ,ËÖ¬YSuníÚµ)ŠJMMÕ Ò¥-_ª^h-|ïÞ=BÎŽ”M™á›3– ÉâfÍøûbDuê$¤JߦØeXFy$ðQÀÓD»ŸVŠêÕS½;FT§ŽÃÊU7b’>a” Žeø¥âS2Œš6}S¦V­W©™eNÌËqXV½zuBHjjªH$jÙ²%NlllìììÔn–éܹ³0¥sçÎ ÃDDD$''?~ü¸iӦ‰M33³nݺ^¿~¿4HN]¦¤¤è/_ž^hÅ¿Œ&))©T5¯ìi˜øƒ´€ð¸öŸô#Å)VÆ=úæík„B,LåÅÊB;¬X‘<¾âÕ+Bˆ¤vm‡U«rhI‚±13JÏ.xSš#WBc§JLMicc‹o¾Á2L™_—Â_¥³µµ%„\½zµG?þøãÞ½{«U«6jÔ( ÕÂÅÅÅÛ¶mÛ±cGVVÖ AƒÜÝÝ/]ºôøñcŽã6mÚ´uëÖÝ»woݺ5//oäÈ‘NNN;vìàïä|þü9Çq^^^cÇŽ xùò¥þòåé¯wïÞîîXìââ2hР¢¢¢ßÿ7Ž”AY¯roó¾L‘®?yÇ«©‡‰‘äÚ±[1‰ì›ÀÅÑõ¿‘]%"ŠpŸ~Zã§Ÿ’, ,[sÅ BÓÅìöjêÞjXÇe{¯Á.úeÊæKlÇ&­ ¡®î¿ö2EÊ¿»lŒŠŠðûûû:ô—_~™>}z||¼þòåé?E¸k”eÙÌÌÌ{÷îmذáÆxÅ@”ñ>ÃOË–ÿ]EQ„#Ü?_­æQ¿æ¸¦Iÿ›OÆÈÅ¥æÊUl^.!Ddi•øõWLZ‰œ6oþ-äEäóîmf Š"Q©ímšúè3[ô\)¤iš¦iáÕ‰üÅ6þ£­­mÓ¦MããããããùçùP'‰!ÇÕ¨QÃÝÝ=555::šŸ%TeddÔªU+ccã‡J¥RÕ¨&‰š5kfbb"¬KOy=-Ôß þoÕø’lin)Ue¾k”QÍP¯u\ÛÖ\žšÂ°,á¸ÂçÏ Ë„%f1,ÛÞÝ\Á¿'E©,ˆ­ck—$¼MT{m%íä…X¢g"˲éééZœ„›-“““SRRÈÛ£ºlQQÑ;w4gñ‹?|øPu–þòzZ¨¿Z @y”÷¡þ2,õv·Íq Ë^ {ÎrlëÆNìÛÐÆ2 K—î©ùr*qEz ”vŽÒ>|eŽe9áKŽã(Šâ÷ûOd†úûvO–eYFÉŽdž Ër„á8-¯“ œÀ»TŽS£ÿ¼$(ü-üQX$'VÆüûÒˆHÄrœ\QÌ0,ËN"a•JB's¬ÊU1•4ö×PïFy³Oèù/âÙ+‘[cQ: !}ú¼JÏΔåeåäÇ%g˜õìÉд¸~}IÆ‘±‰üûhÞüÇi«Í°êJ«œ×Ußþ>j{3E–[p%ô©Ï²ï%…RJ|.ð!Ë0á.?Þo`½bÉ•¨ÙùÜ?ý¨þ!LÇQ!T¼2>>ѼÏèåIäz‹ÖS¬œÆtÍ)jÓux'Êsjô½ÔáÞ…2~Qõ¾#2¡Zý_Ùm¨4bJTÆgêþ(B0˜««+E•1ç3€.WðŽÐ•ÝøÂÞ ÞŒ+xG JC €* ª4B¨Ò JC €* ª4B¨Ò JC €* ª4B¨Ò JWv>8îîîÓ§O¿páBvvöçŸNQTqqq\\ÜîÝ»³³³}||FŒAQ”\.‹‹ûã?¤Rie7*S«V­&MšDÓÿ¦Ü½{·B¡˜8q"MÓ,Ë&%%?>44”㸺uë.^¼øÑ£G[·nõóó«Y³¦jUñññ+W®dYö‹/¾èÙ³§‘‘у¶nÝ*•J…µ°,›‘‘qáÂ…   ŽãÞ{wá«]»ö”)S5j”ŸŸöìÙS§Nñ_ô¤I“:uêDQThhèöíÛår¹®Q¡:ÌZ´h!ŒÏìììÐÐÐ#GŽp·lÙ2­Ã¯fÍšZ×UK¯^½¤RéÒ¥K'Mš$“É?~!•JÍÌÌ&NœÈO|ðàL&»uëVµjÕ*»Éœ† VŒ9Æ “J¥/^¼¸÷Vÿþý?úè#~âýû÷“’’’““§OŸNÓt³fͤRéÑ£GE"ÑÑ£GïÝ»›““óøñã{÷îíÛ·O$­_¿^&“EEEÝ»wO&“]¿~½ZµjÂZîß¿ÿúõëÌÌÌ)S¦¨Fߪ *Œ+{{û{÷§_¾|ùÑ£G2™lîܹ4MïØ±C&“Ëd²?ÿüS$éªÃLu|ÆÆÆfggïܹ“¦i­Ã¯FZ×^Ù[Þ»^½zÉd2??¿É“'gggOž>žeYooïÞ½{gdd¸¹¹ùøø´hÑB$]¿~]©T2 ³zõê9sæäççó‹2*ø2ùùù¯_¿¦(ÊÞÞ^ëðÓºv†aÞ_ÿ+ a ¦M›vóæÍéÓ§ŸýìÙ3ì’`äÈ‘¡¡¡ááá;wîTûÍqÿk©zõê%ÖcggGÉÎÎæ?¾~ýšã8>‚öîÝûúõë7nÜ(((à¯&V|O Rݽ{wÅŠööö 3gÇqVVV„¼¼<¾ÌíÛ·wïÞÀ4dT¸¹¹-Y²dãÆ}úôyùò%ÅÚÀµ¿³¾~@p³L ¤RiFF†“““§§§°?Ú³gϽ{÷ºuë6räÈ   ;wb—TÅ]¾|Ùßߟ㸔”ÍÁ`ddD1d( BˆXüæfµjÕ(ŠR*•üÇüüü””SSSWW×–-[ž;w®Šì§ªŽãÖ®]»ÿþQ£F}üñÇ‹/®W¯ÿCJ¸V'œšâiŽ Íj›7oÞ¨Q£‚‚‚›7o®X±¢¨¨ÈðµÏ˜1ã?¿Ãa <8räÈuëÖ¹¸¸ôëׄϞ=;~üø’%KX–mÛ¶me·*_RRÒöïßåÊÍàäááAQT\\\‰qëùóç„777þ£——!$>>ž_0((hôèÑüý\Ÿ}öÙþ‚Y4qâÄ£Gººº®_¿¾k×®III}ûö'„4hЀ/óý÷ßGDD´k׎†ŒŠ£G6jÔÈÃÃã“O>¹ÿ¾®q¨uíUa˜áˆ°ü¹õäädº´%¡ IDATŠ¢¬­­ !-Z´˜2eJÛ¶mE"Qllle·*Ÿ³³óäÉ“ùýËõë×ù‰õêÕûꫯ<==ûõë~þüùÆë¯ç¯¿þš;wîgŸ}–’’’––6cÆ …BÁßÎGÞŽF™L&•Jííí«ÂªªQ(=zô°°°Ø¾}»½½½­­í‹/Î;çëë;bĈW¯^Œ5J$=}ú´N:İQÁqœR©,ñÀNëÚßI??0„yùò%˲Mš4 '„Œ3†eYþ¾¬_~ùå?ÞJäããÓ¥Kþïo¾ù¦  €âííÝ©S§ŒŒŒS§N-]ºT8é‡L&ûæ›o~þùç… R•ššº`Á‚;wî 2DµXjjª««kÛ¶mïÞ½‹³£ÿ%üñGƒ F½k×.BHLLÌÂ… ÓÒÒ¾ù曟~úé‡~ iúÕ«W~~~999jË £B¸šX!kÇþ­*¢(J,Ó4MÓ4ÿ‡æDž°Ñª*Üæ.àdž*Š¢T'ŠD"aœðÓUï¦QfB‘HäêêÚ¼ysÍÈ—‰DüŠÞcG+_W4M‹D¢Æ;::òOã·£ÂÑÑÑÅÅEu¢ÖQ¡:ÌÔÊh®Km®Öµ@©U‘Ö;ÅïÎ*»–*5®*·§Ug;ópjàC„žU\倪6üpfª4B¨Ò JC €* ª4B¨Ò JC €* ª4B¨Ò JC €*  BUµ.ð~`\T<ªÕ_ñ•Ýø¯ Ö€c”•Ý ƒˆ)ró@Õ…›e JC €* çEá0oÚžà?¨PyQÁæîí0® Â!Â;ÑðÇC¸ü +|¨ Ƽ FT8ŽQb\A…ø€ÿŒ›É¬­„¦+»ïÒ?ãJØ£iDAøïûg¼Cä€*MüOŽ®dÆB¸Jj À»W¯y'|R „¯Ÿš&4EU Íx?^Å‘ÄgÂAŸJÌ£hD@¨8B8¶²UU†e$ÉüùóišŽ=|ø0ÇqÞ,(¿Zµj%''Wv+tRkÞܹsMMM_¿~½gÏ–e+±a%³°°ËåÑÑÑ«V­¢iú=¬ñøñã_ýõ»^ׄ üýýE"Ñ{[£åi€D"9zôèºuëô/^â*ªU«véÒ¥Ï>ûŒ¢ÊòƒI%¡¡¡ãÆÖ~æÌ™äääàà`~û¼7eÜÑÓ4½{÷îÅ‹³,ûìÙ³ÜÜÜÜÜ\™L»}ûv;;»Šm¥‰‰‰D"©Ø:5¹ººz{{óûkÕ5¶oßÞËË«<Á  é²®†­\¹²Q£F«V­bYVOãK\…D"éÚµ«““Syú®«’åË—¯Y³¦cÇŽüô!C†„……½ç PF …Â××—ÿ9Ÿ˜˜¸oß>//¯Î;Ïœ93++k÷îÝû»^$½‡ƒ³•+WJ¥R±X¬¶Æ .¾ç#Cº¬µa-[¶ÌÍÍýä“Oø ¢§ñ%®Bí‹.]•Påïï ´íÌ™3!!!8"€÷¬,;ccãÿýïW¯^½sçÇqsæÌ‰ŒŒÜ¹sgBBBHHˆ››[çÎ7mÚdnn¾pᤤ$BH—.]ÆŒsëÖ-±X¼dÉ’´´´Ï?ÿ|ܸqõë׿ÿ>Çq‰DëtBȼyó,,,âââô”!„Œ;vêÔ©Í›7ýúõŒ3nÞ¼©výràÀ³fÍòòò’J¥©©©üÄÉ“'Oœ8±Aƒ–––­[·^³f ˲§OŸÞ³gO+++[[Ûèèè¼¼¼Θ1£_¿~ Ã<þœ·J*•Nš4©yóæªM"„L˜0aâĉ^^^ R©”Ÿ8|øðéÓ§ûøødff¦¤¤hÖ0wî\Õ.ÇÆÆNŸ>}̘1vvv>ä8N³a|ÍË—/·´´œ9s&˲ªebccgÏž­gš[Uí‹öõõussã×®µS<µ¾<|øpþüù;w3fL5}ºfÍÕCŸÃ‡§§§;vìáÇiiiü&]¾|yAAÁ… nݺ%“ÉzõêU½zuµÔºüìÙ³+W®ÜºuK©T®\¹R³aÂ7õôéÓ]»vñmP-ãááQ\\¬gZ¿á‹^³fM^^ÞàÁƒ)ŠÒÚ)Õá¡ÚKKK…B‘ššzãÆ€€…BñóÏ?óÍ322JKK®eâˆ*‡ƒƒCDDDaaáÅ‹?þøc~¦u¢@3,]ºtÙ²eÌÊÊúòË/)ŠrttT(Ó§Oç‹-Y²¤¨¨ˆ„ …bóæÍ‰D$íÚµ+))IÏtBHZZÚ† „]³fKKË”””ýû÷‰D¢;wªB''§ÌÌ̵k×ò †……9r¤^½zÙÙÙBm‡–Édjk¤iúòåË·oß622rttÌÌÌÜ´i_þ÷ßOII±··ç[µoß>###Õ(X­Zµ‚‚???‰Dbee4oÞ<©Tºf;’Û·oŸ8qÂÊÊJ­µ.oÙ²…/àÀŒŒ {{{Õ† _™™YaaáÒ¥KùJTËT¯^]ÿ*t}#¾¾¾ŸþyAAÁ’%KD"‘ÖN©öZmkðÿøãþ«ÙµkWVVV­ZµøÂ§OŸæƒ!T :--­uëÖC‡ÍÈÈØ¾}{xxøÔ©S3224'ê¹PäììÜ«W¯îÝ»{{{geeñgºô{ùò%Ã0 ÃÄÅÅÙÚÚ–8]ÿ²­[·¶³³;zô¨B¡`&&&FmoooKKK''§Í›7oÝºÕØØØÕÕµC‡fffP*• ü|ùRó¤˲ÇqÇ0LçÎ---ÿøã¾üÁƒíììÚµkÇÇ¡ÈÈH¥R©zëQQÑ“'OF5þ|GGÇ.]º¬[·®S§NÕ«W?tè_É”)SV¬XÁ/¥Yƒf—8`eeÕ¶m[î-†a„f×®]["‘dddh6ž/cÈ*Ô¶|Ÿ>}6lØpîܹ•+W2 £µSšª­èÑ£G|8P½zõ¶mÛòM*•Z[[ký–ÞšÂ0Ì¥K—fÏž½qãÆÚµk?ž¢(­uÕrþüùîÝ»wíÚÕÃÃ#??Ù²e†ß^Á²¬Öº¦k-S»vmBÈ«W¯øéšñÌÖÖ–¢(š¦ÍÍÍÍÍÍ>|P£F Š¢´Æ?­ììì(Šzýú5_>%%…âàà k¥„Aƒùûû><$$äòåËÎÎÎ666ü²|ù¨¨(ᚢžf³^¾|I©Y³fÙn°4¤§j[ÞÚÚÚÔÔ477—a]ÒlŒÚŠ„ü$¡ý¸•Ž&„ôèÑcß¾}ÑÑÑcƌٱcÇ Aƒ†Ñ:QW-ü1Ã02™,$$¤^½zE¥§§+•J33³÷Ð >6hÐ@WçÏŸs÷ÇŒ;v̘1£Gž7o^bb"Çq760¨ÄÅÅq׺uk¾|óæÍ !ÑÑѺÊ7hÐ`È!«W¯nÛ¶­———››Û’%Kø¸ëééÉW2hРÏ?ÿÜð¨æææF‚±š¤¤$…BQ±¯üùçŸ?üðÃèѣǎKQ”ÖN•ø“Eè`Æ ùvòí·¶¶–ÉdØZ€Ò¢ëׯöìÙ† .Z´¨qãÆK—.MNNvvvÖœh`EEEÆÆÆü/^¼àïZôðð1bÄ»{"$$$>>~ÆŒõë×wqq1b„Zh¹zõ*Û¤ƒƒƒD"3fÌ Aƒ®_¿ž––¶páBGGÇÆ4Hk óóómmmΟ?íëë[§N''§Y³f………Ý»wO×a™™ÙÚµkçÌ™Ãq\aa!ÇqÅÅÅ/^|þüùܹsíìì7n¼nÝ:Ÿá€lmmkÕª5gΜ¤¤¤Û·os'4Lµ© ÎÎΚ7|cªá8nýúõçÎ[µj•»»»¹¹¹f§ø›‡ûöí««#_|ñEÆ œœ|}}“’’„zkÕªƒãB¨Dtvvö!C:uê´cÇ…BÁ_ÔÉÉÉÑœh ¨¨([[[þÉôåË—7oÞ<99ùÚµkü-øï¨………sæÌ©_¿þÓ§OÃÂÂÔnèç L›6­fÍšqqq™™™+V¬¨[·nvv¶¯¯¯‡‡G\\ÜÝ»wÕ{œ8qÂÉÉéåË—îîîÓ§O·³³‹‰‰‰‰‰177Ÿ5k–žåÈÈH??¿‰'Êd²ˆˆˆ—/_®X±¢¨¨hæÌ™... ÏŸ?÷óó3d ?yòäùóç®®®sçÎÍÏÏWmXÓ¦M…tëÖ-á²¥jÃ|5±,;uêÔüüü;v<{öL³S,ËΟ?¿_¿~ºVפI“¹sçæääBú÷ïokkëïï@•LëÎKÏNSí®Q±X¬z EÓ´X,æ§(ÊÄĤM›6666üt¾Œê"¥®« EQb±ØÓÓÓÂÂbÅŠ£ñª=‰DžžžmÛ¶•H$|%üR­[·vpp‰DZ×HQTݺu›5kFÓ4_I‹-š7o.tSs#¨n “–-[Ö«WO¸’¯¤uëÖªÕj>ò[{þüùÖÖÖ-Z´H$ÂJU&,غuë¼¼¼¡C‡ _PF×* Üò"‘ˆo­ÖNéªMøX£F6mÚ¨¶ÿðáÃ7nÜÖ…»Fà_ƒß5çåå:tÈÝÖûyoVß¾}çÍ›7`À€ñãÇ'$$\¾|YkÛ(ŠÒl!-T-£µ—-ÕJÉ?vREQëׯˆˆàïÊ)ÕºJ¥ uª.Ò¯_¿´´4þiNBHll¬\.¿wï!ü;tëÖ­{÷îÎË!?ùä“ÈÈÈœœœÔÔÔ3gÎ4iÒäÃi[y˜™™½xñbÊ”)†_a¥iúøñãk×®­Ä—†—(44t„ B ½½½»wï.܈ð¡£Þªì†ü?ß(‹Åb±H$ú ÚVNexÕªH$Zÿ0ÕªUKµSàˆèfòÓÊÌÌlóæÍááá¿þúë©S§ÊŸê¯Ä5»#‘Hœœœ*»£b®!©fòÓjΜ9ãÆ»páÂ¥K—ŒËŸ\°Ä5VŠJÉ\XN±±±|:ɬ¬¬'Ožüøãz~£8::ž8qB*•ÆÅÅ¥¤¤è)|óæÍœœœ\ BBÁ˜1c²³³ÕŠmÛ¶MkÍBksrr^½zuæÌ™V­ZiÝàLjˆ~*EFF oß¾}åÊü€ £šÉO«“'O†††ò·ÎWHrÁ×X)*%sa9%''óé$}||üüü -Z¤ë :uêT\\\Ïž=mllfΜYPP +[a³fÍ:tèСC‡C‡%&&vêÔ‰ÿhaa¡VÒÞÞ¾}ûöÞZ¾|yqqñ§Ÿ~ª5¼ ­íСçŸ~úàÁƒèèh+++Í’Ë—/—ËåŽŽŽ„''§¢¢"†aøúXXXäææª¦L€ª¬\dòäÉ-[¶|òä‰ÚeàÀýû÷—J¥ÇŽ‹ˆˆøæ›o\]]MMM—,Y²víÚÉ“'GFF^¼xQ,/Z´èÈ‘#=zôhÚ´iTTÔ–-[„GËÕ*៹ֵFÁرc;uê”pèС1cÆüðÃ|…jµ•jÕ|á“'O<˜ÏVÁ²ì°aúvíÊ0ÌéÓ§øNNNFFF~~~[·nMNN8p`ß¾}9Ž;}úôåË—ùœ‹šUM˜0¡U«VR©tÏž=ü[ÜæÌ™óøñã‹/jæSÔZa©¶¡¦ÜÜÜàà`–eoÞ¼Ù§OooïU«Vi-Ù¾}ûãÇ_¿~a˜7véÒ¥[·nëÖ­Ó,%TÎ0LHHˆR©$Ú^.šžž.¼%¼~ýúãÇ?tèÐñãÇKlmppp~~þ©S§¼½½Ïœ9£VþÆ ,èÙ³çž={ À²¬L&ÿŸ«ÖL¸zõêììì¿þúëÆEEE_|ñEQeË\¨5·_JJÊ/¿ü¢ì-Z¤«B÷¡æ÷˜œœ,Õ©S'11qëÖ­º~g„„„>ÞÀc÷Ó§OÇÅÅÕ¨QCWÕÖB|||”Jå°aô>š‘‘Á>tèЃÏŸ?/‰~üñÇ‚‚‚Š}#+ü»-\¸ð;“'O¦iZJBGGG­™ü´¦ý“H$.\¸{÷®‘‘1 ^isòt¥$ÔZŸ-ÖÀUó…U3ùíß¿Μ9|™ .ðç{K›¹PWn?Í÷Ôè¯ÐÀŽh ZÉÉÉ wîÜ NKK ׇ|||bcc³³³Ïœ93~üxþ ÕÏð@øõ×_ >\ÏEÖäää;wÖ«WÏÑÑÑÛÛ›Ïn¯+]×õë×oݺ%‰âââ6oÞ¼|ùòôôt±X|æÌ™°°°×lxwÄ„Íó`,Ëòy {öì9vìØíÛ·ûí·;vìØ¶mÚ­}ûöB&?Žã„LFªiÿ!|Ú?Õ¬xš-àÓà±,+¤ÁÓZ‰jî@Õ5 TSr'¤$ÔZ¿«5pÕšé¿øâ‹6mÚŒ;¶zõêb±˜‡‹®Ì…Ç­Ò¥K—ÂÃÃcbb¦N:~üøíÛ·óeteòSMûGyøðarr²{! žÖJJ̨+%¡!MÒ¿jµd‰dÿþý½{÷ÎË˳µµMMMUkŒá™  4{öìáÇûí·wïÞ0a‹/4û¨¿ÂRuDSLLÌúõëùè{ãÆ ÿ#F8p@³<ÇqYYY¿þúëÆ[µjuòäÉüqäÈ‘zÞlذºuë¾ÓWÀÀ¿Ë›Khªg®¤R)¿—éѣǸqãø»-vìØ±yófa'ÅïU7n¬¶{Òþ={Vˆ¥J^¡«’¡C‡j]£@HI^bmº²$R¸W¯^}ôѤI“öïßÏqÜ™3g4OÍ ™ ùÄ{º26hРwïÞ«W¯^°`§§çÙ³g—,Y2qâDÍ```…ú;¢ë‹àgñs£££)в²²¢(Jm;wëÖí÷ߟ8qâõë×Y–½ÿþÝ»wùüˆå4kÖ¬®]»Ž1"33³ÄÂ,Ë ‡æú]¾|9//¯gÏž!!!|¼¼}ûv=X–½pá!üÒ@qvv.** þꫯ„\ ++«¤¤¤Ë—/;995nÜ8**Š¿uÅÄÄ$:::  víÚÕªUûòË/‡ BQÔùóçïܹÃ_•Q»F(Ü¿páB…B¡«kkk­kšdbbwóæM—°°0–euÕV½zuÃW­V¸ÿþJ¥ræÌ™¶¶¶³gÏÎÍͽÿ>ßµ“'O>yò¤V­ZE=zôèæÍ›uëÖurr ‹Åj]öôô,((X±bMÓ7~ýúõöíÛišÖÌíg`…ú;Ò¼yó;wº»»«Ö¬zÕ­M›6'OžÌÉÉñðððôôT+\½zõ„„„   æÍ›SÕ¥K—ׯ_ó·VyxxhÖÌS»F¨YÒÝÝ=##cÿþýÎÎÎŽoÕ¨QC³Dãf®±,;}út~þ,tTT.@Élllúôé£+»!dÔ¨Q))) …B&“íÝ»W¸u¥gÏžÑÑÑ………ùùùÉÉÉß|ó MÓ¥ „º*ѵFÁ!CùW¯^å¡ÖÚtBC SuòäI¥RY\\|ùòåS§N=}ú”ïÚ˜1còóóåryÓ¦M»uëöäÉ“ÂÂB¹\þøñcþA{µ.Såë뛞žž““STTtûöm>§®Ö»F»víZb…ú;2lØ0…BÑ¥KµÐÂ0ŒR©T(999| å¡C‡jîÔ©Óõë×‹ŠŠd2Yaaá_ýÅŸžÕZ˜§5KΛ7¿ÀÉ·6|øp­­Õu5`ãÆ………uëÖå?š››K¥Ò}ûö!€Aô¿!EW&?­iÿTï³70¹ á¹Õ𤙒Pkm¥ZµÚ‘HÔ AƒfÍšñ/øVM4XÚÌ…%æöSí]‰êŸ_xx¸Úvÿ“ð¾r­…ù:Ú¶mkee%4XkaÍ&i-ÉÐl†®Öjýe¦«jkçk@€Š¤+XVH&ÒæÔŸ’°TM*±°žj§4 Yi6LOùµk×ò<² þÂjÓ ¯ù]”,ma€ÿ¬ÿjJŠ¢+µïû,ü.J–¶0€ªÿÔ¾ƒ`€ß!꿱*_æÎ­U«Öž‰Þ)|ûeVÂ]Ç·µµ «ÄC«ò´áCh¿V‰äÏ?ÿlÖ¬™ê+NêׯÏqœ\.׺ˆ®¹BUß~ûmqqñÇ+°³‰¤nݺÙÙÙUá‡ïCoe¨çÆ …¢b¿}€*‚&„<{öŒÏñ&“Ébcc·oß.¼ØÄĤü¹UžONйsçFé)ð>Û_QV®\Ù¨Q£U«Vñ†/[¶,)))&&&%%åÆjï:×?W¨êûï¿_³ff¿¶mÛÊd2>íÿªnCr–˜z°ÄŒƒ†$,q<’V°C‡j4¼~MÂx+± š–/_®õÛƒ$&&ò9Þ:wîͯ‹¢¨(ŠAƒñŸiÓ¦7öîÝ[XPØ)Lž<ù«¯¾Ö;a„©S§Ò4ýŽÚ/пìÀ·lÙòã?¶lÙ’¢¨Ñ£G ìСÃܹsù¿ÝÜܾûî»ÆSõÛo¿=~ü˜¾ÍÂÂ"==ý÷ßç ¤(ªaÆüû<ùwè™KQ­ŠòÑGwíÚUí)x™LÖ¤I¹\Þ¶m[Š¢T¿š¦ƒ‚‚øüDjßÔ¦M›ø‰4M?~üܹsš£PÅ?2Ïg]Vûº…2...III{÷îÕ\‹žñ@éÕ«ä(Šúúë¯ 233¿ýö[š¦¬T*GŽÙ¹sgµþ«ÇÑ„jclÀ€~~~ÖÖÖ„›¥K—<˜¢(­ß>„ÿ‡-ü«;vìØ£GøØ)))%æÔ•PëëQôä“Óšo¨ì¶lÙ’››Ë¿\ÛÂÂ"##c÷îÝÂŽ©ÂÛ/(UοիWgdd˜˜˜BöîÝ«P(Z·nMQÔÂ… óòòøÆ?}út×®]| }ûöU*•Ÿ}ö™°ó¢(êÚµkAAA"‘Hÿ\µª!FFFiiiëÖ­SÝìîîîßÿ½¥¥å† ø¥ ÉAhxêAC-éJ4Xb~AÊ€´‚M›6Uë !õ°ãü3jޱæÍ›geeñ+Z·nL&ãÿÖo ’˜˜°‹“u^ IDATtéÒeË–|(‰ôÏU«ŠqúôiµC7¾€PÌ„†§,1êI4hH~ÁÓ jv°Äú?äñ¦ZÖ1&‹ýüüd2Yÿþýe2ÙO?ý$|Ýšß>”èÍŽÃÙÙ¹W¯^Ý»w÷ööÎÊÊŠ×ZšÏ{Ç0Œ÷N5 Ã0B@Bˆ®ãÇ‹‹{þü¹¿¿?!„Ï'§šoa˜ƒÚÙÙµk×Nu×Þ¿Š¢øôéÓëׯó÷Ƚ‹ö—¸¬jο­[·ò9ÿ}||úöíkkk{üøñ=zPåééÈq\íÚµ%IFFF ߌ´V%•Jù“f!ï„ê×ñìÙ³'N=zt÷îÝöööGUÛ{ò©ýüüªU«¶qãÆ   !5c©”˜hPëxP-Ú¤I!­àÉ“'­­­ù´‚ü}•Z;¨¿þ¼ñ´Ž1Žã~øá‡èèèƒ>þÜÏÏOHW¢ùí@‰ÞÂóçÏwïÞ½k×®ùùùË–-ÓvEÈ{§+  ;wî455511qppèÖ­Û78Ž3$ßÇq'Nœèرc:uºtérîÜ9aÇ÷>Û¯5矹¹ùÇX–½{÷nÛ¶m‡ rÿþýÇ{zzzyy9;;Ÿ9sF³þœœBHÍš5U'ÚØØðÁ@ÿ\­ ¼{žÏA¸nݺ… Nž<¹cÇŽ#FŒP BêÁ>}útíÚµfÍšZo.-Q‰‰µŽÕ–––BZÁ°°°R¥üW7­cŒüªÏN”Á›½|^u†ad2YHHH½zõ üí/d4|•|žÃ0ü?]!ß¿^]ùööìÙÃ0̪U«,,,öîÝ+ü³Ÿí9ÿÆŽ;f̘ѣGÏ›7eÙ+W®4kÖÌËËëÒ¥KÁÁÁ/_¾œ?~bbâÝ»w9ŽKJJR( ÷wïÞÍËËS½Á¡N:žžžüaúçªUų¶¶–Éd%6^ÈAȲ¬jB~n·nÝž?Þ½{w~Ö9õ ŸhÐ××WO¢A­ãAU9Ó þ«Ç›®1Ö¢E‹É“'_¹reܸqB/ˆÁß>¨Òò3¶¨¨ÈØØØÀåCBBâããg̘Q¿~}Õ£ ­wêrþüùèèh__ß:uê899Íš5+,,ìÞ½{j»¹”””«W¯>üÞ½{Ož<Ѻ|oí¿zõjllììÙ³$ɘ1cøÛýýý«U«Ö Aƒ?ÿü“a˜«W¯öèÑãîÝ»üñD~~~BBŸn‰’™™¹wïÞ±cÇΘ1ÃÚÚºM›6û÷ï·²²Ú¾};ÇqúçªUÅ«U«VLL ÇqzrB$ Ÿù¯M›6k×®-((¸qãF³fÍøEBCCÅbñòåËù¼½½;vìEtgþš6múí·ß;v,<<¼nݺú ꪄ¢¨ÂÂÂÇ;::^¹r…ÿƯ\¹R§NgÏžñGrz–ÕUÿ¿e¼éc6lxõêÕ Aƒž>}ªzKšðíØ ZaTT”­­­Ú ºΙ3§~ýúOŸ> “J¥Â¬ùóç÷ë×ÏÀ@ÈqÜ´iÓìììbbbbbbÌÍÍgÍš¥õdÚŸþIÓô‰'tå(oí/,,œ6mZÍš5ãââ233W¬XQ·n]Š¢ÒÓÓÃÃÃ###ùKGÇŽ322vâ„[·n©^Žš={öž={¾ûî»ÔÔÔ;wšæççÿöÛoüQýsÕªêß¿¿­­­¿¿?Çq 4øòË/ÕŽ•³k×®Õ¯_Ê”)QQQ...ü"¹¹¹#FŒËåÁÁÁR©ôâÅ‹¡¡¡³gÏfFµ„¡@ÿþý­­­GŽûü­óçÏ7lØP ª•ðCCCårùÉ“'ù/Ýßß?777,,Ìeµú·Œ7­cìÿûŸ———ŸŸŸB¡X¼xqË–-/^LÓ´ê·_bKà43ä éî ̨5  Ö»Fõdú¥ Kàçëë+“ÉTïr|í/UòBòχ øúU[غuë¼¼¼¡C‡ }¤iÚÚÚºC‡ŽŽŽ"‘¨OŸ>÷ïßçÓ?W­ªÃ‡߸qƒožž†ä ¤ N=HëÈ8HhÐÀü‚tiÒ R?ù÷Œ7Í1¦ºFÕÑ¥úíÀ{¥? `ii>”-°³³8p`||üÁƒ+ðñò·_O›u•_¿~}DD„Útá!8韫ZU¿~ýÒÒÒ:wîÌÏ*CŠ>­‹¨},±Úò0°L…,ûoo%Ž1µoÞ«÷–ðã?ÎÎξ}û¶““SV[)Y ù' ×®][þgŸ…ªÂÃÃ'L˜ zRÚŽ²H‰eÊ_ÀÀ2ïbYUÿ®ñªúíÀ{Å ¨d{G+ÒsB¬<Õ¾Ÿö«‰D•:‡¯ªV­ZØV ×x÷P5”}ûøñã¶¶¶aaaÇi-P­ZµsçÎ?~ü¸Ì(U%––––––ùùùjÓíììLMM ÊÜŒ2+q+}È+š0aÂwß}wôèÑë4díºÊ”vÙò÷Ôð~@GBÚ·oïååEQ”æl‰D¢gy‰DÒµkW'''­‹ÈÀJZ´h˜œœüêÕ«ÐÐÐ6mÚðå;vìx÷îÝW¯^%%%………uèС<)ƒ·REéܹs£F*¶NWWWoooC¶˜!ÝT-£:® YVµwåߤ†÷«BèùGT¶ecccssssss³²²žýôSŠ¢jÔ¨ñêÕ« 6DEEqwáÂ…/¿üRõÇõèÑ£ÍÍÍwìØÁ²l‡:uê´~ýz–eÝÜÜFŒqøðá§OŸr7lذ®]»2 súô退ŽãÔ¹cÇŽ hÝn¥±cÇvêÔ)!!áСCcÆŒùá‡X–:¨vO³=ªsÕÚ¶yóf–eØ¿©TzìØ±ˆˆ~]õLž<¹eË–Ož<ö­“'O¦išßP„ &ÿŸ½óˆâÚþøÝÅHQ¤¨‚%– Å.±÷‚šÄË/b‰øbb¢I4‰ña Ö(Ï®Ï. (X@A@AŠQ@@)²€€ô¶í÷Ç}N&;egwv—59Ÿ¿àî½gÎ=÷Ü;³3wçûξ}ûHÿùt“¬óÅ_yµwïÞ9sæàrn¯HH;ýúõ7nu@CBB&&fÁ‚ÏŸ?W³Ìöovv6B¨uëÖA¨Õ±³³;~üxnn®¯¯/õòâÅ‹7"„^½zµzõêÍ›7‘fcbbÜÝÝ›7oþðáÃÓ§O/Z´hàÀÎÎÎÁÁÁøáÍñãÇGUÕªU«ÂÂBÑP‹w|¿177—Û&†Û*¤V­Z!‰š5k†JNN–J¥‰äèÑ£t;öööøË1=þ.\øæ›o†J>¦ÕŸPèÐ;*¿þú«››ÛÔ©Sñ°2ö—­_$-[¶Dà üñBï1~ùò%.,((@ÙÙÙqô‘1·µí Ÿ ={ö ?ÏFEDD\¾|ÙÛÛ›zý€^ÐÏ#‡3gÎüøãsæÌ™;w.A;vœ2eʯ¿þêîî>pàÀ.]º|ûí·§=y_¨sçΡüü|ú„ ´°°˜={vYY.éѣǕ+Wúõë§R©”Je~~~Ó¦MñúHîêê:pàÀ7nÄÆÆ¾xñbíÚµyyy111*•jÔ¨QÓ§O_µjÕĉ?úè#!?ˆdŸ;vìȧ²þdee©Tª£GÎ;÷ÓO?3gΚ5kFŒÁhG*•ªTª®]»Ò÷úÿç?ÿQ([¶l±´´}úPÓöêÕ«gÏžÔüaë#cnS;˧ƒj¹A¶¥F[­×pS Ž!¦™6uvß Ô­­ðæ;vìš5k&L˜0þüœœœ°°0î·è潇µr›‰'fggŸÌœ93%%¥¢¢¢°°088¸[·n¦¶ð͘1£¼¼<**ÊÉÉ©±}0¦µÿÁÛýñÉï4µ‡=ø!þA[cû€Q=B=z„뀡n˜™™á ±íü=B=z„Œu@PH[GGÇ .¼~ý:33³  ôÀ°€¡@@±è i{éÒ¥ÌÌÌ‘#GZ[[¯X±¢¦¦Fà,€ Ð#=BÐ#4E=ÂþýûŸ?þöíÛ …b÷îÝC‡õôôܶmc§è"Ð#=BÓÓ#Œ‹‹{üøqçÎq õ‡ùèÐ#D Gz„¦§G8lذŒŒŒòòòàààùóç7iÒDÇ€&@ôAÐõ###ûõë7wî܉'îÞ½{Ù²eü±Ú#ôÃs}é^¾|ÙËË+...,,ÌÙÙ™¾¡Ž¡Zn=ÂeË–,\¸ÐÆÆ†jëN™2뺹¹©éž|hccCh¯GÈ‘Û<;¨1h*•ª´´t×®]cÆŒ>|xëÖ­aã(Ð#=Â?=BÑ#ôôôÌÊÊúðÃñ7ŇÆÄÄtéÒEShô=BÐ#41=Âøøx‰D²iÓ&|Ú2dÈ€þøãn;èè‚!èšœaEE…··w}}}llìëׯ¯_¿¿jÕ*x , 6Ý8z„ GHôÉ¿ Gˆ½²³³swwoÑ¢üvŒ!^F¥›¢žÎÇÒ})ä±z„<½ÒÖ8ÝŽFËzq‰ÍˆnÖØ r”¼e€!€ibZkñßô05@P€¡Æ: G€Éz„zô뀡ÎmïÞ½[QQQIcÀ€¦öhþ&€¡@@±èêÜÖÕÕÕÃÃÃÃÃãÔ©Syyyƒ Âÿêý® Ð#=BÐ#D¦§GH¾D¿¿7..¿Ynó€A=Bz„ Ghzz„˜dggí{-üC=Bz„ Ghzz„8€=BÐ#=BSÔ#Àh0\iêKpÕªU^^^ëׯ‰‰Y°`Áá8£¡Zn=B„ЫW¯V¯^½yóf,\‡(z„Í›7Çz„‹-RÓ#<~üøèÑ£ccc«ªªZµjUXX¨1Õ#äð‡ £!B(99Y*•J$’£GÒípë~óÍ7X|L«mõyöŽ Ö#œ:u*]ì¯z„!¼ÇX[=BznkÛA­‚€A=BÐ#üÐ#4=BŒ è"z„ Ghbz„Ð#=BÐ#49=BŒ ›n=BÐ#¤z„äßFÐ#¤WÀàâRT7E=%¤ úRÈcôyz¥­qº–õâ›ݬ±øûz„¦‰i­ÅcÐ#ÀÔ=B=z„ë€!& èêÐ#d¬z„:·ýôÓOËËËÕÄ÷íÛ/£Cz„=BÆ: G¨s[[[Ûþýû{¼aÓ¦M XwL.ð?@ôAÐäô_½zU\\Œåââ2þüS§N?nó€A=Bz„ Ghªz„¡   ÌÌLÆW @!蚪áÒ¥Këêê¼¼¼à¦(Ð#=BÐ#4Q=Â÷Þ{oãÆ§NºtéÜÃz„ Gø§5Ð#4)=Â]»vUVVúùùÁ+À €!èþ 蚎áÊ•+‡îççWRR¢›xz„!蚘a÷îÝׯ_îܹGµk×g;ì—z„ Gz„&§G8~üø–-[~òÉ'd¯³²²®]»fäÈÀ?6Ý8z„ GHôÉ¿ ­GHï5Ùq ˆ!ög릨§ó±„tA_ yl€!O¯´5N·£Ñ²^\b3¢›56ƒ@À41­µøo z„˜ G¨@PcÐ#Àd=B=z„Œu@PHÛŒŒ ,CXQQ‘››Ü»woS{® @P  GÈXô…´•J¥ÇŽ8p ‡‡Ç¬Y³’’’RSS[´h¡'øÐ#=BÐ#49=BLeeell¬R©Œ­®®¾téÒ!Cð r»€Ž€!=BÐ#4==B©TºgÏ2þXMlÚ´ipwôè"Ð#=BÓÓ#”J¥lß¾½££ã!C"##³³³Ù”¿è‚!蚨áüùóçÍ›§R©*++?~ìããSZZÊ+tôAðOk GhRz„ôõõÅ£`š/a€¿ Gz„z„¦£GˆR*•ò7п/ /@!Ð#=BÓ#À˜€!è‚¡Éé`lØtãè‚!Ð#$ÿ6´!}|0†¸ÕMQOçc 邾òØ=Bž^ikœnG£e½¸ÄfD7klþ>€!€ibZkñßô05@P€¡Æ: G€Éz„zÃÈ{ IDATô뀡ÎmÏŸ?Ÿ˜˜HnYŠŽŽNII!ÿŠŠ 7²ÖüÍ=B€!cÐ#Ô¹í¦M›êëëBNNNuuu …¿ÇÒÒ²²²’*L€@@ôAÐäô#""¾úê«‘#Gþç?ÿ™0a‚R©,++›|hccCh¯GÈ‘Û<;¨1h‘‘‘VVV‹-zõêÕõëײ²²¦M›Ö®]»û÷ïÉôè‚ៀ¡é膅…UUU92..kŒŠŠ1b„R© …!èÐ#DôAÐôôkkkŸó÷÷OJJbÜmˆ:yòdEEùêíÏ>û¬¼¼œ<ùÎO­¼­¨¨ÈÍÍ îÝ»·¶g,mX[[ÛÐÐ@•6☣£ã… ªªªd2YAAÁæÍ›µŠáÁƒŸ?^YY™““£¶ÝqëÖ­¥¥¥2™¬¢¢‚T[ÔK KKKŸ>}ª­«lÑcs3mÚ´ââbú[Ñ1ŒùcˆaÒKþ¨%v÷îÝïÞ½[SSS]]âèèÈÓΧŸ~Jífß¾}ZK¯^½"##kjjêëëããã…O·»wïVTTTÒ0`Ÿˆ1úãëëKï)ùâuhœe:¤ÛÔÓ9nçÏŸOLL$+GGG§¤¤ÿFEE…‡‡kµMï#‹¯W]‡g W>ûàƒ*++gΜɈ©S§â“ýܰaCQQÑ‚ æÍ›7oÞ¼)S¦ð ÕÛY³f%%%¥¦¦âʨ1nܸ#F0Zf“6âØ¥K—233GŽimm½bÅŠšš­d½¼¼V¬Xž——Glj‹z‰á°aÃ6lØP[[ûõ×_ówU7aH‚ ._¾|çÎú\eËC “^òCOì»wï>|øðý÷ß÷ððHMM=sæ Ï…ÉÖÖ¶ÿþäÜ´iSCCìY³èGçð*:::))©wïÞݺuKII¹uë–Àp¹ººbN:•——7hÐ ü/ÏëtFZ·níAa×®]R©”¿†¨ÆY¦Cš±M=ã¶iÓ¦úúz¼|;99ÕÕÕ) üJ#KKËÊÊJF]cŽ,¼^t6ÂoÞ<‚ –.]ZSSSRR²~ýz‘H4yòd¹\þÉ'ŸðÏ7CŒ,ÏHr77Ð:lœy¤ÆŸÖñ+ð+ݽ{÷Ýwß%ÿMMM;w.uoá!C¢¢¢ßE²~ýzKKË;wöë×,´³³+..^¼x±­­-Ö ¤6±¶¶¶µµ3fŒ••UTTT}}}qq±šYÒÛªª*‚ ÏÁX ˆ^^XX8nÜ8rߦ³³3~ý¦@Çrss‡Þ¡C‡ŒŒ ¥R9kÖ,„ÿ˜ª7P ---Û·oðàÁáÇwîÜ9)))::¤¯¶mÛÖÉÉ)((ˆç.V¶èq¸J\VV6yòdò­¡Æü1Ð0QûŽtÊ =±ñObðMU*UNN޹¹y÷îÝSRRð±¸#²sçÎÚÚÚµk×2&›WÕÕÕ]ºt!ßÍÝ©S§ÜÜ\ᢿ–ÿVgH#[¶l :þùKDášø_êTnÇ0K—.­««óòòRKWžY™1cFmm-ùàMH¸0ø!ã2Ç50>>>¥¥¥ôz™eÚ¦¢M=$,n·o߯7ú2336mÚ„¿î'$$Pk¬‘ÕÉÆZ‡ :¸J¥Ož<¹|ùò¥K—.]ºôã?ªÙÑ ~Ú¹sg¹\¾lÙ2º7AAAaaa‰D­3ëÖ­333kÚ´éÕ«W ¨ùG„§§geee]]Ý”)SÔ¾ØJ¥R…B!—Ëe2Yiiidd¤Ú=~ø!'''77·®®®ºº:77777ËŽSí¸¸¸üðÃûöí+--%5â…8F„µµõÊ•+ÃÃë««>|Ø©S'µa¸råJÜsñDxèÐ!¬æºcÇ|yH„À†‡‡ûùù­Y³fË–-yyy‘‘‘ju¸]¥GÃUjCr K8òÇä—üaLl˜Û1„Ð{ï½WXXHÿˆgV#„\]]_¾|yôèQ2&BÂ…á8jLiº?˜›7o^¼x‘~8á³ iŸfˆéD($nÿþ÷¿KJJ<<<ärùĉûôé#—Ë'Mš”ýûï¿S}h¬‘ÕÉÆZ‡ :GÆJ¥Ò½{÷âõK,Ó ++«ˆÂÍ›7ùd˜··wCCÃŽ;üüüöïßõ}FïÈ“•±ºÚû¾/^¼xêÔ©³gÏÒ`ß¾}Mš4!ß<©6 È·SÆÄÄ„††¾óÎ;Œ¯m$ÝøñÇ«««ñ¾d!Ž‘G‹Åîîîyyyôg¼Ÿþùš7¸¸¸h<ÚØØ444`Õx„Ѐärùœ9s„ÇpïÞ½8,"‘hüøñ2™ ›åé*=z®RÞºuK«JïÃ$<Ø{æÌ™ô üÁðÏŸÐÐÐŒŒ Æ­ä<³ÚÎÎ.111&&†ºmAxVsœ¹ó„Ñ„½½}eeåêÕ«]à,CÚ§b: ‰~xèÐ!©TŠŸ­¦§§>|X¡P,X°€j¤qG–;’²Ϙ1Ãpó±dìÿF¿O„Mp`íÚµÔüxýú5µf~~¾L&£ÕÉÉ)>>?A±´´$bäÈ‘%%%ááᇠ9wîœJ¥277W©Tԛ澾¾r¹ÜÜÜ\©TÒïð*•Jªj<ýSRËT¥RÉår5 =zôؼyóæÍ›ãââT*)mXTT¤³cžžž‡Z¸páíÛ·•JåÇcbbºt颿Ûï¿ÿNþÍç‰ ‡Ú¢ÀâG8P©©©A´hÑ‚ (!³¹Ê=|µÄ- ‰jÙ²åË—/©%lùcˆaÂ̶ľqãB¨}ûö÷îÝCµmÛ¶¡¡!--§c+W®>|¸··wII‰^a-,,¼¼¼¨,ÃÅ wJ3úƒruu577òä ã8Ë6iƸ………UUU92..?‹ŠŠ1b„R© ¥i”‘åÉFY‡Ÿ={† 6GÆâý?lJˆ²‡moRZZÚáÇé7TÅo˜3gŽ\.8p >{ß»wïÞ½{mÛ¶uppxðàÚMsêqé…½%¹ÿ>ãfH›¢¢¢{{{{{ûÈÈÈôôtŽ5oÞ<'''::ºgÏžA :ôåË—'NœÐöíÕŒ÷g ===›7o~õêÕììl¬´.0†äýý¾}û^¼x±¢¢¢G|î§sDÍU*Û·o‰D=zô8xð Þ7Ϙ?†&¤üaKl‚ âãã###Û´iãââ’œœÌ¶m˜îX÷îÝ‹‹‹?îìììøÆ·l^!„JKKÇŽëää„-4mÚ F·g„lþ „||| …««+ÇA…Ì2þiFí£ÚÔ·èèh¥R¹|ùr|Dü8ù?þ`[Œ9²Z­WF^‡3àß%6:ôøñcŽE_í>ï!Cþøãšššººº'Ož 6Œÿ#MþÞ⥊ñ£)S¦`jkkÓÒÒÆŒ#ܱAƒݾ}»®®®¬¬¬¶¶öÊ•+:¼‚>mll‚‚‚ð}ö¬¬¬©S§ê%†äýýŠŠŠÄÄDoooþ À=6WIð=Xü,aêÔ©2™lèСA°å!†I/ùC¢–Øýû÷OLLÄŽEEEñµúš5kð-<(Æu몪*|éMZ˜1cABÂ…ÑíDÈæBhéÒ¥ …ÂÅÅE+ƒˆß,Ó6ÍÈ>ªM=qÛ½{wmmm»víð¿Íš5{ýúõ±cÇØ0òÈ \¯ ºa1 \ù¬OŸ>UUUô…„ ªÒAb±¸K—.;v”°(Î[Òº´¡Çp[;;;ww÷-Zhû]#¢ÈÔ‘ˆ™ÔÆ ýþ>7lÑcs•äôéÓ¸ƒ6lxôèþ›- 1Lzɪ‡tÇ:uê„¥ ù;F>PQ­œ¡[À Õ=m[±ùCÔÁ>³LÛ4£ºD?–Îq£ÔaLɆzYë•ÖáÆšGºCÄöíÛ­­­µj¥ÃLÐ#ltÌ2«BÐÖ¥qãÆ <êïïOîçÎì;7&ë•i:¦l}Ñ9Í8dâq3ÁõJ[Ø&¸ñŠH$:þ¼¿¿¿/·¿ñññ , ÓCôF”Šüò¤ÐȈÅb};Ј´iÓ†{õü„i¦H£z’ Ð$‰ Cƒ+m|gÐÛ£ÌǦ&DM ¡^ê¿ßbA!ŠhRzÓcR5"¦&šÈ¶Ìo¬Á¦ä§s’°­3&²þ6þlr\C‡¯¯¯¯¯¯Çb60ŒÒhtFŽùøñãúúúòòòÇó_—õ.ЦwÙ6y¢E4¶ÔY SzÓ(¨¦CR ”Ѥõ4"$[Ê=²e>ÇJ¥Ãi‚"’„m1…õÇñg€MŽ+!!!))©gÏžýúõËÈÈ ãé·@³·H™M' Ch/¦†µµõóçÏoܸáìì<}úôââbü3a>¾é]Mï²móD/Šhl#¨³"¦ô¦QPM‡¤â(:F“ÖÓˆl$SÇžùlå|0&(FÛ$a[gŒ¿þ0bˆø3@°ÈqUWWÿý÷øg{öìÉÍÍ¥Lï2fþ_™ÞŠZ¡F¢­4šÞÞÞøÅ%¸_iiiôä6‚(2€lÏ<1œ"Û TD¨ôF†…MPMÛ¤â¨Æ•ÖÓè‰ÀlÑUØ2Ÿ­œ?BV©N­’„m1þúÈ!⯆±ËqåääôîÝ!$‘H\]]srr¨u $cÆæ‘•ùè­”J%Ý›N‰¶ÒhjØÚÚ‘žžŽÛæçç·nÝš:¨FEc!ñט'†VDcSz¨ˆ&PéM£ šnIÅ(SÖÓè‰ÀlÑUØ2Ÿ­œ?T Ú®<R$Z% Û:cüõÇÈñg€þ†!OOÏgÏž=}ú4--íÉ“'jwó -cÖ¸Ê|ôVÞÞÞv×0:H£‘Œ7N.—{{{c³ûöí«©©¡ÆÓø¢hú•m#m2æ‰qÑ0Ô¨ˆ&Pé Ã-¨¦URi ”)HëñŒnÙÂ'ªÜÐ3Ÿ»ÜÐ+£T'þI¶Îmý1~üµ8̶mÛ ÷íÛ·ÿþââbü­–ü”0°ŒYã*óÑ[qØaS\Ãh%¦‘HñòåËmÛ¶8q¢´´´¶¶–ï !Ц_Ù6Ò&cžh;½(¢!Ú TD#„)½!M‚jHˤÒ(ãgÛ”1\¶hŒª¶+’ÆrC¯<ŒRTø' AŒë [9Ï>òÏãÇŸ5s¬¯¯Ÿ?¾X,‰D_}õUee¥ÚvpÃɘÑý1¾2½£6Å5­¤ÑèaiÑ¢ÅO?ýtåÊ•½{÷îܹ³¼¼\-žÆE£ 2°ÜÑè#(\ PzCšÕ–I¥1PÜþGZgd®Ù‚t’©S;®V 1·?ÂW‚Iª“ŠVI¶Îgý1~üÕ`½iéââ"‹?~ŒïDgdd˜››;88PïéNÆŒŽñ•ùè­í°)®‘h%FKYYÙúõë ‚P©T§NÊÏÏW‹•1EÑ1¨ÜAÑ0ôLOOGº*¢ WzÓ(¨†´×Ûã·?Æ‘Öãã‰F "S'­<RTûZ% Û:cœõ5Fü™Q;¯º¸¸”••]¸pÁÆÆÆÎÎîÆùùùxǦwÛõøŒ5’2ãö3ªKlŠk$:H£Qqww·µµEÍ™3§ªªjË–-Œ­ØFA¢h½Ë¶!yÂ6vÑËÑ*½ñTÓ*©øÊYÄgÊpx‚tÊA2u”ãjû„Í$låáꤢU’°­3F^8Ðoüù† ˆ¹sçfeeÕÖÖÖÖÖfddL›6MÛ'Ìú=š 2‡âF7i4µ8ÔÔÔ”——WUU8pÀÜÜœ§o=Š¢‘þèW¶ éš'zQDcAÑ0¥7>‚jÚ&•pÁQ#HëñwF‡l$SG9®n 1#Ò%Ñ6IØÖ#¯?è7þ¬ˆØå¸ºví*1¢ŒG[±‰)óIh¨5×MŠH$rrrrww÷ÝwuXËèa”èâÈãËÝ YÜI#Œ#H誈F¶ÕMéMÄCPMÛ¤(=f‘Æ)£ƒ3<›pGUçãꜽBV‚]£m’°­3¦³þè7þZC„K›á`óÇÔüDz•F3µ®Ñ1Áø G` ½ëío/l“Nˆö'Ûôê8ðO¤Ñ½Ih’0!@ Ð;T€F I=Ê^@#©F@÷Mj˜™™µk×®¼¼\ˆ›wß}·¦¦F_^ñÇÊÊÊÊʪººZ­<""B&“%''3þ®ÅÌÌìÌ™3®®®aaaô mÚ´©ªªR+´±±‹Å *7l±â………££#ýgdlå& [(Ø:Â[æs§zC 2–õ5ny-ƒú¯wMA6•,6‰;}•óÁ ±â £¨$[¹ à zG|}}ézxxÿ‚a9ô†@e,þêk*eÜòZõ_ïš‚l*Ylwú*oôX‘p 4›¨$[yãA]=ÆŽ´nÝڃ®]»¤R)þHga9ô ·2‰@õ5Ä®RÆG^‹Û“Ò$˜T²Ø$îôUn"±Âpˆ²‰J2–7Jøt„#l$Þ0pàÀ’’’Y³f‰D"!Ârè‹?§]‹üH ú õíÌT4Êk½]š‚Œ*YlwX—@x9O©‰D.../_¾Ü¸q#u}=zôªªª”JåÓ§Oÿõ¯íß¿Ÿ¬àççwèС‡Þ½{÷Â… ÇWÛ¼0zôèÞ½{acccaañ¯ýK¥REFFFGG“[¡PôêÕë—_~±³³k×®Øü§·*++Û¿¿šòœ=cÆŒ?üpÉ’%j綆††üüüÎ;S/É-,,œœœNœ8Á3Ðø…ФeÜñwß}W_å¦+mkkkffæããƒOB]»vݱcÇ×_ÍVnä ðï¢\êQCÁÖÒ¸Ïûï¿?{öl²9wæ#–ô@üïD˜žž~ýúu•Jekk;{öì³gÏzzz’sõÌ™3………W®\133û裂ƒƒ©s522²_¿~sçÎ8qâîÝ»—-[öñÇgff’KÆàÁƒ?ûì3‚ lmm ÅÒ¥KB555÷ïß§^á–——ÇÅÅÙÙÙ9;;;ûÃÇ6ÿ[0ÚquuݹsçÙ³gOœ8A¿î~ýú5~Á7IÛ¶mÍÌÌxI—FŒÏ~ðà>møûû/_¾<00P.—3–9dÂóì[(è!5¾ç΋Þ¨F82CO?ô ‡2YGˆúO•2‚S^ë-ÒĨ½ –MâN_å<Ë ±Ò8Ðl¢’¶¶¶Œå3gÎ4rxv„-ª™!{{ûÊÊÊÕ«W«™âÎ|Ä”~è‘ÿ-Ó*e,òÊTˆúšF•2>òZo‘¦ #lwØáåÔï+Í&*ÉVž——gä ` :ëêq¨f"„\]]ÍÍÍŸÜÁÁá?þÐh¦ó[ ׉pÁ‚7n<{ö¬J¥ÒÊèùóç[µj•ÀÝÐÌ̬]»vååå:´Õˆ¡Ž™™Ù™3g\]]ÃÂÂt8–?ÖGmaŒ‰‹‹‹J¥ª¯¯glÂö)ijýúõ ÉÉÉzì,cêþ½1…|ÓÁNDD„L&Óyô-,,BBBËËËoÞ¼©R©Ø¦-÷tf|øðý÷ß÷ððHMM=sæ vO_å|à“íDGG'%%õîÝ»[·n)))·nÝb<ô¸qãFŒÁxŽ\µjUyyù’%KZ´h1tèÐîÝ»ãjlå†Â_P;—|þùç{÷îõõõýõ×_©ç’‰'îÙ³góæÍ|ðÙ±iÓ¦íܹsÛ¶mžžžd!5_W¯^=vìXµ@H¥Òß~û Q$?þêÕ«ø_???\ßÌÌlÆ ®®®«W¯Þ¿ÿâÅ‹E"ш#~ûí·7ÚÙÙÁyìL·nݾøâ‹½{÷~ñÅÔ jÆçÌ™³dÉ\ÁÃÃãË/¿ÄwéÒeãÆ]»v%â÷ßòä éžT*ݳgX,Æ ÷„ d2Ù¤I“°W'Nüí·ßvïÞ=zôhºŸŸþ9y8„Ђ –-[&‰òòòH›"‘(00ðÙ³gŒAfë×ܹs÷ïßÿÍ7ßtèÐaÆ ÆŒ‰¥¥å«W¯:$‘HpL:wî\ZZºk×.‘HÄý)BH-¼Ó§Oohh>|85 TVVÖ­[·úúzwww‚ ¨£ ‰¢££¯]»¦6©8RC¼áÀÙÙÙfffø_ª²N‡òóó9B? G> „F…n‚ –.]ZSSSRR²~ýz‘H4yòd¹\þÉ'Ÿ >>øHÔ|-((عs§ZNÇÅÅ=~ü¸sçθ¾X,&#UPP€ï~XZZÖ××§¦¦†††ÆÆÆÊåòÓ§Ogdd„„„¼zõ*::71¨ó$Ø™ÄÄÄðððëׯ×ÕÕ8pסÿõ×_‹‹‹ÍÍÍBGŽ‘Éd}úôÁƒTUUÕ¶m[„PZZÚáÇɣà¤$ÿ6l˜\.Ÿ6mA_ýuMMÍ7nݺU[[KÞ·!ýܳgOee%6kiiY\\H.L¤ÍsçÎ=~üJ-ÈŒýúþûï"##oß¾‘‘¡P(ÔÒË 1;v¬\.ÿè£ÈÜ%âÖ­[xܹ?¥‡·I“&EEEÛ¶m£k÷îÝøá++«;vàVÔQpppÈËËÛ»w/ÿÔUŸ¹ïIeffÒï³qäÙßââb\çÔ©SIII‘‘‘x!Û¼ysMMÍû￯ÖA>öM6ßÐ_ç&=ÇzöìYZZŠ´mÛ¶²²2|Jã3úôdÀ¨ÕòŠ„­sàÀê‰púôér¹|ذax4gÏž-—ËÝÜÜôUN&‰µµu—.]Ž?îàà@Þ©¦ç5Ûé­íP¿å‡„„ÄÅÅ1N„û÷ïÓ¯&q`kkk¿üòËQ£F-[¶Œ¼wÍVn  üò\‚Ÿ ˜™™‰ÅâÓ§O—••I$''§’’\žðßÿþW,?~|õêÕ¸0...44w˜š¯‰„žÆ ËÈÈ(//ž?~“&MÈȶ8wíÚ…í'&&ÖÔÔôîÝ["‘,\¸P.—ãó™A§›L&#>|8??ŸÍø‡~(—Ë'L˜@Ä‹/^¾|ùÓO?áo÷ïߋŵµµß}÷õDxðàÁöíÛ;::2$222;;»U«VŽŽŽ%%%¿ýö¶èС‚‚[[[ªŸ2™låÊ•"‘hÁ‚ …bÔ¨QAäååݹsç»ï¾ûþûïOždÈêEÜÿûßääd±XÌý)=¼¡ÄÄÄ   µ¯n¸urrrîß¿TôèÑ#ú)Š#uÕÐx"\ºti]]——ãÕ:c>Pëܾ}ûÞ½{b±8333 `Ó¦M¯^½’H$ÁÁÁ ä•>µƒí›r¾Qí0æ˜D"Ù°aCYYÙøñãËÊÊ~úé'r¸5Ž>[¬¨'BƼB±•S3z"üä“O¨Ù‹ÿõððÐW9™NüqEEE~~~^^^EEÅÒ¥KÕn3f;½•··7‡3fÔÖÖ’_$0£Gþꫯ֭[÷ìÙ³ää䯿þzݺuÔ'µ:tËåÉÉÉIII‰‰‰uuu¿üò‹H$b+7PHþ’jýû÷·°°8qâ„\.W©T/^¼ÀÛŸ† beeåää€zçw:uê„òññéÛ·ïܹs›7o.‘H¬­­éËåôÂÈÈÈ~ýúÍ;wâĉ»wï^¶lÙÇœ™™Ißm•››«P(”Jå³gÏÌÍÍ“““åryRRB¨cÇŽQQQu^/^`g233ñªÄh<222//oذaJ¥²U«V#FŒøöÛoÝÜÜ.\¸ R©Ú¶mkffV\\L5>þüyóæ©TªÊÊÊÇûøø”––Ž=ÚÊÊêèÑ£¸S'OžôññéׯßÕ«WɆ±±±=?~üîÝ»'Nœ˜––vûömÜwggçQ£Fá?JKK³³³yö«OŸ>666gÏž•Éd*•êÙ³gÝ`4õúõk|ÓŒD¥Rá()•J²0==ýúõë*•ÊÖÖvöìÙgÏžõôôT(dþ©ËÍ{ï½·qãÆS§N]ºt‰±-c>P+ÄÇÇÏ›7ÏÝݽ}ûö×®]“J¥_}õÕ¸qãzôè7.2vÛ¾éç†1ÇT*Õ?þ8nܸ“'Ofeemذ8£Ï+ [Šê1uõË™3g ¯\¹bfföÑG«õŽ1Û[0ÚquuݹsçÙ³gOœ8AMãÁƒãË [[[…B±téR„PMMÍýû÷©Õ¼uëÖ÷,ᙉÃ{å›4iB½1šó!¥R‰½e4®T*cbbÜÝݧL™òðáÃÓ§O»¹¹ 8ÐÙÙ988˜mżGÕÕÕßÿ=wÉ~á_¹¹¹ä!Œ“ŠŠ „PëÖ­©…ÖÖÖødÀý)#}úäçç«Tªž={"„RSSÕÜøÏþóÕW_mÙ²ÅÒÒòÈ‘#d÷U*¾ô.++‹‹‹£î}à/I;v|ôèQ£Ä$&&¦ªªjøðáçÏŸÇFÜÜÜNŸ>­R©¸?e oË–-_¾|©Ñyì*…ÔÔT‚ Z´hA>оRwåʕÇ÷öö.))a«Ã˜TªªªFާT*U*UTTÔˆ#”Jehh¨Æ¥ÿ­Î7¶ëÕ«×çŸ>oÞ¼'N<|øÊsô¹aÌ+Žr6ÒÓÓBíÛ·¿wïB¨mÛ¶ iiiøÌ-¼œ:ôøenn®T*é—\lÙNoÅh'00ÐÂÂÂËË‹þk?Ò,þö"—ËÕŽ^\\\TTÔ±cGü/Þ±üúõk¶ò¼¼<ó—ëµ[·n­[·ÎÑѱk×®“&MÂ×k7oÞÌÈÈXµj•™™Ù§Ÿ~Š7˜Péëë;xð`Æ«?ú®Ñøøx‰D²iÓ&üHsÈ!  ¾µA7Œã¼lÆ/_¾Ü´iÓŽ;ž9sF¡PܼysĈ11189ª««srrœ5vêÚµk©©©~~~NNN+W®LHHxðàÚ2WPPpóæM//¯<}ú”q¬««{çw4—íëëëââÒ¡Cê·"ãĤ¤¤äÈ‘#sçÎõõõmÙ²eß¾}?Þ¢E‹ýû÷«T*îOÃÛ¦M›gÏž©Tª=zœ½½½››·µ£ÔÖÖ>yòÄÑÑ1<<xxx¸ƒƒCzz:þ&ÇÑ–ÍþÛ’ol9¶cÇŽÜÜÜI“&¥¥¥Q÷èñ}z¬¨…lÓ–ÿtƤ¤¤$%%}þùç­[·vqq™;wî;wêëëõUN=Vnn®T*}þüù‹/èž0f»J¥¢·¢— 0`ùòå2™ iÚ´)Ï`._¾|øÓ§OkkkëëëŸÐs쫯¾jhh˜:u*A£F"7°ð}ÆX5oÞœê°Z^‘°•cÔ6Ë „ú÷ïwÿÕÕÕEEEuëÖ û£¯r>°e;ÏæUUUø«™Ã3fÌ c[µMPPP]]]uuuVV8ŽrCÕW‚ $IŸ>}ìììÄb19xAˆÅb777www333/±XܱcGWWW‰DB5BÝ)ʸk[³³³swwoÑ¢5RlméN’>Çyêß"‘ˆÛ8‡Ã˜>}úTUU‘cÌ%ªý^½zõìÙÿlŽ1°~~~eeeÔ]Žj°ÏôÃqôK"‘¸¹¹YZZþüóÏä2l³eË–ŽŽŽb±x̘1>$ Êñ©š©Ó§OGDD`÷6lØðèÑ#ÆÍœ’¿‚7^ª5aK]ºYj@¨p9ýXT lù vµCà†lëûèíÉ7zŽQHÍ.ž£Ï+µ37=E1låônRïÔ©SûöíÉ4Óc9ز]·æÔTáv/ÂÔæŒå†‚Ølá;ŠÜ%z9Œæ¼SAlß¾=11‘ÏnUnû666'NÌÎÎ>yò$Û"¨cÇŽ]³fÍ„ æÏŸŸ““¦­q}ÅD-ãéƒHÿ”jjܸqEEEøÇ6!µ­Þal¢ö¯F³Â+𬣗¶oK¾iÌ1ÝFŸ¬†O„UUU§NÂÙÅ–¢ZMg²•AËß ØF£œÍŽž=Œþ¿¿¿{©Ì˜1£¼¼<**ÊÉÉI_¾!„fΜ™’’RQQQXX¬û mÐWL¨¦=zD½+‰´íŸ&ë¯À³Ž!ÚRy»ò->>^‡Ñ§VóôôüðÃ{ôèAÞ‡`LQ=¦.ü³‹Åø™–ð] =^›“fñíen›A/1¡šjÓ¦ ¬MzäíÊ7á£O¼,aKQ=¦.pÁ–gZåŸ^Œÿ( ñSòS z¾¬c“§b—bÃÆÆæÝwß­©©Q+gSã©:¦›–˜iÂ"!—ÙcÔ]Óvô[ôØ\5~âb| J#ªâ!}ãéCøÃ1=ea4qb­‡@ 0†CžŠ..åëëK—dÃO§ S[[ÛÐÐ@}kbWc+WC+-1’“'OVTT=úì³Ï¨ÎãWeòŒ’:ptØB$Ä12{ܰé®!i1½ÄP·tåH06u4dÜÄ3Äøê%ñHÔf„΂p|¤5¶òè.Š’:øÃ±âñqIãô4f~²MvÎG\S«[ñ:¦a*q)6y*Fq©Ö­[{Pصk—T*Å=}ú4::ºG®®®)))øµÂäQu1¶r*Új‰a¦NÚÐРR©ÈõhÆ EEE ,˜7oÞ¼yó¦L™ÂAá¯Çj¶ qL£Ì7lºklÒbz‰¡n:jlÑcscÌÄ3Äøê%ñ0ô¡³ iF^±­<:‡K£¢$7Œþp¬x|ljœžÆÌO¶É®sÀùˆkÒ'¸þS‚ †M\ŠCžŠMtŠ|=pàÀ’’’Y³f‰D"{{û7nŒ?ïÚÚºu+~¡>õXŒêbå$Új‰!„š6múøñãû÷ï+•JrÚïÙ³'))IòF ñp|4À&9¶Ps„H cÜ2{ÜLºkˆ}ôõCît¥Ã=6WIŒ“x†_‰‡¡Ï‚pd_ؤ¹½âXytYŸCQ’ W<žQâ3=¶0²MvÎG\“¢ê–v¿®mÛ¶NNNAAAŒ÷”ñ¯VéåÕÕÕ]ºtÁo®CuêÔ)77W¥RYZZ¶oßþàÁƒÃ‡ïܹsRRRtt4y8üÇ–-[‚‚‚Ο?¯T* LJ_œˆrvvV{q(B(88¸¬¬lòäÉ‘‘‘ÔØÊI† Ey#[9Bhýúõ–––;wîìׯYhggW\\¼xñb[[Ûˆˆˆ;wîP›X[[ÛÚÚŽ3ÆÊÊ***ª¾¾žþZzòíáUUUA0žƒÙBÍ"!Žåææ>¼C‡J¥rÖ¬Y!¶÷òÑQ½ZÈ1úúŠ!wºÒa‹‡«$ÆI</5hH§ÄÃÐgþÃóçϱñœœssóîÝ»§¤¤àcq;FFlçεµµk×®eÌ:mW!áRDzbsÀáãŠÇÇÄozmadœìH@ÀÃÃñxä‘#G†úìÙ³òòr|;·ÿþ 7nÜ Nï)¡Y†M£¸ª<›¸Y‹¿¨ý ©W¯^¡¡¡ EEEãÆ£…®.Æ]ŽØ5Ã8´Äºwï^ZZºpáB,öH~#ŒˆˆÀï¸{ñâE]]Ýš5k¨m5j€qëÌñ 5cˆ„8Æ_fµWIqŒ¾ÀjT ä†=‰Š1Nâ1z(„·±±ihhÀbÖ¡ÈårÒ²½½}eeåêÕ«ÕLá{Ð"‘èǬ®®V“CCݺu‹q\ÙÊ‘öãíííÝÐаcÇ??¿ýû÷+Š-[¶`YêWr¬ÐݵkWjR^¼xñÔ©S!!!gÏž¥¯GûöíkÒ¤ Û‡y†š1DB#.‹ÝÝÝóòòè[>ÿüó5opqqÑx"ä}1äNW®Ò£Ç¨$FH<6‘°ñžxl3bæÌ™ô!ù>XŽ!„BCC322eŒt^y† Ãq"äN0FûŠÇÓî鉌˜ŸˆéD($àøYà¡C‡¤R)~(›žž~øða…B±`Áª¥ÄÿºÁ-æQ\ C—§b—Âÿºººš››?yò„¼ÿÛ£GÍ›7oÞ¼9.. Ë5mÚ´Y³fEEEÔ±©‹q¨Ži«%æää„XZZ1räÈ’’’ðððLJ„„œ;wN¥R™››«TªŠŠ þòWÜ:sCÍ"ã)³÷ûï¿“óypÂ1úcÈ®®²E/++‹#QIŒx†_ŒÀÄc›7nÜ@ḥu^yàã†{.° õÑW<*§'2J~r $àüÅ5 ˜Ôç}ûö½xñbEEùn=*÷ïßgÛ¡PZZ:vìX'''ªpà@ìɽ{÷îÝ»×¶m[‡¨ÝÂ&a¼gÍ!£[¨9B¤³cÍ›7ÏÉÉ‰ŽŽîÙ³'AC‡}ùòå‰'´}ãÝÆÑCžéJ‡#z‰Jb„Ä3Äøñ¼Ô IDAT"}$ÛŒ ">>>22²M›6...ÉÉÉlûéŽuïÞ½¸¸øøñãÎÎÎŽo`|â«ÃÊ#$\Ýž²ùƒ˜V<>þðŸžFÈOúdðèèh¥R¹|ùr|Düú?þ`[…ôŸü…©ð4`t‹MžŠM\ !´téR…BáââBµ3eÊ”?þø£¦¦¦¶¶6--m̘1j£ª‹±•3ªŽé¦%†h=† ‚=¬««{òäɰaÃø,ÁþëG¨ÙB$Ä1…HþÐçÛè Œ¡5¶èq$*Æh‰gˆñÕK⑨ÍáÖ¬YÃ(ÍHw@‡•GH¸0º9„úW<>ð™žF^é“]`Àµ×D†H É_¡??àƒ„iDÌ":%¢è‡‘!‹;wîüÞ{ïÑ?EUc+gTÓMK ½yË0õá¿X,îÒ¥KÇŽ=ä€ñv¶¶°…Hˆc»B$D4Ý5Ä)-¦s …¤+G‚±%*Æh‰gˆñÕKâQ=¤;¦ƒ ù¼Gm@µr†må.ª{Ú¶âX W<>ð™žF^éÁpºA’lh ” AÚ®VŒõÕÔÅØÊÙäô«%Öqäá€@Ç Ñ)¹*m]2~â™`и1Y¯LÓ1Ý`ë ,Œü1}5£¦.ÆV.bQ– x€)ùùÏ‚M]Œ¿ê˜´ÄíÄLÈOø›šj€éÙ¨cffF'‘±±±aüQ‹ Ï·ÂëÆlÆ¿Î6¾3ˆÅ ‹:˜Ô=q+++Æ-©ñññóæÍc¼½ÃX®†™™ÙÙ³g·mÛ¦V“­œuŒÆßo¹dz!³Ø@«“ñ³‘-÷L$'Mí¤nÔ³’@™:ƒÊï5– ›×СCãããëëëëë뱌Ïž Ô?{‹´9D+Q#‰M’Œ9òñãÇõõõåå凿¿.ë]MMïzoL/³˜mèužÅHØê¤q0f6²åž)ä$[6r,;¸Œ<+é‚@™:ƒÊïA69®„„„¤¤¤ž={öë×/###,,Œ§?õÏÞ"-@60 at±Ikkëçϟ߸qÃÙÙyúôéÅÅÅŒ?LfDïjjz×{˜`z™ÅlC¯ó,FÂV'‹€Ñ²‘-÷ŒŸ“Œ°e#[9.#üÇ]£¸¦:eêŒ/¿g4F9®êêêï¿ÿwvÏž=¹¹¹<ý!ÑAÿŒÃãkÒ[QK8tÂHŒ)6IÅÛÛ¿*$000--gžëWM @ïg‚n³ ½ÀY,puÒ¸'ÙrÏø9É[6²•kô ñ–.žÊ-®IE"P«±ä÷Œ£‚Æ›WNNÎÿ³wÞQ$Ù" &`0Š(bŽ`XÝ€ \½u(Þêªè-®i1¬ ®xk0¢‚‘ ¨€ ’2C`Bÿþ¨»þõÍtÏ4Qtßç/èyõêUõëªÕý>|8†a<ÏÂÂ"''‡jÓJúgLñ´± b)™L¦è‡I'Œ¤-Å&©tíÚÇñ´´4ä­ b)%~˜¤Úm£©&ן',,ìãǼpáBYY™H$bß-­¡¦Ö²zo¤OÚk›£SØõÍ<Š›9:aª¬M²ÇqÚÜcÚβuìskÒp§|{Ó†–ÅUîwö ù?4Së“ÈïÍŸ?¿õTаÆkïÙÛÛ×××/[¶ŒËår8œŸ~ú©ªªJnuoëéŸ)ÆÓöZ€Š¥hý0Iµ‘´¦šbêèèüú믷oß>vìØ‘#G***ävD[ª©a-­÷FúdJ°68Šw}ób¬£¦jÀÚ*™r¯mrküð¢r»òØØHŠ6g¿³?ÊHxX³u°>‰ü^zz:Öj*hXãµ÷LMM¹\îÛ·oÑãÌŒŒ uuõž={Rƒµžþ™"m¯¨XŠÖ“TIÛhª)ö§P(ܶmŽãA\ºt)??_®“ÛRM–VØkÕ£¡¸ëÓÒÒ°¦ÅÍTX[e#SîµMNb^ØÐLIÑæì÷æeÍ•©£½ýÚzò{x›¨ )AîTÈÔÔT(^¿~]__ßÀÀàÁƒùùùhŦÊx¨>[ê!ö‰´i׿QCb’j#iKM5*¶¶¶]»vÅ0lÑ¢EÕÕÕûöí£-Å´ûZPM Ñâzo‹k¥£cØõÍ9Š›9:±Ú&™r¯sR M¸"T{IÑfîw•G[š)Sתò{m ‚¦¹ ÀqÜÍÍ-++K$‰D¢ŒŒŒ¹sç6v NËN„íP P‰T¢íÅ&Iüýýkkk+**ª««ýýýÕÕÕY6 Ñ‚jjd<-«÷†55ÁZä(fÚõM>бæNl6ËF¦ÜkãœTB“'BZš9Œ°ßï*2¶àÍ“©Syg–} LòlŸJÃ,Ç5`À^êŸ))ËmgZ€ŠÝ.W¼íÅ&I8ޱ±±­­m§Nš´Šýß„¤Rî°9;ŽÉ'Zä(fÚõM>бæNl6ËF¦Ük?9É”9MΨæ #Íœ•šEŽº€6†O˜Lq~*”ô[»Škšjí­Oi‡;®ù4³E­Ñ!ŸD’6’/ow·Ð3ÀhªíÈF> ©´ öH‚­ËÄØ¸qãöíÛ—-[Æáp gà ‡Ið¯ hÏuŸ¦niç´·3¦Äf™]AAA ::šËå²L<>?˜ÿØðÅÔ5Gt­Åé”w‹š£<×J2ŸP·Lyb³Ì..—{÷îݘ˜.—Ë2ñøü`ücÃ#PÇ^tM‘W¤SÞ-JhŽò\+É4~BÝ2å‰Í>»‚‚‚ÐDÈ&ñøü`ü“3ûâêXŠ®µ"›naŠÿ/MSž#‹· L#Óv6ñ4'»Ø$6Ëì"'B%Eø|á1 þ‘+:%¢km¦HÇ$ÞÆ&’f*Ï©ThSB[ê–±É.•‰5)»T&Ÿ+Š‚äO:•¢km¯HÇÔ-­§<‡hY™FåÛ[;»”$6‚MvQ¯•àóFQðü ÿ{Ô©]SÞ­¡HÇÔ-Ê#A4Myk™FåÛ[;»”$6‚MvÉM„J€Ï\AðúëßA N¥èšò~hqE:åÝÒJÊsXKË4ªÜ®<žæg—òÄÆØe—ÜD¨$ñøáYYYy{{+ þ‘F:L•èšò~hqE:åÝÒJÊs-.ÓØÌx°fd“’%5±±&e—’ŸøáåççÛÙÙíØ±cÙ²e†¹¸¸dff~øðj”››‹aNQM¤ÂçóŒŒd2™¡¡áÏ?ÿ\[[F„b)Å-¾¾¾£FZ°`X,F¯×ÕÕQýwïÞ=44T±jr»¥¥åÚµk:”œœŒÌjjjrrrLLLäŠ0mg‰’~‰DïÞ½³³³ûí·ßЯ=ruuMMM-((hlE*»EùiZ+ ´mÛ¶k×®ÅÅÅ‘Ò- ………¤’³„&ÓJÙ%T&6Æ"»CRòŸ+L‚løbêØ‹®1Ñ‚Št*»E%MPžk ™F•Û•ÓÌìR™Øl² ûß[£LEø¼ÁÿØÐLe)&•2’6“£}P×(ZPýKe·4!–Ewh‹Ôû uË”$6›ìÂþw"d*À—í›×Ÿ–ö P|î0%6ËìÊÈȨ¯¯ùò%—Ëe*ÐZ€$Ðz°Ì.‡ &X[[ã8ÎT µI0 õ`™]äg甀¿9?üðƒr5på6¦¦¦;vlè>îîî·nÝâr¹ÔlzImmmÅíúúúZZZ´EºwïÞ¨P>/1†¶6#GŽ´··ÇqÃ0uuu>Ÿ¯Ü~̘1ýúõSÜîíí-ÒÒÒJKKÃÂÂìììÏŒŒŒªªªªªª²²²äääÝ»w7j iq¨íUIŸ>}äŒÙôÉСCÃÃÃAnnîëׯmll·AƒEDDäääܽ{×ÈÈÙŸ8qâýû÷UUUÑÑÑ<¯1-šDpppxx8ºèár¹*g©¢¢¢Ã‡Ë™íÙ³§¦¦ÆËË«W¯^£FzùòeZZšŽŽ†aàܹsöööŽŽŽ^^^"‘hëÖ­Ÿp.¤¶W%{÷î-//—›ØôÉóçÏß¼y3|øð&&&>yòUñêÕ«ÁƒÛÙÙ¥¤¤\¾|mŸ7oÞºuë=z”——!_>îîî¾¾¾ÞÞÞ}úô!/;œœœüüüvïÞ=lØ0rãŠ+Ž?¾qãF++«õë×s8---//¯#F ›±cÇnÛ¶ åœðù|//¯®^½úرc«W¯F–kÖ¬y÷î]FFÆ¿þõ¯îÝ»{zzN›6¬tîܹGŽ9xðàøñãÉŠaÇŽ‹ŠŠÎž=‹®“pŸ0a‚D"™5kŽãÀÏÏËåâ8Îápž?~ÿþ}ÅyH.à™3gzyyéêêbÖ¥K—;v oLý3oÞÇq¦Î‘k¯’Þ>vìØÚµk÷ï߯8’½ÄÔ«$+W®DÍ?räˆ@ àñx‹ÅK–,áp88ŽoÙ²¥ªª Õ‚zéĉ´!ªÑÂÂÂÃÃãøñã+W®äp8'Nüã?vîÜI½ûJ›Zí‹€€€âââk×®%$$¡›f›7o®®®¾{÷ntttIIɘ1cp?zôh]]]HHHDDÄû÷ï³³³y<ž‘‘Q}}=9ønÛ¶­¶¶ ŠN:wî\__ÿèÑ£ºº:‡ãçç———WPPpóæM33³ÂÂÂC‡!‡û÷ﯨ¨¸}ûvXXX]]ÝâÅ‹Ñxª8Ž5J"‘¸»»“qŸÏårccc¯\¹Ò»w ???´100ðÇh"‹ÅkÖ¬AãìöíÛëêêx<ž±±±¢mmm±Xìëë‹6ž}úØÙÙihh\¸pA"‘QZZªÜµƒƒƒ¢4ÂfggK¥R™L–™™©§§‡a˜L&#‚ ©TJÕÏâÅ‹mllÜÜÜ:wîÌãñºté¦aK—.%¯ÿ6mÚ„bHKK !¢k×® .¼zõêøñã¥R©’€ ‚øå—_¦OŸ~ñâŬ¬,///©TJkéààйsçK—.¡þY¹r¥ºººL&£ Ú^Zor½-×-Š(öª"G޹zõê… T:TInn.ª1==]]]=!!A"‘¼yóÃ0ssóÈÈHÅÔbê€OÃ0ggç 6Ì›7oÛ¶mQQQîîîúúú葦¦&†a ÀÐÐÇq6#2BOOOщ\Y™L¦üÏçŸ?~Ê”)ÑÑÑÕÕÕzzz………LÆUUU†uéÒÇñ7n¼|ù²S§NÏŸ?'/hÒÓÓ:„Æâ°°°[·n¹¸¸SSÀ2™,44ÔÖÖ6<<Íš´–èlAAò–””„aX¯^½šÖQím*L½j``pþüùÜÜܵk×J$ ÃÍêëë[#š­Q¨¨8º²WL­÷ïß7hAx}úô™yòä7ß|ãáá¡¥¥Õ¡C777‡SYY‰ ø|¾‘‘‘‘‘‘OmmmXX9è3|øðáÜÜ\ggçÔÔÔ#GŽp8ZËdeemܸQ__À€ttt¬¯¯§íj{•ôö–-[ŒŒŒ àììÜ̧k¾¾¾£FZ³fX,FбcÇÄÄÄ7oÞ¬X±¢[·n¦¦¦nnn¡¡¡M¸"¤…6µàr€vŽãžžžÅÅÅ•••uuu‘‘‘&&&†Mš4)%%E$ÕÔÔ‚ü‘Ãá,\¸°   ¶¶-6ÉÉÉAw,XP\\\___\\ü×_Õ××£íŠN:wî,‹===Ѱ¾e˱XŒŒ]]]kjjêëë\\\Œ– ›œ‰¤¡¡ááÇ7oÞLMMeZ,ƒa‡Ã9pà@IIIMM ªtß¾}È¿@ J¥‰D,WVVÆÇÇS§%„bÀ?ýôSCCZ€3yòd‘H´cLJCÛ?Ó§OÏÌ̉Duuu<@‹q˜:‡ÚÞÉ“'3õ¶X, …èWùbÚ^%©®®&51þ|ÇGމ–º ½?pà@êÉŠòÅ2d—.]JIIAûÅÊÊJ"‘|ÿý÷\.—6µÚG]]}ذa½{÷&ß«ÃqœËåZYYÙÚÚòù|4Þá8Îãñ†ª¥¥uâÄ ´jmWWW·±±éÒ¥ ‡Ã!ÇMZ'hÍ$Y5Õ¸W¯^h#iÃårÍÍÍ-,,x<—Ë%#¤ÚÈ5GSSsäÈ‘d¥Èž z£N®¬bÀ(d‰šOvmÿp¹\kkk¹ždê²½JzÛÚÚÚÀÀ€Ëå*ÎFÔ`êUª±d£¸\nŸ>}PÌr}BëJ±Fê~¡ömj´ShoZâ8N;[`æïïON„J<09i~*ý4ù•5öe•ô›rÛÙ{kqZµxw€öÌÿOc´o”l,++“[5Ãôø§Q…؇Ñ?-^¶±¦|{Kµ½ ´j-ð\€/‡7»:¨jy*•ó”0IèµgZJ> }}}}}}Åí={öl¾s€¿­øáGª^ “v ­1 “„Þ'¡å—,YRQQQõ_^¼x¦ÕQ£FEEEåæææççÇÆÆ’ß4iÒÛ·o³²²***Nž<ɤ² ÈÑŠ:sÔ5*×aÒøùùihhŒ3F$]¹reÿþý“'OþTß%ÙµkW§N¨ß&UmsœÑ§jØT×»wïúúú-[¶ û²²2ôÇÉ“'ËËËGŒAÄ¥K—~ûí7GGGmmí'N¤§§;99 >Üßß¿¢¢bãÆðaO•ðø|þÖ­[ÿýï/^¼ØÄÄäÅ‹gΜ!йsçŽ7N*•Þ¹s'44” dãÆY³f!y™L¦h¦¼V''§3f”——_»v->>žÖ^CCÃÀÀàÀoÞ¼‘ÉdOž<ùæ›og9W3f̰±±ùý÷ßËËË»té²zõêøøø;wîA[é¼yó&NœX]]§©©éááqÿþý—/_1vìØ±cÇþúë¯?þø£±±±ššš——×±cÇ­·+V 6,99™öþ§‡‡GbbbHHÇÛºuë•+W&Nœ8xðत$???¹IËÐÐP œ9s†œw ‚044ÌÍÍ=|øpRRAÁÁÁK–,Áq|êÔ©FFF .üðáÇœg̘±iÓ&ÒÚkS¦Léß¿llì‰'Æ?wîÜ’’??¿¢¢"déîî>|øðòòòÓ§Ogff‚O¾|°\ZZÚ£Gž={&‘HöîÝ«D¢KMM=pà‡Ãa£Hý›VÉö31´zTƒ/X>ðÚµk?þñÇwîÜI•#¦¾ó~õêÕ„„.—»víZ©TJ>5ܽ{·\í ÀúV©2xáÂ…’’’®]»b B€ÈþܹsjjjìõÉ¿iµ÷¸\.íDHB•Ð#7~Ùòaaaõõõ‰‰‰ÙÙÙuuuT%¿¡C‡ÇÆÆMŸ>ÇñéÓ§K$Ô?þù'©LÝË  ÈÆJRÊîÂ… ß~û­­­íýû÷•&&&J$t7¯Qz´Ú{ÊCd’Ðû²åß¾}üÛo¿q¹ÜëׯoÚ´éðáÃ(¼ŠŠŠ˜˜“iÓ¦…„„GFFþöÛo¶¶¶†††hvT¬äùÏDHŽÚÙÙÙ†uëÖÏçŸ;wŽI´o”^ ÆN¤Š¢„žJW_†|àš5kÐOb±800pêÔ©}úôAIÙÙÙ;wîÄ0¬¸¸ØÃÃc÷îÝEEE³gÏÞ¼y³……ÅÇÏ;·dÉ%5‚| ‰üªÑþýûcöñãG–B€Ò Ę5ÿ˜ì%ôTºú2äOž>>`ÆŒ?ÖÒÒjíÈ `£T×XÑAZ=øŒiAA€Oœi› IDATJSnuòùüÍ›7s8œŒŒŒ€€ø hû¤{÷îàSGÁˆ\x7nìÔ©ÓÇOŸ>-“É>a`ª!?Oºoß¾¶y"00ð‡~híºÜÝÝoݺ…ÖµMJhN|>ÿêÕ«T^\e;v|ðàÁ·ß~ÛœgÃLN^¿~½téR²ö   @M®Ãhš8Ðs8œS§NýüóÏ2™,--­ªªªªªJ(fdd?~\__¿e£lÕÃ>}ú888 ñšZãÈ‘#íííÛx¡›&3¶wïÞ~ýúíÛ·O&“) ^e|>ܸqÆÆÆÍi;“ooïŒ5 mŸ={vll,¬Æàó}_ÛÓÓÎçåå;wÎÞÞ~̘1ëÖ­+++;uêTËž×·êáÞ½{ËËËÑ[ÔƒƒƒÃÃÃÛøJ…M“i6lXUUÕ×_&%Á«¬BnG7 &'8Žßºu+44”Œ-(((&&®hcš2ètèÐáŸÿüçãÇ_¼xA„‡‡Gbbâ‰'rrrbbbú÷ï?f̘?þøCSSsË–-"‘(??ð±cǺºº>{öŒÇãÑ**Q4d©zèææ¶jÕª!C†|üøqíÚµrÏ/œœÖ¯_ooo_^^N~.uÅŠË—/777×ÖÖ¶¶¶>pà€L&#k\³fͤI“tttôôôRRRª««œœÖ®];}út©Tš••…aŠª¼¼üûï¿2dˆœ£»»ûòåËííísrrÊËËÑÆyóæ­Y³ÆÑѱ´´´  @ÑÃÆ©MÎÈÈX³f«««¾¾~BBAŠ!ÏÞÞÞÚÚÚëÖ­“ÉdT›ŒŒŒ 6(©B±Wåv´§§gÿþýQí´Bȵ%!!aóæÍ¡¡¡cÆŒquu544|óæ Ᶎ†† 6„‡‡#yË hhhüõ×_ðÔ€6ÅÈÈèäÉ“666Ô»R´I¯ýüüÈóýk×®½}û–ËåÕ×ׯ^½ý´mÛ¶ÚÚZǤ\¨DÑêá®]»ÂÃß>}š‘‘!•JåÞèß¼ysuuõÝ»w£££KJJ¼ÔÑ£Gëë럌ŒŒTSS322*--ýã?ý_ýUPPеkWÕ¹sçÔÔÔ¨³`ÇŽkkk½¼¼ø|¾ŽŽÎóçÏ7mÚdffV^^~àÀä$22òúõë:::räšìçç‡ì/\¸PRRÒµkWj`äÒÐЉD;vì@N¨6;wV^Óñôôüî»ïjkk·oßÎåriEmµ\o Ïž=‹vÍÉ“'ËÊʺwãããïܹƒ&?˜ø$pŠŠŠ¬­­çÌ™SRRrüøñ¸¸¸U«V•””(nTò ÈÄÄdòäÉ&Lppp(++Cwº”ƒ” ¥R©œr!Óvåe­­­õõõ¯^½*‹¥Rizzº\mmmccc__ßcÇŽuèСOŸ>vvv.\H$R©4;;[ñ¦œL&CºTR©t̘1ÚÚÚgÏžEö/^Ô××1bš‡% ué]]]rròÂ… 7oÞldd4vìØƒŽ=ºsçΗ.]BNV®\¹gÏTJуb“/\¸ ££ckkKü©TJ†Ý£G>Ÿ_RR¢<²aS…\ÏO:õðáÃ÷îÝÛ»w¯T*¥m”¢C¹ŠÞ¾}‹Ú{áÂ…Î;ÛÚÚ¢N+//×ÕÕ¥ÝËmÃ0©TúàÁƒ 6=z´GË–-Ãqœv#“—û÷ïO˜0aܸq–––555»víb¿¼‚I¹¢!iÓ£G ÃrssÑvÅùLOOÇq‡£©©©©©™jhhˆã8íüG‹¾¾>Žã?~Dö†0UŠa˜³³ó­[·æÍ›óðáC¤i\PP€ì“’’ÈgŠJ ÊÎÎÆ0¬[·nM[`ɦ¥r=¯««Û©S§ªª*©TÊÔ(Å`ä*"ÿE'Idüð8€Oð‰'ž;w.%%ÅÕÕÕßßßÙÙY*•Òndò‚®9¤R©P(Œ‰‰éÝ»7ŽãÅÅʼnDCC£ š¦@sss&ƒ¬¬,‚ Ξ=ëæææêêºhÑ¢M›6ååå1`À–“Jff&AÖÖÖÈ~È!†¥¤¤0Ù›››Ïž={ÿþý¶¶¶öööýû÷ß¾};šw­¬¬ggçï¾ûŽý¬Ö¿ ÃÈÉXŽüü|±Xܲ¯¯\¾|ù—_~Y´h‘››Žã´RyÊB6°oß¾(N¿®®®P(lÁh ÇÔÔôîÝ»}ûöݺuë€vìØ!LLL7²ôXWWסCôÇû÷ïѪEKKK—Ö{"&&æÃ‡k×®555533sqq‘›Z?~Œ–Mðù|WWWggç§OŸmÙ²ÅÈÈhÀ€ÎÎδÖÔÔèééÜ¿?%%ÅÓÓ³gÏžÆÆÆëׯ}ùò%Óe†††‡‡A"‘ˆ ˆ†††¬¬¬7êëë0ààÁƒŽŽŽ*'™3gêééuïÞÝÃÃ#???22’ 20j¨999&&&ŠÁ³ïL9‚8tèн{÷öíÛ7hÐ MMMÅF¡ÅÃÓ¦McjÈâÅ‹ûöíkllìé陟ŸO.èíÞ½{zz:\ð áTTTÌž={ôèÑþþþb±=Ô©¬¬TÜÈ’¤¤$===ôfº··÷!CÁ“'OÐüVj†H$òðð055MMM•[Ð V¯^Ý­[·ÌÌÌÒÒÒ={öôêÕ«¢¢ÂÓÓÓÒÒ2333**Jîµ’ëׯggg4hÍš5úúúééééééšššëׯWr¡œ˜˜èååµ|ùr¡PŸ½gÏžºººuëÖ™™™åääÄÇÇgeeyyy±éáää䬬¬>}úlܸ±¦¦†ØàÁƒÉèÙ³gäcKª û _Ed2ÙªU«jjjüýýÓÒÒ%“É6oÞ<}út¦*BCC£££333¸qãÆÊÊJ Ãf̘¡§§wëÖ-˜øÄÐ^JM¹U£TBì¿J„¨8Žãêêê666]ºt¡*2)²ÙÎdƒÔ­¬¬´´´öìÙC¾Om—˵²²²µµåóùÈ *emmm``ÀårikÄq¼W¯^9:tè!CÈf*vµ7ÔÕÕ‡ Ö»woªÐ#—˵¶¶¦n”ó@þ‹z{óæÍºººC‡åóùd¥ÔÀÈ‚ÖÖÖÕÕÕsæÌ!wiÃTËž'u(iÅäü×ÐÐÐÆÆ†@@@XXY¬à³ ÍÕÕÕ—.]b3lµÍw³¦M›¶iÓ¦™3g.[¶,''çáÇ´±Ñª*²‰jÓXiÆÆžjP¡žv°ñƒãø¡C‡âããѪœFÕÕ(šà“ZdúôéEEEèmN Ã222êëë_¾| !ŸãÇŸ0a‚¥¥eûù8ä×_˜˜XYYYXX4pàÀö[sÐÐÐxÿþýÊ•+Ù?aåp8>>>Ÿð£á*yýúµ»»;¡ƒƒÃ„ È…Híü¿|ê@þt¿‘Çãñx<.—Û®bk&MøÔ*—Ë%_ZoŸtïÞÚ¨v˜Q°ƒªäG‹†††¯¯o\\Üï¿ÿ~óæÍæKý©¬h=ø|¾±±ñ§Ž eh™gHT%?Z<<<–.]üàÁƒ:4_\PeŸ„O¢\ØL222œdYYYrròîÝ»•œ£]¿~½¼¼<33³  @‰qDDDeee•¤!‰««kEE…œÙŸþI뙌¶²²2777((høðá´Ož*=þ<11‘ü722òÑ£Gp"@‹AUò£åƯ_¿FKç[D\PeŸ„O¢\ØL’“tttôòò‰D[·neÚA7oÞÌÌÌœ4iR—.]Ö­[W[[ˤVhaaagggggwéÒ¥¼¼¼Ñ£G£µ´´ä,»ví:räH»ÿâííÝÐÐðÍ7ßÐNod´vvvß|óÍ›7oRRRttt-½½½ëë댌0 366®««“J¥èƒ>ZZZUUUTÉþÎ4k"Y±bŰaÃ’““å''§3f”——_»v->>þÇìÓ§O§N¶oßîãã³bÅŠÄÄÄ·uëÖ+W®Lœ8qðàÁIII~~~ä«årNÐ;×L5’¸¹¹=:''çÒ¥K®®®¿üò r(ç­QU#ã7nÌš5 ©UÈd²¹sçŽ7N*•Þ¹s'44 «©©yyy;vL 899M›6 ˆ;wî<|øi.*ºrww>|xyyùéÓ§ÑWÜ<<<Þ½{¢¨§Hë°Q}¨HUUUtt´L&‹ˆˆ˜:uªƒƒÃ¾}ûh-GŽøôéS©TzôèѱcÇŽ?þàÁƒŠ–III¤s©T#‘H0º‹“_ 755]¶lÙ¥K—UF]SSsóæM‡   9û°°°Ÿ~úiÒ¤I§OŸž9s¦L& …³fÍzûöíøñãÕÕÕŸ={/òð"""^S¸páRT"Iˆa“’Ÿ¢ìŸ¯¯onnnaaáÍ›7 UŠ 6J;„I’PÑÒÿcYµ¢Xàþýû+**nß¾VWW·xñbÇ›¦\H«íWPPpäȹÉ~ëÖ­LÙ÷¡â~äµQÏž=óòòŽ;ÆtžóöíÛ¾}û"Wä+öJð÷÷ÿðáËk÷;wîdff2P£Å0ÌÑÑQ"‘Ì;—öÝÐ’’d|éÒ¥7oÞ„‡‡ß¿ŸËåîÞ½»¶¶¶e¿È ÀçÍ–-[vRX±b‡ÃQ.IhddD«äG+ûÇç󃃃£¢¢ÔÔÔ02xÕD0IÒzCj±,«FÆT%¿óçÏ{xx ›˜˜˜àà`t¿·±Ê…LÚ~Šß©QîeCh'-@““óâÅ‹èè袢¢¸¸8%ó££cFFFEEEPPвeËÐUû‰ð‡~¨««›7ož’‡¬àĉ½{÷622rpp@êöLr]OŸ>}öì—ËÍÌÌôõõõöö...æñxAAA±±±Ÿ×lZ†aŠ÷Ád2Ò)œ4i’››ÛñãÇ·mÛæïïÿ矢Ûn#GŽ$•ü‚ •Œ¨²†!Ù?ª*žbHO&“‘2x´N¨ÚÔI¨’„A’„´ÞÐP˲jE¹ÁÅ‹ÛØØ¸¹¹uîÜ™Çã¡o¸0)qñâÅÅ‹1"""‚êŠÔö“H$·oß;v¬ì¿Èõ’r‡,”iiiè6l×®].\xõêÕñãÇÓî¬ððð#F¸¹¹999=ztÕªUß}÷ºËäœ%ýúõÛ¹sç¥K—nÞ¼©ÜÛ²eË–.]JDUUÕÛ·o/^\VVFkùúõë¥K—ÚÚÚöîÝûþýûà§Ÿ~š>}º¥¥%º±Ü̘ø2àa–‘‘¡©©InJLLœ2e ’UzðàA\\\zzúªU«–-[vüøqdääG•ýÃ0,!!A °qHŸþüù)S¦DGGWWWëééÊÃ^¹ÐÙÙyÆ óæÍÛ¶m[TT”»»ûû÷ïÛ¨Üa£¢Hzzú¡C‡ÐìvëÖ-— .(ÚQVVöûï¿=ztøðá7nÜØ½{÷‚ ”|yœ%¿ÿþ{UU•§§§JW'NœX»v-Š– tþAk¾~ýúï¿ÿ¾¸¸8$$D"‘deeÍ;·W¯^­ú x>/þóz窼¼2'N\ºt)ZmáïïïëëKRhT0`€ÜðJÊþݽ{—œ?%^ÁädΜ9´5’’„qqq*½1©$²1ž|hll<`À€¤¤$´tE]]=%%%44´G;v\²dÉìÙ³q¿ÿþ‹/ÐS¹g„äúû-[¶ˆÅb&'ººº´5’!©««gffFDD˜™™™™™ÅÆÆÊd2&o;wf_µœñŒ3$ɺuëôôô6lØPUUõêÕ+Ô´7n$''wïÞÇñ·oßFDDôêÕËØØ8&&&&&†ÇãÉ5ÙÊʪ¶¶vÏž=gÀ€?~<~ü8‡ÃQÔöcéPyC† râĉAƒQ=SŸºÙØØÜ¸q£²²ÒÒÒÒÊÊJθsçÎ999ÏŸ?2dŽãcÇŽýøñ#ZZeii©è!÷ŒPÑrРA%%%çÏŸ7111ú/†††Š` ‹eH˜xþü¹L&[³f *‚îB'%%ÁBTÓ¥K—©S§2© a¶pá‚‚±X, Ïœ9C.]™4iRJJŠH$ª©©?þø#‡ÃiÔDÈä„©F’Ù³gçåå!ƒÇ£‰ÖÓDÈÆÇñ7nH$’†††‡Þ¼y3555ÍÕÕµ¦¦¦¾¾~ðàÁãÇONN‰DõõõïÞ½C/ÚË5ÇqOOÏâââÊÊʺººÈÈH¤©K»jtܸq**oÈܹsÅbñرc妩T*‘HÄbqeee||<’Pž3gŽ¢ñèÑ£Ÿ>}ZWW' E"ÑíÛ·ÑíYZc„ÜD¨h¹iÓ&ô€Å€ˆ7om´´!SG‰D½zõBÿjjj–——Ÿ;w&BX¡ü )LJ~´²Ôuö,ÅÙkÊ…¤(IHë­QUËp¹\sss ôoªÐ`c• UjûQ[§Ò¡ò†xyyÅÅÅÉõï!¿WNkŒ|ØÚÚêèèÓ+†Dk‰ Ã`Š–öÌŒ)¹Ú‘˜hI˜&ËQh¬v rIÂF…¤ÒX‰Ü-M6•¶``Jì}||Ð+l *7–ÛÎÞskX6Öà‹åK•$l)˜¤}ÛÒ¸5,k @å‹;Ð h@T¾°€OO jçvïÞ½+ñ­ ì}h2*V êééÅÆÆ~ÂK«æÄÐâ§…Ïç_¾|Ù‚ú‰SSS‚ êëëi‹0ýJºÚ¶m[CCCBBB 6–Ïç÷êÕ«¢¢¢¥¶ÚC¾5ÁOXX˜X,nÙ½8†¥¥¥!7¡P˜‘‘qüøqò{ÄêêêÍפÂ^OŽd̘1ýúõSbЖñ·{÷îíׯ߾}ûЋá»víÊÏÏOOO/(( “ûÖ¹ò_IWÿú׿8 (øgkk+ ‘ìúT7 B•Òƒ*Ù ªÌ6²‚vvvr dï_‘öo*cPÄÛÛ›vïÀм¼<¤ñ6f̘uëÖ•••:u 5-¢H…½ž ùÞa{ˆ¿E6lXUUÕ×_Ƭ_~ù¥¦¦ÆÛÛÛÂÂÂÙÙ9666''ÇÌ̌ͯTW8Žßºu+44Tîõ€Q£FI$’¥K—J$ôQo6„*¥U*²T™ldG-×@öþiù¦2E˜ö>¬ÈËËóóóC/q8œS§N¥§§£ÃÉÓÓ}â„Ïç{yy 8põêÕÇŽ[½z5õ(EæþùçŸÍÌ̼¼¼ÐOŠŸGÁþûB4ª Çñ™3gŠÅbgggdæääôÇ=ztÊ”)dArPX±bÅ?þñ²^ww÷U«Vq8œVŠŸDyY'''??¿Ý»w6 ÇñE‹‘AÚÙÙmܸýÝ¿ÿ;w0ÇñÿûßïÞ½Cï·iiiÿõ×_èÕ@Çûö틾牾9 äW è®0 ûꫯÆ'÷¼P(8p`}}½­­-ŽãÔ½Àápž?Žô‰äöÔü6r8œÀÀÀ{÷î)¾Ž‚ã8ze©.ËínÒÆÌÌ,??ÿÌ™3е(É Ã&OžŒ&9Çøá‡ÚÚÚÒÒÒmÛ¶q8œY³fI$’ Œ3F®Ÿu¾a ¡\ŽÍœ9ÓËËKWWð.]ºìرcÖ¬Y8ŽÓî}Xlò¨»víÚÛ·oÑ]PP R;Iöó(Jôähõö0Ê àççWUU…>®­¥¥URRrêÔ)r`jñøI¥ù·ÿþ’’uuu ÃΜ9#‹­­­qß²eKuu5 >55õäÉ“ÈôiÓ$É·ß~K^8Ž?yòäùóç\.Wù¯r®0 SSS+**:xð µÛ ô¯ýK[[ûðáè BöÒƒl„–˜„Uê â,d,×@6þÛm¾aÿ;*æØ!CÊÊÊPE …hú§Ýû°"///44tÇŽ»víºxñbYYÙ’%KÐH¤R;Icø“ž“Þ5;;;±X¼~ýz‡ãîî.•J'OžŒãx+ÅOÒ(Í¿ &H$’™3gâ8žýñãÇ_ý]Q¡ÌihhˆD¢;v Îqqq‘H$Ô³ø+W®$$$p¹\å¿Ê¹BÄÇÇß¹sGîÒ fl4ÙKªœ• ²ÑT)+¨Ø@•þÛs¾QýÐæÇóòò …3fÌ …¿þú+¹»÷>*ùÏÀabb2yòä &888”••}øðÖéÞI¥RR÷Žª(•JI@ Ø$–-[–™™™••uëÖ- ÞUoO*•^¼xQ__ĈÔ¡3:::..nÆŒ8Ž;99¥¦¦>}ú­‘køU–¥jþ;v iþ…‡‡çåå9::N›6MOO/00pâĉ8Ž[YY…‡‡Ñ£G>Ÿ_RR¢bϰ€ÖUyy9ºiFBêNPwGZZÚõëׯ^½zêÔ©®]»^½zUnôDÒƒ^^^;v}Z*•îÛ·OKKëÌ™3äaß–ñ“šnnn®®®‹-Ú´i“L&{ôè‘………½½ýƒ¢££³³³7oÞœ——ED~~¾X,&ÜGEEUWWS8ôìÙÓÊÊ ½¦üW9W]]]¡P¨2xRƒP&“Q5ѯãÇÏÊÊš0aêØ&K"¡AOOO%Bƒ´ù@¥™²‚Ÿu¾1åØÐ¡CW¬XñèÑ£¥K—’­ÀXï}¨ÐœÆÖÕÕuèÐeù˜˜˜>¬]»ÖÔÔÔÌÌŒzUA»j”‰û÷理¤xzzöìÙÓØØxýúõ±±±/_¾”æ ?~)ÿÙØØøøøÔÖÖ†……YXX "¯_¿æñxÞÞÞèE‡Q£F%%%aÌÊ$¤ÁàÁƒ·mÛvíÚµ¸¸¸^½z)dr‚ã¸H$z÷î‘‘Ñ£GÐôèQÏž=ÓÒÒЕœ’²Lþ?—|cʱÇçææ:;;§¦¦R—¤‘{Ÿe<`´aRR±%j^ IDAT’žžžÜ &D"‘‡‡‡©©ijjjlllyy9ùÓæÍ›§OŸÎr"$bõêÕúúúééééééšššëׯ§½™vùòe‡sýúu&ò6‹_$­^½º[·n™™™¥¥¥{öìéÕ«ŽãÅÅÅqqq‰‰‰èÑѵk×ÔÔÔÈAðgÏžQGmذáôéÓ;wî,,,|ñâE§Njjjþýï£;¢Ê•s5cÆ ==½[·nann¾dɹëEòÉÙ“'OLMMW®\™””dff†ŠTUU¹¸¸Ô××GGG———‡„„¼~ýzÆ R©T¹[ ÃHƒ3fèêê.X° ###ë¿Ü¿¿oß¾Ê=P _¿~]__ãÆ ´ÓoݺUUU˦,-ŸK¾ÑæØ?ÿùO{{{///±XüóÏ?6ìçŸæp8Ô½¯2þE…Ÿ|SÌ1jÔì¢î}Úå*€Eñ¥l}}}''§>\¼x±ˆ7?~%13Ù:t(>>¾K—.rÛÉ?ÈÉIù¯TWÓ§O/**3f ú© }´EäþUé¶ù,mZ¤ìç’o*sLnïЦ´™ àüùó+**"##[Ðí'Q1Doúøø4ÿÝgÒU\\œ»»;õ*¤± aSD¥Mó XÚ´FY*ŸW¾½~ýšº÷hSЊÜM¶VªHÉ ±æ¸m›øåàr¹-%ƒ\uïÞÆÁäóÊ7ØûT¨oêééÅÆÆAkбcÇ{÷î544¼{÷®ÉA4ʉ¶¶¶¶¶vMMÜv}}ýN:ÕÖÖ69Œ&£²—ÚsEîîî;wî¼zõªJŸljg²ilÙæ·”}»ø›ÃÁ0läÈ‘ööö8Ž+þ¬®®Îçó•”çóùãÆ366¦-ΖN†.rss_¿~mccƒìG•›››ŸŸkggל`š€Ê^j)ƌӯ_¿–õÙ§O6=Ʀ™Tj^±)Km]ó»”}»Z%QÓÊfddTUUUUU•••%''ïÞ½›Ãá´P°(ÎåÒ\r¹\凟–––X,öôôlÎQÊÒÉóçÏß¼y3|øð&&&>yòÅœœœüüùsKKK ‹ÄÄÄgϞѶ¥õPÙK-EQQÑáÇ[¶®½{÷–——óx<•–lšIµ¡æ›²ÔÖ5¿KÙ·«EPr5­¬@ 8w½½£££———H$Úºu+Ì…ÐðÖ­[gll¬¦¦æååuâĉe˖ݸqcÖ¬Y¾¾¾‰‰‰!!!<oëÖ­W®\™8qâàÁƒ“’’üüüd2™œ;OOÏ’’’3gÎÈd2ww÷áÇ———Ÿ>}:33“z‡ŠÏçoݺ•¬èìÙ³†q¹ÜþóŸ&&&111§NBÎ=<<Þ½{Ò©S'ƒ¼yóF&“=yòä›o¾ÁqÜÐÐ077÷ðáÃIIIA/Y²„zr½hÑ"MMM™Lfgg7zôèC‡Éd²þýû»¸¸¤¦¦1wîÜqãÆI¥Ò;w†!¤¿¿ÿO?ýDÛ,{ÉÍÍmôèÑ999—.]ruuýå—_d2Ù@¹;xŠñP•‹Í××W&“999͘1£¼¼üÚµkñññ¨“Ÿ+V 6,99™[W¬XÁápPGaæîîÞ¡C‡?ÿü“ŒŸM3I›Õ«W“yuìØ±E‹¡íÊ£"!ýŒ1búôéÔz÷îÝ—/_AÛ^ÅvÉ1oÞ¼‰'VWWÄÅÅ¡RNNNÓ¦M#âÎ;>$÷>Ó®”Ëm¹Æ ¦tRt¸f͹²d¨UUUÑÑÑ2™,""bêÔ©ûöí£mÍâÏ?ÿÌËË+((¸y󦥥eCCCJJJjjê8NAAÁ¡C‡8Ž––V}}}||ü£GBBBêêêüýýÑvòbîÀÕÕÕ³fÍÂq<  ¸¸øÚµk EEEämLòFV¤­­-‹ ÃÂÂBCCÅbño¿ý†²‚‚‚#GŽ(^%ܽ{7&&†¼Ú _½z5!!zr½oß¾’’uuu ÃΜ9#‹­­­qß²eKuuu=0 Û¿EEÅíÛ·ÃÂÂêêê/^Œã¸b´=€‚TÞK†íÚµ«¡¡!<<üéÓ§R©]¬PHBF¹f’‹ÃálÞ¼¹ººúîÝ»ÑÑÑ%%%cÆŒÁqœÉÏÑ£GëëëŸÍÊÊ’J¥ß~û-Žã´í¥mµc½½½kkkƒƒƒŸ={& 'OžŒãøÖ­[kkkŒŒŒTSSëܹ³X,>wš:ä¨#¯X,öõõåóù\.÷äÉ“ùùù<œ¿ûî»ÚÚÚíÛ·s¹ÜŽ;ÖÖÖzyyñù|çÏŸoÚ´‰z £RdEèß³gϪ©©!çeeeÝ»wÇ0ŒÇã)üóçωDäŠaØÐ¡Cƒƒƒccc‹ŠŠä. %ÉÌ™3qÏÎÎþøñ㯿þÊáp_¼x¦ÌóçÏ{xx ¦ÅÄÄs¹\Ú {€M/ikkœ?5ðĉäDHÛ@Úx+"c366.--õññAEbcc¯\¹Âåriý¡‹H´= @(òx<;;;±X¼~ýz‡ãîî.•JÑ{ö,ÚxñâÅÅ‹1"""‚¶uuu´¹Mm¬’*:TÒQiii(“»víºpá«W¯Ž?^*•*é.šÍR6ËÍe2õ:FWW·S§NUUUäQêìì¼aÆyóæmÛ¶-**ÊÝÝýýû÷rž™þýðá†aݺuÃq\ÎÆÀÀàüùó¹¹¹k×®¥N!ÙÙÙ;wîÄ0¬¸¸ØÃÃc÷îÝEEE¤Û¨¨([[ÛÎ;¿zõ* àûï¿···711 BoΟ??eÊ”èèèêêj==½ÂÂB•½!×ÊmÐýÆÜÜ\å>Êã¡BúÑÓÓÃqœÃáhjjb– x<ÞÙ³gý¢‹cÅþ¿~ýúÏ?ÿܳgϱcÇ’iU¦+šÐ:*û÷ï·²²š3gÚ­´íej‰®®.†aÈ )) Ã0´ÆøãÇhcAA†aJÚH›Ûm ›NKOOGϳ1 »uë–‹‹ õü€¡e9\¾|ù—_~Y´h‘››Žãæææ³gÏÞ¿¿­­­½½}ÿþý·oß®ò°'ï õíÛðüü|ÅþÔ©S . …h‹¥¥åíÛ·GŒA„L&ËÏÏïØ±#I=zdaaaooÿàÁƒèèèìììÍ›7çååEEE1yò䯾újÆ NNNß~ûms^ˆdMææælŒ›OVVAgÏžusssuu]´hѦM›&NœHëG 1`Àŵþ§OŸ–J¥ûöíÓÒÒ:sæLk ¸MhÝüùóW®\¹gÏžððpm{óòò˜Ú…@§bVVVÈÀÙÙù»ï¾C®Ðcc Æ ‚aXJJ S0*s»Ó ¥4"%%Çq6~5þp0 «©©ÑÓÓS< fA‡ºwïÞ¾}û ¤©©éãããááA„H$"¢¡¡ iÓ¦1É‹/îÛ·¯±±±§§g~~~DD„\__ßQ£F­Y³F,uìØQ ØÙÙíØ±ÃÀÀÀÐÐÐÅÅ%33]S’ܺu«cÇŽæææ—/_–J¥?ž8qbTTyŃã8zOíÚµcÆŒiñ% 111>|X»v­©©©™™™‹‹ Ù ´}ÒØx?~œ‘‘±aÃ>ŸïêêêììŒã8­Ÿ'OžmÙ²ÅÈÈhÀ€ÎÎΤÿ‚‚‚ÇÏ›7ïåË—ÉÉÉÍœ™òªQ­377?tèPxxx@@@=ŒŒŒºtéBÛÞ§OŸ2µ ’••µqãF}}ý>>`ÆŒ?ÖÒÒjZ'0!‰<<>>õõõŠí­¨¨PÒ. ÃÖ­[gff–““Ÿ••ååå%•JW¯^­¯¯Ÿžžžžž®©©¹~ýz%Ïáis›llNNNPPP£vmGa¶lÙ2”êOž<155]¹r%zGHu×ÐXpïÕ«—……‡Ã‘[ÄHý—ú7²TÜŽø!uuõaÆõîÝ›|™Éù¯¡¡¡ ŸÏ'‡¹"r 3´°°oß¾ýúõ#7ÊA†ìåjçr¹æææ<j©¤7˜z€ÉUjee¥¥¥µgÏò]oÚU£lâ‘+ˆ:ÁÊÊÊÖÖ–Ïç“/œÐúAÁX[[p¹\êÒJOOO¡PH»@±±ÉÀ”Wj*KÙÓ¶WI»¨½dmmMMK´qèСC† ¡æSis›ÚX6 ”Ë ²,µ·åZ 7E Õiì >›ºØ´²Í/®’iÓ¦mÚ´iæÌ™Ë–-ËÉÉyøð¡ò¯4-ÅRJüÈm×××wrrúðáÃÅ‹[ðÓ<´µ·ToÓúQé¹EBbrÒ4oL¾¾þúëÄÄÄÊÊÊ   ¶·oþüù‘‘‘ÆÆÆŸ:€¶£}Å_0h¹?šüÐjÀöö°Ý!D/´}êXh@°=B•6 GØ4ø|>Zû©€/Ð#l@Öô›SÖÈÈèúõëååå™™™ G­ è6Ð#¤µ=Âæ”½yófffæ¤I“ºté²nݺÚÚÚfe0z„ Gz„íQpäÈ‘OŸ>•J¥G;vìøñãFÕ4E½&×Õœ&´”B GÈ2ªÆ:Wô£Òs‹„Ää¤iÞ˜*Ùð™z„í“ö5Áà G@{ô[Ð#Tiz„´[@°=BZÐ#lrÙˆˆˆÊÊÊ*FÕÞ-Àè6Ð#¤µ=Â&—µ°°°³³³³³»téR^^Þèѣѿ-þ†+è‚!èbíOüˆ ú~oLL ú².Üæ€Vô1Ð#=Âö§Gˆð÷ÿ?öÎ; Šk}Øgv#°‚b‰%X¢¢Ø%–Ø»Þ%¶/c4ÑÄ“h“kØ¢þìz ((( h H_`—Ýïs;™™3;»3»,æ}þÒ³3gÞyÏ{ÎlæÙöìÙ3«}®€(à#Dà#¡íù1p!+>Bð‚Ð}„X žwšrù?ÿüó &,_¾üÆ3gÎÄñúYÛûB/^¼X´hѪU«°¸1|„uëÖÅ>ÂO>ù„å#Ü·oß!CbbbJJJêׯŸm4õ ÄÄ×GˆJLLT«Õ*•jÏž=Ü~„}„ß|ó öÒ?ÓÅT¡È³c‚}„cÇŽåúéó5ÃGˆÂ÷›ê#äÖ¶©'hRÒ°(à#áÿ¡ø°&à#D|„à#´1!Ö|„à#¡Íù°6$o!ø€þ·|„ÜͰ8–x+jžQÏìcI9¹ y$ÀG(2*S;çöc´gYB"ub^o¤^ÀG`›ØÖZüC[|„2>B£Û€›|„2>BÞmÀGhö¾}ôQaa!KF¸eËx X ðJ|„¼Û€Ðì}ÝÜÜzôèáûŠ•+WVVVbï˜|!ð_ÀG>BðÚœðÅ‹¹¹¹øX^^^3fÌ8xðàÑ£Gák^°à#Dà#¡­úB§OŸ~ôèï#ð"ð‚ÐV}„óæÍ+//Ÿ0a|) –|„à#¡úßzë­+VÂ… 0`É’%yyyæõ€HÀGˆøÁGhc>ÂöíÛ/_¾üÏ?ÿ¼sçNÓ¦MqµÃý2`!ÀG>BðÚœpøðáõêÕûàƒè³~üøñÙ³g­ü²ð‚äCà#!ðÒÿ¶´{Öô‰`A,q¶yF=³%åä2䑡ȨLíœÛÑže ‰Ô‰y½‘:x}!€mb[kñk >Bl ðÊøn>BlðÊøy·¡”}SSS±†°¨¨(===$$¤K—.¶ö»2¼>€P"à#äÝ|„RöU«Õ{÷îíÕ«—¯¯ïäÉ“’’’œeŠ€ÿ>Bð‚Ðæ|„˜ââ☘½^SZZzâĉ¾}ûâäòžf>B>BðÚžP­VÓùÇ6±qãÆÁ·£ ?à#Dà#¡íùÕjõöíÛ›5kæááÑ·oßÈÈÈgÏž‘Ì_H|„à#¡úg̘1}útƒÁP\\|ïÞ½iÓ¦åçç ä ó!øÿ×ømÊG¸}ûö€€< ¶ùx=!øÿømÇGˆÒëõºWp?/ à#D|„à#´1!Ö|„à#¡Íù°6$o!ø€þ·¥}„ÜñÀXâ­¨yF=³%åä2䑡ȨLíœÛÑže ‰Ô‰y½‘:x}!€mb[kñk >Bl ðÊøn>BlðÊøy·¡Ùû=z4>>ž¾e)::úîÝ»ô£¢¢ÂÃíì€×ðJ|„¼Û€Ðì}W®\YQQáááòôô,//¯ªªÂÏÄqtt,..fŠ)øÁG>B›óFDD,]ºtРAÿ÷ÿ7bĽ^_PP0zôè{÷îùùùÙÛÛ_»v ¾òÙ!!ømÌGHQTnn.þØwðàÁ„„„ÈÈȳgÏ*•ÊU«V•••¹ººJùЀ|„¶ç#¼|ù2þ’ÿÑ£GAAA+W®|ñâ…J¥ ¹}û6ü@2>Bð‚Ð}„qqqÓ§O÷ññiÖ¬ÙÙ³gÕjõÒ¥K‡ Ö¡Cüå­@Ò0 žßQäòžBÖ.Â>ÂùóçÍš5‹ùÅí#3f övìØ‘å#Â[·n¹ººR¦ûj[ä MZdd¤““Ó'Ÿ|òâÅ‹sçÎݾ}ûñãÇãÆkÚ´éõë×áB2>BðþðÚŽðÂ… %%%ƒ ŠÅŸ£¢¢¨×ëÃÂÂàB2>B„ÀG>BÛój4šû÷ï{xxо°ððð&M𤤤à­ÈøÁG>BõÆÅÅUTT?~ÅÉ“'‹‹‹oß¾m4ó˜ ɇÀG>Bà#¤ÿm!kº¸_,ˆ%FežQÏìcI9¹ y$ÀG(2*S;çöc´gYB"ub^o¤^ÀG`›ØÖZüC[£æùIÞAúï ­ øn>Bl–šä#ðþöÛoéééÉÉÉ………V6Ô€wðJÙ755µøï|ùå— ^KQS|„$ïàçŸ^XX8wî\ggç~ýúµoßÞÊ÷¡€wðJÙW­VïÝ»·W¯^¾¯Àê@vjŒÐÝÝäœ3gΩS§vìØ¡Õjñ³’™Ç!ø™Ô!¦¸¸8&&†>(|Ç –¢fùéNhï £££F£ùâ‹/<þüÞ½{³>‚|„45ÅGˆR«Õ ¡+Q³|„\ï`‹-t:]bbbBBB|||yyù/¿üÂÜ|„à#ÄÔ,¡Z­Ž‰‰ùý÷ß7mÚ´iÓ¦O?ý.Š`!j˜ëÄí7oÞœ;w®^¯_³fÍ‚ víÚ•’’‚O|„à#ÄÔ,!BÈÑÑÑÃÃ7VËíÐðçV¹|„Ÿþù„ –/_~ãÆ™3gb ŽÀx}„¬m°w!ôâÅ‹E‹­Zµª¨¨H¯×ß½{¯/‡þôÓO}||RRRèn±°nݺØGøÉ'Ÿ°|„ûöí2dHLLLIIIýúõ³³³fâ>Bxx3Æôó!„ÕjµJ¥Ú³g·aá7ß|ƒ}„ôÏ´F1ÕG(òì˜`áØ±c¹>Bú|Íð"„ð½Ç¦ú¹µmê ŠIZDDD@@ü£‰À jŒäÌÍÍÍÉÉ¡UÎÎÎ!¦Þ|„¡šæ#D¯> cà*–£Æø¼ƒ'OžœBT}„X’7Ù˜"{•Je«V­°Žw)!øé½j„·0°,–x+jžQÏè–PÜÉeÈ#>B‘Q™Ú9·1%$=$R'æõFêàõ|„¶‰m­Å¯1øþ àÇÁ1µõHÊ ¨NìììŽ9²víÚô ¿««««««¼}ÚÙÙIüj‘w–:880Di ²G 5..núôé¤ò¨K “Equu•ýÆcñ899ÙÔ_bX"Yfv™!›¿@Z9“Vƒ4Á­=d1Ÿ­Y³&!!÷nC„ÐŠŠŠèGoüñÇ………ôáèg~šmQQQzzzHHH—.]L½B`µ¡F£©¬¬dª ¥æááqìØ±’’­V›••µjÕ*“r¸}ûö'Ož§¥¥±nwüí·ßòóóµZmQQm[”%‡ùùù<05TRöH¡bÆ—››Ë}*:†·~,1L²Ô «°Û·oõêÕ²²²ÒÒÒÐÐP‘ý|ôÑGÌ3ÂlٲŤqéܹsdddYYYEEE\\œôévõêÕ¢¢¢b={ö“1Þx¸gJ?xÝ(Fg™eFšzfçíèÑ£ñññôÆÑÑÑwïÞ¥ÿnÒýh²,’¼^Yt®žy$Ý|öÎ;ïOš4‰7cÇŽÅtLŸg```NNÎÌ™3§OŸ>}úô1cÆˆÏ 3ÚÉ“''$$$%%áʰ6lØÀy{&© ¥vâĉG 4ÈÅÅå³Ï>+++3IÓ8a„Ï>û,<<<##ƒ9I¶EYrØ¿ÿÀÀ@Fóõ×_‹Õ<1$EQ'Ož¼rå w®’êÇÃ$Ký`¸…}õêÕ[·n½ýöÛ¾¾¾III‡¹0¹¹¹õèуž€+W®¬¬¬œ¢¨yóæ•••ååå-_¾\¡PŒ=Z§Ó}ðÁâëÍ#+2“»[h¶Î}úèѣ̡—>ËL*3D˜zRò^PPàãã³{÷î~ýú=|ø°°°[Û£GÊÊÊóçÏsgÍ‘“ÉêZ‡­3x0j>[¶lÙ XeN¿êàà Ñh¾ûî;îÙ¶oß>??Ö¬YX[C"Œˆˆ¨¨¨¸{÷îÓ§OËËËY¶Â÷ß¿¨¨(333##£¨¨hÞ¼yÌWÕjõöíÛ›5kæááÑ·oßÈÈÈgÏž15@C† Yºté²eË>|˜˜˜øõ×_/[¶Œû›Wm(1°þýû§¦¦†„„̘1£V­Z¢²ÿw¶mÛÆ|[*`[”˜Ã´´´ëׯÇÄÄäääܹs‡ôã. 3ĘøøøÓ§O3ߣ Ô蘭»ôúá-ì>ø+¢ð–ø¿ÌP…ÃÌ›7¯¼¼|„ ¬rYÕ˜‰'j4ú‡7)éÂàO„¼ËœXñ`¦M›–ŸŸÏ½SC–Yfj™!ÎÔCÒòvùòeüEߣG‚‚‚V®\‰?î„„„ܾ}›Xu¬ÑLV×:lÑy$„Z­¾ÿþÉ“'Oœ8qâĉü‘Õ¯‚óÕÖ­[ëtºùóçs£9}úô… T*ëd‚‚‚–-[fggW»ví3gÎdee1ë¢(??¿âââòòò1cư>تÕꪪ*N§Õjóóó###YßüðÃiiiéééåå奥¥ééééééX;ÎìÇËËë‡~زeK~~>툗EQ... . /--½uëV«V­XÃpêÔ©ØWðÖ:ï…pÇŽØæº~ýzüö¢(‰9 _²dÉâÅ‹W¯^‘‘ÉÚF8TnöBeîH/t‹@ýXb˜d©ÞÂ6:…C½õÖ[ÙÙÙ»víâ¾$²ªBÞÞÞÏŸ?ß³g)éÂ\–47ÌÅ‹?Î=œôY†L/3Äw!”’·ÿûßyyy¾¾¾:näÈ‘]»vÕét£FzöìÙüÁŒ¡ºFÖh&«k¶èC† ÁßÈÓc:ëyßÇ?xð`hhè‘#G¸°eË–ZµjÑOždMúé”7nÜ {ã7xÛH‡ñã?–––âû’¥F]©Túøødddpã={öâWxyy½ºººVVVbk>þÆÌÛ¤WµÀ…P¸NxãA5hР¸¸xÑ¢E¼ƒ.q–!ÓË ñ]¥ä ÿ¸cǵZ[MIIÙ¹sgUUÕÌ™3™TïÈ g²ZÖá‰'Zn!BÅþwÔñóDHÂ/¿ü’Y/_¾dn™™™©Õj¹GõôôŒ‹‹Ã¿ 8::R5hР¼¼¼ððð;w†††þù矃ÁÞÞÞ`01¿4Ðétöööz½žû ¯^¯gZ㹯Ò.SƒÁ ÓéX=tèÐaÕªU«V­Š5 ´Ú0''ÇìÀüüüvìØ1k֬˗/ëõú[·nݸq£M›6¬Øþøãúßb~q°-JÌ!þÉ'*))‰¢(gggŠaB&…JÊ~·$,†DÕ«WïùóçÌRýXb˜0ë‡TØçÏŸG5kÖìÚµk¡ÆWVV&''‹ láÂ… ð÷÷ÏËË3#*Ì®]»&L˜À°HL—0Â%ÍBÈÛÛÛÞÞþþýû¼S@â,C¦”™RòváÂ…’’’AƒÅÆÆâŸÁ¢¢¢¨×ëØTËÈŠÌdµ¬Ã>D›GH bñý?¤7JˆqéÞ¤äää;wr¿PU¾bÊ”):®W¯^øê}íÚµk×®5nܸI“&7oÞd}iÎ<.·Ñh´4ׯ_ç½ÒÕÕ5'''44´Aƒ 4ˆŒŒLII‘XݺuÓÒÒ¢££;uêDQT¿~ýž?¾ÿ~SŸ^ÍûýLvv¶ŸŸ_ݺuÏœ9óìÙ3lZ—˜Cúûýnݺ?~¼¨¨¨C‡b¾OÈ)T&YYYëÖ­S(:tؾ};¾ož·~,1LHŽú!6EQqqq‘‘‘5òòòJLL$Ý6Ì ¬}ûö¹¹¹ûöíkÞ¼¹Ç+x¸%E… ÊÏÏ:t¨§§'î¡víÚHZº0æýFHŠ!4mÚ´ªª*oooƒJ™eâËŒyެ©'1oÑÑÑz½~Á‚øˆøçä¿þú‹´&XsdMZ¯¬¼[gñ þ”HìØ±ãÞ½{‹>ë{Þ¾}ûþõ×_eeeååå÷ïßïß¿¿øŸ4ÅG‹—*Þ—ÆŒƒÐh4ÉÉÉï½÷žôÀz÷î}ùòåòòò‚‚FsêÔ)3Á®®®§OŸÆß³?~üxìØ±²äþ~¿¨¨(>>Þßß_|²G •‹K;v¬V«íׯEQ¤ú±Ä0ÉR?4¬ÂîÑ£G||<,**Jü£Õ/^Œ¿’Áƒ‚á]×¢*))Áo½é&NœHQ””taÌ»’âAÍ›7¯ªªÊËËˤ‘¸Yfj™ÑçÈšzó¶iÓ&FÓ´iSüß7ß|óåË—{÷î%`å‘•¸^Yt¶Â<âAºù¬k×®%%%Ü…†¢(¦é¢(¥RÙ¦M›–-[ªAËEKÀUJ ïëîîîãããììlêgAŒ‚¡©£QòÙ%æ ÷û}aHÙ#…JsèСˆˆ|‚wîÜÁÿ&Õ%†I–úaFÈ ¬U«VXU(>0úÖ¸˜ ·€”t1Ã3u/R|øàÁƒäääû÷ﳾͷ´Æ¬zÍ|ܽüýýúá5®aÌP£Ñ 6L§Óùûûãn·lÙRVVÆÌ§õ¥hòjÛè>yëÄ:F4 s%Ñ$šÞ0ÂB5“ŠÊh¢lA­'>3æU‹˜¬ í|ávK¯<¼ªN&â‹„´ÎXmý±~þM8ÌÚµk³³³·lÙ²uëÖÜÜ\ü©–~•²°Æ¬zÍ|ܽú!×0&©ÑXiQ(ÏŸ?_»víþýûóóó5ø³³„M^mÝ'o;YŒhˆ3‚h”4Ó2&TC&•ÑDY¿ŠHSÆrÕb4«¦®HFÛ-½òðª:™ˆ/Š¢x×R»Ès_9ÖÏ?Vw½zõª¨¨˜1c†R©T(K—.-..fÝn97ë›ù¸{ñöC2®Ñ˜¤Fã¦ÅÙÙù§Ÿ~:uêÔæÍ›7lØPXXÈʧ5¥hÜqAÖÝYÁˆÆAéF4$Áô†Œ Õ‰Ee4QÂñXG­'23ÈÜjAfiêXÇ5i!ŽGúÊCñ©:™˜T$¤uÆ:ëõóÏ‚ø¥¥———R©¼wïþ&:55ÕÞÞ¾I“&Ìïô-§1ãb}3w/Þ~HÆ5“ÔhÜ´,_¾œ¢(ƒÁpðàÁÌÌLV®¬)EãÅ¢º;‹Ñ0ÜLIIAæѤ›ÞŒ Õé¾=áD Çcµž˜HŒbM,´ò¨:™ý›T$¤uÆ:몎üóú®zyy;vÌÕÕÕÝÝýüùó™™™øŽMß¶Ëø!ª&3ïígÌHÆ53ÔhL|||ÜÜÜBS¦L)))Y½z5ï^¤QQІ‘]Û†DÔ iì$Ña) F4‰¦7‘B5“ŠJ|¢¬PEb¦Œ@$Ȭj‘¤©c×ÔO$¤x´•G@ÕÉĤ"!­3V^7ÿbCQÔÔ©S?~¬Ñh4Mjjê¸qãLý…YÞ ¡ šùŒkóÔh¬<”••–””lÛ¶ÍÞÞ^dl¥ht<òjÛ¹u"‹4‚fÑ4Ó›¡š©E%]8jµžø`̨Iš:ÆqÍ[ˆy±”ÆÔ"!­3V^7ÿDdWÛ¶mUVÔ˜ ì«´13ŸŠkwóÔhL …§§§O:uÌX˸iTIt Ô‰õuwRwºÞ¤Ì5¢ÑûšgzSˆª™ZTÒ%c2f#rᬚ}\³«WÊÊC‘ S‹„´ÎØÎú#oþM†¢(3–6ËAŠÇÖâD²ªÑlíÔ¸Ø`þ¥#ñŒ,‘Ù}{@Í…4餸?I’5pàŸ¨ÑÙ¢ŒEØ FdŠ 0  3`öª(-°æß4ÁÂÎήiÓ¦………R:quu­S§NYY™\Q‰ÇÉÉÉÉÉ©´´”Õ¡Õjyÿ®ÅÎÎîðáÃÞÞÞ.\ànШQ£’’V£«««R©¬¬¬´P» åJ<Ü?##µÛ`0¤TN„©ò…ËÙhÆ’b_£ÖkY4~Ù‚$KIq'W»,š+‘ðJ%Ií6˜Œ@*¸'Àõááû¤ˆå ‰f,ñö5K™°^Ë¢ñËî$Y²HŠ;¹Ú«=W4M’J’Ú«7 fxõxO¤aƾ 6nܨV«ñKf‹åa3Dû"[ÊÄ资°)§ ÅgÉ")îäj·‘\a¤†$©$o{µ$Ả¤‚t‚Ô+zõê•——7yòd…B!E,€\üoÊqÍXôKík4̧331ª×ªYNA^KIq‡½ÒÛEªò,+á&I%Ií¦&MbÄŸÉ«'`ͤû_½zõéÓ§=ª×륈å‹ÿ^GŽùÎ;ï( //¯çÏŸ¯X±‚¹¾2dÛ¶m%%%z½þÁƒ_}õÕÖ­[é –,Y²cÇŽ[·n]½zõرcûöícݼ0dÈ.]ºPåêêêààðÕW_ †ÈÈÈèèhzbWUUuîÜù—_~qwwoÚ´é´iÓÄ@ŠŸ»WAAÁÖ­[YýÐ×ì‰'¾ûî»sçÎe]Û*++333[·nÍ|Kîàààéé¹ÿ~‘‰ÆT¤{Æ'^§N¹Úm!WFÚÍÍÍÎÎnÚ´iø"Ô¶mÛõë×ýõפv+'Aü‰ Æ[=f*H'Bw>mÚ´·ß~ûÃ?¤w®|D(?dä¿”””sçÎ 77·?üðÈ‘#~~~ô\=|øpvvö©S§ìììþõ¯…„„0çjddd÷îݧN:räÈM›6ÍŸ?ÿý÷ßôè½dôéÓçã?¦(ÊÍÍ­ªªjÞ¼y¡²²²ëׯ3ßáÆÆÆº»»7oÞ|èС81âçÝ+++‹·ooï 69rdÿþýÜ÷Ý/_¾Äø¦iܸ±(å±u©Æ\‰è›7oâËÆš5k,X°k×.NÇÛnå$Ð/òDH©àžíøž:u*¼1;¨| ·ü3½ûšHK%¨×ªANA ëQ°$Å\í"Ë¢¹2:Ð$©¤››oû¤I“¬œ‘'BJ…€5!Ô AƒâââE‹±º®|ÄW~ÈÈ—iÁŒE¿3•b_3j)£×ªANA^HŠ;ƒôvægˆêÊ•Ñ&I%IíVNîÁl¯ž€5!äíímooÿþ}:N³ÅrÈŒQ3 ·Å$ûÉR&R¯Å€˜ø…OÄBNA®ÖŠWq'W»íä ÓÑñJ%yÛ«+ "O„7¤DM›6­ªªÊÛÛ›>©b9nȃD3–xûš€¥Ì¨^Ërñ[È)ȵd‘wrµÛB®0M’J’Ú«7 fxõH'‚š7o^UU•——³“Är"O“‘ÅŒež}Õ‰€^K‰ñ¤™ç$yû¸Š;¹ÚÍ8YÙs%^©$©Ý“ÀÛ 3fÒ â’`Ëhå3Ë[Gú;Væ Û²ëßH'(W{€4Ðí¤~dŽL&L­dÒö¬ò¨ÀìT#¬ò¨ÀìT#FËþ‰(«;€:5*))©î(l sÒ¨Q#GGGÈð?‰µdgg·lÙ²4iÒ䯿þ2Ú-LçŠÐ…pæÌ™+V¬8räˆÁ`0©Ó£GÖ¯_ÿöíÛÂ;ÚÙÙ5mÚ´°°ÐŒ}béà¥cggwøðaooï .˜q,)qZíM…7'^^^ƒ¡¢¢‚wÒ«tWË—/¯¬¬LLL”ñdyK÷õÆêÍŒ~"""´Z­Ù£ïààêááQXXxñâEƒÁ@š¶ÂÓ™÷éêêªT*+++-ÔnœœœœœœJKKÍîÁÁÁÁÃã  @d»“pþüù¥’}QüùçŸóóóU*•©fgg¯[·N¡P6ððð8vìXII‰V«ÍÊÊZµj½ñ™3gö­öàåbÍš5 4@¥¦¦¥§§‡„„téÒ…¢()q¦¤¤à> RSS·nÝêêêŠ_25ÉVƒ™„Ð÷ߟ™™©Óé4MDDD·nݘ9~•îjܸq¹¹¹½{÷fåÓÇǧ  à£>*,,üì³Ï = ùùù<`–%@éb®^½ZTTTÌ¡gÏž8|DÖ«[¶laöc´Ž=O—}ttôÝ»wéÿFEE…‡‡ûúú²NP|ÿ\l¡Þ̘›"G¿G¼¹rttÔjµ_}õ½’°J”†·}ûöíOž<)..NKKc®EíÛ·¿zõjYYYii)¾ÐÊÛ.1Õ.@çÎ###ËÊÊ***âââX³O$¿ýö[~~¾V«-**bVo»%’ð7®]»vñâEîµä—_~yùò¥×’œœœõë× ¤õĉ=4h‹‹ËgŸ}VVV¶dɼ½R©4i<¬¼,¼óÎ;ÅÅÅ“&MÂÕ£V«÷îÝÛ«W/__ßÉ“''$$$%%9;;K‰3##÷Ù§OŸÏ>û,??×®]8Q¦&Ù:°ròã?–––®\¹ÒÛÛ{Ô¨Q·oßNKKkÑ¢…˜W™]QuòäÉ+W®°Š¤gÏž:núôé:nñâÅ …‚…þýûj4š¯¿þš•(ÒÅx{{ûúúúúúŒÃ“«] bª]€èèè„„„.]º´k×îîÝ»—.]â=ô°aÃÈ{üüóÏ çÎëììܯ_¿öíÛãÍHí–HÂß`]KfÏž½y󿀀€_ý•y-9rdppðªU«ÞyçúÄÆ·aƵk×úùùÑÌz]´hÑСCY‰P«Õ¿ÿþ;>¢B¡8zôè™3gð—,Y‚··³³ ôöö^´hÑÖ­[çÌ™£P(øû￯X±ÂÝÝÝ ÁÓà`Úµk÷é§ŸnÞ¼ùÓO?enÀê|Ê”)sçÎÅøúú~ñÅøßmÚ´Y±bEÛ¶m)Šúã?îß¿O‡§V«ƒƒƒ•J%^¸GŒ¡ÕjG…£9räï¿ÿ¾iÓ¦!C†pãœ={6}8„ÐÌ™3çÏŸ4)eF IDAT¯P(222è> Å®]»>|È›dÒyM:uëÖ­ß|óM‹-­™GGÇ/^ìØ±C¥R᜴nÝ:??ãÆ …BøU„+½ãǯ¬¬0`³{÷î]PPЮ]»ŠŠ Š¢˜£ P(¢££Ïž=ËšT¥‹¡^±mÛ¶gÏžÙÙÙáÿ2;¡·iÑ¢EffæîÝ»¹G¨„ÐàÁƒñÂMQÔ¼yóÊÊÊòòò–/_®P(F­Óé>øàƒ>}ú°NPdÿ¶Yoˆ37Y56bĈÀÀÀzõê!„\\\¾ûî»Ñ£GS%fôI¹b]YuECjǩؾ};óBØ®];­VûñÇ+ Š¢–-[V\\¬R©äjgÅ0zôhÖÛ,n p«»³ÅÁÁ!55uΜ9x÷ 6¨ÕjÞOQQQ¡¡¡¼W¦¤¤¤½{÷ÚÙÙ¡W3B ÝBIøÌkɦM›***.]ºtõêÕìììÂÂBÜé—_~YRR“››Û§OŠ¢~ýõ×ÂÂÂS§NEDD”——O›6 ‰Y¯YYY6l`Õtllì½{÷Z·n·W*•t¦²²²ð·ŽŽŽIIIaaa111:îСC©©©¡¡¡/^¼ˆŽŽÆ»X4xL|||xxø¹sçÊËË·mÛ†·ávþë¯¿æææÚÛÛ#„vïÞ­Õj»v튩¤¤¤qãÆ¡äää;wÒGÁEIÿ·ÿþ:nܸqE}ýõ×eeeçÏŸ¿té’F£¡¿·¡ã ...ÆÝ:::æææîÚµ‹^˜è>ÿüóÏ{÷îáD±’Ì{^ßÿ}eeeddäåË—SSS«ªªXåeÑœ :T§Óýë_ÿ¢k—¢¨K—.áq~•›ÞZµjåää¬]»–9¬íÛ·ÿᇜœœÖ¯_÷bŽB“&M2226oÞ,¾tYà ¡ðw§OŸ~ôè÷{6z Ï777osðàÁ„„„ÈÈH¼­Zµª¬¬ÌÕÕõí·ßf ˜þm¶ÞÐßç&·Æ:uꔟŸ´víÚ‚‚|I3úÜbÀ°.„¬º¢!µc¶mÛÆ¼Ž?^§Óõïßæ‡~¨Óé:vì(W;]$...mÚ´ Ú·o_“&Mèoª¹5À¬vî^¼ý0?准†ÆÆÆòN„ëׯsßMâÄj4š/¾øbðàÁóçϧ¿»&µ[( ƒ¾–àß„ƒ‚‚ììì”Jå¡C‡ T*•§§g^^Þš5kpûíÛ·ÿóŸÿ(•Ê}ûö-Z´7ÆÆÆ†……áfÖ«J¥âÖGÿþýSSS CBBf̘Q«V-ú%z_\‚7nÄýÇÇÇ—••uéÒE¥RÍš5K§Óáë™Eƒg›V«¥;ß¹sgff&©ówß}W§Ó1‚¢¨§OŸ>þü§Ÿ~Ÿ®_¿®T*4Íwß}Ǽnß¾½Y³f}ûöŒŒ|öìYýúõ=<<òòò~ÿýwÜÿŽ;²²²ÜÜܘqúúújµÚ… *Š™3gVUU <˜¢¨ŒŒŒ+W®|÷Ýwßÿýòóó?þøcÖÅžt^NNNYYYûöí«U«–R©Ü¾};ï…Ðr9ñ÷÷×ét}ûöe¾‰ûÏþ“˜˜¨T*…_å¦!úôiÖG7¼sÒÒÒ®_¿“““sçÎî%J tY½Λ7¯¼¼|„ ¼ïÖyë¹ÍåË—¯]»¦T*=z´råÊ/^¨TªÛ·oÓïô™'h´[®7f?¼5¦R© †^PPðÓO?ÑÃmtôI¹b^yë !DjgVóBøÁ0«ÿ×××W®vºœÞÿý¢¢¢ÌÌÌŒŒŒ¢¢¢yóæ±¾ç­vî^þþþýLœ8Q£ÑÐ$0C† Yºté²eË>|˜˜˜øõ×_/[¶ŒùKm‹-t:]bbbBBB|||yyù/¿ü¢P(HíJÍßJ­Gû÷ï×étƒáéÓ§øö§¾}û:99yzz!„ÞxãV­Z!„¦M›Ö­[·©S§Ö­[W¥R¹¸¸p Ó鸑‘‘Ý»wŸ:uêÈ‘#7mÚ4þü÷ßÿÑ£GÜ»­ÒÓÓ«ªªôzýÇíííu:]BBB¨eË–QQQ žÅÓ§Oq0=«oç‘‘‘ýû÷×ëõõë×ßµk×À¿ýöÛŽ;;vÌ`04nÜØÎÎ.77—ÙùŒ3¦OŸn0Š‹‹ïÝ»7mÚ´üüü!C†899íÙ³ŸÔ¦M›Ö½{÷3gÎÐ;ÆÄÄܹsgøðá›6m9rdrròåË—ñ¹7oÞ|ðàÁøùùùÏž=y^]»vuuu=räˆV«5 >¬–œ˜oW/_¾Ä_šÑ œ%½^O7¦¤¤œ;wÎ`0¸¹¹}øá‡GŽñó󫪪¢7_ºÂ¼õÖ[+V¬8xðà‰'x÷å­æqqqÓ§O÷ññiÖ¬ÙÙ³gÕjõÒ¥K‡ Ö¡C|ã"ï ÷oûõ†á­1ƒÁðã?6ìÀ? ¤Îèè ç C*QKW^>œ}êÔ);;»ýë_!!!¬³ã­vÞ½²²²xûñööÞ°aÑ#GöïßÏ,ã>}úà·AnnnUUUóæÍC•••]¿~¹ÙÍ›7çΫ×ë׬Y³`Á‚]»váë·ÝrIÀüíÚØ Aü†53ëׯß1½ùæ›o¾ùfbbâ•+WT*ÕÂÂÂ&MšÔ»woÖÛUa þEç½÷Þ0`@Æ Þ³„g& ß+_«V-æ{«Òëõ8ZÞÎõzý7|||ÆŒsëÖ­C‡uìØ±W¯^Í›7 !­˜Û·o¯S§Ž½½½»»»ŸŸ_DD„Á`puu¥(êùóçx¯¬¬,„ýû(ÌcÇŽõìÙ³I“&ýúõ;sæ =ÒgÏž}÷Ýw СC‡ÒÒÒï¿ÿ^8Éôyá/¾ÒÓÓéCX9'EEE¡† 2]\\ðÅ@øU^D^¨>|¸nݺµk×.[¶löìÙ={öô÷÷g–™¥ËËÆ‹‹‹—,Y¼Ê2á­æ‘‘‘NNNŸ|òÉ‹/Î;wûöíÇ7®iÓ¦¬åF|ÿ5¥ÞxkÌ`0èõú+W®8::FFF2kS&Ä{‹EE…\íô¿ C@@@HHÈÅ‹§L™Âݘ·ÚB¬½Hý¸»»ïÛ·/=== €õgÅŠ-Z´ðòòŠ¿zõj«V­¼¼¼6mÚD—JQQ‘^¯¿{÷nUUUUUÕáÇßxã R»V«µP0ûD¨V« CÛ¶mñ?èöÇ †={ö„††âvƒÁ0tèÐñãÇòÉ'ûöí3 !!!"/'~~~;vì˜5kÖåË—õzý­[·nܸѦM1û `àYðv®×ëÃÃÃþùçúõ냗¤–-[Þ¹s§ZrrãÆ’’’=zwÒ¤I“Ž;:tÈ`0¿Ê›Þzõê=þÜhð8T< IIIE9;;S…"Wé.\¸pÀ€þþþyyy¤mxëÉ… JJJ «×ë CTTÔÀõz}XX˜Ñ¥¿FשÆ:wî<{öìðððéÓ§ïß¿ÿÖ­[øU‘£/ o] ´“HIIA5kÖìÚµk¡ÆWVV&''ã+·ôvæÐãK”½½½^¯ç¾å"U;w/Þ~víÚåàà0aÂî_ûÑÝâO/:ŽuôÜÜÜœœœ–-[âÿâ;–_¾|IjÏÈȰP0{¿véÒ¥œœœeË–yxx´mÛvÔ¨QøýÚÅ‹SSS?ÿüswww;;»>úß`FQþƒÊ€€€>}úð¾ûãÞ5§R©V®\‰ÒìÛ·oÏž=™Om0ëÏ‚ÔùÉ“'k׮ݲeËÇWUU]¼xqàÀ7nÜÀÅQZZš––Ö¼ys£'uöìÙ¤¤¤%K–4iÒÄÓÓsáÂ…·oß¾yó&k™ËÊʺxñâ„ nÞ¼ùàÁÞE°¼¼ü7Þ0zDLllì³gϼ¼¼Z´hÁüTdœäååíÞ½{êÔ©õêÕëÖ­Û¾}ûœ·nÝj0„_åMo£F>|h0:tè°}ûvúžlvvvݺu[³fMYYYDD„··7ÞE t…»enðöÛo/_¾üÏ?ÿ¼sçNÓ¦Mñá4hбcGáXGÑh4÷ïß÷ððÇ#Þ¤I“””üIN`_Rÿ5¥ÞH5¶~ýúôôôQ£F%''3ïÑ9úÜ\1IÓVütÆÜ½{7!!aöìÙ 6ôòòš:uê•+W***äjg+==]­V?yòäéÓ§ÜHx«Ý`0p÷â¶õìÙsÁ‚Z­wR»vm‘Àœ}º¼¼¼´´ôñãÇxàÚ-‘b¬E©Tª®]»º»»+•Jzð(ŠR*•;vôññ±³³ÃùR*•-[¶ôööV©TÌN˜wŠòÞ5Š{sww÷ññqvvffŠ´/7H:ëÏü·B¡î\ `L×®]KJJè1æÍ³ÿÎ;wêÔ ÿÙob—,YRPPÀ¼Ë‘µŽ™{8óR©T;vtttüùçŸé?Ê´ZNpŸõêÕóõõõððP*•ï½÷Þ­[·è¿x•ÕÕ¡C‡"""pxwîÜá½™Sõwð—¬]H¥Ëí–™æ¸{,f¤z`…u¼#iÝÓ?ª9õÆ­1æ™Õ%rôysźrsKCjçž&3øV­Z5kÖŒ.3ÛÅ@ªvóvg–ŠxpðxfîÎÛn‰$ÔþFQ¸E–IÁjÁK銢¨uëÖÅÇÇ‹¹[U¸WWב#G>{öìÀ¤EÐ †ºxñâ#F̘1#--íÂ… ¦v.WNXÏDî«Ì®† –““ƒÿØ!´fÍÖ­ÞFáÝ…õ_£ÝJß@ä6²ì[SêÍh™7úôføBXRRrðàA\]¤5i:Ó{Y´½F@AvR?2GXüWtkÖ¬1ãžC&'N,,,ŒŠŠòôô”+6„ФI“îÞ½[TT”bþ¦ WN˜]ݹs‡ù¬B¡0õDÄìbtéˆÜÆû2©YõgÆè37óóó{÷Ýw;tè@Á[¢2–.ü³P*•ø7-)àod|oNw‹¿^6ãk)È’fW5‚µIFjV½I}êt ©De,]‚Tg&ÕŸ,ÿ( ð[êS"2¿­#é©Hr)®®®uêÔ)++cµ“ìb"­cæ¹ÄlRФ ]³Çë]3uô­){¤P­_x–_‹RV<$‡O^,Àô¬–…ÑÆ-Ä&D1F@OÅ•Kp•lø×éž={Þ¸qC£ÑTVVÞ¾}›ùÔ8D¶‹‘ÚY˜ä£9pà@QQ}Fü13xü¨L‘Y2ÃÇ…”")Õì Cò®!‚ZL–šW®F²£!ëž%ÆW–£aͳ…pbÔŒF!­fÌñ Šxœ@ªI)’˜QÍž0$ïI-&KÍ󨑲G cÍÂ³ÄøÊRxîŒ0['FÍh4*ÒÊcvºŒ%…áG`ÅÓ§ÑéiÍú$Mv³.F®Éàò—„ †$—ÐS‘¤SôOнzõÊËË›}š÷;eüW«ÜöÒÒÒ6mÚà'×!„Zµj•žžn0›5k¶}ûö´nÝ:!!!::š>þÇêÕ«OŸ>}ôèQ½^Ÿ=lØ0üàD„PóæÍYE…„„Œ=:22’ù©¦oß¾QQQ܇7’ÚBË—/wttܰaC÷îÝéFww÷ÜÜÜ9s渹¹EDD\¹r…¹‹‹‹‹››Û{ï½çääUQQÁ},=ýôð’’Š¢x¯Á¤T ¤HJ`ééé hÑ¢Ejjª^¯Ÿ.†W0F_® —+RöB¥±NáYh|™ICf†;#ðß9§”™5‘í¡Ö­[ëtºùóç³z#µ#„NŸ>}á•JÅšÛAAAË–-³³³«]»ö™3g²²²˜Õ@Q”ŸŸ_qqqyyù˜1cXÁ0Ÿï—ŸŸÉúÊBdªyS$%0Š¢\\\.\^ZZzëÖ­V­Z±jëÔ©S±¯à­<Þ !ïèKÌ¡p¹ •›=£…бNáñFˆl ðxg„Ñ ¡p`¡·Þz+;;{×®]Ü—Ì^y$¦ #p!4:¸ñ`xW<£ñˆ™žÈŠõ‰ø.„Rþïÿ;//Ï××W§Ó9²k×®:nÔ¨QÏž=ûã?˜1X®$Z­Þ¼y3~4ŸâÕ3j§L™B'Zñêéˆ7nÜ {ã7xŸUèîîãÆ úGxWW×ÊÊJ,³FõìÙS§ÓÑ=7hР¸¸xÑ¢E¬®ðwÐ …âÇ,--eéÐB—.]âWR;2}¼ýýý+++ׯ_¿dÉ’­[·VUU­^½ke˜ɱ¡»mÛ¶Ì¢<~üøÁƒCCC9Â]¶lÙR«V-Ò‹L5oФF]©Túøødddpoy˜={öâWxyy½ Œ¾Ä —«ÑP¹Ù.T+)B$m|¥iFLš4‰{!¤Ÿk40„PXXXjj*¯ÆÈì•Gbº0Báã‘W<‘ñOOdÅúD|B) Ç¿îØ±C­VãeSRRvîÜYUU5sæLf'*‰ÿž†°†Í¨\ ÃÕS‘äRø¿ÞÞÞööö÷ïß§¿ÿíСêU«V­Z‹Årµk×~óÍ7srr˜"ÙŬc¦ºÄ<==ãââð!ŽŽŽE 4(///<<|çΡ¡¡þù§Á`°··7 EEEâõWž9£©H‘Ù‰ÔìýñÇô¿Åüp"0ús(\®¡’²÷øñcB¥±BáYb|1 4#Ο?$á„ÕŒf¯


îŠÇDâôDV©O¤$\¼\Ó‚%Áüý [·nÇ/**¢Ÿ­Çäúõë¤;ô‚‚‚òóó‡êééÉÔSeggûùùÕ­[÷Ì™3Ïž=«W¯ÞeÚ´iUUUÞÞÞô\]]srrBCC4hРAƒÈÈÈ””îá²²²Ö­[Ç}@·óZÇ’““wîÜÉÝ‹·¿ùÂL™2E§ÓõêÕ GríÚµk×®5nܸI“&7oÞd}…MÃûµ€þ†)Õ)2;°ºu릥¥EGGwêÔ‰¢¨~ýú=þ|ÿþý¦>F‹÷ÛÞÑ—˜C‘åÊE {…Jc…Â³Äø"9 4#(ŠŠ‹‹‹ŒŒlÔ¨‘——Wbb"é~cn`íÛ·ÏÍÍÝ·o_óæÍ=^Áû‹¯+”taÌûâ[ñÄÄ#~zZ¡>i¸“]b£££õzý‚ ðñïÐýõi’¿$Ä‹©ð4à ‹¤§"É¥BóæÍ«ªªòòòbö3f̘¿þú«¬¬L£Ñ$''¿÷Þ{¬Ä1íb¤v^ë˜y.1ÄùÙ£oß¾8Âòòòû÷ï÷ïß_ÌŒ¿ ¤š”") "Åäї˜C)5Rö cµÂ³ÄøÊRx4¬a¶nñâżjFnf¬ÿYìbâ­cJp‰¦…Ø2PŸðšN5Àv€jØØÙÙqŸ de\]]yÿ¨ÅÕÕUäSáe‡·šñ_g[?DˆÇÁÁ¡E‹6õ¸““ï-©qqqÓ§Oçýz‡·…Ý‘#GÖ®]ËÚ’ÔÎK“&MŒnc5^¿å’4ôRf±…V'ëW#©öl¤&mí¢nÕ«’DMEõ{ÕeA#é¸úõëWQQQQQ5:"ÏT¢ÿ¬¹¤•¨šd“4ƒ ºwï^EEEaaáÎ;ů˲ÛÔd÷½I,0Yf1ièÍžÅHÚêdt°f5’jÏj’TËŽQ$.#¯Jæ QSgQýž,h¼t\·oßNHHèÔ©S÷îÝSSS/\¸ 2‰þ³ä$yÂ0”Õe“4...Ož<9þ|óæÍÇŸ››Ëû‡É¼ÈnS“Ý÷&±Àd™Å¤¡7{#i«“ÑEÀjÕHª=ë×$/¤j$µ‹Aâ2"~ÜÊ5ÙHÔÔY_¿g /AÇUZZúý÷ßã“ NOOŒþ3x¬ïäîÅlð„ÑXS6ÉÄßß?*'d×®]ÉÉÉ"ë\^›²€ïMdYn“†^â,–¸:]¬S¤Ú³~MòBªFR»ÑØh¥¨tyª°\“‰J¢«ºô{Ö± ñBÒq¥¥¥uéÒ!¤R©¼½½ÓÒÒ˜ÛXÈFŠÇÊ.@î^z½žÛÉFcMÙ$777Š¢RRRpç™™™ 6d½m·ŽM YÀ÷f´À,=‹IŠ8‰³Xâêdt°N5’jÏú5É ©IíFccõÀ«•Kž*0ËØøûûKñ`U—~Ï¢41pŸ0äçç÷ðáÃ$''ß¿Ÿõ˜¥ýgÕëäî%\W¼ª6Œ5j4Æ Óétþþþ8ž-[¶”••1Âú65y}otŸ¼fYŒa½ÄY,quÂ/V¨FRíY­&ÅÀ­Fáv‰JQ‰ãnRAþJšKxwËé÷,jAC¦»÷Bk×®ÍÎÎÞ²eËÖ­[sssñ"E÷i¶ÿ¬z]€Ü½ú!©Ú0Öqª±ò©P("""ž?¾víÚýû2áS¯ IDAT÷çççk4ñi±„MM^ßÝ'oYg#ÎÐKœÅW'dl@V©FŠ¢xkÔ.òìÄ×$2k¹n7o¹»Ñq_C¢«Zô{'N´œ ™îÞëÕ«WEEÅŒ3”J¥B¡Xºtiqq1ëî^ËùϸñXßÈÝ‹·’ªÆ:N5n>úé§S§NmÞ¼yÆ ………¬°¦M Éí{£û$˜f1wè¥Ïb$auBÆd­j$Õžuj™¾¼mŽMŒRTʸ‹Ÿe4*$ÙƒU-ú½‡"‹YÐéî=///¥RyïÞ=üsfjjª½½}“&M˜?ƒYÎÆÅú.@î^¼ýTm4ÖqªqóYPP°|ùrŠ¢ ÃÁƒ333YI¶¦M‹ ö,:‹1Ü¡OIIAæÎbé«“ÑEY«IµgšD¦//b¨•2îRf™TMïׯ–ÓïQV±  Àz+äååUPPpìØ1WWWww÷óçÏgffâ;6ÆÃìS®ßQ5¹yïÍc†DRµÑXÓ©ÆÄÇÇÇÍÍ !4eÊ”’’’Õ«WóîE>mjÙ}oHDYh#ÂÐK™ÅW'‘‹€uª‘T{V®IÌøD(›x¥¨Äq7:ËÄ"QSgQýž,h°*€¢¨©S§>~üX£Ñh4šÔÔÔqãÆ™z޼Bt ¨Ú0Ö—MÒlÛ¶­¬¬¬°°°¤¤dÛ¶mööö"O #£MŽG^ß2·Àd™Å¤¡7{#i«“˜EÀjÕHª=+פf_y‘¸Œˆw£³L,”4MÑofÅÇ@Ò³U—MAÖqµmÛVeEÿ™À¾JsrÓÎÚÝú²I…BáéééããS§N3Š–›3ŠJ¸C)GêS ²ÌbÒЛ=‹‘´ÕIÌ"`µj$ÕžíÔ$©rÌ®()ˈī’$̘u²ÀCµÆ‚gu!7›ŠÙ†SÍÖrÂÅN:ÏÈ ©%o$¯ßpËdx §`;@5P €S ° [”`€åY_|ñÅ·ß~;cÆ …B5¯9$៰eA]5BJ‹ckïo½õ·}åÊ•jµ:%%%///""Â××÷™ššZ\\\\\œŸŸÿàÁƒU«V™t ‘æù¥U«V}ûöem,&K4;wŽŒŒT«ÕéééqqqݺuýµoßþêÕ«iiiYYY¡¡¡x{R;`)ÂÂÂ"##ñ‡¥Riô*•““³~ýzÖf?ÿüsiii```Ó¦M{öìyóæÍ””ggg„Z­Þ»wo¯^½ú÷ï¨Ñh¾þúëj¼2Ï×(¿üòËË—/U*³QL–h¢££ºtéÒ®]»»wï^ºt úêÕ«·nÝzûí·}}}“’’>,Üðz2sæÌ   •+W¶jÕŠþØ1räÈàààU«V½óÎ;tãìÙ³·nÝúÅ_tìØqáÂ… …ÂÑÑ100°{÷îx›~ýú-_¾œ^ YØÙÙ¶k×îÓO?ݼyó§Ÿ~Š·\°`Áýû÷SSSøá‡F-Y²dèСôAÇ·aƵk×úùùÑÜ aíÚµsrröìÙƒ?'Qõî»ïêtºÑ£GS¥V«ƒƒƒ•J%EQ …"::úìÙ³ÜÅðˆ#ëÕ«‡rqqùî»ïpo¤üL˜0!88ø×_íÒ¥ EQ¤ä°ÎW Û›7oøõ×_¹B:K¤¬Ò888¤¦¦Î™3Ÿþ† ÔjµJ¥j×®V«ýøã EQË–-+..h§;ÄGôöö^´hÑÖ­[çÌ™£P(øû￯X±‚ùí+oi؇zñâÅŸþ™˜˜˜““ƒ¿4ûòË/KJJBCCcbbrssûôéCQÔ¦M›ÊËËÏ;wõêÕ'Ož<}úT¥RyxxTTTЋïòåËËÊÊð¢Éí¤nݺñññáááçÎ+//ß¶m›B¡ÎÈÈÈÊÊ:qâD‹-²³³×­[‡;üõ×_ O:Q^^>mÚ4¼žr/„={öÔét3gΤ)Šzûí·éO„ÁÁÁø¥&MšdddlÞ¼™uÁàÜ©S§üü|ÌÚµk |||HùY¹reYYYXXصk× ìééÉ›Öù~õÕW¼Ù®¨¨¸téÒÕ«W³³³ Y¬¬,˜££#oV™3?>†††ÆÆÆ*•ÊñãÇëtºþýûã”~øá‡:®cÇŽ¤vúJ†˜””£Óé:”ššúâÅ‹èèhüƒ·´d*[™¨]»vYYY`` ³³sttôâÅ‹›5k–——·fÍ;;;¥Ryûöíÿüç?Íš5+,, ÆG}öì¾jµÚ àuöÛo¿-//W©TžžžÜNœœœ´ZmPPnܹsgff¦J¥R(.\ˆŠŠªU«EQܾ̋}û-Z„· Ë,÷B8tèPN7vìXæjKÿ[­V§¥¥]¿~=&&&''çÎ; 4`¦‚7`•JXPP0|øð‚‚‚Ÿ~úI©TònÙ²eË—/_þöÛo¸1**êØ±cÍš5ãMó|y{ÃÙ¦uèС‚‚օ΀££#oVyG|âĉ¿Ÿøàƒt:ýë#þ¯¯¯/©y!Ôjµ7nÄGŒ/++ëÒ¥‹J¥š5k–N§ëÓ§½½=·´ª÷wY.ªòòòà·ü§NêׯŸ^¯÷÷÷wrròôô B½ñÆ­ZµòõõuppØ¿¿N§3 yyyÂ]÷íÛ—Û ^IŸ>}ZUU¥×ë=zT¿~}„^¯7 ƒ¡ªªÊ`00û™6mZ·nݦNZ·n]•Jåââ"æÄ¦OŸNþ[¼x1Ž!%%åܹsƒÁÍÍíÃ?e¥… 7«\¼½½7lØpäÈ‘ýû÷íÐ(éééøˆ>´··OLLÔét ¡–-[FEEqK‹”€êB…5jÔçŸ>a„å˗߸qcæÌ™®®®ø‡´7ß|!”˜˜¨V«4h@Q”˜S¿~}n'¬}õz½ðG;;»}ûö 2$&&¦¤¤¤~ýúÙÙÙ¤‹‹‹B...E?~üæÍ›uêÔ‰ŽŽ¦?=|øpݺux-Žˆˆ8yò¤¿¿?}I ¬×ë¯\¹âã㉯š¼[â/`³²²poýõB¨iÓ¦æ%ÊÔl3!eÕÝÝ}ß¾}ééé:!TYYÉݬ¢¢‚ÔN:"¾ZãPñfø“=·´žGåààpâÄ ÞäMÎvÛ¶m¹ïÌf×®]&L(((À-)))¡fÍš]»v !Ô¸qãÊÊÊääd|½ç¶›IË–- Ä*­Y³fÑÁl…ƒƒÃš5k-Zd04Á`¨¬¬¼xñbjjêçŸîîîngg÷ÑG5êòåË999K–,©W¯^‹-è¿+//òäÉ Aƒœ;tèàïï?Žðv"p¯Diiiýúõ¹îMQ”“““““S@@@Ÿ>}>A–””ìܹsòäÉ‹-rüÿíw@GûÇw¯ (UD„DTÄŠ¢±+v4–˜Ø@bÄØ°1*øª)%’W‰"XbBDAT¤EA‘v4á¨ÇnÌ›ým¶Ý^á3Ÿ¿`vöÙ™gž™¹Ý¯HôÞ{ïy{{óx¼ÚÚZA(ÚÙÙÙÙÙ 4hÿþýqqqøàÎTàƒzyyegg:tˆÇãÑæ¼uëV^^Þ† ,,,\\\80jÔ(™LFëb}Y¼`ggçâââåå¥ãÛµ£G:tõêÕ …8¡}ûöiii~~~;wvttôööŽ•ÉdLé]‘6´àí iu (ºiÓ¦ŠŠŠÚÚÚ¦¦¦„„AÆŸ••%•JÄbñÊ•+y<Þ‚ JKKÁb“‚‚ðÔqþüù2™¬¢¢âĉ2™ ¤S˜˜˜(ŠM›6a= @¡P€Ì‹-jhhÉd½{÷®¨¨Ë@ÀCN¥R)—Ë£££¯^½šÍ´XA·oß¾ÊÊʆ†pÑï¿ÿØ‹ÅÍÍÍJ¥R¡PÔÖÖ¦¦¦§%µÀ[¶l‘Ëå`ާ§§T*ݱcÇ£õÏäÉ“sss¥RiSSÓ­[·Àb&çëëééÉäm…B!‘HÀ=.ûbZ¯âÔ××cª˜3gŠ¢C† K]@ë÷ìÙüXaJ®xöìÙ¬¬,Ð.nnnJ¥réÒ¥|>Ÿ6´ ¤ÕÁãñŒŒŒú÷ïß­[7ü»:Eù|¾›››»»»P(㊢ _¿~"‘($$¬éFFFƒ 233ãñxøLk¬™Ä/MÌܵkWWWWˆçáóùNNN®®®€Ïçã%$æ!U§C‡C† quuÅ/ ò_Ô‘Î¥äÕÇ]Aë>Ÿ?pà@’'™œƒ×—ÅÛ´²²âóùÔU D0y•˜™^)>Ÿïìì ÊŒû„)öêÄv!z‰6´ ¤•BûÐEQÚÙAãÇã!‹&#ºC­­?Yã~.‹¸$’Ò¹[Ó;\ЧwãÒøÿiŒöå KbUUiÕ Óë^ q/†vô~®¦NcO×Wݵ@/m§©qiÛðx<ø° @ @Ú0-uKçèèˆa˜¦ î!ióìܹ³¤¤D©TJ¥Ò¸¸8.û,k¤Ì§Çs!Ñ3»víjhhؽ{·«««——WJJJAAA÷îÝÙ'*”ùôx.@ ÿ›?–,YòÅ_ 6¬   ºº$N›6míڵÆ «®®ÆwøôóóóóóëÑ£GCCüyó’““ñ5"‘èôéÓ—.]Ú¸qcYYÙ‹/îܹ³råÊ÷ßÿæÍ›:tJ¥%%%‚Œ9rÑ¢E÷ïß_µjØxÅÜÜl°’““³zõêE‹YXX¤§§c&‰Ôž›••µlÙ2SSÓÜÜ\C{@ mõq;@éÓO?%~”}çΠNÇ$[HTæëÓ§\.ñâELLÌýû÷•Jåwß}Çãñ¸œ T ÁhoÅi“è®Gˆ›š7oQÄðûï¿§§§ƒ‰P­2Ø€ ¿Dxxxee¥¥¥%—s‰š@ ‘Ô#äU‰×Õ ÿôÓOÝÝÝ333¹œ ¤… áA//¯?þøcöìÙÉÉÉÑÑÑD=Â:¤§§ÇÆÆªUÈ";w&&š™™566jT&Ü~~~>Õ @ z„çìì±±±–––666÷îÝ+((ºíjÏEdýúõ“&M‚ßB Dô¢GˆÃãñŽ9"‘Här¹B¡HII=z4¾€E­2Ÿ»»»R©Œ­¬¬”J¥b±ø“O>U?¸j@ Ú »!ÉZ§N<<<>øà\ô·É®ÌVnÞ¼¹S§Nýúõ …Ä/1ÔªúÁU£ÑÝõÕžÈr!NÔ=×ZÕ@ îèSPí‰ì‡0 S©TEEE`õ©Öª~‚Ò#äóùðñ&@ †ö3ø’]EiQ³±±±©¯¯[WoèÑ'`a0ôð¿cI(Œ=ÚÖÖö¯¿þRkvgGþ" …]»v­©©!¾té’¹¹yJJŠŽ“Ó’%K‚‚‚.\¸ ©}@-B¡ðüùó®®®ÑÑÑZ\K—r¬ŽšBëv¥I¦£¸©mÛ¶Éår°—ºËI Ýw›ÖoZ؉‹‹S(Z·¾±±qdd¤]MMÍíÛ·1 cê¶:vgLMMMMM´¶`aañþûïS·aJ×È2ŸÏ—ËåZ[øWcggwùòåúúz…BQZZºgÏüáäŸþéïïÏýYå­[·"""¨L¿ýöÛªª*¦•5,”••ýøãxXºÿþ´´4kkkArrrêêêêêêjkk #"" À¾Gm9_¼xlJ$’œœœcÇŽYXX€Cš:Ù`}‚¨Sšd?Š›š9sfeeåG}Dò§»»»D"Y´hQMMÍš5kx<Þ UUUÏŸ?'†%KèîÝ»W[[[GaèС àФ£ÿýï‰vÔÆÃ¥K—RSSñ°OLLÌÈÈÀÿMHHˆ‰‰ñðð U»}*­!Þ´è›[È!´¾‹é¾úê+|$!…(m:—ˆb¡_¿~ñññ2™ìÉ“'\”VI :ôáÇR©T.—§¤¤xxx Léccã¼¼<ð!ÙâÅ‹‰áúàÁf½zõºwï^cccCCø­À½T:ºåÝáêÕ«¹¹¹ãÇ733[³fMcc#X·‰hþÆîþýû·oߦN„ß}÷]uuµayyùÁƒ[ºaú÷ï_WW‡³(‹OŸ>=lØ0¹s禥¥eeeuìØQ—r›Ã‡_³fMUUÕ©S§€£ZçkQ’OØ•&ÙM¡(úÇÄÆÆ’‚dèСJ¥Ò××W©Tnܸ‘Çãá­0jÔ¨ÀÀ@©TºuëV’£XBàêêêáááááqöìÙ¢¢¢>úü+‰@KKË!C†xüÍîÝ»årùܹs‰#‘Úxؽ{·L&£½½}SSSss³››X]WWüÑG‘*ÈÝ>•ÖoZôMŽ­Ïä+âªr„¢8Lé\"Š…ÄÄÄ´´´ôìÙ3##ãÎ;´‹$&Ož°À”X¶lY~~¾P(D$00°¼¼|É’%¾¾¾¾¾¾3f̺wïÞãÇ{÷îíáá‘••uþüyî 8¸»…¥jïb±ø§Ÿ~Žãñx—.]úóÏ?Á¿›6m{µ…ÂÀÀ@WW×õë×;vlÙ²e<oܸq?ýôSPP••0Ešýüü~þùgÿ½{÷'ÂiÓ¦ïÙ³§ÿþ¸[gΜyèСŒ3O¤íl 0={ö\µjÕÏ?ÿŒË3Ñ_¸pá—_~ 2xxxlذüÝ£G   Eùå—gÏžáÅ‹ÅÁÁÁ|> ÜS§NU(^^^ TÓ¦Mûé§ŸŽ92aÂj9ýüüðË!²dÉ’+Vðx¼¢¢"Ü&Ç;uêÔË—/iÌT/ooïcÇŽ}ýõ×Ý»w 4¤OD"ØÇ|Š¢è|PUUuøðaÇ~A’{gÍš%—ˉ[ñ!òÑGI$’ž={‚}P%¶ÇKLL¼qã©{³„.ýðµø2•Ô“ñ<Ý»w/)) ¥^…%ñôô7Š¢Ë—/oll|óæÍ¶mÛx<ÞôéÓ•Jåüùó‡Nª Gû­3ÞJß$ÅØÔ©S;uê„ ˆ™™ÙŽ;¦OŸŽ¢(—Ögòi"$ÅS:{DMŸ>ôˆ˜bllœ““³lÙ2pú¡C‡Äb1í/û„„„ÈÈHêgc‰¼¾••• ÏÙ³gÓÒÒâããÁh²gÏžÆÆF ‹Þ½{“*ÈÅ~«7äŸ}“c}ûö­ªª:pà€D"S—Ö§€4’â ‡))¢ÌÌÌzôèqôèѰ°0[[[ j òÏ;éÈÈÈäädÚ`{ðàÓD&ð÷… €>K:‚ ={ölhh‚ÚGùÏ;'‘H½½=UéÏ燅…­_¿$&''GEEw3M„ …7~òäÉ’’&ãcÇŽU*•S§NEQ4??¿¸¸ø›o¾wà »±±±T*ݱcq" éÖ­›Ýˆ#âãã_¿~mnnngg÷æÍ›Ÿ~ú Ø?qâDii©¥¥%±œ …bíÚµ<oÉ’%ÍÍÍžžž(ŠÅÆÆîرcçÎgΜ©ªªZ¼x1i²gª—©©iiiiXXX»víø|~HHíDØr>aWšd?Ju/‚ ©©©×¯_'Ý”J IDATº ÄV(((xðàARRØÒ:E±„. µáòåË›ššfÏžMû“™6ˆyîÞ½ žhåææ=zt÷îÝàw}DDDJJ þs›XAµö[s¼íÐÆ˜@  ”H$S¦L‘H$ß|ó ÞÜj[ŸÉWĉ6®aJG˜#ê³Ï>«­­-))1/_¾|Þ¼y¤¢µ9sæH¥RüÇ:`„ [¶l xùòezzúÖ­[¨oCûõë•’’R^^>yòdü(Sú?ü˜˜ˆ;?..N&“eddäçç755çÆóçÏ'v@ð/ñE#µ‚¤'óìcÕÚ4Aâããìíí=mÚ´#GެX±â³Ï>ËÍÍ¥®¶*,,J/_¾422JOOW*•iii‚899%$$à9‡ B/ÄÅ›FŒAU:DÄÇÇgРAÞÞÞ&&&ÀÌÌLmÑqÙÂÜÜ\0*Ñ/**5j”J¥277?uêÔ¸qã¶oßîæævùòe úté" +++‰Æ?ÿüs___ Ãêêê233}||ªªª&L˜`jjúÛo¿J9sÆÇÇgðàÁþù'~bRRÒÓ§O§L™räÈ‘iÓ¦eggß½{ÔÝÁÁÁÓÓüQUUõúõkŽõ8p ……Å…  †a/_¾|+>ÑZSÕÕÕà¡þÙŒJ¥Â_¼xqóæM Ã,--,XpáÂ…1cÆ477㸇.;~øaPPÐÙ³g¯^½J{.m<3}ÀÂEÚ ²Ûoýñ 1 ÃvíÚ5yòä3gÎäååâ §¶õÙ}` QöÐ¥¨óçÏ—••]»vM(~úé§*•ª´´””,¸ºº:tèÂ… áááÄP>|8ø©aiiÙÜܼ|ùrAoÞ<Ü †ñÉ›7oBCC½½½ýýýÒdXXXÇŽ;†aûQZ÷ÚØØ¼|ùð>}ú„„„àŠ•$„B¡Ý AƒöïßߨØçêê Nyòä Sè²›%fèÝ»÷¶mÛ.^¼øôéÓ®]»‚ËY[[»¹¹±[ ]E*•>{öÌÎÎ.&&´xLLŒ­­í‹/À˹LöÛJ¼1ÅØÁƒ ½¼¼²³³‰úh[Ÿê+b"S·eïδ…aXaa¡X,~õêU~~>ÈIM9zôèСCW¯^­P(€‘öíÛ«u&ŽX,öððرc‡•••µµõ¼yórss_¿~]RRB›ncc3nܸ°°0âÏ#ggç5kÖØØØØÚÚúøø¤§§—••¥§§§¥¥ùùùuîÜÙÑÑÑÛÛ;66–´©µ:\ܽvï}ôÑÝ»w›šš$‰T*½víþø…ô^_¯uöìÙ¬¬,ðºÛÍÍM©T.]º”ÇãWñB…B!‘HBCCÁb„NéÏç_¹rE©TÊåòèèè«W¯fggSË”––‚îD*L@@€B¡`2òÄÇÇ?|øØ=z´R©\²d Þ3Oœ8¯©C(«øˆŒ=úùóçR©T&“={ölذa´«[çΫT*ñÏ!­âûòË/ X÷Åädb½f̘QTTœyûöm•JÒ æÞ?•&“’’ª««­¯€L^`R\á0¥3EË¥‰Ô×׃û!QAOQ:äóùNNN®®®€h„©Ä¿yÿ”'¤g)0`àÀõõõ Ó’ŒÓúª_¿~}ûö%ª-’NÙ´i“D"!.¾"ee¦^Ž¥^ÀÍÍM$}ûí·øG™ó BPš´³³ãóù'N|üø1þ%(ËQ’©sçÎÅÅÅâ>}ú”v1§àŸàK̉§0….Õ,Ñ!Ä z-¢¦x ]…t p"ÓÀÁÅ>ÒvâcÄ+£‹cëÓúŠ4sSCÀ”ÎQ¡Æ‰¦Ë&—>øàƒ?üx:múµkרŸo‚œ=zôprr¢Zpvvš²ºÔKÓÓßAZ¢þL6ÁãPö].ª‘)EüñÇÔÔT.«UÙí[XXL›6íõë×gΜÑ㯧I“&mܸqêÔ©ŸþyAAAtt´¦ÆõåRߣ6"õ(ÑÔäÉ“ËËËÁÇ6‚ìß¿Ÿ´ ]-´§þUkV÷ óèåܶojcL»Ödz‰°¾¾þìÙ³ º˜BT£îl`˜¼DJç3oÄbA_…„üK_Ñíß¿Ÿû£ZæÌ™SSS“`oo¯¯²!òÉ'ŸdddÔÖÖ–••EDDhôèCkô墩§OŸÀò˜ÙM©=EmÝ3pÌÓçi[ñöäÉ-ZŸ˜m̘1cÇŽíÓ§þ‚6DõºÈ¿ >ŸÞiéx ¤÷'éàËðÏ.ôâ¢)86é‘¶oº·>ú7x Sˆê1t!w¦î¡Q·Ñ‹ˆ.Àv„€!ÑŽÿÿ!ɤ³elllggGýn† Tµh•3™Tµô•Î$ŠÆQ,M 4ƒ æé.–¦5¶¶¶uuu\r2²õ·£.è®6‡´V¥YÝ£NS ïFH°Ã½C1…–¦C÷¿­}ûöUUUeµ@ÃÌßߟªß^esWÕ yõêU]]]AAqÍ“ª–¾ÒL¢hLé$4’@S+˜Ç“ü€èR]ÄÒt$?~|ff¦L&«©©9yò$®pĽ­¼ÕвCÛ/XúÕoLý…=<ØÑ‹ mƒjT5¦ÐNxÏ`!ÁEÆ’;gΜ©­­ÅëνC± ¹Ô¡›caþ½ò„L:[ëÖ­«©©ùòË/;vì8räHðÝkçÎ=>|X,ƒCÜUµfÏž½fÍš˜˜˜¢¢"bÇfRÕÒW:eEcJ'¢©šZÁ}xœø‚_=lذ7oÞÌ;—Çãi¤ª…¢(Ç !vl&U-}¥kM+ŠÆ’Ž£…»`;´òcT—rKÓ]Œ žz£(zêÔ)|3Ž…lýíˆ;ŸEÔ –~AÛ¨~Cú ¢.<-§BÇu«ÆbAká=ƒum¼`L2–ìÞ´oß>33óÁƒ*• L„Ü;Kh1 ÝD ø ---11œƒ?%ÿþûï¯_¿~éÒ%•JUVV6yòd|3bâ.£={ö2dÈ–-[ð­ñ=»qÀíW¯^CFFF½zõrvvÖKzFF~ňˆ‰D2}úôøøxb1˜ÒqFŒ‘@Ýs’)½°°pôèÑÝ»wÏÉÉQ©TsçÎE„ûN}VVV•••Ë–-³´´Œ‹‹‹%º w)S#â™ÍÌÌ,--'Nœhjjš “ɨÛówuéÒÅÞÞþúõëß…XZZ¢(úâÅ ¿¤¤¤sçÎxïâRHMÛÝðíH²@ ]Xúm?¢ú aè/kx úktðu<5%ê8VÅmÕ˜Bå­tmÜÈ¡C‡¤RéæÍ›iû5“÷Û¶m‰D‡}úôâÅ‹Á!Úv§²M´£ZXaV¡£íGû ÂøóI¨Ð1E÷ªÑZÐNx`°`‘±Të½yóæMœ8188xݺuà-ÀÌ™3MLL¢££5êPÔÐbº(OHÇÿ&BªÎVeeeyy¹““ø·cÇŽ‚àÊX®®®FFFÏž=Ãc‹Im‹VU‹ÐNTU-dº§“º“(‹Xš¦hó~ùåüoÒ« Zù1 Ãh]Ê"–†è&HÆ^H‰D²mÛ6ùìÙ³@<AŽ…Ô´Ý ßŽ\`òK¿@èúÂà7Z˜ÂÏ`:¦¨ã^5Z Z ï!† vKµÞ³··òä x5(‰P?~ü›7obbb8v(¦ÐÊËËcºPž†£GVUUMš4ÉÞÞž¨³uôèѲ²²1cƘ˜˜üù矯_¿Æ,øøø477»ººâ·íååå‘‘‘ÖÖÖÖÖÖñññ/^¼»ÕÔÔL›6úhþøñãÄUp(Š>yò$>>ÞÆÆÆÑÑ1==,°ÔW:éꥥ¥¤uɤtZ±´ììì“'ORÏ¢M711)((HLLìÛ·/Š¢#GŽ,..ç¾Îêþýû÷ïßïÒ¥‹­­í£GRRR˜\ÊÔˆ$h_ˆÅânݺA²+W®ÔÖÖâÛ9ªÅÝÝÝÒÒA… Ö××ÿý÷<{![;â´œ¸ÀÔ/ÀQj?âÞ_†ð –AÇFðàÓºA–¨ãX5& ´Uk=!Ñ«W¯ÊÊʰ°0»¿¡~€Èâ=Çÿ›… ‚•¢ ÇÅZ,C7‘– Œ6 “Ζ……Åõë×›ššòòòˆ²&Ë—/onnvtt$Ú᮪ vl&U-}¥ãEјÒiÅÒ4•@cÑzä­ü­K9Š¥Ñ¢£NÛñãÇkjjêëë?ndd„ ˆF…lýíˆ×TÓ‰aV¡Cèú‘Fý…IŽ zQ¡c‰:ŽUc² µðžaBbãÆ´2–ÔÓY¼‡3þ|¥R‰ϽC1…ËЭ–¯Ÿ™œœÌçó9Æ-„ “ÚS:€$£…0‹cZB—®•ˆ“!/¹s禥¥eee=¸Àä:ö&à"Y—’’’––Ö·oßÁƒçääDGGsjuÑ)d)“Ôœáã`°8Ù½{·L&#½½}SSSss³››Š¢"‘¨®®×]"¢úFëaí˜ÚHSsA/BwLf ¦Š´žÁJ_Á&B.q ¡eP;cJGèd´¸ëêK—®U‰“E¼P:uªB¡ðòòâò£Œ]²Ž© n’u ;wî .,,¤Úi B–"ÑJÍ>~ˆE5Lœxzz*•J___E—/_ÞØØøæÍ›mÛ¶ñx¼éÓ§+•ÊùóçS/Ä¢úFëaî‚vL4õ0©T-*tG[`¦àaªHë¬ôœøDÈr „ ¬vÆ”ŽÐÉhq×#Ô—.]ëÑ«#y AúúzEiŸ'Sa—¬cjŽ’u @D ¸ººó´œN!K‘h¥æ ?†°¤»»{hhèÈ‘#_¾|YSSa 2D.—ߺu‹zÕ7Zs´c² ©‡qO@莶ÀLÁÃT‘Ö3XµPpª[ ·É@d´Môõ¢K×ÚÄÉ„B¡J¥rppصkWqq1÷(d—¬£…£dÝŠ+Ž?ž™™Éãñš››½½½ £SÈ“Šžã‡X$ÃÄ †aàYèàÁƒ£¢¢ª««—-[†¢hß¾}³²²ˆ;#k­ú¦‘ y˜Xæ·%tÇ>>UUUÄ ZKÖÑÂQ²ÎËËËÄÄäÊ•+(ŠÎž={Ò¤IÄA°åt Y`QÑ{‹ñc˜8+úÜÝÝ»uëvãÆ ±X¼eË–É“'÷éÓ'::šX ­Uß´PˆdBS¿]¡;–D[‘V8X1¡Ep²‚PÑx"d‘ÑÂ0Œ»¡îºt­Mœ,$$Äßß(Á¼àh'YG GɺaÆ­\¹rùòå¡¡¡†½zõê믿þí·ß @¬Åt Y`QÑ3düR 'ñññk×®]ºtiEEÅÍ›7•Je^^ÞÌ™3»víJîµV}Ã4Tˆd‚»‡‰—~‹BwL=ˆI1±5 V-œð‰¨Fh<2Éh•••íÚµ‹»¡îºt­M¯lEÏÒiµ“¬£…£d££#ŸÏÏÌ̳rNNŽ‘‘‘­­-xÏò´œN!´Rs}úôÙ½{·!ãç­ÄIttt}}ýøñã“““A£$$$Œ7N¥REEE‹¤‹ê›F ‘Lp÷0±ØoE莽Q+¢©xjË V-œ,‡ lPE^hÓ™d´4Ò#Ô‹.S:©ü†Ñ«+â´ûˆ•]²ŽÚÜ%ë%ÉåË—-,,¬¬¬nݺURRB|c„Cû.AGBÚ"! Rs†R9 ¦k˜˜˜¨R©V¯^ Ž.X°@©Tþõ×_LËqÕª¾Q=Ì]!’É‚F¦IÇpÒ´ÊìÊ|ÔŠ´žÁJ_Á‰üsÕ(Ë)5pœ‰d´¸ëêK—®•ˆ“!ºM„L®Ã’š€»dŠ¢ÞÞÞyyyR©T*•æääÌœ9“û4¦£N!m‘f=ÃÇŽ!u 9"•J»ví þíСCuuõéÓ§™Æ}ð£S#s´c² ©‡¹ G¡;j™zSEZÏ`¥—àDþ92Q“Ö‹úO-”³¡€ÈŒ¶YÝA@ Ë/Z×áš@;É:ªevHm¤2w=ÃÇŽ!u ©è eGk» K‘4ò0ôNLfêAìi ƒ•^‚ùçDÈt Äp (JlKþÛÓ#lsâd$×1¡K[ÛoC¦">~Ú\œp„TT-<ÉÑrëAÓ8o=ƒ•ŽÁ™““#“É=zÄçó™NüKâd.À8´Z8çˆ#ÆŽ;pà@E™NüKâd.À8´Z8'ú7,§@ ÐÓ‚Û“_ºtÉÜÜìcBü[mfÒ!SSSSSÓ†††–+ªÞY²dIPPÐ… ˆÕQëîÛÙÙá_5áXXXðù|Ú¯t!BK ÞA>üÃ?¤þ­63P‹Å………D%°·Â!CÀŽþ\2;;;1‚”ÙÈȈö>Z˜DûÙ·o_aaavvvMM¿¿?x TÍ JKK5Šƒ@ 3-¸¾–¸"Kíj.Ú ÁÁÁÆÆÆÃ‡—J¥¿ÿþûÞ½{===¹ï¯¡_vîÜùþûï“vÚd‚¶:^^^ØßÛØ«¥[·n2™, 䯪ª¬[·ÎÏÏ﫯¾:w›[ee%¸¿½¦¦æèÑ£*•ŠšýªÓ¦M›2eJuuõÅ‹SSSióYí_<@¾ FIDATÛ·/--M¥Rݹs‡VäŒdjÊ”)ƒ :|øpuuµ™™ÙªU«RSSÚ íEgÏž=nܸúúúsçÎ=}ú´C‡ëׯ¿qãÆ£G0 9räÈ‘#¿ù曕+WÚÛÛ·k×.00ð矋ŴÖüüüú÷ïÿüùsÚ—ÕëׯÏÈȸyó¦@ غuëï¿ÿ>nܸ޽{ÿõ×_ÁÁÁ¤ ÒÚÚZ,‡††â“¸Ä²eË®]»vâÄ …BqïÞ=Þ³gO¥K—>þðÐÐЭ[·}ZíÒ¥K&LèÑ£GJJJHHȘ1c€˜upp0¾Û’%K P]]ýë¯¿æææÂ !È»H$’Éd/^¼ˆ‰‰¹ÿ¾R©üî»ïÀ8¾wïÞšššk×®ÅÅÅ555¨@þ¬¬¬ììì}ûöñx<Úl‚”——hÅ7=>LMM‰‰¹yófSSÓñãÇIu¿xñâíÛ·W®\4fÌàR‘H$•J7lØàéé¹bÅ e‡ ȬY³”J%¾E ص Èý[9+++***))I©Tž;w.'''22²¢¢"11ÿ·¢¢ââÅ‹éééåååo÷Y4‘H¤P(‚ƒƒ…B!ŸÏ¯¬¬†……­_¿¤'''GEEñù|ÿôéÓíÚµc7m6„a"´··óæÍþýûAþ”””ßÿÏçÓN„8sæÌ‘J¥¤Ï™iM ‚ÀÀ@‰D2eʉDòÍ7ßðù|ÚœNNNÕÕÕûöí‰ —/_îÖ­›B¡À÷ܾ}{SSØ5&:::!!¡]»v´ÖºuëîAâ¹sç$ i"Äë|ˆg>yòdII )s\\œL&ËÈÈÈÏÏojjÚ¸q#ÇëÞ½»R©LOOOKKKMMmjj¿ZÀ^wø[IÒÖwx+>|\lé4`À@ðÅ_(•ÊáÇ566 …ÂŽ;&&&‚‹ê/Ö ¤5ò¿Á7??(ž„‡‡úé§îîî7nÜðññ4h···‰‰‰@ î‘‘‘‘+-°d£2bÄSSS{{û£G"òÞ{ï9;;³‘I ŒÖ†a»víš}z„ IIIõõõæææeeeøix~¡PÆ”Š¹¹9Š¢<¯C‡‚¤§§‹Åb–9ƒIKŒÅ”J¥Šuww/ØhsvìØAÒÒRpõ¿þú A|+dM«`mm¢(—ùŠJ¥¢ÞxÑŠöUVVªTªŒŒ 0Ÿ?~ÕªUîîîT3„NÕ ÌÖ ¨ [»víPõòòZ·nÝìÙ³·mÛöðáÃ%K–¼zõ ¾&„@ ï6äU£=zô@¤¸¸ØÓÓsÖ¬YK—. Ã0,""‚zׂ Çl8yyy†ýöÛo‘‘‘`„e_HIUSkª_¿~~~~111¾¾¾ááá?¦Í9uêT ÃÜÜÜÀôéååell|õêU¥Rill¬i>þøc Ã\\\ØçuîЊöUVV–——;99<`.¯®®.**B8¨š±ãää4~üø½{÷nÙ²ÅÍÍ-22rûöí_|ñ\z @Þmþw#2uêTsss›õë×—””$$$`†¢(ø˜ÝßßøðáL¯‹8fܾ};''gݺuVVVB¡pÑ¢E^^^L+2Ž=:tèÐÕ«W+ \ L­©ƒzyyegg:tˆÇãÑæ¼uëV^^Þ† ,,,\\\80jÔ(™LöêÕ«ñãÇwìØ±OŸ>D™˜††sss+++ZkwïÞ-//°³³sqqñòòÒñíš³³óš5kllllmm}||ÒÓÓÁ­öü1wîÜQ£F™˜˜¬^½º¸¸811¼5ôóóëܹ³£££··wll,Ë!-ÆÆÆû÷ï_¿~=†aR©Ã0¹\o!È»XFY)•JÅbñ'Ÿ|>ƒ»råŠR©”ËåÑÑÑW¯^ÍÎÎÆËlÚ´ ôLÙæU£ãÇÏÊÊ’J¥ b±xåÊ•<v± “žjjË–-r¹ÈßxzzJ¥Ò;vðx<Ú‹Nž<977W*•655ݺuËÚÚAùóçWTTÈd²ŠŠŠ'NÈd2°ŒeÑ¢E 2™¬wïÞžžžTk ,(--U(‰$44Tíb܇ …‚”™I´ÏÂÂâúõëMMM yyy¸Ð»ªéŠgÏžÍÊÊÍäææ¦T*—.]Êçó7mÚTQQQ[[ Œ888è/Ð ¤µ†ÈÍ›7wêÔ©_¿~B¡@ù|¾“““««+Ã?] iïqÉFüèo¹¹¹¹»» …B. ÓócRášBeèß‚a¸YÚ‹‚Ä%0ܦ‘‘Ñ AƒÌÌ̈²g(ŠvíÚÕÕÕ¨ÐZ´²²âóùT10&‡Ð*>¢ ¢}ÀáÎÎÎÀáÄ- ØU͈W$6ÑK<ÏÈȨÿþD‡@ È;ñ^:zrÔ÷ÒBîN‹St7E›“ö\.²aÜ­i SÕXÒõrQÝ@ H[A R©ŠŠŠjkkÂZPޝˆ´x“¤Ç—OÜMÑæäžHJ×èDíàR ½_¾„@ ÿ:ô(] @ @ 6ƒ® "ô¨±@ ˆáÑõ‰¨F{¼kÀ÷‹iÓð…BáöíÛß¼y³páÂÅ‹ÛÚÚ>}útìØ±6lú''ž'P(…BQ]] ÿI"—DëØ´ÿ{ôtfþHÉÑ,Ÿp“Ãô pET©ÊP]B•ºÂÎ,¬ªª*ww÷ÀÀÀãÇck×®=}úteeå?üP__ÿ¸gèį"‘¨Ñhîß¿µX­ÖŒŠF£Ù2Ä·ô…·$“_éo¨¢ÊTÀl&³¸V“þéWayy9ÀÓÓ000°sçÎþþ~«Õº{÷¢G9!'žh4šòòr«ÕеX¬àryS»¡í†u€X>áÍǾ¢«<èJ…JH T*ì@À 9r¤——×?ÿùO¬…N§ @GGÇ;w Ãc˜šO "‘ˆÏç÷÷÷ètúýû÷-‚˘Y2XA[N†¡¾Ò¡ˆ$`1?^]øƒ@$‡ïå„N8á„Ï-ð›wÀˆß­µÚkGÑZUT˜qèñ¨äÄó<ó`ªûÌ@&¬˜-ÿ±0Tr߀ þƒØí4  v–ÙØo6Sã<]MÝgê¬V+J~=TòÆñÒî>#ÀbøÕUuâY‚½…5Ðo1ƒPµ îû] ¡þU«ÕÒÛKqskÿâþ/-þŸzоÏdyøSI'~SÀ{7T¡£•ær“µ¦Š [¹\‚Hde³­B!»µ!tbÂÅÂz}k][ùØrªýýýÝÝÝØ sæÌÉËËÃL à·nZ­Öh4FGGÈDbbb¢‹‹KCCƒÙì¤ÚžaØ!±ÌÆþP急¥©õÇ›j9v¬åäÉæC‡ZOŸî*(à”ÝóÓ-f#ÖÙ²eÝÝÝ;wî”H$€Ëå ‚ÄÄĘ˜ƒA$£¢¢$IddäG}D£Ñ<==ýüüàw§OŸ®Ñh°Y,ÖÆ¥ àÄãýWa@ÉÍ6`i\´œ·û¬ÿÙNQ\]ë—®âþq}à ‹3Lÿ·°¨TªB¡Ðëõ¡¡¡ £««‹ÇãiµZ™LöÎ;ï´´´TVV¾þúë{÷îåp8AAA3fÌèíí½téÒÅ‹q#˜L&NG&“kjjÿÜxŒ°ûÄêèï3™vUö5/\:@&÷`V*¯L[x²¸±ßd2šM諯¯¯¼¼œÁ`"‘ßwEEE‡–H$^^^û÷ï/--5›ÍÕÕÕÞÞÞ'Nœ8xð`DD„íD"ñÂ… Û¶mCÿêijûVa›–B$öÜïºl’ÌX¼¤çÈaó˯^Îk3[,iÓïõY-È«§§çîÝ»eee½½½sçÎíìì<þ¼V«]¿~}IIIMMÍ–-[ärù;wþð‡?ìß¿ùòåF£q×®]‹ÅbµZ±ärybb"—Ëmllüõ®vˆÐÀ´¥ÆŸ÷Í¿$­ -“g3ÒWÞ]¸òlq#¬VÐÝPV›}Æö» c``\nWW€Ãáèõz‹ÅÂb±ôz=F#‰ƒ¹HÀê¿áijû{,³`€`‘xã^e<‡cèï7ÿãƒ>±P Ë®*f-êõztÏ Î%õ|ÀÎÂ2ÿoaéesøž•÷ ãæ•Õ™ÿ¡¯œ<–CÃÞÂêïÅüQëzá‡ì‚´Å8ÔSÇ 'œp 'žÜßþôIëàÄs‚]ÆÁ 'œp‰Ç2ÙŽyû,â¹™Ès¢C§ÓŸ´ ÏÍDž“…åÄÓçÂrâ±À¹°œx,°ãšü¨ —Ë …‡‡GWWWxx¸Á`x|I¨TêÀÀ#‹ï R©ÑÑÑ|>_&“I$’öövµZ­ÓéÔjuOOOPPP¿‡‡‡L&knn~TB1Ñj" %::º³³ÓÕÕU,Óh48:îïïßÕÕ¬V« Cpppggç#¼†‘ÄZ¼xqTTTUU•Õjuqq1›ÍË–-{L²ØlvOOÏðýƒ‹‹ËÎ;wíÚµtéÒ¬¬¬®®.__ßÛ·oÇÆÆÆððp‹UUUuøðá7n<*¹à‘N䥗^ruuíèèhhhèííµZ­"‘H(æåå™Í怀€«W¯ÆÆÆ³Ùì’’’ï¿ÿþ‘ˆ¿Â«ÐÕÕÕ`0ðx¼gˆÍf“ÉäþþþK—.¹¹¹nß¾]QQÁd2¯\¹b±X¨Tª‹‹ËÐ.@OwïÞ5™L¾¾¾555´X,îîî½½ÿñ*ððð8räœÔO?ýd2™ärù#”þ_…\.W¯×ïÛ·O.—›Íæüüü;wî<&YöUH&“=== Coo¯N§Û·o‰D*..&‰çÏŸŸ7oÞ7jjj¾ýö[6›ýhÝóáD …¯¯ï•+Wx<ž··÷Ý»w=*‹kjjÊËËO:•M¥R‰D¢^¯÷õõ-(((--}$¢Ÿ°Ùì'­Â£Ás3§UèÄcsa9ñXà\XN<8–ω3Uªd< èÛÎ?2&éÉ‚ ÏÃC‹éâ¾ê¯OZ‹G€¶‹?€g‰ïdñøŸ´f}WëÙýOZ‹GNðšÜíIká„N8á„N<6P(”!þ9tg'œxžžž<~ž>}:znµcÇÛDÞÿýÇ®œÏðnøä“O”J¥\.?~|{{{YYÙ¢E‹Æg0ÂÂÂ.]º4oÞ¼þþþ%K–ÉdX*ì7ÞÐh4IIIÞÞÞ]]] Oh"N<]x€ÄÊÌÌ<{ölbbâ×_ 3ˆ†‡‡ïܹó¥—^ìØ±ãÖ­[S§NÍËËãr¹ð+‘‘‘ßÿ}ggç‡~ø‡?üá ÌÀ‰§,,«ÕJ"‘¬Vk[[lÑëõ˜/[KK‹@ ¸xñ¢^¯OMM¥R©€ŽŽ‹Åb2™, ‰ô½»œx¶ðÀR0 ±±±¥¥¥¹¹¹|>¿°°Åbåææ …šššüã&LhnnŽÏÊÊrss«««ƒ|||ÆŒsðàÁÊJÇ Û9ñ¼ãýø¿†Ø¡;‚9¹¹ÿ>N00Ð××7qâĪªªööv:n2™ètº»»û† t:“ɬ¬¬”J¥0)ƒÁ`0V«Õb±0 &“I$M¦ÿ«W€v Ñh°È F£P(0òÝjµnݺõöíÛX89`Ö¬YS§NÍÎÎ^¿~=‹ÅJMM½råŠF£yíµ×®\¹B"‘Ö¯__\\ŒKðÅ_DDDääälÙ²Å`0,Z´¨¤¤ûÅËåòÕ«WËÓÚÚ ÉdrllìŽ;ªªª***°¡t:N§{çw®]»†•íxë­·Ôjµ‡‡Vá1!!A£ÑTTTŒ7N ÀªU999èŒ0àF€+Ìl6777¯\¹òĉ …@ X­V:þæ›oººº.\¸ðÒ¥KA"‘Ô×דH$ƒA§ÓF#@àp8t:Ýl6[,L @˜8qâµk×l6Þƒý„ ÅÅÅXÿŽtÊÊÊx<ÇCj111ï¼óNZZ¶Ì"‘hêÔ©S§NÅ*BèõúÛ·o3™L¹\¾~ýúùóç=û+™L~ï½÷ï¿ÿ>@¨­­-//çp8L&sñâÅ*• ðý÷ß;vÓ¦MgÛ¶m›6mJKKCE`x<Þ† ,XššºzõêwÞy'>>~ÅŠ£FÊÎÎniiA¿5zôèÏ?ÿüÂ… “'O&“ÉÉd$iéÒ¥ÿûß­V«ÙlÞµk×âÅ‹q·mûöíŸ}öYKK @àr¹]yD"‘Ãádff¢×Ôd2?¾¡¡«›QPPÐÚÚzùòe\T~MMMaa¡@ @[ÜÝÝß}÷]FS]]é6´iÓfÏž½yófô†‡‡¿ð ...Ë—/äçç÷õõ‘Éd¥R¹råJØá“O>™?þĉÇÿ»ßýî믿‹Å¨,õFJJÊܹsÿøÇ?ŠD¢ôôôÈÈH8ÈÑ£GÑþøH “Éd6›Ñ' 33ó›o¾éëëÃI²ÍóÁf³5ÍÆCCC/^¼¸{÷î & ƒ×ÖÖÆÇÇ—––Z­V¥R™––väÈ‘îîîû÷ïÃ>%%%V«•Ãátww_¿~u #‘HÍÍÍðçÕÙÙ9cÆŒ¢¢¢àà`Ûâ®ðÍb4Y,¬!eµZ‰D"ŸÏÇ6ÍÍÍR©÷Å’’¨›Ùl>|øð½{÷t:ö׺ºº>úhÑ¢E¸Õod2ùÕW_ݳg®]¥RuwwöÙgXKEEň#T*•¯¯oCC¦Ã`ÀFˆ‹‹ûòË/333CCC±¿^¿~>­÷ï߈‰‰ééééèè¸ÿ>6÷³gÏþðÃÁÁÁf³Y$åää æ¨2a„ÖÖÖŠŠ >Ÿÿ·¿ým÷îÝŸ|ò‰m7üÂÊÎÎÎÎÎ>wîÚˆ[g€ÖÖÖ#GŽ9r¤  mïììüé§ŸÚÚÚJJJÂÂÂ’’’òòò¨T*N‡ÏÏo¿ýö½÷ÞƒérÊÊʾýöÛ9sæ à™7@èïï§ÓéwïÞ…ë ::Z$Ÿk<X133333³¯¯¯¦¦F«ÕæææVUU)•JœÂùùùÑÑÑ#GŽŸ¯R©¿¿?yçÎÐùÜ÷|ñÅ"‘H,Ïš5ëÝwßÄÇÇ¿üò˰Ï믿¯£­ë¢OrrrPPÚÃá$$$DEEÁ'↠0OIìRŒ9>ÏBBB’“““““Åb16›ÍvuuŤ`#@A85Pè$)&&F«ÕBCC“““ÃÃÉDâÈ‘#gÍš¯ƒÁ‹Å …êÁãñ¤R)•Juwwï½÷8Îï~÷»ØØXðóîžN§'$$$%%¹¹¹„ˆˆ8e¸‚›ú¡·ö4mÁ‚Žt‰D/¿üò+¯¼WÒCA¡P [tLÌ-V­Vþ¾¾D"y{{?¬ g^^^ ,pÐ}<::zîܹ¯¼ò º¥vìê‘H¤¡O…X,¬ÆK£Ñx<fŽFFFþYt:ã&~ž›êÏìÐ b±¥ k@"‘PóÒjµÎ›7¯§§§»»Ûb±p8ÛŒa˜¡¾téR•JµpáÂŒŒ "‘(‹¡‰Ëd2!Y .ƒM\‹…£6<<<–,Y2wîÜ#GŽ í4M$a#La …B£ÑÐAètúòåË  AÄápL&nû‚ÎÂV' vèl÷7nÜ8kÖ¬÷Þ{ÍfoÙ²ðᇲX¬ØØØ   @÷Úk¯Mž<7ô¶mÛvïÞ ä{÷îõõõ‘H$…B±bÅ @xxøÇüÒK/Mš4i„ sæÌùòË/áö|Μ9¸¡ªªªþ÷ÿîŠ0ÉdN7yòd5·~ýú)S¦Œ9m”Ëå±±±!!!!==}̘1«V­B;àfa«ƒ;tCEE¬[Èdò¾}ûòòò|||àj#]]]ÕÕÕW¯^mjjª¨¨H$¶¯äÒÒRh†"##¡‰[^^Žñ@gÏž=xð`PPÑh”H$˜‰ûÅ_à†¨ªªÂ™Ü,Ë×××ÍÍ g%Ñh´ýû÷Ÿ:u m¬¨¨¨¯¯¿xñ¢ÕjåñxËåè«7 [œx(Ø¡ÚÛÛ¿ûî;´1!!A§ÓUVVÒh4NùÖÖVOOO>ŸO£ÑöìÙ=Ä–ëÔ©Sl6[¡P°Ùl*• ™FÌÄíëë£ÑhÙÙÙpƒ9jÔ(GTïìì> âããáùš@ |>—Ë…ïk'~1†wö›6mÚÁƒ«QQQt:ý›o¾ù5\óù|€Õj½téÒ¯&׉¡0,ÝàÄoxºÁÇLJÅb¡tô& “ÉF£ã3™L‹Å2þ|è©c6›y<f¨³ÙìG˜r݉gxºÁd2ñx<è>7lØ0cÆŒwß}—ÍfoÞ¼ðÁ0™Ìèèh>Ÿ·páÂÔÔTØöìÙ¿òœx ñÀŠˆˆàr¹F£­PB&“¿ùæÝÐÝÝ]SSsíÚµ¦¦¦òòr©TйËýóŸÿü•çàÄSˆÖÍ›7Ï;—““ƒónHLL„t•JõññtCKK‹———@ `0_|ñ)œx€§ŒFcii).nÉ 'vè€ÓÉ 'œp 'œpâ±:§?_ìT‘Éd '\Ü­ãŠÁRÄñ=ü²: T*uÊ”)ÁÁÁ%â—ÍB Ì™3çØ^è•Ä€Þ¬Á0˜žlÞ=<<âââàÿ±F‡óöÛo¿õÖ[8uÙl¶H$‚Y+°°**•*‹á*a±XB¡·óóó±Øh.— £«cbbT*‹Å"“Éd2Y$ÁëK&“qI8¨T*™Læñx …B¡`#0™ÌU«VÁøÇéÓ§‹D"œ«4@ …еA&“¹\®H$‚J 8 &“Éf³aøǃéQ †ªbÓ„I;„B!tðÂ@&“Ç' ëëëa8#T†Áfa÷Jr8ìBAE@{{»J¥‹Å5±Ùlx¡à41ˆD"ÇÃtÀ®$z7Ñ›…B¡°X,8r¯$Úí·™ööv¹\ž——'—˱„A>>>‘‘‘B¡ðæÍ›°‘H$îܹ“@ ´·· …ˆˆˆ%K–œ:ujãÆ cùòå?ýôÓ[o½åêêêêꊣÄ&MštâÄ ÀÈ‘#“““/_¾ ÃDçÏŸíÚµåË—3ŒßýîwçÏŸwqq A=cccµZí§Ÿ~ÚØØH§Ó½¼¼àr¹|áÂ…%%%555o¾ùfccã‹/¾xáÂì‹©©©+W®&—Á`Œ5ŠF£Ý»woܸq¾¾¾Ó¦MËÎÎ^³f :òÛÅíÛ·í^Éýû÷·¶¶Îœ9³¸¸xùòå®®®b±¸¬¬,..îÞ½{]]];vì8}úô‡~ØÚÚŠM300êP[[»zõê™3gFEE9s»jµ»›èÍBoÁ«¯¾J§ÓËÊʤRéºuë:‘žžŽ¦o°C7DFF¢«/""¢¯¯Á` ¹,KYYY```__ŸB¡€ 0ùŽP(<~üxpp0…B:šaaíÚµ{÷îíé鉌Œ$‘H0¶§¦¦wž——7cÆŒüüü”””‚‚l„êêêÆÆÆ+W®X­Ö’’’cÇŽážPÏìì즦&TĹsçŽ=0vìØîîîòòr˜åç‡~øñÇy<žZ­†!¨‡säÈ©T S›?~::zß¾}YYYÁÁÁ˜´³ÝY„„„ؽ’eee‡–Ëå¡¡¡—.]úâ‹/ÆŽ‹ýÕl6WWW'&&[­Vlš˜ð[[[ÛÒÒB&“±+‰ÞÍÁn\ffæ÷ßßßß_YY‰ÅÞáî”¬,´Sww÷Ñ£G322ššš°F&“yõêÕªªªàààqãÆedd@=`2–ššš’’‹ÅrûöíÛ·o£"ø|>ƒÁD"Q$±X,øjزeË¢E‹ØlvEEEQQÑO?ýH$ða†¡££C§Ó}õÕW¦¯ÀF0™L0îºâ^F£‘B¡ÀD¨¬sNNÎÀÀ@fffMM ŽáååÕÛÛ‹eÎÀD˜Ífÿ˜¦þ•Åb}ýõ׃mFKJJFŒ /š$ƒí,Š‹‹í^INØÛÛ[TTž’’rç΃Áb±‰DúöÛo·oß~àÀt4L˜:GÁ×¼’èÝÄnNIlÊ|>ŸN§Ã×ôC{w*•JìŽD"EDDÀ0=.—íããC¥RwîÜI§Ó?úè#€««ktt4îH¥RcbbâââT*•L&c±X2™L(²Ùìèèhè+Áf³an#0"ÞÛÛ —Ë£¢¢0  ©ÀxyóæÅÄÄ`"8ŽX,¦R©0%ApppHH‘HÄCBXX˜N§ƒûLŸÏŽŽ†¹$°ÎB¡0&&ÆÍ _kˆDbXX í,öÄî,ì^É¿þõ¯QQQp‡¤Õjá½pqq‰‹‹ƒåjètúÎ;è41(ŠR©Ôh4nnnt:»’ØÝ„i5àÍBåÂ78üìïï EØÑ£ÁôéÓçÌ™c7UË“Exxøœ9sæÍ›÷°) žZL™2eˆ¿Òh´yóæ :õŒA"‘H$Ì›‚@ ˆD"Ìø‚ ÓéR©T*•â~ˆ°·üY,–mO,½Ç™ÓÁqÀlw†ËfcÛ“ÉdþÅüüü0SÑ–ÝsçεeÆÛ3àF “É0òUB&“aavvè†ÈÈH4\ðq¹\±X ônÀ©û§?ý)00ðƒ>@çΛ’’2jÔ(4÷&Ç3fÌÚµke2ÚY«ÕÿéOBßzë­øøø­[·¢oÆ5kÖ@é¸`y»€F²D"!˜2—ËÅ–¬H$‚ë&|ÈCÍ_zé%xÿÁ† àPd2ÙvEFFΙ3gÍš5¸-0ǃ\“Ʉ܅BáóùðåÙ¸ƒÑjµ‹-‚÷zSÚÛÛ•J¥íK§´´sÜÅf@&“.\èççs`X,‡ÃÁY9ðRP©T†) ~¾Ý0¹¦$ÖA£Ñà-;Þ eeehžÙ™3gŽ?>==Ïçÿë_ÿЉ‰Ù´i“@ X½zõ´iÓpn€ C¡P`ÅÃþ#ƒHd³Ù?þø#šÀ­±±ñöíÛ•••%%%hçëׯ‡††ÂŒ’(ªªªz{{Ñ¥ÙÕÕ•œœ¼`ÁÜâž0aÂÔ©Sq¯ã¨¨¨õë×'$$ .—»qãÆ7ß|3%%e„ “&MÚ´i“D"Á¦I$ß}÷Ý‘#GÊd2–‘‘hhh(--…is¤R)JûAŒ;’Fèƒ-""béÒ¥ÉÉÉT*5222**jÅŠa¡b8 IDATaaüãçÎ;vìX:>þ|øã Q«Õ0@JJÊË/¿ ÷^v( ³ÀF Óé¡¡¡îîîl6í°nݺqãÆáòÛ®ZµJ ,\¸ÐÃÃS°gÏž¨¨(­V‹*‰vHHH@Çy`aEFFr8Ô»!**ê›o¾Frqqñ±cÇx<´»ººp¦MUULï‰6îÛ·/??ÿƒ>p$[@@ÀÀÀšÒÂÅÅeÏž=hu±âââ9sæÈd2\Œ«õgàFÈÊÊ:pàÚ†$õöö^¿~=%%¥§§§¼¼œÍfcÓ´X,¥¥¥ÁÁÁ}}}*• ÍžXPPó¼ÕÕÕáX¡P¨V«…Baoo/šŽ6%%åÛo¿Ý¿¿N§‰Dp§éÒ¥ýë_ ===UUUØì õÊãñ4 FƒÍÐÀÍŽÐÓÓSWWwóæÍ––´•J=xðàÙ³gÑ>œ––æãã“bJÖÖÖž>cbbsss |ãÀTì2™ÌÍÍÍÓÓ£< _<°aI$’X,f³ÙL&6 ©©É××W(¢ìRÙÙÙ ð‡*‰]=TI´ÃC§=#‰¡¡¡P?ø£©5T*F¥¾ýöÛðí—ň#à€J¥Š‰‰f6‘Hܾ};™ÉdÂåˆ@"‘bccccc£££ÑÜÜܰw 6Fswwçr¹¶99mÁårÑBTЄ†Ù(%ÉÖ­[ B```pp0‘HĦI"‘‚‚‚°Í$™Ølö‡~Uš1c†m2;¥Ri›àëëN"‘ÔjuHHˆJ¥ŠŽŽ^ºtiXX‘H”Ëå111ÑÑÑ™óóóÓjµ!$$ÄËË æw„ÐÌM4 ^vøËÄfûDFFòù|ÛiÚÂÃÃÞMLIìÖP%±^ ¿éy>ŸŸ––F$/]º„KYcd2Y¥RUTTÀ5ŠÛJþ2h4.—{÷îÝÿ~¨§ -,6›m±X ƒíÆeÀV{{;ÊÉÂÆ®®.ƒÁðJÐÀliiÁD0 h 쌎@ , zÀf³Ùl6®'Ìæ ÿŠ+ ð˜ùˆ®®.:nµZÍ'OðtC||<…Bé~ x<ÞÛo¿½jÕ*˜ A*•BϘM>rÅb±-¹’˜˜¸jÕ*§õÁøúú~øá‡hã‹/¾8zôè„„tëÀáp’““±Ó~ & Çh¬\¹:@ùˆÕ«WÃWØ[o½5ì…€™«¥R)Žàñxr¹.qlš0Í0|AÂÒ óæÍƒÎ'<oýúõQn¿<À²”•• …ÂøøxÔ€wuu¥Ñh|>ŸÃá¬X±"+++((èüùó¯¾úê7ZZZŒF£H$ ܹsgss3öż¼<™L†>BL&S©TbÕA0p¹Üï¿ÿå#šššîܹ#‹KKKÑž7nÜxûí·mùˆššƒÁ`ËGÀã´ç„ h4š^¯G­¹ÈÈȉ'Þ¼yóĉØ“®£Ñ˜Ý×ׇM󫯾ڵkWllìæÍ›ß}÷ÝsçÎeff¶¶¶†††~ýõ×€ÆÆÆ’’’¨¨¨ëׯK$[câù†º¡¶¶ÝFEEõ÷÷³X¬þþ~6›}üøqø9þü‰'üýýÇŒ£×ëïß¿ïÈﲪªêûï¿Çñß|óMnnîûï¿ï]*pì@&“}öÙg(QTT4wî\‰DbËG„ûÁ••uðàA´³ÑhäóùƒáÆè4‹‹‹?ùˆâââÐÐÐþþ~qïÞ=˜½¾¾þ·¶ª€]º¡¤¤ääÉ“XcOOϱcÇ wƒÉd ‚—³É³³³M&SNNNmm-ó9‹Å01 ,, ZI C©TÂGǃ)h}||ÚÚÚ0>®×"@ ¼ùæ›G•Ëå耜œlUÁjjj(Jcc£-qèС¡ùˆéÓ§Ã …rïÞ=*•ŠN›;‹ÅÊÊʪªª Äñjµò...O2¹þS ˜8ÿ</""û¢J¥‚ÇàÐ&'‰° 22;“_»v-´`a#|2ÅÇÇúg*•*** 2èL&£à°òBtt4¤¡±\]]Q>ŽIEù‡ƒòp)@>B*•B>›&¤N´Z-‰D ÄøxùHðØå#ž{ü¦é†aÁçóSSS‰DbFF†ƒ|„R©¬¬¬ …V«µ½½ýWPÒ '~CÀçnËåmmml6;++ëIéäÄs¼wÃÀÀ€B¡ÚÙÈ '†žn`³Ù0sß“RÈ 'œp 'œpâ9iø.xxxŒ5ª¥¥¥··W$¡Ž CC(ÂÃr¹­¸ !‰t:]cc#Ú(“Éx<žÉd²-Dm ‰DÂd2{{{JŒã “ɸòévA"‘°:Ð\.—ÇãéõzÌKLÝÑÑúßBÅX,–#¾!ðŒßjµÂ¤R)‰DzF]$ð•)üüüÜÜÜh4ælÄápÖ¯_úô鯯ÆQ£FýùÏÞ·oŸ#C …Â'NìÝ»wÔ¨QèµV«7o^rr²ÑhDÃÌ?ýôÓššš×_WN£Ñtww£÷F*•ÂŽŽŽÇElݺµ««K"‘ ‹ƒáí·ßNII9{ö¬F£Y°`AoooUUÕÆëêêúûû±XVÀĉ,X³tuuÁÆäää‘#G P7oÞZV||¼J¥Z¼xñéÓ§_xá777ƒÁÐÒÒ#Až­zv臃s8‡Ãd2M&Svv¶íÕ š:uêÔ©Sq!A¿ÿýïag@Àd2q~5•••|>ŸH$fff¢íF£±±±çÀçóçÏŸ¯ÕjÑPˆ¦¦¦3gΓÉôP"à‰ä7†¹6>ÿüsè¿;kÖ¬ššèÄ`0\]]QO @ff¦Ñh„ù?Ðv±X¬Ñh0?ñ!péÒ%Ìýz̘1f³^±Xü ê?YØ¡êëëQº¡®®®±±ñæÍ›F£æ;p‰‰‰íííF£Q >|xïÞ½³gÏFéÍfó'Ÿ|òÎ;ïà^^0ðhÓ¦Mh#—Ëåp8r¹jÇãñº»»%ÉC‰Ø¼y3ŸÏÇN$!ø|þÔ©Sm˶´´`¹hnÞ¼îææöî»ï^¸paݺuhÏÎÎÎõë×ïÙ³wæ}ýúõÿ÷ÿþêâð÷÷Ÿ:u*̘B,FƒA£Ñ.\¸°dÉ@}}ýùóçÁ3…ü±~Û~÷î][ÏÚÒÒR½^ÊãñD",ÙŠ†¬°„6(zzz²³³qUUU_}õUaa!zÏ`<¸^¯g³Ùîî€Ù`mD ‡bš—/_öóóãr¹===¾¾¾}}}¨“ `°žH$òððÀù¥åçç£Ii ÂÂÂÚÚÚh4‘H,**òðð€? ¥R) sss‡P«««ÝÏÃú>…ÂÐÐPG|­ÀàI lA§ÓCBB ãÀC‰ð÷÷ Ec'‡6e???è¡ s%8­Ïåra’ G8g™L÷! #$$º¸MŸ>ÝöÙæ„¿E<ÝH$ƒÁn d2Ƹ¸¸8ÈÈår>Ÿo4¡à þ€®8ÓÉ®•J“Ù¡6Ýã³Ù쇚@€"¸\.f:"B H$××ׇ¾ô#Md2…Bqœýù5§üýýa"ØÈårׯ_æÌ™ÆÆÆ‰'J¥ÒQ£F »“J¥£GNNN†\€ŸŸ_GGŽ ˜?~rr²Éd*++ÃÚwíÚUUUµlÙ2Ýàî"‘èøñã{÷î1bDtttjjê¥K—°>ƒ‰ðôôtqqY±bÅ‘#G†Á`0f̘1bĈÖÖÖ°°0gA"‘<==·mÛ–““ƒ³mŠ ‰R©tÅŠW¯^Å6‹ƒÍbÛ¶mb±¸ªªŠB¡°Ùì§ŠñÂÓ ýýýUUUh$4‹Åb³Ùt:Ýd28pàÚµk8u»tCSSÓÙ³gI$ä0T •••<H$âÌ~“É„A‚ùóç{xxà¬Â%K–À%>f̘½{÷ÖÕÕÁ¢èC‹ÈÎÎŽ‰‰Á…cØa0¾üò˺º:çø,Ìfó­[·Z[[m­[ "ªªªòòòplÜ`³ P($ 2)b±8<<|XY¿&° !Ý •JQ+¯¾¾¾©©éÖ­[V«•L&¯Y³æïÿ»#Cs8œÎÎN©Tzøða°mÛ¶{÷îaN•f³ùã?6™L¸7 LfK¹b`³Ù0WLuu5Æk'%%uttH¥R˜QŒ£Á[ƒ‰îééAýƒ‰¸¹¹ìÛ·///ÏñYØŸÏOJJêììÄ¥9ÀD&Mš„ !bË–-)))Û·o_»vm}}ý°Æ_G7¤§§_¿~·û±K7¨T*ßÂd2ÝÝÝa–`÷Zèõzôy Q]]ýÕW_¡;âââîîn˜NîòåËiiiæË/¿ZL±cÇWW×êêê¡Ep¹Ü­[·îܹ“ÃḺº:> »°Ëh ":;;“““m >ÚV^^é±g•À¢@áVcدÐéô   h$ …¹Grª Àb~üüüpïh» ‘Háááaaa¡¡¡Ãvf±X°³B¡x¨Y‡'‚ŠØfš ~~~!!!4™6mºp‰çÑ žžž£Fjnn¦P(‰¤··×ºfúïëë£Óé...L&—@A$y{{£ü5ƒÁ ‘Hf³fŽ–q€é{ôz½ã"ÀÏÙál õ˜˜x …µÀø6(Âß…BaµZàgÛ e+‚Á`¸¸¸ðx<‰äqÏCÍf3FS(8b®6› ³Éä‡A  ô°puuåóùz½7£1cÆ üìÐ l6ÛÛÛ;4…aægΜihhHKKãñx'N¼~ýú°ú½ýöÛ£G>{ölJJН¯o{{;zâ¡Õj,X€³¢améòòò±cDzÙlô@Æ.0}úôøøø¶¶¶ÐÐPE¶mÛÖÚÚ u¬ú&¸¸¸ÔÖÖbä“¿¿ÿÂ… y<^hh(.¶——.ÛL||¼L&[²dÉéÓ§W¯^mµZSRRÐm«],K¥RMœ8Q&“¡‰ïíB.—öÙg555UUUéééýýýiii×®]Z‡Ã1bÄ”)Srss‡Î¼1gÎøóhmm}ï½÷ŠŠŠZZZÐuü‡?ü!--M"‘ܺu 7ŽºÅb¡I5aêp …b2™:d6›q$ä`Þ ÿøÇ?àêæóù¸ôT€ÊÊJøË@­èêêj?þX­V£>-`Á‚^^^èÁˆÁ`øê«¯¸\®ã" …J¥âÜ4233ûúúø|>n§ÜÛÛÛÕÕ…ó¶P©T¯½ö–Ü âÒ¥KuuupéK$’S§NáÎaìŠèìì,,,T©Tß}÷]]]ß|ó ül6›½½½qO »"Z[[ jkk1× EŒ3†@ ÀŠ) ÅvÿWYYI ìãÅÓ ,«­­ ¥Úšššrrr¬V+tq0wJkk+¼GŽÁ uìWn6›ÿú׿â¬èÊÊÊ#F †ÀÀÀÝ»wcí0·=Ì‹ŠP«Õ~~~{÷îE¹€¡E6oÞœ’’²mÛ¶µk×b6l P(¸7 “É,,,Äèb˜YŸÏçã¹¹\®Édb0vß›ƒ‰øýïÿùçŸãýýý½¼¼ Ь™½½½ØJb2™uuu¸Å=˜»V…B9wîÜÖ­[W®\¹nݺ¨¨¨Y³fíÝ»ë|ýúõK—.án ÄÃÑ QQQííí¸ã[»t ˜TÎjµân0në0›Í®®®‹/Þµkzojjj¾üòËââb»\—Ë…çÄŽˆDFFVVVâüXŒF£m(úÞ½{¸Æ¼¼¼={ö ===T*•H$vttDGGã–]:N¥RõööŠÅbô=n×ý•J½}û6.Þ`³°‹aEz{{www‹D"­V«V«q'ÇeÙF7xyy¢¹h†L"‚ƒƒ¬\W!.i¸]°X¬ÐÐÐÐÐP…BñP"|||‚‚‚yî2 Çù©T Ód2™L/”H$‚³€ù †<åðùüÀÀ@}4 7¶#=Q #00Öó÷÷‡)Bp⩇——×Ì™3áo·µX@§^ÛÊR±±±¸Gæ j[$È.¸\.– _£Ñà, »"Øl¶F£Ñh4¶:Ûª-|>ßnO»`±XØ4ô¼V‘HT*•*• —UP,ÛÒ¹jµVÂqDŸ_xº! fÀÅLq>ŸÑ &“iÇŽgXÃx0lÚ´É`0Œ7õCŸ4iÒ‚  j$§§§Ã]k×®…0èt:ÜÛÉÕÕÕUUUëׯ///ïëëC÷[vEp8œØØØÉ“'ß¹sõð|ýõ×ÓÒÒ¤R)j9®Y³f```Á‚………hg˜ç“––& ÇŽ›ŸŸ¿nÝ:…Ba±XPKÍ®ˆùóç‹D"©TZZZŠóÑHJJ‘&F&“½ñÆG¥R©Ç‘ £_ xº¡¯¯D"aç$yK£Ñ8vìXôàb0ºÁ.X,VFF®Â7 ƒ­>vìØ×^{ g껺º¾ú꫸ª`¨‘Ì`0<==qû»"Z[[ ëêêp‘V«ÕvÏÞÝÝ KÉa-°\ÅŒ3pÕ~ø!++K"‘øùùݾ}ûðáÃh1ÁÁDôõõ)•Ê7n 6Ê`¤É;wFŒ±cÇðó¡xš`‡n(--õôôÄ._cccssóíÛ·Y,ÖäÉ“O:åà)ØØ±c™Læ?þˆ>98––†3†a•JEÛ‹ŠŠfÍšUTT„s3‚¯<ܦ5’ÿøÇ?Z­Ö÷Þ{ïõ×_ZÄ`¸víš]+šÁ`üíoƒ‰ !Èd2‡Ã5ÜО eÍš5Ÿ|ò‰‹‹‹­ÛÅ`"þý†nß¾}Ë–-˜[ŸÙlþè£Ìf3îP!44´³³²Þ víß'ûtÃ?ü`ÛÕl6ïÙ³ÇÇÇ—y0ºáÌ™3¶µµµ|>—¦Ñh4ÚæL¯©©!‘Hõõõ¸ J~~þž={l'`…ôö&b0 Ö³  Ç èõúŒŒŒ¢¢"­º~ýzø€)((HMMe±X¸·¹]f³¹¹¹·àp¾£"‘øæ›o¾ÿþû¦¢¢B¥R …Âg/Y<ÊÂÙ-¹ùPC9xO¥R•J%ô‘r¤?—Ë…{sµZíïïï`Â:îàø¶ÁgCÀÏÏ/88zÈår§,“É‚‚‚pœ§]‰Äààààà`XbcêÔ©¸ÂŸN8ñ†N§›5k–D"‹ÅZ­çžk°@·m¸0·`g|¸Ã>»`³ÙjµÚ–°ˆ‹‹Ã± G«ÕjµZÛg’­‰vvþÅ^Ðd2+e;´±XìîîŽ}뀱 4M­VÛ–bxñÀ]ŒŒR©¥¤êëë׬YSVVf0†õÄõóó›7o›ÍŽˆˆ@=B—-[–ššŠ3³ÓÓÓ/\¸@ Ö¬YƒîE  Î’Ÿ4iÇ?~¼-a;Õ‡µŸÓÒÒnß¾bWXu"===##cØÙ?þý÷߇ÎÄëÖ­5jn×hWĶmÛJJJ^y啪ªª_|vhoo‡.F£Q&“‰D¢¥K—Â@™LæˆÇóÓ‰L•ÒÒRÈ Ìȇ1ïúíååkSaŒn0 8+¬¼¼Üb±à¶Þ å7Þ=z4º¦Óé3fÌÀ=Æ}úåË—1J«Õ¾üò˸CûØØXL1nÜ8èz;´”uëÖ%''Ÿ={V¡PìÞ½z7`EEÌŸ?¿°°šú˜òvulß¾½®®ŽÏç×ÔÔ â<==;;;qé*ãããazÔœ\¶l™­ó¶mÛ0^|ñEØ¡½½Ó†Å¾úê«pc'—˰xºÉd–••¡„¬§j2™ŒFã¨Q£h4š#tƒT*­ªªÊÊÊJIIñôôÌÈÈ0¨ bee%¬ŒüTWW{zz~ú駸`ŠÁð駟•ÚÑÑa›A$===¡©?´Àãñîܹƒ6ŠÅâùóçûùù¡i±ššš®\¹B§Óq.+ååå&“ 绌ê€u¨¨¨ÀtÈÎÎ>{ö,6~BB°Wà©…º€Æ~455µ¶¶æååY­V"‘xúôéíÛ·Û†ãPPP Óébcc»ººöïß?f̵Zþþ ™m2™ÐFLÑÓÓøé§Ÿbíƒe=hoo‡”Á`°õFBE@SúÚ^¼xq[¶lINNÞ¾}ûêÕ«±Fø£Ñh8rB¡´´´(•JÔ‚n€:àèL‡9sæ`Y!‰ÛyjaŸn, @QQQ`` Ž ·K7X,–û÷ï{zz~ûí·F£±¤¤ÄÃÃ÷fA«…cßR*•‹-Ú½{7úÆ6ã`ÀDOOOµZ{ÙêˆmnnÆ…ËÖ××õÕW¥¥¥(Uæêê cpGLƒÑ ˜vé†ÄÄÄ={öP©Ô´´´£G>Ü„Ÿ-`ûM:îëë‹{oooxHÇd2}}}<ƒƒ1FäÌŽÃá á3­T*ÖÓÓÓÏÏÏlæããã`zËauP(4Ëå¾öÚkŽ ë„¿!8”»ÁÇÇænÉdð°vØHm…B‰DÅV«Õæqpssëéé±X,"‘H$Á+ÖA"‘øúúâ|è<<zôhàÏ) IDATJJ Úû:´ÃM&Ž àr¹¾¾¾MMMh‡ëׯ÷ôôp¹ÜÚÚÚC‡ݽ{ÇâJ$’ øûû£dN§‹Å0.cƌ𑠰«$:Zyy¹Ñh´e¼¼¼¸\.ºª FddäÌ™3q¨uuueee===­­­ÇÇéòù|›{÷TO7 †ÈÈHt{ÞÜÜÜÚÚšŸŸë'NLOOwdhŒ Àï‰Dìý ~À:`_7›ÍùË_lƒªªª¾ýöÛ¿þõ¯‹ëŸ= Åb±P©ÔÕ«WôÑGè·H$ü… d—˽ÿ~nnî¼yó¸\îwß}7sæLH¬ØUÃåË—/\¸`—M Óé(£“j@éhgLI¥R‰éðÉ'Ÿ¤¥¥Á·@èéé˱±±Ñgž§ çÝàææÖÜÜŒË63l/NŸ>]­V—””´µµ9²ºº:///55•Ãá\¸pÍfcÐ/Ú†šŸŸX0k#ÚÛömÚ´)33wRÞÐÐðÕW_•••¡dÁ½{÷RSSƒ‚‚*++ £££…Bagg§]%ÑÑìn1 ‚N§swwG¯FooïÕ«WKJJp¼¦$ª !!r„#GŽìêꂳpuu‰D¸’H$˜¡Žu>>>~~~C¸Gët:??? ˆÅbOOOø@ÒjµðU8˜’CÃÅÅÖNs¤3ª$ªÆìh4L‡)S¦8ó&8áÒ "‘ˆF£Á àqãÆùûûWWWkµZ±XL$qY„m!—ËQ;|„ ÐP‡Âuuud2Y£ÑX­VG‚Ä¡MÞÓÓcµZÕj5‡ÃÁ¸©Tª×ëe2Ü  ±X,‹qªÃ`J .—‹‘ C£Ñèõz¸‹Å,€JBóf®ƒµÐ`<”æ@•Ôh4/ƒu°«‘HäóùÐm÷õõ…Ü#þòL&&•d³Ù!!!8ÎÿvèµZ- ±=B¡X½zuLLL^^žD"yýõ×=ÚÕÕÅçóÃÂÂ<<<†ÍýÎ;ïäææ¾òÊ+5550ˆ@&“µµµÁS}£ÑKÆa§úè´m õÔÔT …2uêÔ’’’èèè„„½^ߨØH$7oÞüã?®[·.??¿··—H$®Y³F$Ù% d2º§D•DCØÕa„ L&sÒ¤IYYYééé T*•Á`,[¶ìÊ•+£F‚JÂ<Ž+V¬(**âr¹Ÿ~ú)tÁX»vmWWWjjj~~>¦¤¿¿¿ŸŸÆËÀ7nÜ Ñh0·9ªÃ˜1c’’’&L˜‘‘->‘H”žž~îܹÚÚZÇápø|~ww7Ü¥ÁY(•J©TÚÕÕüâ‹/VTTtww«Õê˜+ÏÝÝL&÷öö* ¹\n4¤R©\.G:›Í&r¹Üd2Q©T@€.e;tü?ÖЛH$šÍf¥sïÞ=???ÜaÖ„ ¦NŠ3ΉD¢··7—Ëmii)//ïïïÏÏϯ¨¨`±XF£ñÚµkÙÙÙ.\Àù0ŒèèèY³fá\@Ož< Ëà477gff²X,øÈLNN†>t:= €ÇãÁ¼ ÇŽ³%  ƒ)9¬‡ÊÍÍåóù^^^b±žÒÔ××———C²SüâÛÐÐÐÖÖ†¹`…‹/jµZÈh@%“’’ íâåå…uðù|ÛèÁÁÁÐ`G L’k4W®\SÒŽ?>...>>~æÌ™D"Q&“1 ¸·“ÉdÓ¦M¼ôÒKË—/‹ÅŸþ¹B¡Ø°a‘Hܲe‹F£Ac•“’’öíÛ7vìØQ£Fáü]XXn€ÿÇamHXýáþýûmmm0•¥@ 0›Í¸4Ôq‰¡~ýúõàààŒŒŒ×_=''Çl6ÿùÏÞ¼y3\æ/¾øâ?þˆ»FD"‘@ ؆*À»°OCCÜ/;öôéÓ€íÛ·ŸjÔ(·ueeeÌÀLñ–––ŽŽ˜ZþäÉ“ãÇÇùÏ˜ÍæÖÖVhXUTT´··Cc§³³Ó–JŒ°ÀF@{b†ŠaEÔÕÕ555ÕÖÖúùù]»víûï¿Ç@gÑÔÔtùòå!® vaß»å©{zzNœ8áííÝÔÔäã㓘˜ØÞÞ^WW7qâDì@º¯¯/..îêÕ«,ëøñãIIIçÎûe ᜽†€Á`¸qãFYY™]'[Œ;677·¾¾¾¥¥E¥RùúúæååÍŸ?_"‘@Ž: 777‘Hd[›Ó‰ÿ(Ýð—¿üÅÓÓî|U*•R©„/ŸÏ‡>z0-âÐĄùíx¹„‡‚]2™ #÷]]]á¦^*•j42™ìû3”J%:‹É“';èÝàÄ/ǘ1cž´ $I÷3Ìðá„N<<°±ŒŒ„‡Yt:}XoR'œvè@àäø/§z{{kkk‡­ì„N8á„N8áÄ>˜‚Ãáèt:©TÚÝÝËìc ˜}Åjµâ",üýýG =üÕjµmtЉ'úûûººº …Â!òD°X¬Ù³gÓh´öövOOO‹Å2D:ªÇc0CÄn`:øúúÊåòŽŽŽÁ‚0êêê¤R©B¡"Ý!¦t„âóù¨o1 ;z‰„N§÷÷÷?Ô>855U,WWW …Bèçþ°Å ÑiÚí@§ÓÑå÷n JHH@CÝãââÂÃ܉F£™={6îH$’åË—ß¿FìÞ½Ûöüƒ§§çìÙ³KJJ F\\ÜÔ©Sa"»3™9s¦@ ¨¯¯ ãóùï¼óÎ`â:„­[·Ž?~X‹/bî¨ÞÞÞ/¾øâ5ªC¿ÉdZ¾|9ÚÁb±¸¹¹½ð ðŸ¶!Š*•jݺuk×®ÅùA/E&“É4 Œ†‰D¾¾¾ðȤ°°0&&ÐÖÖ&ài/L/Ïåd2™——×`Ñšè4áê‡42›Íöõõ‰D ã7Þ@o+žn Óé úb€õ´Ð¯‰D"˜¯ÁÖÉ:£-f³ÙjµÂT0—.]ÊÎζ«=ÄÀÀ@gg§Á`ø÷¿ÿEÛÞìÎÎΞžž+W®X­V\ˆö`:Lš4iè<”˜°6bxxø`yÂQ¦M›ÖÞÞ>D™tT‡û÷ﻹ¹€’þ82är9{E|ZZÚºuëèiÜÈF˜Äï‘#G† H¥Ò””ù°dɺÑ!›F£!òÝ¡(JJR‰D“ÿ2Ë l6ÆYp=zB¶ªT*òÈ#ð¿t7rSM&SaaaZZ‚ 2™L"‘À•™J¥‚!–ÁõôOp64hœ»¡ó ƒ[¥Åb|Ê”)Á`pôèÑp?ûÒK/©ÕêÒÒRN·xñâñãÇ2äá‡4hÐÒ¥KFã²e˲³³\Œþüç?+•Ê—_~9>>þé§ŸÎÊÊš>}:ùkÖ¬Ñh4f³j4`\c‚³páÂßþö· .´Ûí”!UݵÒdíêèÑ£A\\œP(ôûý;wîŒkÀ,Ôß ( dÌ2”——ßqÇÌ©¬¦NJ¹®©‹ŠŠ¦L™rìØ1½^íñ¥R©X,v¹\(ŠÂeYuuu\\Ü¡C‡ …Ãáhnn&»0…l8™ rîÜ9 B¾Ìž¯P(Z[[kkkéèΜ9CñtŠ µZMlqYFs„xá…ÆŒC×›“oBü.-- ¹Å…a|„¤¤$±XŒ¢(Ô&‡»­Ñh´Z­°¹ Š‹‹ ƒët"Ê P(l6œ "Ê ‹­V+e%•J|ðAB›0sæL ÜÔd–Á`HLLDD¥R%%%Ùív Ã^ýu ÃþøÇ?>ðÀcÆŒ1›ÍP‡n2™Ìf3ôØ#n²`¨Òh46› LÜÃ0«Õ £‘'&&šL&ò #Ôjµ^¯‡D”97ìLÔwÀ3)" ±Xl6›[[[û2´¸÷Þ{u:]uuõŋǎ+:tÛW™LF™q)HJJ2›Íb±X©Tæäääää°Q´ †¸¸8ºŠ5$† ’““ÓG¿“É•¥dA0 {òÉ'¡r¹°°~hH.@§(À*•*Ü Ì˜1cèé¹6®/C¶¤T*5„“÷À%Ý ¡nÈÎÎ5jqÑ`0$''CYá–Òl6ËåòeË–Ý}÷ÝEÑôôt²AÄË/¿\ZZŠaXaa!ÌÆ&Å<Œ%9qâDÊõŒŒ z?^²d ´ ®@-³Éd‚m—œœœžž#OA†@ X¹r%}sZXXÉd0÷'̪’ŸŸOéX” ž{î9¸}6™Lô ÖJ¥2++‹àÅ_¤·IFFTñÀ¦†Ï`0@ \.·Ùlƒ†KþE‹ÁY)dKÆ9sæ¬\¹€ ÈK/½Y2™¬ã…P7H$òÆþ™gžÉÈÈxöÙgu:T;½ð 0óLWW—Ïç5jTqq1]+³jÕª 6À³É¤¤¤œœr¼špö[¶lùðÃ)©úL&ÓìÙ³óóó)k N—““CŽ_3þüuëÖ-X°žu“Ÿ‚|ƒÁÐÖÖ.l ðù|­­­á4¨á À(x===6›mæÌ™™™™”cìåË—Ãt:ä‹.—«»»›®yïêê‚ÌÙ³g'&&.Z´(..Îãñ<õÔS€¬¬¬+VÀôʰ“ÁÔy![²¦¦æí·ß†ÁŽŽŽS§NÁOH¡Pô¯_nuCOOYŠ¢èÞ½{ËËˉðb(ŠB«’«W¯vwwÿðÃz½~øðá”[·¶¶'Þìí#œNgww7åMà ‹ô1¯¦¦fçÎäL;€††¸6ÅÅÅñññ0ƒ0ñDIAž~úiJC2¼^¯Ãáhjj ×±Âp8mmm‡###ãøñã»ví*(( صkLÝK¹á… èÙäjkkaÓeddìÛ·ïÔ©SÐü8tèбcÇìv{BB¡£Ù’@ ³³“x/0§$ ¹¹™¢/è#B¨(Ö 8Ž?üðþté‚ ÷Þ{/\ÓÔÔÔ'$$Æ#Gް œO€“}Dkkëßþö·ŠŠ ‹«’’Šò×`0¸Ýn¸u ?ùÑ^ýuúò(j2@Ñ!C†À}øôéÓ)Ê?½^¿oß>ºÅUvvöÆáozûþûïzè¡üüüsçÎ%''ët:¨‘' !g4½^?~üxúõAƒÁã›ÍFëׯ‡¹Î06œÂaP™LƒT‘ç# X¦¤Í…X,†{`N§Ñh1™L±±±†‘Ÿ‚ E7nÜH?3 ò‘…_¶l}ÿA.e€¿ ¬N¯×›L&¡P˜{V«5&&&11‘r– ÓéÞxã â¿ð–J¥r¹ü­·Þ b6›aS hy!‘H0 p7oÞˆ#(BQ.ÆÄĬ[·®\'NœÈ>ùhÿ€„íöÃS@;ÊEhÈKA^^^ÔÆ!pÁnÏ+—Ëé]Ü`0L:•Ë9bEá AéÕÝŠžÉÕ <~É f¦ˆÏÈÈ€ñ¥0=\.w:&“ ¦9ðûýÏ>û¬H$êèèðz½éééZ­–ùƒÇ/ TuƒD"ñûý „ò~éÒ¥iiiË–-ÓétK—.¬Zµ*hµZ§Ó Oò‹ŠŠX²æñ AuCcccww7q~‰¢è¾}ûèê§ÓY[[ÛÝÝ}êÔ)NG_0òø%#„º¡½½ýÓO?%.â8>mÚ4BÝpÿý÷ÃÝJuuõÝwßm4ÍfóñãÇù‹7¬_¿>!!n4 …Ùl†»h¡Ph±X ¢ÅbùyXjó¸yéă?nP7`VTTMè uQà=ò¨Q£PíîîîêêB„ëÇ#jÜ0bµµµI$’®®.¥RÉÙcš}®^:FŒA¶…š2eJ¸’™™™dŸZ›ÍFqj5ð\0hÐ «Õ.2`ذayyy”S­VË«s7é`vÏ=÷$''“­ŒFãÒ¥Kkkkb’ '&&R+0 “ÉdÐøS£Ñäää@Ÿ“É4dÈEe2YNN´A=þúè¸qã ûåªU«.\È`T4oÞ¼¦¦&JÜ‘@ ðâ‹/N»Sý‚:Ö=÷Ü£P(*++É–]]]n·»ººšl΢´´4--VÏçóÝu×]ÐCfÍš5B¡Ðl6'$$Ìž=Ûn·Ïœ9S«Õ ‚+VP§'Ÿ|ò½÷Þ£H¼yóæ>øàÃ?¬X±âw¿ûC‰‰ÉËË£øR:Γ'OB‹J ÃøSÎÀ z¬#GŽÀÁ†]„p:.—«®®ŽZK |õÕWo*¯×K¸h"òý÷ß×××§§§c&‰ªªª† f·Û¡ý.9È\.'»vAe‹8ˆBo úõªªªœœœƒ¶´´„ ÉÄ£/¸aÄjkkûî»ï¹BãØívèQg6›,“É<ϸqãâããÏž=‹ HGGǵk×222*++áR)===&&f˜îêêbo;;jÔ(†=¤¥¥ÁàXIIIýèLÁƒè†ØlJJ$ø_ ÃL&“Ñh …2™,!!º(•Jè ‹ ŠØØXèÈÈÈxþùç"Ò±páBJ¬@ÈEzllìk¯½íª'L˜ÀÕ¿ˆÇÏ Î?QC&“Ñ» [r¹œÙ™"--Íf³‰Åb­V›——GŽ3FÉOFffæœ9sn ?–º¥R9{ölºu+=Xþ±„ÉdJOO‡NgpÖ°Ùl†-_¾|ôèÑ0»}vvvzz:…¸bÅŠ ÈåòÞÞÞ‡~ú×k4š¡C‡Ž=`6›³³³Q•ËåÐÛpþüù¼¼" DîX¥¥¥V«µ´´T¯×ÃØNË—/÷ù|†555õôôÜsÏ=ùùùtoñ+V¬_¿¾££Ãív»\.LlÍš5ÐëÒh4Μ9311qÖ¬Yp%´|ùrÊr Ã0úKýë_ÿº}ûv¨n `µZgÏž]XXH^ìû|>§ÓY__OqB¤§§§µµ5RßWšIDAT))é±Ç³Z­?þ8ErEáÉår†à€<Â!rÇBQôÀv»¾x@àõz»ººšššz{{Ož<©Õj鎶ô‚œ:uª¾¾>--M¡PH$’ÊÊÊáÇCu¹°Ãáøþûï)wèî îèèèì쬯¯'k+|>_[[[kk+%~ŒéØÖÖ–––vâĉ/¾ø‚â]þÉ'Ÿ<øàƒ‹ÐÒÒÂg1Ž‘;Žã=ö‘aܸqpޏråÊ}÷Ýg2™OŸ>ͰèÑjµDXXÇSRRæÌAœN§ÃáHOO¿rå T7dddÄÆÆÂÂ&“‰P‰Û¶m«ªªbÈõ0iÒ$¨ u86›mèСeeeÅÅųfÍ:p๤Édúúë¯áÉë# ëׯ…й\g.@`0$‰T*MHH`XÃ0X |ï P( ƒX,‹Åƒnõz½Ñh„ºr‘HEø22È!™Ôj5ÝJ¯×Ã'R«Õ±±±"‘hÄuÀþP0@II ºxô3èsÜÏ(Š&\>ÝÐög(7¿thãÁÏ GÏßîø‰¥áñ³AÑðÑFrî(7†G?!§"tý}‡p ãxðPeß½ ~’gýBXËïðûýÁ`Pˆã¸F£¡ç §@"‘Š%â.—«©©©¢¢À†%‹e2¹Ëålll䯒Ë]Nn,€L&óù|õõõìYR©T,‘¸{{kkkÙ³„B¡B¡p¹\ ìYJ¥AQ¯ÇSSS3Э!‹e2™Óéäô¾D"‘\.w¹\D]·ÛÍÉuAA„ÇÒ»A„›Í~ºìâ V‚Ñ" Ä10–N¯‰Ä‰„K(ÎR~á>&ºÂ¯PYYIÎîŽãxèŽ%rssáDV]]MÉRP˜¦ºº:33³¬¬lèСÕÕÕD–©p,ˆÌÌÌØØØÓ§O“ËGd 6 .¢Cö’,­V;yòäžžžk×®Ñ]ñ’““¡;šÏç;uêå¯áXv»EÑÊÊʼ¼¼Ë—/Sªcx®††§Óò½2°222 Ã… èIVñ`ráØØØ†††+7.þˆÂ8Ž“íÅÍfó»ï¾›˜˜xäÈ‘ŒŒŒ³gϦ¦¦Êd²_ýêW{öì!sCO…£Fš1cF^^Þ’%K(Vçá¤4›ÍO<ñÄ Aƒ–,Y¢Óé-ZDNPÃÐ"wÞyçܹs‡ ²råJrBCf`ÆŒ³fÍ¢ç¥a`Éår…B¡R©èÉsX‹%;;ûÉ'Ÿ7nË^(..¾çž{sæÌ¡˜ 2?W~~þ<@¿ÎÀ*,,œ?~rròË/¿LIDÅÜò ,ÈÈÈXµjÅ8¤`±±±[·nMLL ƒ‹eíÚµßÿ½X,ôò¡õX0ÛýÖ­[Ùžƒaøðágüøñ0âˆ#`pÊ„„–{ ìܹóðáÃìË××××ÔÔüøã,eƒ8xðàÉ“'ƒÁàÖ­[9‰wÓPPPpüøñ-[¶tww“Ýì"âÒ¥K›7oîèè »*Ñáv»[ZZü~¿×ë½råŠÑhììììíí ™8WHž) ƒA‘HuóàÆþK¦°ZZZ:;; vìØ1uêÔ²²2ÊÎ?$ \÷¥9vìØ©S§ÚÛÛÙÔE ä·ÂÌ 9õ3³bccgÍšõ÷¿ÿÞX@ž²Áa˜Ósq•ÐëõJ$A ²€}](Š""ü~81º\®Å‹ÿá€K—3f´¶¶x8H‘<´ºáÛo¿;w®Íf é’®-.\¸`±X:4uêÔ‹/²dí߿ѢE<òH0yò$q‘5uêT…BñÐCMš4é•W^aÉ:wîÜÂ… W¯^Ò¿£Ÿkß¾}‹/NMM…hX²pOKK[»v­@ (++cÃêìì,--…îäôUxhéÉ“'«««À† BÊ’µ}ûv˜fgÅŠá²ôÒY/^|ùå—µZmsss¸S£ùÊ+¯¸I*J–¬Ý»wŸ8q¢9ü¹ µmÛ¶÷ß?Ü Ã±ÊÊÊþïÿþÏãñøýþp*Ç7üì³Ï˜]Ìé¬ŠŠŠW^yE£Ñ\»v-\Úu•——ÿë_ÿ‚I~Y²z{{Ù¤`«n€M_UUÕÓÓr¤³ˆ×L tÆÌ8ÎI—™YôZذü~]]'V¸FX}ƒÆ†îké÷6lmmu»Ý ̬(vÄ"°~ýzN£›*yÖ-ÂúòË/£¸KDPÒüÌßM8ð¬[Å<³G=bA.¤Ã³¿¸#žÅ‰Å2ê.x½^¿ßÏòÄÒ’gýXQXÂòŒ“Á¾c’{=ÏúÙ³ðë¦>ì¢(Š¢œ§ÂÕó¬Ÿ1‹Y©®"¶6ïø—.]‚‹¾èXR©Æe‡ÃõÚ<«ï,Eû‡Œ Çãñx"ŒXZ­†_g Ãà)Rt, Ã"²$‰Élilhðù|Ðc." EQK¢µ¥Ùáñxسjµ&&6¦êÊN,7‡%ë„;aŒÐää6[c%%§ (ê÷sp9rLžh¥f‹­N§Tª(aQ#B.—[mö(¼QhŒT*UZzºPÈÍ•’ŽX¡8#Àu]'DÇb@“U³‡×ë­­©AÄh2sL¡À‚Á íFûÅJ•* F.J†aIÉ)\ÛM£ÕÊår™LʉEGÿv)xÏS!׊qR¯âÊ,>ªª+&“Y$sbš9&' ‘åtºd2™ßçãÄêhoïèèÀƒANº\.—«‚R8"«öêÕÎŽh Åž¥P(ÅqOO ½/f WàPóÎ\‚Óíšår:ËÔ´PYt“6¬êªÐþÌÀq°>ëpŸH÷vuá ¿;‘Õ ·Zß"Jò¬èX.— …Õ¿À#.Þo‘^5þüpé*C²bbbJKKCúºD!!ëî»ï¾ï¾û¸² ù‹C²ŠŠŠ`fÚ(êšuêÔwÞy‡’ ˆ™ÅŒp,³Ù¼nݺ‚‚ŸÏ'‰(§Ñùùù‚|ñÅ!¹œ×X¹¹¹ÈËË{øá‡7nÜH)n^›7oÞG}¤T*333 ¥\DÖ”)S´ZíŽ;î¼óNú·ŽuíÚ5èŸ~ñâEúÓ…cMž+))q¹\Û¶mcϲX,.\8uêTH ép¬ÞÞ^§Ó‰ '‡}³Ù|áÂ…²²2"B ©©©¬¬ÌãñPR¬G|Óô‹YYYYb±øí·ßæÄŠXW8<ÿüóK—.}â‰'ÀêÕ«é^ wˆ°Æ¢@­V—””ìÙ³çêÕ«ì•b±8%%eÓ¦MN§óþûïW ÐÔƒ‡Ãn·§¥¥ ö,œÔÊìY---III©©©Dè6öu1ר_â8^VVvâĉٳg÷o]x˜þáv»ßxãåË—·¶¶²g6»B :::öíÛ7nÜ¸ÆÆÆpK%:<Ï™3g¦OŸ.>ÿüsi(WvìØ¢è„ ¾ûî»®0ñ&C>^]]]¸ÕC]8ŽÃÝS¸&£_¯¯¯‡ Íóçχô¾ât7æ¿644TWWoݺ5 4ˆý=›ššè1?XÇñ¯¾úê©§žbH«œÍf¶lÙ‚¢h¸Uj¸»íÙ³gïÞ½! 0°ššš^{í5Àq„|öÙgáþŽ… Hcc£@ !]éC²ˆ¥ë믿ξ.«Õš›› 3ƒ²gíÝ»þX¿~={ààÁƒáþÄòí‡ôÄdÝ‘N8[UÊhÜ/,†Ï ,ƒZ¡P¬Y³†òÊû½.¡PXVV¶ÿ~†Ï¬¿êbÉbIa[Îꆟ+ºººþýïßœº._¾|ùòå›S×O…þ<Ò!.<ë6bõïˆØ,Þ£«’gÝ^¬@šÍüTëžÕGVß1lØ0h¨“Ãã×Xáv.tà8N„‰Ž—Ï §7!ãY}gù|>6‘‰pâÄ øÃëõB+gD¥R18õh¸6:ÖM®ŽgEÍbsÛ#Vt®ûѱnru<«ï,ð~…<|Çâ1 $I||<'šËå‚¶Z­?±Auuuyy9ωD8Ž_¾|™= Rü~ÿOò\œzìÿ]c1G‰¥ƒ8Ÿ …ì' +Ä[%ǰžîî›ÃJNI¹ôãœX8ާ¤*¿xK&“~¯×ˉ¥Vk´­­l5ʾ‡À¾!ŒZ™Á^Õ‹a˜ÙbikkkjjbÏÒÇÄèõ1õuuœÔÊf‹E¡P464rª ‹»»º¸ª°£`¡( 㪳gù|>"^<{–J¥êu÷ÂÈïìYB¡@ÛÞÞAV1S(À#B30ÙW)Ç0±Dâ#9è±aù|>‰TªR)¹=Àÿ4…%ºtj½7&|cÃB'‰È¾.Ç 8–,·»×çõr­«§§GìtƒèÈâ3j4;-ÍÍ\=Áݽ½çÏžáN®®ŽÉ ‹b‰„!ìvHH¥R³ÙréGj"fAXê0 Àò\[#£y¹HGgè”Rìý®Ó”ã¸×ëáÄ ™”“´œXm×­ÈÙ³Ün÷åK?RF6u]¹|w`Ï…QÔEI‡Î’ÕÝý?›Ê¨'´¾šÍ Ü›¾ÕX°+PÒGÑ«Àõ…0'–÷úgö“´F`±,XøË_þÂ\ëíØK¢`͘1C­V¿ùæ›·¬„Ê¢ƒ¡{à qÞçÏŸ¯T*årùÓO?Í©bµZ 3‡i4Š—#ó©T*©T*4 §¬…2™Œ’k/"‹,!%ÞK(ŠD¢˜˜‰D¾.™L&“É´Z­\.gÉR©T"‘È`0 (ªT*)‡¹·H_ŒØ=BO…óæÍS©T¿ÿýïK–,™3gλï¾ËRš5kÖ?~üìÙ³¿ùÍo,X@Od<òˆÙl>sæÌ]wݵbÅ –«Ôôôô—^zÉï÷_¾|9¤%xH¬Zµê‡~8}úôÚµkçÍ›ÎMƒŽìììuëÖV®\Îu‚‚'Ÿ|277EQ™L¶lÙ2J–¬Ø¸q£Ó錯©©Q*•±±±«V­bö ¹É`Ó=Pzgœ;wîÌ™3á׌¢¨V«}ôÑGg̘A.ƒ“@¡9r$??Ĉ!Óã†d}ðÁv»}Ú´iï½÷^HϾ¬‡zèØ±c+W®ìéé‘J¥,YÇ:thnnîÅ‹é½* P^^¾dɱXœŸŸÏ’%jkkŸ}öY Ã`*åˆ,‘Hôé§ŸnÛ¶Íb±,_¾¼½½}èС,%d@_Xä+»¤„˜ ?þøã‰'Êår°ðG}t×®],Eùæ›o’““‹ŠŠ¾þúköÐÓÓÓÖÖ&‰8å>Å0¬«««££cçÎì•òGŽIMM6lØ7ß|þ.€×ëõù|.—K©TrbÁärìU ^¯×årƒAŸÏçv»E¢¾Æìë#È=„e÷±x‡ƒ¼Ûí^½zu0ôz½!püú†ˆr‡ÃQQQ‘ššzôèQÊŸˆÂtÖØ±c1 ûúë¯çÍ›÷ꫯ²d;vlÒ¤I*•jøðáóæÍ#ÿ•ÕÜÜ\YY™’’òꫯ²—‘‘1wî\“ÉtöìY–u‘Û Üø†Xôòä uéõú¹sç¾õÖ[” ‰Ì¬‘#GæääЗá! ³é8ƒºáµ×^ƒKo®žŠ€ªªªÎÎNNúÆÖÖÖ 6´´´ :T*•²<™Ú½{wsssBBÂ?ÿùOúÊ€-[¶èt:N{‹\½^Ÿ““Ã5—D}}=×)2b÷«n€¡ò+L›6íÞ{ïýõ¯ÍþÛ;v þøê«¯Ø³p?räW ”èlX0ÕïéÓ§9± uã5’ELа?}÷Ýw,ë‚Í›73' ¦³®^½.pPtÝïû‘»oß¾ýû÷ÓrÆgcSϊȺpáB¸°[7MBˆþwXe©_àñóF_­—î̳n_{@Vè©’¥Apñ£î—<ëöeá7暃z %ôˆå÷ûÉ;&‘HDϵBÞ¾²ôñ ¾žu{±(@„ð`&‹)ÄÿER©”“×ë…}EQNÇ’ër¹ gÝ^,À¥‡À¾vŽãÁ£/ô»§"€Û,ûÛBŠ¢†ÓÐÕÝÝMÌÙì¹}d) J_ ˆÕíMkù(XBÇ¥R)sh:P…ñI8qûȲÛí œäüùÁívãž›ÙòQ°¢<Ò‰BÛÆ‰%‘Hâââ×®5‘M¦¢SÃü,Á¦)¬6į^­è÷EgÝ¢k,Kb"‚ ‚M¦ŸZ–Û­--ô7·hp[Ç1 ^_¿å*þ‚½Õu¿£ü ‚…Äãñø~˜¦€ŸÉèÜÔÔAÁ`°²òr_êºEG¬+W*u:ÛíöpŒV£ï¸|9¬±{ `Ç‚¢ãƒÁ–––þ•‡KôËüÐÏ‹w«Õš=a„çž{În·s¢O™2eûöíý+'™LÂ4.åTŸ¤Ü °Ùl‡º™5ÆÆÆ†¼~Èe4×®]ëõz?ÿüó… Nœ8±´´433s÷îÝ6›mðàÁß|óMÈu‚Á Ñhììì$Ûq’rÒ¤IGåDé_ÄÄÄtvv †öööÞÞ^™LÖÛÛ s¡(*‘H”JeSS¼€?T*U ðx\ùý~½^/‹¯]»¦P(d2™ÇãéééÕÏç“J¥Ðü EQ—Ëe0|>ô<‹ÂOîV€Ãá9r$à|kÑ¢E›6mhµÚúúzz€a×à¶]]]ðÄŠÎ…ë ­V«×ë)^V ¬˜˜˜o¾ù¦¤¤„î|G°rrrBÆÿøE¡¬¬ êö8½5†–ï#kܸqeeeä<ßÕÿ긟jkkcHM‡^¯ÿÓŸþÄÒ¥“Ç­ƒ={ö„¼~«(H+** G(ŸnÑCh·;øŽÅc@Àw,‚[eÅã¶±['¶‡B£sTî1ƒ8qûÈêííå çgljÀW7³å#²‡Õ`0È)ž} Ó‹¥ÙH]Èü ðtÝ¢(''§aÆ…††ŠD"-÷ÊÌÌ455íÖ­Û•+W8Ž«(Ù'Ÿ|bnnžžž®ö·€:DQ”£££§§gFF†êv¦±UÇOC#Cm˦ˆ4 )Ú²COÓf®lIQÖ£la~ÝdZ :Bssó‘#Gº»»0àÈ‘#EEEÚ-¹\. }||^½zEÓ´™™™±±±BˆeÙ‚‚‚œœ–e»té" e2™>— &YZZzzz–oÌ0Æ ­z1´P4ƒhúŸô]>Ç["“ä¼x¬6R<>ßšߨ ¿‰MqFRaòëwATãK1rtç™6yûæ8®¸0÷Ñ cçÖ”ºµZB†a|||>ÿüóaÆ™˜˜(CÆøáÇr¹üÅ‹z2ŒŒ4GÁ¬¬¬K—.?~üÆEEEÆÆÆÚd @·k׎¢¨˜˜ S c>ÓÌܘF(:=çfb&Â5ÒžiÜókËþõ.~Q|ÇYëR¶ýRœ‘¬:Œ˜ÿ:²a‹öÅ „E™´hŸÿ «hÔªk”eY¡PXXX˜˜˜¨œCQTƒ ²³³óóó+}ƒ(Š*))‹Åü÷ x<_š}:$72ܼSß„U“Ùâ„1抳Nnw[º‡ih¦È-{EÚBŒ±L&{ôèÑóçÏ{õêõùçŸK$’¢"uS}*ئé¾}ûz{{“‰¦cŠ¢x<ÞW_}Õ©S§¼¼¬Œ©ªb• ÿ½ßWuÇ2[þÙøA?ÃÀ–žsÇBlðŸ§w d1GWoV€Ú§‹Póå-b„$yŕʭi£‚¢Òti~9ªBß@ˆ9Ì•ü#R-íÍW~ÿ©‚eW¹÷4QŒ±ÚÁ?„ÙÍÕÿ3¯¼bÅŒà+âÜbuC†HåO šéÙ½ÉqæX̱˜ãð?ÿ&²– QqAÞŸ§ð2äQï¨&c1Ç:Y™ ëÞ"{ù2Â,[.Í¿ÒWïeDUºFÕ¿dnlÐÎÉ¢XÁ1¶¶†ÑO6íž!}Ks«v¨6w°Ê?|ШOŸLInk‡&7ž¿¹¡jYU&˨éí42`–ïØ$-ñí–#céþýF>>¶††ˆ¢E!ÒCJQE!Š*|û¶$6¶Á'Ÿ0±±ÓüüL ˜s“0æÔ­¸j„žã8Ľû·2òhzñÐöÙi¢¦â‚„¸èÕ+ÄVбÉ0H¡Èð!”çΘ …O?HÀ˜SŸ¨nz޾ä0Ç!òÌÍý²[9uŠ"/å8–ãXŒmi8z4‹ñ»-ïÿkèçg{ìKÓäϼ[·2¦ý0²«ë'„±êñߨŒ~»¹ûôÏ/%~!Œ1žÒ¿ukcѸ±¬Xün+B¡â¸¸Â'O¸ü|Õ¡ÒÌÌÂÈÈÒôô¶¤¥=}Úiòh†F1)„8rd"íÉe¸½ €j§ÿdÄ!D½‹MßÖ²«³@òÓ<ަ©¦MßmÅ!Tüæ Bˆ²²B§:¢È±lqRjÜX™a\'š;÷«uëøpàÀo¾ùfÅŠ›6mâ*b¤ÊdO_}õÕâÅ‹Oœ8ñÇTz¢27nìááaee¥åUØÙÙyxxܸq#77—¢(+++ÿ¡C‡Nš4éâÅ‹ @U]GhlÈ›2¨ƒ·­9E!›õë3~ú© <\ïv¡ñ'ŸX­]Ëûvru¶i´îxDQ‰‚ŒBV )ŠÚ±cÇùóçIA›6mÌÍÍSRRt=2Bß@ˆßµù}ª÷%}Çß7Ô8Že eÛŽå8ŽUœºûòâ“„&kÖ2nnœÆ>RÆÉIð.?O=~û«(eÉðB,BE)Ï¢e‹ðúõëÇ?vìØÑ£GE"QïÞ½¿ûî;íÛaÅÅïžžˆ1ŽŽŽF¹¹¹µnÝÚÂÂ"..NõÕ˜˜„PÛ¶mË÷v¶jÕJ§ôz\…¿¿¿¥¥e“&M\\\&MšdaaܧOŸÚ_þª.ŸàXŽ}ßZÁq,‹9Žãðñ;/Â}Öþ!š7·$1½oª¶† -ÿXwíEê±Û¯I»Šcß…UŒGÓ‹uj;vL9ßÒÝÝýÊ•+3gÎܼy³݆‰!dmmݰaC„P~~¾ê«oß¾E5hРüŽº¦×ã*X–U(dááÇ‹ŠŠvïÞ=nܸëׯÃÄQÐU&Ë`cŽã8î}‹¥(îŸíì±Û±aÏSkþà99qʶ#Ó¬™`íÚ°×iGÂ_²¬By4V9Ò"|4-gâwâ8Ž{ýúutt´¥¥¥››EQ …‚Çãñù|-/ÐÒÒ!$‰’““9޳±±Q}ÕÖÖ–¢(‘HT>Hëš^§«P›øáÇ!èýèßõX¦dˆy­[“y1Œ]ŠHúþ»,Ç*ŽÜйñêåÊÕŒ££êìÆÎÎjõš›qGo½`¥˜cÉ^É™bƒV­Þ¥iÚ4U$ÑûÁ¼cÒ,333C‰D"†aÚµkG‰………¥¥e™É2Ý»wWnéÞ½;˲‘‘‘±±±­ZµRvlš˜˜ôîÝ»°°ðúõëdh!¤ìºÌÌÌÔœ¾*W¡¹MzzºNG@èÿ&ÒH»ñTè3ÜQ.-52äèÅÇïBÈÔØ°¸D‘‹h«U«2~ú©45!Ä·µµZ³&—攲&Ùò‚w©1ºú8~ÆàÁÈØ˜6444(üÐMŽeõ¾] ¥kÒ¤ BèÚµk}úôùý÷ß÷ìÙÓ ASSSÕÄ%%%ÁÁÁÛ¶mËÉÉùòË/===ÿþûïØØXŒñæÍ›ƒ‚‚víÚ”——ççççàà°mÛ62“3!!cܵk×1cÆÜ¸q#))Isúª\ѯ_?OOO„ÇsqqùòË/‹ŠŠBBB`â(èAß1BüîÁ¼I™Ò 'ïumåedÀ;v;î˜{¸0MQ ý>åÇD¸GŒ°^¹2# qœÍªUˆ¦KBwumåÙ~È'Ëö\U»—I™ýÍ}Ò²BÔµ}aI™Rr7ný2ùüùó¯¾úꫯ¾º|ùrPP‡‡‡¿¿```IIÉÁƒ%I=”‰###ïÞ½;þ|„ÐÇ,X P(B‡633[°`Áš5kB;vì '""âôéÓƒ œ1cFrr²æôU¹ ²E9k”ã8‰DòðáÃ7Þ¼yn±zÐsža—a?Ê‹ÿ9EQ#üï[«y9ÛŒke•¾ð'IJ..6«×pyoBL#ó7?Le³²Ã8üõ׎‰Ñ ™øý“)( QHåhïSÿòÜ #…4MÓ4­\À º‘ ¶‘?›4iÒªU«äääääd²Ž„:†aBckkkOOO‘HôòåKò’òPíÛ·744ŒŠŠ’J¥ªQa˜Ö­[=xð@y. é5äPóU«¤ät™R@•Þ³FYÕ'Ô«­ƒm›4,e²‡0.LH@ûäMËq>ž KÉ}RŠ‚øx»&æÑÂtåÝDÕ­²J^K4lä8.;;[mËI9Ù2###33½0ªûÝ»w¯üKd÷¨¨(Õ—4§×CÍW¡6€ª¨ê¡æ4õ¾ÚƘ師O8ÌuháÀ½mËr´n«æ«¨ÒiH ëKÐJ€Ÿþë9+çXbŒ)Š"õþ?9–¥þ™îÉqÇ*8„É’y"XŽÃˆÅXM $ÇDNÔ¤*tþ{HPùoå? ‹Š‘¹!¹_bãâÒ–å8Œ0ŸÏ)!Ì0……%˜SSyŒý?LJP fTõéþ‹|Êx´`ììX„Lû÷OÍ–Kdy9¹ù ±Iß¾,MóœùîîÑñoÈýhÞý‡ÕM»õ€®ª8F¨Ò|û§Õön‹ìmÁÕǯz-[Î/,R¼ ·¢8–Åÿ;Ôwã_”òøWŸ'Šåùø_M?êßÿPn‡V!€ê§çò‰¶ýGçW™(Š24`ì“3$Š÷¬ (DÓ´£EfNnaQ©–C€ 7À`!€j§ÿ¡6Q cTXÄÆ§Šð¿7r—ð& €:W•®Qm™Út|ªò&Õ ,j»Xq¹íå·”Ù^Q FT¥k´VuЂPôl~QUÛ‘ fÊ@/Tû3Éu Îð(FÏ5õÀG€‚@´æææFQz>ó€Š@¹5„®ë €ÔV &@¹5!€z !€z !€z !€z !€z !€z !€z !€z !€z !€z !€z !€z !€zW×øàxzzΘ1ãÒ¥Kr¹|äÈ‘E•””…Â]»vÉåò^½z5Š¢¨ââb¡P*•Jë:Ë .µoß~Ò¤I4ýÏoÊ]»v•––Nœ8‘¦iŽãÒÓÓ/^¼øøñcŒ±½½ýâÅ‹cbb‚‚‚~ûí7ÕC%''¯^½šã¸ï¿ÿ¾o߾Ϟ= ’J¥Ê³p'‹/]ºt÷î]Œq­_.¨q¶¶¶S¦LiÞ¼y~~þùóçO:E>èI“&uëÖ¢¨Çoݺµ¸¸¸¢R¡Z̼½½•åS.—?~üøÈ‘#ãeË–©-~666jÏê—Ï?ÿ\*•þú믓&M’Éd±±±‘‘‘R©ôÖ­[&&&'N$Ÿ={&“Én߾ݠAƒºÎòÇÝݽþ<1gÈ!R©411ñá{üæ›oÈÆG¥§§gdd̘1ƒ¦éÖ­[K¥Ò£G2 sôèчÆÇÇçææÆÆÆ>|øpïÞ½ ÃlذA&“=þüáÇ2™ìúõë 4PžåÑ£Giii‰dÊ”)ªÑ·>¨åJ <|ø0;;ûÊ•+1112™lÞ¼y4MoÛ¶M&“EDDDDDÈd²Ã‡3 SQ©P-fªå3>>^.—oß¾¦iµÅÏÚÚZíÙëú]µîóÏ?—Éd¿ýöÛäÉ“årùäÉ“ù|þºuëd2™¯¯¯êÆÍ›7Ëåò=z|ô_N]Õ‡ KiÈ!2™lóæÍ|>Ÿa†a(Š"ƒ‚‚ø|~óæÍ£££333ÝÜܼ¼¼d2Ù±cǘ÷–/_.—˧M›Fv÷ññ‹ÅW¯^533cfýúõ2™lÁ‚C‡Už¥M›6YYYwîÜa¦®¯¾VÕ‡r5räH™L¶iÓ&>Ÿ/âãão߾ݻwœÓ§O0 sæÌ¹\Þ²eKÕ²§Z*Z·n­,fªiLLL®_¿.—Ë=<|Ø»wo??¿»wïnß¾ª¤zîÊ•+§OŸÆgff–/ !m Iii)BˆÇ{÷ÅlРEQ …‚ü™ŸŸŸ™™illìææÖ®]» .Ô“zªþÀ¯_¿~ß¾}þþþÆ [¼x±££#ù!¥«SvMåKEùömÛ¶yóæááá«V­***Òþì3gÎüèë7hVâÀ~~~ÿ÷ÿçâââëëKáëׯ?þË/¿pשS§ºÎ#¨{éééû÷ïß·oßÕ«WË'///Š¢„Ba¥q+!!!äááAþìÚµ+B(99™ìx÷îÝÑ£G“ù\ß~ûíG?`VMœ8ñèÑ£nnn6løôÓOÓÓÓ œœŒruu%i–/_Ù¹sgR´)GmÞ¼¹——×ðáÃ=zTQ9T{öúPÌ EX Ò·ž‘‘AQTãÆ BÞÞÞS¦LéÔ©ÃX IDAT0ñññuGP÷œœœ&OžLê—ëׯ“ŽŽŽS§NmÓ¦¯¯ïÓ§O/^¼Ø¢E ÍÇ9sæÌ¼yó¾ýöÛÌÌ̬¬¬™3g–––’é|è}i”ÉdR©T Ô‡ª¾)--íÓ§©©éÖ­[A“&M/\¸°`Á‚Q£F¥¦¦øûû3 óêÕ+;;;¤]©À+ŠJvjÏ^#×ù@¨•¤¤$ŽãZ¶lùôéS„Ðwß}Çq™—øÑ÷€JõêÕ«gÏžäßÓ§O/((@õèÑ£[·nb±øÔ©S¿þú«²‡S™L6}úôuëÖýüóÏE‰D¢€€€{÷î}ýõתÉD"‘››[§Nîß¿½£“ÐÐPWW×Ñ£Gïܹ!÷óÏ?geeMŸ>}åÊ•+V¬ i:55õ·ß~ËÍÍ-³¯²T(G«åìP¿ÕGEñx<š¦iš&ÿ(¿Q VبU¦¹+‘²¡Š¢(Õ Ã(Ë Ù®:›Fµ˜)Ó0 ãææÖ¶mÛò%¤a†œ¨/´îÕ“rEÓ4Ã0-Z´hÖ¬YƒÞ—ŠfÍš¹¸¸¨nT[*T‹Y™4åÏUæUµg謞TX5ŠTgu‹K½*Wu{¥õç}& k€txÖsu[ê[ñƒž=õBõBõBõBõBõBõBõBõBõBõBõB€jUßžáj”+€ê¿°@hwRH1ð´KPžqŬ¢®s>BPUA1<„€ÿ˜, ^ƒ@ ^ã5lÝ¥®ó>6yÏ#ê: àãÔ°•‚¹£ ºñš¯:R×y›§ƒ]ê: àãäþûA{ÕŽ‚RªfP®@µƒr –¬X±âêÕ«^^^”ÏIÙ²eËÕ«W†©Þ<ÿý÷ßÕ~X«ê¼•»››[§NÌÌÌ´IܲeËöíÛk2uâéé©e$öO¨ÿꫯ""".\HÓî2gΜŽ;>yòc\é)Šª‰pUC‡ð±Ò¶EبQ#¦M›jH“™™)‰´‰‚ÀB«@¸hÑ¢N:Ñ4Ý©S§Í›7ïß¿ÿîÝ» .466Þ±cǼyólmmGŽ9a„6mÚlذ!!!c`dd´qãÆ3fx{{Ëd²Ó§OŸ9sFm¤9rd÷îÝ£££·oßÎqœ»»û”)Sœóòònß¾Âq\ù½Êälwrrš:uª››[NNξ}û®_¿á€þöîÝõöí[¡PxÿþýÁƒSuëÖ­ÔÔÔððp™LÅ0ÌÁƒåry·nÝHçä­[·Þ?‘““3vìXòê7rssy<B¨S§N)))IIIíÚµ£(ª{÷îIII"‘èÆÏŸ?—ËåÇW;ÿ¥|ÂÃÃåryttô‹/"""$IVVÖ!C ¿€þ†ùþûïåry`` ŸÏ'A%<<<77wçÎvvv$J:t(77WI‚Å‹óù|†a  ‹oß¾M+¡……Åýû÷srrüüüÈäÑ£Gsss Àãñ4hpâÄ ¹\>bĈòÁ¬|È–?ÿü“œtÈ!‰DyR  ­&˰,Kz&1Æ,Ë*»9Ž›={vZZ˲jwä8î?þ(--eYöòåË)))eâÙºuëZ¶l¹uëÖÇ“³4lØcœ••ŲlQQÑŠ+~ú駸¸¸ŠNQ&Ç“ž:uêÁƒ^^^>>>Ð(Pž¶³F+RPP 9rlcœŸŸobb¢úê;w†zûöí_ýUÉöìÙS\\|úôéC‡Íš5K.—ïØ±#22²¢q¾òy(..Vž4::!äææ¦ã•¨ª«èÍ›7,Ë򯯬ÈÇûúúž;wÎÃÃcÙ²ewîÜY¹r¥Þí9‰D‚²¶¶†!€òê8úùùíÙ³ÇÕÕuíڵʊã'OžLŸ>½C‡¾¾¾±±±S¦L?~¼†%ŒXZZ"„`]µ´ -¤ßR¿P¤ù°‹/ŽŽŽ1bĘ1c(Š255MHH¸|ù2EQ,ËÞ¿ïÞ½EyyyiyL2ïTÙþëÞ½;˲‘‘‘Õ›smYصk×1cÆ899Uc fÍšõöíÛ¥K—¶jÕ*//ïùóç>>>ÁÁÁC† 3fÌ?ü€ºuëÆø÷ß¿ÿ~ÇŽ5ôs–””Ï™3gìØ±Ç÷ôô¼víZll,´袨={öÈår¹\NšndõYH”_>Q&Axx¸D"![T×R5}út¹\~ýúõ ØÛÛ‡††J$™L&—Ë…BáܹsÉú‡ÐÐP¹\Þ«W/ §¸råʲeËÒÓÓIn¯^½Z½‘ÀÇD‡ù# ônÝÚÈÈèÁƒÇ1 CQ”B¡PM@ú3IÛ«¢dK™Wiš¦iš,Ï ¯š™™µnÝ:???**Šã82ûT›S „0ÆÖÖÖžžž"‘èåË—ª ýÕò-­«x:¸7€Ji' ?ûŒ÷ß(Faa &ðoZÝt›GQA ÊÓ*¼}Qšƒ*7äðÑ+ìþµŽ¢ €^™`WÇ·XêÖ¿&Ë4jÔÈÇǧ®²ÔsssÕ?ÿÕ<„®QõÜt¨mÛ¶ …"‘èÁƒÆ ««ÚÙÚÚnÚ´)::Z$eee½zõêøñã €ìðŸ5ŒÞ>Üœ}|(Šb!„1æ8®ïtGÓ4EQ¤\’lÔm~U5 jÔž={RRR$‰T*?~xð`>Ÿß¼yó‰'¾|ù2--í“O>ÑõËðã?Êåò‰'êúΛ7O.—Ož<ÙØØ¸M›6YYY÷ïß711)“’¢(Wç?”jZÛ¶mcccÃÂÂN;º»»¿xñ"&&fðàÁM›63fLbb¢jÍ[imò@QTëÖ­cbbnݺ¥k‰ùóçËåòõë×Ó4}òäÉÜÜÜÏ?ÿ\YÞžÇÓþKÍ+gíÚµr¹|„ Zà*~7#""ÂÂÂÔføÅ‹‡"/iþ,ªj]é}™ÚP~yµ)É<-:iÒ$Š¢vìØ¡Ü2uêTŽãBÛ¶m›U‹Ù…ã8…B¡ÓסLAíÔ©Ówß}wûöí={öèôvéýÝLKKóððPû’……EFF9‚6ŸEÕA óP~yµ)„ÚÆaŽãÊ|-iš&Y–Õ&žŸ>}úܹsööö¡¡¡‰‰‰¤ÙÞ³gÏ:Y\B¦ÇÆÆbŒ---•ypssÛ³gO|||vvvllìüajjªå1½¼¼D"ÑîÝ»Ëü¹sçÎË—/4h 6)))!+++e‚ƒƒ“““I‡Õ‚ ʼ·¡¡¡>;vì½{÷233“““ÿþûï2ocçÎOž<) •ÝnR©T(òxZýîÑæ/^¼ÈÎÎ&S...$Abb↠H¶ƒ‚‚rrrÈŸG޹uë–òý™6mšOPPÐË—/u­&z÷îpùòeRÊ1Æ»wï.,,üèÑ#†a5j$‹çÏŸOöjÑ¢…D"9räˆÌß|ó\.ß²eK™7çâÅ‹¹¹¹VVV•& jŸŠ¢=zW½ÃáOž<ÉÍÍUþª“Éd—.]j×®ö¥ÚÐÐðÚµkr¹üáÇ ,hÚ´©Þ™Y¶l™\.>|¸Þ4ŽŽŽqqq="Õ“ö*ýnj6bĹ\>bÄŠ¢îܹ“””tôèQ†aÆŒ#—Ë•¿ÃjÔ0º¾c]¦æ†¤ùæ›o$ɪU«ÈˆorrrÛ¶mõþ õÿ©k×(Bˆ¢¨Œ±NíÒó^ž®½@{÷î‰Dááá3fÌ:t(é:@õèÑ#))éîÝ»ä&Ç…††"„|}}µ|8™™©ÚùÖ·oßgÏž=zôHõ‡ÉúõëE"ÑÝ»wüñǹsçþøãº6‰ÎŸ?ϲ,yÉïMGGGrR333„Pii©ê ô(NÑ¿ÿâââ“'O*»ã?~Œ"3Ÿ?ngggnnÞ³gO†aΜ9ãìì,|||x<ÞãÇIƼ½½y<^™F›–ŒŒŒP¹¡)å33³J Ñ>äM°¶¶¶±±Ñ5·š¥¤¤ØØØÿ ;v¬oß¾Z~dÅÅÅC† 477_²dÉãÇ·oßîääT½™ÔÒÒ¥K---—.]ª_KKÃwS³/^`Œííí=<<Ξ=Û¡CŠ¢ìì슊ŠÈ«zäG?PÃT憤9yòä¾}ûÆ·lÙ²O?ýô÷߉‰Ñûƒ®Õ¼¼ôôôÚ]&Z/X°ÀÚÚ:88ØÈÈÈØØX/>>^¹)âÊiÐdÚá÷ßß¹sg[[Û¥K— ‚+W®èz §°³³322JKKS6eN:Å0 i<}ú”a˜Ž;vîÜ999ùæÍ›EuïÞ½uëÖ………ÊY¤í’––¦ëµ#„ 0Æå$x<Æ833³ÒzäA$!„ÜÜܪ½yA~Òeee]¸paÒ¤IÆÆÆ‹/Ö¾Q˜››»téR//¯éÓ§?{ölĈ§OŸV¶zkÍ—_~ùõ×_ŸÒüÝÔc,‰A·nÝbbbbcc?ûì3+++25¦6A Suške2++«&Mšp׬Y³*ŽYè6Ég„ Ê«å8ެ©@ï2Ô¨Š†.ªqŽ\ff¦ê(4BÈÊÊÊÌÌL§VKttôýû÷ûõëgfföé§ŸÞ¼y³¢…™™™ûöí›5kÖÌ™3W®\Yň ™|þùçqqqÊN˜ê:8B(##£yóææææ™™™å_-))INNvrrrssÛ·oÆøÕ«W-Z´hذáëׯ•õÙ×ÖÖV w".‹CCC›4iRÓßMLL"##Û¶m)•Jsrr„BáÎ;Ëß]ìüùó"‘hóæÍºžzÛ¶m·oßþá‡æÎëîîîèèøý÷ßÿý÷ß;v$ñÅ‹:uÊÏÏ¿ÿ>ÆøÑ£Gvvv666Ož¬J蔇®]»º»»ß¼ySí§9zôh‰DrïÞ½ªôϘššöíÛwëÖ­<ïÏ?ÿ,Sä*:ņ ,XУG¦M›ºººŽ?~É’%ÉÉÉ;wîÔòÚ«è+V¬`æ—_~©tö|Íå!55ÕÍͼ„1¾páEQÍš5Óã‡Kµ|šjA £¥Jk˜®]»Îœ9óÆ»wïfYö×_MKK[½zµÞsÙ þ#33søðáQQQOž< 8s挟Ÿ_ii)I0~üøøøø´´4²ló?þHMM …3fÌPý¤É€¶©©é… *-ß›6mÊÈÈ9r$:th\\\ZZÚ_ýEÓôÏ?ÿüæÍ¡PøË/¿hY˜vìØñå—_Nœ8ÑÉÉI xzz.\¸Ð××÷·ß~+s²"E¯Gqqñ¨Q£vïÞíïïçÎ{÷îÍ›7ïÍ›7Ê_ß‘‘‘¦¦¦¯_¿&—ûömÒyp÷î]å—c|âÄ 333ýn¹ûêÕ«‘#G¾zõjóæÍ¯^½ ÊËË5j”òê4Ny?~É›R‡ iš¬ŒÑ†¬n$+†)óÒ4­v9cùOzÍš5‰ÄÓÓ³ÌéHÔ’R5jOQþmT½g MNNΖ-[TKEQª·tQ=”ÚµN¡öÝ(ó^‘ôª§#ÉÊœˆ¦é›7o&%%é×Aªú^:tH.—ÿôÓOe²¡9–y0`€X,Þ¹sgEß±°°°””=†åÊÖ Ã¨ÍFE§(S&É¡ÓT¥ù ¢öªw+--Ú_E¥ßMÍG(_äT¿V:ÑûÓ„FËFËËÔPÔÿpËbÀ€µ³Š”Õ Aƒ˜˜˜ãÇ—¯úkš@ H$›6mR-4VVV)))çÎû+uéÒE(^¾|Y×GO”áààðèÑ#©TZQ?Œ†šóàîîùàÁƒŠæÔ4iÒD$­[·®æfiVýp„çU5Œ–È—÷CËÕGÎÞÞ¾K—.ŽŽŽÁÁÁÝ»w¯“_"gÏžMHHðóó³¶¶&÷Û ‹ÅU¹cHÍ¡(ª[·n¯_¿>{ö,Y¨«7— .¬Y³¦¢*¬¢òàêêúðáÃ{÷¸h8µÚŸ½Õ«ê§€#|8§ÐÔ0:Q~y!Ö*ooo¡P˜••õèÑ£o¿ý¶®¾KöööýõWLLLVVVvvöëׯO:5hРó»Þ÷ÕTKa-ßפe‚ŠòPy Š †Ñ‰N_Þ(€ÿ×)ïžJVÕÔá¤m2J¤ºZ¼nó¨:¨a€êƒ5bàÀ—.]***R.lðaú°†7µ±fÍšš{ÀØÊ•+%IHHMÓ×®]ËÉÉ!7·%¯Î™3G"‘ÅÂ"‘èÙ³g[¶lQûÈ4Š¢ •÷kÿÐh¾Ìÿ–-€ú@Ûe(¤ÒDMœ8QysQµk”““Óøñãoܸ]ÇÏÉÉáñx2™ !”››ËãñÈÃw²XuÁ‚ûöísss8pàܹsÛ·oß§OŸüü|Õã\¸pÁÉÉ©o^½4_æHM—@} m $šØ±c‡rKHHÈÔ©SIE¿mÛ6-ŸÄTE¾¾¾5wüììl„¹›»T*E•¿y1yäMtttLL YFãëë[æžXãJï»X‡´¹Lm´k×î믿 $©}5]õ¶]£ä^‘ÿÚS—'Ôïß¿?""bÒ¤IYYYIII¡¡¡ª·ê %Íå–Aƒ‰Åbåð‚‚‚bbbV­ZEÓôÁƒ•w5lܸ±rww÷Ý»w¿zõ*+++11ñîÝ»:=à!$‰0Æäf‰¤´´´¢{’Ìä¹wVVVÊ®¹àààäädr÷È ”9{hhèÇÇŽ{ïÞ½ÌÌÌäää¿ÿþ»gÏžª={;w>yò¤P(T½s£P(,s‰Í›7gffΜ9SåŽüL› IDAT;Ú_¦f­Zµš5k–~ áOŸ>}îÜ9{{ûÐÐÐÄÄDÒÕ\æ­Ð@›òàææ¶gÏžøøøìììØØØ?þøC×|kY¢V¯^‘‘¡ka| jé{Ë0LóæÍçÎèãã³råʾ}ûîØ±C¹Ú±Òû[NŸ>½mÛ¶AAAä¡”VVVäªm‘:Ìž=ÛÛÛ{úôéñññärÚ»|ù²¥¥%¹üÂ… ­­­ 5¤wvvFEEE)£È´iÓ\]]gÏžMÓ´ÚÛxº¹¹-_¾üСCݺu›„ •þœ'c~Ê?•7Í«(½e×®]ëҥˌ3ž?>|øðK—.Mš4©Ú;¬ÈÏÿ7J$’iÓ¦5lØP×#H$’Š^JMM6mš³³óùóçŸ>}:xðà5kÖlÚ´éƒjm°,«P(”m 2j¯¦/ª|ÐÒ5ŒÕN‰Ô-ݾÒeé7nœêS¿5pwwWÖDvvvèýôE„9Bƒ ”‰-,,ÊW[šF¤ójß¾}ƒ4h™·YC?á333÷íÛçèè¨ß¼M FŒ!—Ë{ôèaooß¡C‡Õ«WÈ+1ê–†ò™™Ù¤IÕ-VVVfffiii:¿ÖJ ®èVƒ—ù ¯\>¡åî}úôQV"½{÷¦(*<<œÔeéééãvíÚ)téÒ¥|CÀin„‘ÊëþýûQQQj£iuÙ´iSVVÖøñã­­­«ñ°ÎÎÎÙÙÙ¥¥¥54ÌY]¢££×¯_Oæ× åáÆŽŽŽÝºuSŠ¢ôèg®µ¨µ×Ƀ1ž1c†¿¿¿ƒƒÃ¸qãFŽyÿþý .ZéäÉ“ÅÅÅK–,iÛ¶­»»û¢E‹¾øâ‹ò5ÎÍ›7 ÇŒãââÒ¢E‹~øAÙûúë¯Ïœ93f̘fÍš‘åÝ»w¿}ûvÍ®‰ÅâÐÐÐ&Mš”Ÿª7“ÈÈȶmÛFFFJ¥Òœœ¡P¸sçNKKË2)«²Ž°º<{öìÿûŸ\.¯¹Sœ?^$UôÜy åaíÚµ ƒ rpp;vì¬Y³îÝ»GhsjíKÔ¡C‡rrrFŒ1P¡C‡¥§§Ï;÷Ñ£Gb±855õàÁƒªÓ(Šò÷÷ˆˆÈÈÈÈÈÈ zôH$edd<|øP9”èååuþüy¡P(‘H233£¢¢6nÜX½m5åò e–5jôòåËÌÌÌ–-[R5tèи¸¸´´4©Túöí[™L–žž. •·¨t•ÈÁƒ† fnnÎãñlll† –‘‘ñ矖‰[¶l‹ÅdÁb5^c­9wîÜ›7oÊ,-ïÒ¥K‰dË–-=P·¢ò€ruuݳgOBB‚X,~ùòå¦M›,,,´Ï¡ö%*:::))ÉÈÈHûƒêC‡I¥R²p^íêc²NKùj™õ%+³]õ¥jj—‹‘3’¦€jÞT)wÑ|ß›œœœ-[¶”¹®ˆˆˆ[·n•yÇþëk×Ê¿’i¸ÌŠÊCù—t}¯´,Q...Ê•$:ðÐö^£UGQTùû´©*¿’Lí$‘ŠœUûB´òÔÞD[õ¤•æ¡ü«ªw%%‹ ɺ:e@дiÓ¨¨(m2ó¢å‡Ui2 ïy‹„–»÷èÑC¡P}PK\œC‡Éd2mZõÜÙ³güüü¬­­É½ÃÂÂÄbñðáÃaü©ºtíÚ•Ü ¶"ÉÉÉÚ—UÒ4‡OP „Z²··ÿ믿bbb²²²²³³_¿~}êÔ©AƒA·[5"ÝÑšÕuµ§–~Æ’1?X§ roLÒÂP½ÑZ]ç |$þ{]³fMVVyº:PE:ÌŽ !s• ,¿¥¦999?þÆÑÑѵp:à>ŸOn´Bþ_fK-dã‡~¨è‰ä€´]6iÒ$ò0–eI+¦iåÓ'*]å¶ÿþˆˆˆI“&EDDdee%%%…††ÚÚÚ*„††æä䨮ß4hX,VÞ¥3(((&&fÕªU4M}zÛ¶mƒ‚‚8Ž=z4yBº@ J¥Ê]BBB:tè0{ölooïéÓ§ÇÇÇ 5×LÓjov  Òù¤!¨Ç™†ùóÏ?>̲ìŽ;Z¶l9nÜ8__ßóçÏk³ZœœTõ‘èeö­[·>|øðßÿͲlFFÆåË—1Æås°hÑ¢ÿú½:T Ýúõk*………)ãYXXB¨W¯^Õ5Ú—žžîëë;mÚ4SSSrÇdµ¡Žã8…BQÒ)†„„L:µ´´T¿3aŒ…B¡²—’’‚²±±©Æi/³gÏÎÎÎ^±bųgÏ‚ƒƒ½½½aN Í´í%sD·oßN"Ùĉ'L˜°}ûv2†§M3‘Œù)ã(¢ÓÐ)ªÇÞµk׺téâçç7bĈáÇ<ø×_ݱc4þTDÛ@8iÒ$ÕÖ {ÊZv–º»»GGG“àggg‡‰DäO 4h——G[XX”oÏiM$Ý¡ûöí;pà@çÎwîܹ`Á‚-¯@=¤Ã¬QVE™Z¤OŸ>ÊØÖ»woŠ¢ÂÃÃIlKOOÇ·k×N™ K—.åavv6B¨aÆÎBÂáýû÷£¢¢ÔFS ¶:tH.—'$$|÷ÝwãÆKOO¿|ù²rÉD§N²²²._¾ìíííîî¾hÑ¢´´´·oßþöÛoª«ý¼½½333Ïž=ëêêÚ¢E‹~øAùê×_}æÌ™1cþŸ½3kâêÿLqÃ* DE6A´Q¬­m-b±ê§ˆ * ˆèÛŠ-u_~EJµ@] *¡ZµŠ(jE5lʾ[$û6hµ>Bæ÷Ç}ŸùÌ›@2I `{¿ÁdæÎ¹gÎÝï=gý¸qãÆŒØÖÖvíÚ5Õ)Öôôt©Têëë ÛHˆôôt.—»cÇŽ’’±XÌápÒÒÒ¬­­‰Põóó+,,äñx</;;{Ù²eb±X©!DQ4  ¤¤D ðx¼ââb¢sqqÉÌÌd³Ù‰„ÏçWTTÄÆÆZYY© SYYÙÜÜB’1ègprr‰D>>>(ŠzzzŠÅâÉ“'“]˜þذaƒƒƒÃ¡C‡h4ššoƒ¢¨©©©©©©êuccãþ\<Èt— ‚ï¿ÿ~Ê”)ªŸØÈȨÿ×Y†¤;Eõ+vïÞ½dÉ’¨¨¨)S¦„„„Ü¿¸à7$o»EQ¬úK· –M}„$£…é0 %"ô„êõ|ôÑG‚€ò3wî\>ŸÿôéS×¥^èA£#ò›7oÚÙÙ)Š·Úe¹ú\ØÙÙmذ!''§²²Òð²½E¼-Šš1cFkkë/¿üòæÍ‡ ˆ ïÛ¢(5P¬úúÔQËfOU¤Z„a /‹ ‰Wº¢±-œ9s&‹Å’Ëå‚LŸ>½ªªêÖ RÇñŽŽŽ¾–B_ÔçÂËËkÀ€†”ç-åmQÔˆ#0 E¾OJîÛ¢¨oEÕSBR´nܸñÍ›7`¨zE ÍÍÍ2™Ì×××ÅÅE,Ëd2Å‹‹ÅâƒR;;99ýòË/OŸ> …MMM=Ú³gñ¬™™YDDÄýû÷E"QCCCrr² 9ww÷«W¯²Ùl©T*û/l6›˜T177‹‹«­­‰Dl6;%%ÅÁÁ¡g'¬Îž=ÛÒÒ”®1ï‘‘‘‰$&&†¸“¢'Ožäóù[·nÕjj¢©©‰x×™3g¤RiDDø÷âÅ‹yyy ³ú\œ9s¦ªªêèÑ£4---Ðöˆ#ˆ{ Ň~x÷î].—ÛÒÒrçέT­ç×LNN...`2™|>¿K4ªúÚµk7nܰ¶¶NNNnjjåååD"m’Š¢ÏŸ?ßÐÐ ‰jjj~øá333²ÔË€h*8ùñÇëêê„B¡Í{ï½>ºL&[´hñ ý…TOX”ž¥;55µ°°pãÆ………B¡°¹¹999y̘1ä{4êA ...à—_~Q uþðáúºº"ÔŒV ‹-Ÿþymm-›Íö÷÷ mll¬­­]¶l‘ˆúÒM¥¦Õ£^H²¢z%t¼jœú.#×+alllllÌçó·mÛ6`À€Y³fÉår///ê2//¯²²ÒËËk̘1‹/NNNŽ%?ž——wüøñÙ³g;6,,L"‘¤¦¦Z°°°¨ªª*,,œ?¾]TT†a'Nœptt7˜˜˜dffÖÖÖ®^½ÚÆÆfåÊ•,«¤¤Ä‚ªvþË—_~‰aXpp°jîh4š±±ñÚµk1 ûæ›o”n˜>}º\.'òuèÐ!™LvâÄ ¢r§.äéÓ§Åbñ¶mÛ´jóòò®_¿”–ŸŸÏçó/\¸þ---MJJ©©ÏF322:zô(†aÞÞÞ&&&ÀˆRSS¥RiEEEXXØøñã===+**jkkÍÍÍ)Ê©ÿ×LMM•Éd­­­ÝÉ@EÕ7nÜ(..ÎÈÈŸ4iÒ|––fiiIÖ§›Ô¨(kkë²²²'Ož,[¶lüøñ!!!---W®\!—m*2¨/8êBWUU1™LSSS $Q%õˆTdÐÇ¢ô/Ýééé2™¬¶¶vÍš5ööö!!!\.÷æÍ›D6©èÐeý€¢è­[·ž={FVˬY³d2Ù©S§ÀV½ ^^^r¹üÒ¥Kï½÷ÞíÛ·ëêê®\¹2yòäû÷ï“ õ¥ÑdÕê³I£^H²¢ze‘2))I)êWºdÊ”)r¹ÜÛÛEQ???¹\>zôhêïµ°°J¥gΜïBQÔÈÈH)‡à (Ÿ4íæÍ›DiñññÁ0lË–- Æf³Év*—Ëýüü@²(ŠîܹS.—wi êÑhkÖ¬QÓ?~œF£íÝ»W&“>}š\à© E[ÉÏ;WQQadddffÆçóûí·’’##£wÞyG,ïÚµ‹œ`w¹|÷Ýw†yyy©vºSSSÛÛÛ###A}Š¢èöíÛ1 [½z5źþ_S£ TT}ãÆ Ã"""ˆD”Ê‚z›Ô¨¨¸¸8 Ã<<<@"4m×®]r¹<00¢ T Eªªª=z¤ZØõ’"úX”þ¥;==½½½lr111DFQ€îꇀ€ ÃvìØA\Å0ìý÷߯ИMõ2€†p÷îÝFFFß|ó †a`Kç?ü ”ÌRMé¦bÕj²IŠÓdEQyvò1 ¥µ@Õ+Ý1iÒ$EËÊÊp···—J¥B¡ú«E"—ËõòòÚ²e‹™™ŽãJ ¤à X½P(<oÔ¨QC† ¿6 A7oÞ7à8N.Qžžž¯_¿¾zõ*± òøñcA¦M›fàí|ýõ×®]»vìØ‘žž¾uëVò$8u! EGG‡¶kÈÕÕÕcÇŽ>|¸‡‡‡‘‘Ñõë×ííí-,,fÍšellüøñã\ÊÌÌìììÄqÇñ¦¦&Çmmm)ªº§¾¦(¦€¢è… :::@"JeA½MjdþüùÍÍÍ=‰(ŠäädA”52P)8z¢¿=…þ_S#ÙÙÙ …B‘ È|R ¨5\¸pÏç“g)?ùä“òòò’’r¹S“M*2p¹\…B!•JiiiÁqüÅ‹³¯TÐÓª)¢¿ÁEQ¹S»]£¡¡¡oÞ¼QsE  ñãóù‚ØØØp¹\ê¯lÛ¶íèÑ£GŽÙ¾}û;wΞ=[^^N¶ooo??¿I“&1|WÐ'¿Þ½{W&“ùûûWVV¶¶¶†„„XXXœ>}šHaìØ±ƒ jkk#ÝÁƒk+ªžLš4iÁ‚"‘èÛo¿UZ îm!KKKŒŒf̘áîîÞÒÒ’››‹¢è¼yólll^½zUXX؃ aCC‘°WêÛ {êkª‘b /^¼PcÌêmR#t:½¶¶–¬s¡Pˆa˜µµ5u4=é!{ý¿¦zpg³ÙÄ+Z[[¡Óé ¡¨5üç?ÿÉÌÌ œ5k“É\²d‰µµuRR’RÇEM6©ÈðŸÿüùïv§¿ÿþ›ø[ã žVMý †¬(õh±kÔÄÄ$!!¤¯t¥»¶755ÕËË Œ¦E"‚ `+‹ëëëgÏžM±Ñ¾wïÞûï¿¿fÍ__ß+V,[¶lÿþýçÎVâïïìØ±ÆÆÆÓ§O———?{ö,22rùòåÄãgË–- ™™™<ïûï¿ÿé§Ÿ#CQT*•Nœ8Q©íé¥Þ«>ú裼¼¼>ú(&&FI±½-ä£G^¾|éìììââRWWÇãñZZZ¦OŸ>jÔ¨¦¦¦×¯_ëÿ ‰D¢ó³=õ5ÕÈ@15£+6IÕÁ„êõ#<õ§GÐ_ÈAÿ¯©pÌ—èúƒzŒ\ÕRуz~ùåÿµk×,[¶ìåË—¿þú«’êÔ2èÙꫦ‚þC½†¡Únܸ‘¬ÍÎÎNÕ+Ý=»~ýzE™Lfiié—_~©P(šššNœ8 6R”˜ì¯¿þzáÂww÷ÄÄÄððpƒ~õ÷÷§ÑhkÖ¬s8ŽƒÙ32¾¾¾†-\¸°¾¾ž˜: ~åñx&L>|8¶ö!iiiÛ·o‰‰Y·n]mmí±cÇ9{[Èÿüç?---vvvŽŽŽ¿þú+ŽãOŸ>8qâСCY,–VE¨·wØ÷ö×Ô?*6‰¨UŸÏ9r$ùŠ¥¥å°aÃÈ#¨/8úÓ#BRA‹ê©‚ãääTYY $;v,‚ üÛ#z¨¬¬,((øôÓO‡ öá‡æææŠÅbêà[P´ê· ªƒY…BÑI¢Ë+ÝÑÙÙ‰¢èرcŸ>}ÚÑÑ1uêT33³ÊÊJpúB[‰A©.((¨¨¨077'cccãçÏŸ·´´€:‘N§»¸¸(u…ìííE"ÑË—/Á«•zwïÞEdãÆ}îñ¡£££³³sçÎL&s×®]K—.%2b!Ÿ>}jgg7nÜ8&“‰ãxUU•½½ýرckjj´JŒþ‡Ú;böú×Ô?*6‰¨UTNNŽ­­íܹs‰§üüüP½{÷®¶­BwGzPHõècQ=Up>þøc"› ,@Q4??d³Gô€ãøÅ‹-,,öìÙ3räÈß~ûM«‘¾E«~»0P?mÚ´Áƒƒž”««kGG‡¶«MK—.½~ýúúõëÇ7f̘€€€yóæ=xð€H¤¤¤dĈaaaVVV ,8þ¼R2dHYYÙÔ©SËÊÊd2™T*e³Ù‰‰‰£F7ÄÇÇ?xð`óæÍ;vìprr²µµõ÷÷¿sçÎŒ3úä3¿~ý:$$„Çã?~œXÒ§.¤nç©­­9sæ_ýUPP€ãxIIÉØ±cétú“'O´úd¹¹¹¯^½Z¿~½ƒƒÃĉ7oÞ܃·¾¦þ)h´I€EEGG766ÆÅÅy{{ÛØØ„……1™LÕu£îÐXpôG!)¢EõHéÆqü«¯¾òóó³±± \µjUAAÁÍ›72{Jiii\.wõêÕ---7nÜÐêKà[P´jHŠD¢áÇ#òã?–••i»yÚÅÅ%33“ÍfK$>Ÿ_QQkeeEÜ0bĈ„„à˜Åb9s&((Ã0âÈmZZZcc£ÏðáÃétºÇ;qâQœ† YZZ* ¹\nEEEbb¢Ò™Y5lذ¡¡¡¡­­M&“=þ\&“µµµ±Ù쯾ú ¼â‹/¾¨¯¯'nËå\.—ÍfïÛ·Ü tŽAyóæq8œ¢¢"â E!u;Gˆ ˆ§§§\.ÏÎÎßhèС|>_(Û 4怢h@@@II‰@ àñxÅÅÅÄG››É;›—,Y"—Ë8@QZý¿&4ªúÆÏž=ën‹¶F›Ô¨(AÆþüùÆÆF±X\WW÷ÓO?)¶T/ƒÆ‚CîŽOè/$Eô´(=Kwzz:—ËݱcGII‰X,æp8iiiJaÔëAcý@pìØ1 ⢢º< >›jdÇ'ÀY‹àà` ÃÀØqÿþý„Yj,Ý­šz6Õ Þ`4 ©ª¨~8ÓFü­Ã"°Å ì566îò,qòüJ~)N—J¥§OŸ&¿EÑÂÂBÂ[ŠR"ݽE}6‰gɉ€\¨¿Aé𸢤1*BêvްË7*^Ö˜‹.ï$'¨ê"Y5ãj葯IQõªÖèëYM*½ºKE©þÔå¡.52P)8é¨y‹ÎBRGO‹Ò§tƒõ èîK©Š§æíê Î÷ß/‘HÞ}÷]¥Ñ*•lª‘ÜLœÿSú[õñî„ToÕÔ³©*V­æÚÚ›L²STÝFèT6w©¦L\ÇnÀ‘âW ‹Ñ£GWTT¨O„:ŸÕ˜ \Åužê*/Bþ¯ÎµBõ:o´ëîNÕ‹]f³;zäkR”A½õ±I¥Ww—”Fmk´¨žÚó¬&=…¤Žž¥çô Š¢`o„¶âiõö~öÙg999ªÛÓ¨dS½-7+ÕÉÄßzÖ´]þªzZµ¶öÖÏF޽†H$zôè‘··wAAÁ½{÷†êææ:xðàóçÏ¿Îà!ðkBþyX[[[[[óx¼o¿ýväÈ‘111>µùW`mm}êÔ©ªª*¡Ü¬… IDATP(‰X,ÖüáííÝç{D!:¿&ÄÀ¤§§Ëåò™àí’iÓ¦±Ùl¡PXRR²råJhɆäíÞóª-À?˜'üõöq7H/¿&Ä¡(Ú{‘‰wšàD,´d@ @ B°xñb6›ÒKhçÏŸomm•H$2™ Ä'2| 2:îÔÔT±XL}A÷_ôŠ‹‹‰ÀÖ"‘¨±±1;;[[cuwwOII©©©grY,VVVÅH.®®®Dto%X,ų•l6»Ë²²²(¦BÞz¨¯¯¿|ù2pEQ€”””.ß•››ûçŸêpH‚ ÈÌ™3kkkoݺüN899=yò$??x¶ì%œœœD"‘Š¢žžžb±xòäÉýÐoŠ¢¦¦¦j¢”|ÿý÷S¦LÑMò 6888:tœë“s¡O6ß"4~îîè©s«]À`0’’’ˆ0¼Jÿöž>ž¢ÀiVÀ‘#G0 [¹r%ˆµM]‡ªgH£££1 ¢Xð@0÷eË–™˜˜L˜0!88¸®®®­­möìÙTôPXXH8Q¢¶¶6==ým±‡~ÅÔ©Skjj²³³U¦£(úÞ{ïUUUåååQ§®-›6m‰DÀ_óáÇ«ªªzo{¤>¨w¼`gg'‰¨Çÿë}ÂÉöH sÑ#Ù|+ÐÊÏm·øj†)44œÐŠcÕ…Bþ}[޼Ö|>_ ´··ßºuËÓÓ3%%…ŠüëÖ­1bÄêÕ«  …P(|òä Bù©ÒiV俱sµÚ¦´imæÌ™ëÖ­{ðà¶çç:;;;::êëë:;;ccc׬YCÅl[[›³³s—?™››óx<¸ÛM¢££ÍÌÌV¬X¡jÇñêêê½{÷2Œlݺµ7JΜ9“ÅbÉårA¦OŸ^UUÕ?¿£zÇ ^^^ 0¤<½Æ\ü3²I­ül(¡U1¡ÚÒnܸøøïììísPP¸B±¹vtt<þ|CCƒH$ª©©ùá‡ÌÌ̈_“““‹‹‹˜L&ŸÏoii¹s率‡¹ËcnnW[[+‰ÀƒƒƒÎ}"Çä/^¼ XæAf‡C¹ÖÙ{KOqøðaÇ÷îÝ«[Gd¡¦¦ÇñQ£FQQf[[›•••j9tpp055åp8:ˆ¡×®]»qㆵµurrrSS“@ (//W²õ¸»»_½z•Ífsæ2™ŒÍfIõ&GÅhœœ~ùå—§OŸ …¦¦¦GíÙ³G©ÈlÙ²eÖ¬YgΜ©««ëÒq¿víZFFÆêÕ«»Ë`TTÇSM\#ÍÍÍ2™Ì×××ÅÅLÝ{xx,^¼X,$$¤¥¥åÊ•+dŸ¹2™¬µµ5,,lüøñžžžµµµ„»X“ÌÌÌÚÚÚÕ«WÛØØ¬\¹’Åb•””PŸ,S£àï¼óއ‡GVVV}}=u÷ó[·nÅ0ìäÉ“ú¯:tð+Vè3¹±yóf¹\~äÈ­¾4˜]²d ñjà~722’J¾ÂÃÃ1 suuEQ466V*•¿Þü±\.ÿâ‹/¨äèÊ•+䶇 ::Z+·¼ÅÅÅááá“&MúàƒÒÒÒ×ä±°°¨ªª*,,œ?¾Pˉ'Á MN£Ñ"’——WYYéåå5f̘ŋ'''“=ªîß¿ÿìÙ3"nFw|ðÁr¹<>>¾KEGG‹D¢ýû÷kkœ`‚ÏçoÛ¶mÀ€³fÍ’Ëå^^^&&&Ô“Ú±c‡T*ýã?-Zdgg·nݺ[·n‘¿E^^ÞñãÇgÏž=vìØ°°0‰D’ššJØ-pãY[[»fÍ{{û.—{óæM%·±ÆÆÆk×®Å0ì›o¾éÒçÑ£G1 óöö+J3cêe 轩Q¥1o ROêSpPÍÍÍmjj£€»»»L&;{ö,‘_ªÖ(ƒúÏ­ñéé醱X¬µk×öÊ2yQ|ƒ¡±"Ž‹‹Ã0ÌæÑh»ví’Ëådgá‘‘‘À,Š¢Û·oÇ0 8JG$44T.—ûùùûQݹs§\.ïRG]òäÉ“ööv¢Î•ËåYYY®®®ÔÍÝÔÔôÞ½{†‡‡‡=šâƒªèßÚÚÚÖ××—””A!(B4„ pvvÞ´i‹Åª©©±µµ¥ò8‡ëëë‹¢èÇ›››/]ºddd´~ýz Ã(.àwé0WÛÅ€7n`AØŒV ölÙž¢Ñhl6›\ùj49Fkaa!•JÏœ9Ò*åqâĉ‰äâÅ‹…GQ´¤¤¤¾¾¾Ë;uö±Ž È”)Sär¹··7Š¢~~~r¹\+Û7n‡Ãa2™ Wý ã„‹ç›7o6665xzzz{{;ù[ÄÄÄ"‘ÓY³fMw5#‚ ß}÷†aÝ-ž©— ÷BŠ•˜ú\¨¿Ê+ô,8_ý5†a Ü:¸rüøq Ã>úè#âŠFUS”AÍç¦bQ_}õŬi÷¥ y9øŸ¥b.óçÏonn~ôèI<99A¥o™™™ ü)ã8ÂÛÚÚ‚<==_¿~}õêUbZòñãÇ‚Pܱ hmm¥ÓéÎÎÎ~~~üý÷ß?ùäŠ)¼~ýzùòåqqqÇß»wïãÇììì(¾½g9xðà¨Q£<øêÕ+OIIùùù_}õU~~þ_|ÑÚÚJåÁÚÚZÇ­­­mmm322ÜÜÜP;vìßÿ ~Õ˜X¡TEÛyfE/\¸ÖYµõ. Âj¿yó†ì•†l MNÑŠD".—ëååµeË333 ¡R§M›fll\__¯Qo }+++:®ú+XoÖm¢~Ò¤I(Š–••á8noo/•J…B!õÇ/^Ÿ ˆ¶*}Áææf5"y{{ûùùMš4iĈ8p ˜"nÀqœÍf)€nNïÁ†P£ ½MOUbú¿BŸ‚Ãáp=z4wîÜ‘#G …ÂE‹ÙØØœ:uŠ\ö©¨Z¨¼ÇqÕðݡŮQ“„„.õ3 Ç)6‡ª­zE"‘¨y\*•Nœ8Qç@Jà8ÞÐÐÀápœµ*l …âï¿ÿNMMMKK;pà@XXXpppTT”ÁÚ€!C†ìß¿_&“8p@çͺ`L¦CeŠã¸@ 1ªªªjjjššš>úè#KKKê½+W®|øá‡ªjOHHˆˆˆ ®I}tÎáp¶lÙ’™™ÙÑÑÁãñ¾ÿþûŸ~ú‰H“¢É©1ZAîÝ»÷þûï¯Y³Æ××wÅŠË–-Û¿ÿ¹sçÈoAþë+•"=Xw§¦¦zyyY&‘H„ ˜J‹Åõõõ³gϦ^´Õ| ÿcÇŽ566ž>}º¼¼üÙ³g‘‘‘Ë—/WJÄØØ˜èg^7õÈœÖ2ô6=^‰éü =+«k×®}üñÇ«V­:yòä_|¡P(RSS‰EQÕúÈ ƒE©‡jC¸qãFrµÕÙÙ®Pù„|>Q"°´´6lÅŽ0‚ <o„ ÇýÖÇq—U€a]ºtiëÖ­ãÆë)‘¨ðí·ß:99EDDP×^ÏÂãñÌÍÍmll®_¿®P(ŠŠŠf̘addÄãñ(¦ÐÝâ¨wá‚õÎ… Ö×דöį=brÀN~ýõ× .¸»»'&&†‡‡3 â8Å8é`Ëyä¤'`¥‡Éd–––~ùå— …¢©©éĉ±±±`‹8•DÀVáqãÆ¡(Ú¥`þþþ4mÍš5`êÇq0/­„““See%HxZåTÍÍeèU(Z•Ir=_¡'/^Ü¿ÿâÅ‹O:õá‡>yò„<ö2€ªu°(õPmÀr ù •ÇsrrlmmçÎKT~~~(ŠÞ½{—¢¡ß½{A7ö`wØÙÙÙÚÚº»=ëT{C yf`úôé £¯Nn€vvvþù'Žã999“&M²°° >_×Sk„zboo/‰^¾| )½½M4‡æææäN@uuµB¡ptt¤2-aoo/‘Hz°ÔÙÙ ÖwŸ>}ÚÑÑ1uêT33³ÊÊJ Š‰ÜºuëåË—ä}ÈJ?þ¼¥¥ô6ètº‹‹‹êÍü1q¸:ÊÏÏתl‚AíСCu–¡W¡hQjr¡ñ†Þ¨'UyõêUvv¶››ÛÊ•+---A‡˜øÕªÖÁ¢Ôc ùñèèèÆÆÆ¸¸8ooo›€€€°°0&“™””D±î‹ðàÁæÍ›wìØáäädkkëïïçÎÕÃk×®•H$L&SÍ~!33³O>ùäçŸ666>qâ„’ Ý¥>þüÑ£G?~Æ {÷îmiiILL¤˜uºK–Ø·oŸÆs¦½'‡Ãqtt?á8~óæMEÇ×W#Tõdff ÕC/C† )++›:ujYY™L&“J¥l6;11‘8Æ@Ýäºcéҥׯ__¿~ý¸qãÆŒ0oÞ¼+÷ŠŠŠšššyóæ‘ÕvÉœ9sœœœrss»lÒÓÓ¥R)ØÍKE6‚iÓ¦ <tœ]]];::¨øU ÓÔÔtúôé©S§&''{xxŒ;ÖÛÛ;--mÞ¼y@˜’’’#F„……YYY-X°àüùóª•8Žã_}õ•ŸŸŸM``àªU« nÞ¼©•$¹¹¹¯^½Z¿~½ƒƒÃĉ7oÞL|t*2ô6-JM.4Þ ¿ÑRä÷ß711 û믿ÒÓÓÉ T­•E¸»£ñãÇŸ?¾±±Q,×ÕÕýôÓOäãV`':yí’%Kärùˆo>>ª]§îR8uêTMM ŸÏ—ÉdB¡°²²òìٳı3*)h<>Ñe ...2™ìùóçr¹\£·ÒîdP=GØÝ¥€a85®dff¶··/_¾Ü6wãÆgÏžiô¢”••%‘HNŸ>­”‹´´´ÆÆFŸáǯ{>>><ïĉMN£Ñº¸¸dff²Ùl‰DÂçó+**bcc­¬¬”$ܹs'†a;vìPß‹?wî8á×¥’+++››› ¤^ªŠD"ààôÇ,++Ó¡çD£Ñsrrž={&‹³²²&NœD1bDBB›Í‹Å,ëÌ™3AAA†ÇÀÓÓÓ¹\îŽ;JJJÄb1‡ÃIKK#ï¤ûâ‹/êëëÛÚÚûçr¹l6{ß¾}d¥¡(PRR"x<^qq1‘2lذ¡¡¡x…L&kkkc³Ù_}õÅÑ•¨TbjrA寠XpÔƒ¢hii)†a¿ýö›’xU­QŸ›ŠEåäälß¾½·Ôë Ø¼Ž‹©ž¦Rõ‘Švåeœ\ì.@vvvkk«êºêÙ5i“z ä·h•9)p€¦»ºL%y+UÍ õ\¨µÆ€ä7µ¸çEѯ.¸MÉTètºT*=}ú49(Šæåå)ãîÎä4-°yK£Ñrss›››ÕL.Z´H,'&&vYªd2™n®€=3«m rW-\„È/Eþ{ ~À€d]©I\ÍÁS¥zF)§jdP*Ýj^ÑS R‰©É•Ô¿¢§RÊTýI½ª5Ê@ås«(wúØóÛÍÈ‘#Á±cÇtž"‡)ôT ý ‰DòÓO?‘sgiiÙÚÚzãÆ Ãž÷ߟÍfß¾}[)ôÀÉÉ©¬¬¬¨¨¨»=5þþþ"‘¨Æ‹ ‚¶.’!ˆ´êÄÁz5…þLFFFccãš5k¬¬¬Æïëë›-‹õô{§(ŠÎ;—Åbedd(í?~|qq1“Étppèîqê£üþ l!¤°¶¶>uêTUU•P(‰D,ë?þðööî«¶Ÿ˜G¥xýŸl!}ËÛÚ…„@ô,ñ’´N› †,(êp@ @ @ H¿ÆÉÉI$ùøø (êéé)‹ûÕ†ï!C†°X¬¶¶63V"‘p8œ»wïRß§P\\LÄ›qº³³³7lØ Õþ ww÷”””ššp–ÅbeeeQ Ôâêê b:«¢zâ¾;Ølv—)deeQL!22R"‘z¨¯¯¿|ù2pšEQ€”””.ß•››ûçŸþ³wŽô3gά­­½uë–Ò! ''§'Ožäç矤[@|øpUUUÛ'Nh9rð•+Wš˜˜hUç>yò¤ªªÊÔÔÔØØ˜N§{zz‚X?Û77·–––üü|///++«3f„††ÆÇÇSƒ|âžœ‹îνv‰ê9Öèèh ‚‚(¶èÀyͲeËLLL&L˜\WW×ÖÖ6{öl*z(,,ÌÎÎîRàÚÚÚôôtØêÀÔ©Skjj²³³ÉÁÊ(о÷Þ{UUUyyyª¿B ÿ„aÛ¸É-ƒÁHNN¦X1;wîáÇàæ7nôÛMçðñ !$2…¢èìÙ³åryZZÅœÆÆÆ¶··Ï™3‡0 œ&h›D\(1sæL—™™I½×BöⲈaÙ{™®\¹R]]Ý¥ÆALLÌ?øtcïqûöm‡ÓÝ Š¢Ë–-“H$º¹§@Þj¨ZüÆCzrHzª—Š—úææf™Læëëëââæî<<</^,‹<ttt<þ|CCƒH$ª©©ùá‡Ènˆ“““‹‹‹˜L&ŸÏoii¹s率‡¹T›››ÇÅÅÕÖÖŠD"0½æààЇS¯8Žƒ¬½xñ‚â¦|a™Ãᦠ™H•Çã8¾wï^ã>*ŠššÇGEås€è Pºîàà`jjjÈX×®]»qㆵµurrrSS“@ (//W²:õ¸»»_½z•Ífsæ2™ŒÍf½ õFKÅ윜~ùå—§OŸ …¦¦¦GíÙ³G©1Û²eˬY³Îœ9Ó]¬ǯ]»–‘‘±zõêî2ÅãñT‡@Þv´Ãþ ¦§ÑhëhGGG ‹—/_îß¿ßÊÊjÑ¢E …„ð8|ø°B¡°¶¶þý÷ß]\\víÚõþûïÇÆÆúúúž?ž9::>|8==}îܹ!!!t:ýçŸ&¼¬š˜˜¤¤¤|ú駇vssÛ½{÷¬Y³.^¼H00ï¼óއ‡Ç¾}ûD"ÑÏ?ÿL±!A¾ùæ›~R×lÞ¼yöìÙ £¢¢BŸv H ¦ñæÖÖVà²966V*•nÛ¶F£ÙÛÛ#ÒÒÒB%‘+W®Û‚èèhêº522²²²:sæLeeåâÅ‹}}}kjj¨Çí²°°þަOŸþóÏ?Óh´_ýÕÓÓœ™Óh´ÍAƒáææ¶mÛ¶iÓ¦ýÏÿüOCCƒêôæŠ+^¼x¯¦7ƒã8XøX³fM— !ð_Ó?gq ƒB¬‚ÉRòõL™2E.—{{{£(êçç'—ËGMü‡a˜‡‡8ãL£ÑvíÚ%—ËAµ<ýGFFWR(Šnß¾ðիWƒB*—ËýüüˆIÅ;wÊår}¦FÉ.äryVV–««+uLMMïÝ»‡aXqqqxx8YEÚ¢ÿÔ¨­­m}}}IIÉàÁƒµz˜0`€³³ó¦M›X,VMM­­-•ÇA¼\QèáÇÍÍÍ ÒÅúõë1 1 5&Ò¥Ó^mÆÝ¸qðˆˆÂê´j|||0 Û²e xŠF£±Ùì›7o‰h4Zfoaa!•JÏœ9Ò*åqâĉ‰äâÅ‹…GQ´¤¤¤¾¾¾;OÊÿl¯{-ÚÙ41­`BBh©ì—™4iŠ¢eee8ŽÛÛÛK¥R¡PHü:þüæææG“““Q :“™™ÙÙÙ Bƒá…­­-¸ÁÓÓóõë×W¯^%&?~Œ Åý–=Ekk+N·°°pvvöóó8pàï¿ÿþÉ'ŸP”áõë×Ë—/‹‹>|øÞ½{?~œ`gg×ËRwÍÁƒGuðàÁW¯^éðxJJŠ@ ÈÏÏÿꫯòóó¿øâ‹ÖÖV*ÖÖÖâ8nmmmkkëì윑‘áææâÇþý÷ßàW‰ôTì_E/\¸ÐÑѬN«ùaà5ôÍ›7d·5dK h´jÌ^$q¹\//¯-[¶˜™™ •ò8mÚ4ccãúúz*¡Ï›šš¬¬¬ètºê¯ …ÂðÁ“! Å¦M°"øæÍA6nÜHÔsçΓ¥jŸÏGÄÆÆ†Ëå’¥ÓéJœP(Ä0Œ“ A††âðFSSSðïØ±c DŽ zÇÚŽfô§£££³³S(Þ¼y“ÅbåååíÙ³çÞ½{ëÐöööƒFFFúøøøùùùúúº»»/\¸Üo0K–,YºtéÕ«Woݺ¥Û¤h@@@ff&þ¡ò`UUÕ«W¯ètú¢E‹^½z•°víÚ Œ=Z$¸"~ñâ…’­Rìö÷÷¯¬¬lmm ±°°8}ú4¡ŠF«ÆìÙ¶mÛÑ£G9²}ûö;wîœ={¶¼¼œ¬j0¯@1l²@ @ÄÑÑ‘ËåBos TBbÊFpp0¹ZW_7¥¦¦zyy‘H„ >ŠÅâúúúÙ³gƒ¤TÇLªW$IwoAQT*•Nœ8QÉc¡¶½øÇñ††‡ãìì¬Õ¨T¡Püý÷ß©©©iii ŽŠŠ2X0dÈýû÷Ëd²è¬=0&Ó¡2Åq\ XXXŒ=ºªªª¦¦¦©©é£>²´´¤Þ¸råʇ~¨ªö„„„ˆˆêšÔGçgË–- ™™™<ïûï¿ÿé§Ÿˆ4)­³GäÞ½{ï¿ÿþš5k|}}W¬X±lÙ²ýû÷Ÿ;wŽüä¿ÎT)ç?!ÿ*¨6„ä! òßn) ((H}e±~ýzE™Lfiié—_~©P(šššNœ8 ¶¡"ÂçóÁùBKKËaÆQìÆ"Âãñ&L˜0|øp0èì'à8®ó² ¨ /]º´uëV51~{ƒo¿ýÖÉÉ)""‚ºþ{gnnnccsýúu…BQTT4cÆ ###G1…îG ¼ ¬w.\¸°¾¾ž˜ö'~í£vò믿^¸pÁÝÝ=111<<œÁ`7€Ä»‹e¨ØhÃf³ápòïA‹]£$”~Rÿlgg'XàyúôiGGÇÔ©SÍÌÌ*++Áy pONNŽ­­íܹs‰ÊËÏÏEÑ»wïR,wïÞEdãÆýª3ëììlmmM}Ÿ¡*`oˆ!Ï LŸ>=00°  €Á`ôÕ‚8Aagg÷çŸâ8ž““3iÒ$ êóu=µF¨'ööö"‘èåË—ÀÚ•ÞÞƒF šÃ‚‚‚ŠŠ sssr' ººZ¡P8::R™–°··—H$}Õ‚@úµÓ¦M>þÁƒ›7oÞ±c‡“““­­­¿¿ÿ;wf̘¡Tþ×®]+‘H˜L¦ÎÁ©¤`fföÉ'ŸüüóÏÆÆÆ'NœPÊEw)ÄÄÄ„‡‡ÏŸ?ôèÑãÇß°aÃÞ½{[ZZP\ôX IDAT)¦ .Ž9bdd´oß>aqzO‡ãèè~ÂqüæÍ›(ŠŽ7®VЙ™™@õ(ú!CÊÊʦNZVV&“ɤR)›ÍNLL$NGP7ÚîXºtéõë×ׯ_?nÜ8pNcÞ¼y< ®ŠŠŠšššy󿑿vÉœ9sœœœrss»ìm¤§§K¥R°›—ŠlÈÛ‚<œ½÷Þ{oÞ¼)**ÂqüÝwß}öì†aäø|þŠ+öïß7lØ0±X|ýúõƒ‚½9TxýúõêÕ«#""üüü¾þú뎎±X\RR¢:†puu566Vk2¤´´tðàÁC‡¥Ñh?ÿüó?þX[[ëåå¥4î.AlllÄb1øûÕ«W,+$$äÊ•+e0`@``àÎ;MMMß¼y#rss;¦:u¦FŠt™‚‹‹Ëœ9sºLY$Mš4‰¬Š^’A––“ÒÒRp½½½½¬¬lþüùpTCuTwîܹY³fÿùçŸ/^¼5jÔ¼yóNœ8ñ×_………) êFÛFFFˆ‰‰yóæP(¼téÒÑ£GÉŸ Çñ+W®ìᨒ ±±±jz–6l@Qô·ß~ëòí“'OnooÏÈÈ臟y 'ˆ¿»@€ýrà°—êY(ð“ÒýªµH¼»DÙÙÙ­­­]®º©>ëRÔîRèòñ.»ÏÝ¥@–ŸÈ‚V)“‡Ïº»¡ËÈÞJ5ªBM.Ô¿Zc @ òZ <Qµ:5·)N—J¥§OŸ&çEѼ¼<òE5F«Ñì‰øõêmžF£åææ677«™ ]´h‘X,NLLìÒæd2tÀü9r¤@ 8vì˜Îå¦ÐRèÏXXXH$’Ÿ~ú‰œ;KKËÖÖÖ7nÞ?Ëûï¿Ïf³oß¾­zàääTVVVTTÔÝž‘HÔ¯ÂÅ@ ÝÑß;L¡ÿ¤ÐŸÉÈÈhll\³f••Õøñã}}}³³³Åb±þžÐuEѹsç²X¬ŒŒ pÒŸ`üøñÅÅÅL&ÓÁÁ¡»Ç©ò!ù_¬­­O:UUU% E"‹Åúã?¼½½ûªí'æQ)^‡@þ%ÀþÒ‹€%^ò‘vpš°¯å‚@ @ @ @ äߊ›e ØíF„ž ® *ñ( ùGÂ0=Ö /ù Üx @ ·-Â0. Á(F£½%@ ½Õ†h žÁ`t§@ ,III`"4))Ii²´¯Eƒ@ ¤—ë‚ào²›(¢u„@ ä ¹ÿl!ò–Bõøh 7‰ÁÁÁ8Ž'$$€qaHHõºô¨6„JáaÁÖâ"Ü)@ @ @ @ @ @ @ @ @ @þ•XZZ&''³Ùl±XÜÚÚzîÜ9r‹QQQ‰dÅŠdÇuU ¢z ¨I¤; ÝíÞ½{É’%QQQS¦L ¹ÿ>ðâMôìÙ³ëׯ÷m8 [[[‹%“Éèt:ùúÇ¥R©ŒÄÖ­[uh˱±qkk«¶FFFJ$ðj‘HT__ùòå ²v³´´W”››[KKK~~¾———••ÕŒ3BCCããã oWê­ÚÁÁ¡¤¤¤´´4((ÈÎÎÎÅÅå³Ï>#ç±Ï5ùäÉ“ªª* N÷ôô¼{÷®L& èW&§Q“ˆ¾€0Läxô #99\¤žNuuõ£Gº|$99Y.—Ÿ:uªºººo•+WJ¥Ò‹/¶··+5„‡>¥999r¹œÇãH$’‡ŠÅb Ã)¦ Â%K–€nF Ä0ìĉÚJåêêzðàÁ#Fh› {{{777### ÃàÁƒÙlvaa!ù“õ¹¢bccÛÛÛçÌ™îº2üø@£U§¥¥±Ùl'''BN¥º»Ï5 BBrEgÏž-—ËÓÒÒ VH©˜œFMB ÝaLñ¾7* ð7°3D1 á?þ¸xñbssóAƒá8.‹ÁõÕ«Wß¾}ÌŽ¾xñâĉ‡ª®®Ö:=‡……ÅÞ½{™L&—ËUš¶533:t¨L&Ó9ñðððqãÆ1bÇŽ&&&/_¾Üµk—D"ijjRzpÇq¼¦¦ÇñQ£Fi[ì'Ož–””¤mŽšššš›› _¾|ùüùó!C†7ôEy8°[ +åÑõVíää´páÂÄÄÄÆÆFBNò ýA“Jà8j€/^L¥MN£& ¢¢¢üýýOžŸíÚµáÇWUUÕ××;;;SÌS£ pvvÞ´i‹Åª©©±µµÕJ AÖ­[‡a˜Ðét__ßÇ———OŸ>ÈEP”©©é½{÷0 +..=z´vyëiº´j`cL&“Ïç·¶¶^½zôlÀ ýA“Ož>>OŸ>-((8p ¸¡?h’¼YÆÒÒò³Ï>ËÉÉa³ÙŸ~ú©áÔ˜œFMB =¹Dþ‰ aTT”P(œ7o(Þª !‚ 4 ü æoݺ%“É´j‡P%&]i4šê¬F!‰]£`†‡‰"ÄÐÙßßÃ0†Î KK˹sçÆÅʼnÅb¥Ý:}®(BŒ®]»öÖ­[†•——[ZZR<..Ni¾½Ë]ûTèÒª/]ºÔÞÞîç箣(ºmÛ6¹\¾fÍ"³}®IÕÍ2NNN</77—z!íMª19*š„@ºƒêjhÀL}pppPP±™X5ìC®\¹òᇪ}BBBDD„Æ•ƒ9sæ&%%1™L5+D:`óEiiéœ9s¦NZWWGQNÇ ]é¼VßÙÙÙÑÑ¡Û ÒÛARº¥# E"“É5jÔºuë’’’JKKTýDQ …âï¿ÿNMMMKK;pà@XXXpppTTÅ·oß¾sçN¥{p‡Å_ý¥P(®^½ rŠãxqq1‚ &L@Q´_i’œZCC‡ÃÑj~µG4©Æä¨hé-v’Xq±Ï[AAºs™A±¼-[¶làÀ¡¡¡!!!à è8×ÕÕI$ggç.[ Ðýü믿ô“ý-ÔÎl6 JKK»¼­oZ‚K—.mݺuܸqÔìÙfO•¦¦&Eˆ­+ä]ÒLÇqm§zP“]šœš„@´Ø5ÚIBéb¯‰§`d£ Åâ1räÈ‘#GZü—_ýÇñÉ“'­ ¹¹¹ÒS®®®ÏŸ?ôèÑÛØå¬¬¬<~ü¸\.×öÁ‘#G*]™4i‚ Ä.¾þ©¨)S¦ (ÊápúJU®]»öæÍ›µk×}8ࡨ¨(ªjÒÙÙÙÚÚº®®Î`2h49š„@Ô ËA…$ª=VP~È3‡_ýõ;3––V]]íààäîî~ìØ1}Žyõ!ååå:ôÓÿý÷G]¿~½¡¡ÁÎÎnݺu .üý÷߉ÎxPTLL —Ë-((hhhh49¥Ûº»ÁÁÁA&“ŸÃá0™LUù>Tr¢¿uëVäÆÆÆ­­­Ú>)‘HÀ«E"Q}}ýåË—,XÐW¥ÚÖÖ–ÅbÉd2¥0fff±±±õõõB¡°´´T7-!z(ŠÍf«Fi–ÉdYYY†<¥ªÑªûÖ¢\]]Åbq—Šb±XýGQ999]†Ý>uê”¶ºÒÙ¢qwwOII©©© …\.—ÅbeeeM›6 ¶©ÿ" žø›€b™yðàAyy9ç„¢(a@Ë—/—H$/^ôððpvvf02™lݺu†´°øøøæææ}ûöMœ8ñÝwß=þ¼\.ß±c¹¤ÕÖÖ^¾|ÄfÓ!zQPPŸŸßÈ‘#W­Z%—ËÍÍÍmmm7mÚ´|ùrŠ9%‡aš0aBppp]]][[ð¬¨užõ&%%E,?þ\©!d0Ïž=[¿~ý˜1cvïÞ-‘H6mÚD]Wú+J5Dstt4†aAAAë`Q±ê¾µ(E‰÷9rð•+W¾tɳNhT”ê¡þÿùŸÿÁ0ÌÏÏ¢=èoQnnn---ùùù^^^VVV3fÌ ïÞ? „a"âÑPõÓ©®®îÒÅŠ¢&&& u433c³Ù÷îÝ3¤‘ÙÛÛ»¹¹¯(Š<˜Íf’eàp8Dð)ÈÉÉ‘Ëå<¯  @"‘<|øP,c–˜˜H1M²‹5 .00Ã0¥p€Tpuu=xðàˆ#tÊ ‚ ÈÊ•+¥RéÅ‹•|ÑqÆñãÇêh4Úõë×É1í4¢¿¢”˜9s&ÇËÌÌÔÁ?™ÎŠ¢bÕ}nQ‡Â0¬Oæ u(þÙÙÙ555Ô¿¦þŠŠmooŸ3g¸”¾çÊÎ?-Â0vi4ˆ; ƒÁ yóæúÇüñÇÅ‹›››4Çq±X ®¯^½úöíÛ ®Ê/¿üBL“>þ\ Œ;V—<éJSSSss3!ÃË—/Ÿ?Næbff6tèP}ü‡‡‡7nĈ;vì011yùòå®]»$ISS“þÞjjjp5j”¶õ×äÉ“ÃÂÂ’’’tË‘……ÅÞ½{™L&—ËU~ñâÅ&&&wîÜ6£P(òòò>øàƒO>ùDÕ r—ô¬¢9|ø0Žã{÷îÕ!XŠÎŠÒhÕýÍ¢ú m‹ÿܹs§M›vîÜ9ê^¿õW¨ 8x)(}]ÞåïïòäÉ£Göï5h† üZ>¢6¢ÆÇwíÚ5yòä1cÆ´´´TWWÓétê´‚à%«²°°À0Œj>äÊ•+]®"DGGSﵑe˜>}ºµµ5çA[[[E¥R)u©”())¹zõê˜1cètzbb¢««k{{{ff&áD_\\\PÕ¡â]ZÝ^Š È¡C‡ÌÍÍwïÞ­êyø¶~üø1!RCCŽã@T*‰÷¬¢6oÞ<{ölƒQQQ¡Ããú(J½U÷O‹ê´*þ …‚ÜvjDEUVVâ8þÍ7ßh4à¿N™þ“!/‚9R­§}AU«VaK½R]EÐaÅ@§Ó}}}?~\^^>}út¢î^¸p¡\.olläp8mmmEEE;wî455Õ*qOOO>ŸíÚµáÇWUUÕ××k雘0`€³³ó¦M›X,VMM­­­v™DuëÖa¦Ãƒ‚,Z´H,ïÙ³ÇÈÈèäÉ“JS£`KqeΜ9r¹üرcÔ?‡žŠ"°µµ­¯¯/))zôèîî !œ5ýÇ¢ÔòQß#C@¥!¤ÓéeeeÍÍÍ}4‡ÅbÉår Ãòóó?ÿüs²5[YYEGGûùùY[[Ï;÷ìÙ³r¹\Û K—.e2™Ÿþ9Š¢»víº}ûöœ9s´mår9ˆ.TUUÅ`0&MšD=bèŒaØóçÏARZ ‡ RTT”›› ŒA5^Õ­[·ÚÚÚÈõÔŒ3är¹V^ÿõT˜ÒôööÖöYýE¦K«îEÐOBÅÿ믿Öj› þŠ6lØáÇëëë1 ãr¹ vvvZÉyëQÿõRCxåʹ\Ð']*###KK˹sçÆÅʼnÅb¥M(D(0]vëÖ-™L¦U;ë€ûAÔ­Š"yרnÑ…ˆ¡³¿¿?†aÚ£¢¢„Bá¼yóÀ{UÂëׯë?"ÔSQ€%K–H¥ÒÄÄDæ©ôW™î¬ºÏ-Š@Ÿ†0..NiaBõèE4ÿ¢¢"­¶Éôˆ¢h4ÚÀ×®]{ëÖ- ÃÊËË---µMÒß j© LHHÐê°„ÄÄÄ|üñÇgΜIIIÑj¹GÖéìì …=Ú¾}ûíÛ·×­[G>'¤P(ÀŠŽã …¢´´”F£M:•zú8Žwvv‚DÀž#Ör:;;;::::::;; ‘´}¨Wé_Ì™3'000))‰Édv÷^‰D2pàÀwÞy‡¸baa ˆH$¢.§þŠ2dÈþýûe2ÙtØ#£§¢È¨±ê~bQz²}ûvKKK Zíd!ÐXü—,YâäätãÆ ïE)Š¿ÿþ;55ÕÛÛ;..ÎÎÎ.88΂¾íh±k”Ü{ÕJPPPÏî‰Ú¹sg``àåË—÷íÛ§mÍÕ]OV¡PèVfpg³Ù(Š:99•––vyèüõ×_Ú¦ÿö²lÙ²††††„„€+ g]WW'‘Hœ;::ž>}Š ˆ««ë½{÷@]3~üxEÁWƒ‰úí·ß:99EDD´µµ쥪heÕo©EéVÊ” ¢(??¿ÎÎN­¶Éô M½téÒÖ­[Çׇ’@ÞJÔLúùù‰D¢k׮鼩AOFŽ©tåÒ¥K†M™24±æææJ7ܹsçÙ³gªöäs„z&5mÚ´ýû÷“ÇmTÈœ>}º½½}ìØ±ÄlÕ{ï½'‰¾ÿþ{¢§üÇ444 4HO™©3}úô¶¶¶¬¬,m÷s©¢›¢ê­º?XAß®R)þ@‡m2½„ŸŸ†a»wï†#Bˆvt×~üñÇ'''§OªÀýû÷¿ûî»Y³f9ÒÍÍ-66V.—3 BÚ¨¨¨3gÎxxxŒ9ræÌ™`kÃÞ½{ Y z°!Ôóøê!Š¢gΜáp8«W¯¶´´üúë¯e2Yxx¸!•™™ÉçógΜهŠÒhÕýÁ¢ú°!¤Xüÿßÿûºm“ébbbÂÃÃçÏŸ?zôèñãÇoذ¡¶¶¶¢¢Bɧ‚ éééR©Ô××·Ï÷ßBú)Ý5„©©©ííííííJ+|ûöí3X¥°gÏ&“ÙÔÔ$‘HÚÚÚ˜LfDD¹ïéíí••<†·µµååå¸sÚƒ aO¡Ú"2xðàãÇ××׋ÅâÊÊJ%Mö6...2™Œ¼Õ³O\hj´êþ`Q}ØR)þ&&&ÕÕÕºm“éN:USSÃçóÁ†íÊÊʳgÏv¹µµ²²²¹¹Ùó=1´Åƒ:Hu »\=²ö@°,’ßNŒ À=ª7FHÖ'"ºˆÔÑÑ¡zèÓðŠû»ü ¬îF VÝ,Š M‹bñï®ö0 ]Öªþe?~œššºuëVèV@ ÿ:üýýE"ÑäÉ“ûÏœ @ †ì&ƒ­ @ @ @ @þ‹¥¥err288ÕÚÚª­£ý QQQ‰¤Ï=ý÷úƒ¢úƒ oPQŠê)zJ“†n„vïÞ½dÉ’¨¨¨)S¦„„„Ü¿œÂ±´´ßÜܼoß¾‰'¾ûî»çÏŸ—Ëå;vì0|[øÝwß/”™™©š¯ÚÚÚË—/›ššêø7((ÈÏÏoäÈ‘«V­’Ëåæææ¶¶¶›6mZ¾|9•ʱ°°0;;»Km×ÖÖ¦§§¦0,_¾\"‘\¼xÑÃÃÃÙÙ™Á`Èd²uëÖ‘³Ð·ŠBÄÍÍ­¥¥%??ßËËËÊÊjÆŒ¡¡¡ñññÔU¤¿ ä˜Y&L®««kkk›={¶ÁÚB*%‹Á`<{ölýúõcƌٽ{·D"Ù´iõ勵¢TãiGGGcdà@}ñ¿ÿ>‹ÅZ¾|¹µµuhh¨@ Ð*ĦžŠBQ”ÐÏ‘#G0 [¹r%ŽMë¬ê‡zE988””””––ÙÙÙ¹¸¸|öÙgýª~ІÉÈÈÈÈȸßT½B%êêê.]¬ÙÛÛ»¹¹èÿgïÜÚ¸ÒÇ?ˆP-^¸„ˆ(ˆ¥ˆT+ µàжÊzYéê¶KUä&ˆõW«–‹Íª©¨¥R¶Þ­1€¸.¶V\A«VQð†Š\„1$„Ìe­óûã<;O¾IÈL.Ôùü¥ÃÉ9ï¼ï¹Ÿ3ï ÃÇçóù÷ïß7³³³³9tèÇÓj`¡PÈáp nœ………‚ˆÅâ{÷îÉåò;wîÈd2E322Èä™››Ëãñ´ê¤½½=--M/Á¼½½ÇŒ£Ç @A0 GFFÒét`,>Ÿ_PP *Øà* ‚ ôôt¥Réïï»nžSÌ)ƒª?< @dd$Š¢jA.É`°±[Xg¤¦¦‚'4-//¯ººš|Ó3^QjÌœ9S,_¼xÑÌÞÔt7…B±gÏ\QgÏžmjj"/¤ 5¸Ò ûÉœœ>Ÿïî>59½PC0L¸» PF1½ð':Ø»wï’%Klmmßzë- Ãd2x¾råÊ+W®`&š››qgEÝÝÝ]]]#FŒ0à•ŒáéÓ§عs'ÇÓü«ÍÛo¿­P( Î?!!aüøñcÆŒ‰¥ÓéÝÝÝñññr¹\ ñk%‰Ôê… IDAT† ößÿþWõ¹›››•••P(ÔK//¯M›6îzýÃ0Õ88]]]íííãÆÃ º¢ •G(‚z«é Ë 2¨¨ìííõí¿ 6aËZ²d Nÿý÷ߢúúúnÞ¼9wîÜ üþûïdÞÔ´Š‚ h×®]†mß¾ÝÌÞÔt7kkk†ñø‘}}}0 ¿ýöÛäó7¹¢ ÝŠrww ÌÈÈhjjÂ[Ÿj‚¡Ð?¨AvðÄGA.—ÓÛÛuìØ1°5 žèøy||¼———““SKK Çc2™ z'AÕðññqvv®­­%ÿ&& Ì»aÆ;v¼|ùRë,ÏÅņáÎÎNòR©QVVvîÜ9'''&“™‘‘áíí­T*/^¼ÈãñÈØ¯µµ•N§Ož<†áôôôÎÎÎÍ›7Óh´‰'BÔÒÒ¢W%0&ú„ZA(ŠâÿtEATUU…aØ7ß|cð;/ƒ&S§N…aØ€æj*ci¶,à6úÁƒx²ÆÆF À¨dò7­¢Ö¯_ïççÇår+++Í<<ènþ%%%ýë_ÝÜÜ`þè£fÏž]VVF^ȨQƒ‚nE-^¼˜N§õçju(ôÆ‚Ÿ¶5ª#!€Éd?xð ¢¢ÂÇLJüÄÙÂÂBó¤Aß­g>Ÿ¯¹ä D¤©©I(ŠD¢’’’¸¸8+++½r^¸p¡D"9þüèÑ£«««<<d³Ù‡Òëõ­­­—ËEQ4++«©©‰|ÆÚÚZ Ü]\\<<<òóó}}}a7nÜóçÏÁ_ 3Á—Îàœ¿¢¢Â€¥3“Éd±X 7\Õƒ®(‚þøãåË—ïÛ·oôèÑÛ·oðà‡ÃquuÕë팔pòäÉööö[·n}õÕW·nÝúôÓOÉ_r3•±t´,KKKµÈ!/^¼€ ÈÚÚš|þ&QA‰‰‰ööö‰‰‰j›ÿC„ .\¾|™Éd†††ZYYíß¿¿®®N¯%ˆ©5”'Ù±±±\.÷Ã?Œ2e ‡ÃÁ‡º¡Ð?XâÿU½,Jþâ¨î¡……ƒÁ˜={ö¾}ûd2™w LESBŠúßVÕ¥K— …§§'ù™ˆÒÓh´þÐô÷[±Xœ’’òÅ_…ÂiÓ¦)ŠÀÀÀýû÷“¿Ý€/ÃÃÃQuss3f霛›‹ HDD„ÚÏWQªbX[[¯^½úÒ¥K(ŠVTT0 ò?7RÕ[£àj®’˜ÊX:ZV^^žñ+B“+((¨³³3##ð+rûöíS;1ø,­ÍĈ¿ýö›\.ÿî»ï>ùä“»wï*Ф¤$½Š0‰¢ ãV„­¨3gÎ(•Êð†áÍ›7#²jÕ*\Ú!Ò?à½,FA‡¦?ÑÑÑQQQøµÂ3B’ôöövttH¥Òââb{{ûÐÐÐÌÌÌòòr’ yóæiê‚Ãá°X,S­ ñ|À݇òòrÿ÷ß¿®®Ždªñðô• ðööv‡±cÇVWW×ÔÔ‚?þ˜Á`tttÌD­t°’ÖK œ´´´ùóç>|øäÉ“jï2¸ŠRãùóç§NÊÉÉÙ±cǦM›¢££“““Ifh€† ;º0•±t´,¹\nmm=jÔ(¹\;88@$•JÉço¼¢FŒñí·ß*Š;vÖ™|ýõ×qqqªOLÍtݺuþþþ©©©{öìéíí-,,ÌÉÉY¿~ýõëׯ_¿NÒ¾&©QF2ЊzöìY__ß¹sçÀ›bVZZ AÐ»ï¾ ¢“BC¦ÀÑãÖ¨ê$ÀšörP ŸÏ‡aØÝݽ¼¼œÌ¯ú› hh_0åyöìÙ寉X,¶µµ0aB^^^___IIÉŒ3,,,Äb±ÙdÄÅÅEFFž={–ÍfVó+JÐfΜ9³qãÆñãÇŠ C­-ëñãÇy{{€NjÒ¤I0 ƒ ®f“íÿø‡»»;‹Å‰D†å0ÐA¼§OŸŽaØáÇÁ\D©T;vlöìÙúÓŸpÇ ¯­(@ð››~u…ðþÿàö^·F{UP{h¼šÛ»žžž‘¿8j†3B[[[µ'ÞÞÞ]]]wïÞ5[3‰DŽŽŽ®®®×®]Ã0¬°°ÐÓÓÓÁÁ¡­­M_ªªªRSS1@Œ‹UTT´aÃÍ5ÊPP”&à2‘¾™  6a˺pá‹/ñyd@@€T*Ì8©ÉâããyïÞ=.—;d£ºwuuÑh4üɘ1c`&¿ó†pþüùžžžÕ«Wã5 x())5jhöf¥¿3Â7n$%%Íš5ËÎÎÎ××7==Aò—QMŽÖ½ïäää#GŽØÙÙÍœ9óèÑ£‚l߾ݜ™;vìÉdàPgäÈ‘"‘Að…^Y|#þüùB¡°°°°¿Óé¡ ¨´´´„„„9sæŒ;vÒ¤IkÖ¬©­­­¬¬d2™f“Aõƒz#³2ØX„- †á#GŽ…•+W2Œ-[¶(Š„„sëâÅ‹‰dæÌ™CÄ÷¦Öæ?{öl±Xœ——÷á‡:::._¾¼ªªêÑ£GƒrÛe(ß…axÿþýmmmÑÑÑŽŽŽaaaÍÍÍ—.]ÂÏ¡‡Bÿ0Èô7nÛ¶­¸¸X Èår‘HT\\Ìb±ÌìWB­^ºtéåË—Çp‘HtóæÍèèh3 ¢(øj<¹xñ¢R©pßB*œ:uJ©T*•JµO6Ùl6¨ÊCAQ‡ª©©‘H$ …¢£££ªªêèÑ£à›9³aÂÐ`È´¬áǧ¦¦644Èd²ªª*37½©S§*Š®®.A†‚ M¨ÿþ}Á‚yyyÀ)kMM ‡Ã1sÂÊ!A4m×®]<O&“ñù|‡ãèèˆÿu(ôj˜[‰@eš»©ànTp˜1ˆ›$ZåÄgå@ÎAÜ•R=(×¥z{{Ͷ«Ðß-üìa((Jk2À¿Œ‘2Ðh4sšF« dZžÌüÆUZëŸTë¹9鯛R­ØƒR£p†BÕ‚úW¤³F …þ‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚bÀa0ÙÙÙà ’ÖÖÖãÇ¿AQêCrr²\.ô>CAQCA†W‚¡ ¨¡ ÅPÃ܃ÐÖ­[ƒ‚‚’““§M›£ÕGŸ‹‹K}}½B¡0§Sáîîž““ÓÜÜÜÞÞ^ZZeØH×àóù'OžÔúUVQQѵk×ÌüyrTTÔ“'Oòòò4˽s玚 ü7 +Ãåíí-“É4Ã8ö·a2@ôý÷ßËårP®T*mhh8{öìG}dæ>ú“O>ÉÏÏonnnkk»ÿþš5kÔ acc“žž>$///7ÌRŠ‚ èƒ>8yòdMMMGGG[[[}}ýåË—§OŸ®¯® –Ïçk­0—/_,Xƒ—Ëñèq«k>!äöíÛ œ“êw¾ªœ¿  7X=§¦¦‚'4-//|üKÈŠJOOW*•þþþ¸GàZ…ükš°ÂfΜ)‹/^¼8¸¾Á(L‚a˜p8x/¢OàOt°wïÞ%K–ØÚÚ¾õÖ[†Éd2ð|åÊ•W®\ÁwG¶oß^\\l@,…¡ÀôéÓûúúòóó®À¿çÍ›·dÉ’sçΑy£„„„ñãÇ3&66–N§wwwÇÇÇËår@@æç"‘( `ذaj¾ÝÜܬ¬¬ô ¼àååµiÓ¦ÌÌL…B¡×!zúôévîÜÉãñ4ÿjccóöÛo-Ž‘Š2 ¦•8šÁìííõ• 6†aYYY¸À]]]íííãÆÃ,Y²„N§ÿþûïx­¾yóæÜ¹s,Xðûï¿›¡VCÿ‹ã# 863y…Ùµk†aÛ·o×t0–œœ~ðàÁ={öPžÃ^ ôÃþÁår ÃïåååääÔÒÒÂãñ˜L¦ƒƒƒƒƒƒê(AÐÎ;mmm·nÝj@¸áÜÜ\µ3'@JJŠÙ6.h4ZOOÏ‹/ð'‰Ã0ò‘—ËÊÊÎ;çääÄd2322¼½½•JåÅ‹ñÈ^ºimm¥Óé“'O†a8==½³³D¥˜8q"A---zµyƒ#@´aÆ;v¼|ùRë|ÙÅņáÎÎNÃ2‡ŒV”I¦N ð½³1ÆR+ËÁÁEQü¿À¯ôƒðd†QÉäo¼¢ªªª0 ûæ›o ~GÓkýúõ~~~\.·²²Róç4M¯=vŠWüDF£ág„ÙÙÙ$­Þ_ô ‚-Z$“ɶmÛfaaqðàA}·F-,,47ñõ=y2’¤¤$Eð<ùá‡È‹±páB‰DrþüùÑ£GWWW744xxxìq‚ƒƒQ †aøÎ;ÍÍÍ NEXXŠ¢ ù× EQÔÅÅ…üO4ÑêŸ>00A¦¦&¡P(‰JJJââ⬬¬ôÊÙE©bŒ##eÀ·F‡ æáá±nݺúúúšštncA´bÅ EÓÓÓñ›ŸŸ.˜àiüýýùñÇÍS«!²²²*((@Q´´´4!!aìØ±z½”IdÀqqqihh(++>|¸Ö` ¤_!ô3•êr°¯¯oíÚµÑÑÑÑÑÑÆ{ˆ1bÛ‘’’ÒÛÛk@í4C`^B222 Åž={\]]Y,VHHF{þü9ùL¬­­—ËEQ4++«©©‰|À³ÚÚZ Ü]\\<<<òóó}}}a7nÜóçÏÁ_ 3Á×Ö¤Ñh&_[WVV;vŒÍfûùù?|øÍf:tH¯üQ”©0‰ 'Ožloo¿uëÖW_}uëÖ­O?ý”üFÓ‹Éd²X,Þp,--Õb/ƒ=ò'ßÑŠúã?–/_¾o߾ѣGoß¾ýÁƒÇÕÕ•|ÆË€“˜˜hooŸ˜˜¨vÓ××g枇Â|€Û1ZŸ¿"LNNîèèøÓŸþ†ÀC‡ Êe™}ûö©í¯ÆÄÄïP`ž;wî•+WZZZ$ɵk×¶mÛ†¢è¦M›ôÊߦÑhzíÃ0,‹SRR¾øâ ¡P8mÚ4…B¸ÿ~ò·ðµuxx8Š¢nnnƬ­uD,ïöô.]º¤P(Èï!CÆ)JcV„FÊ zkl¦áj!‰i•››‹ HDD„êÏóòòŒ_šÄX4ÍÚÚzõêÕ—.]BQ´¢¢‚Á`ÿ¹Id êììÌÈÈ v>_'È^–£ ‡ÃK ° är¹ >EEE³(ô÷÷ŒŒÌÌÌ,..6øp%77wÞ¼yš5›Ãá°X,’³³¯¿þ:..Nõ c †Ý¼yóöíÛxœ­-[¶@¤×9„j 6}'•†µ··;88Œ;¶ººº¦¦F |üñÇ £££ƒd&j¥ƒ¥¶^b5pñ¡¼¼Üßßÿý÷߯««#™ƒ1Š2&‘hذšoBc¥¥¥ÍŸ?ÿðáÃ'OžT}¹\nmm=jÔ(¹\ž888@$•JÉgnEõõõ=þüÔ©S999;vìØ´iStttrr2É —aĈß~û­B¡Ø±cÇ J¤ ô¸5ª:Æ€J€?4²N,[¶ÌÚÚú‹/¾ˆ‰‰OÀd­®®N.—{xxiÛýÍèõÉôJ¬µP¢3fÌhoo/,,4Û ±Xlkk;a„¼¼¼¾¾¾’’’3fXXXˆÅbó``~ýìÙ³Áä %...22òìÙ³l6[­9?~ü‚ ooï‚‚P'MšÃ0¸àj~QA;sæÌÆÇo΢ÿñ¸»»³X,‘HdÎr)=nöª öÐH!X,–Ãÿø×¿þ…a˜——ÉQg„jÌ;wΜ9gÏž5§ "‘ÈÑÑÑÕÕõÚµk†zzz:88ðEJUUUjj*‚ &ÒÖÖV퉷·wWW×Ý»w_ÅÏf†Æ+$$„ÅbmذA³¹]¸páÅ‹øD3 @*•‚ f¬Ü†n~éûE1øøøDFFÞ»wËåRçF¡ãÖ¨*ƒuFh<Ë–-›0a¤I“6nÜØØØxíڵѣG›S€;vÈd²ÆÆFp¨3räH‘H„ øŽB¯¬Œ¹‘£õŒ099ùÈ‘#vvv3gÎ[&ÉíÛ·7lØ™™9jÔ¨?þøƒÏçÇÇÇgeeQmƒ1ØXkÖ¬5j”Occ£êó½{÷&%%õõõa×Ýݽk×®ˆÅâ~ø!--ÍœÆ6lXdd$øÆ¦§§§½½½¨¨èÇ”H$æ`êÔ©þþþ–––W¯^UÓ³T*õôôTÝóòòR*•ùùùÔö…v€K6ÂdàC3Ècrð[|à ù^4U• D¬É©V‹ƒû{ƒ®+¨lƒ¢ŸA,‡ä¸àZÜ` /]µÂ˜SoªÎiÕP«Þnnnø×,f‚‚‚‚‚b¨.•J½¼¼¨}Q Š7‘¡°Ê§                            J0Œììl>Ÿ/“ÉZ[[?þZ^2NNN–Ëåƒòöb(èa(ÈðJ`EA‹bP0÷ ´uëÖ   äääiÓ¦ÅÄÄܸqÿæôÎ;j‘6nÜhÎaòûï¿—Ëå h©TÚÐÐpöìÙ>úÈ€6 ¼õ“¦àóù'OžÔúeQQѵk×Ìæðþ“O>ÉÏÏonnnkk»ÿþš5k 3„azðöö–Édš1– E}}½¾J0L‚ø|¾V._¾lþÈQQQOž<ÉËËë¯h„¬¨ÒÒR¼åJ¥Ò¦¦¦ëׯk­3„Eô—€Á`ìÙ³§¤¤D"‘…Âââb½ÂÂPP˜<¯j3ÓúP7·oß®¨¨áœ`VcjkkÏž=kee5(1u¡ÿçÝwßŽŽ®««‰D~~~$Ǩ¨¨;;»+V bkkëââ²nݺåË—“Éáþýûׯ_תÌÚÚÚÓ§O›§ÿ]¾|¹\.ÿå—_<<<¸\®B¡ %?!0Rª/ïÞ½EÑÏ?ÿTd Òüt:%%EѨ¨(3×̤¤$0Òh hE&ŒWÔÇ«««AËe2™ .¼zõªB¡ˆˆˆ9A˜àرcÍÍÍl6{òäÉS¦L9qâ‚ ±±±ÔXHaV233étº……—Ë- fþAð‡„ðx¼þ| …B‡3ˆ5[Õñ#ð܉¢èHJUXXˆ ˆX,¾wïž\.¿sçŽL&CQ4##ƒL¹¹¹<O«rÚÛÛÓÒÒôRŽ··wbbâ˜1cÈÿÃpdd$Nz°±±áóùä{X#õ ŠÁŽ@M(`æÌ™b±øâÅ‹föy” È¡C‡x<žÖqŽ0nŒWñraöóóC$''<$,‚0Áĉ}}}AP†‡Îçóïß¿O¤0 d›tTTp-ˆ· ¢O¨>ì½{÷.Y²ÄÖÖö­·ÞÂ0L&“ç+W®¼rå †a666o¿ý¶B¡0ð=L ðÜÍØÛÛ“ì…Æ?fÌ˜ØØX:ÞÝÝ/—˯ƒ"‘( `ذaj‘¯ÝÜܬ¬¬ôu´ïååµiÓ¦ÌÌL}µŠaXVV.pWWW{{û¸qãÈç`¤L‚Éeصk†aÛ·o7s º§OŸ8p`çÎ<ϰº1¹¢0 ÂÓ§OA„E&ÍÍ͸<ÝÝÝ]]]#FŒÐ,=999<<üàÁƒ{öì¡\×RD0L`#4&&Æ€Ž >>ÞËËËÉÉ©¥¥…Çã1™Ln Œ‚¹¸¸À0ÜÙÙ©oÎ8¹¹¹jGŒ€””ƒW™S§N…a˜|PVVvîÜ9'''&“™‘‘áíí­T*/^¼H20okk+NŸ>>š À@HRè…Õl„P «¬¬tèùâL˜÷äÉ“ííí·nÝúꫯnݺõé§ŸêuÎÚÚZ p¹\E³²²šššú ó¦Imm-†aÎÎÎ...ùùù¾¾¾0 7îùóç௄™à+càÿ¾¢¢Â˜•1“Éd±X 7½4iŒL…©dHLL´··OLLTÛ²~m0^Q­­­`›ÇÃÃ#$$ÄÚÚú×_]°`>PAF†úúúºº:‡ÓÝÝÍf³=z¤Ù"úúú77ÅëŒæBд+B‚ð¸*`OïÒ¥K …ÂÓÓÓl_©Þ58Ô 0~ÖÐäs€aX,§¤¤|ñÅB¡pÚ´i …"00pÿþýª—tƒ¯ŒÃÃÃQuss3æ nnn.‚ õ5Xª³"4‰ AAA†í¶íÛ·OmÇÞà{ÿ·"4RQš—eÜÝÝÅbqQQ‘êCÝE‘Á‚Á`Ìž={ß¾}2™Œü-6 Ý=T Ñh\.Ã0üŒ0** ¿äiØÁ¡ø$\T)//÷÷÷ÿý÷ëêêÈü<77wÞ¼yš‡Ãá°X,ò3D°²4øÃ0\úNK1 koowpp;vluuuMM@ øøã FGGÉLÔJ¯£—8iiióçÏ?|øðÉ“' xƒõ`*Œ—aĈß~û­B¡Ø±c‡a5üë¯¿Ž‹‹S}Ò××7ÔÖ+¦5†aB¡Puo“°22ôöövttH¥Òââb{{ûÐÐÐÌÌL<5…ÁèqkÔiÕʺvíZµ‡&Ì%Ÿ={F2}‹†!Øïè@,ÛÚÚN˜0!//¯¯¯¯¤¤dÆŒb±ØÌ’ÄÅÅEFFž={–Íf›ùžäÐáÿø‡»»;‹Å‰D†åðjU?SaØÀÔ‰2ŸÏKÏòòò(…âB[£½½½j¢Ö‡†akk«öÄÛÛ»««ëîÝ»$§{¦:#\Ží„» IDATD"‘£££««ëµk×0 +,,ôôôtpphkkÓwÚ[UU•ššŠ ˆb„„„°X¬¢¢¢ 6¼ |Õñññ‰ŒŒ¼wï—Ë}µjÑ ãáááìì\WWgªµšæy¡§§'AZ/ŽRPèËPÙaß²eË‘#GìììfΜyôèÑ>øàèÑ£CçËBó  ßyç¹\^\\ŒaØo¿ýÃðøñã X‘TTT|÷Ýwz}ö˜?~rr2Ç[³fMww·¾?mؽ{·……›Í~c§`cc³`Á‚Ÿ~úÉÒÒòÀ¦š@üúë¯III³fͲ³³óõõMOO üõ×_5¿ñ8}útgg'¸zm’¢)ÞÌê#C·oßÞ°aCffæ¨Q£þøã>ŸŸ••õ¦ÍÄ[ZZèt:~ì¡T*=z4gÎ}?"„þ·ƒd€ kÖ¬5j”Occ£êó½{÷&%%½!™:uª¿¿¿¥¥åÕ«WÕÔ(•J===ߨíb­L˜0÷’ñßÿþ·¾¾>&&&77×T+Âk×®-]ºtÕªU#GŽ|þüykkkrrò?þ¨i///¥R™ŸŸOR ]€K6ÍçàÎ~ãÜØ4³là ¤ÁH7›ª*:1§TÆ‘iBË(ªþNÕ¬µûk;ä šÆàKÂý毵6º¹¹á™°t ŠWƒððp©TêååEí‹RPPPP¼‰ …M Šÿ ƒÁÈÎÎæóù2™¬µµõøñãoæEçääd¹\n˜/é7 3(в`(¨š²Å `îAhëÖ­AAAÉÉÉÓ¦M‹‰‰¹qã†êw¯L&3--­¼¼\,wttìÞ½ÛÌä»»{NNNsss{{{iiiTT”š„ HÒÞÞnii©W€'‚ø|þÉ“'µ~+VTTtíÚ53FõäÉ“¼¼¼þÊ%L@HŠ*--Å£:H¥Ò¦¦¦ëׯ¯Y³Æsf À|pòäÉšššŽŽŽ¶¶¶úúúË—/OŸ>Ýlý8ƒÁسgOII‰D" …ÅÅÅG·0XämAX„ŽŸ|òI~~~sss[[Ûýû÷ ³5…VÈz–ár¹ ÚEGGošOÈ0cÆŒÖÖÖ¬¬¬žžàHÝÜÜ~ùå ‹ƒØØØL˜0Áœî!ìììrrr† öÕW_UTT¬]»ö‡~a7€;„DEE=þüòåËb±ð††† &,Z´¨££ã?ÿùáËÊd²qãÆiýƒÁ¨¨¨Ð÷•!))iýúõÀ‚a t@¨( ‹¶¶6__ßÞÞ^{{û÷ß?>>>55µ¯¯ïĉdª‘¶€ È××÷Ì™3­­­qqq>?~üŒ3|||ªªªÌVo¿ûî»?ÿùÏ\.÷Ì™34í›o¾IIIyûí·ÓÓÓÍS'!"´a„ –/_~üøñ‚‚‚°°°ööö-[¶¤¦¦öôôüë_ÿ¢<ÈP˜ÌÌL:®¡øz ‰Àãñú‹G˜““ÃçóÝÝÝÁø ð™·GbccùüóÏ4íüùó?¶¶¶&™€ÂÂBAÄbñ½{÷ärù;wd2Š¢d¦·¹¹¹<O«öÚÛÛÓÒÒÌ6GÎÎÎFäСC<Ok <º!T”f '÷îÝ»dÉ[[Û·Þz Ã0Ü-áÊ•+¯\¹‚a˜»»{```FFFSSÈÙü½éÓ§÷õõåççÀ¿çÍ›·dÉ’sçÎaF˜€°ˆ„„„ñãÇ3&66–N§wwwÇÇÇËår@@æç"‘( `ذaj¡ÒÝÜܬ¬¬„B¡¡¯®7OŸ>=pàÀÎ;y<ža t£¯¢0 5óéÓ§$kŽ‘¶€ hĈ …B¼Æ\i½¼¼6mÚ”™™©¯—y@ÐÜÜŒ—ÛÝÝÝÕÕ#‰ñzPCÓ„E&À0,++ —§«««½½]ëîHrrrxxøÁƒ÷ìÙó†øÅ¥0=Â0q¹ÜÌÌLÃbðÆÇÇ{yy999µ´´ðx<&“éàààààFA‚/^L§Ó‹ŠŠ ®»¹¹¹j¡À)))$'¶4­§§çÅ‹ø‰D‚a˜§§'8[wBÊÊÊÎ;çääÄd2322¼½½•JåÅ‹5èk¥µµ•N§Ož<†áôôôÎÎÎÍ›7Óh´‰'Bd€cnƒÙ°aÃŽ;^¾|ii©}.E˜@7z)jÔ¨Ql6[*•þôÓO$•`¤- [ ß|óñ q°š4ì·ªÒúøø8;;ëœÈx=¨¢Õ„E‘AM­‘U€sj¥H1P€½P|k ïÖhuuµÖ­Ñƒ*•ÊÈÈÈââb‰DÒÚÚzîܹ©S§’ß5ÞUtRRŠ¢x¡à 8$“€ .”H$çÏŸ=ztuuuCCƒj oÝ£( BÌܹs§¹¹ùÌ™3aaa(ŠN›6Íüwíø|¾îOÂý¡[Q>T*•øtAË—/{{{ë5œc ‚¬¬¬ P---MHH;v¬¾ïˆŠ¢¨‹‹‹Á90™ÌàààTTTøøøèUŒÔ[¡— +V¬@Q4==]ÓÜ` ¤îÑPè…Õ„á NGbcc¹\î‡~;eʇceeE2ãófdd(Š={ö¸ºº²X¬öüùs’ È`mm-¸\.Š¢YYYMMMšAGû£¶¶Ã0gggüü|___†Ç÷üùsðWò’ qÕÚÚ ¶<<þøcƒÑÑÑA>Ÿ¯¿þ:..NõI__ßP›Dë¥( Ã…B¡^{zÆØ§¯¯ïùóç§NÊÉÉÙ±cǦM›¢££“““Éd¨V:ØÕ0@†ÞÞÞŽŽ©TZ\\loo𙙉‡w&Ä$zPÍMÓ„E”!--mþüù‡>yòäP«±¯.zÜuZmÄo“‰@ €aØÍÍ TôºùAPÞ(ôêâU[#A3fÌhoo/,,T=±×` ‹Å¶¶¶&LÈËËëëë+))™1c†……ø(“$CpØ3 ÃñpTŒ3gÎlܸqüøñƒ%†a|>¬ÉÊËËE hÀlyöìY6›=ÓqŠ7=nöööjV>Sõ§çÏŸïééY½z5>˜ùùùÁ0\RRBrŒ1þŒP¹sçΙ3çìÙ³ýå@˜` ‰DŽŽŽ®®®×®]Ã0¬°°ÐÓÓÓÁÁ¡­­íu: 4gg纺ºAÔ¸¯dÀw,UUU©©©‚èûC̓4OOO‚ôº8jrÂ!!!,«¨¨hÆ †­›)(† ýÂ0¼ÿþ¶¶¶èèhGGǰ°°æææK—.vùÞ`–-[6a„I“&mܸ±±±ñÚµk£GÖ+Á@³cÇ™LÖØØ43räH‘H„ øŽÂœ’îŒP7ªçR666 ,(,,ììì4§›Ê´´´„„„9sæŒ;vÒ¤IkÖ¬©­­­¬¬d2™úfeðç7nÜHJJš5k–¯¯ozz:‚ jW»3ØbþüùB¡°°°ðÏéÓ§;;;ÁÍj“MAazú!¢Ñh»víâñx2™ŒÏçs8GGG3‹÷ïÿ[&“‰ÅâÒÒÒ;wÚØØè›` ‰ˆˆ@Q|5ž\¼xQ©T._¾|PZþ „ªWöÛÚÚ ?ûì3sÎ:TSS#‘H EGGGUUÕÑ£Gßyç³ AжmÛŠ‹‹\.‰DÅÅÅ,ËÌÓG3ØâÔ©SJ¥Rµ›ÍV+¥ªªª¹¹ù­·Þ2UѦÇÂÂBGŸn‹ïae}ƒßâëO Ãjß ‘kþ«Û d\®Ú£†Ýù4¼ºªV‰¡ ƒ9€Ìb ’_ »¹¹áߢ˜°t ŠWƒððp©TêååEí‹RPPPP¼‰·2Ô(HAAAAAAAAAAAAAAAAAAAAAAAAAAAA1”`0ÙÙÙ|>_&“µ¶¶?~œºè<@$''ËåòýÀœ°3Èð†@i’‚bà0÷ ´uëÖ   äääiÓ¦ÅÄÄܸq8a®(4Ãê:tÈü#eTTÔ“'Oòòò4?€³±±IOOohhèèè(//߸q£šxfH@’öövKKËÖÖV}XZZŠÛB*•655]¿~}Íš5šb¡#Á'Ÿ|’ŸŸßÜÜÜÖÖvÿþ}­ù›&“™––V^^.‹;::vïÞ­&†î¯“52æÖ¡jÂþÁ`ìÙ³§¤¤D"‘…ÂââbƒªPPô O¯tIëCÝܾ}»¢¢‚N§CÃ0>½Õü`öË/¿DQ4$$ÄÌSत$Ðä´úCár¹Ož< srrÚºu«\._·nj{3CÝDEE…„„ØÙÙ­X±A[[[—uëÖ‘w=ŸïîîŽK¥66èNðzX“<«šŒ¹ m¡†Zÿ0qâD___àцááÇóùüû÷ï›Óç*Å«‹3ÓžžÕõk×®OÈ„­ß»wo]]]GGÇ„ Þ{ï=™Lv6-Z¤µºÏž={úôé.\0s´ §OŸ8p`Ó¦MZà%K–ÐéôßÿHÕ××wóæÍñãÇ㑸̀„„„5kÖlß¾ÝÆÆ†N§wwwÇÇǯ^½zïÞ½†…À0 Ø÷éÓ§ Â"`–••ÕÓÓ"uuuµ··7Îñ¼¼¼6mÚ4räH}èîîxöìÙ¦¦& m ù¯‡5Éc°ª ÍM¨j54û@ððáÃÞÞ^ðÃîîî®®.­¡Ü’““Åbñ¶mÛ¨Å"Ža˜ÀF(˜¯‚\.—0Zo||¼———““SKK Çc2™W®\ÑZÝ###ûúú²²²È·ÕÜÜ\­§)))äkü† vìØñòåK­!ð§üàÁ\ªÆÆF æN ú53$ ¤¬¬ìܹsNNNL&3##ÃÛÛ[©T^¼xQ¯èÁ8£F `³ÙR©ô§Ÿ~9AF5aPÕW<Ȉ¸ ‹/¦ÓéEEEýM¶¼Ö$Áª†ˆÌM¨j5´öªÿöññqvvÖ‹ xŸ¡VŠªèQ­×®]}ôèQµ:D£Ñ«/g¢ˆa† ÔÚ ÆÂ… ïÞ½[__O¾­þýïg0 OË©#±½½ýóçÏUƒÆ¸ðxØ3$ ð?ÿùÏ_~ùåíÛ·%É?üàîîNòç€ &€U{sss^^AÁÁÁ>Ä×sº‹ÐW†+V0Œââbs†|÷Ýwaf0wïÞ•H$­­­çÎS¢¼Ö4?šæ&Tµ*ºû&“ÌápD"Ñž={4›3‹Å;vìwß}÷úŦ¦0=B0˜©M É,õ%""bäÈ‘?ÿü³^Ùš<0¯&–––jA_¼xAµµµÙÁÚÚZ p¹\E³²²ššš£¸©ÑÚÚ Ví!!!ÖÖÖ¿þú«ê†aäe`2™,  o,|„¨¨¨ÐwœuÅÆÆr¹Ü?ü066vÊ”)ÇÊÊŠd‚ׯšº1^Õªh57¡ªUÑÑ?Ô×××ÕÕq8œîîn6›ýèÑ#Í‘²¯¯Ï´ÝÅ~FõŽ(¸/£W>:ââ”””˜ÿšŒZ£èååå[ìøA~üñGÐ#˜!`Æãà€0=zÝÔ¼^áîî.‹‹ŠŠTê.‚¼ ¹¹¹‚DDDèÕ«â×ÃÃÃQussÓ—GgΜQ*•!!!à¥`Þ¼y3‚ «V­¢&xm¬©ãU­ŠVsªZýƒ……ƒÁ˜={ö¾}ûd2Ù¨ƒ@ 2lh4—ËÅ0 _ÿQÃá€9Wtt´IÖ…AAAîîîGß)[nnî¼yó4› ‡ÃÑkwTr¹ÜÚÚzÔ¨Qr¹|øäÉ“z‰ª–9¾ñNžgÏžõõõ;wd…aXii)ô¿m: ü6ÖÔñªÆéÏÜ„ªÆSêîz{{;::¤Riqq±½½}hhhfffyyù`mS¼*£¢¢@³Á[ÅÚµkU’©vGCBBz{{õº&èÏé†îc?½xüø1AÞÞÞ@¼I“&Á0\SSþk†ƒ†a¯työìY6›mÚÝu2†ÝÜÜð‹'j— PÖÔ æ&T5™þ\åóù`ù[^^nÚ¡xýÐãÖ(øRBó‰Úscpssûè£ô½&0Ãá… ^¼xˆ¸R©ôÚµk@Z3$<<<œëêêL(CHH‹Å***Ú°aƒÁ+ ‚ªªªRSSU/¤äüùó===«W¯ÆUíççÃpII xMÂoš5 V5DdnBUtôšç¦žžži½8JA1Èè>#üî»ïÅ›Œ&ZÏa>räˆP(\¹r%ƒÁزe‹B¡HHHÀ'×fH`TO•lll,X\™ÐÑåüùó…Baaa¡¾÷>41øN? Ãû÷ïokk‹ŽŽvtt knn¾té~øD&ÁeMƒUMhnBUtô7nÜHJJš5k–¯¯ozz:‚ Z}œ>}º³³388xÐ;Š7!Nçñxƒ~M u „ høðá©©© 2™¬ªªŠÅb©Ik†ÍÇ•J%þ!f[[[aaágŸ}fÂîûÔ©SJ¥Rµ›Í6ç A£ÑvíÚÅãñd2ŸÏçp8ŽŽŽz% ¬I2æ&TµîþaÛ¶mÅÅÅ@.—‹D¢âââþT]UUÕÜÜüÖ[o Ä›R¼¢˜{N†–þ¶RuÿÕœè„F£7Nà(BsëÕ Í{‰@îæõwõÑ„º$¡¬9(2ÔÌM¨(2­ü·¿ÜÜÜ¿  €ülÇÛÛ;11„<Õ‹‰'úúúo 0 >œÏçß¿—0—/_nhhxûí·U …B‡Ó_3óöö–Éd©©© O–——§ª|BUM¡¹Éc°-ÈÔ‡œœ>ŸïîîŽW!Ý«ZÃ1‰5³³³9tèÇÓ ­i†¦‚L'Fù^n€X¿~=Š¢ºB -à}¾Ô|¢ƒææf…B¡êoÿwbb"FÛ»wo]]]GGGWW—ªOÂE‹i5ÕìÙ³;;; ‹‘m0j=#A¼CŸ9sæßþö·¨¨(§T*¯^½ôÞ{ï· LAÚûÞ½{·®®Î€6³zõj…BáââbÀ›ªÉðèÑ#µ'L€óÁtvvª…¢µ±±Ñâ|Û¶m(Š.\¸/(>>^í‰nȨZ7„æ& m¡VÜÝÝe2YJJ É¢µáiM‚>¼{÷nKKËÇk„„Ö4Cœääd±X¼mÛ6}H؉æ@¦—;þü… œ³³³A{{{EEE@@H`ccÃb±nܸÑÔÔ$•J³³³'L˜ VЊ+®\¹ÒÒÒ¶ô¯^½ ¢y@täÈ‘êêjAºººÁeP¥=z´¥¥E&“)úñÿÎ;ïœ8q¢±±Q*•ÖÔÔüóŸÿ´±±Áÿš]ZZQ\\,‘HZZZ~ÿýwüîîîYYY?îèèwïÞ%o@––9r¤³³“ÅbÿþòË/7oÞÕÒÄ‹%°ª’^óI€=‰D²yóæaÆ͚5 AÅ‹Óétð ô¶¥¥euuuqq1¾cÖ_Ÿuüøq™L6eÊò3šÜÜ\­‡%äGSÕžqÔ¨Q`v\¶lÙ¤I“bbbZZZrssqN:¥P(Z[[7mÚ4iÒ¤… VVVÖÖÖÚÚÚª¾EUUÕâÅ‹œœ–,Y’žžNR7oÞÄÏ¡oݺ%‘Hþýïƒÿ–——gffÒh4U!M¼êTÝÕ|¢ƒiÓ¦!²téR†CBB;v¬f2Ýqš C(æååé5$Nî IDATÔk–h=šÒš#A._¾ìíí­šÃÂ… %ÉùóçG]]]ÝÐР œ0*+V¬@Q”|QÅøÎ—Éd?xð ¢¢ÂÇÇGSHÂÀRgΜQ³T`` ‚ MMMB¡P$•””ÄÅÅ©ËçççƒK.øA4×":ÐKÕš17IL5jÖ‡ƒ*•ÊÈÈH0ûnmm=wîÜÔ©Sµ¾¦î†c°5UÑ:ZÓ p@/oØNÉNŒ½Ü… P¡3ÀdN-™……>Ÿ£Ñh¿ýö[SSþâãÇ7ž† †ÏÎ5 JJJ"Ü]µj•Öpß¾}(Š1h4Z||<‚ ‘‘‘ %6òý÷ßã¯ðõ×_£(ºråJPœƒƒCggç‘#G€`@Bò9~üxee¥………D"ùùçŸËÊÊ,,,F%“ÉÀÔGUH2yêQ@$^Õ|5ŸèÌ"=z„aØÄ‰;;;;::È—®JDDÄÈ‘#þùg½âT˜$rokk+“Étppððð ±¶¶þõ×_,X€×'kkk@ÀårQÍÊÊjjjR‹ÁF˜‡Éd²X,…BqðàAòBâ ߃Òh´ŠŠ }¾€úúúºº:‡ÓÝÝÍf³áôJAPTTÔÈ‘#Oœ8¡f©ÊÊÊcÇŽ±Ùl??¿ààà‡²ÙlÕ À–––já[_¼xAµµ5ùW ¯êþ 4·nLe €Öúv´bcc¹\î‡~;eʇ£õ²ŸŽ†cŒ5 !´¦àôõõ¯Û„˜`þ÷¿ÿýòåKCCMÛ½½½xð¾¾>±Xloo?bÄð×%K–Œ9òüùóàçiæ`$sæÌinn¾{÷.£¯¯/;;‚ µaõâÅ‹½½½à†a... T*mkk[¼xñÿûÿÏÆÆHHÞ"<oܸq£G°°°ÈËË›8q¢ƒƒÃ¬Y³,--~ü‚ ooo¼6Oš4 †áššózŒ3@æ&DG}0 »¹¹áŠÂwÉÔ ÓpLeM5­i†FbÚNÌ`ÂÃÃi4ÚªU«Ž?^RR"‰FŽ©š@(B4~üxÝÀ1:‘H$jG cäÈ‘"‘ˆ|&`’ú¯ýkÙ²eK—.×SI]/^¼hiiquu}çw*++1 {üøñäÉ“]]]ëëëÁ«i ©²MªÚ[óIôööÂ0œ?¾§§gõêÕ¸¢ÀEù’’U!u4ã­I¡5ÍÀHL؉ƒ¥¥eWWWKK 8Ÿc2™j£.]ºÔÝݤ{P‹ZµAIRXXèââ2{öl¼àœáêÕ«úª ‡÷îÝ«¬¬´µµ%¿†{üø±««ëøñã‹‹‹1 «®®ž8qâ¸qãjjjúrH0sæLAþüç?Ã0-“É4»B€î3Âï¾ûÎÌÞdTQ=4²±±Y°`ð_eB?–óçÏ …………ú^ëМ½ðÃ7n$%%Íš5ËÎÎÎ××7==AÕ»Á„ Ú¿¿\.ïχSrrò‘#GìììfΜyôèQA¶oߎ Ãð‘#G„BáÊ•+ Æ–-[úû¤ià0¡¹ ¶a}€axÿþýmmmÑÑÑŽŽŽaaaÍÍÍ—.]R;dÒÑpŒ·¦*ZÏ ­i†8§OŸîìì Ö׈ä;1BtŸ>yò¤¿3½{÷¢(çèèøÑG]¹rE"‘¨ž‚O† Å©S§ÆÎÿô§?©¾ïôéÓ%I~~þ¤I“&Ož¬é'êÿŒÉd>|ø°¼¼<((h„ ÍÍÍ—/_Æ¿£g„ª¯ vFø×¿þ5///,,lüøñNNN‘‘‘"‘èüùóäô¾ùæ¡PøäÉPè¢E‹:::är9~‘MUÈ!4FFFJ¥ÒÑ£GC´wïÞGõ÷Î:ªNçñxƒrM vŸ¾­­­°°ð³Ï>3aï êj)6›m¶1`Û¶mÅÅÅ@.—‹D¢ââbp™›|‚Q£F555?¾?K-]ºôòåËÀé°H$ºyóftt´Zâáǧ¦¦644Èd²ªª*µ"Ì€ÌM™ú@£ÑvíÚÅãñd2ŸÏçp8ª÷ ¢†c¼5UÑ:B$¬i†€ªªªæææ·Þz‹ð]Ô ß‰bð@8ḟN}}ý‘#G¢¢¢PUýžF£EFF>yòD&“555]¾|yòäɪã Ãeeeíííb±¸´´æÓO?mhh‰D …|tßÖÖÆçóU«Ü¤I“Nœ8ÑÔÔ$“Éêêêöï߯:' §NzñâE>Ÿ/—Ë%IeeezzºZ¥ÕÍÂ… ÁÞ¾ýöÛ‰¤££Ü”Q’L½5ÓP ¾·;àº`û àÅ ûë@£y휩˜p³®¿›}}}}Ž ¤zý¼&ù‘¥ðÈDkªõ—`@1ƒ¹  V¥ÃÆ[Sß‚ 6·ñ ÜÜÜô?¿ øŸ²³³¿üòËœœœ¶¶¶“S7$ß‚ooïÄÄDU÷Nú2Њèú@AAñ G&àg]õ‡Ëå~ñÅdÖ‚ÍÍÍ …"88xêÔ©2™L¡P,Y²D&“%&&Òh´S§NÝ¿íÚµ÷ïßïèèhnnÎÎÎvrrÂsÈÎÎëüÉÒ¥Ke2îïÈ‘#ÕÕÕ{öì¡Ñh999 2¸B¡Pí¦ÝÝݳ²²?~ÜÑÑ!îÞ½»mÛ6½¥ÚÛÛ1 a©åryOOOKK Þ}ïÝ»·®®®££c„ ï½÷xS…B±hÑ"|kîéÓ§Ø´iÓ`yL%| òxyymÚ´I- Ì (2õáwÞ9qâDcc£T*­©©ùç?ÿicc£W)$kTrr²X,Ö·²QPP 9¸\nff¦êúĦ'¡æ–H$›7o6lجY³Y¼x1N]ÃéÓ§ EmmíªU«&NœÓÖÖöÛo¿á9:r!ÈA€æ¥K—ÒétP¨ª7oÞ¬ªªZ¼x±““Ó’%K²³³ÓÓÓõê›`Æ#Ò/ª2XZZVWW[YYT¨€ÇB¨÷ĺÉÍÍÅûtURRRô Ý®ã-ÈŠ¢¨‹‹‹¾?4ƒ¢냳³ó£G>|¸lÙ²I“&ÅÄÄ´´´äææêUÉ•’’"•J¿ýö[j ¤ ‚èÑ®]»†ácÇŽAòGƒ½|ùrÚ´iÖÖÖ===ï¼óA=R êkaaqàÀŸþ¹··÷øñãžžž‘‘‘‹/¾xñ"™Å Ø^S ®ö+‡÷Þ{ïçŸþý÷ß{{{Åbñ•+WôuöŠaîÂUÓ¶êAJMýé9º¿@zyåÖýfÀ Š"¬ 'N º}û6†a`äȑ۷o #~–|b±X[·nUSPP¢ÇüDâSZp4ÈápÀrP-z™V<==a~ôè†a'Nììì[sª\¿~ï¿®_¿AÐܹsMußO*•þöÞ<¬©k{ü>'€â€ŠDP@0Šm§úx{‹•Ö‚„«T‹µ¥¥Nü)”ÖéjÁ DE¨Ö±‡zAE JBæÐjäýc¿=ßÜ’“Ðõyúô‘svö^{\gk/‡ãïïkccƒn.ïs“)Ü ë 1+=xð …B)//×cVÚãÌ;·¡¡¡¨¨]Ì/—˳³³1 ó÷÷'ÙäÈ·(¹\næ:€4ÖS©T¡P¨úhÒ¤IB¡ðîÝ»„~EWįÐs ‹¢z©¿víÚŒ36lØðèÑ£   K—.EGG÷¡I f¤=B!f¥Ê }qÆ£®´tUc¯@‹€ìaTT#Ôg~QQQšGÀ°°0Ç‹‹‹ËÊÊÖ¯_/—Ëëëë8°oß>B•"h4Zee%R~ÎÎÎØßç1 C»‰ÖÖÖmmm(ððáÃÕ‡-Í»‰hñêØ±cÇŸ6mÚáÇãããét:¹2èeðõAC{hnn¶³³S~âàà0dȦ¦&âïë- ²Ÿ®Ä°ËWšÛÙى㸳³óãÇ;::|||lll*++‘=†rÈ… £ü‚ pÿý÷ßÑXÆáp ÅäÉ“‰3fÌPW ÈBnðàÁäAƒ×;w***ºÔ¦½™Þ°GHPYY¹{÷ndÚ;ÑÐnܸáêê:{öl¢ {m®^½ª«%IŸnQ˜‰©S§J¥ÒþóŸ8ޝY³F(>\9@^^žL&c±X«V­rqq‰ˆˆàp8—/_&K§NÊçó/_¾ìëëK£Ñ6oÞÜÔÔÔÚÚJ˜O |}}›››óóó=<<<==×­[G¼]ºtéùóçÃÂÂFíääÑÔÔtîÜ9S\ïRUUUTT¤9fý¬z8ޏ hxAðx‰DíäääççªITTÔÓ§OÏŸ?o:dxï½÷òóó8NII‰é:Cw2888$&&Þ½{·¹¹ùÉ“'ÅÅÅ111f–AWWךš‰DB¥RÍ,Ãÿû_±X¬Üæ?ùäS…ær R©{÷î-++ãr¹|>ÇŽæ”áÆ*…€øé§ŸÈ‹±k×.åž GÏÕ F~ø!Žã‹- …^^^¦HHo,,,,--?ùä™L¶fÍõÔ ÷@¦óÈ÷ßoÌ Óé™™™™™™Ê#{—»ƒÁ`Ü¿¿ÿþ–J˜¿’¾üòK™L¶|ùr+++½¸}ûvyy¹••†a8Ž«TÞÎ;Q·/((0"ìN†÷ß_$8qbÞ¼yãǧÓé‰dÕªU¦èÌÝÉ––ÖÐаmÛ6OOÏ7ÞxãÈ‘#R©tÓ¦M¦¨nÍu8zô¨P(lmm5‘"Ô ƒÁ8uê”r³7Q›× ƒ»»{iiiYYYTT”››Ûĉß}÷]s¶44+óñÇËd2> …‚~»cÇ™L¶dÉSdá_ÿú—@ °³³Ã0ì»ï¾«ªª²´ÔÁi«ÙX¿~½f=§5@o€Lç5777@@¦ÉÖ1…B‰‰‰‘Ëåiii111t:ÝÊÊ ¹ç%é}B¡PtttôWr¹¼££C¡Pè÷s[[[™L†ü«D’ýÞ{ïåää¼ýöۆ˩‡ gÏž6lرcÇ:::0 Û¸qãÛo¿½zõêãǽ仓!11ñ?ÿùÏÇÑ«uëÖÍ™3gùòåû÷ï7®d X¾|ù»ï¾ûÛo¿ùùù=u­2 |ÿþý C 0™Ì£Gº»»+×Ô¹sç.\¸0jÔ¨ìììúúzW^^>oÞloo'ƒ½½½··÷Ï?ÿ|åÊ•ÎÎN.—{ùòe…B¡,IYYƒÁ(,,ܼysrr2š„……ísÁ‚Š¿9pàÀ¢E‹fΜiÄÖ5{öì?þøçŸ–ËåOž<5jÔ¶mÛ"##øáBÔqãÆ:ujïÞ½ÕÕÕ·oß6âÊ™£¹´µ®«è:|4¡½@åï ôDå¡jkk©Tª½$µ †a]a6-Ø¡R© ‰äàÁƒæ/¨šššêêêôôôçÏŸoÛ¶íáÇæÜn4hÐwß}÷èÑ£äääÎÎÎ9øWQQ‘––¶mÛ¶™3g?xð`Û¶m:•4[[[ Ã6mÚD§Óg̘±iÓ¦7Þx#==½ÿþf“A™Õ«W2äçŸ6Ñ– ÚþׯµO˜0ÇqÔPÇŒ#‹ù|>ùŸ ‡ãïïkcc£P(:;;U$áp8r¹\,cÖØØ¨P(ÚÚÚ¬­­­­­QôÔSär9—Ë1b„·-ZôòåË3gÎëä÷ïßÇ0Ì××W¹à8~üøqteÄXDs9)j Û!étºáëZHù+Ñ&%%%ÅÍÍí›o¾a±XæO}„ ãÆ[¼xñƒ>¼ÿ~s*€mÛ¶¹¹¹mÙ²êx<^BBÂñãÇŸ>}ZTT[\\¼lÙ²ñãÇ›M1£ÃIII™™™ §NJMMõôôüàƒzäãàÃ?Ôõ˜ŒÙ@ʯ¹¹Ã0‡£k 7n;vì(//?tèŠvÁ0쯿þÂþ§Û¯ï IDAT>òâÅ âßÄ–S@@@nnîÇy<2ä0bÇqvv0`@SS±»töìY ‹*kkkÓ#ûFDk9h-jÐáÔ(NW(ÄhTTTzz:’ŒÌº¨œ>}úí·ßVÏjzzzBBÌ ÕÙ»wïÂ… SRRŽ=Ú#åÓÙÙÉçóAqqñˆ#V­Z•™™YVVf†pÖ¬Y™™™ÅÅÅ=;à%¾¬ËÊÊfÍšåããS]]mž={&—ËÏœ9ƒz¨B¡¸wïö÷’©™ gÉ’%4-==½·uØœœ …"0 CßýB¡°¶¶væÌ™$Ç·k׮͘1#$$$888(((00pûöíÊÍ@ÃÏÃÃÃüñG‹•’’R^^þôéÓ]»v½ÿþûçïÿÀq\,{zzª| ªLûz¶‚È”ƒÖ¢Ö ²Š0** )!¢°är9Ú5ĺ:mtzÃaâ³Ï>‹ˆˆ8uêÔ¶mÛzöX/RL&ÇqVVVf†D­­­×®]ƒžXXXà8^]]-‰ÆßSÓD4¼>{öÌl)Ö××ã8îîîþèÑ#4 ÷ø®N„††vvvfeeõ¶é Ú¥+...++[¿~½\.¯¯¯?pàÀ¾}ûÐîÉx:9vìØñãǧM›vøðáøøx:Nòçááá %$$¤¾¾uœ!C†è›§®ár¹ãÆ6lšøöNÈ”™¢&ßÌÈθ‰í@­Mì’'444!!áæÍ›ëׯï‘Ù#+3a à †yHHH°³³³³³#v£;¦P(¼¼¼Ì©‡®òdòäÉ­­­EEEfÓçÎkoo_¹r%ñ‰ܽ{×ÌÚÈÝÝ}Á‚¦;&chÙÙÙùñãÇ>>>666•••ú™‡¡1úÎ;Ç'¿dgiiÙÚÚÚØØˆ¶Ç¨Têĉ»‚}õêU ⣣{³¡=ùrÐ\ÔhrO†Þ[¯6+W®‰DÊǦÅÂ… “’’=zùüùó‘á—_~Ù¹sçôéÓíììÞ|óÍ}ûö½óÎ;¿üò 1)1µ èÄ„ún4úœR lºrøâ‹/RSSçÍ›ggg7uêÔC‡M›6íСCê–…¦“¡¼¼üøñãaaa‘‘‘ŽŽŽaaaEEEW®\1O]DFFZ[[›î˜ "//O,ëª?|}}XYY©P(&OžÜÑÑQRR¢“Â^ºtéùóçÃÂÂFíää´zõê9sæÜ¾}›|$¥¥¥¶¶¶qqqŽŽŽ ,8räÈàÁƒuÊ…VÒÒÒnß¾½nݺM›6Ñh4WW×ððð+W®¼õÖ[º–˜éŒÖr YÔ7oÞüóÏ?ɤØoz˜šNò˜N†Û·o¯_¿>33sèС/_¾d2™ŸþyVV–ú2†édP(7n”J¥Ÿ~úiRR’L&»zõêÖ­[Õ?LZVVVï¿ÿ¾ŽÉxyyµ´´äçç뚊··w{{;š(¿ñÆOŸ>•Éd:ÅÀb±,,,¾þúë½{÷¶··óùü“'O&&&’Wü;vì°±±‰ýꫯÄbñµk×Nœ8±gÏ"@ddäæÍ› 0pà@ …òÃ?|ûí·/^¼Ø·oßO?ý$—˵xùòåŠ+BCC¿øâ‹ŽŽ¡PXZZªÇ¦k0ZËdQ———'$$ô®+_,,,Lwñ&y 1¨' “Ía ÙlöèÑ£.ƒú½ŽÝ]qi:ƒY:ƒÐe ¦“A]¤îìjM'ŽãèU—Q#=(ƒ±F õîîîÈXHu?傊K×4W7Žã„Í8JKùßÊb(×Two»ëÝZ¨Soè•Öüš´Áh.ò=‹ä8o¾aïRˆA&/ÂØÙÙyyy=z´©©Éè2,g“Ê@rãÖ¤2¨‹Ô¥T&•¤–ÊAk˜A3ŒsçÎíèèHMMÕcŽ¢ÜBô;y ¹º‘ñX—i)'§ž´æ·ë¬74ZÍå@Þ´±·íF÷ÐŒP&“â†Épºœ¢ Ãk.ƒ7L2™¬µµµË¡òL 05½¼ÁèÄk×bˆ»@`}}•ž‹®tïAyTqppÈÎÎf2™B¡Ífgdd˜Wdz› =HNNŽP($c°xñb&“óZ•IñóóÓÉ¿ñ+FèñE‹ …B///âˆWUU•ºßÝ´´43—]||<:œfȱÒ}ûöI$’èèh'''??¿ÐÐP•H¢¢¢ž>}zþüyÓÙVjá½÷ÞËÏÏohhàp8%%%‘‘‘&*äîdpppHLL¼{÷nssó“'OŠ‹‹M7îh­ Ã\]]kjj$‰q=÷’‘á¿ÿý¯ŠÇéO>ùÄE¡¹¨TêÞ½{ËÊʸ\.ŸÏß±c‡N2G:¦8º©yÑL^^žT*%£ß}÷ݧOŸnذFmcœ÷Ýw}¾H‘{zÂ=ñ'™ý_ÿú—@ @Q~÷ÝwUUUÊí’Á`Ü¿ŸðVܸ©AöË—/·²²Ò[€Û·o———#×*8Ž«ôÕ;w¢±Ï.ìµÊðþûï‹D¢'NÌ›7oüøñt:]"‘¬ZµÊ#Ww2¤¥¥544lÛ¶ÍÓÓó7Þ8räˆT*Ý´i“)ª[s] Ž=* [[[M¤5ÈÀ`0N:¥ÜìMÔæ5Èàîî^ZZZVVåææ6qâD]=Ú#»KKË;vhpo šÍW„Èò½ÏÙ½‰Þ¯upÃ#—Ë‘3zÂï†a$Ý0M:µ¦¦F*•b6eÊuÙd\®›tY¥Þç³mmme2áúRùUvvö{ï½—““óöÛo.§2œ={vذaÇŽCæ½7n|ûí·W¯^}üøq£—|w2$&&þç?ÿyøð!zµnݺ9sæ,_¾|ÿþýÆ@ƒ Ë—/÷Ýwûí7???£§®U†Áƒ‹ÅâöövS›ñhaçζ¶¶~~~L&S.—ã8®«ÿz ɤ¹Ð:€h†¤lÊ–ï€Qèý†.dõsTTºˆ©tÂïÒ‹íííšÞÐÐ ‘H‚ƒƒ'Nœ( %ɼyó/^üŠ-ïÙ³§ººšÏ绸¸x{{£œJ$???⻡­­íÀqqqä?f+ƒB¡ÈÊÊjooGþMZ[[y<ž³³³9e¨¯¯ðà2S(ÏŸ?omm5®{ 2ua˜½½ýÖ­[‹‹‹õ¸kÑplll¬~·9e Ñhï¼óΩS§X,¡&M4r%%%q¹Ü-[¶èÚå2€´··¯]»¶´´”Ïç744dgg;99)8tèPcc#Š?>>^=ÚiÓ¦9s†Éd*¯f3™L¢/k 0|øðýû÷3 @Àd2=êîî®Ü Ï;wáÂ…Q£Fegg×××óx¼òòòyóæk†}ïÞ½Õ«W777766^¹rE%~­Bj àããsþüù¦¦&.—{óæMOOOùi4ZVVÖãÇù|~}}}QQùVáççÇãñÞ{ï=ƒÁd2ÃÃÃ×®]Ëb± F`` ‘ÐØ±c9RWWgä‘-‡ž”$EѲIssóÆûõë7}út©TêïïoeeEdžÁ`”––ê½Txúôi•½Drr²N½ÎËH‰ûñªªªŠ‹‹‰õ.娻`&“iŠ¥Q22¨P[[[RRbDIt•aÊ”)B¡ðäÉ“æ—!%%¥©©ÉÇÇçÀ---Æ]Õ*ƒ···T*MHH0Ý· V>ùä™L¦ëZhwh¸ðääd@°}ûv]óKfÑL^^žL&«©©Y¹rå˜1cbbb8ÎÅ‹•›Zà]¹r¥L&ûòË/Ub¶··¯ªª*))™;w®››ºÁüÀcÇŽ%ÀÊʪ  €Á`¬X±ÂÅÅeùòå555¥¥¥öööD*.\¸wï^~~~||ü„ æÏŸŸ››ëàà Sqi ''G"‘°Ù츸8E‹UTT0 Âe˜V!µ°··¯¨¨¨®® 7nÜ_|ÁápZ[[•—FoݺUYYéïïïää´xñâììì}ûö‘¬J´ÐzòäIooïË—/WWWŸ>}ÚËËëúõë„+ŒQ£F=|øðÁƒʪÑ8 E§Ó‰¦C§ÓUô¢&Mš$•JÑ.zhh¨T*9r¤rƒÑÒÒ¢¢ÆÈgƒüeÓš1Ê­ÜUUUEEEš‡u)BdÀ0ì£>’Édä[¡qe R©ÁÁÁ÷ïß///Ÿ2eŠ)6–4È€³mÙ²ÅÂÂâàÁƒFW„Zexçw¤R)‹ÅzòäISSÓÝ»w?ûì³þýû›S”ñˆˆ4E`³ÙgΜÑÛ žfEˆ4~-M뢙¼¼¼––– 6  P({÷î%"TÒ¥"üðÃe2Yll,“ÉTV¥Z¬]»V*•†††¢˜qÿì³Ï¤R©rZ.\Éd ècÝ.­GquGNNNKKË®]»ˆø?ýôS™L¶bÅ TZ…Ô`óæÍ2™,::yæP(---„"´··‹Å©©©(k(ä[R„›7o¶°°@Ã5:î÷Ã?ðx<4ÿÛ¿¿L&›7oÉhuh‘h9T9^ …B~K`„ 8Ž?|øP¡PŒ3F,óù|•0µµµT*Õ^‰sçΑ\¥Ͻz@¥R$ÉÁƒÍ_P555ÕÕÕéééÏŸ?ß¶mjfK}РAß}÷Ý£G’““‘_V³%MPQQ‘––¶mÛ¶™3g?xð`Û¶m?ýô“97 lmm1 Û´iNŸ1cƦM›ÞxãôôtSèc´õ®_K#3€h¥°°ØË,,,Ä0lþüù$«9IG{ (…B¡ü[­-ZôòåË3gÎKÐ÷ïßÇ0Ì××W9ŽãÇGgÈß.­ÄÆòïêêŠdÐ*¤ÖÓ¦M“Ëå'OžDIÈårÏŽ€ÃáøûûÇÆÆÚØØ <êÚ*8Ž\.‹Å†566*ж¶6kkkkkk ÃæÎÛÐÐPTTD2Z²‹§t:䉘î@m·¹¹Ã0‡£¦÷–yMHIIqssÛ¸q#‹Å2ê&L°³³£ÑhÁÁÁ‡ÎÍÍ‹‹3›>Þ¶m›››Û|Ѓ'#x<^BBšššŠ‹‹]]]—-[¶{÷îêêjó|ôë×𤤤¼¼¼ÎÎÎÆÆÆQ£F}óÍ7|ðAnnnï9æ@fÑŒB¡¨©©!rÄf³1 £R©$áÕ«W‘=Uee%›Íމ‰±··OII!"ÔÀÙÙyÀ€ÊîÐdhàÀÊ µµµé‘;¨««#¤Bã-ñÝ£UH­[[[ÛÚÚˆ<O¥!mܸ111qÇŽŸ~úé•+W:T^^®Scû믿°¿á¼xñ‚ø7Z¤¤R© ƒ|„:œ¥Óé …Bu˜““ãïï&¿Ã04# …µµµ3gÎ4Šæ;}úôÛo¿­Þ¦ÓÓÓ`^¨ÎÞ½{.\˜’’rôèÑ)ŸÎÎN>Ÿ/Š‹‹GŒ±jÕªÌÌ̲²23 ¾³fÍŠˆˆÈÌÌ,..îÙ±ž(y¤ËÊÊfÍšåããS]]mž={&—ËÏœ9ƒº¡B¡¸wï†aãÆÃq¼7(Bc È.‚8Ù‡"!ŸÁ'OžÄÆÆ¦§§tttp¹Üï¿ÿþßÿþ7QƒZà8.‹===U¾½T¦}fèŒ"‘¨»WZ…$“ •RU¯ k׮͘1#$$$888(((00pûöíäó®µâtZã!«£¢¢P¼ÊYŠŠŠ"#wXXŽãÅÅÅeeeëׯ—ËåõõõØ·o:zJ^\ t·«þ%ºä³Ï>‹ˆˆ8uêÔ¶mÛzv Ž“ÉÄqœF£•••™!ÑÀÀ@kkëµkׯÄÄ 'h?£ººZ$?¾§¦‰ht~öì™ÙR¬¯¯ÇqÜÝÝýÑ£Ghp1îñ]Ã1âB£Ñ*++Q6ÑIiõÉŠ‚ƒƒe2Ù;ï¼S[[‹V>UÆÍ¸\î¸qㆠ†æµ½­Bj ÆommML GŒ¡28#­yìØ±ãÇO›6íðáÃñññt:ÝX¹hnnFö¦$!»AØK¨<$ó[´ãììüøñ㎎›ÊÊJdA^V­©À!IBCCnÞ¼¹~ýúñÕÛè„ 0 c0æ !!ÁÎÎÎÎÎŽØ>vì˜B¡ðòò2§$ŽêLž<¹µµµ¨¨ÈlS±sçε··¯\¹’ªfΜ‰ãøÝ»w{Ãt3ê²páB"› ,Àqü÷ß'ŸÍ1cÆ‚çÏŸ£¤ÕÇÍ®^½ŠaXttto6Ó*¤ÖèðPPà­·Þêr–‚Ôá;w***†nÄ}ú7n¸ººÎž=›dœfª__ߢo±É“'wtt¨lŸ*¬\¹R$§ÈÂ… “’’=zùüùó‘á—_~Ù¹sçôéÓíììÞ|óÍ}ûö½óÎ;¿üò 1)1µ èÔ†2(]ô9¥ØtåðÅ_¤¦¦Î›7ÏÎÎnêÔ©‡š6mÚ¡C‡Ô- M'CyyùñãÇÃÂÂ"##ÃÂÂ"""ŠŠŠ®\¹bôš——'‹ƒƒƒuòŒ2€(Š 6„††º¸¸DDD|ôÑGwîܹxñ"Éx ôðáCŸ‡J$±XÌd2>,,lôèÑNNN«W¯ž3gÎíÛ·ØÞ’““Y,ÖþýûIÞög›nu¼½½ÛÛÛÑ7æo¼ñôéS™Lfž¤û(“'O¶´´¼zõªÑ£ÈÈÈ¡C‡N™2¥®®Nùùž={vîÜ©ü k:~ûí·€€€!C†¼xñ‚Íf'%%ýøãêø¦“<¦“áöíÛëׯÏÌÌ:tèË—/™LæçŸž••¥>Õ0 …bãÆR©ôÓO?E¦oW¯^ݺu«)¦Å^^^---ùùùºæÂ(HYYÙ¹sçâââöîÝûçŸÞ¼y3>>žÈæ²eË’’’8pà@ …òÕW_ÅÅÅýùçŸYYY¨_dddLŸ>}Íš5¿ýö[[[Ûˆ#æÌ™sàÀgÏž¡C^Z¼|ùrÅŠ ¡¡¡_|ñEGG‡P(,--Õã2Óµ­Bj ÀápÂÃÿýöÛŒŒ ÇkjjâââÒÒÒˆ$X,–……Å×_½wïÞööv>ŸòäÉÄÄD#.677mß¾}ÿþý¿þúko¹*Ùÿîò+ÆÂÂÂtFuä1Š!™¼hSXXÈf³GmtÈ\šNÂÊ¡ÁŠÈt2¨‹ÔÝ ¦“·#Š¢˨,ºÔÑ`GèîîŽ uôˆŸÌ¢”}冧 ª‹îú•J‹Å)))Ê¿Âq¼¤¤äÖ­[Z(çEC£WZ³£w{P¿Ë»U5 ©5€ra¢Ýwå$È7û.A±¡††ò¿Õe §™f„Ê'VºÛ´{•¬&ÈäEC;;;//¯£G*ŸQ6– $ËÙ¤2ܸ5© ê"u)•Ie i%f†r0ÃVúܹs;::RSSõ˜Ä@4£µœ5×2‰S¹ØÞÞ~äÈ‘d(çÅ91ÃÚƒzü]Þ­ªµ5P/Lå$ 4ŽTX¥a(Ke"Ì×4#”Éd†¸a2½/à@óC¸a’Éd­­­]Ε?Þû"ùùù,+$$ÄÑÑÑÃÃ#88¸°°P(«GZ‘^Þ€>áPF¿Úà5D¥×ô]m§Q£FýôÓOUUUÈøµ¦¦æìٳġ5ÐkyÛ+€) P(„+Gå{ÔÈ€W dÝìêêÚ]‡ììl&“) ÙlvFF†Ê¾‘Ö´¢5 € 009tÕo/sñâÅL&3&&Jø•¡ïUä÷ß?iÒ$íÆ£Ãot:B¡\»vM,+_=…aXUU•ºïß´´4sv ­BšÞPFÄÓÓ3++ë?þ ãÁQdؤ!ÀæÍ›—,Y’””4iÒ¤˜˜˜ëׯ«ìiA+Z“ЊI{–á°Ùìòòòµè *mdߦßÏû÷ïo ›ª©S§2Œ_ýuذaÊÏ ïÝZc Ñh<øý÷ßÑm«¦“&4Æ­Y³†0Îèò¡Iqss‹ŒŒ¼qãFee¥)â‹Å–––R©ð––KKK§À‚ÅbÍš5Kå¶xsÞhªUH3ÐÊÁˆ¤¥¥988ÄÇÇß½{×-ù­·Þb³ÙYYYííí\.ÓÅéy’0uÏ2œÙ³g¿óÎ;‰‰‰C† ‰ŒŒ4¤šÎž=›ŸŸ¯ws½xñ¢›››!­ÝÇÇçÈ‘#\.7,, udÃ{·ÖêêêÂÂÂòòòrss—-[†z¼æý~§P(111kÖ¬IKKCŸÌt:}íÚµkÖ¬Q~hjüýý‘û4Ú„P(Ä0 Ý÷øäÉ•0Èœ³ïõ&#$&OžüÍ7ß ¿¬zÐãå`,ììì¼½½ïÝ»÷믿šè“ÂÖÖy;Âþö¶ÑÛ’0uÏ2œ'Oždee±X¬)S¦jºz7WŽaXrr²Í† P/VÆðÞ­5…BñèÑ£­[·zyy}ýõ×}tǸ-‚¨¨(tŸ:QjÈ==rI¡µ(srrJJJ¢££KJJø|~CCCvv¶““ ;;}ÈO„Bá¶mÛPä©©©UUU‰‰‰ %77W,£å8åqœF£eee=~ü˜Ïç×××mÙ²E§jF>Yçk‘HÔÞÞŽ|“Á KH//¯¸¸8äVÛœøùùñx¼÷Þ{Á` ­šµkײX,ƒˆÖplll®_¿Îb±A]]]vv¶‹‹ ‰ÖEžP(S(ò={öTWWóù|ooo¡Pˆ­ŸŸŸ±V O‚LÏ;vì‘#GêêêÁüñÃ?ØØØè$§á}ûûªt½×$/\¸Àb±8²ýW¿ìMk6:ÔØØˆ 9>>^åçÙÙÙ÷îÝ[½zuqqqsssccã•+WæÍ›§R±±±Ó§OOMMíÒ÷²á½›L …âܹsùùù+V¬P—‘””Äårõ¨¦W:ž™™‰üÿb»êÍÌÌT~Øyyy‰„Á`„„„Œ3&&&†Ãá\¼x‘˜Gæää Y<ñ“%K–H¥Râƒ]m—˜˜(“ɬ¬¬é®r*·nݪ¬¬ô÷÷wrrZ¼xqvvö¾}ûô¸ÅŽHQ}Û†Á` '#äãTæôéÓÄ@£Lrr2y9µ I’U«VÉd2ýhRþþþR©ôäÉ“ÞÞÞ—/_®®®>}ú´——×õëוoÓ¿uëÖîÝ»gΜéìì'‰rrrˆ·Z[yF%•J333õîðÝ•$qcUUUqqqÿþý»³7×».È'¡9 =kÔ¨Q>|ðàA`` ‡‡GLLLccãéÓ§u*jÃû&â÷߯©©Ñ¯á—[úøøH¥Ò””eÈdu·•+WÊd²/¿üREþœœ‰DÂf³ãââ<<<-ZTQQÁ`0Tœm]¿~ýéÓ§ÝítÞ»ÉÇ0þ|©TÚÝÖ~rr²@ ؾ};(Âÿu:N,ZYY¡»S‰‡Ý‘——×ÒÒ‹‚Q(”½{÷J¥RÂG†VEˆØ¹s§L&ó÷÷Wïçöööb±855%n\5z2Œ––5FÌc´BþÂk3` "Ô»"ܼy³……ºÐ.22’B¡üðÃ<h¨úˆët/^¼Èb±ˆ·Z[y&Mš¤>,ê„Ö’¬ªªÒ| Ǻ ™„f4ô¬ýû÷Ëd²yóæ¡ê P(Ÿþ¹T*ˆˆ YbFì›W¯^mll4ð`‘···z“ÏfHHHwа¥¥e×®]èCÇñO?ýT&“­X±‚(UOOO‘HtâĉÞà`ÇñÒÒÒÚÚÚînÆ}®ÖÒ!“h!T¿¥QDaa!Z}’Ëå………†ÍŸ?ßXkD€ÃáøûûÇÆÆÚØØ WM±kU[[K¥Rí•8wîɵ‹Þà=˜˜•¢¥¡òòr=f¥˜aå€a‡Ã‘Ëåb±Ã0´tÓÖÖfmmmmm ê#®çàr¹#FŒPqžn`‹¢R©ÿüç?wíÚÕÑÑqéÒ¥Þ¶ÞK˜;wnCCCQQár=;;ð.µf—±o^¹reèС‡š3gŽN.ȵbx6èn…BQ__¯P(\]]‰|}}---kkk{CcC:::R©Tõ·h!ºnüë ÙOëœO+ …‚ÉdÕÏf³1 £R©F<®½qãF@°cÇŽòòòC‡ùúúšâ,¸ú!‘ÞЦÉäàà`ooÿ÷eõ IDATÉ'ŸÈåò)S¦ 5– S£7°þúë/ìï“/^¼ þM,³äææ>|ø°±±‘Çã}øá‡è;]YCZ”MUUÕ‰'h4Zttô… úV=š *•* • ‡ÏçËd²Q£F‘ÄX}s÷îÝÛ·o÷óó»páBaa¡çUFÉ&†auuuD$èh«ò¦æÈ‘#1 3Ä‹ˆqA§ÃÆŽÛkÍf̃§FÑŽ`LL ªÝ¨¨¨´´4´GH<Ô€Š¥jÁ†=šøµk×f̘±aÆG]ºt)::ºWMí²Gh Ĭ©=•?͆f­ž™™éîîž’’|8>>žN§“Ì£èÎ!KßµÀ3ááá %$$-.)Š.O·jhQdhlld³Ù<ïâÅ‹}ôÑýû÷{Ûe64d¼¹¹YeÒÁÁaÈ!:MkŒÕ7CBB:;;Þ={fÜÊ2J6ɤ‚a˜~Ç›M½½=†aÊ++¯'d?ˆí@­5°páBB ,X°ÇñßÿU‡ÃQ(“'O&̘1C]g ™ÁƒkHu¹;wîTTTt©M{Þ°GHPYY¹{÷n{Þ^‚¥¥ekkkcc#Ú°¡R©'NT¯J -Š$ …­©êmOùj ¡gݸqÃÕÕuöìÙDQ‡††â8~õêU]GOÃûæÐ¡CÛÚÚþüóO£ÜF̦=z$—Ë{ÏRä˜1cD"QïYªí)Ì7#V(6l uqq‰ˆˆøè£îܹsñâEÔÈΜ9óòåË­[·úøøÐh´Í›7¿ûî»êmåæÍ›þùgXX˜»»»§§çºuëˆIýÒ¥KÏŸ?6zôh''§Õ«WÏ™3çöíÛ¯ù—ŽÊËËÿßÿû2™ÌtIðx{öìàÁƒqqq<øî»ïnÞ¼ÕÑÑÞ–––~úé§Ã† ûõ×_oݺõüãã?~ùò¥J$ååå #GŽ,**º~ýzdd$QI,ËÂÂâ믿FÆ@Ÿ~úéÉ“'Él^¾¶ £q&M™‹è±±cÇŽ'NÄÆÆ>zôè?ÿù‹ÅÚ²e‹Š´š[ ‚æºÐÐ³š››ƒ‚‚***öïßÿàÁƒ„„„óçχ„„ í 2˜³oêÝä´fsÙ²eµµµMMM?ýô…Bùꫯž>}Êd2‰K?È P(NŸ>n‰3dgnòäÉ–––ÎVQ-ÿüóÏ]FâååÕÒÒ’ŸŸs £ÌŸûõëGÒ©È ë"â­²Y¨†`*Ï•_™b%aôhû$Ë¡ËQ Õ,a ¨òo"a*ŽªRå-™Ekkk§l­¯+Z­µ—áv„Z“Ъ!ºëYê¯tíYFì›%%%šor £‘¡ú¬Qs6•ßviŒÞªüD] …róæÍ††CH ÙlöèÑ£õû9†a~~~B¡ððáÃ]¦»»{——J˜/“8Ž£=E´+¦þ1ˆöˆ·Ý]è§Lå¹ò+SLwtÚ}…!Y¨:T*Õ,a ¨òo"ÑZPUª¼ÅH´(’¼xñâÎ;3fÌX²d‰áž ºÄ ÍFk]Ö…2Ýõ,õWºö,£ôÍQ£Fýë_ÿòððм ¬5›(*ìo{u9»Rùm—üè­ÊOÔ…‘Ëå_~ùeggçO?ý4tèPYWÅÎÎÎËËëĉzïíÑh´¤¤$‹µuëÖ.›Íܹs;::RSSa:hLòòò¤R©÷Aq[”‹‹ ºró¿ÿý¯óBÃçs†ÇÐ#Ìš5‹¸Ý´K ¿†€Íf߿׮] Ðãç[·n]´h‘££ãÌ™3oܸÑÐÐàééÙS»_8ŽÏž=»¦¦&??_¿Ë~ ¹óÅÃÃãÞ½{ÅÅÅîîîÝ…Q^ªyÍ›Íþøãu²0 +..îòReŒµkëîîŽ iô[éAn $•J?~YSSÓSÓ…BQTT4aÂLßöfH©²X¬3fhNúu3è2“ÂG{~p0½ªE¡Ý#C„1<@3Ênx‘6…E?àu¦ï™Ä}ÿý÷|>ù_!{j”N§£ÓºkÖ¬!ÎuùФ¸¹¹EFFÞ¸q£²²Ò ÉÀÿOff&òG¯Ÿ‡zc±nݺîüh€5ÉŒŠŠjoo×ÛC}NNNIIItttII ŸÏohhÈÎÎVöE’-‹•mo„B!q²wNLL¤P(¹¹¹„W?e§4-++ëñãÇ|>¿¾¾¾¨¨hË–-¯ÉA€~èà†IÅ1¯NXXXŒ7nÓ¦Mû÷ïŸ>}ú®]»þñdddóH­×ô}üñÇ>>>©©©r¹|åÊ•ÈǺ½½½D"!~B§Óß|óÍ7úúú~üñÇuuuÈÛt‡7Ë 7¼iiiHFEE¥§§#EEòþåüüóÏ&Lˆˆˆð÷÷/(( cÙŠ®9Pvª®ò+{{{ooïŸþùÊ•+\.÷òåËfp°ôitX6D ¡Ä y¨_³f ù“2………„>+,,Ä0lþüùÆÚíÇßß?66ÖÆÆÝ ZÐ YEØåq¤ÓÒÒÈÌ “É$¦qèêw*•jÄc/7n;vì(//?t误/œ©4Cvi”B¡Ðét…B¡¼GˆÌ',,,¢¢¢´N ÑžáåéN ‹¢zC½víÚŒ3BBB‚ƒƒƒ‚‚·oßž‘‘óB ;È*¨¨(õ»ùÑ®!FúuVYY‰”Ÿ³³3†a<ý‰¤µµu[[ <|øpõùœæÝD´zìØ±ãÇO›6íðáÃñññt:d€×Nª{þìò¡.\Hè¶ à8NøØäp8 …bòäÉD€3f¨+B@€aØàÁƒ5¤‚Ôá;w***ºÔ¦`nòòòd2‹ÅZµj•‹‹KDD‡Ã¹|ù2a21uêT>Ÿùòe___¶y󿦦¦ÖÖÖ¯¿þZÙÐ××·¹¹9??ßÃÃÃÓÓsݺuÄÛ¥K—ž?>,,lôèÑNNNMMMçÎ3¥?h"//ÃálÚ´©´´T(>yò$77wÔ¨QDÇCCCKJJ¸\.—Ë-,,  …*ŠÇñÕ«W—––òx<.—{ïÞ=BÏMœ8±  €ÉdŠD¢æææŠŠŠ}ûö9::š;« N^^žD"éׯ2œ·´´TŸ¨!ߤÄ[ƒúî‚©33®1^ ètzvv6R{t:ÝÊÊ ]æÒ¥·Bèýè`GH§Ó×®]KÜÞB¡Pïp™ÐGÑA!Íg:QÀüU„t:]Ù7=¼R„h;0==‹Aà•ÔµgÑÑÑ„Ÿ÷ŒŒ ˜¯ ¤¡ÊÖ ú3***==“Õ¼.(¥P(È|¢åè9²³³™L¦P(d³Ù}Ñ©ïâÅ‹™LfLLŒVáýüü„Bá7ß|cÄl9r„Íf‹D"‰DÙ  ÷`î1tóæÍK–,IJJš4iRLLÌõë× …™e0Çû÷ïß¿2!---««"##ÝÝÝ¿ýö[ …¢9æ©S§2Œ_ýuذa:%±k×.‘HD§Ó)ʵk×ÄbñÊ•+ $dNUU•D´´4ò…I£ÑŸïâââíí- ÑJ—ŸŸŸq×Ó4sîܹ .Œ5*;;»¾¾žÇã•——Ï›7¼ ‡jllDòÇÇÇ«­>>>çÏŸojjâr¹7oÞôôôT‰|øðáû÷ïg0€Éd=zÔÝÝccc“pýúu‹%êêê²³³]\\tÍillìôéÓSSS«««õPÆ<O¡Pðù| ÃD"Q{{{cc£rí3™Á`´´´¨|÷걄€ãxiiimmm—‚9hAxm!Õù‘LOOGjN§›„íìììè ]«à8~üøñŽŽ´CI~u— Ó¦M“Ëå'OžìììT(r¹¼¤¤DyÁpÑ¢E/_¾}úôÛo¿­¾,–žžž@^$S ¯2Ȫ â8Ž‹ÅbOOÏŽŽ•_¡ááá?þø#‹ÅJII)//úôé®]»Þÿ}d@¥ý:°þ €::ŸqˆŠŠRÖ%*šŽ   .7‡zʘ¯KÁøñã­­­‰Iáˆ#”Åær¹ãÆ6lXsss—1„‡‡S(”úúz´x;dÈ]Å@‘;99镉Wt‰ÉdÂ÷*èüÜS³CcíštÊ1((ˆ˜y¼õÖ[ÊŠðêÕ«†EGGw75±´´lmmmllDÛ„T*uâĉºyôè‘\.;v¬9MSz9cÆŒ‰D¯Àr1FVŠº   €ÇãŸ____TT´eË‘]>Ÿa˜H$jooollÔiðõññ9þ|SS—˽y󦧧§Ê¢ÜðáÃ÷ïßÏ`0“É|øàÁƒÀÀ@˜˜˜ÆÆÆÓ§OëtÁ)É&—œœ,¶oߊ^_òòòZZZbccÑ(C¡PöîÝ+•JÐЦU"vîÜ)“ɺt#`oo/‹SSSQèòk;Ý)ÂÍ›7Ëd²èèhtÝ6…BÉÈÈhii!áÚµk¥Rihh(úÇñÏ>ûL*•~ùå—„¨Hl3…B¹xñ"‹ÅRWEZ!R`=;òê­ tW¢¡Áìß¿_&“Í›7•6…BùüóÏ¥RiDDÉB#ßäzC]Ðfí™………ÄîZaa!†aóçÏ7Öq>@Àápüýýcccmll Egg§™ÝöN›6M.—Ÿ}-E"¯åååhY299¹÷(ƒ¹sç644¡Ò–ËåÙÙÙ†uç­IòM®ë­˜oTR(L&“Ð l6Ã0*•jÄsí7n;vì(//?tè²v1ŽŽŽ­­­mmmÄ´ÙFüéìì<`ÀäMqöìY ‹arss>|ØØØÈãñ>üðCâÎ̾BPPƒƒƒ½½ý'Ÿ|"—˧L™boooooŸÐ{”•J …ʵÃçóe2Ù¨Q£ÈGÒãMÃ1ßðŠ¶ˆ?Ñj’†óz¬†]»vmÆŒ6lxôèQPPÐ¥K—¢££Í¬BTr¤r¦Çq±X\}TÒ¬ÐÚÔ±cÇ$I||¼9¿Ðr.FŒ¡,—˵µµ6lXÇÿBèËððp …’‘‘q÷îݦ¦¦žò ôj ¡Á477ÛÙÙ)?qpp2dHSS“Nñ÷l“Àp̪.\HŒ ,Àqü÷ßGC‡ÃQ(“'O&̘1C}@AömƒÖ ›îܹSQQÑ¥65¥¥¥AAAĜ୷ÞRàêÕ«†i˜4XZZ¶¶¶666¢+*•:qâľ;°VVVîÞ½æ÷Ì7\]]gÏžMohh(ŽãW¯^Õu ÞƒM€>C^^žL&c±X«V­rqq‰ˆˆ@…‹¥S§Nåóù—/_öõõ¥Ñh›7onjjjmmU95êëëÛÜÜœŸŸïáááéé¹nÝ:âíÒ¥KÏŸ?6zôh''§ˆˆˆ¦¦¦sçÎé}àPÝurrb0üñÇ»ï¾ëææ¶~ýz6›­l>Ñ¿ÿ‚‚‡óùçŸÓh4WW×ððð+W®úrÏž=2™ì³Ï>stt\°`ÁåË—›››[[[ÕmÒµž5ÄŽÐX¾»©õÔhAAÇC§rÔßjh0T*õÁƒeeeK–,qqqY½zuCCÃ¥K—¬¬¬HÊF¾Éååå‰Åâàà`Бðú’——Çáp6mÚTZZ* ŸE}…Y³f?^ÃL´¥¥ÅÃãË5uŽ=š““ƒîX0žŒ P„ Jqq1•JÕ†¤Ä^•©9†‚öQzZ ”ùä'lc*¦NÀ«Íÿê;%µG¡€^}þWßæ^kþפaôXì“ ³_àÕÅuö„Iü¥¤›j0 £àä¯.O˜ØÓbÒ§¤óp h@àµ@a ¸ò à5?~|OË=†%ŽÃÆ ðúv„Àk (BàµÆ¼f¯30#^k@¯Ü™!b IDAT5–*=zÊ”)––ªÏÍFGGGiiiSSSw@B­€„†Hh8¯€„6l˜9E"ƒD"ùóÏ?‰?ÿ§ø …›››H$2»TÿŽãnnnÝ+HHÐp@Bà çðåË—l6»WFÁq¼ÿþ …‚°T]•ËÍ}÷š………••ñ§âoº of ­¬¬T¾¶z¡„ʈõ> Õ õÀÚz¦dõÛ %T¡·I¨2Ô`½OÂÞ?ÚXXXè$¡B¡xñâE¯Ò‚†)Š?ÿüSYªÿ95*—ËÍ&ñw#FXZYYXXpššêYL"i ÅjN ‡ÛÙã>`à@ Þ?Æb2¥I¯’ÐÎn„«›ÛÀAƒ0 {ñâÅ6›×ÌíU"p÷™¯¶¦¥ÞK$ô Ñ¨Ô‘ÊOÊÜþìÖk$¤P(cÇÚ;8ZXX(Ц§OêY½§ =ÆÒ¨#Gª<är8¨G÷ 1 6lØwAƒã8þâŋƆz>‡^õ ‡æîî1hð` ÃZZdÌÚÚgÏžõ* ÛØ¸{Œ2d†am­­,f]KK‹V {› TFYì;,caAA²P(½ñÀNÿþýiãÆ4H$J¥ÒÁƒmh´q½êž~ýú7nÐàÁb‘H$0`ìØ±¨#õ6\]]‡ jaa÷¾º¶îomaañ¬­­åo:;:zZ¨ÿaœ§çH'çÎÎ>'‰^üï—lóçŸÏ%b1ñ_û_!…ÝÓrýciãl† ‘ɤB¡`À€ciýúõëi¡þ++«qãÇÛ "‹e2é°a¶c{ÙhƒaظñžÃ† “HÄR‰dÈСÿ{÷Gq÷|f¯ßIw:õ®Sµån°lË•0ØÓܰq( 8à4x ðÀ~à„PL „ؘâ`šé‚»å^$«X½œºNºÞvç÷ÇàåmYÒ´#Ý÷ý¯åt>}4{»ßÙÙÝÜ1c8™LêP!#Ù)ÖªÊJ„PÞ˜± ‰‰ReèCLl¬R©´Y­å¥¥„3 5Z­N§³ÛíRGûJ¥vØí]wUe%!dÒ”)C”^op0“ÒêtÉ©i‚ °yÄCÇÊÊËJÝn7}…©¸.""66ŽçùÇ»œNÄX<„¹©©Ùl¦ËQQÆñ'Úí¶úº:vrª5V+ÂÉâbA" "4ZmDDdW—”§ÖÅÆÆ©Õ‡Ý^z²„R0c†!**R¯·öôHíFc´N§s:¥%%„ ¦èt±1±mm­RG É !;ÛÉYu´·Ûl6¿Ï'‚J¥’+„ŸÏ'u®ÙlÖ’â!BˆB¡P*U!Ûu¾7Ü23³0ÆqqñRg9 …B!ð¼1:Z£ÑºÝn³¹ ±ôÍ4 c»Ý¦Ñhý~_Ks3SßCtz[æ8.;7rª¢‚çêU{<ŸÏ§P( QQn—K¡T ‚àbiKQ(•!·ÇMëÜn·Z­‰ÐE°SµZ-BÈãñЄ.—S§Ó©5©s…Œd…q^¯×ëõÒåÌìlŽã:;:ÄWA‰ŒÔç/—Ëe2YcC½åôYLF$&%EÇÄÔ×Õ* DR(•œL–•CG¢bcc;ÊÎQšŒ“!„´Z]þ¸ñÇB>Äó¼ÔÑzKKO×jµfs“Ýf“:ËOA¨®¬ÌÊÉ7~Bc\S]E»×Œð¸Ý!­VGGMèÆÂÔ GÏd~t;F!„9aÌÔã 1ÔÖlÊ0™âãã].WUå)vö"AœN§ÇãÆG½&ÅIK¡Pd˜L6[e0ÇY­=ÝËáC:èóù QQ±qqRç €BÈïó•Ÿ8zøÇãÖêtIÉÉRÇ:‹øøBH‹ÙÌຎ‹S*•·Ûn·cŒcãâ™ÚRÚÚÛœN§F£¹°  `ÆLÚýà a_“’ÒÒ3|>YéIñS{ɉã‡ìêꌈˆLJNÚ$—žaR©Ôr¹|Ò”)±q±!£1:3+›YDJNœ8qü˜Óá°ÛíVkBH«Õ±Ó†~¿!äñxº-«ÕÚméF©5vÚ2DE©5Ç#ÎudGbRRLl¬Ãn?tðÀ±#‡;;:ôz}rj*b¦ ‰ ”œ8ÞÚlö¸=m­-6› !DCÇO/Ò8=±„øÑÑD½.Ÿèû‚•!ø«ûžŒ;|'ÄÆfee#„*OUô¬g!a|BBrJŠÍj«®ªÏ_rpaÄ ![&ãd2µL&GÉd2¥RI+ ###323}^_Ey!„†ôû|„}Ƕ„ôBz2†"WÈB>ŸŸ6¤t§¯áéõ{YH¨T*1B^¯—^làõzBr™±Ô†.—«¼¼!$“É.,˜Žr9ä|É ß÷ÐéD©”*úU*ÍÜŸ„ÃopcÃ9³Óêt¹ycä …Ó鈎‰1FG#„º-–Ö–©£ýÀãñDFêée ‘ØØ8BHw·…o^uUeuU%]ÎÊÎIMKëèh¯(+c'¡ÇãÑë r¹c,|TTÏóìL&Duww[­VƒÁ0~âD·ËÃó|gG;;mH)ärŒ‘ßÏÖ,ª««+5-=ÊhÌ3Öï÷Ç'$BlV+SmhŒŽNHHt»]QQFµZm·Ûººº¤õ#‹¥Ëétêtº1ùùˆ ˆˆH·ËÕ%émB áÙi5Zz¥‘V«ÓjuôEžçÛZ[Ù~zº»«*+ÓÒÓé#ÇÓX_ÏÔWó¬ ÅHëQ^¯·êÔ© “‰^Ããñxêjjœ,M£@UVTäæåÑ8Ó„¶Ó23sa"0´rE6«µ¦ª*-=^øïózê[›÷¯Õhcãâè%˜]]]U§Øš‘@©(/ËÎÉOÀ;ŽÊÊS~Æ®¸ †Ä…°¼¬´¼¬1¶Dut´ïÜþý™¯3•ÓÜÔØlnÒh4„ ·›­ë¬{{‡¬…lmmikkÕh4(`¨‡)v»íè‘Ãjµ†ã°óôpkêjkêjk{ë—2››š›Íjµš“ÉœΓ:ÔO455¶µµª5·Ëå÷ûlFkOÏÑÇT*½;ƒ ƒ!q!d¹5YÎ&"„°Öƒ9+–“ý6$„¸\¬'”:ÂyBŸ6À ŸÏÇÚ¢½BØœ3<˜5 ¬eÖ¨ä3³Ï;K ž$ $ $ ÞHO8Ìaú/06ô„5(„ÂBa ®#ŒŸÞ¦œ¾(–F: 4 ¡,„\pÉdâyþäÉ“•••ñññ)))!›ÍVYY9üßÚÌÌL£Ñˆòz½%%%4€\.Ÿ8q"Ƹ¹¹YòÈ#„¿ß/“Éššš}ôÑ¥K—Î;—çy„}'](y¯ïôà¾âééé«W¯NOO§Çà .ܱc!dþüùãÊÊʧžzªÿŸÜ÷±^ÿ?gæÌ™—^z)ÆØëõÞwß}^¯!4uêԻ㸃¾úê«ô bÑ¢ES¦LÁ···÷§†*a ™L¶lÙ²Y³fч^ÒϱX,ï¿ÿþ Æ÷†"!BhÑ¢Eô0‚ž~[¼x±\.?|øð áP$¼ë®»t:x<8f̘¼¼¼–––‡~xò„«W¯6 çúé@74 o¼ñƬ¬,ºãþÃþ ~Â’%KÒÒÒBmÌ!ú"„fÏž}ùå—ÓΟÿüçêêêÁ}Ú%¼å–[æÏŸ¯V«Åa ¯×»gÏžwß}w •&ä Å­¸¢¢¢¦¦æ²Ë.£§! .ܸqcEEE¨¾‡ýœ,C«àÌ™3ׯ_o0xž§UPüžçßÿ}¹\þ»ßýN&“™Íæx ¢¢bÉ’%´;HË c‡ G¨V«ï¾ûnÚùÿª‹.ºÈn·Ëd2$ÝUyyùe—]ÆqœZ­ÎËË£G¸&LÉdãÜÜ\ñIII4j}}½$QBwß}÷´iÓ;õ㘘˜Ûo¿ÝívKÛO ŒD§êÆë¯¿^¡P „¬Ì<ã”ã¸^ (“² W<‰ë·W£Ñ×K£Í½f2åÎ;ï,,,ìµ®U*ÕE]óÜsÏI{RSlºÌÌ̼¼<1'Æ8))é®»îzòÉ';‡ñɦ´7}úô_|‘VA:_F$­›6mB-_¾|Íš5555Ï<ó̬Y³èûA‡F‘!…𪫮JNN¦Ëf³yß¾}r¹|úô鉉‰Áx0Š‹‹½^¯Z­Feff–”” „ÆŒC7£Ñ8a„'N¨Õ길8úO¤›š?¾XÍfóþýû5ÍܹsµZ­J¥ºîºëŽ?ÎH±¡hÏÆf³y<žž—:[¶lQ(K—.¥-Y]]½wï^v¦>|X¼!$“ɦL™B&xžß¶m#9A0æÌ™3sæLú lmmÝ·oŸßïŸ1cFjj*ÆxâĉW^yå_|ÁºV©T]]]û÷ïw8Ó§O§þ˜˜˜k®¹fÓ¦MÓּ‚‚‚_|1**êÌ*H ¡ kÖ¬Á¿õÖ[Ÿ~ú)Bhݺu………t˜T|'’°^pÁ´´¸Ýîõë×·´´ „¶oßþÄOhµÚà?Ð<O}}}nn.Æ8%%…‰5!4eÊ”'NäææÒî !äĉ’|AçÍ›G·»Ýþì³Ïvtt „œNçu×]‡16™Liiiuuuìüñ'Ÿ|ø”ÜŽ;B·Þz+mL‹ÅòÝwßÑ‘©£!„ЦM›{0+W®¤CR¡mÛ¶ª×ëBS¦Lyë­·†'!!D§Ó=öØcF£QœüÒ Bˆ–^{íµ[·nmooŸ7o­‚ljx0…0Øšˆˆˆ¤¤$º\UUÕÚÚJ£wvvz<ž ?ù„Nåba“¦Î,Éìi„xl+ÂìÙ³çÌ™C×iEEÅ–-[à€Q """##ƒ®Öòòòææfú ìêê*..¦_ÅÄÄÄÀIòûý â[œe4Å=ÒPÃ;Žçž{ŽžJãyþ̾ -xÍÍÍk×®u»Ý—\rÉ®]»žyæñ¼ 9=qtÐÛ{°=„„qˆ¹¥¥…UVVFϨ'$$ „ÆŒƒ¢k=666%%%%%%55•¾Yª.WRR’Ø3?~üË/¿L—Å3!:—)¬­ë$##㦛n¢ãÝÝÝ6lÜT7ÀšÄÄDq[îµ? <ƒ’’ÒØØÈÚ˜0))©¾¾~B0ÆÛ¶m{àþú׿jµZ¿ß8:J7æææûï¿¿¶¶ö©§žš={ö‹/¾¸yóf™Löë_ÿZ¼ âÑŒÁö?GŸrÅÅÅt^µZ­ž4i=Xkjj:rämµ .¸ ))I<0—ä«xÞH.—«O§"–&)€ )•ÊU«VÑ1(žçßyçIÆ!ÀPÜ–{]Ѹ{ |;l6›¸<œ !Ç}ÿý÷k×®µÛítî í Ò*HyüñÇ+**þò—¿Ìž=Ûï÷ßsÏ=Ë—/ß²eËþóÚe r×}–'ÔèߎªÕês}€>¹74¡×ë­¯¯;v,ÆøòË/§Nžlk9°øy<žP%ìÏ'ðnˆzùúë¯ÇŒ£P(”Jåš5kNž<éóù&L˜@ïQGùöÛo%ÿ6R …â(--õûýyyyQQQôõÇK•^G¸gÏž%K–h4šŽaŒ}>_ww÷@o áÖ­['OžœžžŽŠŠŠ¢ƒ¶ètW7øÏ’ßﯯ¯ÇE:D_///ïèè {Lžç¥½býàÁƒ_ýõ•W^ÉqœB¡?~<}fÎÍ͉‰aä(’}ÅÅÅôG.—Ož<¹³³sóæÍ’ïzâââÄñ„PttttttàO/IeïÞ½—_~9Í©×ëé¶ì÷ûOœ8!vh@ߎ?þùçŸ/\¸ã¸ÈÈHñ$ýé÷ß¿sçNÉ¿” :®  $lkkûðÃ%< £§ú†ù¾¬ù©A|„ÇãY¿~ýÑ£Gi‡cìv»?øàƒAoؤOƒøÀêêjºÐÑÑqòäIrz®­8jÚÜÜ< vyBBÈ–-[Þ|óM:©Z¼7˜Ûí...~å•Wzþ2ä Cnèþç?ÿÙ¿?uÄÓù™’'Šfyúýþ—_~Y5Á[,– 6ìß¿Ð_ìpûB>üðà 6nË¡¶¶¶Í›7oÚ´i 5fèÚÐãñ¼÷Þ{‡ƒ&¡¼¼|ýúõ‹EÚ„ÃóÝ š§O´µµ=ÿüóqqqéééôô›Óé¼ä’KBòáÁû÷¿ÿýÁ ÓsÄ×7nÜøæ›ožùº$!Û·oß±cGRRRrr²L&ëîª¯0•6õüóÏ‹±JÞbçb·Û_}õU£Ñh2™8Ž«©©a!jssóÏþó>:UŒ4iKKËÓO?–––””d·ÛËËËéî®]»èÔB"„6oÞüÞ{ïÑe¦îê€"„ìܹs×®])))‰‰‰ǵ¶¶ÒËò˜Ê‰úæ›ovìØ‘——§R©ZZZY¿Ã,da¡µµµ­­ ±7¿‘œ¾*³ÖV9ÝNšššèm™{-ÉZ‹‹ ´—ÏNŽ Ö«««£wÞ[f¤ÎµQ3‚nË ˆ½ÖBœNç±cÇÃ!‡AˆÌÎMBÐŒ!Í h½Í8"B)¦  5(„ÂZ°·XëÃSO=E/W÷x<Í?W vÎ6CÂàAÂàAÂà…[Â7ß|“^äÂó¬}$ Éç…ÀÖ ñ9Â@ì<¯5œOŸ)`h@XƒB ¬A!Ö†p²Ì õö$ $ $ ÞHO8Ìaú/06ô„5(„ÂBa !€°…@XƒY£ƒ ƒ ƒ ƒ ƒ³F€‘­w!d¹€S0x0x0x0xì'~R !.—KÚ–%„8Î>~ Ï o¤'Dùýþa Ó‚ þ/NKKÿ‡¢Ñh233u:ݰûÓ鬪ªr»Ýã3 ûo$ôz½ …B&“ ¶sñûý>ŸO¥R‰™RB<Ïû|¾^Õr8q×w«AÂó‚„Áƒ„Áƒ„Á ½^¯„ ÏÄqœR© ÌŒSSS% H fkP„5(„š\Ú©·€´ G ¬A!Ö kP„5(„ÂÌÖ G ¬É‡ôÓ322 äò¡ý-}ðûýEEE çzû ÑH Ï ï¼ õz}BBÂY%1jBZZZl6›øÊ®BHfff{{ûÐýŠóÂgffžk­³Ÿ„°? að aðΛcÜØØ8ºO™aŒ•J%ýcé+C;4*ù£7èêìc¥²ŸIsœF«ÿ—fìõð; )¥R©P(_a-á™ aðFABÇ3º« Bˆâv»ÿÌ!œ,C ,¹Rá\#û Ѱ‡4DEeçäèõŽãÇþ}{i6é›ãÉ“§DÇÄ<_[SSWWÛëçÒ'D!¤R©ÆOœh0D!„ÚÛÚJŠOˆ©IØH¼‘žp˜ÃHˆ®º “eÀÔjõ„ Æèn‹¥©±¡«³SêD?JLLЉ->q¼½½=ÝdÂ'§¤^X0]òÝJ/&S¦ÑÝÓÝm³ÙSàyŸ£”B¡HLLŠ“:ÉÎÙ%&%©Ôên‹åø±£ý³N …‚ÒÓÝ!“qJ¥Òd2™Íf©sõF‡”kkªÕ^¯W«5cvšQ”˜˜Dimm‘:ÈH¥ÓéòÇ·Ûm ®_0 PÁâbãâ1Æã¬ì„PWW';B‹¥Kàù‰“§hÔj›Õ–“ë÷ûëêjYÛÙì¶˜ØØÔ´ôˆÈAÚÛÚXK¨Öhü>_BR¢À cŸÏ'u¨‰n,R§!…ü@¥TÑùr…\§Ó!„l6«Ô¡~d·ÙŽ?ßmé²ÙlùãÆ?v”H=õàLõõ©©iqññ>¯·¼¬´§§[êD½™L¦„Ä$"!…³ç464ÔÖT³V­§±V§Ó32""" 9ÆX¥Rçjh¨·YÚ^À€@!?pºœ^[«Õz=Þîn BÈãöHê',]]Ý ¸ `zkK‹\&ÏÉÍs:fs“ÔÑ~ —ËÇOœ$—Ë !Çy½^V;eêÔö¶öªÊSR§ûAuU• i顺ÚZs‹såçÌ›/v¶víØîõz¥Í(*ÊO—•JeRr2B¨£½ áÈ5´³F'™úž"ÅrB4Œ!#t:•ZMQkÔ11±!¯Çk±t7äp6#!$3;[®ÛlÖq&X{zRRS•jumu ÓÒÓ£ †®ÎÎÎÎŽ¬ìœ±ù㚛͆¡ï ÃÙ†^ŸÏÝÝmQ«5¦×ty"„šÍMb!äyž©„5ÕU jfÌØ±.—óTy!Äjíµä Ï f¢ŸÎ…!øA]]'“gff:ÎcG~KØ™‘aª(/‹Ž‰ñ¸ÝGž8yJLL4-„’SªTc§ÓQ_W§TªÒ32L&“ ÖÖVv“BcCƒÅbÑiu3ºï++-—YKhµZBF£!$L– ‚BÚÚZÓÒÓÑÑùãÇ»œ.„HM5[gL&S·ÅÒl6 ¹B¡P(r9ïç¥Îõƒžîîä䔄Ä$ž … /¾y IDATǹœ‡Ý.u´Ÿhlh@±–*Sß:0êA!?²Ûl'Kг²²1B.—«¦ºZêP?Q^V&“É!ÑÑ1³æÌ¡´¤„‘ýf³Ù¬ÓE¤¥§§gdB¬==˜ãôzýØüq¥'K¤NBÉb±ü÷Ûmjö¨0äw–¢P tŽ/+û Ѱ‡lkmmokS(ÖårŠw„b¤ÅIÖžž=»wEDFºœN:«‘„•§*ª*OEDFº]®ÀéŽbÉö"ÌY_”<á%—]ÞëÒŽ“ÅÅÍÍæó&žxŒ€s„àœ!^¯—©yzg%‚µ§Gê½ÑƒÁ@X175õ*„‡Cª0ìƒB£MyYi¯W­·7 P`´²7 pÓma !€°³F™y.}Ç`?$$ì'HñÄ===ƒžS0rWô¨O¸}ûö;vÐå ‡pö ChØÊd2žçcccyä‘+¯¼’¾L”ÉdQQQc‹Åä8vàËVYaH­VÓŽ‚ÅbéééýBˆpšÔYÀp ¹<ÏnÞ¼yÁ‚tÕÓo ?Ö`0üóŸÿ|óÍ7ãââB–á¡ÑÌÌÌqãÆEEEùý~³Ù|èÐ!§Ó)u¨Ÿ˜6mšÉdR©T‡£¦¦æøñã îÁ§OŸž™™Éóü‘#Gª{”ĸqãt:³‡R(Ó¦M#„Ô××3u"}Ú´iYYY„âââ²²²„„„´´4„ÓédgÒBÈh4FEEutt8p€©y¤‰‰‰´ÑBUUUŒÏÏÔëõyyyôøÌï÷=z”µ<"ÐáP¹\þË_þòž{îQ©T~¿Ÿ>7†N¥m; ¹£ôÍr¹<""B¡PÈd²f±šL¦+VŒ;VüS !v»ýã?þì³ÏXøF,[¶,!!A<åKill|çwŽ;ÆBB„Édºûî»M& yýõ×õÕWL£^¾|yff¦8Nÿý÷#„Þzë­/¾ø‚…fLMMýÅ/~A'ò „®¿þúíÛ·Ûíö«¯¾c\__ÿàƒ²!tñÅ/Y²$""!D¹ñÆ7nܸwï^FâMŸ>ýÖ[o¥_¿õë׳ì¬V®\YXXHÓnß¾zD U0##ã±Ç›5k!„çyŽãÄS<ÏÓÙpjUúf¿ß?ƒFÌÂÄÄÄßþö·±±±»lŒ±^¯_¶l™ ’ï"'Ož|Ï=÷hµÚÀ1ÆééékÖ¬ùÛßþV\\,ùf£V«ï½÷ÞÔÔTñ¹\¾`ÁɃ¢ƒ'¯Ðÿe¤Z+•Ê{ï½7##CÌ#“É.¾øb«ÕJÑɉŠˆˆXµj•Ø·ÆÓIêµµµf³YÚl]×b?@ê8}™6mÚÌ™3é*nll|ë­·`8w@A¸êª«~øáøøx¿ßO×;ù鳟bccÅ>b??cì÷ûiiý…ðšk®«à_|qâĉôôôë®»N­Vs·`Á‚/¿üRÚ½ù¢E‹èe­V«uÆ åååË—/W(Z­öÚk¯-aà9±‹-JII¡Ëf³yÏž=J¥röìÙ111Ò ôÉ'Ÿ †E‹ÑTŸ~ú)!„‘«é¯¾új± ¶´´ìÚµK.—Ïœ9311Qêh½©Õê–––¢¢"Ç3cÆŒŒŒ „PddäÅ_üî»ï²Ð˜#…Z­^¶l™\.Gy<ž 6°vF†qÇ=öØc·Ür Bˆçyq8TìB´Zí?ÿùÏ^¯£Ó·¼éõæ^ !Fãr¹B›¹[¬ñ<_UUE'mÚ´I„C‡¥¥¥Íš5 cßÜÜ’ƒK˜˜˜HwŽûöíãyþË/¿ÌËË£³{­Ú :ä´iÓhH·Ûý—¿ü…v ¶oßþøãëtºA|rÈ›!´wï^„Ðå—_Nÿ×ívõÕWâõ~ZÈN›6.x½Þgžy¦¾¾!ôÕW_=ýôÓz½~Ÿ<mHY­ÖG}´»»!´gÏž§Ÿ~Z¥R¡Ó3rYHxæG îÓ†4!!äÖ[oMJJ¢ÿûÉ'Ÿ””” ´;8ÒÛ0¸\ˆÒÖÖæ÷û …8†yfm£Ã§=Erúv3g¾™܉F·Û’KÿXæz„7n—ů`à©uƒÁÐÒÒªïÓ Øívzs–üüüË.»lçÎN§sýúõâ$H‰ŒŒ»ƒÍÍÍ´¹\.—X%wæJ áž"HJ¥2--LTVV644Ð`v»],„Œðz½ô²„Ùl¶X,´ÛÊZN–aŒ/½ôÒK.¹„®ôâââ>ø@òmy$zùå—<øÄO¤§§û|>qh”B‹ŸÃá¸ë®»š››åòÁôÄèihç‚1WA C:yyyÑÑÑ*• cÉÎy…ï¿ÿþ¶Ûnã8N§ÓÝ~ûíË—/7›Í»víª¨¨`a?ž””$ž{P““ém<ÑlC·ÛMÄ?œ—J¥Z½z5Ýpìvû?þñ–o·Æ,ÚÛ+**Z±bÅŸþô§‹.ºˆçy:MTìÞ ‚ÐÒÒÒÞÞ.uØ1W'Mšt÷ÝwÓ.bò¼:­CÏlq§R©233M&Ó¥—^ZTTô÷¿ÿ]Ü I%p"Ýng¡68âÝB‡Ú0ˆ‡Z­6--MJB父´´Ü{ï½wÞyç/~ñ ¹\Ng͈žô,,;·Þf«*Š;3^)éñx¾ýöÛÚÚZŸÏWPP Îf–!äË/¿üî»ïfΜ9nܸìììÔÔTŽãärù¬Y³<Ïk¯½&툊Çã—wè ÿoù­ÑhØÙbÁñù|;vì˜?¾\.ç8nùòåeee===Rç‘Ä3ý¯½öÚ‰'yä‘ääd¯×K‡IÏJôlM–™X^^Ž1ÎÏχ‘ÒþÛ·o_zz:ÆX­Vÿþ÷¿/++!??ŸÞ½ŒJN§sÓ¦Mk×®U(Ç-[¶¬´´´³³Sê\#íRó<ÿꫯ?ôÐC:Ž…d ¶z„§N¢muõÕW/X° 11±¨¨Hl¸ÐÞku ü~ÿ¦M›èåœ111K–,¹ÿþûo¹åÚÓr8ÿú׿XXÇ~øa]]]6 Ó¦MÓjµbOœ×'Ÿ|R]]Mצ^¯/((˜1c†Á`ðù|RGCèðáÃÛ·o§ë=66våÊ•¬=3h$¢Nìܹó®»îÚ³gkýl¶V0!䥗^:~ü8=ˆ Wœ¼ýöÛï¼óŽ8yA¼®TŠŠŠÖ­[WVVF{ýôô¯Ïç;qâÄÿûÿ…û«!„Ün÷3Ï€ !ôÝwß12Z € !çTQQ›’’8œe6›¿üò˯¿þš©s]l¢w ¦­çñx¾ûî;F¦UhÏR,|éûÎÀ~Âþ¼aŒôfDÂ-[¶¼ÿþû&“)33S£Ñ8ÎÚÚÚÚÚÚAÏŠ ·6¬­­}饗"##ív{qqqWWWðÝÁpká í9BFŒŒs„HŽ¼ššššššÀ%Œ4²X­VzBí…€ó€=x0 õûغ fP„5(„ÂÚÐÎeáôÀyïÛ2œaΕaDL3ÑÍ ûoD'd!Þ° üc¡G ¬A!Ö kP„5(„ÂÌe=! !!a@ÂàAÂàîY£J¥ò®»î¿þúëwÜqGàÂK/½x«Ûá»×( â)”Ãý„h$„„„Áƒ„Áƒ„!”ššJùÌ…sÂBHq»ÝFÂOq¹\}ü”ñ„h$„„„ý ƒ ƒwÞŽÏçS(Ö'ä¼^ïC=„áÌñm½ž¡† Ã"„èõú¬¬,­V;D¿â¼\.Wee¥Íf;ë7ý„h$„„„ý ƒ ƒwÞ„cN'—æç1ø|>§ÓØ;ÂBˆA Ç1ÆÇqÜ9籟„ð¼ að aðú“çùQp²°c™LØX¯×K\> ¬A!Ö kP„5(„ÂÚÐÞb `ô„5(„ÂBa !€°“e„µÞ·‰‰ÉÈÈèûÐÃL„úúúŽŽŽs½Ád2JøèŸÏ·gÏžºººs½ž$ $ $ ÞyJ^eά)?)„„FÓÔÔÄT7c¬V«Ïõ@KBHNNN[[ÛðaŒ³³³Ïµâ!a@ÂàAÂàAÂà7¡äUæÌšÂõú±×ëeª "„!^¯÷\?Å>nQ}·$ìH<bŽ›0qÒ˜ü|ºÇa*á¤ÉSÆž&b*áY‚„’W™3k CC #kGg‚„Áƒ„5nÜø¤¤¤žîn1; »»-馜ÜÜÕB@ƒB±±±)©©fsSkK‹ÔY΢¾®®££ÃdÊŒˆˆ”:ËY(•ʸøø¨¨(©ƒœ“R¥JHHLNNf³¤÷d€L&›>s&Bhßž=lÛ²Ÿ!”šžŽ1®«­e6acC}\\œÉd*.>ÁZHF“ãt:zzzXˆŠŽ‰ÉÎΖË!–fs]]ƒ9ûiÄ\>ÑGÎáÿ0Æ©iiÉ)) M4 ccãLYYÍfsScÙ$O¨V«/œVÐk$êÐÁ.— ±‘P©Ç÷Š ÄhŒ¶Ûív»Ù„m­­>Ÿ/*::0S Éig¾ØÇ?ú\(11I.WÔ××;ìöœÜÜĤd³Ùìñxú“ ¡G80&-=#99Y¥VcŒêë¥NÔ ‰‰‰‰‰‰ÉÎÉi6›êëÝn—Ô‘~c|ÖÙ¿Lñûý_ùbøTû µZ­B¡°Z­Ré !ÄãvGDFÊårŸÏ'uœ‘¤¡¾®Y.·X,„·Ë©×k4Z±Ž8P '//Ó”ÉÉd.—«¾¾¾ÙÜÔm±Hê':::ŠöíMJN‰‹ËÊÎ6™LMæ¦Ò’Fv—n·{÷®½^d$[/l¦ ÄxB•Zò3_]|~BH­VC!ñ':&F«Óy½^›éƒž¾A!ƒÞ “Ë{}}½¹±‘Í-§ÛbééîîNJ2ef Q1Ñ1R'ú‘Z­.˜>£WðÀþ":4 Föûý? ‡#%-cbbb²²s!ÕUU<ÏKgð @å© Ç“0vl~NNnWgguuUOw·Ô¹~¤V«³²sâããéñxG{{C}=S]¿ß?bv‘ n—!$—îþ&ýDºÙ;ãyÁív3>ؘža’Ëå'KŠ{zz¤Î”Ñ0YfØôôôX‹O”—•¦gd$'§$$&¶··‰……„z½!-=ÝãñÔ××××Õ9½ç)H˜ !äv»÷íÝÓëE¦R}ÌÉd$¡F«8i’×ã=vô› N‡×ëU)•gþˆ‘„”R©t9~¿?ðEÚlÖ£GŸ+ B­--ã³VAFö&Ë !ÄçóUWUUWU%$$º›Šâv»ÊNžlhl ‚Àæ‘ÍT½`ŒõzƒÔ)ú"—ÉŒÆhÇ-u¾ôtwÇÅÇ«T*·›Ñœ±qqJ¥ÒÜÔ$u³Ðjµén—‹åË"""Btö²ÔY‚…p0èZoii–:HoV«•ñyz#ûs2é%Ì]]RéKccCl\œ)3«¼¬”Í–LMM#„Ô׳Xi …ÑíPÚ¥Òctô鳬#B΂Á=c C”A„ššj–s¶µ¶¶´4§¦¥uv´···K§·ä”Ôø„„†úz+“ç·zzzèy–Wñþ¢}ˆí„ý…€‘§ºªª¶¦†Ù!GQiI‰\&‹Oèèè`mw™˜˜Øl63Û[E#¡À°Ÿ°Ÿ 0òôñ<¦ø|¾#‡aŽcpyôèfO¥ƒa6f²ð'°pÓ£¾AÂàAÂA „ €±“ÿéLÑÀ Œ$ì#ÈNȈÀ„ðô am¨ ሸ¥$€‘e(ŠËœ#¤A !£àú†Ž^¯W(!BHWÓ×BÀ‚!*.¡/„Ç ‚ðàƒ ‚°nÝ:Œ±p† º÷Þ{§M›†1v:+V¬Ñwk`¨ ]q q!¤AûÛß._¾cìóùž}öYúbh£ÇqÇaŒ9ÎÖЗ!-.¡œ5*½ýöÛ !‚ Ð…çž{.ø¸#z–$ì0O’‰vaÞ†! ƒòY£CQ\†dÖh`PŽã^{íµ×_rûí·¯Y³†¾!T¿ @˜†âš¡Ñ^Aßxã—^zIŽãV­ZµjÕ*BÈ /¼c¤úoxŠK !M°víZ1èsÏ=G{Ï?ÿÿüóÛn»Í`0ˆ©Þxã}ûöѹtEB>ü׿þÕáp sT0hÃY\‚ZËõêÕ«9ŽÛ°aC`P„]X¿~ýÆ !+V¬¸çž{Ôç 8@çéÉd²3fˆ¯Ožû¬ßïïUiô_|ñÿø‡ +V¬øå/9è¸!ñßÿþ×ãñÐå‰'ÒÍX¥RåååÑ庺:iGÌ!o¾ù&=zå8nÑ¢Ejµú²Ë.£ñššš6oÞ,ù5g7Þxã”)Sèz¬®®Þ´iÓÖ­[éhžB¡¸é¦›¤-„»wï/Q?~¼&77—.———wvvJ–ï§8Žëîîþè£Þzë-q(Âh4ÞtÓMŒì»cbb<ÏG}ôÎ;ïˆ[‡R©¼ôÒK%\ÑÝÝÝ[¶lyï½÷:::ħNZZZúöÛoóÍ7>Ÿ!„1ž3gŽ\†¿¸ òò z%£tË–-o¿ýv\\œ×ëíîîÜGËd²¨¨(¥R¹eË–ÈÈÈÅ‹/_¾œòꫯhd/„e©»»»¸¸˜^Èœ““£ÕjívûÌ™3#""è80ˆþuh gccãÖ­[o½õVŒñäÉ“W­ZGË»ï¾ër¹ñ™¡MxñÅÓ/œÅbyôÑG{zz0ÆV«uéҥ㴴´ôôôÚÚZ©BŽ?~ñÅcŒ³²²d2™ ÙÙÙ´Bû÷ïį¢Ã#ŸÏ÷ä“OVVV ‚ðé§Ÿ®_¿>>>!DYHèt:y䑦¦&BÈwß}÷â‹/j4„PFFÆ@?*„ =Ï#<ÒÚÚŠjhhxàèw²¼¼üá‡æyc¬R©è ¹Á`ÈÎÎîϹFÆ ú0Š[q |à !¿ûÝïn»í6„ —]vÙW\ÁqœÅbYµjU[[›øÎ¨¨¨üãF£QŸÏG/Y¾|¹L&{饗¤Z{÷µZ]XX¸mÛ¶©S§Ò=Ïóß}÷ ß³÷Þ{oæÌ™™™™r¹üª«®¢ñ8°{÷nÉ㥤¤¤¤¤ÐåãÇ[­VzåPQQÑĉéÎH¥RI{sïÞ½t„V¯×O™2åàÁƒb]ñx<ÒŽ~÷âóùªªªèFît:=zùå—cŒF£ÉdOcKÈãñ˜Ífz€ØÖÖÖÙÙ™ššŠÒjµ¦ây¾½½6Α#GÄVêêê~'kkkçÎK_OHH(++“,.èIŠË€»t?²zõê+VØív»Ýîp8ÔjµL&Óh4ƒNñÉd²ÈÈHFCßàp8œN§Íf»å–[è $Wùþûï­V+]ž_\\Ü믿ŽÎèÓ÷»\®{î¹§½½]¡PÐ7Ð×Ï|ÿððù|ÇŽ›7oÆ8??üøñâˆYQQ‘äGߢ#GŽ´··‹3&*œ:IDAT++¥š°Þ‹Z­—ÇiC~G‰`BŽ=JÏ­æçç#„²³³é·npã¢ÃÆf³‰ˆ´]®Q‰Ã2 ‹Ë`†F !gö™xž§9Òbq¡½½½½½}¿nˆìÚµ‹ž9ˆ¿úê«Å3FÆE©o¼111Qüß &îÙ³Gò„6›M\¦—ë±iÏž=t6Gffæ´iÓ¢¢¢B.—‹ù¢gEO¿QâÄ.F=©ŠKæPÑó@r¹œöè脸—ñûýôu:_KòKßDEEEííí ¡3fÐ6=yòdww·ÔÑ~’’ríµ×Ò`.—K£Ñp·bÅŠC‡I~©u]]ýj¢Óätµ&''_ýõ4óÖ­[ëêê¤ÍyèÐ!º– Å•W^)®åÀBΠ¤¤¤À‘già •a+.!¸é¶Ø¥s´bbbxž§Éü~LL Bˆž¸FA „öñ÷™„C‡ÑI(â¤ê½{÷ŠQúi!O¸råJ:‘Õår­_¿ž^bŸ’’²dÉ’7t^kh¶··×ÔÔäää`Œ'Nœ˜˜˜ØÔÔ„š={öW\!Â}ìP´!!äÈ‘#?ûÙÏèä[¬¨¨ˆµL©TªI“&Ñé±±±tJ3BÈf³UTTô]]Â>>|@ãá!O8 Tä´áLH£Ñˆcݽæ@ößÐ%Ôëõ≘¶¶6‹Å2¸Ï Õ)’!-.ïÙU5cžçµZí+¯¼˜Œ^âÊæ ¶oß.öB6›™„sçÎ-(( ÙvíÚµ{÷î+®¸‚îÊ,X°cÇÉï öÙgŸÝwß}cN÷ç?ÿùرcZ­ö /¤ÝÄÚÚZFî·k×.Z›éD §Ó¹sçNFÖ²H&“=øàƒ'NœðxQ­V¯^½ZòÓþß~ûí¶mÛè—266ö’K.™9s&-6v»ý7Þ`aB;v,pt±¸¸˜ÁÃ2³Ù¬T* æÌ™#VÁŽŽŽwÞy áh‚OßÓª×HFˆ·ìOȱ`ŠKÈz„ÝÝÝwÜq‡B¡8s»Åû|¾A÷²‡!äàÁƒt•³p}µtéRq€b÷îÝô&‡.))¡·Â™8qâ•W^ùÅ_H˜òâ‹/šÍæ«®º*!!¶¡ ¥¥¥7n”ðN­½ÐÑQñ¬S³‚EGŽ©««[ºt)ÎC)//ýõ×™š_‚X]7>††¡¸„¬Ò+[CõiÆÞã!ÔÙÙÉN!ܰaÃÆé2!„®~BÈÃ?,nH,lE‚ üç?ÿùàƒrrrA¨¬¬¤8Kž-Ðßÿþ÷×^{.³Ðn¢'žxBœùFùïÿ;aµZ]WWרØÈB3>ôÐCâW.ð„Öo~ó1ùð÷YÅvë•êæ›o¦ ©¾øâ‹¯¾úŠ.K¾öÅܺº:FÎÚ¹sçîÝ»é²äm%†âÖwÞKOO§·àB=z”1¨s%a'¡ˆî¬O:uêÔ)ÄêŸl7ªW0—ËuðàAÄR3²ùU<×o?ëÜ:Õbˆõ—Éd¢;œ?þ˜µ,bª­†S˜ÂyóæMš4iÊ”)z½!ä÷û?ûì3¿—#4]¨@KŽb&99!T[[+ùsÊ@ 0-„³gÏ.,,ïõí·ßJ> 0º¥¤¤TUUq·uëVfG)ÂS®#¡½n&11QœÜ±sçοÿýïAÎ;ÒkB/œVVVþñ<ï¯8¯‘Þ†Œ’ëG–W^y%;;ÛívWWW×ÖÖÂÑ`¨ˆòžÂ´–••‰Oc¯&„³0-„PüP¬ŸB¡ÐGÈd²‚‚‚~öIyžïééè3|>ß¹Ö.!Äívk4šþã#„ôÑy‡„ý ƒ ƒ ƒwÞ„ª2ý¬/­,½jÊOª(!D­VGEEÉå ÝŒÛçóuww{<ž³®ZBHtttVV–V«þl”Ë媬¬´X,pÐ að að aðΛPò*sfMéݤE’©Î5ÍÚÇ!c,afúÛ!a0 að að aðú“IZeά)¡?cŒ p€°…@XƒB ¬A!Ö k2 ¯»$=Ba !€°…@XƒB ¬A!Özßÿ;>>>77—©ò<êÔ©¶¶¶s½AòÌ#=¡Édš;w.S`øùýþ;wÖÖÖöñÆ·e ûáÌ„?Ù÷B ƒÙlfíéƒá\ÍÊBæ2f̘~>€Q cœ››ÛG!d|[F°ÎL(ï•Æëõ²ve!!ÄëõöÑj’gé yžgm¥0üÈi}¼‡ñmAÂ~83!œ#€05† œ¶(Šø„kO^op:‹EêD£ÂQB¡Pdeg'&&©ÕjŒ±Ëåjmi©¬<å÷û¥Ž­N7yò”S§*²²²[[[º»»¡«:¤ Ž*•jZÁt¹\^S]ÕÚÚJ‰OHÈÌÌ2DEí/Ú›#Ƙ÷û1Æ<ÏKeôƒs„£ÁøñäryѾ½õõõjµ:""²±¡aÑ>N—•aqü~_cc#!¤±¡Že‡ôG<½Á˜xìØQÇsá´‚„„žçÝn÷žÝ»’““««*¥Î›Õºsǯ׻kç‡Ã!uœÑz„#^B|‚ßïo6›M&S||üÁûOªÐjµ~¿ßÚcÕj5R Œ N§!Upx@!ñ4Z­ËåD%$&Ùl¶ööv…BAçÈøy?ưŠ /°—ñdÇûy„ötET*•>Ÿ!¤Õh½^¯Äù€mPG<Ÿß§P*B<ïר5:]DT”QàŽãRÓÒÚÛÛ¥LƒB8âõôôèt:N×Pß©×Ïž3§³£CqÉ¥— ª¢¦œ@~r¯QÆçÙŸu‡ÎTfI656æææÍwøÐÁ¦¦FBˆÏç«««åyÞãñôŠtfB¦œëØ‘©EÚýá‚«¯ ü]6›mçŽíçÝÛ VÛ.ŸñA()>1yÊÔ™…³šÍMN§K¥Vi4šŠrè †DUee`Is{<† ÂÑ µµuïž=™™™é2™Üï÷u´wH 0jUT”÷zeDvC!%l6ë‰Ç_ÑßKËFÙî áè1ʾš0<`Ö(€°…@XƒBø#¥RÉÔì^C-¼ !Çq²³‘Ëå¡uëÖ].ÿÕ¯~5}út½^ßØØ¸aÆиæŽ;î(,,Ôëõmmm}ôÑÖ­[‡ô0–çùææf«ÕJK!„~ !ÆétÒÿÅwuu544´µµ‰ æÎK–””ÔÕÕI'Ñ]Ø©S§Bô Þd2 †âââ^…B¿`ýßå%$$Œ?¾µµµ«««?ŸÓ÷¯ ?…¢È,x,L¨ÄÆÆþêW¿R«Õ7nt÷`…ðæ›o~üñÇår¹ÕjÍÍÍ-((ÈÊÊZ»vmaaáâÅ‹éÖØÔÔøO^ýõÙ³gûý~§Ó™ŸŸ?gΜիWvìØ9sæÆM›6 ]-ôz½/¿üò¹~Š1¦ƒ;wîܽ{7S££ãÆËËË£¼}{ï{úáÔÝÝM÷ˆ1îèèÈÉÉÉÉÉ©­­k¡ÓéìììÔh4G¡PÄÅÅÑרØÈq\rr2}›ßﯯ¯‹‹‹ŒŒlnnæ8.66¶µµµ±±Ñd2Ñ_dµZµZ­Ãá0 QQQbͳÛí‹E­V»\.­VXéOU*•Ó錋‹ÓjµÃØ< _ŠŠŠ`+‰Ç{lòäÉ÷ÝwßþýûKJJת8`¼úê«årù_|1cÆŒ‡z!tÕUWéõúýë_÷Ýw߯{%¸è¢‹fÏžÍóüÏþó9sæ>|X£ÑЩ(“'Ož9s&!äŽ;î˜5kÖ¿ÿýoŽã/^<Ô°r¹\¥R ‚°páÂãǯ[·!¤P( ÏóGŽéêê*--A.—Ó³qŒX´hÝÏú|¾O>ù„ Î!6›Íb±DFFêõzú¢Ë劌Œ\°`ÁÂ… ¯¿þú‰'ºÝnú£yóæÍž=[¬XF£qÁ‚¹¹¹¡+®¸bêÔ©ãÂÂÂ[o½•ã8‡Ã‘••uà 7,Z´hñâÅYYYâ(½Ó錎Ž^°`ýѸqãèÓÌ)¿ßŸ––výõ×/\¸ðÊ+¯4 L l„!äã?†B‚ ¼ùæ›:î®»îô˜óöõO=õTDDD}}½ÏçÛ±c!D¡P$''ŸþøãtB Ëåê0"Ž‹ž8q¢¾¾^ê8àG‡C«Õêt:Z¨"##ÇŽËó|EE…V«MIIñûýcŽãzíû8Ž£‘‘‘---ô™!&“)))©££Ãf³ †¬¬,­VKG\ŒFcnn.Ïó§NR«Õ©©©¡ÖÖVú Ñétuuu2™,111++«¦¦â!‚Ïç«®®>räÂ~úúë¯#""þð‡?ìÚµë¬öÙgŸ=üðÃóæÍÓjµât¶@!,++C§ïãµjÕ*ŒqSSSEEŹz'Û¶mûöÛoB‚  †3f`Œ‹‹‹BV«õرc¡E‹ †eË–aŒ·mÛ6¤ß •JµfÍšää䯾úŠÖ9‡Ã‘ŸŸ¿lÙ2—ËEgëÑ“.‚ Èd2§Óùì³Ï²P'Nœ˜ýÿÛ»·(Ú?àÏìùè!]MÍ׳•X"YiÔE…˜ÒUD]”$D…–éJeQ]DetíEat‚¢0°T¨ÌvuMS3]m×vvgvç½xx‡mu×ÃßÃøßïçjœ™vŸvçy~ÏyÓh1÷òåKäI¡)ZÁòz½‰‰‰n·»½½ÎÉr»Ý111´75›Í¦P( ß?è¡Édr8:nllL.— :Ÿ9!!A„/_¾Ð¬§R©ÒÒÒÆÇÇi´s»Ýf³™¶=Ott´Ñh]‚ftûöí;wîBÐLŸ½˜˜£Ñ¨V«Ýàr¹ºººrssóòòž={6rP|õ'N9rÄår]¼x1È×I‡ëéquuu||¼Åb¹{÷®8W…RSSC×°wvv^½zu±{üh\œ/J¡õtßó4ÞˆUu)(..¦ý´n·ý¢RC¿úØèt:Fòl\\½ªR©T*•^¯Ÿ˜˜˜ÓËr“žžÞ××7888>>N'”êt:µZm·ÛÅÇàû÷ï###b ¥Ë0è1í2U©T ðÿ„…€Ì;999„ÚWWVV¦Ñhèù÷ïß¿}û–æ4ÑÅo‹©œ‚ ô÷÷ÛívƒÁ`4£¢¢’’’4Íàà í·÷íh¥“T¤Ó‡+Ž\.×h4~÷¾©­­¥%6!äÓ§ObyH»=‚׃˜s ¬¨¨ ÛÙDÁ={öTUU)•ʆ††––ñŸìß¿ÿÌ™36›­¤¤ÄétÒu r¹\©T.j [ss3µåõzé;Êd²œœ“É”••õøñc·Û½ìõ jß¾}ôqD¿¨DpG$úädgg3 c³Ù!‡C¡PÐQ=ZoeYÖétšL&BˆL&S(v»]£Ñð<ï;v@þ+tX–åy^§Óåçç ŽŽÒ¹6‰‰‰±±±ÃÃÃv»ŽšÍfƒÁàñx"""6mÚÔßß/…ñlX¡‡Ùlö „Á¶—Ess³ïŸb¢Ùmddd~M…9ÂúúúÜÜÜ–––†††à…rrrr]]N§³ÛíÛ¶m£ë%!ÇokkS©Tééé<°X,ùùù2™¬µµuQs²J¥*--Õëõ4Ùt;+Bˆ ¦¹¹™¨LNNìܹsdd¤©©Iœû¾\òóóis°½½}hhhyä¿'‡ÎÉüçŸÔjuWW—˜ýl6[lllFFFoo/Ã0±±±qqqf³Y–e£¢¢âãã"""²³³}+°G­Vk4šŸ?*а°0½^ït:GGG⣣ŞUú)))V«U§Óedd(•ÊePaE{ýúuQQÑÔóRhÌ8k”'ƒ9s„111IIIQQQ3Þi2™ÂÃà !F£qûöíây•JÕÛÛ[UUuêÔ© 6lܸ‘ã¸'OžÔ××/ê‡.—ËÅ-ÖÄót‹5ƒÁ@?bA¢££SSSµZí²÷ ää䤤¤ÐãçÏŸ£_tyéõúU«VíØ±ƒ"ÇqÝÝÝ¾Ëø¬V«L&KKKËÌÌ$„x<ºv‚övjµÚììlûúúÒÓÓ].½úëׯիW¯[·.33³µµÕl6'%%mݺ•Â0ŒÝn·X,ô K#Ö®]»~ýzBˆÝnïîÂÃÃ}+õr¹<22ÒívÏo„A¤ó¦5ã¬Ñäää””‹Åòõë×ù=ç¢3 “œœ|h]œ]éפÓ/‰O B<ã‡Þ@¯ÆÅÅ™L¦®®.–eƒ™ÚGx6iöM| K Ã477gee566^¾|Y&“Íig™…J¡ŸšššC‡ÑÉ»vížÇ‹O!Ã0»wïÆ|ŠÙ´™ÙÔÛär¹^¯ÁápøvÒ6Q«Õ“““GÜäO¼j0xž§]# ÃÐŽV–eÝn·ïÑK´Éè{Éï§=Ax½Þ ë¸þ—¼¼€©´Y@ ›BqmR ï¥ººúðáÃ.\hjjše¡í—Â9·½ÍÔ Eð*½Úßß?00°”¹tÚ/€îdmµZ³²²¬V+°dI B܈äÇ~ó/`éÍòAçùi×K‚àr¹Äp¿¤[ÕøþIÓ¾Çqããã3¦!VºàMÕ¼¼¼’’’?Þ»wo)ö]$K™QƒL•••çÏŸÿýû· R˜/š——G÷œ$˜/ 0£GVVVÎ{Ê(‘B ”–e%5ã °°öå²,ûðáCÌðsíÚµžžßqúy@ ”.q¾h[[úE¦ò]M8o„ÛÖÖFg?}úÍA€©dÌP¢†‡‡Å½ßüV^ÀB ”.´–6'€†@! B!„4Bi„Ò ¤!@HC €†@! B!„4Biøõ ø?¡R©Ž;Æ0Lcccii©ïÁ7ý¤!A†YîT,€5kÖÐmêA BAxžW*•‹šÊyày>Ð/ÓJ$Í+7…‚ °,«Õj !Ä ‚àt:ƒß å¼LBBÜn÷¹sç!^¯wêA ú—}Z­622R¡PK‘ã8›ÍƲl –=Í+=…QQQ©©©:n‰S )N§óÛ·occcAî‘x^&Há,LM!@!hBµcVˆç¢Û¥ètIEND®B`‚java-algebra-system-2.7.200/images/eclipse-legendre.png000066400000000000000000006334601445075545500227340ustar00rootroot00000000000000‰PNG  IHDR}|ª%«sBIT|dˆ pHYsÄÄ•+tEXtFensterklasseEclipse{¹—‘;zTXtTitel™óJ,KTÐUÈJ,Ö/.JÖOM)Õ± òs*õ]+s rR‹õ² Š\“s2 ŠSÈÀâˆL4 IDATxœìwxU×À[³IH%¡w”¢ôÐ{“"‚ ذàûªAо6¬èˆ•&b¡‹  H ¡H“jBz϶ÙùþØdIBv³›lŠrÏ3ÏÎÞ¹sî9çÞigî½£¢¬zSÉ•ŒÈ²½è&@ @ A$4 ŒçîyIU0ÍùgŦ/” Ð`‚ƒCШ5hÐV¼†@ @ ¯ ›ÍFvV&Æ#c†>¢‚¼ ÏŠM_(ÕkDRËP µ¬A…ʽ4@ @ A•AQÙ±«ŒWIKNåÁaª´A!ÁÔ6ÔB+ë*WAEAQT**•< @ @ (;åo¨2²-;Ôö¯5Ä€æƒUo*ë7Æ_©†ºzøÈ²ŒÅbÁh2£( Õé±X,˜LfEF­V‹@ @ ¯(ÏxCU–­B…ì¯p[¯–s´¹’JJ.•.eB’$²sr¨U§aaáŽDÇ 3ÒÒÒHJˆ£Zµ tºÊí…$@ àŸAyÆþ ²5*-F)µ,ÛѨÜLÚ¬R¡5©ñKÔ¢ŠU‘}þX—ÆÚïRøþ›~ޘȑ#dgK^bµZIKO§QÓ¦T Âjµb±X°X-X,¬’•àà`6iJJZV«Õ+ù@ øwÒ»_ÿÊVð—¯\aìø‡|"Ër½±«`UÉe±ÁÕRU(]ªŠ}eõÁ|UÅ&@ Tåoø§ÈÖ¢Á.Ë%¢K—¡¦š¾öp- R.'â²H4ËX­«•Ät‰cgRhpÆ@Tç4lT¢!v»¤äš7oŽJQ°˜Í®UkhÔ¸1çNŸ¦víÚh4šå @PÞ\¼x‰ çΔYξ}û4x°4ª¹®Ê¨êþ𴼋/›Ï¶UU|Uw¾ÀWþ¯J6  b)ÏxCEÊÎÌÈ@¯×£V«yEÁd6XÍcÙîƒ>Ù2:³êP=’Á€”!aÔa±JX­VÌÇb2Y8|$“ìœ\FlFX˜¿[±9¹¹ Òj0¹q€„„N§Ç@Nn.!ÁÁnó @PøêòϽ{yfÒ$ŸÈª¹®Ê¨êþð´¼1PP•lö•.UÉ&@ T,åop'ûèÑc´iÓÚg²_}õ5453fÌ@£Ñ ( ΟÏÅ‹ùðƒ<–­v¹P'ËØr­$§™‰OÊÅl–0-Xò>&³“ÉŒÉdÆh¶°ÿ@ûĹ5D–eÒÓÓ©^#³ÉŒ$I%.³‰ˆÈHÒÓÓ‘åJ˜|H U’'O2é™g‚g'?OzF†3oVv6ÓgÌàöá#˜>c&ÙÙÙE«€ÆŽãêÕâââ÷ð#.Ëó„)Ó¦s€½ûö1}ÆLìîݯ?›Þ£FsǨÑìþóOöGG3úž{é?h0;wí*”וÝqW¯îü\Oê®"Ž)Op×î]ÙäΟîüäο@ ¨šoˆ=Offf¡Cnn.§OŸö*Þà.–±vÍZžxâ –,ù²T±ŒâdO™:…Ó§ÏðÚk¯a2™yÿƒعs³gÍöJ¶ë JSr¹—MBB6W¯fŸÙ"9>f F³£9/ðc²pàз•`·Ëdgg£Õj±Z-×xvíÞ…ÅR8Ýb± ×ëÉÎÎÆnA@ 8xûwyòɧ8røS¦Laá'‹èß¿?1‡pðÐaú÷ïï6yé0çÕט3g§OŸaòóÏóö;ï:·í>@÷î=$©Ä¼!!¡¬X¾€ÅŸ}Æè»îâØñüç?ÿu+÷˯¾â…^àðá# 4˜¥Ë–;ó~úùôìÕ‹19}ÆóÞEË(?q‚½{÷1|Ä>ûü gú—_}MŸ¾ýˆŽŽfè°a|ñå—ÅêÙ§OöGGÀÜ–WÒœ2³fÍâ“O?ÅjµòÙç_0kÖlì8Ë®]»yã7ùzÙ2NŸ9ËŽ;X°`!s^}­P^WvÄ]½–Ô–\QÙÇTIþw×îÝáÊŸîüäο@ ¨šoøfåJ^øï ÎÀOn®‘iÓ§óù_xopËØ°~ ,`Þ¼wøî»ïY¾b¹×±Œâdø°|ŠΞ=ËÃ?ÄîÝ»Y¹bááa^ÉvôQ@Mb›Æè›ÖÄ¿n85[Ö¥ã6 | Š¡õdäÄ~ÜûÔ팛<ŠG_º—'g>H§A½ÜV‚ÍnC–e¬+V‹Éj-´ü¶ý7LFc¡4kÞ"ÛíØì6·ò@pãðë/¿Ò%ª3‰WãèÓ«yoð»víêìsè]¢¢Üæ//=òuÙºu+ë~üv·ÝÊï¿ïpnÛM¯^=ó®¹îóôëÛÉb`ï¾ýtêОøËéÖ¥3?oÙêRîî?÷P=,Œø+—èÖµ+;wï¾–wÿ~†JrBHZr½{öäÏ={‹Õ3**нûöŽ O×¼¶àª¼‹/»äBTTžázöêEpµìxö™gÉHM¦cû¶œ:ušqcÇ’ž’Lû¶·a³¾¿qewAÜÕkImÉ•}L•äwíÞ®üéÎOîü+‚ªIqñ†™3gÊ”©SIMIá•WfbµZyó7½Š7'û§Ÿ~bá¢E|úùç <ˆ¥K¿fÕªÕ¬þvu™egef YÌtèØ‰ø« ´iÕFEFzºW²µ ×ß°9Ò¡ÚŸ'Ùš`!Û,a¶8zö˜LVLfGÏcÞ¯ÉlÆd¶b0¨¼b¬ÛаJV$››Í†RäfqþüùÄž;Wè­›Z­vdóî a@ øwsòøQÖ®_Ï™3g9sö¬3½M«–¼rì’$qôèQæÎžl·¹Ì_”‚= vlßVj=Þ~ûmž{î9¦¾ü2†>ü€Í›c·Û‰ŽŽfÚ”)%æÍÇO¯Ãn·ŽÏuÚó¹99äæä+7%%…½{;ÿü¼gZZ:EQðÓ—ø}—e”‡? zdYF…ªP@!9%YIMM-V—ÛÚ´aúôédeeqòäIZÞr 6›ä²¼’æ‚‘¬Vî»ÿ>–-_Æûï¾_è~¥¤ö¥BF–eÌys¨ptç6ææ\—וÝqW¯%µ%WTö1U’ÿ]µû’påOw~rç_@ T]ŠÆ²²²Y¼xO<ùN˜HãÆMXºô+RSR‘$É«xCQÙ6›Ï?ÿœÆqñÂy"ªG°|éR~úé§2ËV……‹} †ïVÇ‹/¾ÀœÙs˜˜½‚·§Åk/,fÖäxùé˜òø;¤9â¶Ô !!Áœùû4I²Zã× §©5jN9MHH0jô‚Šºuë³nÃŒF#?®YC»víœÛÎ_¸Àí·ßN‹fÍøè£ùÎtEQèÙ³ëÖo GΗ ®òå¹3ÎÅÜÉ;þ!¾Y¹œøËÑi4dff°o4}z÷)pp•·8 èÏ¡ÃG°Z­lÿíwž0Ñ¥Ü~}û±ã·mœùû}øÆÞ^@Î֯߀$I¬øæ›BehµZvîÚ…ÙbaùÊ•ÎôâÊ(¬Xù F£‘Ÿ·neàÀÎôÞ½ûð˯Û0›ÍüñÇNzè‘QY–éÞ½?®YK÷îÝm¡$\qñâ%Ž?Á’%K8ü×_\º|Ù#»½Å•ÝqW¯Þ´¥‚T•cÊ®Ú}I¸ò§;?¹ó¯@ ª&®â ÙÙY\¸pžO?û”¤¤D23Ó½Ž7';6ö,—/_*¿ˆ¿Â™3§Ê,û¶ÛÚ²jÕ*d»ÄÅ ÈÌLgå7ßЭ[Wïd»õX¤M€Ž†‘T÷S;'k6š-׆tY¬˜,V,‰nQ è×ë&·"5j5¡!aøùùqüÄq ƒÛ/w Ž=F€ŸÐ04j÷* àßÅÜ9sعk7#GßÅŸîaÆË3œÛæÍ{‡)S§rßЪU«BûuîÔÉñÛ±£GùË‚;¹ï¾û+¿YÅ€ÁC˜:}: ,`÷îÝtéåQÞâ˜ôä“lþùgî5šU«W3þG.å>ýô$¾úz)#îŦ͛y§ÀdµÏLzšØ xàÁ±tïѳÐ~ù ß}ï}´hq³3½¸2ÊÃM›6eô=÷rüÄIžzò‰k6MzŠ˜ƒ9ú.vìÜÉžÞ¥>;vÄf³j ®Ê+i"áE‹3mê4ÒS’™6mZ¡‰‹}Ù¾\Ù]wõê®-ý*[A*û˜*Éÿ®Ú}I¸ò§;?¹ó¯@ ª&îâ ÙYYDïßKFzZ©â åË(NvîÝ1›$$$ I)Éɤ¥$Ó·O?¯d«^ýúee@ÇÙBP£º.ƒåª )Máj²‘=§â9pê i™9˜ÌLfǧÛŸúŒ½¿·µ®]bEȲLBB"'NžÄàïOóæÍ$+6IÂ.˨ÕjtZ:Ž¿OÂj±Òò–[¨U«&jô‚ ½Þˆ5ÑéõX-R’‘$+Õ«^µJMff:áÕ#= ´:õ4"îÒEò{Kï~ýs“¸“ëg0P=²:c8JrbÆÜê6hDÒÕx§nîò4jÚ¬®jµšˆ51ø`“$R’±Z,ÅÊU«5yyý±IÉI HV«SNdÍÚèõzÒR“‰¬YÛYN@`5"kÖBQÒSS¨Yƒ çÎ[Fyø£w¿þ:xаpÌ&)I Ξ9MžMÌf3)I ÎùŽŠú*;'—^z‰%Ÿ}êœ0¹¸ò5mæ²¾óåÕ¬]‡¬Œ L&#þ‡„’x5¾D»‹êäî¿;» æsW¯Þ´%O뮼)OüïªÝµËSºó“;ÿ  êRžñ†ŠlY%“£Îæ—˜­%}¬Y2æD9Ù2i9f–­æBB*f«DãF!Duj@¿^M©Y3ÈãŠ$‰„„bÏ_ 3;“ºuêY«EÂO¯#9%…ËW®J“ƨU«–˜@O •Žd³±gÏæ¾ö?¶mÝRÙêT:åé‚ÁˆÒb6›Y¾òªqÿ=wûH³òÅv{ÂÒ–+ÊŸ@ ¨:”g¼áŸ »`ÐÇ£ÏtèƒÕèƒõu0ðv¯âÇ–{ƒN§£víÚ˜˜DrJ ‰ ÈŠŒZ¥&00æMo¢fÍ„„„8'Ñ 2ùîûïYòåWn‡^ÝHTuÜy×Ý´jÙ’>úÉb®luªU½î@ (-åoø§Éö¨§Oy¢( ’͆ÉdÂl6c·ÛÐh´ üýýÑiµ¨T¯—@ ÅFhxõBÃ@ndÊÓE‡!•†›bµXHJˆ÷zÒæÊÂv{ÂÒ–+ÊŸ@ ¨z”g¼¡*˾nx×ÀŽƒ¨f ®” @ @ À7ÈÈährø%fK _ï@ @ ü#A@ @ ‚!"è#@ @ð/D  T¶@ @ Ÿç=}@ @ þ…ˆ @ @ Á¿¯ƒ>½ûõ/v)¸½¸õòÄ•NîÊw¥gZZšOuË5ùð£}Ͻ <„1ãÆ³tùrdYöi9•IQŸß>|S§¿ì±/wîÚÅ€ÁC˜=wn©uðu½yCï~ýÙúË/Ŧ—EfY©HŸT•v^žçœ‚m¼Oÿ >‚7Þz›ÌÌÌRË++¾®ã²Ë埇áêÕ„Bi»vï¦w¿þìþóÏBéW¯&0Òû¸¢®]žàJOu¬J¶@ *-€J¥òj§Û·•j[yR–r îûð„‰¬_ó£/T`Þ;ïÒ¢ys–~¹„€€rrrX¶b%Ÿ±„Ç›è³r*›‚>4|÷Ã|¼`!³_™Yâ¾s^}9³^¡K—.¥.ß×õæ-«¾]M¯ž=1 >‘ç‹ã¨"}r#¶ó\£‘íÛ·óÁü˜3ë•2É*-åQÇe9–Ë‹^=z°gß^Fßy§3-ú@ 5â@L Ý»us¦ïÙ·—n]»•w=@ *›ü8ÞU„Ò¾µwÅž½{uçHªU«†Z­&88˜î»—M›7û´œªD@@÷Üuûöíó(¿Íf£gè´ÚR—éëzó–;F gÙŠ•ªCQ*Ò'7b; `ð Aìõ°—å]ÇÞËåEÏž=Ø»wo¡´èxü±‰DG(”¾wï^ºwï†@ @ (‡ «®ä¹F#¯ÌžÃÐw0sÖ,ŒF£¯‹vKff&ÿyáE†Á¦Ÿ ?ˆæë\ô×Ô©]›ß|Sh˜Kxx8ë~üÁù?+;›é3fpûðLŸ1“ìììët+îï~ýYýý÷Lxü rrr˜9k6ƒ‡åá 9uê”3oEû_¥R¡ÑhJ,¿¨ÏOœ<ɤgžeðÐaŒ¾ç^¶lÝê”áʾâê­$Ÿô›/¸cÄÄÄ\7%Wv7žøøxâãã3nüõ¶deñü_àλîfíºu…¶¹’[œOʳ xÒÎÝ•ï®Þ½içÛ¶ogÄ£è?h0;wíò™Åa·Ûñ÷÷w©«§Ç¶;ßxÓî˃¢ÇrIç¤ 72fì8Ÿú¿Eóæ\‰‹Çl±€,ËtëÚHLJÀl±{þ­[µòJ7w×Wu8fì88Kï~ý9~âqqqŒ;Î'¶{‚§Çvï~ýÙôÓfn>‚g'?OzFF…é(@ ¨JôñtÞœ‚,ùòKyè!6¬]C—¨.|½tYiŠöX§¢º-þì3ÚµkËš¾çø‰ãÅÊÈ àË!Ó§MeÛ¶íÜsßý|ôñÿ±s×nÎÅÆʳäË/騡#?~·šž=ºóù’/=–ï§×óÞ¼·øäÓÏп›Ö¯çáñãxsÞ;…Ê(Oÿç#Ë2ñW¯òÍ·ßÒ­[×Ë/êó·æÍã¾{ïaÃÚ5L|ô,úÄ)Õ}ÅÕ[I>-è7_ V«yâ±ÇX´xq±Û]ÙÕ¥sg¢8z*DÇÄÐ¥sçëöýì‹/èÕ³+–~ÍßE®äºòIyµOÛ¹«òÝÕ;xÞÎŽ?Áwß®bάW˜óêk>³±(F£‘u6Чw/—ºzzl»ó7íÞ—¸:–K"öüy–|þ™Oý¯R©ˆê܉ƒ°?úQyÇJ·®]½}ýìsŸé(@ ¨š8raÇöm…Oعk7 6@£ÑУ{7þعÓ[]½Ò©¨n{÷ígè!øùù1îÁ±>-Û-š7gÅòe¼6wááá¬]·ŽÇŸ|ŠmÛsæÙ³wƒÀßߟ>½{_71©;zõêEhh¨CΞ=téÒ­VKŸÞ½ùê‹k7ôåíÿü‘¾òÈ„‰$&&2ùÙg½.é—_Ò»W/ôz=ƒ,4|Å}E)ɧýæ+Ú·k‡¢(:|øºm®ìêUèÁ±¸Å?÷ìeÐÀòP^O ’äGy¶OÚ¹»òK²ÃÓvððÃaðó£gØl6ŸÙ…Ûù˜qã¹rù O,4Q @P1”~/IKK£ßÀAÎÿ:®¢Š ##Ãù Q¡e«U*Z¶lIË–-ûàŽ=Æ«¯ÿþýúššJ`` ƒôôte‡†„8×323ñÓë‹ÍWÞþß±}²¢ðÇðÕÒe<3i^—Ÿ••ÅÚõë9sæ,gΞ-´Í}E)ɧýæK&=ù$s_{…ÿ÷q¡tWvµm{oΛ‡$I?q‚™/O¿NfFF†Ó—EÛ®;¥¼Û@IíÜ]ù%Ùái; ò…9ÅâI» ®žÛî|ãM»÷%Ë%æã`j>·Ýz+ÿ·`!²,sìøq^ž> €[Û´áÍ·ça±X8xè0“ž|ÒkÝÜ]\Õaûvíx÷½÷±X,œüû¯Ì˜Á}c$''‡cÇ3wö¬2Ûì)ÞÛ5jÖ Z` YYYå®›@  r©° OHHß®\¶ “õ–…°°0RÓÒ¨Y£éižUÊʈ;Gñãw« Ý„7kÞŒÜÜks.„††’››KPP&³™ ­Åõâ(øåµðð0$IB_ÌbEø_­Rѧwo222xûwøß«¯z]þ˯¼B«[Zrû!Z­–»va¶XX¶ÜýסºwëÆ¡Ã‡±Z­lÿíwžpmØIEúÿΑ#1M…&Jõ´üØØóôë×—[Û´æ›oWÚæÎ¾¢õæÎ§åÍØǰvýúBiîìêźõˆŠº~>€=z°qÓOä,[Q¸íº“[Ô'åÙuŠÇŸšÄ !·3ñ‰'IKOçé§® Axl£ìŽfäè»øí÷…†'äO8z÷½÷Q¿A}·eM|ôQ6nú‰;Ffåªo˜™7üÊßÿEyñ…ÿòÙ_8¿¶ãiùÓ¦¼Äÿ^ƒ‡@ãÆ msg_ÑzsçÓòÆßߟûï½·Pš;»ò`£\ÌòðøqD8Àø‡¦]ÛÛ }IÉÜë|RŽmÀ£vî¦|wvÅ];¨jxÚÝùÆ›v_=–½9'ùšN;b0œóùäÓ¹S't:]©ƒ>î®îê°S§ŽdegÓ±C:´oÙl¡S§Ž¥Ò£´xslש]‡Ñ÷ÜË_G2a£¨¥@  BQ9&oV½úõËÊÀŽƒ©f BMù y¾!33“ñ_Y7¹UY·Eý\‘>­ˆ:¾sô]LŸ6•¶·ÝÆ7ß~Ë­mÚ”I^UëÊñáËz–l6öìÙSió›¹¢*Ÿ¯<Ñ­(U¥í”…ª\'@ ‚¢§@PÅÙ¹k }BJj*­[µâåiS‰ŒŒ¬lµ¥då7«XòÕWÌ~e&={ˆ9U‡èé#@pcP°§ú@ @ üK‘ÉÑæðË-7‘³@ @  â(4©Dƒ&79×U*Š¢¸üïKÊCvYõö û…ýÂþòÔ±ÅE÷*“ü†x£"ìö û…ý7*Â~a¿°_Ø£"ìö û…ý•N§».­`| ((ȧ,Aù¢ä-P$èc2™e¹PÔP­V;× þŒæS\¤°`±`Þ‚éjµºP¹·»“Qüô²ê/ìö û…ýÂ~a¿°_Ø/ìö û…ýÂ~aÿdHHÈueäÇÿl }ŒF£s½`ã-®1M+øßݶ‚iË*nÿ‚·hzqò‹ÊôVÿ‚û…ýÂ~a¿°_Ø/ìö û…ýÂ~a¿°_Ø#Ø‚"ËØe­Ö&(üsqÔf^åçææ^×øT*U¡è^ÑÆ’¥ÌÿÍÏã{-Š©Ñh°Ûí×)_†¢(Å6Ô‚û,ÃeÕ_Ø/ìö û…ýÂ~a¿°_Ø/ìö û…ýÂþÍþœÌd’RÒhÚÌ1O~|@ð%¯^ õô)Ú Š6âÈßÇUc,i{IÜÏ[eÕ_ØcÛŸ™Áùس˜&¯Ê-Š!ÀŸFMn"8$Ôë}Eý û‹[÷a¿°_Ø/ì÷D¾°_Øïëý=Ù^Â~aqëž ì/½þŠ¢™žÌ•K—hrÓÍ×å)I® ê¢u·ñŸ^±eÕ_ØãÚŸžžÊùÓ§ §fDd™ô0šLœýû›· ,¬z™dyƒ¨aeî_Ùû…ý•¹e#ìöWæþ•Í`hµ€Bÿ323¹wµJƒV§=3(Š‚M’;õëÖ#´È|=9ÅÛJMO%))®"T¬4â®\&&z?9ÙYPõw*¨L‡N©[¯¾×»_ôÑiÀh2£Ó|¢Ÿ@PV*£M&ÅÅQ»VmÂÃÊÉÞ$IÂàçGR\\…}þÉTF‹sß¿Q·®¾©:ˆº¥!5-•‹—.Óªõ­W¶:‚*FVVÇýEÃõ©^òsH`PµëÔ«Í*‡Kγw÷N©Ú ²Õñ £ÉÄî¿Ñ¥{O4jìվޠJE~@Ø µ—šHÚ }­§@P**£Mj4BCC0Ê~ó/+WL„æ1•QçâÜ÷ïEÔ­k„oª¢.Aiˆ‹ç¶¶íhܤ©Oî[ÿ.Ìf3Z†Çþò(èÓ°ñÍÔoЬ4«þ>~Ìg/ö+šüŽ?æQÐ'~'(¦§OÜÕ8.]8%n:U†Êh“þz½Þgòôz=þâBì1•QçâÜ÷ïEÔ­k„oª¥© óo£œë†¾kÊC-¯°fî¤Û€=Îÿç¯ï¢éYŽ ª2Z­«Å‚ÞÏ›ÍVÙêücÑju4hÐjÕªU¶*‚*HµjÕhа!§ÿ>Yb^Ç$ÒZ4m±Ãÿ CKBQŸ½Ø¯hò;¯š¼®‹BATáuhÙ&Ÿ*™²ï~"¢VùT¦/¨H½T*iiiÎÿf‹…ðððëò¥¥¥aðósþ/ÕAV°¼âÊÊ/§´òÝ–m>Tlºbh罬2¶ÉvJ;Þ»º˜ñ‡È5åh Cvô¯U*yžrêØfÔzÍš÷u¦ùú¸òËÕe¥Úϯö¸J‘_^ç!w”¥ÌIoÍaá´9¾Wª ø…û1?f)ÇÎüMŠ9 €C0­›ÝÌä㱤Y*TŸmÛÏläðåsøÛ#PÚéP³½›w"ØR¾7ªÿ–ëZy”Wßd$fp0:”D 5ýhß)ŒÐšÞOXÿO£ÉÉgùjuš4ŽÀÏ ¥y³Ú¤‡,³\oë"ý§!ôú—ã¢â·ymús™õ( ÖLÇאַéñêsCÜîSY×EAåãïïOzJ2ÁÁÁ˜LeûhÆŒ¿¿?þ.·/Y²„… 2lØ0æÎ Àìٳٴi“&MâÑG­(U•„@ÀuçZWçÞ¢ŸlÏÏ—žž^¾Jú•Jå &÷|kðósûbÿ«Y/ñð«ï¸Üž­`òç‡èÐ4Œ§»×ð‰ÎÞ ×ë Å <庞>ÿ þA>Q*Ÿ”}÷3àñ}üúiT• üT´^©iiÔ¯ç#™‘™IÆÅ#ŒŒ¨NjZºs­ËW®æuyiii4hУÑH```1åD ( —.]"¬òÝa“5´é<–‚ÓÈ\÷R-5*ThoõX–·mòÀ®½ÎõǺ?ÅÄ£S‘ä †ßÚ €`ÒrSÙzl/G“Ïñ|Û1Ëõ†ü€Jãv®ôëP«ÕX­Vìv;½^_ê™ÿ "+*:šçÕ>¶NñB¾š.Cßõ8‚.l{ÁåvOë¼}߯™<ï~êäýɯ´e‡Å\ø 夷^gá´eÖ©´|rþ[b¶aÄ€Xê4„:¹\1š‰Mç±U/ÓºÙÍ<Ùø¾ ÑgÃÅߨ—rîŽ2©Ý’.JÈRgRNóÑÎ#<Øa$5ÞMö_\׿?ý“|íü_×Imáÿ®&-'´œ ‚©\Wú<É…-#ÊåzUZßd$f°uc­;4§VÞÐÿ­O3h8øù=æ’s½O‡Š“ßää³Xêñôܱì;Êé¿—ٹ첽­ Evÿ¿2YwâZý¼ ì=pîº<]:6­@à‰y›Xœ9š—íÆj•$;’͆$Ù±Ivlv;v»Ìü™£‘eµÇòí²êZ3Í_Q‘Z¹–®ºö×.k\Êó´Îþöíû~ >üxÓÎ rùÂelÖl._¸LýFŽÙô-y=k*ƒOÎË¥+¸ç¶Û0Ë짘ӂ°äÛñZU£Uõ06Ÿ¾À'|[î{°‰ ûèY¿¦Ñ»ÑP–›žçÊùdWoDd°+bÖ1}Àh²Êç¦ÜÛºÍØ³MNv¡´ "ð¿¼àºM8¼{’ϯãv±ùèvnkÐ:õjµ¸¹v "kqfÃÐr»^•¶ÝŒNG£ àä_WœiaÕÃ1Ú«3ÿàûÄ&ÇÓ$²ã:ßK[ÉÞ°lã_ôìÒÚùãγ ïy“OË(Žü€Oxß±ÜñJëfúÓ¡a2¿öͰoëBQûµeYQhÙª ûbb å‹êЄ]¿¼Ox>ÑÓV»» >îL³ËЩýõ»ìÈ_Þ<1oßp\çë†&2üå,ž2ÌÑSjú)~{³ülÒ6¡ßŒSl½b¢¼AA¡q“æœ=MD¤oYWèõ:$‹½¾|æÕ°Z%ÂCC1™ÇÉøÙ²e S¦L! €;w’••Å€°ÙlìØ±ƒ€€† ¼yóÏ-~‘´Ã§Y¾h}¡õÒrÇ]÷°þ‡rŽ-x„ãÁ캫­Z6’xõ ›Ü\¢ˆ›zF¡S«ÐkUhd¨^MK =5u4‰ôãà§Í9ic¢hóE†<ú# ³ná4P~cÏ=Ók-ŠñCùT”»^ùÏÂùÙ“†¨((¥Žú8‚LîzüDFD››K@@€O{üXlZlvòü@¡Z³ñæ%ÅìýO1«gµZQ©T˜ÍfÀqÒÒéth4$IÂb±8{ùyÙ­Ï(ùaµÃ;ÓF!Ùž~ ŠJ…JQ ýXìŽ}®ïVÞåºí‡?Ô°,eNxk&˜Á†„d5£»¹73ÿˆæÀÔEoñöSÓ<*Ó×ø…û9zø4k˜é¦ÿ?gàÇ|;àh_}š×â»#Gð+ç¡^ ¢¿#T¯&9+½½zUã[.d)“Ø{ð0ªZÔ Tñͱ­ŒmPö!2ÅáMÝh2R©Ó­7ŽÀdâ¥$Zi#¨Ó±ÛV ñùõccÜ.ÖÆlbd‡ÎÜVÿV«E Uk©Ö€Ÿõ*×ë•·¾ÉÞ<ŽàˆRŸ!öܵ®Þ›Ô Q«ZL?ú"3ûÚ0wÓ‡Ìö|©?–mO9×O×~ €ÐðZ=p-¦¬ àè Çy¿MËö¥*§$Š|ÖÎôÇnÌA6f{>…z½Ê^†·u!Ë Øs@qøAÎ{ÑÕ¡IÙ•)%6»9ïgß{u‰zÁñÙߘCŽ@T‡vM ­Û쮃ÿ¾bãþòºtèÌð—÷³ñŽ[éøT©‡Ð†£¬ÂløÑëôŽ Îws(æsöÂ9jÕˆ$!)™Z5"INM£~º>/§ªröìYžxâ î¾ûn~þùg4h@RR#GŽ$55•;vаaC.^¼ÈÀyâ‰'øõ×_¹é¦âè[·l¡^½zôÏ Ü>t(›ú‰­[¶0ú®»*Ê´ëHLLÄd21nüx>]¼˜¤¤$jÔ¨øa7ÿEq~²ÝWsú ˜¼ÔZ•4zPë©§N£s׎t‹j‰²#ªÐ‹­˜ÕÝiÏ®RÛ RAnv–£ß„ú¦>MR\ §/¦8׫2ešÓ®M$èÉMÇÙû®õ¨‘lR«z05#‚ðk]—šwD³êý¶ŒyüM¾ýt:(póˆn妥¥¡V« ½¾‹xFFF±éžê¥mY‡Û÷±ê}Çá}½ÍêϦVˆ^ù½nò?•&Ëî++ÿÆ©´½oä¼ '=~®ÄÅù´ÇYÒ#ÙVnŒÁd²’•c"+;‡¬lï͸³äù[OÚd¢Ô˜[£šS¿Ùµ:ˆ õçêÚT.§9z]l:¶‹íG¢Ùp‚j†@´5’ä»[°ŒôØë>ɉ<úØíöB=z´Z-:³ÙŒÑh$ Àxí¢ÿKÂfW#Û¦Í[Ã[SFñŸ×,6ß„»;±|ÝÞš2 ›Ýóž>6YƒìèÄÆœÏv;Æ"Â2’Óe"óÖóG ØeU±²À»óü]ZðÎòuÔªÓ€ñwôå¾í< üxSæÓþ8zùÌü#š­¯=Ä…„c<¾ ]«þÌü#š¯ÕgôÓ1üXùÞì(ë9f~ÌRê…‡nJPàþ6?ð“þ÷µÀXz5˜³´ÄÞ>eÑ+.þ,‘:—²L˜¤\´øóHËOó›Åö=—AÁ…„óàå(Oõò¶=Ùí "n®CÎ…düƒª‘z9Kú9FNÞͪ·cy¼¹~¸BR[Ø|t;ƒomKϽèÛl@¡íõ_ºÀÊ×êz]^yøæÜâ‘Üý‰cØÎòÇVRýÚ9¨EëZ|šò#šµâÈ•8P) ¨Ѭ‹v~Å;]§—(¿¸òš>±Îùß|ä(q=$÷ë•+½.à |ÖÍ ÀnÌÆnÌÁtîwN%ÖÍþåÕN%IA1ÇŽ`‚ÍæÊ›OôAǪNí›bW< ®”õT»Aoì x¿n^/šºtüomÛ:Qv…Bëž^gʪWAâNÿLŸi‡Q³3 “?ôª(eŠ•¼~0_>‚"›P)Žû¾äõÅ÷¦ˆ¼cK‰ò|ᇔ¤«n¶:Ò¸I3Ο;CD Ï?f³ *üŠ™Õb6›^.]veEA«Õâç燿ÁƒÁ€17‹+ Ô«å¦V«F$qñ øüó&m- ³gϦfÍšœ>}š^½z±oß>¢¢¢X½z5iii >œ¸¸8zõêÅéÓ§©Y³&³gÏfÅŠÅÊKLLdè°a×¥ßÖ¶-ëÖ®uþ/:4«àÿ‚ëÙÙÙ|·z5¹¹¹h4úõïÏÍ7_î[·v-’$q÷=÷¸´u÷®]Ô¨Q½^OÍš5Ù½k£FvnwW–»m999¬þö[rss ä¾ûïw¾<ß½{7cbÇýz÷=¸õÖ[KÜöO (”Zµ}÷Év¹v÷¼½FA§"@§!$@CãHâ¾jäâÅVºŽÛ[‚äâѨ5äfg¡Q{vÝûjÖK4oÁòEë9}Ñè™5m ÍF8·»›ãçŸÂuAŸ¼‰=á图¦æÅßxú©ªëZO¿È³ê‚éMÌ™K,\º–«Yƒy¾oÉo˨ߨ>òïÑ\H<ƼÀsWc•ŒdSÿñÌi6Í™ŒÖä ¹¢¬ç˜˜3GhBº±øãiv‡SÌ¥±ª×®Þˆ]gŽ@ AŸ²è•šf'×–„M±a´é*ü¨ÏHbã¦P- €L÷ó9xª—·ukµ:ÚpÎ…ä%Êð†ÐT*5²"£ÓéðÓëÑëtètZNŸ;MPµ l²­ZCBR2mZ¶òiùU-[¶ðË/¿p×]wQ»F$&«Dff&¹¹¹èt:g0Èf³B­È®&%óÃ?°eË–b‡yÙl¶bçˆ(Õ—×Ö¯[GóæÍéÒµ+{÷ìaû¶m×}6ÿôF£‘ÜûeY&>>ž;F:z GuéÂúuëeµZ]bYî¶mذÞ}úаaC~ûí76mÜȽ÷9î—ÆÄмysÄŸþÉÎ?þpvÜmû'Рa êÕóÝiõÕ}¬þô¨´ Ö¡hü®õôê÷¾)øb«ïã1>+¿$~õÒþ>È€1uIøã8Ûêót3þ8ÎÇó7û$àsúÌ>ÿò+.\¼ˆ¿}~}zóÄÓÏ2÷•™ÔªU“„„Df¿ö?/øØeþ² Ç|+ùƒÕ=ìÒiËž¡¿~ ÕÊΘ¹GA¥füÜÝ(ª’²'<:«ÕÊ¢… ÈÉÉÑÖE `µZKÖ+ïæ&_—üõ K×°aé¾üܱ$Õû„%‹>dØœDì<ü—U¯üàKþEU²˜‹µÈ¯#»âèíSÚž>²Œl—±Ëг×,ËädgcµJX¬R¡ßœìlÇ>¥,ïPl ³í͝&b–´XíðýÏYöã^,û7n`Ú[«±ÙÁ$iÙöÕDf=Ú‰C±î»ÏyÚ&s,:̹6,Fv›Ì#÷ŽdÔ­ƒ¨Z—Ow}Í æ=ùäáyŒÅé„¿IHO¦{}ß 8{n/ÕÂëQ«QkNùÍð‘­ž?ì Õj  00Ðù?†y›Í†ÕjÅb±`±X¼šàÙ.ke…—ßYƒ,+d›-¬ß~Œ¶aÕ¦–­ÝO¶Ù‰ӗ™‘—ÇÝœ;E‘ì½xŒ’“dÃ(9œíyiämÏWÛ]PÉ›óP>s¿ÜÈ7›Ÿbþ”U¬Ørš†ujÒ¿Og~ùݳ7Þ”9é­×™ôÖë¼Ñ§æà‡9«©fA¯ @§Ñóî„&Lÿ-€¯çÌ/1à>8ÇIñ™Î%Û’}ÝöÙN1qdc’âŸÙÉ6—<´«,zIHäLäø™ =Lm9¶•I«¦—cǦ/ÝœUžêåm{’¬6/%‘t5“¤„,2®&qæ|‰—’ˆ=ÏÕ3GúÐO,Yôa™>)9idM(ŠcÈæ¹äXVü¹†CN›xŽç¾ù¯ü8—ȾdÉ¢QüÄ#¹¾ö;Ú‚¡-†Z]èÞ=Œ''ßBr|.‰Wr°™!=CA¬E¬Á/ÿ7HKz†÷×”¢å…6êƒUÒb³).«ä»ùaÎÿ>ŸúÝž¦^—IÔîø85Ú=ÂÒ÷–9{ø= ø€ïëÂ*É }zC'ÍE1_K"Š%¡“æ0ìé¹H’‚]q ©Š9ëUš²žƒR6 ¡ß ÛQì e¢Héôýïv¼_»­Z7v.v$Ù³:+‹^‹§ #.ÜlÓívþü´3Š9Å‹l>—·Ä¢XÎ![ÎH;‡ÍZºû¡«?bÐK?” ¶t2P¤Ì¼ß °e¢ØëŠ-Å–‰ìÁˆ_\#dY.´äß·4lÜ”äÄøevéÒY–9rèRž’ÕÊ‘C‡|ò1Š¢dfd’‘žNFzéi餧g•En®‘Z5"IMM%×h&öâ%š4¨¸‰Þ« o¿ý6}zõä࿲yõR.ÞÍÈÃÉÍÍ%44”ÐÐPrrr9b8ïfóê¥üãWúôêÉÛo—Ø-Hiû˧§§Ó±S'´Z-=zödÒÓOÚ¾í×_¹té’Û€ÀþýûÑét4È«ç  ÓéØ¿¿Ge¹Û––šJÆ ÑjµtìØ‘äädç6ƒÁÀ•+W8|è;väégžñhÛ?­V‡ÞÏw=ã^hõ«?›ÌêOŸfõ'3·ßq>øø?<0¦' ›V§íâ°˜lÎ[ðˆ7ó™ö|Éä„+ëHÂǹ|1™Úµ"œùv_Jç»cYü|ÐÑ}¥Fˆç>šÿ ¹óŽ,ÿêKƹŸ%_;F'thߎCGŽpèÈ:´oç6iÈê_w FÆl2^·CqXón"T8^„ªµ*_¨ •ÊôQkô8&‰ÖŸ”Z¢Ü°ðp¦O™””²ˆœœ²ˆ””¦OÙ½´…ô"O¯ G1á±Q<úØ(ÇúÄQ<øV Õ4pöÌÑr×KAA–Kµ  ÒÒ3\.Õ‚‚eE.ýœ>Š3È$;Hù‹Ù„Õl*ô ׆„•Y–1K-æ+¡ IDATvÌV;fI‡Í®0´_;îÅ£÷öáù‰Ãyåù»‘l f›³UÆ"ÙKææi›4Zu˜Œ6̹6l6…ääd¦>ñ_îh7˜Óq˜ºv._ì^ÊŒu¯óáÏKhU·}ê”ý“+7žâ>2™©Ž£ZZ#e¤ [Í(^¼ý°Ûíc6™ILHäÒÅKÄ]‰Ãj±ˆŸŸZ­FƒFãÝ<6»ÚÙÓG­V‘k‘¸£_kî|÷ëÀ¸;;“k‘òzúŒòê!ò†wá¸ø¿ÿL_rl2¹y¶+ ×ÖÙƒž>Þœ‡òIˆ¿Ä΋YÌûî1æOYÅ–]©Q„øK%ïìe™ §Í`á´L˜3•©‹ÞÂn«ÝHŽ9“Í'6 Ù¬ÈØ˜96)ÛöylCYÏ1©f ɦ,çR¿ý…ÿ¼ÿɦ,®¦šñä1¡,z ìÔ àêÔ©^MÞ×ì6ÝÂ{[?Æ?ÐFMnÍ¡W­ëçcò•^ÞÔíü§âèÅ$ïŽaÏÏ;سùwÖ¯ÙÀwË7±ççüöíwœ:°—¶½?f×7_x­wAR³Ó‰MH 3/øv5;…ƒçÏKLl,;NçÀùóü|âONü‘½±=’ësßXsµŒLÎZ>úøfþoÁ-<þT-^~ñ9ütøùi1tÄeæðâðRL^´r.V«•ãÇŽyT–»m²,³háB>þè#–/[V(€y÷=÷`³ÛÙ½{7Ÿ}ú)§þþÛ£mUEQó¦›PŠy&T t`ðtɧhgŒ‚˰9‰,Yô!­:Œ.UÅ•Y’>àøÌÝô!cZ·afßÁŒi݆¹›>ä@ƒndj ÷ЬYc—2Ù|ð*··¯Í=­=ïA¾`þtëÒ½NGŸÞ½ÉÊr¼”íØ¾=‡;‚>‡ÿú‹öíÚºÍïm]¤L9[ò µy…ò,ù‡T¨PcG­²ZìjY¹vJ8d6›iÔ¸1O?ý üÓ¦:>ýì³ÏѨqcçÛ —zÙ´…ôП~^ü¤—=6 ‹o˪—sx ?? ~ÜÅÈóó–~xW~¥ãåý朊R-(È™¯4ØmvrMvPdײuû~Tùý¥ó{0;¿ä¤%×â”4³º§mÒlSóã*Çvð½ŽHirr2o<7›yŸ¾Ïº#¿°ël4þ:#Z ¢]ï2‹r“á)Â"Ç¡®Q‰³pÁŸW¯6(”¸3Gðñî3ÔY™Y¤§§S-(È9>=Ý1YªŸÁÑÀf³a±X<úRB>ZŒF/¿³†×^¸‹ÍÆúíÇ }½Ëb³qâôe–¯;Àk/܉VãùÍ®còμs€‹&`ü;›Gïž\éZ(¿y¹{@óvBS€Zu XÍ\ÍTñù¦g˜8ìÿ˜<ï~^ëÙäÀ¥)ó‹9osÏóQÉ ™¹)è4zþŸ½ûŽoªj8þKÒ¦»Zè`•½ÙSZ\€€L‘¡ ‚[†Š/ "Ë_DEE¶ p¡ ÅWTdï ¥-t¦Y÷ý#MÚ´Íêžïç“ɽçžsîMzŸ>çœQ7±~ÏZº7éBŽYɃ@PõVÌzÛi}%ýŽÑz?Ç™;_ìù‚Y›ç„ùV'Ç?w¦Ï,I¿F¶ìË¿q‡ðReãë¥å‡?2çÛ¹˜¼ÌD†TÇ`6óerk.ÚX‚ïÑœ0 ÔúåÉ{ûäâ]öíïîk›È¹Í¹Ö}¶™žc7¹³.î ÝGŽwY§3¡AUÉÔ]årªå"u«Õ¢j`mxï„^cðÓz³á¯yó»%(hÁhi_€.ïÿ …T¾Y8×®LMàE€‰ ڹöZ\\Ào¯üÇá1-€ ë ÖÐâÏícÒuþ·ÅDuœˆÁhÀ ×cÈÑ£×0›Ì| l>§ Æü̆7{qÏ“SlÛÖ¿½[ç$`Ràà¼aT-ZÖs;£¦$?ëFƒ™ï^¨¸í‘Wl«5~¿ø¬/L 4n XžëÝ ú”ô» Öð-|µ°7'¿»¼)ö«Kæ—»]ïF ¦(uïý‰¯æÞÊÝÏ,˰fEUèxJ¾ôGÅLŸ’ÿªØ¾[Üqæô)"¢\ÏK¨Óé ¤û-·ðëŽüº}=zöDëë‹Þ÷§8|ýìoÖwîüîÝ- UÔ®U€¤+ eÒve–••…^§!3çYçRð×Bp¤eÈÖ–-[hÑ¢ÁþÞÆ&=Þˆ!KI©î0c,""‚÷î¥n]Ëuýpùr  $$¤Èc¬¿¿E¥R¡×ëmÙìÝ7z4¿þò ?þðcÇ+²ÌåË—Ñét<ñ—/á´-Wû&Nš„—WáïϪU«òðã×ëÙ±c[¶l¡Iî°0gû®ÙéIÄ_I¡^ƒÆ¥RŸ5I$wxF“—íyþ¯ÄÁs¯°an7jw-•fݲä×ÎEør‹‰tmš7"¤Ÿ™—îtožÖ‚ÒÓÓùö‡9uú4§Nåýÿܲe Þ^´ƒÁÀ‘£Ç˜òäNË—D‰&r¶þg­Qåýß™ÿÿP V™Q›3A¥Á¬hIJÓ» ú€%]µSçΜ>}šM›6Ò¯_:uîLjjá`Eá~yÛõ ,™>“د(måî\%é—%Û&ÿ¶ —.Ž`GEEÚö[+%wå¯ü?f³?_?ü|‹^¶ÒúW â0šÌ¤gQ© G—…ÃY.|z–%`4:ÿMÇÝÏäSc¢ó½Êû&11‘gšÌüùóéWK¬äÊðAIC¥?Í£ãNóöuT‹¬ƒVëKµjî®e‘‘‘J­!33ßÜ'j iéé„û[–n7™LÿƒuÄšé3ëé˜0™Ì èÕҮ̦?Ò°~-fM®åy¦)oNÛ¹èó²{¬ÏÍÖ ä -Чšô‰éÌ—_ýÀ­½»‘¡7²ê‡ÇyÛ"xu#Ü[œ6¼}|x¥o'F½¶›%6À„‰nMºðÙ¶uôîØ³YÅÛÓfR;º6ãgÍ`ù,çüJòÓª#Ç/¡¨µÝ¾ØóË~û„šUkøàKBR1­ÜËv+n¿4i~<Ò~ïíYÍÊ}_cÆ@TD]T^ W3uÌíý4K»ßô|•{­eKúºôq·_ž¾·zƒ±ÐDÎêEÚ¶ÿ‡M´j_ô°îªÉñKiÄ%Ÿ'M—Ní*Q¼p÷S|ùÏ÷4¨Í莃¸ªK㛿¾#ÀÇ—¨jî’KóÚädèí‚0/¦ÿ”)NްL,ûëòâeBnïúOyÆåq¾Z¬ö¬:…#jðTÝYýÊ»Ôh=ƒÎ€Q¯Ç¤7bV>Veñ9í5;žõ3ÂòôÖ¿¹Þsâm™³ÍšGÛÊy’Qãn_‹5Är3y~mTÆ«¶ÿòMfh?Õ2§Ù¤pâ˜eA‰†ëbt3U’~å×`ÌϬ{¥C§åfŘaÝëó–o:~«ÛuT゚øò•Þ š¼%7öåëÏþeÙÚ·Ñ?»UoI®CDTmΜv<íxÝè¼ï—³gN»ðÉ߯ê5ÂiѲ% EË–T¯îÑûã.ëïÅ—ƒèѽ+é™*{#;v,›7}C»Ž} ©LºÙüõo :”ÐÐP†Ê?‡Ðáî'I8{ŒšÓ8ò÷IÆŽ[d·Ý~;Ÿ¬XÁÎ_¥]»vÔ¯_ŸƒÏÝڕݵkíÚµã‡ï®V­ÿîÝËMmÚ°û÷ß9pà€ÝÐ*///zÆÄðþÒ¥;vŒÆ  víÜIݺu l´Z-uêÔa×®] ¾ç§m9ÛWµjUΜ>MºuÙ¾m§NŸfâĉ¼·x1­Zµ¢K×®øûûÛ}Μí»¤]MâÒ…s¥ôÑrãj@I5ѯxÑiÙò’æx.€ z¬úp7aá>´íP_?çïãOäÝ7@NNþþy÷Ús_y•&skl,‘÷Žä‘'ž@ëíMƒúõùࣉ®[ÇöYvT¾$J4‘³._Ч(ÞjjŒ¨â¾B©5UÉÌq¼bOA©©©Œ;–[o½•¨š5IHp/Z¯3h õËËE³Öcʲ_¶T«ÜÏLÜåË4nd?QVFz—.Å™»ê€õ¸â¨Q½:gÏžG­Våeü(fÛ/b/æý9¶fÍ(Ûï!Åýn2šL¤e-µ(ªÜ‰ ó]x%ÿ“Üý ˜\ *λ%&&2}útæÏŸ_¢z¬Š ø`8擌ºí,+€®}&z\¯Á` ;»ð—ŸŸ¯--·8Œf f“Âì·¿æÅ'ïF†ýçÓBåNœºÀg_ïáÅ'ïöp"gmU.ë¼”™¦¼y|2s{JîG,‘~G<}Ïÿù瞊½™È`?>ùf—/#"ª¿ìù·´·d#Œíà|™ûâ~μý,Wf3L|÷$ó&“cÖÓ«C>ûáLæþÔŽ¶üâì*àcUÜï˜'ÛaÄñǨ_­iÙyÇ|±ç þlY¾ÝÇ|Æ×߇SÉçYÔîE·—l/n¿êiê± ÏS¬:ð#ÿœÛŸŸIWÎðCF.¿¾ŒoçøŒ©¶òÞÿ}ÇíŒWýòô½5ŠžÈ¹à6k¹’x¨õ@Fx–!UYðÝ›Üßý>z7éAï&=ˆK‹çó?×a0éÙwæÏv}8o <7”ÖµÑé äæß°qñrú?:¾P&Ž]»:øuùrÜ¿ÆýÎ:mï!§í¬{s1-ò­ö婵| #žý”^Nhó‘ôF—Y©®”öçÔ¤@ÌËñ¬›NìœxL ;|°dÓäînF»}uÆlÅd™(YÁè1åûÅ¢^£:¹ýwØYiôËªéø­¬{­C§Y±³Ùì´-gûúõïφõëm ªÜ~Ƕ}=cbøeÇÛµhÛ®[û*»²X²=ËàÍÎOçwOX…÷϶+cY^Þ›Þ»Tƒd®êJIUˆŠöÂ’wiÉÆT)*RÎ*øѲås÷ã¦côíá4ðÊw?üÈ]wÜηßÿ@“|ŸÙ³gÏ1áþû‰ŒgùŠOìŽk×öfÞÿ`9îçVywÏ­ BÿÛúúáëäÖÁ9¦|AŸ¼ïßÜMhTÙ¨/­G©5 £ŠZQÛŽqWBBAÁÁý‡–“/ÓÇÚ//¼µÔ2¼ëɉƒx{iÞP¯§&òxÕâôË’VkÿÅÇç}æädÛ•-)// 5£"¸wÙ–ñcýÏïR\œ-à”‘žÆÅ‹—ˆŠŒ,QÛFƒ‘«™†‚Ùz€õÇ<÷‡Éº!78`p¶ ž}&©^½z©|j©&; ø\9ïÅ¿{¡SÏ¢ÿRâŠYQðò.üY,îäÚVF³“¢0ãɘ…Ÿ—>QtAü牚˜pž‰S¨~“3¶ÌH oòfE,c^Èúá09©¿8ïù?ÿüÃðv73¼ýµ·-çþê§Ÿâ´9~Á V̲üõå$ËíϾ[^ÀSÀ×9^fÔ™b}÷%çÐ¥QG\ø—Ú¡–_ì¿Øóó~^ˆàS-˜þ!€ç“èÒ¨£ÛŸ’ô ,?÷Õ¹›ûêä ·Ûûü#´¹} K¼ÅÄçòþŠa}½÷û¯v3ãÇY¿<}oMf3ñçð •ŠÔ8K·¹3×…+ÞfFw̆ÿ}KZvqi¯S«ZMü´¾dëu\H¾HvŽÓ ‰Œî>o³óàeQJãÚX3o6.ß@ÿñ£@çx’úT|Kðñ´=€Ï^[BÛ)ß»½‚ …ûgOaÑ”„5Âåkè9î¥b·¥÷9ýcïAÔi@ÏÜ9|À’=–@KþçždÔ¸ÓWg¬}É{mYJþ쉳vÛë6¬ëQFiIû•_Óñ[Y·°C';ÏV+ ÆýÌú×{1äé)¥€(ëŸõ~gÏž!ªŸüýòóóãjšë~éõKÐGïÙdþÖ!jùÿž›”A€¿Ùºü|}<Îv½ðõõeéÒ¥–ø¤$BCCm“¹Zùûû³|ùr§e eL™@{öì±=ïÖ­ݺu³½¾íö¼lØüK¹ñÀø¢‡Gç/×¾}{Ú·o_¨ŒZ­.4ùs~¶ýÎÚr¶/$$Äá¾-ZТEÑ«Â9Ûw-ð !<¢f©Õ—iðâîÑ3ˆÎý»õjFe?ºËzo˜¡/y¦ÉlÂ?0“³ãOí7œå;×R?¼Š­#§.§2µßpR’38¼Ï’¥ªñög÷/IÄÜVÍa]“zˆw¿ÇêµëˆŽŽæé'·í{âÑGXøöÛè²u Ðßî¸öíÚòþËmóù¸*_\…çôÁLV¶_?ÿ¢ÊÛÉ1¨Qa™/Ç2k²å¶^m¾ŠúÊ7€%j0f¥ *ŵÊrŒ§²³=[Ê×:?­_X@S&å ïš2i对7©îÌéSÒ~A¾€Jn¿ìÇ#[þcÒåèíÊ•4”?ã'ÿð²¬,Kÿ3³¬“8[—ˆ/fÐÇdbí·åe-Gg Üîœ'ŸÉ¢”fÀ@ÃåBŸœŒS¤'Y>M—»îÐjÕ¸t)Ž€|©É™™Ôðp%«‚Ìf5fEÅüw¾fúãw³ê›Ýèõ»9}ŒF“ “ÉÌôÇ`ö$裨mA<ëÇG—û‹–¢]n`/ÿ'ËYЧ¸ï¹£eÙÝ ü§Í‚+ri|áí~–¹¢¬Ù=%Qœï˜‰õ†³øýøÿX–µ–Ú5²ÜÄ^ÍNájV“ÏÓ¥QG&ºXª½4ûåÈÒoѹM4K¼eÛf}ݹMt©ôËÓ÷¶U×ÖüñµýÒÉ)c¡m7u»É£þ9Ò?wØé~K oÇôgl¶6ÍœŒ»ÀàwÚÊGI¯ÍÕ Snæ¬8EI¥J‰>ž´°xæÄÎt¾Ôµ+Þí»øü‰’¹“ÉÄåý«Kð±*Ïi–^‹Á ·?÷¡mÛ÷ (XKp%Kï~6³;}uÆhT ¼6“|áAæJM¾pˆØŽöe–e¿ j:~+ëÞèUâzÜÑä²i«4¿‹Qàì™3DÕ*ùäÇîöK¯×£õñu{å1+S¾LEÉKÀ’!¢ä•½Îõ»»J¥",,¬ˆÒž•q¥¨ Œ¨\<¹·«U§1Q5”ZÛYzû‘A:ƒeŽõG–¼ûñ¬RX…ÓlVðÏ]ɕަúÐ}¯oZC\j*‘Uª0µßpZ¤wåõw¾µ+[¿ó jêE×åÍ׊^ý®KçNtéÜÉöúîþýlÏÃkÔà› ëÜ._\%šÈÙÛÇíï=Ä.?oZ¶‹¡UÍËøùƒ:ˆcsŽìúœƒ§ãjfþ~é-©êH–Á‡ŸØOÚ¼pIÑ“8çñü¯§ž²ŒìÊýæþ£Qå} “’S¨S+Š«iévåJšôc—ñ“ox™ÙdàÜ…Kymæ›í¼8úvlÄ·¿¡~tm åÛ*ÖŸnûç§NŸçήMÇÙÅ™`ת4>7…ßo{îä²€Ë?gÛ–šjùeúŠÏšv/Q[^Þ^DEE’xå ½o­7QQ‘xy—ìçÆhRcVž}lfEaDÿNEfc)  Ra6+ýÖ¬¨É.0JïçY– —lC¾çùʘ̎£~%yÏù{›óì«ÒhÓÛ' T‚=%5±Þpžl7†·ÿú„íÇÿºó–¾Ó¨# ûº?¤«¬ÅÄ´A—šJLLÞ_8¬¯u¥4„§ï­o§{éÔÉ~™Ø·Ë“‹‹¿d¦+ýkÝÂíu:ñÚîOIHIF­Vc6›©Éïy°X>îp÷ÚÄÎü‘¿ßÄgo¯rYgÛÇ]ýëš'í•4à ò¿KÀÇú·GKÀÇx)EQJ-àãŒ'ŸS£YƒYQ¸»yÞ ºYQ¨Ý ð »YQ<Îf.‰‚¿hWæD‹²ÖUÑmGi{<¥×çïò0ècÉN¹B’ëoºìl||Êþ^F\›tˆ½¼¼Á«ôþÏÐå.°d úèM^–çoTm,yœÀd2ìö쎦ú¬½cz^7ÌuøpåNBBíÿc(æjŽ•…Øßä{2‘`ç>“ì^K¶ŸŸ&¨áh:Ûo*}»D—£n¯QË—ãí¶]¸tÙö\­VÛ^,WjT¯N\\^½.Å£Vk¸pɲ-ÿ¾âh™]›²ñ×CEñ*jºïþ=š[Žs¢¸ì7àSp9ôã?Ê{a»DùV‡ÉSÙ¯GFãòKÈËÛ‹ÈȧeùV«ÉÎÎF¯×Q³&Qøúù¹œŸG\ÿEA—Íå¸K\¾t­Vk· LŽ©pРF¹K¶']Ï2üÖ:oØ¥K—hÓ¦M¡c®%*•Š]Û·^¯"‚ZVºlëVž'éJ¡a UÛåê]åÅh4r9>n1½\OTœ@†&-{~(ÙDÎB”‡òþL*ŠBdíÚ\¹| /µÚóy¨ò3›Íèt:"k×¾æ–m¬(ñ=$ß}×/yo“kSyÈ{!„(???Ôj5 qq¤È˜7Q€A¯Ç×××íáéW“ˆ»pÎô¹ž¨Õj‚‚‚\.ãë§0zB­|[*Ïý›YQF­V{”%Yöìq1‡TAë­%ùJõÅþQW*Qµ£ñõ÷'##£4»*„B!n0…²4¼´h½Š7a»¸¾Y?EeöźdûõHQê5lÌ™“ÇJåûåÍšHݰIÉ—lâF§( øùùQ·A£!˜L&rrr$à#„B!„¨”EÁ/ „ðð¨"ƒ ×úˆ“ÉDÕÐP¼¼›sùÂôý5sN*• /o- ›6'0(ƒÁàú |$è#„ÙÙÙ¥»ªB!„BTRµj7$²fýŠîF™ÑëõѸEËkjî+•J…ÙlÆd2yð ú!„B!„7<—7×Å®iF££ÑXÑÝ(W×Ö@6!„B!„BáK¦Ïµ“Ù$„B!„BˆRäj~›keþ‘Ÿ%Ðc7¼+##ƒ´´´ éŽB!„B!Ê_XXX¡mf³™Ë—/S¿þõ;ÏÏÀ.è]AÝB!„B!DeQ£F jÔ¨QÑÝ%$sú!„B!„B\‡rƒ>2>O!„B!„âº;“dú!„B!„B\‡$è#„B!„Bqòr]Ä^f–ž+I²Â—({µj†]7ª¢»!J(!!œœœR©+11‘¸¸¸R©K!„B!®%‘‘‘T¯^Ý£c¼T*•Ë‚fEÅÅKI„…àã­)F…pŸN—Áo»ÿ Eó„VpDqXgü/IðçâÅ‹$%Y¾š7oN½zõJ­âú””ÄîÝ»¨S§þþþÜ#!„B!JOrr2qqÿ¿ÈË IDATqÄÅŹüÉó¸•é£(j¯V5­VF„‰òá«õ"*<½ÞÌñãçhܨ.ÁÁÝ-QLaaa\¹rÅãÀ5à#ÁáLhh(wÝuIIIüõ×_DFFJàG!„B\7ªU«FµjÕlÁÀ­¬·‚>ñ‰)T ñÃ[²{DðõU£Ñ¨8zü4Úµ¬èîˆbR«ÕÔ¨QƒóçÏ{tœ|„'BCCi×®»wï¦Y³fÝ!„B!JUhh(*•Џ¸¸R ú¨Ô¨Õj´Z§ÿ¢Ôhµ^¨ÕjÒ32 ”lŸk™ÛÙ>/^€ðHhh(YYY’í#„B!®;ÕªU#>>žÄÄD—K$Gq\àJR:ÕBüQ©dX—¨XÕBü9qò<7ßÔ´¢»"JÀ“lk–žêܹ³dû!„BˆëVxx¸[Ù>.Ów4j5ZÉòOëã…&S‚7ÉòÅaÍöB!„âzdÍöqÅe4G­V£vcu/!ʃZ-A!„B!„®ƒ>µË¡] Þúçžz Ô:%„#j}Dž¯Ýìtÿiÿ”SO„B!„¢òñÛòíER«Õ¨Ô®3}ò—9úN_Ô^Áüsð7·ˆ Ñ#ëß²E »×†Ð°0z÷êÅ”©SñõõuÙw´lÑ‚–J]%Uðœ *~V¦ó- ’é#ò3™UÜ9ùÏ"÷ÿþq6¾v³[Ÿêa·%^I*VÿÊZõ°Ð2ë[YÖ]žT’©*„B!n@*•eòf§™>f³ZåÖð®üeŒF3=fÌäßž¤Ós3ÙõòL·ê8tè]Û:޵k×2Þ<^~ùe—Ç»«2 WËÎe¥²œoðÛó/¿ü‚n]»°ë·ß4h°m_Büe‡uhÜ@^/ܽYU'3±WÒöÌf3*•Êi›f³Ùe=&ÅññÚ€P4íâvàçzp”¦Š¾ù?Û¶m#&&€íÛ·kÛWZŸ!„Bqýª_¿¾[åN:u͵çêÞÊiÐGQÔj[+wÍ]øíyÃÓ~àINœOá¿<‰Ù £¥uäoG£QÈàÁ÷лw/æÌ™ëòxwU¦•ÈÊ£/•é|Eaûöí 2„åX>3&wþ>ú11=iݺýúÝÅÖm[íŽYþárbcchÛöf&LÏ…‹¶³ìƒe¼óî;n×½ø½ÅtéÒ™^½bY½f5Íš5µß¿x]»v¡Gî¼ñÆBÌŠÙãsÎÿ˜þüt¾þú+»m_}õ%ÓŸŸŽJ­¢Y³¦¬ß°žîݻѩs'fÎ|‘¬ì¬"ÛPPx÷ÝwèÑ£;7ß܆Q£îåÔéS¶ýÍš5eíÚ5tìØ±ãÆºuNŽŽqt¾Û·o'&&†õë×3pÐ Äúõ뉉‰aûöí.¯Éô)o ,°E‰ >¦OŸ^jí¸Ðq+ècRa6+˜ÍJ¡òÕÛ碳fÍbåÊ•œ:u •Jʼn'X¹r%³fͲձâãùäÓOùñÇmÇÕÆŠ+ÈÌÌäÇ-[ØýÇÜÚ§‹-²+û×ßó˯¿2gηΩ¨c=¾ùæk† b»‘S˺õnÈ!|óÍ×Në¸Ñ‚>îüÜ”¦çž{Îö¾|ÌŸ?¿ÔÚ±Ö验+†ÜL³Æ£ÁÌ&0™Àlƒ¹ä×êÕ×^gùò8vìGŽaùòxõµ×˜0~<±½z±ûÿqäè1†Æ´©SìêXúþR>úx'NžbøˆŒ3šUŸÎg+?'îr<Ë>X΃ÆÛ³t _}ý üñ?T¨˜6uj‘ý[»v- 4`ÿþýüýÏ^ Fï¿¿Ô¶ÿÁ ãYöÁr¯$qàà!î¸óNzp‚[çîèܪV­Êí·ßÁŠÛ•ÿdÅ úö½ªU«ºu]вmÛ6†êðûšñ#„B!„;n¸{«ÜMªÙ+žWú¶¿@c ÁU«Û•1 h}ô×:mdÖ‚÷˜õÜ#%êh£F í^ûøøP«V- ÀÃOD£Ñyœ^¯§eË;v€Aƒòùç«ðóósØÎñã'øüó•œ8q‚_œé°Oë2ä-ZLD„enšÝ»w3zô}?~¶ÿ“O>Åß߀øøxÆŽÃ÷ßÿàÖ9d­÷ĉ<ûì³|ðÁŒÿ¯¾ú 6´Õ±|ù‡ÜrË-œ?žÑ£ïcûövç pçwðßÿ.£V­Z$%%q÷Ýعs—­ìO?ýLݺum}puNEãÌÎ;é?`@¡¥J¥bã7ßн{w§Çgdé©U3Ü­¶„gT*•[)ˆ¥1‡Ê©S§P«Õ®Áòýsøðaîºë.‡e–ÏêÈ©¿ ¨TNJ³ ïš;áPT(*ØðZ7ÆÏúÃa=îNä|ôèQžxü1V­ZÍðáÃX´ø=š4iRä1z}µjÖ$!ñŠ­_~ÝI³fÍÈÎΦNíZü¾ûÛϳµœµ½êa¡¬Y³–^½{pöì Èßÿì-TööÛú²á‹/  ..Ž!÷ f×o¿ФIcæÌ™ËСCžkQýpvn§NbÐÀ»ùsÏ´Z Ú·cíºõ4nÜØåuqÆ:OQßùçùqdóæÍ´p1a¾B!„¸¶UÆ9ëׯïÖ½•;sú8 H¯ß°ž?ü¡Ã†*ç¬îãÇS½FuÛëV­[ÙûéÓ§¹é¦Övõùøø8í‹;çܨq#FÝ7Š;î¸gž}–FÙí¿¹íͶ6""#HJJ²kÓúüìÙ³„G„Û^W­V•””»²µëÔ¶{íÎ9<ÆgåòsäFËô¹^•F¦Oâÿ>¦Oãhô‡>£zÇq$¥ëíöM R™AQ¡7¹þ|º3qq“&M¸ÿþèÖ­+3gÎ*ðùóÿãç­?sâÄ öîÝ[è4h`{n L»šä­]ûö¶ç‘‘‘$&&YîĉD×­c·ÍÇ'oÕÃwß}—Q÷ÞËW_~ɽ£F¡V«¹ãŽ;œ¶Ÿ£s«_¿>­[ßÄêÕ«3f,_lØ@“&Mì>®®‹B!„Åu-ÏóX}wuoåÞœ>*çKgó^ f:=7µ·/ž›‰Ñ`ö¸GuëÖ1mê4"£j2~üV®üÜîX///ÛäÓŽÚù믿øfã&6¬_OrrŠÛu["g*‡ý6™L:|„“§NÛ‡)ñ9«TjTXæ.QѾ···íµZ­±«7ÿs­Vkw¬¢X²™ò—õòò¶+ã꜊:ÆÑc×®ß;v\‘C2¶mÛÆØ±ãØµë7§uHÐçúPsúdŸø–:Ã_$ûÄ·˜ ï2) &3Í &¥t?7æ"ú¶ò³ÏxôÑG©Y³&“&=—_~U¨ŒV[8kÒÕgÚË+lÞñ &“‰ /‘x%Éö¸pñ¢mß¾·±mûvn»ý6¶lù‘gŸ™f›ÙWç6é‘I¼ûL&-z—‡žèö±Ž8•è—B!„72W÷M^àpJEq{Éöç¾k{ÞàäeX½«½u¸ÓÎÂ×_gӦ̈́‡[†øXç×°[·n]LFc‘7WV¯,xµZÍÃ?Ì[o¾Éܹsݪ»Q£F¤¦¤Øö=rØntt4)ÉÉDEE¹<OÎùøñã|öÙgüôÓOŒÿmÚ´¡Q£¼lŸ#‡Ð>7 íêUBBBìêÍß¿„øxêÔ±dd¤§êCÁþ¸sNî. ×]wÙ†dä_vÙºmýúõÄÆÆ’ž–æ°ŽiÉöëYI3}w,$¼] µlÅê¯f‘¸ã jôœÌK_±•1™•‚J½ÑaU9zô(~¸œß~ûQ÷ÞËÍmÛÚ²}æÎÃÖmÛmÃ?9â¬*·Ö‘ØØX§ßÖÉ%kH!„BÜÈÝ[Y·¸üó·»«wÍ}ñIÛ#:¢j©­ÞUðÈo¿ÿ†Þ çࡃ<õôSvÇŽ3†Ÿ·þLŽ>‡}«V}ÎÀwÛµ£ñÒ R«6|8ûöýËñÇݪ{ÌØ±¬^³šl]6.^`î¼yvûGÅ×_EVv)©)¼÷Þbî»oT‰ÎY—£cÚ´©,|c!¡a¡¼¾p!Ó¦ME—£³Õ1gî.^ºˆ.Gdž/6СC‡"Û¸÷Þ{Y±âc²²³ÐåèøâË/¨V­šÓþ¸:'wß7kÙü“°~÷Ý·|÷Ý·v“µºªO2}@öÅ? ¼Þ ÀÖ_þ¥wëÆLÕ“Ùšé£ÂX ™>ÙÙÙ<þØ£¼»h1¡¡a¼óî"ìQ²³³ â—_~!''‡}ûö1qâÃ%nà…fpþÜ9²³³Y½z:w.²ÜØqcÙ°~=™™™$'%ñÖ›orÏàA¶ý½{õâ£>´­´uþüy¼½½Ýêƒ;ç6qÒ$æÏŸÇƒ=d—¦Z’ëRpÒæ‚“; !„B!œs=¼Kãùð.ƒ¾¨Õ»Jgx×k¯/dé’%´¹é&ž™6‰¹Ã¬û‡ÁáÇéÖµ+íÚ¶åÇ-[X²ti‘íh4^LþyæÍëV݃ Æd2ѵKî9’#FØ ­yï(222éÞ­=ºwçŸöòÖÛï8=çèºu>T*5/ÌxÑcÆÒ¸qT*55fÌØ±¼0ã[ýûàÎ;îà–=HLHäÕ×^/ò|GÞ; /ooºtîL§Žùûï¿ùlåJ§ï«sr÷}Ë+«"66–O?ý”[néÉ-·ôäÓO?%66Öv£ètx—F‚>e©¼f´/I¦Ï¹MÓ ¬i™¬xö4ËæQœß47ŸÀ3÷vǤ€I±¬àeVÌn­ÞU=,Ôáà™iSyàñ¶ÌžÆ3~üž™fYMëwßáÝwÞ¦QÃ<ñÄã<öØcî] Dll íÛµ%>>ž·ß~§Èr£G!==¶7·¡mÛ›Ù³gï-É[½ë¿Ë–ñíæÍ´nÕ’êa¡¶Õ¼ ^ƒ¢¸snwß=:uë2|øuÄú}a]¦=†Ïµío#¨ˆÕ»²³³ ˆÂÇÛñ ;ÏÍzƒ³&—J‡¯%ÉÉÉÜu×üþûî ëCíÚµ8þB…µ_Þr &B‚+º¢„Ž;†F£q: 3;;›ãÇZ½ëÜçèե©ÒÿÐë,ÿïTªÔ æÂîý˜{Jþ«ÖgŸ½Ò‡Þøµ Τl9[Aëzn»´lÞ¼™–-[Vt7„B!DºÞ‡û; 8p€Fº·ºšz… M:[\­Þ qcõ®WfOñ Ë×®vmÛ2cÆ î¼ë.ÒÒÒxï½÷èׯŸÛ+W••Šn¿ÖÕ»,Z´˜9s^fÚ´i0hÐ`ž}~z…_ŸŠn¿ûеŸ}ͺ|L¼¹’šQgU<©éþØ—ÄmÝ"ì¶Ï_v£QaÁäÖ,˜ÜƒQaþ²#níB!„B¸gåªÕÌåUV®r}ïQTXâ<2§âšTÚ™>!ÁþhôYôz—mj{• 232 ö/Û*¯~¾È="ñÑÚ'oœ—ÇK£bð­5|kM·ö !„B!\Û¾c;~ù€¿üB­šQÄôìéô˜ïV½H|ZD¡í-¢ö*:ô_R*}“ ¸ál@¯ÿÄ—zÝŠ¢£Óáãë‹J2èÊ”§™>®&rnÕ°S©¨PP°¾ƒ‰ié´jX«ÌÏ©8rôf¾û5ŽÿÎjï´ÜöcJ´_!„BQØ¿ûö±jÍZš6mÆœ9s˜1c«Ö¬¥jÕªÜÔºµÃãâÓ"¸¯ÓGEîûìûéPJý“9}Ä eëÜpb§-³úE!59©ÒãôÄöíÛQ©Tn=*Rigú„U @e6qùb9™™x«r²2‰¿xµÙHX•€r8+Ï}¿ó2Z‡ä]Ñ]B!„â†rúôi–}°œˆˆH^˜1ƒ«)I¼0c‘,û`9§OŸ®è.æeú\»·¨âZõù7;Ý.{ï€î%n¯¬>f³™”ä$ÂÂ#P«=©¦§§£×ë1›Í¨Õj´Z-AAAeÐSÇbbbضmC‡eݺuÄÄÄØíß¾}»m_E*íLŸ@?Ú4©KJZ&GN^ =#‹ @š5¨E•àü´äää”ÓٹǬ(¬ßrùOµªè®!„BqÃùzã&|ýü˜={69Ù™˜M&r²3™={6S¦Læë›xê‰Ç+¤oÖ ïªM/×Áœ½[Ý9²un8±SG1$Û&´²ó*¨$þÌf©ÉI˜Í&<ýñJOOG§ÓáëëkÛ¦×ëÉÊÊÂß¿|瓉‰‰aݺu…?ù>ƒAå­´3}ü´øi©^µŒ{_:vþ}…è(j…ûUtW„B!„¸áLž<_?Œ9ÙŒ&L&ÞÞj/~]6f£¡Bû(AQá¾ýt½Ë2¯/±”™:iˆÇõoNÏÇ7 äX–Ü61oÈ›¬ûL·uOUeè[)· ˜s‡w™=ÏÓëõ¨T*[6‰J¥ÂÛÛFCZZ999˜L&4 >>>«î*ø*MÀJ?ÓçZ´æ»óLÑ ¢»!„B!Ä I‚^—…Éh´Ûn00+ j,÷ŸI‚>¢R¸s´ë`Ž;Á¡¢ôúO<랪Êàÿ¼oÛ¶aîÃË7àSRf³ƒ!/ ¬Ñhðöö&''‡¬¬,üüò²9²²²Ê-ð À¶mÛ*EÀÊ&ÓçZ³xFÛŠî‚B!„7,c`O~AÝ\{Oiw§H^*•Ìè#*^¸OÙÕ=ô­Ö=U•AÏÌ·ÛV™(Š‚——jµ•J…——>>>dff¢ÑhÈÉɱM­R©ÐéteôKà§2NL-™>B!„Bˆk—ŠÏþ¸¿È=áÁ—K¡~Ë=œdúˆJC]Æ‹AøÉoëÜpL¡Uè3±l'{v$ N‡ŸŸjµÚöÐjµdggc41™L¶òÞÞ7öjM’é#bÆm·=—%çKG̸í×̵¼VÞÿâ^Ókåü„BQ<7ݹœ›Ê¡ úˆJCSmX?û”Ê–¥M*$ð€V«%--ŒŒL ÞÞÞHVV–el¨Ù2*´2fß”'ÉôÖáü7ÇâÆq­¼ÿÅ Ø\+ç'„B܈Ìf3§OžàÈÑ£èt:ËRA**•eÙ •Ê’ÑàçïOÓ&M¨]7Ú¶­¼IÐGTUîúÃ}©›ç–Z;ΆuÅN?ʶùMØ:7¼D«xWZZ))©áëcYÅ+%%À¶ª—ÑhD¯×Rîý«L$ÓÇ3×RGyÉÖ™XþÅi~ý+‘ä«zÂC}¹§o-õ®Y*õË5B!„¸>8z„ƒ‡Bµ*U,Á»‡¥\¶.‡}ûöa2©× Q…ôÕô¹±D%‘ùÝ\Ng½ï‚®ôÚq´T;€’s‰˜ÉÛlåÊ;ð“‘‘‰Z¥&33Ó¶M­R“––ŽŸŸŸ-Ó'$$¤\æó©Ì$ÓǵÙKѪqýc¢0š6n»ÄþãWyqRó î]Å[´ê©i>Ó†Õ|¸ŸÍ¢U'ðó¢oWÇßB!„âÆvúÌÂBC©R%­·Ö’Å£V¡Îø0Œøhµœ={®‚ƒ>BT ¡Ù¶±un8='.CÁ²T{AJÖ Ûóž—yøQ©UT©Šª˜ ²³ G¸üü|ñ÷÷Çß¿Œ/Ð5D2}\›þ`S¾ûõ2Ͻ±€çÞØÇ-í«3ýÁ¦no6+¬Ü|Žo‰#=ÓH·›Ãxjt#ü|-ƒ1ç¾?_ “Ç6`áÇÇÐéMüç¡f¶:~ÚÏÇ_ž!>)‡–‚yv|S"Â,Yk1ã¶Û±{&sOŸZ:™Æ¡“i<4´>b£ˆ·GG6ä³MgQ« ¶c &h€·—ºTú¿ëï+|8§ÕB´Ô«Àô MyiÉ¡r ú¸êŸÁhæýµ§øyw<Š÷õ¯Ë¢ÏOز‡\3n;³kÁ²õ§‰OÒ]3€ghBÃ:è f–¬9Éöÿ%`V`Ô]u õ1fÜv& oÀ†-HË0ðÀàz »½¶[í»âêýÕå˜xoõI~ý+€íªóÈÈøjÝ«ÿ¡™ñàÐzthYÍv¾Cžþó:P5Xëòú¸jßϯ•£Œ/g?®?›Á²õ§8r:l‘zµ¹¯_ni_Ý­ã…BQ|* (0­•ʲªˆ ÆGKHPÙÙÙÖW÷~s¢ŒìݺÓö\¥vþ( ½þÏÚ™cY7s,k‹x(9—lµ3Çzœé£Vk¨R-µºx3™Í ÞÞ^…f³¤ãäi¦ÏªàÐaO†¯ûñ{§òæ³mXõZg4Ë¿8mÛÿÔ˜Fì9¯]á—¿ùë` OilWǯ{®0ÿéVl|¯í[TãÇìö÷dÞ“­øø«3 ¿½6¯LnÍç›ÏÙöï=’ʇ/w`ùˈOÊaå¦s¸ËUÿUª¢¯Ç©ó™…7–Wý[¹éâ³YöR{>šÛ½GR=:àç?x}Zk¾YÔn7‡òÖ'Çmû>ùæ, I9,¹Ë_nÏ?ê·Ús0…7žmÃê…]øßþdÚwÅÙûûÑ—gHJÕ³üå|0»‰É9¬øê¬Ûu÷‹‰dÓŽ8Ûëß÷&ѼA0Uƒµ¶mή;í;ûünÿ8Æåð>W?μðîúv gÍëÙ¼¤ßÛv•ÿ°d!„âFä£Õº½°Ž—ÖŸ2\ªÚ5Èè.Q1îÐ{t·½V»x”–‘‹RŠ|ä·nÞôBÛÜ¡R©¨Z-´Ø“t…†VÅ`0¢ÕjmƒÁHh¨ãs¾% IDATɧoT’éãÚüeG0Ln À‚É­1æ/;âÖñ›vÄ1e\c"Â| ðâÁ!õlY~^̘،7VåÍÇxaR3ü dy¼ôX jGøã«ÕpOŸšì;jXhÕ(„f ,C[7 ¡I½ ®¤äØöOÑ€Ð*Zª…h™4¢[~wÿ¦ÖUÿoi_·>9Î¥„l F3g.fòzn¶RypÕ¿‹çÑ‘ «êCÕ`-‡7ðèx€ÇF6$<Ô_ Ãï¨Í‰sé¶}?ïŽgÒˆT ÑVŇGFØ×o5ylcj…ûQ%È›×§å­1áNû®8{wìI´õ/´Š–GF6`ûŸ n×}k—pþ>”BJš€-¿ÇÓ§‹}—³ëãNû®>¿®¸úùpF¥‚³³8v6ôL#-3÷É–n/„Bˆë›*wl‹ ï•·Ÿ®çÛŠîD®â|Ôjun¦OñÂT¡¡¡$&&ÙVïŠŠŠ°mydN× ÎÛã¥Q1øÖš ¾Õ½‰Š’tÜûÌvÛ Ž\lÞ ˜Èê~¨TЬ¾ý¾~~%êChh¨yÜ ™>ž)Î*Ra¾,úO[‚ÿWñÓïñdé,™1?íŽçÖÎy™³bT¿:¼ôh ý½HÏ4ÒÿÑŽª*R|RµÂýlÏCC §ÆúhÕè f´ÞöÁVWý÷ÕjxxX}Vß¶mõwçi×¼|2ë\õ/¬ªq‰:êDZæòº|Å~¾/wÞgªø¸¾EϘï(q±¤í[ÚtüþV ÑêŸuþ¥ü½ÿ`â5ï¿GðÓÐå¦P·çò¤ýâr÷çÃÑùÕ‰ôgÚM0™¶ÿ™È[Ÿ— B!ìÈœ>Bä*j˜—¨¼dNŸ²×?&ŠW?eopË0°çÞÜÏå+:¢£¸o@Þ Oo}rœ;zDÒ´^·wà­OóÒ£-,ÇMhÊâU'™¹(‹êU}ypH=~Þíþœ,-…0îùÿ¡V«ˆíXƒÑê*óä}˜·ì0o~r EÉËjrÕÿ¾]ÃyaÑA.%dS5È›¶Í«òîó7U£dÙzù9 mÿ8ÆeÿFõ«ÃûkOñàÌ=ŒÍ®½Wlû]ïÊèuY²æ$Ìø“îëW‡]ÿ\q}`)µÎßßûF³hÕ ˜ñ'ÝÚ†1n`t¡:½ÿVýzF²tÍI3¸Ümß‘üï½õyþ¾¹ûóáèü†ÞV›Ï7ŸcÆ;iøù¨iÞ0„Ùµðè…BqR°ÅyT³W<¯ôiw¦@BªÚÿ+;;›Æ®@!JàØ±ch4´ZÇC%²³³9~ü8wÝuW‘ûíÛëQàgÆÀ%îwNNN…죉·½XÃÒ®WWRrxlî?¬~½sEw¥T”×ûûóî¶þ‘ “ !„¢ÄíÛ ÀŽŸ",,ooo§K¶M&¯Ð¹›e£MšY·3ŽîA6oÞL£F Ý[]MI$S“É}/û„×&Éô•Ö†9Ÿ;Têð/–×&£å±aŽeXÊ|:²rWlÚ±¶lyž• ŸNeÙâŸ89 ÝÞm$~ð=o®R¬zJ«?n׳aN)^Ðâ3Í|³í·´ «è®!„BTˆMälr !DAe½Z–¬Þ%*­î#aÃËpS_8ô Dßdy P%v®‚ä‹ðï–2+§[ʤÄYÊü¸Îîƒæ·0ò÷|õÖ:y ­JsÒ|T×SZýq»ž{f”ßõv¢Ï„_hÓ´ ½Š˜ J!„âF` ú8ZšÃM©W¯rüÄ ²³²J£OBˆræçïO£† ©RÑ]q›dú\ÿ®Ù¡]á à‘,Ï»t\κÏI™Àn#¹ÏU{nÔS!e\(÷÷šý !„B”Tnœ§ÄK¶'%'qöÜyZßt3ÁÁÁ…öoûi ±·ö)i3Bˆ2”––ÆÁû¨[§6¡Õœ/¯( W¯^%$$Än¬jy“L!„B!„p®ÄAŸK/qS››©W¿¾¾¾…öW«V•ºÑÑ%mFQ†t:^ ‡ìsô9tè0çΟ§NíÚ´hѼœzX˜dú!„B!„s%úxyyS§N]‹Ü¯V«ñò*q3Bˆ2Hºu9vä°ÓrçÎçÜùó–ççÏD:µË£‹…H¦gd%,!„B!n<¹«w)Å®ÀÏÏ?ÿRꎢ¢øùûãçççpBB‡&<<œûÇO <<œC‡“P޽Ì#™>®Í^rˆ/¾ˆÑdùŽ7š¾üé"³—ªàž !„B!Ê”b¹%Û….¥¦^eï¿û¦÷­}H¸|‰Þ·ö!88˜½ÿî#5õj¹÷ÉÓLŸÑô›¢Q«xî}<÷Æ>4ÓlZÁ=B!„B”‡J;îjÕk/Û½9í… ê‰ç¨Qýåa«‡…’x%©Œ{$DÉœ8y­VËmwÜAZj2f“‰´Ôdn»ã6~ý5'Nž¤}»¶åÚ'ÉôqOÁ¹¶+pîm!„B!D9«”™>͟ǰ‘6rÇõbh«HÞŸ2µ¢»å¶=º»]V>âZËà!CÐef`2™0™Lè23_­_[èQ”«YZ z3†l3†,3ÙÙŽ†,3™>EÖóÝ·ßÒ¨qc¼¼¼¸ãÎ;Ø´y“m_ãÆéܹƒÞÍ-={R¿~}»c§N{†àà`† ÎO[¶Ø¶oÙò#C‡ # €wßÍ÷ßgw\ÿþ +î%`×o¿Ó¯|||:l˜Ý0±nݺñóO?³sçNníÓ‡ÿýùg‰ÚÂf³½^ïða6›Ë½O’é#„B!„Îy(eÜÈÀ!ÃÜ*—®ó&'ÇÀÎn# jHÉ)zñ±„„"#Âm¯µZ­Ýþz˜N;ðþûÿ-tlÍš–¹.‚ƒƒIII±m'((???íŽ uo8—3)ÉÉ|ôÑGìß¿ýû÷Ûí[úþûÜ?î~î9///¾Ù¸‰›nº©Äm áŒÙlæÈ¡ƒ:r„ìÌ,ËF• •Ê2JÔ:˜`-š6¡a“¦å6G˜dú!„B!DѬqžJ3¼ Ãàóöî;¾¦ûàøë&¹Yˆ#b$V©¢j7‚ ¢KQÔú©Z­QĪQ«U{õ¥j¯*b•Ú£jï#beïûû#rå&¹¹÷æÞäÞÄûùxÜGï=ŸóçsONÏ}>‡˜¨xbÂ㉊Ž'.*ƒWD<Ññ¶é–S¨P!>zÌÓg< yFÐÃGé‹-䃺uY¸haš¼Ï^Gׄ¾z¥ñØugggˆŒŒ¤@ùLq£Û¥kBCC騩«×¬ÕHsv.Ì–­[¹uû'N¢SG¹‰Yïâ¹ÿ8}ú ‘‘(¬¬PX[aem…ÂJÂÚ*i›•ááž>ÃÕK³­mé#„B!„K?TÆL"b•ÄÄê¿ lX´2ÝíÞÞ-¸ví*îîî¬^½šµkÖ°}ÇN®]»Æñãÿ²k÷.¼½½¹qã*TPç5s&£FfõšÕøøø¨·7kÖœõëÖÑùË/Ùºe M›6ÕÚ.¥RIpp°Æ ‘>._ºÄĉ“pssÓXÏ aƒú|ÿýPZûúR°P!($!²Bbb"7oÝFaeE©’%háãC¾|NÄÅÅ©÷Q*•„…‡±g×N=âÖí;xT®‚•UÖ'K¤B!„BdÌ¢"}"c­‰‹'>*éÁ+!žˆØôǬFŽÅÔ)SðpwgùïË™1s–:m̘Ñü0v,¶¶vŒýa,£GÒÈ[¦LÞ©Z…ãÇŽá?bä›2GŽäŸ}ÿP¹REþúk3ãÆG›Ö¾¾Ô®UÓàãŸ5{}ûô¦QÃT®TY#mæ¬Ù̘9ƒR®%éõUOÿ¶Äàò…0D||< ñØØXÓ´¹7ª„D=àñà õëQÐãðòj†Ò&[Ÿä%‘>B!„B‘±¤QUV¯ê£Ÿ˜8kb£±RA¢¬¬ 1HžÅ›ô+$ÆB´–5} ,Èò?V¤›¶&Å´)Ï&MðlÒD#ݯ_?üúõK“¯³3«W§ã˜úI]‹ÿ–î~ºøúúâëë«þÜ×ÏOý¾víÚìß Så ‘Y¶J%*’Ö±zñ<ý'ÒEF„S°3Ö6ÖØ*ÓŸr™$ÒDz¬Øz— 7B™2°šAù†Ï8O5÷ütö-E-³ Ò?“þÉ<ÏîûÕï÷/óÌT™íÿ¬&߯~ÌõýYÊ÷ó¶¿.9µLqmâm§P$óXÔô®J]Y¶ø”9,*PÉ ±±±ìÞ½¥2ý)jBX’”Sº2“ž ô©R½F¶·ñm“Àúݘ;ò=ƒóöïXž¯'ž¡­wIìm­³ uæ'ý“1éãsCdLÿg5ù~u3ç÷g ßÏÛ~üºääþI¾®¥üBdŽE ú¬QËÜM0¹"…µ?ÕËÖÖV¦i‰!!!!ŧ´‹–k¦g‰ô1Œg÷ýߦü‡–­Eíi^¯}J¡´y3è~00„Êåœ(å☦Œ-û²vç}ž„DS¬°=|JÓúÃâêôR.ŽT.çÄ¡S!4¯_,Mþ¬fÌ/‰¦è]õ›»ŒaŠþÑÅÜýcÈùsáÆ+~]s‹¹£,kpE[ÿ^|ÁÆ¿pîÚ+âã)VدŠÒ¡U)“Ýàf×ùŸ™ëŸ)™ëúk¬œp}Ê ÇŸÏ}®–p~!’XÔ ¹¥ž¦e©e aNÙõHv]$ÒG·ñ .QÍ#?m>oÕM<õ ŒŠÇ)oÒÿffýqo»¸“?¯’ð(Ó¬eIOóÈLÿd5cû'ƒ £úVfä¬óLú®Žö™[Ë%³ýóuÇ )d@‡V¥Xp/Sõ§'»ÎŸ—aqü{îý;VH“–•ÇgjûO>eÞªÌñæ¦Ð’ÛoìõÏØóßÜ×_°ìï';Xòñç¶ó#½ëƒÂrØ(T ‹¹‘BXª´¿ ¥¿-{H¤n©ÿáhc­à³f%ù¬YI½ËHކ°³µ¢h¡¤…S?~µP~[B^ÄâZÌAc»£ƒ añÊoË·]’ÖxG^ͧ§/b(”?ó‘0ædLÿèËœýS¥¼Å‹8 P@årNç7¶’oHìm­‰ŽML³¥Ÿ?›÷ѪQqìlÓΨ×çø²š®ó3>AÅâõ·Øw"˜)«k,««ýcÇ.Kñ¾{¦Ú—Ùï××?cÎs_Á²¿SÕŸS?·œ]Àò¯ÏBä~Ic<2½K¡—ä¨át¢‡ÍB"} “Ù¨}òUtËÇ…ë¯Òü£²Bé¼üwå%M>(ªÞvöÊK*”ɧ±ß…ë¡TtÓܦK˜ÞeLÿèËœý³çØ"£“"³öB³º†-Æ™ÛûG—˜ØDvzÄ¢±ÆM‹ËJõÿÃà(Æ/¸Dþ|J«Mþ|JƒÊÎìtJ™ý~SÊì÷iìùolýYý÷cîïÇõçäãO–SÏ}®¦è!„ñrì ½•{.àò?™>&D6R¤ü±ÚŒ@éc9ê¿W˜þ ¦eCíŸ6-Éü57q.h‡{é¼\»Æ¢u·ø¦³»Æ~ûNÓ¬žá7S–4½+#ÚúG_æêŸ¡±Ì[}ƒÉ«£R©1󵪤 “iµÍ©ý£‡óAugƒK²“¶þÿûèf­¸N»®týÈÍèõF2+³ß¯±²ëü7–±?Æ2×÷“ìm?~]²ªô½>Xzÿñ¶§w ! ¢PX©_æ$‘>–£qíÂ\¾ʽG‘Û?|¿}K3å·+´é˜©K®Òíc7ǵß}É•Ûa4N±-;yvߝ޸HùÞ”´õ>õ›³f.¿N«FÅ©T6•Ë9Ѳ¡ 3ÿ¸®;£2ê],ùüIT©Øð÷Ú·´¼Ç´§¤­ÿ'.ºLxdaÂ7ïdi=)oD3½”ÙþÏj–üýZs}–òý¼íǯKNíS\Û„È —ÎàÀÞ=.ìŒR©|ýƒ¸…•+EÒzÉ)×LŽOHàéÓê6h@ùŠ• ®WÛ=H@@îîîiî­B_„nÆîS»²~z—¡>W&ðnÛIÛþÛèO¥Öc°³ÏÜ|!„ YÈ¢ïécY2ûº©ƒª›¸%–Iú'c¹±Öî¸ßå³¼SÜ YêM«%¿–Ä\ߟ¥|?oûñë’SûGz„0,ô9xð ¡¡¡øúúêÜwÉOs^¿SÑ«¯;qÁK‰Œ&24‚¨—¡8ØÆ°ä§Ùô3ŒO~XÇæqí³ªÙBˆBÖôBX²y£jš» B!„Y·¦OLL  `òäÉ$&füÒðX^ø~ßÕGi_¥} ½ƒ³Û¸ÖhŽÇ‡ŸÒï»ú\}ðL¯ú7oÞLµjÕ([¶,;wî|SWX½zõ¢råÊ|õÕW„‡‡ë,ëåË—tïÞJ•*Ñ£G^½z•î~ 6äîݻܽ{—† ê¬ÓÕՕŋӢE vîÜIÙ²eqssÃÛÛ›ÿýWcß”R~ 嫯¾ÂÝݦM›rî¿ÿôê! ¦R½y™‘Dú!„B!DÆ’}²`ºFóæÍY¿~=k×®¥W¯^DDDhÝ÷ÛQ~<»sb_eü&toBåž ¨Üsþh µÌÓ§OsâÄ ,X€ŸŸŸzûÏÓ¦1xð`Ο?OÓ¦M™9s¦Îc™6m7&00-ZðÓO?¥»Ÿ——’"¼¼¼ôªÓÎÎŽU«VàççǸqã¸yó&ß~û-ƒÖÙ>€‰'òÉ'ŸpùÒeÈÀAƒôê! •˜âeN†Fú!„B!ÄÛ@êqž,}üN­ZµX´h»víbáÂ…êí;¶mM³ï«H[݃>Wòy£J\^âÇå%~to^]ëãÚ „ƒƒ-[¶$..N½}×®]T¨P¼½½Ù±}‡ÎãØ»w/mÛ¶%Ož<øúú²{÷ît÷óòòâàÁƒ@Ò §§§^uúøøàìì @½zõØ·oGÅËˋÇëlÀž={hÚ´)6J|}}Ù»w¯^ý!„¡TªDõËœ$ÒG!„B!2–¥ 9Ò»woZ´hAŸ>}ÔÛÓ[Ü9,Z ±¡tŸd‡"ihŠ×cTðúBñ?Tª×) P¨à×9Ó”W @tÛŒ›››ú³R©ÔyOž}úЫW/† †•UÆAEáqv÷€e߇ÑvBqºýØYg=ËF®2¨]… âø±ãØ(õ?tgggÂÃÃÉŸ??Q‘‘ê”ÔA·³³£ZµjüðÃT®\Y=£«Î”ssvvfãÆÄÄİiÓ&ºuëÆ™3gÒäyþü¹Æç"EŠ+“o ‰ôÑmü‚KTóÈOÏÄ'¨Øºï!篿bŒ_•4û¯Ù~Ÿ­Jew3…B!„Y$i$& Öcµ³³cöìÙøûûëðˆˆUB\8Ä…ã=ª üÛGtD<ÑÉÿMùŠcîõ¬^ÜÖ v5kÖŒkׯËŠ+øøãuæñòòbãÆDFF²- @=mKÛ¾üñMš4ÉT^^^lݺkkk ,ÈË—/ÕiJ¥’;wÅìÙ³5òy{{sôèQbbbزe M›6Õy\BdŽ*ÅË|dMÝü{UÂÚJÁðéç>ýÖÖ ü{UJ³ïƒ'QÜ}IƒšÎiÒ„B!„9ÌëÛµ,‹ôiܸ±AûGÆZC|4õÇÔ¥×ÐæD¼ˆMš¾¯çu%=,(9(fñO»Ù·ú#ƒÛ5|øpÌáÇ)W®³fÍÒ™gذa|÷ÝwL™2…:uê¤pI©©—£@c`È:§M›ÆðáÃùæ›oP(,X°@–¼³££#ÃyH ] IDAT‡×È7tèPLß¾})[¶l†mªOíR˜q~—Dúè'õW¤í+[·ó>í¼]±2çœ=!„B!„Ieéš>´hszkø¤gM ÿ†ôì߀ð—±I‹õ$-âCêE|–Ì=¿}´–•zÚUÊÏ `É’%:ó¥|_¨P!–/_®óJ•.¦~}ë¨Y³¦Ö…¢[¶lÉíÛ·ÕŸ»té¢~ïääÄâÅ‹õª#õg! aÞøž7dMÝ&/¾B5÷üLTf=0ePu¶ì{ÈäÅW4¦w½ ‹ãßsÏèß±‚[+„B!„0µ,ôÑ׉MÞÔøx/ógÓ¹ïÙ¿¼³¡EBˆtYȨDúè–zÝkŸ5+ÉgÍJjlß¼7ˆVŠcg›¥tB!„Bd30ïxR:û—¬C#„¥K9½Ëœ$ÒÇ0ڞܛȎCX4¶vö6H!„B‘å,&ÒG‘SXÆ Dú˜ÆÎÃù º3ùó)ÍÝ!„B!„‰I,¿"G’§w/Q¥bÃßhßRÓ.„B!Dn$‘>B=©Rý7õûì%‘>Æ;|:·ޏs0wS„B!„YÀŒ¿m³³wÀÖÖ6Ãt!„eSXYg¼Ãë …Ê2Æ|dMX»ã>~_”7w3„B!„&–|ß&‘>B½¼ßQ¤³-ûI¤ñæªiî&!„B!²¬é#„0*ÅË|dM!„B!„ÈXŽô©Üs¹› Ä[G¥R©_æ$‘>–eÅ¡­ _9#Ûë¾r+mËözM-'÷ŸçØîêWf™ëøuÉ-çWVËì÷'ý«Ÿœz}0ŵA!„ñ^úXÆ#˜…–O‘âeNéc9¢ccXl7ý[tÌöºû·èȺc»ˆŽ‹ÍöºM%7ôßþ±ËØ?vY¦òšóøuÉ çWV3æû“þÕ-'_Œ¹.!„0žâõ ›E®ésnÓÏÕ?›dPþ"…yòÌ”MB$S˜{¸'‰Dú¤uáþ ~ݽ†¹=Ge*=µ”¿ÎÚ)m)šß™æÕêѱJ›7ÿû8x9Ê%ËQª°‹Qí×Õ†ônJv¡rÉrº|ŠæÕ뛼~]tµ/%mýÿ6÷h?þÀ[Ùøïßœ»{ø„xŠ(Œ×;С~+ì•ÚaˆìêϱÝÍzó›™ú³ãïßÎ?S°Ôþ5¤ –z}Ba¼,ŸÞõÉçí Úÿ¿#¨þÙ$×ý *C|„Èý$Ò'­5G¶Ó¡~«L§§'ù—Ú-Cç2âÓ^œ¼yköçÑkghRõýLµÈ0ô_Ÿ_Š=«¾ÏÑ«g3]¿1 ù%[[ÿ¿ÍýÚé¾?iT©Kü&°mø¦vÄ“—Ï¿a¾A囫ÆoXÀŸ'öŸ@|BžØÃø Ù35ÝõgËß¿™Ï¿ÌÊ)ý«OýÉ©ßBˆ7,bMŸùãzýšJ•FîÄ/%êΞ›Æƒƒcp°aþø©|òÃ:3·Vˆ·eLð’HMž=ánÈ#TJÿ‰\ºÒu±SÚR¹d9F·í˾‹'4Ò®>¼Ã;¥ÝÓäñÛƒ—NÑeÎp¼ìEïEc¹ñø^¦êÏÈ;¥Ü¹úð¶ÉË5¥Œúÿmï?mÇ?·ç(Z½×ˆbù±±¶Æ¥@aú·ìHà­K€å÷ÿ§½°¶²bøªé _5k+kü?í¥Wþ‰›2}ÛïêÏ¿l]ÆÄM‹²­þ”²òïß\矱çONé_c™ûú „ÂxIñ£&~Ïþýû‰ŽŽ¦eË–êm;wîÄÞÞOOÏ4û‡ÇÚ_´#º¿™3¬´‡Boöñø0é¿WèŽâI9½+00Ñ£FrñâEòåËÇè1?СCèõUOT*+UbÊ”)Ô­[/G,ÄÛÄ2Ö34Ò§Jõænr–Zwl'íêzc¥eú®t}¥·€÷óðW8ç+˜îþ{/üË´.ß“ß1/kídfÀr½§—é«p¾< ep>] ¦”QÿçÔþ3•ŒŽ?µc×þ£†[%õgKïEªï;õçŒ|׺+½~á˨Hšîö[ß ÙVz²âïߜ矱çONè_c™ûú „ÂxY²¦OxX}úôæ¯-[©]»6§N¢çÿõ`áÂô¡úã š ±n:˞н‰ú©]þh sÿß|¿ÿš{{³qÃÆŒ­ôéõUO&NšD×®ÝØÀ€opâäIýTa6éóÆËˆ0þ½~NëBŸºÒõË­àÌÛ¹ Ï*úO5øºeGŠ8%àw¨ßŠÕ‡€´.†¬c*ÙU1ýoÉý—Ýö_<ɼ«˜ýoÖý³äþ™üçbª•vgJ§A4›Ð“)±åÔ>&ÿ¹˜1ŸûéÌŸÇÎQmû2rõ,&uüG;ûl«?%Sÿý[ cÚ'ý+„"§È’Aß6mð;Û/;wæ?þ K—.øùõ÷M6oX—f­ŸW‘¶«ã—„‡+ù¼Qg>oT)ãýR8rô˜ú}»öíùöÛêÏ 4`ïž½”+WžfÍ›Óæ£ô.Wˆ·•±¿dšŠDú¼±ùä^Z½×;-‹ÛêJÏHòͲҖ¢N…ðzç:7òÕØ§PÞü„„¾ÀÕ¹XšüÉ7$öJ[õS`RÞx»ÈíÓ°Ê›?Óù³š®þÛû/£ã‡¤µRï]Ͼ‹'˜Òy ¥œß,hkÉý“úÆßÆÚšÏ>hÆg4Ó»Œ*®å)^° …‚ʮ岽þ¬úûOɘóÏØÁ<}Ú§MNè_S všûú „ÂxYöô®#GrõêU||ZѲe+FŒ©NKoqçß~íÍÓˈº±‡ >©Ó½–’r*‰ P(þ‡J•´šˆJ ,]üZÛñâùs–.]Êùóç8þ¼FÚ¯ Ò£{:uü¶lÝÆ»ï¾kì¡ ‘«YÊ Dú$‰‰‹eÇ™C,ê36Séºès£P±„î_×zÓžÕ.Ü»NÅnçËŽé]úôNí?SÉèø>füÆäwÌÇâ>ãÈï˜/ÛÛgŠþÉìù´çÜ1"c£“ÞŸ?N³ju³µþìøû7¦-%ªÍRû×ýcîëƒBã% údÁMœ•• -bô¨QLøñG¬¬t¯uc;¥;ŒáÞÚñP§;ŸŽî¦3ϲ‘«2LïÒµ µkÕ¦c§NŒ([ŽúõÞüƒÉÙ¹0[¶n%&&†õëÖÑ©ã\¼tY÷Á !ÌN"}’ì<{˜Ü«k½Ö•n õ=Þ㟠ÿÒ²FÃ,«##û.ž Y5Ã×cËŽF}ú?§öŸ©h;þ¿ÏeÖö´«×‚®?2Û€³¹úçEx(óv­fr§¨P1bõLj•«BÁ¨R±áß¿i_¯e¦ÒM¥q•Ú\ºÅ½G™ÊŸÑà‹çØîꈜ”ï“Ý}ú+oÓ¸r­LÕm¬ŒÚ§oÿ¿ÍýÚâ¦E„GG²tߟ4×CÝ~Ï±Ý ŽÔ»üœÚ?3·/§Õ{¨T²,•K–£å» ™ðG¶·CcÎ_K8ÿ,±×‡ŒXòù/„Ât²lz—¡¢‚þÅÉ¥jŠÏLjxóz^IÓº^ÿзø§Ýý³ƒÎrgÍžCß>½‰ˆˆ _¿þi3gÍfÈÁôíÛ…BÁâß–˜ìx„È­,ez—DúÀá+§q+RBkØ¿®t]ô„±WÚÒ¾^ æïZÔÎ3Ìoht®ýçï^C‡z-±·µ3¨\Sɨ}úönè¿ä›ÅÌDOrü)å¤þÉŒqí¿ÖøÜ§yÚ©ñY);þþÍÙ¿¦8L]zròõ!£)´B!²O–ú¤·hsj÷¶ù“·dÆß€¼%òp›?áÖCH½ˆÏ’¹G8ÐV¯ú}}}ñõ}³(^_¿7 ïÕ®]›ýûxDB¼Ý,eÐG"}`íÑøyk?6]馔zñÑì2µó ³Ô«Cú?'÷Ÿ)n”ÍuüºXòùeI2ûýIÿê'§^,eÍ%!„xÛ½ôQe¼WV ½IªÕxù ”1?d‰{ ”.GøñóÌÿýXšÝ/ïúXkQÛ¶mC©Tfek…@"}`^ÏQF¥‹¬%ý/„B!Ì'iœÇ"¦wݹJ©ÆM°.êD¯¯?ú¨+VJ[‚î\åò.Ã~ÝèÓ»—LÓ" ©To‰Íõ#‘>B!„B‘1‹ô)ã5ˆã˧P¸´ñ†z»¡‚š~¡;!$«T‰ê- E–®Ÿ!‰ô1ÞXEÒÔÛ±ªuZÓÔŸÓÙGŸrrK?>}ÛgéÇa¨”ƒÎ)£³Â¤I“8räÛ[·nMÆ ñ÷÷ÏtÙóæÍc„ “˜˜¨;ƒB!„,bЧDÝn”¨«ûñìB3R¥úoê÷ÙL"}²VòÀ@êÁ!,Eò@OVGFDD0cÆ >œ&múôé4lØo¿ýV¯'•¦güøñüùçŸÔ­[ר¦ !„B¤ñúgzËX˜Ua¹T¼ÌÁÐH}ÄÄÆñôY(G/³}ß)Ž^æé³Pbbã²øhr¶±ªuf«hoÔà”®üæ>>],½}–*<<œR¦Lìììððð`Þ¼yiöÛ´iuêÔ¡bÅŠiÒ*V¬H:uØ´iS¦ÛLýúõ±²2_ä¤B!rŸä@h“DúÄDG¡JLÈ0ÝP;¶m¥•ocš%„0@ll¬^ûeõ4 }™:Ò':6ŽK7‚°QÚP¶œ+ùòæ!,<‚G!/¹ÿä9U*””áq!r‘Ìž={(Uª7nÜ`àÀ899Ñ¥Kõ~[·n¥}{탂íÚµcëÖ­|ùå—·!!!Ábžˆ(„BˆÜI~VBD¥R©_ædêHŸg¯"H´²¢D©âØ:8“JGJ”*A¢•O_„eÃQ&9BeK¯…L)Ðÿ5MØÃiÒµ}N¶å«_™œ¿Kÿ@Ø£iÒuÕŸQ¤ÌËðë{C™”· ³+|ÃÙßè]þ“swYé3™Ÿ ÷äGûÎüVo$—ÿƒ%«V­ÂÃÃ{{{¼¼¼¸sçŽ:M¡PСC *ÄØ±ciÙ²% ä×_U§Ï˜1ƒ"EŠP¬X1 @LLŒÉÚÿ×_±páBÜÝݱ··çwÞaÙ²e,Z´H£œS§NÑ A­õ4hЀS§NéÝ®dñññlÞ¼WWWƒó !„BèK}„9’©#}Î_{€£“q*"㉈KxýßDœòsñÆÃl8ªÌqy· ^;rïÈUöø¯2< 7šNêÄÝC—Ùk@~]ÓŠïåÏnóÈW¼ ß\›MÏ£?rïð½Ë_Ûö®ï8CÇ-Cñýß_{sqíQ­õ§×ž'çîÒ÷ìÏ´ß8„ë;ÎÐÿ7½ógõñUhõ ±ñ< ¼ÅÃS·HˆÇ½Õ{êôÃS6sô—­4Õ–Æ£Úrô—­™ºYïöí¾’»‡.ÓtR'ŠU/£w»’Íœ9“}ûöñÏ?ÿpëÖ-lll=z´:}þüùüý÷ßüùçŸlÚ´‰={ö0þ|26mÚĶmÛxþü9Í›7×$‚¤¢-[¶0nÜ8† ÂöíÛ™:uª:}ÿþýœ;wŽÿþû»wï2yòd“µ_¡P¤esþüyÏ?¦D‰Zë)Q¢þ ¥RI»ví˜8q¢Áy…B!ô%ƒ>B)R¼ÌÇÔ‘>!/à ǖõ+6³nÅ_¬OñŠ@IÈËpe˜KÕõ©Ú¾·öœ32ÿy{ëïøÌ¤'µ˜Ñ|% ’§h~>ZÜGïüqIQG~ÞÂå?O¿ta>_óAmh³°7y] àöa»fPþŒ{|Z&=Qîþ±kêv%oƒ¤("€ªíë©¿C"‰nÿsAÿ/êë/ÙâÅ‹Y¸p!nnn,XÉ“'k¬]ãääÄÊ•+éÛ·/~~~¬ZµŠ|ùòi”±aÃ<< -eþˆ§¡&i žJUÀ­H¦ò¶r»ýΕÍ'¹²ù$6vJ|íEîžz念ç<{üWr%ˆØðh¢_Ffª-é1öøÊ6©Š’ûG¯J…½·&UÕ類šßOXÐs½ËO>Ræ7Ľ{÷¨P¡‚ƶԋ ×­[—råÊ¡P(Ôƒ7ÉNŸ>Ͱaà äÅ‹ô§ ÚÙÙ¥y÷fáôÒ¥Kk¼O9 dlû§M›Æ¸qãhÞ¼9>¤B… ôë×ÀÀ@<...áîîžn=AAA¸¸¸èÝ®döööøùù1aƒó !„Bèë­‰ôТ¡¹› „0!SGúT«àJTh(¶Ö`g­ÀÖl­ÀÎ"CèVÁr×݈zAÔ‹¤è„â¢ô[è;¥äÁ”ëè¢l“ªô=óßÿFÓ‰‰‰c÷?ôο¹û<žºIçíþŒ[˜v!rcOéhG™Æ•ypì÷]£Lã*(lÕéN% šßO¾×ÛôáèœïMþç†Gª¹¹¹ñüùsu¼4Ú°råJ eÕ*Í©íÛ·ç‹/¾àÖ­[¨T*ž?×À*Ù½{÷4Þ/^<Í>DGGÜ~GGG¦NÊ­[·ˆŽŽæÂ… DDDдiSrj׮͑#G´¶ñÈ‘#Ô®]Ûàcpvv&>^ûߦB!„±,vÐÇÐ'wœë©ñøé“òê—«Ã#ÏBˆLR©Þ¼ÌÈÔ‘>… äA‘˜Àã GÄDD ´RÁ“ ÇX%ÆS¸@æ¢%²Ã¥õǸ´þåšUSoO4xpü—7ý«_þ¦Õ4Ò\j¸pqÝ1ƒL>Ð €Ýƒ—öèOCÙùÝ2½ó¯ô™LÐÉ›Øçw¤lÓw°ÍkŸf¿¼ÅòðüÆcí‰ñI7øvNŽœ[q(M>]ùu1öø i]Ÿ°G/ü÷V54Òªwi h~?ï¾Þ¦ä¨¡Këq!ÅZHúêÝ»7={öTO:vì}ô‘:ýÉ“' 4ˆ¥K—ò¿ÿýAƒ¬NŒŒ¤hÑ¢8::rçÎú÷ïop†ÊãÇyòä C‡¥cÇŽiöy÷ÝwY¶lYš)]íÿôÓO¹xñ"111ܺu‹I“&1cÆ ÆŽ«QN›6mX¿~½Ö6®[·Ž6m2÷´Q+++¬­­Ó´]!„ÂTRLﲌ)™ð}u>›s]cÛƒ³»þçï‹ØÖw›»ÏP/œú‰QÉŸ“Ók÷iŽµÒ†ã³¶3»Âòu¢ñ¨¶zW¯[²gøJ»†•5¥êW¤ùOi‹í5±#ûXÇœŠß¢JT©ëo=ÿ+vü¥ÇPåóºZëÑ–?«À½U v úÐ\Ï ‘ÿ§Ä¼ŠäÀø ÔØš†Ã?IÓmík6¥3/o³ÇUÛÕ3¨]$=IÌ××—;wîP¥JFŽ©Nïß¿?=zôàý÷ß [·nôïß_=@²lÙ2 Ä矎««+“&MbõêÕµ¡~ýúT­ZkkkÚ·oϨQ£Òì3gκvíJ¿~ý4ž,¨«ý_~ù%mÛ¶åæÍ›-Z”¦M›rèÐ!Ê—×üa¨mÛ¶ 4ˆ+W®P©R%´Ë—/sòäI6lØ`Ðq¥T²dIöìÙC³fͰ¶¶Ît9B!„)%¯Àªÿû•wí–äσSAÍu ¢¢¢ðððÐZÈ¥sg¹sç.<=±µµMwŸÛ¶êµsðàA¢££ñööVoÛ½{7ööö4nœþ¯›'§{ò~Ïÿ úe4ÑÑÑD¿|Iþ21§o[zÿ0’à æÎÙÂø)ÿGpP›[ÈÐÍ7Ó”µsçNüüüP©Txxx0aÂõ®®®üðÃlذ]»vÊ Aƒ8pà¥K—fÆôéT÷]½ŽSKË¡ýûqs+£þ¼k{1qqtèԙ𰤵^RNE°±I7ΛωMÖa¯´£I³fØÚÚf8ÈríÚ5¬­­µ^7 éúsýúuZ·nnú›‡4ð£kÐG111k˜[ê›|!r…BaÒéxƘ!4>!§OC¨Û iÉ™ò+\¯¶{€€ÜÝÝÓÜ[½zB¤u8»wZÖô®ððpúôéÃéÓ§¤E ûôéCx¸öµbˆû`_{—ºpóÄ¥Æ'üôÝV,ØÂÜ9[3üìÞ’âžÞ?~~~Œ7Ž›7oòí·ß2xð`t;;;õš'Nä“O>áò¥Ë 8ƒßBä Å›—™zM!„ÐÆßß?Í€ÀöíÛðèÑ£>”!„Bd +°œé>>>ôîÝ›=zpêÔ)zôèAïÞ½ñññ’¢†Òˆ¢§yMX½€ ‡0~JR$ÐÜSøÒ/i>ÿì]‡ÓU¯^=öíÛÇÑ£GñòòâðaÍ}|||pvv`Ïž=4mÚ¥ ¾¾¾ìÝ»×TÝ „eË¥kú!„B!Dn‘|·fql6lׯ_ç“O>ÁÛÛ›aÆ©ÓÒ›&Ötl OO,#êÆv*øP¤Nw6 NšÆQµjQ¶Žú€µQ¿¯Zµ(#ëÑzâ1²æÌ™CïÞ½éÚµ+J¥’ 6P½zuuzò€Àóçϱ·O» ¨"{˜zMŸœH¦u‰ÜÌR¦v !„Bäd7èceeÅܹs7n?üðVVºg EÝØNéc¸·v<ÔéNë~îÿòåKŽ,O»˜¤³³37n$&&†M›6Ñ­[7Μ9£NO9/¯H‘"ÄÆÆZÔúB¼M$ÒÇrÈÚBB!„BX&‹ZÓ'™££#S§NÅÑÑ1ÃýììxzàŠÕªÊ§ïT£X­ª<=0»2} úeº¯äŸÔQ>^^^lݺkkk ,ÈË—/µÖíííÍÑ£G‰‰‰aË–-4mÚÔèã"gP¤x™¬é#„B!„³Í–œ&*èßTŸ'½‰ŽNózÖ€iÓ¦1gÎ*T¨€ŸŸ ,ÐZïСCYµjÕ«WgþüùÌž=ÛdÇ$„E³Œ1‰ô± cU댊ò«hŸæñã9…"'4¤´páBÜÝݱµµÅÝÝß~û-›[(„B!ÞFÉÿ>µ¸é]ÉôyÔû½mþä-™€ñß'=Ò=o‰<ÜßæOÑRšû¾¤@†>5kÖd÷îÝé¦=xð@㳓“‹/ÖuBä:–2H,kúK¼îLz6l`âĉüñÇÔ¬Y“ÀÀ@ºt邳³3Ÿ~úiv7U!„B¼…,vÐG/¡7)Pµ/„2æçƒ,q¯CÒå?~žUóÏ¥Ù½Ó¬3é"„ÐÏë›[çý™o¡U‰ô1¿ÔÑ9©£}’Óktû«[±±WÒjVª|^7ýü® ¤P(ذa#FŒàÞ½{T­Z•ß~û5,c€oþüùüôÓO|øá‡xzz2eÊæÎ«1è“<`$  !„BSËу>Aw®Rªq¬‹:Ñëëϰ.ꊕҖ ;We€Gˆ\N"}Ì/ypF×Ô¬òÞïR«w3–4Íο¿ôI•?3SÄÖ¬YÃîÝ»)\¸0¿üò ýû÷çÈ‘#zåÍ(jÍ0gΜQø$kÒ¤  0ºl!„B!ô‘4è“C],ã5ˆã˧P¸´ñ†z»ÂÄ^_&)×7ã¥C"}rŽÊm?ÀZ™ô¿›ÐÏLZöŒ3puu`È!L:Uï¼YYг³3_ý5sçÎ¥pá¼zõ*[Û!„B!ÞFIÿÆÌÑ‘>Î5Úã\#g.þ)DN“|[ª²Œ%}$Ò'±±SfYÙÉ>ôäÇÈÈÈ,«ËPNNN<þæÎ @HHùóç7sš©ð IDATË„B!ÄÛÂ"Ù.„ºH¤0VÊ'o¥~™B58pà€Æ¶ýû÷[ÌšCB!„"÷3I¤½¶¶¶¦g¶\CmÞ°ŽO>—è! ¥°²Ök?«÷Ãæœ•"‘>¹GÞbù òŠç7S¨‚K¶Õ›ÕÓªú÷ïÏ!C(Q¢ï½÷§OŸføðáÌš5Kc?YÈY!„Bd•׃>2_CañŠ7‚*U¢ÙÚ!‘>ægìÓ·’yMìÈþÖ1§â·¨U™ZÐÙ\RF¥¼ùüóÏ ¡GÜ»wÒ¥K3fÌ'w½xñ€òåËgc«…B!Dn§zýoÓ½¦"ûYʱDú˜Ÿ®Á™4pײÍž^ÔìéepýéEÆdw´Œ®úúöíKß¾}µ¦¯\¹{{{6lØ`ê¦ !„B!ƒ>B)R.&‘>BcÉ’%Ì›7OÖùB!„YB}„9’DúˆÜàÌ™3æn‚B!„ÈÅ’~²—Å#5 j”u ‰)윭ù²[Êvš¢ÍÁÁÁZËf¢J|ó2#‰ôB!„B-^óäºHCŸÜµBM¬¢ã5¶•+nÏÁ‘Õ5¶%ÚÛà9ú´Ñíˬ§!ÏÌVwf™¢Í5äêÕk&-SÇR†ˆ%ÒG!„B!2–k}öïßOè«W|ôñÇ峊ˆ¥DËÁ8:&=®úɽ`òDR¢¹·Æ¶°SËLÝd¡‡çÏdÇÒ˜ó‰])I¤B!„BdÌJ÷.9CLL4ýúùñã„ $&êSš˜¨ÂÑњ•J`o¯Ä!_^€4ÛµÇ7„……Ñ£{7Ê—+K·®]W§=öŒÏ>ý„reÝX¹b…F¾ÔS•2šº”2-00ŸV-)SºïT­ÂÚµkÕi”(îBq—bxz~ÈñãÇ´–™Q9E ;³rŠʺ•¡¯/!!!z¥ikó«W¯èÞ­+¥K¹Ò¸QCΞ=«³ÉùµM{ñâ;u¢¬[¾ìÜ™—/_jì·|ùï¼ÿ~mJw! @k?Ã$ªÞ¼ÌÉÐH!„B!„xÛX(,åÌFhÑ¢%nþ‹•+Wн[W"""ôÊÿzfWø§IoRtFÊmññh5eÊd†ÆÕk×iÞÜ›i?ÿ¬N?a< 6âÒå+œÐ”Q9C¾Š““í;t`Ïß떞ݻwÑÜÛ¥RÉGÌÁC‡õn‡6ÿ½›víÛ“'O>úøcvîÜ¡‘>xÈ÷8::Òºukâââô*SèA•âeFé#„B!„Ë5kúœ¥RI@@QQQLŸ1]ïc½|éŸ~ö|P—¹sçh¤5lPŸ¿6oÆÚÚš‚… e…“Q9³fÎ$<<œÕkVããã£wZzZ¶lÅáC‡ˆ‰‰aóæ?iܨ¡^íP*•§[f³fÍY¿n‘‘‘lݲ…¦M›êl‡0ž…Ìî’H!„B!„Ðæõ [®‰ôñôô4èqíQAÿ¦ú|<éÖ…œµßâŽ5Š©S¦àáîÎòß—3cæ,´óÎS»V-4h ‘/yáêÕÞ¡B… i=ÉkÖì9ôíÓ›F P¹Re´™³f3cæ J¹–¤×W=YüÛ­efT@™2ex§jŽ;†ÿˆ‘z§¥ÇÄV¬øƒŠîÌž5›ù èÕŽÖ¾¾Ô®U3Ý2GŽÉ?ûþ¡r¥Šüõ×fÆÓ½ ´0FÒPJ•¨~™søG"}„B!„"c¹jMHZ´YÛ>Éîmó'oɤé_ã¿o @Þy¸¿ÍŸ—Ïxr/8éñí /“ ½¼‚ ²üé¦999±ví›…¤?þäõûÖ­[óðÑ›)cÝ»÷P¿×öÄ*___|}}ÕŸûúù©ß×®]›ýû¤›/u™•àׯ~ýú¥[–¶´”u¤|Ÿ?~–.û=ݲ2jÇâÅ¿i-¿³3«W§3ŸúX3êOa s‡ø¼&‘>B!„B‘±\7裗Л¨Z—BóóA–¸×¡@ér„?ÏÕ]§ˆˆOäÜ&ÍH ÷*ÍÒÔØØXvïÞR©4KýB¨%ö¨Ti·™¡‘>Uª×0_c…B!„ ^úXÈO÷Ù$èÎUJ5n‚uQ'z}ýÖE]±RÚtç*ÝVÝÒú”.søõ×L2Ecš–B"}„B!„"= Å›•kÞÊHŸ2^ƒ8¾B!„B‘±·rЧDÝn”¨ÛÍÜÍ"gJ±Ø¹9I¤B!„Bd,×<½K‘M,ä™íòô.!„B!„Ș ï…*Qûã­b¢£2]nvæâm«×~*•e¬&‘>9‡B¡°˜ó&=æjŸ"EÔœ1õïÚµ‹®]»lÑýœSÉù«½ÞdºêŸ4iGŽ! @c{ëÖ­iذ!þþþYÒF!„âm–üg‰ôBDJý2'‰ôÉ9,ù†Ì×>•Je’ºGͪU«,¾Ÿs*KïWK?#""˜1cÓ§OO“6}út¦OŸNdddV4Q!„È ÂPÉKÁ›ym‰ô1?…B¡~ÙÙÙáææFÿþýyöÌ4‹½§,?Ož}šóçϳÿ~­ûÆÆÆrëÖ-ÆŒƒ———zû¦M›Ø¶mÏŸ?§yóæôíÛW–²þä÷)Û£«}?üð=â¿ÿþãìٳܿŸqãÆiì³fÍvïÞMHH}ôýû÷×HϨ}ÆJïøR˨þ9sæðã?2cÆ =zÄÎ;9zô¨Þõ§tHý2Dyïwé´ua_°sàïê퇧læÈÏ[h2¾-gvçÔ¯³Ü\j¸ñôòƒ4e=½x—nÕrþfåùûøñcJ”(¡5½D‰–!9Ú ..Ž;wîðé§ŸòÍ7ßè•7((ˆ2eʨ?—.]:Í>qqq„††Ê… ø÷ßÕ§OŸ¦yóæ*T…BAÞ¼yMzãøèÑ#6•)S&MDBÊHGGGGú³º}ºèªÿÞ½{T­Z5ÛÚ£…UÚëI胤•§èΤ¼]’¶ÝOÚæRÃØˆîºBä³0"Ÿ…qçÀ%â£ã Šô‘ó7ëÏ_‚‚‚´¦áââbp¹B!„ÐO®ô‰‰‰aÀ€Lž<™ÄÄD½ó%&ªpt´¦p¥ØÛ+qÈ— ͶÄDí¿b…‡…Ñ«W/*W®ÌW_}Exx¸:íùóçtèÐÊ•+³fõj|©§Ee4M*eÚ™3gøøãñðð fÍšlذA¶sçNÊ–-‹››ÞÞÞüûï¿ZĘ̈WWW/^L‹-4êOýßd›7o¦Zµj”-[–;wj­Sä|–2è#kúXÊ”)Ä 8xð ^yJ–,ÉíÛ·ÕŸïÞ½›áþU«Vå·ß~càÀ$&&Ò¾}{¾øâ nݺ…J¥Ò: ÙHîÝ»§þ|ïÞ=ƒnNõmŸƒƒÑÑÑ·ÏØúK•*Å¥K—2]¾©¦wiãT²Ã_,e¬jcUëŸ4€›<°szÉ?¸ÖõÀõwÎ,ùG#Írþ¦eªó·víÚ9¢=RúÈ‘#ê)uB!„0•7ÿvÈ5ƒ>Í›7gýúõ¬]»–^½zi ON-y¦Jø×ëÔ¤øÇjÊmññhõó´i <˜óçÏÓ´iSfΜ©N›mÐ1i3hÐ úôéÃùóç:t(ãÇW§ùùù1nÜ8n޼ɷß~ËàÁƒ3U$…­ZµJc[ò4®ÔÓ¹NŸ>͉'X°`~~~Æ¢:I¤eIHHàÑ£GL›6êÕ«ë•§K—. 8Œ¿¿¿Î<žžž.\˜Í›7IÑ¢EqttäÎ;iÖ#IV²dIHHH0è˜Ú¶mËСCyüø1?æûï¿§mÛ¶zç×·}ï¾û.Ë–-3¸}ÆÖÿÝwßѳgOŽ;Fdd$×®]3èúr™Ô/Sx·›''n"&,Ч—ðg×¹8{”@éhÇ¥ Çq󬂛gU.m<ŽÒÑgíëÇh#çoZ¦:Û´iÃúõëµÖ³nÝ:Ú´Ñ>ß~dB!r²\3èP«V--ZÄ®]»X¸p¡zûŽmÚŸÈ“{Á?zEðãP^> æúíÇi¶ÅÇkÚµk*TÀÆÆooovlß¡NÛ»w/:tÀÞÞžz†Œë²oß>|||°³³ãó¶ŸküúV¯^=öíÛÇÑ£GñòòR?…ÄÐr|||pvvÖ«Mƒ ÂÁÁ–-[—¹Âéc’oÈ’ŸþsûömÖ¬Y£‘–ú}2*V¬HÍš5yçwðòòR¯•‘Áƒ3mÚ4–-[†¿¿?ùòå£iÓ¦|üñÇéîÿÓO?ѯ_?lmmÓ}ú‘¶ö7ŽÂ… S½zuªW¯NÑ¢E;v¬Þ}£oûæÌ™ÃìÙ³_Ï 7ÝÍ­®ú À°aÃøæ›o(V¬Íš5³¨ˆ‹†Ã?¡É¸ö\ùó?ùŠ gáÞº& +Ū•&.27Ϫ¸yV!>:ŽbÕJ§;UL9µ3ÕùÛ¶m[Nœ8Á•+WÒ¤]¾|™“'OòÙgŸ¥[ö‹/4ÖXB!„arÕBÎôìÙ“Zµj1{ölòäÉ£u_;{žžXFÔí8Tð¡Hî,ؑ뷫÷q/û& :"è·E3ùïÛiÊ*W®±±oÖüQ*•êo777n\¿Ò†¸¸8Ê–-«Ž’I½rF "§L{ñâË—/çÂ… \¼x‘{÷î©Óž={öÿìÝy\ÍÙÿð×­n«LÛT*ÉVÈö¥ov¿D’ i2² É>²73R Y’}†/ Ù’P‰YFKvIhRÓ¦eÚ÷Ïïtu»{ݺ·¼ŸóøŒ{?çó9çýY:uÏ=ç|0gÎ<|øl6AAA¿µ–‰‰ Þ¿Ïù®vù¢â¦‰›'q'r®ý-~Íý!‹‰œ_===¤g¤à}Ôym’LŽ-„««+RRR™™‰Ã‡CSSSÖ!"6º !„"ïDÏ8ØÌˆ3PR¨'ZWÿZ·b( •‘Þ‡z"7Kž”Qýøv ¹©öÐ ---:tˆoš¦¦&Ž;Æy_û £Fâ æêêÊy-lN888pÞ»¹¹q^÷éÓW®\á»_Ý<…åSwÛÚïùå¡ùÒ|>-¿9}dAÒž>Âæ"ò­¾¬–$ÿuË–FZ†æ~íÝ»ëׯGFFªª÷J–7ŠŠŠøòË/±fÍO#„BHõ¸F±ä½–eä&çÁkëMêl -Ó(¸û¯.ßGaEžs÷êÜM[&¡–——ãêÕ«`³Ù2)ŸyE=}>MÑØ"¨Œšõ4ÇYËÕÜï¯uëÖáܹsèß¿½ó…òòrܺu “'O¦FB!¤µ˜á]’HI|[Šú&p[8Šú&P`ë!%ñ¾ùí9Þ¦–à›ßžs-}— ~ôyc:pàæÏŸÏ5L‹Y`„,²@súÈ^II 6mÚ„=z@SSZZZ7n®]»Æµ5˜ú ûK<8p Èù ù±dqÿÛ”û+((`èСÈÈȨ_á„BËgÙÓ§íRÜ ðhxq6³€À§tÉÂüùó1þ|Y‡A‡¼ q¡ž>²çêê œ9s:t@~~>nß¾M›6aøðá²4st‰VYYÙ¬½ji[YY EEEY‡C!„´HŸeOÝÞ“Ñgé]žE·÷dY‡FˆÜc†³Èõô‘½°°0lß¾]ºt²²2tuu1nÜ8DFFøô®öëºPY,üüü`jj øûûs¥ñÛ§vúÙ³gaaa555XYYáÑ£Gœô²²2,Y²Ð××ÇÎ;›ôr·nÝpçÎÎû;wîÀÒÒ’k›ÀÀ@˜››CUU¶¶¶HLLäJv~›7k2¼Y“2c/6ë~‡mÆîxt—“^Y^‰È•Ç°ÍØ[õg#tÞ”•ü Ýø¡!VM|æ~zïí¬v¼}}™˜˜ $$|Ó…]#B!„ˆ¦,€ë©U„"﨧ì :ß}÷nܸââbžôڃ ###qíÚ5$&&"""‚ïþ‚œETTT=´~œœœÄyæÌ899qmŒÐÐPdggÃÎÎsçέ›Àó#JíFº‹$:Žì…)W!ÿŸDx嬿½)n½€aëœ1jÇ Ü߉(Ÿêã5ìm†Ì—¼“úg>ÃÞfb•K÷—pl6NNNذaC£ä¿æ :¸z¸ ܽZ½NÚ6nÜ'''š»B‘2ÖÇ?s¤2¼KEU ÊÊÊBÓë›oSîGÈ猥 f×z9i ¦§wÉÞéÓ§áïïï¿ÿqqqèØ±#¾ùæ,[¶ êêêbç³oß>´oß>}PíÛ·sz:,_¾›7oæ¤ýþû±1`Ë–- ‘(ÿ†˜4iÆŒ0 ƒ³gÏ"<<œk›ÚB‹/ÆÏ?ÿÌ“O}Ï´zãuØŠìê?ò’³8ëÜt›Ô JÕõÇóÓw`·ù[ö6Ã_{"À0 ¶·ðHú^ýƒN£ÄûY¤ûK¸ââblÙ²›6mâzú§$ž3ÜÿÖÖª5°ù8°p\õû½:O¤¶¿¸|}}áíí•+WòM—u¯RB!¤¹û,‡wB€a>-2D=}d¯uëÖðööÆ£GPXXˆÀÀ@$$$`êÔ©åcffVïjmQWWGQQç}JJ ÚµkÇyojjZïrê£GPSSCLL bbb ¡¡îÝ»sÒ>|;;;èèè€Åb¡U«V\ñ×hÈù‘%6X ¼½5 @›´f`c«êF‡¼÷Õë {›¡¬°I·âP”•¢¬|$ÞxŠ’r±{úÐý%œªª*æÍ›‡øøøF+£W mÀ´#г_ã”ùóçCUUµq „B>sŸåD΄æzúÈEEEôêÕ ;wîäùðËb±À0ŒÐ¹Sƒ±±1Þ½{‡.]ºþþûïF)G˜I“&!(( Ã`Ò¤I\i“'O†§§'Μ9---äää@GG‡'úžaûI£÷Dkcd¿IÇêœÃPÕÒàJ«iØyxè˜ô7±‡þàJ“Ý_üéêê œ GB…ùÕ¯ÃÇ)Ò/£¢¢ºººÒϘB!¨§!‡24 IDATDRÔÓ‡|4lØ0!11eeex÷îV¯^AƒqmgllŒ°°0TVV6i|®®®ððð@rr2222àééÙ¤åŸæõ â™Ï§¨¨úúúPWWGbb"×|1ÒP{ž›º‹4ôšn¸¹!¥ùÅÈ|‘ŒsÓötÍÀVWÁ‹ »0³é3K¼8{lu蚉•?Ý_¢)((@QQ±QŽ=+ؼØpøù·ê×ÙR~ºzÍS»„5ÌÑD΄BHÃP£!D" XœE–èé]²÷Ã?àÈ‘#èÝ»7¾øâ >l6ÇçÚnË–-˜?>”••%úðÆïéL’ðôô„……úôéƒîÝ»ÃÖÖJJMÛÁµW¯^`³ÙPVVFÏž=¹ÒŽ9OOOhjjbøðá7n\“ÆÖPƒWÇ0ŸÉˆ;÷¶~9A.;ÑÙ±€¥À‚AS”•ÂÌÆf6ÝPQRƒ¦|‡ŠñC÷—xŒqõêU©7ü¬_|=èþ_ ‡50~zõ:i©¬¬Ä•+W8s"ñ“““èØ±£ô &„B>34¼‹¥C á+­QòþRO™²Do(¥ý„ ÷ٰ5 ¿ýv¸ÑË#-ƒ¼|ãJ=}dÏÎÎvvv"·sqq‹‹ ß4a½NDõHá—^{²²2vìØ;v¨žƒÅÏÏo^5÷uÝ<¥q¿ šseäÈ‘xöì×:ggg®÷²œÄÖ›9-ô½"[ÿç5 ÿçÅ=l­Æì»ÜO•ª»¿(t‰ÇÛÛ3gÎDZZªªªœ_AÜï—næ¿]}±Ùl }úØñãÇ¡ªªÊ5á9!„B$Óâ}ÆOš,ÑöQëû@¡„{<|‡6ª¸ù#÷7²UªJ°Yó°ÁñÕWc4À¸Íž…‰õG5!5ä¤Í‡æô!b™:u*Ö¬Yx{{cüøñ<Û4¤a€|Þäáþš9s&fΜÙà|šš8 T‡ÂÞ½{Ñ»7Õß„BH}}lôiþÔFEE!ïß1VÂîñ …e0µ êêÕ›MOÊ€FÑÙäZ—ÿˆ´C–¹òòr8::Ê: ÒÌÈˇ`êéCÄaoo[[[”••a̘1X·n¬C"-Ý_+66VÖ!B!Í‹Uý¹­ÅÌéSZZ‚ùóçáçõë%êÞ\UÅ@]]z]Œ ªÊ†šf+àYWU%øƒn~~>fÎ˜ŽŽÚcú4WpÒ²³²0áëñèÐÞ ÇãÚïK=]¡ï¥=xð£F¡i[t·ì†S§NqÒÂÂÂ`ÔÆm `có¸{7Zh~5ÿ ‹“yDsúq¸ºº"%%™™™8|ø0455eiAèþ"„Bˆ¼k1>öö£p.ä<Ž?†Ó§¡°°P¬ýjžtZ˜Yý¢ÖØ•Úë„=uÓ&_¬\¹ ¯â_ÃÎn$ü¶n夭[¿ƒÁ‹—q¸wÿžDÇ$ÈâE 1þÄ¿NÀ?ü/¯5œ4·Ù³°aãF$§üƒeK—añ¢Å|ó¨.VóocÄIZ*V­Ev¨§!„B!„×b}à¿ÿý/Ž9ŠK—.aïÞ=œõ!A‚'¬¨¨BzR2RÿEFZrS3ðú]ÏºŠ Á½‡.…‡£³¹9”””à0Ú¡a¡œ´«‘‘p™2ªªªXê±T*ÇùçhŒùê+¨¨¨Àiòddg}šïgРA¸võnß¾vvøëžx 8'ii˜ê…Uk©Y'ÔÓ‡B!„B„S9™¢£ÁîÝ»‡3¦ÃÁÁ ,ä¬4¹sæ_GЭ¨™êáKë8ìá‚×犯ÚuæX:·7äl[˜V,ð©^hchÀy¯¬¬Ìy••===€a›6 ;Àr²³qøða<}úOŸ>åJÛ·?fΘ‰).ß@II .†¢W¯^"ólŒ8IË$'ó8SOB!„B ¦§Åôô¹|9_‡o¿Š#G ¡¡!rŸâ„p˜:{¡8!`ïâ§©Õ·dì]`ïâ€Þƒú¸µ²ÀǸëèèàŸÔ4d~ÈBæ‡,¤ü“ÊIûòË/‘žžÈÌÌKíÞ:¢¸NsE^^\¦LÁ‰“§¸ÒtuõpáâE¼}—ˆ 6bŠ‹xvÅ“|Æj:úÔúO†}¨§!„B!„ˆÐb}TTTñË/¿â§5k   ú°2olƒA_K|ݽ úZ"ó†?Œ¬§AM³:·7ä™È¹¼Rðð®‘#íÿ ee¥8zôF;Œâ¤98ŒÆ‘ÇQVVŠ;vpíÇf³†ââbøo÷ûX_¾x¯'L@¿~ý±gÏn®´Áƒâ|H¡­£ƒœœ±ò'!òˆzúB!„Bˆp-¦ÑÇÆÆF¢Çµ§ÄÔy·ú…À‰œwgøñ§Ÿ°yÓ&˜w£ؾc'WÚÓgOaÕ·/ ĵ߃‡à6{zöèŽN:q¥ {’×Î]»1×}† „®]ºr¥íع ÛwlG[c¸Íž…‰•§°8 á&9SOB!„BN X,y™¥£áB‚N œÃ§FR¨'ZWÿZ·b( •‘Þ‡z"7Kž”Qýøv ¹©¨¬œŸ¶¶6~çÿ˜óÖ­[ãÔ©OI?žóÚÑÑÿ¤~26cÆLÎëš§jñ3fÌŒ3†ó~î¼yœ×VVVˆŠºÁw¿ºyÖ~/,NB€Z£¸X¼ëd€zúB!„B5íËFŸv¶Kq7 zâdm/Î&pÖ›X¼ø{,^ü½¬Ã „£öpP†‘Ý/êéC!„B!Â}lô‘åÌMϨÿtõŸ.ë0i–X¬Oó¿3ŒÉ®õô!„B!„áZÌÓ»!MC>žÝEOï"„B!„Q¤2¼«´¤L•àoüKKŠëoSîGÈ第¬L¼ k=½ U‹8¨§!„B!„G=}!Íõô!„B!„á>öô‘õ@ BH³Q%s€QOB!„Bá¯æSõô!„H„©µÈõô!¢°X,Î"ÏêŸ´Ž¯¥žŸ¦"«øäåþ–uù¤qÈËý% ÕŸÂQ|‚Ë•Öý½qãF8::òM»|ù2 äþ:4GŽŽŽðõõ•uÍ5úB$Â0UœE–¨§…a0Œ¬›'E«oŒÒ:>y?GŸàråáÜÈC Dúäåþ…êOá(>ÁåJ£ìÂÂBlß¾þþþ|Ó׬YƒÀÀ@¹¿Í‘¿¿?üýýQTT$ëPšjôáÃÓ®}£åmbbÒ¤ûÕWS—Gšš_”²þF=}äÛ7oàêê CCC(++£W¯^8uê”Tò®ýMœºº:ºté‚õë×£´´T*ù·tµÏŸ††ÌÍͱ|ùrdggË:4Üñ©¨¨ÀÌÌ ,@VV–ÔóoÈñÓ7´¤±Pý)¿¨þ¤úSÁÁÁ°¶¶†……ßô¸¸8 2¤‰£OséÍ'ˆ……¬­­,ëPš…×èã0æ+‰¶Þ:1ëûq-Ú¨ò¬‹Þ:¨‘"Orr²LË'DÞPOÙ{ûö-† †~ýúáþýûÈÏÏÇþýûqúôi©•QÓÀ˜••…€€\¹r+V¬Zþ-]íó‚>ÀÉÉIÖaqÔÄWXXˆÛ·oã‹/¾À”)S¤ž¿¼?ù|Qý)ÿä½þ úSö.^¼ˆÉ“' LÏÏχ²²rF$>yø·¡œœœpñâEY‡Ñ,´˜FŸ›7o"44Tâý Ë`dçNã–£Ó¸åÐüÏ4hàY§P(æã¬ i±ªgò©ýŸ,g÷¡ž>²·víZ,^¼ .„‰‰ TTTпœ={PYY‰ 6 C‡ÐÖÖÆôéÓQPPÀÙŸÅbáìÙ³°°°€šš¬¬¬ðèÑ#¾e©©©ÁÚÚœE………˜;w. ```€yóæIÔÍ·oß¾¸rå ç}II ôôô‘‘!V|¢Êg±Xpvv†ŽŽ¼½½1jÔ(hkkcß¾}œtQß²ÂÜܪªª°µµEbb¢ØÇW›ªª*ºuëDGG‹U¾¨ã/++Ã’%K```}}}ìܹSè±¼ÿ[¶lAÏž=yÒ”””`bb‚U«VáöíÛbÅ'IùüŽ~~k—Í/Qñ‰sˆºÿrý{öì‰-[¶4èK#‹???˜ššBCCƒkCSß?ÒæÍš oÖd„ÌØ‹Íºßa›±;^Ýå¤W–W"rå1l3vÇVýÙwåEÕ½dü Ý¿a­¢âçþuÿ7äúoß¾ èÓ§† †ƒ"77WìýkDFFâÚµkHLLDDDg}SÜ?ÂÔþÐXw‘DÇ‘½0åâ*äÿ“ƒ£œõ·7…àÏ­0l3Fí˜ûû"åSý÷–ao3d¾äý0˜ùü= {›‰U.ÕŸTRýÙüëÏ´´4ñ¬çwüu ‹o÷îÝøù矱}ûv¤¦¦"""‚«EÞ999q}>=sæ O/1q® ß?5ŒŒŒšš*ýh‰Öý¹ûìóìÉC&))‰kyõê#ÌóDZLØù&ïß\¦¤¸ˆïrîÌ)i–úì÷çí[L sæÛ).LÖ‡L±ö‰ôèÆ¤Äe²2Y™——÷1¿-ù†g]¤G7y¬Z¹‚yû)ÈÏcÿvˆùéÇ8i‹.`6oòers²™E 0zº:œ´Ú¯ù½”6 ?&ølóonsäðoŒyçNœ´6†Ìÿöïc ò™³Ag«¾}æ¹äûÅ̯¿ìe23Ò™ùóæòÄ6×}“õ¹Æ,[êQ¯ëHKóYòþÍe·0ÏÇ2ÏÇ2±÷b˜M>^ŒÏOžLÜ‹gÌÝ?o0wÿ¼Áܹu³Ô¬‹{ñŒÙ¸Î‹ñ÷ÝÀÄÞ‹až?ŽZw¼zõŠIHHà©sêÖ?¡¡¡BëŸõçV‰ý¯4”””H%Ÿ–BQQ‘)..æZ‡Ý¿†a,,,˜„„NZzz:cjjʵíû÷ï9ï uuu®ôEEELLL 3pà@fÁ‚ Ã0Œ™™ÏÙ&..Žiß¾=Oœµó©-//ÑÖÖfÒÓÓ†a˜ñãÇ3bÇ'ª|LII SVVÆõšÍf‹_]\å‹Ú£¤¤Ähjj2ššš fÊ”)Laa¡Øû ;þŽ;rýϕׄ CCCfæÌ™Ì¥K—˜òòržüë.&&&\÷Œ°øD•/îñ×ôüŠJçþv~¥_yy9séÒ%fÆŒŒ¡¡!3a¡Û×ÍûíÛ·"·´¾!÷Oc[ 'f-œ˜ò’2¦ª²Šó¾ÆÎN‹˜µpbŠs ™Ò‚f-œ˜ífó†a˜ÈUǘ S™ªª*f›±;³ÍØ©ª¬bÖ«Na"W«|ª?©þ¤ú³ùןjjjω8ù НC‡Ì_ý%Ö¾ Õõî“'O8õUUUÓ¶m[æéÓ§·çw}ÄùýSPPÀ¨©©5<` Õ|VúÅ+s:à7æÜ‰ß™“Ç™ó§™ gN0¡A'™°³§˜ðàÓœå™Ì¡_vsö-))‘x$44”ïg«g0wŸßbÖýi1=}€ê®¦ÿûßÿpùòeìß¿Ÿ³þR¨à±~UHOÊ@Fê¿ÈHËCnj^¿KãYWQ!¸÷ÐåË—Ñ©S'())aäÈ‘¸~‰“víÚ58;;CUU‹-’Êq^¿~£G†ŠŠ &MœÄ5©Ú€pýúuܹs¶¶¶œnžü\½z'N„¦¦&<–,áI_¶t)ÔÕÕ1`ÀDFFJ%vB¤…zúÈžŽŽÒÒÒ¸Ö1µ¾ÍJJJB§N8ß¾ðt•®ÝÃP]]gxA;ºººpuuň#àççHMM…©©)gÛvíÚIô¦¦&&L˜€£G"''·nݸqãÄŽOœòUTTÀf³¹^———‹ßÇagg°X,´jÕJâ§T”——#//yyyxöìbbb$êQ!ìøSRRЮ];ÎûÚçøt/ë}Á|ü´¼¼‰‰‰øú믱HÌß•¢Ê„¿4ί0âÜÂί4ã«} jÿŒŠÃÌ̬^e »šŠ’ ,Þû3/¹zBÜMZ3°±•kõº÷Õë {›¡¬°I·âP”•¢¬|$ÞxŠ’r±{úPýIõ'ÕŸ‚5—úÓÐÐ)))ç)*¾¤¤$žáPÍI= ¦¦†˜˜ÄÄÄ@CCÝ»w礋{}DýþIII¡¡¡´Ão‘ZT£Ïƒ0gÎØÛÛÃÝݳžßäÎ*ªjÈ{r Ýú÷€‰©ºØÏEô¥(\8÷à̱0DGÜ@ô¥(¼|ô iÅŸê•‘‘333˜˜˜ W¯^ø'õNZvv6ôtõ†mÚHå8srr°sçN¸¹¹aèÿ åJÛ½{7òòò0mÚ4ôêÕ Ož<˜OVV444ÆÖ¦MuwEeee©= €4c¿KâÞ%»)}hN9`cc#ô© fffÈÎÎæêÚ]YY)Q5ûáÕ«Wðññªª*€ê?¶’’’8Û&%%ñý實¦†’’¾ùÏ™3Ä™3gàèèuuu±c·üúšI¯_]ÒÞ%HkcÀêœÃðfNÛ9 ¯Šêß%5 ;ý“þæ0é×±‡þàJ…êOª?©þ¬¹ÔŸVVVøóÏ?ÅŽKÜøÚ¶m‹/^Hœ¯<™4i‚‚‚Ä3”U’ûG˜?ÿü“3¤‘×b}"##áääggg8p€Ó˜!LqB8L½Pœ°wq€ÓTGÀwK¦ÁÞÅö.è=¨/Œ[+Ã7òß|tttø.ÉÉÉHNNæªDõôôž‘ÈÌÌ‹$@œ5kòóóáì쌀€®4]]]œ={qqqðññÁôéÓ棯¯ÏŸšžžÎSNuL¥¥¥000;>Ò²ÉvúæO¨§ì­Y³›7oÆÞ½{‘œœŒÒÒRÜ»w“>gÎÌš5 oÞ¼Aii)¢££1vìX©•?qâD¬\¹iiiHKKÊ+0qâDžízõê…#GŽðýÀdmm 555xyy _£!å×WQQôõõ¡®®ŽÄÄDóu;¾ºlll §§‡Ççêê $''###žžž<ÛhiiÁÍÍ QQQxðà:tèží*++‘šš ???¾•Ö·üºj¿¸çרØaaaànèýÑÐëïáá:àÁƒˆŠŠ‚››´´´$:†ÆTŸëW[íÆº‹4ôšn¸¹!¥ùÅÈ|‘ŒsÓötÍÀVWÁ‹ »0³é3K¼8{luèšóÎïÁÕŸTRý)Xs©?¿úê+œ9sF¢c'¾%K–`Ö¬YˆŽŽFQQâãã1oÞ<ž|{¢â†ä_3¯OPPÏ|>â^QNŸ>¯¾üänšÈù“Ó裢¢‚]»vÁÓÓ ÂKEU ™7¶Á ¯%¾îÞ}-‘yÃFÖÓ ¦Ù ÛòLä\^)¸UĈˆ²²2;vŒ«{«½½=PVV†={öpíÇf³ââbìÚµKìc}ùò%ÆŽ kkkÎS jØÚÚââÅ‹PTT„¶¶¶ÐIíí툂ü|ìÞÍûŠ;w¢¨¨7oÞ„ƒƒƒØñ‘NNZ}¨§ìõèч¥¥%ôôô°páB/^Œ¡C‡b̘1ÐÒÒÂÂ… 1cÆ ©•ïãã===ôìÙ={ö„¾¾>¼½½y¶Û½{7víÚ6›Í÷—¿››òòò0bĈF)_QO÷8rä<==¡©©‰áÇó ¨!êøêZ¶lüüüÄzºˆ0žžž°°°@Ÿ>}н{wØÚÚBIIIàöm۶ŪU«¸z Ö”[óô•wïÞáäÉ“<1ñ‹OÒò뿸çwË–-˜?>”••ù>}FP| ½?zýŸ>ŠŠŠë  ºþyýú5ù¦ÿ²Z¢†añˆ«´´*** ·ȗ'NàäÉ“8þ¼¬CiÖRRR0xð`®Þ®ŸSù¤aèú5OTJ‡¬ïY—ßœùúúâöíÛ kÒr÷ìÙƒ+V ::½{7üoܦο¡F!C†ì¥Ö˜ñ¿xòpãÚUèéé~l4T¨nÔ¹YÕã‘Ó“2ªßÎb!75Âz%jiiáСC|Ó455qìØ1ÎûÚ]ÐFÅU¹ºººr^׬¯6®ž7nnnœ×}úôÁ•+WøîW7OmmmÎãô²³³ñÅ_ðl+é77„4I{úH£Ñ‡´<¥¥¥Ø¿?fΜ)ëPš¥©S§bÍš5000€··7ÆÿY•O†®_óFõgÃÈúþ—uù-…¤CS¥åСCØ»wo£5È4vþ .4]Þãoj-®ÑG,yo eÙ¹ÉyðÚz‡:[CË´ î>Å«Ë÷QXQ…'Á1\»tî¦-“PËËËqõêUÎÓ ¤©wïÞØ¾}; €}ûöÁÚÚZêe–G^ÆÆÒœ>DTUUaccY‡Ò,ÙÛÛÃÖÖeee3f Ö­[÷Y•O†®_óFõgÃÈúþ—uù¤abcc›uþ­¹Ç/mJ ášNJâ+´: Šú­á¶põM ÀVFJâ+|óÛsxÚµ8isS;pà¶nÝŠ_ýUêyoÚ´ ?ýøÒÒÓ`ee…;vH½ ÒòÈzçÔÓ‡Hƒ´&}ý\¹ººrõRýÜÊ' Cׯy£ú³ad}ÿ˺|BHãc}léù,{ú´³]Š»þm/Î&pg¥Ø IDATÖ›˜?>æÏŸß(y5Š3ß!â’—?ò¨§!„B!„÷Y6úèöž ÝÞ“e!ÍKN}¨§!„B!„÷Y6úB€æô!„B!„fác£Oþ¹WQUúèeUµzçÛ”ûò9c)(Ê:‰POB!„BáÅÔú?õô!„H„žÞE!„B!̓‚¬ „4/ ÃpY’´§!„B!„|n¨Ñ‡Ò,QOB!„BNø8\C>ÈC‘s,‹³Èõô!„B!„>¶ñPO>–1l´¼¿ÔÓmÒýê«©Ë“U™D ,8KÍ:Y ž>„B!„"\‹›Èyü¤Émµ¾J*¸Öuh£Š›?öäZW¥ª›5_}e~È’YÙ„È#zz!„B!„×b}¢¢¢÷ï¿;nœDû)–ÁhÔ2¨«W?®:=)E`d7’k]þý#Ò™ÒÔÓ‡B!„B„û8¼«ùOèSZZ‚ùóçáçõëQUU%ö~UU ÔÕ¡×Ūªl¨i¶žuUU‚ÏQ~~>fÎ˜ŽŽÚcú4WpÒ²³²0áëñèÐÞ ÇãÚ¯îp&aÛj§=xð£F¡i[t·ì†S§NqÒÂÂÂ`ÔÆm `có¸{7Z`ž9ÙÙ?nºuí‚ß~û§ügÏžbð ˜ì4 ¹¹¹\±œ}‚ٳݠ¡¡GGG”——s¶‹Œ¼§É“¡¡¡±ãÆ!"â'­1Î ù|POB!„B®ÅÌé÷îÝÃŒÓáàà€ rÖ šÜ9ó¯#èÖ¿ÔLõð¥õ öpÁëwi€3ÇÂйý§§x¦céCøßJãÉ'##m 8ï•••9¯³²² §§0lÓ¦aøQNv6>Œ§OŸàéÓ§\iûöïÇÌ31Åå())áÂÅPôêÕ‹o>>|@«V­ÆÖÆÈˆs<êL$­«[=LI©úÒÖÖæ[Fzz:455jjjÈÌÌä¤5ƹ!a>uí‘å/êéC!„B!Â)#ã¹9¤áòå|=~¾ýv*Ž €†††È}ŠÂaêì…â„p€½‹œ¦:¾[2 ö.°wq@ïA}aÜZ™oƒèèèàŸÔ4d~ÈBæ‡,¤ü“ÊIûòË/‘žž\ uÕî­#Šë4WäååÁeÊœ8yŠ+MWW.^ÄÛw‰Ø°a#¦¸þ°k``€ÜÜàÄÈSv6 ´´†µµñ?ìëêê"??PTT---Nš¸ç†È†a8‹,QOŸæCÖó?É+y™K”úÆ×TÇ×RÏŸ4Êm÷‘otÿð×\~¾¨þn˜Ï¡þÞ¸q#%ÞÏÑѾ¾¾‘®ê{¨Å ïRQQÅ/¿üŠŸÖ¬‚‚èÃʼ± }-ñu÷0èk‰Ìþ0²ž5ÍVèÜÞg"çòJÁûFŽ´G|ü+”••âèÑ#í0Š“æà0GFYY)vîØÁµ›ÍFXXŠ‹‹á¿Ý_ìc}ù⾞0ýúõÇž=»¹Òˆó!!PTT„¶Žrrræã0z4~øùùùر};Oºÿ¶m(**BTTLj_m#FØáÌéÓ(**ÂÅ 0|øðOå 97Dþ0BY ž>͇¬å•<4žŠ£¾16ÕñÉû9”U|Íåþ"òî!þšËÏÕß ÓÒëïÂÂBlß¾þþâ­áïï5BdDÚZL£Dk/N‰©óþnõ 9 þÁûñ§Ÿ°yÓ&˜w£ؾc'WÚÓgOaÕ·/ ĵ_ͤÇ={tG§N¸Ò„=Ékç®Ý˜ë>CB×.]¹ÒvìÜ…í;¶£­‰1Üfσ‡æ¹bù \¿~ôÇ Áƒ8Cµj 1C©“'°båJñóã?âë k œ?ŸuŸÒ„œBD¡ž>²×T߀5¤œ7oÞÀÕÕ†††PVVF¯^½¸žxØÐ¸juuutéÒëׯGii©TòÿÜÕ>¿***033 %AÏXqó×ÐЀ¹¹9–/_Îéå*I>„ý|T;tèX,:$zã&Dõ7ÝŸ‰êïæ!88ÖÖÖ°°°x_ X[[#88¸"#ÒÖb}j›´¹FR¨'ZWÿZ·b( •‘Þ‡z"75x&r®¬œŸ¶¶6~?†Ä¿“pí?¸~pZ·nS§NãÉÓg7~<2kÍãèèˆRÓð:á f̘ɕ–ùAp¥8fÌDßÁ“§Ï0wÞ<®m­¬¬u©iéø'5«»^Ý<µutpþÂ<}ö6ÿgƒ/¾ÐâÚväH{öïßÓ§EÿžWÍÏBVVpåʬXÁ;1>©Ÿšó[XXˆÛ·oã‹/¾À”)S¤žVVBBBðáÃ899I-ÿÏý|çÏŸÇèÑ£qáÂY‡Ò¬PýÝüQý-ÿ.^¼ˆÉ“ùÏ}+'''\¼xQŠ‘ÆRÝè#ß=ë¤/ï ´L; 0£^[o¢0£Z¦Àä½Á«Ë‡Q˜'Á¿ æèÄÙŒW—£c7-Ñù6‚²²2„††‚ÍfK=ï®],píêU”””`Ïž=0 ¿ÔË -¼4úPOù'jLzll, §§XYYáìÙ³<û‹“¼ÿ[¶lAÏž=k×®ÅâÅ‹±páB˜˜˜@EEýû÷ç”QYY‰ 6 C‡ÐÖÖÆôéÓQPPÀUþÙ³gaaa555XYYáÑ£G|ËVSSƒµµ59J 1wî\ÀÀÀóæÍ“¨tß¾}qåÊÎû’’èéé!##C¬øD•Ïb±àìì x{{cÔ¨QÐÖÖÆ¾}ûÄ>ç077‡ªª*lmm‘˜˜(öñÕU÷úÕ¦¤¤¬Zµ ·oß+¾²²2,Y²Ð××ÇÎ;n«ªªŠnݺÁßßÑÑÑbŸ¨ûST|â\Q÷_CÎÏž=±eË$''×+]ü~>›7k2¼Y“2c/6ë~‡mÆîxt—“^Y^‰È•Ç°ÍØ[õg#tÞ”U÷òð3tCðÔÝ-®§8R_ÅÖƒ¢¾ ÜN€¢¾ ØzHI|…éoñ6µÓßr-z “X÷íûîsܸ†iI‹ß6¬Z½ :vÄ£G±Ø°‘&ã"Íõô‘¢'L˜WWW$&&âßÿÅŽ;ÀwA¹¹¹8xð † †¾}û"!!Û?ÎQ‰I“& ,ÇŽ¸~ý:þøã¼}ûJJJX³f ×6'OžÄ•+WðáÃŒ; ,zÌUUŸæ[»v-RSSñøñc___¼~ý>ÄÓ§O%pÛ²²2¼}û^^^°µµëøDÝŸ¢âçúˆºÿrþ·oߎ„„ôéÓÆ ÃÁƒ‘››+vz}Ôþù¥ö‡®º‹$:Žì…)W!ÿŸDx嬿½)n½€aëœ1jÇ Ü߉(Ÿ €ao3d¾äý°”ùü= {›‰]vdd$þûßÿ¢}ûö°²²Bdd$ßm®]»†ÄÄDDDDH”.ìú‹SCõ7ÕߢPýÝüëï´´4}|Zs]âüü!55•ÏÞDî¬;úóüóìñC&))‰kyõê#ÌóDZLØù¦´´Tà6çΜš‡,öK‰>ÂÜÙГgI‰>R¯2 i JKK™°ó!ÌóDZÌóDZLì½f“ãó“'÷âsçVsçVs+êg©Y÷â³qãﻉ½Ã<+´¬W¯^1 -€m×¾}{æÇdnܸÁüóÏ?Lee¥DûO˜0144dfΜÉ\ºt‰)//çJWTTdŠ‹‹yòªÉÏ‚IHHथ§§3¦¦¦\Û¾ÿžó¾°°QWWçWQQà 8Y°`Ã0 cffÆÄÇÇs¶‰‹‹cÚ·o/öñååå1ÚÚÚLzz:Ã0 3~üx&00PìøD•€)))aÊÊʸ^³Ùl±â««  €«|Qû‹º~5תöbbbÂuÍ„åß±cG®¿câãã¹¶À())1šššŒ¦¦&€™2e SXX(•ã•.Îõv}¥_yy9séÒ%fÆŒŒ¡¡!3a‰ÒõóÑØÖ‰Y '¦¼¤Œ©ª¬â¼¯±³Ó"f-œ˜âÜB¦´ „Y 'f»Ù|†a&rÕ1fƒÆT¦ªªŠÙfìÎl3vgª*«˜õªS˜ÈUÇÄŽaæÌ™Ì®]»ªËÛ¹“ùî»ï¸Ò0oß¾¸¿¨ôÚê^qêqPý]êonT·Œú[MMï97þ‚‚FMMMhŒ-QÍg¥_ü·2§~cÎø 9yœ9*¹pæt’ ;{Š >ÍY.œ9Áúe7gß’’‰ABCCù~¶zúøóì³îèÌgÙÓǨÿt øá1ÏbÔº¬C#Dî1r2¼‹zú4áááHKKÃ÷ߎ;ÂÐÐP¢¡5÷  oÿutt––ÆwHJJB§N8ûðt…611á¼VWWç;<ƒÅbAWW®®®1büüü©©©055ålÛ®];‰¾ÓÔÔÄ„ pôèQäääàÖ­[WçÂâ§|Îðáš×åååbÅ÷ðáCØÙÙAGG, ­Zµ’høƒ¨ëW³ Ã0(//Gbb"¾þúk,Z´H¬üSRRЮ];ÎûÚç¢Fyy9òòò——‡gÏž!&&†órCOq®°ë+Íøj_~u»¨tQùòûùh*J*l°xﯼäêy7iÍÀÆV®ÕëÞW¯3ìm†²ÂR$ÝŠCQV>вò‘xã*JÊÅîéSUU…°°0Œ;0vìX„††òôv23žŸ tQ×_œú£!¨þŽêoª¿›Cýmhhˆ””¾ùŠúùª¯“¡¡a½â&MKøü¦ô!„44§Oó×¥K5EÐñ‰º~µ)))¡]»vX¿~=nÞ¼)V|ÆÆÆx÷îçýßÿ-t{KKK>a÷§0 ½> =ÿèС}_}õ•ÀtšÈY~|–û!õǰXœE–¨§|öM¼ ×5<<<°yófèééÁÔÔçÎãzúK-[¶`þüùPVVúÇCÛ¶m±jÕ*>>ÐÓÓCÏž=ѳgOèëëÃÛÛ›g»Ý»wc×®]`³Ù|ÏÍÍ yyy1bD£”/ˆ¨ëwäÈxzzBSSÇ8tDÔñÕ¨{ýj—[óôwïÞáäÉ“bÅçéé ôéÓÝ»w‡­­-”””D÷²eËàçç'öñ º?EÅ×ÐëÓÐóÿäɬZµ m۶廟¨ôænðêñæ3qçþÂÖ/g#Èe':;ö°X0èaŠò¢R˜ÙXÂ̦*JÊaÐÔïP1~Ο?ÏÓ1vìXœ?^*ñ‹{ý…ÕT Fõw5ª¿[vý=qâDüõ×_ˆ‹‹;ö/_¾Ä½{÷0a¾é999€Ž;Jœ7‘>Öº£?0#­ЪB­µõ¸‹‹‹ann.pçO!1ño ±±²²2ßm.…^„ÃÁ-€‚4õ~„|îÊÊÊp+* ffí8ï/‡‡¡´¼ÎS¾EvÖ@E­o”:ºz: U¶ †eeetëÙ[`YñññPTTXoÕõÏëׯáèèÈ7ýçÕ5ü‹G\¥¥¥PQQip>„Hâĉ8yò¤Ô>,~®RRR0xð`®!„´tTÈé ú»ñøúúâöíÛ “h¿Ñ£GcÈ!{aíÙ³+V¬@tt4z÷nøßàòäÅ“êÇ×߸vzzºåªXPà3¹¢²™™ÐÐ`@G‹®—+è3HXX:wîÌóÙêßœL)áòýK{úФ>„‘ªÀÀªµ|z(CÓ£ž>äsPZZŠýû÷ ü&7uêT¼zõ ¹¹¹ðööÆøñãe!M†êÙ¢óß0T7 OOO‰|€êÉÜ… »;tèöîÝÛâ|šÓhx!D"ôô.BšŽªª*X,\\\dJ³doo[[[tîÜX·n¬C"¤ÉPý![tþ†êïæ-66ß}÷¬Ã Q£žví-ïÚ¿kŠý꫾åEDD }ûöpww—ZžDÞ°j-²C=}Èç€a\¿~]èPH"˜««+RRR™™‰Ã‡CSSSÖ!Òd¨þ-:ÿ Cõ7!Ò#zF¬fFÒù|¢·‚BI׺mT³¾׺*U% XQÿGÚ5Trr²Ìʖļyóð믿bøðá²…49™„ŸzúB!„BˆpJZÄ£ÔnÞ¼‰¼¼<Œ3F¢ý Ë`4jÔÕ«'¤MOÊ€FÑÙäZ—ÿˆ´Cn‘ÊËË1jÔ(Y‡AÃÇÑ\,†w,HÚÓG9B!„Bˆ¼«=™t‹ÞUZZŠÅ‹Ã××UUUbïWUÅ@]]z]Œ ªÊ†šf+àYWU%øÓmA~>ÜÜÜеkWÌž=œ´ììl8;;£k×®8yâ×~u‡; þT;-66ãÆƒ¹¹9úô郠  NZÍð*333Œ9111óÌÉÉ““þóŸÿàèÑ£<å?þ¶¶¶øöÛoñï¿ÿŠŒ»î¿Âކ¢ž>„B!„"\‹iô±³³Ã™3gpêÔ)¸¹¹¡°°P¬ý*>Žì*H̬~Q«×Síuh«Ÿ–-[†§OŸbøðáØ±c'Í××Dll,<|(Ñ1 ²téR¸»»ãéÓ§X¹r%×ÄfóæÍƒÞ¼yƒï¿ÿË–-˜ÏæÍ›1zôhܼy?æI?pàBCC1{öllÙ²Ed\5CÐjþmŒc'²ÇâóBY 9}!„B!D¸Óè}ûöÅÿþ÷?\¾|û÷ï笿zQà>UHOÊ@Fê¿ÈHËCnj^¿KãYWQ!¸÷ÐåË—Ñ©S'())aäÈ‘¸~‰“víÚ58;;CUU‹-’Êq^¿~£G†ŠŠ &Mœ„ììlNÚ€pýúuܹs¶¶¶¸}û¶À|®^½Š‰'BSSK–ð¤/[ºêêê0`"##%޳1ŽÈù˜È™zúB!„BˆpJÀÈrb)zðàæÌ™{{{®§Gñ›ÜYEU ™A·þ= fª‡/­gà°‡ ^¿Kœ9†Îí 9Û¦ãŠ]{øF¾ãÉ+##fffœ÷l6›ó:;;zºzÃ6m|Œ@õ°¬€€<{ö ÏŸ?çJÛ½{7æÌ™ƒiÓ¦Íf#((={öä›OVV444ÆÖ¦@YYYYYÇÙÇNd§¦–`X¼ëdæô!„B!„Aª?­µ˜ž>‘‘‘prr‚³³38Ài̦8!¦Î^(NØ»8Àiª#à»%Ó`ïâ{ôÔÆ­•ù6ø€ŽŽß%"99ÉÉÉx÷îÓvzzzHÏHdff Œ¥voQfÍš…üü|8;;# €+MWWgÏžE\\|||0}útùèëë#77žžÎSNuL¥¥¥0008nq4/ ,g‘%êéC!„B!µ˜FìÚµ žžžPP~X*ªjȼ± }-ñu÷0èk‰Ìþ0²ž5ÍVèÜÞg"çòJÁûFŒø×ñ(++ñcÇ0nÜ8Nš½½=PVV†={öpíÇf³ââbìÚµKìc}ùò%ÆŽ kkkìÛ·+ÍÖÖ/^„¢¢"´µµ9:üØÛÛ#00ùùؽ{7OúÎ;QTT„›7oÂÁÁA⸅;! EsúB!„Bˆp-¦ÑgèС=®½8%¦Îû»Õ/Nä,x ËêÕ«±mÛ6ôèÑÇÇÖÿgïÎãjÊÿ?€¿nÚ“‘R©(QYãG²„I$‘5²ŒÄ QY¦1ö!C*;“ìúÊR!ÆN¶,cK¢)¥4¥h¹÷þþH×=ݽnÝ–÷óû8ß¹ç|Îg;¥ºŸûþ|>k×2Òž}ú oß¾8vì|}}¥jwÙç"ªï¤&£5}!„B!¤&PW±oÞäéläi¡køðKŽ @}ã’é_ËçõÔ7Ò»Èdgj>$§—lßÎb!;5l¶èò6lˆ;w MÓÖÖÆxçƒoÛ€SÁÜÝÝy¯KwÀÆÙÙ™yãééÉ{Ý©S'DGG ÍW¶LÞvïYYYøá‡îíׯŸ@9Ò¶[\ßIÍÅâ*技«t´¦!„B!„ˆð-nEYü]µTÎk4lÛÙïs°xíì´°EÃfæø|3ÏÏßE^1"˜‘@mtÒÔ¢¢"ÄÆÆ2‡–—Ž;"$$Ý»wǶmÛ`kk+÷:m3V IDATHíÃâõáBÌhh%£HB!„B¯Nú¤$=GÓÞ}PO¿D2þ©ˆÕe°R‹U®öUUÿÊÛ¾ª¢¨öÕ”ï/B!„ÔméC‘RÉ›.—-pM(Ò‡HRúF¼º¬C%Jy ªªÕ}@CQí«)ß_„B©Û¾í½ÌEõùüžRq9ßE’5Ò‡TŽ×¯_ÃÝ݆††PUUE‡päȹ”Íb±x‡¦¦&Zµj…+V   @.å×uüÏWMM fff˜1c233å^¾––,--1wî\deeÉ\N]V×ûO!„rúö'„’b[A©y¸¨Åé£x‰‰‰èÓ§ºv튻wï"77Û·oÇÑ£GåV—Ë—ËEff&öíÛ‡èèhÌ›7Onå×u¥Ï7//W¯^Å?ü€qãÆÉ½üÌÌLœ!„B}!5Eú(Þ’%Kàãベ3gÂÄÄjjjèÖ­Nœ8`³ÙX¹r%ÌÍÍ¡££|þü™—ŸÅbáĉ°²²‚††lllðàÁ¡uihhÀÖÖä *åååaúôé000€¼¼¼ŸŸ/uû;wîŒèèhÞùׯ_¡§§‡ôôt©Ú'©~‹…Ñ£G£Q£FXºt) lÛ¶—^zˆrðàAXZZB]]HJJ’ºe½{÷kÖ¬µµµ@š²²2LLL°`Á\½zUªöbΜ9000€¾¾>Ö¯_/ò^uuu´iÓÁÁÁ¸qã†Týã¯[X[$µOš¯¤ï¿Š<kkk¬Y³ïß¿—:?Iý¯¨Š>Iÿ¾+jüøñ˜>}:ï|Ú´ipww¯Òò9[[[4hÐfffصk—@9òþºB!òFƒ>Bøõ2¬´²ëéVi>y”Yú¨*)¢N"—Ë;‰"}/&&#GŽ™ŠK—.áâÅ‹HLL„²²2-ZĸçðáÃˆŽŽÆÇ1dÈ̘1ClÎ÷y…K–,Ajj*>|ˆàÝ»wX¶l™Ôí÷ôôDXXï<22]»v…¾¾¾T퓦þiÓ¦áÔ©SX¶læÎ‹3gÎà?þð= FœˆˆDFF"++ ŽŽŽŒ7©ÒÈÎÎÆŽ;ЧOtîܯ^½BHHˆÀ}ÅÅÅHNNÆâÅ‹acc#UûñòåKÜ»w ˆ‹‹yoaa!±xñb888HÕ?þúK_ó·GRû¤ùúHúþ«Èó Á«W¯Ð©S'ôéÓ;vì@vv¶Ôù%õ¿¢*ú|¤ù÷][¶lALL þ÷¿ÿ!""±±±Ø²eK••¿qãFüþûï Ajj*Î;‡ëׯ˭~B!¤ª°–ïý•ëÔÙZlM4ÐiÌHüòå ,--Ef~úè’’Þ¢ßg‘»w<~ÃFºÉܰòæ“UÜŠNPúZ̸öèe¬-0®qÔ•a¿è^…ëk¬§‹ŒòY/¡ªXYYâùóµ¾Îº®°°±çÎÂÌÌ”w~þL ŠŠ0zÜOÈÌ(ˆãp¾¿éPR*ùtS·±>"Ž…ºŠúôëUUU±»e½xñõêÕ»ëß—/_ðòåK 4HhúÓGdøùmØj™ŸIYPSS«p9µ…²²2>þ uuuÞµÒO¼¹\.Zµj…¨¨(´hÑ@É`n—.]ðöí[Þ½ïÞ½ƒ‰‰ ??7F^^/½ôMî—/____üßÿý6mÚ„æÍ›#::€çÏŸÃÙÙ‰‰‰ŒvŠÚÝ)77¦¦¦øçŸ ¯¯áÇÃÍÍ cÇŽ•ª}’êg±Xøúõ+””” ªªÊ{­¥¥…ÂÂB‰í++//úúú¼ú%åwuuÅõë×áìì 777ôë×ÊÊÊŒ|e™˜˜ ..Ž÷5W~Ë–-qæÌÞß /_¾„¥¥%cceeehh”쨙››‹qãÆ!,, šššti¾>â¾¾òj_qq1bccqäÈœ;w=zôàEÃI£²v'«èó‘ôï[nÞ¼‰¡C‡N:…®]»Ê­lIå·hчF—.]äZ'!„ší飒¨×Ëb¡§§ °XJ%‘ŸJ,( ‰Î-f³‘‘ñÝìzZXµ–¹^QïA¢¢¢`aa!ðÞ*'û#òëåáÜݳµg÷®¸¸8äü÷†|ûå--¥¼B ð‡¦fÉvÕ’Ó¡•#ÇþŒk¹w÷È»É5F–œõ¬îuiñ¿ùP\H;Eú(^£F––333Þ5.—Ëû%—œœŒ–-[2ò()1LKßP€¦¦¦Àô¬Ò²444дiSŒ3€ÔÔT4kÖŒw¯©©)RSS¥n¿¶¶6FŒ½{÷bÊ”)øûï¿.uû¤©Ÿÿté뢢"©ÚwïÞ=,X°ñññøôé“Ôý*Å?ø"júIé=ÅÅÅHIIÁºuë0kÖ,œ9sFbù)))055åó?‹Rü}}òä †Џ¸8 8°Âý“D𝏝¯<ÛÇÿ5¨.»¡UôùHóﻢºuësss°X,¹øH*?99mÛ¶•{„BHU«5Ó» ¾ÂÛÛ ¿¯XÁÿ—„ÃáBS³ôZA]]Úõ@àtCY¹¹¹˜4Ñ-Ì›Ãc‚;cN{Vf&F óæf?p€‘¯ìô*qÓ­øÓâãã1ÐyL›5E»¶m;åDEEÁ¨‰!šÀÞþGܼyCXqe6ÖÓž}{Ñ¥‹ Œš"**Šqÿ½âúû)+ ÆE›Ö­°k×.:¶mÝŠ>ööbû!k¤jUÆ4ƒò 5}ÏÞÞ"ÓÍÌÌ••Åøža³Ù2ÕQš/??ÏŸ?DzeËx‘E†††HNNæÝ›œœ CCÁé¹øúõ«Ðò§NŠ;vàØ±c4hÐQ¤­¿¼ÜÜÜ0fÌ$&&‚ËåŠÜõJTÿ"""ðìÙ3tëÖ 022´iÓpáÂ{•••ajjŠ+VàÊ•+RµÏØØoÞ¼áKŠðhÛ¶-vìØ___p8©ûWÞH—Š~}*úü/\¸€iÓ¦ÁÈÈèÞ½;ž={&öߌ0•éSÑç#ß’„‡‡#779998xð \Ë–T~Ó¦MñôéS¹×I!„TµZ3èãä4ÿ;ùÂÃ`¢Ç‘áÙe›Ùõ9)£äß§¡ü׊‹!ÒêÕ˜?ž¿x GÇþZ»–—¶|ÅrôìÙ OŸýƒ;wïÈÔ'Q|fÍ„·÷ ¼xù ¿þº‹ŸCï9e2V®Z…÷)ÿÂßÏ>³|¤.÷ÙÓ§¸|ù Âvì„ç”ÉÀ›ŠÆ?%M\W®\ ܼuî N‡SSWÃñÇÅöCÖ:IÝD‘>Š·hÑ"üñÇؼy3Þ¿‚‚ܹóýçÜÔ©S1yòd¼~ý¸qㆠ"·ú]]]1þ|¤¥¥!-- óæÍƒ«««À}:tÀž={„¾!µµµ…††/^,v}¢ŠÔ_^ùùùÐ×ׇ¦¦&’’’D®w$® 6„§§'âââsssøúú ÜÇf³‘ššŠ   ¡ = ãîî___¼ÿééé¼,qìíí¡§§‡“'OJÝ?cccDEEÉ< PѯOEŸ¿¯¯/ÌÍ͸¸8xzz¢aÆ2õÜÿò.$\Ñç#í¿ïò¶ïÇðóóÃîÝ»±k×.øùù ]ﯲʟ3g&OžŒ7n ??/^¼€———Üê'„BªÊ·AŸêj\Q]ºtÁž={qöìYlÞ¼‰wýäqÑÛsð!9é©ÿ!=-Ù©éxù&MàZq±è衳gÎÀÂÒÊÊÊpèŒÈ¨H^ZlL ÆŽuuuøùúÉ¥Ÿ×®ß€ËàÁPSSÃ(77ÆT(;;;\ˆ½€«W¯¢Ÿ£#nß‘~ ÉîŠ×¾}{œ;wgΜAÛ¶m¡§§‡™3gò>1÷ññAïÞ½áâ₆ bæÌ™˜8q¢Üê_¶lôôô`mm kkkèëëcéÒ¥÷mܸ6lø6çZðÍ™§§'rrrЯ_¿J©_a»3ñÛ³g ­­¾}ûòÖ)KRÿJ5mÚ ,À£GÚPº;Ó›7opøða©Ú+++têÔ íÚµƒƒƒcÍ Qüýý$uÿÖ¬Yooo¨ªª ݽKTû*úõ©èóôè,X€¦M›J]§0¢ú€7íŒ &iUôùHóï»"í›1c&Mš„.]ºÀÖÖo•Y¾,X€Y³fÁÀÀýúõã-r.ú !„JÅ¸ß–âø¶óh±µjüBÎwîÜÁ÷ñèÒ¥ ¶nÛ---±÷gÜÞƒ/¯Î@£å@4¶ˆÝ¾cñòM/Ý¢ù÷0ç¼”HLýŠà¿ÓÊ116BAAï\UU)ÿ–Ì‹obh€äwï¡¢¢‚ÂÂB5áE°”]ÔYÜ"ÏüiŸ²²°{÷n$$þ.”••qêt$:tè ±Lqm)›&®¿FM ñî} êÕ«'´¿éy´Šë‡,uù´óÇo 9ÿ´YY¹dÝ+=,äüûÉ_dø×iÑBεӡC‡pøðaüõ×_ŠnJ–’’‚ž={2¦|‘ʵiÓ&Ì›77nÜ@ÇŽÿ'o•Ý>E÷_ÑõB©z5f!çO‘§œówÏÔžé]çÏŸÃðaCñÓOã±gï>‰>ðåÕ4½_^•,Xé4֣Ɨ¼ÁüyÎ8u†ÓXgt´ë ãªB|€’ÅLÿMMCÆÇLd|Ìd F4nÜ>|dddˆl‹, »OpGNNÆŽ‡C‡0Òtuõpêôi$¾IÂÊ•«0n¬ü§µˆë¯²³K>ù*í7?þo~qý¥NRÕ¸PlŒO Šô!òPPP€íÛ·cĈŠnJ4~üx<þÙÙÙXºt)† ¦è&Õ);wîÄæÍ›«í€Ce·OÑýWtý„Bˆ4jÍ šš:¶lÙŠß-’j÷ˆŒËë`й-†·kƒÎm‘q9F¶ ¡]Í r.b‹žÞÕ¿¿^¼xŽÂÂìÝ»ðÒœbÏîÝ(,,ÀúÐPF>DEEáË—/ –º¯Ïž>Åð#еk7lÚ´‘‘ÖÓ®þ:yõêÕƒN£FrÙEEE…1Ï]lÄþ}û‘››‹Ðr÷C–:IÕb ½VZӇȃºº:X,o›v"'''888ÀÂÂÅÅÅX¾|¹¢›T§Ü¿?ÿü³¢›!Re·OÑýWtý„Bˆ4jÍ ½½½LÛµI¹UæüfÉ ‘ 9‹ŽjXøÛoøcõjXZX`ßÞ} ]ÏHKxœ›ÎaggÇÈWº`²uûvÛžŠÛÉký†˜>m*zõ´CëVÌаÐõ‚¦&Æðœ2a;vJU¦8ƒ\\`Ó¹“Tý7w.]º„Ý»Á®§ØõÄõC–:IÝD‘>D¸\..]º$vª!ÍÝÝ)))ÈÈÈÀîÝ»¡­­­è&B!„>’W\¬a¤Y (92õK¦-Ÿ×PßH ï"Y²]ï‡äô’íÛY,d§¦Cܦ!:::Ø·ÿ€Ð´ àÈ‘ï Iå }4hþMý>elâÄI¼×¢Öö¸¸¸ðΧóí&accƒ¸¸ËBó•-“ÿ\\ZXØFš¸þê4j„¿NP2e퇾ïTR¶qý¥NRµ½U{)Šô©9*kËiyQTûø£åªóó!„B!5W­ô‘JÎk4lÛÙïs°xíì´°EÃfæø|3ÏÏßE^1"˜‘@mtÒÔÂÂBDGGCEEE!õ˪u++lÚ´v={bÓ¦MèÞ½›¢›Dä­š¼7•5ÒG 9“ò©îŠj_i½Šž*I!„Bj¯Z3½K)IÏÁRÑC=}xÎzú&PRÑCJÒsxLDbêWxLd=~‹WH[·mÛŠiS=Ó´ª³ uÁXðË´lÑÜÇÊUŠn‘7ß¡@é£xüë;©©©ÁÌÌ 3fÌ@¦ ÓK[¾––,--1wî\deeÉ\N]‹!C†@GGZZZhÓ¦ –/_Žüü|Þ=Õe.B!„R9”€oס?øLüpsß6<=± :ÿ½ÂÓ»pcÿ6˜:ø€È]ºÁÇg6RþM¹muu3hРܽ÷))ˆøßI)ºI¤–¢5}ª.— .—‹¼¼<\½z?üðÆ'÷ò333qòäI|üø£F’[ùµÙ’%K0|øp<|øÙÙÙ8sæ Þ¾}‹1c¾‚–>_B!„R;ÕÉH£nèþëC蛇¢›FHµW]"(Ò§zQVV†‰‰ ,X€«W¯ü½RXXˆ9sæÀÀÀúúúX¿~½È{ÕÕÕѦMãÆ¼ë„¥¥%ÔÕÕáàà€¤¤$^ÝÂÚ"©}yyy˜>}: ```///(™'NÀÊÊ °±±Áƒeˆk_EIªÿÚµk˜4iš5k˜™™!$$±±±rkCEÚ'Íó+½OÑ?o!„Bjª:9èC)../2 $: ô¨zéS½#99‹/† ÉQ$xùò%îÝ»‡„„ÄÅʼn¼·°°‰‰‰X¼x1x×#""‰¬¬,8::búôé¼4þú™ß·‚éÂ,Y²©©©xøð!Œèèh|üøC† ÁŒ3éâÚ'’ê/+22ööörmƒ8’Ú'kû !„Bˆlä²sÁ×/àrDooUðõK¹Ë­Ê|„Ôe………Šn‚L(Ò§z(abb"vð†ßþýûqæÌÖ¬Yƒ“'O2îQQQ†† 77ãÆÃÑ£ßwD<~ü8ïµ~ÿý÷òtC¨'N ::†††€uëÖÁÙÙüñ˜˜æÎËH«ìöIS?¿cÇŽÁ××ÿý·\Û Ž¤öIÓ~š~F!„R~J@OB¤Uº˜¢g[P¤OõP-STT„¤¤$ >³fÍ’*oJJ LMMyçÍš5¸§¨¨999ÈÉÉÁãÇqëÖ-Þ Ò½{÷àèèˆFÅb¡~ýúŒéW•ššÊh“©©)RSS÷”X€¦¦&£þÊnŸ¤úKaîܹð÷÷GTT,--åÚ†Š´OšöB!„Ù•~pFÓ»!2¡5}ˆ0ÊÊÊ055ÅŠ+påÊ©òãÍ›7¼ó·oߊ½¿m۶رc|}}Áápàææ†1cÆ 11\.Wä®^,«\Ñ"†††HNNæ'''ó¢~¤!mû444ðõëW™Û'ׯ_ÃÎÎOŸ>Ž{÷xSï!„BHÝ@ƒ>„‰"}ª6›ÔÔTÁÚÚZª<îîîðõõÅû÷žŽ€€‰yìíí¡§§‡“'O"??úúúÐÔÔDRR’Èõ`Œ6[ô4da\]]1þ|¤¥¥!-- óæÍƒ«««Ôù¥m_‡°gÏ™Û'É`ccDEEAOO¯\å(zWÑõB!„Ôd4èC‘oÝfßE­ãL‘>ÕDéòÒÝ—Þ¼yƒÃ‡3Òʾ.+++têÔ íÚµƒƒƒ”•%/5çïï   ìÙ³ÐÖÖFß¾}1tèP¡÷¯Y³ÞÞÞPUUº{—¨ö-[¶ zzz°¶¶†µµ5ôõõ±téR©Ÿ´íÛ¸q#6lعn¸»»#;;K–,’’#J/;;€ägðéÓ'@‹-äÖ.Y(º~B!„šN\ˆ³® plŽÀ˜7’o,¼ÿ¾ÊòUu™¤ö«.?.dôicÝQÑM®u$M™’”®ªªŠÐÐP„††(Yã'((Hbþ#F`Ĉ€Ç3ÒF-pÿرc1vìX™ÛW¿~}„……!,,Lhº°üü×ú÷ï/UûlllðôéS±m)OýÒLi“tOxx8ÔÕÕ RWfûÊ^«Hý„B!uYé8\vïªNœ]ËtÿµvPúZ̸fÞD·Vte\ã¨+£û¼kn_yÑà ©.ªË 1EúÔãÇÇ¢E‹```€¥K—bذaŠná³sçNlÞ¼;*fÐTÑõB!„ÔtµfÐçÊ•+ÈÉÉ‹‹‹Lù”ò a4Àššõ’Ó¡•#ÇþŒk¹w÷ȻɄ  HŸÚÁÉÉ (,,„‹‹ –/_®è&>÷ï߯ÓõB!„ÔtµfMŸ‚‚øøø 00Gê|ššõ ×Êêê*ÐЮ×8Ñ!ðŸssáéé‰Ö­[cÊ”)øüù3/-++ £GFëÖ­qøÐ!F>þ­j…‹J»ÿ>† KKKtêÔ‰ö~îÜ94oÞfffèß¿?nݺ%Õsظq#V¯^-UŸLLL'''Þyxx8ìììмysœ;wNª:IÍTºEwyvC’'Šô©ÜÝÝ‘’’‚ŒŒ ìÞ½ÚÚÚŠn!„B!µF­ôqttıcÇpäÈxzz"//Oª|Åßfv}NÊ(yÁ7u…ÿZq1DZ$$$ oß¾¼õ) 00=zôÀýû÷ïžL}ÅÏÏÓ¦MCBBæÏŸÏødÜËË Ë–-Ãëׯ1{öløûûK,o÷îÝÈÈÈÀ/¿ü"UŸ@MM äÿóÏ?ˆ‰‰ÁÖ­[áåå%‡^’ê¦tÍf÷û¡Àuœi÷.B!„B‘ Ö ú@çÎñçŸâüùóؾ};ïúÙÈÓ"ósð!9é©ÿ!=-Ù©éxù&MàZq±èè¡óçÏ£eË–PVVFÿþýqöÌY^Ú… 0zôh¨««ÃgÖ,¹ôóÒ¥K8p ÔÔÔ0Òu$²²²xiÝ»wÇ¥K—pýúu888àêÕ«bË:räN:…eË–IÝ'8p tuuyç³gφ¦¦& €¢¢"9ô’T_\(v¸§EúB!„BˆxµfMˆÇÔ©Sáää„iÓ¦ñ®‹ZÜ9À±9Ì›¨#õZ<ïÚË7i€c¢`ÑÜw=/í ¢Eìꕞž333Þ¹ŠŠ ïuVVôtõ†Mš”¯ce|úô ûöíÃãÇñäÉFÚÆ1uêTL˜0***8~ü8¬­­E–uùòedff"%%…1…L\Ÿ0|@OO¯="Dv´¦!„B!„ˆ÷mÐG±ŸØËCLL ¦M›OOO,X°JJ’ƒ˜cÞàÌÌh?ôû¢Í“Óqì@~ž3±sÒ¹xxî{&´œFáæ›PVCÓÓÓÇô066FFF†È¶ðGëH2yòdtêÔ £G†™™ìííyiººº8qâ ± anX¿ú kÖ¬Á† ¤êP}vp"UOÑkù”¢HB!„B† Ö·qžZ3½KMM 6l@@@€T>¥ŠØE›-š \+b‹žÞÕ¯_?¼xù………8pà†ÊKsrr¾}ûPXXˆM›61ò©¨¨àܹsøòå cÀE’gÏžaÈ!°µµÅ¶mÛi8}ú4êÕ«dgg‹-KYEÇÇ‹/QCâúDê6.÷û¡H´¦!„B!„ˆWk}z÷î-óvíP\\òÎUòB΢ßáþòË/X·nÚ·oððp¬]»–‘öäÉôèÑÝ»wgä+]ôØÆÆ-Z´`¤‰ÛÉ+88³fÍ‚ƒƒ¬¬¬iAAAظq#Z¶l ///lݺUb™JJJÀÊ•+¥ê!ÕEúB!„BˆxµjM dÑfQkøÃf—LßÒЮ°XÈNM xÍ]FÆ ±sçN¡iÚÚÚ8pàï|ðàïm0`Þ¼ù¾F»»;ïõû÷ïEÖçìì gggÞ¹§§'ïu§N-4_Ù2ùÏüñGüøãRõI\9’ÚNj¾ê2³Öô!„B!„ñjÝ ¬Z´iˆG[×òŠ9xq‹qÍ¢NU6‹§¨¨±±± )¢(´¦!„B!„Ô u~ЧóÜ«è\æZ€ˆ]º!,, ;VÕ; IDATk×®eLÓ"„P¤!„B!„HRç}„©.>àíí oooE7ƒðvùcDú(.ê‡"}!„B!D¼Z³3!¤Š°ø¢Ý»!„B!D„B!„"\é ¹LïRS×€ªªªØôò–[•ù©ËXJõݙК>„B!„"­éC‘ íÞE!„B!5­éC‘÷ÛÁ¿¨ïZÕ£5}!„B!D¼oƒ>Õã“{BHõWMÖq¦HReªË:V5ÙªU«0hÐ ëƒ B`` ZD!„RÛ•ŒóP¤!¤F¢HRUªË”Æš*//!!!H Fpp0òóóÐ2B!„Ú}„ðëeXie7ÖÓ­Ò|•¡:µ…Ô]éCˆtÄE*mܸæææPUUE‹-°yófF¾©S§Š,Åb‰<øEDDÀÖÖVVVeYYYÁÖÖåí!„B£Ö-äñãÇ—¯#„B!D$%`)|uÅQÊ+„‘£/Z‹–CçBûÿ&@˸»À5¥¼BE7•êÅú~(Eú(^^^¦OŸÀËË‹1M‡Åbáĉ°²²‚††lllðàÁ^:›ÍÆÊ•+annxxxàóçÏUÚ‹…   4kÖ ZZZŒ)H¢"WøÓÅõ¯°°sæÌôõõ±~ýz™M%å—ôüøÛ.¬/Û·oÇÆѵkWhii¡[·nذa¶nÝÊ»'$$Ó§OGq1óÃYܽ{vvv"Óíììp÷î]‘é⾄B!D¸ÒqžZ1½+..çÎc\;wîâââ$æåp¸ÐÔ¬½VFPWW†v}¸Æáˆþ4377“&z …ysxLpgüÑ•™‰ÇÁ¼¹Â`ä+;MJÜ´)þ´øøx tÓfMÑ®m9r„—£&†hbh{ûqóæ ±e†8€æf¦ìâ‚?òÒ>}ú„ŸÆCs3SŒÿé'dgg -£K$¿} xóæ ztï&²>R³ Û¨K›wÑš>ÕÀ’%KššŠ‡âÁƒx÷î–-[ƸçðáÃˆŽŽÆÇ1dÈ̘1ƒ—ŠK—.áâÅ‹HLL„²²2-Z$uýÒN/’$&&.\@RRãw —Ë•É"®xùò%îÝ»‡„„©~'ñ“”_ÒóãoékþþçæJÌ[úáå礌’|oø¯‰ûsõê@ÌŸ¿Ï_¼„£c­]ËK[¾b9zöì…§ÏþÁ»wdë˜>³fÂÛ{^¼|…_]ˆÅ‹¿ÿ‘ï9e2V®Z…÷)ÿÂßÏ>³|Ä–uýú5<|”¬X±œwýÕ«aooÇOžbàÀ\µJh~ûí¸‹~ŽŽrè!©ÎÊûÆZÞ(ÒGñNœ8   ¢I“&X·nŽ;Ƹ'$$¦¦¦ÐÒÒÂܹs‘0aaaؾ};ÌÌÌ ££ƒÀÀ@™ÖváÈ({ÈbÛ¶m°°°@ãÆ-S^qýÛ¿?BBB`ll ¬Y³F¦²%å¯èóËÍÍ…¶¶6ãš¶¶6rËüîÜ´iÖ®]‹wïÞ ”!A7IÊó5%„B!%jÅ ËàÁðòòÆøŸ~ÂÛ·1þ§Ÿàåå —Áƒ'™·¸˜ƒÉéHOýéi9ÈNMÇË7i׊‹9"Ë8{æ ,,-¡¬¬ çΈŒŠä¥ÅÆÄ`ì¸qPWW‡Ÿ¯Ÿ\ú{íú ¸  555ŒrsCVæ÷õ~ìììp!ö®^½Š~ŽŽ¸}Gü@ÓÜyóÑ A¸Øoƒ7QnnÐÒÒ¡CqîÜY¡ùû88 :ú< öB,úöí'‡’ê­zlÚN‘>Š—ššŠfÍšñÎMMM"6LLLx¯555Ó¿’““ѲeKÞ@Þ¿_ù /ÃÌ̬ÜyÅõ/%%¦¦¦¼sþg% Iù+úü„ ð233ƒŸŸfÍš%P†4ƒn†††HIIÛOCÃÊÛ@B!¤.S;EC^~]¸]ºtÁÀÎèÒ¥ ~]¸—&jqçŒÛ{Ц[{˜4ÓC+§é¸q6§þwpì@nœ»ŒgãðìÁS¼Jû"rW¯ôôt414@c=]´²²Bê¿ÿòÒ233¡§§0lÒD.}ý”•…àuë0i¢ºwëÊHÛ¶};rrr0nì´²²d„é cll hР>}úÄ»þáÃÞþÈÈÈš¿W¯^¸uë>eeáÁý"û$µHõó¡HŸjÀÐÐÉÉɼóääd™Þ¼›™™!++‹1XÀf³¥Î/¯é]•µfllŒ7oÞðÎß~› +¯üÒ>?‹%4R¦}ûö¸SæƒÛ·o£C‡÷úùùáõë×8}ú´L}\»vMdúµk×`cc#s¹„B!D´Ò¿þjE¤())aûŸbÂlÿóO()IîÚ—WgÐlôb|yuà4Ö£ÆüÄ7IX¹rÆÿf7ó[½9ÿý}}}¾rtyŸççç£aÆBókkk£]ûöX¼]ºtªªªÔý 5“ëû¡Hé£x®®®˜?>ÒÒÒ––†yóæÁÕÕUêüS§NÅäÉ“ñúõkàÆ2dˆÔùå5½«²¸»»Ã××ïß¿Gzz:„Þ'j JR~iŸŸ±±1¢¢¢„¦NŠÙ³gãÎ;ÈËËÃíÛ·1{ölL›6M  lݺ>>â§ 3xð`iüŽ=ŠÁß"s…©ÓI !„BjªZ3蔄֯ †¦¦¦Ä{3.¯ƒAç¶Þ®= :·EÆå`ÙN€†v}X47Xȹˆ-zzWÿþNxñâ9 °wï tÀKsvˆ=»w£°°ëË,„©¢¢‚¨¨(|ùòÁ!Áe‹éÙÓ§>bºví†M›62ÒzÚõÀ_'O¢^½zÐiÔˆ½#ÌúÐP|þü‡ÂÀy×ûõsı£G‘ŸŸÓ§N¡oß¾"Ëècß»vîDß~¢ï!µ‹¥Ä;‰"}oÙ²eÐÓÓƒµµ5¬­­¡¯¯¥K—JßÇǽ{÷†‹‹ 6lˆ™3gbâĉ•Ö^Y ÛýJ°²²B§NЮ];888@YYYnù¥}~kÖ¬··7TUU}pwwÇ”)Sàææ†† b̘1ðööÆØ±c…¶§gÏžè×9…WšH+WWWܾ}ÿüó@™Ïž=Ã;w0bÄ¡u–þkÑ¢…ð‡D!„BĪUƒ>²ø’r«ÌùÍ’"rýÉñÂß~ëWÃÒÂûöîCHèzFZÂãØtî,°emØŽðœ2ÖíÛ¡eË–Œ4q;y­ß°Ó§ME¯žvhݪ5#-tý„„† ©‰1<§LFØŽbË455E»¶mpóÆ üú}JÜÂ… qñÒE´ne…¿þ:‰eË– ä-ÕÇÁEEE´žOQMfwQ¤O5P¿~}„……!==ééé CýúõyéÂ"nø¯)))aΜ9xöì¾|ù‚øøx‘oþ+‹¸¨ ID’ú§ªªŠÐÐPÞó6lc  ²õ”%)¿´ÏoìØ±HNN›Í¨Ç××oÞ¼AQQëökSXX˜ÐÁÄ='MMMøùùÁßß_ <øûûCKKK ÂÃá®®ŽãÇ M'„B!â)«zDÂËÅÉãGE®áS*92õKþÀ\>¯7 ¾‘ÞE ;³$JèCrzÉöí,²SÓ!n™ ìÛ@hZƒ päÈ÷…¤‡Æ{=hÐ ü›ú}ÊØÄ‰“x¯3>ŠžîåââÞùt//ÞkÄÅ]šOX™^ÞÞðòö¸ÞHW‡ £\¶ccc´nÝM›6ÙfR‹0"|¤_EÞ(Ò‡ÔãÇÇ¢E‹```€¥K—bßÈ_]ˆšÚvæÌ±ùvî܉͛7£cÇŽ•Ñ,B!„Z‹õíczéãÌk“œ×hض=²ßç`ñÚ+Øia‹†ÍÌñùfžŸ¿‹¼bE0#,Úè(¤©………ˆŽŽ†ŠŠŠBê—$??;Âþ„Ó€’o&5·Ì˾®Z²Fú´±¦7¤ê999ÁÁÁ………pqqÁò墣&+#Mwÿþ}E7B!¤F«“ƒ>)IÏÑ´wÔÓoÏ™#POßJ*ªHIzƒ‰ðëe(rÑæª¶mÛVü±z5cšVuÒ¦u+tèÐÂÃÝRU¸¢×·ªJéCjwww¸»»+,?!„B©Ûêä ©ƒnî+Y8YÀÓ¯x×T›ðñ™ ŸÙ•R¶¸)dÒJz›,ù&R«T—Ù éC¤%jËòšBÑíWtý°jÕ*\»v QQQ2å4hzöì)rz!„BHmW'}ŒºyÀ¨›‡¢›AHÄ¥HRÃ(zÀ¢¢Ý~Eן——‡\½zUæ¼ÁÁÁèÙ³'fÏž-ÕΞ„B!µMݽ‹R>î÷C‘h÷.BjY·º/+""¶¶¶°²²HÛ¾};,,, ªª ìØ±ƒ‘nee[[[DDDT¨ „B!5•\"} ¾~—#zŸ‚¯_Ê]nUå;yÎ.ƒËU!µAaa¡ø„­ã¬@éCHÝpúôi¸¹ îÊyüøq¬\¹û÷ïG§Nwwwèêêbøðá¼ûF…Ó§OcüøñUÙlB!„jA ¸Õå]!¤àòŠC‘>Š7~üxLŸ>w>mÚ´*_t˜Åb!((Íš5ƒ––‚ƒƒi¥‡¨¼'Nœ€••444`ccƒðÒ 1gÎ@__ëׯ—)jEؽü×$Õ/©ýmÚ´Áõë×yçׯ_GÛ¶m÷|ÑÑÑøøñ#† ‚3fðÒñòåKÜ»w ˆ‹‹“©]ÒW¿¤ö5 Çç;v £FbÜÈÈHdeeÁÑÑ‘1HWª"ÏO\ùüù…ýÜ Å¥K—pñâE$&&BYY‹-¨#-- FFF×ïß¿ü‘q­OŸ>Œ3022BjjªØ~B!„ÔV4èC‘Iõˆó¡HŸê AƒÇôéÓáåå…ƒB[[[êüüeYlÛ¶ hܸ1¢££eÊSSShiiaîܹŒƒýû÷#$$ÆÆÆ000Àš5kd*»¢õK2räHœ8q@ɳ~üˆ~øq_JJ en!„BHm@‘>åÄæ°à4ç®ÐüUw‰ƒBü.\¸\¸pA ÿ AyÉ£ YÊ111á}ú\žüåÊWQâê×Yž‹¨CQÊöYÕezEúTáááÈÍÍENN<(S^yM窱õXŒñæÍÞùÛ·oeʯ¡¡ÁÄy÷îÜÚVjäÈ‘8~ü8Ž?.åãææ†1cÆ 11\.YYYBË(ïó“¥|a?/ÌÌÌ••Åø™Âf n accƒk×® \ïØ±#._¾Ì¸‡Ž;2®]»v 666²tB!¤Ö AŸodݹ‹ÍýG²ª–.ZÈ0ðsàÀŒ;ááá2µ¡ª½ÿ^ê{·mÛ&Ó'Öüúöí[®|U¶^Yú+­÷ïß =E–gý}Zÿÿ7Í‹"}ïÇðóóÃîÝ»±k×.øùù!==]êüòšÞUYÜÝÝáëë‹÷ïß#==Bï5PÕ±cG#//ÉÉÉðóó“{K×õ9~ü¸Àz>ùùùÐ×ׇ¦¦&’’’ëɃ´å#**J`@gêÔ©˜S¤â͘1“&MB—.]`kk ¹,T„°Ý£d+++têÔ íÚµƒƒƒ”•¥Ÿ½eËœ>> ‡Ã‘:_1›‡ GðSéÆgÂÄn š÷߈b1ApèÐ! >jjj>|8‰™ñéÓ'Œ5 ÿ÷ÿ‡½{÷2¦}ÎÍ…§§'Z·n)S¦l{ûäÉ888à§Ÿ~b,ribb‚°°0899(Ù eèС°´´D§N;Ãð×—““ƒ)S¦ÀÂÂ}ûöÅ£‡õ?W®\Á»äd¡}ÉÎÎÆÄ‰ѪU+Lš4‰×¦Ò:DMy211Axx8ìììмysÞN3={öäM½xûö-zöì)ñ¹ð÷]X½eÛ êò“ôuÄÝÝ·êÅ‹1iÒ$^š¸g.©Ÿ‡B«V­àêêŠ?2ú'ëô²ê²3Eú(ÞñãDZzõjÞùü!4"£2‰‹ ’A$,/ÿ5UUU„††"==ééé6l˜Ð/¢¢“:v숻wïâëׯxþü9FŒÁ¸ORýÒF@½xñ/^¼¸Þ¿<~üxýú5F-Õ3¶~iÊ€±cÇ"99l6›‘®¤¤„9sæàÙ³gøòå âãã…ÎhjjÂÏÏþþþiÓ§OÇ«W¯PXXˆW¯^aÊ”)ŒtøûûCKKKhÃÃá®®Îø]G!„R›(•·BMàèèˆcÇŽáÈ‘#ðôôD^^žTùŠø"}ŠËŒqØ› p8@Gô³e³Ù8|ø0ïÓß1cÆàÐáÃB×4JÞP 8W®\ÁÃ2ƒ,kƒ‚àïï„„ôíÛ¡¡¡Œô°°0DFFbÊ”);Ш©©ñÖâðóóôiÓ€ùóçcùòåBÛ²råJ 6 Ïž>ƒ¯¯/|ËL[¨W¯~ýõW¬øýw¡ùƒ‚‚лwoÄÇÇÃÉɉצҩNâ¦<ýóÏ?ˆ‰‰ÁÖ­[áååpppà­ípåÊ888Hõ\Jû.M½âža)IõIZÓgñâÅøý÷ßQPP€U«Vañâż4qÏ\R½7nÞÄ;wàììÌ{“.MŸ…âr¿ D‘>¤*Œ?ÏŸ?Gvv6–.]ŠaÆ)ºIuR@@¢¢¢dÎwæÌ‘Óò`çÎØ¼y³À:@„B!5]黵:é;wÆŸþ‰óçÏcûöí¼ëg#O‹ÌÃf—\” bs¹`sJƒŠÙ¢}.^¼ˆ¦M›ÂÜÜ`nnަM›ââÅ‹Bï…««+´µµá;g#íüùóhÙ²%”••Ñ¿œ=s–‘îïçMMMtïÞ111Œ´ò¶½½té555Œt)rúOll,úöí ee¸¸¸]„ÚÎÎ\.ׯ îdvḺºBKK ...2m<{ölhjjbÀ€(**P2èsåÊ%ƒ>öööR=þ¾K"î–’TŸ¤5},,,`kk 777ôêÕ Í›7祉{æ’êõõõ…¶¶6FŽ)ôk%‹ò.¶+oéCª‚““`aaââb‘á¤fºÿ>~þùgE7ƒB!¤ÒЖíâãã1uêT899aÚ´i¼ëâw.â(¡˜Ë‹ pYÌQŸb6Àbq. …b}8€[·n LÐÖÖ†£££Àý™™™¼uÃ&MiéééŒmwUTTéMš(™®™™ÉHãôøôéöíÛ‡ÇãÉ“'"Ûž••uuu‘é¥/Z/ooüõ×_Œë>|@ýúõ”ìpS:åHzzz׺wï___">>ž·ž¤ç"í€ þ–’TŸ4~þùgôêÕ‹·q)qÏ\R½ÆÆÆJ¾·²³³enSu$k¤Okú$ŸÈÎÝÝîîîŠn!„B!åRç#}bbb0jÔ(Œ=aaa"çý—UÄaÍæ¢˜SÕÃï{¤l®ðGœ’’‚'Ož 11‘ññúõk<~üÿþû¯@}}}Þö>0Ò5j„¤7I¼rø·€¬O%;000`¤ñGlLž<¹¹¹=z4öíÛ'²ÿ7Faa¡ÈôRM›5CÏž=v&ÓÕÕå­;ó%? 6”X–8jjjhß¾=–,Y‚Ö­[óG$=Y¢UÄ=ÃR’ê“Æ®]»`kk‹;w2®‹{æ’ê-¤ÊÉÉAãÆen¿ê²ÃEúB!„Bˆx%#Õd{\EPSSÆ %%éÇÀŠ‹Y`s¹HÌùŒe'ïbÿ¥ï»Š°Ù%>6…ÅÂó:t“'O†ªªª@{&Mš„C‡ äqrrÂÁƒñ97W`g¬~ýúáÅË(,,ÄvQY¿~=òóóqåÊ8;;‹ì׳gÏ0dÈØÚÚbÛ¶m"ïëß¿?®_¿Ž‚‚œ:uJìÖß³fÍ@rppÀ‰'ŸŸÈ¨(Þt, $J%##Cdy¢888`ÿþýèÓ§çÂOR½ÒŒëׯãõë×¼4qÏ\R½›6mÂçÏŸqôèQ 0@ê>3qÅUÖô!„B!„¾óÔùHŸÒíbeUÈUBézË%ã╇èkm‰€Ÿz‚Í)ôa¡XD¤ÏÙ³gEN˜0a¢¢¢töõõÅåË—ñ£½=ºwïÎØ:ø—_~Áºuëо}{„‡‡cíÚµŒ¼}úôAß¾}qìØ1øúúŠìWpp0fÍšXYY‰¼oþüù8xð ¬­­±eËlذAä½ZZZ˜>}:ãÚ‚ ‡Ž;"22‹-â¥9;;£G"Ë¥ï·Å›ù$=~’ê•æJªOÒBÎË—/ÇÂ… ¡ªªŠ… bÙ²e¼4qÏ\R½Íš5CçÎqûömÌŸ7Oê>WgéC!„B!â±–ïý•; ³348Zø¡!s­”/_¾ÀÒÒRdæ§ )é-zÙÛ D¬”:yZìÚ8¢T÷|ë~ëñócð4­d=š6†%Ï €õíÿö¯qÄÜÒ/R,­¬¬,ôéÓG`/BÊ211‘j‡®ÂÂBü33SÞùù3Q((*Âèq?áCZÉ”Ãââïák¥†Fˆ8~ê*jèÓ¯TUUÅ®¡óâÅ Ô«WOäÏ  äçÏË—/1hÐ ¡éO=iàç·a«…–#‹‚‚¨©©U¸B!„BHÍóôÑÀå ±ÐÓÓ…ŠŠ X,¥’n”XP²éM1›ŒŒèf×ЪµÌõŠz ÷V9Ÿ2_/çâÏR¤Oysηµ{Zé뢕¾8.8.¸.o]ŽðÝ×Ë¥cÇŽ¸té¥ïm¨ IDAT¾~ýŠmÛ¶ÁÖÖV~…"%Ú½‹B!„Bje@¶ÅlI —…N(}t\,¾ÿ–.sROŽÏvõêÕømáoHû„††Ê­lB¤U]V£Ý»!„B!D‹ÅBé`mÙ^N竼Î0á%DÒLíª‰(Ò‡B!„BÄ£é]„™°øE¢Ý»!„B!D<Šô!„HçÛ¼.ÿpçzQ¤!„B!„ˆ§ Tü}›šº†Ø]xÔÔ5Ê]nMÈGHmÀRª§è&È„Öô!„B!„A\|ç¡HBˆlªÉÂïéC!„B!âÑš>„™Ðš>„B!„R3P¤!D&,Šô!„B!„¡dЇ«ÀÕXk¨ÓkÿOlúày÷«¨%„ÔM´¦!„B!„Çâ–|XOӻʉÍaÁiÎ]¡‡y«î…øÅÄD£±ž.bb¢ÒëéV¸­ò(C–rëéâèÑ£•ÖŽÊ.³2Ë­ÉJãp¹¼ƒ°ªF‘>„B!„" ú|3l¤›L÷³¹¢§¸¨j颅 ?{÷ìÅOãÇcßÞ}2µ¡ªe|Ì”úÞÍ›7!??¿[S¹dék]Ã:ØSŠÖô©›$M/•¾jÕ* 4¨2š$Ö AƒXåõB!„Рâââp꯿dÎWÌeÃ︗ú:Lÿ~[â ª¥ -]˜·ê†£«lÄ–óï¿ÿâÑ£‡øã5xôè!RSSËÛ•jÅÃc"BB‚Ý R¸Üï‡Q¤‘V^^BBB\õ?“‚ƒƒ\£Á !„BHÍUç} ¾ÂÛÛ ¿¯X‡#u¾b6 Ü2o~wœ »%hÞ#ŠÅDÀûáê:jjj9rØ/òÞOYY6t(Ú´n…]»v1¦ åææbÒD´0o îøüù3#ïãÇ èi×n£F";;û{[õt±mëVô±·ÄÇÇc ó˜6kŠvmÛàÈ‘#Œ{Ký÷ߘè1Íšš w¯žxðà£>\Ž‹CòÛ·BûRvúÿyc=]>tVV–°²²Ä¹sçpéâE´kÛFM %UßÄ=“²ý×>QÏĶK$%½$%½m—.Ÿ!‘ŠôQ<‹Å;455ѪU+¬X±ŠnCDDlmmaeeUåu[YYÁÖÖU^7!„B!u~ÐÇÉiþwò/„‡ÀD ÈËË“*__¤Oq™±"`³(âˆôa³Ù8Žñîî€q?ý„ðÀf³…Þ¿råJ¸¸¸àæ­Ûxpÿ#mõê@ÌŸ¿Ï_¼„£c­]ËHß¶u+¢cb1mÚt®ZÅHSSWÃñÇ>³fÂÛ{^¼|…_]ˆÅ‹ mËòeË0b„+^'¾Áܹóà3k&#½^½zX´x –.]"²ÿâÜ¿ññ÷´6kþøwãïâÖí;Û±žS&KÕ7IÏ„¿ßâˆz&ýúõÅ¥K—”DŒõë×Wìýµ—ËåŠD‘>ÕCé÷Bff&öíÛ‡èèhÌ›7OÑÍb8}ú4ÜÜd›Â+O£FÂéÓ§V?!„B©»êü téÒ{öìÅÙ³g±yó&Þõ“Ç#.Åf—\” bs¹`sJƒŠÙ¢}bccдi3´hÑТE 4mÚ ±±1BïŽ>QnnhРæÎe¾©:{æ ,,-¡¬¬ çΈŒŠd¤ÏŸ¿ššš°ëÙçÏŸc¤ <ººz€k×oÀeð`¨©©a”›²2…¯m}ŽýûCEEC†Å•¿¯ ÜÓ«W/p¹\\½*˜&ɼùóQ¿~}8ˆ„„G˜2ÅZZZ4hŠŠŠ¤ê›¤gÂßoqD=“~ý÷mÐçr\úö{mAkúa444`kk‹ƒ ]È]”ƒÂÒÒêêêppp@RR/íëׯ˜5k иqcéY’ÒKݽ{vvv×óòò0}útÀÀÀ^^^ŒiX, 'Nœ€••444`óÿìÝy\Ìùð×tŸŽJ%©\V, [®Wa‰ë\RÎ¥h7WŽýÉ‘rk7l!·X K눰 Û²X–%¥ET:fæ÷ǘ1ÓÌwŽ®™ô~þߟæûù|¾ßÏ÷;³5óž÷çóqtÉjd³Ùøßÿþ‡–-[¢qãÆ˜8q¢X–%8;;#55•ñð³¥!„B©nô’’‚I“&bàÀ˜9óSÆŠ´ÉË8j(wD£>ål€Íå€Ãá¢TJÐ'&:ׯ_CcÁvýú5Æ _½z€yÓ¦"e¹¹¹hjn†&&ư·³CÖ‹"åM-,ZZZxUa’bcãOC™òóò¾~=&OšˆÝ»1öýõë×ÐÑÑa,ç[¾|V®XΘ½Ä„ß' @ãÆë2]›¬{"|ÝÒ0Ýg¤¦¦¢´´)))pqé)µ~ÝÇ•²Õ>ÊôQMŠ “xC¯âãã‘——øûû ÊV®\‰ôôt¤¥¥!--MY'o9_vv6,>þž‚¬¬,¤¥¥áÏ?ÿÄóçϱ|ùr‘:ÀÙ³gñêÕ+ 23gΔmذ.\ÀùóçñäÉhhh`ÉñÌ> ‹Ïf¾6B!„R·ð‚>,–ò¿¶W’ß~;ƒa_Å7ߌCtÌnèëëËÕ®ŒÃ›ÍE9‡øö)Ó‡ 6Wr\-##wïÞAæ‹xùêµ`ËÈ|;wþBff¦X333¼y“ÈÉÉ)322‹¬lÁq2_ˆ~ÀÈËË”””ÀÜÜL¤LøæñÆ£  cÆŽÅþÌsÑ˜šš¢´´”±œÏÊÚ½zõÂîÝ1Œu$eÂ(ò­7ӵɺ'òžƒéžhkkácG,Z¸íÚµÁ佇uKhS&ÊôQ-ÅÅŸqãÆŽ‹#FÈÝîÈ‘#°µµ…žžæÌ™ƒË—/ Êöïß°°0˜››ÃÂÂaaa"me•ËrôèQAû¦M›býúõ8|ø°HˆˆX[[C__óçÏÉô‰ŠŠÂO?ý4nÜ¡¡¡•š»G†KB!„Ï ÷c§Þgúhkë`Û¶íX¼d ÔÔä¿åå,°¹\<)xåÇS±çÂA›Í øpØ\”–Kn¿wïLóóƒ––v…þhcÊÔ©'t8höìÞƒwïÞaCD„HY¿~ýñðá?(--ALL4  R¾~=ŠŠŠpñâExzz1^×ý{÷0løptëÖ[¶lf¬7`À@\¹|%%%8~üzõta¬;w^¢ùEdŸ¦¦&P\\Œð*®òÅtm²î‰¼¤ÝwwDGÿ77w¹êhN"Œ?4ÉØØãLJ»»»ÜÁ—[·nÁÃÃFFF`±X000^•••+++Áckkk‘ö²ÊùÌÍÍ%Ò%µ¯˜‘cii)øYOOO¤éééhݺµà˜™™!##Cì<™™™077—Ø7B!„BjR½úôéÓC†U¸])W üKwÿJÇù¤4¸9Ø"ø°9üLÊ2}âã1iÒd‰e“'‹“'Nˆ ‰Z0.\¸€¯zt‡³‹³`è,Z¼kV¯†m›6س6Š´uswCOg<° ‚‚¯kã¦Íð÷›†ž.Îhkß–±^ðÂ…Ø»wìlÛ`ÓÆMض};c]}}}̘):Ñ3Bf‡_ uëÖŒmåÁtm²î‰°Š«‰ “vO<ÜyÁþ|>²ê“êC™>ª,**Â?ÿüƒåË—Ë5ô|||0zôhi÷ÄÊÚZ¡{HªeúÔü¡”³ÃŠŠŠ`jj ===<}ú .)3f ‚‚‚ ‡#¶*˜¬r¾ÁƒãÀ˜4i’È~oooaûÇ õ‚ àíí-÷uM›6 S¦LÁºuë`ii‰[·n!44'>þžæ;tèÆŽËx¦ûC!„BHUÕûLŸÊ*çœs÷Ø›ÃÞÔ\W0¯G±ù‹¥jko‡ßñáÃlÙ²=zt¯¾ƒ@ii)âãã¡©©©ì®(ӧŽFpp0 áææ†¡²./^ KKK888 C‡èÝ»·Bå|ÞÞÞ¸qãož6þ*Ž„B!„T'Êô©$—…¡ýÁŸ ˜ ÞĶüùc«Wã2¼aëÃñýß#;+NN]±eë¶j;6ቌ܎5«W#jÇNewEe©ÊÒÒ”é£|òf¦0ÕëׯîÞ½+²O8#PGG›7oÆæÍŸæÆ »œOOO DBB‚`¿¢¢¢%w¿…÷©©©aîܹ˜;w®ÄöˆÀÀ@ÆEbcc¡££ƒ#GŽ0ƒB!„Ê¢ O%-‹HªõszzzÂÓÓ³ÖÏ[ŸÌ™óæÌùNÙÝPMÜ ÿVü¹–)šéÓΡ“ò:K”.88X)ç=uê”Ôò;wbëÖ­èÔ‰^Ÿ„B!¤úQЇ¢U™v„2}ÈçàöíÛÊî!„BùŒ}œÓG5†kBê–ЦD4§!„B!„HÆÿ¸V-™>%ŠÁ•2cqɇâJ·.´#äsPZZ*W=U S¦OýÄb±¤Î%ÄT¾jÕ*$''‹Ìé#OOO¸¸¸(mx!„B!UA«wBê$Êô!ò*,,DDDÂÃÃnŽððpÕ@Ï!„B©Yô!„(H5ÆwQ¦ò±X,Á¦§§{{{¬\¹%%%Ê¸¸8899ÁÎÎNá¶vvvprrB\\\ ôŒB!„šõ1è£"3³BTžð}e¢LÕÀårÁårñúõkìÞ½gϞł ”Ý-'Ož„O¥Û9'Ož¬ÆB!„RÓxqÊô©¤³›¿’ºò¹á~Ü„}û”€2}T‹®®.œœœ°oß>:tHîvûö탭­-tttàêꊧOŸ Ê>|ø€Ù³gÃÌÌ Mš4ž%«œ/55ÎÎÎbûÇÁc???Œ?^¬ž³³3RSS¯A‚ „B!„HBAŸJbsXè?7UâÖÒ¾‡BŸßÿ–––øý÷ßÅÊ,--«Ü×ê8†"DZ´´ÄÑ£Gk¬5qLKKK‘ÍÞÞ&LÀË—/«ý\ÏK*‡2}T‡ÃQ¨~\\âãã‘——‘ ÌÊ•+‘žžŽ´´4¤¥¥áÂ… "me•óeggÃÂÂBlÿ¶mÛpîÜ9;v qqqHLLĶmÛÄêYXX ++K¡ë"„B!D¨KeÖãQž^ƒªÏæ2ß3-}c´R ð³wï^Œ3±±± õ¡¶eddÈ]722²ÎM|š‘‘!ØRSSѹsg„„„ˆ”×Ä9ëUÞE™>ª¥¸¸7nÜÀرc1bĹÛ9r¶¶¶ÐÓÓÜ9spùòeAÙþýûsssXXX ,,L¤­¬rY4h€ØØXøûûcúô騷o :ðiˆ!„B!ª‚ÿy­Þgú$%%!>>^ávå\8\¶[YoÑÑÿgl»-}ch꣥}wüÞSêq²²²pçÎüøã¸sç²³³+{)*eܸqؼy³²»Qi˜:u*cæ@½Æb}Ú”ˆ2}T?hllŒñãÇÃÝÝ]îàË­[·àáá###°X,ˆ‹³²²`ee%xlmm-Ò^V9Ÿ¹¹9233%–uïÞ-[¶D«V­Ð­[7‰u233ann.×5B!„¢Jê}Ч¤¤sæÌAhh¨BÃÊÙ,p8\p8âßð6é4 –Î!hÑo3Ê¥d¼oª‡ mmm 6 û÷íc¬›ŸŸ‘#GâË/¿DLLŒÈР÷ïÞÁ××mÛ¶ÅÔ©Sñþý{‘¶ÿý7\]]ñÍ7ßàíÛ·‚ý–––ˆŠŠBÿþý·oßÆÐ¡Cakk‹Î;ãÈ‘#"uù 0uêT´iÓnnnø+-Mä|ãÆCRRž§§K¼–ŠÃš„[ZZâСCppp€ƒƒΞ=‹K—.¡sçÎhÑ¢Μ9#×µI»'¯[‹uuuÆ>ÆÆÆÂÙÙY¬OÒž'i÷éÞ»¸¸àÙ³g€gÏžÁÅÅEjýšÀæ°‘âŠkw±X,°9ì;7ÊôQ ü,—¢¢"üóÏ?X¾|9tttäjëããƒÑ£GãÉ“'àr¹ÈËË)·°°@ºÐïô ¿Od•ó9::"99YbYll,Þ½{‡‚‚ìcøý›œœ GGG¹®‰B!„URïƒ>8|ø0<___ÊÕ®L(Ó§¼B¬ˆÃØl€ÃÊ8ÌA6›`̘1€Ñ£Gcÿ`³%€^³f  „¤¤$¤U²¬ C`` îܹ777lذA¤<** ñññ˜:u*Ö®]+R¦­­-ø°???ܹsAAAX±b…ľüïÿÃ×_û÷îcÞ¼y˜ R®®®Ž… bå?2^¿4iii¸zõ*BCCŽ[7oâòåËØ¾};¦OŸ.׵ɺ'Â×-ŒÍf#==‘‘‘ððð`ìãƒpîÜ9±>I{ž¤aº÷®®®¸té^fš«««Ôú5¡àmôôô>&øp…6@OOï ÞÊ>H5£LŸºƒi8`QQLMM¡§§‡§OŸbæÌ™"åcÆŒAPPrrr••%¶*˜¬r¾ÁƒãðáÃbûsrr€_~ù»víB@@rssÅê:tƒ3V…ᎄB!„H¢õ}*‚.]ºàçŸÆo¿ý†Ÿ~úI°ÿt<ó½l6ã¢b‚›Ë›Ã •³™?œ?Í›7GË–--[¶DóæÍqþüy‰õáíí CCCÌ›;W¤ì·ß~CëÖ­¡¡¡~ýúáô©Ó"åÐÓÓC=pîÜ9‘²AƒÁØØpá 4ÚÚÚá=Bì›wᾸ¹¹ACS^^^'¡vvv—ËÅÕ«Wï“yóæÁÀÀýû÷ÇÝ»w1ùÛo¡¯¯ ¬¬L®k“uO„¯ø4™³µµ5ÜÝÝ‘‘‘•+W2öñ»ï¾ƒžžžXŸ¤=OÒ0Ý{WWW$%%à}úôé#µ~uÑÐЀ††454rý*Ø6Œ›˜¢‰©¹`3nb —Ô)ÐTׄ†&¯Mm LŸº/::ÁÁÁ044„››†*R¾xñbXZZÂÁÁ:t@ïÞ½*çóööÆ7ðàÁ‘ý3gÎÄäɓѵkW899aâĉb§û÷ï#%%Ç—xìüü|@«V­ºvB!„Bj?ÎS;ŸÎTÜÍ›71mÚ4ôïß~~~‚ý’&wÖÖÑÅËÑð°µAé½½hâ4 ¯ß•ŠÔ)g,à²P*%è³wï^üñÇbà %f˜¼~ýúúúó¦MEÊrssacc#x¬©©)RÞ´)oå---¼~ýZ¤L8𑟟ݻwãîÝ»øûï¿ûž——'׎¥K–`úŒøõ×_eÖ•Ô'~¡Q£FŒu™®MÖ=¾n€7©2‡ÃÁ©S§eË–ÁÀÀ€ñ¼&&&÷K{ž¤aº÷=zôÀ¼yóPZZŠ›7o æJ’÷¹ª,555hjhÀÐÀo pþ\"Xj¼Éßy‰ ¼×·¦†&LLŒPRüjjµ“@¨h¦O;‡NµÒ¯úDÞÉ‹™êõë×wïÞÙ7jÔ(ÁÏ:::ؼy³Èü`BY…²Êùôôô€ÀÀ@$$$öW¹fͱ¶ ü7]Qll,tttjtx%!„B!•Uïƒ>ç΃ŸŸ|}}ñý÷ßËõµøßS°µéWN“À–éÃâ\pÁæJ>^ff&þþûoÚÚÚØ´i‚ƒƒe|´utñòÒz˜uia_t€Y—öxy)¦ µ°ç§al6PÎá‚Ãæ¢´\ò±öïß)S¦ˆ|øý™zˆÒÒRìÝ»Wl˜ÄÆQTT„¤¤$ 8ñïß¿!C†ÀÉÉ ‘‘‘Œõúõ뇫W¯¢¤¤'Nœ€››cÝÙ³gc÷îÝ"û455qæÌcÓ¦MŒmåÁtm²î‰4'NÄû÷ïÅ&–‡´çIi÷ÞÕÕ{öìAß¾}åª_´´µa ¯Ã†hРok(ºèË V7šÓ‡¨‚Û·oãÛo¿Uv7!„B‘èc DýÔ§W¯^ Õ/Îü ÌÛ =¾8Ÿ”7[ã6‡ËõÂe¡œ!ÓçôéÓŒCž&L˜€¡C‡bn…ù`æÍ›___DGGcÉ’%8xð  ì‡~@`` ®\¹‚–-[bãÆ"mûöí 777´oß^lBcaááá˜={6 E†ºU„ÀÀ@øûû£E‹R7úúúð÷÷¹þäÇzzzøá‡ÛʃéÚdÝYÖ®]‹‰'¢wïÞÐÕÕ•»´çÉÒÒÛI»÷n®®X ˆdóÈû\U555¨³ÔxÙ=j,¨±Xb“×r& ¯)ÊÎôÉyWoBT[Çf¼•'Ó2keEB!„¨ÁêË+brt]¶6£¤¸¸¶¶¶Œ¹÷ןxúôzöé#–±Âw:þ¤Ä¹qdQÅv9‰+``˜ }s[gWf=Eá{süm= íÌy÷ €õñÿö¬õÀü•gî,yyyèÛ·¯B«C‘Ú'ëy’ªm¥¥¥¸|ñ"ll¬û.ýžchjj‚%#èSÎfãåËWèîÌ[R^Ú:>„ºº:ãï €÷ûçÑ£Gðôô”X~ï¯? ü,þzµ¢·DLII‰ £‰‚>Ÿd&ýËówáíã,pÊØ˜^pPv£j¶1,7®'#öH¼XÙö¼y‚”Ñ/0o †ì‚ÚúXÛèú*ï›^èÖÃs+ÿåÇ/?oEøÚñêe.²Þò‚<ô!„BjÆëÿxŸëªò9©•][…ÏË4ª"!!mÚ´ûlUðæŠÕ‹q:5†w)¤à1YµDaî{,]—„ÂÜ÷hdÕ܂ǰ75‡Ã‡Ã—ìàÅ©Æ÷[:uÂ… ðáÃDFFÂÉÉ©úNª<ÏSYYNŸ>-6¹4‘Ÿ²3}È'ÉÁ1ÈQ×Ö)%°RTTˆŸ¶F`EèúZ?·<>ç€@×W+B×#rK8Š‹Š*}ŒõkVbWìQdæ—É®L!„z§ÞO䬈̧ÿ y¯¾P7mßYánj 5M-d>ý «ûñFtáãzF“Ô˜X–Õ«Wcñ¢ÅÈÎɆ£££ÔaZDyäyž¢¢¢°nÝ:lß¾] =ü<Ðê]ªãí¿Y€†­-dÔ¬ 'âðe'´jc'±¼ª(eg UVÒ…DìˆÜŒ?®^FiY),›[ãkïј1'ºzzÊîЪ¾ìâ„„“q1j\¥Žñêe.ºvûªš{F!„Ï/èC£äbí€ë»ÃÜ;ú¯`ÿ’N>5~þ`À€5~R5òÆy(ÓGÆ|`\ ÁBˆl”é£|ü ˜Šù1œ26®/Û‡G‡®Úø¸ û²±PÓTkÓv‚+¿ŽÒ‚"…3jÒn¥baÈÿdö¯âqùåvc{ãéé›ÐÐÑ„óšIhõuw¹®OóŸFoe‰¾ IDATP+cÔÉsWD7·²ÁŠÕáèк©È~~?ícu_ß‹Œç8vd?ŽŒÅ…k²ç«3o †{cÕòEÈÈH‡}{„o‰Âþ[W•ëcÒµ»3Â×ü¨p»òòrü–ð+š6³¬^B!äsAABHD™>ÊÇ~0Cn‡GÚæxô ã-i~yþ.h7ÔG— ábÇb©±0áa$¸¬p?rs³an.>´¬bÿ˜4ws@»Éî8æ±ÉÁ»AY×' ?P •jËÔ‡Ê^¼}ûñÇàè¡}øçþßèõ5V„†ËÝþØÑƒ8øëo026ÁöMáœ%쪬ê¸>y˜7µ@NN–Âí,´Àb±°é§èêï!„B>ÕôÑÖÑ•º ¶ŽüË]×Åv„|Xjê²+©ÊôQ}ÿìO´Þ/èóϾKƒ>N‹GASOí¾u¯Õ>@Ë!Ý ¦ÉûsX˜ùºÖÏϤº³KN;Œ¥?à×ß’jô<òš2nRþ¸ W˜=/=û¸CCC±·%+CÙ.3æbˆ5bujâú*‚*fÉ*¯Ïr‹°eÃ:l_ƒ‘£ÇWË1 !„òùá½»bÆ„BêÊôQ}ï_ð(Úôû ³ò$ÖÕmÒ Òç155GVV&Z¶jS©öêÚŸ÷*zeeeXµl!~=v±GâѪµ­²»àryÍY,PÉ÷ ÂC›tõôª´ –"„7’æì‘U.,ëE&LMÍŽ&MõGÄÚ• ·%„BÈç?u3-ÙN©“Íô!µO¿© äM!JÞŠìS…/:vvDÊõäJ·WUæ Ô7y=ýï1{¸àáƒ{H¼|¿t¬Á+fWìQ\N½‡.]»aÓúÕèhÛ ¾óÇå‹¿+»kµ*åz2:v®ÜóÒØÈåååÕÜ#B!„|N(èC©“(ÓGõÙéx|ì:»°Ý«ÚÏÓo N;RíÇåÓ5mxû$»ÆÎ!Iv‡q“Ç‘ƒ{Ñ¿WWx ðÂÞ#ñ026‘XOÑ@RujذÆMòűSp.)Ö6-°48 ZÏ¡Ìë“lj¸Ãè7ЫRmÕÔÔ ®®6›]ͽ"„BÈç‚&r®¤“ë¾”Z>xÁíZê !õÍé£ú:|Ò·EH]à Ètœé‰ÎC«ý<^C¼ˆ>@k[{Áþª®¾Å×méh¤¬:Œýç‚ËáVjõ®Ê® U³|'Ö­ ÁºU!"eÿ<ÏCÆðöM>À¦E+…_Ý×gaÙ³æ}Yó¾¯ô1*ªë“uÍÒÊýs·o¥`ÇÞà ÷Oз¦Ít1½ú¸C]½nÍÍF!„š÷1èÕ^‹ˆasX"±ìÑ™Ù8¹îK¹?ÿþû/–.Y‚k×®ÂÈÈ3gÍÆ·ß~[ÝÝ•ª‰‰1^¾ªÞÉKk☄£LÕÁQÓÒÀW¡ðUè…Û*BWOþ³²p>bÄË}ìŠåLõÛNpEÛ ® ÷KY$+rþ£‡b¡­£ƒ{:¨âõUܧê×·lá|LŸ==}Ù•,X‚¹Ó¿EnN6²ÞRÆ!„BøxqÕÍw®e_ðQ¨>›Ë<ÿ„–¾1ZÙ÷™ ”›› ïáÃðõ°a¸s÷oìÛ11ш‰‰V¨/ªˆ>¤¦Ñœ>DØœÀD>D>ûvïÂêõ[ðÅgš §ê×{4s¨Ò1F›Œ´‡™ð!„BˆDõ>èsñâEœøõW…Û•sYàp!Øne½EGÿŸ°í"´ô¡©oŒ–öÝqhóäŒ7nÀäÉßÂÇǰ³³ÃúõáØ[•K"¤^ LBª.ñÊ-Œ_»Ù¥µés¿>B!„Yêýœ>%%0cÆtüõ×_X¸hÔÔ䋃•³YàpøËÍŠ–5é4 ,ð’©ÒþêÁxŒß±7vŸÈ>GGGœùí¬àq~~>fÍœ‰«W“áìì‚-[·¢Q£F¼ó˜cóæ-YÆ›«aãÆMÐÖÒÂìÙ³——‡¨;áéé)¨»aÃF,^¼_|Ñ¿DGÃÄD|RÏwïÞaÎìYHJJ‚‹‹ ¶nÛÀèÑ£0}ú ôî݉‰çýK4ö2¨„‡wݼyK/Âßÿ CCC,Y‚Q£FÁ©kW:|66-ðôéðéƒ))Œõ ¦ì9}Ì +¿Ú!„Ô$e½#„B>Wuq< /ÂQ…¥rëºþýàØñ_»“&N@aa¡\íÊ„2}Ê+¼·â°6àp€2ó½ÍÌÌ„•••Ø~–Ðó±fõjôéÓwÿ¾‡Aƒ!tÕ*‘º·oßÆÍ›·¶. k׬AêÍTüq#Q;vÂwꑺW¯&#í¯;ðòòÂÊ•+$öiõêP}>‚‡G?„­['([±b%–…„ ¤¤+W¬ÀŠ•+¯M؜ٳ0cÆL<|ô/.\„¥K—ÜÝÝpἌ+ww7©õ F™>„Ô–Š¿GPVÿX,–`“eÕªU‚/aT*?¿žžž Uv7!„º‡ûéo|½Þ]»vEtt NŸ>­[·ö?rˆ± ›Í߸àTú°¹\°9¼`P9›ù͋ŧbã Î;‹‘>>Ð××Ç¡CqæÌi‘òAA000ÀÀAƒpçÎ_˜:ÕúúúðôôDYY™HÝù ‚РAøŒ…Äsç$žïô©Shck 4ñ ŸæÈ°µµE÷îÝ0ìë¡èÕ»7Z¶l)µï|ÉW¯Ákð`hkkc¤ò^óâ£îî¸ø1èséâE¸º¹I­Oˆ0šÓ‡ÚÁåªöbÊê—Ë•ëÜ………ˆˆˆ@xxx-ôJqªüü†‡‡#<<EEEÊî !„RgQÐ@JJ &MšˆbæÌY‚ýL“;¿¼ [”ÞÛ‹†š(¯¸)gl.¥R‚>VVVHOOÙW\\ŒcÇâsrr`hhÐÕÕÅË—/Eê44x#õ7nÌx¾fÍš4h€üü|‰urssÑÔÜ MLŒaog‡¬/DÊ}§ù!%%Ó|§1ž§¢ü¼<„¯_É“&¢G÷n‚ýÎ..HMMEii RRRàâÒSj}B„Q¦‘%11C† AãÆ¡¯¯víÚaÅŠ" ÉÖøÜ_»¶¶6lll0sæL¼®¦@»ðñõõõakk‹ùóç#//OáãÔeqqqprr‚È~y^Ÿòª«÷HÖvvvprrB\\œÄrB!„ÈVïƒ>¿ývþŠo¾‡è˜ÝÐ×—½ljñ¿§`5j)Šÿ=`3fúpÁæ2ßâ>}ûâTB‚ȾÄsç°cÇÁcccc¼{÷PTT$˜Ï‡O‘7zü7òoßÂÔÔTb###¼ÈÊÆËW¯ñòÕkd¾È)úù'tëÞ?ýü“Üç?a< 0fìXì?ðiIdmmm8tìˆE ¡]»vÐÑÑ‘ZŸa”éCd Á°aÖ–†7oÞàÔ©SxöìFþ”7[ãsÅ¿þÂÂB\¹r 6ÄØ±c«ýø¯_¿ÆñãÇñêÕ+Œ9²ÚŽ_œ>â_"Éóú”f̘1غu« «·¬¬ [¶lÁ˜1cªµÿ5IžÿþFމ“'OÖR!„ÏO½úhkë`Û¶íX¼d‰\“8¿¼´f]ÚcØ`Ö¥=^^ ‡iC-ì¹ð@P‡Íæ|8l.JË™å7Í?ý‰cÇâPTT„ü%Kcöì9‚:îî8|芊ŠpòÄ ¸}U7lÀû÷ï±ÿÀ~ 4Hb~ýúãáÃPZZ‚˜˜h 8@PöðáC\¿þâââpåÊüûï¿r÷þ½{6|8ºuëŽ-[6‹”¹»{ :ú¸¹¹ËUŸ>Êô!, G…tuuáèèˆ?ÿüSPžœœŒÉ“'ÃÊÊ ššš°±±ADD•ØëO–±|°Œåƒã“¶bñ·XßÌ÷Ž\”³ËØ8´ë›ùaéTÄOBYQ ÌÜqãÄ?ýfÂÌ}†,--ñý÷ßãÊ•+dga”––bîܹ033ƒ©©)6nÜÈXWGGíÚµCxx8®]»&Ø¿oß>ØÚÚBGG®®®xúô© LøÜ’ú"«………ð÷÷‡™™ÌÌÌ0}út±,/i¯Yý“Wjj*œÅöWõõ Á\AžžžÐÔÔDLLŒ\íëJ–›³³3RSSËëÂ5B!ÊÁûb¥Þ}úôéƒ!C‡Ê]¿8ó yoÐÏ'¥ÁÍÁÁ߸€Íágú°P.%Ó§¹•bbvãçŸ~‚½-fÍš…~Æ€Ÿ-‹-Âù çÑÖÞ¿þzË—Kž€YÖÖÖø¢};\¿v Á I¬³hñb¬Y½¶mÚ`wÌnDlØ(([ºt B–-ƒ––6–…,Ã’%‹eMLŒÏ»qÓføûMCOg´µo+RæáÎ ö¸ ³¤Õ'„2}8pgϞūW¯0dÈÌœ9SjýøøxôéÓ§ZÎ-ü¡¹â¦ˆVý:bìÉïñîE>ÎÌûôýÊêãH^w}WŒÂ€ “y—˜w²ÁËûbÇzù÷s˜w²QøZÊËË‘žžŽ¥K—ÂÑÑ€ì,ŒÐÐP4ýà^\\ [[[ÆÆ÷þúOŸ>ƒû€ÐÒÒ’Xçø‘CŒsãH£ŠíÒãƒa`˜ }s[gWf=Eá{süm= íÌyK s°>þßžµX´î²Âý©nÂK¨Žç#UWZZŠÄ3§acc-Øwé÷D˜˜CSS,–ï­ j>Ü–³Ùxùòº;»€Ô%Ò>|uuuÆßï÷Ï£GW¼ùñø ~ªcÉö’’hkkWù8¤z°X,<þ–––xC`›4i¸ ãáÇ1kÖ,\¾|Yìo‹ÅªõÀËX¼¿9‹?ÄB]SËÕGñösy‹lj3yÿfã‡7ÑPÓPÇ*ƒñhdÓsÿÛŠÄbqc˿ۈæÓóÒ·ãúãÐý»Ap_ýÌóK XZZââÅ‹hÕª•H=I÷¦uëÖ8uê”à^>zô¶¶¶‚º, ÐÕÕ¼{÷cÇŽETTôôôÄŽWXXSSS±çOÖsÃTÞ¢E œ={mÚ´üóÏ?8p žƒ$$$ M›6bŸ­ ò_¡X£§SOQ¦B £‘UKæ¾ÇÒuI(Ì}FV-Á-x {Sp8\p8\p9\Á¼>¶²;]»JKKMMMew…|æ(Ó‡|`x®%}0,++Ãüù󈄄¹>P×& mM°ÔÄ0¼ÀùêF“°Ê`óN6(-,Aúå(zýE¯ßáé¥{(ÿP¦P¦?Û£¬¬ OŸ>ŰaÃ0{öl¹ÚfffÂÚúSØÊÊJ¬NYY PPP€»wïâ?þdݺu 022‹Å‚Aµ~°ÏÊÊ铵µµXƈ´×OuõÏÜÜ™™™Œå•}}8p³fÍü½ÕÔÔÄìÙ³ øTUm ËÌÌ„¹¹yŸB©Œ²²2#;'Y¹9ÈÊÉEVN^ääàEN62³yÛ‹¬l¼/,DYi©ÒúÊ[òIõ³{UBæÓмW_¨›6€ï¬áP7µ„š¦2Ÿþƒ„ÕýÀÂÇ,@pOÕëÙ8óÈÈíX³z5¢vìTvWÈgŽæô!òxüø1ÆŒܺu &&&Õvlit«#s¢A3#ä=ÎÁù¿@§‘è"üÀέçaÙÝàrq{çy‘2EhhhÀÚÚ+W®¬ô(K³fÍðßÿÁÞÞðìÙ3©õÛ·o;vÀÏÏ €‚ƒƒqøða4jÔùùù022kÇÏQ4°`nnŽôôtA¦OzzºBÁyû§««‹>#¨ÈÑÑÉÉÉ‚~«®×§2—­¯iÉÉÉ‚!‡„Bˆ*àé*ÌÏGcc#¸÷CÃ(gÊøÐPWÇû÷ïp!ñ^½Êƒ¶¶8Ž\óWÞ{'ÊôQ€µk®ïŽÄ½£»Ðøí¿¸wt®í‰„µk~Œ¸„•—ÿ®ÜÀÛ–E$)»ÛPkC­æÌù™/²‡äR](ӇȲwï^8::ÂËË ÕðD癩¸U‡Žû’þ‡’wÅxy/Ç&lÛZ@SO÷Ž\‡MŸv°éÓ÷Ž^‡¦ž6Œmå›?F›ÍFVVÂÂÂààà W›ñãÇcÞ¼yÈÈÈ@nn.‚ƒƒe¶éÓ§LLLpüøqÁÔÔzzzxúô)ã|LÍš5CBBØlÅRg½½½„ììldggcÁ‚ðöö–»½¼ýëØ±#¢££û7xð`>|XlM¿>?‡ÂàÁƒËi"gB!µ­¼¼åçìéãê›Ï‘•™!Ø^d<»Œ^½û¢Œ]†ò2^e  ,ºOD…ib›E÷‰Êî!õeúYÆ7oÞ $$jjj"CQÞ¼y@ò QªÂ凯Ñw¹»uM¦âȘhãÙo̸Y+”•À¦O{Øôi‡òe0ë`%q¨þ5óW¯úï¿ÿÃdÝ›àà`ØÙÙ¡sçÎøâ‹/àêê ™ç DXX¢££ CCC¸¹¹a(â k׮Ō3 ¥¥%qõ.¦þ-_¾&&&ppp€ƒƒLMM±lÙ2¹ï¼ýÛ¼y36mÚôqî3ñ{ïíí7nàÁƒ"ûåy}Ö$UxíËêÃýû÷‘’’‚áÇKlŸŸŸ"sPB!µIWW…ïßàåÕð7(,|m†LàÚ$ûÝ!„¨ E3}ªc"g¢Z$eÔT\Ý©2Ǩ-ü ›™«kª£÷Òè½t„ÄöS¯ÿOj{Yd]»¬r---lذ6lÀ›{%,,LfûáÇ >Äß½{W¤lÔ¨QbõÇŒƒ1cÆ(Ü?DEE!**Jb¹¬×O¿~ýä꟣£#îÝ»ÇØ===æì‘·ÿ5MÙç—§ „¾¾¾ÄòØØXèèèàÈ‘#5Ñ=B!D¦²²2©ï)ÊÊÊj»Kbª%èSò¡\)3—|(®ôqëB;B>¥Jœ\¬2(Ó‡å7n–,Y333,[¶ _ýµ²»¤’äúFÄ:uJjùÎ;±uëVtêDA}B!Ê!:¼[„(_ÿþýáêêŠÒÒRxyyaÅŠÊî©Gnß¾­ì.B!‚¬‘|å'Ô PЇR'Q¦!Ê7~üxŒ?^ÙÝ „BQ:áiU`µMäL©“hõ.B¤ž¸ªÇQæù`ÕªUJYÒÓÓ¡¡¡µ~^B!„Ô!\.Àå‚%ô?þ>U ðGž©F‡êг›¿’ZÞoöÕZê !õeú"?Õ¸ªA—ÊNø[]ç/,,DDD®\¹R¥ãTFxx8\\\ðÝwßAOO¯ÖÏO!„Õ'é’JDW>¾£LŸJbsXè?7UâÖÒ¾‡Ì ßãÇ1qâDØÛÛ£Gˆ‰‰©áž‹³´´¬–coööö˜0a^¾|Y­ç‘t^R?Q¦!ÕC•–©—$..NNN°³³S¨]bb"† ‚ÆC__íڵÊ+PTT$¨#+ÉÎÎNNNˆ‹‹«Ò5B!ä3&ÈêZ´]…2}(èóÑ@¯Á Õgs™ß$k飕Ÿ—/_bôèÑ2dRSSƒ½{÷bïÞ½ õEUddd¶ÔÔTtîÜ!!!"å5qNR?Q¦!õÃÉ“'áãã£p» 6 iiixóæ N:…gÏžaôèO¿¸\®ÌL¦‘#GâäÉ“ ŸŸB!õWʦ ê}Ð')) ñññ ·+ç²ÀáB°ÝÊz‹Žþ?#`ÛEhéCSß-í»ã×ðžŒÇزe &L˜oooÀÖÖkÖ¬Áu?+ÁÀÀS§NÅ… ”Ýò™¢L2nÜ8øûû ûùù‰M*|ðàA899¡Aƒ°±±Á®]»TªÒ°X,Œ5 FFFX¶l €Æ#22RP.©"Çç×—”ñ"+ †Åb!""Mš4™™æÌ™ƒ’’¹ÏߥKœ={VðøÃ‡011Ann®H½ÔÔT8;;K<ÿÑ£Gagg]]]8::âÏ?ÿ”'''còäɰ²²‚¦¦&lllÄÄD¹ûÎÎÎHMMe,¯®y‹!„RW} ñp9Ÿ6 ûÔû OII æÌ™ƒÐÐPp8¹Û•³Yàp¸àpÄ¿%lÒi,CТßf”Kɺpá $²¯sçÎ"ß(¾yó“&M‚½½=&OžŒ·oß Ê,--qèÐ!888ÀÁÁgϞťK—йsg´hÑgΜ©{`ÿ~ØÛÛÃÛÛ¯^½’ا÷ïÞÁ××mÛ¶ÅÔ©Sñþý{AÙøñãqùòeÀùóç1yòd©÷ˆÅbA]]]¤Â?ÇÆÆÂÙÙY¬¯ùùù9r$¾üòKÄÄÄHÂ%\vûöm :¶¶¶èܹ3Ž9pqqÁ³gÏÏž=ƒ‹‹‹Ôú¤n L²mÛ6œ;wÇŽC\\±mÛ6AùæÍ›ñã?"""YYY8sæ ®^•¾5á GÅ­:ú'???œ8qË—/ÇüùóqêÔ)¬Y³F¡c0Îráÿ,ü÷Lž,˜‹/⯿þBZZž={¦Ð¤Ç¾¾¾ˆŠŠ<ŽG·nÝ`jj*R/;;qàÀœ={¯^½Â!C0sæL©çŒGŸ>}äî#XXX ++K¡6„B©?ø#¹8\®`S¡Ñ]ôñððÀáÇqðàAøúú¢°°P®veB™>åbE6ÀfPÆaþpðâÅ XYY‰íþ@†^½záæÍ›èß¿?Ö®]+R7-- W¯^Ehh(ÂÃÃqëæM\¾|Û·oÇôéÓEê^»~)))8p V¯^-±Oëˆ;wîÀÍÍ 6l”-]º?þø#JJJ°jÕ*,]ºTâ1Øl6ÒÓÓ ÆëðàÎ;'Ö×5kÖ`РAHJJBZZcûŠàçç‡;wî ((+V¬¸ººâÒ¥Kx™]®®®R듺2}Hƒ  LŸ>ûö탡¡¡ |Æ صkœ¡¯¯{{{ìØ±Cîã B*nÕÑ?y8;;£[·n€ž={ÂÑÑ™™™ £&………¡iÓ¦077GXXbccånûÍ7ßà÷ßdöÄÆÆbܸq ?""ÖÖÖÐ××ÇüùóE2}*:|ø0æÍ›'òw­:(òš „BÈ爗ÕÃåreú¨˜.]ºàçŸÆo¿ý†Ÿ~úI°ÿt<ó~6›¿qQ1AˆÍå‚ÍáƒÊÙÌA‹6›-µo¿ÿþ;¼½½¡¯¯///‘Tx˜7o пܽ{“¿ýúúú0`ÊÊÊÄêbĈøý÷ß%žï·ß~CëÖ­¡¡¡~ýúáô©Ó‚²6mÚÀÉÉ >>>èÙ³'Z´h!Ò–?‰³µµ5ÜÝÝ‘‘‘•+W2^5”Š}MLL„··7 1oî\©÷G?sJ[[#¼G ///è“””€ôáËËTŸÔ ”éC {÷îhÙ²%Zµj%Žð¥§§£}ûöJê´þÉC[[ššš"?WüÝ®LÂ_\XYY)244ÄðáÃüü|\¾|C‡«gnnÎx\álO===‘IšùÊÊÊ0þ|"!!¶¶¶r÷233ann®PB!„Ô‚LŸ#x£(ÓG¥Ü¼yÓ¦MCÿþýáçç'Ø/mrç2ŽÊÁѨO9`s9àp¸(•ôiÞ¼9ž?.²¯¸¸¿þú«àqNN ºººbòŒ€F1ž¯Y³fxo´ß¼y#±Nnn.lll`ii‰Ž;âEÖ ‘òo¿ý7oÞÄ·ß~+Ö6##CáÓ¼ys,[¶LÐwILLL$îýú5ôõõæM›2¶¯(??7n„¯¯/zõî%Øß£Gܼy¥¥¥¸yó&¾úê+©õIÝ@™>àe‡¼{÷Ø·oŸHYóæÍqïÞ½J…øÐ' IDAT»ªÃ»dõ¯ªtuuE‚ÿž×ûðáãqX,V¥3UÒÓÓE~n*áw¶´óO›6 ;vìÀáÇáéé)qYtGGG$''Wª?†³³3îÝ»‡[·nÁÑÑQác$''Wª!„Bê ÕžÊY P•®(ǹsç0räHŒ5 QQQ‚`ƒ,eØl.Ê9¼À°O™>\°¹Ìqµ^½z‰ÌeðæÊ‰ŽŽ<666Ì«S\T$ÔQäÃÇëׯhÒ¤‰Ä:FFFxúßSÁ*\ÿý÷ŸHù®]»àää„;wJl¯¦¦///L˜0r÷M˜©©© (•““#w»)S¦àÝ»w5jvïÞ-د­­: $$mÛ¶…ŽŽŽÔú¤n L’““ƒ€€üòË/صkD&ž;w.¦L™‚k×®¡¨¨>ö*MU‡wÉê_e'îÔ©ÂÃÃQXXˆôôtH¬×±cGDGG3f–6kÖ 23O% Bvv6rrr„1cÆ(t~'''èêêbéÒ¥1b„Äs <‡V¸o{÷î…££#¼¼¼ÀøEƒ,‡ÂàÁÌ_ÑD΄BHýöiNŸO›²3}^df‚ý19¥ÞgúhkkcÓ¦M†ššü·£¼œ6—‹'ï±üx*ö\x (c³y›‹ÒræcL™2;wîį¿þŠ¢¢"¤¤¤`ùòå"J\]]qôèQ!>!Aá (…mÙ²ï߿ǡC‡0`À‰uÜÝÝñðÑC”––bïÞ½"©ö=Â7pàÀ\½z?f<×ĉñþý{± –<ú÷ï}ûöáý»wؼy³Üíîß¿!C†ÀÉÉI°º Ÿ««+öìÙƒ¾}ûÊUŸ¨>Êô!3gÎÄäɓѵkW899aâĉ"ùΙ3ßÿ=fÏž 333¸»»×jƆ¬þUÕ¶mÛpüøqÃÃÃCbÀàMh½iÓ&hjjJ N¬]»3fÌ€–––ÄÕ»*þ,쫯¾BûöíÑ¡C4kÖ ‹/Vøü¾¾¾(((€»»»Äþ{{{ãÆxðàÄr&ãÇÇ›7o555‘L-þ ²®ñþýûHIIÁðáÃ%ž#??ЪU+…úF!„ÏÉÇ9}8Á¦ìLŸ¿þüø8]±†Òz¡"zõªÜ°žR®ø_ZÞý+¹oòáæ`‹ào\Àæp. åR2}š7oލ¨(¬\¹óçχ™™æÏŸ~ýú ê|ÿý÷˜;w.V¯^ '''lÚ´©Rýxó-téÒ...ØÈ0‘å?ü€ÀÀ@\¹r-[¶ÄÆe+V¬À¢E‹ ¥¥…E‹aùòåR3dÖ®]‹‰'¢wïÞÐÕÕ•»ŸóæÍƒ¯¯/¢££±dɤâŠ{’Vµ;v,ÆŽ[[]!Oÿ0fU\I«âÏ:u[J\Ò±¥s3fŒÄ€‘<M ,À‚ ¤Ö‘u~###xxx0þÐÓÓC@@€`NiýcºgLdÕ D`` cpll,ttthõGB!¤ã¿}¢Ü,à^}ú¬¹ð‚>§ãOJç"6›°ÐÕG𤞀væ&`syñ<‡÷ÒV]»âĉŒåFFFŒ•ŠÁY§M›†iÓ¦I=N£F‡níÙ³Gðsï޽ѻwoÆs¼ Ó… $Ö‘Öׯ Þ@çåå¡aÆRÏÃ7pà@ 8PðØ××Wðss++±¶ÒêÕ§h¦O;‡NÊî2!¤‚’’üôÓO˜þËì©ÓäŽ [½z5/ZŒìœl8::bƒ„¡hQQQX·n¶oß®„U@™>„(WeWüªîcB!„Q4¼«‡þ¦ì.(DÚ°(U3`ÀƉ¦ùf̘3fÔRˆ*¢LB¤ž”¸*Á•Ê.é^]ç€U«V!99YdNŸºDZÿ+{kƒ§§'\\\‡×É*'„Bê…ÇEþž+ùoû›7ùàÐê]„:ŒVï"D:E–——uež¿°°¯ò±”AVÿU5àð<GQQQ¥Ê !„ú€¿NH—«ìµ»xû¸‡w©AÉ!„Ê LÂ'ip"?U¿qqqprr‚È~á%Øõôô`oo•+W¢¤¤¤Vû'ëþ1õ_ßCIìììàä䄸¸¸J•B!õ‚ ÒÃÚ”;©O¯>}aÑÜ ï’©p3÷r_e¡¬¼\ÙÝ!¤Æ°ËÙ0A3ewCn4§!õÃÉ“'áãã#±ŒŸ%S\\Œ;wî 00/_¾Ä¦M›j³‹RI뿲ñÀÕÈ‘#qòäIŒ7®Rå„BÈçNÚÚ®”ž|¢§¯‹œ7/PÐG¦™—ñ¶0­íÚ@G[[ÙÝ!¤Æ”•–#3ñ•²»!7Êô!ÂT«sþy7ˆŒŒøùù¡¨¨{öìÔ9xð Ö¯_ÀÈÈK—.•{µ'‹œ;wsæÌÁõë×ñÇ 44þþþç‚Qd~Y÷OÖ=e±XǪU« ¦¦†Q£FaݺuЖóoe—.]Š~ýú>|øKKKÜ»w¦¦¦‚z©©©Xµj•ÔcéêêÂÉÉ ûöíC×®]å ú”––"((û÷ï—ËÅ¢E‹0wî\Áµ²Ùl¬^½;wîD~~>† ‚­[·ÂÀÀ@pýÂ÷‚¯â½bê¿2^³•áì쌕+WVºœª|„BH•ðÿƩМ>Â(è#óŒttìÒššš`s8Êî!5¦®½¾)Ó‡'ª:Ñ0Ó±¥Ù¶m¾üòK;v \.‰‰‰øóÏ?å›7oÆÏ?ÿŒÈÈHtêÔ ÏŸ?GXX˜BK|ûùùaöìÙèÙ³'Î;}}}Œ;þþþrƒ‰¬û'OÈÅ‹ñ×_ÅbÁÏÏ¡¡¡X¶l™\ç÷õõETT” ènݺ‰| ;;r“£Àï±ÐÐP–,Y‚ˆˆò¿þ˜ú/ÏýUÈÊʪt9!„ò¹ã¿ à½P¥É“yAáL%Å ¡¡¡ÐIBꢺö§LRUUÍ|ª4ÔL©z –¸ŸS·ÍÛØ\æ7ÇZúÆheßY‘ó$¶åoðïa‰›´vµ¹¨öcªÒõÑ&´Õ± ¢™>äóÕ¬Y3$$$€­`¶—ËeÜä‘““ƒ€€üòË/صk››+(Ÿ;w.¦L™‚k×®¡¨¨>ÄôéÓÅŽ#mÉli:uê„ððp"==ëuìØÑÑÑŒ÷§²÷‚‚‚œœa̘1 ßÉÉ ºººXºt)ã°¬Áƒãðáà ÷éþŽ?óæÍCFFrssÅ2„¦M›†)S¦àñãÇ())Áµk×0dȱãȺUí¿²:tƒK~$Oye_ß„BH]Àæ°Áe±x™=,–`ãà²X`s”?š¢Þ}’’’ÏXÎá°%nå\8\¶[YoÑÑÿgl»-}ch꣥}w<ÝÄx iÇW•­.ô‘¶ê}¾ë Êô!|k׮Ō3 ¥¥U«.gΜ‰É“'£k×®prrÂĉ1sæLAùœ9sðý÷ßcöÿٻ︦®6࿦Xe TQËP«RE¨Õ C´ XQÞº'e8J­³Ö‰àÄZ«b­mÅ…[«¶ˆ»ÅÕ*¢TÅ‚ Œ$ï1WB6À<ßÏç¾&÷Ü{Îsïõ­ÉÉsΙ0–––èÕ«W•fD$$$`Ïž=055…‡‡‡Ü@<¡ô²eËÀãñäÞE÷¯ì—uE_Ü»té‚V­Z¡uëÖ°±±Áwß}§qû¡¡¡ÈËËC¯^½äƈ´´4ܸqCþ¨ ˜˜8::¢]»vøôÓOÁçóÁå¾K€G÷îÝáçç‡ `üøñ:t¨L=ªþþ)Š_û[ÝTÅpýúuœ?rÏWUž›› hÞ¼yFM!„Ôy/ó`h`2? âUÞK-F'Ž£Îwú!<<óæÍƒ¼L¡PP(³• …"…²¿ ›;‡­Û 4õ\ŽR#÷|ÉPEe’mÆÈù¸øûU„B¤¿ˆÙa Ù²ë—nabÐ4 hûþç6G’O²e}¾Äá]'0¸c(w Ź#ç‘~ê2þç6_´Œ3‡þ”:öÐöcúl¦ÏÄó'/äÆ˜ŸW€¹ãc`ûá˜36¯ò Ù²3‡þÄ-£_‹Á˜à?×Ò2^S‡/U^Ã(dg>„@(DvæCŒòˆPyÍ´U~«M(Ó‡H 4YYYïuÒØ;wbþüùìû Èdt#==ùùùÈÊʈ#dêQ”]TvŸ¼×ÎÎÎHOOÇ›7opóæMÈ­ÇÅÅ …rËÝ?u2 &Mš„gÏž!''+V¬;„KUû&&&ððð€ÁÛLå"** ÑÑÑRûÕ}ÖŠb×ÕÕÅ’%K““ƒœœôë×¶¶¶l9‡ÃADD®_¿Ž×¯_ãÂ… r;7TýýSE2̪’ª¢££ ###¹ç«*OJJ‚¾¾>vîÜYå±B!ÚÂårÁårÁãrqþ³057‡¹…»™š›C(*EzÚyðtxàò¸R?.½×xµÒj âáá;v`ĈøçŸ°lÙ2©/"¡ˆæTVÉÛL@v¸›0Á%BFîùýœ‚åîOþ{ `è¤`ÄOZ‰ù[gbÓâŸ1yÉ×l}ËbVcPø¸twÆ©}gñã‚-ø¼[Ç­«ÿ`Õ¡x\>s?/ßW~;¬Ü‹+gÿ¢ÈeØqå'öØkiH<ºÇvŸÂ¦Å?cÜ÷¡e®GÜÞÖ¥Û4&Q±ãq|÷il[± _Mÿ²¼(rFÄ„À3ˆ?¤cù·k°òÀb…×­ê>ëÚO_Aï/{áÒïWñY×6 „*¯™Tœ²¿§5eúRûaÍš56l˜ÒãÔœYSC† Á´iÓ`ii‰™3g¢_¿~ÕÒNuÅ_Ýöïß_©òõë×cåÊ•pv¦‰ô !„|88x\.ŒëÕ˼<;|†#^1Kœ8+Ξåqy033AÑë7Z¢*ÔùNhß¾=Ö®]‹€€¬Y³†á@Ê^0€Üa/xD2KÞ D"@Ä@ÄàmFâa3;¯ý$w¿äk;K8}fiÃ~@ëN-aù±9[¶ä×yìñÝý:cå´D©¶Œî =\z:cQä2ÌHœ ]}:ð?ƒ Tz8Ï€0èé¡{Ÿ.ˆè#U&yýçÑ ‰†\z:cWðo‰ |Ú¡.ž¾«ÆpîÚ{µWzݪ®á³®mpxÇqxõÄå³×àÐB¡@å5“ŠßÇÚ3ï­ÞEHí§¯¯=z(šVݼ¼¼ÀçóQ\\ ???Ìž=[+q|¨.]º¤í!„jÁãñ`dh}J00RC¦¹<¸\­þÀÎjÔÄÒZqáÂŒ5 ^^^ c÷{ûõÁí=7 (ó€ø¶þx’¶MìPœ±æ®Cñ,¿Xª¾RÀ0B@Ä XÀH_ž²2 ¯A½áÿ Âç…IŸÿâï8Ž»7î!óF–L}FõÞ¾»¤m=©ò²¯Z4„@ „ž¡ò_¼’{Ü‹§/0Ðy8»ŸËã²eãçŽBÜÄ•˜;6:\Ì\ÿ šµ´SyÝŠ®¡E;¬œ–ˆ7¯‹qëò?ÿC(¡Êk&'¾:ÚCm”éCˆvUÅp$m i*+$$!!!ZB!µ“®žttt ½ÀÃHwúèp8ŠDòßop I?@ŸÓçðáÃ0`ˆÄÄDÙqé  Ù ^ÿ³NÇëÄiÍåû"B T(‚@Ä‘:¿|]ŠÊÊn’ÃÑÙû’R¥ö/ŠX†‚ü|îï†)Ë¿–ª˜VÔVùc_<{ ¡PˆW/_¡éGr3n`Œ-ikñóÅõøùâzlþs [Vï##LOœŒ §Wૉ_bÁ„%j]·¢kÐáé ©Sl\˜„ímÀåqU^3m•ÝjWï/ÍéCHÕ¨é++i+>¦Ü‡6eæÎ ___…õÔT¾¾¾˜7ožê !„"—d¨—¢M[Cº¤bÔvÚ¦§§‡eË–!&&FîaBBz5î‡''ò}+|ñikX¶o…''ã`ñ‘.6·*‡@ îð D(.{~ù P\&Ùîÿû7.ÝBLB$þ>îf¿+ûç:z¸À¾M3ü¶ñ€T}åëVööl؇‚W8þëïhßÃYîqÎ][#ëŸ(zS„Ã;cúÐز‰ý¿ÃÙCBĆõ ‘ÿò•Z×­ìÚti…#;O MçVjO[å·Ú„2}©ÚζQE[ñ©;¹rAAâãã§°žš*..qqq(,,Ôv(„B©&u~NŸîÝ»+-×Ñ‘žˆùuöŸ¨oÕªÌû?ÇN]{Ä î P$Τ1(q”Žßâ2JîþM®l‰ßÀÑáàËñزx;¢ãÇF~÷?$|·o ‹à=Ø€ôd¼åÛUöÞ¼‘)Æ÷ž„–.N›9Ln=ÆôEâ÷›‘~V["lÖ»ãFLý6ÎOBÂwë†ÁøBÙ²ÿuÍ^Où:•]C›ÎâûܺcKµŽ'•#kÑà.šÓ‡UÊf˜èêê¢Q£FðõõÅìÙ³ajjZ¥õÂÆÆþþþøöÛoabb¢Q=5¹cD•ääd¸ººÂÑÑQÛ¡È(ûŒäÝcGGG¸ºº"99C† yŸ¡B!ä=yÛéS{?lU•){áí×Gf?GG‡’”•ƒz6âá_³'‰;‹êYá~J â#Æ£¥•"ñÝd„âÿ)2ìùåm<— 0É9Q‹Ç²ï[vpBËNlY»ÏÛ¢ÝçmÙs<ödË6žKjWÕ{Ï/ùðü’/Ó~Ùã ê |Á»9Ê׬eÌÞô­Ü²òm•-Sv ¦V&ì=RçxR9Baíêô¡LBT“|Ñ/--Å£G€àà`:t¨Jëóæ îܹƒ… bÀ€8zôh•Ô_ìÝ»AAAÚC.ÉóQ6ÄlÀ€Ø»w/uúB!ñç€:?¼KæÝЗ¼Ñ q3ä¼ÂôE§Pó 7ƒ(ï_8Y˜A(A(A$±óú5øð~b,**Æùã¡ÃÕÑú5Ó¦øïBmAsú†a°k×.8::ÂÀÀ...¸|ù²ÚåÕm&„™Lö ]‰¦Ã±Ø& ;ÿ`Ë%ž¼‹m°Èb$RÆ$¢¤°kŠä!ËeêÜ5xb­B5Ž…ËåÂÖÖS¦LÁï¿ÿ@õœ5ÅÅňˆˆ€¥¥%,,,°téR…Çêëë£eË–ˆ‹‹Ã¹sçØý[·n…ƒƒôõõÁç󑙙ɖ•m[^,ªâ+((ÀèÑ£aii KKKŒ3Fj˜’:Ï_Y|êJOO‡›››Ì~MæÒ&777¤§§+,¯ ×@!„Åêüð.Utx\vøPvæM|ܽ't,ê#t|t,lÁáé";ó&öÍ÷èÂÛ9²ß&Oé0L­~ô>bLýù(~ݰa3‡ÖŠ{R׈jÙ3¡LÛ¶mCjj*ÌḬ̀xñbŒ7gΜQ»\e_t5ŽÔܳ-Úê…õnÓp0ò'´ìß ðûü=8³è7ø¯ ž.v ^½ú†ðX0VÎvxrýL]Oþ¾+g;µÛ–(--Åÿý‡Å‹ÃÅÅEê]ç¼yópûöm\¼x\.£GVXqq1|¨í0!„RM¨ÓG=}=”””@GGMøQøc“x¢Æ†2výhÂB»zŠ?ÔÕôáGkNÄ¿—=ñá9Hüe ¦ß“º¨¶=šÓ‡@|||(S“&Md2V”=ÿªŠÏÊÊ ÙÙÙ°··¯pЍšˆ¹*dgg³g„BùðP¦ ìºáƒ?óê!„¢Ú• Aˆ&¥µ«Ó‡2}Hu«ªá]ŠÔ·1Áóã›Ü¡ßÀHªLÒ±sqý1ØvrD"\ZLªL\.Mš4Á÷ßÏfî¨bccƒ»wïÂÉÉ pïÞ=¥Ç·jÕ ëÖ­CXXz÷î   ÄÄÄ`ÇŽhРrsså®ê%Þ¥é0(+++dee±-YYYu^¨ŸÞ¼y}}}¹õ¸¸¸àÌ™3ÕÒéó>²lΜ9Ãù#„Bȇ‡:}T0à¡kSwm‡AHµ+..Æi5‡}Ô”éCª[uánûUŸþ NýŒÏ§÷GÞýgø}þ|±iضm†ªvÛ5ÉöíÛ¬°\ÒGü!„Ú‰Vï"„ÔJ´z©íº~Ó=gáÆî4,2‰ƒ–ÂÞ·€á0°lÝ%…E°ëÑ v=Z¢ôM ,[7ÃQ?#F²ò’dõª»wïbÛ¶mReå_KÄÄÄÀÑÑíڵçŸ~ >Ÿ.WõoEÑÑÑˆÅÆccc¸»»£oß¾r_¸p!ÆŽ ]]]¹«w)ŠoÖ¬Y033C›6mЦMXXX`æÌ™jßuã[¾|9–-['7)00iii¸qã†Äÿ IDATÔ~Uñ¿ªb¸~ý:Ο?€€¹çK†½5oÞ¼z%„BHµz£o!µ eúe+>©S^Ýfж+}¯ÃÓÁçÓûãóéýåž?ò”ž¯ŠªkUU®««‹%K–`É’%Äs¿ÄÆÆªddd(ŒÃÐÐQQQˆŽŽÆ¾}ûÔŽÿ}PCtt4¢££add$·<)) úúúR^B!¤v|  á]„Z‰æô!¤ú 2Ó¦Mƒ¥¥%fΜ‰~ýúi;¤I¡o5‘ª ½×¯_•+WÂÙ™þûI!„ÔVÔéSA©Ë»(-÷œpö=EBHÝD™>„T?///ðù|ÃÏϳgÏÖvHä=ºté’¶C „BH%Q§O „ |¢ÎË-»}pR—wQÙñSv)ÙòŒI“&!-- ººº2å%%%èܹ3¦M›¦pþUž>qqqrËk„ĊÄÅÅ!..………ï½m‘HT%÷¦¢uTUûªžehóùB!D¬Îwú!<<óæÍƒP(Tû¼R¡P¡PöC—¹óxغÍ@SÏå(U’¤Žœ>}pìØ1 6Œ-³µµÅ¶Ÿ†““ñôéSâIôôôpäÈ©ºŽ?¡PÈfù¼ÊÏGhh(Z´h‘#GâÕ«Wì±yyy9r$ìííáîW®°m–ý^¼x¡C‡ÂÉÉ Ã† ÃË—/¥bLLL„———Üë+[Ï¥K—зo_888 ]»vl¶R×®]qïÞ=À½{÷еkW¥Ç“º2}HMW6ÃÐÐNNNøþûïQTTôÞãP&99®®®ptt|O©çÈ‘#ð÷÷GÆ add„–-[böìÙRŽŽŽpuuErr²#U®&gJÕûükÃó!„B>t@¼b{Íý¯zyxx`ÇŽøå—_Š‚‚µÎ+)“éSZ®¯H(@(J„Ê?ìÙÚÚÊÝ$¦OŸŽ9sæ ¨¨sçÎÅôéÓ¥Î?÷Ç8þ<¼½½1þ|☑‘‘X½zµÔ±«V­’ÊòY‹èèh\»v îîîì²¼ðÃ? _¿~¸žq‘‘‘ˆŒŠðn8VÙaY±±±èÞ½;.\¸///,\¸Pª]===lݺUé}€¨¨(„……áÚµk˜¤6dc<{ö ›6mBjj*&Mš¤í°¤ìÝ»AAAÚCÆŒ3ðÅ_àÊ•+xñâöïß{÷îáË/¥;q €½{÷j)ÊÚ¯ºŸ?=B!D;$}ÓÚ·oµk×âСCX³f »ÿ@Šâ)d¡|‚@$‚@(î *(ïôQ5§½½=\]]„nݺ¡iÓ¦RçGFFÂØØýû÷ÇÑ£GÙý^^^ÈËËc3t®^¹‚'OžÀßߟ=æÐ¡Cøä“OÀåráéé‰û°eGŽ»»;¸<.üüü¤ê.ïèÑ£ „‘‘üüüšš*UîããSSS¥÷g"ùøø@OOýû³ÃÈø|>N:@ÜéÓ£G¥Ç“º2}È!C0zôhö}XX˜Ì¤Ã¿üò \]]Q¿~}ØÙÙaÆ ï;L€\]]±uëVlß¾]­sŠ‹‹KKKXXX`éÒ¥RY#?üðš5k†† ⫯¾’ÊØ,;ß‹²ù_ÒÓÓáææ&³¿*猩ˆ3gÎ`ذahܸ1x<ììì/“Åêææ†ôôtëg„‰‰ fΜ‰Þ½{£aÆì&ò®[“{¡êþ«º¿ à >>æææ°´´Dxx¸FYbíÛ·—ú÷øÍ›7033CNNŽÔqÊžÿ®]»àè踸¸àòåËj—K¨z>Úü;F!„ÔÔéàÂ… 5j¼¼¼ÆîW6¹s‰ƒR¶sGº×§TDB…"«èôQÇðáÃqá >\¦ÌÆÆ`llŒ/^°û†ADDV½ýðºjõjDDDHÍå“““;;;ØÚÚ¢mÛ¶øïálÙóçÏ¡¯¯¯V|?F½zõˆ¿ØH†™I¨Óá¹¹¹Xºt)BCCÑýóîìþÎ;ãÂ… (..Æ… Ð¥K¥Ç“º2}HBB>ŒÝ»w#99GŽABB[¾|ùrÌ™3ñññxøð!<ˆ³g•¯ªXVÙ/åå·ŠÒdñ¼yópûöm\¼x×®]É'¤Ê—,Y‚ãÇãØ±c¸sç¸\.¦M›Æ–—óEòZÞ0=‚µµµÌþªš3¦*¥¤¤°ÿÖÖÖxøða…ê Ão¿ý†Y³faâĉؿ?,XP‘ª¾ÿêÜß'NàêÕ«¸rå îÝ»§Ñ¤È¡¡¡HLLdß§¤¤ cÇŽ°°°:NÑó€mÛ¶!55OŸ>…¿¿?ƧQ9P¹çC!„Ê«ó>‡Æ€0pà@$&&ÂÈÈH­óJ„ J…⎟²Þeúˆ Uþoذ®®®X¿~½LÙ³gψçà)¿ŒºîܹƒË—/ãÖ­[RY>`bb‚Ì»™lvÑÝ»wÙ2sss«Ÿ©©)ûëòëÂB4hÐ@ª\Ý/H#FŒ@~~>ˆM›6±ûõôôкuk̘1-Z´`;£OêÊô!õë×GRRF1cÆ`ëÖ­066fË—,Y‚ 6ÀÍÍ FFFprrºuëÔ®¿ìõò›¦^¿~´´4£ÿþj³yófÄÇÇÃÆÆ–––2Cg±fÍØÙÙ¡aƘ7oÞ=wÊŽ;)5¹²ÜÜÜбcG@·nÝàââ‚ììì*«¿²bccѨQ#XYY!66IIIjŸ;xð`=z”ÍìIJJÂ!C4j?>>Mš4‘‘&Nœ(“É£ª\5±s‘Bù¼]²½î¦ÕêééaÙ²eˆ‰‰ÑhE«ÒR‘wò^aÖžtl>~ƒ-Ä>BÅ¥•‹ïöíÛHKKömÛpöìYüûï¿Rå+V¬À«W¯°}ûvôîÝ[ªŒaŒ?#FŒÀøñãe®¯W¯^¸uûŠ‹‹±eËôíÛ—-óôôÄÙ³gQTT„ß~ûMj™v‡'Ož°ïù|>víÚ…ÂÂB¤ìÛ'ó+¬º®_¿¸ººÊÌGÄçó±yófôìÙS­ãɇ2}têÔ Íš5CóæÍÙ/ïYYYhÕª•–"“d™šš"$$½zõBll¬Zçfgg£I“&ìûÆK•geeá“O>aÛ°´´”¬.++«jë訊쨒’Lœ8ÑÑÑØ·o¤Ê³³³aeeU¡ºõôôÀãñ¤^—””T8ÖªVö™7nÜX£çdllŒ€€üôÓOÈÍÍÅéÓ§¥þ—PöüËÎ1hhh(³ —ªr rχB!GK¶¿Õ½{wøùùi|^±ˆ@üú¯«Y8vê ÜÛ8 fpW„’L¥*2}TMä<{ölL:ººº˜:u*fÍš%u~ãÆÑ¾}{¤¥¥a²œÉA}}}ñÙgŸÉý ÷Í7ß`ñâÅhݺ5’’’°hÑ"¶lòäÉØºu+Ú´iƒ„„,[¶Œ-óööf‡XÀ”)SpâÄ 8;;#%%Ejx¼ëU$..&LŸÏ—YEÄýíäÍe;””O>|”éCqöB~~>òòòd&Œÿøã‘‘‘Qẫbx—$‹¡°°7oÞĬY³Ô:kcc#•)YÅPÂÎÎÏŸ?—Ê@Hþa*wÊ2)\\\pæÌ5¯H3•ÉŽ€ÿýnnnÈÈÈÀÅ‹áââ"sÌ™3gäî¯,©NŒû÷ï+<îÍ›7 ëQuÿ•ÉÊÊ’zݨQ#Ú5jÖ­[‡;vÀ×׆††2ÇTçóªïùB!D=u¾ÓGBÙ¤Íò „BÀÚÀ1C»!>“ƒ»B "ñ ^B‘Péê]Š&q.ûKíæÍ›Ñ½»x¾šÏ?ÿ\fÓ¨Q£póæM¬_¿õÊ kàp8X·nÜ,¦ `ýúõ¸yó&8 õëiýúõ‘˜˜ˆ›7oâàÁƒR¿–'$$àöíÛì{lÚ´ ·nÝ–-[`bb"uå¯Yoooœ|”éC?~Œ¨¨(üøãذa¢¢¢¤&©ˆˆÀˆ#pîÜ9âÖ­[3fŒÚõWåð.eu$…„„ 22<@NNbbb¤ÊG…#FàßÿEQQÎ;'3ŒwíÛ·On‡ôéÓ;v쨚‹©B[¶l‹‹ üüü°oß>˜™™É=nûöíèÓGñ|Í4rvvF\\ ••…¨·«X–×¶m[lܸQáýUuÿ•™|¸¶Ã „B>h”éC©•(Ó‡Ô!!! ÑvD ªbx¶‡èB!Dû¸PÙÏzúÐÕÕUZ^ÑzkÃy„|ŽŽ¶CÐÍéCêºÊ,^ÓÌ;gΜ‘šS¦*øúú¢k×®µvø!„BHEˆØÿ¡á]„ZŠ2}ù0 >>qqqU^w\\âââPXXXåuB!„ÔÔéC©•hN"ñ¾—¯ií«¢íøTµŸœœ WWW8::VyÛŽŽŽpuuErrr•×Mª†³³3ìííq÷î]m‡B!„|¨Ó‡R+Q¦!†½{÷"((¨Úê0`öîÝ[mõ“ʹrå &Mš>Ÿ_«W%%„Bj*êô© ½‹>SºBªeú†aØ,Éë÷™ÕRÙö/]ºooo˜™™AOO...صk—TýòÚ,kíÚµ077‡……Æ7oÞhÃ0ˆEãÆadd$3ÄjëÖ­ppp€¾¾>ø|>233¥Êù帺º¢~ýú°³³Ã† 4¾?ééépss“Ù?dÈŒ=š}&3©µ²ö%ÜÜÜžž.³_^œäýãp85j"##ÁçóñèÑ#m‡D!„|P¨Ó§‚B^ér·fNÕêø173U¸UÔ¡CÑÂÉÅÅErË‹‹‹Ñ¦õ§Ø½»â©î999>·üu6kj‡/¿ˆ;wî¼—¶É‡ƒ2}ˆH$b'2–¼Ödbã²å·÷Ñ~@@BBB™™‰—/_bÉ’%Ø´i“ÚçÀ¾}ûpõêU\½z÷ïßÇœ9s4ŽïðáÃ8zô(233qðàA©²ääd¤¤¤àùóçðððê„Y¾|9æÌ™ƒøøx<|øÄÙ³g5nÿÑ£G°¶¶–ÙŸ€Ã‡c÷îÝHNNÆ‘#G vûÖÖÖxøð¡Â{H´‹aŒ5 !!!pwwÇÓ§Oµ!„òÁ NŸ·úõ×,µ\ Rü¥@×ÈÍÕìøyòô™Ü­¢¼¼zÃÚÚ¿üò‹Üòä]»P¿~}ôíÛ¯ÂmtëÖµÂçï®ùqÎ\¸x -[´Äðáê½íÊÜWRóP¦©¬²å·÷adddàâÅ‹ÈÍÍE—.]ð믿jTGll,5j+++ÄÆÆâçŸÖ8ŽÕ«WÃÞÞæææHMM•*Û¹s'`hhˆððpœ>}š-[²d 6lØ777ÁÉÉ ëÖ­Ó¸}Eêׯ¤¤$Œ=cÆŒÁÖ­[all\åí¿ÏgNdq8ܽ{ÑÑÑðññ‡‡rssµ!„òA¨ó>'NœÀo~È€R¡ìvñáK´½Q ' kd ž‘)š9uÂö¹.Õµr'Mª„™±"‘+W®@ôĉàp*þèŸ?«šÎ‡ƒ† bò”)¸Ÿ•õ^Û&µeúÚnÿþýxôè¾þúk4oÞVVVؾ}»Fu4nÜXêuE2Zìììäî¿xñ"<<<`bb†aP¯^=©U°²²²ÐªU+Û+ÏÊÊ ÙÙÙrË:uê„fÍš¡yóæèر£T™ºígggÃÊʪÒq’ê!éô)..FVV¦OŸWWWôîÝyyyÚB©õ8À€a×p¯kŠŠÞ`ìØ1˜óý÷ …jŸW*` Š ÊþBhî<¶n3ÐÔs9J•d©ãË/âäÉ“€#GcÈàÁïÚ13EÒ–-hj×}üüØtèÞ½{COO©©‡¤ê:zô„B!›å“ŸŸaC¿BófMñÕÿBðêÕ+öØ—/_bèWÿCãmѽ[W\¾|™m³ìŸ››‹ÁÁÁhj×CÆ‹/¤b\½jzöè!sm"‘/_¾ÄŠåËÅîïÐÁY÷îîÞ½‹.;)l[Ù5”Wö¼ .ÀÇ»7š4þŸ¶jÉfF¹vè€ÌLñ "™™wáÚ¡ƒÒã‰öP¦‘`¦B™•ÞUÙö%™)—.]B^^–.]ŠqãÆ±åR,÷ïß—©#«L‡yVVlll4ŽOÑõáË/¿Ä;w ‰ðüùs©ò?þŠ/PÍö]\\pæÌ¹eIIIÈÏÏG^^¶nÝZ¡öÏœ9—÷ÿ Q‡ÃP(Ã0(..Æÿý‡ à“O>¯¯/ ´"!„R;½ýüUç3}¼¼zc÷ž_‘”´C¿úŸÚ.JÊdú”–ë+  ¡ò/ªæô™=û{Ìœ1EEEø~ölÌþþ{©óÏž=ƒ+W¯ÁÏÏß?€øöÄI“°rÅJ©cW,—Îò™?&Ož‚›·nÃÃñ‹½kwÖ,âß;w1qâ$„OàÝ©²C¥ÌŸ=z௿3àããƒysçJµ«§¯‡»vÊ\³…¹>iÞ .€……%[Þãó8|ø0àè‘#èåá¡°me× Lø„ñ;vnÝþß~;Ó§OôêåŽãÇgõêå®ôx¢=”éC$lll°oß>Ϋªá]ªÚWÔ‘äéé‰àÕ«W(**BAALLLØrgggÄÅÅ¡  YYYˆ*Ó9.1yòdAH A w• ”T5§ƒƒ:uêˆ/úõE÷Ï?G³fͤΟ8i2êׯ qämG øøøàeÞK6CçòåËÈÉyŒ~ý¾`9°?ìÀåráíã”})lYjê!xxz‚ÇãÁ¿o_œ:ý»Âk8|8‚‚`ddÿ¾}qðà©ò>}üajj&sÍ9OžâŸï`Þ¼ùX¶t [Þ“Ïg³”Ž=w÷^ ÛVv Êœ9{~}ú@OO‚‚Øac½zyàÄÛNŸ“'N€ïî®ôx¢=”éC$.\ˆ±cÇBWWW+_Þ+Ú~dd$,X3334nÜ»wï–Z½+!!{öì©©)<<<0hÐ ™:ºvíŠV­Z¡M›6øøãSeñmܸ111066†»»;úöí+UŽ)S¦`„ °´´D¯^½äfÔ¨j?00iii¸qã†ÔþqãÆaذaèС\]]ñÕW_Iu<©Óþõë×qþüyȽFɼ1Í›7Wï¦*§££‘H.— .— @€ÜÜ\¬Y³ à ÅÅÅÚ•B©•¸Ú &8þ<†ý ÞÞÞ7n<»_ÙäÎ%BJE"0"@ÄH÷ú” †"Å*:}Ô:* ];`Íšµ2e’TþúõëKMzÈ0 &FOÄŠ˱nÝz¬X±\f.Ÿœœ4²z—a£««Ë¾~öìôõõÕŠïñãÇìäšxòä‰T¹©©üU³†ÁG}„AÁÁR™3ݺuÃØ1£‘ûü9._ºŒÎ;+l[Ù5(“ûü9~üñG\»v×®]c÷»uíŠ Æ£¸¸çϟǪÕk”O´‡2}ˆÄ AƒävˆÔ”öey{{ÃÛÛ[áyÎÎÎ2K—­Kò:::ºÂñ)ËjòôôÄ_ý%µoàÀRƒ\áöÀÐÐQQQˆŽŽÆ¾}ûØý;wî”:nÁ‚2çªj?::ÑÑÑ022’[ž””}}}™¶ÈûS¶Óÿäp8(--E~~>6n܈   8;vì`#„Bˆzê|¦Ï¡CñE¿¾}ðï?ÿââÅ‹¸uó&¾øBú—Nü÷ð›y“ýß» @-,,ÔþUÍÔÔùùùÄÃ4h U®ê—å‚‚4lØ}ollŒO[·Æâ¸ÅèСƒÒŽe× LÈÿB——‡AÁÁøyÛ»ùyôôôЦm[Lýv*Z¶lÉv|):žheúòሉ‰‘êð©*û÷ï—›ý$±~ýz¬\¹ÎÎÎUÞ6Q‡Ãa;}$C¼$Y?¥¥¥(,,DRR2331dÈZmBQƒä_Ë:ß飧§„„UønÚ4V´*-e ‰p'ïfíIÇæãïÒÒq‡P Bqiåâ»uëþøãO$''ã÷ßÇ?ÿü#U¾tɼzõ ?oû>>>Re à ""_ý/á_-s}žž^¸uë&Š‹‹ðÓOáãÝ›-ëÝÛ¿Ÿ>¢¢"ìÙ³ÝË,•Îãñ¤æUèÕË;¶oGaa!öþöÜ߉RÇógϰvíôûâ ©ý={ôĆõëáÞKº®òm+»e®gdà‹€tìØ +V,—*ëÕË7þ(5¬LÙñD;(Ó‡RY—.]ÂðáõF¦££ÃþYvˆWÙŽŸ’’lÛ¶ —/_Æ„ ¨Ó‡BÑ@ïôéÑ£üËÍS Žb’9)ÿºš…c§®À½bw…@(ÉôaPª"ÓGÕDÎÓ§OÃŒ™3¡««‡™3fbÚ´ï¤ÎoÒ¤ >mÕœ;‡˜o§ÊÔßÇßíÛ·G@@ LÙÔï¾Ã‚ùóá`oM?mBü’¥lYÌ·ßbË–Ípt°Ç²¥Ë°j[æëç—öíÞÕ3u*Ž?†NŽøõ×=˜5k¶Z×lan†.]ºàõëט:Uúºzòù())‘™ÏG¦άø IDATm%×Pö>–·tÙrŒ…n]ÝЩ…T™G/q›ü2WÊŽ'ÚA™>„RûI†k•ïð‘ü©££ƒ¢¢"èèè`ýúõHMMEQQ‘–£&„BjýÖžÛ•ÎáSž@À@(¬ Œ3´ ¥•"q#ÿ²Õ»ÊNجȶ2C‰zôì‰={J•;cÆŽUx>‡ÃÁÆŸ6É-kذ!6mÞ"·ì£>Â’[–˜¸N꽉©)~þYþ—êòרÎ5⹊Z´h?þXiÛÊ®AY[~~~ðóócß.³âKã&MdÎUv<ÑÊô!¤jTtÉù÷E[ñ•š¬ªý¹sçâÌ™3Õ2DMe÷Ç××]»vU:ÄMÛ$ûtttجɽ …lçϼyóàááׯ_ÃÀÀ@›aB!µh¡RÍ• áÛ¹{œ,Láda¡P¡P‘PÄÎë#Ôl…\ñ¼@ë׫·zCµT)..FJJ x<^•ÔGjÊô!¤jÔä@{ñ‰D"µÚ.((@||<âââÞCT²”Ҹ¸8¾Çˆ4#éàáp8ÐÑÑaçõ‘tq¹\aÍš5ÈÈÈÀÈ‘#ÙÎ!B!„(&ùýŠ2}*H(b°nž{#EwžIþ”Ìš¤£…åƒk»–-œÐ¶­3¶$%UI}«W¯Â‚ùó‘¸n}•ÔGjÊô!D¹²™*ºººhÔ¨|}}1{öl…«*V´~CCCØØØÀßßß~û-LLL4ª§¦w<)“œœ WWW8::Ê”i’-TáêêŠääd 2ä½·¯I¦¤ÓGGG ðY><þù'âââ°zõjXYY©½º(!„B¨Ó§ÂfÆŸÒvj•ªm2ïeUi}áá_#<üë*­“hŸ¦™>-ÛÐê<¤î‘t4”––âÑ£GHHH@pp0:T¥õ¿yówîÜÁÂ… 1`À=z´Jê¯ öîÝ‹  ùÃÃ%÷GÕ*–ÕiÀ€Ø»woíô‘tðp¹\p8öO@…BìÞ½½{÷F×®]ѰaCÊÜ%„B4Pç'r&„ÔN”éC†Á®]»àè踸¸àòåËj—W·™Lf2AØ3t%˜Çb›0dìüƒ-”pxò,¶ Ã"‹‘H“ˆ’Bñµ±V¡H"»Rà®ÁËkªq,\.¶¶¶˜2e ~ÿýwâû#Ùä)..FDD,--aaa¥K—*ŸÌÌL¶¬lÛòbQ_AAF KKKXZZb̘1RØÔyþÊâSWzz:ÜÜÜ4>¯²TÝ 777¤§§«¬G[š6m ôìÙÆ ÃìÙ³ñìÙ3p80 ‡ƒëׯ£sçÎøè£ «««Õx !„Ú†¼[¿Bj šÓ‡À¶mÛššŠ§OŸÂßßãÆÓ¨\™²_ªËošhîÙÁ{§ ÿ¿\Œ|7Aþïó÷àÌ¢ßÐsö@ô^2é«ãĬ+g;<¹þ@¦®'߇•³FíâLŸ¬¬,LŸ>...TÏY3oÞ<ܾ}/^ĵk×pâÄ …ÇãÎ;˜>}:ø|>»?99)))xþü9<<<0zôh¶¬lû’×eãQߌ3ððáC\¹r—/_Æýû÷1kÖ,©cT=eñ©ëÑ£G°¶¶Öø¼ÊRwÎ!kkk<|øð=DT1 ˆ…ŸŸ qüøq´jÕ ×¯_g‡~ݸqíÛ·‡¾¾>ÛD!„å$ŸªdxWÑ›×)™±¸èÍë ×[Î#äCP\\¬í4B™>âããakk ˜8q",X Q¹2U5K‹ÀŽÐá‰ÿ¹Í{ðnXî•M'-ûw‡+ž˜öïígá±`0¬œí¶â D"â?¯™µ Ooþ‡Oz«?T±ü—c[[[¥7emÞ¼û÷ï‡ `á…سgÔ1<]E)??ÁÁÁؾ};[¾sçNöuxx8æÌ™£vìªìÚµ ©©©°²²,^¼ÞÞÞRÏXÕó¯Îøj mϧdggkkk”””àÍ›7xúô)öîÝ OOOÄÅÅáÙ³ghÔ¨ÌÍÍÙù~!„¢>ÞE©•(Ó‡`¿ÐâɄ˯R¤ªü}àêñÀpd¿¨J:€æ7йõBÄûî‹÷Y9Û¡¸ Y§o ðY> Ÿå#ódJß”h”é#É)))Aff&¾øâ L˜0A­s³³³Ñ¤Iö}ãÆeŽ)))A^^òòòð×_áÏ?ÿd;•.^¼˜˜˜€aÔ«W¯JïÿÇ¥bjÒ¤‰LF‹²ç_UñYYY!;;»Wð~dgg³c5‘¾¾>ŒÑ A˜››£iÓ¦ Š+””„à»ï¾£¹|!„ ¢‰œ !µeúê¦,£ *²#êÛ˜àù¿ñMîÐo`$U&騹¸þl;9".­?&U¦ .—‹&Mšàûï¿g3wT±±±ÁÝ»wáää¸wïžÒã[µj…uëÖ!,, ½{÷FPPbbb°cÇ4hй¹¹rWõ’¬Þ¥i‡••²²²`ooÈÊÊÒ¨sCÝø ðæÍ…+F¹¸¸àÌ™3l5Í™3gØ!}5‘dȤdõ..— kkkèëë£E‹ …hذ!LLLÀãñ(Ó‡BÑ›éCÿ„BjÊô!Õ­ì<3å·ªÐö«€S?$£(ÿ5žd<Àîÿ­˜:Xƒg¨‡ŒÀ®GKØõh…Œ]€g¨SÍçxøð!bccѦMµÎ Add$Zk_ Ã@GG†††°²²‚½½=amm ##£'!„RHþݤá]”º¼‹ÒR½(Ó‡Ôv]¿é‡ž³‚pcw™ÄÎAKaïÛÀpX¶nŒ’Â"Øõh»-Qú¦–­Ë*¦ˆä ½dõª»wïbÛ¶mReå_KÄÄÄÀÑÑíڵçŸ~ >Ÿ.Wu‚ptt4bcc±qãFÄÄÄÀØØîîîèÛ·¯Üã.\ˆ±cÇʬʤ*¾Y³fÁÌÌ mÚ´A›6m`aa™3gª}oÔoùòåX¶l™Â,“ÀÀ@¤¥¥áÆ2eª®!77мysµãV·n¸~ý:Ο?€€¹uT¦ýꤣ£===Ô«WõêÕƒ¾¾>ÍçC!„T ïª OÔy¹e·N@êò.ðœpVieç(ïÁÙU[ÔqøðaLš4 iiiÐÕÕ•)/))AçÎ1mÚ4…pUyòä ÌÍÍ+t®­­­Z×V™6ªŠº±íÐ4Ó§eõ'¿%µƒ¼Œ›ò«?©sNu™)Ú®ô½OŸOïϧ÷—{þÈ?~Pz¾*ª®UU¹®®.–,Y‚%K–Ï «òü€€¶“᯿þ’*8p Ìñƒ  Aƒ4ޝ^½zHLLDbb¢ÜrUÏßÓÓS­ø\\\‘‘¡0CCCDEE!::ûöíÓè’’’ ¯¯/5¡´ºÔù»èèhÉ-¯Lû„B©(Óç-o?Å©ÏòDŠmÒ52Es§Îjeü„T¿!C†àæÍ›xñâfΜ‰~ýúi;¤)&&F¦ÃGëׯÇÊ•+áì\=Òû÷ïW:,¯ºÛ'„Bˆö½íôÑîrÚtêÔ)¤¤¤h|^©ˆPv»øð%ÚŽ^‹¨„Ð52ÏÈÍœ:á׸nÕµrX»v­Ì¯€"‘kÖ¬Á×_ §âý}ÏŸ?¯lˆ5¢ R»Ñœ>„T?///ðù|ØÛÛ£´´³gÏÖvH”K—.aøðáu¶}B!„T£·Ýu>Ó§¨¨ááá˜7o„B¡Úç• …"…²“zš;‡­Û 4õ\ŽR%Aê ÁéÓ§ÇŽðaÃØ2[[[lûùg899!00OŸ> NY×ÓÓÑ#G¤ê:~ü8„B!›åó*?¡¡¡hÑ¢FމW¯^±ÇæååaäÈ‘°··‡»»;®^¹Â¶YöOxñ↠''' 6 /_¾”Š111^^^2×fkk‹¤¤$¸¹¹¡iÓ¦8xð Â6”Åš››‹à³Ï>ÃO?ý¤öyÊb+ßþ¥K—зo_888 ]»vl&U×®]ÙmîÝ»‡®]»*=žTÊô!¤ú…„„ ;;Ož<Á?þcccm‡D!„B4Pç;}<<<°cÇüòË/ EAAZç•”Éô)-×W$ %Bå>¶¶¶r7‰éÓ§cΜ9(**Âܹs1}út©óÏýñΟ?oooÌŸ?€xBÇÈÈH¬^½ZêØU«VIeù,ŠEtt4®]»wwwvÞøá‡Я_?\ϸŽÈÈHDFEx7ä©ìÐ§ØØXtïÞ.\€——.\(Õ®žž¶nÝ*÷úoܸÇcÕªU3fŒÂ6”ź`ÁøøøàÔ©S¸ò¶sJóTÅVVTTÂÂÂpíÚ5Lž<™ýµ›ÏçãäÉ“ÄYc|>_éñ¤êP¦©ë$“÷VvrÛŠž_UíÀܹsáëë[ézÊóõõżyóª¼^B!„Ú¢Îwú@ûöí±víZ:tkÖ¬a÷HÙ«ð@²‰P>AH A w• ”V5§½½=\]]„nݺ¡iÓ¦RçGFFÂØØýû÷ÇÑ£GÙý^^^ÈËËc3t®^¹‚'OžÀßߟ=æÐ¡Cøä“OÀåráéé‰û°eGŽ»»;¸<.üüü¤ê.ïèÑ£ „‘‘üüüšš*UîããSSS¹ç~ýõ×044DïÞ½QRR¢° U±ÂØØ‘jŸ§*¶²Ž?èéé¡`vøŸÏÇ©S§ˆ;}zôè¡ôxRu(Ó‡ÔuUµ||E먪ö ¸¸¸J×U^\\âââPXXXåuB!„Ô\ .Ïè#váÂŒ5 ^^^ c÷+›Ü¹DÈA©HFˆé^ŸRÀ0B@Ä XE§:†ŽnݺaÅŠ2e666ccc¼xñ‚ÝÏ0 """°jõj¬Zµ «V¯FDD„Ô\>999°³³cßóx<öõóçÏ¡¯¯¯V|?F½zõì03 e*fffjµ¡,ÖgÏž±+“X5j¤öyªb++77›6mÂ_ý…¿ÿþ›Ýß¹sgDFF¢¸¸.\ÀòåË•Oª­ÞE$†y¯«rÕ´öU©éñ%''ÃÕÕŽŽŽU^·££#\]]‘œœŒ!C†Tyý„B!5]Ïô9|ø0 €"11QᲦå•"” ÅY=e½ËôA ªü-Þ°a\]]±~ýz™²gÏžÏÁS~‰sܹs—/_Æ­[·¤²|ÀÄÄ™w3Ù좻wï²eæææ(..V+>SSSv®œ×……hРTyU¤þ+‹Õ‚íðzüø±ÚçiÛˆ#ŸŸbÓ¦Mì~===´nÝ3fÌ@‹-ØŽ2EÇ“ªC™>„|öîÝ‹   j«À€Ø»Wqæ.!„Bȇ¬ÎwúèééaÙ²eˆ‰‰ÑhE«ÒR‘wò^aÖžtl>~ƒ-Ä>BÅ¥•‹ïöíÛHKKömÛpöìYüûï¿Rå+V¬À«W¯°}ûvôîÝ[ªŒaŒ?#FŒÀøñãe®¯W¯^¸uûŠ‹‹±eËôíÛ—-óôôÄÙ³gQTT„ß~ûMj u‡'Ož°ïù|>víÚ…ÂÂB¤ìÛÇqªŒòm(‹ÕËË [·nÅ«ü|6ÓFó4qýúuøûûÃÕÕUf®$>ŸÍ›7£gÏžjOªÍéCÊÎ'S•ó˼¯ö†ÁÀabb‚™3g¢wïÞhذ!ûß yuiZ¿²øTÅÌ0 âããannKKK„‡‡£¨¨HíöÛ·o/5Ü÷Í›7033CNNŽÔqééépss“Ûþ®]»àè踸¸àòåËj—K¸¹¹!==]aœïûï !„BÈûTç;}ºwï???Ï+q ˆ_ÿu5 ÇN]{Ä î P’éàTE¦ª‰œgÏž©S§BWWS§NŬY³¤Îoܸ1Ú·o´´4Lž4I¦~___|öÙgr;;¾ùæ,^¼­[·FRR-ZÄ–Mž<[·nE›6m€eË–±eÞÞÞèÒ¥ û~Ê”)8q✑’’‚iÓ¦)¿yj(߆²X###qòäI|Þ£:wî .—«Öy啽ïåÅÅÅa„ àóù2CÜßNÞ\¶³KÙñ¤jP¦);§Œäµ&ØÊvz”ßÞGû†ß~û ³fÍÂĉ±ÿ~,X°@£:*Ÿ:ñž8qW¯^Å•+WpïÞ=&E Ebb"û>%%;v„………Ôq=‚µµµÜ:¶mÛ†ÔÔT<}úþþþ7nœFå`mm‡ª7!„Bȇ„™ýÓ·¢Þí|`(4Dý†Òó«¼~ý Oθz™™÷ЭGèêêÊ=æ@Ê^¥sã(RÓÏ[ü'†L>0@Æ#ñ6-­Ä÷O€yû?›z`â÷©Š+ª[[[©IŸ‰x.¢ž={ʬâUuíþãô‰°³kÂî;yôÌÌLÁãñÀ0ñbŽœ/Ç¥žgùÌ4Ûé}ÞÇÞÞ^â»Õ‡Ü7(Òù„CWP¤ºJøÿsîGKs8ZZ€Ï€Ï@À°y}ø“ª…"}È×ÀÀÀ€}­þ,o'ÃÊfgg'öóóçÏ•®kjjŠàà`lܸ¹¹¹8sæŒÔ¨S+++™íŠF`KLÜ(*€çÏŸÃÊÊJéqB!„|Mj)>„HÃ0Xëáž#ò¿pK4]ÊPáâââ0kæ,¼|õÎÎÎX²dI¹ÚKJJÂâÅ‹±zõj TÚ½‹ #MTÍË"ïxU—‰©Ó¿"FFF(,,d#`ž>}*󸢢"™;.–g|ÙÙÙl¤Ovv6•Ù!QQÿ£GFHHêÖ­ ‰hpvvƹsçØ~4íܹspvv®¶ !„Bª:šôQStìm¡F-=’Ç××W"‰uy„……!,,Lc푊A‘>DÈÆÆ€ŸŸtuu•®§©%aŠúN¶¨ÚŸ““0yòd¼}ûRkß¾=6lØ€ÐÐP©ý«{ÿ¥ùÝV¯^ †a0uêT‰¥YŠúwqq‘‘æÌ™#–ßGT`` ’““1|øp•Ʀ¬”” 2Df¹º!„BHu hfKmB©L´{Z´h ¯¯¯•÷³ŠêÕªUسgÌÍÍáíí-u–/_ŽeË–}^S.Ù¿¬ñIÛÝ«¬®]»¢M›6hÛ¶-lll0kÖ,•û E^^¼¼¼¤Ž¿_¿~¸xñ"îܹ#µ¼´rúRõq8¬]»#FŒ{\ttt…ôðàA¹åëׯÇÊ•+áäD¯„Bù:QNBHµD‘>„T}†††èÑ£‡Ì¥iÚvõêUmB!¤BÕئ!¤Ú HB*–&–ÊQrdB!„í~ £œ>„j‰"}ˆ6(JÔ,«|áÂ…ð÷÷W¹?ÄÆÆª\B!„€–w©mßâÉ-Œ¢qB*Eúꢠ ‰‰‰8{ö¬Êuàææ†I“&ÁØØ¸FG!„B¾fé£&ŸOø%©—fŽß)œ€æ2/ê:rä0Z9:€ËåH-çr¹h×ö[ìÞ¦v999j×-Ϲi‚¶û'šC‘>D¸Í8Ã0066†££#,XGú럶¤¥¥ÁÅÅRËåE988ÀÅÅiiê¿fB!„šKÈW¯ úö¨Òñ<ìûLßÄÍ•œøyýæ­Ô‹º|||ammƒ;vH-OÛµ uêÔAPP_µûèÖÍMíºÚVžû–T-ªFú¯“p«ñ·oßbÓ¦MHOOGTT”¶‡%fß¾}8Pµ÷Q À¾}û48"B!„òµÎóÔøHŸS§Ná½{U®W"`À€½\yñíÇþŽ)«NAßÄz&æhæØ) +`ÔòEFEaõªU 4V®\ˆÈHèè¨ÿп{K'Dû(Ò‡ˆ222‚‹‹ ¶mÛ†””¥ëmÛ¶ -[¶„¡¡!<<<••Å–a„ hذ!4h€„„±ºŠÊ….]ºWWW‰Û…QJ¢?K‹úquuÅ¥K—džƒ¬z„B!„ÔøI§aaãð €Ïç+]¯„ǀπÏHL®4p[×¹hÚk9JäD)ã‡!##pìØQü8tè—~,̱uË4mÒxóæ À×׆HO?"ÖÖñãÇÀçóÙ(Ÿ?bÄðahÞ¬)†ý;ùùùì±>|Àðaÿ†Ý7¶pïæ†k×®±}Šþ¹¹¹:dš6iŒ‡Åû÷ïÅÆ¸fõjôìÑCá¹*jgÓ¦èÔÉÖ¬pàÀ/õÞ½Cß  ´nåˆÿüç?r—p‰–]¾|½ý|ÑØî|Û¦5åÒ©²²²²Ã¥S'¹Çí H"*¯ã@éÒ«ýû÷ãÝ»wðööÆØ±cÙ²  ;;ׯ_Çõë×qòäI±ºŠÊ…^¾| kkk‰Û…QJ¢?KÛíÊÚÚ/^¼Pé¼!„BhÒ>>¾Ø½g/¶nÝ‚áÃþ‚‚¥ê‹Dú””ùŽÁç<ÀçÅ|ù“>ŠrúÌŸ¿1sç‚Ãá`Áüù˜¿`XýóçÏáú¿€ æ(ý«odTV®X)vìŠåâQ>qq±˜:uîÞ»oï^ˆ_¼øK¿óæ!8¸>zŒÈÈ(Lœ0À—åQ¢Ë¤~‹C=póŸ[èÝ»7b.ë×ÀЩ»RåÞÊ´sûÖ-ddœFÒºõýi{û/¿ü‚€€üù×E\»zEa?B'ŒGXØÏ¸wÿf̘‰9sf¼¼<Ù/o§N‚——§Üã‰vP¤õéÓ'\¼xC† Aÿþý•®—ššŠ–-[ÂØØ'NÄ™3gزíÛ·#>>VVV°¶¶F||¼X]Eå•EÖd!„B!Ÿ'}jö‡ÅN:aÆ8tèV®\ÁÞ¾'UöOx ì–yxüÒÉ žüIE9}Z¶l‰.]:ãû¾ApïÞÍš5«5uêÔÁÀAƒpìèQööÞ½{ãCÞ6BçÚµkÈÉy…¾}¿g9tð ì[¶D­Zµà×ÛûìgËÒÓÀ»W/èéé¡OPNŸ‘½ëÌÑ£é0p LLLÐ'(‡+ ìss ¹÷ƒ2íDDFÁØØþþþ(..ë€Q§NDF*ŸËãÜù  „ È.[óòòƩϓ>§NÁÃÓSîñD;(Ò‡_–6™››#$$^^^JO¾\¹rÞÞÞ033Ã0¨]»6 Ùò/^ÀÎÎŽ½Þ¸qc±úŠÊ…¬¬¬ðüùsUNKÌóçÏaee¥v}B!„Ró>ÏóÔøHÈÌÌÄðáÃàç營ÏÞ./¹s1_%ìäŽø¬O à øàóà*˜ôQFèè1ÈÌÌÄèÐѶ¿•µ IDATe666€:uê 77—½aDFDbÅŠå€+–KäòÉÉÉA#«†h`aG¼øßÿز·oßÂÐÐP©ñ½zõ ¦¦¦Jój¼~ýZ¬ÜÜ\¹³µca!}âèÍ›7¨]»6ÀªQ#¥úJ—…%üöF †ïºtfowusÃ¥K—Àår™™ 7·nr'ÚA‘>øåRXXˆ»wïbÞ¼yJ¿v 8?üð=z@€wïÞ‰•[[[#;;›½.ú³2åBÎÎÎ8wîœÌq0 #7Rçܹspv®üüp„B!¤ú«ñ“>GŽÆ÷}ƒ0tèØ°qLLL”ªWÌgÀã PÂ/øõ%ÒGž üwqÒïkѹK¬ý}­DÙÛÏÑ&y>ÀÒÒR¬, 0<Ä•+Wpïî]|ÿ}°X¹™™þ÷â%]ôü_rFXZZ‚Ëå*5>sss|üøPXXˆzõꉕ+›`TQ;²4lØïß—Nx½zõJ©:òïäååað!Øžü%?Úµo™3f¢uëÖìHYÇí H¢,Y‰Ž aii cccdeeáçŸ+æí¹„Í'ï°e<^鄟'·¤|ã»wïþüó/¤¥¥áìÙ³xðàXùÒ%KŸŸíÉÛÑ»wo±2†aŽaÿÁÄI“$ίW/Ü»w\.7n@o?_¶Ì××gÏœ‡ÃÁž=»á.²M»žžrrrØë^^ÞØ™’‚ÂÂBìûãx~^¥*uÛñëÝ›7mÆÇ±$1Qéþnߺ…ѹs6"Jt,6üžž^JO*EúòÚ°a¢££ajj OOO‰•Ïš5 ¶¶¶h×®Ú¶m‹îÝ»«T.Ô¯_?\¼xwîÜ‘Z¾hÑ"„……A___bòæöíÛÈÌÌDpp°ÔºÂÏæÍ›+u΄B!¤f©ñ“>=zô@Ÿ2ô•Áè@øGÙ›7²qâôux¶k‰è¡nàñ…‘> JDú(JäÀÿœ»ÇÑÒŽ–àóàóðl^¾ô DƒZ9:àø±c(**Š+ðÝw]$Žár¹Ø¿?ôôô´0BR(Ò‡àêÕ«9r¤¶‡A!„Bª(ŠôQ_À`]¬„é‘ÿ?ïŽ]J®YáâKÀ´éÓðòÅK¸¸tŠ•«$ŽY³f5~‹CÒºõZ!©é£]rËeå·!„B!„TžÏ“>ÊåE _Ä$žÖö”ZVøûûÃßß_î1'NÂĉ“*iD¤2¨éÓº-Ñ44hгgÏÛùJÑ„!„B!¤rÐò.BHµD‘>ÚW\\Œ;v`þ|å’®B!„B*MúBª%Êé£}:::pwwGNN޶‡B!„B‘B#9}8EŸ “±˜SôIív«C=B¾\.WÛCP EúT Àaðx<èêêj{8„B!„Ÿ#}(Ù0!¤z¡HŸªÃÖÖ{öìAII‰¶‡B!„BHÇ0 „ó<´{!¤Z¢HŸªcáÂ…0`Ú€B!„ª‚rúBª%Šô©:bccƒOŸh‰,!„B!U Eú¨)}yW¹å½&œ¯¤‘R3Q¤OÕqïÞ=„……ÁÐÐPÛC!„B!„ˆ I5ñø zOÉ”Zvÿð¤/ïªpâÇÖÖVfÙ³gÏÔ×Ñ£G…‹/B___¢¼¸¸ß}÷fÏž   µúxýú54h V]Ñsfµk׆æÌ™333¥ê+{ߨr,©~TôiÝÎIÛCþj•””ÀÜÜ\Ûà „B!„”AË»>ó Téxž@vòk}s4wüNa4P:¹#í¢.ooo4jÔ©©©RËwïÞ:uê 0Pµóåéé©v]àË9?}ú™/¢S§N˜9s¦ÒuUé‡|½(Ò§jîÚUš,ŽB!„R•ÔøIŸÓ§Ocÿþý*×+0à À^®¼ø€öcÇ”U§ ob=s4s삽 Ý*`Ôò…‡‡ã÷ß—H¨*°víZLš4 ::ê?ôïÞ½+ïYµMMÑ¿œ8qBcm’šrúhÇCzz:lll´=B!„Bˆ:P“ÿ@Ëáp0qâDÄÆÆ‚Ïç+]¯„ǀπϗܭ¦ÓxغÎEÓ^ËQ"'"H!!!8sæ àĉ1b[fkk‹äíÛáèèˆ~ýúáÍ›7€^½zÁÀÀÇŽkëäÉ“àóùl”OþÇ E«V­ðÓO?!??Ÿ=6//?ýôìííáéé‰ׯ³}Šþïß¿ÇðáÃáèèˆ#FàÇbcLJJ‚Ìs,))±±1{ýêÕ« BË–-Ñ¡C±¨%Ñ~µ-z¬¬6ÝÜÜðäÉÀ“'Oàææ¦p ¤j HíÓÓÓèQ££í¡B!„BÄ”ÎSÔøHoooìܹ;vì@hh( ”ªW,éSRf®ˆÏx<€ÏŠùò'}lmm¥^„æÌ™ƒÿû¿ÿ‡ÃÁÂ… 1gαúþü™™™ðóóC\\€Ò\9“'OÆš5kÄŽ]½zµX”ÏâøxDDDàï¿ÿ†§§'–,YÂûË/¿ oß¾¸}ë6&OžŒÉS¦ø²dJtéT||<ÜÝÝqùòeøøø`Ñ¢Ebý`Û¶mRÏ???›7oF@@{Û”)S0fÌüý÷ߘ:u*æÏŸ/óþ“×¶(Ymzxx ##@iÔ—‡‡‡Êc ÚA‘>ÚÇçóñ¿ÿýOl2šB!„¢ÿþ0…M¨ñ“>бcGüþûï8räÖ®]ËÞ~hÿ>™ux<áE€²B<<~édP Oþ¤¢œ>öööpqqÁÀÑ­[74mÚT¬þäÉ“aúy‰ÔñãÇÙÛ}||——ÇFèܸ~¯_¿FŸ>}ØcŽ9‚-Z V­ZèÕ«<Ä–;v žžž¨¥W bm—uüøqôë×&&&@zzºXyï޽Œ¼ '¶ìììЭ[7%<€aø€€WÁ¤2FމnݺaÅŠeÂ\¦¦¦xÿþ={;Ã0Çê5k°zõj¬^³áááb¹|rrrФIöºžžûó»wï”Þ~ùÕ«W¨]»6ÀÈȈ]f&TvRFQ‚åÜÜ\lÚ´ 7oÞÄ?ÿü#÷Xew ’Õæwß}‡É“'ƒËåâòåËX¾|¹Êc ÚA»wiW÷îݵ=B!„Bˆ:P&%MrôèQ 0ƒ BRRLLL”ªWÌgÀã PÂ/êõ%ÒGž üÁTÿùÏàââ‚õë×K”½}û@iž²Û¨÷îÝ=µk×pïÞ=±(033CÖã,6ºèñãÇlYƒ Àår•Ÿ¹¹9›èSa!êÕ«'V®ê®>£FÂÇ1hÐ lÚ´Iî±Ê¶-«M´mÛsçÎE«V­Ø‰.UÆ@´ƒ"}ªŽÇ'ÿÁÊ6S°@0b˜ZÃÂ… áïï/µ,†¨µqª¿V7t~êó÷÷Glll¹ÚX¹r%¬¬¬ÊµA!„B¾BŸçyjü',[¶ ÑÑÑ*}`*)aÀð(/óö\Âæ“wØ2¯t‡Ï€[R¾ñÝ¿/^Drr2Ο?‡Š•¯X±ùùùHII¯¯¯XÃ0?~spp€‹‹ ÒÒÒðã?ªÕFNNºvíªá‘B!¤¢éØo¬”~jü¤Ð¡ýûäæð)‹ÇcÀçÖF&ˆÞ ÐÚÊÚW6ONÙˆ^1Ç£·áÆÖ3€vC»Á3vtõt%êtå[©¢èC¡Ê5—.]ÂÂ… ¯L»Âr§aÝqwßeÔ2ÔƒßÒhÝ¿‹R秈è—qm,Zµj-ZÄþ± Gˆ‹‹ÃŠ+Ä&}„ãTuŒš>¿§OŸbûöíØ²e nܸ¡Tÿ©©©˜1c²³³Ñ¦M¬[·NNNÇ©3ÆÊzü\]]±`Á•ë•””`ïÞ½2#† !„BšôQ_À`]¬„Ÿ ø¼¢ëóÿ¤Iºô¸J—””„Å‹cõêÕÚ ©@é£}ÂÉY“!gãöàüoûÐ{Å(ÀÁñëaXÏî³úI´Åè0˜ò|-nl9­ò8^¾| kkÉ¥eeÇ'Kó^íÑq´Ö»ÎÆáÉ¿Lú(8?E„êFbÈ«§Ì$ÄÕ«W%¢C{ö쉉'ª5Yc(O¤Éû÷šŠ­[·âŸþAß¾}‘˜˜¨týääd¤§§Ã¿ýö~þùgœ;wNíñˆÒÄù)ÃÚÚ/^¼P¹žžž†ÁÆ•N!„ê‰&}Ô{DÛCPj©TM†°°0mƒT0Šô©ú®oÊ´ø€ÒIŸk3¤Núô\ðôM à<Æ»RÇ­úu†®^éÛaÞ³·•Þ¿,å.ÉË˃¹¹9`üøñX±b,,,ðáÃö£®~ýúáüùóðóóôiÓàåå…ZµTûX’˜˜ÈFºDFFâ×_•8¦"ίìDPÙ¨ EåšðéÓ',Z´qqq ÑH›„BùúÔøÝ»!ÕíÞUõ 'PŒê›À¨¾ àãówR5±¬£v?VVVxþü¹Úõkèi-QEªS§Þ½+½¿W¬Xxóæ êÖ­«Ía±D#iÔ¦]Údll\®]°T!Ø‹:×E=þVVV*ÁÐÐãÆÃ½{÷Êq&„BùÚ•NúØ!¤Z HŸª¯ŽàSn>åL?ßVVy–Ð8;;klIOU"œ ‘vQ†““222Än;uê”DÎmIKKÃíÛ·Ñ¥KÄÆÆÂÚÚcÆŒÁñãǵ=´JuîÜ98;;«U×ÜÜœ¶j'„Bˆ>Ïñhdy—¡ôõõå–«Ûnu¨GÈ×€ÑÑU|PB9}ª¾v!î8³·v^`okâ®ñ~‘œœŒáÇk¼m¨Ý°.ò_}À»/aÖBõˆ u•wÐÏ?ÿŒÈÈHX[[ã_ÿú®\¹‚éÓ§céÒ¥bÇ©›èXêÕ«‡ÐÐP„††âéӧضm&Ož¬T"geióü”‘’’‚!C†¨UWGGºººàñxÐÕ­^¯á„B©”Ó‡R-Q¤OÕ×-ú{p>"c~*à»Éþp›ÞWãýôë×S¦LÁ;wàèèÈÞ^ÞÝ·„<~ŒSsS°Üa|Z»wicâ¡ÿþxóæ FŒììlØÙÙaΜ9b;wåææš7o®rûš>¿o¾ùÓ¦MôiÓÔn£¬Ê8?Eç,¯üöíÛÈÌÌDjjªÊã²±±Á±cÇàååE?„B‘@“>„j‰"}ªY“ ºúµà“0 > ÃT®« cccL™28pà€ÒmKlá.ãø£<Ða”‡Ê㪠‘%cÇŽÅØ±ce–oݺ†††jM:hûü”™€©ê爈˜˜˜¨ÝFLL FŒ—/_‚Ïçkpt„BùÔ*~;RBÑ4Šô!¢¢££µ=„jiýúõX¹re•Éó£iUýüëÛ âƒDð²—Ä雘£¹’?¯ß¼•zQ—/¬­m°cÇ©åi»v¡N: R?™j·nnj× Ÿkkœ;ÙOŸáÈ‘#xÿá=b.T»MY³<÷3Ñ>U#}!ÚQQKÈUÝÂ^ž… Âßß_£’Ô†ùr©Šªòÿª~ß‘Ròž?ò~¿üýýê*ãùU‘¯_ò(züjÂãKHuQã'}N:…?öîU¹^‰€_öråÅ´û;¦¬:}s虘£™c¤,t®€QË…Õ«VI$¡X¹r""#¡££þCÿî­ú“%éGŽ`Ô¨ŸP·n]èêꢾ™ÆŸ€-[¶¨Ý¦,å'©ú(҇ꡢ" ´]PP€ÄÄD$$$h`TÒý#(½TEÚNÈ-OU¾ßH)EÏy¿_ HHH@aaaE Oë*úùU¯_²(züjÂãKHuQã'}8œ"„…Ãÿ-X Ò®%<|¾|¾ä‡ÎNãaë:M{-G‰œˆ eüðà dddŽ;ЇýÒ…9¶nÙ‚¦M#0 oÞ¼øúúÂÀÀééGÄÚ:~üø|>åóñãGŒ> Í›5ۇ ??Ÿ=öÇ>ìß°ûÆîÝÜpíÚ5¶OÑÿÒ-q‡‚¦MãÇ¡Cñþý{±1®Y½={ô4iÒK—.[Îeii‰;wïŠ5-mZÚú‘•Øn<Êö%mœe‰–]¾|½ý|ÑØî|Û¦5)åÒ©²²²²Ã¥S'¹Ç“ÊC‘>¤¨¨qqqhÛ¶-LMMQ¯^=áøñãí§*GB(cР[غUýe¹ÚVÑ÷ZZ\\\ààà Q&Œ0‘i"…ÒÑpÖ,d¬®–J^û5AU?mŽO4’ÍØØŽŽŽX°`8~Á44yä=qpp€‹‹ ÒÒÔO9 î냲ïUýõ¿<÷y)zü4ñøB4£ÆOúøøøb÷ž½Øºu †û7 ”ªW,éSRf®ˆÏx<€ÏŠùòß,åô™?bæÎ‡ÃÁ‚ùó1Á±úçÏŸÃõ# ÌPú…•+VŠ»b¹x”O\\,¦N†»÷îÃÛ»â/þÒï¼y#22 'ŒðeI”èÒ¨_ãâУGÜüçz÷î-±TËÀЩ»J·Ë]±rÒÒÒàÔ¾fDOÇÁƒqëŸ$î—K™™¸vý’Ö­GèO£TîKÚ8å™8a<ÂÂ~ƽû0cÆLÌ™3àå剓'O( óòò”{<©<éCBBBpçÎìܹoß¾ÅÇ1räHÄÅÅi{hUÊ•+ùèС¶¶‡QeíÛ·ª¶Ä[H‰rî-» 8—ÄGix€ hûK©¶û¯êÊsÿ£ÙÞ¾}‹M›6!==QQ•ü ¦@yž?0`ÀìÛ·Oƒ#RÎ×òþQÞû¿¼=~Úz| !âjü¤têÔ 6lÄ¡C‡°rå öö=©)2ëðx‹e„xxüÒÉ žü7{E9}Z¶l‰.]:ãû¾ApïÞÍš5«5uêÔÁÀAƒpìèQööÞ½{ãCÞ6BçÚµkÈÉy…¾}¿g9tð ì[¶D­Zµà×ÛûìgËÒÓÀ»W/èéé¡OPNŸ9+óŽMÇ€abb‚>AA8|øXy``˜›[Ú·o‹3ñß aiÙÿýÏzxyyJ$–Žš: FFFð÷÷Gqq±Z}©âÜù  „ È. óòòƩϓ>§NÁÃÓSîñ¤òP¤9pàáèè}}}˜››#((G?¿vìØéééìñEEE°°°`“¼_½z~~~°°°€œ±k×.öxÑ|1ÒòÇðx<üòË/hÖ¬êׯaƉEL2 ƒAƒÁÌÌ 111ðõõEýúõ±fÍ¥ÏñÂ…|üüüðóÏãÙÛå%w.æë „ÜŸõ)á<|¾\“>Ê=™™™:Z¢ÌÆÆP§Näææ²·3 ƒÈˆH¬X±°bÅr‰\>999hdÕ ,Ìáèà€ÿû[ööí[*5¾W¯^ÁÔÔ@é“ׯ_‹•››‹/±ÒÑѳ³3Â'OÆÎÔ]ؽ{æÅĈS¿~}ô¥¬ÜwïðÛo1|¾ëÒ™½ÝÕÍ —.]—ËAff&ÜܺÉ=žTŠô!îîî9r$222ðéÓ'‰òÐÐP$%%±×÷ïßÎ;ÃÒÒŒdeeáÇX²d 6mÚÄ/š3Fø³èrÞ%K–àäÉ“8qâ=z„Zµjaölñ¨¿1cÆà?þÀ¼yó‰ƒâ×_Uêüž<)BPÐMLšd‹œœ®·Åر÷ÙòÌÌèÔÉ”½~ÿ~!ìíÙë7o:##à ..¦ºC èŽóço0 êÔ©S¸qã®_¿Ž'OžHMÊyôèQ?~YYY8|ø0{»29w’““‘žžŽ7oÞ OŸ>øù知֗vÿ+C^ûB/_¾„µµµJíÊ¢Â*qéC¿… IDAT­ÓTN¤ªJtù]ÙKu¥J‚ØØXÜ¿W®\ÁßÿS§N‰•+zýRöù'ëù£ìï—µµ5^¼x¡ôy);¾¹sçâÅ‹¸~ý:®]»†§OŸbÞ¼yl¹¢÷eÏ¿¢^ÿ=~B²îÿ 55•½¾sçN 0@옴´4ìß¿ïÞ½ƒ··7ÆŽ«ôù )züÔ}| !šUã#}Ž9Œïûaèбaã&˜˜˜(U¯˜Ï€Ç „_:ñ#êK¤|`¿ÈâჇ¸rå îݽ‹ï¿+733Ãÿ^¼d£‹žÿïË‹²¥¥%¸\®Rã377ÇÇ………¨W¯žX¹è ¾CK{‰íäÛµoÏÖ×d_ªùwòòò0xÈlOþ’ŸÇÀÀíÚ·ÇÌ3Ѻukv"LÖñ¤òP¤IIIAûöí1iÒ$Ô¯_mÚ´Á‚ Ø¿æ:Çg#{¶nÝŠü‘­Ï0 nݺ…+W® 77]»vÅ^û'%%aíÚµhÒ¤ ê×¯ØØX‰Ü®®®èܹtb¸[·npvvÆóçÏ•j?!áÂÃm1dˆ%LMu1x°%nßþò—겓>¡E ñÉú²Ç¨*>>5‚••âãã±uëV‰cÖ¬Y{{{4hÐ@,²J‰‰‰hܸ1LLL)5§<ÊÛ¾0‰°¢dÂEŸ€¿/QC€^ý5ß~Ye£*;jGSý«{þʶ-ëRÑãÓôãóéÓ'\¼xC† AÿþÊý‚mÞ¼‰‰‰°±±AÆ ±hÑ"±re^¿ª³]»v!>>VVVhÔ¨~ûí7ìܹ“-Wôþ¡¬ŠzýSôø)Ò¿6rU `×®]¿;©©©hÙ²%Œ1qâDœ9sF£ç§Œ¯}ò™ª¢ÆOúbÕªÕ˜5{¶J;Z•”0à x”—y{.aóÉ;lW:áÃç À-)ßøîÝ»‡?ÿü iii8{ö,^¹_°çÏŸ£qãÆìuÑç2 Üë—2ÊóüŽÓÊÊJíú²¼xñBìœ7n,q¢èýCYõú§èñ’uÿ·mÛFFFøë¯¿ð×_ÁÄÄß~û-[~åÊx{{ÃÌÌ Ã víÚR_Ÿ¢Ç¯¢_Bˆjjü¤O=ÐGäK€²¸7 ºy#'N_‡g»–ˆê_éàDA¤¢DÎsæÌÆÜ˜èë fn fÏž%V¿qãÆø¶Mküyá¢gÌ”h?°OtìØÁÁý$ÊfΚ…_ãâÐÒÞ›6nBâ’¥lYôŒزe3ZÚcÙÒeXµz5[æç޾´3s&Nœ6mÞ‚¬'Ù8~â„ØvuëÖÅ7lDÖ“lœ8yß~Û–-KJZ‡ì§_þdfnŽíÛ“ñ$û)v¤ì„™H^²»g™™›#9y<|„W9¯qëöÌŸ¿2ëˆ^W¥¯²ã”·“W@@.üùnü}cÇ;Ö®qc¼~óöööJO*Eúž={"55YYYàr¹xüø1¦OŸ.–ÔÒÅÅFFF˜3gŽÄ‡Þ^½záСCÈÏχÃAAAÌÌÌ$ú±±±Á$¾=£FÂÇÁáppáÂôéÓGåóµì£U+$'ç ?Ÿ‡ää,Yò ‘‘_þ2\XÈÃõëùøø‘‡˜˜,\¹’{{ñIŸ§O9(*’ŸDÞ²“©S§âåË—xõê¦NŠÁƒ«|~å%ëþjß¾=6lØ ö„[`` Ø²òuÐÄò®ê@Öó7$$“'OƳgÏ““ƒèèh±re_¿=ÿÊûüIIIA`` ÌrEËâd¯_¿~ìë×Ë—/…~ý¾üT™÷yíW4EŸ¼û_˜×'55U"ŸOaa!,--allŒ¬¬,©ðP†¢Ç¯¼/!D3hÒGM%|€ÿ9w£¥9--Àç Àç à Ø¼>üÊ} Jàr¹Ø¿?»ä‚TOéCf̘ 6ÀÉÉ uëÖ…§§'ôôô$ò΄††"//^^^b·Ož<¿þú+,,,`gg‡Ý»w‹íÞ%´hÑ"„……A___ìÃéĉáî€Ô«WãÇÇðáÃ5v~«VÙcñâ§°°8„„gؽû[4nüå¯üsç6Á!·ÑªU&ll `l¬#é3a‚ <=¯ƒa2þ l uíÚmÚ´AÛ¶maccƒY³f)®ô™´œ&êuÿ -_¾Ë–-ƒžžžZ}ôë×/^Ä;w\©»¤JS-é’O[÷Ott4СC|ûí·ððð@­ZµØre_¿=ÿd=”ùýº}û6233,Q¦,Yã›7o,,,Ю];´k×–––ˆÙ4DÙ÷Eç/KyŸ_Š?!y¯_íÛ·‡žžôõõÑ®];±² 6 ::¦¦¦ðôô[ú¬,EŸ¢rá4Í›7W¹oBˆj˜ùgü:úÈgˆ:õˆ~úô -[¶”YùÖkÈÊz/_?èëëK=fOjŠÜ]°d©êõb&»£DÀ@ø.Àˆü/ÜM— &ñ´ÊãQF sŠ0QòeKñk\~OZm§Êàr¹8vøš4ù²†<ãø1XX˜þ2¥SúÁE‡Ž”¤”%<^¿~ƒ.®¥ùŸZ·s’Ù×½{÷ ««+óu(}ý¹ÿ¾ÌÇèÿöLWiâGÞx”ÅápÄ¢ÒHõ°}ûv$''«”¤™(^Öð5‰ÅÙ³gqàÀ·-ºœèk‹2©htßiÎóçÏáææ&¶dHSÔ}þôîÝݺu“ÅB¾÷øUäë—<Š?Eå+V¬@TT.\¸'§òF#¤²ÜºQšt½<ß“š;¨žDÖwÀÞÞ^â»UÞû7ø¤ó ‡.€ä”1QJEM䨂&|Ô3qâ$Lœ8IÛà å¤j¤&&}HõÃáp°víZŒ1BÛC!UXE~é¤É õÑ}W>?þø#fÏž† "&&}ûö­~Ô}þ>>ððð€½½=JJJ0¾ìÍ/HÕóµ?~W¯^ÅÈ‘#µ= B¾jÌ癊ô!„TKéC”QS–'Uºï©ÞBBB¢ía5ÑãGÑLúpŠ>A 'c1§è“ÚíV‡z„| ¸\®¶‡ Šô!¤z¨¨Ü@¢kåËÛþÂ… qîÜ9‰œþþþpss£œ#„B©¶h÷.BHµD»wR=TTÄ@ ÐHÛHLLDBB‚DYBBPXXXî~!„B´A`7š"„jƒ"}HQQâââжm[˜šš¢^½z ÂñãÇ5Úº[YWƒÝÂÖ­9Ú†Ú*úþOKKƒ‹‹ $Êàââ‚´´´ !„BHE¡HBHµD‘>$$$wîÜÁÎ;ñöí[<|ø#GŽD\\œ¶‡V¥\¹’jk{UÖ¾}û0pà@™å À¾}û*qD„B!šC“>jJ_ÞUî…R±(Ò‡8p‰‰‰ptt„¾¾>ÌÍÍ„£G:vìˆôôtöø¢¢"XXX '§4êåêÕ«ðóóƒ…… àììŒ]»v±Ç3 ÃF™:áñxøå—_ЬY3Ô¯_Æ C~~¾XýAƒÁÌÌ 111ðõõEýúõ±fÍ¥ÏñÂ…|M›6…­­-lmmѼysœ={V#c¶ikk‹o¾ù­ZµBxx8Þ½{§týªBÙ±È;®*)?Šô!îîî9r$222ðé“d"þÐÐP$%%±×÷ïßÎ;ÃÒÒŒdeeáÇX²d 6mÚÄ/š3Fø³h™%K–àäÉ“8qâ=z„ZµjaöìÙbc3f þøãÌ›7‘‘‘8xð ~ýõW¥ÎïÉ“"ÝĤI¶ÈÉéŠðp[Œ{Ÿ-ÏÌüˆNLÙë÷ïÂÞÞ˜½~ó¦322œàâb  ;‚î8þ_Jõ-têÔ)ܸqׯ_Ç“'O+qÌÑ£GqüøqdeeáðáÃìíÊäÜINNFzz:Þ¼yƒ>}úà矖Z_Úý¯ yí ½|ùÖÖÖ2Û°¶¶Æ‹/Tê—B!_/õ&oÔ­W^éó™_@ JÇó²ÿª§obŽæJLü>|&LÀêÕ«ñìÙ3<{ö ñññøé§Ÿð×_©4Y„í>}ú™/¢S§N˜9s¦FÚ®LÏž=«mªƒ"}HJJ Ú·oI“&¡~ýúhÓ¦ ,XÀ&Ý:t(Ž?ÎFölݺ?þø#[Ÿaܺu W®\Ann.ºv튽{÷*ÝRRÖ®]‹&Mš ~ýúˆ•ÈýâêêŠÎ;ºuëggg<þ\©öž!<ÜC†XÂÔTƒ[âöí/ …ËNú>[·n•8fÍš5°··Gƒ Ä"«”‘˜˜ˆÆÃÄÄ‘‘‘R#qÊ£¢Û4—PšB!Õƒ®®zÓ(êÖ+¯?ésúôiìß¿_åz%|ØË•Ð~ìêôMÌ¡gbŽfŽ]°7¡›Ì6ƇåË—Ã××—½íûï¿Ç/¿ü‚éÓ§«u>òÔ65EÿþýqâÄ ·MHe£HR§NÄÄÄàÚµk(((À¶mÛðàÁvbÇÔÔÁÁÁظq#rssqæÌ±õ<ˆ—/_bÒ¤IhÞ¼9¬¬¬’’¢tÿÙÙÙhÑ¢»¼§aÆ“ËÐÓÓû¹¸¸X©öÓÒÞ`ð`KöúË—\4h Ç^WéSzLœÕŸô±³³ûYÚ„U“&MÔn_4ÓØØXã»d)Ó¾•••܉¸çÏŸÃÊÊJ£ã"„BH5ÆèÀØØDé?ú Múh‡ÃÁĉ >Ÿ¯t½>_>_ò/| œÆÃÖu.šöZŽ9AÅÅÅb>BÁÁÁb!òù?"44­ZµÂO?ý$–3ÂÖÖ[·n…««+š6m*VOê¸KJJá>{ÿþ=†GGGŒ1>|ZÏÕÕO³³YYYèÑ£‡Rc×¾­­-RRRЮ];´k×éééÈÈÈ@‡$Úýà~õêU¡eË–èСRSSåž³*m¸¹¹áÉ“'€'OžÀÍÍ­\}’ŠC‘>D”®®.Ú·o¥K—âØ±cìí£Gƺuë°sçNøûû‹½þ9::bݺu¸zõ*òòò°téR©Ë†‘ú¦Þ¤I¼{÷NléÇÓØ9åäpѨ‘>{=99}ûZ°×¯^͇“Ó—ÍGæ¢E #±6._ÎGÇŽêOúd~ÝþܨQ#‰c*:Ÿ¬û_ÈÈÈEEEj·ïììŒsçÎÉ,?wîœÕnŸB!_Ÿæööàp¹ çø|>8š6kmeü¼e{Í KöööÆÎ;±cÇ„††¢  @©zÅ"‘>%eg>àñ>(æ«þÐ2 öúâøxDDDàï¿ÿ†§§'–,Y"vü;wpôèQ¬^½ãÆ“Ùn~~>6oÞŒ€€ö¶øøx¸»»ãòåËðññÁ¢E‹¤ÖuwwDZÏÛ Ÿ}T>Y‰€[µ2ArròóyHNÎÁ’%Ïùeòº°‡ë×óññ#11Y¸r%ööâ“>OŸrPT$ÿȼDÄS§NÅË—/ñêÕ+L:ƒVùüÊKÖý/Ô¾}{lذAí ·ÀÀ@ìܹSfyJJ e/§D΄BHÍÂå¡IóphÕ|è ¸¸˜½pË\ø`ÐÔ¾%l7‡£þ©Ô!œç©ñ‘>@é/¿ÿþ;Ž9‚µkײ·Ú/{‹VOx ìäO _:TÂSþƒ hâeѨ”#GŽ E‹¨U«Vé—”ƒ‡ÄêMš4 ÆÆÆðõõ•X6 lËÎÎݺuãGÄ–Ž?~ýúõƒ‰‰ dæcèÞ½;Žžô9qâzöì©Ôµ?yòdÔ®]>>>¸yó&FŒ ©ç"tòäIôîÝè߯¿Ò‰©•iÃÃçOŸP:é#ŒhÒDŸD³(̘҇16l€““êÖ­ OOOèééIä E^^¼¼¼ÄnŸúõ뇋/âÎ;e·oßFff&‚ƒƒ¥ÖÍÍÍ4oÞ\å~ !„R=ñù||̃U#ktíæ·žžpíá®î=ñ]·èâÖ]ÝÑÙÕ]º ¥òó>¨´²H“ji¥×*æòåË=z4|||0fÌövyÉ‹ù:(À#þà•ð†á\&}DsAˆNúäääˆåL懲°°€,Š’¿zõ µk—.022›7o¤çæêŠI“&!777nÜ@—.]”ƒ¢öÍÍ͵j•þ*Ö«WOîxÒÙ›6mÂÍ›7ñÏ?ÿ(<^•6¾ûî;Lž<\.—/_ÆòåË5Ö'Ñ,U#}Z·sÒö‰†y{{ÃÛÛ[áqfffðöö†‘‘ø„ˆŸŸüüüÖÒçèÑ£0` „¤¤$™ìÊ*æ3àñ(á—Fõˆúé#O û.ÖÓÓ“šƒçðáÃb;fffÈzœÅîÄõøñcåNN ææælŽ O……2']j›š¢M›6Xºt):vì(1ñ¤nûêüUvÔ¨Qøøñ# $¶½²&Ú000@Û¶m1wî\´jÕ †††ë“hEúep8¬]»Vf¤!-1á”&ûŽŽŽ–YoýúõX¹r%œœhR™B!U“PñI«2,[¶ ÑÑÑÐÑQ~¬¤„O À£¼|ÌÛs ›O~ çñJ'|ø<¸%²ÛX½z5&L˜ 6ñ#º»——îÝ¿.—‹-[¶ˆí>S^صk ±ÿÀ±Íe¹»»cãÆK»4Õ¾²nß¾>}úÀÅÅkÖ¬Ñxؼy³Øyj¢O¢Y”Ó‡(ÃÐÐ Ãh% ùú]½z#GŽÔö0!„RžíZ"z¨x|À0(‘éãëë‹åË—cܸqlþ===¬^½ZlW¯éÓ§#""gÏžE³fͰtéRµÆ,Í´iÓޏ¸8¸¸¸`Ù²e2íÑ£âããUšôQ¥}e%$$`„ ((([ŽW–­­­ÌåmòÚðôðÀ,@l‚JÙ>Iå¡H¢Œªò¦[Ñ}G!„¢¼­Û“‘qú4º»»ãÇ!UçŽ5~ÒGèÐþ}rsø”Åã1àók#Dïhmež`ø¥ÿ(Ú½Ë××Wár­zõêaýúõRËÊNjˆ^W”Ï(]:&k¹RÙúÖÖÖpppË7¤h ª´¯ì¹”Íê°NYòÚøÆÎN¢®¼ã‰vPNíÓÕÕEƒ 0{öl©[B!„RœÊÈ@Æç 2NŸ†­5ztï®åQ•ªñ9}ÔUÂøŸs÷8ZšÃÑÒ|¾|¾¾€ÍëÃWoÙ*§°°ÿùÏЫW/mEeÅÅÅ8tèÒyˆHõ@‘>ÚW\\Œ;v`þüùÚ !„B!ZqýÆ lß‘GÇVHMÝGÇVؾ#×oÜÐöÐ#}(‚[e|ƒu±>¦CàóŠ®Ïÿ ïSݯ$_Ò¿þõ/´mÛþû_mEeIIIX¼x±Xž$RýQ¤öéèèÀÝÝ999Ú !„B!•îñãÇHZ·VV0{Ö,|È}‹Ù³f!jêT$­[ˆÉáhÚ´©v÷yN‚–w©):öˆ¶‡P©îÞ½«í!¨-,, aaaÚÑ0Šô©†Ã0àñxÐÕÕÕöp!„B©4{÷퇡‘æÏŸΧðy

`þüùˆˆ˜‚½ûö#|â­Ž‘&}!ÕEúT¶¶¶Ø³g‚‚‚P«½­B!„šaÊ”)004B çþŸ½ûŽoªê8þ¹IÛ”¶@»P†lÙ[†PÊ*(¢ ò<*"¨ˆ¢øüp±D‘­‚>*È(K (2,Û"C "´¥@wšäþþH’6³Zì÷í+ØÜ{ÏÉ9÷fÜ|sÎ÷æ̹]ŒF#¾¾>üp>9ÙY˜ ¹ÅÚF9;BÜ‘d¤OÉñöÛo3hÐ TU•+> !„BˆRCƒŠ>;£Á`·<77“ª¢LÅÓ4+0Ï¿™Ótüüü\®/l½wB9!þ Í55GFú”ï¼óÿýï™8qbq7E!„BˆÛÆ/Øc+ èvRmþ•«w !îH2Ò§ä8uê£GÆßß¿¸›"„B!„°!A!ÄÉÛ‘>âÖ1 „……w3„B!„ùHÐGqG’‘>%ƒåª]Š¢wS„B!„ùH"çBúnf —ëï{ñÐmj‰¥“äô)~F£‘-[¶P­ZµânŠB!„ÂV^âf ú’Ѥ3á€Ãu§cÇòÝÌ~6lØÀÈÃÉÍ5_ÆM§óç³Ï?§K—.7ÝÆ Ò:«é IDATá7¦[(ŠBPP111Lú¡LŨFRrÊM·£(xÚÛílûDûxÿý¨X±¢WõÞŠ¶Š›##}ŠŸ¯¯/•+Wæ­·Þ*î¦!„BqÛ¥\¹‚FQ )°.55“ªZ -»A¦wåy`àÃ^moTOeð £NƒnGmذQO?Å¢O“”œBRr sÞŸÃÇÿÃO?íñª=ÎX꽜”Ì‘£ÇhÛ®_ºó®°SØ Š¥ÿIÉ);þ ­[µfòäWnº^w)n=ÉéSüL&ýõÆ +î¦!„BqÛ-_±’7Þ~‡ËIIvË/'%ñÆÛï°|ÅÊbjÙ ¥>èǺµk½.gPL*ÖÛÁ‹×höôÇL˜‡_`¾aÔnО5o·vZÇÈÃY°ð#úöík]6pà ¦Ï˜É Ï?_¨þ¸R¶lYyä_lÛºµÈë¾ñÔÓO³}Û¶ânŠ(2ÒG!„BQœž>½^Ïsç‘––@ZZ:̇^¯ç‰á˹…6AŸÒš„3''›Ñ£Gñæo`2™<.g0*˜L*&“Šªªvë*4CDÇשÕs.#‚rssí>ƒ âûqÖûiii :„:µk1äñÿžž~ã±ÂÃX¾|mÚ´¦j•ÊlذÁu» ­÷SSSüØcԪɿæêÕ«˵iÓš?Î 11‘{:´÷¨ ®ê¯ÆŸNýúõ¨_¿±±±ìøþ{înܨ@=¶Sµâãã‰éÓ›ÈÕ¹»q#V¯^í²Ï¶EÁÇçÆ¬FÛz]öãÊèߟF ðé§Ÿ˜:fË“¶¶mÓ†³g8{6‘¶mÚÜtßJé#„B!„(NÃÃxå•É$%'3oþ|ÒÓÓ™7>IÉɼòÊd*ºøÞx»”ú‘>½zõæ›oײjÕJ†yœŒŒ ÊåÚŒô1ä‹™Œ`4‚ɹ&ïƒiŠ¢ Óé¬÷§M{‡‰_âä©ÓôèÑ“Y3gÚm"!;w±è“ÅŒá<’˜žžÎÒ¥K¸ÿþû­Ë¦O›F×®]9þK111¼óöÛËv½·+[óFmß¶è=¬ß°Þ®Üó/¼H@@}ûöµ&„Î_g¥ŠhÛ¦5¿ýö¯¾6ź~ëÖ- zøa¹¿bc79l[·¨(¶lÙ À¶íÛèÞ=Ú£6¸«ÿʼn ¢OL ÇŽeĈ‘:ì‹Å{~¢ß}÷¡ÓéôðÃ\IqžCÇÒÿÊ•*Ò¥sgÎÿù'ïL›ît{gýزe3ƒ~˜råÊñ /:-ïi[££{—ôÙGT÷î^÷­´“‘>æÑ‚«W¯fêÔ©ÅÝ!„B!J¥ÌŒ :ÞÓž~ýî _¿ûèxO{2=Pr«ÉÕ»€0tèúôéÃ3ÏŒ±.w–Ü9iÿRzÔ«‰>a%Ú%%Mo·Þ`E1ª ÷"èc›Ø6èsùòeªT®d½ïççgW.<<Ü£:¹téeË– L™2$åK@eѹsgFzšÔ+W8|è0:tð¨ îêË»Š˜eÊ•£¬çù¥^¹Â’%K8vì(ÇŽs¹mRr &“‰õß}ǬY3yãÍ· rº½³~$''[ËU®RÅmݵµc§NŒ;½>‡°`áG^÷­´“‘> ÑhèÒ¥ —/_.î¦!„BQj¥]»Æ°¡CˆŽŽ¦zD5®$;þ^]4*ª»íþ±6oŽeÀý<øß,]¶Ü.ß3Yg6Rã‘)dÙ€ÑéH£ê|0•¯¯¯Ã<6lÀ×××z?44”¿.þm½ Õ…¿.zØ;÷ÂÂÂHKK 33“àà`‡Û•-[–»›4áÝÙïÒ¦M›§ÂÖ_˜\Rÿyü?\¿~G{ŒÏ¿pŸóF£Ñpÿþ öãžëõãTªT‰«WSs ëfÛªÓéhÚ¬“_™L£Fð÷÷w¹½(èÅ>ÿGú =þNNÎMßJ"EQP£ÑXÜMB!„¢Ôº’œDhp¹ð±DyJýô.Οùóðêk¯¡Ñ¸ßI;ߥR«Æ ¸» •Z5&içl*–÷cÅŽ_­Ûæ€É¨¢78¯kÑ'‹õôSvÛ˸[ôìÙ‹S§N¢×ç°lÙRbúô.\gˆŽîÁ—kÖ™™ÉwëÖÑ=oš‘#ݺvãÓÅ‹éí|››©ßS'ðàƒ´kמyóæz\î‰'ž ==Ým²kGúÄİbù ÒÒÒ˜óÞ{EÒÖèè,]ºÄnª\aû&J·ˆˆ¾ýö[ o8B!„Bˆ[ª$äðɯÔOïêÚµ«WÛg]ØG¹Êmîïàû]GèÞ´/î„Ѥ‚¨ #}úöíË‚…1rÄpkþ___}²Øîª^“_}•qÏŽe×®]Ô©só,ðªÍ®Lž<™gÆ<Ûo¾AûöíY°`¡Óm»EE1mÚ;òùUýžzÿƒ¹<ýÔ“ddd0zô3^•ýÞ{<öè£DEEQ¦L˽øÂ‹ :”Å‹?áÿ¦Nå³ÏVY×Us:ÎU[{DG3 ¬ù|n¶oâöH8z¸¸›P@ìúuœJ8^Ì-B!„B”$¥>ècñíWkœæð±øcýËU3Oÿšúb‚ªòçú—yï¹14ªŽQ5£RLæÜ]½«oß¾üuño—Û„„„°|ÅJ‡ëòlï»ËçÆçŸ;Nr›¿|µjÕhذ!Õ«W÷¸ ÞÔïi_úõëG¿~ý¬÷Ÿ5Êm‹ÈÈšü¸ç'¶·½ÊÚuæ/ÖWRR(_>Øi9[®ÚZ#2²@YWÛ‹;›ÉdâÄñc$üúk‰Iê&„B!î\­>Z5?jiS¦L4hHí»îòhÖNiå  PŠÓúxîúo7nÂÕó×™2s‹ë¶%¸FmÒ÷£AÅpL¦;Ñ š/ßþO™™É'‹>¦WZv'iØ >óæ}HÇN˜7o:´/°^¯gË–-vù˜„°H8~”ÃGŽb4™P´ÚânŽB!„¸ÃiµÊ—/G€¿?¾æ\ý'ÉÎÉáØñ£¨ª‘ºõwsJ ó”Ò,¤ gOR½K7´Ë1r̃h+F ñõãÂÙ“l˜ÖÓ<£‹¼]›ÿÑ"QqIÔ¨aš5kÎÊU«Üoü4ëÝÙ¼4é%þ¾ø7mÛ¶aÞ‡ó l³pá¦O›f—I0òùí÷³h UkDÐ;&†²eË*‘¹B!„(ÝTU%-í:[7ÇríÊU‚‚ (u£]r t~:ÏJÐÇ úx!2j{—Ï Høßëò7Û)Æ–ÝzgÏýQÜM(V}ûöµË³äȳώãÙgÇݦ‰’æêÕ«œ>}†»ïn\ _”Á`Àd4âãçKtž˜ F.üYº_SB!„¢ðƒÊÕ=š¯Ö¬Æd4¢ -e£ÉµZ-”+K¶WÙuu®’’²•+éß}Ô©]ûV4·ØHÐÇ UÛ¡ê?<¸#„ðÞ¥K—8rô¾¾¾hµŽßVu~¾˜rUÊ”)CÒåK·¹…B!„âŸ$íú5*T¬„‚‚¢Ü¸•6¾~~øët.·ñä\]«õáÂ…¿˜=ç}†JË-nEs‹…€* }„¢PΞ;ǯ¿ž¤\¹rô‰éKFÚu †Ü‚* ™™™èõ¹ ˜§‚Ú~8+ŠÆf¹ù¾‚š¼mL***ªjBÍK ªj²Ö¡ªªu¹ež©¢(æíUÕ\y^›Polcß–÷UUEUUûǰܷ©UEµžx`SF‘þJ¥¿Ò_é¯ôWú+ý•þq33³¬Ë5Š‚Ææ±J M¾}œŸ§çêáááÌ™ó>¯¾:™…/â‘Aéu+›~˜Ÿ+E2Ò''; ÕEÆâœì¬B×{'”âŸ@¯×wî8 '~åܹsTª\™={q=5ÅqÀË1F»øPTÕz*‘·Üº ïCë FÞÚ¼s‚¼ûNJ¬Û™Ï`lÑI[ì¹:)±«CUQm›í²né¯ôWú+ý•þJ¥¿Ò_éïÍô×h2ÞøhÌ·ÒF£:ï·7çêC.¾¾0{ö{üßÿý—/Ö|IRr2 ä2¨t'é]BQ©©W9wîÑÑ=HMIÂdtüVP@1'×3©&ëÉÇ%{y¿Ú( (&Û_„ÀüK”ÍI‰IÅö¤Ä²Ür¢(JÞɋТªÖ_¢Ì¿P©6çý/Q¶u˜OJò~‰²i Š"ý•þJ¥¿Ò_é¯ôWú+ý-âþÞ¨Sc½•6Š¢Úá¼=WÈÍÍŘv)¯MáÑÇeû÷;hݪwÕ©sKÚ~»HÐG! ¡r•*4iÚŒcG°aýw´jÙ?'—ÊÔjµæ‘¼Ï#Õtc¸°yaÞ¯P&寝PË=ÖuUµüeÂ<âØæDÄ|’ï¤$ïë›OjPnœ,XÏ5›íòÚc÷¸7*´¹o.wã¤äF=–“ k]Ò_é¯ôWú+ý•þJ¥¿Òß[Ð_ËÔ/×Óœþ©”¼(žV«ÅhÔñæ\ÝÖõk×xëi 0€F£Ïɾeí¿|Àþõ!„½œì,š6mB¹råØóãìÝ·ŸÖ­ZP`[æÆ•4ZMÞý‚o¼&ë'½ FSmœRÌÿX>ì}ä{º,¯7N6lꬿ4¹«ÃÝi‡ôWúë”ôףǗþZ[ ý•þº¬CúkOúûOéoéœÎåŒFcôñæ\ÝârRïÏGrR£G¦{TW’“nGó‹ž JÞóCFúÒ–¹÷¸\ßsìžÛÔ!Dq¹’œDDµªôìÝ›í[·òÓÞ}ÜÓ¡}Ë@j´7†Ú¦]OÃßߟ¬¬L°ýÐB!„ŠB™2eH¿~­¸[Rbhµró¥ëñô\Ì—lŸ6}9ú\^›ò:Ô¿s>ùHЧŒ&…˜ ®;;–-sïñ(ð˨Q£ÈÍ{†êt:–-[F§NnºÖ¿E!((ˆ^½z1eÊBCC=*þüù›nGQð´-–ílûžŸ»znE¿oǾ,IÇ«4¹~í*AAÜwöïßçð2¾¾~•+‹áª‘øýûhÕ¶5!aa¥ò B!„âæ˜T•ŒôëÄïÿ__||}ÑjJ_>0œ 'ùŒ<9Wó%Ûïª[—!C†R!,”ë×®ÞÊfßVôÉÓ§ß}^moTYó £Nƒn?±±±Œ;– лwo¾ùæFŒÁ²eËh×®WmrÄ6ž–ÆÚu똻víâúõëôë×Ï«rUÁd³_ÿ}aÿ·šîMëñbû0j7hÏÚÙé?a·Ã:Feðs²(“ÉĤI“ر£h¿•-ËÀ™:uj‘Ö+Ä­p§%¢ËÉÎæÒ_®ÓçdS§~C´>~œ;—ˆ>ûÎN'„B!ŠŸ¯/~~¾(Z úüs›JÖ‡ZuëQ¹J5·SÝ\«ƒù’í®Ö—dî’x—ú ONNÏ>û,ÇŽ㥗^ò8Bj0*˜ò¢>ù÷o…æcP0'ê:r´ƒÓ:rssí>>ø ]*=-ñ&ðÃ?бcGæÌ™CPP`Å2}útæÏŸÏ_ýU ˆT Ýƒ]òª«W¯òÜsϱwï^:tèÀœ9s(_¾|r;vä‹Ï?§zœ={–¡C‡ç¶ ®êˆˆ`öìÙ¼ùæ›Ìš5 NÇøñãIMMµ«Çv´Î¡C‡øïÿˉ' â•W^aàÀNû숧ýž;w.Lš4馎…mûóO=«S§;wîô¨þ×_¯¾úŠÍ›7h«'û¨S§N¬ZµŠÈÈHÎ;ÇàÁƒùᇬÛ?ûÌ3^íÇ[éNéãŽÉd"ãú5jDFY«&“ …B!„pÀÇÇÇ|•ØRÊd2‘k0~ýZ©>¿–‘>nôèу/¿ü’áÇsæÌ>øàݖ˵é“ÿš,IÃÈ5y?ZAQt:õþÌY³xþùçY°`_~ù%sæÌáÕW_µ®ÿõ×_Ùºu+»víbÔ¨Q$&&:¬7==•+WÚ”fÍšE—.]øðÃùî»ï˜1co½õV²]ºtaÛöí 6Œ;ve·ÞYÜÕäÈöìÙÃÎ;™={6½zöd÷îÝìÞ½Ûi_&L˜À‹/¾H÷îÝùæ›o˜:uª×AOú½dÉ’’’ìFFű°†5dÈ}ôQë×ét|öÙgnûçlEEE±sçNüqvíÚe=Ž&L`„ ì9QXF“‰ôô´ân†B!„âÆíHõ›FQÔZµjÅÇ̃>ÈG}dýò»iýwNsýæ›ùZhöûϨª *¨ŠyD§ò±6oÞÌk¯½†={öäþûî· Œ7Ž€€z÷îmM¿NFCXX=zôàõ×_·®ß¾};/¾ø"ôë×wß}×aÐçÞ{ïeåÊ• 6Œï¿ÿž'Ÿ|Òn½³6¸«üøñÖÓO=õ_|ñûba;ímàCyá…ïPܵkõêÕ¬[·Ž¯¿þÚ®ÜÍ‹üÖ¬YC™2eìFf¹«?&&†°°0·ýs¶¢¢¢X¹r¥5èc 8íØ±½^Ïî¼Ñ[%»é]¶ÑÛ©QÓæÅò¸B!„B‘Ÿ»ïM¥~¤@||ù¤5ð`á(à£ó/CÒþ¥ô¨W}ÂJ*´JJšÞnƒÅª‚Þ‹ Oþä×/_¦fÍšÖû¾¾¾våÂÃÃ=ªÓ‘K—.Y§•)S†ääd‡ÛuêØ‘qãÆ‘ššÊÑ£Giß¾½GmpW¿%€áãc~*»l/@jj*Ë—/çøñãüòË/n·/L»vîÜIJJ .\(²caëï¿ÿæý÷ßgíÚµvËÝÕïIÀœï£:0~üxôz=ñññÌ;׺ýÒ¥KiÚ¸±GõßN‰‰‰ÔªU«¸›!„B!„%†í¬WŸÒ—â;Ÿ­[·2hÐ yä-ZäÑÔ®¬3©ñȲÎlÀ˜oú QU1šÀ`R1ªÎw±¯¯/±±±–ÇÆÆÚ}Ù ålâYΟ?ÏùóçNß*Œ°°0ÒÓÍÙɳ23]‚Ê–¥qãÆ¼ÿþû´jÕª@0¢°õ&YïðáÃIKKã‘Gaùòå^—÷¤]¼ÿãÆcÆŒvË‹êXLœ8‘^x¡@È]ýžî/gûH§ÓѤI^ýu6lˆ¿¿¿Ýö%‰¢(„‡‡“PÜMB!„Bˆ%!!ððp·ßK}ÐG§ÓñÁðòË/»Mâ¬ó/CÒÎw©Ôª1înB¥VIÚ9›ŠåýX±ãWëvF£9àc2ªè Îë[°`cÇŽµ üØ^ÆÝ"::šS§O¡×ëY¹r%ýû÷/|‡ó‰ŠŠâÿû™™™¬ß°®]»:ݶK—.,[¶Œnݺݒú=uâÄ î¿ÿ~Ú¶mËÂ… U‡»vùøú0`ÀN:e7R¦(ŽÅš5k¨\¹ (°®¨Žµ«}ÅŠ+ìŽã‰'¼¾‚Ý­¦( !!!EèB!„Bˆ;™åûQHHˆÛ«w•ú O—.]¼ú²›ua_¾û{ø~׺7­Ç˃;a4YFú(\ŒôéÝ»7sçÎeÔ¨QDDDÁ¨Q£˜;w®]ž—I“&ñî»ïÒ¤IV­ZÅÌ™3½ì¥s/½ôqqq4oÞœõë×óÚk¯9ݶk׮俿zôñ¦~OÍž=›±cÇEýúõ U‡'íÒh4¼üòËv¹~ŠâX¼?ç}>ûìsë1·>æMýùs@Ùrµºç%o¶ tÍž=›ñãÇ{Ý—[ÉòæFBB‚~„B!„¥^bb" „……¹ ø(S—½¢öiÕ2FÊ…ØO5ÉÊÊ¢^½zN '=ÌÙ³çèܵ+~~~·q• Ù•’XîÒ¶©•ý›ÀÊ59õã÷ÔëEÆÅ³d¤Wæ—È14ªlÞ* äý³bF^xc‹×í)‰._¾Ì£>ÊöíÛ‹»)ÂÛK¶†%‘sÍš‘Öe;·o#<< ___Ec~SÑ(hòÞ\lß` F#IIÉ´ïØ pðøÔ©ShµZ§ï¹¹¹˜L&L&W®\!%%Å\o£F’ãG!„BQªX‚=`NWŠF£±Þ´Z­uÛk©Éäh³Ù¿^9{åúo7nÂÕó×™2s‹ë¶%¸FmÒ÷£AÅpL¦×n7¨6—o¿Ãeffòé§ŸÒ³gÏânŠÈ'77—mÛ¶yœgéN¡Ø–BCC æêÕ«$$$Hž!„B!D©Fpp0Æîû’+ôñÂ…³'©Þ¥ÚŠå9æA´#ÐøúqáìI6Lë‰BÞ(òþ´…HT\µhÑ‚&Mš°tÉ’ânŠÈgÑ¢EÌœ9Ó.Ô?¢(Ö<[ªªZƒ?!!!¨ªŠªª˜L&»7¹Â$B!„Bˆ’BUU»¿óxlo–u®òKÐÇ ‘QØ»|6!@ÂÿÎX—¿ÖüáblÙ­wòäÉân‚pbôèÑŒ=º¸›Qä,Ëš%Ðc{Ëÿæ&A!„B!ÄÌ6ècá(àc»¼Àö6KÐÇ aÍ&ìÜ¢¤Èÿfyó³ýþ7D ú!„B!îd޾ãØylÿoùÜÕ÷ ú!J¤üodùßüò{´-#„B!„w"GßmòÏÉüq¥H‚>:ÿ2.¯Â£ó/Sèzï„rBü(­ûŠ7ohB!„B!n°ü„^ÌÍB!„B!„EÁ2bÈyŠg!„B!„BqÇ’ B!„B!Ä?$r.¤ïf¶p¹þ¾ݦ–Qzèt:*V¬XÜÍBˆRíü…Kœ=÷Wq7£Ô‰¨V‰š‘U‹»B!ŠÑåË—ÉÉÉñªŒH‚ÔÂ0šb&p¸îtìX¾›Ù£Àφ 9b8¹¹¹ètþ|öùçtéÒå¦Û˜––Æ[o¾Éúõß‘ššJµjüë_ÿbÜsϡպOÚ[!<Œ¤ä”B=¶«²žÖ[!<Ìú·¢(ÃÔ©o梤ws;xÓç›ÝoÿDìBˆâwíz:¿$ü@xX :ß’y€ªììtöì=@ãFu(_.¨˜[$„âv³|'ò$øc½ò-oÕâ{µ½Qu(ó £NƒnGmذQO?Å¢O“”œBRr sÞŸÃÇÿÃO?íñª=Ž<÷Ü8ªV«Ê{~â?ϳyóf®^»Ê;o¿}Óuß.–ýr9)™#GѶ];&¾4±¸›åµ¢ÖHÀG!Dq¹~=ƒÓ§ÿ <$ª•Êâï烢(r»7?ªV*KxH §OÿÁõëÅý´BQLÂÃÃÑétm[êƒ>qqq¬[»ÖërUÁ¤b½¼xfOÌ„ùqø†áFííYóvk§uŒ1œ ?¢oß¾ÖebúŒ™¼ðüó…ê­-›73|øÊ—/V«%$4”1cƲråÊ›®»8”-[–GùÛ¶n-ÛH>BQüNžN$¤¼4ÜŠñæïïCHy'O'÷ÓB!D1Ñh4O*õAŸœœlFÅ›o¼Édò¸œÁ¨`2©˜LªõRhš!¢ãëÔê9ƒ‹A¹¹¹v‹AƒñýŽ8ëý´´4† BÚµòøHOO¿ñXáa,_¾Œ6mZSµJe6lØ`]W³fMÞF£Ñº¬bÅŠüzò¤õ~jj*ƒ{ŒZ5#ù÷àÁ\½zµ@{Ú¶iÃٳ拳giÛ¦ ñññÄôéMdêÜݸ«W¯¶+wüø1:u¼‡‡ tX¯»¾9b0 ôªýmÚ´æsçHLLäží­ë\íCWõWã‹Ï?§~ýzÔ¯_ØØXv|ÿ=w7nT Û©jîö›3žÔQØcURy½Bq뤥g Ñhð“Ñ=%ææçg¾¥¥Ëh!„(Í<ù¾¤È³(UzõêÍ7ß®eÕª• ò8ž}xæÚŒô1ä‹™Œ`4‚ɹ&ïó%)Šbwð¦M{‡‰_âä©ÓôèÑ“Y3gÚ—©&Þ IDATm"!;w±è“ÅŒ1ܺ|Þ‡óùúë¯iÞ¬)¯¼<‰7’ðË/ve§O›F×®]9þK111§~EGwgÇŽ€ydTttwž;†Ñ£ŸáÔé3¼òÊd¦LyͮܠزuO=õ´Ó)eîúf+==¥K—pÿý÷{Õ~€®÷vekÞ¡íÛ¶Ý£‡ÝzgûÐ]ý‡">þ ³fÎbÆôéüÿ3ûö(P-wûÍÎê(ì±*©d”B¿3¿ýIhùE#·t -À™ßþ,BˆbäÉ÷¥R?Ò M›6,]ºŒM›6ñá‡ó¬Ë¿ýjÓ2F£å¦’€QU1šÌÁ ƒÑó O…ð0»›Å¦©[¯>>>ô‰éÃú ëíÊ=ÿ‹зo_kBh€fÍš±ÿ–,]FÅŠ•Xòéb¢£»óÍ7_[·Ùºu ƒ~˜ÀÀ@îïßŸØØMÚ݃¸¼@Âθ8¢º› ?îù‰~÷݇N§cÐÃs%Å>çÌĉ/@ÇNؼ9ÖaŸÝõͲ/*U¬@Û6­ùí·ßxõµ)^µ [T[¶l`ÛömtïíÑ>tWÿ‹'DŸ˜Ž;ʈ# ,P-wûÍÎê(ì±B!œÑj4øé|P4ŠÜJÐÍOçƒV#§òB!\“K¶`èÐ!ôéÓ‡gžc]î,¹sÒþ¥ô¨W}ÂJ*´JJšÞn½ÁŠbUAïEÐÇ6Q¯mÐçòåËT©\ÉzßÏÏÏ®\xx¸Ó:5 ­[·¦uëÖ<7~<ûöîå©§ždÀ€¸téeË– L™2$%%¨£c§NŒ;½>‡°`áG¤^¹Â’%K8vì(ÇŽ+P®JÕªÖö&;IBì®oî’{Ò~€Î;3zÔÓ¤^¹ÂáC‡éСƒÝzgûÐ]ýayWóñ1¿”BBB\¶Üï7O8«£°ÇêNs$~- àãø€?>øƒOÞ ׯÃÉs—êGº¿Ú›·Ã©=¹\_ïž§nSK„ðœF£A£È•^K"}„B¸Qêƒ>›7Ç2ü‰'xúéQ¼2y²GžYg6Rã‘)ü±z*´ŠÑÁHE£ê¼>___6lØP ¯Ï† ðõõµÞ %þà!»ež¨_¯.ÇŽÇÏïÆT±¦Íš‘––f½FZZÁÁÁdff\ NGÓf͘üÊd5j„¿¿?ÿyü?´nÕšG{ŒWjÕ¶Ë“påÊ*UªDNN•m;¶ Û7oÚæ$Ðw7i»³ß¥M›6‚K…­_)ÄI°»ýv3uöXÝq *7€J:-69«,µZ~ÿ3‰ˆs0ïä¹kÔ,»[)D&êvxÒáº+g6rjÏGø)árŽ}Êá „„ õÑDp­®Åݬ[J£5O'ÊïùöqèjëiœÄ»Oµ+ʦ•z­}„B¸¦(Í?ÞètþÌŸ¿€W_{Í£€OÒÎw©Ôª1înB¥VIÚ9›ŠåýX±ãWë6F#L*&£ŠÞ༮EŸ,fÔÓOÙ%üµ½Œ»EÏž½8uê$z}Ë–-%¦OoúÖ»wofÏžMbb"z½ž‹/òÉ'‹8pu›èè|¹f ™™™|·nÝó¦å݃¥K—ØM‹:‘À€¤]»öÌ›7·@™Ùï¾Kff&qqqôíÛÏa½…í›·íèÖµŸ.^L÷hçÛÜLýžr·ßn¶ŽÂ«;Á&^mHN"sï\ûê 2÷þˆ!¹àh¯ˆˆ Nž»æ´¾3¦ÛÝf͚ɂóÙ¶m«Óizžš1cúM­/ ŠsÜîÇV]$÷×úáv4­üÏ]ÛçðéÓ§Š¢Évu+:uÒî~I|mäûƒo9ÚtkÉ]ÍàÞ””+Î/@˜˜È_|Μ9ï1wî¬]»–””äÛØbǼݷÆáô¢C©a4ÎØáñíPj˜Û)Kß®ý–ÿ{0íÛ·£Ë½]3v 'N$ûT*Û[“&w{,7é#„ÂKœ§ÔôéÚµ«WÛg]ØG¹Êmîïàû]GèÞ´/î„Ѥ‚¨ #}úöíË‚…1rÄpëK___}²ØnôÏäW_eܳcÙµkuêÜÅü ÚÏS}[¡ ¢õ+@Hx¿ìþ˜ÆÊÏö¹kqúô)Ö¯_O¿~ý¨[·^Q4ý–ûöÛoíúâ¨_ÅÉð)S«)ŸŸÅ£]|©Rþ ¿ÿíø½êСƒüþ{"QQÝ Ád2ñ÷ß³aÃ:t¸‡ºuëÞæžV£8žÞe2 Õj™ôö‹në˜öÊL0\N{å•W¸páÏ?ÿ< 6$''‡ØØXFŒÁÂ… iÞ¼ùÍt£HÝìt·Š•*[ÿþ曯éxÏ=ü¸gu >ÀåK»¬G«)Å¿Ü !„<¡‘ÿÊÜwÂã™L&ëÕ)õA‹o¿Zã4‡Åë_&¨šùráS_ì@PÕ@þ\ÿ2ï=7†F•Ã1ªæ/˜ŠÉü»«wõíÛ—¿.ºþ@ aùŠ•×å ØÞ ã‹/\_š;4,ŒÏ?ÿÂmÝ5"# [®êðöX•T®ßÍo]*{þÊfù ’‰/*i)Éб3`øX‚>.Ý`¾®Mš4eáÂôÉgñ¦xL>eèÞ´:µ+™s^¾xÝ ÈÈ6ТVh1·°ä2™ësûãy2¦%ªª¢*X¹­5@ù÷¥ÅÎ+ñ@ݺõèׯk×®å…Ü!®åøü«‹/¦\=jn©©™ËüðÃŒù¤uš-@dd$11}ùòË5wTÐG£q<½ Õ€ÖǼ¼~ ÚÚ%ïPðñÑ¢˜ Žë6oÞÌï¿'²råJë”ï  ² üo´Z-3fÌpúy\œõêªÇÀYüÉ'Œ1’;vеk×¼x×##}„Âsî,…IÝQÏò8ô) ×#¸q®ž¿Î”™»X\·-Á5j“¾÷ *†c2Ý8¨&Õ|ùvQü233ùdÑÇôêíÝô±’@¯×³eË–Bç=ºS¹z“´ŒôQUZôA>è|tè 9èŒþy_8@AAQàlb*ëxŸÌÙd2¡ÓÝȉ5cÆtzöìÅÎqTªT‰ýëQTUåÇàÈ‘#äääP©Rez÷îmMò püøqöíÛKzzuêÔ&:º‡ÝA[?þøD£Ñp÷ÝMèܹ³õ¤~ÆŒé<ðÀìÞ½›«W¯LTTw233سgW¯^EQú÷ïoÝqúô)Ö®]‹ÉdÂÏϪU«ÕðpÏópØZûó(~ŒìÞ€Œlþ>Ô­RŽ2:¶:wSAŸÔÔTvìøžK—.Yóhuér/Õ«WgÉ’O>|„]N.½^ÏâÅŸ0lØdee9,kùr­×뉋ÛÁÉ“'Q…λØ=¶'Çrß¾}<Ovv6ÕªU£gÏ^Ns‰9bÄ~ä™õoÖç-€ŸïÍ<×­[¯Àˆ9WÏ/ð¼ÎŽ“e_;z­¸*c™ndùÿĉ/1cÆtëhwÇfÆŒéôíÛük×®xÜ Û€À£Ö€žÜÔ¿h^ÍqÐGQ~ýõ×£SÂÃÃ5j´Ý2WÇ¥0ûÜË#GsàÀRSSÝî/Ëô®}4æâ«3?WŸ{{=Y™Y¤]»NÚõ4²23ÙüÅ˨((ªŠ5'×a=_ýï+ž|êIütsî 4ˆvíÛ[ËšL&æÍËš5kHOO§Q£F¼ñæ›Ô©S€õë3cæLæ~ð.\@£ÑðÞœ9ôèÑ€­[·2þ¹ç0 Ò¼E &Mšdݧîêìú1oî\V­Z…V«eÀ€<7~Ý~‚†ÕÃ8væO"ªT&¦E5 9Ž¿{jݺµ4mÚŒûî»U5qðàA¶nÝÂèÑÏp×]u9|ø°Ýþ8räuêÔÁßߟի¿pXÖòEnëÖ-Ô«WŸîÝ£¹~ý:k×~k÷ØîŽåáÇ døðh4Ž=ºukyüñ!÷O5™oŸÄdDï–¨&Ø~艗̣óFôn‰ª€o}òs÷üò¦ÎŽ“íè•ü¯Weòyòóäuvüø1Dhh¨5Øy3£œNì5??T5Õ¤Ò°`0XGøä¦þ…6']“'–oÓ¦ [¶lfïÞ½DFFRµjUªW 4Ô>íî¸f_{r,Oœ8ÁC $$$Äíþ2ô)x>£šr­ÏÕi/˜§¥[σ€\£y‰ªšŸÓJ–ÁéI鉄Zµjåp½ŸŸŸ]ÀeÙ²eddd°eëV4 Ÿ}öóæÍcΜ9Öm¾þúk>Y¼˜ÈÈH¶mÛÆsãÆñKBãŸ{Ž9ï¿O=ÈÌÌdí·ß2aüxÖçåXô¤~K;×®]KÍZµØµ{7ªªòÞ{ï±lÙ2†wý»nÝZÈW_}E×®]í>ó,£Ö­[ëöW` ú!„çŠz$;“&MrÜ™6mZ‘<Žªª.¿;IÐÇ ‘QØ»|6!@ÂÿÎX—¿ÙÞó“~qû=÷Gq7¡Ðž}vÏ>;®¸›QÂøð÷orIÉKd^ Âká£Õ¢ÉPÑd]F£Ñpñ¯+(Š‚Áà>ìc›ØÔÇLJòåËÓ¨Q#Úµ³¿ÒÙ=÷tÄÏÏÏ:Ú䨱c<ôÐ@ëý»ï¾›øøŸíÊtïMh¨yôKýúõY½ú ‡AŸC‡òðÃX!nÓ¦ «W¯¶ rôìÙÓ:º¡U«VìÚµ“ž={YëÏ?ºC§Ó¡×›s†ùùùÑ¢E Z´háv8rñj•‚ýXû󄕤C½Š$üög¡êsdÈ¡v÷Û´iËîÝ»hݺ5_|ñ9­ZµB«Õb2™øùçŸyøá‡Ý–øóÏóôîÝ­VKHHݺE±zõé"îŽåÑ£GxôÑǬ£îZ¶lEË–­¼êŸQU0OônÉ'±y¢wKºµˆ¤‘æÑ¡¨ *øú•õª^O¸{~yÓ?wû ¾V<)㌷¯3G£œ¼qbï·”¯ÞUU1M Žì‰§I‹»¬#|\|ÚµkOÍšµÈÈÈàï¿/rüø16oŽ¥J•*<ðÀ”-kÎåî¸f_{r,{õêMHHà~iµ4¦)F¾~æÇ˜4Ë0Ñgç™™IzZ:Y™™ädçðͲIæàIï°€k×®\>Øéz[_ÿï|üñ"Ê™_'xeK—Ú•òÚjתmîkÏ^ ëú²eË’•FÑÄàÁÿfðà{U¿åïU+W²|ù üuæÑ›ÃŸÎ!3rÄH—}èÜ©3K—,¡[·nNÔ»uëÆwëÖÑ©S'·ûB+WïBU®ž;‘}¼PµýªJpGˆÛÂÕó½÷Ìe‘«ª¨¨œ?ŸBµj¡JH¢]ãJnÏÓ¤±åËÛ_ú=55•   ë}23íG»T®|#a§ŸŸ©©©ëNI¹Âœ9ïÙ-óñ±› ¹1uÊò…ÎòÅÍ‘˜˜¾üï_ñ믿Ҵi@)’\"‡/ólÞˆŸóé*½#C¸š¡¿éz.\¸@bâï\¹r…¿ÿþÛú\ ¡R¥J?~ŒfÍš“@xx˜Ýô+ge²²2í¦\Tªdÿ¼pw,SRR o™TÅ~*°Ieç‘?¬#}†õjÁŸ»g˜W6¹©‡*ÀÝóËÛþ¹Ú×PðµâIgFçÓ»BCC¹výááánÛsîÜ9*U®d­+$4ÄÞÈ‚ÿ‹•ªªöɼl‡’ºzSVU&<ïòËš£<®†ªÖ©S‡¡C‡qñâ_üöÛo$&&¢×ëiܸ±Ó2ÎøùØ?vH ñ¿›ƒÕBøxc<}Û7ôº^Ûö=z”}ûöÒ¶m;êÔ©C`` Þ¸ª_›6mÙ´i#M›6cÿþ}Ö<ž”5 Fë>Ì¿/ÝKgS\¼a2ÌéÓ¥Y º¨5@1¯¨ßý9Nn›Fý袜ïíúùåMÿÜíkK}Þ–qƓי'9TܱLéºöç~ÊVkÑdÄh4b2˜ÿ¯šT>ŽT©R•råÊóÑG7®éî¸f_{r,½y.;MälÊÅ'ï}!פ¢¨ (y¡›$ÎX¦,šr&&nÚ´)‡¦GÏž×ÇÅí kWóëÝÏÏE¹Ñ&U5¢×ëíêöóӨò¾{÷h¾[¿£GŽ·#Ž»v’‘‘É<àqý–¿F# '~µËÿæ‰~ø!C†²cÇŽëvìØÁÀY¾|¹ÛÑ>ôBáî{S‘}r²³P]d,ÎÉÎ*t½wB9!þ ôú¢¥QT\½yeg$“}î$J•(®žûž²M›c4Ñj´hàÆe»ð>£w‚ƒƒIKK³þjž““S`›äädªT©b]o;bÁVHH™™™”+W´—=¯X±"+V¤Y³æ\ºt‰eË–*èS¹|Î(–K¿Vµøxc<ëT§R€Â ñD·ªÇÙ¤tª…8­ã£2lØÖi(ÙÙÙÜØ~÷î] 2Ôº’““íÊW¯^ŒGUUjåMß𤬿¿?Öý›”tÙn½»cl4* #Š5°óŸè,ÛrˆÿD·àâž™¶­Ýþ› üœ>}Êî ¡»ç—7ýs·¯‹ªŒmÛܽΊBD@ e6ßÿq?•šc2˜0¨F*ªÇŸ?œÇ¿þõ¨ÝH40­÷Ý—Âì·¢x®ÚrvÉvŨÇÇLJÏ?^‰‚jNÚ æ˜%è“w/­Œ¹N/uþÐCY´èc¢££ ´ûÔ©SlÙ¼™¨nQÔ¬Y“Ë—.Q£F ÒÓÒû˨;zÛew7nÌÝóØcqüøqàuý5kÖ$õʪV­êl÷9Ô·o_»¤Íù9[’;§]¿î²¹d»Bg?*[–ÉÏBˆ;ŽúA‚#ë3gáGW G›´CÞ„‚‹?~lùÚ‚Bô) Y³æÄÇÇ£×ëÉÍÍåøñã”)SÆn›¸¸¤§§“››Ë‰'¨]»ŽÓºÐëõdee±wïOv9g cÙ²¥:tÈÔ»~ýZ¡nL½Èªì9y™°²:¾· ëWäé¾­xºo+Ò²õøûºþ’ÊñãÇÈÍÍ%33“öÛí???Î;‡Á`àÒ¥K¬_ÿ]:Z·nÃîÝ»iÕÊ>G‰»²Õ«Wçðaó¾¸víßÿ½ÝzwDzE‹–œ9sƒÁ€Á`àðáìX±Üãý–K¶c½ý»»9àS·óCv7“þO´¾Zj¶¼‡›½Oòwúô)Ö¯_Oÿþ7»{~yÓ?OŽ“·et:))ÉÖdĶé—/a¸˜LpÑÝœ+çêÅd|”$tÍù3,WÐÓ÷¶Šdgü9îmyKÚÙ¬Y3vîŒcÁót‹ÈÈ<üð#vÛ4hÐ%K>Å`0IŸ>1NëÚ½{}´£ÑH5èÛ·ßMµï¾ûîgÛ¶­ìÚµ“œœ4] À[]WáøŸ©ü~9´¬\ëò²e|‰j\ÅmùÞ½{³uëÖ¼D´ uëÞE÷î7riôéÖ-›Ù²e3!!!´mÛ®À—Ü °oß>7¾Ûn¹»²}úÄgZÓ±c'þúë/ëzwDziÓ¦ìÞ½›­[·`0ˆˆˆ ÿ<Øk7˜TP±nge™ÀP0Ðà£0]l“[X޳í%¸Ý=¿¼éŸ'ÇÉÛ2mÚ´aÅŠ<÷Üx»²ž¼ÎnFþ€EónØ¿å‘~ù8í{?êqíÚµ# €Ÿ~ÚCrr2F£‘ÐÐ0Z·newU@wÇ¥0ûº(ž«¶4ZÇÓ»¾™ÚÛîþ€)±\¸÷šR Z•ª¶qeÞ‡óYºt “&MâìÙ³”/_žN:³øÓ%T®|ãýåÑÇóÎ;oÓ¡½9Ñþ=;²rÕ*‡Ó¯lY–Í÷!S^{iÓ¦“žž†¯/óç/°®÷¦þGÌÌ3èÔ±#z½žîaÎû8ÆfßsðgÓ¦MtéÒ€+VØM[uWF9 !D‰u»®æ.§2uÙ+jL«~øý)bŸ·£¹¥JN®‘òåOBQ:8únu=5™lmã7ÈHŸÂÚ2÷—ë{ŽÝs›Z"D)äúü} ÖPFzÁÀö ‘páG=e-R9Üó+Õq«tí5ÌñŠ–7þ<¸ömTý5Žüt”–ý_¹= +åß*8 ø˜Ò²K}À@ëìê]Àº·\·‡V¦w !„pC‚>…d4)ÄL8àpÝ騱l™{GŸØØXFEn®yš„N§cÙ²en¯Öà‰ô´4¦MŸÎÆIMM¥Zµj 4ˆ1cÆx”Ü1""‚óçÏê±]•õ´Þˆˆëߊ¢D¯^½˜2e ¡¡¡.Jz÷8·ƒ7}¶lgÛ€   Ú¶mË»ï¾K… ¼ª÷Ÿ$¸J8GN%<7™àÂi€Dª5n ÀC};gó„(ð¹½Ê7É·¤øVC í=Ÿôåôê]¢ØIÌG!„;ôÉãíÔ.£ê|~ž_`utpø‰eìØ±,X°€Þ½Íg•ß|ó #FŒ`Ù²e´k×Ϋ6å÷‹/Ò´iSâââ äúõëÌ;—3fðòËwÆtÛ€FzZk×­còäÉÖ¼wŠÂfìúŸžÎ'Ÿ|Â믿ÎüùóoªÞ;Z¥ž4«TÜâÖ‘`(i<¹¼(’ÈY!„;¥þ“b×®]¬_¿ÞërUÁ¤b½¼xfOÌ„ùqø†áFííY;»³Ó:FÅܹs­€ðÖ[o1iRá.ÑkkÛ¶m 2„råÊ¡Õj Ò‰ñ— IDAT aÔ¨Q|ñÅÍ] ¨¸•-ËÀ \q§´ bĈìØ±£¸›"„¢ÑhÍW‰’[ ¼i%'„µRôÉÉÉáÙgŸåwÞÁd2y\Î`T0™TL¦‚™²+4CDÇשÕs.#‚rssí>>ø ±±±ÖûéiiŒ9’† 2bÄÒÓÓ­ë"""Xµj;v¤V­Zvå"##ùðÃ17ÚV¡GŽ±Þ¿zõ*C‡¥Aƒ 6Œk×®hO§N8wîçγN=;tèýû÷§^½z´lÙ’¯¾úÊ®Ü/¿üBTTƒvX¯»¾9b0ðªý;väÏ?þàìÙ³ÖK¡‚ë}èªþˆˆÖ¬YCÓ¦MiÚ´)[¶laçδlÙ²@=¶SµÜí7WE±›šg[¯«~¤¦¦2hÐ Z´hÁ²eË LB!œÑæô‘[É»IN!„Î(y±ˆRÿIÑ£G¾üòKV¯^ÍÈ‘#ÉÈp|ÙÜürmFúòÅŠLF0Ád‚\“÷¿À(Š‚N§³ÞŸ9kÏ?ÿ<ÇŽ£{÷îÌ™3Çnû_ý•­[·²`ÁFe]þÞ{ï±öÛµ´mÛ–)S¦ˉ'ìÊΚ5‹.]ºO¯^½˜1cFöDEE±sçNÀ<2*** € &ðÔSOqìØ1&NœÈÔ©SíÊ-Z´ˆõë×3bćõzÒ7[ééé¬X±‚~ýn\ÊÖ“ötéÒ…mÛ·°cÇk,œíCwõ9r„={öðÎ;ï0{ölÆÇ³{÷îõØr·ß1üñÇ,\¸=z8ÝÎY?¦OŸNLL »ví² ú !„îh$èSbo2½K!„;òI´jÕŠ?þ˜Í›7óÑGY—oZÿÓ2F£å¦’€QU1šÌÁ ƒÑó ODD„ÝÍbóæÍÜu×]øøøÐ³gO6mÜdWnܸqлwokBh€¦M›²û‡Ý,Z´ˆ *°|ùrbbbX»v­u›íÛ·óÐCH¿~ýزeKvEEE±k×.Àô±Œ’Ù±c111èt:>4+W®Ø•{~ÂèС[·nuØgw}³ì‹5jйsg~ÿýw»©ož´àÞ{ïe{^Ðçûï¿§[·níCwõ?Þš`úøñã {â  ÔcËÝ~sÔÿÈÈH¢££9þ>ž¹sçæ)CË—/çøñãüòË/ÊU©R???RRR¶Ï]ßÜ%*ö¤ý:vdܸq¤¦¦rôèQÚ·oo·ÞÙ>tWXX>>æ—Rp°ûË‚»Ûo¶ÎŸ?ÉdbãÆ¼÷Þ{ü÷¿ÿµ¶ÇgýHII!00€ÊUª¸m£BaQ£º|n”Trl„B¸SêGúlݺ•AƒñÈ#°hÑ"ëcW²Îl¤Æ#SÈ:³£Ó‘>*FÕù.öõõµË»bkü ålâYΟ?ÏùóçILLô¨oMš4A¯×X–––f½öÿìy`LWÀ3Y&±†¡APÄN‰¥¶ ˆÐEK­µÔ®¥Ekßµ–R„~E7{QÕÚRÔ–¤(E­µ/¡ª„È*ËdfÞ÷ÇdÆL2{&‰åþ¾ojæÝûî9÷Ì7ygÎ=ÇÛ[ŸG'5%ŤÓB¡PP«V-¦M›FµjÕððð`À€$%%Ñ­[7Ö¬Y“í¼GqÚ–ôôtJ•2]nÉѹ٣?h“@רQƒ°°0êׯŸÍ¹äèø2™ýÛ÷¬Ù-+r¹œN:ѧOÆŒc·<€’%KhY@ @ x~‘Ðæ~á> …‚%K–0a«û¢ž<ˆü‚Rõkйf-JÕ¯ÁƒÈ…”,êÎÚƒ—ôýÔj­ÃG£–PªÌ·lÙ2FŒaäø1,ã®#88˜+W¯ T*Y·n>JÇíÚµcÉ’%DGG“‘‘Á½{÷Xµro½õ–¾OëÖ­Ù²e )))ì 7JplHëÖ­Y»v­Ñ¶¨‹/òúë¯Ó°aC–/_žíœ°°0RRRˆŠŠ¢C‡&ÇutnöêÚ¼>«W¯Î¶µËYãÛŠ5»™£oß¾$''›tZ£}ûöüðÃ$'%é#µ@ @ð|óÂoïjÑ¢…]ýSÿ=F߯p ê mjWaB¯f¨5ÈI†ÊB¤OHHK—.eذaúü+nnn,[¶Ì¨ª×øñã3f ‡¢bÅŠ„……Ù¤ë¤I“øðÃùþûïINNÆÛÛ›Î;3uêT}ŸqãÆñÑG1wî\6lÈ’%KLŽÕ¦uk&ƒ‘ÓcáÂ…Œ1‚Çm‹ÓѪU+Ú´iC5Ì&hvtnöêO¦î ,°ËécÏø¶bÍn–øüóÏéÛ·/-[¶ÄÓÓÓæóFÅ AƒXµjS¦LaÓ¦Mú6???«Ûè@ ‚çë×®q„øxÈR‘Ùad2ŠzyÑ"¨•^®œ¯òÙÌÕ¥ÐúðP{P¤˜q>ÔÔTªT©böä gO}‹æAA¸»»›ì³k瓹q¬ñ4žwßL ¾GA_®>@•¦­yü_4“}ù»üT÷ÕÚOd™ÿYûy[>že:¹° o‰‰‰¡Gú„Î/*=¢U«VÙªx)•J~ˆÀß¿¼þXäþ}øøxãææ†L–Y½E.CnDR‡J­æÁƒ‡4nÚ €êµëšÕáÊ•+¸¸¸˜½n€õë@ @à(—/^`ïî_)V¬8ìø1ÕRRS‰‹{DÛ¡T ¨ž/ò/¦î­ã’&Oå׿µ‘>ög%yAI¼ŽWZÄßIdêü(¾«Ü¯rI>zŽ€’>h4O¼µI[¾]ÿ¤¤¤ðý÷ßÓ®]»üV%_¨[·.‹-¢I“&,_¾œ† fëc®Ú˜@ @ð¼ñ׉?)í[šâŋٜïÓV222ðP(øëøŸz'L^Ëtžž~{—=ü}™²-ZáR²ƒ>x —’~ÈÝÜù7ú2ásÛiwt‘iÚLÿ‹‰~Χ^½zÔªU‹U+Wæ·*ùÂܹs™–æ¯î°~F25Z'E ÌWÉ9’\€É36ðaæ<Ê|íeü+ð01YÿÚ×5wÃ$²Ê»×1¿w»áÓ»×­áÎÚMÔÝž#޾ßvq=æÁ \ypšuÇg:îø‘$d2•mÈ7zõÊr?Œ¥í¸ÍÈe2är•ŠÂ RºdaJy¡iuíõ%õ@S}•¬Œ 5¿.}™Ð×r]7kˆí]@ à™#>î¾¥­;sîýw7ÇNŸM›6àïïÀ¥K—˜1c\ºt‰´´4ôm›6m¢[·nÉêÖ­/aaalܸ‘îÝ»dÔ¾qãF¼¼¼Læû±I£Ýî#iì»aVi\P«¡Gh]£"6j x×þ@ßïþžÉ9ÒÏ µö¶UnaWÒ¿ ^l˜ÛˆøÍËayׯß@açËu‡HKK'%ù1)ÉIKK`ñ§ý–aIžß»Ý¸³vÊË׈ùó$~ïj×ÒøO7––æ\Gßo[‘}Õ’ÑÁÞ,ÜËè`o–œ¹HïÀŒ—¹Máî¦_g†ÿõ˧ÏËÍá&—áî*ÃEÞ…\)SØ’ݨXBÁ__WááÛ@&C–v‹÷~4ü2ߟΟDçº~–N@ @ðL¢Ñhxôð¡Ùöâ>>N‘Ó­[7âãã9}ú4øûûÏÑ£GñõõÅ××—´´4.]ºD@@€Ã~ø!3fÌ`÷î­„„¼ÉªU«ð÷÷'--^߮ÙÛÊlA¥rAì;r•Jƒ2CEZºÊ(êgxÏæ¨4΋"/æ]¹¯Ï£Ç…Y1Ï0‡c‘>eü+}ËèØÐMMöU©sîl0%ϫǻz‡OɆõñêñ.*µÄ§º;M®=è¢\bÔE)R¬åK ªo!ª”,ÀãëŸÓÿøQV6† 7ÿ ;,O’$d™[Ю\½†Z­A¥Ê@¥R¡V«©ÿJ=}_™\†¤¶¾,11™LFáÂÙ×ERR’Éã†\ûýØ“HŸ …‹Ä×»¥| £¨ù¥^?ÎÆ…uè9x›¾žô˜ú¯ÅqïÝ»‡\.§dÉ’ÙÚbbbL·WÐG @ Á3Z­F©T"iÌßð)•JÔjó[‚ìaÈ!̘1CïøñððÐGþè>¾¾¾&óýØKXXiii„„tgÕªUúmeZÇO4aaa|øá‡NÝVf+jÔj‰V +g‹ºÐ¡ÖH)þ²Ód.Zšâ 9žYœ>éOÞ{Whüj[i5:zxŸC²îÜùWWãØˆå‘®$--””TÒÓÒP¦ksÉÌ›îxÔ•)yñÖê>1žÄ}ÃZ wïÍ´¹›HKKË‘.ŽÖ¯cø–s@M|y5¥zì4Ù¦Kx»KÔœp‹-S_‚Ô›¤¥ªi×Óª^sfƵk×Xñõ7øùùéß¹s‡!ƒþë.«c˜FÒGK‰HÙ1¿žÅö×>9•Gš@ /.RlíÐ1mÚ4† ƽ{÷ðòz²}(>3·Ð´iÓr,#,,Œ{÷îѯ_?NŸ> o+óððÀ××—3fdÛV–d¨]Qk$¢N\ËéS²XAꔦlo*×všÌ…½¹µ€è{¿àUi•ö§€»œt•ÖñóråJ4oR!cn:$ëëƒÚŠXn.àªu¼×õU‹çäįhJÞµ›ð{·ºöÆ}ó:î¬ÝD•®½™úI·Ës„˜+7xxí&1ª¢Üõò$¦TA”)DÕ´[º¾=ê±p×tÆ–7IÕuíú @Õ§V«Q©Ô¨Õj45õêÖA.—e¦·L£Fùåç-lÙ¼™ž½{ãY ©))lÙ¼™ AëòJù˜Heì"4ÈejzÎ8wWÐgÆaî±^=®ÿ÷=zcFbÅ×ßàååE||¢ÖÈ}ÜdÛÕÝ#Ø1¿žMŽŸððp @FF …?lØ@‹-r¤ß«M³qã&Ê•/¯?¶k×.ú¼Û›µëÖë+ܾu‹nÝÞá£Çr$³„7ÆêŸëÉd*TˆÐÐPfΜEqoë¥ ÇÊolÕÅR¿§i>@ ÏjµuFj•ù;`uæßØÎD—ÏÅÖãö¢søœ>}›·•å*µ * 4}%{$OA… Ó§Œ%!!///F|ðK–.âÁƒ”(Q‚/¾øÂ!™ÒÝÝh”gyå mn¥ó»rCJ§R“ax¸»¡Ò¡mº *Çæ—š®âÓOÞäú…s|ر1r*¯Êöúö]{S¥kïÜWÄ“‚nà^í“më‡ú0úSXøí)Vvmï’¤ô©XÁ_ïÒÑÅyésûèúÙàøõ+W޶íÚ³{ׯü²å':wéÊ/[~"!!ž¡VÏWªåOte”éCÝdÈd\djä.î€ 9.܉ÅZ6±Úuê0iÒd¦OŸÆ'Ÿ|Ì‚ù øä“¹{÷.ӧϰª—-§O&ovyÇ®þjÉü¦8÷‚ÞT hbÕñΰ¡CøæÛïèØ±#?ý´™¾}Þå‡ hÒIJGÙ;vdïÞ½ 8P,âàAˆŒ8häôÙ»w/íÛ‡˜&G:9’’’øå—Ÿ;n,ß~ûÓeå&ÎpÖ‡@ óQ«Õ¨Õæïîµí¶—~¶ÆŒÚ›0#'‡‡‡¾ÝÑ>[·n$>>M¿],¯¶•ÙB†ÆŽžÎéS³R)>|HµjÕˆÕþý+“ɨV­šÃ‘HOì ùÞ6ª4ŸK¡âå(^s×£†âíß”âejã"—‘žñn®øfnïJWå,‰I‘Ì»úœ–bZå9B•— >ñ¸5÷áüÑ5LÈ ì:¿o^ŽåH€]ºtE£‘øxÌùÃþ eÚ±sçÎ1rúò.ƒƒ}Q*µÑcJe:þþå¹íØV²ü”giî¸£ÝÆè>®áðšV,ª=,ÓöÍ1™%ÛïüóñqÃ$R™Ïí©ÞåââÂ+¯ÔçQl,Ÿ?Oš5yå•úÚë„”*mÙª‰éÔ‘Ë4È5Aæ‚Fr'6Ñú¶1^]ºtáæÍ›ìܹƒN^£K—.6ée r§Œò “žžÆðáÃøtÖ,4v|!¨Ô24 Fʶ¸DÝðk: í–¢²”‘‘aäðÑѵkWŒÐ¿NJJ¢¿¾TªX¾}Þ%99ù‰,oÖ¬YM``Ê”ö%<<€ºuëróÆMý>ÀnßF£QÓ¾}’$qçÎRSS¹tñ" ˆ‹‹£WÏžTð/Oï^½ô_$:YË—-£UfÙÈG±±¼ÕùM*VðgýºuÖm¦RQ°`AýkK² lÀí[ÚŒö7oÞäÕ&­Îß–¹lܰªU«PµjvïÞÍÁ¨Y£z¶q ·ªÑÑÑxyy‚——ÑÑÑzÇONÿ^›3gŽQ….]þ]„‘î¡{­‹@²™\†Wqod–ê › CíŠF‚ÈcÙuŽíûþbsøŸ¬ßz„T¥†‘#F¡R©¸~ý:>>>ܽ{¥RÉÈŽýÈwóºCƒæmññ)@†Mhм5]‡Î"îæÈåà"—‘ª„.ý»ðvÿ.¼Ý¯ ©¶Ýo›¥rÕšúG•ª5IËPãææ€F£¦\¹²¸£qš&«¼¸ät#yþþås$ÏÑ÷ )ÝÐFŒ¸Êu9l´Ï[T*ʉÿRõÇ“Ó<ÒÏ…BABb ‰IÄ'$>yŸ¨Ÿ¨o7,wo W77Zµ ¦óÛoÓªM0®™6¶FšÓÇUfü¯‹ Üäjä¨ý·ɯjy1§ÛnkW77FÃâÅaŒ3Æf½lá…wú´oÂ/[·±~ý:úõíÃãǶ•–ËÈŒôÑH Êâ+Ò¨µÉµ4ÈÐØÿ¡’ÉdF wîÜ9Œ;ŽËW®Ò¶m;ÌŸoÔÿâ… DFFñÍ·ß1hàýmÚ´&**€Ц6æ®}HIóæÍõ^ÄysçÄù¿/ʜٳd)<ü´å'fΚI³f͹pñÇO˜Îo¤#99™U«Vòúë¯ëY“¥#¨e{÷î`ÿ¾}·mkuþ¶ŒêÔ)Nžü‹óðù¼yœ8y‚cÏ6Ž!#G|Àðáïsåê5&NœÄÔ©öG.™#8¸ 3ß—ˆˆ‚ƒÛ8M¦@ Á󈻻;%K—6ûpwwBÔèK°ÇÇÇë?Ó¦M£[·nL›6MïìÑýȘӒ톘Š02”eadr¹ ^Ž‘Ëí‹&Pkd¨5¯6 MÓšthUÎ!¼óZ$`ÉÒE¨Õj (À7(P †%KÙ%G/O¥AV¬1¨“9yx‡v,U" C­Ò G†‹LFZæ öäxpåi9púLž¿•‘ w=RÓU¸¸¸P²¤r•’{·oY(ò@âë[¹J™cç’£ï7@R¦#ÇEžéìÑ9<Ð:~š¾äÉÕ{©¸‰NpúÔªYõëÑ ~=¼‚B¡0 ´P(6xEß^«fu»ÆW(øûW°ËY”®~âôqÁØnr5.²Täÿý„ä÷*YIäÈõçØ£WýúõíÒË^x§@`` «V­f×®]üï_êoýéG³ç¨Õº‡”-bT-I¨5ZgJm»Ó§„·ÑCÇ®_¥r•*¸ººÒ!´;ÃKÅùø (@ÇŽõ ¡:vz½¿i%‘·Õ:}BBB8¡u.ìým/!!ôçìÝû]ßy‡‚ òúo°{·q‰¸×^{ooöíÝKž=ñðð`ô¨ÑfçSªd 6àúõëLžòdk™5Y:ZµnÍo¿íÑÊÜ¿Oï¼²6kã2v,… ¢Ch(çÎeàÀA,X0Û8†>ò^{ …BA×wÞáQ¬ý¹zÌÜVŒˆ u›6N“)@ð¼QÌ»87®^³ú(æ]Ü)òV®\I||¼ÞácˆÎñÏÊ•+"ì0²™LF±âÞú²Î¶¢‘äìÛö5û¶}Í^ƒ/ÿ•¤ØÛܸqƒ²eËâêêÊâEKquu¥lÙ²\¿~Ý.9:Ô@ν[ç8{ö*Q§¸wû Ñ¶É@&‡´ÌÔN[ô¢Eýòçô\ŒQÁÅLK|CÌÌœéÖä9˹äèû ”¦ÍYå"CY¥‹pÉt¹È FOm¤OzÎ>çÎ_àø‰¿øóÄIÒÒÒ2ÿš–ÊñqüÄ_œ;Á¡ñåvnJÏ#ãÉ|]äà"“p“âq°yÌ6¤2o¡‘|IîÈeÚsr[/[p…:¥Ç§_¿¾tèÐ÷ß’•ÜRrç •$!“@’{}TjÉ4 ÉPÚáô1Lökèô‰‰‰¡´o)ý묿Xøøø˜¯I“&Lž< µZÍŸþÉÿ¾Ò–ŒkÔ¨1#>ø€´´4~ÿ=Š3gêϹÿ>… ÀÓÓ“émPy+66V/Û×Ä]kÉ‹­ÉÒѼys†JÜ£Gœ>uš&MšØ4[çâêªÝ^¬˜ñÅÖq±råJÎ;˹sç¬ö·gŒ¦Íš1bÄ(•é?~œeËW8M¦@ ÁóF¥*Uò\¦%‡NnäÕéÖ­»wïÖçÊêpÒEæù±¹x·°ˆ IDAT\žùaßé!#-¶W¬X‘k×®Q¹re@›ˆ÷öíÛT¬XÑnAûC{Ò¿‡)å]ˆ~ïõ ”·éÉ1¨Õ°ußyÄ=ƯT1Íß⌬,Ú—íuVÇŒ3É y޾ߠÍÓóû¯¿ñ»M½³-ÉÞèÜÆMáIÄWƒ9ìéFÍúAÔzé= €¼01ªê\:üß²gÏn¼÷C‡câ¤I6242ÔêLwY¿ŽZç BB-™ÏÍÍðððly}ÂÃÃõû7Š/ÎÉ¿N³jתŰ¡C©Q£žžžúã5æý÷‡ã_¡‚Qžooo’’’ðòò"%%%Ûˆ¡g¸D‰Ü¿???³KX“¥£páÂÔ¬U‹/~A`` ÍaºöÌÅVÞíó. ê7 GÏžL¬PÑ(¿PNÇP(Ú’}'Q½zu}gÈ@ <›¬\¹’þýû›0Ò9~ì0’Édxx:'*ìeÙ.\˜£ñÊÔêî ÆcœŠü€r¯ôçÕ¶µØÂ½€Ó.†2òZ^¶&ÇßïqÃ;;ªÑsð±_›m+ ”ìÚ€y§Ž]¼ðÛ» ¾új“§L±Ëë©RÉPK7“™±õk>)A¨VƒJ#¡QK(ÍWä›o¿cØÐ!FIƒ ˸ëh×®=W®\F©LgõêU„v°½¼zhÇNüòËÏçÁ aû¶mF¥ÛA»Åhó?’’’ÂŽíÛi“¹ÅÈ:„²jåJ”ÊtÂ/¶Y'Gdµ jÅ÷ß}G›`ó}r2¾­\¼pÎo½E£FùòË¥N#8¸-«V­4ÚÂæ ™@ ‚g—•+Wš$š6mšS·”=m¼úÆLºÏøÇäãÕ7fZÀ’$Q¬Xq49-ñe$Q¼¸7’$å¹<ÀÞédw¹v¥$G­­¨Çù³·9u†6µ«0¡W3Ô]N* ‘>;vdÙò 8@ŸÿfÐÀ,[¾Â(úgÒäÉÌ›;—*•+³fõ-³YÏV­ZQ @lÉ[·iƒB¡0Êç0iÒ$<@µ€ªlÛ¶•3Ì_H'MžÌ¹óçhP¿>M›6µY'GdµjÝšŒŒŒlù|œ5¾­„-YÊÐ!ƒiÞ¬)Õª™íg¸=Ïž1Úkç×ÚÀAe«L@ @`I’¨Q§.iiivUp¶FCZZ5êÔÑ;}òRž@`ˆlæê‰Rè+ñÐxP¤X £ÆÔÔTªXØ+{áìi¢£oÒÁì–›­?ýh17Ž9žöófÜœÞc÷ .Ü{@u_mn eþgíçm™4ß¶ÝóÜ¿Ÿ®]Þ&ê÷Cù­ŠC”ðñ¶šã(¿Q*•ìÛ½ ÿòúc‘û÷áãã››2™™L[þT.“iŸ„ªÔj¢‘d|;§½>W–„6Ÿ³î_]I4’ Œ©^-€:uê²nýúüVÅn–/_Ƽ¹sr4 @ ‚üÇÅÅ%O%y-O áôq˜é‹¢ò[…†è[·ó[‡9òCFŽü0¿Õ@ Á ˆ6˰ˆFÏ!111y"ÇRân[ɉ®9‘¯K"oêñ´ºXšc^Ï}ïÞß(áãÍÞ½¿9mLÃ9äÆútƘ¶¬³ëׯӸQÃ˲4®9[™Ó---9sfS¯nÊú½Dhh.^¸­ß19†9ÙÎ 7ǶDJJ õêÖ±ØÇÔ5Æ·TI“}“’’x·woÊ—+K¥Š–ìñN×.DDDXÔM £ßú—ÏzA®Ñ¼y³<‘ãŒ$Ýy¥«)<Œ5ùxÞyZæ¸zÕjzõîÍšÕkreüÜXŸÎÓ–1öìÙMûöÎÏçfn\[tš4q")))ì ÿ•«×®óö[o3tèlý–.YjU¶³×`nŽmޤ¤$ú÷ïÇ;w,öËz}™;ïs>ûl¶É¾ß|ý5eË•åâ¥Ëœ9{???¾þúëÜPß!röùeG[?cöÌ9?Ö!À§³f2eêTx·Þz›³çÎsìÏã)Z” ãÇëûÙjkKö[¼h!#FŒäï 9zìO|}}8à=“ãXÒÇÚ{d‹®æ®5¶È·f«¬ä¶>–ì1uÚ4>•óJ¼Á‹ˆS¶w¥§¥"YÈXœž–êð¸ÏÂyÁó€R©ÌorÌáÇù|Þ<¶mßÀ£Ø§ã¦Þœ¥ë¯¿ÎØqãhÚ´©SÆä.wïÞåìÙ3?q’† øï¿ÿ(]ºt~«•üú,íÙ½‡qãÇ=Uãž8qœ÷ ॗ^`ÀÀ 8ШϩS§(Z´¨Óe[#7Ç6G—·ßbqØìßoó9'Nœàð¡ßù~å*“íûìgþçó)P ýúõcÔ¨œ¡îSK~Ù17ÖL~¬ÃãÇã®PP³f-"£Œ«æŽ?Wê=©(j«­-ÙoóæÍLš<777† Êÿþ÷¥Éq,écí=²¦«¥k-ò­Ù*+¹­%{Ô¬Y …‡'Nœ AƒecD¤@ xæ9|ø0o¼þ:ŸÏ›ÇØqÚ?4u¡Å†!ÆIIIôï×—J+зϻ$''ëÛJøx³|Ù2Zé_oܰªU«PµjvïÞÍÁ¨Y£:eJûnt®áó5kVØ [¿“'OÚ!„òåÊR³Fu6mÚä®bcy«ó›T¬àÏúuëŒl1vÜ8>Ÿ77^Ç;dϬtïÞÈÈHöíÛKï^½¬ÎI7{l¸~Ý:*ø—çµNxøÐôVKv §Li_Jû–"(¨%Gþ‘ã¹››_ÃÀ@¢£o}“†VíaŠuëÖòöÛ]P(téÒ•uëÖµ[²‹­63\W ôëÛ‡reýhѼ§OŸ¶:WSëÓðy\\½zö¤‚yz÷êE||¼Q?sŸkÄÇÇsùòe6l”MfÖ×–Þû¬Ÿí¬ãšàüùs4kú*ïtí¢Ÿ×¿ÿþKýúõ-ê¾há ¸Ís2·žìù Y²Wn®ã &R­Z5‹ö0D©T2~ÜX>›=ÇlŸë×®S®|yýë%KrñâE³ý­­AsŸkß æÖ®¡m-] Y¼hŸ}:Ël{~ØÑÔgÁÔšÛ¿çòkþòËϼùÆ›&ÛTx+¦m«­-Ù/55•””}[zz:iiiVÇ̪µ÷Èš®æ®5¶Ê·Ö–õšè¨>–¶{Ùc×_{ŸÞbv,@`9€+Æ Až‘ÕÙ³mûv}„‹.¤Ü0´|îÜ9Œ;ŽËW®Ò¶m;ÌŸo4žÂCÁO[~Ò¿>uê'OþÅ‚ù ø|ÞÖÞ#KºZºÖØ*ßZ[Öë¾£úXÚæg=š¼ú*;fv,@`Œ¤sôÌ\=Q:~îˆtþÌIéöíÛFË—/K–øûÌ))|ÛV)1!^JKM1ùøeó&³m–ÏÊyâ!ÏË#1!^ ß¶UúûÌ)ýã«…ó¥×|/ý²a­´uãziÛ¦¤í›7H;Ú(…oÙ$ýúóúÇöͤï¾Zª?×—/_–®]»–íšcÏõG’$ÉÇ»¸4oÞ\‹í†Ô«[GÊÈÈ$I’>| Õ¯ÿŠQߘ|‘‘!ùx—=zdrì¬Ï³Žc ¥Riv kºÖ¨^Mº{÷®$I’t+:Ú¬ I’¤yóæZl·ÔfÈøqc¥!í¥É“'™ícjNöØðÆ’$IÒ£G¤êÕLö³d—.o¿%õêÙSŠˆˆRRR,ÎÇ›Îoÿ¾}RŸw{K’$Iýúö‘öîýÍbSìÞ½KêÔ±£Ñ±N;J»wï2ÒÅ’]l±™áóš5ª[µ)ݳÎÃðõ+õêJqqq’$IRRR’T»VM£~–>–ì3xÐ iË–Ÿl:×Ò{ŸUKãf}~+:Z’$IJMM•êÔ®%I’$•ðñ–† ,ý÷ßRjjªôå—K¥‘#>П7hà@ißÞ½&u6'ÛÜz²ç3dÍ^:œ½Ž­É3D¥RIuëÔÖ_¿Ìá[ª¤¤V«õ¯ÕjµT¦´¯ÙþÖÖ ¹Ï‰½ß ¦ž[ºûx—~X¿^ í i4‹s65¶9œeGSkÆÔšÏª—%Ûä×:¬T±‚”˜˜˜íxLLŒÔ³G)===[›5[[²_||¼4tÈ©‚y©þ+õ¤uk×JåÊúYÏ”>¶®uSºZºÖØ*ßÖ¶¼ÒÇš=¤—+U´ilàEÂÔ½Õù3'¥çŽH3WO”DÉvùm©é_t´q$4^\¶nÛ®f9d[›˜˜Jû–Ò¿vww7j÷öö6ùZ÷‹e13áÐYñññ1y<îÑ#V®\ɹsg9wîœÃºÆÆÆêeøšù•W—ß´vÊ)ƒ¡QÃ@V¬0NjmNöØP—#¥H‘"f« X²Ëò+è߯?={tÇÕÕ•í;vR§Žåê,Ö07¿¦Íš1bÄ(•é?~œeËWXìoŠÕ«VsôèÙÂÞ‹)b”XÕ’]l±™!±±±xxxØ5WkÜ¿ŸÂ… àééɃŒÚÍ},¡R©ˆŒŒäó,‘æ°öÞëÖ¡½ã–.SЮ³‡™¿T»»+˜={6Å3Çìׯ¿>Å7¸|å2m‚ƒíš“¹õd¨»¥Ïµy9k®UGôFFˆæÆŸ&»åöne*^¼8wÿ»§¯zòïÝÿŒÚ³^}]|·Ï»$&&Ò£gO6l´œëÅ’®%J”àþýûÙnn,myË ß|½‚F³âëFÇ­ÍÉÆf& NLH dIÓ%ˆ-ÙÅÛÛ‡í;vpãf4Ÿ}6›ž=ºÛ$·nÚúr±©©©ú›GKóS(Ô®S‡I'Q½zu½#ÅÖ÷øÎ;œ?ŽïÞ5ªÄsçß»œ;w–ÿý×&»Øb3CJ–,i6i»=ëÓooo’’’m)_///›Ï5DZcÇ0›4kbikï½nZ7›œÌï¬ôôt|3ÞÞÅr^né˜>m*þþÛh‹¤î_K²Í­'CÝ-am^ÎZÇ9­î·{÷n:„v´Ú¯råÊ<ˆ‰Ñ¿NHH¤rå*fu°¶Í}N¬}'Ø‚¥ë1ÀW_-cô˜¶J= v4·fL­y[É«uhŠ"E‹’d°ÍòÖ­h>9’±cÇQª”}óÐaÉ~Y¹zõ*õë›O.lN{dbéZc|km¶â,}¬Ù#1!¢Esþ#¼(ˆ’íYèÐé5»ú«%ó„¹ô¦’ ŽŸÝ»w3bÄ–-[Æ;w¸sç ,`àÀËá~ÕöeɬEÕªUùýwã¬ùûöï§mÛ¶9’g ÝœþùçŽÿù'Lš4Éérrk%=-§{œ8q‚W^y…iÓ¦åx\k2_D²:t¸¹¹cðÇC»ví¹rå2Je:«W¯"´ƒóKA[ââ… t~ë-5jÌ—_—4µG×BYµr%Je:a‹ãlgÀ•+W8zô?ÿü3‡âÚµk6ÍÉ^Â/&99™ 7j²%»4kú*Û¶nÅÅÅ…bÅ‹ÛùP¦LV­\Irr2ß|óµQUKó n˪U+iÓ&ئþ†¬[·–ÁC†àî®0:®P(0p QBgKv±Åf†„„tàÐï¿“žžÎÖ­¿Ð »=ë3«6ÿø#)))ìØ¾6mÚ˜ìgÚ’Ïí³éNjj* -4j³õ½75®%~ñ)))DDDбc'Ø´q#)))$%%ñõмùfgÖ¬]—í†^÷¯5Ù¦Ö“­X;·Ö±½üùç13“ôZ¢eË–|ûÝ·ÄÇÇ“žžÎ¶­[iݺµÙþÖÖ ¹Ï‰3¾,]A»n»téÂ¥K—8Þö:K8ÃŽæÖŒ©5o+ù¹Ë•-ËÍèh@ Õ¯o?&O™Båʕ횃!–ì×¼YS6nØ€R™ÎåË—Yµrƒ69Ž%}ì]ë:,]kì‘ï,[9Kköˆ¾u‹råÊ:¬§@ð¢òÂ;}¢¢¢Ø¹s§Ýç©$ ýã¯ÿ¨3ôkF{AoÜ zS1 1Û67;ưaÃXºt)!!OþÈèܹ3Ÿ}öãÇwh>::tèÀþ,NŸÈÈHƯ¯Â£c.9} )T¸0]ºtáÀ¹*çi¥P¡B 8PŸ¨P;èœ?::vêDƒú¯è_Oš<™ysçR¥reÖ¬^âÅayª_Ø’¥ 2˜æÍšR-À¸ú…=ºNš<™sçÏÑ ~ýlŽGœ=Ö9O:…iÓ§ãî®`ú´éL™2Ù¦9ÙKùòå©Y£:Gÿøƒ M;ˆ-ÙeqØ-^DY¿—4pß|ûMrç/XÀöíÛ ¨Z•_ÃÙ3÷‰ãÐÒüÚf†±·6¸Á´Åjµšð;éׯ¿ÉöþýßcÇöíúKv±Åf†L˜8‘uëÖRµJe–„-á«eËlÒ=ëú4dÒ¤I8x€jUÙ¶m+3fXO(m=»wÓ.ËÍ£.alíZ5yùå—Úl}ïMk‰6ÁmhÞ¬)›6nà“±c˜2u*k×­% jj֨έ[ÑL5pèÛ3'CL­'[±6vn¬c[ÈúKÿ­[·ð÷÷·Ú÷Ý>}¸ð÷ßÔ«[‡*•_&22’š•cm šûœ8ã;ÁÒõX‡\.gêԩ̘>Ýîñ!wìhn͘Zó¶’Ÿë°q“&;z€Ñ£Gqþü9êÖ©mò;ͶÚï«eËX¹ò{*V¨H¿¾}úè#Ž=J“&MX¼x±>L×ÏÏiÓ¦ñÓO?±gÏ=zİaÃ8{ö,Ó¦NåãO>ÑÏÇÔÜ?~L³fÍ8uê€UYºó›6ÕþšR¶\9¢££éׯçoËø .äÓO?`Á‚( FE\\œÑ8†ºœ:uŠéÓ§sñâE *Äĉõ û™›£F8þ¼ÉþææÇàÁƒ¹ví}ô“&M2Ñc‹®Íš5cýúõ”/_ž[·nÑ«W/:ÄñãÇIŒ‹ÃßÿI©ÌÈýûðññÆÍÍ ™L®Ý *—!ÏÜj¸í@¥VóàÁCg~W¯]פޠqqq±¸oÜÚõGð|QÂÇÛá­Ï‚mÛ¶eóæÍlÚ´‰Aƒñøñc›ÎË0ˆôQiŒÛ4jP«A£ ý9Ad2™ÞáÚ_¡ÇŒùsçhÓ¦ ‹³„_ºt‰½{÷²lÙ2† ¦£U«Vúü@‘‘‘´Ê,³Ø¶m[¢¢´Ž(#ÉÅÅÐ:?Z´hÁÉ“'iß¾=Ÿþ¹‘,…BÁ?üÀœ9sxõÕWµådÿúË✒““Y»v-:= ¶&KG‹-ô[Õ<˜-ìÕÔümÿÌ™39r„9sæ°páBþ:y’ßÿ=Û8†Œ=š!C†pîÜ9ÆŽËÌ™ÖÑV«Õܾ}›åË—[Œ¨27yóæJTTgΜ±*Ïš®­[·ÖG{EEEéí9ÖÎ_ô@àJ¥’;wâææöLý¢#lk;ym«†‘®Trúôé<‘'È{NŸ>Z­À2 ¶ §@ýúõùúë¯Ù³g+V>Þæ±Ÿ$I2|Á“WOš$Ýÿõý2fi{ÒI2>AûT28˰ÍP޾M?’VOI?Rv}¥ìr²É4laîÚ¬Ì]’$ s7aæží¹‰6Ý«cGŽpãÊ%ÓúêžK’Ñül·KöùFìßHü}ú/ÃÙšœ¯mkBû\£‘ÀP²»˜|ß³Ì}ç/[8ö{D¶±$`û–ÍüyÀêÜM}´ë2ûšÈÉÜí]ë¾ÿ€=Û¶X|ߟG*—-÷ÿ[Êvý²ù™ûYdÍ7Ëfa[ÛÉ/[ èÝãÅ|od2´w22Ÿhÿ1؆/3j{òdÝd<9Íðù“±eý´¯M?7x¥D.“éÛ²Éɪ¯aåB™Œ?ÔþÀ|4*£¢†²ìrdYŸÛ9w­l™“ænðÚÄs[æn<]Ù“ÍÍ=«¾&çžÓ5abîY^Ëä2ÓsϪ¯™¹ɱd#™›{9mr™<_>Ùçn '[›á*°ŸÞéãhNŸ µ:óÒ,ïZç BB-™ÏÍÍÝ»w%rmU/CÇNñâÅ9úÇQ\Ýì{»\\\¨Y³&#GޤzõêxzzêòÑGQ¾|y½C´ŽäädŠ-Jª‰²§† ÎÇLJû1÷yéw|%T IDAT¥—L–)µ†5Y: .L5 £~ýú6‡ Û3[0`¯¼ò ݺuÃßß_%c¹\N§Nˆe̘1|ûí·vË,Y²$ñññx{{ëËÂæDW…BA­Zµ˜6mÕªUÓ—F:t(ïj·~OY.öN®´ž#$ÉÀ)lÃ=l~Ýæé™­ÑI2rz¾dìPÉuv eä|qD<ÒÙ=mR)ô–òíÓ Ï²¬7#9Ð ]²÷Èé«"í>IFèi^¼ÍÕÑi3³8c*±*-[‡üÑ3?p'¾ùÏ …‚%K–åš±•J†Z’¸•ô˜µ/µ©Õ€LëøQªÌ±lÙ2FŒaTÁ˰Œ»Žàà`®\½ÂË/¿Ì?þÈæÍ›Ù¶m›Mz†„„ðÞ{ïeË=Ó®];†ÊìÙ³Ž·nÝš-[¶Ð½{wv†‡[tj´oßž5kÖ0f̾üòK›ôqTV‹- ³)‡Ž#ãÛÊÅ‹™>}:þþþvéÒ·o_víÚeÒÉgöíÛóÃ?п_?}TNNumݺ5“'OfºA%‘K—.ñ,!Ëâý–²Dܺu‹FqïÞ=‹ýŠ+Æ… (mIu÷î]jÕªEl¬qJsc˜×ÓÅâ—‰=c9"ßv\raL@ àÅæÂÙœç³T$Ç<Ú{†>§O‹-ìvø(%9™Õt9ö6¢ÎЦv&ôj†Z£Ëé#Ce!Ò'$$„¥K—2lØ0}þSeÜÇÏ_|A­ZµX¿~=óçÏ·YÏ–-[R @lɃ2+®æó7nÔ­[—;wmýÊÊøñãùûï¿yõÕWiÒ¤‰Í:9"+((ˆŒŒŒlù|œ5¾­,\¸#FкukªV­j×¹Ÿþ9óæÍ#55Õ®óFEdd$-ƒ‚hÒ¤‰~;o´G×6™ëÁÐf.‘ö³Fjj*þù'={öÔWV³Fbb¢~»ß|h#Ùœ¢“n[’©‡@ @ ä²™«'Jë¿†Ç Z²ÝÑó¾˜ÜŽÞc÷ .ÜÓæŠ©î«µŸÈ2ÿ³öó¶|<Ët‚bíÄÄÄУG}Bç•GѪU+³U¼L•Š·¥RÉïÏdÉvC=<==)[¶,Ý»wg„ úíkº~æ"}.^¼ˆ¯¯¯þ˜³"}œM~Ë@ ¶c)ÒG’$nFGSÁßßâî{ï­ãæ’ί'wŠœ>Ž¢Ò€F’$%½YfO-I[¾]3RRRøþûï³E%½(Ô­[—E‹ѤI–/_NÆ ³õÉÈÈ`ß¾}/tÙœ8BêÖ­Kdd$ݺuÓÓE‰9gnï@ Ïë7l$2*Š–-Zлg\‘!œ>¢‘d|;§½>a¬„67’î_]þI— 1TnS¯^=jժŪ•+ó[•|aîܹLž4™{÷ïÑ A/^œ­Ï7ß|ÃüùórA lçý÷ßçã?¦L™2Ô«W¿þú‹ñãÇë+ÞåáØ@ †DDF@dT~/•!¨eK§ËN™0gO~«ðÂpùòåüV!_ ±šüyøðá ><4zþèÒ¥ >¤ÿþܾ}›råÊ1uêT:wîœßªéÉš¸„3I @ x9sö,6ýH@@5>ýôS&OžÌ†M?R¬X1êÔ®íTY/|"g@ðìc_5-™ÉíVC‡åÚµk(•J®]»ÆÀm:/¯I @ ‚gŸ›7oòÍ·ßáë[š)“'“˔ɓñõ-Í7ß~ÇÍ›7*O8}Á CN&ÂÙ"@ rʶ;ñðôdæÌ™¤§>F£V“žú˜™3gâáéɶ;*Ï §÷0 O‹Uxžû,œ'<Èä.ù­‚@ @ <׌=…‡'ªôT2TÚÊOjµ779ÿûßW¤§¥¢QeäH†¾¢8"§@ @ Až GB™–‚Z¥2:ž‘‘F’“Y ÜI§@ @ A Êâì1$«#Ȉœ>@ @ Ï!™‘>"1©½ì˜_ÏbûkŸœÊ#M@ @ ²#¶w9ˆZ##tôq“mWw`ÇüzV?%|¼yð0Ö麎kIFÖ~æÈ 3lù4Ú &&†’%Kê_çÆšÉ­u(@ -†›×¯qéòeÒÒÒÈdÈd2d€L&À³@ªV¥lyý±œ œ>™¼Ùå»ú«%óÆw/èM¥€&69~r{næŸågéþ´Ù yóf\¾|Eÿ:7ô{Úæ,@ Ï×._âï (Z¤(޼´Î£‡¶_jZ:gÏžE­VQ¡RåË}á>$&$ðúoØužJ’¡1Øwú^ýgl¢Mí*|ÒX1R1 1?ÎnÀ;O8SeÁ Ä£Xá@ ‚g›ÑÑøx{ãåUw7wm\†ÜÀñ ÊP¡pwçÖ­ÛNqúȧ„ =«¤§§1|ø0>5 ÆöÂh*µ FB£‘$ãœH%ê~€_ÓiTh·•…ˆ £s|¼Y³f5 (SÚ—ððp}€èè›4 àäÉ“„v¡|¹²Ô¬QM›6™WÇ£ØXÞêü&+ø³~Ý:›çª£{÷nDFF°oß^z÷êe$gýºuTð/Ïk:ñðáC£¶åË–Ñ*(€¤¤$ú÷ëK¥ŠèÛç]’““õ}ÃÃÃ)SÚ—Ò¾¥ jÉÑ£ØÔf8ϸ¸8zõìIÿòôîÕ‹øøx£~¦ìì $$$ЯoÊ•õ£Eófœ>}ZßfiÎæl§›“áÜrcž–¶µ @  çȀ… ¢pwG.—#—Ëq1ñP(Ü)Z¸09ñÒ:‘^øê]íÛ‡ðËÖm¬_¿Ž~}ûðøñc›ÎËÈŒôÑH Êâ+Ò¨A­24¶¿U/\ 22Šo¾ýŽA܆ƒÚ¨¤àà6Œñǿϕ«×˜8qS§N±:þÌY3iÖ¬9.^âø‰ìùˆJøx›|èÏŸ9‹éÓ¦‘žžÎ¬™3™9k–ÑùGŽæÌÙstêÔ‰Y³fµ)<ü´å'æÎÃØ±ã¸|å*mÛ¶cÁüùú~ƒà³Ù³¹óï]ÆŒÃÈ#mj3dÞܹqþï „††2göl£vSvv† fΘÁ[o½Íõ7ùøãO9â}›¥9›³nÛ•¹íW9™§@ @ ò…»;nnn6õuuwC¡P8Eî ïô dÕªÕìÚµ‹ÿýïKýñ­?ýhöµZ÷È ¤–$Ô­3H¥¶Ýé3æãO(P ;v$##€àà¶Dd:}"#"hÝFëô9|ä:½ö …‚®ï¼cÓ6 }{÷Ò£gO<<<=jt¶öcM>tT©R…ÆÑùÍ7hѲ%+V4:ÿãOÆR¤HÞéÖ}{÷µ½öÚëx{û°ë×_©\¥ ®®®tíÀÎðú~M›6eÿ¾ý:tˆà¶mùóøq›Ú Ù»÷7º¾ó äõ7Þ`÷î]Fí¦ìì üöÛÚ¶k‡››¯¿ñQ¿Ò·Yš³5Û™#'ó@ Áópúǧ_¿¾tèÐ÷ßa)¹s†FŽJïÜ1öú¨Ô –4h4J;œ>>>>ÙŽ5mÖŒ'N T¦süøqš5k@Ü£G,üâ ú÷ëK“Æl?66V/÷ti›õ2dÐà!?~œÁƒgk{饗(R¤qqqFmÞÞO¢ebbb(í[Š>ÞT­ÊwïêÛ–¯XAbb"={t' jΜ9cS›!÷ïß§páÂxzzòàÁ£vSv¶s6ˆÅÃÃÃä9–æ –mgŽÜž§@ @ žmä%-Í Ãž=»éüæôêÕ›U«×P°`A›ÎËÐÈP«%T­ãÇ'‘>j)g~5…BAí:u˜4qÕ«W×;Þíó.‰‰‰ôèÙ“ MçóÉJ‰%¸ÿ>@6­|óõ 5nÌŠ¯Wdk‹ÍŒ6JLH0*3Æy£Š/ÎÝÿîé£hþ½ûŸ¾ÍÛÛ‡í;vpãf4Ÿ}6›ž=ºÛÔfˆ··7III¤¤¤àåååÐ\ÍaÎ%K–D©Tš<ÇÒœÁ²íÌ‘Ûó@ Á3ˆôÄÇóÂGú(|õÕ2&O™‚\n»9T*jIâFb23¶ž`íÁKú6µZëðѨ%”ªœëÜ–U«VÒ¦M°þØÅ èüÖ[4jÔ˜/¿\jÓ8:„²jåJ”ÊtÂ/¶[+W®pôè1~þùg:ĵk׌ÚÃ/&99™ 7jvœvíÚsåÊe”ÊtV¯^Eh‡}[³¦¯²mëV\\\(V¼¸QÔ‹¥6C‚ƒÛ²ùÇIIIaÇöí´ÉÜç ,Ù $¤‡~ÿôôt¶ný…Í›Ù4g0o;777bbbò|ž@ @ xöyá>AAAv—kPJrÔjíóógos ê mjWaB¯f¨5ºHªFú´ Ö:{þÏÞÇEUîÿv½*XæEÅ5ÄÊJÁ5Q-KsÉ=ÓMÃå¢Xî+*ZVˆ™[î+†[Ü{3DÅ´ìšbþ*D!†9çüþ˜f†Aù¼_¯Qæ<ëyyy¾<‹o©‡ú5Ñkñ^È»èÑÝí<ÚTÏì9sz%:v„O¹ôŠ61þ׿æ"rÞ<ØÙÙc^ä<Ì;G£|óæÍñ\{OüçßÿFĬÙzû±dñb´mÓ±_ÅbÕê5ê´Õk¢±jõ*4uû'&Œ‡MŸaPšFý³gã»ÄïÐÎãYìÛ·óçGiͧMeÆ bÖ,l݇gÛ¶AôšhÄlØ`Ð=ë»þAAèÔñe³Þ'Oë""""""ª„¨¯fÉý:¾ÑõhîRPP€¶mÛê,|õòEܺ•ÿ¾°³³Óšgï®z÷ÆÑ¥¦—[8½FÌHàê_ª#¶=«ÆO ÿ·´7f/;kt7\]tž2EúYzìJÚW(H8zîîÍÕi§O&ÀÕÕ¶¶¶+ÕÑV¬Š,½lO)ŠÈȸ‡.>ªNž/¼¨³ÍëׯÃÚÚZçÏ  âŸ?DDDDDD5ÝÕËTï³UNÖ=ZâÐ…°µtCŸJPJ€$ËeO¹ IÆQYu|;QM¤P(püøqƒ $"""""¢ÇDq ÉÆ²½x|I²€Ï $'C5¦%—ÄѬÃOï"ªN7nÀ’Å‹u.“{•ŽžËFî^_™²DDDDDD–À ‰æ­:cé.Ô(\Úe:KÝ”)`Ê”,Ò¶%™°))'0KDDDDD‰Z¿‘3=þ„Rë`ëÔ©,X°………&ÕADDDDDô$PÍôáJ"zÌ•ÌÄ)((@jj*¦M›†ŒŒ DGGUžA"""""zÜ•,p0Ëò®Â¿ ëÙ±¸ðï“ë}Ê=  …¥»`ŽŽŽðööƶmÛàååepЧ&1bœ±qãF@HHòóógážQMÆ=}ˆè‰$I’¥» ¦oö!{ ÅÄÄॗ^·ß~ Y–‘€‹/š³‹DDDDDôbЇˆž(%Ë»ÂÂÂ0xð`Kw@åOûªW¯âãã Ø¿?êÖ­kŽ®ÑŒA"z"”̦qttDÓ¦M1tèPDDDX¸WæÓ¥K´lÙ‚  sçΖîÕhª_<3èc¢ãk»éMï39©šzBD@ågÓT¥Ê.ï€øøxäææ¶mÛ†aÆ™¥oDDDDDôäbÐÇD¢$ _øy­i¿Œãk»UøqssÃ;wª¢{F·WÝ}!ªM*JOOGxx8<Y–1`Àøûûã©§ž2S‰ˆˆˆˆèIdeéÔA¯•_”uÿæÞÎÉ­<ºV8¨&aÀ‡j;AÔ3rJ]Lš4 cÆŒ——¼½½1jÔ(Lš4ÉÒÝ"""""¢N5ӧ殊¨rgΜANN‚‚‚Œ*§”H¥Æíâ_0fþ7ð{¡->ìâhéÑûVö@pøYsv™ˆÊ0f&MI0§l™Šê°dh×®]ï—,Yb¡žÑã¤ÖÏô),,Ä”)S°hÑ"£ŽxVŠ$I†$Éå½ø>Ü|"Ñ¢ÏZ(õÌÒ';;£G†‡‡ÆŒƒ¨Órrr0~üx´iÓ~~~¸|é’:-%%ÁÁÁhÛ¶-^~ùår‹º¸¹¹UXG÷îÝ‘––HKKC÷îÝ+Õ&Qu“eYýªÎ²DDDDDD–Pëƒ>½{÷ÆÎ;ñÍ7ß`„ xøð¡A劊gúH2 ,+’D@IŠ$Ó‚>Ë—/GÏž=‘œœŒ€€,]ºTöÉ'Ÿ`àÀ¸võ®N GHHRSS1cÆ DEEݶ®:|}}qúôiªR¾¾¾fk“ˆˆˆˆˆˆˆÌ«Ö} cÇŽøì³ÏpìØ1|úé§êëGÐYFK^2ÊNe¢¤ )EÓ‚>'OžÄo¼'''áøñãê´„„øùùÁÆÖAAA8yò¤:-11ýúõƒ½½=¿1™™™F·­«___œ9s€*èÓ«W/³µIDDDDDDDæ¥ÚÓGjõ¾>ÉÉÉx÷Ýw€õu}›;IVPÊ2ͨRAd ƒ>ééépvv8::âÞ½{ê´ÌÌL888h-—••…ØØX\¹r?ýô“Im몣k×® ƒB¡@rr2Ö®]k¶6‰ˆˆˆˆˆˆÈLŠ÷$­õ3}Nœ87ß|C† Á¦M›àäädP¹"I€(ÊPJªY=¥=šé#C”Mbäåå òóQ¿~}uZ£F P(´–7nrss1dÈÄÆÆšÔ¶®:ìííñüóÏ#22íÚµSžÌÑ&™W­úØÛÛ#::°²2|8”J¢,ã·œ<Ìßû#âV§‰¢*à#‰2JÓúåëë‹Ý»w#??R/¥€>}ú )) ………Ø¿?üüüÔi×®]Ààíí7šÔ¶¾:|}}‡W_}Õ¬m‘yÙXº–Ö³gO“Ê)d+ˆ¢êë+—oãnvü^h‹ˆáÝ!J2 (+˜éSúÔ¬wîÜÁÌ™31uêT,^¼ÞÞÞˆŽŽV§Ï˜1Ó¦MÃ{g-Zh¤­\¹“'OÆÃ‡5–ªik÷Î;ZÓôÕáçë‹9€FÊÐ6‰ˆˆˆˆˆˆ¨ú}jñ†>ÅŽ< wŸ²DQ€$M1ºÀ³±+DY5š‚¤úCßé]º‚.аaCK¥êÕ«‡M›6iM D`` úý„ ´¶§¯m}u4mÖ¬\Y}ù‰ˆˆˆˆˆˆÈ2jýLS)%@’eȲ§\¤GÁ3 dÕñí5YQQ`kkk鮑1èc"Iðù¢€’ ±U³{Jý]2yÊZ0íô®ê²iÓ&,[¶ 6l°tWˆˆˆˆˆˆˆÈŒô1QÄ¢c–î‚Y„††"44ÔÒÝ """""""3+Þe¸fÏF!""""""""ÃÅqžZd;Ñ“È,Ë»ìagg§7ÝÔz‡rDOÁÊÚÒ] """"""3âL"""""""¢' >hŠˆˆˆˆˆˆˆˆžœéCDDDDDDDôâ‘í&:°ì%½é¯}˜RM=!"""""""*A‰’€~á給ýzt2,{©ÂÀO#WdÜ»_Ý«°½F®.iÎÎÎèÒµ+Ö¬‰ÆSO=Ueý«î{&*MõײlÜÂÖÊ”%"""""²+(õ,Sk ü–QùEY÷ Ù9¹ •G× gYZƽûêWꕟЩc'Ìž=K#½*Ú$²$Y–M Ú˜ZŽˆˆˆˆˆ¨Ú?»Ôú=}N:…ýûö]N) d¨_þ|€ï}†ð˜S°sr­“ ZztÁŽ…ª ×æçììŒ÷ÞÃÉ„Kw…Èh‚ ¨_uêÔ‡‡,X€ÂÂBƒÊ'$$`À€hРœœœàé鉨¨(äççWqÏ sîÜ9 6 5‚³³3Ú·o¨¨(<|øPkþ¤¤$øøø¨ßWÇýEGGCDGG—K« ã[ú3RKŒQU¨õAŸÂ¿:/XI’ .§H’ I*ÿÛÿF/¾7ŸH´è³J=3‚ôÉÊÊÂðaÃн9F ŽììluÚƒ0zÔ;hÖÔ ={tÇÅ‹ÕiÉÉÉèØÍ›5Åsí=ñÍ7ßܦ °±y´â¯ô°F®.ˆý ^^Ð䙯8tèУ¾ffb`p0<ÛyàË/¿,·t¬´Òiºúêíå…[·nnݺ o/¯Jß=ùJfâÜ¿±±±8~ü8>üðCƒÊFFFbРA¸té²³³qøða¤¥¥aèСUÜkÃDDD ÿþ¸xñ"²²²pøða¤§§ëìß²eË0}útõûª¾¿””Ì™3K—.Åœ9s’¢¹´µ&Œ¯13µª{üˆˆˆˆˆªJ­ßÓ'  /¾Ý»ïŒë×Á†ŸÂÉÉ©ÂrEÅ3}õ¬)5I,þBŠ$Ó‚>K/F¯^½ðÙ¦MØ·w/-\ˆ%K—¢æÏÇ믿MŸ#‡cÊä÷qæì9À”Éï#"bz÷éƒÝ»vá_ÿš‹!C†èmKEܹó;¶oߎ€€ù®]½ŠÓ§Ï 11ÆÃþøä“O„·†ÄaN©åaÑÕW?$&&b̘8uêüýýL¾7ª}áíímÛ¶ÁËËKëÌ“²¾ÿþ{÷îîîXµj7n\UÝ4ÊÙ³g5Þ7oÞü1š4iR.ﯿþŠk×®!88X}­²÷7bÄ8;;cãÆ€äçç#..yyy:t(V¯^±cÇ¢aÆ:t(’““áììl–ö«SUŒ‘¥X@mߥÂËË [¶|…#GŽ`ýúuêë{wíÐYFK^2ÊNe¢(%ÕŒ Sœ8qo¾õœœœ0 8GQ§?~ ½ûô­­-«>ð}Ò¿ôÚk°··Ç›o½…Ìûº÷Ðiäê‚F®.hüôSèÙ£îüþ;-^¢3ÿ´é¢N:èß¿?ŠŠŠ4úóæ[o¡^½z˜>ݰ™úúêïß§§O‚¯ŸŸÑ÷FdÌÌ=m<ˆ^½z™¥/¥—•}K©Tâ·ß~ÃÌ™3áëë[.}ÅŠ˜:u*¬¬ôOä4æþbbbpâÄ |ûí·Ø³g Eÿþý1vìXÀ¸qã†š­ýêTãGDDDDTÝJâ<µ~¦œ?£GB`` &Mz_}]ßæÎE’”² AdAóáR)‚ ²…‰AŸôôtÔ­[€jæBFF†:íþýûpppÐZ.+3›7oFjêe¤¦¦êm#ãÞ}H’„ƒ`ùòeXðñ'êßÌkãêêªõú½{÷Ôå?óŒÞ6 é«O÷î˜<ù}(…8þ<6lüÔè{£Ú«  ©©© ÃàÁƒMªcçÎ +7ÃÆTæÚºtÈÃã\ÿ222päȬZµJo=ÆÞ_½zõ¯žý²ÿ~õÏ§ØØØrùW®\iÖö«KU‘¥Ôú=}Ž;ŠAƒ1|ølù*Ö ¥]€jÙ–(ÊPJªY=¥=šé#C”MbäææòóóQ¿~}uÚSO=…B¡µÜÈwF"''o†¯·W¼ç••cô˜±ø`Êd“úúôÓO#;; €*Xe(]}µ··Ç :`ö¬ÙðôôT¸Œ½7ª]Jfθ¸¸`äÈ‘ð÷÷Çòå˪£¨¨Ó§OÇ´iÓpèÐ!´mÛ¶ŠzkY–¡P(pýúutéÒ!!!éë×¯ÇØ±cáè訵|eî¯K—.hÙ²%Zµj…Î;›ÔÿÊ´_™ÙQ†ªÊñ#""""²„Zô±·w@LÌÌ™;·Âéü¥)•DYÆo9y˜¿÷GÄ%þ¬NEUÀGe(”¦õËß¿7vîØüü|Ø¿~ÅKœ oß@œ;{………Ø»÷[ôìÑ]víêU zýutîÜëÖ­5¸½±cÇ"//OcƒfCö뇸Ø8äææbu¿!/M__ýý{cË–Íðóó7(?QÉF½ùùùøå—_0þ|3â´¹qã|||põêU\¸p:™ïä=s.ï²µµE›6m°bÅ 9òhÙgAA6oÞŒI“&i-WÙû‹Gnn.rrr°mÛ6£û]ÙöK¾¿æš5UVU‘%Ôú O¯^½0 Ô††RÈV‹7l¾rù6¾;s ~5³Ì IDAT/´EÄð™>”Ìô)ÙW§ô fÏžï¿C;g±oß^ÌŸ¥.1k¶nómÛ zM4b6lP§­‰^‹÷BÞEî>hçÑΨ{Z¹j~ò1 Œ*÷áô‘˜˜ˆn]»À§»ÎÀÊÒ××Þþª`o©`WeîHŸ­[·¢S§N ¡C‡t.e4Ué€EÙ—!üýý±oß>dee©gú̘1ÞÞÞê<[¶lA¿~ý´ö½²÷—žžŽððplÞ¼_~ù%ÂÃÃq÷î]ƒËWõøšCUŽQu+ùý²õÕ,¹_Ç×à Ú£^ÍÿÈè¾~õòEܺ•ÿ¾°³³Óšgï®z÷ÆÑ¥¦—[8½FÌHàê_÷žUã'Šÿˆ[Ú³—Õž}2ïßG·nÝðó/¿hMoäꂌ{Ü€¹&R(H8zîîÍÕ×NŸL€«« lmm!VªÙ)V¬´ÌTQŠ"22î¡‹jæ™ç /êlëúõë°¶¶Öùs¨øçOi‚ @Ñ•Oߌ›¬¬,商¶eNgϞŲeËpæÌ( ¸¹¹!88hذ!$I‚§§'8€6mÚ”+oÌýi3xð`´nÝ‹/Ìœ9¿ýövîÜiPÿ+Û¾9hëCÉ÷±ªÇˆˆˆˆj¯«—/¨Þg«œ¬{(´.Ä¡äÜÈÙTJ d²,Àã)$éу r©ãÛŸ`í<žÅºuëáÓ½;Ö­[‡®]»”Ë£P(püøqØÚÚZ ‡ô¤3&SòôtCF–Ò£GôèÑCgúÞ½{áéé©5`T~#é]»vi¼_²D÷)UѾ9èëCU‘¥0èc"Iðù¢õ”)€Pêï’óѬ-ø X]–¯X‰™ÍÄ_þoo/¬[S.ÏÆ°dñblúü ôH¥2ï5ùÁùòåFoZMpüˆˆˆˆèI¥ úÔà‡™šjÞª3–îBÑ¿ôïß_ož)S>À”)TSˆj—¤¤$Kwá±Æñ#"""¢'*ÎSë7r&"""""""z1èCDDDDDDDô2Ëž>…@Ö³cqá߯þ¸•#z( KwˆˆˆˆˆˆÌÈ °ì©4DDDDDDDDdNª8—w=ô!"""""""zÙná^<†Ž¯í¦7½ÏdLDDDDDDDPçáL‰’€€©?j}µôèZaPúöí‹o¿ýVkÚž={зo_“úæææVmù ­###Ã,}!"""""""Ã0èS,0è5£ò‹²îͯíœ\ÐÊ€ÀÏ•+WðùçŸ#''Gãúƒƒ+W®Õ'K¸sçŽAùüüüÌR¦Ö}Μ9ƒƒ]N) d¨_þ|€ï}†ð˜S°sr­“ ZztÁ¾•=ôÖÓ»woìÞ½[ãÚž={`tŸj²ÌÌLKwˆˆˆˆˆˆ¨V)>²ÝÒݰœÂÂBL™2‹-‚$I—SŠ$I†$ÉeÍM‘½ø>Ü|"Ñ¢ÏZ(õÌ€à믿ָ¶mÛ6 0@ãZvv6F Œ3>€j–Ïk¯•ß_èäÉ“xã7àää„   ?~\#mÈ!pppÀ”É“+lO›cÇŽ¡uëÖ°±±AŸ>}päð£ëèÚµ+‘””___œ;wΤ¾$&&¢_¿~°··Çà7«—†ùúúâÌ™3TAŸ^½zéÍODDDDDDT›1è 99ï¾û.¢¾®osç"É JupG3ê£Q– I2}^{í5ìß¿÷ïßÇþýûË-í€ôôt8;;qïÞ=uZff&\]\Ÿy¦Âö´¹{÷.ÜÝÝáææ†:à?ÿ0ºŽµk×"''ï¼ó:tè€Ë—/›Ô—¬¬,¬Y³&L@ÏWzª¯wíÚÉÉÉP(HNNF·nÝôæ'""""""ªÍ¬õñíµÒ‰'ðæ›obÈ!Ø´iœœœ *W$ EJIø)íÑL¢\q\­Y³fhÕªfΜ©þº,õ>;ùù¨_¿¾:ÍÕÕéwÓè?]ß ˜† âÖÍ[¸sçîܹƒ›7oVØom}ܽ{7~þùgÌŸ?£F2º7nrss1dÈÄÆÆª¯ÛÛÛãùçŸGdd$Úµk½ù‰ˆˆˆˆˆˆj¥â@O­ŸécooèèhDDDÀÊÊðáP*ˆ²Œßrò0ïˆKüY&Šª€$ÊP( «oÀ€8zô¨ÖY>€jiÓîÝ»‘ŸŸƒ‡©—6@@@bcc¡P(°nÝ:r¶¶¶8zô( ­³}\ÿõ: ¶nÝŠàà`Ã:^¦€µµ54h€ììl~è H•víÚ5 0ÞÞÞØ¸qc¹6âââðꫯ”Ÿˆˆˆˆˆˆ¨¶ªõAŸž={"((Èèr Ù ¢¨úúÊåÛøîÌ%ø½ÐûC”JfúP0ÓP-ñAë~>0sæLœ:u /¾ø"<ˆ¹sçªÓ>úè#üôÓOèÖ­ºvíªQnÆ ˜8q":uê¤uQé:V¬XçŸñññX¶l™Fº››[¹WYË—/ÇÚµkѺukLœ86lP§ª—c•Ô§ËÊ•+1yòdøúú–ÛÐÚ¯xóæÒA/}ù‰JAýªÎ²DDDDDD–`céÔGл‡OY¢(@’€&ŽNˆÝàÙØ¢¬šE%Hª?ôÞUú4«&Mšà÷ß×™Þ°aCK—êÖ­‹­[·ªß—õíÛWc©ÖÈ‘#µÖ_¿~}|ñÅöS_ÚË/¿¬±Áti111׈ÀÀ@õû &¨¿nÚ¬Y¹²úò•%˦-h-)Ç =.¬€0ÆSJ€T¼wÇS.ðxÊ’$C’dÈ’¬Þ×G-ÝÓš­¨¨GŽ­­­¥»B±Ò³pêÔ©,X°………•?wî† †FÁÙÙíÛ·GTT>|XÅ=7Léû3dÆQRR|||Ôï0`À4hÐNNNðôôDTTòóóÍÖÇèèh‚ u©¥Çרö-1~DDDDDæTò¸Pë—w™J’|¾(_.îƒ/àsõßøbq¾\¤z‰2CjúlÚ´ ¡¡¡KÁˆL!Ë2dYÆýû÷‹ãÇãÃ?4¨lDDú÷ï‹/"++ ‡Fzz:†ZŽ6\Éý•~é²lÙ2LŸ>]ý>22ƒ Â¥K—Ç#--Íl÷—’’‚9sæ`éÒ¥˜3gRRR4Ò-=¾Æ¶_ÝãGDDDDTU¸¼ËD‹ŽYº O„ÐÐP„††Zºôqtt„··7¶mÛ///½˜—8{ö¬ÆûæÍ›ãã?F“&Mªª›Uæ×_ŵk×46cÿþûï5ò¸»»cÕªUhܸ±AuŽ1ÎÎÎêÒCBBŸŸ¸¸8äååaèСX½z5ÆŽ‹† bèСHNN†³³3˯1íW÷øU%}ˆè‰$I’Iå”J%n߾ŋ÷xãðÊÒ·ËÐ=†š4i‚{÷îá©§žÂsÏ=‡ÐÐP­§ý­X±S§N­ð4ƒjlˆ®OLL ^zé%|ûí·e ¸xñ"Uà¶ÿþ;v,`ܸqøé§Ÿªu²ª_cTÔ~uQU²ÔÇ·=ö ššŠ°°0 <ب²¥ƒ3åfˆ˜ÊÔÍ£µ•ÏÌÌÄ?ü€™3gâÊ•+˜5k–:-##GŽÁªU«ôÖ·sçN„……|õêÕC||¼zöËþýûQ·n]ÐØY¹r¥Özªj| UQû–?""""¢ªPòa–™>öް³³Ó›nj½C9¢'`emé.TJɽ££#š6mŠ¡C‡"""¨:dYFQQnݺ…… "$$»wﮊaÆèÛ·/Ú´iƒÎ;k}Ö¯_±cÇÂÑQûϲ¢¢"DDD`ÇŽ8tèÚ¶mkp»]ºtAË–-!:wîlRß+3¾¥6•9M_û5}üˆˆˆˆèñ'I$YRÎb%ÀªÌA-ÖÌ87—wÑ¡²³iJØÚÚ¢M›6X±bÜÜÜÌR§9–w•ekk«±„­  ›7oFrr²Öü7nÜÀÛo¿ WWW\¸p®®®FµÜÜ\À¶mÛ0lØ0“ûmÊøVõ÷÷q?""""z|) !Ê€¨ª 4ƒ>6¶¶°±1ß/äyzÕzþþþØ·o²²² P(pýúu̘1ÞÞÞf©_ÛÉ[ÀUZ`` Ž;†œœäççã‡~ÀðáÃ1~üxuž-[¶ _¿~Zƒ[·nE§N„C‡°HOOGxx86oÞŒ/¿üááá¸{÷®Áå«z|ÍÑ~M?""""züáa~þJOÇŸwÓñgú]ü™žŽ?ÒÓñGú_ø¿¿T¯?þü y¢H¡0K»ª™>ÜÔ‡ˆj±ÈÈH,[¶ £F‚B¡€››‚ƒƒ±gÏKw €jsäyóæáÒ¥K°³³CëÖ­ñî»ïªƒ>’$aÍš58pà€Öò#GŽ ºÏÈÈH´¬¬,Ô¯__oû“&M˜1càåå5j&Mš„;wÔKoEí×ôñ#"""¢Ç›$I(R*ñ0+ \Â? /êÖ­§1sßÊÊ yy¹HL8{÷2aooI’*<`D·â™Cfè­t`ÙKzÓ_û0¥šzBDÆ,ý)™6YºL=УGƒÊYÂàÁƒõnJ½wï^xzz¢M›6ZÓ+»4j×®]ï—,YbTyCÆ·*UÔ~M?""""z¼)•J(•J)•èåëIñÇß5þŸ)œœê¢ç+¯b÷®°.²‚R©Ô»²!¸¼ËD¢$ `êZ_-=ºVßW_Å®]ÚÓ»sçNø¾úª¹»m²F®.•ÎghDUÅØeUæ*[Õ–/_ŽéÓ§[º-ŽUGGGäåæB–eÕ¦ÎÅ/Y–‘——{³¶Ç O±ƒß2*¿(ëþ­¿“ ZøIM½ŒO7nă4®gggcÝÚh¤¦^6ªOU)ãÞýQ•—””„nݺYº-ŽU—¢¢"½{~™µ½â OÍûÍuu9uêöïÛgt9¥,@’¡~]øó:¼÷ÂcNÁÎɶN.héÑ;vÒ[Oß¾ØUf_‡];w¢o` Ñ}"""""""¢šKEu€G*õ*¹&Š¢Z‘Qç©õ3} ÿFhèD|¼`Æ&JQŠ$I†$•_îÑèÅ÷áæ‰}ÖB©gF 4q[ã4®ÅmÃÀƒ4®eeeaø°aháÞ#†Gvvö£ö\]û¼¼:¡É3qèÐ!ƒËmÿúk<ûl[<ûl[=z‰ß}‡çÚ{–«§ôÒ¬äädô ì‹æÍšâ¹öžøæ›o 1Ãêðöò­[7·nÝ„wñƧ¦¶IDDDDDDT“¨göHÒ£Wm%Qëƒ>}ñíÞ}ˆßŠÑ£ÞÁÇ *WTj¦²L¬HQ$ (’ô}ZµjRRT?_¸p¢R‰víÚiä[²x1zõê…+?]E¿~ý°háBôkW¯âôé3Øôù˜0~œÁåRRRœ|Ë—-ÇÒ%KðcòøïçËÕSÚ”Éï#4t®ÿú?Ìš5ÿú×\½÷hLþþ~HLL š…åïïg¶6‰ˆˆˆˆˆˆ,MßLs«õAðòò–-_áÈ‘#X¿~úúÞ];t–Å’—Œ²„DY†(©‚AJ±âˆ¸¸XÀV-³|àĉãxó­·àää„ÁÁ8zôˆFú´é¢N:èß¿¿ÆÀŠÊ}8cœدRS/cüø prr*WOiß'ýA¯½{{{¼ùÖ[ȼoü^=ºêð÷ïSÅAŸÓ§NÁ×ÏÏlmYÚ£™>¥^Uô)>²]°èqÄ–vþüyŒ= ˜4é}õu}›;IVPÊ2ͨRAd C‚>¢×+¯`öìÙøvÏœH8Y.Ozz:êÖ­ @µÛwFF†Fº«««Öº+*çâ¢Zrec£ú(4hРÂþfefbóæÍHM½ŒÔÔÔ óS‡O÷î˜<ù}(…8þ<6lüÔlmYZIpG–¥R×Ì<'§8ÆSëgú;vƒcøðØòU,œœœ *W$ EJI5«§´G3}dˆ|ãš7wG›6m†æîîhݺu¹<...ÈÍÍäçç£~ýúõ³¢r¦ûF¾3999x{Ø0|½Ý´½utÕaoo:tÀìY³áéé ‡âãêÌÑ&‘¥é;½ËÜj}ÐÇÞÞ110gî\XY>J¥Q–ñ[Næïýq‰?«ÓDQð‘D ¥aõ 4‡Æ -K»Õ²§;v ??öï‡_ñ²§Š˜ZNŸkW¯bÐ믣sç.X·n­Ùëð÷ï-[6ÃÏÏ߬mYš¶ƒ>U¤W¯^lt9…l…’“Ô®\¾ïÎ\‚ß m1¼;D©d¦¥S´‚ƒBÔÞ—Ù³gã»ÄïÐÎãYìÛ·óçGT¯©åôY½ï…¼‹Ý}ÐΣÎ|¥Oë2¦ŽÞþª`o©•¡mÕdÕ9ÓÇÆì5>¦öîÚ¡wŸ²DQ€$M1ºÀ³±+D’ê}§weÜ{´ñ?ÿùOÜ͸§3½¡‹ ¾þz{…õ˜«\Ù÷¥¿ BPPúý{'VX¦,}u4kÞ¼\Y}ù‰ˆˆˆˆˆˆ%Á©Ô©PƬ<2ƒ>&RJ(>VM€ÇS.HÒ£¨œ²êøöÚN¡Pàøñã°µµµtWˆˆˆˆˆˆˆ,êÑFÎr¹kæÆ ‰$YÀç‹J6ÄVÍî)õ7Š¿_ÖµøT´7nÀ’Å‹±éó/,Ý"""""""‹%Q.(³œK–e@ šyæƒ>&š·êŒ¥»ðؘ2åL™ò¥»ADDDDDDdQ9rPÇÑùùù@™Ù=u‘—óÀ¬í©‚>‚ ž™BDDDDDDDDæaccH²ŒóÿI‚W—.hèê I|4«ÇÊÚórüðµ¶…­ªŒ)¡dgúU+++ØÚØ ®³3²srð݉+@€P¼mŒjk[[¸º6DaÁßfÙÜÙ,AŸÂ¿ ëYwVøwÉõ>刞 …ÂÒ] """""z"ÙÚÚ©Ž#!*E@+V BñìÀÆÖ66ÖD©‚ Ù>DDDDDDDDUÌÎÞÖÖÖdÕ,ÁJ€• ô±¶²‚$ËrÍÒ¦*èÃý|ˆ¨J¦g쑈•)KDDDDD¨–zY V:ƒ>4öú1Yñ# gúQ­bjÀ¦¤\éÆDDDDDD5Yåwª¥Ž¯í¦÷EDÕG(¯S§<<<°`Á]WZZž~úéÜ9wî† †FÁÙÙíÛ·GTT>|@óþ-¿)(+)) >>>ê÷ AÓ¦Máàà€¦M›"$$f»‡èèh‚€èèh½ù,5þúÆ­²ã[ZUÝŸ¾ñMHHÀ€РA899ÁÓÓQQQªcB«AEŸß²,ñù$"""zR1èc"Q0õG­¯–] üܹsï¾û.<<<ðÜsÏaòäÉHOO7¸eÿÓëææfÔ}T¶œ¡uº¹¹©_M›6E»ví0uêTdffZ¬¦2´/e￲õUô€S“ÆÈdY†,˸ÿ>bccqüøq|øá‡FÕ¡T*1tèP|ôÑGUÔKÓDDD ÿþ¸xñ"²²²pøða¤§§cèСê<%÷_ú¥Ë²eË0}útõû·ß~vvvHJJBNN’’’`gg‡·ß~Û,ýOIIÁœ9s°téRÌ™3)))ZóYrü+³ÊŒo‰ªº¿ŠÆ722ƒ Â¥K—Ç#--MãócSU†|~K«îÏ'Ñ“¬xy÷§ zͨü¢¬û?¿vN.hUøé39Ig¾ììl,Y²|ðÖ®]‹ÂÂBüûßÿÆÒ¥K1oÞ<Ô­[·Â~øùùáòåËê÷wîÜ1ê>*[ÎÔ6òrs±oÿ~Ìž=6l¨ò¶ÍÉÜceh}e¿×¦Öó¤stt„··7¶mÛ//¯ g–”6kÖ,¸ºº",, áááUØKãœ={Vã}óæÍññÇ£I“&F×õ믿âÚµkV_ûÏþƒÝ»wãÿø iÓ¦X°`š6mjP#FŒ€³³36nÜ A~~>âââ——‡¡C‡bõêÕ;v,6lˆ¡C‡"99ÎÎÎõÔÔñ7†¶ñ-aêýUv|¿ÿþ{úÜÝݱjÕ*4nܸwj8c>¿Uñù$"""ªJ~_Wëgúœ9s4ºœR ÉP¿.üùÞû á1§`çä['´ôè‚}+{è¬#&&#GŽDûöíaoozõê! K—.Å®]» ꇡ3ejçºu1xð`|÷Ýw–îÊcãqý^[Š$wÄáÑ£G±}ûvlÙ²Åì}ѵ<È”™J¥¿ýöfΜ ___õõ&MšÀÎÎnnnèÛ·/öï߯µüŠ+0uêTXY=úñ?hÐ DFFâÎ;(**Â;w0oÞ<¼þúëõ)&&'NœÀ·ß~‹={ö !!111€ÐÐPôïßcÇŽŒ7ýû÷Ghh¨FU9þæP™ñ*wæß²<ˆ^½zÝ—ÊÒõù-QŸO"""¢Ú¬Ö} 1eÊ,Z´È¨‡D¥(@’dHRùiþ^|n>‘hÑg-”zf%$$ M›6å®[[[ãðáÃê÷nnnØþõ×ðððÀo¼{÷—þ[Û×;vìÀ /¼€^xÇÇéÓ§ñòË/£E‹8zô¨Îr¥_¯¼òŠ:-/7&L@»ví0~üxäåå©Ó2331dÈ´k×Û¿þZ÷àS*•¨S§Žú}vv6F Œ3<ÐZÎÇǿ߾ ¸uë–Æƒ‹››âããáããSîõÕoêX¥¤¤ 88mÛ¶ÅË/¿lp°®´Òõ=z-Z´€»»;úôéƒÿþ÷¿y ]&¦«_Ý»wGZZÕÞ"Ý»wWçóÍ7î{MTPP€~øÆ ÃàÁƒ *óÇ`̘1غu+\\\ÌÞ'mKƒ*Z"¤ °µµE«V­pöìY|õÕWêúÿøã( \¾|S§NÅܹs±páBò8räF¥q}ݺuHJJBÓ¦Magg‡¦M›")) k×®5¨_õêÕC||<Þ{ï=Lœ8Û¶mSÏTŒÅÊ•+5ò¯\¹±±±ê÷U=þ•UÙñ­ìýUv|ËÚ¹s'°zõê Û. ¬LÀR×ç·DU}>‰ˆˆˆj3+ v/îêÝ»7vî܉o¾ù&Lй±dYE¥fú(ËÄŠ$E@’€"I÷ŒÓÒÒP¯^=­iW®\ÑxÿïÿüçÏŸG`` /^ àÑr}Ëz.]º„¤¤$,Z´+W®Ä…ädœ={6lÀĉµ–¹sçŽúåç燈ˆuÚ²åË1mÚ4¤¦¦ÂÏÏOã¡aÑ¢EèÖ­RRR|á‚Î>@^^ââ⤾¶|ùrôìÙÉÉÉêOÚôìÙ 'OËý¶øçŸƉ'ÊÝcEõ›2Vááá Ajj*f̘¨¨(½÷]‘‰'bþüù¸qã>øàL›6 €aßkCúåëë‹Ó§OPÍr+»ððpŒ?¾R}·´’QŒ9þþþX¾|¹Ae‡މ'¢gÏžUÜËÊ‘e …ׯ_G—.]R.OÆ Ñ·o_ìÙ³§\0`ýúõ;v,5®5 ;wFZZ þäÄ IDAT ‘––///¼óÎ;÷­K—.hÙ²%Zµj…Î;u_æÿÊ#ŒaÊøšãþ*3¾%ŠŠŠ0}útL›6 ‡BÛ¶m+,S6@ijÀ²¤¬¾ÏoU~>‰ˆˆˆj›’ÿ®Õú™>бcG|öÙg8vì>ýôSõõ#è,#Š%/e'‰² QRƒ”¢îA´þǹ¨¨¢(j\ CÝâ%Q'‹† ƒ³³3påÊŒ;NNNèÛ·/ŠŠŠô–ݱcÑ·o_õµcÇŽ¡uëÖ°±±AŸ>}päðuÚÉ“'1dÈ888`ÊäÉåê+™9Ô¬Y3ôèÑ¿ýö›Æ†¦'OžÄo¼'''áøñãZûõÊ+¯¨Çà»ï¾Ã«¯¾ª‘þÁ N:åî±¢úM«ÄÄDôë×öööüÆàJ/ÁêÚµ+‘””___œ;wΤztõË××gΜ  ú”Ì’JLLD@@@¥úni%¢ùùùøå—_0þ|888TöÔ©SˆŒŒÔ:«Á̹¼ËÖÖmÚ´ÁŠ+päȽùJÏ^,((ÀæÍ›1iÒ¤ryOœ8  Y³f°³³C³fÍðÉ'Ÿ !!Áà~ÅÇÇ#77999ضm›Q÷dŽñ¯L0ÂÆŒ¯9î¯2ã 7nÜ€®^½Š . S§NF×aº>¿Uýù$"""ª­ôœœŒwß}¿yÔ·¹s‘d¥:¸£õQŠ€(K$ =AŸæÍ›#77·Üõœœ4kÖLãÚ?ÿùO@ݺu‘mÐ}P/%°±QíÙ]¿~}ƒÊýõ×_X³f >þøcëwïÞ…»»;ÜÜÜСCüñçê´ÌÌL¸º¸?óL¹:Kfݾ})))Xºt)œœœÔééééêGÕËØÊêîãƒóçÏ#++ —/_F—.]4Ò]]]µ–«¨~SÆ*++ kÖ¬Á„ Ðó•ÊÏY»v-rrrðÎ;ï C‡z7n6¥_]»vErr2 ’““Ñ­[7uþõë×Wºÿ+]Ë®Ì@¨ìò.ìÛ·YYYê™3fÌ€··7 00ÇŽCNNòóóñÃ?`øðá³·¶lÙ‚~ýúiý÷áåå…Ù³gãöíÛ(**ÂíÛ·1{öluýIOOGxx86oÞŒ/¿üááá¸{÷®AeªÿʪìøVöþ*;¾[·nE§N„C‡éüYU*úüUûù$"""ªÍj}ÐçĉxóÍ71dÈlÚ´I#¡O‘$@e(%Uà§´G3}dˆ²î!Àõë×Ë]ÿõ×_Ëͺ¸ÿ>U@¨Q£Fõ0}¦ÂŒ30}úôrÿoذ!nݼ¥àܼySæêêŠô»ªãæ+:^\õAùù:ƒ.Îuë¢}ûöX³f :vì[[[³ÔoÊX7¹¹¹2dˆÞ=4 åââ‚Ý»wãçŸÆüùóËímQÙ~ÙÛÛãùçŸGdd$Úµk§ž S’Ÿj¦ÈÈH|ñÅhÑ¢êׯ   4hÐ{öì úþÍ›77F“&MŠ‘#Gª—‚J’„5kÖè<1jûöíÈÏÏG·nÝàììŒnݺáï¿ÿÆ×ìÍ“&M˜1càååoooŒ5J댚LÛ¾5%*;¾•UÙñ9r$²³³ +++GÆüÁÔ \EŸßªþ|Õf6@ñÃnÍø…jµ³··Gtt´ÆÞ2†P*ˆ²Œ´Ü‡ˆKüY#M2P(u×1qâDDFF¢nݺhݺ5àÿû¶oߎ hä]·n>úè#ìØ±Cc¹•­­-222Œ UdÇŽhÜøi 4¨\š¿¿?®ÿz­[·ÆŽ;°sçNìÛ·€*ˆ‹iÓ¦aݺuF·ëëë‹Ý»wcèС8xèÞ“ezöì‰5kÖµ‡Ž1õêÚµk˜7oÜÝÝ+½ŸOIÈ h<ó½Ö×/___Ì™3óæÍÓÈ?gÎdé˜]UÓó0Zò0_Q™²éU½WŒ>=zô@ºO¿Uýù$"""ª¨ž_jýLŸž={ð…l…’mw®\¾ïÎ\‚ß m1¼;D©d¦¥ž™>uëÖÅŒ3ƒ—_~/½ôbbbðÑG©Of)ѬY3tìØ?üðf|ø¡úz`` z‰Ž¹¬Y½Û¶}­q‚W‰>ú+V¬ÀóÏ?øøx,[¶L#í§Ÿ~B·nÝеkW£Û9s&N:…_|ÄܹsuæíÕ«ŠŠŠÊíçc®ú µråJLž<¾¾¾xöÙgõæ-{*𶓏–/_޵k×¢uëÖ˜8q"6lØ N+û½Öw’—¾~ùoÞ\:èµråJ„……éíÿ“ ²›ÐVçž1æ´|ùrLŸ>ÝÒÝxbq|+‡ãGDDDTu„¨¯fÉý;€ƒdºõ5’-((Ð{ºÇÕËqëVzôê;;;­yŽ< wo]jz¹sú`ÄŒ@®þ¥šáÙXµJ ÿ·´7¦/о!±¡ÜÜÜ >µ©¶¸{÷.Þ~ûm£6µ~ÒUös¢P(pöÔ)¸»7W_;}2®®.°µµ… / ±`¥e#b¥("#ãºø¨Ž÷|áEm]¿~ÖÖÖ:nÿü!"""""ªé®^¾ zŸ­r³ï¡PPàà…ýªå]d<¥H² Yàñ” ’ôh€²êøv2¯üü||ùå—èÓ§¥»R#!!!Á཈ˆˆˆˆˆ¨vP}dµvSI²€Ï $'Jý]2œÖÜäIõÒK/áùçŸÇîñØ´i–-[¦±Ì¬­­M.'ŠŒvx¶R/?gú˜*bѱjk‹K»4ýòË/–îBŠÐÐP³×keeÚ&++}ˆˆˆˆˆˆJXòÙªÖoäLDÚY[›öãÁÔrDDDDDDO"K>[ñ錈´¬P§Ž“Á§UɲŒ:uꬩYðÙJµ¼«d3Ù;8ê=…ÇÞÁÑäz‡rDOAË”ÃVmÚàæoÿƒÞ(³$I(,,D‹–­À]¬ˆˆˆˆˆˆ4Uç³Ué]›¹§i¥(üî­ZÃÎÞ·ÓÒ ©Ê+hemƒmÚ¢ñ3ÿD^Î ÷œˆˆˆˆˆ¨æ°ä³ƒ>D¤•$Ix˜›ƒÆÏ4[³æ°²Ò.R*‘—ó’$Uc/‰ˆˆˆˆˆj6K>[1èCD:‰’„¼¼\Kwƒˆˆˆˆˆè±f©g+}Lt`ÙKzÓ_û0¥šzBDDDDDDDTÙ1‘( ˜ú£ÖWK®…Jüþûï;f4Z¸7GÛ6­1ñ½÷ð×_Õ—F®.¦Ü‚Émø¾ú*víÚ©5ßÎ;áûê«•n£ªóZÇÝ»wÍÒ—'‰,ËÈÎÎ6xçy""""""*O–eüvóf•>[1èSlàà·ŒÊ/ʺ÷ѶsrA+?YYYXøÉ'Ÿ6 ?ÿrçLÆ€à`,Zø rrrŒêOuJM½ŒO7năš›JeggcÝÚh¤¦^¶PÏ —qï¾Aùzôèn–zž$W¯^ÿÿó_\½zÍÒ]!"""""zlŽ‹–,Eü×Û«¬Zô9uêöïÛgt9¥,@’¡~]øó:¼÷ÂcNÁÎɶN.héÑ;vÒYǺµk1zôh<÷Üó°··Ç?þñbåªÕØñÍ7•¹­*×·o víÔœí³kçNô ´PªFæýÚÔÑçöíßqû÷ßU_ÿþ;nßþÝÂ=""""""züœ:}§Ïœœ>s§NŸ®’v¬@(}ˆ{-SXø7BC'âã ŒÚ[) $’$—›ŠÕèÅ÷áæ‰}ÖB©gFбcGѶmÛr×­­­qðàÁGõ¹º`ㆠxµW/ª@Ä냢e wÄoݪQ677cFB«–-0ê‘ÈËËÓY¾¼úÚ€ƒ!nkœÆµ¸­q8pƵ¬¬, 6 -Ü›cÄðáÈÎÎ6¨²Ë¦t-£Òwú”®ïСChòLc<Óøiôêõ þóŸkä1t™Xrr2úöEófMñ\{O|S¸óöò­[7·nÝ„·——Þü5ÕÝ»wqõÚ5<ýôÓ3n<ž~úi\½v­Â%pDDDDDDôȥ˗ñõ7;àáÑ»v톇G;|ýÍ\ºl¾U3%‘ˆZ?Ó'  /¾Ý»ññ[1zÔ;xøð¡AåŠJÍôQ–‰I" Š€$E’î Ï­[i¨÷hM+»DÊÞÁ»vïD-ˆB÷î=põÚÏ8ÿãy|‹/ÂŒ3ñËõ_Ñ»w,_¶Lg=úòêkZµjRRTV_¸p¢R‰víÚiä[²x1zõê…+?]E¿~ý°háBƒÛ0DE÷kˆ ãÇá“… qçÿþÀ´ði˜2y €GK· ]Â5eòû „ë¿þ³fÍÆ¿þ5àïï‡ÄÄDª™eþþ~zó×DÙÙpñÒeÔ«W~þ½q÷¯?àçßõêÕÃÅK—‘ý âJˆˆˆˆˆˆj¹›7obÓç_ qãg0wÎ<Ⱥ¹sæ qãg°éó/póæM³¶Wëƒ>àåå…-[¾Â‘#G°~ý:õõ½»vè,#Š%/e'‰² QRƒ”¢î  @ë†M …J¥RãÚk¯ €‹‹+ áÄ ¼=l®‘ïÈáÃhÓ¶-lllØ/ÔY¾¼úÚ(1pÐ@ÄÅŶj™å'NÇ›o½''' ÆÑ£GŒj£"ݯ!|||p2á$Î;ÿÞ½ñÃyÓPß'ýA¯½{{{¼ùÖ[ê¥aþþ½qª8èsúÔ)øúùéÍ_ýïÆ ØÙÙ! 09Ù™D9Ù™ „þwㆥ»HDDDDDTãí;pŽŽˆŠŠBaÁCH¢ˆÂ‚‡ˆŠŠ‚ƒ£#ö0þ™VÙàüùó=z1iÒûêëº6wÎøa z·u‡âêV4òû¹ t¥‚Èz‚>îîîÈÍÉAƒ† 5®çææÀÝÝ]㚋ˣeD÷ï߇««*pÓø™g4òݽ{Ï4~ZýÞÎÎNg=úòêk£ÄÀÑë•W0{öl|»gN$œ,—'==uëÖ8::"##è6*RÑýbã§ŸbÌè1ööPØØØ`ÿƒèСƒÑõdefbóæÍHM½ŒÔÔTõuŸîÝ1yòûP( qþüylØø©Þü5Q¯W_…½=r³³ Š"@Eüý0¯ Ea!òrjþlAxôïÑØò+S–ˆˆˆˆˆÂÃÃaïàeaŠ”ž­lm­°~} ÿ.€¤,2[{µ~¦Ï±cG1h`0†-_ÅÂÉÉ©Â2ÿ;ŒfCþ…‚ÿˆ:gúÈeÝCد~þåçr×ùå—r"—~àlÔ¨ÒÓÓ@#ˆ 6Äþ…Œ{÷‘qï>þï?uÖ£/¯¾6J4oîŽ6mÚ <, ÍÝÝѺuëry\\\›› ÈÏÏGýúõjп™rE÷kWì?p¿Ý¼…O>Yˆao5ºùÎHäääàíaÃðõöGûóØÛÛã…0{ÖlxzzÂÁÁAoþšèïü‡x•‰¢"Í>EEEx•‰¿ó [YÈrù}¸ª²Q +ÈPü¯õÙJñw>¬Ì´árI-µ>èco˜ ˜3w.¬¬*ŽŒÓ+ðtÇöôÜóxºc{dœ^‰§þa‡¸ÄGÁQT|$Q†B©»®÷ߟŒ¯·mÃO?]BQ…¢?ýtÛâã5f•Ø[6o†BQˆ5«Wk¤õé€ë×BQˆ¯¾Ú‚~}uÖ£/¯¾6J8h>ŒAZ–vª¥M;wì@~~>ìß¿â¥Mµakk‹C‡¡  +W­4é ÕݧöíÝ kkk4hØYYYý0t£âkW¯bÐ믣sç.X·n­Fš¿olÙ²~~þå¯i”J%D¥ö³¨T–[ŽXÝAP¿êÔ©,X°………F—/ýªInܸQ£FÁÍÍ vvvhß¾=öîÝ 8wî† †FÁÙÙíÛ·GTT”Î=Ê’’’àãã£~Ÿ‘‘4mÚhÚ´)BBBôc A].ÍÒã_ÑøÛ¿²ã[ZZZž~úi³ßŸ¾ñ5öóQô[eÇ÷ÿÛ»óø¦ª¼ àϽYº—Ö"¶€Z ”ºPvEYœ-êˆÊRŠDP}GqAEEYTe©Ã¾È¦R  ЖîM“¶¹ïiBÒf%I“6Ïw>¥Í]眛óñœ9÷œšx~‰ˆˆˆ\¥¦ÛV>ß采 ³ûxUæ¡*Ÿvÿt}Ú=€™ãz¢B«é# ÜÊHŸÐÐPÌœ•Š·—¿6=„‡Z·ÆÛËßFêìWjñ¼ÔÙ³qòÔItЉ©Ö°H= ßx´l‰ÕŸ¬ÆÒeË­^ÇÒ±ÖîalذáÆ›ÏÃÔÔTìÞ³­¢ÄæÍ_cÞ¼WíºÇû¬ÂS“Ñ®m³#ˆìMoƒúÕ~ªZ¶üm,]¶Q‘÷⩉ÉxÿƒU†}ƒ‡ A§˜Ž&׳dùÛïàÏ<^={ U´é„Ö}“t=‰F^ÖŽ'ÇéGâäää`õêÕØ¹s'RRR>ßøÇ[\¼x½{÷Ftt4~üñGbݺuøðÃ3gÎÄàÁƒqìØ1äææâÛo¿Å70z´ùQk‹/Æ´iÓ ŸÇŒ¥R‰ýû÷£  û÷ï‡R©Ä˜1c\ÿÑ£G1{öl,Z´³gÏ6LoÌ“ùoOþ9_ÕüÕ+//ÇèÑ£ñòË/»4~[ùëèóa‰3U¶òÌ™üu÷óKDDDT› ¯~2KÒq(ü´~ ¯o²S¥R™]R\ï̉c¸t)IZœKåë/6ZœÇo<ïò¶™¹Ž FÍpþ—Ýx G"Šÿw ÅEpºéóhÝH—¡òŸOõEêâ}ÇCµCƒúv¯îåí4 ¾ßþš5kê’ëµn×Þâ¾óçÏC&“YƒÉVýcL„jÄ+W® 66ׯ_·zœµíöÞËÝÆŽ‹˜˜¼ôÒKvŸ“››‹ÆC¥R™l¿pᆊ3gÎF7#33õŒVÌËËCTT”áõLküqã½÷Þ<óÌ3())Á§Ÿ~Š¢¢"ÄÄÄ`ÆŒxòÉ'±jÕ*,Z´‡Fpp0Ïä©-ÆùçH|æòWoúôéøí·ß°uëV‡®élþÚJŸ½\QNæ®álþºóù%"""r֙ǜ¾†£m«‚Ül¨E5¾9²•#}Rð;š4GñÍ"ÌYüŠo!¬IsH¿#ºa}hµ´Z ’V2Ì룭ðtÐäÛ¶mƒB¡ðt(d¶ê²z64nÜJ¥‘‘‘0`¶lÙâ²X,½¾bïȉݻw#((mÚ´¿¿?š7oŽY³f™m°———ã?þÀŒ3˜˜Xmÿ’%Kðâ‹/štHŒ1iii¸zõ*ÊÊÊpõêUÌ;#GŽ´+¾•+Wb×®]øê«¯°iÓ&|ÿý÷X¹r%`Ò¤IÂáÇ«³k×.dff",, ФI,X°Àä|[Ö®]k˜?å³Ï>ÃØ±cí>×GóßUåo)ÿÌgŸµüÝ»w/öîÝ[­³Â‘NW寽éó4Gòן_""""Kjºm%pÑ*ðDTW=™œ Fƒ·ßYÂÂ"@aaÞ~g4 žLNöp„Î8p vìØ‚‚””” ==ãÆÃĉ]r}s+9²BÕĉ1aœ>}jµ/^ijÏ>k˜³$)) ›7oFnn.4 Ο?éÓ§£sçΆk|üñÇ4hêׯ_íú±±±HMMÅåË—QVV†Ë—/#55Õä|knܸ©S§â£>‡~ˆ©S§âæÍ›v ¸?ÿm±•öÄg--•»½åïlþÚó|x’³ùëéç—ˆˆˆÈ5ݶrÉHŸRU $+3«Kí_¤6žGT¨Õj‹ûÖÀ¬Y©˜7o.V¬\‰ž›„+W"+;iisѰ~Ô¥¥5­k%''cîܹ8~ü8”J%Z´h§Ÿ~ºÆ:l?~<òòò0|øpddd Q£F5jæÏŸHKKÃâÅ‹1~üxh4DFFbذaØ´iݤÖË—/ÇÖ­[Í^ýúõ˜9s&ºw¬,4hÐýû÷ǺuëìŠï¹çžÃO<ØØXC¼Ï=÷>ÿüs»Î÷tþÛÊ?[ñÙÊ_g9›¿¶Òg/gFSvÓÿ­¿ž³ùëéç—ˆˆˆÈ5ݶ^ýd–4¸ãPø;1§OçnÝ,NzøÝ¶­8d¨ÃÕ–óˆêŠÂÂB¤8`qÉöÀ  Lÿ/Þyçmö^˜Œ®;¡¤¸¸Úñ59§½œ™÷ÅØÖ”M›6aÍš57òÉ>Ì_÷bþQmfnÉvw·­ŒçôqzÉv?¥9ÙYÎ^†ˆ<,'; ~V:aJŠ‹Ñ£{W ©ì2d(ztïj¶RòV޾Våªs=íÍ7ßÄ´iÓ<FÅüu/æ/Õ55Ù¶’Ö'µ%,< ·²³¡ËQ¿AC(ýüœºÕI’ Q«‘u·²³fõøÂü|<1a<’’’y/n±Ã·VàjDîÅüu/æ/ÕEno[UöË8=§O@@DQDÖÍ›ÈËË«¶¿IÓ¦8}ò„Ã×­-çÕe üýýáççgóØ[ÙY¸+,”>DDDDDDN¨‰¶•K&röó󳫱HDÞÉßÁïomž´™ˆˆˆˆˆÈ[¸»m¥ëô©…sT‘o37!ÁÐÏã’‘>ŽÒjµøíÔIœ9{¶VMKž!ÊäËDÈåy\=. ÑѭмE ˆ¢Ós¯û<Ö?DDDDD¾)0(­[µF«‡ò™¶•GZÑgNÀ±ã'P¡ÕBÉ<Õ"2™ˆzõBèï…•Õ¥êªRµ'O€$U åƒ­<N­Çú‡ˆˆˆˆÈ7•¨T8zì($©m¬,ƒ^—Ôx§V«Åï\‚(ˆhÜ$ BHH(Wü¢j$IBaavíØŽü[y FP` ÏôÈê••—ÃOé‡?ÿ¼ÄN'±þ!""""ò=ú¶åŽï¾Åÿ®^ÃÅßÿDë6í|¢m©ëô¸rVŸ¼¼<\¸pmÚ<„€€“}åååÐVT@®T ©o?hË+yå² ïNuIPpû$á‹ ­Ð‚™ÎÉd@hJÕj›ÇZûî@NN>Y³ÆÅýÍ›»#\cýCDDDDDU‡ ©o?¬[»’V‹òòr(­¼Ib«m¥R©pêÔi´lÙaaaî ýŽèûx\>ÒçÆ8~â$ d2ó—÷S* -“€¬›7\Õ!…ùhÐðn ·|B©´¹Â–=ß=™LŽÌÌkxkÙr$?1;tpG¸Ãú‡ˆˆˆˆˆÌÑ·-erü «ÇÚÛ¶**.Fú¯ÿÅ_ÚµÅÝwß2‹ÀV>IDAT펰æÒNŸK8{öBCC1pÐ` ¼¼¬ú‚JJJ Ñ” &yA¶ë> ±ò­ $I IªìÅ’IÒ®!I’a»¾ŸKÝñ’’îâ•1ég·®Ú±`üY’$HF«™|6º$ ’¡£FçL¯ƒéU«Õ†ëŠ‚Ñ;}D]ö~÷êׯeË–cöìT¼÷Ÿ÷ñØ££Ð'1Ñ¡×Ö?¬˜^¦—éez™^¦—éez™^¦×ZzKKKuq_•½íŠÀÀ@ 1ß}û Ž;ŽèèѬiS‹×õ—uúœùí,222pw£FèÛ¯? rsÌ7¸ o¸&p›ÉPÔ•Û *B€Ê½•å^ùÙÌCc8N÷„ßÑB,¦¬}IL®!IŒÃ¶zm¦×Zz+´ZBås#ê~|(YN·#ß½òò2(À[o-żys±~ãçÈÊÎÆc>jRQÖ6¬Xÿ0½L/ÓËô2½L/ÓËô2½L¯­ôVTT@¬l[šãhÛª¤¨C‡ Ç®;ðÛogQR¢BëVÑ6ãªIºNÛyeUnn222II}‘›“mE…Åãu=kº “´’ÖðpÜnt •ÿ«üTÙ»(€ 5î±t=…FV‚ñCcHžþA„ʇK‚ I†>]¢dt?Ç{F¯¡û’TöŒÅA`zLïícDïÉ(Çnsô»eee¨(ÌÇœWæ`ÌØ1øa÷tЉA‹ûïwKìîÆú‡õÓËô2½L/ÓËô2½L/ÓËôÚ“^Ý¢KÛV¹9YHJꋵk>EFFîiÔááÞ3ÇKFú4ºç´m÷œØé£Õê–­¿¯ùýV‡UÚúîº%ÛçÍ›‡¼[9().r_Ð6˜PÍÌ1ŽbýCDDDDD–Èe2Ô Á-[ZP`OÛ*00}ûõÓµ­J=7?ª­¶•ÕNŸ;0W]ZŠ×2ÍîÓ¨Kqÿƒ­ “+‘‘ñ'4Ìªä ”J™MÕw›|€(“ã¾– Ñ=÷Ú|ÕÍÚwÐ-+hmM±gBnÖ?DDDDDäJJ4iÖ ÷5oá3m+—ô±E«Õ¢¸ Mš6EÓûîƒVËIzÉ:¹\^mfu_¢ÕjQV^Ž¢‚ü:ó}q×H[Xÿù.Q¡•$Ÿj[ÉuÕX<€ ­EE…5{S"ò*w:’ÇY¬ˆˆˆˆˆ¨.1×¶Ò÷ó8õzWëvíï<*"òYötø°þ!"""""²ÎV»É÷fÅ%"¯à©‘>DDDDDDu‰µ¶•ÕNApåÊ—DD¾ëÊ•+vôaýCDDDDDdž=m+]§…ƒA€J¥ry`Dä»T*•Ý«w±þ!"""""2ÏZÛJ¿ÉæHApùòe·HD¾£¢¢—/_¶«Ã`ýCDDDDDdŽ#m+»:}JKKÙð""§dff¢´´ÔP¯Ø3Ò‡õ‘)GÚV6Wï2nx={hÚ´©Ëƒ&¢º)##*• ¢(ÚÝá°þ!"""""2v'm+›>¢¨ $IA€Z­Æ¹sç I$I‚V«5¹ Wä!ò=’$™ü]µ’Éd†¿õûôu‹%¬ˆˆˆˆˆÈ׸®m¥»ŽÍNýoA -㟪g£‹È÷WLzÆ“q´##}ŒgýCDDDDDu«ÛVv½ÞUõæÆ¿«ÄF‘ï1WWDÆ¿õ5öÎéSõ¬ˆˆˆˆˆ¨®ruÛÊ®‘>ƯXX Fÿ7]D¾ÇÜ÷¿j]Pµ‚²…õùW·­äöèhcˆÈUXÿ9¨òÿ#·>“*ÕJìô!""¢ZGE”——Û\ <‡eä=XDD¾‹5?Õ:¢(B­R±ëÅXFÞƒeADä»XóQ­#Ô¥*Î÷åÅXFÞƒeAD仨éCDDDµŽ(ŠP—rä‚7cy–…ç•kJQŸçé0ˆÈ±æ'""¢ZGEhJKÙˆõb,#ïÁ²ð¼â¼¸pî”§Ã "ÄšŸˆˆˆjQQª*±Úˆ9r233M¶íÝ»;´Ç?î5Ùž™™‰‘#†›½NÇí çädÛ£ñyŽì«+ì)#(..ÆÂ7þ…~}“Ð¥s,†=<¼ÿ>´Z­Ûc´Už5]NŽ<_ް§,²³³‘2mâãz£gî˜1=ÅOII æ¿ú*âãÐ7©,x ùùùtå7åÅÑ£{7ôîÕ3_~¹¹¹w§µrrrðòË3‡„øxÌN…¼¼Ú3ræêÿ®âò¥sžƒˆ|PeÍ/y6 """"ˆ‚€2¢•9Jñó¾}&Û8€ûï¿4Ùþó¾}èÝ;ÎìuŽ=føûÑQ£œˆÚ·ØSFðê¼¹¸ûîFørÓW8pðVº…ø÷ŠnÑÛÊÓ]ñØS)Ó^Bûöí±í›o±}ÇN܉ÔY©€W­Âø °ëûðÕכѠA̘>°î³Ïиqc|ÿÃn|·}ÝÓëÖ}vGqZ‹!-mºuí†;vbÇŽèØ1sç¦ÝÑ}GúQ”˜ˆ}?›vú8°/LžŒƒ˜lß÷ó>ÄÅ™ïô1V›FÔ?ýôþúØc (ЍW¯Æ¯¿þÊí÷ö¶òôd<}ü Æ=þ8‚ƒƒŒää‰8~\×áùÍ·ß I“&ËåƸqãôiÝ«Jû÷ÿ‚á#†# AAA5êQœ8~Âå19|„ÒÏJ?? 2¿¦§»&ñ5 ´^î¹·©§Ã "ÄN"""ª“Z·n+—/£´´píÚ5hµZôîI’pýúu@ii)~¿xi¯{•§c‡öX»f ÆŒ~ÌðÙÜo8uò$&ŒÝ»¡_ß$lÛ¶Õ$†sçÎaÔ##ñܤgQPP`6ÎââbL›öz÷ꉗ¦NAqq± sÁûEFFâ£>4y+"¢>~ؽÇð¹c‡öزe ⑘Ü‹û÷£_ß$tŽí„=»w޵V&Æek®<­éØ¡=6}ù%~xhµ{îÙ½c;!¶S F?öW=rİÏZù:»H’„[·naó×_#.>Pª*…J¥2£V« ß«ŒŒ 4n|¯a_DD~ÿý¢ÅëÛ“>s1´iÓÛ·o‡F£AYYvî܉֭[ßA =ƒ9‘§°Ó‡ˆˆˆê$AнG¤§Ø¿=zôôŽ‹Ãûéé‡ÛÙd¾¥Ÿ+ß}Ïäzú×¼Œ_÷JKKÃßþþ7ìÙ³Ï=÷<ÞZ²Ä䜵kÖàÓ5k1vÜ8¬ü÷¿ÍÆùîÊ•øÇ3ÿÀž½?¢g¯^xÿ?ÿq2åµË«óçcÇöí8 ?-Zˆ={öàÂ…óÕŽ;sú4¶nû³RSñg'OàëÍ[°pá"̘1Ýpœ­2Ñ—­¹ò´åŠذacµ{Θ1)Ó§ãPú¯˜øÔS&¯Ù*_gâq‡©S¦àá¡Cðï¯À¸qã½{÷ÂÆQZZŠÜÜ\,[ºÔÐIWXXˆ€€ÃùJ¥Ò0ß9ö¤Ï\ ©©³±xñ"tíÒ]:Ç⽎ٯÌq&©5Š9‘§°Ó‡ˆˆˆê¬ÄÄ>ØW9¯ÏÁƒÑ£§®Ó'..ÞðŠ×¾}ûoújWŸ>I·yý/7mBŸ>I†×Mª¾žóÌ?þ€€tê‹úÑì5öìÙûš7‡L&C||vïþÁátÖf­ZµÆ×›·àÍ%KQŸoÜ€qcÇbÇŽí&Ç=ýÌ3 BBB"Ξ=‹Ñ£Ç 00 ‰‰(//7g«Lì-[sžzêiT»g§NðË/¿à×_EÏž½°yËíÑE¶Ê×™xÜaé²eøißÏ6|8æÏŸ˜–2ΟCߤ>øûßGǘŽð÷÷ •S•`c§;‰aÙ²eHNžˆáç_öcü„ xw¥ùŽToĉœ‰ÈS䞀ˆˆˆÈ]bbb°äÍÅÐjµ8~üæ¿ö C‡H›ó Ôj5~MOÇ”)SMγ·žŸŸÏ7nÄÙsgqîìÙjûï¾ûn€B¡@ž…rrrÛ)ÆðY¡PØuïºDE´mÛmÛ¶Crr2Ž=Š™³f¢ÿ†côe"“ÉõêÕ3{-[eâLË]wÝevû‚×ÿ…”iÓ0ù…ç!—ËñÁªUhÕJ÷ê‘­òõ¦=Qñ쳓Ô'‚×¼nØîÜ9C^„††B£Ñ:ÊËËâòÒÓáµ àçç;vèïô}jJT³hÜU?ÒÓa‘âH"""ª³DQDtt4RgÍBË04LEQDû0ç•ÙˆŒŠB`` ÉyöŽT˜2åEaØÃÃðޙզô£L4 êׯoöaaaHÿõ¿8rôŽ=†Cé¿:’ÄZ/!>Æd[t«V(.*2Ùæª2qvŠ9áááø`Õ*ìÛ÷3¦¥¤`ò “ ûl•¯;âq…ŠŠ DDD˜ÝwéÒŸhÛ¶ Ù}÷!''ǰ¯°°ÍšÝçò‚‚‚dØ'‚¡¨6àDÎDä)ìô!""¢:-!1;vlGÏÊW»ôâââ±k×.»VíÒ“ËåÈÉÉ6|¾xáúèö:à“O>©vüï¿•J…ƒ"1±ÙköêÝüñ4 ¾üâ L?Þîxꂸø8¬úà\¹reee¸yó&6¬_AƒßÑõl•‰±ªåy§F=2»vî„L.GX½0äMØëHùº*ž;1ú±¿b×®](++CII Ö|ú)†xtÔ#زe 4 þøã|ñùç3v  K—.ذa=  Q«±k×NtëÞÝå1$õí‹õë×!??jµ7n@¿þµg¤'r&"Oa§ÕiݺvC@@zöìe²½{÷îP*•ˆ‹‹·ûZ‰}ú`è!†ÏsçÎCê¬YxtÔ#hq‹jÇ÷èÑŽz[·nÁÓÏþ Ο;‹Möt(Dä r³¡5Øvd‹n"gIà¥ïU¥ÕjáhX6š¼ËÈ{°,<9QMp{uE9ˆ€ê«-y%­V ¥¿?±^Œeä=XžZ/¡õÌOŒMDäj’ @„n`‚ B`¯ÕZ­~þlÄz1–‘÷`Yx'r&¢%Ý^RÔo`—ÕlÄz?–‘÷`Yx'r&¢š$@$ãNp>"""ª=$I‚_@€á}uò>,#ïÁ²ð¼«ÿ»ŠË—Îy: "òºi›uýôiA¹(Ç©k§<9áÔÿŽC!S0Z³kí7JZhqOè=¼ þrHDDDDDDDDöÉ+ÉÅ-U.r‹s )1fÐ0³PûÒõÿ’ Õ…5!Ý‘ð€p¼ðד~žÿ?¾e'üî…IEND®B`‚java-algebra-system-2.7.200/images/jas-pack-over.png000066400000000000000000001315741445075545500221660ustar00rootroot00000000000000‰PNG  IHDRPÈ?µY<sBITÛáOà pHYsÄÄ•+ IDATxœìÝy\Ìùð×4$¥ˆÜ«ì"Z6asû¥¶]–•äXWÈj-– [ì.Ù%lŽB’km²îÔfK‹äÂ2#„¡¥&:&Õwæ÷Ç·Mº›™ïïçÃã;Ÿù~ß3ómÞßÏñý|xr¹„Bˆ®3à:B!D(áBÑ ”ð!„èJx„Bô%%´%<Ív1‚ëÐÃë¸FçatJh'jÒ$„¢(áBÑ ”ð!„èJx„Bô%|š‘‘™—W`ffÒ³gg®Ã!z‡jxú+?¿àÞ½Çúvh¡U«äöÅ@·éA‹7p ÑG”ðôשS)c?Ò·C­_°xÑT®£ ú‹žþ:{p«Aƒz\‡@ô%<=uïÞãÍ‘¿éÛ¡ !úŒ­è²[·Òöì¿s÷a“ÆV:µ»{÷áßO711úñ§m[¢J²s=z´h€ÚŽó€è_annþÿ¹ôèá¸ac,‡Ÿ êÒÅáÞ½Ç;9š—W—'ýÒß»S§v2™,xYT^ž4/OÚ¿ß^^ÿS:##óXܹÔÔ{OŸ¾hÞ¼‰ë‡NÆõýº°’CoÛ~X(LÏÍ•ÚÙ5^0"€Ó§Sþ8y)77?/O¶ÀÈÈðéÓ›"bss¥99y›8uúÌe—N#>hffÊúüùë§Ï\¾}û¾©©q÷î>çijj¢öÏžT‹DòjÝúhc¹\îØ©Ý!}Èd²ƒO_¹ú÷½{ml,?òøð£\y<€å+¶ge½ÌÍ•~5Ó'?¿`×î¸Ö­›ytkÖ̆=?ss¥¹¹ùaëç?{öb_쉻wÓ›4i4nìGíÛ·æú½îQ Og:tÚý£/=Ü?Üõ]Pà”ì융ë£%’Wr¹¼Q#‹nÝÞ`hhhccicciÑ >û*™Lþ{â…° 1ç/Ü?ñ»æÍ/ ÞÒ½ÇçOžüàéÓ«CwmÚ¼ÿéÓlù¢ˆÍ¿…oÜ—rù¶âпýv²£ãÈ•;Ý÷Z¼hêTÑg#¿Y¼¥òC3¿8µ>ü×£Çβ[är\½vgͺ½‘Q†a7¾z•÷óšÝ‘QÙu,>á¯'â>Ÿ°8`þ:EEÅ“&ÿaŸÉ/^d3oü§Cû¯þyW‡N^bñs5|à¤x<ÞÆM±+B¶¿x‘mllàÑ£g½ûúŽûm«VM¿ÿnZ·nïyyÏÿdèìââbEEÅÛ¶Ù{æÏË ÃLMg½z°‡?»·§O_ü¼f÷æ-Î5{•S—öŸó\²ÝÙåó´4$E¨†§»6o9Ш‘Å¼gffjn^oá‚I‡Ÿ133133=kLAAᱸsÍšÙÌž5¦ô«ÆŒöH^]¹ú÷æÈßbcBÛÍûf Ç«_߬yó&7,ŒŒ:¨(l``¼tÆå+·ãÎ+6¦¥=3.ðuaÑ™S›íX64‘‘Yù¡§Nžžþ,øÇ(Å–œëÕ3=wN±¥Y3›ÐŸçîÚ}üEföÁC§ccB~ Q# +B¶oßy´·ëû«VÎæñx;Û7nlÙãÉó×îú%X¹/©»W¯r§ú·mk½ç§Ö­›Ëå“§,9áFз¾Ó¦~àÝwÛ<.™¿pýöG§ø[4åú aìþ?BVîL¾°ãâÅTüûí·k×Bq~nÚ¼ÿào« 8:Ú_¹ú÷ñø¿ügxsùn‰ „§³Þmß:îx’] ^½ºôpqì×·Û…¿¶³íB•ãó ˜˜àÌãñÒ`iÙŸÏ/¯üÃÂc^µlaËf;›Çõ8°{5]ùÅÆÁn= –ÿ4ó‹é^­[7“ËåëÖG8ÀYñ6»wïÔÐÂüÄÉUš¨™@p×Ë; WÏ.žÞbdTòCtûö}öË8࿳Åí=æ/\âÄÅ)¾Ãð twîhmmééÙûуcMš4bK*NÅ¡Cú²Ù@³f6¸ŠG2ÔõΈ梄§³ÌŸ˜zó^≋Çãÿ:ÿ÷Á=÷ï[Y¿¾Yu^Þ®] 6mXYYÔ踷ÿ¾ÀÚº¡b‹¥e¶oF¹ìÛµÀãñÚ´±™™ýüE6€}±'._ù[Q¬Q# 33¹\^dOÔãúu¡kŸÉyùÅÅLVÖK[[kvûíÛ÷Ù‹¿ßÔ0Ôœ}\XXÔÜ®±¹ùÃ;íí[²Z´°}{ÿmÛØ©*t¢Í(áé,k놿LJ?zô,îxÒ™3Wþ8™œðû…õa¿²ãAÊØ³7~¤×ÿÚLM«y ¹\^ú¿¶M¬äçTóåoº’—Vf(Š¥eƒzf¦ùÒ‚ÏÇ}¼pÁ¤jp¢Q£†gÏl™3÷çãñ ûlîÉ›Ø1GŠì²ü«^½ºT²‡ÊÏOº¸!å¢A+:k°‡ÿî=Ç[¶lê7mÄžÝË„w4·kœš*bŸe[e2û_¿éËŠŠŠ«³[oæ¡2Eƒu ¦¿x‘­ØXPðšmo¬üÐl“T%;¯ŸÏ<¸'€ËWn—ÞÎ0Ì’¥‘•$N¢~½]ß÷Ý6Ñ{~ììhábê¤É?°çƒ““CS[k¼õ%>~œA·²º£„§³^¿.Z´x#;º€AQQ±«ëû컾ÿ.€ÄEEÅ÷î=nÒ¤Q½z¦ÕÙm—.=.ÉC¿ývòþý'222Ù¤2n¬§çG®r`úŒÙ‘uÅÅžS–Þº•Vå¡»t¶G©$—““ñïÏܳg™Uƶ1|AS[ëN;V2Î¥ àõ×sCïÜyH—üÈÂÂüÈ¡PëF Ý—¸`áz†aLMM~Ù±ÄÏ_öãVö¼‘‘9öó úIÝñèÊWs9;ãbD­_Ýà´úõͲ³s5²ËñøqƸ±ž_Ïk`PRÁZømXø†˜V­šÊå[0h €‘£æ'$œg{¼ø|ƒúŒr/½Ûk×îøN]šžþ¬oß®99ùݺ¾—•õ’×±CÛ›7ö(.. Ù±ÿõëÂÖ­›=~üϨÁ‹MeÇWthö© ×oŽ<àèØ®qc+©´`öWc>úä+öÙ_÷þdß®åÀÿM/**60àò[·nvíÊÞÒáee½\²4òÐá3[ò33_ŽóQÀ7ãët+^?¤¤ÔþåÚ®nçai¥Ï.kë†÷ïINNuíãkllĦ³›7öµnÝìï¿|vùòß­[7ÍÍ•Êd²ó'ŽòÌãñìZxäääñx<6ÿÝJÝ×¼yv牉FŽZÀžÓýF, žaÝxL&c ·oß*%y—RÞˆ¾ŸZ‹ž«ÛMAÁkSS¹\.‘¼*.f7¶zû¹°°(;;ÇÆÆ’Í‚Õ—Ÿ_››Ï¾0;;§¸˜155633)3b³°°(''¯Q£†5:4Ã0IŽ©©±¹y=†až?—˜šš˜™™Uÿ2_*-ÉäÕ¡S=ÿuS^«©—/sëÕ3­¨—Kz~Jh-Í;“ˆ’°uרQÊÊ)†t×H½z¦ŠvHöŽ…ŠöommYÓCóù|KÅã¦Mmj¡b⢽64ç:¢S¨Bˆ^ „G!D/PÂ#„¢(áBÑ ”ð!„èJx„Bô%>xð ê’. $ SE1[[DD`æLH¥ÊˆBÊA Ôà 2¾¾ÈÌ„“SÕåà1±ŠblÅ.9ÆA$ªs”„RJx¤Ú$Ìœ‰ˆ¬] XXTQ^,†PìØQõÎ]\77øø &F)ñBHi”ðHõ°Í˜ áê ¡ööU¼dϸ¸`õj…ª(le…—/1oÖ®EHfÌ æMBˆrQÂ#UQ4cº¹a×.XY•¤¢zõ*{•TŠèhøùÁÌ îîUWÚœœJ:]]‘˜‰„š7 !ÊE Tªt3æ¼y%m XYUöÂ#G`m]ÒÏçí„„’WUÄÂii%­¬°k5oB”‹©TéfL‘`<ff¾Ša_ß’ÿ:9ÁÁ±±•ÈÞB!ˆD˜1ÀÍ›”ó!Ê@ TjÛ¶’fL‹Ÿ§OáàPÙ«RS‘™‰!CþÛ2a""*»?m •JѼ9’“KvººâìY¸¹ÕùmB%üüJnË+›VÙÆR7788 <\9ÁBJx¤Z¶n€#Jþ›–†–-+,üü9ÜÝagWv»—Wu5<} |>,@t4ÄâÚÇL!o¢¹4IUÄb еkáêZ²E$Bóæ• Z)ÍÙ))Õ*)ÁÚú¿¤‰6Ô}àïÏÁqíì\2˜…Bꌚ4‰ŠU¿I“BT‰š4 !„èJx„Bô5iBÑ TÃ#„¢(á‘òT2é%‡43*Bˆ– „GÞ’”OOË."‘&FEÑ”ðÈ›K–ÀË«drKÍѶ-ðï$g„Rstã9yÓþý0n×q¼…ÏÇâŘ5 \ÎD„(;×9)CWn¥¥„GJ‘J‚à`•ÌVw®®%«(,[Æu(Dw]Œà: ÓÃ딆š4I)ÁÁpp€‡×qTlõj$$@ à:Bˆö¡„Gþ%#!K—*y·Êm#²³ƒ–/§Ñ+„š¢„Gþ5w.ÜÝaoÏuUñ÷‡PˆÄD®ã „hêÃ#ÿZ°­ZqD5˜™!:Í›s!DËPÂ#ÿrrâ:‚jÓüj(!DóP“&!„½@ Bˆ^ „G!D/PÂ#„¢(áé1†Tªò£¨aR"5¼ Bˆö£„§Çѧ×AÔ™@€>}(ç'—ËÏ»öôé Å–ë×…çÏ_OL¼–ö˜ÃÀ´%<}%•"4ÁÁ\ÇQgNNppÐ…7BÈ¿<çää•Ù¸cçÑ>ý§´nûÉíÛ÷Ù-cÆöîë;ø£/ùSí1j%Jxú*<ÜܸŽC–.EBÄb®ã D9FŽšŸ”TvÂX‘耢ââôôgì–Ôë1ýû îà´Ýx®—ÄbDG#*J㽫{{¸»cî\ìÝËu(„ÔUVÖËÔÔ{ooÿj¦Ïóç’NÚ¹¹õPllР¾CÓz”ðôRp0Üݵij•*Í›77ÄÇkôR„TE.—/YYðºðí§š4i±)Pý!éJxúG @r2æ:¥²²B@BCáæ¦#ÕV¢[¶m?,¦çæJíì/˜?ÀéÓ)œ¼”››Ÿ—' [`ddxútÊšu{>`ÇΣ璮ðŸáݬ™MFFæÆM±¹¹Ò¼<é“ZµjÊíÛÑRÔ‡§à秃‹†[·r!å(.f~;pj}ø¯Ge·Èå¸zíΚu{#£2 Ãnéßï¾ ‹ú66–66–††%pYY¯V‡îÚ´yVÖK®Þ…¶£žþ‰Ž†©©úç쬎[ñðùض ¶¶ê8!54uÊðôôgÁ?F)¶ à\¯žé±¸s¥· à¼`áz¦P6|ØOÙÚZ¯]3oÛöùytNíQÂÓ?VV\G 2ºWm%:„Ï/Û¢öö–Jðx<>5×× 5iBÑ ”ð!„r¹¼ò·n¥]ºtS=ÁèjÒ$„u`$K'¹G2*(V$“ÉÄOzþ\Ò½{'µ©Û¨†G!êÐ¥³=J%¹œœ¼ˆÈߨÇÏže*Šuíú.¡èணc;uª»(áé†ÑÇi·‚²“3¡!Cú~3÷óW¯òz÷õ>bÞÈQóçÌÃ>ÕÖ~h̾DöñÆð…]:Û/ü6ìƒîã^ùŒrpöìUËFý‹‹‹ë×3í7`Zô¯ Zõûãdóúf‹¿ÛäùÉW\½/-«²™h½ÈHÄÆ"!›£«í¶„2øúâðaºIjÀÙ#Tz†a$’SScsóz Ã<.155133166âñxŠbÙÙ9††|sóz* ¦Zzøqó'¬TÃÓu ""°x1gpõ§âäwwZEh>ŸoccÉf2>Ÿß´©¥eãÒÙ€¥eÈvº…ž®[µ puå:.øû#9™6 !,Jx:M @BV¯æ:ŽØÙÁÏ`®C!„pžîb,_ww½îÄ7öïç:B÷(áé®ÄD… â:N™™a΄„@J3¢ï(áé®; 33®ãàš›°k×qB8F3­è.ú‰gñùغ•?!„žî¢‰Õ(ÛB¨I“¨œ³3×B@ Bˆž „G!D/PÂ#„¢(áé©”¦ÑªšTФ$®ƒ „p€ž Æòå\¡ñ$ÌšEW„è!JxºB,FB–.å:ggww,_Nl¢o(á銹sáî{{®ãÐAA ‘˜Èu„µ¢`uBRfÍBb"¬¬¸EKÄÇ#4Ò=éä tÛh¹teXJxÚaàé //LÊu(ÚƒýÐÜÜ0oסBÔ„š4µßÖ­0y2×qh>!!ˆŽ†XÌu(„5¡„§ýNžÄâÅ4sf99ÁÅׯs!DM¨I“Bˆ^ !„½@ Bˆ^ „G!D/PÂ#*F76B4%>ÈÈЂ„¼H‰ç:gã\õ¨]ú4V™¯žöX¶Œëô­ Kˆ.¢>,€¯/üýuoa&™L–&JãÿK.—hóNi¢4Ç>%“ɆaÆÒÊÒÚÆºÌ~ärùŤ‹mÚµiÚ¬iCzòèÉù?Ï3‚Çã•[àæõ›ùyùy¹ymÚµaãÔ1U~¥¥^K?ççå·µoÛ¾C{‹†DwEõêÕ³ka÷ì鳜—9laתm+ccãŠööOÆ?/%/ÿmÕ¶•‰‰I­ßˆL&»z;/7/?/¿]ûv-[·¬õ®”‚žæ‹¨¨L›©‘¦ñÓŽ_޶nÕôžð¿Ô{¹yó^‡m þk]¸~]8f\àÃôg„°·×°„ÀÉ îî˜;{÷rŠ’ù÷õ"ëÁ½ÚÚ·uxÏa÷‘ÝæMŸ——›wãê¢Â"¾ÁûÎï7eÜçS>/³ŸèÑ_MúÊÐÈðŒàLûíëRÀŒ€ßþnjfúÉgŸ”[ÀoŒßÝÛwå2ùÒÐ¥ÓgO¯Ë±4S•Ÿëáý‡ë–¯‹Ý+—Ëßíôî»ß=~èøµ”kŸþ¬›K·ãgü´î§ÑGïÚ²+ñX⣞g<0fò˜µQkËÝáãôÇ}:÷É}•  K·.†F†‘Ñ‘­Ú´ªfØ/ž¿`ƶ©­bKQQÑ´ÑÓîÞº àçÈŸß>mJ+((8vàØÝ[we2Y‹V-Ü>v³k¡äëKjÒÔ<ÁÁpq“×qÔ•èÞ#Ož<—J_+6æææ;:*,,*]òÃR¯Ç¨;¾šš7B!’’¸ŽCÉLLL.$$\HX¼ÝôS›íüvâ·„ ¶Íl4´lÈ–,÷gë¾è>€â¢âÇéëσ´¿ûÀ–°-•9—zε¿k]Ž¢Éªó ˆ;ׯK¿›wN›5íVÆ­Ääİía[÷m=›z¶¨¨hÂð y9ylÉy‹æ%\Hî3¼Gï~ÝùkEßÑÆŸ7þx0û8&!&áBBõ³€õ!ë#Ö¼1g½‰‰IÒÍ$§ªþ5þ-ìÿ~ÿ{wîõêÛËñ}Çß­èÚ¦kØÊ°ê½:(áiž¡Cuc¬ÊšŸçNÿÉ¡«K7Qž;w­ÜÂ׌ù6++ÃÖ¶ê’ziêWSÇO¿lí²þný벟m·AI§’îܺSQ1óæu9Š&«Î'p1颯·o^nÞô9Ó—š›ÿ÷iÔ¯_ÿûïGMõö«\\]ºØ)f6…nzû٬̬俒2¸Ö‘_8{¡ÜíõÍëWùÚù_οwçßßß­ÿ§#?1f„Œ‘ýðÓGOjÏÛ(áiÝè(rvî¸më÷žž½[òó ~Xº™ÃêÊÃC+Ö âDã&WG¬žöÕ´ÒÕ5•ŸŸ¿;j÷¤“ØÿF…G)):­QO@.—Ï÷Ÿ_\TÜ aƒ¹‹æ¾]€ÇãÍ^8»Üý5ÿ+¿Dþ"É’”y**OK«SŸQI–dãê;6íPT†9vàXTXTÊ…”éã¦ß¿wßk¬WΫÿñþ‹¾.gR¹\5iÆ$##£‰Ó'ÈËÍ‹Þ]£çåå¹÷tÿjòW»tœ0}BÆÓŒ~]úmY¿å½NïíŒØYIÓ¨F©æ'píRI¿@‹Ö-*ÙÛîûy *³ÑÀÀ`fÀL‘ë"¥¥n-Ý»m¯×8¯ŠFoþ¶÷·Ñž£Ï:ôcßl¿+ÉWúvî»rÉJöÙâââvíÛµjÛ €©™i#›Fl™š™–ÙÉ?Ïþ™>nº…¥ÅÄéOý~jøÀáGöQ<Ûµ{×%«–¼ãðÎ=á½æÿpþÏóNÎNÑqÑ|¥ŽÝ£„G*$=`bbܲeS'§öQ‘‹|÷CDzú3¶À¢ )ýû dåÎ=»‚{»¾ Q# =z8~·hZé½}>îcŸQîìã™_Žš=kÌÓ½Þ>èŽGc¢—äâêú¾££}Nnþñø¿Tø&‰24±mòãÚËtÕŒŸ:þÓ‘Ÿø%ò—QãGÍøzF§.†z p ú€\./³“‹IÓ„iì5þXß±FÆF¢Â£d2Y•D…E Rýþ×o¨×Ð.]»|³øÎ]ùùÈø ñ;wTÒU­j~Ù’lÏêl IDATöMc›Zeʶv¶™Ï3÷n+r\\\¼gëžñSÇWô’4Q“æ-›;:9®‰Z ä»vðK;‡vÓgOg‡·tíÞuúìéÓgOïÒµK™lY¿e冕Ÿù|Ö±sǃ8} L™­¶~ûÕ·±»c-,-¼ÆzY5²ªÅ¬%fOƒ·¤|1ç‹_ÿzãñ Ïaž‹æ,Øm Z!jbll$“Éæ¯ëÐÉ˵Ïdÿ/W3d²²×æöö%÷“¶hakl\NßLõµm£ vôDš0máÌ…UkÕ¶U•)ç™øÙ‘ýGÒDi_Nü’ý÷øaISvå£óYŸ|ö Ï€wõÒÕ¢¢"—þºÀÉÙÉá=‡ªß†f¨þ'Ðõû@üX\ÉW-]õן巎Lð›`naþ0íá‘ýGØvÔ)3ËéMW066–Ëä?üЫC/OWÏÿ6SV§ò­À¶yV$ãYFVfû˜ÇãMž1À}Ñý%ó—TÿUÒŽŽ\—”„°0M»£¹¨¨xä¨ù‡Ÿ:¤ï‰ß74oÞÀƒ§ŠóËY7ÀԴ‰*qòä%‡–-[¾11‡¶\ŒC$‚¿?ÔÞéßN?qtÿÑQFõêÓ«v{ø#þ»–U_ Tç;ݹy§ÓNìÏœBΫœ›‚› GÒ¤W~CX×î]»÷ê ×{½š5o–ñ4cü´ñ –.PnJUÿ°×¾÷ÀÞçNžKNJ~™ýRQ¯-M.—o߸}˜÷°rÕÀ¢Á¤/&­_±>,$ÌÒÊÒñ}ÇÆMWXQQÑä‘“ãÅ»uÿíÄol--î@\~q~E/‘dI’“’݇¸—ÞXÉipüÐñ ŸM044Ü÷û>×~®lš”´Ö^½tµ¢WÕ%<®1 –,W9½YÜŠÿëÐá3<à—K,,ÌäåI ë²OE#'[GüyÍnÿ/F–IxZ£m[ص S§rJm°÷&¾.{ñöˆƒêèÔ©‘¡!¡0½¸¸øï¿tèÐVy!«ŸDD@\Y³’Æ244llÛÀ{Þ —ËOÿ~@[û¶]»w­üµ………“.Žøßˆ÷4oÙ¼îÁÄîŽ-((èÙ§g™óêSïOÙþª][vI+]­¢Eƒ qƧý?9iæ7_|3wúÜE_/ŠÝûOÆ?uO jú 8¼çû{lóVÍwGíž8b¢ðo¡â©ÜœÜðUá+X¹}ÿvE"”Ëå¹9¹9¯rûoÚ¬é¨ñ£8÷t®|>Ò¶öm@Žû÷î³[vGíf§ëÌxš¡Øa箤 Ó¤ R7-T‡ÇPS3Óvï¶6ª¤J³3€±‰ñ‚¥ ª¿Ÿ*ñj÷ËE”C"›‚ƒáá¡ä=;;ãbDÕÅ*µ7:>xYÔÝ»é}ûv•Éäú;÷êÙyÚôeééÏZ·nvOx¨yËrròx<ûwu+uÛò àÇŸ¶†¬ÜÉ0ŒL&74ä+žŠþ5á빡2™ÌںᤉCçÍý@bâ…‘£ð ¦ûX<úñ ™LÆî¹}ûV)É»êøvÐÃ))uÝI3fÀ† JÞm59;¿H‰¯õ«¯_½þõÔ¯tuéš&L;wêÜÇÃ?þaÕ¥gøulî˜ó2'?¯¤ñª^ýzòóóñïÏÆêˆÕã§?öüØ!c™b€ß`uÄêÏ|>>høÕKW!‡\.7à\{xmóºÍÞ(cd2™ÌÐÈpÍ–5’LÉ¢¯±ßòëׯ—²ƒæ¬\²rãÏ™b†ÇãÉårC#C†aRÅ©æææm¶•³É<ôìÝ3:.Z.—4<éTÙ‰ßê7¨¿ûðîºÌCfãìQÅiS·oaGÄŽZ|lœW9;"vÄüs;õ¶mSÛ¶öm ^J^Ž3ÂÿE±¹ÓçîûeŸ\.—Édc&Y¶€è®èÓ~Ÿþÿ+{¯[TxÔ²ÀedŒL.—Ÿ¸tÂþ]ûý{÷ÿüó½»÷zõí%“ÉzèݽW÷¯§}ý8ýqËÖ-Sî¥ðx¼—Ù/gŒŸq"îDç® ¶îÛÚ¢U‹‚‚‚¶dLÉrÇ.ã’âFº¼tþ’âĸx÷bÛ&“./ ?;}àô0íák7zèý]ÈwNÝê4É¢³Å7H SHKSIï2+77??¿ÀÚº¡²ºCd2YfæË† Íë8¼¥ÆT‘ðÄb Ѝ(næ>­ÛO-ëÙÓgÏž<«o^ß®¥]ýúUO¥™&|6áÂÙ ‹W,nÞ²9Ç+..Î|žyþÏó»¶ìêþa÷¸¤¸ZïYÕ O)²%ÙÏÄϤùÒ6íÚ(}(¿Bnn®4_ÚȺQ%?ùùù¯ ^×:I–äqúcSSÓÖï´®dI‡ê+“ð¨;"pø0×qTÁܼžr'º400hÜXU“êfg .NKW·hÚ¬iÝôáVnNnܸ!^CÆN[z»÷çÞù«Ž“YkK+ËŠ¦\Q"ssóÒ“v–«^½zõêÕþ窑•ê6¨K‹ÁÝ]7¦ÍÔkþþ˜Èuú˼ù¤“âÆE¬`oM“ËåOŸ<ýî›ïÒ„i_~ó%×MA5<î,X€öuZ6Œh33„‡Ãºì‚¨DV„­î3ü@ô¿1~Ò|©L&«o^¿Cç'RNTgm¢'(áqGûW¼#%h ®ñx¼^}zÕú†B¢'¨I“Bˆ^ „G!D/PÂ#„¢(áBÑ ”ðÔˆaPéôHDGзLˆF¢„§F‰‰VþäåDwèÓ’Ú,TFQ)Jxê"•"(sæpQ1''88`Õ*®ã „”E O]ÂÃáà77®ã ª·z5 U]’¢F”ðÔB,Ft4,ÐÒéIÍØÙÁÝ‹q!ä ”ðÔbî\¸»ÓÔ*z$(B!â9žDŸR%<ÕKJ‚PX2Å0Ñff@h(Ø$DsÐzxªçî//LªÖƒ:;«õpÚBéëáU‚aàé©Ú¯ž¾eõ¨j=ÔT¬^­­«ÅÄ@ €ƒºvE«V°Ò°eö$XXhÜWOˆ¾¢„§7$¤§ãΜ>ääÿ¶ÀÛ›»°ê†aàæ†W¯Jþkm ggôé{{´mK™†R%<]' & %ÿuqAÿþxý¿ü™ 8~\»ƒHpr‚·7nÜÀåË ÀÁ|__«ùB¸@ O×EF@ÇŽhÛvv`,^Œ„Lš„mÛ­ k¹âÒ%ØÛ#9ÁÁððÃàþ}ˆD8{ÞÞ4>–JxzgôhdeaýzÌœ gg,[Æu@Ê •bØ0øú@HHIÎ#„7QÂÓ3ìšýû…ƒafÆu@J’”„Y³pø0M"DÑtž H¥‹¹¢vvÈÈ@HæÌÑlÀÕ..†æf;€ëÑk”ðT`×.LšÄu †‹‹6ú-[†ädÍÜD €¯¯æ^ ¢(á)›XŒˆ,^ÌuˆGr2‚‚¸ŽC¬¬4zr''¸»cî\®ã DQÂS¶ðp¸¸ÀÕ•ã0’’0ztÙŸ~†Ah(´õ6ó*F^v{|  :b1ס¢³(áÕÜÉ“X¼XùÖÅbÄÄ(yŸD¤RDF*Œ‰“ÜÝqwKùõáiÅÚ¤jCêH,ƤI­²Kˆ–¡„Ç5‰HN¦AzÚ„a°x1€#8[ŠR”ð8ÅŽÍsqÁ²etãöIJÂ’%hÔ6Ð×Gˆæ£„Ç‘ÒU®ÖÝ&uGtB´‡!×è1‰‡ÃÎŽë8HXYaÃÄÇ#5•!Žjx„BôÝ–P tÃQ?‰‘‘\AˆN¡„W ÁÁ4™=Q7SSDD¨|êjBô %¼ª$%!9þþµßƒD¢ŽUfˆJJªýýéff@h(­¢@ˆ²P«Ã`ÉøùÕ~hI|<ÜÜðóÏJ ‹h‰K–`ܸÚÏÆN_ÇNeG©3Jx•Ú¿Æ«Ík¥R"(ذA¹q-`e…ƒae…¡CkÙ2ÉçcñbDDЛ„(Ò¬X]V)€F°z5Ýx ïê8½ÀŒ°²¢9ç©;ªáU,85Îv ƒU«àë 77ìÚEÙŽÀɉHàヤ¤¿<( 4lŠºSq ÏÙY…;×I))\G@jˆNòrÑ™¬tú•«‚ÓOõ3­\ŒPù!tF?®# µB'yt&«~eT|úQ“&!„½@ Bˆ^ „G!D/PÂ#„¢(áBÑ ”ð!„èJx„Bô%‘ÝÐÂ<;ë4×ᢨI#GÍOJ¢µWˆNñ›6bÿ¾•\GAˆfÑ÷„—•õ25õ×Q¢| Ôã:B4‹^'<¹\¾didÁëB®!„¢ršÛ‡wöìÕÓg.›˜1Œìõë¹_c»ÙÂÂÍÍ•Êd²~}»¹º¾ -íñ‘£goÝJ“J_¿÷^›)¾Ãš4i¤ØÏë×…‡Ÿ¹qC$=²±±ìØñ‰>133=}:eͺ½‡Ÿ°cçÑsI×øÏðnÖÌFñÂØýܸ!JOÖ®]‹ºu:´¯AÉ%ÂòÛ³²^ææJ¿šé“Ÿ_°kw\ëÖͼGº)^®êׇ½½ A¸óô鋈Íûss¥yyÒ¯fúˆD®\ý;3óe§Nï|äáÚªUÓ2å¯_&ž¸xóæ=cc£Žß:¤o›6ví¼úPê@g²Z¾b»Dò*/Oê>¸WãÆVI ÒÒ·k×¢oŸnÎÎŲ²^n‰:(Œ ÛååI=Ü?ìÑÑÃÈ4·†gjj\\\<áúoƒÂ_¼ÈVdšüü‚…abñs##Cëâ;uö>Ÿ4þóg|1òbrj›w†üñG2[85UäìòùÄIß;8´\¼hª…Eý_.ÿxÈlr9ú÷û€o`À¢¾¥¥¡!Ÿ}áåË·»¼ï³ìǨ¾}º.ùazçÎöS¦-uí3ùáçl¢¢âmÛlŒˆ=óçå…a¦¦Æ³¿^=ØÃ_%Ÿ…TŠøx¸»Ã×"‘JA4C~~Ášµ{6mÞ?`ߟg¯ôëÛÍÕÕiið–¼"6ïW“Édsç…vý`ÌË—¹³g™4qèÕ«wt¹f힊ö\úêŸ$Š?¨‚‚Â…aOŸ¾`ÿ T‹aÑ£áë‹+WT~8¢T ÃìÞs<|ã¾I¾?,ÙþÞ»m†éwèð™î=ÇOó fÀýûO:uö¶µµ^·vޚйöíZ®\µóöß÷¹Ž½„æÖðºwïÔ½{§³ç®:’—'­_ߌÝnccé>¸gØúùþüóÊW³WÕ33‰^naa`ïî[µùxò”%i¢C2™|Ôè…·nß_¿ö›ñŸ E [™ p0ÀyÁÂõL¡lø°*››?rÔüûÄ—.ìd¯\ìí[¼ž0éû “¾;yb“Á¢ )×oc÷ÿ²rgò…/¦hÔÈBÉŸ‚XŒ={ kkøúbȘ™)ùDc4kf²bÖŽGÿy.Y¸`Ò¬¯F³ÛÛ´¶ëé:q†ÿòn]ßëÞ½€Mû^³ûcÏÞK~˜Î–qvîpöܵ9sîìh?hËÛ;gÿ ’þüqòÒ«W¹Š?¨† Í?òøpýºÕ¾7±ÇŽ!"ÖÖðòÂÖ­t&kÀo}¯_ÆÄžèÛ·ëþ}+y<€Þ½ßoÝö“Ȩƒï½×æë9ãb÷ÿñâEvÿ~X[[6¬ÿäIŸZ7jÈuì%4·†Ç \8À/»â<`fùŠí }ÙgÃ6ÄpvîÀf;õꙺº:¥?z&>:~<éÖíû€¿ÿ~ðÉÐÙŠ—¤§?kÙ¶¸¸XQf¯5~ôoò«ÄõëB¦¦Æ|>_±±^=SöàúÝž=;+¶ÛÛ·d°ÕǺ’Jq䢢™ ¬^ »{e<}ZÎKºtù¯LiT^=åÕ¢U«¦÷Ò§Þ¼ ;;çÑã ”:'Yìa%ûéÛ·[o×÷Ï%]ûiù¶¨-‹÷ìoÛÖ®W¯.ÊX*Eb"BC‘“ƒ.]0s&lm‘“ƒRSo>s¦üýxxPùÊÊk¶w9íþ“¼<©§§ë¬™>áö%ý%HúKÀÁ¾å¡?wèЖë0ÍOx</páä¡Ã¿ÞºíPP ï?m ]ýµâÙ-š¤Þ¼÷þûï=¼æíצ\¾Í>ÈÏ/hØÐ¼Êcݺ•–—'íÞ½“••€Â¢Òϳ,-”Þnjj\Ã÷T©]»îîð÷ãB8& å¼$8¸üh*¯žòj‘•õÿVûêÕ3524,*..,,.]†=EËœŸeðx¼ESÜ=¿Üù˱Ào'ÿøÓ¶ˆßª$bÅ™ àúu\¿^ò¸Üt‰AAåï‡ÊW^^°'§Eƒúff&~^ýõßOOøýü©S)§N§Ü¹ûpÎÜÕñqa\‡ h~Âðñǽ;;ÚßH ùtNýúf¥û'<Ü?ŒO8õêß2™LÑ `säož¹öéÝ•ý]8þúgŸ ,ý¬÷H7öwÏçE2™ @Üñ¤çÏ%Ý»wÐßùû%›_¥§?S »sç!c£Uq9¬0u*ÆÃ™3 EŸ>pwǤI%ƒÙ–-òe5Ø•WOygçì¤V²³sîÞM0h  cc£>}Þ?y*åî݇¥‹Ý¹ûÀÀUÄãæÖÃ¥{§äK7?2»I«~ý>PIÐS§bòd$&bÇ…pw‡·7œœÊ/lg‡””ìœÊ+¨þô«œ\.O¾tÀÀÝ –oIO¹9È{¤›÷H7™Lö™×7))·¸ RAÓûð|»p€«×î, œ¢h;ð¥¿÷ ÝŸ¿È Ú —ËÈd²={ãC×ì±´lЮ]‹à¥_X°îÅ‹lr¹|ã¦Øµëöš›—ÔœØ^:¡èணc;}ûvûÂÏ À’¥‘ìn ‹V¬Ü`ùO3[¶,;:\ÉÌÌàá„DE€FFRFµÇ%šdÍÚ½ÙÙ9†ù&`­´àuo×÷ýgŒdŸÝ´áÛæõb÷ÿ‘šZ2j7!á|ròÍÖ­š. ®b¨0[Éð÷ªí½ãóáá½{ ¾¾=ññJUxP¢z¿8Éöûøe×±ónØX[†­ ðúuáöGþüó¿!¸ÅÅŒë‡\è¨ýAWgg\Œ¨ºXU†y¿Û33“‹çw”NxŠ‹‹7Eì߸)@ãÆVOŸ¾èÙ£óòŸf*î‡;~<釥‘>}÷ÝÖÿÓ³‡ãª•³›6-yöÆ Ñ¸ñABá£Ú¶k×b÷/Áìàl¹\¾7:a媙™/[µjúðáÓ6mì¾_øóæ©<R}ªIx{w/å=8;;ÇÌÌÄÔÔ¤’ò99yFF†•—a)nïa¯ —ÿ8óã{+-îÒ*?“/\@XÉÊÁEÂó›úÙ¦ßæåI†QŒg½~]hllÄãñrsósròml,ÕqgŸ~ZЇǪòS344¬(Û000hܸÂËÉJúù iÂM$lëP¹ÚDGñx¼JNi…j^;ï‹=á3zaP ïßOß½çx½z¦žžUXV>>®®påâÐD©·r–¦h„07¯Wn‚[ZЇGˆžÈÍÍ¿pá;Ÿûlǵ#á‹1t(ÆŒÁ×_sŠ‹ÿû¢Ù.:šêÄuA}x„”"•b×.DD€ŸV¯þïGG²v±³CT|}Ñ AIý˜Te; „GÈ›NžÄÚµ%U:³û{—œ¬Öƒ*‹“SIÎkØðÖK†)éÞÓ[ ƒÔTÄÄÀ²e•• ¥l§,4Ó !¥˜™aï^¸º–ÍjÜf»{÷0w.¬­ÕzheqrBp0BB ü·qÿ~ôéƒU« sG$DFÂÓ¾¾ªîÅôõÅÁƒ”픂úðˆ^ªi C,†­-gÙn÷nŒ __„„hS^io¦°|9„B¸»ÃÛ[÷Ù—éž0ýúéu— TÃ#zF,Fd$zô@pp ^egÇY¶‹ŽÆ“'ÈÌÄ!j @¹¦N…Ÿ|}ÿ«Ò99aï^> ¾¾=AÉ ºjÉ ˆÃ‡±w/<<(Û©Õðˆ~¨hà¥f’H0c²²JznFÆÀ˜:ÎÎÚZÃc"%¥d’šÒ·$&RÛQJxDוx©÷±EFâêU,[++ˆDðñ)ÉsÚžðÆ/•êB¥‡aðê¥mÍD£4‰®36ƃå ¼Ôd¥ñçåÁÝ]‹“\i|~eoDÛ³H„S§ìÝËu4¤TÃ#D{h{ ¯vbbЭ›æN/"•âÈ8¡..;V›.­ô Õðˆ®¨¼¹Lèö€ŽJ ƒ,ЬÁœ ƒÅ‹‘kkxyaÃjÉÔpTÃ#ÚO1äÁÚºœºD Ь_|µ‹±g¢£Kô»¹iJ*2..zú¥h!JxDki×ÀKRwŠñGÖÖX¼®®\D´ %<¢sKjËÀK¢,Š•è=<ÔtDOŸªïpDe(á퉎©JGT¨ÌŠt6p©+Jx„h$‘HsÇ%ê6¶©|÷n$'ÃÁÇ—¬HG´M-F4ü1ã°þ‹á㑈ë8´@€Ñ£‘”T§­=z`Ö,¼ó¢£±w/¼½)Ûé º-h$ÅÀK/ê]»å±cpp ^µo1k¬­1gN-ggŽŽFÛ¶zwÊéjÒ$š„^JѧÏ ‘Jqæ BC‘™ ??ŒGU4¢„G4 ¼dÅÄ * qqz—é•‹̹c„BDG¿Q]fÛ®^¥q(ú†ÑññhÐ@«t¥1 <=1g ‚WŽŽàóKj~l dÛèN>=C M"À×gÏR+œ2 HLDttÉ`úÜ~ ß(áõb{éèʺ"Š¥ïˆwÞ·wIUÅÉ*ö„S”ðˆº”xIë|VD @«Vôá¨ÃèÑ iT‹^¡„GTŒ^µ‘Hjp­ÀŽjQ æ¤vN=@ ¨R|<‚‚½xITªôŠt))5~¹@€åË!ÂÝ“&Ñí:ŒQ%¹¹T¥#*Á0HMED’“am __¸¹Õ¾5X$¶mHè^F ¢…"#‹ÌLøøÀÍnÒ'ÕA ÔÛK×­õüõ‰‰AóætÖ‘¡„Gê ôRãááÔùAt»ð¬—žÕv´Z©9©II=C‡âêÕ’y°(ÛÕšH„˜®ƒÐH âã¹Hpò$Üܱ˜ëhHíQ Ô;𒱂®y•bÆ XYaÙ2®ãÐeV¤ÛºU#Ú-ÄÄ !X°€z µ%ýÝi¥©J¼‰¸Ž†è"©´üí”íðù”í4 ZÑ]4ð’¨ZééΞ¥ôVc æT'jÒÔQ ÜÜhÆK¢*"NBDøø`Ø0ªÄÔ˜â”Fµ¨ %<Ý%P•N1Œv)II ƒP|ù%-g_'ìe±±àå…q㨖¬R”ðQ/ww,^ WW®ã¨­øx¼‹ê>¢&ëá÷ßãÒ/u{Á0U óªŒÒ§þòž˜j ÓzNNذb1ÎCr2üe•9ùK¡A+\£—D¥J¯HçãÃu4Dyììàí®ãÐ&”ð¸6lxI”¯ô`sæèéŠt„”B kÑѰ° *Q¾%Kàå…Õ«ih!,Jx\£ZQ‘¸8º"¤4Z–EÙŽ7QÂ#„¢(áBÑ ”ð!„èJx„Bô%ÍÈÈÌË+055îÕ« WA¾MOkx“§,éÓoŠ›‡̾D®c!:";;烿èÛjzú³ Eßí0âÎ¥ $ü~á“¡³û œöñÐÿ³w÷q5ÞÿÀ_§SéPé(wsS6D¤…_#3)™ÆW#wC±, Ój¶Qfµ2æ&ɳr6LZñ°éFÃŽŒ:ÑÍéîœóûãjI¥ÛsÎusÞÏÇ{äês®ëݹ¹Þçs¿„¥ Q}ûOué:ö«ˆ¸ë×ÓÇŒ]øž_h[·=Æ”ëüA;X‰ðEô4á¥\Úëæ6Œí(ˆNY²tÓÏg~ÛøQÀ»eeåŲ’ŒŒûÕ L›ê~:a'[ᢙ™÷ßµÊÚÚêè‘}ûö ¾~»F™-›—…†ø³]ô´I€™ik¶C :åì¹TC‡ôçñxÇnN»‘áæ6´F33z×ív>éŠxͱŸÏŸ9cœR‰ÃÕ.ffÖFó±5H!ªUT$ ´0dˆÝ!vlGDˆêUŸ·i#x¾6íe¦³ /3óþ‰“ç32î:8¼:tHÿ={OÞ¸™µàýwFR½ä¯¿Š“ggKllº¾1ÒqàÀWØŠ™pMEEÅÚ/vÉŠŠdoŽrš8ñ {öžüë¯ì¢¢’ŽÛ­\á 5õæ±ãç˜Áº/¿55m=úM§‘#ÉâOüróæüü‚þým^wÈî_T‰Ù”ŠöO M´~ÞŸÏü å·ÁŸ„¬þ|>ó«{÷rN‹.ݼyÇÀ€çü «‘ÖM7ûð¾Û÷C_;¯””sf{¾9Ê)࣭½ûü¯_¿žW¯þ¾ëpõ’[·ÜÓçÕÓ§½u뎃ãô ×qó¥"¬(--Û±3vçW‡¿r‹9RQQqâdÒö1ñ'Î3GLLŒ­¬,˜jVV €ÄÄ‹¯öôá²-vv½|}Þ–ËcÇ}ÀÖRI"ÁÆ>[¶ ¤„å`ˆ¶i×®­©©@II©••…¥e[æøÆMß½ÒgRTôq±Î^“F_¼t}YÀV#­›ÖðÊË+ü¬++¯X±|Nÿþ6Þöt‰Œ:véRš(1Üôù®»‘#<°–Çã:´ÿ5ñíð]q½{¿¼øƒ©ìDO¸ÄÐÐ04dÁù¤«’¯Uôõ™ðøqþò•φŸÙÙÙØÙÙ„„FËJ¦Muwtì ;[òΔ ‹OÙçàð*€_±îl5aR€æÿÈå¸t©r{°¼¼@[sSf !uR*• –±²´ P4\R]˜l`ùrØÙ=·=žTŠààºUç —Ês¶<Ûx<ž••ÅÝ{9l¾ÕM7Þþ?Μ1Îÿýwd²’V­Œk,{S7²Œ娸‡Ç4iVOr÷î=lðQ..{÷ý™y¿¢¢Âаòƒ¦Ñ›Bx8$üð|}ai __Œ_Yɳ¶FjjNEå9[Þѱ çQ—ßí?u;ýïê¹™ÿtó¶nnÖfeÐΩÓV¾ï¿ÎoþÚ ×­ý"úÂ…kµ¿˜ÿåÆLæç+WþŒ?qÞÊÒ"l[ ÆC&Ü5 ¿-ª%¹ŒŒ{Çãðè‘T.—¿èQ³gé2¸XV¶£²KX*}ZµÒRNÎcõͰ¶Æ¼yHJÂÒ¥ˆŠÂðá BF†&.MôÆú/?hoeqæLêåËi̱øöW»âüûo^=ŸÍã5¦qF5˜o"—#4p©ó篸Œz¯öñ oŒ‹ý’qà=uEnÞ“í[?Z¾2ÌÈÈ0?¿àöí»nc†…¬y¿cGK  CüšöEÔÉÑQ­ï«¼¼'>sWÿôÓefji‹Ë`ÿ…ëð€ÿ$ffÞ÷xkqyy…ÏÐÿÊ+Ý/ýú-€’’Ò›¾‹Š>nfÖÆÆæ¥'O _sì÷å†=Ìi¿ÉÓÓE]A×ùÖ‹QÙ«·p!†E#FßNSó›¿Ï KÏû]©Tòx<>ß`wÔg&Œ“óxùŠ¢Ÿ.õìù’Phf`` 0i{È{|V£Ù/¾¯ê`ÂKN¾æî±hÂÛ#§Lcbb¬T* Šÿ¾û`gøá̬û§ÜáêZsÁ§ŠŠŠââsswºRÂS |æËÊÊ¥Ò§B¡¹±±QqqIaa±‰‰±@`bhȯèû"ÅÅ%<“ÒÒ²üü“V&&ÆÆÆF >°ùêykI¥ˆ‹CDâãam­®ˆfh6á5(?¿À̬5ŸÏú´°´´ÜÄĨĤUc>#ªôâ7¿öá=v®°H¶üãÙýúõª~¼cGËé3ƒïÞË©ýCCC²Ñ*ÆÆFUUÿÖ­MZ·6iüc« ·je¬¹öƒ 1oæÍc9 ¢‹ªjrܼ£ê`ÞìYoµ·²xÁ¿ývƒi>.--;}úÒgŸG¼úJ÷ño`;@B!,ÐÁžÍÍ´¸ƒ1 _nØóøq¾B¡àñx:Z®X>ÇkÒ›Ü\ÛBˆºé`Â`ee±h¡÷¢…ÞlB!„+t°I“B©!„½@ Bˆ^ „G!D/èæ BÈs¤RÈdxô@RRåñà`ÚôœèJx„訠 Ü»‡›7Ÿ;hk‹ž=`øp˜™Q¶#z…!:jøðÊ=eöìPH«ˆB}x„è(wwDE¡];ì܉ŽÙކöQÂ#DwÙÛãÐ!dfÂÃRés¿ÊÈ@l,mDô %Э/†Ÿß³½„B8;ÃÙ2n߆H„âbV%D4¾,©6€m9zkթη–X __„„ÀÝ]ã5 7Øßñœk"#1nÕÖ/R).^ÄO?áÆ œ:>¿ù§ ÂêÕ œaãF,Xд¹n2&LÀœ9psƒPØüðê¿д¨¤Rx{ÃË NN°³kÑóF{ô8á¬[ÇvDͤRܼ‰‹!!7·ò` «8‘‘ˆˆ@||_˜áä„ðð¦<<ÑÑàä„éÓ1t(û F.Ç¥KØ¿))àíaÃàà@óÖ‰vÑׄ—‘oo ß³ˆ6bz¤RRpæ ÒÓÀÍ "2 ÚµÃÁƒÍÏ"L« zóÈd>hzr•Hàé ggt튘ðöÆ„ °±ifÀ*TÕÕÇV½;ÎÓׄ‰C‡ÀçÃÑ¡¡lGCTÍß))pr‚§' €µ5Œñãq⢢`oßÌ3K¥puE»v(-ÅŠõe2&oµiƒ¢¢&¯ò÷‡PˆÐÐçªV¶¶˜8ãÇs¢^%—ãΜHÄ4޾&<77 †§Oqþ:™™Gb"¼½+ûçê‘ {{¸ºâæMìÞÄD$$4árK—".®ŽÕO¬­µ æ””„¨(X¼ÇÃß 5×6#Dãô2á9ƒ‰aowwX[ÃÍÆjê>‘ééͯÞ%$ "ë×Ã܉‰pušC™˜ˆ.]0lD"X[#0ÁÁMXÇÄŹ¹¸téÙ‘äd­YýK €½=pù2bb0h¶l««ÖÄOt”þ%<©éé•7,Fp0UòtŠTZ³2!“aË6s¸GF‚ƒ{ûÊ‘½{cÀ€g“jcÚñzô@ß¾ÈÍ…TŠÉ“áä„9s{Óàç‡;žýQ«WcÑ"-Ë|>ll0o^ec,÷ë¦D§é_‰`kûÜ”^æÎ²n–ÝJHÄbx{#.LgؤIÍ<çîÝðö®Ÿrö,œœžKR'æxÇŽ•ï4fÖM›TαkŒqãž^¹¡Pˆ˜dfj_Ϋò¢ÆäŒ êê#š¡ ïèQLœXóàŒHOGZÕ‰Œ„¯/¼¼àãóÜñ®]±sgó«¡¡¨üyÞ¼ÊAžÌs/ºM_¿KËÊ+º¹áâEpìÆkìu­­áä„cÇ*ÿ©9¯NW®PWÑ =›– —cȈDu,ÚD©µšL†eË’‚mÛà쬡‹::¾p†@d$²³+S£Lcãf¾µd2””<÷veVùêÕ aaºóvefõ=‹¸8äæVÎ8tuU×âjD_éYÂ#:I"Áœ9h×áá½Efd Gº³SMQS0:™óªH$¸pGbÍšÕNT‹ÑrÌ‚&nn /å¬K¤Røûk:Á¢åô;áÅÆ¢K͵€5IN¦Q_dd`ófxzbÈJö¤©ô{Ø»w!Ó½RëÑ+¨?,-+gõUuõ98PË'i$ý®á%$ )‰&DûTuõ¥§ÃÒK—Ò–¶¤Aú]ÃËçQRCl,Wv* ¬­1y2&O†L†+W`jÊv@D èß<¼êÌÌ*7´$ZA*mÚr”*$‘`ýz””4ÿ R©ÚWó‘Ëõñ œ@gçn¡‡Oy1ýNx=z°i4fÏÞ={Ø™s}áBÍzšJ$BD„êªKt4¼½i‘¼gd2¸ºbêTDFV.XCô›~'<†.-Z¡«bcáí WWìÛÇÎ܃sç0jT‹Îàà€”õ¾Ù||àå__Êy•ˆD˜8gÎÀÛnnظb1}äõ–~Zav¯¦ `¹L.ǪUHLÔè*5Èd>11- ȬòÓ“4Fd$""´`“X cºú˜½ã--‘˜Èv@„ú=hE(DHÍæá.f €å/%·o-nçóak‹+WÔžðæÍ__ÊyÏaºúœ!—ãáC¶£!ìÐû&MwwwÇ]sæ W/œ:År\$‚·· šRG¹s*ˆ§AóæÁÏÚ6ëÆç¿ðí$SWŸnÓï&MÂq2'¾Ž8:ª¦AU,†¯/._ÖP7dd$®^Ex¸&®¥‚‚˜KK¸ºÂÕvvz´X~ „GH½är\º¤^¦/úŒ¹¬zW77xx`èPÊ|º!´q#&L ¥°´€\Ž´4ˆDˆ‰©{C1¢…(áBÑ z?h…pL†  Zƒh“Œ šÕ§uô{ZႪ¹D$êATÖ­‘•__à¿®>¦£×Ñ‘íÈšZça½oÒÌÈÀîÝ´ak¬wÛ·²…5ãçz¶U£zW''¤¤à²š×#õâ÷¢„§÷Mš­[Óš ìË„à`„„ 4”  * X´ˆâTƒÏ‡½=šŠ˜ Äv@¤>zŸð2Ûè©3fTÞ#8»™L¦ƒo {{ˆDÈ̤œ§z66•ËÜ®Òû„ÇL®¢áÆŒó>vŒÓô÷íòel¡B!bb(ç=¤÷ ¦×°bòd„‡sb•zÄÅaäHµœ9(ÉÉj9s#QÎ#zIïãÑ#¶# #•"7®®ê:ÿÅ‹ê:s#Uå¼;wXŽ„M¡„XZâÁ¶ƒ sù2,-ÕÕ0|8D"µœ¹I„Bœ:ÅéVeBTŠhÞ ©C|<¼¼Ôuò›Ë‰žcKô %<`òd Àv:Š™{ÉvM$—#%NNê:?3õûî]uŸRJx€½=­=¡R)<<šŠqãØ¥‰ÒÒÀÎN—ps«\Ÿ¢)”ðˆz$'ÃÕ•Û·6ÃpsSosßðá8sFço6¹\g€Q=¹7bñb"<\+{‰ÜÝÕ¾ÚÜ€HOçbj‰ŽÆ„ œè_ÔW%%¥?ÿœRTĽ÷†ö£„GTJ*Å¢E‰…ɓَ†Ã:vD|<g"úø W/x{C,f;=5ÿý/F»ù÷ëÿ޼éS$oÜÈT(ꈪ…8%<¢RææèÙ11°·g;nãó9ÚÒËç#, ®®ðõ¥œÇŠŒÌ{þùç‘LVÚ¤ÛÙO)++WO\ÍÇÀh{ ¢R|>Ø‚´ ó"¶m __DEÑw ÛºyÙÎðØw¼F›š¶nÒ/\¸¦¦Zˆ;QÂ#„Ô…Y™ržÆ9:öÝýYSU\\òùš¯ÕNKq*0Jxs´‰‰¶09/0¶ÐÒ˜””´'“ ‹ å¶­23ïïýîda¡¬°°xGØÇ99ÇýtûöÝÚ͘>¶wï—DEÛ~øêµ¿|öù׆†|ãà ¹U§-((:+ºq#3''·k׎ïÎgg÷l…§O ÅŠþúëo™¬ÄÖ¶›çø'N&]H¾öºóÀÅL9”(§~ÓiÈ»ð¯âx<@J -§Ù4–OçÍ›‡cÇØB(•_¿½uûÁ={OV|ðàñæ­û¿þæhbâÅ–l´Ð{æ /×ëè43+ë>cc£Ã+·â³´lkeeaiiQõðsçRûôóZûEô¨7^ òåóùýz¯ý"šùídؾ2qÇÎCžãG̘îwäç^½'ܹó·zM¤R©T(”§E—v„Ç^¼ôÇ»³?íÒ¥ýšo^2óŸþ°pÑ—¾óÖ(•ÊM—¾ã5zW‰Íòì IDATDÜË=Þ:}úsò–¦¦ç—(•cÆ(ü‘í ´JE…rÃåàÁÊŠ ¶CQ©1c”éélA´ÙàÁÊŠÔ–ü—zù;mÍM«ŽT”^fn×ã<^//¹Ätô*€Û™^¼°›)#+L®~¶ÇêÐ^à§ÄðªƒcÝÿÀí[ß++RÝ݆ؾ5€ùÕþïB èoóøáOiâCÌÁÛ-Ì~>ýÕCÉiÓ63ÓÖÒÇg•©oŒtðé'ó˜’ö…èÙ£KÕµšXóÿ<øE/ÕðÐršMÄlß*!&F+§Ù½HFrsÑ¥‹æ®(—##ƒ6è!Õñù5oËüÿ>ežãGVöCuîlàÞ½‡õŸíP¬èßGRoćªƒ®£‡øùL €¼¼§,,̘_Y´5 ‘<¶´´èׯWõZµ2~ã ÇÚÝÍþáï;'™‡ÄƬ;qlËògËåÚ·uçŸââ’¦Ô‡÷Ÿ{÷ØŽ@KˆÅðõ…“¢£¹8¬%®\­­Fÿ¨²2x{#&†¶, Ñ£{“ÇܺuÇ›8éÙðé¼¼']¬ÛxÇktÊo7~ýõúÌãüzñ:€™3|ª·Û·{Nœ=—:hð4ã¼¼§_~±hÉâiµKš˜×8ò÷߯Ž[tëÏìUÁsì mÝÚ$5õfü‰ó* L¨I€š— Ö‹!"QQ˜7O³TŠôt¼þº¦¯;j’’4}Ñš0AûvÀÐuU ¡ …Àæ­ûÓÒ2¸ŽjÀã•–•߸‘Y½ü¹s©gϦˆ=,êÛ·çŸ7¤\Ú{þÜ7Ýú>ð£YÆÆF¹èö°˜[f;îóùgó[·6Á ¤* L(áý'+‹í8oútˆD:;%ëæMXZ²05ÅÉIûý¯_ˆDFRï#wôë×ËÈÐ@zúÝŠŠŠ?ÿÌîÓ§‡W?]õ€E‹7””T.ÝråÊŸ>sW[Z¶`nÞæÈ‘ŸßžøáÜykæ¿¿ÖÁº•A;NžLj°€MW99¹OŸ¨¨¨ØûÝIÓ6É£¦<¥R©¦Sk‰ÅÅZÖ¬DT+(B! ËÄH¥puE|¼–M­êÊ ÓÁê~K8:ârD³½ö‹èõöÊår…BihÈ¿™vøæÍ¬w¦,//¯00àÌ÷›âoÙþM…BÁ´öîÝ-5e€˜C‰.Û¢P(,-ÛΙí°lfÕi~]úMNNîË/wÎÉyܹ³Õúu‹î /ï‰í+ó¤5kf¶6]ÏŸ‹ìÔÉê)'&^T*•<Ï7ø*|…÷7¦LYYùšo¢¢¿þú@™¬tñ¢©éw7lÜûèqþœY㣣>mv`Í7Ä©u×)áptdmI77,] ww.ÝR)¼½Ñ«å¼ç´,áµB¡ÈÍ}Ò¶­im’J¥2/ï‰Phn`PÙ¶—››?ôÿf[X˜}üÑ,fÔeIIYÎÃÜý~<÷Ëï+—Ï YÐàE•Je~~B¡h×®í‹zãšX‹¼8áÑ BII0®Ù'¯!®®HJÒ¾„'"&ÞÞX´ˆrG´o/|Ñoy<^õyß.^ü##óþŽí^^£«÷ëÜ¥ÛØ»wssQW}ܦJSêÃ#u‹õ®{F `í–=l;×m9&çefB$b;Ò..N¯õ[ûEt|ü/LGš\.¿~=}î{kÌL[Ï÷›Äv€*FMšäyr9¶lAL -L‹f)TÇj“f3”––ÅŸ8ÿ‹äÁ£òò ¥B¡ÙëΧz»uíÚ‰íèš…š4I£H¥ Bf&e;Ò”í´Y«VÆïx~çù&M]EMšä?b1¼½Ðö­„D bcáë WW„…AøÂ¾eBÑ^Ô¤ùŸ  tï^¹˜¾‰ŒDD¶mƒ³3Û¡]A{„{¨†÷}^NÓÇ"‘žf;‰ÉÉl¡s’“1am—H¸†Þôy9M>_›1À©Sl¡s†E¯^ðö¦œG8…^5´œ¦‰àQÇN(,ÈÈÀÆl¡"|>ÂÂ*s^FÛÑR‰ÞÌÌžÎvD³$俢o_¶ã´n˜ÈdlÇ¡"LÎsu…·7Äb¶£! „÷LlG b1Ý}ž¹p¶¶\iÎe¾}›í8T‡ÏG@üüàëKï:”ðž§3߯k“Ë __¤¤° g=ŠQ£Ø¢''|uæÍƒŸõn±:Â=”ðþà ¡ÖÕ>v™ì¹í[ ™ ééxã ¶ã¨fäHœ9Ãvj0obbhuiÂ:Jxÿ ŽÙŽC 22*Ljëðö­Ípå nm‚èà€ôtݬ q¤Ý˜è7JxÕX[ëà—Єx{ÃÕûöÑMç9}û"*Ší žÇt$ß¹Ãv„è&ZiE§I¥FHˆöíµ¦B!ç¾ðùpr•+ܪw’¦âÇv¤n´=®£ž´‹D€s™XärlP!ÜF  DC¨ˆ&Q“&!„ Ìü<€rÑJx„6ØÛ#*ŠrÑ$¥©+ÄbLª›#Ú‰®br^Düýé­K4€^5ÉÉptd;ˆfa¶o<˜í8´„DÂvä?ööˆGf&-¢œGÔ^5Ú¸œ¦\¬_mÛ@ÃÞ&—ÃÓ“–väkkÄÄ 3ÑÑl‡BtõáÕ¢Eãø%Ì™ññ•K“¥¥œßþYÓU[Þ‡-'"&æælÇAtÕðªÑ®å4àé GGœ:EÙ® RRàäÄõªðÎ a;Í ¹þ¢íG ¯íší›–†À@„†Òm¢iââàéÉv 6 ‰‰lAˆ®¡&ÍZ=ÒŽ S@Ûh!©¹¹2„í8ÂìI+‘hÇ[‘-A5¼çYZâÁ¶ƒ j#ÁÒR ªòB!,-iiBT‹Þó´tZi¤sçàåÅvãꊋÙ‚UpsÓš>u¢ (á=/ ..lQ‹ïîyœÚñµvv‰Ø‚U=z W/x{SÎ#ªB ïyB!çÆ‚3Û·&'³‡Nךw @n®^ßëù|„…QÎ#*D Û˜í[1t(Û¡Ͳ¶†¥%rsÙŽƒUÕs^FÛÑ­GÛq•\ŽU«˜HÛ·}WõYˆŠ‚½=ÛÑ-F “¤Røû#/»wÓÀtB 2HJâ\§Ñ”ð¸G,†¯/œœ°i}¶ y†&&’–¡„Ç=R)D"LžÌv„¢S(áBÑ 4J³GGÚ/M×$'Ãߟí !,£„W—GØŽ€¨ÔÅ‹èÙ“í !,£„W‹­­æ–Ó”ËiF­ÚÉ刉«+Ûq4Wd$59¼Pd$"#Ù‚h Jxµh¬* ‘ÀÚÚÔŽY‚¹wo¶ãh®«WqáÛAp•“""(ç‘F¢„W—{÷Ô~‰ääÊí[÷íSûµôÜÙ³prÒâ #GâÜ9¶ƒà*{{DEQÎ#D ¯–îÝ‘­ÆóË娏‹Óö­ræ FŽd;ˆpp@J är¶ãà*Êy¤Ñ(áÕÒµ«O.•bÆ ˆDˆ‰¡™vš •"=¯¿Îv-Ð¥ Ú¯>U9/(ˆ¾zP«KV–ZN+•ÂÛB!bb´fÍ~mwó&,-µ{y¶¶¸r…í8¸ÍÞññHMÅ–-l‡B¸‹KÏióÕ¥¦²A]è…«“ _¬ÈH\½Šðp•ô>QnÞ¸Êížw9‚í8lˆÛ¼½p5¨öÅbÆ"êzŸ¨—ï œDMš„p^ïÞØ¶z§i!ŽÕð!µ pvf;B´Õð!„èJx„Bô%"Õ¼{uÇ?˜7nd* Í_—@¯^Ê¥½nnÃTu6¥RùöÄïdKÜ1ÖÝ@fæýÂÂâêe¦Mu?°SUW$ªuölêô™ÁlGÑD 72ÛqpÇ?˜……ÅvöSÊÊÊY¹:Ñ£&Mf¦­UuªìlÉßwsºuídmÝÞÚºý¡ƒ_´57 Ík^ÑLeW$ª•tá*Û!4Ówû6ìíÙ…£8þÁ¼pá+×% ýJx*TT$ ´bþ9ùWVÃ!M“™yÿëÈïUÕ•«QnnHI¡„÷"\þ`—|¾æk¶£Ðk:•ð23ïŸ8y>#ãž‘‘¡ƒÃ«C‡ôß³÷ä›Y Þgôè!ÕKþú«8ùWqv¶ÄƦë#|¥ê {¿;YTTRT$[¸`r¿~½ EHhTQ‘¬¨H6Òe°—×h‡ã~‰.xôHüI8€ys'¾ürgEE²ø¿Ü¼y'?¿ ›×júYÐr—.ýqò‡¤ÂÂâ.]:|°ÈûëÈï³³Œq:fÌPÇ”¹~=]ôÓå72úöíé9~D÷î5÷4Q™’’Òµ_ìþ&ê˜4¿àÞ½æåëÓ§Çôic5ôÊåHKúuèÙ¡¡M~¸½=Äb5„Åik¿ØÍ| ßå4qâöì=ù×_ÙEE%;¶[¹Â-û`®ûòÛ¼¼'……²y—ìÛêå—;O~ǵsg+¦@NÎãcÇÏݸ‘õäIaß¾=Gº :´“ÔS&*úØÎðÃW¯ýà³Ï¿64䛘ÍUß“FjÓ>¼ïöýÐ×Î+%åÆœÙžoŽr øhkï>ÿëׯçÕ«†ï:\½äÖm·‡ÅôyµÇôicoݺãà8}ÁÂuUÝÈ<Þ´eß®¯ßÀy¸Ï¬ÙŸVï«¿Œ±±Ñˆáƒ˜’––m­¬,,--Ôø|‘ºèH ¯¼¼ÂÁº²òŠËçôïoàmO—Ȩc—.¥‰ÃMŸïº9rðÁk™êÂСý¯‰o‡ïŠëÝûåÅLíÕ륯ÂWDF«*l``²Æÿ÷+·/Vtwÿ¿—^ê°~ã^ccÃ%‹§1³³%ïLù¸ °ø÷”}ÌýtàÀW¬;[M˜ g@g 6 dõûÇŽŸ»~=Ýe„ÇKgŠ!ó¾……€]G6oÝ?ÎãõÕŸÏgÊ;:öIºpmé²ÍýílÞ|Ó©1e–,žVRRöé ;[U½|ê•‘Ý»‘˜KK,]  ?ŠüÇÐÐ04dÁù¤«’ŸõùúLxü8ùÊUGZòÁü$xîõ?ÒãŽü¼~ÃÞ”K{._NЮ9±øöŸÏÍÌZÜ¿¶U+c}ûö¼uëÎî='^~¹3ó6k°ÌÌãlmºm ‹°há“Vj~ÎHt¤†WRRZ\\À”9ÂÜ%ÙÚv«j”`XYZT5޼1ÒÀއ˜#|>¿öùë¿æýJµL¾€×ûZZZxx¼~/ûQb8€M›÷UÈå¯2™Œ1lØæWr¹¼‘eët¤†gfÖfìXçN]øõâõ)];)ŠK—ÿ0£3Ì—¸ŒÌûEE²T›D|=ÿ%Z¢½z½ÀØØè¥—:ÈÏ/¸wÿ!€Ö­Mªcþ)§7²Œ†DF".¹¹•ÿLIAJÊsRSëx”DOϺO¨íåYÒÔ¦MWææ]àúéxÁ;ªXV’‘qï•Wº7¦L þ¢:’ð¼;s\nnþGÛ¶m?XT$366úþð†·ßÙà™I©mÍM«FvÕ¦T*<•¥…¢á’¤1øFFϽ?[·6124,¯¨(+{n1ó 2w´Æ”©íÀÁ„w¼F׸\K͘®]±y3òò0`\\бcà ҄«hQù`ÕÏzTÇÓÄĸƦ_°Æä¹ªÉìLe±1ej8sæ7[Û®]»vjd`¤åt'áí?ðãÌãüßG&+iÕÊØÀ ±­µ7nd5ʱê!<žB©¬þYºwïaƒçqqqØ»ï‡ÌÌû††•O,å?266>|à™³©·oÿ]ýø_·³Œzñ‘eð_ãXÕH%¿ù¡Þ©â„'ÀÝîî‹°0ØÚbáB Šzâ˜G5õ*ZQ¾Å yÕ4ÿÁõÆkç~ùýöí»Õþõ×ßúöéÑ©“U#ËT5É2Wß¼uÿ‚÷ß¡„§I:Ò‡ÀܬÍÊ S§­|ßßüµ ®[ûEô… ×j<ÿË™ÌÏW®ü⼕¥EضÀªØ`ZÆ|ÿý™;wþððan=ß(gÏ?Òep±¬$lGew TútEPezNÎcÕüúmWøJ3ÓÖqG~NKË`Ž$&^LI¹ñr·N¡! _fÐÀWdgKÊË+23ïwèЮFc”*ÙÛ#<"FÂâÅðð@d$mzÐ úÛ¢Z’Ëȸw<þIëé$kùó£€™í{ßÉ–ìýî$säÞ½œo÷œ062ŒþæÓÆ—éׯ—‘¡!€ôô»þ™Ý§O¦=¤exiÐGG\Žhö£ÏŸ¿â2ê½ÚÇ'¼=2.öK¦sÛ{êŠÜ¼'Û·~´|e˜‘‘a~~ÁíÛwÝÆ Yó~ÇŽ–U¹ví/ßykîÞÍ1bPAA±Ã Wóòž0C7ûöéqãÃë7ì ]Í|ÆŒæÌöÜ´q)€’’Ò›¾‹Š>nfÖÆÆæ¥'O _sì÷å†=Ìi¿ÉÓÓ¥Ù †øÕÝkº–½p5lÛ~pÕ§»ªžÛiSÝw„}\½Àýûƒ‚ÃÏœý­}{aYY¹LV:áí‘«>™W½Õ¨Á2 …bÅÊ;Ãc»uë¤TbÇö@fPŒÊ¼èÅ’Ë!aϤ§ÃÏóæ5óü .\ÀäÉ-‰QÓZü>ÉË{â3wõO?]9Ò€i‹Ë`ÿ…ëð€ÿ$îÙ{²ÙLë—Ü Šx<3¢ífÚá.]:T]º¸¸dÃÆ½ßí;e`À ͤ&&Ɖ¡!¿ÁÏWË?˜¥¥e%%eõ¾®¿ŒB¡ÈÍ}Ò¶­©±±Q#/úBœ½'p•Žôá=v®°H¶üãÙýúõª~¼cGËé3ƒïÞË©ýCCÃz²€Ö­Mªš¹š:ö²ê­ZW¯;2kÄlñúËuèÐNu5E ×ëÝ$’ÊÕ5õ‰±±QÕgªú‡´1ZþÁlÕʸúăf”100hß^ØŒK“–Ó‘>¼Ù³Þjoeñþ‚/~ûíÓ QZZvúô¥Ï>xõ•îãßÁv€„¨”@[[\¿Îv„h©áÙÙÙÜL‹;“ðå†=ç+ ש£åŠås¼&½Ù˜ª!ZfÔ($%5m%!úMG++‹E ½-ôf;B4¢o_DDè纚„4Ž4i¢wúö‰„í8Ñ”ðÑNB!,-©ÆÓ&MBôÎúõhßží Ñ”ðÑZ´ï9!MAMš„Bô%<Îàó±s'NŸFP¼¼°x1üýŸ¥:m¼ k…‘#qõ*||žžˆŒ„\ÎvXMäà€”í [3är,Z‘QQ7Žíh›(áq‰ ñá‡ðòB|< µ÷_-òÊ+HIAb"-Bh(¶mC\<<œÌvdMÑ£<|ÈvÜ#•ÂÙ™ˆ‰½=m¨ç(áqÌäÉpr‚¿?:vDxø³ûoFÛ‘é¨Þ½+ÿÏ<íC‡âÔ©g5lmÁç#5•šjb%õê…cÇž ûrrb5&Â&JxÜмíÖÖpw§§][Édðõ…Ÿ*{dz²èÕ$”ð8ÉÞÞÞ d;ýз/ÀÞ~~ „TÊvL¤e\¾\9ÎY"Ab"–/€¤$vã"좄ÇUK—VΪ5¸©Dß¾Às?||Ю‚‚؈¨@Õ܃;akûlV>MÏ×c”ð¸ŠÏoà“)cøpÄÆÒΖ ai‰;w€ÏGx8zö¤gUGT¯Þ1ÌÍÙ‹†°ŒVZÑf زÖ¯§ï­-’‘KKΠƒ‚‚•…ƒ+ÿ¹q#&L ‹ô%<-'“açNÄÄÀÍ tËÖw pq¡Ñ•$xzÒ*£¤ 5ij9ˆGV\]©…SßmÙ‚_~a;Î(.†“e;R…jx:$!ññ £¥õׯJÊv„p%kP…d2‡EêG5<ò<{{œ:__cêTjál€DÂÑ%Ç:v€;wØŽCƒ(Û‘†PÂ#µðù˜<"zö„§'GoèqáG—ãóáä„+WØŽƒ¡&MR/±vvzÔ,Ö þþJ±o瞥ÈH\½Šðp¶ã „+¨†GêeoϹû8×lÚ„¼<.îää„”Z.œ*”ðiÎîÔ»7 gÝx„Ô‹i±˜í¸ÄÆ~~X½š[ylm‘‘Ávj#“ÑüÒ$”ðHÓI$ðõ…¿?á|ÆÇ½z!(ˆí8ž7j’’ØBmBBàãÃvD›Ð Ò, BB’??øøP?H¥¸yÎÎlÇQOM£•3IÓQÂ#-œŒÕ«`ðj k IDATÕ*nÝè‰Î£HÓQÂ#-#—#:pr¦M:[Ÿ œBÕ;Ò,Ô‡GZ†ÏǼyˆÇ A06f;¢hcÒ,TÃ#„hªÞ‘æ¢!D«PõŽ4Õðˆ:1Ë|èçN¹[¶`éR=ýóÕ‡™ cmÍvDûP ¨Ó‘#ððÐßYê"V­b;@*Õ©—ÀÚš²iJxDƇ«+|}Ä­UH4€ÏÇÎHLdɱ˗+÷8$D¿QÂ#ê$ ññÈÊ‚«+bcõk-c²¿ЀÈÍÕ»/„ÔB ¨Ÿµ5DH¢¢ô®…sòd89ÁߟÍLÏ4Þ¼ÉZ„p%<¢)îî8v¬²ž§W¸°›.^d3B8€Fi¢~b1|}vHHÀž=´ÑsTÃ#Dýìí±mzô`-€ž®Å›é!2’í ˆÖ£„GˆF8;³9!鯻}›µZB"Ab"œœØŽƒh=Jx„‚‚ _c85ÌÏíÛ³D³ÐÒ*DE¨pCB‚ƒak‹5kXëè"D+gÕ¡áww$%¡gOx{#(H‹{›ˆjQõލ%<ÂBCƒ¬, N-œ¤²÷nùr¶ã :Âíyž öíƒH„à`<}ŠÉ“ÙH=˜õÆh›øúQõލ%<Â=|>ÜÝáâ¢Ë;Ê 8ññ´r}ºwÇœ9lAt Z!„%AAHMÅ©S´!šA}x„°$8ËKŽ¢O(ám«#c8ì܉˜î´q£Þ­eJÈ(á­"“!* & !íPTAóûµm«_»UR %<¢Uœ:__cêTH$lÔb“&Uî¤NNHLÔеá´B´“TŠ‘˜oo,X€í€Z€©Þ …š¸–L†áÃit(ÑOTÃ#ÚI(Dh(¢¢ aÂíÞÎ[(ÔP¶ ÀÖׯkèrÍ© wÂI”ðˆ6³·Ç©SXµJs C Œ¤$¶ƒx‰xôˆí8ˆn¢„G´ŸOë•4ͰaÜíÆ£¥Uˆ:QÂ#DÏôí €‹Í†´r&Q3JxDGÉå\¼§sP‘ˆ‹ƒV¨zGÔŒÑQ"<=©}[.H$˜:U½as°Ë“ªwDý(áåîŽmÛ.eÒr;"/«V±‡fQõލ%<¢»œqê¼¼°x1üýµ¦…“ÏÇîÝHLÔ‘ÕdC&Cj*U՚xîèÈR$Ü–šÚä‡Ð3É}ÍxY5&!öÒt7PŸ¦|ŠëØïqªÞ|¯l+G÷æ=žI.kö˪!îîˆÇ²eØ·öÒt7P‡¦~Š©I“®Ú´ yy´!ªB ®ªÚ?(#Cõ'—Ë!ëÈFK„4%<¢÷¸|Ó·±HÕŸ™Ï‡¯/nßVý™ á*JxDï…„ (ˆ»ËO«oΜ›RRÔurB¸‡Ñ{  + ®®ˆÕ¾Yê-ao3gØ @,Ö¯'œ°Ñ{ÖÖ8x!!ˆŠ‚‡‡mîà€ôtÖZt%øú"-«½D €»;Žƒ«+|}9Ý©B=z`­oçN89ÑÒ*D“(áòˆGVD"¶£Q?>NNøë/.ͬœÌÂ¥‰£„GÈó˜ÎI“ØŽãüý«²³‰sçTv¶ÆÛ¹nn´ˆ Ñ0Jx„Ô…³‹›xzbýz•­ úúëèÙS5§j<¦z·`¦¯Kô^K‹µPyyyvfvÕ?ÍÚšuêÜ©žÂßù[©¨\ÏÓÔÌ´s—Î’û’¢Â¢Ú…ù†|ë—¬MLLê<ÕãGŸä?áóù†††<O.—WTTXZY¶µhÛ¢¿‡ŠŠŠ®¥^{øà¡R¡ìعãÀךšš²ÏÓ'O>xXõÏŽ;š·5Qá‚Âÿ<¨úgûŽí-„Mz• >xXýÅ•Ëå|>¿[÷nªøk´Š»;’’0gNRAV¶¶F@€*Âj ªÞ5KcnqOŸ<½•vë^ö½NÖ:453}ðσÒÒÒî=»xчβ½¥°Çãiìoa‹ê^îãÜ…³Ê+äâßÅŒ[Ÿÿã|/Û^uþäÃO¢Ã£• ¥U«n=º¹ŒvY²òëí__<1;3;ïq{G{>Ÿ¯P(üóàჇ/u{i–ß,ß¾fæfÕOu<öxìw±Ò®¥••–µ2iÕϾߒKƾ=Vå£&Ýɼ³nÕºq'?ë³Jd%["·xÏò®:þÓ?Íþßl>Ÿy(r̸1-¼J³:v*4(4G’ó4ÿé®»&M­£ßëÔ±SÇcð{Q‡£<½<«ÿ¶I¯òÝ컃{ ðÖ¤·vÇínaðM~Y™„—˜77C ha-’‘oo„„ÀÛK`×)#ƒý/ ¦¢û*£Î[\Ìž˜E³;{Ìy¤3sDš'õ›æw6ñìš-k˜„ǨóCwõ·«³þ7ëÁýcÆ‰ŠªÞÄòÍŽo¶®Ý:eÖ”®/wM>—|ìÐ1‹v¡[C'ÏœÌHù5ÅÇËç ·7‡:fü•-—Ëç.œ»fóšªZã±ØcWoœ=vŸþ}Ä¿‹?ûè3S3Ó½G÷¾þÆë-y*šú)VoÞ¢ÀEböÄ<ÌyXû·_oûú½Åï¡)Õèî=»¿÷Á{®ývíÛ¯¾UM”\u7ûîìI³ Ÿ~ðñÕ³€ÑcG~X\T¸{çn¯Þ½œ]œý?ô·³·+xR°dîU> Þ„7bôˆþƒú—•–En¬ñ«‚§çNŸ?i|SÏÙ¡S懫¿]UAˆ¶qõÆ‚'fÏŸ]û·3çÍäðŠ‹Š¿\õeíßjÒ¼æ·2N»–vNt®Æ¯.&]ìÖ£›u×&÷Öp÷U¶±Á¾} Ap0fÌP˲Î4y2œœÅZ„K²3³ËËÊ8úCõƒVí­\=\ uŸoß±=óÓŸ}ó6€¢‚¢‹I™#3çÍ +ŽÇÓCÿR¡ü9ág¦Àè±£;uéàÈ#Ì‘¢Â¢ÒÒRY±ìZê5æÓ"úøÑãÚß’ÕJõ}xÕñx¼… ý¦úE‡G/Y±¤z³ïÞ¯÷Θ;£Î^Ÿú2?¼j÷ªÊåžòòòø¸xí,:wé\»€°°[÷ngýýãñe2™@ ø>æû›×o¿Ôí%‰¿ˆ~¹•v˪ƒÕ‡£ÇŽ®ñ¦/,(v}ŒŒŒB·…7æ L<€êŸâ‘cFÎ_:ÿé“§U ˜U·ñ|i>3s³õáë/œ½ðÁòªÅ”a hgÙ.â@Ä­?nÍò› ° É|^Ó½4Ÿ?¢ÿˆ-k+÷]“Ëå?ý!jGTê¥Ôù3æßɼã5Ý«àiÁ‚w|òaÝÙkAÀðôsRõÒnñ x¯ökrÆÒŽWY ¨lád±ŽÏçîô ¢Y@©P&Æ'ÌxÓáM¡Í>T”WÔ?R]©TæHröEíû&ìC#ÃOÖ}2n⸪ߚ˜˜¬Ù¼f[Ô6K+KæÈÅó•U=×q®ÌsÞŸeïP¹hN΃&wV0aò„kV·2¾–zm²bÙ¤é“B¶„¨ìïoõÖðú/ó_¾pùW[¾š»h.ó]#nÜ[“Þ4®ÛÕ‡«ŒŒ EŽ$Gü»øÑÃGSfMùøó;Y¿p¶ƒx’ÿ„ù¡žg©U«V•…¥OLš:éiþÓÔ‹©mLÛÄŸgÆz8»8ßÿûþ™„3Ëü–í;¾ÇãååæÍ2÷ñ¿ütdÄ›#|òÅ'7Ä7Ö­õ|dz—m¯wç½ûÏÝ6‡lþ.ò»¨Ø¨Qn£xzyÆî=sô‹í_ÔþRÖÓ¦çøIãOÄØþåö¨ØÊF¶°õaL'nch뫬ÝQøä<Èv¤ùÆO¿/~ß’¹Kÿû˜9R\T|p÷Á3 g~¼øc×—»Ö~ˆ÷Xo>Ÿ_XPx+íVyYy·ÝbNÅØ¾j[ÏU ×­Z`ꜩ§L¬]@©T~ø¹B®à0 xmÍ•tV~°òÞß÷®þvõU»WÝÆ»5²ê©BjOx¦Î™ºþ³õ9ÿä9pdêì© …âÛ]ßN<Üð#_ør—ðx¼Ž;víÞµÎÁ™:¦­°òKÙÓ'O_T¦ªÅ ª0“ŠLÍL«?E^Ó½Î$œ9}â´ä¾¤K×.Ç{üïcž¯zÿ¶‹«ËÏ?þœôs3„ÏçhÓ¦MUãFÇÎä=Î+--­s*ä¢ÀE'âNœ8r"+#«§MÏûwïKîK†8iäß«Ÿ¯2WXZ"=‰çÆÉd,kÕnãÝÄ÷Ä¿_þ=ù\òå —S’SŠ‹Š>xøiÀ§Ñ‡£k—ù1†¥™#É™:njÚµ´éã§'\JhgÙ®Îó+•Êç}˜•žµfË¿Å~u¶Fî‰Ø·/nÒôI["·Ôþ²¾=z;€Â‚B÷aîïy¿»7ö»ãß5£c«Ù4±ÒJëÖ­ç.š `dž …"ñDâ°Ã,„|økÃ^síâ2ÚeÄ›#^éûŠžÜ»÷ìnnaàჇ%%%µ 0•!&“Þ}z×sª.ݺ0?ÜJ»àö­Ûx<Þ¬‰³¦½5ù/þp|§. ž{çuëÑ­ñ-ìƒ^äü†³R¡ ß`×–]ïø~# {•e2$¨l º&…°´Äõëê:¿D‚áÃ9½Ñ®ö;“x€±±ñ°áÃ> 8œxøvîíÙïÏpöôY…BQÏc;YwZ¾z9€;wâ×=ER¡P.L:“tDtdþ’ùs^N¾\£LÜþ¸à¥Á![C¾úî+##£SÇNUý*+#«´´”ùÙÔÌ”vþÓ©ŸDhöŸÜ ZZÌw¯ µàöÍÛ§OžÞµeWõI!-”/ÍÿüãÏ7¬ÞP\\¬ªsr¡¡áÿ¦þ@‰¬äLB›–¥üšÂ´dŽ÷ÿ¢Õgùy•Af–õKÖÌù÷ŸØàäæ¿ýñûÌðQýMíOf0î>˜þgúosõpmð!ºéömcêT•-ÖxÍž)áêªÆz˜¥U¨†×,¼ÅM{kZU“£U«V¡[C­²b™¼¡7FÕ¸è_~ú¥öo EÀü€[Ü:{õ,3sîä‘“Ìd¾*‡ö YrôÌQ¦ò—þgúçŸ3¿úô£O‡ØqèîPaÕÐ ÃÖPÂkgÙnÆÜ¾Üóeæž«ßìøfÇúë?]·?Ž9 ð«zý´WÀªæ¯Ø±§Æà]¥RùMØ7Ú Û2_Íêq%å «VÌ8LWž¯¬´ìÏV/–|.ùÂÙMÕå6ªï€¾e¥e“\'ùøû4r0´²·‡H„ž=áé‰5W³‹ááÑÌË ¦® "håÌ–iä-N©TV¨bhhhfnÖo@¿Úƒ«khgUÙŒ™z©r÷?÷þù÷á¿ärùÒyKâF{Œ>ràȶuÛ¾øä‹Èí‘=lzT=|ôþßûp¢÷Ĕ䔰õaë?[´$¨ªÀ­?nø7çßG1Gòró˜êï2T9uÝ’˜—¤àiAÕ‘ùKçð ܰð£…*¼“;y<扻•vë¡ä!¯é^*¼ +:vêócLç—:ŸI8¸ °¨¨r¼’’’Ï?;{ܪƒÕ“j¯'™•žUõÖ¿•vë›°oÀCØ·aL±½ƒýGŸ~`ù¢åU¥â+â|>`†}6^aA¡¬XVQQÁü“Çã1•<ÇTOõ—PˆÐPDEA$„ já´³€eËšóؾ}‘›«–iì´rfË4þ·rñÊ «7TMéðÍŽoþÍùwùš¾èع£Y[39ÿäÜûûs¶³‰gårùbßÅ¢?M¢ú¥Åîý}ïõ~¯+ ¾!_^!700¸ô×%f&YÀû……»öíbJè: ¸¨¸¢¼<ðx<ƒ±oÝñíŽ÷¦¾÷sÂÏL\©P*ŠC?rú?§Ú—S(!+Cï;<ÄyˆE;‹q'þ¿½ûˆâØþ½ÂÝGGzQPÄÂ#ðÙ¢ñi4¶ÄF¬`}–{•±wDˆŠìÑÄ€ ú ‚€"]:¨½;®pw¿?Æw?„N@÷ûù뜛owæËÎÌîjr5—ü¼D…¿c>Z ÊËÊíŽ{l`hœìÔÓií¶µÎ=kæ¼ycûæí¥Å¥Ö¥Å¥Æ¦Æ6öèÕÆûäáƒ\.§3è /‚öÜqP&•Éd2¦sWð.‘P´|Þr¹\N§Ó¥R©M›Û‰·@"‘ é=ÄÛÇ›üþ)OSF~5’ÉdJÄFgÐårùæ›øñ‡&åë_Ÿ=i6yîN90˜ [;Û«qW›ýÃ6ó°6•T çÎA@téÒË aôèf>rÌÍ vïÕ×çÒ%ª¼ôJvqêk¶®)*(:vÖÌÒL[G;ãEƒÁðßë?ì›a$OÍF'“ÊXlVuuuLR YóqÅÆ§ñOí»Ù;:;æFDFÜ»uïûQõßt+ñV·îÝÞV¾í¬ßYñ€š¶ìÞB™¿‡þ¾kë.m]mëNÖñâK‹K'LðÓ¦Ÿxµ€2šÚŠ?Õ³4[™P(Ì™Ï{Ç313121Rí`ZÛ„¡¶Ã`ÀìÙï—uŒ GŽ´åKeúÒaÀC¨­™™Á°{7œ= _ ‰‰o‚j: xµpå ŒEEmYòò¶|;BŸ<„Ú 2Âù‰îØSò6•k×`ÇŽæï¥°ðýÍæµ?ð¢†1càô鯳¹ºÂƒÍŸJÜ¿¿™"ôéaÀCˆÖ¯‡€€Æ‡+;uÈÎnÎ.ðŨ}À‡P»'•°apút‹ÖpzxÀ°aàëÛÈØ&ƒ]º@||sv/F@í<„Ú=–.…£G[º†sÓ&?¿F²yyÁ­[M./ïP»‡¡ÏÁðápñ" ?þkÖ4ó™a „†BTT#ïçëÓ§9Óxxy‡Ú= x}&ÔÕaùr¸t ²²`ÈfŽpš™Ÿ¬]ÛЃ]ììJJšP,^Þ¡Ï>K!Upskí=@@@ó7=º¥T²IûÑj/GDm§ž€gèÖZ/îúÒá/‰"°7hê¼ñ!Ô nnw¸­+š«ï\¼Â£œÃC!D ðBQ<„B”€!„%`ÀC!D ðBQ<„B”€!„%`ÀC!D ø,M„¨…ϯJOÏåñªx<»{w.IOMÍ‘Hª;·BJKËÒÒrÝÝ F+ì!¯ð¢–ÔÔœoǯè?hÖˆQ‹²³ HbFFžS÷ Ý]& ¹¨Â} ÂÌÌüZ‰R©ÔÝcfÿA³fÌܨÂ}!Ô( xQK¯^©ÏαYj5sr ¥2ddÔŽO-qóæ£ï§®­•ÈçW¾€ŒÌ<î ¡Fá&B”Ãb©q8l‘X¢Hñòê½nÍ,‘H¼|Ù*ÜQÌÝ'uµµ¹Gƒ×ß¾ýxÑÂI*ÜB€‡:¾é—yª-333?èÈy;;ëº_M™<|Êd|]jmðj’“3Ξ»‘Ÿ_*­¬L ì5l˜;F#߆GD=}šÎç ­¬LÆŽtíz\rr¦‘‘¾«K×#þA§Ó ¨èõá s<^Ÿ_µhᤌŒ¼ø'©oÞTvëf3b¸‡••I{<öæM%Ÿ_õ¯Ñ‡ é§HOIÉŒ¾ù099³ªJdiiüíX¯^½­°P(Úº-4øèÅòŠwyyÅkׇNßO§Ï\KHxÁãUÙÛ[ûúLP쫸øõÅ?n¥¤dUVòm ìÕ¯Ÿ3ùªººzë¶POÀãUÍŸ7ÞÆÆüTxTbb‹¥6jdOÏVû.ú<áBm/7·¸§ë”€ÀãË—MÝôË<6bÔ¢#J$Õ$ƒ\.¿uûñž}á›6™0i—«1~Üà‚‚ÒQÿZ2ÐsNQÑk’M îÚýû¡ sžƒçÞ‰‰8ÀÕãÇf¿`‡nãk Iõ‘à ûžIy–¥Øãú ‡z¸L¾z-Ö{æ¿V,Ÿv$ø‚[ß©·n=j´Âr¹\__ÛÕµ+0™LCC]CC]m-MR²L&»ò÷½½û#®]ST ìä•®Žã¯^‹8a誟f0tþÞÓglÿoÜU$ï?pæàá³¥Œûn—«>gö·W¯Åz ™wîÜ  ôÃ+<„ÚY3B§ÓÌÍ;hiinÝâ{þBtÔÕØðˆ¨©?Œ€É“†WTðîÇ&q¹êwnkhp`àÀ^/s‹"£îÏ¿å ;LM þ³øØñ?K_•ÿ¼jæâE“Iá­ÍúyÌðñõwuéÚ»w·z+°fõ±qIþuW‘µyK°…¹QÄ) ŽT*e2™ðêuE£VWç,Yr¹üùól00ÐQ$ÚØXØØX´°Âõzš”5¹âŸ‚*aFFž½}GEz§NfÍØB€WxµÛüCÝúLŒº´îñðsgœ”zâIYÙ[òÁØØ Ál•ðáe_Ãh4É,UUáßOE*¦$kÑÓÓqÛ$@‘Yñ,EÝ”ûO T<„ÚXe%oõÚýR™l{àR77G’HBT£>•Œ–––Õ éé¹'ÿ›|NNÎØ»/‚ð[ÈFÖ‡ONÙµûTEÅ;J¥+Vî®оòèéëóòµ øÏ" s£¤äŒÝ{N‘”7o*FY*‹•¬°KO{ÈÉ)”Hª33óŒôk Z*¬X>µg»ìœÂã'þ$)yyÅ¿»ÌRc†oP¾Î5ŒVóÏ7„P3¹¹AÜáfoýøñóe+vÞ»—èìÜÙÀ@ÇÒÂxÙ¿˜á½ñéÓtö4!ÜÎÎúÐá³ó}ýÍL ÇŽñŒ{lh¨›Ö³§Ý¶- zö´Web6´¤´lÆ´Q™ù\®znn±H$™õ㘥K¦%!11O¾ù×ÒêêjÆ`0V®˜¶úgo½äRŒF£M›:rßÞŸ ¬¬rý†C\º­««Ååª Âå˦’U£ÊTX&“ý¼zßþ§­¬LärØ·gåàÁ}àëQ‹îÞM =­­EBü)„¿?v…N§ééi½îÓ§›ÿÖ…;[€P(26*•JÉxf÷î]îÅ„ ±àþý§r¹\.—3Œ´Ôó ë6¤ï\xô¨Ù‡}.0à!¤ - x„H$®¨x§««Us±¢ xövÖ©ÏΉŒwïøúú:u'´HÀ;urËÄ C+*Þ©«³9v +Æã d2™––f­Ý5\aB,–TT¼34Ô%wÇ7J$ …âZóvŸ<7·¶¨Æ¡u>‹ècÚüá¿}ç¶qP»…ÍöÓiJïç°¯#󼋿 o½P]­ùûׯÍÃ-jß°Ù~ Mmø8¤‰Bˆ0à!„¢ x!„(B!JÀ€‡Bˆ0à!„¢ x!„(B!JÀ€‡Bˆ0à!„¢„z-ÖrÏž%±Ù[Û.-/J&“=žÌçó¾­­¥¥uËËDEE……ù®®}h4šJ |þ<™Ç{'ðÍÍ­:w¶SI™!¢°0ŸÏçÕM70è §§ß’VLµ–«ú€÷øqÜðáýàäÉ?‡Ù¤m_¿~%•JM)‰dΜÉiiÏ`ÇŽ#S§ÎRmm)H  Ô³¬ìõ‚+7løJÊ\´ÈûéÓx™LºjÕæeËÖª¤L„´çþý;99™ee¯ G7ƒ!‘ˆsssD"a½¦OŸ;fÌD55µ¦–¬ò–›ššbgç@§·Ó±CÕW+!áý3R_¿.mê¶{÷>¼«f ›Í¾w/¥G^ª©ÈÍÍ&ͦ´´XUe^»öÀËk˜ªJCÕ´qc@TTì!ï¯.^¼Ÿ‘QvéÒíÜÜŸ©3fŒ …M-Yµ-—Çãõïï$‹UU Ê©>àMž<ó§Ÿ6ÍŸÿï±c'5uÛØØ˜zÓ55¹-®z¯k×nûö›ÿ¨U>÷îìÙ“Ïž%q8œ¡CG}õ•gÍoE"ÑåËgŸ=K*(ÈíØÑ¶G^Ç&£ÉÕÕÕ;wnåóy|>oæÌùÖÖ6çÏŸJIId±XuËù²……ÍÉÉäóy&&f‹¯€óçÃSRù|ÞÀÿtuíz€F£5®[·îÙÙ™§OçóùÖ¬]»v“ÉdÛ·û‘Cìá1hôèñµÊðà¿ÜËÍÍéÔ©óW_y:;÷eNƒq㦴þ¯Ðç.++|ðôªHŒ‰‰¾{÷&YîxÁ`¼|™qŒÇã |ooÒkª·åÖTRRü÷ßSSSÞ¾­´·wôðäæÖ|v4$dRÒØÈd2ÙlNÍIÁ:çÖ¤úýI$âÓ§‡„ìOL| S[[gß¾ÀÍ›WÅÅÝe±X$›šëÀíÜc2Õª««mmí¬¬:‡£®¯o¨¯oÈá¨×*¹´´xÞ¼´µug̘wóæÕ±c½._>§ø61ññÀÝwìØâî>à§Ÿ6988/Y2ëë¯=òò^’ b±($dÿo¿|òäáÌ™ã45¹Ó¦Í©[ÎO*­¾}ûzpðÞ«Wÿ$)r¹ìÖ­«Gî{øð¾¯ï4SSó_Ý€\.—Ó錸¸4##c¹\~þü©}ûËÊÞXXXåå½´²ê¸råF²ZIùrš÷_6îZú»)EèÌ™0Ÿ©}úxüõ×]ðöþ.:: @@c0¿ýöƒ§ä$%%,Yòc~~®»ûï]÷î®edé¦ã½{)0{ö¤²²7Û¶íÙ´i•ššZeeEffš—×°Ÿö«û«6p4Oëýþ5CËšíœ9“o܈$kCd2)‹Å®®®Ž‰I"Ó‰‰Þ¸qÅÓ§ñööÝ ó#""ÉB°³gOúù­æp8ÎååeS§Î ü%3ó̜鰔n¹`ß¾À3gNÐét½’’"W×>ëÖùÛØtVä9>|ýúËd2==ƒ)Sfúú.'é wÎ-ÑÔ†¯²€'“É ó-,¬`Ñ"ïS§B—-[G&T‡Ã!—Æ+Wúª«küòKàÇÊ"‘L™6L&«¬¬ÐÕÕk͹ºÏ"àåççš™YÐéôˆˆã LïׯÿåËw”ß\ ðù<C:^YYQ]]ÍfsÔÕÕë.«®®®ªÔšœkÒiÐTðP»¦Š¿SVRR\RR¤©Éµ±é\³ë“ËåoßVJ¥Rò^…W¯J™L&‡£Îf³ë®Ø¬·åÖ"‰D"¡¶v=óv “ÉÊÊÞhkë(îµ­õ­j;ç¦6|• iúøLsq± =ÿêupp€üü\£1c< ++ãÂ…pŸe ”£¡¡Ñ’ht:½…¯Ìø"8ìâb=gÎdøð)OCC£C#ÒHttt ¹\n½÷'0™ÌZm¦©§B¨IŒMºww±µíR«ë£Ñh::ºúú$½C#==}uuõzïO¨Ûrëb³Ù‹v@§Ó ;Ôí tÎ* xdP˜Ü ™˜øØÉ©çàÁ# ¢¢\ àWT”ç彜?ÿ?¿5ßþƒZâ½}[yåÊE.W»5ïÀÓ!ÔæT6¤Y\\´}ûæçÏ“ ¦‡Ç ¹s“Û– ,ìè™3a\.wöìEƒ iy¥Û¡ö?¤)‹÷î ¸sçºT*íÚÕiþü«ä ½Êû¤§i¢víÓiRS›ÍáQ\ûx_6 x¨]Ãfûi´ÙB!ÔžaÀC!D ðBQ<„B”€!„%`ÀC!D ðBQ<„B”€!„%`ÀC!D ðBQ<„B”À¬›d8Ü­õ딇¡Ï6Ûö ÎÛB¡/i"„¢ x!„(B!JÀ€‡Bˆ0à!„¢ x!„(B!Jø?xg+!§IEND®B`‚java-algebra-system-2.7.200/images/jas-poly-over.png000066400000000000000000005372501445075545500222340ustar00rootroot00000000000000‰PNG  IHDR¢Ç|-¼ùsBITÛáOà pHYsÄÄ•+ IDATxœìÝg\IðI!ôЛ¤ Ò¥‹¢ ¢"v,Ø»bï*öн`džl`¤I•ÞDA¤C€PIHy?¬—ËK<åžÿÏ›ÙÙ™ÙáÙÅq¹\€ÞßÓ ÀÏaèµ Ì½„y ×‚0ôZ=Ýð]ÌÌPl$øÿ¯Ï̪u¶®äI|צpÈóóó´ÍŠ„…DžÈÖyÿa8x îdfÖNh!„{º€ßtÚ½„y ×‚0ôZæÿLpctÄ̬§[ø@˜ïµ°e‹Õ³ßÔÒÒR]] ‰…ï ð£Àu½ —˽tér\\‚‘‘!¯©©™4É}çNŸ›7¯÷tÓBÈËkÍ;ÑÑoÕÕÕ;ÏI¡P|}O†……ËÊÊZYY"„êêêÌÍëŠÇ==‹‹OMM[¸p~w›ñðaà“'Ï lmmdee9NEEErrГӍ5k¼.^ô;räø–-gÍšùûØ]ÑÑ1§OŸ533%“%ËÊÊíí‡={þÌ™“âââ¿ v@/Ç$f»ÿ8ÆäÉW¯^Éá0°6›>gÎlCCƒŽ6éú¿Ë—/üûB8†‚‚|^^Vó>lƵØrKK“»»ÛŒÓy{wîÜiWW—ïkÉ‹ÏBuu^JvvÚ”)“°eww·‹Ïþûýýæ¿'Ž bC£Qy)W¯ú!„jk+¿³LSÓžþÏ ø@§}¯rá‚_ffÖþý{q8–‚Çã;,$Dü—%—••¥¤¤þë"G"‘ºž_PP·/³gÏô÷¿•——‡¥,Z´àñãÀïk ‘HDñ:B:::&&ÆØr·Ùu ãüù‹kÖ¬Ã>¦§§oݺýÚµË"""¼<³fÍ´°Œ-Ÿ™B¡ÔÕÕùûßÒÒÒ+(øÌår==ç?~¢¢¢‚F£)))Ñét ¥ÖG£ÑÆŒ'!!1v¬ë–-Û##£˜LfHÈóåËW]¸à§®> °°pÚ´¼†Mž<­¤¤T__ÏÏï2ïÚtÑ¢¥&&Æ'º¿ŸüüùËŽöµ©©‰B¡½xñêõëX˜g±X¯_¿™7o!B¨“Ú?|øàæ6QSS#&&ÖÙÙuĈáüÝ!!σ֯ßÄápBXoeõêµqq S§NyõêÍÑ£ÇBãÆM¸qÿ¥…Õ¿?óààOŸò ,-m+++ù7¯­­Ý½{ÏÂ…KLMMn»¸8óú'“Úý¾Ö¬ñ’À–6»~ýÊ̙۷{{y­),,ìè@}÷ €ÿ”ž¾k¾‹©iÛ›²ÅÅ¡‡ºx×ÎÎÖßÿ*¶¼gÏ®}û|°å;¶Î™3;++ÕÏï/óîÝÞË–-æ}ܱcëüùs±åèè·£F9r¹Ì¬¬T„Pyy—Ë,--Á2ÌœéqàÀ^îß÷楤ÈyyYCMM599žÃa0™´ÐЗí6rÔ(ÇI“ÜCBžÜ¼ymâÄ »w{ónÌs¹Ì2UT”±åŽj_½zå¶m›¹\&ƒÑH ૪J±ô°°W¡ÄÄØÔÔDoïí7n\á¯×Ãcvo>4ô¥††:÷ïÁrr²--M\.S^^îîÝ›XúÀº§OŸàÕ  ûØryyÑ–-==g%$¼kwï44ÔW®\Öõûîùù¹+V,]²dannFÇÙàÐiß{(++ËËË—´]Ÿ`n>˜?…Á`DGÇ8::øûßD±X,ì!ô×_Û]]ÇïØ±3 àvGu…††õë×Û–Fkêß¿?B‡ÃII‘BÂÂÂt:!ÄårŸÿ*2™¬  ÏÛSþ]毮Ýû6ôÞ½û“&M=ÚÉÓs–P«<³gÏôð˜UWW×*`‡‡G´½}Àáp‚‚]¿îoo?,''ƒÔtädžyBÅÿ¡e‚öX,j7y×.ossëË—¯Ì›7——øüù‹¡C‡´Ê‰ÇãgÍšñìY0æ›››_½z=v¬+‹ÅÚ½{ÏòåK'Lïæ6):ú­’’BHBB"?¿!”••mg7döì™'NœÚ°av>poòäIXV>\÷ð˜öömÄÈ‘Ž¡úúúºº:6›Íf³×¯ßô`ذ¡ÖÖVcÆŒkwøËDIKKcwÖÓÓÓتÆvkONNñð˜æì<ºÕ©–‡?gKKËÅ‹—ž< â/m„ñ‡©¯¯Çºƒ\\œ‰DbWª&S§N™2eòÓ§Ï<}BEE…ËåVUUyzÎ[ºtñ˜1.]¬ŽWNYY™œœ\×ÛÙ‘ØØ¸§OŸùøìâOd±X999ÕÕ5ÆÆFü£NŸ>«¢¢Ì?ñß·™Y¡ÄÄÙH@¯aþÏô­00,ËÖvhXØkaaa,eÍšuÇÛw7ÌÿI ÌøÀH{Л \¼xn×.ƒQ^^nddèââÜÓí€_Â<èå ´oß žnô ˜èµ ̽„ù?S{sÚ€Ìiø?æè]ðÜ<àæ€^ Â<ÐkA˜z-xn¾·hnFC†·NL|×cyÚl•òü¬<0à0Ù-øóY,‚Øí‚N{ ×‚0ôZæ€^ Â<ÐkA˜z-ó@¯aèµ Ì½„y ×‚0ôZæSLf ÖÜÓ­ðgƒ0ÿ**ªÿò>×ÒÂú…ûß Þºí´û¤õ/^´yU Ðeæ¿Sqqåýohg»rõqwKf0˜ëÖß»gù¢î}úÈoxí÷25ÕÍL¿×y.—òΞ9æYpoÀ{¯°…ÆÆ¦'ïøß ™=k ƒÑréò£ysÇ-]2 .åø“À SÐ3«Î×¼½½\mltáZàúã ìaÊÊröÃÌòóK^¾Š]¶tR]]ã¥Ë44úHJŠíöñ{ý&¾¾ž6ÄÖèÀÁ«ááITjƒ¡æå+Ÿ< R £ÓÿÕë¸æfFá—2''k)) #C­½û® .ŠŽI•"‹«ª*oßq6>>³ªŠª¤(«¬,W\\±ÛÇïýûœ¦&ººzŸ¾}._yD&‹ÇÆ¥ÔU z>`€Š­­ñ¨‘VÇ}o566eç|NOÏë:TOOJm¸ð’Åb¿xùÎ|°ž¼¼t``XÈó˜Y3]ètFÈó˜éÓFt´$‘„zú¸þh~OÑÂ…=Ý~6N竹\.…BÆž b³Ùp6ÿ›«©©Áãñ!‹õß×…Kÿ„꺄÷o¡ëÛVUÕJI‰c_$VTYENNJP°«wLÊË)b""¤–ÿVÕÕT!!"‡?‹Åª¨¨QV–Ãî2°ÙlÀ¿Ð;Áuà?¡¥£EEEÛ·{kh¨÷é£RUEQRR¤Óé ®®c~eûÚuñ¢ßÑ£¾›7o˜5kæ73=x˜““;r¤ƒ¤¤$‡Ãiii™;׳OŸ>X.—ëã³wÖ¬ýû÷ïV3***Ξ=C&“­¬,ñx¡Uº»û„ŠŠŠv7INNÎÎÎÑÕÕ166¦ÑhEEEAMM-??‹.***÷üü.Oš4QJЬ££ƒEÁ¸¸xiii{ûa!++ëË—"}}=„PrrÊ Aúªªª¼Š rrrÍÍó×þéÓ§ÌÌ,§  ÐjU»8N}}½šÚ×bóòòòó ´´4ÕÔÔ:¯=55µ¸¸ÄÆÆ:##³  ÀÃcz«›­§OŸ]¶lÉ€Û™J„J¥FDDr¹\{ûa%%%99¹22Òêêê‘‘QZZšêêêl6;66!dccÝn/oBBâ©Sg”••||v*(( „¾|ùrçN@LLD«œööÃ’“SBrrr/ž»pÁïÌ™sžž³\\œ»ÛÜ\ÍÀo¯í4æ!„“ú÷ïO$[¥l6fŒKÛü«W¯‹K˜:uÊ«WoŽ=Îd2££cLLÌî#„N:³lÙÊœœ\:®¬¬Ìb±jjj(”jìšþîÝ€½{ŒëJ"‘&OžÆår)”ê+¼Ž?‘––naaîî>åýû÷!.—ë嵿ñã§&&ÆoßFð.d£¢¢¹ºŽ±µµY¿~c'»K¡P*++SSS·lÙæá1mÇŽmXzMM­—×Ú7oBBÕŽòòZ¥­­åâ2¶¤¤„Á`444`«>}ÊòäéåËWîܹ‹ÂãñFFF­jÏÌÌôð˜eaanffêî>™B¡466úúžÜ·ïà½{÷-,Ì<âë{òÚµëÚÚZÁÁ![·nçßœËå¾}áá1ëÅ‹—ÇÙ·oã±ï !¤¡¡ÞªF!!¡Í›¿11±5k¼nÞ¼^ZZ6q─€{ßèSùÖ,ÈæàOÕÜLç ïý¦°°ð§Oƒ/^ˆÇã׬ñÚ¿ÿ ¸¸ø¼ys<¸}ûnee¥¤¤dpðg2™ìà0Çjçà0BTT”J¥.\¸dÇŽ­$ÉÖÖ¦¡¡!..ÞÎnˆ‰‰qSS“³óhyyy33ÓÐÐp„Е+W?|È[µj…‚‚„ nÚÚZXbbÞ•••Ñh4))©­[7wÒÔ÷ï““BB^¤¤¤Nœ8AHèëóAæ&&ÆØrGµ×ÕÕùúžZ²d‘††Æˆ㢢çÏŸ')ùõ… d2YCC]]]]\\¼£Ú—.]1}úT{ûa~~—µµµGvÊÈÈœ3ÇSFFÆÑqÄþý==gËÉÉ9::„„¼À6är¹ÁÁ!S§z$'§\¸pvÛ¶-­F6477#„ºò• -\8ÿîÝ[,kÊ”éW®\íâø†¶ ÓþT&&ÆA\.·U×n}}}II‰®®.bhh˜¸¸¸¿ÿMìãСvd2ÙÑÑaÚ´)––¶))‰=F””ôžÉd†……c555ZZZ6¨Ž–(,L¢Óé¡'Ožÿs‰Ì Òžž³&L˜$#£`bb¼iÓ†NökäHG‰äìÍÁaÄøñîUU” ÖurÐ:aðãtз ~’qã\7oÞ=dˆ-zxø[=½Ö‘†L&+(ÈϘá}ä- „DEEut´/\ð[·nMÛZ"""Éd2‡›>}vÀ¿mÛ3‰Ôî2*•õ¶¨¨èéÓà+¼ôôjhht¾ƒêêÒÒÒ+**xýÞ­´­@ ,[¶äôé³}úôQRRZ±bY»NŸ> [ÈÌÌâó‚‚‚"""ŽŽæÔÕîùÐèÑNoÞ¼8zôxSSóêÕ+õôôZeÐÖÖ¶°ôxРAüéµµµ™™™mÃ|IIÉѣǫª(§Nùš˜˜´»#ßa¾‡Üxý&îóç2¯¦¦Âápš› òÒ& woÏ{ªB¡wX}báÂ%‰‰±¢¢¢X"“Éüð!¯íCó&Œ?tèH}}½„„B(00ÈÅÅ™H$Þ¸áo`0hÖ¬VVCLLŒ‡ÿúd—„„DSSSeeeUU•••¥––Vxø[lmFF‡ÓÓÓk5(¶àá1mß¾X—Ë-..f³9¡ë×ý'Nœ`dd´dÉ¢òòò’’Ò¶a+„W”´´4B(55mäHÇ””##£6Ó¶®!T\\|ìØáV¯±ÿÿü˜7oBY,ÿ*<?kÖŒgÏ‚±0ßÜÜüêÕë±c]»R/BHUUõĉãeeeÇŸ¨¨¨\±bö( Ç_»vyÈ{7·qúúú¼tÿ[³gÿß¼ùùùGŽc2[V¯^ÙQß@A˜oǺµ3§NÙWÕEEYîéãã!‡såêã)Ó6;¶yx»³RUU›žñQTôûÃPV–{úøøü»/]y´{çâm[ç#„ê냅Ï_àSXX¦¥ÕÿåóÓRCétÆÚ;@oâá1]IIiÊ”éÓ§O544ÈÏ/ÈËû8oÞœ¶#´ÕÔÔüý¯-[¶ÒÍm\MM²²ò—/_víÚ”ðNBBB[[ËÃcÖ¢E 6lX'""²bŲӧϊ‰‰-_¾TPPðáÀ­[w‘H$*µnÑ¢þþ7“’Þ———ëëëÕÖÖ†…½ÅFÿåçlܸÙÑÑ!++›Á`\ºtYGG[@@à΀ââ6›Í`0lmmZµ0(èÑ7……IëÖm˜>}šµ±±ÑˆöOž<`0YY·«ªªÌͧ§g´[û¨Q#ÅÅÅ¥¥å%$$8Ž••å¾}>222§OŸMMM£Rë<ŒÇã›››óò>Þ¹s÷îÝ[ÅÅÅûö¤R©;wîþë¯íì[·náCG´µµòò>.X0/**: à^aá—«W¯\¼xéǼ3gÎaïë{²²²òС#ë×ÿs½§¤¤tàÀ¾ššš“'O;æ»dÉ"kl•¶¶vllÔ† ›­¬,GŒ°¯¯oHHHtr‰{!„²²²Ž;!$D\ïµÞ IDAT·nššÚ¿ÿ³àµ¯¸¸ óÅ_B°.—+%c_WßqÉÚÚKüø±HNNJRRìßÔÅæY,F—”[´xÏ·á£FY±X,A’åªSûž»2ÿ 0 ÞïÃ̬wüø :YÉår¿|ù’—÷qà@]eeåÎs–••ÉÉÉaO¨w®¾¾ž@ ðú BÕÕÕBBBbbßþ£Çb±ª««***Èd2›Í&‰åååD"»Lï .—G$ù/‹;’¸mÛÐÒÒòúõ›¿þÚÿáèm555Ñh49¹îÍfÖVCCÃùó­­­¬­ÿoòùêêêÔÔ4eMMMÞ-€²²²cÇ|½¼Vvþ%þ˜ïGinfÐé Ï›Õ.44áS~±ˆÉcúh6›}óVFl6PUUùÅËw 4§QÖªª_¿*ƒùòelá—2óÁz¿UQ–swѪ–ˆˆä€{¯ÎÝ2Ñ}ÖÍÕVFÆÇw±éTjƒ…¹þ!Æ8.99ç}rƒÑ²dñĘ˜Ô´ôýú*:9Yµ´°ž>,¯¨¶´dfö¯º}¿3׿ÿ®Ì ‡ÃáºBx—˜<Øx´®Àn¨ón«ccÖ»X‡ÃYYYv=ÿ‡yJJJX]‚‚‚&&Æm8ì ‘ößÚ-âââíŽx‘‘áÝáQRR:xpÿ¿¯”>#00lòÔMªªÊ÷jjöÃÖ2ÌmÛÏ:|ûX\\¹tùþsçìÝwYWGíõ›xcÓéUUµ¡šš:£©†Ú 1 K 1–D"îÜ}‘¿®ø„Ìã¾·¶n?}tt´tr²nÛ¤mÛÏ wXÜ¿ŸÒˆáæ›¶œ\´xBˆÅb_ô Ú°Ñ×gÏ¥â’J]Õ1ã¼–.Û¿aã ™ššúÁ–³"#“Þ€ßÄŠËšššöï?xúôÙmÛv;æ{çÎÍžnTO‚«ùδ´°22?±Ù츸ŒgÁQË—N3æŸá¬£GÛhjökllB„•+¦nÝ~æ]lZzê]<?ÚÉúÁÃÐ÷ïsF²zõ!ï‹ï±ušÓ§9=ǧ¥Üá¯KB\TEEžLîðQN„PLLêž}—W¯š>r¤%BhûÖùή«6oš3x°ž­Q\|†–V¿)“G"„Tû+]½ö¤²üµ¤¤˜´´Ä_;χ†% büSü6‚—×ÊžnÅoÂ|gDE…=g»"„æÍ_YU{êL€µµÁ´©Nlbl¤Ýe""„š›!c<Wø¥ !ô¹°‡¡f« utT'MtPR”½s÷BˆËåŽvYñ<øž¨è„PVvþ¶ígBuu òÒ5jj*XS“¯É 55ûaƒø[à?Â|W©èƒ Mì<Ì·;½‘žžºÇôÑŸ–.Û__ßø<øÔàÁ­Ÿ§ÄØÚÙÚ!„’’²%%ZrÁ†8²öZ5K9yâÿ¦˜ ´» ø³±Ø~Ðà»À½ù®ÂBl\|B("â}XX7†v×ÔÔ…¿Mre=k¦ËÚ53üÆ3Õ+½éë·~¢t¬«²’lУplŠc.—»qÓ‰ìì‚îí àc³´§[~W0§ýw8rÔþÂÝ$!bccóø k> EÍšé2ÄÖ(#ããÆM'|ö^ÒÒê·eë©üü’ÒÒª={/1™-S¦m& #£’Ïœ½ñÞ÷Äma’ÐþƒW“’²¥¤$ä奯Œó²²c2xF_U—A†Srs?—–Vëõâå;„Ð ÿà1c½\\W›NWàú.6]oà„›û:’1äyÌå+ddÈ¡¯Ï‰‹‹8Œ\ºdé¾ÉS7ijöÓÕU»výéÓg‘$!âÂÅ{jkëW¬züöÖíç=|düZðÜ|÷ÔÖÖS(Ôþý•ˆÄo?rʳÿÀÕgÁQ{}– µ´°ŠŠ+¶l=mmepýÚ®ïk—Ëmnfˆˆü¬$ÿaà¹ùß<7ÿ“X,úæEøë,Á½ùî‘’’’jý é7”ˆˆ,,ô±“c:ãì¹ûªï‡ƒà› Ìÿ ¾Ç×>so¶ç_²²d„PUU­ë˜!Ë—Méévèå Ìÿ $’ÐÚ53zº€?™™Uë~{3«ÖyÚvìÿ²<,²ò‡åinFC†ÿñy¾u7î̓?Ü›ÿ}À½yð ÀO¾;`¤=ÐkA˜z-ó@¯aèµ Ì½„y ×ú ÏÍ[,úñe û~B˜‡§fÁ/g–Ðè´z-ó@¯a~#‡JmèéV€ÞÂ<tCEEõ_ÞçZZX?£ð””\Ï9ÞÛ¶ŸñÞ ƒœÀaº¡¸¸òþƒ7 ´Î³…×ÖÖw·ðµë-[:yÁ|73ÓßÛ@þ¼ˆºÁÔT73ýÞ7³½|kkkÔÝÂss ûõSTR’54Ôú®ÖЄyè ‡ÃÁãñ¼…„„ÌÊÊZ;;cqqѬ¬ü/_ÊõõÕBÉɹƒi¨ª*Ó錀{¯ü.Mšè %%®££J" !„ Ëââ3¤¥$ìíÍBZZ^qq………~MM=ƒÁÔÓSOMýÀd¶df~ª¯oÔÖVe±X‰‰ÙŸò‹-Ìõ54úòÚSUUñžD²±1$“űÄääœìœÏº:ªÆÆ:mÛüëø}À×íûô©x·_BBVaaÙn¿ÈÈd„PQQÅ8·55! …ºbÕÁã¾·ÓÒò,,ôÝ'mxÿ>‡Ng*+ɱX¬šš: …ÊfsBw^îÝwy¬«‰$4yê&.—[QQ½`‘Ï™³÷ss -­= &…Båp¸%¥Uµµ ¡ÉS7‰ˆF:ZnÞzêþý×X“BC<çz››ëYZêÛÚÍ£P¨¡ÕkŽÄÅgL2òÕ븣ÇüB©©¶ï8›]]°ã¯siiy=u Aƒ«yh­¼œrõÚS%%ÙùóÆ_¿ñTZZrã†ÙD¢ Bh„á ÒX6;;c¦&º³³-BÈÌT74,ÁÄDÇÁÁÇj*+KFQ© íÉʸG" ÙÚíò¹—áèh©¯¯Ád¶Œ3$7û!‰$äà`A"m¬ ±kwY2›Í–““šë9ö¯ç'Nt`0˜3go¿p°o_E&³eˆ­1€ K|ú,òØÑµ¡5«=”û8­\1ÕØXÇÀ@ónÀ«‚‚’ùóÆÇÅgÍ »M>ÃÙ·VLT¤Ý­êêG-ݱmÁüyã##“ƒ…³ÙlA¢ BˆÁ`òŸvÉâ Ò¼2ù çáU°Ù.—Ûùî€^îÍÀ?DDHë×ÍrcwúL€¢¢Ì·áÇ}o]¾òˆÿAy.—Ë –ÿ¿üO9¢MMôÊÊšªªZM-­~ááIتŒŒ™™Ÿ°ü­‚.¯´ˆˆ÷õõ´1c† „JJ+9NaaYyÅ|°Þ«×qXæôô'¸Ù''çÖ×7b‰aLf BˆÃáÜ xyààµáöƒ55ú8yÇÚÊpËæ¹ÒÒ’?ü ß¼¡ZSQ‘ß²yn^Þ—ËW;²’•%ïÛeØPS;;“Ý>~TjãÁC×Xù,8*é}NyEµ¾žFmm}Xx¢˜˜ð`3½Q£¬V,ŸrúL€˜˜Èòe“Þ?´uÛ™¢â ‰H¥6,Zèîw)(3óÓ¹ ZZX& Ga%ïöñ[0ßÍÊÊ@JJÜ÷Ämi!"QAAæúgË—M¹w÷ÀÚõÇh´fI¨¢¢ÚkÕtç}÷²åÜÆÛ×ÔÖ++ɉ‚))¹Ã&Or¤¯qùÊã nöXà?÷C;p˜ÈÌÞP~5‹E(1±§B™™õ¾¿ßýpZ}}#@àï`¯®¦ ÅÄÚï¨o‹Jmàp8ÒÒ’‡Ë儎Êár¹ee99)AA„›ÍÆ2ózøÉwÜ›€ÎðB{w@—k•"#CîV ¼Çâ[Uݶ§¬,ÇûÈ í½0ƃn‚{ó@¯aèµ Ì½„y ×ú¯‡y*µÍfw´666=7÷3BènÀËŸôziàçéÉ‘ö\.×gÏ¥Y3]ú÷Wj»–B¡:9/—––46Ò–•%ãp¸¨è’ñÎí}†>yQð¹ÔÖÆHV–Ìáp**j’SrFY­Y=#00ìÁÃ79¹ŸG:ZJJŠq8Ü–ÖÜ9cûôQàÎf³¾Áb±44úÖ×Ó³6nðTWÿ¿Ùž JžGíÞµ!dmepä¨ÿ¦ž]ܵ£ÇüO8sj“““õ÷ „Vy¾ð2:òr«¶¾Ûá#7^¿‰ûü¹Œ@À«©©p8œæf†‚¼ô„ ÃÝÆÛc¤!„(êp‡Å#†Ʀ‹ÿ/^¼;yú.ÖÌår………“Ù‚Í]3Ñ}ÄòeSº[ •Ú "B¦Ö ‹z2Ì3Ìû^ÛÚµæëêîìÇ)ÉÍý¼mû™;·ö!„&L.&&2Êyùã £¼GVrr>{ï<rs³—•%ÛÙ/ˆ|ë',LB%&fO{ùü´©©.BˆÍf;Y5Ñ}Ä‚ùnضî†wX|æÔ&›¯ï‡f³Ù7Ÿô¿¾ûØ·¯¢˜˜pTTJ_ ½fõŒÇO"X¬û ºèø±µ7o…Àä”ü@ëÖΜ:ed_Ue¹§#„8Ε«§LÛì<ÚæQà„PUUmzÆGQQÒwW4j”Õ¨QVZã?åG†ûÙÚ±Ùì‚‚ÒU«‡¿MúŽ0¿zÍ‘eK'›™ üî&ÿ žì´'‘„R“ïØÛ›µ»–Fk^·fã9μ»Ç:~ü0l-‘(€þÿYRUl;çÍDmf6PUUùÈQìã©Ó ´ùóÆó¶•‘!ïØ¶`Þ‚Ý K O2¤ÁÖ勈<¦f³Ù7o…ÐhôÁfUU•_¼|×Ð@se­ªúõ¯JeeMXxbUU­Ž¶ª¢¢Ì“§‘£FZñ.Æ'dêé©·Ê£¡ÞçMh<¶¼xÉÞ©Ó·t¾ƒ7o…ÔÔÔëë«oÚ|òÖíçXâóç1;w]pp071ÑYåu85õ–¾oÿ•W¯ã&º;ˆ‰‰Ìœµ£®®±Ui™™Ÿi…BEMžºID„4ÒÑróÖS÷ï¿Ær|.ç¶æêµ'--¬TLÌ<Ú}9&ÿqLfKbbV||F``Øä©›TU•ïÔÔ쇭e0˜Û¶ŸÁþ!„Š‹+—.ßîüƒ½û.ë꨽~ol:½ªª!›®®9®²²ÆÖÆh‡÷9ç1«8Îù øëJKÏ ¿uû96˜÷ð!¯ }§LÛìâlkme0gÞÎñÖb·çJJ*[ÌZNNJJJÂÔTWWWHÌÈøÔySøjiaed~JÏøò<úYp”£ƒÅ˜1¶¼µ£GÛðB>@Àº÷ÞŦ>äeb¢3ÚÉšZ×øþ}Bè¢_`#­yÁ|7##mçÑ6EÅS&<n+]iiyQÑ)ØÙ9ÆÖÆhÒD-­~ƒëM2êñ“ˆ‹B›6ŸLMËó=¶ÎÆÆÈm¼ýXW»>}ä­­ õõÕB#†›Oœè€g:}&àÑã·Þ;똚êþµ}ÁÃÀ°sçHJŠyÎvE•”V.]2iÇöùž³\ûöUôþk¡ú€>qqØùDFæ'ŸÝK]\lèÕzxN{^Çùö­ó§Nß2Án;;ã}{–ó2\ô LJÊÎLÀº³nÝ~>mê(^×–¶v1155eì ee”’’JÞø”‘#-I$!gg[II1™ÛR“ï „úöU"‹c?'~uuUª±±6B¨¹™Ñî¨7iiÉââ l¹+Cß…„¾ž(HJŠ)+Ë…¿MêÛGÅbóæ£ÖÔ웞ñ±¸¸âÅËwüjjô;}æÞ ßõ¼ƒêè`á3!Äb±edÄBÇŽ®½}çEXxbeem}=ïÀât´U±eaa!:ùÍÖð_#**Œ…ÃysÇWVÕž:`mm0mªS'›icC‚°Ë†æfBÈÜ\ïòÕÇ……eÚÚªŸ?—)ÈK+)ɶÚp†‡³­­QCÃ??RWW»¦fú’¥ûH$¡ôŒ!¬ïmÄ{ô÷_CC­GG;j Ö¹¨¨(ƒ}Ä* Kà î33ˆÚ¸Áû( °y“çü…>×o<›2Ùñ嫨m[çuñX?×ïòêÉ‚O32>=xøÆÍ}݇œ@÷åKùú ¾G¯æ= ÷áCa«{ê!qqQWW;„лwiƒi´-\}@Ÿ´ôÕ 28nÚÔQaá‰Þ\.Qaa‰Rdñ‘Ž–!aa¡v/÷›[ÿz»ˆÉl"2™-Ü¿«Æ­"béü™y§AA’£ƒ¥……>/±®®ÑqÔÒÛÌŸ7>229èQ8›Íf³9X?ßú@:¢> B(44±ó0 Âoe¢ûˆç1¾'î`w߆]à+¿=>ËDDH!‹ea5›ÉlytL]½Ï¿ð·_ßF/%%^T\A¥6´½M‰ih = Žš:e”˜¨BˆÉü:¥ƒÑ‚Â1rr­ßp3s†ËÎ]÷¸Z^^½dñDx±ÍAOÃå"ìºyÓ–“--,ÍÞ‹UU•Y,6—Ë]´dÏàÁyCâKK«^¾Šåmˆâ¿ænia]¼ˆ³ÃÒyk¥¥%B©©y¡””Ü}{—U}äÓÒò°ôðð¤Q#-åå¥'¸Ù§¥åñ"}øÛ¤Y3Çü½§\.—‹ÇãgÍty…%67Ó?~ñ¾¾ž6fÌ„PIi%‡Ã),,‹ŠJù{+ÞA†{o|6ò..>!ñ>,¬ï9}ûö}S}¢ûˆ9žc—/›ÜQxFÉÊ’±0Ÿý9%õè‘VØU{NÎg„v–€=èËTÿþëËW!„°´MMô¼¼"¬ÿ»¿ùˉ-`ý!7n˜_PróVÈÔ)#»¾àÏEðööþq¥±Ñ…KhAgÿÉøÝºýüÖíÒÒ*ƒAš¡a ÕÕu Mo#Þkhôµ´ôìYÔî=~öÃÌÒ3>¾ ¿råñÚõÇÅÅE.˜pïþëÓg>~,b2YiéyÑ1©†nÚr²¡¡iÙÒÉAAáç.Üÿü¹¬ªª–,)Ö¯Ÿ¢‚‚ttLjMM=IˆH¥6èëkÌðp>|äÆÇOEâ¢ïßç¬ßè»yãœÉ“ymûò¥\\\¤Õ]ÿcÇo­[;{ÂÍ÷Äí„„,Þ~m=£««–û¡ðCnáù |¯ëß_‰@ Œt´a¸²²\`PÖüùs©‘˜žñ±¡æêjwðеðð$*µÁÐ@óò•ÇOžFP© àíß«ø=E öt#B¡ ºþ §9êÜ÷VIq%‡ÃK' êêª  ’™˜˜ÕÔD¸÷jÞÜqû\ Oª«kd2[,-Mœ¼±¨¨¢¶¶^PP ¹™±ËçbmmCÞÇ"c#m}}õuë_ºòÈïrÐù º–˜”5~ܰÐЄµëåæ~Æ!\î‡Â‡¡ÖV†ØCÂrräj 58$:;» &&Õa„EÒûì'O#4ÔûN2RVFòØñ[o#’ž=‹¢P¨ëÖÎ$ðýû)¾‹M KŒ‹O_¿n–¢¢¬ºzŸAzê§ÎDE¥………'ž>±qôh›¢¢òÅK÷•—WU47Ó±á÷<ƒôÕ/]~ô׎¦&º=ô ükð“ïܽÔc"3kwþ{¶d¶ŠŠ*ä䤰³Ý æF$ b3ä`¨Ô†””\%%YMÍ~­^眔”pïÕý+y)EEå›6ŸºéïÓ­zétF}=­íÙ}u5UPP Õ먹\nii•œœT'³\55Ñi´fþ€M¥6p8iiI‡Ãårÿ‹½p‹Pb7®½ÀOdfö}~µµõ µ¥nÍ47Úe…jeÏÙ®¾©‰ž•¿ÊëðÙ3›çÎ÷Ímét‰$Ô&:‘(Ðê6ƒÁhõ÷ŠÉlÁáp¼ùû:ª(**ÅÞÞ¬©‰î8jYä[¿ÎóÿÖà'ß¿Ë׌ý¨Úï‡ÀápVV­ÉdñaÃÚŸœÇÔT÷ö 4Þsí~—‚¾c¸ ‰$Ôîo˜7 ¯U#Uþ¾)ÐR«Ó ìâýÿdA€ï %%ÑÝI&¸\n~~‰•¥¹¹6æF]½ÏöçÈ’â]Ù¼£j÷‚ú×JWNJž<œwÜ÷Öœ¹;%%ÅX,VMMýù³[&LÞÓMû?#ÌgÍpñ»dgg Ñý§ü.ö¿§ÒÒªæf†ºzŸ°°ÄŽ&å=zð~x§=ø3ÀO¾;àj¾3ÊÊrØÄx"¸› ôZæ€^ Âüÿ¹ð’Ng45Ñ> íé¶ÿÖïæ+*ªÿò>‡½Áé×  H$!’1øï)红g[´ë÷ óÅÅ•÷¼á»Ã/SZZõâå;w÷ØGÛgÁQÕÕÔηâéb˯\}ü¯Z tÇïæMMu3ÓïIKKþúªÏž»?ÃÙ?ÅuŒÝ©Ó]ܼ+-çr¹¼yª€_ ‡¨‹Ï()©’——&™˜è$$dVVÖÚÙcsϱX¬¨¨‡kcc-"BÒ×WÏÉù,##9`€JTTŠ¢¢¬‰‰B(;»àË—ruõ>ÎKÔ IDAT}óò¾”öí« ««VRR‰åWW¥Õ_]½›ÍŽÍ@ÙØb³Vq¹ÜgÁQ;½ñ·møðÁ{÷_þkÇ×™“««©d²xGSÉò·<&&µººnäHËÜÜ¢¢ kk))‰ªªÚC‡¯'%e§¤ä ôõÛy“½Å¢oçü*=æºfkcäæfŸ™ùÉgÏ¥Û·öULžº)'븸hs3ÝÅÕk—÷b„¶î„ðÐ CUU•|OÞ"Žv²ë:tÃF_SSÝeK'——W/]¾µ×ôåSjjê·l;5~ܰm[ç766ùž¼-L5ÊjÜØ¡›·œ8p€¸¸ÈX×¡ÇŽß ‰Ú»g9B¨´´JBB´Õd±D¢`}= {}-BÈØÔcÅò)ë×Íjw_ø[^ð¹tæ¬ígÏl638`€Š‰™GvæýÆÆ&%%Y6›M¡P»5]6˜ülp*Ù=Ùiþ6©¤´ŠÅbéé©coTœ0a¸‚Â×·¼¼z×Ò²µ5²µ5ê×O1)){ÍêÚÚª£l²²òçxŽ••%;:Z`Ýàööf††šØ†ú6ÖFØ2–?#óÓϱ22dGGËý®zÎv•““rt°äu¡W**È´m¡’’lII¶pgÿÜ9c;Úþ–{L-''%%%ajª«««F$ fd|RSSl¦'&&âà`aggòïðM=æ·o¿nýq¹®ã¼”•e±D¬!¤®Þ§¬Œ‚½mB¡ªª*ÿik÷Dz “Ht:K' þs‰üwmó iiõÃ:Þ………š›¿n[]Mm÷ÒR’uuز¥å vß7ÃWŽYG[[¢Ó™]8ÀÖ“ö22’Ÿgd|zðð›ûº9ü‘ràÀ6Ö†»}üüÖ-óø_ ûÍW±±XlþüùÛÝVZZ²‘ÖÔ6½‘Ö¤¨ØÎU~Wàñ¸ŽV}øP(!!ª¨(û}%]Ô“a~Ó–“·oî50Ð40ÐŒy—Æb±°Ëw„PUU­‚‚ô¶­óZf.ñ^·ÃÿÞ QÞEsfV>ïì­ò·»­ššryyuÛU¨¨|Öþú§æúÚ_£·Õªp^ñ¼% Ѧ&:B(--oèPÓÎ ð#ôd§=›Í9wþÁë×qW®>vo/((°ÛÇJmN ú44Т¢Rî½JNνzíIRRöå«rs /\|ˆZ²xâÛˆ¤ððÄþÏTû+Ý xùôi$þä䜋—?|øræì½ÜÜϾ'nWVÖ:|!¤  #$$Øjr:!!!*!!†}àE´à€Ÿ|wôäÕ<‘(ˆÇãû÷WjãB9¹ŸûõSÄîÖ‹ˆLMtÛæi…Dêß_ ÇËÈå奻J—,žøüÅ;ÞI›Í~õ*Îsö˜®—ÐErrRãü¿o¼¹tqûqßÛRR⡤¤’Lßã³ôçU',Lš9ÃùÂŇ‹º#„ö¸ºjå4aávÎ?€?Åï楥%wí\ü+k43Èáp &‹Åvt°04Ôú•µ?Üïæ{„¹¹>BHHèëðGû½^]€Â<ŠMÏÍýŒºðòß¼0¾¦¦ŽÁøúà>‹/žÐóþëö%Ï‚£vïZ‚²¶28rÔÓFÏn•ÐÜL÷Þy!¤©ÙFkf±ØÃ†š…ùìþ‰€®èµaþÊÕÇØëp:Áf³7n>é}7ö±o_E11ᨨ[[£.ÖR]M2tþ^ŸåãÇÃRhÖ¶sG ü½ àoàwÒ;Ã<—Ë yóÍ0žd0Hƒÿµ°3g¸LžºéEÈ©.V´|ÅÁ!¶Æ¼=t`Õó1Ýo5½L~68•쎞¼7Ÿ••ÿüyLqqEqqÅ“'Ÿ?—ò¯MNιuûyrr/¥®®1$$:99§®®ñú§iiy¡ÆÆ¦—/cL©©Ã²UUÕnÜt"));%%7#ãc'úß vq¶å¯TRRLPP€B¡b›šè ´ŽÚÿåKù€—ž³][¥ÛÛ›)´÷Z[àëÉ0O¡PW¬:xÜ÷vZZž……¾û¤ ïßÁ«×‰‹Ï˜:eä«×qGù#„>|(ts_§©Ù/æ]šó˜•#†›§¤æÖÕ5:9¯°µ524Ðr³êÓ§b„Pcc“’’,›Í¦P¨55õˆŠOÈÔÓSoÕ* õ>oBã±åÅKöN¾¥£ö'&f!„44ú¶J"nÞ4ç_àßëÉ0oggbb¬ÓÔDwv¶•——63Õ K@……%>}¹xÑD<¿fµÇþWY,Ö¹ól¬ 54ú.˜ï—!$Dœ5s ‹ÅÂÞ£££:ÔÎäü…!55•Áfzbb"ÿcï¼ÃšJº8|B:¡w. ˆ4Á‚bÁŽ®Ø»èÚź¶O]{¯`ï‚ ÖU¤+ €€ U¥©ôz $á~Œ{7Š€¸Xæ}öÙçÞÉ´d÷rîÌœó;C†˜µÖ!Auu,Þ{„²²\^^1ºÞµséÑíªè׳€F£~›ŸƒÁ`0˜¯¥›Ïæ)Š&ºb±àyðk 17wTncc^SS¯§×#::˜ÌJiiƒ!²²R§On¼pñ>NKÏÈV—iq”;¤·˜¶GFF27·]ë訵1y3SÈÍ-––fð}Œv0 Óít¿ ž€…¯DJJBQQfîœqè]ØŽ°|ù2îä©Û……Lß§§Ñ*<..eÁB§‡÷ê訕—Wçå³X BB‚dWiiY †X‹Ááp›Ï§¦¦NII®=3×××°²4zôWHŸ>º¼åååUoß}ÄfƒÁ`0ÝN7ËãA.©É¥õdûaqq©UU5èöáÃàÆFv\|êœÙc×®™uðÀj ‹^è#7wߌњ;/¯¸©©ÉÃÓŸËå2buu,HLL§R©-vH¡Pde%ëëY|SÊÎ.TSU@×/_Æùû¿jmò7®9qñäuô7wŸ)“‡wþGÁ`0ßA”•U¶‘­ûŽW‹ÕPWÇzðày§Ga³9Lf+kaºœî\Í»¹ûľI),bõÖ-/¯ ‰égÑ{ôèn7÷¬rxø¼¯qOmmU!!ÁŠŠj?ÿˆÃ×öî­}îü½ðˆ))‰ýûÔÖÖ§¦feç>¸w¤©‰8uÚ#8$FNNj@ÿ>PYYcÙÏhâÄ!ÿ,{**ªwî:¯££¦¤$[PPš]¸Ûy¹¸¸(ï> ¦Q©ÂÂB $$èã6îß‘;_$<<Þõì] C))‰‚‚ÒaC-οwÖu«„„XWüB ¥ÕŽÓ»*j– ˆ‚‚Ryyi:F„ý”®g¶¨ª*QRRî°Èiåòivvƒ °°”Áf³9tú?/.%%åÒÒdrwÞQIlì{¯»‡®!›äänýŸ‹»ÛގΖɬHHHWU•×ÓëÁûÇó_`µ bbº{°°øvqó…ØØ˜‘®0óæÿig7xÆôQèvÑïΉIé‘×Ñ#?Ðza«>Çm@Ÿr¹Ü+,[:ÅÜÜFŒ\naÞ =ûgæìm"ÂB7oì¦P(—W<Üvù=¯Ãäy\tt²Ã"§—¡—ee¥PI~~Éî=—Οû'g•ãÁÝÎËÉ _䌋çÝ{A~>.¢¢Ÿ^߸éí°È©¼4XJJ¢ó?Ó¯~ä;Â÷k(ŠŠŠ<2É\.·°)#Ã@å 2úšdM%%9ôœðÚx——&m<_‡ssC.·‰72þò•G;¶ÿÞ‰ÙÊÊJ ÞO__Ûx æÉå6‘·ZZª¤÷÷åæî{åÒNò‘¤ó>ŒT*uó¦YYè–N§!‹4mÁ<;·Û¾ééÙ¨ÄqÍáÉöÃy}n,-F ·Ü¸é$Yrîü=ÒÝ1Ánˆ‹«W;¿KRRÆögo\s&m<ÌŸ7Þ ûô`ºšÃ&Ñh´KvìÞsÙÅõαãn›6Ÿ41é9~|ÇöÇZäÏ‹wï¹ÔÔÔ‘êêJ††Z_ß-ƒi'-Ê^Á¿õ¬X¬†›·¼/_y”””ŸŠBrH˜ªªš%ËönÝâзoχp=ëÚÚªÚÚª-Ï¡ªF\LDVV>~Ì}ôWÈèQýùêŒÙÿúMo$ÃEÄSŸ°y+ Þ”Ü&³‚ËmÁÉqâ¤û€ÆZZÿš…B™>Ͷ¹W2ó5üfúôÑ=°ßÑqÕŒ?6Ì=rxÝüyväËø× ))¾~ÝœOŸò€N§-þ}Ò×÷‰Á`ÚI‹²WÐLÏŠÅjTQ–çp8ee•¥¥hMOõ-[Ï0bÛ·-âëüÃÇÜ'O^\½ö—ç01Ñ'?­«c•–Vde<|ìïÿ*(àÚoO}žýB„¾¾$$¤@~~ ƒ!Æ·u'(H¯ªª-*b¢[Só9ÇO¸·öÅcbß붯»aý\ìÙƒéZº? ®ÛQQ‘GÆYtïL0˜_ RöªG¥µëŽ"Ù+¤guâø°aýµ1kVÏ´µµ°±1—“û×áwppÌ¥Ë#®òFÒ"¤$ÅuuÕ 1 QhFa3&æ]YyÕÃGÁ}õ,-{£òšÚ:hÉãÅßÖÔÔ@nn±RK‚ÖÊÊryy%HëÚËó ž¿D&I}=‹÷HƒùvàÿÏ0L·Ñ¢ìU‹zV-z¥ÕÖÖ/^ºgÝÚÙ¤L…ûmß9³Ç¢kYY)CC-CC­¼üTâíýù퀶–ê˜1`ÚT[Mm»Þ½tì퇀I_}ÈÈÈUWWâ Ü›šê“Yìù‘–¬¬ü¸Û¿Ÿ6¾¸™©An^Qóò¸¸##]>7# ækøa6í1ÌχíˆöÉS·Oö e¯H=+ôÏÝ;‡ølü‹oÐÅŽ?ÏR(”ÝÎËÑ-“YÁdV6eö¬1èâí»Í?¥ÓiÊAQè¶W/-ã>ºHx›—à˜Aûªª*€ŒŒ$ZôóQS[§¤Ô®´U æÛ=þš|' Å6Óµü„f¾±‘íáé×U½••U644¢k´Y\\Ö‰®°ÃG‹²W-êY’½*..+))€ˆˆ„Óg5ôÅ›'N–ºž½›^QQ}øÈ úú†ôôlÏ;w<”–V¸žõzûöCQSRR|ÛÿÀÇ™³ælKNÎ@ÚÕ½ž_¶bÿœÙcMúö|óîî½ ˆ°kdEEY!!:ŸP‹ÕÀ`ˆ‘tg\î°—qš»ò‘œ?·íì¹»Ógn]¼h’ŠŠ\ì›.—»`¾Ý·ú­1¿*߯µCãr8œ””L&³ÒÔTûØ·üÈw„ŸmÓÞõœ×üy_»”w\}x°µ)iã@BBìÈ¡µä­‰‰~@`$’Ío,‚Á´FÛ²WÍõ¬€Áÿ6dFÀûæM¡PÔÔGŒ°lnã`Åò©~þ¯Èe—Ë ŒrXÐáµ8F32Òµ±1Ç6óèæMûèèä¼¼ia33ƒW¯Ëʪ¬­M$%Å_¿~[RRÞ¯_oyyéwï>fgé‘”” kjêÂÃÔÕ{õÒF½}ú”G¥Ryu§kjê""Ë+ªFÚZÉÈH¢Âº:—ËmmÃ<;»ÐÓ+ âåU¾òaÃ,ââSÉÛQ#ûD¢W¦¦&&³R^^ºyoXƒi RöJUU¾¡]XXÚU²Wÿ""ÂóæŽ»xéÁ²¥Sàà¡ëk×ÌþbC æ?¦;Wó‡Üàp¸ööä¤$޽ éÙv¿­Cž/ùù%ÓgnMMÍ€ÒÒŠÕk»¸z%&fXZ·úÁƒçAAÑýúõr\sØÏ/uñ*Ñ„G«²²f̸ÕÖÖ&}{޳[ûáC.*_¾bÿÌÙÛøgó711ï@W—?àUHHð[’·úšþŸ“×]¿ñDGï·¯°ÓßHöê¿Á¢—©‰~CCcmmýH[«Ö4ø0˜î¥;Í|Hhl^~ ‡ÃéÝ[g¡ÃD˜?ÏNúïM³ß~ªó·2ÄÌÌÔ ªªvüxk99©þVFž^“& •‘‘lmBšÛÜÜ"Þh‡ƒVØš6CÌ.\¼Êwí\zôðºÖfUÏjÚöä••åòò‹Ñõ”É#|¼OS©-4Á"ÌOŒ¥¥‘ ˜˜ˆ%>†Ã|¯t§™ÿsûâ›NÊʘðÛ:9Tˆ\j¼ïõ …ts&ÏðDD„ëëÐ5“YÉ«Y!++uúäÆ ﻸÞIÏÈ®ªúœ¢FGG­ áz3SÈÍ-nþÒñ@ÈÈ0ȘWIIqkk“æõ¡M 6ÇÔa0 æÛÒf^VVòÓ‡Ç/C/›™ØOÙØÜçŸ rEðf·x°-##‰¤(qq)ã'¬›8ÁÆqÕ S`±¾Y ¯¯aeiô课òòòª·ï>’·55u-ª]òE00 Ót§™ßºí ›Í16ÖsvZ®©©‚Œ:ƒ!Æb5@MM]ff>yàÍ+vÁwMv¨££–ÿ·ª%¸¹û`ŒvþóòŠ›šš<<ý¹\îË—qþþ¯Z›•€€ÀkNg\<““3xËÝÜ}ÈŒX]¨¦¦ˆ®³² .^zÐboXƒù¨«cÕ×9ò¥s–DÂWHc!jjêÈ´×X óŸÑ J.·éü…û½{içäÙO†V·›6οåæS]]—•]л·ÎÁÃ×åå¥ßĥľI),bõÖ­¬¬yö<šN§YYÑh´ÇOBkkY<Ÿ}Ê?tpÍ$âÁ|·¤¥eÙOÙ¨§×#âUâ8»5#†[¢Lqë7‹ŠNž9cT`PÔñn,V£Š²<‡Ã)+«,-­@kúø„4ýžÍûÔï©:!10Й””„¢¢ÌÜ9ãÐ?wïâ³ñ/^¼€Y3ÇÄÅ¥–—Wñ~TXXš’’9sƨæc©¨È_8·mý†c?æµ8 ± †À«W‰’’â #ÃàUÜB´S (Ê‚ùvþ i¾…‘О0˜¯çÇ0óÇO¸iëN$SÔüÇìÛ¥ŸEï¯ì¤¾žµeëé-[O?x|þÂýcÇÝbcß;9_€¡C͹Ù!;?{Îö3.ž=ÝàjDDÂÂEΤòó£Ÿ:göصkf<°Ú¢*œl?,..µªêóŠùáÃàÆF60buu¬ââ2äõ6uʈ‘#­œw_${#bû޳³fŽ&CçëêX¼^ñS§ÚN™<"úõ[ž&Ÿ’%l6çÒ•‡ZZ* £­–Ÿ_Ê7çvJc!v;//)©¸zí/ÞB?¿›!æ_üq0˜.áÇØ´ß°~îã'/Z<‡€k×£Ì7_Oó®üü"e[t¢i?LfÅ`›Åû÷:’9ì««kZ/1¼ ÒçÎ{ô˜[;ƒqϸxÞ½äçãB"Þ¸éívÛ÷ÌéÍ_3I æ¿gÈ`S=}{:F§Ó$%Å:LܺÅAKKÕíæžUއì' ++¯RQ–C«üÕŽ3\Ïz‰‹‹:®š Åóö={/¯Xy`Á|;‚ .]~¨§×có¦ù¨sO¿ÓgÏ|¸írïÇ'ù$š“””1hð¢„8ÞöA ´ÐÏçLóóË_¬•ñýÐy‚ ì§lt=³EUU ˆ’’r‡EN+—OC9A¥òòÒ¼ŠUU5T*¹à‘°X 锾}{v­{lc#{Òä?|¼O“%ÆBÔÕ±Òáíßn IDATètš±±öáýZð#ߺy5œ—W¢  -""lffðêUbYY•µµ‰¤¤øë×oKJÊûõëÍ›––õñcž¹¹!*LMÍ\³î¨”¤x||ª””„¦¦Jbbznn‘••QYYUCC#Òµ(,, O=º?©RIDtôÛ´ô,SýÞ½uJK+޽û>>>•F£¢†Ÿ>åQ©T^_SS‘X^Q5ÒÖJFF6551™•|ñ»$ÙÙ…ž^/¯ò•fÿOØ ÆEËý6:m¤÷Ó0'ç 55uÊÊr\.·´´¢¬ì³SOÄ«D“¾=É TVÖŒ·ÚÚÚ¤¯qÏqvk?|ÈEåmÇÎÆÄ¼€æÛþBB‚ÿÛº¼mg0nLì{]µæåÖÏÅúz˜ véÂŽÝ{.»¸Þ9vÜmÓæ“&&=Ç·îîyý‹ysÇ?~ò¢¬¬°4æÇ¤;Wó!¡±ZZª§wot">žÝºõÇЧ¿ý6Tçßöl̘(ÿÄñc´t& ljff ««VXÈ$=nFŽìod¤ÛØÈ¶³œúþ  ½©‰–– R©cÇrÚ}1((jÜ8ë TW×9,˜½ µÊ+ªµ´TûYô%»€ÜÜ"%¥\j9ZahÚ 1»pñþáCk`Êä=õ4Z{Á¯g5ö…×¾`ÜÖ:¬¯gu(mó=Ó§î>ŽÝ=‹¶ P(»—'$¤YZJbi,ÌHwŒ?·/ž9{Ûâ%{† 1=°ïó£Î{jÅ÷8 }þHRR\EE>$4vîœqÍ»¥P womPUU€ÁƒMEE…¾.))^SSWU] ‘}õPý‰mZ›!“Y©È9#++uúäÆ ïÓé´ôŒlyr>mÄΚ™@nn1oÊ oìl;ƒqÍL Z ËK12ÒÅ9ì1˜.GHH=§ßTw ƒùFt禽¬¬ä§_†^635°Ÿ²±¹3`k®õÐØÈ–ø·[ ¥Eˆ‹ýóÑõO¶ÿéºrÅ´å˦¢¥9‹Õ &*‚ªZ$--«°°dd$y£fãâRÆOX7q‚㪦&¨«/ú0êëkXY=ú+„¯¼¼¼êí»äm;ƒqÌ·{þü5ùB@‹m<ƒÁ`øèN3¿uÛ6›cl¬çì´\SSuC àššºÌÌ|Þói2EDvvaC{èP `0ÄQ\ì»÷ŸM&Aü+ öŒË‡$$Ä‚ÈË+ij"ÜÜ}çÌû<ø5êœ Ï;þðwT.$&¦£ sµüü²+7wߌÑQB^^qSS“‡§?—Ëm;vV@@àÆ5§3.žÉɼånî>S&'oÛŒ;nœõ´©¶Ž«ñfe((È´6 Ó KÉ5ÿuu¬žwº9–ÌÂ4‡êääÔu½qáâX2¡µo{ø1™•5Õu¡/Þèêª÷·êÂÂBAAÑÂB‚¯"³² cß¼735——öó‹04ÔJMËJKͺpñþ©“54”@YYîòÕG‚ ÅÄDÿò•Gwïææ‹ j—Ëõº(%)áça=¨ï簾ú“í‡qõÚc Pžx¿ègÑKYYNVV20(ª¾¾!+»`̘ ®¦pöü½Ù³Æ  3$Ä®^ûKJJ"2*©—¡Ö£Ç!ÚÚªƒ™<þz÷ÞK+WLk-g®œœÔ”É÷ÿy6'§HTD(--ûÞýg#m­ÔÕÿÑоíá7bx?ôÑv‡ãÇ[”=î&ɯ¯gùúE|ø˜;wÎØeìý©¸ì K—v÷$0pñbûÿt-¡¡±óvFF&M°òõ½56²·þÏeÙÒÉ_ã •ìãfnί¼Ût:íãǼŒŒl=½+<<~ëÿÎäæeeøú†Ó¨Ôžikõsf¼Å|GèθùÆF6FÍÉ)’——毬¬©«c)+Ëåç—ˆˆIJŠ“ŒÅj¨ªªå[¹QTÄTT”mÍ5¦©©)/¯XYYŽF£±Ùrs›Ãá•©¨Èó6,))—–– Ÿí3·žuÝ*++EV(,,e0ÄEE…y»j'LfEBBºªª¼ž^^«Ü‰`\‡“’’ÉdVššêÿê>ö8ˆöû¡#qó]Îù ÷ÂÂâÝníýú®¶mw™=k o¦ùNpáâý§>ah»ZsU®UŽw;/çý³Ó6-Jf9,r*/ þ9µ4ð#ߺsý'(HÐÐPæÓ„‘”WV–yii¯9j¾;M¡P””äÚpPWWB–›×0Óh4UU¾†òòÒ¼ïïÎNËoÜôæ­ ¤$‡&܉³pYY©áÃûéëkò­¼;ŒK£ÑŒŒtmlÌuÁü°°P—ôS]]›üöÃWÚxX¶tÊmo?Lf…¿ÿ«sùúOKËòðô %]|""ž ãM–ÃdV´&˜Q_Ïzù2ÎßÿU”””oÙz©rñúî ÞïÙóèöŒX2 ó%°™ÿ2KÛ76~CgŒ‹ù5!x÷þÓÔé›ÝÜ}^E&Î[°Ž½úâÍdûaAQë7|VÑ(-­X½öðÉS‰‰éVVFS¦m~ó&}tó–÷.§ š¥¥È—qààµÀ ¨©SlÅÅEçÍ߉‚S>eæÿf¿á–››ÍÑÐP6³˜ããöáCnß¾zý:‰"ÃÂâMMôÉ®P«ë7ž°ÙmmU3‹9,VúÈÔ|Îñî-~;‡ô,ê÷%»Ûè¤EU.¤WUÕ1¿8 `É,Ì—Àf¾]|ÓxYkk¬qù¡ÓiKÛS(e%¹ÕŽ3ÝnîQQaAAº°°Ðæž:íQ[[C†˜™™ÔձƳVP±07|üRR27m>uìèz eKK£±c¡ž##“¼î®Z9N§™›ZXþ¹óÌ™=V^^šÁ³°è¥§×ƒJÈÌ*°¶6QWWÒÐP~õ*5ÏÍ+RR’#ç‰ZIK3ÌÍ µéÉÉÐG^ž-l9o–„„¯°G‹ðªr bÆÛ\YY./¯ä‹£–ÌÂ| læ1LwB„‘‘NCRT«VN—‘f:| Z“é•)Š&ºBëiÿ€Wººê¤39© åðŠWCSO·ÇSŸ°úÑÿ§Þëú¿×èLf¥°ð¿ÔùZ‘ªýû÷iÃQŽo‹®µNZDFZ’”Çh{”6$³ØlS‡ÁfƒÁt7¼Ù¡–,Ýû*2iãóÿ> ™Ir‡¼ùI³°°`‹±BBB‚({¢±‘M¾ðõÓâ鵌 ƒW«š¥NHU.DMm¯Òv`É,LÛ`3Á`º âoÐmUUÍ•k­]3“J¥”6Ò³"kþÝêss»ñƒ?~Ì#-\NN—Û“í‡%&¦“–>$4vþ<;žÉÑ÷šDG[-?ÿ‹Û¬Õ?UoÞòNMÍlûÛµÝIsU.ò»¨ªÊ·g,™…i›î”ÇÁ`º¬•ñýÐy«áÏ碣ߖ”T(+É©¨È Ò?}ʈHlâ6E¿~ÛS¯GDDÂ`kÓ—aqžþ¹¹Eš*qq)×o<ÉÊ.PSU455073 nj"vlÿ]@@ÀÉùBHHlEEu_c½7½?-)-ïÝKûÑ_!÷î—”÷Ôë¡¢"O£Rcbß üù°œ·ÕÕkŸx¿¨¨¨îÕK[^^zñÒ= 2(o¹¹E{ö^Ž‹K0À¸µN 4øT¹Ð/s÷^в¥SÐm£ ~9É,üÈw„î”ÇÁ`º¬•ñýÐò8 Lf¥²²…BiA……LEE™êêºúz–ŒŒ$òi%"?¿D^^º£.®ìI“ÿðñ>ÝùïÐAøT¹<<ý**jV,ŸÚ¡N~!É,üÈw|rƒÁ`¾/„„UT>ïW·çt™B¡ A-IIqIIqÞr”¦²£ ÒgÎ?hД’e¸Fp¹ÜÀÀ(W—-íIfué¼0??é–ƒÁ|óæŽüäEYYå?ôÁC××®™%""üåªL;ÀfƒÁ`ø¡P(»—gdäüÇãÖÖÖ´µêÛ·ç<.æ'›y ƒi!!AËÿ\^LLä¿ósƒÍ<ƒÁ`0?-ØÌc0 óÓ‚Í<ƒùU¸ã@jêu6›SZZ‚yUö¾))™11ï:ÝœÍæ0™ŸgËá`ÕÛ_P‡Á`~ > ¦Q©ËIOă×ÄÅEå奲² edµµõë×ÍiOÛ¨¨ä„Ä´¥K&wtPÍý®*+Ëu4,0<<Þõì] C))‰‚‚ÒaC-οwÖu«„„XGç€ù ÀfƒÁüüäç—ø¼:n[çšß¼õTRR|ÕÊéèÖqõ!MMt—WüöíÇQ£ú·Ö6>!õ©OX'Ì<¬]3kíº£—.îh¢ê3.žwïùù¸ˆŠ~É»qÓÛí¶ï™Ó›;1ÌOÞ´Ç`0??çÎßãM ÛQž=‹–‘a·k×Ì"¯Ã#ªªøÓÆð²lé”ÇNtn\1199©/Þ´³~RRÆögo\s&m<ÌŸ7Þ {ïÿÂ`3Á`º‡ÿøqhCCcTTòóç¯QvyDMM]@@ä¯R£¦¢¢:$$&""¡¡¡1$$e|ùð!÷ñãÐ'O^DG'“Ý>{}Ç+ ;»•ñÔ'là@c²óæ­˜Ì .—ÛÚT µŽ½•™™nuuÕ'N¡¡±›6Ÿú”™ŸZZZ¾‘·÷K‚ ^½J,,,­¯g½|çïÿ ª«k_¼xóìY4—Ë ‰yö,š÷ȼ²²Æ×7<..¥²²ææ-ïÄÄtT>é·¡“ÕŠ‹ËÚøIOœt0ÀXKK•·B¡LŸfÛ%ö0?"ØÌc0˜î =#ç·Éìrº $D§Ói£Æ¬ŠO€ÊÊš1ãV[[›ô5î9În퇹Àb5()ÉÍš9:,,~Á|»S'7®]3+âUBAAimm½´4cûÿ~€ÃGn¨«)õë×[DDxåŠiû\€ÜÜb%År·7o^ž-œØÚTåä¤^GÝôò<8 Ÿûž™÷›‹l툖²²’Æ}tmm­ÔÔétÚ’Åö EYInµãL·›{$$ÄÈÃYY©ù󯧤fN¶¦®®4vÌ _ßpôÑù ÷ ì«««¾d±}TT² ™9WRRœÜÏÐÔT ðu11Ñomžõõ,2ÿ ƒÀfƒÁt3d~›!fÉo?äåËÊJ>¹ñÂÅû.®wÒ3²«ªjQ …¢­­*"",))...ê°`BTt²¬üðƒêëYð<8¦®Žåæîãæî“”œ¡ÑC˜Ì ^ûæ­ ÿ>²²R­Í°¢¢ZXXhêTÛ ç·Ìx<Þø=û.·V™ ##:¦¨(‹æL~D¡P¤¥$P¹ˆˆ‹ÕˆÊõôzäæ“Y)-Í`0Äx›Ðé4t  0rdÿ6Òù˜™äæ5/‹Ka³qLÝ/Êaæ ‚(+«ìÒœ¹ÿEÓÖÕ±uÚÃ÷éi¾Ì¹¢¢ÂT*õ‹“€óíž?]YÉïÛž\˜Ÿ’î4óAìÙ{9+« :ÕkÖ9}Æ30(êÔi ¯©ùü¸¾~ýv—Óy ˹hCqòÔíQcVÍ·ãÅ‹7EEL'ç #G¯œ6cËñn'OÝÞ·ÿÊü;‡_Ê›xŠŒ¦ôñ kçüSR2'ü¶nÄÈåÿêÿ"44v°ÍâeË÷}e?Ì “ùùyüëqèÄ C¤¥nî¾ëè¨@^^qSS“‡§?—Ë%ˆ½íß¼õ4>>U]]iÅò© &äå/˜g÷Ô'Œ¬äu7´´T ™m´€›·¼SS3[›aJj&鬇&cúÈÈȤ¯ìƒùA¹ãheY™•ŸzõòN˜:eÄšuG¼îVW×ÚŽ°ú}ᤫ×ÿb³9½ µY¬'ç‹›·œ^üû$ssÃÜÜ¢¯UUÕ?á6uŠí¡Ã7êëvî:¿rÅÔ½û® Ò·mwÙ¾í÷!ƒMõôíétN“”_è0që´ÛÿæMÊèQÐXÅÅeGŽÞikÕF^ùóç¶=wwúÌ­‹MRQ‘‹}“ÂårÌ·ëÂÿ^˜ J—î„7‚Å@ˆºÐUÝÙOÙh ¯y`¿#oáê5‡kjê®]uB·GÝÊË+ ŠŠ‰¾…ŽßÎ_¸ç°`y7tøR ó^G¬#{ÈÈÈILLŸ”¤¸®®:ƒ!&!ñ/÷W¾hZee¹¼¼ôâåyPOO½o!,,¸lé?Þ:,<~ÇŸgϜޙäu70.ö6˜›ZXþ¹óÜéS›Nžº-#Ã6ÌfLå~Û÷áÃ`t|€¨¨¨^ºlß»ä»ÂÂBÖÖ&»÷^ŠŠJÖÓSç‹!>|h­¾¾æØ1ƒ\\ïxy¤P(#GZ¹ßö#5·1˜ïaa¡ÝÎ_ëÁÚ~,,z555544 þgƒ¶“>}tôqä+ÌÈÈÙí¼ç›Á|%ÝPGnªý¹}ñÆM'eåGLømŠŠ˜ôÕ€ŒŒ\¾&ééÙ`jÊ/±iã< eÇÕ‡›"++eh¨eccNêTx{¿„fÑ´$2Ғ䢼íhZàý“anfàëþ¯tx´¨ôt{<õ _¿]]õæå$±±ïÙÁ!1(ðWOWÍæ´C úúhgRDXøk2lb0¿––Fß¡o CC-%%¹îžæ‡ç{‰¤”••üôáqrò‡ûžÙOÙ˜–ò°W/-ã>ºÏƒ_£µ/IpHÌ }›gf¤R©7¯;÷5UPXê°`B‹£Ìž5]¼}÷ÁÎn0_4-IMm’R «ü/ÒÈæ  !!AÞtÔl!!: Ñ›•ÿ뎔”…B™=k :J@ï%qq) :=¼TGG­¼¼:/¯˜Åj@ [ŒÁÅ`0 ÑÍF‚ >nÝv†Íæë9;-×ÔTáp¸4íÊ¥gÏÝÍÉ)$ëgdäܼõôÒ…ÏiëêXHO¡­­vúÔ¦à˜Að?{vþù¢iIrrŠTUåÑuÛÑ´PVVI:Ê=þzþ¼ñ0Ù~Xbb:iÑCBc‘tåÜ9ã^†Å£Â¦¦¦°ðø9³Çü=Icc½ž={„„Ä¢:ÉÉoß~h=†ZŒÁÅ`~,ššš**ª»{ß–ÈȤ¶ÿ’ü|¥Š@ŽÆH¸ë¦†ù†tçjþ¶‡ß똷%¥å–ýzs¹Mç/ÜïÝK;'·È~Ò0äXkaÑëyÐùe+öÏ™=Ö¤oÏ×1ïîÞ Š»f`  ‘‘IÇN¸½y“"$Dß²Ùõé°`‚¯_z (,,u={7!!½¢¢úð‘õõ ééÙžwîx€fÑ´«Á#ÝSÛŽ¦€9³Çž=wW¿§fôëdy”¡²gOs®ÿs\}hü8ëwï?‰‰‰lüc.ªœŸ_²}‡k«>AQl˜;hIxx¼çÿœœ"7wŸ¹sÆ=¸wdû޳9¹E‚ÕË–Ni1†822Ùën`VVÁõOúé^½þWjjÖÅK:—Öƒé.âãSŸpg0Ää䤜v-ë’>›ššºþ:æ]EEõ`kÓ¹sÆ¢L3ÝŧOyO}Âöì^QQÉ ‰iíyNCCcwì<×ËP iù}=¤ظqÖj˜“SøçÎóººjjjŠ%%åÊÊr,V£¢‚Ì„ Cºdb˜oÊ÷7ßØÈ¦Ñ¨99EòòÒ¼™’€ ˆ¼¼âÔÔ,CC-ù.šêgx£iž~5+–OíP?……¥22’|•Aäç—ÈËKó•s8œÂB¦ŠŠ|[îLf… ¯dæcˆ]pí÷CÇãæGŒ\¾¯£°°`NNŠï*¶ïpõ~ú2!®·\^= ±±1“–f´]­Óp¹ÜYs¶»Ý܃þ\¸xÿ©OX;3лŠq IDAT¸Þ‰ŒLêZEUŽw;/o`DD¼;ý]µµ?û%%e ´^xëÆžI“†váÄ:~ä;Â÷r²+(HÐÐPæ³ñ@¡PÔÔGŒ°ìrÿަ.—尠ÊQJJr|¶(ŠªªBór¦¦¦Øö±º¬¬Ÿ,öcˆ1˜‘ÔÔ¬=”úöíÙµ6¨Ü«Fr¹M_¬ÖiBBbûè’–-ÒN-ú%솸¸¶7ø¶¶¶~¾Ã®½{V6úôÑÅA=?ß‹™ï.ø¢iº¾vÍ,þW ÓåŸÚØÈ~ûöCjjfVVA``djj&“YOžóÉIUW×¾xñæÙ³h.—Œ´îß½ûèëÎë¬ÃË»wýü"rs‹rs‹ž +/¯"+s8œ˜çÏ_744>|LÚ!°ûž–N™<‚¯|Êäá4Z»²é`º_ÝÌ€…E/Sý††ÆÚÚú‘¶VHƒÁ|k‚(-­hj"òòKÊË««ªj¹qì¸[`PÔ²û^½JlQNª±‘íë±zíá+WÿÒÕU{Ÿ’¹Àa×-·§h¹l;jE‹‘¥¥«×>yÊ#11ÝÊÊhÊ´ÍoÞ¤°X*Êò§¬¬²´´­é›ëSÀºõG_¼|£¯¯1~ÂÚ¼üâ†vuu]óšEEÌ%Ëöž=w/55«ÿ@ä„ýúmïÞ:h7èYÔïKv£ÛsUF¡Ôõ_ÄÏ/Ây÷E[[K33ƒµëŽ&$¤À§Ìüßì7\¿ñ„Íæhk«šYÌA/+õõ¬Qci4š  ]ßp²©©þÛwP?R‹‰y¯¡¡Ü|K²_¿Þ]¾û‚ùF`3ðw4­˜˜ˆ¥¥QwσùU°µµ4°oÿþ}úôÑ1Üò}JæÌ£ƒÎõï߇”“¤Ï˜>*-=ëáÃ`YY©ùóÆ¿OÉüm¢ººÒ¸±ƒÜ=üÌÍ uuÕmm­¢£ß’¼ bffjPWÇ7ÎZAAÆÂÜðyðk)) [[+s[[+11¤OµóÏ%HŸªºº.**¹²²æÔÏ˧êêªn¿ø÷IA4¯9rd##ÝÆF¶ÝàÔ÷éAÔÕ±H3)!!Fªw€¦¦J€¯ ål›šš:‡ENH-GUUÁqÕŒy v1göXyyiii†¹¹¡¡¡–  =9ùF±Ùkkkk“=”bcß“é»ào0tíåypщ­[_߀Wí?:ø”ó3ÂåBd$ˆ‹Cß¾Ý=L P(½{iÃßò¾~Sx4"‘œÔäÉÃ)Š´”Ò©¤úN§Óh4j}=KR²!w …‚‚tP«å¤H}ª¿GTg³9ââ"Jвyy%ÊÅÅeHo»Åš@¡@ïÞÚ€´=êëøvx•öFŽäOÛÑ"±±ï9.é7§§§ž”œ‘›[¤®®D¡PH |!«ttÔ JÑÐ¥¥šš*¼½ñ)€µ1®™™ÁÃGÁAðNªªjòòJ:!¶ùïÁfóÓ‘›7ƒ…ÄÄ€…¬Z**_n…ù>àõ}ñâM‹úT°jå4׳^jjŠÊÊr«g@+JVŸ¿‚Ø?_ADD©t|%Hq‹4·ègáù5ø¿W¯^Úƒöݳ÷2•*°}Ûïææ†¼Ÿ¶_ì·‰6ÿÛæ?x°)oyHH,yùÎùu7í K" ²C^0˜ï—ü|X¹„Çaß>ðñÁƒaâD¸t êë»{r˜–á°â³jSNê_ÂPä¿y›ó)cý»Õ?å †X]«¸¸¬¤¤¼E}*ÈÍ-vvZ¶fõÌ];—¢ôt­Õä­ …"++Y_ÿc ï4Oœt'ýéZùqÌÌ ÔÔ?§ì ‰=ª¿‚‚ ß×$¯JJÊevlÿ}û¶ßçÌË×mûÀTTä]]¶,]¾¯¶öŸ'¨±‘–žò|b¾¨NNN]×.^%- Í6‡ ˆ½û®hj(KII4ÿôþýgGŽÞ<~Â->>M’!¦®®TYYóçγ{÷]~ó&Ũ·N‹ûr7w&³RK«Õ5\c#{ëÿ\–-L£ÑÔÕwï¹<|¸E;ÇO¸Í™·C¿§¯:}'X»îèÂENö“†¡”˜ÎsÙæÍƒS§àøqpp€M›@Y@@tuaÞ553==‰j„¾ˆ2móÏÃGn†…Ç÷ÑSR’k^óò•Gwïææ‹ ‘ÚÙÙ…¢=z(@nnÑž½—ãâR…… 0.((Yøû ƒÍGxxü×;ïS>IK3LM Fìèðúú†˜ØwAQg]¶Š‰‰89_ ‰­¨¨îk¬wõÚã'Þ/**ª{õÒÖÐPÞ¾ÃuÓæS§N{?áž’’9l¨9Zý³X wï¡„[°xé2‹XsŒûèõ2ÔúcÓ  DE%ûùG,Zø[wF$]ö†¥K»môî”Ça±¬,8y|#Ÿj=I``䨱Že%Ïy•+V®:èê²…ï ˆ» µ¶nq@·×®?FYïH¶mw™=kŒ‘‘.ºOõóEÖÿ"C‡/ݸaÞW:š!¯hqý+_0`µ `Ù2˜;DDZ®“Ÿ{÷“ Ó§ƒNùõÍØ±£sYmÐ9©¯¤ªª†J¥Š‰ýó?¯>•OØë˜w;¶ÿN¥RÙlNPPÔ.ç Ñ‘7›×l‘ØØ÷^w\Ó%Se2+ètÚ³Èÿo›Ëða¶¶V ¥®ŽuèðõÚZÖÑ#ë ³ `Adg¦§g÷ê¥ý-$L:–Çéݹ²JˆólÍÆÃß:0|={öhÛÆÀëΤÍ.((E©ëIª«k“ß~ m<˜˜èF¶qÛÒÌ» É…Bé’~0²í8h,/ÿöóÀt=í‘“úJ q^ÿÖ§JKÏVV–£R©@§ÓÌÌ xÌš+YñannÈå6µ±3ß!de¥¾hã %5³G%ô§RTTØÜìóÙ|§À(І†²­­U÷ÛxLéN¼ôôìózöì¡¥¥ ÑÑÉyy% Ò""Âff­î ‘¼{÷1;»ÐÈHââRûôÑEÞ¤ÅÅeÉÉ$$Dûõëšš¹fÝQ)IñøøT)) TáÁÃàaCùß-F쉴›šš˜ÌJ”â½ ÒÒ²>~Ì377ä­Y_Ïzñ"®²ª†/^qqYxxF:Ô¼ÅÒ'4ôM)³b@c´¿GDZZVì›m-UÒ6""ɬ5ªjjVNNÑÀÆßN¤óGâÑ#psƒI“`ýz9¨zσ_3™•5Õu¡/Þèêª÷·úìX>jdÿK—•–– úø†çåϘ1 -‹ÝÜ}ZÔ»(*bžq½“𖥦ªh` ©¬,wùê#aaA …‚RDШԘØwC›ñMfÄð~::jðüùëÝ{/­\1­5·X?¿CC­Ô´¬´Ô¬ ïŸ:¹QCC† ³ððôÏÌÌÏÉ)r={÷ø± ::êT*µE] $ R^^ejj0`€qEEõ¯‡ëðʲ_o55ÅOŸò#"›¸MѯßöÔë‘0ØÚôÚõÇ-ªa|1.àgke|?tPƒé ø‘ïÝ)ó¯–lš“S$//-*ú¯`‚ 23ó?~ÌëÛ·§œœT':G "eÉmóI“ÿðñ>MVhjj²µ2Ðßµm·;>X¬†ªªÚæòUuu¬êêZÅfG_Ôµàp8EEe**ò¤oACC#“Y©¬,G¡PØlŸ„æ3X+ãûÁ¢Ëåq0~ð#ß¾³ä&К˜ …¢¥¥Šbë;…Báu­¤Ïœ1*<<~РÏ~v¾¾ ì:dã@XX”ó!**Ì÷¦‚ ½ðZƒF£ñ†Ú€ é ‹m<ƒÁ`:Ê/ªï=oîøÇO^”•U@^^qг¨ysÇw÷¤0 ƒéb~Q3O¡Pv;/ÏÈÈ€OŸò\óE] ƒÁ`~8~Ý}`!!A¤ñÅy ƒÁ`~P~ÑÕ<ƒÁ`0¿ØÌc0 óÓ‚Í|»(,, ˆür½v@DII9’ì%‚ÃáÀ¯6›ó¥¦-PSSGŠà¢®0 ƒ!ùQÍü¥Ë zM¹yË»ÅO‹Š˜»œÎ·m8CCcÛ,F"²mÓØÈvÞ}iÈÓNÎõorr :íÛå©Oرãnnî>W®þåë;îÖþ®‚¸|åÑ’¥{oÜôvs÷Ý·ÿJZZÖ§¯œ!ƒÁ`~2~T¼%‹íý^ñ È_»þ˜Lm—›[|ïþ³µkfÉÈH¶ÖƒùŒé###“¾8–“ó…U+§µ"ß~""æ-Øè節ý9·MRRÆ@ë…·nìuu%qq‘°°øöø1sÖÿTU.^ØŽššš/Ùóö݇¯™!ƒÁ`~>~ÔÕ<ód)((ÿ'‰»¹¹áÛ¤»mØøÏ=´ÃrWW×&¿ý`d¤Ûéy@mmý|‡]{÷¬ m<ô飻jåtòvÞÜñ{ö]þ?{ç×DÖÅá›FBïB(‚(»îÚEׂŠuÝËîbì îêª Š¢`é "Ezé„’FHy? ÎfÓË‹ežŸ&7wΜ¹˜Ü̽çüÏ@¬]úû^IiÕ±£›á$@4}úÔÏåp†òi¾´´ª®®ÙÂÂÇã½zUigg®®®L§3ÓÒ uu5FÈÈ(jo§:9UT”ËÎ.im퀺ñÛ)/¯Ù²í„’¢\AA¹’’¼¾¾VvvIKK‡³³•¼¼lQQ‰Ô2fÌHQUE²±1–§­­mâp¸½½½ššjŠŠru(JQQN]]ùÞý$W[þÎÍÍmii…ÞÃËí@&“ÕÛÛ+//+òNïÞ{ÚÜÜ6ÞdöùóÜÈävèXQQ‡Ã¶µuB‚¾ †®]3Ò „QT”›æ9^âx# |w åÓ|[[çæ­AÁEE•ööžÓ7ß»÷,11ËÎn”ï–ÀØØt@Ee×ìmõõÍ€ÆÆÖù•—× Øa0XDM5V»­­“Fcêëɳçî€fÐÖÖŸG}·ÔדõõµV¯9pãfŒ€2™²tù¾ ›ŽAëC¯EmØt´¥¥šZ`5Öî™–Và·;hÎ4å:Ùª* ðÙpdÑ’=âî4'絞Q`bØÙ™{yM„_ê<}–%Ù …ÒY]Óhd¤+ü–ÿëÅ9€€€€€ð}2”Ó¼³³µµ•)•ʘ1ÃIMMÉÑÁâVDüœ9.**ŠÆÆÅgV,÷RV’‡úÏžíUÀÚÚÔÈHGWGÃÝÝaôh#À¼ynýì“'Û›™éÏãêîî`ffp!ÈÏgц2¿{{‹Ã766¶BëZ·ÃBEîHd~=ü¾>ž²²<ƒ™6m›ÍILÌ„Úÿø}݉Àmâî´»»‹}¿`>‘¨F"µH6Èb±ØAÊï# |Ÿ ñÞ< …25Շޥ¥ ¦&ÿww÷@ÇüÁ—¤è ×}>\SSS5ùy®@ÿÉ“íÑhTBBf__Þ ïëS(]¿{Þ'Z-[:= 0䯋wèt&õ]2›¡¡Ž™™8g¬­MI¤Váb€T*ýõëjø¥ŠŠbW]²A--õaêÊ $²ð[YYÅâ@@@@@ø>ú<4%òX$\n¯ä))yï½"“É’—“hD¡P¾›~<t+11kêG¸]EENgÂ/CBïý-xㆅ>ëhjª u~ÉÌž5‰ËíMM-hONÎåÿC§3ùWD‚B¡V®ðzð0YøGCZzá{=A@@°TF|üKhÿá+eˆ§yOWÇpYh¥šNgÖÔ4ööö¾ëóo79&“(}]%l @¡tA99¥h4ÚÅÅö]ŸY±|FzzaRrÿc´áÆÆ6øåù ÛÞ+gÊËËòx<©µ¯v#ðâE~\\†¸ÛÔÒRÚµÎç0ƒÑ 7²Ùœ7u#Fü[`·®®Yç]!Z ì÷imí¼úÏCþÆØØôIÎ6â@@ø2‘,qqòTØÜù;§zn  9söæ±€ŸÖpq[ím…݈NJzOÑñHhÃ/•áâbxüÚÀµ§ž ”ðÚïGÀ¶ãAæÅOg°Ÿ®.:“É"Õ[¥¥ñŠŠrh´à:Ç#“)ªÂû÷žÓ}½WΜ3Û…JegÓñ|!bƒÏ~ãl6gμŸ££ÎÁ-}}}$R ‘¨†Åb9.¼ë?x<^]]sEEݨQ#´´Ôùߪ¯oöÛt#ìÐÀ­1™¬ÂÂ78ÖÒÒX8Œÿ;Âa=ÈyÏSÂÿ [ÛOû à¿ÿbÔ“9YÿjD’É”˜Øtï•3?ÀÚÆMÇì÷rVÅA£1–.ß÷èÁiþF7wŸ¨Ggdd¹Ê±€¶¶ÎÇÅÆäeË÷¹¸Ø®ùiÎGÚùA>òƒáëPÁST”ST”Lü P(qÛ—Ãáxqz8þm9ÚØÑÑBUUQà„”nÑSÓÒ &¼{ÊG£ÑººšÐñ æxÈI==¢žQø­ËWìÛûÓ ¬ÉÈƳÔ)_ü€¬¬b©uØ0eii‚ðêÔ›1sç¸jh¨Ž¶0jii/.~+//cggN£1òóË9®‹‹Í‹ù½½}“&YCš°}™pùʃ… Ü••åMMõ¡oƒÚڦ̬beWW[ –ÊLâÿrÎ@__…Ò% Þ! ™LÉË+9R??¨»›•’’ßE¥O?FûÝ ¥¥=-­‹Å¸¸ØˆTËàr¹ÏŸçµQ:Ç9Z® àñxoÞÔææ•0Ðvt uƒÅHùùå£Géëk½ÿÏ€ðM3ô!xŸ›ÐÇx¼TRRNvv‰¸>VcM^—Uß»Ÿ­À °|ÙŒGSÚÛ»>Ÿ“ññ/uu5%Äê# |“ðK\år{çÎuUR’?~âÜ‡Íæ64ËÊj®þóªùdccÆ`tÿqö\8€ÍæÄĦûn ¼ô÷}CCÚº¦ÅK÷ Øg±ØZDu.—ÛÞÞÕÖÖÙÛÛ¸äèÕY3 ü‹ü ¥M© S}(ÅúØÐx6$$’´ô‚ôô"[ÛQ÷$mßq²\]Mò^åob¢çé1îò•°€Gllúþ—ÜÝí­­M·n;QXøFÀƒÑí5k›‚‚쬙Î{ö½x‘8~âÚó”¼ys]3·ï8 õ„ÄHΜ /*ªpp°˜¿ð×¼¼²AÿU¾-¾ýiÞ{åÌè¨sW¯üagg.®Ï̙λýVmܰPx/€B¡ì÷©¬¬ÿ|NâpXdiá;„_â"ùy.©±•Ëåš›Âõ)t:35­ 5­€Dj… ´==úeUU•V,ŸQV^3o®«®®æ4Ï 11iö•”äÝÝÐhô¤I6îî²²Ò´uëÿþÛZïä4–Fcff!© "QÔØ¯i1Þäè¨s‰Ú¦&ús纪«+ïüyùËÌW÷î=lÚ°x‘§¾¾–‚‚ܞݫwùkh ÓéLïÕþöûÈËËjkóÝôãò•¿ ì¥ÕÕÑ´³3—–&lܰððÑ+‚”Ž@Àÿ¼cÙÙsáPx/$FÂd²¦Ow6LÅÖÆìYRö ÿ&ß_Ç¢ýƒÇKÙÛ[|>û’Ⱦaà`šßö®Y´dÏšµ­Žö…;¨¨(,úÑ ØÆ…ƒB¡”•ä54TÒÒx(7G¸?¹¹¯ÙlNRrÿ¯±‘./ •ûkZ(*ʽ·Ä k³˜Øô™3³mq8¬††jRrÎp]M.·WUµ?\ÀØX÷UqeCÞŒúúæ­ÛN””¼%“ÛŸfUW“²³K›šÚ,, «ªH••uÆÆÃhª»›µï· ‰‰™--Eii…x)Ü_ﺹÙ}Œ‡ß&—£ÀºuCí€K—þ 8xèrâÓ,*•1ÑiìýIJÆ|ž’gd¤ëè0úÄÉë÷î'ÕÔ4ÒhL6›Ã_±)-­à|ðíò7µ:Ú22„C‡¯¾ééᘙéï?p©èU%ƒÑíè8: 0¶/-g2YE¯^UþøãTYYé©SŸ¸Î`t——×TTÔM›6€Å`rrK'Zóûy3®­kÒÑÖYìê+ùȆ¡Ì›g±zÆ­ucB\°ä°;úúúššÚˆD5_L&‹FchmP(8VAANœA.—K&·ki©ÃK==l ¥‹HTC¡PƒÕðøºA>òƒa(í |aþ­!Ÿãi4FqÉÛœãŒîÞ:¸žã£GmÚøür¦—sPpÄ@¬ùnœèdÏñyyÙã[?ÆC„/))ÖÓ#~¾9   Ç?ÇTU•äøŠ\ÀRpKLLº÷J¯AÍñ4­­=Lø‰_F† <ÇCnH˜ãX,V[{ÿ¶/ÏúßÑ0H†r𝍍‹‹Ë¨®&JK«bcÓÈ äÇSjj FwYYÍÛ· oß6ÚÛ»**êÊÊj ÓóóËn†Çæç—¸\nZZATÔ —‘QÔÜÜõŠzy'1?¿¬£ƒ*|„°FssÛÝ»OŸ‰N52™óêU% «‹>mÆ( tûŽ“™YÅ‹~œš˜yêtJ_W/øá×°Ñ/‹–¯ü½£ƒê·û¼‡Ç¸9³]‚‚#jk›„Ï‚ÜPÃHK+ðÛ4gŽ r쾬l–ž:}Cܽää¼ÖÓ# +ÎÚÙ™{yM„Ž¥¤pT*ƒL¦H6˜“S ÞKÃã¥vû­ØÐ" |8üRÕÕǶ ¼6—ÆPNóÖVýz–"U””äÞ±ÌÑÁzªÖÕÕØ´qáÆ “’r¢ž¼ðY¿FïØ¾ôX@ Ö®™‹B¡ˆšj›}…];XQQ÷¦¢®­­‡Ãþ²s…ŠŠ¢ðYY5Œ¾>ž²²<ƒ™6m›ÍILÌ„Ú#n[½j–ÐMôÓÝÝ?µK€HTƒ%>Äìfõb á3Ke89ý® F |ý ñvÿOdqª|ÿ¹`û“'©³fNØÉSa©i F÷d7;<^ŠÅbWTÔ½­j¸qý¶ö°°ÑÚZÃÄeäþ}ùþÉSa{v¯Z±ÜK ýÔé»ý¼ùÛ¹ÅÒ›šê9z•HTã¯+²²š_va2YOþÄm ñüyî¾ßÿefpñ¯½cA˜¡”ÇÝÝ,iéÿdÓòx¼¦¦6uue‘_ƒAÓhL:É/(!|–H5 ©…HTÃb±ƒàñxuuÍu£FÐÒRç+üVlg'}ƒÏ‚[£P: +´µÕ‡J²ûûÑÊør¤Í*((§RéÑÑ©" ™æø¯Æç€Áèžâî0fÌÈÏdá+¥¾ž<{î2¹x<”Ëí;×UIIþø‰kp6›ÛÐ@.+«¹úÏChµ±1c0ºƒÿŒ8{.ês;"þÈÑ«³f:øù ©Û¶ýÄ£Ç)Ö֦ϟçeeÃo¥gú`ššêǽ«WYUÕ ¡5•ÿ÷„0$Rë›1†MMmsçï„’fÙlÎJï?X,ö‚ù“K_Wíüå äUu5É{•¿‰‰ž§Ç¸ËWܸ#lPXÈK¤lÎ<{>üðÑ«wî>µ·· ¾|a@rÚßÈ4߬†ñ9••Fá„™7ÏMCC:N~žKjlår¹ææ†«¼ÿUŽ¢Ó™©i©i°´ÀÀ@ÛÓc íí]==lè ¥¹/ðð1@8.…Ò }ñÓC@øŠ€U­üöœçp¸––Æûý}ôõµ¸Ü^èݾ¾þFóOó°–¥¥ñȑÓ“s¡öââÊ’’·€O}ké’iÏSò c×@jÃô uÿÝ €èì¤)(ÈBÇ==ìÓgnÀA‚"ioï‚ >{–½bù À²¥Ó_¤öW³íëëKM+XºÄƒÁ,^äñ"5j'“)T÷Éöü·#RÈKœl—€ÂØ€Fá;ãïïÿé¬õ‚KWÀZÁ ªÿgx<Þ¡ÃWôõˆJJòŸÄàƒOóœ .¯w€tw³öýv!11³¥¥##£(-­/…ûëâ]77;EÙ‹—î99¸µ´´¿ÝçȵµM11iX fßoNqwÀ‹É úƹÖ­j'\º4¨o€ƒ‡.'>Í¢RÆÞD¡tÑiÌç)yFFºŽ£Oœ¼~ï~RMM#Æd³9üeÓÒ Îß.S«£­an>bêÇã'®3Ýåå5uÓ¦M¸{3<¦¾¾Ùp„Ž»»ƒÑ}ïÞ3@Ô“Ôüü²ü‚ò‘ÆÃõõµtu†]øëÎ’Åžü^¥§¡ÑèÉnö€¦¦ÖU?˜5ÓyØ0‘·ÐÐЂF£+ßÖwuÒÃoÅÊÈHC«£GÕÕ5GǤ1¬ F.\àî5c"ÀÕÕ6üV\MMc}=9øBä©“; u¡Ûy]V­¬¬0ÉÙf옑GŽþx -½PYIÞÔÔ ··7"2AIQ>6.Ýi˜ÇQ)VV&ô àÛee5ŠŠr½½}§ÏÞ()©’““¶±1û€?Ý×ò‘ _<Ždþ yÇì°X=ãVž9µSœ<Öí@Hg|JçÄIkŽò3Çj¡ÑãVOv³;sz' (øöØ1&œéÏÝŠ¼“$#ÓŸžz-Ê{µG[Ò§úeó•he|9 R‡6›ƒÅbêëÉêêÊðÿíAA¡tâñRÙq0\.Ú‰'“)X,FIIZ–ÿq‘ß…`?UU%¸çzŸÃÛ¶.+N ææ6Erv\.·¹™¢¥¥.°´Îd²h4†pXŒ°×ÇÈv}k ùÁð-,Ú75µ¼_øÂü[0Çóx<á8Õà?# %¸ÁwsàD'+xŽÈËËØ ¿\¾lÆÁ×bêիʽû.„þ³Ÿÿ{pÅòH$?ÂWŽ”Fëé?lލª*‰›ãX,šV54TUU•à­÷ýþ>¡×¢àn--íRR¸ÁÎñMM5á’µX,VGGCxû\F† aŽøçrH¶ ‹Å‚ÁËv!|Ï ý4_UÕðäIjss‡Ã}û¶‘QôäI*”{š]ÚÚÚu–›(/¯ñ^íßÜÜVPP^SÓ¨¨¨‹‹Ë¨®&Á—šHO/|ü8¥§‡]TTñäIjGÐÚÚ±Ëï\nîë‚‚r¸fŒ°tÎŒy;"ž_Kúa.îëêšoEÄ{¯\Étuµ…?犊r8¶­­ó½OŸ¹1nœ¥6# …úa¡»Èú~’15Õ———ÍÊ*p8Ü}¿]8rxÓP;…€ðÉÊižÇãmò=váÏ;ffúQORÿðÿ J‰©¨¬óš½­¾¾ÐØØúÃ"¿òòZ Fn‚Á`5ÕX=ì¶¶N ho§nÛqòé³lè*ÂBÕ5³çî }ÌápGŒÐ¶¶]ÊbõÐéL"Q­···­­³½ + ÑÕE÷œ¾ÙÉiìˑӽ¶B?J>Ž,Z²GÜmB¯ø·!ðx©Ý~«à—F†:OŸe½×`Nîk#CáöÛ—!…m>ŒµkæBÑï••õöûÈË˵GŸŒ¡œæÿ yô2³øxàÖ#t~Z=ûÑã¨}År/åw{̳g»¾›ÕDÊMX[›éèêh¸»;@Ú,¬­L¡SD M,]2M]]YYYÁÆÆÌÌÌ@J W\üÖÀ@ÛÎÖ\NNÆÝÝÁÙÙ:]@:ƒË媫+LMõ'9[_¼tjÿã÷u'·‰»ÍnV‹}Or‘¨+_J0ØÝÍ‚Ví>!PdŒ™™¦¦ÚPû‚€ð)Ê ãqÔ W[(C…BÙXÿʿŧЈ”›˜'ª;œt#Rhʲ5}§„%-g±Ø"=ÎPUU:wfçÅKwq8lEeÝ0õþÈ[CQ×0Ðoކ†ee·²²Šau<EX K‚Ak+ÓY¸=?¿ÌÂÂÙ±C@@@@àg(Ÿæ x)þloqe¡ôY Fn‚¿gJJžÀ¹°Ðô/òv‹.a'ûÍ›Úææ6 $‘Ÿ_6cæ¶Y3'ùnúÑj¬)€Åêyoª‚‰‰žƒ½Åƒ‡ÉíÔ’Ò*ø%ÎÈcÄÊ^ÏžeC ü$?ÏEæx„o×ÚÚiÚóx¼ïP(¢¹¹->þ% >þå@ªé @ å4¿tÉ´¸ø—Ð綯¯¯¸äß"N ²Ð6ά©i„¤'DÊMä˜L ôuÿ¬ KFˆš|J€OSBAA²STTEá Hg„݈?ÎzÔ&‘ZúúúÂoÅõöö¾x‘—!î6Ñhtè?þçƒnÁ‘}ï¬Eó/NÔÕ5ëhƒŽ%œ>ÝiáwßÍüµµMâ’z¾dÈdÊþI–‡ª¯oö^åøÈ•'Ñ©'O……݈¾rõaLÌ×'ÞÎãñº\[Ûôç²Ùœýþvv¶¸¸Ø¿6ð:§N‡0šûÑr÷[·ÐÔš Ç$!|- åóŸ—×Īj’ïæÀY3ËßÔògÑü²sÅõ°hY[×dnnx,0D]]yé’i­{÷;:ŒNHÌüyÇ2¨BüœÙ.wî&†ßŠ…¤o†Çfç”´¶uØÛ™32ìÚÁM¾s縶wPµˆjRR8ÿýéôî'¯ÿñûÚû’ëêš/ü©ªª8j”©©þå+ÈdÊ‚ü™6 æOÞ²íxDdÆpŸlòt˜©©>‹½ÿ ©½êá1NÜš˜è¿LùÕïÜ8GËÉnvT*#;§ÔÓcÐ\éëjÿ?ÖCÇ’ þõçž Fþ°ÈoÍê9ZZj¹ye½½½+Wx}Ôa(hhh¹s÷éÖ-‹ÅÉO¥§._ù{B\ðˆý;Y¯^UŽwZu=ôàÿÑMAH¤–’’ª©Sߣuþ+ÅÑÓþs7ÑiÂX==â`¯è¿ÿ⦠¡¯8))ܲ¥ÓNœ óÛå=swl_öèq ¼,úÁœ9ýó›1ˆÖÞWÇÐËãp¹\2¹]KK}ñ’=îîk~šµwuÑ™L‘¨ÖØØ*-WT”ƒrOEÊMðx<2™¢¡¡*rå_XhB­­ÊÊòp˜›°tFss›‚‚œŒ á*(”Πmmucãáüþ××7ûíºvhস\nYY …Òeeeò½ÇØ#Z_!# ƒÑ=ÆjñÁ>‹ýG¥Îo÷yG‡ÑüBÿg""Ð(ô0 ¦¦¶c!gÏìüÈËÑhŒ¥Ë÷=zpš¿ÑÍÝ'êÑ™j xN÷õÝø£—×ÄôDgø´äg—„ó†þß ùÁ0ô»¹X,V[{€Ãåò¯Ý)*Ê)*Ê´´ÔúëèhA¡P6¶!¡‰úÅÒÃ@Ò;¶/ƒ[à }À^¸ªª’››pûå+öíýiP¦°X¬……Ñ`@@ø¢ÈÎ.iiépv¶‚rز²ŠI¤ÖaÔ¥¥ ÖÖ¦wï=mnn›?o²ÀYóç¹A%ê--íii…X,ÆÅÅ2’ž^H¡tMêXVVÓÚÚ1~üBSS[nîk[[3èó[ZZUW×laaÈãñ^½ª´³3WWW¦Ó™ii…ºº£F¼~]]W×lh¨cd¤[QQW]ݨ««affðüyî/¿žõÝôCAA¹ŽŽ†šš ¹¹--­@À{x8B åå5[¶PR”+((WR’××ת¨¨«ª"9ÜÀ@»´´ —êéa›˜èõööUU‘Ðh”¶ö0YYéÚڦ̬beWW[h÷ðÞý$WA½¯©Sãã_B¿uúúú(”.ï.aÞ¼©­ª"ÙØ˜ñ÷ìîf¥¤äwQéÆÑ~·o(r`àr¹ÏŸçµQ:Ç9Z® àñxoÞÔææ•0Ðvt uƒ‡Ÿ_>z´‘¾¾–d?>-C/qãf ›ÍÉÈ(JO/j_þ¿tÆg">þ¥®®æ¨n! |íÔדgÏÝÍÙÇC¹ÜÞ¹s]•”䟸ÈÉy­§G––³³3‡LccÓ÷¸äînommºuÛ‰ÂÂ7à0Æõ°h‡«§G´¶]úömØ1Ǝ㽡൶¶ÎÍ[ƒ‚#ŠŠ*íí-<§o¾wïYbb–Ý(ß-Ð6vs3e£ï±Ø¸t@{;uϾ »÷ž¸Ü^ÙÖÖ ~MK+ðÛ4gŽ rìI–ôxýºÚÖ~Ù•«y<—Û»uû‰óA·{zØ·#â½:k¦3€ÿa‘´ÚššZ`%TðÞÔD?.¾?‚'$ô±¡ñl¸|ŽHnÜŒio§ZXúí>3¼¿Wu5É{•¿‰‰ž§Ç¸ËWܸµ‹X~Œn¯YÛdgÍtÞ³7èÅ‹|Àñמ§ä͛뚘¹}ÇI¨'4ÔgΆU88XÌ_øk^^Ù@þo |*¾”i~é’iž¹z`üø1Cí‹ °tÆg‡ÃÂ[ßóæ¹ihôG&?Ï%5¶r¹\ssCh?»»»G‚àÎô^í©ÙhkóÝôãò•¿óx0"#ÕSRòœ­CBߺy;@^\_šl IDAT^6òN"€Åê¢âù» œk` íä4özX4‚2e å®%‹=¡øÜeK§C=UTø< èt¦¦Äâ7`³9òr2 ‡Ãò/UBb$’BIIÎÒÒöbíºCêêʇnÀ`0ë}óRqcùRí¿v^¾|U^^óILq8\ ¥Z"ƒRc™LT*ûhoïêéé×øûE¾|xïT,üöœçp¸––Æûý}ôõµ¸Ü^--õà ]ë|CË¿l6çME݈ÚÖÖ¦::ÊŠ* öää\©Ž€Ä…1ÿ±ðu…á>°€ ¤´ª··ngvÿ«Õq>è¶÷Ê™òò²<Djíëã…݈%= 6¬_|!‚ÃáJK––Æ#GONÎ…Þ-.®,)y 0¡ÓØØ&0nuuÍp0rmmÓ¥¿ïIg¸X]]sOÇÅŃÁ,^äñ"5j'“)T÷ÉöïX`år¯'Ñ©ð½DD&P©ô+ÿ<ܺeƒijjëãñàqøïðJváÓƒñ÷÷ÿtÖzÁ¥+`­`)¶¡‚Çã:|E_8À*ìÏŸç®ðþýåËW3½œu¡êjRDdÂÂ…S>ÈÍIK+ðÛ}¾¡\[Û“†Å`öýöçw99™ª*Ree±ñðšêîfíûíBbbfKKGFFQZZ!^ ÷×Å»"ãü¿z.Guë†Ú —. êàà¡Ë‰O³¨TÆD§±÷$Q(]tóyJž‘‘®£Ãh€åhãQf?ÿr€F£23‹cãÒW¯š--MÀ`0S§8†vw÷ää–&$f^ò“••öß199·³“6ÆÒ8ôZÔ£GÏ[Û:ÌGxð0ùÎÄ–ÖŽ‘ÆÃŸ%e‡ßŠkh ëëi¾ù'äQUIG{XuuãÅKw«ªHÃTÌÌ tt†…„>Ö"ª½HÍïè ÆÅgè 'Ž©''+sëvÎ45Ñ×Ó#öööFD&()ÊÇÆ¥;Mó8*ÅÊÊĈHT»|õ …B¡ÆŽ5¹{3<¦±±Õr´1T,ÃÐPûì¹pÿ?ÖC² zêÇã'®3Ýåå5uÓ¦M`1˜œÜRç‰ÿY¸;ÙÍRëzö,ûÀ¡¿7nX(\ñ"66ÝÌÌ üMí›òÚ‹—îž=³ÊÝwuµ ¿WSÓX_O¾yêäCC]q ý±::¨VV¦ãÆYvvÒnGÄs¹½qñövæ::ÕÕééE}½}YÙ%#‡§§Nt²z‘šu~~YHèãÚº&mÊÊC>òƒaèóæ?,Vø•gNíøæ÷_臘„]Dþzooïâ¥{îŽçƒnEÞIŒ‚aC¯Ey¯öïhK‚~¦lò=v`¿¿8(”Ή“Ö9ä 'ÓhŒñN«'»Ù9ý±)¼_"Hí—ÃGäͳÙ,S_OVWWHçñxuuÍu£FNŽ¥P:q8ìgR`±zÈäv]]ŽjooŸŠŠ”/Çáp©T:üyìëë#‘ZˆD5,˯¨!YÒÐÝÍ‚åî—‚K`³Ùœ9ó~ŽŽ:wèëësŸº1!.XrØð½P© aÅL¨òµ†ÐÀ{V=ï®§‡M¡t‰j(ê”E ò‘ ßò¢=€/Ì¿5¨7þí´’œœk9Úè#çøW¯*÷î»úÏ~þo·Ëg8¼+l˜éå1k¾›':Yñ‹‡ÈËËØú1" |n¤¤ph4ZO(,ù‚B¡ôôˆîî"0TU•>ŸB€×Ó#¢ÑhUU¥aÃT`á,Ëÿ›FëêjBïòÏm¤‡¸9 <ÇTU•à9 %…[ôãÔ´´¸%&&Ý{¥× æxè^DªbËÈ„çx0€…TOøï—‚g}¤ÊÆÂPNóEEÑÑ©JgEE¬÷ÞÙI{ôèùÇÉ=‰ÔòôiVAA9ƈŽN­¬¬‡ªV¤¦¤¦ðo§•—×Ü }ùòl¿¢¢...£ºš(-­ŠMoh 74?N©©iä÷„B錋˨ªÔj®­mŠˆLHLÌ„RE:v#zÆt'ø‘ž$—š8}æÆ¸q–Úü(ꇅîp芛›\òYdšl]]ó­ˆxï•‚ §®®¶"?É_>Ë—Íxô8¥½½ @"µ$>Í\¾lÆP;…ðu0”Ó<™LY»þÐ…?ï”—×:Ž÷f³9%%o—.ßçà`ak;jþÂ_ÛÚ:étæÙóáGýy'ÑÁÁ"ðxèÙsá¡×¢LLô¢cR÷î †L‰”e࣠ÑpízÔþMMõÛÚ:oÝŽƒÝÖ©v•]bnnŸ%Ò“ªª ­©ÙÙ%â†"'÷µ‘¨â³;¶/ƒMKIá¨T™L^ZÙ,=uú†S9¥á}/<^j·ß*q |É P¨û}*+ëÕÕǶHX!@@àg(§ù)S-,ŒØlŽ—×Äò×÷¤¤p}-Yì©¡¡ª­=ÌÕÅöò•&&úÓ<'—¼]å=KUUiÊÇc!Þ+gª«+OqwŒyWsI¤,¿…8‰†²²š_~={òÄv==¢½½Å4Ï PÿÎNš°N…°Ã<Édñ¯Ø‹ôD__+>&h¬ŽLw7 ^ ”‘¨F"õWÌ‹¸ulõªY"L±zDE¾Fðx){{ €“ÓØÜ%Dø®â½ ˜›hkëéa§¥Nqw€$¸Ü^UU9¨‰‰ôÓUš€9r8´#%-ïîî—Y/ËÀ- qñFFºpJ(¬ !N§‚ßa@w·`½y‘ž Ñè)S$³²¶2m ‘…ÛóóË,,Œà-.eEX–Œ6hhhQVVx++«Øžo³á›gèC$ädû#Mp8HôÑÑÁAp*âÏ™1"A–á¿v—¹)‘¹ât*øHKãD3è‰+Wx-]¾¯«‹UëI~žkõnA@g0¡< ˜˜è9Ø[ôrͺƒÃ†©Xó=ëè©)ÍŸç¶÷· õõdiü›7uwî>âîÀ/IýMhe|9 R‡L¦?qÍiÂX æ=!Ï’rÜÝ>οOã Ì`5¸øa³9~»ƒÖ¯›‡Åbuu5¼ìæf+NßF€S§Ã–.ßg2Rï#K¿oÝvbÕjÿ¹s\UT÷ø¾hü`øåq˜LƒÑýÞÚÉ|Œ,Çkn¦hh¨ÐhÌîn–ŠŠ"á" S!LnîëˆÈ„€wå>Ò.—[VVC¡tYY™d¬†ßŠíì¤oðY0pkJgaa…¶¶º±ñð~}|• Z_ƒ”ÇÉÍ}½Âû÷Ï/C2pâàñxŽã½«£>ßÿä:óOÈ#¨€ø .˜={ƒ–,ö´°èß\+((ËðÛå=ÀÓ]ÜÖíܱ*ÈûÁðxá%¤?„kÖ}(ê“ØAø’ú¼o€ßö­9pðï€c[>ßlz, dë–Å"³¾^²³KZZ:œ­äåeYYÅ$Rë°aÊÒÒkë7¤R^äíüyy赨ëaOøë2p¹Ü¤¤œÎ.úHãáx¼”©©~{{WzzQ7«ÇÈPG__ Ê7iiiOK+Äb1..6Ð… *+ë_f¾2Ðײµ…ÇK 8ÓÜÜ––VH à=<¡|×òòš-ÛN()Ê”+)ÉëëkUTÔUU‘FŽn` ]ZZ…ÇKõô°MLôz{ûªªHh4J[{˜¬¬tmmSfV±Š²‚««-”(tï~’«‹àƒ©Sãã_Bú•}}}J×{xÞ¼©­ª"ÙØ˜ñ÷ìîf¥¤äwQéÆr‚ Äÿx>ž×Féçh mDòx¼7ojsóÊFhÃÙ=¥¥Uuu͆€üüòÑ£ôõµ$û‰0„ yŸEE¹íÛ–VW7¾¿ëÁ`tOqw3fäg²€0TÔדgÏÝÕw<ÊåöÎ몤$üÄ5¸¤uF£—-~÷Þ3þçÝõ>G¬­MÌŸœ—_—ÞÑAõÛ}ÞÃcÜœÙ.AÁµµM€ØØôý.¹»Û[[›nÝv¢°°ÿYüä©°3goΞ5‰ËíõšµMÀ™´´¿ÝAs渠Ñ(×É>ƒÁ"jª±zØmm4üWƒëõëj[ûeW®>äñx\nïÖí'ÎÝîéa mRS ¬„„4LMôãâ3 ãÐdžƳE*]ÂܸÓÞNµ°0ôÛ}þfx,ÔX]Mò^åob¢çé1îò•7nÆ@íâÆ†ÁèöšµMAAvÖLç={ƒ^¼Èbô¾$¨!| Óü§AKKÝP”ŒÝ'AVVI„Cø&™7ÏMC£?.5ùy.©±•Ëåš››߀¸¸ Oñ€Ù³&õõõ=|” µóx¼¤äœúz2`ÙÒéc,GVTÔ½©¨kkëÄá°¿ì\¡¢¢H§3½WûØï#//«­=ÌwÓËWþÎãñŠŠ*޽zž²²<ƒ™6m›ÍILÌX[›éèêh¸»;@ «ü\óçOöY¿ §‡ÅB¹ÁçÎþ‚F£……¶ $²¦¦šÀh‰j¤Æ–~kó&GG“¬Zïé9ÞÑq´ŽŽÆ©“;|744›6,^䩯¯¥  ·g÷ê]~çÈâÆßZàñP]M;;siiÂÆ ½Äè}‰SCø2Aí†X´õ·½k-Ù³fíAgg«£‡}áIÉ9åoj£cÒ£F¸½x‘'t¢ß.o'矔”ägLw:zÄWII~¤ñp]½é&&zË–NßõëÊ/ò¹Ü^¸ÆŒ±±î«âʆòÓgY††:Ð.ØÈ‘zGø 83q¢•Œ ! 0DQQŽNgRÅçòñkp­[;×ÊféÑ#¾ F7 #Nh‹BéÞWQQ€“{圜ÆJ:XÎKQQNKK=ùyî §$&f¾‹Æá°ªIÉ9Ãu5EŽöͳ¤œáºš:ƒÑ­7œ$)‰PCø2A¦y„/UUÅê·Š‹ßÞ½÷tîüoÊî£P¨®.º‘‘îÆ ¡>6ÖfS<6B¥]y<ž«‹-¥õYFFÑß—ìøùôÑ#¾'Ol Øš˜˜yâT‘¨fj¢Ïfsx<4Ckïx¼”¬¬4‹Å–àLHèã[·ã"oÈËËFÞIB:W))yÎÎÖgh;9½F£V®ðâ…¶TTèt¦Àét:SóCëK±Ùy9 ÃaÙl.;/…ÇK‰~ JJr––FüR`@¢Þ—°Ú— ²h€€0”ÀºU~{Îs8\KKãýþ>úúZ¾dØè™|9c“&Ykjª†ßŠôööþ²ë,/åâbûÏÕ?›ZKJÞ^¹úPII~Á÷£‡}kk›¬­Mut†U@§''çzLu6LÅkÆÄææ¶úúf¨ýîݧÐÌ;s>è¶÷Ê™òò²<Dj…·ä à€Ò×UïüÿdÖ†õ ‚/Dp8\h©@œÐ–áÆÆ6¡¨«kÖÑÑ€Žkk›.ý}Oòе¶vÀ'öôp\\l1ÌâE/Ró¡v2™ÒÑAuŸl/nøoyår¯'Ñ©ð½DD&HT¡6†ðe2”ò8ŸD+ãËaò8]N|šE¥2&:½ÿ ‰Bé¢Ó˜ÏSòŒŒtííÌ7o ¼ðgdeeýôéNPnjð…ˆ—™¯²²Kh4†½½ù©Ó7¤¤°ô»÷žþ¸p* …м›hnj‹‹Ïظa¡²²ÂÔ)Ž¡ÝÝ=9¹¥ ‰™‚üde¥ååeíí̺,…Ã¥¼È#ð–£ùÁá°‘ JŠò±qéNÆ<ŽJ±²2±°0"Õ._}@ H¡P¨±cMn†ÇÂ\µ¡¡öÙsáþ¬‡ó0´°Ð‹Áää–:OüÏzÀÍðØÉnvP”ϳgÙý½qÃBqù;±±éffåojß”×^¼t÷ì™zzD€««mø­¸ššÆúzrð…ÈS'wêb0‘ãÝrGÕÊÊtÜ8ËÎNÚíˆx.·7.>ÃÞÎ\GGC¤Þ׋Ô|‘jcÿ¿ä{ä#?¾Dy„Áhe|9 R‡(¢¾¾ž¬®®,#3 ÜQh!º¹™¢¥¥ŽÃa9.ƒ¦Ñ˜t:Ö®€ P:q8¬€ÇkjjSWW©oÑ××G"µ‰jX,–_ç ªI­¡¡*®lw7K8÷U@h‹ÍæÌ™÷stÔ9þ˹Oݘ,9ìN«‡JeËk2™,¡!´ røár¹dr;ÿè}ŒÞ×çùȆ/à†€€€$K=’~Ø)Ð ¤¨('P GŸñƒB¡´´ÔÅG£Ñp„ÿ܆B¡„ƒäù©o!à€”nÑSÓÒ &L賋‰I÷^é5¨9@ àEVÆ’‘!ˆü©$røÁb±ü©öàÞtüEÌñƒÙ›G@@@–/›ñèqJ{{€DjI|š¹|ÙŒ¡v á™æ† u`¿Oee= ºº1àØq»²ƒ€€€04àñRòÕ{Sä>äiᛙ憞Ûñ,V“ɺwïÙPû‚ðM,Ú# |AüuñÎé37ÿø}Ý’ÅžCí‹hÂnDkk `ñYwèð•ËgHÎ ¸? ‹Á@1óx¼TttêôéNôçÌÙ›‰O³h4†§ÇxËfsZ[;–/›—ø“ìpmmÓÕ¦¦ÈÊJ;Ø[lß¶t€ÙŒ_ ÈÓ<„Ïúff&ÝÿB ö”„„Ì̬âÚìéaß¹›XUE’п±±5.>cþüÉÐË3œžD§R(ôgÛÖ%Æáñx»ýVíüyùžÝ«7müÁÍÝçùóÜ8¬§GÜïïÃb± ôµ÷îùIòÿàArGu€Ž!|! Oó_¼`M—ÏDSS[A`=Ö÷²à6 |aþ-Éÿü뎀’üL/ç àˆ?~¨Ð‡åË32Òµ±1 ½5i’Í{†- $'>>á%-øÕ<Í# %,VO|üËÛñ°Â<…ÒZSÓ·p¹Ü—/_ݸ%¡:;iÉÉ9éé…==ìääHm^¸›È •—×x¯öonn+((‡¯ÂårŸ>ͺ_W×,Ò~KKû³gÙÙÙ%Pÿöö®¨¨‘wóóË::¨Â6+*êââ2ª«ûŸæy<^ffñõ°'ÅÅ•)Ç{:~¼%¿«nnvOŸeñ…äÂóP©ôââ·&Œ8 (,|óäIjg'-5µàzØ“¾¾>ÓKK«bcÓÈ äÇS a±z®]º|åÁ«W•åpIºÚÚ¦ˆÈ„ÄÄLØC.—›œœóìYvOûþý¤¸¸ ‘=‹Š*¢£S)”ÎŠŠºââÊßÂ`A¦y„!£¡K$ª‘H­(}Ä­cÆÆï© #//ck; ÐÝÍܽ÷t¢“•‘‘®6ìpWýìù[ÖK,;ÙÍ>5µàü¹_…M9;[[[™2™,( þ¸»; ÑèI“lÔÔ”´uë—Gx'§±ý™YÜÒÒÎáp¡…ýáÃ5ss_ïØ¾LdÏ)S-,ŒØlŽ—×Äò×÷ Ýb„Ï2Í# </>þ媕ýíüvyÃo™šêCÒÒxx}øô©ŸÃoÅ%%ç´´tP© ¨…B¡--M–âºI¸?Ï’r†ëj†Ýˆ0ÝzÉ"íÃZu¶¶£F×Õ›nb¢·léô]¿®i–¶‹Ox9ÆÒ:ž5kt@¡tŠ¥WQVìê¢CÇŽŽ£EZæ‡ÃB³/À{å̪*Òì¹;Š‹"P(ì°œœ´¦†*‰Ôª§Glii71Ñg …B‰üð“›ûšÍæ$%÷—16Òåp¸††:MMmÐ~D[[§¾¾–¸žÐȘ›¨è#|Ziah@¡P²²Ò,[ø-4ZPöµ«‹>ÅcãïûÖ®ùi΋ù&÷ööBKÇrrÒïí&îB))yÎÎÖJJr––FÑpöù!“ÛOžØ°511óÄ©0"QÍ{å¿Ex!›üýeeDø ¢¢Hg.›è &TÙöÃ05Õ/}]M§3ååeáF ³iãÂà ::D¢Úfß%Xþð“’’§¤$B¡–,ö„v qãñxÆ9xè2ƒÞ»ç'3€Èžr²2|ä»Þ›ùòUyyÍ'1Åd² µ²ÿ3·#â¡ßÅ_#Ë–NKHÌ„ŽétæãÇ)Ȇ e§¤äQ© /¯‰RcK___mmSjj__IÝD^HAAŠÚ+}]X¹ÜëIt*l."2á3ÿñn))y{åêC%%ù Üö­­m¶ ÝtÂÒ%Óž%eCh<ïÖí8€Vs3ExdêëÉÚÚýuá®]’üMÅû¯—}}}‘w§Nq„æxþ7Zöû¯ß²yÑ¿¯Ãb±â,ˆüd¡8ÄÖÖKKã‘#‡''÷§íW–”¼mmíÐÐPÙ·÷§½{~Zºdô–Èžü#ƒðYÁøûû:k½àÒ°væû;~fþ¾|é²} ²cƌקºš™°pᔼÖãÇ)þÙÑI-)©ºzõ!‡1BzëÔé°¥Ë÷™ŒÔ32±¯–’’—ò"oŒ¥X‚¢‚ìÅK÷˜âÂbõlØxlÍÚ||ÌNX}}óOk:|eƒÏ‚6ò)¹Ö 4õáóréÒ ¾&N´Š™_PÖÞN}•2ožÛÝ{ÏÂoÅ54õõ´òóËBB×Ö5éhkØÛ[ÜÄ`t×Ô4⥤^WÒh ³Qgφçç—3™¬Q£FÈÊJ«ª* w›9ÓÙÃcœÀ…¤¥ D¢Úå«) 5v¬É¨Q#:;i·#â¹ÜÞ¸ø {;óÎNÚ±€~ûiiçƒo—¿©ÕÑÖ ð‘wÁÿØ;ï¸&²-Žß4zï¨ ]¥¨ØQ±®+bíêºÖìuí Á^è ½W¥©ôB’ÌûctÌKBËÝûý¼ÏûL.wî=3nrfî=çw¨©n MX·v¶‚‚¬À˜÷|ƒïù'Â)© IDATUUÕ[0>Ü A7Ÿáîù‹˜Á¶ý´µÕääd|î-˜ÿ1°…Éd<_½júqŪC*Ø¿gÎÞ»ëýòÇJ‡›””‘üÏå‡ê*—.ì––&ólf¦“6köÎó^~ǎ߉˰`ÜÞÎ:}Æ'$4±¦†ÚØØlkÛᄄÈ#£^ 3!!;'§xîÜñ²²ÒãÇ9?q·­­½  ¤¨¨lâÄa22”={/ìØyöì9ßS§}òóKF²‘–¦÷¼výI@@XEe4…lnnнÿÌàW¾;à¾ëÃØI—¿ß€_˜Ά®X>]ä_¹\î|×=Þw}cÜÇá#× ËnÞø ­Íápæ-øc¸£Õ¦óÑ£Æ¬Ú¾Õ }·àÄÉ»™™ÞwwkÆ'O¢FŽ´VVVÀZ¼.Ü4д‹ž¾£ƒ#-;”Ö%'÷Mke¹¹ÅΓÜ+Ê‚¾eï†ýjš*i# lm¿â€Á`¶µµ««+±'ÖÊãñTTy<‚ Ug﬛ðDhÈ·¦¦*¶ÍápjkutÔ¿X/®£ƒC à[[t:ƒ¿¿ð˜üê´·¹™Áĉð>¾~Á4ý»?FƦ¤¾Ù»g9@èèà„‡'ýuàrrân ÒÒB'²²Ÿ72¨T™,…þ¤üþ‡×˜Ñ¶NNö8ŽÁ`z»ÕÖÆ ¤$¯¢¢Àãñùx1Ý„'ÂápZZjüþ˜H$êêjt¥&,*J£¨('Ð_xL~„Ç_»Æ%8${ãâr¹aaIKOù¢Ý¥°¨L[[ ½!$ÑÚÚì+~äø}<@UU óÜù%½{k¡W'#C±±6ï¬'ä_CÂ!x'::½Jâ`Ù»·ÚØÞÎLIyƒÇㇵ,**35Õ¯¬¬+((•••¶··¨«kÌË{O"Ñ÷WA KÓÒóûèvšœœ[YY¯¡¡,-MA3s¼}7ºÏãïSW×—E$F²Á‚V¨Tš’’|g¿&gÏùh"ð«¡§§ih¨wñÒƒ³g¶c……¥ïßWÚØ˜c©TZnî;«cüx´¥´´:)9WEYaôh[tFA’“ó ‹J­™öïoÈb±ý®]2ÛÅIYYÞÌLõµŠŠr$±¡†ÆÙŠ·ùÓmç&'ç2L;; ~mËÂÂÒ´ô·:ÚꎎƒøGè¬CØx‡“šúöÝû {; tÏ¢µµ-#£ £ƒ3j”Íë×\.oäHkþÝA俉´4Åmá¤+W¡«ôž·6mœ/-ýý…åÝ7Ì=ïußÃó–¼¼Luu‡Ãõ»÷÷÷âúÕ?ÏœõUV–'••uJJòG¯û¾S@º‹$ßæ…Å(©©o&LÜÀãñäåeNžòÞ¸ù µ•qâÔÝã'ï gݸùtÿÁ ƒÇO܉ŽIŸ9ctXxÒ–­'…g9vü6‡Ã1c´’’üñ—§’Sòú÷7ÄúÇ8xÅÉÉÎÚÚlÓæYYµ*Å«RdfššˆÈH15é“™U€}ô¹ÔØØbaa¸û÷ó÷|ƒÑF&“š°jÍÇ·yaía% ‘ò(F†z˜fVW”4Μ½§®®¬¦¦4gÞnìbzÜ Or™å$''ã¶h–ÌÓY;†°ñ@”D ›Ý¿aã±+Wê•–UÏwÝ#ÞNä?‚­m?«A¦,»­­}œ“½˜ ¢o@ lÞ´`÷®%ë×Í9|hÇQw==Íï;…ŠŠâÁk¶lvÝè>ÏÓcãï»—’ÿ-ébHgHÒÍcbÒÒ”ukg9zõmÛ·ºe;p ‰¾if¦ïO(*Êéè¨GE§¡i£ØUˆÔŽ©¤Ñ**ŠèÓèš’f’yNnqee]Hh‚¡¡ÖÁب÷…‹çÎîè¬kéLø¢3%e%yTØKZš,&@ ßIºya1 4r [Žî,†…Ãùœ)¾rÕauuåÇÖ„ÕkŽ˜L€˜ªªâ‡wÏrsß=|1cÖöÂüÇÒÒdþ·p2YŠÍî@•VîÊBÓüyÎËWljjá{¯©iÈÏ/9î¹Iä)lv‡¼PŠHíˆKÿ<ïùÅ7èt†––Ú i@VV½ üíè£@gíâ£d" Ý @ Š$s…Å(Œ{ÛÚ˜\ËÍÉù\¶HAAs{yoÞ£>£¥…~ýæÓMç„êê‚ðxˆ·Oà^ØýÇùŽŽ¥¥ñýkôõu8.‡SUUÄÔl¬­Íôô4²³‹ÐQQiÆ;hh¨€/©R¸Ì;nœýƒW°Aöì½8ÞLÑP_ß„”•Õ°X£FÙ Œ#R;B¤’øy l„²²½Oj‘_TÒÔ×,eù*eÚÔÊÊ 3gŒÎÎ.‚dç¿}û­|Ð×׾먡®œ]ÔÜÒæï&#C1ÜúǪøøl——œ’gbÜ;>>k¸£U\|Ö=ß òòþz±q™Tj3½•“ndÔËÁ~ ¬¬F^^í'ãÇ9x»ÝÞÎJM{žtÑk7ºò/^•‡ÃÍœ1&))×? LMU©¼¼ö¯ý—{{z¸cï¬ÁÁñææ…¥…¥—¯<<{f{Ÿ>ÚèŸ[îÜ}¹yÓ/¬abÒ[XIÀ/O!-ýqÑâô™{Û·¹¡É{âmÄ'dËÈkk_ǦÇÅe?·CF†¢ªªdjÒçÔio÷øÉ+Ù»g9Ù^UUèðµ´´|‡3fÌ`aãEJ”XY™ž<å•UÈbu˜›ë8x%;§¸­­ÝÁaÀ·V­€Z=‡nÊã@ _üÊwÉË㈣hh IK“ËËkƯÅ4Xx<^yy­––*—Ë£ÑZUUÑ¥u‹M¥6kk«áp¸Ž‰ô;lv‘H(/¯UWWÆ’ÇÒÒÞú„yzläïI¥ÒH$¢‚‚\w/›Édeeáñ¸MDz,&“ÕÒÒ†®`–:Or_üŒßí‘7G@ž¢¼¼f÷ï^>ÞÝKÁojj! üz×AªªêÕÕ•®¢³v~„Éwjeô¾Jéð+ß$ŸµŒŠE4¢)à~Áv<½ óg{“ÉR::ÅŸ|<õL؉(66æ¾~!­­mü~‹Âë. ÙÞ^\p,…BæØàî9j¤ŠŠ"ZIŒ"oŽÀƒÈµëOöîYÞ]›ùã 0p8œÈRQµó#l¼’’‹þûèøø¬¥Ë´¶¶ueð«×›÷w¹s÷…øn>T¾ Œ55Õ byò”w×í¯­¥þµÿød@ ‡$ÝüšÕ.ææü’éÝb̘Á³]œÚÚ˜"ÿzÞËï÷=^×®þ¹uËÂeKÛóÇò¢ârï{Aüõ[ŰrÅŒ–Æl¶8Ìårwý~þϽ+нziÉÉIÇÆfvÑþŠŠº#¾øØñäITSSKÇ„@ „ /ÚS¾­1*ï*LNNñž½oß<À¯¢³Èm²}w*<ò Úˆ$**Ír€¿0œÛÂɇºœåoccž— ¢¢(¾[hXbM  G$ÔQ©´¤¤Ü~ýúêëë -'5õí»÷övFF½ÐÆÆÆæøøìv&ËÈPO__Óqc2YññÙJJòÖÖ…ÜOŸñ2ÄÒÀ@—7g¶ÿQ5¶°°4-ý­Ž¶º£ã ~Ö*óóKììú ™‘‘ÿ6¿ÄÜLßê“\¼·OàF÷yü}åH$bC Uñc0˜\.W@P#%%¯®®iÄ+yyÙ7oÞ—•ÕXX22  0Ò××a2Yþa×®?™í⤬,of¦ÿÅ'@ø‘|^zz~JÊ[Û~³fïLOÏGçÌÛ-#C?Îá÷=^„ššZvÿ~~„!ÓåuÁ¿´´íYWßøàa„¥¥±×…û.ú£©ioD‰ÞlݲUŠ=êq3,<Ée–“œœŒÛ¢}ÍÍt‚ ›·œxö<ÆÚÚ,::=9%;qËÖ“IɹóæŽ O:uúã|rJ^ÿþ†SêED&£ÇkÖþ=oÁ]xyyío3¶ÖÖ6h9ë›]dooÞ &“­£­Îáp›hð@ ÝEònžÃá:;ÕÐP±µ1|•‚6ª©*q¹\uuåeK¦;qPTTVXTÖÐ@#‘ˆ;¶/ÂÖºKJª\LTSS7Î>(8mlog‰.T$&æø„­_7‡D"ÚØ˜ÛÚšÿ¹ïàæ­g…Ee›6Î×ÔT9s Xxõ*õÅË×kV»àñø­[\=z -Mf2YèñéSÛÒÒóOöŽŽIoiiØÚö31îݫϤþf?~òJOO;­Þ&M¡`§[[™UTÖ Ï•‘‘ßÑÁ Mà¸56êý20ðüÅk«A¦X;ù“ |•"//ëíèíèw?täH:½½½%²¸ŸŠŠ"º604Ô¯6Ï_w‡Ã‰¼|5’wóØf9Fs3}ôØÕZšª[·,œ<ÉÀårËËkOžØÒPqà¯ÕOŸEß¹ûòÓé".añ¢)‘‘)˜»ÅˆŠN#‘ˆd²x?›ÝA&“²”HÏ­¤$¯©©²Ðuú¿€ûžJJòÒÒd‡+Ü™Nghi©uãúù¾üÄĤݰùÏ"a7 æY1“ÞÒÒ6eÊp@eUÇ+-­ö»~ã©’’¼‹‹ÓÑ#нy|§öГ&9ÎvqÚàîÉ?Wii5Zñ}æŒÑÙÙE˜§ŠN[ä6àº`btL::‚ •u\.ퟑQÐÒòñ¡áñãWlv‡SUUloLç++«ÑûT³õõ댄._¾ˆ[PPe0˜uuõõMân%é>˜¼Õ·Ã`0…~4 óÑ£ÈyRÈÏaÿþýßo4.¸r¬œÚÅÞÞ>¾~!µú}t22òoÝ~^ZV­§«iggñøÉ«¶¶ö’’*²”TNnqkk[?ó¾Ï_ÄjªBBÖ­]äuá~~~‰¢¢—Ë;}Ö'/|œ´9`òdÇêꆧ¼äÚÛ™AÁñïÞW,tˆÇãUU•LMúœ:íÍãñ?yÅã!{÷,Çãñ&&}ÚÚÚÑïÌ‹—±ù™&ƽ 24Ðäï£7ââ³”•äÍÌ ee5òò2½{kñ_Ôé3÷¶osC3ýΞóMIy3}ú(‘—èðµðˆä––¶áŽƒ>Šy+ŒŒz1Ì„„윜â¹sÇKKÃH{Q\{V­’´W®týà‡²ió‰¥ËöϘ>ZEE¡³>>Tú„Íž=îçzþ<æÒ?M´–¼¼÷7n<%‘ˆ}ûê˜LÖÚu+V\»ÆE8Ž“ó:} ¥ÉWOM"ß¿¯,..36îÝ•þùù%K—ï¿~ãÉâES¾zR@yyÍò•¹¾vË·Œó•À¯|wÀ‰\¦þZØÀv(Hºü]Æ¢ÑZy<žŠŠ"ÇC„ÇC|k+ƒNgèè¨óïj‹Ãáäç—P©ÍVV¦hŒ=‚ UUõêêÊ_?‡C¥6kjªÖÖR‰D‚’’<šn‡ Huuƒºº2‰ô1¸/-í­@˜§ÇFìÜòòšÝ¿{ùxþÖ‹ÿZZè†àuŠýjš*i# lm¿×/À7‚ ˆº¦Sbü-,#W.—;ßu÷C"p×9|äZaaÙÍ¡?gÞ‚?†;ZmÚ8ÐÑÁ‘–JkŒ’““>÷ÄÉ»™™Þw»÷‹qóÖ³¥K¦ñ·¬ßàqðÀUU¥®œ•º}ç™ÔänHvŠ$7·Øy’{EYÐ7Žó5À¯|wèyó"QR’GÐÝw4³]QQNQQNÌY‰D #‘ÂápºŸV×NÑÔT ÿÏß_ p­¹¯_Hkk–íú“½{–wݼ."ð€@¾‡ëL> EXÞê+HK{{ò”waþcL{ƒH$ž9µÍÂr®ó„!¦¦ú$‘H$tvúömnÝA àx7?uʯ þíëÒ î÷’߀2? ’Áû©ùs‡®òx<@hhb¯^ZâCë!ˆ4Zë³gÑOŸFaá/€övfLLzll&ÇC÷Î++ë"#S’’ruu¯^¥bÂÒ'11Çç^Pqq¹È)8NXXbÀƒð¬¬Âüü´ÑÛ'ðŨ«k|üøÕóç1üÔuubŒ?{Îwà@uueþF==MCC½‹—ðÀMNΊJe0>oÞS©´èè´ÐÐD¬ B OB£‚‚$%åÞõ~™›[Œ H}}Ó®ÝçÒÒÞffäæc'Ž3“ë@GÆFè :‘œžžþ|a–úúGG§ñ€ HBBö=ßàœœb¡‘:5žNg„†&Þ÷mllF[Z[ÛbbÒ#"’¹\nTTjDDò('ºùoBQQnËfת$qÅòé’¶ù™ÈË{çê¶×ÞÞÈjh RSßL˜¸ÇãÉËËœ<å½qó @k+ãÄ©»ÇOÞ´µµß¸ùtÿÁ»ÂjZ¬^ó·µµ™Ë¬±éùÁ!Õ5ä­‚ƒã¼âädgmm¶i󉬬BÀû÷š:ãSRò:³?3«ÐÔ¤p»©IŸÌ¬ì㙳÷ÔÕ•ÕÔ”æÌÛŽ `2Ù!¡ «Ö|\±¿ïú÷ÑӦޠPÈsæíF„ÃáÌž»ëmþ‡9³Ç½x»ÿÀe:¡­­ÆårhŸK]HI‘ZZÚjk©èG+×S§}ÄÜöÊÊzŸ{A†ÕÕ 3fmÇ’’DꆱÙ‹—üÅd²]f}óöýög„·z…on¦;Orwt4ÐÒdÒ”MïÞU CÇoØxìÊÕdž†z¥eÕó]÷ˆ±ò]€nþ[ÑÑQG³ðG¶•´-ÈOƺ  æ;kjªêêjŒe{íúÔ·mßê6j”íÀ&ú:yyïffúΆ¢gèΜ1DXM‹A^E¥–—׺NBãÝä­ètÆ’eûX#//«««±aý\·ÅûÑ×× òÄ'§!ΙXËáréôvìãÒ%Ó t-,ŒÜ? ÐÕÕÀÖÞi´ÖU«ìûs%…BvtÔÚÊHJʽ|åQk+cÉâ©d²T?sƒ¾}õ tÛö—““qr²1šFmmµÊÊzôØßÏcÙÒÿ[Õ€B‘Z½j–¦¦êäÉŽýÌûîýó"è\7ìÌÙ{** £GÛJI‘æÎ_XTúøñ+þÑDÏápÐE33ý‘#¬/_yPUUZä69¿ dæŒÑ½ziMt'ÆNÈw¡çîÍC _‹—5ÎÉÞÛ'ÀápUUåòòÞ—”VcÍhâ Š”Ôçß+þ ÜÓ§¶ùú…¼ŠJ­«kBÕ´øÁáp»w-q±\II~ò$Ç£oÈ[¥¥½åp¸X›±q¯œÜ⊊Ú^½´Æss ƒ™¿±SPTTfcýÙrT™½œœÜâÊÊ:==Mþ«HK{Ëfw¼ŠúVflÔ«£ƒ–8ÐÒm™6m¤3*ÊŸ…¹ˆïLæ«fcm¶û/€°nØ…‹çÎî ŽŸ5s ûËÀØ™|-"WUU:wfûå+I$bQq™†úGÅO§¬$F>IK“™L¶xS!ßtó?ŠÄÄeeyL1÷[èèà´´ÐUTq8‡Ã!‰ 388žÿ›ütHDÊ8'{ûÏ¥#Ñx¬‚Cg95Øžns3}Ü„uûö®\±|úë×OžFq¹\.—‡½©#2z”-µ>2!!ûêµ'[·¾us¿€¼*™… :*ªAîBýÌù󜗯8ØÔÔ‚UÒÔÔ4äç—÷Ü$ÜY8kFII‡Ã-˜ïŒF/t¸ôÏ1^°°°TAA㢷1´´T;ë,vG^^|º ü¦¢O'd2I¨ýÿîŒHã32ò/Ýÿøá CC½¦¦ÖÊÊ:&“…ž(RÓ ò〷[÷ýC§þ¶yÏÞ ž·¸î™>s›‡ç­?÷]šé²ýÜy?1'~øPù20öÛ}|\\æ×=ç½üž>‹þûèøø¬¥Ë´¶¶ÉÈPÈd©ÀÀØ® ‚ È¡Ã×°b?HÇ/r›üòÓÆííÌgÏ¢{ÛÚ˜\ËåùRPÃÜ^Þ›÷裀H5-4:•œâr¹;v%“¥F²½y㯪êz€€¼•µµ™žžFvvú1**mÂx ‹}úŒDž.³ÆŽgàà¬A={/Ο7ÁÉÉk¬¯§¡‘¯R¦MÁÿL€biilbÒ;** ý˜›[œ—÷ÎuÁÄÈW)hD‚ ~÷CÀ'½,@vviÍòòZ]Ý©@wùÓØØŒÊEF¦,r› :× [è:éõ§hG—éºÀð)z‰4ÞÛ'hèKty ²²ŽÇãùú…p¹\M01FB¾’”ÇéùܹóÂ}ý¼…®“ED¦ÔÖ5^þgϘу‡ ès/¸3Ý.—»fÝѳ§·ó ¿‚ó^~ç¼üüï{Žamee6b¸uä«Ôƒ‡¯íܱ˜B!›˜ô>söžƒ½…Œ Eü8,{ë¶Söv tÄt«¬¬KLÌ1UÙ¯§µ2zÝ”Ç9ÒæÉ“¨·o?Ph!¡‰³fŽ¡PÈãÇ9œ>ムHvNñÛ·ÒÒÞnݲ ¯¯}×;PC]9;»¨¹¥Íß?LF†2i’£°šÖÔ©#NžòHnjj8ÐôÊÕGRRDþðQÄÜÙãÑÕüòVaü8Ïc·ÛÛY©io“.zí–••®®®_ºüà´©#PMap8ÜÌc’’rýÂÔT•ÊËkÿÚÙØ¸·§‡;öΟ-#C®­m|›—uþÜì;ÛØØrçîËÍ›øñ㎟¸ÛÖÖ^PPRTT6qâ0“Þ‚ܸù pÏ_Ä ¶í§­­¦ªªžÔÞÎ*-«vvþ¬Àd²„¯^5 ý¸bÕ! ëO%³¨¨¨ÃãñÅïÊ›it_¿`éÝ»–àp¸Îtà 0*+« Šc´1/^ ˜íâ4eòðŠŠÚC‡¯¥¥ås8œ1c ¯ /{ãæS%%ùĤœ~æOžEõí«Û«—Öá#׳² Y¬ssý¯dç·µµ;8 è^f#üÊw‡ž+Ó8yÊ{ÛÖ…èñwÏâwåÁ^èÇã'îìØ¾HäYÉ ‰Ù{÷¬ø–©srЇ _–•á‹þ$¡ 2dØÒàÀó¨¨@pp|Rrn“e¿ˆ@‡sqqú.£ý«@­ŒžÃWÉã0̶¶v´´†š´4¹¼¼ÖiüZLƒ…Çã•—×ji©rwúì IDAT¹<­UUU]PÓxÂFäkj¨::êbä­T*D"~…R“ÉÊÊ*ÂãqšˆôXMM-D"ÓØ@),,užäþ¾ø¿d²¿–‡Ã©­mЫ¯oRV–ÇêpúúÓhôî ÒÕÔ4¨¨( X+F7 ½b–Ü…¯©iPP“‘¡ttp°;ÿ€_ùî yM{þ¬P´Q8{õÍ›÷ÁÁñµåå5±¨º;Î Ixóæ=Ú§¬¬&<<);»¨¦¦!00–?ƒA‚‚’{¾Á‰‰9h ‡Ã‰‹Ë|ñâ5šZSÓ€¶ ¤~wÔ™åíDš „òq…gGŸÛzúŒÏ!–ü>€ÃáæÌvÂ*Üt1Y¶¨¨,$$áÇJþ;YQQûüyLIIÚ'::mÇγJª23 Ф&ä_CF†"àãjjJ²²ÒœŽŽÏ©Õx<¾Om2YJF†¢££Žm+)ɣũñx¼ð*š”‰L–êÓG›ßÓØØ˜s¹<yUU¥¯S£¢PÈööƒ÷ïì­TYYßÇop÷|ð ¼¢¢®ÿ¾èå‰D]] uueÌÇs¹Ü°°¤%‹»-^«¥¥&l-ª&ÜN$õô4Åo« ¯¥¥†.]|Oé&’tóÂY¡ “ìÕ†šû¦c^ü³³‹íì,œ'¹?zž{fû“·ú÷CRV­œù]Æikkçd?pà׿üòHÒÍ g…FG§u–½ŠÃáÌÌôÑviiŠ™éçãÚÚÏj”ØÒ1Ü:(8~Ö¬±ë×Íyþ<ÆóØ-täÖÖ6ÔÑ"baaH"55U#"’…S?ÅßY¢­ªª’@¸Cg³‹Ïmµ¶2«¨¬nÏÈÈ·°0Â.³‹É²ü ~ÿ'ÉðÝò_F PÅO‡¬¬´˜EGHÖÍËÊH d…ŠÏ^Åö¤Ž;ƒÁ`jh(V®:¬®®|øÐZ°zÍ“ÉBë.`;I"S?ÅЙ©ù¸âgÃâES\Ýö67ÓJõDE§YñÐ~]²¬ø»“. °@ ŸIîÍ g…v–½ ør4…ùǤ~ª‘ÐÖÖº`¾sK ýúͧ›6Î#ÕÕ <áñoŸ äh‘©Ÿü#óx÷y®ÎLÈÇílvð¥ÜÖI“g»8mp÷äo,-­Hìéb²,‚€NîÞç> ²Œv&àÍÛ÷YHAêêÑ_ ~Á–Í}ÿP&“Å`0=ŠüŠÓétZ•‡ÇãÁJ-IæÍ g…êéiŠÌ^õö ôõ ©¨¨Õ•UxóÖ³÷ï+õt5>|¨º|åáû÷•š*ææ±q™ÉÉy\.·¡žö÷Ñ›7-7ÎAJŠôáCU||6ËKNÉ31îŸeggqõêãää¼úzš¶–šŽŽºÈ¼UÔÎÀÀØ»ÞÏ_Ä”—×666×ÔR-w–h þ?WäìíúôÑŸÛ ˜<Ù±ººáÄ)oE¹övfPpü»÷ ]'bÁ®]L–½ç|Ï7¨ªªÞr€qxDv'32òoÝ~^ZV­§«idÔKNVÆï~Î03ÕïÓG»;ÿî’&Ñöº™7ßuüÂ?~…ÖU+,*½ôÏÃiSGtñܤ¤ÜÀ X~ÝÜ®óøñ+giiL"ß¿¯,..36îÝÅs›ÿÜ÷µ±97·8,,ñåËXÅ.nxûR©Íâµ.þ»À¯|w|޼ȬЯË^õð¼URRuñÂîêêmm5þÜ‹M¥6kk«áp8ñœÂ©Ÿâ6U8·ë³ ÃápòóK¨Ôf++Sòuɲb@Uu±€ƒŸ˜DÛsè~Þü“'Q#GZ ÃñSTT¶ÿÀïÅÜ<¿uçÅ‹ggº8Åå+_Æ>{rº»–TUÕzzäH›ÆÆfMMÕ¢¢²ÑcW£Âø‰‰9®n{‹ Ÿ ›h«V&“¥ÎŸÛ)` ))÷ô?ߣOœì~äÐzkk3t4cã^b¶ºjk©OŸE‡…'…‡'ii©%ÆßBSdæJHÈ9zUsS›Í!ðrr2W¯=ŽŽNó¾{ðöí‡~f×T†hjªVW7›N§·Ä¬m]{n;Ö.22eÓ–9Y÷»uçbàW¾;ü:oóäg§3Õ)­‡ÃeëqÔ==ÕÇÏ÷èîß½x<^Dd²¡¡ºuebÒõñàÿ•¯€PÑz‰ˆµŒi/Ò*•&RßB@“JŒ§ÑZ55UW­œpß³äý EE¹ë7žˆì‰ÃáúöÕ•–¦(*Ê¡±Aü6ãp8e%yôZ¤¥É˜Üˆ±Q¯ŠÊ:@]}cß¾º¢†@ ›‡@ =ƒ˜˜tLu mÁT§nßyQ]Ý€õœíâ$#CimeÈÊ Jlat1–Á`ÊË öDƒTTém áSº®Iåáy ;VT”[ºdjy¹ ´%pÀc(ŒÈš1S§ŽÈÎ.:ïå—‘QpåŸ=]1 òäwóߨkÒÑÁ¡RièOT·€@¾/ ²hÐY}}SgªS‚Üõ~‰ÒÞÎêÛWWQQnÊäá55 åå5hûÇèS¿øI(@SS ûôYô"·É– tjj¨ÂwQ“ ðâåëÆO‚]*µyØÐ"çú@Kg‚`yyï·m]è¾až§ÇFô]F’ò8?šoѵ@‰‹ËÜýûùŠŠÚÒÒê  8"°÷ÏKãœì1ý]Hjeôº/Ã`0²srŠçÎ/''#Ru*1)§¢¢îÝ» € µµÇŽßÞ¹c‘®®†¼¼¬Ýàþ_“"‘b^§S(dãÞî»Ä¯|UQQ{è𵌌 EjÈËŠŠºûþ¡x<žÞʸ|å¡®®Æï»—¢+äü–HK“åäd|î-˜ïL |~ê¢&Š·O ‡Ã-¯¨Å–øî]ÅæÍ „ç*/¯ñ𼕑QÀ`0ûõë+++—yþÂý‚ÂR=]MÊá#׳² Y¬ssý¯dç·µµ;8 àñû!‹Ï{Ý?qòÎÃG‘êjJX¹Š_ø•ï¿lÞ7êZÎ{ù<ôBë%nßy±dÙþ¦†WJJòßßbÈWãqzÝÁ´´Ð *"‰" :U]Ý ¥¥Êb±33 Y,¶9ÿš<‚ ÕÕ êêÊ]¥HLÌY²lþ›‡55 **Š…Õ,9uÚÛÜÌÄÝÔ¤BuºJJª Ëôõµ±ì€Î®º[ÔÖR×»{Þ½}PZšÂãñ J§Mß’”pËÔÿ•_ùîðË.Ú£®ENNñž½oß<€ùxÀ"·Éö°ò½QPðvªS¨‚$…Bvp0r¤À¾;‡ÓÑQï¢ð*¢ÐÒRðñ–¬]ã’€½ uW“J[[  ¯¯3~¼ƒ€ž«»TUÕ“¥¤Ð A<olÜKKK¿î‚"a7 HRRî]ï—¹¹ÅØwIX#;»(((®ªª¾  $((®®®À`0óóKÞ½«(..466•åç—€ï¡kqúŒÏ!–ÿ¼ŠÃáæÌvêJq<Ò)..÷»Ò§öÉSÞ]é/-Mq[8éÊÕGèÇ¥Ieee6g¶Óþ—/^ 8ò÷õ]»Ï{uÇ2ô  I¢åp8óü1eòðùó&œ>s/àAøýk‚ƒãŸ¿ˆñ8êÞÒÒ¶ió‰MçhR_ß´fÝQ³ukfëëë,[qpþ¼ S&‰ß²íT€Ÿ‡‘Q¯¦¦ÖiÓ·®Y=ËÌL_¼®«beãê¾aîŽí‹DÚ–šöv¸ã áö­[þˆ[@þŒŒz]ðÚÝ­Slmûñx<‹Íáp{š&Õo¿úí·Q’¶ÒÓ‘¤›¿|åQk+cÉâ©€~æM´V:±dÙþ¼yyYyyÙ ëçº-Þ—•á;v¬¹¹þŒé£œì½v÷0ûmރ͛º±@ HÏG’n^VFPÚ¢3q ás ¦¼œ `æŒ1ee5))yÕÕ zzšè_¿]×bñ¢)‘‘)Ø3FTtZwKÌA ")$éæ]LŒ|•‚ÆÁ!âw?¤3q ô#•úQh"5õ 5Ê@"׬vY»þè`Û~ØÈß®k1i’ãl§ îžü¥¥Õ˜1ô|$ùb:y²cIiÕºõS§ŒÈ/(;f°”ééãS‡\Ÿ0a‹ÅމI¿së Öÿõë UUE‘è}/èų3hÀª•3BB`=55UÉdRG‡ÿÍ›Éd)(ÈbY:ç½îw¬æ˜šêwfÞ?—þ¸x)`μÝ+–M×ÑQKKÏçr¹‹}ÏúîüP$/ÃápjkutÔùK5ˆcœ'mX²xêôßFµ´´ ¼R×ÖR£cÒçÌÇßøºüæåç—P©ÍVV¦üö@zP+£çðUò8H÷€_ùî yy"‘¨««!PBJ@|µ PȘ¯®n˜2m3àÑãW¿M)0ì7êZð›gaa4r¤ ôñùéø9¢ÉnÝ~N&K½z•jfª?xp´Q]]©¯îå+mmÌ…Ãô0] T}ºGéZ@ ¿2ö«%mùŒäí(Éɹšp8ܼ¼w0çõ—®àý§ÈÊþþàÈIÛüH~Ñþ‡bggA&KÉÊJCü deåË%mò3ñ‹»yòë•vîgÏJÚäg¢G¸ù¦¦–ïºwð•ÔÔ4„†&BCÑê8ïÎÀªq8PCòU >ÞÏHÚägBÂ!xÍÍôÕkŽ Ü?0(6"ì ZÂfw8xõô©­€Q£lþØsÁãè†.ÊÚ§§çß¹û"6.Ój™‘‘‚€–ú¬™cmlÌÑ‚>r}‘Ûä>}´»kØÉSÞ±q™mmícÇ &“¥˜LvQQÙ»÷>wëêjtw´A®ßxš””;h ollžíâtààUïÃ’6 ò³ùxeeÐÞ.ik Ÿ »ùsçý¬¬L—.™*--B‚^ 7o=[ºdÚw´dÿËë×ÍF•ð¥¤H ]'ž8é½{×’®œkmm6p 1Efè¡kÑLýúú¦a×íܱxÅòé‹ýàa¸ã°A_áæ·m]H¥Ò‚Cvíüh ÇÛ±ólQQY×Ý|ee]^Þûñãº;ûWƒ ȼù¿ëêj\¹¼Í–äñx+VÊ{óî_³ò‹Àïã!H7‘ð¢}AAIïÞZ**ŠëÖÎîúY‚ÇG3Z[ÛróÞYXa-ƒ™††%2Ì.Ž@ <–ý¯®®«¥EPŸÿûRW׸÷Ï‹7n>E?^¹ú(ïÍ{£îØ=Áãñ§OmCSëë›æ/ø#22¥'lÖ@z4ÐÇC ߆$Ý|QQYcSKiiMff—ËE¤  äžopbb7&“šxß?´¼¼P_ß´k÷¹´´·™™¹¹ÅX·ÂÂR_¿àèè4T$ŸFkŠJÏb±ØQQ© ³´´º¸¸¼  -HSTTV\\^_ßxôøÕèQ‚>xü8t«ÀãñО]§¹™n` ƒ]iHH‡•€ÊʺˆˆäÌÌ‚–z``lzz>ÿYYY…/_ÆÒh­±±™w½_òxŒ@ÇDG§íØyöCIUffAC íÓÞÎ I𫬬C[²³‹c©TZQQzcß¾ýðî]Å›7ï¹\.›Ý‘Ÿ_RXXÚÖ&¸dZ^^³mûéßÿðš3{ܲ¥¿¡žÇn».˜(%Eâ難(7Ñy(@]]ùꕽ™Y³çîzñâ5töÑ@|3’tó4Z+‹Å®«klh ñxÈñw¢cÒgΞ´eëI´OEEíÄÉååefL½ÞÝ3""™Nghk«q¹Ü†Zcc Úí¨ÇͰð$—YNrr2n‹ö57Ó™L֣ǯöî»tóÖ³[·_œ>ãS[KuuÛ»v½“Éܾóbíú£h¨]ll¦Õ SóÌLõCBÐã[·Ÿÿ†>@ˆ¡¹…^_ßTXXzéŸx<ÎßÏmollÙ¼õdDd €Ngœ=ï{äè#ìì,¼.Ü¿pÑí¶yˉ˜×馦}&OÝTYUÇbu´¶~¬³Çfs**jóóKnÜ|Šú~#£^ΓÜ ´4™4eÓ»whÏÈÈ”%ËöÛÙõwp°p±¼¡ÆápUTZ[ 4ôÚ?|¨\²t¿©iç C®]âs/P[K]¹úðÅK J†.AýºÃ¢+Wñx‡ÃußtìÜy?ësQÁââò îžž·Ö®q¹~mŸå§²ÂT*íCI•‘Q/á[´ÿ¯Ú)rr2[·,ô¹{¸ªºÞeÎNÿ€°/Þ^È èã!ï$÷æ¥Ö¯__''{€Œ EJŠD¡·m](§àxøÐ:YYé-ÛNç0dˆ%`è ²ºƒmûËÉÉ gsüÂ2ÒîllÌmmÍÿÜwéÜÙóçM9zÕËçgæÏs&ðrr2G­Û°ñ˜ºº2ÀÀ@gëWE@Ee­––š€yÚÚj•UßtgÍkb܇@ ˆ¿¢¢¢2E¹’Òª§Ï¢Ö¬rÁöÎíí-¬­ÌÐcSSý‰Îü.Ü÷÷óÀápãÆÙûÜ ^¿nNs3ýìy¿f"‘H;Æ.66óü¹ØÈt:#6.“No¯¬¬G[8z!ffú#GX_¾òð˜ç&‹í¶øÏþÇzõÒb³;†;Zø±cíTU-awl½»çª3õõuü¾ÌÀpêÈÖãÆ9XX±ÙS¦ /xûHJŠ4cÆè´ô·õõM$‘D"N?dÛÖ…è"|NNñ¹ó~ŠŠr»w-Áêÿb õ…‰_º]2YjÕʙ˖NóŸ;ÿ÷É“…× ÿE¸\¨Tpý:˜>}ù"Š‘P‡²~ÝeÏc·îùZ[Û Møéq÷®%˜Ò-?!¡ ††zØGc£Þ/c8®o_]iiŠ¢¢œœœ `ìX;<–ÄãñèôvÔǨÔf EP.WEE«7¯¨(çè8è‹—`kÓÏÙyèšÕ.§Ons™³“Ÿ_³‡¦¦}P)M¡ oØrrÒZšª¨¯«kìÛWWÀ˜ys'¬X>}‘Ûd´EUUéܙ헯<ôºp¿¨¸¬¥¥ ðæÍûªêô­ZJŠtéâïÊÊ F²ÙááÉFFï‰DÔÔT}•ŠÖ¿_ö€²fõ,¿û¡Íee5ú:¨ÍµµÔ 78OrüØ&aÐÑQ×PW®¨¬þSrr®p#‘H\0ßù¢×î«×Ÿ9{¯³Û ùA €íÛÁë×À¬_æÎ11®÷@ ݧ¹ù•«'$ælßæ¶bùtÔ°XlYYiôÕP$……¥55 d²›Ý5²ÙdòÇ×A99iþþ8nÃú¹ç¼üÂÓÇûv®¢¢@§3§ÓZšª_w-††z\õ"Áãï<@X¿nö…‹þçÎûik«¹o˜+òÄÝ»–ÈÊJ22ò'OÝKتÊʺmÛOoßqÆëÜ®;wf<ä?‡´4pv!!ÀÞøù{{põ*ÈÎMÝ ”@þËHØÍ#@=AK ýúͧ›6Î#ÕÕ <áñoŸ …®ÓÐÎt:ãù󀂂,Ÿ]D fÎ]„yú¨è´EnS""´k‘Ûäøø¬WQ©ææŸE6 ûêUU5ô,+«Á^UKK«¯\}$öB>‚~”’"ÉÊP23 èÿcW*tüÙÄŠŠºûWotŸ÷×¾Uü)û‚ðx»áñãù½}‚†±D—1*+ëx<ž¯_ˆŽÝàþØËÉ)FƒédíLÀ›·ï Âüy^Çf }jk©MM-Ncí Ãp_?×ë‚?ºn5*(ÈíÚ¹äîíƒÅïÊ]æì|ò$J Zðà5õõ4,ð%88~äþ–÷ï+ÖoðØàÊòe¿Ý¹}ÐÚÚLÌM†üwÙº\¼^¿ŠŠàôiœ,iƒ ŸÂþýû¿ßh\på:X9µ‹½ïùûÜ ,-«! ¶¶ý>|¨ŠÏæqyÉ)y&ƽã㳆;Z-tš˜‘™ßØØòüEÌÌ™c¤¥)ªªŠaáIíí¬Ò²jg硪ªJ¦&}NöæñxŸ¼âñ½{–—{xÞÊÈ(`0˜ýúõE߀RR¤ÚZꨑ¶&&½1KˆBjÚ›íÌ;f0êG##S¾ºnílá·p@FFþ‰“ÞiéùÔFX::8aáIŽÃ½ŠJ}÷®âžoPUU½åãââr¯ ÷óóKå¸\Þé³>yyïåä¤mlÌ£cÒfÍÞyÞËïØñ;±q–Œ54TNœ¼ûèñ«’’ªÖV›Ýŵ)ÈËÞ¸ùTII>1)§Ÿ¹Á“gQ}ûê::ZM?äÌÙ{t:ãm~INNÑ´©#q8œœ¬Œßý:afªß§öèѶ¾~!%%Uååµ.œ:¹Õа׵ëOÂ**ë¤)dþg Þ½µüÂX‹.ðC"íì,fΓœ’{äïëV§p IDAT<ÏÜL½ED"q¡ëDŸ{Á¡¡ JJòµµGª©)c{oÞ¼ÿcÏ…””¼íÛÜ-š‚Æ|%×^€U«¾þtÈωú÷nnÀÞhiIÚäç gU¨c±ØTj³¶¶‡ëèà`¯ ³­­]ÀÔ×7)+Ëco½‚TUÕ««+1€ëÂEÿµk\ø6›Ý1}æ¶Àç°ç4~]XÈ…/†Ý‰¡  ¤ªªÁÑqÿ{pgƦ¤¾Ù»g9@èèà„‡'ýuàrrâñgÕÔ4((ÈÉÈPøo€J¥‘ÉRhDJG§¥…®ªª„µ0ÌÖÖ6Í/mL rá¢ÿ†õ¢70¸\îÃG‘­­mË—Mçog0˜YY…$ÑÒÒû§©®n8}Ægó¦::êâ‡í°BtBϪ7O&Ka¿ûüNKF†"ü*)àõq8œxU¸ƒ‡®Z0vp°PUUx)—’"Í›;>..sذïšAAñKOù05Õ75Õïbç¢2mm5tF‰hmmÖ•€s,A@àI‚ßcEÞU~fºl?}r[AAéØ1v_´„@ Ì™=N¸]F†‚&J𣭭vÌsÓÇ„@ È7Ò³ÜüÅjinÞ»ªêú5«g ÿÕmáäÝ¿Ÿ777PQQ¬¬¬ H:urë¿ižû†¹ç½î{xÞ’——©®nàp¸~÷þþ7 Æn°EpH¼ºš2ÿ>@~"zÖ¢½da±ØYY…vv±±™vvýaööO\´ÿU©ªÛ¶__IÛüÄü‡Þæ¿™,eggèJŠ<ùá¼| fÌ´ÈÏ tó¤GÂå‚Ë—Áë×’¶ù¹éAò8ò™°00a–þrOÒ9?›G¤®®­n¯y÷£¹ïÊd² æ£G‘_qzG§¡†@ü›fC ?=·oƒ9s$mòÓós,Úû„”ššö©ªªWQQxý:óꕽ]<7))7+»pÕÊ™_1ïãǯˆ…BÉR±“&9vñ\AŽzÜ”““QWW*-­QQQhkkß²ÙõGÛ ü 45ee0p ¤í€@~z$ü6_YY‡Õt¢²§O£ÿÜ»bÎìq›7-‘¦T× ÓŠ!3«àÅË/oï [RUUš0kÖXôãäÉŽ/c©TZç½s÷¥¢¢ÜF÷yóç9ïÞµ$;»ˆËåu6××Ù ü²(+ƒ‹%mò+ a7ŸÕÒBßçulšY³Æê‰•Á`õªYÏžœþ K.ýó`¡ë$þ–©SFx]ðïâ¼É**Ÿ«ÃmÚ8_Ì\_g3@ ⑤›ŽNÛ±ó쇒ªÌÌ‚††oÉííÌÿ€°ÊʵÞÍÍ îû‡ÅĤ£q8ÜÖ-Ÿ—¾‹‹Ë½}ãâ2Y,6‡Ã‰‹Ë|ñâ5‚ Ù55 ííÌׯ3BBè_Ÿ=‹f±ØII¹‘‘)mmíY‚ ÈËÀØ¡CÿO¾m̘Á‘ŸkfP©4nç•1ÍÍ ŽŸ¸[RR…~42ê5mêá¹ÄÛÜÚÚ“‘Ìår£¢R#"’9œÏ•åš›éAAqùÍÍô;w_dg}Õ¿@~Y$éæ9®ŠŠBk+£¡†Ö\ÿð¡rÉÒý¦¦}œ' ¹vý‰Ï½ €½½Å¤‰ÃFŽYÕ[ò’¥û_½J51郎pò”÷™³÷~›6’ÃáN™¶AÀ›·\æìôö LHÌv[¼Ãá†G$-_y€  ¨¸ü·™ÛþÚ™L&‘HÄñÎëÑòq–TUÕ+(È kâ¶´´ÕÖRÑV6®§Nûtvu+WÌèèàô5šf9hÞ¶í§‹‹ËQ³æo3›Ý¿aã±+Wê•–UÏw݃Ž_XX:cÖvcãÞñ Ù“¦l;Æ.3«à;ÿ A ä'G’n~ìX;UUEËFNNöhÉ×õîžóç9ëëë((Èýñû²]»ÏUTÔâñxïïÂÿY0ß9;§hì¸5ÿ\~ÈÎ.úûèãÇ6ÉËËjk«ÙÚô#‘ˆ+WÌÀápÚZjîæyß9$//‹-¼“HÄ%‹§’¥Hë×Í4Ètøp«õëæ¸-Þ‡ ˆ°%u"‹Íkk«UVÖ£Çþ~Ë–NëìêÔÔ”R’îøûy qððQ„Íà…))yÂW-ÞfUU¥En“ó JfÎÝ«—ÖDçaAAqèŸþ¹üpØÐFF½V®˜‘””K&K¡åw!ÁèA ulvGxx²‘‘ú‘D"jjª¾ŠJ¥ÑZq8ܨQ¶GÝÓS}ü|îþÝ‹ÇãED&êIKS&&}Žþ½=A CôtZ¬ÊËÈÖ¹yï°Ý~¨T`/€Š²bsóÇmu‡Âb0h´V …ìââtùŸ=-r›|èȵÎ:‹±‡Ã)+É£íÒÒd&“¶÷®¨¨P©ÍÊÊ ² üLìÙ²²$mòëÐSÜ|LL:€'‘ˆlöç½g6»ƒL–º}çEuõçÐúÙ.N22”ÖV†¬¬4æóà/À*ƒ ÀJÑc–TTém áSèm -­/TnEñð¼…ãñx÷ sËËkú`âmYäÞi¬‹Õqæì½³ç|ƒ^žƒ ü_öv,,$mòë a7¯  ËhgÞ¼}O æÏ›ð:6ýSm-µ©©Åi¬‚ w½_b§´·³úöÕUT”›2yxMMCyy Úþða›Ý|ë/ð@¥6£OŸEO›:BYYAÀ€NM UØàòòZ]Ý¥rïÜ}QPPÒÙ¥å”$'çòO:lè@á«Æ,ìÌfc¬OFf낉›6Î÷8ênkÛ¯33 Ÿ‰çÏÁêÕàÛ @C ~û÷ïÿ~£qÁ•ë`åÔ®Ÿ '+ãw?„Ng˜™ê÷é£=z´­¯_HIIUyyí…‹§Nn54았”SQQ÷î]@ÚÚÆcÇoïܱHWWC^^Önpÿƒ‡¯I‘H1¯Ó)²‰qï?÷]JNΫ¯§ik©éè¨WTÔ:|-#£€B‘B«ž>r]IIžÁ`†…'¦¦¾ùçâïhÍuKääd|î-˜ïL |~b2YÂW¯úXÇvŪC*ÖVf"/íéÓèŽN~A ‘HÌË{wëöó#‡× Ï¥©©"Æf]]ÃG®ge²Xææú^ÉÎ)nkkwp ­¥:rôÊ'ïž:ísõÚc:½ÝqØ áŠÿ×^€U«$mä{°u+رÈËKÚä×Aò…h;:8--tþMnƒÙÚÚ¦ù)®ººAKK•Åbgf²XlsþõmAª«ÔÕ•±wñPd†”¼N&K‰yùÿÛϰäÔios3ƒ‰‡a|ý‚i4úÚ5.]™¨ººA[[J¥egËËË dB$~¶Pøª»‚ 3fm¿p~—®®‚ õõMK–í_·fö”)ÿnÀŸXˆö× + xxÀ²³È÷Eòb·$QÀÛÉÈPз^mm5…Bvp |:‡ÓÑQïâ\\.—Ëåutp´´Ô¾hÉÚ5.»÷rvо"s¹Ü°°¤ ^»º8j¶ªªÒèѶ_œ«»p¹Üš**¿ƒÃá44TÌLõ¿z4¤Gœ 6l´ȯ†äßæÿ5˜LÖßGo¾ŽÍ°µ1ß¶u¡HO/@jê›´ô·è*ý‘¿¯O™<|à@“oi—ÈÉ)¾ç¬««ÎbuÔÔ4 `ä¶pòtѾÍC H'ü‡Üüבœœ;p  ‡ÃÍË{gg€{$ÐÍC ÿcï¾ÃšHÚ€OBè½I•Ž€"(vTÔ»¢‚½÷;˧çaïb ö‚" ¢¢ ¢ ¥I‘Ž4é%Ô„$¤ì÷Çz¹\€°pâû{î¹'YfwÞݬy³³³3t ûíÿãðÔ..Ž ÇøéüWž›À7iè± ÍºU}=Zµª»ƒ Ç‚4èVAAhРî€ ºàº›.\@/^twôXp5è>ïÞ!gg¤¨ØÝqÐc}Û«yBÙ.ÿ¦Ûô\ÞÞh۶ìÛ¦y"ŒRÒCÄÄ §OÑþýÝèÑh4TW‡ìî8èÉ Ñ´§¬ ={†Âº;УIJ¢gϺ;z8Hó =©©hË´s'ª¯ïîPtÝ·ÓôÖÖèÅ ‡®_G·n!‘î@WÀÕÙÔÔÄÔÔðúúúÒeeeoܸúúõ›;wõíÛ÷Â…³ÞÃ΋‰‰õñ9gmm¥  _QQ9bÄðsç.œ={FVVö;ÖŠ ˜¯/ÚÝA€Ÿ\]æëÛÝAü¤ZÛýÃaÌœ9}ãÆu_ÂfÓ.t8м£U„ÿïÊ߯߇ÃPSë•——)dù={þ²±±æ¾õò:6`@ÿºº*üíùó>“&¹t-ƒ‚zøðwI}}õ°aŽø¡;s椛ۜ¯ßß/þwú´×СTjwɵk—BõõÕ]ܦ••0'4Úƒ/1¢»#?¿  îŽ §ñõ½”‘‘yèЀ/!‰^^ÇÄÅžrË))ß`¶* !!!|yQQQî¾ „-òøð!=0ðþvùò¥=èZ$bbb!"ñŸ|§  0¾[}}=BHBB¼k› ð°°gsçÎÇï§|øðaÇŽ?¯_¿"%%Å-³`Á|[ÛÁøë3g|vïÞ[WW÷Í#F{ð%FFÐb¾ ›‚‚¿wÇñsb±©/êÇ.]ºO`\òòòãÇ·?"5‹ÅzýúMmm­½½ŽŽNuuucc#¾ŠŠŠJvv¶˜˜˜´´tSSÓºuRRRôôôÚ®ÛÜÜœœœÂd2‡wŠŠŠf³ÙNNÃHÉápÒÒÒÈä:‡!¼ÄÇ'”••õêÕKRRÂÒÒò‹ûÝÔÔ„Ò××CÑh´ÄĤ––g籂kollŒ}«®®f``ððá# ‹æææ|[öñ9·zõʱcÇ`í=h–œœœ••mff:hÐ „Plì[2™>¡íÂW¯"ZZZnÝò»uËïÇt]]]|ù_ýYUUµk×îE‹vTW»ëEE555„¤¤$NGaöøqÈ AøŠ{OáÏ?wüþûVeeµI“¦hjjtT—‚‚ü¸qÎS¦üvꔋÅڵ˓û'ÞÛöíÖŽ266Æ ™LVTTä^%ãz÷ÖîׯߴiSð%!!OøöTVVßSÿ»NNÃ( ^©© ^FRR’÷5FÃ_ïÛwàþý¾¾ç¦NuåíÀei9¨ÝÏ+99™Éd¶]®¯¯ê”—ÍàÑ£Çá·Wº îÍ M¸í°µíîzàî>?8øáš5«xóB(&&ÖÆf0_ysóóæ¹ñ-g³ÙÖÖV÷Þ¾}7dˆ=ß_ß¼‰6lhGë¶MfxŸ;¬½ÞÊÊJ……yééé÷î=pu‘››Év[††ÁÁ:úk»©tôè‘QQÑ'Ož®¬¬ áë¸À5wî„™L®¬¬ä]®   ¦Ö‹»§¼»Ì[]»UïÛ·'6öíêÕëôõõ6lX§ªªÊWÀÝ}¾›Û‚ÆÆFyyyÞå‘‘oðN¼8NpðÃ7n1<;;·×^@šïŒ¸ Ýàc»¼ÝÅ{öxÚØ ¹råêâÅ‹¸ Þ99µs/ßÝ}þéÓÞ[¶üŽ'×€€À™3g°X¬½{÷¯Y³jêÔ)®®3bb^khh „äää B™™YÆ mw]¼5ß8o^ws›óúõ›±cÇ „šššÙl6BhÛ¶wîÜ277777}Ëb±DEùjåÝ&BHII)''‡F£µ¶¶ÖÕÕñÕØníÉÉ)nns&LÏ÷/Ã÷ûãäÉÓãÆ9ónmêÔ)Gojj›<vq™ &&&LÕ¡!Cì‡ ±OIIÙ²e»²²ÒÆëµ´´¸0aüŒÓ׬Yóæ5îÂâââ^½þõƒ€Åbݽ4qâ„»wo‹‹ƒ§D<==¿~+¿__´tRwøÅ\ Aí C"‘æÍ›ëçwçùó UUÕ÷ï?PQQqttl[¸oß¾ wï°X¬gÏ^ØØX§¦¦-[¶"..~ãÆõ’’’—/_ ºO"‰XZÒÐP¿t銄„€,,,Ú®K§Ó÷í;˜ššÊ`0ÌÌLwïÞ›–öJ¥ÚÙÙŽ5òáÃG……EõõõOŸ†¾}û®¸ø“Íà§OCÉä: …òúõ###;;þÖ“'OÝ+,,¢R©††òòòúúz~~wôôt£¢¢555ŽóJNN–ÐÒÒì¨v u'§‘ÇŽ8qâäÅ‹—)Š££CbbÒ‡’h4ZiiilìÛ§OC=~åÊõ£G½Ÿ|æŒOVV¶¢¢‚“Ó0 ‹F‹‰‰UTT455õôÜùº¡¡qàÀׯß|ôèqMMm¿~}ƒƒÝ«®®éÓ§&Ïä^êêêS¦LÖÕÕ9|øèóç/LMMÿî|êâ2¡¢¢âرòòò4-44,?¿`Þ<7¼y€Á`\½zmÿþƒýúõݳÇsð`kR{OXü›È— S×t‚µ5\Í~4þçÁø´´´¤¦¦‰ŠŠš›訙Çb±ªªª455¿Ø`ŽaXUU•šš·¤ðë"„¨Tjkk«¢¢bII‰œœœœœ“É$‘H%%%ªªªÂ7AÓéô¨¨hcc#ü¹¾/Æìê:ÝÇç´––†a555‹W­Z1q¢‹Õq·SQQ¡ªªÚ¶½¡³Š‹‹½½Ïnß¾UII‰»Åbegg“ÉuƒYðöðñ9§¥¥9yò¤vo ´ÏÚ^˜Îöæ…iðã})Í‹ÅrttŠˆç>öiÓï#GŽèlšÿ™—æáÞ<€Ÿ‰Dºxñüž=û´´´ Fee¥…Å@— ÝW÷ƒ4 '0`ÀÁƒº;Šÿxnè± ÍÀ̾¤yøkoL{vL{Hó@iè± Í=¤y Ç‚çæà¿ö¯·,6rXÅ_†oŒN _÷“•i;IOÛGÛ–iÛ ­íl¢¿N™öÀ`·BƒÁn {Ù.2·.h´z,Hó@iè± Í=¤y Ç‚4ôXæ€ Ò<ÐcAšz,Hó@iè±`êþ‘—÷éÈÑ…¥¢¢$%EyIdõª™^'ýzLvv¶ïÚ6Ý=þ**.¯ªª“‘‘TWWa³Ù ÍZZ½æÍ0yò0"±ÃŸÚiiyóüYQQ{õò_'íê>}†Íž³ýSIå›ÈK¢¢~i\¿²wߥººÆ‚dùvœÅb±Xl}-÷,¸k½~´pñîûWÏžåüCö€_ \ÍðÙ±ã7û ˜)''ý(Ø+ì©÷m¿ýÇmÜåyþnà &“ÕåÍ^¿¶{éלÜbS½G'CŸœ‰z}IWGÃuúïÛÿç-`Essãý{WÕ’X,v—kÿ&8NTtJJJ.…Ò" ˜û‚‰¿MvªohÆßòíxØSïG'ÙlŽ£Ó’C‡¯q×ÊÊ.,,*OMÍû®»À/ Ò<!·eë©Q£;ºAZZ_¨ªªx÷œ¬ô·­‹D"-]âŠò:y»¥…. ¤¤¤ø·­ºkDDDÒRü³3ï)*Ê .)8` ñµkf!„öî»ÔÚÊÄ._6-õý½{V|«h¼ Ñ„Úwà2†ÐìYÎw¹œœÌ‚ù.22’Ü%åå5‘¯“JJ* ´ûm¸¨(©¼¼æÙó·T*mú´Q”7QÉb¿Mv’““é¨:‡ƒ"‘DDDˆ¡ÖVæ‹qÙ9EÊÊòCë´]åáÃH:£•Ãáö<¸_c#åÉÓh"‘àè`QSSÿ>9›Á`®\1=&&55-W§·úøñCH¤ÏÿÀkk""‹ŠÊõô4GްVVV@%'gs׊MMûðQ§·ú¸qöL&+$$ª²Šlg;ÀÚº/B(##ÿ]Ü*•¾l©«„„8†aQQÉiòZZè†Ú..ŽÂþ©¯oF©ª*pÿoß kn¦ÖÕ5nýÅ#™]ô.îÆbo^SSŸ˜¹Ðc’ººŠµð ‚«y‡Ãyÿ>!Ô[[­í_ÏœÞ2|¸5þ:88Ò¬ßô††æß&7Øv>•JÃ0,""qíú£'¼üBÃb-™îÙ{ÑeÒ†Žª£PZN¾ƒòük™¸¸XqqÅ «¹Ï_¼›è⨩¡:bÔò£Çn´]KBBüÏ]çÜ=<9 !D oŸ»IIYÅb_¼¼eë©}û/—WÔ˜™êOvÝ´{ÏE|ÅgÏÞö0£©‰â:eD]]cßþ3ÂÃãB¼k•–U›™êMümêՇ¶l=­¦¦\W×4ØnATT2BˆÍæ\»²~ã1:½!ôèÑk§‘Ëde¥§ºŽ¼ríQ¿3kjê^r]cbbfllêÍ[OV®>8z”Íã‡'¹?§ª«ëV®>ü0!$øHžñö·µw×ÒTík¦?bÔò³ç“Þg½|•  j¤y‡ÃÁÛô/CQ©´EKvj¯Z9ÃÔTïÄñMiiy/´´zÍœ1!D¡Ð6¬Ÿkeefg; :&…FûWƒ|Dd¢ÇBÏî»Üþ%%%ñ.æÚ–?ÜBë7ËÏ/=rx‰‰Þرvî“¶n;–ƯÚÙÙ~Çÿ3Y¬÷ÉÙ! CD"ñð¡uZZ½îf€‡ IDATçè`Am¡÷é£3sƘ‘#kkõ ‡¢Ó rmÉâ)g¼ýW¯šÁ×QßÊÒŒÆ@edT×ÔTSæ–ÑÐP‰‰MÍÎ.ânŸw-ccyyî.àácjª·fÕÌ3Þw[ZèxÆFJ{Çõ3Cm÷I¡…“uô\-Ù3vŒ–V/«´{$m÷‹ŽIa2YD"¡¤¤Š[ ¤yBhíšY <þ Žœ5s,¾äêO„ÝÒ²êí[Nœ8´°° !db¢»oï*¼ ÷ŽDél½AZZ’Û !Ä`´"„x{p‰Š’¶mõX±êàù AOCc¢^_â+Ð6|;­LAÛç]K˜]X¿áØ¥ËÁ!NŽ98::å¦ßÓ/®‚ÓÖV«®©|$ø*¼Ý0fÍ+//³~Ã1î:eÄÖ-îBÖ À¯ í@¡yn/üÍ?àùé3þxÿ8„“Éâ½ë¬§§9~ܨ¨dîÂààÈ+W~eÕ‹N®«oÊÈÈGa¢¢¬0Ñ¥ýå=Ü'ij¨lØx|ù²i""_NÉÆÆ:C&$dâíÞT*-))k¸“•¾¾V×¢Å0Ìïv¨©©ÞÈ‘ƒBÙ9Eèï…ÂPUU@ÅÅ¥#„¼}î’É ÂWý*"AJJbîœq«VÎp›;^JJâËëðËñôôìî~¾¾hé¤î|/aòd'ë¾>çΊŽNyñ"îèñ›¿Mv’‘‘²·372êM \&8ÖÖ6>z=!!30ðE]]ÓÆ n))¹Ûwœ!“ ‹ÊLMôž<¾ãÿŒÖBŸœ=cúè%K÷†<‰ª¯k¢PZÞD½ïc¬£©©Ê[õ°¡–â⢇^OHȸzí1…ÒrûÖ~­>þ±õTmMÃÇüóFx+7‰$B"‰dçùžß÷ÒG]¿råêC*…–ö!o¢ËÐÍ¿{%&eR©´êê:ç±ö]†æç—zŸ ˆ‹K?íí?غŸï…ÒÒ’|kmÙz*>>ƒBi©¨¨µ²2óXäYQ^[UU§¤$÷!ý£ïÅûÍÍ-9¹Å3gŒQQ‘õ*!&&%##_VVšH$?Œd±XÅŸ*ñb§ºŽX¶|¾ãõ Í/_Å[[õUV–×é­•ŸÁ`´FǤ,ô˜}ÆæìmÏž½ý•~o,«¡¡ù{×r7à9“ _ƒ?ô´ÿŽh4ºçn_„±±•Jc±ØÃ¬GìÛ»ªSÛ©­m8uúNDd¢’’œ£ƒ‡ƒÕÕ5*(È®]3KVVºÝUJJ*7n>‘›û)-Åÿì‰Ð0 Û·ÿò‚ù.ººÂvÂëÖËW MMÔ ãˆDƒÁTR’ópŸ$##…—‹KOMË]¶tj—CÚàòüy.]Xñýûì7C¢cRY˜icjj¢L›:ÊÊÊŒ[æ–ßS-Í^#FXwvãÇOÜŠŽI¡Ri£F£Ó[óò>å”úÝܧ¥Õ« Ñþ0†]¾ò0..Ý¢‘H¬«kœ1}ôî=ýníë®xº*##¥ªªP\\©¤$G¥Ò6npfݯ9»)3¦ž=Ë!Ô×L¿²ŠÜ…¶c§O~~©©©ž˜˜hLlªŠ²‚™™~}}SÚ‡¼­¸Þé³N€¬¬B¯“~ƒ÷“‘‘ÌÍý„½‰_¾¼xéÁ /¿íÛ<ÌŸ(d]CìÍŸ¸µm«ÇWE „iþ{!“†:-9°oÍ”)Ãñ%ÍÍÔ!Ž‹FÜÙM©¨(ìݳrÔ˜¦&z[þpÇž:}ÇaèâØè+܌ȫwouÏ]ËÆMXû{Ð FkнpG‹ŽÒ<_`›6ΣRé!O¢¶o[ˆ/9yêöÇE¯#|åB)©9OžFw9͇…Ū©)õ–¦KH Ù»{åøñ¡ššz‡¡‹¶üá¾dñ¼Ì‹qffú]Hó›7Í#“ž½ÝºÅ_ÂápþØr*/ïS§ÒüÕkzLîlí]†aØì9Ûµ´zù^ØA BgÉÒ½™ù?,>7n>‘——Y½j&þvÍÚÃzzšøë²²êŒŒ‚±cí:Z÷+Ï®.èÔç•StåÒ_òò2¡¾ý§; ˆ§Æ‡#Ó3ò¿ašþüÝÿvz¿|q¯ !äuÒoƬ­AGðOY€¥K\_¾ŒomíÄÕyïÞê22’ÑÑ)ŽŽ] í¿—5k uÄÍñ!YY飇×wyƒ¢¢$Þ׋NþþñÉÓèŽÊKHˆw¹®.“OMöœöø%ñ~•àûŽ¿]¾lÚ£`¯.Çãs.`Áü®\ÊãDDDDDˆÜðTU'M¶ë¯óÜׯíîòE‰˜˜(‘øÏމÄ-,(*®~ µ))¹]«]HÕÕu;ÿ<{åêCü­ïÅû™‡®å"‘èub³¸¸Bð+\½öèG6ɾ|¯¤$Ç}»~Ýîë˜ØÔ¦&Š€u¿òìê, ÃBÃb…/?Ä~ 7ï‰Dî?ÿÉ“èôÖoUs3uɲ½û÷®æÖ…Z·vöÇ%7n>f ]øª™?ÏeïþK] t ¤ùïâÓ§Jÿ€çî“ø–a­¦¦Ì}ÛÐÐüèÑë‡#ñ/£²²ê—/ãSRršš(OŸF¿Ÿ-  …†RR”CaöömÚí;a>|l[²¦¦>/ïS^Þ§òò„PiiÕÇ%ÅÅ‚««®®{ð âñã7Üû¯±±©¿a0ZSSsÃÃãZZ衊ŠÚ¨ÊÊZ¼L^Þ§gÏÞ–áoY,Ö»wün‡~üX"ä¡kj¢"„ôõ4B4=**™{ד@ZZÞ“'ÑõõMܵ)¡¡1ÉÉÙ”7CÒÒòB……e"""ÜÖŽ´´¼§O£É䆼¼Oéé¹»)d`ÜŠôõ5¹ë¾z•¾ôÙ}úTùøñ›â⊼¼OW®>¬©©çÛ¬ßíЖºššò€þF4:ñüù»»ÏKJ*B99E‹<++kSRrŠŠÊñ2mÏ„ââŠ/Þåä‘É ÑÑ)'+«0?¿43³€Íf·¶2³³‹rs‹©T_H%%•›÷Úþ?ï™3Æ,Zø¾ðð‘ënsÇ‹‰‰ò–”——?nBˆ@ œõÙ&'+=kÎ6Ÿ³4]ø[]]‡Ÿ¥µèï³߯–:÷$lËÌLÿè±›Ü#`dÔ{ò¤a¡×¯“þØrª°¨<%%§¶¶ÅbÅĤ„„Dᇨ²²ö+ϮΪ©©ßºítRRVJJ÷ô¼kC;¸Ø%Ž¡ääìÛwÂ’“³Bmw°¹™úæÍû—/ãÙlvDDb||:›ÍÆ0,3³ 44ÿ÷‹ ¯¨¨ùïVF‘Ñ£lOxÝBíBx™Â²ÐÐ2¹/<ÁQáeäåeDEIµµüë‚ïÒüw‘˜˜‰jÛV,..ÆmÎÈÈw›¿ÓÖ¶¿µußi3¶ÔÖ6P(-§ÎÜÙðJн—66ý½}îúœ hwûµµ [·^±lÚèѶ­­Lw¿èôÖéÓFefüþÇI¼#Ws3õÐákCáß\YY…&®ËÈÈP]XXìî=¾£GÛXZš®ßp,55!TXTþ›ë¦›·ž2™,]] Kk·§O£óóK4¶âç˺º¦ ›Ž¿|•€ogæìmRRcÇØmßáô÷z[xÿ©ŠŠÚèè”]÷»¹oÌ;„‹Å·xé¼Àµë™L––¥µÎ@åæ»NûÝØX'ömÚ„‰ëF´IIÍAžM³؇[KUyéò}gÏåäÛ ñhme”ªiŽÅó´M”ššúÜÜâs烈DB€ÿ!|9•Jó9pêô„€ƒøÂs÷ssã½û.=hl¤ÃýÔÚÊ*-­ÊÎ.ºrõ!þíieeÖîA+-­ï²NVVÊuʈÕk¿|O¥Ò5ÔUèŒÖÚÚ†ææ„P»gBSõðÑëÇOÜz·|åþ·oÓ²³‹lìø^¼Ïá`,{íú#§Ïøs»ˆ"„>~,Y³öð¡Ã×V®˜~ùÒ.ssc|9™ÜPXTÞîÏ¿>MF$§Mu/ð¨‘ao…žGÝÆx57·ì?peØð¥øYš“S>!»Ö£â–42Ô~ù*¾ Gt¤ùFG‘H"ʬZshîœqjjÊZZ½F ·¾t9ØÄDoü8‡ÌÌ‚…“UTÆŒ±åkâ‹‹O?!ÈÛç®ÿÝg7Ì=wv;@8yê¶’’܈Öbb¢³fŽÍÍ+~ð ‚w-íãÇ62L¼¿žšš²÷é­&8vT…Òâ±ÈsÏî²²ÒZZ½Ö¬ž5ß}†ansÇ«ª*ÊÉI[[÷56Ö!W8:Zôî­®««ñömBÈÖ¶¿å SnÕ*Ê l6[UUq‘Çä#Çntt(¨TZbbf\\z`P8ƒÁt™àˆ/—••žç6[ @QQÎÊÊÌÌL_LL4==!tþÂ=‡!Œz/]â—...†÷*-­RWÿ§ídÌ»þýZ[™'Íɺ/&&ª§§ù<ÔÛÂÂDð§™—÷)))ëUDÂÃG‘Æ;rïëëks‚¿ðÙ:|Ímîx]]¹sÆ…¿Œ:t÷ë›Bi‰ŽI‰ŽI)+«|Ð6n>1vŒ½½¹˜˜èûrrÒ––¦FFÚ½µÕF¶0À!Ôî™0`€Ñ¨‘6YÙE³g9‡??gg7ÀÕuÄÊÓi4†¨(IJJÂy¬ý™Ó[””äB>|\ºlßù ÷¶mõðñÞÆ—Ññ†b’ˆ ³G œíïúbo¾jõ¡Ý{|ëê¯bh¨íubSK ï“¡¥ÕëÌ©-£FÙ „þÚµìØ‘ ­¨¢¢w#Àÿ½Ý€{÷_Z ž‡ÿn5ÊFYYÞ|€ÑèѶÚÚj¢¢¤¥K\ ‚†ºÊÚ5³oÝØû•gWgéëk ¶î'##5z´í°a–øBÁ»&@DDbÈ“¨˧‰ÄMݾF ¾TVVX0ß%+»è·ÉN½{«Oïàw'ÌÊÒÌȨ÷èѶññxË…ÒÂb±ÛVÁb±Yl6ƒÑÚöºzíQnÞ§õëæ¨©)O:ÒÄDOø¨¸Û×ÐP)+«î¾ƒÎ‚4ÿ]à©®¤¤Š»$""ñÏ]çú˜ºÚ;x„…Å2­11©……e·üžÞò{Êb±ee¥B21ÑÅo|JJHà×\ýú¬X>}ÍêYkVÏôw6 ‹åý:66Òi{Ã^AAvîœqçÎ!„""ÇŒ±Å—·[]RR‹ÅVVVø¼AãÞÒ?––V!„‚éßÿ¤%%Åy_Óþ•·ËŽ×‰ÍIï³OxÝzýæ=þÒ.Ùqã†L™2üÔÉßY,ïÍo¾@|à‰ÇØXLnTT”““ûüô™ÜÈw×@@ýú „ðTM$ÇŒ±k{ÃÇÚªï¸qCV,Ÿîu|óô™[x›ÜyÃëè³36ê]ZVª®©30Ðâݲ’’ÜìYÎKOáí@Ðö aöüù»_UoÛê1xp¿¶qvt&„~} B*"""¡˧ùß}^W×øéS¥¾ž&sUÙyüšqÎöG¬×ÖVk»}MMÕ^ªŠ¥eUmÿŸÞv!BÈÁÁâÒÅ?««ëx/ã:¢¨(7mêHß‹÷BÏž¿0Á_nh¨mf¦ßÑZ ÍâÓ§¾p~GÁÇG æ ºé‹aXÿþ†¢¢$üÞÙל]ß„à]àUD‚¬¬4þíá÷¹““~¯í**Èâ¯%%ÅBxu¢¢$I¿«baaR\\Ñö)ļ¼O†Úrr2¨Í)ô8$jÏcñ¿oâNII¾±QPÏ ð­@šÿ.LMõlmú?Œä.1Âzïž•ZZ½l÷7n~!5f´Ý<· óÜ&ìús)·«°0±ðåý'ÚÚÊÄûCñY³zæÅKÊËk””äx¿ÝÚV'..ÖÚÊä¶üãçnóß½ÆõÂml¤Œµ\]MyÓÆyø:~3Xðîj¿' @ÛJG²a0˜'OÝ>uúNè“ÓÜ;ÇJJòJ _aévL’¡¡6›Ã‰ˆLì8¶v>»I“†¥¥åñöONÎñ=¿£Ý·mõ––D4&“%--) ×Õ›7ï‘À3ïq mm5ggûËW†<‰š<Ù _¨¦¦œô1¿dƬ­aa±|·~BÁ}ÁÄà‡‘mÿ›Ú6**•vòÔíYs¶eûø¡P=ÝV®˜î{ñ~CC³¤¤¸ˆÍ¡C‡¯q_‰Äµkfñþ¼ÆáÇ×î“)<[öìú¹¹ÅÜ»Ô]£  «¦¦„{Ìs›x÷°‚‚,þ'¾ä;'Ûž¢“' ‹ŠJæ]Èáp^¿y?{ÖXîÞÍJˆ‹µ=:BˆBiQWWfgÁW‚4ÿ]‰ÄkW<ÏxßÅïjã0 +.®À3,‘H\0ß…{ÙM£Ñ=zÂ0Äý÷Ã÷‰÷O¼æ¹MˆŠNÁ_s8œè˜·¹ãðÕyË÷ëg8p ±û¿¦ºŽlw›Ü––¦ÚÚ½¸ýŒ"#“œÇÚõê¥ô÷6y×ýçuÛm¾y󾩉:qâP„PYy5‡Ã).®ˆŽNá Œï­’’|NN1Fol¤–µWøŸ×ø‹ä”·¹ãׯ›sèàZkë¾Ü††Úx¯ÃŽŽ!ƒÑêuÒOÀÍcìoø[11Qi)‰””„þÿ6¤Ï.#£`ó¦yk×Ì>|hïÕ †aÎçbDâçþü´ynã_„Çá…)”–Çß „äädðŽT™YHè3·võ,oŸQQoc†œœÌÖ-7¯ïù˜_2}æ–ààHn+ÜžÝ+jj¸ïqaa±Nìx—46R¼â¾ð¯¾fîsuÁÍ.EEå|«ó<¸Ÿ¦¦êÂÅ»yÏRÞŽrmeçñ¶%ÉCþ½;Òøí3üøð}šmL§Î®ŽØA99iüóJKËÃÄÞ5^‡÷³˜ê:"99‡ûÁƒøOs;ˆ¿àþŸ»\OOóÐÁ5Ûþw†÷7¢ßíP:±sÇâ¶ÛA¹ÍÿúÍ{î¦J˪Ùl¶ðQá>}ªÔþoÑcˆxzzvw ? __´”¿ç¼** ӧܹëlQQ¹Œ´d~~i@`ø´i£‚½½9BÈÉÉ*882+«\Ûðìù»iSG&$dzûÜÍÎ.’——a³9^§ü22 dd$uu5Ž»ö,¶²’ÜÐÐ<ÄÞœ÷'ù€FŸ>U> i¡ÒÏž œ1}ôD—¡¥¥U{÷]JJÊf±XÃ>+ÈË´¶2]\†âo££SÚ­ÎÆ¦ÿØ1v‡\§Ñ‰I™/ÂãÎzo“––ôÜ}!22©¡¡y ¹ñõ!½®©­ï×× øadPPxuM}cÈ×I·ï„–—ט0îÛ×àAp•J+**ûþ±¹™jeevìøMn`'Oݺ÷²°°ŒJ¥jËËËèëkùÝÓÓÓˆŠJÖÔT=vüfrrŽ„„˜½½9oW®>zò¦¡¡¹o_S]§K¿yÂËï⥠ÍÑÁ‚@ ôÖîuö|ÐÜ9ãðý½t980ðEiYµ¤„8ÞtYQQ³pñžÉ“†á?bø$'g;~+é}6¹®@@ú!„˜LÖ‹ð8G‹ˆÈD“uÆçnNn±¶–ZmmC»ÓÊÊŒAoµµw?ã}÷Øñ÷î¿RUQ05Õ;vüæýEEåÍÍ-­­Lnc»²²|Ûƒ6iÒ0ggûçÏß%§d×Õ5=y3uêHII •KW‚%$Ä‚……I»gBxxÜß{99E--ô!öæÜ½ÓÑQ|±g÷J)) ¾%ÙØôŸê:2>!}ÿËÇÌT?åH$Ò<·ñ~·Ãž?«  [UUwÿÁ+EîÐ55õ‡_»qóÉŒé£ß<ßÐP›¯a<<¾ÅKLL´²‚›ÊëáÃ×L&+;§ˆD"edä_»þxÿ¾ÕøNÉHKùß}F¡´˜šè©©)ý¹ë\||FMMƒ†ºŠ¦¦*þo¤ËgWAAY Þ¿¿B¨  ŒB¥á}ì ²²ü‹ð8Qü©bܸ!_Ü5Üù AAቕ•䊊Z"‘¨««¡¨(g1°ÏƒW†bbSdõô4ùvðÓ§Ê}û/§¦æ2Ì~ý ‹‰IÑÐP10Ðî(0£UøG±+*j54TÈ䆴´²²R}H¤>&“ÕÔDéò àì «%7à£à…‡ÇUV‘¹úï`MM½¢¢,o]†aXEE­ªª¢0§âáçguuÝ A&Âü«g±Xdr£ššrU™DQPÅOTa¢*)©Ü¶Ý»+#'Ú.G‰Þ5í‚Qð¾;%%yÃÅHII´½œê‰Ôn·)„PhhLLlêÞ=+ Ëðä'¤o’¹7ç„ïs !!Ž?P' 6›]YIÆH!½z)q{Q!„v{®¸~#dÓÆyˆøKLLôLxª¬¼¼F\L OZD"ÑØ¸·ºº ·­¾#´¶g @à»Á)àLÀMþ»×ñÍ99Å£FÚ|1~‘™3Æ´].%%aÏÓ6À æ¨ýÆ?¤l».ïF:5ÜŠ†† BHYY¡Ýe¢¢¤¯9Ÿ]¼ƒ_ÿ›ž‹@ ð^Õð¬' IDAT%"‘hf¦/|—@és—:Þ[QBFuér0÷ŽøÞ Í÷|&&º¯"NŸñŸ3Û¹»cùöH$ÒÅ ;÷콤¥¥Ê`0++k-,ú¸¸|~$ÏÔT/*:9>>]À#ÈßÕ A¦3gŒöÜ}AMM¹¾¾©®®éðÁµ**ß²u¡³l÷{«ª¢Øµ>Þ_©¼¼ÆÚªogû™vÁgWk+“Áh%¼wµ®ìÏŸ¿ëÝ[½[N¿_4Ú ­«ö ÛÁèÙà›ËÊ*ƒFû΃4/4Hóн Íw´,=¤y Ç‚4ßÃUVÖ>.hP¹o¥¥…Ž?GÛ5L&‹LnÀo!±X?nSÐ)J w4!ø˜ø)Àð8Bëäð8?ÞÅKæÍÿSNNjàßÓ²µ¶2·m÷^¾l*‰Dªª"=vÃÑÁBDäË¿íââÒŸ†F[Y™ _»¨(©  ìãÇOÆÆ: ;&&eÛö3¥¥UÅÅ¡¡1$‘ž3Ú¶Ý!{xð bÿË]),,OIÉ {ööá£H)õŽV¹xéÛ¼rrÒy&²û¾xxy{ÿ>ûð‘k;wMHÈÌÊ*ˆŽNy­  Ë}f ð}û/ëéjpÃûæ0 »|åá¹óAUUäéùÏŸ¿UWSÞ°ñÄ´©#¿¼2ß Óyð@ÝÂÕkzLþÊ,]âúòe|kë?×Xž»/¬^5 ¹´´:èÞËõëæ˜—’šóäiô²¥S;¶‹‹ãê5‡lmû ÿ¤òoÿÀ ð°§ÞÜÇÁ¯ß¹u;ôÌé-BnËÕu„ŠŠÂ°KßD^·V[Û`ïàñçÎ%M)¶t‰ë³çoyØñÅÃ˘¥¥éÀÆRCöî^9~¼B¨¦¦Þaè¢-¸/Y<!Ä`´Ý wt°ÐÕÕøÑb6{Îv-­^¾vàƒðp8œ%K÷fdæêß4Úw? Ãø&œí2ÞqEš›©éùø`œ!++³ŒÂäx„ÐòeÓa®‘vÞ4q˜·O€Ñ~øðqÇγׯîæòeÁ|Û®>㎺Å}DEEaò$§ƒ‡® XE¢“mß„0‡—70"wœ;UUÅI‡qçñ“OMöïúJmTW×íüó,w`vß‹÷32 \Ë €H$zØŒ7·ÔÔÔÏ™û¿W¯à™þ›àjþ{a±X¯_¿¯%7ØÛ™ëè¨S©´’’*IDD„¨¯¯UPPŠ+ÊÉI=v#))+%%‡Dáfåääì¬ì"3S=|ÂÙØØT2¹qìX»œœâ’’ª!CÌñi¹q……eÙÙE66ÿšœôþƒˆÃÿùêOHȨ®®6l>ë<™ÜÀœ’FOLÌji¡;;ÛwTuMM}»a9øÀ¡+íúܪ& „×I?{{s¾Áw ÂÌ£y' ëÔ¡àC¡´àC˜!„ª«ëbbRI$‘áíðƒÀ++«PLL”Áh51Ñe³9eD"AK«WjjnGÕaöî݇¢òýðßËʪ³³‹”•å µ£¢’ûôÑ54Ôf³ÙïÞ¥#„¾Ã‹ª¬¬‰I•wv¶r ÔÆFоþç‘€óò>”õ飣¯¯Å ÀÀ@+::E]]…wÜÙÔÔÜÒÒj‡ééù…EensÇóâRRRyòÔ††æõëæ˜ÿ=ïíá#×—.qå›™M^^fü¸!!UUÅ‹¾;}/Þ?{>ÐcÁ$G¾AìÝ ®æ¿ *•6qò99éÉ“†ýo‡wTTrk+3&6ÅÒÚ- ðBÈÛ'`õÚCÙÙEJ‹†† ›Í®­m¨«kÂW߸éx\|úìYc_„Çðº…*,*ÿÍuÓµë™L––¥µ>9†a6{ôø¥¥éë×ïãþ™ª+::…wNè’’ªß\7UUÕáoY¹ðòk7x‹þ2nñÒ=øÛv«n7l„˜˜hSµªŠüÅZB‰IYF†íŒû½iã<îÚŠ6{Ázù2þMT²Ï™­¡°°ØÝ{|G¶±´4]¿áï̸ìì"»¾ïs8‹Å^»þÈé3þ FkGÕµ¶2Ý=þ¢Ó[§O•™Uðû'1 £PZN¹sðÐÕÀ p[ÛþGŽ^?uúÎõ!&&ºOC£wìôi{xcbR¶m÷ž2e8‘H1j…€‰z›(55õ¹¹ÅçΉ„ÿCøòºº¦ ›Ž¿|•€ÂØðJн—66ý½}îúœýܸ²aã±7QïMLt]&­/+¯f0˜ÍÍÿÌÒûñcÉšµ‡¾¶rÅôË—vqs<™ÜPXTÎ;=—ç_Ëñ22R›6Î󻹯¼¢fúÌ-/ðùÊÿæ¿‹#G¯÷ÖV<¸Ÿ¤¤Äª•3ö¼¬¨(·xÑ”{Gîø?«®®“——yrÚÅÅQ__k°u?©Ñ£m‡ ³DED$†<‰Z±|:‘HÜ´ÑíÐák,ËmîxUUEEE9++333}11Ñôô|„ÐÕkró>­_7GMMyêÔ‘¼c­—–UñŽv>uêH5µæa ð?´haû½de¥¹“p „Ú­ºmØ\*ee5_¬!ÔÒB|ñÚ©CÁås6ðü… S§ýkÉ ‰ñ7-,L(”Ež{v¯••ÖÒêµfõ¬ùî»ø™]]G¬\1FcˆŠ’¤¤$œÇÚŸ9½EII¾£êNžº­¤$7b„µ˜˜è¬™csóŠ<ˆ01Ñ?Î!=#¡Çdee…1cì¾æá>IUUqÌh;üßáåp0EEY‘ñãZ[™áÏ6ÛV^Þ§¤¤¬W ENï¨õ÷$ž¶¶ý-}¾dÇÈÌ,Xè1YEEaÌ[¼ÒÆFÊ©3þ+WL72ê=j¤MttÊ’ÅSð)Ô>|ø¸tÙ¾óîmÛêáã½/£ã“Ü“„˜pH\\lÙÒ©wïd±Ø³æl¿zí‘€Ÿ,€í¿‹W‰:½Õoù=EQ©4]Ï}£ÆŒ±›“œm7Ä#åýíŽF½~‘ ++¯‹rr²¢Ph ²;m†¤¤8þýû8$Š÷’]œ§e•Lnä›ä‘·5ÕÎn€€øùÚ]Û­º#JŠòaj±´4-)­ä¾¥Ó§NßIHÌŒM›>mÔ¡ƒk;u(¸ÜLä4>))‹Åbs;÷þþ±´´ªwïuÂ_±|Z¿3XC¡Ðôõ4¹¡ÝêBÃbyû™é{©Ó0«gU”=ãN‚Âûqý; ¼íAFFR]M¹¬¬FWW£ººÎÄD/\UEv¿æÌ©?¦NÙnc»¦¦j/UÅÒ²ª¶jw¦‰4wθѣl¦LÝ\SS¿å÷Žvðc@šÿ.dÌÍx/Ú¸¤¥%MMõ|/>ø}ó|¾?åæËÉI+(Ȫ©)q×åÝïkœ„¸XG]Ÿ””ä(”–vÿÔm«æÂÃæ¶P¨-êêÊæå>â¼;)øe¥„„øÖ-¯_'Ý»ÿj·çr))‰N ÄÅÅZ[™†á™ ¿ÊlûÀž¶¶š³³ýå+¥¥%—.qåýSÛêÄÅEy¯V[[™Ü òþ€ûâ&×®?ö¿û,ðîaYYéÀ p„ÎÏ?«¦¦œtî|ÐŒY[—,šâìlßöžû‚‰Á#׬žÅ÷§˜ØÔ¶i¾¬¬ú„—_MM½÷é­‚§£üÐhÿ]¸ÏŸøäi47ã÷ãB7o=1`ìûÀÕk^½JÀÊÉI·´ÐBiiy"""S]G$'ç45}¾ ~ð O'öOBç¾r›;þõ›÷ø[ ÃJ˪¹·E ´ËËky£Âx6qãfHNNQGñó–ì¨j¾°¹…KJª´´T…©ÅÅÅqú´Ñ+Và­«øSúûz·S‡‚ûºíïKKSmí^iiyøÛÈÈ$ç±v½z)!„0ì_å×®žåí *Jâ*»Ýêæ¹MˆŠNÁ_s8œè˜·¹ãø6È{ÛÏÏoÏxßõpŸ$++aXYY ‡ƒÝò mw;Ü·bb¢ÒR))9!üÿÿ.ŒÚ­´´´z·çòukgÿµkï½99™­[ã×Qu#G þô©òihL •~ö\àŒé£'º ŽNñö¹›]$//ƒaØq¯[>|”’’““>tøZÚ‡<"‘¨«£Î{xÙlv@à yÙ°g±Ž‡¼4È$íÃGn`drñ㷒Þg“ë4 ¿BˆÉd½st°ˆˆLÌÏ/½}'´¼¼Æ|€ñÇ%ÜØlŽ×)¿ŒŒI++³×o’¦ÍØrÆÛÿÈÑÑ1ÉæŒñ:8QQ’Mÿ©®#ãÒ÷¸ÌápÌLõðV‰4Ïm¼ßí°çÏß*(ÈVUÕÝðJEE‘;é_ffÁÿvø$$dü¾yþ‚¿á|êðƒáq:f¨Zçg¨c±XUUuššªÂg­­Íd+*jG ·>w>è¬Ï¶¶SÌ vÂëÖËW MMÔñã†ˆŠ’êêšØlöÊÓùæÇãµ~ñ»Ïc¢®¶7¿Î÷óÅÃ{ñÒƒã'nýoûÂó'>xqïþË윢±cìäåe8ŒÉd-Z8Y[[ /Œaؾý—ÌwùN³Ñ#„h4ºçn_„±±•Jc±ØÃ¬GìÛ»ê;Õ¤ùÿ®ààH''K³¬vÊÕkzükÏÝV¯š«ZZZtïåúus„铟’šóäiôÓ<_ë×ÍY¿áØEßÂOTzÆÛ?0(<ì©7w°šë7BnÝ=sz‹[àÚ´q•JòæÛáK’’²¬Ï{y‘;‹.Ÿ“^›ýn‡þø>ª_<¼K—¸>{þ¶µ•…ru¡¢¢0lÄҨחðg3šó<ÌÇÊÊ !Ä`´Ý wt°øNižLnê´äÀ¾5S¦ Ç—47S‡8.5rð÷¨ÐYÐhÿßõüÅ;6›óårB¨¨¨MIù×Ô«ÍÍÔôŒ|n†³²2Ëø(äswË—M{ìÕÙ¥¥%UTÞ¼y/dÌ>|ܱóìõ«»¹9!´`¾‹mW;ú‰Š’x±±²2Ó××ò9ØQyÀ7÷Ï!Ìá•ào€áþx²¶î«§§yüÄ­Ï%%ÄS“ýGŒ°þVáedä/]¶/>þó”ÇkÖê8ˆ›ãB²²ÒG¯Ç_×ÔÔÏ™û¿W¯à‰º \Í/†ÅÇgäæ²0é×Ïÿ¦ÑèoÞ$76Q† Ä›¯33 >}ªìßß!”œœ3`€‘žž&Î|qérðŒé£eMMõèôÖ””11Q++³·oÓllúKII°X¬ÄĬü‚R[›þ¼ó‡ÒéŒ7o’뚆؛÷î­ž“S´nÃ1y™””Y==M„Ðý#†ÿóÕŸQ]]?lØ ¼1¼ººŽw$T^4=11«¥…îìlßÜLMNÎa2YÇ[EE%³Ù''K‰Ôn¡)¿ ÷¿ûÌÉéóXèjAyô³·7çkT'3gŒæN$Ãb±^¿~_Kn°·3×ÑQï(žŽª PZ””>7–äæ'½ÏÒÔPut´ù÷¼«--ôOŸ*EEI†õ®«k$“ÙlŽ––ª€êÚ~ÖeeÕÙÙEÊÊò††ÚQQÉ}úèj³ÙìwïÒB ïáÅÏ¢ÜÜâ¤÷ÙúZ‚§ûãâp8MM}ýÏÇ:úúZížlÜSSsKK«¦§ç•¹ÍÏ7´_BB†·O€¦¦ê¾½+ÕÔ”BŸ>Uú<ºÂÈÖÉ)9!UUÅ‹¾;}/Þ?{>ÐcÁ$GáÛrß\Í,kƬ­YÙ…3gŒ yí¹ûB¨°°Ìc¡§‰‰î8gûK—ƒýn‡"„jkÖ®?ròÔ´´<[ÛþÓflyÿ>›þöÎ3¬‰¬ À7 %ôÐ{E@@A@»®»Ø (6tmXPQ±" ì. Ši * H¯"½=!¤Í÷cÜÙl Ëú­;ï<3“;÷œ9wfîÜv•¦¦ªÈ`0::ºÛÛ»˜L•:ð 6eïþ‹7n>¾yëiÐÙÀ¼»ÄÅñ“]lwû…ÄÄ$âˆÓfl’’wã´aãñ/Þ“ÉTUê­½½«·÷s̺´´<ö¶õõÄß\}‰Ä@UUƒ²Ú䬬b>—ÆL~‘¹jÍ!FŸá³éDØ•X}}ں態ý<%Œuþœñ7¸@vN©¯Aqß­K`oµdrÿÌÙ[¤¥%fÏ¿Ç/äÍ›\~úpC¡PCBïRp¤Ôc7’’3=Ü%%Å=—îGéÂÐéŒø„ £9pœ˜ÎÎÞÙs|ß"ŽgY÷õQ‚ÏG ¼“lcczâä­às‘·n?52ÒŽ{žæ·7”ü€“§n¿zýÁÍÕ))9s«ïi~¶´·wµ¶väçWìñ ]¼hÚþ}kàã=[|O¿x™øÜlp²-[O½~óÁÈH{ƬÍM­t¤à zõ*gñ’½ ‰oÏm;vÔ®ãð´JŽõQQ‘Ý»VÀÛ’’â¾[—DüÐÔÜæ1oǽè$$º Ê?ZÍÿ.‡=èí¥,_6KTTd¸‰®žž`ÃÆã LÕÑQ“––ܳ{åÎ]çˆãÇ[ZŽ2¦P¨Ó§;()ÉY[™¼LÉ"¤œm°X¬££•³³„„˜ŠŠÂÂSÒÒò–-|vûæM  ò&“©¨(»rùì§>û'ߺíÌdÛ±cÍDD„íÆšKKKXZhhj(;;ÛŒù¹—¾¡‘ˆ„ޏ¹MTVþܰÖÑQK|bÁöÀŽ””V^ž°ÔsFYy›«“¦¦Ê´©öÏŸ§xJÈÈHvtt "@¡PiˆNœ¼¥©¡2zô11üzï¹GŽ]ã§B}}Ë¥Ë1/Å\ºch õ6ý†ŒŒä»w…÷¢“6¬Ÿ',,deebmm²oÿEö³dd$·l^dogNg0ššÊÞ^›7-Dϲ62Ò™6Õ¾¨øÓŠå³åå ..¶Ço._6KQQÖÅÙöy|‡yââxa<^t›ï’às‘dr??k|øP–]ò<>#/¿ÜÃ}ׯÆ Äóftw÷Ÿòöò00М4qLZZÞêUsàè;qqi îÎÍ+»ì·×o5ÇL‘~ê@H¾„¨¨ÈÚ5nw#1Ìù w߸ù˜=Œ/ Êí´ÿ!$&½373„·gÏvÐhôää÷'7Á………”•åSR³=—ÌÀ`0ÆÆ:ðq11Q*u€gž FOO]L /&öùHЙm‘Q )©Ù­­==dA‰‰ïV,ûIo×Îåü4$‘º9ž‘ÞT,ëâb;ÈÕ±÷»b0Y‚ܼ¥RiƒŸ(,,Äd2q8Ü¥XZ×7´ »Tê@ð¹È¬ì’ŒŒ÷IÇ6¾LÉÖÒT ˆÉýÚZª_ÔGVVÚkgX„Ä·ìsé ´B/DŸ þ#ÙFŸùgƒï,\0õÑãWn®Nƒ\þ e ŒŒ´aŠáE‡ Ó‚ÄÄDûû¸Í»aý¼'O^?qS^žèí%KHˆ^Lžl‹Ç‹NŸî ##¹Øso~n›ÙÛ6›MRRLEY¾±±M[[µµµÃÈHNŸ±qóÉ'‚†×ã)þ€hhhåž(úþ}·»$!!¡E §:O3Çm[[['Ü•‚‚‚òCA[ó? q1Ž ‡Ã Á³£ah4:ÒäB›y‚L[“”üëßÝÝç4iв¼ïÖ%3¦;˜L&ÎàÍ3+99é¾> ¿dCbðàlsîÄÅñ#ßüXæ93%%é?ÇãEwîX¾qÃüæ–öƒþëÄÅñ‚¤™™Á’ÅÓ—,ž¾n­ûåK~‚èè¨{Ë’F£‹Š s'ssXW×’•UÜÜÜŽ,Wã)îKeä\Ö¬ xû®pû6ÏÕ«æÀÕ?¿¯@}=‚ÂJ"‘Ä/÷͆Ãá6¬ŸzáÞ¹óQªª }>è›6ÍþEÒÅK—ï¯^s¸¸øwVFFÚ6cL>Jå8ÞÙÙS\Rž±±uÛö í¿Ÿ 9·­ãQPþÐjþ‡°xÑ´—)Yð$AQwp8ÜÂSޤ堈DRggó¤1pd2û|dii …ÚÚÚÑÖÖùg²¿þ}ýúCOyæÌq€Æ¦V‹U[Ûœ––·dñ´¤äL8M_åÉ“×iiI … ()ýüòÕ×Óhjjg×Qc`€t6¢·—Ìïêþ®ðß¶Ù”ç”èêê•–þ¼Þý‹RfÌpðpwöò>Êžmm]3ø³½»Ìs泸4äß{ÑIƒèÃñ;n®N‘š>õUÎRϙܧ y­óðÞpl´õp~¦€7-kðEÓ!Ç{zú®Ýx´yÓ×ÜÜ΂  xÎ{ð¤Âüüx2¡¡¡¡õ ÿºMØ¿–}¬DGGí\ðï‡yßþãÙòþ99¥ì¦Ãb±·nøŸ‰**ªd?çî6‘ýHUUß@ÿƒa«VþvûÖ!KKcÎb@AAù1àüýý¶ÿÂÂÀšY¦6L ‚ ë7cæÉÓ×£­‡«ª*89YGF%ÔÔ4Õ×C/DŸ9í«¯¯•ÐÐ@ÔÑVËÍ-»yëIm]³†º²&…B}û¶ °°rþüÉõõ-Çoææ–S(ÔáÃõ$$Ääåeb¦Éý55M¢""…E•½½äY³ÆO™261ñ]n^YGGÏ“§¯ÝÜ&ЉáUU®^ˆÇ‹`0x8\‡ËÎ)?ÎVøpÀÕäï{zÈã,:;{V¬:4{ÖxžÓàˆ‡®ææ–ãñ"êêJG®åçW ÐMLt +(¬$“ûmmGjk©rHdd`±ØIÇš›Û‘3s†‘H:yê¶´”•:ð2%«»›¬§«>ÙÅVDDxøp½®®Þ»÷ fBâÛ1£GP©4~ú\¸“\[ÛL¡PutTÙ;™åå FôÏ…³X¬Ø‡),´×o‹…mÒÙÙ3j”±ŒŒ$ÀØHûAlÊþ}kàº~â¦L¶å.ë´´¼Ð»ee5ð°÷é ðÂÂJqq¼´´Dàñ›…±X¬¶– b^GG«êꦌŒ“õ>«x˜¡VFFþ8‡Qéùw"Ÿ××·èëi|øPv),¦¦¦¹­­“ #©¥¥¢¬,—ž‘ßÑуä IDATéêêÍÊ.¹ù¼©©Íl¤aò‹L~7Û«×9îswœ‰:qòvZz®ÙHCör‘’wq¶?~TxDÜÕ«±ÊÊrZZ*ð_ w·‰~û.Ô×ÅÅD+*êbî¿pq¶ÑÔüœ ¤¤j_hVVñömžK—ÎTT”ð!BAáÁÕ§`íÚŸ­Ä¿ 4BÀ =BƒÁ ;ÔÔÙG[)jo/™«<8==}8Žßp, ««—ÅbÉÉɰX,‚þp …J&÷³¿R!"IÊÊò°24}ŽÛ¶¸§ç†tEC‚C"`ב-› 5Ò+“É,-­noï27Æ=ÌÓÈ_§mSS›¢¢¬ˆ{"‘ôêõ‡ys]ÌsHe͉ԭªª€Á`èt† n !z÷®^~)ˆˆ¸¸´¬ì’½~«p8ÎHNÎs~(gƒïˆ‹ã¿{D"É}××~®V((<@«ù¡ƒÎ´ÿïâ¹dÆ®ÝçMLtt~÷-Ð錽û.œ>µõG ú(*ôtÕ/‡Ý·¶2ùõêxÀFŸùçCî¿)%%ÞÜÜÎ`0£îýÙJ¡  |ÐÖ¼Àür­yÀÀ-?¿âˆ_ZZ-++žReÈ ­ù¡ƒ¶æÿÓˆŠŠüu<`¨ãñ(((((ßtA Ê/ ZÍ£     ü² Õ<ÊgÞ½+,/¯ù%&¾kmíøêÓûú(ˆSƒ1xb”ŸAmm, ÞF‹é[èèèøì×µ$ÊW€ŽÍÿ:‰¤ £÷ú­di5ÕÕÏâÒòdfåT Ë«'<"N]MiHáÌ'L°ÚãxÌgðÈ4@tíú£ÌÌ" ‹aX,¶££{®‡óÁCW"ÂÏÐÞÞ|.2%5[NNÚÁÞ‚Å‚::º ©>óá ¼ÜÔ×·lÝv¦¢¢® /Šg‚ÇÍ»yË©»÷Óß\×××8þâeVOyú4{,30@—““^¾l–¤¤8œø[oÙ·ÿ’†††r[[§ªª•JSV’›5küòùð¡ìöOÓÒóÌ͆™˜èö÷ttte´xÑ4~Î’_½ÊÙ»ÿâp]Äíñ?íúuŠõ÷Sý† µÈä~ƒ9ÁÑ*öaJÀáõßGo”ÿ h5ÿëÐÐÐsÿÅæM ‡º@ŽÉdîÜ}>üöax7/¿üY\š€Õ|RR¦‰‰î«ù7¯X>Þ^²xÚ©ÓáƒDÖá‚  w««+…]öƒÝà°X¬Õk—ðp´>8 „Ǽ'¹xé nÕƒÏEÚ[•‘v©ÙÑÔTñß¿vêôC•õí|Ѽgƒ¶EÜy¯—ñݺ„L¦>}ö {6øŽÃÊW)a°[¡¯¾C$##ßsÙþ¤„P8$# °°ÒÎaÅ·5+KKcssC¼¸Ý!¯éÓ cÁ¢=©©9ׯàyŠ££Õüy.ïÞ~Ë%|_´êW(F"us\}4ÀgΜ ð‘Þ^²ÃÊIG»Â(ÿ5ÐNû_++“âÂè¯xƒ§¦æ˜4@¼¿­[ëþøa€çÞºyð‹µuss{^^û £Ä¤w°Ó{A»ò ¸¤*ðØFö0zAg¶}õ*vaa!ö°1+WÌ.,ª|—Æ/=/úu‚¾‘/šƒÁ°Gb÷_WtL2¼ûÕwO ŠÏX´ØC!“û—.?pØ©ã#GlX?ïëòÇáà@†Ÿ‹IHHh™çÌ·ž •ç§“ Vý¢bÅÅŸÖ¬ xÿ¾ÞõÙxbœÃ(¤ŽHIIœ<¾ÞNMÍöò>ZQQË/7‚¼¼Þ¸ù˜NG;ùQÐÖü¡ àcCÑÆÆ´££g`€fjjèêê}ýúANNÖÒÒ’pʶ¶Îׯ?àñ¢ööæ‚Tiiu]]‹¾¾†æÇuÕÕMššÊ&&ºµµÍµZZ* „ÒÒ;;3,ûþ}Qcc›’’¬˜ÞÒÒ8+«¸µµsüøQX,¶¾žw!êëkttt“HÝL& Ž@š›[VZVcb¬3êÏ0äáq›6.€·ûû©ÙÙ¥ uÊ”±‹E"uóóCÞÚÚQTôIJJ|ôè­ee5òò2zzêiiy** px’òòšM[Nd$óòÊ )5øÜÉ.¶‰‰ïàÙàRÇOÜZ³Ú•à ­ŒŒä´©vÈ.‡yùéÓ¾¾~€ÜŸžt+*js>”ª©*:8XptS(Ôººaa!‚ 4Ûª«+ææ–ÓéŒ ¬Þ¼Ée2YŽŽ–ȨD?õõëÜîž>{;suu%@IIU]]‹©©>A……•£GPT”í룤§çkj*Ã_ÙÍ € ¨¢¢6çC™ž®º­íH~מX÷O›#wˆ””DFF>‰Ô=y²myym}=ÑÎÎ q$Ì`0ÒÒòX,ÈÞÞ<..]\ß ,+66åNTü¤‰c®]Ý'&†Ü𢥥ÝÝm‡în‰Ä¿¦bÔÖ6g¾/’“•vr²Æápˆ¹¹å#G wb"SD„…`ßÏÜ&e§¶¶™Ng0™LÉë0ŒŒŒd[[ç â8ʽ·—Œ”éë×¹x++,[ZZ][Ûìèh%.Žç°* ¯’‘QÐÙÕãâl#ÈUVVqHè=55Å€ÃÞ°_人–¨{‰o®s¤tr²ÎÍ+L˜`­¯¯töNwwߦ Ì͇q¤Ä`0BwÅÆ¦Ì_¸kÒÄ1+W̆Ëå¿ Úšÿ!‰¤5ë.\Œ)/¯µµ[N£Ñ‹‹?-öÜkccjm=Ü}îŽöö.ÀË—YËWú3ÂÖÖÔaüªöö®–ÒzŸÀø„ @GGÏž½!÷¼ôôŸ¼uúLxRræ:ï#oßœ8y‹Á`ºº:R'OÝÔ×sõ%;ètƳ¸4£9……•€îî¾i36½LÉlõ=ù¾hÁüÉIÉ™g‚Âamßg¡o3Ì䙫ւwoÞz¢oøj2¹?ôâ½às‘€¾>JðùÈ#Ç®ÇÜ1fŒiHèÝÐ ÷d2UUE:@koïêíý+ô­±‘NBâ[A¤H]Õ5MšÜùXop›—Ÿ>Ü´·wíÜuÎk­»³³ àXà¤äLwgIIqÏ¥û‘H¸0t:#>!ÃÀhü­³³wö߄ķ4ýy|†Ï¦aWbõõ5jëš.þ<[]ݸ|…¿‘‘öÔ)c¯^{qç9,tãæ!¡÷ *ÇŒ1:}ãƒ/““ß=ÜgÓ‰øø óNžºýêõ7W§¤äÌ­¾§y^ ¬a{{Wss{ZZÞþ—"þpq±…ÿBî@uMÓo®¾7o=¡Ózzê–Ö‹á·ýýÔÉS}„„„DD„LÜF2b¡Ó·ÿx:wþN2¥?êαõÞs‘ú#;»T[[•;"ÀèÑ#à8Š€»÷»>{Öx<^tÞ‚]Áv8YPðÑÆÆÔ}îŽʸ/ ‚ ë‚ÏE…]Þ+))ÎӤ쉤Ş{½7ÂuëöSï ÇZ[;Ç]îp™nÜ|âÚõG¥e5Ë–ø#ü|Γ½á±v«vw÷M¾ÑÁÁÂÜlØô™›?}jàWL½z•³xÉÞ„Ä·gƒ¶;êƒÄ>ÈÎ.pßð¢¢"ÈpŒ¦¦Ê™Ó¾Ç6ÆÜá¹t÷ˆ‹uwŸt?ú¤¾æòþ'OÝ$$ʯ ZÍÿ\\lMM h4úÌ™ãÊKˆˆ¯÷ \´pª²²¼ºº’Óë«× Ð<—íÛ»g•¦¦Š””Ä8‡Q8ÖÉÉÚÜÜÎÄÆÆÔÞî³Ãù‘# &MSZV³`þ”äÄ‹¶¶#S_å46µ1Œ#ôáao7·‰ÊÊrAj›ï[Sx^®¦¦ò†õs×{ÏMIÉ~úì×:,ë»uqàñ› ‚ …м¥¤$–,žŽ\ˆ»Û¤¸§çøMzÒÕUŸ:ås{ÚÈHgÚTû’’ªËg+(\\lžÇg,- 445”mFŽ4@ÎUUUhljDJÿ@hÐ(õÜæå§Bæû¢K—cBBïFÝMغeÑÅ »1Ì»w…÷¢“6¬Ÿ',,deebmm²oÿEö³dd$·l^dogNÿÓ¶Þ^›7-”—',õœQV^ãæê¤©©2mªýóçéð)6_¸`ªŽŽš´´äžÝ+wî:×Ð@?ÞÒr”qOyÆ ‚­iÔ½Ä9s&ÈÉÉŒs°€?€ØÍ Ç‹ˆãñ¢Û|—Ÿ‹$“ûyš‚LîÏÎ.ÉÌ,ŠŽI Ï˜î€ü…Ü!€Å‹¦)*ÊÊÊJ[Y™˜˜èŠˆ}$%eÒé   --•œœRß­KTêÀÅK1‹–øIJˆGß=¾Ôs&ÇŒ3 …*$4Xuuõ®]wdÿ¾5x¼¨ƒƒEo/%3³¶…B>ÝAIIÎÚÊþEˆ}˜rérÌÙà;oÒr£ï.[:“ŸIÙÏ3ÆôÈáõp,"€®®ÚÝÈc#FèódzÜá2--«ùm¶£¦¦Êôiö‘ñV–&šÎÎ6ïßÃ%ìVe0°DccÇñ–—ÃîsÛ‚ ¸¸´ wçæ•‡]öÛë·š# S?u0¸1aeò9¿3õU΢Å~/_fqx5Å`0S¦Œ½h7Ölý†Àƒ‡Â::º¿˜-Ê/ZÍÿ(00b„@]]i`€–žž_]ÝÇ`0¥¤ÄKJªššÛÍÌ ""Â/솟vaaöLض1#†ëTUp8Ü>¿ÕÛ?+¯8iÖo[ÔÔ4Hzo/ЋрgÏÒfÏr¼LÉ’’’€uˆº›èèhÕ××ßß?Àýj@¶ed$‹mÞƒFFÚð1<nHñCNNi(.E]]IQPÏö¯¬¬8rÕaü*]ýY.Fó4ïõ1\Ïk‡Ï†ù>æ#ã ‰oõõÿZ64Ðâ9`¿Ñgþ¹óQ€G_¹¹:!¦%HÁm211Q*• ÑèÉÉï >ç),,¤¬,Ÿ’𠧇‡Qbbxc£¿¶á/ðwónX?ONVúø‰›w"ãüg‚ÔÔ©vsæL>»Á`ì?p‰ýß¿—†Mèg…õõ5š›Ûá°ôíí]HŸvÀ‘kb_†]òss›È>­ÁÒÒ¸¡¡^DsëöÓM›OªiLuŸû{YYMNN)FOI͆‹ÉÐ@9þ»D9ŠÉÅÙÆkÇÖ-‹W®ø n;ˆIÙ™4i ‹IJÊd±X}}ýHÿ9OqüÊ£LÁŸþ………„„pýýT«ÊËÎÝ~9ì~HèÝ•uðwññ7Ÿ<°í–Í‹xŸ´e hhhåþ ¼gGFFr×Îå¾[/_韞žÏ`ooqõʾÖÖÏeûy&@ù…AÇæ ’Ÿ§m ‰‹ã]œmmlþò, Ï   g–Áø[?6ûÝðÂÕ}{EY,G$Ö¹Î¾Û‚Š‹?UU7þöÛ ¥¬,‡4Öá ‚8¤| <+„ׯ?Œÿ9Â}_EE°­ fù²Y¥nô™_£æ^¿ÕL&ëAìËõÞsY,·yчQQŽìÒhtQQqiÝ\'ún;“•UÜÜÜ®¡¡<ˆ8+,,D£ý5ŠF£#3±X Û¹_¤»fm€¢¢lÀao·Îë€J|n—¾¾ÆÃG©ƒ$à:|¸ž½ùါ8ÖoÏ*$”mÀáõù|ŽëêªmÙ¼ˆ{"Åo³÷ø…¦¥å!E¼léLÏ%ÓC/Ü[²hº±±™ÜÁ`-œ [‰½Óè‹×ÎÎà&EÀ`0>æŸ ‰Â`0“ÿ¶à'nrç(ÓÁï¨Üܲe+ücïŸÒ××èììmll¥R8t›6ÍþEÒÅ3A uë–EÈx‚‘‘¶ÍÓ‡RÙ{¿=Å%UÜÞ©³³K‚ÏE*+˿˸É3à/™Üåjlꫜež3ûÍqýQ~IÐÖü‚ÒJÆb±K=g íÂþ~êãǯ 4ÇŒ‘”œ ,,¬,*ªHKKÀí*@qI“Éú3Cˆ½Ù½kÏy:affxÐßKGG ®ªÙÓˆ‰áW,Ÿµí÷ £aÚð7W§ÜÜòžžÏmèØØŽÁ`äåev G&µµÍaW z™)Å~ÉìªJKK“êKJ«ƒuu-HùE)ý×µµur¤©­m†k}žæDŽ¿Øqsu*(øˆ¼ñS_å,õœ ¸Œ/,,äµÎÃ{ñÑÖÃÿn Nq8ná‚)oÒrá]"‘ÔÙÙãH>99™òòÚþ~jww_uu#¯Ä€Ch[[§²²Ü^¿U~{V-^4Ý8vvæw"ŽÌõpÞ±3xûïgÿÖÜTWW 9¿cͺön†úz" ‚àb2336L+55þ«¨¨²¸ø—Jeq\ÌŸ|ɤ¥\ê9###?%5›=¤Oq‚”;¼ürxn7Ö îhlle±X‘Q L&“C1µsÁ¿>ä}ûgËWøç䔲_ ‹½uÃÿ|HüB@ˆsw›È~äÍ›Ü w?|”tfÛ©“[¸ëøîǮ/[q`¸‰^ìýS®®NCýðEùÀùûûÿlþ%„…5³L{õÚÃè褆ÆV1¼(üŠqt´zø0µ´´šÔÞ•øÎÝm"/:eòسÁwúú(¥e5……gÏrÄ`0J7o=QSUx“–ÛÙÙ“øV[Kµ®®årØýòò …j7Ö p'2žDêî를zýÁÀ@ÓÖfäါÉ/Þ÷ôÇ9XÀŒzºêçCîž Ú?Û²²ÒæÃŽ» ž‘/K26ÖÔÕµHI‰ki©ˆ‡®ææ–ãñ"cÇš½|™u(àÊzï¹<ßééyçCï–WÔj¨+··w…„Þ-+«‘‘‘d2YAÁÅÅU’’bVV&ªª W¯?ÄãE0Œ……|îÈøIGÃ/ÄÁ¥„……<—LŒJˆ‹K#¤ÚÛ»=N555Âá¦NµãiÞ¬¬žúhk«ž!£¥…ÔÕÕk7ÖŒ]¨¼<Áh˜ö™ p‹û0…Å‚öú­jjj;p5'§ŒÁ`Lp´‚Si?ˆMÙ¿o \‡ÕÕµ¹–Ÿ_10@71Ñ9x(¬ °’Lî·µ9e²mdTBMMS}=1ôBô™Ó¾úúšáq‘Q DmµüüŠ7WU5j¨+UW7]»_UÕ¨¬$×Ñј×Ḭ̀ºº)#£€Åd½Ï*f¨•‘‘?ÎaÔí?ž%¿xßÙÙ3j”ñ›c®n$“ûõõ5dd$uuÕ#îÄë訾y“km=üLPr‡?q355§««×ÜÌðúÇOž¾îêê>\O[[Õooèï;‚ƒÏEž Š(+«qš`ÅÞUQQ˜óÛmm•ã'n%&½36ÖA†–ÍÌ ‡›èúnb±XB8\nnybÒ;÷IÊÊrúú8v²‹íÉSÉýåå5?ÖM›fÏn‡Üܲ›·žÔÖ5k¨+÷ö’OÏùPF"uC‹c2¹““5·Iá»±´¬ZVV #I­‡ Ó‚Oä'ÎÆÆ”»ÜZ‘21BÏÿ`XaaeWW¯…Ű€#×Þ¿/îë£pXUIIîúG‚Ô»ÌÂá&º§êé©8ƒ‘’wq¶?~TxDÜÕ«±ÊÊrð3PP ¸»MôÛw¡¾ž(.&ZQQsÿ…‹³ ”ÝþãiZzÞ( c ==}în“r¹¶Ôs†¶¶êR‚ k×efYX Ãb±Ýs=œºðƒ$¢  ü+@«ù_œ¦¦¶„Ä·—.îwgÌpØàhcc*/O0‡ó!QÑ1Éñq!È"Ý[·Ÿ†ßy~þÜŽ¡*ãêꤠ@ï´æuêU8·öö®±öË÷í]ͯ_³Ú5!ñ-»gÓ†††Ö˜û/6oZÈ/–(»b––Æææ†xq»Ã½§M³´µuÚ[¹ã÷e«WÍ Ðbî';Ø[ü j‚  w««+…]öC<¬^s˜=¸ Ê´Óþçâ¥vçá€Y3LJ„òÉÊMaa¥ßÞ ·ndwıÔs† —cmLjSqÂìYŽÇor þg¬[³²2).Œ<^8»b8‡Ã"®`egÍ„ÁãEós£œœ¬¿—z­­{÷]¸~ã¼våAqIUైX,6èÌ6xÉ_[[çÂE{¸Ã—¡  ü@[ó?„‚‚ DÓŽŽžš©© ««÷õë99YKKK¶¶vÀ!Ú$%ÅUUˆT*MH§££Æ‘²¶¶¹¢¢VKKEAPZZcgg†Åbß¿/jllSR’Ãþ® Æ«WÚI]cmÍ`¯™=‹K;迎]·‰G ¼~`ÿg‡‘$R ÅÏ]ÐÙˆ±cÍtuÕÙb0˜ysÙãäæ–•–Õ˜ëÀ¡Þ22òI¤îÉ“mËËkëë‰vvf¡6Ùéë£ÈÉ}þ·µµ#==_H7a‚÷ˆ@iiµˆˆðÀÍÈH›ÉdUU5b±uu¥üü ~â z÷®°º¦i¤©¤±±µ¬¬F^^F__ãÍ›Üaôõõ5˜Læ»wE{{s¸¦ÌÊ*nmí?~¬FKK{zz>/:eŠ-·GBžtw÷éê~v<÷ñc]UUã°aZººêˆzzêiiy** ì®Êòó+ZííÍ‹Š>U×4.^4ÓA}}ËÙàÈ®®ÞÍ›"žSŸ¸µfµ+ÇEÉiS튊²WÂö†]ypáRôò¥³fÌpøEüž¢  Úšÿ!‰¤5ë.\Œ)/¯µµ[N£Ñ‹‹?-öÜkccjm=Ü}îŽöö®Þ^Ê‘£×ÇOXÓÙÙ(/¯užìýéSwÊžòñ“·NŸ OJÎ\ç}äíÛ‚'o1LWW'Aêä©Û2¹æì-ÒÒ³gßãòæM. ©©MZZ‚£žîé!‰$xw”Õâ3Aü.$;§Ô€×Jzß­K¤¥%áí­¾§3ß-˜?9)9óLP8 º¦é7Wß›·žÐé ==uKëÅ<ƒÒ2Œ/Þ¿~“z~' >>ãà¡0gç1––Æ›·œÊϯàH_VV3ÆviØ•,Ä`07n>qî|ÔÀŸ8¾lù*•æá>©¤´jûïg!ê룟<x#:&ÙÆÆôÄÉ[Áç"oÝ~jd¤÷<Íoo(,«¾žø› Mò IDAT«/‘ØHOÏÛµ;dΜ X,Æi’{(3º{úÚÚ:+*j/^ŠÁb1÷¢áã=[|O¿x™€8rìzÌýcƘ†„Þ ½ð¹seËÖS¯ß|02Òž1kscSëÀ½·—‚d^YYï³ñxàñ›Þ^×®îGêx©«º¦ÉÀ@“[ÿŸ¿ð$%Å}·.‰ø# ©¹ÍcÞŽ{ÑILæw Kˆ‚‚òÿ ZÍÿ\\lMM h4úÌ™ãÊKˆˆ¯÷ \´pª²²¼ºº’Óë«×êëkñ¥P¨pÓS]]é|ðŽI“Æp§9Ò`ÒÄ1¥e5 æOIN¼hk;2õUNcSƒÁ1BÅòÙ€'oij¨Œ=BL ¿Þ{î‘c× ­<ƒ½ªª*46¶ÁÛ÷¢W®˜ÍïB(êà×””ì§ÏÞx­óÀb±¾[¿É`0/š¦¨(+++meebb¢+""\Tô·AâÐ Ñ—.ÇŸ‹j'ue¿ÿ诲|¥ÿ¡ƒ^RRêêJ>æ{.ÛÏÑÉìêêäíåÑß?ö2yìùs;äädø‰;|GNNÚÉÉZDDxþ¼ÉkccSŒŒt¦Mµ/*þ´bùlyy‚‹‹màñ›Ë—ÍRT”uq¶}ŸËrs›¨¬,o³XìnÚ4{žügPAn>~¬ËÉ)}™’õèqêôiêêJðqSË?CÚà ””T­X>[Aàâb íîî >åíåa` 9i☴´¼Õ«æÈÈH +׬ ¸tùþ®ËCCvqÔèp¿Õ íY½æðøñ£Žñ¼LÉÖÒTÏ"“ûµµT$RÏxär²2ðxÀÖvä Waii\ßЂìR©Áç"³²K22 <Ü'Ûø2%KJJ– pt´êëë'¤0ŒñŸ~ÑÅÄD‘к0Ë–ÎTPøÛÀœœRƒ‰L 44Ô,,ªlh Â!¹¼Ö¹9ïØQŸ¾¾~]5¤ó™§¸çñì; ´žÅ¥¹¹MÄ`€‘‘6|®^tØ0-xÌBLL´¿ÿ¯^$óqãF‰‹ãŸ¸)##Ù×Géa ´ÊµÕðÏóÆ[4Ÿßܘ€ÄÑaï&ÿ»x¸ïARRLEY¾±±M[[µµµÃÈèsø`"‘4ešÏùàßÝÜ&òìlWSSTR”mh$rÿõþ}wxr!!¡E §:O3Çm[[[çŽß—ñ»”_´šÿHJ|ŽÁ·>]œmml8ß¹Þ^sܶmÞ´PLL‡Ãa0~)Ù#zÉËËTz\Tôéþƒ®îÛ+Êb I33ŽÙvrr2}d à¢LQQ(TÚ2Ï™K–îíî•x¼èÎË_½Ê¹ÿàåAÿuââxAJYY‘Ë®ûàý¡ÑèП±ÉáV&·Óx å)SÆ^»þHBBlÍjWö¿¸Å‰Š ³·Vi4:’!û@ÆÝøß¼õ$ênBôÝãRRÑ1É*u€ç÷‚¾¾“ÅJIÍæÂŽ[(‡Û°~nè…{ʪª }æÃÇ••åËJb.^Š™;çê•s¦LËQÙc0˜eKg>|”ê³a>Ç_éùÜÕ|ccë™ ˆ¶¶Îs;Áf(((í´ÿQ@@úœ±XìRÏÏâÒàÝþ~êãǯàíÑ£G¨©)®XuÐÍuâ )!bïÁÞµç<Î033<è北£Æ`0—yÎ|—†¤¹ÐÕUki!qëV_OTWÿìÚööOËËkø]ÅŒîÎ^ÞGÙ¥×Ö5ƒ?»n®N¹¹å==ŸûbcSàš•]_ösámî)ß––ÆJáÝÔÔœ)“m•”ä8, ظa~Hè=aa!öí<Å-Y<ýMZ¼Íb±ÒÒó/šÊ‘!»a9´Bþ:rwù²YRR56¶±XPxÄsžù »""Ââø¼¼rüû÷Ä€§Ð††Öƒþë6m\p`ÿZö±iiÉ;–ÿqëPå§zy;>Le±Xìª:èÕÖÖ…L¼‡‰ÏpoÅ~¤ªªaƒO ÿÁ°U+»}ëZÇ£ üÀùûûÿlþ%„…5³L{õÚÃè褆ÆV1¼¨‰‰.ÀÑÑêáÃÔÒÒjR{WBâ;w·‰HËRDD¸¥™´hÑTx—;å›7¹—Ãî——×P(T»±f€;‘ñ$Rw_/åÕëš¶6#‡×ëêê½{/‘Á`&$¾3z„’’œ¤¤xÄç‹NÅáþúž£R¢c’×­ý¹kõÚÃJJrÈÈ173g8‰¤“§nKKIP©/S²º»Ézºê“]lED„ee¥-̇=v@ =#_– el¬ëðrjjNWW¯¹™áõŸ<}ÝÕÕ;|¸^zzþ¥°˜ššæ¶¶N‚Œ$û"r7ÙÅöø‰[ýýÙ9%IÉ™BvIHˆÝ‰Œ¿ù¼¾¾E_O^> ¥¥r/:éÐAod?qF×ÕµÄ=O§©.FÏõpž9c\ZZ^Hèݲ²I‚N…VŠ‹ã¥¥%ß,(üˆÅbííÌ\M~ñ¾§‡<ÎÁBXXè^tAF*>!ÃÁÞüÉÓ×£FV"Š‘H]§N‡ç|(#uta0`¤©€Ng$%g:Ø[¤¤fúÔp'òySS›ÙHÃÊÊzD&“Q\\%))feeòêuŽûÜçC¢Nœ¼–žk6ÒþÐ3ÆÔÍuâû¬¢#G¯±X,c¸W@HHhÉâiwâßRDbǃؗ ²ˆß¡’’ª=~¡YYÅÛ·y.]:J@Aù—qõ)X»ög+ñ/P'0ß#B…B%“û9^² Ð8:y¦D ÑèBB¸úz¢¢¢,ûŠvƒA$v¨©)"·g‚ÂMŒuaŸ-0‘Qñ]]}Þ^CÒœÉd––V··w™›ã^APss»¢¢,?Ÿq‚C"u !Óø¹ (ôÂ=Ÿ óÌÁ`´´ÔÔ¿%Æ.‹ÅjllUUU¢Ó^fyyMSS»ƒƒ… éãâÒ²²Köú­Âápt:#99óÀÁËïßÝæ™˜ÉdÞð²·—¼jåöã 5?¿BXXÈÌÌY_×ÜÜt6bËæEÿXt"”¡nè Õ¼Àü;Ñö÷Swí9´ ®ø™Læšµ¡!;ÅÄð_<÷ÿ 7íA§·•—×jj*Ã}$¿gƒïˆ‹ã×®qƒw‰D’ûÜi¯¯ý\­PPþ¿@«ù¡ƒVóóï¬æÙÙ%9Já^ú#G¯Íœ1ÎÜ|ØÏVêk<~SVVJQAÖmþü/“É<r—J¥II‰77·3LŸ ó44”¶^((ÿO ÕüÐA«yù×Vó€÷ï‹Ì͇1ÌââOÜS¯QPPPþ ÕüÐAÔý'€«vQQ€Öñ((((ÿ)Ðu((((((¿,h5‚‚‚‚‚òË‚Vóÿ9h4zdTüÏÖå{APkkÎø.¹••Õdg—|õé}}”Þ?ý3ßG¥ÿ&t:ƒDê‚§O¡–DùjÐjþÿúú–¹ówšY,ø^9zm´õÀ™ p=ƒÙñkœÌÌ¢°+¾—>W®Æw¿ýÇSA‰¤þ—¾W}ÆÎPí—’ò1($ôî¾ýß¿/^¸xÏÆãßž¡±±NbÒ»ÆÆÖ!AÐÕk׬ ¸uûixÄó#G¯UTÔ.[îÿ œ Ÿ1kó8ÇÕG]?yêöî=!;vWW7rÊæ-§TÔ&úÔðâ¾…/> Cº½ÒÓó-ö;õèñ«£Ç®gdä¯Xy°—0”A@«ùÿw45Uôîèèþ.¹ÅÇg(+ËÃ!Î|·.ÑÒRa0†4/¿üé³7_LvãæcAr[³ÚÕÔTŸF¨ænhh¹ÿâ‹ï»‡Sáð¾‚3T;'%ef¾/úb2ðÕ¼|™õ,.-àðú™3ÇÙ5ëêêýº|8ôܼiáÿË‚/à hÁÂÝ%%Ua—ý6¬Ÿçíå±{׊Àã7‹K>}ùd.|·.±µ90@Û³{åïÛ—;ê3Þd«ÑKŠŠ*ùr6hƒÁüç× }ñYÒí s>$j·_ÈÕ+û|·.Y¹â7¿=«>VÖ‡ßyÎd²¾|2 h5ÿ/çŒàòÕ„^¼·ÔsÆ7æ¼n­ûã‡Aƒ§innÏËã Ï”ª©*:8XÀA„(j]]‹°°AšÝ$R7“ÉRWWD\?õõëÜîž>{;suu% Ø3Åþ, ª¨¨ÍùP¦§«>x|gäŠÂ®yäØõ˜û/ÆŒ1 ½záœCNN©ç²ý’’bJJrçÎG!9ÇÇg<æì<ÆÒÒxó–Sùù€öö®›O„„Þ+(¨3Ætêô¼LN~?zôpŸM'Ñ÷Œ·|üß]¿ñÈcÞŽ”Ôl@UUƒ²Ú䬬bž) fò‹ÌUkh4úóø ŸM'®ÄêëkÔÖ5/\ì “©ª* ÔZ{{Wo/H¸ƒàå}tÁ¢=üþ­¯'þæêK$v W}68² à£©ûÜ>”Q©45UEƒÑÑÑÝÞÞõÅ6=?;ß¼õDßð7&“÷ˆ™Üzñ^ð¹HÀ¿‡d‚6ø^¸cb¢óôYÚÿK‚”E__?™ÜßÝÓ×ÞÞÕÞÞÅ>–Áó>éîî›:}£ƒƒ…¹Ù°é37Ã#Ùüô46ÖIH|o®‰ÔU]Óqà`b±™³·HKKÌž5~_È›7¹ünn(jHè]AjÇïËÇo$%gz¸;KJŠ{.ÝßÝÝÇž˜NgÄ'dÍ?}:;{gÏñMH|;ˆ¸êêÆå+üŒ´§N{õÚÈ;Ï`Ïû³8yêö«×Ü\’’3·úžæy-0=‡®®]wÄÊÒä^TàŒH/HvN©¾÷)¾[—À°X¬»û¤ûÑ' ô5—¯ð?yê6:f28h5ÿCpq±555 Ñè3gŽ+/} ""ÌbA²²R8nÚ4{žœœ 02Ò™6Õ¾¤¤jÅòÙ ›çŸ_Œ¹ówîØ¾ÔÂÂH[[uÅòÙp¶}}”å+ýô’’’PWWòÙ0ßsÙ~‚Æ·´eÜÓCž1ÃAA`kcu/qΜ rr2ã,ß§74y†™/,¬yÿî6ìWGG-ñyˆÅŸ]ÁHII Aååå K=g”•׸¹:ijªL›jÿüy:ÀÒÒØÀ@CSCÙÙÙfäHƒ!™îÀþµ§Nlá÷¯›ÛDeåÏmJøª)êôéJJrÖV&/S²)gg,ëèhåìl#!!6ˆ,~v¸»MŠ{zŽ£¥ˆ ««>uÊçv*¿B’nÜ|ü.³èä‰Ízz«VþöøÉkøøàeab¢kh¨¥­¥êìlãìl3b„>|œß}Â`0àþ ccÇñ–—ÃŒŒ$2Sap5úûB|lsâä-M •Ñ£Gˆ‰á×{Ï=rì¿›¡¾¾åÒ嘋—b.]Ž14Ðz›~CFFòÝ»Â{ÑIÖϲ²2±¶6Ù·ÿ"ûY22’[6/²·3§3MMeo/Í›"nÃÆã LÕÑQ“––ܳ{åÎ]爂þÅ²à ¿ûD^žpîìöËa÷CBï~¬¬ë鬈Á`„……àþŒÁÕPWWRT Ô7‘#••õG®:Œ_¥«?ëÂÅhÀË”l …WXT©­¥ ¾tóÈÊJ{­óðöòðݺdÊ”±ðP}Bâ[}¶Æ®¡Ö³¸4n•6ú̇ûf=~åæê„\·8žœüÞÀàsžÂÂBÊÊòpWŠ Ïûm°aý<9Yéã'nÞ‰Œp7²!rŸ»ƒÅ‚Â.ïµ¶ÎÓ˜–£Œ‰ÜÇssËxŽÇÛÛ[\½²¯µµÃsÙ~ž¢  ÕüDRâ¯Qð›·žøí ]ï=×kܤF*î©ðd"îiâ¢"49÷ü#•ûׇ}ANN¦¯³÷xäHƒkWö/Yºo¨SÓÙd v >ëk¥ó¸R¥ó³óW©ñMFÀ‹Š°/Œæhá ~÷InnÙŒY[fÏrôÙ0”…1€J`¿|=ÅÅñüú3ØÁ`0Ë—Ízø(ÉÊÀ@s¯ßjgii‰õÞs‚¤™™Á’ÅÓ—,ž¾n­ûåKŸ;̇¾4d—F£‹Š s'ssXW×’•UÜÜÜÎþ‡[‡bŸ O£Ñ¦ØY³6àí»ÂíÛEXXÈk‡÷†c£ÙÍ<Åáp¸… ¦¼IË…w‰DRggó¤1¼lËCUäxOOßµ6oZ€Ãáš›ÛYÄóÇáp æO‰½JMUq±çÞàs‘°å¦Ow˜ëáÌáÿ ¶¶™cþcwwßÑc×—­80ÜD/öþ)WW§¡~0¡üwÀùûûÿlþ%„…5³L{õÚÃè褆ÆV1¼(ÜÍd2ïE'd¤â2ìÍŸ<}=j”QWW_Hèݲ²I&“Q\\%))fm=|²‹íé3áUTÔ½LÉJz‘ÙO¡Nb7ÙÅöø‰[ýýÙ9%IÉ™BvIHˆ…GÄEF%44u´Õòó+nÜ|\UÕ¨¡®T]Ýt9ì~UU£²’œ‰‰®¦†Ò…K1‹NE”Œ‰Innin¢Çd2OŸ Ï˯m=œJX±êÐìYãyάnh ¸š›[ŽÇ‹¨«+¹–Ÿ_10@71Ñ9x(¬ °’Lî·µ©­¥zõúC<^ƒÁÀ½â«V"ISÙ¦^Ã܉Œ¿ù¼¾¾E_OCKK%ø\dVVÉœ9xöpÀÕäï{zÈã,î?x\unnÙÍ[Ojëš5Ô• 4)êÛ·……•óçOMNÎÜ´åÔ¢…Sdd$ÙsÃ`0<íìâlóòeÖ¡€+ë½çò|{¦§ç½[^Q«¡®ÜÞÞų­¬LTU4°aÚ,ëöÏp8lÜóôÊÊzsóa––ÆÍÍmƒ”Erræå°û?Ö©(Ë“H]çCï—|’““5ʘç}"-%qýÆ#Aê]fáp݇SõôÔíí-¸õdd`±ØIÇW ,,ä¹dzdTB\\ ÕÞÞõèqª©©_ìðáz]]½wï%2̄ķcF Riünž ££c’kk›)ªŽŽª¬¬4"H^ž`4LûLP8‹ÅŠ}˜ÂbA{ýVa±XøÆèìì5Ê.ec#í±)û÷­?5êêZø‰›2Ù62*¡¦¦©¾žz!úÌi_}}MAž)))qäYpt´ª®nÊÈ(`1Yﳊ‡jedäs•ž‘Ï~{#7ž‘‘ö\g2¹ßÿàåÊÊz33¤ aÆ ‡ææöSgÂe¤%ûû©Ïã3>U5,Y< ¾ÛÚ:ß¼ýdz¹ÎÛ·yêëk|cßÏ¿Œ«OÁÚµ?[‰h Zùæ@´,«±±UUUAHHˆNg2àÚÞÞ%))†Á`Z[;äå ÈRZ©KXXžy;$æ/Øu!t2jûC ˆH$)+Ë#¯¡?Ÿy.™1øYß‹žž>‡LÁKOÏSUUÐÓã1‡ð·ó·3$#0 "±CMMqá¢=ÎÎ6«WÍùFé<ï“––viiIqq<ûMÈ­ç:¯#[6/|ž7 5?¿‡Ãš™rOA.ðk&‚ššÚe9–ð±C$’^½þ0o®‹€yR(ÔÞ^2FN„ùêzú ¿×­ÛO}·.ùºÓ‡ƒQQQ@v[ZÚÙ'+üh8ê¶Â¢Ê±cÍø%ægçogHF‚'lÒŒïâÿ„ç}‚èÃ~rèÙÚÚ!""<Ô: .ŽÄÎÈ~# †_>ÍÍíkÖ<}|öAlÊʳy¦á‰¸8þÛ?ïDEEÔÔámÁ'NÚÚŽä^g/$$ûÛ`ƒÁœä¿…'èpÎ cc))‰÷xiýîää”Íž=þŸ— hjj³¶þÿ0x)ˆ"î<§Ñèoßddäÿ3Zq@§3öî»pôȆŸ"ýQT$èéª_»omeòÕ>øPP~%ÐN{ùæNûÿÒÒò_-†ò_¦´´ZVVнq‚òÿÚi?tÐNûÿ"h2_ÑW‚‚òËÏïÆDAAAAAAùA Õ< Ê/ ZÍ£ÄÝ{‰Tê…B}ðàåÏÖEP::ºGcì>æP† jI”/èØ<Ê—‰MÂáàeТ¢"qqiÓ§;xî©Ód¼Íïììµ·3w°·`÷ APÀ‘kK=ghk«~Gmûû©þƆZdr?ƒÁœàhû0…c]òùð¡ìöOÓÒóÌ͆™˜èö÷ttte´xÑ4~.`_½ÊÙ»ÿâp]Ä™ë?Ã-Y_ß²uÛ™ŠŠº‚¼(ž xò½,‰‚‚òA«ù_“ÆÆÖââªÉ“m¿=«¦¦¶„Ä·—.~;c†ÃŸ@S×îoßæé··çÉSNï€ZÌýd{ ~•ÓÇ©ŽŽ–ìNо‰Ô5ÎqõÑÄ^o/ÙÎa変£ÏÆÒÒØÜÜ/nwÈß þ¬a0 íIM͹~íÏS­æÏsy÷®p¨²¾‘/ZRSSÅÿÚ©Ó7 žçw´$ ÊOí´ÿ5IÏÈïéáŒ~ñu\¼Ãm0kæè}¥ IDATøÐ{‚ç ,,$"ÂãƒÍÏrr²æwbbÒ»/Œ/.þ´fmâ Àgã‰q£Ø}åJIIœ<¾YpmÙÁáp8Yp/$$´Ìsæ[OˆD¿S¸]¿ý|Ñ’@ÅZ[;ö8ÿÜ’mm íyù2k¹çC¢Ð©((?´5ÿ£`0iiy,doo—þ?öî;¬‰¤ ø¤Ð{G@zAŠ EEPÁ†ØöÞïì½bQ°`EEQ°{VD@iÒ»R¤I 5Iöûc½|¹P9¸÷÷ÜsO²™yw³òfgwgùœ¬B¥Ñ1©’¢ööæ$)==÷ë×o††¡„„¬Aƒ4UUØ•$$dfdæë骚˜è2ŒèèÔêêzggÛSÔÔäå¥1 ËÎ.ˆÿ”©®¦ÈHëÝ»ø?7{¯^5-11KIIâ­±‘žP[Gµ±6ÆGKNÎ)**³´4¬ªªkjj64Ôd0¡¡q5µTm-e>>^]]U Ãþz±oï2ÎM9rÈa+{vYšB©éÌTf\rr¾æækk+«©)"„bbR‹‹+de%øõõÕî½¾tùáT7 ]]ÕÖY*66ÍÇ÷®‚‚ÌÁ+ð1J¿~ýx÷UÔû+\%ííͳØo¹¾‚ââòÌÌ|))1uuňˆDyyéF¥ÒxyÈøº†}ü˜’—_2ÈP³õŒòÕ55õ!!!™¢¢2:½™‡‡L&“:h®¼¼*22‰L&a&""„ŠŠJ¢Pj‡ffæWTT[[ ò—–VÆÇg˜›ëáO·síIƒ—ñ%·ÈÒÂPSs࿈ÂÂo§¼o×ÔÔ¯[;ÓÈH«3{RFFâ¢ßN¿‹÷ÏžrŸ7ÞÙÙ¶õøµkVψM[¿á¤‚‚Ìúu3áA|zœÍ÷ˆÆFºã˜Õd2™——GGÏÕÄD'-ý BèÎÝW‡\™0ÞŽŸŸoÚŒ­†UVÖ¬Ywì”÷íääKKÃ)S7ú”‰W²aãÉè˜ÔÓ_‡D{zÝÄ0”ž‘ç6móÍ€g>&ãÓK?qý]ø'×Éö¯C¢7l<‰¯È`0%%Eëë*+kð©0óòŠÝìÕÑQãduéòÀ[ÏBee”%Ëž=œ•U0ÔÚ½¹¹eÙò榺nSF}JÈ|ñ2 !TRR!**Ä5~//O]}Fkb6ÛÓ+à'öRUUÝú'ß¼E;îÏ`0'O¶9~â:Þ¬0@†Á`TUÕVVÖpžÓcöî]üì9;_¾úpÊkӑëÙãÇÅ¥#„Z'6>>Þm[à¯[Tjƒ÷™Û‡Ž\ ¾÷ÆÂÂÐÇ÷ŽïÙ6ú*0 ËÉùê}:ÐïÂNaaÁææ–ùî{èôf·)£Ò3rÿøó×ym}=Íãè5›a ñ~32òƹ¬MKûÒAs/^DíÛïçà`ajª»ný‰¤¤l„P^~ÉÄÉoÜ|ÖÒÂPQ`j>ûÙ³ˆ/_ŠŒµ†Z»——WqíI„д[ùGݶÃ'88¤ƒ¯àóçÂÕkŽz½¶b¹ÛåK»ñßÉ=),,¸qÜ€KJ+ܦm¾ôŸœžÓ!×ý÷Ï3n×îóë7œ(((í @O€4ß#^¿ŽniaØÚ¶µ¬¬,Ÿ±qÜššú¥ËíÞµ„ŸŸÏÖvp}}Cttª©©‰nC}Ü8[YYIs3½·¡±¡Ðи§½_¾ÌH$nÜ0Ûãè5-Y<™@ —^³zÆÍëB‚‚ü¼¼<üü|›6Îñ>}›FkDe!%%f4HÓÁÁŸl{Õš£3gŒQUUÞ¾má–­§‹ŠÊFjh¨ÙÜÜââ2,+ã>94,®°° !4gö8c#m„PQQ¹|[“y  ]\ü}NÛ»]<œÍÒÒÐÔäû‰lØ»øâ’ ƒa` ±À}‚¸¸ˆƒƒ%‘H>ÜÌÁÁ’}öüìYÄŒ™Û³ü.ìØ¹c1×eû†F:BˆLn·_¡Í¯@GGuì›ôôÜÅG¶|þ"Šs­CÏ_>å}ë}DBÐùó\B§¼oIJŠÚÛ›óòòLŸæ˜SðàA(çZêêJ'OlhjjÁOÊåä¤|No7ζ½æ¨Ô÷…{÷ï[.""¤¨(»zÕô¹ówc6{ÖX QQ!ss}--e‰˜_Pjk;xà@y•>$síI„´”8“É”‘‘Xè>áØ‰ëm”ÏK–<áÞÖ-î¾>[¹2z#½©ã=ÉÆÇÇ»t‰ëÛG æô™Û®^{Ì9<ÎÀ@ã¢ßÎukgžô¼¹r•GvvÁ«tè´ïJ¥¥•øé]ee ÞŸÑÜÜö}¤F-Íøô$AWW_( À‡Ÿ¿ ºð _>|¸•Ú(..‚a˜¡¡?…]µrÚ“'áG]Ãoˆ«¯§±çdcknn ‰9汋¯7wŽ3€ ÔBx7þÖ-î¶v‹ÄÅEœÇÙ9¼!D¡Ô´yMWRB¬¶öûµÿÖ³nüЛ7166Æüü|ìŽÞ];Ϙµ}ñ’vv&G­ns­/¢Ö¬;þä‘—¾¾z›ðTWXXÆNÿ¡¡qoCcïÜ}%%%¶g×Rr;_ÒÑQÁ»øùñ¯€m´ƒ¥››W[Ï_DMqÉ~«¥©ü׳WŽ%!qq‘Y3Çœ;|äðêа¸µkfàËÛl.>>ƒÁ`²olÔÒ˜’ú¹¨¨là@y «£Š/àã|Ýøw¨œ]æ^ž›n¾ ‹+/¯®«kc’ø²2ŠÓØÕg¼ÿtuÙædqøž,**o}ÿcLLª……!×B2™Z8ÕÖRG;­Ü½sÉâE“Þ¿Oxø(ŒÉdrÝÉ(''•™|î|ðÔé[/œäädÅ•ìutTð=ÉuÏAuu]Zznë4_\\îéPQQíszK›w6°X¬‡îßüË~„yfú½nœêÐ1è´ïÕrr’;w,Ú±}ÑìYcñ…FFZÚÚÊaañøÛÔÔÏii_B†±/ë²/ïºN¶OHÈbß-ÿàA(ž8 ×ÕQ/_}´ní ‰TZZÉÂ0 »ð!$**„÷`§gä’H¤™3œÞG$àk••Qª«ëFYàͱkc2™nñæãã1Âüê•=%¥!55…oßÚ¸«¼°°LQñû„›×o<ÍÊÊï`op„ŒB%%¡aqx^a°uû™–†‘‘Ö¾½ËUU æ÷­h ——WUTTã몪*œöþóÀþ×oüå¾`o||gCD"ñÚ•½g|îàWµÙ­”âY¬ý¯q|çºÖö­äsf{‘ˆ¿f±X‘‰³gi½±ÆÆZóìqüÿý6›35ÕUR’MNÎÁ߆…Å;9•••äªÃçëÖu†‡ª«£¹¸ C—”³X¬‚‚ÒˆˆD®MÞ²Ùý†ÿþÏ_ ݦm~ø0ŒÅúÿO"‘èuïŸÀÔÔÏœ[}3àÙ”öXäæ­Zí±wŸß¢…¯ûïoã FÀ­ç“§üA©ª½sûȺµ3!Çð;‘öîÝÛÛ1ô~~hÉøN–äß±Ó÷ÏÍÞÞ§o{zdfæÛ0àw=ôø‰4ZcVV~NÎ×±cmn<»ø²¨¨LUE!!!óšÿ“‚¯¥JŠrææúƒµ¹Š0•$!.¢ªª°k÷¹˜˜´ŠŠšòÒ 2¼¼ÕQMMQXX0àÖóY3ÇHÿÿEH§7‡,[:»xéYYIÎkÜŽ÷¼óêë×R‹õác²ÿõ§lö–‘‘˜?ÏåÖí·n?/)©0¤õ64–B©¥Ö7¼ ÿ¤©9p¨å „PCýÇ䔔ÏÓ§; ü¿‹BDDp´ƒ¥ÉÍ€g—.=““TVþ>O¼´´¸Û”‘;wŸÍÏ/øò¥ènPÈ”)£‚••‰DlýDD$úøÞÉÌÌf2Y^Þii¹ÂÂD"áÄÉ›ñŸ2)”Z cksn× Aš_¿~{ö<²F?{.hª›ƒ‹ó°ÈÈÄ3¾w22ó$$DÙ= âbÂÍÍ-ÎÎÃð·í5gaaè8zèÑcþMqñé¯C¢ÏúlØ»ïBXX|MM½±‘–ÿõ§¿«¨¬6ÐWø(,88¤¼¢Z[K9ì]<{Oêë«?xJ£5æç—ðñò¦¤~®¯§™™é8y#>>“Á`ŒnÆÞ ²……¡ëä‘1±©‡_f±XzºªxOƒ´´øב;v-,,àËÎþ|ïÍhË¿ïêôôÜí;|ccÓþØ4wÞ< ®¯¾©©ùêµÇ‡_1ÐWß¿oùsƒÎ\ì #—ž¢¥K{;ˆ>&¢í´®LD»m»ÏH{sKÐÐ@?zìF?q|=þ)…RÃÇÇËÙ÷Þ ÃJK+ed$xxÚ½¼ÒÔÔL¡Ô M ZZì’--Œº:*ç 6 ôúzš\[·Ôáðƒoß( 2ìz<½nêéªkÃ.v;ðEM uÅr·ÆßyÍÍ-d2©°°LFF‚ól¯®ŽJ"‘ZßpÀV_O»àwßÚÊÈÚÚ˜syUUmRR޼¼”¶¶rë‡ý:ÿtŒÁ`໫ƒ>ÿ§Oߨãºu…RÃÃCý¥K×55õ,KRRŒÅba֙ǙLæ½ûoëëi‹NâŠ'))GQQFKK™½™¥¥•^§Ö¯›¥  Ó^…¾gï**ÈN˜`×Õ "´ &¢í:HóÖ•4?yʇWëü}«ÔãÇïÂß'°Ó|ßÒØHߺÍç”×&¼›Éd.YzÐ×g‹€t½väùóÈȨ¤ûWœñ¹Ã¾ùðK Íw¤ùNëJš¯ªª=å}[BB}E\\dã†ÙmÞ¢Õ'ÄÅ¥ÇÊÀ{é¾ìâ<Œ«´–›[tî|°’’ÜÌNø%vÀ¯‚4ßuæ;­+i¾ÿ‰‰I56Öf0˜ii_Zßh ¿¤ù®ƒê@§à©AŽ€>nú-Hó@¿iè· Íý¤y ß‚4ô[ð@]WX.ëí€.€áqø›9<‰z;@_ö O¹{1™½ÄïR]rr Ç~¤yЧ„…¡¼¼ÞâwIOGNN½ oƒ4ú”#ÐçϽÄïòá7®·ƒômæAŸ¢£ƒÞ¿ïí ~—ׯ‘¾~oèÛ Íƒ>E[½|ÙÛAüÕÕ!$!ÑÛqú6Hó O@RR¨¤¤·ãèyééhôèÞÐçAš}ͱcÿ‰sÜ•Uoèó ̓¾ÆØ ôv=.̺¤yþ}àÂ< ›@šàß.̺ ¤yþ}àÂ< ›@šàß'0.̺¤yÐUW£•+{;ˆSR‚´´àÂ< [@š}¨(Љéí zLr29²·ƒôæAD"!-­~;HÎû÷È¢·ƒôæAß4r$JNîí zÆË—H[»·ƒôæAߤ¯ß?ç°Á/ÌÿÆÿüæAߤ¯ââz;ˆæÝ Ò<è›$$P``oÑàÂ< [0 ëí37GïßC§= »ÀÙ<ÿpaÐÝ Íð¯æÝ Ò<ÿaapaн ̓¾¬º56övÝ„ÉD11Èа·ãô+æA_öú5z÷®·ƒè&yyÈ‘H½ _4ú2þ3HΧOhĈÞÐß@š}™¶6zù²·ƒè&/_"SÓÞÐß{;~€’’B%%HA¡·Cù5/¢¤$ÄÏßÛqü'™›#„P܇.´â.öþ-÷³Ž?Wæã{D&÷±2\;ç¿U¦Ï¶ Ãã€>îÄ de…llz;Ž_ðâòòBææhØ04fLoGóßcnÞÆŸ{¾ãéí~tÚƒ>ÎÊ Õ×÷v¿ ) yy¡À@4mzü¸·£ô7Ðiú¸>}Ÿ”„6oFHB‰Š¢˜ÄdÂÍö€ngóôÎ"‘…JMíí°ý ¤yzWŽÇbbz/¦ÿª¾è)­ïÈëƒ Íв²Ð¢EÿÈñ![[ôöm/:ÒÒÒB¡Pð– Fo‡~Ã°ŠŠ ‹…¿þepm€Þ`jŠ<=Ñ´iÿX¨ €rrPu5wú½'22Ê×÷œ¹¹™¸¸Xié7{ûçÎ]8{öŒˆˆHo‡†.^¼äéé½mÛæyóæþ°°§ç©7oÞÖÕÕ7–H$655IJJº»ÏÆ ”••={~çÎí<<]»·<..þÖ­ÛŸ>%èêêèêêbV]]’’*""rýúÕ þÈÎÎINþô3ÙE………»víÕÔÔPRR¬¨¨0@žN§ËÉÉïòZÿ—Âèüüz;‚.b0033¬¡á 1GGî…àwhnó¿Ó§½† ³¡ÑjØK®]»„ª®.oo•NþwåŠß/Ö€ÿ7}úÔ‹Ïu²ðþý{,,ÌÙo½¼N dXUU†¿‹û¨¯¯G¡|û‰0šš¨¡Gî±—TW—ÛÙÙ²XMÖœ’òIQQ¡[¶·ãÿ"#ß©««}ù’É^’œ/,,ôàAÐOÖifÖÛGf7€N{Ð/¼}‹JJz;ˆ® ‘“ÊÎþÿöÕz˜oþß!%%eÇŽ]þþWÙ çÍ›ki9äkÆ0ìùó¿+C*ñððöÛ… ÝSRRƒ‚îáoÍÌLÓÒ’$%%" ^^^„‘øÿ„"..>wîìêêê®Ùy†½xñrÖ¬¹õõõ!6oÞ‚ƒ÷©««³Ë 4hÕªøë°°wË—¯ÌæüG÷ßö _9%'÷±±ð† C¯_#cc„Ú¹#ô*/¯ÓVVCÕÔÔ8„iÓ¦ræ36ƒñî]xee¥•ÕPeeeVXXH&“I$’ššZnn.†a!QQÑãÇOÆÇJLL$“ɆÏI˜‘‘©§§kbb‚ŠŠú@¡PGgeeY[[Ipyyy™™YÿøÁ[\\,+++ ÀoÚ‰“ëêêBjjªøÛØØ¸òòr;»a"""´Î`0"""Y,–õ³gÏœ¹jöõ=·jÕ GÇÑX[ïDGÇHJJÚÛ ‘Hééé_¿`–’’:dˆ¹ŒŒ •JŒŒ8PI__¿u ,ëÁƒ‡·nŽ5òòe?„н{÷¿}û6eŠ+Wá)S\ËÊÊB#F ×ÐP÷òò®­­[»v•1þOï?ÎæA¿ ¯ß÷æ°±´D¯_#„PRZ´ùúBŽïø`·­ÄÅÅkjj´^¾qãzQQQ®…4ÍÅe¢¨¨è„ ã·oßõþ}Dsssdd”©©ÅÝ»Á!Ÿ³«V­ÍÌÌ¢R© `2™••”ªªj|õ 6EGÇΘ1ýõë7žž§Byyy'º^»v½¥…¡®®fjjA§ÓB†­_¿ññ㧦¦&ïÞ…ÇÄÄâ5;v‚Á`Lžöµ¿*m4ú}ý¾÷XžÔïÞE‹¡Ë—‘¦foþ¡±±‘Lîlç±c'8dˆ¹€€ÀÊ•Ë:"!!±hÑÂ{÷îÞ¾}§¼¼\LLìÙ³'ÎÎãÔÔÔ† 1vpeg7 !öôé³åË—‰Ä×{xc0³gÏ’‘‘‘733ÕÓÓãååMMMC]½z-;;gݺ5rrr®®“ut´ñÂÂÞ3 ƒ æ·'F‹‹‹ŽŽ njjrvÇþÈÕu²œœþº½Ö_¿iii±µµ±µµQVÿiãÆõì  ¡¡®¡¡N&·=ÄSMMÍÒ¥+vïÞÁÏÏokkS__cg7ÌÔÔ¤®®ÎÙyœ´´ôСw'Mš())9l˜íË—¯ðuétú¹sfÍš+,,8oÞ\®[éü¾dddØçããönÖ¬¹o߆¶Ùë€âí¿oêÛÀ÷”ÙçîQwsCÇŽ¡Ë—Ѧÿ°155)**n½ý‹}&ŠÿÔÜ܆¿ÕÒÒliiù»-]v[œíâ½ ¡ƒGGÇܽ{[¢㦦&<Ä0Œs+BuuuÅÅÅzzz\åÅÄĶnÝïê:õÖ­¶¶}y<Íu1Í·Ó»À¿ÂèѽÁOY´¨·#m˜?îìÙójkkÅÄÄ8—‡……ã—Ï9‰‹‹ š3gvëz„„„tuuüü.ýñÇF®²³³EEEÅÅÅåädÙërVÒú—??›§žRR’yy9©©©÷î=˜#''ûñc„Bߺ­§‹º~6}¡€^b¹¬ÍÅãÆ:Õmõêu7n\c/,((•åN0¡ùóçž>í³yóxr½{7hÚ´©¡7n š7oŽ•Õ0SS“‘#íB¢¢" ¡ää”áÃí\]'?~²®®¿äÿàÁCgçq¼¼¼øÓPxýì³gÏþâË—Ü9sf·yš[SS{çÎ]ƒñòåk 󺺺õë7<éµaÃZEEÅ7oÞz{Ÿ¡R©Cäåå_¿ill,(ø:fŒ“„„ÄàÁƇE‹ŒŒ’ÐÕÕÝ»wXØ»ššZcãAW®\{òäiMM¾¾ž5F»ÿBèéÓg ‰ÚÚÚQQ(”**•úî]¸¦¦æÐ¡–\ž:u:8ø^^^>FÓÐPSSS ¸­ªªòþ}„¹¹™§ç©7uuõÆÙ=z¼ÍÖUTTvìØõçŸ[¼½ÏxzžÊÌ̲·žœœrø°Gll|cccQQQTÔ‡gÏž?~òÊÿãÇ=(ʇããã ÆÈ‘öŽŽÇ{ÒhÔ¬¬¬œœÏcÇŽ¹y3àöí;EEEªª*IIIW¯úçææ*))æåå_¸à—››'''ËÙå.//?iÒå£G¿zõZWW‡Ýod4H__oÓ¦?BD"1::æÅ‹— ºã·éaöêÕë­[·3Œýû÷Œ7–óQÖZx] IDATÉöõù©¤º8ß¼¹9œÍú’Q2ŒÌÌL ¥ÊÄdpë{ì¹J–••)((ü°Ã!TQQ!!!Á¾k ðÒÒR™Î BÇ`0(Šœœ\YY™Lg2™d2¹°°PFF¦sÙ !„ètúû÷ZZš\WÙÛ³mÛŽ‘#íF„†††£GÓh´'Žu²96 …ÂÇÇÇ€ï§øøœÝ¶m çãþ†}ýú5'ç³¾¾go|HÈ›´´ô%Ku~ÿ s«¾woo+æÿy¦yÀ6y²›‡Ç!ï·È=~ü$<üýO¤ù>£_¤y¸Ó@§\¾ìwêÔi ‰T\\,..~èÐÞ ü¤y"))¹ÿÞÞŽt ô[æ€~ Ò<à¿­çæ€1í€þ«_Œiiè· Íý¤y ßêà—˜[¡¸ÿË` ¡Ã¸Ëpø–ilDÃFöù2\BæV?¨ä7—éƒ`°[³\Ö†wœ Óè· Íý¤y ß‚4ô[æ€~ Ò<ÐoAšú-Hó@¿iè· Íý¤y ß‚©k@ïxó&æÜ…àÚZ*¯¨ˆ¬¬ÄœÙã–,;ùþŠ  ÿOTXRR±tù¡òòªº:šŒŒ„˜˜pSS3Þ¬­¥¼jå4SSÝÖõ¿þôÀÁKUUµ¹Ÿ‹‹‹üì6uƒÊÊš‘ËGâ幩ƒbëÖŸ¾¢®®ôþݥߠ/‚4~7ƒ1kÎÎ'OÂÏŸÛ>göX‰„JKû2ÖymaQ‹Åú¹jdž>>µxÉËWý±iîâE“BµµÔñ×›[ÌyüÐËÅ¥Õ_›?Ï%99ÇóTÀÏ5Ý**ªSR? ýà‡Ž÷©?""ëëi¿'*@ßöàwÛàRPpÈÞ=KçÏsÁsà¿ÎæÁo•šú¥…Á ¤¨(Ãõ@ˆùxŸÿûIêÎ]gG:,WQ0j¤ÅÖíg–-?„b0˜/=ܼÅûà¡Ë%¥zºj&oÜ·ÿb›maV\\îý)/Ï®‹B/_~04µ®Ž:y’}UU­¾áÔèÖa°X¬Y³w8x‰D""„ˆD↞µµT555oÝvÆûLàÆMž¢¢B ô¡6îìJ<Ž^sp\9PIÎyœí_Ï"LÌf~Cèk‰ˆÑh–Öî‡\ñ:uk°±öÓ¿Þ›˜Í®©©ÇKîÜuöø‰ëx…›·xOŸ¹Íyœ­µ•Ñ‚Eû&¹nÂ0¬;¾À¤yð[566!„ˆD"»»¾MQQI‡Ž\™3{œ£ãPSSÝ];_¼ü0/¯xÈ[›Á´º¶¶ò´©£GŽ¢¤(ò†;UŸ;ì¾`ï¬Ù;6ýá5vŒuvæƒáÃÍèô¦yî»õõÕ-œ¤©9pÙÒ)ZZÊsçïnnná\—ŸŸoÞ\—¹sÆefåã©·¤¤bò$ûËÝÈdòĉ#ÔÕÃÂâvîX4b„ù×Q¡7ocBŸ>enÛá³háÄQ£,tuUOžXŸ•U°a“'B_+4,nÇöEööæSÝBOž†9¼ÚÄDwŒ“5¥ª6))!4v¬––2;[›ÁSÝ´µ•‡ 1˜1Ýéñ“ðÏŸ »ã{üW@§=ø­Œµ1Y¬òò*99)„PIIÅò•‡BïÞ}Â0lØ0“ck#"Bé¹;wEÕÖRåd%ËʪÔÔñzÌLõð||¼øON“'عc1×´´ÜòŠê‘rRì%HGF%efæiqÞºÅÝÿúÓÃG®ÜáʵÇ…-[:!¤  óø¡Þ$ lƒºsûˆ°°`LlBhŒ“õúu³ðÏœÞÌYç%üN@5·üÿܽ©©™½œ‹ŽŽêôiŽw^Žc¥0@FEeÀ[ÿ^ÿß}†555s>žÇµÖ7Á`XZÍonnyüÐKCCéà¡Kaïâ;^¸@§=øÝNyml¬½m»Ï;ޤURRÁYfÂx;…Ò…1™L„†a[¶žÎÈÈû•vµ´”m¬ccÓñ“o­1>>cÄp3v—íÛ²0lñ’Û¶.èLýÆ—” Ÿ€¿MJÊ®§6,\0á§ÎÈÈOLÊvr´ÒÐPBefæ#„~úCÀiïÞ½](î燖Œï©XÀ…„öð»ôúÇäà{o®^{²vÍŒ²2ÊâE“yxÈ‚‚ü.ζïÂã/]~êã©……¡“£•ÿõ§W®>¢Q“Sr\œ‡múÃ+.>Fk,/¯24И=wgl\:½±©¤´òÅ˨)®£8ï .Îþ|)ò9{7::õ´Oàs¿ ;…„nÝ~áwñ~}}ç„L×Éöøíñrr’IIÙf¦z NdWòçæSïß'466|³¶6šç¾§¸¸¼¢¢ZTTÈÖv°“ãÐGÃ< }û6öÒ•G«WMß²ÙD"r®ek;xμÅEåÕBBü55ÔÃG®ÔÔÔgç|µbà}úVhX|m-µ¹¹ÅÕu$¥²æÙóÈŒŒ¼¨¨$‡Q–ñŸ2ž< ×Ôxåꣷ¡quuÔÒÒJ''«^øAué)Zº´·ƒÝ‰ÐµwÍÍQô… üç´´0¾~ý&(È///Õæ£b†566ýܸxíÁ0¬¡.$ÔF_=îÝ»øÁƒuÄÄ„ÇO\âØzÕ.ÕÏb±šššº-f:½‰ý=ËrŠ‹ëí @w‚kó 7ñðñéö„îÍñxäøŠŠê£–y^m ¯a ¯ÑÕ"‰Ý˜ãBã? Ò<ÿ --¾{çâôô<~ðÀŠÞ~ ¤yþ@ ìÛ»¼·£€îwÚý¤y ß‚4ô[æ€~ Ò<ÐoAšú-Hó@¿Õõçæ-—õ@è~]Oó0¦=ôWp"×ï@§=ÐoAšú-Hó@¿iè· Íý¤y ß‚4ô[æ€~ Ò<ÐoAšú-Hó@¿iè· ÍýLD ô[0-€¿Á‰\¿ö@¿iè· Íý¤y ß‚4ô[¿/ÍcVQQÍb±ð× ã·5ܹ݇ûŠNoúÅJZZJ †a!ØÏÿZTjC}= Ýɯ©¡~ÿþÛž Ðßtýº®+,ü¶k÷yMM%%%¹ŠŠê¤éôf9YÉñãíºTϧO™×o<ˆL46ÒÖÓSkllªªª51Ñ™=k,‰Djs•wïâwî>§¯§váüŽîØ”Î*+£œ=´sÇbž¶÷p›=xJ&‘øùù~ºÝÈÈDß³Aææzââ"¥¥•ö#ÌÏ>ë»UDD¨Kõ**iîüݯ_úª«+áKRR>[Û.¸á «U™šêkñ Zïß»ÿ3Ç`0fÌÚåòž6W>Ülú´Ñ?¦üÊ&ü„¢¢òà{oÖ­)))ÖÉÀJJ*^¾úpþÜöŸnôŒO`PpÈ‹g>‚‚üøÿëOoÞz~æôæ®V5y²½´´¸ý’ð°Kxm••5V6î»v.n/‹/Y<ùå«ÍÍ¿»ó 1)ë¯g¤yÎÀ؇Ð}+ÆŽµAUTTÛ [¸ùÏù‹MB555ß ±µÜCið3·)*Êú]ØA B,kñ’ié_:Yƒ³³íªÕ––†RRâ=! ŸéÙN{­qžûžƒV°sÞŸkëW,[:åñC¯ŽËp†BxŠEÉÈHŒw±Û½çü÷’ü|I ööæÝ^yyÕÎ]g¯\}„¿õ»x?-=×ãÈvD"ÑËs/B¨¢¢zæ¬ío߯â\Ú3ÞÅÎÇ÷nwEèßzölþÞý7ß¾UNqŵ|ŠëȲ²*öÛ‚‚Òè˜TI Q{{s‰”žžûõë7CC „PBBÖ Ašªª í5A¥5ðò…„Bôðð„Ú:ªµ±¢¢,WÉ‚‚Ò–“É”——ÎÉùJ ÄÄ„+*ª;h.;» þS†Â[ÛÁ$©¾ž–ÕÒÂ1Â,<'§¡dr§ïÚZªšÚ÷o<'çknn±¶¶²šš";uuňˆDyyiSS]öZIIÙEEå66Æ©©_òò‹gÏËþõ‰+,üvÊûvMMýºµ3Œ´ð…Gù/Y<™——‡³¤˜˜ðØ1Ö!‰‹~;ý.Þ?{>È}Þxgg[ö¯N#G9ìqeÏî¥Ù:À\ÏžÍÇÅe¨¨ àú£†2ÄÀÅeþúÎÝW‡\™0ÞŽŸŸoÚŒ­†UVÖ¬Ywì”÷íääKKÃ)S7ú”Ùºr Ãrr¾zŸô»°SXX0/¯Ø}Á^•1NV—.? ¸õœ«|YeöÜ+Vyà÷¸ù_ºbÕ‘òòªš;âqõuH´ÛaaÁ¹óv×ÖR››[ž¿ˆZ³îØå+45•22óç»ï¹qó/|Wàça……e'oÄÊÔÖRÇŒ[ck;ØØH{œËº/_ŠZoKII…¨¨;OÔÕÑŽ÷?éyóuHô²‡>|HF™˜Íöô hwWÇghj(µ^¾qÃQQaüõ†'£cRgLw|íéu!”—_2qòÆkþOZZêꊦæ³Û¼Á`¼yþ>Á÷Ì„ЋQûöû98X˜šê®["))›«|ff¾ÅÐy~ï³XƒÁ\³îØé3MMÍí5×ÜÜ2ß}Þì6eTzFîžÂ0ŒJmð>sûˆÇÕ àKKÃcÇý½Oßö¿þTGGåÙóˆ;}B 3äMô¢%ûñv##·nó™4i‘H°µ¼¹¹¥½ÝU[G­¨¨ÎÎ.8w>˜H$Ü ôÀ—WUÕ­ßxòÍÛX„À¡#W‚ï½±°0ôñ½ã{öû9ôú 'ÂßÒÑQq¿®¸¤¼©©¥¾¾]ùçÏ…«×õ8zmÅr·Ë—v³s<…R“—_¢©9°u<{÷|ÿ…',,¸qÜ€KJ+ܦm¾ôšÉdræåå©«£uЃl=›æèdrÛgŸ¸ššú¥ËíÞµ„ŸŸÏÖvp}}Cttª©©‰nC}Ü8[YYIs3½·¡±œk=xzþBð)ï[ï#‚îxÌŸç‚ZµæèÌcTUDE…·o[¸eë颢2ε,, XYRR!##RSS¸sûˆF{Í}ü˜r7èõª•ÓxxÈffzææz»vŸ“’Ÿ7×9#3â„áÊkpû…™©ž¦æ@˘˜´º:BÈÕu¤œœ$Þ.ƒÁÀ[ÔÕUngzÁï^ëýPTT./'Å~;h樑™ù3¦;…¼:7tè „ÐÝ@… &t¸«;:y {ú×ûåË܈DâÆ ³=Ž^c0³g•‘‘53ÓÓÓSãååIMýÇEbß³Aç/{Ÿ¬¤ÔÄÅÜz6n¬-»ïÇÒÒÐÔäû);@zzî÷ ÒÒâ£G[âÖÖR½Ï®X9pÔH‹ˆˆÄÅ‹&‰‰ #„RR>/Yzðü…{[·¸ûúlåÊètz3BˆÜN '>>Þ¥K\ïÜ>Â`0§ÏÜvõÚc®Ÿ,HWü°èÙN{SSÝCY,û<ÕÿúÓøøŒà{o¬¬:°ª¸¸¼¹¹%4,ÿTKs`K !D tuUñ…|\§˜£,ÝÜ8—47·„„ÄóX‹¿åá!ËÉI…†ÅÍãÌYlÔ( "‘ðúuôèÑ–Tj#»ÿ¼Íæ^¾ú Áq~¬¥©ì{6è´÷ŸAB\DNN /ŒÒÓSÃ%“Itü/>»»UJJüô©?.øÝãá!ç|þ*+#ÙzGQ(5\—ê ‚¾:BhÀi| žìÛcjª[Xôý–Noò>};6.=**ÙmÊ(#kކƊˆÝ x†>ÜŒJm!º:œÛÞÌYíüy.ÒÒÿ¸Õ+>>ƒÁ`²ïÿÒÒ˜’ú¹¨¨là@yÎbË—M14íÈáÕTj£šª{o´ÙÜóQS\G²×ÕÒTþëY„«ëHéè¨àë ðóik+ã×,ø›Ø²W6ÌDPÿè±kbbÂTjCÝß«µfn¦?fŒ5Bh¸Ù ãé¥Å/ñŸb!ÎnòÀÂÂòrRÅÅ**ÊË«ttTðÂee§±«Ïxÿéê:²ÍÎvY‰¢â²ÖÅĤZ´º‹‚L&Ïš9Æa”Å$×MÕ›ÿœÏþHRB¬¶–ÚÞÖ[Ϧù‰†oßá‘hggŠ/™?Ïeîœq¾gïΙ5NWW•Fk$³fŽÁpž™q^Qþ!‰ÈÃCæ¼Í»¹¹…¯Õaaõªé§} ‚ã衜µnŽ—óª¹¹…çïÂÿèázË%!!sþ‚½îÐÐPª®®/..§Ó›¸b“”£Ò¸Vì Z.óçºÌ™·³¶–ŠÿÈàççÛ²ÙýÝ»ø{÷ßîÛ»LP_\\DNN’½‡zWã»Ã0<“Ứõ®VR’sr²º|å‘À’Å“9?jkWó´ÚÕ¼&r¬øƒÎ§kþOï¼ ºsTDD((8!D§7u|¦††“Å ‹›6ut›Z7J"‘V­œê{ö®’’Ü€ÒkVOÇ—ËÉIe¦Ÿ;ßulŸUW÷ýðÁƒP|Ó8Ûኟk ÎÔTWII699çûn ‹wr*++‰ï:ÎòkVM÷ñ½ËÃCæ< ÍææÌ÷>"Íb±""gÏÃUaëÝÞzùŸ;îóÇ‹ˆaV\\Ába7ž·Yû-// bbBÿÿ? £6-**ß·wÙÚ53öì^Êy­DTTxËf÷þû?)t›¶ùáÃ0|<(¶ýû–WTÔ°o¼Ç½x5ÜÎŒsInnѪÕ{÷ù-Z8ñºÿ~®*,,ST”Að#¤½{÷v¡¸ŸZ2¾K iéë©müËÅb‘I¤„„¬W¯?ºM%''©¡¡D"G=~âÖ˜••Ÿ“óuìX››Ïn¾,**SUQHHȼæÿ¤àk©’¢\}=íÄÉ›ñŸ2)”Z cks6doo~;ðe~~Iaa™ïÙ Ï“54FF&žñ½“‘™'!!Šß ÅËËSVF1Ü\[[_±½æ,- u´U<½n²X¬CY,lçŽEEEå]NJÊnjj10Pß»Ï/%åsMMýàÁÚ]މI£RÌÍõ=½BÞÄÔÕцÙ–••¼rõ‘¸¸ÈÇè}=µ‡ÃÔÕBœ Üz>k扈 ‰¾àw/++¿¡nme„ǹxéYYIö•ãÖ\œmËÊ(ÇO\¢Ó›Þ†ÆÖÖÒÔÕGååå‘l¬}øÈU„¡È¨$ q]]µ½û.„…Å×ÔÔi]¹úøÉÓðššz}}õÈȤó~Áùù¥Õâbœ‘“H$ÇÑCóollŠ‹O}Ög«À­Û/nÝ~^XøMC]IYY!¤¬,7èõþ}+ØÏøµ×ÜHû!_¿~{ö<²F?{.hª›ƒ‹ó°ˆˆDß;™™ùbb†ôº™’òYP_TTÈãèµä”"‘¨¢,àॄ„,~~^++#&“y7赸˜È‹—Q¶6ÆOž†›˜è$§|fF¡Ô|?„ªj4ÈP!ÔÒÂxmk384,îË—¢[·Ÿ—”T Òúü¹“ÉòòHKË03Ó{?eêæ3>ÇŽ_ˆL0¤…ÿÐÁñð-, ]'Œ‰M=tø2‹ÅÒÓUÅ{ÈdòœÙcn½xõꃸ¸HYYÕýo¥¥%Øã¥§çnßá›öǦ¹óæ¹°/%p¢Ó›‚‚C–-Ò¥‰tÊ¥§h)<Äѯ:~B—›¹9оðÍ`öõë·œœ¯::*JJr­¯\R(5||¼]ê¦nSC½¾ž&'×Q¦ïÙ»+–»ý°‡a~×^ëçºäÛ·JQQaAAþ–F›CãyzÝÔÓUÃÇlùL&3##¯²²ÆØX»õÓq†•–VÊÈH´7<_çQ(5<´JK+½N¬_7KA¡£3õÛ/jj¨+–»ufÓèËe(.®·ƒÝé7¥ùƒý. Ò:Ô0ì]üŒéN½·ÆFúÖm>§¼6µy÷Vßâêö‡×ÉMYYÊq^éNyßäg»WVF™2usDøåßÓ:“É\²ô ¯Ïþ— « Í÷;ÿ¡4ÿäIxjÚ11áå˦üÊùbω‹Kÿ”Ñ:c=Ž^“‘‘–p帾ß`2™g|îÐéÍ""‚¥¥• sõªiJJr¿§õC‡/»8ãºb@·4ßïü‡Ò|Ÿ“jl¬ÝúÆuB4ZcZÚ—Ö÷äÐm Í÷;¿c†:Ðyðt@HHŽ@—üû®Ð-~_šÇ0¬¢¢ŒÃ0ãwÏXÚ'ܹûªÍQ廤¥…A¡Ôà—c`?ÿkQ© ìñ$þ _6×Ð@¿ÿmoG@§üŽNûÂÂo»vŸ×ÔTRR’«¨¨0@šNo–“•?Þ®Kõ|ú”yýÆÓˆÆ^ÝC IDATÈDc#m==µÆÆ¦ªªZٳƶ7oÛ»wñ;wŸÓ×S»p~GwlJg••QΞ Ú¹cq{hµ؃¡déWfÎŒLô=dn®'..RZZi?ÂüÜùà³¾[[O"×±BïÝ“™•?Úa¨””X]­®Žê6Åýxwk/=8éysû¶íMHßC¢£S“’³;˜ož30ö!d2XWSS ÃP]uŠë(33=¼0†a]ž7×¹‡æ›Ç›¸|åQttêàÁÚD"±ªªvª›Ã¾ýn졨»›ŽÅťߺýâSB¦®Žª®®*†aÕÕõ)©ŸE„¯ûïïjm>$_¿ñWZúmÕ•+ÜLþObÙòC™yC ]ÛswÚ òóññ>{1nœm5@wéñ4•4wþî×/}ÙSΧ¤|¶¶]pÃÿ@W«25Õ56Öâ´Þ¿w9þ¯‹Á`̘µ=,,þÊå=m®2|¸Ùôi£?~Lù•Mø EEåÁ÷Þ¬[;³½)ç[VRRñòÕ‡óç¶ÿt£g|ƒ‚C^<óaGãýéÍ[ÏÏœÞÜÕª&O¶—–·³_v ¯­²²ÆÊÆ}×ÎÅíeñ%‹'¿|õs¼áß#1)ë¯g¤yÎÀ؇Ð}+ð! **ªm†-ÜüçüÅ‹&!„šššƒï…ØÚ î¡4aØŒ™Ûeý.ìÀŸœd±X‹—HKÿòÃu{H7637×72Òâ´Ú¸~ö„ Ãñ…55õ'odÜyVVF&&:ʪÎ3gŒ1á3êà•]>q|}竺zíñ÷v'…j³³íªÕ––†ìùøwêÙN{­qžûžƒV°saüð#×:X…¿7X¶tÊã‡^—á ?„ØIEFFb¼‹Ýî=ç¿—äçKJ´·7ï®ðÊË«vî:ËÝÖïâý´ô\#k؉D/ÏMø³Õ3gmû6¶kÏ¿ü‚n?l:†Äy’-..2wŽsuuÝOÔÆÏÏç><×ÈÁOž†oÙ<¿½UZ+-­LLäžI¹“Æ»ØùøÞý¹uømzölþÞý7ß¾UNqŵ|ŠëH|.v\AAitLª¤„¨½½9‰DJOÏýúõ›¡¡B(!!kÐ MUU…öš ÒxyÈBB¡ÆFzxxBmÕÆÚ˜=µ(g+-- &“)//-&&œ“ó•@ ˆ‰ WTTwÐ\vvAü§ …2¶¶ƒI$R}=-!!«¥…1b„Yxx‚¿™™‘HÌÈÈ+((>Ü ÿs›V^^mgg‚w{R© QQÉÕ5u£,ÛÌý†ýõ,bßÞeìP³³ ”•奥Å32ò­­ˆD"…R#..ÒÞå ¯SVVFjjŠœ ´©œSÅ$$dfdæëéªâ'@QQIJ­£ãЬ¬‚ÂÂ2kk£ÖçýWS$%¿Z^^™D&“FŒ0kݵ›‘‘ÇËËÓÔÔ¬££Âd²rs‹‰D‚¢¢lRRv{ÍaöñcJ^~É CÍAƒ4BÅÅå™™ùRRbJïß'hk«hh(1™ÌSB66Æ¡±‘—ÑÐ@wr²Âëùö­222‰ŸŸÏÉihÇ3ó²ÕÖRÕÔ¾ã99_ss‹µµ•ÕÔÙ¨«+FD$ÊËKsŽ-Ÿ””]TTnccœšú%/¿xö¬±\]Ä……ßNyß®©©_·v&{Êù£Çü—,žÌ5¢¢˜˜ðØ1Ö!‰‹~;ý.Þ?{>È}ÞxggÛ®žã~þ\ø1:EMUÁÜ\ÿéP^^Å9/—N6íá:œ~Øß³wW­œæ8z(†aååUøœ{bbÂÒÒâ™™ù¼¼$#„LÌf{z´»«ã349¦ÍeÛ¸a{<Ú OFǤΘîø:$ÚÓë&B(/¿dâä×üŸ´´0ÔÕMÍg·y ƒÁxó&&ü}‚ï™-¡/¢öí÷sp°05Õ]·þDR÷ÉPff¾ÅÐy~ï³XƒÁ\³îØé3MMÍí5×ÜÜ2ß}Þì6eTzFîžÂ0ŒJmð>sûˆÇÕ àKKÃcÇý½Oßö¿þTGGåÙóˆ;}B 3äMô¢%߯ìFF&nÝæ3iÒ"‘`?j9×íœjë¨ÕÙÙçΉ„»øòªªºõO¾y‹Â8täJð½7†>¾w|Ï~?u[¿áDøûO::*Îã×—”75µÔ×ÿ‚ÁÏŸ W¯9êqôÚŠån—/ífçx ¥&/¿„kzÜÞ=ßá nÜ0'àÆÁ’Ò ·i›ï½f2™ím—“ž7Oyßš8a8ƒÁt™°!”›[$§à›ÖÞ*9lÚÓúpúas¸˜Ø´Çß;î9ÊÊòRR⵵ԛϴõ\óòJ0 s_¸÷”÷­²2J]õ¤×Í…‹÷…¼‰ÑÕU={.hÝúìÞmm•áv¦/=Àß&%e6Öi/¼¢¢²±ÎkED'O²_µæè›714}€¼4½©¹²²ÿÛ<éô¦ûBwî>wõÚãkþO½N}ÿgÈËËSWGë +€ƒžMó t2¹í³O\MMýÒe‡vïZÂÏÏgk;¸¾¾!::ÕÎÎÔÔD·¡>nœ­¬¬¤¹™ÞÛÐXε< =!ø”÷­÷ Aw<æÏsA­ZstæŒ1ªª ¢¢ÂÛ·-ܲõtQÑ?&ö¶°0@=BHMMáÎí#í5÷ñcÊÝÿ±wÞaMd]¿!„„z‰Té¢*ŠD]Å."Ø»¢îëºkYì]W viº6¤#½ƒôŽHï%Bú| Ž1ĺû¹ó{||fnn9srÉ™ÛÎ ‰Þºe 'jaalii|ðÐ5ÙUnÎ¥e5¿Ì³ÓÐPí4É? ÂÂÜXOOÃÞÞ:3³¸·—pq™®¢Ò?¦áp8p‹FFÚvSÌoø>ÖCCC›*ŸþÑ£õfL·*-«Y¶tVLÔ58Ò|pà©5«]A¤ÓC^ãâ²C_%mÚ¸HDDd÷.×S§ïq8×NJJrrrD ccã‘bb¸¢¢‰}®†\¿ñøÒåÀŽNrvæÃ±c ©TºÇ¯#‡7IKKª©)oÛºÔÍýÀ$ó‚Ó6oZÔ×ÇÄáD%$³fN¸ry¯¼¼Ì`Íýu鑼34ÔvrœTTüvµÇ<Y›S§ïy¸ÏUR’s°· HHKKò¯tðxœœ4‹uršÄb±cb2ÓFee]NNé븬ç/âg;Ù"s?ÖÖ¦Hp X€’’êÕóe¬áF{z¨—®nÞ´HOOcÆt«ää¼ukçÃñ «Öo8výÆ“}¿yøxï°è  :È| ?x¼Ø†õ.A'9îÒå¿ß½÷bˆW˜‚‚Ê'ïœ=³SZZ’DR´´ÐÖîŒt…éëûD·Œ»Ó'›ƒ!‘uuÕuuÔù›Ö××<ìµéÐu7|ŸTTÔmÜàâ}å·±c MMõì¦XŒ13Xé:[GGýÜYψÈTþ]îë×-ðA§3‘©ŽŽoמ 3l&L0ÃMœ0†H”477ÒÓS×PW±··†îvEUUÅåËf%'繯šsé¯_wîXÎÿ,í_ @”Æ÷´777zú,ŽÇã!ãÔûBsrJ?‰0aôñ£[ÛX,v\|¿Ó%}= 6›À`0FFÚp¢¸8^`ˆé`o½h‘= ‹Åމɷ“›[æ¾Úëé“sººêÝÝ”ÆÆ6ƒ) ›¼¼ •F(øYñúÜÝæ¬\u §‡ ¿døßöz$$ä<ùûõa¯YYiyDÃ_¬jX-ÈÖhXEªVWW™5kÂí;Ï%%Åׯ[ÀÿÑ@ªÆ ©Zì}f¾‚Ÿ˜|ºwÿe`PdHÐiiiÉÇ1ƒ9ôL]]u.Ÿ½d±Ã€„Åb±[·,ö¹¬®®B")nßÖ‚OEE¡¬äñµë/ýmÝšù³fM0ö Æ}ÕœgÏã·m]*ðQJj¾°™oll»pÑ¿½½ÛûòoÂ!ç”xEî«æ¸º}è6ñ 9ãy ¢; ŸËä–÷óÞ\.ÏÒÂ8äqLZZÁĉc,E§3”•?Äç%ðn+oÞzŠÃ‰.˜?mñ†VQbâ›)ṠèŠRRâÂ¥¨4ºªêPñ0QPþq¾ï¤½šš²÷•½ë7£ð«êë[yï„™™¾f||üQQQUqñ[AÈ<0ÿ|0ÄÿX,vù²YIɹðmkkgww¯ý «÷E>ä\åæœššŸÍ9mÀæ\L+(¨Dþæãrà³dg†øÿço ¹õóŸ8Á žhllãñx‘\.—?ûÈ‘#ZZ>Zá~ÐCËËk„½ggÛE í7m>Á_ª¶®¼ïº,˜–›[ÞÛÛ?òxú4~4þväH177RWW.(¨ìWK|ά™6ð®+ú(ÿö­K½}‚q8QþAá€Í­t”œ_óx¼ä”<׎ «]8ýŠw‡û\iiI‚Ûy<ÈÏ?|Àz[11œ¤!/¯ÿÿqf0`£ m‡½6îØ¾ìÏCøgž‰D©ßöz<¼¤êmý¢%{Ÿ=‹‡ýA!9¼©½,°9<""ÕnŠJuuÃÖm§¼û®]ó˃ûGøm|BBNll&bŽóä––Žúúþ'ObY,6“ɺø—?eðYÙ³m/²ß¶ý4bmm3²n°æìNŸlnÀNõ×¥c#m‡Ã9zìÖÖ-KüO¬\u°¹¹ÉÓÙÕ_Ðh}ñ ÙðûÂúuóSRóÓÓ ‘cŠ·ÒÕ)úý:•Jù2@$JÁþ%¥Õ`¨®8ðé‡úúV5µ¡¢£ üã`½¼¼>#»¯/X?÷³03Óe{¯££àLJJÂÿQøŠåŽX¬ &&ã†ï“òò:1q‚,çº G••åÍcÍq¶mmí<{îQZ’Á`¾ŽËêé¡éŒT›é`#&†““#Žcpâä]”Ô|9Yi#£‘^‡oÄÇçÉ”1fúwî¾xšH&SFÒIIÉ¿îû¸¦¦¹½½[VFŠÿ9‹é`súÌý¾>fvNItLÆUï}’’â"„××·èê¨kjª45UƒC¢ÞŒÖ¬¹éÓÆ×Õµ„…§ÐiŒ«×B/²Ÿã<999ÏÛ'¨¬¬FFF ‚ óý «$$D¢ä©Ó÷ +EDD´4U»•›[N ˆM˜`ÆårƒC¢ee¤#"Sm'yš8nœaAa"Xg'¹¿ u‘10ÚTÀfs¢c2l'‹Ï~û¶áQ@xSS»ÙhýªªzD.—wñ’qqµ””¸……qBbÎÂÅ{¯xž9û 9%×l´>ÿörNÔÊÊÔeÁô̬¢ã'nóxqòŽçÎKÊÊò‘‘©®Ëw÷Å›Å`0C›á3ÄWæ²è׋ç÷”—×Θn5ü EEE¿>j»ˆˆ²pø¶ÇÐPÛðýÆÀORQYG")‡577â‹Å¸ê/!A˜ð~žDR 6›ÃfsDDD†øKð£Åþ‰À`0ÈŸ'Ìpº"—ËŽÎðñþíÒ£ üÓü‡âÍ¿|™XTüVFFjÓÆ…ßÏÙõ×]’ó¦ô'˜†×a_€¾¾&ÖÇáp§ÚY<}wìè–Ϫ‡Édý±ßG]]ÙÐ@ëeh’¼róâ…Ý€©S-þØïsêä¶Ï pò­´‚‚‚‚ò•|_3ÿ×Å=þÂ?o3ÿÇ\¼°'0( ®Éd=~c;iì˜yÏ+úú˜á)¿ï[ §TUÕ[Z¹=zÞÎÎb貟¤³“<Ùn݉cÛæÏŸ §P(´‰¶kfLÿ¹U?qGYYn—§+AÜWÍ–;q;;§d03ßÐÐöøIìÎË f?4wï½XíñQà;¯Ã7¶nY »‚ítu:wÞo°PÂ|Cm     |%ßwÒƒÁ_u6Œ¿ŸŸ8mšå—U…Éò—×ÓÓ°°0ºÿ ôkăٶýÌdÛqˆUHKKžý”Ÿ“ÉÊ.7Ö€Á`œgÛ"“ )Iw–-5X) ãâÂ/°ñÍÍyyE‹§PhEÅoù=¥Œk>„¾¡6PPPPP¾’z ŽÃá$$¼éè$O°1ƒÝžCTQQ›ó¦Lg¤ UWPPÙÙÙ3iÒ‡(U••uÕÕš#Gª56¶••Õ((Èèè¨%'穪*òO¿ççW44´Mš4¦¨èí»šF×NÂþpz{©EEo‘';»ômuƒµ•)2hîêêIM-èc0õtÕµµGÀ¾cssËJËjŒ´á^uu-ÁQ©IwêŸ6Í27¯¾nkëJIÉÅNj!--‰ä¨ª´ô]Oµú]C¥«»§®®%/¯¼¯ÙÕÕ«­M21Ñ… VUÕ§gŽÔai9 ËÊ*nkëž2e\9™LIL|Aдi–D¢Ô`º*/¯ÙáyNVF*/¯\VVZ[{àï§qÓ¦ ¾HÍt°‰ŠJ‡-7Îàr¹üOÁÏp´‚‚‚‚òÃøq[ðh´¾9ó<‰DÉys§ü±ß;))pö܃„Ä7. ¦EÇdìÚ}ÎÙÙI^²l_cc»©©î­ÛϺºzáô®®^ÏÝçc_g¨Tú¥+ÇOÞyü$ÖÊÊÔÛ'Èçj0œÍs׹Ĥ7††ZÎsw66µ1™l …ŽÔ‘‘zïþË›Nœ:¹}Íê_à–,Û'!A˜é`óû~ïÇcÝݽû~¿2kÖ„ù¿Lõö ®­mìÚ}>#³hÙÒ™Ñ1.ú²³KÂÓéx¼¼@‘zøˆ¯½½•¹¹ÑNÏsùùý£g᪺»{Y,vGþÇ`°ÚÚº::Ƚ½´Ógï=}<Áï¯K~™gÇápçÌóÔ×·þ²`wkk ¸ø­«ÛkkSKËQ ïíè ¦+ARUd0YdDEÉÉyãÆ <‹‘¡vdT|½ió‰e+þì[þ¤6PPPPP~$?ÎÌŸ9{_C]uüxqq–͋Ÿ¼ ˆ‰áüžÝ+/] Ñú»v_°oâìl«¢¢°uËQÑþpÖÖ¦H|6CCm'ÇI%%Õ«=æ)*Ê:8X‡G¤zz¨—®nÞ´HOOcÆt«ää¼ukç#±´¥¥%,-GYZŽš1}ü¬Yþ~úúíÛø#EY.—«¤$·ÆcÞ™s••u•udNô¿®’——‰‹Ë}•´iã"‘Ý»\O¾ÇápúL"¤T*ÝcבÛ¤¥%ÕÔ”·m]êæ~‚ «š8qŒ¢¢ìØ1†ööÖööÖ#HJ£FéØÛ[Ïš5a‚M¿ÿó‚‚Ê'ïœ=³SZZ’DR´´pq™®¢Òl˶S+–;ª¨}ø2, IDAT(¨©)O›jyëö³Átenn¤§§®¡®boo=ztÿ,}Cc«€o‰¤ØØÔ_ÿyhù3žƒ}ËCkåóã&í_Çekj¨úù‡h´>-M`ë–%/_&ž>sŽƒB¡Ð$$/CÝVΆKa0þ¸ üQ]0`h¨z' &@JJ\UE¡±±]K‹ÔÖÖeh¨Å/'ŠxçöpŸ[]ÝøË‚ÝEÁ æâ…=‘qñÙmmݽ½4€¥å(}M ­Ù††Z+]gÿ¶×ýæ­§ÒÒ’ð#ìì,¨Ô>øÍ£¡¡M8\ffQ_“Ãá"Q^ôõ5 ‹ªZ_Çe W%++=˜öx6±¯3uuÕÅÅ ­“'¶ñg`2Y))ùöÖpÍWAAj0] Hggðv yybOOèî¡M ­ Ôq ÊæÇ™yYY)33½•®³ù×o8¦¤$wìèf,»qÓq“É"ðÃÜ›/¼âŽÅb·nYìs5X]]…DRܾm¨(¨FFÚ%¥ï¨T:9ÌÚrèÀúukç'%å>{ÏårÚΟÛuæôΘ˜ŒsüH$EYYiyäà "QÒÚÊôÙóxd@ ÓÝÝ[\Rml4’ÅbC›X‹ ÀãŬj8HJŠ3¬Á>ÅáD%$ö6ÖÖ‚uèh=‰‰o¦L1ÈË©TºÀ§T*]uÈØ¾††ZCh5ó((((?˜ï>iA|ÎÝmΫ°däp]pHto/õöÝç;w,Ãb±ÍÍ<âñ ?ÿp×N ‰9p¶Þ^jOqA©áãëï m‡½6îØ¾ìÏCøO{#’Àðx¼Ç13l¤¥%ßôöÒæÌ™ hljãñxµµÍÁ!Ñ·ï<—••^´ÈþäñmµµÍ. ¦åæ–÷öökŸ>c±Ø"""÷ïz]ñ,*ªâp?ÿ°….ÓÍÍÔÕ• *áÄøøœY3m”•å¬Jø¡>¾€9Γ[Z:êë[àô'Obß„ Yåæü*,þ´¯ñâEº"¥à-ô%¥ÕpŠ®ŽzSS‡À—XWׂD`KJÊŒLƒ0´6+…‚‚‚‚òÀzyy}Fv__°~îð³=v+&6³»»wÜ8£ ÌÈdJPp‡ÃŒJ³o¢®®òî]SjjËËÌ*6Ð×LMÍŸl;n¥«Óó‰ïj»»)aá)iéµu-VãMÂÂS„75µ›Ö¯ªª÷ö *+«‘‘‘âry/ùWKI‰[X'$æ,\¼÷Šwà™³’SrÍFë++ËÿuéÑC¿WïÞ5r8ÜŒŒ¢˜ØÌë7ž(+É_óÙ'.ŽWPyú,ŽFë«©i‹‰UQ(´QÆ:/C-Í‘Qi[6/ÖÔ$cpâä]”Ô|9Yi#£‘EEÙ….Ó÷¼Z_ß*!ޝ¨¨{ü$ÖÁÞZCC‹ÅÎt°9}æ~_3;§$:&ãª÷>IIq99¢pU·n?{ü8¦¹¥ÃÈP+.>ÛÿQx]}‹®Žz^^ù»/ª«55TÇŽ5´oräØ-1.1é €7­ë¹·—6Ùv¬ã¬‰ÏžÅ—–¾ëì GF¥/t™ž•U2˜®H$Å[wžb fìXC€(›S2e²9ÿ÷ø( bÆôñðtý¥ËYY%üçåBŸÑÓPPPþn…‚ þi!P¾%?:-‡Ãimí1B Ylf2Y=$’"ƒa³9ˆ7­ÅbËÉëë[ˆD)"Qÿ2?aaÉYÙ%ö¯Åb±l6'&&ãÏÃ72Ó G62™Âãñäåex<A<„ÅŠP(t*•Î/0AÍÍJJrÂ.ç:;Éùù•jjJúúš“ädN”H”âO¢ª¡ùdA:A£õ))É §ªÖÖNdYa¾Ëž°ÐËHg?sKt¤ûyë†Ð Ê¿4íOÇÏoþ¯K$$Ö»À·­­ ïMN¼ýÏJõÿ‹CuuÔ'M ß¾z•ÜÙE^å6矕 åG€šùŸŽŸ-ÞüömK¯x:}OZZ¢¹¹ƒÃá>:ñO õÿ ·•Îû~¿blxzëö³Âª¼¼rä1ÛÚºž>{ù2‘B¡ÁKIÉ M‚ (-­ ¥¥®êUXòĉfüO4}úøØ×™Èmg'™_Ú¡ùǵÑÞÞýÛ¾Ë99¥yyåüÎð+*j#rà‚je~œ™§ÑúæÌó$%çÍòÇ~襤\ÀÙs߸,˜“±k÷y8gg'yɲ}í¦¦º·n?ëêê…Ó»ºz=wŸ} Ré—®?yçñ“X++SoŸ Ÿ«ýcYÏ]ç“Þj9ÏÝÙØÔÆd²)”þkd2544)(8êìù~÷·ãƱXì”Ô‚8Î⥿•–½[²Ø!ôU²×á kI‰Ãátuõttá1}DDêá#¾ööVææF;=ÏåçW@()}·hÉ^?ÿ°´ô7÷C€¦¦v"QRÀ}¬˜®·—ÖÚÚÙÿ\®.úƒ!ù÷hƒJ¥“HŠ\.·£ƒŒ|Ý'OÝŽÉX´Ð^JJÂmÕ¡žê€Ú@AAAA‚gæÏœ½¯¡®:~¼‰¸8aËæÅÇOÞHHÄÄp~Ïî•—.Ðh}€]»/X7qv¶UQQغe‰¨h¿+ukkS8œ9ÀÐPÛÉqRIIõjyŠŠ²Öð”oOõÒ•ÀÍ›ééi̘n•œœ·ní|™~Oòxœ2ožÝ€úÉÉ)åp¸È:}}¢ª††V U‚LMuq8Q@g'Þ`/€¼œLOOd[›Ñ ÿO´•Æ:C_OÓçjÈåKÿhe~œ™—••23ÓØ8¶~Ã1%%¹cG7c±Ø›Ž˜L€æöá¸gX,vë–Å>WƒÕÕUH$ÅíÛ–X96ö&·ÌÁÁ¾–”72Òö½ùô×=n–¢ÓÒÒÉ¿vÁÊUwyº"güde¥1̊厰lðó^»þ˜Á` ñ ‰‰oðx1‹ A)¼Ÿ÷HI}hW^^†J£ WB¥ÑUU¿Äòý«´QQQK$JÂÚ@Y,6ÿám_(((((CðÝ'í!‚×kÝÝæ¼ KFÎï‡D÷öRoß}¾sÇ2,ÛÜÜÁƒ òów]ᔘgëí¥öôPù¶n¤†¯?¼44´öÚ¸cû²?mýðó^´·w#{÷ú½2­øèÄÝ{/^¿ÎBòtw÷";øž¿HXåæÌ_Ü9“¥¥%Öo<¶àýyq33}Íøø~ù‹ŠªŠ‹ßº®pz—?AA‘ð§D¢$Îhkëjoï677RWW.(¨„?ŠÏ™5ÓFYYzÒèÈ‘#ZZ:…U]_ߪ¦¦_?xZ^^#œç_« X€‚‚J,ë²`ZAA%béãràyÂÚ@AAAA¬——×gd÷õëç?ûÑc·bb3»»{Ç3š0ÁŒL¦Gq8ÜȨ4«ñ&êê*ïÞ5¥¦ð¸¼Ì¬b}ÍÔÔüɶãVº:=‘ø®¦±»›ž’–^P[×b5Þ$,<åQ@xSS»ÙhýªªzoŸ ²²).—wñ’qqµ””¸……qBbÎÂÅ{¯xž9û 9%×l´¾²²ü™³÷ƒ¢êêšy<^FfQbRn@`ĶgllÌôõ4fvNItLÆUï}X¬ÈÁC×23‹ÛÛÉ$UÅ#”RRþÂW,wÄb?¼¥1ÌÇ17,„o×m8ª¬,leà_¨ ™è˜Œ¾>fm]³£ãDYC­ ýx<ÞÓgq<t`ÿZ‹-¬ ”oÉ­P°aÃ?-Ê·äGG¨ãp8­­]#F(!æÉduvöHŠ †Íæàpýão­ÅbËÉëë[ˆD)"Q’ߢ FXXrVvÉýk±X,›Í‰‰ÉøóðÌô_&mzz¡Ç¯²’'--òò2j£PhWØÅMg'ãŸ^~v@o/‹ÅJJŠóÄáD‰D©!»pÑÏØh¤“Ó$$% 0‚L¦nÞ´èsŸqøüm´·wËÉI#s055µ+)É¡!òPP~¨{œŸŽíÓ^TTTMM™ÿ—C~딇­…††ªŒŒÔpl< ¢²ŽDRÄb±pmææF_c!Øl›Í¨ª*V´´ä€nìd–…Ÿ@$JñÛx¸àÐ6°yÓ¢ˆÈ4äËåFGgx¸ÏùÔ}?@JJrüë, FMMµñ((((_ÌϺfû¶¥t:ãÔé{>Wƒ¼zñ¯GN|YUUUõA‘ZZ¤óü¾­_¸8Ámålß›÷§NßÛ¹c¹¸8áûµøoÖ Ê`üèI{”oHffј1·¸ø-å«@'í:~Ü:”olÚñx€Úx”ùÙ&íQPPPPPPP3‚‚‚‚‚òÓ‚šùÿg´´tDE¥¢¢ÒÛÚºþiqþ?‡ÂƒÝûÀtþi‰PPPP¾;ßwm~§ç¹ à¨”¤;üþÉ? Ï]çƒúk€ èØñÛ«Üœ_ªÃÇÛ'(*:½»›òòùEYYiþ._ |ð0tªå*7g³÷¾ÖEùÖ» –áæ­§ç/øýñûjØ€Åb>róâ…Ý€©S-þØïsêä6þhCðêUrÈã˜Ò²wçÎxNž<Žÿ£¤¤ÜÝ¿^0¥»ÐeúÜ÷Ñc¿€ìì’GorËŒ µŒ´!êî¦UIKI<¸ä‹«ýzêë[º®§§®®®ÒÞÞM")2,eyþ‡mmí¼výqJj¾¬¬ô›Ñ"""4Z_yym]}ËßÏÊËË|V‹ii¾*.ykh ½eó¢qïýmÜt¼´ìÕxÓ3§w»jFAAAùæ|_3ÿ×Å=þ¿Æ5éÅ {ƒ¢à˜LÖã'1¶“Æ~™ß¶u)›Í‰ŽÉðóÛ¶õƒ£{&“U^^SYYŸ•ñp˜Gó¿yùå¯Â’‡0óë×-ˆŒJc±> :½ߨºe1·FL ·ÒÕéÜy¿}¿y §9ggÛ#÷¼zéJ€€™[Ý›[î{}ÿ¸A¼æ KËQffúx‰ »=]‘˜4d2å—»_ýÒØØV\\=s¦Í×´>©©ùn#}ttúß5 «&Ú®~xÿ£w** ^nœh»z´©Þî]+áD.—»yËÉwïš>×ÌO˜`6nœ¡¦¶óòeŽüZ=vt˱ã·Ïõ~Uwï½Xíñ‰`ƒ((((ƒñ}Ç †@ûV5øüÜÀiÓ,¿¬*NtÃ:ß›Où_;""RgMä¼öÃØ¸aá‹g‡ÎCÀÐ…B+*~kjª‡¤Œk»‚8œèJ×ÙQQé--HbCC«ºš2øØ7Ñ»²á§ÊÊJ»­tîîî¢TJj~o/õë[‡).~»~ñÌÌ"Ö·ÊãÏcG7#60z´ÞÖ-K,+&†ã‹ÅîýŸ{mmóˆA à=ÜçÞ¹ûœ?ñehâo{݇_ Ap„åÏ%>>{Óæµ_Pågâ‡Nr8œØØÌ à¨ºº8‚ òòšGéé…ü9y<^^^yll&^¦²².22íÝ»F@cc[llf^^yo/5,,‰¹“Ÿ_ñêU2™LINÎ{è÷ ‰¶âà`ÝÓCÍÈ(Br’{¨Â^Û**j#ràð* -1ñMll&—ËÏŽÍä_ÖíëcDF¦‡D76¶Á)ˆl -,,¹ªª^ NNÎKN΃_2úúII¹‘‘iC럿ŸÆM›*øŠ3ÓÁ^ª‡•ÖÞÞ=Xqy9â/óìîÝERââ³…ßœZZ:ž<‰}õ*yÒ‚‚Êð𔦦öòòšðð”an ð¹ AÐ`_YBBÎÿö^zWÓ”—WÞÑAæp8))y¡¡I¥¥´´t´·wWVÖUVÖ55µZ«ªê4½YYÅîúù‡;º>døäïØ––Ž….3r.t™ÇÞý¤ð::j::j4Z_YYMUU=Üýª«Þ¾mxû¶L¦$$äÄÇgÓh}11ÙÙ%H˜%Àºµó³sJóòÊ‘”ææÄmmspHtLL_d&(#£è¡ß«¢¢*x'Áoû.ç䔿å•U!•ôOa¦NµÜÿÇšë7ž¬]w$?¿â“ß ÊÏÊ3ó4ZßœyžD¢ä¼¹SþØï”” 8{îABâ—Ó¢c2ví>çìì$/Y¶¯±±ÝÔT÷Öíg]]ýÁ®®^ÏÝçc_g¨Tú¥+ÇOÞyü$ÖÊÊÔÛ'þQxî:—˜ôÆÐPËyîÎÆ¦6&“M¡ô‡mÅbEÖ®ùqWUU¯«#¸iàä©»Ñ1‹ÚKII¸­:ÔÓCe±Øá©Ûvœñ½ùTWW½¶®y¹ë~8ó»w«½ µgM¸uû™ÿ£pD¶“§î†<ޱ¶6=söþ¥Ë÷„j……'ï?ààp¸1±k×÷¯X¨’“óÆ5H42ÔŽŒêW¸wÿ¥®þ/üff@Ö¯[póÖSøÕÎ ûFHIÉÛ÷»÷üùSED0Ófl‚Ãĵ·woÚrrÛŽÓõõ­ÚÚ#Ö¬;?ì€df¿x‘pæì}ØÀhjª*(Èö•q8\yy"…Bïè 3L%¥ï-Ùëç––^àæ~ˆB¡:}oÒä5ð”@ié»Ùsv¿Ešƒ (!!ÇuåȨ´¿.î9ybŠ>;»TK‹$ì.wüx“9s&(üÛꆗ/ïÜ};ÖÅb§¤æ™[º‡D¼}‚·n?UVVÃd²^†&-wÝýÆ--RQñ[ÇÙÛÉd \•–Ý󛷞·ùùcÇôƒAÁQ'NÞ™7w €_²lü"¸xéo¥eï–,v}•ìuø•J'‘¹\nGù+îŸÂƒsjh¨^8¿ûÔÉíŸÄº­:8Ä$ ÊOÌ3ógÎÞ×PW?ÞD\œ°eóâã'o$$bb8¿g÷ÊK—h´>À®Ý¬Æ›8;Ûª¨(lݲuY[›"!× µ'•”T¯ö˜§¨(ëà` ÏmöôP/] ܼi‘žžÆŒéVÉÉyëÖΗ‘ùà"~ÍêyŸÄöôP)©ù“&á2=½08$zë–%8œ¨……±¥¥ñÁC×dW¹9—•׸,˜¦¡¡êä8)<<οuûéå˵µG‰Rü¾æ·}—ZaÙŠŠß®ö˜§  ëà`sêô=÷¹JJrö6°œÒÒ’pðu˜õ @Cc«ªª¢@"‰¤ØØÔ?‹°ÐeFXèe›-ÌäÉãp8Q8¼l\\öôiã2ðxœœ4‹uršÄb±cb23fXk/˜?ÍÞÞÚØxäUï}›6Ÿhhh° IQWW]WG{à`_ÙŒV 2f£õìí­ÕÕUp8Ñõë`0’ªâömËüÕÑQ?n“É–––¨¨(x_þmöl[AaaÉË–ÿž›Wî{cÿýëæfúú˜Ÿµ +#¥§§¡«£.-ýÁ ¿œqíšùOBÎF¶µuÉÈH……^†»è¢…3$$»w¹êëkz¸Ï©=âà¡kHÁõëø?Š€V""S'ÈdʆÇ\O àmmÇR(ôŒŒ¢¾S(t÷¹x¼Ø(ã‘::ê#Gª·4‘’’°··ž2Å Ò?…5Æÿ8JJrGlö¾ò[|BÎ ×ý¯_g¡a|QPþSü83ÿ:.›Ngøù‡ùù‡Uii’[·,‘—#ž>sïQ@€B¡Aô24¶b0þ¡ÿ: µà5uqžÞ—’WUQhll´µuéè¨ ˆ¡®®2eйÿ£p8žÀ’|dTÿ¡}=ÍWaɰr²ÒðQ\Ï`°,;&&SO¯??'ª¢¢Ÿ-$ÞÀ@¶¾ââø¾>&òhHCÂzV`ggðFyy"üÊ‘‘²µ; òùÁ`0ëÖÎ÷½õÐÔÜ®¦¦,aòäq+]gŸ>sïúÇT*½—Odý^SSUUU!>!gÀ&4ÔULLt.œÈš$¤ÿŠŒ™šêÂ*ÈÊJ¯Xîxíúc@\|¶ƒƒ5œ-""uûγÚà¹s…@ ss£ÆÆvaÃÖÛK--}7`Ó ²ÆÆ#íì,÷0Xx€ƒƒÍòe³l&zìò\Á¿„Ïß‘ìì,øWÓºLÁ„<Žéëcàñbp7ÈÉ)e±ØqñÙ🃾ž›Í‰ŠNóþ Ç¼yvî«D4XÿÖ˜22Rû~óؽËÕcWJJþ€Ž‚‚òSòãœÝÊÊJ™™éñaë7SR’;vt3‹Ý¸é8€ÉdøaŽ7„$a±Ø­[û\ VWW!‘·o[*\jú‡¼®ki’f:níÆãÅà9j‹ÇãoK‡åß Ïb±ñï7ÍñçÿäÑ)a=0LxG=‚¼<‘J¥ ¤Réªý¬ûª9^‡oV©(PöÞý—A‘!A§¥¥%CÇ ( €NgHtN˜Ëä–ÖN8ehU$&¾‡­ˆvÛ¶.±›¶aû¶¥òòDĦ:9Mоvá¢?ÎØå¹ÂÄDW Â_æÙýþ‡wrržÀá‚øøáÌ (.y‹ÌðKJŠiûÞ|úë·KÑé þiï¶Òùæ­§8œè‚ùÓàDYYi ³b'Ï>6 IDAT¹#¬ øâÚõÇðëã€TTÔ‰’CôO ¤1~²³K.]PQQHO½‡l@AAù/ðÝGóÁc)w·9¯Â’‘qUpHto/õöÝç;w,Ãb±ÍÍ<âñ ?ÿp×N ‰ýÃÄÞ^jO•o@jøøúÃ{ACCÛa¯;¶/ûóÐþIc:ÏΞ=©½½;=£PQQ–_B€Ë‚i•È/i|B|f?rÅb—/›•”œ ß¶¶vvw÷Úϰ–m@9‘ôÁô P®ŽzSÓ‡ò0uu-êê*ðumm3²í`@ ()É9϶ݾóÌŒãIÑ®xy¸Ï•––„ ¨±±ÐÙÙ_dg—ˆˆˆLj ØK(𘀿.i «É@$JÒû€’Òj>y>ªÄÄDwÌ}÷Õº,˜ÎŸ®­=âò¥ÿ=²ùÁÃW«½rrJù?1BÉÇû· ›Žó¯ƒ°XìŠÊ:x¦§¦¦‰3¼p»±±™N÷{è÷Êl´~à£wï½€W=`º»{‘mžÏ_$¬rsæ¯aýºù)©ùéé…ÈAP33}ÍøøþN^TTU\üÖu…Óë¸,¸«CÙ¯:PPP‰Åb‡îŸÎÆ'%å.[þû³çñ/ì9wÖµñ((ÿ5°^^^Ÿ‘Ý׬Ÿ;üìGÝŠ‰Íìîî7ÎhÂ32™Åáp#£Ò¬Æ›¨««¼{×”šZÀãò2³Š ô5SSó'ÛŽ[éêôüE⻚ÆînJXxJZzAm]‹Õx“°ð”GáMMíf£õ«ªê½}‚ÊÊjdd¤¸\ÞÅKþÅÅÕRRâÆ ‰9 ï½âxæìƒä”\³ÑúÊÊòÿò÷½ùwzF¡ÚemíL&kÚTK--Ò“'±¾·þ./¯¥ÑèÊÊò£Féh]¸èÇãñž>‹ãñ û×64´;~;?¿‚Édk>â[PXE£õÙØŒž5Ó& 0²¦¦©¾¾ÕçjÈ…ó»uu5’“óÙ :ѯ°°JB‚@$Jž:}¯ °RDDDKSõè±[¹¹å‚˜Å€zHIÍ^_ߢ«£®©©*ŠÅfç”L™lίáG3¦‡'r_¿Î:rìæ–Í‹1¿x‘pôøí¸ølAlŒ™Š²<'jgg‘•U|îüüüŠŽ2€70Ðär¹Á!Ѳ2Ò‘©¶“Ƽ M7ÎÐÔTÏÏ?¬­µ‹Ãå–—×ú\ ñ½¾¶[—.de•ÌŸ?5+«øÄÉ;YÙ%} fCCkjZAXxÊÙóîÜ{qöÌΜœ²Á¾2)I‰À H*•nd¨­¢"ðеÌÌâöv2IU‘ß,ÉÊH±Xlgç¶ÎIKK8Ø[O™2ÎÏ?ìÖ­§**òššªðGf£õGÜó¿‹LFFQDdêšÕ¿Àq{cb2vxž[±|V_ãô™û/^&vuõP(´´ôÂØ×Y·o?ûýï-›ãp¢ž»ÎŸ¿à·ËÓUMM9öuæ¥ËT*ÝÊÊ´µµ+(8JDD„J¡ßð}¢¦¦üû¾Õü+2ÊÊò‘‘©®ËŒGÂ)X¬ÈL›³çÒh}åå5••uNN“ 4!ºs÷`^†&Ž·E")*(ÈDÇdôõ1këš'*(È ÷O‹-¬1‚¢¢Ò÷ýq…Ãá9¼i¶Ó$ ‰ï§åçáV(ذáŸå[ò£Ñr8œÖÖ®#”ßA&“ÕÙÙC")b0x½N§ÑúX,¶œ±¾¾…H”"%‡s´=,,9+»äÀþµX,–ÍæÄÄdüyøFfúƒÏ‚ ¦¦v%%9áÚB§3(Ú€k¢Ãg0= °Xìù.{ÂB/#)<Ï~æ–èHŸOn»û\x<^cc‰¤(**Šã8{›‡ûÜù¿Líí¥)+ËÛÙlNo/UAAvˆ<¡¡I&&:#G î·€B¡Ýðý{ⳉ?쯄 ¨®®¥²²nÔ(mJJ‰¤¨#tæb˜¤§z¬ñ*+yÒÒÒ!//3`ŸillSUUþš:;Éx¼ÿd»ð ½½[NN™šNÿŒ‰É(.©^¿njÝQ>4íOÇD+***°ç C~vùm›¤¤8¼©JCCuøõWTÖ‘HŠðï)'jnn4LS̓ޘ6„¯ÿ1Lbb¸eKg¦¤äMšÔ¿¯-<<ÕÃ}Î7·ñDíˆ0l6‡Íæxáuú¯‡ÌƇ‡§¤¤æ=²¹ú]ã`§àø‘––^8Ç`0ZZ¤ý'UM˜`ö2ÃÀjŸƒ@¬; ?²ð@IIŽÿv8ýÓÞÞÚÞÞzè<(((ÿ~6¯ÚÛ·-¥Ó§Nßó¹|ààÕ‹= |tâŸê›á¶ÒžU46¶ÅÄf¸­tþd©o½û/ñx±¸¸ì¬¬âÓ"‚¡¡“ɺ|%pÙҙ߼ò¦¦vK‹Q_ì^¾ªª>0(RK‹tþ‚ß· å›ð£'íQ¾&“•Ÿ_aeešœœgeeòs((((ƒ‚NÚÿtüèI{”¯ƒÝ¸çˆ< ÊœŸmÒ5óCÁb±#ee5ÙÙ%_\›Íéì$Ãë#üaoP>T“((((ŸÅ¿kÒ>!!çàŸ×ŒFÞ¸¾ÿŸ–ŽŸ¸ ïq32Ò>qò‰¤øY;ð))y>WC,-ee¥››;¦Mµ¼výñUŸ}°{öásá¢_ìë¬Þ^š“ãDN´««—ËånÞ´hˆÓe;=ÏG¥$ÝáwúÈÈ(Ê/¨Ø°Þe° 7o==ÁïßWî]†É·Ò$ ÊŠ—™·³³X±Ü199ï Ê66¶WÏœ)è¿ö‹‰ˆHUQQÐÓÓ€owîX¾ÓóÜMßÃLÅ;0äqLD˜7rÜîþƒP¿GáW.ïý\avïZI£1^†&þñû8%'§ÔbüÊÄø›üèùùëâÿGá?>NI^~ù«°ä!Ìüúu "£Òø’o¨I”ÿÿºIû/>“’šßÛKý†’ø\ æ÷Z*))®¨(›˜øf˜Å «ö¸zÿîaþ#õ«Üœ­­L¿LN”ÿÜ—……ñÈ‘j>WCËÁ`„CÝü6nXøâÙÅ¡óðC Æd²nø>Ù½ç|ûIM^ñ<|Ä>gˆ‚‚‚‚ÂÏwÍs8œŒŒ¢înг³mzzáÈ‘#`ÿ!µµÍ™EòrÄiÓ,×.äììR}} ¤xcc[yy­¤¤¸µµi[[Wqq5'Šl/ooïNL|C à'M#++ó¿½—¶m]’—W®®®¢¨(›–VÐÕÕkk;VFF*+«¸½½{üx%%¹’’꺺SS]‚ «àD*•ž’’¯¡¡2j”\ÿ»wX,V Èü_¦EÚÙYÀ·mm]C8ƒ»ø—ÿ„ f“ê fÉb{ ¢¢„„7ä 6fššª -7·œÍæLj‘””ËåòììÌùÝò @¥Òååûã®VTÔæ¼)AR²µ+à0‡NgÔÕµàp¢ééituõtvöp¹<55¥!šëëc$&æöôR'M/U46¶••Õ((Èèêª'%åhéêªs¹Üôô"À¤Ic0L_#;»”NgÌš5APEEmΛ2‘j66£{þ'ò½ùwZz¡Çª¹È|À'5¹}Û²¬¬bÏ]çGŒPòܹ|75((((ÿ5¾ãh‚@Ié»EKöúù‡¥¥¸¹G8ygÞÜ)~ɲ}ð”òƒ‡¡zÝ02Òîè Ã; ýÜ…‡gÏ?Ðh}wî>÷:Òdÿõë,5^VV&66¦¶SÖvt9®¼<‘B¡wtáð¦•Uus~ñ¬¯o45µ/Y¶¯¼¼ÐÑAÞ¾óŒ·OpAA•••©ãìíÿý:&&süøQÛvœ‰xB45­`ì'22ÒŽŒJ‡¯««TFÌÂWLvN©Þ@‹â»w­$¥à‡š3Ï“H”œ7wÊû½“’rY,vxDê¶g|o>ÕÕU¯­k^î:ð:áí$++½÷§îFÇd,Zh/%%á¶êš†ÍæDD¦êÎÏË+twSæÍß•6DsïÞ5z¬ö24Ôrœ5áÖígþÂT*ýÒ•€“§î†<ޱ¶6=söþ¥Ë÷„j……'ï?ààp¸1±k×ë9{îABâ—Ó¢c2ví>?˜®ÝݽGÝÚ°ñ¸…¹qpà)gg[dq䓚Œoòàþ·•³ºî¹ë\mmóm¡   üwøŽf‡]¿nƒ!©*nß¶ÌïÁQ2™²aãñC×x[Û± =#£¨¬¬æ{/?·KK‹deeêä8 .nd¤í8k"|=r¤—ŒÉd¹¹<ðÇZ UiiÉɶã°X‘3¬dÌFëÙÛ[ÃÛV¹Í‘“•†‹üòËTdÚ”)ææãŒz{iÎÎ¶ŠŠ²6Ö¦ÁQóçO•——™l;62ª?ÒZCC«ªª z)dfX[{DT¸÷ر†ƒ=>Îb 8sö¾†ºêøñ&ââ„-›?y[AAv•›sYyË‚iªNŽ“ÂÃSø‹Ô×·\¿ñøÚõÇ×o<Ö×ÓLK¹+##•ž^½uËNÔÂÂØÒÒøà¡kb{î\1iâ6‡ÐÐPÙ¼iÑΡhnëöÓË—9jk ¥þø}Íoû.74´j;9N**~»Úcž‚‚¬ƒƒÍ©Ó÷<Üç*)É9ØÛÀAÖ¥¥%ùc KHÄÄp~Ïî•—.ð‡‰ChmíÜÀg÷ž NŽù·³³ØýÐ×÷ M"˜˜èÞô=°sÇòóü¶l=UQQ;œR((((?1?"­©©.'ª¢¢“SÊb±ãâ³ýüÃüüÃôõ4ØlNdTšžž¦?~¶˜Ø‡wä§¿¤¤º©¹ÃÌL &†»võw99â€Mó{ˆã· ÆÈH¾'~¸îëcÂ×=»0 ' ‡ qp°Ðù<Œ¹¹Q}C rË`0OŸ¹·hÉÞêŽ;vž¥Ó¯ã²ét¬ŠÂ¢*-MÜ„œ¬4G\/€\Nޏiã¢Í›íÞµrÖ¬ ðR}dTÿ^z}=ÍWaÉÂòlß¶ôò•@Àó . ¦!O$Ü‹ÅމÉÔÓë¯þîââ³ 04Ô‚•)NÀh ââxDuüªÞºe‰¼ñô™{" M@*‚.ÞËãA¾7XZŽX“ãŒ[…ÓssË`gòŒ©vé¯_­¬Lìgn˜Ø@AAAù¯ñ#vÚ#+ܲ²Ò fÅrGØ>Áþ’ÒêáìGIÃñl˜L|!Lbâ›)SÌ‘á0Èê¸À5‚¼¼ •JN— 3TŒ»Ûœ•«ôôPed¤þ·½ 9Oþ~}Øk£„AVVÊÌLìû^žÏ{÷ÂãÅä‹Íÿª„à²`úî=²²Š››;õ6‡ÅŠàp¢ü;áY,6òÆŸÿ“¢®ßpLIIîØÑÍX,vã¦ãƒÉÿþ„Á`â|CÇ,^ú›“ãD÷¹x¡Ýyî«æ¸º}Ð$B|BθqF™y<Þ³gñü^M›jYVòφ‚‚òçûŽæ¡÷À·ffúšññ9ðmQQUqñÛ9Γ««‘QW}}+—˃¯‰D)d8[\R §ëéiX7‰ŽÉ€Ó «ŠŠªD¢$½()­~_\.N¥ÒkjšàQ8"Հ׈人êMMíC&SˆÄþSÚL&ëâ_þÂÃSggÛE í7m>Á_mm]3x?Þuw›ó*,ù48$zy>âÇeÁ´‚‚JÄÒÇ'ä çÑù‹àp¢›6.Ú¼õäx¾Aó€Ía±ØåËf%%ç·­­Ýݽö3¬>©:$½·—zûîó;–a±ØææñxŸ¸@=X,vÙÒYOŸœARru;pérÎàÀÙ³m/²ß¶ý4bmm³ÀþG‡ãÿ(|ÁÂ_;»z‚Nîܱµñ((((X//¯ÏÈîë ÖÏf^ƒyðеÌÌâöv2IUqÄ%,Vd¦ƒÍÙsi´¾òòšÊÊ:'§ID¢¤…¹ñ©Ó÷±”Ôü”Ôü¤ä©®nTQ–76©¡®|õúãËùŸ(5µ@DDdÆt+@ssûêµGæÍ2Äfû9ζ­­gÏ= JK2Ì×qY==4‘j3lÄÄp£FéÉ” à(‡•f5Þ„Á`;~;?¿‚Édk>â[PXE£õÙØŒ¾z-$äqLmm3ÎÐÖ&ñ¯S((Èh]¸èÇãñž>‹ãñ û׊ˆˆ=v+&6³»»wÜ8#xld¨õ÷Ó¸C×Ãïuu-ƒ57k¦M@`dMMS}}«ÏÕ çwëêj$'çyû••ÕÈÈHAtþ¢_aa•„H”æfzÌ÷7ÎËÂkOÁÚµÿïDpøžü,Ôáñ½<<ÜŒÇÕ jkÃKK‹ ÈdŠ˜˜¼²N§ÓÛedÄi4zo¸òêg dx˜ÚßO`´áÝ×G ‘(²²--||<""‚cŸ_ºlopÐ^ÆÐÖùÛ¶Õ]GGu\™¥Ñhååµ]]½††X·P©Ôöön99ɱkÝ‚ZZ:%%EÙØ¬koǧg¼[²xÆÃ$‘(Dxåþ«Âãûde%P(Ôð0•ÍnFrrJž>{uôÈFG*•ZQQ‡Ç÷k!{ìAÁÑòrRóçOùj{²8pøÇBÝ/Çí¨TTÔÅ'dîØ¾¾íèè>rôÚ¿QíZkkךuGŸ>>ùÊýU+ç³.~sàÀÃ'8Ýü/gô3*ÚÚ*BBoÞ”†‡©?¶ñÿ¨¯AR§¦*kfªÃéã9pàÀá?g4ÿ23 mmÊËkEE…8êÕ8pàð‹ÃÍÿrü\¦k~B`õºã]çÀ~8“ö8pàÀÃ/ §›çÀ~Yþ+Ý|NNIeeÝ·‡ÓÝÝ78øIc¢˜ÃOÅð0ï…7pêè{QQQ——÷þ«'Hˆ.)N¥| ñæ0^~ÁµùmÛý£î%g½ºhz¯­m~ŸyÄoýW‡I&S|‡45•ˆD2•J›jg÷0•é`÷y÷®âÎݧ™Y…†ttTÉäÁîî>cc-÷Ù£éÐMOÏ?pè²®ŽjÈ•‘­Õý :zìú Ï9°®!VÛ¶ï ¨ªj(.Œêêê ¼™š–'!³¶šèë#X˜ë3žeÏÍ--*®BÌËþ²² ƒ‚cÌÌtp8¡ÖÖ.û©f—¯ÜÚ+$$ð!_»þP_O},¶tÛÛñÁ—cì_=F 쩨¨û}Ïy‰òâù•q=xõZÜÙ€°?ö­DT"~#ÚÚ*ÇOÜ••€­‚®ßx”›[jd4‹‹«»»o±«Ãa¿«áaGÇ›€€sa/^¾íï'Îv´Áb1ÝÝý4m½+“…bF¶nó¿ý·WÁ?CXx¼¼œ”½½Ù÷MØo¿6?W7óÖã•Þó¿1s;£î%#'h4Úž}ÃîùêñøÞÉv«Ý´páTØe`€hc»jú4óñeb¢mh¨ÉËoãçëãäd  R©ËÜÿHKË¿qýϱ³3]ºdFNNÉW§ÿ뺛b;Éh´n^QQÆ÷ÐZG§Í Ü¿õÓgøhMPÞ³Û|ÎWìƒwnûÁš ‹*ŸÅgþ¸nþ⥨˜û)‰ñ—··ï< ‹Hø.ªâ2‡‡©céæ›š:îǾغÅMLL„·‡ÓììLF³º„ ­­²sûò]»Ï/¹¬Y휔üšÑ0Á·³u‹ÛÖmþWCŒQ•AËÜöÉËK…†ì‡¡Óé«×){ÿñ+bß±}9‘Hyò4ã}«`—üürSóåiWõõ5F|äü¹á ã;Lô=xþ=ÙÖéãBBgNmýºÐÐh4Í…Œq1Œ—çÜ›·Ÿ´·ãG{„ÕVÞ?//OQA›W`I‹A:8_a ÕÕ °Ëºµ.žû^É ݱ3¾-)ù°ÿ@ð훇õدðœci¡__¼uØ/±#<^Ü÷_ïã:Ÿ¦¦:e%1ìûx@òóÄv{¾ºöy¿·Ž> \FÆ»1ú½ú ì}ÍÉ›©àââ:°ó«•7`±FE‡¦¦:ªªòAÁ1£ùgzücܾuxïo6¾˜°q‰7A>ëß¼õxDƒ8üðÑ|oï@FÆ;‚ìíÍ„…;:ºa+5""‚¸ŠŠ:nn¬€_?aË6œˆ`aa%'¤¢" R©ééïºð½ÖVJJ2Ä‚‚ÊáaêÔ©¦¯^Ðht;;Ä9N/.®Æãû&M2dL@Xxü–ÍËÄVrscMMu^¿.¶°Ðççç%‘(4m´‰¯††¶¨èäìW7˜ÜííÍ +‘ÛúúÖÜ7¥b¢Âööfh4º¹¹£¢¢N\\DMM>3³PFFÂĄٖHâÆb`ƒ{åä”ÔÖµLÔט8‘yŒÒÙÙÓÛ;à“““ljj§P†°X ƒf]GGwVVƒž:ÕÎfvvß7s¦UEE]gg!??okkW~~¹™™¬ ºº¡¦¦yÂ%xR”J¥æå•¬i²´Ð×ÐP-/ŒôõøÄÅEd2%/¯œD¢Ìše;ûúÙÙE22âjj §jÁF‡ÿ*.)ôêƒ×9%Þ+æ!sç·[[0ÍߢP¨%‹` „›7-{û¶lÛö³rr’Û¶ºKBmmsMM³ˆˆ l*—½À¼}[ÖÑÑ3eбÀû÷5 múúꀂ‚ʉ5TTä(”Áè˜ç×®?\ìê **¤­­2ÆŽœD¢44´a0hNHBÇ>L°ÊûZhhh+*ª20Ð~•Y0oîIIQÀÂS£î%ÙÙ™ÂÞ::ºÙØt8uúöšÕÎL_Ø""‚³mÛqµqV’˜Ø§‘ªªúüwår²’¶¶FLK`pÑa±‚44»»ûðø>.//É&:2™’‘QÐ×O˜dc/U  APIÉss=IIQ”•U¤¨(­««—IiéG!!~ss=¸ä«ªêóßU¨©Êe6è+Ä…Bí‹K]ê¶wú4‹U+çóñqŒ6qø‹;š/+ûèáyÀÒRßÌL×eñî®®Þ¾>BXxüEµµ-y¯ò=ÑÞŽ')²2”Á¡®®Þ€H$Ï¿MXX`þ¼)ì¿ôêUÁÐÐpBbö¦-§C¯Æ©«+Ô7´ºy|Z®Æã{—,ÛÛÜÜ©¯¯~íúÃîî~$ oÞ–éé©Ã×Êàƒ¸Ô‡.ß¼õøÖí§ç·|Ö_æþÇhY€·±vl<<Üûö®„¯ïE'?qcþ¼)¼¼Â…KQ—‚>){ill_༣½½ÐÕÕ»yëéó‘ÅÅÕ––ú.‹w¿{WA¡ ÉÉJR©Ôîî¾®®Þ1ŽéƒƒCS¦®>†Ç÷~1ŒŒ(Wlj!:æ¹ïáÍ#G¯_ŽÑÔPª­m†ÿÒÖVIJίkjš¤åf¾}[6b¤x|om]ˈ_„¾®ƒ/ÆÕÆ™ ‘(—‚îápB»÷œ8yóyJ®«‹]rgŸ IDATƒ  ¿çŠCˆÅK˜áajbR¶†ÖÂÂÂJ@OÏÀü…;’’_³‰®¶¶Ù{¥¯––²ã,ëk׆G$€Ïz)(º¸øƒ……¾£Óæ^¦¤¼17×Ý´åtbb6œ© ËÑ"ápÎøßIÏx·ÈÙþyJîögÙTÓ·ˆ7—‹Ëôؘ3êŠÞ+}Ïøßac<“ÃÛÍoØtÒÝÍQZZ\^^Ê~ªÙµë55•ûú:°:$4¶ªªaÝÚE—.î12Ò21ÑÖÐPPTvp°„G§ÏÜVT17×ãããݰ~ñ±×ÅÅq+<çTTÖ-r¶WT”™í8)!! ŽhûŽ s½9sl¥¥Å7nX‚(ƒ ˆD¢ ã  ·e³23 ½VÌ <¿kë7ÀŸ‡ÖúŸÞ6Z`ã¶l,žõö¬]wìÐÁ5¼¼<¶¶F¤ÜÜR--•ÙŽ“Þ¿¯Yé=_B7c†eBb6ãSqS¯„Ü?ñ*³ æÞI¯sç#ÄÄ„íí͸¹±K—̬ª®‹Ke|JMMá¬ÿöÁÁax '--~éÂ''ÛÑ¢#HÞ«|ýû ÈËKmÚ¸ÔÓëAî³%%E……ÌÌt55•Ðh®ºúV[[#EEeeÙׯ‹––ú& ÖÜ%Äq4MRRt•÷üÓþwF+¶v|^Þû¬ì¢ˆ¨D--e =Ø]HH`¹‡|ͦ¯„ÄN²1ÔÐP\³Ú97·”‡‡ÞAÖÞŽß hÇ΀َ6áÇììL™–‡Éd ›1#zzêWClÝâv6 lÃÆ“UUõ_|ÄÈHkîœÉÈ-{Y´hš´ô§î”)&&ÆÚ$ÅÉÉVJJÌÌTçeê[NÈÁÁ’‹‹ËÎÎÔÁÁžÅù"4íæ­Çâ.ïÓÒRùb2Q®ØÔÂÉS·<Üg++˺»9¦¼x3y²±ÅçµAdáCEE.9á’‘‘Öˆ‘’ɃÌ(KaÆÕÆaÛ®„Ü¿|åþ•ûšJ¯³nŠˆæä”DÇ<߸a ‹15Õ13Ó9xè2ãS""‚Û¶ºO²1¦RŠŠÒë}\·nqcÝÆÍ§Ü–9ª¨È þ±oÕž½ššÚá íï'Ιc+!³²ÔŠN^¸pª˜˜Èd[£¤ä×UUyÇYMWðóórscyyyvîXx!’H$³–Ã÷o 5k–õ½¨“6Ö6žü–U*¿?°›ÊÊ*ª­m  §RiBBŸ¬Éýyhm{G÷!ß+«V.íñ—©y$~¶¤ôƒ²’,…B‰â„`›i||<°9y‚ž<Í0þüºA¡PH¿N&2 ˆQ(”šš<¯ˆˆ lÝN]]’;¸«kllG\RSóºQQaaaA.‹wÓéPhÈxÚœcí¦ævV÷‚‚Š,UUåÏï²°Ðs˜¹iä7"Œ‰g/0¬9ÕÖV¯ùøx˜Ä`Œ‰”M›O¿xù–qÖ÷‹É@M®F­ Ŧæ@Gg·šóD1‹¡Ñh..®3¬F;P //%)klú«R>|hë\×û¸îؾ|Ö,kx©>)ù5ã–õ`ó¦¥.F=N_äläˆ5º¡¡á””7ŸÂÄb1ÒÒâ©iy€¹By/üeþ.7,>uúVDd"€uý#Ä{Ò$£kWvtt{z1@ÿ)~`7Åbøùyg8X-÷pZîátèàš–ÀÑht3S²²ðÀ‘ x'h` ?»n­ rœŒÕØ( …âååq×*•JcrÓø F[[ÅÒBÿá£4ÄÅÞÞìˆßzyy) s}GGN…B¹»9ÂI º´wòdãÑ’ÊìÐÐ0r;44<âf¥M—\½×ÒÒ)&&ÌøBaއ‡{hhùÐG„­Y¯Yéë#ØO_'#-¾cûò9N¶ƘTV°XŒ²²ìó”ÜÑ<ŒX8Ó-‡ÏF^ˆLxvþ\C¡Pé©¡††š‹—î Eô0âµbîË—oY;ì´ô|Ö~ˆN§?xðÒÙeW_¡â}¬ˆˆ ø‘°/Û±ìh£Ñhþg¶Ñh´ó_‘6r5b-Ì›7¥¸¸ú⥨‚‚ÊP–cœüü¼£þd…By{Í{ø( ? ÅûWÏp°ذ~1OÿR¹Y28–ÛEÎÓÚÞ¾-kmíRPFÜY£C£¹°X ã9…¿ÚX`ÍÚ£¯sJvíô\ýÛB¸µ2}ê}wñ&Éç#–ºís˜nùäÑwÛôÊáßËìæ¹¸¸VxÎA>«ÉdÊãÇé*•zäèµ–D†_¾â`kkìAXXD¢Þ—×¼<ç>‹ÏDÞÑ1Ï!.ŒÃt÷Ùéùðu?¡¯8P(”¸¸™LA|2ð‰W¯ ’’^³ÉÅ­¾/݃Wµ‘@êë[áÖÀ@sÂ¥´´O±—–~(+û€ 0bR!ˆ5 ŸXîáô*³¾¦Óé™Y…iÖÓS74ÔôZùç"çi Áމ‰¶‚‚Tqq5|›––?k¦¼gŠ1LŒ×¬afd¼ëï'Î;ÐÜÒA§Óëë[33 ™²Â˜€˜˜¼²^RòF£1Õ݈…SPXéá>{ë·“'63ŽlÐhô²¥³âbýåd%=<^ˆ„EÁÉÉv±«Ã¦Í§ëë[™6ˆQ©Ôðˆg—]øî¾{‘'¶nqC¶.S(ƒ/EeE“½À°æŽáú/?ÂÂ$¥££»³³PW×rãæ£ÑB“”à»sËïŒÿ]ØdâØ’ñ©lÙÊÕµPVV³sÇòÍ›–:¹æ"ôöÀS,€ÁÁ¡sçÃÙ”Øaßu=¡W0:Ö×·"ߦãjãL1²ÈÙ¾¸¸ééÓÒómŒ`±Ÿu®ë7ž0g­£C£ÑnËf½Ê,€oÛÛñ==ýÓ-XýÞÆ ¿Ÿpý棭[–¡ÑèÖÖ.:ÑéPXxÓ³ßK¼ûúÇOÜðZù§®ŽZ\¬¿³³ýx?˜8ü’ }}}Çá=4¬™7vïvv¦¦•—×â»z“’s\MËÈx·ÖçXnnéöm||<×o<ºûƒA›kËÊJ\»ñ——…BiéêªõöÜ‹N¦RiIɯ-Ìõ(”¡£Ç®U ëè¨ö -.ù@$’­¬&NŸfþèqFm]sOÏ@|BÖëœâú†6 s=N¨¡¡MHˆ_IIPUUòÔ­‚‚J‰¢««/‹^ˆ|ûö=ãy9&$$p®.Ó ®«kàûø±):&ÅÅe: …²¶6@£¹fΰ:ã—H$WVÖUW7Ìž=)3³ðRÐ½ŠŠ:A~.0¼¬¬FP‹ å6,ÿ]ßAtCà ŒMœ¨ÑÐПE"R‚/Ç,vu˜;grVVáÅ {åµ¢¢ÂÈžsœˆàÐÐðœÏ Æ£Ega¡?s†Õ©Ó·ÉäÁ¼ü÷ÏSrƒ/íàó=’––ßÛ;`h yûÎÓÇÓ;»zôtÕ>J»?¥£³g‚¦RZz~DdBKK§ÁDM]]µ¸‡©D"¹®®…‡›»¤ôÃÀÑÔTÇÿìÝüü *•ª¯§~ÆÿNbRvkkWww?<Ÿ!!Ž }0ÇiÒÃGiŠGŽ^+(¨äåå–——­eeÄíì×øŸ½p.üêµ8l;ÉéP(”––òbW"‘ì{8äÇF dŒ5gŽmkk—@˜ˆ° ™LIHÌþXÓ´Üc6ü¦ºyëñ±ã7ôtÕüû˜›é1í·hnîôZ髦&?â!ìw m°°˜#G¯¥¼xÓßOœlkûàEdTRSS»Š²\AAÅ­ÛOêZä¥54I$Êë×Å%%–.ÉÇÇ“’’»e›¿»Û,¦©Xbß½«àãã±´œx/:ùÆÍG¦&:ì“™™ÐØØ¦®¦0gŽ-«\54´V t:diíuñÒ=ÿ³wb¼””À!ÓÔÙÙÅ\\\Ó§YZ[;Wþæ7Þ”Ñ6Ûc±ÏåN‘QIññ™8œPWWï£Çiúú4ÚÑÑ0®6|9&æ~J}}+‰DQQ‘eT9 .ŽÓš p.ŒN§Ç=L¥Ó¡ûãââ‚뢧§ßØX.Xm-åq©‡®…ŠM!Ìši•TW×ÒØØpv‡ººbXxËá§äŸ0DK"QˆD2| ‡=µ·ã¥¥Å¥R©ííÝrr’c‘Z"‘<44,**ÜØØ&,,(,,€B¡òóË£cžŸ:¹e¼Éf¥»»¯¨¨ZFF|Â%ÖyK<¾—‡‡^ïÿ¨Tj[^NN’Í—øÓ§¯ôôÔØèÿbM‹Aöœ½½t:]LL„N§C4–™ÛŽŽî‚‚JKK}N苞!rvÙtq¼¼A=Þ«|7ø,†gXÉÉ)yúì“"B*•ZQQ‡Ç÷k1æ7(8Z^NŠQ++t:=2*ÉÃ}6ë_¡Wä䔌¦Âèëèï' Ñhd ^VV¡¬¬„šÚÒ×6¹´·ã7n>u÷¶/N¯¬¬Ÿ¿p{îëÛ°&€u>Ƕmu¯ÁF‰RTT…Fsh²žWgA--’’¢l”d´·ãÓ3Þ-Y(%%6k–õ=Óh´¶6<| …BII‰!û›FÄÊj"ëAd 3âpÙ†ÄÄìI6Sº@¥R§9øÜ¼îÛÔÔËü^0}u•”~°¶6ø¾Q0ÂF®iiéäáæ†;c...MME :tttssc¿Â(3??/›¬«³…BNkkךuGŸ>>ÿ .uÕÊqèÙû»‹ <<Ürr’ðõØU ]¼Q(Ô™±¹àðßäçRvûƒ8x`µß‘«§Nnù·¯Tii)¿L}{áb”Û²Yÿï´|0ÌÕ~G®ÉËK·µuM˜3ÇöŸ‰‚ ëeB@£Ñ†“²{zú÷ìöúq±·´tš™êþ òil¬½d±ƒïáiiñžžþîîþS'6KHà†‡©ŸõßþÿNà× )‰SS• 53Õùj|8üKù'&íZZ:ÉäÁØ‚¿ ååµ¢¢BãÒÈá_ gÒþ—ã?1š “f8pø ¾b®ž?ÿÿIB8pàÀÂÓÍ@NNIeeÝ7o§Óéð5•ʱõ32iA“m·o!+»¨¿ÿoz¡ÓÒò &j°Ñ§Á"‘¼ÂûÏ£GÖ3j5™8Qc,§´GF£Ñ\ȃÁxyνyûI{;~´GÆh­üûÂËËSTžWfJ‹AôŸÀù ‹H¨®n€]nß:<Þ±2‡BBcwì €oKJ>ì?|ûæaÆ3Ð+<çXZè òYüæ­Çì§å=—Ï9rìÚØÓ°ióéɶƌZê„„ΜÚ:®Œ ü‚ÁJYÙÇ5k"j}Ù—dgg›û/_¾ß¡!þ3üðÑ<…2˜‘QÐÓÛocm€h­éèèÎÊ*Â`ÐS§šÂS¦ÙÙEx|ßÌ™V••õí66¢¢Â=güïäç—Vb0h}}úúÖªªz%% \yy@ÊÎ.îéíŸá` ëê‚éììÉÈxÇËË3i’!'”žžÿûîÀM—V*(HKHàaáñ[6/ƒý÷öVrscMMu^¿.¶°Ðççç%‘(4m´yÝØ/ÚÚº\MgrwY4 ¶8S_ßšû¦TLTØÞÞ F¿_ÓÐЦ¯¯((¨œ8Qƒé¸6#"‰‹ÕþÉ”ŒŒ‚¾~Â$CVM õõ­ÃÃT&##!""X]Ý€B¡DD;;{ØDWUUŸÿ®\NVÒÖÖF  *‡‡©S§šfdðššêpqq•—×Ö×·ÚÙ™Â=euuCMMó„ J°&¾Ñª€ }ýA>qq@GGwiéG!!~ss=ƼzU@£ÑíìL+œ mEEUšCCï2 æÍ¤]‘@ …^}ð:§Ä{żµkÁŽç·[[0) D¡PK;pq¡P(TpÐÞ¸¸Ô¥n{§O³Xµr>ßQDD±XLWW/,9죡¡-*:9ûÕ &w{{³‚ÂJäö_$€¡‘VTÔuvöØØòóó¶¶våç—›™éÀgí¾Q0Þ¾-»-''yôÈzX÷ÜKRRRôjèЫ‚¯Äx¯˜Çh¦àG曚ÚgÏÙ"$Äï¼Ð~ãæS/^¼$&fö up°01ÑÞºÍ6 S[ײÀyÇ­ÛO†‡©jjò&fÊ @’•• Ñh]]½ÝÝý€þ~â©3·Ï„=OÉ]·þØë×Å}}G§Í¶¶F†œænýø± ŽúåË·Þ«|-,ô¬¬ôm§üÖÕÕK¥ÒÄÄ„H]]½ˆ‘¨7oËífÊàƒ¸Ô‡.ß¼õøÖí§ç·|Ö_æþÇhÌË+WV–e 07×C´ÔÝ‹N>~âÆüySxyy–,Û APWWïæ­§ÏFW[Zê»,Þýî]kàUW7^ˆ 9 (È_[Ûì½ÒWKKÙq–õµëÃ#˜ü··ã=<¬ßxÎÝí;O×o<ÑÑÑÍ&º'o>OÉuuqä÷\q¨¯044œ˜½yëéë7ih(”WÔyyÿy7ìœG‡™ëá1Swwÿ¶g_¼| ­ X!‘(]]½õõ­qq©II¯S’/ÃêùˆDrÐåèÀ ‘8›¶œ½§®®PßÐêæñiu9:æ¹ïáÍ#G¯_ŽÑÔPª­mFïéé?rôÚÚuÇLMt¢£N2¾îóòË5FR™°cûrX—‹Ëôؘ3êŠÞ+}ÏøßÑ"‹†ºÂ‹—oàë/ Æ{£ùWî}{WÂ×ÿ.ÁŸéݰøáaª²²¬‰™G||æÇM††šV6ÞÝàk‚ ôô|å’’_Ÿ?·óÄñMˆ~Ù±”¤  ÿŽíËÃïmiít]²;:æ9l¹ŠàGwóÛwÌœaemmÀ͵±6 HÞ«|ýû ÈËKmÚ¸ÔÓëAî³%%EEE…MMuttT¹¹±¥¥UUåÍÍôù,§L1Lœ¨1}šEyEݲ¥³R’/[YM¤R©ðxN[[ÅnŠIHh,`ppÈÓëà?~ST”˜lkŒFsMŸn!..b0QÃÁÁÖú A‰DA:i ·e³23 ½VÌ <¿kë7ÀŸ‡Öú®H’D¢0Y@a¢·w`íºc‡®áåå±µ5 åæ–N™bbb¬M"Qœœl¥¤ÄÌLu^¦¾e|*îaê•ûç#^eÄÜ;éµb.`ãæSnËUTä„…ÿØ·jÏÞ MM3Ama¡ìÈX­7@UUî^ä ==õÑ¢ËÉ)‰Žy¾qÃ,cjªcf¦sðÐeqqÜ Ï9åu æÛ)*Ê8Íž™hj¢£¡¡èà`ùæMllÞÒRßÄø“í«`DÚÚñyyï³²‹"¢µ´”-,ô`wUUyÇY6ð5œ€ŠÊºEÎöŠŠ2³'%$dÁùgh¤Œ×äÏI—`$&foÞzæÉ£sººjlJ²©©ƒ©û¼yS ç1‚Á`Üݦ[,\´³³³g÷ï?PE1ÿ ~`7B¡ø˜zkî¡¡a‚à×:ü¹h™æâuQ­ªª^XX^ÿc´WPPáµÒ7.Ö_]]¡§g ¹¹ƒB„ׇó_Ldd¼›2Å„‡JežÜù‘Y0ßîýA™™…ðdÀkÅ\ÏåNAÁÑËÝ´µUˆD2 …rws„¿–{8!ϲÉ,+h4‹úkØÐÐ0«vn µiãÒ —¢P(ÔÌVŒ±F×ÅßÄ~öü·iöºÖG¬öšÃ±XŒ²²ìó”\¤›gbÄçÍ›RPPyñRTSSGèçsb(*=54æ~Êâ¥{f;Úx{ÍcÚkÅ\Ï}}&3¯iéùÆÆÌF½ˆDòÕkqiéù^žs,°cü‹@ QÛ«¶¶Š¥…þÃGiˆí`{{3{{³Ì¬Bƒ‰šŽŽ6ùùåÿFÁ`òÏ>©cŒÙ³'½x~9à\8‰DÙ¾ÍÕ>––2\’'þÍdKOOÙûÖn¾¹¹#à\xggÏ¥ {¾Å6þåüØIû峟§äÂ×éÉ“ m©ââjØ1--ÖL+Ø^5ý5´F®„…H$  ¸¸Þ1ú ,<ÁÆÚ|47wÀ¶DUUå,Ìõ¨KJ>”–~ø™x_^@¡Pââ"d2 íïaÀ«WII¯GË ¼¼Ô¥‹»×¬;ʸ”ÛØØNÿüc` 9a‚RZZ>üWi釲²L¹`Œ‚X“h4ÚmÙ¬W™ðm{;¾§§ßaºkšWxÎÉÎ.JMËcÔN:bt‹œí‹‹«‘zZzþ Ϲ,ž!Æ_Ƙ è“ûˆU@£Ñ˜†ø‡),ª””|`òÌš˜²²š;–oÞ´ý~ù: IDATìÔÉ-Œ¶AÑhô²¥³âbýåd%=<^ˆ„eÁÉÉv±«Ã¦Í§ëë[™ ¥÷õŽŸ¸áµòO]µ¸Xgg{¦¯††6…ÏÜØ ×­¾/݃·ž y©¯o…»ÿFÁÌ0^3„9Áøë¹ ¿ñ[çî3ùùåL%yû¦ïÅKQpF wY4Ñ¥¦¦i㦓¾‡C[µàÎm?NÏ Ú××wÞCCÁšyc÷>y²qrrNAaEwwÿ“§‹MäŸ9ÃêÔéÛdò`^þûç)¹Á—ö ðùIKËïí04мqóñ“§½½ººjÚÚÊÏSrÉäÁú†VGG›””ÜÐØÊÊ:‰bcm¸qó'”“[¢«£úðqššš¼­­ñ¬™Öç#RyE]IIõüyv(JP€?ê^@ÒÖRÏõ64´ ñ+)ɪªêOžºUPPI"QtuÕà™€À ‘oß¾g<ÌĦ®ŽêŽ]çèt:.(¨L~žãê2]ZZL]]æš9ÃêŒÿ]"‘\YYW]Ý0{ö¤°ðøÈ¨¤¦¦ve¹‚‚Š[·ŸÔ7´*ÈK ýφ快Àãû ˆnh81"{{³È¨¤ºº–ÆÆö à˜€³;ÔÕ³² /Ý+¯¨F)ÚÛñSíÌ&LP‚-:KK}­ ÊçÂètzÜÃT::°ÿ·¦¦Ž£Ç®U ëé©ù-)ùÐÛ;`d4áè±ëoÞ”$33ÝGÓ#"ZZ: &jjj*±VI˜œœäÿ;‰IÙ­­]ÝÝý“'$Äq!¡æ8Mzø( ‹Å\ ºWYU¯ /ÍÏÏ‹$@GGå°_hqÉ"‘le5‘N‡,­½.^ºçöN샗’8d€B¡´´”»:‰dßÃ!>4h cÇ9sl[[»üÂD„ÉdJBböÇš¦å³á޼³³çä©[wî>[ìê°k§§ººÂˆ»µÏصӓ——{,‚!!su™vàPp]]‹ ßÇMÑ1)..ÓQ(”µµÁ¿N0¸¸¸éí;O?NïìêÑÓU{ø(íþý”ŽÎž šJiéùìCYYöÈÑkùùT*uª)’ !!þ–S¦‡…Ç_»'--·J¸$]MÛ0¸±±Ÿ§ªªá~ì‹–ÈÉ÷ïkþØôömÙ®ž+VÌe:|Áa|\{ Ö®ý'‚Ã÷䟰PG"QˆD2SÛÃã{±X “ÉíÑèììb³‹ª­­KXXŸŸwx˜Ê¸ÔŠÇ÷òðp3NòSûû Èæ€üüòè˜ç§>/m~554´UW7hi)+(H³v¬)ù:H$ÊÀ‘q,ËJPpôz×1Z5… ÞœõÕÊ`F«6tttTZZê#–ìÙÐގ߸ùÔÝÛ~||¼t:½²²~þÂí¹¯ovL+'§äé³WLZÒ¨TjEEßgl¬…ÈA»÷º-sd?þkllÛ»ïRxØÑ±d‘îî¾¢¢jñ ”X•Öqƒ•bHèkCFw<¾·¨¨Z^^RSS ÉEkk×¹óáÛ¶ºsÌS}8ê~9þ+†hÙ°ë÷óZ3§?9~G®LÔ´²ÒOKÏ_¶ôW3H_PPá6,ìîøŠJ¥ÚO÷‰‹õ‡O±ÿüé{eÙÒYÿFCm¿¶`pøÎpºù_޲ÛÍÁ«ýŽ\=urËG9?-ÆFZ¥e[Z;}Ö¹ü¿Óòý16Ö^²ØÁ÷pˆ´´xOOwwÿ©›ÿ±>>99GQQæßØÇƒ_]08pàÀÎhZZ:ÉäAöG¤8ü—IMÍû¡fu8pøYàŒæ98£yà¬êq`§çÀÿ”÷458pàÀ œnž8pøeù×tómm]ÉÉ9ß%(‚:;{èt:|M¥²3?Ê _W’u°=’¯ƒ@ !ʈ8u÷-|{IBÍê|9– _•JmoÇs Ã÷âg\›ß¶Ý?ê^rÖ«Èž¸¡¡áÃ~WÏìøÆÛº¢¡¡   ÝÙÙ#++A¡ IK‰Í›7e\áÄÅ¥Æ>xQQY7ÃÁJ\\¤¿ŸØßOpuq°µ5í‘«×â΄ý±o%¢P쟡½|9æÀþÕ£YNOÏ?pè²®ŽjÈgõ±cá[JR[[åø‰²²¬&SÙAÐõrsKŒ&pqquw÷-vu8ìwu¼Ù»ºz/D¦¦å‰‰ ÛN2¢Ó¡îî>Nh󦥣ªlllÛ¾3 ªª¡¸0j\q};aáñòrRlvlÝæ/úoå‹|¯’äå½gR8zýºxÃúÅã ›[ZT\…Xþj¾(ö?'ƒƒCì’——ÔÖR‰{˜†Xãee´z¿z-.à\ø¾½Þÿð{†ÃÏÌÏØÎ쌺—ÌxÀ÷pÈÆ ‹yyy¾%Øìì"O¯CÏ“‚ÔÔ>5Œ’’6¶+ïÞ>2Þ œí%$pSì×d¤]ƒõçwuõZOò>x`õh­kÍjç¤ä׌ºÇÿšš:îǾغÅm452vv¦K—ÌÈÉ){˜ß^’[·¸mÝæ5ôÀMƒC´ÌmŸ¼¼ThÈ~ø:¾zÍ‘²÷Çžl Ü¿õÓgøhk© vM/DNšü[væÕÔ(*ÊøZëè´y¼q};ÏŸçê訲éæÏŸÛ‘0öó2ß±$á {v{39>y’1¾ÝHÞ¿LaQå³øÌoïæ¿(ö07o=^é=ÿãúŽ;~CRRtÇöå€í;JK?ŽÖÍVïkV;¿xñæŸÏpø™ù'íQ(¬Of`€XZöQ__ƒÍ#_„H$¯ðþóè‘õHϘ8Qcã†%_ Ýb4Ÿlêýÿ%«~Z~øh¾¯]$##®¦¦ðèq𑡬aûÇƜÜU933]øC§Ó‹‹«ñø¾I“þ¦áòA\ªýÔ¿fÚÚº²²ŠxyyfͲB4àâñ½8œ«2Q˜Ø/ÚÚº\MgrwY4­½½¹-(¨(¯¨ÓÑV —egáñ}3gZUVÖ76¶ÛذZÃD HbbŸþ%“)}ý„I6†¬SÓååµÜÜØÁÁ!--e^SÓÌÅ…’——ª¯omhhÓ×WTNœ¨¡¢"?APNNIm]ËD} ØT×À±  rx˜:uªiFF€¯©©Wyym}}«)<ÍðömYGGÏ”)ÆðŒôˆE7t:=..5"*qú4‹ë×òññŽ¥$§N5SWW8w>¢¯°eó2&ì Lº—d÷Y«yGG7“!FN¾½fµ3“ÖUÁÙŽ6Èmoï@FÆ;‚ìíÍ„…ËçÕ«ngg2Z– 2@ìsåVUÕç¿+—“•´µ5b’(‰ÒÐІÅb ÒÐPìîîÃãûh4º¼¼$›èXåáýû¸®!*)ù`n®'))J ²²Š¥a«¬Ý¥¥…„øÍÍõUUÕç¿«PS•·²š8ZY1dŠzõÁëœïóñ1û’D¡PÁA{ãâR—ºí>ÍbÕÊùp¥È³g™sYºóöv¼ˆˆ ÜÓ47wTVÖ ðYZêwtt—•Õ`±[[£Ñª†L¦äå•“H”Y³¬‰Drcc;ü1­®®€”³¶¶ « W75µ[Zêww÷éëk0‰=@ÊÎ.îéíŸá` ÷ý••u[¶ùãD +q8!¸¡Q©Ôôôw]ø^k+D£>ÝYYE zêTS!!ŽŽî¾>@P_VV¢©©BÂ`Ð**rLY_ßZUU¯¤$#!+/¯³±1`ÒÇU^^Û×G¨©m*,¬$ÉÝÝýººjÈœ<Ó«‰•ÚÚæŠŠ: ½Ñê‹Ã–;š¯ªªwvÙ¥©©”ýºØiî–éÓ,`£dgÂÎF,˜oG¥ÒæÎßÀã{—,ÛÛÜÜ©¯¯~íúÃîî~$ÌÌBc#-ä6+«pï¾K NåâBÙO÷Aìh›zœ -%yyåÊʲ¬Ú¹ÍÍõWÕögsß”.[:óyJnÀ¹0@m]Ëç·n?¦ª©É›˜y0Ùÿ†¡R©/^¼ÉxUtq ¶¶Ù{¥¯––²ã,ëk׆G$0ù¯¨¨³°ZzõQ©´Í[O_¸588ÔÕÕ»yëéó‘ÅÅÕ––ú.‹w¿{Wöòþ“Bru™þ¾¼f×ïç!NHÌÞ¼õôõ44Ê+ê¼¼ÿ¼ö ΣÃÌõð„^ccûçp𤋮©i’–›ùömÙˆ‰Áã{këZ44Yÿòýs|QVöÑÃó€¥¥¾™™®ËâÝ]]½pùlÚr:ôjœººB}C«›ÇÈ›ººz÷ì½à³ÖÅÁÁpâäÍç)¹®.‚‚üž+Á/qÆ’ILÊÖÐZXXX è阿pGRòk6Ñ(p]_ Š..þ`a¡ïè´ùÁƒ—))oÌÍu7m9˜˜ ÉA—£/DÂáœñ¿“žñn‘³ýó”Üí;ÎŽ˜˜žžþ#G¯­]wÌÔD':êäœ9¶ðØ},%ÉÅÅåâ2=6挆º¢÷Jß3þw­/2òøIÆ|–­‘‰î³áë’ÀÝ3gïÀy¹qó‘¯_`´²¢Ri)/r[ã—ó³øL ­…%%}}„Ùs¶¼L};¢ ··ã׬;|ù~ee½•÷ÐÐ0£Ø÷õ6ÛÚLpš»õãÇ&‘H‘•‘  uuõ àοMXX`þ¼)ì¿ôêUk–³û…:8X˜˜hoÝæ_TT50@:vüÆ”©kzzú••õ3×üØÄ*ýýÄSgnŸ {ž’»ný±×¯‹Ykmhh¸««ö|àPpjÚ'55¬¯&F Ú¶Ýÿñ“ íôôwoÞ–ŽX_þ³üØnþJHì$C Å5«ssKyx¸WxÎ-.®>~âÆ™Ó[…„de%ÌLuÛwX˜ëÍ™c+--¾qà æ¯!TSs;£‘o:B£Ñ³gONùlm6:ê䪕£.³‘HÆ0YIMÍ{úì•Ï:W..®Û=NžºE¥R=ÜgKJŠŠŠ ›šêèè¨rscKKÿ¶„s%ä~à…¨.|oÞ›»FFZ€›O¹-sTQ‘ücߪ={/45µ3>åìl¿ÞÇ•LÄb1üü¼³fZ_¼°[LLdÊcm‰âäd+%%ffªó2õ-à|`„˜˜°½½77vé’™UÕõqq©â⸞sÊ+êÌ·ST”qš=)<2ÑÔDGCCÑÁÁòÍ›²þ~"`Ñ¢iÒÒb싎 eðò•ûîË÷ ðÇÜ;µÂs.Ó&&2y}I"HJŠñ[éâž´ô|wý/_¾e\JìîUTä’.1|Ì1ÅÀŒ2O³aÓIw7Giiqyy)û©f×®?„˧¢²n‘³½¢¢ÌlÇI YŒä¾)½rÿRн¨{IÛ·¹_Þ‡B¡rrJ¢cžoܰ‹Å˜šê˜™é®[·¸±‰nDy€ëº¿Ÿ8gŽ­„ÎÊR?*:yá©bb"“m’’_TUågý5]ÁÏÏËÍåååÙ¹cyà…H"‘ÌZííøý‚vì ˜íh~ÌÎΔq÷…2ôÅ’„A¡P³fYß‹:icm°aãÉÃ~¡HeÁttt °Î¿yS† (µµUô«ªÊ/rþd7v´²XîáûÁá„vîXne©Oý\Î7,Þ°~ñˆ244œ’òæôg“wX,FZZ<5-ÏsùFo>ë\ô&.9q|@VU‘CÞÅ( 1®ÊÇÇO$$f3šÖÖÔPzŸ¹hÑ4 %Š‚7éðññ`¥ëX,ƒA“ÉA8LöEÇÈÑc×sß”FGmy.I‚˜vÏõ÷š›;Yµ¾‹ˆîÝã—÷~‘ëïaÇÃ( ‹ÅÐh44ÍÅÅ5c†ÕˆÑäå¥$%p ŸJ>4FÝKJLzÝÜÜñû®¿­Z•U4ÃÁ®>*•&.þ)ãŒåÃTwzºj>ë\™âJJ~͸uYSC)(8æBàïLÞ6oZz>0Âm™ã£Ç鋜푱FÇFþ^×¼ bÆ‹,$1òÆ Kž<É8uúl_q`€ÛJF€ Èeñîɶơ!FÜa.'')%)ÚÔÜÎú×›7¥ú¬î“&™™éîØàéuèÙ“@Ä="2ÑÝÍ‘Ésaa¥¡áÆ4ssÿ• F÷Ѫ†I¨Öû¸]Žquuxö,sþ<;0º £P@OO €¬‘!A‰‹ã.œß‹Åbª?4HI޼6ô25OIQ!"‘¬¬$Ëä!?¿œJ¥!Æ-55KJ?45µ+*ʸ,šzõÁŸ‡Ö&%¿Þ´qÉààÐh©§«`ÝÐÀ ’þÑ^MˆÏ'O_1Îwò|›EA¿?¶›w˜nñêUÁùÀˆ¶6|³ pç- ÀÇôÂE¡P¼¼<£m&HÈí­ÛO¢î%ÅÜ;%$$s?@¡ ~q×É‚ùvìÊÌ,œ2ÅvñZ1×s¹SPpôrw'mmNHZZ L €aŸÝX@£¹°X ãNס¡aÖb Ò³fY_¿ñH@€oÍjgÆ¿X£ãáÁ2N°3È´¼ÇÞúÎXŠîè‘ ÙÙE7RU•Û¶ÕÕt÷‚ùvûþ¸”™Y›GHKË×ÓSg4/ï}à…Hiiñœì[LJ…ùùyGÛKÁ …òöš÷ðQÚæMKáwŸ††âý«i4úƒ¸—Ö/¦Óéüü¼3¬,-™;ªñš#âááf)ê^š‹œ§íØðömYkk—‚‚4›èØËc]QÌÖ¬=*))zôÈz4½Îç`©> •žs?eñÒ=³m¼½æ1  …òZ1÷ᣴM—2u¨YÙE¬Ý<‘H¾z-.-=ßËsî‚Û<Ÿ›[ºu‹“ÿ°ð„m[™˜Æ c©šÅ®;vž++ûXSÛ¼`ÁTÀV†F6æ[PPáµÒ7.Ö_]]¡§g ¹¹ƒBd,™ŒŒwS¦˜àp‚Œ Ÿ X6\XNàpÖû¸.\´së7>>4B¡Fȯ°8ÌæÕÃËÃ=>Ó$þcüØIû‚ÂJ÷Ù[·¸<±ÙÌLvœ;gr[[Wcc|ûbhhØÃ}vzF>ìÒßOèë#Ðh4øV]M¡¥¥ óâ¥{Þ^ó„„ jnî¤Ó¡°ðÀ»O++ëFK‰¼¼Ô¥‹»×¬;Ê¸ÐØØØNÿÜh9ÛTö÷Zˆ‹K…›1ýÕ‚Û|ÍÚºÐh´Û²Y¯2?-ìµ·ã{zú¦[ èoþ7o\z)(‹Å0¼ †ø¿Ë=œ^eÂ×t:=3«ÐÃÝ‘Å3ÄøË”Tøv´¢û»w`cc~l±«Ãî=»~?ßÜÜÁ˜A99É K{Öúcœ4®ªnPS“gôùêUÁ2·}¥ ØéfSßÛ;Ïî‡Îm pØw]ggOèÕŒŽõõ­pÝqqq­ðœƒì“'“)§X> e2BÝ9ÛW#=}Zz>|B’©H±XŒÏ:×õO˜–êÑ¢c+ó?bRçþ~Âõ›¶nY†F£[[»èô÷êû+ºeKgÅÅúËÉJzx¼Ét®Ýï°Oggï›³í¦˜2ºôõŽŸ¸áµòO]µ¸Xgg{Æ^¹¸¸ÚÀ@“éCax˜ÚÞŽgüè "ßôeïkh4úòû×-ïJïy;?§5Av]†Y«øSPaá 6Öð$MssNŒJ¢Ñh‚pá¼/¯xyÎ}Ÿ‰óüm©ââjø6--ÖL+xߨ¹¹žœœäÊßà cÈaÌâ™í« x¸ÏNÏx‡´ý¦æäåÉíëë;ï¡¡`ͼ±{±³_ãönÀ¹ð«×â²í$#aa s=¿£×¸±ØŒWïxyy &jNžlôèqFm]sOÏ@|BÖëœâú†6 s=NƒFç忟2ùÓ(œF£EÇ<lj%&eÛN2|ò4ÃØXK__cõÚ#RRb&£lChêê¨îØuŽN§cÐè‚‚Êäç9®.Ó¥¥ÅÔÕDE… '?q@ +»H'¤­­ê{8$--¿·wÀÐ@óÆÍÇOžfôöèêªee] ½_W×ÚÙÙƒTVþÛüž½½YdTR]]Kcc{PpLÀÙêꊑ‰‘ mêj ð&^%%™è˜ç~‡×Ã[âaáñ‘QIMMí*Êr·n?©ohU—v^hßÐПE"R‚/Ç,vu˜;grCCÛÑc×‹Šª‡õôÔ|‡–”|èí02špôØõ7oÊ’™™nÀ¹ð”oúû‰“m°X kÑõõ.Ý+¯¨†AÀÈÈH,\0UYYæÔéÛÉÏs´µUi|ƒ‰šº:ª;?àâBåæ–&&e¯Z¹^ˆ (99gï©Tšßa§Ù“ 2’]ÌÅÅ5}š µµsåo~óçMm³=‹ñ\‰Ã uuõ>zœ¦¯¯A£mvv¦¦•—×â»z“’sàmÿHùèè¨ö -.ù@$’54#“²ÛÚð½½6ÖÛð,.ŽÓš p.ŒN§Ç=L¥Ó¡ûkié|œ¦¦&?i’‘¬¬Äµyy¹Q(”‘‘–®®ZoïÀ½èd*•–”üÚÂ\IÑhôÌV§Nß&“óòß?OÉ ¾´Y7áæÆ¶µâÝÝ?-d° ä«W!¡±••u$Åæsî¹výáýû)­m]ÚZÊ©iyá mêj ††X_Mpáz77×#ɼ<}–YPPQPX9AS 9§3>®=k×~̓~V~ !Z‚œ]v]Ü#//kEõ^å»Ág1¼‚ ÖÖ®ÿµwÞQ]Ÿƒ£ÃÑD¤7éRD¢ "jT° bIìblùŒ…Ø{/€Š©vT Å‚H¤Iဣ_ß»ýþظ¹ÜqKŒd~íÍÍNy3»o§½§¢¢È;–¥Ré,[Q‘T[ÛH"É’H2ÅbϘµ)>î ËåÖ×7©© !‰l62 CW(ŠÖÔ4–•Õëhjªò½Âz,Õ§A£1ºº¨Â¬[€†Bý×Ìíg‚‚46RÔÕU:Í˧‰®ºº!0(jë–%¼‘qIš™éóŽÔ“’^¾«X¶tfÚgÅÊýë×ͨw‘—W***bii(¸RC£1¨TºàBÃ@AQôÇfEÁ8d2%õÙ›9³Ýû™Ó¾OIDATfŸý¡?0™, ¥CMm@èó½xñ6îaÚ¾½«ùÊ“—W*&F´´4Ä«‰¢èæßNûÌ›lc#ôsAŸ~Þs=t_øÏK÷œ=³Y°Ñ¹\nm-yØ0e‡ÛÞÞ¥¬,?Pkt:ƒ÷\ß§õáÆÆIVZZ’÷EÉdŠªª2þ@„LnUWWéÅp…Ò.&F$‘þö•ƒ¢(“Éâë“_ªC‚~¼š¡P:TU•Éd ‘(ÚËéâ>€Žh_QÍ#âä¼4ùéyüݸéÄx×Q‚gmûäú8}ͱc…š’ý¾˜åýëÉã›JJªµ´TªçMM­{÷]:{fó·.È€ihhY¶b_ÜýSçÎÇþ´dú'Ûçù~yø0½½£ ?5‡ÑÚÚ±cçùÀ³¿}«RA¾PÍ:¾â<"‘xñBÀž½—44T˜LvccËÈ‘FžžNŸ”ßÏ-[ÏššêõnÖê{aô(‹ÄG™*Cÿ›:žÍF~>~l÷.ȧ ¢¢ ¯§q!ä–­éPÇîÜMeÊØ~z(€ü«£ùAÇw£æ!òÕj~Ðñot]@ ä‹Õ<@ ƒ¨æ?‹™ø•omí`2ÿ´.ÂgD 2 >A’4;‹üi°Ù…ÒŽ-ŠÁ¶û¾ˆ$ƒÏÅp¹\¾ÀÇ_ôî1|uG´_„‹—îœ8¾uËâ…~SÃo&{õŸÎص;`h¨M¥Ò„3ÎÅöÎÝd¾£Ï}òæMñõqé¹V–F¦¦zt:³µµÃÚÚØw¾‡°3µ©©Ù;Ι™ê]8ß³?·¯Š¢ûö_^èçÉgk§¶¶q楥5ù¹‘ýOös$)--)!!Ÿ>eÊÀއddäÇØÙ™*(È54´¸Ž³;w>68h æµÿœ8öô¬ÎNªÇdG11bkk'‡ÃYµÒ[OOCØ-ëÖ‹Š~œ‘v…×2ÿ?ÀË—yù¥¸»[A.^ºsüDض­K0«‚ýäKI’Éd=ž¿zÕl¾ða/]ü}@IaÉ”às1Û—~¦>»=òù|j~ÙÒ™OŸ¾Â ƒûÎ÷ª¢8ÑÃÿÞ½xÿgHLÌTUUîѳç'C¡´ÿà²ôÀ>ÿ3Æa!]]TG§Ÿ&Œ5ФllL¬¬ %¥÷ìZ‰é*AæÍß–’’}åòÎoqq±;ǽG×±_&“{+ÉiìHaï;-­a»v,ŸÁHÀÆ ¨Tƃ¸gÛ¶þ„…dgÙŽZð,墅Åðo9urSøÍ„ÞÂyn^ÉÃøô^Ôü²¥3=~ÎkÛ¿O¾ $ý} $%%òr"]]ízÓ{"……åË–ïÜ"‚¾$ÙÜÜæ3Ÿ{\A¦Mu ŠîOoß¾ßzu7¯1¸…~žöŸzTLŒÈkôÐÖÖTOO#(8FX|ÀëÎñcÅr¯ûwOöG²W…Êd².„ÜÚ¸éö³OIž Œt+ŒqiÓ†ßLôÏïd¯ŸØÚš¾ù|3ýéö(Š&$f~fFÿ2_WSffæQ(':W57·9:ZIKK64´dgÙÙ™â'§Q}ñâmeÕ‡ÃùlbWVÖWá¬éê¢æä”°Ùȸq¶ii9×ÅņH$VU}@‡ÃQSB"É–•ÕIfèP¥êꆗ¯ ”I®®v¢¢¢ùùeuud{{‹ÖÖN&“…“^½*¨¯o:TQJJ3üÙÞÞõìÙE]]í0;—••õ¢¢¢¸Ë©wï*jj-, P}ûöý¨Qæ**ŠÝÝ´ŒŒ<--U33},Æàp8Âfkj#£g¦]á wuµËÉ-ÁòUÏ“S2bÄð^ÌYwSiâbDÌ7Îxö,§£³{¬£îÁ“76áp8Æ ‘—ÿS†òò²ÍÍm½dWZZý¦H]MÅÉi$¶4ПnPVVSQQod¤ÍHwwÓ23óÛÚ;ÝÝìûó2ÍÊ* ŠVWWÙ·wfP¶OIª¨(^ ¹x;ø|Ìâ…Ó<=z<ö=~ü¨‡®ìÜñ§•簾Va†÷'O…cÉ7©N æÌvÃÐ!’šú¦…Ò>ÆÁón€Ë§¤¤º¶–ìèhÙË4Uw7MI‰„&##H7ÎV°GUŠ‹‹1™,cc‡[QQ/"BÐК—W*,;Á'±¾¾©¸¸JYYÞÀ@3--ÇÈHÇÀ@“Ãá¼xQ;ÖŠ@ ÐéŒ×¯‹h4ƤIc°t[22ò$%%&Mr ûxÉtwÓB.Þ~þâíâ…Óðù€>%¹Ö^VVáú ÇÕÕUÖ¯óéÅ ™L‘——åûFDQ4+«pã_ðñÒÝM›2ʼnNgdg·¶v`£aM“•UØÔÔæìl-''óî]…„„¸ œQåëÃÕÕ ¥¥ÕÚÚÆ Q(*ªrt´,/¯ãíö‚¼~]T^Qg?Ú›#lnn;zìzvvQnn ‘(ŠÏâääW™šèZ ÷â`|ÝÑ|eÕ‡gn¼Ïf#::j6v¾ññéååuVV†Ž‹›šZ,{Ñâ ËÛk»¢Š_ÿw wµ´~ñûžÙؘ¤¦¾y•UÐc,;!1Óÿ—#!ïhV×4øønÉ­>¾Ûü9‚9Ⱥ¿rõ ¥#*úñƒW¦Os–””˜3o fÔzÙŠ}ÁçbKJª³Xì#GC„3s¦«‚‚ÜÑc×……å¾~öövvf^³7·´´2Ÿç´2ÂKÒÒÒ¾vÝ‘À èüü÷£G[Lž²ööí?’’^eæÿË‘Äßã+W˜7›0‰½~ý ¸ !!¾uËìZ° XÖ§NGäç—ÙÛ[xÍÞüæM±`â(Š–•Õœ>r!@VVº²²~ñ’]ÆÆ:“'¹tùnøÍ¾ød2Å×/`ÕšC˜ÛûÐëq«Öljjí%»ƒ‡®>Izéíå&++í·pGGGw?»AkkçúÇŸþ‘èèèžuúzIfú4çmÛÓÒrpù\ }Àf#úú6v¾˜Àù ÑAQ r›ÿ·˜˜¹{Oˆ›Ûh“uëåå•òÅ/.®í°0äâm.EÎÚuGΜd2Y²ëñIìî¦>qðÐÕ˜Ø${{‹#GCOŸ‰½gl¬Ÿ¾= € œ¤§/^ö§•ûŒŒÜ-[gÌ'"Bp°’×±/mm{÷]Z¾b¿­itä!Þ/­>% 5Êüzè¿S~ßq~ý†cÕÕ =ær3"‘Ï4/ 7·ÄÚÚw)û îÙÂÅ;±ºd>Ï›åý§™?a²ª­%ÿ8s#™Ü (*ª´½àò•{(Š"g݆cg£š›[ûpg'õðÑÐã'ž$½\±jÿóçù¼Ý0gÞiiɉî[·ÆÆ&º»ijjC8NKK{kk'mÃÆã/_Ì›;ñIÒË'ĉÁøºjÞw¾‡ŠŠ"‰$cggfh¨-**RUÝàä4RKk˜ŽŽÚóçù€S§o*)‘\]íÄÅÅæÎ™XZV}çN2àêµû¥e5ë~ñQUUž5k¼±±nY(++,ôó,.©š5ÓUKk˜Çä± {{‹}{VcÎúúáÔÔ†,_±ÇïË$%%œœFvuÑ^¾,pww°°Îb±§Ný¡¤è¶¸¸XJjvý‡fAÌÍ °%±Õþ‡æûLVUUÖÐê:ÎîÒ廀º:ò°ay"qv¶±±6éì¤zz: ¢à`oýxÆŒqJJò?8|ôø9mçŽåÇŽ¬&1 …úœhoﬖ5Ƙ2ÅièP%;[Ó?’³xïºs7ùü…ØS§o¦¥çÄDZ´p*`ÍÚÃ>ó&ëꪓH²Û¶þôÛ–3uudÞ»F¶Ø¿w5æÄ §§qÐÜÜ@Xv/^¼Žy²fõ11¢­­©éï;Îõ³ØÛ[àÞÁr41Ñuq¶¹rKP(ŠÆÇ§ÏóÙš“[ra{Àö¥|#`:ƒÙ»$q$$Ä—/›qA8s}¶^½vŸO3©© ©¯oèêª?N9ÒXXR4£÷Áë‘£¡ZšÃF2—’’\½jöþƒ—qù(*’lmMMMõÄÅÅ Êñ[jkÏ_ˆ=w>öü…XÃáÚÏ3®ÊËËvwÓÿ´kÏî•rr2Cý×Ìõ[´ƒoõaæL×U+½ét¦˜QZZrÒÄ1gÏlVR’–]O¢±±®Çä±…åKOWVVpww8tøÚâEÓTTÝݰÉd99^'è\.ª¨('**êá1–Åb'%½”™LÙ´qÓ ÉŽ7Ã÷»¸ØòM¥Ðé}HÇÜÜàbHÀº_|ŽŸ[½æàÎùW¯ §ÃÂð2+++à»håäd–-‰G&«Y³Æ«ªþ9©ãå5aå o&“E$¥¥%ÝÝìÏœþŸœœŒ`1bø„ñ£‹Š«æÍ”ôøœƒÃÞn¢¬ÀápTTZ<ýȱë==Qvæ²²ÒnnöÎÎ6€ää×qÓV®ðÙ¸Á÷Ðákð¤w¾úò6@0ù¨¡¥¤$x¯±qBb¦×¬ñx|ÃáÚãÓgÍÿ .Íšç}*!ÜW@PTÆqRR¸kww{ƒõìÙgg›¶¶NŧO_±Xìä”×óÒb³ÌÍõØÄõïۗΛ¿mé²½ÎÎÖ÷û3™¬ŒŒÞcv?ç­ápí àÌþyŸÝ€¿ç••ΜúõBÈ-11bÙûš¡*=L’'&f®]wôÁ½“øjH’¬«kœõª@Ðj2‘Hœï3ÙmÂè³657·a#f %EylZBDDÄÝÝ¡ÇìþÌÔÆ¤¶®ÿÉ`0OŸ‰Èzý.33ßÛk¡ƒkÿH~­­5 ëHT*]G[ícÝÿ&¼I+Wxóe”]„ |c ¡¡ÖÛ‚÷uud-­a¼ÑV®ð21çàÿînºž®:®J{ÌNØ“H ccì^)I ##ml-FJJ‚NÇÛî/%ýÃÖÒÒ’‡\Ã>G:»¨|…GQÔkö本C.ÛaccmRWO ÏÉ)¶°.x—žžÆéS¿†^s›¸úm^î$77·ÄÊʈï‚Åb77·ñ®Rñº"ä‹,¬ix£-_6ÓÚÖ÷à*•Žy·Ö‡ ‚¹™>@MmÈÇ¿ò:ybSDä£ä”×MMmürÃø#9KNNëBÛînº‚‚\‘!ðÏì´ÇW%ù®1$$ÄxO,Ûû*)!Þÿ Ã=úfY¹Â+è\ ‘(:ÖÑ    G æûLÆâóAde¤ñkeeùÊòûå·n?éõkñ»[ÒÒ’înööÓ JJòÝÝ´U¶OLLtíG[ܽ—‚»~wuµsuµKÏȵa8y²cvv‘°* (;QQ11"ïÎg\ò¼ÿ5sÏF„‰×p=5¥¸@SŠõ¿÷¢æä/Z²ëέcšmm]õõM “¯lcŸ>9wâd8ÆØ°~¾¹¹_"ÆÆ:˜$ùv{´µu¾«TóõõM'N†77·žùÏ k7•Æ;mÓ ‹ü¦.XÐÑÑ©II‰ß6/NM;uûÝ»VHKK*(ÈZZçm5œ5&jEñig,/š¦¦ê¤Ic._¹'##Å;Hí1;aO"øûóÕ§äk¡"£ÅD–““‰‰M0LÞ¥qš›4{îo“/š&XòE §úúý%Iœ”ÔlÁÕh.—{÷nÊõ°‡®ãì°§ÿ+,Œïæá£££Û}ÒêË–þ<#--çÃáüuÖ¿´´šD’QPSUU»P} áå«ï´GÑ¿”5ŠÞkŒ¾SÒÒs±k.—›ž‘‹mõï‘úì ¾N_Wß„¯›b÷âé¢J•––óèÑsaâ¹ve×ÙÀ(Þ¥VE««°¯~áUàÍŽ¿H‚ŸK¢¢¢>ó&¥¥ç`?ÉdJ[[§Û„ÑàïMXèç™™™—œòš×Ÿ^Ù͚隟_†«Š”ÔlütŸÝð´BXx‚ãKlb ¾¾‰ËåFD>âp8|UÑÕU?sú{÷¬º~ãáâ%»²³‹ø$zu×ÙÀÈ‚‚÷¼áaáñ¼cV@EEÝÿC»v‡üüÓ×C÷ºZ¯­%kh¨˜LÖÉSá]ÃSOO'o/·•«𖳺¦|ü-ò›ú0>ÿ7:æIOòùë^!­llL45‡æç—a?SR²'MtÀöòݲvÍÜÀ h11"ï¸Çì„=‰¼O‡°^Í~60jñ¢irr2(ŠÖ×7s¹hXx_:¢¢¢óæNºs똺šŠ¯_Àé34ƒ·‚S¦8Íövó_{˜7°ººoÿ#‚ á7fzýJi툊8¸î^Ïf#d2ESS•Oz÷î§Îøqo‰$Ã`0±â–£(ŠÛÒégÓ¬ZáÍf#˜ßí~öa^±<{ö¦³“йªÿÐÄår««ÒÓsI$L8ùùe¢¢¢³fºæä”tvvc·ß¹“ÜËî ºk×®D ˦õ?ú®ÝRR²ÛÛ»¬, C¯ÇÝ¿ŸÚÜÒfn¦÷^JllRSs›‘¡ö¤Icjjã2hTFð¹˜ÙÞnS=éP©tÌ YÜÃôœœâœÜ#CíŒÌ¼ËWïÕÔ465µJJЉÄ}û/çå•2™lSSÝÝ{Bòß¾§Ré#ÄÅŤ¥%KKkììL±õTQQ‘‰îGÝ Ré%%Uee5c/]¾󤮾IJRÓd7#)”Žî.Zê³7Çk9Øpq±½{7¥¨¨’ÒÒþèñ ¯Yã%$ĵ4‡Ÿïó癜°ðøˆÈGuud]õ¼¼Ò«×îWTÔkj ­¬üp!äVEE½êP%SS½Óg"²²ÞñžòâcÈo¯ñ;‚«ª>ÈÊH•—×EÇ$yyM cÆXöXÞ¬srН…>¨®iÐÔPíê¢;–ý¦˜Bé@Q®φA€««]D䣪ªµµä à˜Ç7hedäž Š**®TT$a3 ââbd2eœ‹‘‘¶`My³³··06Ò9q2ŒËåÞ¹›Ìå¢ÛéO7HI;‘ðáC³åCCCí+Wï)(ȽxùÖÌTïîý}} µ½û.eg#2Îů…œœ´»›½³³uXxü¥KwTU•°íë˜$½fßþ{pm-YZJ¢´´&öÖSw7{|fûÝ»ŠmÛƒ²² Ýä·páTl1•ƒ›´b¹ ¡¡yÉÏ{¦Osîe³ýTO'2™rôØu’œ ƒÁü#9«£ƒª¯§1ÑÝA\\ÌÌL¿½½+*ú1‚p=~>z”ùСJ¼ò¹rõþƒ¸gíí]ffúá7bb“ª«h4†®®ïꃨ¨èDw‡ÃGBétæëìwO’^n‘‘‘Ú»ïRÒÓWmmÖÖ&Ø8X[{XtÌ“=»WáúOXvã]G >‰éé¹AQÅÅUòò²(Š?ööí{iiIIæÐákùoËDDDt´‡íÝw)'§DRR|ÌK‡óDA^.ñQ¦ÓX«qϬ­óß¾¿‘P[Ûh ¯‰7@06Ö™ííF¥Òwí¾ðþ}­¥åp|dïééÔÐÐrìD˜IzI§3«k&OvTT$´2:pð*@AFfž¢‚œ‰Éõg}),_þ%„|kþ-êil¤¨««ðM "‚-“É"QTAAN˜ù6a`se|ëmJ»„„¸°Ù3‹M$ŠÖÖ’UTy4ƒJ¥ó*ƒ¹ó¶mé¿í”ÑÚÚ‘—W6l˜2¾Úÿ*ôÑÕEåÛdÀGPpôª•Þ}ÎÖb (ŠíÚ¾¢?46¶H²ÒÒ’l6ÒO ]]Ô !·ÇX::Zñ†S(íyye*††Úx-ZNž _¿n¾ººJ/iFD&¶·w¯ZÉ¿:Þ;§¨¨²¥¥ÝÊÊHps‚ dr+¶ˆ; d¡PÚÅĈøæsAP Žö_3·Ÿ {—Ë­¯oRSB$ûß|/^¼{˜Æg Aââ* ¥ÃÚÚ˜·šAÁÑêC§Ow?/ÝsöÌfÞGecmÂ×C0[$%%äåekj••åed¤Ô@t:Êó&8Ð>ÜÞÞÅår•”ä¹\.Š¢øƒßÜܦ¨(‡oKDQÛ_üå͇@uƒŽ‹šÿN).®ŠOH߸aÁ·.ÈWaÏÞ‹–# ,RR³çÍô­‹ó àp8Ë–ï üïõý]0ËûדÇ7•”Tki©ò.¸üGhmíØ±ó|àÙßøÂ}„ÝØûùXƒ¨æß¼'&&ºrr2¸ÙµA†õHã¢âÊÛw’çÌvÿÖeù6:|mÝ/>ߣŽŒe‘ø(³»›öÔñ€È¨Ç>óø¿M ËÍÌô Ž‡ü§€£ù/@zz®“ÓÈo] ȆJ¥– îɇ|<|˜>eÊX>þæMñ°aʽ/Óü×£ùATóùTóƒ8i@ È ªy@-PÍC 2hj@ A Tó Z š‡@ dÐ2pC‰ö+¾B1 |yxn@ È÷œ´‡@ dÐÕ<@ ƒ¨æ!´@5@ È ªy@-PÍC 2hù?ÂãÏ÷óIEND®B`‚java-algebra-system-2.7.200/images/jas-py.desktop000066400000000000000000000004671445075545500216100ustar00rootroot00000000000000[Desktop Entry] Type=Application Encoding=UTF-8 Name=JAS.py GenericName=Java Algebra System Comment=jpython shell for JAS Icon=jas.xpm #Exec=jas -py Exec=gnome-terminal --show-menubar -x jas -py #Exec=gnome-terminal --show-menubar -x jas -d -v -py #Terminal=true Categories=Education;Science;Java;Math; # #$Id$ java-algebra-system-2.7.200/images/jas-rb.desktop000066400000000000000000000004651445075545500215610ustar00rootroot00000000000000[Desktop Entry] Type=Application Encoding=UTF-8 Name=JAS.rb GenericName=Java Algebra System Comment=jruby shell for JAS Icon=jas.xpm #Exec=jas -rb Exec=gnome-terminal --show-menubar -x jas -rb #Exec=gnome-terminal --show-menubar -x jas -d -v -rb #Terminal=true Categories=Education;Science;Java;Math; # #$Id$ java-algebra-system-2.7.200/images/jas.png000066400000000000000000000066271445075545500203010ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ ºŸ~š $IDATxÚí›l[×uÇ?÷=ò‘¢~Ø‘mù‡êI(/ŽZ»±cwÞMÜ"[Ûk']t(öG÷ǰí~¡X—®Ø–nm–Ì݆( ]â:AܤÎRlÉÇŽ5ùGd9‘,ÉôY²eIE‰É÷{ÜKñ‰‘Q=ó.øHñ]žó=ßsî9ç>Á­qkÜÿŸ‡¨ÔÂßj6¸°Ù…¸«¬êÔQº ®>ŒûtaÀ‡> :Spôœí‡<àß°< a> ìöa›+ˆ°€F ÄCd„¢ŽàäÁ΃•l¬qõ™ é@w~}ö¾§s>À˜7þ vùðmî ‹ã°úÓ°|Üv',XµË@jhº¦ iòfÏÇ÷l\ϳr)ë…t/\iƒ¾Ãpå$ä,‡—OÁ?¼5@|dþêuØãÁïF"p÷#°ák°ò· T%€F`=°¸ X ,QµŠ ¤ è:€S@¾g‘섎çáäO!5ŒôÀ÷^€Ÿ«›ÝëÀw¡Qƒý.l¾ã~øìÓ°l@=ðE`°U*ëG”|À“Ó÷Rh€.ß@¸ÀÐüðpšÉ!8ò·pìG`»¸=°ç9ø0ˆô˜ëÀßA• ¯yðé-_‡mÏ€©¾ | h’ zy𕲾/õ÷gúéЄE3@‹Ià`ÐC÷ pà÷!;Ž{¾þ¸R.ô¹ð <éÁŸ€Ïÿ´Ðz%ÜnðCà‚;N윌r® žžB-$£ ï€gJ°Üœz̓Ÿ“,ðÓ’1b=ðeqó)¯…ÄKhõïƒÓièGî•à)hþ­¡‰ªÏC¸æSÀ¥o»#àLª0nJÅí CÜ|BaжS½ì k¿”fôŸ¨ù|fþG {6úhå`Ã@ÓŠOAÍŠp;¸à¤ÁNƒ•3]¼ÁwܬTÌÍN_ÐÉ€3ø»üN¢ñQ+›Q†DäËà&Á×µ¬Þ`%¬Sûn¬’.ðq ¢K6ÒzN,ObnV‰‚š¾tËIJíÒŠ©õ[IÔĉ§Z”ßgÁ™$ñ±ÝEk÷ü½t…°ü¹DãŸËuŒ¯·ŸP”†«…E–Kca°& Ô­B&aÎ0ØcàŒÉWKÍR ;Ɇ°,±Få{{lÚwâ§¿ öø´uã—þ"@Ç E¤j–AT·Uc€€Å! j@¬8w‚m­ô>;-÷qÏT­ t2p=¢|?^.pïXq÷ð‹©Cüò@D“qÇìGC¬ªÎA‚`ÌVm! \S¾[º€3VœAØf¤I¬ýEëïƒ9L<ñ¬¤óª'$ ÖX)â§¾!?_ÿ4‰OþˆÄ'ÿµÈ²©™ë Øi„& ­„(RÎö>x Õ þJpª‹å›SÂRû½æ°üLhÓ?ó¬©$(~ô1[~Q |÷z‰µK]Èʽ 'þLçÇpü4çfÛ™ü$LØÐñð`¶:gT«z3X?È‚k1@ŸCv×_†æ$ÞO¡ýM8 ¼ ¼¯úè\/Ü ÛÐÓ÷çÚ©ÍõBÃ6ÑbôÔ€R6À¸ôshû˜Y¼Ÿ@ûkEåßUÍPÿz`ŸËÃб¶Ú],œì€%€^ÇÔáÞ¬]@ìå«áÂ?ÃûßËÁù1œüµ¤üÛÀQ`h®'Có€uÎB[3Ü+γd¼M2A_¨DÓ§þ\€ õkàü3ÐõL‚õ4{KZþ`@yg®‚ÏÖ µÁÑ{`£Ñϲ‰S°ôaЪULÐ>$”*_ ½{ û)HCî)h9&Þ[ÀñbùJ²ƒ—< G7Á–PËœaXòùYÁ  ÔÀð+Ðùgóo ¥ÞÞÚÔvç}TµyÀ²ýðÞóð ҩò $ØÒŒ’¤'\2Cò¨aô8x>üºNI‹¿­”™åç|24‹‘‹B»)N)F@lï*É’(:º& ‘‘M˜ ³ÜLïÿ ¾ Yóá‡~.nºÈ}÷Ý®——„Ã™ÌÆÇGÉç͉ÑÑÑIUVÝø xüñÇC¶mo‡Ã47obrÒÂ4se2 Ä¢E+Y¾|%gÏv뚦 Ãy­+öîÝ븮Ûíºm _™¹Þ½ÊB#›àĉà ‹Å" ,¨«„¬«3FGGÛV¬h|h||tIooë×o¢¶¶–pXÇ0ÂW‘ˆA4åÈ‘×9qâ0®ëš­­­G/^¼ØŠüçä|æK„‡ÏŸ?ÿí¦¦¦ŸÙ¶Uëyµµ58Žó!û¿¬yòù,º®sìØñöþþþàòAhû†j˜ííío¬^½º5‰lkm=H]Ý­„ø¾G29ˆš›J¥.(åç­|½˜Ðu½G±íÔ©¶ëº³.i#‘¨pÇ´,k¸¨š¡ó^ *?¿ ljËP¢Ð@K BÎݬ¨Cmn›ã|ä‰ï0òé¯[ãÖ˜çñ¿{ƹmÆAIEND®B`‚java-algebra-system-2.7.200/images/jas.xpm000066400000000000000000000507231445075545500203150ustar00rootroot00000000000000/* XPM */ static char * jas_xpm[] = { "64 64 778 2", " c None", ". c #740000", "+ c #760000", "@ c #770000", "# c #780000", "$ c #750000", "% c #720000", "& c #710000", "* c #7B0000", "= c #7A0000", "- c #790000", "; c #7F0100", "> c #830700", ", c #891300", "' c #932700", ") c #9A3600", "! c #9E3E00", "~ c #A34800", "{ c #A44900", "] c #A04100", "^ c #9B3900", "/ c #952C00", "( c #8B1800", "_ c #850A00", ": c #810200", "< c #7C0000", "[ c #6C0000", "} c #7E0000", "| c #7F0000", "1 c #932400", "2 c #B26300", "3 c #CB9600", "4 c #DCB900", "5 c #EBD700", "6 c #F8EF00", "7 c #FBF702", "8 c #FDFA08", "9 c #FFFC0E", "0 c #FFFE10", "a c #FFFC0F", "b c #FEFA0A", "c c #FBF804", "d c #F9F300", "e c #F0E100", "f c #E1C200", "g c #D1A300", "h c #B97200", "i c #9C3600", "j c #840600", "k c #6E0000", "l c #800000", "m c #850700", "n c #AF5A00", "o c #DEBC00", "p c #FBF600", "q c #FFFF01", "r c #FFFF1C", "s c #FFFF4A", "t c #FFFF79", "u c #FFFFA1", "v c #FFFFC0", "w c #FFFFD9", "x c #FFFFE9", "y c #FFFFF1", "z c #FFFFEE", "A c #FFFFDE", "B c #FFFFCB", "C c #FFFFAE", "D c #FFFF87", "E c #FFFF5C", "F c #FFFF2E", "G c #FFFF06", "H c #FEFD00", "I c #EAD300", "J c #BF7A00", "K c #8F1900", "L c #7D0000", "M c #830000", "N c #A23E00", "O c #E7CC00", "P c #FFFF00", "Q c #FFFF12", "R c #FFFF5F", "S c #FFFFAF", "T c #FFFFE8", "U c #FFFFF8", "V c #FFFEFF", "W c #FFFDFF", "X c #FFFDFE", "Y c #FFFDFC", "Z c #FFFDFA", "` c #FFFCF9", " . c #FFFDF9", ".. c #FFFDFB", "+. c #FFFFFC", "@. c #FFFFF0", "#. c #FFFFC8", "$. c #FFFF7E", "%. c #FFFF29", "&. c #F4E900", "*. c #BA6F00", "=. c #850300", "-. c #5A0000", ";. c #840000", ">. c #820000", ",. c #B86800", "'. c #FCF800", "). c #FFFF0C", "!. c #FFFF6B", "~. c #FFFFCD", "{. c #FFFFF2", "]. c #FFFEF1", "^. c #FFFCE9", "/. c #FFFBE7", "(. c #FFFAE6", "_. c #FFF9E5", ":. c #FFF8E5", "<. c #FFF7E5", "[. c #FFF7E6", "}. c #FFFBE6", "|. c #FFFBE8", "1. c #FFFDEE", "2. c #FFFFF5", "3. c #FFFFE1", "4. c #FFFF93", "5. c #FFFF26", "6. c #D8AA00", "7. c #8C0E00", "8. c #4C0000", "9. c #860000", "0. c #B45D00", "a. c #FFFFB0", "b. c #FFFFE3", "c. c #FFFEDC", "d. c #FFFCD6", "e. c #FFFAD5", "f. c #FFF7D5", "g. c #FFF4D5", "h. c #FFF2D5", "i. c #FFF2D6", "j. c #FFF3D9", "k. c #FFF3DD", "l. c #FFF6E3", "m. c #FFF8E8", "n. c #FFF4DD", "o. c #FFF3D5", "p. c #FFF6D5", "q. c #FFF9D5", "r. c #FFFBD5", "s. c #FFFDD9", "t. c #FFFFE4", "u. c #D9AC00", "v. c #890400", "w. c #870000", "x. c #9B2500", "y. c #F5E800", "z. c #FFFF37", "A. c #FFFFBF", "B. c #FFFFD0", "C. c #FFFCC6", "D. c #FFF9C6", "E. c #FFF6C6", "F. c #FFF3C6", "G. c #FFF0C5", "H. c #FFEDC5", "I. c #FFEDC7", "J. c #FFEFCB", "K. c #FFF1D3", "L. c #FFF9EA", "M. c #FFFCF7", "N. c #FFFDF7", "O. c #FFF5DE", "P. c #FFEECC", "Q. c #FFEDC8", "R. c #FFEFC5", "S. c #FFF2C6", "T. c #FFF5C6", "U. c #FFF8C6", "V. c #FFFBC6", "W. c #FFFECB", "X. c #FFFF6E", "Y. c #BF7400", "Z. c #5E0000", "`. c #890000", " + c #880000", ".+ c #CE9200", "++ c #FFFF1D", "@+ c #FFFFAB", "#+ c #FFFFBE", "$+ c #FFFBB6", "%+ c #FFF8B6", "&+ c #FFF4B6", "*+ c #FFF0B6", "=+ c #FFECB6", "-+ c #FFE8B6", ";+ c #FFE8B8", ">+ c #FFEABC", ",+ c #FFECC5", "'+ c #FFF0D0", ")+ c #FFF5DD", "!+ c #FFF9EB", "~+ c #FFFCF5", "{+ c #FFF0D1", "]+ c #FFEABD", "^+ c #FFEBB6", "/+ c #FFEFB6", "(+ c #FFF2B6", "_+ c #FFF6B6", ":+ c #FFFAB6", "<+ c #FFFDB9", "[+ c #FFFFC1", "}+ c #FFFF4F", "|+ c #F4E700", "1+ c #991C00", "2+ c #8A0000", "3+ c #971400", "4+ c #F3E500", "5+ c #FFFF6A", "6+ c #FFFFB3", "7+ c #FFFBA7", "8+ c #FFF6A7", "9+ c #FFF2A7", "0+ c #FFEEA7", "a+ c #DB0000", "b+ c #FFE3A8", "c+ c #FFE4AB", "d+ c #FFE7B3", "e+ c #FFEBBE", "f+ c #FFF8E9", "g+ c #FFF7E2", "h+ c #FFF3D7", "i+ c #FFEBBF", "j+ c #FFE7B4", "k+ c #FFE5AC", "l+ c #FFE3A9", "m+ c #FFF9A7", "n+ c #FFFDAC", "o+ c #FFFF9A", "p+ c #FFFF10", "q+ c #BF6E00", "r+ c #440000", "s+ c #B14B00", "t+ c #FFFF0A", "u+ c #FFFF8B", "v+ c #FFFC9A", "w+ c #FFF797", "x+ c #FFF197", "y+ c #FFEC97", "z+ c #FFE797", "A+ c #FFDF9A", "B+ c #FFE1A0", "C+ c #FFE4A9", "D+ c #FFE8B5", "E+ c #FFECC1", "F+ c #FFF4DC", "G+ c #FFF3D6", "H+ c #FFF0CD", "I+ c #FFECC2", "J+ c #FFE4AA", "K+ c #FFFA98", "L+ c #FFFE9D", "M+ c #FFFF36", "N+ c #DEB200", "O+ c #8F0000", "P+ c #610000", "Q+ c #8C0000", "R+ c #C67A00", "S+ c #FFFE84", "T+ c #FFF88A", "U+ c #FFF188", "V+ c #FFEC88", "W+ c #FFE788", "X+ c #FFE188", "Y+ c #FFDB8D", "Z+ c #FFDD93", "`+ c #FFE09D", " @ c #FFEEC7", ".@ c #FFDA8A", "+@ c #FFDA88", "@@ c #FFDF88", "#@ c #FFE588", "$@ c #FFFB90", "%@ c #FFFF3E", "&@ c #F4E400", "*@ c #990D00", "=@ c #910000", "-@ c #D49800", ";@ c #FFFF09", ">@ c #FFFA6F", ",@ c #FFF37B", "'@ c #FFED79", ")@ c #FFE779", "!@ c #FFE179", "~@ c #FFDB79", "{@ c #FFD780", "]@ c #FFD987", "^@ c #FFDC90", "/@ c #FFE09B", "(@ c #FFE8B7", "_@ c #FFE5AF", ":@ c #FFE3A6", "<@ c #FFE09C", "[@ c #FFD781", "}@ c #FFD57C", "|@ c #FFD579", "1@ c #FFD979", "2@ c #FFDF79", "3@ c #FFE579", "4@ c #FFF67D", "5@ c #FFFF2C", "6@ c #A52500", "7@ c #8B0000", "8@ c #950000", "9@ c #DDAB00", "0@ c #FFF44B", "a@ c #FFEF6E", "b@ c #FFE869", "c@ c #FFE269", "d@ c #FFDB69", "e@ c #FFD669", "f@ c #FFD270", "g@ c #FFD477", "h@ c #FFDA8B", "i@ c #FFE2A3", "j@ c #FFDD95", "k@ c #FFDB8C", "l@ c #FFD272", "m@ c #FFD06C", "n@ c #FFD069", "o@ c #FFD469", "p@ c #FFDA69", "q@ c #FFDF69", "r@ c #FFE669", "s@ c #FFED6B", "t@ c #FFF266", "u@ c #FFF810", "v@ c #FEFB00", "w@ c #AF3B00", "x@ c #000000", "y@ c #990000", "z@ c #E2B700", "A@ c #FFEE24", "B@ c #FFEB5E", "C@ c #FFE45A", "D@ c #FFDE5A", "E@ c #FFD75A", "F@ c #FFD05A", "G@ c #FFCD61", "H@ c #FFCF68", "I@ c #FFD170", "J@ c #FFDA89", "K@ c #FFDB8E", "L@ c #FFDC91", "M@ c #FFD782", "N@ c #FFD57A", "O@ c #FFD271", "P@ c #FFCF5A", "Q@ c #FFD65A", "R@ c #FFDB5A", "S@ c #FFE25A", "T@ c #FFE95E", "U@ c #FFEC41", "V@ c #FFF300", "W@ c #FFFD00", "X@ c #B54700", "Y@ c #8D0000", "Z@ c #9B0000", "`@ c #E3B600", " # c #FFFE00", ".# c #FFE805", "+# c #FFE741", "@# c #FFE04C", "## c #FFD94A", "$# c #FFD34A", "%# c #FFCC4A", "&# c #FFC851", "*# c #FFC955", "=# c #FFCC5D", "-# c #FFD374", ";# c #FFD478", "># c #FFD16E", ",# c #FFCF66", "'# c #FFCC5E", ")# c #FFCA57", "!# c #FFDE4B", "~# c #FFE54C", "{# c #FFE617", "]# c #FFEF00", "^# c #FFFA00", "/# c #B74800", "(# c #900000", "_# c #DFA900", ":# c #FFE500", "<# c #FFE019", "[# c #FFDD3F", "}# c #FFD63E", "|# c #FFCF3C", "1# c #FFC93C", "2# c #FFC340", "3# c #FFC444", "4# c #FFC64B", "5# c #FFCA59", "6# c #FFC852", "7# c #FFC74B", "8# c #FFC446", "9# c #FFC341", "0# c #FFC13E", "a# c #FFC23C", "b# c #FFDF2A", "c# c #FFE100", "d# c #FFEE00", "e# c #FEF300", "f# c #B43B00", "g# c #D89400", "h# c #FFE400", "i# c #FFDB02", "j# c #FFD614", "k# c #FFCF1C", "l# c #FFC921", "m# c #FFC425", "n# c #FFBC2E", "o# c #FFBD31", "p# c #FFC342", "q# c #FFC13C", "r# c #FFC036", "s# c #FFBE30", "t# c #FFBB2B", "u# c #FFB924", "v# c #FFBB20", "w# c #FFBF1C", "x# c #FFC517", "y# c #FFCA12", "z# c #FFE000", "A# c #FFED00", "B# c #FCED00", "C# c #AE2700", "D# c #CE7500", "E# c #FFC900", "F# c #FFC200", "G# c #FFBC00", "H# c #FFB009", "I# c #FFB20D", "J# c #FFB71E", "K# c #FFB922", "L# c #FFBA25", "M# c #FFBA27", "N# c #FFB61B", "O# c #FFB514", "P# c #FFAF03", "Q# c #FFAF00", "R# c #FFB300", "S# c #FFB900", "T# c #FFC000", "U# c #FFC700", "V# c #F6DB00", "W# c #A60E00", "X# c #9E0000", "Y# c #BF4A00", "Z# c #FFF100", "`# c #FFE600", " $ c #FFCB00", ".$ c #FFC400", "+$ c #FFBD00", "@$ c #FFAD00", "#$ c #FFB10A", "$$ c #FFB20C", "%$ c #FFB30F", "&$ c #FFB310", "*$ c #FFB20A", "=$ c #FFB008", "-$ c #FFB000", ";$ c #FFB600", ">$ c #FFBB00", ",$ c #FFC100", "'$ c #FFF400", ")$ c #E6B100", "!$ c #A30000", "~$ c #6D0000", "{$ c #9C0000", "]$ c #AD1800", "^$ c #F7DC00", "/$ c #FFE900", "($ c #FFB500", "_$ c #FFB100", ":$ c #FFAF04", "<$ c #FFB006", "[$ c #FFB109", "}$ c #FFAE01", "|$ c #FFD900", "1$ c #FFF700", "2$ c #D07700", "3$ c #A00000", "4$ c #4E0000", "5$ c #920000", "6$ c #A40000", "7$ c #DF9C00", "8$ c #FFDE00", "9$ c #FFAE00", "0$ c #FFAF02", "a$ c #FFB005", "b$ c #FFD400", "c$ c #FFDB00", "d$ c #FCE500", "e$ c #B62B00", "f$ c #1D0000", "g$ c #A50000", "h$ c #BF4100", "i$ c #FFEC00", "j$ c #FFE200", "k$ c #FFD800", "l$ c #FFD200", "m$ c #FFCD00", "n$ c #FFC600", "o$ c #FFB800", "p$ c #FFB200", "q$ c #FFB400", "r$ c #FFB700", "s$ c #FFC500", "t$ c #FFCA00", "u$ c #FFD000", "v$ c #FFD600", "w$ c #FFDD00", "x$ c #FFF200", "y$ c #E19C00", "z$ c #A60000", "A$ c #9A0000", "B$ c #A90000", "C$ c #E3A000", "D$ c #FFF000", "E$ c #FFD500", "F$ c #FFCF00", "G$ c #FFBF00", "H$ c #FFC800", "I$ c #FFD300", "J$ c #FBDF00", "K$ c #BA2D00", "L$ c #350000", "M$ c #B82300", "N$ c #F7D300", "O$ c #FFBE00", "P$ c #FFBA00", "Q$ c #FFC300", "R$ c #FFCC00", "S$ c #D36C00", "T$ c #A80000", "U$ c #AB0000", "V$ c #C84A00", "W$ c #FEE400", "X$ c #FFD100", "Y$ c #FFDA00", "Z$ c #E29300", "`$ c #AD0100", " % c #190000", ".% c #AD0000", "+% c #D15E00", "@% c #FFEB00", "#% c #E9A100", "$% c #B20A00", "%% c #390000", "&% c #A10000", "*% c #AF0000", "=% c #D35F00", "-% c #FFCE00", ";% c #E89B00", ">% c #B50D00", ",% c #AC0000", "'% c #490000", ")% c #A20000", "!% c #B10000", "~% c #CF5100", "{% c #FDDB00", "]% c #FFE800", "^% c #E48C00", "/% c #B50700", "(% c #AE0000", "_% c #4A0000", ":% c #9F0000", "<% c #B20000", "[% c #CC4200", "}% c #FAD300", "|% c #DF7B00", "1% c #B50100", "2% c #470000", "3% c #B40000", "4% c #C93800", "5% c #FAD100", "6% c #FFE300", "7% c #FFDC00", "8% c #FFE700", "9% c #DE7600", "0% c #B60000", "a% c #AA0000", "b% c #3A0000", "c% c #B70000", "d% c #CC3A00", "e% c #FCD800", "f% c #FFD700", "g% c #E07A00", "h% c #B80000", "i% c #A70000", "j% c #300000", "k% c #D65700", "l% c #FFDF00", "m% c #EA9B00", "n% c #BB0100", "o% c #2E0000", "p% c #C41B00", "q% c #FCDD00", "r% c #D96700", "s% c #B90000", "t% c #550000", "u% c #C71B00", "v% c #FCE200", "w% c #FFEA00", "x% c #FFF800", "y% c #DC6900", "z% c #BC0000", "A% c #480000", "B% c #BA0000", "C% c #C91C00", "D% c #FCE600", "E% c #DD6B00", "F% c #BE0000", "G% c #4B0000", "H% c #CC1D00", "I% c #FCEB00", "J% c #DF6E00", "K% c #C10000", "L% c #C00000", "M% c #CD1D00", "N% c #FDF000", "O% c #FFF600", "P% c #FFF500", "Q% c #FFF900", "R% c #E06F00", "S% c #C30000", "T% c #4D0000", "U% c #CE1E00", "V% c #FDF400", "W% c #FFFC00", "X% c #FFFB00", "Y% c #E07200", "Z% c #C50000", "`% c #C70000", " & c #D41D00", ".& c #FDF300", "+& c #E47100", "@& c #CB0000", "#& c #510000", "$& c #AA1012", "%& c #B41E14", "&& c #C66918", "*& c #C76E18", "=& c #C76D18", "-& c #C87218", ";& c #BC3C16", ">& c #AF0C12", ",& c #400F0F", "'& c #4C4B4B", ")& c #6C696D", "!& c #BCB1C8", "~& c #BEB2CA", "{& c #BDB1C9", "]& c #C4B7D0", "^& c #918B97", "/& c #4D4C4A", "(& c #232828", "_& c #4A4B4B", ":& c #636568", "<& c #C5C8D6", "[& c #CBCDDC", "}& c #C9CBDA", "|& c #D1D3E3", "1& c #8D8F97", "2& c #484A49", "3& c #1E1E1E", "4& c #4A4A4A", "5& c #5A5A5B", "6& c #C7C7D3", "7& c #D1D1DE", "8& c #CFCFDC", "9& c #D6D6E4", "0& c #8D8D92", "a& c #484848", "b& c #161616", "c& c #4E4E4D", "d& c #898991", "e& c #CDCDDA", "f& c #CCCCD9", "g& c #D0D0DD", "h& c #B8B8C4", "i& c #5E5E60", "j& c #20201F", "k& c #525252", "l& c #535353", "m& c #9B9BA8", "n& c #B9B9CE", "o& c #B2B2C6", "p& c #B3B3C8", "q& c #ACACBD", "r& c #66666A", "s& c #4F4F4F", "t& c #50504F", "u& c #626263", "v& c #B6B6C3", "w& c #C8C8D7", "x& c #C5C5D4", "y& c #CACAD9", "z& c #8B8B91", "A& c #4D4D4C", "B& c #222222", "C& c #555555", "D& c #8D8D98", "E& c #C0C0D0", "F& c #C3C3D3", "G& c #C2C2D2", "H& c #C5C5D5", "I& c #B4B4C3", "J& c #636366", "K& c #393938", "L& c #555554", "M& c #8E8E9B", "N& c #B5B5CA", "O& c #B5B5C9", "P& c #A4A4B6", "Q& c #525251", "R& c #202020", "S& c #78787D", "T& c #CBCBD9", "U& c #CECEDB", "V& c #D2D2E0", "W& c #A8A8B1", "X& c #0F0F0F", "Y& c #585858", "Z& c #A3A3B0", "`& c #C0C0D3", " * c #B9B9CA", ".* c #BCBCCE", "+* c #BBBBCE", "@* c #6E6E72", "#* c #4B4B4B", "$* c #111111", "%* c #505050", "&* c #79797F", "** c #ABABBB", "=* c #B9B9CB", "-* c #BABACC", ";* c #B2B2C2", ">* c #888892", ",* c #595959", "'* c #565656", ")* c #616162", "!* c #BBBBC9", "~* c #C7C7D7", "{* c #C6C6D5", "]* c #C8C8D8", "^* c #838389", "/* c #1C1C1C", "(* c #545454", "_* c #5C5C5C", ":* c #B9B9C5", "<* c #D4D4E3", "[* c #D0D0DF", "}* c #D1D1E0", "|* c #7B7B7F", "1* c #4E4E4E", "2* c #5B5B5B", "3* c #828286", "4* c #909096", "5* c #8E8E94", "6* c #8F8F95", "7* c #8E8E93", "8* c #676768", "9* c #0E0E0E", "0* c #515151", "a* c #545453", "b* c #515150", "c* c #080808", " ", " ", " ", " ", " . + @ @ # # @ @ @ # @ + $ % & ", " * = - = ; > , ' ) ! ~ { ] ^ / ( _ : < # = + [ ", " } * | 1 2 3 4 5 6 7 8 9 0 0 a b c d e f g h i j * < k ", " l } m n o p q r s t u v w x y y z A B C D E F G H I J K L * ", " M l N O P Q R S T U V W X Y Z ` ` ...X W V +.@.#.$.%.P &.*.=.l -. ", " ;.>.,.'.).!.~.{.].^./.(._.:.<.[.[.[.[.<.<.:._.}.|.1.2.3.4.5.P 6.7.>.8. ", " 9.M 0.P F a.b.c.d.e.f.g.h.i.j.k.l.m.m.l.n.j.i.o.g.p.q.r.s.t.~.E P u.v.< ", " w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.n.L.M.N.L.O.K.P.Q.H.R.S.T.U.V.W.B.X.P Y.9.Z. ", " `. +.+++@+#+$+%+&+*+=+-+;+>+,+'+)+!+~+~+!+)+{+H.]+;+-+^+/+(+_+:+<+[+}+|+1+| ", " 2+3+4+5+6+7+8+9+0+a+a+b+c+d+e+J.a+a+a+f+g+h+J.i+j+k+l+a+a+a+a+a+m+n+o+p+q+ +r+ ", " 2+s+t+u+v+w+x+y+z+a+a+A+B+C+D+E+a+a+a+F+G+H+I+-+J+a+a+a+a+a+a+a+a+K+L+M+N+O+P+ ", " Q+R+p+S+T+U+V+W+X+a+a+Y+Z+`+C+a+a+ @a+a+ @i+D+J+a+a+a+.@+@@@#@a+a+a+$@%@&@*@. ", " =@-@;@>@,@'@)@!@~@a+a+{@]@^@/@a+a+(@a+a+-+_@:@<@a+a+[@}@|@1@2@3@a+a+4@5@p 6@>. ", " 7@8@9@P 0@a@b@c@d@e@a+a+f@g@{@h@a+a+i@a+a+i@`+j@k@a+a+l@m@n@o@p@q@r@s@t@u@v@w@7@x@ ", " Q+y@z@P A@B@C@D@E@F@a+a+G@H@I@a+a+J@K@L@a+a+J@M@N@O@a+a+a+a+P@Q@R@S@T@U@V@W@X@O+x@ ", " Y@Z@`@ #.#+#@###$#%#a+a+&#*#=#a+a+-#;#N@a+a+-#>#,#'#)#a+a+a+a+a+a+!#~#{#]#^#/#(#x@ ", " O+Z@_#W@:#<#[#}#|#1#a+a+2#3#4#a+a+a+a+a+a+a+'#5#6#7#8#9#0#a#a+a+a+a+b#c#d#e#f#=@x@ ", " Z@g#W@h#i#j#k#l#m#a+a+n#o#a+a+a+a+a+a+a+a+a+p#q#r#s#t#u#v#w#x#y#a+a+z#A#B#C#7@x@ ", " Z@D#W@h#a+a+E#F#G#a+a+H#I#a+a+J#K#L#M#M#a+a+N#O#a+a+P#Q#R#S#T#U#a+a+z#d#V#W#| x@ ", " X#Y#Z#`#a+a+ $.$+$a+a+@$@$a+a+#$$$%$&$&$a+a+*$=$a+a+a+-$;$>$,$a+a+a+z#'$)$!$~$ ", " {$]$^$/$a+a+a+a+a+a+($_$a+a+:$<$=$[$#$#$[$a+a+:$}$a+a+a+a+a+a+a+a+|$c#1$2$3$4$ ", " 5$6$7$'$8$a+a+a+a++$S#($a+a+9$0$P#a$a$a$a$a+a+}$9$-$a+a+a+a+a+a+b$c$`#d$e${$f$ ", " g$h$i$j$k$l$m$n$,$+$o$($p$Q#9$9$}$}$}$}$9$9$Q#_$q$r$>$T#s$t$u$v$w$x$y$z$@ x@ ", " A$B$C$D$c$E$F$t$s$,$+$S#;$q$_$-$Q#9$9$Q#Q#-$R#;$S#>$G$.$H$m$I$|$h#J$K$g$L$ ", " B$M$N$`#k$I$m$E#s$,$O$>$o$;$($R#R#R#R#q$;$r$P$+$G$Q$H$R$u$v$w$d#S$T$. x@ ", " Y@U$V$W$c#v$X$m$E#s$F#G$+$>$S#o$o$o$o$S#>$G#G$,$.$U# $F$b$Y$A#Z$`$y@ % ", " Z@.%+%:#8$E$X$m$E#U#.$,$T#G$+$+$+$+$O$G$,$.$s$H$R$F$I$|$@%#%$%T$%%x@ ", " &%*%=%c#8$E$X$-% $E#n$s$.$F#F#F#F#Q$s$n$H$t$R$u$b$|$/$;%>%,%'%x@ ", " )%!%~%{%z#E$l$u$-% $t$H$U#U#U#U#H$E# $R$-%X$b$Y$]%^%/%(%_%x@ ", " :%<%[%}%j$v$E$l$F$-%-%R$R$R$R$m$-%F$l$I$v$c$:#|%1%*%2%x@ ", " A$3%4%5%6%|$k$E$b$l$X$X$X$X$l$I$b$v$k$7%8%9%0%a%b%x@ ", " y@c%d%e%6%c$Y$|$f%v$v$v$v$f%k$|$c$8$]%g%h%i%j%x@ ", " {$h%k%`#j$l%8$7%c$c$c$c$7%w$8$c#@%m%n%,%o%x@ ", " <%p%q%/$h#j$j$c#l%l%z#c#j$6%:#V@r%s%t%x@ ", " 3%u%v%d#/$8%8%:#:#:#:#`#8%]%w%x%y%z%A% ", " B%C%D%V@d#i$i$w%w%w%w%@%i$A#]# #E%F%G% ", " F%H%I%1$x$x$Z#]#]#]#]#D$Z#x$V@P J%K%8. ", " L%M%N%W@x%O%P%P%'$'$'$P%O%1$Q%P R%S%T% ", " K%U%V%P #W@W%X%X%X%X%X%W@ #P P Y%Z%4$ ", " `% &.&P P P P P P #P P P P P P +&@&#& ", " $&%&&&*&=&=&=&=&=&=&=&=&=&=&=&-&;&>&,& ", " '&)&!&~&{&{&{&{&{&{&{&{&{&{&{&]&^&/&(& ", " _&:&<&[&}&}&}&}&}&}&}&}&}&}&}&|&1&2&3& ", " 4&5&6&7&8&8&8&8&8&8&8&8&8&8&8&9&0&a&b& ", " c&d&e&e&f&f&f&f&f&f&f&f&f&f&f&g&h&i&j& ", " k&l&m&n&o&o&o&o&o&o&o&o&o&o&o&o&p&q&r&a& ", " s&t&u&v&w&x&x&x&x&x&x&x&x&x&x&x&y&z&A&k&B& ", " C&D&E&F&G&G&G&G&G&G&G&G&G&G&G&H&I&J&K&x@ ", " l&L&M&N&o&o&o&o&o&o&o&o&o&o&o&o&O&P&J&Q&R& ", " k&S&T&U&e&e&e&e&e&e&e&e&e&e&e&V&W&C&4&X& ", " l&Y&Z&`& * * * * * * * * * * * *.*+*@*#*$* ", " %*L&&***=*=*=*=*=*=*=*=*=*=*=*-*;*>*,*C&R& ", " %*'*)*!*~*x&x&x&x&x&x&x&x&{*]*^*Q&k&/* ", " (*_*:*<*[*[*[*[*[*[*[*[*}*}*|*L&R&x@ ", " 1*2*3*4*5*5*5*5*5*5*5*5*6*7*8*'*9* ", " 0*_*a*b*b*b*b*b*b*b*b*b*b*b*Y&k&c* ", " x@x@x@x@x@x@x@x@x@x@x@x@x@ ", " ", " ", " "}; java-algebra-system-2.7.200/images/mathlibre-jas-py-rb_deb.png000066400000000000000000007042121445075545500241020ustar00rootroot00000000000000‰PNG  IHDRQpv¾sBIT|dˆ pHYsÄÄ•+tEXtFensterklassevirt-managerŵ¥€)tEXtTitelmathlibre-debian Virtuelle Maschine/¯Ë IDATxœì}y UUõÿgßá €ð@E1‡LͲ2åŠB~¾6ZN Z‰Ζ9Ußò«Vbše˜Z H©€d¿ÔDTœë›óôà½;œýûãìaíéÜs;K/ïž³×^{íµ§õY{Ÿs,ºîîñ mˆ¢ª”QFe”QFe”QFe”QFmÇÔ§{|çKç2zO]Ü9÷6Þ½gôÜ¡'òùЬ°õ5Ì(£ŒjóÜãâ~è¯'{­, "¨(¾ÙÚë;\Hc¡ë)€{î%dÒÙ¸s—«ë:tH2L A¬¾ÒRË5 k›°F7¨­‡Êìï»5ÛÛV€`!-CåÔG‰Œ¢|zl¡rm&jÎÅ÷Ú-UϸMÇ+ÊT:H}Hr ›G–ý9×— Â7¿\»l¾97QZ¨ ¹¿ySVÂ.¾vóØ…ÕT¼Äkg«5—ÖQ™Å.Ùœëë¨g}<,ηîq‹§>J4KgÖ~GX½C׌´Œ2ʨë¨#*¡R©`úõØ´q¾<æí©Ý9÷6Þg§Ñ¿GäP@ŽùvFeÔÄ9“cŒ‡Úþë%æü1äÊŠE2p^u?ôæµpò/ȵW¿dí½w”nVªòñ™G€2•6çÄᙼΠ*‹™@‚¤Q`ò¾Q†Vˆ1išÌ£«æAM«)õÓ6‹í—Ó}Bãœ0–ƒQ)Ú×dŸ jÙ²ÝAúÄ}·& 7úgü%áRð(®™ô'¥NJw 'ÙI9²2æó_™ÒyòÀJ3ò¥IË){B´=ˆ]̱*õÎ966å¤êÉÉòrLÙŽ FÒ¥q}cX @0ÜkII|².¢\ßü¡ÊÈ=£O K‰ôHÕ‹fTêЛV]8c×”¾¢þªl=çÙR9í\}ç@Ü/åw’G¦Ñ<š/VÁÎ#y"¥žeW.ÆÇþ ˆíDªCÓtzFÐcV~—vaD¾—œ›ëуóH”ÏTiOΣàœd(æ7æX; †9ôJÓ¤ž4a,ÎÍ•JWÝÒ‘ž@×+pà¬1ê’«ùήŠÑÜv2·¤&GmXmrèµÙ]»Í1 øÆ0·R7›ß«…1ÆÏ;CØBrYe”ÑæS•WQaUü{Ý¿°zåj|å¨oÆÇº÷ìþ= 5|  r®¬l2ÈèÃB΂K £(Äþë%Ëùâ1 .îÊ)BÀÞÿ—8Ò'å³ ²æ5 F˜:›A_v nYŽÀ;Ë¡c9mIùÇ 0P'×Y\+­¯Q†H N´©§ž«47Ó¸•ÇœÚü:8à5¿h_#`À4ŽÍi°ËrÄá•¶!¶Õþ2Óía=·&½(˜É«ÊÊIF ße„XrB®k"5ÂÌnÓéà€áÕ3tx@ƒ-±ÑH@E—åË«Ã.± XŽ)]¹‹´5ŽrP޵rÎUPˆ¹ãB}µ*a”–!yI’mƒT òP:¨ø×ãŠçcQy<2zIµ¤:(ÂE?°ìÈd9ò†øNŸøG7£'( õ6´ñ̶0y¬_¤íÉu y‰i?§à[éIÓ8r4ѶnD9Vˆ—ãMÚGØÒZÊöÎiÀ«“³æNì™Óåªö#íêÊ ÚªQ/Fë¡ås@Ïe4M’‘gRs=׺r;Mæ±$Í\k88±­;Þ¸Ñ>²ÁºçHÙ‹(ç5¥€˜Üh€7ìø „ßës䜀BX?S5úW·‡¿¬Œ2Ú´%1é¶";Çr(¢ˆÝw€ŽŽ@þº»~Ä÷Ø}ô,ôBŽNî[‰¢(BGG6´mDµRry´ojÇÆMí8r¹\6d´]“ì¿ö_û{Š×\¿¼zÿÚ:†N Ä ÉuI’m;~žÒ¯†SÅLà/S:á)Àáò NKˆwô™Q†Qs.ß 霪]Y+=ìðÑv[C§ú†j]O;àò€vÜ@±©›³ P½m5ÒH[i€fZ+r_Y²((ô›\Ÿ°u3ÌOƒÜH°«¯ƒ 8pÕ³;⋬Ÿ“nX$‡VǶ½|’c”SI’G:Ê\è«ëãà UOÊ£[²…h Ô‚Î#" —¼Z g1Ì`"šÃƒ2"±cÞt¥4 B!\k<cŸÑ‰C„‹6Ò=À Ðû”dà&€ Pà¯Æq¤û=UXÂ$»“'X¨aU™T:ùnÍ F@AÚÒ¶v5pÓñ8ÇÒBO_Y®CL­á¥×3I®Œôq=/05اÁhùÎik­ ÕÍåÞ eòkr­Ó>áj”,æ|P/¥ò/2ʨ iKbÒmY6C¹¡‚OŒøØe… ¥6äs¹À»e©\.cíºµØqç¾Ø¥ßnñM¹Nr`õšÕX½b9zöê…b±¸ÕõË(£­EIÇù|€RWÏ¢oÿ Ê 9ò?6 "óo¹Ä*›øÎ®#”0È.® ¤]§Ë¬§á4úî3šfÙ’ì0ÉêHù±¯®w”hÝh9øí§l)nËÝÚ¦úaâÓÀ )Ð'HŸ` çqp@½ lƒ8&”©ZüMns;ªÒ¤nðPðÄâ#Øîc\±Çüž`ˆØé”D¬‹´<ª'6 2%ØgÂãò#5¦T^)O€DÛ 0“À‡ ÕH~ùEòˆ¿²‹Åâ#ݾWÊ£ãz¬[{¸u‚CÉ$Œ{›Ò$¨HmZëH¹1·Û¨>&äx¤r¤ %°…1®Ú dç—™¤Å‚‘S &@–éâP¿’¥LÕ¿Aêùø· «ÄÕã†QlË8i>“j{ÁH7€¿Ð=¢õ ëBl&y*D<&À¤­ÉÉøƒ]ù”­êgÍ©ª~büsÔ!MLƱ±¦*ûë>æ¬ º5SÐ9£lÛÆ€a:¯:Xu£sM‚¡ ÛØm ­á)›žP £~n4Ũ·ÏJéëd”ÑÖ¦-‰I·uÙŒù\m¥ ÈEQ…ÜÖ„ ££„å+V`·Ýû£{÷î(•Jèèè@G©(•KØ¡Çè·ûîxÙ2tt”¶ºŽeÔUZ¬'"E„ÜçØŽOR™ieÙ; NYA]­ríËz÷ð‡rÈdytW†:ƒî}áÐ ð,ïëãVPŽ[†¥“'@a€GRçð®P‚”Üpšö»=òm@AœË¸îz7“‹‚ô®`ü="÷ºCƒ$]”©£Ái©¯Á w5‰M¥Öœ¢1+(Æ¡çåË— ™1óž{1ì®z#°ç!Šsð!Jôà!ƒU°ÇT—k Ä¡û SZj»F1Lç2/tþAƒ©úémƒ2 8‘ooæÀ€´ÄG–¥rpC%Ýv\Ø;ŠÀ£óçÍÃ'>q J†<ù)utà3Ÿù4fÏš…ýwWm¥Æ,â2–-[.ªhêbÊÓuÔý&þ/¼T< $öÑv0¢"êRÝ7nfÍœ);ˆ¶5fΜ‰ñãÇ“R‚hnNú&3ÔVe˱CA¶ToϽöÔA'H€'ï½÷^ Ú4hByBÚi×4t7Ò´µ¸•^oP Σß íj”N èÊ €œ¹ˆË)³@S+Oû4ùU°iP¬Ö`UAnÙNÙ¡uI®1ª¦ ë^pmtܰ ݱOZ»Ck{H¯4z¦•UËשå+e”Ñ– -‰I·ÙEVD5Š>€gT«U¼¿ì}ì¾{0ÎÑÑÞŽR©årI}J¥´wlãÀîýwÇûᅦj5û ÅŒ¶OJ -ªö‚¨Ö~ëÔ@íÓPÎN2°ÔæÂ]—×q±jo|uœ7‘@O $¤ ùq?|Λt%°œ:Àà§2”«,lâ4*Ÿ1ÃÆ¦¹BÎP8Mûßžtb(HP€Ã­4 "x_”J¦-¦ Ðà‚Q0n*b¾ÄMä`1`¤êÑ~!uãˆ"ŽcŽ=–*¤„q²£Ì‰ÞœG`œãí·ÿi`¦À~\žì @2Þ˜Jç”C:ü\*\¬@­Ù· b‡ñš_„Xo*SªHù%€7€¼€b}G…~ýúáü¸ç¿Y³ga‡vÀ¸ñãâr-Y²ŒÑ£G‰²´ò–L°ë(OœÐ`ˆÃG.h„Ú|ñâŸõÖ[±ný:eOε«×ছnÆâÅ‹8ƒR’sÑæB> ÄÿˆS<Š£¥Žùmf†(ÒyûíêÄH[G9dß,0Ç õX†¶®¸Òî¸'Í ÝèØ£ýÎì­òeƒ4MµM3d“vóRº €9µÓ£÷ÆDb€Q™fµ)[öa$‚~ºÎ˜AäÀ#Я×9^ý¯ÑìõÙ^CiÎkr­ÁÁÀ‚ç´'ýÌ—ÏÔµ>=Óè˜QF]M[“nMÙk׬A{û&CvGG;V­YU—ìàoþiÞB”Ú;0dÈ@|üc{c΃¢T.ƒ3†j!Ïš››±qÓ&ðj„\>qcF ¹©±feÖo؀Ɔ°|›ÚÛyË(£Xl@¡Ø€õ6 ¥W¯šò3Êh{"4¦=5t.Þ>¢A…´²Ô_X§H:Ñ€µƒÀLG€YyÅ%Íîì"Ä—L9uÔÉ%yì ‡.Ó–¡tq8m¯€´ÓjË—àR:Ħ“+’U3‰J;m ¤}¬€Ö[`9ÝÎF[›3ylX:’´³0õÌ2å¡v0¾p¢òÄ0þÎ`Êb@N‚,â`K˜Âg±aô·Õ«W#Šd]µ®òè~¤Êcª<0†J¹$ìßT}å³°ÒšŒn $H“ÀM¢S«mÌ¶Ž´þªíH§¢Á' 4˹ÕC¸jWXvµÔÐ-ATœ2åLüèG?ÄW¾òU+`ÅqÓM7áŒ3¦@=vbI’W«V­‚ ?1Õàt “^-æÇæE¶¢jÜppÒ¦Ö˜UXZFY3gá„N€TjöìY3f4^yåe´ ‡ÂU9j+®Ú˜)@×-²Òõ`àQܘ @0†RG»joòþb$•¢æYS¾0ÉÀà 8c¶‚,OÌÒPö)‚˜gËýT›ê¥ëHä[ë‚L3‚ºFý`òs]gÀ èqb¥µŽ40L‚&^ЯƒÛîÉ.­Ÿ\äºZD›Æ ­ÉÜ'¿[ÀÈÚÁ„P^; `ë˜ô7M€ £Œºš¶$&M’ý¼ˆØ¿Ëd_~ùÈçs¸øâ‹‘ÏçÁ9Çu×_·ß~×]{mjÙÁ=š‘{o^yõ ¼ûþ2T7mB÷UkqÔè‘øô`ß}öÂà=âsÇŒÁnývDsS#þùï$Vˆ_°jÕ*ôÙiG´ojG¹\®ùéhß„wì;!‘çY¼Œ2ÚNhs"æ”ÔâkA®ù×_¦ Ø œ'á¥Z¶0DØ¢À¡œ;|‘•m¨ ²sCe˜:'ŽÓûŽ/¹óª$7nyÀ#”ÿîÍOy‚·+’¹S(A‹pøl`@äFÊ&d÷Lü•;˜v?Õ€O\K§Ô†ÊÇ>û샙÷Þ‹Ïr9ôP<òÈ#øËcaØaÃð±} óçÍWyŸáÿåãññOˆ¡Ã†aæ½30ìµW|4{ï½÷x¤ôš3g>ý™Ïà£ûî‹ùóç 4irŽ!{î)tËxiÉuÔQ8ñ['bõÚµJ×ÁCã7¿ù5ÆÎ ë7`òi§áÀÄäɓж±M×NžÝV­Z‰¯}ýkØÿ€ýq×ÝwikEmÚ0yÒdðñ0qâlØØfæ%‹côèÑ8á„°vÍZÕA¨ìùÜ¢çðù/|ûîûQ|æàÏà÷Ü#ŒÌ0pà@Ü1ã >C† ÁƒÎUu§ŸÑ£F¡±± ?ôqÁ£"Š"Œ;öظÜD?ˆ[n¹cÇŽÿ$àpý0„Ò™slX¿“'O€‰'¢­m#d@õõàÂV§MšŒüã˜4i"Ú„­â‘î¾¢»7wÞu§Æ¸ó®»0nÜ8ÝÝÁ±hÑsøÒ—¾ˆý8‡z(fÞ;3V…sÌ›7ýè>Ø{Ÿ}0nüx<ý·¿‰ñǰníœþíÓññ€cŽ=ÿxñE€su°åOsîÃÁûî»/æÍ›§Ú|¯½÷V:ï½Ï>¸ë®»0jÔ(Ñßçƒ#âm6à»gœO}úÓøö·¿¶ m*daϾS2ÀGI‚Ò0Æ´ü±/dŽÐQޏޫ®º?ÿùÏñü /`Á‚…˜6m¦œ9ET¸à‚ 0aÂD<ÿü ˜:õ<üðG?‡>šýöÛÿ4vlŸ{î9<õÔS˜6mÎ8ãŒ)CÓ¾­í}ëo~ƒûSN=ÿ{Í5"!®}SS¦OŸ0àÚkÿgu-z#[[ñ³ŸýLª×Lì<3püøÇ?ÆÐ¡Ãðì³ÇsÏ='ÊŒÀpÍÿ^ƒ3¥œ‘­¸þºë%ªÜòë_Çúœr*~zÍOÅ3ôrW=Ñœ{8q"-zS§NÅUW]ë-û—_y>8Ó¦M÷¿}ºaÕ 8óÌ)¸éæ›5ØÇ/oúe|Z —Ó ‡t—ÆÆFLŸ>ÃlÕ1³±…Î×\óS£Þ×]w]ܧ$ª6:flOÇV×_/øÅé JEg4hcxáùÀ9ðü¢çQ­V±÷^{)¹Ày矉'iû]}$Tüîgà²Ë~€W_} ßýî8ÿ‚ T á~òwÜqxñÅŘ2åLœþùñ˜å?·hžz2îS¦L vÐÀÜ«K_Uí3åÌ3Õø¹îúëqöYgcÑs‹ÐÚ: 7ÜpC0 eEx‚Žw®Æ¥œë˜ìøÐc› 9%@Z@È£€ôÌÃ&éG:BéD-gý0æJncY†»s[h92Ö_zBPÀýô¾%CÖÝQ‚°Ò €'9ÕPP@êUk —2¤B6¸O´/ ¤ñqÒœ˜Ì(£®"&ýýwàœ³ÏQÁ¶¶¸à q˯]& áÝ9÷ÍÁ 7Ü€ÿùŸŸàø#¦Ï˜^7ÞõÉîÖÜ ÓgÌÀk¯½†OüüqÜ1cúôéN¶‡ÁƒîŽÕ¨ üï÷ðò+K‘[¶åÆ<·èyä y¬Y³ «×­ÁÓ{ ½z÷Æ’ã¥%/£T.'6B¥RA¥¡ÔQB©£åRÉø<úȣشq£q¯$>ÕJ•J%Q~FmïdEõc²³@Þ4Á ìýAí$Pª+ƒT¿$~ñã‡Ò¶Ï¹27vêh‹E|þó_ÀªU« zÆ”)hjjĘ1cb{òÈü£GÁúõëð /^xá,_¾\ì°s€$Ä÷±cÇ¢wïDê‘ }B@öµ#-uæˆë=xrŒaŒ¨·z\¢Ïªòâþ(mÅDž¹êgâq}Á+õ?~¼:5p÷ÝwaܸñâyÝzèauÔQÈçŽ;î8¬^½Zàb†C=>ú{ì/1b8.ü‹Êûè£bĈˆ¢*Ž>ú(Ì“§[D]Ï<ó,äò9ŒÙêú**PöÝï~…|Nõw9¤~øa 4•J­­#1oþõéÏàwßÃûí|žaÍêÕuɾc [s3º57‚¯X‹î½ºcÈgš¦F¼þÊËhnlÄþûï‡W_{¯-[‰zöçÊÕ¼²ô5°ß¾‰ Q.•P®–ãÑZ9®¿þz¼ñúë(“C.—‹+”2ú“í(„‚æ;NÖŸTywm¾ ©UÂ¥7/óòë[â_ù º• Ž=2bN§{Op@¥å0ËyŒÅ3ÌåÝ8¯®“|]S;Á–ÓÍåû¨|{'Mò{+¥\&~O€Œåx§¡rlÆT:u*¾JÛM~'êq*Ïž;®õ;ôçU~ÿý÷ðû;îÀ’%K°ä¥—Œºi[ÈŸ©vèÑàQUeÔ¡áJÙe—¾8 Å‚ØL½ ®¥¥·4 –/_Nvžÿìï9DÝ{ýõ×Á?{¿cŸÁ9Ðwç¾ÒD`–/_®…Pr$€]vÙ<â( Xµj¥¡w„XÈŠË1cÆ ,Y²‹/Ö•z÷é݇Št#Ï8c n¾éfüâ¿ÀÍ7ÝŒ)S¦ '@Ž/ïÞ}`DÕœ±Ç¶•çTâzïiÔ›ÄØ ½¸‘g/'»rö“#ÇŒ=Ç{ Î>ûÌ™3÷;Ï"+V¬ÀŒÓ-ûÅŠ\wÝõ8í´É8õÔSQ(pÇw`ÿý÷8ÇÊ•+ÑÐÿŠSTU:t€ @Ýã´¨ªDêþ§ûi¯–^àœ#ªH¾˜gùòåØw_í?ÅõÕãÉSò§*ø'] òÕØ£ ›ëõÆN—ï°L¨}B@p%Œ*{‚£‘¸§ÔTs ûÄBœ¡eˆ)+¾ï!Ñí$çW½Ë­çú@售ҦÊñ \±Z ÊÃüîÎ>> ¤Ñ{udÙ†FÖ—4y©eôA’I×­[›nº“&Ÿ†“O9{ì1·ßþ[¬\±år¹.LjË®T*¸å–[°Çƒðö[ob§wÂôÛoÇý÷߿ٲ9ç˜vãxú™gñ‡»ÿ€sÏ=—}ÿ²xMÏåRËNüU‚}ì£ØyP|l—`‡½a—w®ývÚÕk°ßþû¡±¡ˆ]vÙ ׯÃ'>y zt놧Ÿy6±ÀB¡€¦¦&¬X¾QÄG ^yùe”J%ã^EX±|šššP(ceô¡ ßB™±9|ó& ÌpD¼NŽ¥•Ü]¡oZ–N¬PÐ_m¹Ô‘“ œÖ›[<ÚÁ£€HQ»Æä¯pò ¾ÖÛwz âÜ('ž°É‘XáôÒÓ_SYÙ°@ò›:¸ P ûçöa¤ËèvW €³ø”3ä ~!*âZìD#ní° ¹§Ÿ~:Ú6nÄñ_þ n»ív¡‘ãônÖ5`º£½bÅJ@GGúöí+ê+õäâõ }úôÁ믿·ßþ'Þ~ûŸxíµ×u¿½?æÝi§ðÞ²÷p,_aþ¬¢Wië•«V‚³ø4Dß¾}JÈcä“&MÂúõðßÿ}¼¶KDwH9hâÖ'â‘úuÔ¼ñæxnÑsxõµWqì±Çª4ÝCᴒ͹(Jp¨Óò×*|õ6 ±üëµäKúb[s®30ÎÑ@ì¹çž¸øâ‹0`À@ Úc5Ö"Á;yò$lذǯíQÄѳgOÜ}÷ÝX¼x .»ì2Lœ8Q¥÷íÛ¥Ž’˜[H_£2ÃîôQ,ãQ¼¯OKÄ¿ôø0Æ1V$Æ l™.Çr$Ë'œùIg}BÀ‘²& S ôØ™‰…yìSi4ªú“=O[óS$Ʊï”]"1GÆÕ$åªN-OP‘€¢g'\!ZI²Ü1QŽ)ÐXóh Ä>vCnA/(¯#(`ö‰à—T› ªüŒ2»ú ( IDATúɇI7lXýë_¸ñÆiøÔAŸÂ¯} Þï}¬[·¶.Lê“ý¯ôÇ;ÿþ7Êå2Þ{ï]ôîÝ'NÜlÙÓgÌÀßþö4fLŸŽ~ýúbúôéxó­·ðË›nªKvb`àãûï‡çÿùvCŸAŸ^½P.µãÙgŸÁN}vħ:Q¥‚çÿñôîÓ‚¾}wÁS{:ù¥¹ZZzáõW_C>Ÿ7~VAþlƒ}/—Ïáµ×_CKK/ärÈ/,f”ÑV¥4;öž\Οt»û0á=ËM HÝ}˽ÜM‘yU=9ü¹#«ëÛÅŠÔšW;adgC9–Äa´RéhÚà_oåH©ã·LþbAüÓƒª+Ý#Ž«©×– PçX½ PØQ2X¼37@œ.=a™®ˆVÊ È63´%AZË¥K—bܸqøä'?§M3ªT(°lÅ äÛÕ·¸”¦Œ:mÚ Ø¸iþúØc8ú裕=!êÂGFŽlÅ’%‹ÑÖ¶·ß~þ뿎ç"j_.‹_;à0fôÜ1cJ¸ñÆEc ÛÚÚŠ—–,AÛÆ6üîw·Çrˆ5nøÅ/°±­ }üq}ôÑF?’MüÊ+¯`üøñøô§>¥äsýò>©iQ9ýôocòäÉ8í´Ó€„;-;nƒåq¹<>å0wÞ\lÜ´ ¿øÅ Jç(âhÙŠ—^z ›H½é³F[!†­­qž¶¶6üNت?Ŷ6V\Ö¸qã1þ|Œ?<ª0¦ìwÐAá—¿¼QÕcìØ£1{Ö,DÕ*zîÐSÖ®]]7&õÉ~ã×ð¯ýÓÀ¸ï¼óxõÕW6[ö~wÞy'¢jo¿õÖ®];~ÿ{ zh]²ãZØÌÚwç°|ù*üð3€?ÎP÷wëד'MŽ@ŸÞ½qÁyªôW^YŠ}?º·À|.‡Þ-½Ñ­¹K^Z‚½÷Úëׯ*¸Ã;`ñ‹KУ¹z·ôF>—£^rF}hɇbGGÃc€Q„™'ü—™Ô)IÎóùw5 g€ÈŠóX*3#«“—ÚBCKÓ>ÒQ6wʸÁK½Û÷¸ fê ÈÎ1q8¥\u7²žw¥ò€–ò¥óe¸òÏ© ¸ëtÇ…Ù#vTùÝTƒÑÜ©ueE²Í w|c–}¾7²Ú)Ç4.A¿*¢LZ §u…¼Ÿþä§8óÌ3±qãFL˜0ÁH;v,F…EÏ=§ËçæÉFíÌA‚:ˆ3òÈ‘;v,öÛo?\óSùòAÁéãßçž{.Î;o*žxâ Þc0®½öZ2#µc8wê¹øîw¿‹#Ž<—^z)f̘¡Ñ¹çNÅySÏÅãO<ÁƒãÚk¯3‚'Gy¤ÖçškbÙÆ à§?ý)ÎsæÜ‡qãÆùvëž¼;v,Ž<â,~ñEÀ´iÓpúé§£{÷î˜:õ‰a«=ãZñÂB*—ê}²ÍŽ;W_}Ž{LìÞȹ¢(¶ß”3Ѷ±M÷+ÑÖ?ùÉOqÑEâìsÎc Ó¦M9Î>ëlœþù8ãŒ30hÐ \wÝõ¤ûlEÒ¸uß¶'pÎ9çà¼ó¦âÉ'ŸÄ{ì¡ú•eŒ-º #Ƙ&û§~„HV7Òó¤ÕäfpÓ©Þ*1Èc®c4Xª rþ6:0ªÛòøæ\9oÑy—‚~èÉz`¬%B–ó…²WLLè%×Zîz@€³aR 4{Œ*Uy=Çþ½yu[ù¾µÛãKĺ‹à@Òº/¯I0!D* Eedþ{FÛ%aÒr¹Œ§ÿö”Á_&Ý’x×'û°að©}#V,O)®X¾ÕJG1+W.¯!›ø¶—ßvsðÑØ1·#ržårÙÈò9ùâ‚\.ƘzÃa>ŸG>ŸVˆ¤wÞ}‹/A¡XÄ^{í‰r¹„J¹Œj!—Ë¡X(¢X,â•¥KU#ì·ßǰ[¿~Ù‰Œ>ô䋲ûO$É0ƒ€ š}åYØû5òRç’‘§šeF]žÇ°—ÚSôÕWƒzÉ#åK91€'vsx̺H°¯yLHÙÆª?MWúÊ0¿ Ó6£±š„‡ùo« «ªD°œãPÇI$¨@o‘ܽÇØØ¶AÕ¯[÷ñu,ÍݺcãÆ60ħ …"À*å2Š Ø´± ÐÐØ„|>öMMÍÝбi£*'¾Þ΀¦¦f´·oÐØÔŒŽMÆÐØÔŒr©„B±E(WÊ `566¡Ô¾ Î3Ë¡P,"—‹ë])— ÐÇSp PŒõŽªUä ”Ë%e‹|AË©VÊJN±Ø€J¥¯¡\¿s ¨”Ë8X.‡\.^gy!—Ï+}ŠÅUc …B• y)pÈÑÈP­ºÏŠ *¿”%Û=Ÿ/Äþ€,/—C>ï7DÕ rù‚ÐYÖ»ÿÚ¨› „Μ£ØÐˆr¹¤ÒL[Ub@+•Ñ4ÎQ*u¨ÛņF”K \546¡ÔÑpŽ\¾€¼8JY­VQ(Ô‹,s¹ Å‹}r¹û7¢4‹Èåóˆ¢(¶yï&75wS}‘hnî†M¢7uë®úm³øÎ…MºuïMmÔxihlD>ŸGq”:Ú•o%LJêoâ/Eff°T¿¿Äî§6Øw{Dìs;ÁËãÎSÎ\&,È|mðèk!A³–éÊ rãó?ôžyzJòÈ2}ÀWî°Óz:ëª\Ò¬ø€¹¬<æî½‡Å]ƒkìøÓªQ„JE¼\'ŠŒ—ÒFÕŠ*å28Óç)*p3åJYi\©TدTcpU+¨FüÅÇ«„Oþ¢Õj%µqŒ<²žGU‰ãÝÆ€9GÄ#T«UDÕ*tweˆª•‘cò1€U}7Š„ü*¸(K2FHr¡^U”!?! =HóËïvåQ—GXT­ˆzq%“‹ÀäŒGâùɾbüŒ±• Z0Oω a;„¢pNÀ}|JªZ­¢"t­T+ªßÈD¥ZA¥\1N0pTªUT*åXðâÜè‹T_å}SðÉþ-ÓÊå’}¥R.ÇÁY®üË<ði-‰¡°Kh|0ŸÈ&ëNÑW­'>°.‚Æš$RŒ<ÜL§ó³žýt]é´®®¡ç¬ø™Ÿ9¬!Ö4'Ær²Så 9ÔLÌÝöšE¿«µfXŽxºóª!OCà!Œ¿@ü¢oR@ÁðH£ÅzÊÉÞ²íƒXd¯òoRžŒ2Ú´%1éö"›sŽ´ãµ¿þU‚-MÅbÙí#èÞ­;Þ{ï},[¶ /¿´c9ôèÞûîóQìºë.hiiÉ^:˜Ñ%EÏ};ö4?/7sŸÓ`æåÖÿîC@CËÑàO|qêªå™»6öñSzäѶ‡z°Zù$ Áå[»™pBiàE;§´Óç4%_$ßÐ-äPÇR:TÒ¦;IÒá’ª›»4¦m¥yÔµ@u!ð/åÅõ% fñiÇ›“«Ÿ¶ ¸®“Ë#lK£·—XÈT9¸´m‰#ë®di2è`«âjz^þE‚Ô( m!k$œhùyÂ'u¤ R#…À‰Ó¬l¦œa òÈx!cS#q ,QùpÇ¿Z3õMKö i ZËñ§ ê+7ÚÛzÚÐZ6©«²M™ýEÉŽ` 6%CŽqÝÿùHiR†ÍGjËe>«vسû2'r-àeëÙ5Ç&Dsä´.pv¿tæ_¯ O s…¶yU«/p9‡ÆDO×ܲô\ÚÝ—kä5‡q­æm4!V(  ß@ß]`Í’ÄHÞê[ó™®#w„Øk­²¹gƒzg^'yݹTÔ™I»“r¾À‚:%àóAÒù É>OFm-Ú’˜t{“ý¢íB¡€wÜ={öDÿþ»cS{;ªÕ òùš›šÐÜÜŒb±˜MýG’ÀÓûióhàȼKh—0&%Å(0ílÒÓv€ÀèPb(XµxÝJh‡3f"IL¾-Ÿ8„£‚ˆlêÈÕºŽm!c ¸à_7 ìêJøªÜSGN%”m4ܦ…Ó&a5ƒ"™º¿êÔ´ÍláÁê6•´Ú[;ÔôÅ]ŒØœƒqŽHØZòÉwζtÖ=Á38oÀ@úÊk8Ÿ4ø´…Lc êÝV0D (¯ ~h€@‰÷€Ô$¢Žz(t ^S~ ÔAì%Ò¸ÍgÛÜ Ðýš™âÿhÒç°ÏIø´ŸP@«ô—}P<æ G¡ì›‘èÃJ–äcLóÉ2ißW¦‘ýCχþ`Ó˜ÿ™—'™Ò ÐdŸ 0Á¾4>Y1güåÒnZŽ9§1ã’Ûf)åüc¡¤ý|\kµž±À/–iä|OÖ2î°¸AÁKû›Ô)îÒæ¸2Öf+¨ÏYþS>_ª-„?`Ly¨¾¦¬ì‚Œ¶]Ú’˜t{’]Ò9[Šchhh@CCzõêõj’QFÛ%°Zy´# ìdùþ<Öã¤ÌÄ@÷óÚÉì hlD@?0QG3%î:G¢>Lò¨ß·¦;yP2(± %qŸtÀ%¯r.¡q°•®õ4ô8úܹb`ˆ"ž$ v6jbD‘MÁ#FS\§— ¤m¨]%*¿V €G€x~Ûî\ÑÀˆh0YÁûä€-?"×’‡v/£ËýÜÜ1UÁúä´ª$ˆâ€U Xið†ÁÁ2°R ÌÛ€?ät"( UK%7>û²oH6 ôÇ9åœaŽ2iwÆJܸgAYQ¼þ)Ncžr9å!A5gÐ €Ì/Ë /d³æÑ¸:ñ{ÒŒúQ€K@w˜¸þ7ÜØÖ5sèø#äôE¦öüg^º Ûª“ î(€.j§.fP ¾´ç ×Þw<¢åd™ƒ1cv°Ìc|&”àÜ4³×UÕÙÄ,£† îé c¤Ýœ¹¦O vÁÇkSè”@-Ÿ#£Œ>hÚ’˜t[—-Gmv>?£Œ¶ EØ ''!oŸ0w¨3à+‡[èn»{`9M€@^&„4ïeà–!ÇxvÓÿz÷C:LvýgÏãçPûd˜ÉAbA¡6¯oÇEòÑ A\ý« øeÚ±ÓN¨¡¤rÊÕE(P@ÚŸ&¥ éÐm¿]âBë¤ à¼ Ð' ì`}˶0Po¿·ìáìÛAêÌ›­+`Ú‚*°Òb\æ20 N >u1¿âu:^ê¬C‹V8Ë å€Ëm«^êEqÀ/KVóL@+0Cã+c$Pð/õ´€]Dù¬€ñæuÀx$@•i½]–«‚B«Èø•ÂGæá­@1VUèw >“ƒñüF‚F··Z™\FrΦ=€6¤ @ÏÿžªˆKR¢œs  ­yì Al9Ç…­f’¸¼ÊÊa|Áx%Õ^Ï¥¬í?¢ßÑuCò:µðø¡ @vJ £Œ¶Êe´Pø·O¤ 0Ï1Ê. øò[wàlæ· ùÕ®‰:|à£J@ÉaIà߀ˆÿÕ“SgÊ”Då(G–Éäc7H vÝãh‡ÊDŸý¢È.Ç€F†AUŠñn—ϨYB @i&û£Ž»´‡`"X ½R»S@h€4ò×0ùä» ¤‹ì H^0î§eˆsû_Ú—Dù‰XŽœ.`V~άœçÜžJE!yö¼b°‘9TØøT+ ÊítÊ#õñ¥»0Ôj7R†¯=U€ÈÖGö»@€hòÍÅ*À5È3"˜ÊNñ@L ô*>ŸÁ ²läu­ÊÉXR=Ç’âÕšÀ¹šW¹¬§ €ª7•gγêQ21«£ô†ÖÖx¤A61Ð9±«=O+)ª}Ä+h ì¨¦ifö+Û”Þ›¾µÑ³*ïz¯T{ýît@`ŒÛC[Ë¥s±àJÁ›QFmÛ”2Êh;¢ÔÇ÷X2/åS»ÍÒ²’ôdPòhTÈ 'ÅôÐÌ¯ßæ®Õ°åØÀĸ´bt§ŽäPÜÝ}¦\Fé@J€£+áX“EÐÅ@W¡²tîõË®§š•­É.‘–Étõ%H0*Ofê»Z#ª¹oZH§ÝEÊòðÑ:Ó`‡Þ2G¶—jn&0yÌÝ1ÓI§Ù 3\|Ù‡…>êeƒ¶l»ˆ t+ïm q©n…‚V>;xU/l熎µœ÷ÍÙ Ð'Ÿ»õØœŸ¿(czË´ç!ƒÓ¼Éåù.ÌiOvü˜›ú)Y @øÔ´è¶³9kÈ“ü¥ „y­°GŸùÕnî\ ÐÊ[S‹lIš™PØ÷žÇæ¼Â’{î6pŠLÎwmDæÆ÷ìt@Fmÿ”2ÊèCLÆBÝ©5[{„:E@A4ó;€Á¼q¡N†Ú2jx÷€ñe6 sîÚ B\igÐäuœF <¬`éè2”úëèi/c(X@Fù®ñ¸}L¿Ù’W H>ÆuÍBþiÐyõï°Æ…hxq­Óí¶áî…ˆ±øä*Ø_“ %LVœç*T{´è¾˜¾ÕxËòih¯Ô0GÕYË50].t® B¬¡@bË’þAŸM·½zvôQà iñ©¬Óݹ‘’L›pd„æ"çQ#À}/‰æ3xÉübòê¿¶õ¥‹þ9ÑÕ'+ Íå…m_7ßæÀß.Ô™×ÍV_>ƒÈàÌ‚eôá ø7£ê˜:Ìø6|,\˜:ÿÊ•+ë*«+hì±ãP.—½iårãû/Ìè¡ÄòêÑ;‰h­ß7O< sçÎó¦=8w.¾yâI’›–’ôîª6ë zü‰'pÈÐaxü‰'¶JyÛRÝm:dè0rè0|öСÎ'5‰ç“©™n\ˆ΋ªÒL=V^ùŒ´xv¸ÖçÓV½ÔJ‰ð—¾PVß& ^ÎÈÇ/@è!RYU¯ˆðr—×âã„/òòq ùxëΛ¤IÈÇæ«ÇùLæw$+û™pñ®Šˆ(/EýÌ+Ôß׌ÿl"†³ó@çñcç‘mCOÝÆ®9/8˜øÀªI0¿Q[3Ýå'êíšžÚÅo>|Åè†üBõuu#}ŒšÏ¤¯ùmPÏhèìx5¤ó5‹‡×¹%ÍFÆ„3¾ÄüE\Ï?d®±ù8á‹jðiÞˆðr¯á8`Ì­^s­î±ª#×åòås§‰ÚcÀß×@úlº^aªš.¯·>fǨ‹ô¸ëTöŒ2Êh¦\g2=õÄãêså—ã²\ž:8ðõN¨«œ® ¾}ûâþð¦Í›7=zô@ëÈ‘‰åÕ£÷–¦¥K—âλîÂú ŒûëׯÇï¦ÏÀÒ¥K? ͺ®Íº‚fΚÏY³go•ò¶¥ºÛDǬqýd'‚&Ê©¾úõoÔéÔjL ËMŸ ‡)T.ü¦—ÄñÅýçãlw%—åsUåS´òíÍÌS³ÿ#ú9€ÞÉn:˜àÁ Ò¸_.T«¾V…]pâåJ¨(x¨£¥=-¡lî"‹"v0íªZ3âàQ|ò„ 4˜r“ø?>›yÇQ‚ãò߇ðDêC;må dñ†ê)í૵Ÿ¯Ý8‡n‡Èhî7¾vó÷s§ï™¦PÓ^‘¸ ÙXa7àWZ¶?»‚ˆ |@Vþ¶ó˜‘Žõqf1w|I>ÂkÚ›»v6Àm¤¹›~ô—TM甓ÄêŽ'kŽ«+ ÐÉÞF¨“â¬Y@ £Œ>ìÔ©À¥#FŒÀeßÿ.¹ô{©ø×¬Y»¹EÖM§œ|îøýÂ1ÕÄ9ÇŒ;îÀÉ'ˆ\.Ù„ÞItøá‡áÁç÷|p.†~ø¤Ñ¶EË–-Ã+¯¼‚sÏ9¯¼²Ë—/ÿ UÚ6ÉugÆš5k §½> O[ÔãXk'×Îà•ÁLÀí‚|é|Ò­A„uBÀЏ±>ôåáã>Ø|ŠAãÙÌFAIÁz­ÌMTƒD>_Õqεr>ÿÖñS|‘: Hj’ü‘}“‚wñ‰ìL¥ŒÈ™µ[JvBN—àÌ›2ÌþDOvDžr0Ï}Þâ£U $±1>²ß»2IðõCæÓ)¹¾n°ƒö`¿nèñ”í6)€öS³¯E‡EÎÑÎüíÎóÚ°tu +„è0¢³¦Š^[øSr«Yߺ ë»wp¦ c]Ê(£Œ>ô£a†ÍôGŒJ¥¢®/^‚ 'áÈÖQ7þsj·^µ¦G®ÛÚÚpÁEaÔ˜£pþbãÆ*­«Žf~ØahlhÀã›»£O>õ"ÎÑ:r¤SÞ!C‡á÷wÞ…o~ëD¯Þ¶nië¢zóŒ5 ÷͹ϸ7{ÎŒÕjÜ µ,X¸‡ a‡Ç ßú=ÿ¼J[¿a.¸ð"1²_ÿÆ xéå— ¹óæÏÇQcq%±m4köl|é¿wø:c£zè¾9spÔ˜ÑhhhÀQcÆ`ö}sŒô$ÝìÇe¾ü•¯¦Ò›Ö}íÚµ8ý;ßÅ1ãÆãž{ﭫχôÚ’´øÅ%8uÂD1²ÇŽ?ß¿r*]°ÃŽ¡‡Žo|ó›xnÑ"pÎÕcŸ=t¨â]ßÖ†ó/¼­£Çà¼ó/Hl×  ¹‡á'|‹-R®U[[οðBŒ5SÏ¿›6mRNØÁ‡ŠY³gã _ú†v.X œ¶µkÖâÛßþŽÙŠÙst›sÚÚ0õüóqÄÈVœ;õ<´µµ)ÇÿÓŒ{gÎÄ}á 8dè0<º`¡«ëRéè‚åzý> lçÝÏK\\DZ£@H?V`:…¶\¿ólêFJ'N¬×ÝævN«vx‰ùƒ;ßVZ.ÌíÝÕȸ&ž%Íf{øÌ.€BÅ’ûÃvÆvéí;‘’Ìsò¡À8üGÕi°„h¦ú ¸g7>-…òsS*Ñ|X¯Ä²@5O°tJë IDATç@dÚ.ò´kÿxð–Âeà@_WäζçØÊ›ü‰™<XîÔzøÆ©­9ŽŒæY]Ÿ-Íûæ\#Ëtû¯?—ß°&èÖ‘Ð<&ïyÂnõ æ%6ftÌ×ðº dÜÀ¡îï$¿5§Øáf;˜@?æ±-.VÈ[Ë ©¹ðë\ç§Ž¢3Ê(£í•È<³Ù'|tÅUWák_û*æ>p?&MšˆŸýüç`c–tó¯nÁ„SNÁÜîǰ¡CñëßÜÚåú0ÆpòÉ'aÆw÷§ÏH>-ÐØØ€Ÿ]Wï$êLêÍ3 00,yé%À’%KP­V1xð`ƒ/ÔpÉ¥ßÃÙg‰Ç.ÀI'žˆ+¯ºZ¥ÝpÃ4Œ= Í›‹“O> W^y•!÷Å_Äì™÷âÊ+.O<-òúë¯ãw·ßæðmÉv¢sþô'|îsŸŒ?sþ4'vÄSèFÝ:§6¹n½yÓÍ8rÄÜ}çïU¥•ÒkKRí~rþú—…8ùÄ“påUWƒ1†ÿ'CøO>¡œ_ýêW˜xê)˜÷à6l(nùÍo´³d}.¾äRœsöYxü±¿àä“N4úØM7ÿ N€ùsçâ°aÃð«[~mø'¯½ö:î˜þ;üðª+qáÅ—(gè7Ü€O}ê Äo×ÚKúã>ÞŠpê¼_ÁÖ=ôsN"#ÓºúÞƒÎÊ6n<}Ž”g4’Ñ/}}*%HðZ×ÕÜês>]unr•`¯Í|º‹JEvÛÛãÜrÇý­¶ñ||ú™Ùú¯5NÌ©Fö-7/³Ç—n"‡=n.ÚŽ¦Ž)SÎ5æŽºŽ„pžPcR7©l ášÎ™SÝqNexG£‚ýä;öcP‰¬z{˜üoPÁWŸyµŒ%3Ê(£ÿ(2q’E'­÷ïœ1GŽ8 ÅŒ=êèø~ ÿ¿üƒB>—ÇðÃÇ‚ j—ՉψÇcý† x饗¼ôÒËX¹r%Flõ—àÈG ¥W‹_—„ëÔuJ›'`ëQ­­˜=û>€³ï›ƒQ­­uµÅAŸü$žxò)<ûì³zÈ¡øã]w©´¿>þ8†:…|­GŽÄŒßýÎ(ÿÔ“OAScŽ.N‹êwò‰'¡¹©Ùá««¾u~žxâIôÛµìÞàÀ€Ýû£ß®ýðÄO¦ÒM~þüçûÑÔ×±Þ¶ýëããè£Fî=pÊI'ÕÕ?jéµÙ»ï¦ê'Oâ™gžÁÐCÅ=wß”µ`!­Ûp,xt>‚Ía8¤Ÿ:è <ñÄ“xæ™g1ìС¸çÐ6Z¸{ ˆ|.‡á‡ŽG,PG¸à”“NBScFH‰2â Œ?vqÒ‰'л­ ,ÄàA{ Ÿ/`Äðáñ©RSN>ÍMºO›/Å2ëÉÔÇuxéî®úD<Þ±ä¸ÊϽü6àtßÐf3˯Úy5ä ½¼Ž=çâ®áœÚŘê8 YÕ/Š?V^JÁçÐÅGåqì›±ÛGØ‘¶·NŠà}¹Zåyäú>ÆKÜÄ.¸z.>  úévðóU_×}Ò´ò]0޲Žät±WÈžiÚÂ,ÇnW˜úåÚýȶ«9®¤ köcØriã$éšƘÓõUãQ´ƒ× ÝÍùÎ|Au0ú‰oþQó¿_gÓ^¶ÍæÊˆä!õÒó/Œ¹™qf¦II{»ínñSy–LãG\¤=¬±nŽy«?§©³eZΩÍÒå3exÖƒì“}²ÏÞ‡Pþû›Ek׮Ž3gâ•¥K±ôÕWyW­\‰aÇ«ëb±Ø…šhbŒáäOÄô3pÕW`úŒ5ß-ÐÒÒÒ©²:S§ÎäimmÅ ßúN›4 óz·þú×OR[\~Ùe¸ðâ‹qö¹SQ(pã 7à£ûìX³f ƒe÷ìÙ³¦~лwoïý-Ùî3gÍ¢çŸÇ!ÃÌÇ=zôèÃȽn°|ùrÜúÛßâW7ÝdÜO«÷êիѽ[7ÀÎ;í\—Œ$½¶ÕÝO>úQï&êU«0”¼ç¨gÎÀ9~pÙe¸ð¢‹pÖ9ç P(à—B.¬\µ ‡v˜!‡–×»ws—ƒÅ{c«W¯FŸ>}ÀôÝÙ´ûÊU«pÈPý+ Åbј÷úØvgÌ[GJÜ™<å%“ÿ†„p€O·¬9 ™ÜN£eÞò}z›ªÅ‰LþF¼Gu¹—mÖW^ømǹÍH ÉW+ó}52XÄl“™¹sK¬ˆÜ*Ì.\åM0¤±aë9& (¬ÝEW©}ѧ¯G/ÁãësuyŸ–:ÓO|®E¯^½0ëž{/t @ HýàñýÞ--øå´i(•Jx`î\œ=u*øÓŸ”œÙ÷Þ›`# Ø g²OŸ>X¾bvÝeewépõêÕ ³gÎD1­Ýyìdzgf@ï$!Žª´ôY†d'Ô“ÇN®Cïs\MUh@ ¶j7 ÈÉC€-#νy$—‹uêa}M}ÊÕcdioxâÐ[¡H -ÄW$q<éîØ!õ"ϘèAÜÒ ÉA¡Ô”$¿n9¡<Ì-ÆÃ“µB÷™ÇÖÁ¾Ï=}#,ÝÈð. õ”–=ðÅ™4ŸÑ´œL!LÇ@LÀ€ó*0 lrjË”D ÈHêž²Yà{ H/0öÅ*byà(êó5Èçoõ5?öÊzךŒ2Ê(#“6û .Äe—_Ž+/¿\Ý{ý70zÔ(xà˜n=×_(  tذaxó­·P.—1sÖ,L˜4isU c ßúæ7qÞ…â›'œPó—(Ùz ,X¸íííøím·¼©Sgí0ªµ ÿòŒ5Ê›žÔ_ýÆ7ðð# ŸÏ£gÏžXK‡~8žýûßQ*•ðÐÃwùÏ5n©v¿oÎ|ùøã]ø††ü÷¿ˆûî»/SÓŸï¿;ï´Ž3¦Óz>³î»mmmøíí·wJÆÖ¤Îö“B¡€+V¨#¢‡ †7Þzår³fÏÆ„I“ÔÏNÙô•¯=ü0òùmçMzGðÆÐÖÝcÚˆ|,+ÅæÊ¸ª+óWÅh³ðþžW«O¤ø829‘“Ø™R|jɯWÏ„z×´ 7Ôòt[Ñó4&ÈvÛ‚öPÿ±eió†Æ}´<îßú±úñTÆ“WO§c““çÈ©nqCɘ³E¹fž@«Y ¡å‡»’·ñ<Òí»jޱΠyëHæyQAçCç=³«ëLJ¨ŽŒsÿË}/8 ®¦Mí²éÜ"ógnué{²˜Œ2Ê(#<1@h \yùå8bÄuï’‹.Â÷/» 7mÂ×¾úU#ï#Fà‹Ç? 8mÒ$\yõÕxú™g0`À\ö½-û²µ#8óz£@:D¶ÞW^~9.ùÞ÷ÐÜÜŒÓ&O6x;S§ÎÚ¡µµ?¿áŒ¿¬`SR[\|á…øñÿü¾wÙe`ŒÁI'⪫¯ÆE—\‚þýûãû]Ü.[ªÝ,X€[n¾Ù›ö…Ï&OÆ)'Ÿœ(ã7·ÞŠ¿óŽñVû§¼.½O9é$\pñÅøã=÷àŒï|sÄNx=2¶&u¶ŸÔÏ?H¨Û%]„Ùr…túäɸ⪫ðÌ3Ï ÿ€øÁ÷¿o8n6x•W§OžŒ‹/½ŸÿÂpÖ”)¸çÞ{•Ó%e>ýôÓ0`.åÚ2$Åþ©83:²kïòpâÞ¾$ªÊ36A†k–áOçö7néë‘]3‡)€à”Ç*ÿ³)Ø•¿k»ú°NYivË-e¤sm´0#ûË2‰Ó¹wGUƒÄPÁAõR8ãšÅ/%Ø B;Ñ©ÔèZ”POù¡a6_W£›Ý;½Ñ¹-ó#eôMkÖ®ÅW¿öu<ðç?Õfþ9ŽÇ+ Ò³¨Ös•)'Çë ÉK%Kˆ€(0ŸzË0AF=DwÀÍ;¦„üÎU EŒd³Ò)ò:Ñ BBÒ¸ÅëÚ3Uii•sÊò±+/QÔ×ö>‘[#ÔÖk>o}R–caÚúÉaÁ²<åpî `J GÏê§`P¥†l ä­@_M­¸ÿ"1Ÿ7‘´}šr}¹“l™0÷Ú±ÍÚå„×…€BõË’òjœðË5³Æf”QFÕAU^ŬÁ¼¿=Ð5ïÈ(£ŒL:fÜx\zÉÅ8蓟ČwàøA«ô‘ã°p€3¿#ãs¤ôOñy¶âìM'G–ú'ÖÄy¾ÚH-W;!P`<ƒJŽÙOåv©)LøÇ}úZuqXB”ˆ°Lôl›ÍÈÈ=u0v!ƒˆÆæ)ºVàË&óž6° #»ºqškOŸÝÅu’5üò¬¼-ë7³ ©âw@H[ÍFÏéÉØmöèad¼õáa»;åÔƒBî”â”Oû=ùÂŒ{ÑF§šÚ[½æ©§³Ø,îtkRÍè•#ådâ |yæ'Óž¸‡T3YE½sj,Ežì¡¡÷h±à­]w‹{êg– €ÙïÉ ílŽe³øôï È‚e”QWQPUFeÔtþÔ©¸æšÿÅò+ðñÀ¥—\üA«´m‘íÚJùÒO?«î¼š›ìéÚHÑq5hq1¦·Ÿ<Ç<5?·sÁØ·ò9âÙX™b8˜Db¹N!M5¸h=Àˆ^1Ÿï¤A xšš€:Pg‚Œ–à$Ÿªƒ/¸ =HÂìRú‚{¾©Kn¨äûbýfòP%Ê’ü¶’‡YѳÛmáÈAêÌ 6Q­9Ò¡ú˜ß|1¨a4ò§F8žU“(,Ö|Fßðä>¥È‹È>U¢F@co‚Lû/½ ļ±N Ïä–ä%·/@ÇJBÀîò] áǬ÷ øõ'å&˜C/ìĉ‚Œ2Ê(£ºIÌ5Ù‰Œ2Ú4bÄpŒ1¼6cFš$øfév@‚A„Ðs¤*£+=igÆÄˆso°@;w–r£‹èÈ­w ˜ú›' Ü'{wÊt†ƒN¾H”Ãq¡} ÀÛ ¸;#`Ñ+×LïÙA&£x0ðì絉Vi@uÀÈÜIׇ–ç•ê-7noßN(ååª1­V ÄU:»à—¥ ·up2Ä7ÌúBÌWž–[c¤›ß#>ýÌ_ígÛ†+nO ³wKÛ„6 =ì^rÛѦ‹sH€žª«pÍIåjXåzk»¶€­¥•G/¿»>þÓ"ƒsæv—Ðd€Ïn€ØÐv¹•)õÝP¹!Ðo#`™\#¨çIèìÎ¿Ôøµó:ó‘?·oþò6¡ý®ú8Fh\zçwî ÎåHò$ßÏ¿Š(Færg”QFÛÑŸ~ÍN d”QFÛù€B ’^¥kàÞŸb 톙º Fm< ¤YÈË­á°¦$³B¾]þPKù^°Çc$D‚ö éYKŽhÝÈ “€|§/v*€À]¦Ä IA= Íáêö“0¾ƒy>ÏÌŒw¦X­åmgÿtbw{‡=E¿udÉSŒôÚ-¸[Ÿ=QFmo”2Ê(£yƒ]*0á’YÇs£qÛmv¹7ØGs¥FÚ÷G“}Û‚!eœ[vd °—PKLµ“·åSHò@to Á»ÍèÁ²iQG-éþòjɉY¸cgÍO‚ u)Yk;¿^òÉ÷Ý·o»\KÊn–á+Ї“:K ŽPy*·³ ?§ybÈôpÛ#Ô~Icžž@!³›øÇµ3³(Vð.N¯o¾µ~Ý»fLlé CFe”ÑÖ àðí-[¶ /¾øllkÛòQOtëÞûïúöí»… Ë(£Œþ#¨Æ#¡c£îû xØç«ñ[Ôþ·M‹97ôKŠO),Û¿1ž ù÷Êíõ yð†N³dÔ<°€„‘ˆo„%”“fo8´#n'§)ò°DœâØ+ÕºÜu§h’e§mu3‡qÅíDË6v‘é×ÍÐiw'!Bî³›ú}”l¢ZcÙ²¬=‡¸}’s8ëöætŽ4ÓÒ,ŸGÁ9/ñkŽöôªT²è\žÈ(£Œ>4Dæ¼ï2ðî»ïàùçžCïÞ}°sŸ·Š^7mÂߟy~ò“è×o·­RfFeôDܳ·l B>±lËKΧǻûŒÉΦÙů$iÏÍ,bÖá–p4[rÔÖ/m$‚;·ì“ ÁÒˆðí’ú¿ì©@Ph³•|IÉÓí¯'À£l=ôB6‹m^é8]‡}¼‡^ꈩ„úG o&û üº¯z H^éIE¦FÁì`^ß(ËææZ6 öÒ¹Ïy¿÷·ËöPè½]ýþŒ2Ê(£m‡âù-ø(Á›¯¿Ž~»öCŸ>½Q,·ŠJårMqÙY` £Œ2Úä ¤Û¾MpZ¥ ‡—é—ǹ얓œívö ³ü0,ó=LáÕ#x»Û¹“v{ýOtØEXI®¤Í}™Æ», èÖ3žG2jÛº¤»ßjYÏûNÉ:vð]ÙÄÆI!¯2ú±Ãž~ðr„oj 5íí0øsxç:›ƒ{ú_‚X·‹[xÚ‡YÝ^µ~w®î™Û3Ê(£ŒþCÈ ^L--½ÐÔÔ´Õ”Éçóhié…¶M›¶æ&GFe”‘I‰'sÕ8OH”N06ãˆ<ú'ôŒ­y²ÀS°oƒÌâ÷?6 2Ñ|Ú-`]´Ówª#Ïižk3@Gx7Ô+•ûL›HÁ÷zKëDô$ñ´CBá[…üÆJÀÑué[oXˆ…ħhÓä>Á¼c5(ÏSasxêà_-ª«y»(0Äêè„@EÓÔñ˱–2æœÉÒ­‡9·º…zðÜWnFe”QFù¹B{ŽlnlDCCÃVW¨¡¡ÍÎÏËåcâ'ÁÀyÎ9"ÎÁ£´{M[8ç(•J(•Ë(‹‹E‹E4‹hhhHÿ;í¤r¹‚+W`ÕªÕXµf V¯^ èÝ»7ú´´ OŸÞØiÇP,nwVnn„~ ÛfKPÔÅ}1—Ëu©¼ŒBäß@h|Ö· H…äMÓùùÓ›Á^C·úFUmAjï°Öš<ÛµžSz—_î¥ú#&Ʊd rÃà‹Bh]6~%Û&lc³-²ù$¦˜Ôè òL¤ß8kškÿtíÖU ?QIÞŸfM×\OjÙç$Ÿü4öKãeÇÿ3Ê(£Œj“ós…Wi»"øû[kñæÊ¼¿!B%bÈåshÌsìÜ£€A}ñ‰=À«ÕÍ^,X.‡r¹„b±a³‚ ›ÚÛ±fÍTªUð(Á .Êh¹ ùÓ‚Ø$2Ák2oêv³lÑÕ0+M°%œ7ÙÆ†]}m*ìëãKë¹ÐÂ×ý’^¢ÉiêRŸ¬v®&—f¯´ãÄ<µwþkÊO8þoûr¾¹7£Œ2Ê(£0ѵ½®­ß÷W¬Äšu°±½½KéÖÔ„–ž=°ËN›÷rCÆþ½º?›÷† è‡O Þ û67 ©XP®T±¾½„Åÿ^ƒû½SÛ iiجÛb±ˆÖ£[·î(utÔ?Š"¬Y³m7¢R© Åš‹ hjŠOL´·w T.¡R® R®`ÅŠèÞ­ZZZºlw¸T*á©§ŸÆk¯¿¶¶6@Ïž=ѯ_?ì¶ÛnàœãÝwßÅÊ•+±nÝ:¬_¿óy{ŒC>ó™Í>URüûshØe´Q×Δá 0†BK 6ýå1äÆŒÞ,}:Cé ï¾÷.FŽ9 QÔ5nv.ÇðÈüyY``!ï/x@8“o§Ù0Èöz'tyÚ2“|œÔ‰àAÚ_M0‚ÞƒÁš‘›{Ë¡Ù=P ÑdñE¶£ÄF€ÀzvÚ=þ/¿XåÊ|¤Îu͉)hkí£¦ïe\œèð ñ·½ô±Öî㑩ʨâ@¿7HæöSgñÍÄóf~ËÒ©OeÂé“] úk74ЖêÌ=Ø„ñ>ª…PÙy³ @Fe”QgÉ $Oº«Ö®ÃرÇ`§wV?7l­ñnjûÀŠåËñÀ÷é“Û¼‰û¯Ä„cFæ&¼³ªe 5r²kì¶cühîR²{#¾6twpÞ¹à@±XD©Ôÿí¨/PEÞ{ÿ}”ÊeTÊtëÖ }úôACCòù}pñ•?ÃSϾ°Yò©ãŠ ¿ýÿÙûò8;Šjÿoußuö%™If2™„$0YÔ‚ ¨(âü‰ ˆ ¨àÊ{úžŠ( È&Š ˆ‘Eö°dC²ï“Ì–™¹3÷ÞÞê÷G¬ýçm IDAToUÕÕw™,¨ïçsçvWW:UÝ÷Îýžsêr£c»$ç׋ÿ®5ðÅÓŽÂæþ6÷ Këå `hÌ@*¡áÃGÍÆïŸü7ŠÿX‹O;}\Ë ôDFÑ€ž¨~½ýÀà Äã8˜8q"ê‘H$¡išëAô¬å”RPJ‘H$ÐÑÑ‘‘aôööÁ &1¡u×"-ž|êiôöõ¡X,âÄOļyóÐÔÔ„d2‰D"áéBà8lÛFCCÎ<óL,]º<ðzûúðäSOãÝG/·¦a@Ïå@m7j¢@)rÍÍHŒŽ¢É˵0 ë Z½:; ˜55¨BÆûѯiLoéÃÞÆxŸ˲°aÃ@ssKɺ«V­êÉŽ;;wÏÒ…}ò<¢Æé÷Xd;C¦ŽP=ÖL ?¬´‚úõ'<1+ñ¼2²ÈåŒ dG½Èr¯4 ª0oB=Ê-lú®eF— r•õ–J¡…!nä\ßÒБÝg<•‘ýJÿ£ÆFoˆòcdËçØ›ŸÐF£3ï’'ᡤ_ÿþ“uB™òñWö Ëi™I$T~¼†DZÙIer„üvbtƒ"ý û,8&Sî«Ú¶mX–§_xŸ<óT·ÐlêÀq8¶›:°,ŽmÁ´X† Ã2`šЦËpÉÞÓ/¼˲a{dOD%ÿ6VoÂu®ÁWÎ:Ë7 q×Î}ÏLÀ¯ZüÏÊÀÐÆ"Ž>h*~vÏSxÇìVÌœT}øu2™‚iÝuåU´Ëc$7 Ó4ÑÖֆƦ&$ hšË2‘J¥…\?ÄÑ@4 ѰmÛ6ŒäF‘ÍÖ ¦f|žöuë7`ÅÊW188ˆ÷½ï}X¸p!J¥H$|ض´—rÁ‚H$¸ûî»±b嫘ÖÝéÓº«W‚R8…9: ê8°$Ž: Íž £XÄŽ»ïÍfqà‡? Øøûßccè>õT¤3l~õUž~:=•‚㸆”½1Pý³@áêêÜgÏO8¶žìز,öç«Â›•üª¥v4ˆ—_æ‹-P¦?ÁË‘T¹³˜×‘ý>åD!I'\qâdúl]´ È>¯Ô3PT°•¥Ø>nN8š¹/})÷§Ô=æçµ„ÑF µ¶-3Ö0P^ŠKn| '½ëlßYŒüï¬Oë8 ³@¨ƒ±"_aco'9ßò~ÿµ£¡ëÕ‘ÉDÒõ'ªÈÐï8úúa[jkjÐØØpMÓ088MÓ0aÂèºîµ"Ðu MsØ74Ô#72‚ÑÑQôô#“é¨zIaxô±Ç‘Ëå0sæLzè¡hllD*•‚eYÐ4 Žã ™tÃÜÇÆÆ`4MCMM 4MÃüùó±|ùr¬Zµ >ö8:;&+߀íØÀè¨10g¦Ìží&:´m˜ÃèknFÖ[fÎd0º};êS)8‰:8ë6m‚óï#‘ÍÂç²]ÅxžÀ%ö†aìü% røäÆ’Û=¹žå¯§'¯â¤b[ÁS-\æÙwX)zïEó­h[¾hàGt|åŒuÄëDÖžF\ÝøùÚC†¡@¬"ý o&$ï\ÿÍ݈7\{pÈõÐÛŽǦpŽãÀô ¦eÂ2m¦Ã4aE¦b1$B¦1P¼¸;­$šêê1VŒz[G ÜøÀJPJ±}gº%Ï5é 4ƒ‡_ÚŒí—Õ X,Âð"&&Lœ€d2üæÃCäI“ÐÐÐÀ%áÑu”“&OšÕk`&ŠÅb@œ+ÅÖm=wÜqhjjB:†a¸ë®»ÐÛÛ‹ƒ>§vàþûïÇâÅ‹144„Ÿýìghhh€ã88ýôÓñ£ýغ­Óº§V='6¥°ÇÆ@)ŔîëÐ5 kï¸ÆÐNØ…ö`nœbÆÐNl¸óNLÿô§A)ÅÄ… ±õ¥—*`¿Á<3gÎØ­ò–/}i·ÊSx3‚VÄI… /Îè/CªL¥¸•ã!MÒV>"Bê!Ž$Ä%Ñí ¾—¶rÊðs?ˆ5#æFáwܣݼl ”|´Ê>|‚®qTvÊMGtÂJ…d ÉrNBc[5Ï#͵‰ŠÊþ‘ÈAxRêsYR㔂‚‚‚›þ¿ª\œ–eÁ4]Ã@.7ê•9®À²aZ6,Ë„i9Ávw–íÀ²-ض·Ô€Ù Àò¶Å^X½ ÈÅ${£¾¼= å³¢ÿóE›ë±dmï^1 ŠEPê •L!•JCÓˆ àþ°p Z0- k×®CSc#¦tu!‘Ѓ蚦A×u¤3i ÆaØÖÓƒb±ˆ‰'¢½½=È)à8 ÃÀðð0òù|PŸ‚¡¡!ô÷÷CÓ4$“I¤ÓiÔÖÖbòäÉØ¼y3¶õŒÏ0àP gl ‰Ž4´´@×u /_Ž‘×^…®Ä Âì‰1ÍÅÈk+1²bjçÌA}s3HSìbN•†þþ~MCKssäÚÀà ¨ã uó8”ÃóÇlw7š-Bó¢EÈNŸ^Q»üºu|ì1 >öò6`áâÅ{TO…·¨œ‰†×c¶«Ô P©‚í[K0¹‡^ˆYðÄÄG(ÄeCÔ«¬Z¼×˜ŠzTOÄ\ÏuL»]Lþ¶+(éÉ/«WéyˆÈö£E*Ы2ï|ð§DуOƒ]«Ž– €¿Mïî̦O¼l–"Á÷ó©Ìý 2T½” ?æ& ,x^z—ÈÚž!À†i[Á±mÛ°lÇ5 8Çæþ§çóùqG ,]Û‹tc7òFÔ°Ñ5üöâEžÎþï@OÈÃí³é ^Y¿m\:T‹b¡Çvªs÷»CmÛ[vá-±èíëÅÐ𺻻ÑÔÔ€xÆ Ùlc£c(ªß*qÛ¶†‰'¢X,¶í`9‚¿û€â><<Œ8ŽB’É$R©º»»±víZlÛÖ3®9±)…], ¾¥%ˆžÈ½º º5Š„hv>0iv k°Ü«ËÐpÐAÐuÓ§#÷ò˰ìê–ÜxÓÍØ¸i¾uÙ¥hok Ê·ïØÿúÁ1µ« _ôµq«Rd»»±õÖ[±õÖ[Ñz 8øÎ;¡×Õ•lcçrXyþùèðA@Ç'>±GuTPÞ]Ièruùv…ÄÈWðtIž› šJ ˜!Â>© û”¨dÈ¢<¯O’7O÷]$ž¥tßÒW·ñ`:ÊH¯•¢":í½UF…8Tµ8õî EÃ@Á0P,zhÂ0Lo Ë ²ÿÙãX½métù¢Í¿ ƒyÿ{ÏR$tɤŽQ“"oiÈ›yà ê Ùtk¶ •ïp7 àyµ3™ ˆGÄ ³Ò0 FÑ[{î®?Ïç X½z Ö¯ßÛ¶ƒÝÚÚ:8”¢P‡a §¦i¢££étÚÓÃÝ}`Íš5X½z5FFF‚ú¶mcpp;vì¥4ˆZÐu³fÍ‚išØÖ3Ã¥p oܧX!®ÑÃBÂÌ!aæ Yù úD·‹È¤€l6jæCÂŽçžÃÒ®‡C2? y|æ3çÀ0 üï•WãÁÿ^y ÃÀg>sNõcªÍ‹ÂšßùβFÐëêÐüÎwJe((ìû ç²º— …¢tý µ!»äPÆÃím9+Ó¯”LJ)œ˜1Uú /ìÕWåúQDïŸÌMüüÈæÒq&²$~^ǃjì²1íÒ3óÚû…·BÃ@„ʶì`K¸BÑ@¡h Xð І‰¢iÂ0¨˶Ac’™† Û_Ä`X@Þ0×E‘· ò4—7‡ûÂYy‡ H éòEÏà^Y¿÷?·Î8£ªÖ™ù‡.û¡‘/ä1<<ŒÁÁÚ‰B¡Ó4à86ä?ÊýÀ”ÃÞÃ}¥ëׯÇóÏ?Í›7‡zåóÂиóC¸¡ãŒ/ñŸ``å lê©P^: cõK°7.¶­ r[8—aôé¿aà;QÈõó[·€èì*ÝOžÔŽK/½ ½½½¸êçWc$—ÃU?¿½½½¸ôÒË0yRû¸ÆT š-Bë '`æå—cõw¾ƒu?ùIÙ6ë~ò¬þÎw0óòËÑz Ê0 ðA•ähœ‡²ZÄ’µ(\¾<þX„H¿Žã³É7ü+Œš‹sÅsEâ£,ª¹_q¨”À—˜ÁWPPPPØÇÀüïª.Ç€m뽋^¨¹eZÞrÛÛ¡ ܺ°œÏÆ´LXöø"ºZëñÚÆmÈÔÔ!™ÐJeH§NgLës`š&Цíc6tËÕqÓŽaØF° À*ÔBWKz\:T‹t:…b±€B¾Ú½Nà]ÝKFH@J¥0sæL´´¸ûÜû?hÆÆF™Õ¢½­ Û¶mÖ-["?’t]GMM ³+‚û£+‘H ¦¦†“C)Åš5k@áBñ«C¢k|þiÀ3.4{oü;‡á<»úýsÜ’KþŽ µa57 õ¤Ó=v¾ð ´„§ÊŸ•†QÄûÏÄ¿ø%\}õÏqþ_œþ8`ÿ™(0yö²Ó§‡Ët)ï>—Bª¥3ðL¿øbLÍå*Š2PPPˆCõÆ»7¯B‰~J.¨.ì~O¡=ö–n¥ÖÛ+((((((„ð •ýƒ¶-–iáÀý§cùkëv©ã÷Ÿ†B¾0îˆYMXúÊ0FL Г@’¸£IH8hË8Èår.ØX?` Ø ¥Bsus³&7îÒX*E&ÁAÑ(Þ?Ï!Ñ4$ôh(&µOÂÌY3ƒmY¯ÅØØ!Ȥ3Uë1iR;´¥z¼$„¶í/õ H§Óhnn–nÂÃÚÚZ477~›µk×BÓ4L§wÝIh0ûzÐûÈè8é44Nê@ÝE?…ö VËþû¿µ)ÀJd‘9ïGhhïô=ò¬þíÐjù½¥+D!ŸÇ¢w½ëÖ­Ã}÷Ý‹SN9‹ÞõNŒæFÊ7ÞMð‰ýô‹/®¨~ç9áePPx}QY^…×û ùÝWôPPPPPPPÀãP|Ä@™ÿݶ—ï’óÏFÚÛ7]Óܵæî»Æm¿ç¯ýóÚ^d¦mÛzâ“–Ñeþ´6ܳ¤ÐÓ€®»ÆD H¦Ý÷#WOÉ  ™ÌÖ@Ž; Ã[qðô©Uÿ°³L ©t –iUÜ6“N” X(´,w'B¡ë®q@×4$nR¿ýö› Zù¹ ŽMaÛÆFó%žÌêtï˜4 šæFFFÐÔÔD‚ÔÕÕ¡µµ5²ÓAcc£wŸ5PJaš&òù<Ö­[MÓÐ1iRõ?Ž)àâ&†Ô€Õ?ù.&½ëXšZtû>ljëÄÖ¿^‡ìæ—@)ÅhÇ<¤Þ{.¦´À5PŒŽ`ÍO¿]hÒ‹GtæèÈÎù̧qüñÇ£{j†«j?žg­g{^ÿu?ù R--ñ—a˯ c`Ó/¾8hÈT¿¿ªDÕ»˜ã ý/%s<8ã˜Ù¸öþ—°–gH¸=PŠt O&&ŠŽ $<í8€cÆÚRyœqÌìªû7MÉT¦i”¯ì!“É ‘ÐQ,ر};¦L邦9Ð4×X¡ë:ÚÚÚÐÕÕ…dR°ÙÐ0ÉÒ¶­Û`YÒé2™ê#º¦LA]]z{{qß}÷áSŸúÒé4²Ù,~úÓŸgøà?ˆO<”R466ºK4ŠEÜ}÷ÝÈår˜8q"º¦L©ZÀ_Jà†âæ7¯Ç«_ý8æþìvèz“8ÅiW ŸÏÃ0 LH&‘ÍfÝä‡FÿþêÇQܲ¨NàìBdêÐà Ú&´VmÆ÷,øÈ¯[‡•çŸæw¾ÓÍðƒ”mc `õe—¶Á'žÀœ«¯®x›Cû¬ÌÍØØPÞÞ^7üß'a”D ¥ôÊà½7 ž Çžb`` õãR<™ÐðãsÆg®zö”…€–ð"HÃÄËß]hÈhØvå;1ù›/£¨'ǰtè;VàÇdÌV†¥`™’)ÏK\!4MC{[6oÙŠ¡¡!444¢©©„¸FÎÎNd2Y.‰’élÛF.7‚¾¾^èzímmÁ6ƒÕ NãÔ“OÂoï¸K–,Á!‡‚Ã; 𦡡¡Éd’[ÿY[[‹l6ËE ¬X±?ü0jkkqêÉ'qKªoðŸÏ>†Uç¼Ý—\ôÜÌމD𦡦& ýßÏcí_ÇΕ¯NrMßõu¾Æ8vxÆ÷,ø|ì1ô?ø ú|3/¿¼¢åÓ/¾°m¬þÎwÊ0           P5¼% Œ@.Ç«º:;ðô¿žBÿ@õ^UZ[š1uJç¸Û9·'2÷­\t ÐtZGÿbƒE@t€Z02®CÓÝ÷žåxïÛ¦à¨Ç׿iH¥2U{‰ëêêÐØÐ€CCغu+4 ¡¡”Éd Ô_âàÁp#r¹¬_¿𦣱¡u»°¾|ÎìÙ8äàùxaÉ‹¸ë®»L&qÈ!‡Àq¤Ói$“I.¡mÛA¤ÀŠ+pÍ5× “ÉàƒçcÎìê#.‚ñy†Ûq9l]û6~å44Ï=u‡¿5íSÝeÛ7bôÙG0¸r9Fó^à‡÷Òtì•`2Œ÷Y\R?ñDEÉí\ƒO<ÁÉè8ûìªûVPPPPPPPPPPxë‚õí'â/E1oîl̛˓ÀCÈŽáɧŸÅ¦M›¤íºººðŽ#ÞŽl&‰­å³®W¢‹Ÿ|îhX×<‚_y Žùv`a-h"ƒ¥#Y ™us˜E •Œ<ðÒvhÚÓ8aþd\ñ¹c*îG„iH¦“¬NF[ÛDŒåÇ`6lØ€ææ&ttt@×A~”RØŽ­[·¢¿¯š¦!•J¡­mâ¸u÷qÊÉ'aý†èïïÇ/ùKqÄøèG?Šºº:¤R)èº䊰mù|¿ûÝïððÃ#›Í¢µµ§œ|Ò.èAAu$¡ÁvË, 0L ˜†ÿ½ ƺeHènjÓŠP4Ý:¦å¶±m ©iðbRvy^ªÅøž·^~Ãt|âh^´Í‹U”LP¯«Ãœ«¯Æàcað±Çß°‘©’ (((((((((((T‡ªr ˆX½nV­[–æÌž}æÍ;Èó4‡b]O³þCèÙ¾³¦OÃÌéÝ»ªw]×ðóóÇ?_Þ„‹õ(v®èæhhš:݈¡­Àp`Ð\Û‡Ÿs Ž>¸k—ú¥Žãî àm±W­ÎÓº»±}Çv `pçN  ¦&‹ššÚ `ttccc…eÛÐu õhok‡®W¿„@D6“Á—Îûî½ÿ~¼øÒËxî¹ç°lÙ2L›6 3fÌÀBV¯^5kÖ`íÚµEMM ÞvÈÁ8õä“‘GŽƒš†Æ9"Yc ‘I “rÓ@ X) Ÿ¬௖pÀ´Ó¨ è6Üc­­é®®°ò^Äxž…„÷Y¸xñ¸úÌNŸŽìôé\¤@Bߥ³‚‚‚‚‚‚‚‚‚‚Â[äòß\JOxûIh¢Ð’ª—–,Á¤IíH$âÉÆ“ÏûÞƒNí;j$—ÃöíÛaš³}¡ïõ% Ä}%“ ´··£~mO·b嫸ó½÷açÐP°¡ŸR×õàÕÔØˆ÷Ÿz æÎÿòÖÀVýöô­|5ØgšõySá]¢ihš6 óY$Z*Hy}1<2‚m[·ÁvÆ—|S„®é˜Ü1 õãËÙ¡          ðÖ‚ Ãd<û7yÄ€¦ià2àÅà‡/ÜíʦipªôƧS |á‡çþÞɤ‚±¼^¨¯«CmM òù<ò… … 7 ^&“F&“A6“ ²ñï)Ì33ö›Ž 7bó–­Ø²e+¶xFŸÎŽtvv`Jgº§Nw¢A--˜sþ—Ýp€]A…Ï쾂†úzÔͪݭ2÷äó¡          ðæ…Ô0 ë:jkkáн¿^Ù¡uuuÐt½jÀˆ}Ù ÀBÓ4ÔÖÖ¢¶v÷Åj‘N§±ÿ¬YØÖ¬½Û±»-ÃÞís€"ò û\ÀÇÿ}3€C)ºº»±uó&$t}¯ÇqP(ÐÕÝ Ç¡*š‚‚‚‚‚‚‚‚‚‚‚‚‚†4bÀ¶m457#™J¡w{,Ó Âò÷!Ðõº÷›ššZòc{´?…Ã¥ù±1d2̘uÈ^ˆ p# £¨Œ { „uÙ9£X„Q,¾z)((((((((((((((ì)PäoWÙÏÞÂà–ÜÔ; „„¼à¼2ßšÀÖñ„÷ < Cˆn@JÜ÷˜ ¤{ÚSIs–QmÇ–S±_.¶e^êDô¤¼ü¸þ(Ü@ ^'íƒí‹NÌX"çlßBÿà÷ÄJúåeIÿ¾\FW ^'ZRgnŽ)£#ô‹»L;ê ŠôÃÖaç„Ô{m'¼7<¢O$¥B1 ñ¹– îD yB#>÷G´}T «P\¥° ~l’B©œhm×¼M&PAAAAAAAAAAa/â?s†–¸k>ùgŒD0ÈŽÙ6Á_"¯ï„á ¯ð Oycs=xgô£4Ô%LBÒèBº"¯ ô¢à T”Iy=ƒ¶‚‚<©÷ç•åvÄkÀêÂéFBÃ~#èâëÃ÷ãþ ){¯(ܾü«š§?hTž Ä“ïÊô{"A¯ ˆŒ“ë[ìCÂiƒb¶®“‚‰(ÅÚå×ãk7”Ÿ3Q÷àÆwéªÌÿc6Ìqh$¢ >i§42‡¢ñÔ]>ƨJþÓWÁ„1Z°F(B£5â4,ËíùIá/ùŸ¨Øx”3ù÷‹Óž3sÅ f²›Sºs5PJñꫯ–¦          °»ÁE{‡‘ˆ€ØpâòÐà%*` „0íBŸtt)A”ûo`¼í\£3G/=VEYãC9Õëå·c tdÅcxÂ. %¬ TàH"oâP7iô3_a¹Œ»qÄ|ÿNQñ#_,âj±ú3E2vMÂ9Ñ* ­g9d ó—òk™É»ªÏlC™”o1ÄDÍMÔ·â0ã†í(FÂ|ð(¯xø©ó§,|(xõbŒ‘烹k’g-Ö±b!,ðNmÛ†ã8e¦          °»A%üJº]!Ëú}£@p‰ðU#Xƒ€G¬HèqŒpLA p^ꆭsh¦!…kœÞ Gõµ  bû‰, üuÑ ç••;R¹ ù ¢À¥ðçœzsPYñ²XãG`h)åeÚûˆTeù¤À3©pM½áOˆÛ„rò"}E 1z†z“çÎ¥w7üØxß`Ec{žš¸Ž¹ËÁHä×¹{3ù²n+¸OÁMå 3Ñ™ ‡cœ²ÁÒ‚J@IÏ€2 ((((((((((¼^ýO¼³šK6èŸ3Ç,•¯»ï¾w‘rd(¸±„/i"±FHr‰X( ‰áx+1 F.G4ãéþ5†“ñDšµÄx e[ßÁx¶~Á–1Õ¢sFwŸ¸—°.Dy!c‘ÌCз o oõeÓД#óÐ}fü¼(¯`øò/(KuŸ1q½…WG…í'®NŽLQÂ$]äàëÆ<7Ü5¡ž/Ïí‰V`àUŠä‡ò±”z>s©œ…+ÆÀÀÒé4>x>t]îEøÎ¶çç@Ó4,_¾¹\®„ •âž{îœ~úéo¹ ãËü£hòÁJ„Á§¥ IDAT²sf16wõ€ –ØõÛ ± –¤KGŽ¡ŠdŸMHèV!œç9"&†Ô±ËDRÄòÓXo±06É¡\n0DÆÍ9ýdrˆ,ûkìðm‚$¢³PÑü~±†.Á£dr½Åî©/ÛSˆh„#Šœ"ƈÀ$™€4‹–a Üø¤“#7ÕÄc`ÛFˆ¶h8áî¥ü9 JüXˆ7áš×I,·Œ3왢)ceâv Ç îi]] £ˆ ׺Q2ŽÇvÜw‡ÂqØÂùØØöÛoêëë1227…}üãK^ÿà?¸—4á! 1Ý—å*((((T‡’K ¸ßþ Ä"¼‚sâ,¯Lb Ógå1œ…+“‘0ÖKîÓ † 08/k\ˆé3ðhÄX @Þ1ä<!ò@)„„›UJh&5$$ÆRØ10Ë8~H|›7`qiA,;”p^1J‚ëV0–peòÎté€1IU‹1fHK "d‹Ôw…HwÆTЇJrFÂ_/•"Oø@Ç??Œ.‚ZÜ| Õ\Y¥„ù~I©9àš¹ØˆÇq0::Šá¡aPJaÛÔ38œQÀ²läóy cxx55µèììTKÞ°xÿûßÿùÏŽ”ímìé¾Õ÷µ‚‚‚¾ÀéŠð|$Ç€HüÅ2–XÇ„z¦>wÌxP¹RÈŒà9·?Î8 \b®S攄ç~g„!0.©÷†äXB´8Ï„ÖÖVœvÚiAù/~ñ œqÆhmmÅæÍ›ñ›ßü3fÌÀÉ'ŸŒÚÚZlذ×^{-V¯^ÍÉ;õÔS¹ó«®º ùÈG0qâDlÚ´ ×^{-·³Ìûßÿ~œ{î¹ ”bçÎxöÙgñë_ÿù|^:6…7Üpƒ´ü³ŸýlÕ2ü6⹈Ø>ˆp"3å~&tÂ%>Z€H Üq„ ç„§Q fˆ”˜5]FÞSwbÈh. Üž'È[¡!JPÿ¬š¾7â•ÆÂr&ùâ"ë°ö­êæ! ŒÎÜufn]A€g`p—l0ÊsD:4øcÔ¤Ññv”ˆq‡";ÛîóC9Ë:žCkƒhpaŸ7B_Úq9[Çöä?ƒÒŠ”Ñ›6² n~‚.xËÙ%xK„ý@¥Ñ"þŽ ‘íe–,æ÷Zål¾.¬a€R Ûr`F¸”À{™¦‰¡!7BÀ²,W3A¾q@AAAáÍÿ;íä“OÆ¿øE<òÈ#¸ä’Kpúé§ã¼ó΃eYøÛßþƵ™1c¾ð…/`tt”+Ÿ={6.¸àtÐAøö·¿ï~÷»X¼x1>ÿùÏãÀÄw¾ó\xá…øÂ¾ ÕÁÇüùóñ•¯| .ÄÅ_Œ .¸çw^p=›ÍâóŸÿWw$wDÐŽ”4žÈ¤ú7Af£ìGŒ,áŽâÕ¸ä’2ËûiŽxþ9Ä“íZ¨Üû~rƒœlué0@h8qÏû«¯¾Š;wçõõuhjjÆG‰Í›7áÙgŸÅÚµëà8ét:ˆ °m;0 8ŽƒÞÞ^lÙ²EÞ‰‚‚‚ÂþwÚäÉ“·Ür w½³³3ò½·téR©¬W^y%RöòË/s皦Eä‰ç¥ÚøÑsæÌACC4ML˜0¡¬\²ïÇ]ýÎ,Õž7:¸¿ÿ¥>‰ ü?>¹gH>wŒ°-Q F°}°´Æç;AuÁ+Ì/«Ñßi£ÞÉÚ4P@¼@Žã@Ó4$‰@ŸB¡€éu ØöìüÎíÌ`U¾¯Œ¤°=¯³S$ÌKS–Š±Äž„DˆŽ-NpÉ{\#ÁõÌÊ"¼‘EÊΓ~>yGýŠe œ±bõ(Á•À†‚"\"!ªÛŽY$"X6XÃe dÉcµ“Ì?¿¥+ÄŸKTH£íxM$©cîO\`H)㊴Ve 88Å+¯¼‚žžœrÊ©8óÌâg?û,Ër „À¶mX–Ã0T8ª‚‚›;vìÀ”)SpôÑGcûöí¯·:±¸òÊ+ÑÙÙ‰óÎ;O<ñR©–,YÞÌxôÑG¥åÇsÌë®Ç£>Z•.#¦€¸V™KæÅ2Ñ Û¯Ž0ÅA]Áðàù.#áËÜk>ߊIwH³‰‰zV”Rh„€  N¾nÝ:¬[·===C&“A}}=öÛo?ì?kÒ™Œ;1‰`YÐ`afjudðÌP 6ÒØÓB*NC=ÑP~;7îŠ?P¡þ¢ÑCœ‹ÒüŽÞÚ8ϼ;ï Q”È㊣|9$Ò¼I 8 Á€Cb̪S27¿½>!ú ¢1 >* :nêyÇ™P‰oó‘"ÿeT‹-åþA»rÙüå"䱯I\axçÝä„þçï3´+!T–P±lÛ´iÓ°hÑÑÈårxòÉ'±páBLš4 ¦i⥗^Âàà À¦i ”Ê—((((¼IpË-·àÒK/Å%—\‚ÿüÏÿ„iš8ôÐCqöÙgãœsÎy½Õ à;WFFFN§ñ•¯|åuÖHAAAá‡8Cµð Ëó½ï"xO©¸|€}'b溘l0ˆ" Â9s‘mAv¨8ï-%f5Ó³´’QPdž¦éA.]×Q,ZX±|9î¹ç¼ðÂôöõ"7’ƒi™Ð5™L&LÀÌY3qÚi§á¸ãŽƒ®ëÐ4 „èº˶pXÝNÌ®Ëà¯v¶ô€àG³È JS¾8nk:ß``‘ø1m㊠ž²Y}žÆp5–I³DõäKEh¨§_¸'E²7ahÄ!‚ܨB4!QÏèC™¨.c¨(ËO¡’ËRþÌ2‡1ê¹ù„Z2j€­P¶"LÓÄÛÞö6œzê©Á@ á£)ü$„”R í¶°+…·2¬{TNâÝëòÆDr‘ˆ%‘Èþb,i£<µ®{ïÓj Úƒ7…œ&D ¬\¹?üá±|ùrPJ1þ||õ«_EGG¶nÝŠÛo¿‹ZŒÖÖV|î¼ÏáðÃGOOî»ï>Ü{ï½X¶lþûþ---8ôÐCƒdg„hH$ÜDhN>0¥7¯Í¸;°ÓË…bh/áÇîÍN@È$¼œkëw½Æ¬ÑK$‰b_>h¤²_ßUž½gŒ ‚Ôñüµ”¦¡~,)?Ô û\xÔ«GÙ9dh¼_—í°=ÅŸÔ²»(x=Ä“ñ†®žÿ‡Åå0à.òóy$â8¼A¹ûD˜ú±æ‡’{7ºÀ5×\ƒºº:PJ9#'Y:@A¡PP®v>G‘ïJÀVŒ1 øbXæÈV-ÙŽ0$IhÇ‘_Ÿ@ öîZ‡7Œ‚€Â¶.¬_¿]tV¯^ Ó0ÐÜÜŒóÎ;Çs,ŠFm'¢»»[·nÅI'„O~ò“ „ «« ³gÏFOOžyæ¬_·—]v~úÓŸâ ƒ‚mÛf½5„ï§á¦U)é8C’/!O2ö͞˼Øà ¯Ln ~ÇuËÕõ9+öUª“?¾[Âx܃~KE”q2ûÆÂäQ B…øH¹þ•Vå¢+"—iÏ0hþY® ’€„Ÿ”’‰öbÆDuˆ$¾©§JÏ‹LLÅ‘ñ°mË–-ãÊJCÔU…ÝŠXÀ̛^ þ§å~ªû¤Ð_> 㲤r"=˜ÑHqhÝ(ˈ]סëî6‚𦡧§W\q¶÷ô`Ò¤Iضu+¦L™‚  h‘L&ÑØØˆl6‹Ï~ö³ØÿýA -¡¡¶¶©d üàñì³Ï‚RŠ5kÖàW7ü —}ë2´¶¶D’§Ù¶¤ÕØ0–ˆ‡€ÊJvS(É È6|Á¶Ž ‡7¸~ðr\Öï+R1sÕÑÇ— ÄäswÁÐ!¥Œ¬LEŸ†ËbôC©ñŠD[°Ê#:ïe{羑Œ–0xD£T´žü¾ðÉ.I¬Ò% Al ‰…IftŠ^ k°†ôôô ¹¥MMM.ñO§–aàÐC ¹¹ÙlÉT z"Ë01s¦›tв,8Žƒ‡yGu$Î<óÌ`³«;…¦kHNž4Š¿ô4`˨dFˆp"dj(爤[v7H ½ˆrž`¦N©¨6 ¡ŽŒ%ø%Ôa¯×gp¦#qz¨×¡¾ñ…×ËvàJæZÎÛÃÞã–Ïæ^GŒ\†ÿÿs%|ŽƒEɰŠ@ËØÀ31y:G—¿Ä=ËŒ¥ÑC¡PÕTPPPPPPPPPPØË ¬W—]’¶BPHâ9ãIëPð[ÊȇA(ªok20A ¤HÓ´ Î–­[pß}÷ámo{ÇÁ¦M›`Û6†‡‡AmŠþÜóÇ{°`Áy䑨¸q£»®ûÛßÐÔÜŒ£Ž: CÃÃA‚3P`xx¿øÅ/pÌ1Ç ­­-ôfjn¤B2•FÂÉãìý’¸bE Šaªƒø9b™nàˆ é 751$\p^K ;ñH¸Ã Õyb»cÉŸTÑøæ¾§½´GZБgµqŒ[Ú·h‹ š9/v žg^2’Øžeãg:¯$wôsŸüsny>Ü@féõÕc#vJ)ÇWJÉ# PYô€Ê           ðúÃÿÍžFÜþ!åˢğkæ–ÑŒø•Ã@ÐdF?Z )I1«6ˤ šÉ\®ixà‹E´´´`Íš5„ešØ¶u+^Yú2–¼ø"î»ï>¬_¿--ÍøÃÝw¡xÊ©p@på•WaÊ”)˜Ô> >ð@°cà6oÞŒ;î¸\p4Mã"ü­Ôôü(æ5¥ð\¹Ô DÊž¨@ËzÕ…¹â3ÒóceI<þ) ®3d4®™¸ãÚ±F&1ºyˆ‚:ñÎìã–=%çMˆXð=ÞÜ®ÁÖ™þèJ+õ¬—š.:€ú’b(³_×ׇ1¸Í)D#IÉ$…Bô«buPbƒ9ŠŒ±:€ŸKé3ÇY-PPPPPPPPPPØçˆÏ¢?ìãœÑ!ïr 0 dœŠÛoÞ{_8Á‚iZÁ–„^„@×uŒŽŽâ/ùZZZ±cÇlÛ¶ ÃÃÃH$“(y<ø—_¡¶~"²Ù Z›RÐÿˆÏ}p­­á…µ3¡i&¶6`Å3Ä’ç…îïrÀxgœqººº`Û64Mƒã¸[%&“I†yucxn !BÄ1–&ýò«„0ž¨¼/_d©Ä|lѶQ¸t­¼Ì_Šè³}W`áI=až%\£»½%«>ј:àëÇlbD=óßg„•€<7ƒ¤*aÆèÊÄ”H\õ%#d*’`¯’ Å<‘Ò’Ñ!Ë–¾TRW…Ý‹gŸyŸ9÷KøŸç ^–w»§ÐBg¿ö±wþH`(˜4ñîÉ6ÙæêÅå'™PŸT…uy’T÷£5JzÖ!—Ñyfûð•’‘]÷~ !$¢÷Ÿ3NHÈ£P©!yP¸úùd£Q‚ËF˜yâ¼ØQB<¼Ä‰G¡eQ¬®@ÃTÕM*k„èá¦GïûÀ”Üô î9JëÑè8|ììïTAAAAAAAAAAa·béË/ %îtM¬f/—U'ˆI•Á¶¡¡ã]|9Þ+î:0½ÆÂŠåK12’ úðwÓ0ñÐâ‡Ëå°jÕj¬_¿5 ßúŠž[ÀÁû;¨ÍÚ¨¯7ð®C Lœ¨!ÓœÉ6B«m@:mãØÞ¶_5))>wŠ…[¾já?…L7ŸÏã_O>‰¾Þ^$‰ "$ PJa™,ÃæÍÓ9:¡ÞXÜ‹Ä硾1Å¿ €ã ÷½ËBlSñšLrXãöjÜ¢±`ûÑŸðž|i~½8] &¯‚‡3¦¯òÛrºý¦+"é–€)—èÍU ‡XjŠ%ý°MŒâìçC+ß/ ô)7}ŒÚ¥JêŵWPPPPPPPPPPØÉ1 ûÝÎz^I‰úŒ6R+ ÑöJI´nœÃ²;[Äíü š¦aÎ치;wº¦v!™HÔM:¸rÅJ ˜†M×A4‚Ú 04¬a]O‡Íu## µ5-ÅAÔ$Æ™`€  Aà+7gИµqÈ4/2€¸^Ø¥K—aë¶mhkor øð—Ì®Ëcm>ƒM² ÊÁŸ#æÄ…²»ŽÞÒj"™[_®Ð–‚í:îi(£>»FŸ ;ðBHØ Ä{Ø9'·è’<à‚÷¥Ê—È–W&ôŸqIdLp=Þ±Õ2÷“!ñÉ#Ë $ó,Q L$C™èðöJrQ0 û6\ÀºÍ†… ^gö$ ,7¹d„HñLµ”‡jt â8ì°·ã÷wßU«Vãþ¿ÝúúzL˜0 ]óÏ=+W€R ƒÖàÁWæLËc¤ ÃAÂ4§b ºDÈlZqÔÊ:&4 okÌ%aÙîø—Àtur(Ö¯_‡?„Ù³g#™L¶mäóyŒaÛ¶mX²d :;;¡Ïý€Lt*$ˆxúÙù Â‰$ü]´%Äm ׸ÁÝ ‰á \B½°w¯<†ÄKÕU&Ñë„Ô‰Š§ð ’|SXo!{$‰p,ÓAl*Tz""F¦3¾¥Ü²+¹YRQB£Èò‚x.Ï¡$©ëPx99ã³5)((((((((((ìa„œ Üxß3Èþ¦çœ¸gÛ­LYRÀÖ¥¾'Ú'O„ç‚ý€RŠýl´g)²ÏÇkÿþ7–¼ø"lÛF?úûûÑ×ׇµk×ÂðÂ÷‰¦A×u$“)¼¼¹+7öã€.w¤±_G(ìtë%s€– 0ò Æ0ˆæ°jcê-<ør Ö ¤H ò,€ãظýŽ;Q[WéÓ§ct4‡¾Þ>lÙº}}}¨­­Åa ¢{"ÁúM̰XÂ$Œ5 íâäʈ$À» ™¢€Éø&<×åHŸß ¡ár­—¤Ç,‰˜%ñŒT¬DHìJòÕ¡°à™%ˆD[ÄtÏ@|ºùIYËL p¡ó~à„pc¨$#aIħ$!á7"' 'rvÖ@ ±âïCK=åv‰ #€Ø6¹G±ÆE…×LÖÿ’ûêù¤Ì%<Óg=­? ¥¼±,}c[u=MË@P_߀ãßóìèíÅèè(LÓD__††† ë:(¥Á¶…‰DÙl&jð‡—'âòY¯b8G0’·P¯›@~( ††JÇ‚ãlÚž†á$°c@Çß—O‚¦çH$Ã!ƒ;wâ®»îÂŒû!•JƒR Û¶AÁ¼yó0sÖ,´4[øÓ¦47ç1“ÀL6?ïRH<ïqÕË8ø¥As7b±!Ñ Á!óD“Òã‰áùÌ’„0F  $‘—F)”)È­”ðzö°ˆ·(ˆPN'~«JRB'âݳÅ5.…KF”2•{ö h@”ŸÞkáG=KƒzThÃÖey ÉEÐΡ4Èžï—»ÇÔ±¡‚îînœyæ™Èf³¨©©Áèè(ZZZ06: ê8A_©T Édét³ŽÀÈ„/£¾±ë·¥Q0@m× àxy¨›lëMbko­“»ñÄŽ÷"g7 N#•JAÓ´ ¡[1Ÿ‡®ëèëë÷v'’É$fÌØ'½÷$èºÓ0.M€ GÀ—ùÜ’ÍÛÇò)¯r½Õ’˜lI@´Ž÷Šò8µø00cÕ`½Ø²Ds„ N!úx¶+Fô„מ'ÓD®”¤H.7悟€ˆ¼âš-T'ØÝ¢„Šl¯ü¸™X´gtŠæÏ=ß+:¼^2·£gíÞñùˆÓGaŸÅÌý|½UxËã­vÞjãݱ/ßV·_| ÇŸpò>­¯‚‚‚¾ÿ7>·+Ëÿ¢OØk4bÓ†kçS¾®Ì€@Å>Ù> ¢é!Ð5³fΉ'žˆþþ~444 P( 7:4ðÃÆ“É$:;;qÌÑÇ¢mîÇPwÀç‘É6ãµ  y›a IDATåR@¶¨Ÿ4tÁJ5aõ† v &1¡s? L¸‡.ú:::ƒÀ]FàË/‹°, ¶m£¡¡S§NÅû?ðÔÖÕ"‘HÀv,qjbçI™ß/'B­jÈ–ÏÛIpÂëS‰¬¨Ñ@¸Î*IdU£½ú°^9]¤ó'ôK„Š!¹&=#» @$Ûe”’0çrM¦|­²]Uª ©¤ni YóBÙ$d}½É­êii¨ù‰‡š…݉7óó7¶ýø§¸äâ¯bõkË÷²F o>ð»°!âÞŸÀ»ë‚ðb¸8„’‹`ǵmɳøËê@#ºººÐÚÚŠ ÖcçÎÜrǶ‘H$L&1þ|Ì;í]0šÿ,[Gfí°j[ÆÀ$4´6Ã4ä‡ÓhKí@Mã ·|ZÝþ˜\ã`ÿý÷Çk¯½]׃|ŒŽaÊ”)€ÚÚZœtÒI˜Ú5š¦yóäpãc:ŠsÎGDàý÷S ¿ ¶ßèRa(8 Yòs³ÜGÛGdŠÊðyfË÷EˆjË •D¦f¤ªF*“)ê!kwï7§b¡ðY„Ïaì½`DÄ ÃU%œøH5¦ ܽ@"¬”žÑeMö8ü„ÔÖÖ¢«k ½ë8ç3ŸBKKKUrªý¹·~²?Œ !hmmÁ‡Žo|ý"LšÔ¾WtØùÏüî ¸áW7⊟^…‹¾v!>{îgv›ÜÝ5{{^GFFpÝõ¿Âßx==Û‘N§pØa ñÉOœ…£Žñe!,g#dÂXj’Ò€æ Qd}ä/½ôÑÒÒ‚¥K—Áô€¦ë°muuu8äàCÐÖÞ]ב­k…sÀy裭˜š»Ù Ú8 ™¤±Vm?zë½Ö[6 á°ÃÃâÅ‹á8N$ÝXnš¦¡¿¿çœsæÎ™ÃDSP8N¼›4B˜bÈ_„¿–b—"»ÉsZIÆy.“<'ÃM¼ÇF°²8c‘Èèãg4‰³x,W7&zÀ¿þ>Lƒ¶öÇA…’ðùå¦4øHo¨lb"½yU8žÉ„ð Ä„…ÑçÄWˆFºô“|ºrhÔÐ üÂÀ°Åöôï%Ãdå1úÇLÕn…ÿÃ1ŸÏcݺõøÃ=Â)§}¿»ë·˜ÒÙ¹ç:Þ‹ðÇè8úúúðëƒ ¿rî¼ãÖ×Y³7/ÇÁm·ß…Ë.ý:nºùœó™Oà·*.¸ðkè˜<¿ºþZtvv`ddO?ý,~ñ¿|KÞ F°7r¹R©Ôë­†‚‚‚›ž{;,`·Sá¸þz„ïjš†¶¶6|é‹çaÙòëZjü€;–›nºï\ônÌ:à  üú~Ã|v¾÷ýÿ‚iš÷ÉΫÿ^íüÞ~Ç]8úØ÷àÀy ðá| ¯½¶jwLcEøçc£±±ŸüÄYhnjÂc?Á]/§ß¿žz§}àÃ8pÞ}ì{ð»»ϵõaÛ6®úÙÕXtÌñX°ðüúÆ›¹~âúˆ›×=‰çž{ßøúE˜6­Éd---8ùä÷âö߆:ËtÙãöýgFD%úŠŸ»™ûˆÛn¿ǼûDÌ9ðœô¾÷ãù–à÷ü ÇŸpr0®5k×qrØãRsPî»`_C©ç‰}öË͵‚‚‚‚‚†ƒGr °ëýY¢Î’{é¹PWF²‚ú~]Ê·w([FÐ[ xuHçHÊÊ•+‘ËåÐÛÛ‹|>t: MÓ é:7Æ)S:‘Éd`ZlÇA~,B±Ó4¡ÕLƒ=ñ ŒdÎF¾þC¨o?Ùš$IΔH$0uêT8ŽǶ9ù𮣡¡íííXµj—¨Š“!ñ¾³à8>s1̈„_B" ÂûmêDËA% aË8’M]ªá†²ëC½ &ìqã&±·‚﯉†ÓIÈe/&^_0cl@%ë–ê‡Ñ[^YLLÈ×+mˆÊÜ ö)>rƇñ¯=œŸþWðñ³>†'ÿs1ÚÛÛð“+®.d•õôÝü›[ñÌ3Ïá··ÞˆG?Ó²8cÃëÇqÐÛÛ‡_^wæÏŸ”—ÓµÔø}<óÜs¸ç÷wbÕ¿—eO>ùþò§ßã¯÷ýë֭ǵ¿¼¡â>}ìÊü>þø“¸í·7ãùgŸÄыޅoçû㜹êqÛmwâÿଳþ¿ýí‘:¥ô»è¢oà Ÿÿ^|áiÜqÛ-xñ¥W¤ý\wý¯ðÜó/à··Ü„<ü zz¶WÔGܼîIþöÃpÙ·¿‡–¼ˆB¡0.ã/°ï?3"*ÑWö¹{ôÑÇpËͿ’çŸÂi§¾çœ{|h1núõõxþÙ'qÜ»)9®RsPÉwÁ¾Ù³¿/~_+(((¼QÀX>Ë~ÁÓ/‹pË]ªáz¥Åsµ÷ ŽÿbÊüÌõEØiŽí&ò³, /¼ðzzz022‚††Ìš5 õõõÐ4 ºžˆ=uj7FGG1¼s}½½Ø9´ù±Qäóyä—<ç¿"ó‡;A®ù9è}øÆEÐ?ÿYô}ælËðæÃAGG È,%Ð5×=::ŠM›6a47ÊÕÑ5=2Grϼ7?¬'WBþXCMAF¬>AÐ?OcŒx_dcÚÃhk›ˆÁÁÁù}÷þGñvd2Ô××ãk_ý2{üñ’2îºën|ï{ß”)SÐØØ€o~ýb<ðàC{Zu)|ÏØþ³çáÈw;ïºßÿî·*Öµ’ñû²o¢­­/ûÖ7ÑÞÞŽööv|ë²oàOþKÅ}–C%í/ÿþw0¥³Ùlçžói,_±²bù»‚M›6ã•¥Ëpê)'NyßIxeé2lÞ¼¹býô„Ž;v ¿“ñß?¸\Ú×îù¾ûíË0ujpÙ¥_¯¸½Ÿ]uö›> ßûÞâÐαLjÿùÑ©XÆ®Œw_~fd¨D_Ùçî?ø>¦NíB6›Å§Îþ$FGGñ_—]]S‚²W^YÛo©9Ïwáž‚ÿ½&¾Æƒ}éûZAAAá7Ÿùá,½ªì:a¥^r÷á…ú¨ûƒDs ¹¦éhnn†aØ9,°v¡€Áuë°,ŸÍd 5´À®o†fY0ÆÆPÁqé,lJ$ÐÜÔ‡Iº iZ06Çq088èæèÇ”š)Þt$RÉè˜D÷¿Ä»/%Åþ\‹“ÃN'eg•†ç~Cö/Í1@ U ªárˆ²¨L@‰ú@)a[J¬n‘Ĉà ,kQÛøþÚwvÝ=÷„ú9 „á”^"*„pÆ£Ø$~Œ ©HYî„ÝKìBRÑöŒ¾îÒ{ÃÝ=!§CŒR{ ;vô¢¥¹98_ºl9~üãŸbÅÊ•èB´‘ˆ-[·á„OáÊ^¯5æ¬Gx``7ÿæ·¸ü?ˆ[o¹@y]+GÇäH¿]]S‚ã©S»°}ûŽà|Wç§’ö'N޳Ù̸½ÔÕâ¶ÛïÄÀÀœ·@(¿ _¿äké÷Ëk®Æ/þï—øùÕ× ©©ßþÖ7qô¢wEúêéÙŽîº¼^s C]].üòù¸ðËçƒRŠÕ«×à†_݈¯~íë¸áúk*’±+ãÝ—Ÿ*ÑWö¹k›818Îf3ªW©ºãù.ÜS(•|°ZìKß× oP”ð»€ù/r΀`½:‹À8.ù Gö‰@!)CƘ2—èkpŠÞÞ>är9Ì;9ã#èèìÀ–-[ÐÐÐÊp(,Óò’ÑP‹·?ïÿBÒ01²µÙyóÐyð<ÔÕ6xù˜¦ Û¶‘ÊdP4Šn®€DÔqÏ©¦ëZZ[1ÞAX¿~r¹úúú‚] !xh«Î#b WˆQÁ»HªJ,/òB`cwf[©öZ¯ns Ÿx \1âDÑ‹)g ÁJ0t„I hЯl œÁJ\ä~0•8Ò žÂ—!ÂÄldœ2ÝŠdF‡ €ÒHÛH÷LA¬áÀ—”Ü¡:ãcán€DðÄïîþ=ŽzÇ‘Áù—/üÎÿÒçqõ±W¢¾®#¹vTp]Ñ1y2n¼ñº}.aKK >÷ÿÎÁáG†¹ËéZnü€|6mÚŒ™3gÇíí¡g³šùy#Ío±XÄ=ü3ýǃœn›7oÆéþ\øå/!N—•sàsqí5?¥þó1|ã›ßÂSOþ3RoòäIذa#ößVÕº–ÛrtOâÿ³wæñ1]ýÿÜÉAQD"!v ÑTR´Q´Tñ<–RŠ¢©%BciBm]‘*} %–Ɽµ%„X~B‹Ð"¢ö%"–òXI&3™ûûc2wî½sgæÎÌ%rÞ¯×%sïY¾çœï9÷~¿çÜs)ŠBãÆ0cúT´ïð!sÞÍÍ EEÅŒAûÏ?O8ñ,)¯£êŒ>ÄÈkë63”GÊ›n‚#¡ó*Û@Ò±Ii¶GqÃò?VÁ´Àzå€eüi^]М+¢ (ó_<}úøâ‹/à[×2™ ^^^ŒA®N—V¯ (-eÒP©TMÁIæ §âb¸––À£fMP”Ö®[‹´ƒiÈÊÊBbb"Š ‹àìì\öª˜/P¥Þä°ÌÀ©]»6 ŒVo½¥R‰/^028ÉœW(++·v±·>›ˆÍ­s¡ºÔWãPc/jf×ugšȸÎÝ¥æÚ#&Nˆ¶^A À^ZûFÕªhú6~ø^kP“ÕXùõñn»¶èÙ»”J%þÕ£;¢F'G¯_6¿ü²ôÈ1xÐgHX± Ÿôée4Î;aÌØñ¸Ÿ—‡† pÚ‹ÍÈ_¢°°EQQ¾%ZV¡zµ&Ñ_EaÓ¦-øvælËQ³fMtìÐK–hË6wÎLL›1?%®Á›oÖÀ¨‘ÃqøðQæº%åuTч#ÊkîXàè8b]‚#ÃLæ æl˜Fw û•K+cÓ³æ dZ#EF•ít¯™°efA)n8õ)0ÿñfKùÓÐÚ"úÞ³fÿìå¯Dm§WÚ4( ÎÎÎÌLþ¶mÛÇÌÚS…/¿üê´ Q|ð¿|‰JMšB~íj „¦M›âÀþˆ‹˜˜¯ñÑG]Q©R%899áÕ+õF…ë×­ÃÏëÖ1šÆ10nü8|ýõ×€sçΡ¸¸mÚ´\+ª„´Ç•P ¤´†)¸v³B€·¢‚1b5«ØuB³ãqÓÍÚÀ‘“/}–!®¢Òbåp_ à¤MkeÓÊ@kóârÒÊæžOv™ùƒ-ïõeZ]ŒìÚ9eå—[Å=/Ki¹úkÀË¡ï”ÛÙÂÝ”â…JC£³üpd¡¹ÖÆ¥uKœp†äç–¡úê]ô/eÇógOã@ éIÞ±K—¯¤Ü§|<{€»Ç Ù£îf‚ÐÎÆ²gÙ3ŠšY`Í ±ÎÊè®.`f¡ Ë_m¼/×Ãê;Á™Ö~2Pã „„„ÀßÏYeŽ𦑕•¹\777"ëÑc4ÎÍÁ½›7áò6”yyغe üêÖEà °{÷øúÖEXX“MÓ¸•Ŭ(«ȜСCд N2'«_9P•ÂÉÙù*7µS€Wv¾¡«S÷¬za- SÎyÞl¬6î»ß‚q\ãÛ¢ìMûøåc¿î¯iG¶S€Ž>!Ùõ­,a#*LÙ'i4-\lÑÝ5äÐÍ‚Á¨<¬¼Ãy°›U³ÔŸf…â†ÓSa: ÌÜsWhnN(Ÿ^Ý ]=@kË 1b7¨²Õ§Ü¬˜2–çò9"¤Î…!õ¢¡º©¨u!†Š0vByBí(34Sƒf4ó4Oƒå$Ïa¯Þ¦®—…QAÀ®à…ãÏ«TÀÍBw4õxU–ŒZ•J 4@Û¶aȾ|ªRõŸ;ì™}µQÀ6<8vëuõ…ì±²ó:³å<#‡cH³ ’KÏdh^IÆlXZZÊl„¦¢Uèõ¯îØôËVÎÞýuþþ~pvvF•7kàEÍšxÃÍ”—êÖõE‹–-A«hxU®Œàà`Èår899•­Páä‰xõJû ƒF˜}ø6œŠ€¦j‚rõd.Ë(`׃J¸ýŠâDÑYö_Vpšeqó—ðë8 „êYö{­Á_ö=F©ÆHÔä/hÃjcÉË>Íü(ûŸ¢¨¸¯èÈ ž‘Ëߟ֭½N%–RjýY¼ô2‹Vkk+Ù ÂÈÔ¾N>¬ìb±+W°-XiÊç80(€¢h€¦xY—¹Í4¯¾p/q &àô¡X9ŸVdÍü3R–­``¿ï¢)ÍYN¢qnXa¹@ @0 öÓ¹àöÈ|–9Ï6V¹Ïý:q9Ïèåͯróæ{ÊfŽËù?·²SeFŠýø¼n-BÇ7öbL·:p¡”€ªEÅ…8zärïÝM«@Q€"(×½*£jpvq…››ªT­ggTöªŒ*UªÀÅŪR%nݺ…””T”–*Õ9Ò P(A—jöu®D•KA?¿^öª /UîÈe­Ð_f÷ˆžÚà"äPaêŒw‰ŸMóêÙ@>b®zM„}‚y½<Y_º‚ „1 “¶ ÔºÀ—Œ:_ É¥çËë`Ç7ü¡Ê؇8m,–Ù5¿ù6°Pt}«;ØM&äPÐ'#o:¼tN° B£Ž£A¿eÌwèøh]ƒUGV¦Ð“†m­·,†¬i=×ôæaÄ87è  hnX~d¨tÁ*ç¯ðXŸs€}^¯ìçñ@ ŽŠ àÚ~œ~¶3 ,³Ë½ž0G¸™®!ÉZP¶ØX(-MÄœ ûx0Æ7”ª\gçá]Ãߌ DËæµ  UJ¤¦ìÅÉ¿£´”FåÊUôÁ¨Y«hšBQq1ä%r””” ¤¤Dí(‘#ãÿÒ‘’²ÅE… èRÐ4àé1a© ä¿Uô r¥ŠœÞEQ¸Rà…¼"'òr_# Y³êDÀfb¹úÞµç¶Þªeý¦˜…à‚öZ™åjЄ¼ÈZæÎs,ñNf¥ÏÀ669Î ÍŽ{Ì>ºá5™³Ec^Ó0dÄ3—xÖ9ωA™|h䶪پö¬;; ¾à¥ǹÀIœ¬4¸ºA•½²Ã­1v\~õqÓ§@ÉXÂ@ ‡Ac_ÉtOR£•o| :x³ÕüCÅ_–.†gˆiKœðŠò`Þe~õfg”ªÜ@)pv£æ‡ÿþÔC«ÃÓB~Á+,]úRSSðüùsf†U¡,…B¡€¼XŽââb”È‹ñèÑC$ïLÆÜ‹ðòÅÿ@Q€› …·z`Ý¢÷ѯO¸U÷Ê6,ªÔ ²jp­¸ ’ïs¿D ì1j¡j†l(Z85e7ǘÖþ¯™9VïÌÏ1K¹éÚ:âò A¡UL=è™ufÿ ™Ùm#™ ™¨´pï8c@»*häÿ@=ÀÕ4ŠðÊÉEµ>Â…/ö<ödö_ã8Q֯묧¨Úß4רf¯ `ÎÑÚ¯D\™ÁŠÃj9V`J7UVMpáhZïKN½+X+ 8aÊ6" Yá˜|Ø+O8J¤»™"ÍþG°RБ‡'€1 gmJÈÝdQX&Îé²t¹A¹™i“/KT Žæ« 4Ó1…R⇕³QcYf:ýžZµ;E¢i°·º8sú².ü% @ @°%eŸ+äš4cPZCƒÒ'l£‚´NJk4°í nÚ,#‰/M™AÓ< Üðù `ÿ}ôò§P͉†²v{y.^„ŸŸ|ëÖCåÊ^(xõ y÷óp÷ÎM<ùç1ªTvCïw=ð^ëªx'€B ÛsxVñ”¯ ¼q ªx‰(ªÓ Wd8ø¸TÐ]) kÓœòò¯ëÛ QguÛhã×;ˆÆ ¨'2§MYåÑ1öYF. Jë2ÁžÖg•rôCÈðgf²Tßl IDATäd}qoöò‹Jk£ {"˜‹êÐb&¹iv…ñá†ÿ…¡OzRì†`ü.ZI8ŸZd Èw:hëGÛkÙvÙØõ‘-'ã`¥Å—›Ý†|ÿ Eqœ…Ýz„ [@ ñ,^°Îì¸mÚ†Ë×2¿5ÏþœìO2¿Ù†ÏØdÛVŒS@{™3sÈxäºãˆ7[,$®‰¼"'Æ)À7>ùN¾ã@¨Œ4(ý³æe?hž!Éù)ÆÚÒTº€ÑÌ~„}Íam,Oº,S­‘¯;ÇÍOGŸ³ƒqºphPç§5ô5m"äÇЭuÁ9mc›c@X×Ôåe¨ u^·á O±tËPµðÛVžé‡}S5ì¬>/”ŸSPŸ£@ @ XÎógOE…3¶·÷«´þÏrfÃiîu°ÃÒ¬ëìpà†áüM \gÖLºÎuš9RXú·޾ª‹þý¡ [€âwV€ ÿt«Ù ë õÆ; Ýj2µ?D¥R1ÿ«T*u>2”º×…‹O{x šG^Àü‚¾H¼_×òQ Ô~ZQ[w|cžæÖ¸‡º<Ç)À® ÍoM¹ÁOŸ¹ äÐ=¯c³g¥ =!Oß ÷4xéñòg– ƒ*ûj‚ú0´ªœ]:Áx't dZ]·ì 8eåŧ8$€âf¥>ø™Rz?ñÇ1â)¦êt³¡¸©ê«N¡¶cì<ô¥E Ÿ§*S¨­Œ}í@,éé'ÖÕPð:E5<,ÁÒøRcKyÄäe(Œ±öbóøñSx{·±k}§§ŸDÏž£P­Z*Wn‰ÐÐ^ظñ7N¹¼3g.C£FàáˆF:aæÌeËK˜0å]-iw1uh y¤ÂÚ:âÄY 45k†¢J•`„†öÂúõÉœz¶DŒ>+•¥˜?&8¸;vïN×Ikß¾#hÑâc¸»7G˖ݰÿÿY$[yiwk´iy);`\ç­1&X‚©òº7UTg#Õ½»<•]̳)Ï?ކÀç Q6›©qÕ|nPçà]gÂQœ ¡*;„ k­Q¬qRÐ\‡ƒ@!4ñä* ó‰ Iw¼p¦ :ÎäWÇKxBæäˉ v¨ÿW*•P©TP(Ìugg¸¹{àïW^8ü¬:~¾W· ]¡¤)ár±yìü:eþ.3Aif=eúŸSf±Å2ìõߊʮ°¦—)Ö%šs»é“ËÀz-‚¾ ±ÍX¨ZkQ¯ñÏŽ#p‘ÉŸ¿nŸOvŠ1Âù…Ò“´aôYé:á„NiMi jÃ^³\ŸW½:iQ¬ƒ¡ÌáÂOë¦ÃŽËJ@#ƒæŒs€I‹gÜkÎéÈD —C“µ%[ Ì›·ññS †¡é›:‡© 8+Vl‚B¡(J$$lÄÀãÍ’ÛRl)˜¼ÄÊ#¦½4DGÏÆçŸ÷–¨æÑ¥ËP¼|Y€={VãñãLlÚ´›6ý†¹s˜011 pæÌìÛ÷3ž=û ))kqîÜ%ÄÆ~ÇI«¼é¡Tí.¦¥’G*l©óS§Æ£GN8>OžœÃÆK°uë^ÄÅ-•¼\b£Ïññ«±wïüúë*<}zkÖ,À¬Y?âìÙ,&LVÖU >Ë–}‹çÏÏ㇦ã‹/&áòå&ÉSÛ]ª6-eŒë¼Tc‚T˜*¾{SEÖy6–Ü»ËkÙÅ<Û˜òüãhPs6L£»„v…WieDûÚÞò„ל+W®<8iV|Šj(hhé;o*%% $%íDrò:t]º„£oßÑ®®.§ïÈòˆÉËTyŒµËž=é7n²³ÀË«¥$mh“&-ÄâÅßpöé¸wïBC{áÑ£3€š5CqáB ||j3aòòá­·þ…Ç3”O=”ªÝÅÔáëZv6¦èÀýûЪUw7iò!vî\ààfL˜3g.`ÕªÍHJZ ˆŒœŽ&M3‚ ³xñjܾ}«VÍ-Oyow æ´iy/»>—jL Sä1to":où½»<—7ÎKõ< Å Ö1›ò_%8~üàý÷¹{ $ïØ@½ia‹–oÒ¦¢À©ÏPï1@EQ8zô¨Õ„'¨S§Ž½E0 Å[ÚÀÿ-†Q£¦C¥Rá矵³oÇO““V¯žosyZ·î‰ bѵëû̹“'ÏaÔ¨iÈÎN3)/)ä€/ò‡5k R%O³ÒàÊaþM8>~ŠÎ9w(•¥¬ô)Èdœ…vÉdf—ß¶ÔC)Ú]LŠåuÕy!43Tæ`‰Î‹ÑçÜ܇hÒ$€¦E‹&øãí{ªg1nÜœ0ݺuÀgŸ3K&C¿Å`Kׇ9mú:ê¼”c‚VëŽó€ñ{SE×y©îݯ£Î;ÇŸ@ÔXµ.®Zñç€0겪ïekÚUªRrƒä°êaM||ÚÁÍ­: _¿±øóÏl“Ó:4%%%HIQß5%e-äò cR: ³péÒ5ìØ‘ ؾ=—/ß@BÂ,»È9‰‰[9ç¶oOAÿþ=LÊK*y 6ö;„‡‡¢{÷Ž&ǵË—oÀgŸý‹ù9‘‘3pýúÈå%¸~ý"#g *j0'^yÓCk¶;¿Åð:ë¼…B‰‹¯`ذX ÜËìt,AŒ>ûùÕÁw9ñ²³¯#7÷!ó;''uï½÷)Ú·€ ü““g’<å]ç-iÓŠ ó̬‰<ÆîM]祸wW$·%§€\.‡\.GÔØqÌê½ÐÌ?êW >jý1¼T^hÜ4ÐꄊM½zõHÿ*Aß¾c0iÒH„„áÅ‹|>ü;&O^ˆ„„ÙèÕ«³¤y‰åþýGèÜyç!2rÞÄY¶kKy áïŽìì¨S§hš†Ÿß{8th#š7odV^–„9zôúöƒË—Óàí]Stz–Ê#–Ý»Ó1qâ<<ÜqùrüpëÖ=Lœ811 °|ùLå_¥jw}uh*¯“γÓ()Q ;û:&L˜‹iÓ¾Ç?ƉŽ/•΋Ñ篿þ4M£oß1ÈÉÉCãÆõ‘#§1éxx¸£¸XOOœ:• xõªžžî¢eáSÞtÞÒ65U}8ªÎ– ¶çÅÜ›*²ÎKuï6U}8²ÎK_÷ ÉæãS«Wê½nµ/À™}ªT©031¡|0gŽú]«¸¸év–„` Ú¶ ÑYkk23/Â×·6ΞÍBûöav•%2rúôiÓ¢°cG*g©­¹y3QQß"*ê[ÎyS=ìì°Rxç·mKÁW_ÍÄþýIhÕª9çÚÖ­{‘••ÊçÏïC‡Ñ¡C¼ývÝä D­Z5šz ÉÉpøð/v“Åš_–0—5kþ‹˜˜8xpBC[ †úĬ± Š*’Š©C[âH:/„æsÉöÂ}^¹òôë×ùŠ´´ã#)5õÞÿÉä4{޽önSGÓyGŒÉ#æÞT‘uÞïÝŽ¦óåµc ì&@Œ%‚=ùý÷Sø°s'æ÷É“p®›£Ÿúâ]ýèÖ-&D ]»·AQNŸ>±cgbÊ”Ñv‘§  ƒOÄúõ‹Q­ZU$&ÎÇàÁ‘™¹ ^^–ïÀo.‘‘1nÜT¯þš6m`79E‹1cÆüöÛOhÛ6D0Ì'ŸtÅðáS°tét4hà;wr1qâ<ôíû1¦"롘:´Ž¢ó;Atô0¼ÿ~XÙþˆ‰™!CúØE1úܧÏhÌ›ƒ&M›û?ü°W®Üĺu‹˜0ÑÑCѹó´jÕáá¡ÈÈÈÄ’%?ãèÑ-ö(–MuÞÑÚTƒ£è¼£ RÉS‘uÞQq·gNŸ@Ö…¿ŒÔ 0¾õ惡Ã«Ô 5j½)„‚H–|ÿ@‹¸råFŽŠ€§§^½*ÄÏkÖ#¨Es\8Ÿˆ‰Õ~æÏsçqôèqPOO4hØ;†ÃÕÕ•I“&®æÚÇݺàô©L¼|™ê5ªãÃ;Â××ñ?£÷:ò–Ú£nêæƒü÷¬®çzçÎýX²d-.\øîîn jŒ)SF£GN:ñlÁ!1ðñ©…E‹´«V&O^ˆ‡Ÿ`ãÆïí" ~ÒǧbbF ..Újùk/}qì5ë $¯†þ9‹7߬†ÂÂ"ÌžýìØ±yyàãSô@\\4<<Ôï–Vd=S‡öÀQt>##ññkpüø(•¥hÐÀý= ÎÎNV“Kbô99ù¦O_‚[·ràëëO>銸¸hT­Z™“Ö¾}GðÍ7‹pãÆ]4n\ññSÑ­[›— °­Î;Z›jpw´1Á\y„îMUç…°÷ŠÀqt^l)X¼`Z¶ 1Ë)ÀÞ|ðPZ*^¹à`æ®c ªæðãRõ&Ã"cÓ†­y»Â۷ÉŒ?pþ¯‹øâËϱvÍÀø‰c˜x§Oe¢qㆨúFU\½r‡Ap«èôÁûœtÙqØç›7oŠÂqçvì?„jÕ«aè°V//ký.ó¿J@°ŒÒÒRøù…ãÈ‘_Ь™þ‡$áuè<¡¢AtžPѨˆ:¿xÁ:Ô¬Yˬ¸=û t p÷P”F&¬W%4nÜ/\Bófqñâ%5…»› †­Ÿ­[·ЪR4jT‡·nÞFûöm9éêÓéwÚ¼ '…€?Àógωþ^{hšÆO?mAݺÞæÆI¨Ø'T4ˆÎ*Dç¥Cí(Û|Æðv3‚õ „†¾…k×nb×®TÐ*¡­ßâè¤æïGãÔ©sxòä)Š‹å ËvOzõªPG‡õéte¯J'™ €zP!úOxݑɡ^=_ìØ‘`oQ›@tžPÑ :O¨h—€2_gÅ€±h kAQªW¯†† ëãÆÛ i ¯2ã8‚üüüûß]áï_Je)׫{žëÓi¡óDÿ ¯;ö~@°5Dç  ¢ó„ŠÑyép˜!“È`4º×£G£a4+ÜÝÝ R©pêT¦Nw#??U«VÑ›–±s@ ðºÃ[1 ³—„ ŽÝÓ„éÖ­3Ž;‰ää}¨TÉaa!:aÚµ Ãdbýúÿ&L-˜–©2@ Âëy•€`W&NŒ29Lݺ>øüóO9çZµj¡ó›N_~bd @ „×Àì7™Œ"9ÈA«–òøñSx{·üNì‹ùˆ‰Y€€€psk†  ®Øµës==ý$zö…jÕBP¹rK„†öÂÆ¿é¤³oß´hñ1ÜÝ›£eËnØ¿ÿÿ,’Ùз“¥FL^úÂPTCÁÃÚòH…%eÔúÖÛ`©uÃRŒÉ,FçOœ8‹Aƒ& fÍPT©ŒÐÐ^X¿>™ymKl:@Åí;€ññÇòH…%eW*K1þ 4jÔ îŽÝ»Ó¥Ñ$Äôe úî)bú…˜1³"«úÊîîÞܪòH…%e—ËK0sæ2¦_4jÔ 3g.ƒ\nŸ/`™ª‡†žµŒ…©È:ov·EÙ5ÃãPoÜ&#9ÈA«–=ŸÞ[ç|q±;‚\^‚ÇA~~¶nýëÖí`Âté2/_`ÏžÕxü8›6-Á¦M¿aî\íN¶YYW1|ø,[ö-ž??~˜Ž/¾˜„Ë—o˜$çÀã±bÅ&(J€B¡DBÂF 8ÞÌ’[–—Xyhú¦Îa y¤Bʲϛ·ññSõæ%•nH‰1™ÅèüÔ©ñèÑ£ΟOÁ“'ç°qãlݺqqKMJ§"÷1ãTòH…Te_½{à×_WáéÓsX³ffÍúgÏfI.³XŒõ 6úî)bú n̬¨ãªP¹§O‹ˆˆ~’Ë#R•=&fΜ¹€}û~Ƴg!%e-λ„ØØï$—Y,¦è¡¾~!6LEÕy©ÚÝ–e§išY%ÀyJ·÷L"9ÈAŽ×ÿ°„={ÒqúôyÌž­;0®X± AA‘0 øÁÕÕÁÁͰgÏj&LlìH=ºíÛ‡ÁÃÃÍ›7ºu‹°‘ “°“'BçÎïÁÝÝ ]º„#&f–/ß`’¬6|gggôè1УÇp¸¸¸`ÆïÍ,½ey9š<¶ÌK¬<ÇŽmAÇŽmôæ%•nH‰1™Åè|FÆ6 Ü ¾¾µáêê‚À@u˜U«6›”NEî;bÆ©ä‘ ©Êž”´«WÏGpp3xzz M›·˜8+Vl’\f±ë ÝSÄô [RuƒO~þ+$&nÁäÉ£$—G*¤*û¶mû°víB4kÖîînhÚ´V¯žmÛöI.³Ôꦄ±”ŠÜî¶,;Žc€¢(rƒä°êa./^ä#**+WÎA¥Jž:ד“ *j°Á4âã§èÈàáᥲ”ù‘qܦ[·8~üŒÉ2óó2§ü£FMLjÜ™¯áç`Ô¨é&ç%…³i(“œ.ËÐþËŒÉAr¼Þ‡¹ÄÆ~‡ððPtïÞQðúåË7ðøñSw‡‡G š5ë‚¥K×A¥RLwùò øì³1¿sròPðÞ{Ÿ¢}ûhÐÀ99y&É;th JJJ’²’²ry †1)„„Y¸tévìHlßž‚Ë—o !a–Iy‰•ÇǧÜÜš!  úõ‹?ÿÌ6I^)Ë9‰‰[9ç¶oOAÿþ=LÊK*y¤Ò {Ã×y6 …/^Á°a±<¸—IéTä¾cîøc­²Û²ïøùÕÁw9yeg_GnîC“d¶5Æî)l õ 1c¦#«¶¾§hËK°lY¦N5}ÃçòØ/"#"2r®_¿¹¼ׯßAdä Ɉæ FÅô 1a*ªÎKÕîR•],Ÿ5gÃ4ºKhWx)½àëWÇ*™‚†ÀÀ·œçèÑSèÛw ._Nƒ·wMêÍXØï¬995FXX0–-›ààf¸y3‘‘ÓÑ¿L˜!˜îîÝé˜8q23w¡F7˜tŠ«ÉdhÛ¶/œœdÈÈØ—¦(-½nV™ù²šÊýûйó$&ÎCdä >¼ >>µÍÎK_˜¾}Ç`Ò¤‘ ‹ù8|øwLž¼ ³Ñ«Wg³d·¤ì…ð÷GvöÔ©S 4MÃÏï=:´Í›72+/KÂXC7¤Bl= é<; !!ÈÈØ¦w6ˆô.æŒ?Æ(/}'>~ öìIǪUsѰ¡?.]º†ñãçàÌ™‹P*¯™%¿Tè“YÌ=…†~¿3f:Ú¸ Ø®_°ùé§-8pàÿ°kW¢Ùr‹ÍK¶ì%% tí: ÇŽfÎuêÔ¬‡««‹Yò[‚=Ó/Ä„©È:ov×—×âëP³f-³ÒìÙgZ´| pð@ _áà¹\Ç@‘ü‘Y‰‚Xzöü€iŽF:!6v$FĜ㔕*µÀ±c[Ìœ»xñ ú÷Æ•+º;ƒïÙ“ŽQ£¦#-m=ZµÒîìåÕŸ§§sîÕ«Bx{·A~¾ý6ÓÊÈÈD§Nƒ™÷¼mEzúIŒ?ÙÙi6Ë“ÍèÑ3P·n̘1'NœETÔ·ÈÊÚoÕ<õÝ„¥Ö þNÖ<ôˆyѧólJJÈÎ¾Ž æâ­·šãÇãD§S‘ûŽ©ã-°Uß)--Å’%k±víväää¡qãúˆ‹‹ÆÈ‘Óðì™é¯Ø¢_ˆ¹§°Ó/4ˆ3í=®¶½§”––¢iÓÎØ¼y)Ú´y˪yÃVý⫯fáÖ­,Y2 ~¸uë&Nœ‡&M°|ùL“Ó“²_hà롘~ajßÑ——=°…ÎKÝ†cÀ@Ùg €¡RÉJ ’qóf¢¢¾ETÔ·œóì›QݺÞ j̹޸q}ÁeÌÛ¶¥à«¯fbÿþ$Éßß·oçrÒº};þþ>RÇ,23/Â×·6ΞͲ©c mÛe¶$2rúôiÓ¢°cG*gɧ­‘Z7¤x°‹!gãêê‚@lÞ¼­ZõÐ1€H߯”ñÇVتï899aòäQœ åNœ8‹æÍÍûÄ–-ú…˜{ cý‚˜1ÓÞã*`Û{Êöí©¨WÏ×îNÀvýbëÖ½ÈÊJef¥!)i‚ƒ»›e Z£_ðõPL¿0µïèËËØBç¥nw[cù·ÃÁÊèûì û&Ô®]²³¹Ë•¯_¿?Þ+RkÖü#GNÅÞ½kÚR'¯ððP͉RSáý÷ß‘ª8&sîÜ%¬_ŸŒóç÷!)i§Yïê™ËÅ‹WP¯ž¯ÍòãˆZµj 5õ’“ ÿîv“ÅuC Æt^•J…BaR:ŽX?¶ê;bÇ[bϾ³rå/èׯ›Íò31÷!„ú1c¦½ÇU[ßS.ü Ó¦±jb±e¿Ð|ž#m>È×C1ýÂܾS‘tÞÑÛÝÄ1@ ^ ÆŽ‚Ñ£gàÌ™ (**FVÖUŒ=_~ù)fÑ¢DŒ‡-[–¡mÛÁt¢£‡bÑ¢D>ü;äò¤§ŸÄ’%?#:z˜­ŠÂ¡  ƒOÄêÕóQ­ZU$&ÎÇàÁQPP(y^ݺE -í8^¾,@~þ+¤§ŸDDÄdL™2Zò¼L!2r Æ›ƒêÕß@Ó¦ ì&‡£é†Äè|çÎC°{w:ž={âb9þü3ÆÅbÈ>&¥ãhõc˾#fü±¶è;}úŒF—êg IDATvöu(Jܾ}ÑѳqåÊMŒó¹Uò³bú…˜1ÓÑÆU[ö HI9 ww7|øá»VIßlÑ/>ù¤+†Ÿ‚¿ÿ¾¹¼W¯ÞˆSÑ·ïÇVÉ϶ÔʬóŽÖî¦BÍÙ0þ(ôcTRxÂÛÇôχ‚)´ nÀ´=„Z¶¶k×!|ûí¸~ý|}k#"âSL™2ÎÎNL}üóÏY¼ùf5À¾}GðÍ7‹pãÆ]4n\ññSÑ­[½q­É!1ðñ©…E‹¾aÎMž¼>ÁÆÒ~ÏvçÎýX²d-.\øîîn jŒ)SF£GN’æc*¯^ÂǧbbF ..Újùé_ÇI7ã2‹ÑùŒŒLÄǯÁñãg T–¢A?DDôCtô0ÒwLÀØøclÑw’“`úô%¸u+¾¾Þøä“®ˆ‹‹FÕª•­’ŸÄôe¡8ì0bú…˜1ÓÑÆU[÷‹ððþˆ‰Þ½»Hž¶¹Ø¢_aöìÿ`ÇŽýÈË{ŸÚ0 ââ¢ááán•< a®š³_EÖy[¶»t{ ìC¡K!ž-Û|ð£ÖeŽ_â ÖE*Ç¡âPZZ ?¿p9ò š53ï½e¡"Bú  é„×k8œ5h´ÐKåˆZµ½ñø‘c7מ¼.õóº”Ú°ëèìÙ³ø*znݺEêPî i?ý´uëz“8ÁHß!t!ý‚@à¶þõ†r ˆ!hR?@¿Ìž3qßÎ@÷îöÛ´@0™¬êÕóÅŽ ö…@(W¾C èBú Ÿ²Í{¥Àëbô®X±u||±bÅJIÓ•ª~jÕö–$À ())áœöEç·\.GóÀ <}úT’<_g µ ûš>=¸|ù2:wî,¹\‚- é›¸sç8çûðÁ8¤ïº~A ¡öpV ”÷W Ç-ƒJ¥BÒúõ˜3g6V¯^ƒÑ£#!“Ùþ£ÆêGŠú ÅþÐóßÿ<þiiixúô)ªW¯HIIAXXªW¯nVžŽÚÎÖÂPyõ]ÓœÏÏχ‹‹K…«3@  ŽeªR©°té2„†½ƒ¦M›a„‰(,Ô~Ê!##»t½úh†Í›7‹Ž[Û»ŽÎaJ\ J¥‹/ÆÛ­CѤiS¬Zõ§@6lDëÐ0ø×«î=þ…+W®˜”¡ø–pøÈ¼Qµ*F ŽjÕªáÈÑ£œëÆò6T÷RÔ& ~Û˜Ãg`ûöÌïÌÌL¨T*dff2çþ»m>0@T›$&®FHÈÛð®ã£“×…‹ñVHÖ¬YÑßR=:WRR‚Éß|ƒ¦Íš£EË`$¬XaRúÖÆü캰·œ@ Á±Ú W¯ÆÉßO"yçœ>} …‹-MÓ ic¿ŠÆøñãqýÚUìÞõΞ;Ç\3÷áƒ<æøþûxtéÒEt\ÌßËpêÔi$ïÜ3§O#//îèÑ£øí×dü}9|Ð “&M6)Cñ-9’’ÖãË/¿MÓˆøbÖ­Kâ\7–·¡º—¢~>Ȧ,)ë‡~€‹/âŸþMÓ8}æ :vè€Óg΀¦iä=x€Ë—ÿƇ~ ªM~ÿãw¤¦¦âAÞ}Ny<ˆá»ßaĈ’ê™Ð¹~XŠ{÷rqìèQ:xÇ38×¥oî!$—Ð5¡¿…ÚÕZršR@ `4眿ü² ¿ûþþþ¨Zµ*fΌþ”溓“=|„'OžÀ××?,Y":®†ãÇ3°aý¬Z¹Â丰mÛ6,˜?õë×GÕªU1gÎlÎõE‹ÂÏÏžžž…‹YY&åc(¾¹Ü½{çÏŸGŸ>½½{÷Æùóç‘““#:oCuÏÆ’ú‘ ôìùoüúÛo€3g2‹Ì3ê;¶ï@¯^=áââ"ªMæÍ oïÚœsIII˜4y26ÿ² ÜUGKõLˆ_û sfÏ‚·wmx{×Ö©[KÓ7„wÁì)§£`è›ëÆÂPTCÁÃݽ¹Ôbпŋ|ÄÄ,@@@¸¹5CPPWìÚuȤ0úÊÅFLS±4¾Ôyé £T–bþühÔ¨<<Ü»w§[]©°¤ì€8³%éé'ÖÛ ÌûöA‹Ãݽ9Z¶ì†ýûÿs]L_NO?‰ž=G¡ZµT®Ü¡¡½°qão¢Ò±„ò¤R´…©”—ú±†nXŠ÷6?…·wÁ0µÝqýBLS(Oõ£ÁþØ1m!æ>øº‡,ÇÜÜ\¼Þž1:Z·B^^bÃú$œ8qvî‚wß{GŽa®‹ ×®]Ô©S”´^^^&ÅÕ—÷z T«–ö{Ž(..6)CñÍeÆxúô)êÕ€wÔ«€§OŸbý†¢ó6T÷l,©)0`¶oÛ…B/^ 4´5ž=Ž’’lÛ¾ ®M|}}uÒÿ)q5ú÷ï·ÞzKçšz&ÄÇáïïÏü®W¯纥éÌ›µ‚}˜ƒ5å´'ŽÇŠ› P( … 1pàx“ÂÐôMcúô±ˆˆègÛ•Q\,GÇŽƒ ——àðá_ŸŸ…­[ĺu;L —˜0ÆSÏR!U»ÇǯÆÞ½Gð믫ðôé9¬Y³³fýˆ³gMsž–Dz‹Õ[2oÞ ÄÇOÕ{=+ë*†Ÿ‚e˾ÅóççñÃÓñÅ“pùò &Œ˜¾Ü¥ËP¼|Y€={VãñãLlÚ´›6ý†¹s¹;–WÔ~HÓRÉ,RÖº!RÞ 4DGÏÆçŸ÷Ö9_ÑÛÝX¿F ™¥BÊúÑ Ol±¶Ûw^Çñýûœ¯¯/Μ>…y÷™ã~î=f p‹-°nÝZd_ÊÂìY³1aâ×Ì5cqÿùçD|9Ë–.…¯¯/gi±±¸€v‰´¯nݺ%zÉ5'® ùˆYÆ-æ(..ƶíÛuò=}êlÛ¶ ÅÅÅ¢ò6T÷RÕEQ’-  à¿ÿý/Þ MÓxûí¬]»înnêë"Û„/7üök2öîÙ‹+Vr®Y¢gnnn(,,d~?zôˆ“···7îÞ½Ëü¾sçŽIúeÉÒ{1×ÄümM9M)5ذá{8;;£Gá€=†ÃÅÅ6|oR>ùù¯˜¸“'²šì†X±b‚‚#!a4ðƒ«« ‚ƒ›aÏžÕ&…±%æÔ³5ó&)i'V¯žààfðôô@›6o!1qV¬Ø$¹þ¸ç\·npüø½q„úr|üúððp‡RY*­Àe”·~!sÚBå­ïXkß/ÄòâE>¢¢â°råTªä©sÝÑÚÝÑú…””Ç~aLLÅÚ÷©úŽ£õ Sá8¾ŒˆÀG}„/‡@£ÆM0vìXôîÝ‹™éëÚU}­q“¦X´x1–',g®‹{îÜŸ?aêøø2‡Ø¸€vÆ3** ¡¡¡èóI_´iÛ¾¾>¢gÄMÉGÌl­˜#i}† &xmØÐ!HZŸ$*oCu/Uý|õÕXüëß=9mcÉѧOäç£]»v imÛ¶A‰\Ž>}úHÒ&µkÕBòÎØ¹3?,]j±ž-Z¸GŽA`P ôí÷):vêÈÉÂøñðñ©ƒŽ;¡K— ggÑé[2Ã.暘¿­)§)å1•ÈÈAHLÜÊ9·}{ ú÷ïÁü:4%%%HIY HIY ¹¼C‡Æ˜†\^‚eË’0uªý'—/ßÀãÇOÜhÖ¬ –.]•JeRðñi7·fè€~ýÆâÏ?³uòƦֳ>fáÒ¥kر#€ºÍ/_¾„„Y&å%&ŒŸ_ܸq—“vöuäæ>4If©ÊnK«?ŽDNNêÞ{ïS´o? ø!'Gøµ(SúòòåðÙgÿ✫¨ýB ¦¶…>Êcß¤Ñ ©ò^ûÂÃCѽ{GÁ¼­Ý­_HEyíÆôÇÑê>èhýÂT¨9¦Ñ]Zw…g‰'jÖ¶ì3uBEâï¿ÿFÄ—Ãqêßí-J¹âíÖ¡€NŠŽSPPÿpdg@:µ@Ó4üüÞáCѼy#ðÕÆÞóæ§Ÿ¶àÀÿî]‰¢e57/}895FXX0–-›ààf¸y3‘‘ÓÑ¿L˜!:Lß¾c0iÒH„„áÅ‹|>ü;&O^ˆ„„ÙèÕ«³è0¶,;Ü¿ÿ;Abâ¾u†É»ŸkIl‡˜2å³Ü3gÍÂØ1cQR"Ç×1±lÞ³fÍ´Z~¯c]šã€Ñ£g nÝ:˜1c,Nœ8‹¨¨o‘•µß"JKKÑ´iglÞ¼mÚènri CËÞL¹¹UªÔÇŽmAXX0sîâÅ+èß?W®Fˆôô“?~²³Ó, cm222Ñ©Ó`æ]pkPZZŠ%KÖbíÚíÈÉÉCãÆõ‘#§áÙ3Ó_'[é¼¹úÃG*ç§)×Ë«%?>OOæÜ«W…ðönƒü|bûòž=é5j:ÒÒÖ£U+Ã_!©(ý‚ma+l}¿`cŽnØò~!_æF:!6v$FÄ‘‘-‹#¶;à8ýÂÔ0¶ÀVýBŒþˆÁ–÷SûŽ#Œ‡R:Š qðÏ48³™»Ì— Ÿû¹÷Œ†yÝê]L™òYîºuë¢[÷îP(èúÑG˜£1mZvìHå,³Û·§¢^=_³œ÷¦eÉCAݺÞ jÌ9׸q}β41a„hÛ6Dgù¼9a¬MfæEøúÖÆÙ³YV{ÐsrrÂäÉ£8Ó8qÍ›ÛïK¶Òysõ‡T:/ܾˑûöí\øûëNpˆéËÛ¶¥à«¯fbÿþ$£N âô 1˜Ò¶ÂÖ÷ 6æè†-ïBðe¾y3QQß"*ê[N8¶lŽØî€ãô GÄVýBŒþˆÁ–÷©îƒŽÚ/Ä"3„@ h1|8ÎfžÁ…óañâEððð0‰ !!¨U«RS!9ùú÷ïnÕü.ü Ó¦±jbh×.ÙÙÜågׯߟ_“ÂqñâÔ«§û9PSÃX“sç.aýúdœ?¿II;múþîÊ•¿ _¿n6Ë­tÞ\ý±'áá¡:i¥¦Ãûï¿£ÖX_^³æ¿9r*öî]ƒÐЖ¢ò¯Èý‚)ma+l}¿`cOÝê^ ïs†lÃÌÛÝ‘ú…#b«~!F ©îƒŽØ/LAh¿^h«ÍÇÈArTÜÃ"#bܸ9¨^ý 4mÚÀÒñO/))Gáîî†?|×jyˆeìØ!=zΜ¹€¢¢bde]ÅèÑ3ðå—Ÿš¦[·¤¥ÇË—ÈÏ…ôô“ˆˆ˜Œ)SF›Æ–bðà‰X½z>ªU«ŠÄÄù—>í3qqÑR‹ÆÞ±±#Ñ»w«åa »v·ßþ€ë×ïÀ×·6"">Å”)£áìì$:ÌÎû±dÉZ\¸ð7ÜÝÝÔS¦ŒF˜4Ä„±%C†ÄÀǧ-Ò~:tòä…xøð 6n”ö[¾ÉÉ0}úܺ•__o|òIWÄÅE£jÕÊ’æc*¶Òy1:fK„Þ-åÏ6íÛwß|³7nÜEãÆõ?ݺq?e¬/z‡õŸÎâÍ7«Uè~H×¶Æ}ÇÑtæ^ „ÐRnGjwGìbÂØ[ÝSøØ{Ÿ1m!æ>èHã¡t{ ìA‘s‘vóAc ŸxÕ‚•é× ó¥¥¥ðó Ç‘#¿ Y3û½ûM Ø ¢ó‚y¾C èBúÅëƒ5Î@ ¼×¾£D¢‚´Ð4Ÿ~Ú‚ºu½ÉÍŒP! :O ˜é;‚.¤_¡Pp¿JPXøÊâ‚Qd²F¨WÏ;v$Ø[Á&'̃ôAÒ/Æp6„@ ì½ßË#l ÑyÁ¢¢â°fÍTªäiVRÉ#Vçíµî¯«Ž•7mÜp„ç>R6ƒ5?¨þ*™a'LBÂ,\ºt ;v¤¶oOÁåË70‹ 3th JJJ’²’²ry †1)Œ¹,_¾Ÿ}ö/“âH%Odä $&nåœÛ¾=ýû÷0)/SåQ(”¸xñ † ‹ÅàÁ½L’Ùš˜Ó99y¨ xï½OѾý4hà‡œœ<“Ò‘ªMYç-i÷ò®óÌÑ1kBtÞ::ûÂÃCѽ{G“ãJ-·†ÆŸvpsk†€€è×o,þü3Ûäô_g“¢~l‰£ö¾!ŸasÊ|êW Þþžr´jýŽ¥"¯;uêÔ`ú«÷ï?BçÎC˜8‘‘3pøð&øø¯r²tsSÂÀîÝé˜8q23w¡F7Œ†·$/! áïŽìì¨S§hš†Ÿß{8th#š7×}çOв³7M DFÆ6‡ðŒk }årrj …â*d2Ú¶í ''22¶ÁÅ¥)JK¯›%‹¥ËDQç¥l÷ò¦ó¤èïRBtÞ2yô…9zôúöƒË—Óàí]Stz–Ê£SuÞVúöƒI“F"$$/^äãðáß1yòB$$ÌF¯^ÍÎïuÑ1kÔT”—qÃ^÷[ŽúìU‚”Ý(v-¡?–­ À×××Þ"”kHý¬¯om¬^=|ð9V¯ž¯÷FˆÛÌGªAzÏžtDFNÇo¿­²ÈH°D//Oôïßk×î ^FW­ZU½‹RÔMß„\~þ¹•+{aÚ´ïMê&û°KÚÂÃÃÅÅrÀ©SÉ8yrŠŠŠáéén¶<–ê˜#ê¼Tín©<öÐy@šþNt^?ޤó#GNÅ‚±ÌýØRç!•’“W¢mÛ¸¹¹¢V­8ðßHJZŒiÓâ-ÊÏIǤ®)Ç}8Ú¸a¯{>¤7lѦld@¡b¼#k¹Ä€&Ì'3ó"|}kãìÙ,{‹ض-ÇOÁ¾}?£U«æv•%2r~þyT*vìHµÉòRWW„„b󿥸å—Ýf¥AÓ79‡¹XÚþþ>¸};—sîöí\øûû˜-“8šÎÒ´»ØZç¥êïDç ã(:óf¢¢¾Õy(·Åù>¤Ôy©ô0mLhÛ67nܵ(?KqÂ’ú‘²Mõáˆã†=žô!õ¸a‹6eìp„]®^½Šwß}Wïo[qÿþ}IÒrH•¶Øõçëë‹N:©w¡gAÓ4:vìh’Â87öàܹKX¿>çÏïCRÒN»¿‡·fÍ1räTìÝ»¡¡-í*  ^ÂY«V ¤¦CròôïßÝfy«T*( ›åÇGжEZÚqιÔÔcxÿ}û½bçh:ÏÇÞínKw´þNtÞúðÈ5åöÜEÞžã¼ÄŒ /^A½zö{Žt$ÂÞõc G7©_8â¸a Z?€L÷”ý8~ü8Þÿ}½¿ ¦Á¯?¤§§s¤¥¥ÁÓÓþï†(((ÄàÁ±zõ|T«V‰‰ó1xðDÚEžE‹1fL¶lY†¶mCì"ƒ‘‘1nÜT¯þš6m`•<:w‚Ý»ÓñìÙ ËñçŸÙ6,C†ô±J~ƪ-¢£‡bÑ¢D>ü;äò¤§ŸÄ’%?#:z˜„ÒŠÇÑtÞÑÚ]ƒ-tÞÑú;ÑùŠ-t^ bÆ„nÝ"–v/_ ?ÿÒÓO""b2¦Lm™MÇ­~Äàhã†Géå­€³ÇÀ7˜¿U*~üñG´mÛøúë¯QX¨í8¾¾¾Ø´iÚ´ióÿìy|L×À¿“ub-ŠHDD"!¤ŠŠÚk+Š6-Š"Dh,MBÄZš**–ØwEµ¶(•àGuAÔKciUíªilYç÷Gš‘‘Iòfòf‰Ü¯Ï|dÞ»ïžsï=ç¼ûîÜw/µjÕ¢sçÎ\¸pAãüó<ìùï \¹r…Áƒãé鉻»;üý÷ßy-\¸ àééIxx¸Æ¨eaçóÓ+##ƒ¨¨(^ýuêÖ­KLLŒú\A:åäáè訑_î¿ÓÒÒ˜4i 6¤aÆLš4‰´´4ÉuüÃ?Ю];jÕªEãÆÙ°aCõ9tèP,X ‘fÁ‚ 6Lã˜>å ÔU ( AAéÚµºܤ‰7;·bèЃÈ{~ú×óSÀÂÂ>###“ÎÄ¢‡ IDATåyÿëÞ½ÑI |ð6÷ï?àÝw;LƤIÃY¾|3..Íyùe>úh4]º´aÞ<ôEaHm‹ÂÚ´~ý:,_>“áÃ'S®œ#GNeÕª(<ùóÏ?yóÍ7™;w.>>>üôÓOŒ=šC‡áää¤ÖKßr¤«@ƒ¾» '33''?öï_‡»û‹u³´!l^PÒ6/ä¥$ú…\»ìŽÝÆSë§Äýš{Wüúë¯ê¯ëׯgƌԨQC=0°{÷nL?ýôSœœœ(UªC† áÌÝñÈýpyüøq\]])W®œÖïqqq¼ñÆ(•JÊ–-ËØ±c9pà€F~S¦LÁÞÞ{{{&Ož¬äz^›6mbÚ´i8;;S¾|yõ €T âÛo¿eÊ”)T«VjÕª1uêT¾ùæ4Õ±••·oßæÞ½{8::ª´Õ€……C† QÏˆŽŽ&(( ÍÍ)ô-WQíA èJ¥bñâ T¯n_bnŠ‚’°yAICؼ@áE$×jV¹?}úTý÷õë×ó¼ßÿüd•*ÏF)ììì4®×•ÂÖ8uêÓ§OçìÙ³$''`ii©‘‡³³³úïš5krëÖ-ÎkãæÍ›¸¸¸h='E§‚¸uë–†N...yt*¨ŽW¬XÁܹsùâ‹/x饗˜2e ­Zµò_ŸÁßߟٳg³mÛ6Î;ÇÊ•+e+—œö tÃÂÂggG¶l‰6µ*Q6/(i›ò"üB>r->¨‰££#?ÿü3ýõ—úóçŸJÎØÖÖ–'Ož¨¿ß¹s§Àô… áïïÏ?þȵk×HLL$33S#?þøCão{{{ÎkÃÁÁ«W¯j=W˜N EÁÛ@ÚÛÛkètõêUI:åP¿~}–/_Ι3g˜X€ö  À[o½E@@µk×fذa:=´Îœ9“ýû÷S¯^=Þ{ï=Z¶l™oÚ~ø×_+++­ßfϞ͌3pssã½÷ÞÃ××7O>~~~´k׎V­ZáììÌðáÃu:¯¡C‡Ò¨Q#zôèA“&M4Vâ/L§?þ˜.]ºhÝ¡²@tss£C‡tèÐ:uê0bĈBuÊ¡]»vP§N>ûì3¢£³§Ðh«?](j¹@ @`þäŒ(¦¬¯jãÝ»T;ú46‰2cÇŽÅÍÍ€€­ß¥ m¥|]οHèS±»@ ú#×®ßÅnç‰õ“çv%Ð:oÀ8>|Xã}øç¿ tCÔŸàEæÎûØÛ7Öºwì®]û©W¯=Je]ê×ïÀwßý¯H²ÌmZcê#EVAiââŽÐ¨Ñ;ù¦ùá‡ãôê5’Ê•}(WÎ Ÿ®¬Zµ•Êt÷¢Ât–’æù}ååØç¸¸´{\ܺtL… Þ”-[Ÿ®¬Yó­Áõ‘ CÛ¼!ꧨH±ùÂâjjj“&ÍÅÕµ%vv¸º¶dÒ¤¹¤¦¦é”®Û0D¬+.eyâª1‘â§Rm>99…¸¸4ÇÖÖOÏvlÛ¶O#MIõ‹ÜÔ¯“[¹0†_Èmù£"gÀBó«iøñÇ©]»v¾ßº!êOð"<™?ÌûZÓ™380Œ¹s'òÏ?'ùâ‹p>úh4çÎ]Ò)ÿž=G°`ÁZÒÓ³×îHOÏ :z ={JÍGNŒ©YRõ™6mQQãò•5n\:µääÉXîÝK`ÍšÙlܸ“ˆˆ9²—K*…é,5Ju9ÏGWŠc»·mÛ—ÿ}ÈŽK¸sçk×ÎfíÚo™:U·•¢‹cÙ¡pÛ«~ä¤0¥ÄÕ=zŠ]»–ñàÁ¯ÄÆ.'!á,¡¡Ÿê”Š£mÈëŠcÙA¾¸j,¤ø©›ú4•-z‘ššF|ü:RRΰqãw÷WP*m©S§K–LgÓ¦]:å#…âhrźâXv0¯¸*)~*Åæ,X‹§§ÑёԪå„5^^îìØ±D¦$ûEõëäÒG.ŒérÙ†$T³/A¾»9‘œœBPP N¡téRyÎ>|œöí›këС9‡ÕYÖóƒ¥ú žN@€æhðÀa n}^{­ {÷Ò8väHžžít–%‡>ù‘3Ê®æ0 UNŒi‡r´{TTXžcvvJ224·–‹hórÖÏ3= kóRâªB¡ÀÂB³;iaa¡QÖ⟠iúĺÑ/ AQüBŠŸJ±ù­[÷Ô»@Y%Ý/ ë×IåEô 9mC²­Ú”ï¼ dd¤óäñcñŸõIIù—û÷ïøÑ—ÐÐOñóó¡cÇZÏ_»v—ê4múÍš½O­ZN\»vC'9}û†––Flìrbc—“ššFß¾!:åÉÙ³¿±eËn6oŽåܹKDGGšDŸÀÀ^ÄÄlÔ8¶ys,þþt’%—>¹IOÏàôé ôëJïÞ]õÎÇ\pph‚­­;..Íy÷Ýaœ8‘¨sÆ´CC¶ûüù«ùàƒ·uÒ¹$Ø|úÔ1‘W{8¤¤ßIMM#)éw'h<ÇølÛ(J¬+I~an<ï§RlþܹKܹs/¯ŽØÙyàîÞ–9sV••¥NSÒý¢°~^T¿Ë6$‘kà¿] ÞB™jËúõäfFXXX`ckkj5fŒ••Ö––¦V£è˜Ç ½V¢-tÛ•àÀŸéÑc(çÎíÅÞ¾2ý‹@îw·--ÝHO¿ˆ……¾¾=°´´àðáMX[×!33I/]Ÿ—¡+ýu›6mú3ÀÀ ÄǯÅÁ¡ªÞùEŸ‡S£†‰‰{¨V­ *• '§¦ìÛ·†ºu]õ’%GšÜ¿ìx{{pøð&½9(j{é’O~izôÊèуðöö$99…øø3f&ÑÑ“éÚµÁô)]ìP®vؾ=ŽQ£¦qìØ6*UzI/Ý_D›ÏÁÔõ#%)q5--víúqðà/êëZ¶ôeÏžUØØXKÎG.¥bl¿0—XgÎ~aÌ.m~*Õæ5òbîÜ xy¹sùò5Ãñ÷ïÄÈ‘ýÕiJª_Hé×éÊ‹äRlC®] vïü–TÛTöýú=ÝÏŒš­Wæ9cÊUÎyÉÐ…AƒÆ1cF¨úæ¡ ;;%OŸ¦Rª”?ÿ¼€GSª”Ro]‹Ú±pt¬Ê’%ÓiÙ²7¬/Ò @Qõ)S¦þþY¾| & ãÈ‘*T(¯õ†'U–/•ê2iié$&&1räTÆÿœyó"$_ÿü”ÑÜßåêêÂÖ­ ÕW©R‰ž=;S¹rEFŒ˜¢÷À€1íP®vß±#ŽÀÀpöî]¥÷C¯TYùa®6E«cÚ¼”¸úÉ'Ó±³SrîÜ^\\œ¸råOFšFHÈ æÏŸ$9])n~QÔX§«>ùaÎ~Q áùù©›W*m™?yP¿~/ž†¿°z` $û…”~®¼H~aÛ‚ÆÀÀß÷îT˜@ èÃåË× šHPÐDã¹GZkÔpàêÕëxzº©Ï_½z5Œªëó;vGǪ?~†fÍ™T—ÀÀ^të6„ñãƒØ²e·Æ9Sbcc··ë×Ï¡AƒN:u–sßxåü•HN|}½¹té“ê`L;Ü´)–?žÄwß­¤Aƒº•UæhóE­cÚ¼”¸ºqãNΜ٭~€ððpeåÊYxyuT?$‰øœMQbœ˜£_¹ý¢ ?•bóÕ«ÛkØ;€›[M©à%Ù/¤ôëŒ9ù…©lã¿•3²ç«ÄG|ÄG| üчü¶Ë}óðóóɳpÌîÝyóÍ×õ”ZtβjÕVNžÜÅÊ•_ëõ®¹œx{{P¥J%vï>ÈÖ­{ð÷ïhR}ž'++‹ôôtS«!;§O_ÀÙÙÑdòi‡K—~Å AãØ¹s)>>õ &G*æfóæV?…!5®j›˜—{Á-Ÿ51u¬37¿07¤øia6ߤ‰7‰‰š¯$%ýŽ“S5õ÷’ìRúuÆÆœüÂØ¶‘cÎϾª²­\|ÄG|ÄÇÜ—Y³bˆÿ‘ÔÔ4ââŽ0{ö2‚ƒûLfA<|ø˜Þ½G±dÉt*T(OLÌtz÷ÅÇM¢O=>| +¾D:µL¦G›6}ؾ=Ž’yú4•'é×/”>}º™L'9èС?{÷âß’’òˆ¸¸#ôï?†°°!&Ñǘv8kV C‡F°aÃ\|}½eÏ__ÌÅæÍµ~ BJ\íÞ½†qþü%RSÓ¸xñ ãèÑ£½Nùcú…¹Æ:sñ sCŠŸJ±ùaÃú0dÈŽ=Å“'O9sæ"C†L`À€÷ÔiJ²_˜+æâƵg}ó\‹Úààèla@ðŒ†¯¾è¶ø 6´M7Ûµk?cÇÎâÒ¥?ps«ITÔ8:th^$9úÒ§OU˜5k¬úؘ13¹uëkÖÈ¿¿®T=zŒƒCBBˆˆ6˜mÛEån¯Ã‡µ”C‡Ž’‘‘I­ZNôïÿ.ÁÁý°²2Í …é,%Í×_ÇìÙË9uê&Nü‚¤¤ßqt¬Jÿþï6D£ÝKª_hÃ^4'¿(Ì6ä[|ðžÚ¦÷ë÷ÏlSmpp¨¡Wæ@ ï×|€¢ ô#33''?öï_‡»»a÷@ÌaóA^„_y)N~!×À@ìñ¿~Ÿó*@ ^tT*‹o zu{³¿á r l^ È‹ð /Â/rïJ ‚Ë—õÛ3S æ……+ÎÎŽlÙmjU£ l^ È‹ð /%Ö/T¨—ÐØ®°i³’®_´h'OžTïÖ­íÛ·/àŠ—ððpîý·Íc57™.¢]àÊ•+¼ßócŽŸÈ…– 1ª,ª$T1QðVgȵ‚¬AH~€õg4Ù²œN”Ë¥Rš bj³pG,¯¸jß'U S¿»'aóA^„_y~ñß®ÙFÒ~ùå‡ÏråÊÑ¢E ù5+&899©ÿ¾~ý:Ož<1‰¢]²©U«/W* ùnŒ—J‘ÊÒ†øëOlÃi²yÝ-5ÒUð]T{íu1( @ L‚â¿ç&«ü¤¥¥±víZvïÞÍíÛw¨YÓ™-ZpêÔ)tÝ»wG©Tæ“Ë‹»»;¿þú+½/íÑ£GiÞÜp«‰Šv)iùœÉÕ]ÖPýu²2ÁÂ+geÁ[”žŠß¾oim ¶ÏAœÏ„ZïõbÎòåòË@ кøà7ðñiD@@Ç_%%å%ââ~aРAìØ±ƒÌÌLêÕ«‡¯¯¯Q67êÕ«‡"×/ÏñññdeeD–hi(HEcÆ€*²þD‘yW.Ò0óÊ/œ‘¡ð×5ù¸yÅŒñ4‰ßNk(ûœ—%gÁ¡tèÚ·/666òË@ ÈõÈòìAêÃûpýú]BB~‚aÃv2yòoôᅥ›7ïpôè1*UªÄG}¤ñP\yùå—ñððP¿}û6qqq‘%ÚEÒAõEæ^Ê:ˆ§â­ïÐÜ*  ]nýφE”ïü–3ÃáÒHËo¦üv»°¡´ûî+:[eQFËÐÛIÛÒ ùb­[·)º”+ç…OWV­ÚŠJ¥ùêÉ®]û©W¯=Je]ê×ïÀwßýOã|jj“&ÍÅÕµ%vv¸º¶dÒ¤¹¤¦¦é”®´¿²ÜH‘•_…â­Cë#E){FF&Ó§/PÛ†—WG¶o7Ì=A*qqGhÔèËUX)mZ’Û 99…¸¸4ÇÖÖOÏvlÛ¶Ï úÈEQÊ.5‹üìP©¬«N#ÅOãâŽÐ¥Ë`*Tð¦lÙúøøteÍšoóÈq>ÿz6„>rane/*Râ¼}©÷¸’ꆈ‡†/û³>pžÇ–Ý»wsàÀ~‚‚vP»ö³)ñ …_ß>ôêµÄijtéÒ…²eËXÑâA—.]4Ä·oßÎÙ³gùüóÏiÕª5žžõèÔ©+W®$##C/¢]tÃ2ëÕ²Žámñ­­Òñ³RQMV °P@)x+²hÿï¼—|NÅÝP,ø ~;™úµIç)9Šv?}O[«,l´ŒÍ\̈́ۮuù8x8––xÁ ùúü~'îPLɸqQtêÔ’“'c¹w/5kf³qãN""æ¨Óœ9s‘Ø;w"ÿüs’/¾ç£FsîÜ%uš=zŠ]»–ñàÁ¯ÄÆ.'!á,¡¡Ÿê”zöÁ‚kIO϶Ëôô ¢£×гçˆ"Ö†~²¤ê£R]Îó1„>r!WÙ£¢–°sç~¾ùf÷ï'°té "#çqüøÙu–Ê´i ˆŠWä4RÚ´¤¶ûÓ§©´hÑ‹ÔÔ4âãב’r†ç±bÅÙõ‘ ¹Ê.%m6>ŒþýßU§‘â§mÛöåß²cÇîÜ9ÆÚµ³Y»ö[¦N}¶byIŽóRêY.}äÂÜÊ.'…Åp¹ú6R|§$û…\ñИeÏMž­[·R­Zmœ}´^ШѨT*~úé'ƒ*Vœ¨Y³¦ÆÔýЬٛŒ;–[· lYoΟ¿Ë€xóÍæ¤¤¤è,C´‹t¦NÊËv)x[¥òª%¼¬õ…™lãI ,U4ÿë2ž‹g¢Þ–͇Guz1Åô0Z;È›ÖÙÏ“’ß§+ˆ˜õ™Îe*ÎÌ;õ £O,'ôÄ2FŸ0íš ‡o¢wï®8:VÅÆÆWV¬˜Å¢EëÕi¢£×0fÌ`Ú´iŠRiKÛ¶~„„0þjušM›v±|ùLÜÝ_A©´¥NZ,Y2M›vé”V¯þ+++:u@§N±¶¶fõêÏ‹XúÉ27}Œ)KJš•+¿fÉ’éxy¹Sª”7$&f ¬•]g©<¸-9±(Ží¾`ÁZ<=ÝˆŽŽ¤V-'ll¬ñòrgÇŽ%²ë#r•]J<4%))ˆ‰ÙÀ˜1ƒÕǤøihè XO³f°³SR·nöý":z:ˆóÏÐVÏré#æVv9),†ËÕ·‘â;%Ù/䊇Æ,{nþ{dz6…àîÝ»”*U)ß ¬­íP*Ksÿþ}ƒ*VÜøàƒ¨Zµ*üKËrŒœ‘#ã0`-aaG6l'§N%2jÔ':ç/ÚE:¯¾öß:Ì ûê\Ï‚¬ü6(ø+ ²|3Óèzéµ£Â)Óñuë—Â_f/&X¿¥ÌèÁô8²—ÖV*ì´ d¨à‡ ˜¾åZ´h©wÙŠ#OUé<"Ǫ4å»0¤t 1¥*gDàðáã´o¯¹€h‡Í9tèh.XXhŽ8YXXhÌ’’Tž5HŸW…' @óׄÃ>ûG(7£¶g=YÊWìÈ©;muh"ÒÓ38}úýú…Ò»wWõñk×nàâR€¦MߣY³÷©Uˉk×n¨Óö$0pII¿“ššFRÒïNÐx0’úö !--ØØìÙ±±ËIMM£oßò‰ŽŽäìÙߨ²e7›7ÇrîÜ%¢£#u’%U‡&ØÚºãâÒœwßƉ‰:é+gÙ{³QãØæÍ±øûwÒI–”4NNÕ¸té Y‰‰I\¿~K'Í)mjNínL›?wîwîÜÇË«#vv¸»·eΜ:/F\m^J<4©©iÌ»’qã‚4Žëë§óç¯æƒÞV/éq>‡üêY ÅÑæsS”²¹ú6R|§$û…\ñP®²ëŠbÊêñª6 ÛbóÔ–%ËW‘œœÌ–-_ãï?‡–-ƒó\°n] /îàÊ•K”.]Ú ÊGzõêÅ Lž|QëùŒŒT‚ƒK3cÆtÆŽ›ç|ff&7oÞ$))‰ÄÄDΟ?OFF†h=9‘@ÂÏ?±xd0õ-A©Ã`ÛSÜQÁ9»²Ü¨Û€ô~C¡C7ÈYàØ(¦‡áŸø M¬Ty¶$ÌÍ÷ÕkóÙŽX\]]‹V bH£$¤gßDT™*ìÇŸàæÍ#zå§P¼¢×{ËÏ瑃··‡o¢téRXZº‘ž~ |}{`iiÁáÛ°¶®Cffiié´k׃QçÓ²¥/{ö¬ÂÆÆZr>úè]”²ÿõ×mÚ´éCLÌ4'¿‡ªzËÊ/MC=zÞÞž$'§ÿ#cÆÌ$:z2]»ê·èfQÊþðácjÔð#1qÕªUA¥RáäÔ”}ûÖP·n^Ÿ,JÙ£¢–²cG‹Må•WjpöìoŒ1…£GO“‘ñ›^úË…¡ÛÔÜÚŒgó––n4jäÅܹðòrçòåk†ãï߉‘#ûë¥{q±y)ñÐT,^¼={þǶm1ÇõñÓíÛã5jÇŽm£R¥—€’çs“_=ëJq±ùÜÈUv¹((FÉÑ·‘â;%Ù/ ó“õÙŒT®\E¯<»t{Ÿzõ»}+iviìûuVÏ',_¾<^^õÙ´iwï^¡U«áT¬Xƒ[·Î³sç$Nœø†õë׋‡Ï|xòä ¥JUÈ÷¼••-ÖÖ¶lÞ¼™ÿý—òåËcccCZZ>äîÝ»Zaí¢¯¾ö ½½QYYñåø0ê?L¦œâÙ”™‚P*À p|šÂÝ?püÔ1î¯^ÈÓÀ°´ä¥ÈQt¾y…×­TXiÉ/S·² .<_kT"ò çŒm«Ÿ?ËR÷…Ju™´´t“9r*ãÇμy@öTѧOS)UÊŽŸÞ À£G)UJ©¾þ“O¦cg§äܹ½¸¸8qåÊŸŒ5ÌŸ?Ir>úè]«²dÉtZ¶ìÍëó½)J••_š­[ªÿ®R¥={v¦r劌1EïÄ¢”½L™Røûwdùò-L˜0Œ#G¨P¡¼Ö΢TYù¥ù䓨T*zôʵk7ps«IDD0ƒ×K÷çm¿¨6 /RÚÔÜÚŒgóJ¥-óçO¢Q#/êׯÃâÅÓð÷Ö{` øØ|áñPä²ùÌÌL>ÿ|)ë×ÏÉsNW`ü¯ IDAT?ݱ#ŽÀÀpöî]¥€’çs(¨žu¥¸Ø|r•Ýq^®¾ß)É~!w<”ª\Xd |v@¡Pп8th!ááµ ²bòäú\ºÏâÅ‹éÕ«—Ñ,nxxxpçN™™éZÏÿý÷5RSóÒK/qïÞ=._¾Ìùóç¹|ù2·oßÎwÚ¡hý±°°`pàÆÎÏ6ü©Ê~hÏM~ã9¯Ø[@»¬Tü~Àeˆ?åGô£ÛËøXjHSÁOéäÓŒöaX¸|…ìå*n¨2u›R«qís+œeÅóll¬ñöö`ýú9¬[·]}¼F ®^½®‘öêÕëÔ¨á þ¾qãN–-û”ºu]Q*mñðpeåÊYlܸC§|LÁ±c§qt¬jôUò}}½óL?4&½X¶lYYYlÙ²[cz©œXZZ2fÌ`.^ŒãÉ“sœ>½{ûÊÔ­«ßÚE]áßHiSS·;Çæ«W·ÇÓÓM㘛[M§Îʉ±l^J<Ô¹l~óæÝ8;;Ò¸qÃ<çtñÓM›b80Œ]»–Ñ ævt"Î\ÏÆÆX6Ÿƒ\e7Fœ—«o#ÅwJ²_ÈEÎX€ÆŒ.]ºÐ¸qc^~ùe {u÷øøxnܸÁ+¯¼BëÖ­)W®œÑ•-N <˜Ù³¿`ïÞYtì8AãœJ•Å7ߌ¥lÙòÔ¬YSR~ŽŽŽ¼öÚk¢]d OŸ>88TcÛúõœ^·Š:Ù[Bîå7ó’óÜo­€W,¡\V:gSà­Dëš²`_:<ªU›õËWˆ™ä0£5rÈÊÊ"=ýÙ@žŸŸ{÷ÒèäïÞ}7ß|]ã:mEɽ0ŒÔ|ŒIBÂYV­ÚÊÉ“»hÞ¼'Í›7æÕW="ûôé 8;;E–6¼½=¨R¥»wdëÖ=Äǯ3šì… ×ñ&ÏXHiSS·»±l¾Io“Ô3’’~ÇÉ©šì²¤bL›/,š‚™3óÅá…'üm~ºtéW„„ÌàûïWããS?Ï5"Îë^Ï†ÄØqÞœÊ^rõm´ñ¼ï”t¿0Çx(•\»¨èÔ©“úá jÕªôêÕ‹ÐÐPºuë&>%àììLDÄD¶oŸÈªUqíÚ >¼GRÒaæÍ{‹cǾbäÈáøùùáé鉳³³úãááÁ믿ÎÛo¿M`` QQQDDDˆv‘‘Ö­ÛðEÌÆq,y¬*xPr¼ãid¨=?(ðT éðME&ïÝÏÁ'Å @F ‹Â+Ú´iÓ‡íÛãxð ™§OS9q"‘~ýBéÓ§›:Mpp_fÍŠ!>þGRSÓˆ‹;ÂìÙËî§NÓ½{; ãüùK¤¦¦qñâÆÑ£G{ò1&>¦wïQ,Y2 Ê3Þ½GñðácÙeuèП½{ñï¿IIyD\Üú÷CXØÙeéB``O†ŸBÅŠ/Q§N-ƒÈèÖm‰‰I¤§gpõêŸOæÂ…Ë ú¡Aä )mjnínL›6¬C†LàèÑSûŒiÓ¦ñðáCõñ*Uªòå—óxÿý÷M¨ ‡Ʊ3f!Õ- ª*(žÍ PÿsìåLø[ƒìž»“?¤CãQchùV;Zµjehõ‹ Ö æxêÕì÷2²TØO< è¿ø`Q8|øQQK9tè(™ÔªåDÿþïÜ++Kuº]»ö3vì,.]ú7·šDE£C‡g[ï<~ü„É“¿dË–ï¸qã6UyÿýNDDcg§”œ1éÓ'‡*ÌšõlÑÓ1cfrëÖ=Ö¬‘w_ܯ¿þŽÙ³—sêÔy”J[<=Ý B§N¦ÝªóÑ£Ç884!$$€ˆˆ¼‹¸ÊÁÖ­{ŸÍ•+×pt´§{÷vDDS¾|YƒÈ“‚¶->ŸŸ®ZX)mjnínL›ضm'~ARÒï8:V¥ÿ÷ ¢[Œ1l^j<4&~~þ„†âwÚj=/ÅO Ú÷îÝã¼ürözR%5ÎCáõl Œaó`~e—çåèÛH½Ç•T¿0f<”oñÁ¯IU¦wrŸ0$>äðáÃê)ÿo¼ñ666¦VKð)ÿþËÏ?ÿ„Я{w,Ÿ>¦²jZ@E‹ü¯;Ÿ™½ýaßÿ3àût˜¶víZ.%%a‡Š}›6òï•ËTP@² RTð›¾o¶dÜ„ b&HAX( 3+;ÌXÅW/®8;;²eKtቂaó‚’†°y hˆA>ôéÓGý÷[]ßáþý{lÛøG֬ƭ¶áËVŠÅ%ðŠee²Jý7[ KÅ M« Dbn[ý †Fؼ ¤!l^ Ѓ\ó¬´Ïñêk¯Ðö­v,X¹ÒÄÚ/¾ê9]ã{µ0Ómß%@ ²É=PÀk@ @ ^t,Tˆ÷~@ @ (Iä̰xöUÚËŽŽŽQH ¢‚ü)hÿi)i’“S ™‹KslmÝñôlǶmûäTQ2 Å+Z?Je]­éïܹ½}ã<åKMMcÒ¤¹¸º¶ÄÎÎW×–Lš4—ÔÔ4t»ví§^½ö(•u©_¿ß}÷¿"ëo,ŠÒî™LŸ¾@]?^^Ù¾=ÎàúÈEQÊžŸ™Š¸¸#té2˜ ¼)[¶>>>]Y³æÛ<é ³Õ~8N¯^#©\Ù‡rå¼ðñéʪU[Q©žõw QöâÒî]×½S`š’r“_\5&RïRî_%¹M¥Ø¼”4ºP\êGJÌ4&Rû-9ä§/ºÍgí+^% ŒÄ1={Ž`Á‚µ¤§gžžAtôzö¡Sš§OSiÑ¢©©iÄǯ#%å 7ÎcÅŠ-Æ-ШT—ó|ÂÇѿÿ»ZÓOæÃßÉs<$dGžb×®edÇŽ%ܹsŒµkg³ví·Lúl¥q)¶:n\:µääÉXîÝK`ÍšÙlܸ“ˆˆ9òä({qm÷iÓ5._Y%9&ä&¿¸jL¤Ü ¤Ü¿Jz›fóRÓÈ¡³\ÈU?Rc¦±ÒoÉM~~ú¢Ú¼!¹¸sçãÇÇ××ggg<<<øðÃÙ¿±”£+ŽŽŽy>憹Ö]Aüõ×_¦VÁ¨˜ªV¯þ+++:u@§N±¶¶fõêÏuJ³`ÁZ<=ÝˆŽŽ¤V-'ll¬ñòrgÇŽ%Õ_*))ˆ‰ÙÀ˜1ƒóœÛ±#Ž_~9ÉäÉyo›6íbùò™¸»¿‚RiK:µX²d:›6íR§‰Ž^Ø1ƒiÓ¦)J¥-mÛúÀüù«uÒQJ=Ë…\í¾rå×,Y2//wJ•²£qã†ÄÄLcÁ‚µ²ë#r•ÝÜ ÄëiÖ¬vvJêÖueÅŠYDG¯Q§‘b«‡o¢wï®8:VÅÆÆì|-Z/»ÎŵÝÜ@‹ó•U’cBÅUS¢í^ åþUÒÛ´0›—šFåB®ú1fÌ”‚”~Kùé‹jó†@ üÇ­[·èܹ3J¥’µk×rñâEŽ9ÂG}ÄòåË‹}ù믿4>愹×ÀpmôÚk]Ø»÷Ʊ#Gðôl§qL¡Pø]Jš­[÷Ô[o] Í¢Eëi×îM\\œ4Ž''§ÁÂ…S(]ºTžë š!ßÂÂB£ü‡§}ûæi:thΡCGuÖSJ[ÆàÁáhþj3p`ƒ‡ë,«°4ׯߢvmcõêÕæ§Ÿ~ÕYo9ÊnL›77¢¢Âòèhg§$##Sý½(¶šó ŒÜ7›—‚¹ÅcûEaqUW䜬í^ åþenmjn6/'ÅÑæµQ”˜Y›—ÒoÂýôE¶y¹É30••żyóðõõÅÃÃO>ù„Çk¤Y¸p! 4ÀÓÓ“ððpÒÓÓÕçYºt)>>>T¯^€+W®0xð`<==qww' €¿ÿþÛÀEÓ¨¨(ºuëFDDnnn(•J*T¨@›6mX¿þÙHYaõ“––ƤI“hذ! 6dÒ¤I¤¥¥É.^Ìv(cµ‘££#kÖ¬¡I“&Ô¬Y“V­ZqôèQ6oÞŒŸŸµjÕ¢sçÎ\ºt‰þù‡úõ드œ¬¡ë?ÿüCƒ HNNÖ˜yQno¼ñ/^T§Ý²åÙÔ¿‹/òÆoÈW™BjéJ``/bb6jÛ¼9ÿNêï}û†––FllöDlìrRSÓèÛ7D§4çÎ]âÎûxyuÄÎÎw÷¶Ì™³‚¬¬,½õ—‹ÔÔ4æÎ]ɸqAyÎ…†~ŠŸŸ;¶Ðzm``O'”ô;©©i$%ýN`àNäµk7pqÉŽM›¾G³fïS«–×®ÝÐIO)õ,…èèHΞý-[vÙm~îÜ%¢£#u’%%“S5.]úCC~bbׯßÒIg¹ÊnL›pph‚­­;..Íy÷Ýaœ8‘¨“¾†fþüÕ|ðÁÛêïºÚjzz§O_ _¿Pz÷îªqN޲G›—‚¹ÅcûEaqÕTäw/rÿ2·657›—‹âjó93…”~ î§/ªÍÅ”ÕãU­´Áö© >›²dÉâãã‰ŠŠ¢|ùòLœ8‘J•*1iÒ$ û¡©Y³fÌ;€‘#Gòúë¯óÉ'Ÿ¨Ï·k׎O?ý”ªU«ЦM¦L™Â«¯¾Jzz:³fÍ"55•¨¨(ƒN¼½½Ùºu+µjÕ*0]aõEBBsæd¿3|øp7nLhh¨¬r ÑŽŽŽT¬X‘'OžàììL¯^½øè£°´´Ô§JeÇXmäèèHëÖ­™:u*•+WfÙ²e,X°€7ÞxƒÈÈHõ±C‡ñõ×_†““Æ Sëͽ{÷ˆŒŒÄÑÑQ=û¢ ÝÆ»»;}ûöåæÍ›´hÑ‚„„Ê”)ÃêÕ«ùí·ß˜>}º!ªV6¤´QµjÕ¸yóˆä|>|L~$&î¡Zµ*¨T*œœš²oßêÖuÍ“^¡x¥Ð÷„óKciéF£F^Ì;//w._¾F``8þþ9²¿d ÁâÅسçlÛ£qüÀŸéÑc(çÎíÅÞ¾2·|iié´k׃QkÙÒ—={Vacc d—==ý"øúöÀÒ҂Ç7am]‡ÌÌ$½t–Òñ×_·iÓ¦11Ó œ@|üZªê-+¿4QQKÙ±#ŽE‹¦òÊ+58{ö7FŒ˜ÂÑ£§ÉÈøM/Ý‹RvcÚ|C=zÞÞž$'§ÿ#cÆÌ$:z2]»¶ÑK9Ù¾=ŽQ£¦qìØ6*Uz ÐÍVsÿbåííÁáÛԿ*¢ìÅÅæ¥¤1·˜`L¿Wu¥¨×çß½@ÊýËÜÚÌËæuM#…âbó¹Ïçð|ÌÔ•¢”]J¿EŠŸ¾¨6ÿÙŒT®\E/ù]º½O½ú ØõíRí2ˆ?µ/ïÀ@óæÍY±b¯¼’mwïÞåí·ßæ—_²ÅÑÑ‘P»vm û—Ìþýûóã?ªÏÿòË/ê_©µ‘’’BË–-9~ü¸^…1ÎÎÎ\¼x¥R©>–û—Þœ»Âêç7Þ`ÕªUêú¹pá P×\r Ùiiiœ?^ý«zdd¤¤:44Æj#GGG~ýõWªTÉv¶'OžàêêšçX½zõ¸|ù2—.]¢W¯^üøãXYY‘‘‘ŸŸ[·nU¯Õ E·ï¿ÿžo¿ý–E‹±`Ábbb £W¯^ 2„=zжm[ƒÕ¯Hi#}† ™@õêÕ˜0a?üpœ  ‰œ9ó<Šç¢téz<¸F¼ÔÇNŸ¾€¿0.è¾3ÁóÓèô½‘dffR§NÖ¯ŸCãÆ 5ιº¶$4tC†ôÒ›[ÖÇGråÊ5fÏ‹‹W®üɨQÓ¨]Û…ùó³ÍÊ”©Ï;G)UÊN}Ý£G±·oLJŠn‹ðÉÉáÃÇhÙ²·ú½sC™™ÉìÙËY¾|3×®ÝÀÍ­&Á 4žt@ŒeóÚˆ‹;ˆSHLÜ«óµrÙ¿hÝ©S§ð÷÷ÇÃÃGGGÜÝݹsçŽ^1+VÌSNmïÙV?·nÝÒ¨ú‘K®lllhР ,`Ó¦MyΛ cµ °³³ÓzìéÓ§¸ººR§NvïΞ‹ÖÅ Ò­iÓ¦$$$ðÍ7ß0gÎuýŸ8q‚¦M›J©&“"µô!0°Ë–m"++‹-[vkL£““êÕíñôtÓ8ææVSç)g9ȵÒûæÍ»qvvÌÓ¸|ùAAól·–ûæ¼qãN–-û”ºu]Q*mñðpeåÊYlܸC¦F ®^½®‘÷իשQÃAo½åàØ±Ó8:VÕy‡]°´´d̘Á\¼Ç“'ç8}z7öö•©[×tÛ“ËæµáëëçÕ ©Èeó›6Å2p`»v-ÓÝmÕÆÆooÖ¯ŸÃºuÛ ”[”²Ë…1l^ æŒåR⪞÷…¢úFA÷)÷/slS0›7GLq/Ð%f>\6/¥ß"ÅO…ÍKG=0 úoCGGG~þùgèþüóO‹þøã¿ííí5Î?¿8BPPþþþüøã\»vÄÄD2331'š7o.é!¸°ú±··×¨Ÿ«W¯jÔ\rÀðí`aa­­m¡º cµ‘>°lÙ2–-[Æ!CtÖ­téÒÔ¨Qƒ;w¢T*iݺ5ìÝ»gggJ•*úÂG†Fj郷·UªTb÷îƒlݺÿޑӤ‰7‰‰šSË’’~ÇÉ©šAäIeæÌÅŒ?Të¹ü¶[{þ&¬m+âÜqÂÏÏ'Ï"G»wäÍ7_/¢öú“p–U«¶ròä.V®üÚ¨ï¾/\¸Žwßí`4yÏc,›×ÆéÓpv6ÝÎ4K—~Å AãØ¹s)>>õóœ××V³²²4Öãц©ËnJ›sŒ Æò ©qÕØt/rÿ2Ç65'›7GLy/3 Iaý)~*l¾`Tÿý-‹öíÛ—Ñ£G“””Dzz:.\ (Hsq“ÈÈHnݺŭ[·ˆŒŒ¤{÷î |òä eÊ”¡T©R\¿~1cÆÈXy eË–-L™2…¤¤$ž>}Jrr2qqqé «Ÿ®]»ÁÍ›7¹yó&¼óÎ;²ËùÛaèС\¸pôôt’’’5j;wÖ© ‰±ÚHš7oÎÇY¹r%¥K—¦^½zZÓ¦[Ë–-‰ŒŒ¤GtïÞððpZ¶lY$ýŒ…Ô6Ò—ÀÀž >…Š_¢N‚ךЗaÃú0dÈŽ=Å“'O9sæ"C†L`À€÷ "O ±±P*miÝZÿ(»woÇÀaœ?‰ÔÔ4.^¼B@À8zôh¯NÜ—Y³bˆÿ‘ÔÔ4ââŽ0{ö2‚ƒûÉQ yøð1½{bÉ’éT¨Pž˜˜éôî=Ї~±Žtë6„ÄÄ$ÒÓ3¸zõO‚ƒ'sáÂe†ýPvYº` ›ïС?{÷âß’’òˆ¸¸#ôï?†°0휆fÖ¬†`ƹøúzkM#ÅVÛ´éÃöíqhóÔšFýL­@ xÁÑwñAÈ^tÉÉÉýû×áînúµ@`h„Í y~!(i›<\‹îüv3©vì?—=c@¢À‹ÀÔ¨T*/Þ@õêöâ¦((›ò"üBPÒ6/049cV&ÖC $aaኳ³#[¶D›ZÀ(›ò"üBPÒ6/0b`@  L½´@`l„Í y~!(i›‹ìÅU*в„@ @ ‚ì-!óÙ®P @ AÉá¿bÊ€@ @ %…gcÙ ÅÓÀt´Wp\Ü5z'ß4qqGèÒe0*xS¶l}||º²fÍ·ÓGn¤È2fÙ‹‚}RSÓ˜4i.®®-±³óÀÕµ%“&Í%55M#Ý®]û©W¯=Je]ê×ïÀwßý¯Hº—6…Âmþ‡ŽÓ«×H*Wö¡\9/||º²jÕVTE¸¡›Ã~Ýr!¥~rö(þS^$ËÍ;÷±·olr‘¢³ˆÆE!?T*뚦¨r͉ÉÆÌ­O’£SA:Kí“$'§2—æØÚºãéÙŽmÛöé­—9Øa®7 Ä«À´ôì9‚ Ö’žž@zzÑÑkèÙs„FºiÓ5.ß|Ú¶íË¿ÿ>dÇŽ%ܹsŒµkg³ví·LªÛ*¾Rõ‘)²¤¤‘«ìr!EŸ=zŠ]»–ñàÁ¯ÄÆ.'!á,¡¡ŸªÓœ9s‘Ø;w"ÿüs’/¾ç£FsîÜ%ô)Žm …Ûü¸qQtêÔ’“'c¹w/5kf³qãN""æÈ®sqDjý¨T—ó|tåEµ±ÜOæÃß‘©úS˜Î"n'nÈ…6ÿ FÿþïšNWÌ-Ö½¨6fn}(\g)}’§OSiÑ¢©©iÄǯ#%å 7ÎcÅŠ-:ébnv˜Å”ÕãU­´Á걯7ifj}Á NµjÕ¸yóiié¬\ù5[·îaß¾hÛÖ=ÚÓ¿ÿ»ØØXç¹^¡xEk‡`ôè™|öÙX …úØŸÞÄǧ+·o•¬Ÿ®ú)²¤¤‘«ìr!EŸÊ•}8u*‡ªê47nܦa÷¹sçáÔ®íBHH€:ÍgŸ-áêÕ?Y´hªd}Šc›æ&?›×Æ_ݦAƒŽÜ»— «Î/ Ï×.u[/ºíØÇðáSHLÜC™2õÍb•ôütq#CÇ C‘’òˆZµšsôè·¸¸8ÅÓOÍMcÚ˜¹õIr“ŸÎRú$³g/ã×_ϱnÝEÒA®vÿlÆ *W®¢—]º½O½ú ØþÍ&2ì2‰?—{@ 0 ¹oÚ¾K!**,ÏuvvJ222M¢Ïk¯uaïÞCÇŽIÀӳβ K#gÙŸÉÐz›} š“Ö,,,4®;|ø8íÛ7×HÓ¡CsÒ½c!G›N@€æ/†1xp¸Î²äÐ'?r~…ÐcÚ¼nzÉ?ÍRŸú‘‹jcÉÉ)E°páJ—.¥WÆÄÜâ†1ïEÁP~¡+‹­§]»7ÕƒrcL?5–>æfc†è“)}’­[÷Ô[6y}7>bW@`ôíB&|sÛ IDATZZ±±Ëˆ]Njj}û†9ïùóWóÁo›DŸÀÀ^ÄÄlÔ8¶ys,þþt’¥¯>ú”Ý<¯O``O'”ô;©©i$%ýN`à›îµk7pq©@Ó¦ïѬÙûÔªåĵk7t’-W›FGGröìolÙ²ÈnÏsç.©“,CØ|zz§O_ _¿Pz÷îªÓµÆ´ySQPý884ÁÖÖ—æ¼ûî0NœHÔ9ÿÙÆBC?ÅÏχŽ[è|­)0·¸aê{AA%n‚ÔÔ4æÎ]ɸqAyÎ7?5¦>ælc9˜[Ÿäy¤ôIλÄ;÷ñòêˆîîm™3gYYY:É2d=•ÿ^%hÕckñ*@ 08Ï¿J)Ó¥N)ܾ=ŽQ£¦qìØ6*UzI/]‹2}ñáÃÇÔ¨áGbâªU«‚J¥ÂÉ©)ûö­¡n]W½d—²KÑ'--víúqðà/êt-[ú²gÏ*õT:KK7ÒÓ/baa¯o,--8|xÖÖuÈÌLÒK—¢–믿nÓ¦Mbb¦8øøµSu•%GšÜ¿ª{{{pøð&½Ù5¦ÍZŸÜyäð|ýôè1”Ñ£áííIrr ññ?2fÌL¢£'Óµk“èlN6vàÀÏôè1”sçöbo_Yr~Æ ?=Ì-n˜ê^`̸!‹o`Ïžÿ±m[ŒÆñâÖÇ\m,9ú$r‘ŸÎRû$y1wܹ|ùáøûwbäÈþ²ê#y_%È þtü³] PÁ÷ßOûöíiÖ¬æ1¥H ”äêlîØG``8ß~»¨H7¡¢èS¦L)üý;²|yö¢4GŽ$P¡Bù|¤È’’¦(e~µg9VÎOŸO>™Ž’sçöòäÉ9÷bmmMHÈ u;;%OŸ¦ðóÏ[9rd Ož<¥T)¥ÞúÕÆ«²dÉtZµú%K¦Ø”«M¥ä‘šz'vR¶lÆÿ¼Hyé‹®6ŸrÛaAõ³uëB|}½±µµ¡J•JôìÙ™•+?cüø(½dåÈ+ ædcƒcÆŒPõ @Q‘sUùü0·¸aª{”<äˆrµiff&Ÿ¾TëlâÖÇ\m äé#nHé“(•¶ÌŸ? __oJ•²£~ý:,^<Å‹7è-×Ys¯( ñ*ÁgŸ}FVV¥J•"22ÒÈZ AÑÙ´)–ÃØµk Ô-üØ‹eË6‘••Å–-» >¥º¨e~µç¢¬þ\˜>7îdÙ²O©[×¥ÒWV®œÅÆ;ÔijÔpàêÕë×]½z5ôÒG.Ž;£cUŽ?cR=rccc··ë×Ïaݺí&ÓC›—ÛA·úñõõæÒ¥?ô–%æbc—/_#(h¢ÖÁ}(êªòR0Ǹaì{TäˆrµéæÍ»qvv¤qã†’Ò ?ÕÄmL®þ˜1↔>Iõêöxzºi\çæVSçה̙\‹ª4>8xð ÷îÝ3Và…$#Ó° Ï,]úƒcçÎ¥øøÔ7¨,)x{{P¥J%vï>ÈÖ­{ð÷ïh0YæVv)úhÛ6;÷}ÈÏÏ'Ï‚J»wäÍ7_—UW]HH8˪U[9yr+W~­×{®†$++‹ôôt“É7¦Í냔ú9}úÎÎŽFÒ(/ædcùmg¿råƒ9ÆÁ/ ÍÌ™‹?~¨äôÂO5173·>‰ ë“4iâMb¢æëHII¿ãäTÍЪ˜g·Êý]•«FJ—.ÍðáÃÙ°Aÿ邼¤?~Ìóç¸{ñ"ßbi –Ö`a @ª,ÈÊ‚Ì4ÈÈ„, úî;¬íìȪ{{£°kGÊ…hÓ‘™É½û÷ –ÿ¬Y1L˜0›o¿]Œ¯¯·ÁäèJ``O†ŸBÅŠ/Q§N-ƒÈ0·²Kѧ{÷v Æœ9áÔªUƒß¿Î¨QÓèÑ£½:Mpp_Ú´éCƒuñóóáðácÌž½ŒLs_zøð1½{bժϨP¡<11ÓéÝ{ÇŽm£Lã¿›Û¦M‚ƒûñæ›þ›y‰éôéÓÍèºäÆ6/)õÓ¡CFŽìO“&¯¢P(øå—“ 6‰°°!&ÑÙÜl¬8bnq#‡âäÆ&6öJ¥-­[¿¡õ¼ðSi˜‹™[ŸD Rú$ÆõaÈ ,Z4•úõëpéÒ 2Þ3¡æòòlñÁGVŒ‹­­-666( RSSùòË/ñòò2µž/g¾úŠ«‡qrå"Ê;CEW(WÊT»—Ø”¶ÂÒÖ…2ÓT¤?Éàéƒ,݆‡wáþUøûüû/¼AÍV­pmÞ¼pÁ‚íbþùçÖmØÀô©ÙûHk[|° ´M]Íý«UAS[ïÞ=ÎË/WÐIž\!88TaÖ¬±êccÆÌäÖ­{¬Y£ÿ{ýùQ˜Í>|Œ¨¨¥:t”ŒŒLjÕr¢ÿw •¥ìúHÅ6/)õóõ×ß1{örN:Ri‹§§aaCèÔ©¥It67ËïS΢³9ÅŒåÅ1nøùù:ˆwÞi«õ|I÷S©˜‹™[Ÿ ×YjŸdÛ¶}LœøII¿ãèX•þýß#,lˆI|G¶Å·~EF©LâOÇ?°|dEèØpT*ÖÖÖX[[caaUÚSº¿ó}<<ÏþŽiü”Äîáùu2GŸ»x¼ UêAé*Õ°)[k»Ú(¬j¡PTE¡( X R=þ&+ó2žþFú£ <¾ÿ’2¸¼No«Š¯ÐkÓ&^{ÍÔE,–ˆv1.¿ÿþ;Ý»uãæ­[ðöÎ;<ŠjýãŸÝMÙB'„„€@€  ×  øCDEŠ(" à” Ò¤HQŒ^BIèE¸€\¥áÊQ¤I B¢ôšºý÷GÈ’%m6™mä|žgždgÏÎyßy¿sæÌ™S°¾aÀU1 F°sç*‚ƒm3iŽ@àLÍ ù×…ÀÖ•-äjøáAÃÀÎã; %x@ÿþý™1c>>>T¨P“ÉDÍJ•èqí$ŸøˆI³¿)½eŒÛ)),kÝŠÊõnñÚ<õ^ÀÍó9P¼†‚0U“; #äŽëÈÑ¢D¥4¡*gÀ³|&åj$Q½ñ&‚^ù‰g¢ÎñËôs¬éØšÌÚ!|°iUü;!—+!âb_Œ&FƒwEñi'L& ¬¦V-?q“” „æ‚üˆëB`k„Ær২Q£U«VE©T’™™I¹r帔‘Åšë¼[>‹Û·oS¥JšëZ¤îÛǦ~ý¨z‹—f{S5¸5 E Œž`Ѓá΃Ù.”€ ”ÚjLz0cÎÓ¨RBÕ”#P¹¿IÐÕtø×wšs]3³gþ|ÞxÐE[P4".ÀdÂd2¡,hf—Ç¥2ˆ:uX¿>ÖѦvAh^ ȸ.¶FhLP*L²hÑcÀd2‘‘‘AùòåÉÊÊÂÛ;g]7ÒiçëËÉ“'yþùçío¬‹ri÷nt·Sx~™šj!Ý€wÁP-ç¡SoÊÙ P¨@énåAå(@Ÿ†l0då<Œ*Mà¦È‰˜Ê T½ðöõåÙó¸zä:§×¬áâoð„è¾^,".ŽA¡PàææV|ÂÇgž¹[ °BóA~Äu!°5Bc9°¨¥ß»w´´4Ê•+‡——&SΆ·²´¬KM£C¹r޲Óå¸öûïìŸ6…°Áà×ü`êšó&Z÷7úÔ»è/߯3¸. •¨¼0êthÏ_·òx>Õ ¦œOC:è³À¤CóÇL #¸²‚¦-QWÊàŸ|Õ7Ïñ篿RGÌŠ_$".ŽA©TâééA5ßjœMýËÑæ@ ‚<ä<©\¾|777L&*•ŠÌÌLLºï¿™Nl¬èž"£/ õ^V¡t.çAR{²orÉ÷¤¾8Ó½« ¿† ´$‘щÔð6˜î_C2AŸIÖ¯‡¸ýõJ.wøˆÔvÃIm=œ¿:Ž&k×Ï` ¦J£ŸC‡¢ÍÊr´çΈ‹Ã(ïSWßèêh3@ äÌ)ð`¤¯2ïÞÔÔT<==ÍYYY˜Œ Öè èo^e]d:d£] µÁ'À…Ét×As+gÓgæ$ÐßÝ}ЧqkâÊw} ϧ‚¹9v2hï‚þ>Ú”³\1‡Û1kñ›ý5—ô£æÊ~o¥qm`Ù“ñ¨P߯PC™;9ž (D\C… èýÞûŽ6C @ y[,ú6_¼xÑ¢a w¸-þ’´´4»›íJÜIN¦‚/xøè@ûh®çlÙ×AŸ‘“H{+gÓÜ$ûȸVAUÉÍÃ}²¯c¼ý7º WñûWÊ=ïO¹ðê”kU€ï{¢òQ`ʸ‚Êý.Ÿ€j^p&9Ù¡~;;".ŽC¡Pà.Ã:¯E­[\šÄÄ}¼þú@*WÃǧÍ›wfÅŠïmn\”ÆwÈñ¿E‹7JÆ\¿~ ?¿–EÚ%%\%¦?ÿ|ˆwÞùêÕ›S¡B(Í›wfÙ² æ}[Ù#öÐó–-;iÚôeÔêÆ4kÖ‘ü_‰l•‹âl–S©å˜Ü¾»’6r)ke‚^o`Ú´¹µÃË+„ÐÐWظ1Qn%cmUT¼îÝK#:z:uë¶ÁÓ3˜&M:ðÃ?™¿W(긕W‰{Yö]£Ñ2qâl³æƒ‚Ú1qâl4­ÜfZMiôl‹úªrÌDxá …¹!ÀÓÓ“ììlóg£ÉĦ[4¨Y™• æÙÜ8W槨(Ôå@å©Í6o€æ†å¨æißïFUÉ ¯gªS¾S ·ï’µg/d_Å­¢uóZdüt’; v‘õKho v#pÛëx=¥Ý<+‚·'DEE9Öq'GÄű(%ë;ѳçpæÎ]‰N§@§Ó»‚ž=‡[•楗úpÿ~:›6ÅsýúAV®œÉÊ•ß3eŠuä¤ä%rù0uê\bbÆ™Ÿ”4Ž`èÐɼûî¥NS®Ó1cbèÔ©G&póæaV¬˜Éš5›™0a–ìöÈ…=õ|âD2‘‘£™=ûSîÞ=Ê×_ã½÷>æÔ©³²û%•âl–S)å˜\¾»ª6r)keBLL<›7ïä?ÿ™Ï­[‡Y¸p:“&}áC'd·Y Ö–Q…Å+;[CÛ¶ï ÑhÙ±cii'X³æ–,Yo‘Îd:—o³WŒ;”]ߣ£§sàÀ1¶lYÄ;¿“°˜Ã‡O2räç²Ûl-¥Ñ³\õU)( æÙó Ñh̹­yæÿM&çïe²îz7’ÿÝ°Ç % R=hsѦ€î*載6<è²þà¡4mÃ/¨*«ñ~¦":ÕÃpû>™»ÍUÜ*eRc| ´)W¸=÷7®MúØÆI{ïº,”*P•ݹí$#ââš,_þnnntê @§N‘¸»»³|ùWV¥9r»v}KëÖ-ðòRÓ¸qK–Ì 6v…ìöÈ…\¾ìÞ½š¶m[™Ÿ”4öfÓ¦D~ûí(“'^9‘’¦(\1¦{÷®¥W¯ÎÔÀÃÃ=ÏŸÿ­ìöÈ…=õ»‚Q£Ò¾ýs¨Õž¼ôRÑÑý™3g¹ì~I¥8›¥ÄTJ9&—ﮪ (›eÂÒ¥ß?ÐÐ`¼½½hÙò)ââ¦2wîJÙm–‚5eTQñš;w%Mš4 6võêâááNhh0›6ÅËn³+ÆÝžöØ3/)iÖ®ÝÂâÅ_\µÚ“Fê?µk·Èn³5”VÏrÕW­Åâ‘%ooÜÍÛÛƒÁ`±ï§¿î“éæiSÃ\ªaÌ£–o¤Ï€öè®1='Qö5ô]Ę–‰ækœkþ%çž™Ž)S‹þÊ5 7ÎAæeÜ«¥0'„z[[PùÍÊnÞ ëç \³ÃÍLÆ40éê²K ââ| 8Žþý-ß EFŽfàÀqûímPPïƒâÒÄČηÏËK^o°Ún)öÇ3ϼÎöí{,öíÛw˜&M:X—öØ‚ÒvG¼w/Áƒ'0oÞg”+ç]â4RãÚSÏ…‘ûvÅG=ïÝ{ˆ—_nc±¯cÇ6ìÙsÀêc=´Ã1ClòÆTJ9&§ï®x]8S™`Ïë"5õ* ÖµØ×´iC~ýõw«í~˜‡üš´Œ*.^6lcðà^²ÛQ®¨y¹p5Í+ ”¬ú¥T*KuŽl]o‘¢g9ë«Ö`>“&@¥RåkHOO·t3SÃoI§ÈÈȰ©q®Lû¸8tws–»×_Ósû_Ð¥œ‚¬3 ¿•“(ã"÷7'ûä*uõ¡Òå©ÔÅŸIÛt–ìß~G9™ÛK’0\:‹ÒxŽŠ/ß'0Nï§nÜÿö6ÙG21észÂgf;ÖgW@ÄÅùˆÄÉ“gX¿~+ëÖ%pêÔYbc'™ÓôéV«%!a1 ‹Ñh´ôémUš‚˜3g9o¿ýªU6—4¯G‰Šz‡¸¸5ûÖ­K GNVå%—=ÎÈÈ‘ŸÑœW^i[ª4Å!×9t”žu:=ÇŸ¦oß‘ôêÕÙ*›W=_ºô7uëÖà¹çÞ¤uë·¨W/K—þ¶ê8ŽÂš˜>ZŽÉ廫^ÎT&Øóº ¬ÉÙ³Zä•””BjêU«l¶E鹸x:u–ë×oú ^^!¿Ä¬YK0éüý[áéLݺmèÞýŽI²ÚNWÕ¼3ùnOÍGEõ$*j<))Ñh´¤¤\$*j¼]’E.=?JIê«Rȳ(ŠÏ–5µ }· ýµZR©4·¸(•Jt:>>>9ã ¼ÜÜøgŠ\ÎÔÓ+~žž¢A^n>ÌϽ›Óf xÝ…ÔŽPó(·—ælõ¾Urw‹‰ÛkLÔ[W¥· "û¬ŽÔïPs’7*©ÑYxÖ‡€ÏAéxÂ_CÖa¨¹<^‚#ŸÂ¶%ðâŽD´kçh÷ÇS³fM®\ÙgÞ÷×_×hß¾7qqS‰ŠÏŽ+ñ÷¯QàïŠúÅŽ“’`ãÆD>úh*þ@Õª•¬ðÂú¼ "==“Úµ#HJÚFÍš¾˜L&Ÿã§ŸVиqP‰ò²g)”æ8»ví§[·!œ:µ?¿êOJ{Ú ö×sÞ·aa!ìÝ»¶ÄoI'=«T Ðé’Q*•„‡wC¥R²wïZÜÝa0¤XçœöÈqkbZP9挾Ûëºp¶2Áž×ELÌB6mJdþü)Ô¯_›“'Ï0|øg8p½þL‰ì—CóEéYJ¼Tª´hÊìÙã æÜ¹KDE£GN|øa?ºuÂÇ ,¬ ÷cÇ/Œõ±±“éܹ}‰ívÍ;›ïöÔ¼V«£C‡¾ìÞý›y_»válÛ¶ ÷Ùoëz‹=?JAåü—Ó—P½ºo‰ì|½Ë[4mö?lø7zo;ï ßègF<\‰ ï Z­ÖÜs Û`à÷tô ¬Äì ãKdÔãNÚŸp÷$(ʃª\ýÎu€û[ÁÿsÐ^3r{½ ¿O”(Ü3AŸú4<ëdQ¹‡W§eâá§¡ú@Ð] ½á\8÷ dŸ‚jcÁû¹œônŸ€ó&hþ쳎vÛéqq>j?^x—øøi…Þ8I…µ”4›6%5Žï¿Ÿ_âF©yFùòÞôèñ ‹çL8³oßa*W®XàSj^r<´”–GgE.é,ÉŒaúô‘æ›kIÓXKiÏ¡½õl2C£9Í‘#›ññ)ÏØ±%ú8éÙËKMvvNfÿþ ìÛ·ž¬¬l¼½ÕVG.=[ƒÔ˜VŽÉåû£6•{]ÎV&Øóº1â}^{íEºuB•*O9š#"ññ)g•Írk¾(=K‰—ZíÉœ9 ÃÛÛ‹fͱ`ÁT,XmN³aÃ<ÂÃÃðôôÀ×·*={¾ÆÒ¥_2vlL‰lε»4ØKóÎæ»}5? //5§Nm'+ëIIÛqww':zºU6Û³Þ"EÏy‘«¾*…‡ &ð÷÷ÇÃÃÃb%Èi$P(dgg›?›L&ßNg[¦–vi‹íþPÖðªY“j϶å¯p«~³ Ò{P©'øŽïàV*wÚF&=u`Ò¢@‡w3•:ƒÂÝHÅW ZTê•zä£Ú¨Ôåàöø; N" E#ââ¼ɲe8zt mÚô¤M›–<ýt›Ø°pá¿‰ŽžÎÿ»œæÍ›Ù$k Á×·*[·îfÆmìØ±ÊÑ&9 Ýí’'%½±§žÅh4¢Ó9nÆSgÒsDDs¶oßcQÛºu7Ï?ïZ=¸ Šiqå˜3ún¯ëÂËG^óæ­¢{÷Žv˯8Õ³”xµjFRR -Z„š÷¥¤\$0°f‘y?~š:ud°ºd8ò^àhßí©ù<Óà™qÔÌrêÙ~õÕ‡Ï9C V¯^Mff&ÿüç?yõÕW)h•///ÒÓsfo7™L¤ÜNçÇ[Ù €3ÓlÔ(ª„¿DÒtȺ&Or"s7À“‡•E}ç‘?AçAòøÃߟ'_x•Jeg/]Ç`0¹ŸžÂÒôôLzõúˆøøiT®\‘¸¸iôêõé陲Û0cFC†L`õêÙ„‡‡É~ü’Õ“aÃ>£J•J4jTÏÑæJ=õܾ}o6nLäÎ{dgk8r$‰¾}GÒ»wÙó²gÑóС}˜1#Ž;~A£Ñ’˜¸™31th_‡ÙTRb*¥s6ßíy]8+ö¸.ºtDRR :ž .3tèdNŸ>Ç!ïÚ$¿â«ŒúàƒÞ 4žŽ‘••͉É 4ž÷ßÓœ¦cÇ~lß¾‡û÷ÓIKË 1qýúbôèAr»% {jÞÙ|ÏÅšïÚµ‘‘£ùã³h4Z’“ÏÓ¿ÿºu{Ù&ùÉ=;ª¾ªølùXÓ Í^D•¡dú—_çìT(hРO?ý4ÉÉÉìÞ½­VkžˆÐ`0àíímžœ°Š—'õ›†Ò¯_?‚‚ ?RV9µb'ÿ9€Foj žjÌo¦ÑzrÞLly[½”¶œ¹ïrþ>x85¨!uœ˜k®Aðøñ|:eŠ=smD\ìÁ`äöý4BC‚‡“öî¿¿/3f|bN;jÔ\½z“+ä];·¨®¤7n¢ZµÊ²æ'•ŒŒLüý[ÝŸ †Ú,Ÿ‚ü´u[JGbωK‚=õ¼wïAbb²gÏôzõêÒ¯_w†í‹››ã#IÏ[¶ìä“OfpöìŸ4hð11cèØ±M¾ßÙ‹âl–S©å˜3ùnÏë¢ Ýcìs]lذqãfrþü%üèÚµ& ¥bE›äW%-£ Š×?üħŸ~MJÊEjЯߛŒ=È|œï¾û‘™3sìØ¨Õž4iҀѣÑ©“c&~¶§æÍ÷\ì¡ùÌÌ,&Oþë×ÿÈß_Ãß¿o½Õ‰ †âåå½uK¢g)å¼l“~·½·‘'vX6 þ„J•*™WP*•´lÙ’öíÛÇþýû1 (•J´Z-*T0¯Rð²_%úÖðâ|Ò¼yóù¸rzþ|þ5„†ï@ã‘ 4óð©£ðPŃMIÎÃ§Š‡o­ËÕÿÂñ)°û2ìlØoD£Œ•ˆ¸Ø—Â`0 Œ`çÎU;vl¼@PZ„ž‚üˆëBPÖš·-¶hpË›(33“ÌÌL¼½½yöÙgiÑ¢¤¦¦R¡BÜÝÝÉÈÈÀËË Fcžœ`ÏÍ4ÚWóæØW“hþï-¥póñ£QTJ…‚ÓãFc̸GÃÁà r,‹{Í}õÈy^½úø}üt7lÈ¿þJ•*Uìî—«#â"pL& ¬¦V-?qã¸|’‘#?·Êæ²wWô]®ë]NŠÓsLL<›7ïä?ÿ™Ï­[‡Y¸p:“&}áC'ÌiʲžË²ïPðõìHŠÓ³”òGjDß]1îRÊ¹ì‘ 95ŸËС“y÷Ý7d·ÕÑX4 äN*˜žžŽ¯¯/•*U27( óÐ…BÁÝ»w¹uëYYY˜L&´Z-CšùóÚ5Y¿Þq79WAŃq¹³Û»óð-uÞíÁçR‘ó¯xµ-".ö'6v£F ¤}ûçP«=y饢£û3gÎr«Ž³|ùW¸¹¹Ñ©S$:EâîîÎòå_Én³”¼¤¤™;w%Mš4 6võêâááNhh0›6ÅËn\Èåû£¤¥e·šQ£Ên³öî]K¯^ ¨‡‡;!!A,Y2ƒùó¿µH·{÷jÚ¶mYèq¤ÄtíÚ-,^üÁÁõQ«=iÔ¨ññÓX»v‹U6—帻¢ïr]ïrRœž—.ýŽøøi„†ãííEË–O7•¹sWšÓ”e=—eß‘âôü(•?rÕI¤àŠq—R&Èe\È­ùM›ùí·£Lž,#†£É³\¡‚´´4ªU«†òÁ’b¹½|||P*•dddpïÞ=ŒF£ùûÌÌL<<<?~‘‘£Q©TÄÇO³*¯âÒlذ­È·Ö ‡ïÏ<ó:Ó§¤C‡çÍûöí;ÌÀcIJÚnU^ÖÚ3þ·tèð/©©Wiذ®Å¾¦Mò믿籡ìêÙÙ|wdîŠTþÈY'‘‚«i^J™ WÔü½{i <… §S®ÜcR÷7AîCEiV©R¥œïM&Ê—/¿¿?5jÔ@£ÑpãÆ 2220èõznß¾MPPëׯçøñã¼õÖ[ Ÿú]#ØÛ—ä·úõ8ô\wt­ç¡o=]Dá›1"ž¿žÿ„Äf!ÜW«múcˆ‹ý¹téoêÖ­ÀsϽIëÖoQ¯^ —.ýmÕqúô‰F«Õ’°€„„Åh4Zúô‰¶ê8±±“8yò ë×o`ݺN:Klì$«ò’’æÔ©³\¿~‹ÐÐWðò !8ø%fÍZbn|µ·ïQQï·Æbߺu ôèÑIvßó¢Ñh™={)cÆ ¶Ê^[¡Óé9~ü4}ûޤW¯ÎVýVJL£¢z5ž””‹h4ZRR.5žÁƒ{Y•—+j>/¥‰»+j^®ëÝžÖäìÙ?-ö%%¥šzÕü¹,ëÙÙ|·wîïß OÏ`êÖmC÷îpäH’Uö:’ÂÊ©u9|wEÍK)¤àªš9òs""šóÊ+m­²ÓUP|¶|¬©]³v¸¥+4t5jÔ R¥JF®^½Jff¦9qVV†0hÐ sC‚Àz&L˜@zz6=߉D¥rËY*¢Tnn;z€eËâèÐáÿøä“OìhiÙBÄÅöÔ¬Y€+Wö R5@§KF©TÞ •JÉÞ½kqwo„ÁR¢/Îw{jÞÙ®w)lj‰YȦM‰ÌŸ?…úõksòä†ÿŒŽ£×ŸʶžÍw{ê¹[·!|üñšpï^;vü¨Q_;™ÎÛ—È~¹(Mù#¥Nb ß]EóRÊkqÍïÚµŸn݆pêÔvüüª—ÚöÒòåô%T¯î[¢ß¾Þå-š6{ €ï×­ÆPÞÄÎ;,{ ´hÑ‚ *péÒ%Ο?Off&F£‘ôôt¼¼¼øúë¯IIIaôèÑ¢Q ܹs­VCýúÁ F´ ¶Ð-;+?¿ÚøúÖ@-ÞLÛ Ûc0òíóòR“­`ÿþ ìÛ·ž¬¬l¼½K~NK[HÔ >~/¼ð.ññÓ ½¹JÍ«°4jµ'sæL$<< oo/š5kÄ‚SY°`u‰m/ïåË{Ó£Ç+,^œ3O̾}‡©\¹b7W©y—Æ`0ðÕW KÜ[àÑ¡K;C´Étæ4GŽlÆÇ§§qã ÔjOBB‚XºtkÖl*±Ír`ÍçRڸˉ½4/×õn ͆J¥bÔ¨$''’•uŠãÇ·âçWÆVb˲žÑw{—áy Ë×Í\*ö\Ý ¨ò§¤u’Òø.öм”2ÁÞØKóçÎ]bðàO lœ- δ¢G.OùƒŒŒ ÒÓÓùç?ÿÉ©S§ˆ‹‹£^½zŽ²ï±¤uëÖ4hЕJ…‡‡;jµžž…ojµåÊå´Ämݺ•ääd{ðx"âb[îݽËÒ…ùgߎˆhÎöí{,ömݺ›çŸÖ^¦åãðá“,[¶£G·°téw67ÙªUII–Ã%RR.XÓ&ùI!,,_ߪlݺ› ¶Ñ£Ç+6Íï‹/0vì›æQRŒF#:ΪßHiA£”9¹—½4Ÿ‹3ÅÝ^šwÆë½$Ì›·ŠîÝ;Zì+Ëzv6ßí]†çåøñÓÔ©`·üJJQåOIë$ŽöÝÞex^ *쉽4_Ø•ÎòP/ ¾¾¾,Y²„äädˆ———£ìz¬INNæúõ븻{¡ÑèÉÈÈ"33»Ð-##Έ»»•*UÂݽdãÖE#âb;Œ–4½yãf¾ï†íÃŒqìØñ –ÄÄ}Ìœ¹ˆ¡Cû:ÀÒœñj½z}D|ü4*W®H\Ü4zõúˆôôÌâl%|ЛAƒÆsàÀ1²²²9q"™AƒÆóþûoÊž—5DEõdذϨR¥Ù®a8!ajµ'/¾ø›å!•öí{³qc"wîÜ#;[Ñ#Iôí;’Þ½»Xu)1íÚµ‘‘£ùã³h4Z’“ÏÓ¿ÿºu{Yn·$aO̓sÅ={hÞY¯÷¢èÒeII)ètz.\¸ÌС“9}úC†¼kNS–õìl¾çb=wìØíÛ÷pÿ~:ii$&î£_¿QŒ=È&ùÉEqå”:‰³ùnOÍK)½ê-;J P(ضmÿø‡óܨW|}}ññ©€»»’råÔÅnåË«)_Þ …4 z½uËg ¤!âbCL¦œ·¯Zm¾¯š5kÄâÅ_0lØd*Tåç°lY !!³5ƒJçÎí rÞò½öÚ 2Aö¼Z´åÓO‡9šÊ•Ãxã(^y¥ÑÑýeÏËÞ~ûUnݺcó7Ÿ>_Ö•JÓj?qâ0/^Gݺm¨V­9ï½÷1¯¿Þžo¾±Œ{Ac»ó"%¦ß|ó)O>L§Ný©XñI:v|Ÿ'Ÿl̬YãKli°§æAþ¸Ë=4o‹ë]ŽÉ6‹Òó»ï¾A·nC(W® /¼ð.îìÚµµÚÓœ¦,ëÙÙ|ÏÅzŽŒìÁ¤IÿÂϯ%uê´fòäñõ×ãÚÐUœž¡øòGJÄÙ|·§æ¥” ŽÀ^õ–ÇÅgËÇš^höª %áímO™à»ï¾cíÚÓ²e;7~ww·"ÓF®\Ie÷î-$'ÿÁŒ3hÓ¦¬-;ˆ¸Ø£ÑÈ… çéÕ½;^½<\•@à| #عsÁÁÎ1!Ž@`K„æBÏ‚²FYÔ¼-V%(úÉG`ºtéÂíÛ·Ù³gJ¥‚–-Û T<M¡Prñb ?ÿü#þyW_}•ˆˆ;[\6q±J¥•Ê má«? œ“ÉÄ‚«©U˯ÌÜ\e¡yÁã„г ¬!4/nPäRí R©8p {öìáöíë\»v•JUHjׯÿN§åîÝ»´jÕªˆ´‚Ò âb[|||xµó,Œ/ÝšåÛ¢TQ§Në×Ç:ÚÀ.Í '„že ¡ùÒczÐ z 8“ÉÄå˸r%µÈtƒžììl*UªÄ‹/¾h'ëÊ.".¶¡bÅJ ?{÷®¥W¯ÎÔÀÃà –,™ÁüùßÊnsIHKË .n5£F 4ï[»v ‹App}ÔjO5ªG|ü4Ö®ÝbNS–c Åk^j9l– ¹ÎÏÈ‘صë[Z·n——šÆs4»Bv›¥R\,–.ýŽøøi„†ãííEË–O7•¹sWšÓÈu¿pŘBñçP®¸Ûóüة秬–P¼ïÎ~?-)Î/[ àh6lØÆàÁ½J}œ½{ñòËm,öuìØ†={X}¬G'm-É$®Ž£ËV÷ÈÈÑ 8Îê¼ä°ÇÙÎÏ3ϼÎöí{,öíÛw˜&M:XWIíÉm­w4óçK‡ÏS·n yŸB¡@©´¼+•J ßœ-¦Î¦y9q5ÍÇČηÏËK^o°Ún{‘šz•† ëZìkÚ´!¿þú»ù³\÷ x<5/gÜí©y{aïëâqÔXa8Ëý´48[9/7jŽó!R8uê,ׯß"4ô¼¼B~‰Y³–`4-Òùû·ÂÓ3˜ºuÛнû9’dñý¥KS·n-ž{îMZ·~‹zõ¹téo«ìéÓ'­VKBÂb£ÑhéÓ'ÚªãÄÆNâäÉ3¬_Ÿ³äåºu œ:u–ØØIVå%—=Îv~¢¢Þ!.nžuëèÑ£“UyYkN§çøñÓôí;’^½:[e³-Ðh´Ìž½”1c[ìŠêITÔxRR.¢ÑhII¹HTÔx‹‡"g‹©³i^.\]ó¹Ì™³œ·ß~Õ*›íI``MΞýÓb_RR ©©WÍŸ¥Þ/Š£,i¾$q·§æ­®‹² 1g¹ŸW?”‚³•óòaÊ]”ÅgËÇš^höª %á퀜7ýõW?-껲LAçeþüù|þùçŒ3†Áƒ-+tiiiÄÆÆ’À•+Wðôô$<<œ÷ߟˆˆ{šþØã¨Ø”åkåQßOŸ>MÏž=4h“&MàÊ•}ù~§PÔ/pÜ—JÕ€-B™={<¡¡Áœ;w‰¨¨qôèщ?ì@·nCøøã„…5áÞ½4vìø…Q£¾ 6v2;·7G§KF©TÞ •JÉÞ½kqwo„ÁR"_ ³Y*ýuöí{7•¨¨ñìØ±ÿ%Ϋ4iœíü¤§gR»vIIÛ¨YÓ“ÉD`àsüôÓ 7*Q^Å¥É;ÉOXX{÷®¥\9ïÙ/ ¬fÛ¶ÿñÃqûµZ:ôe÷îßÌûÚµ gÛ¶exxä, êl1çÒ¼µi¤àjšÏeãÆD>úh*þ@Õª•Jd¿\fsLÌB6mJdþü)Ô¯_›“'Ï0|øg8p½þ í~!—=RqV̓|˜·ß~› &U¢c¨ÕžÌ™3‘ðð0¼½½hÖ¬ LeÁ‚Õæ46Ì#<< OO|}«Ò³çk,]ú%cÇÆ˜Óxy©ÉÎÖ°ÿöí[OVV6ÞÞêûWÚ A@@ âã§ñ ï?­Ð¹Ô¼Jc³Ÿòå½éÑã/Ι4lß¾ÃT®\±ÐÊ¢çÇd:‡Fsš#G6ããSž±cK6žO®Ù _}µ0_o€#¦áå¥æÔ©íde")i;îîîDGO7§q¶˜‚siÞ¸šæ6mJ$*jß?¿T‡rÍø]#F¼Ïk¯½H·nC¨Råi"#G3bD$>>åÌi¤Ü/¬åqÕ¼q/­=Öj¾8äÔ¡\çG £Æœå~*¥~h-ÎVÎË…h°»ví¢bÅŠ¼ÿþûT®\™Ý»w[|¿ÿ~>ýôSêÖ­‹»»;U«Våµ×^ã»ï¾+ô˜Ì›7'Ÿ|’&Mš0nÜ8t:]»veãÆéÿúë/ÂÂÂHKK“Ý?WÆV±Y¸p!Í›7§V­Zæý…Å«¬°gÏú÷ïÏœ9sèÒ¥K‰S«–Mš4°Ø× ÁÅv‡³èvZ»¶?.¤Z¤¹p!•ÚµýKl›Ù¸ø‚\š/ •JŨQINN$+ëÇoÅϯ:?|X(éýÂÖ8›æåŠ»È©y¹tèLçG*Φ1p®ûi^­ÚGÔm¤ lIJeËè×/§ËZß¾}Yºt©Å÷ÿøÇ?øøã9xð ÙÙÙ’»g϶oßÎŽ;8wîsæÌ`ذaÌš5Ëâí÷¬Y³èß¿?>>>2xôø`«Øüúë¯$$$šú°^X¼Ê DGG³bÅ Z·n]ªcµjFR’e·ç””‹Ö,òwÇŸ¦N‡“@FD4Ï7áËÖ­»yþùgKe_i8|ø$Ë–màèÑ-,]ú]‰Æ½É…3žŸ°°|}«²uën6lØF¯Ø-o£ÑèðƼ/¾XÀرC ý¾ e¡óNPäŒ1u&Í;#öÔüÂ…ÿfÀ€1lÞ¼æÍ›Ù,[2oÞ*ºwïhþ\Òû…-q6Í;[ÜY΄³)8›ÆÅî§yy´~hoœM󹈆ðçŸrìØ1Þxã :wî̱cǸté’9ͼyó¨_¿>cÇŽ%$$„üãL™2¥Ø·ûŸ}ö~~~øùù1yòdó[ì¶mÛR®\9s¯ .°{÷nÞÿ}yéšØ:65jÔÈ·¯ x•† ÂäÉ“iÖ¬ô7Õ>èÍ Aã9pàYYÙœ8‘Ì Aãyÿý7Íi:vìÇöí{¸?´´ ÷ѯß(FdN3thf̈cÇŽ_Ðh´$&îcæÌE Ú·Ô6–„ôôLzõúˆøøiT®\‘¸¸iôêõéé™±ÇÙÎO.QQ=6ì3ªT©D£Fõl’Gûö½Ù¸1‘;wî‘­áÈ‘$úöIïÞ%ïéRZv¡V{òâ‹ÿ(ðû®];9š?þ8‹F£%9ù<ýû¡[·—Íiœ-¦Î¦ygÅšŸ1#Ž!C&°zõlÂÃÃl’‡Üté2ˆ¤¤t:=.\fèÐÉœ>}Ž!CÞ5§‘r¿°'Φyg»=4/g=?Eáls¶û©”ú¡#pÍçåÁäƒ/¢ÊP˜'¬S§)))xxxX$Öh4qùòeGØêÔälmÊ”),X° _šÁƒ3~üø|ûM&gΜaþüùܾ}›+ ^K6 €óçÏãéé äÄ£qãxr“W IDATÆœ?€íÛ·3mÚ4víÚŰaÃxæ™gDÃö‹MjjªÅ›ºââõ8ÀÌ™3™2e ‹/&<<Üü]Íš9omòN>XИ±G»‹ýðÃO|úéפ¤\$  ýú½ÉèуpsSðÝw?2sæbŽûµÚ“&M0zô :ujgqœ-[vòÉ'38{öO4x‚˜˜1tìh¹œ›½èÝ;_fÌøÄ¼oÔ¨/¸zõ&+VÈ¿V­”óìLç'—ŒŒLüý[ÝŸ †Ú$½{³={ ×¨W/~ýº3th_³ÆìMDDFŽÀo¼Tà÷™™YLžü/Ö¯ÿ‘¿ÿ¾†¿ Þz«& ÅËëáÎSgÔ¼”4öÆš/j¬î‡¨V­²Mò-Šâb±aÃ6Æ›Éùó—ð£k×L˜0”Š-{Fw¿°'ΦygŒ;ØGóRz~œ©Üp69ÛýTjýÐÞ”VórN>¨/gb×É7 ´mÛ–Y³ffÙRväȆ ÂþýûKdÄãLîçF£¡E‹$$$øp½éK—.ñꫯrðàAóƒâ£Ü¿Ÿ-Zœœ\h»ví¢aÆœ9s†÷Þ{_~ùÈyˆmß¾=íÚµcË–-ìÝ»www™=u=ì›GW (.^3¹çã¿ÿý/~ø!³gÏæÿþïÿ€‚‚¢0 F°sç*‚ƒm3©™@àLÍ ÊBó‚²Fi5o‹†‡ôëב#Gò믿’––FZZ¿þú+ü1}û:¶K©³³qãFÂÂÂ,<j׮͓O>ɦM9“BuïÞÍ›7sãÆ ôz=—.]bÚ´i<û¬å¸Ï€Ëñ/“&MâêÕ«\½z•I“&ѵkWów …‚áÇ3þ|†.ÁÖ±)ˆ¢âUø¿ÿû?–.]ʈ#X·n£Í¸ &“‰ VS«–Ÿ¨, ÊB󂲆м ¬á¬šw+hgŸ>}ðòòbÊ”)ænÏõêÕcðàÁtïÞÝ®ºË–-cäÈ‘~×§OfϞ͛o¾ÉG}ÄÒ¥Kùä“OÈÎΦF¼ð ÅNNA‡ÐéttîÜ™aÆY|¯R©¨[·.o¾é˜±tÎŒ­cSÅÅ«,вeKÖ¯_O¯^½¸u떣͸Jeuê°~}¬£Mì‚м ¬!4/(k8«æ %xU†Ò<”@`÷ïß§U«V$%ÙvЂº«?Ê{ï½Ço¼až\¯¬c¯Ø¤#†@ %GÞ¡FvÜUptt:«V­"44Ô¡vFV¯^ÍåË—yýõ×j‹³à,±@ gF4 ”’   BBB˜5k–Cí $00¸¸8”J± %8Ol@ À™ ¥äÏ?ÿ´[^E #(nˆAYÄž±@ WCAÎrëâÕ²@ pŠZ?81q-Z¼QhšÄÄ}¼þú@*WÃǧÍ›wfÅŠïmeªU\¿~ ?¿–ùl×h´Lœ8›  vxy…ÔŽ‰g£ÑhKœWQçÐØÓ)y•FcRÓØ“âìÑë L›6׬±ÐÐWظ1Ñ"«ë°4q·E¹á*¾ƒ4=oÙ²“¦M_F­nL³fùñÇÿ•ÈV¹)¬\•šFn¿\%î?ÿ|ˆwÞùêÕ›S¡B(Í›wfÙ² ˜L&›Ú#¥ñ]Jyè( Óª›Šún¥ÁUbš)e‚\öÈ…\¾Ë…h¥gÏáÌ»N€N§'6v={·H7uê\bbÆzœ—^êÃýûélÚÏõëY¹r&+W~Ï”)ŽŸñuèÐɼûnþ A££§sàÀ1¶lYÄ;¿“°˜Ã‡O2räçV_ê9´ö´GJ^riLj{Rœ=11ñlÞ¼“ÿüg>·nfáÂéLšô ‡0§qEÊw¹Ê WôŠ×ωÉDFŽföìO¹{÷(_=Ž÷Þû˜S§ÎÊî—µV®JI#—_®÷1cbèÔ©G&póæaV¬˜Éš5›™0Áºa—®è»”òÐQ¦U©6›LçòmÖâŠ1Í‹”2¡4öÈ…-|— %€éÁ&öfùò¯pss£S§H:uŠÄÝÝåË¿²H·{÷jÚ¶mYèqFŽÀ®]ßÒºu ¼¼Ô4nÄ’%3ˆ]aSû‹cÓ¦D~ûí(“'ç/Ì×®ÝÂâÅ_\µÚ“Fê?µk·X•‡Ôsh/ìi”¼äÒ˜Ô4ö¤8{–.ýŽøøi„†ãííEË–O7•¹sWšÓ¸¢劻\å†+úÅë'6v£F ¤}ûçP«=y饢£û3gÎrÙý²†¢ÊU)iäòËã¾wïZzõêL@@ <<Ü ÉÑüüùßÊn\Èå»”òÐ¥U{ÚìŠ1ÍEJ™PZ{äBnßå ·@ôG¡PùY 11£óýÎËK^o(•m¥áÞ½4žÀ¼yŸQ®œw¾ï E¾ÉB•Je‰ü—ã8Žþý-ßFFŽfàÀq±ç™g^gûö=ûöí;L“&¬ÎK{\‘ÔÔ«4lX×b_Ó¦ ùõ×ßÍŸ]U‡rÄ]ÎrãqÔüÞ½‡xùå6û:vlÞ=¬>–\W®JI#§_®¦ùÂÈ}3i ®¦y)塽)N«ö¶Ùõ,¥L‚«éÙ(>[>ÖÔ®Ù ¨2”T÷ $((ˆvíÚÙ5kúrëÖüýkðÌ3M;vO?ÝÄ*[\UÏRÊ{ùnO=9} Õ«ûZåg.¯wy‹¦Ížàûuߢ/gb×É– 3gÏå»ï¾£]»vìÚµ«D AQÔ¬YxØ09È6nL䣦rðàT­Z©dÆ–‚]»öÓ­ÛNÚŽŸ_u ¿íZ­Žú²{÷oæ}íÚ…³mÛ2«ÄóRÚÖ¿þºFûö½‰‹›JTÔxvìX‰¿¯4ö¤§gR»vIIÛ¨YÓ“ÉD`àsüôÓ 7*Q^öLcO ³'&f!›6%2þêׯÍÉ“g>ü38Ž^p}:[¹ñ8i^¥j€N—ŒR©$<¼*•’½{×âîÞƒ!Å:çd@J¹*%-ür5ÍçÐ,,,„½{×–øm««h^JyhO¤hUŠÍݺ áãÖ„{÷ÒØ±ãFú‚ØØÉtîܾD¶¹Šž¥œCkq=Û¢aÀ @aÊéšðûﻥŽë~+Ê&r=hmÚ”HTÔ8¶o_VªÊ}^¬µmÀ€1LŸ>Ò|£*ˆ#¦áå¥æÔ©íÔ­Èùó—ù裩DGOgΜ‰%²»´ç0  ññÓh×®»v}[ªFÒÚS¾¼7=z¼ÂâÅë?þöí;LåÊ ¼¹JÍËÙæób ÛFŒx“ÉD·nC¸téo4x‚ †2`ÀØõ„âmÞ°ažù_ߪôìùÕ«WaøðÏJÜ0à*z–r­ÅUô,'.W˜mþ_¯×‹Mlb›ì›­Y»6ÈÈÑlÙ²ˆ'Ÿl\âã”vvßsç.1xð§ù–Ê[‘X³f3‹}NãÆA¨Õž„„±té Ö¬ÙTb»åààÁãÔpŠ™š£¢ÞaÑ¢µFÖ¯ßJm’l”VcRP©TŒ5ääD²²NqüøVüüªÓ¸±Ða^ä*7äÀ™4_»¶?.¤Zì»p!•ÚµýKt<{”«RÒÈí—\Ø»ìõðp',,„o¿ÅªUí’gAØKóRÊCk°‡žKjsxxgÏþiµMrb=K9‡öÆ™Êpkq+ì ½Áöx@ “… ÿMtôtþûßå4oÞÌ¡¶TI(¨;XAKG;rb¼Ã‡O²lÙŽÝB›6=iÓ¦¥Õãå$,,_ߪlݺ› ¶±cÇ*‡Ùò¸0oÞ*ºwïh±¯,ëÐ™Ê p.ÍGD4gûö=4iÒÀ¼oëÖÝ<ÿü³±GJ¹*%³ùŽ-{F#:Î.y„#5_Pyh/¤ÖEŠÍÇŸ¦N€RÙWì¥ç’žC[âLe¸µÚ0`Ð?, ôz=—.]æþýû Ly+9ÿä|~X³0™L”/ïÃOÔÆÓÓS~Ë 3fÄ1~üL¾ÿ~ááaŽ6G]»v 2r4³f£^½Ú\¼˜ÊGM¥[·—bOzz&½z}IJe_R¹rEââ¦Ñ«×G<øåË—|¦ßÒÕ“aÃr&ïiÔ¨žÃìpEºtÄÔ©Ñ4lX—ÔÔ+|ýõNŸ>Ç’%3ÌiʲµÜpÍÚ‡öí{ó䓉ˆhÎÞ½™9s»v­v˜Mràl~ÙSóíÛ÷fèо<ÿ|‹CˆÎ=Þ½»ÈšµØCóRÊCgCŠÍ;öãÃûѪÕÓ( ~ûí(|0‘Ñ£9Äfg­KØg)íERVËŽ;8zì0&SNË¢Ñ`Ìùk4a41˜?çüŸ™™IÓ¦ÍõÉHTn*»8#_òv Ëý?o‹ðèÑ_ðÚkòýöÆCT«VÙÆZÏ7ß|ÊäÉÿ¢S§þüý÷5üýkðÖ[˜0a¨Cì<øS:wno~@jÕ*Œ×^{!C&°b…mÖΕÂÛo¿ÊˆÓxï½n6ͧ8IMcOгçÝwß [·!œ?‰€?ºvíÀ®]«Q«6Ø—e:k¹á,šoÖ¬‹Á°a“9{öO4x‚eËb )x¼¬«àl~ÙSó'#&f!}ûŽD¯7P¯^ ýúugèо²æc-öм”òÐÙbsdd&MúÇŽýZíI“& øúëqtêä˜U朵.aOìU†Ëâ³åcM/4}e¦‚V9j×®ë¾[cN¤ÕjY²h)‡Àd2™ý«×ÈÊÊâþýûÜ¿ŸÆsÏ=ÇW3gàSÁÇQþ '#´i΢ U ‚‚0 F°sç*‚ƒ7nP °B󂲆мàqÂz–sUC9ØyrGN&Àr,aÞ¡F½ƒÑ€V«3÷0  ÙÙÙÜ»wôô F£1ç8ƒÅ±@ ŠÉdbÁ‚ÕÔªå'*‹‚2м ¬!4/xœpI=+r¦4”@o4`ÐÐh´‡<Øt:÷îåôÈq<ï„E£ALd(‚¡TQ§Në×Ç:ÚÀ.Í ÊBó‚ÿgïÌãcºþÿÿL"²”¶¨-D­‰¤BTT,Ñø)iiK)ŠjK-%$öPÄÖ I컑Z*–¯X*Ò–PФ–(U´”ªZ³Îï4‘‰LrgæÎ™ä<y;ï9ï÷9çuνsæ¾Ï-I˜³ž5/ d¤çý?+3‹ÌÌL^z©™™Yüý÷ߨTÙ¤§gpÿþ}ž>}†J¥¾ñàÿ#+3C­,@ ¤bÌü}ÀÍ JBó‚’„9ëYã€EÿgeeñꫯҢEKnÜø¤¤$®\ù•ìl666¨Tª¼ƒü‹LR@ @`*h^È—`aaAvv6gÏžãÏ?oãç÷.=zôä믿&33 ,,,ÈÊÊ"##ƒôôô¼=rß@ @`zh\°´T_ÈÊÊ¢víÚ´n݆Gñý÷ßãéÙŒªU«‘‘‘ÁÏ?ÿÌýû÷IOOÇÊÊ •J•·(¿,@ @ ¦ƒ¥¦7,,,Õ^YYÙ<|øýû÷ÃÕ«W±±±ÅÞÞ{{{ììì([¶,ÖÖÖXYYaii™·0P°,ñ/ñ*½¯‚¤¥¥3eÊ"êÖõÁÎÎ…ºu}˜2eiiÆÙ›$33‹™3—äÅãîÞ™;ãÕlâãéÒe0*xP¾¼žž]Y·n»Æ2ïܹGµj-ÈÿÌp]Ð÷órû*ÊæÁƒ‡ÍÂÙ¹-66 quíÈŽ \˜ZÝõ%>>‘æÍß׳…Åë…¾ò£í8-mš×Ô†¶¶ \¢îƤ8ÍçG“V¥hÞu7—~7ĹÛ\êž¹æ:}ÒRûk÷îC4nü¶¶psëÄÞ½ß雹ô©”k?CÄcjXÂó´GGǼ7ž©·T4iÒW7nLçÎéܹ35jÔ lÙ²”+WŽ·Þz‹N:ѹsgÞ{ï=Þÿ}Z·n•••ZYâ%^âUº_ šÅ‰?³{÷ îß?M\ÜJN:ÏØ±_*3  <|ß~{ˆo¾‰äÞ½S,_>‹©S¿âäÉsy6:ôãß±k×2îÜIbýúù¬_¿3 ßvĈi|òÉû:ÅÓ«×(–,YOFFÎÓ]222‰ˆXG¯^£t*O__Rlž=K£]»Þ¤¥¥sðà><ÇæÍ_±jUŒìñÈ…©Õ]N–>¡H•êÊ ¯üh;NK›æ k¿á Ð]öxäB®ºCñúQ)šÏE“V¥j^Žº›c¿Ëuî6ǺçGŸ¹N.¤ô…›sç.âïÌ¢E“øçŸ3,X§Ÿ~AJJªVñ˜cŸJ¹ö“+S$ww@‹ék'ªÚ»½åc ZzûàããÃæÍ«òŒŸ>}ÆÃ‡é”)có¡B.îó þoÂÜ×K/•¡|ù— V@`^xx¼À$P¹²'?ÿ‡ƒCÕ<›[·nӤɻܹ“¤x|õë¿Í¶mKpwo˜wìĉŸ‰ŒÜÈêÕsøâ‹ÙÌ;^m.üý÷?ðôìÊíÛ'ÔÊÛµ+ž‘#§“œ¼råÜ´¾hLOÏ`õêmÄÆîãÀctèàM·nï0`@wÊ–µÖ£¦ºù’b3þ NŸNaÆG.L­î†ÀÂâõBõ§éx~´§¥Qóyøð1uê´åĉí8;;É\ÈUw)ú1ÅÅV”V¥h^®º›c¿Ëuî6Ǻç¢ï\'RúBŠM@@õë;40ÏfîÜe\½ú;‘‘3$ÇcŽ}*åÚÏÔê>wÖ**W®¢Óg»|ГÆnMؾu#™åT>wHZ* 66Vdg§‘žþ˜ÇÿáÁƒ{Ü¿‡{÷þäÞ½?ùûï;±TK%ˆ‰YgÇ Tãæö&ð<• ==ƒŽûsäÈñ</öí[£ómWúÜÞ¾œ]»â‰ŒœÁë¯×äüùKŒ5'Î’™y©ÐÏìÜO``II;¨TéUþ‘n݆‘’²ŸjÕ*ë—Ÿ¿yó6¾¾}‰Ž# ”ƒ׫ÝV¨­/M6VVõhÞÜE‹BqwoÈ•+× ¡G?F SìúÔýÑ£'Ô¬éMrò>ªW¯‚J¥ÂÉ©¬£Q£º:ù2—ºK)§[·a|ñÅ <<\yðà!~ϸq³‰ˆ˜F×®¾€´qZš5ŸŸ¨¨MìÛ÷;vDë·T_šPRóRô£-†Ö¼­JѼ)Ö])͛ڹ[IÍ›Ú\'¥/¤ØXYÕ##ã"–––xyuÃÊÊ’„„-X[7 +ë²âõåô¬Ëµ_qZϲ¦¼”Íáó‡¥?•@¼ÄK¼ÄKŽWAÆŒ™‰-))ûyú4…ääýX[[4K«I®àŽÐºî=fÌg¼÷ÞÛtë6ŒŠ›âï̘1þ÷JÙµ+ž€€¶oÌ[4h³fÍ»h}/”«²lÙLÚ·ÿ„eËfj<¹Jõ¥ÉÆÖֆŋ§àåå½½nn ˆŠ #*j“αëS÷råìéÑ£3+Wæl˜˜xŠ ^)ôbQª/C×].=K!6v)^^ØØ”¥J•Jôêõ«WÏeâÄð<)ã´4k>—¬¬,æÍ[®Óݺģ %5/E?RPRóR´*EórÕ=?æ¢y¹ÎÝÚÆ£ %5/×\'ßuKñ}!ÅÆÎΖgÏÒøñÇXcxúôöö¶:×Ñ|ô¬ÝµŸ”Ô³\XL_;Qõ¶ÛÛX<¶ {ÏO¸yó&>>>|óîp@  —¦Àó;*Ujƹs{^ØÇݽ3wïžÒɇܛa;v’qãfóý÷ÛÔŽoÙÇçŸOaïÞÕxzº½ƒ&Œ¹Qׂ+ùê«5Œ=€ÀÀÏ â£A_NŸþ{{»¼cOŸ>£R¥fš—ÒRl\\:«k½<›óç/ѳç’“÷ë›(9‡çGÓµŸR§g¹îس‰Ì—²9tîeòݼy3ïÿ©©gtr$ÚRÈ6'(±Á•T–.Ý@÷îÔŽ-_þ?‚‚fñÿ·ö…E(üâÀØ»wŸ:už5kb9sf7mÛö¢mÛ4mê*»Ÿ–-=HN¾LóæîyÇ._¾†“SuÙ}IÅÃÃ…*U*±gÏbc÷ì‹›)Ö]Ξ½@­ZŽjÇŠ§¥Yó¹ÌžÅ‚!Å*€Rš/ŒÂôcJHÕª.ç&c×]I͛ڹ[)Í›â\'¥/гñöödÿþ£j {ö¡M›7e‹S[”žÃóSصŸ’c/SÔ›uœ›<@PºùðÃŽøû³pauêÔäÚµ†Ñ­Û;F‰çƒ†DýúÎܸñ ¬âÂ…+¬Z5'ÏfΜhBCç³}{^^F‰S[=zBŸ>¬Y3— ^!:z&}ú’”´ƒråôßQ9?Ç÷eÈP"#gàæÖ€ÔÔß2$”Ï>ûHV?ÚЋ‘#§S±â«4hPÇ >LµîEÑ©ÓF@Ë–M±°°àøñ3 >…àà!y6¦6N¥ ¤æââckkÃÛo¿%{Ùº¢„æ¥èÇ‘¢yS«»’š7Õ9A Í›RúBŠÍˆýðõíËo4ÂÛÛ“„„$æÏ_ÁáÃÆ¹‹\I=K¹ö3JëY-• ÿæƒs玣ŽsSþ¹ÏàA‚Òƒw›·ç©OžÄøñsHMýzõj>NÚjrmP”Ô³”k?cP”ž ‘JóT··± @ . J‘••…““7‡m aCÃ?'] 06Bóý)jâ IDAT‚҆м $Q”že{*Á ‡ÏÒüT@ J *•Ѝ¨MÔ¨QM\, JBó‚҆м $a =¹Ç€@ %K˺ԪåHLL„±CAh^PÚš”$Œ¡çœ…• 0À@ cî-¡yAiCh^P’PRϪœu‘J @ A)F, ”êÖWæyžÍ”¶>(mõ@ J2¥ba@|‰)Ñ>šm#@ J:Š- Ô­ïJÝú®ÔkИ&M[ð^×n„Ï[Àßÿ­u9Ú’z)YëÏèBnsëéõVF~ÁŸÞVÄ¿®äosý"¼|Å*4rgùŠU²–+—v”nׇ2oþB|ÿ_g»7£Yó– 6‚ïøQÑ8´¥°gOKµ9vì$½{¦reO^~ÙOÏ®¬Y‹J¥’;LIH‰GjÌ»w¢qãw°µm„›['öîýN¯Ø¤´³\èÓ§ññ‰4oþ~‘6¥µ}âãéÒe0*xP¾¼žž]Y·n»Ü!JÆÂâõB_¶¶ ³¹ôHÓ³mP²} éR¦RZ?¦6'h‹9Ž/}sBɃ ÿ5‰’(zÇ@ê¥d._<ωG˜óeÏž¥ñn—nܸySÉ0 Jê¥dR/%sñ—³ìÚ±ªU«0:p¬±Ã*Ñdgg³qÓB&ŽgÓæ-dgg;$£3rt÷ïÿÊe‘œ>õ#öÇÑå]?"–D;´èÕkK–¬'##€ŒŒL""ÖÑ«×(­l&LÇÏχ3gâ¸{÷ëÖÍgóæo™b×®eܹ“ÄúõóY¿~;3fgGn•êÊ ¯á Ð]ö˜Í±¿ x=Kµ‘#fsDŠÆ¤PRõcjs‚Ìq|ÉIiJê”ëšÄX%•ÀÎΗFL @>dá¢Åyï]½vÏGŒÆ³ù[4iÚ‚aÃGqÿþ}àù¯®¹¿Êç’Í’¥Q´óù4kÞ’à ¡<}ú4ï}cü niiI•*Uø|øÎ'§H޵¨úCN]V¯^‡w›öÔkÐ8ïø²å+iѲ5žÍßbê´0222$ûÌß®¹ÿjÛ¾›6o¡­O\ÝšÒ½Go.]º,G3J⻣ ¼òÊËôëÛ‡ ¯¾ÊÑ„cjïß÷?üH—÷»ãêÖ”¶>سMí³¹dee±è«Å´içKSO/V®Z£æG“MíjH’’N<~,µk×ÂÚÚšŠ+Ò¹ó;lÚð<æÂb‘£¾P¼fò³ví<Ê”)ƒŸŸ?~~þX[[³ví<­l¶Ð§OW«R¶¬5..uYµj‘‘¥7œŒH‰GŠMDÄ:ÆŒ¯o+lmmèÐÁ›  ,^¼V«x¤´¡\ÈÕ§GŽl¢]»}•æö;v‡o¤uëæØÙÙÒ¨QŽ~""Öɳ.<|ø˜èèMŒ78ï˜\1›cAñz–j#GÌ%Â4&…’ªSŸ ÃÇ—œ”Ö9¡¤ŽA¹®IŒ…%€ÊPÅþœ—’ôø¨;ßÿCÞß#FòIŸÞK8DÂwñT­Z…ðy‹€ç·uçþ*ŸËšµë9~<‰ ëWq(~?™™j‹ Æ ;;›¿þºKTôrÜÝÝòŽkQõÏåxRßlû—/žÏ;–˜ø»vl#n÷v®^½FdÔrÉ>sѧ}Ù¸a 'O$Ò¶Mk&Mž¦cËiÏÆÿ£ï'½èÓ§6l~Á¦¨øÆŽ fØÐNŸú‘Í×qúÌÙBýD/[AÒÉSlX·šÃÿï…M>4µ«!iñfsB&MåÔO§yöì™NeèZ_Ð~LZXXù·T›ÂÈ]ýÕCÜÞ&%žü6 'yç¶jïwêÔ–£GOhí[×6ÌÏàÁ! ¨¾ZîïÌàÁ!Zû’#SkŸfͺ°ÿQµc‰‰§puí¨µ¯âlÂÃ_8fggKff–Öq?÷!Ÿæ##7Ò±cœòŽÉsIÔ³œ(©gíâ2¬Æ¤ÇQòôcˆ9A”œÅ£¤æ•ŠÇÔ4&ç5‰’¨ÈIa5úæƒUªTæþýòþÞýív¼¼ÞÄÖÖ–òåË4fGŠ,cË–¦N ¥F¼òÊËLÿûÿC/”Ü_…ë7t£e«¶üoK Ó¦„JŽUJý'…L J•*êÇB'PµjUªV­JhH0;vî’ì³8¤|~ú´ÉÔptÄÎÎŽþHNùErùúðûï78{î<ï½Û€wý:qöÜynܸ!9>«2Vܹs‡{÷þÆÁ¡:_Μ^¨¯Øov0eR5k:ñÊ+/2q¼dJóÕ¢yÔq®ÍÔ©3hÖü-|ÞîÈì9óxøð¡ä2ô©¯6šë×/ˆôôtââV·’´´túõ ÒÊ&?™œ={þýÇÒ§OWÉu6RâÑdsýú-œkЪÕG´nÝ“:uœ¸~ý–V1hÛ†šˆˆ˜Êù󗈉ÙÀÖ­q¤¤¤1U+_rÅcjíЛèhõÅÉ­[ãèÑÃO+_ºÆ³xñZ>þø]­b6iié,Z´š †k«KÌ%UÏr¡¤ž…6+HiÒ1çcχ‚ç(©y%ã15ÉuMb,,¦¯¨òqkÕ#KÞzâ@»Ù>Ì;Ž:ÎMùçþ=YÕ­ïZ该·nýA÷zñ}âÎOfîÜù¤üò ü €••9«±œÆîÍ^øUÔÒÒ’KÎé[n úùûï¿Y³v§OŸaýºU’b•RÿËÏ«­bÕ­ïJò¹Ÿ°±± --¦ž-I>÷“$Ÿùã–«}•jóÙsæ±båêŽøãÇIŠ/99…ˆ%Q$<Å«¯¾Â¤Ð ´mÓú;W·¦ütò‡¼vÖT^aÇ”jÂP©T¤¦^aùŠUÜ¿ÿË—-Õ“\õ-J3ÞmÞà?_(×ÂâuTª+EÖ§8›ü¿Fyx¸°…—^²/²L]}I-£¸xв±²ªGFÆE,--ñòꆕ•% [°¶n@V–n);úÖëæÍÛøúö%::Œ€€P\ƒCU}éccjíóèÑjÖô&9yÕ«WA¥RáäÔŠÖѨQ]|IgçÎxÃHJÚA¥J¯ê¿šˆŠÚľ}ß±cGt‘v¦³)éY[)(©gCÇ“©3t<¦ªg|郱æC%Ç—\˜ËœÚiÞÐñ˜šÆ qM¢‰¹³VQ¹r•â ¡Ë=iìÖ€í1›È´ÏæðùCÆ¿c`kÌ6ÞjÕ2ïïQ£ƒøðîŒßÇÅ_Îr2é{²²žßUØmÕ«säðÿåݪz)9ïK«1©X±"ƒý9}æç¼cÅÅZ\ý¡ð6øý÷jÿ¯Zõ¹P´isjß´´4¾Ù¾ó…ØŽÚOì7;HKK“TŽ«« ‘K¿&éø1B&Ž'xBh¡vÕ«Wã·ß®ë«1oy³°° ^½º„†LàDÒɼã666<}úüËû_ÝUûœ>õÕU3RN ÅÙ¨TWHK»ÀO?}Kùòå˜8Q»|µü;]ö·¶H‰§(;;[ž=ËÑò?Æ’˜Ãӧϰ··Õ)ž\úàèX•eËfÒ¾ý',[6³È 9ú´(L­}Ê•³§Gά\äÜÒX¡Â+¿DÉÕ>»vÅÂöí‘Z[óYYYÌ›·¼Ø_rõ‰9?%Iφ@I=kÂX“BIÕã«àÓ´ÅXó¡RèÛ>ÆBIÍ:SÓ˜Ü×$JkÌ( OŸ>#%åÂfÎfkÌ7Œõy¾÷žR®\9ìíì¸uëBC§¨}¶B… \¹ò«Ú±Þ½{2…+W~%##ƒ‹—.1j´ñŸðÏ?ÿ°|Å*6lw¬¸X‹«¿&ÂfÍæöíÛܾ}›°Y³éÚåùmcÚ´9µï4yÃŽŽjÇkÔ¨[cWâöì“TÎèÀ/HM½BffN^·…Eáâۇï3mÆL~ÿýüËÌYs$ÇZX»’ÞŸ|Êž=û¸{÷™™™Ü¸qƒðy ðlÖ4Ϧ±« +V®æéӧܸqƒÐÉSÕÊЧ¾ÆÖLÙ²Öxx¸°qãB6lØ©Õgóïv]Øß†ŠG“MÍš\½ªžsõê jÖtÐ99HJ:‹£cUNž4î"¡)¶O@@oV¬ÈyBJL̃ßv½eKþþÁìÞ½‚7ÞÐþ±mrk~ëÖ=ÔªåH‹M ³Ü˜ŠžM9ôl )‰©éG®ñUð º ô|¨$r´¹bJš7%É}M¢´ÆÊX Ì¯™uë»baaµj:Ѻµ7ßR¥Šy6_ΚÁ¬Ys1r UªTf ÿöíž›<$` õìÍ¿ÿ>Ì»m¹_ß>XZZ2løH~¿qçÚµ =B‘:$ÿ®î¯¾ò Í<›²`Þó/TÅÅZ\ý5ñVK/º¼ßÌÌLÞõëÌÐ!ÏwèÕ¦}L½}ó³aÃ&Fkˆ£Oï‰XɇŸ_îëëð᣸y믿^G­¿ò3hàg&ý—ŠÂÚÕŒø|(ë×obÒ”i<{–FåÊ•i×¶5óç?¯ÛŒéS˜:…¨èå¼öZ%òçàÁÃyïëS_SÑLvv¶Ú:Œ”x Úx{{²ÿQ\]ëåÛ³çmÚ¼i°8‹ãÔ©ó¬YË™3»iÛ¶mÛ¶ iSåŸþ¦Ù>.T©R‰={Ž»ƒ7Ì×òåÿ#(hÿ÷kñôt+þ 0{v hÞˆÊÔb6%=›"JêY*ÅiLILM?¦6¾LQ?ý05Í›’ÆLñšD ¹kÓ×NTµw{ËG||©:^=Ï[‰Kdßc@ €"÷Ð_ß¾ŒÑŸ6mrÓ”’’JPÐL\\ê±d‰nOÉÐ'ïMJORÒÊ•Óm/)hê SkŸ\V®ÜÊÌ™K)WΞ³g÷ÄÇœ9Ñ„†Îgûö(Þ}·½,eê›{w˜éÓsüø7…¾oˆ˜õÁÔô¬­RÈ©gCkLILM?¦6¾rQb>̹/0Ÿ˜¥ùâ0)yM"çYö*?¨¾0ð}ÂÜ¥I‹f². H}v»±6g“)u4çú™"¢Í ÇÔÛÅP  I„‡/çèÑdffQ§ŽtgĈþ”)c%«/¹â‘óî݇?~©©¿Q¯^mÂÃ'ЩS[M® Jß¾A88TaΜçO©7n6þy—uëäþpa9uOƦÔ>¹<~ü‡– dòdÃÜ-ST¾á_äµ×*ÄoQx{÷`ìØA¼ÿ~‡Bß7µ˜MQÏRl”F =K¥8)‰©éÇÔÆW.JéÇÇ—¹Å¬´æ¥bJSêšÄà Ÿ~¹™ËûWѶMkqÇ€@ 0†ZL‰¬¬,œœ¼9th šÏ¦TAa= ôAèG`hJ£Æ ±0ðß.k*.efBýv– 4£R©ˆŠÚDÕJÍŠ ä"ô,С¡“ƒœµ€2jÇ®Ÿ‡aðµ1"Àì±´¬K­ZŽÄÄD;@o„žú ô#04Bcò¡¾0Ðwª&¾ba@ 1v>¸@ 'BÏ}ú¡1ùP\a³wÀB™G @ @ 0¹_ÿ- =*@  TP¦¨7O?ƹŸO+‹@ @ …) RAa÷ tòó “Ÿ‡Â! ‚’ÌÂÅ+µþŒ¦g3Ky~³>¹g¯+–»&Å—&›øøD¾þz- IdffÒ AFŽü”~ý>0hÿ¼ýûˆ…Žw6šKÝÓÒÒ™5k)7îäæÍÛ8:V¥OŸ®Lœ8 ›²† Y#RúBjíÞ}ˆàà¹yÏöž;7X¯g{›KŸæçÎ{¸»wæöí»¥b,kšÇllÊòìÙ/²Ä§+EõEqósi>ç–æs¯ sE•óP‚©@`¢¨TW^xébS½zbÉ’õddd‘‘IDÄ:zõ¥wtñ%ŦC‡~üûï#víZÆ;I¬_?Ÿõë·3c†v;ôšcÝÃ×ñí·‡øæ›HîÝ;Åò峘:õ+Nž<'{ÌR [Bxøï?{–F»v½IKKçàÁ <|xŽÍ›¿bÕª5»Òªç ÂñóóáÌ™8îÞ=źuóÙ¼ù[&O^({çBé=7I=w›3ba@ ò±ví<Ê”)ƒŸŸ?~~þX[[³ví<£ø’b3vì ÞHëÖͱ³³¥Q£º¬Z5‡ˆˆu²Ç#rÕ}õêm,[6w÷†ØÛÛÑ¢E¢£ÃX²d½ì1KåÈ‘M´k×BãûK–¬ÇÕµS©Slj²e­qwoÈ®]ËdÅû4!a }útÅѱ*eËZãâ’£çÈȲÇ#rÕ}˖ݬ\9›† _ÇÖÖ† ê°lÙL¶lÙ-{ÌRÒRl""Ö1nÜ`|}[akkC‡Þ dñâµZÅcŽ}šË®]ñ?~†iÓtûâcÎuÏåáÃÇDGobܸÁ²Ç¬ Eõ…”ù¹4Ÿs•ŒGI_Rl”èûy¹}i²‘Ò>†ˆG.ô©;ääZ5oþ¾F›øøDºtL… ”/gWÖ­Û®s¼rP\ÌRõ¼{÷!7~[ÛF¸¹ubïÞï æKÌI?Rqph‰MCœÛÒ½ûp~ú)Y'›âè×/ˆôôtââröBˆ‹[IZZ:ýúiUNDÄTΟ¿DL̶n#%%•ˆˆ©ZùÒ5žÅ‹×òñÇïj³\uèMtôfµc[·ÆÑ£‡ŸV¾¤Ø89U'5õ75_ÉÉ—¹qãO­bV’””Ô¼üV;;6ìÀÂ…«ÈÎÎV³zÎùryöìú÷KŸ>]µŠÙõЋ€€P._¾FZZ:—/_# Ô$.F¥ô…&›ë×oáì\€V­>¢uëžÔ©ãÄõë·´ŠÁ\õ>½5nTÒ¶m fÌÄÓÓk×n0rätÚ´y“I“>—µ^R‘sqz>wî"¾¾}Ù¸q!ÞÞž$$$ñÉ'c8|x..ueõ%sÑÏÌ™ÑüñG¢dݺ ã‹/áááʃ9xð{Æ›MDÄ´¼Mæ¤Øh‹¾}sóæm|}ûF@@(®ÇÁ¡ªÎ¾¤Æ³sg¤Òùcæ’ÿ,¥)zÖ6gÒ\òµÀ°c§zõV€v{ tê4€Ñ£вeS,,,8~ü ÇOaüø>ûì#É6JòèÑ“ÿ6"‹——?üpšÏ>ORÒÊ•Ó}Wê˜3'šÐÐùl߯ﶗµl}X¹r+3g.¥\9{ΞÝc|0„°° ê×wæÆ?X°`‰‰'ùþûmØÚÚħT4¤¤³ Jdä ÜÜšú!tíÚñã€Ò­g_ß¾ŒÑŸ6mšÿw[}*AA3qq©Ç’%Ódõ¥ JèyР‰üþû,\B:5¹víaÔ¬é@TT˜A|…”¾b“»'ϦM‹òöäéÓ'ð…=y”BI=†\×0ú „žââ3}úbŽÿÆ`>ô¡`_H™ŸM휫¤žMíÜ”‹z–¢ %‘u{‡ÎÌÝ|ðm¬[ÒòI;@óÂälŒ“œ|™Ñ£gФI#¾új²F§ññ‰Œ5ääý:- IøøôÉËq74Ú´!2$”5ª:œcÇN2tè$ÎÛkPŸRNt»vÅ3xpû÷¯Ñú¶«¢n»Óõ«Íɹ žË•sãÎØÛÛåÙ<~ü„jÕZððá‹·qéãËjìè²0°mÛ^æÏ_ÉÏ?ÿ‚­­ ®®õ‚ŸŸV6JÒ·oU˜3g|Þ±qãfóçŸwY·NÞ}Šýu’×^« «?©<~ü‡– dòäñ»ùüúëu«ñᇙ¯¿!00Œ×^«hð'w¢Û²%ŽÏ?ŸÂÞ½«õ¾íÊÐw FA=»¸t$&&B-ßèüùKôì9¢Ð/ôúø2†;º, Ì“¬¬,œœ¼9th _@„ž% ¡gAI¢4êÙ ê{ Ü¿÷¤åGKÉ13vΉȇ4N~oa˜Z.–.Ô³!s&KóØ” T*QQ›¨Q£Z©9I J.BÏ‚’„г $!ô,erþùo§›ù] ½ TT7Ò”?Ö·ïy6šrN‚ƒ‡(Tu=zBŸ>¬Y3— ^!:z&}ú*š™¿}ŒA@@/FŽœNÅŠ¯Ò A£Å‘?ËËËÃhqhƒ=Ñ_ß¾¼ñF£¼œÉùóWpø°v-)ÍcGPr±´¬K­ZŽÄÄD;@o„ž% ¡gAIBèYrÖʨóõ€J‡!®¾Úá)SF¾œþýǾ?–‹¿¦NýZ-çdÁ‚£åœ :‰®]}󾈶léÁ{ïµgذɲçÛHicðñÇï2fÌL>ý´›AýäϵÊýþ[惃çðÞ{ƒ^ø¬®¹Xú¦³=»¹5`åÊÙŒ9-/grÍšð6R’×’(9v%cçÏ r"ô,(I= JBÏòñßí±zlEË4w¨N»A?»Ç€Àô)ù6ÓGì1 @ 莼{ dsøü¡{ dU„kÆÙE_ /"ßF @ RÈI%°Èw$Ë®pKY!òm@ @ Xü·`YŒ©ÀLQ©®píÚQš7w7v(dîܹGµj- }Fðƒ š…³s[llâêÚ‘;佟H—.ƒ©PÁƒòåÝðôìʺuÛõЧ¨gË_EÙ×>†ˆG.ô©»…Åë…¾ŒÅ±c'éÝ{4•+{òòËîxzveÍšXT*•V6óÜ÷ÆßÁÖ¶nnØ»÷;½b3÷>µµmdÐxäBß±œKQó¡’ÄÇ'Ò¼ùûzÍ?†§æÒ§iiéL™²ˆºu}°³s¡n]¦LYDZZºAã‘ }ê.u®S ):,ÍZÍÌÌbæÌ%yZuwïÌÎñG.ô©»!®!õEÊÜ+7ba@ ˜ #FLã“OÞáø³gi´k×›´´tÜÀÃ‡çØ¼ù+V­ŠÉ³éСÿþûˆ]»–qçNë×Ïgýúí̘¡Ý]3½zbÉ’õddd‘‘IDÄ:zõ¥_åtô%ÅFJûÈ\ÈUwÈY-ø2&„ãççÙ3qܽ{Šuëæ³yó·Lž¼P+›sç.âïÌ¢E“øçŸ3,X§Ÿ~AJJªVñ˜cŸÖŸ!!Ã0 »ìñÈ…œzÎEÓ|¨4aaKŸ ñ}©óãÔû4(h'NüÌîÝ+¸ÿ4qq+9uê|Ltô&Æ,{ݲe7+WΦaÃ×±µµ¡Aƒ:,[6“-[vË\ÈUw)s]IÅûkõêm,[6w÷†ØÛÛÑ¢E¢£ÃX²d½ìñÈ…\u—ëRNŠ›{å%ç.±0 ŒÎƒ:t2K—N祗ì_x?6vC‡ö)²Œðð`,,,ÔŽÙÙÙ’™™¥u<Ë)ø·aà@õ•^ÿ`ÑÚWq6RÚG*rÔ½Y³.ìßTíXbâ)\];jíKŽxLÜ_*¤Ú$$œäwÚª½ß©S[Ž=¡µosÓsA"#7Ò±cœ´ Y'_…¡´ž‹›M 9ç)˜›ž-,,°´T¿Ü¶´´Ô)nsÔsaH™Kæ¦Õ7þ¤~}gµc×ç‡Nk·¹iUÎkHsFë…sÉ1DžŒ>Hͳ’’'¬k._þüL)íSšó¬JsŽ«!ò!‹cìØ/ñöö¤sçv…¾Ÿ’’Ê;÷pwïŒ v`áÂUdggYîâÅkùøãwµŠ¥_¿ ÒÓÓ‰‹[ @\ÜJÒÒÒé×/H«r""¦rþü%bbö°uk))©DDLÕÊ—]ÛÇPuèMtôfµc[·ÆÑ£‡Ÿìupph‰MCœÛÒ½ûp~ú)Y«x EFF&gÏ^ ÿ±ôéÓU+›ë×oáì\€V­>¢uëžÔ©ãÄõë·´ŠÁõœŸ´´t-ZÍ„ CµŠW_šPZÏÅ͇¦†ÔùGŽqjŽzèE@@(—/_#--Ë—¯ªõbйê9)ó¡HÑaiÕª“SuRSSóŸœ|™7þÔ*fs×j.º\Cš;Ó×NTµoÜ«ÇV´|Ò€v³}˜;wÍ›7rr3¼½=<¸eË6 =ý"ÑÑ›HL<ÅæÍ_É_Rl¾ü2’;ãY¶l&uëÖâܹ‹ 2‰åËgáéé&kÌRhݺ'C†ô¦];/*W®Hjêo†ñæ›î̘1ÈÉÓkÙ²;­Z5cÌjԨƅ W ]wKž›Â ]À½{÷‰ŒœHk ‹×eÉÕ5GýFÁ6”+¹«îŸ>•+W~cáÂPj×®Áo¿Ýüo!ʉŋ§ègõê­øãDþ‘n݆‘’²ŸjÕ*/jÏʪÍ›»³hQ(îî ¹rå:!ôèáÇèÑ õ³sgÅ¡OÝ=zBÍšÞ$'ï£zõ*¨T*œœZqàÀ:5ª«“/M6ݺ ã‹/áááʃ9xð{Æ›MDÄ4ºvõÕ)~9È¿ðæááBB–~ý-ÊÆÊª±´´ÄË«VV–$$lÁÚºYY—uŽÉôœŸ¨¨MìÛ÷;vDë·T_šPRÏRæCc¡Ïücˆqj.zNOÏ cÇþ9r<ï˜ûö­¡lYkb7=ç?Mó¡HÑaiÖjxørvíŠ'2r¯¿^“óç/1jÔtNœ8Kfæ%b77­æ"Ç5¤\hŠyî¬UT®\E§2»|ГÆnMؾuÙ/©8xþ úÂÀ¤Ä,:œ>ÀÞ;ÇÕÒÓ3X½z±±û8pà:xÓ­Û; Ð]çIMR|I±©_ÿm¶m[‚»{ü²Oœø™ÈȬ^=WÖ˜uåæÍÛ¼ñFgîÞ=Àüù+8}:… hüŒ›‚<|ø˜:uÚrâÄö¼[1¥´\#樟‚Ö†rÅ#rÕ½reO~þ9Ní¤sëÖmš4y—;w’ô޳àÂ@ݺ>Œ;ˆ!CzçÙÔÞK/5æÈ‘MjOÙ8{ö=zŒàÂ…wÞßµ+žÁƒCØ¿ o¼¡û]r„OŸ¼Ü5C mû(Á!¡Ô¨QÐÐá;v’¡C'qîÜ^E|ÇÇ'2jÔt’“÷kýÙ‚wÒè3¦§gœ|™Ñ£gФI#¾új²d›råܸsçööÏ!üøñªUkÁÇÚm%'Jè9—¬¬,4ðeãÆ…´hÑÄ ¾ŠC)=K™µAN=kŠC×ùGŸq*Jèùóϧòë¯×™?"ÎÎNüúëï†Q¿¾³,‹íº`ŒùYÊ|Xrê9):,-ZÍÊÊbþü•¬\¹•ë×oQ¯^m&OÁ A¹_ût90†V帆Tbî5Ä€Z*ÁÂè@jÝþ­ÐÌ-WDÎ<C’?ÏJJžž.¹|…åg*Ý>æ–gUÒ”ã*g>¤®\¹ÎС“^HWÉ?©Ö¨Q W×zjŸ«W¯v¡·UoÙ‡¿0»w¯0ú¢@RÒY«j½«¯6hÓ>JЛ+¶ML̵[ÿ ——Ç ·CJEΧ”-k‡‡ 7.dÆZÙÔ¬éÀÕ«7Ôl¯^½AÍšzŤ/Jè9—­[÷P«–£Ñ@9=K™µA‰§uè:ÿè3NåB =oÞü-+V|I£Fu±µµÁÅ¥.«WÏaóæ]óYƘŸ¥Ì‡Åa=KÑaiѪ••ãÆ æâÅxž>MáìÙ=T«V™FŒ÷ÈT¥µ*×5¤©<)I[Ô®þû}±Ž‘C¿~ÁÈsEäÊ“1šò¬¤äéi›K¬)?Sjû”Ö<«ü”¶W¹ò!¥¢é±@ù'Ò–-=HNV¿}úòåk89UW;¶|ùÿ4hß~»Ü()C9uê45tŒ=N•Ôsí¤ãn¤jÌùYÊ|¨$RtXš´Z¥K7н{'ÅüDI­šÚ5¤1´Ç€ÚÌ$WÄy2rP\NiqyzÚækÊÏ”Ò>¥9Ï*?¥-ÇÕùù)˜J %¶¤¤³ Jdä ÜÜšú!tíÚñã˜3'šÐÐùlßÅ»ï¶×;N}yôèÉ›ŒÎÅË˃~8ÍgŸ')iåÊÉ›[)¥}ŒÁÊ•[™9s)åÊÙsöìƒøèÔi£G e˦XXXpüø†ŸÂøñ|öÙGñY¾¾}1¢?mÚä<ò(%%•  ™¸¸ÔcÉ’i’mλˆ¯o_6mZ„··' IôéÈáÛpqyqÌ%õ w˜éÓsüø7²—­+Jè¹0L})ó©S%õô턃CæÌŸwlܸÙüùç]Ö­“ÿY¾Åµ1xüø - ÈäÉ# âcÛ¶½ÌŸ¿’Ÿþ[[\]ë<??ƒø+Ž„„$Â×sôè 23³¨Sljº3bDÿ¼¾b°{÷!ÆŸCjêoÔ«W›ðð têÔV“kƒ¢´ž½½{0vì Þ¿ƒìeëŠz. c/ 6·j;?›Ú8URÏOž¿þzGÇj|øaG&OÁ+¯”—Õ¶(¡US»†„âçÞ±0pút |0„_=B``¯½V‘I“>—ÝOa;v’qãfóý÷ÛñW7nüÉoøqï^Îæƒ ørúô·j›M=}úŒJ•šñäI²d›\ròÚ¶pðàIñHiŸGžP©RSÒÒ.H®§Ü,X°’¯¾ZÃèÑ üÌ ¾´mCC¢ÔØ©T©çÎíyaóAw÷çeꃔ;%ƒ¬¬,œœ¼9th /GQ ¡gAIBèY`.­Ž!òí1PH”0f^“±ód R0ÏJJžž6¹|ÚægJiŸÒ–gUs\Áôò!æ‡J¥"*j5jT'rÙ#ô,(I= Ì¡U…øïÂß²3ƒЋ‘#§S±â«4hPÇ >>ø`ÉÉ—ÉÈÈäêÕß1b.\aذO â¯8|}û²sg<÷ï?àÙ³4~ú)™þýÇÒ·ïy6Ç÷eÈPNœø™§OŸqîÜE† UËi’b9ù™¶¶6¼ýö[…Æ#¥}:uÀþýGù÷ßG<|ø˜øøD Gpð™[G=¡OŸ@–-›I… ¯=“>}yôè‰Aü׆Æ@‰±óá‡ñ÷æ—_RIKKçâÅ_8pݺ½c‚’‰¥e]Â×%T ¡gAIBèY`.­*Kc8ýøãw3f&Ÿ~ÚÍ`>>ùä}ºu¦–'søð&£mž1eÊHÂ×ӿÿØò¬riÞÜI“Fàﬖ§4P+€/¿Œ,r})íãï߃©S¿V˳Z° ÄhyVC‡N¢kW_¼¼<€œ»'Þ{¯=ÆM6HŽkqmh ”;_}5‰iÓ¾ÆÏoà ùTLa³4@.„ž% ¡g¹ ´ª,ùö°Ä«uÎ>Ãí1"WD Е’0vÄ@ îȺǀ}6‡’)ŸJ rEÝcG @ ÅS ,-ëR«–#11J»Ì1v@ !°¥žGƒJu…k׎Ҽ¹»‚^ó§$øøDš7¿ÈçÈjƒ\åÈå«()uß½û¿ƒ­m#ÜÜ:±wïw:Å*%ž’Žý%—ž;tèǼyËõ*C  (r׌òT@ ÈOXØÂÃ'èUF¯^£X²d=™ddd±Ž^½FÉ¢Ö¾¤ÆS\ÝÏ»ˆ¿0‹MâŸΰ`AŸ~ú))©²Ç\RQ²¿¤ÚHáË/¿`Á‚Uy1 @ ÈÉ_ýEvv6  päÈ&Úµk¡Wk×ΣL™2øùùàççµµ5k×ÊÿÄ )¾¤ÆS\Ý#"Ö1nÜ`|}[akkC‡Þ dñâµ²Ç\RQ²¿¤ÚHÁÓÓ5ªqàÀ1½Ë@ (È¥‹—(“Q(°0˜p„Ä„#ƈI ôÆÂ¢ȿ¥0xpªÿÚëïÌàÁ!Zû’#ž„„“¼óN[µc:µåèÑZ—%G<Íšuaÿþ£jÇOáêÚQë²äÀÔúKn>þø]víŠ7v@ J oy·Æ¡†#ð߀ʼn^oµÆë­Ö…~¨¸W ‹× }ÙÚ6R³{ðà!AA³pvn‹MC\];²cǼ÷;IïÞ£©\Ù“—_vÇÓ³+kÖÄ¢R©Šõ¥"'Y÷xäFŸö1„6ô¥¸þŠO¤K—ÁT¨àAùònxzveݺí/Ø7vÒÒÒ™2euëú`gçBݺ>L™²ˆ´´tµrŠÓ†”rL±ûõ "==¸¸•ÄÅ­$--~ý‚´*'"b*çÏ_"&f[·Æ‘’’JDÄT­|ÉÏõë·pv®@«VѺuOêÔqâúõ[Z•#W<½‰ŽÞ¬vlëÖ8zôðÓª¹0µþ’ooONœøÙ¨1@ (™ÜýëO~¿s‹ék'ªÚ»¶Çê‰%õ]ÜèÖý#æÎGóæ €œW_ß¾lܸooO’øä“1>¼ —º…†.àÞ½ûDFÎàÙ³4Z¶ìN«VÍ3ÆŸ5ªqáÂBC°k×2Z·îÉ!½i×΋ʕ+’šúa¼ù¦;3fŒÉ ÚâuTª+z7D¯^£ðöödðà^”-Û€ôô‹DGo"1ñ›7¥wùÚú’O»v½™:u>>½ m]ûK—˜åB®ö‘KrR\YX¼NÛ¶-˜1#OO7®]»ÁÈ‘ÓiÓæM&Mú6v>ÿ|*W®üÆÂ…¡Ô®]ƒß~»ùßB‚‹O¤iCJ9ú´sõê­øãÄBÛBŽþÓ·œ›7oãëÛ—èè0B9xp=Uuö¥•U=22.bii‰—W7¬¬,IHØ‚µu²².K¯”–ñhâÑ£'Ô¬éMrò>ªW¯‚J¥ÂÉ©¬£Q#é󋜘RikSwïÞ§~ý·ùûïŸô*G AÉaî¬UT®\E§Ïvù 'Ýš0väpÞjÛšøÔÿ“¶0BýúÎ |ÌÜe\½ú{Þ—þ‚<|ø˜:uÚrâÄvœ˜?§O§°aí‚¿yó6o¼Ñ™»wOò}yHOÏ`õêmÄÆîãÀctèàM·nï0`@wÊ–µÖ»|m}i¦vÐ¥¿tY.äjS\ÈESl_|1›¹sǫݶüûïàéÙ•Û·sn—2v*WöäçŸãÔ¾ݺu›&MÞåÎ$@š6¤”cê r„OÞHëÖÍ îOSÝË•sãÎØÛÛå{üø ÕªµàáÃs«0† ¥FꄆçØ±“ :‰sçöêTVÁ;MtíSé/mmŠ###{{22.éUŽ@ ‚’ƒ\ ßlýÕk9²þÈji+Ô%Ç52r#;¶É[ˆÝÇС}tª€¡ve9ÉE£dN²©æúùððàêaggKffVÞßRÆŽ……––êû‰ZZZª•-ERÊ) $%Åѱ*'OçËw.5k:põê µcW¯Þ fM#E”“N°bŲ³³‰‰Ù£WJuEí¥+¦Ò_róàÁCÊ—/gì0@ ”@ò§Hz*¶9®iié,Z´š †ªOIIåÎ{¸»wÆÎÎ…† ;°p᪼G$$##“³g/пÿXúôéªöžƒCKllâìÜ–î݇óÓOÉRª¢†ÈI.%s’ål9´al/^ËÇ¿›÷·”±Ћ€€P._¾FZZ:—/_# TmAAŠ6¤”%£5qêÔyÖ¬‰å̙ݬ^½Í¨uóöö|aamÏž#´ió¦‘"ªT©Äž=GˆÝG ˜VÉÍ•+¿Q»¶£±Ã@P¹tñ2eÒsžJ`1}íD•k{Ê‘J mŽkTÔ&öíûŽ;¢ÕŽ[YÕ£ysw- Åݽ!W®\' „=ü=z€šmþ_i=<\HHØÂK/ÙçÄ×m_|1W}†½½í ¶YYYÌ›·ü…»lmmX¼x ^^ØÛÛáæÖ€¨¨0¢¢6½`«R]!-í?ýô-åË—câÄçÏ’Ž]Š——66e©R¥½z½ÇêÕs™81\‹&yÑŸ>8:VeÙ²™´oÿ Ë–ÍÔ¸( Õ—>ñhÓ_RÑ'žråìéÑ£3+WÆ9i*¼¢q£2}ÚG.mÜi_©÷wíŠ' „íÛ#ó@ÚØ3f&vv¶¤¤ìçéÓ’“÷cmmMPЬ<)ÚRŽÜc°°¶6C‡N¢kW_¼¼<hÙÒƒ÷Þkϰa“ ⯸º»¹5`åÊÙŒ9—_vgôè¬YnÔEÈyŒÞ½{÷éÞ½“Qã0µþ’j#•Í›¿¥KÝ5ÿŸ½{‹)ÿÿþšèÆÚ66×B”(ÙÉý’ÔÏ%ŠeKrK·JJ*—YŠ\r)—Jˆ’%"«°Èn¡E²KZ—¯eµ¬%¢ëüþ°Í65—33g¦²ïçã‘GyÏçóþœó9Çœ3ŸÏ9„B‘„ƒ üþâ1 1“7TÍq57ï$X&nŽkbâ)tèн{÷¨õš¾~k¡2 S§Žb‡¸kh¨Ãʪ+ˆ€¥¥6oÿA¯O+Ü¿ÿˆIs”¦úWUÜüJY¶—ªðx1vìlÍQxN²¬äéÕ/<¨ê[ìÇS1~0NŸŽ¥¥ðc>™ì; '›{JpQªkWÄĬƒ…ÅHÁÓ˜ô &刢È>X×£ª‹ßPkÙúõJ«IÛG²Å¨Q¶JËAZZšhÚ´IO#¨Û‹­þœ}OŸÂÞ~+åB!„ˆÃè²ÌqýöÛ š+²œ¾}­—'<”=?ÿ! ÚH¬¿²²eeecnÝú:ÔÝ<Ìú4Ç•æ$ «ë¾ÁÄ®]‡0sf NœØ.·{­×™î;|w­>"ˆißVŽ( a=vðù|ìÜyúú­ajZw£;>uAAáX¸p:ÔÕ]Ã'„B‘£ žžS°n]22® ¤¤é陨°a7<=§ Å¥¦ž‡––&†í'²œyó&cöì¥Èξ‰÷ï? 7÷.fÏ^ŠéÓ¿ÄØÙMÆñãéxõê5>|(ANN¦NõÃäÉc1#F¸ãÌ™‹xóæ-ŠŠÞ!==îîþ˜-Ï:PØÛ·ÅpsóAtôèêê *j ÜÜ|ðömqäÃt{©ç /¯4oþºt1RJõ­o0±n]æÎ]Žƒ7 †C×ÄdßùúëaððÀ/¿ÜGII)îÞý 3fbܸlÕ¼- IDATá‚&}ƒI9 q=ö¨©™ ,l¶m[Yש|ÒÒÓãáç7³®Ó „BÈ'íã7‚Œ¾†¨>ÇõþýGèÔ©£È9®k×îyo*ÖÖX¶ÌÈψvíZÁÝý¡gª{!,l¦NõCyyŒŒ àî>^èÄÅÃÃ+VlÁÍ›¿@KKææ°qã88 ‘i°EÒ×}ûÂ¥¼[vÕç«Vý^}è*Óí¥j&ŒÂÂ…k0mÚ8¥Õ¡Œ¾¡è°`iÛ+ `=`ôèÚ'þy _~©ËhßÙ¼yV®Ü‡xúô9Ú¶m,_î)ˆaÒ7˜”SßöA¢Zõiê!„BQ'$.ˆoÛm(½ãˆ}*!l¨¨¨€Áœ;·Ÿ†ÿ‡Iz*!„B!D2¶žJð]âT4åãÜísG ˆšOL›hN2!„B!„Ô#NÕLfS Q”šš :th‡¤¤ÈºN…B!„BH5Œn>Hˆ¢øü<|xÖÖu !Œ:uFF6PS3QèYôõͧÚ.&ÂÂvÁÞ~ŠÜï··Ÿ‚ðð],fD!„R÷þ¹0@s !¤&oïDE­Fyù½Oê†{ªjW}»èPVVŽˆˆ½X»v‘Üe¬]»7îEYY9‹™B!„Ô•×hÄ!„ˆñàÁØÙõ‡šÚ§u¨üTÛ%Í÷ß_‚Ap¹Ýå.ƒËí}ýÖ8{ö2‹™B!„Ô­ÿÖ§BBH½cié€ vã?þTz SŽ18cTTT†Û×õ·ßŽ1 _ÂÕÕººVÐÓãbÓ¦™ËÖ®'2пÿ7ÐÔ4…žîîþxõêµP̱cgÁå:AKË ;ÂÞ½I"ë©þ»¨õ·qãÙ@C£ ŒŒlĶGRÛ _bîÜå02²A“&æÐѱİaÓpúôµÊIII‡‹‹ƒØ:ââŽÂÄd45Majj}û¾;aÂ(¤¤¤‹|B!¤!º0PðÛUüvU%3ù-)&==ÖÖcÄÆ\¾| '.€žŸn.× ±±Éà+ðUž(²~ÒÓ3áè8 ººVhÖ¬;¸\'±pU¡ú‰Aõ--3™rfR¼~]_ßP†¦¦)ÌÍ‡áØ±³RËQ´ª¢ì}§ºÂ—hݺ·R×»ûx$&ž‚¾~ SP\ü^)1Lñù‚!öU¿Ë:ä^\?S¤¿MŸ¾ŽŽvøí· ÈÍ=üü‡2½ŸI»6mŠAHˆþþû~ùå,ttšaöìe‚×OœÈ€·wBCýðâÅu¤¥ÅàÊ•™ëÙ¿ÿ¢£áÀ¼zõ3öï߈íÛ÷ãС“2µ}üøyèØQW®$áÍ›[¸ÿ”ÀÆf"JJJ‘‘±EE¹HHØ\ëMQeɪ!ö @ú¾S§çJLš4†ÕœkZ°ÀYYGq÷n:ä"4t;Z·î wwœ;÷#«1ª$ª)Òß`ܸápu ]]´n­‡mÛV²œ5‘±C‡öƒ¶¶¾üR!!>HKû÷Û÷µkw`Ë–`üßÿ ÄgŸ5©©1vï^+s=[¶ÄaëÖ`ôík…¦M› _¿žØ²%{EÆ‹kûÍ›¿`Ô([´n­‡ÆAO¯9¾þz22ö×*ãÁƒ'02j/!§åèßÿ+4mÚ}úXaË–åX»vG­8#£öxøðw™ÛL!„R_ ø¡ÇüÐc‹Ò*‹‹ GãÆáààppð€ºº:ââÂeŠ€ ÂÆ¦·Øº.]: 77'´k× êèÚÕ{÷®ÃŽXÏ™-l­?¿™8þ´†¶¶ÌÌ>¶]ÔIY](*z‡¨¨ƒð÷Ÿ%X&O΢ÊÙ¶-ææ¹FFÐÐP‡……)RR¢YoGCì€ô}§JJJ:²²n`åJù.tˆËGcãöX²dnßNÃΫqìØY :I)1 ÕðეZþ«W¯áícchkw‡c K½Äܸñ  ÿ­;SùùÑ«—¥Ð²>}zàÞ½"ãŵÝ×wzöAƒ&ÀÛ;›7Ç"+ë†ÈØ¢¢wÐÑi&6§>}¬„þîÝ»òòîÕŠÓÑi†¢¢·bË!„BihX»ÇÀ¬YK0c†ð·˜5k‰Ð2NÕð13‘—¿EE¹ MÁb‹¸¶/_î‰_~ù3gº@WWW0dˆ|}CkÅ6kÖ¯_ÉToeeí¶¿~]„fÍ>“©B!„úìã…ªÏ=|þÇ9DF®ÀíÛ÷”t ˜˜Š;wî#2r… fÊ_”––"5u 5uJJJ1eНL1²*++Ç­[¿bêT?¸¹9Éô^¶òáñ&"**AhYbb*œÿ½–2×ÏÖ­q˜0a”L9+CII)6mŠA`ੱ’rWÎ;÷QXø#¡­Ý¦¦öˆˆØ‹ÊÊJ¡¸¶mûBSÓ††ƒ1~ü<äääÉܶúF}ÜwüüÖbÀ.FŽ´‘ù½Òò©)<|¸\'˜šÚãÒ¥« š‹çϳ†¡Cû±£JʘJ l.ü„ˆˆ¥033––&àܹ+B1=z˜áâEf÷¢iܸ‘Ø‹{:u¬5O?+ë:w6”9oCCLž<+Vx#%%99)µŽ·ãôQPðHl9?þø³ÐßÙÙ7ѵ«I­¸‚‚GèØ±ÌyB!„Ô7U§ÿœ¸ ¾­¹-«¡_r Àà›ÞX¿ÞÖÖ]d*ô÷ߟÃÎn2¢¢VƒÇ[ŠŒŒx´mÛJd,‡c,õÃ11Õ¿™³²êŠK—Ëý (“|Äyû¶íÛ@^^Ú´i >Ÿƒþ8{vÌÌjðdkýÀñãéðñY«W¡E‹/äÊ_‘¶W·sçA¤¥ý€cÇ¢$ÆIËY\9u‚µµ6mZ S<·ÎÎX°À0nÜ\,Z4VVæxýºWàïÿ-"#WÂÉÉN®v)º~êÓ¾sþüO7n.îÜ9ƒÖ­õ—Ç´®6múž=Ëðñi“'››“Øo…ÙŠQ$ïºÆ4—ªcž´ã¢¨×v…MoøøLÁ¾ñÛoÿÄŸ8‘ùóW`×®Pôë÷ž>}Žˆˆ½Ø±cU­ò:wŠU«büøáhÔ¨‘Ðkññß!4tbc×£[·ÎÈͽ‹iÓü±|¹'&NtdÜöþý¿ÁÌ™`kÛm۶Ÿ¾Ä¶mûqþüÈ̾··]ºaáB‘ë¤sgCÄĬ‡¥¥)òòò1mš?Ö­óÇèÑC…b7lØüü‡Ø¹sµÈœ!„B”i}è^èéÉ÷y×q¬ ºuïø.é ʵ*qþÎ94f3ÁvíZ!:z † qÃùóĞؒ?´ÊäŒÒÒ2äååcÁ‚U ÇæÍËå.K^Ÿ}ÖÎÎ#±gO–.‡ÌÌëÐÕÕyQ€i]LbRRÒÁã-Á™3±2_¨9ܹúßò¬‹ŠŠ „‡ïÂ’o)-gIåhiibëÖ`X[[ºwï‚;WÃÙÙSpa 9y» ¾eËpu =½æðö‘û€¢}µ>í;3g"4ÔOpQ€ ’ò¹y3UêûÙŠ!’íß¿ ¬‚‘‘ >|(AϞ戋 ÇÀ.‚˜Ñ£‡¢¼¼a¸}ûZµúÁÁ^"Ë Ä‚«1qâTVV õƒI“Æà?^ÀÅÅ ¿ÿþôõÛ`þüɵ. Hꇭ[÷Á×7ÅÅïѶmKŒ=TäÅG''{¬\¹Eä…˜I“âÉ“gèØQ‹ój]€„„ ñ‘)OB!„úìã…ö¦ðãêÕ[h×®®]Ë•øX(UÒÐP‡•UW8KK¹/ (ŠÇ›ˆ±cg#(h’’N M#P†Ã‡S1~0NŸŽ¥¥™ô7ÔPýC<ßœ&&žB‡íлw±1Lr–T޾~k˜›wZÖ©SG<~üTbn}úXáþ}ñCŒU¡¾ì;1gÎ2Ì™³Lhy}úö\UêS{™æ¢È…#ƒ6BÎÄÅû;öÿ¤ÖãèhGGÑÛ8-š‰E‹fÊ/ ܃K¿™&ØÛÀÌ™A¸v-\n÷Z¯»»zʉ(ÙÙ7ñôi!ìí0ª“B!¤>«º˜ðÍùø÷~r¸~ý6bc“qãÆIÄÄ‘kÞ¶2UVV¢¬¬¬Î귲ꊖ-[àÔ© HNNƒ³óH¥Õµk×!Ìœˆ'v‰ü\¾ýv'‚‚æŠ}iÎ’ÊéÛ× yyùBËòóÂÀ ÄÜnÝú:ÔÝœáú´ïˆ›_ŸN’ ‘‡ºzcøø¸#00Lî2‚‚±pát¨«³:àŽB!¤N±öT‚·o‹áææƒèè5ÐÕÕATÔ¸¹ùàíÛb¶ª‰Ýd?žŽW¯^ãÇäääaêT?Lž<¶Nò©Âã¹ÂË+Í›.]Œ”RǺuQ˜;w9ÜTëñ[u%5õ<´´4ÅÞŽiÎÒÊ™7o2fÏ^Šìì›xÿþrsïbö쥘>ýÄî8sæ"Þ¼y‹¢¢wHOÏ„»»?f+ÖH9Õ·}‡O™ŸßLœ=+ÿ£[ÓÓãáç'}”!„BHCÂÚ…9s–ÁÉÉNpR×·¯F¶Åܹʶ_ý‘_¢ÿì…={ah8_~ÉÅ´i‹àèhWgÓªL˜0 /_¾Âøñ#”VG@Àz”—W`ô虵‘öâÅ+¹ÊTôÛâµkwH|Óœ¥•cmmeË<áá]]+ŒÃÃÈ‘Càë;CãááŒ+¶ uëÞèÐa V®Ü‚—]ìûâ4ÄmQŸ×§8’޽ööS¾Ká:˜ìëlÕE©[ÿ<­½›Bùï(++GDÄ^¬]»¨®SaUCyñb6 š€¦M»AO /¾”».IÛ‚­œ™¤£˜ìË……/1wîrÙ IsèèXbذi8}ú‡ZõI;ö’’.m°B•uB”åã5€Z—Y•yq æ|Ǫ--3¡¸ôôLX[‘z°fsþ¤*?H)2g2==ŽŽ³ «k…fͺƒËuùaší|Ø¢è|Qi}CëGÔç¥×åî>‰‰§ ¯ßÇ»ãàÁ¿WJ Sîîãqøð¬\¹^^Sqôè¬[%ÔI?5MŸ¾ŽŽvøí· ÈÍ=üü‡€´´‹˜2Å‹óPXxÉÉÛ±WèÛ—“'ÏáÛow".. ý•ƒ}û6`íÚ2·éĉ x{‡ 4Ô/^\GZZ ®\ÉŠa’O•«Woaà@k‘uíß Ñчpà@^½úû÷oÄöíûqèÐI¡¸ÐÐ툋 Ç_å 6v=BC·#-í¢\ùâ×3lÚƒüý÷ üòËYèè4ÃìÙ˯W6+n>Óv1ɇ iý°!ãóùXóçÂÙ³ûкµžàµ)S|QZZŠÔÔ=€ÔÔ=())Å”)¾2Ÿ¸ŒBbâ)¡zN…³³ä“*ÑùJîªîó¿™PÖúÇÇg5V¯^ˆÂÂlܸ‘ ux{‡(T—"Óe¤½I=LQÒöåñãç¡cG}\¹’„7onáþýóàñ\EÎß—tì­2`ÙÙ7¥®6¨².BˆrqBâ‚ø¶Ýl¡öN ýŽ|°¹µë×ûÃÚº‹ÒXºt#^¾|…;V –ÙØLÄŠÞ2d¢Èƒ6‡cÌÊÐ/WWo ÀŬY®ÐÐè‚ÒÒ»ˆŠ:ˆÌÌëHHجpù²ÖÅ$†Ã1ÆàÁ½±j•¸Üîxøð ¼¼B0hP/,[6ÿ“n;À¬o°±~”é¿Þç׬ùøaèÙ³L¡ø‚‚Ç8tèNàñã§7n8&O [Û¾¬ÇHÂáãýû;mí®‚ß›7ï‰ââ<™×‡cŒ½{×ÁÝ}|­× p†‹Ë(xzþ{©ÔÔóˆŒÜ‡Ó§c1ÁÁ^°· ˆIK»ˆ#Ü}B\ÿ¨¾¼_¿ñX¼x6œœìÄæÊ$Ÿ*ººV¸ÿ51é‡L¶;“vÉš—"åp8Æx÷î6&MZˆ^½,0[áúÄÅüúkþïÿ¦âÑ£Kàp8àóùhß~ÒÓãÑ¥‹‘Üù‹ªKÕ}C–u(Ž*ׇcŒ¬¬£èÕËR°ìùóèÞ} ¯²ZÛåHzÉ1ŠÉ¾¬£c‰LF×®&Ró•tì­òâÅ+tî<ý•#6†)ië‡Íº!Ì­Ý =½–r½×q¬ ºuïø.é *šTâÜísG ð« ¨øEEïuþþ³„–_¸p66½•^¿*ç(²5gÒÏo&Ο?€­¡­­33ìÝ»‘‘ûXχ-lΕÖ7ØZ?ÊB}^]l¼±q{,Y2·o§açÎÕ8vì,†¤”i´´4¡¥¥)ôûû÷d*£ºáÉ\ž““‡¯¿&´¬_¿žÈͽ+ø;//_èÃ4ôéÓCænÜøƒIþ–‰I>UŠŠÞAG§™ÈròóŠÌùÞ½5–Y ýÝ»wäåÝ“+@üz~õê5¼½C`llmí®àpŒ¡£c‰¢¢w"ãÅaÚ.iù0Åv?¬/ìì&ãöí{"§ÔÄäÄO\Œ©©1tuuðã?®\ÉAóæ_È}Ò+‰ªû†,ëPU®°²2ú»U«/ñçŸ)¥.UazŒ’¶/ûúÎ@Ïž£1hÐx{‡`óæØZÓ<ªH:öVÑÑi†¢¢·ò4Ifª¬‹Â>¾à q]&²cÇ 6††u–“yŒÒÌšµ•••ؽ{­`™‡G5j„èè52Õ%-&,, Ö{´µµP^^!sÞl´ý«¯ê'ô­_fæuÌš„¼¼32ÕÅF>l®Ÿó`ç[ €ú¼¤ºîß„C‡N"!!Eè›~eÄ(JÚ4Œšý¥MñWtõõûÕZVýfZòÞXKÞ»DK˧J³fMñúu‘Äo­äQY)|uši>€øõ_£K#Œc¯´ºœGâðá“èׯ'>)un¶ª(Ú7ØZ‡ª\?êêuú‘Sid9F‰³|¹'&OƒË—¯¡ à122® 00 sæ¸aÆ ¡X&ÇÞׯ‹Ð¬Ùg2å /UÖEQ®:»­nII)6mŠA`à¹Þß¶m_hjšÂÐp0ÆŸ‡œÙ‡ø2™£ÈDdä ܾ}IIçê%&¦âÎûˆŒ\!S]òæ³uk&L%SÎlµÇ›ˆ¨¨¡e‰‰Âs•Ùv&äY?Ê@}þc]5…‡ï—ëSS{\ºtAAsñüy6bcÃ0th?VcØR}¾©¨¦¸Üîxþ<»Öû+*ò1ææjÍßüé'áo’Z´ø¢ÖM¼rrn ýÝ£‡.^”U õQPðHd9:u¬•sVÖ tîl(´¬ê›Ê*ÙÙ7…†ÒÊ’$.ü„ˆˆ¥033|kwîÜ‘±7{!‘i»T…Év¯¢­­…JT‘–T66½Ñ®]+? o nܸ£´º\\FáÈ‘4”—WàÈ‘4¹æÏ3¡ê¾ÁÖ:TÕúiÈ$Ø:F€¡¡&O‹+¼‘’œœ”ZŸ¯>Ɖ?öV)(x„ŽÛÉœƒq¢#.\ȳg…>Þ )99 ÎÎ#eª‹­|j’wý(õùÆBó0«ÄÇÄ £ð¿ÿ]Æ™3±pssB“&ÚJ‰©o–/÷Äĉ }ÅÅïñ÷ßopìØYØÚº bfÃÛ{²³oâÝ»b\¹’Së†]¶¶ýàëЧOŸ£¸ø=.]ºŠyó‚…bçÀËk%¾ÿþÞ¾-ƽ{0gÎ2¡&ùT±¶¶ÀåË×D¶ËÓs ¼¼B•uïÞã§Ÿ~†·÷*x{OŠóöÁ•+9x÷®ÙÙ7áí½ ‹óäÊG++sDDìÅß¿Áß¿Arr||V‹Œ544@rr**jŸ0m—,¹‘(“í^ÅÒÒ ±±É"ÛÅV>²êÙÓQQkàäÄSøi"☘t@«V-ºmÚèÁĤƒRêQFß`‚É:”´MUµ~ê ýYÒ1­cTÿþß 66?Eyyž=+ÄþýÇaiiZ+VÒ±·ÊåË×jMmQUÖEQ.áq]Rî/Póà*ïðꊊ „‡ïÂr½?9y»à÷–-[ÀÕu4ôôšÃÛ;Dâµ$Qt¨x»v­½C†¸áüùhÛ¶•Bu1‰III·gÎÄ*4œW‘¶öY8;Äž=IXºt23¯CWWff¢o ÃVÛ™PdýÔìëÕÿ–'?êóâëºy3Uj]lÅÔ7UÏà^¼x®]ËEe%ýúõ„¿ÿ¿'Ç#GÚàùó˜<Ùüm°|¹¦M[$ˆÙ²e9¼¼B`a1ÅÅг§96n\‚Áƒ]1£GEyyÃpûö=´jõ%‚ƒ½dÎ§Š““=V®Ü‚… =j½6iÒüñÇ ¸¸xá÷ßÿ€¾~ÌŸ?': ÅÌÆ¤I ñäÉ3tì¨Å‹y=z¨\ùH²ÿF,X° FF6øð¡={š#..ºÔŠ Ä‚«1qâTVV õ]¦íR&Û½ÊÖ­Á˜2Åsç.ŸÏ¹OV=¾Ñظ½Òs¯2fŒ=òóÂÑq~ø!ÚÚZ¬×áâ2 Ë–mĪU Y/»J]ö IëÉ6Utý°ýÿ¥*È’³¤c[ǨÐP?lݺ¾¾¡(.~¶m[bôè¡8v¬öSH${«$$œPÙ"ª¬‹¢\œ¸ þs[4*VC¿ÄžJp[¹O%HH8Ý»##c¿ääd˜Ûýöm1Z´è‰’’_ÙHQ.7îÁæÍ±X°À>>Ó•Z×áé˜??§OÇ€ËUîO>=êêáããŽÀÀ°ºN…°dÏž$lÛ¶Rê ¤*§Å0ݦ¤ávì ÇÂ…Ó>Qg²Ÿ³U!¤~h pTö˜ÂÔÔóÐÒÒTèf`#F¸cÁwôíÛYY70o^°ÜÏòUÔÛ·ÅpsóAlìzèêê *j ÜÜ|põê1|öYVëZ·. K—nÀwßí¬õ¨¯ºÄã¹ÂË+D©:b¢>®êóäSåç7~~3ë: Â’Ÿ>!5†F 4,L¶)ix${ÓÓãY©ƒÉ¾ÎV]„ºUõ̰÷PþÕµkwH½+{õ+”U¿W?@yx8cÅŠ-¸yóhiiÂܼ6n\‡!ÊIZŠ9s–ÁÉÉNp"Ú·¯F¶Åܹ˱o»Ï‡X=ºöþy _~©Ëj}LM˜0 ®Á´iã”Z´¾¡Œõ£èaêó„ÔF'˜„B!õG±?Ê¿0pùr¢ÔiÇñãG°•’Ââã7ÔZ¶~}€Rꪯ¦µ´4Ñ´i¥O#Öþú¸~¨ÏB!„Bê³:{\!ùtðù|ìÜyúú­ajJóN !„B!¤!¨ bħf,!©©™ C‡vHJЬëT!„B!„ÈHÄmDUtBòɨÃ÷ ©Oèo„B!¤>£©„ÒÐãá!„Bˆ²¨§j”  „ÖÑhB!„RŸÕ1@!*dié€ vã?þTz Ž1ââŽÂÄd45Majj}û¾ø®®ÞÐÕµ‚ž›6Ž^õ#îý/fcР hÚ´ôô¸pqñBaáËZe0)OZ»\\¼Ð¼yO¬X±Ç»£yóžˆM–¹,U‘e[B!„ùÉ<•@•ÃY™Ô%.¦¼¼kÖlƒ‰Éhkw……ÅH?žÎvŠŒ]¾| '.€žŸn.× ±±Éàó…¯Äœ¼+Wn—×T=ºëÖEÉTFõ‹¢~˜Æ0%˶ „B!òQª à@äC \]½±m[<ÊÊÊee刌ÜWWoÖbR“˜°°hœ8qGîÀË—×±kW(V¬ØŒk×rYÏ™‰ÀÀ088 Á©xñâ:öíÛ€„„X¾Vزe9Ö®Ý!2vܸápu ]]´n­‡mÛVÊT׎«0hP/4mÚíÚµBxx 22®ÈTS66½1p 5ÀÖ¶/úôéG~—©Œê'Dý0aJ–mA!„BdSu-€Ä·5·…Ú;5ôKl°É[„õëýamÝPZZ†˜˜#HNNÃÙ³—ao?ãÆ ‡»ûxhh¨³š“º˜Ätî<GŽlƒ……© ììì›Ø±ãbbÖ³š³¼~ÿý9,-GâÅ‹ëo :w6„¯ï AÌúõÑxðàرcã¶êb¢!ö vãçŸï`ÿþJχ-lµ]O‹›7SѶm+AÙOŸ>G£PXx•ÕœÅiÓ¦?àÙ³L±1¦`Þ¼`üý÷±'’lÅÔÄáãï¿o@G§™`Ùë×E06¶ì?ÕcŸ>ýmÚ´”Z¦¨ú9c”–Þ…ºzc©ñŠ>Ù úûÅý^ßȲ-!„Bþ+ևžäÏŸâ8ŽuA·î=G“¢B»çóÎ1ŸJÀáp$þÍÄW_9âÌá! ™™×an>L溤ÅbÄ`\¼˜-S [u1ÅFߘ5k fÌZæá€Y³–È\—´˜ää4Ì™ã&sŽ¢4´ý‚Ãá@MMx·WSS“+o¶Ý¿ÿ«Woƒ¹ù0ðxKàäd‡ôôx¥ÄÈ£²Rô X¤]¦æEúNÕS D·-!„Bˆ|g>ÿãO S¦ø¢´´©©{©©{PRRŠ)S|eªŒÇ›ˆ¨¨¡e‰‰©pvv©.&1mpÿþ#¡ºòòòñäÉ2å¬ eeå¸uëWLê77'ÁòÇŸÂÐPпÿ78ÐFFxüø©L1lÕÅ[}#2rnß¾‡¤¤S>ö‹;wî#2r…Lu1‰¹sç> _ÂÂb$´µ»ÂÔÔ{QYYY'mWå~Á㹂Ç[Šüü‡())E~þCðxKY»P"ðð]àr`jjK—®"(h.ž?ÏFll†íÇj S5/ fgßD×®&ì4XN7ByyEæ¨~*A}Ü„B!ŸŠª/S «¡ï¡Ï6wü…¦¿Qþa§oߣ}ûÈËKC›6-Áçóa`ÐgÏYízLê¶ ))騱cŒÛãöí{ðöAvö-”—ß“+6†ÜVÿ¶Ìʪ+.]:Œ¦M›5ꄲ²»PSSCŸ>ãШ‘.]: uõ.¨¨ÈgÃV]ò´M‘õóûïÏag7QQ«Áã-EFF¼ÐwYëÓ¨Q'X[[`Ó¦¥°°0EAÁcðxKàìì€ Üåʽ¡ì¥¥e6l*.\È,2¤ÒÒbYŸþ NÍ©––˜CPP¸à5mm-|øPøé§ddf&áýûhÒDK¦¶ê’§mŠh×®¢£×ÀÖv¢£×ˆ½(À´.q1ZZšØº5}úX¡ImtïÞ;w®ÆÎåνáìk ­­…;wÎàýû;ÈË;uuuøú†Ê•;CÄoÞL…ŸßL‰'ólÅ00“&-„®®&MZ__™ODÙ>v„‡"00 ¦*} F]cc[B!„Éþ¹0 ºùš<ÞDìÞ}•••HJ:%4\šM5‚¿ÿ,ܽ›Ž÷ïïàÖ­ShÝZff²} –4DV^ê°²êŠ"°ÿqÁòöíÛâÁƒ'B±H!„B©2O%`ç /¯4oþºt1RJcÇÎF^^>ÊÊÊñàÁÿà鹿þZ€¹s')¥>iìì&ãøñt¼zõ>” ''S§úaò䱂OÏ)X·. WPRRŠôôLlذžžSeŠa«.Uzû¶nn>ˆŽ^]]DE­››Þ¾-f½®yó&cöì¥Èξ‰÷ï? 7÷.fÏ^ŠéÓ¿a½.Y¨b¿øúëaððÀ/¿ÜGII)îÞý 3fbܸáJ©B!„Rÿ}¼0 âo 'L…—/_)õÛûI“Æ`ܸ¹hÚÔ¶¶“ ¡¡ŽóçBKKSî2rì…={ah8_~ÉÅ´i‹àèh‡Í›— bºwï‚={¾…—×J|þ¹,X…ØØ0¡;p3‰a«.Uš3gœœìЧ€ßêm‹¹s—Ky§ì¬­-°l™'<< «k…1cx9r|}g°^—,T±_lÞ¼ ––¦pp˜KŒ1––fˆˆXª´:šú>´þ¿„¶!„Bˆj||*A7[4z§†¾ Mp`óËb±O%`CEE àܹý05ýïÜD‹Iþ+ûEͧB!„B˜cõ©Ú|œË«ùT¾à¥áóùعó ôõ[Ò'?„È‚ö B!„BH]i @øZ€’P ¦f‚Ú!))R¹Ò€Ð~A!„BQ)>çÿU^7Í%¤–ÿò~Ááˆ!ñ_^/„B!„¨ŠÊ/ BHuÕOþ9cº@!„BˆŠÕÉã !„B!„R?üsa@µ+$„yp8Æ(,| WWoèêZAO‹M›b¯‰{Ou'Nd૯¡¥e†bç΃JÏ›B!„úˆÃùx“ÚO%qóÁ’’Ro‚‰Éhkw…‰ÉoBII©PÜÉ“çЭÛphi™¡{÷8}ú“TÝÝÙ™Ô%.¦¼¼kÖl¬ ‹‘8~<]éù°E‘¶s8Æ"êÊåË×0qâèéqñùçàr› >ÿߎžž GÇYÐÕµB³fÝÁå:aß¾ï„ÊaºM_¿.‚¯o( CSÓææÃpìØY¡˜ôôLX[Qé:l(ýGÓ§/†££~ûírsO#?ÿ!ã÷¦¥]Ä”)~X¼˜‡Â«HNÞŽˆˆ½8{ö2kùB!„ÒÐÔ˜J úÊ€¯o(²³oâäÉÝxõêg¤¦îÁõë·áç·V“›{Ø´iþþû6n\‚iÓáÎû2%äêêmÛâQVV(++Gdä>¸ºzËÜ86êb'ÎáèÑxùò:ví ÅŠ›qíZ.ëù°…­¶çˆ×ü©+app‚7RñâÅuìÛ· '°|y„ ÆÞ~ Þ¼y‹””h^E|üÄLJU«þ}"“múáC ll&¢¤¤ûQT”‹„„ÍØ»7I(§Õ«·!,,PbÞl¬Ã†Ò5nÜp¸ºŽ†®®Z·Ööm+¿wõêH„„øÀÙÙŸþ¸ÜîØ¸q 6nÜ£p^„B!„4Tj€ô'>|{ö| SSchii¢K#DG¯ÁáÃ'1‘‘ûàï? vvý¡¥¥ {ûðõ­[ãdJ(..7†ƒƒÀÁÁêêꈋ —­e,ÕÅ$&&梣×ÀÂÂMšh£wZmÛâYχ-lµ½¾¹té0ÜܜЮ]+hh¨£kWìÝ»;vÄøùÍÄùó0p 5´µµ`fö1¦úI+“mºm[<ÌÍ;!2rŒŒ  ¡¡ S¤¤D åtáÂAØØôVzÛJÿQÔðáƒä~oNN¾þz˜Ð²~ýz"7÷®¢iB!„ÒàT] `tóA‡55áP555p8ÿÞ›àÒ¥k>|°P̈ƒqñb¶ÌÉU/WÔßLÌšµ3fKëá€Y³–È\—´˜'Oþ@çΆB˺uëŒüYæ¼ÙhûW_9âÌ™‹BË23¯ÃÜ\ø„ˆ¶7UßZ@XX@­vhkk¡¼¼Bð7“mšœœ†9sÜ””±|Ú¾#6mZ2Ž­¾Ý«èë÷š²Ñ¼yO<{ö§ÂyB!„ÒP1º0À㹂Ç[Šüü‡())E~þCðxK…NŠ?~ CC}@ÿþß`à@àñã§2%4eŠ/JKK‘šúqhojê”””bÊ_™Ê‰Œ\Û·ï!)é 11wîÜGdä ™êbc`Ð÷ï?ª?//Ožü!SÎlµÇ›ˆ¨¨¡e‰‰©pvv©.¦ù´mÛšš¦04Œñãç!''O¦|•¥¬¬·nýŠ©Sýàææ$1vëÖ8L˜0Jð7“mzçÎ}¾„…ÅHhkw…©©=""ö¢²²Ræ\ÙX‡ eßQ–-¾@aáK¡e99·…þær»ãùóìZÓ6**ò•–!„B!õ'$.ˆokn‡FÅ@ßÚ›»X¿ÞÖÖ]¥¥e6l*.\ȼqÈ>HK‹…†ÆÇ¡ÁuBYÙ]¨©©¡OŸqhÔH —.†ºz¹?t+úLóß;»ÉˆŠZ o)22âѶm+¹ë¶ ))騱cŒÛãöí{ðöAvö-”—ß“+wEÚþöm1Ú·€¼¼4´iÓ|>ýqöì>˜™™ÈU—¸˜qãæbÑ¢™°²2Çë×EÈȸÿo¹NNvråφê7»³²êŠK—£iÓ&"cO‡Ïj\½z -Z|€Ù6mÔ¨¬­-°iÓRXX˜¢ à1x¼%pvvÀ‚î"sRÕ:¬ÏûN›6ýÏžeÊ\–¤×=¡©©uëüñÅŸãúõÛðñYë×o Þ“žž‰o¿Ý‰ÐP?tëÖ¥¥e¸p! [¶Äâܹ"Ë%„B!¤>Yº³2ò2j>•€ÿñ§†… ×@[[ wîœÁû÷w—wêêêðõ ÄhkkáÇÀO?%#33 ïß@“&Z2'üo:ŠÝÄ®]»VˆŽ^[ÛIˆŽ^#öĆi]âb.œŽÑ£‡bܸ¹hÞ¼'<<°p¡š5k*wý³ÏšÀÙy$öìùx¼ÌÌëÐÕÕyQ€i]âb’“·£O+hjj eËpu˜˜õ “+w¶îÌÏç ¤äWääœ@³fŸ!(Hô<û””tðxKðÝw;fÛTKK[·£O+4i¢îÝ»`çÎÕ2?þŽíu4œ}‡M[¶,GII),,FâË/¹ ÃÆÂÓììú#(h./^‡V­z¡]»~ض-þþ<¥çG!„BH]ÉκŒÜ›â§º7fRHBÂ äæžœtíj‚˜˜u°°‰­[ƒí۷ŃO`nÞI𾞠}û¶Šä¯°«Wo¡]»V¸v-Z+¥ŽFÁßüýg –]¾| ffu÷Ø>o"ÆŽ  9HJ:%4@Ùúô±ª5 Ÿ)6O 54ÔaeÕDÀÒÒ›7/zýðáTÌŸŒÓ§c`ii&ô“mª¯ßZ¨¿@§Než>#Š"ë-ªØwj’¶ý%½Þºµ·J}­m_ØÚö•/AB!„Bê‘¿_½”H¼(î1 í¹"ÝHlÀn­Þ:uƒõ’ž¥’\¿~±±É¸qã$bbލtîûöíû1~ü•ÕW“•UW´lÙ§N]@rrœGª¬î[·~E‡íTVŸ4•••(++Z¶k×!Ìœˆ'vËíΨœšÛ´o_+äå O“Éσ6 ç\×ë°.÷B!„Bˆjðÿ¹Àh*Á×_ƒ‡G~ùå>JJJq÷îo˜1#ãÆ ÄxzNÁºuQÈȸ‚’’R¤§gbÆÝðôœªÜ–ˆñöm1ÜÜ|½ºº:ˆŠZ77¼}[Ìz]cÇÎF^^>ÊÊÊñàÁÿà鹿þZ€¹s'±^—,xo?UæÆÖ¶¨ÏëSIû[}žÉ1žíý‹ecü¸BB!u§!~8ûT•••#"b/Ö®]$1ŽÏ/Ÿ_ ô|ØêLÛ%ÉÚµ‹°qã^”••³’“8®®Þض-^POYY9"#÷ÁÕÕ[¦˜ºð)o/oïDE­Fyù=•ô}"žª¶E}û¿IÚ~ÁVŸgr|WÕñ¶ÐˆBQ2ú€¬8¶Ö!å|ÿý%´—Û…Œê6ÚÅåv‡¾~kœ={™ÅÌj‹‹ GãÆáààppð€ºº:ââÂeŠiÈêãözðà ììúCM>^Š¢Êÿ ØÚ íÿ/iû…ªŽQª®‹6Ô8ZðA£!ªdié€ vã?þTz Ž1ââŽÂÄd45Majj}û¾ø®®ÞÐÕµ‚ž›6Ž.i¨!‡cŒ‹³1hÐ4mÚ zz\¸¸x¡°ðe­2˜”÷)bÒæ÷ÀÈÈ]`dd#´ ˜–Ãd[TIII‡‹‹ƒ¼Mb¤°ð%æÎ]##4ibK 6 §Oÿ ”3Ó¾!­¯²µ+&æ š r›0aRRÒ¥–¡øôŽÄ¿™ÆÈV§èœëÛö27†¬¬B˲²n [·áµb™n/IªÚRQQ!º^³mLöÓª²¤µ]’úª$²¬CiØ<þ0­KÒ¶`+g&ýùĉ |õ•#´´ÌСÃ@ìÜy°V9..^hÞ¼'V¬ØŒáÃÝѼyOÄÆ& b˜ì_U˜ÇØèóL©².B¥” ªüЪÈÜÂôôL8:΂®®š5ë.×Iì €ª¤§gÂÚzŒÔqÍ&1ZZf‚˜’’Ro‚‰Éhkw…‰ÉoBII©Luɪ¡ô @ú¶¸|ù&N\==.>ÿÜ\®bc“ÁçË¿}j'|ÒÖ!¸»Gbâ)èë÷Çðáî8x0ÅÅï•ÃThèvÄŅ㯿r»¡¡Û‘–vQdìôé‹áèh‡ß~»€ÜÜÓÈÏ(xÉPCŸÕX½z! ³qãF*44Ôáí"²Œªßù§ú{•ýMuIkïþýÇ}DàÕ«Ÿ±ÿFlß¾‡”©@ú¶¨rõê- h-W{˜?~:vÔÇ•+Ixóæîß?ÏUh¾ª¬}CR_˜µ‹Ïç# `=Οÿ gÏîCëÖzµb à";û¦ ­W—øþ3eŠ/JKK‘šºšº%%¥˜2ÅW¦&u1Qß¶—‹Ë($&žZvøp*œkŸ0±±½¤µé~ZEZÛ™å$½¯J"Ë:”ž {ÇYêRäÿ iïcROZÚEL™â‡Å‹y(,¼Šää툈Ø[ëtw÷ñ8|x V®Ü/¯©8ztÖ­‹¼ÎdÿªÂä8ÆÖ1Š UÖEˆ<8à€Ïÿxќķ5·E£b5ôWØä/Ãúõþ°¶î¸PWWo ÀŬY®ÐÐè‚ÒÒ»ˆŠ:ˆÌÌëHHØÌj˜ÔÅ$†Ã1ÆàÁ½±j•¸Üîxøð ¼¼B0hP/,[6ŸÕœ™²±™ˆ+¼1dÈD‘dÇX®üÒ¥ñòå+ìØ± 0þ Ú·€ôôxtéb$Ët{1ÁÆ~Êô¸*)¦}UYÖ¡,¹)züQ´.¶Ë‘ôú€ÎpqOÏo˜šz‘‘ûpútŒàýïßßhkwüÞ¼yOçmÿbr|VEŸWF]„T·>t/|{ö| SSchii¢K#DG¯Ááâ¯Þ+¢!ö @ú¶¸té0ÜܜЮ]+hh¨£k×ýgÇŽ¬çÜPÉÒŸÛcÉ’y¸}; ;w®Æ±cg1tè$¥ÄHÓ§•Ðß½{÷@^Þ=‘±Ã‡¹œ)++s¡¿[µúþù—Beþ—äç?ú0 }úôÀ½{d.‹é¶(*zf2—/ _ßèÙs4 šoïlÞ[kX³¬¤õUií²³›ŒÛ·ïIޝ£Ó EEoE¾Vsô£Ñ˜œü(r‚Ä$çú¶½LM¡««ƒüpåJš7ÿBä ­¤íÅY÷SE«Lûª$²¬C6|Šÿäääá믇 -ëׯ'rsï -ÓÒÒ„––¦Ðïïß¼.ËþÅäø¬Š>_u¢(á  Î$`c.ßW_9âÌá!»™™×an.|`acnaXX@­eÚÚZ(/¯9ïúlÇŽ6l Ë8N­Ò¨©©)<ÿR6úƬYK0cF Ð2ÌšµDæºØžwZÕÿ ôõû ]LkÞ¼'ž=“í~²ì_LŽÏªìóõqÿ"DÖF È2—Oo"¢¢„‡ë&& Ïéb{nau[·Æa„Q2å¬jmÛö…¦¦) cüøyÈÉÉRŠM›b8Gh9ç o)ò󢤤ùùÁã-Åœ9nr×%[}#2rnß¾‡¤¤sþSqçÎ}DF®©.¶ò©®¬¬·nýŠ©Sýàææ$Ó{U¹ïÔGáá»Àå:ÁÔÔ—.]EPÐ\<žØØ0 ÚÕ¦ª¾!ª’}“ÑFejܸÑ'wÑ’ :u¬53+ë:w6TZ††ú((x¤´òÿ­Ç“'ÅŠÞHI‰FNNJ­}`¯oHk—Mo´k× ÇGƒÇ[‚7+(x„ŽÛ)œOCSß¶—‹Ë(9’†òò 9’&öÿUl/Uï§Lûª4L×ᙤþÌåvÇóçÙBÓøüTTäË\Óý‹ÉñY•Ǩÿêñ4L¬]8th æÏŸ"¸â©®ÞžžSpèЙʙ8Ñ.dáÙ³Bo“œœgç‘2Õ%O>ǧ#>þBB|dÊY•¾þzŽÝŽ7on!+ë(Æ'§Y8~\ôOcbŽ W/ ˜›wZ¾l™'Þ¼)BçÎC¡¥e†Î‡¢¨è-‚‚æÊ]—8lõ u$'oÇòå›pñb6‚ƒ7#9y44Ôeª‹­|ªp8ÆÐÐèKKüõ×ß éýªÜwê£øøc˜0aþ÷¿Ë8s&nnNhÒD[)1Ly{‡àÊ•¼{WŒìì›ðö^…Å‹yr·‘ ††HNþöÎ<,ª#ûûß0CŒŠ"Œà&8∢Ä`PÄ%ˆŠšÁ %ˆ»pËPÄÝQ¸bô .#šÄ5n05&Æ8I&ù%F¢²Þ÷èî»÷½ÝÕ·»¡>σÒuÏ­sêÖ©ÛTÕ©ªc(/×fp@ËÓ,Ñ7S¦,ÆùóWñçŸOñå—_aêÔ1uê{ddѹsGœ={Éjù@·nïbëÖÃï¿ÿ>CïÞQ"9I£¦})yiùŽª‰ïCŠãb•ƒf- ¬[·"""33@e(´‡G}øúŠÏÖ‘Z[xèPbcç`ÿþ ²–ÈAr÷~)rrÖ#((®®µÑ¨QDFBVV ’’R²åååX¹r“ ZfÌH†»» ãÙ³B‡‹‹ ',K.¥X.êåÕÉèÝ{$22’Ñ´ic‹t‘_e˜{(.¾…+W£^½ºHJ2o-ÛŽ)´ðg¸v-3gŽ— %%£”Äĉ9r<<0rä ÄÇÇ`Р>ªò ½–zåÊÙ˜=;µk·³z‡ý·ß¨Ü¯ÁÞ9òmŒû.† ›‚—^z‘‘Ó0~ü0Œ1Ø Cº.ÂÂúbïÞ\"öK±téL9rƒP¯^G ¨èO8.%åjÊõöÛ}ñ÷¿ÆàÁ8k`ÏžÃ<8Ädö¼|@ )›íµ¾† { K–¤ÉÎt+­/KPÒN­…œ¯*y×)y†rXc_ k£Æf9 醤¤ÉøàƒhÜø¯ðòúÖ­Û„uíjÚ—’v¡…ÏÛB…b)ºÅÛ’˜>í{ÃéO'tÝ^u*Á]õ§䫯 1dÈD|óÍiLŸ¾¯¼ò²UO Ø»7ÿû|úi;XMÔì&[Tô üÅÅ·8é{öÆæÍ{qâÄNÁ= ¼7Žr:Öý„Žâ—_.«Ö¥%«Wg⣶bÚ´hLŸ>ÖêúÔÔÅÇ?¢S§Püú«ô3´&Z·¥°Ÿ¡Ô©öBMßýÒÒ¶cÖ¬åøâ‹Oðúë~¶6ÅÅ%ðð0ìPmkJKËðê«=pð`ºäw†#ú‘’r™âÂ…kxûí‰øî»üj»fÚ^ õe9öö®£XŽ©vAÚçåÞõ5½}Q¬ ÉS ÊëTàdÿT†©ü±1~hÔ¨Ž=mõPèM›þ‰ñãgãðáMv3( –ë×o¡E áú¥åË7r–ð«jS›ÞIéÒŠË—obëÖ\½zYYŸ˜µç5©¨¨@ii©ÍôkÙv(Õ—ÌÌl¬[·ÈnþPÎÎ>ŠöíÛØÚ ..µ0}z4fÏ–ž²÷YA>JË%GRÒJ̘1–þ¬´¾,ÇÞÞuË1Õ.Hù¼’÷{Mo_ÇÃn=566S¦,¶êÑ0+V¤cîÜUØ¿£àx2{eÀ€hL›®]ÿN‡óç¯âý÷ÎéÍÍ=77WÉM×Þy§bb±fÍ´lÙß~ûÓ§/AxxÕº´¢¨è)¢¢¦cëÖxxÔGzz2¢¢¦ãâŨ[·Žæö„„ŒB\ÜôèѹjYÆ]ÄÇ'cÔ¨!šÛÂF‹¶C©Þ|õÕa[›†?º¼½›`çÎÕ6¶†ËÌ™ã1sæxÉëŽ- ÇT¹LAâŠrh}Y†½¼ë(d‘k¤|^É;¾¦·/ŠãQ °‹ Ç¿…3’ñÞ{áVÓ‘˜˜4Høòøßÿ.á•W<¬¦[ öè£þwöË'&& þ×®ýnn®ð÷oÕ«ç 4´'ŸeË6ˆî- ç£æaÑ¢ 4t=ú M›6ưa¡˜??Nµ.­˜4iÂÂB ƒ8]»`Рޘ¶o7]¿¦êbÁ‚)HMÝ„1cf¢¬¬-[z#:z(ââÆ·E Z´¥ˆ=COOO[™£GíÐUGh]P( …B¡X™ª±nÄ€¸¹¹â…êX5Úÿè4eÓС0tè“ùœ=»Oöz:îX±â¬Xñź´bÇŽU‚´”u'¨ÁT]tïÞÝ»w¶š~sÑ¢í(Eìê÷ P( …B¡P(öïTû`7îF³fžh×ÎqÖgR(¶†¶ …B¡P( …¢‘=l?8àäÔ -Zx!;;ÍÖ¦P(m; …B¡P( E-N¦E´‡aîáÛoÏ s玶6…Bq(½í¤¦nBß¾£mm1òòΡsç·-Þ™¾oßÑX¹r“"Y%º¤dØgU³ÜÜ|UÙ«–êVï¤ÐªÞe¾JÊŸÕPÝ|£º¼( …Rý°Ë …Ró(--Ú5[°lÙ,[›BŒ%KÖ!5u¶Åù,[6 «WoAii™èõÈÈ©X·n‡áziiÒÒ¶#2rª*†¹'ø™3ç}DGµ¸ RTÇz'…Võ(óURþ¬”êèŽöNÄß  …B±.œ?‹œìÝŠ~LA(Š]ðÿþ_>¼½› 0°ƒ­M!ÆéÓ»ñæ›],Î'0°š5óÄgŸ½¾mÛJÔªU ¡¡1€Ðи¸¸`Û¶•ªdøüpFµ.;¼ùæ,\8½zõ“7n#$dvíZƒàà@äç_ÄÈ‘3pêÔnøùµ"Z.%èt¯¡gÏ.øðÃé ì€o¿}ˆ)S£G¿bÞ¼¿äL•‹Í°aSàíÝ«VmæÈ’šrßHNNü÷¿ç8yzxàîÝShÐà%³íúᇟ2 ééK;'Nì@Ó¦Í/(!HÔñ/¿ü†6múàÿþïŠÅº”ÈlܸÇŽý¤«¶U –Ö{QÑS4oŒ‚‚chÒ¤†·w7|öÙvøúš÷î°´¾Hú¡ÖõNJ†ÕÑ7H棅o„‡OƬYãàÇŸàĉϑ°ii‹b‘ý …B1Ÿ”¥[´pþóSŠî),¸~>þxñr)aæÌñ8ujºwï ww7øúVÖWZÚvŽœÒõ¢‡åáüù«X´hªIYsqßâÉ“?Q¿~=‹ìòòjŒŒŒdôî=É ØÛ.Üõë×Ó'E&å”t6LÉ”——cåÊMV,¯÷ºuë "b 23³T†Š{xÔWÝñã×µ%uOÒµ¬w{£:úI´ðœœõ €«km4jÔ‘‘ƒ••‚¤¤TÕöR( Å>ѯ"S´ù N§ƒ“WÔÉÉIõZ´‡D›6>œ´öíÛà‹/Ôoš@b]Ü„ s0nwwà˜˜DL˜0Gµ.sí‘ÚQXeãÁ8~ü 'íܹËð÷ï§Z {òó/¡ÿžœ´zâÌ™ ªó"Ajj¢ îîn(++W×ãÇO0iÒ|¬_¿/¼P‡”‰¢8r»¨Wï<~üD­¹.^¼/¯Æ¸té†EùØÛ.Ü?A½zu5ѵoßQ´há….]^·º.õ;›7ïEEE²³š*ίkKëž”jYïöFuõ RØÊ7‚‚p÷îwšë¥P(ŠuQ40‰ØØ¹¸sç[—àÎo;“&EqäL­Cóön"ø2)(¸ƒ‡Te4©5“JÖ‚Zc gii®_¿…1cf"**L•ͤʮdí¥–ëW©VkaïÝû¯¾ê¥‰®åË7")i²&ºHÔ{@€5j€£GO#'ç""²Î} .^< ºÞUª\§N}‰ððÉ(,<Oφ¢²ÖXÃiÏí¢I“n„{ ÄÆÎAÛ¶-1cFŒY6=­ÚÔ3AAøâ‹¯0vì¸xñêÖµn¤†)H¬'^µj3îÜù7.!d•8¹¹§°xñÇ8þ_&eõï3KÊfi½ëÉÌ܇ääõ¨[·®_?jQ^–¾[Iú¡Võ®‡ä» ¾aÍ|´ð¢1mZ4ºvý t:Ο¿Š÷ß_€>ˆÅرïZM/…B¡PäÛc øy1îß¿‹ŠŠ €³³‚þÖ {âþ7_ãê•‹„{ ”שÀÉ‚“ÊN%˜1#îîn(,<ŽgÏ QPp...ˆ_jQ²mÆŒ±4¨ÂÃ'ãå—ÿ‚˜˜D̘ƒzõ^0û¡XúŪf-(‰5œ sÅÅ·påÊaÔ«WIIæ¯ÿ¶¤ìj×^Z{ýª»»ž?/|ùeÎËÆ³gÏQ§Ž›Yù‘\~èPbcç`ÿþ ª7Á?~6–.iÃk8­]@XX_ìÝ›«ÊN6“&ÍCXX‚‚]»`Рޘ}¡U_üô߇()~nòþZJ”ìÙs7n5tüüZ!+k:vh8•@ þ:4ggg$$L@BÂCÚÙ³—àëkÛ |ØkA-9I)µk» À»v­A§N¡øè#Ût\bcG`ȉHJšdöÚKR4oÞ÷ï?„¿kCÚýûѼyS³ò#µösïÞ\üýï ðé§YèÔÉWõý÷î=À¤Ió0iÒII+1cÆX¸¸(ËÕ„ÌÌl¬[·¯¿îgQ>$êalܸÍšy¢];ÛŸ A {¬w%Pß°>Žê …BÑðgÑcUƒ€>bÀпg Ó GÞy§bb±fÍ´lÙß~ûÓ§/AxxƒŒÔ:´Äĉ™!C&bÉ’x´iデÿ‹Õ«·àÖ­{زe…Ye¶”¢¢§ˆŠšŽ­[SàáQééÉˆŠšn•5É!!£7=zt®Z–qññÉ5jQ=j‰Ä”)‹ñòË/¡mÛ–6³#.n4BBF¡S'_"?ÿ"V­ÚŒS§vÛÄž+Ò1wî*ìß¿Ñl-”´-Ѳ]ð™9sp~ ü-«2±çý9§Pª/åååðöÆÉ“;«U˜%Å~‘:•€B¡P( …B¡˜F*Á™SÇqïîmU÷*;•€R£¨®k/) …B¡P( ¥:cΠ€¼]k¤7¤T?ªëÚK …B¡P( …B©®t †‡×á_5óO‚Z Ö„”]{I¡P( …B¡P(ŽE3ïæøý·_‰ä¥c*ÇèR …B¡P( …B¡Pª9îuêâ‹ÏóE¯Ñp) …B¡P( …B©Æ¸×©‹“Ÿå‚aÄ·àF 0Lå…B¡hD§N¡Xµj3~üñV—¡P( …B¡PjìAÿöDeœu[²Ïmç§‹ý¸¹ùª6œRö°)++Grò:´jÕ îî~èØq ÌãÈäåÃàÁàá€zõ: 00 Û·ïè;rä$Ú·ï77_tè0Ÿ~úo³òQ[F­P¢KKßp”²ÀãÇO¿>>=áêÚþþýpàÀg$MTŒ’º åóJÚ DGž}GѬY7ôïÝ»áéÓgV‘¡P( …B¡PjüA¯4•S´Ç@däT¬[·¥¥e€ÒÒ2¤¥mGdäTƒ ÃÜüÌ™ó>¢£‡(ŽyˆÙÄ&55‡ŸÄ¿þµ¿þz›6-ÅÂ…áÒ¥™¾}Gã?ŠpèP~þù"vìX…;öãÃ;ù߸q11‰X»v~ÿý*V¯žƒ÷Þ›…»ªòQ‚’º …]Zú†#–ýùób¼ùæ—àĉxòäöìù[¶d·Y Jê‚”ÏKéâ3mZ4ΟÿnßÎC÷îXºt=<=» ::'O~AT†B¡P( …B©)ð<›4ÃK/7•Õ-Þ–Äôöï ç§:ü-³Ð=¿MFJJ:wn ())EVÖ'ÈÉ9†Ï>;‹¾}ƒÞÑÑCQ»¶‹hÆOžü‰–-{âÂ…ýðññ¶Za¥Ðé^3¹ë~›6}ðÉ'ëбc;CÚ… ×°aÃ.de¥fÍZŽ”” ÓOmøþûÿ"00 ?ýt;mÚø >~œA&%%÷ï >TœÌ© sQ¢KKßpIJ¯Zµ_}Uˆ;WµbuAÊç¥tÕªå øïÏIÚµ{÷!¼ÿþüþû’혔 …B¡P( …âHÜ»óܤŒØ t:œÌû³öïÛ w' OTE Ö0’ë Ø±Ï|6lØ…~ýzX4(`ípñ‡D›6>œ´öíÛà‹/¾2|NMM”ÕÝÝ eeå†Ïùù—пOŽÌ€=q挱ï$¥¨­ 1&L˜ƒqãfsÒbb1aÂÕº´ô eãÁ8~ü 'íܹËð÷ï§Z—)™œœc˜4)JµrlbuAÊç¥tIq÷îwX²düýû!6vÂÂB—·Ã*2 …¶­s IDATB¡P(JuErPà³\0âýOÁR±nÖèÑñ())Ann& 77ÅÅ%=:^4Óââ¬]›…Ù³'™_4mÚ®®íàãÓC‡¾+W 8×½½›àîÝï8iwððá²ù~üñ6 þ–áóƒàãÓ Ð­Û»èÞ}Z¶ôƃT壵u!EZÚBܼù5²³öíËEaá]¤¥-T¥KKß UöØØHOßÃIÛ·/¡ªt)‘),¼‹Ÿþ;„»»Úµë‹5k¶ ¢¢B]á­€šº°Ôçåt­\¹ ah×®/òó/")i2~úé¶nMEŸ>#*C¡P( …B¡Tgdd6¬\Jà×ÎÏtè–YÙYéñw)ç!ú7îÆ±cÿÆéJ‰.)ÂÃ'cÖ¬ñðÇãÇOpâÄçHHXŽ´´E ¤¦n¡CyذáC¼öZsܼù5¦N]Œ ®£¬ìkÑ|ÌÃôéKpñâ4hðÀÙ¹5JKoÃÉÉ AAápvvB~þ^¸¸´EyùÅù¨Å’ç?üðBBF!=} bcçâĉhÚ´±ÙºÅ7ŠŠž¢yó`C“&À0 ¼½»á³Ï¶Ã×·•Yº¤dœ[£sçŽX»v.:vl‡{÷ 6v""B1mZ´Yö[Zïz”Ö ŸgëjÒ¤ãR‚NB1jÔÛˆŠ C“&⛡’¡P( …B¡P©¥J¼ÒA«Œâe/%¨ ˆÇ 1Õ!)//ÇÊ•›°k×E3“fVÓÊÉYoø½Q£ˆŒ„† _ÆÔ©‹ 3fŒÃ0ŸŒ¡uëW1~ÆOÍóС<ÄÆÎÁñã[9yww7<^Œ:uÜñå—9€?ÿ|Š:uÜTå£K;‡^^‘‘‘Œ^½¢pêÔ.ÉA¥º¬íjí‘¢nÝ:ˆˆˆÌÌlÌû>λ ú¢ƒJuIɸ¹¹âã s玀ÚbãÆ%ˆˆˆS50@ª]èQZ$|Þ”®k×rMÚKJ†B¡P( …B©Ž(ðlÒ /ԫϹ©ÚK€·”€ºÃ …ìÛw-Zx¡K—×ͺŸ‚€Ô‰æÀY:àì쌄„ ¸};Ïžâúõ£ðôl__áî½{s“ˆ#G6£S'î1{Í›7Åýû9i÷ï?DóæMUåc .^¼/¯Æœ“¬…¥¾A’ØØؼy/***}”³Œ€$ÍšyÂß¿5'­uëWM.3áCº](© R>oOõN¡P( …B¡T7” @§Ãá{EóPt\¡–/߈¤¤É¤³%Âõë·Ð¢…—¬Ìúõ;1tèNÚ¦MÿÄøñ³qøð&vÜ(ØÌîèÑÓèÑ㯪òњ˗obëÖ\½zYYŸö` =ùF@€5j€£GO#'ç""ZEO×®((à†Öß¹ó-¼½›XEŸRLÕ)ŸW¢‹B¡P( …B¡˜‡šAå›Z,€ÜÜSpssµ‹¾ ˆÆñãgðÇExòäOäåCtt'd† ™ˆ‚‚;(--Ãýûß#.nnݺ‡É“GdV¬HÇäÉó±{÷ZˆêŠ‹+ÒqâÄç(..A^Þ9¬ZµqqcTå£%EEO5Éðð¨ôôdDEMGQÑS«è³'ßЉ)Sãå—_BÛ¶-­¢ãý÷GaâŸpáž={Ž7ncâĹ;ö]«èS‚©º åóJtQ( …B¡P(óP=( ³ù`-€wÄšƒË–m z%Ëbb"°pá?píÚàææ ÿÖX½zBC{dFŽ|áá“ñÍ7àåå‰wÞé‡S§vÃÍÍÕ “˜˜4h¼@Çÿþw ¯¼âÚ"3s9¦LY„»w¿CëÖ¯bëÖTøùµR•–Lš4aa!†Ž_×®4¨7&OžíÛW×GÚ7H0|ø[˜1#ï½n5;wļyqˆ‰IÄ;ßÂË«1¢£ßE|ü8³ó´tY©º åóJtQ( …B¡P(õ˜;(Pÿ%^¿³j, òTÿÞp~ªC·Í•a=,•<•€B©.”——ÃÛ;'OîD»vÂ}%(Ö*…B¡P( …BQÎï¿{àȽ`˜ ø·ï„W6‹/½b2M?(Ü£€ÊS Êë08YPu*…RÓ`7îF³fžtPÀFè( …B¡P(Šm©`-Ð);µBqhœœZ¡E /dg§ÙÚ …B¡P( …B± Uc4b€R#!qü%Å<è …B¡ÔR–nAÆ̺wðaøæþ$$¤à?^c é {/0¦êôq†á¦£ê\r†-ʰîg8ñãÊòu‰èÑÿ&²OSÁ@ìÐ1|S¸vq/pïØ&±IÃ-“h~‚ç$b/ÃWÊÏKüG¯äý|ERéb×ÄŸ»9ù¨²˜ •÷¨ÑQ•ÆŸ°fÄýIõ&ybÏA¶~$ž›’:•Ó)›G•¼N©¬œ^e¶pN%Ð Z'…B¡P( …B±Gô}~įNâÏùJ9eë ò”J“¯êÀ‰"3•} =Æté0fEÎŒ”éò«œ–¨ÌOE†fvæmí-k«èòƒ¤zž²’Ä €DÌAÅ P50 ã4O …B¡P( …b:— «#ÎéôVí(nèDTuyyTÊ ;ë:Ö=\Yñ±þ“<tÆÛØù± ¼°058 3”Ug°AN^ b:Ù j1”ߊ=xNöª#TvòUÏ|«Eæ9‘ˆP•7¡üu¬¡H'¬3( &£“¬$…B¡P( …B±)•KÖgI9ÞgÎ'¦òºHU,?Ãà€¤ñއšþ¯Nâw~~¢"Ãà€D§H'JÁë4 Žrg„ƒ-Æ‹0Æ^“0cYƒÕТ~íÞÀ€i£u:Ó;¸ËÉäåCçÎoËÊ9ríÛ÷‡››/:t€O?ý·IæÚCKžÏÙ³—0bÄ44lˆ_ìˆÀÀ0lÝš#².J;”Ô—)î5Ñ>¦ê]i>jpßÈÔ…ZåùäåÃàÁàá€zõ: 00 Û·ï'm¢bÔÚóóÏ¿ÂÓ³‹ |Jß 5µÞÓe·†ohù|¬’çCýдŒ©²ÛÛ÷;ý>Õþ½Ac@€ü̺ø,{UÇW0K¯¿&Òé• Å7Þõ¯jÖž_ÊP9(! æG@¨E8È!?¿oIäu¡ä’¹É®ãW7‹-m±Êå⪗5Èf&ž=-#P;0CâÝ­6²ƒXDƒ´¼HÄ€P82r*Ö­ÛÒÒ2@iiÒÒ¶#2rª*X²dRSgKtãÆmÄÄ$bíÚyøý÷«X½zÞ{o ïÊÑ›IAêùÌžŠÐÐ^¸z5¿ürÛ·¯Âž=‡1þâ6+ÅT})•a˜{‚6JëÝT>JpDßÈÕ ›IAêùôí;üQ„C‡2ðóϱcÇ*ìØ±~h›S'ÔÚ·#G¾-HWúN¨©õ˜.;)ßÐòùh‰’çCýÐr?´Çïwú}jý÷)ŒÁ:Á »ñ3à 'ç ð×ôƒ¿T€›'ÿ³äR±èxVXtÉØì?ïE{ð:IüPz~¤÷ƒ0ùù{/¯Æ¨]Û~~­°eË lذ‹¸ÍJ1U_JeLAªÞ•àˆ¾hWŽø|fÎS§v¡{÷Îpwwƒ¯oeÛIKÛNÜf%¨±çС<œ?‹ ÿVúN¨©õ˜.;)ßÐòùh‰’çCýÐr?´ÇïwT×ú²·ï=†õô&:’!ùüϬΪ©û¥¤Ò„×Lwr¹{"°ïãÚ!_~>À‹ »$ô©šÔ&$ß¹¿àhM í )U³¿€Úý)Ìô7ÁÀ€ÒAE7æP cŠüüKèß¿''mÀ€ž8sæ‚ê¼HØóƃqüøNÚ¹s—áïßOµ.síÑ|›ƒ£„¼’¬w%ð æ`Ü8îŒCLL"&L˜£Z {Hâhm'55Qæî²rÕvu˜ßv”ÚóøñLš4ë×/Æ /ÔQœ¿%ï9ªc» éZ¶ uvYßWÅ ~h9ÕáûÝѾ/”`ï‹` ÿHFpe3óœ½QüŒh~Hè;{p@i \£Ï•ç*gG-póé膯×*›u|=R]xÖ³’»®·‹{Á¸üœ7‚ì‡av\ÍF*uÈæEjÓAµ{ÈÈ;¢ÐB{Ôv¸¢Ç:Êé[‡£Á2€\¡„’äæfrs3Q\\‚Ñ£ãUÉ(áÁƒGðñièÖí]tï> -[zãÁƒGªò!eOl줧ïá¤íÛ—‹ˆˆPUºÔÚSZZ†ë×oa̘™ˆŠ Se³=Ò´iW¸º¶ƒOO ú>®\)à\WZï¦òQ)ßHK[ˆ›7¿FvöQ•~QXxii Ué"e)½íèùøãm>ü-U6[1{fÎ\†àà@ ø¦Éû­ýN¨IíÂßв]عçCýÐr?´—ïw{ú>µõ÷…lùÂîÛ³öë Vvä¤÷àæ§dM½lt€DçÔ` Ø=&ô “”u„¸vª\?.‘¬.DŸ—´~ÑÜt:i»Ì€ÜX¦5£´Ø[@EzåEa’'î,BAÛÑ-Þ–Äôñë§ç:tßT ~°)) èܹ­ðÝk&סY"ãìÜ¥¥·áää„  p8;;!?/\\Ú¢¼üŽÉ™kEEOѼy0 Ž¡I“F`ÞÞÝðÙgÛáëÛÊ,]¦dس~ÈÏß«j6Q­=¤ò‘’ ŸŒY³Æ# À?Á‰Ÿ#!a9ÒÒ!,,€²zW’5Ê%Ç?ü„QHO_‚ØØ¹8qbš6ml¶.-e”àhmGÏÁƒy˜>} .^<€ ^2Ë~RÏPÊžS§¾Dxød‡§gCYJß öPï€ý¶ Àö¾¡¶]XÛ>rχúaõù~··ïS[}_Xû½‘²t 6l¤XžÍà!ÃðÍý+HHHÁ×Í*—F°7«dª¢ôÿsÓõi ç³qâ’tyØù0 Ãé1¬Eí•çÙaÈ[/`¼GjNFg,A„'k¸W$cRE•%Œ”€0‰‘Nd$fÎEKaªãɈ”Ÿ@´÷#¨SbÑàçkfþRD£Ôؤ6:B¥^É|*ÄŸxæ2:•Ûòùº‘¨p¯ÀÉ“ê+Tòµä‹ÜÝÝ ÏŸWP|ùeÎËÆ³gÏQ§Ž›ÙyZbOݺu1™™Ù*CÛ<<êKþGâù0Ì=ß•+‡Q¯^]$%©[«Çßa˜ÔŽÃæ’“³AApu­F 2r²²R””jQRïJòQ‹¥¼zy5FFF2z÷‰ŒŒdÉ?:•ê"õÇ=)­í•köccç`ÿþ ª;~Öh;RöŒ?K—Î4 Èaé;A-Õµ]Xâ¤ìQÛ.¤ÐÒWõP?´ÜíåûÝÞ¾Omõ}¡Rï pO¨ eç‡ôóÂ³Ýüö¦€üÐ{±%²{~c‡ÜË,C›‰×³œ¡r?a§Fn_§cÀ>žPvYKA'‹á<+žÉ*&¼Ùü2œ™7>«,SU3(`*[LÆ[sPÀ—Ò|¬‘¡p#KÕÖ¦yó¦¸ÿ!'íþý‡hÞ¼©,ª qÛ¼y/***}T“ÏÚµ]à‡]»Ö`ç΃ªîåï0lÉŽÃÖ"((wï~gøln½óó±/^‡—Wc\ºtævØ#Z·½{s“ˆ#G6£S'_Õ÷“n;röÜ»÷“&ÍýC_ KÞ ¶ÀÞÚ…¥¾AíBK_eCýÐrìõûÝÖß§¶ø[ËöôÞCz €²N \;/•§XŸÍ8  ÓrtïÚÔ‘~2˜XI!´CúWŽpGÛ¬ýHê0'Z@ æt¬‰mÚhÍeR*Í\°Ô¥T?/®¼Se;DÆŽEpp `š£GO£G¿ÚÈ¢Êp¿FàèÑÓÈÉ9†ˆˆšé®¨¨@ii©fú´âúõ[hÑÂËðÙÜzçç£5—/ßÄÖ­9¸zõ²²>1kfuF˶³iÓ?1~ül>¼ ¬¦‡”=RG…™úßÞ öÖ.ìÍ7lù"†9χú¡åØÛ3´õ÷iuhÖ‚;³Ïß\‘ŸÎå}r{0Æÿ2úYg~²1ŒÜÔf„Æt…ƒ ¬û©ýÊM•õªÄöB0æq=j[$CàYJÉftÀe—ˆç%µ¡#1›$ó‘AÕ`!ÝDOŠË[$µƒ?Ä6F”¯CýoÂS d²Ô‚¸¸ÑX±"'N|ŽââäåêU›7ƦvÅÆFbÊ”Åxùå—жmK«è …ƒóðÛoñüy1®\)À˜131jÔ«èÓŠ¢qüøüñGž<ùyyç€Äĉ%õ®$-)*zЍ¨éÈÈH†‡G}¤§'#*j:ŠŠžÚÄ{E‹¶³bE:&OžÝ»×"((À*:la#¾ì­]Ø›oèÑ¢](AÉó¡~h9öö ííûT#µ ­a‡ç‹-¨”áðNŒ`xŸK D"üÙYr:äFYÆ O¬#Ï^ÀÇV/2°!\Ž ¾´Àh;·ÄÂçÅÏN§`m€ÔRuË x÷)Dí×Êwz-vPy?±M …ó«•·æ ‚”NµÈr¡4‹ÅÛ’˜Þ~½áüÜ =2ž: ÛƒÉÍ-E,L–?CväÈI|ðÁ ܽûZ·~©©³1`@OⶨáÏ?Ÿ¢iÓ®ˆ‡ùó㬢#?ÿ"RS7áÌ™ (++GË–ÞˆŽЏ¸1¨UËÙ*:M¡¤¾LÉ|òɧXµ*×®ýnn®ð÷oÄĉ íŹÇT½+ÍG+FŠGÓ¦°bņ´„„åøñÇ_°};ùµ·$êÂhÑväÖ×þï—ðÊ+VÑ+…¹öð7ÂRúN°§z··vao¾¡G‹v¡%χú¡iL•ÝÞ¾ßííûTVíB«÷©Íïè7dý €»i£ÿ,¶± wöÚ¸_;b†=ÅòçêbäeEf« ›ŠæÍÔ‰ØÌ)&/ÉÉà ÛyÉŒäzzyeÑügÄ3Ý Mì×ÊÏÜcíøõ#—•V^9‹ä¢DË.S{Ût k¥æ H=Iy)½*ìa T¸38Yx‚¿”ÀŒQ˜Ã0ظq7š5ó¬_TŠVжC¡¡í‚BBÛ…<†S8iú°{@ÿ7¼qYAú5øœ Ø{ðõ?ëO5Ø$°¬eÂÍ %70ä/9`'z#5b|’û–HìØÏêP)‰„×éí•XZ`¢Þ¬îšôMÒ¶Y»_¨6B³öju¨0«n:¨<ò¢–RÁšŒ“S+´há…ìì4[›B¡8´íP(Bh» P„Ðv!‡±sªŸ”7N3Ðñ" ôrü¿éu:'<Ý'}?x÷ ûZF[ªuÆÙwC¾ìM VÉØ-ÓÙaç#^^〈Ԍ8¿œüçÃý_ú¹ÈÙÆ·GðQ¶óª ª<áGaˆËKE HÝÂ8’‹zÏPm´Ë!É›ƒÆƒ@•“Xsé‚9ƒ#Êó ð±õm ÅQ¡m‡BBÛ…"„¶ ep8y~çÞØçˆèxà ’rLåÎ5ýú¨VZ¬“ÌOcwJuUùº+¯sK£'`À"*D4Dl¨ºQÔ–JÝ:å¼ädêCo§*gyÅò”“—O×oÔ¡ CÉH¤+Ej–œÄà€lX½è™We»Äà)fDLðŽ+¤P( …B¡P(ö 7RÛ•W˜Ÿì© à á.àç)•¯Ô¦vÊ—¿lê^éëb¶›o‡i:£d;nª;ŒaVG ZwÚ æ/©×DýkJ¥Ü=$6¡P( …B¡P(Ú#è`šœhd ³á†< 7ŠœcÏ j¶_nvYo‹”‘b÷HZèäòbDl”Ú„§ZpŒ¡Œ RyT~–ïIí_`RNÁ=raùÒÏÍÌP~QŒÊã ÉéVú.­WíÌ=e†¼xH;ºD2¡eftê„Itd€B¡P( …B±¤f蹩LÕL½ÄFƒ&òÓoÈPàŸ¢¦ÏSǹáÞË'Œ{ šØ”ÏÐñÕ l×KJuŒ+uóï•—ÂxE?€bIƒ¼œŒÄàƒ²ðr©¨nV–u0¹å'µ·€>sE&T$;ás Õ`fÝ;ÚÕÍÙ³—0bÄ44lˆ_ìˆÀÀ0lÝšÃY/£DF-rçÑÚ-íQ¢KN&/ï:w~Ûb­¨ >fIæåÃàÁàá€zõ: 00 Û·ï·º=¤ÐŸ9‰öíûÃÍÍ: À§ŸþÛ,[I ÄW‹‹K°`ÁZ´jÕ îî~hÕª,X‹â⃌N÷šè%8J½×äö^VVŽääußèØq Ì#m¢*LµA%6+ñy€|[v”zgóóÏ¿ÂÓ³KiïJ}ÃQtæE:üÆ‹êó“»]TVÇžÙg F˜ÒÉ}`£°CcI„¼ÜÒ~g]Ùà€éïî² ÊinÝq!9©kà bb{ Xfݺù¨QIâ™Û„HÄ€õ˜=;¡¡½põj.~ùå2¶o_…={cþü5ªd”9ëÖí@ii ´´ iiÛ9•h™ìÑ%º”Ú³dÉ:¤¦Î–Õ§DF+ª«‘ªÓ¾}Gã?ŠpèP~þù"vìX…;öãÃÕííˆeLûê·“ˆµkçá÷߯bõê9xï½Y(,¼K¼\JPâ«ññKqáÂ59²¿ýörs3qùòMÌœ¹Œ“ÃÜü¨Åë½&·÷ÔÔ >|ÿú×üúëelÚ´ ~„K—n·Y)¦Ú ›•ø<©¶ìˆõÎ&.nFŽ|Ûjö‚TÙ•¾N' ªc©Ÿ]ç‰ ÷ €„Då ú$û ëhBÁ%rýkA—xØ¿Ž²ÀQ$¶ÁŸNt2–+'ºöbKdFBˆm†|Îærª[,úAæÙ˜ê0ŠNb‹GXHŸà$ÂçåÊlβ5¨Þ_*€H-uG·x[ÓÛ¯7œŸ9¡GÆSèt:üíûT¤¤$ sç¶ÄòùᇟЩÓ@üòËe‹dø”””"+ëääÃgŸEß¾Áïè表]Û…„éªÐÒ%ºÔÚ£Ó½f²#¡DÆT#U§³f-GJÊœ/¹ï¿ÿ/ÃðÓOªuÙÙHùjlì´iãƒøøq†´”” Ü¿ÿ=6løh¹Ì…ï« âÚµ\4mÚØ óèÑOxýõ·ðóÏk›Ž^ïzjJ{oÓ¦>ùd:vlgÈûÂ…kذa²²RˆÚ¬)ŸTb³Ÿ'Õ–±Þõ:”‡)S£ àêÖí úàˆeWâZ’²t 6ldÖ½ƒ‡ Ã7÷¯ !!ß4©Ü(œ³tžÛ)Ðï$Ï äX"úÏ" ¦‚í{v­×±³`XGÝIë¯îh„97Ž;»“ˆ æØÄž7ÞŒãÇÏpÒλ ÿ~ªu‘°ÇP÷1uššš(HswwCY™ðHSTGÎÏ¿„þý{rÒ è‰3g”šhÛWu:œœ¸Á_NNNVkÏŽæóRت½kéóþˆ6m|8iíÛ·Á_|¥Ún­Pb³Ÿ'Ù–Ñç?~‚I“æcýúÅxá…:ªíU£ËZú¼ÖïC-‘/ôßîü¢s" ä6æ3êκ ŸµVU/­ST[žc rEŠl™-—”ÕßÂP¨SeºjªÍI*1ëˆB5ò¤°•^Óhº”€Mii®_¿…1cf"**Ìl)FŽGII rs3¹¹™(..ÁèÑñªòIK[ˆ›7¿FvIÊË" IDATöQÀ¾}¹(,¼‹´´…6±'6vÒÓ÷pÒöíËEDD¨*]¤ì±gª“Y³N?þx†K•ÍÕÕŸF².ÌÃôéKpñâ4hð’Y¶W'vvnÒÒÛprrBPP8œŸ¿..mQ^~G]á"ç«%%¥è×o NŸ>oéÕ+ÇŽm5„׆‡OƬYãàÇŸàĉϑ°ii‹b¶MŽäóöÒÞµôùÔÔM8t(6|ˆ×^kŽ›7¿ÆÔ©‹qáÂu”•}m–ý¤°Äf%>o¶ì(>êÔ—ŸŒÂÂãðôlHÄvGñy%¾¡%¤–Ü×/%?œ]F®»ç‡å‹FÁWT°r1 óàÞËu7Ú¢ïô²eEôñ 0Uú*„Ž,¿|à?Ö]"û"—aðï«0æ)Ñáö¥å;´â—„÷Ê¡y6ÒIX…ªú¹Eâyu¨ a7µ¬B4/±Îp…D>É5ËÌÚ[@í³YF f@Åä25ø?~ül,]:Ó0(@ÇñyÓ¾¡-|^±-¬£ø*ë0å÷+éˆHt8ô³ñ²¡õ [VÁ„(SÕç`ô÷p¦íMÞ/œ¹descϺ‹„#òЋ3U¶›Ê‹I| A'Ê ïCËöQ¥ëOÕJ3*u¨R"î$6”ËGvð†@tY¨DAêÙ[- ÿM¸Ç€¨î.Ö–ìj­§vmøa×®5عó Ù2Zqñâuxy5¶énÎzbcG`󿽍¨¨@vöQN8ž£B}L[Û»711‰8rd3:uòµº>9ìÉŸ›7oŠû÷rÒî߈æÍ›š•Ÿ¥§°‘òÕ={cóæeðõm77WøùµBVÖ ìÙsH6¿  AȶÖhý^µ—ö®•Ï;;;#!anßÎóg…¸~ý(<=Â××üWRþ,…›•ø<é¶L -|þÞ½˜4ižè€»­ÐÊçÍ}J¡…Ï«ÁÚ/Jo„‘ìœ —T††ëXi•÷é?ýrAžLvKëׇö³&¼ ²¢Ëøyë—1°l⩲Ã.Öob‡Ás–ðC©…·r¯qNKàfu²/KwØeg=?á †²jEû1¨ ¿èÐI^3©[òs;ìjï#50 ¦£_õ¼-ÝžAÕ@‚ºrÚl=(--µXÆš\¾|[·æàêÕ#ÈÊúĬµ¹$ ðC£F pôèiääCDÄ@›ÚcïPã²iÓ?1~ül>¼ ¬¦G)öäÏÁÁ‚M²Ž==þj#‹„ˆùªØw„©Ñüë×o¡E /’¦©Â–ïU[·w[úüúõ;1tèÍô‘@ÌfS>omY+Ÿ—:šÔ–[-}Þœ÷¡c /˜¾skj­»Ô>ò*,áÌžKOÓW$HE*°nSV=RÑ â£få©`6\'×9µ¢ÑØUW›f–¹½²›Ín[D7Ú#”—YËT¢êqˆ.P-£GÓQ8x0¿ýöÏŸãÊ•Œ3£F Q%£%EEO5Éðð¨ôôdDEMGQÑS›Ø£'66S¦,ÆË/¿„¶m[ÚÔ{‚ú˜<+V¤còäùؽ{-‚‚ˆço.öâÏqq£±bE:NœøÅÅ%ÈË;‡U«6#.nŒMìQâ«ï¼Ó11‰øÏ¸·oƒqãf#<¼¿AfÀ€h?~üQ„'OþD^Þ9DG' 1q¢-Š¥©ÏÛ[{×£…Ï2wPZZ†û÷¿G\Ü"ܺu“'´Š>(±Y‰ÏÛ[[¶×¿%´D ŸW⎋¾£/ÑA– –í‹°Ââ¥6)ÔgÂþ¬ãuðÅfûùp?p%Ùáï Ä&áÅì瘦¢³ÅÞѯÄI :Ñõ¬{†³7äå/z†¡2!2’DìS¨ÃRfD@ Ã­z³CµzIÙ£.'¾ô¨–^¯ù#Î LAfæ>øøôÄ+¯â½÷faðà|ôÑ|U2Z2iÒ<„……:Q]»`Рޘ<Ù6öè>ü-üúëoVŸù[÷oŽŒ¨YÏÇSPVVŽAƒÆ ÖNþòËoÄõ)Å^ü¹C‡¶ÈÌ\Ž)SáÅ;bÚ´±uk*üüÄ×ÂZ%¾úÑGóЩS;„†ŽCýú0`ÀXtêä‹5kædbb"°pá?àéÙ-ZtÇ¢EÿÀêÕs0vì»¶(–¦>ooí]>?räÛŸŒ^ðGïÞ#Q»¶ NÚ 77W«é4…©6¨Äf%>oomÙ^ÿ–Ð-|^‰o8"ü°wcGžÛ‘ëØ‹±'nÏÞ½Ÿ%,X/:8 r-Àß1ß(«È£Ä×ô³O½.•ÎYŽ E!*/úœd½.b ¤Í²Ñò?QÝ„gÇÅ#Ìé´«€ÔI$±ƒ#-¡òTÿ>p~ªÃ››Š c€ ‡«%O% ØåååðöÆÉ“;Ñ®m7Ä¡P,…ú3¥¦A}žRÓ¨‰>OêT‚o[ÄîoXªÏ›•æ÷MÎ5Þï²LÕš}}”{cÐ)>GɳS\ ©ÏØÁ“:aÁ˜7W?_Cù¾ÿ>Æä³à^¿(,+§¢÷ñŸ­à¢¤º >V†¢Ö Äö/rˆ/³0¥›sR SF5³Û:‰@Vž”^†¿a†iy5ù‹™(-`¼öyÚTÔapÒp*A:Ã?{†alܸÍšyÖ˜/WJõ…ú3¥¦A}žRÓ >o)òSûH…Å RY*t:nÇU°q¡>]Êd=Œh¿Hn#Eù¼™™²A¸tµ Ÿ‡ªýt¬‘©NïÙMc•I°y`E•-Âq„é²'ZÈÝ«¢Ó̉±æ €Ü=¤:Ûj!¶|Aí ¹(…ZÄr¢h†“S+´há…ìì4[›B¡X õgJMƒú<¥¦A}ÞRŒ!áì>€>”_¬[ ÕéÀ0ŒáI9è*g¥«úuÜkúùj†›'Û]U¼™s]Õ„O©iPŸ'‡xçÕTg´JJä;®ük¢ƒö:ï"ùËÊ‹]ÍÃXñç!^*®j‡5F8H!ÝÃåZÀù$ò<ø·ò]ä;~"³ÿ¬aS¶q²1e›à©¨ G”»Ljo³ïÁD9ë&¥`ÎóV!_VîæƒŒøò …B¡P( …b{t¼^¥`3B–œ`Ó?Ãæƒìõôyè{ÕÆuCÆÄwåÙÄO§?@d\á†çœ0|V”„°l¬ÙzNd8+ ïßļgb|nBûاðÑ¡*ŠÃ ÔÏ_žÁÑ#Ú«ß Qo³x¼¾XFœtE'9Èu˜tR›7’ZB@2Z@íÞ¢kùM xÒÝŒçM8âÁ‰iµ8æ•B¡P( …B©&ð;ñrýÙsåMÌJ N à~àé×Ë]_î.6`!‹„€ð„–’­Â޼ÀF•HÚ/’—l}˜ÄœÎ Ì="f™gjP€3ø!{žAÝö {eÔä/-¯®q½J¡P( …B¡Pìaçš÷Yöš0 _LNrò™ÄÌ´Ü}ŒLŸE¢“.‘ÿ¸F%p7ÚŸÝ—ïÈ JŒùÉtø¥"*$7ãc=[ï‚ÔZpAµ‘ìz›xÆæt̉Ï<« å—'¥WV·š(’æçÅ` çJñóÏ¿ÂÓ³ øg—••#9yZµêww?tì8æqdøç¦KyäÈI´oßnn¾èÐa>ýôßæ•Ž¥W+”è’’Qú|HÛC k”ÝÍÍ—´™ŠPbOqq ,XkðùV­zaÁ‚µ(..1™RíËûµÂ’z€ÇŸ >~)||zÂÕµüýûáÀϬj)ì­ì–@ÒŸóòΡsç·=ŸšæóÖx×9zÙm‰š6(å«gÏ^ˆÓаa ^|±#ðukoƒ·šûý®äÝb {Haé{ž$âNñërרŸõË }SNô;þ$~úvXb†X|™/Ê@Á,g v±ï3–E'H«”e ÷Š^)“¡\lÎ ƒD™x>n¾ t&¦b+Ÿ›ô2c¾âË!trÃ&f–Å–)˜=3/1H$¬SÈÚ$ rsÊgîòÑF#†ÊÁÉ:U¹œ‚‡S¥)ʉ‹[„‘#ߤ§¦fàðá“ø×¿6à×_/cÓ¦¥X¸ð#\ºtƒksOðÃæÆÛˆ‰IÄÚµóðûïW±zõ¼÷Þ,ÞUl#DFNźu;PZZ(--CZÚvDFNU•)]Jí1õ|HÙC Re+÷œ9ï#:z(q›• Äžøø¥¸páŽÙŒß~û ¹¹™¸|ù&fÎ\f2/)¤Ú—±ÞŸ?/Æ›oŽ@qq NœØ‰'On`Ïž°eK6q{Haoe'I^²dRSg+Ò[Ó|žÔ»ÎËùŽ#…Ú6(嫳g§"4´®^ÍÅ/¿\Æöí«°gÏaÌŸ¿†#WS¿ß•¾[HØC ’>O¹¿ÒM 0Fx‹Ê2‚¾ŠÜ¯Òe¦:ÜÊäÕ-A¸nj£F…³ÜÜ}x×*/Hç)i‚Nî¢)‹DÒä¢7ªî²xR_Ù‹–V˜µÎÞÊÑrHEÒ¨ÉßÚK' ï†Êÿ…ãW2úÊÃùóW±h‘𥗕õ 22’ѱc;Ô©ãŽ.]^Gzú¬[·C•}iiÛ‘0!!ÝàææŠ¾}ƒ?¼MU>Û¶­D­Zµ ‹‹ ¶m[©*RºìÍ-u™cÏ“'"=}7&·ÙÄìÙ»÷23—£]»×àææŠ¶m["##{÷1K‡\ûR‚#Öûºu;àïßii Ѳ¥7j×vAÇŽípèPq{Haoe'I>}z7Þ|³‹I¹šèó|Ì}×U‡²Û5mPÎWóó÷"** ^^Q»¶ üüZaË–ذaq›±ÞI½[±ìä0nÔ§¤_Å™á7µ¯€d¼Ùqþ™rQŒHºÁ~‰YwY;Ågûåç5•/=àÏîëÿcOœÊETËÜðŒåå Š>3¾ »ƒ­ÐK©¥ ¦óî-`l´¿€ÕF$9¡Öa2g`@®>?~‚I“æcýúÅxá…:‚ëþˆ6m|8iíÛ·Á_|%“«üüKèß¿''mÀ€ž8s悪|±‘Fõ;aÂŒÇùЉIÄ„ sTë"aRHèzãÁ8~ü 'íܹËð÷ï§Z—Z{6lØ…~ýzÀÇÇ[ÉVCÌN''îØš“““YÏÚTûRŠ£ù|NÎ1Lš¥ÚF1ÍçI–$ýY 5ÕçùXò®s4Ÿ·7”¶As}U?“LGóy’ïêóz=òv¼ÁQYaßI—Ú‚@,tß°c”ѧóCñ¥ó"Í`X²/©-n›a)‚ˆc:ÃOàä%Z½U3ââuo\Á·QvË…Gĉ=ÛJ}U nº¢ó(mƒj|µ´´ ׯߘ13ƹfOßïZú¼Òw‹Ve·Õß6$PÕŸR3S¬Æ¹x*Õ,U=ÕÀpM$M²x ¤:…òƒ¼è öNüw Xº˜Nþ…Œðƒ`€Ã¬Î ÃùO)¢Ï‡h´€ô¾r÷Á¬½Ôê¶á€„(R Â$ÝâmILoß>p~®CŸM@:¿)) èܹ-àÔ©/>……ÇáéÙ°òFÝkœõq©©›pèP6lø¯½Ö7o~©SãÂ…ë(+û>³fG@€??~‚'>GBÂr¤¥-BXXÀÙ¹5JKoÃÉÉ AAápvvB~þ^¸¸´Eyù³ßVµüðÃO …ôô%ˆ‹'v iÓÆfë’’Qò|ÔbIÙ‹Šž¢yó`C“&À0 ¼½»á³Ï¶Ã×·•Yº”ÈlܸÇŽý¤›e7i¤ì)))E¿~cpúôyCZ¯^A8vl+j×v ¬N•´/µ8ŠÏ;;·Fçαví\tìØ÷î=@lìDD„bÚ´h³lwŸ·FÙ-”?³‘*{Möy6¤ÞuŽâóָ޳%mP¯²7  ðC~þ^C„½}¿Úù¼’w‹ZÅçS–nAÆ̲sðaøæþ$$¤àÁ«Æïv¿†ßÇ1lxi¸À@TÕ`x7/3Âk +·?ÁÑ)2A̰:é²ùò®3"½9] §âú*Ë&’ç^~LØ.HgÙÀë÷2ܸº éù™èЊ•µò)2ü,å2·MV¿H؆^^Aè¼Ànv™¶ $&YH ¨ÝtÔÞ¤6d%±a ÊÝ+p²ð$)øÈÍøñ³±téL×¢3fŒÅ A}>/¿üÄÄ$bƌԫ÷‚A&'g=‚‚àêZ5@dä de¥ ))Õ ãîî†çÏ‹_~™ƒsç²ñìÙsÔ©ã&©Û–nnäåÕÉèÝ{$22’%¿8•ê’’Qò|ÔbIÙëÖ­ƒˆˆÈ̬܈éܹËðð¨/úÅ©T—)™òòr¬\¹ÉâhR;?ËÙ3cF2ÜÝÝPXxÏž¢ à8\\\¿Ô £¤N•´/µ8ŠÏ»¹¹âã ((u긣C‡¶Ø¸q 6nÜm¶íŽâó¤Ën©Ï“òg%ÔdŸ×Cê]§Ô)´ôyÒßq–ú¼’6¨ÆW抋oáʕèW¯.’’ŒkÍííûÐÎ畼[Ôâ(>o äf¯ù;ù³e ¡þ¢²¨Úíž‘¸VõköÛþÏ[3/\&ÀeY×øöËGuq£tÒeY!¶ì@N·`YHØ{©ƒàšH‘»Àü°{î²}~j¢6„úÅ–)¤ìeå#4co«A›¢®Ì•& pïÞLš4OðÌþ"vvvFBÂܾ‡gÏ qýúQxz6„¯¯ü—uPPg BóæMqÿþCŽÌýûѼyS5å"ÎÅ‹×áåÕXpÊ‚µá?­‰Í›÷¢¢¢ÙÙG9¡vÖ`ß¾£hÑ ]º¼nQ>¤v½–³gÏžÃØ¼y|}[ÁÍÍ~~­•µ{ö’Í“_§JÚ—-ÐÂç›5ó„¿kNZëÖ¯ª^:D­|žtÙ-õyRþ¬„šìózH½ëH õ{ž%ßq–ú¼’6¨ÖWk×vA@€víZƒ;Êê·õ÷; Ï›ûn±&¶ôyHö¥Xÿ‰\T´7àš!P@BVD§qB¦£+±ÛNá%¹N#hàèØg¼O ûn P#|–R³ÀUzT¨ÑßÃÎZÑà€„z“{HE ¨P";8`õÿHé­‚Àó - ‘,h³•†swƒaÄ•Ô;¦¾ˆ×¯ß‰¡CÈÊ\¿~ -Zx> 6…9zô4zôø«l>Öäò囨º5W¯AVÖ'š®‰ä?­ ðC£F pôèiääCDÄ@«ê[¾|#’’&[U‡LÙ#ÖvM~òëÔÜöeM´òù®]PPÀ]"tçηðönb}JÐÊçí±ì$üY™žšëózìé]§õ{ž-¿ã”´As}µ¢¢¥¥¥²2¶þ~×ÒçÍy·X[ú¼9ˆu쑌1dœ+/àæ#ܨ§Üð#•é$ "xYÊêdÙ%eÄl6Æã‹ &Hï[ 28Á õ—zl:°dÄtÒÑÆ<Œ/:A>böÊåÇ~Î Ä6/4lH(y¿L]šÐ)¼¤v†_®|êó"‡è‹KFÖŠRö†70`¾Î!C&¢ àJKËpÿþ÷ˆ‹[„[·îaòä‘™¢qüøüñGž<ùyyç€Äĉ™¸¸ÑX±"'N|ŽââäåêU›7Æ<Ã,¤¨è)¢¢¦###õ‘žžŒ¨¨é(*zJ\—’çc bc#1eÊb¼üòKhÛ¶¥Õôäæž‚››+úôù›Õt¨Á”=ï¼Ó11‰øÏ¸·oƒqãf#<¼¿AÆ^ëT-}þý÷GaâŸpáž={Ž7ncâĹ;ö]âºÔ …ÏÛ[Ù««?+AKŸìï]hãóöæ?¤Ú`HÈ(<˜‡ß~{ŒçÏ‹qåJÆŒ™‰Q£†dì­ìZú¼’w‹-ÐêoR¨ÙÈûÇ|ex=w -*B.×agç.Lg 6 ¡3èË—o7opÀD‹³D@ôºøàб¬ Ÿ/£/›Î¸´BnÔCcJDOX²á $G4€äIÉg«“äž;±HHå/1 w oGŽ|áá“ñ þèÝ{$j×vÁ©S»áææj‰‰‰ÀÂ…ÿ€§g´hÑ‹ý«WÏá| wèЙ™Ë1eÊ"¼øbGL›ö!¶nM…ŸŸøÚ/k3iÒ<„…… ((@å àA½1yò|⺔<[0|ø[øõ×ßLFXʲeìæ$À´=}4:µChè8Ô¯ß ŒE§N¾X³f®AÆ^ëT-}¾s玘7/11‰ððÀÛÿŸ½wó©ÚÿÇŸ{Ƙ%©CÂиÄšsF¦*áçVÔ!%E z i4 JÅ ã2ã~‰ÊeÄi‡t!ŽˆRŽúvœJîÆ\öï÷¼ßï}Ykíµö{¿÷¼g¬çy8ÍìõZ¯×k­õÚïy¿^ëµ^ë±dtíÚ©©—%7l>ÔÆî¤=S®Kûˆ€Ü´y ô>ëwl>Ô>z_}8-Z‹ØØñ—¿$à¹ç^F÷îðÎ;~û µ±»ió<Ÿ-¥·¾Û>§VçÏ–[;9䌊ógè«ÓÃêLºJ¯7`å(ãV×G’‚ ¤ ¦vR0Ã×EŸ¢¯ïK>[®(Œ+5œ@áK»§‘‘1°yéyòÛ…¥ ô×iŠžïÑÉ ¢»ÿäõ>D ìfÏ­MÚ#üª‚ŽÙ gfén%¸±QTT„˜˜6ؾ}%7í/øN@Ú¼Äió7ܰy§n%øÏ]Ïûžëªõ—øNÞÊîæ ï*ŒÕýUoª<Á÷ôÓªZè¦Êò>3ßjàk#øÕº*þ û^ªf'Ú|c€ÊìCtS ¹v|ÄJù>^ªnÆ[ÌK ’~4ôšªô˜n ~zbŸŽZ相Øô^DP¯[ß÷˜)Ÿlî&€z+áñçóú£¸’м#y†£ç$n<¨ªŠùóW¡víò袀 ió7¤ÍKÜh(¯6oµ#î¡aô7x6"´Ö Ó[Ö8°S|ÏR*I*r–ö»~”è|:Z£CÐq&—pð¼µìŸÑ>v((`%Û‘c A‡J4ç IDATlõ’¸aÖuëÖºu™¥­Š„„+6/q£Aڼòló øî¦7}eW ÿÕÐIàqðxý­~·ÜÈTQ<;ÝŠ¢èw´Uo¥í8|9YЧƗŒÃ¯³Lã( &‡¦’Ç­éãuHýãõÈòñ4e-嘘u§uUr‚ŽŸwžÙüÈëÌš#†b$žÌÚ‚°u¾ß¡  >… È¥e;0ºhPÁO­Èl J³J¸„Di@Ú¼Äió7ʺÍ+?Lëˆ{s½!8 ý]ï4šEÿí|„6_=?ŸN,Ç^GÜó›ª ˜SÖýÁsº¿Þéö>S z›ÛL:iæCïxëuÖŽJ‰n*iNc0ï0ñÖao(Aoß:jôF‰-yòTÄ×y´”m×i¶^'gäÙ8”-`EO•ÍñÌq”¼%²Ì·HHHHHHHHHHH„˜Uý­újé)E謮ͳø]¯“ñ˜€Y&»¿^56/òøo6 J®ÈM¥§ü¢/~H¿^9f@Ì£µàå¡-Žhyg"é‘gšŠcÎ>R‚ÙNÑ+â9t|½Í5dp@BBBBBBBBB"´@­:¯êžÏé3œk_Eý?Äwç½&K|ÞŸb¯ç[Ò¦®,$xû¦› ŒãÔÜv è½}(N²o^m&>%ôÞ1˜Îºûâ'´ %âK·÷¯ñ @hæß¤šÝ_ÊѼYP> á%ιƒÁ‚9 hÁ¬ g 8v =…/ˆÌcÖ_WX:÷,HHHHHHHHHHH »&Ž sj½‰•·]}ôÎ,M–98@×ÍZã8ù2HzyØq¤ÏSž“0$GY¡zö9Ú¬ËÙ°ãÒ‚ ΦEq½€£ÛJãgñ 6D³ìL‰—“c3ó #P1qöìï¨Q£U©ÞKýé§_áé§_Dµj ¸å–æHHè¥K×ëΠðÐxï×6þÓ‚‡FnÎ,Maa&Ožƒ Ú!:º š7ïŠ rƒ®Sdì<öã6rs÷ eËǘ㲢‘6oMÃ3Ï›7oÇ=÷tFTTš5ë‚?þ—-]yôqÌOnîtï>U«Æ£råfHHèåË?tZEnðèÈß‚¨¨8Ûº••5œùlEi~‡p4Ù„gÂã &šÌ_80’2Ï<ó˜h7G1ztºuk‡ƒsðÛoû±|ù ¬^½ ãÆ½-DªzÒôÏ+ôé3sæ¬@AA!   ™™ËѧÏa^NÈâ¡ÉÈÈÆ¦MÛñÁóðûïû±`ÁŒÿ¾úê°ãú8§ÆÎk?nbÒ¤9ÈÈ0´y¶>Vsxøð1$%¥cÖ¬×ðçŸ1sæX<÷ÜË8zô„ã:;§æ§cÇ~¸pá6nÌÆÙ³û°bÅ ¬Xñ!Þx£t*{óèÃó.“ì}ìØ0`@/!}ÊâšÎ}¶8¡sY:õî”W µÏ¸jÏŒ`’cé?Wo†ÉÉVôDgEÏÛó3‰·^_ýñ½#nJ»'èëeHg‰®¼™Úq*ㆠ ôiüН³¡Åùòû°*åè+€â•iœ#ïx)÷ÔúheééhÙ9äÔºŽ^ÕÀV€Á „k X*hMÜ|LÅÙi7æâË/b„Òý#¾{÷ôíÛµjÝŠ#ФI,^<óæ½+Dã&–-›Ž * [·$@·nIˆˆˆÀ²eÓKEÍ’%ï#;{2š7oŒJ•¢ÑªÕ½ÈÊš„9sV8®Spjì¡f?°sç*<ôP«€iÜBY\wÀz33—#-m0:th¨¨HtìØ©©1{ö2Çuv NÍϨQƒ°cÇ»hÛ¶%¢££çy/23—;®3xô±ó._¼xYY«–6XHŸ²¸¦€{Ÿ-nΛà±C§Þòjc¡öÙƒҰgþãÌZ<0†¤óã¬]næy\G4AbaCFp€?šÃFc“ÞS#–µ@²è©Hgë Ðdõ\)ÇÄE‹¦å“×Ö˜Î9µ“¨Ar§ŽTˆ7rg œ?C‡ŽÃܹqÓM•5sÞ¨m 4Á‚uuVk <ê£îIIé<ïr~þuÌšµ£G–]^mÞ)¸ió¥ ž÷Âλs#ÙXi~¶8õ¹êô×à™ƒz_“ä0¾ïûOéurIúéy‘ÑÍ:T R0€/8 hõñ>ÔÝ@®ðïÏ| ´“ð ·°t4ŽƒØ®Ôu'ÑSôÔëGâ¥9f§ÂawDùöaÝø\ ÊQj EÏ3‹6ê1F@qâ²1êÃMFøÕ0tÊúŠÄŸù¦MKCË–;v|ž=‡áèÑm¨Q£š§£RßÖ¹c'¡ÇÇ7ÁîÝkLÙ ,šž=‡áå—!>¾)Ο¿ˆ¼¼Ï–ö23' GÜ4vôdî~þù¿èÐáYdeMBrò«ÈË[š5ï°-‹F“‘±7æbÞ¼7P¿~|óÍ÷1b"öî=„ÂÂïméÈØ/]º‚:uÚàÈ‘­¸óÎêPU11­ñÉ'Ë×À–,+sŒKÚ|à4áá QPp aaaHLì‰ðð0ìÞ½PTtœP‚úÐPï…6äbäÈIØ·ï#Ü~û­¶ôw,}xßåùóWaëÖᣲÒ¥<Ù¼( Ü´y·Áó^8ñî”WJ~œú\6e1ªU«nK‡î?‰N@ZÚ4ü|×óPR4U…Jøb¯zFÕø\Õ·>ÇFŸ êè}}|¿“ݯNÞF ‘QO3oz»‡§Y'­q¬Úÿ7ñ.iÓê§ÓÇì0©¤AÔ&ëá}¦¯àïG—J¢Õ¶ûùÃ8—z¦,ò®¸ož ίê-x(|…« ¥NsלÜGµ•1 *_± ¨SEY:‰Ö Ú„¹áóyP¥"ïÛoÆ}??ýsãí tQªÆaT‰ÙT©ühÙ”qŽà Äi´•Jo§…ÞNP€óH “žÕG8èÂ’AéBiðñtšýŸ1^ >˜k M»º,”œââbLsèÐw¨[·VÀ4ÁÄþýß`éÒõ8xp3–,yßÖùo»˜;w%zõêâš<#âã› zõÛ±eËN¬_¿½{wuM6ý”EH›C›6 ¦¢T[¶ìÄÜWJ¹û^,Xð M› !¡YÐäSÚ»üÖ[ó1fÌ0§U´…P²ùPDiþ- ÇCíÝ 5 µù -ó¤0 ÎYî°2ê®±åápXïø—ð"Ȥr·Øùe>tÏXmF'žªcgß–ÿf·#ÿ®p`ÿ A Â<ä`‡0œ*8Èì#(ÛR¾ôVò…xÙ9B`0À¡Ev:<‹ rqîÜy\»–Ž ÿQxöÙÇ…hºt€mÛváÂ…K¸xñ2rs÷`À€4¤§¢q—.]Aß¾#‘=U«VAVÖdôí;—.]q\ÖãÁ‘#ÇQPPˆS§þƒ”” øî»“6ìÇe‰ 9¹†ŸˆÛn»Õ Š û)‹68RRúaêÔ,äå}†üüëÈÍ݃3"%¥©èã…ïÅÔ©Y6lV­š…ÄÄø ÈpZÞw9'g¢¢"Ѿýÿ¹¡:¡fó¡ 7lžFà˜J´y 8Œ’ë -t‘p”ÝÛ’FzÍJ_ cð~ùó«Œgîu¿Yʤ^?(Rÿ@ÈZ§Ö¬E®JqÒ-À ‚0­¥­«÷àuÔiÁ}PÀ$Ë ðí¤óÅ%ìf+xeð®!!(à8DÇÂPˆÊŠW†¼ºŒRäKBBBBBBBBBB"” Âwëø3ÅXÕ?*Ûb9ç08b$ÊbjÅW¦Êrô¨}ÙŽ+}·ÝœMAÓ+8 kž“éÍýÅÒÔ)ñ= gz;Wp@Б÷xòGYÙ N íc«x!íºA‡t*ðQÖ]³¹¹{вåcÓ¸‰ÒÐ9TÆî…›úðÈ t-6oÞŽ{î錨¨84kÖü/[º:E©Oü'JcG®[dMss÷ {÷Á¨Z5•+7CBB,_þaÐõq Œ½°°“'ÏAƒíÝÍ›wņ ¹N«(ž÷ëüù‹HM‚ØØÙM›vÂG}âk¿‘íùÓO¿ÂÓO¿ˆjÕpË-Í‘ÐK—®·w&S@§ÈØóó¯ãõ×gùì¹AƒvxýõYÈϿ\àY ÞõrúoJYYS-Ξý5j´ºaÞeÚçXTTœÓjÚ„Ö‹g“+õkvة٠ÇÝsjAlKÕ£˹T5t”6ªž*ñ$…ç]&}Œ†>š1Ðç“ÆKÏÃLC9V`ȱ¦3‚ÔOõ¨6£_+0ƒªGK¡ìp(_Q¬,W4[À©@‚À«›hMÂ,uЧÏÌ™³…€‚‚Bdf.GŸ>#tt“&ÍAFÆh&/7á–μsèÜÔ‡G–S6vøð1$%¥cÖ¬×ðçŸ1sæX<÷ÜË8zô„ããâ…ªž4ý³Cc…²¸¦;öÃ… —°qc6Ξ݇+f`ÅŠñÆbU ËâØ32²±iÓv|ðÁ<üþû~,X0ãÇ¿ƒ¯¾:ì¸Î¼°z¿®]ËÇC=üüëÈË[‰‹cõêw°xñ:ÝjÏ£Gg [·v8x0¿ý¶Ë—ÏÀêÕ›0nÜÛŽëãœ{jêìÝû56o^ˆsçþœœEØ¿ÿŒõ¦ã:ó€g-xhœú›R×T‹”” xæ™Ç‚¦Spjì¤Ï°±c_À€½×Yäyß±æujÞþ†³âª¾G6©‰î¸ÃÖŽ+‘­ñ-»A»ãoèHQS7¿DžÆ'œN¶¥žÔŽdÙý:°ÒÑõýÌG1È`&¨r,À:ÒÁ FÁC ûÇ,é-õî$(Þ~Å”1@²eÓQ¡Btë–èÖ- X¶lºŽnçÎUxè¡VL^<4nÂ-yçÐ-¸©,§l,3s9ÒÒ£C‡ÖˆŠŠDÇŽmš:³g/s|\¡†²¸¦£F ÂŽï¢mÛ–ˆŽŽB\\,^<™™Ë×Ç)85ö%KÞGvöd4oÞ•*E£U«{‘•5 sæ¬p\g^X½_sæ¬@Ó¦ ‘™9õêÅ bÅ4oÞ7f;®KY\ÓÝ»× oߨUëT¬&M<ö¢¢"ѨQ=dgOÆš5›×™ÿüßÂzûe×Vׯߊ¡CûU†eÍžiðîLŠ ¬Ù³¢( Óï5„……ô]!ö̳Z'ÿ¦”E{>þ"†‡¹s'⦛* ë+"Ë ¥ù}cÞ¼wѩӈQÙah‚ð§«›’Í”-ØD"R ¡½Æ~肜Y_œÑ^è‘ÊÓbŽ"‹?é¶®¾ìˆÓ|GN(+EL?;½})-âFçlféaz‘*@ˆÜõë—Šëׯ#'g 'gòó¯£_¿T—Ô,ûpj33Çã›o¾Çºu[k׿àèÑÈÌ_*ú$'?¬¬Õºgk׿ wïnB²œÒçôé_[кõhÛöIÔ«ƒÓ§âã$jÖ¼‘‘û zõz±Ec7m,˜k:{ö2<õÔ#B:—E{މ¹'Nü¤“uäÈqœ9ó«ÎnâèÑ8{öw4oÞÑÑMиqG¼ýöbë‹âH{ö8—‡}‡þýG¡oßB:—E{NNîƒääWqüøÈÏ¿ŽãÇDrò«®’hàY SSʪ=õ&Ú´I@×® é©EY´g-òó¯cÖ¬%=z¨¾î‚DZ'í"B·kÍ+Æêx€¾º½ªïCbhzLK…÷ö!;èŠŽÆØF¡¿n+€$º£®êþc¤õø»¤@Fžæ?Æ93u„„uüm;bZFŠbÏ¿uú‹mNé‚òôb‚‘-@l²#CÿýM™¸lŒúp\{„_SðȂߡ(À=§ç`Ú´4´lÙÈÔ]Qê[žuІnò þù¿èÐáYdeMBrò«ÈË[š5ï(}.]º‚:uÚàÈ‘­¸óÎêPU11­ñÉ'Ë×À–¬@hÂâ à˜Øááaؽ{ ""¡¨è¸Øàô¡¡gÏaxùåAˆoŠóç/"/ï3¤¥½…ÌÌ èÑ£7›:b6æä»³aC.FŽœ„}û>Âí·ßjK÷²bÏ °qc.æÍ{õë×Á7ß|#&bïÞC(,üÞ–þÁþŒ oˆ–-›cÖ¬WѼycœÊÖyڔŨV­ºp?èþø“øáÔ¤¥MÃ/wõ‡Êp´3Í~‰ÇY AõúŸÚþ_»…Z¬’ûû¨Å†g~¾¤žª Ó´¿ªçJ5þ êǪgå•hÖÖÏV%ΟJq*ýbm*Ã?Uýzš›uú›æÛ47ºÉÑéhZGEKªšúí†.›¬ºwþÉmä3œYªnÖ:Ðx‘QLÖÍÉ› ¨– ‡Ìq¨ø|~Š¢íGóŒ×ZÉ/ÂXéÚ©Ê×n!Ð9¬UëdgOÆÃ?ƒììÉÕçæ›+¡wï®X´ÈS|lÏžý¨Zµ ñ4¯¬@ô‰ŽŽÂµkù€/¾X={ÖáêÕk¨T)JˆS6¶~ý\$&Æ#2²"ªW¿}ú<Š%K¦a̘ !Q¸icN­éƹHN‹?œg;(À+g©RÙ IDAT‹7íù¥—žÇ£¶GÏžÃpÛmERR:^z) •+ß$¤³›Ÿ‡QQ‘˜=ûu$&Æ£R¥h4kÖóçOÂüù«|4Òž=íùùßáÀM¨\ùfŒcÿ,uÙ±çÉˆŽŽÂÑ£ÛpõêQ9² HM"¤³Óö̳,§þ¦å·ìyРј2e”/(àÊŠ={QTT„éÓ”~¶kcšé4iwìÌ“ÖÊ1ª3ѪÄt~žc¬>¦6­^ÄxRBf´ŒÄtð´Óx²iÍ4ìµbpb-¯jdöaÁVZ屯¾Œ5¨¬ìïÊÿˆ¼¹¡°q,[ÀLf$`À +]Rùº¬bß¾C¨UëŽR­`îEròÓX¸p Š‹‹±nÝ]ZŸÛ¨S§&N:£{vêÔÔ©SSˆO0m,11Þ”Bn‡&ØpÓÆÖ¬ÉARR:6o^ˆ-J÷:(·ì9<<iiƒqìX.®^=ŠC‡¶ Fjˆ‹s€Üü<¬]»š6m¨{Ö°á]–iÕ7š=@ÅŠˆo‚wß}+WnpE& nÙóêÕ›°pᛈ‹k€¨¨H4iÒK–LÅêÕ…øÞyÖ‚FãÔß§á†=Ÿm¿äŸJVެ¯êãI¬®¯Óõ¡BàÑêª=²AÒMÕþ¢ÓÃøˆ¿ÞI=C H!·™ƒ26vÞY:pèf–ïϦà³s;ÙÅ´¶^"]¨²ÅÆf©€DÈaÿþo°téz<¸K–¼oëü®“ˆo‚êÕoÇ–-;±~ýVôîݵÔtiÓ&ÁTœhË–xàûJI#3úuëÖ ˜&˜pÓÆ,xƒƦM Ð,hrxQšö~üGÄÄÜÉìw#Ù³ÅÅÅ(((pMžnÚ3éûG¨*øÖÂHŠSܲgÚµ£¥¹ ãöçó[oÍǘ1Â*Ã_ÛýçÆùw}õ;ȤTd–¬’ŸSPÀêý×9Š>gštÖŸí£ë (¬Â†äzæ>*³Ižù9›–Vv3‚Q?…œ·ïiÓ 0ÑÇd9Ï ]'žl :Æ  ?¬ÿœÿY05’³è XˆòbºêvŽOiM׆Ðßp .]º‚¾}G";{2ªV­‚¬¬ÉèÛw$.]ºRªz%'÷ÁðáqÛm·¢Q£z¥¦GJJ?Lš…¼¼ÏŸ¹¹{0cÆB¤¤ô/}ºt€mÛváÂ…K¸xñ2rs÷`À€4¤§¢qnÚØÔ©Y6lV­š…ÄÄxÇùÛ…öüøãCpäÈqâÔ©ÿ %e¾ûî$† {&(òœÀ /<‹!C^ÅÞ½_ãêÕk8|ø† yÏ?ÿ„æF¶çžÅ† ¹8wî<®]ËÇGпÿ(<ûìãŽËöü÷¿wBRR:¾ýöòó¯ãر0pàhôìÙ9(ò¬À³<4¡ö7%T¿¸ ·¾oääì@TT$Ú·ÿ¿ Éwö3Àn"º¿Z‡]àº9–`«ÛXW’¯õ³rh ÏT+G_5éfud@1=ÑʧMØ·(ÐôèÁ_EEެýxü@óÎ:YÚ¸|n¹¥9^|ñ ,]š&MÈgyˆ%%õÆøñÿ@­P·n[L˜ðÌœ9VçHñи 7m,=} ‹ð裃t骊R¿ývÎqy¼pÞŸyæ1ôì9 7ÝÔ?ü *VŒÀŽ«i›g°?[¶lŽ×^KARR:ªVÇc%£k×vHM裹‘íùõׇcÑ¢µˆ}ùKž{îetïÞï¼Sþ?Ÿßyç5´hÑݺ D•*-Ð¥ËóhÑ"o¿ýªmžØ3ÏZðÐãoJ Õïn­ïo¾9¯ôk Aõ¼_Þiê\çÐUòcoX þv:¬0³2È)öÞ6}Ú½© %sðVjWpí(kÓö©µ,28týT¿¢¼uÌÇ'ŒúiûÑô Í¥–Ù`*‹åÚGÎnîMlÎ#Æ> h(A9ÂÙvŽˆf °"ÊÄecÔöMÚ#ì*Ðcá暴»OeRo% ¡¨¨11m°}ûJ4n\6Š@JHÐ íY¢ŸŸ„âh t+A¸ yöŽ’SR×Ò÷N±¨6Þ[E™ãå'à“QAûK˜¢ <³7$ nÝZX·.³´U‘Òž%ʤ=K”'ܰö¬ÒŽk>A_*@5´)¾R…ÜÉÛÏŸìØúž«ægþñ©ä>Þg€¦¢Ùï÷;ßFñ:9„ñSe£ä¶6 žZݼ\Hþø_éVÖ×4**.¨ú8…@ße/XŸ‡n"7wZ¶|, ÏŸùon~þu¼þú,4hÐÑÑMРA;¼þú,äç_ª>N!±ó~Ö¹Õ—BïL¦€ÙwS-xøƒ,ÞÔ»é9Î={uÒûµþ¾DL)‰RPb ä bïÓbrÂb&!°¢yÎö'­64e@$Íé6ʲÌà0<ˆYvo!`8òÔà€­ù=ˆ6b#íß±ë ÏmùþÖïë¹w­uQ€ˆð0Dº”1’2Ï<ó˜éùµkùxè¡§‘Ÿyy+qñâa¬^ý/^ç£éر.\¸„³qöì>¬X1+V|ˆ7Þ«RÛ§ÏÌ™³…€‚‚Bdf.GŸ>#œMY¼ú¨êIÓ¿`èãœ;m”¤=—űμËNaôè tëÖæà·ßöcùòX½zÆ{[ˆæðácHJJǬY¯áÏ?bæÌ±xî¹—qôè !}Êâš’ÖsìØ0`@/Çõq NÚ³´ÏC·1iÒddŒ¦¶ó~þܨsSS§`ïÞ¯±yóBœ;÷oää,Âþýß`Ô¨7×Ç)85vžÏ:wa°ò"8Žø2ÒEv|ͼµý­7WÉzyüZ•1lÿ®¼?  è›‰:”ôSŠ5íì£$:â1’šŒçþvÊh„ëxÇO`pâY»ÜüÁF€†Ú‡‡–¦—@Æ‹¡X¢yÍ‚/H%’c#hBWÀfÒcòsÃQ‚0DT~ÆÀƹøò˃˜0ÁüGaΜhÚ´!23Ç£^½T¬æÍcãÆlͨQƒ°cÇ»hÛ¶%¢££׋OEfær!=–-›Ž * [·$@·nIˆˆˆÀ²eÓ MY¡¦›²xhxl£4 í¹ô×´,Ž=Ô°{÷ôíÛµjÝŠ#Ф‰ÇçÍ{Wˆ&3s9ÒÒ£C‡ÖˆŠŠDÇŽmš:³g/Ò§<¬éÅ‹—‘•µ iiƒ×Ç)8=vÖç¡Ûعsz¨µÝÍ¿)eqM׬ٌE‹ÞBãÆõ‰Fê!;{2Ö¬Ùì¸>NÁ©±ó|Ö¹ Æ—û@‚"»½T]œ7{G„~‡Ìø«ªeNˆ4™ „‚|´#Þç&ý5W5šž›œ{kj!=RŠ>ìdó¸xŠý±kò9·ú`ÍLR¶gÁAS­n¦ã#¼X`úþbN>•ÁF¼¿é¢[OèçMŸWôXÐÎ3ï|[g øûø«ýkÛh»ó¤L ²¶þyooÐÀ˜©àKí°”iÜ=g™9{UÂ;æ'g:€h·æ]~­^Þ`˜S¬(*|GM‚RQI>°ÞMVÒc3"@(>xsTG1jÔ›hÓ&]»>Dl?zôΞýÍ›wEtt4nÜo¿½ÅÅÅDz/fÏ^†§žzDH—~ýRqýúuää,ää,B~þuôë—*Ä'3s<¾ùæ{¬[·°vmŽ=ÌÌñB²xõ©Yó~DF6FlìƒèÕë8pDH_'Çžœü4²²Vëž­]›ƒÞ½» É⡱kÁ„´çÐXÓ²hÏ€3ïr0PPPˆC‡¾Cÿþ£Ð·o!šÓ§Allm@ëÖO mÛ'Q¯^ NŸþEH‡²hÏZäç_ǬYK0zôP!}íÈ¢Ám{¶ú< 5ð~þ„Òß\7í99¹’“_Åñã?"?ÿ:ŽÿÉɯ Sʪ={Áóyzàp8³’YiÓtgNÛ_¬/M–ßQfƒ]¼Ž²ëO™…Õú1:/¯\+ÁW1!0'‘˜¹`£F5Pbû:=;;å³uŸ0ƒ"ºéƒ`ú&6/eâ²1jû&ívMÁ˜­×{¬LôiihÙ²‘¹ƒRßö9Ø;¾@ÏžÃpôè6Ô¨QÈ/<¼!Z¶lŽY³^Eóæqòäi$'EïÞÝð⋈|7lÈÅÈ‘“°oßG¸ýö[méȸàçŸÿ‹žEVÖ$$'¿Š¼¼¨YóÛ²h4={ÃË/B||Sœ?yyŸ!-í-dfN@léÈØ/]º‚:uÚàÈ‘­¸óÎêPU11­ñÉ'Ë×À–,Û°‚´g2ܲçP[S7í9ÔÞe-/âã›`÷î5¦Ý_MxxCCXX{"<< »w¯ADD#·­SY°g-æÏ_…­[ÿ…>ʲ­7¯,Ü´gžÏCQ8aÏ,><Ÿ?¡øžºeÏׯ S§þعóKß³ví±uëRT¬aK÷²bÏÚv/hŸ‡,L›²ÕªUç¦×¢ûãOâ‡S–6 ?×yÆß@qlTÍÿûI ´†"ƒfV~'\»!®v±I,44Å}½ý ´&ي晦É(BÕÉSKø64Yåæâ’*Ñ…R}õTaIcVýÔý¬a¬ni•½ô*A¿`m«ˆ¦ÝɤîµëeìMéÇ Û“j^ Kߟ-à7!AVê¼sèÆù˜ÝG0ø@y?Ï„¢hÛn7 SÐì.³#b¬Äk·2ï A£1eÊ(ß—¢¢"1{öëHLŒG¥JÑhÖ¬æÏŸ„ùóWé7nÌEròX|øá<ÛN€€¿|Ôªu²³'ãᇟAvödêi^Y4šõëç"11‘‘Q½úíèÓçQ,Y2 cÆdØÖ=±ß|s%ôîÝ‹yŠ5íÙ³U«V!þ‘æ•E£µ ¤=[Ã-{vjMEõ¡ÁM{vê]vÊžµúæç‡6¡rå›1fŒù0‹&:: ׮徸b=öìY‡«W¯¡R¥([úxå·ìÙ‹¢¢"LŸ¾ÀV¶€}hpÓžy>yà´=³Àóùjs÷ìù¥—&#:: GnÃÕ«GqäÈ6DDD 5uŠmÝËŠ=kÛ­>]E »–7øx}qÞí}fMÆsM¡Aφ¸q+ß éC=zàÛ=6§Ãç‚‹¯ªBñiȨ¬OhP4Ï©ýˆºéåÐeÆGXCËb„Œ]ecOÞb¼ "Ô .šrÓ ;Ù<òÞVP@¸Ýñ°ûé·WŽÄí•Í_ÞŒ•xíVæ=yò4†}ø‡ß‹Úµk iÓ†º~ ÞELC]³&II騼y!Z´°”SØ·ïjÕº_}uØU¹‰‰ñ8qâ'Wej‘œü4.\ƒââb¬[·E—Öç$DlƒiÏ|pÞZS'á–=“`ç]vÊžµ¨X1ññMðî»ocåÊ B4uêÔÄ©Sgt´§NA:5mëãÜü|^»v êÖ­…V­î º,+¸eÏ<Ÿ‡<†=Ó`÷ó§´ÿæîØóêÕ›°pᛈ‹k€¨¨H4iÒK–LÅêÕƒ&Ó ¥ñùÌóyXf`ÇáëlŸ#ÇÁGÑLШeöÏøt ûu~ƺfE19Î4ÇØì0êç–f¯( Qub “. §_$8À@í{ø›ê-xåòh¦ÚPІ“Í*FhŽÅ-¬Þc6tÆ1UðÇÅü@5¢‚våöþý÷ÇãÈ}ºéñã?"&æNݳ ÞàA£±iÓ$$4 šÎ¼Ø¿ÿ,]ºnÆ’%ï»zVøÐ¡ïP·n-×äßիߎ-[vbýú­èÝ»kPäðÚ†[ö8BmM÷완Ò~—(..FAAM›6 ¦a[¶ìÄÜyàöçó[oÍǘ1Â*ƒnÙ3Ïça¨ÁîçOi¿§nÚ3iSÊBª4”æç3ÏçaðÀNÃ&%¼ëR¾½;ò,þ¦TmF‘…M犨›q+ßÜÕ_”Ž }}þ]ZËjúGÜÊñçoc‘²#´ ÞQÖ Æà…FO‡²³-j¾9¶“rOO=“Ô£vœoFÑ#L´&>^ºÀ@Ó:·â»3çp/¼ð,† y{÷~«W¯áðác2äU<ÿü>š©S³0lØ8¬Z5 ‰‰ñ¥¨­—.]Aß¾#‘=U«VAVÖdôí;—.]q\V—.°mÛ.\¸p /^Fnî †ôô!ŽËArr >·Ýv+5ª<¶jöÌF¨®©öjïr‡ÏbÆ\œ;w×®åãÀ#èßž}öq!š””~˜:5 yyŸ!?ÿ:rs÷`ÆŒ…HIé_ÃrÕž 'g¢¢"Ѿýÿ…¿¸aÏe<Ÿ?¡öžºiÏÿ{'$%¥ãÛoO ?ÿ:ŽûŽFÏž—%7ì™ç³ÎUX:õö7ðú–ütÆ4woŠ8‘ÚïØÓj2{ºsËWœ0>š3Îï¤[Ýˆà‘§%"ÓS‹#2 ³ÌY ”L âmÆàE(M‹–Â^{Ñ|„Àßä äp‰¶ úí l)⓯+>øsX,6í=Ÿ6¼N->è4H…_>úè¼öÚL?þ#jÕº<ôô!¨P!Üׇ†ÿýï+üå/Uƒª³Ï>›Šš5«cêÔW|ÏÒÒÞ¯¿þ†åË=öþûcÆŒEøúëo‰¦M"=}ºukç¨Q\¾|5kÞÔÔ7.%hr¬l£´!íY¡¸¦nØs¨½Ë»wïCFÆìÚµ……E¨W/ôBJJßZðÐÀæÍÛñÊ+SqâÄOhØð.ddŒF—.–ʸܶç6mzcÔ¨Ax챎Žó¶ ·>Ÿpªx` òý|µ÷ÔM{¾rå*&LøÖ­û¿üò_Ô¬yž|²ÆKAt´ýš! {æý¬³‚cÅch7A¨šÿ7´¨*P̨*û î‚u*ΊY7b-oG*T…BSâ3‘uRu²LZPûYŒ—ZhÐK«Òý5•P<Þy+öÿ¬‚‡'Å¡S5N<­È$}Ã[%ÿθߞÆÌÓ·ØðŒ§H*=zìœ1ê¡jæ—­‡µ~&@å]£¾‚Œ *X}(Ù>ÏöÔr~¬‚£§ÏáO&¹((**BLLlß¾÷îi ‰`CÚ³Dy‚´g‰ò„²dÏÁ ¨„Ÿ4­ÅŒTh¦Cvʬœ9ruzJ`Àp|Àì¨ùw~M·|½^FÇ^0ùδ~}}sÌsIrfiUõMý´Êúªê“úªæ¹%¬{Ùüãóˆ%ßÚ@Ôß×H?9ˆb’MT–âÈ|½ˆ9Ñôøƒ†F F7‚y]½]  „iåþñ᪪bþüU¨]»FÈÿ‘–°‚´g‰òiÏå Òž¦x¾ÔSƒö¿åSSÀI[ù,j è«Æ«´\q¿¢^$¹<…øxæÄO#”Ž®=“ïTÉ>–sjqlEØ6èzðȤ-!ñ´¾U@\w÷J¥Ðœu·äXËW(ªgB*hi.\)À­7WtB;‰aa P·n-¬[—YÚªHH iÏå Òž%ʤ=ó9ÝÌÝ}',‘¢rÞ€€UZMí9à¹<@õ±äíê»tÀÛs.E¡f!˜»‘û)€çø„ S]FÅ·Ô•ÐÇ'›´;-ÄÊЗ¯3÷œ‚I€ÅºŠ<´uîiÁãØ ]芳}HÅ×V(V‹=©GåªÓ¢ö,Qž íY¢<áÆ¶gò÷sOÖ¶Ê"aöço·Ãa-i¦;rž\RººÅ÷œÜßSߎ¨ tÒÿ—·}œ È΢ÉA§\Uhìë¿ÕO¥Ò0õUUÍì²YEGiv8}•’ÿ³Zfp¢DGÖ…V…}ö­†«¯q»´ž¡>6æg*!!!!!!!!!!Z`Ø$<í‚Çᢎ3ü×ÔHÙÅUùÒ÷‰·xÏÇ«*•­b¾ÿgA‰#NÕƒZÕì# WË7ßT@åa1ŸÁÎÎ׫染^Þ¸ÿD _†‡¡ƒ¿Q7®nœòô6íEw]aéÝL+!!!!!!!!!!Á_¦€©Ÿ15›T`œé¶®ò9+ýŒWÜyRÒ-ƒ6@«¾Ì ÁÆU€¡º6“o^Ò—x._Ué2ià]?‚ž¬+³/i©#Xbn@êÃ&øŒu³ vi×S!=föá¥Â8da!"ÌôDF$$$$$$$$$$Bmö1S@e8ºZÙ<…ê ÝÑ6ô'ñÕ"L}É©üþîg›š5`tüY0¤Ù[ðÓïd‹­-8`Žú”ŒîÐÓ³(hòÙÁsÖ‚W2oÏñc0I)ùŸ•"OjgÓôépøGÁAÂ}eÎ`Æ¥>ñŸ(¹nG¦°°“'ÏAƒíÝÍ›wņ ¹A×Ç)2öÜÜ=èÞ}0ªVGåÊÍÐË—è´ŠBÈÍ݃–-cŽ‹‡Fee½¾±oÞ¼÷ÜÓQQqhÖ¬ >þø_¶tåѧ¼ÃõrÊž;vì‡éÓÄCBBBB‚ (¹yÀ’Ê5píT›:QžÛȺd€ÊÚ™9ÓN…ÂÚ½õµàFwàuÏyuc8”ì54))ž IDATì‚C$(B ÇÀeCvœhkˆ™/¶€Ÿ¿K;ïvI%ê™3‚ U=iúg‡Æ }úŒÀœ9+PPP(((Dfærôé3"à1Ø‘ÅC“‘‘M›¶ãƒæá÷ß÷cÁ‚)?þ|õÕaÇõq N½cÇ~¸pá6nÌÆÙ³û°bÅ ¬Xñ!Þx£ô*Oš4£¦±BY\/Àzì‡CRR:fÍz þy3gŽÅsϽŒ£GO8®sy…›ëÅKÃ7ß|3g.öé$!!!!á Tïu„´6ÏO,ìboÖ X·[ÕPT'˧q7ÝÈ7ÐZ &GÕß½ém‘ŠNÊö¶ÒGU¡P.º§fh&M’U‘?ÆøESÓ-aŽ‚ƒda*¹å(SIØõ§\?B {L^JzŸ"rXöDoÒÂ(?ç–-›Ž * [·$@·nIˆˆˆÀ²eÓKEÍ’%ï#;{2š7oŒJ•¢ÑªÕ½ÈÊš„9sV8®Spjì£F ÂŽï¢mÛ–ˆŽŽB\\,^<™™Ë×™;w®ÂCµ ˜Æ eq½ë±gf.GZÚ`tèÐQQ‘èØ± RSböìeŽë\^áæzñÒð !¡j×®O>ù4`^% 8™ž&¾ €%MPÁv\,¯«·Ð›î0[T #uÝJ&±€¡o0*5Az¬( ;¢¹€¦–—¾Ÿ·/±+…/#ÃÀî‘‹kéPu´Âz½DwϽ}|GïÊü`;ûA´Ÿž^¸ø`YJå5¤xàcðà±8P¿ƒ–””ŽÁƒÇ ˲¢9sæWÜ}w¬îÙ=÷ÜÏ?ÿ·°ÞNŒýoëŽmÛvéžíÙ³M›v–eE“‘‘nz…ÂÂ"a½ý2¤­ËVy°{÷WèÜùAݳ.]Ä®]{…y¹iÏbzÙ·±P[/§ñÔS`ãÆÀŽBIHHHHøA=:,‚\í%mŠþ³€pv›ãþfά‘~¬¢zT†Z¾Nk ϵywœÖŸÁ܆MÑêý‹7íÙM„Úz96m°wï×¥ªƒ„„„Dy€ªªP)Ç4T,*ßóUP©¹Ðžvª~þôo½§êšÌáÉÃfð×4ñÜ> Ûi..Ö<·.2èÏ®·šo£#nØÅöí"ú©ž±Ò Òxjž›¢ÐÑæÇ»³ÍÈxФî³2tÞÂŽŽ¿ùöŠbr@¥d^°˜³Ž»P‹/04YÆÜ>B ™eâ²1êÃMÚ#쪂±[.£êÍ‘ø#w ¦MKCË–L}¥¾­3ÿгç0¼üò ÄÇ7Åùó‘—÷ÒÒÞBfæôèÑ›Fè ?ÿü_tèð,²²&!9ùUäå­@ÍšwØ–E£ÉÈX€s1oÞ¨_¿¾ùæ{Œ1{÷Baá÷¶tdì—.]A:mpäÈVÜygu¨ªŠ˜˜Öøä“刋k`K¯>6äbäÈIØ·ï#Ü~û­¶ôtÝEø¸)‹·l•‡&<¼! Ž!,, ‰‰=†Ý»× "¢ŠŠŽóJPDí9Øú¡µ^¢4Vøí·s¸ûîöøãñ‘(«˜6e1ªU«n«o÷ǟħ -mÎÔêàôÖ  5ëÛDªç°Dƒ¿JãíÏÐöW½¦Ÿ£w„Œòi<ôýµšhy‘ƒ´¹Ô>gÒ‚úqk%šØmÇ×'K¥Ì?K _"MÉ3:_}@Æo =-ìÊ?7™ó®‚|¥%Ý6¼zõb¾/Å2Öø(A3V¼@õ¼t R¶ÀçÙCP¥bû·y¨Àîéæ¿.ü_ׯŸëû¹zõÛѧϣ¨Ví6Œ1ÑçôóЈ"Ð/¸µjÝììÉh×®/vìx—úÅW楗ž‡ªªèÙsNŸþ Þ…qãR0hÐÛº2ö›o®„Þ½»bÑ¢uxõÕ°gÏ~T­Z…êD2v-6nÌEròXlÛ¶T8(à”­–ÊŠ­ò :: ×®å£R¥h|ñÅzÀåËWP©R”mžnÚ3 NÚX(­—Ó¨R¥2.^¼TÚjHHHH”SxEÑ]GNS±Y»OqÖ©q²\ÅÇÇjl´rÅã(2j5(ŠÅÔzö[!Ì™C·!˜E2=SVG´¹°˜[ ª&¢(Š.èÁì(êÜkèuz Ðhü¸Û˜KªBQ;A[:Ðyy®+d¨x¾ljoä¶#ãMéóvh‚}û¡V­;„oAxx8ÒÒãØ±\\½z‡mAÕWzgå““ŸÆÂ…kP\\Œuë¶=ízÍš$%¥cóæ…hÑ"N¸0mµ¬À [åA:5qêÔݳS§Î N𥤑3öì´…Êz9óç/¢rå›K[ ‰rï°÷ç HÐ9”†]e£3Ç Ï[z†ÿÒÚI¿zôæ¹uOôXºî B"_•‘šïïhJ£÷¦®ÓnËÛ(G 5Ì… úé˜ådoæ`Œõ‘þ#îŠï¦’Þ¼«Mš;;øDv&þZ ŒLjº[¶^UÂHÝÄ¡Cß¡nÝZÓû÷ƒ¥K×ãàÁÍX²ä}[5ìbîÜ•èÕ«‹kòŒˆo‚êÕoÇ–-;±~ýVôîÝ5h²,xƒƦM Ð,hrÊ3JÓVhÓ&ÁTìoË–xàûJI#w홡´^NãäÉŸp×]¥÷¹-!!!Q^Á¼ná,Õ ,·ÔÉÐU{gm~"Zr<=Y‡_М=«HD0<%úhžð9¢úy07fô¤:ྡྷ‚âzP‚)΃í0‹ô¡7Ùµ1»Ù â}ÂŒ‚èÒe¶mÛ… .áâÅËÈÍ݃Òž>DˆÆM\ºt}ûŽDvödT­ZYY“Ñ·ïH\ºtÅqY?>GŽGAA!NúRR&à»ïNbذg—%‚ää>>|"n»íV4jT/(2¦NͰaã°jÕ,$&ÆEFy‡›¶Êƒ””~˜:5 yyŸ!?ÿ:rs÷`ÆŒ…HIé_*úxá†=ó ÔÖËi|úéW¸ï¾¥­†„„„D¹ªŠÕÐ5ñ8Þ -(` :Xe 躲2 4ü™ºÚMµ.á­ÛôsT“o¯+BÈ*̨IË'ê¤K{§ÑˆÀJ2X×ô Ý`^xO?+Õ—-a#­Ã"ÝžšUÁawd=è²ÄšÈiºÂŒNé@Ü$LÇ€ë3Ã~JvRRoŒÿffl uë¶Å„ ÿÀÌ™cñüóOѸ‰¡C_C|Îêý÷ÇãÑGưaã—õÌ3¡gÏa¸é¦¦xøágP±bvìX…¨¨HÇe‰à©§Á￟ jæBzú4áÑGAQêëþýöÛ9[<=>à•oüY”Æ-¸i«€õØ›5k„E‹ÞÂðápË-Íñâ‹o`éÒ 4ib¯ÐŸSpÒž±±P[/^^¬^½ ݻ۫ #!!!!á‡? ä ›€ù«Î™3:g^PÓ‡µ LÞy68ت@Š8eî<óaj3ßl ïã×ÓR0‘Я·Åœk+ÿ—Èe'°¼¥€êˆ{tQhÞ³! d'ð:ï`Û‰'DZª~¾y$¹°Zò ¢N¹Âj¤À"3HH>›ŸîV‚öqí¡\Sðê–˨zsEüžû&õV‰EEEˆ‰iƒíÛW¢qãÒs|%$œ€´çàcïÞ¯ñØcCðÓO»ÁUãVBBB¢ÜÁ©[ þSóI6±…S/ e%è®K¤ìˆª¬mYBU}Vñ9½Îúv­/Ç ˜øë"“Ÿ{%Q+â—ȦéMé«m§n «Åt¹eõ7#V)ÙÖ·*“ù2ú±“WTЫõ“oXð¯%=[€ž1ÃÐM;-3(@ZWïOâ·X9ùäq±ú0t”¯½• ÌÜIBÂUU1þ*Ô®]C:QeÒžÝÁ˜1ÓñÒKÏË €„„„D0Á*>æ%áÙ•f9œF§…–)`ÁŸîÏY¥J³Û-Ï€s¤ù3eÛp´oÖ„içÚ[dŸÓß9F`Qw‚^k@ßOßdÓ/䨅gt¶u„À_&ˆ±Ð¢E6Ÿÿ¹óA¾cq4[€¥›†om¥P}P"¤ÖuëÖºu™¥­Š„DÀöìrsW”¶ 7<¸‚„^ÚvÕðˆH«PdÒÏ©çSÈÂgñÕJ0㋘£in÷:tæ òs^ð;ƒ$=õÓÒëøsðôñ%ðâõ(½Î+Q/Jt)9ø`¶ C!Bÿ’+üH‚uvd]w;Éû,سa~ŸkMh ¦^ü]`À³H28 áÇtÍŸDù‡´g ‰r@j PSçUs;ÑÓ<äÜÝ%¦vÛ*¸æuø¬²h|Ø·n÷ÜH­9óO™AG¢N¼^¥ˆ÷ivútã­¢;Ï©ŠÅšèÀêÇ ~û‘œy…•b‘E@†0ºYè'¤ƒ­L ÞÌÏÏú£¥~HHHHHHHHHHH B&¥ í^RåY䦂~VÎ mW”CŸ.ºÙI ˆh´¼u 5"uéá”â}ä¢z hG$ôÅU(Ôã äímÅ7Ï=­$óZBE?v}GCÂb |¬Õw5¡3Å)Ðe4˜­:—È6'Û9¬§wÞ‹…úzú[*D¡åXÇŽ^ð€¾Žô!ÒvðÉõ¤Çb1‡Z0ª&Zc}lÅGíŸÿܘ˜;‘ÐÌyŽ+!¡j×®O>ùÔ6ÌÌåHKŒZ#**;¶Ajê@Ìž½ÌG3jÔ ìØñ.Ú¶m‰èè(ÄÅ5ÀâÅS‘™¹< ýíê œ:u:´FXXÈÆ­l¡¼ŽË N¼ËN¼_eªªzþñ<,,UU¡›ïe÷tåpHT M4ò5 Tãñb¶x#[éÜGÑ—¥n×!×ÜÛæk+eì6•VŒÏñTv†»ð«ãA«ã¢óI9Åàh~Ÿ|z0Ai§Î=‹EÖÜ–¬ ·‡Â›’®(õqöìïèÓgªVGµj ˜5k‰¯}É’÷Q¿þC¨X±5ê€%KÞ'òÙ¸1O>Ù*ãÉ'‡ã¶ÛþŠñãßAçÎpÛmÅÒ¥ëut›6å¡uë'ÙÕª%`À€4œ;w^h\ŠR»víÅ<…›nºÕª%àÉ'‡ãìÙßM´O=õ6nÌeÎV¦»w…ÎÔ=ëÒåAìÚµ×÷{FFº)ª…ÂÂ"K¹ÁЧE‹n˜1c!~ýõ¶åõ(**ò¥Û—öî·•=óò°­~ôÑ'HH訨8Üu×X¼xQŽögÒüÍœ¹õêyÞÁzõ¢Ž‡5ö³gǰaãP¯ÞC¨T©)ªTiNž#5±z——-û ´Cddc4nÜÑt4Æ Þ÷KBBBBB¢|AÐIå(¨ê¼rÝ·ÎdÀÁŸo·_˜7ÍÁôza¼…}pAñö*âgèO¥1ë¤M¥g%u(”œwOÁôu/4Õý·°æÎ ™§ñ1×qUµØÙ¦e5hä”üÏOϰâÙT·>¦C‡lÞ½@‘c îÀ€H:úóÏ¿‚îÝ;à‡vâðáqüø¾¶·ÞšåËgàܹcÙ² Lš…œœ&ûöBÛ¶-©2 è…5kþ þáÃûãƒæaêÔ,ͬYK0qâHüùçA|ûí'¨R¥2† yMx\#GN¤I/áìÙ½8x0+F`Ĉ‰&º6m°wï×L^,œ>ý bckZ·~mÛ>‰zõbpúô/Ì~³g/ÃSO=¢{V³æýˆŒlŒØØÑ«× 8pàHPô0 ݂֮ڵ[£sçXµj#®\¹*, Я…Ý#´ú XöÌžqYÙê¦My1b"¦L…ß~Û­[—à³ÏËY¹ò#dg¿‡wß}çÎý+WÎÄܹ+ñÞ{›…ÆÞ«× ¸ë®Úøì³u¸páNœØää>Ä:Vïò”)s±lÙtüñÇ,]: S¦ÌÅÖ­»Lt¾_åN©Ê óïä Ñ €E;ó~º2¨r8n°ÓfÙn·Msƒ&_ðp>O¼‚VãÁ^ðˆæ¨³º9œòo«à e£%”‰ËƨǵGØ5ãr.âÖÊ‘ø-÷-L›–†–-™;(õ™Îš¢ÔÇâÅS1`@/bÛÖ­KЩÓ¾gÿüçnLœ8Ÿ~ºVG[µjío¿ÃÝw·Ç0²áBxxCCXX{"<< »w¯ADD#'öÙ°!#GN¾}ùæªgÏaxùåAˆoŠóç/"/ï3¤¥½…ÌÌ èÑ£CPô9yò4Þ{oV¯Þ„Ó§AÏžñì³ãá‡ïž+s,{¶Ã‹w\F[ý¿ÿë…W^µ~,9÷Ý÷8&ONEÇŽm|϶nÝ…×_Ÿ…/¿üÀć6ö*UZàóÏ×£I“–úX½Ë¤Ï„É“çâ_ÿZ­£ ôý’pÓ¦,FµjÕmõíþø“øáÔ¤¥MÃé;Ÿ`óîP{3è ÆýL ¼Uµ÷M¥“jÓ¸ GTcC>Ãqóû`ä£~Œß4ýhsL|®–è¦jõ4*G鯪¦çþÍúþýusi4bÏ«“¹U÷_Õ¼x}¬ÇoÒÁ×F42V÷Í6`‘ PÞ-æûÆ:v`\ŸPå AJÖëó…/ (ZÅö£y¨àïàME <üÖ¹óÔ¶ÄÄxÝï­ZÝK,fwñâeT©R™Ê'**ÒôóÕ«×|ÏÎ;ñãßÁæÍÛñË/gqíZ>{•7ãã›ê~¿ãŽ¿àÿûÃDW¥Je\¼xI˜¿ÑÑQ¸v-•*Eã‹/<Ç"._¾‚J•¢ˆô7æ"9y,¶m[ªsºÖ¯Ÿëû¹zõÛѧϣ¨Ví6Œ1Q(0 ¢Oýúu0vì ;ö¬Zµ/¼ð:–.]2~ `Ù³à±Õƒ¿ÅÐwÝyqüøº $&Þ‹ï¿?E¤§=5u þú×Gqß}-ßõêÕAbâ½hÕê^­Õ»LúL8rä{] ï—„„„„„Ä ë£\• ìËÖ(D =©ßzÕÞj~X]›9ݸlðÕ·W m _íªnœõ-`\mK¯ÚÜ_¡(ø`·/ËFY ¢ò‚õ¶ýQÅ™´œ;†…™õÊ•oÂùómëпÿ˸pá6o^ˆsçþ U=‰‹Û2²ˆˆ \tçÏ_DåÊ7 ó÷¢Nš8uêŒîÙ©SgP§NMíš59HJJÇæÍ Ñ¢Eœ%ïÄÄxœ8ñSÐô9qâ'Lš4M›vBròXôèѹ¹+„ä9`%µgQ8i«Nƒ6öqãRðí·ÿÄ AO¢jÕ*ÈËû íÚõEjê­w¹˜píP ï—„„„„„D¹ÏyvU…Z̦ӹ{œÙÂzàjX˶Ï}ƒ€—@Mï’n )žÀÓ×ß “z “ÐÔ ·3è~Ó×s°¡ ¥Ÿýk1sÆœNJ£Ý¢‡”À ÑF¸dg Áçñ:ˆÏ?ÿ·nrïޯѴéÝ&ºØØÚ8yò'bú1vîü§OŠ[o½Å÷lûöÏlñâÅÉ“?á®»jÙîߦM¶mÛ…¦MúžmÙ²*TGaa*T7µ5lxöîýZw”àË/âî»c…õŽAllŒï÷ï¾;‰„„Ç0cÆû]&}&Ž(ú~IHHHHH”ðÔuؤÁ=H;ÔúŒvŽ €^°IFg6o/+hõï)àhèæßÍtŸV5d ðAÛÇhàÚ Ò(JùƯ£MŒoF?ßѨ“Kæ©…bŠMxû{à ªPPÀÏÏfŒ–Í!žpÁ!‡Œ0À?ÎU>¤cĈ‰øì³¸|ù öîý#F¼ôô!&º–-›ãÓO¿²-'>¾)Þ~{1þüóþüó֯ߊ‘#'¢º%>ýô+Sš6 ´Ýë””~˜:5 yyŸ!?ÿ:rs÷`ÆŒ…HIé:5 ÆêU³L)Ø^té2Û¶íÂ… —pñâeäæîÁ€iÄyTŸ+>ÂSO=‚ÿüçSlÛ¶}ûö(µ @i"Œ[=z(†Ÿ€þs7.]º‚ï¿?…¡C_#ò‹Áúõ[QTd¾©"%¥†Ÿˆ/¿<ˆË—¯à‹/þ#ÞÀˆÏ éܺõXºt=NŸþ……Eøÿï,V®Ü€-›h­ÞeÒgÂ+¯$›èxß/ ‰Þë ÿöÎ;¾ª"ýÿŸ’€ü0*= 0"ÂEúYAJta©ÂnDâJ/¾¢tP‚K‘âRE!)A%°‚Ö]E,ôP’ÜóûãÞsï)ÓNI!Λ×%¹gfžyÎÌÜ›ó<óÌŒˆS€)À+%d}~ô#+NZy‹pOä³‰Ðæ†œ]îÙÇš `1ìÜ,½‚ÀÉÄDÎr*v#,Ü.ÖGîcºã…­†!‚CñÉŠ0<Ú÷VghÇŒ¾}Gà»ï~DU1nÜ‹èС•)_BB<&MZ€#ú[’¯òÖ[s1lØÔ¬Ù·nÝF£F±HKKA‹=ˆ÷a|ogæyíÚ­˜B¦Zˆ¡âôtý[’)ªó*˜îSû–¾Áž¿^Šþúf¤‡ºÓ—ž+P4ŽÅF—4€u÷ap€ssúXcˆ+ G…ñdSšG{RI_ƒž„4]yV—¬ðìq /­­ø>ÕiGÛ€*”u¾ý IDAT]{_6„±ÿÑ›/Áìý"Ó·”À-’›„……bøðDŒ7»°UbüøŒñ¼4Z$n|–åçK"‘H$¿o8Ƹ¢øg›-:´å¹8t (ƒßTÞæ ¯Hº×kvVñ­ÿÏÆ¡G—¦¹.¸Ù my{#;£\Òe¿qIm ZCñô´;³oíþ…ãf=XeÜ<4yœz8c¿H?e5£F™Cæ‹"…±¿Dr·àô³,?_‰D"ùÝ"´Aa–\3ÃÀ¼tÛ4ñÌs*pŒA(‚S€T§I†bVÃxõ“EÛ ÿÖ–qløÐ…²Ûì?¡²¬vFظù¸G]Az½Ú͉K0|÷bÚ8§À€°„"оÌÖFŒfgK°¿‚Éúvï'󱑬r¤°rö lšS€‚О#Æã %‰¤¹O‘H$‰¤0ÑœÃ"0™Ës è²ëŠ@À)`³°;x@n'Mƒ²f¡‰)„¶Õ‰àî•@©‹²Ñ^pò¯/U¶©Qü÷â±ZVál|È«ÓÊuzZð8HÃu›Ûó{;MZt 0q;ò@O(`uwI‰D"‘H$‰DR×ésguÓµ”$ž±¯Î•ŠG t ¾Ñþ ”·úÌ›)¥Ú~¢å)"Y1¤ ýL8 z»‰ÎΣˆŽ ºNÁ™q½S€$ÓòF„¬YxEaÜ'#€9ÖØÉö£:hehò¬‹³-`nk1 ‘H$‰D"‘Ü ˜CèÐfÀÕPq†±®hteØõÂÎÉåõ2L‘ì øõ‹„.:hû˜äÒt2Ãæ µ­¼%týe?R@‹ñ’þ½‡_q¿n|$ ÇV{+ðöZ`Ž †8M¿ëïÛy;ªè¾F‰D"‘H$‰¤H™‰ˆD:íb.Ýí|ãNø¦ì"ŠPæƒEŒ‘BÆ=µZ±z©†¦X->‚Æ»P>ŽÎt þe}îÄ®a·.­OK·#ÓN1ñr¦ˆ¢´ª`öìeˆïWØj¸Ffæ‡hÜøx<1ŽäÄÇ÷CJÊ2f=]º DTTC”)Sqq X½ú]Ëy´È¾ Ãë '†ø¢QÜÚÙ-xí ˆõ©[ý.‘H$I"´tÀŸÎ‹`ÈPŒ†‹½¾<-/šª˜¾~'ËTnÃÛ,OrOH³Ý ÷,:áïuw>Íš{F_ù„0õ!;&(uÒU¥–9Õ ¸ÞŸ"NÑæ<ÍÙ.¬>&EЋÐ¹æreúã óãC`“œœ\Ì›·3fŒ.lU\cêÔE˜={œc93fŒÆÜ¹+““KLW¯##c).^<Šôô9HOS¦¤ZÊ£"û‚¯/@QΚ^$Šc;»…H;‹ô©[ý.‘H$I!ºÎž·yžp¤€^lðàL=ñ’öºƒHp6ªscO³ÄüMôÆ»ð> 6ŒCBKu‘6äFØqŒ Ð7ÖïØ_ŽæŸ ¨Cs6œ–—˜8t ø´ì‚Ÿƒ$óEÄ7°{÷AT­Z qqõ [ר¿ Z·~±œ¸¸úˆŽ®ˆ={ÓG€}ûþ…-#22õêÕŠ3‘šºÚRÙtx}a…âØÎn!ÒÎ"}êV¿K$‰DRøh§9ųš“(ð²3ñÄS ‘à%uë9ç!ôL‚m§€f6_(b¬›íÑ”æX†¢w ˆÈ"ee„_k ºµGšå¸lÝ,:>hi&Í„óÊÆ5Òƒ:qŒjŠ“sÚ,·½Ù{Ö>„ö1îö‡mgšÃ¥!f!Î>\11Õ0aÂK8}z'/žŠÍ›÷ mÛç,˹víÊ–-ãH—*U*`éÒihÓæ9,]: •+W°-KtWù‚¢lÙ2¸ví:7_FF&’’&àÝwÿ‰ûï¿×V§}qÏ=¥Ð½ûÓX¾|#_x{TTYÔ«WË’cû•þ`õŦMo I“†/‰òåïG¯^±rå,Œ?Û”·8¶³›ŸAÑ1/‘H$Iñ„c´…Ô È`äÑ9 ˜Ç ò ›`ºÙ~&—×E P–I˜àmÈh¼& §™N5‹†YPokë÷³È>Šq+¸C¿)VŽ;–ɳ÷Ü¥~uèGÒÚ–ÕæŒ¾vñ’:]l9ÝOCÄ€—|ž§ÀR•3gÎaêÔEˆ} IIЙ™é …È”)SW®\³\ÎÈÑ£Ÿ¢J• 8vì”#9"»Ê$W®\C™2÷0ó¬_¿ýû'cÛ¶7Ñ A=ÛyÜ苤¤ÞxóÍõðz½Ø¸q‡­ðvcû•þé -Mš4Ä™3çL׋k;»õ´ÚΉD"‘f1wôw’¬«‹é°"Ì¢›rOÈDïßõk¼“)¸Ë÷ÛSÀaå¨Ã`¶SÀF"‹NüÂ…q*Vß HIY†uë¶áĉ/жmSŒ?Ï>û'”*iK±5¢qöì9ê,·ÿþ÷i¬Zµ 'NlC«V½ÐªÕhÔ(Ö¶¼¢ÄÙ³çP½zjú²eë0rätìÞFÝå^$àN_4lø0Ê—¿;vìǦM;±wï[¶e5x}aäÓO¿ÄƒšóÇvvó3hµ%‰D")ö¸á0øùøNc€ñ²5=ÅŽ7„~)k†ÚBÝÌt 3·6;Ïtb¸gØMêq#LÌøäð4ŒDîÉvÚ5sO¯Ž7ãO[ÐhJ9jÛ1Õ±vïºE qíT‚ôôÍèÙ³¾ûîvíZ…>}l; qãGqèÐ1Ûå¯_ÏFŸ>ñté4DE•Å’%ÓЧÏp\¿žm[fQâСcxüñÄ´™3—`ðà‰X³f>š4ih;ŠÓ¾PIJê…!C&ã¾ûîE:5Ë+*°ú¢C‡DìÚuW¯^ǵk7™ù!Ç 9y)oqkg·?ƒ¬v–H$‰äwG8´û°¢Ä–ØSOS‘XÒò–ñd¸ÎoVClZ¨·Ö9A“Éj;α‚4F9®Aé±¢8:šÐ¢S@Ÿæ$JÔ:mG ؽwZ÷ðúÖLˆO˜'ÏnWž<¹£F @¥JåmJГõë·Û.ÿ⋯ !¡]Àè}òɆèܹ žèŠ~v ­Û¶ËÚµ[Ñ¥K;bZrò,äææ¡sç¦e¿ürI8ŠÓ¾PéÙ³~ýõºuëàX–ÓåÕýûwÇk¯-@ÅŠOàÁ[`Ò¤˜;wžþ/¦¼Å­Ýþ ²ÚëS7û]"‘H$’BCd=¸M§€vÀ,¡úœ ±Àãò¹îuª†¿H{Ó.:k?¶1..Û£ûa2£ØÑV»È‘£ 6¯‡½ ¡®Ï=fOC7–Lz’-§€Æ¹cÞ÷@Å_Ö¼”ÀéçÚ%âã›cÀ€ñ8vì3ÌFzúÓµY³’ÝPÍ6n­…ÏÊ:‰~¸ˆøøæ¶ë±¢‹Ó¾P‰ˆGéÒ¥ŠÄiÕݺu6Ћ[;»ùäµ3àþ¸—H$‰¤( {42¬œ9‚¿³CÅÅö E¨I¼Y^M´‚]§@¾/`ß?[;ŒÝ.Ï\{<ݦ“Äe 6–,â)\Ô7¨+K¤o?¢Z6ð ÔÅ*g¸l^Bª‹–$â°³†kK Ü&,,Ç'bÜ8óîí¿wÆOÁˆÏ#,Lh‹ǸÑŠ¢`ñâ5ˆŽ®ˆºu‹Ï,­›}!Û™NAy‰D"‘HŠ™|óK“É‚ó1‡A¼|^>zš˜A¤ÍÏvb ž< ²è^Ö Éš·†t;!┼ÚcÎw®AI9Í­Ù8§Š'žN@KtQ ;Õ`Í!Œ`•³¡ÓÙÆ´5nÙeBíêRŒ5£F (l5ŠvNypŠÓ¾ ©…¬‚S]Ôªðq»/d;“)Œ1/‘H$I‘3cÎ7ÔM™ò9¬Ç‰ÆtZv¦¥šß:zÔÍiC'Î G»áçS¡¬1®+M;s¯åQÓÖ4[4´É™È¿êføE ^Ž ÜéÕ_ÕðlB>ÖÖîjD„@” ÑÝâNóîýùc|l’®×Cþ®ÓY¡F_ê ×ÎRŒ£9µ 'U§ïù>íèj×€g'S—2ØZBŒP¡-ñà¡_J`q×I‰D"‘H$‰D’xõƲ>ôß©S@1ü þª·?,:héVDRÔBÀê#åWÛCÌ𶺄BdOŽ<öð°êiw¿hjVí&|Æ%¼ ü¸hdëj&G°Òú0›˜QÎÁZíh«El|†xò4øN%ΉD"‘H$‰ä®AQ¼~'k¢“gDè§ÞÉû|ƒ–]Pt»È~ÜÙ^kF“ÞØ žÒÆ–omÖ\¿6=?fÖ!tïtsÏIÏ`¦§AñÚô)ð#´xè›<ô±£ «í˜ìF4°êCîä%‘H$‰D"‘Ü5ôõ“ß6gøÒûÆ!÷˜AÖÆ‚†$ªS@1ë©ÓúùK°,6Œ¯ÀeÎÒG“îNþ² Þc4…&-ž¯øß[{¬²Ⱥ–D“·¢8㇮ «œs§@°^‘v«Ì¼„‚&1 ËÀâäÜo«egÏ^†øø~¶ë³‚ÓóÌããû!%e™c=¶m{<ÒõP¿~¼÷ÞºôÌÌÑ¥Ë@DE5D™2õ—€Õ«ß5ɹråFŽœŽ5Z!<¼.bcŸÂæÍ{\×GâcÇŽý¨Y³5BBj9KE‰7ß\*Uš¢D‰ÚÔ<´û-¬v(Èï( m[²ÚU¤ÍyyDë’Ø§D‰Ú¨R¥)–/ßàŠ<·úÉ-9¼ç‚c¼ºÜzÞÜ­XŽ ;Ÿ >Ü v Ä}¸ÑÍŽ,kN²Óh ž|v²SÓ0SŽ]çûËÈíŽ=?¶â´1Î|å¬òÀã¯K_–u ƒ¡R³LÀtýsZ'½ÐÈÉÉży+0cÆèÂVEˆ3FcîÜÈÉɵ-ãÔ©¯Ð¿2æÏ—/ŸÀܹð·¿ÆçŸŸ ä‰ï‡«W¯##c).^<Šôô9HOS¦w¡¿uë6Z·îÛ·ï`ïÞ·píÚ)¬]û¬X±Ñu}$>†Œ%K¦"7÷ëbµàĉó±|ùë¸sçËÂVå®D©dzõŠE‹Òß—99¹HM]^½†ZÊSÜ)JãçÎ/±dÉTLœ8¿°Uqßãó†änDÀòÚá"ÇtÉ˯\ŠÀÑ…’Ø?Á-@’EÙlO1¥ÓTД%5 A¾>jAd¦ž3«l×öbl4¬›Zc]<{m Ô™{Q³€\:vÛ‘5æEÆ7­«ß-ÊãÁm7÷ä…XYPFÏîÝQµj%ÄÅÕ/úœÞW\\}DGWÄž=‡lËHM]1c¢]»fˆˆG||sŒù.L ä5jöíûZ´hŒÈÈÔ«W +VÌDjêê@žE‹Ò[©©¯¡fͪ(Y2 >ZK]×GâãÛo¿G»vÍÂÏ|qáÂψo†%J¶*’bDZZ BCCѱc@ÇŽý†´´Ky$G‰%о}+\¸ð³+òÜz–pCNA?o8Åç ÉÝ…º'/ƒ`’}kU·Q¡-{Ec¤«xŒÆ¸¶2'†±°Vòë·âˆ±U‰ý2´HGíf7ZÀšnmfÞn± D ãŠF™ÚŸ¤4«°ûŠ|€ Eÿ[a+Æã‰ ¼xù.^ü½z ETTC”+‡ùóWÒW®|11­Q²dÔ©Ó+W¾M”“‘‘‰=:RëèÑc^{íhß>÷Ý׫VmÒåÛºu/š5û ÂÃë¢\¹8$&ŽÁ¥KW,ݗǃ²Ð²eO”.ýÊ•‹CCpñ⯦¼={vBFF&³}´u9xðÚ·o¥»Ö¡C+8x?{v²éÜܼÀûM›vâÅûpõpCŸ :bΜ7?,Šô©Çƒ´´wP«Ö^uëÆ—Q$jÛååå–Xåsk<çGû(ŠâšS`åʷѲeOËc%6ö)9rBwíÈ‘xä‘ö®èÅ®ÎÚqÀúŽ™;w9jÖô}Ö¬ÙZ÷])ÊÅ‹¿bðà‰¨Y³5J•ŠEÙ² ðÔSs´ì§ fªÍ;›ÿ‚‰äq'÷îÖX-ªã'4´¼^Ö:Y>"Ï"÷åæßnÖóFQEôyCR\ð)úÓ|Èwe—rŽ¡MÌkV…¹‰›ˆ¾§€XFÞU’*Œ{¼1KÓo$XXˆD*ðÊ»Kà4ê5לHæ ½_¦ñùÁQå‡!O+ŠàC?Þ”Œ°c@QÎ {æŸ~,ºti‡ÿüg?Nzß|óß@Úë¯/ÆêÕspéÒ'HK›™3—`ûö}&G~Š-SëHLì†õë`Ò¤2ä¯xçbæÌ%º<óç¯ÄäÉÃqùò |ñÅ”-[ƒ½bù¾†ŸŠ©SGàâÅ,œ8±%K†aèÐɦ|Í›Ç!+ë$S‹óç@Ñ€fÍþ‚-z fͪ8þf¹… Óгg§ÀûÏ??ƒ‹Å£>ÈȇQ·n<æÍ[aùNDŸÄÄnذa¢£›¡}ûD¬Y“ìì›–êÑÊâõéôéo --¿ýv«VÍÂôéo`çΖêÑ>P’^VÐŽõw;3Xng7ÚGåÖ­Û uîPÉɳ°oßÇØ³g5*V,g©|°aÃݵõë·£{÷ü{wª³È¸xë­ÍXºtþõ¯y¸té¼õÖ\¼ñÆ[X·n›¥ººu{ Õ«Gãðá¸zõSœ9³II½ } ²ö~÷Þ¯ßHܹsÛ·/lß¾·oßA¿~#-å©« qk¬åñZ·nݶT‡Þw¤è}¹ù·›÷¼¡ÖGú=?©Ëéó†äî&pd!Eñ’gÔƒ¹Á5¬,;T=´v Ç€a8ˆË<Á4“…ü<«èâ诘/éäÓF9£¼£åùv¢$ü•³" åõÙx÷Ìë{ª·ˆ³,sO”dæš}†®¾r¬öÕ8´-¤)b6ÆÙ÷ÏÔÓòÞc·§grÚx¥íÃmá¹éÁk[AT™üôþ\Ìš5×1ðÄ0ÿ(z<1X±b&»Óvî\‰§žj¸¶{÷ALž¼‡é74ŠŠjˆ3göáþûï%ʹyós@däÃßﻯ²³?£êvõêuT­Ú W®˜ÿ˜ÒîËã‰Á‘#ïàñÇ®ýôÓ/¨_¿.^<ªËûË/—ðÐCmñÛoÇ©:°(Q¢6rr¾BHHš4éŠ%Bpðàz„…ÕA^Þ7Ä2[¶dbøð©8zts ­J”¨ÆÅüùÿ‡G­‹³gÏ#)iºwïˆaÃóEŸ³gÏcݺ­X»v+Οÿ]»¶G߾ϢM›'…êéSÚø™6í |ðÁZáûÊxŸ ^Y7Ƴ›í“““‹Õ«ßÁœ9Ëñù绸úÓ>;7nœÆsÏÀã7@rò K:¨|ùåYüéOŹs»¬V«Ö™™é¨S§¦°>"¸¥³ˆ.?þ,¦M‰øøæk;wÀ«¯ÎÇ‘#ï×Q¶l|ôÑ&<üp-GºjqÒ†ùQWQÓ‡†Õ±êD—Â??üFŽì~ýþŒ°0ûÑîÍê}¹ñ·›õ¼QTqú¼!)fM_råÊÛ*ÛåÙøÏ·Ç1fÌ,œ‰êDÈÁ0nDgµuN1¨kýùùòè¬Q¢S€¡+w“?YSZõ(N53ÿ¸D³¼“xz+%Y}@—¥èeë§õæbº¦,Q„¦ÏȺéMÁ«g•—w¯äå7ܽ/àåÞ‡¾&rßêO»3ÔM+¶ö ôo súGˇÂ¡`ï{óç¸Âöí[RÓš4i¨{ÿÄ7³»víÊ–-C•núýæÍ[k—.]Ák¯ýÛ¶½~¸˜á°ŠÚ°a¬î}… àçŸ3å+[¶ ®]»nY¾JddnݺR¥"ññǾ0ò7²QªT1FF&’’&`×®Uºšˆˆp,\ø*7~P¿~,^<Ý»¿lÉ1`EŸ˜˜j˜0á%L˜ðÖ¬ÉÀK/½ŠU«6YzÀæõ)@?Ÿ}öµpE·Æ³[íS²dx<lÚô†å²ZÚµë‹_~¹„'žx̶ŒºucU}ô š6m„Çã¾ûîµeh‰à†Î"|óÍuF 4iò¾þú[KrFŽ|uÆã7@Æ£fÍjhÒä1Ëú£e´ïóÓ(‘ßN·î½ ÇjaŸ3FãÙgá…ÆåK¿¸u_€øßnÞóFQÄéó†än†o„“fµMáÙ  =BOQ;ÞÃh›¸ë0ÁzDwÉ)@¿$i@UÀrõ–lCò1uþ÷´pÿüºoN¤ Ë Ã,Ê1ÄŒmkG(’“ŒG:ŠÔÕëæfƒÊê—¸´~³R%kÞÑs½eʔƕ+×lëð×¿ŽÆÕ«×±mÛ›¸té(ÊY\»vJà‹ÃŒè¬È•+×P¦Ì=–å«T«Vß~û½îÚ·ß~jÕ*›ò®_¿ýû'cÛ¶7Ñ A=]ZttEÄÆê—«]»:wI‚}Μ9‡©S!6ö)$%M@BB;df¦[ªÏ.^¯µ>us)AAád<[m¸}ûK,X0¯¿¾ØŽº¦O}ûÖ 5uµ­ã2Uºwë×ûB‰×¯ß–¯ëÝÒ¹ ˜8ñe|ñÅn ÐQQe±wïaüñ}0rätKrŒ!ëN–ÆÜm¸yï9VÝÀêø™6m,˜ˆÛ·‹þI%¢»>oNŸ7$w+"Æ/}f3ðOñú_ú‰Ií{ó„%aöžk 3f¢û%ÐÒx¡ùBCQpùÝPÕÎú*†$§°oOtéeù[?vc¥Ûr (Ð:¬ˆÉÔâúDY+´VŸâøbD‘xÖfƒvÚVlíåC¯Ï0îA_&T½äÏ;“ß[;}ôÑ'ºˆ‚¬¬“ˆ}È”¯Fhœ={ÎvhßþýãüùC¸÷Þÿ¸öþû‡mÉåìÙs¨^½ŠíòÍ›Ça×®:£~ÇŽýhÙòq]¾eËÖaäÈ騽;¸‹ò“O6ÄgŸ}ˆ|³0U«Vr]Ÿ””eX·nNœømÛ6Åøñƒñì³B©R‘–ê…4~¬†P߆Žèxv£} dÉ0$&vØ13í)ì§uë'[¶,E‡‰¨^½ {ìaËrzôè„V­zaΜ xûí8p`#½X¸¥3à[››GÜ«¡víêÈÊ:© ™>räz¨†åzjÔ¨Š5ªÞùåYÄÅ=ƒ9sÆÛÒ[b7ÇjQ?§N}…ÄÄn(Y2Ìr="¸y_¢8}Þ( œ>oHî.TãÍÑZlŸ á¬Brlæa£æÍÌfò(Š¢9:OTŽÃH|ù|‡³bƸ¡ïh]iߌ·‚àgxüq:•tiŒÙ{V•$=„¯³“ì·)_õ·Sº Ž-C‡NÆáÃÇqãF6²²NbèÐ)Äu¼?ŠC‡ŽÙ®§aÃXÌ›·—/_ÅåËW±iÓN >Õ‰ê\:f $A›™~ùå~˜×ú¬º IDAT9s öî=ŒÛ·ï 3óCÌ™ó&^~ù¯<3g.ÁàÁ±fÍ|SظÊK/õÅ Aÿ‡¬¬“¸yóNú ƒýžþ/®ë“ž¾={vÂwß®]«Ð§OB¾9òø;6)ßês' ¢ãÙÍö)]º”i)‡]5ŠÅ’%ÓDÝáŸÕ>µj=ˆ îÇôéo R¥r¨UëAWôbáTgÀgpmÚ´yyy¦´—_î‡!C&ãÈ‘¸q#ü †‚¡CÿfIÏfÍþ‚U«6áüù››‡¼ˆ·ÞÚ‚ êZ’#q+cõn?·nÝFéÒ¥˜2|×¹u_Vpú¼¡¥ "ÏDŸ7$Å áÙ|jA~VBá`!Q Eœ³øT•HÆžÖ( Ö!Rž~d"M=M›Û×6AÇH>E 0ÊóÓÙÿ™“‚Ëiéúx˜KDš¶gèCÅWÎê‰Î¢,(ò,.IÐÅÙÑ:Ì͵§ãÇFß¾#ðÝw?¢Fª7îEtèÐÊ”/!!“&-Àˆý-ÉWyë­¹6l jÖl[·n£Q£X¤¥¥ E‹Äû0¾·3«¼víVLž<Ü–¾€o/€åË_Ç!“pæÌ9Ô®]«VÍÖÍø&'Ïtî<ÀTþçŸá¢Ð¸ñ£xå•—Ñ¿2¾ù濨R¥ÿ‚‘#_p]Ÿ“'·Û¼[{$'ÂsÏÀ÷ßÿˆêÕ£1vl:wn[ :"ã(ÚíóÌ3ñøæ›ÿ¢K—øàƒµˆŒ îU¡»SZ¾GNx啹˜2eD¾ëªÂÒY„””q6l*z÷¯×«û^yî¹gpáÂ/èÑcþ÷¿ ˆŽ®„¿ÿ½/z÷îb©ŽéÓGaáÂÕ9r:²³o¢råòèܹ-6o^Â/LánŒªq 7îÝ­±z·Ž'ˆÜ—Û»>o¨ˆ|¹…Óç Iñ@ûÌO5º *J€±,@L¼Æ) hÑE“º‚ù°®Þβò‹t=,ÕÁ<Çžª#I Ͷ|kNq¹6Êñî…;îìD øÆ$9‚ÃÁXµÉà?• M½¶¹åÁäm¿àÞÒ¸°~*AA‘““‹êÕ[bË–%Äpù¢FVÖI<óÌ œ;wÐÑNÍ:¹3ùÝH~´OhèC¸qã4ÂÃKæk½©©«1zôëøè£·m‡í»©D"1sûöÜsÏ#ÈÉq¶áëíÛwÕyêJAâÖó†›ßc,äóÆÝƒ[§|]öiü3ÉMkªõÉ65öÈyÜu (0¾Ógú9u(4æ:‚)ǯvVs]ý5«@À©Á;9¾Ç$eõ13ú"(‰~2šN“O—«ÐÖÏ+d™A¹¬rô²D_%ú@¿b3ûâÑ@âÑ,=>Z> Þp{¿ÜkXJPk  Åðá‰7nva«"Äøñ)1âyùGZR¬¨V­2vìØO ev“åË7bÑ¢Iùú0-‘Hì“——‡-[ö7ŸµÊÆ;ðÈ#æ½… ·ž7 ê{L>oü~цã“v<.3ð›)ÜÍ嘵ùÍÙó€fÔOì^r,Ì~šÅ ”g`æ:‚WÈN½hëN¢~vgìý÷ÏÜ ‘é¼h;fš/Ýì»âõ #««,¯N¾SÀJuÁ  ú%؆6D–]ÈŸã ÝbÔ¨5Ê2_)¨ø%’‚dÊ”á2dºv ¯×|¬¨[|òÉÖ|“-‘HœS²d]T®\3g޵-C ù¯ZµÞzk®[ª¹‚Ïõ=&Ÿ7$*ºÍô|ô?5ùŒ0曆ÁMƒëÔB}<Ì šë2”0g§¤Sëã:(¿Í¨ KM›±'¶B¾ Fß¾ ¬SDnDüfÍÇø§ßƒùÖÆ~bNýF‚"Ž ñË:Øq‹“L‘v H$Zdx8›ühŸ>}ЧO‚ër%|D60“Ÿ ·ÇO^Þ7NÔ±\ŸD"aAöK&fðÁ(£Î.^§•(ršÀyjá÷ì$kN{8)oßtk–ÜfY˜'ÚÖi:ÀQÿ9(K­×îxu6Bƒx oLI$’»–¢ö°_Ôô±Kq¹Iá ÇDR\!ͰúfŠIñ¼àõb¼DC؉E]RÀ5`HaïbùtuœúÙc‡(ögŠƒž¡GM þÜhPhÍ;'I'Û–AÍ»g›e–ZðõrQ^¿2œôãí:ÄÒÌÇJï€D"‘H$‰DR$PÏçt§«¬˜í¦ðí F uŸcXÈ) rÓö"‚b8F(u醥Z8õsðœÂÿmíAhëGò1ÛjÔ ±¤æe(cÅûeVÈæ,;]Ÿ`º5Çœ¶œå²\§¥ ýoXJÀþr‘H$‰D"‘H$‹úün:y@ð¹ÝhÿémZÀ€72óÑ)¯—2c.P>1"E8kûÉç#2ÐSéÓÍš²jV¹ß¸·m­ÿ„Uc69g}Ýh‡ÝT¸ëêØuXå¿‘îðÀ#²F§€™={âãû¶®‘™ù!7~Fhí'‹øø~HIY&”W¤.ZžÌÌÑ¥Ë@DE5D™2õ—€Õ«ßµœ'?cƒLA '†øÊoŠ[¿»EAõ; 6VÝωD"¢Ùõ?ÏëÈNðÙ&~Y^%`«è_ÚSHéú|ü ½1*òõéüHÅ›GÌ'äðë)º»¿Ýwæ{™Áº¼ŒHgQôIgEÓ‡´‚"Æ9­]9Å9XÉ,¹¤âêE–S@_È´Ahí+ öyñ+ À¸” ‘““‹yóV`ƌх­ŠkLº³gs,gƌј;wrrr‰é½z Å¢Eéôœœ\¤¦®F¯^C-å‰ï‡«W¯##c).^<Šôô9HOS¦¤ZÊã6rlÐ)¨±ŠrÖôÊOŠc¿»EAö»ÈXuk‹6mž´$'*ª!Μهûï¿×²*ÿûßOh×®/–,™Š¤¤ÿÃÞ½é¨\¹‚mynáñÄ8^ýË/—ðÐCmñÛoÇ×%ªÏ–-™>|*ŽÝLí‘ ú*¤¶7ìõÅXŸ1^¤|§uøhåpx#€½_ìuo)JLL5L˜ðNŸÞ‰Å‹§bóæ=hÛö9Ër®]»²eË8Ò¥J• XºtÚ´yK—Nsä(èÝ×y”-[×®]çæy(É“‘‘‰¤¤ x÷ÝR 3‘û'”*)R…‰5¢qöì9G3Ïÿþ÷i¬Zµ 'NlC«V½ÐªÕhÔ(Ö¶¼¢ÄÙ³çP½z•|¯gÙ²u9r:vïN£î/’ÇMÜ >ŒòåïÇŽû±iÓNìÝû–‹.56Œ|úé—xðÁü«·8ö»›ßQ…Õï‰D")8´†©ÖÐQ4ÿ›ÍCh3¯ã’?ýÌèf”¥¸ÐÒ@fJí6œæ0oJÄ„P¤€f–ž±É ¿<%Õ` ZßðÑÀ)ZŸHÔË®3„eLs‡ž]C }‹’SÀ|]hóAÒÓ7£gÏNøî»CصkúôI°í€ÆÅ¡CÇl—¿~=}ú ÇÒ¥ÓUK–LCŸ>Ãqýz¶m™E‰C‡ŽáñÇäk3g.ÁàÁ±fÍ|4iÒÐv-n„Ú;*II½0dÈdÜwß½¨S§¦cyE…‚:$b×®¸zõ:®]»ÌÌ‘˜8ÉɃˆùe¿›qû;ª ú]"‘H$EÚšeª !¼¹ ÏÈ™•vcæÚWWà(BRbBˆ™]iãÖÈ`еæ ÖÏLÑÅ®D?±/¢³˜S€¤=Á¾!î¡´;`ÁIßÐuÑ;‚ø2B¸ºròävŒ5•*ÙÛdÅHBB<Ö¯ßn»ü‹/¾‚„„vcõÉ'¢sç6WTçG¸¶”ÀmÂÂB1|x"ÆË¿]ÎïVÆOÁˆÏ#,¬Èúuˆ,_¾‹MÂc=ìHŽcCQ,^¼ÑÑQ·nñ™Í,ŠcCö{þSû]"‘H$îœç=¼Œ™îàË §© í"M'­O‰€öÞDpî ï+Àw ðÅ S€-àÄ)à4Ú€-¤þÔÿ'ÔGfŒN0ó’k‘:9Ɖr¢läGÛŠ> —ù¬‡ WPŒ5£F (l5ŠvNy( |òÉV×d9!!µðàƒU°qcªk:ŠâØýžÿÅ~—H$‰ûhŸíÍAŠîwãÓ½ÞàR´YMø6*±D#´õÙ1êü2¬F ‹Ypr°‡€Y c&Мüåì¾_Á“ÏJgÝ?=™ëÜ"Œ[º~æ²ô4òeÇ#àpã÷5#ƒõ4Cÿh€¸ØÔGýnÐO/)–÷»HîJd¨óïÙï‰D").(ŠÆ9 0;¬?Ñ€)Yc›˜åi×*kuP—<¨aþÿ1hú°uÂM€ž®+kÇ) ^qèÐ]§ÚÁÆ:2‘)àÔ)ÀCpß²þÆèJªcÈã7rycªM8;ÍÙÿØ´,—§–²ö>BN J߉8dÜ©D"‘H$‰DrØW@û†]B_Žä!`òÐÎúêu¤)ä|<ôu0“íÉqž@¡rÎL¬¥íFy¥ ¤S7ô€iÀ­×íÎÔʶSLɇ8ºO‡úHÇ€D"‘H$‰DRD!o>H äQ±²¹ ù@…QÀ !çåÑÔatRópëS´ÿY°•l-0mìÇ™•ÖlŽo”Á™Ç§UIÕM¿,¦¯•mqV](Á_?e¼ñaµ=G/ŽN¶ 3ô²üˆ ›Nª>Ö=¡ºKùâõH$‰D"‘H$vQ ƒ€b £„1“÷2pîPÅ?wÌ1Øm:ôÁâNæòN_Ž_OþЦùwrnëN& ø É ílÒÁ”E,Q4‚ZVafá!ÖF„zm­åçœlàºS€‡ÙÑbÊÀìä¾®^½ŽŒŒ¥¸xñ(ÒÓç =ý]L™Üe]QΚ^&¼„ÄÄn®ë#ñ1tèd,Y2¹¹_« î&NœåË_Ç;_¶*E†^½†bÑ¢ôÀg=''©©«Ñ«×PKyD¹sçK,Y2'ÎwçŠ!Nÿ^ˆö—ßó‰DÂ"ëÈ!œ:ù‰îZÀÜð[×J^‚Ç’(Zc^¿nŸfåÓe鮪Žèb¬KW…Ö3@­JT¯éJÐ7!z_jvr;*Š…å|1Ôa–¡_sŠQ†hø>±‰ê©3éÁ¶"Ü%A¾ÂL×é °'Þ¿¡ŸŒ‘¤v× ¦nXÀKÜ®çõ£œ—¦“ç +SÎe}BÊÆ#T ÆèÙ½û ªV­„¸¸úRŸÓûŠ‹«èèŠØ³çm©©«1fÌ@´k× áˆoŽ‘#_ÀÂ…i<£F À¾}ÿB‹zõjaÅŠ™HM]M•{íÚ ,Y²cÆ t]‰o¿ýíÚ5CHH‘õµÙâÂ…Ÿß %J”(lUŠ ii) EÇŽý;öGXXÒÒR,å¥D‰hß¾.\øÙ(†8ý{!Ú_n|ÏK$’ß'—/ý*ô2:¨,w=»ÿ=cKñ™iÞL¥@µR!ãHDEkr“% Þ{ù€¸®fcÚÇì É9ÀT–¡_ R„ë`Áë/Ô²¢}M)kÓ)@Š ¡áI¬×k÷†ˆDõ¸V£;[1Út^¾‹E¯^CÕåÊÅaþü•ô•+ßFLLk”,Yuê´ÃÊ•oåddd¢GŽÔ:zô‚ûîk„×^ûÚ·OÄ}÷5ªU›tù¶nÝ‹fÍþ‚ððº(W.‰‰cpéÒK÷åñÄàÀ,´lÙ¥K?‚råâУÇ\¼ø«)oÏž‘‘ÉlmF<†öí[é®uèÐ dÞÏžlräDFF 77Zß?ÿù/<õTKÔ¨QÕu}4èˆ9sÞtl´x<1HK{µjýááuQ·n¼i‰DQDm»¼¼¼À2;áènŒçühCEQ\s ¬\ù6Z¶ìiy¬ÄÆ>…#GNè®9r<ÒÞ½XÐt6~IÎU^+÷Z^ªWXÞ÷óÖ­{ñ‡?tADD=<ø` ,^¼Æ$cÕªM¨S§ÂÃë"&¦µé;\tiÉæÍ{—€ˆˆz¨^½%V¬Øh*#¢Àþ{aÔ®¿Oñïy‰D"q ÍÌ5É ÌØûfjt¸f6]1¼4™5Pd‰äa†±ktb  ¹?š¯" éžõi¢Qj3äeŠš_(Ò€\=ïõ› %šë`Jaë`H?$½¬ÖÍu01E+œLvÇ(ïsÀs0ÙËŒŠ¡—SeaÞc€:ΠϪ?ÿüXtéÒÿùÏ~œ:õ¾ùæ¿´×__ŒÕ«çàÒ¥O–63g.ÁöíûL2Žý-Z4¦Ö‘˜Ø ë×/À¤I 0dÈ_ñÎ;ÿÄÌ™KtyæÏ_‰É“‡ãòåøâ‹=([¶  zÅò} >S§ŽÀÅ‹Y8qb;J– ÃС“Mùš7CVÖI¦,çÏÿ€5¢Íšý-Zô@ÍšUqþüÌr ¦¡gÏNÄ´Û·ï`þü•7îÅ|Ñ'1±6lØèèfhß>kÖd ;û¦åº`úô7––‚ß~;ŽU«faúô7°sçK2hû+h ‘<¢hÇvé†UÜÏn´¡Ê­[·êÜ) ( ’“gaß¾±gÏjT¬XÎRù=:aƺkë×oG÷î|CÐ.,ûõ‰;wî`ûöå€íÛ—ãöí;è×o¤¥*¼¿|™íE (†·‡Ù­ôòbÑé6l!‡@_šàÔq%R7A®H‹KeôºðËx&§WÚÖmƒÛ!˜´ùˆ*‰?HŬYcиqsO Óðñxb°bÅLâzv';w®ÄSOµ \Û½û &O^ˆC‡ôkEE5Ä™3ûpÿý÷åܼù9 2òáÀï÷Ý×ÙÙŸQu»zõ:ªVm†+WÌu´ûòxbpäÈ;xüñk?ýô ê×êòþòË%<ôP[üöÛq£!J”¨œœ¯‚&Mº¢D‰<¸aau—÷ ±Ì–-™>|*ŽÝLl«Å‹×`çΰyóBi÷ô9{ö<Ö­ÛŠµk·âüùеk{ôíû,Ú´yR¨.ÚØ˜6í |ðÁZ˺4¼Ï¯¬ãÙÍ6ÌÉÉÅêÕï`Μåøüó]\ýiŸ7Nã¹çFàñÇ 9y%T¾üò,þô§¿âܹƒðx¤¦®Æ{ï­ äyõÕ!ˆoȳsçtè¸GÖxP¯7mÚ cÇBBB;ª®"ú¨°þa«1- IDAT^X…×§N¿ç%Éï‡YÓW ÿÀ—ø–ˆ°i£/2ªÿÀ—ñŸoc̘Y8Þ†’Ûÿ ïÑØ¡†gÇ£3™r˜NA`ŠQ4›2 l‘ ¹3¼š$AÇ3MäÞ˜ò4N’š\ÇB '¥j§€¢@!ôµ¢ùŸ^”ãPU ¥à}°Oì6ö;µh²9ËØÝç5èi”/æ0ç9¶}Î0«aÔG¤œ1Ô­o„‚½_ì5/%°ëÑÒ¾}KjZ“& uïŸxâ1âfv×®Ý@Ù²e¨r""®ûýæÍ[ôK—®`èÐɈ‰iÈȇáñÄ lÙ¸ví†ÕÛAƱº÷*<€ŸþÍ”¯lÙ2¸víºeù*‘‘Á?Þ„?܈›7o¡T©bþŒŒL$%MÀ»ïþ“ø@œ——‡””e¶¢¬êS &¼„Ó§wbñâ©Ø¼yÚ¶}ÎR}¤±ñÙg_ÛÒýníñìV–,YŒÇ´iæS+´k×§Omi#uëÆ *ª,>úÈ·îòðáã¸ï¾{‰Æ³XÑYÄAËcõ¾fÌÆ£dI³ÃÖ ´ïçãÇ?ßÿü”îZÓ¦pêÔW÷Ÿ}öÎI Mš†pÆxðÁ*xâ ëîVõ9sæÖ­Û†µk3tNñZÜ胷@QÎ å)j8ÏVÛnßþK—®Åë¯/ƳÏþÉŽÊ€éÓG£víêhÒäϨS§&žy&Þ–œîÝŸÆúõÛдi#¬_¿Mh=¹]ÜÒY+÷5mÚ",X0örT'ëû9:º©éšvCM»›kÚÝÅŸ§ŠÓ¿Vpú=/‘H$NP@8òÌh›û c>ÕôòX9ÏOx6žcdªãN{‹'3 ~¦ˆ€±Í«ËlЕ¡môÈÐÑ$ƒ•.òGš (ÌÉv °Ú5f9u«å9ÕÚ3]ê´e„sòØu 0Ç«x¨ª4]Bü¹„:ESÉÊ:‰ØØ‡LùjÔˆÆÙ³çl׳ÿǘ7ïÿP¯^­ÀLìûï¶-O„³gÏ¡zuúÙ³<š7î]úõà;vìGË–ë®-[¶ŒÃ֭˘»p¿þúbŒ?8_õIIY†¸¸Ô­ƒbüøÁøé§,¬Z5mÛšêYÆÆÃײ$ƒtT£qí¿Hž¢†èxv£  dÉ0$&v#ÎÎZ¡uë'P¥JlÙ²IIpâÄç¶äôèÑ o¿½¹¹yxûíùº¿€[:‹`å¾Nú ‰‰ÝP²dX¾èW?ý”eúÕ‰ê\:f ³%AÛäîå—ûaæÌ%Ø»÷0nß¾ƒÌÌ1gΛxùå¿òÌœ¹ƒOÄš5óMaãZ¶o߇ˆˆp!ã܉>éé›Ñ³g'|÷Ý!ìÚµ }ú$ T©Hn$HccìØ$[²Š"v67TÏn¶aéÒ¥t˜ШQ,–,™†„„$ꩬö©UëAT¨p?¦O•*•C­Zº¢ bå¾nݺҥK1å9c'¾ŒÞ½‡!+ë$²³oâò嫨¼yÚ´éÈ“œ<C‡NAVÖIܸ‘Ç›6bmÓ¦)FŽœŽ~ø ÙÙ7qðàQ¼ôÒ«º<ãÆ½ˆ!C&a÷~=_ý-^|Q¿‘¦ˆ>*¢/œ´Šè÷¼D"‘¸‡yf:¸ƒ>‚† )”\Ñ¿ŒR‰sý"kîuXYDdñ *BBx?}É€ú¢4C_º1OQç+ɾ_î骞´Ð}@ÀñãsèP Y ß2öÌ8ËQ£×ß<þ8ºQ!;ªôû °Šó iJÙ—ËuR8K@(FÞø ¥}ou†uüøÁèÛw¾ûîGÔ¨QãÆ½ˆZ™ò%$ÄcÒ¤1¢¿%ù*o½5ÆMAÍš­qëÖm4j‹´´´hуxÆ÷vfŽ×®ÝŠÉ“‡ÛÒêׯƒåË_Ç!“pæÌ9Ô®]«VÍÖÍø&'Ïtî<ÀTþçŸá¢3füÓöÞVô9yr»£:´$'ÂsÏÀ÷ßÿˆêÕ£1vl:wnëšü»‘ñ í6|æ™x|óÍÑ¥Ë@|ðÁZDF÷ªP]Œ‰©F-ߣG'¼òÊ\L™2"ßuUaéì…q_$Úµk†Œ;ÇŽ‚׫ iÓF3&èXzúéÖøé§_зïH|ûíw¨Zµ&N‚¿ýmt Ï‚1dÈd<úèÓÈξ…Fb1wî´j\ѹs[äææaܸÙ8}úkT¨ð^}uˆe}Tœþ½°‚Óïy‰D"± q‡{õ‡Ï8ØÇ÷¿êc D k8¶<#K8¾›ã ìîÏ‹ 0©!± ºtŠƒMÙ:Ù¯š{!·ƒ˜#†>cÎÁ‹Z1VNÞ˜°'–ƒŠ™ýe×)À¬Ðvß©õÚ"ä–¯½û=¢ÊDâÂEÔS Šœœ\T¯Þ[¶,a†Ë²²Nâ™gáܹƒ¶w ÿ=ãd'y‰ühÃÐЇpãÆi„‡—Ì×zSSWcôè×ñÑGoã±Çv$«8Ž¥Û·ïàž{ANÎïc3N«Ôß ù=/‘H¬àÖ©Ÿ–lMÞWÀ`DÑ7Í¥ 2 D/ÕºmU'V6¡Œ*Xt 0g¹)Khå¬8ù8Ä"NCS™³ðœ "ÎÅtE_žv\&¯Jz?“N0ëÉWlG£ õÚu û½±Œ‘‡W7BÁûæS >8DXX(†Oĸq³ [!ÆOÁˆÏˇEI±¢ZµÊرc?òòòòµžåË7bÑ¢IŽÅ‘¼¼àÄ! Rƒ@.¡¹aE¿«=+'Ñ)@ͬK7ÕÁt 02ˆ`+T_ NE ³¼U§àÉTy øŽ» c@1ü”H âú]äGöé“€>}\—+‡´ ¿D"‘H~_(^_øoà AÍózÐgÏZ‹,ЕSÌÆÙÑ «6Î6+BAŸ—ì8Ð;Lr,™&Nfˆµ2ÌNƒÝ(Ú† E+âñÀxô¤-ùBáîŽ28*Ïtmä·n¶—pƒ¬›j”3,ù¡ëóL¨OF H$‰D"‘H$wÚð|’½êa,9–¼ƒÇ¢C€O!Ú9ÂQ¢ægæØ´ó<³B5\¢† K Û…Vm{žÉÍž1§ ÐoæG(Ï1^…7½d ±›(>+oÿ˜G†\nô‚ð‡QW–Þä"QbNõÜZY"‘H$‰D")¢( hÈ£˜×ÿkÃôÙø yÍ%óľˆ¥.`‰ŠaøX1fiQn;Äöà˲â°šÌu*°J :‚õÊ UgU'MݶÖï‹§‹,ðÐcéä‹‘*EöT‚âx¹D"‘H$‰ä÷EÖ‘C8uòG2ÔGtÖ¬¾jy4᪡B<€iXûë3,á­@‚P²¥|Ý­9Ôʬ9ì„õ‹½<ƒ\d£A†®L[Qu?Ù™Õ6êÀ.oÙx`sC?µnµ~Ëý'23_Ðe:2Ș#Šs@"‘H$‰D"¹[qÃ) 3ý?‰qÃGu˜73òh׿“8³Ô"ˆÎó ÎQ‹È^ '+Äá2¥—lp›‹±¯ÐŠá.RV0Š,ŠæÜRÛ>Ÿ" Ñf‡cüä«Nö;®-%hР#úõ{}ú$ bÅr¶åx<1ÄßIÑO ~ú) C‡NÆÎZ&¼„aéÆë[·îÅk¯ýŸ}ö *TxãÆ½ˆAƒzÛÖ_"‘H$‰D"€»¢CÇ®–ÊØ·‹›Gß ^ GÆc ™QéìËÚµèZ1¦M]v (ŠWÀÈ©Œá0ÈqäàÚx>]xuð# õÒ“)åYŽNSMnÏ@‹G øÞjó;uŸÑ'ž` û2Xõ«KŽBDªóxb˜/HLì† v :ºÚ·OÄš5ÈξiCé³Ã]ýµ¤àùçÇ¢K—vøÏöãÔ©÷ðÍ7ÿ®kçÎè×oÆŽMÂÅ‹G±iÓ˜7oöì9dYo‰D"‘H$‰Ä öíÂÙ3_ åUü%ÏàPó(„õãÚÉ@ôW¤¹¬^AÛË8A«Úź÷º—¢Óͨþåe;„Öj+j«AñPîÖ/GÑ´¹1ó÷j9žƒéPueÖ­AnÒ—;y¬íwýu½ŽôúÅ f¤€Ö(7*ÃmJõþ¬;fã ´PV á¸íBÔG[Ö¶^’S€|ÌŸÞðT@;aO!¾#ŸTÌŒ2 •æÍÒ²“ý• dR…)Á_mÊRà;uAaéè7]mmÁ f6MföÎø"wdtò0’ Õ+„¥ 9V"/È•p‹’Ž©dÉÖ‹äÉwn|³oÁ†la¹´<¬úi!<5¬S &¼„Ó§wbñâ©Ø¼yÚ¶}ÎÅô´oßÒvÙãÇ?ßÿü”îZÓ¦pꔘ§V"‘H$‰D"ÉoL³ú$Z³’?׬PÞ©õ‘K° v²_0'E §€*‡æPg—®á&X3=xOô¥¼ œ÷7R€«ƒ×Rh¼BèGú‰,§ÿæhýÈ×Wà~xkø¹eíÔ-¢·Ýq«/'´Ç€v­?Q¤&¢àÌ™sX·nÖ®ÍÀùó?"ò‹J•Ê çÍÉÉ5]‹ŽnjºbZa!‘H$‰D"‘8¾uû¾˜Õ¶ š”Š>`›n{’g¦uÛxµ©>ãƒjÌZ‰2ÞÒ ’,â¡ A}Ø.JŠB{Cˬèë%Ôÿ3†‡1q¬&è"HrŒg’SA#ˆTÂx-À‹`©F¿‡`;91êyã–œÎw89K7ïa./äYJ’² ëÖmÉ_ mÛ¦?~0ž}öO(U*R¤ ³b¡%››‡ÐжÊßÿ½¸xñW”/àÚñã§uyââêãí·éòH$‰D"‘H$n“““ƒ ?þ¯¢_“â AÅJ•F)4è<+†g½•jºÌ+`T+Ú“ èÆ…º¡}æWWŸ‡oÙä¨9èwå×Ýx ¡)äÞšQæsÒhЉܗ©~ gªÚ~5Ûìf£·­˜S@ëÔ°á0& : ëæÞ‡¸lñ`¶CÇÙ^¬j9ŸB} }h?3¼¡“ž¾={vÂwß®]«Ð§O‚m§Ô¨Q›6íD^^ž­òmÚ4ÅÈ‘ÓñÃ?!;û&<Š—^zU—gâÄ—Ñ»÷0deDvöM\¾|›7ïA›6}lë-‘H$‰D"‘ Cùòq3;7®_Çë×qëf6}¬1yô(Á`²iIÖcÖÒJà#â›õÕo`H¨O8„Û ¿ˆÍmʦ_,§€ÍevœªCÇÙ®ô,£˜,&CÔq#nˆÒ«¢[»³ê,ÙB¥X¢2-O¡Ê«Óªãеã OžÜî–(@JÊ8 6½{ƒ×ëŠZв`ÁD 2>ú4²³o¡Q£XÌ;­Zõ äi×®BBB0vìL;v ^¯‚¦Ma̘$WïE"‘H$‰D" Gݺ±øê«Ïmã;¡R•ªøæËS¸sû¹ÅÆöºyÇ74e#›ÚZ¨“íÃÉ Ë×[ìâjnßOEQ‚›Å™“Ù:P2YY: ê@Â(IvÐus) ùIv8ð¢¨Â\RCI7]1´«íH›†½íåŠ!1b@QÄô–H\‚w¦«ûLH¬£}pPÿ(ißK$‰D")` ô½|YÉ>ÅÒ²`$'8ü“”b²ü?Tã!l„òd0 7«N¦nLQô6?ŽP+Ül弄 wKB‚ÂÌæ;uÙ-¯ÿâ²õ{Ø|×~w8,äRI¡#bð[q Hì£]s¨>@H‡€D"‘H$ö9°oΞùÊýßaó^Æt}é ?@?CÈÙ«Ðÿ+ùÀà ó7 Xÿï†S€ Ã|ɾH4r ×Xï(•Á7COÉÏÊ`ê*`ôªûˆ.¥`9=x ìü”ú5yXò­9#|²Ù9Nµýã@øþm:,F è#PÈrCý9e €Dò»G]&P“Â&—H$‰DbçN:b{ ¾Ÿíú¬à4T=>¾RR–9ÖcÛ¶÷ñÈ#íQõëwÀ{ï} KÏÌü]º DTTC”)Sqq X½ú]]žÛ·ïàÕWç£V­?"2òaÔªõG¼úê|ܾ}Çu}$‰D"‘H$f¢«VÃåK¿Ú~©(}RÝ@<°‘¸i†U#Å”7˜¬^š  U€×Tj°)ŠÅëõ½yŒ÷¡Þ·ÖFÔO\û…o$)þPò@Ä% ~½ØôÔúô÷–êò m3Ê›_Í`n_F!‚> §¡¼¢ùg¼Uò&ö†!èÀHÔÿ4• *@n¶¸—N¢”€\J¿ð>‡\§;=„¡[¡’““‹yóV`ƌх­Š3fŒÆÜ¹+““k[Æ©S_¡ÿdÌŸÿ ._>¹s'àoÏ??ÈßW¯^GFÆR\¼xéésžþ.¦LI ä9r:²²NbÛ¶7qéÒ'ؾ}9þýïÓ5j†ëúH$‰D"‘HÜ#²Ô=øèðAÃUEó?¢aK3üà·mè§’ .ž_@Ä ê'p#¾+„Ah¦VÄH'yB ê: ×—g…ìë’ÕÒ;x(2uñ•ãD ˜j¹?½Žbmª”æpˆj@[t èÒ™º8Hs9! Y ’ Ä|‰]  v†ß½û ªV­„¸¸úRŸÓûŠ‹«èèŠØ³çm©©«1fÌ@´k× áˆoŽ‘#_ÀÂ…i<£F À¾}ÿB‹zõjaÅŠ™HM]ȳ~ý6,_þ:êÖADD8êÔ©‰¥K§aýúm®ë#‘H$‰D"q‡ÈR÷àý=Û¡xó׌áæÔÇ{‚EÝÙž8i06µÑš*ȳ×|£ƒ$©œ‹NRäBP'ýf{æ{¹?ò̱¾>ACœî§èÁtpœ|ç„Y†Î) i ¦s‰SÀëå8 wzåpäP@mc¶ñͳ±9Yx‘Ì%!œ>÷£s °pÖÝîìÌìîÜÞ¼¿yç‡~6e> ¾Á¬Y3Ò–1kÖ%””ìÉþpӧϦ¤dOyäßIé^xaûïÿ\®±”—Oeöì+inníÑyIÒÞ}w1t:^ïDÊ˧2kÖ%Ô×7vK{úé3Y¸ðŒ×'±Ì®¼÷ÞR¦O?8iÛ1ÇÌ»ï.޾õÖ«ºÍ#óxÜèzçˆ$IÈr²æ#ËrÚùg}©ÏäÉ3¸ýö‡¨­mH™·Mv⢀L˜89i_*£6n®¦4;Ù´Fq:„HëæŸ˜Ì;Ñ£ ë+yCÆBI2­:FI~™™Ï9…'DïÎý™®UV/¨]'ºÛà y›ñóJOzc5yÚ@6£9V­„i‰uMÈ3íÉdñÔÈX¾ÙEK:&9ïžNˆYßé«ùXaFoRÊݹˆ¹µ¥TegªW¯óíBwt±KÄúœGÕýëÿáøã`Æ·Y±â¾þzS|ߟÿ|?ÿøÇí47Æ£ÞʼyðÒKouËcÉ’/8ðÀ½Ó–1{ö©<ýôÜxã\rÉ/yî¹û˜7ï¤4ûÛÃÜtÓZZ>gÕª×),,àüó¯ïñyÍ™s37ß|9õõ‹ùüó—p:\zéMÝÒpÀT/^ž1¯LlÙ²ªªÁì¿ÿO8ðÀY >„-[¶g<î®»åôÓgÆ?ŸwÞœwÞu|ýõ&Âá_½‰óÎ»Ž .8s§×göìSyæ™—Ÿûîû#ûìc)·^o·Ýv5{ìqL·tÇW²iSu·í]I'Dƒ!Ün†aÆë„Òæµ`Á<öØó,Yò||Ûõ×_ÌÑGÿ’Ñ£o;ôÐý¸æš wz}.»l6—]6›õë·ðÔS/0wþuœrÊt~þó“â÷ÆÆÆÆÆÆÆÆÆ¦;]Eþã-(¤~G†˜NÂ2ݽAc†KÒ_F[ÌÚ)å¹>9ÃØy÷½Rª%2fݽ9·º¥6ŒsH–‚ìuÊUÉ”FˆôE¥!OŸQºã{–GZïqݗѨÎr®™¤nžÖq¹Š »VèTov}2æ™c¾Ñ¯mòT‘i2AîLŸ~PÚ}ûí7%éó¾ûþ(e0»öv?……ióq»]q£5ö>ì4X››[¹ôÒ›1â<žñHÒ 'ÓÞîïéé0eÊ„¤Ïe444uKWXX@{{Góáñ¸ …Â|üñ¿ùàƒ †ÈËs§L¿páœwÞµüç?÷QZZß~ùå·àñ¸ùê«ÿ ~ÅÊ•ÿÅápðÛßÎÝeõ1¢’k¯ý _~ù*÷ß3Ï?ÿ:‡þ³•gcccccccóC"•(€$ñÂóOÇÓtÚˆÝGSà‹Ä¤d4×°Œ%3yÄžTFbÌŠÍ2ªšãjÖF¯½zäIËàRÂî×6yŠB¶ëÐy­bÕèæ%aÒMHíòŸa9úJî¹å‘è±Ñµ>I&)³I_F²7E–óHº·éî÷¥{2ÐQ Z·ôËJÆòî¥'Aºk“‹AFqªgž1ºO%ÈY1LÏ€éÝŸRVBî>¡ ÀKkk{¯ëðË_þ޶¶Žxd~!ÖÓÞ¾"³K5§t­­íä÷8ÿ••Ù¸q[Ò¶·QY9°[Ú§Ÿ~‰³ÎºŠ_|ˆÉ“Ç%í{òÉxè¡?1nÜHÜnãÇäá‡çñä“ wY}Ö­ÛÌÍ7ßÄ GsÞy×r GðÆõ¨<›Ý…áY>ÛØØØØØØô•t¢@×àƒ™ ä4é ¸žö~“Å\ƒæåjŒ§Ÿ§”WN®å½3€2å•yþ|ny$mízX—ËÙ½<)e>é3ÌV§L{³ôgòè^F¢’3]„®Tù¦ÞŸ:M÷¼ûà)@W,÷ãr­[üm®$ ?¹•«ý«Æò—b™ìR7 øè£Ï’< /^΄ £»¥«ªÌúõ›“FÂ{ÂÛoÌ–-ïSTä‹o{óÍ{•W®¬_¿™aÃõúø˜Êÿû.&ŒŠo{ùå·9è }’Ò=øàSüö·syíµGÓ®Úêþ§ >Ø—úÜvÛƒ<õÔ‹|þù*?üÇ\sÍ…œtÒQäåyzT–Íî@§k+’$E&±}¾ùjÙØØØØØ|ÏÈ( D·´Y‰EÒÀò¼ŽoíÒçK4d’¦ˆÄíÙj(R¼KF²2ÍthŠ"áàTÉv‚Á•C2Ñí¢f²r«Sæ9ô åf5R30‹„÷éóÉbì§)§›§Eú\º%Jr1Š;ÿf3ø{,ÄóN' äV¿ÌµÈp®½ðèRvæ}™Êì¹PËVîºqghn™¸ôÒ›øðÃeøý/^Î¥—þ‘«®:¿[º½÷žÄûï/íu9S¦Là¯ý?ZZÚhiiãßÿ~•9snîKÕ³òþûKã±2‘n€‹/þóæ=À¢EGxã¸ýö‡¸øâ_ÆÓÌ›÷^xO<ñ·nÓ2bœ|òÑœuÖU¬ZµŽp8š58ûì«9å”é;½>=ö<§Ÿ>“­[ßç¿ÿ}„3Ï<Á¾ÃH’ïD$Î=쩨dcccccc“š\DLÁ!6’›½ãž.H_æùܬØäø+ú&…¹i½$‘zÅ 3g0x»|Hôzèܰ³¼>ý]ë©6i®o÷œÂiŠÊm”<>å;íK¼©·æ$ dˆeCä¤ÛÇ KR{ÆF=­}¹ŽÄ¦Ùÿ+ˆ[ÂR´ü^äÙ=÷ÎO‰ùIt7"Óº÷¡“ÍÝ=–&îu™]_ [ÀCÑ'£1ûþ$Q ‡eôøR¦2˜¶¤žNéH>vI¶ó;Òûºõ’lž;á„¥›½F>öp¤ÄµO¬¢Ä—Gã’G™?ÿJöÞ{LŸ è-š¦3lØA,Xð@Zwù݉ŋ—sâ‰ç³yó{9Ç$°±Ä˜\D˜\ÓÙØØØØØØØì¬ÿ:yU©\E$‰7ßx…1ã+¹òÊù|Ù+u´ÿ$Ùý9"Éb@÷ôIBBÚ@hé6DÿöiÚ@êzõ:¯¬ÆUry™ƒÊuÍZtO’±¨Ô×½{>¹Ô·»hÒ= ç•õò%×µÇ#ñY§$ß« ¢@_<¢9ìÜú¥ñÔHòÈxl6A ó¹¥mÇBðác×!\‚E«u™J5Ûo‡CeΜÙ\}õ­ßvUrâšknãòËm‹666666666IôHè|0÷c+Yî#â‰ÑßS¹ºÊ'a½vÚ´$ įIo‡„ëùœWH“¶¢@÷Õr¹] þTÅ&œwÚ²’˜Gºýéí¼ç¹vì½(»=¬_ìø]* d¸Ð}ò$è›(еlµëþ݉+®8‡+®èî2¿;bGà·±±±±±±±±éJEÑ5ø`Ì`É%t§ñ–9i×äØ_‘ÖK ÑLèô`H‘g&Iê(K²\…ƒl‚€Ufæì’G»Ó¦ÍÉS>‹¡ÙCá$mê ¢èŸ½Œô…d®¦$E—üK/´ÄßõFHLÙ[[6GQ ÍÁ½/2[…3¶Ý>é§(;I°æÂô>‹ÞŠ…EÅ4µXÂ@¢‘Ÿ¼²@ÌIbtíÓ[É{8Â}ßUè\Æ.šVJ…î&`äì)°s‘S<Ôû“ËÁËÑK@dZ.GA ‹ýÜsôÈ•?{±%43‹=™²Ñ5ÿÌ‚ÎÎó°’wM“ƒ§DÊi'd¿×»JHy?¬Ï¶ß»Í·Nªllllllll¾Ë”–àÅ矎ûeåýÈË÷eÝVXTÜ-¯X?>y0_ÐUHOçÒjÙR2ÉÛ¤øPsjlóäS ¹R$™ÞU:ÛÐ}W£/Sš¾‰"n䥫knFžÈÅ ±ˆúi3É­¤¾Œǽ*2‹}v{Q ïç–þØÛK ‘/S[KžJÐ¥%KÖäT¨MoY¼øåœÓÚíÑÆÆÆÆÆÆæ»Ä˜ C0h£®¡º†uY·Å<RÑÕ¸Oêã§©O9—=9…°'#õ³Ó:Oq¨ÔãyÏÙÜø“ë˜Ú†ïr1ÒíÊɨÊAH“$µ±Û;/îgœÎ»!ÑèË¡Îi«ÒGƒ6–GVA S^9z" 2$Ía$?­(Më‹Q»>YêÖ—k“XNÚüSÓÍc –üÊ+çç\°Í®¤»qß=¶Ÿµ£SÈb Å–Ô#¶Ü_¦Ø FK–ø]í¾®a ¬PݽÃtzCˆÄ?)ŽI¬Vu!Çý¹§Éå§O”»—€%»t“5RæÑÍXÍT\lÙ¬#ÑYŒÝY–#ì“(è‰>Qæ<¢ùäO@$ë~ŽÓ[rñîI¿=wa {¹Ùµ„è7ì¹[N‹nžÙ»BÓ‡©oh ¾®ŽP(Lii •••äååíÔrlR³fÍZþõì³´··gLWPPÀþ?žÆ>ûìC(â‘GÿASSSRš)S~Ä©§œ²+«ûÅÐ LÃH󠱱Ɍ$IÈŠŒ¢tŸáe·-›¾¶m A$¢¡E"˜Y]nmlº#Ë2ªÃËåú¶«bccccÓ Ö|µ"®7ìÒš¦ÑÖÖÆ¦M›iرƒ¢¢"6oÙLII ²,Ó-ò©M! m!$ ÌçîÓuúôÓOBpàfLøèãO‚L›6~ýÊÙ±cº®ÇÓTWoO{üg_,cûöjLÓìö2RlËø2¬¿£Fæ¸cëõ¹SèêíÕ¬\±‚¦æ¦ìØØ$ Ë2…¾BÆMOee%ªÃßg·-›¾¶m A0`ÛöjV®ø‚†††o·¢6ß9E¡¤¤„=ö˜Ì¨1c1»,¯gccccóÝb—†aà÷û©©©a{M .—›N8ùóç3qÂÊû•‰D$ ‡Ã,Ë9åûù石xñLa¦4”»n“%™½÷žÊäÉ“wÊyíJ„4´ysù66Ô¶Q݉«7’Kœ ¯ðqØS^èé‘Pàøñz½{ì±x<ž´éZ[[yóÍ7Y²d .—‹Ã;œ`0ÄÚµkãn4f÷ mÕ[9考q8(ŠŠªª(²‚,ˆ‰ahèºnñ÷†©cè:ša`è:†¡£BLÓä…^Üí…Ó0¨®®æÓ¥K8ìˆÃ©6EQ2£k´H¡‡0µ0B„#§ßÀ)ßPímv4Mc˦ ¼ýÖ[˜†É°áU¨ª£WmËÆ&‘tm+œ–~ò &NbÒ“‘d[¨·ÉI’‚,^ü1ù¾†T%ÛÕ²ÙI¼ñßW¾‘rŽ8úfÏ_”vÿ‚y³vZYM;vZ^¹PZVþ–—Æß/XAcc­­mäû ÃFÕ¡R^VŠ×ëÝ™UüαS…!áp˜††¶o¯¡µµ•Aƒ3xð`\.¦Amm-y%%%¨jö*èºÎ;ï¼Ë_{¦¦& Ã@’¤¤Ðí³Ãá`ÃÆ44ìààƒÂáp¤-#  …ú3˜èQŸŸ5m›?Ä ¯çƒÕ È’Œªª¸] ñy,BPצº±†·Wlã€qý8~ÚH|^wNu1M3~Í2]ƒ’’Ž8âœN'ï¿ÿ>º¡sòI'ò쿟cݺuQƒ=ºn•1zú5iÓÈÑŽ§5Õ%óµ~éÞ³“¼v¦iæ,DåŠaè¬ür‡~8U#FuÛßÑÚˆjA6`ARQd§ RÇB¡0ºäA‘EN‰pÈ ØÂÀ ‡ÃÁˆQcBâ³eK4xªêÈÚ¶ll²‘®miZ˜/W|ÁÄI“ðzóPUu§?m¾ÿø ˜²×^|¾l#F޲…›]Ÿž]Ûç<®>utÖ4Ûª·ñÑ'ÑÚÚÒ£¼ ‹˜¶ï4ÜÛêÙôS˜|½f=_,Ymy¢›"n_X¯èû¤íû‰¾×uƒüÂdÓ}ÏfˆË²Laa!|0áp˜?þ-¢qüqÇñÒK/±jõꌺ®ÇË2ñ`L³óº˜BPV衲!ƦšVÚüapàä!ä{¦À0MtCðÂþ€±…]׉haò<;W ZZ[¨¬žrӦŠîçB&( ¸KA˜èÔ×7â­˜€/ÏÖ Œ0¦awΨc˜MÓñнmÅD¾¾ ˲íuð¤kÛ2MASSÝnTEÁ¡¨Èv»°éª¬Ñ"d‰Fgc“–…óOO¿s'z dã£O>âŒYgâóùzt\Kk O>õON>áäŒp6;ŸpPC š(2Q»£S 0M+H¦Óå@ "ºa…ð3-A Œà÷‡ð•„rê_µ­ZEÙ§Ë(Óu„ivõK\é ë²€ iôü|VççS8u*Jƒãß4;¥Fáp˜šš¶UW£(*>_!‘p„õë׉D((( ¡¡òòrV­^Íà!ƒñz½x<žœF("Q/]×ñz½I‰ÄŒßÄX#&þÌeD",ÿâ3ššAˆ¸QkÍy·Ö5ÍÄÏ"aN|çgkE‡ÃÉ´ý¦1¼ª*m™-í®{ôjZ‚x=‚a E‘‘ãž#ëf4Ý01„ĺí-\óðûÌ}@Vq qî~.â@AAp¡Pˆ>þ§Óɱ3ŽI¢0ÃÃR×uÌhþ†aÆØ9¸*aÍ Öiõ‡1MÁ€R/’A !F시g_°”@P$Œ®iäyvMÀKÓ4Q%åõ•$ „åm!É0u"‘0›7¬eýúÍ2h05K„2u ]Þiž+¹¢(JŸ N›CTöŒNl[+V¬àÓO—ÆŸ ’þ&Š¥]ÿÆÒMœ¸ûï¿ÿn©T÷» g§kÛŠy’dE&'ót±œÊ$ÛóàF,(ê÷ì‘bó ²»¸¸·¶¶ÄEN;"úûú/¢ûbQí…€¢Â"ÚÛÛ…B¶0ð {䘆 "AˆÚkN·“1“†áv`ùy>V~ºžö?Á`˜P0Œ®Qû(ýTë¤2eUÓPZZ ÖçHÅzjšµ:C¢8ý,÷Pxú&±„‘eù…4˜¦I `ý† ´µµ“—çAQT¶oßNkk+¦iÅèèè`ýúõTUUqÐAQ]]®=µÒuUUñù|I±/nÌðÕu]×ãMÓâé2s)1;;Ò#ÞÓLV¢LSÄ?[õ³öö6 ÅÅÅq#9Ýù¼õUÛš‚(ŠB0¬!ËŠ,#Ë–ǽµ`‰mì¦ibDËVT[ý<þÆ—œÜž§d$̱ã\^^ÎQG…ÓéäwßE×uÎ8}nwúé F‚Ç€mS²¢ EÛVA¾i ê8Lƒû –àaš,Q¡ó:õ­£ït€—ÓE~žw—Cj†¶l)“ñeNL¿•·R]Ûdm:`b†nGž·él‰mkóæM¼öÚKq¡P˜¢Ë÷;Y°LÞgÒÞÞÎÏþ ~üãï€mÌ$´-Uµ~ã¢Þo-­m¬^½ºOÂÓèÑcPQ¾[´¯É„=&³rÅòo»»%ß´mc³«1L#ê1l‰]í]×Ð «_—Øþû*¬Úô!@7Ld3*ļ “à شq3õ[Û¦ lÂr7›¾®N²5zdÇ |Ãè4üM\.e˜9FŒ€ÇƒÚZ…’K v'¢¿Ù½òˆÅ¨««gÍÚ5äççSXXHSSµµµ„Ãan·Ã4lܸ§ÓÉgœÁ3Ï<æM0 ?N§3§òb†~¢Ñ{ubi sÄ9—.Ã0£†¨ µw@²ç@l4ÚïÐÚj)…1!!S§(hpsÐÃðaCÙ¸y È2¦!У õ€=*9¨!íA–À!aÝ;Y’dÐ"Á0…ùJÚ2c×/’$Q\\Ì¡‡J8æý>@Ó4fÌ86í1ºÞƒÀår¡È2DGEÆírÑ ¡——GI¾Õá@7LL Lšf %ˆ}õÐ4†iÑ"DÂa"ZÄzH.§‹ƒ(.*îS9È2º¦¥tŵڨ†$E€¡a„[ÐtÓ4¬)¦å1a†)ºÝ'UU?~<Ë—/OºÏB&MšÄªU«r¾Vªª¦Lkwîv$©»–жLÓzæ$>ŸÒ Ö~ÃÐiii£µµÅ þð„Åß#];³ÝÙm8)ÚVlzžêp „`ëÖ­}ž~úÓ39nÆ1ßÒI&3qÒøò‹ÏwZ~vûJ„„®íúç…Í7…µ<0(Ñ©wwÝý7Áyž<.¾è2L!ˆDì˜ß.Öª¡)ê9nÆ'¦lP¿­-,øC45¶2n¯Ê¨—“÷rêñ³=Q0M>N9Þy† ƒI“ ¬ ¦O‡¯¾²¶ÇÒÆî) Dé±0`--­¬ýz-†n0bÄHêëÙ¼y3qw§ÓI]]£G&//­[·²víZòóó9ðÀY´hcÆŒ¡¢¢"§‘…XÒê[žáp˜ÖÖVt]GÓ4 ÃÀçó¡ªjûœòòr~wÅüìggf®´C0š±@ƒI2P áPÂh¦†CÑq9EC–;ÅóŠøº£FÁ¥— AðÞ{Ö>@ †tè¡— ñâ‹`qÑ)Wb÷D’$\.%%%Œ7–SO9…SO=5iê^¦U0rýžõ誄#¶lÙÂ'‹?¡_¿ ÆŒË×_M $‰‰Dâq–,YÂË/¿Ì3Ï<ƒÛífêÔ©hšÆªÕ«q»Ý¸œN¾ür%á#؆A$Á0Œxð,§ÓI^^ùùùø|¾ø4ƒp8Œ¦ihš÷ ÈÍcÀˆwl_šÛfn`€ººzêêê ‚q\ ËH$BM›@QUEfôè‘DBtÝàê3áõ/ZùbSkýl¨ °bsO½[Íð~yzU óTž@0õíL÷} ë}IdΜË=z4O?õ$›7mäí·Þd̘1üÏUWsÅï~—1ß¿ÿýïüæÂ YõÕJ¾\ñ'Ÿ|2?ò³gÿ:žæ«¯VqâI'!!ñч²hÑ|öYvÙ´MŒØË0Ñu—ÚξœxX¿9Wå’óœvdL6(ðDâÇöJð5MKp¹`Ö,Ä!ˆ×_G,_Žek qGæ‹/ZÁé§cTUѬ)(½)sGC=kV¯âŸ?FEEþæ"~rÚ,B±© dú®e#'a@Akk+_,_NMmÓ¦ý˜––î»÷^^}õUöÚk/ª«« ƒŒ3†µkײdÉbB¡›7ofÞ¼y4440mÚ4êêØºe UUU,ýt)õõ 9}©b€×ëåÒK/åºë®ãꫯæ–[naî̛ܹ7›nº‰I“&QZZŠaqa ×9¬¦i¢i‘ˆídÑãcï5ZZZ©«­£££#aºgFe$¡%¬ (Ö寬HÏÇÔQØÜ Óæ éøƒ F0¤Ñæðþ—;(p'»ª+Š‚P…ØAd“ IDAT¹õD HüÑ—eǃ$I)`ŒÄàƒªÃCUq9]¸=nN'’¢’—ç¡ ?Ï («IÁDF2š š!kÉÁ±²W8¦¹µ™æÖ–øßÚúZš[[Ð YVøÅÏgSÑ/ùˆöŽvFͰ!ÃV9œâ¢ÒŒedE’PG†Ž“„ihÖ=Ð#á6 SÇ4´èÃÁŒŠ¦iX.Q):¥'tõõõ|øá‡!xûí·illäÄO:p³fÍâ‚ .`Ó¦MlذrÍ5× „ˆÇ܈ g‰ù¿öÚk,Z´ˆÚÚZ¦OŸÎ\ðíw8ˆ¯ÄNvж•É` CTWo§¡aGÆïNªr·ßqǼóÎ;¼þúë¬Y³MÓøýöÝwßåƒ> ‰Ä·½üò˼úê«Ô××sÆg0sæLžþy^zé%jkk™9s&^xaÊ2³µÁLíºk^ö+{Û’$ ‡m[¦À– fß…§®^fü7>qÚßéÇÎ䀃áúþ€ßïïŸô£=ùÇcsäÑÓ™“MoÉ&|“ÄúÌ`EeyøõZž|»ŽG^¯fù†@|8N§“Aƒñ§¹·ðì³ÿާK%è<õÔ“tÐAx<ŠŠŠ˜sÙe,ÿâ‹xš¿üõ/„ÃaæÎ½…¡C+)+-åöÛoËZ/!¬x†n$Ø9C×ÉsxÕfÊŠ J‹4òÍxÝ&N·E±<š{30(L"Äȑִ5k0~½±1ÞÑtÈ+¯ ¿ü2RYâ€Є@3Í^K©ùùùLš4‰»î¼“_ÏžÍÛo¿ÍíùK/sKMÖ©º®ÓØØÈW_­¢´´”üÿ|üq:ü~Á?ûÙÏX±bŸ}ö—\|1ÍÍ,[¶ EQ)**¤¤¸Õáà¾{ïåún`ì¸q¬]»–Áƒa&7n _¿òŒAí„°:´··3qâDòòòâñ b^¦i2iÒ$6lØÀ•W^I]]]|d4v£2Ÿ«A^ž—ÂÂ"¶nÝJ$‰a²Ü+[ZÚèèè:§ $æ›Û”AK 6Ç×Ú¦È&Œ¥ª Âê­múj"G‡ Íè4‡µÕíì7¾„`· ò™ëmÜ{ßý\>ç²xÚ¥Ÿ~Êc>Byyyü¸÷Þ{ŸûgÒÒRžxò).ºè¦î=•{Ғžxò)n¾e.ýýne|øáG<ô÷(..â±ÇÿÉÍ·Ìåáÿ{€+®ü~wÅåÜüÇ›Ð4{î½;î¼›®¿6e^6X‚¥ömWÃÆf§ašVÖ‚e DœŽ?|2¯¾· _Aa—t?ÜçÂâÅKºõ2á÷ûyð!ë¹›85öƒ>àŠß]ɪU«ÈÏÏ縙3ùýïoÀëM¿Ì¸Ñv-/8!ˆ„uòœ ›Ñ‚­Ñ?* èáf§Ûi}Ö „È]܉­Þ£é:ÒС¨.úÒ¥hõõ§ z8ŒÖÔ„þꫨÇUU„ZZ0% í[õ…³Îú5ÿûÿdzÏ>˵×\ÓçübdÂá0Û¶mcÛ¶m±fíZ¾^»–#Gà û:t(S¦LáÄOdÆŒø yàïà÷û)..bÈà!ì1i† ¦MùÓŸþÄ-sçR[[KsK ý**øråÊœb ˜¦‰ßï§¶¶–`ÀRëE¡£½‚‚‚ø(·ÏçcôèÑLŸ>;î¸Ç“óÒ!º®“—çåÌ3FKK ï½÷.+W~I[[;ííñ Š1b‚E×Q·LÄDSHÄV5$è_QB…O°eM+þC‘e+ž¿¸)âŽú‰ùY.=ZT×0Ö±3 £×À½ Ò¦‰­é‰¥¢Jº‰D,І„é膂)¬ Í Ñk:aM'¢èz§aœMh ƒlÞ¼‰áÃGàp¹hjl¦jøPòÚ[Û©©ÙNÿŠœrÒOhnz(HSc3{LžÄgË–qÐár¹zumbD"¥ûõ5 CÒ‘‘Fahq!Rt53Ꙣé‘Hˆ®QR#‘0³fÆ7ÞÈã?Î_|ÁSO=~û»lÙ2®»îz–/_NKK `}Wƒä¤ ˜SRRß®ª Á`Ьó “îk[1“N:‰ŠŠþ¼øâB–.ý4þŒŠ=ŸbÏ£TßY!¬€I©–”‹Ýï-[¶0a„¤}²,'µ‡þý+ºµÒÒ’¤6ÙÛUâûLi{Û®m,Òµ-] ëª5ê+Ì> OдHÊç·¦YžmÏ=÷nÿgúõ+àâ‹.dö¯Ïáâ‹.Œ§sÙ%Ƹúª+)+³<¼NûÉ)Ü}Ͻ\uå”–vn{ð¡ÿM:&ñý•¿»<žöŒÓOãÿ~$¾ÿŸ=Oçr99ïܳ™uÆÏÒæeÓ‰‘EÀ·±ù®aD;o|ø#Bj)Gÿx,¯¾·ÑÈÊV’ïõ&Ù?D6mÞÌUW]…,Ëüñ7Å·gòòHô$6t(×]ÛiÐ6770ýè£ùÏsÿæþÎ-sç ‡¸óŽ;Òæ)†@U$„iõ‘dYÂáTz+˜dY”A’m8TN§ð¼¾c¶X®è¦‰f(*`´¶ 1››‘7m‚ÒR‚Ë—^¾UQð†Ã˜ºN`íZDy9æNÔ¨¬¬ ¶¶®Û¾TSprõ¾I+ ƒAª««Ùºm¬ør%åee}ôQÔ××óù† \xáoøõ¯Íĉ9í´Ó˜7ouµu 4ÂÂB¦L™Â¾ûîÀ˜8q¾ÂBî¾ë.Î=÷\Þ{ï=Lদ†-[¶RRR’q…‚˜" 2¨ë:F4è n„£+ÄîìOÏ<“õë×óꫯæl !ؼywÝu'{ï½7Çs,Gu4 .äÝwß»ÓÇHM‰MYÈE (pI¦Àˆ.«¡H²$áðxPæÓ¯›Q%ºd¡eø †òvó 0…@3Š”^H4²À§#—ãc9|öÖ³½*'‘lßѯV­dÊ”=imoÃÐuFŒ¨¢¡¡%ÏK¿ò fw/¿üãöÙ›I{üÓ4ÉÏÏ.¡(1¢ŠH(˜ÑcXµj?úÑz]WU•ã×9†®ë„B!üíDƒZj„±~tb‚’i †¡£ézD`HɆ›iš8.¸à|Î9çn¸ázG’›+À/~ñK®ºê*{ìø|>ÚÚÚ¨¬ߟÎ#×m6»)á߉mK]׸瞻)/ïÇqÇÇO~2‹o¼èŽû±ô±ge×)UéîklûàÁƒyþùÿÄxR—êY×›v•î}×mÙÚu¦ó²IÓ¶Qoº¶¾ O±ý©ˆm¯©­å'³ÎHÚ'ËrÒqýúu˧´´$¾-&ä–”$o ‡ÃIÇ%¾Ï”vÕªÕÜ}ï}¬Y³–ööö”uú¡Ùø~-LiccÅ̺ý™•¬ÝÞÁÑŒgÑÇkÙkt~ÿ«“âžÄmí­ñe h<úpýõ7‡¹ëÎ;8ú¨£r:®qGíííÜÿüyÞ<Î=ï<^zñEÊÊʨ©©áœsÎÆëõrÎ9gsËܹ¼üò+…„@˜&†n"+2ªêÀN¾Z§h‘ØlÂ4 š·«x‹5L|8œ*’&@€iˆxÌ\0L“ˆa ÖÖâD¿~V­Âhk#p饗‡¾};?v,rA‘-[…BÑuúÎæÍ›k¦+}™‚c BBJ¨¦a´µµSSSC[k†apÀþ?Æív³eëV>_¾œC=ŒG}€_üâ,\°Í›7SUU…,ËT­düøq 0¯×K^^‡|0¼ù曌1œ_¬$Ö¯_Ϙ1£³ ªª"ëÖ­Ãíñàq»éèèÀçóYFy4­iš´´´°çž{±xñâ¸Áž Ó´FKjkkyùå—Ù°a³gÏæ¨£ŽbéÒ¥@ò(v¬c¤ëz<¢w,®A:$IBQU<´Ž8P YR$XWb¿1¥|´¦‘ްŽ,Ŧ\™C'õ#¬'vR ¬„ȾôËvØâs 3\G]×1LƒOŸ½UVUÅú«(Ñ¥ åøUˆXu+à£aêñ¿†n ‘púxK–.á?û ^XÀС•4Ô7àÍËCÓ#¬Y»† ã&pÉEsd‰H$‚ÛíFahŒ1‚-[¶R^^Δ‰{±páú$ XF¼å ÑÑÑA[[­­­´î¨aDq3†©`èA„²<bîg’àÃÅËÙ{BºaºŒh†5õ@Nöt‰]û9sæ0gΜ¤m‰ïùx<¶lÙÂõ×_Ÿ´¿´´”Õ«W3f̘”ùgÛf³ëˆy%ýjDÛVÌÓ4=¾®rl• ǃ×ëMEH$Vcû3Ýï³Ï>‹‹.ºˆùóçSUUÅ×_Ím·ÝÆÃ?Ü-mªã{²-›á•k»Nw¼Eª¶û íkgOÙ„þüí¯·3`@ÿ”ûsýœË¶\Û×µ×ÿž³~ý+æÞ|ùùùtttpÔôvûÊ!¬uÝmlvWŸ:ú+˂۟þ’µÛý>m o|´†1½œ{l%µõÛ¬Ažèô+Áë¹PWWÇ%—^Êo,bÊ”)üõ¯a‰{”GAA\p>ž7Ï>ë\Nv„ñÔÔÔtKïñx2ä&pºœ¨.a€+ÏêPq8TdÕÃW[KPä l_g4Œ ˜í&ŠòT]“Ñ4Å!á-p§ô¤L…nšD"Âo¾‰ë§?ÅyÈ!HûíGè¿ÿEÔ×cbýÔªC†PpþùÓ¤åµ×bM3Ø-桇þ€SO=µï™ +:D…Ä‘öÎÏà+,¤¢¢‚üü|‚Á Û¶mcýúõ”–”ÒÔÔÄêÕ«9êÈ#¨««ãµ×þ˘ѣ‘$ ¯×ËøqãRY I%%%LÛo?^ý ‚Á ýôgë¶j6lÜ@SSùùù()Ö‰C‡Åétò—¿þHVóSut…¸\.‚Á®³òScŠ¢0qâ|ðA 0•+¿â­·Þ¢¬¬ ŸÏ7¾ƒÁ ÍÍÍI¢@.A,$IBUÊœ[ÃN‡Š,I¨Še4¯©páÌQ¼µ¼–¥ë,·š©#‹9zÏ8Jl5@«›‚`XC„ý¨J^Fa 6 ·Â@.Ç=–|¨gA‹²÷œs8óÌ3Ù¼y #GŒàÚë®Mj¹¶—lÛrÍ3[»Nw¼EÚ¶%¬àƒB6ag O¦™Ò/3vN:éæþéÏ\~Ù¥ 4-[¶òÈ?ã7þ¾[ÚTÇ÷d[®í+ âÍóàv¹Ø¾};÷Ü{NÇÛDÛ–iî²%m~Ø45æ¾úLiY9Ç_ùTÚý_yxÆã |>®}àÖÖ8|ÚÞüx-“‡—ñû_MËèj^ßP‡×›Ÿs=¿‹üç?Ïó»+¯DÓ4þ4w.gŸ}VJC:æÆž8j}Æ?å7¿¹©S§ ¹ï~ëù:mÚ´xšK£‚Ã>Äyç˃ZqN;í´´u2 ƒa#‡pú9å²,!K2’,Åm²DÛÌ ²›¸¯aõÝ §Ë‰Ã™5ôZ{;k×¢77#Ýsåúe÷ßtûí´¿ù&R8Œ{ÂÊ.»Œ¼¤yáBv¼ð–áÝÛ_’ŽŽ6lÜȃ>ÈO<É!‡Âo/¿¼—¹u³KˆÖÏrKè-(ŠBqQ…>šfE nnn&àñx¨¨èÏÇ}ĈÃ5f,÷ßwãÆ#//!ãÆeìØ1ú|I†¾,Ë :”©S÷bùò/9j4Þ¼<𛛍®®fÀ€)…«ÒÛÖÖÖ$A F*#3Wo°‚ç <˜™3g²|ùržxâI‘e™ã?ž#Ž8Ó4Q…eË–ñÔSOŽºN1HwN§“‰ýë7šDt3þ°Q™æ€ÎÒ-:“Fõc¿‰ý1 A{P§=lR]®>& „uؤH ât¥-/“Ëg®tu“OÅON>•Ÿœœ^¹úó­bòäÉ4Fò¥¥e,_¾œ«~wuëÓØØDSs3çžNÊýEE…x ò9üÐ#p¹Ülݺ…ˆÆåtqÌôcyáÅÜwÿ=4Eç49TkÉÇL^+™% Ã4QT•¢ÂèœvD(ŽA‹„„‰$K¨²Li‘—ê:kyÃÐÑ5-úê*t577ÅW|HEâþ#Ž<‚#Ž<"iÿ9çžßá…rá…Ö\ÞØ¶Tùg+Ófç“êzÇÚV¢QöðÃÿGSS3.— —Ë…‚ D9‰††<O|µ’Ä^I²¦'uuLºß’Ä9çžÃ9ç&¿zÚ^²mK÷>UÚlíÚn¯™Iym$Ó0£S DÜàï³ð”ÅcàÔ“OB’$®ºö:¶o¯¡rÈÎ=笜G÷{²-×<¯¹êJî¸û®½þ”––òÓ3fñÖÛïØ9.ð®Íw SÖø‡³±¡…£Ï+ï­$Ïhijc·ÞþvÆc½Þ|öš²WÎ#λ+]ç¦'ùgŸÓÙ¸úšk¸ºKÀ»Lîë¿üÕ/™7o>Ÿ.[†ÓédàÀÌ™s_tQ<ͧMãï€Ûn»[o»ð?W^Éœ„ ´]‘$dð¥N[qÇòºU–$ÙZ>=Á®‰ ›R£„„êꛚ0ºûîÃ,)¡ü¢‹¨¸ãÊš›‘ji)( M¯¼ÂÆ+® ÐÒb.ÌZBjÊÊûát:)))a̘1Üs÷]œvÚiÅ™D²N/ˆþ¾uJ# ×B’$œN'†a‡1MÇ“­P)7lÀãñ0aÂDþõÌÓ :”ŠŠ Ádܸq”••¥ úçr¹=z4µµuÔÔÔ0|Äp>þ¸ž›61vÜ8\.WJÕY’$ÂápÒÇméÞ§J»ï~ûòÄ~û&í?åä“2oc!I²ßÃæ;)·ÿëK¶6}Àx^ÿp5ãåsþ1“rJ'ËrÆÖ¾ d2s·ž*Ýô£fúÑGg=ö”“O攓OΩ°ìˆòÒÒÔ«¢HõõõlÞ¼ǃßïG˜&S¦ü¨[°ñ˜ý‘Óý-ú[`ÂïgËþ@Ó»ïR:ky& 9´.]JãK/Ñðì³D㢀r ‰oÑ“x½Ž- &t "µ1ît:),ôEç BKK3š®Ñ¯¢‚/¾ø·ÛCUUÁ`Š~Œ7Žþýû§ð.I………Œ9‚O?]F~~^¯—Í›6ÑÔØHqQQ·Ñv]· îX'$–O0DÓ´$ÃW–å$ãNÓé$ÉMØáp0lØ0"‘ªª2`ÀN§‡Ã_ö0Öñv¹\ÄÝ'])Ãá0¥¥¥ D÷€€Š¢PPPÀ¾CÚhXë§½¼yn¦ÀP¬‘A%ºT¡a˜LâCÐL+aX3iéáok£Ò¦  4£‡B*Á¤§ôv‚a¬ß°Žõ×Q^^Á×ëÖˆ®*‘——Gqa ï¼ÿ6£FŒdÄðQ9«­¥¥%”––ô¨.[¶náwßáˆÃ ¥¥™3ŽçåW^Äãq1rĨŸ[WbâN0²Üô[ÛðÈ!¾® Rl„Q£íX’%+ÖB4ø¤‚ išnàñU`"uѵùa*FI¬m—”ð×èTªØs¥ëßÎc:GocßÝX@L#«·Í÷›Ôño¢Â:PVZ¶s„'ûÙõƒ#Sl%›ÝSî{a ëëüÌ8`4/ð5* ™sòûgò;@^^^ü}×Z§ÓIUUEEE455±cÇn K̉ Þ=A : }3Áÿê«Ô½ör~>B–Ñý~ M#64K+êîö)”ä1`¦Ž‘(ËrÜÀT ‡#xó¼Ñ9ÔA&Œ‡i òóó;v C++»Eï( :”êíÛiinaÈàÁ¬ýz-Û¶USYYilA8Æï‚½÷žÊ[o½<+q%€Ø6YîT®c¢Àøñãéhï`ݺuôëׂ‚‚nõ“d‰‹.º]ד椤zÅòîúŠÞ†a ª*Š,c AWSW’$Ün7+Ê8"¸×·Ú;Lò·Ûu©Ç\WLHGì¼²}yË0 ƒÖÖVþõïg¹öêëR>`G ¯B¸åO7sÞ9ç'M?ÉÅû¢'T©IbÑ›opÌôc ýÌœqïø>;(zô–¶Ö ‹Š(.*bÜØ±¼ñÆ"Clm ãrëäé%’,ãpç“_<Õé‰.Shà)BÅÄ£A@옆‘zR¬m†Nccc|{ºàl]§6Åâ±Ä…J!ìùÒ?0Òµ- 9D«d'O~þö6¾ãµ6=@–•Œƒ66»+BÀËj0øÅ1ãyéƒ ì5¢ˆsc‹ßb¶`lZwDÓ‡B¸=ŠŠŠñù )**Ч@’Q•ÚšEFUUGü¥ªjÆAJÙéDTVâ(*ŠýI¯èï©5W_J¶®…@õz!/³ü­ ’b ˆŒ£G4îØaäyÜ47·‰D?n,‡@0È!C:t(ùùù9¬×ëeÔÈ‘|ôÑGø|…€ÄƙӽBÄ—“Œ ;[·n¥®®Ž‹.ùMÚe#EA–e¶WW£( .§3üÊápì\q`ð$$^}õŽ;î\NûL݇ښí¦"÷¼s#!P…€ß¯°€±cÇÒÞÞÁꕟR¥lĪCÉ+ÅU8·o ΂”HDÿ­ÔmY…¦mÇYX‰oøtöˆÛ”†úz ‹âÑâ»¶­aC‡¦ ø¦f‚WOìû£(JôGωÓÙù£—8Üæ‡A·¶%¢:°t+æD0 ¡¡Ó±7ÂS$FÁD˜»Y§Çf—aAiI©=à{Hª¹Êß'¶Ô·ãó:9å€a|ðU-‡M*ç° ´Eï1A ÇÿƒAüŠ¢¢(õÝÏõIDAT „B!Ün7Š¢°cÇ›É÷zQU.—])ÍšféÌ`{”M›Fá¸qHªÚ;Ï^ÓDr8w'15aú_t¹BÒNÁ×4¶öv ÃÀåtáïè@–$FIqQ1€ŸA2bøp|>_ήà²,Ó¿ŠKJCø|>¶×ÔÐÒÒLQQ!Š¢àõz­iá0eåeTUUÑÑÑ]Ï4“ç½'ŽˆÅFü } 8±cÇ’ŸŸo]ñù himKÈÛZN/m7>G?áBIXåȲŒ$Ë(Š `ùùv§ÓIQQß·­õ5¬nvÑqÓòPYîe{sC¤H;J¤r¹þ%ù”•ÂWPÓœøXý- N÷§+ápÃ0²ßßèµ+žÄàÁƒ¹üÒË£±Ò‚ªªäççãr:;ïÏ.z2<IšÆÂpÊÉ?ÁãrQ\\ÒkCIVFŒÅ'Ÿ|̾ûý˜²òrdYbŸ}öfŸ}Ò¯ª UUUTUU%mÏÖ¹Ò4í;;ÍÀŒŠGßUt]ßE#í‘p˜%K3iÒdÑïuê¶%Ç]»{C&Ï!»m}{|ÓmKu83z }ô!&ŒÇét¡bìhMÑÑ =>•,^?IB‰º`ZⓇÚj§(Š5JÒ¥Fï…éo!†ùÝu•7 c—|­UÅår±rÅ ;ò¨¤éž6ß}žþç?¾Ñò¾ bpy>CúåSÛbÚ˜2†”§bg³{›  ª*¦)p8¬ß¨`0HmM >Ÿµœª0­•êZZšikkÃãv'ýv©ª÷öÎ4 ©z½Ö¨ÿ÷ )y¹BÒDaŒúj‘^¯—HDÃårS^Þâ’b"á0ÅÅÅŒ1‚âââ¬#×]ñx<Œ7ŽÞÿ€~ýúQ]½êêjEv¹\8N¦îµwüí¯´··ÓÞÞN‡ßO8&¢EÐ5 ÓŒd€ÓåÂíráõz)))aÀ€””g¼Ñ>ŸŸÏŸ¢¸>s×÷NñAŽ»¢Ä:E±¹\p:âv¹(,l§²­ ¿ßO8ÒLÄ:À©€ËéÄ[èÅçDAAn·;çëïͧ­­ ä”> ^•v¿$I8ºÔÉãñPVÖ{ý]åj3xÐÿ·w÷¾IEaÀŸsîá\*H€ ¥ÚÓúU­CéfkZGãääààâàh«£q2ÆÁQÿ„nSm416Ö’ØÉɦ–jnøp¸\r©`íE.y~ Â=ÀËÇ{Þs^Ž`öâ,VÞ½ÅÌÌ ¤ð¿îÕ0ÆÇÆ€JÞ¯ °½íìánƒ!%Œ&Í;ƒ&RG§~úkm¶ú¨ ”Rª­xiI禧1œ9Œð³gŽ±Õˆ±åS“Ø2M“'NŠEñæõ+lnn¶\Õõ¯ )¡z ¶„Ðê€gzýµ6{!´ t¨#Ó%.Í_F.w »> Ô›æ®v,ßMÓÚäöóÊ&†‚?¸»áÜýbë…Š>ãæŠJ©ZÕßÉÝ¢Ñ¨ÓØ»TrVµi]+; Â#™gÕ\-gsó7?ý‚ç!;[ *{®õPJÕ÷gm–eY(—Ë)…t:ƒD"Ñôö‡ȤÓH&“éòù<¾nl`jêLÃ’~!,Ë‚eYõ½îÞ“›°{—Ϻ/¶Ÿ/B7Ht-¼6oÅ£Uÿ?Ç‹D"‡ÃˆÇã°m¥r¹^RBF½JxÐÀ››Ãçµ5,--ùŸ+•Jaqañ¯·é§7Tv$‹ìHö¿Ü— iŒçrÈŽŽ:U}Z£î‘B ¤5ÌpãÆµ«UlU*eÇÄÄ$Ä4è× ýÌÙ>bsR€¨™VIuÏùÞËûiÖν®yÛ¸xðæ~þÈÛ¼¼ÅÝvs·R¢öÜÜv¯z>{qÅñ©³]uÚ—O±m°üm2¦£øY,t{LDDDDDDD âb:æ,,yòâQõtêT·ÇDDDDDDDDYý¾Š›×n;]Ž i`}+ßí1QÖ·Ö¡¤Ó+°ÞqáéËÇÕ *>4Œ˜ŽÂ4Ì–w@DDDDDDDý¥`P(î Pü%5n\½%€&=*>PýUÚ ~„DDDDDDDÔQ1Ãëwæ~µKyå¼6æÄ‰+<žÏýûOßñ·\X~B¼¹?yy_3³¡3gn*/¯¢”² wî—AGGMOO“{in®_ZZ>uê†-[fªª*êëk}`{´µÿTCÿHÈ$©®NtôhÒ?½té{àN¢šš2˰|ùî$éxyM 4hPW>†!„š;œ›„ÐêõëÊݻτ†â „DF^¸°¾ukM©É-"QýâÅ{Ì͇ÉËûZYX»ö'±˜RJþù ç³}û/,NˆŠúQE¥WVÖ]ÿ9”R“!„xSJßVœÍቋ;çä4VAÁ×Ñqìo¿¥³=ÖÕ‰æÌÙ®¯?HQÑÏ×7,7·ˆkL\Ü9{û`9¹zzÇŽ]UZZ.ÕÚ·KPJy<žXLÅbñ/¿\eÓ‡šhC}½8*êG#£¯|»t ]¾|_ÃùQ ;âïøÑ±ýîÞ}ÆÙyœ‚‚¯…EàÑ£I'O^kß~Œ¼¼¯­mÐÙ³)\U”ÒgÏJ—.³° ]ß©“=”—W±“È ,'w S'ûÐÐõË—ïëT1Œ%B53 ô/ûós“®_¿]SS×±c;©.¯ŽŽz§Níääd¤ºÚÓ§oÜ¿ÿÜÖ­aû–-¿bžŋwBüý;Mšä?kÖ–û÷Ÿ]ºt=:zï† ÓÚµ3Û³g!$5uûÇG Ñâ\ýßdëÖ°””mÊÊ #G.­¯³=îÜy*&&<'gOŸ>çÍÛÁ2/ð.(Øwøðâ_M={›ÔQH5žmˆDõ‰‰K–ìöõu•ìd7цÈȘM›ŽmÜ8=7wo@€OTÔ.h áÊ©Æ4}ì«Wÿoýú©™™;MLtCBVDEý–™¹ÃÈH'(h)‹.22 Ç_mj:ôر¤¨¨¢¢ŸV®œHáN¢T #yW¬˜PTôSTTH|ü%“!ãÆ­ÊÈ(lx!„P³€s“úO••U€††Ê_Nž¡”>}ZºmÛ‰sçÖz{;€±±ÎÇ/æÏß1gÎ(YYþš5S3Æ[•Ÿøð/ÆŽýÔÕUàÍÔ ®x·nŽ„]®8ÛÅ’%c==í`Ê”AAËž?/“‘áÇÆžŒ‰ ó÷ïÓ§.,|°yóqxòä¥XL ´ŒtLLtþy!Dê(¸>´ƒC—^]]«¦¦Ü¯_§U«&5<̆m——ݸñè?Ì8°+L›6¨°ðÁ¦MÇ$K¹¹M”úô¶oŸ5t¨÷ò/}Ù² ݺ9ÀĉþKÖ¬™Âš1n\ßáÃ?}Z¢§§Ù¡Ãx33½³g×téâ yŒÜIlâ BåÇŒéÒë÷ßoŒ½|çαø··åG!„>e3 ôŸÒÖV€/^YY5“’™y«¾^Ü·o$×7­¯WW×>xðÌÜ\OQQ..nž»ûDíÍ›¿ixß½‰â쥥¥!+Ånÿ×Õ‰²³ïŠDõžžv, „tîìÀb†Nì¿úªÛĉkçÎíÑÃÅß¿óàÁ^ogøå—††Ú"Qýùói³goóósÛ´éEE¹†‡Ù° ¹¹Eµµ¢Îí¹6tíê(39²¤M}É==Í¿uìvv¦l¿ÊÊ `n®Ïr*)É€HT ÅÄœ92zâDÿqãúhk«±öp'ÑÒò/¿gÏJccOnÝúsmmÝ‚AÒoãs“B53 ô/ûós“Ì•”ä¯^Íòð°•ìn>|øbĈ%‹éÚÕ¥SJÅb1<Õ¶íŸ ##–'55Çã=zô"#£°k×öR{n¢xVÖàñH£«œ)® ²²\%ø|ÞO?Eegß;uêÚùó©AAËvîAAËØŠdÉ~0Wœ•µ´4äŠs¤zäíÛ[ÈÉÉ\¼˜Á !A6{ëÒ¥ë“&­µ´4 š°êûï§ýúkêË—¯›X÷ÌR|}]/ŸÄVl7üL¤Úàèh!++sõjVÃ6H•’JùÀcgcRõ+(È÷JMÝ–°ª¬¬ÜÃcKd'ñÕ«JÉâÜIOÏɯ^Uœ>½:%%&8¸—¼¼,>= !„Pó…÷½úOQJ££Ç%&fxyM]° ØÕÕúåËW;wžúá‡ø•+'ZXHf66Ö5ÊwîÜXuu•N삜iÓ6xËÊòëêêGŽŒ¶·7ÿöÛa¥¥å!¡¡ë÷(×®e{zÚé¼­8· ©Ž¬††ÊŒ_Í«©ÙÊÓÓ.!AÀ&&€ŠŠblìI±˜Îœ9¤®Ntüøï66&ªŽ3HÖL™5kØ©S×""búôéØð3‘jƒ–V«É“ýçÎÝ®­­æäd™ ؼù˜T¶çÏË?~)U{`óÇÞpœAòe·nŽ^^íïÝ{ÂÒ›8‰lÒTAÁ>33½†+uä8= !„P³€1Bÿ2â-9=‰¢©©zùò¦åËã"#cîÝ{"''Ó¡CÛ#G³%¿’(¥11á&&{çÌÙ^\ü\WW}Ò$ÿE‹ÆÀ‚;²²î¦¥m—‘ákk«mÝ6p༞=Ýìúå—£G/€‚‚}o+.¹ ©.[6AMMeÖ¬-OŸ–¸»ÛFEGDÄ€³³e\ܼeËâÇ*)ÉwïÞá—_VðxM=7‰{ÉçóvìøÖÙyÜ×_7fÌ— S*eõêɪªJ_ýÝóçe..ÖK–ì‘—ÿÿ_móòš&ý1RVvR2åï{âáj . ÐÒjÕèI0  +õ×B!Ô|F§ „þ1„H-i@éܹ{{söÓo”ÒÍ›GDl-+;Åç·¬é”ÄÇB5 -ë !ÔüQJ¾¸$99÷îÝÇÇŽý¾téÞ  ž--`|nB¡fÇú·]üØ h~JKË¿ývëÏ?_~ùòµ‘‘ΨQ~s挔úÁ»¡ÛÇnB!ôN0f@è߆1zŒB5-n¬!„š‹–6l‚B¨ÅÂç&µØùø”áh„B5g3´ Ø1ý4ïÝ„B¡‚s“Bè#Áåd!„š Œú—áøB!„š9œ›„>E”Ò˜˜;wžÊɹW[+26Öñ÷ïy3 O!dãÆ£pøðbÿNPQQíá1955?)é†SÓwî'GšîâK•Šæ^Þ¸q›«nÞ¼Ãek¢Jé»ç”ÌðAB!„Ð ×3 †R*äÈÉõ ÛÌmPJ)¥b±öî=“ž^H)(++œ:µR ØâèhÁ:Ö”ÒÓ§…]º„*)õTQéåí=ýò囬,!„’“Säå5MQÑÏÁ!äܹ¶GB¼ ñÞ¿ÿ|×®SýììFŸ8q…•âñ|x<Ÿää\òf"»û$–È2¸»O"Ä›RzçΣçiiùËÊ~a`0øë¯×WTT³éFR9“’®ûøÌPVÖçË/#RSóYÂÉØ†m7Z„婪ª17æä4¶¬¬‚mÔÔÔá2"„Bè¿¿ÝRÒ¼ÖÚRJ+*ª]\&”––§¦nûâ‹™¥¥åyy{ÕÕU *êÇÅ‹÷°ÿ9utÔ;w¶ïÙÓ=0°G«VJ¬ìÙ³)}úDˆÅ´sgûÊÊšôôee…ÌÌææz<ž())¸»Ûܾýèþý§ªÅŇååeùüîЪ•’££åíÛ‹‹Ÿ«¨(>ztTIIž• ·.[wìØïàííÄsüøeèÖÍQ]]åèÑ%îî“RSóMM[·kg&æ>^6vì—Û¶…4_2ç7ß ñõ ‰ê;v´ãóù—/ßPP»zu³½½9°–[\]­¹íªªÚF‹88´€ýûÏho߆m,[6þcœºÃÖ3 „B¨YÁqôqBÂÃ7™C!„Ðçcôq?=©  ×£‡ Û êÉMÝáñÈ”)ý³³wîÿñÇÈÞÊÊ ¾ ÝÀ:ÐiiàççÆºà;v|{äÈbg®;Þ½» ˜˜´fª«káM`ÀÞ²´4d9kjê@¢ãž,ÄMvâŠOŸ>,Ø©­í?tè¢çÏKmlL¤r€P˜C)3f%›à¼œRzéÒõ†9¹m¡0ÆŒYÉæP/€K—®“?À´iƒëëÅóçï`óæÅþw' !„BŸ1\>CCí3¾Z·îÐÏ?_a[·þ|±šÚ—k×þo%‰;úML‚7¡ H(¥<R_/€{÷žLž¼.:zO``””˜‚‚}ðàÁ36÷I2§‹K[èÕ˃Mp5ªgûö#Fø6Ñ*®ÈÑ£KŽ]ÂaïþôSâ¥K×gÎòüyÛðñqþÎB!„Ž3 ƒ¢  ·kWdçΡkÖ`ÑÑ{Ö­ûºMýiÓ­_xâÄ5[¶36Ö½}ûavö=BÈ’%cYzöìýûÏ]³æàåË7ëêD))yJJòýûw†·ÀŸG à-c  ££öôié„ kTU•Î[+ù2!aÕµkÙ™™·®\¹Ù©“= ÌÍõ­­¥ †… ½z5kΜíGŽ\TSS¾x1³¾^¼eËÌ&Z5gÎÈ~ýf7,Â&PEFÆ88´™;w”³ó8‡6‹¡ïü0Y„B¡1úh!nn6µµ¿²—ܬ]ûµÙ®]§oÞ¼sãÆmuu•=\†öìéÆ2ôíÛñرè¥K÷¦¥åóùk!„j†p=B!„B¨)3 „B!„š‚1B!„B¨)3 „B!„š‚1B!„B¨)3 „B!„š‚1B!„B¨)3 „B!„š‚1j~bcOòx>„xs­Z}Ù£ÇÌìì{”RJivö=ÏG^Þ÷õëÊ÷þÕ»wKí…ýñx>7nÜÎÍ-âñ|de¿(/¯úg!„BèS#ó±€ÐßC)MNÎ;;3/¯ö Õ_»–}áBz@ÀÂ7~$^½ª˜8±Ÿ¾¾¶ŠŠ"!äýö"ä@«VÊ_H¾%++Ó®ùÞ½gYTTÿ£B!„ú„aÌ€šBˆ@ #GúFF²àùó2]Ý99÷îÜydaaàéiçéi÷{INÎww›Í›¿ixpïRJß/,A!„j.pnjfÊË«²²î€££%ë¬SJ_¼xÅf%±—:}ÍãùlÞ|œÛ^½ú€¿ÿ5µ>jj}–.ã&,>|ÑÆf”ŠJ¯I“Ö&'çòx>––¬*¡0œ­†Ü»®®6PVVce5BAÁ×À`pDDLMM¥411ƒÇó±µ Z¿þp›6Õ”zöë7ûÉ“’©S7´n=PE¥Wxøæ÷ž:…B!ôŸ!Øei!šø±ñ¯£”^ºtÝÛ{:Ü¿ÈÀ@»²²:+ëîÔ©RRò,, òòâD¢z5µ/kjê„­íÛ[°mYY™NÚñù¼ Ò !÷î44Ô>{6åË/# ÿΩ©ùjjÊ7oÞ6¬û¾}óD¢z ¾••5]»¶·³3•lÊååeÕÔúÔÕ‰RS·µicЭ۴ë×o»¸´m×Î,!AøìYéÌ™«WO^½ú`dd G,, ]\Ú<ø¥ÔÈHG__«uk'®@aá~ ƒòa~ÄðšƒB5787 5'„¡0‡B)56|KGG}÷î9„@ffaMM‚‚\ûö™™…ÕÕµ=6<|heeªjoJiMMDGï¡”~óMÀš5“SRòÜÝ'€‹‹5ܼy§²²†RzéRæ¥K™Ü^ ´7oþæÚµìº:‘’’¼½½ùœ9Û¯_¿=`@—ǧO ûô‰Œ‹;·zõä””\°·7¿|y“’’¼@sçÎ#gg«øøèŠŠ*5µ> //û~~!„BïcÔœp  mmM»us,,,>>ÏçmØ0mĈjjÊÀÖ.;9YÊÊò‚Bˆ¹¹~xøP(,,€V­”ÌÍõ_¿®ºz5 FîíÛ[°9Hnn6\%¦¦­ïÞ=ذ ìÝÚÊÈðÙèA||ŸïÃå)))¡0¦OÿJIIþÕ«Ê{÷Àœ9# ŒŒBhÝZÃÈHç_þÌB!„>Æ ¨9aã Ò›…£G/‹;—˜˜>eJ ”²»ûîî6À¶ýü\Y|ñÊ•,øã©J9ðfu2Ûöôl÷fY3{Ø‘-ÈÉɲÄ[·@lìI°³3SR’ç º¸X7ºZrl5‚ŸŸÛ–-3·l™ijªgbÒ:0°[$ݺµF›6ú„®¸»Û°úØ£ŸÜÜl0`@!„ЧÇPsÂ:â²²2..Öì½¹¹þÀ]¾¸råþcÇ¢ËÊ*òó€»»-·Í `“‘X_ßÜ\¿Mƒ;wõï?ÇÎÎŒ­Hvs³€×¯«rrî@bb:›Pıµ5 ü‚Íqb±GDDà˜1+§MûþÂ…´¢¢§W¯fééiŽåÇÆ"<=íØc„Âlðð°•l Ž3 „B¨YÀ˜5'ìWÚ·o£¨(Ç=hu„~‡_üå—«·n=¼}û¥TCCÕÊÊðܹÔ7ÛF”Ò’’ò¼¼ûðÇÍ~Büï ÆŒYqëÖC[[S[ ÇÃÃRRòÄbJ)=s&Yrï„ÈÈ@¡0—¢££nn®G î%++³fÍ£G“TT¿Xºt¼¡¡67¦ÁÚÉ¢;Jéݻٌ&7·FÆ1B!„>5ø¬Õ–âóxÖê?hÒ¤µÆÆ­Ç룫«^WWoj:äÉ“’[·ö››ë즵hø¬U„B¨Âqô9b¿ó›[tèÐonn6ééOž”ôêåŽB!„PC8ÎÐRà8Ãß”ž^ðí·[…ÂÜŠŠ*mmµ>}:®Z5ISS' ý»pœ!„j†0fh)0f@ÍÆ !„P3„ÏZE!„B5ÇZ œQƒš ¼æ „BÍ ®nApnúôïÝ„Bým87 !„B!ÔŒB!„BMÁ˜ásG)Ý¿ÿ¼¢¢_YYÅÛòðx>„xâÍãùðùÝy<ƒÁìÝ’’×|~wö®äŸ‚‚oeeͱc¿K•mÕêËîÝ¿¹qã6·–†Rš—w̘•ÆÆ ¾¦¦C§MûþÙ³Ò†-=zùš5+*ªÕÔú?ÿ[«qîÞ}Ìãù<øÀ5<”Ò¸¸s²²_”—W}H=!„BÍÆ Ÿ;BH@@·ÒÒ“jjÊf ”æçÇUTœ®¬b@IIÉmß¾ ÷¡˜¢” Ùîî¶øÌ1„B}&0fhá$ûµ ï¯SJÅbª¥åÿÝw‡(¥»wŸ±·–—÷UUííå5íâÅL©nqNν  ¥ÞÞNëÖ}ͤ¤ä¶mk$//Û°þúzqJJ^‡m¥šqóæEEy%%˜7/ÖÕÕzΜ’å'LèwäÈ%JRZ[+š{v<+k·­­©¿ÿœšš:®TIÉëæii©<¸PVV†«A(Ìqt´l´ûž›[ôêU¥³³`TTTïÚuzåÊý¡¡eeùee¿þš:n\_©¶QJÍÍõËÊ*JKË`ß¾s> ÈÕ£¥¥V^^õêUeÃ#Zµjò‹'””ä%k‹iZZ@XP°²‚Õ–ž^ЭÛt{{ó‚‚}II¯\Éš0a ë÷7L€ŒŒÂšš:ö‰uí:ÕÕÕ¦°p¿@°åÞ½'£F-€{÷žøøÌpv¶ÌË‹»uk¿‰Ÿ_ÊPr IDATxuu-°y\‹í2¤û;¦Oÿ*22æ}Î+B!„П¡%ÓÑéuu"ppa]ägÏŽsØÝwYY™¬òòîSJ·m;accâæfÆå¬¯.yøðùåË›´µÕ¸ô;w=}ZŸÄöű´4¼re“P˜S§n˜9s«äõëʶm—,;mÚ`ÈÍ-ª¯»ºZK…„’’×À&MíÞ}Úß¿³ºº ÷.;(‘¨žR*UVNNúÿjBHvöòòª;#:v´€©S///¯RVV˜:uƒ¯¯ËÚµS!úúZ‘‘#&MZ[SS÷¶t¡0GYY¡];³ž=gx/\8tuÕÆUQQ-Ó˜˜ð¡C}Ø'ܹ³ClìI …9„Í›¿quµfŸNpB!„Чc†–,-m;$&fŒ½üìÙµ::j ÙÉfËyÌåœ,X8wîvÉ>>Î6Lm×ÎŒ»¯?{ö¶³gS~ú)ª}û6\ý”R âã£íìL%w­  Éɹ::ê))1PZZµëö퇿þºNSS•Õüúu%¨ª*Iuý)¥×®eYX()ÉWW×^»–½aÃ4.¥ôùó2>Ÿ§®®ò. šÙhMMÕº°ülB$ª/.~~åJÖ‰˹š55UE¢úüü¦WTT''纸´}ôèÅo¿¥''ç;ö;ÛK]ˆR*ÕËÈð/_¾±qã‘ÊÊšÊÊêž98˜³=&'çzyµg¥4#£ÀÚÚä}N-B!„Ðc†–ÌØX—Rʆôõ5õõµ¤2°q;Ö2Ä{àÀ.{÷ž‹ŒŒñ÷ŸSX¸€@\ܹ5k.X4x°—dq¶°XAAÎÇÇYV–ß°û.æxxØë€‘‘ÎÞ½sí탧Nݰÿ|¶w33=¸s瑉‰®d«JK˸0}ú`ÈË»_[+rr²” u23 íìÌÞqA3k§££¥Œ ŸÕŸ™Y¨££®¦¦œ‘Qööæì „ddhh¨¾|ùªÑtMMU¡0§ÿ.ùùàüùuzzš’;’““õòšjaa>ÌÊÊÈÄD×Ím¢¯¯+O sBCqu 9¶ïr!„B®ghášXÏÀ–ófdººZÿþû OÏÉ ++ÒkÍš)wï>.++€””¼‰×ÔuÁ‚à†59NN– UU5ׯßvs³a¥!ŠŠrß~;üÀ ©©ù,ÅÒÒÐÙÙjÓ¦xÉßj‹éĉk54TgÎ /_¾uÉ</fz{;½ãÄ6ÎPVVÎ"‹Dõ\2ÄØ:쒒׬ý••5»vþê«noK/))/((vuµÖÔT‘¨ÞÈHÇÈHGAA®wïo/_¾)æ=ݲefÿþíìL³²îæç?ðöv€»w?}ZêéiÇꬫ¥¦æ»»cÌ€B¡OÆ -_ïÞbñoúúZ × ddÖÖŠ<<ì\\¬‹ŠžnÜxôÅ‹W<;zô¢££…ººÊãÇ/ šß¶­ÑÖ­a55µÕÕµUU5UU5ÕÕµ¬ó–VСƒ—ÎýÕÕ‰ÒÒ D¢z;Éñ‘#}[µRúþû#\ ±yó7 ‚Q£–fd–”¼þý÷½zÍr~ùe…ªª"°Á>7M(55?'çÞèѽ*55u55u’)”ÒêêÚ7nWVÖìÙs¶  xìØUÕs玀¬,- çÍ‹-.~^XX°°®®~áÂà·¥''çRJ=<ì-mmMçÏßñðá‹ôô¾}gËËËõíÛÑÐP›rèPbiiùùóilUt»vf æBXE)½qãNUU§§Ý¿rÖB!„þ93|¾Ø(A«VJ66&ŠŠr§N­üùçË&&CìíC!ññѰaÃáââç™™·ttú+)õäþÜÜ&ëõnÚtLò-%¥žÊʽví:-äBÜܬ%GTT{:”øâÅ+–îáa+l‰ê¿øb¦®î€±cW¹ºZ§§ÇÚÚš° <Úðòå+.ÌXµêýûwîÐÁJêˆêêDƒ§LùNêÑ®éé…|>ïäɱ±¿8:Žyüøebâ†Ö­5!22ü„„U„›Qnn54T®^Ýl` Õhº¾¾¦@£§§il¬Cœ8±\QQÞÚz¤Ÿ_˜³³åùóë””ä-- ×®²~ý!SÓ¡;vœ\¾|¼*INα¶6nÕJéÍĤlee{{óûD#„B} ‚mi!šø±ñÏ{ó ý¶oŸà II×ýý礥m73ÓûÀ_tFñ¼æ „>eÜ7 ÷­J¼1SþHùŒ¿Â0fh)ZhÌ”ÒaÛ˜è®Z5©ªªÖÍmâ’%cì‚C³ôy_pBÍ@Ëý>Eêóþ ùIèSG3æËÓ§…0yòºÑ£{aÀ€B!ô_Âq†–ï‹ fáó¾Iƒjðû½U·Ý€ ÇB!„ÞÀ€¡Æ`Ì€B!„j Æ !„Bý•Ï{-%Æ !„BopOØDIÀ˜!„B!ÔŒ>w”ÒýûÏ+*ú••U43/ïþ˜1+|MM‡N›öý³g¥Üs·jjêý<='K=‰ëË/#||fPJKJ^óùÝy<B¼¹?ÏGAÁ·²²†+5zôò5kVTT«©õ).~þ·žëu÷îcϧ àÁ> ŒRwNVö‹òòª©!„PËP]]»fÍÁÆ+*ú©ªöîÚuêÑ£IÿÈ“'ëëű±'Ÿ?/ûGj£”ž8q…Çó¹ÿé»ç—ú^–—÷53:sæ¦òò*®Â;w½G )¥‡%JÖÏí¥cÇ)’•ÿýcýÛ-iô$þÝZþÖ52»è##„t<ØK^^¶‰l‡_ Z6t¨ÏñãËÚ´ÑÏË»±ÕÓsÊ•+›tuÕ #£°¦¦.=½ðÒ¥ë^^íÙï'PJ…œqãú€P˜K)½re“££…TäåeYþE‹v¿zU><=íöì93{öˆw<J©P˜«ªªdaaø¿Þ@INÎm×ÎLEEñCêA!Ôü4xnRYY…Ÿ_xUUMTTH‡V••5{÷ž X¸råݰ!òC)MHL˜°¦gO·äw‡$+¡”þe,!äÚµ-ÆÆ:,±ººöÚµì3~xò¤$.n®¯¯kqñaõ÷h!WÿÅ‹,- %ß’“ûS¯ã]ZûÞ(¥¯^U¾í$²^úK3´| ‚>}"‹‹ëéi6úRVö/þ7HMÍ5jéüù£gÏd5¸»Û$$¬ru8wîöØØo@ È‘““6¬ûÚµ»usJiaañË—¯]]mX¾““¥‚‚\£{¹p!}ýúCYY»Ù ww›„Addà;^D!))¹íÛ·áñ>ô¢C)²ÝÝmÿÕKB¡O¥4"bëË—¯RR¶©©)³ÄåË'ÔÖŠæÍ‹:ÔÇÈH罿)ùÿŸÉúG¾q$‡Þ¥6.¿ŽŽš¾¾—nf¦WZZ>uê†-[f¶j¥$ùÖûµG[[­a%·µk¿"QýÑ£I?üp4)i#!„;‰­Z)±}-[6^ò$zyM 4hP׿ì}¶pnR ×ô?HJ©XLµ´ü¿ûî¥t÷î3ööÁòò¾ªª½½¼¦]¼˜I)¥”ΛëêjÍ ¬*¹ ú9rI,¦”Ò””\[[Óqãúž|1›ŽE)MO/èÙs–ªjo%¥žÝºMrX:›‚uò䵑#£54újjö[»ö§÷9s!„>ååU»wŸ Ä @)Œ ¼pa}ëÖšR·öE¢úÅ‹÷˜›“—÷µ²±víOì[ò矯ðx>Û·ÿÂrFEý¨¢ÒëæÍ;ýûÏ¥”š˜ áó»7QœÍቋ;çä4VAÁ×Ñqìo¿¥³ïº:Ñœ9Ûõõ)*úùù…çæq‰‹;go,'×COoàØ±«JKË¥ŽNªñ’é<O,¦b±˜›>ÔDêëÅQQ?}¥ àÛ¥KèòåûÎj8µé?:¶ßÝ»Ï8;SPðµ°>3œ-óòânÝÚoccâç^]] o¦`-Z´kÈîwî˜>ý«ÈȘ÷>}!„þk~nÒõë·kjê:vl'Õ¥ÖÑQïÔ©œÜŸîIB¦O߸ÿ¹­[à ö-[6~ÅŠ}‹ï€~ý:Nšä?kÖ–¢¢§/fFGïݰaZ»vf»wÏ&„¤¦n/.> o+Î|ÿý‘­[ÃRR¶)++Œ¹T,¦¬ÈΧbbÂsröôéÓqÞ¼,sAAqpðò€ï‚‚}‡/þõ×ÔÙ³·I} 7¼±Èúî¿ý–¾dÉn__WÉH©‰6DFÆlÚtlãÆé¹¹{|¢¢vAÞ”|Ùô±¯^ý¿õë§ffî41Ñ YõcLLXfæ##  ¥õõbJiFFá¸q«LM‡;–RTôÓŠ$O¢T¸“HY¹rbQÑOQQ!ññ—LL†Œ¿:#£°áQ|Îpü¥%ÓÑéuu"ppaÿTž=;Îe`÷æeee:t°ÊË»O)ݶ턉››MLLXLLddÖ׋]]­¥†MÙ=u——-))/,,ž9sL:hʔÇéêª 9láîÝÇOŸ–ÆÇ'éêl¡¥¥áÕ«› !»wŸö÷אַ®ÂÒ !¬Ù"Q}ÃáZ©k4ËŸ}§¼¼jçΈŽí`êÔÁÁÁËËË«”•¦NÝàëë²víBˆ¾¾VdäˆI“ÖÖÔÔ½-](ÌQVVh×άgÏYÞ Ž]]õ°°¡C†DUTT‹Å4&&|èPö9tîì{’]ú„ÂBÈæÍ߸ºZ³üG–µ!„ú(ظ´††Ê»Lžyò¤dÛ¶çέíÖÍ‘bb¢ûðá‹ùówÌ™3JV–¿fÍ”ÄÄŒqãVåçß>ü‹1czûâÓÑQÓÓÓ|ú´”÷övcc®8«É’±ì[uÊ”AAËž?/“‘áÇÆžŒ‰ ëׯ#!dÆŒ¯ lÞ|žzôò;ÄâßÞ–ù3„1CK––¶3F^~öìZ5øóŒI¶Ø×ÁÁ\QQÞÉÉòÀ…sçn÷ð˜ìãã¼aÃÔvíÌàõëJPUUjx¡¹v-ËÂÂ@II>)é:¥”]D†ÿbΜíÛ¶ˆˆÌÈ(ìׯ3°IJññÑvv¦’•((ȱG\»–½aÃ4®m”ÒçÏËø|žºú;]¦ÙhMMUvÁ6 !Õ?¿r%ëĉå\Íššª"Q}~þƒFÓ+*ª““s]\Ú>zôâ·ßÒ““sûí¥®NÄnÀÈÈð/_¾±qã‘ÊÊšÊÊêž98˜³=&'çzyµg¥4#£ÀÚÚä}O B¡L[[ ^¼xeiùë (¥™™·êëÅ}ûFr9ëëÅÕÕµ.nž»ûDíÍ›¿iX[ÅÙKKË?òÁnÿ×Õ‰²³ïŠDõžžvÜwYçÎ,fèÔÉþ«¯ºMœ¸vîÜØ=\üý;ìÕðöÛøå—††Ú"Qýùói³goóósÛ´éÉñ|NÃ6äæÕÖŠ¸n:¥´kWG©˜áÈ‘%mÚèK¦èéiþ­c·³3eo)++€¹¹>k<÷u ÅÄœ92zâDÿqãúè訳öp'ÑÊÊèí'ð¾GlìÉ­[®­­[° ¨aŽ&Š·x3´dÆÆºÜ?}}ÍF— …9vì"2dˆ÷À]öî=ãï?§°p?!`f¦wî<26þÓ2¯’’×\˜>}0…¹ÊÊ ööæ //;qb¿ØØ“}út¬©©ã3((Èùø87" ”æåݯ­99YJ3™™…vvf︠™-€vt´”‘áÃîBu55e6¶hooÎŽ‘’‘Q ¡¡úòå«FÓ55U…œþý»äç?€óç×I^×!rr²^^S-, ÃÇYY™˜èº¹Môõue/¡0'4tW'7Ò‚B¨yøós“Ø-¡«W³<=íþ? ¥½1bÉ¢EcØÍo „ˆÅb8x0ªmÛ?õMŒtØwDjjÇ{ôèEFFa—.R{n¢xVÖàñˆäصÄ6à¾w¸%¼<9xpaNNÑ©S×ΟO Z¶s穳g×HÖÌ}íšš¶63Ó#„ØÚš¶mkÜ·odMMÝáË~< ÛÀúë’mh8Ànb¢ËúËcçóyžIÕÈd§… ƒ##G8paãÆ£K–ì>ü‹¯¿èìlÉD[ÉR¾`'±kW‡´´‚M›â¸`kkºhQÈðá_4ý<ÉÏ®ghášXÏÀûfdººZÿþû OÏÉ ++ÒkÍš)wï>.++'„XY9;[mÚ/YU}½xâĵª3g€ää—¶|>],&Mêÿôiɶm?óx„Ýqrœœ, ¬…/_¾uÉÇG\¼˜éííôŽ{Ø8CYY9[G!Õ8paÈoPRR€’’׬ý••5»vþê«noK/))/((vuµÖÔT‘¨ÞÈHÇÈHGAA®wïo/_¾)æ=ݲefÿþíìL³²îæç?ðöv†7S°¸û=uu¢ÔÔ|wwŒB¨¹RP5Êoóæc’ëë!ëÖ¼|ù¦¡¡¶ä7W»vf„¢¢'VVFVVF––†W¯f/\ø#ËŸÿ`æÌMQQ!C†ø-cf$¿[¹â––†¬ÉâÜ®%‹´oo!''sñbw_ Èfo%%ݘ(ÅÏÏuñâ1ññI±±'ýL¤Úàèh!++sõjVÃ6H•’J‘Üû{;ûÆ—zWAA.8¸WJJLBª²²rI„EEyv_¿®’<_ÜIOÏɯ^Uœ>½:5u[pp/ ˜¡åëÝÛC,þM__«á䢌ŒÂÚZ‘‡‡‹‹uQÑÓ¾xñêÁƒgG^tt´ÐÐPJéæÍß$$FŽŒÎÈ(,)y”t½W¯YAÎ/¿¬`  s=<ì¸úõô4‡ ë¾k×i“V­”D¢ú´´‚¬ªªj¤þØl6˜ #Ãç.7©©ù99÷FîÕðSSSWSS'™Âf7ݸq»²²fÏž³ÅcÇ®ª¨¨ž;wtè`eii8o^lqñóÂÂ …uuõ ¿-=99—Rêáaçèhikk:þއ_¤§öí;[^^®oߎ††Ú„C‡KKËÏŸOc«¢Ù<.¡0—âæfÃ.d7nÜ©ªª‘¼5…B¨y!„DG“‘á{yM=z4©¨èiFFá´i߯[whéÒqmÚèKŽéŒå;wnìÿþwþÞ½'‡]œ6mƒ²²‚¬,¿®®~äÈh{{óo¿¶aÃÔêêÚÐÐõ ¨(×®e?xðŒ+~àÀ…{÷žüôS"WœkTGYCCeÆŒ¯æÎ=xð·{÷žÄÄœ`“@EE16ödhèú¼¼û7oÞ9~üw ÕFãèÁSJgÍÖ¥‹CDDÌ£G/~&RmÐÒj5y²ÿܹÛ¿ü¦ Ǥ*þ¼ìÑ£R’wßãØ†’ouëæxøðâ‚‚}¬wããg'qúôì$ZXB ö:´ˆ5j>7 }ž(¥AN«VJ66&ŠŠr§N­üùçË&&CìíC!ññÑìŸ!ÄÝÝF Ø*ÕñÅL]ÝcÇ®ruµNOe‹nß~ôìY)ë(s5O›6¸¶VÄn±ß¸q§²²zÓ¦cJJ=¥því: Úðòå+n«Vý¯ÿÎ:XIµ¹®Nd`0xÊ”ï¤. éé…|>ïäɱ±¿8:Žyüøebâ†Ö­5!22ü„„U„›Qnn54T®^Ýl` Õhº¾¾¦@£§§il¬Cœ8±\QQÞÚz¤Ÿ_˜³³åùóë””ä-- ×®²~ý!SÓ¡;vœ\¾|°¡’ääkkcGB‚lnÊB¡æáÏÏM-­V—/oòõuŒŒ±²ѵëÔÌÌ[GŽ,Úðf\LLxhèÀ9s¶[Y˜9ó‡I“üøa,X°#+ëî?Fòù<-­V[·†íß>.‡í—_zŒ½ÜÚzÔÇ/ÞV\rR;]¶l¬YÃfÍÚbm=rÿþ_£¢‚Yº³³e\ܼkײÇzyMSRRøå—RSz!<Ù±ãÛÚÚº¯¿þ®‘O¨AV¯ž<~|߯¿þÎÚzäÞ½g#"€»UO)õòšf`0Xꯢ¢J²’¿{ì Cˆ†Me®!ššªžÄY³†IælXâ42ç 5K„4üéÊfþñý¶oŸà II×ýý礥mÇÀ-ñþÌ×!„>uÍöûôc¡”þúkª½½9÷Ó±›6‹ˆØZVvŠÇ“Ž.š·Ïû+ ÇÐGÆîgôìé.æPJ++k&MZ·cG !„ЧrøðÅÀÀ%))ywï>ŽOZºtoPPÏ–0ÀçþÜ$gh)šù}‘3g’ÃÃ7_¿¾38xE»væ³fIø¢âó¾Iƒj.~ì43”Ò²²Šo¿ÝúóÏ—_¾|md¤3j”ßœ9#[â2ân»Æ -E3Ðçc„Чcô6ŸuÌ€s“B!„ú+Ÿ÷ üM7„B¨åú¼{9ï Çíjc„B¨EÃðßÒàY«!À¹I!„BýµÏ{=Æ !„Boà° BÁ¹IŸ;JéÿþwaìØ•Ç«©)¿-™Ù0??×mÛÂ%:p༻w§§Ç6QÿþýçYå|>oýúÃsæŒäñþ¿†Ñ£—;8´™<¹¿ÁàììÝZïþˆÕ»w·i3yRrÿþSww[©ßlrúõëD)}Û%›RÊ*—““7nu~þýyóFqï.Z´ûÕ«Šðð¡àéi·gϙٳG¼c³)¥Ba®ªª’…Å @INÎm×Î „úoPJ££÷.\ø#ŸÏsw·ÕÐPIK+X¿þpRÒõ+W6ÉÊ6Õ9‘üÒy÷ë?¥tÀ€. ¡¡ ÎÎãnÞ¼#la58;e/ÿ¿ò†£ 4‘8·ssܪ?r6–ç†üñ,{áVpµ¦<ÖãlºÔ'œÒ »ü9§|®0fhù}úDæ~Ô]JÓWgBHJJxxØqSJiQÑÓÇ_6}‡Â*§”^¹r³oߎ\ .¤¯_(+k7»ªº»Û$$"#ßñ €’’’Û¾}ÉQ‹÷C)²ÝÝm›~Býƒ!7€Ã‡ûûw€ŠŠjÉ©©ùII7||œšþfá~Zêݯۄøøhîå·¹àæÍ;\¶&*¡”¾{NÉ ïä ô©Áõ -œäoö5¼TQJÅbª¥åÿÝw‡(¥»wŸ±·–—÷UUííå5íâÅLJ)¥455OUU©];3É«ž@îÿ˜v IDATî¶%%¯ùüî'O^92ZC£¯¦f¿µkbÙXåóæÅòùÝss‹Ö¬9øÕW )¥µµ¢É“×…… Õ××$„BÚ´1ÈÈ(l´…3flTQéUYY#•.æèêjôï?WQÑÏÕuBnnw°))y~~á**½ÔÕû//+«x[:kLfæ-77¸qãv¿~³UU{«©õ>|ñ³g¥ìHO/èÙs–ªjo%¥žÝºMrXzÇŽBˆHËÉõ ÛÌm°ë§X,€½{Ϥ§R ÊÊ §N­¶8:Zp7§NŸv骤ÔSE¥—·÷ôË—o²²ì‹#'§ÈËkš¢¢ŸƒCȹs)l„xâ½ÿù®]§**úÙÙ>qâ +Åãùðx>ÉɹäÍÜw÷I,‘epwŸDˆ7¥ôÎGÎÓÒò—•ýÂÀ`ð×_¯¯¨¨¦”òùÝ¥r&%]÷ñ™¡¬ÜKM­Ï—_F¤¦æ³o"ØHÆ6ôÍ8CÃ",OUU¹ù0'§±eel£¦¦x}:0fhá¤f5|· àAIÉkwwÛ¬¬»cƬŒˆ|öìxVÖn[[Sÿ955uššïêjÍçó$«JNÎQVVh×ÎL(Ì¥”.Z´kÈîwî˜>ý«ÈȘòò*J)«¼W/„„U„üü¸À¾}ç>|:ûbÐÒR+/¯zõª²a W­šüâÅ %%yɽ‹Å4-­@ ÈŽˆ,(ØG YÁjKO/èÖmº½½yAÁ¾¤¤W®dM˜°†õû¦@FFaMMûºvêêjSX¸_ ØrïÞ“Q£–À½{O||f8;[æåÅݺµßÆÆÄÏ/¼ºº=öòü!„P³E)­¨¨ Z¦¡¡úÍ7lcþü Öã GŽ\rq¯§7pРù kk-­V¬ìÙ³)}ûF^¹’åâÒÖÚÚäÒ¥ë½zͺsç1¼é‚Ož¼NF†¯««‘•uwذÅÕÕµ\81eÊ:§­­–›[4bD4»ëÄuÜÙ$%ðöv0 Ë€]X)ö† ‰:~ür«VJ={º‰Dõ[¶Ÿ1c#ôïßY2gRÒ=Â.]ºîìléädyölr·nÓnÞ¼#ذqÛaƒŠŠòK—Ž¿~ýöÊ•ûÙÆ¢E»p\}:0fhÉttúëèô>|188„èêÐÑé/™Ý­—••éÐÁJ$ª§”nÛv"/¯ÈÄD7&&¬¬ì¤‚‚¤¦æ{zÚI Y9..mù|žP˜CÙ¼ùÿNêê*––†”R¬r—¶×¯ßÒÓÓ´´4”••!„ìÞ}Úß¿³ºº W[]X¤ŽBNNFj­!$;ûnyyÕúõS;v´34Ôž:u°@Õ©S7øúº¬];E__ËÁ¡Mdäˆøø¤ššº·¥ …?Ó§o ð^¸ptëÖÖÖÆaaCÏK­¨¨‹iLLøŠ ´ôô4;wv(/¯úcžjcÇþOŸF„j–!áá› ,Z½‡m°+?¥tÁ‚à~˜accÏž•;öûäÉëìì‚Xš½G,¦óæºtéû””˜Þ~~n÷î=†7]ðY³†^¸ð]bâzJéË—¯ ‹áM`0cÆW‰‰ëÏ[ ååU·o?‰ŽûÑ£KØöªU“âã£ãã£Y©U«&=º²³ïÀر}öí›ùòß}:b„/›Ý$™3*êǺ:Ql쬤¤‰‰ëw숨¬¬Y¶,ŽUÞè8Wä÷߸xqW„e6¬»‡‡íêÕLM[³+W²>™C¨13´diiÛÓÒ¶oÜ8Ξ]Ë^Juý““sÌåœ,XøøñKÉ_|1“»Sòðá‹G^¸¹ÙHÞí¨©©KIÉëØ±$'çzyµwuµJiFFµµ‰¢¢{ËÁÁ\AA.--Ÿ«¡ªªæÚµl//GÉ‹éóçe|>O]]å]î©PJ…Â\MMUîæ…‰ê‹‹Ÿ_¹’5~|?nCSSU$ªÏÏÐhzEEurr®‹KÛG^üö[úÁƒ¿±@KWwÀر+)¥"Q½Œ ÿòå]º„vè0ÞÖ6hÊ”uæJJòìÓkxìÿÔéC¡f­¸øylìI¹=\ØFPPOnêG¦L韽»°pÿ?F†„ôVVVxøðEhèöí“–V~~nì:¿cÇ·GŽ,öñqæºãÝ»»€‰Ik– ÿ²mö»C)ecæo›,$9&À6¦O ìÔÖö:tÑóç¥66& G„ÂJé˜1+Ù§ààå”ÒK—®71Î æÀ˜1+ÙªààåpéÒuò˜6mp}½xþülcÞ¼¦žLˆÐ ×@·dÆÆº”Rmm5Ð××Ô××’ÊÀƸÅÍC†xØeïÞs‘‘1þþs ÷ùù÷ÀÁ¡ •Xý믩ÕÕµ=z¸€P˜:ˆ»> 9¶ÜÅÑÃÃRSóGòcè¼¼ûµµ"''KÉ‹iff¡Ù;.h&„¤¤ä::ZÊÈðY{23 utÔÕÔ”32 ÀÞÞœkOFF††êË—¯M×ÔT sú÷ï’ŸÿΟ_§§§)¹#99Y/¯©†ááìþ½ó‹êèþø™]`—&,M:¢‹QzQ¢`CØlK¢X±ÅÞË‹ Kü©1j‚•hl1M‚%ƲKGq—&H‘^–]˜ßï»/-Ä%óyöɳ™;sî\<ß9Ó®•©¹¹›Ûœ¡C]ɽ´zï¯óÈ( ¥Ó`b¢·xñĽ{/üðÃ}òåË/XºÔ„Bqxøw2™üâÅ-=z÷èaÙ²%‚ÅBë×òzBycÐy†Nj{?Ƹ¡Až””éêjýûï<=瀲²ÒŒÃ÷ì™—“SXYY/¥ËË+fœ LÖ¸}ûi++SÇœœÂ¢¢ OO;ò«L&O'gI¥2RxeemVV9ª!TVV úúÚŠ>úÎdÇ.ì!ó ••5d,G.oŒŒ¼àjj\(/¯&öH$Òˆˆë'z·•^^^“‘‘ïêjMN—ËMMõMMõ¹\•#VÜ»÷X(åæ9²tÌ/;;‹ÔÔœôô<'hëÞ_çyQ(J§c¼uë,[[‹íÛO/Y@¾”–VaŒuu»|ÿý+W~?v,ŠéÐ'%e€¡¡ñ펎|ˆŠz@´còä-ZZ“s&Úš%…ývÁKq$ ƘÅb!„›àÙ³sçîݶíÔ”)CââŽfdœ€¼¼b²öI1§‹KO>܃,p Ö§O©S‡¶csÉ¥K[/]ÚÊ\B~=þöo¿¥,]PRRI¾ èôž…ÒhÌÐù1£©é–‘Qó×¥!„’’2äv..Ö¹¹E^*-­ÊË+¾t鎃CO!äàУÿ>S§n=vìÇû÷S##o°0%%+"b‹…„B1BÈÍ͆¸ÈG²ëꤞžvÀN–9éëk“s'Èd‚’› BâãÓE¢gÁÁÛYR©ŒÌ)3`Œëë=z*‘HOú9##Ö¬]µµõk×€³³Ÿo²nÝñüü’ÌÌ|ÿ2YãÆÓÛJcŒ=<ìø¶¶ëן(((MLÌôó[Íá¨øùõ51ÑC]¸p»¢¢&&&ìŠîÕ«´sï …BAq¹*«ª«%{öD’/Û¶€îÝ-1ž3g³óg£G¯±·Ÿ¾eË)„ÐÖ­³H{õê©¡={¾óòZàîòÃ÷1ÆcÆxAǃv:î ¯¯³gïù装uu ŠÿËãi>|øäúuáàÁKFŽ\åë»,-¬­Íš]¸dI‹…Ö¬9ææ6gÈ¥›¶n=UXXÖŽUäŦkÖsw:ts ‘¶U«ŽöîÝ}íÚ òeË–™J£PÞ4fø÷‚1D]º¨Ùؘ«ªªüôÓÎ~¸gn`o?½Üé¡~øÏ´iCwí:7hÐâùó÷ë _’Îql¬ÈÚÚ¬Kµ—‹sž¨«síí-€)œÏ7qtä÷í;ïòå»`l¬eeULù»v3ÆËÙÙª™…2™ÜØx¼yûðÿîÁHLÌd³YQQ;ŽÿÑÁafaaÙíÛºvå!„””ØäŒ&› 7·9<žÆƒ‡u[M72ÒD††:ffúÁµkaªªkëi¾¾Ëœœø11{ÕÔ8|¾Ixø¼ýû/XXž86ÈTI;÷N¡P( + ¿îÛ·€ùB|fxøü¯¾ZÞ¯ŸýÓ§ÏúéaaaÙ!.?ý´sÊ”ÁäZ?¿¾W®lsw·IHHò$ÇÇÇñ—_­¬L»ã¯<ϰsgˆ©©~ZÚ……eååÕŠÿ[]-ùùç=³f}¬ªÊùå—¸òòjŸ_ WQQjv¡‡‡mTÔÎú¤¥ýq÷î£^½º}ýõÊ9sFÁË5N-­>ܽå%³gû‘øêéÓsÉÉ'´´ÔÉ.W¥åP…òOhÛI@¨•7¾à?ß1êØ±Ïýý}àîݔѣ×$$ëÖÍ:ÇÎò¡ïÔ¤PÞ)ˆ:PÞS¨Ó¦¼„Î3PÞ)! æNŽ›H¤!!{OœXI …B¡P(”÷3PÞ5¡™3?¾~]sçî >nÜG4` P( …Byo¡k“: tö™òA@§¹)”w UÊë@6å%tžB¡P( …B¡´( …B¡P(J{ИB¡P( …B¡´( …B¡P(J{ИB¡P( …B¡´(ïŒñ·ßþ¢¬<¸¦¦î/s‡íÙóÝ9Ñ+-í™3wš™ùs¹C-,-ú¢¸¸‚)9'§Å˜‘‘׬.ŒñÙ³1ªª¾••µ·ÆššºmÛN75áÚÚz-­‘ùù%¿c̘ôwëm Óàôl4 …òrüx‹5!æÓ¥ËÇC†,}òäyaó“'ÏX¬ÎÐêjÉ+û1±8·Y-ä3~üúW.cÜØØtòä ê])ÿ*”þi(ÿ B±±â^½ºih¨¶“ c¼eË©ªªÚeË^ÿ ßç“Oþ8ðêÕÿtïn”–öÇÊ•_zzλÿ6…bMMµ=LšÕ…ò÷÷ž0a‡£ü·jć†LOÿcíÚijjOO»S§n¬Z5¥ƒ÷‚bL¿N `ŒIƒ««sé»/(ÊûñQ`g×mÀ€> —7>|øäæÍDÿ}ƒTUÕΙ3ÊÈHOCCõÕüÆX §8Pñ§Q£¼^¹Ì¤¤ÌO?Ý­®Î ö %P((4fèüDG FŽ\•Ÿÿ½¡¡Î?Õ}Ä OÜÝmÛé cŒoÝJÚ¿ÿBjêÉ×·3>>=(hûúõÁ«WÿÙeww·‰ŽÞåê:gíÚcǯ€¸8qŸ>ÝY¬VêRV~•¡û÷ûùõU¨Q°zõÔ^Ž1&&!¯Ù!Òà4` P(ï!ÄGÀ´iC™•’’Jƒ±"ѳììç=z{zÚyzÚ½f-±±"pw·9|xÉñ‡¡¾OLÌX¾<ð5w(” º6©“£8sÚ–k{ôèé¨Q«55Ghiœ×Ô¡¦6ÌÛ;T ‘< òää,778yò†½ýtg¨¦æˆݹ“LòÈdsçî]¶,ÐØXþì@§ùú.×Ю­=rúô°ÊÊÚ–‹ˆ/>¨¡1\"‘6K_·î¸««50ÛçrUfÏuñâoMMc,Š xcƬUUõuu-çK›´µGÜÝÔTÿÎäAƒ–ƒ+öìùN([ZÅÅÕÖÖ¸y3qóæ©TÆá(?}úgccÝcÇ>€%Kþ/+« W¯nVWç&'g9;öí·¿„‡Ï EÐÔ„ 2e0lÜøÍÕ«÷²²ò1Æ¿ü-ÐÕí²iÓ ºÀ‰òA@c†ÎLBÂ1¸};)88ìçŸÃõõµ€éFcŒóòŠoÝJŒ_¹ò;¹„¸×œœÂß~K¹xq ““ËUáp”ù ˆ||I9ds³»» ()±ïÝ{tðàE‰D*‘Ôçå÷îmIfbcÅ..=•”ØŽŽüÈÈk×óð˜;p Ó {õêõõ >9p`©1/¯øþýÔkטZtt4åòÆÚÚzG¹}÷Š1®®–€¦¦ZËÎúÇ©=z«©q„B±ŽŽ&õb§\ÞH¬ur²***oµqòóKbb"#7´ HÒÉr bsII%›ÍÒÖÖèÈšW²š˜DúèŒIùù%­¶Fzz^[­DüùóÒVoA.olõa©ªªÛ0 ‹KObsRR†µµyûÆS(JÇa6@ÛÚZx{;dfæÇÄ$°Ù¬M:DKKÈjIGG¾²2[ ‘YâåË 33ºtQ³´4ª®®{𠂃‡@Ÿ>=ˆã"KaI!ššjS§Q4 0pÈåEE¦FG ªªjÉŒ„««5DFÆÀ¼ycµµ5Bƒ;ì¬h¹§§©èêÕ{:Q] 66æãÆF\XXFröë׋ c2Ÿ‘‘‡1¬Xq¶l™©££ùÖ[œByИ¡3cff€1ÖÓÓ####]Å_Bééy³×ÐPG1=-ípr²b:£qqiŽŽ|%‰DúøqöŠ“‰»¬¯o¸{7eñbÿºº†öèa²|ù$++Sss7·9C‡º’î¯P(3æ#RZ@€Ï¸q>ý˪UGG^“™y!HKû£¡AîèÈ'ù‰$ØÛ[2AKRR§©££Ù‘Îw·n†ýÜÌL_1yyudäÍÐÐ 'vpà+)±IùÉÉ™úúÚD«„BQÿþ}Újr6«£ã×à>yòÌÈH—ÇÓˆO òeÒ““3íìºupC3Ƙ˜Äf³H~Ƥ¤¤ÌV[£¬¬ª­V" ÞÖ-¨¨(·ú°H9B¡hÁ‚ñL™ˆÌ/Q(ÊÌ3ÀŒ#Höí·¿Ü¾8oÞxé€ H‘ï¾¾ú¨‡Ÿ€««5BŸ_ÜÔ„ÀÚÚ ž>-6›E¦IÉ…}Ô»Õ ÐŸ}¶ûôéŸ54TGŽô8Ð9'§°´´jÐ gÈÊ* µ·xŠOww;¢V¥ à‡“’2B,26Ö%÷8zôGŒ’öéÓž>}þÝw7SRž:8ôøì3¿Ž *Q(ït?C'§ý c2¼!—7š™˜™p¹*#F¬¸wﱪ*ÊË«ÉåååÕß|M:ŽOžä4669;÷$ëìºRYYëîn#Šrs‹ŽY:fŒ—EjjNzzž”—×dd仺Zÿþû#OϹ ¬¬4cÆð={æåäVVÖ@YY5èëkǪ¦Æ%õ’Zêê""®OœèÝAÇjeeêäduèÐåf»æÌ çñ4—. ¡P\YYCÊ—Ë##oø@}}CJÊS77[¦qLMõMMõ™ÆápT€l†Ãgdä;:ΊŠzPYY›•U@Ά"-çN²cm&ó ••5$¿L&gLj«5ÚJg¼­çË<¬±c?êÕ«ó°0ÆÙÙÏ‹Š*<=혖‰O'+ƒ) åðüyinn¼­GmÞ<ƒÍf}ÿýû÷SáÏS•DàêúßéOÏ^/·5“£l@EE™$’^þñãQ`g×ÌÓ2¶ôÃã n@d䯳g×Ïšõ1Y•DæxêÍ Áðù&jjœ‚‚’}û.Àþý ™A" åý‡Æ Ÿ#<ššné¶/qpàÛÚZ¬_"?¿$!!ÃÏo5‡£âç××ÙÙÊÈHwýú¥ÉÉY~~«KJ*Éè†9ßdݺã¥YYþþe²Æ§7 {¤RYÏÚ ŒñáÃK¢£Ó¦mKJÊ,/¯¾{7eøðÏÑ?îÐÔT­¯oxôè©D"=uê猌üY³vÕÖÖ¯] ry£‡‡-Ó8¥‰‰™L㸸ô45Õß¼9¢°°,!!câÄ ^^öS¦ ![5ôõµÉiHqqi"ѳààá-C5bv³ôº:)1éäÉééyŠ&µÕm¥3 ÞÖóeVyyõ¯¿Æ+>,¡PŒrs³!røèQv]ô5;¤P(EÈYFÊÊJ..ÖÄZZ×vî<‹1®¨¨!Ó¤îî¶••µä;`ÅH$œ°´4êÞÝ!4fÌš±cב¾¸››5”–VefæcŒûõëÕêhÒÝk>Ð IDAT?vìÚ¾}ß¼”¨‰““ €Ï>ÛÖ¯ßü²²j[ ‹®¡çÏK ,ìÛo¿ýc¼`Á8X²äÿ¦NÝÖ¯ßüèh¾¾ö_,JMÍ©­­WRb;9ñ™$ õêeY_ß+ 8`@0P> hÌð¯†ÅB×®…©ªr¬­§ùú.srâÇÄìUWçr¹*W¯n/,,ëÞ}Ò¼yût2Ïзo¯9sFÍŸ¿ðà¥ÊÊJ³fäóMtt4ù|“ððyû÷_°°ßÄё߷ï¼Ë—ïÀ®]çÆŒñrrâ7›ê‘ˉÙÍÒ[5‰¼R£­Öh+4¸¹¹A[Ï×ÊÊ´­‡+²¶6#k´0ÆÁuu.=ÓƒB¡¼AÈ;úôéΜ‡1ž={üøãƒ¬¬rz§iee¢ðÝc\VVMVÏ’…C,:wnƒE^^1Ƙ蔇‡¼QRb{x´ò¦ŒqDÄj[[‹¨¨‡ÇŽ]›4i#²nûöÏV¬˜‘‘7õõµví 9rd)ɰzõ4--õ;w’Éþ·Å‹':´ØÊÊôòå»ÙÙϧNòðááîÝÈGïÞݹÜÿž‡"«˜ÔÕ¹;w†Ð€òaZö·($¾ý6 ÆoÞqøðÕ/.¿=×ØØ¤«;êØ±Ï;¾é-¸¹¾¾áêÕí¯\Æø÷ß½&!ᘥ¥Ñ´­3€|€ú å]òÖÔá} $$Ü̬맟Ž40ЖÉ-,^¼(ÏÊ:û~úÞ²²jgçOss‹6mš±aÃ'ÿ´9ƒ:mÊKèhÊ_@Ö•¶Ü öfa³Yƹ …"Ÿ·WK;ÙðÒÒª7„»wÏ}åMid_AHÈÞ'V¾Ÿ¢E¡P(Œño¿¥ˆÅ¹.Ürs³ILÌxñ¢|øp÷÷Í÷bŒe²Æ‘#W>yòìùóRó+&Ñ­Ï”º6‰ò45a¡PLŽ}{µ`ŒgÎüøúuá?5ñ…š4iK¯^Ó}}Ý>ùdØ+»r„Ðܹ{ƒƒ‡ßÿÍZH¡P(EBgά<Ø9;»ð›o¢óòŠgÌqúôÚ÷mB¨´´òÉ“g%%•}ûöºreû_N¡¼‡ÐµI…N=ûLé<Ðin åCÕò:P§My g P( …B¡P(íA÷3P( …Ò©A>ÿ´ åƒ‡Æ  …B¡tjèÚ$Ê+CNÊKèÚ$ …B¡P( …Ò4f P( …B¡P(íAc†;ãýû¿×ÒÙØØônJ»{7eâÄ ††ãTT†˜™ùÏŸ¿¿¤¤òoßUSS§¬<øÜ¹˜¿¼ c¶gÏwµµõZZ#óóK:^ ÆøìÙUUßÊÊÚvòÔÔÔu¼L …BéÜÔÔÔmÛvº© cŒÍÌüY¬ù äÃb d³±X'œååÕlö ò«â‡Ë*‘H¯\ù½Ùµ]º|}nfÖuæÌÚÚ#utFíÙóókbbưaŸkjŽPSæí*ˆ˜Ož¼ao?ê©9bÀ€Ewî$ÿeiÛ¶vqé¹jÕÆ„±±îùó›¼½0Æqqi¾¾Ë54†kkœ>=ŒY”šš3jÔjuõá'Nü—FÂŒñ£GOGZ­©9BKkääÉ[Š‹+HºLÖ8wîÞeËuIíÝ»'%e¶*‹ÔÐ.‘H§¼›š°®îè}û. ô¨¨‡Ó¦mãñüttF…‡ŸÇU°ÙƒÒÒþx#OŠB¡PÞ%í«!55çãWª© ³´œq=$$|Ò¤ÍmùÞ¢¢ „|ÄâÜððó&lP,G$zöÉ'Û}|÷îÏÌÄʼn{ö4mõÈMqqiÎÎ=›ùøq¶ª*GM ëÖwuµ^³fªâ…ªªœÙ³G]¼øÆ€1nh!02Ò! ‚VÕ‚fé­*—‰‰^Ú˜BéTИ¡“£è[v—BB¡ºúh…E×ÌÌ3ÑÑ»þïÿ.EG \]m 55§ÿ…®®6™™g‚#Ïž½ ÚN„áÌ™_ J,Gî!¤««USSW]Ý|Æx×®¹¥¥×TUU%!##¯¼¼ÚÝÝ–L oÞ0(;ûÏ›ª­­×ÓÓŠŽÞõ柅B¡¼}ÚW‰žõï¿ÐÆÆ<;;òüùM[·žºt鮋‹5´á{õô´®_ßJK;¹)³¼¼zìØuººZß}·QYY‰©](98ð[í¾‹Å¹UU''+&À¨­­ˆ¸¾sçÙ Æ)+³++ký5þÓOýZúsKK£ÊÊÚŠŠ`„€)‡AU•¤ek!PSã(–Ö–rQ(ÿBèû:3úúc@&“@ïÞ3ˆÓ,.¾ÊdÀÇÆŠØlÖ… ›íì,ÀÒÒ!DÜzS>zty`à@’ÓË«÷ñãQÄ?Ëå㯾ºfccîêj}ôè²£G—µ_šXœÛÔ„==í0Æ­ŠÄÂ…†u Ÿ‡22Ò]µjjHH¸T*[´è —ž†’ôÏ?ŸßäþýCB¡.<°té!RHuµ¤gO³­[g-Z4ÄâÜÆÆ&WWë–þ¼¼¼ȲR"ÚÚ̯Œ´T¢–B€j_¹(”4fèÌ$$€Û·“‚ƒÃ~þ9\__ ™g4È™tñ1ÆIIöö–ÄÛ*)±ïÝ{tðàE‰D*‘Ôçå÷îmIÆ`zDFn\»ö˜‡ÇÜXhooÙ~iä|!mmV†üü’û÷S¯] cºø::šrycFF^LLÂåËÛ˜tRš»»m^^ñ­[‰±±â+W~'åÈdrŒ±\ÞX_ßððá“)ÞiII%›ÍÒÖÖèˆë'›¹{÷¶ärUbcÅôqqéI®JJʰ¶6'íN”B¡P> ÚWŒqvváo¿¥(údO“ÅB..=Ûñ½Ä%*–³zõW?ÿwþü¦>}º3µcŒ\¾¼è—«±±b}}í¸¸£PQQ³iSÄÓ§¿þºWGG“”\]-MMµfþcüðajÆjjFía„ #s2^óS(3tfÌÌ 0ÆdhÇÈHÇÈH·YŒql¬xùòIÄ¥"„>|B†ðëê XØ£‡Éò哬¬LÍÍ ÜÜæ êÊäô÷÷7î£Ó§YµêèèÑk23Ï"­–F\­¾¾6¼xQnjª¯è|ÃÂÎÜ»÷hÉ’°··d®MJÊàñ4‹‹+ÀёϤ'&¦[Y™òx‰‰³Wq¤!¤¥¥žœœÕÐ g®"wšœœig× ¡6Wî6k¡PäáaB¡hÁ‚ñL9ÈÃÖLˆÇǧù¾ÖC¢P(”wNûê€zú´z÷î®è{­­Í54TÉÔV}/q‰Œ·üöÛ_öìùnÆO&LЬü¸81—«2p “²2»¥O E¶ff`jªúôZ{ûé 8{v=)¹[7CÈÎ~nnnÀ\…1®¨¨‰Œ¼:ÒÒþ B 8xD„ ƒ Bí(×êÕSÛ¾”Bé„Ðý œvV¬bŒ33óKK«˜n½T*KLÌps³¡P”›[täÈÒ1c¼ìì,RSsÒÓó||œàîÝOϹ ¬¬4sæˆ={æåäVVÖ´UÙ0׫W7ccÝsçbMÊÊ*ر㬓“•¦¦”—W“_%iDÄõ‰½É˜“^VV}âÄOîî6 ££ ry£©©¾©©>—«2bÄŠ{÷“l ¯¯­(wî$ûø8v0`hh'%eººZçäU‰i2Ÿîîn ••µYYä;…B¡|X´¯<ž&W0ãú'OÞps³†¶}/㉷Œ‹K›3'|üøþ6LoY¾@ rtä·0ÔÕISRž’ù b§ªªÊŠ“##oÆÇ§“>ßÄÉÉêСËÍ®˜3'œÇÓ\º4„@1‚ž›Ô¾ru¤ ¥3Ac†ÎψMM·ŒŒt[®û Åd®™¸øää,©Tæéi&&z¡ nWTÔÄÄ$m€^½º€‹‹unnÑÿýßåÒÒª?þ(ºt鎃Cmm¶J#cTl6k÷î¹_|qqóæˆ?þ(*+«>þ¶O¨··ÃúõÁÎÎV|¾ÉºuÇóóK23óýý7Êd7NwrâhoÜøM~~É“'Ï7U¨ÆÁokk±~ý‰‚‚ÒÄÄL?¿ÕŽŠŸ__ cHJJlFââÒD¢gÁÁÃ[J—T*“JeÍNçHJÊlh{xØ …b„›› ¹‹G²ëꤤ‰?ÎÆ“Q( …BùàhGzðù&kÖËË+NNÎ;v]~~ ÙÝ–ïe\¢D"-,,?~}Ïž¦_~¹L*m¨¯o¨«“ÖÕIÉ)rycBB†³³“Î|d2yBB†\Þ¨ø„дiC»tQûâ‹‹L qøð’èhAPÐö¤¤Ìòòêß4|øçèÇwhjª‚‚0óññéDZ*Dš%¶¯\oå‘P(ï14fø÷B¶,ÛÙuÓÐP%bàI—.j66æÀ盄‡ÏÛ¿ÿ‚…Eà‰Qaa³ ¬¬!¤¦Æùé§?üpÏÜ<ÀÞ~BèòåmÐViŒ‹Ÿ4iÐ?î¸};ÉÎ.ØÄdÂîÝçÖ® º|y›ŠŠ’’;:zBÈÆ&ÈÍm§ñàÁacc]UUÎåËÛrs_ôè1yÖ¬³fÄ“y„àÚµ0UU޵õ4_ßeNNü˜˜½d›±±”•U1R±k×¹1c¼œœþçŒ"]ÆÆæÍÛ×,] ãccEÖÖfäµncà‰º:×ÞÞ’4‘£#¿oßyïî™Q(Ê;AI‰}åÊv‰¤žÏŸ´ ”í[mù^Æ%^¾|÷ÀïóóK’“³ôõǨ© c>nns€ ¾:tEñ'5µaêêÃ#"® "„››µâPކ†ê”)C.\¸]ZZEÒ=@}…ò.y%u(*ª‹sûöµSRbÀ–-§öï¿ðâÅ•–‡ ½Ÿà?ß±3êØ±Ïýý}àîÝ"ݺÒ Íê´)/¡ó ”N›Í6ÌœÖWWײ÷ĉ•4` P(”Ž€1ÎÏ/öñ Œ¼YSSwïÞã/¿¼ºpáø%`„‹…ˆ`Œ%)0P(¯ (ŒñÌ™_¿.€¹s÷?¾ÿ?m…B¡| „ù»v…lÚ¡§7fÊ”­!!£7lþ°& „š Á¸qÑ€ByeèÚ¤Î]›Dù  ÓÜÊ;†ªåu N›ò:Ï@¡P( …B¡PÚƒÆ  …B¡P( ¥=hÌ@¡P( …B¡PÚƒÆ  …B¡P( ¥=hÌ@¡P( …B¡PÚƒÆ ”Œ±‘Ñx„|š}X¬††ãššð_ž¶gÏwoÊž»wS&NÜ`h8NEeˆ™™ÿüùûKJ*1ƵµõZZ#óóKþÖédgÏÆ¨ªúVVÖ¶sUMMÝ›0œB¡PÞ055uÛ¶VôÃiiÌœ¹ÓÌÌŸËja¸hÑÅÅ̯R©LUÕ×Ósn3÷ñÇ+\Œ1./¯f³±X›y{.w¨D"e®"^ýÕ¼.¡¥'½– P:4f |x „ž>='‘ÜHnlÚ4CI‰]ZzM"¹Q[{ýÙ³óAû'poÞ|²ªªvùòÀ7bÌŽg}|óxš×¯ï..¾zéÒÖ¸¸´ÕÔÔ©©q<=íNºÑñÁ1ÆþþÞQ]º¨µuÆ84ôà1žB¡PÞ Ä;ݸ!düð÷ßßqrúc|õê /Ÿ?¿)%%ËÓs^QQÆcœ””)•Ê3û-…éècŒ…B‘‡‡-…bŒñýû‡ˆÏ'ŸÚÚëQªª*¤Æ«««sÿ®×%´êÉßtóP(64fèüDG X¬ÏŸ—v¦wq¨ªrÈ'%%«W¯n::šä9åö¥âæÍÄýû/:´ä´Æ­[‰k×ߺuÖW_-wtäki©»ºZ_º´5+«àäÉàîn-èx]!ee¥öï!tÿþã×7žB¡üËyãê@¼“§§ñ`ññéAAÛ×­ûäë¯W:;[ikk¸»ÛDGïârUÖ®=†B "¥É“…‡G®Âgfæ—•U»ºÚ€@ RRb;:ò·O>\¢WÇÿ]¯ m{ò7Ò&J§Æ E¿ÙV7455güøõ<ž‡3ÔÕuö±$=..Í×w¹†Æpmí‘Ó§‡UVÖ’ô ¾¶°þx¥šÚ0KËI×CBÂ'MÚL<|KçÌx§ððó&lÀ¯[wÜÕÕzõêÿñ\®ÊìÙ£.^ü¬_Š‹ÛÚZ|ú©_TÔÃ'Ož‘<Ä“y†¸8qÏž¦\®J«6óê¡¿ëuÛòä&&zíþÓ¥PþuИ¡“£è7[wyôèi¿~ó»u3|ü8"7÷¼››Íĉê꤉‰ÞÞ¡öö–gîÞ=xÿ~êìÙ{ˆT…¢ÊÊš˜˜øŸ~Úùã;~øá~ß¾ó¬¬ÌD¢S«WOÛºõTU•¤¡Až˜˜qñâ°°Ùg`úô0bLNNáÀ‹œøiißfeµ±1÷õ]^W'Å?^–—Wüõ×?­\9%#ãŒyÿþ ]]m23Ï Gž={´]qòº°°,/¯ØÅÅZñ6Û±üÌ™_ J,×¾%-Ûp×®¹¥¥×ÔÔ8ŠYYY{çNÒgŸù±X¨Yþ1c¼z÷Z55uUU’–™‘‘W^^íînK¦ã7oŽ”:qÕª£µµõzzZׯïþ»Óî”÷Œé‡~Þî§ þRD¢gýû/´±1ÏÎŽ<~ÓÖ­§.]ºëâb ©©9-3ãÒÒNGFn¨¬¬ýõ×øO?õkæ¯B––F••µ5 ˆ\\zzyÙ;8ôØ·ï<ñÕqqb##]SS} EüV-léÕ1Æ×ë¶åÉ)J3”þi(o}ý1 “É wïÄ¥_e2`Œ—-;ìåe>üzäÈÒ#G–bŒ.<0t¨ I72Ò]µjjHH¸T*ãp”ccÓúöíõõ×+@.o€1‹m%UUY¢úÅ¡}ûÚÀÂ…¦O«©©SWç65á£G—ø½¼z?Eä@ x;w† äÓ§ïð÷÷Ù°á„P×®¼eË6ÕÖÖ««sÉxRllyF0Ú±üäÉë£G{ikkœmY”Ơ¢Òü_ BH,Îmjžžv-ó3yHãËå,S()++9;[íÙóBèðá%®®ÖÀç›`ŒY,B’’eh¨Óñ? …BiFGÔaîܽŒ:tíÊ[½zêìÙ{ÜÜl 4ô ¿¿ÏÆÁ`` Mœ³DRO¼“••)ˆÅ¹M®®ÖͼÙÖ ŽryyMffþÒ¥°páøyóömÛö©¶@ðçf†œœÂ¢¢ŠË—ïŒU´ŸÏ7yðà0BHÑ«Ã+yÝ¿ôä …@c†ÎLBÂ1¸};)88ìçŸÃõõµ@±{ýâEyLLBdä†f=?¿äþýÔkטœ::šrycmm}nnQyyõüùãȨP(f³Y3gŽx¹z5ÍÁ¯¬Ì E††:~~}Iº¦¦*466€’ûÞ½G^”H¤I}^^qïÞ–ªª*+æóMFŒp€¼¼â[·ccÅW®üN “Éäc¹¼‘±*>>ÃQîÝ»;“ÒŽå㇟8°ˆ´B¨-K:"crx‘¶¶F;›•KJ*ÙlV;yšå÷îmÉåªÄÆŠ èCŒqRR†µµ9i¥„„t"Û …òjü¥:dgþö[Š¢/åñ4Y,äâÒ³çL¼Q‡êj hj6?Î!ôðajÆjjœ»wS0Æ$<˜·vmÐåËÛTT”B»v3ÆËÙ٪م­–I ué¢fcc+²¶6#šŠž0Ó÷|¾‰£#¿oßyoâùS(Jë()±¯\Ù.‘ÔóùS‚‚¶“1 ²“ !héœÕÔ8Œwº|ù.ñ]îî6Á—ryãàÁK ÆÎšµËÕÕ:1ñ8ÙœðôéóââŠfsÅ‹Mhh“©ÔG²%’úC‡®¨© kö‰ˆ¸ͼúßõº„v<ù[ma åƒupþŽò¾ƒàÛÿ´/Ϻ>q"*;;òýÙRFNIÒÕuìØçþþ>ï Æ»wSF^“p¬[7Ã÷§þyO;‡?R(”7Ï+©CQQ…XœÛ·¯’¶l9µÿ…/®´ºLè¡¥W§^÷­@6å%tžò†AÅÅ¥‘¹ˆÚ–ÿ‚b±Ð°aîB¡èÄɉ4$dï‰+©tQ(”Œq~~±OhdäÍššº{÷ùåÕ… Ç¿?´ðêÔëR(o3PÞ0d{±‹‹õû6……š9óãë×…o[NȹæÁÁÃÇûˆJ…Bùà@9:òwí Ù´)BOoÌ”)[CBFoØüÞzu ^—ByÛеI…÷fm…Òtš›ByÇPu ¼ÔiS^Bç( …B¡P(J{ИB¡P( …B¡´( …B¡P(J{ИB¡P( …B¡´( …B¡P(J{ИÒ:ão¿ýEYypMMÝÛ(?88lÏžïjkëµ´Fæç—¼Âù]wï¦Lœ¸ÁÐpœŠÊ33ÿùó÷¿ ;) åß ÆX.oœ:u›šÚ0mí‘·o'½Ùò{öœ6cÆŽöóÔÔÔmÛvº© ¿ƒ31ÆD˜0ÆgÏÆ¨ªúVVÖþe½oC+1ÆŒ8¾ÂµT)o 3PZ!+îÕ«›††ê/|óæ“UUµË—ª«s==íNºñwOÔÞ±ã¬ÏbOóúõÝÅÅW/]Ú—öÆí¤P(”-¡;w’Ï‹‰ŽÞ%Ÿöð°}ƒ÷’’ÊÌÌ|7·öÊㆼqCˆ¼ƒ÷êlÙrªªªvÙ²ð÷÷®¨ˆêÒEí/ë}Z‰RSãqü[mŽ1Þ¹óGÊ[‚Æ Ÿèh‹5ðùóÒ¿ëz‚'îîoR$7o&îßáС%cŒ±»»Mt´àoÕrëVâڵǷnõÕWËùZZê®®Ö—.m}³vR(Jç¦}uÀß»÷¸kWÞ€} uTU9oªãŽ1 ÅàînÓN™¡û÷{zÚ½ƒ€áÖ­$"L!„²²‡£Ü‘zß’V"„ˆ8vüÞ1Æ·o'q¨¡1\"‘6Kß¶í´‹KÏU«¦0W!„LLôÞDƒQ(Ê¿‚öÕ¡© ëéÙ¸ñëÂÂ26{н{ÍÍöí»à뻜Ëzî\L«º€1Þ°ák ‹À3g~íÙsšªªïرkKK«,د§7šÇóÛ¸ñRPø„ËUéÓ§G[RRTTXœ~~„ ã–²BjLMÍùøã•jjÃ,-'ED\ Ÿ4i3¹‹¶”¨Ù½ÈdD˜ŒuɽëêŽÞ·ïB³0€‘$&ýõµ²UãÉ}ql5ii iUFÓ©8RÞ4fèä(*A«®çÑ£§ýúÍïÖÍðñãˆÜÜónn6'n¨¯oHJÊ”Jeîî¶II™ÞÞ¡öö–gîÞ=xÿ~êìÙ{@(cŒ7oŽ”:qÕª£µµõãdzû÷_èêj“™yV 8òìÙ‹  íÄ ž9óKAAÉ‚ãˆac]]­ššºª*IKËwíš[ZzMM£x ••µwî$}ö™‹õvGž( ¥Ó¾:°X(/ï‚o󿙵µ×--òòŠ¿þú§•+§ddœéÑä¥.a ¡PTYYÿÓO;üqÇ?ÜïÛwž••™Htjõêi[·ž"=i¡Pìäd¥¬ÌnKJôô´®_ßJK;¹!55§¥¬€XœÛ¿ÿBóììÈóç7mÝzêÒ¥»..Öí(QAA©â½L˜àÍÑ©ŒŒ¼òòjwwÛfMD$IUUEq¸êu´R$zÖªñ¤%‰8VW×5{:­Z5DßÁR.Ê¿¥ÚÊ[D_ ÈdrèÝ{q"ÅÅW™ ãeË{yÙ‡‡Ï#¿9²ôÈ‘¥c¡P¤®ÎíÕ«›OèС.{÷ÎCCU«¦†„„K¥2¡P„:|x‰‹KOàóM0Æ, BCúûûlØð B¨kWÞ²e›jkëÕÕ¹'O^=ÚK[[ƒ€"æÉåãfnNE¥ùß'BH,Îmjžžv-óS( ¥#tD ËŠ‹+úõëÅåªO`çÎÁƒ`òä--u¡¾¾ÃQŽMë۷׉+@.o€1¡¡ÀÀ@[EEIU•B¡è“O†‘/DJ\]­AAJ‚””,CC++Sx)+7“rY™;w¯——=±ÄÀ@{õꩳgï!£þm)Q³{ÁaÒÒR'í Š”••œ­U!ÔR’^S+‰ñD»vå1Æ“ ÇfJ×–%Œ8Re¤¼%hÌЙIH8·o'‡ýüs¸¾¾0NcüâEyLLBd䆖.)6VìâÒ³°°ìþýÔk×ÂÈU!M¹¼±¶¶>6V<`@—žäÚ¤¤ kksUU•¼¼â[·ccÅW®üNJ“Éääüúú†‡Ÿ8°Hц’’J6›¥­­ÑÁ•£älŠæ§P(JKÚWøsù!Dúß±±b>ßäã= /¯¸-]ÈÍ-*/¯ž?ÜËη˜ÍfÍœ9‚t‚ããÓøÊÊ쌌ü²²jW×?K0  0ÆŒ”@BB:é@·%+y¿ý–¢h §Éb!—ží(‘â½`ŒabT)6VÜ»·%—«ò—*ó:Z™]HŒgêeŒ')Œ8vd€ !Ĉ#P£¼%hÌЙ133Àëéi€‘‘Ž‘‘®â¯!‘èÆØÑ‘Ï¸˜ÔÔ##]OC(óQff>ØÛ[2N-))ƒÇÓÔÑÑ E ŒgÒ‘‡‡-¤§ç@LÌ^CCź´´Ô““³䎎|EYJNδ³ëÖÁ…F!}}mxñ¢ÜÔT_Ñ-†…Y½zêë4…B¡üKh_c'¶±1ïÒE „BÑ!.¤ëߎ.DG X,4`€É+rpèÁŒß32AFúÉw"%LW›ä!ùããÓƒ‚|¡mY‹s wïîŒ%‰‰éÖÖæªdu«JÄÜ ©1-í"LLŠP(òðèÐh=™gx5­|ú´€ÏÔKŒ×ÔT#9‰8vp¡ƘG33Åô;ÎRq¤¼è~†NN;+V1ÆŽ 44ÈI¶ôô>¡ÞÞo¯ ) ¥óÑ–:€\Þ˜îæf bqnU•„éø¶¥ Š™€ $À'&fÊdr„"ò…‘’GQJ?Î&c牔‘•‚‚ÒÄÄLFVzðù&kÖËÏ/IIy:vìºüükh[‰ïBŒ0’’2äÍæ0ÆD’ðÿžSôzZù§ñyyÅÉÿÏÞ‡5um _; ³f™§ A Ȥµ¬uªÎV¯¾´úÕŠ¶hªVÑgm­õZÔ+z«·jë€¶å ¯µ5TL˜°Ê,aL`ìš› ˜bAŸ~ì³Î>Ág¯³ÎÞç$«@ÕyvÜ´´–Ûßìk߆Çã²ä¸n]°õª !€cBÏSÏ ¥´¬¬F&+8P¤£Ã€µkãwî<ñàÁinçsJKK+KL'?ÏLôða5ë<Ç€uë©:ÿË/7Xrtq±ynýy"´Ñc8Ï€žvãgĈ@‰DJ)­¯oš3gûþýK±`@!ô´!%%e!!QÇŽý»¶¶þ—_nüýïß/X0þ© àr9,1=ÏLD)Uu^.o¸r妪ó Í,9öˆ‚!58Ï -^’;I/¦.^üõõëÞ£§§Ë’%S°`xµà-+„ž³—$;ü5[·~»gÏ÷ÅÅe}ú˜ÎšõîÊ•3ØmûΣ”þøcKLϹlضíx›Îs¹–?ýô½çÖ“?ƒ6z km¡ÕYiL?=g˜PWà õI!„B!M°f@!„Bi‚5B!„BH¬B!„Bš`Í€B!„ÒkôüÈå ë×nm¥ú¶.JiDDìÖ­ßÖÕ5òù£KJÊŸöX”ÒË—¯Oœ¸ÚÚzœ®î;“æÍÛùW;ŽB¨PJåò¡ IÝ“å‹.¾’Rzôh’Áðšš: mT‰L•žþÂq1=¡—Ö è9¡”FEíºxQBh~6¥tݺCÕEGO64Ô0@tèÐŧ”)¥›6%„„,255¾paKYÙ÷'OƤ¥åtù$Býu„k×r[ZZƒ‚DÝòªwõ|ÑÅ_W „Lš\]}ŽÏ7ÒІ%2‡é³ôô´Çݸñ(¦'ô2šAû%&Š9œ!÷ïW¼Øßâ „üúëÍDZ0\º”¹sç‰Ý»?&„B…‰‰âÎÊ”ÒääÌ•+÷ÅÄÌŠ‹[âã#àó„'OÆtÇy „–xþÙR*‘H--M\\¬»þjmòE×»§£ÃÓÓÓÑ|D–È(¥”R–žžêÛ»t)ƒ¥§o¾YÌÒ“¿¿;¦'ôRÀšAË©eí‡TJiUU-—ûö¹sW§O_ojjf6fÛ¶ãªOoܸ=fÌrcãQ|þè©Sו•U³2;»ðÝw—ŽpqyïàÁ sæl{ï½µl¯ŒŒ¼#–24%K)¥V"“mÛv|„Õ"+-‘‘Û££§ØÚš³>¸ºÚffæw8(/Z´«W¯‘õõMmNsýúÃ~~}—-›¦¾ÝÎ΢›¾T„zéiÎŒ£ãä;N ¾X_XBBR‡ÃûŸæ‘ììÂ1c–tršrà@bZZN` 1--gøðŽz41ýþû±ªEA«WpršräÈÏ}ûN70>vìÊŠŠGóçï´°35 ]³ææ‹»ÑÉÜA)mm¥ææa;vœxRœ‡«¹Ü·e²¢­[¿8q °ôÔanU¢ÍvUzRíEÁô„^ X3h9õ±¬ýÐI‘Hd”ÒµkNžüö;Ç¢¢&.[¶W.o`ý[o-ð÷æç‹÷ܽû`ÆŒ “½õÖ¡ÐñÎcÇsèäÉË~~î”ÒÂÂ߇ Yäë+ÈÉùgAÁQ¡ÐqøðÅÍü ¶Brr;¶ºÃÈlVáÈ‘ŸJKËçÏÇzK17çËå µµ múO)ݼ9²¢âŒ®úiVWËSR2?ü0ôOA!„Ð+Ksv€ÒÒŠââ²Î/]:-/¿{‡Ã;hÈ#2YÑ›oÎwrꓟ$1qóW_LLûû )¥yÁÁQýú¹äå¹|yׯ¿fÏž½•‰´¦Fž”tíüùMgÏnüá‡_œëææ •Z¾|zLÌ¡Gê@=_PJ;ìF]]cgr!$/¯¸ªª60ÐãIq,,ø‰‰› !¹¹ÿ!ΉL °c1Ué‰RÚæ(íAQ¥§öíêù°fÐfééqœœûãÛ,-ù >TBRSeƒ¿ÎzJiffž»»£nqqÙ¥K©©²Ó§a %¥4/¯øÿþïú™3±,!ÄÔÔ˜Ã!llåñ¸W®Üصë»úú¦úúÆââ2//]HOÏ RJŸY©lill¾zõÖ_,Tïayy —Ë11éÕ™A–"—7@'Û#„Ð+¨“ÙA °{÷Ý öQ‡Ã;»þ¤Ï å4¬Xe<|X­ZÆ£P(¯]Ë ô33cP*[ìí-íí-õõuGúôÊ•›¦¦Æ zdY.oˆ¿à‰´¨èáž=ŸŒû¦§§svvannqHˆ/¥´ºZ^PPª92TVÖ€¥¥‰ú½®””¬ŸNÞ•!„xz:ÛÚš'$$©?Üvûöýví»D!í¡9;´¶Ò´´œ  ‘êrœ ïááƒD"'Õðòˆ¾¾.TUÕ>~TZ¾ÿùÀ@!ê³Ø^õõM^˜81ÒÒd"‘sïÞ†ðŸKö?ÞSÔØØœ•Uàï/„vùâÎû¬¬¥RÙºÑÉ‚¡¹Y™™™ïïï®:6q ¦¦Ž%2U9ÁÒS‡OƒtxUzRïUAA)¦'ôRÀšAûÔÚzÉÆÆ¼ýšN‰DFaK†(¥7nÜihh0@ÞÞ§U«ö—–Vdd䇆.×ÓÓ èíýš@`·bE\IIùõë·ÇŽý¬¤¤ÜÏÏìì,!'N$WUÕþüó5öÀ´§§3ܼy‡ÍÔ×7=)2°»5<W5§¥åH¥w#"F¶OiMMЦ&EûÁšÇãnÙùå—ß­[ïÞÃÊÊÚ'RBB¢‚ƒ½ŸÍŒB/% ÙA&+zô¨^ué¬Þ««åIIéêû†<âë+°²2Y³æ¥¥RiÑ”)Ÿ?|Xàýû» vŸ}¶¯¤¤>‚çž:uùI‘ÀÖÖ*+©îâlÞœ>È×WÐæ–˜RÙbk;aîÜÞCš:uèÙ³““3E¢;» [¶$¬\9ãÔ©õÏãkE¡—»»ojjìæfϲƒ@`÷¤á]CÑ××=uj}Qу×^›:kÖ¦Y³FSJÙ‹Vy<.{‘P8# à#SÓ^¿ýöµ™BÑ’™™ß¦H`KƒØcÙ|¾‘»»#üw¾ „°n°Ÿcc-Y7:“;Øùöîm(:>)üw"–žú÷wkóí)Jvˆö·´!ï½÷6¦'ô’"œSC=!@“ŸõA(¥ee52YÑÀ"¬]¿sç‰Nëèp»þPWKK«¹ù˜¸¸%l†ú—_n„…­HOsq±é†Þ£ž€„Ž9=OÏ%;<êùâùT* Í IDAT?R|ùòu–žœ»áÇéz4´Ñc8Ï€ž!¤¤¤,$$êØ±×ÖÖÿòË¿ÿýû ÆwKÁ\.gĈ@‰D Ísælß¿) !„ÚPå‹çÉ^_ßÄÒ“ö ©Áš=__·Í›ç|þùA ‹ðiÓbæÌ [½:¢»MJéÌ™ï^¸ €ÈÈí#Ç«["#„Ò&ª|ñœ—KPJYz7îM,Ð+×&i -}FÚ§¹zÎ0; ®ÀA=†ó !„B!M°f@!„Bi‚5B!„BH¬B!„Bš`Í€B!„ÒkôlQJ#"b·ný¶[ÞÐE)½|ùúĉ«­­Çéê¾ãà0iÞ¼åå5”ÒººF>tIIy·ÄìzWBuf „z>¬Ð3D)]·îУGuÑÑ“»þkJé¦M !!‹LM/\ØRVöýÉ“1ii9ƒ/”Ë õ :tñ©RΓbv±«!„: 3B/¬´_b¢˜Ãrÿ~Åóÿá›K—2wî<±{÷ÇÝ’’“3W®Ü3+.n‰€Ï7 ž<SPP…‰‰âÎKCÌ.ö!„z¾•Ôa¦@èe5ƒ–SÏO"ãã/öë÷¾žÞ0cãQƒ/LIÉ¢”Þ¼y‡ÃòÛoÙ¬MMM÷vBB¥tõêNNSŽù¹oßéÃÇŽ]YQñhþüa¦¦¡kÖüƒRJ)U(Z"#·GGO±µ5g=ÉÈÈ1b‰±ñ(CÃÁÁQb±´ÃDµhÑ®^½FÖ×7µéüúõ‡ýüú.[6M}»ÅñãŸ{€««mff~·ÄìÜ·‹B/«Îd‡ììÂñãW™š†êé ó÷Ÿ}ñb*Ûž––3|øâ^½Fš˜Œ~ÿýØšš:¶ý7æEG¥¯?, à#™¬ˆm_¹rßë¯ÏT·ºZާϸ͛a¦@è%‚5ƒ–SÏ‘7oÞ™9sÓÒ¥ÓÊʾÏÎŽ÷ðp [ÑÔ¤‹¥ºº<__7VH$ÒÖV艴¦Fž”tíüùMgÏnüá‡_œëææ •Z¾|zLÌ¡GêàÈ‘ŸJKËçÏÇ"ܽû`ÈE¾¾‚œœ ‡_ÜØØÜ¦W”ÒÍ›#+*Îèªw¾ºZž’’ùᇡ„´Moáჼ¼\ !ææ|¹¼¡¶¶¡ë1BH»ýiv¸qãöoÌsv¶¾yó`QÑñ€áĉ«š22ò‚ƒ£úõsÉË;rùò®_Íž={+¥´©I‘‘‘÷Ýw)±±³óòŽÀûïDzñ_$rÎÏ/iiieÇ]·.ÞĤWTÔÀLÐ˃÷¢;€ž!KËpP(”àåõìÊʾW5 ”*•-”Òo¾9#:úû»ïݽwo4¥45Uêë릧§Ãöºzõ–…ÿµ×l 55gà@Ï–€RÙsæ„/\8¬¬Ltuyz!,lŸoÄ"´¶Ò½{O™2„wÐ ¯}ûÎQÚv&„èê¶ýoI)•ÉŠZ[逢' Ù”Rv¦JeKwÅD!­Ô™ìýõ Aý¶m›Ë>ݳç“={>¡”.XðŰa~l»ù²e›3g[S“âúõÛMMŠ/¿Œzã OX°`ÂûïÇÖÕ5é÷ëçÒØØ\Xø»««LV´{÷éï¾[dže̽,°fÐfééqœœûãÛ,-ù@)U |„oï׎[³re\PPä!¾_|± _?BˆX, ña-)¥©©²À@!¥4/¯¤ªªvÞ¼qìD"ãr93gŽb-¯]Ëñöèèp›¯^½õÅ Ux<î•+7víú®¾¾©¾¾±¸¸ÌËËÅÐP¯3'B‘ËÀĤ—zÿÛ´)/¯ár9Ú>¡¡¡yðàÙÙ…‹¿wøðÊÔÔ½öö–ÆùwòÁ;J©¥¥ Q55)ššíï*ñxÜ-["¿üò»uëâïÝ{XYY{âDJHHTp°÷ªU”Ò´´©ônDÄÈn‰Ù_3oÞΡC?ÑÑáÍš5Z °333V(Z23óÛ AA,a‹oñùFîîŽ`kk••XKÀnÛ¶¹;wžprš²ÿ¹ØØÙPYYÛæF—RÙbk;aîÜÞš:uèÙ³““3E¢;» [¶$¬\9ãÔ©õ::\ؼ9!<|¯¯ [bvóB/==sç6–•U»¸¼7jÔ§ÁÁÞgÎÄr¹›˜¸™"ÎøÈÔ´×o¿}mcc–ššC)=s&vß¾³¯¿>³¸¸ìÒ¥}ú˜²hìn}S“"&f–êqgJ)f „^"¤“ËQOGÐä݉ÿhii57·dâÄàgýÐ¥ô—_n„…­HOsq±y¦ÇB]EBÇ„ž§ç’bbíß®°ðÛ?¥”FDÄÞºU(ÿËýÏÍJÌ/´Ñc8Ï€ž .—3bD D"}i ¡¡yΜíû÷/Å4€BÏ[óÃ^›ÑþÓý+eíڃǎýûë¯?Q/3B/¬Ð3A)9óÝ $Ïz"‹¹="bäøño=Ó!„ê{|ÙÏϽý¥?¥tÖ¬ÍqqçXÊžvkó)f „^¸6I[ô°µIu §¹zÎ0; ®ÀA=†ó !„B!M°f@!„Bi‚5B!„BH¬B!„Bš`Í€B!„Òkôt(¥……¿s8CòòŠÛ*—7¬_¸µ•vËû¸ÚGc? ´uë·ÝŸRzùòõ‰W[[ÓÕ}ÇÁaÒ¼y;ËËk(¥uu|þè’’òn‰Ùõ®"„Ð+¥»Fû²²êO>Ùíæö7}ýa|þè  ÈíÛO(Jöé“r¥ôèÑ$ƒá55u¡ç˜AVš=BˆD"366|í5»öƒlTÔ®‹%„@× §}4Jéºu‡=ª‹ŽžÜ-ñ7mJ Ydjj|á–²²ïOžŒIKËßèiJÁ ‚´Ö Ú/1QÌá ¹¿¢»îͧ¥É^ݵÃAö×_o ê–_ôlRzéRæÎ'vïþ¸[ †ääÌ•+÷ÅÄÌŠ‹[âã#àó„'OÆ”ÆÇ_€À@ab¢¸óÇÒ³‹½E¡g¡{³Cwé®ÑžRšš*ËÎ.ܱc¾Ÿ__ccCó3†ÇÆÎ>xðB]]#hÈY::<==¿vhBf¤}°fÐrê™àIƒW|üÅ~ýÞ×ÓflaÂjJ©£ãä;N ¾X_XBBRFFÞˆKŒGŽŽ‹¥ªfgŽ¿ÊÔ4TOo˜¿ÿì‹SÛGS(Z"#·GGO±µ5g{µØaÚ[´hW¯^#ëë›Ú|ë×öóë»lÙ4õívvÇì ®®¶™™ùÝóOÿL!ôœu&;¼ñƼè诃ƒ£ôõ‡|$“©öÕ0·ü;L1”Ò7n³ÜØxŸ?zêÔueeÕl{ûѾÃmÎE5,«Ÿ”•• lß~œU̬Yï*IõõMÎ'嬣G“ÌÍÃvì8QUUËå¾}îÜÕéÓ×›š†š™Ù¶í¸êèÙÙ…ï¾»ÔÐp„‹Ë{^˜3gÛ{ï­egi¬´œz&èpðºyóÎÌ™›–.VVö}vv¼‡‡SXØŠ¦&…X,ÕÕåùúº±áO"‘¶¶ÒÀ@ÖVšžž'ßZºtZ^ÞBÈl þ… [!99‡[}ÿ~eqqÙçY3÷!Cùú rrþYPpT(t>|qCC+NÞxcž³³õÍ›‹ŠŽ'N\Ý«—z48rä§ÒÒòùóDZþܽû }ÀÆÆæö‰dóæÈŠŠ3ºê_Euµ<%%óÃCÛÏ–„‡òòr%„˜›óåò†ÚÚ†®ÇD¡žæO³CS“"##ï»ïRbcgçå€÷ßýÓ¸´´B}ð ;L1ÙÙ…o½µÀß_˜ŸT,Þs÷îƒ36B!mFûììÂ#´¹àfò¡¡žú)¸¹ÙoØðÿöî=ãìuêºÂÂ߀Ã!rVFFžŽ¯7‰DJùúëÇŒÈç v”R‡‘‘Û ê·mÛÜ>}L„Ë—ÿ­¼¼& @øx¶3Ò6¼Ýô ¥§Ç@rrfDDì?n³´ä¥T5$B¼½_;vlÍÊ•qAA‘C†ø~ñÅ‚~ý\!b±4$ÄGõ,Ajª,0P‰ÌÌÌxìØ7Ù½vSG©l€ôô\6\@jªL °5*Eàñ¸W®Üصë»úú¦úúÆââ2//ݪ’’Ò[­Þ+vDõhÍW¯Þúâ‹…ªþt°Í¦'!„Èå `bÒ«ÍqÕÛ”—×p¹ mž6&BõɉÔÚÚ,4t ‡  ¥¥ž0¤³˜ þï¾ÄâøøÚ¤OOçââ²K—2RSe§Oÿš)Jv«Íhÿ¤O5ÆöïïvèЊ­[ç~ùåwÛ¶}›•UpëV½qãvXØŠÖVZW×xóæÀ@v¿¤©Iqùòõ€HK“y{ ¸\»”••oiibbÒ‹ríZ®¿ÿÓ²‰ôwüرêë›^]¸xñ{‡¯LMÝkoo9l˜?H¥w)¥>>Õ°›]XYY êÑrrî57+}|¬? Íìäc|”RKKxð ªM¡{$4t»­•••/9wršXsÌÎô !„ž›?ÍìV‘HäÄÆ@6Ú÷écÚ»·¡†˜-d}ç?õÑxòäõC)äæ@RÒöôô8öïÆçóÔG{ þt´gÙä³Ïö©#õécºaÃÿÛ°áÜœ{ÕÕrøï,£ž³ØY‰@"‘úŸíb±4(Ènß.//WUüŒŒ\wwGccCøc–3Ò6X3h9 +V)¥—/_0 ttx3gŽÚºunaáï55ò[· [ZZû÷ïËÓÝ»O×ÔÔ©æjjä,¬B¡;öMOOçììÂÜÜâ_ÐÓÓ€æf%k™—Wâã3ëܹßjjêTÑ(¥¬Š°´4Q î,`xø ‘ÈI°“÷f!žžÎ¶¶æ Iªï„Rzûöýúúºñx\BHJJ–j¦¥‹1;!„ž'ÍÏ3°‘¶±±™5kjR>üÓäÉCàI#0´¶R6ø³½ÔSÌŒT¥33cP*[ìí-íí-õõuGúôÊ•› >ÚkˆÐ™;÷<÷СÙ= Õiéêê«g™69«¹Y™™™ïïï^XøûÇÕü±]©l¹v-70ÐLM ¬¬šõ¤¶¶>>þb@€»ª„À ‚´Ö ÚoÔ¨ ÖÖK66æígüüÜ‹Š~õÕ©ŠŠG÷î=3oÞΡC?ÑÑáÍš5Z °333ÎÈÈçr9çÎmܷ﬷÷Ì߯LNþÂÚÚŒ"Øùøœ{êÔe±XjjjìæfφE77ûmÛæîÜyÂÉiÊþýçbcgÃã›Iºº¼sç6–•U»¸¼7jÔ§ÁÁÞgÎÄr8ÿ lm- ²ò¸»¶¹m¦T¶ØÚN˜;wG‡wz¦NzöìÆääL‘(ÂÎn–- +WÎ8uj½Ž6oNäë+è–˜Ýù7C¡gŒRšššC)=s&vß¾³¯¿>³¸¸ìÒ¥}ú˜j@5ø³±ÚÀ@·ÃCœ9k` çî>}øðh__ARÒvö8D›Ñ¾Ãm.¸ %–Û_ Ÿ>½A(tœ1cƒ•ÕX`ÚþýçöìùdéÒ©r[€Ô»·¡P蘚*uww`?ëF)‹oé³Gþx<îéÓêë‚i3fl`…„êhÌ H+‘N.G=!@“_t'ž•––Vsó1qqK&N ~Ö‡QJùåFXØŠôô8›gz¬W szžþRvˆ‰9´ÿ¹ÂÂoŸA‡4yž£}W<|X-“ (âñ¸°nÝ¡;O>‚Í›ç|þùA ‹ðiÓbæÌ [½:0ƒ -†k“´…V¯MBÚ§¹zÎ0; ®ÀA=†¿é†Bi5ò¢{€zéaÍ€Bi/¼IüR ÿR¨‡ÃçB!„^V0ôàǾ¬B!„BšaÍ€B!ô‚¨V%áTêÙ°f@]õÏþ¤£3T.oËÖ¯?ÜÚJ)¥G& ¯©©{Ò^”RÕŽšãSJ#"b·ný¶[ÞñE)½|ùúĉ«­­Çéê¾ãà0iÞ¼åå5”ÒººF>tIIy·ÄìzWBi¹61`Ù€z0¬P—PJSSežžÎFFúQQ».^”p8„2iRpuõ9>ßèI;BØŽ½zhŽ¿nÝ¡Gꢣ'wýMá”ÒM›BB™š_¸°¥¬ìû“'cÒÒr^(—7ê  :tèâS'OŠÙÅ®"„BõX3h¿ÄD1‡3äþýŠgñ[„±øV` üúëÍDì(::<== ;RJÙŽzE)½t)sçλwÜ-CrræÊ•ûbbfÅÅ-ññðùF“'c Jãã/@` 01QÜùciˆÙÅÞ"„Òr¾+ §PO…5ƒ–S¿"Ò¥ðêÕœœ¦9òsß¾Ó †»²¢âÑüù;-,ÂLMC׬ù¥ôæÍ;Îß~˦”RJkjêx¼·’ššYYÎÎ6\îÛ2YÑÖ­ßNœ¸¦µ•š›‡íØq‚RúÆ󢣿ŽÒ×ð‘LVÄ"47+³² „Ÿ}¶ÿõ×gªz[]-ïÓgÜæÍÇ(¥ EKdäöèè)¶¶æìÓŒŒ¼#–24%K;,9-ÚÕ«×Èúú¦6§¿~ýa?¿¾Ë–MSßnggqüøçÁÁÞàêj›™™ß-1;÷÷A!„z `Í åÔë„/…)¥‰´¦Fž”tíüùMgÏnüá‡_œëææ •Z¾|zLÌ¡GêÅb©®.Ï××B‘H¤­­40Ð#33¿©Iñî»A‰‰› !¹¹ÿ2d‘¯¯ 'çŸG…BÇáÃ766·9/JéæÍ‘g tÕO¿ºZž’’ùᇡ„´-ŸÂÃyy¹BÌÍùryCmmC×c"„BO¤ápªõHø›nÚÌÒ2 %xy}À.jËʾWoCIMÍ8ÐóÀ¥ T¶Àœ9á Ž++]]ž^jªÔ××M__(¥W¯Þ²°à»ºÚœ?ÕÈH¿_?—Ÿ~J³¶6ì@"‘êèðú÷wËÊ*hjR|ùeÔÀ"X°`ÂûïÇÊå FFú‰ÔÈHßÓÓ› wuµ‘ÉŠvï>ýÝwëtuy!,lŸoÄzÞÚJ÷î]PJÕ/pss‹«ªjçÍÇî¬K$2.—3sæ(ÖæÚµooŽW,–†„ø°}ÙãËBHM•ùùõår9éé¹B¶WjªÌËËE__W"‘Z[›…†dÛ €M)¨v y¦½{ªï¨«ËëÛ×>'§èܹ«?ÿ|mÛ¶¹¬'99÷š›•>>³¡¡yðàÙÙ…‹¿wøðÊÔÔ½öö–ÆùwòÁnJ©¥¥ H$rÊÎ.ÌÍ- ñíäÝ}Bˆ§§³­­yBB’ê{ ”Þ¾}ãÆ£¾¾n<—’’’âÓ-1;!„Ð+‡ÒþiØŽPÏ€5ƒö5*¨µõ’yûKaJ©D"c/HU l>’‘‘¯P(…ÍÍJøí·ì‚‚Ò þyð`"z¤¦Ê(¥AA¢›7ï°›îõõM™™ùÍÍÊ  Quµ<7·8?¿$>þb~~ÉìÙ[›W¬˜ªÙqE"—ƒ/TWË?ûìØÅ7!„ÍNðx\ÖÆÎ΂râDruµ<))}ÆŒ àééÜþaå¦&ES“¢}Äãq·l‰üòËïÖ­‹¿wïaeeí‰)!!QÁÁÞ«VEPJÓÒr¤Ò»#»%f—ÿn!„B=Ö ¯.ö2ÓÌÌü6EBP»L‹oñùFîîŽz~ôјyóvú‰Žo֬љ™±X,µ¶6sp°ì||Î=uê²X,íÝÛP(tLMÍ¡”ž9»oßÙ×_ŸY\\véÒN++PíÈŽëééÜÔ¤ˆ‰™¥zÜ™Rjkk••XÀnÛ¶¹;wžprš²ÿ¹ØØÙPYYÛf"E©l±µ0wîŽç ¦NzöìÆääL‘(ÂÎn–- +WÎ8uj½Ž6oNäë+è–˜Ýü×B!„zqȳø/ô4ùEwâ?(¥ë×Þ¿ÿÜ;Ç4/õ¡”FDÄÞºU(ÿËýOÛÒÒjn>&.nÉĉÁÏúñbJé/¿Ü [‘žçâbóLõª#!8ÛŽBmá[’P‡ïMBÏ!$--GõØô“üë_)7oÞ>vìß¿üò•zÁ\.gĈ@‰D:iRÈ3í*{ÀzΜíû÷/Å‚!„B¨=\›„ž öö$??w Y”ÒY³6ÇÅ;p`){sk›OgÎ|÷Âɳž #„DFnˆ9~ü[Ïô@!„B/)\›¤-zØÚ$„:†k“B¨=\›„z<œg@!„Bi‚5B!„BH¬B!„Bš`Í€B!ôBáà ¨ÇÚ!„B!¤ Ö ¯:JéÑ£IÃkjê^t_Úb?÷¶uë·uu|þè’’ò¿áòåë'®¶¶§«ûŽƒÃ¤yóv>‹®"„Bi1¬^u„I“‚««ÏñùF/º/ÿ…RºnÝ¡Gꢣ'ê  :tèâS½˜RºiSBHÈ"SSã ¶”•}òdLZZγë3B!„VšAû%&Š9œ!÷ïW<é‚[G‡§§§óœ{¥¥ôÒ¥Ì;OìÞý1!„(LLkþUé6’“3W®Ü3+.n‰€Ï7 ž<óL{ŽB!¤}°fÐrêuBû nJik+57Û±ãDUU-—ûö¹sW§O_ojjf6fÛ¶ã”RJéøñ«¦N]§ UUUke5öÿ÷¥ôÆÛcÆ,76Åçž:u]YY5kãè8yÇŽÇ/Ö×–±_¿÷õô†þ8ÖgBˆ¹9_.o¨­mhs”ÒÍ›#+*Î誟luµ<%%óÃC é XB!„zÌS¨Çã½è gÈÒ2 %xy}À.ËʾW5 ”J$R^ÿþn[·~Kùúëýüú€@`G)åp8 :mÛv¼¥¥•Ã!ùù%_}uêØ±5zz:QQ»&M Y½ú!}ú˜FGO™<ùóººF±ølÚ4gèÐþPQñˆRúÍ7g„BÇ€áÞ½Ñ{÷FÛ}Íš°²2a»Ëå FFúññÂÂñùFªB……RÙÒ¦ „èê¶ýoL)•ÉŠZ[é€",B!„ºkm–žÉÉ™±?þ¸ÍÒ’”RÕe4!$5Uæå墯¯›š*<øu?¿¾ìÓÌÌtIIù_xWXû˜ÝÕ[„B¡žkô_(¥×®å¶´´‰`Ò¤àêês½{BÚ7&„°|¾Q›íª z¾vmü£Gu‹Oé–þoÜx4$d‘©©ñ… [Êʾ?y2&--gðà…ryƒ¡¡Þ€¢C‡.vx.O³[z‹B!ôRÀšAû%&Š9œ!÷ïWtæþ:!D"‘ZZš¸ºÚBttxzz:.²Yƒ6)¥,ˆ‹‹µæ ôÿ;cçλwÜ-¿réRÆÊ•ûbbf}óÍbŸoäïï~òdLAAi|üE &&ŠŸêXOŠÙõÞ"„BÀg@=Ö ZNýúøI—ïÙÙ…cÆ,72éä4eÿþóii9BJik+57Û±ãÄøñ«¦N]§ UUUke5öÿ÷ˆª¥T=ȉ,;â·ÇŒYnl<ŠÏ=u꺲²j§¹Y¹=:zŠ™ªehè2#£‘ŽŽ“HŒŽþzÆŒ m.ñ)¥‹íêÕkd}}S›íë×öóë»lÙ4Õ™BlmÍÿ<8Ø\]m33óÛOÓÎ΢ó„B¡—Ö ZNýú¸ÃûëRéÝ7ßœïäÔ'?ÿHbâæ¯¾:™˜(ö÷@^^qUUm` ‡§§³LVÄBQJ7l8Ü»·á'ŸLR5ÉŠ: B)½yóÎ[o-ð÷æç‹÷ܽû€•”Ò#G~*--Ÿ?‹|ýúíAƒæ;;[çå9~ÓŽÇÿõ¯”€6—ø„Í›#+*Î꩟ZMM]JJ懆r8mÛ‡‡òòrss¾\ÞðèQ}ûoé©b"„B½R°fÐf––á––áS§®/¯¬¬ÆZZ†«7 ”.\ø¥Ÿ_ß]»¢llÌE"§%K¦Êå AA ‘Hutxýû» …N99÷ZZZ)¥ùù%_}ujëÖ¹zz:ª,ÈW_-²±1÷ðpTµkÒ¤Õ«ÿ§OS¡Ð1:zÊO?]««k€øø aaƒLLz=îÉAA»vEÙÚš÷ëçòé§SïÝ{äѾÔÑÕm» Š"“µ¶Òžø!D¡P€RÙÒ]1B!„^¼Ýô ¥§Ç@rrfDDì?n³´ä¥T5cPZZ‘””~êÔzÕvÝè©©2//}}]OOçÆÆæÂÂß]]m–-û&8ØgìØ7U *+kY™¢ R\\véRFjªìôé_X— %¥T©lill¾zõÖ_,d—ãÅÅeÿ÷׿ûnª'úúºzz:>>‚Î<²ÌÞÔ&&½žÔžRZ^^Ãår4´yÚ˜!„B¯¬´™ƒƒ¥Ô‚66f66æêŸBrrî€@u¹Ÿ‘‘ëæfoff ‰”½=ÉÝÝËåÈdE÷î=½rå&;XZš°½ ôÔ{RUUû$v¸0©C”ROOg[[ó„„$õS.((ݸñ¨¯¯—Ë€””¬Ÿn‰Ù™!„P§àl6êñ°fÐ~£Fµ¶^²±1oÿ0±¯¯ÀÊÊdÍš”””ߺuwÊ”Ï>¬ð€ÌÌüæfePˆÝõ‰œöí;wçÎýÕ«#ØUUÒÒ ©´H=ˆ··ÀÃÃiÕªý%%åééy¡¡ËõôtCC»ÙÏãqY´þýÝllÌW­Ú_ZZ‘•Uº¼¼¼¦ýÐÐÔ¤hjR´ÙHár9[¶D~ùåwk×¼wïaeeíñãÉ!!QÁÁÞ«VEÀµk¹Ré݈ˆ‘ݳ‹„B¡—Ö ¯4½S§Ö=xíµ©³fmš5k4¥”MˆÅÒÞ½ …BG6àéé|ãÆí˜˜Y¦¦Æ@)U5Ð××í0!„Ã!gÎÄè¹»O><Ú×W”´ÝÈHŸbkk••Ø]}}Ýï¿ßðûï•®®ïÍ»cÈh?Ï P(mm'Ì»£ý\!ä½÷Þ>{vcrr¦Hag7aË–„•+gœ:µ^W—GÙ¼9!<|Pÿþnmvük1»óÏ€B!Ô³|!Œ– hò‹îDg=þñ‡1qqK&M iÿéÚµ¿þúûNu×ÃÇ—/_ [‘žçìü'?3‡ž-‚?]„Bm‚c#êápž½l bĈ@‰DÚáÝ}±XªúI¸®«¯oš3gûþýK±`@!„ú °f@/!dæÌw/\´¿ˆom¥‰, @Ø-“`”ÒÈÈí#Ç{ „B¡¿×&i‹—jmzuáÚ$„j×&¡çB!„Bš`Í€B!„Òk„B!„&X3 „B!„4Áš!„B!¤ Ö èù9z4ÉÀ`xMM]'ßÖE)•Ëtt†&$$=í±(¥±[·~Û]/l½|ùúĉ«­­Çéê¾ãà0iÞ¼åå5”ÒººF>tIIy·ÄìzWB!„ºÖ è9¡”Nš\]}®woÃNþN!äڵܖ–Ö  ÑS]úSJ×­;ôèQ]tôä®ÿ&¥tÓ¦„E¦¦Æ.l)+ûþäɘ´´œÁƒÊå ††zˆºø´=ì0f»ŠB!ô,`Í ýÅÎû÷+^ìoqBttxzz:¿ˆ§”J$RKK—§øýfJé¥K™;wžØ½ûãn)’“3W®Ü3+.n‰€Ï7 ž<SPP…‰‰â§êá“bv±·!„BÏÖ ZN½NxÒE­£ãä;N ¾X_XBBÒ·ÇŒYnl<ŠÏ=u꺲²jJ)¥tõêNNSŽù¹oßéÃÇŽ]YQñhþüa¦¦¡kÖüƒEËÈÈ1b‰±ñ(CÃÁÁQb±”mom¥ææa;vœ¨ªªårß>wîêôéëMMCÍÌÆlÛv\ÕÛììÂ1c–tršrà@bZZN` õ¼}Ç:ì¿Bѹ=:zŠ­­9‹yãÆíÐÐeFF#'8ýõŒÚ‹íêÕkd}}S›/mýúÃ~~}—-›¦¾ÝÎÎâøñσƒ½ÀÕÕ633¿Ã’ìic>ñ‰B!ôâ`Í åÔë„/jKK+Š‹Ë8¿té´¼¼#B¡ã[o-ð÷æç‹÷ܽû`ÆŒ „BˆD"­©‘'%];~ÓÙ³øá×纹9H¥‡–/Ÿs¨¦¦®°ð÷!Cùú rrþYPpT(t>|qCC¥4/¯¸ªª60ÐC"‘QJ×®=8yòÛwš¸lÙ^¹¼R*“½ùæ|'§>ùùG7õÕÉÄD±¿¿Rzóæö£”¶éÿ„ ÁGŽüTZZ>þ8VêܸqgРùÎÎÖyyGΟߴcÇñý+% À£Í·A)ݼ9²¢âŒ®ú—V]-OIÉüðÃPBÚ]áჼ¼\ !ææ|¹¼¡¶¶¡ë1B!„z Þ‹îz†,-Ã@¡P€—×ìò´¬ì{UJéÿgïÎãjÊÿ?€>·å–¤=¥¤(”¥²•-YŠìŒB’ì†Â-»Š² ÙFC²¯ƒLB„2fdß½’µî½ŸßŸ™ó»î½Ý®õåõ|øãvîç|Îç¼ÏG}Þç|Î9ééBæÍ nݺ!dР¨ž=½§OH±´4?¾w¯^¯^½50Ð;{öJãÆµÖ¬™H‘H¤„àà.£GÇKêêjë닟??¡W/o¾­¦Më¬^½—¤Ïœ¹¬££]¯žÓ‚‰”ÒåËÇ6hPƒâèhÉD„Q£–Õ¯_=&f !ÄÊÊô‡ú0ÛÃÙ2zttÏžÞÓ¦PJ+V4á {ýúBûc :wnjddÀÛ0jÔRg^§µµéĉ}œëáá¬0X§”êê*þwàiŒLÆ<=]ŠÜ3Æx„%é窠LAÎð5;~!$%%sàÀ¹‡-´°0"„0Æ„¡*¥ôìÙlGG›öí=!÷î=9vìÂÙ³Ù;vœà %Œ1‰DzíÚƒœœü#ºñuÏœÉÖÒúñ3ëçÎ]quuÔÑÑÒÖÖJKû#::éÍ›÷oÞ¼»ÿi:úúº„³g³ëÔqÐÓÓ={6ÛË«.Oc™™×jÔ°Ó××}øðù‘#ç““góRJÅbBH£FÎ÷ï?-ªaòígŒ½{Wpúô_K—Žâí¼wïÉï¿_LJš)Ô©§§+븹9ÊÇ¡(”ÒW¯ÞBŒËUžRúìYž––HM™­¾-¥zÃ!€&3|Í*W¶dŒ™›B¬­M­­Í ð›ŒÛ´©Ï‡þW¯Þ'„9²ÈÊÊT(C)522سç”HD½¼\yɳg/»ºVÎå§§_öðp~û¶ÀËkdµj6&ôqr²µ³³lØp˜OƒÓŒË.üChhwaÏ×%„\¹râææÈË3Æ.\¸êädkbRþÂ…kE5Lh?¯íÊ•{ž{äîî$Ô™‘qÅÍÍQWW[“Á:c̘òøqNåÊ–òË£¢6§¥ý±cÇ--QVÖu{ '©¯3<¼±5|a¸Ÿá+§æ~ƘLÆ22®xx¸ð·©©!!D"‘ÚÚZØÚZèééúùMLK»DÉÈÈvq±74Ô—èÿ3µæíÛ÷YY74¨yæÌå»wŸ¬X1®k×fµjÙÿùçí«Wï{{»3ÆÞ¿/Ì̼ޠAÛ·=y’+LË),”œ;wµQ#gBˆžž.!$''Ÿß‡“ójÍš}Õ$„ «\Ù²reK¡aòíç{ôâE>!Ę·S__,_gnk÷+OLR½Zµì+U2ûå—#Bôc7oþµÙÝÝI[[‹Rzüx–··Ûg©S“¾0ä _???™ì˜µµ™òlûìì»/_¾ñôtáCjWWGgç*?þ¸æáÃç.\ïØ1\,ÖíØ±1!äÌ™la Ï“„FœùZ.\/,”4jTÓÆÆœRºukJNNþo¿ãÏ&ªUËž’™y½ @âááræL6¥´aÚ Êoß¾÷ôt!„¸»;ZZOŸ¾öáÃç—/ßíÝ;âɓ܆ !BîV­oPм  Œ1þ U‘ˆªl˜|ûùUªdNyñâ¥pGÄÎs=zQµjŸÅ-[ºB®3ðû"*Uú.$d±Êk}û¶Þ³'*%%ÓÅe Íwóçÿ2eŠròl-BÈO?ýÒ¥KSwwÇÏRçg=Ÿ-Ý÷|ÁgC)a)¥ÝˆÒ'•ÊÌÌ:­ZõC-”ëk—/ßùäɎϲ-ÆØ‰tî<ùüùUÖŸ¥Î¯õÆ­~ÿsp¾*ZZ¢¶m9sY9aà×U5ªùYòdÆØÛ·ÁÁ‹Ö¬™„„> ž¡erøª0ÆÛ8pFùîÆÈ™3Ù Öü,7¥”¾hàÀvÝ»7ÿôÚÊ2ÌMúZ`nüOÀÜ$e”âw#”qȾ¸¬ ÿ+ð;@r(óðN·¯~×|Åð·Jîg(Ûx€ëHPz3€:ÈÊ0aV.5@éAÎPV)ÜÆ€´J rP9@™¤òYI¸Ô¥9¨ƒœ ìQóB\j€/9@SìÜ6À—…œÔÑ.í€~A“ËÅ^ŽøL3”%H ìÁÜ$P9@™‡;ž¾n¸È erP9¨ƒœÔAÎê gu3”*<Ê<ä  rõ IDATP9¨ƒœÔAÎê gu3€:È@ä  rP9¨ƒœ Ìc¬´[ß4ä  rP9¨ƒœÔAÎê g(ó(-íÀ Ïǃ29¨ƒœÔAÎê gu3€:ÈJžerP9¨ƒœÔAÎê gu3€:È@ä  rP9¨ƒœÔAÎPæ1VÚ-€orP9¨ƒœÔAÎê gu3”y”–v à¿„çãA™‡œÔAÎê gu3€:È@ä ¥ Ïǃ29¨ƒœÔAÎê gu3€:È@ä  rP9¨ƒœÔAÎêh—v 8Œ•v €JÿùÀRþ]â%XòÏü'€¯eøMP,JÿŒ 9|:JÑ‹ ŒÃÜ$P9À'Àéaø gÐ&&À7 9¨ƒœàÏÔ(1Ìpƒ29€„'l|{3€:ÈJèÝ»‚ ëÕû^_ß×ÐЯyó‘Û·§~–—ÞH¥²Õ«÷>{–÷YjcŒíÞ}R$jyïÞÍËSê-ü‰ZŠÅ>öö½Ç‹}õê­Pá­[— …Œ±­[Säë¶Ò¸qˆ|忯ݕñckùoZP†à=ÐPznR^Þk_ß oß¾ˆ\¯žÓ›7ï7l8سçôyó†ß‹~ÂwÆØþýéC‡.hÛ¶á§Ô#¯„1Vl¼¥ôôé•+[ð…ïÞœ>ýט11çlÜ8ÅǧÁƒÛ,,ŒKÐB¡þãÇ—::ÚÈ¥««#ÿ£&­-1ÆØË—oŠ:ˆ&ôþ¶ ð¿9ÀGcŒMš÷âÅËŒŒ•FF|áܹC $S§®îÝ»¥­­E‰»”Ráäýg4Ë_ Ф6¡¼……‘µµ™°ÜÞÞ*7÷ÕÈ‘KW¬W¡B9ù¯JÖss#åJ>¶µµ]‰Dº}{jLÌöÔÔhJ©p+T(Ç·ù½üAôòÚ½{÷æ::øs ß4ÌMøh¯^½MH8Ú]H!Œ±°°~G.©XÑTáÔ¾D"9s½ƒC±ØÇÉ©ÿÂ…¿ÊdŒ1¶k×I‘¨åªU{xɈˆµåË·»téV—.Scvv½´´Z©YÏáÙ¸ñ°›[žž«kбccŒ±ÂBÉäÉ«¬­»ëëûúúNÈξ+4fãÆÃµkÒÕmceÕ-(è§ÜÜW {§Ðxùå"‘H&c2™L˜>¤¦ R©,"b­­m==ŸfÍBçÎݤDOϧZµ~Û·§îÝ{ºnÝ@±ØÇÙ9àС ùjŸ>ÍŒÜT­Z¿ÐÐ%MšÔfŒåç¿áQHøÖ…ƒHiÒ¤vhè’jÕúEFn*rªž›Ÿ½Ê<ä øð¹I/Þ|ÿ¾°qãZ Cj ã&Mjéê~pNšR:ztôæÍ‡ãâÆ_»¶)2òû¨¨M3g®#„têÔ88¸ó?¬¸{÷ÉñãY³goXºtT­Zö á”ÒsçV=x°RÔêܲeIqqã32Vè 0G&c|•ŸÞ?áòåõ:4ž:u /|íÚƒAƒæöìé}íÚ¦mÛfþöÛ¹ðð• Caå3ý|ì~ìØ…Y³||ÈgJjÚ»#:ztvö†ž=[FD¬#J”¯$(4Fý¾ÏŸÿË’%#³²~¶³³<8*"bm|üø¬¬5¶¶s¤Rc,3óú!?U©Ò{ÇŽÔˆˆÁwïþ5Tþ *´A8ˆ”Òyó†Ý½ûkDÄàääßíìz}ÿýüÌÌëÊ{ðÕÃÅV€–—÷šbbR^“É3ç¬\¹ûðá…-Z¸RJíì,>|þãk&Oö×ÑÑZ° $%%sÈŸ®^½×·oëÀ@?Bˆ±qyBˆ……‘••é“'¹|uoo7BHåÊÂê¼þY³‚<<œ !!!]"Ÿ=ËÓÖÖZ½zo|üøNSJÇŒéqýúýåËwB?~!“±J•Ìmm-ìì,w튤”*ì…ðc:ƒ…ÏïÞtêÔä§Ÿ‚•÷Q¹ b±Ntôö˜˜1]»6£”ŽýÝõë÷ccwȯհá0…M¯ZõCïÞ-…‹Ý÷ÈÈ¡^^u !Æuî×oÖ‚!×"„ Ò±oß™OžäXY™Ö«÷½½½Õ¡C š6­-¿9á ªŸ¦¯/ ô ôKM½8pàÜŸÞ/“+ª0À× 9ÀG377"„<þÒѱ˜û cYY7¤RYÇŽaBI©Töî]ÁýûO«Vµ.WN¼qãÔF†Uªd¾|ùXåÚÔ¬Îtt´á_ñÓÿ……’¿þº-‘H==]„«M›Öá9C“&µ{ôh1lØÂ)SV·iS¿sç¦ß}ç¥0hÎôïÙecc.‘H9¾Ò×·alìØråÄÊ»©Ü†ìì»a˜ÎkÞÜU!gHJšUµªµü++ÓÚw—*ü+=Bˆƒƒ5o€„1öìYÞêÕ{ãâvN› \BÍê_ä øð¹Iuê8”+'>uêOOO—ÿ/ÂØß¿èßÖŒüä7!„R*“É!‰‰Õ«06µµµàÜs箈D¢¿ÿ~ž™y½Y³: [V³úŸÞ"„ˆDT~>0öÏgJ©p ¯HD§_¾|wß¾ÓGŽœ ˆüùç}‡-¯Y W©RÑÞÞŠRêì\¥zõÊ;†½_¸mÛ åð(·×åÛ |3€¥l¨Tì¾ki‰>œI¥b²ÓôéƒÂÂúoÙr4:zû¬Yëûöm=bD7wwGá zx8˯õðás~›7¯sþüµØØä-[Ž:;W™1cpß¾­ÅbðíÁý MOO×ßßwùò/_¾RJ-JLK»dcc.ÿà£Zµì)¥wï>vr²ur²ut´9uê¯éÓ×òW¯Þ7.6"bp¯^-"ù„ù!¬°º££ ¯A~uaÓò«Ô­[MWWûøñLázú_ü«ÔÔ?†_äèh3~|¯}ûæ-[6ê·ßÎ=þR¾6•O.òõm0sf`rrêêÕ{UÆD¡ ®®Õtt´OúS¹ k),‘ßz öß~­ð­žžî Aí22â÷ïÿ)/G0¥T__Ìb~þ[ùã%DBˆ§çð—/_80ÿܹ•ƒµCÂß,\gøh”ÒÙ³‡¤¤dzyœ6mPƒ5^¼xùóÏûbb’çÍVµªµüsxlm-üý}¦LYml\¾I“Úéé—GZÚ³§·ŽŽVa¡tÀ€Ùµk;LœØ'7÷U:ƒCC—lØ0E__L9}ú/OO5« íQ8…obR~̘S¦¬65­àéé²:Ÿ˜D)_^õê½27®Wa¡dçÎ5kÚ™˜ÊOORù>ÆØ?ôÙ·ïô¤Iñ:4VމBÌÌ* ÞyÊ”UææFnnŽû÷§/_¾C¡ògÏòþþû¹B=üE\ ö]! Qد-\[´p½}û_KÍA¬V­!äÚµMUªT,æ®J1= ¾zÈ4@½¦'™™UHK‹;wcXXü;uuµëÕ«ž”4“ßòûÁª”ÆÇO°³Û0yòªžYZwž1#2mÚš?ÿ¼}þü*--‘™Y…¸¸ñݺMmÛ¶Q·nÍÛ·÷8p.!äÚµME­.¿ …öFF52*ÿÃ+ž<ÉiÔÈ9"bФIñ„wwǧFFntu *WNܪU½={¢¦ô¨¼Î@)‰Èš5Ý݇Œ±80°½b„”Ú0þpCÃr#F,~ö,¯~ý“&õ›5k½pªž1æå5J9Ò/_î“ÿñc÷]} ÁÙÛ[ñ¦¦†*b·nÍJ|ãTL0E”*¿ Ô`ŒýöÛ¹Úµ¬¬þy[ElìŽI“âòòö‰DŠOjúßF½q>®VA™‡ûàó£”nÛv¼_¿YWnß~”œœ:gΆ€€¶_[Â@ðÜ$ø&à:€&Ž—vþÇ0Æòò^Oœ·kWÚ‹ù¶¶þþ¾“'øo#nQÚ €ÿ}¸ÎerM g€¢ g€O†œÊ<ÌMø_ÙT+U´ñË@#¸¾UÚ„à!@q¨wi· Ô`nÀ'À4tø gЮÇÀ7 ï†RsàÀ™%K¶ž9“ŸÿÆÄÄÐÃÃy„>^^u?åÙíTn‰®®Ž‰Iy??%KFh¸î™3q Ô(ÝçÇkÒƘ–V+BHzúІ k~Éæ}Ó„&¤ßæþ3¡s 'Ú¿å%_5ä P:fÌH˜1c!ÄÍͱbE“‹oîÝ{úÀ3[¶LïÞ½yɆìŒ1¾b‹®FFyy¯Ožü3!á`NN~ròlõu ëBJ7a`ŒuíÚŒbbb¨¦%”âAÉ¥AùjÃ7½D©~ËK>z”yÈ 9r~ÆŒub±NròìvíBÞ¿/4hnbâ±qãb»ukN+ÁÀ]FÿôSpƒ5!»wŸêÒeòÎiçT¬h¢á\>øò(¥Éɳ‹-Vº€o îg€R°lY!dÔ¨ïxÂ@‹u–-µoß¼3gâøH85õbË–c Úuhß~Ò¹sW…1=¥Þ”zoÞ|¤yó‘úú¾..wï>ÉãÃh>’æ|}ðçðåYY7:v «P¡}¹rm›5 Ý·/×)¿n×®SE¢–cÇÆð: %––]E¢–¿ývŽ1VÔÖy=jê‰ZŠD-7múÍËk”¾¾oݺ.\‹ŠÚ\©Òwíºt™òôi.ß"/yöl6cL*•͘‘P­Z?Öí5 >pà ù7ÉÁ¥ø3@)8yò!¤U«zòC^ ãvíU¬hBIMý£M›ñ¿ÿ~ÑÝÝÑÍÍñС³-ZŒºté–|b²H$™›egßíßö›7ï !Â0š8t(ƒ"QsÆXfæõ&MFìÛ—^µªuÆ5Ožü³S§ðÍ›‡àAA!‰‰Çd2F9räü³gyUªTlÕªù7QÞº†õ/ÔÖÖ222¸téV«VcgÍZ_«–½L&Û½ûdDÄ:^¹|2°lYÒŒëž=ËkÛ¶¡eFÆ•îÝÌË{-Ÿäü§3@)ÈÍ}E122àCÞáÉD-ùù{‘¨eFÆ•ˆˆµ……’Õ«HMNIY²fͤ7oÞGFn”RÓ#%eÉáà !¯^½½yó!ùw@?qb\÷î?¶l9¦gÏé„ï¾kafV2iRüÛ·ïl›™¹æøñ¥K–ŒdŒ+‘Hå‡àíÛ{ØØ˜?zôâèÑó„­[S!¶‰ŠÙº&õOœØ÷È‘Eññc¹¹¯§:´`âľ„ÌÌë WK! ÔˆŠvøðÂÝ»çþþû2ÆØÛ·ïoß~Dä$€ÿr(ææF„'Oþ™ŠS·nµ.]šòù øÌ™ËŒ±ÀÀy|–ΠAsc¿ÿ~Q~HݪU}Bˆ££ _øþ}!ùw’’¹clj“'ÿ477 î¼fÍD¾JjêEBH@@[^lðàvŒ±G^\»vŸÈ Áµ´DƒûB¶l9ZP INN¥”´+vëšÔß²¥;!ÄÚÚŒ×Óºu=BHÅŠ¦„‚‚Båë ÍšÕ©[·êæÍ‡½¼F98ôá É¿ Ò=rðMÂ=ÐP š7¯»mÛñÒ;wnB>¼Ëðá]Ø¿%„ÈdŒRêåU×ÄÄPXKGG›‘ùxZ__—¢¥%’_È?«|ü(cL$úàÉHŒáæòáã’ö›3gãöí¿·k×(7÷•··›ƒƒU±[פ~±X‡B©P˜|ðØF¦Ð’±cc–-ÛÞ A ß B<=‡ËïÑG‡Ê Jñè$(ãpJÁÈ‘Ý !«WïMJú/‘Je«Víίׯ_Ò®GròìääÙþþmëÖ­Ö¿¿ÂÔå³òò÷3(l”RÚ¨‘3!dÆC¼Øºu!•*™99Ù’§úØÛ[µiS?/ïõ¸q±„Û ¹š­k^¿ÊÕU.\½z/!$"bphh7aëüK\g€/× 4o^wÆŒÁÓ§¯íÙszݺUml,.^¼qÿþSBˆµµYÅŠ¦“'èÔ)|òäUIIÇŒ ŽÏ’Je+VŒ“?©OT•>+¦csæ iÙr̺uΟ¿jl\>5õ‘ˆ.^ʯ(¬Ôáðጞ–ëÑ£…Üx½È­kXQ««\hgW1;ûî AsÝÝRS/ŠDT&cü†\g€/× tüøcÀ¡C :ujòðáóÇ3 $>> –.uåÊ;;K??½{çyyÕ½rå^jêµjÙÿüó¤aÃ:‘âÎô«¿ÎàéérâDL§NMîÝ{zæLv“&µöíû©G õð]º4åwN÷êå]®œX“ë Ö/´G“…6LiРF^ÞëK—nMŸ>¨{w/BHjjÁuøR(#ªÞî ðÍ»}ûQÍšþ’ß_Ö¬YÒn@YB½1÷àsÂý PæanÀcii—¢£·§¦^,(4jT |ã3|€Rª££½gÏ)ÆX›6õW¬Çç#•v»J æ&ÀGÂÜ$€Ï s“ ÌÃ=РEV  çD>#\g€2O›ÌM€A½K»ðEan¨ƒœÔù¤œA"‘®^½·E‹Ñ&&Åb;»^νxñfÉjcŒíÞ}’Ro៮n›*Uz/ÌÉÉW¿îîÝ'E¢–·ný­üößÿo3ß´æerròkÖô¿zõ~‰[Ë+*ø%®“7’G^$j)|5ujÿŽ&Ç]¾Œü>òb±½}ïqãb_½zûéû²º·÷h‰Dú…û!Àªäïgxÿ¾°K—É™™×'Nì3ÚȨüõëbc“==‡<8¿yóº[!>¥ôôé•+[B¤RÙÕ«÷£>|¾s眢ž‘/?>ûÂÏѧ”úø4xð`›……qQOñ—_È›:aŠnÝš;9Ù”¬µŒ±‚‰šà7kVçckb˜ž§ü]»"‹ZQaï¾dücBð5éa !ïÞœ>ýט11çlÜ8¥Ø£©žŸŸÇòå;¢£·Ûóc×(³ŠÌvï>٥˔;wmm-”OŒ±¹s7ž9“‘±²jUk¾ÐÎβeK·öí'……­B¬ss_¹tÅŠq††úê+T16eŠûö“ jgbbXâzÊÕs“Ôc……Òèèä#º ƒPxíÚ°={æòµ$éÌ™ëúˆÅ>NNý.üU&c »¹ééù¸º;vAecúúba‰D"={ƒ½}o±ØÇÙ9`åÊ=Œ1ùÖN˜°¢R¥ïøäƘLƪVí;cF‚Ê-ò2EÕÉWIH8èî>DOϧZµ~Û·§îÝ{ºnÝ@^òС ùÙ,Œ±¼¼×cÆDW«ÖO,ö14ôóòuüx–Bô–,Ùêç×Șü;mfêÔÕÆÆLM;)L‰)jâMA„_H„Xñà û¥yðUqJ©|•RèãÇ/çÁç?ª>/£²Naß?=øEÍRˆ›H$’ɘL&Û³ç¯PM›¥RYDÄZ[Ûzz>Íš…λI$jyïÞ^­‡‡³……ñš5û0= ¾ªsåé4 ß^¼x#''ß×·¡ò·VV¦ü +clôèèÍ›ÇÅ¿vmSdä÷QQ›fÎ\'”\¶,).n|FÆJ½æÈdŠÃVÆØÅ‹7çÍÛܪ•»‘‘¥t̘èeË’–,yåʆ#º…†.‰‰I–ßz``ûG^Í%„<cãÆÅ®^½W(“½A[[kåÊ݇/ôöv#„T®lñðáó\3y²?/3kV‡‡3!$$¤k@@ä³gy|y:ƒyµ……™Œùø4X¹rcìéÓ¼¸¸]ññºtiJ) ívíÚý¨¨Í¡¡Ý„íº¸TiÒ¤ÖúõÛ·÷ „$$ðõmX¹²EVÖu•[¤”ª¯32rh‹®„aÃ:÷ë7kÁ‚OOBÈ!ûöùäIŽ\XH«VõZ´puss$„ØØ˜‡†vëÝ{wùò—/ßÔ©ã ? œ<ÙßÅ¥Šr râ ¥T¾0kìØ˜¢‚ߢ…+¥ÔÎÎR9ø|G4 >!D~×®Í!#FtUüS¦¬66.ߤIíôôË£F-íÙÓ[GGK¨§¨söÊçÝ)¥+š´ _ifVÁÝÝiÿþô¸¸]QQCŠB‚‚:4n"‰/U¨Ga‹š×Yl›+V4¡”®[·ßظ¼L&Û¹3mÑ¢DBÈë×o…25jT622È̼®ðþ •×Þ½+ÈÉÉ·°0V¸ÖÁû,Á/*QQ¹ÜÊÊ´Ø@ñÈÈ_!V 5k|õ5ÈWUlðUÖC)ýá‡>ûöž4)¾C‡ÆÅFÃ̬Âðá§LYennäææ¸úòåÿÜÌ ¤/Þ¨_¿†–^²_‰’ߣ)ë$'Ïþõ×cëÖíŸ?K~þ3³ Î[¶LëÞ݋֟`g·aòäU<³´4îBÞ½+8}ú¯1cb?ÎÙ¸qJ±=°Tð÷øúNxûö}DÄàzõœÞ¼y¿aÃÁž=§Ï›7l„ÞÿõÖù‡ß_æèh#ÿ•®®N ¢D) êпÿìÓ§ÿòôtj ”&$hÓ¦~µj•>¶ÎýûÓ‡]жmÃý_Ó®]£åËwDGo3¦GÙ9âðu+2gؽûd—.SîÜI´µµPþ³Ä›;wã™3Ù+«Vµæ íì,[¶tkß~RXØÊ'¢K0lå,,Œ¬­Íøg[[‹ðð!!‹óóßõnÝRBôôt…Öª¤0¼xñæ–-GoßÞRâvRJ…à;8Xñzìì,[µr÷ó›¶2--¦u¦¥]úã›.¬®[·*¥ÔÖÖbá³g³cb’{ôhñ_$ljÖÕä˜ -,Œ¬¬Lù66æ¼Ã¼|ù¦B…rŸ½ÍŸˆRZl‡QÙ$ù}$„88Xçæ¾9réŠã õÕWX*(¥“&Žxñ2#ce… åxË##¿/(Lººwï–•+[þ§[çÌÍ?ˆ[‰1ƺuknfVaÓ¦Ã×–_¿þ 5õ-[¦•à7ÐKlO™âß¾ý¤AƒÚ—GÚ_€ê¹IêUŒ±ÂBittòˆ]…„A(¼vmØž=sùZ‰tæÌõ}Äb'§þ þ*“1a6ÅÆ‡ÝÜ‚ôô|\]ƒŽ» ²Œ1}}±°D"‘Ξ½ÁÞ¾·Xìãì°råƘ|k'LXQ©Òw‰”/—ÉXÕª}gÌHP¹E^¦¨:ù* Ý݇èéùT«ÖoûöÔ½{O×­ÈK:”!?3„1–—÷z̘èjÕú‰Å>††~^^£ŽÏRˆÞ’%[ýüYX“§ LºÚظƒ©i'…é%EMb)(ðà ƒ+|a¿4>cÌа!$1ñha¡”o‘Ršš}üøRáh*J¡{ º víABkß¿/47ï#c¥Þ€säǼŒ±‹oΛ·¹U+w##Jé˜1ÑË–%-Y2òÊ• #Ft ]“,¿õÀÀö½8xð,¥”RzìØ…»wì§f‹êëœ?ÿ—%KFfeýlgg9xpTDÄÚøøñYYklm-æ(Œc"SR2ׯŸ|ãÆæ£GSJ»wÿ±°ðÿ§K¥²ääÔV­êË‹SR2ÓÒb÷îrpøÿL˜ÄR¹²¥ÂႯ|nžŸïûÇ¿^=§  öQQ›­­»÷ê±lÙö+WîÉ'oÊŠŽÞ.ßöûë¯;çÏ_ã{·gÏ©—/ßø™ðð•aaý¯\Ù8ztqãbccw(t*õûBäziVÖ ÞaøE†bÛ,tÞfõF*•‡ÏÛaTî£D"MIÉœ5+Áǧ‘‘B1•m ‹Ý=:;{CÏž-#"Ö)Ô©rs#F,Ž‹ÛµpaHvöú  óîoQÛKo¾_ظq-…^jaaܤI-]]m5ƒÝ¢z¯rb rëDƒß`:5îüÃ+îÞ}rüxÖìÙ–.U«–=/0vlÌøñ½¯\Ù0aBï±ccV¬ø'm lÿüùË}ûN §$ÔŽïNQm.*’ á”ÒsçV=x°×W~K0ÆZ·®—”t\ÍøŒTÌM24ô#„H¥2Bˆ³sÿ뛟¿_(À{ú4—"\ôgŒ»zõ^¡Lvömm­•+w>¼ÐÛÛR¹²ÅÇÏüqÍäÉþ¼Ì¬YA΄®‘Ïžåñåuê æÕJd2æãÓ`åÊ Œ±§OóââvÅÇOèÒ¥)¥44´Ûµk÷£¢6‡†v¶ëâR¥I“Zë×lßÞƒ’pÀ×·aåÊYY×Un‘Rª¾ÎÈÈ¡-Z¸B† ëܯ߬ B<=]!C†tìÛwæ“'9ra!­ZÕkÑÂÕÍÍ‘bccÚ­wïL¹Ã„}$„¼{W`ddЩS“Ÿ~ V.©Üf±X':z{L̘nÝšBFê~ýú}ž˜©™röìYÞºuV®œÀ×?¾WA„±&Ò¨é¥yy¯ !&&åK0içñãœ¢Ž¸ŽŽV±['ryBÆÃ¶¾jÕ}ú´¢”.X’’’9dÈOW¯ÞëÛ·u` ŸPfÊÿAƒÚB‚ƒ;_½zoÁ‚ÄààΔÒZµì›6­½qãa“#GÎÝ¿ÿ4(¨cLM/ÍË{¥2’ÆÆåÉ¿³ÎŠí« ¿%(¥µkW]³fŸD"ÕÑ)ùmiRñÇæüùU„cÇ2ƒƒîßÿ“••)!Š~%!7÷_N) ÒUXQ&“eeÝ–Je;† +J¥²wï îßÊttüç&`~®´°P—ïÙeccNÑÕÕ©XÑDOO—7àÒ¥[2Î\2Æš6­½]H6¸ÀÀ#F,ÎÉy¥¥%JJú}ݺ0á+å-^½z_}..UøøÃÀ@âà`ÍK–+'&„È?º„RÒe×®“¿üräÎG·n=ºté!D&“ e>|Ná·« ?êfhƘ|¡Í% >oƒ ^²uëz­[×cŒÝ¹óø×_SfÍJèÓgFjj´|ራ þ A~ &þôSð‹ùû÷ŸILœ®Id¼½Ý„}iܸöÒ¥IÏŸ¿êÌʺ¡~_:ŒXüÏM®¶™w˜/òUv…( ¦¨:…Ðax %ë0¾‰ôÈ‘óáá+}}ÆÆŽÕ××U.©Üæìì»’¦Mk mnÞÜ•ç E è)¥—.Ý’Ježž.ÂZ“'÷W.©cÌÜ܈òüùK''[ ×ÖUsÄ&CEX1)i–Â*B²]®œxãÆ© «TÉ|ùò±òqðñ©/ì5ï¹¹¯ø?(¨CpðÂçÏ_šš&$hݺ¿ûYM›ïÜy¤2’»wŸ¶Xl_Uø-Á³°0*,”Ö¬iW½zåŽÃÞ¿/LJš©\R¹ÍuêOgù>|Þ¿ÿ¬3›7Wýt/áºÊ#®áÿaíì,‹JZcçÎ]‰Dÿý<3óz³fu„¯tt´b¥­ýÏõž=½ÇŽIL<Ö·o«ääÔuëÂùr5m¾yó¡°kE5¸Ø~¥ð[‚Rª¥¥E‰p?| %¼ŸA,Ö í¶hѯ·o?’ÿŠŸŸæŸkÕ²§”Þ½ûØÑÑÆÉÉÖÉÉöÔ©¿¦O_«PUQã…%Œ±ÚµD"zêԟŸՓ'/U¬hbjj(_ÒÀ@¯oßÖ‰‰G·n=æïï««ûA^¤°EMê”c©ióÉ“ž8ñǶm3çÏܹE WþÈvùøñ3‚¿P®S¹Â¢èééòàß¹óX¡åàóÈ;:Ú(_¡ wîý—«´´?œ«ð'B ôú÷o³eË‘_M©P¡\×®Íx´Õ´¹¨HªüE¤¾_É·ÿ￟ëêjó§)ü׊œÛ©S™ìXQßRJ§MxéÒ-ácÇölÛ¶¡‰‰áÕ«÷lÙr´aÃšÆÆåË—×÷÷÷™2eµ±qù&Mj§§_5jiÏžÞ::ÿ ¹¨!‹òÙD> h¾Ò̬‚»»Óþýéqq»¢¢†*#„uhÜ8D$-^ªPÂ5¯³Ø6W¬hB)]·n¿±qy™L¶sgÚ¢E‰„×¯ß ejÔ¨ldd™y]áý*Ïž¾{W““oaa¬p­ƒ1öY‚¯°Å°°þ»wŸôö3}ú g™LöÛoç¦M[3uj€X¬ceeZl xd j׿ÿìׯ߭[Æ—™ðð•&&åëÔ©ºcljøøÝëÖ…ËWkkkñ±ûÂiÞfù£p|j֤è¯A¾ªb;ŒÊz(¥?üÐgß¾Ó“&ÅwèÐXMIÎ̬Âðá§LYennäææ¸úòåÿÜÌÀyôèŸùrò×v!ÖÖfþþ>áá+ÍÍœívîLÛ±ãÄž=Q }UM/={HJJ¦—×ÈiÓ5hPãÅ‹—?ÿ¼/&&yÞ¼aU«ZËdìñã|ÓòëRJ‹:â ù¿ú­óÏžå=zôB)ò¦‰tÀ€Ùµk;LœØ'7÷U:ƒCC—lØ0… ‹75­àêZm×®´øøÝ áÂ^3Æ‚‚:4l8ìÕ«·ƒµî¯PÓæ¢"ÉïCà/|°µµÐ¤_ÉGéâÅõë×P8jð¿ Ï3€2¯ä7ωÅ:ÉɳýõغuûçÏß’ŸÿÆÌ¬‚‡‡ó–-Óºw÷âWÌãã'ØÙm˜¬X1ÎÚ:aäÈ¥OŸæV¯^96vÌ!äËð?« Ô¨UË^__\»¶)îÁ‹šÔ©I›kÔ¨¼jÕQQ›V­ÚcnnÔ¥KÓ´´X7· ôôËffx--Ñwßy~•––È̬B\Üønݦ¶mۈߴðã§M[sùò]''›õë'÷êå-?Xwss¬W¯ú¹sW§Ë//ªÍ„•‘|ýú]ûöÎ%„\»¶é£ú•LÆÎ9²»æÓ>e„–RÚÍøÌ %}""µ/kPÿúëNýúß߸ñ‹µõgxÕ|:>ãŸw…tñ«qøpFíÚüCŒ±åËwNš——·O$¢64hî“';ø]Ë_Òúõ‡ø¦ÍÌ*”…ÿ Œ±={N©LBÊÆXJJfïÞ3®_ß\Ô‹ ÿsÔ§E¾)ªïgøÅËÍ}µsgZhèRÆH¿~mÊÂ@D‹K•|/þµ ¶í”›ûj×®“B‡)êšÀÿ4ÆØ¶mÇûõ›uölöíÛvì81gΆ€€¶"-(,X°eòäþ_>axÿ¾oºŒ$ Dƒ» ÊJéüù[ÂÃû—ZÂßž¯êÁÞ”R©Tæï?Ç̬¦MSùÓ-ËÆØ‚!žžÃ‡íô±¡„Ï‹?Hè0úúºedðúyQJçÍ6qb\§Ná/^äÛÚZ|ÿ}ÇÉ“BtuµOZÎ û…‰Å:§N-/WN\vb^âÇ|až}÷®`Ô¨ï01 ¾˜¯snü‡07 àóUÍMøßƒk†Pæ!gu3€:È@ä  ŽŠœ¿0ÈÙ9€1Æsqxøp†ÂÓÊùk°V¯ÞÛ¢Åh“Žb±]¯ç^¼x³ÄÏ5ß½û¤HÔ’RoJ½E¢–ººmªTé¼0''_MŒ1¾â­[—l»ŸBØ´šÊ—aŒåää׬éõêýOÙnQÁ/Ym<†<òüŸ|ðÕ¯«Iþ šwù2Êû(µ‹}ìí{ûêÕ[…Â_r_>ÖÓ§¹£GGW­ÚW,ö13ëìë;aÿþôj3ÈìêÕ{Ÿ=ËûØ­ó(Ý»÷„ÐÑiýäI®°uÆX~þƒv¼L‰#¹º·÷h‰DZÆÀ7BEÎ@)MO¿ìááLÉË{}íÚý† k*¼í¨ @Ò±cØÔ©«»tiöûïË®]Û´n]ø«Wo==‡Ÿ8ñG þÌ «¤§Ç=|˜ôàÁ¶›7Y»6ìÀ3ÎUó òR| cÌǧÁƒÛ*W¶,ª… O|§”N˜°¢[·æÕ«—üÍ ïßüÔÔ‹%¨7žRʃÿða’|ðÕ'l •|1”R!øEµP¹IòûøàÁ¶ììõsçÝ´é·aÃBŠ=šeAa¡¤M›ñçÏ_]·.üÆÍ))Kj×vèØ1|Û¶ãš÷JéþýéC‡.xûöýÇ& KD"Qrrª1Jé®]'ß½+~Ô¼ry~~††å¢£·—åcðíPñN7ÆØÙ³—½½Ý !gÎd;9Ù——/@);wã™3Ù+¬øu;;ËV­Üýü&†…­LK‹ùØv# #++Sþ£yxø€Å/_¾)ê§¥;lÕÓÓµ¶6S_FøÌ»xñæ–-GoßÞRâ—11Æ„àW­jÍÚÙY¶léÖ¾ý¤°°•'NDlÍB -,Œ„ݱµµàÁÏÏkh¨¯²N…½ûÂñ/6ø*GÃòûH±··ÊÍ}5räÒ+ÆU¨PN}…¥Ž1––vé?n^¸°ÚÕµ!ÄÖÖbÑ¢gÏfÇÄ$÷ìé­y=Bp>ê¨)nݺÞöí¿Ú‘ÅÛºõX³fuxúú)ý|Êÿöí' ÔÎÄİ5Àg¤xÏÙHJú}äÈ¥"Q˶m'\¾|‡Roù2’èèä#º Ç[»6lÏž¹|D"‘HgÎ\ïàÐG,öqrê¿pá¯2f€lÜxØÍ-HOÏÇÕ5èØ± *‡þ”R}}1ùwˆ#‘HgÏÞ`oß[,öqvX¹rùp3~üòJ•¾“H¤üG™ŒU­ÚwÆŒ•[äeTÖIþ€‘pÐÝ}ˆžžOµjý¶oOÝ»÷tݺ¼ä¡C ³Yòò^]­Z?±ØÇÐÐÏËkÔñãY ÃÖ%K¶úù527761uêjc㦦ä§Ä5ñ†1VX(åÁ!V<ø< |…M„à« ”ü¸“2a |¾\}ð‹: |ùç >)‚Bg‰D2“ÉdB…jÚ,•Ê""ÖÚÚöÐÓóiÖ,tîÜMÅNÂÑdwŠZKa¢¥Ôа!$1ñhADXžš}üøRòï¤A5QåýÍ̬sçΓcvv½(õ.ê+¯¼°P2yò*këîúú¾>>ã³³ïÊ·³GïcÇ.¼x‘Ï·’—÷úС ù쥨ÿ¼=ëתSg°XìS­Z¿åËwÊ漢‡³……ñš5û0=  Ô)æ &ýñÇZmm­Û·>LêÐÁsæÌÀ‡“䇒/ÞÈÉÉ÷õm¨p‘RjeejbbÈ'ጽyóḸñ×®mŠŒü>*jÓÌ™ë„ÂË–%ÅÅÏÈXi` 7`Àa€Bä†tYY7æÍÛܪ•;¿È0fLô²eIK–Œ¼reÈÝBC—DGo—O¶ôèÅÁƒgùð娱 wï><ØOå¥RcL}óçÿ²dÉȬ¬Ÿíì,ŽŠˆX?>+k­­E@Àm&„D¦¤d®_Ò™R9 IDAT?ùÆÍG.¦”vïþca¡T( •Ê’“S[µªÏãæ¤d¦¥ÅîÝeoo%Ÿ,©œxC)‚¯<âÁç,qð…³Å/ÞäÁ722 ”**&&Y~ëBðùÞ©>ߢú:?oðå û(‘H»0kV‚O##…b*Û»#:ztvö†ž=[FD¬“¯S™†}I*•)¬UÔD©úõ«µŠÚlmݽgÏéË–m¿råžü®©ªÐßÖ¯ŸL)=wnÕÇI„•†ÿ?=:úçŸ÷ÅÇO¸|y}‡§N]#ßž-\ÍÌ*ìØq‚÷;ÓÜݪT©¨á¡;6füøÞW®l˜0¡÷ر1+V|6´n]/)é8¦'”:ÅœÁÊÊôÑ£NN¶vv–VV¦W¯ÞoÚ´Ž0YˆB)}ú4——ÆCcÇÆú ÿy’#”dŒ´jUoݺð&MjÙÚZ4lX34´[NN>wùò—/ßÔ©ã †~òdÿZµì7®¥00âo´µµ®äÁ¾ÊÁò$—¿mÛ†vv–=z´P¾Çÿ±wçq9eÿÀÏyžê)­ª'¥§’RŠP„ÂÄØJ–”%cÚ²Tf&"™F¢ÍPaì‘¥¡1F4#cÉÒ„I¨¨Ä žç9¿?Îüî÷ºÏR²›Ïû5¯ï«îsî9Ÿó¹·¯sî=÷>®v:YÊ&ŸV¢¡1I>!¤²²–&ÊÇÇÝÒÒ8,ÌWIòiïd“Ïi‘I¾¢:ãâ¦{x8ÙÚš1Éws³·µ5S’|ww‘HØ­›­lòLut†hh 3æk/¯n[¶DË–”¹®îIbâ^æ„™5kÔôéØC#[bÍ%š<—8“Cæ­3-m^^Þª1c<þøãzxx¢]ÀÀååUÍ9RÌùFÒ¥€Ì #û×úða}zú¡å˧{{÷¢]þüó¡ì`x<ƒöQ,–üüó¹ÈÈÔ»'%ͦurÈÆ\Rr»¡AìîîÀÄܧSRÒ>ÔŒû MžK/u5}À€®tEݼyoçÎã±±ãÆ->y2±É#EÏ7NmÅÅ¥ŠN˜[·î‰Å77{öß{BhôhÏO?W[û˜tìØ©©óΞ½J?jòÐxy¹05÷ìéðÝw{jkëéiÑ-B¡nc£¸²²–ž–xW¸smíÁt´ŽÎº*ÝÂÂ!T_ŸK `Œ­µµ[;öG·n¶ôŸv##=##=B³Ö™Ž vìˆá¼ H$^ºT†âñ0~q*B°°hceõÂJ}ú)3È`Ctï…[%~~žsæ¬Û±ãŸÏ×ÔT÷övg>’m±É:ù|Þ‹W ÅbÉ€snÞ¼çççééÙ%8Ø¢¼¼Êß» Ý—Ç{¡NÎå!Lò»wïH7Òä#„^*ùìØÉg/‘bÂfÅ ïZ|N‹MÖÉçóØ‘`¬ðZ~s’Ï`úhggÑ¡ƒÙ°a Ÿ?oܽ{±lIÙ˜éD…nÌL/d+a66y.5sê¿íùóÆ¯¿žDµ´4ž7o¬ººZxxbmíã&³*÷|SrÂܾ}Ÿv™ùQUåþŸFŸ> tsr èìÂÄDŸù¨ÉC£ªªÂùëc"$„ðù|„k“€wŒ»6éܹ4ýï¿_pî\ÚŒ#‡ ëyî\Ú¹siìᎺºZX˜ï·ßî¼uë>gAÅ­[÷éÏ:YbŒoß¾oc#²±Y[›ž>}ùë¯7±Ûb/ÑálçlÁ;8XñxøôéKôSŒqAÁÅ6mZëëk³‹iii|öÙ€;ŽíÚ•ïï?¹M!·ÅfÖ©¤FAÁ¥_ýs÷î%+W†y÷íÛ¹´´!Ä.K¯•Þ¿ÿP¶NÙ å ª4ù7oÞcD‘M¾µµ)Í¿lò91°·s¶B˜D1ƒ9ÙD!„45ÕÙÉWS{apÉi±9ur²­(f&ù ÁAAÞN²É—ÛÇ»-Y25;ûdzú!E%Ù-:9µWUUaÇ\XxYQÞ˜.(ªM¶wòÃ}±¶[·î­\¹ýîÝœ[µ´j¥Þü¬²›Sò×Ú¹s{55•'Î3#L—Ìò¤Ý»³&¡fü]œ9s™©ùÔ©?íì,èCÞtËÝ»ÔÔT„B½&3€7Š{ɰuk튊ÞÞ½´´4þúë®§gî7 B¾újÒÅ‹e®®Á³g4¨{ëÖÚ×®•gdü¸}û±îÝ;êéiiiiøû{EG§ëéiõêåPXxeæÌïÆŒñTUýßúlEƒ$¹ÛõEF¦ètéb“›[˜œœ?B(0phÏž!<oõê0ÎpœSs›6­›Yg“1·iÓc¼ys®žž–T*Ý¿ÿÔ·ßî@=yò”)ckk¦««yþüÞ½•×Iyþ¼±¦¦^(Ôã¬hÇ¿–ä+š¨È^íÆ7'Qt/vòe¯£s2ÖÌ:›Œ¹9É—ÛGBȼyã>³`AÊС=å–dÿj` ìfh¨ëìl›[¸~ý¿ “¤RrÿþC„P¨Ç¾C¢dr¨ü>óg ôàÔ¶pá„ <=ÿþz²««T*ýé§³_}µqÑ¢55•æg•¾ëÌ™Ënnö"‘Pî £¦¦¢¯¯>:::]__ÇÍÍ>7·³0‰¢Ë“x<œ•õ“!Mš… SôõuœœÚçäœJI9‘É>:.”º¸ØòùðuõÀ;Æ3œ9s¹S'K-- „ÐéÓ—ÂÃGËDª©©dg/ݹ3óæÜ„„íõõÿ踺ÚmßþÕÈ‘}é¿ñ))ææYQQiwîTéy/^<•]Oó‡­tㆠsLL2fÌø®ªª¶C³¤¤ðÀÀ!œÀB..:u²ÔÐЫ§Ê[lfMÆlkk––6/>~kZÚACC]÷S§’œ ¯èÐ2|>oÔ¨¾GŽü6cÆHåýÅçåùøD—–n“],$¨*I>]ÈÑdò_j†1–MÔ´i/< K{Ñ­›-M¾ƒƒ’¹ÊΩ¶9u6'ææ$_n=cmÜ8¿K—i¡¡«§N¢¨$#!!X[»Uhèêêê:Û ÆÇÆf ªuuMMG#„JK·±×)É€’ÞB˜€³TÏ¢Ío¿¥¬X±-&fSyyŸÏsrjŸ”4{üø´†ffÕÕÕnÈ×I“–#„®_ß*÷„¡%ãâ¦ëêjÍ›·¡²²¦G»˜˜É ¤pÒÒ»·£¾¾vçÎíé{„Mš/¿œôÕW¯\¹mccš™åççÉZª„òòŠfÌÙüÅ{xC0A‘ãï:Œ×†.:·²3…3Tzç!W®Üvqù¼´ô‡¶mßëïk±ÆF1M~`ào¨Gùé§³VÌ{«’’ö-X\Ww˜ÇÃYYy“'/¯¬Üg` óñõýõ"„1~|lQÑÕ›7ïegŸ\¶,+ `‡Ä+WnŠš†æhòyBHBÂöÈÈ 0aÞܵI.BˆD"õ÷_f` ³uë" µ÷p¨1^¹2ÄÍ-xúôáÌ«}fìÝ{òÛjh¶P]Ýë›o¶3?{z΢iQ´×«äM"‘¦§ª®®cö­©©ïØÑÿÚµrBHnn¡§ç,±XÒ‚šßD~À[Ö’ïgPþnõ`WâåÕíÎÝB¡ÞËÖÌDUX˜lf&D=ÞøçŸ……}W]]—’2÷Õã䨫{2p`ÄÓ§Ïcb¦tíjóÏ?ϳ²ŽŒóõŠ_ÌëײÌBNúóðá½{cûõëÂüÜ«—ƒD" õ!rßgÿ*yËÍ-œ>}å AÝ龄ˆˆ ¾¾}llL1ƃ»®_¿/1qïìÙc^ªæ7‘ðö)œ38Pàã}ëÖ‘HÈÞq¾ÃõÕìIˆººš‰‰A *a uõé¯mîÜ©ž9síêÕa¯÷‹Æ! $?|ø¨¨(UWW“n\¾|zCƒxÑ¢ô±cûÉæ­™½xòäBÈÅ¥ƒŽN+æg¡PWImãWÉ“úÃ… mß~ìæÍíÌ":ÚÈ“'Úºµv3«m2?ffF-ˆ¼}ò×&5ù-­ì_ÅbÉ’%™VVã/› «Ví”Jÿ-PW÷$<<±}ûñ—¶öà¾}gž8QL!„46Š£¢ÒLLFjh 80¢¤ä6Ý…YcCز%ÏÙ9P]ÝËÉ)0?ÿº¯D"‰Ù$VW÷êÝ;lùò­t]“lÌãV­ÔB‰„¢$ž-[ò&«©}blìøMmícº]nï!?ÍÈ86’ÓÌ,\8þر5mÚèÓÌ,]šei9V ð²³ HM=ȤNQµ{I17÷ãñú1?33ª´tÛ±c«1Æ#G~ÙØ(¡{}ÿýá””ˆ+W2‡í¹hÑF¹‘¬]»'9ynQQª¦¦úĉËèldᔤ¤}‰‰³JJ²ÆŒé³™³óåË·V­Ú1þ8-- „¢x®_¿3yòò1c<¯_ߺ{÷’Ÿ~:™Š1ÆËíBèÂ…¿ž?oìÙ³g~%êõêÕIMMcž¸víž5kf\½šê¶fݺlšEÕVTìÉ̌Ÿ=›Æþ™Ý»ÐÐÕÉÉ9«V…””d:uÅ?þÖäQ’ÒŒŒHÚÊ;»%ivöÉþý]8ý0 ëž='dï8Ñ5QffFœòMæGîáï!9C7míÁ!‰Dв³  ÃÄúú\¦{XYY›šz /o•‡‡ÆØÜܨ¢âÁ—_nŒŠòWQá÷ïßÕÃÃÉÙÙ!djjæ;vì⪪ZuuµôôC))s‡ï‰1}ãFùúõûeƒ‰ tuµC…„Œˆ«®®T÷®[>bDoŒñ¬Y£nÜ(OJÚÇìâè8…ÆÜØ(nh[ZÏ™3!DRÏýû¥RÒ¶­¡H$477Êɉ£+v”ô®®î B¨uk-EK†*+k““sRR"||Ü1Æaa¾×¯—ÇÇo óeªõôtF™™ ™jõõô´Ðÿ¯°b~¾s§ŠV[]]·yó©©¾¾}Bsçú54ˆÙÓ:%13)us³g§”ÝâÅ‹eýãèhÅ™7:8´Û¸ñpc£XUõ…sFîš(zKGy~À‡BΜáܹ4„P~þù  U¹¹ß룟[`‹‹K%é°a ™‰ôÙ³†òò*++㟜œ‚~øùÖ­{ee÷.^,CI¥Ò JÅb‰››=³bÞÝÝQîœÁÚÚ”–¡K\Å%%·Äîî̾}ú8±ç Æ›š"„ž=k8{öÚÂ…)&Ä>¼c¤(ž^½Föøâ‹UÑÑéŸ|ââíí>jT_å½34ÔE=xðÈÚZþCÉ/–I¥¤gÏNì>&&î­®®Sž4åìâÅ2‰DêæfOÆ8*jBèÀ‚&“R:ëcRÊ®¿¢âBˆó°5ÆX(ÔmlWVÖ¶mkÐä4c¬_v_E!ŽŽVÊóÓ·oç&ëïƒW}ž¡S'KŒñíÛ÷mlD66"kkÓÓ§/ýõ&„PAÁ¥_ýs÷î% ÁAAÞN¥¥!BPçÎíÕÔTNœ8Ï\ƒ/,¼¬(D:àf~urj¯ªªrúô%%û²_¤««EÀJâùå— AA«¬­M#"Æææ~³víÌŸ~:ûða½’Þ©««ùû\¿~ߣGÿ°CýöÛ§N]455tp°âñ0;΂‚‹mÚ´Ö××fªµ¶6¥53Õ6‰îûûïW™>ŽýUhèšæv~=æNoÑÜ¿ÿSàîÝjj*ôþC“AÒ÷8)ÏOs: Þ E>¼—Tš/÷#ö¨Q$úû{EG§ëéiõêåPXxeæÌïÆŒñTUå·iÓc¼ys®žž–T*Ý¿ÿÔ·ßî@=yòÔÌL>:::]__ÇÍÍ>7·PîÂ$ÙæB:ÁÁÞÑÑi††ºÎÎÖ¹¹…ë×ïC¬oUUººBˆTYY³~}ö¨QZZJâÑÒÒHO?$•’9süÅû÷ÿÚ±£yëÖÚúúÚr{Gá]ºtÚñãçûöñÕW“»u³}øðÑ÷ß^·.{ÅŠ/Úµ3A ŠŒL50ÐéÒÅ&7·099'>~:ÆØÌÌHQÒš<`ÆÆúþþ^‘‘©††ºvvæû÷ŸÚ·ï׃ã™%FJŽS ç^††!tæÌe77{[[3]]Íóçoôéó¿û„ J]\lù|îý‡çÏkjê…B=•‚Ç7™ðAhÉëk8#Δ”s󬨨´;wªŒô‚‚¼/žŠ²µ5KK›¿5-í ¡¡®û©SIÎÎ……W:v4‹›®««5oÞ†ÊÊš=ìbb&/XÒœæB ÁÚÚ­BCWWW×¹¸Ø.X0>66S P¥ŸººѽTUUÌÌ„>>½cb&+gÒ¤A[¶,Š‹Ûâäت• ÿ®ÆóxXQïèr#S§’–/ß²paÊ­[÷ÕÔTºví°gÏúp6BhÆ9&&3f|WUUÛ¡ƒYRRø´iCB„¹Õ6sÝròÜÅ‹7ñÅÊû÷k:tmÙ²hРîžnòˆ08Ó0WW»!C\'MZŽº~}ë¨Q}ù-,Ì—¹CBÊË+š1c¤ì{“òòŠ||¢KK·YZs>m2?àƒ€ Bˆ×a¼BÈO?up°b¾¸-)iß‚Éuu‡›¹Ú(wùò-—ÏKK01ù7ÃùùŒ»øÆmÚÚaž¨ËÍ…1üM÷œüçÞgãÝ»OŒ[TtõæÍ{ÙÙ'—-Ë †×ÅÞÞbâD¯Õ«w2÷¶GFN€ ÀÓyŸ¡®îÉüùÉ99§>¬‰„þþ£¢&2k“À+"„xï}xsïÌx½`ÎÞ{på  ÌÊÀœà‚…Ià½s€20g(ÓÂ9Ã<^¿²²»äuÜM#„Ð ÿþ»òUj&„ìÚucOÎ<^¿ž=CZÛ'ŸÌéØÑ_vû¦M¹|~ÿÒÒŠ—Š“"‘HÓÓUW×½l$„ššúŽý¯]+'„äæzz΋%/[Ï®]Çy¼~²YêÙ3¤e9§)âìKaRô²u2)z-gxE*-؇=’{-_òÅ®ÄË«Û;»…B½ÔLwÁŸ8ñµµ)û#55UBÈËÖI :aÂÒÓ§/õìÙ‰½=#ãÇO>qi×Îä¥êÄçæž™>}å AÝ_6ŒqDÄ_ß>:ˆBŸ~Úcýú}‰‰{ÃÃG7¿æØýòËZÙµ,ç4EgÎ\vs³gjÀÓµoßö¥*¤Ó!š"ø 9€÷Âû Ì…Ùk½ì‘ÜëºÏÀü¬®®fbb ¢Â•z uML Øÿè´l@ìëÛÇÀ@gëÖ<¦rBHiiÅÉ“N›6´“¦ž—Ý·¸¸tûöcsæøÑ0ÆÑÑþ±±™µµ›˜F uõ9)z©x(B“"vnܸCSô²gƘê„^/ùsåw8#9±X²dI¦•Õ8ÀËÆfªU;¥Ò ÔÕ= Olß~¼@७=¸oß™'NÓqsc£8**ÍÄd¤†ÆÀ#JJnÓ]˜µIô‡-[òœÕÕ½œœóóÿ ûJ$Ò˜˜M"Ñhuu¯Þ½Ã–/ßJ§7J‚¤rr x¼~iii=11›´´>½x±Œ¶•™yÔÑqŠ@àÕ¾ýøõë÷ÓÔÕÕíØ‘ßÐ fë™™GŒŒô||zBävŸjhÇÄlj×î3ÀËÎ. #ãBÈÛ;Šbn'Ý}éÒ,K˱´Lj꿱Ñ-J×Óª¯?¼¬ìîš5»îah¨Ë77{¡PoãÆÃ²ÇHѯ&,“"ºEyŠh%*MÑóçL=LŠ”Ÿ!²)"„øøDÓñùý妈ÝG&E²‡ø0À}uðÞ“¿6‰s'3¸äü:kVâÏ?ŸMNžkggQXx9$du}ý“¯¿žŒ ˆ»uë^ff”…E›»wDDl9òË»w÷ªªògÍJÜ»÷—ÔÔy;·Û·ï× RäF²vížää¹ZZÓ§¯œ8qÙíÛ;y<¼paÊæÍ?¦¦Ftéb³ÿ©ùó“•wáíÝ+(È{Þ¼ ƒõ(+»»tiVJJD§N–eewB³g¯[µ*ÄÓÓ97·0<|Æ((È!4uêÕ«w>|Æ×·BH"‘fd™<ùSUU¾¢îÇÄLA…†®>p `Æ9ÎÎÖ{öü2uê ##½Į̀I“–¥š˜è#„ÂÃwî<žšáìl}ðàé°°5ÏŸ7„…ùÒ€?êTÒ£GOÌÌŒ²³OÆÅM皺îÙsbî\?ÎvEK¼š<²Ã‡÷|©û`Œ™Ñ!$•š"55ågˆÜedD¶ ErÏðêäÌ´µ#„$)BÈÎ.€+ëës™ìkÕ••µ©©òòVyx8aŒÍÍ**|ù寍(~ÿþ]=<œœ­B¦¦†aa¾cÇ.®ªªUWWKO?”’2wøðžãððÑ7n”ÓëÖ±±®®v¡qÕÕujbâÞuëÂGŒè1ž5kÔåIIûØ{uïþg4œ–6oìØ~¡•+CŽ??mÚ7×®ýýÙg‡0e¢£ý'M„1ö¹víï•+wû „ìí-ÜݶlÉ£âŸ>W^^8”Ý}OOg„™™é~]Ýc:±¡qFDŒmh‚ôô´BB¡®±±~UU]rrNJJ„;Æ8,Ì÷úõòøømÌ€8*Ê¿S'K„ПþõèÑ?ŽŽVì>ÆØÁ¡ÝƇÅb‰Š Ÿ½.ñ’Í'sìä¦hܸþcNЦNÌNÑäÉŸ"„‚‚¼iŠ‚‚¼1Æ:YÒÑiÕÏ?Ÿ¥)"„(9C˜ѽæÎõS’"šüÐв)¡»È¸ IDAT²··€'Þ9s†sçÒBùù烂Våæ~cl¬^¼&ÍŸ—J$ÒaÃ2%é³g ååUVVÆ!!>99?üðó­[÷ÊÊî]¼X†’J¥.”ŠÅæ‘YBˆ»»£Ü9ƒµµ)-£««‰jl—”Ünh»»;0ûöéãÄ™3ìÙÛ® {‹±±>-¯¡¡¶eË¢=¾hÛÖpýúÙìù—— SgÏžß}·§¦¦¾ukmú˜oPЪ‡ëõõµ32~0 +}€XI÷oݺ'‘HÙGEM „¦C|š¢1)¢O?7'ELQQBȦˆ)#›"˜0¼Qræ 66"B}ÀÀÒÒØÌ̈S€=ΖJ¥¡;bèË|"‘P,– 0çæÍ{~~žžž]‚ƒ-ÊË«üý—¡ÿ¹‚˜ ªªüUR<f7GW·sö•}tÁÜ܈™lp`ŒÏž½ÊãñîÞ}pþü>}:3©ªªpêTQáÓÆŒñœ={ÝŽùŸ}Ö?;ûäæÍ‘t»’îÿõW³Üé³;S†i—Çû÷9æîý_Ç©Ïç3YjÎЙɕ¹¹‘HQvŠz÷vd§ˆ™Þ0)¢[dSD·7'EJžªgRÄi—¢¼ 4Ÿüg •¿‰ýi§N–ãÛ·ïÛØˆllDÖÖ¦§O_þúëM¡‚‚K¿þúçîÝK‚ƒ‚¼=<œè«ú A;·WSS9qâ<3,,¼¬(D:˜f~urj¯ªªrúô%åû*D^½ú÷œ9I11Süüúı_:tæÌe¦ÎS§þ´³³ÐÒÒ ­·j%˜0á“íÛÞ¹ó¸ŽN+ºÜˆ®É¡Ý·¶6¥`ºO?úý÷«L£G²š˜ƒƒ‡Ù})(¸Ø¦Mk}}mvþ !ô6Âýû9‡æîÝjj*Í5­ò#K7^»VÎNQ]Ýÿ8sæ2ó 8M‘¶v+ú‘¦¦:'E4r%g“"&’Ñ£¿ ]#7EL»²)‚ À¥ðû†ï%•æËýˆ=Ö‰„þþ^ÑÑézzZ½z9^™9ó»1cmÚPv»´-þ¨Q}ùmÆŒ‘ÌGR)ÉË+š1c$gÐLÉË+òñ‰.-ÝfeõÂC L1ÙaŒëê1)âóy:ÊSäççÉžÀ8;[3)bo—›":{iYŠØO®Ë=CÀk„ Bˆ×a¼BÈO?up°bkNJÚ·`Ar]Ýa·løxà@a[Z¿ŸPBÈ•+·]\>/-ý¡m[ºåøñócÇ.¾qc›ŽN«7ÝúÁƒ§åNBÿEØÁW.ða Sà=§ð{ ß[ãÝ»OŒ[TtõæÍ{ÙÙ'—-Ë Ôâ ƒò¯9{O`ŒíìÌ'NôZ½z'³²?!a{dä„7=a@oà›¿ÀäÛ3BV¬øÂÆF4|xd‡çÎ]ÿùçÃV¯kñpÿCcŒW® 9xðôw!GŽüþìYÃÌ™£ÞBÌÄ´ ¼!ÞÚ$ï¬Màõ‚µIà½÷áÝg¼M0g(s€20g(s€2-œ38PÀãõ++»ûZ^ôI¡þýwå«ÔL÷UUPYYËÞ^_ÿ¦æ§´þWöe1½++»Ûü255õ;ú_»VNÉÍ-ôôœ%KÞçWÁ€UKæ ¯ýmýìJ¼¼ºÝ¹³ÛÌÌèekf¢âñxÙÙ'™_ !99Ïž5pн5c¦SŠZç|G!$"bƒ¯oSŒñàÁ®ÚÚ­÷Âw#!¸&Þ{ ç Ì…Ùaîkÿ4v%êêj&&**ü—­„‰jÀ€®{÷þÂüŠ1Þµ+¿woGN±·‰é”¢Ö9i¼pá¯íÛÍ™ãGËB¢£ýcc3kjêßF¸°ÈŸ3(¿“ÀàŠÅ’%K2­¬Æ ^66V­Ú)•þ[ ®îIxxbûöã/míÁ}ûÎ~ë’%›é: îøñó™™Q¥¥ÛŽ[19òËÆF Ýëû理D\¹’9thÏE‹6ÊdíÚ=ÉÉs‹ŠR55Õ'N\Fg# ¦$%íKLœUR’5fL¿˜˜Íì]<<œ töíû•ưÿ©.]l,,Ú0ÂÃ׮ݳfÍŒ«W³BC}ÃÂÖ$&îeº)·EÙ]Ö­Ëf*LHøaÍšÅÅß››M™³)%enqñF‘H°Œ™AQJrBI$Òìì“ýû»pfntݳç,Oo™œ9ƒ¶ö`míÁcÇ.FÙÙèè ÑÖÌ.ÀËVVÖ¦¦HNž;p`7ss£1c<- øöÛ]BPÿþ]7oŽtww‰„ݺن…ùÖÔÔWUÕ>|XŸž~hùòéÇ÷´´4ýùçCåÆèêjש“eHȈ»wTW×ÕÕ=ILÜ»|ùô#z[ZÏš5júôa/t‰‡GêK—'Ñ…I~~ý˜O«ªê’“s˜ÝCCGûÄÇoSÒ"³‹»¥¥qX˜/g—¸¸éN¶¶f_|á]_ÿÏÊ•!nnö¶¶fÓ¦ «¬¬­¬¬a¥NaN˜2W®ÜzôèGG+ÎÌÍÁ¡Ý¹s×Å &o€Šì¦sçÒBùù烂Våæ~cl¬"„°Ÿ` —J$ÒaÃ2%é³g ååUVVÆ!!>99?üðó­[÷ÊÊî]¼X†’J¥.”ŠÅ77{f½¾»»ãúõûeƒ±¶6¥etu5Bâ’’Û bwwfß>}œ’’ö±÷=ÚóÓOçÕÔÔ‚Žû#5uÞÙ³WéG/–I¥¤gÏN´GcwwÇÄĽÕÕuŠZ¼v­œîÂŽ–½‹½½Gijª#„¬¬LhÉV­!±ø÷0FŠr”©¨x€ õ89 uÅ••µ¦¦†JŽ(¯—œ9ƒˆB0°´4633â`ßg ƒÝ;b:t±ËˆDB±X2`Àœ›7ïùùyzzv ¶(/¯ò÷_†þÖAbr"Añx˜Ý}´€³¯ìê©>}:èæäЙ‰‰‰>'`V „îÎãñµÈìÂi‘Ù…Ïç±çQ+|4\INX»cZ9ç>ŸÏ§áÉ­*ŒáÕIà='¤Î­rÖгíÔÉc|ûöý¡CÝhᬬ¼,ܼ9² àÒ¯¿þyæÌ†îÝmé.K–d"„A;·WSS9qâ¼½½Ý«°ð²¢9­;9µWUU9}ú’’}™åI ì…I!+Ÿ>}ÉÎΜN .¶iÓZ__[Q‹Ì.L‹²»p& Šž:P’½pÿþCú¢U¦Â»w¨©©0FðvÈŸ3 „†ï%•æËýˆ=>‰„þþ^ÑÑézzZ½z9^™9ó»1cÙ^¸PêâbËçÃWw€·JáœA Îø8%%ÂÜ<+**íÎj##½  ïÅ‹§"„lmÍÒÒæÅÇoMK;hh¨ëãã~êT’³s`aᕎÍãâ¦ëêjÍ›·¡²²¦G»˜˜É ¤4§9„PBB°¶v«ÐÐÕÕÕu..¶ ŒÍTÙez÷vÔ××îܹ½g÷ 昘d̘ñ]UUm‡fIIáC”·(»Ë´i/<´ÝÌû JrÂÄÉçóFê{äÈoaa¾¬T(/¯hÆŒ‘ðÞ$ð–a‚"Çßu/òÓOg¬Œõé:)iß‚Éuu‡y<üq ©/_¾åâòyié&&ÿö1?ÿ±c߸±M[[ããè#à†=aí5¯<ÏÞ{ÞBŒñîÝ'Æ-*ºzóæ½ìì“Ë–e úh& !{{‹‰½V¯ÞÉÜgHHØ9& àíû ï3ÔÕ=™??9'çÔÇõ"‘Ðß`TÔDÎÚ¤!äÑ£ÜÜ‚sr⬭M-Z±b[^Þ*x˜ð^€û ¼^pŸ¼÷>¼9€w æ ¼^0gï=¸n Pæ e`ÎPæ e`ÎP¦…s† x¼~eewÉë{ÌŸ"‘HÓÓUW×B˜&ä–¬©©ïØÑÿÚµrBHnn¡§ç,±XòRm)©ŸbÓ’þðQhÉœ=†~_1†1ÎÍ-œ>}åÓ§Ï5Ç”ŒˆØàëÛ§CÆøÓO{hk·JLÜÛüÁ=ÆØË«Û;»ÍÌŒäîE§"4ø5ð_¦pÎ@/Ãÿýw¥Ü!;óóë½Ï ·6Ù!{qqéöíÇæÌñ£å1ÆÑÑþ±±™µµ›ººš‰‰Š _î”cÌT÷À™ü9ƒò; œ1´X,Y²$ÓÊjœ@àec3aÕªR)aÿlÙ’ç쨮îå䘟ÿÝE"‘ÆÄl‰F««{õî¶|ùV¯_yy•·w!ÄÜÜÇëGKæäØÙ¨«{uë6½ àW¬Y³kðà††ºLlnnöB¡ÞƇe£U´ŒŠÙ.7NBˆO4 †ÏïÿrIà#"ΠüNg\>kVâ¶myÉÉs¯_ß÷y|üÖ%K63Ÿ®]»'9ynQQª¦¦úĉË$)!dᔤ¤}‰‰³JJ²ÆŒéóoùÌÌ(ŒñÙ³i{è–ÔÔ©©¿ÿž¢¦¦:~ü„D"ÍÎ>Ù¿¿ 'ȺîÙs‚-!„Yƒ¤¼Sœ8¥R’‘Iƒ¹sg·âð‘S‘ݤ­=!$‘HBvvt¨]_ŸË`¸++kSSäå­òðp››UT<øòËQQþ´@ll ››=B($dD@@\uu@ š˜¸wݺp_ß>¡™3GÞ¸Qž”´!¤§§… uõéî Á½{;"„ÂÂFNœ¸´ººîÞ½‡ýãèhEa¦c‡v7‹%ìåFcº‰ÓGÙÛ²q2ÁÈîðÚÀ*hðÞ“3g8w. !”Ÿ>(hUnî7tøÎ 3…‹‹K%é°a ™‰ôÙ³†òò*ú«µµ)cèêj"„Å%%·Äîî´NŒqŸ>NtÎ ‹>åŒÒÖÖ@=ÞXQñ!$êqî…ºâÊÊZSSÃ&»-{ŸA6Nvax ügÉ™3ØØˆ!%%·B––ÆffFœì·T*EíØÓ¡ƒˆ]F$^ºT†âñ0gpO_ŠJÈ¿sE>S|>ý)3|çñxœi ŸÏ§Í5gˆ/[@6N%…øïxÕç:u²Äß¾}߯Fdc#²¶6=}úò×_ob—çÌ œœÚ«ªªœ>}‰yëQaáeÙšÙͱ·ÓÛ÷ï?äy÷î55ÎýE½_UîTÞ›þ˾kuøð^Ri>çÑaŠ=†‰„þþ^ÑÑé?üðó­[÷wí:1sæwššêªª|¦ gÐo` ì–“SpëÖýääœõë÷Ñb„Й3—™¥MHf(okk¦««yþü ÎøþÂ…R[•ÿµK={Öp÷î±XÒä­Nœrƒ࿦%ßéÆp§¤D„…ùFE¥ÙØL˜3g]P÷ºuá첫‚?ÿ|Xhèj[Û‰YYG,T]]í† q4i¹­­?}nÉ åù|Þ¨Q}ù½Q*%yyE£G{Ⱦ7)/¯ÈÔtôßW6ùµœ8ÙÁ4;7|l0A‘ão¹Õ¼¼"+ú>"BÈúõû,H®«;Ìç7=‡!„\¹rÛÅåóÒÒÚ¶ý·†ãÇÏ»øÆm::­Þxôð‡=á5/¼NÃßxϵä>Ã+"„ìÞ}büøØß/¹yóÞ¾}¿.[–0¨9„ÆØÎÎ|âD¯Õ«w2OD$$lŒœ^»wsŸ¡¶öñüùÉ99§>¬‰„þþ£¢&ª©©4ÿ EuuOÜÜ‚sr⬭M-Z±b[^Þ*λ¼pŸ€× î3€÷Þ»™3ø€Áœ€× æ à½÷Ö&> 0g(s€20g(s€2oiÎ@‘H¤é釪«ë^Wðxýþþ»’~sMM}ÇŽþ×®•¿Jb±$=ý‡Ç¬Ö­‡ ^ææ~“&-¿pᯖÕF9p cOæ?5µO,,Æ­ª©©W¾/í]YÙ]¹_YýæÐ˜iÓÍ)#ÛG¯Ÿ@àei9vΜ¤ÇŸr ¿Í8_¶¿¿¢v9ƒÚ³g¯xOºB,–pR¡èLcÿªüHÉ=%ŠÆæêj'êmÜx˜Óœù/uæ#„^êÌ>zòç œ‘lBȬY‰Û¶å%'Ͻ~}k\Üçññ[—,ÙŒ1ööîä=oÞ†¿ÿ®úå— K—f}÷ÝÌN,33£0ÆgϦUTìAÉÝ©íÚ=ÉÉs‹ŠR55Õ'N\&‘Hi‹ß8%%âʕ̡C{.Z´‘–H¤ÙÙ'û÷wÁ3‘?~þÔ©¤C‡â--™Ìò33#Î÷Â…Òššú»ËöרXŸ^µUÔkEaK¥Ü©½%²bŶþý»èêjbŒÃÃ׮ݳfÍŒ«W³BC}ÃÂÖ¬[—Ín}êÔ!÷î=8!¤§§… uõ™Ý=<œ0ÆææFÌî´‰ØØ@77{„PHȈ€€¸êê:~zú¡””¹ÞÞ½B³fºq£|ýúý¡+Wn=zô££{Ðåß©“¥lïä.? „TUÕ"„Œõ™!Μ9Ié釘2%%Y**|E½fÂvuµc‡M·;:N¡Õ66Š¥RâåÕ-55‚RUU—œœ“’áããŽ1 ó½~½<>~[X˜/Ó®½½E¯^23 âŠÊÈøqàÀîffÂââr[Ä+¯3.nº‡‡Bè‹/¼Ç]¹2„¦zÚ´aŸ}¶¤²²†•Ô¿W'ggk„©©aX˜ïر‹i®8˜>"„ž=kÐÕÕ>¼×7ßÉ–”Y PMLÜ»n]øˆ½1Æôà&%íCЍ(ZÄ‚1–{ˆe+‘=ǘSTù&úùs×§O_9uêào¾ ’¡¢3ù¹É£/!“(_ß>¡™3G2‰bÎ[‡v7nl«ª¾ð× gþ:ó€ÿ9s†sçÒBùù烂Våæ~cl¬d†eÅÅ¥‰tذ…ÌF‰DúìYCyy•••±††Ú–-‹zôø¢m[ÃõëgË^¿T²;ýÕÚÚ”îE¯R76Š/_¾)KÜÜìi$cwwG:g¨¨x€â99?üðó­[÷ÊÊî]¼X†’J¥²9¤}‹%?ÿ|.22uàÀîII³i²1—”Ünh»»;01÷éãÄ ËjÎò9Eå™08ç»p“íúû/{þ¼Ñ¸™ç˜l¨M}Ù™D1g)“(f‹P¨ÛØ(®¬¬mÛÖ ÉØàÌG¯|æÿræ 66"B}ZÀÒÒØÌ̈S€Bÿíܱ#†óž"æé³g¯òx¼»wœ?Cö½+Jv¿t© !Äãaöp‡Ãò¿ë©ÌeTº…Çã±Ç…**üææ!ÎÎÖÚÚ­Žû£{÷Žt£‘‘ž‘‘Bˆyp¢9a³c`~¶°hÃ^"Å„Í A˜áÝ…Ç{a͘ŸŸçœ9ÓÃ_t IDATëvì8Æçó55Õ½½Ý™d[l²N>ŸÇŽc…OvŠÅ’æÜ¼yÏÏÏÓÓ³Kp°Eyy•¿ÿ2¹…™>ÚÙYtè`6lØÂçÏwï^,[R6f:\#„3zùû ŠÈ=Ç”–ý(*jâ³gÏ##S?ý´‡µµ©òÖå¶Òä‘’IóWÀTÈláóù²û*‰Î|Y/uæÿ-yžcÜ©“%ÆøöíûÖÖ¦66"ÑéÓ—¿þz-õêßsæ$ÅÄLñóëÇ\Âdj`v§ûZ[›2»³Ûe7ݹs{55•'Î3ë¶ /Óè…Ìû÷Ò‚’ÈÁ ªaa¾ß~»óæÍ{œ0nÝºÏ [¶×쪚ã25;8XñxøôéKÌ€¯ àb›6­õõ_x馦úgŸ Ø±ãØ®]ùþþÕÔ^˜éqZlNœÜ*й àÒ¯¿þ¹{÷’„„à  o§ÒÒ „¢¼2• ØmÉ’©ÙÙ'ÙK\”ÄìäÔ^UU…3spßÜ}$/J s>š0á“E‹,,ÚLº‚.äkŽWPSS¡¯”mNðÑSø®ÕáÃ{I¥ùŠ>533ò÷÷ŠŽN×ÓÓêÕË¡°ðÊÌ™ß㩪Êol”Lœ¸ÔÁÁjþüqµµ§„…­ÉÊŠ¦¯L9sæ²››½H$T´;ÓçßòÖ­µÂÃGGG§ëë븹ÙçæÒ…I![[3]]ÍóçoôîíÈÞEî`åùóÆššz¡POö¡Õ¯¾štñb™«kðìÙc êÞºµöµkå?nß~¬{÷ŽzzZZZM†­h &{-cܦM뀀A‘‘©:]ºØäæ&'çÄÇO—íE`àО=Cx<ÞêÕaœz8-6¿Î&cnÓ¦5Æxóæ\==-©Tºÿ©o¿Ýzòä©ò>BæÍwøð™ R†í)·$ûWà`ïèè4CC]ggëÜÜÂõëÿ]˜$•’û÷"„„B=öub%÷ž=k ‡XQyEy`Ÿ¢¦¦Â&ÛTÓÓç÷î¶zõ®¹sý8!É=ÓØoÁ‘R’(&ó.”º¸Ør®©Ã™/7Ÿ¯ëÌ€W×$À{¯…ßéFII‰07ÏŠŠJ»s§ÚÈH/(È{ñâ©¡¯¾ÚxéÒÍsçÒTTø††ºÉÉs}} ÔÃ×·Ï!®“&-G]¿¾UÑîì&8ÆÅM×ÕÕš7oCeeMv11“,HAñù¼Q£ú9òÛŒ#95ÈVòòŠ||¢KK·É.™T³³—îÜ™¿ysnBÂöúú t\]í¶oÿjäȾ<F5¶¢kފƬ6Ì11ɘ1㻪ªÚÌ’’§M*Û‹nÝl;u²ÔÐ88Xq’#[ssêlN̶¶fiióâã·¦¥44Ôõñq?u*ÉÙ9°°ðŠŽ’>bŒy<´qãü.]¦…†®ž:uH“ÙHHÖÖnººººÎÅÅvÁ‚ñ±±™j]ÝcSÓÑ¡ÒÒmVVÿ{¨¢ B˜C¬¨¼¢®®vÌ)úûï)ŽŽSšl×ÍÍ~öì1_}õý!nvvæì È=Ó8Ù#¥$Q´$!(/¯hÆŒ‘pæ¿Í3øèa‚"Çßu¯„råÊm—ÏKKhÛöõwØû ±Qle5.&fJ`àæ,Åù°B~ú鬃ƒóöž¤¤} $×ÕæñpVVÞäÉË++÷è°û¾o߯#G~ùº¾vPVfæQ¹í¾[yyEVô H„õë÷ÓDñù<„P~þcÇ.¾qc›¢/Mûà|Ügþ {ÂeQøO‘ÿ<Çclgg>q¢×êÕ;›ÿ ÃR[ûxÿþSaaß‚Æÿä£6aŒwï>1~|lQÑÕ›7ïegŸ\¶,+ `‡Ä+WnŠšÀ¸_¾|ëçŸÏÒ…ûo"'ÏŸ7Êm÷Ý"„ÐDýþ{ÉÍ›÷öíû•&ŠN! Û##'|†ÿÈ™|(>†û T]Ý7·àœœ8æ%Œ‡YY30ÐÙ´i!};þLJRW÷dþü䜜SÖ‹DBÿQQU„Г'ÏZµ°©TJÌÌÆ<~ü4:Úþüqo(*ÙvßµµeE>z´hÅŠmyy«èâC÷_8ó?`pŸþc>ž9€·æ ðó1\ø€½g÷´s€20g(s€20g(óŽç „‰Dšž~¨ººîMÔF©©©ïØÑÿÚµòW©Y,–¤§òð˜Õºõ0ÀËÜÜoÒ¤å.üÕâ8(ÀØ“ùOMí ‹±AA«jjê•ï{à@ׯ¬ìî[þ& 3mº9edûÈãõ¼,-ÇΙ“ôøñSNáÄ“›[èé9K,–´ ªª*+k™v !õõÿhj~ÊãõûûïÊì[>^Ñ;ž3`Œss §O_ùôéóW¨ÉÖ†1ŽˆØàëÛ§CQ‹«}þ¼qذ…‹¥ûøôþ嗵ׯoݼ9òñã§nnÁ'O^hYœô “+*öTTìùë¯6mZøã¿Mš´\Iؽåï À{yu»sg·™™‘¢eCb÷ñÎÝ%%™Ë—Oߺõ§/¾X…b*lA_0ÆŸ~ÚC[»UbâÞæŸ9LC</;û$ó+Æ8'§àÙ³Eø/S8g —cßô5WBSÿ«Ôdk+..ݾýØœ9~-î!dùò-¿ýVRP°~Μ1ŽŽíÌÍú÷ï²{÷b§… S[vœþ Ꚙ˜˜ˆDÂþý»DFNòç M^Ï&„„†®NNÎYµ*¤¤$30pèÔ©+rs !áá‰k×îY³fÆÕ«Y¡¡¾aakØ«G֮ݓœ<·¨(USS}âÄeR)É̌Ÿ=›VQ±‡–9~üü©SI‡Å[ZÄ?~>33ª´tÛ±c«1Æ#G~ÙØ(AÉð㿱k“H¤ÙÙ'û÷wÁ3=bWÎ^š"wá ÆøÂ…Òššú»ËæÁØX¿ukmšY³·mËKNž{ýúÖ¸¸Ïãã·.Y²™))ÛkNª !.üµbŶþý»èêjbŒeÓ¸n]6»õ©S‡Ü»÷ðÈ‘ßiïòóÿ¸}ûþ”)ƒ•´¨¼Î„„Ö¬™Q\ü½¹¹Ñ”)ñ11›RRæo‰„/ÄŒRr\NtÒ’ŸÿGll†—W7]]MN1¹1/\˜’”´/1qVIIÖ˜1ýbb6sê0 ëž='8G‡"wáSÌÃÃÉÀ@gß¾_iööï?Õ¥‹…E›fvpöìus玽z5+"bììÙë6l€i>f*²›´µ#„$)BÈÎ.€¹êës™„êêºÍ›LMðõ탚;ׯ¡ALªªªKNÎII‰1¢7B(4tÄõëåññÛÂÂ|é¾±±®®v¡qÕÕuzzZ!¡PרXŸ–‰Šò···@‚ú÷ïêááäìl255 ó;vqUU­šš `ĈÞ㈈±4vm/–=zô££{@åß©“¥l¯é:ÎFBHUU-BÈØXŸ¤Î™“”ž~ˆ)SR’¥¢ÂOM=—·ÊÓÓ!df&¬¨xðå—£¢üõšnwtœB«mlK¥ÄË«[jj!„I£;Æ8,Ì—“F„½½E¯^23 âŠÊÈøqàÀîffÂââr[Ä+¯3.nº‡‡Bè‹/¼Ç]¹2ÄÍÍ!4mÚ°Ï>[RYYÃJ‹Âã"›X¦¡gÏtu5‡ïõÍ7A²%ecT÷®[Nò¬Y£nÜ(OJÚGî;8´Û¸ñ°X,a/šÂË= ¬çð¨Q}÷îýeêÔÁ¡]»òýüúÉvÐÉ©=ÆX$r:í?yòÿ±wßqQïÀgî¨"Rº‚ ¢¨hÀŽ4¢±F,Xb‰¿%*FFD5ö+T{Cш±#±+Mîn~L²¿Ë5N4ràçýÊ+¯»½ÝÙ™gOg÷Ù½O !Çw¾~ý9s6ÞwA@e¥&g8wn !äàÁóÇÏMOÿŽOåù¯@)½xñ¦L& ô¦n11ý!ü*—³&MêË›5«›˜¸U˜%{z:ñvøiæ’©j¼¼œþÙ9²KZÚ‰õë¹}ûÁÍ›.^¼I‘ËåB„^ÅÄôcŒíÚuRhçÞ½'„‰ÄRq2çåå¤8í(¥üJ¯˜ç#ŠŽî?rdW!Dr¹<;û–L&ïÔ)JhV&“¿zUœ——¯}Ô»v%89ÙBŒŒ íí­LLŒx¨/^¼ÉÃ($*Jaäî1ïÙ³b±hË–#+VD ©îñúõ<ímúø¸ñäÊÌÌ„âááÈ׬RŘ¢øx"J‰¦ã¢C>F©TöË/碣SÛµkœ”ôoS‰jŸ¯^½S\,mÖÌWès‹~RÝc©mŠÅ"ÅžPªñV`-ÇE•0Foo·š5]:uŠzýºdóæ©ªkªö™'*Œ)÷Yqb±XضÔ#«¸B‹õll,ÒÒNH¥²À@GGkÝhhh ô /óÜúOMÎ@T2ÕIm:î”Ò3g®Õ®íÊ?ýüó)vvVS¦ ‰èÉ“—¼½]ù”îĉ‹ööVÖÖæjW}«¸ðĉKÇŽývêÔâÆkñ%Ó¦­"„0F„x{ó*&Ö³ç7vvV!!B#üÄóÇO•¦òotÁØØ02²Û÷ßoêÝ»µ»»ƒb#·o?ä¯ygîÜyÀ[^µjÿÞ½™+VDk¦ÚåŒ1__Æj´˜j !ff&}ú´Ý¸ñ€¡¡Ahh;#£M¥–uiS)IÐÔg-ÇEûÛµk4mÚà˜˜%K—î2¤c©Ñðó«ahh ØçÌÌËŠk2Æîßbdd t5IÅ åIÅÅ%Š…IŠüøãÚ|«øøÕŠg „|öYS¹ü ¦OmBCƒ££Smm-¼½]wì8¾}û±]»ìí­ÂÂÚGG§ÚØTkÐÀ+==399-!a¨â¶JSþ° S§.óêyÅuìí­(¥+V¤[ZV•Ëå;vÿþû„—/ÿª]ÛUm „ÖjÕr±°0;þ†ð MNí4ýõë’gÏŠ$K¥Æ”Ò)S\¼x3 `ÄW_õlß¾±••ùõëy+Wîݰá@ãÆµ--«V­j»ÔÒ²jÓ¦¾™™WFþ¡gÏ CC±â.ÔFRmJ¦KùVáá›4)‰æÍ‹TjGiº·YjŸµícdŒMœøÅž=§&MJ騱‰Ú5ßÚØT1¢slì[[‹úõ=ÓÓ3-ú»0I¸ÎpáB®¿-ÕÓü¯^óªxýDi€¼JƒøMöª©À‡i,F€2 ¦@ÏiüèJ€RêííÚ¿ð¼y›4•ÙTPŒ±‚‚;vŒü1Ò·ï'•/a „PJ7o>Ü·o|VÖµ[·lÛvtúôÕaaíE"^—DgÏÞÝïý$ ¤¼‡ ¼TæœB)3gä®]'oܸ[™&y”R™L:}ÿþ3k×NVûèÒJ€16kÖ0//çÏ>‹®Y³ÿøñ‹¾ü²“pçÆ¾}g^½*=ºÇ{;²ÚK¿Ê¨MQ ²ªÌµIðŸ@mÀ¦’_g€·„œ´AÎÚ gm3”+<‹ô^s™L¾téîÇ K}Ìe~~Á˜1‰Õ«÷16¶±éܮ݄ôôLÆcLhDu«;OˆD­oÞ¼_æÇh>{VT»vèõëyŒ±ôôÌ  1R©ìZcŒ©í<ÿTScBçËÖs½R–œÏ‡ó×_¯µ?¥¾¤DúÉ'ãÏ»¾bEtnîºC‡æûúztê½yóaBˆÐˆê´;8¸ÑÝ»›]\ìÊö|ÆØ„ ‹»ukáååD)íÐ!ÀܼJbâVÝ[cŒI¥2µÿé§CZ"@):_™~>Xs~²ü?©N|)¥ÂB-ÓbÆØñãûí÷… ǶlYÏÙYR·nõï¿hÚ´ÎÂ…Û·Uv›˜9:ÚˆË0$ÆØ… ¿oØp`ܸ^¼eÆXllh|üªgÏŠtl„R*t¾E‹º¼ósçŽTí¼j„Îãg¿ PŸ3hÿ½[ÆX—.±Œ1W×^bq~JþÛoW»»÷66ööKMÝÅ747¯BÙ¸ñ@q±TØüèÑÄÇ ”vîá4ˆ§(“'/µ´ìhmýYbâV^ÞׯY“Q¿~¸‰I°Ÿ_øÁƒ¿ ¥MqqË?71 nÞñÿñÇINN¶Šð–cbB}|Ü!»vTìR||x@€7!däÈ®aa3?.466LLܺpáØ®]›SJÇŒéqãF^RÒvBÈ•+·Ÿ?ÿ³n]¥ÌÇ×·ú²e{JJ¤††ÿ5/%R¥45u‚Ðy~Fpp#-¯SDzsç ¥Îú¨í|·n-!£Gw: oÔ\g8wnɹsKæÏEIOÿŽ¿ÕR­tñâM¹œ5iRG8߬YÝû÷ŸÏjÛ¶aròø7Öýþûú„„a'O^úâ‹©j{ÃoYV­†òôü{¹……!¤¤Dš[\,mÖÌW¸c¡E ?¾ò½{O!‰¥RŸ%‹’é£GºßšÌ¯N$'ÏÉY{óæ†Y³†kïk*—Tû Œ1SScBÈ©S—óòòíí­ÂÂÚGG§îØqüöí‡ÉÉiÉÉi_݇ÕÏÂÂ,(hìºu¿äæÞËÉÉ[¼xÇ”)Ë&O322PlD±q]¦Ý66ÕFŒè»„ï4%eç¢EÛ !”ÒZµ\,,ÌΟ¿¡”ù\¸ëï_K,V¾þðêUñýûOø¹ÅåBçׯ?À;Ÿœœ¦½ó:&ÑOJÚ>iRraᑈ^¹rÇßÿËÜÜõŽŽzð௽{O½qc¹¹©>œÎÏÈÈòõõàÏkbŒ-Z´ƒw^,.Ë/s¼W4ˆà.,€wˆRü™=WQg¨”ÒÍ›÷ퟕuíÖ­Û¶>}uXX{~ñ[ÿþÁóæm®3Ìž½!:ºŸž$ Œ1Þù3g®Þºõ`ûöc¼óH@Uàë ……/¿þ:9-íøÓ§EÎÎ’ÐÐv11ýyycìùó?G¤¥ÍðôtÚ¿?kÖ¬usõgR^PðBµóFFúÒ”×Þ-\g½WQs(7ÈÞ-ä  ÷ôå¼;è'ä   r€r…Â$Ð{È@ä  Ms™L¾téîÇ 5ýò± ?¿`̘ÄêÕûÛØtn×nBzz&cŒ1&4¢ºÕÎ'D¢Ö7oÞ/µ}Mž=+ª];ôúõ¼2·À1ÆÔª)Œ1aeØczz&¥A”µn=ÖܼÍ£‘žž4F*•½Ñ¸Þÿ( Ò(KÎÀg®C‡Îùë¯×ÚO ¤DúÉ'ãÏ»¾bEtnîºC‡æûúztê½yóaBˆÐˆêT58¸ÑÝ»›]\ìÊö{Œ± wëÖÂËËém~ñ€1&•ÊÔá§Ÿi‰¥T›&-¼)Jivö›7O»qcݪU1ÂÂÌÍ«$&nÕ}\å2 ¨44æ üóaÚ­݇ “Écš† ØÕcA)mÛ¶á–-‡u,%*÷Q@…¦&g07ï`nÞ¡wï©„oï°jÕBÌÍ;(®ÀãÕ2‰…ƒƒu~~arrÚÌ™C»vmîîîÑuĈ. ëø”tÉ’‰s{ölõë¯9cÇ&z{‡µk7ŸJWl„·êããè£Ô¥øøð€ï:uÜGŽìzÿþ“Ç _&&nv:fL¡C;ñ•¯\¹ýüùŸuëzð w` ÛÚµ<…X½z_HH€ƒƒµÒ„[S¥45u‚0„1cÔ®Ú¾ýļ¼|¥8C¨SǽI“:ªC ôñõõPB·n-ÜÝFî. A1Ôª×|c¾¾ÕÏË))‘*­¯Ÿ£€ MMÎpîÜ’sç–ÌŸ?Š’žþ«¥ZéâÅ›r9kÒ¤ŽpÞºY³º|BÉ—´mÛ09yüë~ÿ}}B°“'/}ñÅTµ½á·,«VCyzþ½ÜÂÂŒRR"ÍÎÎ-.–6kæ+L£[´ðã+ß»÷„"‘X ý8°Ãúõ¿ÈdòüüÂôôÓvx£ê|~^?9y|NÎÚ›77Ìš5\û”&úÂørÕ!ý† ¸kµ×$‹’é£Gºßš\Ž£€ Í@u‘——3cìêÕ;„ww;¥”¦’r¹œ¿¦ï|‘H4kÖúׯK¾ùf_ÁÝÝaâÄÞ&&FcÇ&¼PÓ±ÚI°HD—ó;(!ŒÆŸX+ÝQ-‰„þ„†¶‹]ºÖõëX[›wìÈ·*5:Œ1>„)SÂø^Üݾþú íCPÛ²H¤<û† 7¥(¾Ö‹Åªmêí( B+ãý Š+øúzˆDôäÉK™æ'.ÚÛ[Y[›ß¾ý`Μ ÷ï?Qj¹Jã*ULÔÎJÕ^gP]îçWÃÐÐàäÉKÂT53ó2ÿÈÉÉ–òðáS¡?vv–:5Ù¸ñÀúõ¿„…µ×ý)@”R>„ž*=\HË4Í›•– Cú) AÓ¨…5ïßbdd \KÑóQ@…¦ñY«Ÿ}ÖT.?¨öc¦¦Æ„S§.çååÛÛ[……µŽNݱãøíÛ““Ó’“Ó¾þº!$*ªŸ……YPÐØuë~Éͽ—““·xñŽ)S–Mžfdd ØˆbãºLUmlªÑ96v ßiJÊÎE‹¶B(¥µj¹XX˜?Cè9¥tàÀO·m;š•umàÀOÕŽèÕ«âû÷Ÿð³æŠË…!¬_€!99MûtL{„!¤¥àq† iÔB‚táB®¿-±X¤´²~Ž*45µI¥¢”x‡„ 0“’“³vñâqŽŽ+Gú!?¿ fM—¤¤±áá!”R77ûÓ§SfÍZ·L©5aŒñ!œ9sõÖ­Û·†ÀWÈÏ/|ú´èÑ£á6e^ª4{ö†èè~z’0h€J£_g(,|ùõ×ÉiiÇŸ>-rv–„†¶‹‰éÏKbcÏŸÿ8"-m†——sywV£‚‚ªC022Ø»÷tÇŽQ„V­ü²²®½|ùŠÂ+ŽöïÏš5k]FÆ\ý™”k…>¤4ðŸÀu€w ×@ïUÔœÊ r€w 9è=}9W ú 9hƒœ´AÎÚ gmÊ-g`ŒíÜyB$jýÇø’gÏŠj×½~=OÓ/¿iûR©léÒÝ­Z±²êdlìêÚkÀ€™.ü^æöy‡) ¢4H$jmdô‰›[ïáÃç>{V¤¥Ma¤7oÞ/ëhÊNص–*®“žž4F*••!Jš^¶žó¸ñhóÿ®}[]Fý_ÐåX—ï÷  Ê-gP|x?ÿ©² wëÖÂËËéíŸëÏ+.–vê5yòÒ.]š9² 'gíŠÑ/^ü8âØ±ßÊ0•6ÉÌL¾woËÝ»›ÿ}ýòåQ{÷ž0`¦–>+´ Ã)3ÆXpp£»w7»¸Øiê¡b—(¥:˜›WILÜú¦GáõëM?zôB:Ï;@)å¿wo‹bÀµ'iJ¼7”R!àšzˆŸ­exÐ*è=MìÜy¢K—ØÛ·7:;Kþ‹YŽÒŒêÂ…ß7l8pëÖ†w²/JéÌ™kNŸ¾š••êááÀÛtuµkÓ¦A‡_GE¥?¾° mò‰…ƒƒ5ëädÝäÈyÏŸÿY­Zµ–ïÖÄÄÈÑÑFû:ÂkÞÕØØÐI~jee®ãŽcBÀ«Wwä ]]íZ·®2)**õرÄ7»7‰ÄB‚³³„¼¨è/M¿„­4¢÷óRþžóF€·§þ:ƒ.Ó\™L·ÜÙùs“àæÍ#gÎ\Ë ø9þ¸¸åÕ«÷16öö[¹r¿’PR"‰YâèØÝÔ´]»v®^½#´6þO:|,‘X’~ãyìØÄ5ú››whÙrôáÃÙª}ÐT‚R\,MLÜÑUH„q-_µk×LÞ©T6mÚ*/Œƒ½¼úÍ»I.gBéÈš5õ뇛˜ûù…<ø«Ú˜PJMMÉ?—J¤RÙ·ß®vwïÍžšºK)€ãÇ/úè£R©Œ¿•ËYõê}¦N]©v|µm c_¹r_ƒCLL‚kÔè»uëÑÝ»OÕ«7˜¯¹–bŒ¦¨*‹Rà-‘X.[¶G)ªšŠjc%%2p!aäçAx£€+íBx!\mpø6œ0a18_®=àš"_þ®®ú5Ðsês†RËicQQ)IIÛÇ\½ººgÏÖqq+„O#"æ%'§Í;òêÕUáážµwïiBȘ1‰?þ¸'%e•+«:vl2yò2¾¾L&ß¶íh›6þ|_”Ò°°‡_µ*&7wÝó(¥Ý»ÿ¯¸XªÔµ…7Œ± rŸ=+j×®±RÂC)up°¶²2ç“ã1c×­ËHNŸ“³vÆŒ/ÖN›öÿ£X°`Kròø¬¬T33“þý§ËåLqüEvvî¬YëÚ´iÀ/2Œ›¸`Á–ùóG]»¶:"¢[däüÄÄ­Š<8äÁƒ§ûöáÓЃ½sçá AÔîQ&“3Æ´·9{öúùóGegÿèêj7hPB\Üò””ñÙÙËœ%aaÿê3!DmTKJdJ㢔¶mÛp˖êÑS[xC)®úmáç—9à¼'Œ± ~ç·°0£”ªgáÂmŠ{θö€ó=joóÝ BPS›dnÞ"“É !ÞÞa|ºVT”.¬ÀO &&n]¸pl·n-!£Gw¿q#/)i;!äñãÂ+ö¦¦NèÚµ9¥t„ÞÅÅRÆÈÓ§EK—îNIÿÙgM(¥cÇ~~ãFÞ¢E;!W®Ü~þüϺu=ø¾ärÖ¦MÃV­üüüjPJ%‘‘Ýz÷žšŸ_ðÑG6ŠçøÕÖPJóó !ÖBiÊW_-\ºt·°ÎÕ«« Ä©©;32æ¶jåG)uuµ»wïÉÿþ·,&&”¯èC9²kXØŒÇ ùòºuñ6KJ¤r9 n”š:’Ÿ_˜œœ–’2¡k׿„ˆˆ®99y ë"#» ûõñqkڴΪUû:v $„¬\¹·]»Æ..’ììj÷H)ÕÞæŒC[¶¬G6¬sß¾ñsæŒlÒ¤!dÈN}úL{ôè™ÂQ#š¢ª:~|}}«/[¶§¤Djhø¯oˆÚ€3Æ„€ -Œ—¤)àAAõ !..Õ€xëpƘð.]šQJ##»i xHH€Ú€+íQ¸¦6gÌÚª•ŸbÀù!Óðúõ= !NN¶ª¨Ôä çÎ-!„>n|ïff&„GÞB•*Æ„¡ŠB)ÑUÅÐñ½H$%%ÒGþ•¤iB).´P¶€ó´ÜÄĈwU¸â7JSÀŸ={¡6àJ{®©M7a!à|Ͳ BP“3xy93ÆøÍîî..vJ+ðšoBcÿfZ(Já(ˆJšñÏšÿ?1ÎaóD"‘p:¹mÛq·n=èÕ+((¨Áˆnyyù¡¡Ó•ÚÔ„RZ¿¾§¹y•~mԨߗ¥¥0.òÏÔmãÆ¸š57wv–\ºt“"Qµ5ZnnöÿªÚçŸ sA¥˜ˆDÿ*ëÕ+hܸ…7‹Åff&;7>RÝc©mŠÅ¢— i¼ÿD*•iŠªbèø^Äb±j4aŒ oܸ6_ÈNy£€+ŽE1àîîJ=¡” Á¾Qe¸ÒKmS,)ö„R÷4ëpBþþ礼; úç&)Í\U§k~~5 Nž¼äííʧV™™—ù§uê¸SJÏœ¹æííÆ7ïÙó;;«o¿bddpøðyŸ¿— ›ð³È>õòr"„œ8q騱ßNZüñǵùšññ«‰BŠR*£ÈÈnß¿©wïÖnnöŠ©ËíÛûyçÎC^&Ä[½:cïÞÌ+¢Ç®¶}µ1ñõõ‰¨bLNœ¸hooemm®¸ZÕª¦}ú´Ý¸ñ€¡¡Ahh;ccC¥–ßêØ¦–Z¢ª4.JéýûOŒŒ „+?jT쀱±¡pwwÅUÀÛ\µj¿RÀ5íKu9cLŽðR !ÄÌÌD1àFFÿúÎ+µ¬K›JÖÔg!à×âëL›¶ŠàyzPi|ÖêgŸ5•ËjúÔÖÖbĈα±Klm-ê×÷LOÏ\´h;ùç&ãÐÐàèèT[[ oo×;Žoß~l×®+«ªcÇ~»ÔÚºZ` Ozz&/L"„Ôªåbaavþü-êBìí­(¥+V¤[ZV•Ëå;vÿþû„—/ÿRšÂ¾zUüìY‘Db©tö—16eÊ€‹oŒøê«žíÛ7¶²2¿~=oåʽ6hܸ¶¥eÕªUMCCƒcc—ZZVmÚÔ73óÊèÑ?ôìdh(ÚÑ} Kqp° kjcS­A¯ôôÌää´„„¡ŠëðéfxxÇ&MFŠD¢yó"µO@íí­tl³Ô>k‰ªÒ¶ü&rÿZªQ}ýº„ÜÀ@¬Ø8¥ôü’4]‚÷R ¸öK÷6Kí³.¨4æ Ú1ÆfÏan^%"bÞãÇ…þþµ&M꿊Ÿ5ON?uêŠaÃæ<|ø¬fMç5k&úéÇ„3†ZXT8qñ£GÏ>þØ;.nà¤I)„±XÔ£GË}ûNGFv£”Ö®íºdÉÄ„„µK–ì²µµèÒ¥ÙñãIõë‡gf^á×.„>dddué››»N©XˆRjdd°mÛ·›6\±"}öì EEÚØT ðÞ°aJ÷î-Åb!$%e‚«ëꘘ%wï>¶³³>¼óÔ©ƒ•†©iøjÏ|/^<ÎÑqå¨Q?äçԬ钔46<S—/ßö÷ÿ27w½££µŽH¿ÄÃ㋸¸AJ“Q=qð௽{O½qc¦M«pJJ¤<àáá!•cD匡Ìà]Âý  ÷Ê2¿'„0Æ6o>Ü·oü™3WoÝz°}û±éÓW‡…µ/[Â@ññqëß?xÞ¼M•{JWPð"-íDd䌑¾}?ÑtM 1ÆfÏÞݯ$ Œ±‚‚;v^ÑGP.Ê~¡ àÅ×_'§¥ú´ÈÙYÚ.&¦¿‘‘AÙ¦eŒ±çÏÿ ‘–6ÃË˹ô * ÆØÓ§E_ØØT[¾<Šÿ.Dywê_cû÷gÍšµ.#cn™Ó?½òäÉs!àüw!àÀu€w ×@ï•=g€r€w 9è½Êp.þ;È@ä   rÐ9h£G9ÃÎ'D¢Öüñˆ1Æ_ß¼y_?ÁàÙ³¢ÚµC¯_Ïû/Ú—JeK—înÕjŒ•U'cã`W×^̼pá÷²µÆƒIiðŸ‘Ñ'nn½‡ŸûìY‘ömËë((~tY‡1–žž4F*••a_š^æQóŽñh‹D­®¥M]FýßÑåX—c÷ |éKΠi¦¢o¿`@¡”N˜°¸[·5k¾ûß‘xýº¤S§¨É“—véÒüÈ‘99kW¬ˆ~ñâ¯ÀÀG^([oùÿ33“ïÝÛrïÞ–ß_¿|yÔÞ½§ ˜©} «ÔÈ{C) nt÷îf;¿Ÿ~ú±¹y•ÄÄ­o4ÑgŒK5üرßÊ6›ð€ß½»Y1àZ"©øÑûOÒ„€kê¡fïðÞhú`çÎ]ºÄÞ¾½ÑÙYò¦ŒZf*ú–6dgçnØpàÖ­ ï¼oŒ±™3ל>}5++µzuG¾ÐÕÕ®uëú!!“¢¢RK|Ó= S=‰ÄÂÑц¿vv–DG÷9r^QÑ_š~ïYi ûž‚‰‰‘Ð[µTSšØØÐI~jiYUÇÞRJ…€{x8ð­\]íÚ´iСÃ×QQ©Ç/|Óž »–H,¬ù[''[ðçÏÿ¬V­ŠŽ#zo(¥¥\ßþÀû¤þ:ƒöé‹PD±rå¾ †˜˜רÑwëÖ£»wŸªWo°±q°·wØþýYŒ1^øñí·«ÝÝ{óå©©»„ÆKJ¤11K»›š¶ õêµáûZ³&£~ýp“`?¿ðƒeŒ :Ç×w ÐÚë×%¶¶gÍZÏw:mÚ*/Œƒ½¼úÍ»I.gB·'O^jiÙÑÚú³›7ï¯Y“áë;ÐÈè‡nááß¼à­ij16þO:|lkk!ô­Ô8¨žRc¬¤D–˜¸-"¢«0‡`ùò¨]»þ>K­}tJR{Xc¦¦ÆÂµÇH±Û&,þè£R©Œ/—ËYõê}¦N]©éÐh:îºsKe _Ž›X£F_cã`só-[Ž>|8[u\>‰å²e{T¿±š oŠ‹¥<àB 4È.ŒE÷€«ý³C)®68äßÐÆ_ÄÎßj¸ðUmS÷¯h©Çu€™úœA{™„ðéìÙëçÏ•ý£««Ý A qqËSRÆgg/sv–„…M—Ë!dìØÄ ¶ÌŸ?êÚµÕÝ"#ç/\¸ÏœÆŒIüñÇ=))®\YÕ±c“É“—iéè‚[’“Çge¥š™™ôï?].gƒu¸|ùö¹s9¼µ]»N>þgXX;BȘ1‰ëÖe$'ÏÉY;cÆ— k§M[!4uèÐùãÇ“vïN()‘ 8³gÏ œœµ›7Oûùç³ÑÑ©BßÔ¶ “É·m;Ú¦?¥T÷8(Í#ÕÞPJ/\È}ö¬¨]»Æª1wp°¶²2ç‡CûèT¥tàc.ü>kÖº6mXX˜QJÕ#ŽòàÁÓ}ûÎðQ<øë; ê eÚÛÔå›# ›qèÐùU«brs×80RÚ½ûÿJJþÿÖa\mÛ6ܲå°j’¦¶ð†1&\)Í ”ò€óñ–9àBO²³syÀùEÕà(UU çßFí—ÉäŒ1ím¾Û€À‡FMm’¹yBˆL&'„x{‡ñéTQQº°‚0™1ch«V~„aÃ:÷í?gÎÈÀ@BÈ!úô™öèÑ3±Xœœœ–’2¡K—f”ÒÈÈn99y ë"#»=}Z´téî””ñ;7%„ŒÓãÆ¼E‹vhêh||8o|äÈ®aa3?. ôññq[»6Ãß¿&!dõê}!!Ö¤¦îÌȘTŸââ"¹wïÉÿþ·,&&”7êããF9vì7¹œ}ô‘­³³ÄÕÕ.-m¬–®]»óüùŸuëz(ÎðJƒRÕ‡Ú:ÆX~~!D(haŒ—´téna«WWˆµ.>>< À[1P|yݺƒx³%%R¹œ7JMÀËÏ/ÔtŒ„ýúø¸5mZgÕª}!!„•+÷¶kרÅE’}Cí)¥ÚÛ,5b a!mÚ4lÕʯ~}OBˆ““mdd·Þ½§òX ¡ã“{_ßêË–í‘JebÅsüjN)._}õÕBMoÕÊRêêj§p¥o¦–€B„€wíÚœÑUKÀ;v Tp¥= ×ÔæŒC[¶¬§ð&Mêh¸Ÿ_ J©³³D5àðŽáZ.è=59ùsK!ž>|nzúwÖäßí 7>u633!„xx8òªT1&„H¥²+WîÈå¬I“:Â$¸Y³º‰‰[?.¼xñ¦T* ô&|ÍšÕÕ’3xz:ñ}YX˜BJJ¤„;Ì»ñ»ï†?}Z”ž~zãÆo!ÙÙ¹2™¼S§(¡Ÿ2™üÕ«â¼¼|þÖËˉÔ´©ï矷6lnlìÒO>ñïܹY-µ·pïÞBˆDb©xfºÔ8èr?¥”_I((x!Ä$:ºÿÈ‘]…Ã!—˳³oi§çߣS !d×®''[Bˆ‘‘¡½½•‰‰?"/ÞÔtŒ»7xpLjˆyÏž½‹E[¶Y±"JñÐ(íñúõ<ím–1…°‘#»¤¥X¿þ—Û·ܼùàâÅ›„¹\®:¾‰Ä¢¤DúèQ©vŒ1!àB e ¸ê7S5àÆÆ†¼!àŠß|Mú´HmÀ•ö(\S›>>n|ïBÀy e 8|hÔä ^^ÎŒ1~w»»ƒ‹‹Ò Â)v±X¤8¦T¹I˜gS¾‚H$úg–öÿ>CC7dBD"ª¸/ÞNhh»ØØ¥û÷g]¿þ‡µµ9?)ËwºqcœÒsœ%—.Ý$„ˆyÄbÑÆß\¹rgÏžS¿ür6,lÆ?îÙ·o¶–nܸËû¯8ÒRã Ëý£Œ±úõ=ÍÍ«8ðkãÆµùB;;K;;KBˆp³G©£‰¨âÞ…×nnöîîJ=¡”j9FŠköê4n܈Åb33“Λ ©î±Ô6K˜@*•µm;îÖ­½z51Â-//?4tºRèø^Äb±Ð]’4!àÕâ-ð€ ߢ[ÀÕÖò¹¹Ù{xüë¾¥àßü2\i¥¶)ÿëK©Æï¤.€Í[ÝÏ@f'ÂGŠŸúúzˆDôäÉKÂTæÄ‰‹ööVÖÖæõêÕ0228|ø<ßœRš™yY{_U÷eoo#úÈ IDATÕ©S“¬_ÿKXX{CCJi:î”Ò;wzz:yy9{y9Ÿ}Z¤¥~æøáçJ#Õ]FFvûþûM·n=PøíÛùkG§vF¨º1¦å)®iffÒ§OÛüôÓÁÐÐvFFÿJðt?Ö1Á‰—Žûmóæi³g>¼s«V~¹¹÷È¿¯â {¹ÿ‰‘‘ÒU -LLŒxÀoß~¨ÔÕ€óh{z:©\i,ŠË•–PJ…àß|ÕàPJ«V5U ¸p™BíulSK !àsæŒ>¼sË–õT§ö?û¬©\~PíGJ³+MBìí­ÂÂÚGG§ÚØTkÐÀ+==399-!a(¥ÔÚÚ|ìØÏcc—Z[W ôIOÏÔR˜¤e_~گ߷/_¾Z±"ŠŸ]vq± Ž]jiYµiSßÌÌ+£Gÿгg¡¡XiÛªUM—.Ý-—³qãz•”Hwì8V»¶«••¹µµ¹¦jÕr±°0;þFóæuKí›ÚOc¯_—<{V$‘Xˆ•V›2eÀÅ‹7F|õUÏöí™_¿ž·råÞ 4n\ÛÒ²jÕª¦:ŽN•êÙwžw©=FªýïØ¤ÉH‘H4o^dÙŽ»îSlŠRºbEº¥eU¹\¾cÇñï¿ßHyùò/¥qQJ/\Èõ÷¯¥UBÈ«WÅ<àJ×7cï$àšRµË¬K †bÀµ_¹Ò%à:^ûÒ%àð¡ÑV¤‰–3誑ŋÇ9:®5ê‡üü‚š5]’’ÆÒ‘o8cÆP ‹ª'.~ôèÙÇ{ÇÅ œ4)EË~Õî«C‡€jÕªÔ«W½vmWá|sJÊW×Õ11KîÞ}lgg9|xç©S«nÛ çš5“gÌXãç^¥Šq›6 wíJà#PÛ¥ÔÀ@Ü£GË}ûNÕ½Ô¾)~*,¡”fddué››»NµXÈØØpÛ¶o7m:¸bEúìÙŠŠþ´±©à½aÔîÝ[ŠDTSß´-Ë)¥šŽ‘Rÿ5ªU§Ž»©©±¯¯Ñš:ÍÇ]Lj jÕrY²dbBÂÚ%KvÙÚZtéÒìøñ¤úõÃ33¯ØØTSÜV.gY£FuWJcBÀ•Š…(¥FFZ.‹ˆ×=Iã Uƒ¢ ÿš<àüZ‡ö=êØf©}Ö%à𡡌•w7* ÆØ•+wüý¿ÌÍ]ÿÑGÚ~«ò))‘zx|7(<$¸ÎoK\g€Š—ô2€J ×à­á K•rxGP°PI¡6 *”'T È* \g€ÿ –t„3b ÷3@…‚ß„¨pP°Pñ!g€÷? Pa!g€÷Kr¨hPžP  `  BAÎåKr¨€p© ’AÁ€~CÎúKú 9è,èä P1¡<  ÒCÁ€Þ@Îz Kz9T(X(?È ÂByÀKå9T4(Xx¿DåÝ€·À/5À‹±¿ÿÀ_ÿ%\g€ Kÿ1ä P) ` à?ƒÚ$¨àPžJP°ð®á:TFx6+T zòýÿ¿Cÿ, Â,áK(Ó“¯)ÀÛÀCWÞ¥ÿ?GPDƒP›Ú gÍCΕî„xK(LÍ3€6È ²À¥€ÿ¥È@á ›*3€6È AyÀ»Ã{õªxΜ ~ijÚÎܼC‹£¶n=úNZ–ÉäK—î~ü¸ðí[ãvîå§8Ö¥5aýÌÌd ýêUñ©S—ÇŽ]øðá³5kbƒƒݽ»Y"±,C…öYàé餸‘‘‘¡âÛ·»v……/5Äñã{é¾wä  ŒR:iRòӧϳ²R«U«Â'—3f|Y\,}M}##ç7mêKyñâ/~…„¯)DBHÓ¦¾‘‘ókÔè;sæ:¥bxn¢üܤ ~ýº¤I“:JS^‰Ä²iÓ:FFJSí1c×­ËHNŸ“³vÆŒ/ÖN›¶‚RÚ¹sÓáÃ;Oœ¸ø?ò¹ðí·«øat:î«VÅPJÏž]rïÞBˆÚÍ…ö,Ø’œ<>++ÕÌ̤ÿé2™œïñÇ÷¤¤L¸reUÇŽM&O^ÆWÎɹ;pàÌž=ƒrrÖnÞ<íçŸÏFG§*B©óü…T*;tè||üÊààFŠ“l-}ˆŠJIJÚž˜8æêÕÕ={¶Ž‹[AT¨Þ9 ÔícŸ={ýüù£²³tuµ4(!.nyJÊøììeÎÎ’°°é<»8þÆ—_Îvsë½}ûѸ¸Awîlš5k¥T8ˆJ9ŒâALHzçΦ¸¸AÛ¶quí5dÈwçÏßPj“ Òá—þû;Š*±Â—„+«ª¥Ï0Æ=*HMÝ™‘17(¨>!ÄÅErïÞ“ÿýoYLL¨¡¡xΜ‘‡2ä»ë×ÿèÓ§mxx!ÄÒ²*ù§4HؼU+?J©««°9ßE||x` !däÈ®aa3?.40/]º;%e|çÎM !cÆô¸q#oÑ¢„‡ŸÊåì£l%®®vii3(¥J£æÐuë–¿zUlaaöÙgM¿ûn¸ê0Uû`ll˜˜¸uá±ݺµ „ŒÝýƼ¤¤íŠ[5n=vì·fþøcº\~Pi5ä  ÌÖÖ‚òäÉs//gíkRJ³³se2y§NQÂÜT&“¿zUœ——ïáá`jj´fÍä?öÑG¶‹}¥zÞ]Ëæü­§§ߊŸþ/)‘^¾|K*•úðd€RÚ¬Y]ž34mêûùç­† ›»ô“Oü;wnÖ£GKM×víJpr²•Je¿ür.::µ]»ÆII_™š©SµW¯Þ).–6kæ+ô¡E ?¥œaË–øêÕ—88X¿ÑØ}|Üø~ÍÌL!Ž|Í*UŒ !R©Œ2eJXJÊÎþý¿6¬ó!mm-x„ƒèéYJâ—Ÿ_°téîää´ââ’)S”?Æs“€åç&Õ­ëQ¥ŠñÉ“—¼§›÷î=é×/~êÔÁ-ZÔåËcr¹œ²qc\ÍšÿJ0œ%|³g¯‰D¢û÷Ÿœ?£E‹zJ{Ö²ù¥K7 !"U{—3cD胡áßÓZ±X´iSÜåË·÷ì9õË/gÃÂfüøãž}ûf«½ÎàæfïááH©]ÛµfM—N¢^¿.Ù²ešjxTûÀçëŠ}PM‡\]íT“.ÅÕJ»X,RÜ/¥ÊÅN”Ò¸¸AQQý6l8˜¸5>~UŸ>m#"º5hà)D~iBØûýûO…ƒxî\NRÒ¶ x{»M:¨OŸ¶FFjÜÏ•î„x;¦¦Æ¡¡í-Ú^Tô—â¶ß¿ñøñ‹NN¶Š7FשãN)½sç¡§§“——³——óÉ“—¿ùf9ßäÚµ?ÆKŠ‹Ô«Wë°°üŽdÅy°°9ßÖÓÓIØ\ 4#¯W¯†‘‘ÁáÃçùBJifæeþÑ‘#†Ÿëéé4aBïôôï,ýóÏgŸ>-Òrß3_ì?mÚàmÛŽò;¶Uc¢Ô?¿††'O^RíƒÒVJKÞrìü‚Rû&&F~zöljzúw……/†ó…ü >þ§âæÂA$„ŽxþüåÞ½³³²RüÔØØPí \geŒ±o¿rèÐù–-GM™2°Q£ZOŸ>ÿñÇ= n›5kX)®ìâb»ÔÒ²jÓ¦¾™™WFþ¡gÏ CCqI‰¬ÿo}}=¾þú‹‚‚u늌œ¿zu¬©©1!äÔ©Ë>ÎÎM› »PšÈZYU;öóØØ¥ÖÖÕ}ÒÓ3ya!¤jUÓ¥KwËålܸ^%%Ò;ŽÕ®íjee®ö:ƒb˔҉¿Ø³çÔ¤I);6Q‰RllªÑ96v‰­­Eýúžé陋mWZíñãž*µÃXÄ•aìª×ß¶jåײe½Û·òåZ"/šÊÉYëîî :X¥‘#g€J wB¼¤XžD)µ¶6?~}ˆ¥eUBˆžŒÞ¡BIH!>Ì%4è_¥ Âc?Ô%ÈàÀÿÌã¡« ÆØ´i«ââ–B4ð²··ºpá÷Ý»OíÝ{zÆozôhY¶f)ýûåAAõ-,Ì _ž8qiåÊ}Ïžmß>]Çmy÷ÊñÙí”Ò.]šB¬¬ÌµôDé#þºU+?ž!üõ×ëãÇ/&'§ýñÇ£;gBti*Õ« ô•ÉǺ¿Ïä ÿJq9ôÍ/¿œ oll¸mÛ·íÛ7&„Kœ¹qãA»›77ˆDe™Ôªž¡OK;ѵk,!äÞ½-Öo´­þS½ÎÀ_ó”àĉKÍ›GBòò6ô‘M¹öà?À¯3À?p?|p'4À‡dÁ‚-„Ñ£{´oߘRÊki,½gϬӧ“yÂpôè…Ö­Çš™}jaÑ1$dÒÙ³×ù¶Œ1‘¨µHÔzݺ_Z´ejÚÎÇgÀÎ'È?× ø¹6þ¢]»FüÅÃ‡Ïø‹ììÜN¢ªU ©R¥}óæ‘{öd µL¶]ºÄŠD­¿új!ßcI‰Ôή«HÔúçŸÏjÙ;ß©¦ö !”Q´víÏ-[Ž65mW¯Þà_ÍIHX÷ÑG=ÌÌ>íÒ%6?¿@qÍ3g®2Æd2ùÔ©+kÔèkhØÖÌìÓ?¾wïiÞUº6ùû5ÿ?c¬~}O¾ÚãÇ…Œ1Å6ùk¥!ý\¹r_­Z¡¦¦íZ¶½~ý/|¼ÿíÞr¨lNœ¸HiÓ¦¡â”W"±üôÓíí­!GŽ\øä“ñGŽ\hÐÀ³~}ÏýûÏ´j5ú·ß~' “û‘#¿‰D¶¶W¯Þé×ïÛ—/_)N£ù‹ýû³(¥b±ÈÉÉ–’Û´iÄž=™Õ«;6n\ûĉKŸ}½~ý¥)xxxGBÈÆe29cì—_Î=~\èæfߦMCòO6¢vﺴ?|ø\±……ÙÅ‹7Û´ù*>~U:îr¹|çÎqq+T“ ¶LºâñãÂöí»ºÚee]ëÞýÏŸÿ)ô„¯¦˜,É嬰ðåìÙ(¥f^^ND!©^+ áÏ?_3Æ6m:4hPBNN^ýúžýõzøðï÷z 9ü{çSúð÷.SRSjRšRÊ¥,¶\ [ånµ emº¬–\*k£E–6$*Y•[-É%B»b]£]jíÊmú%Tb·Ë̼¿?ÞÝósfN#ã²y¾ŸÓ9ïyÞçyÞ÷Ì<ÏyŸsšUUÏBGgÎü–Þùfî…GGonh§¦Î=yrÝñãk6mšÿ×_uË–m• ©ÃÂÆ;¶:??ŽRSó×ÜCÿ†Îóæ%½ÐÍmÖøñ_!„ÆŽu51`ŒçÏOþûïº)S†\¸zìØêÕ«C !sæ$J$R$v{z:[X˜@¬4!ôá‡<Þ@ FF#¢£7kii®];KW—/'“n3& „ž=û›š—… sæÌúóç“}|ËöÀ; ä À{”'À{ƒ‰‰!ôðaG»uk?jT¿Q£ú1áé¹s—Bþþ+h1uêr„ÐO?•Ȇԃõ@ÙÚZÐuu èßÐùر‹{÷ž:}ú7A` ×¦Móè)'N” „üü†ÐS¦MŠ*/¯¼ví’ Á54xÓ¦ Cef­¯çäœÀûù m´wUäØ!dnnLå üB¨uëV¡úú¹uŒqÿþݺuk·}{þ€ŸÛØ|LÔ×7 Ö:BÈÍÍÉÍÍI[[ cܵk»ßO÷óó@ÿ>0-·ÎÀ˜@åPèbΘ1èÎ Â:ü'€÷&Íþý»íÚuüС‘#{cŒgÎôž9ÓýûP/BH*%!WWG##}æ,--Mòï³!]]mŒ±¦¦S“Ãü/û(°,Ì£Õÿ6F²e#ãiÓ†-]ºu÷ý°ªê™››S»væHæmE {WE>Ÿ¯…ÂøŸ::ÚH敉ršB¾øbÝÚµ»{öìèëë±jUPïÞAŒ’²Òío¾ ìÙ³ãÙ³¿»»Ï¹t©lÞ¼¤;óxÿ¤:Lcº­««ÒÐà±Í—‹ ðŸÖ€÷ Xj€÷ƒÐÐ1¡ÔÔ»wŸ ·±%iJJ.s/¼G¡¡CwïŽÙ½;Æ×wH·ní?ùÄ]®t‡]ý/{‡^®SBȇÚ#„¶l9B›¥¥Â[X˜ØÙ‰äε±1ÿè£ÕÕÏgÏNDM™2”‰þ9zWQ>£Üé w¦¦@EGO MþÏÿËžH·]\RRæBvïþiõê]Ü^Â/–-99Ù"„vïþ‰îܶ-Öà?¬3Í~ýº.^>DCƒ'w.B( `ø‘#çïÜ©00Ð7Ε鋣wå+;]áN+«Ö¥¥·§N]Þ½»Ý‰%<©”ÐBØë ÌÆ¤IƒŽ»šzàË/7 îÒ¡ƒH™—ääÌûñ˜1_®]›}þ|i]]CiémXg€ÿ°Î470Æ úæçÇyyõ½wïq~~Q}½ø£z¬^zåÊKKáС8°bÀ€nW®üyâį;[÷Ýü3F¼Ê:B¨wïÎ'O®9²ÏŸVœ;WÚ§O烿?Þ ½XñO7¼½ûÒ'§'LpÓÓÓaä+ëc¬¢|ŠŠë [¶DõìÙ±ºúù¥Ke_}5u̘¡'Š‘’u& X½:´sgë¿ÿ®ó÷_!•ªºÎ0jT¿ï¾›ß¾}› ®¶Ü¸q.Bˆæ<¼ËÀoºïðûnê~Ó ^BÈ­[å:ùÖ׋úimß¾]Þ‡Ûí„´´CV98´9²B(;û§ñ㿲°0ùóÏo[;xøM·Ú$x£œ<ùkBÂî'JêëÅ~Øé=IBãÛ·Ë/NÇÐMSSãôéßBt©€wÈ€÷ú$4Ü<àm@ÑÒÒÌÍ=Cùè£6Ì~O„!$"brCƒxçÎãgÎüF‰„'üòK¿·­µIÀ{ ä jj“€æÔ&½ßÝÚzâìىϞý-׸iZUVÖtêä{õê&H „ìÜyLVCFÏ'Jš¦Šý¾VϨ×.BˆD"MM=ðèQõËžû&Qe~2†Ð{ÎË+ts›%KÞ¤ž¼àyà=~¨á­RW×àíyñâõyó|Ö­›%´¼~ýnbbŽ‹ËÌÇWöïßíeÒ—ÜcŒÏžÝ`i)DI$Ò«WïøûÇÞ»÷xïÞ¥ÊÞ‚/A¾á7åcŒÝÝ{Þ½»K(4$„(ì½SÖF„PmmýÙ³¿‡…­+/¯Üº5ŠØ4[!ááFîoggÑ Ì(?¾ÆÖÖBö±±@™¯{ô‘Z=£^»0ÆyyggÌX5dH¯×ç“W§ÑùI“j=:tè‡ë×ïIHØ6îµ €&9¯…ýûO{{Gݺ•% †Ë—o=w®´¨(¥];sºÓÊÊtà@'OÏù ¤œ<™ð²ú …sscº- #"&Å×Ôü­¯¯ÛhPþæ8mF[…(¼).k#BÈÚÚ¬ªêYhèš f´àÈÝWIÉ™™GoÞÌlrÊA7LLMVãUú}}ž¡j±‹Þ’§Ûïx`Í=?1þÿÛ鵃1ŽŠòõôœ?uêPCÖï¸u¨Ô& ~¸ïÜB$ 9ÁÁ£˜„i¼yó‚ÜÜåô,±X²dI†ÍÇ|¾»Ý'qqßK¥„©—غ5ßÉ)@GÇÝÑ1  à‚B!ºº|fX,ùúë-ÖÖù|w{{¿””\Ùè !¾¡M›±b±„î—JI»v“/NWØ#m£L&=%=ýp÷îÓutÜÛ·÷Ù½ûÄg»uó§-)’+˜©®~–о½Ÿï®¯?lÀ€Ï/VÑÉ<O*%R©”È¡³D"ŽÞ,ÓÑqï×/dùòm<ÞÀ?ÿ|ˆZ½zç°a …†´‹úzqtôæví&QÓÓsXX [m…6R™ û’3YY©Œ²~Õè5Ú…òòŠ$„XYMÀØ­ÑY´paª¡áðV­FŽ»Háüä˜$^,e…[:ÍÛ;Š¢¡1ˆžëââ nÚthN@μßÀ“ЯîÀc\Rr£²²ÆÃ£û¨™Y+##}zâ¬Y Û·ç'%͹vmÛ²eŸÆÆn[²$i¹vmvRÒœ¢¢==É“—J¥ò‰ ½k¾bÅöAƒº zã°°„µk³W¯½reKpðèÕëÖåÈöîïïùàÁ“ÇÏÓ;¦nß.Ÿ6mGÜ2W®Ü±zuhqñwVV¦Ó¦ÅFGoNNžS\¼I$úù½ 3BÈÏoÙ±c32"oÜØ~ôh<Æx̘/—†36ŠÅ’‚‚ 11éîî==¹f u^° 91qOB¬ÒÒ-ãÇŒŽþÇ«‰4'çÄ A=˜ 88>)i_\\PiiF@Àpÿ‡Sfµ\¦0]ä°Qa_ri©Œ¥¥);x­ža{þíÊȈÄÿüóÆ{÷²•ù“‘ìØÅS§ˆ]²Ä_áüTö„£ªœ±‰TNƱÜ/ÛiééÔ»ww1ž<øƒììãoøé ^+P›€šÑ׆¢A‰½½ #jjò˜„ŠŠ*„™Y+&Ș=;15õÓ¦´t‹¦¦FJÊþüü877'„¥¥ðÞ½Ç_~¹)2Ò—¶‰‰ pv¶Gòó[Æ}:gdöôtF¥§òðèei),.¾®°GŒ1·ÌeËf¸º:"„>ûÌËÇ'fÕª „Ðôé#&MZòða¥Œ[РA¸º::9Ù"„,,LBBFOœ¸˜úJÆF„Pmm½@ 7rdŸo¾ d·dëÌçk%$ì^·.lÔ¨~ãY³Æ^¿~'1qBèòå[OŸþÕµ« ^QQ•–v(%%œ¶ ŸX_/&)ódhè¦ß^½>“>W­ š1c‡ÚÚš û’ Е•Ê0Í^“gÔn—¡aK„P(03kÕèÌŒŒôíÜÙ!DQ8?}V'&&€N<ÆXSÓÿ?×1VèX¶X¶ÆætŒq—.í6m:(K´´ Ì€f\ÌÀ{< ­n~ùe#B¨ àb``\^Þ7ff­Ð‹Ï `ŒéJBUÕ3¦:"brPÐ(æD©TZ\|S"‘ޱ€9Q"‘ÖÖÖß¹SAÿ´µýç!]z ¹¡AL÷çæÆZX˜ „´µµZ·6ÒÑѦ \ºT&•’Þ½;3‰Jß¾]v˽»Æßxpp|eå3 ^vöOii ˜Cì¯^½Ã-ÓÁ¡-ÛôôtB66æ´e‹|„ìëe0FAAÞûöÞ±ãÇ[·”•=¸t© !$•¾pKXÖF±Xòã¿DD¤xxôJLü‚Ê”ƒ­siéíúzqß¾]û÷w¤‘ñ½{BôW„Ð¥Ke‰ÔÅÅ‚ÈÈO!Z]QQeb" -³³cd Ïh±‡ ûb›£ &8~MžaP‹]„ÜÜ3ŒFg¦s¥°ç'G sÈÖÖ‚ºˆ1V•Â!öB[ŽlcF¡PÐÐ ~ø°Š^‰4 g@ÍØÙ‰!¥¥·BÖÖf––¦r !NN¶úú-Ž½Ð«W'ºÓÔÔÐÔÔ!DODÿÆÊYYÑ:ˆdO‰„¿ýV†âñ°lLÃl·mÛÚÚÚL.$Â3Á7~ÑSx¼ª4'Lp›={]VÖQ ==/¯¾Ì!vÊÔÐàÉj‚±âjx„X,sfÛ;w*|}—*lÌØhoß¶CË#ÔÕ5ìÚµ˜Ý’­3MT‘×ýbòxÿèÌT°È¥|ªxÒÊÊ” Êe»Vf£Â¾T‡9å5yF½vÉب?555˜pœ=?9<ÆèÏãa9Uñ3»[»1ÆXCCƒ6æ–ÀxžõÃ]1æóµBBFûí÷7o>=D¹u«œnwîl1¾}»ÜÖÖÂÎNdg':sæ÷¯¾Ú,'JaÜ£°â¼KŸ9ó~>}©uk£V­ôe[êééLš48+ëèξ¾ÚÚ/Ü[‘ëQ™ì*…:Ÿ>ýÛÉ“¿îÚµdåÊ™^®®Ž7nÜCHé#Äãç’%þ99'd‹»8tvtl¯¥¥)«saáïô½+\^þ„êL‡àüù+LËqãÅ«èIvÚÆa£²¾T¬‰W¼ªÑ3j·« ³ˆöÅžŸª¬3 EóPÙYr²w*”Ãì$„Ü¿ÿX[[“.ÂÐ<€u€ò¤×ÂÈ‘}¤ÒeG1Æ‹M¹t©ÌÙyæ_Œ2¤—‘‘þÕ«wÒÓefíÕ«“¡aË–-u}}Ý£¢R [öéÓ¥°ðò矯?ÞMKKƒ‘£, dßCÅ·nmäç7$""ÅØØ {w»¼¼Â¤¤}±±3äš!„†÷îÄãñâãCääÈõ¨ºÌFunÝÚcœ––ghØR*•îÝ{êÛo³BÏŸÿÍm#!dîÜ<;~òðá½¶”ýÓØØ`æL¯¨¨&&''Û¼¼Âõë÷P=;v´ô.^¼NÃ̬•¯¯{DDЉ‰ÀÞÞjïÞS{öœÌÍUf5ÛR¹˜•ÃÆN¬ö%'¡®®¡²²F(4ÔÔÔíK®™Ú=£v»h¡ÿÙ³¿»¸8ˆDBÕgƘ=?¥RR^þ!$çŽ$AΊÚÚzêXÙ•1Urú^2Æš†•”ÜèÑ££ÜðŸrÞ|¾VNÎ×ß_––·refMÍ_ÆÆÎÎö™™‹ÆŒ@«’“í¬¶DFn¼{÷‘©©a` ×âÅþ²B”Ý+UëlØ0ÛÜ<=4tMEEU‡–‰‰aÓ§—mC©ž=;vîl­«ËïÒÅ5öêXUdª¢sÇŽ–7Îݶqc®‰‰ÀÛ»ï©S‰NN……— 8lÄóxhÓ¦yÝ»OŽ÷÷÷lÔ+WÎÔ×oÿèQuçÏ÷‰‰Éàóµ44xcÇ8|ø\HÈhü%%ÍY¼8í³ÏV•—Wvè ÚºuáСrXÍá+š“(³±S'+e}ÉJÈÏ/òöŽºqc»\ù™²"uy†ã¬&Ø5dH¯çÏk==§LYŽºvm›Š3“n³çguõ³6mÆ"„þøc‡¬g8Vüä1޵±1WvŠÂÎÎö²†´icLÊÏ/ Ó´23ÞMkÀ{ ,54 Œ9ö¶•P3 b›££§x6¿ ‡òÃ?wébü·*1qÏüùIÕÕy<|ùòí=>½qc‡¹y«æg;7Üžyw¼ÁžŸ„-[ò§N]þðáæ1ô·!䨱‹'.¾~}»A‹·¨ ¼*Ø ¢Yày€ „TU=Û»÷THÈBÏGïN˜¨F0Æ»v÷ñ‰)*ºróæƒœœK—nñóBÃb‡¶“'»ÇÇß,mç†Û3o[;¥ó“R_/^µ*32ò“·›0 „0Æ+WfFD| 43`þÖšFóZgxüø©ÍÇÆÆ›7/ ¿ Ñü „TW?Ÿ7/iß¾SOžÔˆDB__ÈÈÉ´‡òôé_..3÷í[fg'jTZs‚Û3ïÊæ'!䯿êèû|ß.‡Ÿ_±b{~~Ü;’h@Óu†œd€´¡ 4¯œ‚œA¨M€ ÈàrþP ä p9¼,5¼ä ¼5ÄbIjêW×YFF#ø|w+« S¦,/)ù£iÒ!û÷ŸÆØù§­ýQÛ¶ã*+k¸ÏÝ¿ÿ47°¬ìþ~•Õ™v­J¶<Þ@>ßÝÚzâìىϞý-׸iZUVÖtêä{õê&H „ìÜyLVCFÏ'Jš¦Šý¾VϨ×.BˆD"MM=ðèQõËžû&Qe~2†pxU½öBx¼ì± ÿ^]¾ÂëêV­ÊêÞ}ºžÞPOW×Y™™GU—@ÝøçŸ_jîå庹͋%ðŠKà]@óm+À{J]]ƒ·wäÅ‹×çÍóY·n–@Ðòúõ»‰‰9..3^Ù¿·—H_1>{vƒ¥¥!$‘H¯^½ãï{ïÞã½{—*{[¼ì÷ñ~£<ÆØÝ½çÝ»»„BCBˆÂÞÙ;emDÕÖÖŸ=û{XغòòÊ­[£M³…¾aôèþvvMÀŒÂñãklm-d ”Ùøê°G©Õ3êµ cœ—wvÆŒUC†ôz}>yuŸ„¼¼Bj‡êµc|÷î.ºýÃ?O™²¼¨(Åܼ£’zýI©­­:tÞíÛå_~9ÅÕÕQ,–äæžùôÓ•Gþ’’®ŠYåUïzØ0çõë÷$$ìþâ‹ñMQÔ ä À‚–'Á}WcÿþÓÞÞQ·ne‰DB…¡Æòå[Ï+-*Ji×Μ28ÐÉÓsþ‚)'O&¼ì?óÅ, ÌÍé¶H$Œˆ˜_Só·¾¾n£Aù›àtt´m¢ð£¬!kk³ªªg¡¡k6l˜m`Ђ[ w_%%df½y3³É)Ý014YWé÷õy†n¨Å.B#ðM(ÜóãÿÿÊǵ£v{• ["„„B™Y«×—Ž.Zô]YÙýóç“MMÿI8;tõîÝÙÕõó'OvoT³ýRŸ0„¨(_OÏùS§52Òo²   6 õÃ}_ÒÐ IHÈ Å$ LãÍ›äæ.§g‰Å’%K2ll>æóÝíì>‰‹û^*%L½ÄÖ­ùNN::*@ÑÕå3{ÄbÉ×_o±¶žÈç»ÛÛû¥¤äÊF3¡ðð mÚŒ¥Å„©”´k7iñât…=Ò6ÊdÒSÒÓwï>]Gǽ}{ŸÝ»O8p¶[7ÚòÈ‘"¹‚™êêçaa íÛûðùîúúà øüøñbÌãñ¤R"•J:K$ÒèèÍ"Ñ8÷~ýB–/ßF 'B«Wï6ìC¡ÐvQ_/ŽŽÞÜ®Ý$ªszúa«+§´ôö˪WVvcììl/nÚtÊ“€·ä  xúÕà1Æ%%7*+k<1Æ\¸}»|Ú´a=rË\¹rÇêÕ¡ÅÅßYY™N›½99yNqñ&‘Hèç÷‚Î!?¿eÇŽ]ÌȈ¼qcûÑ£ñã1c¾lhp8™†_bbÒÝÝ{ zrÍê¼`Arbâž„„Y¥¥[ÆýW%iNΉAƒz0 @pp|RÒ¾¸¸ ÒÒŒ€€áþþ+:§Ìj¹LaºÈa£Â¾äÒRKKSv:ñZ=Ãöü+Ú•‘‰1þùç÷îe+ó'#ÿر‹§N%8»d‰¿Âùɬ+4V"‘ÊéÏ8–ûâe;-==‚r÷î.ŽuUìe©B­„ìmîÏ Æ™ÖÖfH…+ô×_ÿxþ¼¶_¿®r:`Œüà矯ÔÖÖ³%Ïš•ðÝw““Ã/_Î>¼÷Â…›˜_J=ŒñàÁdgÇ×£€÷¨M@ÍèëCÑ ÄÞÞ~ÕÕÔä1 !U!¦œ€2{vbjê¦MiéMM””ýùùqnnN!KKá½{¿ürSd¤/màìl åç·Œy¼²k×iTlCƒX*%îî=SR !ÕIIû’“ý½ûbŒCBF_»v'6v{HÈh¦_‡¶}útÎÈ8ìééŒJO?äáÑËÒRX\|]acn™Ë–ÍpuuD}ö™—O̪UA..¡éÓGLš´äáÃJ· Aƒ>puutr²EYX˜„„Œž8q1õ•Œ¡ÚÚz@oäÈ>ß|ÈnÉÖ™Ï×JHؽn]بQý0Ƴf½~ýNbâ„ÐåË·ž>ý«kW*¼¢¢*-íPJJ8m>±¾^LRæÉÐÐ1L¿½z}&å¬Z4cƵµ5ö%*)+•aš½&ϨÝ.Ù¢šFgfd¤oçÎÖ!BˆÂùÙè³:11tâ1ÆÊÝ5WèX¶X¶Æî&Uì•?Z±­C2‰âÇUÜŸ‘‘¾mB¹¹g W(ý`166++"„˜˜¤RRUõLNò“'5©©’“çxyõAщ´~ý^„£ž««#ÆØÊÊ”­k¦—.]ÚmÚt°¡A¬¥1ð6ù€šùå—¡‚‚‹qyyߘ™µB/VñbŒéJBUÕ3ºc19(hs¢T*-.¾)‘HGŒXÀœ(‘HkkëïÜ© ÚÚþó.½…ÜÐ ¦ûssc-,LBÚÚZ­[éèhS.]*“JIïÞ™ð¢oß® »åÞåâï?<88¾²ò™†/;û§´´Ì!vW¯Þá–éàЖF6zz:!sÚ²E >BH,þÿÆ((È{ß¾Ó;vüxëÖƒ²²—.•!„¤Òn ËÚ(K~üñ—ˆˆ^‰‰_P™r°u.-½]_/îÛ· £sÿþŽ42¾wï1Bˆ>ðŠºt©L"‘º¸80Cù !¤ à¢B«+*ªLL´evvŒlá-vâ°Qa_ls”Á„¯É3 j±‹BVJ£3ÓÎ΂¹RØó“ûácÆXê"ÆXUî[³×Ørd7šºpÛ[QQEý©"ìç0ÆÅÅ7¸?7äîoô ¥–>}ú{áÉ“§<ZÊI.)¹!K\\­úöíJsUÔ“û´  ⇫èǼ- g%À“ÐMÅÎND¡õ»ÖÖf––¦r !NN¶úú-Ž½Ð«W'ºÓÔÔÐÔÔ!ÄþÒX9++ºC‘ìé"‘ð·ßÊB<–E˜í¶m[[[›±¿à™à›ù"§§ðx/TiN˜à6{öº¬¬£zz:^^}™Cì•©¡Á“ÕcÅÕð!±X2xðì›7L˜àææÖ}æÌ¶wîTøú.Uؘ±ÑÞ¾m‡–#F,¨«kصk1»%[gš¨"¯3ú7ãñþÑ™©`‘ bTñ¤••)”Ëv­ÌF…}©sÊkòŒzí’3°Qjjj0á5{~ª¬óxXNgUüÌnÀ–ÃÑXÙ!{_jô®34ú¹¡©©!{b£W¨““mË–ºÇðœí?ýTܽ»®®6ÝÃHþW™ÿkÅ,¨¢ž\/!j“€· <Ï€úQU0Gù|­Ñß~ûýÍ›dBnÝ*§Û;[cŒoß.·µµ°³ÙىΜùý«¯6ˉRa°wBºt±áñð™3¿1_ä§O_jÝÚ¨U«^H¢§§3iÒବ£;wøúzhk¿poE®GUd²«üê|úôo'Oþºk×’•+gz¹º:Þ¸q!¥y+#Äãç’%þ99'd‹»8tvtl¯¥¥)«saáïô½‘Y^þ„êL‡àüù+LËqãÅ«èIvÚÆa£²¾T|ôSaðªFϨݮ&Ì"Ú{~ª¬7ú´ …ÎW&‡c¤ä2{_*]dÎ`Œ›ð¹Á}…êèhz­Z•yÿþÙ§&Î+ÍÊ* Ë–Ü­[{mmÍãÇ/2Z1‰QêfkkÁVON™û÷kkk¾Ô ¼`”K ¯ÀÈ‘}¤ÒeG1Æ‹M¹t©ÌÙyæ_Œ2¤—‘‘þÕ«wÒÓefíÕ«“¡aË–-u}}Ý£¢R [öéÓ¥°ðò矯?ÞMKKƒ‘£,Laß­Ä·nmäç7$""ÅØØ {w»¼¼Â¤¤}±±3äš!„†÷îÄãñâãCääÈõ¨ºÌFunÝÚcœ––ghØR*•îÝ{êÛo³BÏŸÿÍm#!dîÜ<;~òðá½¶”ýÓØØ`æL¯¨¨&&''Û¼¼Âõë÷P=;v´ô.^¼NÃ̬•¯¯{DDЉ‰ÀÞÞjïÞS{öœÌÍUf5ÛR¹ÈŒÃÆN¬ö%'¡®®¡²²F(4ÔÔÔíK®™Ú=£v»èç³gwqq‰„ªÏ"Œ1{~J¥¤¼ü BHÎ3I‚œµµõÔ±²÷ÝUIÈé{ɨ!BF 99²Í”ÙËîN¡VÜÖYZš¾ìçF£Whtô´sç.÷é=mÀÇúú†ÎÆÄ¤Ožìîçç!w.ƸU+ý°°qQQ©­Z¸¸8äåÒÂ$„H$lT=¹ÙURr£GŽp“xË@ÎÀÛÏ×ÊÉùúûï ÒÒòV®Ì¬©ùËØØÀÙÙ>3sј1èB|rr¸•Õ–ÈÈwï>255 ôZ¼Ø_Vˆ²»’Êb f››§‡†®©¨¨êÐÁ211lúôá²mèW~Ïž;w¶ÖÕåwébƒ+ÀPE¦*:wìh¹qãÜØØm7暘¼½ûž:•èäPXxÙØØ€ÃFŒ1‡6mš×½ûôààxÏF½±råL}ýÁÁñU÷èÑqþ|Ÿ˜˜ >_KCƒ7vì€Ã‡Ï…„Œ¦wL“’æ,^œöÙg«ÊË+;tmݺpèÐ9¬æðÍI”ÙØ©“•²¾d%äçy{Gݸ±]®üLa¿jô ÇYM°kÈ^ÏŸ×zz:O™²!tíÚ6g&ÝfÏÏêêgmÚŒEýñÇYÏp¬øÉbkcc®ì…;íCΟOîÚuBˆ-G¶™*örh¥Ì&Q|ÙÏF¯P]]í#Gâv¯^½300NSS£GŽë×ÏöñŒÍ=BȲe3‚–sçnxø°òÃí££§ÎŸŸLÛ4ªž¬-„ üü¢ÐÐ1/µ¯ÅšüXghŒ9ö¶•P3 b›££§x6¿¯jBÈ?üÜ¥‹ óÞªÄÄ=óç'UWäñðåË·{ôøôÆææ¯ëG²ÞY¸=óîxƒ=? ![¶äOºüáÃ=Ìcèo…ŒŒ#T ccƒwÇcÿ] .Lœ¸øúõíÊ~’x`7d¥.à~¨á}‚RUõlïÞS!!kA>>5Ë/iŒñ®]Ç}|bŠŠ®Ü¼ù 'çÄÒ¥[üü†Ð°ØÁ¡íäÉîññß7KÛ¹áöÌÛÖNéü$„Ô׋W­ÊŒŒüäí& uu T HÔ!dåÊ̈ˆO aÞ`,ÎÆ7 IDAT–¸i^ë ?µ±ùØØØ`óæôýîÍBHuõóyó’öí;õäIH$ôõõˆŒœL+p!OŸþåâ2sß¾evv¢F¥5'¸=ó. l~Bþú«Ž¾-ôíòüym‹|pÕÂáÃçW¬ØžŸ3¼`áE g€Æ€œ›æ•3B3È™+4”'ð~9\@Î*K ¼Ç@Î3Àä  Pžô‹%©©\]gàóÝ­¬&L™²¼¤ä¦I#„ìßc7柶öGmÛN Œ«¬¬á>wÿþÓ<ÞÀ²²ûoøUrTgÚµ*mØ6òxù|wk뉳g'>{ö·\ã¦iUYYÓ©“ïÕ«wš ²sç1Y =Oœ(iš>*öûZ=£^»!‰45õÀ£GÕ/{î›D•ùÉÂáUõÚKáñ²Ç‚þ{uù {¬«kXµ*«{÷ézzC <]]gefU]uãŸ>|G^VYQQ5kVB»v“ø|wcc/ð¼¼BB÷H½Ê”—WÈã äñ¦¯?ŒnSQyy…nn³Äb‰:,^#šo[ÞSêê¼½#/^¼>ožÏºu³‚–ׯßMLÌqq™yøðÊþý»½¬@úJxŒñÙ³,-…!‰DzõêÿØ{÷ïÝ»TÙ;ãe¿ÿÞð{å1Æîî=ïÞÝ%BöÎÞ)k#B¨¶¶þìÙßÃÂÖ•—WnÝÅlš-„ðð £G÷·³³h‚fŽ_ckk!{ÈØX ÌÆW‡=úH­žQ¯]ã¼¼³3f¬2¤×ëóÉ«Óèü¤5„à õÚ‹1¾{wÝþᇟ§LY^T”bnÞŠQI½þ$„ÔÖÖ:ïöíò/¿œâêê(KrsÏ|úéÊ£GII WE‚¬òjÔ­i44ˆ?úhŽA‹´´ˆvíÌ++k6oÎ1""3sѸq®Ì€Êy’Òä+ˆñÀÅ‹›,,LÄbÉ‘#ç§LYNwúáúõ{v‡…{ü(rPºÔðnÜ%z÷Ù¿ÿ´·wÔ­[Y"‘Pa¨±|ùÖsçJ‹ŠRÚµ3§;­¬Ltòôœ¿`AÊÉ“ MþZ ææÆt[$FDL Н©ù[Ùo©Ê}/¾á/-mF[…(¼¥'k#BÈÚÚ¬ªêYhèš f´àÈÝWIÉ™™GoÞÌlrÊA7LLMVãUú}}ž¡j±‹ÞÐ¥ÛïxÄ=?1þÿ¯ÙÔôŸp¹CQïÞ]]?0Àqòd÷F%0Ûo=E$„œ:ué×_ÿ¸p!Õѱ=BH$~ûmðùó¥ëÖåŒçªl¤0Æ~X)ƒ% ZµÒGÿs(*Ê×ÓsþÔ©C [¾ãWÄû Ô& ~¸ï«B$ 9ÁÁ£˜„i¼yó‚ÜÜåô,±X²dI†ÍÇ|¾»Ý'qqßK¥„©—غ5ßÉ)@GÇÝÑ1  à‚B!ºº|fX,ùúë-ÖÖù|w{{¿””\Ùh!¾¡M›±b±„î—JI»v“/NWØ#m£L&=%=ýp÷îÓutÜÛ·÷Ù½ûÄg»uó§-)’+˜©®~–о½Ÿï®¯?lÀ€Ï/VÑÉ<O*%R©”È¡³D"ŽÞ,ÓÑqï×/dùòm´p!´zõÎaÃ> iõõâèèÍ´†ÁÞÞ/=ý0‡Õˆ±ÕVh#•©°/9“••Ê(ëWžQ£]!/¯HBˆ•ÕŒÝE ¦oÕj䨱‹ÎOŽIÒèÅBQVvÒ¨Ó¼½£¨!ƒ”•¬`ŒU±Wu­Ø!;¸?7g&$ìVå ­«kHJÚ÷ùçc™„v×»·Ã¸q® »Ù’ËÊî74ˆ##7š›ÑÕõpwŸSZzûeÕSVF™1cU—.SóëêLL¼V¬Ø¡lì䥯ß!”•u´¾^Ìì?q"áøñ5r#¥Ðc¯xaŒÙW«‹‹ƒPh¸iÓAHÞe g@ýpŽã’’••5½ØGÍÌZéÓgÍJؾ=?)iεkÛ–-û46vÛ’%iL˵k³“’æ¥èééLž¼T*• è]ó+¶Ô] ÐÇ…%¬]›½zuè•+[‚ƒG‡„¬^·.G¶wÏž>|ž~±\¸}»|Ú´a=rË\¹rÇêÕ¡ÅÅßYY™N›½99yNqñ&‘Hèç÷‚Î!?¿eÇŽ]ÌȈ¼qcûÑ£ñã1c¾lhP\æËØ(K .ÄĤ»»÷ôäš)ÔyÁ‚äÄÄ= ³JK·Œ?0:ú¯J$Òœœƒõ`€ààø¤¤}qqA¥¥ÃýýW:tN™Õr ˜Ât‘ÃF…}É ¤Õ––¦ìtâµz†íùW´+##cüóÏïÝËVæOFþ±cOJ

¼÷Â…›˜_J=…VO›6ì÷ßoýòË5zÅåæžyúô/??…¥DlïõèÑ! À36v»¹ù˜ñã¿Z»v÷•+*)•šv)ü” „ üAvöqe3x€Ú$x }:gdöôtF¥§òðèei),.¾®°GŒ1·ÌeËf¸º:"„>ûÌËÇ'fÕª „Ðôé#&MZòða¥Œ[РA¸º::9Ù"„,,LBBFOœ¸˜úJÆF„Pmm½@ 7rdŸo¾ d·dëÌçk%$ì^·.lÔ¨~ãY³Æ^¿~'1qBèòå[OŸþÕµ« ^QQ•–v(%%œ¶ ŸX_/&)ódhè¦ß^½>“TV­ š1c‡ÚÚš û’ w”UG0Í^“gÔn—lQM£332Ò·sgk„!DáülôY˜˜:ñcåîš+t,[,[cw “*öÊέØÖ!™ÐóáÃ*îÏÈH_‡¶¡ÜÜ3H…+”~°V}¿‰‰@*%UUÏä$?yR“šz 9yŽ—W„Hë×ïE1깺:bŒ­¬LÙêѱæ wïÎm·mËïÑ£Bh˖ÞžÎrŽâöÞÆs?þxðÎ?üðsvöO¡>êñÝwó-,LdGJ¡ÇšvÉM*êUŒq—.í6m:(K´´ 4}G@ÍüòËF„PAÁÅÀÀ¸¼¼oèì×-Ƙ®$TU=c¾0""&bN”J¥ÅÅ7%éˆ ˜%immý;ôO[ÛÒ¥·þYgÏ͵°0Aikkµnm¤££M¸t©L*%½{wf‹¾}»&$ì–{Cˆ¿ÿðààøÊÊg¼ììŸÒÒ0‡Ø=^½z‡[¦ƒC[Ùèéé „llÌiË-ø!ÙW…`Œ‚‚¼÷í;½cÇ·n=(+{péRBH*}á–°¬b±äljˆHñð蕘ø•)[çÒÒÛõõâ¾}»0:÷ïïH¿×ïÝ{Œ¢¼"„.]*“H¤..ÌDF~B)(¸¨Ðꊊ*m™#[xF‹8lTØÛe0áãkò ƒZì¢÷†!ÎL;; æJaÏOŽræ­­uc¬*E 웾l9²M]¸í­¨¨¢þT¹žú§¸ø÷ç†ÜÃý^¡ÔÒ§Oÿb¯3yR“—w.+ë«FÏ’cðàþ!tóæƒï¿?“þñÇ‹OœH`·Tö:„¦]Ar“i) ÄVÑOoàrxI`©¡1ììD„Z¿kmmfii*×€âäd«¯ßâèÑ ½zu¢;MM MM BLá/•³²¢;tÉž. û­ !ÄãaÙ¯f»mÛÖÖÖfì/x&øf¾Èé)<Þ Uš&¸Íž½.+먆††žžŽ—W_æ»ÇFejhðd5ÁXq5=D¹u«œnwîl1¾}»ÜÖÖÂÎNdg':sæ÷¯¾Ú,'Já7%{'!¤KŸ9óóE~úô¥Ö­è{<ôôt&Mœ•utçÎ__míî­Èõ¨ŠLvý®BOŸþíäÉ_wíZ²råÌÀ@/WWÇ7î!¤4?e„xxô\²Ä?'ç„lq‡ÎŽŽíµ´4eu.,ü¢wøÊËŸPéœ?…i9nÜ¢  x=ÉNÛ8lTÖ—ŠõÍ ƒW5zFív5aѾØóSÅ`]a97 ¯LÇHÉeö¾TºÈþœÁ7ásƒû ÕÑÑ ôZµ*óþý'L3Bȹs¥YY¡¡cÙ’»uk¯­­yüøEF+f"1êQÝlm-Øê©2ç[·61¢wVÖÑ;~ôó¢z=!äÖ­«VeÞ¿ÿXVm„P‹ü-t”}¢ª²_•+Háü!„Ü¿ÿX[[󥚀7 ¬3ðZ9²TZ ì(ÆxÑ¢)—.•9;Ïüâ‹ñC†ô22Ò¿zõNzú¡ÌÌ£½zu24lÙ²¥®¯¯{TTª¡aË>}º^þüó5ãÇ»iii0r”}¹²ïVbŒ[·6òó‘bllн»]^^aRÒ¾ØØrÍBÃ{÷âñxññ!ì»b²ª.³Q[·6§¥å¶”J¥{÷žúöÛ,„ÐóçsÛH™;÷ãƒÏΟŸ<|xo…-eÿ466˜9Ó+*j£‰‰ÀÉÉ6/¯pýú=TÏŽ-½‹¯ÓßÇ03kåëë‘bb"°··Ú»÷Ôž='ssc•Y­ð¢ìŸ6vêd¥°/9 uu ••5B¡¡¦¦†l_rÍÔîµÛEƒ¼³gwqq‰„ªÏ"Œ1{~J¥¤¼ü BHÎ3I‚œµµõÔ±²÷ÝUIÈé{ɨ!BF 99²Í”ÙËîN¡VÜÖYZš¾ìçF£Whtô´sç.÷é=mÀÇúú†ÎÆÄ¤Ožìîçç!w.ƸU+ý°°qQQ©­Z¸¸8äåÒÂ$„H$lT=î1e:š:uè'Ÿ|ýüymZÚ…ë3ÊÆtÁ‚Oöï?íæöÕWSí¥Ré?ü¼hѦ… ý´µ5eGŠÃ' ÷«r)[g()¹Ñ£GG¶¥À»ä ðò@y’:àóµrr¾þþû‚´´¼•+3kjþ266pv¶ÏÌ\4f̺Bœneµ%2rãÝ»LM ½/ö—¢ì®¤²XgÃ†Ùææé¡¡k**ª:t°LL ›>}¸lúÖ³gÇέuuù]ºØ Æ 0T‘©ŠÎ;ZnÜ876vÛÆ¹&&oï¾§N%:9^666à°cÌã¡M›æuï>=88Þßß³Qo¬\9S_¿Eppü£GÕ=ztœ?ß'&&ƒÏ×ÒÐà;àðás!!£éyRҜŋÓ>ûlUyye‡¢­[ú!‡Õ¾¢9‰2;u²RÖ—¬„üü"oï¨7¶Ë•Ÿ)ìWžá8« v ÒëùóZOOgú³V×®mSqfÒmöü¬®~Ö¦ÍX„ÐìõŒ2±1޵±1WvŠÂÎÎöŒ!çÏ'wí: !Ä–#ÛL{9´Rf“(¾ìçF£W¨®®ö‘#q »W¯Þ§©©Ñ£GÇõëgûø FŠæ!dÙ²A˹s7<|Xùá‡öÑÑSçÏO¦mUÚ¢lL™Ž† s60hÑ­[»N¬&Tʼ׶mësç’W¬Ø½ùÎ ž£cûÄÄ/¨9²#¢Ì'Êö7z)ô¶TJòó‹BCǼTqð†QPj@ã@ÎÀ€1"ÇÞ¶j¦¡Alcóqtô´€Ïæ÷Fùᇟ»t±aÞ[•˜¸gþü¤êêƒ<¾|ùvŸÞ¸±ÃÜüuýHÖ; ·gÞo°ç'!dË–ü©S—?|¸‡y ý­‘q„ªallðîxì¿È»3¦ªÃq9r~øðwïr¢?úI“„бc'N\|ýúvƒoÙY°|ÑËÏ3ü!¤ªêÙÞ½§BBÖ‚||>j–AÆx×®ã>>1EEWnÞ|“sbéÒ-~~ChXìàÐvòd÷øøï›¥íÜp{æmk§t~BêëÅ«VeFF~òvƒËººª$ ¯Î;2¦/ÇDTTT?~ü´¼¼’yØš®g®\™ñÉ»•0,`š ,5Pš×:ÃãÇOml>666ؼy}¿{óƒR]ý|Þ¼¤}ûN=yR# }}="#'ÓúBÈÓ§¹¸ÌÜ·o™¨QiÍ nϼ (›Ÿ„¿þª£o }»<^Û¢†WçÝSÕQvikk:tÎÓs>BÈÍÍ©¨èʳg£Ë®Ž)Z±b{~~Ü;’œÿXgxÈ ©@Î@i^9 9ƒ ÐÜœ. g€ Èà€ò$Þ g€ ÈàÕ€¥†· !D"‘¦¦xô¨úuH#„TVÖtêä{õêýûOóxËÊî«øº9îöì¾òò ÝÜf‰Å’&¼ÎN,–¤¦pued4‚Ïw·²š0eÊò’’?^V£Ûþý§1vcþikÔ¶íÄÀÀ¸ÊÊîs_ÖKê‚êL»V¥ ÛFo Ÿïnm=qöìÄgÏþ–kü&mxœ€ÿ0ã¼¼Â3VýýwÝ«vliãðð £G÷·³³pwïy÷î.KKSUÞ NánÏîkØ0g}ý »_ö åuu #F,X¸0ÕÛ»ßO?­½vm[ZZijg»¸Ì‹C½Ôˆ4o4ß¶4Oöï?ííuëV–H$|}!!„ _½¶´ââ™™GoÞÌDéèh››«( cÌÝžÝ!$*Ê×ÓsþÔ©CŒôU×yùò­çΕ¥´kgNwZY™èäé9Á‚”“'^Ö3ŒbB¡€1A$FDL Н©ù[__WY"$+ä ‡ÚÂ\BÖF„µµYUÕ³ÐÐ56Ì60h¡úˆ4o`^(Ob¡Êýæúzqtôæví&ñùîöö~éé‡é~±Xòõ×[¬­'Òý))¹t?-Ùº5ßÉ)@GÇÝÑ1  àBÈË+’be5c7ÚfáÂTCÃá­Z,+»_]ý<,,¡}{>ß]_Ø€Ÿ?^Lãu… ÈJ#„¬^½sذMLH¦êFÎÒF÷«¢9u”³³½Ph¸iÓA¹è–£—†IBBNpð(&a`ܾyó‚ÜÜåÔÿb±dÉ’ ›ù|w;»Oââ¾—J #–­{( !ºº|f{˜d³ „Pxø†6mÆÒR+BˆTJÚµ›´xqºÂie2é)é釻wŸ®£ãÞ¾½ÏîÝ'8Û­›?myäH‘\)‘ÂqW8kºòx<©”H¥RI$ÒèèÍ"Ñ8÷~ýB–/߯ã üóχÊúø9êGî~3»!$88>)i_\\PiiF@Àpÿyy…„°°„µk³W¯½reKpðèÕ »!k×f'%Í)*JÑÓÓ™@3j“@Ð¥xP!„¾þ0„D"EÙÛûÑ€¬¦&i@yô¨:-íPJJøèÑýBsæL¨¯‚**ª“’ö%'‡Õ!<êÚµ;±±ÛCBFÓscbœíBAA£üü–=zTmhØ!$ ÌÌZÑ6‘‘¾mB„ Aƒ>puutr²EYX˜„„Œž8qqEE•¶¶&U`Ô¨~ãðð‰TYi—.•=}úW×®6rá¸\@¯°$†Ásk΄­]º´Û´é`CƒXKë…Ïge½TTT!„d%Ìž˜šz€iSZºESS#%e~~œ››BÈÒRxïÞã/¿Üé«L7º¿k×iTlCƒX*%îî=SR !Ì0y{÷Ň„Œ–&„ƒCÛ>}:gdöôtF¥§òðèei),.¾®°GŒ1·ÌeËf¸º:"„>ûÌËÇ'fÕª „Ðôé#&MZòða¥Œ[”Ž;bÁ؈ª­­ôFŽìóÍ7ì–lù|­„„ÝëÖ…ÑY4kÖØë×ï$&îaŸ ð_rÔÌ/¿lD\ ŒËËû††ò²ÕíãK—Ê$©‹‹Ý1ŽŒü!tôè©”ôîÝ™Ùß·oׄ„ÝLkkkAåÐÛÀ b¶vvÿöE‚‚¼÷í;½cÇ·n=(+{péRBH*•2 0ZEF~BÉÍ=Ãȹwï1BH(4”KT©Ôg7àÐ\Ö3B¡ ¡AüðaU›6ƪôBWªªž1‹ˆ˜4 ý;R©´¸ø¦D"1b#P"‘ÖÖÖß¹SÁ­[nn¬…… BH[[«uk#mjþ¥Ket˜˜DEn˜(þþÃã++Ÿihð²³JK[Àá«WïpËtphK31==„9mÙ¢!$ÿ c¤lÜÙ>¤6ŠÅ’ü%""ÅãWbâTf£#XZz»¾^Ü·oFçþý!g Y9jÆÎND)-½²¶6³´4•k@«Àé¶\ÍÕ1A y¼ )y<,{ _aᓦ¦Ss?xðì›7L˜àææÖ}æÌ¶wîTøú.Eÿ.ƒ V2#+‡þÉãñ¸×ÂVŒCsFBˆ††m¬b/NN¶úú-Ž½Ð«W'ºÓÔÔÐÔÔ!D‡ý+geEwè ’=]$þö[‡nmÛ¶¶¶6c»…&&Q‘&Ê„ n³g¯ËÊ:ª¡¡¡§§ãåÕ—ÃÊÔÐàÉj‚±âÑGœãΆ±ÑÞ¾m‡–#F,¨«kصk1»%[gš¨"¯3@óžg5OBËÀý<ƸsgkŒñùóW˜£ãÆ- ^Ý¥‹ ‡Ïœù©ï?}úRëÖF­ZéËžþbì¨ø>ãÓ§;yò×]»–¬\930ÐËÕÕñÆ{!B£¬·(((^V½Å^^þ„ãyU<Шæ²÷ï?ÖÖÖ Uì…Ï× ýí·ßß¼ù@ö!äÖ­rºM½}»ÜÖÖÂÎNdg':sæ÷¯¾ÚÌ¡‡!„f˜ﱇ !¤§§3iÒବ£;wøúzhk¿p—J®GUdÊ=f­LgŽqW#Äãç’%þ99'd‹»8tvtl¯¥¥)«saáïŠûøë ¼FŽì#•(;jnnìëë‘bb"°··Ú»÷Ôž='ssc[·6òó‘bllн»]^^aRÒ¾ØØ²çÊÓôe>gÏþN«ÛeÛ´nm„1NKË34l)•J÷î=õí·Y¡çÏÿîÔÉJ¡ô)*­cGK@ïâÅëýúu•íQ.¨«k¨¬¬ 555”)É­9Bˆ®ÆBJJnôèÑQ²^¨2‹M¹t©ÌÙyæ_Œ2¤—‘‘þÕ«wÒÓefíÕ«“¡aË–-u}˜hMé IDAT}Ý£¢R [öéÓ¥°ðò矯?ÞMK«…‘¢B,Œ±*ÃDÏ Þ»wÇ‹a—xÉþ©ºÌFuæwn !sç~|ðàÙùó“‡ï­°¥ìŸÆÆ3gzEEm4189Ùæå®_¿‡­'@3rPð$´ÊB’’æ,^œöÙg«ÊË+;tmݺpÈ^¡ f››§‡†®©¨¨êÐÁ211, ÀSö\¹€ÌÙÙÞÓÓyÊ”å¡øøÙ6;ZnÜ876vÛÆ¹&&oï¾§N%:9^îÔÉJ¡ÏŸ×2Ò®]Û6vì€Ã‡Ï…†Ž‘S^ve ?¿ÈÛ;êÆí²e<ªÜ³—ÕüÚµmmÚ‚òó‹BCǰÃt…½Pø|­œœ¯¿ÿ¾ --oåÊÌšš¿Œ œí333€Çáääp+«-‘‘ïÞ}djjèµx±?‡nÜû1Æìaš>}8ÛK={vìÜÙZW—ߥ‹ jì%¼ªÈTEgŽq766à°cÌã¡M›æuï>=88ÞßßSYK†•+gêë·Žô¨ºGŽóçûÄÄdðùZ øïÅ— VÞÜcD޽m%^ „Ë—o÷èñé;Ú´y¿íUPpaâÄÅׯoWö£iÿ9Ä66GGO ðlÉBùᇟ»t±aÞ[•˜¸gþü¤êêƒPú ÿq°Û{÷…Î |¨(cloo5y²{|ü÷oàö !dåÊ̈ˆOšAÂ@©ªz¶wï©5„ Ÿþë)c¼k×qŸ˜¢¢+7o>ÈÉ9±té?¿!tm 9ë  nÞ·¥†æ»Î@©®~îâ2sß¾eÌ«6_„#GŠV¬ØžŸ×]Gǽ}{ŸÝ»O8p¶[7ÚòÈ‘"¹R¢êêçaa íÛûðùîúúà øüøñb…ó ±¦%Ç“J‰T*åAª›D"ŽÞ,ÓÑqï×/dùòm´°MY_Í ÈP?r÷¡Ù !³f%lßžŸ”4çÚµmË–}»mÉ’4Œ±—WŸÀ@¯¹s7üùgÅO?•|ýõ–5k>ïÜÙ:##cüóÏïÝËF)<‘¿vmvRÒœ¢¢==É“—J$RÚãwßLN¿|9cøðÞ n¢%iNΉAƒz`Œ•iΔÄXZšrgDr]K¥DVsz.ÆxðಳËÎÑKIÉÿ±wßqQmÀgîhŠH/J,ˆb;¢`ÇÞ{CT쾊bÁØPDQ±K"bǒذaÔˆ±—Ø{[înÞ?&Ùœw°œ¨ ðû~ü÷vgž™›ƒyvg÷^½zãí][½?­¬LøõŠœzU$6•†ðK.sælðô¬nh¨O) Œ\¼81"bÄÕ«k‡ï±dI’ríýû·züøåÞ½¿óÞ;xð»wŸôë×R¤Fñ2çÎÝ1"-m¥E¿~á¡¡«bbƦ¥­°±1÷óû$fBˆŸß¬C‡Î­Y|óæ†RJ;vü_V–œdGh£L&?xð°°Õ^^µ õs} !“&ÅDEmŒuåÊÚ.]š„†Æ«—Pˆam|e- !r¹‚R©’Ÿ¨½y“,ìÀ{ú4=6vÇþýó=<ªBlmÍ>|ñ¿ÿ­öÕ֖Λçèйºví^M hE12*A177´²2oÜØ•Rjgg!Ϋ àîîLñ÷oïç7ëùó --i\Ü®˜˜±>>õ!£FuºqãþÒ¥Û!—/ßyýú}•**Óq• }¶KbÔgðaaÜÜ*)W­¹0muq)»bÅî¬,™¶ö'¿‡sªåÙ³tBˆr cÆDÅÅíö¹re­––4§^Í)6¾½J•~¼Ø¬,™BÁ¼¼jÅÆŽcŒ={–½=&f\»võ)¥®_¿¾!  ƒP¯³s™zõ*¯Y³·U+7BÈêÕ{¼½kÛÚš§¥ÝȶFJ©x™³f nÜØ•2dˆOÏžaóæùó·ràÀ6=zLúô•R·OÏ»V«æH±¶6 èЭÛ4ÞW*„6B>|È44ÔoÛ¶ÞO? UßS=f]]íÈÈ-K–¶o߀RÊOTÔVõc +ä ßR‘¼úìÙ儃Ï :?9ù'++òéªwJiZÚM¹\ѦÍ$a£\®øð!óþýgVÅŠé¬[7¹N!¥K›-]:Z}^.r8ÿ¯££5?ŠŸEÎÊ’]ºt[&“»»;óH(¥õëWá9ÃÇ/!ê·Àj²R_}GGk¾Q¨Z}gJ©¹¹aV–ìéÓôÒ¥M5©…_IHO+ÄÔÛß¿½ÐÕ …"-ív®Ý’ml;w†[[›Btt´--õôtxó/\¸¥P°ºu+ ‰JýúU"#·¨<½ªÿÖÇ/|õê­T*IL<?I¤7®]»/^¦³sþÞéëëBJñ=‹×%„Èdÿ]C ”øû·Û¾ýøÆ¿Ý¹óøÖ­Ç.Ü"„( õ>äm”Éä¿ýv6((ÖÛ»vTÔh^f®ïà•+w33eõë»17l芜Šä ð•99Ù0ÆøÝööV¶¶*;0Æø¬.!!´|yå—„¦Ïœ¹*‘H=zqîÜ õ'‰~ñâ-BˆD¢ºÊèßÙÞ T„ü|‹D"¿Î-õ|F"¡ÊU~j—J¥êqŠÔR­š£Añþ¨]»"ßhaadaaDnÌФ[²­LK{{+õ…RÂä[HTø!É'ëZ»võ3fIB©Tª¯¯çãS_¤7r-S*•(GBiöËÛ!2™¼iÓ1·o?îÚÕÃãú°aeîßæë;3Û…6VªT¦|yÛ6m&}ü˜µyó4õ=Õcæ‰ cª1¸Ÿà+’wB‹ßÏ@)­\ÙžRz÷îGGk''''›'.MºŠïõê½1c¢BCûuíÚÄÏo–pr](A8œëèh-®\¯rÕU«–ÓÑÑ:|øœpGAjê%þ?ÅþäÉK‘û4i©òÆOg½Tý‡G^èèhñ†jR‹®®v@@‡ ~¾}û±J3ïÜyÂéÕœbicÌÅÅA"¡'N\RãÇ/XZ›˜|ò¸'}}½=š&$øå—ƒ¾¾Þ::ŸœR©Q“2UÞ»œb>~üâÑ£nÞ<}îÜaC‡ú4nìzóæCBr¼°'âí]kúôþII)Ê‹»Dbvu-§­­¥³0xŠ\g€o¢mÛz ÅÁœ^µµµðõõ ‰32*Q¯žKjêå‘#uéâ¡­-ÍÊ’÷î=ÃÅÅa„îééo«Té±vm˜ÏÉ“—ÜÝmlÌs:\¨Be–il\"0°sHHœ‰IIwwçääT¾0‰R¡‚­¡¡þ¹s74¨¢|ˆJþðñcÖ«WoÌÍ´´¤ÊÛÕ[§²Qˆœ7œüs«ñÍš5+¨œSϩ̔)}.\¸åæ6lôè.Í›×666¸víþêÕ{6m:P»vE#£%J˵[rJQÔbQJ--ýüšÅšš–¬^Ý)995:z{xø`õ^0 uݺþ‰dáÂõ%^ÊÿÕ¼Ì\c¶´4¦”ÆÇ'•P(Û¶[° òîÝßâmdŒß}÷î“'Æ´n]7Û=•ÿkjZrØ0Ÿåff†Õª9&'§.]ºU=N€B 9ÆXLÌ8;»µÁÁËpøð…ýû·Êµ7æÎf`P|øð…ÏŸgÔ¬YaâÄžaaktuµ³  ðÁ¢L€|Qˆï„¦”°CÄaŒ]¾|·fÍA7on,]:?¾ÛëàÁ?ºu›vãÆ†œ¾4퇓•%spèÚoÀ€V…£EÊc¿þzÆÅÅAxnUTÔÖ‰£32vK¥Xâ PHQBû‡;OðËŠ:Ji¥Jv½{{-\øs>œFaŒÍ»)(¨W!Hcééo·m;°ˆ1Ò³g³½EÙ¢”nÞ|¸gϰӧ¯Þ¾ý8))eæÌµ~~Íùµ€¢×ò®3|÷22Þ¹»Û¾}–ð¨Ío1¶oßé9s6ìß?¿pœ¢~ñⵃCwSÓ’«VMâß Qøð/œž0!zûöc/_¾±±1÷õõîµI…®3| 9@~)¬iCaÉþƒœáS…á,|;ÈòK‘ü¢(3€ä 9@>Âò$ø!g€ —+ââv=ž‘ë£Ûž=K5*²lÙºº^¦¦>ÞÞã’“ScŒ1¡õ£vì8.‘4¹uëQž ÷êÕ›Š}¯]»ÏKNNõð%“É?«4ÆX¶ÁóWsêƘ|Þ"øê3ä/\j „Ïž÷÷ßÅ¿ !+KÖ¬ÙØ³g¯ÅÇݼ¹áС‡6m‚6o>L QŸv{yÕzð`³­­EÞ¾i16nܲ:9YSJ[¶t30(¹EóÒc2™<ÛàùåHPJ…àñ,løN g€o‚Ÿ,¿wï©úÄ—Òÿ¾FdZÌ;vìŸþµdI`£FUmlÌ«T)»`Áðzõ*/Y’¤|¬ú´[OO§T)S--i"gŒ?ÿצMÆŒéÊKfŒ…„ø†…­yõꆅPJ…à6¬ÂƒŸ?ß_=xõ‚/”ß© ?"ä ðõ)σÕ'¾Œ±víBcvv]¥RO~J~ÆŒµööÝtu½*Uò‹ÝÉ40(NIH8™)OI‰<|x¥ÔÇ'˜B©OQ&OŽ32jmbÒ62r _Þ÷¯[·¿Zµzz^®®üCXÚºÊƦ³žžWƒ³g¯çI!$"â—–-똛 Mps«dnn´bÅn —1ƄೲþYÔD)åÁB”{ೂçå‹ðÕ!gÈwE`y’ržíu†Õ«ƒ(¥gÎ,ð`3!$00rñâĈˆW¯®>¼C@@DdäBHÍšå h¾¡T©Ž]ºL]¼xËÕ«÷„b׬ æ…<|˜È7:tîØ±¨]»Âíí­”k\¼81:zìéÓ±úúz½{ÏT(!dÒ¤˜¨¨­‘‘£®\YÛ¥K“ÐÐx¾³\®HJJñô¬©’ù4mZ#1ñ°†K‰(¥5j8 Áwíʃ’•Ð|{{«ñã»éééF¦§¿U¯ZKKší„^"¡ÊÛù„ÆcŒ§*wTK$•ë R©”¥É­ÉŒ1ü”)~¼|{{« º‹ŸmÉ*5*¯Òcß®3À×—ëý Ê;¸¸8H$ôĉ‹ÂYóãÇ/XZ›˜ܹóxÞ¼M½P)¹xqÝâÅõ²ag{A}»«k9mm­'. ÓîÔÔKü%kk3BÈ“'/U®3aBBȤI½ õ=<7løíæÍ‡×¯ß_¶lÛ”)+&OöÓÑÑR.D¹pM¦Ý¦¦%‡ ó YÎ+‰Ù±téVB¥´B[CCýsçn¨d>çÏ߬Y³‚TªzýáÇÌG^ðsÿÊÛ…à7n<ÀƒŽÞ.¼† üöíÇy Á‹¼#y†µIßø£K[µrëÓg6!äúõõË–)Ujõˆ‹ž=K/_Þ6**pÀ€V”Ò2e,OŠ™3gChèªû÷ŸI¥W×rQQ£{ölJQ.dá¡ðœ*UÙ2wî0ƒâÇ/|þ<£fÍ 'ö [£««-•J:uj´wï)~6ù'ß û÷Ÿ1¢£ús“öï?Ý®]ÈÍ›ìí­„W)¥vvÙß«W³œ‚Ïé †úöœ‚×ìø…œ  ýèiÙ3ˆAÎð©ïåœ|Ÿ3€ä  wBÀ÷ 9ˆAÎðÀ¥øŽ!g€BbÇŽãI“{÷ž~•ÇÁ1Æ^½zS±¢ïµk÷yÉ·n=ÊCÉŒ1áðœö‘Ëqq»ž?Ï)_“r¾E½"%ß»÷´`#É›ÌLY›6“ôô¼<þ¯<÷ïpJ=(õHšèè4+S¦ÛСó_½zóÇØ×¥É§¬Ãä P(Ï3¾ÊwPJÇ[Ö¡CC''ë/)™RêåUëÁƒÍ¶¶ÙN†øtsðàyÿýQ¤|å—4™J~­z¿çHò€1vìØŸ»w§nÚ4uР¶ÂÆ<”£3¥´E‹:Å##·|nÆs˜É“ãÚµkpäÈâë××Çǽ}û·»û°£GÿÌ[lü‡ÔÔè‡<Øü×_W­š´gÏ©>}fÅ1ö1Æ„A’S„x4<@ÁBÎð}(tË“¾îYÿ\}õéNZÚÍM›ŒÓUycÞJÖÓÓ)UÊTKKšídˆÒÿ¾'Gü°ò!ùVï÷IPJß½û@©Y³|É’Å…y(G%fJiHˆoXØšôô·š·‚R:{öºS§®?¾tôèÎUª”µ³³ðô¬ž˜8½qc×I“bóÿÁÜÜÐÊʤT)Só&MªõÞµëäë×ïs:ð«'Þš£” ƒDdŸü T g€¯O|ò!,˜<9ÎȨµ‰IÛ[·ed¼ Œ,W®§®®—AËFF>œ&ì¹nÝþjÕèéy¹º8xð^NV–,8xy©R‹óöò{åÊ]¡ ™L>cÆZ{ûnºº^•*ùÅÆîä Hxi«Wï­^} žžW¹r=·lIÙµëdÕªýùžûöæ{FDüÒ²e33C•àÏœ¹fjêÓ¿ÿ™L®25Ìiq…°=Û¶0ÆÚµ aŒÙÙu•J=sšnŠ$Eß´^^rW{{º:ÿ#ÉÌ”MºÊÞ¾[ñâÍ==G/^¼%ÛÔ4§H(õhÛ6ˆ×¥\¬ú€^ÊidªÇìîîlnn´bÅnõ1ŸS<™™²ÈȤáÃÛ;8X©¼Å«VMÚ¹s62™|úô5Ýuu½œœzÍŸÿ³BñßxVïO¥öRá‡bÅtyÉ9µW9€±c—–.ÝIXj¥P°²e{L›¶Zäó˜Sjø¡Sú<§ù9Àw£]j?ë/¼zèйcÇ¢ví ···òó›uèй5k‚oÞÜpàÀBJiÇŽÿËÊúgʲxqbtôØÓ§cõõõz÷ž)—+c£FE®\¹;&fÜåËkZ·®;yò ¡ŠÀÀÈÅ‹#"F\½ºvøðK–$ ¯Î»1"bDZÚJ;;‹~ýÂCCWÅÄŒMK[accîç7S¡`r¹"))ÅÓ³&_v"xöìuoïqÝ»{ÆÅMJ%*ÍÌvq…zóUÚ¢P°Õ«ƒ(¥gÎ,ð`³& 3ò³^^]N]]‘,^¶l[DĈ‹ã½¼jÅ~V$&®YÌëR.Y}ÀDFnáÅæ42ÕcfŒ5mZ#1ñ°J“Eâ9þæ«Wo¼½k«´šRjeebllÀGà¨Q‘6ìŽ{ýúúY³…‡¯Ÿ>=^¤?Õ;?-íæœ9<=«ó«+Ù¶W9ìþý[=~ürïÞßyŽqðàwï>éׯe¶5òÏ£x™¹~è”›/þÛ røÊ Z´ìÖm!¤R%¿’%[´TÞA˜FûV®l_·neƈ§gøø zõ*ÛØ˜×®]1  Ã«Wož=Kç{†… pwwvqqð÷oÿèÑ‹çÏ3^¾|·köìÁ>>õìí­Fê4hPk¾ó³gÑÑÛgÏÜ®]}{{«€€Ƶ ß 0kÖàÆ]+T°2ÄçÍ›÷óæù»»;W¨`;p`›§OÓŸ>}uùòׯßW©âÀ'Lü(ž0ôïß2**P"¡ê“¼lW¨Ï€ÕÛbdT‚bnnXª”iN½šÓ,ü[×Kyñâ5ïê¶mëÚÛ[vº:Ÿ#yö,}ÅŠÝüup(Ô«{wÏÏŠÄÊÊD¨K©ØLûö ìí­†oÏ cL¡`9Lõ˜)¥..eÏž½®r J$>­*5Ô² IDAT¬L„ýG^Â?Aü߃ÏŸtuëV®XÑNøÐ {æúÛ „VA…ÍÙ³Ë !ž:t~ròOVV&„Ƙò2 þƒ““5ß.‘PÿvÛ·߸ñ·;wߺõøÂ…[„…BÁ÷tt´æ“*CC}BHV–ìÒ¥Û2™ÜÝÝ™—@)­_¿ÊÒ¥Û!.ÜR(Xݺ•…³¿õëW‰ŒÜ"Ì¥œËðÒôõõ!¥øžÅ‹ëBd2ùÇ/!ææFÊó]_ß™?f•)c¥Ü–\©ŸeWo‹òΟ{!ê=þ&ïjåþä]Ï‘\¸pK&“׫÷ß;ëéYcÕªd #Éi7aÀ(%>`ÌÌ ÅG¦rÌŒ1ssì,ÙÓ§éÖÖf¹Ã366 „¤§¿J êíïßžüû R(ii·årE›6“„àårŇ™÷ï?ãÿÍ©?wî çaèèh[ZëêjóDÚ«^ÿþ­‡_øòå©T’˜x$>~’ð’z×®Ý/ÓÙ¹ ¯]øÐñ„Ò{DrísÈȾ'|yÒ¾l×ÉɆ1Æ—¼ÛÛ[ÙÚZ¨ì L"…›b³²dM›Ž¹}ûq×®Õ‡ +sÿþ3_ß™Â!*çõ•fiD˜likÿó M˜[Ó^£DòÏ•U•eE”ªÎkù«‰Dy{ppï>ŶhQ§\¹Òyž¤ª·Edçl_Ò$iùŠõ ]-ô§ÐÕùÉ¿ûÿ‰®®¶æ‘ì¢4`„±$ ™L.>2•£”J¥RÞ@ {¦Z5GƒâüQ«VÞ" # #á$„—Z¾¼òá66æ/Þ"9÷g™2–¥Ô{@¤½Ê{víê1fÌ’„„R©T__Ïǧ¾ð’z¹–)•J>}£s|¯5ésÈÈàëŸàªÏoŽ¿xôèŸ'O.«S§"ß¶–O²'•Ù^Õªått´>W©’Ÿl¥¦^â/¹¸8H$ôĉ‹ÎÎeøÇ_°´4611È©4•ùÙÙ'O^*ÏÒzõjVª”éÖ­Gû÷Ÿsð`„D’dzì"µÓë y®Wèj¡?…®ÎçHªUsT‰ääÉ‹šG’Ón€Æ’0`Ž9ŸÓÈT™1öèÑ -•+T"ôôt:,Xðs·nMÊ”±TN?îÜy®\ÙžRz÷î“Ö­Ýy-k×îß³'•/4bȶül?}"íUÞ­D‰b=z4MH8 ­­åëë-¤gÙÖ¨a™"%4ùmù9|mÛÖS(fû’úô×ÒÒ˜RŸldTB¡PlÛvlÁ‚BÈ»w«ì)06.Ø9$$ÎĤ¤»»srr*_-ÃKóókkjZ²zu§ääÔèèíáვŸ¾T¨`kh¨îÜ ª(o×ÕÕŽ‹›Ð AÀÂ…¿Œ×M¥]>d¾zõÆÜÜHù:F¶sG•ü6'O^rww¶¶6òä%!D¤•‰à·®W¤«ó9#£ãÇw"Ù³ç”pk»&‘æ©"Fdd*ÇlccÎ'ÊçÏ߬Y³‚úCEâ™2¥Ï… ·Ü܆Ý¥yóÚÆÆ×®Ý_½zϦMj×®hdT¢D‰b¾¾^!!qFF%êÕsIM½‡«XÑnùòñ¿þz¦rå>MšÞºõðر(©T’šzYyO•9ǬYƒÇï>~ü² zoØðkhh_á¥eËÆ ÔfĈE*ô^ºtkTTàèÑ]TêUI]”_•J%:5Ú»÷”ÊvBˆ›[¥Ñ£»L™²òÒ¥;ÊÛcû÷Ÿ¶¶î|ïÞÓ\'©*µ»¹UjÕÊ­OŸÙ*ø^¾|ÇÚº³x9*Û¿i½¼ºœº:ÿ#™>½ÿÔ©}CB–W¨Ð{åÊÝ&ôÐ<’ó|ÁS(Øþý§;wn¬Òdñxtt´’’f,Z4âС?š5[¾|ï>}f½{÷÷¦MSŽ20(N)‰Ð!8x¹“S¯1c– ê³dI HæÚùÙ¶W%0JiÍšå+W¶¯QÉ_ëùåÔ‡êeæs… ¶¹þ6€üG³ýÄ@Aú±ni ”°CÄWÆ»|ùnÍšƒnÞÜXº´Ø“|¾…5köõí;ûéÓ­¦¦%5\âòC×û%‘ìØq¼]»;wø™þ|‹PcìСsݺM»qcƒðmq?4ƘL&wpèÚoàÀÖ@¾£?Òßâo×¾?EàRÃwŽRZ©’]ïÞ^ þœÏ'V>~Ìš7oSpp¯|ž¸T½_ÉçÞãñMQJçÎÝÔ«p$ ééo·o?°ˆ1Ò³g3œ^ÜÏ Jé¼yþîîÃnëèhoSR]]í'–/®›Ï“à‚ª÷K"¹Ç#ÿíÝûû‡™#Gv*ðH¾cL.WøúÎ45-¹~ýäbÅt~ôÀ—ÃÚ$€ïÒ´<©0®M€¢k“>…µIß%,O€ïrƒœà{…K ð}@Îb3€ä ß1,O€ïrƒœàû†K PÐ3€ä †2|-6À÷Òï÷ì±t ¥ïö/oAÐ*èà‡_©EÍ÷|¾ ¬Mñ„Šä ?ü…€‚ƒœ4#¬J‰ €"9À¡ `©ÜÆ€_JE rƒœr“í³’p© È@ÎðãÀŸg(È@”È2à\@Ñ€œà‡‚?ÏÏrý7ü^(3€­‚¾Wü‚&—r½?2Êð øáào3 ü (z°6 Ä gøáŽCÈGÈ@ rƒœàÇ„åI_3€ä 9À Ë“ _ g1È~d¸ÔßrƒœÄ gøÁay|cÈ@ r€.5À·„œÄ g1È ,O€o9ˆAÎPXàR|È@ rƒœ Áò$ø3€ä 9@á‚åIðµ!g1È \j€¯ 9ˆAÎb3FXž_rƒœ Â¥øJ3€ä 9@á…åIð5 g1È 5\j€/†œÄ g1È ;,O€/ƒœÄ g1ÈŠ,O€/€œÄ g(p©ò 9ˆAÎb3Xžy‚œÄ g(Jp©>rƒœÄ g(b°< >rƒœ èÁ¥øÈ@ rƒœ HÂò$ÐrƒœÄ g(ª°< 4ƒœÄ g(Âp©4€œÄ g1ÈŠ6,O€Ü g1ÈŠ<\jQZä!9d‡þÝâ-ØòÏÆ@(Ãï€"‚ÒÿæˆÊ>+g  @QƒµI 9@‘‡ë 9@‘…I'È@ r€"\QÈŠ á ›Ÿ9ˆAÎPt1Æ>|Èœ7/¡FAÅŠy´lØpÄ–-)_¥d¹\·ëùóŒ//Û±ã¸DÒäÞ½§~³ߟR៮®—½}·1c¢Þ¾ý›1Æw¸uëQÞâùå—C*åóuëú+ž߃”í›øyõâ¹I ß Pd|úÜ$ÆØë×ï½½Çýý÷ÇÐÐ~5j8½ÿqíÚ½]ºL3gȸqݾ¤*JiròÉÁƒç5o^›1F¿x¹¼ò X“Ò„ýSS£mmÍùÏ>dž}ú‡îºº^NN½æÏÿY¡`Œ±íÛK$M–/ßÉó„ÐÐU%J´¸xñ¶O0cÌή+¥Œ±œçkxÖ­Û_­Ú==/W×þÁkÌÊ’//Uªc±bÞ^^c¯\¹+³nÝ~—¾::ͬ¬: ðSzú[•hsº.Á“H$ S(;wžàˇDbË¡¡«ll:ëéy5h0{özõõQêq »Ž×»zõÞêÕêéy•+×sË–”]»NV­Ú_W׫R%¿}ûN E1Æž=KŸ9s]¹r="êÕs!„¼}û7…„ï)¼‰„zõ\"Ê•ë9{ö†—Š!—QÈŠŒOŸ›tþü_?fÕ­[YeÊknnT¯^e-•©ö¨Q‘6ìŽ{ýúúY³…‡¯Ÿ>=žRêãSoèPŸñã—Ý»÷ìÈ‘ó3f¬]´hdåÊökÖSJÏœYþða"!$ÛÃ…ò/NŒŽ{út¬¾¾^ïÞ3år¯qåÊÝ11ã._^ÓºuÝÉ“Wð¯_зïì.]<®__¿yóô_=«Ò •àù2™üСsaa«½¼j)O²Eb˜4)&*jkdä¨+WÖvéÒ$44ž¨Q¿s@%ñ¶Ï»1"bDZÚJ;;‹~ýÂCCWÅÄŒMK[accîç7“gçÎÝ4hn™2ݶnM íw÷îÏsæ ¡” o¢J£ü&†‡¾{÷çÐÐ~IIGììºøÓ¹s7Ô[ k“ЍŒŒw„cã¹.žaŒ=}š»cÿþùÕ!¶¶æ¾øßÿVûjkKçÍó?tèÜÀ?]»v¯G¦´"„• ÿ. oÜØ•Rjgg!Ϋ àîîLñ÷oïç7ëùó --i\Ü®˜˜±>>õ!£FuºqãþÒ¥Û!Ož¼T(XéÒf66ævvÛ·Ï¢”ª´B˜CW©ÒOØþáC¦¡¡~Û¶õ~úi¨z3ÕcÐÕÕŽŒÜ²dI`‡ !#Gv¼qã~TÔVå£j×¢Ò{Ë—ïÖ­‰ðß\Û>kÖàÆ] !C†øôì6ož?càÀ6=zLúô•••Iƒìí­öí›× Aå6 o¢È;H)-VL·ÿ–ýúµ8zôÏ>}f¯\™¬PÌiuÈŠ(33CBÈ‹¯œlÄ÷¤”¦¥Ý”ËmÚLæ¦r¹âÇÌû÷Ÿ98X+¦³nÝä:u†”.m¶téhõóî"‡óÿ::Zó£øéÿ¬,Ù¥K·e2¹»»3O(¥õëWá9C½z.;72d~HH\³f5}|êwêÔ(§ë ;w†[[›Édòß~;ëí];*jt±b:êÍTáÊ•»™™²úõ]„6tUÉÃÊ–-¥¼ÅÊÊä³Úîì\†×«¯¯Gqp(Å÷,^\—"“É !S¦øÅÄìèÝ{Æ!>¶633äño¢£c.‰ß³géqq»¢£·gffM™â§ú2ž›¢3Ÿ>7©J‡âÅuOœ¸èæVIyºùðá‹^½Â¦Mëß°a¾1¦P(! ¡åË’`ØØ˜ó}Μ¹*‘H=zqî܆ «ªÔ,røÅ‹·! Íö.gƈƒ¶ö?³¤RÉÏ?‡^ºtg÷î“¿ývÆÏoÖÊ•»÷î›íu†2e,JB*V´+_Þ¶M›I?f%&NWïõø|]9õtÈÎÎB=éRÞ-×¶K¥åz)U]ìD) í7iR¯M›DFn [Ó£GÓáÃ;T¯î(¼‰üÒ„Pû£G/…7ñìÙëQQI›6¨T©Ì´iýzôhª£ƒ¿þðyp?@U¬˜®¯¯÷Ò¥[ß¼ù[ùFÛ Ž»`mm¦|ctåÊö”Ò»wŸ8:Z;9Ù89Ùœ8qiêÔUü«WïÚ¯k×&~~³øÉÊó`áp~¬££µp¸@eF^µj9­Ã‡Ïñ”ÒÔÔKü¥#GÎ:ßÑÑzܸnÉÉ?-^<ò×_ϼ|ùFä¾g¾ÅË«æôéý“’RøÛê}¢ƒ«k9mm­'.ªÇ r”Ê–/l;¿† R¾žžNß¾-Μ‰MNþ)#ã­›ÛP¾‘¿‰¯_¿W>\x !îîÃ^¿~·gÏÜÓ§cúöm¡««§'À癀"Š16cÆÀC‡Î5j4bÊ”¾µjUxùòõÊ•»—,Iš3gH¹r¥•w¶µµðõõ ‰32*Q¯žKjêå‘#uéâ¡­-ÍÊ’÷î=ÃÅÅa„îééo«Té±vmH±bº„“'/¹»;ÛØ˜çt¸P…ÊDÖØ¸D``ç8“’îîÎÉÉ©|a!¤D‰bqq» 6fL׬,Ù¶mG+V´366Èö:ƒrÉ”Òñã»ïÞ}râĘ֭ëª÷‰J ¦¦%‡ ó YnffX­šcrrêÒ¥[Uv{þ<ãñã—*åðqyh»úuåÿ6nìÚ¨QÕ;wžðí"o"_4uýúz{{+õƪ´Ë“@r€"ƒz(/O¢”š˜;5{öºI“bîÜy¢££U£FùÄÄéü–_eŒ±˜˜qvvkƒƒ—?xðÜÂÂhèPŸiÓúB¦LYqñâí³g—kiIÍÌ ££Çvè0¹yó::4lÕÊ­OŸÙ„ë××çt¸r*•Κ5ØÐ°ÄøñËž>}U§N¥Ðо'ÆBªWw\·nò¬Yë\]/®ëéYcçÎp‰Dì¹IÂ¥RÉŠªW8|øÂþý[©7SeËܹà Š¾ðùóŒš5+LœØ3,l®îßÚÖ¨ÑHÕn¦4#c—ò–Ïm»z ¡~·†˜š–ÌöMlß¾?*÷„ 74¾Ó¾ ”ªÜÒ¹Ú¿ÿ´‹‹ÿê7ÆØÒ¥Û&NŒÎÈØ-•®Å½Ôã3®3à¢@ÑS¸~å|=Œ±Í›÷ìöûïWnß~¼uëÑ™3×úù5/l Ás“ ¸ÎPt.è~<ééo'LˆÞ¾ýØË—ollÌ}}½ƒƒ{«|á]¡Ðø3öÅu€¢9@Ñœr‚œÄº««ð¹ ÛeøÊ´ðk Á=Ððù´ÁŸ€¢ztðCÂÚ$€"÷'€(ä E®*@žà{ ¡`0Æöîý="â—S§®¼yóÞØØÀÍ­Ò¸qÝ7výÂ’££·¯\¹ûòå;™™2[[sŸú“'û—ÐäÁˆ”zBNŠ®U«BÞ¤(^‚&å3ƤROþ@3J©¶¶–±q‰–-Ý""F”,Y\<*~,!$5uYíÚóÿ×¢y$BŸlÀE‹°BIH!Šæþ-fÂgJ8Ñ^”·ä9ÆØôékBCWBªWw²´4>þ¯]»NîÙsjÓ¦©:5ÊsÉaak¦N]%•JêÔ©dl\âìÙë›SRÎ?¥¥%ÍuÂ-ì·„A¼ ˧ôŸ' {xT34ÔÏÈxwüøÅÕ«÷¾zõfëÖ™âǪT—ÿ(¥íÚÕ'„ˆDR°A]êWŠôµérQÞä PøcÚ´x==¤¤Í›×&„dfÊúöpp̘¨J$yœ²GFn!„lÞ„µk÷Éå BÈ¡CçnÝzTº´i›6u !‹'N›ÿüyFóæµíì,NŸ¾Ú±ãÿ^¿~Oþå:_.WT­ZîÆƒÍ]»vŸJù))ª7ðÂ…[*Óhþþ}§)¥R©ÄÚÚŒ’–vS½ 7P9vÀ€Ö„„„ƒr¹‚1öÛogŸ?Ï(SÆÒÓ³†g¶}¨IùC‡Î×Ò’ê_¸pËÓstXؚʕí ÅŽÇCCãÕ“\{,¿†är(ééo !††ú|¾8lØ~NZ83º*+K7þèÑ%‡/Z±bâû÷gÍZ§< ì|èPÄþýócoÞ¼ÿ믇„)SúFE®XÑŽòìYúÖ­Gýý:;û Óñ‰cþþûcŸ>ÍÏ[qøð¢ˆˆŒ±±c£d2ù§×Ümm->|±ÿiBÈêÕ{!´ÖÖÖ¢”ÖªU!<|Èþýówì˜}äÈbBȇ™·o?&ÿÎòGŽìtâÄÒÔÔeþþí!›U¦ÑBSR"ŠÈwà;O˜Ý¡ÃdQ]ºL%„têÔØÌÌR*4á?⊚ÀÓa Þª•›µµÙãÇ/8Kùå—C„>}šói¼HjRþ„ =~ûmALÌ8BHFÆ»„„©ûöÍ›0¡!äܹÊ­àïx®=–?ò933CBÈÓ§é|¾Xµj¹öí´oß@˜>ž:u™Ò¿ÿžEôí;›räÈyåɨ§gMBˆ££5ßøñc¥T"¡þþí._^sýúúU«&õëײxq݇_,⻥¤œ'„øù5ç…ôëׂ1öøñËë×ï¥ ·T*8°5!dÍš½oÞü˜xX"¡ýû·â¯6lXµjÕ²6ìoÔh¤ƒCw~Tff–PBûö ø:5&„\ºt[e}êÔeÆXÿþsø¡¾}g3ÆŽ9/¤„C‡ÎmÛvìøñ‹ff†C‡ú¬X1¿*4—Ù¯_ BÈ“'¯x„>”J%ýúµ$„lÚt 3S–””B)õók!Þ‡„MÊoÒ¤:!¤T)S^NÓ¦5!––&„ÌÌ,õ«%¹öX¾Œ;È#Ü  aê›7Þ³'µmÛº”ÒaÃÚ ÖŽüûØMBˆBÁ!»Gikk±WíBŠÓ¡”jiIÙ¿KÿOº2~BV–lË–°råJ—+Wºoß>>õ;vüßéÓWùnÂÝÕ¼ƈ0¯%ŸÞ7Ô°|]]mB¥ÿlÔÓÓ!JmT‰„16zôñ€ï®3@1¢#!$.n×–-)ü4³\®ˆÝ)œ™®Y³~l|üBHéÒ¦NN6äÓsÞVVá#Jœ IDAT&íÛ7øûïS¦¬$„ ÔV˜ ÇÅí"„„†öã·Oü‹%lÜø+ÿaëÖBˆ««£JäB“’f$%ͨ~†^¥ëcBønññ{(¥ÖÖf¼ ÊÇ:8”jÖ¬fFÆ»1c¢!}ú´fÿ9õ!!DÃò…x˜Ú}Ìêsí±¼&øöp @ƒU¦Më7eÊÊΧ¸º–³¶6?þæƒÏ !VV&––&ÁÁ½Û¶ ^ž˜xØÐPÿðá4¹\±lÙ•³õ*ç³Ë–-5rdÇE‹‡¿lÙV[[‹¿þzxéÒJiXؾÛÌ™›4 Œßsöì5#£))J$táÂ~r]¥ä!C|~ùåPzú[óV­Ü„y°å•+wûö]½ºSJÊy©T¢P0~“?0!áà™3׊Óåw{ÛM%òœ¨~†^%m ”æÔ©T¢r,!dÀ€Öûöý~ÿþ³’%õ;wn,”ŸSŠt‘Jù9žíÆ\{ ¾g¸Î€R:y²ïþýó}|êóûŒ33eÍšÕŒˆqõêZ[[ó-êìÚ5§Q£ªW¯ÞKIù³reû•+'ÜFü:!dþüá11cëÖ­ü×_vï>ùøñËfÍjîÞ=§GO¾›»»óÑ£KÚ¶­wïÞ³S§®Ô«Wy÷îŸødZ¥dBˆ§gu~;õ€­¤R‰0^»6¤V­ ï.\¸5ujߎBRRÒ„–.mh¨öì5''›5k‚;th R~¶ 2¤-ùô‘¬ÙΧëÖ­¬Þ„.]<Ô¥”¶kWŸß9ݵ«‡¾¾žÐÿ9õ!¥TÃò9 ¯3äÚc_e\À7BÉî{1àÇÇ»sçIÅŠ¾™™²#Gׯúÿ¡ø"ä<¢]PÔ`m@átô蟑‘[RRÎgfÊêÔ©ˆ„ò 9@!ÄÓÖÖÚ¹óc¬Y³šÂy€µIP$amRžam@у{ @ ʼn(¢p²wîÆ„ =—,ehXâÆQQIîîÃöîÛ A•Ï}ë[Äü…c^^µ<Ølnn”k»È¿¡Ž·¬C‡†åËÛä¹Þ³DLÆUóPfV–,§Ó¹scÍ[§9‘c5yOùFJéÉ“ËÔ̶m3¿EÌ_ˆR* ñv©lÚHùð!óäÉKKžÈ>g`ŒíÜy¢]»;wlm-Ôw ”Ξ½îÔ©+§OÇ:8Xñ?ÛvvžžÕ[¶œ0iRì±cK>7Jé±cþüó¯?þˆ«Zµ,¥ÔÆÆ|þ|ÿß¿²dIÒ÷<$„˜›ZY™ðÿZ[›õö÷_øúõû’%‹õ˜¿¥TOO§T)Sñ}„ŸcçÏÿµiÓÛ·7å9½aŒ ¦lÙR|£E“&ÕZµš8iRìÑ£‘yxï„ãêZŽbcc¾`Áp>`¾ó$ÓÜÜPx llÌù€yóæoƒb¹NÊó9É$„ä:`²½\ ÜFBˆ½½UzúÛ#-[6¦dÉâ⊣”†„ø¶j5±oßFF%6|kÙ¯MÊi&$ÈÌ”EF& Þ^H„W­š´sçl¾ E&“OŸ¾ÆÁ¡»®®—“S¯ùóV(˜°2aݺýÕª ÐÓórupðàŒ1ƒâ„„„YYr^/¥4%%òðáE¼™L>cÆZ{ûnºº^•*ùÅÆîT‰vðày..}…˜?~Ì23ó™3g#c,#ã]``d¹r=uu½ Z6j4òðá4áÀ½{¯Zµ¿žžWÅŠ¾QQ[yüÊMΩ-êF)-VL—÷ïñ˜ÇŽ]Zºt'a¡…BÁÊ–í1mÚêl{IF½Lòïò•Õ«÷V¯>POÏ«\¹ž[¶¤ìÚu²jÕþ|Ï}ûN«¬ ɶ[TÚñKË–uÌÌ …*&OŽ32jmbÒVyyIN‹XcYYr>`„„Aè+>`„÷WóCLf¦L(“òï•+•ŽRyg‡ ™ïâÒWˆ3×#»wïï®®„CÔ>5Ù¶E¥[„„“훫ó¸qËø€áÛÅLNƒoÿZ†ä@å"‘H ¦P(„Eb–Ë¡¡«ll:ëéy5h0{öz‰¤É½{Oy™îîÎææF+VìF²ÏÄϘ2ÆÎŸ¿ùêÕoïÚêçæ­¬LŒ (¥”ÒQ£"7lØ=öúõõ³f _?}z¼°óâʼnÑÑcOŸŽÕ××ëÝ{¦BÁjÔp0 Uxø†R¥:víºxñ–«Wï)O­#/NŒˆqõêÚáÃ;DDFnQ޶_¿–—.Ý9{ö:ŸvìÜyâõë÷~~Þ„?¿Y‡[³&øæÍ ,¤”vìø¿¬¬fêAA±“&õºzuݨQÇŒ‰â³@eâmQî´´´›sælðô¬Î/2äsÿþ­?~¹wïï<æƒÿ¸{÷I¿~-³í%¹\‘k?Ì»1"bDZÚJ;;‹~ýÂCCWÅÄŒMK[accîç7Seæ*Þ-„¹\‘””âéY“¿§|ã¡C王ڵ+ÜÞÞJ9YâkNlm-T†0`ÔSP>`x~É€éÒe*0ÊõªwÔ’%IʵósæÌ5¾žÌ’%I*MËuÀð~ã—qø€14Ô×$faÀðwD|Àð·[¼Ì¯;`²m£L&?xð°°Õ^^µ õUvË6æI“b¢¢¶FFŽºrem—.MBCãUÊlÚ´Fbâá|¾» hÊfm’AKBˆ\® „TªäÇÿB¿~½[yjøìY:!ÄÊÊDX&1zô’¸¸]B!W®¬ÕÒ’ÆÆîØ¿~ãÆ®”R;;‹‡_üï+‚ƒ}ù>aaÜÝ !þþíýüf=žaaa;®{÷¦¿ürð×_ÏlÞ|˜âåUkåʉÖÖfÏžeDGo‰×¾}BÈðáí¯_¿¾!  ƒP¯»»³³s™õë÷׬Yž²víÞV­Ü¬¬L#žž57v­VÍ‘bmmС[·i¼!„™3õèáI)6¬Ýµk÷æÏO>¼½PìÓ§éâm©R¥,™BÁ¼¼jÅÆŽ#„h³³s™zõ*¯Y³·ukwBÈêÕ{¼½kÛÚš§¥Ýȶ—(¥âeΚ5¸Q£ª„!C|zö ›7Ï¿nÝÊ„Ûôè1ýéÓWBÕB·¸º–ã‹ÁTº…rùòׯßW©â <9 ö­\Ù^}ðd»ˆ…1& aÂ7fLTNÆÃ£!ÄÖÖ\}À¸¹URî KKãåËÇ &1ñ!¤Y³š*¦]»ú”Ò€€"¦F §lLN=3sæ ž=›B†õ09µ%ÛÃÓ$faÀ´jå–í€Qé%aÀäTæ¬Yƒ7vU0|ȉ ˜œ>GÊ„6B>|È44ÔoÛ¶ÞO? UßS=f]]íÈÈ-K–¶o߀R:jT§7îóLžÿΡ”º¸”]±b·L&×ÖÎã}Y ¡lþÖž=»œrð๡Cç''ÿdeeBÔÖ]ðÃééo…)`PPoÿö …"-í¶\®hÓf’p¬\®øð!óþýgü¿ŽŽÖ|ÊÏ;feÉøžM›ÖhÚ´cìÎ'?ÿ|(,lu÷îÓRR"/\¸¥P°ºu+ “†úõ«DFnyþMç= ßN69ƒ““ !äÊ•»„{{+sõHÕª9?pàZµ*ði“……‘……cŒHþF$$„ª~ÌÚ¼yšúžê1óD…1Õ˜•[!•Jù±ÙÖ_Q^îg „èéétX°àç;wž¨ì|çÎþsåÊö”Ò»wŸ89Ù89Ù8:ZŸ8qiêÔU*)~çÎãyó6=~üRy~@)^\·xq=‰„ž8q‘ý{{ôñã,-ML ”°´4nÓ¦nBÂóók®­­E)=~üâÑ£nÞ<}îÜaC‡ú4nìzóæCBˆPù©SW„)àÑ£çœl”W]kØ•^¢”js‰Åzôhšpà—_úúz —)²í% Ë)A t˼yþC‡ú4jTU¥[!ü$î“'/ÕËT/0[”R]]m>`nß~¬ü¿šÄ:ÙÑÑš÷³z'«ÄÀÌ£G/”w jFxgÕ;Šbaa¤<`øÔ?מ9uêŠÐÿ"F¼-*ÅÓ0f}}=壣óIò¯ÒKš”©2BTJäú9R!âí]kúôþII)Ê ÒDbvu-§­­¥sjê%å2c½ÐÑÑ277ʾnøz²_L)mÛ¶žBq0§ÃcS¦ô¹pá–›Û°Ñ£»4o^ÛØØàÚµû«WïÙ´é@íÚŒJ”(QÌ××+$$ÎȨD½z.©©—GŽ\Ô¥‹‡¶¶T¹"åb'MêµcÇqÀ©Sûº¹UR(¿þzfÊ”“'ûéêj[Y™øù5 Š55-Y½ºSrrjtôöððÁ*Búömѫ׌wï>ÄÇOâ[,-)¥ññÉFF% ŶmÇ,H „¼{÷7?0((ÖØ¸D•*e·n=³#>>H¹XóÏm §yÌ´®[×_"‘,\ 2W)ÙÒÒXÃ2ÅcÓ¤[!*ØêŸ;w£Aƒ*âe2Æ>~Ìzõê¹¹‘òIw¾óW0*í0::Zšto…ò€á[òaÀ¨/î⯆1+•rTzIó2s*A¹¨\ŒJ9Âüøî»wŸœ81¦uëºÙî©ü_SӒÆù„„,733¬VÍ199uéÒ& ×Ο¿Y³f•‘ßB樂êèh%%ÍøùçƒññÉsçnz󿽩iI7·J›þÏÞ™ÇÕ”ÿüó¹·º•öº-ÓŽ¨”"¦ì‘2… ¢P†´Œ-´X²×([E £…²diÒŒBdÉX!“,¡ƒºÝÏïÏ8ß3çÞ{î-3Ão|žþ¸ûù¼Ïûýþ¼î½ŸÏ9ïsNÎÒ1cr¹@JJ˜‰IVddÚ£GÏuu5=—/÷§ÛaLLLt/\H‰ÍŽŽÞQSSÇårìì:%%Í4i(n¼uë<ƒŒÐÐMuu ]º'%Í ð`8pwwTSSîÞ½£¥¥ ÞÒµ«qZÚ‚˜˜]iiGttÔ½¼ú•”$ÙÛ”–ÞÒÖV,Yâ·`ÁÖû÷ŸXZšìÚµXôîþ²Ä"v-£Ï]ºu3SRâáCÔ,YÈh“ÅFjZ\.çÛo^ Ã/„°¨¨ÌË+ªª*[´ð†Ç“g ®0‘šd†MI‚ññqÁ-E5}úpÑÌP‚±²2ÅÛ--MÚ$˜±c1rÛÖX¨²ø !ìÕ«+Œ9øë‹Z–1ì¾Ù#Ö„ÃÛ·/ìÑczpðI-)Ö­›¥ªª¼áùóF‡®‹ù¬\™I‚ QQQYhèÙ¯«!Ðn  “ŸÚ/\Àmn>!:zc2÷ÉAݺõÐÁỪªÝ_}Õþçpþ^ZZX0ÿ½I3BèçŸ/ÙØ˜S÷ÚJJ:¸hQrcã1¼¼A[[mÇŽpüü‡Oí”ß89ÍÊÏ_CÝ“ð©xñâ%üü‡ÿ¡ÆÆ7 &çç—¼|ÙddÄ÷õu‹ŒœÌãÉ /ÆÆfÅ3î*F ´ rž¡Ýó —Y3á‹„¬Ú Y3_¤6‰@ @ °AÖ @  ²f @ l5@ @`ƒ¬@ í_3àÇmÛvtРٚš#xÆçGö¸p„P}}“¥¥oeeÍÇìW’`>ƦXÁHU ,hk_YÆ·ÁjÁtÁüs> ²ÇE¹Çˆ‘ÃÌ㹚™yÏ›—ôúõ[Fã3Yx÷®9..·gÏï””ÜTUÝ Ý¿ÿô¿à'BhïÞ“ô¼QÙëÓ'¨}6‡gié+º}ÇŽ.wHUUm›âBµ¶ ·m;úüyc[=)((uvž-´~†#N Yk_7„Ps³ÀË+òêÕ» ú$&ÎVWW¹{÷QRÒ'§Y……ëú÷·më}Óñ"dèÐùjjÊéé;Ô×7íØQ0bDDNÎÒqãœ%u¤ï!Ô¦ý²ô¥ÿ¶I²Iµ)-M66æZ[…••5þþ1µµ/òó×ü>$!W×^íãó5¤Æ>¸¶uôè]ºµ{¿ïß·°fÀ€îí°ÙÒ"$˜±cÉì°ô•eLñFáùó[EsèÐêÂçBH †=.Æ*FÀ»wÍçÏßœ3'ñéÓú;£¤*ðSÑØøÆÍ-ìíÛ÷ÑÑÓzö´øã÷YY…ãÆ-‹9þøÔ[J§NmêÜÙþ–‚‚|;¾%BÃ'MZuîÜ>}ºÑ·gdü4t¨CÇŽmý¶,(8?cFܰa½Ûê»»ã–-öÏ;® 1á³Aüš!täÈ9/¯¨êê\cc]ѵkw^¸PQV–jn®_##>LSÓ[UU%©“òy‘ *±é1ÌÌô^‡†nÚºužšš2»ÁOBhÑ¢ä—/_••¥ª«wÀ×®ÑÜ,X¼x›·÷`##þ?—y*‡::êKr „£GÐÖVÛµ«ÈÉÉ{Žªªª=}ú·œœ¥íøÄQN¶£oT”¯‡Ç¢©S¿ÑÔTmS_@ |ˆ¯M’4¢hn$$E-¨Æ;v„9²ÿº­+Vdš›Oàñ\-,&ÅÇï U™°sg‘½}€¢¢«]@qñ„ªª2 7÷DKËŸ§°!„§O'œ:µ ïE h]µ*ËÌÌ›Çsµ²òKM=ÂðvÆŒ8›©”Ïïß·èèxÆÆîÆ•3'¡S'ÏUUÕ}àÀïO*§:^ìÞÝ_QÑÕÒÒ7)é ý×#)ѤA•”xàÃO¬TŸçÏßòÕWß ­ø_¡uì8qùò ±Y¢œµ >”¯ddöè1]QѵS'ŸýûO=z¾{wÜòøñ2FeˆØ´0b߸q¯»û×::êÔ./Þ¦¡1\Kk$½¼DR B¨¥¥ †Z0P¹Â‚¡ÆWvÁ(Á47 (›X0àÙ+F¢#;sf¼ÍTÊO©‚¡ú^´³  D>5bca¤…zA Fìà2| ÛŠƒ·³ F’ñö¿K0@Œ‡Ã ‘P(¤ ²øÜÚ*ŒŽÞad4VQѵÿµkwq8ƒÿýKq >ÿ½תYYùedÊXB†zýúmFFaHÈjÁ€·‡‡ûœ8±QOO‹}¢,õ+#©ÐKê·n~þYgpZÚŸc½CEå›ë×ïcƒ™™Çmm§ñx®:ùlÙr[PTTðó–›[ÜÜ, ¾Q33 uu5¼¼ú³|E‹Í$ÀÓ3!db2Bg©º¢K­ø|íÛ±Œ @ >[įؘ"„®]«ª¯orsë-zl^__KSSB!œ=;!;»(9yþ;»Ö¬ù.&f׊éTãÍ›ó’“ç—•¥vè 8yòj¡õìià“m`0füøèÍ›÷ß¾ý;}j5gNÂæÍy7†Þ¾<:$dcBÂ~º·Ó¦¹ß¼Y}ùòüÓuäȹW¯þðósøù­9yòjffdUUö‰ „cÆ,iiùs¦‘>éöí³g7/ Ïé°ÇBOZyyUllö!=ðI©>ûû{}±„kNŒu¢#:]À‚Á üÁŒ· †¾_ÑD%& ï æÒ¥Jܾ݂IL<ÀMª`¨ã¾×®ÝÂQWï ‹Ï”`ðˆ° 7»Í¿W0bcZ‹‹¯¬\™áêÚ‹>#gñ9<<%)é`BÂ슊¬qãGG§ÓmJÚ]pð†ääüøø ŠŠÌ€€áþþ±?ýt¡FÉ*½÷þ}KŸ>ÝÛù|¾}»)(°UrJR¯¨·b÷d8OåéÙ70ÐsÁ‚­¿ÿ^÷ë¯×V­ÊÚ´éûnÝÌð»sç&Οï}ûvVX˜÷ܹ‰ÉÉùøûÄßßãÅ‹WÇŽÇ6[[……S§~#/ÏTŠu%6“™™‘ÂK—Òjkó€4]1¾% „..=óòN}ni@1¿‚ªªî€ÖV!ÀÊÊ¿¿zuŒ>5¬«kèëk¡esç&nÛv”2RQ‘%'ÇMM=\T?h„ÐÄD·¶öÅ’%Û##ÿ¼&oåÊ''k@PÐ(?¿5ÏŸ7êêj¤¦†M˜à²woñÏ?_Ú·ïÀÕµ×?.24Ô©«kLNÎOI 5ª? 8xÔ;511Ù!!£©ý:9Y[[›îÚUäàЕUèáᨯ¯…2¤ç Avöö††:!!£½½—ã@«W7qâá¬Y^••¿ÇÇç¢Ì>{ÖÀ‹­í4œ‡–Pˆ\]{¥¦†dñÙÚÚ´oßn™™…Ç;22~rsëmlÌ//¿+6KBv›kÖÌ8°;`æLOŸ•qqA¸šyúô'®xö¬žÚ5•;»N¸Œ‘À­[Õ¯^ýakkNŸÓDFúR“:b‹XB”`¨Iä¼yI’ãìl06æ‹ ÆÑÑŠž ==Í´´”`òò~ êÀŒ—W?aHÈhÁôìi!V0’2³zõw>>.€À@OÁHŠE¬`B²øL ÆÃÃQ¬`Y¢#Éæš53 ²£ KŽE0’>Gt¨ïÞ5««w9²ï?жõ™Ç“OHØŸ˜8gÔ¨þÂÙ³¿½{·¯ä‘äÒ¬ºº†ôôÁ’³ IDATŸRSÃp¯°0ïæfBÌ)¸$•66¾hjª´£ð†eÄ‹ I…^ÔN{÷žÉp -m·÷`@\\ÐÉ“W§Oÿ¡²ò÷‰]<¨6QQ¾S¦ £¾ÁâârgÍòX[›öëg³sgþºøå—Ë55uëJ_‹Í¤†† øPŠ)U«Œo „MÇíÛµ´äåÛy)@ >b¾¸/_N_ Œ/(øA__ ˆœ7dž^SSÀˆˆÉAA£¨ŽB¡°¼üAk«pĈpªok«ðݻ暚:üoçΆxŠ;¶´pK—ž..=BÕÕO÷ì9¹reÆ„ ËOŸN¸~ý¾PˆðQ@|Ôª_?Û„„ýŒ›xLêŸûÃ/_6\ÈÍ]€yåçŸÝ½û—êê'÷ï?¹~ý>@(â^ÎÎöT,}úØlÚ”÷âÅ+Êfyy{,GŽÄêäõô4yã… BLŸäó B|v”¥ ![[seeÞ¹s7ðijûãÇ/'MZ¹|¹?>}'¶/ˈËèå°‰‰.µˆmséÒm‡óøñ‹«WïÒï6&//'ú †_Œçwè H £ú…‘%Yl2°@!õsÄ€2âæÖkÅ ÿNÓ ÒX|¶³ë$//G÷¹´ô¦¤¼Q!à´_¼x›ê5vìÒ   ²hB¨¨¨àëë¶eËÁW¯þ o_¿>·¤äº¡¡Ž$;BYFœ©ßº€Û·Ÿ7/):zÚøñƒýüÖàwø­óçoRQ—”üfeeª¢¢„³ª¬Ì›4ihNÎ/{öœTSSÆåFì>KÊd;tEêñã r|¾†ìi!Âg‚ø¢RáÈ‘}…ÂbIÝBK—N¹~ý¾£ã¬¹sÇ Ö[SSµ²²&#ã§œœ½{[jh¨¨¨(ùúºFEmÓÐPéÛצ´ôÖ÷ßo7Î_{Gíˆn6<|ÒáÃgç,[6ÕÑÑJ(þüó¥¥K·/^ìÇãÉëëkùù ‹ˆHÕÖVëÑâ  499?&fÃ1ÀÔ©ßLš´êÍ›wééáx‹žž&„0=½@CCE(:T²~}.àÍ›·¸cDDª¦¦Š­mǃϤ¤NO ›52â·5Œì> ïÓ'ˆÃálؘš0,ëéiÊh“Ý7YÒèÚÕX]½ÃÕ«wû÷·e·‰zÿ¾¥¾¾‰Ï× tÇÿÁ0âbŒ‚‚œ,‰ÂQЃ·ü ‚=ŽW¼2úL Ã#K²Û”dnJª`v¨ 傎;¿hQÊðá}ͤÿ«­­6k–gTTšŽŽº½}ç‚‚Ò-[þ,L ÑÓ§/|¾ý „P__Ë××5""UGGÝÊÊäС’ƒÏ9ÃX벨tÕªé'O^80téÒ©½zu}ùòÕ?KL<;³cG„À“'–ê1úëJqÌ»wÍ’öŽ_<ÞH_ȼ–@Ð:yò*ó… '44¼¶µ²1++ 7OÑÒR³³ë”Ÿ_’’r8##‚ž™€€á½{Ï|ýúíÔ©ßP+LŸ%e_‡pþüM''k##~›t…ºv­ÊÁ¡+—Ûþg‰áSÑÎ Ñ „ r¬Ú³§8=½`ݺœ¦¦?´µÕ­rr–Ž3ÿ*¤¤„™˜dEF¦=zô\WW#0ÐsùrºÆDÁÄD÷Â…”ØØìèè55u\.ÇήSRÒÜI“†âÆ[·Î30È ÝTW×Ð¥‹qRÒúU€àÃO”»»£ššr÷î--Mð–®]ÓÒÄÄìJK;¢££îåÕ¯¤$ÉÞ> ´ô–¶¶`É¿ ¶Þ¿ÿÄÒÒd׮Ţw÷—%±Óh}vpèÒ­›™’ácÉ@F›,0RÓàr9ß~;°°ðBhèöx!„EEe^^QUUÙ¢…7<ž<‹`p¹‚Ô$3lJŒ n)š¨éÓ‡‹f†Œ••)ÞniiÒ&ÁŒ;ˆ‘Û¶ÆBm”Åga¯^]±`llÌ´£Ô2æÝ7 ›`ÄÚr8`ûö…=zLÞàïï!©%źu³TU•ƒƒ7<ÞèàÐuÑ"Ÿ•+3y<ùÆÆ×††cUUÙŒ‚@aròüåËÓgÎŒ{ú´¾K£;óÍ׌6,*ÕÖV+)IZ»vgxxJuõS¹ž=»äå­À76¾þê«o÷îífôE‰qѸ$íBhàÀïE3ùêÕ±Õ«³nÜxpùršœWGG=9yþèÑ‹‡ û_—¼dÉ”¥K·ßºõÐÂÂ033_3MÑ£‡EÏž].]ªÌÍ]F_ȱø,šÉaÃz¿yóÎÃÃqÊ”µ€;wvɨUðç‰,PTT:F’ºð9üÔn|éànsó ÑÑÓ?ºŸ„Э[¾«ªÚýÕWŸÝs¸¾XZZX0ÿ½IBèçŸ/ÙØ˜S—ÿ&%\´(¹±ñ‡³²Š¦N]ûìÙAmmµ3v„µk|ÁôçÀáÃg%->+Š‹¯x{/¿{7[Òƒ ?ÐYb]Iê„/ rŽøÓÓÐð:?ÿlHÈ&„€ÏPÙ¯øw€ZY™LžìºaÞÏÍ·/„PCÃëC‡J(Á|.Ó¯¿á¾}§||V–•Ý~ðàɧW¯ÎòóÆáÀæfA\\Ndä¤Á@íúóY0ÈrÄçBhݺœˆˆIŸÑ‚@ mÜ$ûƒjmúú®ÖÖVÛµk±’’Âgøƒ !Œ‹ rrš5cÆHIwt!ü;@é‚{ëÒÿ¡ØØ™ &ñòe“‘ÿ»ïFDFNÆ×ÓŸ;·EY™÷/ëdž;·ß‘ö3QÝôy~6BÇ—½{×üý÷ß~žA*¤6‰@ _$¤6©ÝÚ$á˃Ô&@ 6Èš@ @ °AÖ @  ²f @ l5@ @`CüšáäÉ«VV~øµµõ”¢¢2Ñ6Aë¶mG š­©9‚Çs51?eÊÚk×î}Œ7uu ³g'tì8‘ÇsÕÖöts +((•úL€Ã‡Ïr8ƒïßÜŽ§HꋢޒԷЙúSPjjê__ßôÏùü1ȽM}}“¥¥oeeM»½Å­+˜±)V0R{IÍ@ûúÊ2¦¸ V ‡3˜.–^ãóÇ#{\¸ =FüÇ㹚™yÏ›—ôúõÛO‹ì´O]¢´¶ ·m;úüyc›tNeé÷ߟáòò.Ïž5ÐÛ45ýÑ¡Ã7¸M[½¢öRPPêì<[ hmŸ@ |9ˆY3 „JKo9:Zá§GݹSÓ»·%ãïýû–#Â/ÞæåÕÿ×_7ß¹³+==âõë·NN³NŸ¾Ö>WZZC‡Î¿|¹2==¢ª*ûäÉ66æ#FDìÛwŠ}:E½në¿Yú2îz.¶;n!,-M®­Í«­Í»wo÷Žá?ýtaÊ”µÿÏ „ÐÕµ×£GûŒuÙã „Baa[G`aÑÎ'3à‡aIÌ™3¿µcÙ€!b³wïI–޲Œl;úÊ2¦T,˜GöÑÃ’Ûñù#AQ‚‘êCQ[›WQ‘¹víŒ]»~ž93 UŸœv«KÔNAAéŒqoß¾oÓgG´1‡Ã9pà4•1„P~þÙwïš©e7NßË7ß|­ªªœ°ÿ³ @ |&ˆy¦„ðâÅ[ÎÎ=.TXX©«w`ÌZÖ®ÝyáBEYYjÇŽx£‰‰îàÁö‹ÂÃSÏœIhÇô½¤äúo¿Ý»re›]'€‘ýúà‹+Œç,©ãÇ<Òˆ¥o›¦€|¾º6~mdĈ˜´¡©é­¤'ž~ÚÇ0)**PÞŠ…1{¸ví^NΉrÚí'„Œ¹¹>¶cb¢;dHw÷…áá©%%‰í°I ¦{÷ŽB##~||ÌØ±ƒd™àþs‹LöqçóÕõõµð¿††:X0¯^ý¡¦¦ü·ûü‘@¥ F¬Kôææ ¯CC7mÝ:OUU‰Ýà'§ÝêµCŸåË>v¢3x—žû÷ÿ:sæHÊòÞ½ÅýûÛâc4óÙŒŠòõðX4uê7*äk@ó<.*ÈËû54t‡3xذ°[·ª¹Ü!ô_¾––Ö„„ÁÁ£¨B¸cGø‘#1ZW¬È47ŸÀã¹ZXLŠß#"êœûÎEööŠŠ®vvÅÅWªªÊ€ÜÜÍÍÊæéÓ §NmŽü­Z•efæÍã¹ZYù¥¦ÁGÁ©Æ3gÆÛØL¥ü|ÿ¾EGÇ36v7B¨±ñÍœ9 :ùðx®ªªî~êT9Õ·°ð¢]€¢¢«¥¥oRÒA 2 =vz~””xÔ©>‡…mýê«o‚V¼](D;N\¾” ,^¼MCc¸–ÖHFy‰¤"–æf µ` r…CÅ%»`B”`ZZZñ!„X0”‰bŒìŒq66S)o¥ †êXXx±{wJ0Œ1’ÅO5 Ü€R‚;¸ ŸçÏß‚ƒÿe 匨Mj¼>^02ž°âp8B! …GŽœÃY|nmFGï02«¨èÚ¿ÈÚµ»Ø‹pd׿Ø^ %·[]@ä3âå…21¿E% !ÔÒ"ˆŒL30£¤äææVQñîÒØ±ÎÅÅW^¼x…ÿmhx}üxu0…eh°?™™Çmm§ñx®:ùlÙrˆž''k>_cûöcdÁ@ ˜k†GöýöÛ99µµyÇ;­XáÿèÑ>úçÚµªúú&7·Þ¢s}}-MMUBhöì„ìì¢ääùwîìZ³æ»˜˜]+V¤S-7oÎKNž_V–Ú¡ƒâäÉ«…BÔ³§E@€GLL¶Á˜qã–mÞ¼ÿöíß©öÂ9s6oÎÛ¸1ôöí¬ààÑ!!Ð÷>mšû͛՗.UâöGŽœ{õê??7€Ÿßš“'¯ffFVUeŸ8±B8fÌ’––?'^©áá“nßÞ9{öØyó’0Bc|˜!„®]»›=dH|rFªÏþþOž¼,,¼!„_yøðé´iî’²`·¹nÝîCËË41Ñ6-&:zGJÊüòòíFF|?¿ÕŒ¥{Z­­ÂNâ@ŸŸÝŒôµ¶6]ˆ-bR‚¡Ê3æÎM”$˜Aƒì „&&º¢‚ÁP©ÐÕÕHM £³oß)€«k/†`FêÅ"‡.b#)3«W7qâá¬Y^,‚‘‹XÁdñ™ÌðáNbÃÈ%I6׬™1p`wº`úôéÆ.IŸ#:TŒ€wïšÕÕ;ŒÙ÷‡E[ŠúÌãÉ'$ìOLœ3zôÀ÷ß¹{·Fô j¾+Uÿ ‰Jª¼‚~Œºðgðüy#øP©ÅòMÒÔôǶmGSRæÙB8gÎØ»wk¶l9DùÃáÀo¿¸ÿ¯€½{‹Ç,:4’å;eÊ0J±qq¹³fyQ‘ÚØtܾý˜@Ð*//¦Z•@  ºf@•—WuïÞ!ôúõÛ{÷jíí;Ó+q!„øLBCÃk¼B19(h ¸øj``¼P(,/ÐÚ*1"œêØÚ*|÷®¹¦¦ÿÛ¹óŸÔâãŽ--lÍÅ¥§‹KOÀƒOöì9¹reÆ„ ËOŸN¸~ý¾PˆúôéF-Túõ³MHØ’)¦NuÏýá‡À—/› .äæ.ƒB‚‚¼òóÏîÞýKuõ“û÷Ÿ\¿~  q/gg{*–>}l6mÊ£jååUì±9ch¨PP×ÓÓTTTÀÊ賿ÿðàà õõ¯¹\N^Þ¯ééáÔ[¢Yª¬¬a·immŠçO:(ÌÍ pKee€~ƒ©iÔÖ¾ðùôcmº!D †ò¹}‚Á>P©À-±`BÕÕOÅ †Y#Kfœí©X>^0<ž|ŠC¦t%zÈÀ€îÚÚêùùgñêÂÀ@‹zKêÐÈËˉ*–ÚÂår¹ž@ a^ÏpùršÖ?.º|9-4ẗ}._N»|9~žÇ“ ½~ýžžÐûâ£qøu·nf‡ŸvîlhaadaatîÜÍeËvÐÛãŸ+êßêê'qq9¿ 7(+ó”•mlÌ9xîÜ êGúìÙëzzšZZªt›ºº#FôÉÍ=±{÷/~~ÃðLîìÙgÎü¶oߊ¸¸ À@Ï»WUÕ¨ßô *ЇËÏœ¹†oEÙ”1F&B2úÜ¡ƒâĉ.¹¹'öî-öõuSPøË\‘%YlÒçX¢(¨´¬[7+0ÐsÐ ;FZø¸ãÓ§/EmŠ”„¢¢LuõS†QÁà wîl(šd†X0Ož¼¤WfÁP#+š(¡žž&]0òòrB©™¹p¡‚Ê?‹`Øcad B(£Ï**JtÁP§)ÄfIF›,(¤~ŽP{tuuX±ÂÿÀÓiiGÄZfìÑή“¼¼ÝçÒÒ›’òF… ÉšhtâÝý«µ¿E]Œ]³|“tïÞIAAîÔ©«”®¨)¨ò¤}ûNÒ “€ ŸåóçoR–KJ~³²2UQQ¢¶<~üBAAßç€@ ±0eijªÖÖ¾ðôì«¢¢tïÞcgçTy „péÒ)ׯßwtœ5wî¸aÃzkjªVVÖddü”“s¢woK %__ר¨m*}ûÚ”–ÞúþûMãÆ9ËËÿïp,ãÇ;<|ÒáÃgç,[6ÕÑÑJ(þüó¥¥K·/^ì§  §§§éç7,""U[[­G‹‚‚Òääü˜˜ ÇS§~3iÒª7oÞ¥§ÿY §§ !LO/ÐÐP …‡•¬_Ÿ xóæ-©©bkÛñàÁ3))‡ÓÓ#èfŒø²Ä"š%Ù}Þ§O‡ÃÙ°!„a‡‘%ÙmJ²@7Åž@×®Æêê®^½;`@w†MÑeûwÍõõM|¾ãX/Bèo c,‚áñäõõµ¤& g†.¼å_ŒØE—ì>ÓÃ~]ÁÈx$^Áˆµ!\°`±cç-J>¼KKŒ¶¶Ú¬YžQQi::êöö J·lùób„À“'ÖËÑÏí°,hY¢C½ß‚E˰öw© ßëüù›NNÖ,ÂÐÔT™3glTÔ6--5''ë‚‚RFa—'q80++о]êЄ‡§hi©ÙÙuÊÏ/II9Œ¯Ì¦ríZ•ƒCWz@`À\3œ?³[73|ŸÁsçnÌ™3Vì‚Ç“?p`Õž=ÅééëÖå45ý¡­­æèh•“³t̘øwJJ˜‰IVddÚ£GÏuu5=—/÷§aX61ѽp!%66;:zGMM—˱³ë””4×ÇǷܺužAFh覺º†.]Œ“’æLŸ>œnÿH»»;ª©)wïÞÑÊÊo·´4IK[³+-íˆŽŽº—W¿’’${û€ÒÒ[ÚÚj€%Kü,ØzÿþKK“]»;ˆo[c¡6Êâ3„°W¯®Ýº™))ñllÌëHö<°ûèÚÕ˜=-.—óí· /Ð/Ãk!TTTæåUU•Í(¼*(ȱ†Ëå’̈K’`&MŠ‹& _?ʈ‚Œ¥¥ Þ"53 Áˆ>?D–XÄæPFŸº`ÁàC×,Yâ#Ö&‹Œ,‚‘#—ËÙ¾}aÓƒƒ7øû{©À IDATˆ¶dlY·n–ªªrpð†çϺ.Zä³re&'ߨøú«¯¾Ü»·›^Èr&A4:z/J´ k—º­<<§LY ¸sg—Xaà–kÖÌPWWY°`ë³gõ_m=uÑ¢FZú÷·ÕÒRíÞ½#á2(vÊÒ¥ÛoÝzhaa˜™éíý¿ÓB!*** #{Á!@ ¾@  “ŸÚ/–¹ù„èèiŸÛÏöÍ›ÕßUUí60ÐúÜ|û2ÁÿX0Œå↢¢2s|G#„Ж-‡-Jnl<ÆáÀ¬¬¢©S×>{vPGGýS»ùÿ€Ã‡ÏŠ.Š(B'O^õö^~÷n¶¤G þ—ÎKëì@HRG |i0¯g ü› „^:T² !àã3ô3œ”[[›NžìºaÞÏз/††×ùùg)ÁÈRÿÿ„о}§||V^¼XñàÁ“ƒϬ^åç7ŒÃÍÍ‚¸¸œÈÈIdÁ R¯A‚®[—1éK\0¡-»qJ „­­B_ßÕÚÚj»v-Æ·ƒüÜ@ÅÅ99Íš1c¤……‘ô„ „]0JJ ÿÉ…„06væÂ…É#GF¼|ÙddÄÿ‘“ rçÎmÁ÷Q%H…Q²%ª–‹ïÞ5ÿý·¤0‰@ ìÚ$@ |‘Ú¤vCj“„/R›D @ Ø k@ ÀY3@ 6Èš@ @ °AÖ @ O³f8|ø,‡3øþýÇ­­ÂmÛŽ>Þˆ¢6Jê%KL}}“¥¥oeeÍßr÷zü­mÛŽ4[Ssçjb2~Ê”µ×®Ýk·}„P]]ÃìÙ ;Näñ\µµ=ÝÜ J¥ö’1míK½Ån¡3„ÎÎ`…¡¦¦ÞñõõM,½>ÆçGö¸p›‚‚RgçÙAk;FV’H>Ʊ"‘ê›,Q·µ¯ìŸP¬üGÉ?çóÇð÷~óð_å¬ès‚‚‚Ò3âÞ¾}puíõèÑ>cc]I“ƽÆY쇅m=z€……áÇßq!ÔÜ,1"|ñâm^^ýýuó;»ÒÓ#^¿~ëä4ëÌ™ßÚ1ÅÁ‹¡Cç_¾\™žQU•}òäFó#"öî=ÉÒQÆ ´µ¯Ô?ÑÛ”–&×Öæ=z´ïÞ½Ý;v„ÿôÓ…)SÖ²äùc|þHB”¨¤Æ€º»;ªª*'$ìo«rÞ¿o‘$’Ó§¯µÏÿ–X‘ìÛwŠ]ÿôˆÚ´G–¾²Œ#n!Ä"©­Í£‹äòù#¶é›‡@ „/ñÏtC9rÎË+ªº:רX÷ïÝ¥ØÉ„PQQÁÀ@›¥£ŒSÛk×îåäœxð çoù¥‡®]»óÂ…Š²²Tss}lÓÄDwÈîî ÃÃSKJÛa³¤äúo¿Ý»re[÷î!„FFüøø ‹+Œ;HÆ n›v*ûtPÒóbñ >_]__ ÿkh¨19(hëWHzŽì§J•¨£¢|=<Mú¦¦ªŒ;BQ"éØÑo41Ñ<ØÞÃcQxxê™3 í/J$vvFFüõ냱HÆs–1¢6í—¥o›–|¾:•v##>ISÓ[UU%vuµÃç§Mß<@ |™ˆ?Ï õ˜">SŸ‘QØ£ÇtEE×N|öï?}ôèùîÝýypà÷§N•KŠH´4¢¹Yp 8xµ` Ò²cGø‘#kBø¼ÁŠ™ææx_cûöc2ç „ZZZ±H¨e‹„SÙE DÒÜ, lb‘€g«ÉaŒæÌ™ñ66S)?¥Š„ê[XxÑÎ.€ ùN #-Ô J$b”ásXØV,¼]$’„‡·ÿ]"@ |ñˆ_3°S¤Þ]·n÷Æ¡åå?š˜èN›½#%e~yùv##¾ŸßjúBtbŠÉÌŒ„^º”V[›ÇxkîÜÄùó½oßÎ óž;7qëÖCt þþOž¼,,¼ˆ-_yøðé´iî­­ÂNâ@MÄýüÖœéöí³g7/ Ïé°ÇB@yyUllö!=ðI©>K5±YjmJÍƒì ”š*.¡‹Kϼ¼S¢#.¶ˆBH‰DTäX$ØøÇˆdܸeX$ôýŠ&'1ñ}ïX$—.UâöíIbâFhRE‚³‡Ïûa‘¨«wÅgJ$ø“Å.<Äì6ÿ^‘ðe"fÍ ªê®¦æáí½`e姪ꮪê.v±fÍŒ»wéb4s¦gSÓqqA}út³´4™>}ijg ÏžÕÓ»ˆ­7ÐÐPÊ]oEEùNú™™~` gPW\\.ý]kkÓ¾}»efbË?¹¹õ66æßºUýêÕ¶¶æxwB!2¤gzzD߾݌Œø½{[†„Œ®¯oª«k`D„ëää¸ô½@ëêúúZTû¹sqNðߣGÏŸ>­OM=œœ<ßÍ­—‰‰î¸q΋û­_¿—šj¬\àädmcc4êñãÏŸ7RSÊŠâÇtåÊÙ³7[Zú¶ ¦¦!TWטœœ¿víŒQ£ú›™éš5Ë+&&›î›““µµµé®]E8YY…ŽúúZr¿~6FFü^½ºR!㎫W7qâSS½Y³¼‚‚¼âãÿ’ØgÏØc±µ¦¦æ¡ªê®¨èÚ»÷L33ýôô€,>K5IY’jSvRiU}¸!›Ž—/ßiiùËÂ|(b‘“ã2–”H( ¢"¡;lXoݱc‰ŠÄÑѪ[73*|aZÚJ$sæ$XYù¹¹…a‘<{Ö€“ãåÕÏÌL?$d4‹Hð"MT$’²±zõw>>.¦¦zøÓ'I$’b±µ†WRr£D"£Ï”H°Ï¢"ad‰‰$›kÖÌ4È®kWcJ$NNÖ]»³ˆDÒg‡@ „/1×3\¾œ(.¾_PðžÍ‹­V²¶6ÅÛ;tP˜›à·”•yª€ö»º:àÊfaŸ>6›6å54¼¦7ð÷¼áåË&.—“—÷kzz8 ¶ö€Ï×À}9䕟v÷î_ª«ŸÜ¿ÿäúõû¡P(KÍ4B$nhxMM#"&¢R$ ËË´¶ GŒ§l¶¶ ß½k®©©Ãÿvîlˆ3 ®ÞÐÒ"À-]\zº¸ôDUW?ݳçäÊ•&,?}:áúõûB!êÓ§•~ýlöãÅÅÔ©îññ¹?üøòeSAÁ…ÜÜe¤q/gg{*œØ/^Q6ËË«Øc9r$ÆÐP   ¯§§ÉãÉã–2ú,vÔ$e©²²†Ý¦ì ”šð¡’BÈç«·´ž=køê+m©:R"¡,´O$ø-*|l ‹ðàÁ±"¡FSF‘àõ»T‘0>}#EE졌>c‘Ô׿+F–(‘H²immŠUA‰·lŸH@ø2³f°°0TT<˜™éñE‹4ð .—ó×£õ/®Å/ÚtŠ_^^Žšà½0NŒïqâJ¯^]ñJWWCWW!„S>L)rs£»t1¢w72â߸qÀáüå4 B(&&ûýû–¥Ký°M33ý… '(**Ì™“ÐÐ𚚣02Àáü弯¯[TÔ¶ãÇË*+×ÒR>Ü ´J Ãá@j:(šX©±˜šê™›ÿ¥j{(£ÏbGrŒ‘%©6¥*BjZè{ár¹¢þH!D‰¤woK¼‹|øÙDB!»ûýû–e˦à-ffú x‹Š„1šRE‚/*–OŸ,"13Ó‡"ß2úÌ.F–¤Úär9tO ”xC‘ðe"ñ¾IÔkÑiË»Œcy@cã¼ýîÝG S,s²óçovíjŒ'%%¿YY™ª¨(Ñ;ª¨(Mœè’›{B^^Î××Ç“ࣛOŸ¾´°0œ={ãÌ™ßΟßúõזؽ•+³ÉzEE…Ñë×ïñöljªG_UW?ů»u3ƒ>|øÏÚBYYE?ýTŠ‹vÄf¦ºúÉÎE3fŒ ´”•yÊÊŠ66æAgƼ¥kWcuõW¯Þ0 ;@OOB˜ž^ ¡¡" *Y¿>ðæÍ[ÆtðÝ»æúú&>_ƒqT!´té”ë×ï;:Κ;wܰa½55U++k22~ÊÉ9Ñ»·¥††ŠŠŠ’¯¯kTÔ6 •¾}mJKo}ÿý¦qãœååÿwh–‘™ððI‡Ÿuvž³lÙTGG+¡PøóÏ—–.ݾx±'¯¯¯åç7,""U[[­G‹‚‚Òääü˜˜¢˜:õ›I“V½yó.==oa wŒˆHÕÔT±µíxðà™””ÃôyÀȈßÖX0²û,:j’,ëéiÊh“Ý7YÒhç®]«rpè*ª„÷ï[°HD¯{ù[Dˆ…E$ r²$ûO Þò/ˆDìÂRvŸé"a_ÊnS’º)©"!áËDüšÙÏ3èëkmß¾pÙ²¶¶Ó´[´È'$d#½££•‡‡ã”)k6„ÐßZ²dÊÒ¥ÛoÝzhaa˜™9~¼3ý]¼_‡.ݺ™))ñðO—ËùöÛ……BBFC--MÒÒÄÄìJK;¢££îåÕ¯¤$ÉÞ> ´ô–••)Ýí¢¢2/¯¨ªªlFá „PAAîÀU{ö§§¬[—ÓÔô‡¶¶š££UNÎÒ1cr¹@JJ˜‰IVddÚ£GÏuu5=—/÷gÉŒ‰‰î… )±±ÙÑÑ;jjê¸\Ž]§¤¤¹“& Å·ng`º©®®¡K㤤9¢pwwTSSîÞ½£¥¥ ÞÒµ«±¤µµÕK–ø-X°õþý'––&»v-½Ó¿,±ˆ=Š,£Ï¢£&)Km²XÀHM Õ!PTT:FtÊK‰D´ð†Ç“g ‡eI,æ$‘øø¸à–¢É™>}¸h6(‘Pšgù\ˆÉرƒùlk,ÔFY|†öêÕ‹ÄÆÆ°~çÈžv߀l"!áË":ù©ÝøèÃãäD§ï¢-‚Vsó ÑÑÓèS„›7«¾«ªÚm` %cá_CÒ¨}>_ñö^~÷n¶¤þZZX$dÿЙTžµIê„/öœgøGaTƒHš.44¼>uªüرóŸ¡ô–ÖÖ¦“'»nذgݺYÿ†Ç™aµÏ„кu9“Ȃᓀjl|C @ >>»5{Õ¦µUèë»Z[[m×®ÅJJ Œ•F\\“Ó¬3Fâ{@>ØGís!tüxÙ»wÍßÿíçæÛ„.|;T@ ŸœÏ®6‰@ „R›ÔnHmðå!æ9Ð@ @AÖ @  ²f @ l5@ @`ƒ¬@ ŸfÍpøðYgðýû[[…Û¶}þ¼!Dm”ÔK–6{÷žäpߺU-éyÀbinŒ®¨è“ý¡öX_ßdié[YY#»5I „Þ½kŽ‹ËíÙó;%%7UU÷B÷ï?M½[PPêì<[ hm‡e uÛ¶£ƒÍÖÔÁ㹚˜ŒŸ2eíµk÷Ú”:8Õ:CèÌá VPjjê__ßÄbS–1úç vÍâá't@ áÿ)Ÿ`Í@ŸÏ”Θ÷öí{€«k¯GöëJšð1ÂÀnYöûë#„JJ~;v¬4'g™‰‰ö›‚†…m=z@—.ûœ„ЫW 4;3³pñb¿[·2KK“û÷·7nY\\.Þ×7ß|­ªªœ°¿M}„^ó,^¼ÍË«ÿ¯¿n¾sgWzzÄë×oœf9ó[;– T—ÒÒäÚÚ¼GöÝ»·{ÇŽðŸ~º0eÊZ–ÜJ£„%!–'{ü›.@ ü7ÿL7„Б#ç¼¼¢ª«suÿÞ]ŠVB ´Y:J]Èø iÑ^oÞ¼88t¹zõ.ÝTyyUNΉr>þ‰ÅÂE‹’_¾|UV–ª¦¦Œ­­Yó]s³`ñâmÞÞƒñL7*Ê×ÃcÑÔ©ßhh¨ÈîÿÚµ;/\¨(+K57×ǽLLt‡ éáî¾0<<µ¤$±Þâ|¾º¾¾þ×ÐP'"brPІW¯þPSSÛ±}˶¿Y$DžÔF ÐÄŸgz´xddöè1]QѵS'ŸýûO=z¾{wÏÕÊÊïøñ2Ñ2üïï¿?£ìxzF"„LLÆCèL5Æ/23ÛÚNãñ\;uòÙ²åëùó·|õÕ·TPˆ:vœ¸|y†Ø0A늙ææx_cûöc¢þK²ÜÜ,HH8<ŠZ0P·cGø‘#kB¸xIløØìÎEööŠŠ®vvÅÅWÄNý!„JJ|:mš»Øð¿³g'dg%'Ï¿sgך5ßÅÄìZ±"P[›G¹A÷§µUxàÀé!CpBÁÁ’“óããƒ**2†ûûÇ”2ö"¶<!tíÚ½÷ï[úôéÆÈ'Ÿ¯Ñ·o79j/..=óòN‰ú/ÙrU}}“›[o†e¡¾¾–¦¦*„B()|ÌæÍyÉÉóËÊR;tPœ<™9vøEyyUllö!=ðI†9s6oÎÛ¸1ôöí¬ààÑ!!UUìcÄØck«!ÄnSv½üüÖœ>+ãâ‚úôé˜>}Äĉ+ž=«§lJª ÑÐP `oEEùNú 0г²ò÷¸¸ÜÀ@Oê]kkÓ¾}»efîÈÈøÉÍ­·±1¿ôÞ1±~ö¬!5õpQQ¼³³=Àؘ_[ûbÉ’í‘‘¾úúZ”t®_¿ÿêÕ¶¶æxÎúüyczúO©©a£GÌŸ?¾¹Y€Ð_Š $•Ç@ß45UØËœ „66·o?&´ÊÉqe±\W×Ð××¢,Ï›¸mÛQªMEE–œ‡?h„ÐÄD— ·Y¹2ÀÉÉ4ÊÏo u¸­í4l³¥E "W×^©©a€ººÆääü””°Q£ú‚ƒGݹS“2Zê•—ß»G!»MÙõ†2¤ç Avvv „FFüÑÞÞËq®@ mBÌšáòå4@qñÕÀÀø‚‚ðl^lµ’µµ)ÞÞ¡ƒ"ÀÜÜ¿¥¬ÌÐïÿÓŽšWW< †öéc³iS^CÃkzÿáÁÁ^¾lâr9yy¿¦§‡ÓßeLåËË«Z[…#F„S[[…ïÞ5×ÔÔ™›ë‹u ¶ö€Ï×À]®_¿ßÚ*tr²¦¼ŠŒœ$c,!uÀ‹¯,,Ø.§Fñùê--‚gÏ ud±¬©© hhxM©ˆˆ˜4 |D¡PX^þ@RøøßÎ ñ©«w´´ðö#Gb° òzzš<ž<• ¡õéÓÊF¿~¶ û©Å†eŒD÷XYYÃnSv½A‚‚¼òóÏîÞýKuõ“û÷Ÿ\¿~  ¥¦”@ À@ÌšOj+*ÌÌôŒø¢E/ø—Ëùkó|ãÔD›*CäåÿW®ƒ÷"'Ç¥7?ÞyÞ¼ÄÜÜ\.·CEOÏ~bw-àÉbnn4ãHFF|I` Ο1â/ ]×ÑBmmÍ••yçÎÝpt´¢[¨­}1iÒÊåËý °Åe.— àp ,^Cíí;«ª*Ÿ8q¥W¯®Ø‚®®†®®B"ø0Wþ÷ñîÄ. MMõÌÍ ;¥òIeƒ#ç/Õn,c$ºG©6¥êB huq™÷àÁ“ñã{ÌšeZSSçë»ZR @ ,|Ôõ ø]ÆÌþ®‚‚< ±ñ Þ~÷î#†)–9ñùó7©ž–”üfeeª¢¢D諸¢4q¢Kn{‹}}ݨCàbìÖÍ BøðáÓÎ -,Œ,,ŒÎ»¹lÙðñõ§O_â±…‹oS–ÇŽ]´A’ÿ ””x¾¾n[¶ljzKY@­_Ÿ[RrÝÐP‡š(?~üBAAŽ:¿!EE…Ñë×ï©®~ʈººú)~M…cïÜÙP4|Iלˆn„ÚØ˜s8ðܹÔ={]OOSKK•ÞLêÑËh“ÅÅÙ³7Μùmß¾qqAžv¯ªªK  @ Úø{­BGŽì+Kz—z͘±1¦¹¶¶ærrÜØØì•+**&%`˜Â÷á9þ&.m§ž¢¥¥fg×)?¿$%åpFFý]¼ß€€á}úq8œ Bèžœ9óÛƒO¨õô´zôèìëëµMCC¥o_›ÒÒ[ß¿iÜ8gyù¿œ» ûÓµ«±ºz‡«Wïöïo !40ÐöõuˆHÕÑQ·²29t¨äàÁ3GŽÄ0μ{×\_ßÄçkp¹F¢V­š~òäÕC—.Ú«W×—/_ýøã±Äı±3;uúŠJàµkU]'UØ-/]:åúõûŽŽ³æÎ7lXoMMÕÊÊšŒŒŸrrNôîm©¡¡¢¢¢$5|IK±Ûõõµüü†ED¤jk«õèaQPPšœœ3Cö1µ¬§§)£M©>ëéiBÓÓ 44T„Bá¡C%ë×çÞ¼y+¶=@ ñkvXÎB0¦túúZÛ·/\¶l‡­í´í-ò ÙHoàèhåáá8eÊZÀ† !ô·–,™²téö[·ZXffFŽïLï×Á¡K·nfJJ<|zwÆŒ8zK/¯~û÷¯LI 31ÉŠŒL{ôè¹®®F` çòåþ ÿéþܹ³ëÛo^ ƒCKNž¿|yúÌ™qOŸÖwéb´sçâaÃz3¦ïEEe^^QUUÙŒ’¡––jIIÒÚµ;ÃÃSª«Ÿ*(ÈõìÙ%/o¾¨#¢¢¢²ÐÐ1Œ¥»e¹VíÙSœž^°n]NSÓÚÚjŽŽV99KÇŒÈårbÃg;úv±çš¶ng`º©®®¡K㤤9²‘Ø=ÊhSªÏ­„n½ IDAT]»§¥-ˆ‰Ù•–vDGGÝË«_II’½}@ié-mm5±]@ ’€€N~j7þ½;«iëã¾ÖiŽ44…̳2+ÜkV\’ÌS3çÊ5F%W á."!cf2׬ÌÎzÿX¯}Ï=vGBêûyîó>§=¬ý[kïí]¿³ÖÞç_ìóÏÉåîçÞ2;;ÇÚºWP×€¿E$W®Ü«[÷·›77”+'öKa…xÄÄÄÔž=§Ý¸±>¯Mû¹|ësPpÔ  ˆR4@I£øy†Hd⓬ôô·Û·õ÷_ÄéÓ§õ·ø­.J©U¿~. lüå+<â¼y1}‹GÂðÎ|E.güZØ&'Gêî>kïÞ“ëÖMÒÒR/À»Œ”A) ñ‹?vãÆÃïÐåݳçäǙÆýR º×ßíÀ·Väæ&|˜›T`˜›Pò¹q(R3€ä 9ˆAÎb~LΰcÇQ‰Äùöírr¤‘‘;Ÿ?Ï`Œ óÚK™m6mJ”Hœ¯\¹ûE¯+ÍÌÌîÔ)@SÓ%8x=G8â«WoªVuOK{ |iyaŒmÚ”H©“܉sãÆ~+³uëQU«ºç^¾jU‚ŠJË›7}Q;ð¤Ê¶€òRœœ†ggçàE±ÙÙ9‘‘;[´®¯ßICÃÅʪGÿþsΟ¿õ¥åÈzö,}øð%+öÖÐp14tmÓfLBBJ¾± Xj‘×¾Ê_Û²W…ºzëòå{úúÎõêÍ·‹ùkÖ= EßÈd{6 )†|øð‰ââRïáÃÍ––&yu}òý¹7e~ÛAá^ÉÉvíJ‰‰™jeeÊãáEQJÇŒYÞµkóÊ•-”,M‰RzøðâGâ„ÿ>Ü\€cÌǧcZÚƒcÇ.É-ŽÞݺuÝŠË~ѯ"PJ…3ò¥ñ´oßPGG{É’-_ú; Ÿ>euê0iR¤›[³Ã‡_¿¾.**ðíÛ NJ:ÿEE ²²²[·}æLZTTàÍ›ëÖ¨aÝ©SàæÍ‡DêU°ë'ß}•ù™BáÚHI ãWÅ­[V­ ؽûDÿþs¾QÌ_‰RúE÷,ü¼T.eŒÅÇss›x÷n¬¥¥IáRaŠRª©©^¶¬¡ÈŽùväJV²¿B)}÷î#!¤nÝÊ©©7d‹:wîfLÌ;wb”/M„¿‘‘®xM•D)íÚµ¹¡a™uëö5jTGÈ»yóQRÒ…˜˜)èøÊž‘/ÝwâD÷Æ{z¶Ó××Q~¯9sÖž8qõÔ©ˆŠËò…VV&Îε:tqäÈ’D’œ|ñÂ…[gÏF:8T"„XXÿñÇ“'¯.]ºµ{w§¼v,Øõ“ï¾JþL!ÿ`lüïµaaaØÏÏoÁ›7tt´ ñš/,_tÏÀÏKñ8C¾ßŒòùÑÑ{j× ©éR©RŸ-[’vî<^³¦·††‹ÇÞ½§rOKàÞ¿ÿT(ÇÕucÌʪ¥NÂÆüÃêÕ{íí½44\*Uê³lÙ_rQ½¬\¹_²³søŸR)«X±÷´iÑ «ÀegçLŸ¾ÚÚº—††‹­mßùó7J¥Œ1F©SçÎ< Ùxc njß¾‘‘./-¯d"2#ßVݾý¨Dâ¼bE<ï»­*]ºÝÅ‹·6/ASSÝãmlìÁÌÌlaldõê=&&znnÍcyÅÌËÌÌ ZÅgïØÙyDGï‘;#|÷™3×T¨Ð“oñÿØxH“&Eêéu40èÌ+Û°¡±±ÞÊ•»”lÆXVVÎ’%[‡ é"$ B[­Z?G¼åy±k×î«UËGSÓÅÁÁçàÁ³„mBHlìÌÌl¡Ì¤¤%‡-âÇÍ«^ÂÆƒͯQÃSˆóÓ§,##×¹s70Æ22Þ±¤R¥>.::í‡:tNØwÏž“>šš.U«º‡†nË}ÞÖE®Y„ZZÂ’|c3f9¿)ørá¦PØJ|ñó«ü žW³ä¾Èàg¤8gÿfTX;oÞ†… ‡ž;÷§••‰—WpPЪððÑçέ´°0öð˜%Û’ëÜV¯ž@)=}zÅ£Gqr«FŽ\:ztÏk×ÖŒÓsäȥ˗ÿ%[‚·w‡Ç_îÙs’—|ðàÙ{÷žxyµWXþçðáKÖ¯ß6úúõu³gÿ¼núô(BÈ£GqB²ñääH·nMjÙ²®ðý½ÂrODÉkÂF¾ß7»º6ñõu;vùýûÏ>?sæšE‹†U¯^Aaƒ„…mçu÷öîðâÅë]»Žó2sr¤ÑÑ{<=Û©©©BòŠ™R:dÈ‚°°íóçû]½ºÚǧ£·÷ÜÝ»OÈ‘#–,^·páÐk×Ö ÒÕßáÒ¥[…€S““Cwî ®PÁŒ—ÙªU¸¸CJ¶ ¥ôüù›¯^½iÓ¦~îËÃÌÌ€Wˆœ;nñ⸰°Ñ§NE”*¥Ù¯ß,©”Õ©cëãÓ!8x}ٲݺwŸºxñ–k×îËW¼^„/¯ö—/ß=}:oìõë÷m!³SW¯žpóæúPJ»u›œ•õÿô500"  ïµkk‡ÿuԨХK·ÊUM¼.µÁ;þÖܹë[¶¬­«[J™˜…›‚Ÿ ¹›"w+å{~•¿Áómø©)˜›¤£Óž’“#%„ØÙyðÌë×»„Ž ðaö쎎5 !ƒ¹öé3#$įqãê„:õî=ýéÓWB™yM™ÐÓ+M16Ö533[5q¢»§g;Bˆ¯¯kZÚýX__Wamµjå›4©¾zõžŽB¢£w·iSßÒÒ8%EÁcOŸ¦GDìØ·o¾“S-Bˆ¥¥ñ£G/&O^9a‚»™™†l</Þ~ýú½½½5ï󉔠®þŸfÌk†RýúƒädÅŠ±={:BBBüS ø=-í~ïÞ­||:È6Hÿþm)¥ƒ»ñ<Ø7EÓ¦5Ö®Ý×¥K3BÈþýgÆÍ­)¥Ôß¿ëõ낃×ûûwå!M˜à.¤4¼kÔ¨¸r宬¬l5µüÛ„1öìY:!ÄÌÌ@è(¹SØæêÕ5ªª*yÕ‚o3c†OÆv„?¿.³Ÿ?Ï05Õ_±bl¯^­6m:ø÷ß§ãâBZ·®ûçŸãÍÍò­!¤Q£jÕª•_·n_:¶„5kötèÐÐÌÌ€1Ò²e-*QJ-,Œýý»öì9W„2kÖo}ú´"Ÿ¯Ûùóc‡ é"+rFøöö^¼)²²²¥RæâR/"b cL™˜…›¢C‡†Dæ¦8wî†ÂV¢”Š—9{öÀ-ˆÌ Þ¨Q5¢èš¥V-Bˆ¹¹‘\³ÀOMAÎpæÌ BÈÁƒ©¾¾ó~ç½y…ójªU+Ï——*¥I±¶.ËWikkB„‰C¤@Óš]\êòùÙ”ÒÆk,Z—žþVvoïŽC†,xùòŠŠ$.îpTT€ìZٹݔÒsçnæäH;u æäH?~Ì|ðà™µµ™Â=zA16Öžm)A™yäB#ÄÅÍ›Š#tšµ´Ô×®Ô Á r化-)Ûn..ÿŽxðyõê¾¾¥Ôǧ£¯ïü—/ßèDGïnÕªŽ¹xÌwï>ÎÉ‘ OAB&LèËŸcŽxñâm©”5n\]8nÓ¦öK–lÞªdkk.×ÎÆÆºYYÙOŸ¦—+g˜o›PJùHBzú[á\öóóëB>_R©ôܹ;yÕ‚ÿiccÎWéê–"„deeóÒZµªÓªUBÈ;7nLœ1#ºW¯iIIKò­çéÙ~þüØß÷}ùòMBÂ‰ØØ©”RJ‰ŸŸÛöíG7lØ÷îãÛ·_¼x›"•Jù^NNµä®Û/^ eŠœþg||°¹¹!D]]ÍÔT_SSG¨dÌü¦xõêmî›"w+¥¥=/³Zµòü np¾eî<ßf€Ÿš‚œÁÖÖ‚rõê=BH… fƹ§šð**’ÿN5Éó1Ÿ¿:ý‚‰ jjªBW†EUUEvƒ=œFZ{@EE¥T)MWצ ÍKà}—ØØ ¹7 YXç/A"ùEJPþakþÁÊÊDèÀåÞæôék‰äŸ^¤¦ÞhÞ¼¦°JMMUèŒ Â?tïî4räÒØØƒ½{·Üº5)**0ߘoÝz$4Nî$NèðÉW"ùÿ”6UU¹vVQQ!„H$TÉ$ªV-íÎÖ¯_•/41Ñ31Ñ#Ÿ¯@ñZ\ºt›Nö:dŒÍ»áÓ§¬©Sûó%*˜ÛSSS}Ĉ%ééoó­çîÞfâÄȽ{O¥¥Ý70Ð騱 U«Qwî<îÑÃÉÉ©öàÁåKØK¨»Âë6ߺ”/oÊ'zÉ®¥”*³ÈM‘»•ò-SEE" ¥y&ÿù6 üÔ¾êy¾V®×(»V]]’‘ñŽ/¿qã¡\Q"=ËãÇ/³Ïõ&'_°³+_º´–쎥KkõîÝ*6öÀ¦MÝÝÛhh¨) áW¯^RzïÞs[[ [[‹cÇ.OºJ$þuï“'/yEJPr%ßç!×®Ý5*4(È«GgÙü x¡A„ΨР<6mm¾}[ÇÄì߸1±Lm>ÝH ‰ùçŸr ®­­¡­­©L½!&&z:5Ž=°aÃ~¶¼ëôè¥#G.lÞ<=$ÄÏ××ÕѱæÍ›!BuOœ¸*\·GŽœ·µµàßëQ]äŠ1¦dÌ¥JiÊÞr³æäZIÉó+r¿ „f™7o°¯¯k‹rÍ?5ÅïZ¥”vîÜD*=˜×Zá³\×P®?aoo­ªª2wîú3|®^½úŸG6 !üµ0Ç_æó¤e„”qp¨´}{rxøŽèè@Ùµü¸>>7ö“H$ øËFräÈÙ>¨©©AíÚ6îî.'Fêé•nÒ¤FJÊ•aÃuïîÄVO•*–ºº¥RSo4kfO)µ´4É«¹ùô)ëÕ«7ÆÆzr#ÂfÏŸgÈvg… ³³súõ›Y£†õ¸q½ÒÓßÚÛ{ùû/\³fb^ ";>àãÓ±~ýAoß~ðôl'ôEb633pww Œ02Òµ³³úë¯ämÛŽÄÇóçx XX{x´ Œ04,S»¶mBBJXØöàà +EþÿØîͺu«È}?-Þ&S¦ô¿xñvƃGŽìÞ¶m}}}´´ÑÑ»cbÔ¯_UO¯téÒZùž;¹ë0  ïŽGœFLêÙ°¡T*ýûïÓS¦¬œ4ÉC]]ÕÔT_Ézyz¶ëÛwæ»w£¢þ?›ÈÔTŸR• §WZ*•þõWòÄBÞ½ûÀw ŒÐ×/mo_qÛ¶#áá;¢¢þsÝZX+S—Üã ÊÇ,{SÈ•#×JÊ—™W ²E‰7 üÔç âD¾/—ëR˜™¬\9nêÔUöö^ŽŽãÇ÷ñ÷_(»AÆv:4ìß!dÁÙU“'÷Ÿ2eå•+÷lmÍW¯žÐ£‡“ìZ~ܺu+W¯^AKKƒ}+¬80DvK7·¦[¶Ìceµf„>71Ñóõu6Í[.~Ùx®__÷Ë/Ž{öœ:´¯š2%PJ÷í;åæ6ñæÍõr“Lxã0ƇånÕׯwÍšµæÒ¥;gάPUU12Ò ݵ뤶mðç’å„?3-¨]Û¶NʧO§ÅÆN:â1‡…ž6-jР'O^U®l±ví¤¶më¿{÷Q¶–/U¶lôС‹ž=K¯\Ù24tÄ€åθÌT²oß©¡C»)ß&„ µ­[gnÜx0**aÞ¼˜7oÞ–iØÐ.&fJ·nŽ %„(¬EîëA`eerâDøÜ¹ëƒ‚V=xðLEEâàP)4tdŸ>­ø–ÊÔ‹Ò¾}Ã2e´kÖ¬hgWž/¯ZÕjÅŠ±ÁÁëV¬ˆ72ÒuskšœZ«–OJÊCÃ2„É“=ÆŽ]~ûöãªU­Ö­›ôë¯-äNô—ÖEX¨ä¹¨W¯ ¿)jÔ°&ùn)Ùâ±BªT±oø©QFa‰?:Œ±Ï?'wóæzkë²â[fgçX[÷ ò’ëèV$W®Ü«[÷·›77”+W?ÁV`;vÍ«Ã]¤>ÓÒ?~Y®Ù££w·n]·R¥r_¡p1|Q<”Òvíèèh/Y²åK“ ž+NšéæÖìðáÅׯ¯‹Š |ûöC£Fƒ¹P°T*;;§uëÑgΤEEÞ¼¹>1qaÖ:nÚ”(^ ÙB¾è "û*ùk'üCJJØ£Gqn¾ukêU»wŸèߎȹø¿Âþ¹È·^ðõT.eŒÅÇss›x÷n¬¥¥IáRaWƒRª©©^¶¬¡ÈŽùv€äJV²ëI)}÷î#!¤nÝÊ©©7d‹:wîfLÌ;wb”/Mä(ãLJ½|ùúÔ©ˆ2e´yi³gÿ–™™=iRdϞ΅ÞÎrG猌tÍÌ ¾þg×c]»674,³nݾƫ ËoÜx˜”t!&fÊ—¶¥T8¿ØwâD÷Æ{z¶ÓÓ+­üyŸ3gí‰WOа¶6ã{YY™´lY»}ûqÉÉK•A(39ùâ… ·Îž¬Y³"¥ÔÂÂxþ|¿“'¯.]ºõ×_[(ÓÁýÒ³#²¯2w„°ÐØøßkÃÜÜ(0°ŸŸß‚ׯߗ)£]è1%eþ¹Ào "Åã ù~ƒÈý££÷Ô®=@SÓ¥R¥>[¶$íÜy¼fMo ;;½{O垺Àÿ¼ÿ©PŽ«ëƘ•UJ„ù‡Õ«÷ÚÛ{ih¸TªÔgÙ²¿ä¢=zY¹r¿ÓQ¤RV±bïiÓ¢VËÎΙ>}µµu/ [Û¾óço”JcŒR§Îy²ñ0Æ.ÜÔ¾}##]^ZffvPÐ*>çÄÎÎ#:zO^-“{ÊÄ›7÷øûwd@@ŸššˆOQ¼òGïÞ1ƶo?*‘8¯XÏ—­*]ºÝÅ‹·EÎ…††š‡GÛØØƒŸ>e å¬^½ÇÄDÏÍ­Y^ ηÌÝ’Œ17·‰¼ñUTZò*Ïœ¹¦B…ž|›ˆˆxÙ:Nš©§×ÑÀ 3¿º5ªfl¬·rå®ÜµË«M23³—,Ù:dH!aj±jU@|üÆX^-/\Ûk×î«UËGSÓÅÁÁçàÁ³Œ1mBHl쬬a´*)iÉ¡C‹øQÖK6€CjÔð¢ýô)ËÈÈuîÜ Œ±ŒŒw#F,©T©††‹ŽN{GÇa‡vܳçdÍšÞšš.U«º‡†nãñËV9¯ºä¾6(¥ZZ¼5ò:ÊÜ [IFäü*ÿoK^Í‚q€B¤8gÈ·‹É?Ì›·aá¡çÎýieeâå´*<|ô¹s+-,Œ==ŠòèQœ†l<99Ò­[“Z¶¬Ë[€16dÈ‚°°íóçû]½ºÚǧ£·÷\¹yêyM™`Œ?ëÓ§¬Æ«Ëµ§±±^“&ÕÕÕUÅ'( >wóš°!žRJ;wnìëë:vìò{÷ž:tnæÌ5‹ «^½B^ç‚ïåíÝáŋ׻vçgA*eÑÑ{<=Ûñêä³Â–ܽûDtt oü‡7BFŒX²xqÜÂ…C¯][3dHWÿ…²³S““Cwî ¶¶.Ë+ÕªU¸¸CJ¶ cìüù›¯^½iÓ¦~î¶233Ð×ס”æU aãÅ‹ãÂÂFŸ:Qª”f¿~³¤RV§Ž­O‡ààõeËvëÑ#hñâ-׮ݗB¯!ÄË«ýåËwÏœ¹ÎÛ*>þØë×ï=<ÚB<ü×Q£BCC·ÉhñºÈ^çÎÝœ;w}Ë–µù C¾1‹ßr­”“#Í·”ÿ·%ßf€¯§`n’ŽN{BHNŽ”bgçÁ{T¯_ï’ý’˜={ £cMBÈ A®}úÌ ñãÓT èÔ»÷ô§O_ eæÕ!ÖÓ+M>OŠ[5q¢»§g;Bˆ¯¯kZÚýX__Wamµjå›4©¾zõžŽB¢£w·iSßÒÒ8ås^®ƒøôizDÄŽ}ûæ;9Õ"„XZ?zôbòä•&¸›™aÈÆsñâíׯßÛÛ[ó~ÌóçQQ»#"ÆtíÚœ2ztÌÌlÆþ3å#¯)”ÒŒŒw„}ýÒ˜æôäÉ+|‹”R++!x55•|Ndú‚õë’;úŠc{õjI) ñKLL0à÷´´û½{·òöþ7Sx.(¥Õ«WhÚ´ÆÚµûx›ìßúÁƒg>>e{–N133ÎÈÈ‘K##w Û\½ºFUU%¯ZðmfÌðiÔ¨!Äϯ‹‡ÇìçÏ3LLô""ÆôêÕjÓ¦ƒÿ}zóæC„—zþ9ÞÜÜ(ßzB5ªV­ZùuëöÕ­[™²fÍžš™0FZ¶¬Ó¢…C­Z6„ss#ÿ®={Nã!„Ìšõ[ïÞ-)¥ƒ»¥¥ÝŸ??vÈ.B±"g„o`oïÅÛ!++[*e..õ""ÆB”‰9¯ûñܹ [‰R*^¦òÿ¶ÍâàP‰O“køz r†3gVBLõõŸð;ïÍ+ü¢Zè´•*¥I±¶.ËWikkBdßcS€y..uygŽRÚ¸qE‹âÒÓßÊnàíÝqÈ/_¾QQ‘ÄÅŽŠ ]+ו?wîfNŽ´S§aaNŽôãÇÌžY[›) àÑ£„cc=¾ËÅ‹·sr¤U¢š0¡¯’uaŒéB^¼xmkûeS3ÆD‚¯X±¬2…;ÆÅÍÛEè4kkk¬];©AƒAåÊ-[6RöŒ+<¼‹ïãÓÑ×wþ‹¯ t¢£w·jU‡?ý,óÝ»¶äŽG…#^¼x[*eW¶iÚÔ~É’-Â+­lmÍå®Iccݬ¬ì§OÓÍÍ”iU}}BHzú[a)0°ŸŸ_òùâ—J¥çÎÝÉ«üOs~mëê–"„deeó-[µªÓªUÆØÝ»O6nLœ1#ºW¯iIIKò­çéÙ~þüØß÷}ùòMBÂ‰ØØ©„J‰ŸŸÛöíG7lØ÷îãÛ·_¼x›"•Jù^NNµ„ºðÓôâÅk¡L‘3ÂÿŒæM§®®fjª¯¡¡&\ùÊÄ,r?æn¥´´âe*ÿoK¾Í_OAÎÀ;µW¯Þ#„T¨`faaœ×DÉg1åùæçï/¿`¶€ššªÐâGQUU‘Ý G§Q£–ÆÆPQQ)UJÓÕµ©ÂCóx"66Hî HÆyÀKHþ_G>ðBò_‡¾3 IDAT3A)µ··ÖÖÖ8vìRÆv²%>ë×ôöíOÏvÂó"1çÕ’jjªBã[X{x´ Œ04,S»¶mBBJXØöààr×€l+?³nÝ*rƒQâm2eJÿ‹o7l8xäÈîmÛÖ×××IK{½;&æ@ýúUõôJ—.­•ïe#wÍôݱ㨓ӈ©S=6´“J¥ÿ}zÊ”•“&yhh¨™™(S/Bˆ§g»¾}g¾{÷1**€/15Õ§”FE%èé•–J¥ý•üDZ„wï>ð#ôõKÛÛWܶíHxøŽ¨¨ÿÜ2y‘ºpÊÇœ×ý˜»dSS}%ËM™f€¯§8g'2 !÷óff+WŽ›:u•½½—££Ãøñ}üýÊnа¡]‡ û÷ŸCY°À_vÕäÉý§LYyåÊ=[[óÕ«'ôèá$»–·nÝÊÕ«WÐÒÒàß¡ k ‘ÝÒÍ­é–-3ÂÃÇXY­™0aÅÇÏMLô|}]§Mó–‹_6žë××ýò‹ãž='†íÆ«6zÚ´¨AƒBže…„ÄL˜Ð·ˆ$ DésñÃQJçÍ‹ ì‹„áGù÷#ü@™›ôM‰?~-l““#uwŸehXfݺIZZêߨ“M) ñkÔhðÀmlÌ¿iW^CCíØ±eÚÚE$a Ê‹¢`Ïž“?fö‹’o‘‚ÂõÝîGøQŠÜÜ$€ïs“ s“Jž"77 Šä 9ˆAÎb3€ä 9ˆAÎb3€ä †âÇß „bøÿÀ¡MPÒ¨â¶ô@æ&!ŒJtPD!g1È€‚¡Èrø i(‚œd m€\3€ä ð_j€ÿBι mÈ@ rPC ðrÈÒ „ g1H9ˆC΢0ÔPâ!g€ü m(Ù3€6”`È@ rP†J*ä  4¤ %rƒœ¾†Jä ð…6”0ÈàË!m(I3€ä P j(13@A!m(3€ä ð0ÔP g€¯ƒ´ ¸CÎ_ i@±†œÄ g€Â€¡€â 9¤ År(_ŒÒ{{_¯Øå ˜›b3ªâ5È@3`b€8ä 9@¡*v¿ùƒœJ<á]™ rƒœà 0Æ>~Ì ‰­Sç7-­6::í›7ºeKR¡”œ“#ŒÜùüyÆ×—ÆíØqT"q¾ÿ©’?ÉÅ·§ÔIøOCÃ¥B…ž£F…¾}û1Æ7¸}ûŸ‚ųiS¢\ùü¿Æýd ÿ? ¦ð$Úq‹Ý{“ð;ÐPâ)ýÞ$ÆØë×ïÛ´óáç  ¯:ulß¿ÿ´fÍžîݧÎ;h̘ž_¥4!áøÀ!mÛÖgŒÑ¯ž/ÛV¦4aû””0KKcþùãÇÌãÇ/±ôÉ“Wk×Ntq©÷ðáfcc½D(”øðbsÙUêêj²~}ÝÅed¼Ëë$ŽÝã[ýg„œ OŒ±ììœ-[’–.Ý’”´„R:~|ØË—¯OŠ(SF›w.gÏþ-33{ҤȞ=--M¾æXB¯ºPº­²…(ÓÅ606Ö533þ´¶.›žþvèÐEË—ÒÑÑ*[Öð+ã12úOù¹JÊ$+++›ŸÄÇB„“¨«[Šo0gÎ@á$ZX;:ó÷ïÖ­[sUU¹fV©©• Ž4æ&(öìYúìÙë*Uêãï¿°I“Œ±7oÞGGïñ÷ï&$ „Ji@@ŸššÈMnÉÎΙ>}µµu/ [Û¾óço”Jclûö£‰óŠñ}H$†œiPÐ* ‹_55]š5óŸ3g]îùQ¹S%›Ž7:zOíÚ45]*Uê³eKÒÎÇkÖôÖÐp±³óØ»÷”PcìÙ³ôY³Ö '‘òöí~…„o)œDBH“&5üýVªÔgΜõ²SÅ(¥ÂªÙ³×=ž¡x:S±©@Î%^®÷&¥¦Þ0à÷òå{nÛ–äuïÞÆàà„óço}ú”Õ¸qu¹.¯±±^“&ÕÕÕUåºÚÇ/Y¿~_XØèë××Ížý[pðºéÓ£(¥®®M|}]ÇŽ]~ÿþ³Ã‡ÏÏœ¹fÑ¢aÕ«WX½z¥ôôéÅBî.”¿xq\XØèS§"J•Òì×oVNŽ”ñÏ?w…‡¹reuÇŽ'MZÉ7¾~ý¡§çœîÝ®__·yóô¿ÿ>!W ¹àù‡ììœÄÄÔ3¢]\êÉv²Eb ݶdÉð«W×tïîErÉÝÕ– F¼îóæmX¸pè¹sZY™xy­ }îÜJ cY<»HM½ñÛoódOâܹƒ(¥ÂI”ËadObpðÀ{÷6ymÝzØÊªÇ€¿§¦ÞàÛÏ;HvÕo¿ÍKM½‘»‚ÅL RPR:¿U¨`¶woHÓ¦5dû²ï!úú¥ó<Ã{ú4="bǾ}óœjB,-=z1yòÊ ÜÕÔTBBüS ø=-í~ïÞ­||:BôôJ“ÏSƒ„Ý[´p ”ZY™»óC̘áÓ¨Q5BˆŸ_ÙÏŸg¨ªªDFî íêÚ„2|ø/7nxðÌÚÚLKK}íÚI  *WÎhÙ²‘¹¿wÙÿiccÎ÷â_ÿgee_¾|';;§Q£j< ”6mjÏs†&Mjüúk‹AƒæOœÙºu]Wצ¿üâ˜×8C||°¹¹QvvÎþýg#Ú´©:RKK=w5sÇpõê½ÌÌì¦Mk14oî —3ÄÅͨX±¬ì33ƒ/ª{µjåùqK•Ò$„X[—å[jkkB²³sH®“hd¤ËãN¢M>‰ß³gé‘‘;ögffM™â!¤XŒ±çÏ3dWÉï‰÷&7¹Þ›4uªg@@ߘ˜K–l™1cuïÞ­† éZ»¶½½µ¶¶Æ±c—6´“ín>zô¢oßÓ¦y7on/t+¥R)!$66¨råÿ$Æ|›Ó§¯I$’þy‘šz£yóšr1ˆì~éÒmBˆDB>åÌbžÓUQ‘lÜtùòÝ]»ŽïßÚÃcöŸîÚ³gžÂq†òåM­­ËBªVµª\Ù²S§€OŸ²ââ¦çn¹Ü1ðþºl ¹Ó!++“ÜI—ìfùÖ]EE"{\Jå';QJƒ‚¼ÄO"šŽþÏ?/…“xæÌõÐЭ11ììÊO›æÕ»w+aâÙéÓir«44þóÒ§b Ï3È£”jjª{z¶;u*Ý{ëÖ$þÄvî¶’‹ÁÁ¡’ššê±c—rÇ ·Wî6ÿšºó1¹òùI<}:B8‰|!?‰¯_¿—Ý]8‰„F¿~ýn÷îy§N…{z¶ÓÐPR aÕéÓ|UîÚ?gÈ¥´E ‡-îÜyÌ»¡3gHLLut:eŠg½zU^¾|ý矻–.Ý:wî J•ÊÉîkiiâîî2qb¤ž^é&Mj¤¤\6lQ÷îNjj*YY9ýúͬQÃzܸ^ééoíí½üý®Y3QKKƒrüøåFªYXçµ»lx²GÔ×/=bį'F”iÔ¨ZBB Ÿ˜D)]Z+2r§TÊFê‘••ý×_GªVµÒ××Q8Î [2¥tìØ^»v?>¼cÇÆ ›HöOCÃ2ƒ»Nœ¸ÂÈH·V-›„„”e˶ÉmöüyÆãÇ/åÊá/,â P÷Üã ²¶háàèXóîÝ'|¹ÈI䓦®__W¡‚™ÂÊ^¿¾®|yÓ|^Ki1›ž„œJ<ê”ïϺ =HääÐ9sÖ„ß½ûD]]µNÊqqÓù#¿²cáác¬¬ÖL˜°âáÃç&&z¾¾®Ó¦yB¦LYyéÒ3gV¨ªª醅îÚuRÛ¶ ºvmÞ¡CÃþýçB®__—×;èìÙuuK»üéÓW ØyŽN©]ÛfíÚI³g¯upðÑÖÖhÙ²N||°D"öÞ$áOÉÊ•ãj×0dÈo﹫)·dÞ¼Á::ÚC†,xþ<£nÝ*ãÇ÷™1cµì÷ñŽŽÃäv¡”fdì”]ò¥uÏBä~ZC8‰††ežÄ.]šñ½& œÈªbŒ~‡Ÿæ(Ò(Uþ§ !_ûöªQÚÿôclÙ²¿ÆËÈØ¥¢RbfÅS§b6ÎPbÎ|{Œ±Í›õé3ãäÉ«wî<Þ¶íȬYk<<Ú– „Ã÷&aœàРXIO;n\ØöíÉ/_¾±°0vwo3aB?¹¼+îZüè rä P¸Š[ÎP’‰¾ƒb7¢‚÷&•ÅîÚ(Lx oÈJük uúÑi˜›P¨ŠÝÃÈ ÄÃP<€(ÌM€bh÷î n:qâê›7ïõõu6´3¦—£cͯyÍc,<|ÇŸîºrånff¶¥¥±«kÓI“< t”ÙWE¥%!$%eyýúU vt‘”/ŸÊLÀPWWÓ×/ݾ}Ã… ‡êê–Ê7¾ï‰aõêUù±/LT&Ù6©W¯ŠŠJKÙ÷jh¨™štìØhÖ¬úú:J– ÅŸpƒ)–(^òùnn,Q¸¤AÎÅÍ´iÑÓ¦EBjÕ²15Õ?þÖÎÇwï>3µ[·æë2ÆfÎ\3uê*Iƒvúú¥Ïœ¹¾páæ¤¤óG†ª©åóo)¥ÿ¾Øš1V€ÄKP²|aU‹ºº¥22Þ=z):zÏ«Wo¶n)•l±?¶KÍëÒ¥!D__G$Ù6á{Bœœjéé•&„|øð)9ùbXØöû÷Ÿnß>›¢L™PüåmÀ¹%r?oœ»sŒ%År(Vöï?3mZ”††ÚÖ­3Ûµk@ùô)ËÓsNlìÁQ£B»vmNH»ìK–l!„lÞ<ÝÕµ !äÝ» >}:-)邳s­oÝá/AÉò…nôï¿ûÖ«W…²cÇ17· ý•üäÉ+SS}%»àK{ ¥tëÖ™ùn&$ÿüûï¾|†1vìØå¦M‡ÄÇû矗eË(S&@‰…ç XY¼8Ž2lØ/dRÒygç¥JµÓÕíØ¡ÃøÓ§Ó„Þ0¥N”:­_¿¿yó¡ZZmªUë¿cÇQÆcL*•BÖ¬Ùsöì ÆH©Rš»vÍMIYîàP‰÷GcçÎÝìÔ) L™ÚÚm›5óßµ+…—Ì;Üüs‡ã%çÀÀ~D©”UªÔG"qÞº5‰1–“#6-ºR¥>jj­J•j× ïîÝ'dK8þV³fþZZm*Wî·rå®Üå3ÆrW‹w£y´üC›6õø‡'O^ñ幫{ß.]&I$Î#G.åÍÊÊ61é"‘8ÿý÷iÆX^mÈË)_"q–Hœ×­ûÛÑq˜–V›š5½Ïž½¼¾\¹_J•jçæ6ñÙ³t~D¾åÉ“W•i1¡|¡}øÚZµlxž?Ï „È–É?ËUA(':zO•*îZZm‡mذŸ×·0/b€¢9+G^$„´lYGv^б±^»v LMõ !IIZ·}øðùÚµmjÕ²Ù»÷d‹Ã.^¼Íû”¼éç÷‡D"12Ò½zõ^ß¾3ß¿ÿDñ÷ïJ‰‹;\·îoff]»u›œR¥Š•¡aò9ahÒdÈ®])+–­_¿êÑ£—:wܰá€lÉ„Aƒ\ !kÖìÍÎÎaŒ%&¦Þ¾ýO¹r†:5&„,^7mZÔóçmÛÖ·²29uêZ·n“32Þ %øúÎÏɑ֬Yéúõü¾ví>¹òVðÂ…[$WjÁÛ»÷!D"¡ææFŒ±ÔÔ¹«°~ý~¹}}|:BbcJ¥Œ²ÿ™çÏ3Ê—7mÙ²ùœänC%Ë÷õ¯ªª¢«[êâÅÛ-[Žœ1cuõê¤RéŽGƒ‚¢xá²É@¾-Æ7“ý,•²ôô·óæÅBʔѶµ5'2I…ðY® ïÞ}dŒmÚtÈÓsNZÚýZµl>|øäëû‡lÉÅr(VÒÓßBtuKñnÜàÁH$Îü›`‰ÄùÔ©kAA«²²²##Ç&%-IL\¸råø÷ï?Íž½V¶3:b቉ ÷í›Oyûöí[!S¦x.]:¢jU+BȳgéÛ¶<øjÕ<„îøøñá>|êß¿íÙ³‘‰‰ .Ê=:4'GJdº¤;6²´4yôèž}§!ÑÑ» !>>UUU!õêU ´oßü;æ>¼˜1öáç;w % öËÑ£¡Ç/2¤ ¥táÂÍrÝh¡‚GŠs IDATŽ,=th‘PAÙÔbܸ°nÝ&;;èÞ}*!ä—_ZðÌG¨BjêÊC‡ UàéÐ9îС¡¹¹ÑãÇ/8CÙ´)‘Ò¿[‰$Ÿ6T¦üqãzïßÿGxøÆXzúÛØØ©{÷†Œ×›’šzC.AR¦Åøfüsƒ¾‰³ŠŠ³¾~§iÓ¢ÔÔT/®©©Nþ›TðÏBcoÞ¼çU˜??–RÊωa}ú´’= @q…œŠ##]BÈÓ§ÿŸÄR³f%7·¦üñVÞ±;qâ cÌÛ{.Ÿâé9‡1vøðyÙÎhË–u !66æ|á§OY„‰„úù¹]¾}ãÆúU«¼¼Ú—*¥ùèÑ ÿE|³¤¤ó„¶¼/¯v„'O^]¿þ€ÈtIUT$t$„¬^½çÍ›qq‡$êíÝoЬ™}Íšׯßçè8ÌÚº_˜™™%”Ð¥K3þá—_ZB._¾#×>qâ !ÄÛ{.Ï”<=çB>/›Z$&¦nÛväèÑKFFº¾¾®+WŽãk…*ðͼ¼Ú1Æ?~É« tŽUT$^^í !1123³·nM¢”zx´Ë· •)ßÙ¹6!¤lYC^N«Vu!¦¦„Ì̬Üã ù¶ߌvrªåäTK]]RZ£†õåËÑîî.¹Ë䟅*ð xxŠØ­›#_Ø£‡3Æ $À3ÐP¬4o^sóæC»w§ð'•v<Ø}~í&!D*e”RGÇšü ›œšš*ýüL!DKK¢¢"ž´mÛ^ß 5õ:!ÄÌÌàó¼;BÈš5{ù¾QQ»)¥ææF¶¶Dæ;oJiÙ²†]º4ûðáÓ”)B~û­³PfdäNBHP—¿W!Þ)åŸ7lø›ض-‰âà`#¹PÁ-[flÙ2C¨ \r÷t)¥BøfQQ» !åÊò*È~_¡‚YëÖu32ÞJéß¿äÕ†„åËW¸»Â…ù¶˜ìŽüCãÆÕ#"ÆB¶nMÊ=¹K6¹¶%„ÔªeCÙ²å0_¸nÝ>Œ3@I€q(Vš7¯9mš×Ô©«ºwŸZ³fEssãóço>xðŒR¶¬¡©©Á„ ý:wœ0aE\Ü!]ÝR‡ËÉ‘._>JîÛz¹ï³+V,;lX·… 7²|ù6KK“[·]¾|—R:c†ßlÖ¬ÎÎ#¢¢vŸ9“¦§W:)é‚DB,ðWQ‘ä.yÐ ×¾zõÆÒÒ¤C‡†ÂÑ­¬L¯^½çé9§vmÛ¤¤ó åì ;ÆÆ<}:MKKãØ±K„Ñ£{ÊEžWåj”»›ËË« ||@n_ŸŽûözøð¹ŽŽö¯¿¶é¯+nC‘&’+?¯Ý.Ì·Ådw$Ÿ³š>}Z%&žŒÜ9yòÊŽU®l‘{œü;òo9cÇöúå—)K–l9yòê§OYW¯ÞÃ8”g€âfòd½{C:wnŸ3ÎÌÌvq©·hѰk×ÖXY™´oßpçÎ¹ŽŽ5¯]»Ÿ”t¡zõ þ9~РÎ$¿ïÈçÏ1¦I“·ný³k×ñÇ_¶n]w×®¹}ú´â4n\ýÈ‘¥;7¹ÿÙ‰W›4©¾k×ïÝ»;),ÙÙ¹–]yJ©Oþô3_µfÍÄzõªdd¼»xñöÔ©žÝº9B’’Î ;.[6RW·Ô™3i66æÑÑݺ5—+¿]»¹+8p`'eÆ5ª–» ¿þÚ"÷¾Œ17·¦üÉé=œ´µ5”gP²|!eæÛb²;™4`á¡իWøðá“·÷\©”)3Î@)íÚµùÊ•ã*V,{öìu=½Ò+VŒ¥” g ¸úÏÏdBqF©‚t(¨;wW­êž™™}øðâfÍìt8ßɪU OŸ¦W«Vž¿wË–¤îݧš›Ý¿¿éG‡ð]Èý4”˜›_€1–œ|qÉ’-IIç33³4¨ZrÆØ½{O¦M‹¦”::ÖTUU9zô!„&cÈà PJÕÔTãã1ÆZ·®ËŸ”(!SJûeeeoÚtèØ±KŒ ãž='OöøÑ¡|[˜›Tb`n|%ÌM*©ð 4ˆÁ8C‰Q2fÀ·…®c‰„çJÌM€¯A~tðc`nˆAÎb3@>cÙÙ9‘‘;[´®¯ßICÃÅʪGÿþsΟ¿Uà‡acÏž¥¾¤bÅÞ.††®mÚŒIHHÉw¯;ŽJ$ηoÿS€#Šì+¬©߆R'J$guõÖåË÷ôõÿêÕ‘½¾&毧|½ø6²uäÿih¸T¨ÐsԨзo?|}]c¯^½©ZÕ=-íAÁJØ´)Q.Bþ_RÒùoúhÖ·n™Â­WNŽ42rçóçEüq5ñë“1&T„/IHHqržSÄëP,áyÃËÌÌvs›šzcܸ>K—×Õ-}ãÆÃÐЭ Þ³g^³fö_ú^vž„´n=ºLí¨¨ÀŠ˾zõfÕª„Ncb¦ˆü4’ì¾ô}ð"ûÊö?ò*SØ&%%ÌÒÒ˜’“#MK{àíüèÑ‹íÛg‹˜¿cÌÅ¥ÞÇ›õò­—,¡Ž„3¿¼ØÆÆ\v•¡¡î·kÛÜgŸjËn½c )†´m[¿(ÿfB¾×'¥4!á8¯oÕöí.[¶mÉ’-#Gvÿþ”pÈJ4ÆX|ü17·‰wïÆZZšäÞ€R:gÎÚ'®ž:ammÆÿ¯ÝÊʤeËÚíÛ ˆHN^ú¥¥”&'_¼páÖÙ³‘5kV¤”ZXÏŸïwòäÕ¥K·þúk e:¸î–åÞW™n½°ÐØX×ÌÌ€ÿinnØÏÏoÁë×ïË”Ñ.ô˜¿¥TSS½lYCñmr/”­#!ÄÚºlzúÛ¡C-_>JGGK¼@qçÎÝŒ‰9pçNLSþÁÈè?~k Ï>)¼–)ÜzQúïÛðŠòO­å{}2Æ„ŠðZ0ö?öÎ<®‰ãmà3 @î›9D ¨ª Š"xß ‚µ¨xs¨E©Šê( VðD)Ò‚Öµ*Ö*¢±hÅ´H2ïÓîo»I6Q°ø–ù~øƒlfžyžgggç™yvƒbc†_4LWWó_R”@ ’›ÔÉ‘µÜNÑÒ"LN>>Š ¨Â;wFåç¯Å÷u¡P´jÕ.+«I<žÀÆfjRÒ±Q {ö9;‡¨ª œœBJJ®#„45Õ99Å­­¥@ÏžM>sfnE(}õÕnKˉ<žÀÎ.0==Ÿ¡í¬Y‰A”ÎÍÍ­~ëÖíG½|ù:22¹{÷)<ž@SÓgР¹gΔQ ¯8:«ª lmRRŽÒç%Y¶H: B¨¦ÆOnäê¼páÖ>+ŠðG±uë6yåÊ,©^¢”‘” þNêÈÊ*tq™©ª*èÞ}ÊáÃgOœ¸äèŒKž:u•ž0#Ë-²r<çšÃáˆÅH,çç_ÄYt‰Äqq;ÍÍÇ©ª ŒX»v/‡óéo¿=EmÜxÐÇçcƒ¿ÖÎ[Z„qq;q~š]`VV!»Õìû©—ÕY©2²ÚmGÏ´£]!ÿX„Ÿ?Ë,«gRö.[–¡£3BOo䨱+¤öO¹‰m’8C©‰[ô㲜æçƒ Ð ;ÇÍÍÎÐPgÇŽ“$=‰@ þeHÌЩ‘;Y¹y³²¾¾ÉÛ›™ä!41ÑÓÕÕ„BçÍKÞ·¯(5uá½{{׬ùL×vÆ ŸÛ·«¯]»‡çëùùÿ ô®9}úÆ®]1••ûŠ‹7@ÇŒYÞÚú×L(::=*jêÝ»{æÍ·`AJJÊQ†Õì¶ÐVVV¹nݾÁƒ]ð&ƒ\ƒƒ‡?yRWXxë\RrýáÃÚ3|¤zI$ËõÃúõû7nœSVö-Ÿo4cFB\Üδ´…ee;ÌÍ W‹Åÿ˜T±»EVÇ E§O߈Ïújkwa“ªsTTZJÊÑääyåå»Çÿ4.î/ï‰Dâ#GÎìJ­‡‡oHMÍKJ +/ß2"8x]AA©,«¼B(ÕÆ–¡¬¶&ãT #ö¨v÷ŒTÏ¿³]ß}w9++BøÓOÛ=:äõÌÓ§oœ?ŸrâDªUÁRû§Ü}?É œ1°PŽep$åìÚƒ yü8—Z\2¤Onî™vÿ„@ þ«Ü¤Î‹¦¦@$ììñ=¸±ñ$}ýÙ³€‰‰•ä0þ–ŒŒ”òòÝJJÜôôãEEIžžNB>ßèñã˗ ÀeâãCÜÝíaa£×<þÒÈH'=}ѤIC,ùþûŸ:ú~ûíR33ƒgÏ^¦¦æ¥¥-5j <|Ô½{5 û""FSíº»ÛÛÛwÝ»·ÈÕµ`÷îÂáÃÝLLôƒ÷ñôtrv¶˜™DDŒž8q%6°zõç“'†Ξí_Qñ[RRNxø(JìÓ§ ì¶ôî=û¡µU(# ozú"€":ÛÛwí߿׮]…#F¸²²¾óöîgaaXVv_ª— „ì2׬™5h#à‹/ü¦L‰OL óðè˜9ÓwòäUOŸÖSMSnqrꎓÁn¡CÙxó¦E[»ËÈ‘ý¿þ:T²¤¤Î<žrròá-["Gþ0wî˜û÷kp`vçNucã½{[áÉßóç/33¿KO_„K.\8¡¥EˆBžì×ï ú”111lÖ,_UT”¤¶EOÝaI•¡fºïÉ3ín—ŽŽø;“J®?cbìí»âv%û'Ÿ/%e‘òe¬››ÝXcc]zI©Ž•ŒŽ$åÐ ¡BM‡n;vœlm*+“û@ ü{1·óríÚv@IÉÐФ‚‚¯MLô€Ä’*NnhxEݰ££§……¢*ŠÅâ²²"‘Ø×7Šª+‰ß¼i©©y†?Z[›áù^Žmmâ’C†ô2¤B¨ººöÀÓññY“&­<{6ùÖ­*±yxôÂS:ွ““S¯OÁù$%å|ýuh]]SAÁ圜/‚°0ÿ¼¼ û÷ÿP]ý¤ªêÉ­[U±XŒkyy9S¶xx8lÚ”ûâE#%³¬¬’Ý–üü33€ŠŠ²±±.§ŒK*¨spðˆðð uuM\.'7÷ÇÌÌ(ê+I/UT԰ˤ¦z]º¨¬¬L±uu€J2QÄ-t°B¡è‡®EG§{{÷KI™¯¦¦"YRRçòò‡--Â(?ùÄ ÏŒ?~ x½u«J$»»ÛS%cb¦Š‹¯Ë²ÚÀ@·››ß­›)¥–Éb£¬¶„ê ïÉ3íe×ñã(!r{¦uEHöO–'"¨I¿µõ_(cyŽB²€¤ÉÂBCCíÖVáÓ§ øJ$¿‰:/66æ€òò‡KKssCÉ” ggkMMõââë}ûöÄ####„®þžwæäÄ1^†cnnøË/U2B‘„„}ÍÍ­+Vb™––&K–LRUU‰ŒLnhxEMd©© žp8ÿH¥ ðŽÍ8uêjEÅozzšxqT( ²àÁƒ'&xyy¹ÌžÝµ¦æY@Àjª‡©É«¤Ä¥¾•kK×®ÆVV¦àŸ „Ôy¯ ¶ääs¹Ü.]TýüÐcxI®L.—óÏd™YËu ÊF[[~¾¾QÍÍ­¹¹«$KJꌄ˜:SVp8éŒ7¸€D˜ªˆ'ù|#Ü{é´¶ eÙ(µ-Å¡LxOži_»båúSI‰K]’ý“ÅcÔWøš¢+ ˆŸ%Í—”#)!Äårqa¹M¡!Ï3tjØÓ‹ªª*£¿ùæ@uu-£puu-þ¿W/Káǵ66æ66æÖÖf/ÞþòËŒ†èÕ««Ÿ$&f?yRG† ®ÎSWWup°âpàÅ‹¿PÌ.Ü26ÖÕÓûß›R „ÆÆº¾¾99Åû÷ÿ8TYY BxáÂ/çÎý|èЪõëg‡†úyz:UV>P_¾\NM>λiccNOFWІ— „ ꬡ¡6yòœœâƒK¼©m ©^RP&‹ Ê-‰‰a¡¡~ƒ92Ü€jQ p]µ*øÈ‘³Û·çK•ÌhÑÉ©»²²]çÒÒÛø+¼*\[[‡uÆ®¾rå.U}ܸááeY­¯¯Å23F±Ø(µ­°° Ò—@²Ýöõ £Ví ßHWXÁ^„ÿ‘ìŸ,na ,gG*R†úöõÏï¿¿PQQ24Ô‘Û@ Ú²ÏЩŽÙ_,.‘U!´bÅô[·ªÜÜfÏŸ?~èÐ~ººš5YYßeg÷ëg«££¡¡¡ ˆÍÐÑÑèßß¡´ôÎܹ›Æ÷RVæÒ¢‹Ššzüø/¯È/¿ rs³‹ÅßÿÓŠ;–- äñ”MLô‡FG§ëëk¹¸Ø”¦¦æ%$Ìb( 6uêW¯_¿ÁIcc]affŽŽ†X,>vìü7ßä^¿þWŒŽN×ÕÕèÝ»ÛÑ£çÒÒŽgfFÓÅš›¾­-Åu ááÆáp6lˆ`L­’u”É®›"na@Ÿ¢-^<éäÉKK—¦áÁR£¯¯5{¶_lìvmggë‚‚Ò­[âb={Zhkw¹qã>þMSSý€Attº¶ÿرóGžËÏOe5»¥8†”e£­-_j[Œñ7oZêë› u¸\ެðûðL»Û…ý/]ºíînonn¨H/¢iÉþ‰¨­­0<Ã$0¾jnnÅŽ¥ïéÉ ´èñ{É.]º À/ƒFݼYéêÚ“Ë% ^ð¯BbB¥#G¾:p $3³`ýú즦?ôõµÜÜì²³WŒ3ß¹ÓÒñù»cb¶?zôÜÈH'4ÔoåÊ`ºÆT€Ï7º|9mݺ}qq;kjžq¹'§î))ó§Ný Þ¶m©iÖœ9›ž=kèÑÃ"%%2$d8C1€›––º£c7[[>>Ò³§Åöí‹önßžo` íï?àüùgçÒÒ;úúZ€åË/ÞVUõÄÖ–¿wï2ÉŸSÄÉ©¹â:»ºöèÕËRM‡‰Y¼PP&‹Œ\·HšCIær9;v,qq™¾!8x¸dIÆ‘õëgkjª‡‡oxþü¥«kÏ¥K§ÄÇïâñ”¹\ÎØ±ƒ /Ï™3WLM]¸reæ_$ÖÖÖ÷èa¾gϲ¡CûɲZÒRÆ[[¾,mmùRÛbLm‹Š®úûÇVVîc¤Ÿ1е»gÚÝ®×¯ß î6}úZÀ½{{ïEBÉþÙÐÐdf6Àð Ë.%úçÃå”c--M¤†²ä¸¹ÙÑ ùè#}„@QÑÕ9sƼ[š@ Þ(k’Aø¯!@§;Z‰ÎÎk·²š7cæÌ­Î{¡¨èªƒƒ~OBhëÖcK—¦¾|y’Ãwîœ%sYýs×®SAAkŸ>=ÊÈû÷))¹>qâÊû÷÷ijª‘°@è —ÌÄVšå^E üçihx•—w!"bB`Ê”Ïþ“á:BèС3S¦Ä_¹RþàÁ“£GÏ­^½;0p(Îi±³ãO›&ذáÀÒvvX<ÓѪý…¬þÙÜÜš˜˜3µÃ„ÐúõÙÑÑSIÀ@ ÿ>dŸ¡Ó@ö:„P]]“•Õ$}}­;£ðï?t´Rï…††WK–¤æå¯«k277 ðŽ‰™¦¢¢„í}ùòµ»ûì¼¼5Ô‹5;ìžéXØûçë×oÔÕy0œ:uuݺ}EEIN E tFÈ>Cg…Ä 3@h#$fè¬Õ@ À‰@ $f @ l˜@ @ °Ab@ À‰rÀ?ó”‘qÂÓsž®®/'àó'LŸ¾öæÍ_ßù¥[¡gÏæÍKîÖm2'Ð×÷óö^TPP*·Öñã8œO«ª~‡YêR_±X„Ë@衇ó©ŠÊg]»N Mª¯ob©ÕÛŽâvá2tñ'°´œ¸`AÊ«W¶Ý„P}}“­m@EEÍ»I8xð4CCüwöìÍ÷ú ¸÷í™öµK$gdœxþüåþZ<öþ‰¢ a—Ó¾öJžêªo»p©47·&&游ÌìÒe˜–ÖpOÏyÙÙÅ ÚBõ½ß~{ªx‹¡‚‚R/¯yB¡è]µ&¥ŽV€ðAƒjiúûÇܸqÉ’)[¶ÌÓÖÖ¸ÿQJÊw÷Ù……ëìý¶omÇAÈgŸ-ÔÒRÏÌŒîÖÍ´¾¾içÎ_ßèììãÇ{ɪHo!ôVí²Ô¥ß›eɤʔ–¦ZXD"qEEMppÂãÇ/òòÖ¼ÛBH èûèÑ!CC¹vÑ¡l¼yÓréÒíÈÈ-µµõ{öÄRßÍá¢EÛFþ¤Gó·­K×öÇ7[[›Ñ¿Ò××~¾•<û ]=Ó¾váéà¬Y‰C‡öû~ùArû'„° à6„Å«ík/Bèñã\üÿ÷ßÿ4}úÚ«WÓMMõÚ(–…?ÿl6lÉǵ˗O÷ôt Eùù?ÿ|}qñµ´´…r-z·B8lØÇ[·MN>9îCî'áÃÄ „P~þEÿØêê #ɵk÷\¾\~õjº•• ¾µðùFƒ»øø,‰ŠJ?~ËÛ6 !<þÖÏ?ÿzýz†£c7¡¹¹aRRØ•+å[¶7ÎS‘ î;OË$ë*rÓ¥j›˜èáffÑÑÓÂÂ646þ¡¥¥Þî:·¡ªªŠ©©>{ɃtVV¦ ¯æÌÙ´mÛMM5v씕Ufg?xýÎ!þÇÀà¾o¤ž}Ð~ži_» ü߯îüËaê[!·"„(CX¬h_{!„X%„ŽŽÀÐP»-}ž„ЊßVUý~åJš±±.>س§…‡G/OϹƒ9Mú»Eï<Â@cc†_4LGGãƒí'áÃä&ujd-·S´´““„‡¢ªðÎQùùkñ}](­ZµËÊj'°±™š”t@,FÔ¦ùž=EÎÎ!ªª'§’’ë!MMu@NNqk«· !<{6ùÌ™M¸¡PôÕW»--'òx;»Àôô|†¶³f%:8Q:77·ø­[·!ôòåëÈÈäîݧðxMMŸAƒæž9SFU,,¼â謪*°µ HI9JŸ—`dÙ"é4¡šü=¹‘«óÂ…[?úh,• £nÝ&¯\™%ÕK”2’2ÁßIYY…..3UUÝ»O9|øì‰—ƒqÉS§®Òfd¹EVþã\s8±‰Åâüü‹X ‹Î"‘8.n§¹ù8UUÁÀk×îʼn¡úø|l`ð×ÚyK‹0.n'ÎO³³ ÌÊ*d·š}zÄ~êeµEGVªŒ¬vÛÑ3íhBÈß?!ÄçOàrËê™”½Ë–eèèŒÐÓ9vì ©ýSnb›äÎÐ_jâý¸,§ùùÅ`C ô’¥ƒâö*¢•ÔAIØÇ:Ê™Éɇ¹B[Z„©©ys玥Lÿþ½ÆóLN>,yšªª~omÆÄl75£¦æíí½¨¼üáÛª‡­vw·74ÔÙ±ã$ ‚"˜¡S#w²rófe}}“·7sÓBhb¢§«« !„Λ—¼o_QjêÂ{÷ö®YóyBÂÞU«2©Â›7禦.¼z5½KÕiÓV‹Å¨O›á ûLMÇL˜·yóá»w£ß˜##“7oÎݸqÎÝ»»ÃÃGGDlLN>L×vÆ ŸÛ·«¯]»‡çëùùÿ ô®9}úÆ®]1••ûŠ‹7@ÇŒYÞÚú×L(::=*jêÝ»{æÍ·`AJJÊQ†Õì¶ÐVVV¹nݾÁƒ]ð&ƒ\ƒƒ‡?yRWXxë\RrýáÃÚ3|¤zI$ËõÃúõû7nœSVö-Ÿo4^úšú IDATcFB\Üδ´…ee;ÌÍ W‹Åÿ˜º±»EVÇ E§O߈Ïújkwa“ªsTTZJÊÑääyåå»Çÿ4.î/ï‰Dâ#GÎìŠûB(<|Cjj^RRXyù®ÁÁë JeY ä…¸B©6¶´eµÅ0§ÊXX±ïDµ»g¤zþíúî»ËYYÑŸ~ÚþèÑ! ¯gž>}ãüù”'V­ –Ú?åîûI^àŒ…r,û€#)g×®lÈãǹ,ñ­"öJÖ’ª•ÔA_&`(gZZš®ÐŸþõõë7ö– ´>ý´ÏO?Ý}ó¦ERò¼yÉß~{2-mÑ;»FŒðX¶lUQAõ¬¬Lq+C†ôÉÍ=ÃÉMê¼hjúD"1ÀÎ.ßOÒoÏž5LLô¨Mÿùó·ddœ „”—ïVR⦧/*Jòôt‚òùF¿X¾|GLL.âîn ¸æùó—FF:éé‹&Mrð`É÷ßÿtèЀ@Ð÷Ûo—š™<{ö255/-mѨQáá£îÝ«IHØ1šj×ÝÝÞÞ¾ëÞ½E®®=»wîfb¢‡<¸§§“³³5ÀÌÌ "bôĉ+±!€Õ«?Ÿm`·¥wïØ­­B± }ÓÓÑÙÞ¾kÿþ½ví*1•õ·w? ò²ûR½!d—¹fͬAƒ_|á7eJ|bb˜‡G/ÀÌ™¾“'¯zú´žjšr‹“Swœ Æp ÊFÀ›7-ÚÚ]FŽìÿõס’%%uæñ”““oÙ9zô'€¹sÇÜ¿_ƒ³;wªÿèÝÛ OPž?™™ù]zú"\rá --B„òd¿~_Ðgœ‰‰a³fù²Ø¨¢¢$µ-z* Kª 5£zOžiw»¨¤=¹þŒ‰ °·ïŠÛ•ìŸ|¾””EÊc”±nnvtc«æR+9O•”C7„%tQÐ^†öÌ(©)‹µµõìãCLL@¯^–€ãÇ/®Püx·¾¾–d˜j` -£††W É/^4fdœHK[8r¤„02rÜýû5[·´áËËË`aa(©u®q+Ývì8)Š”•Éd€@ È —k×¶JJn„†&|mb¢$ºš€††WÔÚptô´°°QTE±X\Vö@$ûúFQuE"ñ›7-55ÏðGkk3C†ôAUW×8p:>>kÒ¤•gÏ&ߺU%#^øV !0 wròaÆëS‚‚|’’r¾þ:´®®© àrNΗAX˜^Þ…ýû¨®~RUõäÖ­*€X,Ƶ¼¼œ)[<<6mÊ}ñ¢‘’YVVÉnK~~‚™™@EEÙØX—ÇSÆ%Ô98xDxø†ºº&.—“›ûcffõ•¤—**jØeR·ÿ.]TVV¦X‚º:@#Š\·ÐÁ6 …¢~¸îíÝ/%e¾ššŠdIIË˶´ p tþä'<3~üø€zàõÖ­*‘HìînO•Œ‰™ (.¾.ËjmÜnnn|·n¦”X&‹²ÚRª3¼'ÏP´—]xŠ‘Û3ml̨+B²"Ö‡)cqÊX–Z’^¥;!‡¥°¬¯X쥒âAê>ƒÜñÁÆÆŒ^QîŠ-mlüI¼˜¡®®‘ÃÚÚ É7oV …"ww{ê¬ ÐÇ Š¨ÇhÅÐP»µUøôiÖ3t^llÌ8ÖÒÒÄÜÜPr­ËÙÙZSS½¸øzß¾=ñ ØÈHÇÈH!D%ÑâygNNãe8ææ†¿üRàp ãF•°¯¹¹uÅŠ@,ÓÒÒdÉ’Iªª*‘‘É ¯¨‰,uSÄ7Kç©tÞ±±§N]­¨øMOO/Ž …¢!Cx°$ À›Ú¦ê%e²H  Ü’˜ê7h#Ã- ¨×U«‚9»}{¾¬´oúq'§îÊÊJtKKoã¯ðBfmmÖ»úÊ•»TõqãV„‡o”e5#ƒ¡ BˆÅF©m……mn¼’í¶¯gµÚhWxøFºÂ ö"üdÿdq c@`9;R‘:à0äÐg·,r±W__K®Jt¤Žï0Ö±_¡ªª*¡¡~‰‰ÙxŽ¢´ôNNNÉœ9c%%;:vWQQ:sæ5ŽQ‰RÏÚÚ k(©C™ß¡¢¢dh¨óVÎ!²ÏЩŽÙ_,.‘U!´bÅô[·ªÜÜfÏŸ?~èÐ~ººš5YYßeg÷ëg«££¡¡¡ ˆÍÐÑÑèßß¡´ôÎܹ›Æ÷RVæÒ¢‹Ššzüø/¯È/¿ rs³‹ÅßÿÓŠ;–- äñ”MLô‡FG§ëëk¹¸Ø”¦¦æ%$Ìb( 6uêW¯_¿ÁIcc]affŽŽ†X,>vìü7ßä^¿þWŒŽN×ÕÕèÝ»ÛÑ£çÒÒŽgfFÓÅš›¾­-Åu ááÆáp6lˆ`L­’u”É®›"na@Ÿ«-^<éäÉKK—¦áÁR£¯¯5{¶_lìvmggë‚‚Ò­[âb={Zhkw¹qã>þMSSý€Attº¶ÿرóGžËÏOe5»¥8†”e£­-_j[ŒÕë7oZêë› u¸\”1~žiw»ðÂó¥K·ÝÝíÍÍ éEÔT²"jkë ϰ Œ¯š›[±cé{z²-úGü^²K—nÌÌ )5r¨b,ö"‰ä©ZÉ2|‡ñAî7ãòå;ýû‡ÅÅÍ4È©¥¥õĉKññYÓ¦ ’uuu5"#ÇÅÆfèéi¹»Û”âÄ$Õcì3ܼYéêÚSª‰l@UT”ŽùêÀ’ÌÌ‚õë³›šþÐ××rs³ËÎ^1fÌ .—HK[ÄçÙþèÑs##ÐP¿•+ƒér7N>ßèòå´uëöÅÅí¬©yÆårœœº§¤ÌŸ:õ3\xÛ¶¦¦Ysælzö¬¡G‹””Èá Å>>nZZꎎÝlmùøHÏžÛ·/NHØ»}{¾¶¿ÿ€óçSœCJKïà…ÆåË/ÞVUõÄÖ–¿wï2ÉŸSÄÉ¿â:»ºöèÕËRM‡Y¼PP&‹Œ\·HšCIær9;v,qq™¾!8x¸dIÆ‘õëgkjª‡‡oxþü¥«kÏ¥K§ÄÇïâñ”¹\ÎØ±ƒ /Ï™3WLM]¸reæ_$ÖÖÖ÷èa¾gϲ¡CûɲZÒRÆ[[¾,mmùRÛbÌ ‹Š®úûÇVVîc¤ŸI>¶£gÚÝ®×¯ß î6}úZÀ½{{ïEBÉþÙÐÐdf6Àð Ë.%cbJ9ÖÒÒDjÈ!KŽ››eÈ•+iA€_ÝÏC/&Ë^É`LªVìÖAßv¬“B¨«óNJJN>¼qãÁÐÐ$%%®«kÏ­[àW5HzB¸fÍ,mmÅ‹·=}ZÿñÇvqqAK—¦á2rգˋQQÑÕ9sÆ(˜NF :9PÖ$ƒð_B€Nw´„P(²²š7cæÌ­Î{¡¨èªƒƒõÃX[·[º4õåË“¼sç¡«ëç••û?úè}ýHÖ‡Œ,ÏàÀûC@VÿܵëTPÐÚ§OJ¾áçßÔm÷î"¬õ4<áA>}câÄ•÷ïï“õ“”‚t —ÌÄVšå^E üçihx•—w!"bB`Ê”Ïþ“á:BèС3S¦Ä_¹RþàÁ“£GÏ­^½;0p(Îi±³ãO›&ذáÀÒvvX<ÓѪý…¬þÙÜÜš˜˜3µc†–!Vƒ í„pýúìèè©$`  Bö: dŸ¡CAÕÕ5YYMÒ××Ú¹3 ¿ß½£•z/44¼Z²$5/ï|]]“¹¹a@€wLÌ4%lïË—¯ÝÝgçå­¡^¬Ùy`÷LÇÂÞ?_¿~£®ÎëX=BüÑŒ_ZJh;……WÖ­ÛWT”ÄxÇ ²ÏÐY!1C§Ä @ Ú‰:+ʶ8@ @ø0!1@ @`ƒÄ @  3@ 6HÌ@ @ Ø 1Aøgž22NxzÎÓÕõåñ|þ„éÓ×Þ¼ùë;¿t !ôìYüyÉݺMæñúú~ÞÞ‹ JåÖ:~ü‡óiUÕïïÐ"K]ê+‹p½ ôâp>UQù¬k׉¡¡IõõM,µÚ¢sÛQÜ.\†n#þãñ––,Hyõê϶ۂª¯o²µ ¨¨¨y7 žfhˆÿΞ½ù^_÷¾=Ó¾v‰D⌌ÏŸ¿üÀ_‹ÇÞ?B”!ìrÚ×^ɳ@]õm.•ææÖÄÄ—™]º ÓÒîé9/;»XA[¨¾÷ÛoOß“zìí¾UŸg¿Ž©Ë>šÑ{‚"åeÁÒKéÇ÷UAA©—×<¡Pô_¹„N‹RG+@ø Á?¥äïsãÆý%K¦lÙ2O[[ãþýG))GÜÝg®8°÷Û¾Û!Ÿ}¶PKK=33º[7Óúú¦; |}£³³WŒï%«"½!„Ð[µËR—>:Ë’I•)-Mµ°0ˆD⊊šàà„Ç_äå­y:·„@Ð÷Ñ£C††:rí¢CÙxó¦åÒ¥Û‘‘[jkë÷쉥¾›-ÂE‹¶ýIæo[—®í?n¶¶6£¥¯¯ýþ|+yöA»z¦}íB”Κ•8th¿ù½ûrû'„° à6„Å«ík/Bèñã\üÿ÷ßÿ4}úÚ«WÓMMõÚ(–…?ÿl6lÉǵ˗O÷ôt Eùù?ÿ|}qñµ´´…r-ê¨æÚUä:Rd¤R¤'äŽ~,z²ôwÐPq_ùø¸mÝz49ùðüùãßJgáßÄ „P~þEÿØêê #ɵk÷\¾\~õjº•• ìø|£Áƒ]||–DE¥Ÿ?¿åm…ž?ë矽~=Ãѱ„ÐÜÜ0))ìÊ•ò-[ŽŒçÙ–Û†,Ú8 S µMLôðG33ƒèèiaaÿõ[ªmѹ@UUULMõÙËH¤Û°²2mhx5gΦmÛhjª± d§¬¬2;»øÁƒìw9ð?ÿÐð}#õìƒöóLûÚáÿ~uç_Sß ¹ý!DÂbEûÚ !Ä*!„tt4††Úméóì „V¬ø¶ªê÷+WÒŒuñÁž=-<åðá³'N\rt Æ%OºÊØ—êY;àŒsÍápÄb$‹óó/b,:‹D⸸ææãTUF¬]»'N „6n<èãó±Á_kç--¸¸8?ÍÎ.0+«Ýjö[/û©—Õ–Ô‚÷í™v´ !äï‹âó'p¹ƒeõLÊÞeË2ttFèé;v…Ôþ)7Cògè/51ƒ~\–Óüüb°!zÉÒAq{ÑJꉠÇ$ìcåÌääÊ\¡--ÂÔÔ¼¹sÇR¦ÿ^ãÆy&'–pàtzú"ggëüü‹››[""FS-ΘᓑqâÚµ{}úØòó/66þè  \S]ýd×®˜®]ÿýÅ¢EÛÆŒYþûï‡qÅèèô””ù8œ¬1ç¬ì¾T/q8]æúõûSR曘腆&͘‘У‡yZÚB]]Í9s6®~ô(—n»[$O=¼={3>>K è«­Ý…QLªÎQQi™™ß¥§/rq±9vìü’%©¸°H$>räìš5³¨³¾áøñ Û¶-pv¶ÎÍý18x‘‘ΰaKµzΜ1ìkBY6*+s¥¶åããF(+™Aj»í詞o‹]YYÑô„ ö^túôóçS_kiuéÝ{†dÿ”»ï'ÍØ„ÖR·$ÅJÊÙµ+†2„euY{çÌèŞN&k™€}| œ‰ŸÁ{…þüó¯¯_¿8°·äÊô§Ÿö9xð›7oZ’--MÂÃ7>üczúbGÇnGž[º4ª¨ zVV¦ìç”Þ\DÄ&ö!‘¡ù;_GxQ_î dfôžpõê]ª<û% Ùñ¸\Kx·˜¸¸”ü!CúäæžY´h¢ÔsD t $fè¼hjúD"1ÀÎ.‰'éƒã³g “ÿݰçÏß’‘q‚R^¾[I‰›ž~¼¨(ÉÓÓ BÈç=~übùò11¸L||ˆ»»= ,lT`àšçÏ_餧/š4iÈÁƒ%ßÿÓ¡CgAßo¿]jffðìÙËÔÔ¼´´E£F „‡ºw¯&!a}þíînooßuïÞ"W׀ݻ ‡w31ÑC ÜÇÓÓÉÙÙ`ff1zâÄ•ØÀêÕŸOž<B8{¶EÅoII9ôýéÓv[z÷žýÐÚ*‹‘@Ð7=}@íí»öïßk×®Â#ÜYYßy{÷³°0Ä1ƒ¤— „ì2׬™5h#à‹/ü¦L‰OL óðè˜9ÓwòäUOŸÖSMSnqrꎓÁn¡CÙxó¦E[»ËÈ‘ý¿þ:T²¤¤Î<žrròá-["Gþ0wî˜û÷kðbÛ;Õôîm…ïÄÏŸ¿Äh\rá --B„òd¿~_Ð牉a³fù²Ø¨¢¢$µ-ÆVV25uxOžiw»¨„ =¹þŒ‰ °·ïŠÛ•ìŸ|¾””EÊc”±nnvtc«æR+¹Œ*)‡nK袠½ ì¹+R'¸µµõìãCLL@¯^–€ãÇ/®PZèëkIN¯ ´ÅbÔÐðŠ!ùŋƌŒii GŽô€FFŽ»¿fëÖc€6|yy9,, %Õ£Î5»Õ¸¤"2h·ë!$w¬£½'På©.áï?B1šq H½CA¥ö±±¥«W>eÊ@h¨Ë-FÒŸ**J¸!‡n;vœlm*+“áÂôÈÎ˵kÛ%%7BC“ ¾Æƒ,c”Ä)• ¯¨µáèèiaa£¨Šb±¸¬ìH$öõ¢êŠDâ7oZjjžáÖÖføn—c[[…¸ä!}† 郪®®=pàt||Ö¤I+ÏžM¾u«J,F½ð0 !0 wròaÆëS‚‚|’’r¾þ:´®®© àrNΗAX˜^Þ…ýû¨®~RUõäÖ­*Þõxy9S¶xx8lÚ”ûâE#%³¬¬’Ý–üü33€ŠŠ²±±.§ŒK*¨spðˆðð uuM\.'7÷ÇÌÌ(ê+I/UT԰ˤnÿ]º¨¬¬L±uu€J2QÄ-t°B¡è‡®EG§{{÷KI™¯¦¦"YRRçòò‡--Â(?ùÄ ÏŒ?~ Voݪ‰ÄîîöTɘ˜©€ââ벬60ÐÆíææÆwëö¿…R,“ÅFYm)ÕÞ“g(ÚË.C]]#‡µµ5’oÞ¬ EîîöÔY0 7ŽQÝ”òTI¹2ëÙ¡£Èu¤Xso1šZ— {Œ~ ȺCIí”{‹¡úÞ[Ýbp0„ÐÐP»µUøôi¾×$fè¼ØØ˜p.¬¥¥‰¹¹¡äZ—³³µ¦¦zqñõ¾}{âáÌÈHÇÈH!D%Ñâ±2''Žñ2ssÃ_~©p8Ì›„„}ÍÍ­+Vb™––&K–LRUU‰ŒLnhxE ¾ÔÀÇnçßxÇÆfœ:uµ¢â7==M¼8*І YðàÁ“ ¼¼¼\fÏîZSó, `5U‹ÃÔ€ŽÅ*)q©oåÚÒµ«±ä¶>BHA'LðZ°`KNN1—ËíÒEÕÏo]1†—äÊär9ÿ¼«É¼yËu ÊF[[~¾¾QÍÍ­¹¹«$KJꌄ˜:SVp8éŒ7¸€D˜ªˆ'ù|#Ü{é´¶ eÙ(µ-Å¡LxOži_»båúSI‰K]’ýS‘É:¾¦è (âgIó%å("Sq{ßêì3\ ÿZc–3>()qéå^¡ÎÎÖjgΔáýRzë?þXæâbCE¤”ä¿íÔY£V£QýìP_á’ŠÈoÆY®#Eš{«Ñ кcä§.É«•*I?ÿÞa–{‹aô=o1T-.—‹åÈu)ð/CžîÔH]G¡£ªª1ú›oTW×2 WW×âÿ{õ²„>|Xkccnccnmmvñâí/¿ÜÉhˆ^½ºúIbbö“'uÔAjùM]]ÕÁÁŠÃ/þ‚þ~,ìÂ…[ÆÆºzzÿ{„ÐØX×××#'§xÿþ‡*++A/\øåܹŸZµ~ýìÐP?OO§ÊÊǪñË—Ë©¡ùܹ›66æôdtmax B¨ Îj“'ÉÉ)>x°$ À›Ú¦ê%e²H  Ü’˜ê7h#Ã- ¨×U«‚9»}{¾TÉŒœº+++Ñu.-½¿ÂkfµµuXgìê+WîRÕÇ[¾Q–ÕŒü †2!¥¶¶AºñH¶Û¾žaÔj£]ááé +Ø‹ð?’ý“Å-ŒåìHEê€ÃCýÏ>ÍUÄ^}}-¹*Ñ‘:6¾ÃXÇ~…ªªª„†ú%&fã]8ŠÒÒ;99%s挕”ìèØ]EEéÌ™Ô8Fu$J=kk3¬¡¤zì“{IÍÛ.Sj1Yב"f¹"¤jBu Êc’—€äY“ôw=b._.§¬c¹ÅHú“ªõûï/TT” uñ*ðoBö:5‘#û‹Å%² „V¬˜~ëV•›ÛìùóÇÚOWW³¢¢&+ë»ììâ~ýlut444Ô±±::ýû;”–Þ™;wÓøñ^ÊÊ\zCt±QQS¿àåùå—Annvb±øûïZ±bDze<ž²‰‰^`àÐèèt}}-›‚‚ÒÔÔ¼„„Y ÅAAæNýêõë78‰`l¬ !ÌÌ,ÐÑÑ‹ÅÇŽÿæ›Àë×ý`Pttº®®FïÞÝŽ=—–v<33š.ÖÜÜðmmÁ(®sHÈ0‡³aCcjÅll¬« LvÝq ú\mñâI'O^Zº4mÄ–’}}­Ù³ýbc·h;;[”nÝú×›Czö´ÐÖîrãÆ}ü›¦¦ú‚èètm;;þ±cç=—ŸŸ ËjvKq )ËF[[¾Ô¶ë£oÞ´þìœé IDATÔ×7êp¹ÉùÍûóL»Û…ž/]ºíînonn¨H/¢¦D’ý!P[[`x†%H`|ÕÜÜŠK_p•hÑ?â÷’]ºt`ffH©ÁCc±I$ÿHÕJ– øã;Œr¯Ð¸¸—/ßéß?,.nÆ AN--­'N\ŠÏš6M ¬«««9.66COOËÝݾ  '&)¨Þ[S¡……‘"2Ûë:RÄ–+‚Þèåå^’gMê>ûõˆK¾ó-†ºoÞ¬tu퉟Ã&>(HÌ@`B¨¢¢täÈW”df¬_ŸÝÔô‡¾¾–››]vöŠ1cáq--mŸ¿;&fû£GÏŒtBCýV® ¦ËaÜ8ù|£Ë—ÓÖ­Û·³¦æ—Ëqrêž’2êÔÏpámÛ˜šfÍ™³éÙ³†=,RR"CB†3øø¸ii©;:v³µåã#={Zlß¾8!aïöíùÚþþΟOqv)-½ƒ—/\¼x[UÕ[[þÞ½Ë$BN[$oüŠëìêÚ£W/K55^pbñ@A™,0rÝ"i%™ËåìØ±ÄÅefxø†ààá’%GÖ¯Ÿ­©©¾áùó—®®=—.¿‹ÇSær9cÇ*,¼Œß`ƒJM]¸reæ_$ÖÖÖ÷èa¾gÏ2ücLR­–zS§±µå˲ÑÖ–/µ-Æœ ¨èª¿leå>Fú™Ôéc;z¦ÝízýúÍðánÓ§¯Ü»·Wñ^!”ìŸ Mffã ϰìRÒ­€R޵´4Ò¦§²ä¸¹ÙQ†\¹’æàøõ×ý 9ôb²ì• ƤjÅn„ðmÇ:¹!„º:ïÔ©¤ääÃ7 MRR⺺öܺu~Uƒ¤W!„kÖÌÒÖÖX¼xÛÓ§õlD½:I®zo{NB ʤ$´å::|8^ns,£Ù¸qžTOذ!‚ª"Ù%fÎÁ~^¤z°^Ro1ãÆy‚"Õ@ªE„@QÑUÆkâ„(k’Aø¯!@§;Z‰ÎBH(YYMŠ‹›Á¸iýg(*ºêà`Eý(ÒÖ­Ç–.M}ùò$‡ïÜyèêúyeåþ>z_?’õ!#Ë3΂¢¬þ¹kש  µOŸ•|ÃÏ¿©ÛîÝEX êixÂ;ó!œS‚$%%×'N\yÿþ>Y?o÷A½d&¶þÓ|(÷*á?OCë¼¼ ›S¦|öŸ ×B‡™2%þÊ•òž=znõêÝCq–‚Ú4Á† þ“¶³Ã♎Ví/dõÏææÖÄÄ옘©0´´±$`h;Â9%H‚Z¿>;:zê0:1dŸ¡Ó@ö:„P]]“•Õ$}}­;£ðÛÇ;Z©÷BCë%KRóòÎ×Õ5™›xÇÄLSQQÂö¾|ùÚÝ}v^ÞêÅšvÏt,ìýóõë7ê꼎Õ!ôÇÍø¥¥„¶ó!œS„ЩSW×­ÛWT”ôá,%H‡ì3tVHÌÐi 1@ „6Bb†ÎʇË@ „Ž†Ä @  3@ 6HÌ@ @ Ø 1@ @`ƒÄ „vF$gdœxþüe»¼’ !tüøçÓß~{ŠÔ×7ÙÚTTÔàãUU¿¿•–òtÍB¥^^ó„BÑ;è,Š22NxzÎÓÕõåñ|þ„éÓ×Þ¼ùë;û!ôìYüyÉݺMæñúú~ÞÞ‹ JåÖz+/)^—úŠÅ"\B/½8œOUT>ëÚubhhR}}K­¶èÜv· —¡Ûˆÿx<¥åÄ R^½ú³cm!¡!1¡=ÁSíY³ÿü³¹]ÞüM‚§ò‹m=ú3 ï£G‡,,Œ™ˆCÙË34‡ö±¦¦zròá·šèãŸòõZ¶,Ãßà?n¾wooffô«Wº»Ï>wîçwpòÙg ¯]«ÈÌŒ®¬ÜwúôF+_ßèƒO³[MòV²Ô¥”u–©2¥¥©ç>ztè×_÷ïÜõÝw—§O_ËÒ7Ú¢sAQD®]t°ø¯¼|×Úµ³öîýþ‹/’oÕK @ø`Qêh B(?ÿ¢¿luuŽ……QÛBø¿_ü@µ=l`Ì´nÞü5;»øÁƒl¡ªªŠ©©¾â¢ØËKj!Œ >|iPÐ0 m®]»çòåò«WÓ­¬Lp->ßhð`Ÿ%QQéçÏoQ\gJæùó·~þù×ë×3»AÍÍ “’®\)ß²åȸqžŠLpßö\°ÔeLë¥J¦j›˜èáffÑÑÓÂÂ646þ¡¥¥Þî:·E:•T•è6¬¬L^Í™³iÛ¶ššjoÕK @ø0!û ¹kºx…{Õª]VV“x<ÍÔ¤¤b1Båå]àp>ݾ=—Œ‹Û©¡1ìÖ­*ÿX„Ÿ?ËÌRçlìÙSä좪*pr ))¹ŽwZ[…11ÛMMǨ©y{{/*/Hé³qãAŸ u€ì4¹Çe5ÍÐàînoh¨³cÇIÉ™¢¬VZZ„ÉÉGÂÃGQåÉ;£òó×bßÖ-ššê€œœâÖVnBxölò™3›p+B¡è«¯v[ZNäñvvééùŒó;kV¢ƒC¥mss«ßºuûB/_¾ŽŒLîÞ} 'ÐÔô4hî™3eTÅÂÂ+ŽŽÁªª[Û€””£XºÉ²l‘ìfB55ø{ËH®Î ný裱Tz˜XŒºu›¼re–T/QÊHʤÎWVV¡‹ËLUUA÷îS>{âÄ%GÇ`\òÔ©«ôT"Yn‘µ]À8×G,Fb±8?ÿ"K¯ÃåE"q\ÜNsóqªª‚#Ö®ÝKOÆ#áC€Ä ¹kºÂyó’÷í+JM]xïÞÞ5k>OHØ»jU&`äHÐP¿Å‹·=|øôÌ™²¯¾Ú½iÓÜ^½,³²¢!„?ý´ýÑ£CYÕ1›7禦.¼z5½KÕiÓV‹ÅWùöÛ“ii‹îÜÙ5b„Dze;pa‘H|äÈÙÁƒ]ÓVÆtMjz‰äTO²iºæ¸.BhÈ>¹¹g$“sdµrófe}}“·w?ɵy=]]M¼ƒñ¶néÓÇ&$dxBÂ>SÓ1&ÄmÞ|øîÝßè#‘‘É›7çnÜ8çîÝÝáá£#"62²ªfÌð¹}»úÚµ{Ø{ùùÿ ô®9}úÆ®]1••ûŠ‹7@ÇŒYÞÚú×L=::=*jêÝ»{æÍ·`AJJÊQ†'Ùm¡;¿¬¬rݺ}ƒ»àM¹:ò¤®°ð Ö¹¤äúǵ3føHõ’H$–ë‡õë÷oÜ8§¬ì[>ßhÆŒ„¸¸ii ËÊv˜›þÕý(ØÝ€jB(>}#>>K è«­Ý…QLªÎQQi))G““ç•—ï?þÓ¸¸L¦t@ :’›ÔyÑÔôˆDb€] žã66þcM½¶¶>=ýxQQ’§§„Ï7züøÅòå;bb”•¹‰‰a§Oߘ9ó늊ß&OìÐÑÑgk<}Ú€«{y9,, ©êX~||ˆ›› ,lT`àšçÏ_*)q32N¤¥-9ÒB9îþýš­[îÜ©nlü£wo+Ætœž#+½D2"Šqw·§7MiNU‡:8tÛ±ã¤P(RRâ*Òʳg =J«ùó·ddœ Ê”—ïVRâÊòª,ÝŒŒtÒÓMš4äàÁ’ï¿ÿéС3 ï·ß.533xöìejj^ZÚ¢Q£ÂÃGÝ»W“°/"b4Õ®»»½½}×½{‹\]{vï.>ÜÍÄD!0xpOO'ggk€™™ADÄè‰WbC«W>yò`áìÙþ¿%%儇¢ÄR§X–-½{ÏÀ~hmŠÅH 蛞¾ ˆÎöö]û÷ïµkWáˆ¬ï¼½ûYX–•Ý—ê%!»Ì5kf äøâ ¿)SâÃ<þø‹>2غu¾ä¼œ¥:þhmm†¿Â+²­­ÂÛ·…"ww{j¥À€Þ8fxüøÀÐP‡±ê¯HÖ»ä>ƒµµ>H5M/Lµnh¨ÝÚ*|ú´ÁÌÌ@‘Vtu5 ¯( ÑÑÓÂÂF¿]-‹ËÊÈu C7\rÈ>C†ôAUW×8p:>>kÒ¤•gÏ&ߺU%#^Ô“ôNN>üüùKºzAA>II9_ZW×TPp9'çK„ ,Ì?/ïÂþý?TW?©ªzrëV@,ãZ^^Δ-›6å¾xÑHÉ”{Šóó°ëTT”uy|Xkccnccnmmvñâí/¿Ü‰ TTÔ,X7c„O×¼|ùš!‡ªnmm†%ЫSíÒ«8:vWQQ:sæ5…*-½¿ÂËÕµµu,Ï3(b)ý T9ôç~ÿý…ŠŠ’¡¡Ž"­TUU""FóÍêêZ†ðêêZü?»W¥êV]ý$11ûÉ“:ºnuužººªƒƒ‡/^ü…z<úÂ…[ÆÆºzzštŒu}}=rrŠ÷ïÿ!0p¨²²„ðÂ…_ÎûùСUë×Ï õóôtª¬|  ¿|¹œ:çÎÝ´±1§§é+h ÃKBuÖÐP›wLÌöGž鄆ú­\ X±bÇ/¿<¸vm;—ËÑ××JM]8zô²¡C?=ú“áÃݦO_ ¸wo¯¬êô&®Y3K[[cñâmOŸÖü±]\\ÐÒ¥i.—3vì ÂÂËôÇdBEEWýýc++÷ÑSbd­øÒ?º¹ÙÑ5ÿè#}„@QÑÕ9sÆ0ÂY­`eTT”ŽùêÀ’ÌÌ‚õë³›šþÐ××rs³ËÎ^1fÌ .—ë†n|¾ÑåËiëÖí‹‹ÛYSóŒËå89uOI™?uêg¸ð¶m LM³æÌÙôìYC))‘!!Ã%½äã㦥¥îèØÍÖ–ôìi±}ûâ„„½Û·çhûû8>ÅÙ9¤´ô޾¾`ùòÀÅ‹·UU=±µåïÝ»lüx/†±Eê.–‚:»ºöèÕËRM‡÷4X¼PP&‹Œ\·HšCIær9;v,qq™¾!8x¸dIÆ‘õëgkjª‡‡oxþü¥«kÏ¥K§ÄÇïâñ”¥*F B‡eÝ2 ÿ5 ètG+ÑVnß®vuý¼²r¿©©Þû^ˆE>}câÄ•÷ïï“õd„÷ Îø·²š7cæÌ­Î{¡¨èªƒƒ~ BhëÖcK—¦¾|y‡—ða½d¦iþÓ{áÿöö]§MlØpà_ÈÜ€®_Ÿ=• ECë¼¼ ›S¦|öŸ\à@:tfÊ”ø+WÊ(È>C§á?±Ï€jlüÃÝ}v^ÞüÞ§÷Gaá•uëö%1ÞuCøw@ÕÕ5YYMÒ××Ú¹3 ÿþCG+õ^hhxµdIj^Þùºº&ssÀi**JÿU{ ÂÿoÈ>Cg…Ä †ÿDÌ@ ¡#!1Cg…l@ 6HÌ@ @ Ø 1@ @`ƒÄ @  3@ 6HÌ@ø—‰Ä'ž?Ù.¯ê’”V_ßdkPQQsüøçÓªªß‘ƒ’[žÞB¨  ÔËkžP(z[ñÏ“edœðôœ§«ëËã øü Ó§¯½yó×wö BèÙ³†yó’»u›Ìã ôõý¼½”Ê­õV^R¼.õ‹E¸ „^zq8Ÿª¨|ÖµëÄÐФúú&–Zmѹí(n.C·ÿñxKˉ ¤¼zõgÇÚB Â;@b¿žjÏš•øçŸÍm뼤4„ТEÛFþÄÆÆL èûèÑ! #E&âBöòŒ¶ „Æ}¬©©žœ|ø­&ú¡–¡¯oÔ²eþþüqó½{{33£_½úÓÝ}ö¹s?¿CØ€ƒÏ>[xíZEffteå¾Ó§7:8XùúFƒÍ=s¦ ë Uº4ÀÆ}|>64Ô²ÓHäWDs\×ÝÝÞÐPgÇŽ“’3EY­´´““„‡¢ÊÃ;wFå篥¼ºjÕ.+«I<žÀÆfjRÒ±˜Í«ššê€œœâÖVnBxölò™3›p+’§‰qÞgÍJtp¢´mnn50ð[·n?Bˆå¤ ¯8:«ª lmRRŽbýé&˲E²ûAÕÔxØR»Cç… ·~ôÑX*=L,þ¿öî?®¦ûøû}o¿D¿»ýX·”U*%d+¿›ÄÂ$ó;Ý!ý¢ù]ÑÑj¥¹•‘¢I´däãG"&kDõI$RRa£î½ïïïíì~îSÛwfôz>ö‡ÎyŸ÷y×¹ÇÞ¯ó~Ÿ{I¯^3֮ݭ0KL0ò}2÷k÷îüþýçihx¾ûîÌC‡Î;v±oß¹´å‰%ÒK‰”¥EÙt̽æp8 ‘H$¹¹E,Ÿ:Ú^,–DFîâó'khx¼qc:‡óÁ½{žx¥ fèÒ:|v‹1 Š sbbËË÷øû›;wÓ÷ß_B…†&ÄÇgÅŅܺ•ä·uëaæÀøø,¡pIIIr÷î³f­—HÈîÝaã+WRîß?HÛ^;>ñرhKK`Caáµ={«ª2NŠÅOšôE[›ˆ¢0éÞÄbÉáÃgGŽt‘¶Ê ×./‘ê±GÎ,…òð•uF~q޲³\¿^õäÉÓѣߓ6ob¢¯§§Eg0-JÈÈ( —TT¤oØðittúºu©,± `ãï?6::ÃÔtÒÔ©‘ññ‡nݺ'=1"›dVUÍ™ãuãFÍÕ«4{¹¹E­­¿£B oJ{ûo#õ°°ä•+}oÝÚ»hÑäÅ‹³e2É~-ÒÉ/-­Ú´)cäÈþt’¡Ã˜çÎûðaS~þeóéÓ?Þ½[?gŽ—Â,‰Å’ó°y󾸸ÒÒFsæDGFîJJZRZºƒÏç ë%’ÿ¹Ëìi‘ÁœB$^‹ŠÚíé9PG§»L3…1¯\™”˜˜°¨¼O~Ù …@rÏì™3 ¡#ç·Õnîðe æ }{»ÈÃcñ;§Nuwwïг¶¶ÁÏo=ú}±¾zAwq8–yeä°D..—Kwò,ýúYkiiž:õãÀ½iÆŒŒtŒt !ô ßÇ™™‘¶¶|éÃù|ÞÏ?W+Œ-::ãåËöÕ«´OKK“å˧kh¨…†&47?cn3¸—¹M”Ÿß興í'N”ܾ}O__‹>¼‰ÄÊn “(™»¯¢Âeövx-={[Y™Ê$ŠÒɘ§Nu_¼xkfæ).Àa\WIDAT—Û½»Æ„ C¤“ÉR‡}r¹œÿ½ÑJ ÎÓ"¹F;; [[óñãW¾|Ùž•µN¾¥|Ì´P!D6fീ÷º4ö÷!}úXbŒ/_¾Å \&O^ëèhÅáࢢŸ™í.”ëéëkIÞáû´Í… ?Ÿ;÷ÓÁƒë¶l \°`Âðá}«ªêB„ &¦«É“WÅI÷FW××7uæŒ,è0ré÷uÎÎ着ªHÇ\\|Cñ9€Wæº4ŒñG –HN+Ûkb¢ïçç–lh¨cooqäÈùììs¹¹ÑÆÆzÁ˜°°díþýmòòŠ…ÂœèèÏd—þ“~1ÎÅ‹7èºmé6ÆÆzãÔÔ<]݉äÈ‘ó_‰zþüW;; …¨ªª0½õîm®£ÓýÚµÊaÃúJŸQfàÅ‹¶'Ožòxº\î3 Gü,‘ÓÙŒñõëU..½¥Ÿ¬³œ…³zõ'eeÕ®®Ÿ>e̘÷ôô´n߮ݽûûýûO½÷ž®n=ºùùyFDl×Õí1x°cqñÍ… ¿™2Å]Uõ³ÈĶr¥ïÑ£ÜÝC׬™íêj/‘HNž¼²zõŽU«êêª&&úÞ&:$=ûC_ß/Ÿ?‘šº’na¹)ôÀ°°d=½NN½²³Ï%%MM “î–ÏçýÙk¡:³¿ÿ¸Aƒ9Nll0û²´Î|\;¹°­Ã´Èþ¤-[6ýøñ‹+V$7ˆ¥%e` 0!""ÅÐP§_?ë¼¼âo¿Íf x¥ fl0ÆBá’µkSçÏßR_ÿÄÖ–¿wïª?|!´mÛbSÓÝ!!ß444ÛÚš'&†Î›7NúX™A˜««ýر®Ÿ|²!Ì´ÁÛÙY¤¤,‹ŽNOIÉ54Ôñörþ|b¿~þÅÅ7íì,ä3æ½çÏ_0½UT¤üñðüüKÒ¯É"¹åL%ÞÞUUÒKb”=ñUyEEú;ï‚ JBB&É”%ÊÎBƒQSS9|øËï¾;šš·yóþ§O10Ðvuµß¿õ¤Iù\B()i©…EZxxÊýûFFº LX»v.KlF—.%mÚ”¹«¶¶Ëå8;¿›˜ø¹¯ï(ÚXþ6ùû•Ï’——«¶¶fß¾½ìì,è–޽͕Ým„Ð_–-ÛV]ýÐÎÎ"=}Õ”)î2iì̵(œÝêdÌ..¶}úXvë¦Nç4X²„}\öÉÒÕaZä/‡é™ËåìØ±¼ÿyAA±s玕o)³eóæ--Í  ØÆÆ—Þ+VÌŒŠÚ£®®ª00à•ÂÊþ×Þ6#RøºƒxUnܨqqù´ªjŸ©©þ«~K),¼6mÚÚÊÊ e?@^5ºâßÊjzdä™bõ­QPPâèhE¿†‹òí·GV¬¶´§å%¼Ø]érLðVƒÿ÷€·ƒCÏY³!ž™93êòåò;wfgŸ[¿>M €×溌·zžÒÚú‹›[@NÎú}P¯N~þåM›2 bd¾ëü3!MMO­¬¦hïÚµ’þþÃëê•hn~¶|¹0'ç|SÓS>Ÿçç7:<|–ššÊÛz½€7Ì3tUP3touÍ€Ô ]LsØ@Í`5€ Ô 6P3Ø@Í”"„ˆÅ’íÛ56¶tز¡¡yÑ¢„^½f¨«{L=zi^^1ÝËt"ó%]„£G/p8TW?øË>yòÔÎÎïöíZBH^^±»û"‘HügûQÆøÃß×ÒÒLH8ô§zko) þàÁ3!e „0ÁÃ÷åàí5C—Æ<é¿wÌ@™eXŒ1>¾ì§Ÿþ»ukè°aN|>ÏÉ©WLLààÁ}¶n=Lûa:”9VCCÍÔÔ@E…û׆ݥ¥Uû÷ŸZ¼x*ícáµ§¹ùY'ËBüðá}ið_$¼|ÁÃÿ"xƒ@ÍÐ¥IƒåÙã  !S1v§ó _~™fi9M]ÝÓÞ^œœKë --M„Pfæ©öv13|?{6áÌ™oBÞÞ´.w$-QV­Ú®«;N_ÿ£„„CtyݾwoA¿~þžÎÎþ§OÿHË%‘‘»øüÉžC‡oܘN‹BH\Ü/¯÷ u˜ qssàñtwì8._„(\J„1f‚ok1Ûið2øSÁ3K›ÿ7Ý@€Ô ]šÌèY~ïž=áã+WRêê²B¡¡ ññYqq!·n¥ùÇчñØøûŽÎ054ujd|ü¡[·î1ÅÃîÝa´“û÷Òž ¯?ŸxìX´¥¥‰ôã㳄Â%%%ÉÝ»kÌšµ^,–BV®LJLÌNHXT^ž6eÊ‘‘©´±X,9|øìÈ‘.2•‡Ç€¬¬3_JäâbË?eʼ² t>x‰„ „”ðQyÝ€×FKË !$KBöö:’nmýã =ÆXW·BˆÇÓ11Ñohh s’’–z{ÁûTTÔFGg„„LB%'/>ÝãÀÓ'O^¡oxzܹs…™™¡t'´çðp¿>},BG^)*ÊßÍÍ!8Q ØÐØØ¢®®šphëÖPŸa¡… 'UVÖ&&f#„nÞ¬imýÅÉÉŠ"³£c¯;Ž‹Dbé%OÌR"…©HIYÆŸ•õ„ШQ.,Á;8ôDåæÉïêj¯0ø‰‡bŒ-ú˜ à ó ]×Õ«)W¯¦ÄÅ… „òò¾¢²¬V*+«–HÈ A}hBÈ!NB¨¼ü.BÈÒÒ„ÏçÉ¿æ+ý§D"¡ÿ Ïõ1ÆtÏáp¢£3^¾l_½Z@·[Zš,_>]CC-44¡¹ù™ü©•½ôÌá`™€~q*!ˆv˼”Ìápdæ¸\.íJz; üš5ŸÐ?--M–-›Æ¼Â¬é/“1€7 Ì3ti¾Ï ½ÑÑÑŠÃÁEE?3Ã÷ ÊŒõôõµjjnÙ²ÿáÃ&™¯HÒÔT×ÔÔP8pW8Ï ¿ÝÙù]UU•¢¢Ÿ™y†âât—™™!B¨¾¾I¦ÌxðౚšŠÌüKhð<–IKð çä·3Á3c‚xƒ@ÍÐ¥aŒ?úh°DrÚÜÜHáÞnÝÔB/Þ¨­m06ÖÆ„…%ggŸ«©©OJ:*æ,_>!´r¥¯ŽNww÷Ð}ûNUUÕUTÔ …9«WïXµJ ¦¦"݉tçvhLˆˆHÉɹPSS/æ|ûm6mÖ»·¹ŽN÷k×*e*Ÿë׫\\zËê‹m<‰Ä2í™à32~ ÁoÛv„=øNŸçç7:<|–šš }rßÒòÜÍ- 'gƒµµÙ‰%›6eÄÈ|ÿÒëBiiy.<¬Mð¦‚y†® j†.ã­ðo5CWk“l f°šÀj¨l fJB޽Àá|P]ý Ã–"‘˜ÏŸ¬¦6ª®îñ?öe\‰"K¶o?ÖØØÒù+béíÉ“§vv~·o×BòòŠÝ݉Dâ¿7æ?‹é¾ ¯Ô @)Œ±§çÀû÷š›±F1ÆÇŽ]|ò䙉‰~JÊÑì·:!Æ8/¯ø³Ï¶üúëK„P'¯ˆåŒK—nóñfkËÇøáûZZš ‡:ß›trþ–!¾t'ÿ†_¥ÀÛj†.yæ}ïÞ#… 44ÔLM TT¸ìƒQBÈÎÇÝÜ||†¥¤ä¶·‹^M¼%BB3ªÆwòŠ”)-­Ú¿ÿÔâÅS™_žŽˆð‹ŠÚÓÜü¬“Àß>ÄÿÛ‹P3ti7¥½ìÝ[àè8[Mm”‰‰¿ÿWÍÍϘÛâè8›‰óåËvCà ›6í£ë¬Ö­Ûce5]]ÝÓÆÆ7&æ;‰„–$.×û††:LêÜÜx<Ý;ŽË — 1Íòó/÷í;WCÃÓÎÎ/11›iÃ’ù]Òs¸|ðt—Âü09Ü»· _? OggÿÓ§„ò ¨º4ögÞÒ{+*îÏž½qÊ÷ŠŠôƒ×ÏÂÂ('gƘ6HHjjÞðáÎff†¡™3Gmܘ^VVݧ¥Â£”õ†jhh s’’–Nœ8!4±¢¢6::#8ا±±%5õûää¥'Å/]:­­M$=J'9`Äç~ý¬Bff†ÁÁ>Ó¦­mhhÖÕíâñtLLô™önn=ÓÓ \\lBiiùcǺš˜è?zÔœœ|´  ÆÝ½BÈÜœWW÷ø‹/v„‡ûݺu·µõ''+Bˆt–{íØq\$K/ybÖAɤi°~ý§3fŒÄxß¾}/&&3(h"K˜]ÞÞC0ÆÁÁ>Ì.¦s&ø#œ1ÆFLð**\eù¡ÇFEù»ºÚ#„' [ŒõþÒ' o˜g躮^M¹z5%..!”—÷ýSÙj¥Áƒ'O1~Œ©é$_ß/oÞ¬±·· O¯OŸþ±ªªnútZE̘áڶ툲£X¶—•UK$dР>Ì Æ!N}­›[àìÙÑ!‰D¢,³g{íÛ÷ƒH$~ô¨9/ïÒìÙ^¡ÒÒ*±X2~üJ--/--/mí±aaÉÏžýZ[ÛPW÷!ÄãéÊd‰ÇÓio=zÔÜ™÷˜¬º»÷£í !ƒ9ÖÔÔ?~ÜÊžº‹9ŠÙÅtί­=–ÆÏßa~¬­ÍèÔÑéŽú'_JÀ¿Ì3t]66|„Pyù]„¥¥ ŸÏ“òJÿÉáàÌÌ57oÞ=~üâ?\6ìÜyüĉ-¡;#„‚‚bƒ‚b™öii'6løT[[SáQ\®‚Þòó73ãWfXL‡Î‡Î‡Ð gBD"±‡Çâ;wNêîîÞ?  gmmƒŸßz– øùŽˆØ~âDÉíÛ÷ôõµÆsC¿¡33#mmùÒù|^eå}ŒL \.—¦Hz»2L¦=Ƙ^¦Š —%Ì.™£8œ?*–à;̇ùÞg溴οÏpöìO_[[›-Y2õøñMññ Ož¼òøqkSÓÓÇÏNž<‚NSÐÿ6mšÿìÙ¯{öä+;ê?ÿ¹.¿½©é©££‡ƒ‹Š~fž²_¸Pfl¬§¯¯Õ§%Æøòå[Ì`zòäÕT).ü|îÜO®Û¼9`Á‚ #F8WUÕ!„QüõDccc½ñãefžÚ·ï`Œªª ƘžèîÝzkk3¾ ¿¨èÆš5»BtñU}}“Ì<ÃÕÔTdæ:Ìù¥Kå̵œ;wÝÆ†¯£Ó%Ì.æ(fÓ9<ÜÚÚŒ ž%?Ò9ok€<˜gèÒ0Æ}4X"9­l/óï=ºmß~L"!‹Omo9rÎÎÎBOO+!áЋmË—ÏprêÅ4¶µ5Ï sÒÒ"¥¬7Œ‘@0&,,ÙÀ@»›¼¼b¡0':ú3„‰‰¾ŸŸgXX²¡¡Ž½½Å‘#ç³³ÏåæF3KhŒõ0Æ©©yºº=$É‘#ç¿þ:!ôüù¯Ýº©#„.^¼áææÀIå³gèëûåóç/RSWÒç÷ææF~~žÛuu{ ìX\|sáÂo¦LqWUåöîm®£ÓýڵʡC¤ç®_¯rq魢•Ià‹mOž<åñt¹\ŽüÜHXX²ž^'§^ÙÙç’’Ž¦¦†aŒMLô•eÀØXOÙ.ŸÏS!$?ÿò‹m ~ óux‹ÁÚ¤.Ö&àÿ Ö&uU0Ï`5€ Ô 6P3Ø@Í`5€ Ô 6P3Ø@Í`5€ &ðà]Ư;¼ù`èØ%ýX¦/¨>-²IEND®B`‚java-algebra-system-2.7.200/images/overview-recursive.png000066400000000000000000002306031445075545500233700ustar00rootroot00000000000000‰PNG  IHDR®ôé½ IDATxœìÝy\MùÿðÏç¶/Z(”D*²$d)K²5LdŠŒ,EÙׯ¥BcO̯!Ù’-3–,ÃØ¿CC)’}7ŒYZîýüþøÌœïuo%­wy=þ8åsιçú|ÎûóyŸ{(cŒ”¥ÿL°„ç¸cæü3õ T9ÔQ˜SÌÔQ„PDP>(ý_ -.(ÔQPÔQ„BDU}PÅ@C'(2ÔQ„DPn04Š u@±¨;DPÁ„ß~P@¨£!ˆ  Ü¿õ €PG Q€ºCT…1öñcÞŠ»Zµ­§çQ­Z¯N&îÛw®\J‹%11‡_¾Ì.{iÜ¡C¿‹D]ž>}QÂ7xðõ)uþéèô¨_ßgÚ´599c|…G2Jw<{ö$È”Ïÿ¹ºŽ“.¼Þ7RèEü²ýâ÷=@!¡ŽBõÔQ„B4«ú@U|úûŒ±7oÞ{xÌøð!7,ld«Vöïßçnß~|Рùáá3fø”eW”Ò£G/Ž³â«¯Ú0Æh™SB¥Û’”&¬Ÿ˜¸®n]s>ýñcÞÅ‹7§L‰zþ<3..¤GÖϞś››”â…òÏž]egWGz‘¶¶–ôŸe?÷âeg¿+ê"NŸî]Ñ{(O¨£PG@±@… ”Κµîõë7ÉÉŒŒôyÕ¼dÉè¼¼‚ÐП.uëÖ,uáŒ1¡M*—J_º’4Â ææÆµkWþ´±±ÈÊÊ™8ñ‡µk§U«¦gaQ£ŒÇcföIùòÊå†CZ~~Á¾}碢ö=»Š"\Dcc¾ÂÒ¥c„‹heeîæ6i„tÒÔÔ@ Juê( "¨o߾ߺõø„ „æ–B)=Û÷Ô©ÈZµªË ïˆ,Øfc3XG§‡½ýЕ+wK$Œ1vðàï"Q—á­lXØfCÞ7n<öò fŒY[{SêÎ+js>Šw²E ]ÝNNþ§O_á{ÌÏ/Þha1@OÏ£Gé·o?&.îd³f#´µ»×®ÝßßyVVŽÌÑÕoljD “H$¿ür s b±$,l³•Õ@]Ý;NXºt‡|†€|3VÂŽïwëÖã-[èêö°µõÝ·ïÜáÛ7¥£Ó£qc¿'’…¢cÿµxqœ­­ï„ ‘íÛ7#„ää|àQhnùšÂE$„´oßl„H[[ߥK,2Y-1(ÔQ¨£þu!Q”›Oß#-íann¾«kS™ÃÜܤ}û¦ÚÚš2 ÕäÉ«üñäºuÓïÝÛ±dÉèeËv,X°…RêåÕ>(Èë?ÿYûôéßgϦ-Z´ý‡&5mZÛ¶`JiJÊÆôô½„B7Ê_µjïºuÓ““7è~ûíb±XÂ÷{dýú·nmóôt ÝÄW¾wïÙˆK r¿woG|ü‚ÿþ7eΜ 2g!sð|¢ @œºpáÖ=ZK7QÅÃìÙë׬9°zõäÛ··Ô%,l ‘#Ÿ+s0ÅŸ{DÄO‘‘¯^µ¶®9rä²°°Íë×O¿zu“••¹ŸßbÞ6§¦Þ=:¢^=ŸÎ……|òdwxx ¥T¸ˆ2wÒqÙ²1Ožì ¹ÿYkk婩÷åϠꡎB…:  XÈ ‚ ‘ýŽbjjøÙácÆØ‹Y6:yr¥»{ BHݺæé靿ÎÝräâ¬Yë==]å?™c¨QÃhìX¯ffÆ-ZØ=š}@fµ—/³ÿúëµL9ü‡5¸Rœ»|?œôŸ;;¹¹5ÿãç|~1‘§ Ü»·£~ýÚò'+sæ Eƒ:Jþ3A æ@9¡îÒô”ÒêÕ«?¿féÒ¸Ù³×ÿñÇsmmÍV­îÝ»€?¸&1¶~ý këíÁÁŸ={Y³¦IP×wß"„Ì›·éÆÇ—/oÔÔÔ033^·nzÿþ¡_}Õ¶ÿN_Ýnøð¥„{÷vµ¹ô.dvºdÉccÃÿügí‹™mÛ6 1kÖzBHË–vqq¡K–Ä99ùëëëtíÚê—_–‰DÅý¾‡ð§††hÓ¦™-[Œÿ£F}-š2s""ÆV«¦?~üÿ½|™íìÜhÖ,ß… ·éèüï@nn“d?fJ³³KÏùÒs—o€å3’…F´F £B/b¿~ùVŸonê(ÔQP,Zè0"À£T&m>ëäÉäfÍlø‹„cÑÑ?Ïšµ.;ûˆ††j¥öQwôÃAÕCõåPG¨Õú  <cññg|}^ºtûñã¿ømñâí~~_©ZsKðûJ u€ºÁX”—3U}Ê'++gæÌužýú­••ù°aÁÁßʼ>I%t®ê ¨£Ju€ZATå-.-.(ÔQPÔQ„ ƒ*œªu+€jA@Áo©© ªñ$” ÔQ•Qº*÷Ö‘º—s ÎPGT.d@ÃÃK ÈPGB@¹ÁÐ<(2ÔQÅB|ÞºuccܺõG^^Aݺæ^^BCýLM ùq:aŒž%0Æ44ºÆ iC¤šd©uŠßª5!’‚S[·ïÔÉѾ᷄1![7ÍêÔÉÑήu)¦±X²uëñNþáv„Ðb÷N©;!$‰Ö’Ó"Q—¦?·ÕgæðwâŸÐ¥Îs* ê(ÔQå0@í!*€ÏX¸pÛüù›54DmÛ6655¼|ù^ddü¹si¿ÿ¾FSSC¶Ñ•ê£ôßß½MZÇZ7¢…­SèV}ûv „˜FŒ%¶–-ü¯_”˜¸–INBZ:ù_Xž˜¸–úšÒç0ÆZ¶ ¸~ýQbÒ:ÚÆ¡¨}ñ5ÿ9…ĵ|ï|ºø­J=Z˜ „PJ% !dûöã—/ß“H˜î‘#቉kœl…ö騱¤Ž'èëehØÓÝ}òùó×É¿cìÖ­':MÔÓóptyòd2Ÿ)u‰ºüøã¯|Q“&Ãú—F©;¥î—.ÝÖÐèÊWnÛ6ˆÏä+´mÄ=z”Ñ¿h^ZZÝ,-¿?>òÝ»Œ1ù5ÏKëÒeŠAOccϯ¿ž•’r—¯À[Vé;aZ~~0>äÚØ nÑÂ?;ûŸÈÍͯðË öPGÔQP¡¨!BKþ÷öíц ëÖ¬iúôé>‘™ù‹DrZ"9=þpþU¡”š››ôë×qíÚiÙÙG$’Ó|ÛcÇ"44D”ÒŽ[µjH)54Ô{ðà'‰ä4oÀôõuÝÝ[X[×¢”V¯nôáà ‰ä4/ÓØØÀÍÍÉÊÊœRZ­š~NÎ1a«¤¤uýúuäÓîî-úõëØ¯_G¾ÿS"9ݺu#Jiýúµ==]ÌÍM(¥žÉi™5ÏœY¥­­%‰:thæææ¤¡!20ÐMK‹åÇÏ×LJZ'URÒº¢6áŸÉŽs)¥sæ &„OãŸøŸP¨£PG@¥C½ –>mq%’Ó}(¥k×N&„&D,>½fÍTkéΪ:uÌ„æ§cGGJéܹ~|ýQ£¾0ÀíÔ©ÿ°ùó‡K$§>ü‰7Ÿ×®mšU¾èÖ­m|M^f¡M ß—Ðó}éëëRJ.ôÏÊ:|÷n\däÄÓ§#eÖ”HNwéÒ’R;‹oµeËJéàÁ]åצ…Mø:Â&ÂgââÒDSSã·ß¢øÄùókÐâ”ÔQ¨£ Ò!ƒHzú«˜˜ÃººÚÝ»;ó ?¿¯„öU$¢ãÆõ½ukÛ½{;6ož=rd/}}ôôW&üÀÛ§Ë—ïB<<Ú0Æ!›6ÍÜ»wA—.-É¿ƒÝ]»:B¬­kñïÜÇyä߉/²³«Ã×äÃÜÒCäÂ4Ÿà[ ›Ožü clîÜMff^>>ß½|™Åï ¤×$„$%Ý"„Œ·øGŒXJ9{6M~Ma:)éclÔ¨pžE0bÄRÆØÙ³i|©HD'MúF,–Ì»‰O„†ÆTʵPG¨£PG@%ÀÓÆ@,-kL™2ðûï÷<ø;ŸX·îàÔ© !—.ÝY¹rW~~Á¾} mm-mm-GŒèéåÕaÀ€¹ÉÉw˜Ô3pb±„7>äêèh‹Dÿ4f„==mBŸCþ}ZŽOëéiSJ555„v”H=NG>}´ŽH=È'/èÝ»ýÞ½gRÓÒ¤¦ÞߺõøíÛÛy±B! #„tîìdjZM˜©¥¥)S¦ô´DÂ(¥nnÍe6Naýúƒ" õ[°`‹HDçÎõ+ÛE€"¡Žf¢Ž€Šƒ± |€»qãz‹oŸ:Õ›O¼~ý–R£†Q|ü™~Û°á¾2c,5õ!¤ví꼫E ;BÈáÃx'Ö! Œ¿^±b“zH®˜/>Qhß!D$QJys.Ì‹%Œ±?þx>nÜÿ-Z´Í×·{ròú{÷v0Æž>}qÿþ3òoÛ)K!ÎÎ !={¶Û·oá¾} ‡ ûªysÛ¡C{sTÂ&û÷/Ú¿‘° _aÏž3gϦM›æýòe6ŸpwoQñ @M¡ŽB•’{’±„¤¤uZZšS¦ &øü)S -kŸ>í›6­O)‰D;vÌåù¬‡-åíbûöÍÚ´q ”èÞ½WLÆ­|ö­ôšÒÓµj™RJ´oßìÝ»ãÒfgiÑÂŽRjllЫW;{{+Jiƒ–?ž”ÙpïÞ…üYÃÖ­uëÖŠÿ„ùºuÓ‹9ª#G‹ÚäÇ66Í›Ûfeæ>œý<ñ?  ,PG¡Ž€J‡ "øG›6yyÿåÓÂclåÊñMšÔß²åØõë®]{hbbؽ»óôé>­y_—§§Ë‹/Þ~ùò] ‘»{‹Å‹ììê¹ÁtV‚aw™éðð ¹s7ݹóÔÊÊ<3ó­ôŸoß¾?qbEpðÆ_~¹pòd²‰‰á AîË–ÑÑÑ’Ù°]»Æ‡‡/]wùò½ÜÜü¦MëO™2høð¯Š9ªž=ÛÊo2bDOBˆ®®öÇ?ñÕ„ ¨h¨£ê(¨HŸ¼ÔE¡/Ý„rDÝ þg”ꨊ†: äà¹u‡¨@Ý!*Pwˆ Ô¢u‡¨@Ý!*Pwˆ Ô¢(½˜˜Ã"QJÝ…FF_wï>íæÍ?ø«³oÞüC$ꢣÓãíÛ÷¥~_ÞãÇÉì…ÿ‰º\»öðöí'"Q-­n99Ê÷ì@ñUN-ÄëùZhÀ€¹¥.“1&K¶n=Žw‰€‚ЬêeÅ»té6!¤I“únnÍ !â‹ož:ueРù×®m¦”¼yó.0°……™¡¡¥´t{IL¼E122ðõí&½HKK³iS›íÛOðc04Ô+‡³åQɵ©i5Ÿ.Ò‹úôéPê2SSïDèþU)J(wˆ  ”(¥‰‰7 !ß~Ûcöl_Þ4¾|™]³f¿[·þxô(ÃÖÖÒÅ¥‰‹K“2îåÒ¥[„¶m¢£§Ê7ÀÂRÆXéšgPR R •®Ì~ˆ¿råÞŒ>¨»@A ƒJ)'çà !NNv¼IcŒ½zõ†Úó?Û·/u‰ŽþY˜ŽˆØéållìilì¹xqœ0tÆÁa˜¡aÏ  •—.݉ºØÙùò¢’’nBZ¶´—o8…¥­[;B²³ßÍž½ÞÞ~¨®nKËofÍZŸ››ÏKHH‰º4nìß Á}ý¯úô™óüyæÄ‰?ÔªÕßаçŒÑÄP:•\ 5iR¿ÐZ(/¯`Á‚m ÓÖîÎó—ÒÒò¥ïßç.X°ÍÁa˜¶vwKËofÎ\——WÀ³±¼mÛ ÆXDÄNoï0ÆØßgM˜imí­£Ó£^=Ÿàà?æñ½[Z~#uÙ³'ÁÅe¬ŽNž¼ôóÏçùÒ7kiuÓÒêvíÚÃÊúà@5!*€Ò`Œ¥¤Ü-(3Æš7o ‘°œœII·‡ [L)µ³«ccc‘Ÿ/¾rå!¤m[a:4tÓÛ·ïÛ´iôöíûyóbŸ={É;~ü’Ïw÷î=óðhsôh’¿ÿrBHÛ¶ !âË—ïBoû½ô¿ììw¹¹ùW¯>à»xóæ}çΓ–/ßibb8xpW±X±3$d#!„·è÷îý¹víÏ..Mrs󾨦M`RÒíví¿{÷qåÊÝfTÝÇ _¬Òj!¡žqp¨'ß}@)3&",lóÇyß~Û£^½Z§N]8pcìÝ»]»N Ûüþ}î!Ýc+Vì ÉÍÍwssâEùûíç÷Õ«WoÚ·ý³¶¶¦O—ÜܼeË~ ZIyòäÅ_½‰hPÐ÷ææ&ÁÁßöëבRzÿþ3J)¥tæÌub±dìØ¾ÍšÙTîUƒ "( JiRÒ-J)c¬nÝAÒ‹ÌÍM¶n ¦”\½z?77_WW»ysÛ«Wïü˜GY´ÈÆ Ÿ÷ïs«UëÅËÍÍ'„,Z´16uê +Æ&'ßiÛ6ˆâì܈rýú£÷ïscgÏ^={öª°KK³èè©/ÞÌÏ/Ð××iÖÌ&8xcZÚÃ~ý:ÆÇ/ ”;–äé9;.îdDÄØääÛ„fÍlΟ_£¯¯“˜xëÑ£Œ–-í÷ï_ôîÝccOBˆŽŽV%~~PV•V ]¹r/?¿€1¸"0p…°—€Ï f0FúõëÔ¡ƒcÏžm­¬ÌÏœ¹ÚµëÔgÏ^BV¬Ø•”tÛÆÆ"9y½‰‰á©SW¾ûnKnn¾ŽŽÖðá=·o?aiYcãÆÿB¦Nzð ½iÓú.Dè^½ú U«Ñqq'W®Ÿ”t‹"‘°Õ«'óg«æÏßüóÏçªÐºu#BÈοBÆëgbbH)íÖ­U·n­¤ÜÅ¥ ßÑÏ?Ÿ'„Lž<ÐÀ@—âà`Í‹Ù_½æk¶oß”‡Œ1>&pïÞŸŒ‘™3×B,U½zµ ÿÄ@Õ!*€Òà½t„‘#{ñ&vøð¥qq'®Œ×—Âã=ômÛ:Bø´‡GkÞ^¼x“Òºu#JɳgK$ŒÒ¨Q]BÈÇé„ ‘³sCaÃ6m y˜˜R*½‹¿þzM)ýæ733caSÓjÏŸg>yò‚Ò¹s BHbâ-‰„™šVãíý… 7 !mÛ6ÆÊ¥’k¡Ž }ÔxôèˆíÛOêyzºtéÒêñã¿^½zÓµk+Bȃé|ïòuWJÊBHÛ¶MxQzú+BH³f6|ÍÔÔû”R‘ˆZZÖàçèåÕ‘×Q”ÒæÍm !fìÚu*-í¡““íèѽQƒ@Ùá¹(ŒŒWüV›÷uQJ¿ûn¤††(>þÌï¿ß ÿü6È-òïsÀ|ÚÅ¥é¿îñôhLÑÖÖâ3y s˜Ò¤I}}}aCgçF…>ä'½ [[KBˆ‡G›µk§­];­^½ÚÖÖµ|}»ó‡ jÕ2mÐÀ‚RÊoÚ¶uàåñ0iÓF¶ÙWɵ‹KÓBk¡={!;wÎÿñǹþþ_óÜ!>&`jZòæÍ{ÆØ;OÍ̼œœüÿøã9c,9ùù'&¡”R>V™šzŸ¿Ä`áÂm„¯¾j[­š~JÊ]BHÇŽŽÂãÔvvuôõuÒÓ_þßÿí!„DFNÔС€²ÃX”¿ÕÖÒÒtvnÄû¨ll,ú÷ï&<üÇeg¿»{÷OBHÛ¶…ia¸œÖó¦ÚÆÆ¢AËG2úö nÒ¤þ¡C¿BÚ´iDyûöí[B®ð´AãÆõ}}»ñޮϚå;jTø¤I«NºüäÉ‹ nÔ®]}Ø0ÞÏçâòOŸ\RÒMBH»v¥cJ§rj¡W¯Þðz¦}û¦…ŽXZY™ß¿ÿlãÆC·o?Ù´é0J¡eK{BȰa=¾ÿ~ÏèÑÝ»;>|13óí€nõêÕ"„dd¼"„,]—žþrèÐî&ôŸ>=zêÔ¨³g¯>x~éÒmss“U«&ݸñøÝ»šš-[Ú c"iÚÔ&)éÖ¥K·îêæÖu” Œ@ið_ïnÞ¼žž¶Ðƒ5fLBÈ/¿\xð =)é6cÌÔ´š½}©i+ÆØë×oïÜyJþX‰èO?ÍkÒ¤ÞŸþÍk×®1!¤]»&„ää; ã?²nÝAáßúõ‡þúëURÒmJiÍš¦66µ)¥#Fôܾ=ÄÁÁzß¾s·o?ñõíváBt:fB oPùD»vMceð¼£6m ‹EV9µ¯g455„®iŒ±-[æ4n\ïðá‹7<¸+sxûö=!dñâÑ3g&„ìÜyÊÜÜxùò µk§ñæÌùÖØØàÌ™«bBÈ”)׬™booµÿ¹G2†í~ñbtƒ|˜Âѱ®®¶°wJ)Ï520Ð BÝå…âgÚÕ¥„%TõAü#(heݺµ¨^Uü¡šPN+åfŸ€BÚŒ4TSJ Q( ëiûR¸áPpˆ ÔùÜT¢P2?û­> ž2€òRÏØÕ€J@TJEhrä!•|kô©ÞÙ¨*µŠ PM¨ D œ„@Uû¨Ôä~@…©ö‹ ª)Uƒ¨”“ô‹…9ªD¾¡UÉÁ•§Â±ª)ÕBþ÷‚2Rφ=s øÔ³~P~x_€ò@C  àTrL ð9(!DJEõ^‡ 2ÐGÎáCPNˆ @ ¡éPdè¿PBˆ ” š[„Þ ø4” ¢å„ÀÊ¢P6è#è„P0¨—@ù!*eƒ¦—ÃçåQ@` T¢¨Hx @ *(- ”~9 @ *€Š‡À@±!*P~hkª J€ÂCTJ·¿J yDŠ Q(tËm-@åCT:¨¬¢•€Àâ(†¨à a  ÔÐ… ¨€’@üYhk* ª£2Be x¨´µ àS($D*m-(Œm(Dªm-(TV Q(=€²CET9ЋP¥€Àð&@•BTŠ ýsPµ0PP™TDêQ@0PPù0\PE¨JÑЀr@`P¨ôw|) T-• Q€Ú@÷( Äc•Q(*Ü¿@Â@A•CG@åBT NÐÊ€rA•PY¨´²Ÿ…E€«P‰€BÂØ}ÅÁ J#œ•Q€úA+ JU@¥@T î€âAŸP%@ß(TYQ($ä¾W´² ,Ð.T0Dê M,€ Äɠƨ1 Ê!Q(ü&)T T> Þ¨7 ¢@ÿ( ” ú2*¢P*䨈 @‘ »*j%…À \!*eƒ@ ¼!*5†å…<"€r…¨ Úæ*‡&”€òƒ¨Ô þ…¨¤ ã ” j-€r‚¨ä ‰u€•À < *€Oá> ”€²ATrÐñ**W Ì€bÀ=(”º3ÊQí+¨6t-«*T\¥…¨†òÚWP"hJÊQí+(Œs”¢(ÚWP:èÑ(DPÕ>PÕ@±0\ª_f€" *€À½¨|І¨>)^ 2ðeV7J QT)SÈ?áGŽ2dˆ««ëàÁƒ“““ù:QQQ®®®ãÆ{üø±P¦““Sxx¸WÓ¦›7oÎÊÊæSJÿYäåËShäÏâÝ»w‡òöö600î¿)¥#FŒX·n]5йáþlù2Œ0¡««K‹ÅçÎRzÄbñúõë{õêåêê:jÔ¨ØØXù,)™E"cL"‘BrrrV¬XáåååââÒ©S§€€€””ÆØ´iÓcžžžmÚ´‘Î ‹Å111½{÷vqqùæ›oöíÛÇÒ ½ …î¢ÐGu õƒ "¨H&P wîÜÙ½{÷Ñ£Gmmm{öì©­­ÍoXåéèèFEEÍš5«E‹¿ýöÛÊ•+cÞÞÞ2…ïܹ388XOOoñâÅ¡¡¡‡‰D§OŸ ±··OHHXµj•°þĉ§N=¶o_|||LLL¯^½¼½½6lH)4iR``à±cǤ5jÔHØ–1vïÞ½üüüæÍ›ËôÖ›šššššÿ9”¤|aš—Ï{ôèQ\\ÜðáÃõõõ¥K[½zõ¡C‡BCC5j$sŽÒòrÄbñ•+WbbbÚµkW­Z5Bȼyó222,X`aañòåËÈÈÈ3fœ8qâ»ï¾›?~\\œ™™ÙÍ›7…¢V¬XqòäÉF;w.<<yò$..N>*;v¬££#!dРAóæÍËÊÊÒÔÔY³fMBH^^Þ­[·V¯^*=p÷îÝüüü-ZçØ²eK™¨€"‹“’’¢¢¢\]]gÏž­££Ã×÷öö>sæÌñãÇ322ž={öàÁBˆäÓg-<`Œ #$Œ1''§;w )XòWáKw¡R€:AT ¹¹ªe̘1#FŒ8qâÄÎ;cbbzöìÉ3g(¥….âŠD"á6”ßtÊ?ù*EOÓñ…m55ÿ×lÝÒ×ßýÝwÇ·±± úꫯ´´´øš·nÝÚ½{·ô"mmm™}ÙÛÛëêꦥ¥5kÖLz¿ÿýwhhh```Ë–-…ýîØ±CúÀnß¾ýÙòù„………¥¥%ÿÓÖÖöãÇáááÒ?**‹eÎQþ) ‹:uêBêׯomm=eÊ”¼¼¼ˆˆBHAAAPPPzzº‡‡‡³³óÀ_¼x1wîÜ¢® p+/!|w"‘¨¨« ‹¿h*¨DPÁÐÙ¦B(¥:::}úôéÝ»÷åË—wíÚåçç—””Ä—òE}úôIIIá‹ù¢ëׯ׫Wßq¦¦¦Z[[ó®h27ÄöööZZZ)))666|Ûëׯÿ³L$Þ¦û»wQQQÂí»PÈðáÃÝÝÝ£¢¢ZµjUÔ¹èèèxzzîÙ³§_¿~úúúÒ@jjjÍš5¥Ó¤ÇJR~¡ SJ e²•6l¨©©™––VÈ9~Z _êââ´fÍšýû÷÷ë×ïêÕ«©©©[¶liÖ¬_mãÆ2û•fkkK)MKKkР_?--­zõêFFF…/ßÙÙ¹U«Vœ¨¨(###;;»„„„½{÷†……U¬ôŸFFF¾¾¾ÑÑÑÆÆÆŽŽŽçÏŸçéCÜ,-- -äÀÅ?-À7n\rrr@@ÀèÑ£›4i’}ðàÁ]»vMš4ÉÊʪ˜sÿlù¢ÌÌLþÔ5cìõë×{öìéÖ­›ôÓÆÆÆÆŒŽŽ611iÔ¨‘pŽò¯w&üüüΟ?¿jÕªŽ;Ö¨QƒRzèСjÕª1Æø°Æ‡ø~¯]»&]N5z÷îellìààpþüùøøø‰'º/a“¢vQô§«ZЩêQT< ¨®BïË !”RéE‘‘‘éééõë×_´hQ÷îÝ ÝJ>yfüøñ‘‘‘™™™M›6 ü')_"±,ú¦¼¨£’9B##£ØØØÍ›7¯^½:##CKKËÁÁ!""‚?ø[ŒÏ–ÏO„*ð9ZZZµjÕrww3fŒÌÊS¦L100à/8kܸñðáÃcbbdR’¤C/ yóæùúú.[¶lÅŠ¡¡¡[¶lÙ¿¿‰‰‰»»{llì!C®_¿Þ­[·:ÌŸ?Ÿ2}út¡¨9s昙™EDDdffZ[[Ïš5«ÿþò/¨W¯^Q»066.þs%Bå«`€ À 0/^´³³333#„0ÆöìÙ³jÕª3gΔïKÇŠ‡·˜AC:æ§„W={öL~©ô›†¾¨´bÞÃú¥rss·mÛæëëëêêÚ©S'ÿS§N•K÷ÁYccþû†ÎÎέ[·nÛ¶mŸ>}Ö¬Y“››+ý±³/¾š³”Ö­[»¸¸ôîÝûûï¿/æ=¯ä߇&÷ïßÏß9UÌU(Ó9VL± Âc¿þúkHHÈ7ÒÓÓ6mÚäéé‰*2ˆ*•Ì3‘2¶k×îØ±c¦¦¦%üõôbJ+œœœqãÆåææ:88|üøñÈ‘#³fÍš8qâ°aÃÊR>cŒ]WW÷³ç.œ¯©©)O·à,--ß¾}»|ùòàà`ƒ¢¶6/ÅG]¸‡ƒÒ©V­ZhhhU” 2!Au!ƒ*˜ÔžŒ±ÌÌÌM›6yyy…‡‡Ë¼ó533366VX$Ì¿pá‚««ë€vïÞÍïY…ü>qäÈ‘!C†¸ºº<899™¯SPPåáááêê:~üøÇ e:99…‡‡{yyÅÆÆò<á…E›7o^W$sïß¿?tè···ôOF2ÆFŒ±nÝ:þ;$E}%)ŸEé_SÑÕÕ%„ˆÅbé "±X¼~ýú^½z¹ººŽ5*66V>KJæ—E"cL"‘0ÆrrrV¬XáåååââÒ©S§€€€””BÈÔ©ScžžžÎÎÎ2»‹‰‰éÝ»·‹‹Ë7ß|³oß>^l1W¡Ð]`¬ 2 ô‚ª…*Õ…±€2¹sçÎîÝ»=jkkسgOáWïÞ½+³HúGE¢¢¢fÍšÕ¢E‹ß~ûmåÊ•Œ1ooo™Âwîܬ§§·xñâÐÐÐÇ‹D¢ˆˆˆÓ§O‡„„ØÛÛ'$$/IåyÇŽ‹‰‰éÕ«—ð†©‰'Ê/jذ¡ô ú½{÷òóó›7o.º@)555^a[¨–ÿÏÚ2J)c„‡ÆÅÅ >\ú‡ !«W¯>tèPhhh£F¤ÏQf§üs–H$W®\‰‰‰i×®gæÍ›—‘‘±`Á ‹—/_FFFΘ1ãĉ ,˜?~\\œ™™ÙÍ›7…¢V¬XqòäÉF;w.<<}ú”ÿº9¿•×ÑÑéÛ·oß¾}¯\¹2þüŸþùÒ¥KüåG|‘——Wjj*_”œœ,ì‹÷BŒŒŒJ‘ S’òù„íØ‘têTPPŸŸoii9tèPé¢rrrvíÚ5sæLwww~ŽþùçîÝ»¥×ñññ277×ÐÐÐÍÍmòäÉ|Gü™fþVÝš5kz{{Ï™3'33³Zµj„“5jEeffÆÇLJ„„ð£ôöö~úôé–-[„¨@þ*˜ššò]ð°§V­ZÂ.¾ôse…ÀT¢¨0êQcŽ=zïÞ½¡¡¡ èß¿¿‰‰‰Ð‡-³ˆw· 7ÇÎÎΚ͛7ÿé§Ÿ²³³e ¯[·._‡wY³fMBH^^Þ­[·V¯^*=p÷îÝüüü-ZgÔ²eK™¨€"‹“’’¢¢¢\]]gϞ͓‘!ÞÞÞgΜ9~üxFFƳgÏÔ£Jå€<"PEˆ Ê$00pĈ'NœØ¹sgLLLÏž=½½½(¥cÆŒ‘_Ä;° !<žß†òPAþ‡…Eœôs¶ƒŌ±Û·oïÞ½ûøñã666AAA_}õÏY*t‘–––Ì#ÑöööºººiiiŽŽŽÒó_¾|تU+áÀøËM·nÝúlù|¢N:|ÚÎÎîãÇáááï߿֋Å2ç(Ÿ¯oaaaiiI)µ±±±¶¶ž2eJ^^ÞòåËùæAAAéééÎÎÎ|ñâÅܹs‹º‚­¼„ð݉D¢¢®Â—îTòˆ@å *(+>}úôéÓ'%%e×®]~~~‰‰‰BÒNŸ>}z÷î}ùòeaßêúõëõë×'„0ÆRSS­­­¥ŸñÈôÙÛÛÛkii¥¤¤4hЀo{ýúuaéðáÃÝÝÝ£¢¢„Ûw¡aQË–-‹ú mmmOOÏ={öôë×Oø%¤¦¦Ö¬YSºïßÚÚZzó’”/L å0Æ eÖoذ¡¦¦fZZZ¡ç(_ ««kPPК5k8Я_¿«W¯¦¦¦nÙ²¥iÓ¦| 6úar¶¶¶”Ò´´4~ÕÒÒÒªW¯nddTèÁB„]ðÌ"ÆØÆåK†ò„Û/PLøf‚ ATPnœ[µj•‘‘!ÿ“£ü•[éééĄ̂¨(###;;»„„„½{÷†……Z¦L7¹‘‘‘¯¯ott´±±±££ãùóçyúwàÀ ù{_ÆØ,--‹?~Jé¸qã’““FݤI“ìììƒîÚµkÒ¤IuêÔ)æ7ˆ>[¾p"™™™ÂÙ¯_¿Þ³gO·nݤŸ66668p`tt´‰‰I£F„s”Ù»tháççwþüùU«VuìØ‘ÿVÒ¡C‡ªU«ÆKHHàÃ>|àû½víšt95jÔèÝ»wTT”±±±ƒƒÃùóçããã'NœXèÁ ›µ‹b?`P-È#Õ‚¨*†ºvŸPJ‹¹9¶´´î/"##ÓÓÓëׯ¿hÑ¢=zU ÌœñãÇDFFfff6mÚ400'å³ëâJš±±qllìæÍ›W¯^‘‘¡¥¥åààÁü-j«’”/l>|øpþ§¦¦f­œwÿ1cÆÈ¬<&&Fúœ¤ ä?K:oÞ<__ßeË–­X±"44tË–-û÷ï711qww2dÈõë×»uëÖ¡C‡ùóçB¦OŸ.5gÎ33³ˆˆˆÌÌLkkëY³fõëׯÐ}qõêÕ+jÆÆÆÅPêZŸ€@¨BvÊjI(!¹¯ c,11ÑÎÎNxCÂîÝ»W­ZuæÌ‘H„7…©#Ô' Èx¥„¯((?¼Å ªš\ÂÕ¯¿þróæÍôôôÓ§OoÚ´ÉÓÓ!šBH ßOP+€ €V¾È§_þæ„~øáìÙ³ÙÙÙµjÕúúë¯G%“Aêõ (|QAù!*€ €Ê¾¾3P(|1@‰àë JDêQ(üÀÈCÏ+(Ôc ä@@C¥ƒ”š?Pfˆ @1 5i(¨\ˆ @a`ü Š *Ń€Ê…¨ † ª¢P< @Ù¡eƒ¨Ê*A(;¤Ž€ ÀÈ'(DP~ð›!P^К€ @UJQ( ÜBTD 00ުà<T $@9A'”êPm @á!*¨HˆxA *€ª†PyÈ#…‡¨Êj:¨Pø‚€j@m Q”ôóAÅA›jÃ@¨ |ÏA±!*¨èㆨ”šRU…PC¨Í@!!*€2C£•M)(;´˜ ¨(÷ÊQT|ÙT .(”#¡×€%ü;Çs0çŸ9¨jJQ”Úu¨Lø¾©\M(G”þï.@¢‚’AT„ŠQ” Úu¨dxì¾nTJF³ª@Õ©Ešã;噃zƒkêB IDATªÔŽ*;\A(wH(䆅lÕÊþýûÜíÛ4?<ÆØÑ£‰cƬøê«6e)G ]cì³eò(¥/®­[לÏüø1ïâÅ›S¦D=žÒ£GëgÏâÍÍMJq„BùgÎü`gWGz‘¶¶–ôŸ%9ÚRcŒ½y󾨋8c†OíWm!*¨`ÔID•Œ16kֺׯß$'o066à3—.“—WããÓÅÊʼԷ³”þï'Ëå¶Xº;¿$¥ ë››Ôæ×¯_;++gâÄÖ®fd¤/½¨tÇcff,_È—íí· @¼oß¹¨¨}çέ¦” ÑÈHŸïkÉ’ÑÒÑÍmÒ„  褥…{Ú²BT @%ÊÉù°uëñ !!„16{¶ï©S‘µjU—éž/(/X°ÍÆf°ŽN{û¡+Wî–HcìàÁßE¢.7þÂ× ÛlhØóúõG}û†0Ƭ­½54º³9Ï´‰‹;Ù¢…¿®n''ÿÓ§¯0ÆcùùÁÁ-,èéyxx̸}û‰p0qq'›5¡­Ý½víþþþ˳²rdÎNæà¥ç‹D"‰„I$!ɧ˜c‹%aa›­¬êêöèØqÂÒ¥;䳘äJøÑñýnÝz¼eË]ݶ¶¾ûö;|øbóæ£ttz4nìwâD²t±ÿµdÉ[[ß "Û·oÆ{ûö=¿ˆBHÀ÷.\DBHûöÍ&Lˆ´µõ]²dG‘ ]È5-D•­|2äŠ(YHs,{iœæX¬D¾¾tbQiŽ¥;ž={dÊçÿdÒ+á-嫊Û#€rôéo¥¥=ÌÍÍwum*sÓlnnÒ¾}SmíOú•)¥“'¯þñÇ“ëÖM¿woÇ’%£—-Û±`ÁBHŸ>®AA^ÿùÏÚ'O^œ9suÑ¢í?ü0©iÓú[·Î¡”¦¤l|ö,žRÔæÜªU{×­›žœ¼ÁÀ@÷ÛoK$Œo{dýú·nmóôt ÝÄW¾wïÙˆK r¿woG|ü‚ÿþ7eΜ 2í‹|o=¿;?}úÊÂ…[{ôh- s ³g¯_³æÀêÕ“oßÞ>hP—°°-DŽüh€ÌÁî?EFN¼z5ÖÚºæÈ‘ËÂÂ6¯_?ýêÕMVVæ~~‹Åb c,5õ~@Àòzõ|86òÉ“ÝË–‘¾ˆ2Ç \DJixxà“'»ÃÂFîßÖÚÚ{ôèˆÔÔûòg%Ñ– öiúP…fÈQJ½ÈÓ«v@31qÝgÓKq„BùgÏ®*>ͱâr¹ŠËUPYø•+;û!ÄÔÔ°$uòóç™6:yreçÎN”Rkëšé靿ÎÝ(ì¨\ŽVºð>üDþ­%…?ml,„4ÇjÕôJæ(hföIùòÊýá§üüžæxöì*BÈgsU…4GMM  •Ù)Š*‘™™1!äÕ«7vvŸicW¯>‹%½{ÏÖ‹%?æýùçß XèëëÄÅ…¶mhii=U¾´b6çÚÙÕá‹x«‘Ÿ_póæã‚±‹K¡§¿CG´oßlàÀÎ+CBbºwwöòêðÍ7n2íšÐÜÿò˲:uÌ Ä¿þzyΜ mÖ¬™ª¯¯#šòÇpûö“¼¼áFœ1Ö©““LT°wï ,¤çÔ®]ý‹Î½I“z|‘.!ÄÆÆ‚~¼+,l$RATPÁŠHs,&CN˜É+4WRêåÕž§9>}ú÷Ù³iBšã¶mÁ<Í1=}/ùÂ4GžÛ÷EiŽEURDê½ @œZÂ4G~ %Is,þá§Ïž{ñiŽ<~HM½?zt„tšcxx ¥ô³¹ª”ÒeËÆH§9,Gš#¨;ôÕAåÒÕÕ6Ì#:úÀ›7ï…™”Òï¿ßuþüõ:ṳï›6­O)}òä9¿ñµ³«sáÂÍùó7óîÞýsÚ´5aa#½½»øù-ái-ÒŽ°¹p-½¹°kéMš7·ÕÖÖÉ(†/‚ ¢JU 9Bc¬˜\=ù4Gÿ¯IiŽòY’| ú»¸4!…¥9zyµ'„ðÃbÒ‹Ðü¢4G™cÒû÷ïD™4i@YÒ‹:÷%KÆtîìD¤Òùa𿨱££ô9–$W•×e£Fõ9²ço¿]Cšc%áøûT4(€ª@)]´( !!ÕÍmâ¼y#Z·nôúõ›ØØ#QQûÃÃ4°±·²26¬GHHŒ‰‰aûöÍoMšôàAîZZùùâo¿]Ô¬™ÍÌ™ƒ³²rGN˜¹}{ˆžž!äâÅ›..MŠÙ\8™Î,SSÃ)S†„ÄT¯näâÒäèÑDÞÚB õbbK$lÚ4ïüü‚ŸþÍÁÁÚÔ´št›[hŠ/cì?ÿ|äÈÅY³Ö{zºÊ&2ÇP£†Ñر^!!ÍÌŒ[´°;z41:ú€Lá/_fgd¼’)‡Šs¥8w™ÖSæ¼:wvêÜÙéñã¿øVÅ\D[[KBȽ{;êÕ«õ™d]4 %ƒ¨ R•0CŽB)-&WÏÆ¦¶žž¶tš£|ßyIÒùVòiŽü¿(¥´ø4Ç¢Æ MsÔÓÓ–?MùcÒ…c¨ 4G¾_!Í‘¯YL𣙙1?ž’çªþýwÒ«j„+•@îA5j?¿féÒ¸Ù³×ÿñÇsmmÍV­îÝ»€?\ûɦ”®_?ÃÚz{pðÆgÏ^Ö¬iäõÝw£!óæmºqãñåË54D5þŸ½û‹âjûüœÄJQAcWŒFÄ€ ‚ ‚F±E±ƒ5ŠK"–„ £ˆhLb¢Ñ ~*‚â+vDc‰1ÑX_#+mÏ÷ljóŽ»Ë²RwÙß}yy-»3眙9ÏœgfªY¬_?³ÿÀž=Ûôïß©wï¶~~_Ñßç5»¼ •ö~þùKËÊŸ~úÍ£GimÚ¼»hѨٳ¿%¢V­mÛøùçÛZ¶[±¢y—.ïÿüór‘x#Í«q¬€1¦PЦM³Zµ7yòWcÆôV]CjmX¹rb•*'Oþêñã gg‡Ù³‡-Y²U:ÝÎ9ws›¦¾¦ÿùç€üÏ·]víA‚P¯^Mñ¢jÕ*¿DqêP>%¢‚b–GšcÛ¶ïÊ÷îý=|ø’  1:µ"~)W¯I“7BéÁ+ò4ÇNUjÖ2ûåË·ˆH¡Pѓҥ6HiŽ&&Š;]¹òçÿ9|øìÈ‘ŸGD8xp¥ÆTݺ¶õëÛQÓ¦uš4y§oßÏ23³÷ìY¬¾zÔÛ ¥9JmИæ¨VÉ'ËwÙMLòzÓ°“Z´hôgŸ ß¾ýÈš5QK–l:´ëäÉý[µj$}‰bxAªýþý'Ò—xîܵk£·o?òî»uƒ‚FÚUå.xP\pu¾Á×¥ªjÕ*+WN\¹rb¾Sš››-^ýôÓ!âÅ!]† 颥µŒ1•’¥÷7®ýìY¬øSLP¿¾Æ6pÎãã/Lšä³xñqL\»6¦bEóªU-ˆhÐ wž÷cXåµçµê´,»úŸZ–T÷/ ×”¨|3ää¿–\=ÎùµkwäiŽâÚ_i޳$¥ªå½a)ÍQºðHJ1LHH XݨQ­O>üË/+Dšã“'Oµ\a,ÞéÞÝY¤9Šk£Õ׉J¤4Gõ6¨Ì¥òN!—]=둈DšãÙ³¤4GÒ!W•diŽgÎ|+ÒóÜ„"„À@ß` @/1Ævï>6lØ’3g®ýñǃèèÄe˾9²§Ê »²{!Ýàüe‰âœç›!'yçÅæ¨ò³/@š£.šÚÓUÚ cšãƒOTÊyÛ4Ç·Ðìܹ¥››ãŸ>ïkÏU%¢7¾ÏL‰.P敱Žè¹¼OlƒFœóà`ÿY³Ö{yÍyòäiíÚÕÇï;wî‡e-$!*(fo¦9Š0írÎy¾iަ¦&66–NsT?ãþViŽ …¶{Iš˜(´¤9ª·A{š#©§92Æ22Þ¸åÂÛ.»–‹Ÿ¤ ¤Ž~¾¹ªHs,e¸ìXà[ÐWŒ1+«Ê6|²aÃ'¥ÝÐ îM E‰1œ½x[‡yï½úâagœóuë~š={}FÆ“²•ðÆÜÑa*^ J—ˆ«ñ@É9VÚ }…®n0Vú…s¾{÷±Ï?ß¶bE@õêVçÏßiŽe-$ ô–À`#7,e o§á cÅ §.ÞZzú³Y³ÖïÝ{B¤9ŽÑcîÜUñV&t.í ”"¬|ƒcèƒÛjw&øÆ tƒ¨ ¸!*€¼ *(~HbТ(³pÀÕI™ËÊ0emèC/!0 ×ç û)€R„ûæþï éàkœïˆœ©‡#íùÈ2ˆŠyÌš¤9–Dº0ô "Ã!Þ2ˆJ ö×%« ?ˆ Šλ€ñ` Ì(\WP"ô'ѰtßAš#Ò¡Ìö `˜p]2)KÒÊ6\ÂaÐp4,KpÀ…·‡ "(  ¢0&ÈzÐQÅQô\4ATFF~#,(((»bc“==?­ZÕË̬k>^^sŽ»XÈû”0æ.ý37ï^³fÿÑ£—gd<×}ÞÓ§¯–ú½Rti ç\¡ðP(<Äd …‡|ÙË—ï^·îàI“¾JK{ª{™Åw& ‚‚¶E‘“S#[[ë””ß÷ïÿOllòöí  èÄ ]sÎÅŒ;·´´¬”‘ñ<)éò–-ÓÒžFG/Õ^¦4/¬ö¢Â9÷ñéHDÖÖU´´„±7îô(^»»;YYU&¢—/3OœH]¿~ï;öîýœˆt) øàΤ¸[ ÂÒ@àôvQÁš,3Þ<>|®{÷™ææfÑÑK==ÛQffö¨Q_ìØqôwjܺµ±vÍs'¢ääõ..D´oßIoï¹Dtÿ~”­­µö2åóê×™snbÒ…ˆNúÆÅÅAzݺuSñéÉ“W:t˜LDwïî±³«Z”K„.¼=d€±Òû.@) ÝCDÓ¦} B"277 và@pròzñëILLñð˜^©’§¥eŸÞ½gŸ={]:Õ(’a~øáp§NS+TèѬ™ß¾}Iœsq¾_tÅ‹=\Ä‹‡ÓÄû/ÞìÛ÷3 ‹Þ+öìØqʧD™òy}| 3ÂD™ÙÙ95jø(ÿ÷g9çyÕ.ÊÑR¾Høùþûÿss›V¡BGÇ1çÏßX¾ü{û*Uòôöž÷ßÿ¦‹å©A¹¹Ê  - 33ëZ©’g›6±±Éôz¬@ªWz-þgŒ995Kôøq©¤)*‹ •³eËA‡*ôps›öã‡ÅòãÖÆQfœsÉ”…,SÊ)T(<äÉ”ùŽØÈw@…iCáéÞì¤@¯á,Z‘À@AÙ•””JD]º¼/?BU¯nåéÙÆÖÖšˆ/uë63!!¥U«FNNââNwî<-5õ–¼ë?iÒ— …ÂÆÆòêÕÛÇ/}ñ"“ÞìsÎãâΑBÁjÕ²áœ_¸ð[ûö“8Õ ]ëÖM“’.{yÍùá‡Ãôf'{ìØ>D´cÇQ¥’ÑáÃç?Ψ[×¶K—÷éu¼¡^»Žå¬655±´¬”šz«K—K–lmÞ¼žR©Ü·/iÑ¢HQ¸¼»º'((òñ㌞=[שSãÌ™kÌw)Œ‘Z%^+•<=ýÙʕۉÈ¢bãÆµäkFz­²ÏŸ¿âœïÚulÔ¨/®_¿ãäÔèåËÌ€€/å%¢ 8ç‹oíÕkÖÁƒ§ëÕ«Ù­›³™™éþýÿéÖíã={ \¬”_èîîÔ¯_ûöí›§¥=۲堟ßçùþ˜å; ÒMúbŒy{wðöî`m]Eû%VØI¾ÃeÇyKOFD––•Äž|âÄ/å'¶Îœ¹¶hÑæììœððO×ÄLJlÚ4ûÅ‹ÌÏ?ß&ï4OŸ>0>>äСÕDôìÙËß¿G¯;dzf­0`¾‡ÇôAƒÑt®VÍ‚ˆfÏþöåËL?¿ž.l:vì멜ó™3׿ääÊ,½{·­UËæÁƒ'GŽœ#¢]»â‰Èϯ§B‘Oíº”?kÖÐÇ¿üöÛO8çééÏvìX·jÖ¬¡DtáÂo*#Däââ°|¹ÿ¡C«÷íû"!!”sþòeæ< Mý6m kë¾AA‘ff¦¡¡•/_ŽÞ Äki8çOŸ¾‹°zõÆØ´i$%­MN^?lXWy-†¨@ƒ#GÎE–/_î—_Vœ=»áÀàßÿqð`Ü\åǯ§% @Ú‰¬X³ìèÑ]»‚ˆhïÞ¤žè8/•ö%VD½4:zi£Fµò½Ä ;)€² eš%=zôoÂŒ£cCoïârX±oONþ•s>fL°@5ê ÎyBBмÓÜ¥‹35jTK¼™™™M¯;ÇññbbŽ'%]¶±± è·iÓ,1Kbb ÙSL6z´'çüÁƒ'7nüE²N¶‰‰bôè^D´}û‘¬¬œèèDÆØÈ‘žùÖ®Kù­ˆÈήš(§k×÷‰ÈÖ¶*eee«tìØÂѱÁ?rs›V¿þ1AVV6iêè»»;¹»;•+gÆ{ï½úW®l1¢»z™âµ´b±—.ýND¸‰7}}=pŠ¢ ¤dÊž=[‹_Z¹r¦R2¥BÁHS2¥˜—ç ¨r¾ŸsÞ£‡‹xñðašx¡žìÈ_gJóz{ÏÉ”¢F•dJ홈y•O¯~´'SʧԒL©~@Oa¸ :9Qlì)±3Ÿ8Ñ;:ziTÔiß®TrÆXçÎ-}|:Jÿ:txOÞÁ­P¡™˜(¤7éuç89y=çñYYÿw÷îîuëfT®\þ=†¾Ñ‡æüßLv)‚˜`ôè^Œ±¨¨„½{O¤§?ëܹeýú5ó­]—òÍÍÍèß°W”c.? ©ãfÌëÝ{vRÒe__Ç¿RïÜË_¯XpäÈWññ!+š§¦Þš5k=çʯ+T(Ç355á¯É¿#•NEQ~ý`”h %SÊœòdÊ„„õdJ»K;#¹€*û¸¸3Œ1E­Z6DtñâMõdÇ<¢²³’)ss•œs•dJ-µëR¾ödJõÝ–ÆdÊþyAØIA`P((ë¦N@Dááû¥ÔÙÜ\åÆû¥}»³s"òôl+GŒèéèØpøðî*G y7]”#ï˪TÊkÓæ]"úî»81Ydd,ÙÛWkܸ6½yd)¾Ï?þx-ùùyе׮{ùg×øfxø~"Z´hô”)ý¥ÚŇê}ñÂÕµù† ŸQttbHÈníkIåÈëäÔˆˆ¢¢Ä›ßHþ)@!*Ð@J¦?ʼn¿”?väôé«R2åñãaÇŽ}-%Sʺsųf­ïß?ÐÝý#)™ÒÆÆ’1&%;ž?"%;ææ*I¶ƒÈ+™Rì´Ô®KùR2%ed{ÊËË•16q¢÷ĉÞôúá)D$.8îܹ¥µui.33Sé,Éséõ¾ÿ{…–æÇ¯HÉŽ¯'&yò]Òèѽ–-Û•àéÙ&=ý™»»Sƒv${î£ÆÚu)_J¦o¾¾+¿õª´„s>cFXhh”‹‹Ãˆ=V­šäê:Ij¤ú€aéÖ͹[7ç¼>íÙ³uÏž­ÕßgŒ)•GåïpÙóѸÖ'‡2Æ\\~úi™ÆOUæ½ÿï§O_,}(ßÚ‰HÇò[·n*/Gê ¨OéìÜ$9y½Æå%¨´Š1V±¢ù¥K›5–©Òfù¼›7ÿòèQúW_MéÛוˆ¢¢‰¨fͪ ;Œh %SFE%Š=7W¹aÃÏR¤.%SFE-‰ŠZ"%Sj<“¡å<ç\Jv“EFÆ2ÆjղɎòyë×·SI¦”ú÷Zj×±|©=\‡aS•dÊ×þ7q~/ÅÛ*€áàœ?~iðà öí'geå´iÓ´cǥݨÂ9¿}ûáœ9||»t™Ñ£Ç'#G~NDƒ¹—vÓÀàa¬@ƒŽ[^° bàÀ-[6¬U«zJÊÍ»wQÍšUE2¥—ל¹s7îÙsÌÒ²Ò±css•ß|ó±üÔ;i:Ç/?Ë®0Æ–-çá1=22öܹëVV•/‰dG…ʼD4vlŸ¸¸Óýõ_ ‹JbèS¥XõÚu,?¯Ù5¾Y§ŽíÕ«·Gú¢U«Æ‰‰)&& ñdÂXƘ™™éÏ?Ÿäœwëæ,Ž¿FrÐaŒÍ™óavvή]ÇNž¼Ì9Õ®]}ð`ùóG–vÓÀà!*Ѐ18ÂÕµùš5Q'O^¾råOkë*ݺ9÷íÛ~ôhÏÊ•+¼óNõýûƒ¿øbWóª IDATÛ¹s723³›7¯7}ú ?¿žê 6ôfçX¥Ë®ÂÕµùñãaK–l=~üÒõëµoß|þ|¿=\HSwßÛ»ƒåßÿãëë^©Ry飼jgŒéX~^×øæwßÍ›8ñË‹oŠdʳg¯íÞ},1ñb÷îÎ((ƒpë!ÐmÛ¾ûüyli·¢t”+gºt鸥KÇ•vC ¬aèºc¤5ÇQqÎÿüóaÓ¦#²²rBÅý¡K»Q:`îèO6De˜ !O8àÂÛÃXá9~üÒš5Q‰‰)"™Ò`B0t Ê.D†s®’L‰ ˆ¡ï ÆQaŒs2%@I/@` ë LÃIŒ¢5xÚ± ”uˆ ò€ÀŒ¢Mpj\‚#€¨ È#£¨ò†ã€;“ä w)£ÂÜK»PjäÇh£]pãd ßµn¥h6èdh…C €Þ2Ð+D³ ®ñ"$0¸fƒÎäÇ8„8)zΕʼnqìô±[)IØÞÀ@aÙ ˆtÞÚà.þ1Ж˛j@͆·ë ô¾Ÿªç¿=4Œ„a¿‹„Q-,q.¯llŸ†²cQi¤¡4Þ2ˆô›žçðéyó=olN¥Kw¤þ¨ÁuL¥Î´ÁµŒ¢(»¤ƒzrP$p(]eòü´þ¤4®výo6¼=DzL~FA{zÞ<9ýo!в×#0ZBCÙɗɨÊDúJcŸþÐóæ©Óÿ@^ÊvZŸPe !*€2ªlBŒGÙØŸk_ ýìaç»æõ³ÙPPˆ ô’žçðéyóò¢ÿ-(uø€*!€!ÀI¡p âŽÊ%úß`ÐB}O®ç»wõ¶éÿ"èþf½j6¢ý“o_éþöô¼y‚A4 ]ÙÛÊÞè YzõÔØì%Ê4dé=ÏáÓóæéÈ  P‚€QB`…Wƶ"œC‘×¶Š  pA¤Oô<‡OÇJK=EGcí38 i(è=ÏáÓ½zÒ`I;§ ú£ÌlZú³Ÿ€R‚ "(sй’Tfƒ€ Ø *0nèf¢€ÂÂp>D`Ðoƒbe¸ À€`s(Nˆ Œ¢€¢`ˆÃ8ó ¯!*(: ±Å Q C<• †Å°º,èc€ ¢€¢ƒà ¢£„0 Ú(~ˆ Šú.`€€~C° Pü@áÖžÚ°Z eŽG ;DÆ·HM}ë‚ãF.DÅIßÂ_@IATÆÇ(1zub7DP8èah‡§Xe±[ýƒ¨À”áÞD`”p’J† @ï!*ãƒ3¦P*J10@L†\% Q@ñ+õÎM©7ô¢€QZyD( *(ë0PéC%Q%\ý ¥¢ä7 —°»×{z¾»Ôóæé¨l,9ƈÇËß§ÌOú¦uë¦DÄ9ßµëØ!A+š?{û–e»QròzÑ•OJºÜ±ã"úë¯ÝööÕÞjÞâÃ971éBDJåQY Üñ“"cœ{`]jm6èD¸´t%2vèõ cìÅ‹WDÔ¤É;“y¶l9èà0¢B…nnÓ~üñ°øTLÉzñ?çÜÉ©‘øèñã Îyn®2(hKÆÃÌ̺VªäÙ¦M@ll2ç\„DÔ¦M€‰IñŽ”¶Ä9¿xñfß¾ŸYXô®X±gÇŽS8%ýSþðÃáN¦V¨Ð£Y3¿}û’Ä\«£×c8Pæ!ƒ@W¢?kÖz‘ö“‘ñüøñKõëÛmÚ4KêÜ‹)Å0ÂèÑˉ¨mÛw_¾Ì øRŠ%T¦äœþùçù×_ïaŒYXTlܸ…†î ЬR¥bÏž­oÞ¼wæÌµæß¿åãÓ1&æ8½Nd’ .^¼Ù¡Ã”—/3XZVNLLñòšóÝwó†í"M9iÒ—-[6²±±¼zõöðáKïߪXÑ<¯ê,,*÷p5œ{Ј t%ºòññ¤wc¹¹¹·n=prjDovÐW¯ÞADS§øúë©D4qâ—ß~»dã œó6mäå—+gúQ… æDäââ°|¹¿»»SëÖgØÚöõ*ë?DE-)=+VH‰LR ³gûòe¦Ÿ_ψˆÙD´fMôôékfÎ\ëëënb¢SNŸ>páÂQ×®ÝiÖÌïÙ³—¿ÿ~ï½÷ê«TW£†ÏË—™üñÀѱ Œ2ˆt%Ò~’“×+•GsrŽ<|óÉ'ƒoß~4vlð«WY$K1"¢K—~'¢ÜÄ›¾¾oäI.»»;•+gÆkÑ¢Á•+[FŽì!fïÔÉÑѱÁ?rs›V¿þ1oVV6½™È$OF"¢ÄÄ"9²§xsôhO"zø0íÆ¿¤öwéâLDÕ³gffQÇŽ-äÕ‰)Euòò ¬BT@D¸´t"ïô›˜(jÔ°Z¸ped<¿yóåÑ–_B ¥é‹×+V9òU||HÅŠæ©©·fÍZ¯Tþ[þôékz÷ž”tÙ××ãðá¯ä%k,P|¤P0yS9ÿ_ä ½Y¡B9Ñ~y|2cF˜¼:y™¸®Š Ò‡ô ¢]©_"|ûöCÑi®VÍ‚Þì@‹œ¢¨¨ñæ÷ßR+¦l×®Ù† ŸrΣ¢BBv‹ÂÃ÷Ñ¢E£§LéÏÿ‡¤Úss•êcmÚ¼KDß}'ÞŒŒŒeŒÕªeÓ¸qmÒN¨T÷z‚7–Ê0\W +ч–®6ÎÌÌ>}ú*cÌÓ³MÍšUéÍë >ýtÈ€óCC÷œ>}533ûêÕÛòëŒå'þ‰hèÐ.ññçÃÃ÷ÏŸ¿©OŸvMšÔ®SÇöêÕÛ£F}ѪUãÄÄ…RÉÓÓŸQõê–¥O˜°ªJ•Ї­–ŸÈ_¶lœ‡ÇôÈÈØsç®[YUNL¼¤P°¯¾šbb¢ 7/qVi­Ju “ªÃ@€1ÀX€®D7:>þBLÌñ˜˜ã‡ÉÍUúúºoÝ:Wýì»OLjˆÙ ÚŸ?ÃʪòÆŸÒ›y;Òµ¢ä©Í›×{ù2s̘`¥’÷Ý<‡ŒŒç©©·.5`€%&^$¢àà€Úµ«_»vçÁƒ'iiOå#®®ÍóòjçΓ“¯¶oßüÀƒ¹ÓëG§å5V ¥:Œ@±@ú€žÁSÌôžžï7õ¼yo¥,-  µ§˜éŽsûèQz³fu½¼ÚÑž= ƒ-¬UËæöíßÉÆSÌ ðŒ|—k ‹o ÍÝ ƒà5qÁ1öwPc·o? ÚÂsss455IJºLDƒ¹|HP$°³Åô ¢€¢Ç9Ÿ3çÃììœ]»Žô¢MðÔÐcÿëñ”V×GTZ°íVe.lùF Q@AIñ@!CùŒ…ŒH H㈠Œ ¢€‘ºÑ…/G * 3{BlE éC†W¼%ñ@Áú=ÅÔ§/@±êsÉctéÊ:D:+Ú.r^}÷Âߨï,„ØÀ8 ƒ ¸àäT.!Pÿ´TzÌZê-À¬eäA!}À@ *ýÂ9OHHpqq¹{÷®ú§ÒG:>“[*íÁƒEÕÂÌÌÌ­[·6ÌÕÕµS§NcÇŽ=räH‘<#\4ÕÙÙÙÙÙÙÅÅ¥M›6^^^k×®ÍÌÌ”¯-u‰Éœe\\\Úµk×·oß/¿üòÅ‹ÚçÍÍÍŽŽNOO×þ-~‹¼Øâ%u…óZ{Å‘;T˜[”¦í³ 6€@H` Aú…Ézœs•?Û¶mkmmÍtë”h)­`ž={6iÒ¤ÌÌLÿ¦M›¾zõêÀ³gÏž:uêˆ# S¾Ô_ß²eKÍš5‰(++ë·ß~ NOOŸ;w®.Ë.>bŒEFFŠBˆ(33óÒ¥K«W¯þûï¿—-[¦eÞ¤¤¤eË–¹ººZZZJÕÉzSYFCRL™3ê!A1O-އ”!§ ,ÂX”œœœœ¸¸¸±cǪô9ç?RéŒ2ÆÌÍÍmllLLLt¬Q¥¢±cÇÆÅÅåää¨O)}¤ýlzhhè?ÿü³iÓ¦.]ºØÛÛ7hÐ`Ê”)Æ ûæ›o>|¨eÞ|Ë—ÖÚÚºZµj666ööö:u=zôÞ½{333uYv©pkkk›×jÕªÕ³gÏ &ÄÅÅ=þ\˼ÒìòU]T!©}¡@KÊÊ4oK—Yò=Ó¯cÕ»ìX—É”!ˆ  ØqÎÓÒÒ6mÚÔ¯_¿ààà–-[Ê{‡iiiÒGÒû'Ož}ú8;;«TÞ·oßvíÚ}ðÁQQQ¢X-ß‚Æ* o¬ 8úÜŪ¨.†Ñ«…€ "(^×®]Û¹sç/¿üÒ°aCOOOsss"âœ_¿~]å£råÊI3†……Íž=ÛÉÉéøñã«W¯æœûúúª¾}ûö¹sçV¨PaÙ²eû÷ïW(+W®|¸¼¨gÏžíØ±cÖ¬Yîîîbÿúë¯;wʧ‘ !¢ÌÌÌÊ•+»¹¹}ôÑG¢"qM³ƒƒÕ¨QÃ××wΜ9iiiUªT!"++«jÕªIE¥¥¥íÞ½{Þ¼yDäëë{çÎÈÈH)*Pÿ¬­­E"ì±µµ•ªxÛõV¢Ð£-<ù3’@;üL@Ï *€â5~üø={ö0 ÿþVVVÒ9l•Äév©sììì,Méèèøã?fdd¨þÎ;ïˆiÄ)𜜜[·nåææ¶hÑBš·eË–"*ÞIOOŽŽÞ³gOvvöøñãUҙ䩌 XYYQFFF¾àrÎÝÜܤ?ÄôÚË/BBBjÔ¨ADYYY¿þúëš5kå£ׯ_ÏÎÎvrr’–¨U«V*Q($777999,,ÌÕÕõ³Ï>ÉHDäëë{ìØ±ƒÞ¿ÿîÝ»7oÞ$"¥R©qYnÞ¼)¾ÑZÆXË–-·oß.åA© Œ±·ª¢ô¡#[„p-2HiDP¼üýýG·}ûöððpOOO__ߦM›2Æ&L˜ þ‘8MD"^tCE¨ ~¡­ô‘ ¿N@š×ÔÔTzóêÕ«;wî}zVVÖŠ+Äì÷îÝëÑ£‡³³óÀ=z4þü¼¾A©+/!¢:…B‘×·ð¶U”&=é¼–½ÎbCƒ¨Š¹¹¹—————×Ù³gwìØ1räÈS§NII;^^^}ûö=wîœô‘˜+55µ^½zDÄ9¿páB:uä×øJTÎÙ7nÜØÌÌììÙ³ 4󦦦JŸúùù¹»»‡……IÝw©é£V­Z©Ž0Fœ3ÆÊ•+×§OŸ]»vùøøTªTIš÷ûï¿¿páB5äçþëÔ©#/C[ùj "•Ã9¯\¹²ÊôMš4155MIIѸŒêººº¬]»6&&ÆÇÇçâÅ‹.\ˆŒŒlÞ¼¹˜fÆ W¦Ð°aCÆXJJJýúõÅ·–’’RµjU '"© ‘YÄ9߸q£zÉ¥¬¬vX‹ãV¤†ØÀ˜éÏvºAT%ÇÙÙùý÷ß¿ÿ¾ú-GÅ#·îÝ»'½faaѨQ£øøø={ö,Z´Hc™*§É-,,† ¶nÝ:KKË-Zœ8qB¤ 111vvvê}_ÎyLLŒ½½½öö3Æ&MštæÌ™qãÆ?¾Y³f{÷îݱcÇ´iÓjÕª¥åDù–/-HZZštAö“'OvíÚÕµkWùÕÆ–––\·n•••ƒƒƒ´Œ*µËC‹‘#Gž8q"44´cÇŽâ^Iûöí«R¥ ç<>>^ k¼|ùRÔ{éÒ%y9ÕªUëÛ·oXX˜¥¥eÓ¦MOœ8±{÷î©S§jl¼4K^Uh]Á%ýÔ’„ØÀ *€ÅÓÒ9¶··—ú—ãÆ ¹wï^½zõ–.]Ú½{÷¼ TygòäÉ•*U IKKkÞ¼¹¿¿¿HÊ×RµöVÉYZZFDDlÞ¼yÍš5÷ïß733kÚ´éÊ•+Å…¿yÍ¥KùÒì~~~âOSSS[[[ww÷ &¨L<}úôJ•*‰œ½ûî»~~~áááò;8É ·%]°`Á°aÖ/_¾jÕªÀÀÀÈÈÈèèh+++ww÷ˆˆˆ¡C‡¦¦¦víÚµC‡ .$¢™3gJEÍ™3ÇÆÆfåÊ•iiiuêÔ™={¶Æº„ºuëæU…¥¥¥öõPìÐ7--ˆ ô›†ŒdÐ/z>«çÍ+z¶ŒœóS§N5jÔHzBÂÎ;CCC;¦P( ïIa%FŸû£E»éÙ«>P$ô#Ô†¸– ±Í 3<Å ?Eõd¨"Â;|øð¼yó®\¹rïÞ½£GnÚ´©OŸ> òĘNO)†#¾ ñ½ùCÕ?•?4ð­JSyvaadffnݺuذa®®®:u;vì‘#GŠä¼¡hªHuqqiÓ¦——×Úµk333å«Eûsåœe\\\Úµk×·oß/¿üòÅ‹ÚçÍÍÍŽŽO®Ôò-~‹¼X€† "Ã9Ÿ6mÚ×_=cÆŒŒŒ [[Ûþýû3!qNºÈϽéÕÇZè ‹ŽÆÛ H¶mÛ666ÖÚÚZÇ_±–Ò æÙ³g“&MÊÌÌô÷÷oÚ´é«W¯80{öì©S§Ž1¢0åKýõ-[¶Ô¬Y“ˆ²²²~ûí7‘9wî\]–]|Ä‹ŒŒ…Qffæ¥K—V¯^ý÷ß/[¶L˼IIIË–-suuµ´´”ª+’õ¦²Œ†Q€aŒU©R%00°´b ôÿ€­ÿ-­rrrŽ9²cÇŽððp•þznn®ô‘ô¾úíÌÍÍŵþ:R醎;vðàÁ]ºt‘nĬþ‘‰‰‰–Û!„††þóÏ?Û¶m“nõ6eÊ”ìììo¾ù¦G¶¶¶yÍ«¹|YP*½imm-%=ÚÙÙ=zôhåÊ•3gÎ,_¾|¾Ë.-¯µµµô¾½½ýÓ§OW¬X1wî\é¾pêórYcÞvUëgd Ì@”]èpÃé`qÎÓÒÒ6mÚÔ¯_¿àà`•g´§¥¥EDDHIïŸ___ùÝŸ9ç£FZ¿~½Ô•×8¯.åK¯å·@UÌÍÍ•gåææ~ûí·½zõruu3fLDD„z–”JâÉ6J¥R<~~ÕªUýúõk×®]§NÆwöìY"š1cç¼OŸ>ÎÎÎ*Õ…‡‡÷íÛ·]»v|ðATT”(VË· ± Œ@™±ÝDJ@`y_×®]Û¹sç/¿üÒ°aCOOOé†Âׯ_WùH~°°°°Ù³g;99?~|õêÕœs___•·oß>wîÜ *,[¶,00pÿþý …båÊ•G7o^ãÆããã¥ç3ƦM›æïï»{÷îððð^½z‰'B2ƦNªþQ“&Mäô7ndggKÏ/—Þ·¶¶œÏKžå1Ù4ÒôRù¿ÿþû¶mÛüüüä÷\&¢5kÖìÛ·/00ÐÁÁA¾Œ*•Š¢”JåùóçÃÃÃÛ¶m+â™ Ü¿ñâÅvvv? ùä“Oâââ/^¼páÂmÛ¶ÙØØ\¹rE*jÕªU‡š7ožƒƒCbbbpppVVÖàÁƒµ| yU¡e-D:г ŽACèJ–Ã]Ò Lõû >|¸½½ýºu뜜œäï3ƤTF„É“'{zz2Æ tûöímÛ¶©G'NO4hЂ ÒÓÓMMMcbbæÍ›çææÆ6lØ;wăJDWÛÜÜÜÛÛÛÛÛûüùó .üé§ŸNŸ>-=,ÒÛÛ»_¿~.\9sFªKœÿ&" ‹dÂh(?&挦GÎTeffV®\ÙÍÍí£>‰kšˆ¨F¾¾¾sæÌIKK«R¥ YYYU«VM**--m÷îÝóæÍóðð "__ß;wîDFFJQú·`mm-ªa•­­­TÅÛ®7ý„¨ Ÿ~÷ á­é}l0~üø={ö0 ÿþVVVÒ9l•Äév©sììì,Méèèøã?fdd¨þÎ;ïˆiÄ)𜜜[·nåææ¶hÑBš·eË–òÇrÎÓÓÓ£££÷ìÙ“=~üx•t&ùG*cVVVD”‘‘‘︜s777éÏ„„1ýåß¿¯R¾xR£F "ÊÊÊúõ×_׬Y( ¸~ýzvv¶“““´D­ZÂM.™ IDATµR‰ D!¹¹¹ÉÉÉaaa®®®Ÿ}ö™HF""__ßcÇŽ%%¥E‹ò÷?~èïïÿþûïK Ï)—üú믪四«”/^ØÙÙÕªUK¼nԨѫW¯‚ƒƒ_¼x!M™››«²ŒêùúvvvöööŒ±úõëשSgúôéYYY+V¬³Ü»w¯GÎÎÎ|ôèÑüùóóú¥®¼„ˆê E^ßÂÛV`p€aÒ¿žbAàz•|ékl`nnîåååååuöìÙ;vŒ9òÔ©SRÒŽ——Wß¾}Ï;'}$æJMM­W¯qÎ/\¸P§Nù5¾•sö7633;{ölƒ ļ©©©Ò§~~~îîîaaaR÷]*Dú¨U«VÇcåÊ•ëÓ§Ï®]»|||¤;ùˆàÂ… 5jÔŸû¯S§Ž|vÕòÕ¶g×pÎ+W®¬Òž&Mš˜šš¦¤¤h\Fõ]]]Ö®]ãããsñâÅ .DFF6oÞ\L³aÃ+Shذ!c,%%¥~ýúâ[KII©Zµª………ÆÆ‘T…È,âœoܸQ½dÃ…¨@7†rxc g½C( òØ@Ͼzggç÷ßÿþýûê·ܺwïžôfXX˜……E£Fâãã÷ìÙ³hÑ"eªœ&·°°6lغuë,--[´hqâÄ ‘>$ÄÄÄØÙÙ©÷}9ç111öööÚÛÏ›4iÒ™3gÆ7~üøfÍšeddìÝ»wÇŽÓ¦M«U«––{å[¾´ iiiÒÙOž<ÙµkW×®]åWZ8pݺuVVVÒ2ªÔ.-FŽyâĉÐÐÐŽ;Š{%íÛ·¯J•*œóøøx1¬ñòåKQï¥K—äåT«V­oß¾aaa–––M›6=qâÄîÝ»§Nª±ñÒ,yU¡u D`89)6 ýÚ cZ:ÇöööRÿrܸq!!!÷îÝ«W¯ÞÒ¥K»wïžW*ïLž<¹R¥J!!!iiiÍ›7÷÷÷IùZªÖÞ*9KKˈˆˆÍ›7¯Y³æþýûfffM›6]¹r¥¸ð7¯¹t)_šÝÏÏOüijjjkkëîî>a•‰§OŸ^©R%ñ€³wß}×ÏÏ/<<\~'yⶤ ,6lØòåËW­Zmeeåîî1tèÐÔÔÔ®]»vèÐaáÂ…D4sæL©¨9sæØØØ¬\¹2--­N:³gÏöññÑX—P·nݼª°´´Ô¾ ‚†¼=Ð/úwbì zÞ¼¢eT «‡ô¯/XŠu£*Û[l™ÜŒçüÔ©S5’ž°sçÎÐÐÐcÇŽ)вù¤0Cü…b›AgxŠè=)oG#`{([c‡ž7oÞ•+WîÝ»wôèÑM›6õéӧ̆úczOÏãr=o^‘3¶å-ueû|pqoNØ\Ápˆ''|ýõ× ¶¶¶½{÷3fŒJQ™bˆ¿PCl3è QÞÓó_ ž7@Ÿ!*(rF¸È`¸ qs5Ä6ƒÎAPFá3¹Å"ÛR܃Ê}½O€žÃXºPTpŠЏUÉÀJ.@AÏ`¬JNëB1Á¸€Î@é1æî.Ú+1ˆ t€ "€·„±ò¢‚^Z 0 Žó‚œ¢b‚ø ¬ÀX”8ÄPZ0nDoIœnD¢`Ð} ÅØ^CÆâAG"sCdqèlŠ…‡Èª0p=ƒ¨Š†ô2ˆ 8!Ш$ϰ"çMwØ\Àˆ!*(t³t„µ¤V‹~µÈo»A€²DoB€2 ÷0£„¨ŠzQPf 6#ƒ "("è<é-ŒnrŠò‚ô!€2QúLP¶!6#€ "€©€§€ñbüö ,ÂXΛR/ —J``´ß#¶a€²Q¼=#ï £=wn´ NF¼ìØïAÙ…¨ÞâЈǗv Šs/í#\WPPÆvi.!0tFµ¹À[ÂXäãe¢(NÆpnÒ–Q(ÃKŠ€Œ¢(fÈ6=W‰¸y è%\W`ŒíJxˆ Œ¢(äB  g;DÆQ@I)õá‚cÈ¢c‡¨ÀØ!*€ÂA6¨áœÇÆ&{z~Zµª—™Y×5|¼¼æ;v±e*Œ¹3æ®Px˜›w¯Y³ÿèÑË32žóüò²Ä¼ …ÇéÓW Ó†ÂÓ½%bIOŸ¾Ê9¯¥e/_¾{ݺƒ'Mú*-í)ç¼d–N¥ ææÝëÖüñÇk_¼È,Â6äæ*#"~¹qã¯X®Òß*p=ƒg™b¾¼s¾xñÖE‹6Q«Vmm­SR~ß¿ÿ?±±ÉÛ·/üෂ˽ww'KËJÏ“’.oÙr0-íiLÌ2çÍc¥×cŒy{w "kë*ZZ¢ò‘xݹsK+«ÊDôòe扩ë×ï½sçѾ}_‘.eLbbJÇŽ-TÚÀ9ñ"óĉÔÝééÏ""fI8ç­ZKM½uêÔ7¢„â[.RÛ*Ž¿Ô±c‹RÜ6JË÷ ”²R¿ý¥¨:ÓêµùVáââ`bÒ¥yózãÇ{ÑÝʪ²æÚ‹vw¡';„·bˆm!ƒ ¤ÇÑ44tM›öAÏž­cŒ±råLCC§8œœ¼^„‰‰)Ó+Uò´´ìÓ»÷ì³g¯‹y¥¤Ž~8Ü©ÓÔ z4kæ·o_½>³+Îd‰=z¸ˆ¦‰/ÞìÛ÷3 ‹Þ+öìØqʧÄôòy½½ç)3f„‰³³sjÔðQ(<þïÿÎj©]TšWùô:ÁæûïÿÏÍmZ… =Çœ?cùòìí?¨TÉÓÛ{Þÿ›.ŸR¤åæ*ƒ‚¶4l8Ì̬k¥JžmÚÄÆ&‹¦ŠU÷z–_‹ÿ9çNNÄdgH)Fòt#•EÚ¹eËA‡*ôps›öã‡ÅòÊO™'&¦øù}Q»öÀ3Â._þ£Y³º*í‘ÚðâÅ+"jÒä×ïÿ¯ œs•ŠÄ§¢–¼–Zš M›“.*Ë¥ËúW_ê¼V²ÊVAD-Z4¸|ùéÓ×Ô®=hìØ'O^.‚€AAT% ÙÆ…o‰ü0©Ë”…Ï–¯añOžÖœï¼R¢ðÛ¶¿`Š»|ÈWRR*uéò¾¼S[½º•§g[[k"JHHéÖmfBBJ«VœœÅÅîÜyÚ¥K¿“¬£6iÒ— …ÂÆÆòêÕÛÇ/}þü•JÇ”1w†1fb¢¨Uˆˆ.^¼Ù¾ýäN5h`׺uÓ¤¤Ë^^s~üñˆJ§vìØ>D´cÇÑÜ\%çüðásgÔ­kÛ¥Ëûô:ÞÐX».å¬655±´¬”šz«K—K–lmÞ¼žR©Ü·/iÑ¢Hõî~hèž  ÈÇ3zöl]§N3g® 0ÿŸ^H-“ÉÃ!¥’gd<_¹r;cÌÒ²RãÆµH6H¯UAüêwîŒ=zù995zù23 àK©ID²»E‹ÑnnÓ¶n=X½ºÕ¬YCÏÛxéÒfQ ˜rÖ¬õýûöïصëÇ&¬ª_ßnÓ¦Yê˵k×±Q£¾¸~ýŽT‘¼¼–Úǧ£˜ÝÝÝIäÉËÔeý«/u^+Y ä[ÔÅ‹›ÎÛ8s¦¯µuåÈÈØ¦89 ‹.¦Ÿ €BT%‡s¾xñÖ^½fÞ³'¡ÀÅʳûõkß¾}ó´´g[¶ôóû<ßh•³nCá‰lcoï"ƒ6¯ÉÔÏØ©KLL‘&ÝÝ||:öë×¾sç–g„„ìž2%D|¤KôæöñéèãÓÑÝÝéɓ֯ß;räçùÎÛªÕ¸qãV¤§?­%X[W)Žô•®IbbJ‘WQ󦞞þŒˆ,-+‰o|âÄ/å!åéÓW-ÚœþéñãaÇŽ}½iÓì/2?ÿ|›|»>}`||È¡C«9çOŸ¾øý÷{ôºs,:¦îî ´ˆ>ø ³%clöìo_¾Ìôóëyþ|x||HHÈTÎùÌ™kss•$ëX÷îݶV-›ž9rŽˆvíŠ'"?¿žb«ÑR».åÏš5ôðá/¿ýö"ÊÈx¾cǸ¸U³f %¢ ~“÷ŒÅºrqqX¾ÜÿСÕûö}‘JD¯^eýñÇRëèQ›6 …‡‰‰‡µußE‹6›™™††~T¡‚¹J™âµ´DôìÙK±«Wï ¢©Sœ<¹îôéo‡ ë*oÒǯ½råϺumùeÅ­[Ûƒƒý[µj, ˆññbbŽÇÄ?zô|vvNnnî­[Ô—kõꌱiÓ>HJZ›œ¼~ذ®ò/7¯¥ŽŠZ"&X±" :z©J™º¬K­RçüåËL±’UöÿNNV¬øóÏ{÷~^§N‹oNúu‘ÿ@ô¢(9GŽœ Š,_¾Ü/¿¬8{vÃÁ¿ÿþãàÁ¹¹Ê?^«T°§"iV¬ˆ‰YvôhÈ®]AD´woÒƒOtœ—òîd—˜èè¥ÑÑK5ª¥¥%Z˜'Ož†„ì~ï½Q;$?H¯Xµ$&fY\ܪ͛?#¢;Šyu©‘Þ\Ãb–_~Yqðà*ÎùÏ?Ÿ¼ÿ‰ö0&5õ–ÔxƘTéÛ¬]©t#:wþ¨E‹Ñ¡¡QùŽi@²±±$¢GÒÅ7îèØP„‚Òo-9ùW"3&XÄ £F}AD )òí¶Kg"'c,33›^ÿHãã/üôÓ‰¤¤Ë66–ý¤sÕ"9²§˜eôhO"zø0MŒSIµ›˜(FîEDÛ·ÉÊʉŽNdŒé™oíº”ïáÑŠˆì쪉rºv}Ÿˆlm«QVV¶¼g,féÔÉÑѱÁ?rs›V¿þ1AVV6©‘»»“»»S¹rfŒ±-\¹²eäȤ ‹×Ò"ˆrÄ"ˆ™ÜÄ›¾¾ò&uîÜ’ˆnß~4tè≿”Õìõ©ääõJåÑœœ#Æ|úéÛ·üòe¦J¤ŠÄ›¾¾Òê%"]–Ze]é¸þ5.uÇŽ-äÕ‰)Eu*ûÎùþseÚ´ÐQ£¾øóχbú`0@ÉA¶qÑfK‡±âÎVEcNNDùgPÞ‰Â"9˜sÞ¦Mcî\-mI}Õåûk©N¥Ñ¢EƒÔÔ[}Z»ö 1c‚Ož¼¬%€¢Ò©“#ÅÆþû+˜8Ñ[„‚ÒV$NtîÜRD >>½½;tèðžü¬P¡cÌÔÔ„¿F¯7¿ääõ¹¹G²²þïîÝÝëÖͨ\¹‚˜EºˆYšC*ÞìdÝ‹1•°wï‰ôôg;·lÐÀŽdÝkµëR¾¹¹1öow³|ùr$»ÿ¤<ð³LŸ¾¦wïÙII—}}=þJ½s/½bEÀ‘#_ÅLJT¬hžšzkÖ¬õbM2Mc*”#"…¼;.‘ï¤O ¹reËŒƒLL7þܹóG RM|bŒ™˜(ªW·\¸pç<=ýÙÍ›ÿÉQÙä +­+]–Ze]é¸þ5.õŒaòêÔוx´ÅÁaDûö“×­‹!¢3ýúëÖ#G¾Òa“(#@ÉA¶qÑfsÎK,X>¥RÉÓÓŸ­\¹ˆ,,*Š´æ¼ìíÝAÌ+²TÚáÂoê«î‡çûë˜}áBøùóáŸ|2ØÚºòæÍ¿´o?¹U«q¥–(\ÚƒQ%fêÔD¾?**Q|¹¹Ê ~–¶"gç&DäéÙ6*jITÔ’#z::6>¼»z§™k: NšFö8çmÚ¼KDß}'&‹ŒŒeŒÕªeÓ¸qm•yë×·ëÖÍ9#ãùǯ%"??O®vš@½vË—Ú£2»Æ7ÃÃ÷Ñ¢E£§LéÏÿçËg¯Ûµk¶açœó¨¨„ÝÚ×’JÇÚÉ©EE%ˆ7¿ÿþ4»˜ iÓ:«VM¼sg×–-s:vlñÛow-ŠTÿ^Dá·o?U«f¡²¤ŠÄ›ßH^ˆ–¥%ˆpÁÖ¿úR«T÷zRisPPäo¿ÝíÐá½ÈÈ9wîìúòËÉM›ÖQßÒÊ2zNÏ¿#íÍ#â<^úgjjÂ;yrRyT©<ÐO¾)&'¯÷ðhÅ‹ˆ˜-¦ŒœÃ2¤‹˜^ì¾.ôS*þúëV1WJJ„¸k½Îzïܹ¥a÷õõåôèÑš16j”§(ç믧1ÆjÖ¬š}Xš79y}vöáÚµ«3ÆââV)•GÇŒé-U§½v]Ê_¼xŒRy4&f™(gß¾/”Ê£ ø1ÆÚ·O´Sj‰Ry4!!488àÔ©õJåÑGbÄ\.l’Z"&¯EpnîQùÚŸªÿäëֵݳg‰zmڼ˛6í•oG>¥c¬\9³-[æŠéU,¦ –×¢Ò~iÕ‰ZTV–u®Ëú‘¯œœ#ûö}Q·®íëÁÿ>*¡Ÿ˜žÿ éÍ_ºRytñâ1âûjÙ²aïÞíÄ/‹1fgWíÏ?w8,Îæº¸8tíú¾Ø3¬_?Se QßJå¯ßøy<çñIIkÍÍÍc-[6ìܹ¥B¡01QìܹH½¥ò莋Ä;•ž=‹•ÿjòª]÷ò““׋rD]ëÖÍ «>å»ïÖeŒU¯nÕ£Gë ÌÅj9xp•Æ_ºÔ*¥òèøñ}c+–¿zõ;•5£åµD|êêÚüý÷›T¬X^j§úúT*¦¦F~ôÑòr¤‹‹zõj+.çèÕ«­úrIWHÉ÷'Z–ÚÖÖš1Ö¢Eƒöíß{þü`ÁÖ¿ÊRk©N>×”)ý/^ŒP_Ÿ»0ÄÝ‚!¶t†±(9È6.òlã’É–¦”§5¿÷^ý+W¶Œñïù]3wÙ›çð¤U'Þ=Ú“sþàÁ±êòZç:®©–“'/‹DáÛ·I+ Šc,0pÄ¡C«ûõëpïÞ߇ÉÊÊéÖÍ9$dêµkß½óNuOÏ6û÷»¹9^»v'1ñRóæõ""fO˜ÐWe Qù]Ö±"rum~üx˜—Wû;wþ›œ|µ}ûæ¬4ÈÔ® bŒy{wZ__÷J•ÊKåçU»èàêR¾ Þxo~÷Ý<‡ŒŒç©©·.5`€%&^¤<Æ øëóô!!S›7¯÷òeæ˜1ÁJ¥®c>>#"f7lhþü +«Ê7~J¯óm4~Í›× ™*/G\müÓO':“›«ôõuߺu®úºê߿ӦM³4°“*b²Œ,-KP»võk×îך59:6Ègã(Óðlc(9:9îÞ},6ö”——+clâDéõckH–mlm]EšËÌÌT:‘<ß—^#¥î¯ÆßȳQ‰Hd£JJG"=º×²eÛ¢¢<=Û¤§?sww’gçU».å˳‰H=ÛXÞÎùŒa¡¡Q..#FôXµj’«ë$©‘òcÿÑ£!W¯ÞÞ¸ñç-[b7nüyãÆŸ6´ÿðÃî ø©LibÂDðÊ•ÛEpóæõäË.‘7C¥m+V¸¸8üç?WºwŸ)Òšwí "ú7sWÞàví&j/På«y] Éû|y­s×mùþûC¿ýv—ˆªV­2}úÀ ¼š6­£¾Ôƨ8ŸFÄëÖ͹[7ç¼&èÙ³µxÀ™:•±)é„®Êk\\~úIÃsŽcòy9ç÷ïÿýôé z>$m6Zj×½üÖ­›ÊË‘öuêe:;7IN^¯qYä%¨×U¬h~éÒfeª´Yš—sûèQúW_MñòjODâæo5kV•¯¼h3”“×»yó/¢¢¾}]‰(**QTÄ^§åµÔ~~=ýüzæµ,:®•Öj©.ß- À¨`¬J²5ήñM]²Åÿ%“¬rÆnÆO‰(::1$d·øHKæ®B¡`Œåæ*ÕÏáI«N¼KDööÕĪӲÎuÌÆ^´hóµoß|óæÏîÜÙµzõ$„püø¥!C·o?9++§M›¦:¼—o‡¸l{€9s6øøzxLïÞ}æÈ‘ŸÑ AîE»8çRE]ºÌèÑã©"g"@O`¬JNÇŽ-‚‚F/X1pà‚–-ÖªU=%åæÝ»‰¨fͪ¶¶UçÎýÐËkÎܹ÷ì9fiY騱‹¹¹Êo¾ùXå³ú9~ùÙh•ÃclÙ²qÓ##cÏ»neU91ñ’BÁ¾újЉ‰‚ÔÎdÛ'.îô_ý×¢ÒÀ¥º´Ô®cùyÍ®ñÍ:ul¯^½=jÔ­Z5NLL11Qˆk|Õ׃xQ¡‚ùˆ=>ü°û•+nܸO¾ÆfÍZoeU™ˆ23³Å<=ÛØÙUS©ñÓO‡|ðÁ‚5k¢NŸ¾š™™}õêm#*bU Ö5>þ|xøþùó7õéÓ®I“Ú* V(˜ÔàêÕ-=JŸ0aU•*Z-ÿ‚òZub AË:×eýÑ”)ýÇ÷jÑ¢¾‘tû _œs33ÓŸ>É9ïÖÍù›o>6žmƒs>g·ÙÙ9»v;yò2çT»võÁƒ=æÏ©ËXîcyUd™‡¼ÐF›ADE×0üÒÁH”ÀîBÏéíÞ Š®60vˆ Œ¢€â¤Ïîâ‚cDðÿìÝg\G𙣣H±aWP‘^ŒØÅ{AQ°—Ä+XP,‘ lØKì-6°G všÄ^£`¸ÛçÅÄ}Ö½ã8úq÷û~xql™™Ùÿm9DºQ n?È   að{:¬°~ËŒúBf ä *(Jû¨q!Ò…}Ðv¸ƒ@×!*Ðu”Õ_ §É/;'¹eRA© É‡h+ ß•*yµá¹(JZßwèBÿȇvZ¿§: wŒÖ_áƒJµgt¢€ÓúsepÜo±Dx >”ˆ ò‹¿}ˆ+k7~Yl  »\pºpƒh D…ÿ]‹‰"œïhD#ú]»ƒ\i}h¤ÅPqº ï (T,0ÐÖïÑsÝ;6 —J\+È'ÇÚ}Å@½ãŸ= O'” ˆ LñD¿$€ÒQ@Ñ@` Zá€ÃsEF»o©ÏßÂåù§´µR©{¼D»‰€ÜàZ@Þ)žyòä\·Â'N)]»v-K„òéÓ§Ë—//Z´èßÿ3gŽŠuO:5gÎ777ssó¼¶^un (*xyQaÀøˆñã£úŠt|ĵ‚‚â8.;;ûàÁƒƒ Rœ«t–blgdddmm­§§§f‹ÝAƒš5¿Š¥¥eùòå­­­+Uªäìì|âĉwïީȳb"ŃRÊW´ŠeøÏ¢ÚTlKü¾W®\ÙËË+88xçΟ>}Êu+ÂÄ---­?«R¥J›6m† rðàAÕeȯ.Ü©B,O5[xÉÀ ˆ@ÿø®`|Ì=}‰ã#Áø˜E:>"*(W¯^ÅÇÇDEE999ñUÂqÜ«W¯V¯^ÍÏâW9}útïÞ½ÝÜܺuë¶uëV6‘¿Ä>ìÝ»·OŸ>nnn½{÷>ofÆ–ÉÎÎ^ºtiëÖ­ÝÜ܆ öÏ?ÿði:99EEE¬Y³&==ŸN)ågÅÇdzëYŠ{ñîÝ»]»võìÙ³L™2|k£”ÅÅÅ•/_>§¦F)u:p ×ô³²²6oÞܳgÏ*UªˆZóŒ3¢££ÙQ$“ÉV¬XÑ©S'WW×.]ºlذA.—óà¾(“óç•v^ì$ŸK™L¶jÕªŽ;ººº~ýõ× äËÃiñâÅmÚ´‘Édì_¹\°bÅ ¥[dË(M“¯Á]»v±KÌGŽIIIéÕ«[òôéÓ¢k—oß¾]¸pa@@€«««——WHHHjjªâ~©hK¢}766f9nE&“-_¾¼]»vnnnŒgÖ…‰ˆ6*‘H8Žc…¯4“„±cÇrסC©T*ÚœŠòQ¬DuÊäÜÂ4ƒϊc|üÜ3kèø¨FúY”–²ñÑÜã£6äË7fÎœéææÖ¯_¿¤¤¤?²V¢t›~üøq©Têãã³wïÞGmݺµE‹›7o–ËålÖƒ؇þýû_ºtéÖ­[AAAm7ÎÎΖËå‘‘‘þþþÇŽ{øðá¦M›Z´h!•J?~,—ËårùÇ“’’úõëçææ6sæÌ7nðùQœ%ܹ\þÇH¥ÒË—/ç§ É5ý«W¯J¥Ò .¨Niîܹ]»v=uêÔãÇ<زe˸¸8¾p¾(“6m²³³ùBã÷ôæÍ›Ý»w:t(+“yóæ}õÕWGŽyøðáæÍ›]\\~ùåaiß¾}›´lù³gÏ:;;?~ü8§-æšf=Ο?ÿ÷ß2ÄËË«_¿~/^üûᅦêïï/Êóرc{÷îýÇ>x€ñ±ˆÆGê§ —T*íÔ©ÓüÁ7;F.—ó³DÓY-nݺ•Ÿ²páÂŽ;*öz§NbËìÙ³GÚ¬Ù‹/ÒÓÓ]\\vìØÁ¯;oÞ<Ö|E[¹páB§N¤R©bžùY¢<§¤¤H¥Ò»w«E0Ôå”þ‰'Dé/\¸ÐSàéÓ§/^¼hÞ¼ùï¿ÿÎ/³iÓ&OOO¾õQ&Ré‹/Øt–ˆ«««‹‹Ë¨Q£ž>}*—Ëÿý÷_ggçÄÄD¾d,XЦMQ§§NbåÃiîåð¹SæÓTÑ¡èÒÉnAéLlP|ã£TªÑã£éŸ(W®”ææ%?>>x€ñ±ˆÆGQF&“………=zô¨uëÖR©´{÷îÏž=›6mšh]ÕmI¸ï?~ŒŠŠzÿþ½p+|>Ùîp ç%¶¶¶•+W¦”Ö¨QÃÞÞ~̘1™™™óçÏW3“B¹–(Ç©¹ ¥-<§l”2Z÷ü:ÆGöï7rM¿Îû÷E0>’’ä¥ÔÈȨS§N;v¼pá–-[Ï;Çæ²Y:uJMMe³Îž=Ëf]¹r¥Zµj¬ ¦¥¥ÙÛÛ³¸PDÔ:k×®m``ššZ£F ¶î•+Wø¹ ðõõ]ºt)ß=ñ‰ð³š5k–Ó¾uèÐaÛ¶m]ºt155vpiii+VäÓ¤” ¿/á8n@ݺ¾ïÞåš~¯^½6mÚÔºuk[[[aj?fŸÙ·OžÇa|Qg\`û…ñ‘öøˆ¨  (¥R©T*•>zôHñð“J¥Íš5ãmBÈÒ¥KË•+çààpìØ±íÛ· jQ²ÂË•+×·oßeË–™››7nÜøäÉ“ìò(“””T¹re¥‰$%% ;¥8Ž6lØùóçCBBÜ AƒŒŒŒ;wnÙ²eÔ¨Qvvv*ö=éêUÛÔÔ\ÓÂãmOûhp—¢||Ôà ç ÆG¥p­t×›7oRSSOž<Éq\»ví”~§RªQJ>¼fÍšQ£FYZZÞ¼ysõêÕ:tÐå. Ÿ¶œ%h(áÕíº€š ã£nµ§á#®†g/gǽ~ýºcÇŽ3fÌJ¥šØøZÁÛ·oüñÇää䌌ŒJ•*µoß~àÀ¢+¤¥¶Á-KqBik¬MUã£Ff80>*…¨@ãiø¨áÙÓ(aÍºÈ J JݱSê2 y;ˆJ9Ü\†¨ ”ÓÒ—@qBT ÙØ/a€u <€üBTƒØU!<€{ö'–Hµ4F´#))—XÛSº$ß2!Wº “R“Âí¤Ø\ ö*r’×Á^i½ð¨+ «WO jwÐÂVvíš«zݦMCبÀQs(ÊQùœ8q™o{Š„-4ÇáÃ""Ö$&ÎnÛÖ…òéSVPÐÜ-[ŽŽÛµ«!ùi9|Û˜??ÌÙ¹.!d×®Ó;OÞ±ãäÓ§¯*U²,ÈqWl(¥‰‰³s]L”Iöyþü0*swúô5á»wŸ~üø¥­­•:iªã¸W¯Þ®_`ÕªÝ׮ݕɎBŽù#"b­±±abâì6mšB23³…Õ*‘¨ÿç÷nçÎS]ºLÙ¹óÔ“'/ml¬ÔY—”tÿOQ§ T´Ã—/ßð.—%ŸCAÖÚÙ’[·ëÝ;bëÖ£«WOP³!e%¬Ø~Tœ!\¹ò7Ÿy5w3ßDÁ°Ïè† «Ü©KK3Ñ’*悈®ÜAÄwRûöÍOM]±woÔ_ýÒ«—ŸL&7.V.Ïçå'vQJçÏKJšsôhô¶m„ÖI©¹.ÑŒN*1q¶ƒC•\KvŠ.ؽ|ù&:ú×F‚||F³øÁ~ïÞ¨ VîÛ7_Xà'NAM|æÏKLœ}äÈâmÛ"8Žcƒ½ê4U俘±>š¸ŠÅrj!DZoÜ8ØÇg4Û)¾&&ÎNJšsàÀ‚5k&B¶n=Êf©³Eòe '$ÌJLœ½ÿ‚Böì9óèÑ¿ª×½|ù/a «Ó®òMX>„ŸÑŽŽcb^½z#ª_ŽãTÌ…B–—_8މÙN5êkBŒŒ bbFíÝuî\K&%咟ߘ2eÚš›whß~bjêŸ| ²[~þù°—×H“Ö  صë”ðˆ „°­[;³OŸ¾bÓ/^¼Ó±ã¤råÚ›š¶ñô±wïÙÏÙÿÿº]ºL•HüÆŽ]ÊÒÌÊÊ®X±‹Dâ÷Ûo©Çå´u–ŽŠôÙí›6ýæí=ÊĤµ£ãÀ?þ¸5oÞÏ•+]¦LÛΧ<ž.ºñƒÝž±®V­¾_•)ÓÖÅ%lÿþsäËž¥/<)¥Mš8°=zñ"ƒ"ºÝH"ñíŸÎºuêÖíobÒÚÛ{Ô/¿fû+¬¾””KAAóììº{íÚÝ ª± ñÕÚ¦Ms6ÅÐPŸ¯V(V«¨|s%êÃ9ŽkÝÚ™}`ý?ÇqŠÅΗ¿nçÎSXµ²-ŠªUu™ä”>ßUW«pIժ؆ÙÖSR. 0×ήûرK¯^ý§Aƒj9-ùþýGBH:U?OÿÿUÔ¬â(©Ø~rÊ0»^Íqœ‹K¥¾œÂmK¹JË\ò!„4n\óÊ•¿Gޱ³ë1p`ÔéÓW…G„й Æi+B8îÿàA)0¡\~”M‘Ë>{–´oßü'OÙ”ää_ß&¦¦ÆåÊ•i×®Åùó+ø%YãÛ´iš§gcccÃúõ«íÜÉæ²bÛ–“sçâø­''Ƕ111b)4lX-ɸ°øgË(¸(ç¢]Vš‡²)ii«ÙÅÕ£°ÀYš¢Ïiëj¦¯ºÀE{‘S+Ö ßJY³6¬žÓ’kÖL¢”6mZ[i¹­]û}:U ½¼þy››S-¿{w€¥ñb¼Š"ìXXj¢£#×¶ª´ÆÕ,GÇZ,禦ÆÁÁíNж=ÕsÿûË©?Ôâ~²ˆ¨(±/{fkksJéþý ø– ü“Ë?chh ‘H<<y{;ééIÊ”1¾t)^ØVÍÍËx{;ÙÙU ”š™™¾}»_±ííØI)ÕÓ“<¾C.?úÇ«LM)¥NNµ¼½(¥‰dÓ¦i¢vÅÖ²µ-Ÿ}D.?ºoß|Jiõê62Y.[W'ý²eMüüš² eMM[µ’RJ‡ ë¢ØÂøa8¥´\¹2:¸Ö«gO)511JOß#êO„Ÿe²£¯^ífù|ÿþ€¨dØg¥»°eK8›ëêÚÀÙ¹n¹re„½ÄâÅ#6¬Î¦ØÛWš0¡Ï… +ùZã«UÉQÆã¸c9U«p¯•æJÔ;©Y­¢žMuµªØº:é«®VÅþ_Eµ kŠ8›Â¸¨ÿôõmÒ¥‹g—.ž~~M ôk̖֬mQuÍæÚ~rÊp—.žl]– QþÕ9"”–¹šåÃ6ñÝw½ªT±fÓœj-Y2šo“*ææÒÿëí-…ÆtRÅÓIa°/ôÁ^õ0,ìŽE£‚â·l gË󣛫¸d^Gáà$Ê¿:m5¯£‚èèãû}6õû| T:7÷QCE>¨èëëQJOŸ^Æþ  ‚Û<΋óókJ)ŸÈÚÉÚµßSJ{÷n)l«3f Ë^¿¾žÕ,ëF„G„“¡¡¥´gO?–NëÖÍ)¥AAmY:?þ8ŠRjcc••uXØ®²²³ÖxðàB¹üèÀí)¥3f Èuëê¤?sæ@¹ü(¯é®]såò£Ó§ ”º»7R왓“c¢¢ÂΞ“Ë>{–ÄÖb_? Y¢€Rjhh°nÝdÅ4Ùg~Øòl\\êSJGúš­ ØKT«Viß¾ù¬ÛTZ­¢uù|òÕÊIÁªU˜C¥¹ö0ÂjeéðÅÎÒ;¿õœª5×­«“>_­,³ˆX IDATQµ*ö±¢jek±jU¬)¾ÀEã)Uvu®ZµJÛ·ÏRÜ¢:5«¢ý¨ÙEùWçˆPZæê”°4²³ìÚ5·ZµJl®¨eŠæ"*P¤½¥Ã؃Nªx:) öE4Øç4 +íÊÙ¨ ¸E~TÖ|W¤˜¸Ï×+Ô즅ùW§­*-s5ˇo{|¿ÏæŠZ¦Š¹ˆ ÚQ¥tÇŽÿ® -[6–…µ|Í–)c¬Ø+W¶¶êãÇcäò£YY‡ÙÜß_.:960Я\ÙzèÐÎoÞìcÛeWÛŽYÌÒyýz/[òÚµu¢v5mZ ¥tàÀö?²´4“H$wîü’ëÖÕI?%e‰\~ôìÙ8– ¹ccÇRJë*ArùÑ}ûæýµ§gã2eŒ{cág_ß&¾¾MX÷ظqÍÛ·–+\£æsÂï[W¸ ÇŽýÈÖ:rd±°—ðõmÂÖµ°(;dH§ääá1ÈW+›ÂW+ŸO–QU¹²µ0‡Js%G„ÕÊrÅ;Kçõë½l]VìÂRRZ­¹n]ôùje鈪UÔ³t„ÕªX;쳯o¶_àŠý?ñùéÓ¤ñã{³…Y„û®ºfsm?ê´CÅ\©sD(–¹úåÖ'”R//GGÇš?ÿ|ÈÛ{T½Ù™™YDpÇ*!„½»éÞ½g}úÌ:ô–†RÊ8[ÅѱVçÎl°g)œ;wã¸£Ø …AAs9ŽKN¾$Ì¿Ël"Ûeöùر´¤¤ÂÿÜ#ÿW l±àà¶Ç=yò’Ÿÿœ <×­«“>_à,Q ë”—§gca³XóõBaÃðÝ»OYŸ8q™Ü7)ìšÙ¨ðÝw½îÝ{6hPÔÇ™¢º»|ù/BH·nÞlbÏž~Âç>?¸,®][Øš­®N µ+5ÛªÒ2W§|èç»iÏœ¹6jTLPÐÜ»wŸ²½–’â\5:(BìÅ û÷ŸeU9thçÄÄÙ ³øš•Ë9J©ë±ÙŸ‡G#áqdbbHÑÓ“0DpܱÌÌß>üuÙ²±eËšÿîcþÿÉ%¥”ãþû@"°‚ƒÛQJ’wî<™žþÖÇÇ©F ›\·®NúFFä¿76±tŒ›Ur»´}û‰§N]íÙÓïðáÅÂ#ZñóüùaGŽ,>v,ÚÔÔèÊ•¿'Lˆã¿¦É>›˜RJõõõ¸Ï„u¤ô >rdñõëëÇë©§'Y±b—·÷¨:uú±×KPJùje+²jMLœÍ'ÅžåVkç΄›Pš+î¿á#N&;"¬V¶ _ìü|‚¢RR¬Öš5m‰ /UºuuÒç«•¥cllH?y"l9l•1c–«U±v؇£G£¯][7vl==ÉÊ•»}|F×®ýMDÄZQRJõô$*˜Ï˜Äq\zúÛ;w‰ö]uÍæÚ~Ôi‡Š-M#B±ÌÕ,BHDĺ:uúyxŒøé§„1cº_»¶îèÑh–sADW¢tRÅÜIa°/ôÁ^õ0,\ROOR±¢ÅŒA„ŒŒwlTn‘'ʹ0oŠ£ÿP¾š-D”+uÚªÒ2WsŠˆXW·nw÷áË–%BÆŽíqýúzö5!$§¹Š‚ÚÙ²jÕžíÛ“Ù™L¾rå¾f¥Ò:„¶m[°»ÿ6ŽŽµ¾ùÆ_t)¶7Q-D)uq©OÙ°á [líÚý„Ê•Ë×®mG¾<îªW·iÕJš‘ñnܸXBÈ€mù«bëꧯtu¥W­ÚC 1¢+÷ÿs¸ÿ/,\‘}psk¸bÅxBHbbJtô¯ªKIÔ/5iâ@IHHf7m:$<*)¥õêÙ/Z4ìþýmë×Oöòr¼sçQDÄ:–_­ )lŠL&_±b7Ÿ>_­ ³fñÕ*Ê¡b®„{'ªVŽãøbg‹­]»ŸRZ¥Š5+váº5jØŠª•ß/[W3}aÙæ:QT­|÷¨Ø†ëÕ³_¸pèýûÛÖ­ûÞÓ³ñíÛÃÃ×*–Ëɽ{OÙ¬òåˉò¦¢fE­ZiûQÑ% ¥T&“çûˆÈ_ùBÂÃ×ܺõÀݽáš5“îßß¶hѰzõìù6£b.ˆèJT€NJéêJ'J'…Á^éêJ'ª3س*†aQ;ä8îÞ½§l„[äG6qÓ¦CÂD„Kºº6X±b<Çq ÉÑÑ¿²Y*ZÛºL&Ïw[Í_ùB""ÖÞ¾ýÐãÑÚµßß¿¿í‡†³‡È1CŽs¡yy9FDggËzô˜Ñ¤É &U¯Þ+4t!!ÄÖ¶|¥JV“'÷“HèäÉ+›7mÕj\¯^á³f­òäe{æ9sB õ×®Ýß´iˆŸß˜±c—J$tñâ,vµÆAƒ:B>|affÚ½»§FϬfú|~85zf{ûJ„  ¹mÛNhÙr,K*=ý-ùòèõ}û~Ò2mÚê›7ï«(%Ñq7~|oBÈ’% îîÃ¥Ò!¿ür„Ï’°0MLŒú÷oœsùòšQ£º±t<=GDgeewï>½iÓŽ¿¯^½WXØ"Bˆ•°Z]\Âüý¿å«U±7£yéÿùboÒd¯ïh¾ØÙ ¢ú4¨Çq„#º^¼Ÿ’²dÀ€ÿÞÆ!<”TÌ]‰ ÐI)]]éÄ‚wRƒ½ mä:QÁ^XeJ‡a¶ä„ q]»NíÚuj‡“¼½GQJÛµkÁ^ã-Üâøñ½9Ž‹‰Ùîá1ÂÙ9ô—_Ž•RŸ>-îH)6mõŸ>PÝBøQÁÓs䇙ùh«ù+BÈðá]ÒÒVŸ8±”õû¢#QÅ\(YÓ¦<¸°S'÷Gþ=tè|ff¶¿¿ó?Žºysƒ½}ÅvíZìÙåííxóæý””Ë VŸÚ‰äÖ7ªî™]]œ8±´S'÷û÷ŸŸ;wÃݽáÞ½óY¯«Ø;wö`¡uÏž¾¦¦FêôÌj¦ÏçG‰6Lqv®›‘ñîÊ•¿gÌêÖÍ›’’r‘|yt‹zHŽã¢£G6lXýÇOFÉÿ Øs¹V@)íÚÕkõê 5kÚþñÇ- ‹²+WާŸ/V+­Ç† «GGäó0ujÿC‡xðÕÚª•4:zäÍ›ªV­Ð¶­‹bµÒ± ý?!ÄÍ­¡b±÷èá«´¾:wö`oÅèÙÓ—¿a]ÅÖ)¥j¦/,Û\'ª¨VÕm˜¸°Äص;vœw"ÂuY'õ￯;)¥[ç;©\ÓÏ)óJ'nØ0eèÐ.^¼ÃÂÔÔ›¿þz<%墿¿T˜Q:|'ÅO™6-PTàþþάÀÍÌLíí+*xPP[¥%#ìUçu=¢ñ÷—*­G6س ö9m]ÍôsZ]éD®ºuñÎòÌF6K__ÏÌÌ´gOߥKÇ(n±KÏøø‰sæløã[îîV®߯ßlvv®X”Òèè‘§O_½zõŸ£’“cTd8**Œ}¥dgWáÕ«7ùh«ù.Ÿ%KF+OõÜѼýL/äO«VÒV­¤9ÍmÓ¦9û%,*xû-#|ì^é#øÂuëîØ¡ü·&Eë>~üï›7ï‰àŠb®['„¨™~óæõ„é ÚyèÐÎJ—”Jëœ;§4Aa ¢\QJMM._^£4MQž…ë®Y³ïÙ³ôÅ‹GtìèFIHH!„°Çˆ•æA„Rš¿jU+¹²—, åTì¢úâ8NX­Â.HÅÖÕO¿yózÂtDÕ*\REµªnÃyZRýšÍµý¨Èð€m h“S®Ô?â ½|@}”ÓÖ1RRªZ Çqwï>­W¯ffvrr »Ã¾¤3¥åþùç _àìwãuÇqk×îö,½Aƒj:¹B¶oOîÑcF•*Ö÷îmÕéVG}Å1¢‚‚PZz¥§gæ8îäÉ+K–$¤¤\zò䥋K½3g~*éLŽãfÎ\±ŽRêíí¨¯¯wêÔÕ>Ó}Ñ¢a¥½—8qâ²°ZOŸ^VÚ÷H}Ú]³¢Øÿë$]¹V áøN*33ÛÅ¥B‚"%ìYëNH@>?ˆ&!=zø¢Õð(¥ú»wŸæ8®U+éO?S¼>©­(¥ßß/++{Û¶ã§O_å8bgW¡W/?öBÏ’Î]p'ªÖÒ¾Gy¢Å5 …× JÇqçÎÝhÙr,Çqžžúi\­Z•K:SZîìÙë¯YÓVw:DŽã²²d3g®Ý¶íøÝ»O„£û©µ’Î`ÉÁµ‚ÂUʯ€ÁµB¢€ÿ *(\ˆ  ´@T@Ñw@Nä_§îo™€&@T ë@ÑÀÅ€ÒQ€®CT ëè:D ðòÐ1ˆ t~Ig´—â/Sß’É ¨D9m}sn€¼âûCÅsYÈ”$€6Á­Õ´÷ZÖ´ZPz±_8F' ñð\€®CTð%|· ºQ€®CTE ¯Ðxˆ  (áv,€ÒQ€®CT ëàD “@c¿e Q€®CT ëè:DºQ€^@TDðÀ1€fCTÅ€CT ëè:DºQ€®CTð^’º Q!„Jñ’œ"‡¸ @S!*Ðuˆ  ár€FBTÅ÷hh*DºQ€®CT€€®CTňãðÀ1€BT ëè:DºQ€®CT:/ *fxà@ó *Ðuˆ t¢]‡¨@×!*‡G‹8Ð0ˆ  $ Ð$ˆ t¢]‡¨@×!*Ðuˆ @·áM8%… 1€£o ˆ Q”ü–€Æ@T ëè:DºQè*¼€à3DPrðÀ1€f@T ëè:DºQ€®CT: / Òxà@ *Ðuˆ t¢]‡¨t*@T% A@ICT ëè:DºQ€®CTº¿¤ ð%D ­”DºQèJñv|D 87”DºQ€®CT ëè:D Kð" ‡ŽJ¢]‡¨@×!*Ðuˆ t¢Ð$xà $ *äQ€®CT ë€ÎÀíC¥-(vú%Ò€œ¸cŸ§øß>%²uLÉu N4ŠŽ,€âE9ô¼¹¢ô‹st¢ÐxgƒVÃDºQ@à+Ð ˆ Ô€Û‡@«!*Ý€wÚ”:¨2€b„¨ pÖZQø÷Qh#D ð6=•äÇq?f.\¸¥Y³Á&&­ÍÌÚyyLHH)””e2ùªU{^¼È(xjÌ®]§$¿û÷Ÿ©ùÛlyJ}ù?##ÿêÕ{ûöíŽãØÿý8ùÙ¶í˜(}öçæ6L˜x1ü’†ÒJÌÛvq¢ Ptð ÇÅ¿m¬†/ßAÄqÜë×ï[·þîÇOááÁÍšÕ~ÿþÓ† zô˜úÝw½ ²)Jé¾}g† YئMsŽãhGDá9®:©ñËŸ=WµjöùãÇÌ3g®³ôéÓW7Nñ÷w~øð× ,ò‘C>ýää‡*ÂY††Â ¾ïªed¼Ë©¿ý¶gQo@£ *È3Jéĉq/_¾>~E¹r¦ìô12rpfföÔ©«zõò«Zµb¾ç8Ž?o.”Sa"êœÄó T¨`nccÅÿ[£†mzúÛ‘#üé§qff&¶¶å ˜kë/ÒWT(A‘PVVvBBÊÒ¥ ÉÉ1„¾ÍÍ˰æÎÂW¢]oïQ#FtëÖÍK__Ah7ÜA”goÞ¼_·îÀˆÝø€B)4©ï‘#Ñ•*Y‰nAÉΖ͜¹¾FÞFFþµk³hÑV¹œã8nçÎS‰ßÊ•»Y$¾¦lÙ¶W¯þ0™ã8{ûž”úr—ÓêìN›5i2ÈØØßÉiÐÑ£°-feeOž¼ÒÖ¶›‰IkÿooܸÇgfãÆC¶²±é:hÐüôô·¢Üætmã8‰D"—sr¹|÷îÓì&yÉäáákììºû{zŽ˜;w“â]LЧÚjÛîºuš6 16ö¯U«oBBÊž=gùׯxðày>)Žãž?OŸ3gc­Z}GŒˆvwoDyûö«D>$`Kò•Hqwo4bDt­Z}çÎý9Ǻ-€V@T †/ßAtéÒ_Ÿ>e¹¹5ÔV¨`áîÞÐÐP_t2=zô’Ÿ>÷í­[›"#Ï›·iæÌµ”Ò€÷°°€ñãºÿyrò¥Ù³7üøã¨† «¯_?™Rššºòѣ턥«óéÇÄl‹ûöüùeÊ÷ë7G&“³-ÆÇï]¾ü»ë××wèà6uêj¶ð­[ƒ‚æöèá{ëÖ¦_ùÛo©ß¿B´¢Ì³ÙÙ²cÇÒfÍZçïï,ßÀïîããD)µ·¯È¯Î61kÖ WׄaúF¾x‘¡¯¯·jÕžåË¿ p'„ŒýõíÛ–-ÛAyúô¥\ÎU®lmgWÁÞ¾âΑ”RÑ^ðgÉóÓ?~Ì47/Ó©“ûüùaŠ»©˜##ƒ%K–.Óµ«!dÔ¨n·o?ˆM®Õ¼y¨¨ôV®ß«—ÿo®û9ÄÇljзſt ‡±l„„tìÓgæ³g¯ll¬š5\½ºÍÁƒ == ÷‘¯D5H)5118°]ppÛ'.07>~Ÿ\~4§åAsáD¥{àÕPô䙵µ9!äß_×®m§zIJéÅ‹wd2yÇŽ“ø³O™LþñcæƒÏkÔ°111ܸqª‹KhåÊÖË–Uüî\Åêì_‡*l-ö~VVöµkÿdgË\]°Ó}J©‡Gc¸»7êÞÝ'4tÑ”)«Zµ’x|ýµwN× vïžW¥Šuv¶ìðá ß¿¢uëæ±±cML wS17nÜËÌÌöðhÄçÁËËIlß>«fM[á«<í{ƒÕØvË”1&„Ô¨aË–455"„dgË!Ó§._¾«_¿Ù¡¡!!¬­ÍY~øJtpÈ%´{þ<}Õª=qq;33³¦OÏÆÉ hDjøòD×055:}új‹õ…'”ýûÍ7³""zy5fÓ9Ž“Ëå„-[ÂëÔù"„°³«À–IM½)‘H?þ7-í¶——£hË*V¿zõoBˆDB•>OÌq„σÁµ¬§'Ùº5üÚµ»{÷ž9|85002>~ï ”^+¨V­R¶„zõìëÔ©Ú±ã¤OŸ²¶oŸ©X<Šy`gäÂ<(<ööÃ*áb¹î»žžD¸]JÅ·$QJÃÃ'Múfóæ#K–$Ìšµ¾OŸ¯†ïÚ´©_‰ìò¿õÇ_ò•xáÂ­ØØÄ͛ԯ_-""¸OŸ¯ q¼€vÂsyfbbÔ¿ëeË’Þ¼ù |¤õ‡¶œ}mÆŒ5l•›7ïܳ§_``${öWx¦Ë¯ÎÖup¨Â¯Îs;:Ö24Ô?~jÔ=zøèeeÉúõ›Ý¨Q z§§¿mÜ8xĈè ¦˜˜BΜ¹æêÚÀήBN«ó›ªZZ–3¦û”)«¬¬Ê¹º6Ø·ï,»}ˆR¶¬ÉªU{ärnܸžYYÙ;vœ¨WÏÞÒÒLéµaÊ”Òñã{ïÝ{fâÄå:¸)–‰(åË—:4`Ê”•ÖÖæMš8ìÛwvÙ²$Ñb/^d|Q±¢EXX@DÄ@BÈô髯^ýçÂ…•úúzÖÖæqqßví:µM—®]½Ú·o1`À\BÈ­[›rZ]¸ ÑF##‡˜›—?þ§gÏ^¹¸Ôš8q9!¤iS‡§FFntrdjjÔ²e³Ý»çI$ªÞAÄÿ«§'Y½zBÓ¦!Ç/8°½ânЦ,X0ÔÌÌtøðÅ/^dH¥u'Nì;kÖz#£ÿÿN™·÷(q1Sš‘±G8%¯û®$(>5ÁŸè—/_Ni%véâÉÖÊ=$€b€_8(Té !ðJE@®:ߨQ öcgÇ-[¶câĸŒŒ½zzÚuÓõÅW˜š_3kT"€†ÀÁ¨Õ´ë 4Çq¿þz¼oßY¿ÿ~㟞$%˜3gC``m ÞAZ× Ôq¼¤3Pú¤§¿0!nçΓ/_¾±³«Ð¿ëÉ“û‰~âM+ø”t 7øfK  ñã);ÿ£«˜‚)ùš‚¨@ˆ 'ˆ  $àöf(\ÔWëîè(NÚvét”>NkÔ‚p´Çé‚SÞÜð·^hœ¼AaÃD€Çr@+ *PÂqÐb”â·ÕVÒ¯‹Ò”)ìw»þÿB´Ï_–ëòÐXx£¥6AmQ_|k …‹rß…C^à×|¡Áy¤6AmáͤP¸ðfRíÆqÜÇ™ niÖl°‰Ik3³v^^#R %e™L¾jÕž/2 ž³k×)‰Äïþýgjþ¦[žR_þÏÈÈ¿zõ^ãÆÅ¾}ûã8¶Àß?Î_~¶m;&JŸý¹¹ &^ ¿¦´ m»ÿ½ƒ@ûàµË ÅÔ¾PÀqÜë×ï[·þîÇOááÁÍšÕ~ÿþÓ† zô˜úÝw½ ’ Jé¾}g† YئMsŽãh;^á9®:©ñËŸ=WµjöùãÇÌ3g®³ôéÓW7Nñ÷w~øð× ,ò‘C>ýää‡*ÂY††Â ¾ïªed¼Ë©¿ý¶g¡lQh/Üp¢MØM¨S€Üp—-KHXŸå× IDATHYº4!%e ¥tâĸ—/_Ÿ?¿¢\9Svú9833{êÔU½zùU­Z± ÛâÏ› åÄT˜ˆ:'ñü*˜ÛØXñÿÖ¨a›žþväÈúiœ™™‰­mùæÇÚú‹ôJP$”••Í*199†ÂW¢¹y¶ÀܹCøJ´³«àí=jĈnݺyéë뉊‘Ÿe` êÌwh‰çÏÓ##7ÕªÕwĈhw÷Fǽyó~ݺ#FtãCB¥tÒ¤¾GŽDWªd%º%;[6sæú5zù×®ýÍ¢E[årŽã¸;OI$~+Wîf‘@xøš²eÛ^½úO@ÀdŽãìí{RêË¥«³;m6n<Ô¤É cc'§AGþÁ¶˜••=yòJ[Ûn&&­ýý¿½q㟙5jdhØÊƦë AóÓÓߊr›ÓµŽã$‰\ÎÉåòÝ»O³›|TäA&“‡‡¯±³ënlìïé9bîÜMŠw1)žô«Ytl»ëÖhÚ4ÄØØ¿V­¾ ){öœqthdä_¿~àÁƒçù¤8Ž{þ<}Μ|%BÞ¾ýÀ*‘ Ø’|%BÜÝ]«Vß¹sÞÐE)ågEFnzñ"CùMG”"*(m~b5-ívHÈüjÕz%%¥„‡ß»·uÞ¼!„K—þúô)ËÍ­¡è¤¶B w÷†††ú¢“éÑ£—üü󡸸ooÝÚ9xÞ¼M3g®¥”¸‡…ŒÿÓýûÏ““/Íž½áÇG5lX}ýúÉ”ÒÔÔ•m'„(]O?&f{\Ü·çϯ(SƸ_¿92™œm1>~ïòåß]¿¾¾C·©SW³…oÝz4·Gß[·6ýúëÌß~Kýþû¢½ež}ÈΖ;–6kÖ:gái´Š})—s•+[ÛÙU°·¯¸sg$¥T´üYrãÆÁüô3ÍÍËtêä>~˜ân*æÁÈÈ`É’„¥KÇtíêE5ªÛíÛbc“„k5o**½•+Ç÷êåÇÿ›ë¾GFññq"„„†ôí;káÂa,!!ûô™ùìÙ++¾== ÷‘¯D5H)5118°]ppÛ'.07>~Ÿ\~”Íe³l—’rI4‹‡¨J|áûïW´nÝ<6v¬‰‰¡ân*æáÆ{™™Ùøü±zz’­[ï]»»wï™Ã‡S#ãã÷8°@鵂jÕ*Õ¨aK©WϾNª;Núô)kûö™Š%§˜vF.̃bÀco_Q1¬.–ë¾ëéI„Û¥T|K¥4<R¿~µˆˆà>}¾âoKMýS4ËÈè‹(ýW2Š“Øföï?×¶íx+«N_U¬Ø¥S§ï¿¨tá<‰‹ÛéâffÖÎÈÈßÁ¡ï¸q±/_¾QóM«ìí°¿ÿ~#ßofU‚:ésÇ¿³V"ñ32ò·±é‚ܰauJé½{OªÔ®mW»¶ÝéÓ×fÌXÃV¹yóþ¸q±ááÁ={úF²g…gºüêl]‡*üê<Ñ9·£c-CCýãÇÓØDJéÙ³×Ø¬ääKaa‹ª|÷]¯}ûæÇÄŒúí·TÑy£b„@)õ÷—Μ9011…=­XV¢<89Õ20Ð?}úªbDk)–yAö]¥Ï*15u_‰l"«Ä×¯ß Wç+‘âê:ôõëwû÷/8~yPP[##>Èág¥¦®`³÷Ž(½ƒˆã¸™3ׇ‡¯!„4mZ»R%ËK—þÚ³çÌþýç6ožñõ×ÞJRǬYëgÌX£§'qq©oiYöÂ…[ÑÑ¿¦¤\:u*Vô%¥¹¶Ú|l]u j¦Ïnh#„øú617/“‘ñîÔ©«ëÖxõêMRÒÕà×m®øQJ;wö „XZš©ÈIÉfòRêããäããôÏ?O؉ÇìÙ!ÇŽ¥y{œ>=ÈÙ¹îË—¯ãã÷.]šZ«VeáºU«VìßßÊ”UeÝÝ={}Ô¨{ôð50ÐËÊ’õë7»Q£&ôNOÛ¸qðˆÑ6L111"„œ9sÍÕµ]…œVfO¸EK˲cÆtŸ2e••U9W×ûöe·BÊ–5Yµj\Î×3++{ÇŽõêÙ[Zš)½V L™R:~|ï½{ÏLœ¸¼C7¥E$ü·|ùrC‡L™²ÒÚÚ¼I‡}ûÎ.[–$ZìÅ‹Œ'O^ŠÒa/ÿaò±ïŠ× „ÿúø8y{;Þ½û”MWQ‰ìÖ¦[·6U¯n£tgoÝÚT­Z¥\Nê(U9òGDÄZccÃÄÄÙmÚ4'„dffÍݲåè¸q±]»zI$ù<)_²$òë¯3Ù)éÛ·Z´ššúgJÊå–-›ª^½à§ÔªSP3}~ÖüùaÍ›×#„ìÜyªK—);wžzòä¥è³œÖ%EÿS¹JLœë2Â2 B}sý!3þÑÊÊìäÉØ¹s7Nš´üîݧ††úÍšÕÙ¾}&{¸Vˆã¸åË¿³·ß0yòʇ_T¬h12}úê«Wÿ¹pa¥¾¾žµµy\Ü·]»NmÓÆ¥kW¯öí[ 0—rëÖ¦œVnB´ÑÈÈ!ææeÇÿéÙ³W..õÃÃ&N\NiÚÔaãÆ©‘‘œ™šµlÙl÷îy¢³Ðœ~ß@OO²zõ„¦MC†_xð ­iSÛêÕÿÍü.]úñý÷?KLLÍÉÉíܹÅܹ£û÷ï*/ùôé n‹K™3gäL$"ΩE‹ÿûé§?DרÕ|ٲ푑‡ýõ¾©©I»v—,'ÒQÂgŸ½³ukì¹s74¨5gÎ(ñ½¼|GÇV'O^V4°s碆⎚””MŽŽ­ˆ(33»R¥>Dtñb˜]S"JM½­hB¿~NŠu—-Û~à@ò[o Y³fegçÔ«7ôáÃŒ#GVõìÙYGrÎó-ÿóÏç}úéþ3g®·hQÛ¶÷>º/#ãi¯^[¶¼#?’·"ß{é)uæ‰3 ÀDÞ\„¥]‰ŠãèѳíÛ7?vÆ9ß°á«9s6edÄÌ—ø3O-MMN¾BD=zt–ŸØ®YÓÚÛÛI¤‰‰©½z½˜˜Ú©SóŽ›9r¦{÷é—/ߦg—9çS¦|¬R©ll¬®_ÿõÿþoÙÓ§ÿpΧMÄ9ß·/ÑÑqR:ƒžèÐéV­J)ÁÅ‹?të656ötÓ¦u»tiœü½¯ï{_|qL^2MžìGDÛ·ÉÍUщúé[Û¸Qhè¾Å‹#>ÌèÛ·KƵΞ½1xð|q–(!(hun®ÚήÙ?ü>qâGÛ·Q”Ÿ”tY³W®ü$n/Ž9Ë32R‰›º.]úQ³ ;wW¬;~¼íÞ/¾%÷رóf4jT»GÎR=µö¡>å­666²²²¼rå§=f.]Ù®]cµZ}à@ò¢EŠšèÓcŵÿ”6ÎùÞ½ £F-=sæúÏ?ß‹‰9¹|ùö1cúPJ@Dœkimzú"²²²#Â7ÞøXp`…øèþÉúùç{ôb?}úS§6œ>½qÊ”D²W1P–˜”´öĉ©b±ðìÙ› šçéùÖk¯-$¢!Cº‹o’špá–'B¤&ˆFd÷ïßµ^=›{÷?~žˆöì9ADcÇöu}¨Où³gn\°ø¢ž€€œóÄÄT)y ¢'.~õÕ·ÉÉßÛØXù……Ís¥&ˆ2½‰èþý4Ñ©ŒTýˆh×®ãYY9ÑÑIŒ±1c¼u÷!éS¾—W'"ª[·†(§gÏÎô☬¬lÍ+ùöX±ìzÅw˜@AX[WÞ¼ù÷îEge}sûöÎÅ‹¥ïð1Zž6vw·Û»7!.î´¯¯ cì7¾ñÆ@zq':©Õœˆºw·¯V­Š´–‰‰1ñuNDT©’)cÌØØHL䜧¤\_½zwvvNTÔÒfÍl›5³ ðöós¯>$"=Ë—ê£X]ëÄ|{Lÿ=  Ø!(•eŒá¯¤þtè{ûfõêÕLMýñ÷ßQ:Õk×®>wîë¾¾ïÍûÙ¾} VV– —rsÕ7ÎRœqWœ“nÚ´îôéƒ?ùd_PÐêc4¨uûöÝ«WaŒ-]:^,¶|ù/¯qçÏß´¶®œ”tY¥bkÖL'È%Ožì·gωôô'õë×ìß¿«4Òmذöõ뿬èÔ©ERRª‘‘J­æâa ±âîÝñçÎݬTÉLGŽœùí·?«Vµ:´»T~^}¨£‹å絺։ùö€¾p¿{É@VEM˵ÆØ¼y£]íçç*žèÍÊÊéÕË!$äÍ7¶7hPÓÛÛéàÁ`»7î$%]n×®qxøœI“è¾V@D«WOýôÓ·]\ÚݾýGlìw÷î=êÕË!66xäÈb1gç¶'O®óõívçΟ))×»uk»R —%QăËãÇ÷—~Dšs¾}ûûŽŽ­22ž^¹òÓÂ…ƒ{QRÒ%©J6Ì´²²<þf‹õ##çä¦(_k'Oö¥Cö¼®‘‹K;Í&¼öš§æºŒ±]Å3ÊÆyZZšKýŸW2Æô,_ÐóZA¾=V¨] Ê Îµü^” Îù/¿ÜoÝztVVNbb¨«kûòqb¿Wyaø}€rª»–;ˆ œç\¥òKªT^ff½ëÔøaFÆÓ|k%ÖU©¼Îœ¹^¸úýk"ïñZj»¹yïF†O™²&-í1ç¼ì´ÎÐàWÌ XpΗ,‰\´h+uêÔ¢víj©©·ü...e×®…C†xºä¥K#.Üjd¤rrjS­Zåóço…„ìMJJMN^ollÄt¦‹œsiÝK®=ËgŒ‰Ñ¿§gG++ËŒŒ§ÉÉßoÛv8-íqLÌrÝÖUl®ä1Æt%¢jժ訉b–xݽ»½µue"zþ<óÛo¯lÚ´ÿά "}Ê„"‡¬* |@süø…Å‹#ÌÍM££—õíÛ…ˆ²²rVìÞ?kÖúAƒÜUªBÊ×®"¢½{—ˆáã“'Ï»v}ãܹ›II—{ôè¤{õWRë.AÏò¥Y+WuéÒšˆöïOö÷ÿþä{÷Õ©S]G^=±)BÑÑËò]FÞ'D$^¯\äèØJÔ?9ù{7·i~w÷î_¶¶5ô)ŠÇþ úP6aç4@xÓË"ÎOH~~®Œ±Ù³GªÕñbŠZÿàAÌ¡C+ïÝ‹SC==;ZX˜W­jÙ¯_׳g7KK2Æc;vÌwsë`nnÚ¦M£ýû?skÔ¨Ê2ÄãܹÏrsãÕêøŸÞ’²éáÃýÒ¶.^ óñq®RÅ¢R%3W×ö+JNIÙÔ¯_WÆØ»ïŽR«ãÕêøÜÜø¦MmcQQKÕêøœœã‹6mjklldaaÞ¥KëC‡VŠ%E [¶ÌvumonnÚ¢Eý-[fk–¯VÇk6Pª¡‰‰ÅÔêøçψ)/†‰)šMÐ\WtòŒCÅô¬¬ojÖ´fŒ=ºZwêSþçŸÏsw·377íСéùóŸ­X1©nÝæ~~®Äh¶"ß‹I¯¥š<}zX”séR¸Z//S¼V4AªgDÄ{-[6077uw·ûâ‹ù¢dùNˆ(¡?ôT™‡á8€žð1@xÓËš—³+ÆX\ÜG/Òd ¡¦¦&*•ÊÕµ½‡‡½‘‘ÊÒÒ<55\>Ü´²²ôð°¯_¿&c¬J‹'OâÔêø… ÇŠ¹Œ±š5­ýýÝ6nœ•‘+ /\Øbaaγ·oæáaÏS©T;vÌW dcb–3ÆêÕ³ÉÎ>¦VÇ;¶Fü›•õZÿñÇScU«Zúø8·nÝ1V©’YzúAi¨jlläìÜÖÉ©ŒFFÎU”ŸWe±ÖW_}À32RýùçWju|^MP¬+Öª[·FNÎqµ:þС•Œ±ÆëˆdIGêS~åÊ•¼¼:Õ®]1fm]Ù¼W/ssSÆØ”)þšÃý|{L>ЯssãÓÒ¾^´(1feeùìÙa­)„Ö&ìÞ½HÌuvnëèØªjUËOy#+(ôT™'O pÚ@|" Þ÷2å噸ÅÿÔ© bøä'¿[!%e“—W'ÆXxøé¼/clĈòáæÂ…cÕêøk×"ÅZbH›¿~ýL1î”Òƒzõl¤wŸ>]cÞ¢äO>™Î«S§ºýKƒÎììc ÖfŒÅÆ«ÕñcÆôeŒ-X0VºŽtúô&q‰C¬%Nä‹×³f KNêÏëܹ¥b ,5PL—(O<=;úû»uïnojjÂ6ÌKÌ•š ÖU4AêÃììcb¬|äÈ*µ:~ܸþR§éîC}Ê_²dœZ/r'ÆØ+Ôêø Æ2ƺuk¯y­ ß“ú¤ÁÔÔdÛ6eZ%ÕDj‚(G4AäcÓ§kùáZÁ«Àw•yÒ}xâžiÅcÿý”%66VDôàAº«ÙÙ5ó÷wó÷wÿQJÊ5"7.X|M@À "JLL}1¶ãœó=ˆ¨yózbbff6cL¥bS¦ ¼v-òÖ­[·¾ØÏÂÂìîÝ¿¦MûD,–””JDcÆô…zsÎïÝ{tëÖoôb˜HDFFª |ˆ(2òðãÇÏ÷íKP©Ø¸qýÅ\ww;;»¦_|qÔÃcz“&#ÄZYYÙR þþnâÅ!݉èêÕŸå5 äœ,¾T' `ç<11U, :áĉ‹_}õmrò÷66VAA~aa³Å\© ¢ÌÀ@o"º?M4AêC##U``?"ÚµëxVVNttclÌoÝ}HDú”ïåÕ‰ˆêÖ­!ÊéÙ³3Õ®]ˆ²²²¥Vˆš0Æòí1±cðY{zv¹P‡M¯^Ý6fL1W*Sª‰ÔQŽhÂåË·‰hð`1qØ0/ùV  ð´q9‘×ða×€²ÊÝÝnïÞ„¸¸Ó¾¾.Œ±7ÞøÆ‰ˆ1O±€Z͉¨{wûjÕªHk™˜‹VªdÊ3669ç))×W¯Þµ´Y3ÛfÍl¼ýü\žöì ±˜ô³(„s’F®ôòº&ø,[¶}ÿþdW×ÃÏžeúø87lXK,0cÆÚÐÐ(GÇV£G÷YµjŠ‹Ëi-±@vvî‹¡¹©ä5 dŒyxØ)ø¢V"sØ$=t+'5áEÃI^¸|ìØoùòÏ£¢½½ÒÓŸxzvlÚ´.½^kíC=Ë733!ç™››Š_îÛÿÆú3g®ÓÝcò×âiãï¾»Ú»÷ÛW®ü4{ö¦={«Tÿ&3ÒÂâu¥J¦¢‡5›//\ëUЮ”"%@ >#eÏ›o&¢-[FE%‰“¸¹¹êÍ›¿–Î;8´$"oï®QQK£¢–ŽÝ×ήÙÿý_oÅwÅ9é5ªîÝ›sróæ¯Å†8ç/Þ"¢:uª‹ÅœœÚÑöíGĺqDdk[£E‹úôòyë:uªûû»=ž¹`A8Mœè+;·l9HD‹N›6HvŸI%ìÜùx“DDööÍ5—½,:z™Ô@ͳ슮ãœKM‹EDÄ1ÆêÕ³M¯Û¤IÝ^½22žÎšµžˆÆŽõ–Æ÷yõ!éY¾TÅêZ'æÛcòÅkgç¶›7¿Ã9ŠJ Ù«Y¦¼¥òQǎ͉(**QLܱã(®¼ \+€ ‡ƒ…·¾ ssë°xqà‚áC‡.°·oñ©]@ IDATV¯^ÍÔÔÿý!Õ©S½víêsç¾îëûÞܹŸíÛ—`ee™p)7W½qã,ÅwÅéá¦MëNŸ>ø“Oö­Þ¸1¦AƒZ·oß½zõÆØÒ¥ãÅbË—OðòšwþüMkëÊII—U*¶fÍ4q‚\QòäÉ~{öœHOR¿~Íþý»J£Ò† k_¿þk@ÀŠNZ$%¥©ÔjžžþDZq÷îøsçnVªd–œ|…ˆÞ~{¸¢æy5Pó,»"1`ŒåÕ##•b]"?ÞçÈ‘3¿ýögÕª–C‡v—ÊÏ«ut‘¢ü¼V×:1ß“¯(½9²Ç‰¶l98~˜sË–õ5¯H/äå¼óΈÁƒç‡†î;sæzfföõë¿âZÁ«Àµ(Œ±yóF=ºÚÏÏõîÝ¿Ž=›••Ó«—CHÈ›7nloР¦··ÓÁƒÁv7nÜIJºÜ®]ãðð9“& Ð}­€ˆV¯žúé§o»¸´»}ûØØïîÝ{Ô«—CllðÈ‘=ÄbÎÎmOž\çëÛíÎ?SR®wëÖ.6v¥.+J&¢=:µn݈Æï/¿Geûö÷[ed<½rå§… ö ¢¤¤KR•6l˜ieeyþüÍ-êGFÎ4ÈMQ¾ÖNžìK/ß=¯u,ëâÒN³ ¯½æ©¹.clà@WñOÆyZZšKýŸW2Æô,_ÐóZA¾=&_‘dý7Ûµküüyæ¸qÁâ¶+}®øû»…‡ÏiÖÌöÂ…[ÖÖ•?ûì"Y ÂKwnA™¦¸AB|Zðö@ÙÁ½ø(1œó_~¹ßºõ謬œÄÄPW×ö†pÊœs÷àAzÛ¶|}»Ѿ}‰¯½¶°^=›;wöü·óÄ`IO¸ƒ¨Ü»8î¥0`'O^^»6*))5++ÇÉ©µ¤DÄûõ×û‹ocŒyxØ%'ODâr²‚òCë3ÇxÀPqÎMLŒ¿þúç¼W/é‰CÀ9ï½×³³söìI8uê{Ω~ýšÃ‡{ÍŸ?¦´«V^á¢r%¯w@Y€;ˆ ¬ÁDzÃåŠî_-0˜ÓJØùûÀ«AVPQH?u P@È ÊÝWÁ@Á!+¨pDb€Üô†¬ "Âc`hp¥àÕ +¨ ð˜|9/À+CVP¡!1= +¨èpòƒ¬ÀÐ!+€ ÷L¼Æq‡ ”kxÚ$ØJ3(ƒôc\Ú€'B6>!Päpp)§ôOçðW\È ô3gø`C€=àÕéHo+:ð8»Dÿ=|(¥¸P`3"Â%ƒ†ß+œ 0Lyå )ÎdPáà6H_<š¤Y”Oö†û  ²C‡¬ô†S³²Лø5äåŽÚPÈ   ðkP.H¿É`°ðÅ£P@È  €”eÒ“!%€‚À¯˜AÁágΠÔa÷Ð á Y–tÑ Ôá  ¯wÁ+ÀÝD¥· AQ@V¯‰”Mxà .@ÁDðÊð˜@ÉC>E Yeî ‚Ò€Ÿ‚BÞ…€ÝÊ&¤P–àZ”)1@4ýá*ThPÆàZ”én"Cƒ”ÊdPª8ÇÝD¥Y”H J²(@ñA„Ò…ŸëòOC™;, ‚Á÷j@ù¬Ê |_”#È ¼ÁDE )”C¸VeB*”;8xA¹…kPVá×  ác(âFG¤P>áZ”aRb€ e.@ù‡¬Ê”AH  AVå3wáÕ!†@ÂSP± +€òC_Ô p0zƒ¢…= *dPÞ 1(jÈ  ÂcPÂpЊŽq\ÿ‚r Ïx@ÉÀWáÀµ(·ðü17qi)ü^”gÓPLpE ®¼ )\+xù*d`Hp8äù6ÜAž?®xðžBÂož€VH ÀàáZT8Ò!Áò…CáZTLøÒÒŠ÷{@ñAYTXH _È^@V—8ýƒÄ ?È  ¢‰rà|€d`p7à €NÈ À0 10X"ÀSÅ:!+ƒÇ Ê#|¼"|ñ(€~€AbBA…‡K_1ß9œ ¨Øä × À áPPQ!%(\+C…@ƒ|à +€ò_Nðjp”U8ÆC±Â£†ôT1¼d/`|Pîà[†Š²€pâ ÜA>PDÈ 10(P¼€¬àe"1@nP`Ä ÎÅY€1ű LAX(NÈ  ¸$&&:::þþûïüå3¾œsiVAK»wï/ŠóÇœóÌÌÌÈÈÈQ£F¹¸¸¸»»?þøñãò% w7‘hƒŒ“““¯¯ïúõë333õo»XL^޳³ó€>þøãgÏžé^7777:::==]¾¹"é7y ú@qÐýy,hJ»wï^QÕPk°-pD’¾eH¶¢88ØÏÏoëÖ­éééÒtƘ4+<<\\ÕÕlÅÓ§O80lØ0KKK)æ2Æ6mÚT£F åZ/3Ч|E#½077'¢ÜÜܤ¤$é¢vnnî§Ÿ~Ú¯_?—qãÆ…‡‡kÞ%¥(P¥RqÎÕj5=yòdÕªU~~~ÎÎÎîîî&L8wîç|Ö¬YœsŸ.]ºÈ¯¡çæænÙ²eÀ€ÎÎÎC† ‰ŠŠG5ï‚ÖMhÙ3ʯ²7ðÒŒ¨ò8 ˆÃÒôS§N >\ ¶òOw^ÁV,#¶S§NÕlsžW–·âÙ³g"ØV®\Y>] ¶:®yÚ>üÎ;~ÞÞ[ÃÂò*_z-äR°UD?­ÁVGR°åœç gΜ)‚­ƒƒƒî`+ŠÕñ.äϵö@qáz¸~ýú’%K\\\^ýõ˜˜˜þùGÄJ­³Äô„„‡îÝ»ÇÆÆÞ½{÷Ë/¿ìÚµë®]»Ôjµ˜õÛo¿‰£GNMM½uëV@@@ß¾}srrÔjõ|лwï'Nüþûï;vìèÚµ«ƒƒÃü¡V«Õjõ?ÿüóú믻¸¸,Y²äúõëR}4gÉ¢V«/\¸àààpùòå÷‘>åK­“¦üøãÇ_¿~½|®Z­^³fM=Ž?®ÙFùb¢œœœœ3gÎx{{O™2EL™9sæˆ#.\¸pïÞ½+W®L˜0ÁÓÓ3++ë믿vpp¸víÚŸþ)/çÃ?ìÙ³§ØÜ®]»œœœvîÜ)mKë»×&m,ˆNPbÊÒΖWDU«ÕZã°ô.ò`+¶›WÄÓ‡)Ø*¦çHM”oùšqòU‚­Ô.y°=\Áƒ-À e(BYæàààëë{áÂEPV«ÕÒ,ÅtˤSVjµzÕªU ÐzôH­VçææîØ±C~˜û%Ï"èåÛñ¥uÿÛW¯]»öå—_>|¸I“&AAA}ûö511KjÎ255Ul«E‹æææ©©©íÛ·—o÷Ï?ÿœ7oÞäÉ“;uê$mwÇŽòŠ]¿~ýËE‹ûøè(_¼¨[·®­­­ø·Y³fÿüóOpp°üKEsssmäãàºuëÖ«Wˆ7nܰaÃ3fdee}ôÑGD”““t÷îÝ>}ú888 :ôÁƒóçÏÏ딎.ÒJlN¥Råõ.äææhðê´FÔÖ­[3ÆòŠÃbEq¼üÓ­5ØÊãŒ<ØJëJÁö߈§-¢j%Åaiu)ØvèÐA>ýáÇ"Øv™S©v˜™ÑÍ›Òb:â¼¢òRœ$¢æÍ›ë¶Šþ‘“"v“&M¤`»råJ±zá‚­"¶Ëƒ­â]@°…2YèE|Á‚¯¯ï€Ο?¿{÷î1cƤ¤¤ˆ¹b–¯¯ï¹sçĬӧO‹YW®\iÔ¨‘Ä/^lذ¡ü±3‰"F·hÑÂÄÄäܹsMš4ë^¹rEš;vìXOOÏuëÖIÃw©i–t°Ñdffæãã³gÏ ypñâÅZµjÉÏEɯ'èS>Ïã¸Ê•++N•µlÙÒØØ855UkåйÎÎÎAAAë×¯ŽŽö÷÷¿téÒÅ‹#""Ú·o/ûì³ÏÛ•kÖ¬c,55µiÓ¦bùÔÔÔêÕ«W­ZUkå‰HÚD»víD™›7oÖÞ§Pt´FT4ã°<Ø6nܘˆ8ç:‚­">HÁVŠ Zƒ­"â1ÆòŠÃòeLMM¥`kii)M—‚íçþ9W\ºÕ§|éµüôŠŽ`«µšº¸¸ˆ`#¶š‘Pw°•b»f°U¬¨#ž”$dP0Œ1ñS/wïÞÕ¼(ìààйsç?þøCš²nݺªU«6oÞüĉûöí[´hQ^ÅÊÿ­Zµê¨Q£6lØ`eeÕ¡C‡o¿ýV\ÑbbblmmµS·nÝ|/UO™2åìÙ³&L˜8qbÛ¶m322öïß¿{÷îéӧׯ__GÛó-_š•––fff&6÷èÑ£={öôìÙÓÂÂBZÒÊÊjèС6l°¶¶nÕª•ÔFEáòÔb̘1ß~ûmhh¨›››øúŽT©R…s~âÄ qYãùóçb»—/_–—S£F¬[·ÎÊʪuëÖß~ûíÞ½{ß|óM­Û’VÉky÷.@9Tð_&)RDÕ R–&êlɾÁVkÄãœç‡õÔlëÕ«—W,Õ§|©!Elå©Eq[Å»€` e²(¤¼â5cL>k„ !!!wïÞmܸñ²eËzõê¥u-Íë¹S§Nµ´´ IKKk×®ÝäÉ“¥ûDu*ò=J‰V­Z5<<|ëÖ­k×®ýã?LLLZ·nýÑGyyyé^WKù/NtÉ"®*ˆ)&&&µk×öôôœ4i’bÕ3fXZZŠßÜiÓ¦ÍØ±c·lÙ¢¸%Ižz-X°`Ô¨Q~øáªU«æÍ›mmmíéé>räÈ+W®ôìÙÓÕÕuáÂ…DôöÛoKE½÷Þ{666}ôQZZZÆ çÌ™3hРŶäÿ6jÔ(¯MXYYéî((Šˆª`kk+}lÁ¶wïÞy¨˜’W°Õ±iݵ’³²²Òl===uŸ^Ñ'å/D°÷>½J°•Ÿ‚Q©TElýýýµnK@°…2BËÝuP0/'úûî»ïš7onccCDœó={ö„††&$$펕KeòÄ-TdØåJLaf¡qÎOŸ>ݼysé¾üòKl¥'߀ð+fE€óï@(ØJüرcï¿ÿþ÷ß÷îÝ'N„……ùøø %Àø  ÂŸî’ý€3ÆD°½zõêÝ»wãããE°EJ €kE§€ÃÙÇòÉ'‰‰‰µk×îß¿ÿ¸qãß³aˆ@©ÀŽW¬Jü„sþäÉÍ`«¸ƒ©Ò;òUœA©ÀŽWLÊ ÜAP¤Ä‘ÏÀOöH ÊdE ‰c¥ò¾™ H‰‡`hp} |µ€b#¾˜ ©”–‚“h” ÜBVPœp7Ü2PÎá;ˆŠNžé× ^²P€òAÊjÖ¬õ=Ös]•ÊK¥ò:sæz¡·®£ýËgÌSú33ë]§Î ÀÀ32žêS±Ö™3×_±'_>5‘÷‰x-o»¹yïF†O™²&-í±þe¾ Í:˜™õnÔhø¬YëŸ=Ë,ª:pÎssÕáá‡nÝú­¨ÊÔ­ììe\Ú€Š,..%$dOJÊõÇŸU«V¥k×6ÿûß;ÆX¡ËäœúéððØk×~ÉÊÊiР¦ŸŸë¼ycªW¯¢ÏºFF=ˆèôé]º´.ÜÖu” ùŒyJ¯MMMªU«Ü¯_×7­¬,ó­ƒX7%e“£c«WéÉW§OMôﱤü8jjjR§Nõ!C<–-›`aa¦çåu{ñš™š×®]ÝÇÇyùò ÖÖ•u¯››«Þ¶í°»{‡æÍëÑ+î3º½ú>©Å‹·-^AD;6¯]»Zjê탿‹‹KÙµkáàÁî…Û‹8çË–m_¸p«‘‘ÊÉ©Mµj•ÏŸ¿²7))59y½‰I>Ƙô^sÎ QÝ%èY¾4«{w{++ËŒŒ§ÉÉßoÛv8-íqtô2ݵ’[ºŸDι¿¿U«VEGMä}"Ö""OÏŽÖÖ•‰èùóÌo¿½²iÓþ;wìßÿéSfáj{òäeww;©>¢œógÏ2¿ýöJHÈÞôô'aa³‹¤Œ±NÆ_¹òÓéÓſЩ]‚bgKJJuw·+ò­dP\0Á@„ôè“â"È{XsÄsàÀ Ýëvê4AŒ!D!ºŠnŸÑMÑ?'O^vsëP´[9vìüâÅff&ÑÑ˼½ˆ(33; `ÅîÝñ³f­4ȨŸ…µk£ˆhïÞ%~~݈èéÓºv}ãܹ›II—½¼:÷ž¬»=Ë—úåÊ GÇVDtàÀ©ç~õÕ·÷ï§Õ®]íUöíËŽ^–ïbŠJŠ×+W‰t”s~êÔUWש_}ê?Õ­[]Ÿ2õÇ9OK{yxË–¯¯^ý%7÷¸Ö:ìÙ“0bÄâ/¿ŒŸCD¯^Îù•+?‰×bsEÛ.EêÕ½û[íÚ5ž8ÑwôèÞÕªåê  tá"(Ò@$66øüùÏZyûöÎáýrsÕ³f­çœ wiU>9yrí+nÞü¼M›Fb ’o™â ( ¯2É«=ˇ ÎùÊ•AÑÑËŽ_³gÏbιˆèn…´.Q!û°¨ˆHtô2qB=/yõ çüÑ£Ç!!{;tìÞý-Ñ(±¤è–˜˜å‡´uë»Dôå—ñb–>[¤—{8*jitô²¸¸^ED~w÷î_º×½|ù¶¼‡¥ß™E©äîÝß²³•–ö¸¨ÞßÐÐ}D4}ú‘‘™™IhèôØØà””MbËII©^^3,-½­¬|ú÷ŸsîÜMiëâvˆ/¾8æîþf¥J}Ú¶{à@²è^µZMDÛ·¾páÎÉÒÒ<66øôéööÍD‹8ç—.ý8`À»U«ö·°èëæ6-6ö´(Y¾'÷ï?G¥òzï½Íb‹j5oÖl”Jå$nÿX¼x[³f£LLzZZz;9ÅÅ¥ÈKHM½íæ6­R¥>-[¾«Y>ç\³šý/^ôéã(^Ü¿Ÿ&¦k6As]ÿy*•×Ì™ëÄF³³sjÕòW©¼¾ùæç<¯>åè(_Üð³cÇ7Ó+Uêcg7îÂ…[~ø…­íKKïßÿóÏt±Eù­Aùö˜T¾|?gŒuìØ\´èáà "RÜn¤Ry)š •³mÛáV­FWªÔÇÃcúÎÇD{å;aRRj@À‡õë5kýÕ«¿´mÛHlH³ÏžýCD-[6P´K”£Ø˜+–ÔÚjþâ $çÜÉ)ˆ1OÍ2óí­­ÎksŠOt‡M¯\ùé­·Bë×mܸàS§¾/ݸ P$ˆ8?!ýùù¹2ÆfÏ)ŸøàAÌ¡C+ïÝ‹V«ãÕêøÄÄPOÏŽæU«Zöë×õìÙÍju¼XRìœ;vÌwsë`nnÚ¦M£ýû?kÕ¨Q•16dˆÇ¹sŸåæÆ«Õñ?ÿ¼;%eÓÇûźjuüÅ‹a>>ÎUªXTªdæêÚþàÁ`EÉ))›úõëÊ{÷ÝQbznn|Ó¦¶Œ±¨¨¥ju|NÎñE‹›6µ566²°0ïÒ¥õ¡C+å%lÙ2ÛÕµ½¹¹i‹õ·l™­Y¾ÖJ5‡””MbÊóçGÄ”‹ÃÄÍ&h®+:yÆŒ¡¢g²²¾©YÓš1vôèjµ:>¯>Ô³üÏ?ŸçîngnnÚ¡CÓóç?[±bRݺ5,,Ìýü\<ˆ[”j¢O‰ÅÄ”ÄÄÐ1cúVªd&Jh×®q^KnÝú.c¬S§Š-йïµlÙÀÜÜÔÝÝî‹/拹Z—T«ãŸ>=,Ê¿t)<¯ Ký&£iNÞIDATˆÒäµÒgïÒºßêÙ?vvÍDÍ-,Ìû%'¯—‚þýË7n¿üa´±±bŒÅÅ}$ÕSþ§VÇ'$„ššš¨T*W×ööFF*KKóÔÔpyOZYYzxØ×¯_“1V¥ŠÅ“'qjuüÂ…c¥ÑOÍšÖþþn7ÎÊȈ•J¾pa‹……9cÌÞ¾™‡‡=cL¥RíØ1_ñÅÄ,gŒÕ«g“}L­Ž?vlø7+ëµ:þã§2ƪVµôñqnݺ!c¬R%³ôôƒR ÆÆFÎÎmœÚˆšDFÎU”ŸW5û_­Žÿê«cFFª?ÿüJG늵êÖ­‘“s\­Ž?th%c¬qã:"FéèC}ʯ\¹’—W'qáÂÚº²……y¯^ææ¦Œ±)Sü5[‘o‰Åä¯ssãÓÒ¾^´(PÔóٳÊ=_¼ÖÚ„Ý»‰¹ÎÎm[U­j)ÿ$®Y3­]»ÆbJƵgÏyþügŠhãéÙÑßßÍßßÍË«“‰‰qÓ¦¶Ò2ò:ìÞ½H,/mèÅ0æç'òjµ¿¿›|+ŠvéÓÿZ[­£“{Ô… [þ÷¿áõêÙˆéööÍÖ®}«`Ÿh€’‚}Š"ˆè1)±!‚|I­#c±®4†×_Ÿ½« c©|Qsi !¦f ñò‡ÑØØˆ1vêÔñoP“ÝZ“’²ÉË«c,<|ŽhEDÄ{Œ±#zÈ{rá±juüµk‘¢V⣚›¿~ýÌÖ­’L½z6Ò~Þ§OÆX@€·(ù“O¦3ÆêÔ©.>tÒ{”}¬aÃÚŒ±ØØ`µ:~̘¾Œ± ÆJ§‚ƒƒNŸÞ¤VÇ?x#Öºx1L*aÖ¬abÉ©Sýc;·TìR¥dR4Pþ®‰·»{w{SSÆØ°a^b®Ô±®¢ Ò{—}L¼ãGެR«ãÇëÏ[¸pl¾}¨OùK–ŒS«ãcb–‹rX¡VÇ/X0–1Ö­[{Í=ß“ôåc¦¦&Û¶)£™ôZj‚X^4ÁÉ© clúô!b­  ?ÍOb£FµZ)B“|çÔZ‡FjïÛ·T³Ò†ä{2{‘~èÙjE™úô¿ÖV+6'–›S|¢Å_NÎñV4jT[ÌEVeöE("ˆ` ¢÷@¤†LÛÝ>bÄÃ_\¯Ðó .¯¿>{—Ö>׳¤ICˆ¹¯’Ô©S1öÕWÿ^µØ°a¦Hº¤íZZškö•­­¼ÏBÕêøììcbî™3ŸÊkûÃ_lÝún``?KKsƘ‡‡½XW\:~|Xòï¿cEiW¯nS¼›K–ŒŒŒXKKs##ÕÏ?ï–Ê?thå[o qsë ÊW UCŒǯaŒ™››*ö±–b¿²µµÑÜëLLŒmmmÞxcàãLJÄ\© ¢Ì¿ÿŽKŠ&Èß»ùóÇ0ÆÆëÿÏ?G«U«¢R©~üqg¾}¨OùIIkÕêøÓ§7‰rDZ»~ýLƘ£c+­'t÷˜üµ§gGOÏŽ"uèÐô‡¾Pk»ò)^KMëÊ›pâÄ'òwAú$zzvëZ[Wž4É711T¾çÈë““süþý˜wÞÁ³¶®¬y½BÚ(ùøñ5òO‡>­Öl—>ý¯ÙjQŽ|sš}%ÿD''¯Ÿ2Å_\è}ެÊ&å{yu"¢ºukˆrzöìLDµkW'¢¬¬ly+Ä;žo‰ÅÄá—_î¹ä7>>yò¿§A¤:ˇÿûßð_}0~|ð?ÿdÉÛND—/ß&¢Áƒ=ÄÄaüä ç/\–x®^Ý6fL±º»»¼Âb]Qai+Š÷TÞu:ö.­}®Oÿ°÷â÷ÝÕéÓCVüòË}©Ó M|J\Üi±¡7Þ½,*j©´]µš3ƺw·Ù‚øsum/—+U2»œ4ñÌ™Ç/5kfà6ûóÏçÑÙ³7Äb*“Þ\Ñ©R—*ÞÍ |LLŒ÷ïOŽŒ<üìYf¿~]EFÄ9Ÿ9s]ÿþs’“¿6ÌëØ±5òµÄëìì\ñÂÈÈHQI±¤Z͉HÞÀ]]]ÛËß_1dÌÊúæ÷ß÷nØ0³råJôïåÿÎ`Œqþï &{A,Ø1•¸ÿ·ééOºw·oÒ¤Žî>$"}Ê733!"ÆèE9f²ÍjÙKóí1ùë•+ƒŽ_sâDˆ……Ù•+?Íž½Iþ61öRõ*U2eŒ½xC_ºE^ëçøñ5×®EΚ5ÌÈHµyóé-[¾.¾ˆBCŒŒTµjY/\@DOüñ®¢‡%Šþ…èÓjÍvéÓÿš­æœÏ˜±V¾9;¯/ÞÖ²åë®®Ó6nüŠˆfÌzõê¶øø(“@±À@­‘"ˆ×š#ñ¾‘>uÅ{*ï:{—Ö>×sȲxñ¶V­Fwë6uÆ"š9óµk×"¥s¢…óæ›ƒ‰hË–ƒûö%Š)¹¹êÏ>;(m×Á¡%y{wÏUÝ×ήÙÿý_oÅ»¬è5ªîÝ›sR%¸xñÕ©S],&n±Û¾ýßÇf""âcõêÙ´hQ_ÑÏuëÖð÷w{þc¬u놫WO¹sgOdä\ww»¼»xñ6ͽKþë¯÷Ŭ5ª*z@Ú˜¸cÇQy!:Z­R©c¹¹êB÷¿f«›{u^´hë­[¿uëÖnëÖwïÜÙ³zõÅ…n€2Y D0шˆ%3D/éìÜvóæw8çQQ‰!!{Å,u±õÜ\µæP@ÿ½«ýCD‹GüðÃï®®í#"Þ»sgÏÇO!hý”éÉÝÝnñâÀœœÜ×^[رãxŸw7>yò*"ª[·FíÚÕçÎ}]¥bsç~Ö¥Ëä^½f ¾héÒÈ{÷iî«òÞhÚ´îôéƒ9ç“'¯êÜy¢ŸßÜöí–,‰dŒ-]:^,¶|ùSS㈈¸ŽÇ{z¾5sæ:•Š­Y3M¤LŠ’'Oö㜧¥=®_¿fÿþ]¥} aÃÚD°ÂÛ{v3Eb–žþDZq÷îøÎ'ººN ÙKDo¿=\Qs©NNA½{¿-5Pë^'Ç9—šÐ©Ó/¯RD5ïøøñ>Dôûï«T±:´»OòêC"Ò³|©>ŠÕµNÌ·Çä+Ò‹(4jTOqùtþü°7îpm× HÛ¾ýÎ;#ˆhíÚ¨nݦ:8LÚ¹ó¸T%ygVªd6ztŸÄÄÐË—·NŸ>X^ÎìÙ› š7hÐ<Ÿw=<¦3ÆúõëZ§NuE¼óÎÎyhè>W×iŽŽ“wî<./DG«kÖ´"¢I“V¹ºN{ö,³ý¯ÙjÅæÄ.-6'/Ú´A—.…'%­;ößïWÈãc P& +€b"¤1á²¼¢¸‡Š^9²Çĉcóç‡Ý¼ù›f…åui áæöæóçYò¡@ö®B Ô¦Nõ¿x1ìäÉub ¡÷.óç9rd•¯o·»wÿ:zôlVVNïÞŽŸ|2ýÆí ÖêׯëÁƒÁv7nÜIJºÜ®]ãðð9“'ûR~éåêÕS7oþ_·níoßþ#6ö»{÷õêåÔ³|©>úLÌ·Çä+’,  y³]»ÆÏŸgެþ7)ÎçZclÐ ÷°°ÙM›Ö½pá–µuåÏ>{‡½¸ßFëÞØ®]ã7¥ž!"q/eLÌÉ£GÏææª‡ 󌌜«Ù.·ðð9ÍšÙJ"ÙE9­ª_¿æwîÝ{$¾ó· ý¯ù‰Ö±9yùk×¾eg×”!€r‚åõ¹(ÆHãiÑo¾9·vmÔ©Sß§§?©V­Š½}³ºzW©bAD‡ŸY±âóóçoeff·iÓpƌ׼‰ˆküÚ«üm9§°°ƒqW®üôôéskëÊ;·|ûíá}ûv‘¶{öì¥K#Ož¼üüy¦ƒCËùóÇöé㨵dÎy»vׯÿºpáXq³ŠpîÜÍ7ÞøøÒ¥ml¬¦Orîܽ{Þÿõ%KƉ"#熅ü Ôš?ÌèÑ}å;:¶:r䬢cÇö}q(ý¯Eš Îù¹s7MèÝÛAs]"ÊÊÊ©_è_ý=~|ÿÍ›ÿ'àuô¡h >åŸ={£k×7ˆHüäЦMû§N qphyæÌ§Š%ÏŸ¿¥»Ç ñÛÆÆÆFUªXôéã¸nÝ ñ¤Š¢qË—oÿý÷‡Ýºµ?Þçõ×—©ÄÓœš=üìYf×®Aßÿ³‹K»ÄÄЋȫ‘‘GæÏ»?­~ýš‰‰¡ ¼&¯¿þ{WÑöϘ'éŽÛÚ>ŒP~þù^ëÖ£³²rCÝÜ:”vuJÈÖ­‡}RLL¬¿»†Ö®]ãFhBB¬––Ög3=êý¬¥¥ÅÙÙ‰‡‡‡N§KIIyzÎÅ3¤¤¼ÌÊÊöòZô¥ÝHKK¿víú«Wzzºzzz†566æä䊉‰]¹r)6öŶm; Î;ýÅGøåÊÊʶo÷ÖÖÖRVVª­­SP§Ñhrrr&¸þ„Ö?@½ý9q☽½-…ÒÄN ¼€jlüø‰R}ùàÿ5`ƒÅ¢ËÉÉåõ1ÿîÝ;‡ #³wó12ÒÐPƒïž=ë7a‚Ë×õ„NoCݹÎNilü8|¸‹EÇ0ÆÉ“¾³¾ýx?û'!!VSSãÝ»|vJvvº¨¨HDÄͯ¬Óܼ¿ÿrþéà ääälݺýòåaaavâ¼ys---¾±æªªªÌ̬o¬!D ûžŸ@ °w.ôÌÉɽy3ß]²dñÝ»_×~~~„Ï¿ÿÄH$Òܹ!AA¯«öÓ0 ‹Šz4{öÜÖÖV„…B™7oÁÞ½»455ÙyŒŒŒV¬X†oŸ<é·kמ†††ÑÀéà ;vÂÚÚJCC£k"@˜>}Z×XÅÆd2cc_ÔÕÕY[[©ªª~üø±¹¹!$!!1hРüü|~~~‘–––իבH¤ÌÌL‰¤®®Þ½lkkkFFfGGÇÈ‘#âââ;;;GŒNüç™n,+;;»¾¾ÁÖÖ¦k^¾L­¨¨••433ûì¶´´ „44ÔBT*5--½½½}üøq¡ÄĤúúúqãÆ”••ÛØXKJJ⥚››“äåå455ïܹkb2ÔØØ˜£f?¿3+V,7n,ÖÓÔ222Þ¼É×××355Eååå}øP6dˆ!†a99¹d™¶¶¶„„Deƒî5°X¬ˆˆÛ×®Ý=zÔÅ‹þBBB¡ðð[ÕÕÕîîS82»»O©©©A­Zµ"55míÚ ŠŠ k×®–——ÿì) pzÒ˪㴴tmíæ˜×¯_+..ΑH¡P\]'‰‹‹Oœ8áÏ?·ÇÅÅ777]<ذ¸¸Ã0OÏß|}OÔÔÔP(VWWϾ|ä(Ë`0"#£V®\ãïAKK³´´tÖ¬9xCõõõӧϪ¨¨2ÄðÂ…ö5åáÃ>L&ÓÍm2‰$qäÈÑÞŽµ£ƒYWWWUUŸ°cÇ®ààËcÇŽA1™Ì§O£ûÍ ÏV\\zÔ!TWW¿jÕÚS§Nggç fáèèzëVÄÓ§Ñä•+×DE=úoÿ;®\¹:mÚL …rãFðòåKñø_jjjøx@WdWWöö•+—æÎõؾÝ{íÚõ¥¥¥½¨¿%Ç}&à§éßq|0@™›÷8ª­­µzõŠ>NšîرuÑ¢…ìÙñãDzÓ,˜Ÿ——uáÂYvæ={¼W¬Xúé²yyY¡êê2 cTV–ŠˆãæÎõ8th?öÏ\¸¤$ Ÿ wrz­££Ã=豓ìÕÕy/"âæêÕ+fÏžÙÔTËþ´°ðµ’’"{WVV&$$ßùÍËËS[[ÉÎ:}údnnFXØe˼º¶{þü|.üÙ³ÇÚÚZxbGG»ŒÌ ¼ÃÓ§OeY¾|É´iîì3³ví*|›Jm9}úäÔ©SÂÃC:;iÝnÑ¢…ÆÆF}Ÿç~ÿ¾`ÕªåË–yä~2'`@€«pðÌÌLËË+º§gddtttp$>{ö¼½½=((8((8''WMM Oß¹s{MMÍŽ».\Ð[C=–%’’$999„~Œaؽ{÷MMMð‚}ѹ}ûÖ7IKËM˜0YQQ¡·¶H$ GÇñ“'O:~ü“ÉܱÛýQ×ir|WOOßfw@GG?'õõõ’’’£**ʆ††îîSììlñ”û÷p©˜˜~¤7n„Œ1¼­­íŸ¶ôØmum—J¥âÛ{÷î¿u+ÂßÿÌ”)n=Nd˜™™VTT`݆î[ZZÞ¼yÓ=¿††Æñãdž ³3ÆŸò d?~.œLþáM€Ÿeþü¹óš››%$$º¦ÇļÀ'q»"‘HÆÆFsæxp¤wvv’Éæ7o†'%%ÛØpŽØ¿x7|¸}oe»*|ýZ÷(…’––*..ÊÍÍ ps›VX˜Ç’»ÓÒÒ¼}ûî'2tïÀ˜1£âââ}}OTWWGFÞï>j›={B¨¾¾¾ºººk:‰D’““ei×CîÚVzïÞ݉‰I+V¬ÖÐP_»vµŒŒ G†I“&lÙ²5>>ÁÞÞ®kzLL¬¡!ç„:‹Åº}ûΕ+A#óós»®X L?e9[ʹŸÑ øŽ,—ô˜ììì4mÚÔ•+×\½ÈN,--••å ¡ùóçž8qê?6â34ôæôéÓ˜Læž=ûV®\>eÊd7·i ± !qqñ÷ï‹Byyo†·ï±,>p„WÞ5f{xÌŠ}1nÜX„PKKKsssgg'Bhóæ­×¯'&&1™L>>ÎWlu­!$%%UPP@¥R FCCǧ=v ##ÓÃc–³³Çï<Ço _ߎŽã»V5eÊä#GþjiiÁ/ß#"n»¸8óóós´Õã#„ll¬ml¬333ÿøc‹´´Ôºuk”””ØŸ***úùðòZ–––,""‚'2ŒÂ¢®7…3™ÌÐÐÐ0WWçk?dµ<à»ãõööþ±-øû£Å~là»»põò<窪*Ÿ£T*522êÝ»÷sæxt¿L400hjj e2™=6Œœ••íåµ4%ååºuk„„„.^¼v‹Hä533UP¿p!@PP@@&&&ÝËÒh´½{deeÑét}}½]»ödgçP(++ËÑ£Gݹs·¸¸¤±±ñáÃȤ¤äÒÒÆY<|Y_ßÐÖÖûB[[ÛÊÊ’£‡¾¾'‹‹K(Š––¦„„„††zpðuuuµ¸¸xEEŸc‚‚‚ÖÖVÞÞ»cbb›šš‡5 ¼wï~SS“¾žžîˆ£||Ž=ê{þüŶ¶6;;Û´´ôýû¦¦¦S©ÔòòòÄĤ‡#ù+ àò‘#_½Ê8yÒïÍ›|IIÒˆÃML†îß!,!!QRRROO/((øúõòòruuµ¬¬¬K—.¿ÿ^YY©¸¸äÜ9ÿ÷ï‹åädõõõÙ"//?yòD55ÕC‡Ž<~üDOO—½ZÞØØÈÀ@ÆßB<<<))/£¢-\è‰/y£Óé—.îÛwÀÐÐ`÷no 2‘Ø—Ÿõ¼}ûkø±~üûÂÉd¸ ç>¼œ÷Dq`2™ùùùõõ ¦¦&Ý×¢s䬩©QTTüì 6†a555rrrìœ}/‹¢P( CRR²¬¬L\\\\\¼££ƒH$–••ÉÈÈô}X˜F£ÅÅÅëèhã÷¶}¶ÏnnSýüN())aV[[ëéùÛòåKÙë½ûðªª*™îã_ª´´ôÔ©Ó[¶l’’’êZÿ‡ŠŠÞè+**²ÓýüÎ())Nœ8¡Çúž‘­QZÚ7vð]@=ù\8&“ig7âùó§ìû¸Ö¯ß8j”׆pn!€íÀ×#‰çϟݽ{¯’’N¯®®61êââÜßýü_€À7122:pÀ¨¿{ø÷…\ B8À• „ƒžôòŒtàé Â_¢O7Ž~áW‚p%áW‚i-Ð7L&²²çLLKúÏ.•ŠìGq}Ž ¨§Å}0ÀVøË%ðHQÀéW‚p%áW‚p%áW‚p%áW‚p%áW‚p%áW‚לôª©©Õ篫É)9üü|""B¡9³ŠÞ–µ´PvïZúuuúüuõitJII//†††aMM­’’âcÇX.^ä&,,ø‰²Ö¶žÅÅ•žó'<°êëZÿ^Žùû¾ùàž¯®®zoy²³‹æÌÛ^UUwéâNW×nïGðÍ „÷,:úåÌ٪୬,‡¢ÓÞ»üܰnÎWW»qÃÜ™3Æ©¨»()ÊÜ¿ë‹Â0ìÎX·©㣟œáççë­ìã(?qÉ4ý«[ÿ^RRrß½//)©úD76ÖÙ·gùD·õLfçOìüôTW×Íòø“@@·ÂŽàñ!$ À¿ß ‡‘äïÛ@˜]Å󉼔v*»ˆ©‰.úgxÿYÀF /ywo:úÙK„¼¼4¾« 0!ôìyêÊ38rji)Ïžå|-rwAImm“šªǰ™™¾w€Nïxö,URROÁëÇЉM76ÖÁSÌÍõ»–"“ þÙåã8v6ï^aáÑá·¢åä¤ 5·´uÏໃÞƒ… &ò ŒJ Óx$Û°~Άõs6o9yèÈe'GÛ½{–#„ "57·íÙ½Œ@ t¯„Hüšs+*"Œb0þ9§Ó;؉ÝmÙ¼ øZäƒuõM'ÿÞ­¼)ADDˆÁè`§Ðé „¨¨Po¥ºWÂ!$ô±Çœm¬ò?·•H$âÃò~Hïžžºß©Mµ¿-ÚÝÞNc§w½.G-_6µ¹¥íÙ³T|÷ýûò5k}¾±éžB/â^á»ø†çü =f60Ðtw}5èÌ ’††R_ê_¸`bCc >gaX\|æ i’«Ë×ß·zó ‹Åúmá$"‘XTô¡“Å—æøÑx½½½l þþhqÏh 35Ñ6uÌÃÈ„/ÅĦÅÅeœñ˜6„Ðî=ç/߯ûøôÀ¡ÀãÇ6~EýŸ~˜ë—úº‰ßþçåJ‹~›ÜÐвjõ‘-›‰$VUUç0’|ælØi¿Íbb"?®Qȸ „—— ^³z–””Äw¯¼¾¾É~Ä¢ý{WNž<Oim¥ØØ-=ÊâK«23Ó:TGPØf·÷Rgg;„“Éœ9ûϘ˜ô€‹;{,2b„ùŒéc““s¾á¾Î jgkÒ[WQ‘÷Þáåè¼ !4hiÏîe£Ç.Õ¬¶éOôÏq…ߊ¾ry7@@efs3†auuM«Öö=~=;»ÈÒrˆû´?^½Êï^9†aEEŽŸ¸án›¨¨0ƒÑ1ßs'Ƙê>:ïÍû¿ûâk²ØZ[)ÚÚ/lllA½ySììºúõëwmmíÇO^ßw ,>#-MB1™O£S~[¼!Ä`tDF%®\}Øÿ|„––r釪YO󖺹oÔÑQMLÊvv]=z԰̬'56¶ìÙ{ÁkÉ>s3ýÐ]\ìØýiéo´µ”»÷gýº9ââ¢ø¶……á•Ë»çÎqÞ¾ãìÚu>¥¥U½ü2\;ÖjÈm£ÃÕÕ¾àÍ-~~¾)SFÉÉIáŸzÌv’‘‘””77××××àççËÍ}‡zò$¥£ƒiggbgg¢ª*Ÿžþfýº9¡;¼|¯í­­v* !D$ö¼Ö !ÔÔÔêµdߎí‹ììLZ[ÛSRr‡733Õko§9;ÛÉÊJ‘ÍõŸ=OíZ*âöó³çÂ|_‹‹Ï¸rpþf ''}êÄ≫]]u'GÛ¼¼÷ <'D;Ö22*!”œœzóÉŠåÓùøˆææúd²þögاH\\„L6ÐÑQååå))­²³3QQ‘WSSHJÊFYZ13ýûRžÉdÊÈH"„ôôÔG 7;çÞÛÙ¨®©OKËKH̺v#JWWmØ0C<]LLdއ3¾--Mš7×%¿ dŠ›ƒŠŠ¼“£mddþÑÙsá¶6CµµU/rKIÉàŸ7×!TSS¿u›ßú Gm®ï1œ¼qT*}ÿi††Zçý·­Y=믣AËW,,,íK)àRn !D CCM„’’ì?)„.ŸôtÕñm!!ÒÒR®ªªÃ¯këêšØ#ÛZ=]½±áa¬¬¬†=ÿüyÚ³ç©!¡¥¥%vn÷âã#2ÏcÒðOu´U::˜÷A¯kè]«;ÆrêÔ1mEF%ºOÅÞÕÑV}ð0~J—„‰$6{–㙳aö¯|“¶zÕLö ÑÕUÃO‚  ÞÜ£ÇI]NG[ÕïôÍÇï~ŠºnSÿé*ûŒJK“Nøn<çÎÇG,zûAVFª·Ó¥©¡äèhƒš6uŒº¦«¡–››Ã?µýç ’$‰ÉÉI£._BHGGõåË\„P}}³¤¤¸¸¸BÃ0÷iØÛ™úŸÛÖÛf¦zå5ÝÓ32ò‡ Ñî^JCCé¸ïÆËWî·<'+DBB´·#®6C8BHTDøŸâ3 ]hÚÚ Ý³÷//ÏÖ?37×ïK+zzê–ÆܾÞ‘up ;8ã2tmÒÓ߄ٳñjìkÍûði| F{—ÁèàïžmåŠé#¼kqÙ IDATV­œ!%%Þ5.²—Èu©¿[…|=vïÓ]ÍÈÈŸ¿À;"ÜGKK¹±±µ¢â#Fï±ol||D55…'OSØ!œC÷Þ"„ÆŒ—á{üZuu}äƒüü|!ûÜÿfØÓi3699ÚxΟнéùó\=ænknnãÆ1±é¦¦z™Y,ÖíÛ1W‚8Œ$çç…w]¿˜7ŽÂ0Ä1OŒa;¥Ëæ¿Ùjkå䤶mým럿yÌvbŒ‹Ëxô(©·†xxx¼Ož ÉÊ*ìÚVii=uV‰IÇ?ÊÍ}ûúõ»nýáìçºþ9Îqñ™ø6‹ÅŠOÈô˜íÈq8!CC­¡Cuæ/Ø9Åíß ô®'„½1ÅÍ!;»ˆÅcbÓñqén§uÝî^gPp¤µ1~A_Qñ‘Åb]¿ñ¨³³“ãP8¾)) |&;'ç-GfŽmv‘ŒÌÙNkVÏ:x`™lÀNçåå9c|D¸¢‚ŒÇÜmÇO\oo§u=uÎÎvÓ¦ŽY¹êP×ÄÒÒ*YÙÿ 0™Ìàk‘nîëšC®X³zÄoÀ¯×ÛÛûǶàïOè{ö oß¼ù¤¼â£ €¾¾BhÏÞ O£_¶´PìíLŒ‰Iojjj¬péî½û/ššZ 4ÕÔ¶nóûýãÇO\?z,8?¿Äa¤¹€ÿñ×SSóºÞ3ÆaÐ ÒT÷QÛvœ.)©z÷®<ôæSw÷ÑÁÚÚ˜——gÜX«#>W)jAAIQÑ''Û à‡×o<*/¯QWSÌÈȼ|¯ôC•²’\k+Å篠ôWùõõÍÆ:tp׆ŒŒ´?|¨~™ÐN¡>ssÚÔ1®.ö ™'ýBÞäKJгGH¢ F‡‹‹=¾ŸyÊ/$?¿DBB´³“uìxðë×ïEE…ƳÖ¬vôX‹ÅЏýœÅ¶mý‡‡Ç{×9ö)º|åþÝ»±µu†š·ïÄ„…=ýXÛ8XG5&6ýÚõÈÊÊZc#Õ€KwH$±ä”}Ûwc45•ÔÔö콞žÏd2‡jñ¹õ(±ªª®¡¡ÅÞÞ!4HštÎÿ–‹³íí;1ÚÚ*{ö^ÈÈ(äWR’Ý»ïbVV!Þ¡¯¯¾k·vÎ[ …jee¤ /=Âa±Ï_W >!¢­jgkÂi ººjӦޡP¨Þ»Î½}[fl¬Í¾"wq±«ªªó9$!.J¥Ò"£ß½/Ÿãá„_îÓéŒKw÷í04Ðܽk©Ùðë¾Æ…ûÈËë{Vß¡—‹Æï‡LF)ç~lmùóÔ(ò˜1–¡½vèp …Bó9ÒëB¶îš³²Šäå¥Víþ0µúú&~QÑO ï÷“ɬ®®WT”éq¨wÿ~œ¡¡&Ç=T½Á0¬²²VFF—þjÕÕuââ¢Â‚Ì>>ïãdžŒŒKË!$’X_úéæ¾Ñïä&%%Y Ãjk=z/_:ÍÕÕ¾ÇüÉÉ9÷Äq< Édæç—Ô×7›šê²×¢#„üN‡*)Êv}ZÜwf¹¥¥ýšà йð/•_Pâ9ß¿¤47Ó—ñE5HII|âQ'øÝSߎH$*+ËõøQddBBbÖžÝËÞWôغ#ìEß‚}/uߟb+++5~¼u3wvvVW×KI‰#„‚¬¬{‘]¬¬Œ¬¬Œ8‰Dâ!œ÷Ó#„V,ŸÞÇnÀ¯ä¹ ohhö=~]RRŒ——·¢â#‰$¶~ǧ×d 4ïß—Ÿ9¦¬,7kæxŽYÞ_CNÎÛk×£””dèôŽêê:##í¹s\8î à*0 ý"!€B8`@ˆ+ÒðY®ôÿÂ1 ûø±¡³³!Ôõ¹(€«µµµ·¶Rðm&“Ù¿€Ÿ†‹W¤ÇƦoÛqÆ@_ãÜÙ­}ÉzóIAA©®®Zee­””x\\æyÿm?¨oeeÕë7+((Íμ:åòøIrccë½;Ç8nÁ:qòÆ•«÷GŽ Ï›ëÂñÚ®o—––wízÔ«Œ|=]u==u Ãrߊ‰ _¹¼ûKk»òèö혊ÊZkã?~Ÿ‡¯Ò/)©ü}Óñ–Šû”Q?î}á=Â0ìbÀ””\“Á<<< ÍÓ¦ŽÙµû|pÐÞŸÙ è/\ÂGŒ0Ÿ1}lrrN_2}¸s'–ýŸ{XØÓªêº/mñRàÝžû’SEE~Ï®ecÆ-ÃwW®˜ÑÑÁ|ò4%(øáÊ3ØÙètFAAIQQYjÊÕ±6›L606Ö¶^¿ÖcâÄxbSSë$·õ†}i‹3gŒ×¬ff1ÇÿìVö]vêêŠÓ§%òòöö°ÕõýLö𙳶()ÉúŸÛŠ‹ÅZ´xþ†:øÀÝé‚‚}ÌŸ!**ÄÞuw­ü…·SWUÕef~>ß¿}ûÏ-m||D¯ESüÏGt½ **Ñq¼ ñ;Æï¶m?p龋?ò¥ë3OH$±¹s\ðWš~)SS= ²»r\aaé'ž×Ý—žÉùŸ¿õ:ïýÁ«Ø§Ž‡‡çØÑ ø„†-]¶ÿRà]üµ4ðKp!>35õ5‹ÅâèÃØ±–ÍÍm))¹ì”¦æ6öKÒØu&'ç_‹|û¶Œ’y÷n,ÎHIÉ}ö,•B¡öxŒeeÕ6Ûòç©éÓÆ.\0©Ç<ø»ÆÇµÂ0¬¤¤òÝ»òüü …ÚÚJ)((),,mnnûð¡úéÓ”ìì¢ê꺇ãÙ=Á-^ävùÊ}öJ‚††f)) vÍÈÈ¿v=*#ãߨÓhôÇ“CB—•U#„z<“†%%e_»•“óöï3Óí+à8C‡/{Ìvâx&„„¨“£ Bˆ@ œöÛ,.&2cÖf¿Ó¡T*gqø ¸þæM1yØœ‹w0 c2;׬ó9y*äÅ‹W›·œš>>â8Ç™™]K½}[¶rÕ¡ƒ‡—-zñÂŽîsê/S_ß½{øÈeü….ªªòÒÒ¤ŠŠ›ÿ<9zìRN¡P‡\|+ây{;­¥¥í¯cA ízýROOýô™›kÖú°fÎ×ÞN»s7ß½ötú´¿ß¬ºný_)/sgÎ÷äiÊÑcA¡òò'—ÕbbÂn“V¬:ý²û™d0:æ{î¤ÑSÝGç½y¿ñw_ ú]§¾¾©¸¤R[[¥ûí½s ¾ÁÃÃãî>:üæm-ÏÞG|®|âp£ÂÝÝG/]2•Ng‰DaaÁ±c,Oÿ]TTòš““-ƒÑñôiJ÷‚;wxùîõ¡è<<<ÁA{Ÿ?=;{–cvNÑè±KÏž C%'ç„Þ|²bùt>>¢¹¹>™¬¿}ÇyùA³fŽÏœ?Ïõ¸ïÆ5«g™™éik+«(Ëcid¤:|䲊²¼……¡àòeÓö¸Èd2§ÍØôÇÆy&&ºjj =Îõ.\01,<º¹¹ !”˜ek;”#à iRgg§ŒŒäBω‡}® „øøˆžó'ðó­X>ÍÄD×ÞÞtÅòésçïÀcjNÎÛÅ^{Ïž ß¼ÉÓïÔæ£BHAa––²–¦2‘øïê[[“ëÁûtuÕï?ˆOHȺqtó&O…AC†hn>ÔxðgMMeŸ#k£%Þºõ /%&&2k¦ãù ! ÃZðyñçÏÓî?ˆ[ºd*Ïúu2™ÌuŽŽkemmÌÏÏgc=T\\¤û™ô=~MJJÜÁÌÏÏ7cú¸Â¢ÒˆˆçÝ¿‚®‡ƒ¿ƒœØíQöÝ„ñã­Cn´±6^¾âà®Ýþ ÍŸ-\aÀ…p„×b· àÈÖVJuu¢¢ @°·7ãá|èpàÙsammí-=]Nii)ão6ëQSS+@9’|ðÀªWiÁ7®ؼå‹Åzô8 Ï&NG[õÁÃx„@ÐÔT”íñí&Ïž§µ·Ó‚‚?ÌÉ}«¦ªðúõûâ’J]Ü,øZ$þ6‘îSàÇŽnH•ôXPì‹W--ÿ9LöÓËG 7Ë}ý®¢âcMMýx§•Žã­^ÓÛ£×q*Êr††Zîî£íìLð”û÷ãBD"1äúýŠK*9žIÎnއ‡g¸½YdT"û£Å‹&?yšR\\‘’’keiôÏ IÁOÈÇ#F˜·¶¶?~œ<ôŸ!Í›<-, »÷-2*±ë/¾|ŠŠ2²2’å5Ýk{ù2·{"BÈÖÖäÂùí?6Ì¿ã' ¸È@ áJvv&WƒÞ¾ã6y$B(ðò½­Ûý–/›¶tÉTyyi„Fÿ¢:/_¹_UõïôiSÇ ¶¶¶ ðw–g0:þž^íºü­+|BD56Öžãá<ÇÃy‰—û¹³[ñõkŸ}`­×"7ÿó·?N7ÖŠã£ææ6‡ÑKäå¤×¯›ãâl‡ÂpdÃ'†ED„ää¤óóÂÞ¾+›6cSTTb_ž•;{–#B¨¾¾©º¦ž}È.Îvç/DÔÕ5õVª½&&öoµ°046Ò¾p'&6}äHs<‘D“““ÂOÈç›!‡$%ÅED„ð+æágR@€¯ÛWð÷¯ŸÞ¾0žëí;1Ý9!1«{~ …ê{üÚŒY[ÆŒ¶¼wçXoýî2C8BhÙ’©~§C;:˜BB‚¡“§B<çOÁ0¬¢¢–Å‚‚#Böïÿáqq%õV!†aWƒ°w©Tº¦¦’„„è7‡ìì"v‰‰MŸ7ו£fœ¸¸(;óÞ¼GÍŸëúàa<;SèÍ'::ªds}öй²²êÎÎW´µ·ÓðâÎζµµÉ)9ƒ‘þièïJ^¼xÕÒBÁ_SVQù‘Åb•–VÅÇgâŸÖ×ÿ=|çnìÄ Ãñupâ⢛þð¼zy÷ÛweS§ÿqûv Ç2:¼rŽƒñ=~]_O!ÔÐÐ|Ê/ôÈá5ÖÏ™9{K×¥‚õÿ 8S(Ô˜Ø4<öãÂâEn ³¦¸9dd´´´á»ÏŒŽ9NOþ™õhkk¿wïE÷39ÇÃ9îŸcd±Xñ ™³{ü bcÓ££_âÛ»w-­­mâX•8b¸y×”ææ¶ýæ/Øi ¯îãææð£^H ?¯··÷mÁß-žð¥…´´”ŽŸ¸î½s‰””B¨³³3ôæ’„XÔ£D;Û¡÷î¿05Õmnn;éò&¿XRRÜØXçø‰ë©©y½ÝÝ”œ’S^þñÝ»r„a55 ‡\þã÷yJJ²ÒÒ$ÝÁjG±X¬ˆÛÏY,lÛÖßÞ¾-;x(0#£ ½f` )""„RPt!à¶  ?@01Ñ50Ðljj }Ìdv>zœ4ÌÂPNNzÜX«¿ŽaVXøáÙóÔ'Ñ)ÔvÚØ1–Ç|ƒýÏßJNÉQR”UWW¤Ó#Éjj ááÑþn”R(í²²Rúú·ŸS(Ô’’J~þœÜ·­­” † îÝw‘Dko§=yšœ––wöôaaAöÑññ‡ 2ÅmÔËÔÜ}û/²X,}=užÔÔ×û¤¦åQiôòòšÄ¤ì‡‘ Gþºx÷Èá5W®>XøÛ.IIñ)n£0 ۽竌i)q--åø„Ì—/_wvvÖÕ6í?°vÍì±ÿ3ÐÑQ=|äÊÙÓ[ØCÜ’’â&Cï?p a(!1K’$¦§§aooúøqrFf~CC˽û/¦L%$$Èq&Œ´?|¨~™ÐN¡>ssÚÔ1®.ö……¥Ý¿‚ã'®_¸³Äk BˆH$Îñp ¾õøq‰$VSÓp+âÙ A’왂ÚÚÆƒ‡¯\}0mê˜æji)ý{î#/¯¯, ?ÌÀ}S•JÃ/Áq,«¢â£‚ "‘ˆO$QmUUuòòÒt:#3³Ng˜›ëw^Å0¬²²VFF’ã&%†ÕÔÔËÉI³ƒ“ɬ©iÀ'ìÙÙêêšDE…ÂÇ ÒÒ¤®±¶/ššZY,–””‹ÅÂ0Œ——!$(l]òþž€?‘È+&&ò‰âá·žµ¶R~[8ù‹Úíêà¡À’’ÊÓ~›«ªêõxåZVV­¢"Ï‘ˆaXUUŒŒd×/¨½F¡Ped$»fë~&««ëe>}•|5èÁÜ9.]SÚÛiYY…||DccöׇaØ›ŽÏšéhf¦÷%ÇÝ xS`@¸!°uvv Û¼{§{ÈüAöì½PRRyñÂÀZùÕÙÙyáâí%^î?»aဠæ:¾k÷y;;“'oTùCa¿Â³g©oÞ76µ„‡Gÿ„æú.%%×}Êèþî pÀçÀU8`@‚«p€+A¸„p€+A¸„p€+A¸„p€+}ÙcJ¿’å’ŸÑ ðÿä§„px´ àjð0 Á@:À• „\ B8À• „\ B8À• „\ B8À• „\ B8À• „\ B8À• „\ B8À•àe£W"`Öß}ßfëV´o_wÀÏé\îí[ôèÊÊêï~øÙ „s¹K—Ž íï~øÙ „s3*=z„УG¨±±¿{à§‚ÎÍ‚‚Ð’%HH-Y‚ÂÂú»7~*á\«³……¡©SBhêT†:;û»O~á\+9ii!II„’”Dd2JNîï>øy „s­S§Ð’.7ÜOŸŽNê¿ÞøÙ „s§ÊJÔЀ†ý7ß~û¶¿zà'ƒή]CëÖq&Ο.]êÞèðt6.D¥"{{‡„„þ“ÞÙ‰,-{Hð+ú)ÏHß×½{HGÅÆö𑎠B‹ÿô>øÙ` ))¡ùóÿÝݶíßíùó‘ÁÏҹ™ŒÒÒú»~6¸ ¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+A¸„p€+û»à×E&£¸8$$Ä™È!%ñòrYž´4ÎÈóíy_ˆ€aX÷|2y€þoH&£´¤þî°øú»p=H¸„p€+A¸„p€+A? ¬e½![÷wø@ý©£££¾¾¿-‚ÉdöwwÀg`V[[Ëb±ðmøÊè_p_8è ‰~~gÈdsI¢ªªÚÁaä™3çNŸ>)&&Öß]Ck×®¿q#4!!VKKë³™õŽ~ÖÒÒâììÄÃÃC§Ó¥¤¤<=牊ŠâRR^fee{y-úÒn¤¥¥_»výÕ« ==]=== ÃsrrÅÄÄ®\¹ûbÛ¶çÎþâ#üreeeÛ·{kkk)++ÕÖÖ)(ÈÓh499¹ \B뀞a€Û™›÷wzÃèíωÇìím)”&vJ`à„PcãÇO”êËŸ€ÿo¬Ã,]NN¶¨(¯ùwïÞ9l™½{옑ц†|÷ìY¿ \¾®'tzBèÎpvJcãÇáÃíX,:†1Nžôõð˜õíÇûÙ? ±ššïÞå³S²³ÓEEE""n~e÷/-ÜÒÁÏ–““³uëöË—„……Ù‰óæÍµ´´øÆš«ªª23³¾±„@ì{~>>>ÀÞ]¸Ð3''÷æÍp|wÉ’ÅwïF|]OøùùB<<ÿþ;%‘Hsçz466"„¾®ÚOÃ0,*êÑìÙs[[[B eÞ¼{÷îÒÔÔdç122Z±b¾}ò¤ß®]{~DgŸéàg;v섵µ•††F×D0}ú´®±ŠÉdÆÆ¾¨««³¶¶RUUýøñcss3BHBBbРAùùùüüü"""---«W¯#‘H™™™$I]]½{Y„PbbR}}ý¸qc ÊÊÊml¬%%%ñ†X,Vvvv}}ƒ­­M×¼|™ZQQ!+++$$hfföÙliiAih¨#„¨TjZZz{{ûøñã>Ý:“ÉŒO`±X¶¶6F ãEºòó;³bŲqãÆb==T±´´4%奔””ƒÃH^^Þ¼¼¼ʆ 1Ä0,''ׂ,##ÓÖÖ–¨¢¢l``н‹qûÚµ£GºxÑ_HH!~«ººÚÝ} Gfw÷)555¡U«V¤¦¦­]»AQQaíÚÕòòòŸ=E€ï®ÂÁÓ˪㴴tmíæ˜×¯_+..ΑH¡P\]'‰‹‹Oœ8áÏ?·ÇÅÅ777]<ذ¸¸Ã0OÏß|}OÔÔÔP(VWWϾ|ä(‹*..ž4iJ`à•Ž¦¦¦†™Ù0†ª¯¯Ÿ>}VEEå!†.°¯)öa2™nn“I$‰#GŽöv¬̺ººªªªøø„;v_;v BˆÉd>}ýÛo^x¶ÞZ§R©ãÆ9‰D~~~]]CSS“×¯óØ•¿|™z÷î½Ã‡}²²²BªªªÒÒÒ Ý¿ÿÐĉ§OŸ…aX]]ýªUkO:3l˜…££ë­[OŸF[XW®\õè¿ýï¸råê´i3)ÊÁË—/úçáöiiéjjjøx@WdWWöö•+—æÎõؾÝ{íÚõ¥¥¥½¨¿%Ç}&  „ƒŸJ¥‰}þ9|ØGEEÅ‚,$$´|ùÒ}ûèèèìÚµsÇŽ­çÎ/,,\²dñ©S'LLLÌÌÌ´µµTT”ÇŒmddÔcY„‡ÇlII’¹¹™¾¾>??nîk„кu‡ ³pqq–““[±b»‡11±L&ÓÐÐpÁ‚ù½õ“B¡¤¥¥§¤¼¼y3ŒN§»¸8ãébbbsæÌfgë­õ'OžvttØÙÙÚÙÙªªª¤§¿Z¿~-»”‚‚‚––¦––&‘È‹zÒÔÔäåµlÇŽ­‚‚‚vv¶­­­))/‡·733miiqqq4h•Õ°7B'Ož$%%eoo÷èÑc¼,F;sæÜìÙsEEEoÞ¼1oÞ\>¾ÿ<½œJ¥õñû244<þìš5«þúëØòå+ {ÍÚç¿€O€~633ÓòòŠîé‰Ïž=ooo  ÎÉÉUSSÃÓwîÜ^SS³cÇ®… ôÖPoe ‚žž.¾-$$D£Ñ0 »wᄅ© ;û¢sûö­7n’––›0a²¢¢Bom‘HŽŽã'Ožtüø1&“¹c‡7û£®Óä=¶ŽÒÒÒ¬ªªÆ×§ÔÕÕã³l**ʆ††îîSììlñ”û÷tÍžþŠÁ`<ƒ¬ŽŽ6~& ‚žž»­®íR©T|{ïÞý·nEøûŸ™2ŭlj 33ÓŠŠŠîC÷---oÞ¼éž_CCãøñcÆYŒãˆOy~Oþîþ~@00qÕ75þ\yÍÍÍ]Ócb^˜ššrd&‘HÆÆFsæxp¤wvv’Éæ7o†'%%ÛØpŽØ¿x7|¸}oeш¡Ö¯õ8Á,--U\\”››áæ6­°0#$w§¥¥yûöÝOdè) lmmöìÙÇËË»uëfsóžgÜgÏž…ª¯¯¯®®îšN"‘ÂìÙ³ðš»r×¶zŒÐ{÷îNLLZ±bµ††úÚµ«edd82Lš4aË–­ññ ööv]Ócbb 9'ÔY,ÖíÛw®\ rp™ŸŸÛuÅ"à»ûÜpVʹŸÒ ð+²\Òc²³³Ó´iSW®\sõj ;±´´TV–3x „æÏŸ{âÄ©?þ S"Ë IDAT؈ÎÐЛӧOc2™{öì[¹rù”)“Ýܦ%$Ä*(( „ÄÅÅß¿/Fåå½>ܾDzèŸ)ñúÙ³bc_Œ7!ÔÒÒÒÜÜÜÙÙ‰Ú¼yëõëAÆÆÆÆÆÆ‰‰IL&“cœ™£B„””TAA•Je0 ŸöØzmm­œœì¶mrDY<Ço _ߎŽã»Vell4xðà˜˜ØQ£B¹¹¹ÁÐУ­îíâll¬ml¬333ÿøc‹´´Ôºuk”””ØŸ***úùðòZ–––,""‚'2ŒÂ¢®7…3™ÌÐÐÐ0WWçk?dµ< +^ooï^?ô÷G‹'ü¼¾€_Ì…û¨—癸¸8WUUùø• R©‘‘QïÞ½Ÿ3Ç£ÇËÓ¦¦æP&“ùèÑ“aÃÈYYÙ^^KSR^®[·FHHèâÅKaa·ˆD^33Sù  dbbÒ½¬¬¬¬·÷ئ¦æ¡CïÝ»ßÔÔd` ?eŠÛ;w‹‹K>ŒLJJ.-ý0l˜ÅÇ‘õõ mmm±±/´µµ­¬,9zèë{",,¼¸¸„B¡hiiJHHhh¨_WWW‹‹‹WTTðñ9–‘‘!((hmmÕ[ëjjj[·nÿý÷MÇŸû@äåå'Ož¨¦¦zèБǟèéé²WËèoØð;Bˆ‡‡'%åeTÔ£… =ñ%ot:ýÒ¥À}ûìÞímaAîÛÜyÏóú€¾#ô8xø72®ÂÁ×ã5þôçL&3??¿¾¾ÁÔÔ¤ûZtŽœ555ŠŠŠŸÄÆ0¬¦¦FNN޳ïeB …Á`HJJ–••‰‹‹‹‹‹wtt‰Ä²²2™¾ Óh´¸¸xmŽYíÞlÙ²uÔ(‡1cF„öööC‡ŽP(ŸÃ}lŽ­¾¾^@@€ý`¸¯VZZzêÔé-[6III±1 ûðáCQÑ[}EEEvºŸß%%ʼn'ô8Pß3²5JKûÆN „ƒæs!°¹¹M=xpŸ®îßËÍîÞ½÷âEÜW„p®!€ïní ÿ]¼èïë{BRR’——·¢¢‚D"íÛ·§¿;è „Ðÿ¤¤¤vïöîï^¸ Üp%áW‚~˜^ž‘JKêïð+€p%áW‚p%áW‚ûÂÁOÄd"+{ÎDŽ•Mß+•ŠìGq}žî˾º/ü5ò¾<`€ŸÂr ‘­/'~y\™Læì9ÛîÝ{qöÌŸs<œxyyB¯_¿srY]V^Ãb±¾ºfÿó·Ž *ÌàççCÝy´eë© ëæ|ºÔã(?qÉ4ý+ZTQ‘?ã·ÅÚnAG³û§Ç}7Æ'd¶¶R>QÃøñÖãÇ[kžüî}ùý»¾ÚÚ*¡‚‚û‹.Þ}™|E]]±·²óç¹fgõ þŠž_µµ9¹oED>óÛ«/'~y\<¾{Ï…›aO½wzÍŸçŠÇo„¡¡VЕ=ßXsèͧJxüFÍœ1ÞÅÙî³¥„„¾¥QAAþï^¹®®ú(‹Úº¦‹w>ó;ÿ½èëkåGD=<õÙœ¤Ãиõ*œNg<ˆš9c<ÇGöö¦d"‘—’›û6)9§©©ÕrØ{{S‘‘ÿ*#ŸNïX¶tjBBVVv¡ªŠ¼““ ‘HDÉÊH†Ü|2ÛcëŒéc­¬Œä䤽wx©©)àµa–””‘Y€27Ó·²2êÞ½ä䜒ÒJ ",äêj fvvjk©¨«+&³ÓÎÖDUU¾  $#³€Å¦MýòCYµœ¬”““mTT⇲j ²!{~¡Ç3ÓÙÙ|-’B¡Y ÔÕ?I¦Ñèÿcï¾£šJº€ßÐ;„"M¤Ké¢öv{{]ëÚu-Ø»Š]Wì®XVem(‚ ‚HWz/¡&R¾?ž›/†P š¸÷wöìI&óæM&‘›™73o@GCCÝ„„ô7aåÇŒîG¼Ó/Þ}þ’+''3mê0hh`ø%#Ï©‡Õ?OßZt›Üø½…Xt_QQ=ftÿ§Ï"{ôœQ[KkœÅb½{÷éÙ³HCâúzppD·îªªj<Æ(/¯´´šðìYdãÖc±XS§mÚésV\\ ÄÄÄV®:\YYC"A]]ýú 'ޏ¾jõa%%y*•ÞËÅ‹(¤™–ÉÍ-^¼tï©€;»vŸ373xam;ùÈÑÀ—!ÑŽ–7ùyx®!Î^WW¿y‹ÿƒ—‰§k×›4eÈá®Î½­½çl;nus··G¡ÿQ á4Zˆ‰‰q†Ðù ÛµçüôiÇíeoo¾eÓÜ3ç‚22òzôèæêb[K¥wíÚeâ„!öè¬ÛéÙó¯ñÌÕÕö}tàl¯Ñú]´ þcúˆQË##ÀÏÿæ½û¯¶moggîà`ñÇ–yÝ}y*àÏyííÍì[.F"EE%)éŸsüN¬³·75²ï¤‰Cuu;yx pp0?|ä›î5k”׬QööæÇŽ®)-­˜;߇§äÚZÚì¹Û;/^4ÁÜÜàð¡Uññi7o=åγ|åA/ïm“¦lðó¿µcû¸ØkÚÚêtzÝL¯­––Fsf51Ñ[0ßÓÔ´ËŒY[ë븕‘‘ž9cäŒéÓS2+*ª ?¿Äcì€E ÇKHHŒÓßÈH7$$zó¦9ýû;zŽÏ_¼k¦eÄÅÅ[6"ÞÆ:¸ÒÞÞ|ÄpךZZQQù²¥“-œº½|MûaÃ\LM»p*ãêb;aüà®]»ôèÑmò$·û^§§ç4óq#„ÐЍ¤Ûؘ’˜,Vqq¹¦¦äç—,\¼^½zÏf³ûô±Û¿÷·7a 1éËæ-þPYY£ÙIµ¨¨ÜÐP—(ÇÁÞ‚x --Eü,€ääLssƒsg·@^^ñ…‹÷·üqêì¹ ž=­ž¿ˆ--5"§¶¶:¼xùné’I<541Ñ›4qèµëÁÛ·-,-­ÐÑÖ †â—-tõÚïÙÛTU•‹ŠÊ++k¸âŒ‹‰‰è¼M®®®UT”çdøôé3¥¢Z“VG¼#00СPª¸ Ù°ÎÛÕÕ–§>Ÿ>}).¡ ÔTã¤hk«‡…Ç%'gZ[›òd^¿ÎëÒ击÷\¼â³ïÀ¥“~¸_ÕÑÑÐÒR‡Ççi4:´Ø2v¶fbbbœ£þmy)I&‹Å`0‰«ÜFêK¥Ñ-Þ###ý1!xš !„þËD5„+*Ê{{>ñ~нó=@GGã~Ð:½NVÁn\Û£  õ9¯X>•8ðÄñµÜåp_2ç˜6cóÃûG‰ ¤«Ûió¦¹÷©¡€‚¼Ô×9¯«kà$6¶qƒ÷µÁûö_,)­8°o9¤¦fõvñ<ÈétÀfee…¸øÔââò¦Þ#‰r²2<ó¶ˆñ|33}Ÿ‹‰΃æ)(È@}ÃÿûÜuuõœtff“&½~#ØÝ½7çÇßFk±ex"tã€ÍƒÁ`ôì=«¾¾á~ÐcãÎ>»Î†¼Šiþ„úOÕt8zdµ­M× }_qýeÏÏ/áÎ3zT_mõ {!L&ØlöºõÇ“’2š/™Édþ±íg}^—›[ømÙ䢢²¹s<$%%äädFŽp}õ:æì¹{‘‘ —þ|èädå6´÷¥ËÏ_¸W[C‹ÿ˜6rDŸÕkŽDÇ$ÖÖÒŠ‹Ë‡éuîü½®¦ú¾þ7_¼x÷ôéÛ>g¦Nq_ºd‰D26îܽ›±¯ÿÍ7o>Ü zù2$ÚïøºaÃ\`ŒÇªììÂ’м¼Œ9QIS½ ïþéCôž ôµ“’3ï…ddä=5}úðgÏ£<|í6´7•Jü8|Ìè~gÏ…¾‰=|4ÐkÖ¨ÛJHHlÜäûâetUUMAA©»›óˆá®¥¥û\z÷.ñÖ­§ååU+WL{ö,jõïGRS³ 9%óÓ§/C‡öân.‰4rDŸÏŸs}ýoFF&÷½ÞñÛé€Íòò²W¯=9}æ¯êjêûØäqˆùíššªqq©ö³gáòûÚ£¡¡±4Z]VV¡³³õL¯?òòŠKJ(JJòžãòm™úú†ñ×åäQ(U’’õõ Û¶Ÿ¦”W¥¥çXw7ùëî‹[·ŸÑiuÑ1IS§¸oÜäû2$¦²²¦¾¾aܸe¥‡%%e„‡Ç Ô3æ}Òƒ‡¯MŒõÎ_¸Çi7·Þ?ì+÷]Î>„ùóv%B¿RsS|!2àV¦ýÙÙ…rr2ZZj|×±Ùl­®•ûµUTT«¨(²Ùì’JM U__»ñ¤¹úú‰ÔÌj.ƒÁÓ“f³Ùuuõœ9óÑhtYÙ–«J¥Òee¥ÛºÎŠÍfS©tyy>ãç„W¯blmÍ”•FYqpÿ 33ƒ6•ßú–i%:½®™¶=@tôÏ®Bè—"ª×ÂyHJJíM!‘H­ßo•Ød”D"uê¤Ú©“*ß<œ_ZÔø¢/‰Dj>&µ&~@ûv%‘HÍÄï’JÿA öî^ÚÍÒ¸›¥q[ã7´¥eZéWˆß!Ô~‘ŽE]]eëæ¹‰‰µµtŸ‹~vuB5 C8ú‰DÚ¾máÏ®B¡–‰ðŒt„Bè¿ C8B!$’0„#„B" C8B!$’0„#„B" C8B!$’0„#„B"©¥uá=üj „B¨mZ á"²G:B #„ ÒB!‘„!!„IÂB!‘„!!„IÂB!‘ô‹„ðòòʺºzâ1ƒÁhw9eeD9õõ ‚©55ÔêêZâñ÷|…Bè‡éØû…GF&ÄŧΟ7®ƒÊ§ÑèÛ¶ŸSÓ.µµ4ƒÙ¿ŸÃÝ —>;·µ¨¸¸ÔÀ«,ÊË«˜LfÈ«˜Û7÷7•yùŠƒ7nþzÞØ¸sëOñ÷ßo¶ï<í6´÷΋¸Ósr W®>œššÿá:ßïÞ}yç¯çÉ)™C÷RSS®ªª­ªªï9ØÕÕ¶©s9{÷Ðá+7xÏœ1²õ5ü~EEeþ'omÞ4WR’ÿWëÕ«˜Í[OZZœÚôþ}òå?¾ û`gknbҙ͆ªªÏqƒ,8ù¯>ÒÕé4`€cU˜ÍfŸ;/22ÁÖ¶«˜˜Xyyå„ñƒ·ï8xŧƒÎˆB‚Ò±!üC\ÊßÞtP/+«èÓoînŸ¥cÇö'Rª«k]gØ£­E1™ÌßVøç‰Ÿ´´dgîØy¦™üG¬¼ú˜Íf·é,#F¸¾‹þTSCãI×ÓÓÚ¶u¾ûðeMèá1@]]¥ï€y¯CÎÊÉÉ@iiEo¯-›ç6¡çÍõþ'¢¾þG÷&ss‹oßy¾ü·)ªªÊ|3ôëç0iâ·o?€½½¹©ŒœóÎ틆 s€’ŠKŸÙkŸ5wÎX"ÿÓ§‘†ÂÙlöä)tu;ØD"‘€ÅbÍ·óSâçŽ8B VǤ/˜ïy?èH¾tÙþ>®vœø ŠŠòö-oGQYY……eDü€.]´<Æh&?‰D’‘‘jljdd¤Û”ÎAtjÅÄHÄSuu•Ñ£úíÙ{±¹sI·§†ßÉÁÁâÓÇ[MÅo÷›#Â'hhGì»õSœ —.n_¿ÎKPÕ+..ß¼Åÿü…{ÄÓÓgþú”øeïžeœ ˆ‰‰9¼šø&°Ùì…‹v_¸x¿¡ÇÕBÂH`½pƒ™@¡TáúöíGCCee…èè$*•îæÖÂÃãÊÊ*‡í•’’•“SäìlM&+qŽ}óæ‹Åvq±yô(LNNÆÍ­7•Jg2™ŠŠò|O—]xýæ?á¡çyÒ pŒýÂyš•U• JV0ÀQ\\<1ñKvv¡••1ÄÆ¦tïnb` ;kæåŸgÅÅÅ6mœÃ½ ¨ææ=¬‚î…pÆE p0ÀñMØëî¦îîÎ11I$iêw111àh\‡””¬ä”Ìɓ܈§ffînÎ99…ššjõõ l6›ˆÄx¸t£ib††º®®¶^y$&Fš5s$\¼ôàúà[7ö)*Êߺý èôºÆsÖêë¿i.ŦªÍ—¸¸˜¤¤÷Ìóúú†Æ5$‘HK—L:î{D" Ò‹û¥Æ­!--Å=ò__ß --ùoæo†mxžòˆMžå½íîƒÆÆ)”ê¼¼b:½®qݸwf²X/C¢'NÂ7ß3ŽÕ766å„ïõÜÜâÓ§6‰ššjɉ·Ožº=aÒº¹³Çº¹õnüƒrÖÌ‘A÷B–.™ÄóRXx\ã^[K;sönÈ«˜Y3FŽÓ¯™wB?† g¤³ÿÅ“òíÓÿ?&””P45U7oš³iãœiS‡q2‡†ÆG4Yo1±‹ç·ð½Á}qšÍfge­­M»víC¼”þéÓgž*qˆ_ |Ìb±8Ok©4GGK{{óÎ;Åǧ‰!!1nC{uê¤Úø­-Z0ÞÏÿfCƒ˜ñtÂ÷†×¬QŠŠòl6;/¯„Åb_ üz‰º¤”B<`±XoÂ>LâÎ]Z3Õæn4qqñ)“ÝBßÄO‹ŠÊ(”ªÁƒœˆwÇæŒááq/C¢‰®3§Å·Æ8ññiœ(ò*†Xºömf6÷ÿù~èW;÷¶&:ôyyÅ,ëÚõ`&“Éó5à>\JJR^NæÃ‡ þÿmfà©áÓ§/«WM_¶tò¾½¿ƒ%%…uk½þ¼´#ýsÎø‰kƒ‚B¸?bر}aIIg‚:áÉ“ð~}¸S*+kvï9?ËûK £»wzx hþ· BýâÛ¶mkòÅÓ§aÞ¨VD§×mÙz2*êSII…¶–ºŽŽFnnÑNŸ³±v¥à IDAT±)22R½{[oÛSQQmcmzþÂý_WTT[ZéëkoÚì÷ûÚcÇŽ_;|$099s@ii©cǯ½{—ȽfŒ‡ººÊxÏ›·úgfæ+ÈË~þœ{óÖ3OÏA$©wokqq±¡Cz8øgm--%%3--{Ø0—+®]ÎÍ-2Ð׉M¾xéAVvAg]MÙÐ7òóK¨µ4*•~áâ};[óþýÄÅŇéµoÿ%­.:&ñé³Hßõòò²;}Î>{E¡TÙÙ™£ÇÆÆºÇŽ_ÛöÇbŒšÉdÞ¼õTEYñIp¸«‹Íƒ‡¯íì̬¬LÞ„}05éÿ1­¤˜rìø5/¯ÑC†ô"*&&™Á` Ø£qµƒ‚BN¾™YPRBQQVÐ×׿n‡¯]ÎÌÌÏÉ)òó¿uøÐ*cc½«×ž\½ö8'§Ðبs—.Z %%YTTÖ¿Ÿc×®]ˆ›jž=­Ìºê>r…ÅbÝ zÉb±7oš“›[ì³ë\\\j]]C·nFÛ¶Ÿþø1½¢¢ÚÖ¶«Ï®sQQŸjj¨ŽŽ–‡>{UUUÛÇÕ¶S'Õó(¾ühiat?„å>áw#)9ƒLVb2™]‰yŸ\V^A"Aw+hh`<}éêbû2$šÑÀ8áw#%5«³®fii…¯ßääLee&“uäXà§O_d,êèõ={Ï:á{ãà¡Ëwþz¡¡®Â¹:’’NNVã<F½Kصû‹Å²07 b°„„Äôiï>ùçŸÅ¢¢ò¿î¾PW'söÌ))¡ìÝwñòŸO?xÍêÆÆùŽÉ·ÊÙ‡0~;E!~HÍíOâè‘]ƒ }p<¸'‰D¢Réûö_¬­¥<ÐäD¶ÆÊË+ãâÒ´´ÔºvíÒx VYY…´´TóÃû55T6›­  ÷ñczQQ™µµ)wgŽ(DRRBII¡™Bh4:÷¢#‹•—W¬­­.!!ÑÐÀàÞ­ŒÅb”jk«7Ó™kMµ¹Q©ôêêZžjóðó¿¹háøVö Ùl61ŽgÍU[–*))ÈÉÉð4B3RR2óóK]]m[“¿¨¨lɲ}^Ú!++Ãb±RR²F]q‰ï6&“yç¯ÕÕµsfåN§Réqq©’’ÖÖ¦œ÷Ëf³×®;6e²;÷êµöë¹¢£PBý«cwgkä”L¯Y#‰ÎœœŒƒ½ÅëÐØ6• ªªÜÌî]œÉhÍàDJkkSÓö³hXLLŒ3ë'‰‰‰5^½ÝŽ3r“““!Vf7¶cçëzY©©)·~˜D"µXÉÖÐÒR'´2~€™™Ù¿Ó[”Ÿ_"-%EÌ335ÕÓÒRg±øÿ0ç{•]NN¦wokžD‰t é5!ôÓýü^xyyåÑc׈%XyyÅ**Š«VNk~Òj“^'|ú¬¬¬°pç/y÷Þ½÷±ÉššjJUyy•ç¸ÎÎ6?»R`/!$h??„#ôŸ€!!$h¿`Ÿ !„ú/ÀŽB‰$ á!„HÂŽB‰$ á!„HÂŽB‰$ á!„Hjiìž ~H5B!Ô6-…pÜÚ!À_Ã!AÃt„BH$aG!„D†p„BH$aG!„D†p„BH$aG!„D†p„BH$aG!„D†p„BH$aG!„D†p„BH$aG!„D†p„BH$áÍFB!‘Db³Ù?»¨Õ˜L>¶n—&3ôì ÷@\¬] AA +û#«‰BèÀt‘òô)@DD“V¯þú4%ÊÊÀǧãk†BèGÃ.:h4ؼöï‡ë×›Ìóô);÷õÿÇŽÁ—/öƒ*‰BèGÁ.:üü`Á°±SSHOçŸçéS°´„;aíZ`2!8,-áÐ!ر(”[]„B C¸ˆÈχ§OaölxÿžOžôtPU2LLÀÑ‚‚ÈdÐÑ9s`Ó¦Za„B C¸ˆðñ•+A\ÀÞîÞå“çý{ððøúxÉسþúÔÓàÉ“PS„B?†pQ ¸»}jbii@£ñf»{ìí¿>ÖÑ—ÿç‡]»`ófNG¡_†p¡ÇdÂŽ°sç7‰“'óŽ¥S(P^&&ÿO‘•…°0ÈÏÿú”LX¼˜Ì®1B¡C¸Ð»s¿‰Íл7ïÒ²ÈH2ä›”gÏ`ÃðóûŠ»;ÉpçN‡Õ!„Ѓ!\¸Ñh°?¬YÛnoÏ»´ìþýoB81`>v,DG3}}×.Ø¿ÿÿ]s„B"«¥ VÑÏåãjjpû6èé¢"‚¬,É +ûuiÑ;§Ñ * Nœøú˜B¤$°¶†§OAUÖ¯‡•+!"bb - œœ >þëöm!„Dn°*܈îr|<Àë×ÕÕjjsæÀĉÿn¤ eeúú ) ùù ­ Ÿ?ƒdfÂÖ­à舑!„~Ø nDÄ%þom àïðoh§R¿fëÚ.\øÎM›@SºvkkÐÔqqX¼,-1~#„ЯC¸è RLþú˜'ËÊ~s#“>}àÿ‹Ð ÿÿº#„ú%àt6Ñ‘ž­Íœ“óÍS33 t…BýLÂEGUèéµ*§‰ df~“Ò¥ DGw@Bý4ÂEG\hk·*§œo ™ ee|6tC!$²0„‹ 44Z•“L†à`ÞD77HMx¥Bý,ÂEGTÔÿ§³5{j‡ ¤¤¶F!„~" á"‚ØØœoln ÏMÌÌ .NUB!ôSaEE`jÚ†ünn¼W¾»vå3ºŽBHdaFFmË_RòÍSYYPSÛ"„Ð/C¸ˆˆoâp°±‚ÞDGGÈÎ\BýLÂEG+…”” ªŠ7±OœÑ†B¿ á""4Û_[›Ïä5 \BýLÂE‡¡a2ó]A®« QQ‚ªB¡Ÿ C¸ˆnÛŠ2>;ª3Úˆ»œ!„qÂEG+÷u!èè|½w8!C #CP5B!ôaùù ¦ÖžoŠne‰‰ß_#„B?Þ/\D8:¶ù'' Px‡ß­­áþ}AUêÇcoÚD jBívî,ØØþìJ †pQ‘ѶQt™ T*o¢¦¦ˆÏhc—ß¿ÈÒÑúÙÕ@‰uGwÖï¿‹8ðËDqHÕÕ`eÕæ£ =7Q\LMqFB迉rã$ë÷ß!îÃÏ®ˆ`` í9ª©­` >þ{ªƒB"ŠMVù•¢8†pQ@¡€µu{äû{÷nço„}¿RÇ. ¯ðn kkþ7514„˜˜ï¬B‰®_&Šcee £Óž¿|ᓨ£ii_o@ŽBÿI¿FÇ.ôÚ}{PMMHKãÿ’“µ»F!ô ø¢8†p¡G£›[{þ½m;;œÑ†B¢Å1„ ½ïÙÕÔ”oÛÒg´!„ˆxÇ.ôª«¡OŸvkdÄ?ÝО>mwBèW"ºQC¸ÐËÉù®Ãùv≛ 4ÞA!„þ“D4Šcz™™í\}ú@u5ÿ—ÜÜ /¯Ý•B¡_Œ(Fq áBï°ÖkªocÃgûU„ú¹(Ž·9zii ©ÙÎcML 4”ÿKffpó&¸»·»^!$rÔ[÷GoÎÜvî©õcanÄåjbyX;ÈÉ5¹¬¼K‘ø‚"„ ”F?ieÎÖFúŸ Ò……NNí?œLnòÖ¢d2ÎhC!‘†½páVRdòÔ©S¯]»6eÊNò±cÇ444¸3^½z•óØÙÙ:wî,!+Û\ánnš 66®3B¡C¸p+(›37îÞ½›;™L&óÍYRRòðáCàó É@"‘¸3/ÕÐØcd¤ðm_¾|yÏž=¹SÆŒ#//Ï’™™ òòòsÙÿÿÊ+'ÍœÔÔ¡ÏC««ª $))I)§0™LïEÞú†úMkãòA7‚ÚÔ˜ó)îÓÌù3›ÊÐâ›åKP4¶¤ÿÉü’0„ ·¨¨ï¯JJPUÕ䫎Ž-ð.@<¿Ørr áW/\êý½½yŸ#>w¯ßå9hÆ™gîߺãÉ ¹–]¿týö•Û{Oìmë©?§}~|ïq@`ñôþíûEMÞ=VWOwí¶µÝ'¶õ,‹W-¾Ì`0xÒgΛù2øe}}}3Rk©Á‚Wn\I¤ÄÅÄ rôàõ + ¾‡ì:ºëvàíÖ7¦ $|Høçïš <-¾ÙÆøAcK ª%U¸¨Lˆ÷ m~Vy‹´µ!.®ÉWûô””ï*_&|ÀÚH$’´Œt+3'~Lܵi—ï%_9®a•I3'Ù÷´oǩ߆¾UPø/d”ç(íÎÚÍäo}=[y`‹JJJЉýÿÏ‹ƒ¾¡þ9¿sMåoSc Ь³ï6Ÿ§ùŠÕÕÕ] ¸´eÕâ©`?hÀ–lº%Ïœ8³û~Jy[_”–”Ο2?ôEèÿAóÃ`/\ˆ©é÷Òü¤q8|&¶¹&„*+*#^G°Ùl×®ŠJŠ%Å%U•U ¤¬¤¦®––œ&)%)'/WSU³á· Ê*Ê?|TVQîbÐ Fø«ð²Ò²½{tîÒ¹¦º&>6žÑÀpéïò6ô-“Étîç̹üÆb±>Å¢”Qœ\þ¿dŸÁ`¼yù¦²¢Ò¸«±´´´©9ïwêÈ©½{ðŒ’H¤1ÇpÿŽOKJ3µ0µ¶³€¨ð(J¥ÿÐþé)éy9yNÎN*dèjÑu˪-žÓ<û:å,Zµˆ(ÍfG¿ÎÎȶènaÙÝ’§œf‘W×ÒÖÊÏͧÓézúzŸS?ÇÅÄéé;örä9*=5=ëK–ƒº†:߯ç©6_µ5µdU2§À¸˜8-­^®½Ä¿Ý¹ˆJ¥æeçIHJ°Ùl##J9¥¼¬œÅdiëj7ó¡Ðh´ˆ×U•U=]zjëj@A^AZrYlhlaÜÕØÐØÉdF¿€ž.=I$FûýF¥ tH4]3ÐXMMÍåÓ—£#¢'{Mæô>[óA·éûÖ|K–—D…EIHH¸ôwi<¶œš”*)%Y_WobfÂd2³¾d‘ÄHÚºÚŸâ>ñý^‰VKÎ[6/ö]즛´t´¬X ©Å»‹¥º†úá3‡/Ÿ¾|Þÿüd¯ÉCG åY•ó À^¸£R›¼[hëÉÊ6· ›®n“{¿ˆ”äOÉ §-´ïioëhëåéUVZVUYuûÊí^]{egd³Ùì¥^KŽ”•ÔÖÖjjkÒéôòÒòšê¨­­:rª¢’¢ûhwŸ>¡õõõÏ?_·tÝåÓ— Œ r²ræO™Oœ¨¼¬|ÎÄ9yæVæWÎ^áôV/Xmmo=züèø÷ñÏŸfúõ‹× #ƒöét:8ôt2|Ș~clºØ,õZúæå“®&P__¿dÖ’:zݨñ£RS¶®ÙÊÓÿ¨©®9²ëÈè¾£+)•ž’î9Ø3ós¦ïßðWá#Æy²yåfîCîÞ©(¯°°²Ø¹~ç«w¿…ÆÕæA¥RÏúžURQZ¶vÝsôÕÓW£ÇVPPXzú‹àÍ|(YY˼–™˜™ rôçÙ?oÞ€ÚšÚ€cÇö»wëžCOßý¾Ç®_ºnbfòìѳ]›v“Á|ýìõò9_WO4Ó<*(w\=µƒÍ¹›ç¸cC‹t›¾oÍ·äó'Ïl?Ðop?k{ëË7&ÄñŽ-¥%§ uzùôe‹Å`0Ö/[æø™úºú¦¾W¢Õ’`×ÃÎÿ²ÿÄ÷nÙ»iŦœ,Þ[B(((,^µøTà©¢ü"ïñÞA7ƒ˜Äèæ¯C¸KO‡ï_dEìÂÖYY05…üüï=Ë϶vñZÏ©ž4;iëj»p½röб©ñºíëÖl]s)àÒçÔϳÌÚ绯»mw{CC]=Ý~ƒûTßý¾ºzºv=ìdeeg/ž}d×U5ÕI3'¥'§7BWOwаAÏÊ›Wn¶w²:bh'ÍNs–Ì!ºJl6ûÍË7y9y0aú+«Æ5¤QiÍO£}óòÍ?ÿñZè%&&¶hÕ¢ã{3ŒñÓÆ«k¨+“•mlºZt•’’JNH11±S§‚^yNõLŒOôäqñÔE8@V%»p•’’ò˜äñ9õóßwÿæ>‹¡±¡Ï*•ªLVm]í½'ööÔWVNVRJRFFfñêÅÇjkk9‡ tèØËQ§³ÎÎÃ;×-]—Ÿ›ßbµ‰—òrò.žºxáä…‹§.™=‰x¢¤¬ý6úÞÍ{s–Ì‘””´q°±q´Ù³ewJÊJ W,trqjhh]=]ïEÞ –/hæCY·dݸ)ãºtQTR\¹qåöuÛósóMÌLœ”4Õ{ªªšj¿!ýŽï=>ÅkŠº†zÿ!ý‰cÆOÏ9u3ÀQ\T¼kÓ®-«¶ 68àj€K?žŽ]‹t›¾oÍ´dMMÍ2¯eëw¬WPTÐÖÕž³tÎâ‹y~±ðá½È›N£KJJÊÉÉ t¸÷Ä^²*¹©ï•Pµ$FoåÌsónæGΙ¿|¾ÿ!ÿßÿžžÊ{'iié™ógž½q–É`Î4÷ê…«mº$/Ì0„ ±ª*ÐÓLQÍl¤êàÀÿžâ¢£®®.2,2+#ëÖ•[·®Üb0œÅßÿø½¤¨dïÖ½ÓfOkêðСT*•86éc’ž¾H$e²r'ÍN ++KôQØlvðƒàîv݉I$±Ž‹D"-_¿|¤ëHk=ëõK×w³éÖø,ÖöÖDŒ'ÐéôãûŽ{÷¶Ò±ÚðÛ*•ú"TAQ¨ÆÝëwû9×ÖÔ…s†åedeˆšTVT’H$—þ.[÷n}ñþÅ™ëgv¬ßÁb±ž=~ÆÝq165~ú÷Sžš¨UFyŽº|ú2¼~1xø`˜³dY•||ßq¢ŸMŒO¤¤¿®USRVÒÒÑ ãi=¾Õ&NäµÐË{‘÷âU‹º $?_¿006h¾†0wÙÜ3ÇÏÀã{GŽÉiðÆJ}}ý«g¯8ïZRR²“f§7/ßùMÌLˆÀ #+cÜÕ˜´—‘•¡ýû/‚;l4Ó6›ííéÍb±Ÿ>lëhÛ¸Úкº•ß7¾-Ç`0TÕT9-™ô1‰çx-ôúëú_”rJnvnÃ.œ÷Ûø{%„-Ùøí@|l<ñ󎇾¡þîc»íì={ò í$$$<§zî÷ßÿç™?Žð=©ÈÁkáB,.N0W©œ€BirZœ•$&‚‹‹Nô“HJJÊÊÉöÒß¡§ÏKL&ÓÖÑöÞ­{ï"Þ99óî6þ:ܹ¯³²Šr7ën¦Oày•û5D"ÉÈÈ4žÃf³]¸¤–¥FGD_>sy˪-¾}yòLš5iÑôEU•UJÊJ ##óÛºßÂ^…=¼ópÝöurrrÊ*Êšœjp×§qM®_º>fâ-m-âé˜ c6¯Ø\S]#--Íݽ¨¯¯ç`nÞ‹¼gŒ±`ùYYYâoñÊy+Õ4Ô6úl_½`5Ðétžêx.¸6Sm¾ZYÑãFnYµ%ö]lQA‘Nçÿïjи)ÄÅÅ%%%›*“;ãcy´Ø$éþ«û÷nÝ›=aöàaƒ'{M––æŸÕšº•ß·æ-Éf³‰ØI´@ãÆÔé¬3Ðm`à¹@9y¹óf4sF!lÉ…ÓrZ’#,$¬ñ” ‹õ(èÑË7\¸F$GÈñ[‹[WpòðÉÒ’Ò½¾{mì‘¥±.ܲƒ)™ Tj“¯Z[Cl¬Îò󈉉Mš9‰Ó™£ÑhOî?ƒqhç¡ÙKfŸ¾vzÑôE…_·“STR¤Qiš˜ “fMzú÷SN`ºl6›“³=§y†¿ 'WWUWUV±˜,&“¹í÷mÒÒÒ.ý]N\8Q˜ÿÿ}ë8†Ž:züè5 ×p—–›• ÿv_FŒñ1öcuU5ñÒßwÿ&þ˜ò­ ›Í¾õç-N94MßH_IYiÂô oC߉,+òMäøiãy »vZ:Z˼—7‚x#çç/Ÿ/..^XPÈf±Ù,ö­+_Ë/+ùz!&7;·®®Î¥¿ w­©6·ãF$Æ'râDXHg•0÷!’’’^ ½~_ô»];α|›B\\|Ü”qœw]\T\A©è7¸oØÐøXî<Í4w9âââã&»|÷²–ŽÖÂi ŽP¿ýÇÕâݦï[3-imo­ÓYçSü'NKp ÑI£ñ!s—Í=ë{VBRBRR²™Æ¶–2|Ș cÖ-]ǘ“•C¼Gƒq;ðöL™åeågoœ]°|Aãøù%sí’µû·íŸ6gšÿeÿ_&~€ø¶mÛ~vPÖ­ƒÅ‹ë_];}ùL&˜˜ðUN¶o‡9s €ŸãÅsºSwv£™·Îýœ=JMJ-/+ür¤çȈ×+篌‰ŒY´r‘Œ¬Là¹À·ˆKˆ[Û[kjk^9{EZFšD"u·ínfiVYQt#ˆÁ`¼ ~iïd_G¯;äsèSܧúºzS ÓÛ$Æ'Rk©½úêûøÞãìŒì JųGÏÞE¼ËÍʵu´ýóÌŸ’R’UUî<;i,ß7†ŽZ\Tì{ÀWQI±Ž^ú"´º²ZßH¿ÿÐþRRR*d+[«#»@dX¤2Y¹«y×ýÛö‡…„UVTv³évõüÕàÁUUf–fŸ3 r 2>g@qQ±ï~ßek—iëj[v·ÌËÎ{öèJ;ï~ô„ÑCGÍÏÍ?´óP\L\£À )%Y\X<~êx’’ÊÊÈŠ b±Xï£Þw5Ž êÕ§—ž¾Þó'Ï»ZtMOIÿœúùRÀ¥ÝÇvëéëݹzçÎÕ;y9yÆV6V«}êè©{·îådåШ4==ÎlgPUS5139yø$‹Åúûîß,kõæÕbbbw|ýìu%¥²»]w¢×ebnòð¯‡k¶®!"_nvnSÊ@·]û+;3;/'ï¼ßyŸÃ>†Æ†oß¼=ë{6=9]IY‰ÍfûòOú˜$+'«¨¤x|ïñÄøD11±Îúí<ô1ö£”Œ”K?¾Åy³»t&Þ1°çwnîÒ¹ªKû] IDAT­,PØZ’Á`¤%§•—•[ÛYs¿Ís~ç´uµÝG»7õ=/,(x{Cp°Š ƒˆX³¦É ‚•Us1^h4ÂÑ/ ° pÕ¼UW^½pòÂÔÙS_"E­7kÜ,Ÿ#>é)éºzº]-ºþìêˆQ á¢0vúŸåØò–­bh”&70èݰ[BßO]C]ßHÿRÀ%[G[ŒßßÉÞÉþÅ“µ5µ¿U8#]XÅÇ rëò/_š{ÕÐ|ygP#ôSHHHì9¾§å|¨–¯_Þr&$ʰ.ĬøìÒšš–Ö\HKƒ_kÓ"„úåaV¡¡ Øäü”¶!ö n>B;9AQ“·ºB!$„0„ 1CÁÝî×Ô´…mgññ;B¡Ž‡!\XEGïmF¹µx»KK ØéBu< ᪬LÓÙÈä:Ù††"±‚!„†p¡Ôü°vhqfœŽ”•5w7„BBC¸P¢ÑÀÍMÀeæðÞI——›äåµ!„ÐÀ.”~÷OÈÌl! ¤óÞg!„ÐÂ.”ª«¡OA('×ò༙ÎhC!‚!\( |»S2¢¢ZÈÓ¥ ÎhC!‚!\(Q(`Í{OûïÒšõid2”• ~&B¡Ž!\(uDoXM òó[ÈãæÙÙ‚?5B¡€!\(•• þîÝ­¹ï™ ¤¤ø¼!„:†páÓq‹³KJZÈ`oqquv„B…!\øP(‚_66PPÐB]]ü©Bu á§žrû()AUU ydeAM g´!„HÀ.| ÀÆFðÅjk·jÜÑg´!„HÀ.|rr@IIðÅjh´*[Ÿ>-¯ G!$0„ ŸÌL01|±²²­ºÎmb±±‚?;B!A“øÙ@|ùrr‚/¶•·.54î^8Iu´×Ï®B  áÂ'- 45;ªp­…ÚÄÅÁÔòó¿0]H»vÁ®]?»!$p ]È0™ââR¸“S«f›;8þVi!„ C¸)*'§Ž*œL*µålVV˜ØQu@!$ Â… •ÚÚ‹Öí``Ъ;‚[[ãŒ6„~Â…Lzz‡, 'èéµ*›¦&DE}ÒG!$¬0„ ™ªªYNPT„ÐЖ³3ÚŠŠ:ª!„C¸‰‹míŽ*Üаµ9„øøŽªB!AÀ.d(”Ön£Ö>_¾´*›¥%$$t`5B}7 áB&*ª§³ijBZZ«rBLLGU!„ `&Ä ²æ·^ùÄróÖÌSÓÑ´4œÑ†B C¸0)*SÓŽ=Eëç©99áŒ6„fÂ…Œ‘‘°”og‡3ÚBH˜a&ññ``б§ “[˜--[µ !„ÐO‚!\È´r÷•v³²jmNKKˆŽîȪ „ú.Â…Ih((*vøYrrZ•L†²2 Ñ:¸6!„Ú C¸iýî+ícm ™™­ÍìæyyX„BßC¸0 îÀe­¹ß(ÁƦU·EA!ô3ØlöÏ®ú—£c›/?;:Bd$ïýÅy³qòÐhЧDG7—§5å|gžÆoóü˜<¡_†p¡‘ŸÞÞܶ£!:¢c*„~’?»¡„é¤q/ !„j†p¡‘‘Ñ»£#„úå`ÕÕmX´Bè?C¸ÐHHø‹ÂBý*0„ ¥=‹Âq.jŠcïŸ]„PÇÂ.4:lýOCCCYY±ô€Á`tÐY °Ùì’’‹E<Æ !Ô‰Ÿ]ô¯²2ÐÑl‘aaá~~'TT”  èòd€¿ÿ E!±_±bÕõë7ÃÂ^·˜ùðá£ÏŸ¿¨ªª>|˜˜˜X]]ªªª—×L"CddT\\üüùsÛZè蘫W¯½knnfnnÎf³)ÊÇ ŠŠŠ—/_xõêõæÍ[---üÛüÛ.''gË–m&&Æ;ë–””jkkÑétMMÍQ£Fþ€³#„D ƒòr¶ƒC»Ž¬oê¿ãÇôéãR[[ÁI¹xñ,P(ÅÍÕšÿΟ?ý%°Ùõ,V¦f§´´ÄVæß±ã''GÎÓ#GvïnU^^D<=uÊoÔ¨í«I]] Ü»w‡“B¡÷íëÊbÕ±Ùõ'N6mÊ÷¿ßÿ {eddøùs2'%>>FAAþîÝ[í,³ß(„ÈÀtá@£››Ëûøñã¦M[.]:/''ÇIœ9sFÏž=¾³ä‚‚‚â¾³ ‘H222­Ï/))I"‘8OgÏöúø1áÖ­;ÄÓ æÝ¿·}5‘’’1±ÿÿ[PQQ™1c…BéöÛ<6›ýäIðÔ©3ª«« ¶¶væLoŸíF\7tïÞ½û’%‹ˆÇ'Nømß¾³¼¼¼#*ƒQ8.22Úy Æw[õ#GŽ÷îÝËðÛùq$iâÄ Ü±ŠƒÁ`¼zõº´´´wï^]ºt)..®¬¬eeeuuõääd)))yyùªªªß~[©¢¢òáÃÆÇVWWÇÆ~hhhèß¿_hè&“Ù¯__ ‰¯ß4‹_VVîââÌ]¨¨wyyy:u’••±··oñ}WUU€¡¡Ðh´èè*•êæ6ÂÃ#ÊÊʆ’’’’““ëìÜ›üï‚ûÊÊÊðð--M##£{÷îÛÚÚX[[ó”ìçwrÉ’EC‡aóÛ¸0666))ÙÂÂÜÎγ³s¬¬º±ÙìzôpÔÐШ©© ×ÓëliiÙ¸‹u÷nÐÕ«× xîÜiYYY¸sç¯ÂÂBOÏq<™==ÇÀ²eKÞ½‹^±bµŽŽöŠ¿iiiµØD¡_öÂ…Cu5ôéÓžû ä›cbÂçóªU+”””xkkkGŽ£¤¤4zô¨·„†¾©¬¬¼råj×®Ý222Ùl¶—ל£GÕÖÖjkkÓéôÒÒ2N÷‘çØúúúÇŸ,]ºüô鳯ÆFYYYS¦L'NTVV6q┼¼|+«ngÏžçô)÷ï?È`0<<ƪ¨(8p¸©÷ÚÐÀ(---((xó&lëÖí—†  ãÙ³çsæÌ'²eddŒ3îâÅË ##C{{':©©©ãMMMÂÃß>jРÜà QQïîß°ÿÁ¸¸xèÒ¥‹ššOV®\ùnòäIOŸ>?|ø(”––-[¶Â××?>þ£“Sw÷‘ýu÷Ù³ç=z8.]ºüÉ“o¶Ëmhh¸|ùÏ &×ÖÖ^¿¸xñBÙ~EGÇèëëãÜzôp9rçñåËf̘¶e˶+Veee5ÕP_áj„~uÂ…C+ïáÝj4ÓñmÑþýõôôzôp”••]¼xá®]{LMM·oÿcëÖMgRSS,˜çë{ÜÖÖÖÞÞÞÄÄXO¯óàÁƒºwïÎ÷X55µ™3§''§Œ7VOOoØ0÷ÇŸ'Z¹r“S#†kjj.Y²ˆSÃWyyy £[·nÞÞ³šªgmmmttLddÔ­[·ëêêFŒN¤+**NŸ>•“mÚ´©d²Šƒƒ½………””TBÂ'8uê´‹‹³‰‰É¼ys"#£¤¥¥gΜÁ9J[[ÛØØÈØØHBBøyù2äáÃG Î[µjÅÞ½û Fß¾}ìííªªªFŒ®®®Þ«—Óõë7ÇŽ£ªªÚ§kpð?ıt:ýäÉ€©Sg(((ܺu}æÌ’’ßì^N£Ñ[ùyuëÖíÌ™SË—/;tèÈâÅKSSS[sBè—„!\8dfB£Ýïaoo—›ËçVß±±± <‰/^¼¤R©W®^¹øñc‚¾¾>‘þÇ[ŠŠŠ¶nÝ>{¶wS'â{,‰D"“U455@VV–è³ÙìÚÙÙ’H$N§sË–MkÖ¬SSÓ5j¬ŽŽvSçRQQvww;v̱cG ÆÖ­Û8/q_&'žš››9055%Ú¤¬¬ŒL&óŒFèéuîÖ­›§ç8WW"åáÿyÞ©¢¢"ñN¯_¿Ñ¯_ßšššÏeÎ9÷yi4ñØÇg÷_Ý=}úä¸q|/dØÛÛååå5º¯ªªJJJjœßÐÐðر#NN=v'.y „þƒÚ~-oÅÑAÚz²fÍš5cÚ´™•••ÊÊÊÜé!!¯‰‹¸ÜTTT¬­»OŸ>'Éd:::ܺu'"â­³3ï>!¯_‡öíÛ§©c*bþß Ìjjªi wîÜõ𘚚È’366 ºßL†Æ~ü°ñ¨5aêÔ)PVVVXXÈ®¢¢¢©Ù‰óN¹ß2÷¹øFhŸááK–üfhh°bÅo<ÆŒµaæ7oÂúôqåN yÕ­ïu‹tïòå+ôONNàž±ˆúOi×t¶ÈAWµWÏ|“‡6aÂø¥K—ÿùçENbVVV§N¼ÁfÍšqü¸ïÚµkˆÀyóæ­‰'0Œ;w-]ºxܸ±ÂÂ^ikk€’’Ò—/˜˜Ô·o¾Ç«ˆÂ¹cö´iS^½z=t訪ªª¬¬d2™°~ý¦k×®X[[[[[‡‡G0 žqføwõ#穪ªjJJ F«¯¯///çy•obc?L›6eøða<¿ˆ <¿-Ž=îîîÆ]Ô¸qc8TUUEtßïÞ 1b¸””Ϲø¾qpvîíìÜûÇk×nPSS]¹r¹®®.çU?¿ãóç/ŠŽ~+//O$Ö××§¦¦q/ g07nܼyóöÈ‘Ãoܸ*-Ý!³åB¢B|Û¶mm;âôi˜7ªCê‚ÚáìChb?“#†zæÌ¹ššWW—èè˜Ý»÷¾{C£ÑrssÃÃ#=z|àÀ¡óç/8°÷ýûØ'ü’’’Éd•~ýúÚÚÚìÞ½€N&“ÍÍͯ\ ¼víFnn®~\\Ü… —¾|ùÒ¹³nFFf@Àé/_245;YXXpÞˆ––ÖØ±£õõ»ìÛwàŸžš››qfË[[w·´´X½úw‹ŒŒzò$xöl/bÊ[]]Ý… wíÚÓ­›åŽÛzôplݵsþ×õB¿ßÍæ8:b/\ˆˆ·pÁ`$''—••ÛÙÙ6ž‹Î“³¨¨HGG§ÅAl6›]TT¤©©ÉÉÙúc ¶¶¶¾¾žL&çää()))))544HHHääähhh´~X˜N§‡†¾155!Ö¶µXgñ~~ÇuuuÙlvII‰—לŋræ{·›Í.((ÐÐÐh?¿“ºº:£Gâ;PÏŸcïŽÛµ!$ 0„‹¸–B8"0 W×~/_>ã¬ãZµjÍÀÚÂE †p„~u¸µ úO8sæÔŽ>ºººuuu………¶¶6œei!$Š0„£ÿŠîÝ»ïÙÓýg×!„×…#„B" C¸ˆûwó„Bÿ5ÂE\{¤#ô?öî3¬‰¬ ð ½w¤ ÒATº¨€‚Š€"X@Q± ö¶ÖµëZpí]ì}í;ˆŠˆH‘Þ›"Ò{ ¡$™ïǬù² (ˆèyà̽çÞ™Lr2wîLðéýò0…#„Bݦp„B¨[ÂŽBuK˜ÂB¡n ï ïþñÿù/V 9ËpúñÃCþÇ/œÛð"¬¯áÄW¯Þ[ØÓgî8xåîí½×®îxpÿ€ºº’ïƒ×MMôÖk=÷ó)*.¯¯oø†UUOø¬+)­l¶•ÓGq±©¨¬i%B³»âñÃC™ŸÍ-¦>~ÜJݶÄÿ1JJ*3ÃÂZ/vøÐ*EE¹šêéBýÚ~¢t%%¹©£êwí¹ømnÝ~¡¡¡" ÀOþw’»ƒÓ(ë¯Öü¶æHBB\RRlÊdG`÷ÞK­—üÎÎw”Þ½52Rïû==öÕ’?I‡BèðsýØhEE5()ʱ/LLÌ K¨¬¬`Ñwð` …B.ˆHŒ‰M«­¥ééö5ÊŠ‡‡§‡¼ôÍÛS<6¸O1p`?Ù-›çöê¥D–'"44>&6 ÌL{Ø»aa Ÿ²ó)ЍˆðèуàîÝ—tC[KU]]éÉÓ·ùù¥ÒÒ⃭M 4Ù+2Ì7o¢“S>ª(÷:Ô\LL¤Ù ¬««þ<,=#[FFÒuü0ii‰–v“I€ à¿_GJK+_G~ú”¯®®fåñóóêØØ˜±^5„B¥ëÏÂ?}ÊŒL Œ!ÓÉyixx"ø¿õàaЖÍsMLôÍÌzÿµiνû'OÝå茩©þÞÝKy(”ˆˆDrI懟£kLMõGqŸh¯¢Òcܸ¡ffúþ'…{ÎpöœáljªøÐªÒÒÊÙs½¹·tÉÒ½³òvïúC__}Á|75ò›ˉ“w5õ“¾¾ú¹³› /¯øÂŇ›þ:yöœï€}_¾ŠEEY²¤’’¼ |¿x‘;G´µUÝ'Ú_¿á¿uËüÒÒJe%yr(~Éb÷k×ýfzm‘‘‘,**¯ªªe¯Å'æááQWWŽŽI­©¡Š‹‹² ñöm¬°à¾ýÿKøøx©u4ö ãÆÚnÜ0›£?II‹K*†)Ȳ–()É…¼‹KMýdh¨ÃQxíÏK—ÿ½óÂÕ+Þ»÷^:᳎}­²²¼¢¢|Ÿ§Ñê ðu$ûž’’gŸQ¨¢,Oî.²–™iorT\PPh´f¦:;©£Õ/X¸SHH0!18vB¡ï×õ)œ…¼—,=ãs^^±ŠJ ÇÀ,—-B–9zd5\¿áåÕ<¦m|üð™oTTzlÜ0ûÁàÚÚ:€ÆÆGΚX ¹­_7óúMÿÝ{.–”VîݽÒÓ³YÍ´nqúÔFII±¸øôââò–6„Ba!Žy[ ENNªªªvû¶íº0,&& Mÿ?çnhhd-ç §§î>ÑþÆMGÇA¬/,||¼-ÆÿrNODCC#û-jµš ÂŽN§4£±±é¡ïA-­žÞ;ξŠj½ B¡oÐõé,bb"B‚@}oÛ~ÆÅyˆ²’œïƒ× ‚X³öHJJ–çŒÑ|¼¼Ïž…33s–.Û ã¯-'Y÷wÕ×7äæ»¸ €™ž.ð&8š\EþAžýsëÛW{ìÛ ‰‰ kk«€ÿóÐòŠj)#%%Å Fzúg&“`¿¾ûùs!ùGNNaZZö,¯1||œ_.p«ª®eà~ü˜Kv»u::jV–Fïß'“'ÍT*-**ÅÖÆLCC¥Ùòë×y1 böœíëÖÎüjppq¶‘‘–xCþ7..½¦¶Îk¦K[ê6+%åSl\ºƒý ò;Yjê'`2™ß!„P³x·lÙÒ¾§OÜæ3_Ûåç—xLÛ•L£5d.xñ2b‚›…B‘” OŒOÈÈÈÈáååue=ÚÉ:èMÔÙsÂÃ/ýóØÂ¢¯ƒý %%¹Aû]¹öìî½WAAÑ/^†oÛ:_\\äÜùº:½Ž¿õêÕû€€°mÞg¦Lv\¼ÈB¡hiõì×GëØñ[o߯Þ÷ |ésdÍÈ‘V0fÜŠÏŸ KJ*DE…LLþ}”ŠŽ¶ê…‹¯þãMލ÷RJIýtß÷uVVÞË—S§Žzñ2âÑã7öƒêêêŸ={7ÆÅæìYßà·1]õœá¼më|>>¾k×ýNŸ¹WSS“:~ÜÐ!CLee$wï¹øömì“§o#7ošS[[ç1mãûÈäzZC~A©Ÿÿ;×ñÃyyÿ¦K¡PF; þð!÷Øñ[áá‰GŽÝèoÞçô©¢¢ÂñÉiä 2qqéf¦½½¼Æ°‚ü¹úPpp Ö]hii8Ý󯼼⒒ Qkkcû¾¾ïøêÕû³ç,^ä¾fµ'//{-kkã©Ó7æå“;ª²²öïç++kÒ3>[ôïsøÈµÀ×QUUµMãÇ++­|ú,$%%ëÝ»8»á¢¢S=~£­¥zþƒW‘ÕÕµ¥ƒ¾ó(jÆÙÇ0wnLJE¡Ÿ¥ÝS…ÍÍ!üTçt€N§çæ (²ÝZFÖ ""ÄQ¸±±‰Éd ý;d]YY#%%NDIIEmm]¯^Jì¹U…B¡Ùî«=á8“&™YÍq£Ñê……9;É­¾¾ŸŸ»o­#¢®®^T´™ñsRPP”±±ž¤¤˜ó˜eûö,ÓÓSoW|&“ÙÐÐØ–þ·Q}}C+ûªS ˜‘‘?´E„ê:?ѵpŸºº2ÇB …¿€õy—B¡ôè!Ó£‡L³ñ9ª´Þîn´ž“Ú˜ÿ¾-±Q(”VòwII…íðy»þ^ÜÇ@«V{ó7ðððt`þ†oÝL„BmôÓ¥pômää¤6oœœœE¥Ö{o_ÐÕÝA!Ôé0…ÿ"(ÊÖ-ó»º!„~œŸhF:B!„ÚS8B!Ô-a G!„º%Lá!„P·„)!„ê–0…#„Bݦp„jûž IDATB¨[ú¦ûÂÌëèn „B¨}ÚÿŒtôëÉÌ„ `ÇŽ®©ŽBè›à@:iþwÓÛJEüý;¨+!„Ú S8þ®,, ²²ŸßqB!ôu˜Â€´ô÷F07‡¬¬Žè B¡¶Â޾¨¨øöºƒCrrÇu!„Ð×a Gàà4Ú·W74„˜˜Žë B¡¯Ã޾()ùöº Ñq]A!ôu˜ÂAAÁ·WçåœÑ†B?¦pßÁÌ g´!„Є)€¸8W„¾}!4´ƒzƒBèë0…#ÐÐøÞ††Õ]A!Ô&˜ÂÑ‘‘ßU]A22€Áè Þ „ú Lᔕ¡¬ì»"ðò‚…uP‡B}¦pÄæ{n ˆï ® „ú Láè ‹ïz@@bbõ!„ÐW` G_|ÿ“Ò54pFBý0˜ÂÑêêß; ®¬ ß;B¨m0…£/TU; ˆ…äåu@„B_ƒ)±ùþ+Ù¶¶™Ù]A!ô˜Âц†ß; ôô¾÷)o!„ÚS8bóñã÷FPSûÞGÄ „jLáè òñjßIZÊÊpFBý˜ÂѼ¼ÇÁg´!„Ѐ)±éßü62‚èèŽè B¡Ö` Gl45; ˆžÄÅu@„B­ÂŽþ++ë{#èê‚¿Gt!„Pk0…#6ƒCMÍ÷YÙ¸? !„P«0…£ÿÊÉé€ ææðùsÄA!Ô2Lሶ6|úÔq†´´ˆƒB¨e˜Â‘Ž×ÖÆm!ÔÙ0…#6ÒÒÑqTTpFBu6Lሰp‡Å‘•í€[ÌBµ S8âÒ!cé#FtÀýi!„Z†)ý—ƒCÇ<á¼o_HNî€8!„Z€)q))é€ ††ÓqBµS8ú/##((è€8 33!„P 0…£ÿ’€êêˆÃËÛ1?š‚B¨˜ÂÑ))uØ-Ýff8£ !„:¦pô_òòªo_ í°h!„þ S8âÙ1q !*ªcB!„â‚)ý—²2”•uX¨Œ `0:&B¡ÿÂŽšÓ!·†€…uL(„BÿE!¢«û€~??ظ±«;B¿Ÿ€–îŒÀ˜Â~~5PÓà8´«ûB¿9sGBV†rãfgdqHG!„:Q›1ɽc~~â¿0…#„Bˆ6Ç£“²8¦p„B¨suRÇŽBuºÎÈâ˜ÂB¡¡Ã³8¦p„BèéØ,Ž)!„úq:0‹c G!„~¨ŽÊâ˜ÂB¡­C²8¦p„B¨ |ÇŽBuïÌâ˜ÂB¡.ó=Yœ¯3:„B!’œ¹c›Ê…‡ƒcÛJ~)!„ê,¥‘~m)&è(Þþà8ŽBuK˜ÂB¡n S8B!Ô-a G!„º%Lá¨;!¢´¤”Éd’ÓéôoŽSR\Â`0 ±±±#»ˆ¾OSSSYiAÐ}^šºº:Ö©M=ºû¨S›hÝùãçÉ÷Ý/ £>F~8#uËg.Ÿ8pbÙºeîÓÝÛX%/'oç¦ÚÊ=•ËJÊ”êëë{(ôppvhoë¾·|3Ó2µõ´ ó ¥e¤Ã‚Þ9ØRáõK×ûÞô}òDCK£íM?püܱs{Žïî8œ}yHPÈÎ;õ ôöŸÚßlÅ'÷Ÿ<ºû(35Óf„Œ¬LMuMMu³›ó@ë-µuùÌåãû/_¿¼í;³C_8~aÅÆüüüÍøêÆr âÐÎC¢b¢²ò²¹Ù¹Ò2ÒT*uÁòœT__¿nɺgžE~Œc_õm»Ñÿ‘Ћ CSC‚ â¢âFŽicgÓöêmwûŸÛV¶VE…E—N] 6îo¼ó°¨ ¨•ò;í¸sõyRØv W,ôèÏýíÞÊÆj¬ûØÈ°È–*:s’‘“qâòðÍC(+-9häÊM+[J-ÓçLôüñ'¬¹ï<œ»t®´Œt³¾º±n^¾)!)1kÑ,ò¿k¯QSWk©p{ƒ“„„„ößsíÂ5îUß°÷{ïOOI÷¹äÃÇÇnn³&ÎJMJ·t^»zÅÒÒ›‹ ˆØÈØE«Q(”Õ­e5JÏ@ïÏÍ~[+-QQUY½eõDljܫüù;º8Ûñù(ø‘°°0ÄFÆÚÙÜy~ÇĘ̀ím½x­Û[—#…[ÙX¹Nq {ö}ÛÑ¢üùyà@:j‚ ^>{Ù!¡…ÛX’J¥.š¾h÷:Ö úx-òú†vÃ‚ÃØO¿œ]•z*µRžB¡´½«ìZªõÕhäI-Ï¿ïMY9YGÇC;}C[ÊÈÌ($)¤¥üMj½cA¼ô{9oʼښZxóò”ŒkíÜ¥s[ïÀ·m5???™q¿3`\TÜñýÇ·ØÎŠÆÏÏï}Ð{׿]™i™ßбVÞ\ñÑñFfF …Õ¿@ó#ß©¥=àÿÈŸužJŸ¬Î›«©«ßß¾,èsÉgéÚ¥mïÀ7à8º¾ú1ò:dåü•™é-¾v¥%¥s'Ï ~ÜÞ/ô ÏÂÐéôwAïÊJËúêßS­gIqIuU5HHJÈÊÉf¤fð ð‹ˆŠðññÛ{,.*.!65‚Ÿ‘’¡Ó[ÇÐÄ"ÞET”UØÚÛf¦eæåäYXZHIÿÿs9;+;#5ÃÔ”½ÑÑyr=ä„„…ŒL9¿Ë?¾û¸¸°ØÙÕ™c¹³«sqQ1ë¿ÝHKNËýœKv2!&¡w¿Þä)noÝM+6¹z¸Z± …²`Åÿ‡j3Ó3ã¢â•ZäååeoŽJ¥æçäóñ󀆖FEyEyY9“ÁÔÑ×)*,Љæ0Œ#=d¦gfÌ623’“—kvççdçD…GIËH[µæhñÿM×RY™²¤¸$"$‚ÏÊÖJL\Œ£dzJ:¿cC£¶ž6ƒÁÈþ˜Má¡(©(%Å%µô¢ù9ësï~½ ú@mMm|L<½‰nekú&TDTÄÈ̈‡‡'=%=';ÇÒÆ’ˆySR\b9Ä’ìF+;“É|rÿÉÝkw‡ rèÜ!ò|N··®Ï^Ÿþƒú“¯”¦¶¦ƒ‹CKdÇ:bEÅD•ósóëëëùøø”{*ÇFÆ~úðÉt€©¦¶&{M«£™X˜›ÃãMÁ]àÔáS&ýMz(ô`_¨¦®¦­§}þøù¿ÿž’žû9W]K]S[óCƇÏYŸUTUt{ë’%9Ž´Ò’Òfß\¤;Wï,Zµ¨õ]J¢Ñh¡oB««ªX PRùÿwÓÒ’ÒÐ7¡‚B‚¬HJI’ØÒÎáP\T,!)!$$ÔìZ&“YS]£¦ñÿñ’ªÊªÐ7¡AXµ—€ŠòŠˆwõ´z m 5uµ¦¦¦ÔÄT1q1“þ&d•ò²òØÈXMÿwƒ<©µÔ£FÐh´¸¨¸ÊòJr$ Ù&8ºÄ}t}õcÄÊÖJ]KýäÁ“ÕUÕsþ˜Óר/GI9y¹g\>}ùüñó“<'Ù;Ù³¾Çt!< ÿÝQ©Ô)£§ˆKˆ;º8z¯÷ ­®ª¾såÎ@ÝŸ³>±Øsñ©C§JŠJ¨µT%ƒQ^Z^Qþï³|7.ß=nÒ¸ € ãŽÀç¬ÏSÇL½qñ½‰®®©>ÌtX}}=±aÙ¿‡~†¦†ï‚ÞEGD“Žî9J§ÓÆ9IJIúìõáîaldlÏ^=8–›ô7qíÐR7ÊJËÖ-YwòÐɤø$Ó¦3]gÆEÇ€Ù³£FŒ±c¤f´ØsñÛÀ·ÚºÚdC;¹¸¹ˆ‰‰-œ¶Ì ,ô&zÀ“ m‹”„¨®ªž4rRð«àððík·;Ї‡gìбì#±w¯Þ­,¯ìÝ·÷öµÛï^»Ë½i÷oÞ?ô÷!GGA!ÁYgq»§Óéo^¾y÷æÝnŸÝðÒïåÞ­{mìl M ×/]Ÿ—ÈQ>#5ÃÞÂþòéËL&“N§¯]²öÌ‘3 -½(‹f,j¨opvsNKNÛ¼j3A/Ÿ½\»díÕsW5´5ÒSÒÍXtëŸ[䙟«+Ùϼœ¼ic¦‘­ìMMM7/ßôšàUG­;sãŒ×B/ò¦Í™ÖÔÔd¦i6ÄpÈæ•›?f~$_šf;ɳ¶¦öàŽƒ.C\ª*ª 3-ÓÕÎõÓ‡O³&ζµ·õ^çýðÎCö*§’•—•‘“™=q6÷nä~SpoHbl¢–®÷r-]­ÄØD(.,^½põ+¿WPY^¹cýÖ|4î#­Ù7©±±±¬´LQY±¥]Ê’•½Äs‰¶žöpÇáÿœýçÎÕ;äòàWÁK<—˜Z˜š4w²v*+-€Vv‡»×îºy¸q,,/-/).IŒKô^ïíæá¶jó*ryjRê|ù¦LÍ=]=ËJË*+*·¯Ý>Ìaب±£Î;—“SG­;çsîÔá/fݼ|s÷_»uôuÊKËï߸ÏÚjÿGþ‹¦/ñþÝûãg´Ô«W­]mùQQUÙ~`û¦]›Ýy´`ÚîË4bbb W,{ÀªÊªsW¬Ú¼JHHh õÀÚšÚ¨ð(ÖÚó>ç/ž¼xúðé²Ò²‘/ú÷«­­]â¹dí¶µbâbJ*J³ÏZ8m!G2sç4sÁÌzZ=??¿ˆˆÈ0‡a»Žî’–‘néE9uè9 0Î}܇ôOî?‘‘•qŸîž‘’á8ÆQEUÅn”ÝÝ«wÌŒ4µ5mìl¢#¢kªk`ôøÑò òd»­ì–úúú '.Ì›2OTLôüíóîÓÝ9æÁÉÊɼ8wë\ÿAýÝ}4ÜlxÌû˜–:É^QCKÃû w]]¤´$(©(í:ºkÈð!²r² CN^nŠ×”£{޲W™ûÚ…k]xë¤ÿî‚_«¨©Ü¾rê¨uª½TÉåþõ§‡³Ç®Í»ÎÝ:×J]1q1².XÚXRk©’R’ EG_‡\($,Džðù?òïgÒU—õž_¹iåœIs–Í^f9ÄrãÎÜ­š>¹ÿ„Éd².߸t#.*îÑGæƒÌ7ìØÐ®nTUVIJIZÙZYÙZmÞµÙ÷–+¦ÏþÊÿ•º–:«Q-­ó>çwùO€™ fžó9çâæð$€Ö4xˆˆÈ‘ÝG$$%¨µT2½‘ÿýÊ/!)¡¨¬ò:dÂÔ ¬µqQqMMoß’ÿÕÔÑljjb­uŸá.+'ËÞt\TN—‘•aõ0%!%?7_EU…½˜ç|O«>Vwn¤ÖRÕ4ÔXc}ÍîÏ^°-jéh< =~4…B‘”–$G‰…„…€&/$Óh4 I `» ÚÊN`9à} *<êÜ­sìVØ‘/‹›‹‹› “É\÷Ǻ}Û÷]}xµ¥N²×•’–rvu¾|úòê¿V¿ò5{ñlØ~pû½ë÷Þ¾--.åèë¥123JIH)È+`ŸSÍý¦xrÿ ë –›‡›A?ƒ¾Æ}9¾“‘òsóY£åìç|¬}ÕÆ#å©ïÓ½'ö¶´–ð4ÀÆÎ&èEÐ_{þ"—ðóó÷Pèñ6ð­~_ý¢ü"C²?ûNì# ´²sØ%Ä&ô1êÃ=blko+$$4bÔ I‰ùóƒâ‚ ¡¡!<$Üf„ ¹ëÈÃÕØÜXKWËHÕH[O{ÂÔ ¬ùƒcohhk°> X@ {¯Ù&  Gù1BǶÔT×ä°^2 I‰¥k—ÆFÆÎ?ãÔµSÜ·„ðññ¹Nqb7dúØée%eKV/iiv*Lá¿;I)É>†}ØS ‰Á`›?¸ýà}è{ K ޵™é™ââ’R’ò ò¬ºìAXé–EHH¨Ùi Ò²ÒÑYÑ)‰)ï>ž1nFxz8Ç{l䘑Þë½ÃÞ†±ÎN&͘4qÚÄs>ç&L £¯Ó®nܸtcÌÄ1ŠJÿKŽ™0fã²µ5µ‚‚‚ì_¥YŸòì\&¸lZ±)5)õÓÇO#ÇŒ€ë¯ß¿qÿüíóbâbn?€úúzî ‡MM'mä— ×)®d'¹_dYŸAdo¹;©ÜSy˜Ã°«ç®ŠˆŠ°Ÿ»4»7ZÙjŽÂÜuÙµe'¬÷^ñ.bÍ¢5jjó–Íãžpx×áÍ»6³š›³dΜIsZï$»™ fN;mÞÒy¼¼¼ÕUÕ®#\Wm^5mö´ÐàЧ¾O ƒÁàJmjlÑÿ\ç~Sļihh`­€ñ“ǯÿc}SS??CCN­¯¯ôîìͳÜÝcÝžðÕÍ!ß\ Š PZR*&.Æ nIldì0‡aüüüÜ‘ÉMklhe­jiçpG¾}åöüeó[iZ]K=9>¹¸¨¸‡B~~~aaÛ¶fÌX ·íßöמ¿‚^ùìóQPR˜ìùÿÁ¶–>8°ö^³M@Ž®‘cFn_·=ìmØ ÁƒØ—‡¼Ñë£ÇÝbldì©Ã§ääýÃü›½ŠQWpâÀ‰Ò’Ò]ÇvqÏàùap ýwç>Ã=àIë]ä{Ëètúþíû½y¾~zÁÔ……äZq qZ ’ã“yyyÆ;%Ä$°¾Â?¹ÿ„ü!‚õ‡«‡ë» wä ‚ÈÏÍg2˜°}íö¦¦¦>†}Öl]£ª®Ê}#–’ŠÒîc»WÌYAÎ,%ååäÌ“Y»ºAÄín³âÐh´^š½$$%œÆ;%Ç'³>C^‡°nâb#,,·©“&ýM•—Ì\â4Þ Bß„ÖT×—9É.ådç„¿ çxi‚_;¸8§n¬€Üo “þ&ã''ÿ‘Ã.n.ý-ûŸ9r¦¶¦öüñóï>NOI?à}Àn¤ÝPû¡dEq ñ†újR*™#[:Ò8Þ\äÚ{×ï¹Nq…ÿ"ØŽŽ·o ó yyyÇOÏÚQÅEÅ••6v6šÚš&&¯^“Ë“’SSZÚ9»´©©©¤¨„ãžoŽã“œh™—IñIîÓÝž«h4šßC¿´¤´+ç®ã+›vnÊÉÎaßÕö£í³?f³æäåä‘ ¬½GKMJ%‚Šãn‚ü»õ£KQYqÏžsWP©TÖÂÆÆÆéØç¨@hpèœIsžú>õ>è½mß6îüýéã§Õ‹VïÙ²Çc–ÇñËÇ»0ï–-[º°yôãdf6B#C›óù$zzU•U¾7}étz  ©…iR\Òò¹Ë£Â£,_ $,tõÜÕGwñòñšÊÈÊÑh´ÜìÜáŽÃ¥¤¥ú÷=ø÷A —”–ÔÕ×ݳeOÈëªÊª>F}®¿æÿÈ¿º²ZÏ@o€Õ*•úøÞcxþøy|L|BL‚–®9ƒZK}ôNS[Ó| 9wßûöÑ5ÐÝ´b“Éäåã‰ýüµ‹›‹¼‚¼º–z³Ý¸}åö½ë÷òsóUÕUãcâ¯_¼ž›«ÜS¹¬´¬ · ëCÛslÉê%J*J2²2ÚzÚ'œ §³2™Ì•WòððìÛ¾ïÍ‹7UUýLú‘£Ç½4{=zvÇ¡ä‰)ƒÁxpë„”ÄK¿—­’× z÷íýÒï¥noÝÌ´Ìé.ºô÷á¿U{©†‡„Ÿ=z6#%CJZªŸI?[{[Ÿ½>T*5#-ãcÆG»‘vO}Ÿ^òúùk}2ƒú=ðkjjÊHÍàããKMJ½qñƆDDD úpw’}O²‚ó ð»MqiYé§÷ŸR©ÔÏŸ> &'$×ÖÔ:8;ˆˆˆ¼÷^XD¸¸¨8484"$b×Ñ]Â"Âì»q¸ãpŽ7ùU‰…Bqïôæå›;Wï¨öRígÜoÙœe=Õzî<²“Á`—]•z*ݸxCQY1,8¬ª¢*Ð?°g¯žƒ,š=Ò8Þ\d+§Ÿž»t.k\ª¨°èèî£~ý*Ê+jkjC^‡\8qaç¦v£ì¬l¬¬‡Zß»~ïó§Ïy9yç}Î{ðÖÐÒ P(C†ž:tª¶¶6#%#9!ÙÑűÙcdfä³Ï'.*®‰ÞD~Ý|ñôEOµžì·°ŽÏÒ’R )‰žj=åäÃCÂ+Ë+…«*«¦ÎžúÔ÷izJzyYy àh×ÑEEo?€âÂâWþ¯¼z%'$Ÿ=z63-S¹§²©…©‘™Ñá]‡…#B""B"‚äd¤ M EÅD?d|(+)+/+¯ª¬zpóAiI©¥¥í[Ž&؇ß[:ºÀÀÐ@Ï@oóÊÍÀÃÃõÒ磊—9ÈADàóÀmk·ÑéôµÛÖÚ²ã¾U!-9mÇú1ïc­Zä>ݽ¥ÛL¾ _æ'AmívÕ¢üT·¸¡NäçW5 ŽC›]I§ÓKŠJ•Ûr›DiI©”´knAEE²ò²-=¥‹£¡ò²ò =Š‹Šùøø$¥$ÉÏ»¼œ€_UYÅd2¥e¤™L&Aì·íUVTòññ5;%Õb[ÞõõõIqI÷oÜŸ4c’©…é±½Çÿ¹˜µ¶¤¨DEU¥²¢’Á`HËH“ÕÒ‘ÆþæJILñ{è·|ýòVZçVWWW[SËq·4w˜µ²sHKg-ÝytgëïJørËŸ€€ëé.uuuuÔ:2Ã555ñòòÖÖÔRk©-íL‚ Š ‹z(ô¨­©¥ÑhÒ2Ò¬ÝRTX$$$$!)‘û9WZVZTT”ŒÀÞDKØ.ö¶È==ö3ì A©I©ÓæLki{ O<9Ùü¶Üð ýÅAÛU Søo£ÕŽ~ 3ÆÏð>è™–É~ 2ú1‚^y8{ô5®vúúéï¸uÍÖÙ‹gsLWüa*Ê+vmÞµûØî.iý7ôm)¯…#ôÉ¥± IDATë0µ0}å÷ŠZKÅüýãYµöZ䥢ª²iצïF§Ó‹ Šº*Àý÷ÇOßU­£6Âéý:š}h%ú1xyy·íÛÖQÑê¨u7ü`={õä¾ýl0…#„ÐOGBR‚ãö§ÌÞɾ [Gm„é!„P·„)!„ê–0…#„Bݦp„B¨[ÂŽBuK˜ÂB¡n S8B!Ô-a G!„º%Lá!„P·„)!„ê–0…#„Bݦp„B¨[ÂŽBuK˜ÂB¡n S8B!Ô-a G!„º%Lá!„P·„)!„ê–0…#„BÝ_Wwý8Áá]Ý„B͇Áví­E!¢3zƒ~:ùùÿuoÝ‚#@ZºC;ôÅÆ°mðà€P›¼{÷,--»º#¡ŽfhÊÊíªgá¿ eåöÿ ýûƒ¶v‡v苇ÁØøÛûö›ùT^–ŽŽ]Ý„P×ÃSÔêê™ÙYÁML¾}x!„~c˜ÂQ¨ªvbpîÄø!ô‹ÂŽÚ@\¼³¬†DFvVp„úuáµpÔ\YÊÊ€FaáNlåWÑ«W¯®îBèg)µÍÇÜÁòò:kºÜ¯ÅÊʪ«»€úYà@:jeeÈÈèÄøFF8]!„~Q˜ÂQ›1YOg´!„P{a Gm££EE\M g´!„P{a Gm£©Ù‰Á¥¥¡¬ **:± „úå` Gm#-ݹ`qp€ÏŸ;1þ¯"$$$$$¤«{ú)` GmÓ·oçÆ<ÒÒ:·‰_BvvvvvvW÷!ôSÀŽÚ,1±ƒkkC\\'ÆG¡_¦pÔ6††{­ZEüý;1>Býr0…£6ëÔ., ²²8£ !„ÚS8jiiˆˆèÜ&ÌÍqFBµ>`µÍx€ùàÁFFÞPwfiiÙÕ]@ý,ð,µ™¬,äçwb|mmˆ‰éÄø¿uuuuuõ®îBè§€)µ™¹yçÆ×Ðèô±z„ú…` Gí‘•Õ‰ÁyyAG§sOôBè‚)µÙàÁPSÓ¹M˜™uî·„ú…` GíQ]ݹñûö…ääÎm!„~˜ÂQ›))uúÔ qF[ëðé!Lá¨Íäå;½ ˆˆèÄ&ïþðé!¼/µ™°0øûÃŽØ9£­¨”•;±•îËÜ|JX0ðñ4±-ÄY,2”«"–éŠ2Á¯8¨À¤ÃÊÿˆ‡7 Ÿ … ˆ®îê>ÌÍ!2²s›8sTUÁѱs[é¦ÌÍ›IðwuPÀtÔNýsƒÎýI4„úU` Gíáà4Zç6¡¡QQÛBý0…£vª«ëÜøÊÊ‘3ÚBè«0…£öPW‡ÌÌNoÅŠŠ:½„êæ0…£öPUý­˜˜@|üh¨ÛÁ¹l¨%ýè§„)µ‡¸8wz+?¢•_TmmmÍ—çàÒéô®í úª¦¦¦²²2òÎ |½P{á}á¨=44~D+°mÛhèBĹsçÃÃßñðð”——O˜àºu«÷Õ«—»ºk““³bÅŸiiéññÑ_-\ZZzøðÑÀÀ×rrrƒ €ªª* ‹þ..Î<<ÿžr„‡GÄÅÅÏ;»½=¹wïþ£GO²²²¬­­äää˜LfQQQLL¬££ÃŠËΜ9»ÿ¡õë×LŸ>­½‘¿AHÈ;ŸææfRR’…C‡Úž8qêøñ£âââ? uô‹ j»¼<ÂÞþG4dfFÔÕýˆ†º™Æfÿ1™ 'º-_þ“Ù@.a0êgΜaddØR•¶ÿ;þô÷II‰WQQn{ùaÃlW¯^IþÝÔTçê:nêÔ)¬­;yÒÇÙÙéÛzâïÿªªJÙûæî>üÛÕuÜ™3'¾{¿úïÈ‘ƒƒ[Q©•¬%/ž€ŠŠâoŒifÖÕ'ê8ŽÚCYÊÊ~DC—÷#ú%œ>}6))y×®¿) ¹„‡‡çàÁ}‚‚ß¹   6¶Œ/$$Ô®òüüü¬máãã›1cÚ•+×222È%óæÍyøðþ·õD@@X'ô ¯¯ojjòmýl£†††S§Î¬X±ŠüoBB† ›.]:/""Â*3}ú´ú“=ê³uëöòòòÎè ú•à@:j?xy;· ##ÈÌmíÎm¥Û¡Ñš}ˆæîÝ{çÌ™E&'IIÉ‘#›È]eeå›7ÁA j+!!ñéÓ'ƒÑÔÔ¤ªªÊd2óóó)Š‚‚Baaá,—’’Š•’’RWW:ô¦´´tРjjj55511±MMM¶¶6ÁÁo †Í>>¾/ý¥EEE ÊÊʰZ§Óé¯+++uuuõõõ¿ºÝUUUbb¢²²²dÌÈȨºº:ûÖ[¯ªªz÷.TQQASSóÁƒ‡ÆÆF†††ìaËËËýüü§L™Ü¡¾¾žJ¥2ìÞ=ߺº:*•ª¤¤T___ZZFN‘£R©£G‘pqq^¿~SpðÛÆÆÆgÏü/^zúôY--ÍìììÉ“§’ EEEO›æ)&&Ú£‡ü‘#ÇX˜7o¡©©‰››kttŒŸßó–¶µ®®®´´4;;ûþ}_ÿ€/üÉN§Ó_¼x9kÖ\h¥õôôôqãÜtt´ß½ 5Êyøðaìà ϞùÝ¿ïûçŸk™L&šÃòå+ÃÃßOšäðòÀC••5fÌøþ¹ÒÔDïÕKÍÔÔâéÓg>|4228к¸¸˜½zEEÅöí;æÎ]`ffzëÖu'§Q¬q…ÈȨf_¯+–IHH÷ïo~ùò…iÓ<6mÚ²lÙŠ¯ÿ¶Mg?ùýœºz$u7ë×yyÞJyùºèÞ½˜™q_ÍÍÍ€{÷nµñ¢é!ÖW®\$ÿÞ±cÛÎÞäõæ¡Cm.^<{çÎÐÐ`VáíÛ·,Z4ŸõßÍ›7ÌžíEþäà0‚ ““ã °0‡ óó³EEEÈ€êáá!dáØØ÷äµp&³ACC=&&‚Élhl¤¾zõ¼ÙN:8Œ˜0ÁõÙ³GW¯^rs¿}ûÖ…p‚hLOOb]Yo¶u‚h\¾ü×DcCC-//OII>¹<00"#Ãââ"·lÙôÏ?ØÛõð˜L^ õê¹¶¶ñåb¼¼¼\SSA4öè!óæUr¹AoŸ#¬½êë{‡ü»°0gýú5žžÓß¿mvë´µµþøcQÛ¯sü˜¶dÉ 榥%¶\ ýŽp µ“´4ÄÇwú/‰IKCYTT€´tç6Ôý)++÷è!Ÿ›ÛÌÔˆˆ÷ýÙ—444„„¼1ÂîÊ•«@§ÓÉS[>>¾›7¯Y[ÛΙ3ËÕu|Km½z¨¦¦FÖ¥Rëzõê EZZJAA„……ëëë )))+등±YQPPüƒB¡¬]»ÚÚÚVJJÊÉiÔÎÞ-µ¥©©áèè&¸©«k÷éc0nÜXVV±f[ˆˆ÷PVV&--Í:»%éé銉‰ihh¼~yyùææfì[*..Nn)ØØ ©­­•’’¢P(úúzäBaaaö¿i4áê:qð`ëÓ§Oðó7ÿÓ#¦¦&;^111}ûö宥¡¡qøðÁK—.ÛÙ9&$ÄHJJ¶´ÓÐïæ'Náø¤‚ŸÙÆ?¢•#~D+Ý…B™1cš¯ïƒÅ‹²ç6 yÇ‘ÂùùùEDDFŒ°0À‚#Ncc£“ÓÈ3gÎyzN—““ãXûæMð!ƒ¥¤¤ ûMêÁ±–}v‰œFpý"AC‡Ú”•…††9snÅŠ?/^<×úòóó÷ê¥ð‚•¿Ú:ØÙ ~{èБÂÂÂgÏsL ‰‹‹;;€Ðа~ýú²¯’’’RPèÁÚRöMfoŽ»i …ôêöí;&L9ÒÑÓs:ëë ËŒÓ<<¦WUUq$ãׯßpé3™L_ß—/_:Ô655‘}B?q €ðS]Ý„~&æ5»xÛ¶-–çÏ_˜5Ë‹µÐÏÏ߯f0GIžéÓ§>yò”Lá4- à…‹‹syyù±cÇ÷îÝ­¯¯?i’‡ŸßrR˜„„ÄÇYœœ2dÈà3¦9rlõêUäw…[·nOœ8Ð#ã³þÐÑÑ177}ó&xÄ;ÈÉÉe0À`0þüs­¯ï][[KËA£Giv‹Øc€ŒŒ y%;!!ÁÀÀ€£EîÖ &&ÖÃcò¨Q#9¾ÖeØK6559sîÑ#_öhãÇÝ»wuu5yú~ÿ¾¯“Ó(¶4ÍËË;i’»»ûÄÇŸxxL<ØzΜYì©wÔ¨‘&¸-^¼ôŸ.²fgg÷è!ÏÞU:~óæ­[·îŒ=êæÍkÜ_âݲeKW÷¡§OÃç®îB?“³¡¹ç™ðññM:åêÕëÏŸHIIß»w_NNÎÚÚš»°Í_ß))©eeeþþÏ]]Ç]¼xÙËkŽ´´ôøñc ‚ضÍ;::FVVFKKSIIñìÙóBBB TVVݼy‹N§ûûXX˜×××{{‹khhèÝ[ëÖíññ T*uРNN£öï?HDzzÆ«W/i´ºáÇíÝ{@@€¿²²êîÝ{îî8&f—––îÝ»ßÏïyAAayyùàÁÖ ''wêÔ'§‘¾¾µµµ¶oÿ;&&FHHHEE¹ÙÖ ¤¤hc3lß¾:sæ\mm­µµÕ;w}|Ndf~hllŒO ywïÞýµk7ÔÔÔ.Z´àÚµë×®ÝÈÉÉÑÒÒ422466úûïÝDHÈ;iii}}ý-[¶½~TYYedÔïÒ¥>|TRRÚ§¯ïÃ;wî—èêê*¹ÆD¡Pôôt'Lp£R©[¶lËÌÌ44ìÇJÃNN£ öí; ))I£Ñž=óûðáãÔ©äi}CCÃ… wìØÙ§Á¶m[ú÷7gM³oY'ß$‚~Jî‘®Ÿ…¹9ž…#ô¼†­¯¯««‹‹‹ççç74ì×ìÐ1{I*•*//ßJAEEE ¬ÓY:^TT¤¬¬Ìq‚Û¬ÒÒR111 …R\\,+++""ÒØØHDaa¡²²rKW‹¹ÇÄÄ`!%%Õ–>çæãsDEE… ˆ’’OÏY Î=کͱâÈËË·½Ÿ- üø‰·÷;H§ÓSSSËÊÊMLŒÙ¯ÖûøœPQQf Ý×™ÂIé¿!Láu_KáˆD§Ó­­m_¹~ÅŠUÆ mo ïN0…ÿ–~îká!Ô~|||gΜܶÍ[EE¥¡¡¡°°ÐØØÈÉiTW÷ ¡†)!ô êׯßÎýººu.|:B!Ô-a G¨û Ñºº¡Ÿ¦p„ºæž‘Ž>#ý7…)!„ê–0…#„Bݦp„B¨[ÂŽBuKx_8BÝ #þ?ÿ¥5€íœe8kØye¸ŸŸÈýC,?² ÷”.î<ü}Ê ß>`!Ô= ˜‡y ýæp !„ê–0…#„Bݦp„B¨[ÂŽBuK˜ÂB¡n S8B!Ô-a G!„º%Lá!„P·„)!„ê–0…w®üü’-[¢gÌ1Áß?ï#ùBµÙïòŒôÀÀÈcÇo  VTVKKIlÜ0KCCåû#—”TÈËK·´öø‰ÛBB°ÿÀ•×A‘yy% ®®$,$tõŠ÷÷·ÎíÒåÇ۽ϖ—W}Ì|(%%αöåˈÌ9 Åß?ô¨ÏÍì삦&ºšš"??_]]½„„èP[óÓGKKK|CÓAAQ3gmý{Ç¢Iî«l†ÎIKËž<Éáà•߸a\˜Læ1Ÿ[/ÂÄÅD©u´A Ã#×®ö0 oKUâã3¦NßTPPzáÜ_£Gno‹¯üó`iiehÈ]Ý^k—.Ûwçî MÍžÁAg[ŠÀ±ÛøkkëxyyÌÍ –þ1YYY¾•ÖÛÿÇhå…f7ÈÊ3++ßs†ó®K~Xßú­ü)|é²}'Oݹ}s·‹‹ 0ŒeË÷÷é7ñÂù¿Ü'Úgðavóân6»ª¡¡ñÒåÇ‘ÿÀÊSÝ'ŽPUwâå቎¼ú¶bÆôÑññ5ßı㷖,r‡Aƒ´uÇ~ø˜ûøá!mmU‚ ¢¢R†Xpäèà ³**=ÚÛtJjVÖ§ü¸¸ îOöç~>¢–4ZÃ7lQKNŸ¹wàà•ôÔûüpã¦ÿº ÇV.ŸÚJCCÛºŒ[A§3¾¡ÅÑ£'&}X·á“ÙÌ0ÆáC«Þ†ÄÖÔP[‰À½Û -íÓ`›Ù.>Œ»¬®®ÜRݶÄÿ1Zy¡Ù=÷ó‘¶©¯ïÈ!Äî×H¿wïÕ‘c7¦Lv$ó7ðòò>´JQQvî¼¹¹Eß<::5++¯¥µwî¾´µ1SPýž&¾°°`³Ë³³ 2[:û¤P(ææC‡šg}Ê¿tùñ7´;o®k\ôõíÛæs¯àáéàƒíÖí*dþ€IîN£¬¿Z«¥ÓFä˜JÇ×ÓS6´Iiå¹óZ/ùï(­¼Ðì~’Þ"ô ûõÏÂ÷ø&Ord_ÈÃÃ3ÁÍnϾËgÏùnùk^LLjtLj]]ýôi£%%Å> *,*ö˜2’,_ZZø:òÓ§|uuåaCÍee¥àÊÕ§6oj¢_¼ô&¸Ù‰Š ³·rÌçæáƒ«ÚÞÕôôìw¡ñeeUúzêööùùÿÿê|øŸ—W¬¢Òcì[11‚ ‚ƒcâ2êêêµ4{:9Y }åóä©»óæŽçååm¥LEE5()ɱ–ñúuT\|:ÏHGK5`2™þþ¡É)Y22üü|öƒä奯]÷«©¡–—WÙÚþûKˆ‰‰™Ñ1©MMtGKV@ƒqíº•JÓPWqp”]ð*ð}]]½ƒý ò¬´Ù¹õ—¾y;`ŠÇ÷‰#ì§  »eóÜ^½”ȵMá©iŸde%­,š òàÁëú†F&“©­¥Ú¿ŸªªÚ'OßòðP¬­ŒkkiÁocJK+•”äF´êÑC†½bM õÉ“·9¹…úzêC†˜¶ôí$?¿äuPTNN¡–fÏ1clÙ_PL‚AÁ¿Ž4{¼±ËÊÊ Kàããmllš8a„€ppL~A‰„¸¨½ýÀ«×žQ©õýÍ ÔÕ•ýŸ‡ÖÔP,Yç÷A„†ÆÇĦ€™iïû‘/ {­çaõõ CmÍ54T3߆Ċ‹‹Žq±Žº¬¬òÉÓ·ùù¥ÒÒ⃭M 4[ÚL„PÇúÅÏ™LfBB&¨¨p^e$Šãâ3€Ngœ9ëûDz}d«oh\¶|ÿÞ}—É’þþ¡}úM¨®®7vhyy•Aß /^„€¸˜ˆ„„(…B¦P(ìñ£¢R ¦…E‹×e9ìÚ}ÑÎ~¡jO§QÖOž¾51›’“SH®:tøš¡ñ$­ÁyôeË÷»M\ Ù ›+..:~ܰóöé7±¤¤¢•øõõ W®>å5†{UBBæû÷I~~ïV¬<”ôñoïE3¦fÕ²w\´~ã1›!¦úzêƒmf_þç1,\´+'·hÎì±V–F;w]ÈÎ.€ââò‹vù>xMîù9s½G»,“—“6ì§ó×–S &“ÕbNNÑ‚E»®ßð'K>}²ø=‰‰Zi‘ÛâEîÂB‚×oúu]¥¨â`d2‰5/!;»ÀÄlÊó€°ÑNÖÊJòC‡Ïc½šì„„7m>á9s 9¿Bã'nGE¥TTTOŠŠJ™ê1òÇ\uMç·ocÙ+®Yw ûélÝ~ÆzȬêêZî྾¯{÷q«¬¬ãbð"¼ÿ€iT*»“É|ÿ>éÅ‹p uåY^c¡åãoròG÷ÉëȽMîüM›O#ü¹¹Å ï:yêîß;Ï÷Ö×xñ2ÂÄl yx45Ñǹ®Ú°é¸å Ãúý¹æ°ë„?ét:{­ŸÓ×S÷ó54žtðÐÕÀבæfë7øŒs]Åj‹õB€ýÂý®L›:ª‡¼Œ±é”ý®4ûz!„:Ü/žÂ fCCpŸ'ñññ—“ÎþýûX[³VMœ0‚5±¨¾¾aºçfÍY^cµµUçÍuÕÑQ›6csccÓ˜1¶ 2||¼nnvnnv""BìñùÜ\¼hbûºnñY^c†·Ð×Wß¿oYZZöò• -íÓª?v²ž3{œ¦×Lû@W·—‹óÁÖÆÚÚª,žô1+õ‘Ú¬›·FØ à>Ÿ€ôŒìĤaá gÎÞ74Ô™ééÌÚ]]{ñ2bÝš™&&úöögL½ióIxù*"88&,,QAAöÔ‰ šš*°d±;+æ•«OÏž÷ݺeþÈ‘Výû÷aŸÐÄËËûÇ’I¬ÿjh¨Œùr£•¹Y[GG^õòt饦ñ ™NÎKÃÃ`éò}>äîÙý‡žžº½ý@ÏÎkÖ‰Ïàˆàà0hÝÚ™Môø„Lr A»v.ÑÕí5fŒóè!ªªŠÖ{ÑêNœ¼Ã^që_󜜬--þö^–°uÛŽÈT*ÍköV-­ž LÐ×W?°E||Æ­Ûìe–.ßç9s‹ûäu>ÇooÛ:?.溒’\+Ç{]UUÅ-ÍÕÒìžH~ÿHLúà½}¡““5k÷††ÅïÛ»ÌÔT¤£eeUmtt*ø¿õàaЖÍsMLôÍÌzÿµiνÿ±wßQMd]À_ U::ˆRĆ ‚bGÅêâZ×¶v]Y{ETÀ†  XWT:ˆÒ« XèÒkB $™ïÙÍ—M‚„Àý‡LÞÌܼy™;óÞÌ$0ìÂŇœs:¹ÉÌÌÀqŠ…J++«^¿n¾……¡¥å°°<Ùsnh„д©ãœçMRWWž5ËÆÜÜÀã4¤pþ#=¼#]D„~lþ‡Æº5óÎyÝkllÂ/««ãs.ˆÃ0ÌËûÞŸ]|ßuš=ïÁ–““Þ´ÅcŸûÅ‹vãoEE'#„ž¿ˆŽ‹ÏD}þRÄb±˜LæÎËÖ¬=zËÿ/„м9¶¾—÷r-344!¤Õñkþù®ñÙó¨_ܰ˼yå3t¨NvvžÆß?BÅÅå×®?Ù»ï‚ï• KË!¡¡ñòò2bb[«ªöÅ HäÝd‹MqÿóÒÑc×]]¦ž¿ð`õª9$‰D"¹ÿ±òÁÇBTT Õýû<›Ýã‚»DF%q-63ósMmƒ ­yÏ^|І†~¼È¶sû2+«a<3¶·½‘Éä;\YyÐïæsçyv¯^¿Û³{gÓaúø¡^x# C- 1 ‹_·Ö™g.„…ù`|º˜¨“Åb0˜d2÷Ncý:gÿ;/—-wWP-+«n£«‡§p„Ð’ÅŽ[·Ÿ‰OÈ´·ÕÔÔœ7t¨6™LÆw»®.ÓøÎ…Ÿm „¤¤$Bô–ÿŸ57ÓÙÓÙRSsš›éìnó+Wƒ–,žòÝÁi Þ<ܵsùßkùçL ðæf:~K˜¼œ B¨ººžkÞ Oú^ zöÄs„áÑÑ)7o¿hcEqq™""dóvÇ­ÑÖê ‹gOQê+Z½jΰaúœ%GŽ0ª({óæM\dTÒÕkON{úÿ±×³€¬¬ú§“ã»8¯ç»ÆÌÌÏœ[JAA!´hÉžgO<ñ$¤®®¼g÷/ŸDP(¡O ÎÓV¾› '"BÞ¾Íeíúc7üž=~~!t/àÕ¢Å{ŽYéân2™Ì·‡çrEEY®éx¾¾þ ƒÖàSØ´­í ·d±ãŸû/=v½´´ ?øà|—7×"„¤úH"„ètÆ? oaOä;ß…pÊÉÉ5f™íDËK÷ÈÊJ¥¦å”—W·= @PzxG:BhÓÆ…ÖãÍO{ú''g/\¼;>áÃ\ç—}#"“¶ou5Ê/&''…jj¢#„ŠŠÊŠŠÊñ¼¢«;pÌh“øø4ZBˆJ¥%&fY7Çï)———inna2™!¡q_þ¹4Éd^º¸ê×9mÆb±þØw¡¸¸\NNzú´ñ ò2hëèæ IDAT‘QÉø[©©9 ”Æå˦#„lm-5©†…'à7çÐhMs·ãhL˜0!”ý1_`këòò¾ÇÕùÉžx>}.ªªª­ªªõö Xé6‹H <|Šhjjž7‹Åšh·º®Ž2k–Íi-«WÍá½Pkñ¢ÉD!1) ùáÄ“ùw„bb¢b¢"ìÛðÞoü°‰ïÖÌÁd2÷¹_hia°K•OŸ>!´|ÙôêšúÌÌÏ! â¢Sú*ÊMuä)þòeÓû©(®^stù²xÆ ¸ÿšÅb­X>ƒL&çæ0Y,®º-øç2ü¤ÖmÅ,®ejh¨Mv•̾@!((üêµï\p޾×Þ¸ˆŠŠlßæòåkñmÿ¿æ;·ëöÈe®ÓG·AÛ²íü*¶º¦~ÑÂɲ²RL&3'§€ÅÂàÙAü7HîîîÂŽ¡—.!·ß³°‰ÄÅ‹&KHˆíÙëSYY«®¦ó6ÕßÿåM¿ý~[P\\.##…4H5<"14,>+ëk\|f¥13ósEE£ãØ©Žc?.òò xÿ>ã¬×ÝáC.]܃_|®®¦‘ò5¯dû6¼ÇòéÓȲòê•n³9Ã8yêæ‰S~_óJ0 KHøpõÚã›N½zó^[«ÿºµÎÒÒ’ö“F>~ï{õñºµÎÛ·¹’HD11QÇ)Vïã2¼¼ï%&fùß Þ°~††Zß¾²¡¡ñ11)™™Ÿ¥¥û‰Ä Çá #¿ ôÒåG IÉÙ³gÙˆˆËË«÷ì=Þg'çYZppì–­§srò1 ËÈüüõkÉøñ檪} J?|ø’û©ðù‹˜‰6Ã'L>r„Ñå+Ï_D‡‡'Þ¾órão  R={înFæç¨¨äðð„²];—õé#1cÖæ‚‚ÒŠŠšT&L°435¸pé!~¡\bbVJjΗ/ERR––CI$"‘H|–Ÿÿ-8ø­¸¸Xì»´ÄĬ1£MFŽ4â»FÞ-{åêc=ÝA^>¡¡ñ¯_¿ÛðòÂëÖ:„qcÍÄÄDޏŸyíúS ¥ÑÿÖ!--õôôO[·Ÿ©¬¨ýô¹ÐØH¿¤‘L&“ɤY_|/íÅ«HcZrJöÃG!_¿–df~ž8aøÃG¡IIÙsæØ¾{ŸN&“ô8üåË·÷_Ÿ8¶ÁÙyBh×n¯Ð°„úzÊ·o•ö£§XUVÖ;q#>þÃýû¯««ë7m\ôæM^í¡ìy™™_&MÉù¡Bkísùöö£ðòFCµ¯\}¼ï7s³¿»Xèô–9ó¶–ÕÔÔ‹ˆi´æý/×Ô4ä~*4¦?v¬©Ñm/Ÿ€èè”À °°ðï³Û'OÃ5Þâþ祚êúÜO…ÆF:Cï?xÓDkNHÌZ¸ÀsCÛÛÊÊÎ ÿúµ8$$nñâ)oBâž>‹´Ÿ4j‰Ë^¼XŸ>⦦ÿ.só}†V®übè>?ïñ²…z/àG“666—³X,ásgÏž £= $4.îÝÿ»I©T‰D«¯§H$qqQvÚÃ0¬±±‰ë¶1Ö$..Ƶ³_³kÇr‹ˆÅb57Ó%$Äù¾…Àyé{SS³˜˜(×Åð\¾B§·üéþ»xÙ›JJ*TT¤¥û°'2 &“Å]f0d2™Bi”kû.µ¦¦füÖíúzª˜˜ç â ƒJm’‘éÓÒÂÀ?ˆ¨¨û³p­‘Wmmƒœœ4†a5Jã Aª¼‘466‰‹ÿ–t à &W_ƒÁÀ0ÔÚ`,‹NoùîX ƒ„„XÛÛˆoH­µ7„PSSsttŠEcc“ýÚ¨ß6îXã‹No!«5øÐO{jCFüŠþÓ5ð“éùcáœ$%ÅñëÂlmGí•L&ãC梢"ì'´´¶F^ø ‚²²×}Ûl\· ´†o2k{õD"±«1ð†ÔZ{C=}5oþŽw1×> Ù»û—ÈļÞá¿Î߀ޖÂÙ<=¶lßyv@•ûW vÉÞ>k×Ìíè)W×yü8Ârø¶¾ ºÛ‰–K;ú^ 7ÎÔÑñûϤôH½«#ý?à{%hÁ|û6ΟþcoÞ¼ï×OqèPa€ AG:èõzéYx×ùeÅLa‡ð/¶¶#„€.Ñóo*z$Há@·)è– …ݤp [‚tK?÷Me#~vÀOê'~´ èRSQ@:tHØq@¯é s”àÑ­ ÂA§ÁC.@ …ƒÎQSCUUÂz#Há@h4aG½¤pÐi––¨¦FØA@¯)tš¼}vÐë@ 6`€°#€ÞR8„Œ aG½¤pÐiÆÆp9ü÷ …AøòEØ@¯)tšŠ ÊÍvÐë@ F"!„“)ì8 wAW•• ;è] …AÐÒvÐë@ òõ«°#€ÞR8„±cQCƒ°ƒ€ÞR8ÂBaG½ ¤p ::(/OØA@ï)‚¤$<  þc ÈË£¸8a½ ¤p ÂŽzHá@p /þC€ØÛ#MØA@/)NE…°#€^R8ôí›°ƒ€^R8T_/ì  DU¥¦ ;èE …QRvл@ ‚“ ì DM UU ;èEÈÂô,4Z¯xR“‰ÊÊ„ Û’—È®R8KKTSÓ+RxYk™ ÓÜTØqðAJL&VÁcòøé½~äå;¹ Há@päåQc£°ƒø´X˜4Ú&ì(ÝR_ l¾3áî½Nfq ‚£¡>}vÐ 4ÎqÄæ;wò§% …Á0@Ø@÷@s[Ôù,)Ž´4ÊÈvÐ=t>‹C ‚£© ¿7 í×É,)Ô—/ÂŽº“ÎdqHá@pTTPn®°ƒ€n懳8¤p 8$B1™ÂŽº™ËâÂ@éêÂcËàü@‡JKKØ@wÕÑ,)”¼<úúUØA@wÕ¡,)ÔС¨¡AØA@7Öþ,)Za¡°#€îíÿYœFk£üÌ (%ì àg×ס]åÚüùGHá@ $%ámжʄ—í)&½û¨X› #”¼<Š‹vÐ+@ Õz‡Á‚MQ•”;èù …A³°v ½jªkš››ñ¿ Æ/§ºª_NLd@p0 «¬¨d±XøßÙÐ@P_AËÙ@¨¨@jj¢·ð»ìwÞãüÆ—:·svÜý8BHKW«‘ÚÈd0ÇXyø|×Á]]{FjƃÛLÌMj«k™LfLx̵×Z+¼kî {AÏcžkjk¶¯ž¿:ñç‰ övØÉ9½¸°xϦ=Ÿs>G¦Eòñyàó§Ÿ~Êþ4Þn¼‚¢BC}CC}ô9ÓFZlm]~—ý|NùlÚµ©ý•)åeå×|®mÞ³YDD„o˜ˆ˜#{Žèꟺxªý‹-.,>²÷ˆ¦Ž¦ZµªŠ*U•¦¦&eeûiö /5)5À/à}ôû!&CôëÑh´ÚêZ#S£9‹æð_FPÀ‡aØ©ƒ§œ—:4@€ ð+#X ™˜ o߉‰°ãèü¯ù/\¶°“ Yê¶4*$ªý§¿ÕUÕSÇNÝsxÏ”™Sð)”ÊäÑ“ÇM×ÑU3™Ì]¿íºÿ꾘˜B¨¨ èäþ“m”?äyèÁí†uh-“'¥Ä§P(®éêÔ·¹o›ç0¯µg9*ôU˜>nú“È'’’’¡ªÊªÉ£&oÙ»¥µ ½ÔmiXpØß—ð­èÛ“OVnX)¯ Ï·À˜ñcf:ÏLx—Ðþeƽ[³d̓×4´4ð)Ò?L=Åç¦OGÃ313j2T]\}ûþívSìB Ãm¾[LxÌÙ«g°@477?}ðt¤ÕÈÖRø&À¯ŒÀAG:4T_/ì º ÃBþ È¢ÄÄÛ¾ñä_v¬Û1jì(öÎ!$%-å~ÂýÖ[˜_X^ZŽço„Pÿýg9¶Qž@ t(T¶ÖæúîÒð“Z"ñïb_E‡éžG<`]]ÊÄÜ$&3¦µüûn`Ù™Ù›Ü6%Å%!„¨TêÚ¥kwÜÉÎß!C#Ãåk—ÿX„$‰D"±k’L&Ïw™çÚò²ò¸+ˆ‹‹G¤FXÙXµQ¦C5‰¾÷•‰ Ù²j˧œO­- ð-«¶ø_óoiiiç§h?8 ‚¦ªŠ¢¢Ð¼VÏz¼´ä´Ü¬\ÝÁºÆ¦ÆT*µ¤°„D&‘H¤Ašƒò¾äáç Ò2Ò^'¼RSÓSÒÉdòࡃyçEŽ«©ª±ždýéã§âÂbËÑ–ròrìåÍÏÍÎ5³4ã\û×Ï_?f~$J*J\o!„Š Šï¾xû‚kº•Uzr:ûea~aâûDyy++‰ôñÃÇ¢‚"<ÈôäôÁFƒj D©õWûVüíÚùkKÜ–Éd„Ðê-«Ù ©(¯ˆ‹‰#“Éc¬ÇHIKq­ñ㇢b¢ôfºŽ¾“ÉÌÿ’O TÕU) ”¸˜81q± öðe²•—•§%¥iëi·ÖÏ6ß2T •)i4Zldl}]ýˆ1#TÕUy—ÖÒÒÂb²”û)ËÈÊ|ÎýL ddeª*ªøÖîSΧÔÄÔ~jýFZ$‘H”JZr£…1ÆzLld¬dIs"‘˜“•S˜_8züh¼{ 9>¹¢¼bô¸ÑxEQ(”ø·ñµ5µÖvÖmçu\r|²¯—o?µ~;îTVQF={ø¬¼´|šÓ4®’Óœ¦q&Ývnh¾(Šˆ¨ˆdÉŸª&?ç~Îÿ’¯­§=Hs@jò»_™1Öc4´5.œ¾P_Wïö›ÛP“¡\%  ŸÏŸÿâü˸‰ã._(!¸;wà,š’’°#¦=›ö$½Oš5VÄëŸzËû˜÷Ì&<xŒºâueûÚí¹Ù¹T UEU…ÉdVWV×T×ð!Tðµ`ñŒÅw¯ße´04´4&˜MhjjBa¶{ãî—O^›¿xË>]xýîEà ûiö#¬F¸ouç /%!!¤©ÃÅÄÄ6î܈ÿx/Ðó°§Ãt1q±óV`VUYµsýÎ ž2Ó2ÍF˜-sZ–š”ŠýãØÛ×m×WÒ_4mÑëw´tþþ©º—!'þ<1Þv¼±™ñ® »2R3¸Ö˜“•cka{ûÊmü«]vùžóŒ=°ãÀ”™SˆDâL›™œÚq1qñoã‡Y {øbϦ=¼½ñ¼as`0‘!‘o#ßó>†Êÿš¿Þu½Ž¾ÎD‡‰7}o>¸ý€«|EYŪE«~_ý;^ç÷nÜÛºzkeyekµò<âñ:búœéRRRk–¬©¯«§Óé!…ìX¿ãö•Ûš:š9Y9k]ÖÜ A9Ù:áq/™±O®õuõÎÎ#¬F 5:Êü¯Ÿ[ýÝ Ãb"b~]ôkhpè!ÏC{ìų¾¡ûê/**Ê5‹épSû©öÝмëýœûùÒ™K—<¤¤¤~ªš¬­®Ý½qwdH¤k}ï+£>@ý€Ç½G÷>}ðtõ’Õ¼½ôD"qšÓ´ë¯kêh®w]ïu‹ÒÀ=0ôc …A“@ÁÁÂB8¢Ã¢_={åºÊ•H$®Þ¼úìѳRÒR‹W,¾þðú£;*Ê+¤e¥ï¾¸;ÉqÒ ÍA¦ÃMûHõo;~ô¸Ñ|çe0sÍé«ÔWV^ÖÄÜDo°ž¨¨hvF6BÈÿšÿçœÏ¿nøUYEyêì©:ú:xñoã˾•Q©T9y¹M»7ñFHk¤!„¸În9ÕÕÖm^¹ù÷?~i5’Ò@I|Ÿ8zÜhc3cZ#ÍnŠ’²Ò0‹aÑ¡ÑxùkWDgDoرF£m^¹yõâÕ†Q(”õ®ëwìß!%-¥ª®ºbÝŠ5KÖpåÔiNÓ\W¹677“ÉdIIIk;ë#gô‘ê#'/G"‘l'ÛÒéôˆ7ìòººŽ³û*õ]ûûÚ„w Ï=ûnØìw¯z_½~áú¥3—ª*«Þ$¼1f„Ú¾vûì³j ”–‘Þ´kÓŸÛÿ,)ú×Íf–f»í.-)í«Ô!4Ps ï=_ƒ!­ÕF»„ÇW¬]!""bbnbbardïEç¥Î¹Y¹3Ô¨ÛN±}xû¡‰¹‰–ŽÖxÛñIqI õ ¡©³§*©ü}ìË`0•ñ´û[ñ·öoh¶ñvã§Ï™ÞÛj!TRT•ÚBIqI¼cU2²2vlHIHq™írÑÿ"ßÛFŒ1ÌbØÞÍ{×,Ysçù¾ëm'Há kÐh½ðIm²r²J*JsÏÅ_²ÿ@Iö‘Ô5Ðõ»ä·ö÷µ\s}Êù$-#ÝÆ¼¼Y_\\œïuÝuµuÏ£Ÿ¿zöjÇúúCôÙ=Û8]]³f/‚^ 1‚O±²±²²±zýnˆñ‰SS ‚ÓB'|¥m‡ñéã§ÜìÜÙógã/ñ®Ô’Â%%:Ža¾3ÅûÃ9s0næ ‘V#n‰Dgg„Ðëwï^½UJZêñýÇ¡¦¦&qqq®[è-\ƒëø±ß°ù"‘H"""œõt:7Bð˺_.Ÿ½L l&Ùp¾Å[bbb­-«pk‡q¸´ä´u.ënÞÐÔÖ¬­©ýVü­©©‰}”†³lû(äÑyó´FÚªM« †p-dòŒÉw|ýïãAÍw™?oɼ+ÞWæ.ž«k ÛHmlÿ†nC¯I}ü+chdÈ9½¶¦6;3›7…§$¤\xjmg aö*lÿŽý cÇþ¶Slñkã9UVTž9z&À/`úÜéë~_§©­Éîío›Xh4Ùr’–n­¡£Yàû._F ‡öýnwTRÒìíÑphß71 +ûV¦¨¤ØÚ“¶8UVTÊÉ˱/–éм £ºªZYE¹¼¬œL&ËÊÉ2™LQQѲÒ2QQÑïÞBSS]“™š©ÜOY[O›÷¬êªjQ1Q))î›Á8Q(„¡>R}>¤¨(«046d_ÇË^ˆˆˆˆ´L«; „Fã¼Ç†Åb}+þ¦¢ªB&“[ZZ8ëÅb•}+SQUiãÜ¥=asjll¤4P¸ÂærÅûʲÕËÚy„aXiI©¢’"ïÕàRVZ&-#-))ÉU m 4Pn\¼1|ôpËÑ–œñ}Éý¢£¯£Ö_7st´ÆZÓãk!T]U™š©ª®ª¥«Åþo"²3³—¸-áÍÜìâ¾Í}ö‚Ù&f~à•ôî£bk7·ñ°KHá  ¼|‰êµ)ô 'öŸb<Ä|¤yLx {¼ü¨ÉöÝ—³. -^¼èÉ)ôƦÆYY¥%¥®«\…K÷5Ùu …ƒ. Ù±àçd?;£?ø‚šì:pE:è_¾;èá …ƒ. ¢‚rs…ôpÂAÀ/of2…ôdÂA×ÐÕEeeÂz2Há khi}¿ €N€º†¼@W€ºŒ¢"*)vÐcA ]ÆÂBØ@O)t¥Š aG=¤pÐeÆŽEß¾ ;è± …ƒ®T_/ì Ç‚ºŒª*JMvÐcA ]FIIØ@OFv ç’@ÁÁèÐ!aÇÑ%5uÄ’RaGèÉ5um€ºŒ¼¼°#è2$yEYï[ÂŽ£‡h¤6VUW,׃› %¯Øöc²†ýgÁ€^ǽ~Ý“s9è*•zíÚµC‡)++»¹¹9;;+Áà gá +ÙÛ# R8àëË—/ÕÕÕ¯^½222v,tKÂAklvà§À`0ÈäípŒŒŒ yÐpEïÌ+? IDAT:èJèÓ'a„,==}ÿþý"""yðò¤pЕ v@h***¼¼¼TUU/^¬  P^^®¡¡!ì èQ #t%iiôârpv@îÝ»CÝt)Há +ij ; 4ëÖ­vôpБºXB‚°#] ê&€^R8èJjj¨ªJØA€.Á5ÔM¡P„½t¤ƒ®Çd"IØA³µµurrŠ…‹ÔHá ‹éꢲ2¤¦&ì8€€¥ÂÏÐ lБº˜––°#‚uÛÙÙ ;7Há ‹ÉË£´4a:Œk¨;((HظAG:èbC‡ ;ÐaÆÆÆ«W¯†¡n~fÂA×ËÈ€§»t/JJJß¾}v€ï€ŽtÐÅŒQM°ƒ­Â‡ºýýý… Ã …ƒ®)üçÃ5Ô=cÆ aGè0Há ‹ÉË£¸8aþåÅ‹ÆÆÆÕÕÕ±±±©©©ëÖ­ëÓ§°ƒtÃ0aÇz: xÌêO…÷§»Ýœ…ƒ®§¨ˆJJ„D/•žž¾aîê†ü @Ï)t= aGÐëTTTìß¿êÖÕÕURRvDÁƒþ_¿ ;‚^dÿþýÆÆÆ!ê gƒ±pÐõ^¾DÁ­áÿ*• 9€ÞÎÂÁ¢¾^ØôLøP7×DÈßôÂA×SUEð«VÅ5ÔÍ`0„@àÂTÐõàZ*²³³ËÈÈ€˜::Þòÿ?-Fq¿ù. qݬòceb¹§@™ÿ  o¨P$!ÑÍʪþle~òÆÓ{Êül ¾7q~ª†ÑÞ2~BF'R8ÚÉb”ÀSxÇÂy) p9Ð-A º%Há@·)èzHÁ§ðêêêææfüoxâÄÏB¡444àwr{ÕÕÕÅÇ'°X¬ÍÅ`0jkk;³ÞŸ†axU`_ðS½´ptÁ/ ì¦2æî¾!¤««C¥62 këñAîïtUXX¸yóÖsÒÒ’¾[8))ÉÏïVtô[SÓa::Ú†Õ××;9Í677c—¹u붺ººuG#9uêttt •J8q‚˜˜XKKKAAAzzÆì™0ÁæòeßS§>öìÙ%"""Àƒ> ÌÎþhg7QQQ‘N§Óétss³ŽÖázíqù²¯‡Ç™;·µwÑ™½tDDäÞ½û|ñ¢OßIr}û FKK‹¢¢¢›ÛŠÖy»urvXÇÐùþ«¬ü6x°A`à}ö”úúª¡C‡lذ®µYÚù¯¨èkpðóN.ÃèYYiêêjí,Ì`ÐÈdÒ‹Oð—ååźº:—/ŸgXºtñ‘#,’;·™šãœâçwõäÉcøßNN³8WÔEÿX¬æyóælÚô‹ÕŒOa2›–-s111þáeîÝ»ëüy/ £·3þààçff¦UU¥ì)Ç™={&;¤Žþ ¼_]]Æ9eÂë­[7³_zzž22ÚÐPÝÚ.\ðž6ͱ3¡¥¥ùùs6{JZZ¢”TίFûÿáíðùóÇøË––F'§YË–¹´1˹sž‹-èÌGø ï snÊΊ¢RkÙU±uëæU«Ü~¸ytô_—põê%éì<·ý»‹Îï¥ÏŸ÷boÄ¿“äúöa= ÀâD›ÊÊo[²€ ¦#}ݺ cÇZÍœ9ƒ=EZZúĉ£_rLÌÛzAüB†¸¸xû “H$‰D ð—JJJÓ¦9þñÇŸì7n\ݱcÛE"**Êu¢¹xñ"vçs‡âl¿òòò={þ¸zõþòÒ%ßÌÌGfF"‘xúôI11Q„†a«V­¹vízKKžäS]]Íd2«««ååå¿[¸¡¡á—_~=pÀ]AA=qÓ¦ ÙÙýünvàƒqxõê5“Éäœ"""ÂYÕË—»¦§g<þ¢µ%üú«Û“'í_#†a/_/\¸‰ R©K—.;xðO---v##£µkWwàcpÀÛ!û#Éd—%×®Ý(++kmqq±[Wg˜››ef¦rnJ^ß ,33ÓÍmU\\<þ?×av‰tìØ‘¸¸„[·nãSÎóþóÏÕÕÕ­-0<}ÌÍ͈DbVVV~~Áøñã$%%yRXXèéy¶¶¶nÆuøoH#„Ž;áæ¶BTT”³¤¬¬ìäÉ!àããäì¼pâÄ Ë—»Jp=‘==½ØØwÁÍmB¨¢¢¢ººšD"‘ÉdÞçxß¿ÿ ¼¼ÜÞ~çD2™ìè8ÙÃ㌋ËÒâââsúôé3b„eyyyfæ+«1ìMó–L&[[—––njj ¸ïë{uîÜ9òòr|¿ä !„g …òömlMM->…F£%$$666ÚÛOª­­MII577‹}gi9œ«nY,V``¿ÿ݉'\¹r ¯Ÿ‡•––:9ÍæZ¯“ÓlΤËÕø?|øPPP8tè„PrrŠ‘ÑÐ6{N¡PDEEð"£Ñh‘‘QuuucÆŒVWWç*™ŸŸßÒÒÂd2ûõë'++›››K dee+**ÚX]NNNbb’ššš•Õ‰ÔÎ&ŸP^^>nÜX|‚·nÛŸàå壦¦zðàŸ***­#®®K8¼dÉb„Ðúõkãã6nÜ¢¦¦ºqãoýúõã*om=^[[ëôé3uuõ¿ý¶ÖÄÄ仑´+^ÉÉÉYYÙƒ˜ššR©ÔÂÂB2™L"‘455¿|ù‚aBHFFæÄ‰S‰‰I)))d2yèС¼ó"„Ún_¿~ÍÎþhi9œsíŸ?ÎÌü€ï9¹ÞBíÞKWTTDFF‰‹‹3ZNNŸXUU•¨««Óvýô°$_®®KÍ÷ïß§®®.ðöcpžˆÒÑÑæš.&&¶sçvÞò÷î>|lúôiâââóæ-À0¬¸¸dÇŽÝ'Ú755Q©Ôqã&}ú´nÝoG_½ú×+W.±›fUUÕׯy¼Û !äîþþ‘Htršýða€ŽŽ¶«ëŠ'N±/yk­í„»wïMŸ>?}©©©Y¹rõÖ­;òòòy §¤¤êèèðŽéêéé~øð¡¹¹¹¡¡áäI¼~¨TêÕ«×ñ1<„ÐË—ÁþyÀÖv¢™™é† ›SSS›ššÔÔÔ Fuuuee×¹8®²²rûö]«V¹ÙÚN¬««spp´²cbb•J½{÷öš5«ØÇ7 ‰ƒ â:0B n1uª#þ7o㯬¬Z¿~£§çÙ´´ô#,œœ“’ø\±aXnnî™3ç.]:/%%õõëWW×úúzö¾¾Woßöç*_VV¾hÑÒÕ«×á_œ7n®^½®¼¼¼Õ9rìõë9sœ¤¤¤–,q­««kg“+,,œ1ãïþuˆa‘‹- ~åéyêÈ‘CmäoÜ Ass?±›âðá~~×–,Y´w¯ûÆ›óó¹[Ú€<k×þ–ý‘B¡¨ªª2™ÌÊʪêê¾ó"„ZÛL†mܸùÉ“gff¦‘ìN‹èè˜ÀÀÇÓ¦Mµ²³u+Ÿ½n{öÒ¡¡a®®+,-‡9ÂÊʺ²²!äçwsß¾? ô++«îÞ àš½§î$[3hÐ „û §Ã ¬+oÚÁŽw>û·n]Gq C¶ö¯¦¦\FFº¨è+þÒÎnbll†Ñ[ZmlÆ_¿îûàÁ]| þoâD›û÷ï°_ŽguëÖuüïC‡öãc->>ç ãcTþþ~ŽŽ“ñjjj¼ƒNI‰ÇÇÂY¬fMMää8«™N§††¾â§˜˜èîýõôüy/{{;®±ÌK—|ØcB|׎atSÓaoÞ¼Ä0zHHðСCØóîÛ·ÇÐppVVZB»3¦~á\ò¢E ðaž?þØýË/Ëñ‰11öövFÿð!!TZZˆaôòòb„PFF2†Ñét*‰D¬­­À˧¥%þòËò-[6r-ÿWTô!ôèQ@ûÇo¢£Ã/^èî¾·µñN«ÙÓó”¹¹ÙÁƒ²§ìÛ·‡Á ñ-¿l™ËÈ‘–¼ÓüÙméÌ'§YøôG&N´Á0zCCµŠŠ2{8*1ñ‘ÑP¼òI$bEE çÒìíí¬­Ç?ïuîœç¹sžIIïñé••ßfΜŽsnÛ¶…=^ž““ɾ`âíÛHrcc]mm>|N£Õûøœ›3göÇ÷˜Ì&ÞàW¬XfllôÞ¼9«W¯Ä'®\ùˉG9ÛáÊ•¿œ?ïåáqâÊ•‹Ÿñé“'Û³Û$NUWW÷õåËçÙ-óõë¿ôõõðP}}/°·ßÕÅÆF fÂ^ï©SÇׯ_Óþ&§¦¦š›û¡ºå ŒÅj~þüñ¼ysNŸ>I¡Ôð­«ØØ(„VÏ9ñÍ›—!vrþûòåãúõkV¯^ùñcßÖÖV9rpÁçàöŒgw(€ÐÐW::Úøß--JJ}[Z1ŒþêÕ ã²²"w÷½ì66dˆáwçå»™®\¹8y²={Þ™3§ã»‹cÇoÞ¼o¨|/ºyóZÛ{馦55Õ·o#1ŒÞÜLYµÊ­ºº,++MYY©©©/ãéyŠó‚†¼“dÀ¿þzÊ9¥¥¥!ÄÎAn`ææ‚þþ—v¤[Œâý133S„PQQï h\\~ü8 …"''ggg»`óÈ‘V)) ­ÝjÑÚ¼|7ÓÓ§ÏMM‡±çeï1\]—Ξ=WQQÅÌÌ”ï4¾—.,,d·Þ°°ðÐа{÷î+**ìÛ·WEE¹¤ä›±±BHTTôüyo„Ÿß-möZ8wP¸žº“lMyy9BÈÄ„Ïɺ@ØÀX¸¾¾þˆžqN¯©©ÉÌÌäJ xÓ\¸pÞ /^Ä~‹N§;:N¾|ùŠ«ëR|Ø›Sdd”•ÕIII;;Û#,¹Þåýz࣡Ï-s†ÙØŒ¯ª*‹}wùò•Í›·^¿~¥í¨­­Íd²ÂÂÂç͛˷ß/ç´iŽÉÉ)çÎy]ºtžïŒ&Øà$%%ÛÙÙr¾%''gllÄY?|×Å»j•ììŒóç/Î;ÿ—_–ÛÛOâj£ÁÅeIPÐãuëÖp½ó–7…S©ÔË—¯„‡G¸¸,™1c:ï§HLLºpáÒ¡CÂòå®+V¬<}ú$BHG§ÕÁ³éÓ§îܹ;##cèС†ÕÖÖâ{–ààWË–¹ð–gߺ*&&F§Ó1 Ã#§ÓéˆgÏ5nÜØÖVJNNvqYx_[[»¦¦¦¸¸¸©©‰w÷$%%ÅùòàÁýo߯®]û›¦¦ÆÆ¿)ñüúŒÓvíÚÃ^»‹ËÒ%K{{Ÿ_¼x¡•ÚØZãïЭt$IDDÿì8:Î?@X·nÍÙ³^aÒ¤µ.ÞÕáËwßmrœÚS·“';„„{xx66Ò6múmÈ!ßùÀÿxùòÕ²e.¼û\‹ôØÏï–uvvßñ΄„Ä3gΩ¨(¿{Í÷  3ÈÉÉ©¨(³7(ç–íÓ§þ¥K¾¿ÿ¾™k®œœ™6æå»[ãݧ!„jkk££# Ÿ={±~ýÆ!C ¹¾}ø^šÝWlccmccclläà`_–ÕÜÜŒ_iÑöêxõ°dk^¾ ¶´´À ¸¤ýŒ…‰Ä7®ž;ç‘‘Á9ýÖ-Þóicc#==½ððüeFFFff&B¨ººÚËËçĉc[¶lš?{—-##ÓØØˆúð!‹H$.]º˜}E1F{òä)úg,ŸÈþCWW×ÂÂ,2òï§ááC¤L&sëÖbbbÖÖã¯]ó-))áýDì> ü¥¨¨hŸ>’))©¡””Þ5ò®!”™ùaË–Mëׯ=vìç gy\EEERR2×»..Kž?Á.pŸïºØÿs.SFFfûö­7o^ÿôéóœ9ÎAA¹·²¿{EE%ûÚKÜË—ÁãÇÿ+óÕÕÕ>|ÔÅe¹¡áàÀÀ³fÍäû=,//¯««Ã/;yò8‹ÅZ·nìY3ñwŸ={Î;‹††ÆÑ£‡wïþƒÅby{ŸŒŒú믗oÞ„nÛöû?ŸBš}´ž™ùß|ff¦ýû÷OKK燇GØÛÛ)++£šJyyyEEEkU»uËôè‘ÚÚÚ¡ââb »sç.“Élm³²=ÊßÿæÜ¹NÛ¶íüý÷mÅÅÿêÉPWW÷ò:ãæ¶Šs¬´°°Åúû€£µÆßZâj‡l$iÁ‚ùQQ1øË²²²šš[Û‰¼a/]ºøíÛØ°°pÎßÕÍž=3--ÅÃÃ#–.]Ì·0ß&Ç~ÙžºEihhœ=ëyà€»Ÿß-W׉‰ÜÃÿœëÂ={öüÇ,öå8ƒqû¶ÿ¬YsªªªîÝóß°a=oþŽŠŠž?QPÐãÓ§Ož}&3󃔔”……ù¤I¶§NÆ0,''744ìõë­qâÄ 'NxˆŠŠÔÖÖ=|øÈÙy®¦æ¿:p’““OžôHLLªªª"‘ÑP„PKKËë×o¬¬Æ„…E0Œsç¼?~Ìéß_½²²ŠïÚÍÍÍš››GŒ}îœ÷É“>RRR20Ð?~üäÝ»,ëýû¸ÈȨ;wî®[·aäÈ“';øûßñ÷¿[XX¨­­åà`_[[wï^ƒÁ~miiÑÔÔtðà‘ÔÔÔæææ!C ÝÝ÷§§§×ÖÖfrðàḸx …baaÎ>ˆ±´>{ö̸¸¸C‡Ž°XÌÁƒ ðL&“/^xûöW¯^ËÉÉ•••?zØ·o_+++|ÞŠŠŠ£GûùÝš;×é÷ß7kkk·q”ª¡1(55-99YEE98ø•¦¦&‘Hxöì¹¢¢â;÷LMMx¯FaI&“NŸ>S__go?éôé3))©·oû)**â}Ñ7oÞRVVNKK«««¸/))9fÌèI“l;I£5&$$¾~âãsÿȱ±ïÒÓ3œçQ©Ô'N½|ùª´´¬¶¶vôèQœ222W¯^“““}÷áà  ÇZZZƒ Ÿ? xàä4‹@ Ž5’@ ØÛÛyzž¥P²²²ÓÓ3¦OŸ&##cnnvôè qqñ˜˜·11±QQÑ ò¡ž½“LJJ:zôxlì{VXXü*$$ôÒ¥óìîö40n—® •ÜãzÔÁ§³YXðŽ…sªªªJMMSWWÓÕÕm»Ã­ªªJLLŒ«¯’¯–––úúzöð'B¨±±‘J¥òödòUYY)%%E ÊËË%%%ñžØÒÒR55µö?jçãÇ%%߬¬Æ´g–²²²µk»y󺄄‹Åúøñãôé³ß¿iÏ=6œ FYY™ššZ‡lx1™Ì‡544¬X±œszcccjjšˆˆˆ±±{ìðmÛv,XàÌyïGÛ0 KOO¯¬¬211Æ·TaaavöGcc£¶/3Æ+§¸¸¤   ªªzëÖ->25†ï÷Y,Vaaa¿~ý˜Lfmm­¢¢"»K¶ªªJDDDFF†siõõõ$‰+㶦´´TFFFRR²¥¥å‡Ÿ¸”ŸŸïåå³sçvÎ-‹aXAAAnî'më nIDAT}}½þýûón»ö7þ¶566644´]ÃÞÞçW¯þµõ†•””())ñ^Wß!?P· /^=zÔèÑíºj×Ûû¼ººÚôéÓZûhoÞ„df~ps[ÑöŽõæÍ[­Ý$ÖQ†}ûöMII©=¹¢¢Ïô?0/ƒÁ¨ªªRQQ)++#“ÉrrrL&STT´´´TTTô»;™êêêÔÔ´~ýTôôôx¯VámœøÞREE¥¡¡F£)((´Öyòô­[7ðVÅ`0lllðŽñ•JUTT6̤²²*77«“ßF°ÿAcc£‘#G„‡GÌŸï,ìp~R¥¥¥±±ï؃>à¿Ô[w’ÂMá­?#pyüøIRR²ŠŠJMMMuuµ“Óìvž^ôZ×®]ø0pË–M?ð\eÀåéÓg™²²²«V­Ècç{¤çÏ_88Ø·vßèj½r' )è–œÂáðè– …ݤp ëuÁ3Ò!…ÝRSxWüÐ :΀n R8Ð-uü—Êð¾ô„žéÜS~ò2L&1¢­2(ÆYÃ]æýŽd0ÿ»2´fdý[·/ÃU!4â×ï,Êü@™®øRtÓ24Ëóãu?y™Ÿjoٛ˰¡vŽ>Ú¥7±°à³£à§5âW>{(@Ïé@·)è– …ݤp [‚tK€n R8Ð-A º%Há@·)è–:þŒtðC¼|ŠJHˆÕÔÖËËÉìÙ½BSS÷”Ç­ðˆ„ââ „††ª„¸øí[ÙóÇžó¾—Ÿÿ­¥…1p`?rcc“ŒLk —¥SååeØ%?}*ܹÛKLT¤©™.&*:vì°°°„{w¶Ø ¿gúVW×}ùôDNNº£Ÿkÿ˾W‚$$Ä>f=âz+--wñҽ߾U^»²oêTž'BÿÃÅu_^~IYYµ””D¿~}™Lfmmƒººòâ…S¦OG$¶u”9jŒëׯ%®.ÓŽYßÑÈë´çmoŸûÏŸzêëk´V¦í)ü¿°aãÉ Ü¿wlúôñ!&“¹qÓ©!Fó®]Ýç)ÊËûÖF og…@;AGz—{ô(ô¬×Ý… ðü"‘Hg<ï×Oqå¯‡ŠŠÊ~`™ÁÂÂÐÆÆâk^É ¿gøÄ„„yùßôtâ/å<=¶´gib?›¸x«³ÿØ’Éd2~rÚÓ¿±±©’Œ\€n\ÿ3=åî¤I#Û.öó èà,¼Ëô¸‰Z0ßs"‘Hœ;ÇöøI?ß+Aîûx~&²}jjêBªª}ñ—ÊÊ ¡ÅK÷nÚ¸Ðz¼…‘‘Ž™™ÁÖ-KÙå++kÃÂòòJ44Ô&ØX(*Êq-Fkzø(TTT„Á`Z6p`¿ó’S>²Xا‰ïÞ¥§¥ç666ikõwt´âÊÜÅÅåQÑÉMÃ-†éð ðððÄÔ´"‘8Ùa´î?G¼X,BˆL&‘HD|ÆØØ´ä”!s³Á#GñÎòî]z^~ @è#)wS?|Â`2u´¨ªö ~K¥Òæ8M¬«£DF%‹‹‹Î˜>^FFªšINÎNJÎnnnY½jÎÛ·©iéŸèçà0ª¥…ñìYTiYÕÈF†øìÏžGQ©4qq1¡ì켨èäÊÊZUÕ¾S&Á7 œ…w-‹•žþ !¤®®ÄõÞûš–Û¡¦§ŠÏ|ùòíæ-™™_\ë²t*þ–¾þ éÓÆ—oÙêin¹X^Ñzõš#£GãïÇ1š[_O™5Ó¦ººÎpèÜ7oÞs-œ@ °X¬…‹v9z Ï¡-¿Ÿ®«£<{5~ÂJié>³gM¸zýÉ£y5쫪êö¹_쯮ÒOEq²ãúÿµwïq1¥}À'Õ”ÜRm…’.ÌtÑ'–D.ŸµJˆ\BÅʪµ)"½å]¹ßÒv±J)jUØJ¬.T^Ý³Š¨QR‰Š0æR3sÞ?Κm§‹Á¶vÞ÷÷ýëtæy~óœg>ŸùÍùçœ<6îëúOl¹\Þœ¯Üwì ¶šfJ£ciõMtLJ·ÇÈb±?þ»]i4ùŽþBûï}w…|9Ùh’Åx/ïcöK¼ø|¾X/yy¹ø„_—­ØQU]GíɾQ|66 ’$³²Š6n>pøHì•ô[¦&ô€Àˆy¶ž½Ï Ÿ/ˆ8uq›÷±=ÿþ©¾á9ƒ®ccçéæ´Íû¸ººÊ‹¯Í'­ÎÉ)’$ssË<6í//g@sóK#ãeÅÅ÷W:Îe2ëutmssË$þ„BHR˜Âû–@ äñ: ë²,YÙ~ðîLZr«—W0oçß8•lddàâl+ŠLDÒ…ÁÇ·M·2£É˽esÃO%/wô%I’Ëå­vö;VwíšúúZë]í ´W9ùµ·wt® @[½ÊÆqÅÜŠ &‹Å€––6›y–¾]Ì šo;Írª±¾¾Ö&ej.^Êu …á;§N5þúë©în'ü9%%GläGŽÆ]Ï(ØîíbbBŸ3g’Ój›]~¡de9»ø¯vòsrÙÝ¿¿Âí¼¨m^Np2$áÒåþ~®&&t33Æî]ë’’³BÃÅ⛚Òî÷”!ˆÛ·ïR{ªªëB‚}LMéÇá°d6°XÏÍ+ÌÌ“,Æçæ•q8Ü^fÆÜ|ÜÔ)ÆoÙÜÑ£µ—:Ì™>}¢ÎHͨ3¿l°´4±_d ™Y… ¦¦¼léÑH R²³³²µ™¦¥¥á»c ‡Ëû1ôÂ}Ê!$ ,¤÷-99YCç·»ÕuuM ƨÎ/55µÀ˜Ñ#{éîµí¨ÓjCÃ?êÒö‹fR¥Ú!CnÙzx·XX¨/õR[Û.—çîæàîæÐÞÞ‘Ÿ_îæ”š–ÛØØÜÔÔú¼ù¥µºŠ(ަ¦jÞ­;••µFFboêãís65h_Täiÿ}Î;ò=Ðé:n'‚ãÙl.‡Ã€W¯X¢.AAmëꀛ9%¶¶Ó:‡ÍÉ-€Ô´Ü‚ `>ª … _¿~TcTT¤×IÈÈ, ÑÈ 3«ÐÃ}©XK=½+–w%àAmssÛHmM--Î LMéÔ&<^“YÿÞ™13eˆzh<@š 14š¼¿Ÿë…ČĤ uuàÕkV×f!ô‰ð,¼Ï­Z9 ‹*€Ëå••= ŠÀ7sJÀÙɶ§Ž$I^þå&UoïJOw¼; ¤dgÿ+ ‚Ú–——³´4 úa#°Xì ½ãsn¯¨ýbŒQ‹Ï:{%))s¨ò`êη͞ínµµ™êëºnQ/ÇKåò®ÚÕT•`÷‹÷ºí t»°ÿÉã4QþîÅ¥þÐÞÎ7òÑή¶û¸ÀÞ ¨ ýQ>ÞÎb¯R•?—`f:÷ê¡«ø„kL–+))†‡ùîýÁ£÷ûâBè£á—KŸÛâ¹bº•Ù‘£q¥¥•+VúÝ[²Ô'âTò›%Þ^N“'uÛK(úímhxÞÓ½ÚjjÊPͬommkmm;’ñ ×JK+Emªªëèctôõµ ´§|9¡°ð‡Ã€·o9ÅÅ÷§[™‰nL³ÃÇ…/8®Ú¹ÝÇH’Œ»B§ëX[›@åƒZx·âL4ZÑÒúŒŒ‚ú/u˜-ÓuÝB‚HLʤþäryË|:鉋ó|x÷‹Þ÷ÓgìX]{û™1gSÕT‡ôtt}èÌH"áç_…BáÚ5v²²²UUu¡P’ÃD¡ÕÏßßÿsáŸ*<ÖõxŠ,9™•Žsi;w…´´´ öEÞ­;qqé1Ñ›7-ohx>hЀƒ‡bŠ®©m$I²¨èÞéÈKž[]»ž¯§;ÂÃ}éÕ«ÿÙêuäáÃÇ$I–W0kj­¬Ì45UëêšîÝ{TUý$5-oæ s>_PUýäÑ£†Ó‘— Ê##/çݺ¨®®B„Í8$!?¿üxðyó‰ãÂÃv*))ÆKHzó†]RZ¹há 99YÐÐP-+{`Ú@;âTrü¹½**ƒ©=ÅÅ÷·ûžhm}USÛ@£“š–{îüU›[RZé°d¶Ý|«ngæLtÊéÈKoYœßîVÙÌ³Üæ}¬  ‚Åb?}ÚbfÆp^ãÿ´±åÙ³C‡êH«ªŸXϘhbL/-«LLʨ©i¬¨`δ6OLÊ,)©3F§ó„ôT_ùx§RÀÕõ/މú#º®F¿›8òÃþÚl6·¡á¹P(k¸dÑ"k}=­ŒÌ‚‚ÛÑŸ°±±Y]}èÀJ— —ËkllVVÔùÁm’$Ùl®’R7õs1€ ±"0—Ë£ÑäE—½Å´·wÈȲ²ïY`Áçó!u-ùƒ´·wAýÈèêÙ³ÖÚÚ§†å'‚ãc¢?(¸ä3#!>ŸO’ÐÓhû„Åz(*úûÞ!ô¹ár¶¿Uÿþ ÔÍгfY\HÌ€ï<?1 µº ¨ š®îˆnÛ!a–êö*u/Oqyy9I"Ëʾ7ËLü€Àˆ¨3)-ϯïÝE-Áû ’ÏŒ„>ò BHbø-óy=¼Õ{ûq­ê>÷XþG|³vÁ‹¯7n:°ÝÛY[[ãýBHÊa!½g}PHG¨a!¡ÿ3¸"!„’J˜ÂB!©„)!„’J˜ÂB!©„)!„’J˜ÂB!©„)!„’Jøh—^Y¬ÿÜ#@!„º‡vA!„¤ÒB!©„)!„’J˜ÂB!©„)!„’J˜ÂB!©„)!„’J˜ÂB!©„)!„’J˜ÂB!©ô_Z¥éòзÒIEND®B`‚java-algebra-system-2.7.200/images/poly-ring-over.png000066400000000000000000002403021445075545500224030ustar00rootroot00000000000000‰PNG  IHDRg®Í@'ŽsBITÛáOà pHYsÄÄ•+ IDATxœìÝwTÙÛð; @èHGEP±ƒ‚`ÃÞ+öÞëZ±ëªk¯Øl(¸ºö‚½aC@)@¥÷:ï³o~, Æ ì~?'Ç“ÜÜòÌ Ç'S/EÓ4%°ª:€Y@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…¬  ,•ª¾ÄÁ<{DTJm)‡6eë„>ýg“¯¬ðè.QW¯¬øé<*TKf¥®îÊþ‡ ÿBªU(Gh”…¬  ,dMe!kV{8©ù_ààPÕ€R5k<>Ÿ/“É!Ì¿P%°þ#pçIM%‰6mÚÂf³­­­òó ôõõîß°qãz==½_LVVÖ‚‹JJJΜ ¬¼æùóN äóù i:++ËÕÕ¥k×.Ì·QQQ·oß?®òC§¦¦úøø]»v½]»¶ÖÖÖ2™,%%åþý¾¾Þêêêóç{˜™™îß¿÷Û—­RÕj+À¯@Cu'.ÿ‹‹\]Ûœ=¨(‰Ž~Éår²²R+¬ÿÅ—\.ÚºuÓ·µe^/^<íÞ½«25wïÞÙ­[æ½H$pvn}èÐ~æã“'—.]ô Ás¹œ'O*JΞ <þ M‹ÏŸ?3nܘïY®ò/¡°@™­ ¨¦ÔËÞ¾ªÿÌ@)8B[íI¥å˶oß©««;xð EIÓ¦MGù̓¼~ýúãÇßÜœ¢¢ÂV²&‹Å¢(Šy¯¦¦ææÖñرãÌÇ6mœ7mÚðµCSÅf³™> MQQù‘GSÞ¿?þÂÝ»ÿÞs­d+ˆÅâ%K–­_¿177÷UGh«=çvå/:sæ¯Aƒ”)œ1cš††F™B©Têíí£¥¥™™™5nܘÄÄ×®]/))ñðX}ãÆMkk«V­ZΞ=—Ãáøøø:;;5kÖ¬L«ÂÂÂ;ßÄĤwï^•,œL&{þ>®ÿ¾4-~ù2ÄÆ¦annÆåËçó•ËE4->|øà¬YÓ+iuâÄ;;ÛŒŒdšwêÔ1$ä sT¶OŸ^I1M‹½½0Gh×­[öŒ¦Å¹¹î+ÒÞ½»lm[œ9°sç¶öíÛ>þXñUzzRݺu˜÷ޏvíïÛ·o¡iñ‚sýü¼G¤y¼û|5¨°¯YóPU¯^½ää”2åEEEŠƒŸ„‘Htø°o÷îÝîß@ I±³³ÛºuÓ°a#G1nÜØòýWØJSSÓÂÂÜÈȈbbb’––FÙºuûàÁ™£ Í›7ÿë¯ó„-š2bРݺu2eR…‹`bbìî>˜Ò¨‘Í”)Ó_¾|Áb±!¥÷ð*11ñCÝ!FFFññ µjÕRÔ4h ³³SýúÖÌÇ>XZZ*¾Ý¿ÿ`§NnÌ©ªªÆÄÄÚÛ·ÒÔÔ´³³#„˜››5kÖŒbnnžžžÎ¬‡¡CGtìØaÇŽmêå«üV°°°Ø´iCVVÖÆ›Y,ÖŽÛ*\'P#T]ÖÄ jß¡[·.¯^E”)<}úϱcÇ”>“' ¥RY§Nnªªª„wïb™ò.]:ïß0>>¡|ω‰‰zzz¶R¤4Š¢är9!$33S[[»L;wºpáì•+×<<– ê¾bŲJ¤Gî}úôŠŠ²µµ-ÿmùÝÝ<@ÓtLLìÖ­›Ê7éÞ½MÓ„ë×o̘1MQ^PPèèèàììD ºÊápþ ¦ÿòcq8œyóæœ<pü¸ÿøñcM”Ü „œœœƒ½d2ÙÔ©“+YPýU龿s¯ª½¦pšV¾ì?ÖØÛ;½xêèø÷‘H$•ÊÊüg­««ëêÚæÕ«ˆvíÚB?~âêê"•J÷ï?xþüÙ¡CG\¾|¥oß>„.—+K!÷ï?˜0a|ùV†Ö½{·ˆˆÈAƒBòóó™tµqãæÅ‹=–-[²pá|w÷²'ÉÿŸ`ÞS¥££fkk›––¦¥¥UùÊHHHÜ¿ŠŠJ™Ó–ЙܖýéÓ§Òz÷îÞ«WOBÈÛ·ouuu™½ØÊ¹¹utsëøôé³9sæ7iÒxò䉥÷†•Ù ©©©û÷,))™5k†••ÕG€j޽fÍšªÙÛ›Lé[5C×,ÓW”/ãp8C† ÞºuGrr²––fddÔ;÷FŽ^~ÈÍ­ãλårYDD„ªªjRRÒĉSØlÖÀòó æÎ] “ÉZ·v4559zô˜ªªª±±±µµu™Vl6ËÓsODDdƒõããã=žÓª•]ÝÏŸ¿“““™™uåÊÕÛ·ïXZÖMNN‰‹{#•JïÞ½×®][›Òñ\¼xéøqÿwïÞBZ·v¤(ŠÏ燇¿255ÉÈÈ:qÂÿþýÖÖV<¯Âuttœœ\Ïž=·ÿÁ—/_9;·ÎÏÏßµkÏÍ›·UTØÉÉ)!!/.^¼4{öÜ^½zíܹûÕ«›†£G<{ö¯””Ô´´´wïÞ¹ººž …-Z4÷ôÜýèQ°¹¹™\.Û¿ÿ`BBbÓ¦MÌÍÍ™˜k×¶èÛ·7—ËÙ¼yëë×1Í›7cÖså[!11qÆM¡¡a³fÍpwü…;8œÈÔ©ßþG¿JÕÍæà€}M¥°[Tòe^^^LL¬•U=SSÓJªåäähii©©©UR‡¦éÜÜ\Å¢J¶"„²Ùl‹•ŸŸ¯§§GQ”ŠŠJJJŠ‘‘ÑÛ2bcc%I‹•-)!D"‘Œ=ÎÏï0Ç“J¥—/_¹xñòÑ£¾Ê Ár¹¼üQeåÅÆÆÞºugΜ٥ Ëo±X¼c‡çäÉ •êס .£¨p5Pͦ§§÷¹Ã§¥•Î…ŸCQT™jÊ´"„(«r¹\E¡………2m7V¦š\. …Ì#ëTTT´µµÍÍÍ”…¢©©ùUõËkܸqùhËo55µeË–|çXP !kBÁáp||¼üüŽòxEEŵk[¬[·¶ªƒ€ÿdM¨IŒŒŒæÍ›SÕQÀž¨Wí …Uü Y³Úkשª#€Ÿ—ÔÈšÊBÖP²&€²p m äÐæËÌ#&•çv•U Ëž+-S¡Lÿ_¬€~@8¯ P3àÙ@Pý8MC€ê Gh”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”õ/Éš¥ŸpTeO;€»šýÚ¼¼‚M›DD¾ÓÑÑÔÕÑ$„ôëÛaÃ&ß§~mW É¿¯>õ^(,qjÝŒ¦I¿@MMuÒ„þ}û¶ÿ\«Ã>ç7lôµµmxñüÎïXŽo4uÚú˜ØÄ÷¼Ùlv…J‡wõjð ÿ«¡a±::šYŠ%Òââ’F6–³f©WÏœ©ïwäâ†~·nì·²²ø…ËPcÔà¬ùúu|·©nnçÎnãñÔ !ùù‚>ýæ½{—ô ½YYYøŸXo×jDRRÆ»7˜Â5k½ú \à{xÕÄ ý+l5eòÀ¿ÎÝ)*~óR|¬l~nn¾\N&iþ#¼Þ½ÛººÚêÕrëÞÍÙÿÄzBˆ@PܵûL¿#Ÿ?=Ö ABŸ_˜““/I~áBÔ$5õ­T*1jEqqɾ=‹™”IÑÑÑ<â»úŽÒ¥³!ÄÿäõJꨨTÙ/sg·EGþ©ªZY•„§©©Ñ¾]«<~áå+™’óGçfßmܸÞàߢ¦îkÆÄ$FE¿wëè`llPº¼~ýÚ;¶ÏW|¼qãéé?oÖª¥›™™÷Ûìaööûœ?Ô¾]ËfÍêÇÅ}x=cš{ïÞm+%##‡Ò¼Y}Bˆ@P¼eë1‘HÌb±$éÒ%ã õJWöõ»píúcš¦gÏÖ©“c@`Pàé›nÆë;z쪼¼‚Ýž·n?OHH¡(â¹s!§.—ËýŽ\ŠŒ|§©©ž›[0sÆ-ðù…Šú7o=ûô)¢¨f9z)--;ñCê¦ ³4¨ñvñÒ=EEÂà‡¾„[·ž<dfV+î͇>½ÛMߢ¨ÊסD" ‹ÑPçvíâL‹%îCçæìÛ³ØÎÎföo["£ÞÍ™=<5-;%%ó}|ÒÆõ³ll, !†ûŸ¼f` ›Í·°0zú,rÝÚŽŽM¿~3Ô4tU±·§¥¡ßü 8¹2ĽK%uΟÝNyñì8- ½qmŸ®Ž&?ç>- uu±­SÛäî­C´4tòƵtå’LÛ Ø,ÖÞÝ‹öìòX¶d¼…¹Ñ„q}‹ ‚eâ¶®vŠáÎ]ßÚ¢¨ ˜–†öîÕ¶s'G¦|±ÇX5U•”O×iihÔ«ÀÓÜ™ò[Aû !“&ô?Mþx²ïZº|é„ÚÆBÁcZzù‚§šªJÔ«@Eý‰ãû•=IK"„¸´i‘–DKC­­,FïÁt»nít6‹Å¼ï×·½«‹-3.!äÂ_Û™òÒáåeß#„Ô³4[±lâŒiîuj›Ø·j”š¤XcîûBÝ÷¡¥¡¢â§!N­›1‹SßÚ‚Yüä×8jª§ü×ÓÒÐùsGZ[Yܼ¾ïSâ•ïÙše_ööUög P©šz„Ö²®!D (V”lØèë±h×’¥{/Ùí±h!ä ×YŽšªP( ~Åf³øù‚/^B¸\5GÕÍÍbl¬Ÿ•Í—ÉdŠ~dry»¶-{öp6upÂûK~¾«54¸aa±Á_9Ø7fê8:6yŸ|ýúã2Q-˜?ŠÅbmßq‚²}‡ÿÒ%ã™r.—CéÔÉQMMÕØXŸ’šš%—Ë÷ì lÖÌšùÖѱ‰X"õò>§¨ß¹skGÍĤ!¤UËF̃”ÔÌÒÝ2ŽYë}hÅ¥Kž<$„¼|õæs«®aÃ:ë×Í<°éòeÂÂ㎟¸¢øŠËUS¼WSSe±X-š×733$„¤¦fBJJÄ"±DK“GÑÔÔÈÉáwîܺvm“/l0€…šz„ÖÖ¶…¹QxxœD"eNìÍ›;’¦icÓn\®ÚÇÄ+„‘HLQ”Š ›¢(õ§ÁGš5³fškkó*éÜÚÚBSS£tI~¾€¢¸T•ÍbBøù…eL™<ÐËûœûàÎŽj:ÿÈ%ÚZÿT,–—°Ùÿpa:çó +¬¯££YIÀR©tæ¬Í1± [6Íé×·ý´+©¬0h`§é37ž¾¹dñøÏÕÑÖ.;®µµÅð¡ÝŽû_}üòÙó¨“'Ö³X5õ·Àת©ÿß©«sý#7·`ÉÒ=r¹œÂã©«ªªH$RŠ¢˜œç>¸s‰H¬­Ísvnîìܹ\N×®Noß~bâM$„ôë×áÂ{ö,:àôÕ«¦vïÞF"‘ånZÕÕÕ¢‰Œ|WT$|ÿ>éåË8%‡ûø)míêióæŽ¼x~g.ß0@ Å^³fMÕŒìíM¦ôýžêÕ36´ëé3·öî ‹}ð lמ€¡CºMš8€âàÐDC³eÛñèè÷ç/܉ĺ=vùÌ™Û|¾@]S"íÞ›S—Wаa¹ó¶¿|õF"–ÆÇ's¹œ† ë(ÆârÕ:¹9ž ¸þôiäÍ[Ï¿<ìµ²U«FÇŽ_9}úfv6_[›×ªU#BˆŽŽfRRz=K³I“0mùüÂ9ó¶}ú˜žš–Õµ‹Óê5^ááqyü‚&­&Oðòå›ÀÓ7BB^;qeÑÂ1ãÇõÍÏ”©›Ç/hdcy=èÉ¥Kòò 455d2ÙÖídz²ò!t|ý:þÚõÇYYyQÑñ ê×¹pñ––Fdä;ExiiÙ›6yóæ£P( k×¶¥–ËU ~‘••wéÊC·Ž+?øáCZRrúˆáÝ—-ßÍçÚ4¬{ûÎó ïçåjiiØÛ7>sööÏžþ[¶;pàŒT*m×®å÷lʲ|®©Sd‡?¥ÌNÉOáà@ž{ýžhšÎÌÌ•Je&&Þï_\\¢®Îùâ5¥ÊH¤4M«©©–ÿ*.îCA uëf'­]ä1Vùû7hš EÜïŒM.—K$RGíËUK KÒÓsLMk•>KZ‰€À }ûÿܱm>—«&Š^„ÆÌ¿=ùã5ss£oŠº"NÓHhèë àÇ©©ç5K£(ªÌý'e|BR¨äæÈ}ûOø˜öÛ¬auê˜|Õ-EýY,ÖצLBˆº:Wñl e°Ùìü|A­Zºõë×–J¥¯cÌÍ +?í ð¯ñoØ×¬&ÒÓ³¿bbRkÌè^ÿî d"#ß]»þ¸°°ˆ¦i++‹AÝôõu~äØ×€ê YªdM¨®þÍ»D?²&€²5”…¬  ,dMe!k(«JŸrà4­*GøJUš5q¿&T?§ ºÂZe!k( Y@YÈšÊBÖ„/ŠE"1ó^&“Um0Uëß0¿&!äÅ‹×G] âÞ…Çã—¼zõ–ËUóöZù=Ÿ?ïT`Ÿ_8p€MÓYYy®.¶]»:3ßFE½¿}çùüy£”ï055ËÇ÷µëÛµµ³¶¶H¤ )ÏžG=¼ïSÉä¿MÓ§o„„¼nÙÒF*• …"MM m-ÞÀnU@•©FÿMGǦr9íã{áÙ“£L‰T*:mÃ÷÷>™òäIÄ‘£—¶n™£XrO}Åò‰Ì{/ïsóìxûöã š«ûš4M9zI.§ ôuÌÌ œšÉåò“§®s8j|~¡Sëf¶¶ Ë4ÙµûԊ哆랟_øäIdAaQRRÆo³‡iiñ!EEÂC^éq8jmœ›×®mr* ȶEƒ¦M­¿ŒL&{=jdOæãê5‡23óX–˜˜²c§¿­mCs3ÃüAzzμ¹#)Š‹%žÑÐàÊårmmÍW¯ÞlÝ2·t‡gÿºãêbkmmabbpéÒ¹œ~ù*nÜØ>Ì~g™P³²ø³çlápÔ||/8;5kÖ¬¾@PìòšžžvNNþ÷.††zׯ?>4uÊ ×1ñZZ¼F6–—¯<$„LŸ6˜ËålÙzŒÇã®\1Y€H$>zìrHÈëûûù®fÒäÙ¿î´hÑ ÌeŸÞí’’2!sçŒàó :›’’9eòÀòëàߪìknØè›™™7yÒƒy ¶BV®: ¡Î:¤ë”É7nò{ý:ž©)•Êy]³ÖëT@!DCƒëã{1üeܘѽ-,Œ–¯ØO¡izÀ ….mZŒÝ;>>ùÀÁ³„gÏ¢*ßÕKOÏ9{ö¶ç®“ºLß´aö¬™C™ò™3†\zL©WÏÜÙ¹ùƒgšŒÞãÊÕG¡¡1„Í[ŽÊdò©S½{—$‰/§èóÜù»;vú¯^ãEa±XÑÑñ;<ý è8qBÿþVj«V&Nèß´‰ÕäIš5«/—ËöèÛ§ý°¡ÝÆŒî5tøÒââ’ž=]…%¢ËWví✙™koߨÂÂøÍ›&&µtuµ¸\µßfg(*îÚ}jÎÜm-š7ðõù½K'ÅžeLlB}ëÚeV‚®®Vóæõï—-°eóœ»÷^LŸ±ñÙ³¨oÞ¾5Hußפiz§çÉgÇ !ÎÎÍoß<(‘H=wâçÞ'„Påææ°{OsÕŠ {ú4wBHqq Óü·ÙÊ‹KîÝ MKËŽŒzG‰Œ|›ÈœPôX8†¦iBȞ݋*ÃÄÄÀݽ !¤‘å”ië_†b±X„O]QG“§aaadd¤O11®•––MILLéÑÃ…bd¤Ÿ\«–®¢þ œ›««ÿ½?׺uÓ€“ÃÃãSÞ¿O’ÉdÑÑñåC-íɓȢ"¡¹¹!DK‹gl¤áâý‘#zhò44¨cmmÁ\¦4jd5k½²²òx<õ† ëèèhBλ{âäµÕ«¦Ì›;²üòZÕ³ø””^~[ 555%<žúüy£D"±¯ßÅu|þ Ü\z…üûT÷}M©TVXXÌü_LQ§.—ˆÄŠËM9µÌ¬²×ã0WîBž<‰œ1k“©i­NnŽ2™œ’—W øŸ]UU…¹òEy=z¸DGÇGE½¯ð[žÆß=S‘ËiBˆûà./><}#&&ñ·ÙÃÊ7qÜ™I´Ÿ>¥OžºŽÏ/ìß¿›Í¢iºòPS²²òJ_vËá¨efæ2ïMŒ åêêÜÑ£zö9åê£>½Û1…nnö­ùú]ŒŽ®`YºuuŽˆx+—ËKV¸àb±Äÿäµ°°Ø¹¿@Ê€½êž5UUUºtiýüy4ó18ø•žžvkǦÑÑ•ˆxÛ³‡ !„¦iÅÞ˜¥¥óæ·¹[×ÿ1³Q#˼¼Bš¦oÜxÚ¸±•@P¬È.ÁÁ¯!ÏŸGgdä|.†RŠ¢tt4CÃb!ÌÞdå“÷ï[Ò»WÛcG×—Êd4M˜NŒô54¸„Í[ŽöíÓ¾S'G±X*Šòó°|¨\®s‰Óýa..-RR²¤R)äë˜ø.[WÆŒéî^Þç ‹˜3»„==í•+&oÜ0ëzГ™³6‡…Å–®ß¿GÇ&{ö–.|ò4ÂÞ¾±âcqqÉÞ}³foiØ ®¯Ïïݺ9qmÔtì5kÖTÍÈÞÞdJ_e*vì`¿kw€œ¦#"ÞŠÅ’Æëursܽ'@&“ݹ"ŠyŒ 9xèlTÔ{±X¢(EÖLNÎx-“Éó CCc9µ^=]šnÙzŒËQ»}'ÄÚÊÜĤÖÔéë95;;›ò£_¼xÿ¸ÿÕwï>BZ·nJQŸ/351ÈÈÌ=qâêýaÖÖ<žºç®“‘ïÔ¯Ÿ|ôØåìl~«–6:ÚšNmÆýëÎþ¾|ùÆÙ©Y~¾`ï¾Ó÷BaI‹ ˜$béÙ¿nëëé<|®¯¯Ó¯_‡.Ê„jh¨wôØeUUc#[Û†6 ëòúK.—=v¹oŸö]º8ݹâwäbZz¶…¹QíÚÆL纺ZÁ_NœÐßÀ@·ôÒq8j®.¶:9\¼ôÀÏžv:&„Š¢ú÷ëpãæ³[·žèk§¤d^¹úÈ­£³[\P ؽ'àôŸ·ú÷ë8mÚàºuM¿ñoàs|®©SpŸ?UþlÙ/âàðU3…åäðµ´x¥Rfgóµ´48µÊŠDâ‚‚"CC=©TÊf³™ ^hšÎÌÌ54ÔcNO~­ØØD‰DªHxŸ#‘HGYé绚ÇS—J¥—/?ºxéÁÑ#k>W_.—gdäëS%•ʘ£¯åC¥i:77_‘ÿhšÎÈÈ12Ò¯|Y||/Lž4 ’ "‘ø„ÿ5§ÖÍ—üBJJD‘‘ïtuµêׯ­èÿࡳíÛµTæ’ãoä4„†þ¬Î¾Cu¿H¡ÌN!¤ô•5•àpÔ Õ!**ÿ[XŠ¢J/ýZ×S¦š\.–ˆ˜§Ð©¨¨hkóÌÍ +©Ïb±LMk1ï',ˇJQTéµAQ”‰I­ÏõxúFJJV×.N;”ä8µòi•Ëå´nݬLáŒéî•wðoUcö5k¨ÌÌÜSA<žzQ‘°¶…ñÀnß¶wûôÄó( IDATͲ³ùA7žêפóި׀ê YªdM¨®ªû5´Õ²&€²5ÿçìÙÛ×®WuP}!kþO¿0_XI¿#srø¿,¨njÌ'¿À”É+¯píúã~};üš` ªîYS"‘®^sH(Þýã§ô·o?Κ9´¤Dtäèå‚‚¢¡Cº´lÙh§§?Ÿ/˜>mPhhlé™¶‚â?ÖÖÖæ¹´±½s7dÁüQb±ô¯swfϪày°©©Y[¶«_ßâ·ÙÃ}ý.ܼùlÕÊɱqâã“û÷ëиq½õ|.\¸ïêbk` 3vLŸ_¿* ÊU÷#´ªª*3g 9áM.§‡¸w‘ËéÃ>çMLj èßñT@3³c­Zº}û´ûø1½ÌL[ššcÇôöñ½`bb ¯¯SPP”‘‘s÷Þ‹ o¶133tqiG™4q@XxܳçÑCÜ»¸ºØz,ÞEY¹b²‰‰Á˜Ñ½‘2þ³ªû¾&!DSSC,–895#„˜˜ÄÆ&B7®×¤I½[·žwïÞF$’8:6•ÉdefÚb³Ùšš‰´I«&M¬˜ÞÎÝþ¹3–B45Õ[ÚÙ0#*ó”vø/¨îûš .óüXŠ¢ÓWÍœ>dÿÁ??~L«[Ç”T4ÓS­’§ÍUN1=Y™ ³rsóù•^4ÿV5#kV¨W/×èèxß ]º´&Í´u÷î‹2M‚âò…Êãr9b±äÕ«·ÈšÿMÕ=kJ$Ò­ÛŽåç ¼¼ÿЉI8áÞÓgQ½$„°Ùì)“êèh2OvíÞ­Íõ Ç7n<=áuÌèÞ6ú™˜ìÞ””î¹ë$3 åË—ofÌÚTáyÍOŸÒOžºþ2îÙ³¨€À ¤¤Œ}ûOú”¾go`JJÖ©€ BÈøq}üŽ\ yñúÇÏ5AÍ~­T*¥(ŠÍf3+œiëÇ*(p¹œÒ–Á‡çÐ@uU®ªDéÉ¿ÈgfÚú±´µ5F·P#T÷#´Õ²&€²5”…¬  ¬š}5Ð%««sØl6ó\¡Ÿ4ʶíÇ32rÇŒîuÂÿZƒµ§Mü“€Y“Bòó[¶µ³³¡(*/¯àåË7,ûb«M›¸îÜ A¯+%%s—§!ÄÖ¶¡Ç¢]ß1TdMBY¿ÁgÌèÞ-Z4 „|øzîü]¦ÜïÈÅþý:èVØ*==§¨Høë¢€ª†óš„›XPPļ·´4ëäæÈ¼¿výq%ؽËÃÎÎæ„ÕDuß×LOÏþ¶©4#"Þ%§dð4Ô_E¼]÷Ç ¹\¾c§ÿÔ)ƒtt*xLA—έÇMX½tÉøNnŽÖÖóç"„”™Póúõǧ‚¦Nô:&^K‹gmeá}øÜèQ½:ur¬p>NBHFFŽï.—ÃbQ¹¹óæŽüÕk~œê¾¯ùmSiæää{>7vLŸÁƒ;3S—ˆDâ»÷^|î©ë¿Í6~\ß }ëÛ °m9üýû$RnBÍž=]…%¢ËWví✙™ëìÜœÃQû””N>3'!dĨ=º»L›:øà¡³mœ[ŒÕë—¬3øYªû¾&ù¦©4išNü:p°GçNŽãÆö!„¨«s¯_Ýû¹!TTTV­œ¼rŤ·o?/¯ òþýO^#„Peccé¹s¡\.ÏÉÉW|[zBMcƒÏuR~>Ήúoßqâè±Ë–uÍÜܾmÙ ú¨Yók§Ò,((Ú±Óø°îG¬™4q@LLMÓAAOÄbI…ýŸ¿pO (fÞSU¯ž™¾¾6ùî 5Y,jÃúYCÜ»<°ìçÝ ¿LÍÈš_;•&EQ…_¸pÿîÝBa‰£cS¡P4y꺄„” ûg±XÇŽ_¹yóÙ›7ŦMÓ¥çéÝ«í‹Ð×\.‡ËåP÷µñSuèÀ²Í[Ž*æNYû‡÷£6¬«dðß|?öš5kªfdoo2¥¯2µ´x·n?#„H$’V-µuµ=}úfVVÞ»wŸnÜx²}Û¼ääŒÝ{^Ç$èêj5mjM騡•ç®Sjj*oƒn< ³³m¨§§Ýµû̾}Ú+®¯)#/¯ÀÇ÷üÙsw¢¢ÞËåòü|M]++‹ÜÜüëןˆDâ;wCºvuö?yí¯swÅbiÃutt4ƒƒ_yûœKJÎhÕ²ÑÅKο+•Ê6¬ë¹ëdȋזuM7®giiÖÈÆrÕï ôuøüÂí;N˜™þ¾j ‹Åzóæƒ2Á·kײò0~܆©|®©S«:€ Ô˜ù5ssóõô´÷„Å2™¼òl‘Í×ÓÓ„R©TWWK17ç7H¤|~¡¡áw=9V.—¿Ÿ”Ÿ/hÑ¢‡£Vyå ƒÿ!aÔ˜_ª«“5á?Yª«p^ š@ÖP²&€²5”…¬  ,dMe!k( Y@YUúôv§iU9:ÀWªÒ¬‰gA…ðs ª+¡P²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…§·(‹¢iºªcøÏKM%ÁÁdèЪŽ¾Gh««W‰¯oU_†¬YÕ„BâåEHDDU‡_€¬YÕ< Ó¦‘ ˆf¨î5«š§'qw'õ듼<’šZÕÑ@e5«TDqp zz„2n¹zµª€Ê kV)/¯ÿ]:Ûµ+ñò"Ba••AÖ¬:©©$/ØÚþý‘Í&Ó¦‘ª4&¨ ²fÕ¹z•Œ÷wwâéYEÑÀ—!kV™Œxy‘®]ÿQ¨§‡[Pª3<¨ŠOOâà@!4M¤R¢ªJ! DO8PµÑ@…5«H^Þÿ.üÉÌ$Çÿ}kfV%A@åªôéíÿezzßpÂPWG¦¨þp^@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP²&€²5”…¬  ,dMe!k( Y@YÈšÊBÖP–JU¿œƒ!„„†VP¨ðü9a³+«Pyó/Vxôˆ¨«#€_üMÓUÃ^j*Ù¿ŸlØð‹†sp ¡OÑXP•T«:€!¡P²&€²5”…¬ù߃‹Dþ ÚTuÿNÈšP–D")((`ÞËd²ª æ?K ˆD"æ=¶@õ;OàÂÂÂònÝÚËåfgç´jÕòæÍ[6¬«’`Ö®]wø°orò‡Ê«…††=z,8øÉøñcUUUA­ZcÇŽQUU%„®[·aݺµGù¡wîÜuíÚuSSS—6„ìììààÇcÇŽ6lè‚=~ùòÅw,Yehš <ò¢eK;©T*–hjò´µµð“F€¯‚¬ »téò¦M[îß¿Ã$š¦ÇŸ¤¥¥ùÍúùéß¿ŸÁ·5ÿý÷•{÷îÿb5{55ÕÇ}ç͛Ô,Xà1vì„€BˆX,NKK—J¥_•5,˜wëÖí&MϘ1)ùôéÓ¡CÞ***ü±ÆÎ®Ü‘ßG.—K¥R555BÈҥ˅BáîÝžEBŠŠŠœ×­[C)))ár¹?vhøZ8B „Âçó§L™¾wïnEv¡(jýúµßÓçµkAßs70EQ**Jýªc±XLŽaôèÑýôé?…B!!ÄÀÀàĉ£<ïkGg³ÙŠ>“““ëÔ©ciiIQ2$%I¥Ò'ü'MšOyòäé‘#ǶnݬšÇã­X±”yïåuxþü…oß¾ýÀ×¾æLFØeË>|”ŸŸogg[º°víÚÇ+ßÁùó²³³E"qÛ¶.vvv;wîÊÊÊjÕªå!î+WþNQÔ¸qcÿ¼p᢫«‹þرcÊ·òõõ»yóöªUËccãâãú÷ïÛ¸qcBHNNN`àŸÆÆF:::ŠïÞ½—œœÌãñ^½ŠX·î ¹<8øñ!îêêê„S§._¾ºk×}}ýÕ«× …Â#†üøñíÛw³fÍÐÕÕ%„„‡‡ß¼y›Ëå}üø©MçÚ+zËÈÈ üÓÃcÁÈ‘ÃË ”}äÈ1 óœœÜéÓ§&%%íØáikÛÂÆÆ&99¹¸¸xĈá÷îÝŠŠvttèÒ¥sé¶"‘èèÑã!!/FŒæçw˜I“gÏþÕ¢Eó2;”}úôNJJ"„ÌûŸÏ?xÐ+%%eÊ”I¶¶ÿØXð‹ÐPåRRèåËÝpöö4-.óÚ´i½MÃòåå_§OŸœ>} M‹%’bçââ|™¬dܸ1›7oÉJfÏž‘™™ÂÔ477ËÊJý\+š[[[>|¦ÅÞíÕ«M‹ùü,gçÖLqqQ\.‡¦ÅbqѰaCq–)**\E…}æL€ŸŸwݼ½Èå"Å·Ù$&¾¥iqRR‚þÓ§hZüÇ«·nÝÄŒhiYW")ÎËˬWϲ¸8¿  ‡¦Å½{÷ìß¿ï¾}»»wïºmÛfEo……¹uëÖa¢²·oõéSš º:lØÐа6mÚåååUò—jfffmmuéÒ• ¿ÕÐÐ`R bĺuë6jd³ÿÁM›¶lذN½ÌÕ ÑÑÑ™|غubbb]]ÿñ×È6Q|ÔÕÕ #„¤¥¥™šš~qÙ[µj9qâx6›Í„­èSñ^GGG.—‡„„Nžûú‰ŒŒ;vô¤I¿8"üX_s5Ðs¯ŸüBNÓ*,þí·Yzzº“'O7nŒ~hh˜¥¥¥µµu™j+W.Ÿ?¡—×a33ÓÜÜÜáÇ­X±ÊËëð‹O SSÓ† îá± ]»¶ãÇõó;ª¢¢âæÖ±L«qãÆ&%%íÛw`ñb={ö¥¤¤œ:0räˆÁƒ­_¿ÑÕÕåõë±X¼víºyóæ<|øèÂ…‹ÚÚÚB¡ÐÑñ7~„……{y¦izýúãǵ°°˜0aÜâÅËâãッs¹Ü?îÛw`Ó¦ [·nÏÏÏ÷ò:Ü®ëùó³³³= n×®íãÇOüýOq¹\mm­Y³f >lçÎ]¯^E…B护œœœ  fffR©tóæ­ÙÙÙ~~G&NœàçwxÁ‚Eýû÷MOOwvvúðáC@À鈈È7n²X¬ÐÐ0@`gg{éÒ‰D²qãæåËÿ¾VKKkÑ¢…B¡ÐÇÇÏÛÛgìØÑLÆ¥(êÔ©6lZ¶lÅСî2™<<ü¥›[&:䘘8yò¤ß~›õÃÿ.@JÎ&&.ÈšÿìŸûF&“½yóF(,iÞ¼Yé}¯2\.×ÖÖ®|œ‚‚.—«èGÉVb±¸¨¨HOO/%%E___]]]"‘”””…BCCÃÒ7™|NZZZBB¢“Së/Þ(âçw„Çã :„¢¨¬¬¬aÃFúúz׫Wï‹C0hšÎÌÌ444d±¾ñ‘Htâ„¿“SëæÍ›+ KJJ"#£tuuêׯ¯èùàA¯öíÛ6mÚT©~Úàщ?î<`³ÙMš4ùb5MM¥ž~P&A*ÙJMMI´æææL‰ªªªªªªâ:/255UæØ,!D$3O"„hii|ÕiBŠ¢˜k¾‡Ã™!yÙ’ þ'Ö_ºà¹dѸ¹ó·O™ºþsM”éöçáó sròE"Éç*”^VVþ'Ö³XTRR†ÿ‰õ§6^8·CGG³mûIgÎþýÓD*•eeåååþ¢øÉ~QÖüóÌ­CÞÍœ1¤C{E¡»{—‘#z|[‡/Bc„BQA€ù8rD[Û•7QQaÛXŸkø vìèÀf±Oß”J?û[á›ãü~ æÎ;۸q½JêT‹Åêѽ MÈ ÿ«L‰–ïCÂåÃÞ+p Uä¡ <}ƒÒ¯oû2åK—ŒWìÆñù…›6‰ÄEE%õê™-ò[T$=vU^^ÁnO[·Ÿ'$¤PñܹÇS·mÑP&—7m>´gO§ÖÍzöp º¶—éG (Þ²õ˜H$f±X‰té’ñ††z¥}ôèåÁCgEÅ={¸Î˜îý~ùÊýÆFË–Ž_õû¡† ëÄÆ&6hPgé’ñ<ž:ÓäÃÇÔ•«Èdò¬¬¼éÓ;84)³ 2™ìࡳQQï54¸R©lÅò‰&&µÊ¯‡œ¾L.oÚÔJEEE.—û¹ùNSS=7·`æŒ!-Zü#ñgfæ.Z¼;_`nftðÀ2™Læ>t‰ªªÊö­ó¶n;õnÎìá©iÙ))™ïã“6®ŸeccIILLÙéyRKK£¨¨¤N“ßfSSSýÛEýÔÔ¬„Ä”?ÖLŒz“;kÆÐ=\Äb‰ûÐŹ¹ûö,¶³³IHHþÜÚ¨ÄÓgQ„ý;2Oùø^hÚÄjïžÅOŸF®^ëÅ媭^55èÆ“—¯Þ8µn¶Èc¬b“1?ƒLMkegóÅb)r-TG´RD´½=- ýæ—Mú„ב~®‚¤ä™}«F½{µ•K^ÈÄ!®.¶¬™NKCoí'„LšÐ_Tü4ùã5BÈþ½K˜&^—«s9ŠY¾t- •‰CÚºÚ qïÂÔY8t}k‹¢‚`ZºmË\6‹Å”_½´‹rñÜZ**~Ú½›³¤äÙÎíóUØì¢‚`QñScƒysF(‚oig#ÈDKCÏžÞ¢Â5)T IDATf‡…øÓÒÐÏŽBÝ÷¡¥¡snd¨WÈHKC—-ßÉÍi;÷·á„óFíݽè5Ó[µläÖÑá]ÜyZº|é„ÚÆBÁcZzù‚§šªJÔ«À2Ýf¦ÝÒPçΞ9”émÔˆ®01S„8µn–òé:- ­omÁ,rZrž®³Š¤¢çŽMF表ßÚ±iòÇkÌYÖ5}xï0- 4¡¿™i-¦ÿG÷}Cnm”^´4Ô¶EE­X6qáüÑ­Z6Ò×Ó~öøhé-Û¹“cçNŽÌûË&jòÔwí\(—¼ð?¾Nñ'1{æP›†uå’üœû„ƒû—žØô=oe_ööÊý|Á/:BkiiJŠ™¡¡1 =</Ù½déE»nÞ|öâELXx\m ãÇ#ž<‰¬givãæSB—Ë!„tê䨦¦jl¬OIMÍb:™:ePVÆí×öý¾r²e]Ó›ÄÄ$„…Å?~å`ߘ©ãèØä}|òõëËÄÓ³§kK;› ›ühš>yêú¨‘=UTTfÏqúÉ“ˆ€Àêꜗ¯Þ(ê[Y™3{ZíÛ·’Êd¾~J÷&“ɼ¼ÏÕ«gþêÕÛààWµjéÞ»*ÿïì MÝÝ]FŽèñðþá»·Õ¯_[.—ïÙج™5³€ŽŽMÄ©—÷¹2qêM›:ÈÇ÷Bzzv\ÜmmÍ:uL!jjª,«Eóúff†„ccfµœð¿–Ç/dŸÍfÛ·j|2 ('‡ÏÔ·mÑÀÜ܈bbb ©©Ñ®]Kæ}jZ63—û¿k”*Ye¨ªª¬_7sû¶yG|W ÅkþøÇ<¬ÜR¿l¸\5A‘pˆ{Š¢Œþ·5ùüBMMuŠ¢ÔÕ9l«¤D_P¾¾ŽNÙ¶e(³6ÊhÑ¢AýúµoÜxš››_I5mí²[sÆtw™L¾hñ®I“ÿ>¬ÛÔ)ƒ”à×ûEYsÆt÷n]7n:›HQUUÑÔÔ`öÆ8U55UGǦuj›ddæ:;7wvnncS÷öç•tX\\²{o@IÉßçDUTØŽZË–6ŽŽM õââ>0å±qÔ¹œÎZ—ïaРNl,GY9 G‰Dºlù>÷Á]ÆíS»¶qFF.]êÐü|ó1<<ŽÒ¿_‡Ò]©©©öë×þÓ§ô–-mœ›·nÝôöºÒûG¹\N×®Noß~’Ëå„fµôûg· 33ÃIì?p†Íf׫g^IŸ„^=])BâÞ(?±i«zõÌ*oU^åk£úú:4!!!¯%éÅ‹÷•îå«7#†wŸ;g„çÎ…‡½Wjhp¿6`€_ƒ½fÍ%ªÉˆ·/™Ò÷›‡¡(jÄðnÜ¥ËöÞ½÷"<<Îÿäõ¬¬<;Û†ÖÖö­«©©vïæ|þ½k×?‰>ýç­1£{©©©Î™·íÓÇôÔ´¬®]œV¯ñ Ëã4il•“›ÿ>>)(è郇á†oÛ~bõïS:´·çrÕ:¹9ž ¸þôiäÍ[Ï¿<ìµ²U«F!!Ñ[·ÏÊÊËÏtëæÌ„¤§§uÿA˜¯Ïï***l6«¸¸äò•‡©©YŸD´iÓâò•G©©YÝ»·ñò>׳‡ëùó÷ž?ÚéyråòIcÇö),,š=gë‡iIÉé½zºöëÛ!!!åÀ¡3QQïýý¯µuµkÚÔzÊÔõ…óó ÓÒ³³²ø.ÿ¼ÿ²k§—/ßž¾òú؉+‹Ž?®¯@P\º[uu.!¤iS«½ûý¯30ÐeÚ.Yº'$$šÏ/´iX÷öç.ÞÏË+ÔÒÒ0À­aÃ:{÷ŽŽ~òÔu±Dzüè:eꟿp//¯@Cƒ[$(Þ³/07§ /¯ÀÅ¥…bèÑ£z–”ˆÊ¯ ==-Åj¬_ßbî¼í/_½‰$oß~20Щ[×´Nmã7ž¾{Ÿôòe\:&/BcþüófV¿vmã‚|ÁŽþ9ÙùYYyNNÍ.òLú”‘’šÕ£» —Ë>j¹ç®SÛ¶ß´ùÈ›O;vpÐ×ÿ?öî;¬‰¬køIB =tP”**UDŠØP@ì"X×ŽŠ½ëb÷U×®Xw±cÅ‚ T°`ADl€Þ Iæûcü²ÙЂR<¿ÇÇ'™Ü¹÷Ì$ädîÜ;£üÓŸ7aGÃ`ÆŒF« !ô£ˆv Á»îðüPýEÀb±33sÕÕUªw0—Ë­ªâž «Qy9“N—¥R©Åee̶mµ¨Ôÿ7WUq‚‘‘®»žª*Ž`W*TV²jkɬ$ÓXm‚`2Y :Tªc9`€sFFÎÆMGOÜ zµLf¥¬¬ŒÐ>ù uìÚp¹ÜŒŒ\ee²7»^§k·ñ3}½,òòŠÖo8dÞÙ¸1ÇÐ:øBll£Õ†ú5ëµH²²2uô4Òh4þi¹:ðOª©©¨©©T/ ” kS½XI¢î”  ¥¡½‹u¬’›[8jŒßý»'¯oÙ<·AÕÖªˆš2€F£‘C–DD¥Ry<¢¢¢ÒÜÜXFFúÛ·l6»ÊÜܨ¡í"„P3hcM$ºë×ƽJùcÜý–Ž¥ •—3¯\z÷î3‡Ã¡ÓåúõíÆ¿&_ãÀcM„P#Á¬‰~˜5Bï†B‰ ³&B!$*Ìš!„¨0k"„B¢Â¬‰B‰ ³&B!$ª†\åÀÁ·ÉÂ@!„$@C²&Î×D ð!„ öÐ"„B¢Â¬‰B‰ ³&B!$*Ìš!„¨0k¶rUUœ’’2ò1—ËmÙ`BHÒµÀý5oÜx¼bÕí[ç{xtç/LOÏ\´d·ž®ÆÁ~ ­pÏÞsW®FµÓ×qt´är¹ùùÅ£G¹wêdXcá†6”˜øñî½ç‹þ!z<•Ã<ww²ÒÔd¼|™Ìfsœœ,ó󋣟ğ=½IS“!X¸¬¬bá¢]ié÷"—;~åŽn?ðx<6»Š||íÚƒ¹ó·Ø¿|ú4Ï ã-\0îø‰kd+••¬mB!¾ÆÏšIIŸ>Ϊ»Œ”T ǸRR´Ÿn”J¥R(ò±žž¦±qÛKwko½®†X,öÝ{1ü§NNV[6ÏmP0dÖ$S(~`înŽÙÙ¢Ç#úáp8§ÏÜð™¶áÓ§oPTT:ÝwÓþ½ËeeeøalÚ8‹|õrúŒM÷ï¿hPJF!ÞC—2wþ6YY™£Ç®8:XXX˜$%}úú5ûSê7éi>Ãù)äSê·Ë—ï—´qq±ª'!áÃÝ{Ï54TåérÞÞ®p.è¶µ•©¹¹q½1äå}û–ã9Ü…ÿôD൶mµòó‹gúz &löˆÇ#^½N™4q°‘QÛììüåîKLüxôØ•öítÜÜ×­ÈÉ)üçïPVVqæìMC9?¿x¤·«¦&#**öä©°?Æ ((,ÉÏ/nÛFkÈ^;ñÓ• öíuUU•®]{ Ø"ùA@XØ#f%+7·pâ„AŠŠò‚+r8œÃGB•”äsr 'M¬¡¡Ê‰Åbž¼“4vLÿãÇÖ‘»÷áøââ2›‚•èëëŒÝ<<º÷ëg|þδé‡ë3xpOþ›‚B¨n|¬ikÛqê”aæ¦ù ·°0€%ËüeeeæÌõôiÂåË÷ù%32rFŒè;eòÐS§ÃBC#+IK˘1ó¯ysÇLœ08ìÆc²¯õٳĴ´Ì:šNLüx1äîÊU&MY÷âù©nÝÌ ªŠã1pî˜ÑîcÇx(*Êï?p^p•çÏßìò?3|xŸ©S† ó\ÚÚêkVOSSSžæ3ÜÍÍfÏyëv4ðx}úfkÛq¤·«›«ƒ»Çœª*ŽàŠóìTSSž0~çð>Ófl$–—3÷ì=7Á+KÓcG׺º:ð“ßÛä4½êô=zؤ¥¥&Œtäðj6»ÊgÚ†óÂq B‰¢ÉÇО<ñ?ss£ë×r¹¼„Äüå¶¶€B¡Œë±mÇIÁUO^×ÕÕˆŽ~«ªª ûö.<¸g YZšŒôvýkÓ sã¿6'>~ü:?¿øÓ§oQQ±p?ò…à*ööæAg7Çťį¾ýøñk™CAN>xò$¡¼œÙ¦())hk©]¹ŠŠtkë4MZZJFFª¼œYGµµ¨££®§§ ¦¦í(Ê=.b‹}äh(]N6**öË—ïäoˆË—¦OﮇV99Y µbdÔ&##‡Çã -/+«|J¥R½¼ú;ºVEYqààññïëˆ!„4iÖLKË€×·n tt´´´4ár…¿Ç€N—+((\RRRnÖ¡½££¥££åÖ-ó.+z£ eÐÀgÎÞ$sFII™®®YÕ˜Ñî—Cv þòåû´‹ŠJ‡ ëM£Q…Îó‘ñóåæ AÊÊÊääü8I©  ÇoÇ«ëdaÝ-’ètÙ‚ÂþS&“ÅárûöíFnŇw¡àâb×Õ¶ã±ãWß¼ùX½†Î6\./5õ?ñóx¼àóáB% ‚¸{÷yÈ¥{Þ^ýjuŒBˆ¯ñ³¦œœ 9’3êÁËÌÌÜ={ÏíÚ¹HS“QPPL¿3–LöêuÊÁ½k4°Ç‹Ø$99Y99Y …B]=þ&;;¿¶F ‚àg UU¥Â¢Ò´´Ì²² ++“oßr¸\Y[LÌÁµ¶n 2¸Wß¾ÝØl“É*..»ÿ…`ü‚…»w·ÊÈÈåp8dsIo?¹ö³¯woV[‹äÞ ‹UUqÒÓ³úôîÊ_EUUɹ»õë×ïÉMˆ} †òêUÓ6ÿ5çÖí'³çl}ù2Y°Q==Í­[æ-]¾G°é;wžºôù÷ü1Ç»z5ÊgÚ†œÜ€VLŸæ)##]ïæ „Ðo޶~ýzŠqáð1˜>D”55'¯KKKik©››‡G{ž˜˜øqó_s²²òvûŸ}ÿάC{WW‡‚‚â[·ž°Xì{÷cÜÜed¤gÌÜ$++cccV½Åý‚¯^{˜“S ¬¤Ð¹³‘ººJdd¬¬¬ô›¤ONŽV]m;ùï9K£R=~ejÒŽÉdñjÛV;äÒ]5†ÊÃGqjj*±±o pÖ×׎¸û ªªª¬,M6ýu,êÁKcã¶öfÚºÄãñO^2¸—««Ããǯ½üõ[¶m—Ž¡W"C¯D€swk))ZRÒ§3go†^‰LÿœÅdVÊÉÊèéiV±9Õ[€¯_¿–”º4wΨ.]:ž¿t‡É¬ìálÓßÝi·ÿY—Ÿð^ZZÊØøÇ"YYçîÖ}ûÚ]½öàøñ«j åvítÈ—ìíÍ9ξýÁ U¥²²Š[·Ÿhj2ºté'ø|¸ÿž³¦¦í–/ŸdmÕJmí»83f´t¡Ö€"Úô6ØuýNaA««ÿêY\\F¥R””ªª8‚œäi6¡ñ¢|UUœ¢¢R¡kˆˆÇã=þF__»m[m2žœœMMFõôÀãñ²³ ´µÕ( ‡Ãå‡WPPÌ`(W\JDvv¾––ÚOgšÚZ$ƒÔÒR«mDk~~‘’’BmG„,ûô™›ö––&ü…\.÷Ý»ÏL&ËÒÒ„¿bXØ#))ZÿþN¿ÑÐY_ˆmé B­A“dM„Ä fM„P#ií]s!„PãÁ¬‰B‰ ³&B!$*Ìš!„¨0k"„B¢Â¬‰B‰ ³&B!$*Ìš!„¨rMß& !„’ Éšxm $¡ðB¨‘`-B!$*Ìš!„¨0k"„B¢Â¬‰B‰ ³&B!$*Ìš!„¨0k"„B¢Â¬‰B‰ ³&B!$*Ìš!„¨0k"„B¢ñ:´Òx1O„B¿; A-úGŽ€¾>xxÀǰf 5lõÛ·Áß‚ƒÁhšøBèw‡=´â$$üýË…¸8øðnßnØê&&cÆ@ttSD‡B³¦Øˆ;;ðö†ˆˆŠ‚cÇ`õj`2Pƒ¼<ØÙAp0œ= ;w—Ûd±"„Ðo ³¦Øˆˆ€Q£`üxؽ>}kkØ´ 6mj@ ¤¦ƒû÷Ì›……M,Býž0kŠ.‚ƒÁÂètèÙ:tpsƒÔTøøQÔJètøð€Fƒ¥Ká?`̈oª˜Bè÷ƒYS<¼ycÆ ®IIÀå7š5 èkUWÿ·°³3ÃòåpäöÖ"„P£À¬)""ÀÍíÇãG`øp8~ÀÄŒŒ "BÔzìì ;ûß§ ܼ ¯^Á¼y˜8Bè×aÖLæîYò1LŸ‡ýx¼zu†1PQñïS."" &†mô¨Bè7„YS ÄůïîÙ¸8èÛètðõ…3gèô ²°ø÷È˃¼<8;C·n`bòò §Wm™™0t(˜š‚ŸX[ÃìÙàë ÖÖMº!ôûÀ¬)fæÏ‡Ù³¡cG€;aøðWüQa!<nn?úc33aʸy»gB¨Q`­˜QReåORŠˆÁøÏ)L==°³kÀ\„Bu¬)Ætuáë×_­dõjð÷oØ•ùBÕ³¦˜¼]‰¦&¤§ÿj…t:øøüŽ‹Bè×`Ö3ðã±¶6ÄÆ6B^^™™PBýÞ0kŠ1 òó§žµkáàÁF¨ !„~o˜5Å[ÿþsŒèì ©©x%w„úE˜5ÅŒ®.””üûTè y¿b×.غ¯F‹B¿³¦˜ÑÔüÏáOL>©ž^Ã.B¨Ìšâ­Q&Ÿð-] þþx¸‰B? ³¦xk”É'| x{ÿ¸B¡†Ã¬)f (,ü÷icM>á›:BBþÓB!‘aÖ3t:ÄÄüû”œ|Òˆ}ª4,Z;w6Z…!ô;Á¬)öú÷‡ììÆ¬ÐÃRSmBýN0kŠ=rs¹ÎaÍšF®!„~˜5Žý.¶naYYÜ„‰ Att#W‹B­fMñ#4 HWÞ¼iüVæÌ p B5fM±§©Ù$C^õôÀÛ.]jüšB¨õ¬)ö´µáÎ&©yüx8v o½‰B¢Ã¬)~zö„´´ŸÒh ®Þ$]©t:,Z›65~Í!ÔJaÖK¥¥ÿyjg×È“OøÜÜ 5o½‰B"¬) ò ‰F??X²¤I*G¡V³¦øQR^¢¯ßø“Oø¬­ÁÀ[o"„(0kŠCCxôè?KLLšdò ßêÕ°|9ÎBA¡zaÖ”òòM{½u==psÃ[o"„P½0kJ=½¦š|Â7g¬^³PB¨n˜5ÅеHM4ù„N‡M›ààÁ&l!„$fMñ#t³0RÓM>á#;iq BÕ³¦„hºÉ'|4lߎ=@¡:`Ö”M:ù„ÏÚ q BÕ³¦X25˜ÓÔ“Oøví‚­[q BÕ³¦X22ÔÔ“OøôôÀÈg¡ „P0kJˆf˜|·z5øûã,„ª³¦ähêÉ'|t:øøÀ™3ÍÑBIÌšbÉÚº†³Í0ù„ÏË BBp B Á¬)–”•k1Û “Oøh4X»/z€BB0kJŽæ™|Âçì ©©8 !„aÖ”Í6ù„oãFغµY[D!ñ†YS,YYÕ åå!5µYÃ01##¸}»YE!1†YS\UŸ©§WÃõi›ÚÒ¥àï=@!fM‰¢®ÞÜÓ( ðö†ãÇ›µQ„W˜5Å^ór;»fºB ©S!$¤ÚE!ñƒYS,15_ ÈÀÒÒš; -‚;›»]„?˜5%о>”–¶@»šŠ=@!ÌšÅÄ=j™¦ýü`É’–i!„ÄfMqejZÃÈUuõ;¿hm FFÝ2­#„xÀ¬)®ŒŒj¸ê,ƒÑ“OøæÌ p Bèw†YSÒT¿au³ÑÓoo¸t©eZG!1 ÕÒ "oX]ÛÔ”¦Ö¯Ïg*÷õ JË€’Òá÷!"Œ–¤ñaÖWäNôô„—[[CZZ Ë›‡œ\Uw»Ò¿þl™ÖBB#ü>1f4%ø|ëKœØC+®j»Ã‰²rËL>A¡†(Þ¶Š3ºõ] ³¦¤±²j±É'!$2Žy«Lœ˜5% ÞÊ>‚¡ÖªU&NÌšâÊľ~­ayËN>A¡†h}‰³¦¸’—‡ôôš_jÁÉ'!Ô@­,qbÖ”@ää„’­)qbÖ”@ää„’­&qbÖWzz[óK8ù!$ZGâĬ)Æòók^Ž“OB’©$NÌš'Ÿ „$–¤'N¼¢žSW¯y9N>A‰= ;zJ¸¹ÕzJŒaÖcvv™Yó%gÉÉ'-u w„ªS^ìízËÔŸVÅöÐJ&œ|‚B-³¦d²¶†„„–!„~;˜5ŘTTÔü’²2””4o4!„0kŠ3}}øø±æ—¬¬ >¾y£‘Teee,‹|Ìår¢†Ò’Ò_Y‰‰_ÿ$ü&pGÕ GI&:RS[:ˆæÿ2~í’µïz±/é_V/Z­£§³ýàvk>´÷ОÍ{^|z¡¨¨(b=7Bo\:w© ¿`ˆ×W˜_ÈPgLò$##S½ptTôúåëg.œé5ÎKÄ~ZYiÙÎ;Wl\!++[ýUÁ"7¡¸¨xç ‚ òsóííû¸õ!K¾M|ûàîQÞÜùõOÂ÷¬ï玟»vñZ/×^F&F¥%¥ù£'ŽîhÞ±za‡³fñšgžE¾ŠlÔí¨ÙµktyºÛ@·_¤Qþd~˜5%ƒ>´t FÄÁç.›ûs«[wµvìÎf±E)¼ÁoC%³róÞÍ ÊËË]í\Wl\Ñ 7úm<zRZZBχæçÖ|݉víÆLsóÊMÑkö]à{`ÇÕ3ÈsPÆ×Œˆ>s|È%~óüüæúí>¼»zaç>ÎöÝíÙl‘öÕ/b³ÙÙY٧Ƭ)¸QüM˜:{*¹âÐÞC?§~žä; ÊËÊórò%$ÇápÈß¿þIÐÑÕY¼jñß»þâ5¤›S7Èü–Ù×¶oØ£03¡ÂRRR~üúØôi” ©WQaQm¢D"⎪¬¬”““«­6›M£Ñh4Ú¯lˆÁZ1¦«[óÍÂH¦¦7Œ6%)åëçÚ·H4)‘þ2cžÄZ·}ù÷ ‹W-nP[A¼Ž}ÍápȧƒG VTV¬­°ˆ ’’ªá7kÝõP©Tþ@Ͼ=/]&¢±Bú9jêjÿœþGAA¡¶‚‘n‚ŒŒL—Á'ƒÉ§Ýœº­Ù²æƒáp8N_Xà³ ýS:4Ò'¡zäzmõ´uµÃÃÂk,Ùl{&NŸèý‡wm¯ÖIƒvTtTô¢é‹ÝTã‡-ãkÆâ‹Ï8×<¿ÒZkŠ1MÍZoFFÀdƒÑ|ñÔ.?/?èDn[ÝÂüÂÉ3''¾JŒ¸ÁªdÍY:'91ùþûÆV¶V~sýddeN=mçh×É¢“ÐZ_3þÞõ·¹µ¹nÝ’â’œï93Î$ÿ†#nrp£ IDATFäçæ«¨ªd~ËT×P€Ò’ÒÐàP†:£¸¨XKGË}»`<×C®w¶ê,ôëØ}°{Æ× òqRBÒƒ»Ô5Ôéòô¡ÞC££¢ƒO{ÿá]XPX˜_¨×V¯ÿþ ÅÖÁvÌÀ1ÓçMwê央¡>}ÞtrõG÷}ÏüJÊJCÿ3çìöµÛ±ÏbUªs—ÍMJHºtÙÂÆ¢“E§Œ¯éŸÒ¥e¤'L›ÀÿbzñäEEyÅ÷Ìïýô302Ú«BAVßíïÞ¾ëÑ·…Báñx!gCddeJŠJll-¬-‹ì ÈÍεîj=Ô{èõK×_Ǿöêñîí»¨ð¨%k–¼O~Ÿþ)}À°:u€²²²3!* •Âü¡#‡jhjœ9v&*{ô¬´¤4ãkÆôyÓ•jý\.÷åó—ü/ýmë¶åæäîügçç´Ïµ}®^¼šó=‡Ëåjjk&Ä%Ìÿs>ùy‹7bìˆ}Ç÷‘åå“P=òòòò¬Œ,ÇžŽžš¥¤¢Tɬ5aÙ3AŠçú˜4s’œœÜ¾mûää½ÿð®q몿‰üý`bf’õ-«¢¢bÄØ#''&wéÖ¥·kïï™ß÷mÛghbH~2££¢+++ã_ÆÛw·ïáÒ£¶Ýþ;ªŸG¿^ýz…‡.œ¶pàðîƒÝ½î9ºçÉÃ'~sýÌ­ÍÇMGoÕSÉñXSbõì)&“OªªªF{Œöãé5ÖKAQáÈþ#]ºu0lÀÐT*µ¬¬¬C§ã}Æ[ÛZ›:®£yÇ Ó&t²èT}­ö†íííNü}ÂÆÎÆk¬WxXøëØ×pdÿ‘ø—ñc&ñê‘•M6zxßak;ë!^Cœù5S(¤woßUï:SQUélÙ>§}^ýöú |tÔê8iÄ$fîß¹ëê­‘ãGŽ?2õcê™cg[ñêñ%틲ª2˜[™W”W 5|í’µ²²²>s|bŸÆ†]ãæp8ƒ<2væ3…ŽÂ«I.Ïü–têÈ©½[÷ý}êoؼz3]ž>|Ôð Ó'ìÙ¼'%)E°ª©³§^9…Üv+[+=;G»ñ>ãã_ÆÇ>‹6r˜½³ýº¥ë€ÇãMòœÔHÏÑž£&ŒòåSQQÁ/éâîbçd7És’]n¨÷Ð’â’Kg/€×8¯Ä׉•ÌJ8yèdB\¨ £ôÚêmZ¹©ÆLÎ÷œk!×þñÿdz¯çš-køÎSfO¹wëÔöIˆ~}áô…éó¦Þ¿}ኅª U(//ذrþÊÎV÷ÛÛÛµ7ÿ;½±> ¤ð°ð À ÃûoøsCÀÙ[{ÛïYß—Î\:nê8¯±^6ó§ÎlȺ«µn[Ýï>jëh«¨ªÈÊÉNŸ7½¶­«þ&’%Oœ413ñçzpçA·n“gNž3ièèétëÞ-þe<ùÞMñžâØÓqß‚óWd~þ£¨wGšÖ¶£@ZZzÔ„QþGüÙlöŸ¡çC÷ …Bqîí¼ûðî®]×,^spçÁ²Ò²ßýV5%–’dd´tÏ?/È/Hÿ”Nvõ<¾ÿxÖ¢Y–6–ë·¯Ÿ6zš÷Þc&q-E½¶zšZš ¥£••MÄ®»Âc€B¡ðÿ†Í­Ì}Fú 1ÈÅÝeÂô B•·7j_Qþï¤Ä׉î?*/+—‘‘=itp`°¶®vLt ¨¨ªDGF[ÛZ+(*tÐï@žž‘–‘®(¯PRVRSW;x€Ëå¾zñjËš-ü6ìügçøc‚ܺ:~¼ÏxÁÖ}ú®Z¸jâô‰d²§P(N P(w®ßár¹oÞñB–´²µyyùž}{žøçÄÚ­kù•Ô$¨k¨Ž|œ•ý6ám--òÐÙ´£é¢é‹"_ER©TWç—©þI€¯é_ÉØ4´4Ò?¥3Ôv9ìÂé ËÖ-›¹pfõ¶ë“@®ÞÛµ·sgÁúÏ;kcgCž´¶µ~x÷á÷Ìï‚=ùÞxo_¿=/7O^AÞ¸ƒ±²Šr[WÛ›¨ ¨ £§£¥­Eîðví¨Tª*C•Ÿ“ø;J¥>ˆŸ›ÿ2^FF&õCª^Ûÿ\V¬Þ•ñEøû„ ˆòòrÁkT*•ü©zÿÎý1Ǭ۾N¨cÃÆÎÆÆÎ&%)eÞ”yƒG n†ÁhÍ5ضv]e ÅdòIiI©¶®vWÇ®]»zŽñ ¼H.ïåÚ‹B¡IQÈç´Ïµ­Åÿ û¬8NaA!ÿk‹¯g¿ž§®œb¨1Ö-]·wë^¡W]Ü]b¢cx<ùÔÒÆrÖ¢Y§œn£ßFGW§´¤ÔÄÌ„lzÍÖ5¾ }klšËå^:w h4š£ÝÁ“Ÿ?~ù¹ùü^8Y™Üœ\¡Ömím«ØUñqññqñÖ]­ èDо­ûº:vílٹơürt¹¢‚"¡½ZcÕ•—•³*Yu‡4nê¸ËA—KŠKx<žà˜[r“ÉíÚ4¡ªø%÷Á>ËõâÉ‹e³–iëj÷ìÛ³ÞI ý<ú%¿I~›Xsrz;Àc¨ÇÛ„·—Î]:êüê-«ÉW{¸ô°îj}öØÙä7ÉÕ+i”OB› ´Ç¤e¤…v>N9~äé#§ÃÃÂûþ·³W¨‰:ÞDÁ’üÇÕ÷|EEÅúeëÜ}à:ÐU[W»úίwG½‰#´±Éo’“… ñàîƒë!ׇx!{õ…¼O~êð©N–ú¸÷©þj+€YSŒÑhu ”e0Ädò‰½³}æ·L.—+'''''çøÁã'CO&Ä%§v@NN®Š]ÑQÑ5®U´´t¯~½’â“ȧ%Å%äx„=›÷´m×vኅ/"^>)´Ö€a:Zt ØÀ_ÂãñX•,YpäöêÅ+²] …’WsG7A—Î]â ËÓÉ}ù_ôIñI®\…V¤P(“gMöÿË_EU¾g~?´çІ]445 ‚¸zƒ,É? J|•è>ø?§fk ’ ˆêÃ1Tª]ì»ð¿ k ‰¡Æpè6wò\—þ.5n,©[÷nYYä(‚ Þ%½ëíÚ»ŽòÕ­˜·b妕¦M‹ ‹‚¸ç~ůÔ!¸  EYE™ìŸüžõ½ÞÊ?§}^¸raÿ!ý·îßêÔÓ‰\¨ÊP]²zÉêÍ«ïݺ·lö2²»’¯Q> Õ#çü0äçåÓh4³ÎfBe¦ÌšròÐɲҲ:ÎòŠò&ÖíÖÕ[\.w´ t:]ècÆo¢îÕ¥[—Ãû .|ñäù³Äãñn]½µÀgA^NÞ΀§Ošõ”ð*aùœå·®ÞòÛà·|Ýrþ)çV†¶~ýú–ŽÕîða˜1£æ—¤¥aëÖZ_m"¥¥ÜOÙýþ3Ð@^^¾³eçÿ*úìÑ3#S£wIïL]@¥Q{.).Y¹`%—ËíbßEKW+(0HJZJS[³³eg¡µ*Ê+üÞÄ¿125Jû”TW`ik9ÈsP€€´ŒtR|ÒýÛ÷ããâ-m,“ß$LùÈápÝäÔÓIèÜ…B0|@äÈûwî3Ô9ßsn]¹Õ­{7=#S##ƒÂ‚Â{·î±X¬‡÷övëwúð錯V¶V7CoÞ ½ vNvge³ØA=ptîò¹jêj=®œ¿’—›÷éçÈ;‘ëw®/È/Øø:ÑÄ̤½Q{013Ùµa×FÿÒÒÒ²r²‘á‘l;=5]AQ!âf„qc«.V±Oc©TjIQIØ¥°6úmÆM÷íË7~=½]{ yïÖ½ó§Î|ÿ‘B¥XÙZ ÁíÑ·Ç¡½‡x\ÞÃ{™LæÜes_<}qòÐÉŒ/Ö]­Õ4Ô mû¶¯^¼3ñGoù¥ K¡Á¡L&³“E§ÿ€O^èµÕëæÔÍÄÌ$0 Çã÷Ò¿·ko~Is+óÿ€§žê¶Ñåò¸ÇûœúÙÌÜìÙãg—ƒ.³Ùlw—ŒoqÏã¸\nIqÉëØ×2²2ƦÆþ?6êmâÛó§Î§~H[{[ …R\Tœ—¨¥«•—wáô…è¨hcyù? mõÛŽòr6$0 ðÞí{ƦÆ:z:äæÈÈÊØ;Û÷ìÛóÖÕ[玟SUSmÛ®mc}Úµ ŒŠˆb±XZdÍ$#S£¬oYÏ?+.*>yèäÚ­kµuµwoÚýøþc--²\EUåÙãg㦎SSW€/é_jܺÁ^ƒ…ÞįŸ¿òK~Nû|îĹœï9V¶VAAQáQTU¿½~À„$Ë.–†&†N]P×Ty£©­ùðÞC+[«ËA—#©gG y'2*"Š¡ÎÈÊÈ  wvq&»‘9Nhph€€‘©Ñ¼åóÌ­ÍÉNu¾çÑÏwoÚÍd2çÿ9¿gßž²r5ÌAªNþð™æþk ”Ú†­#±`gW×tfφ¿þjÖa´™™¬ƒ»Kÿò«þ A¹9¹šBNÕ‹’_¢¯ùyùª Õò²r‡£¢ªÂãñ¤¤¤²2²4´4jœæOª¬¬LNLVTR4î`,ÔDUUUqQ±†¦F–—(*)&¿I®(¯°°±XVVÆãòÈÓT5b±X‚óKŠK¨Tª¢’bUU•`Ÿ^A~’²’à’†É—Ÿ—¯¨¤Xã¤IHJHªdVvuèZo=AädçhjiÖû¦ÔˆÅb•–”jhjp8&8زFï“ßWUU™[™×[ó’™Kø-hgÐŽ ˆ)æLšQcN_èêЕ~ù“P·ªªª¢Â" MÚ6öôÑÓ¦ Ÿ}¯QÝob½rsrUTUddd„>f5ªmG½Mx«¬ªldbÄßQwÂîHIIõíß·Æ üøîã“OFOÝа5ì<$ñNa˜5ÅÛªU°ti­yqÕ*˜3§æ[‰5‘Ú³&[º¸uõü©ó"~q‹­ySæ-ð[@ö+ded­˜¿"ðR`KU—ËÁ—¿g|ïíÖ›YÁ´s´képÄŽ„fMC+öꘔIN>iά‰$ПÿûózÈõçJ–;/»%%%E¡P _\IÜôví}ÿöýœï9.îuNF’³¦$›É'Hœñ/ô*édeeÇM×ÒQ4€º†úÈñ#[: ÔÈp ­x«ûœ¥ØL>A¡ßfMñfaQ×€Äfò Bý&0kJ2:]ï|‚B’ ³¦„³·—¸;Ÿ „ä¬)Þtu¡¤¤® 0™Í Býî0kŠ7MÍzÆûˆÍOBèw€YSÂ))Õs0ŠB¨ñ`Ö”p8ù!„šfMñVïÜœ|‚Bͳ¦x«wn N>A¡f„YSòÙÛCffKB¿Ìš’Á€ÿÞø!„PÁ¬)öìí뙑ٳ'|üØ\Ñ „Ðo ³¦Øc0ê¹ú’|ýÚ\Ñ „Ðo ³¦ä34„ôô–!„~ ˜5%ƒ!‰÷CG!I„YSìõì iiu Ó!?¿¹¢A¡ßšTK€DPZZOþý!3ôôš!ڧϲ·#›¡!„C˜5[…f›|Â`HMöQjÜ:³³áâE˜;·qkE‰»M›Z:‚ŸYSì))Õ¬ia?‚‰I“C§ƒ‡GãWûþ=4IÍ!Ô¨ð¼¦Ø34„Gê)£«+Ù“OæÌàr[:„ªfÍVASS²'Ÿèé·7\ºÔÒq „P=0k¶ ÚÚ?ùdüx8v¬ž« !„PKì)öê½6Ðh?ù„N‡E‹$ttBè÷YSìÑéS1rò‰DssƒÔT‰ß „P«†Y³µhw>¡ÑÀÏ–,ié8B¨V˜5[ rò‰¤³¶##ˆŽné8B¨f˜5%A½7 ÉŸ|Â7glØ€³PBâ ³¦$e@¤O>áÓÓ77ˆˆhé8B¨˜5[‹V0ù„oÎX½g¡ „Ä^Q¯µh“OøètØ´ „¥K[:Ifgûô¿ þó´îWë-ðè>Ðéuxö¤¤ê* é4z„?@kù¹,!(A´t ¨>.€™X[×SlÕ*˜3§yî|Òä¸\8Nœh%›Ó"ìì„¿pQë$ÝÒü^°‡V(+CVVýÅZÁä> ¶oÇ‹ „Ä fÍV¤uL>á#­ãã[:„úfÍVDWÞ¼ié ÕêÕ°u+ÎBA‰Ìš’ÀÊJ¤t¨©YÿÉ¢§FF8 å'á ‘ßAõÁA¨‰aÖ”¢¤Cmm¸s§éCi^«Wƒ¿?ÎBi eee,‹|ÌÅúRTTDî|| $Ψ  ÐЦi4YgIIIII‰§çð¼¼<1$mÞ¼uñâ¥d´;wîVUUõòÁ/`nnþÇãÈLJY´hÉû÷ï1Ôˆ°‡¶u±°€¬¬ú¯‡ qœáÀˆo…›ÖtjºÊAHÈ%++K999Á…ƒúZíÒÿçðá£JJŠ99¹“&M`³Ù'Ož...5Ê[SSóÀ¿'Nœ°víúÄÄ7Gkß¾½››«ÐZ***ëÖýÉdŽ;æóçÏïߘ3g–ªª*äçç_ÐÖÖRQQ![$âìÙsÒÒÒ<¯°°höì™uoßãÇÑ#GzÓét8w.èúõ{ö쪨¨ØµËßÚÚªM›6ÅÅÅß¿g/\8ŸÌ‹/†|ÿžÍårµµµââ^ýùç2 ~m·oß122²³ë:fÌh¡†îÞ½¯¡¡.//ïííõàäÉÓ&üÁf³SSÓÌÌ:¤¤¼‹Ž~2uêdcccÁusrrü§¨¨hÖ,ߎ;’ /^¼4b„pø¬Y¾òòò°`Á¼¢¢¢þ9”‘‘1}ºuÝŸùgêÞK¨ñµôÁ.ˆý0>;v4q(-äÃb̘–B¢tíZ½C¯7_ßi¢týÍš5#(è4A°?}J6lA° s,--ž={œýmÁ‚¹lv9A°?|xknÞ¹Žµ¾~MUWW{úôA°7lXGvçå::Úçäd;%%QNN– ØEîÚµì8ݲeSõ㤤h/?~ØÃÃýðá¿ùýÌÁîØÑ,-í=A°OŸ>accý Ø}ûö‰‰yB쨨»C† "öµk—'NŸŸÿÃa[AA~ٲŻvm73ëðâÅS~mׯ‡’=´©©ïº‘;iÒ„—/ŸÛÇgÊĉã9&›]®££}ùò²SwìØÑü¾~Mõó[¶té"2*¡nar/Õý¯¬¬p÷î¾¾ÓȽWû?Ô¬ðXSB˜šŠ4ÌG^¾µM>á31ùqëMgç–E‚~ù"|XIDyy¹¢¢" ‹Å:räXÿþîQQ .ª^»vÙËkôÈ‘^»ví Uû4Ö¸–¢¢"›Ívp°íää8{6ÈÌÌLSSÌÌÌÈ!<íÛ·ûã‰oß&»¸ô^°`^ñÓh4oo/èßßÝÉ©§«k?CCCò%~÷¬¢¢bÛ¶m´´´@GG'++ ÒÓÓÛ´Ñ--­OŸ>©©©ñë1ÂÓÑÑÁÄäÇ1bzzºÿÕÀÀSºººÑÑO@UU%2ò­­­¢¢‚¾¾>F£Ñh222¶¶] M›6ß¿'×Z½zmQQѪU+tuu…6B¡~û–!´¼¼¼\^^^° ZAAaÑ¢,ëØ±7þuáBPC» QSÀ¬Y6Øuoé88ˆZ²õÍ?ákÅ›Ö,ÜÝÝæÍ[Èãñ¨ÔÇ4¼y󦬬ÜÉÉ‘¿„Édr8ܾ}]Ȫ>$“ËÛ·oïîîzïÞý¥K Õœ––Æ`0j\‹Ÿ ( Ç€œœee%¡ÔÔÔž={|õêõ³gƒNž<~«Ž ÑÓÓ366ºv-¬ÆüÊÏ.ü‡røðÑsç‚¢£ŸlÙòWõUú÷w'nݺ3k–/yII‰™YGGptt 7M¨ ò1¿-˜4iÂßž3g™¿¹»»¾~-|Ñ«óç/Lœ8Aè|*›Í>sæìË—q ÌÔ)&0kÖçù¡–Ž¡Ÿâà[}Ù°aCO:³oß… çó>yòlÊ”I‚ÅTUU^¿ŽïÙ³DG?qvîgΜ6mªŠŠÊŠ«vìØrrrl6¢¢L™2¹Æµªsww[¹r5ù¸¼¼¼ªª ""î***Μ9cæÌJíðÿ§“ƒŒ} YYYÕ鄤¥¥­\é׫WÏ1cF V˯<ÞÍËËûòå‹àŠƒ ܲey&˜ÅbÅŽêÖÍ®î¶ÀÔÔÔß×çÏŸwìØ%%%5wîì6mÚð_ݰa}×®/^Äò«b±XW0eVTT;v"!!qâÄñ>>Sëm5Úúõë[:±Å…ÃÇ`ú–¡Ÿ2}Pµ…–Q(”aÆ޹qW]]-##3,즋KïêÇC..}vïÞËãqãã㥥¥)X²dùùóW®ôSUU™6Í7??¿CÓvíÚEDÜ ªªªlm»­Õ®þ_m‰Šz ©©)/Oß·ïàû÷ï;v4ëÑù´´,"â.—Ë ¿{óæ-‚ ôôtCC¯ÊÉÉ%$$hjj ûÀË—qÿ}èõë× ÅÈÈPYYY^^þäÉÓôŒŒz÷î]PP0›ÍîÐÁÔß_||‚©©É§OŸOåååÛÚÚèëë{x >{6( àðíÛwLMM`Ïž}ááw¥¤hß¾eÄļ¸zõÚܹ  ­­µ{÷ÞׯãÍÌ:¸ºö+((¸uë6‹Åºwï¾››kL̋Ç}ýúÕÖÖæêÕk—/_áp8d»11/ ÚwêÔ‰ŒYUUÕÝÝÍܼóÁƒÿܺuÛÔÔ„œŽ)++;r¤×öí»¾}û¦¤¤˜xï^ä¸qcÈÌ]RR²wïþóç/ 6Ô×wzûöíêz—íœ`ÆŒ_úœ Â;…Õ vÝñXI0šUm¯TVV&$$ªªª˜˜˜Ò ÊÏÏWRR’‘‘©»‚‚ƒÁ?''âZl6»¼¼œÁ`ddd¨©©IIIIIIåææÒét%%áþÛeee¥¦¦98Ø×;QdæÌÙ~~Ë ‚HII™4ijLLn£VUUUTTDžˆý9yyy‡]¸p>9P–TXXøöm²‘‘¡à±ò?ÿêÕ«‡¹¹¹HõÚ9ᥛöÐ"ô;’““³·ïVo1uuuQj\#úZ222df콬~Ô[]]ÝzûfI,›¼| …BQVVÖ××½––þ•” +W Ï‹e0Õ;±Ϫ"1„Y!Ôú~Ù´a¶¥¥I…KKË^œœvýª¿““•è­„†Fþ¹bŸŠŠâ‹ç§…^š=gë¥Ë÷–.™°léÄ×Ú^f%«´´ÂƺÒÅãµµÕkk±Þj›Î«W)Þ£þܾu¾—W¿ íFŸiÞ½ÿüý{¾¹¹‘¢‚|³’B‘Þ®£G¹S©?~ûÎðÝô69íAäaÖŒ›‚Ðï³fë´tÉc}Oï¥Ó|†ûý9ÒÒ2¬»Œ={îÖó§'¥¥ð¾óx¼á#–ìÚ±hÈ^’’ÞÍaw·¶òJJ ;¶-pê1…Ëå5(fOO—7?Ž~]ý¥û—Ÿ¼Æb±k[·úöfgç[Z¾výa\ìYyy¹ת·Ú¦SQQ™—WTVά­€Ðnsj£££%\¾|ßkÔò'Oöï[N®’›WTPPÌã˜4j:ØCû»04lÓ©“á«×ï?6hÅÜÜ¿•O;v4˜|øÒÑÌ cGrIQQé–­'X,vyy¥¡¡Þ²¥¥¥¥˜ÌÊ;O§¥e¨ª*”ìÚ¹HKKMWGcÒ”õÇO\ëálÓ»—í¶­óåäd€Çã?q-!ტ"½  dö¬‘VV¦‚æä,[¾·°¨¤mí¿úq¹ÜQcüh4Ú¦³÷ì9§ªª˜]@¥RW­œj` G®RQQ¹eë &“•‘‘ãææ0z”{õ }çÎÓóÂ54Tsr çÍݵk§êÛKDvvŒ´”©i;xðàePðuu•‚‚’þîNÆõªvÙò=ïÞ¦ËÉîÞµ¸M­•«¤¼KŸ9Ãûó—¬sA·{õìbaa’’’þ<æÍ,_ïAƒz@YYŶí'Y,6•J­ªâøý9YS“ñôiºÿ’““Y·fÆ­ÛÑII©66&M|ôØ•ôô,))šÿîÅtºœßŠýOŸ%Lš8xê”a••¬ÅKükÜuxú4<‡»ÿ~¹ß¾òræã‡ÇŠŠJÇO\SXX²×iÄÝç©© øï^¢ @'âØñ«¯_¿“––¢R©òòr¾¼¶OQQ^”OB³f+w'üiYYÅÇ_ï„?õÑoÿ¾etºp8W÷Y::ׯúÑ«Ït.—·z•§×ÒœœÂçOO¦¥e˜uö:¤——W¿ ÛÆþ±êÁøãþÚrܥݭûdeeÖ¬ýçô™›ïS.ËÉɆ…=êæ0áå‹3ÿžïÔÒRÛ¹ca{ÃÁ3}½€F£)*Èÿo½oaaÉ?‡B"ntuuðµÜÓké«—çÈUòòŠFr32j›‘‘cl:,7·pÞÜ1‚[tåJ”§÷ÒÏNÙÙuæê>+=5LEåÇÉÚ'Oã<Ïd²G¿f³«®†îÖÕÕÖàܤ„ ;åæê·x`ÿŸÓ|† V»}ÛÇî“™L–®®´i£emÝÁÝÝNž <x|ýšÕÓ¦ÏØ4Åg}vVAÍ×ÕÕ¸¼–.ÛӽǔøWÁNNVöÝÌ÷î êëÒmÕJŸóÂÇþ±*==k99úƒºví4}šç¦³”z¸¹:@rrZm{£º€C—®]û2ùáøÃ«ø[amÝ¡g›õÿ; ªªJ çuó˜pèÒßýrs Û¶hcc6{ÖÈË—ïO÷Ý”ùõ¶ŽŽz×nãm»tœ>ÍSVVæ×>eýF°‡¶•ëïî´iãì³g6 ØãDàµW¯Þ‘Ë_¼xû2.E¿­vttü“' †zwŸ~üøõNø3—>vÒÒR:´OûxÍÓÓºw·Nýxõù“À];vw²ŠŒŠ=xÇãíÛlaa,'' ݺufWq¾,€¦&ÃwƈC‡/“»²²Òz66fï“/+))œ º]^Î|ÿž_^^^ÎȨ-´i£elÜ6àÐ%¡ ÿ9"+#Íd²?~M£Q‹ŠË^¼Hú·9 †GÿîžÃ]N[—òö’‡GwØ»?Hž.ש“!¡a›½û‚„ª¥P(«VLM|ó1,ì›]vãÑHoWò%99YYi;ÐÖVËÍ+âr¹/_&?Ž~m÷ÿ‡¹ÝºuþøéÛ­[Ñdù²r樑n EG[\ûÙËÈHëè¨@FFHIIñ»RëØÕÍôõÚü×ÜóA[ Û¬YûOII9ÿ%ò|Ü·o7imm5ÈÌÌ€¢âRPT¤S(EEz^~Ñ„ñƒ°S!ÑaÖü-Ðh´aÃúðâbÈ]r 9†F£JIѤ¤hsf:zxMEE%¹,c` G¥R?ÎZ±òF³··X¼hü£G--LRRÒÙ쪊ŠJ~arÜfQQiõÖ—.™Àápöî Ú¹ë49Z522¶Oß·nGÛvéheiZ}’ªªRyµñ2,›B¡a+(П>>AŽŽ!1Ê&&ú&&újj*ü>Øââ2*õßþXZcœƒ÷´´0Ù´ùØé37þ7€?6”•„ —ñ·hT*üNª¾ ÿP¸F"î A †r_»ìœ‚¨¨ºn¬¬$ö¸±6Ö-Þ½pÑNii©ÛˆÒBˆ³æïB¡ OŸ%@xø33³öíôu²s --ÍÌÚß½÷¼S'Cã¶OŸ%’L>|ør·ªŠxò:y„dÆrt´”““ussxÿþ Ç€ää4:´wõ¦Û´Ñš~N¾ryùv „DG[¿~}KÇ ¶¸pøLÒÒaüŒ]»Ïœ9{3ã[NAaqrršGÿîúúÚÉ)iQQ/ed¤®^‹š:e˜G§Ð+‘7oF?ysþBÄ„ñuu5ÝÝoßyrábDlìÛ¨/}}½***ÃnïjÛéNøÓ¸¸”¿¶ïëÒmë–ùÒÒR+Vxö,17¯ÈÂÜx„g_yºì¶§Þ¼ùz%’Åb{zºìö?KnoqIY\\ŠPRtt´àqy{÷%%}Úð¼K»m[çËÈH VÛ®tìhpþBÄ‚ùcíºv&×=xíâÅ»EEetºl%“µwPA~IaaÉða}úºt;tëéÓ„ðˆg¿:rhµ­mǧOví>“ŸWœ›[èà`±x©ÿ—/ß32sÝ\V¯ùçÕ«w…%;ºD6íÜÝÚРMõ½Ñ«§í’eþüÝ8Á·⊠K¿eä”—3»vídÖ¡}ÄÝç/bßVUqÞø¢ª¢¸}ç©ÜÜB°¶2¿pÇ—Ïß3³rÝ\Ö­?—RXTÒ¹“Q§N†óìØº=p×î3[¶ž9sÓĸmëÉGÃ`ÆŒ–µr¼ÎKíØ`מjé0SQQiQQi»v:üîG.—[UÅ<%UU‡C&<.—ËbUÉËË•—3sr Ú´Ñ’‘‘,L“ɪmN¤`BçÏ*+Y²²25Nba2+åädëžßRQQI§×SFHy9S^^®ÆU"#cMLÚêèh 4ïfØ>¡m¬CU‡ ÑËצ޽Q‚ ²³óyôJdï^]ɱ²­—˽wïÅÓg lv•JµíÒqР¿~ ,.ðX5=ÌšuÀ¬‰DÁ¬‰šŽ¡E!„D…Y!„fM„BHT˜5B!QaÖD!„D…Y!„^å >¾-B!qY³>8_!I¿qQÓÃZ„BHT˜5B!QaÖD!„D…Y!„fM±Àb±KJÊÈ••¬–Õª¬¬‚Åb“¹\nË#ÎpG¡Ö Çж°òræšµÿ´o¯«®®r"𚅹ɛ¤=œ»¤¥eØØtàp¸áÏúô@OHø`aa²dñx¡öî Ú¼åø§Wåù ÓÓ3-Ù­§«qð€_ƒâÉÊÊ;~âêÅ»ýÝÚµÓáp¸••¬i>ÃÕÕUk,»ÜoßÂãÆõ¥þÄÄwï=_´ðÑCzú4a˶ÎÝ­åoßyblÔÖØ¸mZZf^^Ñ©“„ ''§-Z²«›ùÆ ³ø 9Îâ%þ¿zõòœèí ""øü˜˜¤.]Ì8.“ÉRT”WVRðôt±þŽuíç`bÒ¶¤¤3|X''+¸ví“ó”—/Î())T/ß§]w'+6»ª¶ ‚عëô²¥ɧee99… éÝûÏkVMëÖÍŽŸ¸6j¤Û„ñƒ‚˜=gkõÂ:z{¹¦¤¤ .”’’Úð¿™6¶cÔ.Çãp¸ä½'ýVìg2Y{÷,¥P(P^δ³Ÿ°ñ3E¯¿c½Fô%wì·oÙ¶v±·7¯±7û×÷‡Ã9}æ†Ï´ Ÿ>}€'OâO^Û¾m>Ÿ((ÐW­œÚ ­ îØ¶mµuu5Ân<®±ä¯¼} 5}šçãÔöj‘4hG:|yÑâ]ïß®±ª¯_³gøþu"ðZ¿Àx¬Ù8ÒÓ3Ï_oß^— ˆž}eeeRS¿…G}ýšý)õ›ŒŒô4Ÿáü¯§'OÊË™™Y¹<ºµZ1442/¿ˆÅb÷p¶±±1ãñx»vŸ™1}Äÿ±wßaM$mÀ' „Þ¤7©vzWäÁ‚X öÞ°—Sïôì½bAE¬XP*½+UŠÔÐ[ê~ì]¾\1‚ïïññ ›ÙÙiÉ›ÝIdd$¿YµèèäþýúZYý·¸ªÀ™’ÅbG²XXbRÖ¼¹tu5²V¯=,"B¾âóÐÆÚÀÀ@ÿÏÝ+*j.œßŽjÛD>W†…ÅîÚ¹83« 7·ØuâˆAƒtÚkiSGÕ×7††ÆÔ74•¯Y=ƒ}6ÜØØ|÷ÞK:Áb±fÍt&ÿõé°ªªÖ×ﱆ†…R·|ÙTΨO¥Òü®=ùð!}¦»ÓUŸ?ñæ½wÿ•‘Q?®ó¤ ã튊Êy¶ ÏZ´-SSKII¥Ýp„Ðë׿–V"„¤¥$&NÁ™ìñãˆØ÷©²²R[6ÏKL̺s÷¥žºšâµëÁ³g­®©§Pê4Ô•\\~ûàf@ˆˆ¹¶¶ÁÚÊÀظxxܵëÁsÆÓhô¼ü’ýµttÔ²² ¢ß%/\ધ§ñõkåá#×ôõ5Ö¬voÛƒíŠïh(ϵ3kk.\¼WRR±dñdcãþœÉôô4®\ÞõömÂê5‡û/\0QLL´½£Ðà\³ P(µ.®ë—/›æ>ÃÉïZpxx|iiÕò•.péîlb<`á¢=¡üü’¥Ë÷¯Yí>×cBðÓ¨„„,{{‹þý´F9X-^4iñ¢Ix 45(++Åó@rrÒ7Ÿ!¯Zé“òàÁköS còdûó'ÎöØÉyn‡ºs÷EØ‹Ø%‹'/_6uÕšÃ--­T*íõ›µµ |*õúÍÇÀÛ¡ í¹ÿàUJR ^¤¶UàÜåýû´ã'oLš4ráW×ÉBff.p2Xwñ¢Iú¡•+¦‡m´í0ãM[N!„Úk )) Ÿ«³<æŒ×ÐPú}‡û©´ô܉.¿ÍšéÌ`07l<Á¹Îp·Ú}Ƙ™îÎ’’âgÏÝÆ·75µœ:°Öó¨‘a?Ÿ+ŒmÍþD’‘™7 ¿×Ñee¥ õy¶ ÏZ°?ô»öäÌÙÀ­ÛÎÜôßgeeóèqÄœÙãæÌ—“[äsõ!gú‰G–áŸoLL0™ÌnŽ#GZH¤ëþO§NqX¼hÒÂÅáwÜìÜu^\LÔmºã’Å“¼šžž‹§¼v=ØÑÑzÉâÉsæîJNÎ7n¸¥Å]\@©©)fŸÅ³ÛâßPúzší5þxû¶‡­}ýæãòbcÿ5A FŒ0÷¾´ÓÚÊ`ÃÆ“ÇŽû744ñ,Ý¢f¸q3ÄØ¨þ¾öàÞÑ1cl|®>´0„_é13øòÕ‡¯_+ý®=QUUˆŽN “••|÷Ǻæ»gÈÝ'OÞ2™¬”Ôlöv3³!qqQ{Ë ïqîâuþŽŠŠ|xx\TT’°°PFF¾˜˜hÈÓ³ZZª|ä`oé>Ãéâ…ßSÓr‚ƒ#ñü«`e5äÖÍ Yqq99E<Ãðl"„¤¤˜©É„ŠŠ|iiÿÖX³zƪ•noÞÄ•–Vq¶†Á=2Bh¦»“×ù»MM-ì§¢¢’(”ºÜÜâðð8„Ðë7B¼ž3w×Èæ—.îÀ/:rÒÕÑhjjeÿ™”ôéÄÉí½|è°_iiÏ6áS‹Ñ£¬æÏsY»ÆýÜÙ­NNCBG_ÿÏ8ãÆ?|äW<×μ|%ðÓ=æŒÇOŽ%%ÅŒû“H$aa!2Y¨©©…Ngœ<0a‚Bˆ@ ØÛ[œ>s OidÔïŸ”ÂøPQWW,+§üÝ)âwÊ7{ð› U\RÁµÃ°ÆÆfÎ-bë×Í>}jSBbÖxOÎÞÁYX ¾p~ûXça í ¸õð3¨ÙjjêÙÁ@BBŒ@ TVÖâS²82Y¸¢¢º¾¾i@-CÃC׬óüž{=|ýž:ìgcchh¨Ïd²Ú&©®®ãÜR_ßdi1?îóggñ7M‘É£GYßagŧ ……e‹—î­­mpuA"1 ã|6?¿„óOžM„?Æ“@ °X<*ÈéÝ»”«ªª*8Ø[òl <*×Õ5²·Ô×7ªª*àUpŸ1æÁ½c!{{ s³>W¥¥å´ÍdŒ£Mô»$vaLL¬_7ûò• MMeUU…öÚDðZTVÖ°›BDD¸íÝR––C„„„bbRÒÒsÙçm! ‰¿ç0 ‹…566·RiY‘+*kÚ¤äW0þ=(HC%'æÊ6--75•;1F¿qóY||¦çš™ì×§ÌÌ|ïËA†úcmÚ> @7‚¨ÙœÆ ý—¿Å´´´ÆÇg:; Mýçm¥ªª–D"¬;~Üðq颢"¢¢"kz!ÔöM ßÂÞþõkå©ÓÇ­WT”«®®Ã0,(è þûd(1éÓ„ñvœ™Œ7<>! ?naaYee †aÏŸ¿ãã+û ²²Rqq¡ÒÒ*þU8tØÏeÂo–4£¥…ZW×øúõGQQ2~ ðˆxÎÄ<›¨½òpì_­´ÆóȾ¿V¨]SÓ€aXhhLss+Bˆ}ú’––kdÔOMM‘½‹­­Iqq“ÉÂkñáCBHNNzçŽÅö¯ yþnåªCññ™œuua` êôÿ—^°X¬ÖVšYo^þÝÚ¦a¹7:; c7ErröXçamw\³zÆ»/*+ÉóÉ\NNÚÊrHZZî?Y}æ™<{ëüÊÒr𙳜ßÅ$››bÿÙÜÜzö\àªÕ‡û÷Óò¹òǘ1ÜA111kÕêCGüµgùŸ,UPà½ä €îBÚ½{ww—á§ÅDÞ>h‰Ë7Óij*3Ì{÷_1̧ϢG[èWDE%ÖÖ6^ò¾èÀMMe]]êêºwT*íÕ뎎6‘‘‰W}•—W[Yñ»ö$øi$BhÀ-üZ¿kOnÝzž˜˜ÕÐÐ\T\ni1XTT$ìE •JÏË/‘”{Ý¿_SÓ11)D±¶¶áþƒ×šÊ L,,,;qòfRò§ýµæÌ{ïÞ«’’ŠÒ¯UÙ9E¶ÃŒ[Z¨ŽN+]&üÖö-©´´Êëü/b©Tºšš‚ºº’ššÂù wG9X…†½›éîÌU…¸¸ŒK—•™› ”––¼wÿe9™·‘ }úÈÄÅeŒkÛO¿¯ßµ'ÂÂBÊJòZZ*ûöû„GÄëéiLrÙ¶‰n> kii50Ð?y*à]LІ†~võòåûÛw^< ‰®¢ÔÕÔÔ÷í«"%%^\\þþC“ɪ«oˆ‹Ë!e•œüYDD¸¬ŒRPPz3 äÄñ ÒÒûöû¼~óQEEÞÖÖÄÐ@ÿä©›$"12*±Ÿ~_EE9¼î""dÛaÆG\½ú¨œtß¾*!0ÉuDhXlhXŒ|™²²ª‡"† 5RSUìׯoÛn½ÿàUÛZ((ÈþÓ°4%¥>xÎ¸á¶Æ·o‡UVÖdg††¾;vtˆˆ0»À¦¦Búk]ò~p`ÿ*üΦ¨¨$ï+ŠŠËÍL=|ô0!d;ÌØq´Íé3·˜Læ«×ZZ¨›7ÍŽNf§|ô8âAÐkƒÙ¿¿ÖÉS7?|L×ÖR•;qòfJj¶©Ée¥>\=èèhsÎë6gIø7”ëÄ¡a±/^¼—ï#]RRü4Ò~¤…’R„P}}ãé3·nßyá:qä²eSÛ^ ˆŽNÚ·ÿJK uë–ùö–¢¢ä޾bÑ•`´ti‡÷ #<>ú‚¿ÑÅ0Á)ŒNgÔÕ5rÆ!:QSS¯¨(Ǿ]ßX[ÛÀ~§þuuD"AJJ‚NgpNrR(µÒÒ’œ[8566³X,iéoß4ÛVSSK\\†©é|w>U`±XååÕÊÊ}ƒÁÄ ƒaXuuÏïIàÙDB¥Òêë›å ‰DbçC§3êëÛûr Ã**ªå¸n¯åÌÖÿÆ3k+ÎÑÖVjjjŽ””Dÿþ}¹vì|·6663™¬öîj¦Ñè·CçzL$«ªªZ))qüÊnGñìA>Úk¨””lYY)}}MvC]¸xï7;Sžßê€úô© âm¼¹¾¯Ø³^†â¾çvQ“ŽEM~„5kÌž5¶¨¸Üq´u{·ƒ¿AÔ?\×à§¶dñä‚/_ûékBÈàgßrÀOÍȨŸ‘Q¿î.àop®  ¢& (ˆš€  j‚‚¨  ¢& (Xyò-Ö˺»~5¿¾€ž>ã‚fhAAÔQDM@P5AAÔQDM@P5AAÔQ|-BÁ7[ø?†aÝ]Ðq99èáC´iÓ÷ìËd¢qãPhhW— z?˜¡í™ÄÅQMÍwîK"! ¥KK¿ ˆš¿$''ôõkwzˆš¿$99ÔÜÜÝ…€ž¢fϤ¦†ââ¾w”“Óu¥€_DÍ«3×&UUQQQ×~5IŠŠ¨  » =DÍK^þû÷UVîÔ/üª jöXß,¾ø„ÉìÒ@ïQóWåä„ÊË»»ÐÃ@ÔüUÉÉ¡ÊÊî.ô05{,míN­¹40@¥¥]Wø%@Ôì±45;µæRU¥¥u]ià—QóW¥¨øýßd ¿*ˆš¿*eeøÙè(ˆš=–¾~§¾ß‡DBòò°ø:¢f%.ÞÙï÷±°€Å'Ð!5£¸Ñ— IDATaÚÚ°ø:¢æ/LSŸ@‡@Ôì±:ÿ]²úú°ø:¢f…—lgˆ‹Ãâ舚¿055X|Qó׋O # jödNNb…Å'Ð5{¸––Ní‹O # jþÚ`ñ tDÍžLN®³9Àâ舚=™JIéT°ø:¢æ¯ Ÿ@G@ÔüåÁâDÍžLUÕ×w6X|ƒ¨Ù“)*¢ääÎf‹O@`5y°øQ󗧯"#»»Ð3@ÔìÉ”•Q^^g3Å' 0ˆš=‰„²³;›‰šúð¡+J½DM€¼|g¿Ï~ 5B0I ‚€¨ÙÃYYuAÀÓÖFùù]Qèå jöprr]0¹ª©‰º¢4ÐËAÔ°øQ $/×5@5{8;».¸$)'‹O@5{¾.¹$Ù¯,>€o‚¨ BéêÂ$-|DÍNJªkò16†Å'ðM5{8®¹ýUZŸÀ70 ëî2üô,,º»ÐÓ¼xä亻]¢¦,,ªâžww! ÇP°pÆäûo÷¾À 3´º^Ýá˜ûŒÞw›!DM]a2¤WNˆš~ˆ^8!jøQz_à„¨ àêe¢&€«7Nˆš~¸^8!jø/ôŽÀ QÀ¤Nˆšþ;==p uwôB ÎßHáèˆââþ“²t%ˆšº˜ ßÝýí°úS‚Z@P5AAÔQDÍ^ˆN§7Ô7à™LæwäÐØØˆïø}»ƒnG£ÑZ[[ÑO܃ÍÍÍt:ýGäüêù«–––‘s{¾äIMJý/ØU©T*þø§*?¸‡ö§VUYµkÃ.j+õêÝ«‚¤OŽOö»ègje***J©¢™…‡…ïØ¿Cð#Ö×ÕŸ9|ÆÀÄ€@ ÔÕÔ¥$¦»p¬m2ƒ±kîØÈØ7‰oÌ9ìiؾíûþ<òç(çQæ“—tËïÖû¨÷nsÝÄÄÄjªkè4úâ5‹åäÛ&.,(ܹ~§ŠšÊ¯#©3N<å2ÍE¯Ÿ^Û§8+Å®‚û|waaá¦Æ¦> }fÌ!,,Œjlh<¶÷Øö½ÛEDDºª`†yó’í#+#+SY^ë}Ë›gÊ>7Žî9¬©¥)HÎ;×íü’ÿ%èUPgò‰{fbaB§ÑãßÇ/õ\ʳ¿[È£QΣ?&Þ½q7.6n”ó¨áöÃmGÚv>çöjp5`ÉÚ%üûZmUr|òÿpvu^±~EçËφa؃À‰ M  FkK«„¤„”´ÔøÉã»ð(½DÍîÜÑs«7¯þ¾}–y.;°ó€ ‰Ÿ?~~êà©Gáð·` ÃVÏ_-)%Ù¡#ßwÜÍÃmˆÑ„PaAaðƒ`žÉ„„„¶ýµm¤ÉHÁs3~̃[ †àù˜X˜“…ý/û¯Ü°ßòäþב®¯â_µ 3}µûºÏsöð™àEꌊ²Šæ¦fžOqVŠ]…åë–ãÏîÚ°kÕÜUx$£Ñhå¥å £K¢fkk«¨¨è‹g/È"ä9‹æ „ ÆÕóí~Þš³hΕ³W0 0IIɵÛÖ.u_Ú™|> ò»ïG"‘Bc]ÇŽ>þ ø\ÎçœìÌì±®c¹¶ggeëÐG™Zšbæ{Á746”@ t(óöð¬)“ɬ©®QPTPPTàÓׂh;¨ŒÍÇLC£Ò:_x‹Å`0Èd2Bè¯mµ¶´8}o™¦¦¦Ñ£·ïÝŽþEíeB£ÑH$Þw¿,˜¡ý±¨TjÄˈÎä@h€ÖÕÖ­_²þÐÙCì÷_ðû¾ß;z¸ÏŸÙ³»}µûÚ9Øu²`œ„„x|J㟑Hä|˳s°û”þ)+-««ŠôÝœ>`hbØÞ³œ%᪂ƒ³CÐí | ±|Ÿ þ$$$:Y˜woß­_²þMèôïš1wŸyöÈw¤0ŸÚšÚík¶ÿyøOöÛ®”´ÔêÍ«7.Û(xðÆ…‡…óœà½pꬩøc"‘ÈÕø×¶¦/#FŒÁ>b{}-žƒªó£šÁ`Üñ¿ã¹È³ ·!ôá݇[¾·þ<ò'»¨vlÀG‡G¯_²>òu$Ï))*Ù°tC€oÖ¼‡‚sÍïÄ`0®{_—”’¬ª¨š1oF¼X_Wïêæª ¨påÜ I‰sgúãPfj¦ÿM-Í‘Ž#¹ö’–‘>üçáÖ–Ö)3§})Êýœ»hÕ"Y„PVzÖ»ˆwªêªÕ”jüˆ†Ý»yOHXˆÅbÕÕÔ-\¹³<1ocêëê L 87ªkªOvŸŒ?¦TQnùÞRÕP­¡ÔÌ_>¿¤¨äüñóCŒ‡¨ª«Ö×ÕW”U,_·œ@ ü6ú·ÕóV¯Ý¶ÖÎÁNGOgùú¿?5䄇…KÉHµ¶´ºy¸qN:%Ç'?üœ@ Ì_1_TTô쑳’R’s—ÎŒm¨o()*Y²f û”· · øAp]m–ŽÖpûá\­ÊUȶïPŸ2>)«*ë ÐCE¾Ž,ûZ†’’–ržø¯åÒÏ?‹“‘•Y³eMJbÊ£; RUW ¼8mö´šêšJš†š“‹BˆÅbÝ»y,B®¯­7³6306ˆ¼èæáF£Ñ¾ä}Ñ ßW§ovVö‡è³ÎÒÑÓ‰‹»î}}úœévv,+,8ŒÅb¥&¦Î˜7C[W›ÿÈyõÞuº«˜˜Bè~ÀýÐ'¡ûNí“ë#×ÞHHNH QTV,þRl1ÔÂv„-{H¼}ýèÎ#+[«Ã^‡ñÓ»Qv®#\ Â(çQ†¦†ìlll¼w㞌œL ¥fâô‰ Š ì"•—•ßò½ÕPßàêæjdjtþÄùúÚúyËç%Ç%·­†a¡Á¡­-­”JŠÛ\7IÉMfpp®¹ôØÈXƒ¡×ÿ_ó±C-VÍ]U^Vž™x-pÊÌ)£œG]8y!>6þ”Ï)IIɶü øÔÁSN.Nuµuã'ï#ßÏŠÉdVSª•ùwϦhjjºvñš‚’Y„l9ÔR]S=:<ºµµ59>Ùj˜UÛ±ÊöòÙËÝGw³¯BOƒžRª(4*Íz¸µ¡‰aΧœ˜ÈY9ÙÜϹSgM-/-g*„Ћg/(•Y™¯Å_ñfŒ|ɳ}ø¼j¨Tj _`‡„)3§œ¹z“Oî=l4˜ë„rÌ„1%E%¡QΣ~õ[P`кÅëÆM7fÂÎÏ:z:§®œz÷öݶÕÛ†™µp»v¿8×üNÛ×n—í#ëæá6nò¸u‹×©¨©,X±àå³— :ƒ,B¦QižÛ<5µ47îÚ(ÛGÖc±ÇHÇ‘m÷^¸ráÿ;,Ëuº+‹Åò¿ìJŠKÚ»mïÜ¥sǺŽe_¢ý¾²¢ròŒÉSܧ°O&Ø>e|ÒÖÓnfl†Û „ètú ç“Ý'O9UBRâòÙËZ:Z6¾ç}M,L¦Îœ–—„Z²f‰û|÷“ûOZé[0‘Ÿ“*+-Û´|Ó¬…³¦Îœj`b°váZÎC›«¨©äfç*)+IËH“H¤yËæ]»t-%!ÅÍÃMMCmßïû؉KKJ'L™0kÁ¬Û×o? zÊ™OÛBâÛ Æ-¿[¾çOœ¿{ãîÃ7%%%_‡¾y2}Îôés¦çåäÝð¹Á™•óDçâÂbii„¡‰!“Éœ4c’íH[‰tûúm—©.sÏY»p-Þ¶v›ä6Éc‰Ç©§²Ò³ð”×G:ŽôXâ±bΊôätÇqަ–¦‡vBYØXEÈÅ…Å¡ø÷ñçŸ7iܬ…³<\=xŽ&“ùøÞã߀cg¨iª]ü»jSgMMMJmmimo$Ô×Õ/˜º`Õ¦U3çÏ<°ãÀRÏ¥ÆfÆ!‹ü Øs‘g]mÝÉË'ç,šƒ‡L„±™ñY¿³Oî=m1z°Êà°à0<ý¼Éóœ\œ&Ϙìæá¶ÈmQsóÿg•U”ÇMw?ྱBH^AÞÉÅ©øK1Ïzåçæ›»Nwá8bú˜é\'|\#œ«>e|ÒÒÑâ:ùï~Jÿ„G‹¢‚"„Ð2ÏeoÂÞ0¼;h” Ãí‡=Âc±;d"„¢ÞDñ™Áñl ÃæNšk9ÌÒÍí ·àêù«,kÁ´6v6žÛ<·¯Ýþµø+ÏÜêDDEØÏ§¯Þyø&ìÍÜ%sç/Ÿ¿uÕÖ–––;Ì^8ÛeªË`£ÁõuõœƒêòÙËÉñÉîóÜ':——–ã9ðlŸö^5MMMO]ü}íö9=bôv³Êø¤£¯ÃUY™Á†ƒñÇÂÂÂnn'/Ÿ¤Ñhž‹<ƒnqÞ(D lGØžð>anm¾kÃ.¯c^ üÛ¼—¨ù=¨Tªÿe11±èðè’Â’”„„Œ¬ÌÇ7¶¬Üp5à¯ãµ½€ç^’4ÍÜÚ!¤¤¢„¿BÎ9;aê<²‡²¦–¦÷iïu‹×ݸ¿Ô“ûÚ’–®ç‘ò²r/Ÿc{ßw<).é}ÔûjJuAnAtx4B(êu~h5 5üƒ9ûÐBBB›vmJÈOˆÉŠn?|Þ”y†Ýô¹iba‚¿5›¿}ù?Éc›î1ý]ĻښÚÖÖV}Y9ÙÅk/\µ0êMTyiyFJ;¥‘™Bˆ@ L5õÌá3œ™ð,$BˆÅdÍœ?sÖ‚Y+7¬ËÕ Ë<—ù_öÇ0,ñc¢›‡Þ˜’Æ$IXXX˜,ÜÜÔL§Ó/ž¼8f¼TÃí‡{ŸöÆS1ÂN‰[U]µ¼ìï·0q qü™•™÷-ïä„䤸¤üœ|ž7"’H¤‰Ó&ÎZ0ë´ÏéûN²ŸbOÏò uµu"¢"BBBRÒRø¬ƒ¤”dΧ7g7!!¡Ó>§§¸Oi{‘ÉeªË›Ä7å[÷l]=uqañ‡wš›šUÕUñ””•B†pîÒPÿƒ„¿GQ©TSKÓöꥤ¢¤¢¦‚Òë§G Þ¾zËΤí¯¦T'Å%áÿZZZ4új´ýÀWZRŠRPR@á§×!"‘ˆ·p{ÄSXpž²=E_Šx6EzJúçÌÏ–C-B«6­Úºg+‘HŒHŽ TRž=|F&“ó²óxføèî#×鮜[Úëë«^W•T”¢Ã£ßG½þœñYCKcì°±'öŸÐè«1È`úgPav|ïq77¼ÊìwžíÃóUü xÅœ¶#m_:ŽWŠ“–®Viq)×F ÃÿüˆD¢ËT—Ó>§¥e¤Ýǹ§%§qíbbarì±QcG­Y°æ~À}>ÍÞË@Ôü­-­LÓÎÁÎÜÆÜÜÆüCö|»¦–æÈ1#ß¾zÛö’À—ü/íí%..Ž $, !TUQ%%-Å•ƒlÙç±ÏM,Lîݼ×öœÆf¸ ¥’‚ϱ „”U”­Z”û9·øK±‰…IC}ƒ²ª2~ÜÉî“ýøý}èÞúÙ‡¾{ã.þ§þý}'÷a,¬šRM©¤p~& WVTr]\\|òŒÉ¾/ž¾Àß¶>¾û¸yÅfeUe;;žDTL´¶º–sK{…䉳Hd2WyB¦–¦$!Òǘ™i™œï;\Unjl¢¶RyfÅ™L 0wϯ[¼®¾¶~¬ëX‰ÄÿúœŠšŠ¶žöóǼ¿¢³íHÐÔÒì7°Ÿ—Ï©ƒ§vìßφiëiO55äQÈëÐ×mw÷Æ]|£¢’â‚ ¦¸OIøÀÕƒ<[láÊ…>^>E_Šð“?AêÅÕ‰mGxîç\¿‹~ø¿ÚêZ+[«òÒòªÊ*ÎL2S3Õûª÷Ô¯8{;~D>„û’ÿÐØÐ(Læ_Õëç¯y6E]Mûã‹°°0™LnnnÞ½ywÄˈÑãF+«*··*#9>ÙØÜ˜çS\}ÝPß`jiŠ·Ìíç·ÌŒ¶îÙúû¾ßëjëÜǹÇFŲwd05Õ5mßx¶ÏWÍpûáÆæÆ7}nf¦e¶ÍÄ~Œ}Zr>ÀØ2Ó23S¹cñ2âɽ'.Ó\ðâò9óóuïëƒ 3’g#ôJ5¿‡Œ¬Œ•­UjRª¨¨¨¨¨(>·‰º{ãîœÅs~õÛÞí{ñ-¢¢¢t!ÝÞ^mÙ;Ù§'§ãëëêñ—GÄ‹ˆOéŸæ/Ÿø,PHHˆkЫ¨©ì8°c˪-œïn-Í-d2BÈÊÖêkñW&“‰:áCB{‡~ô”ý‘“@ ôÕé+×GÎÁÙ!#õïóEJ…D" <€kÇyËç]»x­†R#×G!´}Íöß÷ýÞo`¿ÚšZüò>%È>!NMLÅ/+²ñ,$^¶oÙœEJON=vtÛº,Y³äЇ•ù]å’•“5µ2e¿¹´—gqrq²s°£Ñh---õuõ‘¯#9`ÆY~Y¼ëËJ˸óâÅÈÌhÖÂY«7¯^¼z1¾EHHhæü™'¼OÔ×Õ{.ò|ô”s0dge'Ç'³ÿ””Рo9̲´¤¿ðOéŸØ7°°7:+-ëÆ•øSíÕ«¹©¯N/*(â\ÑÑv„[µ²Ï>ë£Ð'á}BR\REYÅpûám;ˆ@ ˆˆŠ<¹ÿ¤¢¬ÂÁÙ?-ó¿ìï±ÄƒÃ?&^>{95!URJ25)õ~Àý]v9¹8 ·Þ¶)È"dK“³‡ÏŠˆŠD¼ŒÐÖÓÖÔÖ¼sý޼¢ü‡w•ß¾zkjiš—ÄÙb>^>îóÜÙwº%Ç'óéë+<¾÷¸´¤´¼´lï£ßŸØw¢¥¥eíÖµvv"¢ß¿hJÜûZÊ}±éçGèè ß¿" ‹ö~õ¦šR-)%Éõ)¬­šêY9YöëYÀ½‰$"‘H¬¯«Çwªª¬ã³ “Édæ~Îmnjh0ë69 Ã*+*¸^œêëê¥e¤ ‹ ‹Èy«N¯­©UPThïV~*•Ê9?F¥Rê ‰Dbï…ŸËrÝ{Ù¡B²566²˜,ü®Ÿ¶h4ZP`ÿ¥l”*Ф”ä÷­›d±XåJÊJÁ`|sU{YiÙ—¼/æÖæß\°qóêMq ñIn“BUeÕâ‹OûœÖÒÑâJ†aXø‹ð¦Æ¦ S&à=H©¢|Îü¬®©ÞW»/g²Šò E%ÅöÚ–Á`ö…Òöê…÷‘¢’b{#á›#œF£e¦fbvþøù£ŽVSª?g~všà„g^M©–W/+-“”’”ÀÒ¶ƒh4µ•Š‡Ì¢/Eo?\³e ÿöäßmÇ^eE¥Œ¬ ™L¦Óé\ÝŠaض5ÛŸ;Ìÿ@\}ÝØØˆ±0¼Ìt:Ã0J%EYU™gPª(²r²MM CFVïžíóÍW •J½ãÇÜÚœójEkkkFJ†´¬´®¾.{ÇÐàP!!!'ž›ó)ç]Ä»óftÉ c çžøûš5Ð~Ô?§mk¶M›=­¤¨d¤ãHö =‘ï_ I‰és¦„ÖÖÖ•+{þæÊŠäÜÑsÇ÷ŽJRRVúî|N<…ß°Ý…eã/6*¶¤¨dêÌ©ÿÙ{Ÿ5a½&è…<–x|ÊøÔo`¿2B V,xúÚ똗œ¼\]mÝžc{zSÈD-Y»DBRÂĘ̀3!ð²¯eÿeÈD=ü|ëž­ÿåÁOÎ5çšüÜêxÞtÚ›ŽØûôÐsM¸‡Ðãý÷ Bæ/ ¢& (ˆš€  j‚‚¨  ¢& (ˆš€  j‚‚¨  ¢& (ˆš€  j‚‚¨  ¢& (ˆš€  j‚‚¨ J¨» Ð3¿–uwt?†aÝ]†ŸkÇv õ„VJIAFF]™!†¡Ì,4xPWæùSúœ­¥ÙWDT¤» À/„€Äý»»Q³±°@qq= ϟϬY³8 ­­ÝÝüìàºf/âä„jjº>ϯ_»8ϟϪU«»»€¢fïÒÒÒÅÊÉ¡ææ.Îóçckk+!!ÑÝ¥ô5_('§» ? ˆš½ˆœ\×ç©ªŠŠŠº>[è™ jö"(%¥‹óTTD]œ'ôX5_ÊÊ¿Â=´ÑÑÑMMMÝ] @QðE"! ¥» ñÃyyyUVVvw)=DÍ^DUÕ×w}¶¿ÆâDÍ^DQ%'w}¶¿ÆâDMð-°øþQ|‹ª*JKëîBÀO~ó¤QVFyy]Ÿ­¢b×QßOæôéÓr?bµ+ ×sÍ^„DBÙÙ]Ÿ­²2 íúl&ŠŠŠBBð ðmðN¾…DB!&óï@(.æß[†r§áŸ ò5ã— 6qEz®,@——° ’»à¿Ö»ü öÚ±­Z…ÔÔº>çÞªmÔ½pwt˜¡í]~Ä…!„ää| @Ôì…ºüÇÂB¨´´ë³ýiœ;w¾ ˆš@úú½{ñÉ»wïà{h‚€¨  .ÞëŸt1¸¨ù+°°èî€nQ³w±³Cùù]Ÿ­šZ¯_|ò«­­e2™!üðßÃ0¬¦¦¿zVžô: ?$[yyX|ÒyT*õàÁÃ$IOO·®®¾O¹ððˆöuËw,TVVnذ¹µµõîÝ@þ)ƒ‚ÖÖÖNž< ðÊÊJ[ÛaŽŽ£ñgSSS_¾|½~½§à‡þø1ÎÏïZ||ÂôéÓ$$$¨TjVVVVÖ§7o^¬_¿IMMÕËëì÷ׯòòò={ööïß_EE¹¼¼ÂÄÄØÇÇ÷úußt8ÐË@Ô‚±°@åå°ø¤3ètú¨QcÖDº?u IDAT¯÷œ:u ¾%==}þüE{÷îù¾ 1 ;vìÄæÍ¿owEEEOÏ5;wþñÍ”“'O***~úôÙÊ•ËB4mć¼¼üeË– „›***:thKK ‹uåÊÕØØh| †ak×®«­­ÕÖÖž7ÏãáÃǯ?­­­¢¢¢¡ÂÂB‡1aaÏtuuñ§|}ý¹’И¡í]¤¤~TÎÚÚ½xñI@@€¶¶ö>ʱc'deeÙ!!4dÈÙ³g}w†ééé_¾|éL‘„„< ‰L&“ííG^»vÿsèP›ƒ÷wôÐ$‰aqq1@ðð˜SPP€êÚïiÊÉÉY¿~ãéÓŸ¹.Y²|ùò¥ì‰š?ž¾¾BˆF£mݺ}ß¾ÕÕÕ]XÐËÀ¹fƒ¼¼³s×笩‰JK‘±q×çÜ+Y m{CÐÝ»÷§L™ÄµqÅŠeâââ\«ªª|}¯ih¨S(ÕË—/MLLzö,¤µµuÓ¦ ©©i¡¡azzºff¦«W{Šˆˆ\¹âcccm``À`0¼½¯HIIVTTΛçÑÐÐpüøIcc#uuõººº²²òuëÖâ*===""R]]òÏOŽ×××Þ‘—ïS[[«¢¢2~ü8>•c2™ïß`Çû?ÿÜSQQqá‚Wxxĵkþ³gϬ®®¦Pª54Ô]\& „h4ÚùóÅÅÅY,–´´TRRò‘#‡83}údNNξ}$$$V­Z¡¢¢Â§Ðû÷üž½z“’ì÷ßHÎÙÙØÑ£?$ç^ÉÜÃhœÿX,ª¨¨È­[þ\ÛÛþ£ÑšÌÍÍ s1Œæë{ùĉ£FKLü0`@ÿêêò'O‚®]óa±¨F»|ùªUËÙ;®X±Ï?77ËÕÕÃhþþ¾&&ÆååÅFspùáÃ; £}ü3aÂ8:½ÃhÞÞçœ1Œ¶wïîøøX £UW—_¸p®m©Îž=ellt÷î­'ŽþöÛð÷ï£ÙO••iiõÅ/Z´ÀÃc6ƒÑB£5)(È3-FÛ³çcÇcmÃÏ«W½++¿âÅ ‘ˆ.œÛ»w·ŠŠ2籞< š7ÏÃh·oß\¾| †ÑèôæaÃlš›ë0Œ¦§§{åÊE £EF¾2dpjj†Ñ<=W_ºtžÃÇ1+V,=rä`]]gÎ11‘¡ÒÒÂoöBQQÞ¶m›·lÙXPÝ~2ð+‚sM X|Ò9AGG§¸¸„k{SS“¸¸8{®!M¡PrsórsóB¯_¿Y¿ÞÓÄÄäÈ‘ƒ3fÌš={æ¼ysÛæO¥R/_öqrÂ/ÔIJJjh¨+))!„TTTJKKBGŽ›:u2> jhhxÿ~BÈÈÈpúô™S¦L3ÆqÉ’E<« ¢¢IžŸŸ¿ÿÁ¸¸øU«VL›6õ[ëhaùò¯¨ã¿façš|Ɉϓ555™ºº:ªªªí¥Á0¬¢¢BQQ¿vÈ'Yuu5~ƒ(ŽB¡HII‘Édþlhh ‘HD"±®®NNNŽ@  •””())}s_\ff&N72âWS„NŸ3gÞÕ«—%$$ Æ“'Á=ñóó䏯ÆF‹ÕvVYp™™™/^¼Z»v5{ †aÅÅÅEEÅCØ9Óh´ãÇO.^¼PQQQ |-†þæ?7¸€ÿšœœ\{Ó§lAYYù›YΉâú³=ìiUÎEý‚ì‹4h ÉX,VKK þ•uBBBÒÒÒêêû® ®ût¾Ã Aƒ¸JK 45555597’ÉäíÛ·vòX ×ƒ¨ øDDD®\¹tõªŸ„„xSS³¦¦Æw?ˆš€KIIiݺµÝ] º|£?ƒÑÝ%ü5øl캻àǃ[~I5AAÔQDM@P°ò€ƒ™ò¯?¹¾™–ë ¶Ld»’_‚*¹–_‚¶ß|Ë?ÁP®›e¸~øëY&Y[óKÐÒ‚ììø%hûÃÿqÀ¯¾QЬ—A¿˜¡QDM@P5AAÔQDM@P5AusÔÄ0¬Ã_³ÐqIIŸ‚ƒ#ôQøhll>u:  ÐIì>ú: ~fÝóz,ëò• g!ÑjªŠ,«´¬jÊd‡ys'„ïËÉdWhi©ò|öÐa¿å˦æåÿµ÷JfV~K ÕÔd€––ê_{–w¢Ü._ ÚÀÇØ¸ÿ£ \Oݸù¬¶¶!tì¸ÿë7?.ÔÔTVWSl¥Ò¨TÚÈKO’––ìÐá–.Û—‘™ñÆ›D"qnw½<55Ç×çÏ :û†8x5==OBB¬µ•:x°î§O_ü|w·—~åªC÷¼Ú´Ñcó¦¹:ÐØñkââ2/xm›6m4çöØØÔ¥Ë÷—–VU–¿ä¹c^^ñ^LIÍiiiµ¶2À0TS[O& /Zàêâò[{‡ãÓSÿö:޳0W}í?põE¨—®®ÆX~QÝ51 s¼!3³àmøe55E„Pvv¡Ãèå!!Ñ·~_àÌÏÿº{Ï¥þûÚ>õõkevNшæÁÏw·‰ÙÌÔ´œwQW%%Å;[“[²xòý¯ššZ¸¶cæ}9èé“Ó¡M=ôõ4'OÛ´xѤm[ç#„òóKŒMgÞ ysMX¸ÝQYU[]]Çba\ï½Þwô8™Á`v²:¡€[Ͻ‰ûàO ˜LæªÕ‡këø¤?wv‹¯ßc*•ÖÑ]¾´SS{<ƒÉ]fÃY3wî:ßÞŽºº7ü÷™˜Í,**Ïþô߸{Ï¥‰“7ø\Þµp+ϽÚë©ÿF{ÇÆÙŒ‚ ˜ÚÚ ¥ŽJ¥ÿwuàÖ 3´¾~ƒŸFmÙ<™¡~ýúnX?ûν—·ï„}_ž^çï´÷”÷åË–Nùî³Øâö""âÐVUUà¹‹ŽŽú A:‰IŸRSs:t¬÷ަ¥Üih…„Úy3¨¤ÖVjk+!D"‘öþµ‚Dâ7`ˆD"ÿíáSæï¨ÎèQÖ¡7Cø±Û~· ½Žcãߌm̆õsª«^¤Óõe´Ñ ïAß „솛rn´izø0Ü}†Óå+A·CûjªøùˆßðjccóÛðËBBBùù%'NÞ”’ojjíÛWeÍêd²ðü»ýo<ÕÖV[¼d¯½½ÅìYcÙÙÒhôÛw^Ä}ðÿf©X,ÖUßÇ))Ù’’bÕÕõ+WL72ê‡Â0ÌÿÆÓ—/?((È—TlÛ2ßÌlà‹±7ž«©)d}*˜0ÞnÁü‰|¢òY¯Û×ÏiïÙªªÚììÂ´ÔÆ·|þüåØqYY©²2Š‹ËoÓ§nii=qò¦¨¨ΈŠNºâ½³¼¼z˶3MM-Qo}B­­T¯ówóòŠee¥8çýø´dmmÃÁC¾T*­©©UGGmó¦¹mßÇMLú_ô¾¯£7q¬ó0++ƒI®#o\ß‹?ų#8÷ݼåÔ§Ï_ÄÅD[¯®®´s×ùŒÌ¼åK§edæåä ‘¾–V­Y5ÃÎîÿÃàíÛÄÔÔœ–*‹ÅÚ²yûC› eF•—SB†ú¡ÆÆæÃG®Q©4"‘H§3¶m¯¨(Ç™ØçêÃg!ц­^9ÃÁÁòVàóÀÛaö#-¬­ þÜsIT”ü箥ÏCß%&}²¶2Àgžy•ÚÚ†9swÕÔÔŸ>¹)ìElaa@8°•¯ßãÒÒªü‚¯÷¯îׯorògÎŽëÐ@â9`h4ú4·-ÕÕõçÎl11°zÍá”Ô쵫ݿ–V•”Tä䨷jÀm„ÐÛ· 7n>“——­ªªÕÐPЉMÙ»g…¥åþ‡pÃ:ÊÜcÄuæ_ÿ~}Be%¡œ¿ä#„Œ õñ?m‡›› Äã!‡Þ[Zü\NVÊëìVŒÇ ¾·´<{¦3žF]M‘ý˜ó_À}ë=gqn16ê‡j¨}Ë•ò÷m 45”[£1FÜ“‡'ÉÂB©I#îàþÕb¢"EO1FœªŠÂê•n#n¢Ëo¶ÃŒ1F\jR Bèáýcx&ãÇ å`É™ma~°¥Å`ý#{Kнc¡‘#Ìwl_8cº£¬Œä¢®Í Qìv’?zØcÄU–½”’xííëóç²%SðL6m˜SR‚1âöîYN"1F‹þqÂøá&ÆýñLnúïCÝ;Ƨ%é­±æfÇ΢dÒ>Ø3þk÷ò¶­GmŽY¾t*{¨ˆŠ=8Ž1âøt„„¸èÞ=ËñRYZ 65€ûâùí7ý÷1id¤%wl_ˆ1âΞÞ,B.-~Žgˆb×qõJ7­¾*uÕá#îèaO¼š|ÊllÔD$ž=½ùÌ©MÛ·Î×PWZ0Ï¥©>ŠIû0ÜÖdú´Ñìêëëi4ÕGqõÔ–MsÉÂBx«¦&®X6 ß¾cûBI ±S'6²èñ é)wø •ϽB çOlmz‡×hØP#¼‚zº³Üÿn"vÇñHìfüæ€Áq‘áWB‘áWð.# dme€WG_O¯~ñ—g"dá€û0FÜzÏYzºa!ç óƒ;ùZþ×?só¿™Ðuà ­††B¨ªª–scMM=B¨OüOQQ2û)öcÿÏjj,Ì!„H$’¹Ù ›·žS(ÿʇËù ÷V®˜Î¿<¾~Y,Ö™³z¢¢"!KËÁ4:ã’÷„ÐÙsƒéhh(#„â?Þ8|h-Bèšïï‹;?Žx“‚JLúÔ^æ/Ý_±|ZÛ§1C÷í]yóƾñã†ûú=NLü;‡›! ÍÒÒQQIYY}ûª„½ˆÕÔPö¾ü@SkÜ4·-vÃMñ“0¼¨¡üü’à§Q.~EáJÚ¶çã3â²45”££“ß½KÑÑV ‹yö,j÷žKø¿¨¨$„™,|áüöò¯aw­]íN"—.ßa˜ A vl_˜˜ôéùów #èá›nŽD"1-åö ·1wî¾ÈÍ-¦ÒèYYì] ôð†úí7³/…e¡a±œò,3ûY&‹e7Üt¬³í²¥Sór_õùS\\4>>3*: /'Þ­9¹Å!!Ñ\}±aýl"‘xì¸?BèØñøåC¼¹›Z¦OM ”•ú „¾~­ä3Tð-£FY‰ˆUTBf¦ñ**ò%_+þÉV„}hÁR{†«‹Éda"‘hd¨eeù¯_+B­­4*.%)’”§PjG²ÒÔTiïp€ötCÔt°·D}þ\ˆ8Vž¤gä!„\xÝö‰ý³Ú¡®®!ĞįýÔÖ6r&æ¼:˜%--¡¯¯É§0EEe¡¡14½¹¹•}1 ?~×+çvUUqqQƒ±rÕ¡Ysvˆˆ'¶£&B¨µ•ôðûŒ1í% ‘H®®#Yv÷Þß÷ˆâ÷€ ‘ðW¼w­\1ÝÞÞâã{9ãKJ*&MÙÙICC3BˆÅbñ) ŽÝ’øQH$"~”U+Ý®xïÊÈ̃ÿËË/F­Y{„B©URê3}ÚèÓ§6]óÝS^Q]W×(HG „\\~3¢wàoàí0·éŽ$©°°lòÔM{özëh«øÍ¼½rÊÊH"„¸îÖáYfÎzzúúšZZªìi[îr‰¡¶74)+Ë/Y<ù’÷ƒwï’ED„ûöýW,‘––àü“ÏPù;½ÔÿÓËÈð»/ZðÄÖvÀðÔö~l== w·1×o<ݺíLÄÛø›þûˆDX« À÷è†WÎÆ s †è9v-/¯xåªCëÖŠJ:z캙éÀeÿÌЉ‰Ðé üqvNBÃи±¶„²>àÛ3³ò‡ ÖÕÑQC‰‹‹Òè üÊ>×ù;kVÍàS&“¹uÛY eQQGGëÏŸ ñØ“™™š8qBÈuâÈÌÌ|üT¸¥¥õô™[±±i·n‡þ¹k©“ÓP¼X;«ïÞ{9Ñe~ Øž>rÒ¡˜ØT„PXXì¨QVB$RK ÕÆÆÐÆÆPLL$..cÿ«_Xí·~Ýì/…¥œ9 ¤££­–™•ÿYQQÍY$ž-ii9¤¯¦JyE5~”´^¾z¿i£Gì;?üß\ ¡ššú3gÙY è¯%##ɧ#8‰Äß·/ˆŠN:y*`Îìq¡ëþÁqñ™ÞwXZihl Æ9„PBb–„¸è(KÎÜx–™OÃâ»()ʱOg3³ ÄDEF9XµM¹y“Îpq]¿eó<þyò*%ø@âÄ5`êë¹?¬´çKaéž?—­óœõ(脳ó°ï(0!DÚ½{wÇöðöFK\:sH!!¡9³ÇfgîØu^I±œœÔâeûœ†ÜÜßÜÜ‚/‘–’yþ®¤¤2<<ŽR]—‘‘WXX¶f{ÿþ}Ïž»––s3 „Fg\÷ûK^þïI݇ó² m õBJíÁþGx²gGóòŠ×¬=ò1.£•JËÍ)ºø|ÓæS1±©3Üm¬ G['&~ ¼úáCú5ÿàÍ=æÏs!ööEEå§NßÊÈÈ»sçŬ™Îƒ뤧ç> ‰®¬¬IMËí§ß÷á£))ñ””ì۷êªj¥¥%ÌÌ"„V¬ oll¾};,..ãIpäÝ{//_Ú©®®¤©©Â³#¶ÿ~.66µ²ªÖ`ˆ~Æ6xÎí;/V,ŸfccˆRP}ÿ>5ìÅû’’ aa¡ÒÒª/ß›÷—‘‘¼};ÌÄd@hhLHHô³h_ŸÝÆÆý?|HëYW×8a¼]Û2766{®;–˜ô‰Ncäæ‹ŠŠôïÿÿ jQQ²ƒ½åÍ[!11)a/b#£/_Úif6ðÚõ`®ž’‘‘,**ÓÑV[´h¾oLLÊñ7(Uu••5ÖÖ7Ÿ,*,/ùZéì4l’ëȶC¥®®qíº£…_ʾ–V:޶þs÷¥øøÌšÚú´Cž¿{ü8¢¦¦^RRœÉd²;nò¤‘<Ò;/ØÍx÷ÞKþÆuâˆ5žG þÇÞ}Ç5‘¼ ŸMè½WA¤ª  "`ÁDÁ.6A,`CD=õìzŠ]»bQÀŠ]@ET@@¤ v@zOh!!ɾì½ùåB ‚‡ÂóýðlfgŸæÉÎî&Åù%óæÚmÞr211“B©5ÐïûìyÂÝ{ÑÕÕµ’’bC‡¸yëÙºõ¾G}¯<xúôM&“É}+V¸ð-]Ú•ðKÂøy{û/ff(á\Wm¾¼¼šÁhÚ±óì›øt{»ï’³_¾8Ïyµ¡¡QTT¸±‘Îd²DE…9O ÐhÂÂBãÏs[ÔvÌ­Å€ãx‹M÷áCnMM¹¹Ñâ%oX¿€ÿç7Zë*ÕnGjQóÓ¶Ðð“§n=¼VDDˆF£¿MÊòZ{¤ ﱺºÒEÝ‹e()©ËjàWÕmO­ˆÇºN¹p?ûCî¦ ¹_%†¤æ3œ-Îy’H$ÎHÊb±®=zýòBGãÁ0¬ÅqÃ0žOE ‘Hmt'OÝXµrŸÛ•‘‘ä>%Eÿ¾g„Hríæ N<Í/§µÖ’d2¹µO¨A»L"‘Z{Ø´íÉgBó‡CÚHüܱ5mÇÌg 'O]ÏÍ+öôpÔÔTéÐ#­u•Žj·#µ¨y‡i™L¦Rëdtu5˜Læû¬oêjŠm_v´¨›³&ÁÊjð½;GËÊ«¸Lê’ Ÿ?;j¤i‡†•®USS—‘ùÅæßWæÀ/hÛÖ%W–”VîØîÞݱüDsfëo uëöóÚÚzǵµû¤§†vùÇcÐtó íORW×Àf³;úÉ®]ˆ˜Õlí €fhAïðKœkv¹nÝÆ¬&€ß<³ð ²&À/Èš¿ kü‚¬ ðë‡î¡µXÖÕa¿Êš¿üóš€ÿ¼™½ÌÐü‚¬ ð ²&À/Èš¿~鬉ãxuu ñùò,ëV¯ª¢²X,Ç©T~¿ò¾“jjþÙÐ ~MML8”€æ~‰OoÏÍ-Zû§šªÂ©“›ˆ%¥¥•ï>¯¯¯©¢"_ZZej¢ñÒ½+»ù¯óÁƒW/_%[2½~ã)£©ÉÈP'?¿ôâ…­• {N¡Ô:L·Æq¼¼¼zä“qã,ùßbfæ—›·ž™ë7ЩԺúzÚÆ ®üìl»=ŠÙ¼õä¡«ííGðYORRV@àƒ˜ØÔ.“DEEªª¨ F“窹 2]Rgì?pyÖ̱zzšmGÂÙ……®Sêêd¸L&¾,³¶¶~÷…=»WüÀ—S¶íÝ»ì³çn››ŠˆUTP† îù4~¯·G×nð›ú%²¦––š«Ëä»÷¢‰?¿/±±]~R[»±ärÀýä”üWØØH߸éøûŒ$)>!³®®aíšùééŸÛXÅÁÁ:¿ ôÑ㘕+f#„Œ¦?¬Ý¿å.[:“Á¤Û IDATÏnÚr2ìöbL¿~#²¼¼ºÅb<;ËI“F…„†3™ÿ:ãi»3³BB‚ç/„­[ëL,¹}ûù›¥ïÞ^mžf~ ¤Î()©¬¯§µøw$œ]XãåD¼ºîOŸ®;B‚÷!„Œ¦ââ &“%ÜΗX·Íf3™,⻲ïß¹ÿàåè(¢•p_¸h—¤¤B¨±‘Þî7fz¼_e†V@€ÌùÝ}™÷òe39)!´ÐuŠ®®ÿµ•”TÊËK“H$„²²œŽNii +«Ám¯E"aöÏïBB‚Öc̯<äs‹8Ž'%e1™LâÏ6RRâ­æÞY> ´ðþ¦ízH$ìûƒÍ°÷Yß23¿vUH?ì˜ßzSSƒÖ^厄gìíF\¿I£5"„äåe‚®ìíL$L&3èê£%n»¿~-@Q(µî˼OÛÈyca˜÷žÄïÑÑïÜ—zGE½íðWÒzŸx®ñ&8$|ú´1õ ´ÊJªá@m[[ ⥨¨·EÅå!)Iñ©Sÿà^‹J­‹|¿}«÷B ÃÖ¯sA±ÙìkÁO„……(”Z s#}„“Éô?&))VVVíº`²  @èõÈâ⊠ï"„Þ¼IÇ’”[²xz||Fyyõ”)£Û žÅb%$fÎwš@üɳ Ç/Üg³qy9i55E # £‰“½<=G¢  ã¹jn»;{ÿþËø„ YY© 뤧 05Õ'&“¿~+t[2“6¾~+¸s'ŠB­í§¥nmmÆpzúçgÏdÄDEfͲm¾GYYßTU ú¶Ø†~Ç‚KK«†é?k–ííÛÏ“ÞeO2:+û[ddüömnÙr¿~-˜6õú!„êê®^{,++UYI=ËVQQö⥻‘‘ñ;¶»–§¥š>m …R›—Wœ‘ùeãWqqÑøø ÿówœçO´±VUE}ý:¥¦¶>?¿Ôs•£¤d«ï31±©³gÙŠŠŠ „‚CÂ<µeŠÚ¶ý´˜¨ÈœÙãÜÝöí¿ôþýW„Ðj¯#rrR.Γ¦q[ºGZZb®ãxYYI·%ÓÝ–L>ÜxÈàþKOG}ü”×öLoIIå­[Ï|ý®ÙØ.ß¿w•ÇÊ9ÄržM „öî»XVVí¶dºŠŠüšuGB—.ìè«©ºÄ}·’ŠíŒYëÛÝÙ©SÿÈÉ)’‘‘DëÕ×ÓæÌ÷ç_aa!•sÞ¼I'ZŒPXX6c†Í¢…S¯= {Á]ONNáÒå{=WÍ]à2ùᣘääö‘Éd>¸pßÇ÷êÕkO^J[¶žjñˆ°Xì[·ž]¸?a’§††rhÈ~b¹Ó<ûÔ´O4½_?uKËA§ÏÜ438o®ýÃG¯“’²B/_¾ ºúÈsÕ\í>ááo6oZ$++‰ª¯§ù ^íuØxÞÅ ;lm-8É/+;GKK­ùi=Ñ÷B‚‚.ΓÎûoc0š–¸í¾~#n ·ù¹3´¢¢"F†‘Éd·ÅÓ¹‚:|ôʤ‰£ˆ'Œ:x({mmu„PAAOUuu MML_¿àÉ“­B†Y[›;B§3Î_ŽŽNúþ½„“0Zäº`òÎKÛ( ¢"?k–íÚ5ó7m\è¾Ì›Íf#„šoÇqßk³fŽEYZzy!$//pyWEÙó¸˜Ëµµ ›6ŸhwgBk¼œ.]¾‡z÷.ÛuÁd Ã/ÿmh¨ýàÁ+‹žñ¿k±C†ô'vÜižýÁÃÿª' ðªªBlljtt’ŒŒÄ‹è$b9‹Í^è:eÑ©ëÖ:Ÿ9½ÙÀ@«Å6ä®JHHpåŠÙç/ÜEÅĦ.[:“H*¢ƒM ˆ&*.®@ÅÅ¥××ÓÔÕ•B’’âÊJrÄõH QS„ººb}=ÍÈH!¤®®TRRIl‚3­ê¹ÊÑcåœ/’Š‹+¸÷”™Lš5ËvÑ©ÏïðÞ{17·ˆó’¸¸ñ‹„¸XŸ>JJJr!e"¼Ü¼bu5%„’’Ü×orrÒd2ùÎ(çÛÇü1ôÜ٭ÇólK[[½°°Œ8èÜêê¸ÿ$‘H3g޽xa‡´”ÄÄÉ^iiŸZŒÐ#ýw×5ed$«ª¨¡òòjâ–„°°`YÙ¿îšQR’31ÖKm6…„FÔÕ54Ò\ë ••WÓht&‹ec3ÌÒr¥å Ïú$Z{û™™_32¾ „šo‚ÉdÕÖ6£?†aââ¢,+8$!D&“--^þ;&6µÝE™›2ÌääÉ)†€ºðàÀÁKËAƒé²X¼#8Bˆ¸'–{IMM½~_"¼û=×xÍkm¿ZlCž2‹M §RëØlœ¸G†ÀÙ_"¯pïÚ?U•Uñ”ä$HÎZÜââÒWxìWUU°±ÖâžrSSSÔÑésÿÁ«_ãl±Ù8Bhê”Ñ韃C¯=Ü¿wñªµµÙÐ!ý/^º—™ù¥y%£Fš²Xìoß ¹²ÙìÐë‘<%qö,áÖíç³fŽ%&«½ÄOÏšÄD%BèÕëä)“G#„ìíFdüÿ˜•–öy×Ó„‹çw<@¡Ôr–ä䪩*ÊÊJ™3äÜÏ’–öi‚ýÉ‘#LRS?‰ˆ‹ˆ³s<8·oäæµqf€ãÿ»ÏÃ0ii‰¤wY!γ AA[[ó„„L¢pLL*ŽãÁ!áœõÅÄDˆÁ´ÝÅ0lÅòY{÷_$æi‹ŠÊýŽ=²VQQ¶ªŠŠã8g2–sßiJê¢%9&Mõ6é=†aÄ 7 Ï­+-¶!OHrrÒ'ŒZ¸x—Ýø¶¼1¸°°œ¸ Çñ÷Y_mÇš·Q¾9O¯CÞ»Wöï¯U]]‹ãxDÄNo!àø¿â—‘‘ Ž/q6Ù¶œœ¢-›O™luâøFÎ`²²RÛ¶ºíÛëñ$ËÞ½“S$**üòÕ»ììœC½F4¹~=²¼¼úóçïqG¯©¬¤úø^KMûh ßW[[]MMÑÒÂhû޳†‘HØË—ïò¾;8Xcfc=ìØñ‹õ<*‘F£oX¿Ã0ë1f>¾×Ø,vZú'AAee¹ý.¿~Ú·¯ ³‰yêÌÍŸòäå¤ ´Îž»ýøqÌ´icš‡zï^ô•«>þŽ277Ä0ŒB©KNþ ª"_YI]è:™{::}Æü1ÔïXÇÓÒ>1M}Ïùߡӛp6»ªªæä©ë×/——nwgB}wï9ï{t  €ˆˆpäÓ7tzÓ·œB ÑÇObõõ5îõâ­’’\yYu|BFFÆ—}{=Š‹+8õØÚZTUQŸ<‰£ÓÏ£dzÌÈørúÌÍŒŒ/,K«¯ª¬¬gO›·a~~)OH}5UÞ¾}¿`Ádb•ÐðÐÐH­ÑÈH××/8îMzŸ>JÃ- ôûž=w›Íf>˜2y´­­§¤±±ž¯_ðë×)êêŠlûÔé›ßr jçåû_+,,³5˜J­KHÌd±ØÔšÚ¤¤laa!==M_¿"©®®9}æfjê' CÚÚêRRb¢"A&ØxôñcnHHƒÑ¤¯¯éëw--ý³ž®æ×¯**(Chh(ÛOô¼üäì¹ÛáqzºšjjŠÄî abccvïþËK—îÉÉJijª/™›2™Ìã'Bee$ëêž„Ç)*ÊÜ!Äd2C¯Gúú]ÓÓÓܸÑÕÄXŸ¸IüãÂC´´­Ëô X‡o£73ãÿ›Â.Úeo?|ò$+„„„÷Kuu ,[ZZ¢µuq/((ÍÏ/52Ò‘’úW±Š Ф¤Ïs‡••IIñ®}ãŸÓÔÄ46ÖkmÜK¨Ô:II±Ì̯õõ4SS}âVOB»;K§3¸w‡J­#‘0IIñ¦&&÷,(q§%9šš˜J­¢¢,?»Öbr¤§¦ÑèFíÖƒãxii¥’’Ü¥:QSS¯¨(Ëd2Édr»w¥W|ûV`aaÔâ£8Ü–¯Ø·é¯…ZZj8Žøëºhgbü•ºúØÂ܈¸ŠÀb±>~Ì£Ñèƒér÷ǯÈvvÃáÖÙ–Y,CIIÝ?ÝÏý”ƒúZ}=­ÅQ¾µ¡ŸÃ0  •æ/µø7òò-,ì$žKVÍ7Á½„HŠœË­ÝåÉ^œüÊ2Û­GPP€Ï”‰ZiC„ЈQ‹¢£üß¾w[2Ÿz0 SQQàs£Í )* ¡VHmNUUAU•¯ÍÑé :AD(%%®¡¡ÜZÍ÷”L&¨Í³¸… ÐËýÄsÍ/’3ÉdÒÌ6ÜY~eOŸÆ—WPÆÚ SV–ïîX:…Ng‡„××ÓÈÄÇí> :Î5Aïðsgh½dMÐ;Àí ¿ kü‚¬ ð ²&À/Èš¿ küú¡O9°XÖÕa¿Êšð¼&€¼™½ÌÐü‚¬ ð ²&À/Èš¿ kü‚¬ ð ²&À/Èš¿ kü‚¬ ð ²&À/øôv€_ŽãÝø™¶nEHM­»ã€žfh{:++”“ÓÝA@Y³¨­íî ‡€¬ ð ²fO')ÙÝ@ÏY³§ë×½~ÝÝA@YàdM€_5{:QÑîŽzÈš=¬,Šˆèî  ‡€¬ ð ²&À/Èš½€žb±º;è köÚÚ¨´´»ƒ€ž²&À/Èš¿ kö&&¨¼¼»ƒ€ž²f/ %…Š‹»;è kü‚¬ ð ²f/`lŒ23»;è köÕÕÝô5~AÖìàË ‹@ÖìàË ‹@Öø%ÐÝðŸïqwGþC¢¢HV¶»ƒèÉ0Ç»;ðóÙÙõöIZ3³Z;~:ÉmÑÅ ÈÄ´»é±à\³w03CEEHM­»ãèNt{ëNrÛAö† ¤Ã‡!qþ$p]z”êëgØ6 ´Ôî¤g‚¬ = .+‰óç¬Ù;hi¡††îðÄùó@Öì44З/Ý࿉ó'¬ =$Ο²&ôX8»dÍÞAWåçww€n‰³kAÖìÄÄPnnwè8»dMèù qvÈšÐ+@âìð‰z½ƒšJJêî ÿ3ûvJ,qCOŸÂ‡¼ÿÈš½FeewGøé*’Úÿzé-‡i4Èš?fh~AÖì5äå»;øíAÖì5ˆ/ Ð 5ø555ÕÖÔ¿³X¬¨¡®®ŽXñÇV¿ˆÎ÷еàn ~®ŠòŠíë¶Óé—n^â§|Ú»´€³ƒÍ‹ˆˆTVT1ŽŽŒÞºw+ÿ[¬¡Ö?xÜÈÔÃ0j55=%ýÈ™#Í‹1™Ìíë¶Ç¿Ž‘ò‚Ïš#EzoöÞyhçXû±|Ö“š”’“0gÁQQÑêªê&F“›§›¼B — ¾ç~ß¶v›ŠšÊ¡S‡ø ©3üöûM™5EGO§íH8»0wá\AAÁúºz99ÇŽ‚‚‚¡ºÚº#{ŽlÞ³YXX¸kÃë|O?dÍ^î—ûQ8ŽŸ:rjÕ†U?¶º‚¢Â2¯eû¶íã§pøýp¿ý~÷¢ïC0Žã«®’”èÐzã2ÇÐØ!ô=÷ûÃ;[,& °i÷¦1¦cø¯yü¤ñwBî0™Lþë153 :´rÝJbɃÛ¦™öüÝóæiFSKs®ëÜÇwóRg”•”5Ô·ü zÜ‘pvaùšåÄ«Û×m÷Xàáâb0¥Å¥L&³K²fcc£ˆˆj³'0 2™L&“;¿9ð`†¶×02BééÝÄoéÃûùyú_²_•B]ë¾öÀ‰œñð-Þ[:º¹OYŸ8szšZšV6V Œ›€@ oµÛ®‡D"aÆùÓÊÆêãû2?tUH?lß±}ƒLµö*w$<»`cov=ŒF£!„ääåÎïd0q¯âÖº¯}ñµ× ó ×-]|9˜Á`tr£àÀ¹&轘Læÿ+’eŽ®Žßs¾?}ü”ÞH÷Xï‘‘¥¥£e<ÄxÓªMBÂBA‚Ì,Í àYKJZêà΃´Æófäçåýôu‰Çii„Ї÷â^Æ©ª«VUV[ÄqüÖµ[‚l6›ZM]¼r1w'Æ&:-vê§Ó/)>éŠÿ•Ùγ­l¬ØlväÃH6›‘’áèꨥ­ÕvÏIˆI˜6{š¨¨(BèvðíˆÞ~Þ²r²­õ„{7ï••”±X,EeÅôäôÕ­æLPã8uïÆ=ó‘æOj·'ôÓéçwÁ/îUܦU› M ;‘€ÿœk‚ÞkóêÍ2r2s\æLt˜¸ÆmÍàaƒ'L›ð(ì‰Dª««Ó ï¼ÄÙdˆ‰Ób§þ†ý]Ü\ h¾–  àâ•‹oÝ`³ÙÓfOc³ÙAçƒB©I©{6íY°tÁ„i87q$Ä&”—•;8:̘;ƒs:Èñ1룖ŽVó“9ËQ–¡¦¦&G{G‡¹3çÍ—?âüÈ1#Édòõ+×§Ìœâìæ¼zñjbCîžîsÎõÝëk®kþ‡É9_rBQQOî=™í<{¶óìo_¾]½x•{&CMTÔT¾~þª¤¬$%-E&“]—¹ž LONŸã2G­š÷oNáâÂâÉ3&;-rº~åú£°GÜõäåä­[ºÎÝÓÝqcäÃÈ´ä4b9“É  ¾|ÚçôÍ«7ᄌ+!!ÑvHöSí ¾HIK!„™b±XÓ§·¸Ël6ÛÕÁÕnŠƒ£Ã—9Kæ,ihh J††Ž7ÆÅÝe…óŠ÷iïÇM7xØàÛ „Ì,Í„„… ¾ „Þ%¼;}ôôÄé;¹Lsi±·°X¬û·î_vœà¨¦¡v>ô<±|¦Ó̌ԌFZck=!öeì îžîýtúE…G­Ù¼FFV!Äf³ÞyèµÄ‹J¡úž÷u^âL¤L¢'hhi´ÖB†üc¤¿ÏP‹¡Û×m?uäT]m]‹aƒ.Y³×PUE55ÝÄ/„N§Ž-ü^˜žœŽd:hס]nŽnÕ•ÕŽ ¹'åÚXK\BœÁ` µŠRRQ*-.E8tbòÌÉÄÀ7pÐ@bu¾þÇü׸­¹|{©×RžÊûj÷å¾ÌVZRzñÔÅ#{Žõ>šš”š“PUY•û576:!ClÚÈĈL& « ¬ß¾>9'ù͇7£¬G¹ÎpÅqüäá“ã&#j7q܉ƒ'x¶>ÛevÜË8J5¥±±±Ÿn?Y7O·Å‹c^Ä”—f¥gqJ1Fa6ÓiæñƒÇ¹+ UVUNŒMŒŽ•–‘Ž}K,g³ØóÎsZä´rÝÊ#gŽèè"„Ú i™×² óA8ާ¼M™ã2‡hÌæ»œ—ØPß ª®Š’”PRVzr÷ QÒÐØS’[U]µ´¤”¨_L\Œøeˆùÿÿ´ä´Ô¤Ôœ/9-ÞªJ&“§Îšê´ÈéØÅc>Þ>ßs¿s^âL϶Øòs󉨔r¿æÊÊÉ’Éä/¿Ì±Ÿ# pìâ±sgð\¤ì«Ý·¤°„ÍfóÄPWÇ›MÍLœ92vÂXÏEž·ƒo7t9Èš½†¢"JKëî ~!´F“eec5ÔrèPË¡‰Ÿ‰å£mGc–û5·ù*y9y­­%&&F¤X ÈÁ®¢¬BRJ’§9™ðøpS3Ó[×n5?§±eYY^Y˜_Hü©¬¢¼ÄcÉ×O_ ò LÍLkkj•U•‰í:Ìu¸ðϦÿèçlúæÕ›ÄŸººÞ¾Þ8¯ª¬ª,¯$îùD •—•ól]LLÌÁÑ!ørðÓGOÇOz÷vÊ ʪÊV6V-&QJ…{ImM­®.äöÛ—­YÖ|-ŽvCÒ<#5CDDDDD$5)!Äd2/º˜žœñ ‚()""ÒÄhBçOÍ×j‘µõû´÷Äï5Ôbd|ùôåÇ÷._ú8T@@€çdBEMeë¾­=6r£´š°BÈ|¤yQA‹Å"6œ˜ÜÚ¦…=✔`¦ÙOSVNÖÆÞ&+ãŸóÅ÷iïm'Ø6_Ñu¹kàÙÀêÊjY9Y„ÐfÏÍ[¼·èõ×£TSˆËo !Î qFJqY‘cܤq)oSˆ1 #ÎʼnÝižø ÉÝÓýÀŽŠÊŠ­í,Bh؈aÅ…ÅĽ8Ž|ÿñÛ?Ú(ßÜñÇí¦ØYÙX1 VC­yõš»ŽãÜñKËH‡¾¤¸¤ÝÊóròÖlYc7ÅîÀ‰í† æ-œçãïSC­ñZâõ(ìwgPQSÙ~`ûÎõ;¹7Ås9=%}£ÇÆ'÷žlÚ½iãÎ->̺y×®]ÝøOÔÖ¢·oÑØ±í—ì‘üý–:ó,e=êŒÏ6›™–)((X˜_èµØ‹D&Mv˜\C­Ùâµ…Åb 6¬¤ª" ( ¨¬ØO§ÏZêšê>{}b£cååEÅDÏ?ÿåÓÝþºÓfO{ö¨ª²ª¢¬"òaäËg/5´4‡=~Ÿþ^^Q~Øða¹÷äÑGL&SG_ç¬ïÙäÄd - J5åŠÿ•âÂâáVÃ…E„ïߺ/+'ûæÕY9ÙÔ¤ÔÆ¯]¸FDB©¦\>}9#5Ã0-m-I)I11±ÐÀбÆÆ¾ˆýüñó; c”õ¨{BÃþsìçܺv+àlÀóðç:z:*j*D H¤Fì¦Øå|É9qèDC}ƒþ}bO‡˜a2™çŸ—–•®¯«ö䙼¢Þ>4mõ_«­l¬„E:öЋÈóX²¹%’ä üÀÚž‹=‹…œQHHwÇÑMÌÌZû.ˆªÊ* I Î-Âq¼ºªZN^®Ck!„êjëHd‰Dª¡ÖÈÈÊ`& PQ^!**ÚÆ1…ðp IDATS˜,ë맯 õ ýúOïqGR^V® ¨@Œ­-ª¡ÖHIK}Ïý^ð½ ¿aî°ëêêØ,6q‹M‹èt:÷s‡t:½¶¦VAQÉd’ÉdÎ…^â\VB¢å]hjj¢R¨ Š ­m…[Û!1Œ°Ð0ÇŽíÖƒãxYi™¢’b-Ó6›]VZ¦¤¬„a“ÉäžòmQIqIÞ·¼¡C[|‡ÛŸËÿôÚ䥩¥‰ãøçŸ=\=ž&>m1þè§Ñõuõ“gLæ,d±X_>~i¤54€ÓÙ¾|ü÷2ÎÑÕñ‡Ÿ•ÞrHpÕ¤¦öc«÷rðäI¯A&£ÏŸ»;ˆ_wRi †a<ÅøY !ÄIÜÉOQ©­ùF„™LÖ ßZ$JÊJm¯Nd M-MM-MÞxZÉs<±°°°°¢0jö˜fÛõ ò™2Û¨j“ç¦Yógæò<‘Ò ÔU”ùÜhs$IEõŸSÀvS&BHEU…S¾m :ƒAgJJIªk¨·X Ã0ëñÖ< Éd²Á@ž…ººÄíT [@ÖüŠ\Ü]>f}Ôë¯G<òøû:röÈíàÛÑO£0 ;p²»#Yð+246$>ðw',,ì´È©»£]î¡íMììPuuw¿1Èš½ ÖÝÀo ²&À/Èš½ |YtdÍÞ¾, :²&À/Èš¿ kö&ð±“Ð95{“~ýÐë×íôxÊ?þ都dMè}þý=Ø€5~AÖìMdeáõ 3 kö&¢¢(1±»ƒ€ßdM€_5~AÖìeÌÍákOà‡AÖìeà† èî€ÿˆô–CÝ¿w©ÝÂo ²&è’’»;@3´½Œ•ÊÉéî àwY³÷©­íî~{¹¹¹¹¹¹Ý À -‡ÒÒÒêî@ÿ58×ìeàË  kö2ðeaÐ 5~AÖøwõ2¢¢ÝAOàääÔÝ!ºœkö2²²("¢»ƒ€ßdM€_5~AÖì}ôô‹ÕÝAÀo ²fJK»;ˆß[llllllwGè5è°¼¼¼¼¼¼îŽÐ kü‚¬Ùû˜˜ òòî~K5{))T\ÜÝAÀo >€ëÛ·ow‡è5è°‘#Gvw€î3´½±1ÊÌìî à·Y³Wª®îîà·YàdÍÞ¾, ~†ãø®jf†’Þü{Éðýÿ ´ú*Bí¬Þn×Q¼ €~ñš€  ûHâÝbëº4k¿Aþ‹Â -À/Èš¿ kèÝÌÌø/Û‰¬ 5ô2?ë\ÇñêêjâV#‹õ“¶ò“P("æß.òŸ¤ó ‚ãxzz:F㕚šš¿Uí½ü$еºW×miiéßïÑ××WQQ.--355¹xñò•+—»|Cü¸yóÖöí»‚‚† kÿœN§ïßL&ëèhS©5rr²ÑÑ/÷íó–••mc­wï’ÿüsôiS×®õJJz·páAAÁºº:ù \Bµµµ{öìݳçoaaaþwÁÇÇïñã'ªªª#F GUTTÄÄÄ.Xàìè8gݺõ¯_Ǧ¤¼å¿¶ù±i‘‡‡§«ë‚ÐÐë‹-l»$ŽãgΜ«©©ÑÓÓ­¨¨üôéÓÎÛ¥¤¤~pBqŽË‚΢¢¢UUU ÃÓÓCAA¡Åò·nÝ›8qÂl«óÖ¡hsss×®]¯¦¦zêÔ‰ˆ¶£öï?8kÖ ==½æ/1™Lþ;¤Ÿßñ»wï©©©YYjll¬¬¬422ttœƒaØOˆ!„Š‹‹/] ¸yó¶­­®®.•J­­­2e²……ùOÚ"?þþ{Ïùó rù)Üù*,ìnpp(…Bqp˜ŽãxyyùÈ‘#Ƴ%Jfdd<{µv­ÿñ]¸péñã'VV£tttX,VaaatôË‹ýEEE^Ïìæ£‰ÿ8F󟼼/::Ú_¿~à,¹tÉßÐp`‹…ùù¹xñ\EEñ¯ŽãŒI“&¼yóºÝb FýÈ‘ÃoÝ å,ÉÌL.//jwÝÇìßïMüž––$$$ÈyiíÚÕsçÎ!~¯¨(vvvª««îè.ØÛß·ow#oÞ¼ÇÕÕe}ûjv¦qšÿÐh5l6½Ý¡Ñjø¯³¶¶jÈÁ8Î ½Úná•+—:´ŸógJJ¢‘‘á4OÏá9.·n…ll¬mq]ÿÓW¯ty£ñÿÓ¡hÃÂnºººtþÐóó³zµGJJbk¯¶Û!9 …ã ‡iܽúØ17·ÅÄïtz“Ik»ž‹_VV&.îg+ÎÎN—/ŸïLƒtr€b³éòòrü”ìªêØ1Ÿñãm9-`ii~öì)âϸ¸W›6mø]æ´*Ž3nÝ »‰ÿœžÉÝ…Ú8šî!C‡òŸùºx†ÖÝ}ùòåKµµµ9K.tÕÕÕùá ?ïä4€_çÓGŽøÈÈÈÌœ9ƒ³ÄÐÐpþ|§Žn‚D"q¿_¶··»~ý13)// ..ÎoèÿL&sê,((ÐÔÔÔÒÒB|ïŸ(ʾ}Ö­[ODÛvƒœ;w~íÚ??}úÄOÍ,«²²’F£‘Éä¶KÆÄÄ>|øØËË“³ÄÔÔÔÜ|˜·÷¾ŽîOÏá9.66Öïßgef¾oq]ww7>}‡жk»AÛŽó555míÕ6"ái(Ôl===RRRïÝ»ÊÏÏ_ºtÅåË £yU 㯿6{{﫪ªêhüÜòñ9¼qãæ‚‚‚ŽÖÃÑÉ ðn „„„¬­Ç^!þ>Ürÿþ½ü†þÿ0 ã P555555Ó+**ÐO P›G3:ú¥»ûò¨¨üׯù¤{e6œç† *•ùlûö­Ü 1 [¿~]óµÓÓÓŸ=‹RP›5k¦_yyù!ƒgÏžµmÛ Ã\]]BCoܽ{oäÈòòr ¸4_ëâÅK‘‘϶oß’ýáë×oÓ¦M0`BˆÉd^½zMXXXDD„N§[ŒŠzQPP ..žšš¶gÏß<ñܼy{ÆŒé< W¬X&&&Füþòå«´´tuu5aaáÉ“'!„?~R^^.##SPPÐÚ\_LLììÙ³DEEBÁÁ!<òó;*''·sçß4mÞ¼¹yyyŸ>}öðX!##ƒºyóVII)‹ÅRVVJNNùë¯ Ü5—––††ÞX¿~“ÓܶÛ3:úe``‹Ë|ƒñí[Ž~¿~Z>|Œ[¼x¡ŽÎ¿ÞÇ”••:u†B¡¬X±¬ÿþü4ˆ——'…B9sæ\aa¡»û“wŸ ---$$tö¬¿§§B()éÝíÛwÈdò¼yކ††Ü%ïÜ :tˆ÷ÂáÃ-öÙ¿¯¿ÿ…¨¨GŽ”””ôöÞÇf³=Œúöí[dä3ii)æââ,((èí½§çðÈÊÊVUU10Яªªzý:¦¦¦&?¿ÀÓÓCRR²¨¨èàÁúººžž'NœŠOؼyãýûÇgf6´3† »[QQA§3FajjÚZn-Z„PTÔ‹¢¢"„””ÔÔ©S¸‹Ý¿ÿ >>AFFfãÆõ)))7nÜ222TWW š?^UUUeeUŸ>êS¦LF±Ùìkׂ………)ª…Å0“vûL||‚¿ÿgg'k6›ýðá#6›’’êêêÂýF™G‹ Õ†aãÇÛ^¹ruÚ´©:::.œ{õêõªU^&&Æ‹/åúä!!¡cÇ|¿|ùâí½O\\ÜÃc…ŠŠJkÕ¶MQQQWW',ìÑ3¹ñ)>(>oeeehè ee%iiiÎ;3@á8~ùr›Í–——WSS#&*Û X,VBB"'õîÜùwYYÙ™3§rrrŽõ511VWW§R©%%¥kÖ¬&òSÛTxx„¶¶¶™Ùйsy¶ÕâнcÇÖ¢´´ôéÓ§R(Ô¼¼¼ŒŒÌ×óœZðÙ…¸¦½½Ýر6¡¡×ÝÜ–MŸ>uòäIíLþwèsF|‚vèPž“Ü7o^#„Š‹¿·{:üíÛG ‹a F=Ž3\]]Þ½‹g±]]]ØËb5®Zµ¢¬¬(©®®Æ™‚h¾Ž3tt´ÏŸ?ƒãŒW¯¢&N´'f fÎtxùò9Ž3êêªuuuÞ¼yÍ`Ô;:Î&êáLVðL2ܸÜZÀÑÑÏ&N´g³é F½¤¤D}=åøqßÝ»wë:9ÍåÔ™‘‘, @¾y3äÒ%{ûñþþ§9ó 8Îèßß 'çŽ3òó¿ÉËËSÇ»wï$æ$££ŸM™2 Ç÷ïßY°À¹²²„˜§š4i´iSNž}*qPÚ>Rü P|_ ¥ÜÒÒœ¨áÇ agtr€Ú³g±V\Ü+KKsg´6@8ágbb|ófˆÏáÑ£G%$Är*))Éç¾  Ë¦¦&¥¥8౓˜‡·>@‰‹‹mذîèÑCúoß¾áTÈé™­ ÝD~ýú…¡áÀŒŒdgxy­:wî4Ÿ]ˆŸ£Éb5Þººh‘khèÕ6§ý; +Ï µµû!„ yÞúÕÕÕIHHp/ ¸¢ªª‡’‘‘~ñâå!CÎ;mg7±¢¢bûö­ŠŠŠÍëoq- ‰Áƒ#„TT”‹‹KBÙÙÙIIïF¶B‰‹‹ëèh#„rrrfkãêÊ{òaX¿~ýêëë9K?~’žžÁ`0¤¤¤Ö¬YíçwÜÁa†a‚‚‚ÅÅù¢¢¢{öìMLŒ#Ö4Ȉ»62™< [Ž&›Í¾wïþ’%KËÊÊΞ=åîîÆsÏÄ!ïÚµëWõ÷GKÝx–©©©ZZZlß¾ Ã0‰ôò嫼¼ïÓy®ÄjkkWUU=yN§ÓŸ?=ÚÊÛ{ߺu¶lùKGGçÈŸèè—}ú¨÷í«YSS“’’Z\\2iÒD­5nœííÛwBC¯Óh4##C_ßcqqoúôQ733<ØÔÏ︨¨hTÔ‹¨¨è¼¼ïææf'Nœ’••-**þôéÓüùóx&”„……gÏžyø°O^^ž¤¤Ä‡ãââõõõlmÇŠˆˆXX˜?~ü$''·¸¸855ÝÚz̘1£}} ¥¥¥‡‡G$''›šš–””œ>}.55Ã0mí~RRRbbbA&ؽxýñãÇPƒam=fïÞýÑÑ/ÅÄD?õéÓ§þý ÚÛO¾v-äìYÿðð===555¿°°»T*µ¡–”ô.""rëÖí‚‚‚Ó½½÷EE½PQQž9sOË$&¾õ÷¿˜ŸŸ?dˆé½{÷ïܹËd2õõõ|}'&¾ÕÒêËbdddÆgh8ðÔ©3Ož„ëéé rèÐÑ‚‚II‰ôôŒçÏ_89Í%@MMͱc'®_¿1mÚÔeËÜûöÕl­›¨©©úú<Øôýû,QQQ2™+##sóæ-kë1<®b6cÆôK—>| >D„œž“œœrúô¹ŒŒ ‹¥¥Õ—ûù¶‚‚‚„„D‹E¥R“’Þ ëééúúKOÏ<Ø42òéíÛa C__ûƶ­µ^4bÄð[·nþüyäÈ!!¡Í;0ƒÑÔZ´£F¼~ýFyyùçÏŸ#"ž9r°²²ÒÇçXjjš>q‰ÄÀ@ÿÜ9ÿ}û¼‰i·˜˜XNO »v!D<¥wìØ ‹õüyFÛ°áÏØØ¸¶ûLu5ÅßÿBaa‘•Õ(‘[·nËÉɽzõZNN.))iÜ8Û“'O’˜“l£¡Ž;qëÖ …ÒÐÐðæMü³gϳ²²/‰ˆˆ+ÆÆÆy{ï£ÑhýµÁÆÆš³œ““³wïþ¤¤w+fÍšÉóÀâ™3ç||ü/^Ľ°¸¸øøñ“?(((|õêõýû455·mÛÒü>ž#ef6tçοÛ FŽÁÏñ8qBmmÝÓ§ÏX,Vdä³ÇŸà8>|¸å‡~x€3f´Ÿß 6›––Æ`0 èßâ•””tåÊÕÏŸ¿ „Ì͇aF¡P’“SUUUJK˃‚®FG¿ÔÑÑ÷õ=ž––®§§ûõë×€€+•C†˜jhhð P!?¿ã‘‘ÏÈ…‰‰oïÝ»¿j•×ĉ”••8=ÓÖvlkC·±ñ _ßc¯_Ǩ««±Ù¬S§Î|û–ch8P]]½.ÔîÑd2™¡¡×}}ëéénܸÞÄĘøwh•™Zº´­Ü:vп´zÉͦÿþ56ö%•ZÑF1£žsQ½*µ‚¸×£Ck±Ùô²²B6›^ZZ@¥V7òÔÔT––pßžÓü§ºº,&&:?ÿ[óbµµU<{T^^ÄdÒ(”òŠŠâÖ.5åÅÄD÷e´ý³l™qћͦge¥ Æ{¿UÛ?|¶L?ååE{÷§p/¬ª*‰‰.*Êã^xúô âþ~~¨ÔŠ×¯_ää|"š´  çÕ«¨¶Á¤R+bb¢SSß::Îf2iª«Ë8»Y]]ÖÔÔPX˜Ëy„‘Á¨o~dyzNk?µD»555´Ý7øo´õ¢ŽþÔÖVQ(å­½J§×^ä?øÖm÷‡Åj,*Êc±‰®k¨>|È8wîtkÑéuûöíi»«_¿~­3-Ü¡#ÅÓÍø\‹N¯«ª*ÅqFAAqßP稊ŠbžÏÏ•••–––ÄOƒüšT‹?„=yò ÿÎy^³߯‰š~tEвE‹Ü6mÚ```€*,,\½zííÛ7º;¨n6iÒÔ·o“´´ú&&Âç·ÃÓÓkþ|§üüüqãl9·MõB4íöí;ÎÎó»;ž¦'PfÃùÿbjÈš¿:R_ß €a˜“Ó\îe{§‚‚‚;wîNŸ>US³ÕI`@HOOÏÊÊîßß "è ¾|ù¢©©Ù%W°·ž<@AÖøYà‹„Úû¼OŽN½ÉD–VÿZòïïC4²²i«@ó ¥*@Í ð¼úßG@@·ÀS yææèôiÞUZÑ™{hùcf†ÎýÜMÐSY,ãÿ†xÀ**B-}QR‹`†@ïÆwÊD5þAÖøYàdM€_5~AÖøYàdM€_½%kþ¼@âÔüÓ?e @wëºÏ¡ý%åänßq†D"II‰WW× ìþ{¹†† BèÛ·‚Ý{.dÈ¡ÑèƒM úöUÝý÷rΊKÜvü”WRRih¨-!.Ö@kÄ04{–­ãœñ$Ò?o5²²¾íØuVA^¦¡¡QIIîó—ïÞ»W¤Ûb$ññK—ï-.®(/}Ö¡] {ñ׿ãÒÒo‚x^ZéqàöçëÿtÙ°~A‹ë9õâí§Oß54”ÕÕiôÚÚSý?×9++Ë·¸JmmýÄÉ^ÙÙÔAG|ùIDAT9îùnÜ¡P;/%åì9:°zæÌ±-ànÆoß vì<›žñ…Fk´07b±Øõ 49Yé¥î#F˜åi´ÆQ£ÝÆÚ ;tÐë?Ü@Õ“Ï5_½J64ÇØX/0àï“'þº´GEEa Ñì„„L„¶vŸ€Ë»ètFFæ—S'ÿâN™¡‹v˜ ðõ[Áæ¿]»êvûˆ³ÓD'çm^kŽØlöôººL>{fË•ÀÝnK¦GE½e±X­ci9Èiž}uuMG÷ÂÁÁz´ÕÚÚ†æ/<±±¦¦žNg´¶îú?]–ºÍøú­Ànüð«AÞ·o Üøàë¥ -®"))~ø We•Åbw4ÔÎkhh¬¨ ÔÕÓZ+ÀÝŒÚÚ}®y“HX~~éÕ ïà}wï•––5zÉÍ[ÿ¼5a2YååÕÕÕµÿÑzº›5étÆ÷Ý 2ëÖÎÇ0 !„aØß»–‰ˆ/vû»ôÖš F „¯<$fbËË«?ɯ¦ü“û÷×Zè:…ØPk:ðuáü¬H"‘ÈäŽAeeycc½Ÿò’’²:º¹ÿÀÈ‘¦Õ•/\Ln£Lá‘H${»á8BAWK$%Ås¿=8ï¿­‹ôV=v†63óë—¯sfÙ üo…„GŽ4¹wÿåçÏùýûku¨Â7o2BÓ­‰Ô¨¤$§ª¢àºh×¥Ë÷G4ýcôƒV‹ˆ!„Ølö¥Ë÷ÓÓ?KHˆVUÕ¬\1ÛØX»ª×¯SΜ½UWß0Á~äŠå³23¿lÙvJYI~ó¦…ÛwœÕ××ÌÎÎÑÓÓÜô×BqqQb•††Æý.Óhô²qã,çŒož¡#"Þ\¿©  SVVí¹ÊqèÐÍ÷ÇñÒÒ*!A==M„ÐË—ïBB#ä奫ªjìÆŸ6íîjËʪ6l䦤~Xä:UEEþIx\Zú§‘#LÖ­uFmÚ|âM|ºë‚É‹Mkl¤¯ûÓWFF¢´´ŠD"mݲXK«ýOX~Ÿš>m ñgpHø…‹w jŸ8¾ñÍ›ôŸÚ¹}ixD\JêG s#br»®®áà¡@^SS§ªªPQAa0˜kÍõجùésBHNNšg¹œ¬B(;;‡Ï¬yöÜíû^&½Ë~õ*ÙÿìV·%Ó‰å†ÝºqpÞü­/_%¿|•¼wÿ%ë1fOÚ¾ãLÐÕÇŸ>Ü~øðõ0 —wo¯ýïz§•ÕàÚÚúIS׸-žŽÒ×ïË`49½éÄÉë7n>¥V¿ ÷í7¹®®Á×çOb•Š ŠãœqÚÚ} Ëtô¦•—W{®šËçݻѳֿ¿bf6022ÞvüŠÜo¥¥%ˆWãÞ¤îPll²“Ë¢»ÑÏôïciÑ»“’b––½õbbêëÙkBè‡%Þ"¾nýá¾Û§MµháDiºü }·YSQQþØÑõ¯3ò#"bŸß²õÔ¶_O‡„ÞÍ{[|ìè:Éó1‘Hôó†c=zhuØ 9eG^6»zõ@ :YVVMî%3–ƒƒƒ!;r¤}^^1Žã¡ììB„ÐøñÃÛ78q¢KSý™³ñœàD£ÑáÆMǽ'¹úÌq×ÓÓªªª—¼”Çãs¹­!.·5;»P|ÝNÌ{ÒˆV_IIÞÁÁÂÁÁ¢ °¬ªª¾óCä>n(§™Kžlq¹­……åã=†µ/¦££¹`¾ç‰ß¯P©TÝÎÛ;f0†PNnùgvN¡Y?CƒOxâ«Øî½ç44T¶m]ܧ~m- IwG¬šš2ÐË—™ðæÍ8)ûJMË>môÊÓý­9{æ99Æg ø7 nÛ¶íËöpæ Zèñe»øK‹ÞÆôÿuÇ™§OSílÍ®^{x="öú•Ãjjªªê–¯ØŸ”œÕÊã¿Ë/ »½vÝá„S§Œt°·X¸hç“§)¬†¦Ò²êæfîÀ}MMzݘ”œ%óÞÛ ìuûinnQÔíø¤¤ÌC‡C¬­L׬ž…aØHWûÔÔÜKá1/_fž¿µnÍì¹>II™û×Ô4°ÙœQ£B†©ª*Æ=~à¿…F£Q©”––ÖȨ'åå5Ïž§dõ´¼¼fôèAQ·ŸÐ7æ^BJJή=ç\œm÷îYA§Ó6n:þâEFM-ËÜÌh¢—‹Svßà7oò#nÄòx|//çC~!CV³9))9m’¢ƒƒ9. ËÌ|wìD¸³“;½+x<þ²û‹Š*JJ+ÇŽÌd2Bff†ÇŽ_º¼C]]…¬ûó†£/_¾a±šLMz=x˜xãf\CC“¢¢œ§§³‰IÏcÇÃᬐ ½Ëƒƒ¶««+ݺrå‹Åa2e[¹¼ÃGÃêêØuuìþýM×®?RR\UZVí6zÐÎ]äˆ;ZèëFÝŽÏÉ)ÊÈÈ71éõòeæã')ÚZꇆ’‡ÑظÇÊUSÓryyü$eèëðË÷ù¹™QIIU€ÿ–•ˆˆ ½Íb5yy:QSÓ0ØÑjäHé{d³9ûöY[›bÖÐИšš{ò÷Ò ö£nßŽßøŸãû÷®psso,**ÿiÍ!î'Žoh_%99+è|dü³´9³Ç1™Œúz6Ÿ/X¾lš††JûÂ7õ·Û³7Ð{ÒˆÞ½{v‰xs}<èt‡Ó¢¡¡2g¶;ùÓ¦¦æ;ýwlÿAVVæï ïÕ«ìS§¯ÙÙ™12µµ¬ýûÜ»ÿb×Î¥o/€.â›Ìš4mû¯K¬L'ÿ,.®tq]r/ú¸¡arK`Э”Ôélmå­ßp43ã2…By‘ø†ÃiùiÕÌׯßvRÅË˹¤´êöø˜ŒâóÖ-^4IÊNwîòŸ=kœ¥eo„PQQùõˆGk3XiŒ7$ìR´Pø—3}}ŸÙî7nÆuXÅÆ¦ŸŒ ý¬ÄêŸf‘[®]{èä²èUÒÅöi¦ó¦þv••uÍÍÜwIF"ª•3Ƚ«×šã³%,t7BˆÏTTÔ …"ÙO~ÊuZ[yäã²oÝz¼g_`Ü£3äQ"bî¼mŠŠr’eß“ou†–F£Š_/\¼sÉâI┉šëãñIOQ®¬¬SWW¦P(!--5#£ÊÊ C‡öï¼…‚aدedèÎN6烣¤ï4+»°±±™|­¯¯ãâlû¡’’ƒ•ÖÁ÷¡ÎÛ¡P°?ǃ‹‹mfVÁ›7ïþ®>Û‘Ãk­­M?´W2’6Cpí~ù—ÛŠRWW¹¼C^žùóäIÊÂE;cbB,VÓÂÅ;Y/þbaØÎ?¯ãâ^-\´óÑ£¤/þ[ÀWÔ…Î5cbBâ='85·pëêØfý ]]íÉ]%•WÔ „”åÇ.Y‹ÍæÜ»ÿbó|%7b¶võìNêFDÄÖÖ±x<þÁÖº—ÂïUTÔúÜ@%$¼&RT”[0ßóÅ‹Œšša ^$%¾|3sÆòO¡Pxæl„¢¢\uuƒÏw ‚ ƒná8¡®¦¬££iooî:ÂÎgÞÖ ?Ïuq¶52êñÓª™ì­[_$f¨ª*­[;çõë·a—b¬­MÈÉäw¥22tßžâ´ñ® ôúõG,v“¾®³³M›€_¿~ûàa¢††Š“áííÚ~DYYݵ5LM{á8zWVV†Åj²·3·²2i’ŠŠâúu>©©9—¯<077ÒÕÑ<5sƘú†Æº:vÝnä1äpZ.†ÜQUUª«cOövÕÔT‹K>5{Ö8>_PPXfjÒËÀ@''§èÙóôùó&õxñ"ãÌÙë³fŽuq±Åq<*ê)Ž©i9>sÜ%¿'u(þYÚdoW&“ ‹ŽŒ|rØoššòÖm§¸\Þôi£ßWæå½_úãE„Е«*+kE"\KK-%%ççõsÅÔAÄÄ$\¾rð`«Ç–‘¡#„žcº[Zz—Ë£Ói?þ0ùÂÅ;8NLövÅqâ¬BèñãW.Þ^¾lš‘aèè„橪*"„p¿~ýÑßí,vÓÙ3¿,˜ïI¦L„PVv¡¾¾NûÓzò!D§ÓfÏwöÌ/|¾`ïöðË÷`¡ߺ.”5BL&ÃÞÞÃ0*•ê;ßsÿÁ`„Ðß‚ÇB;fȾýç%«ê"„JK«Û4Åá´|¨î‰ß/kk«ÇÅ%ÇǧÑé´¬¬ÂÅã3Ç}ë–E¬­­îííúÓª™ÖÏ]¸x'Žã!Ö?‚É‹K..®LIÉ!â_ˆ÷¤!‹÷N"„h4Úæ_| ßEæd^uv²™è½Ž ˆÎ‹ZµrƹÀ›¡W¯²}æ¸cv>ðW33ÃÈÈ'"þ:ãÏk±ôAa6cºÛ¾i'è|d÷îÏž¥ÅÅ%«¨(ÄÆ%“ÛE8>×ÇcÞÜñ«šuò÷¦¦úÐïp¨»ûP²)gg›#GÃÚ„´rÅô³þA$%eΞ5ŽÌ" L++*•J§ÓddhÍÍÜçÏ_77suu»!„嵺©‘×#˜––½ÿW’N†­««YYUG¶/žVµ³3 Ù’’“œœ•Ÿ_Òa¢R)ÞÞ®óæŽ8»e简¢¢rñ.yyùBAAŽÏØÛ›“ï`EE-B¨è}…®N7„P·njï JÕÔ”©Tjnn‘ÛØå45ÀË´©£©Ô¿ÌKê–•U“oº$òOŒB¡Lš4"À‹²’ÂX÷•ééyíÃ|+ºVÖ”¤¢¢X_ÏFÕÔ4Ë B²²ôêêÉbݺ©YYöNk÷Iv)æCu›mmú98X88XDß9F~LÿŸÜÜß¼y—‘‘âryB‘ÈÅÅ–ìâmn„P(jjj!?ý1 #_\ ¹Cþijªïwh Žãuuì΋²³3ãó…))9)©9öEEîÝäà`aaa,µýG‘kb%·466›šô"ÃÛ»gùª•\jÄá´´òø!ÉT×´ ÉÖÖŒF£%$¼~“ùÎÂÂX¼]œ¥0 ÃqBrh4U]ß®$¥öÙ¨¸¸ÒwÑ«i„áT*¥óë…::šFF=nE>ép¯œƒœ/w4ÞcØëŒ·¡aÑÁ¢öìZF32ê1cºÛÍ[cbÚw7d°µH„”InÄqüRø½6% ‚xð ñ굇ޓFôíkÐIØ€.®ËeÍ––VòÅ“§)îÃBn£3Þä“ÓÓߎ‘¸›‚pv˾ýA,V“xKaa™NwÍÕ7vÈ«”C–Á-.®¬i—ÄŸEEåœÄŸ¤†)++$¿ÊBq¹¼ÁŽViiydÉÉYt:ÍÕÕ.1ñ Y8>> !q#V|R‚a˜ŽššÒG‹aØK¼wí çiËËk ýíàOššªõõl‚ Ä“±âu§©i9ä‘7vHRr&†aä -9–6¹AUUÉÎÖL¼&(==¯}H¡å˦nÙvJ«›ú‡ŽBÈÑѲ¬¬F(’½df½sa×Iùööî òpæâbËç ¹\›Íyô(I²Aü%~…ää,„y6Ù¹ÂÂòMæ{¸=vt½x!F›ëãqæôØœ¾Û#"b%s¹ŽŽæÞ=Ë×®?,ÙiLL‚³ÓŸW‘q¿y3nïöꚆS'7.ôõOð¾EÔmÛ¶}ÙΜA =¤,{ãf\aa9“)ûøÉ«ììÂýûVÒé´!ƒ­ÂÃïÕÔ4¼}[óüàU²²ô»Å&ik«÷ïßGGGÓÁÞ|ó–S†Q(ØãǯÞWxy9cÖ¾®¼<ÓÑÑòêÕ‡eeÕåµoóK¬,{ïÙøôiZ¯^ÚBðÄÉ+¹yïÕÕ”MMõO¾vçNü„ NíC½y3.øâí·o‹Bvvf†±Xœ””œîÚêuuì¹>î‡üBpžþ:N§õp>ðð‘0œ ÒÓóø|Aß¾W¯=d³9¬†&¡PxáâíQ®}û|t°!SÓ^Ûwœõûm5Nc0dïÝOàñ…e Ì;wŸ™˜ôì߿ϣؤnÝÔjª^$fddäïÞµ´¢¢ö_HZz®©I/WWûúzöÝ»Ïy<þÃG/GŽtÈÈÈÿý䕌Œ|‘H¤ß«»ªª’x¤.ζGކ‰D¢‡^r¹¼ukç””T‰›"gÈMMz>s}÷®¥ä:äøø´3þ×KJ«ôïq#6âFBhÔ(³~†§N_Ãq<è|¤‡û0WW{É’7o=¾ñH(™˜ôò;ò2)S¿W÷††Æ3þeeÕC‡ôg0d¯^{ ¦ªüäiŠššrrr–¥Uoÿ€d$ ¿Ÿ¼’––‡aÈÐPWIIAŽÉ8áö7ÇØ¸äÜÜ¢°°>_àìl³kw@ÜãWšš*rLÆÑã—òòŠû˜ê›™º]z÷ÔékÑ1Ï{÷ÔÑÑ$…B173òð–Ÿ_²ÿ@psKkß¾úäHíìÌ„BáÑc—TU9œ–»ÑÏ55UÉ·I(^ ¿çw8¤wïžë×ûXYšU>ZÔÙ5ÀW†}ñeñ66Ò?)lî¼mnnƒÜÇ E)(ÈIîâpZD"œ\uÒ!‚ JK«JJªÌÍ””>Z—ÃiÁq¼MÉÿSvv¡@ $oÁDÕÕ±å%Ï-$·°Ùee…¢¢òââJ33Cuõ?Oࣃåñø’·Q²Ù ST”„’³ ä¹l›#)&Y¬&MMUi†V[ËRT”ûÐOðù‚Ká1sf»´‚ ªªêºuSûœ‚ŽãUUõZZj† …"ÉÁv¨¢¢¶  ÔÞÞ¼Ã[q$-ùa÷†Ÿçêëë‘“Sä3oëËÁÆÿ~"‡Ó2q¢‹x£H$ÊÍ}Ïåò,,ŒÅowTÔS:zô ÿké¬ýb”œüùÕ·.tç B¨¹…ÛÜÌíðSþCýb†ééiëéiKY÷£ ~†6—¬$aû-dRÔ××Ñ××ùÔØÚd/q~m“E:o‡N§I™2BþHBhùŠý3gŒ))­ï1¼Ãm`¦­­!e§íQ(”îÝÿ¨þÑ”‰êÞ]C\¾s<ŸÇã“*)ÉëéiuX ðQ£Úþ•Jí×ϰÍFr à;Ó…²fllòÀ}ëë J?z+è"úzeeô1Õ'¯³~»NÜ}ÿA"FÅ0,èܶ:"@WÔµfh3´t1]n -ÐeAÖ¤YdM@Z5iAÖ¤õUî×´_ü5z¾°¯’5á~M>|ã ‹Z@Z5iAÖ¤YdM@Z5iAÖ¤YdM@Z5iAÖ¤¿ÞH #⟎ø6À - -Èš€´ kÒ‚¬ H ²& -Èš€´ kÒ‚¬ H ²& ­ÿñ»Á_Ølµ£IEND®B`‚java-algebra-system-2.7.200/index.html000066400000000000000000000015271445075545500175400ustar00rootroot00000000000000 Java Algebra System (JAS) <body> <div class="nav"> <p><a href="navigate.html">Navigation without frames</a></p> <p>Please activate frames to view these pages.</p> </div> <!--p align="right" > $Id$ </p--> </body> java-algebra-system-2.7.200/intro.html000066400000000000000000000211751445075545500175650ustar00rootroot00000000000000 JAS Project

Java Algebra System (JAS) Project

Introduction. The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through a jython (Java Python) or jruby (Java Ruby) front end, there is also an Android App based on Ruboto (jruby for Android). The focus of JAS is at the moment on commutative, solvable and non-commutative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core CPU ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android to compute clusters (using MPJ a Java Message Passing Interface (MPI) or OpenMPI).

Documentation Overview

The JAS documentation consists of Web overview and summary pages, API documentation of the Java, Ruby and Python implementations and of published papers on specific topics of JAS.

For information on how to get started with JAS see the users guide or the README. For frequently asked questions see FAQ.

The software packages of the JAS library are summarized in the packages page. There is an index of algorithms for the book Gröbner bases and their JAS equivalents. An index of algorithms for the book Algorithms for Computer Algebra and their JAS equivalents is also available.

The JAS API guide describes the interface and class design considerations and contains an overview of the most important classes and methods. An online Javadoc documentation of the API together with source code is contained in the API documentation (also available as jas-doc.jar). Some design considerations for the new generic version are discussed in the problems and issues page.

JAS is open source. The licensing infos are in COPYING.jas (GPL) or COPYING.lgpl.jas (LGPL). The Java bytecode is dual licenced also under the Apache 2.0 licence to allow usage in Android projects.

A list of papers and conference talks about JAS and its design and mathematical packages is contained in the publications page.

This pages contain documentation for the latest version which is designed using type parameters and requires at least Java 8 (JDK 1.8). It may still compile on Java 7 (JDK 1.7) or Java 6 (JDK 1.6). Older versions (no more supported) can be found here: JAS 2.6, JAS 2.5, JAS 2.4, JAS 2.3, JAS 2.2, JAS 2.1, JAS 2.0, JAS using JDK 1.5 and JAS using JDK 1.4.

Download, installation and usage scenarios

Informations on obtaining JAS and its optional packages is contained in the Download page.

Usage with the JEclipse IDE

See Download and API guide pages.

Usage with the Jython interpreter

See Download and Users guide pages.

jython examples

Commutative: trinks.py, katsura.py

Solvable: wa_32.py, u_sl_3_prod.py, u_sl_3.py

Modules: armbruster.py, syz.py, syzy2.py

Usage with the JRuby interpreter

See Download and Users guide pages.

jruby examples

Commutative: trinks.rb, all_rings.rb, gbs.rb

RunGB Examples

The following are examples can be executed with the class edu.jas.application.RunGB. E.g.
java -cp .:log4j.jar:jas.jar:... edu.jas.application.RunGB <args>

Commutative: gbks.jas, katsura2.jas, katsura3.jas, katsura4.jas, katsura5.jas, katsura5s.jas, katsura5w.jas, katsura6.jas, katsura6w.jas, katsura7.jas, katsura8.jas, rose.jas, trinks6.jas, trinks7.jas, vw.jas,

The following are examples can be executed with
java -cp .:log4j.jar:jas.jar:... edu.jas.application.RunSGB <args>

Solvable: kw_18.jas, ore_t.jas, sgb.jas, u_sl_3.jas, wa_1.jas, wa_32.jas, wa_34.jas, wa_39.jas, wa_41.jas, wa_61.jas


Heinz Kredel

Last modified: Mon Jan 2 10:06:29 CET 2023

java-algebra-system-2.7.200/ivy.xml000066400000000000000000000034011445075545500170650ustar00rootroot00000000000000 Java Algebra System (JAS) java-algebra-system-2.7.200/ivysettings.xml000066400000000000000000000010621445075545500206470ustar00rootroot00000000000000 java-algebra-system-2.7.200/jas000077500000000000000000000215631445075545500162500ustar00rootroot00000000000000#!/bin/bash # $Id$ # #SCRIPT_LANG="unknown" #SCRIPT_LANG="python" SCRIPT_LANG="ruby" # DEBUG=0 ## resolve links - $0 may be a link to home PRG=$0 while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '.*/.*' > /dev/null; then if expr "$link" : '/' > /dev/null; then PRG="$link" else PRG="`dirname ${PRG}`/${link}" fi else PRG="`dirname $PRG`/$link" fi done # try to dynamically determine JAS home # (this script typically resides in JAS home) if [ -z "$JAS_HOME" ] ; then if [ "$PRG" = "./jas" ] ; then # current dir is the script dir JAS_HOME_1=`pwd` else # current dir is not the script dir JAS_HOME_1=`dirname "$PRG"` fi if [ -f "$JAS_HOME_1"/examples/jas.rb -a -f "$JAS_HOME_1"/examples/jas.py ] ; then JAS_HOME="$JAS_HOME_1" else JAS_HOME=`dirname "$JAS_HOME_1"` if [ -f "$JAS_HOME"/examples/jas.rb -a -f "$JAS_HOME"/examples/jas.py ] ; then echo -n "" else JAS_HOME="/usr/share/jas" fi fi fi # verify that JAS home is found if [ -d "$JAS_HOME/examples" ] ; then JAVA_LIBS=".:$JAS_HOME:$JAS_HOME/examples:$JAS_HOME/jas.jar" elif [ -d "examples" ] ; then JAVA_LIBS=".:examples:jas.jar" else echo "===================================" echo "Error: examples directory not found" echo "Please install JAS properly" echo "===================================" exit 0 fi # # setup required libs: JAVA_LIBS="log4j*.jar:junit*.jar:jas.jar:examples" # if [ -f "../lib/log4j-core.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:../lib/log4j-core.jar" JAVA_LIBS="$JAVA_LIBS:../lib/log4j-api.jar" elif [ -f "lib/log4j-core.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:lib/log4j-core.jar" JAVA_LIBS="$JAVA_LIBS:lib/log4j-api.jar" elif [ -f "$JAS_HOME/../lib/log4j-core.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/log4j-core.jar" JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/log4j-api.jar" elif [ -f /usr/share/java/log4j-core.jar ] ; then JAVA_LIBS="$JAVA_LIBS:`ls /usr/share/java/log4j-core.jar|tail -1`" JAVA_LIBS="$JAVA_LIBS:`ls /usr/share/java/log4j-api.jar|tail -1`" elif [ -f "../lib/log4j.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:../lib/log4j.jar" elif [ -f "lib/log4j.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:lib/log4j.jar" elif [ -f "$JAS_HOME/../lib/log4j.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/log4j.jar" else echo "==================================" echo "Error: library log4j.jar not found" echo "Please install log4j.jar" echo "==================================" exit 0 fi # if [ -f "../lib/junit-4.12.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:../lib/junit-4.12.jar" JAVA_LIBS="$JAVA_LIBS:../lib/hamcrest-core-1.3.jar" elif [ -f "lib/junit-4.12.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:lib/junit-4.12.jar" JAVA_LIBS="$JAVA_LIBS:lib/hamcrest-core-1.3.jar" elif [ -f "$JAS_HOME/../lib/junit-4.12.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/junit-4.12.jar" JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/hamcrest-core-1.3.jar" elif [ -f `ls /usr/share/java/junit4*.jar|tail -1` ] ; then JAVA_LIBS=$JAVA_LIBS:`ls /usr/share/java/junit4*.jar|tail -1` JAVA_LIBS=$JAVA_LIBS:`ls /usr/share/java/hamcrest-core-*.jar|tail -1` elif [ -f "../lib/junit.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:../lib/junit.jar" elif [ -f "lib/junit.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:lib/junit.jar" elif [ -f "$JAS_HOME/../lib/junit.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/junit.jar" elif [ -f `ls /usr/share/java/junit*.jar|tail -1` ] ; then JAVA_LIBS=$JAVA_LIBS:`ls /usr/share/java/junit*.jar|tail -1` else echo "====================================" echo "Warning: library junit.jar not found" echo "Please install junit.jar" echo "====================================" fi # if [ -d "edu/jas" ] ; then JAVA_LIBS="$JAVA_LIBS:." elif [ -f "../lib/jas.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:../lib/jas.jar" elif [ -f "lib/jas.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:lib/jas.jar" elif [ -f "jas.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:jas.jar" elif [ -f "$JAS_HOME/../lib/jas.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/../lib/jas.jar" elif [ -f "$JAS_HOME/jas.jar" ] ; then JAVA_LIBS="$JAVA_LIBS:$JAS_HOME/jas.jar" elif [ -f `ls $JAS_HOME/jas*bin.jar|tail -1` ] ; then JAVA_LIBS=$JAVA_LIBS:`ls $JAS_HOME/jas*bin.jar|tail -1` elif [ -f `ls /usr/share/java/jas*.jar|tail -1` ] ; then JAVA_LIBS=$JAVA_LIBS:`ls /usr/share/java/jas*.jar|tail -1` else echo "===============================================" echo "Error: library jas.jar or class files not found" echo "Please install jas.jar or JAS classes" echo "===============================================" exit 0 fi # #JAVA_LIBS="$JAVA_LIBS:." # #JAVA_OPTS="-J-verbose:gc -J-Xms1100M -J-Xmx1900M" #JAVA_OPTS="-J-verbose:gc -J-Xms350M -J-Xmx800M" #JAVA_OPTS="-J-Xms350M -J-Xmx800M" JAVA_OPTS="" LANGOPT=0 SCRIPT_OPTS= # # check for scripting language # Scanning for args is aborted by '--'. #set -- $JAS_OPTS "$@" #echo "jas_args: " $* while [ $# -gt 0 ] do case "$1" in # use python -py*|-jy*) SCRIPT_LANG="python" # old: LANGOPT=`jython -h 2>&1|grep '\-J\-'| grep -v '\-Jarg' -c` ;; # use ruby -rb*|-ruby|-jr*) SCRIPT_LANG="ruby" ;; -h|--help) help_requested=true ;; -d) DEBUG=1 ;; -v|--verbose) SCRIPT_OPTS="-v" ;; --) break ;; # Other opts go through -*) jas_args=("${jas_args[@]}" "$1") ;; # Abort processing on first non-opt arg *) jas_args=("${jas_args[@]}" "$1") break ;; esac shift done [[ $DEBUG > 0 ]] && echo "PRG :" $PRG [[ $DEBUG > 0 ]] && echo "JAS_HOME :" $JAS_HOME [[ $DEBUG > 0 ]] && echo "JAVA_LIBS:" $JAVA_LIBS [[ $DEBUG > 0 ]] && echo "LANGOPT :" $LANGOPT if [ "$SCRIPT_LANG" = "python" ]; then if [ -f "examples/jas.py" ] ; then echo -n "" elif [ -f "$JAS_HOME/examples/jas.py" ] ; then echo -n "" else echo "===============================" echo "Error: library jas.py not found" echo "Please install jas.py" echo "===============================" exit 0 fi TMPX=`which jython` if [[ -n $TMPX && -x $TMPX ]] ; then echo -n "" else echo "==================================" echo "Error: jython script not found" echo "Please install jython in your PATH" echo "==================================" exit 0 fi fi JASRB= if [ "$SCRIPT_LANG" = "ruby" ]; then if [ -f "examples/jas.rb" ] ; then #JASRB="examples/jas.rb" JASRB="jas" echo -n "" elif [ -f "$JAS_HOME/examples/jas.rb" ] ; then #JASRB="$JAS_HOME/examples/jas.rb" JASRB="jas" echo -n "" else echo "===============================" echo "Error: library jas.rb not found" echo "Please install jas.rb" echo "===============================" exit 0 fi TMPX=`which jruby` if [[ -n $TMPX && -x $TMPX ]] ; then echo -n "" else echo "=================================" echo "Error: jruby script not found" echo "Please install jruby in your PATH" echo "=================================" exit 0 fi fi #echo "jas_args: " $jas_args # Put the jas_args back into the position arguments $1, $2 etc set -- "${jas_args[@]}" if [ -n "$help_requested" ] ; then echo "JAS options:" >&2 echo "-py|-jy : use Python scripting with jython" >&2 echo "-rb|-jr : use Ruby scripting with jruby" >&2 echo "-d : debug this script" >&2 echo "-v : verbose option for scripting language" >&2 echo "-h|--help : this infos" >&2 echo "-- : pass remaining arguments through to Jython|JRuby" >&2 exit 0 fi # # run scripting language # if [ "$SCRIPT_LANG" = "python" ]; then if [[ $LANGOPT > 0 ]] ; then JAVA_LIBS="-J-cp $JAVA_LIBS" [[ $DEBUG > 0 ]] && echo JAVA_LIBS: $JAVA_LIBS else export CLASSPATH=$CLASSPATH:$JAVA_LIBS JAVA_LIBS="-Dpython.path=$JAVA_LIBS" export JAVA_OPTIONS="${JAVA_OPTS//-J/}" [[ $DEBUG > 0 ]] && echo CLASSPATH: $CLASSPATH [[ $DEBUG > 0 ]] && echo JAVA_OPTIONS: $JAVA_OPTIONS [[ $DEBUG > 0 ]] && echo JAVA_LIBS: $JAVA_LIBS fi #[[ $DEBUG > 0 ]] && jython --print $SCRIPT_OPTS "$JAVA_LIBS" $JAVA_OPTS $* [[ $DEBUG > 0 ]] && echo jython $SCRIPT_OPTS $JAVA_LIBS $JAVA_OPTS $* jython $SCRIPT_OPTS $JAVA_LIBS $JAVA_OPTS $* elif [ "$SCRIPT_LANG" = "ruby" ]; then if [[ "$SCRIPT_OPTS" = "-v" ]]; then SCRIPT_OPTS="-d -w -W" fi [[ $DEBUG > 0 ]] && echo jruby $SCRIPT_OPTS -J-cp "$JAVA_LIBS" $JAVA_OPTS -S jirb --noinspect --readline -r "$JASRB" $* jruby $SCRIPT_OPTS -J-cp "$JAVA_LIBS" $JAVA_OPTS -S jirb --noinspect --readline -r "$JASRB" $* else echo "===========================================" echo "Unknown scripting language $SCRIPT_LANG" echo "===========================================" exit 0 fi # java-algebra-system-2.7.200/jlinalg_adapter/000077500000000000000000000000001445075545500206565ustar00rootroot00000000000000java-algebra-system-2.7.200/jlinalg_adapter/.gitignore000066400000000000000000000000461445075545500226460ustar00rootroot00000000000000/test /*.jar /*.out /classes /*.class java-algebra-system-2.7.200/jlinalg_adapter/Makefile000066400000000000000000000035121445075545500223170ustar00rootroot00000000000000# # $Id$ # # Makefile for the JLinAlg Adapter parts # by Heinz kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib JLINALG=$(LIBPATH)/jlinalg-api_0.6.jar CLASSPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar:$(LIBPATH)/junit.jar:$(JLINALG):$(JASPATH) #CLASSPATH=$(LIBPATH)/log4j.jar:$(LIBPATH)/junit.jar:$(JLINALG):$(JASPATH) #$(LIBPATH)/jas.jar #LOG4JPATH=$(LIBPATH)/log4j-core-2.13.2.jar:$(LIBPATH)/log4j-api-2.13.2.jar #DOCOPTS=-package DOCOPTS=-package -author -version -linksource -Xdoclint:none -overview overview.html DOCCLASSES=$(CLASSPATH) DOC=javadoc -classpath $(DOCCLASSES) .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/*/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) all: clean jlinalg_adapter.jar $(CLASSES): $(FILES) Makefile -mkdir -p classes javac -classpath $(CLASSPATH) -d classes src/edu/jas/*/*.java -echo $(CLASSES) #compile: $(HOME)/java/lib/jlinalg_adapter.jar jlinalg_adapter.jar: $(CLASSES) -mkdir -p classes/META-INF cp -a manifest.mf classes/META-INF/MANIFEST.MF jar cfM jlinalg_adapter.jar -C classes . #jar uf jlinalg_adapter.jar -C src . cp -f jlinalg_adapter.jar $(LIBPATH) cp -f jlinalg_adapter.jar .. # javac -d . -cp $(JARS):. -Xlint:unchecked edu/jas/jlinalg/*.java # jar -cf $(HOME)/java/lib/jlinalg_adapter.jar edu Makefile # #jar -tvf $(HOME)/java/lib/jlinalg_adapter.jar tests: java -cp $(CLASSPATH):jlinalg_adapter.jar -Xms500M -Xmx600M -verbose:gc edu.jas.jlinalg.JLAdapterTest java -cp $(CLASSPATH):jlinalg_adapter.jar -Xms500M -Xmx600M -verbose:gc edu.jas.jlinalg.MatrixExamples clean: -rm -rf classes find . -name "*~" -follow -print -exec rm {} \; -rm -f jlinalg_adapter.jar doc: $(FILES) $(DOC) $(DOCOPTS) -d ../doc/jlinalg_adapter $(FILES) java-algebra-system-2.7.200/jlinalg_adapter/manifest.mf000066400000000000000000000000671445075545500230130ustar00rootroot00000000000000Manifest-Version: 1.0 Created-By: 1.7.0_0 (IceTea) java-algebra-system-2.7.200/jlinalg_adapter/overview.html000066400000000000000000000043061445075545500234150ustar00rootroot00000000000000 Java Algebra System, JLinAlg-Adapter

Java algebra system, JLinAlg-Adapter.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

This package contains adapters to some JLinAlg classes.

See introduction for a general overview.

For a discussion of the design and comparison to the Apache Commons Math adapter see Heinz Kredel, Fostering Interoperability in Java-Based Computer Algebra Software, Proceedings FINA Workshop AINA-2012, March 26-29, 2012, Fukuoka, Japan (slides)


Heinz Kredel

Last modified: Sat Jun 28 17:28:46 CEST 2014

$Id$

java-algebra-system-2.7.200/jlinalg_adapter/src/000077500000000000000000000000001445075545500214455ustar00rootroot00000000000000java-algebra-system-2.7.200/jlinalg_adapter/src/edu/000077500000000000000000000000001445075545500222225ustar00rootroot00000000000000java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/000077500000000000000000000000001445075545500227775ustar00rootroot00000000000000java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/000077500000000000000000000000001445075545500244175ustar00rootroot00000000000000java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/GaussElimination.java000066400000000000000000000135021445075545500305360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; import java.util.ArrayList; import org.jlinalg.AffineLinearSubspace; import org.jlinalg.LinSysSolver; import org.jlinalg.Matrix; import org.jlinalg.Vector; import org.jlinalg.polynomial.Polynomial; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Algorithms related to Gaussian elimination. Conversion to JLinAlg classes and * delegation to JLinAlg algorithms. * @param coefficient ring element type * @author Heinz Kredel */ public class GaussElimination> { /** * Solve a linear system: a x = b. * @param a matrix * @param b vector of right hand side * @return a solution vector x */ public GenVector solve(GenMatrix a, GenVector b) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); Vector> bv = JLAdapterUtil. toJLAdapterVector(b); Vector> xv = LinSysSolver.solve(am, bv); GenVector xa = JLAdapterUtil. vectorFromJLAdapter(b.modul, xv); return xa; } /** * Null space, generating system of solutions of a linear system: a x = 0. * @param a matrix * @return matrix of generating system of solution vectors x */ public GenMatrix nullSpace(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); GenVectorModul vfac = new GenVectorModul(a.ring.coFac, a.ring.cols); Vector> bv = JLAdapterUtil. toJLAdapterVector(vfac.getZERO()); ArrayList> nsl = null; int dim = 0; try { AffineLinearSubspace> ss = LinSysSolver.solutionSpace(am, bv); //System.out.println("ss = " + ss); try { ss = ss.normalize(); } catch (Exception e) { //e.printStackTrace(); } Vector>[] nsa = ss.getGeneratingSystem(); dim = nsa.length; nsl = new ArrayList>(nsa.length); for (int i = 0; i < nsa.length; i++) { nsl.add(JLAdapterUtil. listFromJLAdapter(nsa[i])); } } catch (Exception e) { //e.printStackTrace(); nsl = new ArrayList>(); } GenMatrixRing nr; if (dim > 0) { nr = new GenMatrixRing(a.ring.coFac, dim, a.ring.cols); } else { nr = new GenMatrixRing(a.ring.coFac, a.ring.rows, a.ring.cols); } GenMatrix ns = new GenMatrix(nr, nsl); if (dim > 0) { nr = nr.transpose(); ns = ns.transpose(nr); // column vectors } return ns; } /** * Test if n is a null space for the linear system: a n = 0. * @param a matrix * @param n matrix * @return true, if n is a nullspace of a, else false */ public boolean isNullSpace(GenMatrix a, GenMatrix n) { GenMatrix z = a.multiply(n); // .transpose(n.ring) better not transpose here //System.out.println("z = " + z); return z.isZERO(); } /** * Characteristic polynomial of a matrix. * @param a matrix * @return characteristic polynomial of a */ public GenPolynomial characteristicPolynomial(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); Polynomial> p = am.characteristicPolynomial(); GenPolynomialRing pfac = new GenPolynomialRing(a.ring.coFac, new String[] { "x" }); GenPolynomial cp = pfac.parse(p.toString()); return cp; } /** * Determinant of a matrix. * @param a matrix * @return determinant of a */ public C determinant(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); JLAdapter dm = am.det(); C d = dm.val; return d; } /** * Trace of a matrix. * @param a matrix * @return trace of a */ public C trace(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); JLAdapter dm = am.trace(); C d = dm.val; return d; } /** * Rank of a matrix. * @param a matrix * @return rank of a */ public int rank(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); int r = am.rank(); return r; } /** * Gauss elimination of a matrix. * @param a matrix * @return Gauss elimination of a */ public GenMatrix gaussElimination(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); Matrix> bm = am.gausselim(); GenMatrix g = JLAdapterUtil. matrixFromJLAdapter(a.ring, bm); return g; } /** * Gauss-Jordan elimination of a matrix. * @param a matrix * @return Gauss-Jordan elimination of a */ public GenMatrix gaussJordanElimination(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); Matrix> bm = am.gaussjord(); GenMatrix g = JLAdapterUtil. matrixFromJLAdapter(a.ring, bm); return g; } /** * Inverse of a matrix. * @param a matrix * @return inverse matrix of a */ public GenMatrix inverse(GenMatrix a) { Matrix> am = JLAdapterUtil. toJLAdapterMatrix(a); Matrix> bm = am.inverse(); GenMatrix g = JLAdapterUtil. matrixFromJLAdapter(a.ring, bm); return g; } } java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/JLAdapter.java000066400000000000000000000063451445075545500271000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; import org.jlinalg.DivisionByZeroException; import org.jlinalg.IRingElement; import org.jlinalg.IRingElementFactory; import org.jlinalg.operator.MonadicOperator; import edu.jas.structure.RingElem; /** * Class that wraps a JAS RingElem in an JLinALg * IRingElement. * @param JAS ring element type * @author Heinz Kredel */ public class JLAdapter> implements IRingElement> { public final C val; public JLAdapter(C v) { val = v; } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); //s.append("JLAdapter("); s.append(val.toString()); //s.append(")"); return s.toString(); } /** * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { if (!(obj instanceof JLAdapter)) { return false; } JLAdapter other = (JLAdapter) obj; return this.compareTo(other) == 0; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return val.hashCode(); } @Override public JLAdapter abs() { return new JLAdapter(val.abs()); } @Override public JLAdapter norm() { return new JLAdapter(val.abs()); } @Override public JLAdapter add(JLAdapter other) { return new JLAdapter(val.sum(other.val)); } @Override public JLAdapter apply(MonadicOperator> fun) { return fun.apply(this); } @Override public int compareTo(JLAdapter other) { return val.compareTo(other.val); } @Override public JLAdapter divide(JLAdapter other) throws DivisionByZeroException { return new JLAdapter(val.divide(other.val)); } @Override public boolean ge(JLAdapter val) { return this.compareTo(val) >= 0; } @Override public IRingElementFactory> getFactory() { return new JLAdapterFactory(val.factory()); } @Override public boolean gt(JLAdapter val) { return this.compareTo(val) > 0; } @Override public JLAdapter invert() throws DivisionByZeroException { return new JLAdapter(val.inverse()); } @Override public boolean isOne() { return val.isONE(); } @Override public boolean isZero() { return val.isZERO(); } @Override public boolean le(JLAdapter val) { return this.compareTo(val) <= 0; } @Override public boolean lt(JLAdapter val) { return this.compareTo(val) < 0; } @Override public JLAdapter multiply(JLAdapter other) { return new JLAdapter(val.multiply(other.val)); } @Override public JLAdapter negate() { return new JLAdapter(val.negate()); } @Override public JLAdapter subtract(JLAdapter other) { return new JLAdapter(val.subtract(other.val)); } } java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/JLAdapterFactory.java000066400000000000000000000153531445075545500304270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; import java.util.Random; import org.jlinalg.IRingElement; import org.jlinalg.IRingElementFactory; import org.jlinalg.Matrix; import org.jlinalg.Vector; import edu.jas.structure.ElemFactory; import edu.jas.structure.Element; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Class that wraps a JAS RingFactory in an JLinALg * IRingElementFactory. * @param JAS ring element type * @author Heinz Kredel */ public class JLAdapterFactory> implements IRingElementFactory> { public final RingFactory fac; /** * @param f */ public JLAdapterFactory(RingFactory f) { fac = f; } /** * @param f element factory */ @SuppressWarnings("unchecked") public JLAdapterFactory(ElemFactory f) { this((RingFactory) f); } /** * Get the string representation. * @see java.lang.Object#toString() */ @SuppressWarnings("unchecked") @Override public String toString() { StringBuffer s = new StringBuffer(); //s.append("JLAdapterFactory("); String f = null; try { f = ((Element) fac).toScriptFactory(); } catch (Exception ignored) { f = fac.toScript(); } if (f != null) { s.append(f); } //s.append(")"); return s.toString(); } /** * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object obj) { //System.out.println("factory equals, this = " + this + ", obj = " + obj); if (!(obj instanceof IRingElementFactory)) { return false; } IRingElementFactory other = (IRingElementFactory) obj; if (!(other instanceof JLAdapterFactory)) { return false; } JLAdapterFactory fother = (JLAdapterFactory) other; RingFactory ofac = fother.fac; //System.out.println("factory equals, this = " + fac.getClass() + ", obj = " + ofac.getClass()); if (!fac.getClass().getName().equals(ofac.getClass().getName())) { return false; } RingFactory ofac1 = null; try { ofac1 = (RingFactory) ((RingElem) ofac).factory(); } catch (ClassCastException e) { } if ( /*fac*/ofac.equals(ofac1)) { // case BigInteger etc return true; } System.out.println("factory equals, this = " + ofac + ", obj = " + ofac1); // if (fac.characteristic().equals(ffac.characteristic())) { // return true; // } return fac.equals(ofac); } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { RingFactory fac1 = null; try { fac1 = (RingFactory) ((RingElem) fac).factory(); } catch (ClassCastException e) { } if (fac.equals(fac1)) { // case BigInteger etc //int h = fac.getClass().getSimpleName().hashCode(); //h = h * 37 + fac.characteristic().hashCode(); return fac.getClass().getName().hashCode(); } return fac.hashCode(); } @Override public JLAdapter get(Object o) { if (o == null) { return null; } String s = o.toString(); return new JLAdapter(fac.parse(s)); } @Override public JLAdapter get(int i) { return new JLAdapter(fac.fromInteger(i)); } @Override public JLAdapter get(long i) { return new JLAdapter(fac.fromInteger(i)); } @Override public JLAdapter get(double d) { throw new RuntimeException("not implemented " + d); } @SuppressWarnings({ "unchecked", "cast" }) @Override public JLAdapter[] getArray(int size) { JLAdapter[] arr = (JLAdapter[]) new JLAdapter[size]; for (int i = 0; i < arr.length; i++) { arr[i] = zero(); } return arr; } @SuppressWarnings({ "unchecked", "cast" }) @Override public JLAdapter[][] getArray(int rows, int columns) { JLAdapter[][] arr = (JLAdapter[][]) new JLAdapter[rows][columns]; for (int i = 0; i < arr.length; i++) { arr[i] = getArray(columns); } return arr; } /** * Minus one? OK * @see org.jlinalg.IRingElementFactory#m_one() */ @Override public JLAdapter m_one() { return new JLAdapter(fac.getONE().negate()); } @Override public JLAdapter one() { return new JLAdapter(fac.getONE()); } @Override public JLAdapter zero() { return new JLAdapter(fac.getZERO()); } @Deprecated @Override public JLAdapter randomValue(Random random) { return new JLAdapter(fac.random(3, random)); } @Override public JLAdapter randomValue() { return new JLAdapter(fac.random(3)); } @Deprecated @Override public JLAdapter gaussianRandomValue(Random random) { throw new RuntimeException("not implemented " + random); } @Override public JLAdapter gaussianRandomValue() { throw new RuntimeException("not implemented"); } @Deprecated @Override public JLAdapter randomValue(Random random, JLAdapter min, JLAdapter max) { throw new RuntimeException("not implemented"); } @Override public JLAdapter randomValue(JLAdapter min, JLAdapter max) { throw new RuntimeException("not implemented"); } @SuppressWarnings({ "unchecked", "cast" }) @Override public Vector> convert(Vector> from) { //if (true) { // throw new RuntimeException("not implemented"); //} JLAdapter[] to = (JLAdapter[]) new JLAdapter[from.length()]; for (int row = 0; row < from.length(); row++) { to[row] = this.get(from.getEntry(row)); } return new Vector>(to, this); } @SuppressWarnings({ "unchecked", "cast" }) @Override public Matrix> convert(Matrix> from) { //if (true) { // throw new RuntimeException("not implemented"); //} JLAdapter[][] to = (JLAdapter[][]) new JLAdapter[from.getRows()][from.getCols()]; for (int row = 0; row < from.getRows(); row++) { for (int col = 0; col < from.getCols(); col++) { to[row][col] = this.get(from.get(row, col)); } } return new Matrix>(to, this); } } java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/JLAdapterTest.java000066400000000000000000000137651445075545500277440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; import java.util.Arrays; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * JLAdapter tests with JUnit * @author Heinz Kredel. */ public class JLAdapterTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a JLAdapterTest object. * @param name String. */ public JLAdapterTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(JLAdapterTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. */ public void testConstruction() { BigRational z = new BigRational(0); JLAdapter a = new JLAdapter(z); //System.out.println("a = " + a); assertTrue("isZero( a )", a.isZero()); BigRational o = new BigRational(1); JLAdapter b = new JLAdapter(o); //System.out.println("b = " + b); assertTrue("isOne( b )", b.isOne()); JLAdapter c = b.subtract(b); //System.out.println("c = " + c); assertTrue("isZero( c )", c.isZero()); assertEquals("a == c ", a, c); c = new JLAdapter(new BigRational(1, 2)); //System.out.println("c = " + c); assertTrue("!isZero( c )", !c.isZero()); JLAdapter d = c.invert(); //System.out.println("d = " + d); assertTrue("!isZero( d )", !d.isZero()); assertTrue("isOne( 1/2 * 2 ) ", d.multiply(c).isOne()); JLAdapter e = b.divide(d); //System.out.println("e = " + e); assertEquals("1/2 == 1 / (2) ", c, e); } /** * Test factory and toString. */ public void testFactory() { RingFactory z = new BigRational(0); JLAdapterFactory fac = new JLAdapterFactory(z); //System.out.println("fac = " + fac); JLAdapter a = fac.zero(); //System.out.println("a = " + a); assertTrue("isZero( a )", a.isZero()); JLAdapter b = fac.one(); //System.out.println("b = " + b); assertTrue("isOne( b )", b.isOne()); } /** * Test matrix solve. */ public void xtestGenMatrixSolv() { //MatrixExamples gms = new MatrixExamples(); MatrixExamples.main(null); } /** * Test vector conversions. */ public void testVectorConversion() { RingFactory z = new BigRational(0); JLAdapterFactory fac = new JLAdapterFactory(z); JLAdapter[] vec1 = fac.getArray(ll); //System.out.println("vec1 =" + Arrays.toString(vec1)); RingElem[] v1 = JLAdapterUtil. fromJLAdapter(vec1); //System.out.println("v1 =" + Arrays.toString(v1)); JLAdapter[] vec2 = JLAdapterUtil. toJLAdapterRE(v1); //System.out.println("vec2 =" + Arrays.toString(vec2)); assertTrue("v1[] == v2[] ", Arrays.equals(vec1, vec2)); BigRational[] v2 = new BigRational[ll]; for (int i = 0; i < v2.length; i++) { v2[i] = z.random(kl); } //System.out.println("v2 =" + Arrays.toString(v2)); JLAdapter[] vec3 = JLAdapterUtil. toJLAdapter(v2); //System.out.println("vec3 =" + Arrays.toString(vec3)); RingElem[] v3 = JLAdapterUtil. fromJLAdapter(vec3); //System.out.println("v3 =" + Arrays.toString(v3)); assertTrue("v2[] == v3[] ", Arrays.equals(v2, v3)); } /** * Test matrix conversions. */ public void testMatrixConversion() { RingFactory z = new BigRational(0); JLAdapterFactory fac = new JLAdapterFactory(z); JLAdapter[][] vec1 = fac.getArray(ll, ll); //System.out.println("vec1 =" + matrixToString(vec1)); RingElem[][] v1 = JLAdapterUtil. fromJLAdapter(vec1); //System.out.println("v1 =" + matrixToString(v1)); JLAdapter[][] vec2 = JLAdapterUtil. toJLAdapterRE(v1); //System.out.println("vec2 =" + matrixToString(vec2)); assertMatrixEquals(vec1, vec2); BigRational[][] v2 = new BigRational[ll][]; for (int i = 0; i < v2.length; i++) { v2[i] = new BigRational[ll]; for (int j = 0; j < v2.length; j++) { v2[i][j] = z.random(kl); } } //System.out.println("v2 =" + matrixToString(v2)); JLAdapter[][] vec3 = JLAdapterUtil. toJLAdapter(v2); //System.out.println("vec1 =" + matrixToString(vec3)); RingElem[][] v3 = JLAdapterUtil. fromJLAdapter(vec3); //System.out.println("v3 =" + matrixToString(v3)); //v3[0][0] = v3[1][1]; assertMatrixEquals(v2, v3); } public String matrixToString(Object[][] m) { StringBuffer s = new StringBuffer("["); for (int i = 0; i < m.length; i++) { if (i != 0) { s.append(", "); } s.append(Arrays.toString(m[i])); } s.append("]"); return s.toString(); } public void assertMatrixEquals(Object[][] m1, Object[][] m2) { for (int i = 0; i < m1.length; i++) { assertTrue("m1[][] == m2[][] ", Arrays.equals(m1[i], m2[i])); } } } java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/JLAdapterUtil.java000066400000000000000000000300341445075545500277260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; // import static edu.jas.jlinalg.JLAdapterUtil.toArray; import java.util.ArrayList; import java.util.List; import org.jlinalg.Matrix; import org.jlinalg.Vector; import edu.jas.structure.RingElem; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Conversion utilities. * @author Heinz Kredel */ public class JLAdapterUtil { public static > C[] toArray(GenVector a) { if (a == null) { return null; } return toArray(a.val); } @SuppressWarnings("unchecked") public static > C[] toArray(List a) { if (a == null) { return null; } C[] av = (C[]) new RingElem[a.size()]; int i = 0; for (C e : a) { av[i++] = e; } return av; } public static > ArrayList toList(C[] a) { if (a == null) { return null; } ArrayList av = new ArrayList(a.length); for (int i = 0; i < a.length; i++) { av.add(a[i]); } return av; } public static > ArrayList> toList(C[][] a) { if (a == null) { return null; } ArrayList> av = new ArrayList>(a.length); for (int i = 0; i < a.length; i++) { av.add(JLAdapterUtil. toList(a[i])); } return av; } public static > C[][] toArray(GenMatrix a) { if (a == null) { return null; } return toArrayFromList(a.matrix); } @SuppressWarnings("unchecked") public static > C[][] toArrayFromList(List> a) { // Array only once if (a == null) { return null; } C[][] av = (C[][]) new RingElem[a.size()][]; int i = 0; for (List e : a) { av[i++] = toArray(e); } return av; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v array of ring elements * @return array of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[] toJLAdapter(C[] v) { if (v == null) { return null; } JLAdapter[] va = (JLAdapter[]) new JLAdapter[v.length]; for (int i = 0; i < v.length; i++) { va[i] = new JLAdapter(v[i]); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v array of ring elements * @return array of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[] toJLAdapterRE(RingElem[] v) { if (v == null) { return null; } JLAdapter[] va = (JLAdapter[]) new JLAdapter[v.length]; for (int i = 0; i < v.length; i++) { va[i] = new JLAdapter((C) v[i]); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v JAS vector of ring elements * @return array of JLAdapter objects */ public static > JLAdapter[] toJLAdapter(GenVector v) { if (v == null) { return null; } JLAdapter[] va = JLAdapterUtil. toJLAdapter(v.val); return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v list of ring elements * @return array of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[] toJLAdapter(List v) { if (v == null) { return null; } JLAdapter[] va = (JLAdapter[]) new JLAdapter[v.size()]; for (int i = 0; i < v.size(); i++) { va[i] = new JLAdapter(v.get(i)); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v JAS vector of ring elements * @return JLinAlg vector of JLAdapter objects */ public static > Vector> toJLAdapterVector(GenVector v) { if (v == null) { return null; } Vector> va = new Vector>(JLAdapterUtil. toJLAdapter(v.val)); return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v matrix of ring elements * @return matrix of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[][] toJLAdapter(C[][] v) { if (v == null) { return null; } JLAdapter[][] va = (JLAdapter[][]) new JLAdapter[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = JLAdapterUtil. toJLAdapter(v[i]); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v matrix of ring elements * @return matrix of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[][] toJLAdapterRE(RingElem[][] v) { if (v == null) { return null; } JLAdapter[][] va = (JLAdapter[][]) new JLAdapter[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = JLAdapterUtil. toJLAdapterRE(v[i]); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v JAS matrix of ring elements * @return array of JLAdapter objects */ public static > JLAdapter[][] toJLAdapter(GenMatrix v) { if (v == null) { return null; } JLAdapter[][] va = JLAdapterUtil. toJLAdapterFromList(v.matrix); return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v list of lists of ring elements * @return array of JLAdapter objects */ @SuppressWarnings({ "unchecked", "cast" }) public static > JLAdapter[][] toJLAdapterFromList(List> v) { if (v == null) { return null; } JLAdapter[][] va = (JLAdapter[][]) new JLAdapter[v.size()][]; for (int i = 0; i < v.size(); i++) { va[i] = JLAdapterUtil. toJLAdapter(v.get(i)); } return va; } /** * Convert JAS RingElem to JLinAlg IRingElement. * @param ring element type * @param v JAS vector of ring elements * @return JLinAlg vector of JLAdapter objects */ public static > Matrix> toJLAdapterMatrix(GenMatrix v) { if (v == null) { return null; } Matrix> va = new Matrix>(JLAdapterUtil. toJLAdapterFromList(v.matrix)); return va; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v array of JLAdapter objects * @return array of ring elements */ @SuppressWarnings("unchecked") public static > C[] fromJLAdapter(JLAdapter[] v) { if (v == null) { return null; } C[] va = (C[]) new RingElem[v.length]; for (int i = 0; i < v.length; i++) { if (v[i] != null) { va[i] = v[i].val; } else { va[i] = null; } } return va; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v matrix of JLAdapter objects * @return matrix of ring elements */ @SuppressWarnings("unchecked") public static > C[][] fromJLAdapter(JLAdapter[][] v) { if (v == null) { return null; } C[][] va = (C[][]) new RingElem[v.length][]; for (int i = 0; i < v.length; i++) { va[i] = JLAdapterUtil. fromJLAdapter(v[i]); } return va; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v JLinAlg vector of JLAdapter objects * @return array of ring elements */ @SuppressWarnings("unchecked") public static > C[] fromJLAdapter(Vector> v) { if (v == null) { return null; } C[] va = (C[]) new RingElem[v.length()]; for (int i = 0; i < va.length; i++) { JLAdapter e = v.getEntry(i + 1); if (e != null) { va[i] = e.val; } else { va[i] = null; } } return va; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v JLinAlg vector of JLAdapter objects * @return Java list of ring elements */ public static > ArrayList listFromJLAdapter(Vector> v) { if (v == null) { return null; } ArrayList vv = new ArrayList(v.length()); for (int i = 0; i < v.length(); i++) { JLAdapter e = v.getEntry(i + 1); if (e != null) { vv.add(e.val); } else { vv.add(null); } } return vv; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v JLinAlg vector of JLAdapter objects * @return JAS vector of ring elements */ public static > GenVector vectorFromJLAdapter(GenVectorModul fac, Vector> v) { if (v == null) { return null; } List list = listFromJLAdapter(v); GenVector vv = new GenVector(fac, list); return vv; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v JLinAlg vector of JLAdapter objects * @return Java list of ring elements */ public static > List> listFromJLAdapter(Matrix> v) { if (v == null) { return null; } ArrayList> vv = new ArrayList>(v.getRows()); for (int i = 0; i < v.getRows(); i++) { Vector> e = v.getRow(i + 1); List l = listFromJLAdapter(e); vv.add(l); } return vv; } /** * Convert JLinAlg IRingElement to JAS RingElem * to. * @param ring element type * @param v JLinAlg vector of JLAdapter objects * @return JAS matrix of ring elements */ public static > GenMatrix matrixFromJLAdapter(GenMatrixRing fac, Matrix> v) { if (v == null) { return null; } List> list = listFromJLAdapter(v); GenMatrix vv = new GenMatrix(fac, list); return vv; } } java-algebra-system-2.7.200/jlinalg_adapter/src/edu/jas/jlinalg/MatrixExamples.java000066400000000000000000000262601445075545500302330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.jlinalg; import org.jlinalg.LinSysSolver; import org.jlinalg.Matrix; import org.jlinalg.Vector; import org.jlinalg.polynomial.Polynomial; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Example that computes a solution of a linear equation system. * @author Heinz Kredel */ public class MatrixExamples { public static void main(String[] argv) { example1(); example2(); example3(); } @SuppressWarnings({ "unchecked" }) public static void example1() { BigRational r1, r2, r3, r4, r5, r6, z; r1 = new BigRational(1, 10); r2 = new BigRational(6, 5); r3 = new BigRational(1, 9); r4 = new BigRational(1, 1); r5 = r2.sum(r3); r6 = r1.multiply(r4); z = new BigRational(); JLAdapter r1a, r2a, r3a, r4a, r5a, r6a, d, t, za; r1a = new JLAdapter(r1); r2a = new JLAdapter(r2); r3a = new JLAdapter(r3); r4a = new JLAdapter(r4); r5a = new JLAdapter(r5); r6a = new JLAdapter(r6); za = new JLAdapter(z); Matrix> a = new Matrix>( new JLAdapter[][] { { r1a, r2a, r3a }, { r4a, r5a, r6a } }); System.out.println("system = " + a); Vector> b = new Vector>(new JLAdapter[] { r1a, r2a }); System.out.println("rhs = " + b); Vector> solution = LinSysSolver.solve(a, b); System.out.println("x = " + solution); System.out.println("solutionSpace = " + LinSysSolver.solutionSpace(a, b)); Vector> bz = new Vector>(new JLAdapter[] { za, za }); System.out.println("rhs = " + bz); System.out.println("nullSolutionSpace = " + LinSysSolver.solutionSpace(a, bz)); Matrix> m = new Matrix>( new JLAdapter[][] { { r1a, r2a, r3a }, { r4a, r5a, r6a }, { r2a, r1a, r3a } }); System.out.println("matrix = " + m); m = m.multiply(m); System.out.println("matrix^2 = " + m); d = m.det(); System.out.println("det(matrix^2) = " + d); t = m.trace(); System.out.println("trace(matrix^2) = " + t); Polynomial> cp = m.characteristicPolynomial(); System.out.println("charPol(matrix^2) = " + cp); Polynomial> mp = m.minimalPolynomial(); System.out.println("minPol(matrix^2) = " + mp); Matrix> mg = m.gausselim(); System.out.println("matrix, gauss = " + mg); Matrix> m2 = new Matrix>(new JLAdapter[][] { { r1a, r2a, r3a, r4a }, { r4a, r5a, r6a, r1a }, { r2a, r1a, r3a, r5a } }); System.out.println("matrix_2 = " + m2); Matrix> mj = m2.gaussjord(); System.out.println("matrix,gauss-jordan = " + mj); try { System.out.println("matrix,eigenvalue = "); // + m.eig()); fails for Double } catch (org.jlinalg.InvalidOperationException e) { System.out.println("" + e); } } @SuppressWarnings({ "unchecked" }) public static void example2() { BigRational r1, r2, r3, r4, r5, r6, z; r1 = new BigRational(1, 10); r2 = new BigRational(6, 5); r3 = new BigRational(1, 9); r4 = new BigRational(1, 1); r5 = r2.sum(r3); r6 = r1.multiply(r4); z = new BigRational(); JLAdapter d, t; Matrix> a = new Matrix>(JLAdapterUtil . toJLAdapter(new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 } })); System.out.println("system = " + a); Vector> b = new Vector>( JLAdapterUtil. toJLAdapter(new BigRational[] { r1, r2 })); System.out.println("rhs = " + b); Vector> solution = LinSysSolver.solve(a, b); System.out.println("x = " + solution); System.out.println("solutionSpace = " + LinSysSolver.solutionSpace(a, b)); Vector> bz = new Vector>( JLAdapterUtil. toJLAdapter(new BigRational[] { z, z })); System.out.println("rhs = " + bz); System.out.println("nullSolutionSpace = " + LinSysSolver.solutionSpace(a, bz)); Matrix> m = new Matrix>( JLAdapterUtil. toJLAdapter(new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 }, { r2, r1, r3 } })); System.out.println("matrix = " + m); m = m.multiply(m); System.out.println("matrix^2 = " + m); d = m.det(); System.out.println("det(matrix^2) = " + d); t = m.trace(); System.out.println("trace(matrix^2) = " + t); Polynomial> cp = m.characteristicPolynomial(); System.out.println("charPol(matrix^2) = " + cp); Polynomial> mp = m.minimalPolynomial(); System.out.println("minPol(matrix^2) = " + mp); Matrix> mg = m.gausselim(); System.out.println("matrix, gauss = " + mg); Matrix> m2 = new Matrix>( JLAdapterUtil. toJLAdapter(new BigRational[][] { { r1, r2, r3, r4 }, { r4, r5, r6, r1 }, { r2, r1, r3, r5 } })); System.out.println("matrix_2 = " + m2); Matrix> mj = m2.gaussjord(); System.out.println("matrix,gauss-jordan = " + mj); try { System.out.println("matrix,eigenvalue = "); // + m.eig()); fails for Double } catch (org.jlinalg.InvalidOperationException e) { System.out.println("" + e); } } @SuppressWarnings({ "unchecked" }) public static void example3() { BigRational r1, r2, r3, r4, r5, r6, fac; r1 = new BigRational(1, 10); r2 = new BigRational(6, 5); r3 = new BigRational(1, 9); r4 = new BigRational(1, 1); r5 = r2.sum(r3); r6 = r1.multiply(r4); fac = new BigRational(); //JLAdapter d, t; BigRational[][] aa = new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 } }; GenMatrixRing mfac = new GenMatrixRing(fac, aa.length, aa[0].length); GenMatrix a = new GenMatrix(mfac, JLAdapterUtil. toList(aa)); System.out.println("system = " + a); BigRational[] ba = new BigRational[] { r1, r2 }; GenVectorModul vfac = new GenVectorModul(fac, ba.length); GenVector b = new GenVector(vfac, JLAdapterUtil. toList(ba)); System.out.println("right hand side = " + b); GaussElimination ge = new GaussElimination(); GenVector x = ge.solve(a, b); System.out.println("solution = " + x); BigRational[][] am = new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 }, { r2, r1, r3 } }; GenMatrixRing mfacm = new GenMatrixRing(fac, am.length, am[0].length); GenMatrix m = new GenMatrix(mfacm, JLAdapterUtil. toList(am)); System.out.println("matrix = " + m); GenPolynomial p = ge.characteristicPolynomial(m); System.out.println("characteristicPolynomial = " + p); // m = m.multiply(m); // System.out.println("matrix = " + m); // p = ge.characteristicPolynomial(m); // System.out.println("characteristicPolynomial = " + p); m = mfacm.getONE(); System.out.println("matrix = " + m); p = ge.characteristicPolynomial(m); System.out.println("characteristicPolynomial = " + p); m = mfacm.getZERO(); System.out.println("matrix = " + m); p = ge.characteristicPolynomial(m); System.out.println("characteristicPolynomial = " + p); m = mfacm.getONE(); System.out.println("matrix = " + m); GenMatrix ns = ge.nullSpace(m); System.out.println("nullSpace = " + ns); System.out.println("isNullSpace = " + ge.isNullSpace(m, ns)); am = new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 }, { r4, r5, r6 } }; mfacm = new GenMatrixRing(fac, am.length, am[0].length); m = new GenMatrix(mfacm, JLAdapterUtil. toList(am)); System.out.println("matrix = " + m); ns = ge.nullSpace(m); System.out.println("nullSpace = " + ns); System.out.println("isNullSpace = " + ge.isNullSpace(m, ns)); //System.out.println("isNullSpace = " + ge.isNullSpace(ns,m)); //System.out.println("isNullSpace = " + ge.isNullSpace(m,ns.transpose(mfacm))); m = mfacm.getZERO(); System.out.println("matrix = " + m); ns = ge.nullSpace(m); System.out.println("nullSpace = " + ns); System.out.println("isNullSpace = " + ge.isNullSpace(m, ns)); int kl = 3; int ll = 10; mfac = new GenMatrixRing(fac, ll, ll + 1); m = mfac.random(kl); System.out.println("matrix = " + m); m = ge.gaussElimination(m); System.out.println("Gauss elimination = " + m); m = ge.gaussJordanElimination(m); System.out.println("Gauss-Jordan elimination = " + m); mfac = new GenMatrixRing(fac, ll, ll); m = mfac.random(kl); System.out.println("matrix = " + m); GenMatrix mi = null; try { mi = ge.inverse(m); System.out.println("inverse = " + mi); if (mi != null) { GenMatrix tt = m.multiply(mi); boolean inv = tt.isONE(); if (!inv) { System.out.println("m * inverse = " + tt); } System.out.println("isInverse = " + inv); } } catch (Exception ignored) { } kl = 3; ll = 10; // for ll > 40 must adjust JVM parameters, e.g. -Xms500M -Xmx600M mfac = new GenMatrixRing(fac, ll, ll); m = mfac.random(kl); //System.out.println("matrix = " + m); m = ge.gaussElimination(m); //System.out.println("Gauss elimination = " + m); m = ge.gaussJordanElimination(m); //System.out.println("Gauss-Jordan elimination = " + m); System.out.println("is Gauss-Jordan elimination = " + m.isONE()); } } java-algebra-system-2.7.200/jruby_tests.sh000066400000000000000000000050451445075545500204530ustar00rootroot00000000000000#!/bin/sh # run some rb files #OPTS="-J-cp ../lib/log4j.jar:../lib/junit.jar:." OPTS="-J-cp ../lib/log4j-core-2.17.1.jar:../lib/log4j-api-2.17.1.jar:../lib/junit.jar-4.13.1.jar:../lib/hamcrest-core-1.3.jar:. -I." echo jruby $OPTS -J-verbose:gc examples/all_rings.rb time jruby $OPTS -J-verbose:gc examples/all_rings.rb echo jruby $OPTS -J-verbose:gc examples/trinks.rb time jruby $OPTS -J-verbose:gc examples/trinks.rb echo jruby $OPTS -J-verbose:gc examples/0dim_primary-decomp.rb time jruby $OPTS -J-verbose:gc examples/0dim_primary-decomp.rb echo jruby $OPTS -J-verbose:gc examples/0dim_prime-decomp.rb time jruby $OPTS -J-verbose:gc examples/0dim_prime-decomp.rb echo jruby $OPTS -J-verbose:gc examples/0dim_radical.rb time jruby $OPTS -J-verbose:gc examples/0dim_radical.rb echo jruby $OPTS -J-verbose:gc examples/cgb_0.rb time jruby $OPTS -J-verbose:gc examples/cgb_0.rb echo jruby $OPTS -J-verbose:gc examples/cgb_2.rb time jruby $OPTS -J-verbose:gc examples/cgb_2.rb echo jruby $OPTS -J-verbose:gc examples/chebyshev.rb time jruby $OPTS -J-verbose:gc examples/chebyshev.rb echo jruby $OPTS -J-verbose:gc examples/e-gb.rb time jruby $OPTS -J-verbose:gc examples/e-gb.rb echo jruby $OPTS -J-verbose:gc examples/eliminate.rb time jruby $OPTS -J-verbose:gc examples/eliminate.rb echo jruby $OPTS -J-verbose:gc examples/factors.rb time jruby $OPTS -J-verbose:gc examples/factors.rb echo jruby $OPTS -J-verbose:gc examples/factors_abs.rb time jruby $OPTS -J-verbose:gc examples/factors_abs.rb echo jruby $OPTS -J-verbose:gc examples/factors_abs_complex.rb time jruby $OPTS -J-verbose:gc examples/factors_abs_complex.rb echo jruby $OPTS -J-verbose:gc examples/factors_abs_mult.rb time jruby $OPTS -J-verbose:gc examples/factors_abs_mult.rb echo jruby $OPTS -J-verbose:gc examples/factors_algeb.rb time jruby $OPTS -J-verbose:gc examples/factors_algeb.rb echo jruby $OPTS -J-verbose:gc examples/getstart.rb time jruby $OPTS -J-verbose:gc examples/getstart.rb echo jruby $OPTS -J-verbose:gc examples/hawes2.rb time jruby $OPTS -J-verbose:gc examples/hawes2.rb echo jruby $OPTS -J-verbose:gc examples/module.rb time jruby $OPTS -J-verbose:gc examples/module.rb echo jruby $OPTS -J-verbose:gc examples/polynomial.rb time jruby $OPTS -J-verbose:gc examples/polynomial.rb echo jruby $OPTS -J-verbose:gc examples/polypower.rb time jruby $OPTS -J-verbose:gc examples/polypower.rb echo jruby $OPTS -J-verbose:gc examples/powerseries.rb time jruby $OPTS -J-verbose:gc examples/powerseries.rb echo jruby $OPTS -J-verbose:gc examples/prime-decomp.rb time jruby $OPTS -J-verbose:gc examples/prime-decomp.rb java-algebra-system-2.7.200/jython/000077500000000000000000000000001445075545500170515ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/.gitignore000066400000000000000000000000151445075545500210350ustar00rootroot00000000000000/test /*.jar java-algebra-system-2.7.200/jython/Makefile000066400000000000000000000042711445075545500205150ustar00rootroot00000000000000# # $Id$ # # Makefile for the interface of JAS to jython # by Raphael Jolly, Heinz kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib JYTHONPATH=$(HOME)/java/jython/jython.jar JRUBYPATH=$(HOME)/java/jruby/lib/jruby.jar:$(HOME)/java/jruby/lib/ruby/stdlib LOG4JPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar JUNITPATH=$(LIBPATH)/junit.jar:$(LIBPATH)/hamcrest-core.jar CLASSPATH=$(LOG4JPATH):$(JUNITPATH):$(JASPATH):$(LIBPATH)/jas.jar BOOTCLASSPATH6="/usr/lib64/jvm/java-1.6.0/jre/lib/rt.jar" .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/*/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) #DOCOPTS=-package DOCOPTS=-package -author -version -linksource -overview overview.html DOCCLASSES=$(CLASSPATH) DOC=javadoc -classpath $(DOCCLASSES):$(JYTHONPATH) all: clean jas-jython.jar $(CLASSES): $(FILES) -mkdir -p classes javac -g -classpath $(JYTHONPATH):$(CLASSPATH) -sourcepath src -d classes src/edu/jas/*/*.java #javac -g -source 1.6 -target 1.6 -classpath $(JYTHONPATH):$(CLASSPATH) -bootclasspath $(BOOTCLASSPATH6) -sourcepath src -d classes src/edu/jas/*/*.java jas-jython.jar: $(CLASSES) $(JASPATH)/examples/jas.py services/javax.script.ScriptEngineFactory -mkdir -p classes/META-INF -mkdir -p classes/META-INF/services -cp -a manifest.mf classes/META-INF/MANIFEST.MF #cp -a services/javax.script.ScriptEngineFactory classes/META-INF/services/ -cp -a $(JASPATH)/examples/jas.py $(JASPATH)/examples/*.class $(JASPATH)/examples/basic_sigbased_gb.py classes #-cp -a $(JASPATH)/examples/jas.pyc classes -cp -a $(JASPATH)/examples/jas.rb classes -cp -a $(JASPATH)/log4j2.properties classes jar cfM jas-jython.jar -C classes . cp -f jas-jython.jar $(LIBPATH) cp -f jas-jython.jar .. clean: rm -rf classes find . -name "*~" -follow -print -exec rm {} \; tests: jas-jython.jar java -client -cp $(JYTHONPATH):$(JRUBYPATH):$(CLASSPATH):jas-jython.jar edu.jas.gb.GBSigBasedTest exam: jas-jython.jar java -client -cp $(JYTHONPATH):$(JRUBYPATH):$(CLASSPATH):jas-jython.jar edu.jas.kern.ScriptingExample doc: $(FILES) $(DOC) $(DOCOPTS) -d ../doc/jas-jython $(FILES) java-algebra-system-2.7.200/jython/manifest.mf000066400000000000000000000000671445075545500212060ustar00rootroot00000000000000Manifest-Version: 1.0 Created-By: 1.7.0_0 (IceTea) java-algebra-system-2.7.200/jython/overview.html000066400000000000000000000043211445075545500216050ustar00rootroot00000000000000 Java Algebra System, Apache Commons Math-Adapter

Java algebra system, Jython access to Signature based Gröber base Python scripts.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

This package contains example adapters to the Python scripts of Ebert and Perry for the computation of signature based Gröber base algorithms.

See introduction for a general overview.

The original Python - Sage - Singular scripts from Eder and Perry are available at http://www.math.usm.edu/perry/Research/basic_sigbased_gb.py. The scripts for JAS are verbatim the same with two small modifications.


Heinz Kredel

Last modified: Sat Jan 3 20:13:42 CET 2015

$Id$

java-algebra-system-2.7.200/jython/services/000077500000000000000000000000001445075545500206745ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/services/javax.script.ScriptEngineFactory000066400000000000000000000000431445075545500271510ustar00rootroot00000000000000edu.jas.kern.PyScriptEngineFactory java-algebra-system-2.7.200/jython/src/000077500000000000000000000000001445075545500176405ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/src/edu/000077500000000000000000000000001445075545500204155ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/src/edu/jas/000077500000000000000000000000001445075545500211725ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/src/edu/jas/gb/000077500000000000000000000000001445075545500215625ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/src/edu/jas/gb/GBSigBased.java000066400000000000000000000125051445075545500243220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Groebner bases via signatur based GBs using jython script. TODO: Computing * via the ScriptEngine is way slower than the direct execution in the jython * interpreter. Check if a different engine is in the path or if it must be * configured in some special way. * @author Heinz Kredel */ public class GBSigBased> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GBSigBased.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GB algorithm indicators: * sbgb = sigbased_gb(), arri = arris_algorithm(), * ggv = ggv(), ggv1 = ggv_first_implementation(), f5 = f5(), ff5 = f5z(). */ public static enum GBAlgo { sbgb, arri, ggv, ggv1, f5, ff5 } /** * Scripting engine. */ public final ScriptEngine engine; /** * Selected GB algorithm. */ public final GBAlgo algo; /** * GBSigBased constructor. */ public GBSigBased() { this(GBAlgo.ggv1); } /** * GBSigBased constructor. * @param a GB algorithm indicator. */ public GBSigBased(GBAlgo a) { algo = a; ScriptEngineManager manager = new ScriptEngineManager(); //System.out.println("manager = " + manager); //System.out.println("factories = " + manager.getEngineFactories()); engine = manager.getEngineByExtension("py"); if (engine == null) { logger.error("no script engine found"); throw new RuntimeException("no script engine found"); } StringBuffer sb = new StringBuffer(); sb.append("from jas import PolyRing, ZZ, QQ, arraylist2pylist, pylist2arraylist;\n"); sb.append("from basic_sigbased_gb import sigbased_gb, arris_algorithm, ggv, ggv_first_implementation, f5, f5z;\n"); sb.append("sbgb = sigbased_gb();\n"); sb.append("arri = arris_algorithm();\n"); sb.append("ggv = ggv();\n"); sb.append("ggv1 = ggv_first_implementation();\n"); sb.append("f5 = f5();\n"); sb.append("ff5 = f5z();\n"); String ex = sb.toString(); if (debug) { logger.info("input for evaluation:\n" + ex); } try { Object ans = engine.eval(ex); if (ans != null) { logger.info("constructor answer: " + ans); } } catch (ScriptException e) { e.printStackTrace(); throw new RuntimeException(e); } logger.info(toString()); } /** * Get the String representation with GB engine. * @see java.lang.Object#toString() */ @Override public String toString() { return "GBSigBased[ " + engine.getClass().getName() + ", GBAlgo = " + algo + " ]"; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { } /** * Cancel ThreadPool. */ @Override public int cancel() { return 0; } /** * Groebner base. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override @SuppressWarnings("unchecked") public List> GB(int modv, List> F) { if (F == null || F.isEmpty()) { return F; } if (modv != 0) { throw new UnsupportedOperationException("implemented only for modv = 0, not " + modv); } //GenPolynomialRing pfac = F.get(0).ring; List> G = new ArrayList>(); long millis = System.currentTimeMillis(); try { engine.put("F", F); StringBuffer sb = new StringBuffer(); //sb.append("r = " + pfac.toScript() + ";\n"); //sb.append("print str(r);\n"); //sb.append("print \"F = \" + str(F);\n"); sb.append("Fp = arraylist2pylist(F);\n"); //sb.append("Gp = sbgb.basis_sig(Fp);\n"); //sb.append("Gp = ff5.basis_sig(Fp);\n"); //sb.append("Gp = arri.basis_sig(Fp);\n"); //sb.append("Gp = ggv1.basis_sig(Fp);\n"); sb.append("Gp = " + algo + ".basis_sig(Fp);\n"); sb.append("G = pylist2arraylist(Gp);\n"); String ex = sb.toString(); if (debug) { logger.info("input for evaluation:\n" + ex); } Object ans = engine.eval(ex); if (ans != null) { logger.info("answer: " + ans); } G = (List>) engine.get("G"); } catch (ScriptException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } millis = System.currentTimeMillis() - millis; System.out.println("evaluation took " + millis); if (debug) { logger.info("polynomials G: " + G); } return G; } } java-algebra-system-2.7.200/jython/src/edu/jas/gb/GBSigBasedTest.java000066400000000000000000000131341445075545500251610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigRational; // import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base sig based via jython tests with JUnit. * @author Heinz Kredel. */ public class GBSigBasedTest extends TestCase { private static final Logger logger = LogManager.getLogger(GBSigBasedTest.class); /** * main @param args not used */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GBSigBasedTest object. * @param name String. */ public GBSigBasedTest(String name) { super(name); } /** * suite. * @return test suite. */ public static Test suite() { TestSuite suite = new TestSuite(GBSigBasedTest.class); return suite; } GenPolynomialRing fac; List> L; PolynomialList F; List> G, Gn; GroebnerBaseAbstract bb; GroebnerBaseAbstract bbn; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 5; //10; int ll = 5; //7; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; //bb = new GBSigBased(); bb = new GBSigBased(GBSigBased.GBAlgo.ggv1); //sbgb); //bbn = new GroebnerBaseSeq(new ReductionSeq(),new OrderedSyzPairlist()); bbn = new GroebnerBaseSeq(); //logger.info("using " + bb); } @Override protected void tearDown() { int s = bb.cancel(); logger.debug("canceled tasks: " + s); //assertTrue("s >= 0 " + s, s >= 0); a = b = c = d = e = null; fac = null; bb = null; bbn = null; } /** * Test GBase. */ public void testGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks7GBase() { //String exam = "Mod 32003 (B,S,T,Z,P,W) L " String exam = "Rat (B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long t; t = System.currentTimeMillis(); Gn = bbn.GB(F.list); t = System.currentTimeMillis() - t; System.out.println("bbn took = " + t); G = bb.GB(F.list); G = bb.GB(F.list); assertEquals("#GB(Trinks7) == 6", 6, G.size()); assertTrue("isGB( GB(Trinks7) ) " + G, bb.isGB(G)); assertEquals("#G == #Gn", G.size(), Gn.size()); assertTrue("t >= 0 ", t >= 0); //PolynomialList trinks = new PolynomialList(F.ring, G); //System.out.println("G = " + trinks); // t = System.currentTimeMillis(); // Gn = bbn.GB(F.list); // t = System.currentTimeMillis() - t; // System.out.println("bbn took = " + t); // G = bb.GB(F.list); // assertEquals("#G == #Gn", G.size(), Gn.size()); // t = System.currentTimeMillis(); // Gn = bbn.GB(F.list); // t = System.currentTimeMillis() - t; // System.out.println("bbn took = " + t); // G = bb.GB(F.list); // assertEquals("#G == #Gn", G.size(), Gn.size()); // assertEquals("#GB(Trinks7) == 6", 6, G.size()); } } java-algebra-system-2.7.200/jython/src/edu/jas/kern/000077500000000000000000000000001445075545500221315ustar00rootroot00000000000000java-algebra-system-2.7.200/jython/src/edu/jas/kern/PyScriptEngine.java000066400000000000000000000027051445075545500257030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.Reader; import javax.script.AbstractScriptEngine; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngineFactory; import javax.script.SimpleBindings; import org.python.util.PythonInterpreter; public class PyScriptEngine extends AbstractScriptEngine /*implements Invocable, Compilable*/{ PythonInterpreter pyint = new PythonInterpreter(); public PyScriptEngine() { super(); //pyint.execfile(this.getClass().getResourceAsStream("/jas.py")); } public PyScriptEngine(Bindings b) { super(b); //pyint.execfile(this.getClass().getResourceAsStream("/jas.py")); } @Override public Object eval(Reader r, ScriptContext c) { throw new RuntimeException("eval(Reader r,..) not implemented"); } @Override public Object eval(String s, ScriptContext c) { //Obejct o = pyint.eval(s); //return pyint.eval(s).__str__().toString(); pyint.exec(s); return null; } @Override public ScriptEngineFactory getFactory() { return new PyScriptEngineFactory(); } @Override public Bindings createBindings() { return new SimpleBindings(); } @Override public String toString() { ScriptEngineFactory sf = getFactory(); return "PyScriptEngine(" + sf.getLanguageName() + ", " + sf.getLanguageVersion() + ")"; } } java-algebra-system-2.7.200/jython/src/edu/jas/kern/PyScriptEngineFactory.java000066400000000000000000000037361445075545500272400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; public class PyScriptEngineFactory implements ScriptEngineFactory { @Override public String getProgram(String... S) { StringBuffer sb = new StringBuffer(); for (String s : S) { sb.append(s + "; "); } return sb.toString(); } @Override public ScriptEngine getScriptEngine() { return new PyScriptEngine(); } @Override public String getOutputStatement(String s) { return s; } @Override public String getMethodCallSyntax(String o, String m, String... S) { return o + "." + m + "(" + Arrays.toString(S) + ")"; } @Override public Object getParameter(String s) { return s; } @Override public String getLanguageVersion() { return "1.0"; } @Override public String getLanguageName() { return "JAS jython"; } @Override public String getEngineVersion() { return "0.1"; } @Override public String getEngineName() { return "JAS_jython"; } @Override public List getNames() { List ls = new ArrayList(); ls.add("jython"); //System.out.println("getNames: " + ls); return Collections.unmodifiableList(ls); } @Override public List getMimeTypes() { List ls = new ArrayList(); ls.add("x-application/python"); //System.out.println("getMimeTypes: " + ls); return Collections.unmodifiableList(ls); } @Override public List getExtensions() { List ls = new ArrayList(); ls.add("py"); //System.out.println("getExtensions: " + ls); return Collections.unmodifiableList(ls); } } java-algebra-system-2.7.200/jython/src/edu/jas/kern/ScriptingExample.java000066400000000000000000000075171445075545500262640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class ScriptingExample { public static void main(String[] args) { runJython(); //runJythonRegister(); runJruby(); } public static void runJythonRegister() { ScriptEngine jas = new ScriptEngineManager().getEngineByExtension("py"); System.out.println("JAS service discovered: " + jas); if (jas == null) { ScriptEngineManager scriptManager = new ScriptEngineManager(); scriptManager.registerEngineExtension("py", new PyScriptEngineFactory()); jas = scriptManager.getEngineByExtension("py"); } if (jas == null) { jas = new PyScriptEngine(); } if (jas == null) { System.out.println("No JAS engine found"); return; } System.out.println("Using JAS engine: " + jas); try { long millis = System.currentTimeMillis(); //String ex = "x = 1; print(4*2*x)"; String ex = "from jas import PolyRing, ZZ; r = PolyRing(ZZ(),\"x,y,z\",PolyRing.lex); print str(r);" + "[one,x,y,z] = r.gens(); p = ((x*y)+z)**33; print \"p = \" + str(p)"; System.out.println("input: " + ex); Object ans = jas.eval(ex); millis = System.currentTimeMillis() - millis; System.out.println("answer: " + ans); System.out.println("evaluation took " + millis); } catch (ScriptException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static void runJython() { ScriptEngine jas = new ScriptEngineManager().getEngineByExtension("py"); System.out.println("JAS service discovered: " + jas); if (jas == null) { System.out.println("No JAS engine found"); return; } System.out.println("Using JAS engine: " + jas); try { long millis = System.currentTimeMillis(); //String ex = "x = 1; print(4*2*x)"; String ex = "from jas import PolyRing, ZZ;\nr = PolyRing(ZZ(),\"x,y,z\",PolyRing.lex);\nprint str(r);\n" + "[one,x,y,z] = r.gens();\np = ((x*y)+z)**33;\nprint \"p = \" + str(p)"; System.out.println("input: " + ex); Object ans = jas.eval(ex); millis = System.currentTimeMillis() - millis; System.out.println("answer: " + ans); System.out.println("evaluation took " + millis); } catch (ScriptException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static void runJruby() { ScriptEngine jas = new ScriptEngineManager().getEngineByExtension("rb"); System.out.println("JAS service discovered: " + jas); if (jas == null) { System.out.println("No JAS engine found"); return; } System.out.println("Using JAS engine: " + jas); try { long millis = System.currentTimeMillis(); //String ex = "x = 1; print(4*2*x)"; String ex = "require \"jas\"; r = PolyRing.new(ZZ(),\"x,y,z\",PolyRing.lex); puts r.to_s;" + "one,x,y,z = r.gens(); p = ((x*y)+z)**33; puts \"p = \" + p.to_s"; System.out.println("input: " + ex); Object ans = jas.eval(ex); millis = System.currentTimeMillis() - millis; System.out.println("answer: " + ans); System.out.println("evaluation took " + millis); } catch (ScriptException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } java-algebra-system-2.7.200/jython_tests.sh000066400000000000000000000056151445075545500206360ustar00rootroot00000000000000#!/bin/sh # run some py files #OPTS="-J-cp ../lib/log4j.jar:../lib/junit.jar:." OPTS="-J-cp ../lib/log4j-core-2.17.1.jar:../lib/log4j-api-2.17.1.jar:../lib/junit.jar-4.13.1.jar:../lib/hamcrest-core-1.3.jar:." echo jython $OPTS -J-verbose:gc examples/all_rings.py time jython $OPTS -J-verbose:gc examples/all_rings.py echo jython $OPTS -J-verbose:gc examples/intprog.py time jython $OPTS -J-verbose:gc examples/intprog.py echo jython $OPTS -J-verbose:gc examples/intprog2.py time jython $OPTS -J-verbose:gc examples/intprog2.py echo jython $OPTS -J-verbose:gc examples/katsura.py time jython $OPTS -J-verbose:gc examples/katsura.py echo jython $OPTS -J-verbose:gc examples/preimage.py time jython $OPTS -J-verbose:gc examples/preimage.py echo jython $OPTS -J-verbose:gc examples/quantumplane_syz.py time jython $OPTS -J-verbose:gc examples/quantumplane_syz.py echo jython $OPTS -J-verbose:gc examples/rose.py time jython $OPTS -J-verbose:gc examples/rose.py echo jython $OPTS -J-verbose:gc examples/solvablemodule.py time jython $OPTS -J-verbose:gc examples/solvablemodule.py echo jython $OPTS -J-verbose:gc examples/solvmodright.py time jython $OPTS -J-verbose:gc examples/solvmodright.py echo jython $OPTS -J-verbose:gc examples/syz.py time jython $OPTS -J-verbose:gc examples/syz.py echo jython $OPTS -J-verbose:gc examples/syzsolv.py time jython $OPTS -J-verbose:gc examples/syzsolv.py echo jython $OPTS -J-verbose:gc examples/trinks.py time jython $OPTS -J-verbose:gc examples/trinks.py echo jython $OPTS -J-verbose:gc examples/mark.py time jython $OPTS -J-verbose:gc examples/mark.py echo jython $OPTS -J-verbose:gc examples/u_2_wa_1.py time jython $OPTS -J-verbose:gc examples/u_2_wa_1.py echo jython $OPTS -J-verbose:gc examples/u_sl_2.py time jython $OPTS -J-verbose:gc examples/u_sl_2.py echo jython $OPTS -J-verbose:gc examples/u_sl_3.py time jython $OPTS -J-verbose:gc examples/u_sl_3.py echo jython $OPTS -J-verbose:gc examples/u_sl_3_prod.py time jython $OPTS -J-verbose:gc examples/u_sl_3_prod.py echo jython $OPTS -J-verbose:gc examples/u_so_3.py time jython $OPTS -J-verbose:gc examples/u_so_3.py echo jython $OPTS -J-verbose:gc examples/wa_1.py time jython $OPTS -J-verbose:gc examples/wa_1.py echo jython $OPTS -J-verbose:gc examples/wa_32.py time jython $OPTS -J-verbose:gc examples/wa_32.py echo jython $OPTS -J-verbose:gc examples/wa_32_syz.py time jython $OPTS -J-verbose:gc examples/wa_32_syz.py echo jython $OPTS -J-verbose:gc examples/chebyshev.py time jython $OPTS -J-verbose:gc examples/chebyshev.py echo jython $OPTS -J-verbose:gc examples/legendre.py time jython $OPTS -J-verbose:gc examples/legendre.py echo jython $OPTS -J-verbose:gc examples/arith.py time jython $OPTS -J-verbose:gc examples/arith.py echo jython $OPTS -J-verbose:gc examples/powerseries.py time jython $OPTS -J-verbose:gc examples/powerseries.py echo jython $OPTS -J-verbose:gc examples/polynomial.py time jython $OPTS -J-verbose:gc examples/polynomial.py java-algebra-system-2.7.200/log4j2.properties000066400000000000000000000036231445075545500207610ustar00rootroot00000000000000# $Id$ # logging for log4j2 itself status = error #status = debug #nok: dest = file://test/log.log name = JASPropertiesConfig appenders = console, rolling # appender for console appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %-4r %-5p [%t] %c - %m%n #appender.console.layout.pattern = %-4r [%t] %-5p %c - %m%n # appender for files appender.rolling.type = RollingFile appender.rolling.name = RollingFile #appender.rolling.fileName = test/jastest.log appender.rolling.fileName = ${sys:java.io.tmpdir}/test/jastest.log #appender.rolling.fileName = ${sys:user.home}/test/jastest.log appender.rolling.filePattern = test/jastest-%d{MM-dd-yy-HH-mm-ss}-%i.log #appender.rolling.filePattern = test/jastest-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz appender.rolling.append = true appender.rolling.layout.type = PatternLayout #appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n appender.rolling.layout.pattern = %-4r [%t] %-5p %c - %m%n appender.rolling.policies.type = Policies appender.rolling.policies.time.type = TimeBasedTriggeringPolicy appender.rolling.policies.time.interval = 2 appender.rolling.policies.time.modulate = true appender.rolling.policies.size.type = SizeBasedTriggeringPolicy appender.rolling.policies.size.size=1MB appender.rolling.strategy.type = DefaultRolloverStrategy appender.rolling.strategy.max = 5 loggers = rolling # rolling logger logger.rolling.name = org.apache.logging.log4j.core.appender.rolling logger.rolling.level = debug logger.rolling.additivity = false logger.rolling.appenderRefs = rolling logger.rolling.appenderRef.rolling.ref = RollingFile #rootLogger.level = debug #rootLogger.level = info #rootLogger.level = warn rootLogger.level = error rootLogger.appenderRefs = stdout rootLogger.appenderRef.stdout.ref = STDOUT #rootLogger.appenderRefs = fileio #rootLogger.appenderRef.fileio.ref = RollingFile java-algebra-system-2.7.200/machines.localhost000066400000000000000000000003761445075545500212450ustar00rootroot00000000000000# machines file for jas unit tests localhost:7114 # first host is master localhost:8114 # first client host, master-port+1000 localhost:9114 # second client host with port #localhost:8411 # next host with port #localhost:8411 # last host # eof java-algebra-system-2.7.200/meditor/000077500000000000000000000000001445075545500172015ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/.gitignore000066400000000000000000000000151445075545500211650ustar00rootroot00000000000000/test /*.jar java-algebra-system-2.7.200/meditor/Makefile000066400000000000000000000026621445075545500206470ustar00rootroot00000000000000# # $Id$ # # Makefile for the interface of JAS to meditor # by Raphael Jolly, Heinz kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib MEDITORPATH=$(HOME)/java/meditor3.0 CLASSPATH=$(LIBPATH)/jython.jar:$(MEDITORPATH)/meditor.jar # incompatible with jython version #BOOTCLASSPATH4="/usr/java/j2sdk1.4.0/jre/lib/rt.jar" # javac -g -source 1.4 -target 1.4 -classpath $(CLASSPATH) -bootclasspath $(BOOTCLASSPATH4) -sourcepath src -d classes src/edu/jas/editorengine/*.java BOOTCLASSPATH8=/usr/lib64/jvm/java-1.8.0-openjdk-1.8.0/jre/lib/rt.jar .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/editorengine/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) all: jas-meditor.jar $(CLASSES): $(FILES) -mkdir classes javac -g -source 1.8 -target 1.8 -classpath $(CLASSPATH) -bootclasspath $(BOOTCLASSPATH8) -sourcepath src -d classes src/edu/jas/editorengine/*.java jas-meditor.jar: $(CLASSES) $(JASPATH)/examples/jas.py manifest.mf services/jscl.editor.EngineFactory -mkdir classes/META-INF -mkdir classes/META-INF/services cp -a manifest.mf classes/META-INF/MANIFEST.MF cp -a services/jscl.editor.EngineFactory classes/META-INF/services/ jar cfM jas-meditor.jar -C classes . jar uf jas-meditor.jar -C $(JASPATH)/examples jas.py cp -f jas-meditor.jar $(LIBPATH) cp -f jas-meditor.jar .. -rm -rf classes clean: rm -rf classes java-algebra-system-2.7.200/meditor/manifest.mf000066400000000000000000000000671445075545500213360ustar00rootroot00000000000000Manifest-Version: 1.0 Created-By: 1.7.0_0 (IceTea) java-algebra-system-2.7.200/meditor/meditor000077500000000000000000000010561445075545500205740ustar00rootroot00000000000000#!/bin/bash # script to call meditor with the jas engine # # $Id$ LIBPATH=~/java/lib MEDITORPATH=~/java/meditor3.0 JASPATH=.. #UTILS=$LIBPATH/jython.jar:$LIBPATH/log4j.jar UTILS=~/java/jython2.7.0/jython.jar:$LIBPATH/log4j.jar JAS=$JASPATH/jas.jar:jas-meditor.jar if [[ ! -f "jas.py" ]]; then jar xf jas-meditor.jar jas.py fi MEDITOR=$MEDITORPATH/meditor.jar:$MEDITORPATH/lib/jscl.jar CLASSPATH=$UTILS:$JAS:$MEDITOR:.:.. mkdir -p test #####-Dpython.home=$JASPATH/examples java -classpath $CLASSPATH -Duser.home=$JASPATH/examples jscl.editor.Editor java-algebra-system-2.7.200/meditor/services/000077500000000000000000000000001445075545500210245ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/services/jscl.editor.EngineFactory000066400000000000000000000000511445075545500257170ustar00rootroot00000000000000edu.jas.editorengine.EditorEngineFactory java-algebra-system-2.7.200/meditor/src/000077500000000000000000000000001445075545500177705ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/src/edu/000077500000000000000000000000001445075545500205455ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/src/edu/jas/000077500000000000000000000000001445075545500213225ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/src/edu/jas/editorengine/000077500000000000000000000000001445075545500237765ustar00rootroot00000000000000java-algebra-system-2.7.200/meditor/src/edu/jas/editorengine/EditorEngine.java000066400000000000000000000011451445075545500272160ustar00rootroot00000000000000package edu.jas.editorengine; import jscl.editor.Engine; import org.python.util.PythonInterpreter; public class EditorEngine extends Engine { PythonInterpreter interp=new PythonInterpreter(); public EditorEngine() { //interp.execfile(EditorEngine.class.getResourceAsStream("/jas.py")); } public String eval(String str) { if(str.lastIndexOf("\n")==str.length()-1) { interp.exec(str); return str; } else return interp.eval(str).__str__().toString(); } public void exec(String str) { String re = eval(str); return; } } java-algebra-system-2.7.200/meditor/src/edu/jas/editorengine/EditorEngineFactory.java000066400000000000000000000003251445075545500305450ustar00rootroot00000000000000package edu.jas.editorengine; import jscl.editor.Engine; import jscl.editor.EngineFactory; public class EditorEngineFactory extends EngineFactory { public Engine getEngine() { return new EditorEngine(); } } java-algebra-system-2.7.200/mpi/000077500000000000000000000000001445075545500163235ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/.gitignore000066400000000000000000000000461445075545500203130ustar00rootroot00000000000000/test /*.jar /*.out /classes /*.class java-algebra-system-2.7.200/mpi/Makefile000066400000000000000000000036071445075545500177710ustar00rootroot00000000000000# # $Id: $ # # Makefile for the Java Open MPI dependend parts # by Heinz kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib #MPILIB=$(MPI_HOME)/lib/mpi.jar MPILIB=$(LIBPATH)/mpi.jar CLASSPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar:$(LIBPATH)/junit.jar:$(MPILIB):$(JASPATH) #$(LIBPATH)/jas.jar #LOG4JPATH=$(LIBPATH)/log4j-core-2.13.2.jar:$(LIBPATH)/log4j-api-2.13.2.jar NP=2 PPN=3 MPI_CMD=mpirun -np $(NP) -bynode -display-map -verbose java -cp $(CLASSPATH):jas-mpi.jar #DOCOPTS=-package DOCOPTS=-package -author -version -linksource -Xdoclint:none -overview overview.html DOCCLASSES=$(CLASSPATH) DOC=javadoc -classpath $(DOCCLASSES) # --- syncing ---------- DRY=--dry-run DELETE= RSYNC=rsync -e ssh -avuz $(DRY) $(DELETE) --exclude=*~ --exclude=*.log* --exclude=*.out* --exclude=*.txt* --exclude=.svn --exclude=classes --exclude=.git* .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/*/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) all: jas-mpi.jar $(CLASSES): $(FILES) Makefile -mkdir classes javac -classpath $(CLASSPATH) -d classes src/edu/jas/*/*.java jas-mpi.jar: $(CLASSES) -mkdir classes/META-INF cp -a manifest.mf classes/META-INF/MANIFEST.MF jar cfM jas-mpi.jar -C classes . cp -f jas-mpi.jar $(LIBPATH) cp -f jas-mpi.jar .. clean: rm -rf classes find . -name "*~" -follow -print -exec rm {} \; MFILE=machines EFILE=$(JASPATH)/examples/trinks6.jas tests: jas-mpi.jar # $(MPI_CMD) -Xmx1000M edu.jas.application.RunMPIGB distmpi $(EFILE) $(NP)/$(PPN) $(MFILE) $(MPI_CMD) -Xmx1000M edu.jas.application.RunMPIGB disthybmpi $(EFILE) $(NP)/$(PPN) $(MFILE) doc: $(FILES) $(DOC) $(DOCOPTS) -d ../doc/mpi $(FILES) BWDIR=java/jas-2.5/mpi home: $(RSYNC) bwgrid:$(BWDIR)/src/ src bwgrid: $(RSYNC) src/ bwgrid:$(BWDIR)/src java-algebra-system-2.7.200/mpi/machines000066400000000000000000000000121445075545500200260ustar00rootroot00000000000000localhost java-algebra-system-2.7.200/mpi/manifest.mf000066400000000000000000000001521445075545500204530ustar00rootroot00000000000000Manifest-Version: 1.0 Class-Path: lib/log4j.jar lib/junit.jar Main-Class: edu.jas.application.RunMPIGB java-algebra-system-2.7.200/mpi/overview.html000066400000000000000000000031461445075545500210630ustar00rootroot00000000000000 Java Algebra System, MPI part

Java algebra system, MPI part.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

See introduction for a general overview.


Heinz Kredel

Last modified: Sat Oct 5 21:55:10 CEST 2013

$Id$

java-algebra-system-2.7.200/mpi/src/000077500000000000000000000000001445075545500171125ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/000077500000000000000000000000001445075545500176675ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/000077500000000000000000000000001445075545500204445ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/application/000077500000000000000000000000001445075545500227475ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/application/RunMPIGB.java000066400000000000000000000256561445075545500251530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import mpi.MPIException; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseDistributedEC; import edu.jas.gb.GroebnerBaseDistributedHybridEC; import edu.jas.gb.GroebnerBaseDistributedHybridMPI; import edu.jas.gb.GroebnerBaseDistributedMPI; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.ReductionPar; import edu.jas.gb.ReductionSeq; import edu.jas.gbufd.GBFactory; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPIEngine; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.util.CatReader; import edu.jas.util.ExecutableServer; /** * Simple setup to run a GB example in MPI environment.
* Usage: RunGB [seq(+)|par(+)|dist(1)(+)|disthyb|cli] <file> * #procs/#threadsPerNode [machinefile] * @author Heinz Kredel */ public class RunMPIGB { /** * Check result GB if it is a GB. */ static boolean doCheck = false; /** * main method to be called from commandline
* Usage: RunMPIGB [seq|par(+)|dist(+)|disthyb|cli] <file> * #procs/#threadsPerNode [machinefile] */ @SuppressWarnings("unchecked") public static void main(String[] args) throws IOException, MPIException { MPIEngine.setCommandLine(args); //args = MPI.Init(args); String[] allkinds = new String[] { "seq", "seq+", "par", "par+", "dist", "dist+", "disthyb", "disthyb+", "distmpi", "distmpi+", "disthybmpi", "disthybmpi+", "cli" }; String usage = "Usage: RunGB [ " + RunGB.join(allkinds, " | ") + "[port] ] " + " " + "#procs/#threadsPerNode " + "[machinefile] " + "[check]"; if (args.length < 1) { System.out.println("args: " + Arrays.toString(args)); System.out.println(usage); return; } boolean plusextra = false; String kind = args[0]; boolean sup = false; int k = -1; for (int i = 0; i < args.length; i++) { int j = RunGB.indexOf(allkinds, args[i]); if (j < 0) { continue; } sup = true; k = i; kind = args[k]; break; } if (!sup) { System.out.println("args(sup): " + Arrays.toString(args)); System.out.println(usage); return; } if (kind.indexOf("+") >= 0) { plusextra = true; } System.out.println("kind: " + kind + ", k = " + k); final int GB_SERVER_PORT = 7114; int port = GB_SERVER_PORT; if (kind.equals("cli")) { if (args.length - k >= 2) { try { port = Integer.parseInt(args[k + 1]); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(port): " + Arrays.toString(args)); System.out.println(usage); return; } } RunGB.runClient(port); return; } String filename = null; if (!kind.equals("cli")) { if (args.length - k < 2) { System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } filename = args[k + 1]; } int j = RunGB.indexOf(args, "check"); if (j >= 0) { doCheck = true; RunGB.doCheck = true; } int threads = 0; int threadsPerNode = 1; if (kind.startsWith("par") || kind.startsWith("dist")) { if (args.length - k < 3) { System.out.println("args(par|dist): " + Arrays.toString(args)); System.out.println(usage); return; } String tup = args[k + 2]; String t = tup; int i = tup.indexOf("/"); if (i >= 0) { t = tup.substring(0, i).trim(); tup = tup.substring(i + 1).trim(); try { threadsPerNode = Integer.parseInt(tup); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threadsPerNode): " + Arrays.toString(args)); System.out.println(usage); return; } } try { threads = Integer.parseInt(t); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threads): " + Arrays.toString(args)); System.out.println(usage); return; } } String mfile = null; if (kind.startsWith("dist")) { if (args.length - k >= 4) { mfile = args[k + 3]; } else { mfile = "machines"; } } Reader problem = RunGB.getReader(filename); if (problem == null) { System.out.println("args(file): " + filename); System.out.println("args(file): examples.jar(" + filename + ")"); System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } RingFactoryTokenizer rftok = new RingFactoryTokenizer(problem); GenPolynomialRing pfac = null; try { pfac = rftok.nextPolynomialRing(); rftok = null; } catch (IOException e) { e.printStackTrace(); return; } Reader polyreader = new CatReader(new StringReader("("), problem); // ( has gone //Reader polyreader = problem; GenPolynomialTokenizer tok = new GenPolynomialTokenizer(pfac, polyreader); PolynomialList S = null; try { S = new PolynomialList(pfac, tok.nextPolynomialList()); } catch (IOException e) { e.printStackTrace(); return; } System.out.println("S =\n" + S); if (kind.startsWith("seq")) { RunGB.runSequential(S, plusextra); } else if (kind.startsWith("par")) { RunGB.runParallel(S, threads, plusextra); } else if (kind.startsWith("distmpi")) { runMpi(S, threads, mfile, port, plusextra); } else if (kind.startsWith("disthybmpi")) { runHybridMpi(S, threads, threadsPerNode, mfile, port, plusextra); } else if (kind.startsWith("disthyb")) { RunGB.runMasterHyb(S, threads, threadsPerNode, mfile, port, plusextra); } else if (kind.startsWith("dist")) { RunGB.runMaster(S, threads, mfile, port, plusextra); } ComputerThreads.terminate(); //System.exit(0); } @SuppressWarnings("unchecked") static void runMpi(PolynomialList S, int threads, String mfile, int port, boolean plusextra) throws IOException, MPIException { List L = S.list; List G = null; long t, t1; t = System.currentTimeMillis(); System.out.println("\nGroebner base distributed MPI (" + threads + ", " + mfile + ", " + port + ") ..."); GroebnerBaseDistributedMPI gbd = null; GroebnerBaseDistributedMPI gbds = null; if (plusextra) { gbds = new GroebnerBaseDistributedMPI(threads, new OrderedSyzPairlist()); } else { gbd = new GroebnerBaseDistributedMPI(threads); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); } else { gbd.terminate(); } MPIEngine.terminate(); if (G == null) { return; // mpi.rank != 0 } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("m+ "); } else { System.out.print("m "); } System.out.println("= " + threads + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); RunGB.checkGB(S); System.out.println(""); } @SuppressWarnings("unchecked") static void runHybridMpi(PolynomialList S, int threads, int threadsPerNode, String mfile, int port, boolean plusextra) throws IOException, MPIException { List L = S.list; List G = null; long t, t1; t = System.currentTimeMillis(); System.out.println("\nGroebner base distributed hybrid MPI (" + threads + "/" + threadsPerNode + ", " + mfile + ", " + port + ") ..."); GroebnerBaseDistributedHybridMPI gbd = null; GroebnerBaseDistributedHybridMPI gbds = null; if (plusextra) { gbds = new GroebnerBaseDistributedHybridMPI(threads, threadsPerNode, new OrderedSyzPairlist()); } else { gbd = new GroebnerBaseDistributedHybridMPI(threads, threadsPerNode); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); } else { gbd.terminate(); } MPIEngine.terminate(); if (G == null) { return; // mpi.rank != 0 } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("m+ "); } else { System.out.print("m "); } System.out.println("= " + threads + ", ppn = " + threadsPerNode + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); RunGB.checkGB(S); System.out.println(""); } } java-algebra-system-2.7.200/mpi/src/edu/jas/gb/000077500000000000000000000000001445075545500210345ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/gb/GroebnerBaseDistHybridMPITest.java000066400000000000000000000146741445075545500274450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import mpi.MPIException; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPIEngine; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Distributed GroebnerBase MPI tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistHybridMPITest extends TestCase { protected static Comm engine; boolean mpjBug = true; // bug after cancel recv /** * main */ public static void main(String[] args) throws IOException, MPIException { engine = MPIEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); MPIEngine.terminate(); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistHybridMPITest object. * @param name String. */ public GroebnerBaseDistHybridMPITest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistHybridMPITest.class); return suite; } int port = 4711; String host = "localhost"; GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseDistributedHybridMPI bbdist; GroebnerBaseDistributedHybridMPI bbdists; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads; int threadsPerNode = 3; @Override protected void setUp() throws IOException { try { threads = engine.Size(); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdist = new GroebnerBaseDistributedHybridMPI(threads, threadsPerNode); //bbdists = new GroebnerBaseDistributedHybridMPI(threads,threadsPerNode, new OrderedSyzPairlist()); } catch (MPIException e) { e.printStackTrace(); } } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; //bbdists.terminate(); bbdists = null; ComputerThreads.terminate(); } /** * Test distributed GBase. */ public void onlyOnetestDistributedGBase() throws MPIException { L = new ArrayList>(); if (engine.Rank() == 0) { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); } if (engine.Rank() == 0) { L.add(a); L.add(b); System.out.println("L = " + L); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L0 = " + L); assertTrue("isGB( { a } )", bbseq.isGB(L)); L.add(b); } if (mpjBug) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return; } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L1 = " + L); assertTrue("isGB( { a, b } )", bbseq.isGB(L)); L.add(c); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L2 = " + L); assertTrue("isGB( { a, b, c } )", bbseq.isGB(L)); L.add(d); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L3 = " + L); assertTrue("isGB( { a, b, c, d } )", bbseq.isGB(L)); L.add(e); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L4 = " + L); assertTrue("isGB( { a, b, c, d, e } )", bbseq.isGB(L)); } else { System.out.println("rank = " + engine.Rank()); } } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() throws MPIException { List> Fl; long t = 0; if (engine.Rank() == 0) { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } System.out.println("F = " + F); Fl = F.list; t = System.currentTimeMillis(); } else { Fl = null; } G = bbdist.GB(Fl); if (engine.Rank() == 0) { t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + G); System.out.println("executed in " + t + " milliseconds"); } else { assertTrue("G == null: ", G == null); } } } java-algebra-system-2.7.200/mpi/src/edu/jas/gb/GroebnerBaseDistMPITest.java000066400000000000000000000141451445075545500262740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import mpi.MPIException; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPIEngine; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Distributed GroebnerBase MPI tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistMPITest extends TestCase { protected static Comm engine; boolean mpjBug = true; // bug after cancel recv /** * main */ public static void main(String[] args) throws IOException, MPIException { engine = MPIEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); MPIEngine.terminate(); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistMPITest object. * @param name String. */ public GroebnerBaseDistMPITest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistMPITest.class); return suite; } int port = 4711; String host = "localhost"; GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseDistributedMPI bbdist; GroebnerBaseDistributedMPI bbdists; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads; @Override protected void setUp() throws IOException { try { threads = engine.Size(); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdists = new GroebnerBaseDistributedMPI(threads); bbdist = new GroebnerBaseDistributedMPI(threads, new OrderedSyzPairlist()); } catch (MPIException e) { e.printStackTrace(); } } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; bbdists.terminate(); bbdists = null; ComputerThreads.terminate(); } /** * Test distributed GBase. */ public void testDistributedGBase() throws MPIException { L = new ArrayList>(); if (engine.Rank() == 0) { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); } if (engine.Rank() == 0) { assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a } )", bbseq.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); } if (mpjBug) { return; } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b } )", bbseq.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c } )", bbseq.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c, d } )", bbseq.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c, d, e } )", bbseq.isGB(L)); } } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() throws MPIException { List> Fl; long t = 0; if (engine.Rank() == 0) { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } System.out.println("F = " + F); Fl = F.list; t = System.currentTimeMillis(); } else { Fl = null; } G = bbdists.GB(Fl); if (engine.Rank() == 0) { t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + G); System.out.println("executed in " + t + " milliseconds"); } } } java-algebra-system-2.7.200/mpi/src/edu/jas/gb/GroebnerBaseDistributedHybridMPI.java000066400000000000000000001035751445075545500301630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.atomic.AtomicInteger; import mpi.Comm; import mpi.MPIException; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPIEngine; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; import edu.jas.util.DistHashTableMPI; import edu.jas.util.MPIChannel; import edu.jas.util.Terminator; import edu.jas.util.ThreadPool; /** * Groebner Base distributed hybrid algorithm with MPI. Implements a distributed * memory with multi-core CPUs parallel version of Groebner bases with MPI. * Using pairlist class, distributed multi-threaded tasks do reduction, one * communication channel per remote node. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedHybridMPI> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedHybridMPI.class); public final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ protected static final int DEFAULT_THREADS = 2; /** * Number of threads per node to use. */ protected final int threadsPerNode; /** * Default number of threads per compute node. */ protected static final int DEFAULT_THREADS_PER_NODE = 1; /** * Pool of threads to use. */ //protected final ExecutorService pool; // not for single node tests protected transient final ThreadPool pool; /* * Underlying MPI engine. */ protected transient final Comm engine; /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridEC.pairTag.intValue(); /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridEC.resultTag.intValue(); /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridEC.ackTag.intValue(); /** * Constructor. */ public GroebnerBaseDistributedHybridMPI() throws IOException { this(DEFAULT_THREADS); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseDistributedHybridMPI(int threads) throws IOException { this(threads, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. */ public GroebnerBaseDistributedHybridMPI(int threads, int threadsPerNode) throws IOException { this(threads, threadsPerNode, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. */ public GroebnerBaseDistributedHybridMPI(int threads, ThreadPool pool) throws IOException { this(threads, DEFAULT_THREADS_PER_NODE, pool); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedHybridMPI(int threads, int threadsPerNode, PairList pl) throws IOException { this(threads, threadsPerNode, new ThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. */ public GroebnerBaseDistributedHybridMPI(int threads, int threadsPerNode, ThreadPool pool) throws IOException { this(threads, threadsPerNode, pool, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pool ThreadPool to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedHybridMPI(int threads, int threadsPerNode, ThreadPool pool, PairList pl) throws IOException { super(new ReductionPar(), pl); int size = 0; try { engine = MPIEngine.getCommunicator(); size = engine.Size(); } catch (MPIException e) { throw new IOException(e); } if (size < 2) { throw new IllegalArgumentException("Minimal 2 MPI processes required, not " + size); } if (threads != size || pool.getNumber() != size) { throw new IllegalArgumentException("threads != size: " + threads + " != " + size + ", #pool " + pool.getNumber()); } this.threads = threads; this.pool = pool; this.threadsPerNode = threadsPerNode; //logger.info("generated pool: " + pool); } /** * Cleanup and terminate. */ @Override public void terminate() { if (pool == null) { return; } //pool.terminate(); pool.cancel(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs or on * MPI client part. */ public List> GB(int modv, List> F) { try { if (engine.Rank() == 0) { return GBmaster(modv, F); } } catch (MPIException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } catch (IOException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } pool.terminate(); // not used on clients try { clientPart(0); // only 0 } catch (IOException e) { logger.info("clientPart: " + e); e.printStackTrace(); } catch (MPIException e) { logger.info("clientPart: " + e); e.printStackTrace(); } return null; } /** * Distributed hybrid Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ public List> GBmaster(int modv, List> F) throws MPIException, IOException { long t = System.currentTimeMillis(); GenPolynomial p; List> G = new ArrayList>(); PairList pairlist = null; boolean oneInGB = false; //int l = F.size(); int unused = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; G.clear(); G.add(p); //return G; must signal termination to others } if (!oneInGB) { G.add(p); } if (pairlist == null) { //pairlist = new OrderedPairlist(modv, p.ring); pairlist = strategy.create(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { //l--; } } //if (l <= 1) { //return G; must signal termination to others //} logger.info("pairlist " + pairlist + ": " + unused); logger.debug("looking for clients"); DistHashTableMPI> theList = new DistHashTableMPI>( engine); theList.init(); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { // no wait required GenPolynomial nn = theList.put(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i)); } } Terminator finner = new Terminator((threads - 1) * threadsPerNode); HybridReducerServerMPI R; logger.info("using pool = " + pool); for (int i = 1; i < threads; i++) { MPIChannel chan = new MPIChannel(engine, i); // closed in server R = new HybridReducerServerMPI(i, threadsPerNode, finner, chan, theList, pairlist); pool.addJob(R); //logger.info("server submitted " + R); } logger.info("main loop waiting " + finner); finner.waitDone(); int ps = theList.size(); logger.info("#distributed list = " + ps); // make sure all polynomials arrived: not needed in master G = pairlist.getList(); if (ps != G.size()) { logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size()); } for (GenPolynomial q : theList.getValueList()) { if (q != null && !q.isZERO()) { logger.debug("final q = " + q.leadingExpVector()); } } logger.debug("distributed list end"); long time = System.currentTimeMillis(); List> Gp; Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi time = " + time); G = Gp; logger.info("server theList.terminate() " + theList.size()); theList.terminate(); t = System.currentTimeMillis() - t; logger.info("server GB end, time = " + t + ", " + pairlist.toString()); return G; } /** * GB distributed client. * @param rank of the MPI where the server runs on. * @throws IOException */ public void clientPart(int rank) throws IOException, MPIException { if (rank != 0) { throw new UnsupportedOperationException("only master at rank 0 implemented: " + rank); } Comm engine = MPIEngine.getCommunicator(); DistHashTableMPI> theList = new DistHashTableMPI>( engine); theList.init(); MPIChannel chan = new MPIChannel(engine, rank); ThreadPool pool = new ThreadPool(threadsPerNode); logger.info("client using pool = " + pool); for (int i = 0; i < threadsPerNode; i++) { HybridReducerClientMPI Rr = new HybridReducerClientMPI(chan, theList); // i pool.addJob(Rr); } if (debug) { logger.info("clients submitted"); } pool.terminate(); logger.info("client pool.terminate()"); chan.close(); theList.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @SuppressWarnings("unchecked") @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB MiMPIReducerServer[] mirs = (MiMPIReducerServer[]) new MiMPIReducerServer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiMPIReducerServer(R, a); pool.addJob(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker proxy threads. * @param coefficient type */ class HybridReducerServerMPI> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerServerMPI.class); public final boolean debug = logger.isDebugEnabled(); private final Terminator finner; private final MPIChannel pairChannel; //protected transient final Comm engine; private final DistHashTableMPI> theList; private final PairList pairlist; private final int threadsPerNode; final int rank; /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridMPI.pairTag; /** * Constructor. * @param r MPI rank of partner. * @param tpn number of threads per node * @param fin terminator * @param chan MPIChannel * @param dl distributed hash table * @param L ordered pair list */ HybridReducerServerMPI(int r, int tpn, Terminator fin, MPIChannel chan, DistHashTableMPI> dl, PairList L) { rank = r; threadsPerNode = tpn; finner = fin; this.pairChannel = chan; theList = dl; pairlist = L; //logger.info("reducer server created " + this); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override @SuppressWarnings("unchecked") public void run() { //logger.info("reducer server running with " + engine); // try { // pairChannel = new MPIChannel(engine, rank); //,pairTag // } catch (IOException e) { // e.printStackTrace(); // return; // } catch (MPIException e) { // e.printStackTrace(); // return; // } if (logger.isInfoEnabled()) { logger.info("reducer server running: pairChannel = " + pairChannel); } // record idle remote workers (minus one?) //finner.beIdle(threadsPerNode-1); finner.initIdle(threadsPerNode); AtomicInteger active = new AtomicInteger(0); // start receiver HybridReducerReceiverMPI receiver = new HybridReducerReceiverMPI(rank, finner, active, pairChannel, theList, pairlist); receiver.start(); Pair pair; //boolean set = false; boolean goon = true; //int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request if thread is reported incactive logger.debug("receive request"); Object req = null; try { req = pairChannel.receive(pairTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (MPIException e) { e.printStackTrace(); return; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } logger.debug("received request, req = " + req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair and manage termination status logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!finner.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 3 == 0) { logger.info("waiting for reducers, remaining = " + finner.getJobs()); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (!pairlist.hasNext() && !finner.hasJobs()) { logger.info("termination detection: no pairs and no jobs left"); goon = false; break; //continue; //break? } finner.notIdle(); // before pairlist get!! pair = pairlist.removeNext(); // send pair to client, even if null if (debug) { logger.info("active count = " + active.get()); logger.info("send pair = " + pair); } GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); } else { msg = new GBTransportMess(); //not End(); at this time // goon ?= false; } try { red++; pairChannel.send(pairTag, msg); @SuppressWarnings("unused") int a = active.getAndIncrement(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (MPIException e) { e.printStackTrace(); goon = false; break; } //logger.debug("#distributed list = " + theList.size()); } logger.info("terminated, send " + red + " reduction pairs"); /* * send end mark to clients */ logger.debug("send end"); try { for (int i = 0; i < threadsPerNode; i++) { // -1 pairChannel.send(pairTag, new GBTransportMessEnd()); } logger.info("sent end to clients"); // send also end to receiver, no more //pairChannel.send(resultTag, new GBTransportMessEnd(), engine.Rank()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } catch (MPIException e) { e.printStackTrace(); } int d = active.get(); if (d > 0) { logger.info("remaining active tasks = " + d); } receiver.terminate(); //logger.info("terminated, send " + red + " reduction pairs"); pairChannel.close(); logger.info("redServ pairChannel.close()"); finner.release(); } } /** * Distributed server receiving worker thread. * @param coefficient type */ class HybridReducerReceiverMPI> extends Thread { private static final Logger logger = LogManager.getLogger(HybridReducerReceiverMPI.class); public final boolean debug = logger.isDebugEnabled(); private final DistHashTableMPI> theList; private final PairList pairlist; private final MPIChannel pairChannel; final int rank; private final Terminator finner; //private final int threadsPerNode; private final AtomicInteger active; private volatile boolean goon; /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridMPI.resultTag; /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridMPI.ackTag; /** * Constructor. * @param r MPI rank of partner. * @param fin terminator * @param a active remote tasks count * @param pc tagged socket channel * @param dl distributed hash table * @param L ordered pair list */ HybridReducerReceiverMPI(int r, Terminator fin, AtomicInteger a, MPIChannel pc, DistHashTableMPI> dl, PairList L) { rank = r; active = a; //threadsPerNode = tpn; finner = fin; pairChannel = pc; theList = dl; pairlist = L; goon = true; //logger.info("reducer server created " + this); } /** * Work loop. * @see java.lang.Thread#run() */ @Override @SuppressWarnings("unchecked") public void run() { //Pair pair = null; GenPolynomial H = null; int red = 0; int polIndex = -1; //Integer senderId; // obsolete // while more requests while (goon) { // receive request logger.debug("receive result"); //senderId = null; Object rh = null; try { rh = pairChannel.receive(resultTag); @SuppressWarnings("unused") int i = active.getAndDecrement(); //} catch (InterruptedException e) { //goon = false; ////e.printStackTrace(); ////?? finner.initIdle(1); //break; } catch (IOException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } catch (MPIException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } logger.info("received result"); if (rh == null) { if (this.isInterrupted()) { goon = false; finner.initIdle(1); break; } //finner.initIdle(1); } else if (rh instanceof GBTransportMessEnd) { // should only happen from server logger.info("received GBTransportMessEnd"); goon = false; //?? finner.initIdle(1); break; } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; GBTransportMessPoly mpi = (GBTransportMessPoly) rh; H = mpi.pol; //senderId = mpi.threadId; if (H != null) { if (logger.isInfoEnabled()) { // debug logger.info("H = " + H.leadingExpVector()); } if (!H.isZERO()) { if (H.isONE()) { polIndex = pairlist.putOne(); //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); //goon = false; must wait for other clients //finner.initIdle(1); //break; } else { polIndex = pairlist.put(H); // use putWait ? but still not all distributed //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); } } } } // only after recording in pairlist ! finner.initIdle(1); try { pairChannel.send(ackTag, new GBTransportMess()); logger.debug("send acknowledgement"); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (MPIException e) { e.printStackTrace(); goon = false; break; } } // end while goon = false; logger.info("terminated, received " + red + " reductions"); } /** * Terminate. */ public void terminate() { goon = false; try { this.join(); //this.interrupt(); } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); } logger.info("terminate end"); } } /** * Distributed clients reducing worker threads. */ class HybridReducerClientMPI> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerClientMPI.class); public final boolean debug = logger.isDebugEnabled(); private final MPIChannel pairChannel; private final DistHashTableMPI> theList; private final ReductionPar red; //private final int threadsPerNode; /* * Identification number for this thread. */ //public final Integer threadId; // obsolete /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridMPI.pairTag; /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridMPI.resultTag; /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridMPI.ackTag; /** * Constructor. * @param tc tagged socket channel * @param dl distributed hash table */ HybridReducerClientMPI(MPIChannel tc, DistHashTableMPI> dl) { //this.threadsPerNode = tpn; pairChannel = tc; //threadId = 100 + tid; // keep distinct from other tags theList = dl; red = new ReductionPar(); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override @SuppressWarnings("unchecked") public void run() { if (debug) { logger.info("pairChannel = " + pairChannel + " reducer client running"); } Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; boolean doEnd = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result, receive acknowledgment */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.debug("send request = " + req); try { pairChannel.send(pairTag, req); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } logger.info("receive pair, exception "); break; } catch (MPIException e) { goon = false; if (debug) { e.printStackTrace(); } logger.info("receive pair, exception "); break; } logger.debug("receive pair, goon = " + goon); doEnd = true; Object pp = null; try { pp = pairChannel.receive(pairTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (MPIException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (debug) { logger.info("received pair = " + pp); } H = null; if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; //doEnd = false; // bug continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { pair = ((GBTransportMessPair) pp).pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = " + pair.i // + ", pjx = " + pair.j); } } if (pp instanceof GBTransportMessPairIndex) { pix = ((GBTransportMessPairIndex) pp).i; pjx = ((GBTransportMessPairIndex) pp).j; psx = ((GBTransportMessPairIndex) pp).s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); //logger.info("pix = " + pix + ", pjx = " +pjx + ", psx = " +psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //System.out.println("S = " + S); logger.info("ht(S) = " + S.leadingExpVector()); if (S.isZERO()) { // pair.setZero(); does not work in dist H = S; } else { if (debug) { logger.debug("ht(S) = " + S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = " + H.leadingExpVector()); } } } } else { logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps); } } if (pp instanceof GBTransportMess) { logger.debug("null pair results in null H poly"); } // send H or must send null, if not at end if (debug) { logger.debug("#distributed list = " + theList.size()); logger.debug("send H polynomial = " + H); } try { pairChannel.send(resultTag, new GBTransportMessPoly(H)); //,threadId)); doEnd = false; } catch (IOException e) { goon = false; e.printStackTrace(); } catch (MPIException e) { goon = false; e.printStackTrace(); } logger.debug("done send poly message of " + pp); try { pp = pairChannel.receive(ackTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (MPIException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (!(pp instanceof GBTransportMess)) { logger.error("invalid acknowledgement " + pp); } logger.debug("received acknowledgment " + pp); } logger.info("terminated, done " + reduction + " reductions"); if (doEnd) { try { pairChannel.send(resultTag, new GBTransportMessEnd()); } catch (IOException e) { //e.printStackTrace(); } catch (MPIException e) { //e.printStackTrace(); } logger.info("terminated, send done"); } } } java-algebra-system-2.7.200/mpi/src/edu/jas/gb/GroebnerBaseDistributedMPI.java000066400000000000000000000615221445075545500270140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPIEngine; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; import edu.jas.util.DistHashTableMPI; import edu.jas.util.MPIChannel; import edu.jas.util.Terminator; import edu.jas.util.ThreadPool; import mpi.Comm; import mpi.MPIException; /** * Groebner Base distributed algorithm with MPI. Implements a distributed memory * parallel version of Groebner bases. Using MPI and pairlist class, distributed * tasks do reduction. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedMPI> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedMPI.class); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ public static final int DEFAULT_THREADS = 2; /* * Pool of threads to use. Note: No ComputerThreads for one node * tests */ protected transient final ThreadPool pool; /* * Underlying MPI engine. */ protected transient final Comm engine; /** * Constructor. */ public GroebnerBaseDistributedMPI() throws IOException { this(DEFAULT_THREADS); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseDistributedMPI(int threads) throws IOException { this(threads, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. */ public GroebnerBaseDistributedMPI(int threads, ThreadPool pool) throws IOException { this(threads, pool, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedMPI(int threads, PairList pl) throws IOException { this(threads, new ThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedMPI(int threads, ThreadPool pool, PairList pl) throws IOException { super(new ReductionPar(), pl); int size = 0; try { engine = MPIEngine.getCommunicator(); size = engine.Size(); } catch (MPIException e) { throw new IOException(e); } if (size < 2) { throw new IllegalArgumentException("Minimal 2 MPI processes required, not " + size); } if (threads != size || pool.getNumber() != size) { throw new IllegalArgumentException( "threads != size: " + threads + " != " + size + ", #pool " + pool.getNumber()); } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { if (pool == null) { return; } //pool.terminate(); pool.cancel(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs or on * MPI client part. */ public List> GB(int modv, List> F) { try { if (engine.Rank() == 0) { return GBmaster(modv, F); } } catch (MPIException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } catch (IOException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } pool.terminate(); // not used on clients try { clientPart(0); } catch (IOException e) { logger.info("clientPart: " + e); e.printStackTrace(); } catch (MPIException e) { logger.info("clientPart: " + e); e.printStackTrace(); } return null; } /** * Distributed Groebner base, part for MPI master. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ public List> GBmaster(int modv, List> F) throws MPIException, IOException { List> G = new ArrayList>(); GenPolynomial p; PairList pairlist = null; boolean oneInGB = false; //int l = F.size(); int unused = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; G.clear(); G.add(p); //return G; must signal termination to others } if (!oneInGB) { G.add(p); } if (pairlist == null) { pairlist = strategy.create(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { //l--; } } //if (l <= 1) { //return G; must signal termination to others //} logger.info("done pairlist, initialize DHT: " + unused); DistHashTableMPI> theList = new DistHashTableMPI>( engine); theList.init(); //logger.info("done DHT: " + theList); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { // no wait required GenPolynomial nn = theList.put(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i)); } } Terminator fin = new Terminator(threads - 1); MPIReducerServer R; for (int i = 1; i < threads; i++) { logger.debug("addJob " + i + " of " + threads); MPIChannel chan = new MPIChannel(engine, i); // closed in server R = new MPIReducerServer(i, fin, chan, theList, pairlist); pool.addJob(R); } logger.debug("main loop waiting"); fin.waitDone(); int ps = theList.size(); logger.info("#distributed list = " + ps); // make sure all polynomials arrived: not needed in master // G = (ArrayList)theList.values(); G = pairlist.getList(); if (ps != G.size()) { logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size()); } long time = System.currentTimeMillis(); List> Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi = " + time); G = Gp; logger.info("theList.terminate()"); theList.terminate(); logger.info("end" + pairlist); return G; } /** * GB distributed client. * @param rank of the MPI where the server runs on. * @throws IOException */ public void clientPart(int rank) throws IOException, MPIException { if (rank != 0) { throw new UnsupportedOperationException("only master at rank 0 implemented: " + rank); } Comm engine = MPIEngine.getCommunicator(); DistHashTableMPI> theList = new DistHashTableMPI>(); theList.init(); MPIChannel chan = new MPIChannel(engine, rank); MPIReducerClient R = new MPIReducerClient(chan, theList); R.run(); chan.close(); theList.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @SuppressWarnings("unchecked") @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB MiMPIReducerServer[] mirs = (MiMPIReducerServer[]) new MiMPIReducerServer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiMPIReducerServer(R, a); pool.addJob(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker threads. * @param coefficient type */ class MPIReducerServer> implements Runnable { /* * Termination detection coordinator. */ private final Terminator finaler; /* * Underlying MPI engine. */ //protected transient final Comm engine; /* * MPI channel. */ private final MPIChannel pairChannel; /* * GB rank. */ final int rank; /* * Distributed HashTable of polynomials. */ private final DistHashTableMPI> theList; /* * Critical pair list of polynomials. */ private final PairList pairlist; private static final Logger logger = LogManager.getLogger(MPIReducerServer.class); /** * Constructor. * @param r MPI rank of partner. * @param fin termination coordinator to use. * @param c MPI channel to use. * @param dl DHT to use. * @param L pair selection strategy */ MPIReducerServer(int r, Terminator fin, MPIChannel c, DistHashTableMPI> dl, PairList L) { rank = r; finaler = fin; //engine = e; theList = dl; pairlist = L; pairChannel = c; logger.debug("reducer server constructor: "); // + r); } /** * Main method. */ @SuppressWarnings("unchecked") public void run() { logger.debug("reducer server running: "); // + rank); // try { // pairChannel = new MPIChannel(engine, rank); // } catch (IOException e) { // e.printStackTrace(); // return; // } catch (MPIException e) { // e.printStackTrace(); // return; // } if (logger.isInfoEnabled()) { logger.info("reducer server running: pairChannel = " + pairChannel); } Pair pair; GenPolynomial H = null; boolean set = false; boolean goon = true; int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request logger.debug("receive request"); Object req = null; try { req = pairChannel.receive(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (MPIException e) { goon = false; e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } //logger.debug("received request, req = " + req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!set) { finaler.beIdle(); set = true; } if (!finaler.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (!pairlist.hasNext() && !finaler.hasJobs()) { goon = false; break; //continue; //break? } if (set) { set = false; finaler.notIdle(); } pair = pairlist.removeNext(); /* * send pair to client, receive H */ logger.debug("send pair = " + pair); GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); } else { msg = new GBTransportMess(); //End(); // goon ?= false; } try { pairChannel.send(msg); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (MPIException e) { e.printStackTrace(); goon = false; break; } logger.debug("#distributed list = " + theList.size()); Object rh = null; try { rh = pairChannel.receive(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (MPIException e) { e.printStackTrace(); goon = false; break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; break; } //logger.debug("received H polynomial"); if (rh == null) { if (pair != null) { pair.setZero(); } } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; H = ((GBTransportMessPoly) rh).pol; if (logger.isDebugEnabled()) { logger.debug("H = " + H); } if (H == null) { if (pair != null) { pair.setZero(); } } else { if (H.isZERO()) { pair.setZero(); } else { if (H.isONE()) { polIndex = pairlist.putOne(); //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); goon = false; break; } polIndex = pairlist.put(H); // use putWait ? but still not all distributed //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); } } } } logger.info("terminated, done " + red + " reductions"); /* * send end mark to client */ logger.debug("send end"); try { pairChannel.send(new GBTransportMessEnd()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } catch (MPIException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } finaler.beIdle(); pairChannel.close(); } } /** * Distributed clients reducing worker threads. */ class MPIReducerClient> implements Runnable { private final MPIChannel pairChannel; private final DistHashTableMPI> theList; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(MPIReducerClient.class); /** * Constructor. * @param pc MPI communication channel. * @param dl DHT to use. */ MPIReducerClient(MPIChannel pc, DistHashTableMPI> dl) { pairChannel = pc; theList = dl; red = new ReductionPar(); } /** * Main run method. */ @SuppressWarnings("unchecked") public void run() { logger.debug("reducer client running"); Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.debug("send request"); try { pairChannel.send(req); } catch (IOException e) { goon = false; e.printStackTrace(); break; } catch (MPIException e) { goon = false; e.printStackTrace(); break; } logger.debug("receive pair, goon"); Object pp = null; try { pp = pairChannel.receive(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (MPIException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("received pair = " + pp); } H = null; if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { pair = ((GBTransportMessPair) pp).pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = " + pair.i // + ", pjx = " + pair.j); } } if (pp instanceof GBTransportMessPairIndex) { pix = ((GBTransportMessPairIndex) pp).i; pjx = ((GBTransportMessPairIndex) pp).j; psx = ((GBTransportMessPairIndex) pp).s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); //logger.info("pix = " + pix + ", pjx = " + pjx + ", psx = " + psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //System.out.println("S = " + S); if (S.isZERO()) { // pair.setZero(); does not work in dist } else { if (logger.isDebugEnabled()) { logger.info("ht(S) = " + S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = " + H.leadingExpVector()); } } } } else { logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps); } } // send H or must send null if (logger.isDebugEnabled()) { logger.debug("#distributed list = " + theList.size()); logger.debug("send H polynomial = " + H); } try { pairChannel.send(new GBTransportMessPoly(H)); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (MPIException e) { goon = false; e.printStackTrace(); } } logger.info("terminated, done " + reduction + " reductions"); pairChannel.close(); } } /** * Distributed server reducing worker threads for minimal GB Not jet distributed * but threaded. */ class MiMPIReducerServer> implements Runnable { private final List> G; private GenPolynomial H; private final Semaphore done = new Semaphore(0); private final Reduction red; private static final Logger logger = LogManager.getLogger(MiMPIReducerServer.class); /** * Constructor. * @param G polynomial list. * @param p polynomial. */ MiMPIReducerServer(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } /** * Main run method. */ public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = " + H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = " + H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/mpi/src/edu/jas/kern/000077500000000000000000000000001445075545500214035ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/kern/MPIEngine.java000066400000000000000000000216771445075545500240360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import mpi.Comm; import mpi.Intracomm; import mpi.MPI; import mpi.MPIException; import mpi.Status; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * MPI engine, provides global MPI service. Note: could eventually be * done directly with MPI, but provides logging. Usage: To obtain a * reference to the MPI service communicator use * MPIEngine.getComminicator(). Once an engine has been created it * must be shutdown to exit JAS with MPIEngine.terminate(). * @author Heinz Kredel */ public final class MPIEngine { private static final Logger logger = LogManager.getLogger(MPIEngine.class); private static final boolean debug = logger.isDebugEnabled(); /** * Command line arguments. Required for MPI runtime system. */ protected static String[] cmdline; /** * Hostnames of MPI partners. */ public static ArrayList hostNames = new ArrayList(); /** * Flag for MPI usage. Note: Only introduced because Google app * engine does not support MPI. */ public static boolean NO_MPI = false; /** * Number of processors. */ public static final int N_CPUS = Runtime.getRuntime().availableProcessors(); /* * Core number of threads. * N_CPUS x 1.5, x 2, x 2.5, min 3, ?. */ public static final int N_THREADS = (N_CPUS < 3 ? 3 : N_CPUS + N_CPUS / 2); /** * MPI communicator engine. */ static Intracomm mpiComm; /** * MPI engine base tag number. */ public static final int TAG = 11; /** * Hostname suffix. */ public static final String hostSuf = "-ib"; // /* // * Send locks per tag. // */ // private static SortedMap sendLocks = new TreeMap(); // /* // * receive locks per tag. // */ // private static SortedMap recvLocks = new TreeMap(); /** * No public constructor. */ private MPIEngine() { } /** * Set the commandline. * @param args the command line to use for the MPI runtime system. */ public static synchronized void setCommandLine(String[] args) { cmdline = args; } /** * Test if a pool is running. * @return true if a thread pool has been started or is running, else false. */ public static synchronized boolean isRunning() { if (mpiComm == null) { return false; } return true; } /** * Get the MPI communicator. * @return a Communicator constructed for cmdline. */ public static synchronized Comm getCommunicator() throws IOException, MPIException { if (cmdline == null) { throw new IllegalArgumentException("command line not set"); } return getCommunicator(cmdline); } /** * Get the MPI communicator. * @param args the command line to use for the MPI runtime system. * @return a Communicator. */ public static synchronized Comm getCommunicator(String[] args) throws IOException, MPIException { if (NO_MPI) { return null; } if (mpiComm == null) { //String[] args = new String[] { }; //"-np " + N_THREADS }; if (args == null) { throw new IllegalArgumentException("command line is null"); } cmdline = args; args = MPI.Init(args); //int tl = MPI.Init_thread(args,MPI.THREAD_MULTIPLE); logger.info("MPI initialized on " + MPI.Get_processor_name()); //logger.info("thread level MPI.THREAD_MULTIPLE: " + MPI.THREAD_MULTIPLE // + ", provided: " + tl); if (debug) { logger.debug("remaining args: " + Arrays.toString(args)); } mpiComm = MPI.COMM_WORLD; int size = mpiComm.Size(); int rank = mpiComm.Rank(); logger.info("MPI size = " + size + ", rank = " + rank); // maintain list of hostnames of partners hostNames.ensureCapacity(size); for (int i = 0; i < size; i++) { hostNames.add(""); } String myhost = MPI.Get_processor_name(); if ( myhost.matches("\\An\\d*") ) { // bwGRiD node names n010207 myhost += hostSuf; } if ( myhost.matches("kredel.*") ) { myhost = "localhost"; } hostNames.set(rank, myhost); if (rank == 0) { String[] va = new String[1]; va[0] = hostNames.get(0); mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); for (int i = 1; i < size; i++) { Status stat = mpiComm.Recv(va, 0, va.length, MPI.OBJECT, i, TAG); if (stat == null) { throw new IOException("no Status received"); //throw new MPIException("no Status received"); } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { throw new IOException("no Object received"); //throw new MPIException("no object received"); } String v = va[0]; hostNames.set(i, v); } logger.info("MPI partner host names = " + hostNames); } else { String[] va = new String[1]; mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); hostNames.set(0, va[0]); va[0] = hostNames.get(rank); mpiComm.Send(va, 0, va.length, MPI.OBJECT, 0, TAG); } } return mpiComm; } /** * Stop execution. */ public static synchronized void terminate() { if (mpiComm == null) { return; } try { logger.info("terminating MPI on rank = " + mpiComm.Rank()); mpiComm = null; MPI.Finalize(); } catch (MPIException e) { e.printStackTrace(); } } /** * Set no MPI usage. */ public static synchronized void setNoMPI() { NO_MPI = true; terminate(); } /** * Set MPI usage. */ public static synchronized void setMPI() { NO_MPI = false; } // /* // * Get send lock per tag. // * @param tag message tag. // * @return a lock for sends. // */ // public static synchronized Object getSendLock(int tag) { // tag = 11; // one global lock // Object lock = sendLocks.get(tag); // if ( lock == null ) { // lock = new Object(); // sendLocks.put(tag,lock); // } // return lock; // } // /* // * Get receive lock per tag. // * @param tag message tag. // * @return a lock for receives. // */ // public static synchronized Object getRecvLock(int tag) { // Object lock = recvLocks.get(tag); // if ( lock == null ) { // lock = new Object(); // recvLocks.put(tag,lock); // } // return lock; // } // /* // * Wait for termination of a mpi Request. // * @param req a Request. // * @return a Status after termination of req.Wait(). // */ // public static Status waitRequest(final Request req) throws MPIException { // if ( req == null || req.Is_null() ) { // throw new IllegalArgumentException("null request"); // } // int delay = 50; // int delcnt = 0; // Status stat = null; // while (true) { // synchronized (MPIEngine.class) { // global static lock // stat = req.Test(); // logger.info("Request: " + req + ", Status: " + stat); // if (stat != null) { // logger.info("Status: index = " + stat.index + ", source = " + stat.source // + ", tag = " + stat.tag); // if (!stat.Test_cancelled()) { // logger.info("enter req.Wait(): " + Thread.currentThread().toString()); // return req.Wait(); // should terminate immediately // } // } // } // try { // Thread.currentThread().sleep(delay); // varied a bit // } catch (InterruptedException e) { // logger.info("sleep interrupted"); // e.printStackTrace(); // } // delcnt++; // if ( delcnt % 7 != 0 ) { // delay++; // logger.info("delay(" + delay + "): " + Thread.currentThread().toString()); // } // } // } } java-algebra-system-2.7.200/mpi/src/edu/jas/kern/MPIEngineTest.java000066400000000000000000000054471445075545500246730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.MPI; import mpi.MPIException; import mpi.Status; /** * MPIEngine tests with JUnit. * @author Heinz Kredel */ public class MPIEngineTest extends TestCase { /** * main */ public static void main(String[] args) { cmdline = args; junit.textui.TestRunner.run(suite()); MPIEngine.terminate(); } static String[] cmdline; static mpi.Comm engine; /** * Constructs a MPIEngineTest object. * @param name String. */ public MPIEngineTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(MPIEngineTest.class); return suite; } @Override protected void setUp() { if (engine == null) { try { engine = MPIEngine.getCommunicator(cmdline); } catch (IOException e) { e.printStackTrace(); } catch (MPIException e) { e.printStackTrace(); } } } @Override protected void tearDown() { if (engine == null) { return; } engine = null; } /** * Test MPIEngine. */ public void testMPIEngine() throws MPIException { int me = engine.Rank(); int size = engine.Size(); assertTrue("size > 0", size > 0); assertTrue("0 <= me < size", 0 <= me && me < size); //System.out.println("testMPIEngine(): Hello World from " + me + " of " + size); } /** * Test communication. */ public void testCommunication() throws MPIException { int me = engine.Rank(); int size = engine.Size(); int tag = 13; int[] data = new int[5]; if (me == 0) { //System.out.println("testCommunication(): from " + me + " of " + size); for (int i = 1; i < size; i++) { data[0] = i; engine.Send(data, 0, data.length, MPI.INT, i, tag); } } else { Status stat = engine.Recv(data, 0, data.length, MPI.INT, 0, tag); int cnt = stat.Get_count(MPI.INT); int elem = stat.Get_elements(MPI.INT); //System.out.println("testCommunication(): status " + me + ", " + cnt + ", " + elem); //System.out.println("testCommunication(): received " + Arrays.toString(data)); assertTrue("length == count", data.length == cnt); assertTrue("recv == me", data[0] == me); assertTrue("elem >= 0: " + elem, elem >= 0); } //System.out.println("testCommunication(): done"); } } java-algebra-system-2.7.200/mpi/src/edu/jas/util/000077500000000000000000000000001445075545500214215ustar00rootroot00000000000000java-algebra-system-2.7.200/mpi/src/edu/jas/util/DistHashTableMPI.java000066400000000000000000000362671445075545500253270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import mpi.Comm; import mpi.MPI; import mpi.MPIException; import mpi.Status; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPIEngine; /** * Distributed version of a HashTable using MPI. Implemented with a SortedMap / * TreeMap to keep the sequence order of elements. Implemented using MPI * transport or TCP transport. * @author Heinz Kredel */ public class DistHashTableMPI extends AbstractMap { private static final Logger logger = LogManager.getLogger(DistHashTableMPI.class); private static final boolean debug = logger.isDebugEnabled(); /* * Backing data structure. */ protected final SortedMap theList; /* * Thread for receiving pairs. */ protected DHTMPIListener listener; /* * MPI communicator. */ protected final Comm engine; /* * Size of Comm. */ private final int size; /* * This rank. */ private final int rank; /** * Message tag for DHT communicaton. */ public static final int DHTTAG = MPIEngine.TAG + 1; /* * TCP/IP object channels. */ private final SocketChannel[] soc; /** * Transport layer. * true: use TCP/IP socket layer, false: use MPI transport layer. */ static final boolean useTCP = false; /** * DistHashTableMPI. */ public DistHashTableMPI() throws MPIException, IOException { this(MPIEngine.getCommunicator()); } /** * DistHashTableMPI. * @param args command line for MPI runtime system. */ public DistHashTableMPI(String[] args) throws MPIException, IOException { this(MPIEngine.getCommunicator(args)); } /** * DistHashTableMPI. * @param cm MPI communicator to use. */ public DistHashTableMPI(Comm cm) throws MPIException, IOException { engine = cm; rank = engine.Rank(); size = engine.Size(); if (useTCP) { // && soc == null int port = ChannelFactory.DEFAULT_PORT + 11; ChannelFactory cf; if (rank == 0) { cf = new ChannelFactory(port); cf.init(); soc = new SocketChannel[size]; soc[0] = null; try { for (int i = 1; i < size; i++) { SocketChannel sc = cf.getChannel(); // TODO not correct wrt rank soc[i] = sc; } } catch (InterruptedException e) { throw new IOException(e); } cf.terminate(); } else { cf = new ChannelFactory(port-1); // in case of localhost soc = new SocketChannel[1]; SocketChannel sc = cf.getChannel(MPIEngine.hostNames.get(0), port); soc[0] = sc; cf.terminate(); } } else { soc = null; } theList = new TreeMap(); //theList = new ConcurrentSkipListMap(); // Java 1.6 listener = new DHTMPIListener(engine, soc, theList); logger.info("constructor: " + rank + "/" + size + ", useTCP: " + useTCP); } /** * Hash code. */ @Override public int hashCode() { return theList.hashCode(); } /** * Equals. */ @Override public boolean equals(Object o) { return theList.equals(o); } /** * Contains key. */ @Override public boolean containsKey(Object o) { return theList.containsKey(o); } /** * Contains value. */ @Override public boolean containsValue(Object o) { return theList.containsValue(o); } /** * Get the values as Collection. */ @Override public Collection values() { synchronized (theList) { return new ArrayList(theList.values()); } } /** * Get the keys as set. */ @Override public Set keySet() { synchronized (theList) { return theList.keySet(); } } /** * Get the entries as Set. */ @Override public Set> entrySet() { synchronized (theList) { return theList.entrySet(); } } /** * Get the internal list, convert from Collection. */ public List getValueList() { synchronized (theList) { return new ArrayList(theList.values()); } } /** * Get the internal sorted map. For synchronization purpose in normalform. */ public SortedMap getList() { return theList; } /** * Size of the (local) list. */ @Override public int size() { synchronized (theList) { return theList.size(); } } /** * Is the List empty? */ @Override public boolean isEmpty() { synchronized (theList) { return theList.isEmpty(); } } /** * List key iterator. */ public Iterator iterator() { synchronized (theList) { return theList.keySet().iterator(); } } /** * List value iterator. */ public Iterator valueIterator() { synchronized (theList) { return theList.values().iterator(); } } /** * Put object to the distributed hash table. Blocks until the key value pair * is send and received from the server. * @param key * @param value */ public void putWait(K key, V value) { put(key, value); // = send // assume key does not change multiple times before test: V val = null; do { val = getWait(key); //System.out.print("#"); } while (!value.equals(val)); } /** * Put object to the distributed hash table. Returns immediately after * sending does not block. * @param key * @param value */ @Override public V put(K key, V value) { if (key == null || value == null) { throw new NullPointerException("null keys or values not allowed"); } try { DHTTransport tc = DHTTransport. create(key, value); for (int i = 1; i < size; i++) { // send not to self.listener if (useTCP) { soc[i].send(tc); } else { DHTTransport[] tcl = new DHTTransport[] { tc }; synchronized (MPIEngine.class) { // do not remove engine.Send(tcl, 0, tcl.length, MPI.OBJECT, i, DHTTAG); } } } synchronized (theList) { // add to self.listener theList.put(key, value); //avoid seri: tc.key(), tc.value()); theList.notifyAll(); } if (debug) { K k = tc.key(); if (!key.equals(k)) { logger.warn("deserial(serial)) != key: " + key + " != " + k); } V v = tc.value(); if (!value.equals(v)) { logger.warn("deserial(serial)) != value: " + value + " != " + v); } } //System.out.println("send: "+tc); } catch (ClassNotFoundException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } catch (MPIException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } catch (IOException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } return null; } /** * Get value under key from DHT. Blocks until the object is send and * received from the server (actually it blocks until some value under key * is received). * @param key * @return the value stored under the key. */ public V getWait(K key) { V value = null; try { synchronized (theList) { value = theList.get(key); while (value == null) { //System.out.print("-"); theList.wait(100); value = theList.get(key); } } } catch (InterruptedException e) { //Thread.currentThread().interrupt(); e.printStackTrace(); return value; } return value; } /** * Get value under key from DHT. If no value is jet available null is * returned. * @param key * @return the value stored under the key. */ @Override public V get(Object key) { synchronized (theList) { return theList.get(key); } } /** * Clear the List. Caveat: must be called on all clients. */ @Override public void clear() { // send clear message to others synchronized (theList) { theList.clear(); } } /** * Initialize and start the list thread. */ public void init() { logger.info("init " + listener + ", theList = " + theList); if (listener == null) { return; } if (listener.isDone()) { return; } if (debug) { logger.debug("initialize " + listener); } synchronized (theList) { listener.start(); } } /** * Terminate the list thread. */ public void terminate() { if (listener == null) { return; } if (debug) { Runtime rt = Runtime.getRuntime(); logger.debug("terminate " + listener + ", runtime = " + rt.hashCode()); } listener.setDone(); DHTTransport tc = new DHTTransportTerminate(); try { if (rank == 0) { //logger.info("send(" + rank + ") terminate"); for (int i = 1; i < size; i++) { // send not to self.listener if (useTCP) { soc[i].send(tc); } else { DHTTransport[] tcl = new DHTTransport[] { tc }; synchronized (MPIEngine.class) { // do not remove engine.Send(tcl, 0, tcl.length, MPI.OBJECT, i, DHTTAG); } } } } } catch (MPIException e) { logger.info("sending(terminate)"); logger.info("send " + e); e.printStackTrace(); } catch (IOException e) { logger.info("sending(terminate)"); logger.info("send " + e); e.printStackTrace(); } try { while (listener.isAlive()) { //System.out.print("+++++"); listener.join(999); listener.interrupt(); } } catch (InterruptedException e) { //Thread.currentThread().interrupt(); } listener = null; } } /** * Thread to comunicate with the other DHT lists. */ class DHTMPIListener extends Thread { private static final Logger logger = LogManager.getLogger(DHTMPIListener.class); private static final boolean debug = logger.isDebugEnabled(); private final Comm engine; private final SortedMap theList; private final SocketChannel[] soc; private boolean goon; /** * Constructor. */ DHTMPIListener(Comm cm, SocketChannel[] s, SortedMap list) { engine = cm; theList = list; goon = true; soc = s; } /** * Test if done. */ boolean isDone() { return !goon; } /** * Set to done status. */ void setDone() { goon = false; } /** * run. */ @SuppressWarnings("unchecked") @Override public void run() { logger.info("listener run() " + this); int rank = -1; DHTTransport tc; //goon = true; while (goon) { tc = null; try { if (rank < 0) { rank = engine.Rank(); } if (rank == 0) { logger.info("listener on rank 0 stopped"); goon = false; continue; } Object to = null; if (DistHashTableMPI.useTCP) { to = soc[0].receive(); } else { DHTTransport[] tcl = new DHTTransport[1]; Status stat = null; synchronized (MPIEngine.class) { // do not remove global static lock, // only from 0: stat = engine.Recv(tcl, 0, tcl.length, MPI.OBJECT, 0, //MPI.ANY_SOURCE, DistHashTableMPI.DHTTAG); } //logger.info("waitRequest done: stat = " + stat); if (stat == null) { goon = false; break; } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { goon = false; break; } else if (cnt > 1) { logger.warn("ignoring " + (cnt - 1) + " received objects"); } to = tcl[0]; } tc = (DHTTransport) to; if (debug) { logger.debug("receive(" + tc + ")"); } if (tc instanceof DHTTransportTerminate) { logger.info("receive(" + rank + ") terminate"); goon = false; break; } if (this.isInterrupted()) { goon = false; break; } K key = tc.key(); if (key != null) { logger.info("receive(" + rank + "), key=" + key); V val = tc.value(); synchronized (theList) { theList.put(key, val); theList.notifyAll(); } } } catch (MPIException e) { goon = false; logger.warn("receive(MPI) " + e); //e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; logger.info("receive(Class) " + e); e.printStackTrace(); } catch (Exception e) { goon = false; logger.info("receive " + e); e.printStackTrace(); } } logger.info("terminated at " + rank); } } java-algebra-system-2.7.200/mpi/src/edu/jas/util/DistHashTableMPITest.java000066400000000000000000000116731445075545500261610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import mpi.MPIException; import edu.jas.kern.MPIEngine; /** * DistHashTableMPI test with JUnit. * @author Heinz Kredel */ public class DistHashTableMPITest extends TestCase { protected static Comm engine; /** * main. */ public static void main(String[] args) throws IOException, MPIException { //long t = System.currentTimeMillis(); engine = MPIEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); MPIEngine.terminate(); //t = System.currentTimeMillis() - t; //System.out.println("MPI runtime = " + t + " milli seconds"); } /** * Constructs a DistHashTableMPITest object. * @param name String. */ public DistHashTableMPITest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(DistHashTableMPITest.class); return suite; } private DistHashTableMPI l1; private DistHashTableMPI l2; private DistHashTableMPI l3; @Override protected void setUp() { } @Override protected void tearDown() { if (l1 != null) l1.terminate(); if (l2 != null) l2.terminate(); if (l3 != null) l3.terminate(); l1 = l2 = l3 = null; try { //Thread.currentThread(); //System.out.println("tearDown: sleep = 1"); Thread.sleep(1); } catch (InterruptedException e) { } } /** * Tests create and terminate DistHashTableMPI. */ public void xtestDistHashTable1() throws MPIException, IOException { l1 = new DistHashTableMPI(engine); l1.init(); assertTrue("l1==empty", l1.isEmpty()); } /** * Tests if the created DistHashTable has #n objects as content. */ public void xtestDistHashTable2() throws MPIException, IOException { int me = engine.Rank(); l1 = new DistHashTableMPI(engine); l1.init(); assertTrue("l1==empty", l1.isEmpty()); Integer s = 0; if (me == 0) { l1.putWait(Integer.valueOf(1), Integer.valueOf(1)); } else { s = l1.getWait(Integer.valueOf(1)); } assertFalse("l1!=empty: ", l1.isEmpty()); assertTrue("#l1==1: " + l1.getList(), l1.size() >= 1); assertEquals("s == 1: ", s, Integer.valueOf(1)); if (me == 0) { l1.putWait(Integer.valueOf(2), Integer.valueOf(2)); } else { s = l1.getWait(Integer.valueOf(2)); } assertTrue("#l1==2: " + l1.getList(), l1.size() >= 2); assertEquals("s == 2: ", s, Integer.valueOf(2)); if (me == 0) { l1.putWait(Integer.valueOf(3), Integer.valueOf(3)); } else { s = l1.getWait(Integer.valueOf(3)); } assertTrue("#l1==3: " + l1.getList(), l1.size() >= 3); assertEquals("s == 3: ", s, Integer.valueOf(3)); Iterator it = null; it = l1.iterator(); int i = 0; while (it.hasNext()) { Object k = it.next(); Object o = l1.get(k); Integer x = Integer.valueOf(++i); assertEquals("l1(i)==v(i)", x, o); assertEquals("l1(i)==k(i)", x, k); } l1.clear(); assertTrue("#l1==0", l1.size() == 0); } /** * Tests if the two created DistHashTables have #n objects as content. */ public void testDistHashTable3() throws MPIException, IOException { int me = engine.Rank(); l2 = new DistHashTableMPI(engine); l2.init(); //System.out.println("test3: me = " + me + ", l2 = "+ l2); assertTrue("l2==empty", l2.isEmpty()); int i = 0, loops = 10; while (i < loops) { Integer x = Integer.valueOf(++i); //System.out.println("me = " + me + ", x = "+ x); if (me == 0) { l2.putWait(x, x); } else { Integer s = l2.getWait(x); assertEquals("s = x: " + s + ", " + x, s, x); } assertTrue("#l1==i: " + i + ", #l1 = " + l2.size(), l2.size() >= i); } assertTrue("#l2==" + loops, l2.size() == loops); Iterator it = l2.iterator(); i = 0; while (it.hasNext()) { Object k = it.next(); Object o = l2.get(k); Integer x = Integer.valueOf(++i); //System.out.println("me = " + me + ", o = " + o + ", x = "+ x); assertEquals("l2(i)==k(i)", x, k); assertEquals("l2(i)==v(i)", x, o); } } } java-algebra-system-2.7.200/mpi/src/edu/jas/util/MPIChannel.java000066400000000000000000000153471445075545500242140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Arrays; import mpi.Comm; import mpi.MPI; import mpi.MPIException; import mpi.Status; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPIEngine; /** * MPIChannel provides a communication channel for Java objects using MPI or * TCP/IP to a given rank. * @author Heinz Kredel */ public final class MPIChannel { private static final Logger logger = LogManager.getLogger(MPIChannel.class); public static final int CHANTAG = MPIEngine.TAG + 2; /* * Underlying MPI engine. */ private final Comm engine; // essentially static when useTCP ! /* * Size of Comm. */ private final int size; /* * This rank. */ private final int rank; /* * TCP/IP object channels with tags. */ private static TaggedSocketChannel[] soc = null; /* * Transport layer. * true: use TCP/IP socket layer, false: use MPI transport layer. * Can not be set to false for OpenMPI Java: not working. */ static final boolean useTCP = true; /* * Partner rank. */ private final int partnerRank; /* * Message tag. */ private final int tag; /** * Constructs a MPI channel on the given MPI engine. * @param s MPI communicator object. * @param r rank of MPI partner. */ public MPIChannel(Comm s, int r) throws IOException, MPIException { this(s, r, CHANTAG); } /** * Constructs a MPI channel on the given MPI engine. * @param s MPI communicator object. * @param r rank of MPI partner. * @param t tag for messages. */ public MPIChannel(Comm s, int r, int t) throws IOException, MPIException { engine = s; rank = engine.Rank(); size = engine.Size(); if (r < 0 || size <= r) { throw new IOException("r out of bounds: 0 <= r < size: " + r + ", " + size); } partnerRank = r; tag = t; synchronized (engine) { if (soc == null && useTCP) { int port = ChannelFactory.DEFAULT_PORT; ChannelFactory cf; if (rank == 0) { cf = new ChannelFactory(port); cf.init(); soc = new TaggedSocketChannel[size]; soc[0] = null; try { for (int i = 1; i < size; i++) { SocketChannel sc = cf.getChannel(); // TODO not correct wrt rank soc[i] = new TaggedSocketChannel(sc); soc[i].init(); } } catch (InterruptedException e) { throw new IOException(e); } cf.terminate(); } else { cf = new ChannelFactory(port - 1); // in case of localhost soc = new TaggedSocketChannel[1]; SocketChannel sc = cf.getChannel(MPIEngine.hostNames.get(0), port); soc[0] = new TaggedSocketChannel(sc); soc[0].init(); cf.terminate(); } } } logger.info("constructor: " + this.toString() + ", useTCP: " + useTCP); } /** * Get the MPI engine. */ public Comm getEngine() { return engine; } /** * Sends an object. * @param v message object. */ public void send(Object v) throws IOException, MPIException { send(tag, v, partnerRank); } /** * Sends an object. * @param t message tag. * @param v message object. */ public void send(int t, Object v) throws IOException, MPIException { send(t, v, partnerRank); } /** * Sends an object. * @param t message tag. * @param v message object. * @param pr partner rank. */ void send(int t, Object v, int pr) throws IOException, MPIException { if (useTCP) { if (soc == null) { logger.warn("soc not initialized: lost " + v); return; } if (soc[pr] == null) { logger.warn("soc[" + pr + "] not initialized: lost " + v); return; } soc[pr].send(t, v); } else { Object[] va = new Object[] { v }; //synchronized (MPJEngine.class) { engine.Send(va, 0, va.length, MPI.OBJECT, pr, t); //} } } /** * Receives an object. * @return a message object. */ public Object receive() throws IOException, ClassNotFoundException, MPIException { return receive(tag); } /** * Receives an object. * @param t message tag. * @return a message object. */ public Object receive(int t) throws IOException, ClassNotFoundException, MPIException { if (useTCP) { if (soc == null) { logger.warn("soc not initialized"); return null; } if (soc[partnerRank] == null) { logger.warn("soc[" + partnerRank + "] not initialized"); return null; } try { return soc[partnerRank].receive(t); } catch (InterruptedException e) { throw new IOException(e); } } Object[] va = new Object[1]; Status stat = null; //synchronized (MPJEngine.class) { stat = engine.Recv(va, 0, va.length, MPI.OBJECT, partnerRank, t); //} if (stat == null) { throw new IOException("received null Status"); } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { throw new IOException("no object received"); } if (cnt > 1) { logger.warn("too many objects received, ignored " + (cnt - 1)); } // int pr = stat.source; // if (pr != partnerRank) { // logger.warn("received out of order message from " + pr); // } return va[0]; } /** * Closes the channel. */ public void close() { if (useTCP) { if (soc == null) { return; } for (int i = 0; i < soc.length; i++) { if (soc[i] != null) { soc[i].close(); soc[i] = null; } } } } /** * to string. */ @Override public String toString() { return "MPIChannel(on=" + rank + ",to=" + partnerRank + ",tag=" + tag + "," + Arrays.toString(soc) + ")"; } } java-algebra-system-2.7.200/mpj/000077500000000000000000000000001445075545500163245ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/.gitignore000066400000000000000000000000461445075545500203140ustar00rootroot00000000000000/test /*.jar /*.out /classes /*.class java-algebra-system-2.7.200/mpj/Makefile000066400000000000000000000071551445075545500177740ustar00rootroot00000000000000# # $Id$ # # Makefile for the (Fast) MPJ (Express) dependend parts # by Heinz kredel # #JASPATH=$(HOME)/jas JASPATH=.. LIBPATH=$(HOME)/java/lib FMPJ_HOME=$(HOME)/java/fastmpj FMPJ_LIB=$(FMPJ_HOME)/lib/mpj.jar MPJE_HOME=$(HOME)/java/mpj-v0_44 MPJE_BIN=$(MPJE_HOME)/bin NP=2 PPN=3 CLASSPATH=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar:$(LIBPATH)/junit-4.12.jar:$(FMPJ_LIB):$(JASPATH) #$(LIBPATH)/jas.jar CLASSPATHE=$(LIBPATH)/log4j-core-2.17.1.jar:$(LIBPATH)/log4j-api-2.17.1.jar:$(LIBPATH)/junit-4.12.jar:$(JASPATH) #LOG4JPATH=$(LIBPATH)/log4j-core-2.13.2.jar:$(LIBPATH)/log4j-api-2.13.2.jar #FMPJ_RUNLIB=$(FMPJ_HOME)/lib/runtime.jar #FMPJ_CMD=java -cp $(FMPJ_RUNLIB) runtime.FMPJRun -dev niodev -cp $(CLASSPATH):jas-mpj.jar FMPJ_CMD=$(FMPJ_HOME)/bin/fmpjrun -dev niodev -dmap -cp $(CLASSPATH):jas-mpj.jar #FMPJ_CMD=$(FMPJ_HOME)/bin/fmpjrun -dev psmdev -dmap -cp $(CLASSPATH):jas-mpj.jar #old MPJE_CMD=$(MPJE_HOME)/bin/mpjrun.sh -dev niodev -cp $(CLASSPATHE):jas-mpj.jar MPJE_CMD=mpjrun.sh -dev niodev -cp $(CLASSPATHE):classes:jas-mpj.jar #MPJE_CMD=mpjrun.sh -dev hybdev -cp "$(CLASSPATHE):classes:jas-mpj.jar" #DOCOPTS=-package DOCOPTS=-package -author -version -linksource -Xdoclint:none -overview overview.html DOCCLASSES=$(CLASSPATH) DOC=javadoc -classpath $(DOCCLASSES) # --- syncing ---------- DRY=--dry-run DELETE= RSYNC=rsync -e ssh -avuz $(DRY) $(DELETE) --exclude=*~ --exclude=*.log* --exclude=*.out* --exclude=*.txt* --exclude=.svn .SUFFIXES : .class .java .jar .PHONY : clean FILES=$(wildcard src/edu/jas/*/*.java) #echo $(FILES) $(JASPATH)/examples/jas.py CLASSES=$(subst src,classes,$(subst java,class,$(FILES))) #echo $(CLASSES) all: jas-mpj.jar $(CLASSES): $(FILES) Makefile -mkdir -p classes javac -classpath $(CLASSPATH) -d classes src/edu/jas/*/*.java # fmpjc -classpath $(CLASSPATH) -d classes src/edu/jas/*/*.java jas-mpj.jar: $(CLASSES) -mkdir -p classes/META-INF cp -a manifest.mf classes/META-INF/MANIFEST.MF jar cfM jas-mpj.jar -C classes . cp -f jas-mpj.jar $(LIBPATH) cp -f jas-mpj.jar .. clean: rm -rf classes find . -name "*~" -follow -print -exec rm {} \; MFILE=machines #EFILE=$(JASPATH)/examples/ideal_one.jas #EFILE=$(JASPATH)/examples/ideal_zero.jas EFILE=$(JASPATH)/examples/trinks6.jas fmpjtests: jas-mpj.jar FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -np $(NP) -machinefile $(MFILE) -class edu.jas.application.RunMPJGB disthybmpj $(EFILE) $(NP)/$(PPN) $(MFILE) # $(FMPJ_CMD) -np $(NP) -machinefile $(MFILE) -class edu.jas.application.RunMPJGB disthybmpj $(EFILE) $(NP)/$(PPN) $(MFILE) notest: jas-mpj.jar FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -np $(NP) -machinefile $(MFILE) -class edu.jas.application.RunMPJGB distmpj $(EFILE) $(NP) $(MFILE) FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -class edu.jas.gb.HelloWorld FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -class edu.jas.kern.MPJEngineTest -n $(NP) FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -class edu.jas.util.DistHashTableMPJTest -n $(NP) gbtest: jas-mpj.jar FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -np $(NP) -machinefile $(MFILE) -class edu.jas.gb.GroebnerBaseDistMPJTest gbhybtest: jas-mpj.jar FMPJ_HOME=$(FMPJ_HOME) $(FMPJ_CMD) -np $(NP) -machinefile $(MFILE) -class edu.jas.gb.GroebnerBaseDistHybridMPJTest tests: jas-mpj.jar #export PATH=$(PATH):$(MPJE_BIN); export MPJ_HOME=$(MPJE_HOME); $(MPJE_BIN)/mpjboot machines $(MPJE_BIN)/$(MPJE_CMD) -np $(NP) edu.jas.application.RunMPJGB disthybmpj $(EFILE) $(NP)/$(PPN) $(MFILE) nolog nocheck $(MPJE_BIN)/mpjhalt machines doc: $(FILES) $(DOC) $(DOCOPTS) -d ../doc/mpj $(FILES) BWDIR=java/jas-2.5/mpj home: $(RSYNC) bwgrid:$(BWDIR)/src/ src bwgrid: $(RSYNC) src/ bwgrid:$(BWDIR)/src/ java-algebra-system-2.7.200/mpj/machines000066400000000000000000000000241445075545500200320ustar00rootroot00000000000000localhost localhost java-algebra-system-2.7.200/mpj/manifest.mf000066400000000000000000000001011445075545500204460ustar00rootroot00000000000000Manifest-Version: 1.0 Main-Class: edu.jas.application.RunMPJGB java-algebra-system-2.7.200/mpj/overview.html000066400000000000000000000031461445075545500210640ustar00rootroot00000000000000 Java Algebra System, MPJ part

Java algebra system, MPJ part.

The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through an jython (Java Python) or jruby (Java Ruby) front ends. The focus of JAS is at the moment on commutative, solvable and non-commuative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core cpu ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android (using the jruby Ruboto App and others) to compute clusters (using MPJ a Java Message Passing Interface (MPI)).

See introduction for a general overview.


Heinz Kredel

Last modified: Sat Oct 5 21:53:42 CEST 2013

$Id$

java-algebra-system-2.7.200/mpj/src/000077500000000000000000000000001445075545500171135ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/000077500000000000000000000000001445075545500176705ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/000077500000000000000000000000001445075545500204455ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/application/000077500000000000000000000000001445075545500227505ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/application/RunMPJGB.java000066400000000000000000000255501445075545500251460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseDistributedEC; import edu.jas.gb.GroebnerBaseDistributedHybridEC; import edu.jas.gb.GroebnerBaseDistributedHybridMPJ; import edu.jas.gb.GroebnerBaseDistributedMPJ; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.ReductionPar; import edu.jas.gb.ReductionSeq; import edu.jas.gbufd.GBFactory; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPJEngine; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.util.CatReader; import edu.jas.util.ExecutableServer; /** * Simple setup to run a GB example in MPJ environment.
* Usage: RunGB [seq(+)|par(+)|dist(1)(+)|disthyb|cli] <file> * #procs/#threadsPerNode [machinefile] * @author Heinz Kredel */ public class RunMPJGB { /** * Check result GB if it is a GB. */ static boolean doCheck = false; /** * main method to be called from commandline
* Usage: RunMPJGB [seq|par(+)|dist(1)(+)|disthyb|cli] <file> * #procs/#threadsPerNode [machinefile] */ @SuppressWarnings("unchecked") public static void main(String[] args) throws IOException { MPJEngine.setCommandLine(args); //args = MPI.Init(args); String[] allkinds = new String[] { "seq", "seq+", "par", "par+", "dist", "dist+", "disthyb", "disthyb+", "distmpj", "distmpj+", "disthybmpj", "disthybmpj+", "cli" }; String usage = "Usage: RunGB [ " + RunGB.join(allkinds, " | ") + "[port] ] " + " " + "#procs/#threadsPerNode " + "[machinefile] " + "[check]"; if (args.length < 1) { System.out.println("args: " + Arrays.toString(args)); System.out.println(usage); return; } boolean plusextra = false; String kind = args[0]; boolean sup = false; int k = -1; for (int i = 0; i < args.length; i++) { int j = RunGB.indexOf(allkinds, args[i]); if (j < 0) { continue; } sup = true; k = i; kind = args[k]; break; } if (!sup) { System.out.println("args(sup): " + Arrays.toString(args)); System.out.println(usage); return; } if (kind.indexOf("+") >= 0) { plusextra = true; } System.out.println("kind: " + kind + ", k = " + k); final int GB_SERVER_PORT = 7114; int port = GB_SERVER_PORT; if (kind.equals("cli")) { if (args.length - k >= 2) { try { port = Integer.parseInt(args[k + 1]); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(port): " + Arrays.toString(args)); System.out.println(usage); return; } } RunGB.runClient(port); return; } String filename = null; if (!kind.equals("cli")) { if (args.length - k < 2) { System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } filename = args[k + 1]; } int j = RunGB.indexOf(args, "check"); if (j >= 0) { doCheck = true; RunGB.doCheck = true; } int threads = 0; int threadsPerNode = 1; if (kind.startsWith("par") || kind.startsWith("dist")) { if (args.length - k < 3) { System.out.println("args(par|dist): " + Arrays.toString(args)); System.out.println(usage); return; } String tup = args[k + 2]; String t = tup; int i = tup.indexOf("/"); if (i >= 0) { t = tup.substring(0, i).trim(); tup = tup.substring(i + 1).trim(); try { threadsPerNode = Integer.parseInt(tup); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threadsPerNode): " + Arrays.toString(args)); System.out.println(usage); return; } } try { threads = Integer.parseInt(t); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threads): " + Arrays.toString(args)); System.out.println(usage); return; } } String mfile = null; if (kind.startsWith("dist")) { if (args.length - k >= 4) { mfile = args[k + 3]; } else { mfile = "machines"; } } Reader problem = RunGB.getReader(filename); if (problem == null) { System.out.println("args(file): " + filename); System.out.println("args(file): examples.jar(" + filename + ")"); System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } RingFactoryTokenizer rftok = new RingFactoryTokenizer(problem); GenPolynomialRing pfac = null; try { pfac = rftok.nextPolynomialRing(); rftok = null; } catch (IOException e) { e.printStackTrace(); return; } Reader polyreader = new CatReader(new StringReader("("), problem); // ( has gone //Reader polyreader = problem; GenPolynomialTokenizer tok = new GenPolynomialTokenizer(pfac, polyreader); PolynomialList S = null; try { S = new PolynomialList(pfac, tok.nextPolynomialList()); } catch (IOException e) { e.printStackTrace(); return; } System.out.println("S =\n" + S); if (kind.startsWith("seq")) { RunGB.runSequential(S, plusextra); } else if (kind.startsWith("par")) { RunGB.runParallel(S, threads, plusextra); } else if (kind.startsWith("distmpj")) { runMpj(S, threads, mfile, port, plusextra); } else if (kind.startsWith("disthybmpj")) { runHybridMpj(S, threads, threadsPerNode, mfile, port, plusextra); } else if (kind.startsWith("disthyb")) { RunGB.runMasterHyb(S, threads, threadsPerNode, mfile, port, plusextra); } else if (kind.startsWith("dist")) { RunGB.runMaster(S, threads, mfile, port, plusextra); } ComputerThreads.terminate(); //System.exit(0); } @SuppressWarnings("unchecked") static void runMpj(PolynomialList S, int threads, String mfile, int port, boolean plusextra) throws IOException { List L = S.list; List G = null; long t, t1; t = System.currentTimeMillis(); System.out.println("\nGroebner base distributed MPJ (" + threads + ", " + mfile + ", " + port + ") ..."); GroebnerBaseDistributedMPJ gbd = null; GroebnerBaseDistributedMPJ gbds = null; if (plusextra) { gbds = new GroebnerBaseDistributedMPJ(threads, new OrderedSyzPairlist()); } else { gbd = new GroebnerBaseDistributedMPJ(threads); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); } else { gbd.terminate(); } MPJEngine.terminate(); if (G == null) { return; // mpi.rank != 0 } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("m+ "); } else { System.out.print("m "); } System.out.println("= " + threads + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); RunGB.checkGB(S); System.out.println(""); } @SuppressWarnings("unchecked") static void runHybridMpj(PolynomialList S, int threads, int threadsPerNode, String mfile, int port, boolean plusextra) throws IOException { List L = S.list; List G = null; long t, t1; t = System.currentTimeMillis(); System.out.println("\nGroebner base distributed hybrid MPJ (" + threads + "/" + threadsPerNode + ", " + mfile + ", " + port + ") ..."); GroebnerBaseDistributedHybridMPJ gbd = null; GroebnerBaseDistributedHybridMPJ gbds = null; if (plusextra) { gbds = new GroebnerBaseDistributedHybridMPJ(threads, threadsPerNode, new OrderedSyzPairlist()); } else { gbd = new GroebnerBaseDistributedHybridMPJ(threads, threadsPerNode); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); } else { gbd.terminate(); } MPJEngine.terminate(); if (G == null) { return; // mpi.rank != 0 } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("m+ "); } else { System.out.print("m "); } System.out.println("= " + threads + ", ppn = " + threadsPerNode + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); RunGB.checkGB(S); System.out.println(""); } } java-algebra-system-2.7.200/mpj/src/edu/jas/gb/000077500000000000000000000000001445075545500210355ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/gb/GroebnerBaseDistHybridMPJTest.java000066400000000000000000000145641445075545500274450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPJEngine; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Distributed GroebnerBase MPJ tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistHybridMPJTest extends TestCase { protected static Comm engine; boolean mpjBug = true; // bug after cancel recv /** * main */ public static void main(String[] args) throws IOException { engine = MPJEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); engine.Barrier(); MPJEngine.terminate(); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistHybridMPJTest object. * @param name String. */ public GroebnerBaseDistHybridMPJTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistHybridMPJTest.class); return suite; } int port = 4711; String host = "localhost"; GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseDistributedHybridMPJ bbdist; GroebnerBaseDistributedHybridMPJ bbdists; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads; int threadsPerNode = 3; @Override protected void setUp() { try { threads = engine.Size(); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdist = new GroebnerBaseDistributedHybridMPJ(threads, threadsPerNode); //bbdists = new GroebnerBaseDistributedHybridMPJ(threads,threadsPerNode, new OrderedSyzPairlist()); } catch (IOException e) { e.printStackTrace(); } } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; //bbdists.terminate(); bbdists = null; ComputerThreads.terminate(); } /** * Test distributed GBase. */ public void onlyOnetestDistributedGBase() { L = new ArrayList>(); if (engine.Rank() == 0) { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); } if (engine.Rank() == 0) { L.add(a); L.add(b); System.out.println("L = " + L); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L0 = " + L); assertTrue("isGB( { a } )", bbseq.isGB(L)); L.add(b); } if (mpjBug) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } return; } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L1 = " + L); assertTrue("isGB( { a, b } )", bbseq.isGB(L)); L.add(c); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L2 = " + L); assertTrue("isGB( { a, b, c } )", bbseq.isGB(L)); L.add(d); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L3 = " + L); assertTrue("isGB( { a, b, c, d } )", bbseq.isGB(L)); L.add(e); } L = bbdist.GB(L); if (engine.Rank() == 0) { System.out.println("L4 = " + L); assertTrue("isGB( { a, b, c, d, e } )", bbseq.isGB(L)); } else { System.out.println("rank = " + engine.Rank()); } } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { List> Fl; long t = 0; if (engine.Rank() == 0) { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } System.out.println("F = " + F); Fl = F.list; t = System.currentTimeMillis(); } else { Fl = null; } G = bbdist.GB(Fl); if (engine.Rank() == 0) { t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + G); System.out.println("executed in " + t + " milliseconds"); } else { assertTrue("G == null: ", G == null); } } } java-algebra-system-2.7.200/mpj/src/edu/jas/gb/GroebnerBaseDistMPJTest.java000066400000000000000000000140341445075545500262730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.MPJEngine; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Distributed GroebnerBase MPJ tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistMPJTest extends TestCase { protected static Comm engine; boolean mpjBug = true; // bug after cancel recv /** * main */ public static void main(String[] args) throws IOException { engine = MPJEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); engine.Barrier(); MPJEngine.terminate(); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistMPJTest object. * @param name String. */ public GroebnerBaseDistMPJTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistMPJTest.class); return suite; } int port = 4711; String host = "localhost"; GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseDistributedMPJ bbdist; GroebnerBaseDistributedMPJ bbdists; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads; @Override protected void setUp() { try { threads = engine.Size(); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdists = new GroebnerBaseDistributedMPJ(threads); bbdist = new GroebnerBaseDistributedMPJ(threads, new OrderedSyzPairlist()); } catch (IOException e) { e.printStackTrace(); } } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; bbdists.terminate(); bbdists = null; ComputerThreads.terminate(); } /** * Test distributed GBase. */ public void testDistributedGBase() { L = new ArrayList>(); if (engine.Rank() == 0) { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); } if (engine.Rank() == 0) { assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a } )", bbseq.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); } if (mpjBug) { return; } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b } )", bbseq.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c } )", bbseq.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c, d } )", bbseq.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); } L = bbdist.GB(L); if (engine.Rank() == 0) { assertTrue("isGB( { a, b, c, d, e } )", bbseq.isGB(L)); } } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { List> Fl; long t = 0; if (engine.Rank() == 0) { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } System.out.println("F = " + F); Fl = F.list; t = System.currentTimeMillis(); } else { Fl = null; } G = bbdists.GB(Fl); if (engine.Rank() == 0) { t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + G); System.out.println("executed in " + t + " milliseconds"); } } } java-algebra-system-2.7.200/mpj/src/edu/jas/gb/GroebnerBaseDistributedHybridMPJ.java000066400000000000000000001012301445075545500301470ustar00rootroot00000000000000/* * $Id: GroebnerBaseDistributedHybridMPJ.java 4952 2014-10-12 19:41:46Z axelclk * $ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.atomic.AtomicInteger; import mpi.Comm; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPJEngine; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.DistHashTableMPJ; import edu.jas.util.MPJChannel; import edu.jas.util.Terminator; import edu.jas.util.ThreadPool; /** * Groebner Base distributed hybrid algorithm with MPJ. Implements a distributed * memory with multi-core CPUs parallel version of Groebner bases with MPJ. * Using pairlist class, distributed multi-threaded tasks do reduction, one * communication channel per remote node. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedHybridMPJ> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedHybridMPJ.class); public final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ protected static final int DEFAULT_THREADS = 2; /** * Number of threads per node to use. */ protected final int threadsPerNode; /** * Default number of threads per compute node. */ protected static final int DEFAULT_THREADS_PER_NODE = 1; /** * Pool of threads to use. */ //protected final ExecutorService pool; // not for single node tests protected transient final ThreadPool pool; /* * Underlying MPJ engine. */ protected transient final Comm engine; /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridEC.pairTag.intValue(); /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridEC.resultTag.intValue(); /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridEC.ackTag.intValue(); /** * Constructor. */ public GroebnerBaseDistributedHybridMPJ() throws IOException { this(DEFAULT_THREADS); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseDistributedHybridMPJ(int threads) throws IOException { this(threads, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. */ public GroebnerBaseDistributedHybridMPJ(int threads, int threadsPerNode) throws IOException { this(threads, threadsPerNode, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. */ public GroebnerBaseDistributedHybridMPJ(int threads, ThreadPool pool) throws IOException { this(threads, DEFAULT_THREADS_PER_NODE, pool); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedHybridMPJ(int threads, int threadsPerNode, PairList pl) throws IOException { this(threads, threadsPerNode, new ThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. */ public GroebnerBaseDistributedHybridMPJ(int threads, int threadsPerNode, ThreadPool pool) throws IOException { this(threads, threadsPerNode, pool, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pool ThreadPool to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedHybridMPJ(int threads, int threadsPerNode, ThreadPool pool, PairList pl) throws IOException { super(new ReductionPar(), pl); this.engine = MPJEngine.getCommunicator(); int size = engine.Size(); if (size < 2) { throw new IllegalArgumentException("Minimal 2 MPJ processes required, not " + size); } if (threads != size || pool.getNumber() != size) { throw new IllegalArgumentException("threads != size: " + threads + " != " + size + ", #pool " + pool.getNumber()); } this.threads = threads; this.pool = pool; this.threadsPerNode = threadsPerNode; //logger.info("generated pool: " + pool); } /** * Cleanup and terminate. */ @Override public void terminate() { if (pool == null) { return; } //pool.terminate(); pool.cancel(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs or on * MPJ client part. */ public List> GB(int modv, List> F) { try { if (engine.Rank() == 0) { return GBmaster(modv, F); } } catch (IOException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } pool.terminate(); // not used on clients try { clientPart(0); // only 0 } catch (IOException e) { logger.info("clientPart: " + e); e.printStackTrace(); } return null; } /** * Distributed hybrid Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ List> GBmaster(int modv, List> F) throws IOException { long t = System.currentTimeMillis(); List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { //return G; } if (G.isEmpty()) { throw new IllegalArgumentException("empty F / zero ideal not allowed"); } GenPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(G); /* GenPolynomial p; List> G = new ArrayList>(); PairList pairlist = null; boolean oneInGB = false; int l = F.size(); int unused = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; G.clear(); G.add(p); //return G; must signal termination to others } if (!oneInGB) { G.add(p); } if (pairlist == null) { //pairlist = new OrderedPairlist(modv, p.ring); pairlist = strategy.create(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { l--; } } //if (l <= 1) { //return G; must signal termination to others //} */ logger.info("pairlist " + pairlist); logger.debug("looking for clients"); DistHashTableMPJ> theList = new DistHashTableMPJ>( engine); theList.init(); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { // no wait required GenPolynomial nn = theList.put(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i)); } } Terminator finner = new Terminator((threads - 1) * threadsPerNode); HybridReducerServerMPJ R; logger.info("using pool = " + pool); for (int i = 1; i < threads; i++) { MPJChannel chan = new MPJChannel(engine, i); // closed in server R = new HybridReducerServerMPJ(i, threadsPerNode, finner, chan, theList, pairlist); pool.addJob(R); //logger.info("server submitted " + R); } logger.info("main loop waiting " + finner); finner.waitDone(); int ps = theList.size(); logger.info("#distributed list = " + ps); // make sure all polynomials arrived: not needed in master G = pairlist.getList(); if (ps != G.size()) { logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size()); } for (GenPolynomial q : theList.getValueList()) { if (q != null && !q.isZERO()) { logger.debug("final q = " + q.leadingExpVector()); } } logger.debug("distributed list end"); long time = System.currentTimeMillis(); List> Gp; Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi time = " + time); G = Gp; logger.info("server theList.terminate() " + theList.size()); theList.terminate(); t = System.currentTimeMillis() - t; logger.info("server GB end, time = " + t + ", " + pairlist.toString()); return G; } /** * GB distributed client. * @param rank of the MPJ where the server runs on. * @throws IOException */ public void clientPart(int rank) throws IOException { if (rank != 0) { throw new UnsupportedOperationException("only master at rank 0 implemented: " + rank); } Comm engine = MPJEngine.getCommunicator(); DistHashTableMPJ> theList = new DistHashTableMPJ>(); theList.init(); MPJChannel chan = new MPJChannel(engine, rank); ThreadPool pool = new ThreadPool(threadsPerNode); logger.info("client using pool = " + pool); for (int i = 0; i < threadsPerNode; i++) { HybridReducerClientMPJ Rr = new HybridReducerClientMPJ(chan, theList); // i pool.addJob(Rr); } if (debug) { logger.info("clients submitted"); } pool.terminate(); logger.info("client pool.terminate()"); chan.close(); theList.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @SuppressWarnings("unchecked") @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB MiMPJReducerServer[] mirs = (MiMPJReducerServer[]) new MiMPJReducerServer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiMPJReducerServer(R, a); pool.addJob(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker proxy threads. * @param coefficient type */ class HybridReducerServerMPJ> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerServerMPJ.class); public final boolean debug = logger.isDebugEnabled(); private final Terminator finner; private final MPJChannel pairChannel; //protected transient final Comm engine; private final DistHashTableMPJ> theList; private final PairList pairlist; private final int threadsPerNode; final int rank; /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridMPJ.pairTag; /** * Constructor. * @param r MPJ rank of partner. * @param tpn number of threads per node * @param fin terminator * @param chan MPJ channel * @param dl distributed hash table * @param L ordered pair list */ HybridReducerServerMPJ(int r, int tpn, Terminator fin, MPJChannel chan, DistHashTableMPJ> dl, PairList L) { rank = r; threadsPerNode = tpn; finner = fin; this.pairChannel = chan; theList = dl; pairlist = L; //logger.info("reducer server created " + this); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override @SuppressWarnings("unchecked") public void run() { //logger.info("reducer server running with " + engine); // try { // pairChannel = new MPJChannel(engine, rank); //,pairTag // } catch (IOException e) { // e.printStackTrace(); // return; // } if (logger.isInfoEnabled()) { logger.info("reducer server running: pairChannel = " + pairChannel); } // record idle remote workers (minus one?) //finner.beIdle(threadsPerNode-1); finner.initIdle(threadsPerNode); AtomicInteger active = new AtomicInteger(0); // start receiver HybridReducerReceiverMPJ receiver = new HybridReducerReceiverMPJ(rank, finner, active, pairChannel, theList, pairlist); receiver.start(); Pair pair; //boolean set = false; boolean goon = true; //int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request if thread is reported incactive logger.debug("receive request"); Object req = null; try { req = pairChannel.receive(pairTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } logger.debug("received request, req = " + req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair and manage termination status logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!finner.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 3 == 0) { logger.info("waiting for reducers, remaining = " + finner.getJobs()); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (!pairlist.hasNext() && !finner.hasJobs()) { logger.info("termination detection: no pairs and no jobs left"); goon = false; break; //continue; //break? } finner.notIdle(); // before pairlist get!! pair = pairlist.removeNext(); // send pair to client, even if null if (debug) { logger.info("active count = " + active.get()); logger.info("send pair = " + pair); } GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); } else { msg = new GBTransportMess(); //not End(); at this time // goon ?= false; } try { red++; pairChannel.send(pairTag, msg); @SuppressWarnings("unused") int a = active.getAndIncrement(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } //logger.debug("#distributed list = " + theList.size()); } logger.info("terminated, send " + red + " reduction pairs"); /* * send end mark to clients */ logger.debug("send end"); try { for (int i = 0; i < threadsPerNode; i++) { // -1 pairChannel.send(pairTag, new GBTransportMessEnd()); } logger.info("sent end to clients"); // send also end to receiver, no more //pairChannel.send(resultTag, new GBTransportMessEnd(), engine.Rank()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } int d = active.get(); if (d > 0) { logger.info("remaining active tasks = " + d); } receiver.terminate(); //logger.info("terminated, send " + red + " reduction pairs"); pairChannel.close(); logger.info("redServ pairChannel.close()"); finner.release(); } } /** * Distributed server receiving worker thread. * @param coefficient type */ class HybridReducerReceiverMPJ> extends Thread { private static final Logger logger = LogManager.getLogger(HybridReducerReceiverMPJ.class); public final boolean debug = logger.isDebugEnabled(); private final DistHashTableMPJ> theList; private final PairList pairlist; private final MPJChannel pairChannel; final int rank; private final Terminator finner; //private final int threadsPerNode; private final AtomicInteger active; private volatile boolean goon; /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridMPJ.resultTag; /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridMPJ.ackTag; /** * Constructor. * @param r MPJ rank of partner. * @param fin terminator * @param a active remote tasks count * @param pc tagged socket channel * @param dl distributed hash table * @param L ordered pair list */ HybridReducerReceiverMPJ(int r, Terminator fin, AtomicInteger a, MPJChannel pc, DistHashTableMPJ> dl, PairList L) { rank = r; active = a; //threadsPerNode = tpn; finner = fin; pairChannel = pc; theList = dl; pairlist = L; goon = true; //logger.info("reducer server created " + this); } /** * Work loop. * @see java.lang.Thread#run() */ @Override @SuppressWarnings("unchecked") public void run() { //Pair pair = null; GenPolynomial H = null; int red = 0; int polIndex = -1; //Integer senderId; // obsolete // while more requests while (goon) { // receive request logger.debug("receive result"); //senderId = null; Object rh = null; try { rh = pairChannel.receive(resultTag); @SuppressWarnings("unused") int i = active.getAndDecrement(); //} catch (InterruptedException e) { //goon = false; ////e.printStackTrace(); ////?? finner.initIdle(1); //break; } catch (IOException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } logger.info("received result"); if (rh == null) { if (this.isInterrupted()) { goon = false; finner.initIdle(1); break; } //finner.initIdle(1); } else if (rh instanceof GBTransportMessEnd) { // should only happen from server logger.info("received GBTransportMessEnd"); goon = false; //?? finner.initIdle(1); break; } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; GBTransportMessPoly mpi = (GBTransportMessPoly) rh; H = mpi.pol; //senderId = mpi.threadId; if (H != null) { if (logger.isInfoEnabled()) { // debug logger.info("H = " + H.leadingExpVector()); } if (!H.isZERO()) { if (H.isONE()) { polIndex = pairlist.putOne(); //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); //goon = false; must wait for other clients //finner.initIdle(1); //break; } else { polIndex = pairlist.put(H); // use putWait ? but still not all distributed //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); } } } } // only after recording in pairlist ! finner.initIdle(1); try { pairChannel.send(ackTag, new GBTransportMess()); logger.debug("send acknowledgement"); } catch (IOException e) { e.printStackTrace(); goon = false; break; } } // end while goon = false; logger.info("terminated, received " + red + " reductions"); } /** * Terminate. */ public void terminate() { goon = false; try { this.join(); //this.interrupt(); } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); } logger.info("terminate end"); } } /** * Distributed clients reducing worker threads. */ class HybridReducerClientMPJ> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerClientMPJ.class); public final boolean debug = logger.isDebugEnabled(); private final MPJChannel pairChannel; private final DistHashTableMPJ> theList; private final ReductionPar red; //private final int threadsPerNode; /* * Identification number for this thread. */ //public final Integer threadId; // obsolete /** * Message tag for pairs. */ public static final int pairTag = GroebnerBaseDistributedHybridMPJ.pairTag; /** * Message tag for results. */ public static final int resultTag = GroebnerBaseDistributedHybridMPJ.resultTag; /** * Message tag for acknowledgments. */ public static final int ackTag = GroebnerBaseDistributedHybridMPJ.ackTag; /** * Constructor. * @param tc tagged socket channel * @param dl distributed hash table */ HybridReducerClientMPJ(MPJChannel tc, DistHashTableMPJ> dl) { //this.threadsPerNode = tpn; pairChannel = tc; //threadId = 100 + tid; // keep distinct from other tags theList = dl; red = new ReductionPar(); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override @SuppressWarnings("unchecked") public void run() { if (debug) { logger.info("pairChannel = " + pairChannel + " reducer client running"); } Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; boolean doEnd = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result, receive acknowledgment */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.debug("send request = " + req); try { pairChannel.send(pairTag, req); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } logger.info("receive pair, exception "); break; } logger.debug("receive pair, goon = " + goon); doEnd = true; Object pp = null; try { pp = pairChannel.receive(pairTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (debug) { logger.info("received pair = " + pp); } H = null; if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; //doEnd = false; // bug continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { pair = ((GBTransportMessPair) pp).pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = " + pair.i // + ", pjx = " + pair.j); } } if (pp instanceof GBTransportMessPairIndex) { pix = ((GBTransportMessPairIndex) pp).i; pjx = ((GBTransportMessPairIndex) pp).j; psx = ((GBTransportMessPairIndex) pp).s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); //logger.info("pix = " + pix + ", pjx = " +pjx + ", psx = " +psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //System.out.println("S = " + S); logger.info("ht(S) = " + S.leadingExpVector()); if (S.isZERO()) { // pair.setZero(); does not work in dist H = S; } else { if (debug) { logger.debug("ht(S) = " + S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = " + H.leadingExpVector()); } } } } else { logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps); } } if (pp instanceof GBTransportMess) { logger.debug("null pair results in null H poly"); } // send H or must send null, if not at end if (debug) { logger.debug("#distributed list = " + theList.size()); logger.debug("send H polynomial = " + H); } try { pairChannel.send(resultTag, new GBTransportMessPoly(H)); //,threadId)); doEnd = false; } catch (IOException e) { goon = false; e.printStackTrace(); } logger.debug("done send poly message of " + pp); try { pp = pairChannel.receive(ackTag); //} catch (InterruptedException e) { //goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; if (debug) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (!(pp instanceof GBTransportMess)) { logger.error("invalid acknowledgement " + pp); } logger.debug("received acknowledgment " + pp); } logger.info("terminated, done " + reduction + " reductions"); if (doEnd) { try { pairChannel.send(resultTag, new GBTransportMessEnd()); } catch (IOException e) { //e.printStackTrace(); } logger.info("terminated, send done"); } } } java-algebra-system-2.7.200/mpj/src/edu/jas/gb/GroebnerBaseDistributedMPJ.java000066400000000000000000000577271445075545500270320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPJEngine; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.DistHashTableMPJ; import edu.jas.util.MPJChannel; import edu.jas.util.Terminator; import edu.jas.util.ThreadPool; import mpi.Comm; /** * Groebner Base distributed algorithm with MPJ. Implements a distributed memory * parallel version of Groebner bases. Using MPJ and pairlist class, distributed * tasks do reduction. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedMPJ> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedMPJ.class); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ public static final int DEFAULT_THREADS = 2; /* * Pool of threads to use. Note: No ComputerThreads for one node * tests */ protected transient final ThreadPool pool; /* * Underlying MPJ engine. */ protected transient final Comm engine; /** * Constructor. */ public GroebnerBaseDistributedMPJ() throws IOException { this(DEFAULT_THREADS); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseDistributedMPJ(int threads) throws IOException { this(threads, new ThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. */ public GroebnerBaseDistributedMPJ(int threads, ThreadPool pool) throws IOException { this(threads, pool, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedMPJ(int threads, PairList pl) throws IOException { this(threads, new ThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. * @param pl pair selection strategy */ public GroebnerBaseDistributedMPJ(int threads, ThreadPool pool, PairList pl) throws IOException { super(new ReductionPar(), pl); this.engine = MPJEngine.getCommunicator(); int size = engine.Size(); if (size < 2) { throw new IllegalArgumentException("Minimal 2 MPJ processes required, not " + size); } if (threads != size || pool.getNumber() != size) { throw new IllegalArgumentException( "threads != size: " + threads + " != " + size + ", #pool " + pool.getNumber()); } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { if (pool == null) { return; } //pool.terminate(); pool.cancel(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs or on * MPJ client part. */ public List> GB(int modv, List> F) { try { if (engine.Rank() == 0) { return GBmaster(modv, F); } } catch (IOException e) { logger.info("GBmaster: " + e); e.printStackTrace(); return null; } pool.terminate(); // not used on clients try { clientPart(0); } catch (IOException e) { logger.info("clientPart: " + e); e.printStackTrace(); } return null; } /** * Distributed Groebner base, part for MPJ master. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ List> GBmaster(int modv, List> F) throws IOException { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { //return G; } if (G.isEmpty()) { throw new IllegalArgumentException("empty F / zero ideal not allowed"); } GenPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(G); /* List> G = new ArrayList>(); GenPolynomial p; PairList pairlist = null; boolean oneInGB = false; int l = F.size(); int unused = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; G.clear(); G.add(p); //return G; must signal termination to others } if (!oneInGB) { G.add(p); } if (pairlist == null) { pairlist = strategy.create(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { l--; } } //if (l <= 1) { //return G; must signal termination to others //} */ logger.info("done pairlist, initialize DHT: " + pairlist); DistHashTableMPJ> theList = new DistHashTableMPJ>( engine); theList.init(); //logger.info("done DHT: " + theList); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { // no wait required GenPolynomial nn = theList.put(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials " + i + ", nn = " + nn + ", al(i) = " + al.get(i)); } } Terminator fin = new Terminator(threads - 1); MPJReducerServer R; for (int i = 1; i < threads; i++) { logger.debug("addJob " + i + " of " + threads); MPJChannel chan = new MPJChannel(engine, i); // closed in server R = new MPJReducerServer(i, fin, chan, theList, pairlist); pool.addJob(R); } logger.debug("main loop waiting"); fin.waitDone(); int ps = theList.size(); logger.info("#distributed list = " + ps); // make sure all polynomials arrived: not needed in master // G = (ArrayList)theList.values(); G = pairlist.getList(); if (ps != G.size()) { logger.info("#distributed list = " + theList.size() + " #pairlist list = " + G.size()); } long time = System.currentTimeMillis(); List> Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi = " + time); G = Gp; logger.info("theList.terminate()"); theList.terminate(); logger.info("end" + pairlist); return G; } /** * GB distributed client. * @param rank of the MPJ where the server runs on. * @throws IOException */ public void clientPart(int rank) throws IOException { if (rank != 0) { throw new UnsupportedOperationException("only master at rank 0 implemented: " + rank); } Comm engine = MPJEngine.getCommunicator(); DistHashTableMPJ> theList = new DistHashTableMPJ>(); theList.init(); MPJChannel chan = new MPJChannel(engine, rank); MPJReducerClient R = new MPJReducerClient(chan, theList); R.run(); chan.close(); theList.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @SuppressWarnings("unchecked") @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB MiMPJReducerServer[] mirs = (MiMPJReducerServer[]) new MiMPJReducerServer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiMPJReducerServer(R, a); pool.addJob(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker threads. * @param coefficient type */ class MPJReducerServer> implements Runnable { /* * Termination detection coordinator. */ private final Terminator finaler; /* * Underlying MPJ engine. */ //protected transient final Comm engine; /* * MPJ channel. */ private final MPJChannel pairChannel; /* * GB rank. */ final int rank; /* * Distributed HashTable of polynomials. */ private final DistHashTableMPJ> theList; /* * Critical pair list of polynomials. */ private final PairList pairlist; private static final Logger logger = LogManager.getLogger(MPJReducerServer.class); /** * Constructor. * @param r MPJ rank of partner. * @param fin termination coordinator to use. * @param c MPJ channel to use. * @param dl DHT to use. * @param L pair selection strategy */ MPJReducerServer(int r, Terminator fin, MPJChannel c, DistHashTableMPJ> dl, PairList L) { rank = r; finaler = fin; //engine = e; theList = dl; pairlist = L; pairChannel = c; logger.debug("reducer server constructor: "); // + r); } /** * Main method. */ @SuppressWarnings("unchecked") public void run() { logger.debug("reducer server running: "); // + this); // try { // pairChannel = new MPJChannel(engine, rank); // } catch (IOException e) { // e.printStackTrace(); // return; // } if (logger.isInfoEnabled()) { logger.info("reducer server running: pairChannel = " + pairChannel); } Pair pair; GenPolynomial H = null; boolean set = false; boolean goon = true; int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request logger.debug("receive request"); Object req = null; try { req = pairChannel.receive(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } //logger.debug("received request, req = " + req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!set) { finaler.beIdle(); set = true; } if (!finaler.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (!pairlist.hasNext() && !finaler.hasJobs()) { goon = false; break; //continue; //break? } if (set) { set = false; finaler.notIdle(); } pair = pairlist.removeNext(); /* * send pair to client, receive H */ logger.debug("send pair = " + pair); GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); } else { msg = new GBTransportMess(); //End(); // goon ?= false; } try { pairChannel.send(msg); } catch (IOException e) { e.printStackTrace(); goon = false; break; } logger.debug("#distributed list = " + theList.size()); Object rh = null; try { rh = pairChannel.receive(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; break; } //logger.debug("received H polynomial"); if (rh == null) { if (pair != null) { pair.setZero(); } } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; H = ((GBTransportMessPoly) rh).pol; if (logger.isDebugEnabled()) { logger.debug("H = " + H); } if (H == null) { if (pair != null) { pair.setZero(); } } else { if (H.isZERO()) { pair.setZero(); } else { if (H.isONE()) { polIndex = pairlist.putOne(); //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); goon = false; break; } polIndex = pairlist.put(H); // use putWait ? but still not all distributed //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); } } } } logger.info("terminated, done " + red + " reductions"); /* * send end mark to client */ logger.debug("send end"); try { pairChannel.send(new GBTransportMessEnd()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } finaler.beIdle(); pairChannel.close(); } } /** * Distributed clients reducing worker threads. */ class MPJReducerClient> implements Runnable { private final MPJChannel pairChannel; private final DistHashTableMPJ> theList; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(MPJReducerClient.class); /** * Constructor. * @param pc MPJ communication channel. * @param dl DHT to use. */ MPJReducerClient(MPJChannel pc, DistHashTableMPJ> dl) { pairChannel = pc; theList = dl; red = new ReductionPar(); } /** * Main run method. */ @SuppressWarnings("unchecked") public void run() { logger.debug("reducer client running"); Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.debug("send request"); try { pairChannel.send(req); } catch (IOException e) { goon = false; e.printStackTrace(); break; } logger.debug("receive pair, goon"); Object pp = null; try { pp = pairChannel.receive(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("received pair = " + pp); } H = null; if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { pair = ((GBTransportMessPair) pp).pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = " + pair.i // + ", pjx = " + pair.j); } } if (pp instanceof GBTransportMessPairIndex) { pix = ((GBTransportMessPairIndex) pp).i; pjx = ((GBTransportMessPairIndex) pp).j; psx = ((GBTransportMessPairIndex) pp).s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //System.out.println("S = " + S); if (S.isZERO()) { // pair.setZero(); does not work in dist } else { if (logger.isDebugEnabled()) { logger.info("ht(S) = " + S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = " + H.leadingExpVector()); } } } } else { logger.info("pi = " + pi + ", pj = " + pj + ", ps = " + ps); } } // send H or must send null if (logger.isDebugEnabled()) { logger.debug("#distributed list = " + theList.size()); logger.debug("send H polynomial = " + H); } try { pairChannel.send(new GBTransportMessPoly(H)); } catch (IOException e) { goon = false; e.printStackTrace(); } } logger.info("terminated, done " + reduction + " reductions"); pairChannel.close(); } } /** * Distributed server reducing worker threads for minimal GB Not jet distributed * but threaded. */ class MiMPJReducerServer> implements Runnable { private final List> G; private GenPolynomial H; private final Semaphore done = new Semaphore(0); private final Reduction red; private static final Logger logger = LogManager.getLogger(MiMPJReducerServer.class); /** * Constructor. * @param G polynomial list. * @param p polynomial. */ @SuppressWarnings("unchecked") MiMPJReducerServer(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } /** * Main run method. */ public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = " + H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = " + H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/mpj/src/edu/jas/kern/000077500000000000000000000000001445075545500214045ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/kern/MPJEngine.java000066400000000000000000000214311445075545500240240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import mpi.Comm; import mpi.Intracomm; import mpi.MPI; import mpi.MPIException; import mpi.Status; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * MPI engine, provides global MPI service. Note: could eventually be * done directly with MPI, but provides logging. Usage: To obtain a * reference to the MPI service communicator use * MPJEngine.getComminicator(). Once an engine has been created it * must be shutdown to exit JAS with MPJEngine.terminate(). * @author Heinz Kredel */ public final class MPJEngine { private static final Logger logger = LogManager.getLogger(MPJEngine.class); private static final boolean debug = logger.isDebugEnabled(); /** * Command line arguments. Required for MPI runtime system. */ protected static String[] cmdline; /** * Hostnames of MPI partners. */ public static ArrayList hostNames = new ArrayList(); /** * Flag for MPI usage. Note: Only introduced because Google app * engine does not support MPI. */ public static boolean NO_MPI = false; /** * Number of processors. */ public static final int N_CPUS = Runtime.getRuntime().availableProcessors(); /* * Core number of threads. * N_CPUS x 1.5, x 2, x 2.5, min 3, ?. */ public static final int N_THREADS = (N_CPUS < 3 ? 3 : N_CPUS + N_CPUS / 2); /** * MPI communicator engine. */ static Intracomm mpiComm; /** * MPI engine base tag number. */ public static final int TAG = 11; /** * Hostname suffix. */ public static final String hostSuf = "-ib"; // /* // * Send locks per tag. // */ // private static SortedMap sendLocks = new TreeMap(); // /* // * receive locks per tag. // */ // private static SortedMap recvLocks = new TreeMap(); /** * No public constructor. */ private MPJEngine() { } /** * Set the commandline. * @param args the command line to use for the MPI runtime system. */ public static synchronized void setCommandLine(String[] args) { cmdline = args; } /** * Test if a pool is running. * @return true if a thread pool has been started or is running, else false. */ public static synchronized boolean isRunning() { if (mpiComm == null) { return false; } //if (MPI.Finalized()) { // FMPJ only // return false; //} return true; } /** * Get the MPI communicator. * @return a Communicator constructed for cmdline. */ public static synchronized Comm getCommunicator() throws IOException { if (cmdline == null) { throw new IllegalArgumentException("command line not set"); } return getCommunicator(cmdline); } /** * Get the MPI communicator. * @param args the command line to use for the MPI runtime system. * @return a Communicator. */ public static synchronized Comm getCommunicator(String[] args) throws IOException { if (NO_MPI) { return null; } if (mpiComm == null) { //String[] args = new String[] { }; //"-np " + N_THREADS }; if (!MPI.Initialized()) { if (args == null) { throw new IllegalArgumentException("command line is null"); } cmdline = args; args = MPI.Init(args); //int tl = MPI.Init_thread(args,MPI.THREAD_MULTIPLE); logger.info("MPI initialized on " + MPI.Get_processor_name()); //logger.info("thread level MPI.THREAD_MULTIPLE: " + MPI.THREAD_MULTIPLE // + ", provided: " + tl); if (debug) { logger.debug("remaining args: " + Arrays.toString(args)); } } mpiComm = MPI.COMM_WORLD; int size = mpiComm.Size(); int rank = mpiComm.Rank(); logger.info("MPI size = " + size + ", rank = " + rank); // maintain list of hostnames of partners hostNames.ensureCapacity(size); for (int i = 0; i < size; i++) { hostNames.add(""); } String myhost = MPI.Get_processor_name(); if (myhost.matches("\\An\\d*")) { // bwGRiD node names n010207 myhost += hostSuf; } if (myhost.matches("kredel.*")) { myhost = "localhost"; } hostNames.set(rank, myhost); if (rank == 0) { String[] va = new String[1]; va[0] = hostNames.get(0); mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); for (int i = 1; i < size; i++) { Status stat = mpiComm.Recv(va, 0, va.length, MPI.OBJECT, i, TAG); if (stat == null) { throw new IOException("no Status received"); //throw new MPIException("no Status received"); } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { throw new IOException("no Object received"); //throw new MPIException("no object received"); } String v = va[0]; hostNames.set(i, v); } logger.info("MPI partner host names = " + hostNames); } else { String[] va = new String[1]; mpiComm.Bcast(va, 0, va.length, MPI.OBJECT, 0); hostNames.set(0, va[0]); va[0] = hostNames.get(rank); mpiComm.Send(va, 0, va.length, MPI.OBJECT, 0, TAG); } } return mpiComm; } /** * Stop execution. */ public static synchronized void terminate() { if (mpiComm == null) { return; } //if (MPI.Finalized()) { // FMPJ only // return; //} try { logger.info("terminating MPI on rank = " + mpiComm.Rank()); mpiComm = null; MPI.Finalize(); } catch (MPIException e) { e.printStackTrace(); } } /** * Set no MPI usage. */ public static synchronized void setNoMPI() { NO_MPI = true; terminate(); } /** * Set MPI usage. */ public static synchronized void setMPI() { NO_MPI = false; } // /* // * Get send lock per tag. // * @param tag message tag. // * @return a lock for sends. // */ // public static synchronized Object getSendLock(int tag) { // tag = 11; // one global lock // Object lock = sendLocks.get(tag); // if ( lock == null ) { // lock = new Object(); // sendLocks.put(tag,lock); // } // return lock; // } // /* // * Get receive lock per tag. // * @param tag message tag. // * @return a lock for receives. // */ // public static synchronized Object getRecvLock(int tag) { // Object lock = recvLocks.get(tag); // if ( lock == null ) { // lock = new Object(); // recvLocks.put(tag,lock); // } // return lock; // } // /* // * Wait for termination of a mpj Request. // * @param req a Request. // * @return a Status after termination of req.Wait(). // */ // public static Status waitRequest(final Request req) { // if ( req == null ) { // throw new IllegalArgumentException("null request"); // } // int delay = 10; // int delcnt = 0; // Status stat = null; // while (true) { // synchronized (MPJEngine.class) { // global static lock // stat = req.Get_status(); // should be non destructive, but is not // if ( stat != null ) { // return req.Wait(); // should terminate immediately // } // } // try { // Thread.currentThread().sleep(delay); // varied a bit // } catch (InterruptedException e) { // logger.info("sleep interrupted"); // e.printStackTrace(); // } // delcnt++; // if ( delcnt % 7 == 0 ) { // delay++; // System.out.println("delay(" + delay + "): " + Thread.currentThread().toString()); // } // } // } } java-algebra-system-2.7.200/mpj/src/edu/jas/kern/MPJEngineTest.java000066400000000000000000000050751445075545500246720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.MPI; import mpi.Status; /** * MPJEngine tests with JUnit. * @author Heinz Kredel */ public class MPJEngineTest extends TestCase { /** * main */ public static void main(String[] args) { cmdline = args; junit.textui.TestRunner.run(suite()); MPJEngine.terminate(); } static String[] cmdline; static mpi.Comm engine; /** * Constructs a MPJEngineTest object. * @param name String. */ public MPJEngineTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(MPJEngineTest.class); return suite; } @Override protected void setUp() throws IOException { if (engine == null) { engine = MPJEngine.getCommunicator(cmdline); } } @Override protected void tearDown() { if (engine == null) { return; } engine = null; } /** * Test MPJEngine. */ public void testMPJEngine() { int me = engine.Rank(); int size = engine.Size(); assertTrue("size > 0", size > 0); assertTrue("0 <= me < size", 0 <= me && me < size); //System.out.println("testMPJEngine(): Hello World from " + me + " of " + size); } /** * Test communication. */ public void testCommunication() { int me = engine.Rank(); int size = engine.Size(); int tag = 13; int[] data = new int[5]; if (me == 0) { //System.out.println("testCommunication(): from " + me + " of " + size); for (int i = 1; i < size; i++) { data[0] = i; engine.Send(data, 0, data.length, MPI.INT, i, tag); } } else { Status stat = engine.Recv(data, 0, data.length, MPI.INT, 0, tag); int cnt = stat.Get_count(MPI.INT); int elem = stat.Get_elements(MPI.INT); //System.out.println("testCommunication(): status " + me + ", " + cnt + ", " + elem); //System.out.println("testCommunication(): received " + Arrays.toString(data)); assertTrue("length == count", data.length == cnt); assertTrue("recv == me", data[0] == me); assertTrue("elem >= 0: " + elem, elem >= 0); } //System.out.println("testCommunication(): done"); } } java-algebra-system-2.7.200/mpj/src/edu/jas/util/000077500000000000000000000000001445075545500214225ustar00rootroot00000000000000java-algebra-system-2.7.200/mpj/src/edu/jas/util/DistHashTableMPJ.java000066400000000000000000000361771445075545500253310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import mpi.Comm; import mpi.MPI; import mpi.MPIException; import mpi.Status; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPJEngine; /** * Distributed version of a HashTable using MPI. Implemented with a SortedMap / * TreeMap to keep the sequence order of elements. Implemented using MPI * transport or TCP transport. * @author Heinz Kredel */ public class DistHashTableMPJ extends AbstractMap { private static final Logger logger = LogManager.getLogger(DistHashTableMPJ.class); private static final boolean debug = logger.isDebugEnabled(); /* * Backing data structure. */ protected final SortedMap theList; /* * Thread for receiving pairs. */ protected DHTMPJListener listener; /* * MPI communicator. */ protected final Comm engine; /* * Size of Comm. */ private final int size; /* * This rank. */ private final int rank; /** * Message tag for DHT communicaton. */ public static final int DHTTAG = MPJEngine.TAG + 1; /* * TCP/IP object channels. */ private final SocketChannel[] soc; /** * Transport layer. true: use TCP/IP socket layer, false: use MPI transport * layer. */ static final boolean useTCP = false; /** * DistHashTableMPJ. */ public DistHashTableMPJ() throws IOException { this(MPJEngine.getCommunicator()); } /** * DistHashTableMPJ. * @param args command line for MPJ runtime system. */ public DistHashTableMPJ(String[] args) throws IOException { this(MPJEngine.getCommunicator(args)); } /** * DistHashTableMPJ. * @param cm MPJ communicator to use. */ public DistHashTableMPJ(Comm cm) throws IOException { engine = cm; rank = engine.Rank(); size = engine.Size(); if (useTCP) { // && soc == null int port = ChannelFactory.DEFAULT_PORT + 11; ChannelFactory cf; if (rank == 0) { cf = new ChannelFactory(port); cf.init(); soc = new SocketChannel[size]; soc[0] = null; try { for (int i = 1; i < size; i++) { SocketChannel sc = cf.getChannel(); // TODO not correct wrt rank soc[i] = sc; } } catch (InterruptedException e) { throw new IOException(e); } cf.terminate(); } else { cf = new ChannelFactory(port - 1); // in case of localhost soc = new SocketChannel[1]; SocketChannel sc = cf.getChannel(MPJEngine.hostNames.get(0), port); soc[0] = sc; cf.terminate(); } } else { soc = null; } theList = new TreeMap(); //theList = new ConcurrentSkipListMap(); // Java 1.6 listener = new DHTMPJListener(engine, soc, theList); logger.info("constructor: " + rank + "/" + size + ", useTCP: " + useTCP); } /** * Hash code. */ @Override public int hashCode() { return theList.hashCode(); } /** * Equals. */ @Override public boolean equals(Object o) { return theList.equals(o); } /** * Contains key. */ @Override public boolean containsKey(Object o) { return theList.containsKey(o); } /** * Contains value. */ @Override public boolean containsValue(Object o) { return theList.containsValue(o); } /** * Get the values as Collection. */ @Override public Collection values() { synchronized (theList) { return new ArrayList(theList.values()); } } /** * Get the keys as set. */ @Override public Set keySet() { synchronized (theList) { return theList.keySet(); } } /** * Get the entries as Set. */ @Override public Set> entrySet() { synchronized (theList) { return theList.entrySet(); } } /** * Get the internal list, convert from Collection. */ public List getValueList() { synchronized (theList) { return new ArrayList(theList.values()); } } /** * Get the internal sorted map. For synchronization purpose in normalform. */ public SortedMap getList() { return theList; } /** * Size of the (local) list. */ @Override public int size() { synchronized (theList) { return theList.size(); } } /** * Is the List empty? */ @Override public boolean isEmpty() { synchronized (theList) { return theList.isEmpty(); } } /** * List key iterator. */ public Iterator iterator() { synchronized (theList) { return theList.keySet().iterator(); } } /** * List value iterator. */ public Iterator valueIterator() { synchronized (theList) { return theList.values().iterator(); } } /** * Put object to the distributed hash table. Blocks until the key value pair * is send and received from the server. * @param key * @param value */ public void putWait(K key, V value) { put(key, value); // = send // assume key does not change multiple times before test: V val = null; do { val = getWait(key); //System.out.print("#"); } while (!value.equals(val)); } /** * Put object to the distributed hash table. Returns immediately after * sending does not block. * @param key * @param value */ @Override public V put(K key, V value) { if (key == null || value == null) { throw new NullPointerException("null keys or values not allowed"); } try { DHTTransport tc = DHTTransport. create(key, value); for (int i = 1; i < size; i++) { // send not to self.listener if (useTCP) { soc[i].send(tc); } else { DHTTransport[] tcl = new DHTTransport[] { tc }; synchronized (MPJEngine.class) { // not remove engine.Send(tcl, 0, tcl.length, MPI.OBJECT, i, DHTTAG); } } } synchronized (theList) { // add to self.listener theList.put(key, value); //avoid seri: tc.key(), tc.value()); theList.notifyAll(); } if (debug) { K k = tc.key(); if (!key.equals(k)) { logger.warn("deserial(serial)) != key: " + key + " != " + k); } V v = tc.value(); if (!value.equals(v)) { logger.warn("deserial(serial)) != value: " + value + " != " + v); } } //System.out.println("send: "+tc); } catch (ClassNotFoundException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } catch (MPIException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } catch (IOException e) { logger.info("sending(key=" + key + ")"); logger.warn("send " + e); e.printStackTrace(); } return null; } /** * Get value under key from DHT. Blocks until the object is send and * received from the server (actually it blocks until some value under key * is received). * @param key * @return the value stored under the key. */ public V getWait(K key) { V value = null; try { synchronized (theList) { value = theList.get(key); while (value == null) { //System.out.print("-"); theList.wait(100); value = theList.get(key); } } } catch (InterruptedException e) { //Thread.currentThread().interrupt(); e.printStackTrace(); return value; } return value; } /** * Get value under key from DHT. If no value is jet available null is * returned. * @param key * @return the value stored under the key. */ @Override public V get(Object key) { synchronized (theList) { return theList.get(key); } } /** * Clear the List. Caveat: must be called on all clients. */ @Override public void clear() { // send clear message to others synchronized (theList) { theList.clear(); } } /** * Initialize and start the list thread. */ public void init() { logger.info("init " + listener + ", theList = " + theList); if (listener == null) { return; } if (listener.isDone()) { return; } if (debug) { logger.debug("initialize " + listener); } synchronized (theList) { listener.start(); } } /** * Terminate the list thread. */ public void terminate() { if (listener == null) { return; } if (debug) { Runtime rt = Runtime.getRuntime(); logger.debug("terminate " + listener + ", runtime = " + rt.hashCode()); } listener.setDone(); DHTTransport tc = new DHTTransportTerminate(); try { if (rank == 0) { //logger.info("send(" + rank + ") terminate"); for (int i = 1; i < size; i++) { // send not to self.listener if (useTCP) { soc[i].send(tc); } else { DHTTransport[] tcl = new DHTTransport[] { tc }; synchronized (MPJEngine.class) { // not remove engine.Send(tcl, 0, tcl.length, MPI.OBJECT, i, DHTTAG); } } } } } catch (MPIException e) { logger.info("sending(terminate)"); logger.info("send " + e); e.printStackTrace(); } catch (IOException e) { logger.info("sending(terminate)"); logger.info("send " + e); e.printStackTrace(); } try { while (listener.isAlive()) { //System.out.print("+++++"); listener.join(999); listener.interrupt(); } } catch (InterruptedException e) { //Thread.currentThread().interrupt(); } listener = null; } } /** * Thread to comunicate with the other DHT lists. */ class DHTMPJListener extends Thread { private static final Logger logger = LogManager.getLogger(DHTMPJListener.class); private static final boolean debug = logger.isDebugEnabled(); private final Comm engine; private final SortedMap theList; private final SocketChannel[] soc; private boolean goon; /** * Constructor. */ DHTMPJListener(Comm cm, SocketChannel[] s, SortedMap list) { engine = cm; theList = list; goon = true; soc = s; } /** * Test if done. */ boolean isDone() { return !goon; } /** * Set to done status. */ void setDone() { goon = false; } /** * run. */ @SuppressWarnings("unchecked") @Override public void run() { logger.info("listener run() " + this); int rank = -1; DHTTransport tc; //goon = true; while (goon) { tc = null; try { if (rank < 0) { rank = engine.Rank(); } if (rank == 0) { logger.info("listener on rank 0 stopped"); goon = false; continue; } Object to = null; if (DistHashTableMPJ.useTCP) { to = soc[0].receive(); } else { DHTTransport[] tcl = new DHTTransport[1]; Status stat = null; synchronized (MPJEngine.class) { // not remove global static lock // only from 0 stat = engine.Recv(tcl, 0, tcl.length, MPI.OBJECT, 0, //MPI.ANY_SOURCE, DistHashTableMPJ.DHTTAG); } //logger.info("waitRequest done: stat = " + stat); if (stat == null) { goon = false; break; } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { goon = false; break; } else if (cnt > 1) { logger.warn("ignoring " + (cnt - 1) + " received objects"); } to = tcl[0]; } tc = (DHTTransport) to; if (debug) { logger.debug("receive(" + tc + ")"); } if (tc instanceof DHTTransportTerminate) { logger.info("receive(" + rank + ") terminate"); goon = false; break; } if (this.isInterrupted()) { goon = false; break; } K key = tc.key(); if (key != null) { logger.info("receive(" + rank + "), key=" + key); V val = tc.value(); synchronized (theList) { theList.put(key, val); theList.notifyAll(); } } } catch (MPIException e) { goon = false; logger.warn("receive(MPI) " + e); //e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; logger.info("receive(Class) " + e); e.printStackTrace(); } catch (Exception e) { goon = false; logger.info("receive " + e); e.printStackTrace(); } } logger.info("terminated at " + rank); } } java-algebra-system-2.7.200/mpj/src/edu/jas/util/DistHashTableMPJTest.java000066400000000000000000000117221445075545500261560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import mpi.Comm; import edu.jas.kern.MPJEngine; /** * DistHashTableMPJ test with JUnit. * @author Heinz Kredel */ public class DistHashTableMPJTest extends TestCase { protected static Comm engine; /** * main. */ public static void main(String[] args) throws IOException { //long t = System.currentTimeMillis(); engine = MPJEngine.getCommunicator(args); junit.textui.TestRunner.run(suite()); engine.Barrier(); MPJEngine.terminate(); //t = System.currentTimeMillis() - t; //System.out.println("MPJ runtime = " + t + " milli seconds"); } /** * Constructs a DistHashTableMPJTest object. * @param name String. */ public DistHashTableMPJTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(DistHashTableMPJTest.class); return suite; } private DistHashTableMPJ l1; private DistHashTableMPJ l2; private DistHashTableMPJ l3; @Override protected void setUp() { engine.Barrier(); } @Override protected void tearDown() { engine.Barrier(); if (l1 != null) l1.terminate(); if (l2 != null) l2.terminate(); if (l3 != null) l3.terminate(); l1 = l2 = l3 = null; try { //Thread.currentThread(); //System.out.println("tearDown: sleep = 1"); Thread.sleep(1); } catch (InterruptedException e) { } engine.Barrier(); } /** * Tests create and terminate DistHashTableMPJ. */ public void xtestDistHashTable1() throws IOException { l1 = new DistHashTableMPJ(engine); l1.init(); assertTrue("l1==empty", l1.isEmpty()); } /** * Tests if the created DistHashTable has #n objects as content. */ public void xtestDistHashTable2() throws IOException { int me = engine.Rank(); l1 = new DistHashTableMPJ(engine); l1.init(); assertTrue("l1==empty", l1.isEmpty()); Integer s = 0; if (me == 0) { l1.putWait(Integer.valueOf(1), Integer.valueOf(1)); } else { s = l1.getWait(Integer.valueOf(1)); } assertFalse("l1!=empty: ", l1.isEmpty()); assertTrue("#l1==1: " + l1.getList(), l1.size() >= 1); assertEquals("s == 1: ", s, Integer.valueOf(1)); if (me == 0) { l1.putWait(Integer.valueOf(2), Integer.valueOf(2)); } else { s = l1.getWait(Integer.valueOf(2)); } assertTrue("#l1==2: " + l1.getList(), l1.size() >= 2); assertEquals("s == 2: ", s, Integer.valueOf(2)); if (me == 0) { l1.putWait(Integer.valueOf(3), Integer.valueOf(3)); } else { s = l1.getWait(Integer.valueOf(3)); } assertTrue("#l1==3: " + l1.getList(), l1.size() >= 3); assertEquals("s == 3: ", s, Integer.valueOf(3)); Iterator it = null; it = l1.iterator(); int i = 0; while (it.hasNext()) { Object k = it.next(); Object o = l1.get(k); Integer x = Integer.valueOf(++i); assertEquals("l1(i)==v(i)", x, o); assertEquals("l1(i)==k(i)", x, k); } l1.clear(); assertTrue("#l1==0", l1.size() == 0); } /** * Tests if the two created DistHashTables have #n objects as content. */ public void testDistHashTable3() throws IOException { int me = engine.Rank(); l2 = new DistHashTableMPJ(engine); l2.init(); //System.out.println("test3: me = " + me + ", l2 = "+ l2); assertTrue("l2==empty", l2.isEmpty()); int i = 0, loops = 10; while (i < loops) { Integer x = Integer.valueOf(++i); //System.out.println("me = " + me + ", x = "+ x); if (me == 0) { l2.putWait(x, x); } else { Integer s = l2.getWait(x); assertEquals("s = x: " + s + ", " + x, s, x); } assertTrue("#l1==i: " + i + ", #l1 = " + l2.size(), l2.size() >= i); } assertTrue("#l2==" + loops, l2.size() == loops); Iterator it = l2.iterator(); i = 0; while (it.hasNext()) { Object k = it.next(); Object o = l2.get(k); Integer x = Integer.valueOf(++i); //System.out.println("me = " + me + ", o = " + o + ", x = "+ x); assertEquals("l2(i)==k(i)", x, k); assertEquals("l2(i)==v(i)", x, o); } } } java-algebra-system-2.7.200/mpj/src/edu/jas/util/MPJChannel.java000066400000000000000000000154241445075545500242120ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Arrays; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.MPJEngine; import mpi.Comm; import mpi.MPI; import mpi.MPIException; import mpi.Status; /** * MPJChannel provides a communication channel for Java objects using MPI or * TCP/IP to a given rank. Can use MPI transport layer for "niodev" with * FastMPJ. * @author Heinz Kredel */ public final class MPJChannel { private static final Logger logger = LogManager.getLogger(MPJChannel.class); public static final int CHANTAG = MPJEngine.TAG + 2; /* * Underlying MPI engine. */ private final Comm engine; // essentially static when useTCP ! /* * Size of Comm. */ private final int size; /* * This rank. */ private final int rank; /* * TCP/IP object channels with tags. */ private static TaggedSocketChannel[] soc = null; /* * Transport layer. * true: use TCP/IP socket layer, false: use MPI transport layer. * Can be set to false for "niodev" with FastMPJ. */ static boolean useTCP = false; /* * Partner rank. */ private final int partnerRank; /* * Message tag. */ private final int tag; /** * Constructs a MPI channel on the given MPI engine. * @param s MPI communicator object. * @param r rank of MPI partner. */ public MPJChannel(Comm s, int r) throws IOException, MPIException { this(s, r, CHANTAG); } /** * Constructs a MPI channel on the given MPI engine. * @param s MPI communicator object. * @param r rank of MPI partner. * @param t tag for messages. */ public MPJChannel(Comm s, int r, int t) throws IOException, MPIException { engine = s; rank = engine.Rank(); size = engine.Size(); if (r < 0 || size <= r) { throw new IOException("r out of bounds: 0 <= r < size: " + r + ", " + size); } partnerRank = r; tag = t; synchronized (engine) { if (soc == null && useTCP) { int port = ChannelFactory.DEFAULT_PORT; ChannelFactory cf; if (rank == 0) { cf = new ChannelFactory(port); cf.init(); soc = new TaggedSocketChannel[size]; soc[0] = null; try { for (int i = 1; i < size; i++) { SocketChannel sc = cf.getChannel(); // TODO not correct wrt rank soc[i] = new TaggedSocketChannel(sc); soc[i].init(); } } catch (InterruptedException e) { throw new IOException(e); } cf.terminate(); } else { cf = new ChannelFactory(port - 1); // in case of localhost soc = new TaggedSocketChannel[1]; SocketChannel sc = cf.getChannel(MPJEngine.hostNames.get(0), port); soc[0] = new TaggedSocketChannel(sc); soc[0].init(); cf.terminate(); } } } logger.info("constructor: " + this.toString() + ", useTCP: " + useTCP); } /** * Get the MPI engine. */ public Comm getEngine() { return engine; } /** * Sends an object. * @param v message object. */ public void send(Object v) throws IOException, MPIException { send(tag, v, partnerRank); } /** * Sends an object. * @param t message tag. * @param v message object. */ public void send(int t, Object v) throws IOException, MPIException { send(t, v, partnerRank); } /** * Sends an object. * @param t message tag. * @param v message object. * @param pr partner rank. */ void send(int t, Object v, int pr) throws IOException, MPIException { if (useTCP) { if (soc == null) { logger.warn("soc not initialized: lost " + v); return; } if (soc[pr] == null) { logger.warn("soc[" + pr + "] not initialized: lost " + v); return; } soc[pr].send(t, v); } else { Object[] va = new Object[] { v }; //synchronized (MPJEngine.class) { engine.Send(va, 0, va.length, MPI.OBJECT, pr, t); //} } } /** * Receives an object. * @return a message object. */ public Object receive() throws IOException, ClassNotFoundException, MPIException { return receive(tag); } /** * Receives an object. * @param t message tag. * @return a message object. */ public Object receive(int t) throws IOException, ClassNotFoundException, MPIException { if (useTCP) { if (soc == null) { logger.warn("soc not initialized"); return null; } if (soc[partnerRank] == null) { logger.warn("soc[" + partnerRank + "] not initialized"); return null; } try { return soc[partnerRank].receive(t); } catch (InterruptedException e) { throw new IOException(e); } } Object[] va = new Object[1]; Status stat = null; //synchronized (MPJEngine.class) { stat = engine.Recv(va, 0, va.length, MPI.OBJECT, partnerRank, t); //} if (stat == null) { throw new IOException("received null Status"); } int cnt = stat.Get_count(MPI.OBJECT); if (cnt == 0) { throw new IOException("no object received"); } if (cnt > 1) { logger.warn("too many objects received, ignored " + (cnt - 1)); } // int pr = stat.source; // if (pr != partnerRank) { // logger.warn("received out of order message from " + pr); // } return va[0]; } /** * Closes the channel. */ public void close() { if (useTCP) { if (soc == null) { return; } for (int i = 0; i < soc.length; i++) { if (soc[i] != null) { soc[i].close(); soc[i] = null; } } } } /** * to string. */ @Override public String toString() { return "MPJChannel(on=" + rank + ",to=" + partnerRank + ",tag=" + tag + "," + Arrays.toString(soc) + ")"; } } java-algebra-system-2.7.200/navigate.html000066400000000000000000000062641445075545500202320ustar00rootroot00000000000000 Navigation

J A S


Home


Users guide
API guide
Documentation
FAQ
Weblog
Credits
Contributing
Related Projects


Download
COPYING
GitHub
Contact


Google this site:

no frames


Google code
freshmeat
Ohloh

java-algebra-system-2.7.200/pom.xml000066400000000000000000000127511445075545500170610ustar00rootroot00000000000000 4.0.0 Java Algebra System (JAS) de.uni-mannheim.rz.krum jas @SVNREV@ jar The Java Algebra System (JAS) is an object oriented, type safe and multi-threaded approach to computer algebra. JAS provides a well designed software library using generic types for algebraic computations implemented in the Java programming language using the JVM runtime infrastructure. The library can be used as any other Java software package or it can be used interactively or interpreted through a jython (Java Python) or jruby (Java Ruby) front end, there is also an Android App based on Ruboto (jruby for Android). The focus of JAS is at the moment on commutative, solvable and non-commutative polynomials, power series, Groebner bases, factorization, real and complex roots and applications. By the use of Java as implementation language JAS is 64-bit and multi-core CPU ready and can make use of mutiple CPUs where available. JAS can run on a wide variety of devices ranging from Android to compute clusters (using MPJ a Java Message Passing Interface (MPI) or OpenMPI). http://krum.rz.uni-mannheim.de/jas GNU GENERAL PUBLIC LICENSE Version 2, June 1991 http://www.gnu.org/licenses/old-licenses/gpl-2.0 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 http://www.gnu.org/licenses/old-licenses/lgpl-2.1 Heinz Kredel kredel@rz.uni-mannheim.de University Mannheim http://www.uni-mannheim.de/rum/ Axel Kramer Raphael Jolly Jan Suess Youssef Elbarbary Maximilian Nohr Hannes Wellmann Akitoshi Yoshida scm:git:https://github.com/kredel/java-algebra-system.git scm:git:ssh://github.com/kredel/java-algebra-system.git https://github.com/kredel/java-algebra-system/tree/master org.apache.logging.log4j log4j-core [2.17.1,) test org.apache.logging.log4j log4j-api [2.17.1,) compile junit junit 4.13.1 test src trc org.apache.maven.plugins maven-compiler-plugin 3.3 1.11 1.11 org.apache.maven.plugins maven-source-plugin 3.0.1 attach-sources jar org.apache.maven.plugins maven-javadoc-plugin 3.0.1 attach-javadocs jar org.apache.maven.plugins maven-project-info-reports-plugin 2.7 org.apache.maven.plugins maven-javadoc-plugin 3.0.1 maven-central https://oss.sonatype.org/content/groups/public jas-repository http://krum.rz.uni-mannheim.de/maven-repository java-algebra-system-2.7.200/sample.jythonrc000066400000000000000000000004521445075545500206020ustar00rootroot00000000000000#!/bin/bash # # this is a sample rc file for certain versions of jython # modifiy it and place it as .jythonrc in your home directory # export CLASSPATH="$HOME/java/lib/junit.jar:$HOME/java/lib/log4j.jar:." export BASE_OPTIONS="-Xms300M -Xmx600M -XX:+AggressiveHeap -XX:+UseParallelGC -verbose:gc" java-algebra-system-2.7.200/settings.gradle000066400000000000000000000011731445075545500205600ustar00rootroot00000000000000/* * This settings file was auto generated by the Gradle buildInit task * by 'kredel' at '19.06.14 23:00' with Gradle 1.12 * * The settings file is used to specify which projects to include in your build. * In a single project build this file can be empty or even removed. * * Detailed information about configuring a multi-project build in Gradle can be found * in the user guide at http://gradle.org/docs/1.12/userguide/multi_project_builds.html */ /* // To declare projects as part of a multi-project build use the 'include' method include 'shared' include 'api' include 'services:webservice' */ rootProject.name = 'jas' java-algebra-system-2.7.200/spin/000077500000000000000000000000001445075545500165075ustar00rootroot00000000000000java-algebra-system-2.7.200/spin/README000066400000000000000000000001411445075545500173630ustar00rootroot00000000000000See: https://en.wikipedia.org/wiki/SPIN_model_checker https://spinroot.com/spin/whatispin.html java-algebra-system-2.7.200/spin/dgb.spin000066400000000000000000000025261445075545500201430ustar00rootroot00000000000000/* * Distributed GB communications check * $Id$ */ mtype = { Get, Fin, Pair, Hpol }; byte idler = 0; #define PROCNUM 3 #define noJobs (idler == PROCNUM) byte pairsRemaining = 10; #define nextPair (pairsRemaining != 0) byte maxPairs = 50; #define erledigt (! nextPair && noJobs ) inline addPair() { atomic { if :: ( maxPairs == 0 ) -> skip; :: ( maxPairs > 0 ) -> pairsRemaining++; maxPairs--; fi } } inline getPair() { atomic { if :: (pairsRemaining == 0) -> skip; :: (pairsRemaining > 0) -> pairsRemaining--; fi } } chan pairchan[PROCNUM] = [2] of { mtype }; proctype Server (chan pairs) { do :: idler++; pairs ? Get; if :: ( erledigt ) -> pairs ! Fin; break; //goto fertig; :: ( ! nextPair ) -> skip //delay; :: else skip; fi; idler--; getPair(); pairs ! Pair; /* compute H-Pol in client */ progress: skip; pairs ? Hpol; addPair(); od; fertig: assert( ! nextPair ); } proctype Client (chan pairs) { do :: pairs ! Get; if :: pairs ? Fin -> break; :: pairs ? Pair -> pairs ! Hpol; fi od } active proctype Monitor() { atomic { noJobs -> ! nextPair; } } init { idler = 0; run Server(pairchan[0]); run Server(pairchan[1]); run Client(pairchan[0]); run Client(pairchan[1]); run Client(pairchan[2]); run Server(pairchan[2]); } java-algebra-system-2.7.200/spin/pgb.spin000066400000000000000000000016441445075545500201570ustar00rootroot00000000000000/* * parallel GB check * $Id$ */ byte idler = 0; #define PROCNUM 3 #define noJobs (idler == PROCNUM) byte pairsRemaining = 10; #define nextPair (pairsRemaining != 0) byte maxPairs = 30; #define erledigt ( (! nextPair) && noJobs ) inline addPair() { atomic { if :: ( maxPairs == 0 ) -> skip; :: ( maxPairs > 0 ) -> pairsRemaining++; maxPairs--; fi } } inline getPair() { atomic { if :: (pairsRemaining == 0) -> skip; :: (pairsRemaining > 0) -> pairsRemaining--; fi } } proctype Server () { do :: idler++; if :: ( erledigt ) -> break; //goto fertig; :: ( ! nextPair ) -> skip //delay; :: else skip; fi; idler--; getPair(); /* compute H-Pol */ progress: skip; addPair(); od; fertig: assert( ! nextPair ); } active proctype Monitor() { atomic { noJobs -> ! nextPair; } } init { idler = 0; run Server(); run Server(); run Server(); } java-algebra-system-2.7.200/src/000077500000000000000000000000001445075545500163255ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/000077500000000000000000000000001445075545500171025ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/000077500000000000000000000000001445075545500176575ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/application/000077500000000000000000000000001445075545500221625ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/application/AlgebraicRootsPrimElem.java000066400000000000000000000115501445075545500273620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.List; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.GenPolynomial; import edu.jas.poly.Complex; import edu.jas.root.AlgebraicRoots; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.ComplexAlgebraicNumber; import edu.jas.structure.GcdRingElem; /** * Container for the real and complex algebraic roots of a univariate * polynomial together with primitive element. * @param coefficient type. * @author Heinz Kredel */ public class AlgebraicRootsPrimElem & Rational> extends AlgebraicRoots implements Serializable { /** * Primitive Element algebraic roots. */ public final PrimitiveElement pelem; /** * Roots of unity of primitive element origin representations. */ public final List> runit; /** * Constructor not for use. */ protected AlgebraicRootsPrimElem() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param p univariate polynomial * @param cp univariate polynomial with compelx coefficients * @param r list of real algebraic roots * @param c list of complex algebraic roots * @param pe primitive element * @param ru roots of unity of primitive element origin representations */ public AlgebraicRootsPrimElem(GenPolynomial p, GenPolynomial> cp, List> r, List> c, PrimitiveElement pe, List> ru) { super(p, cp, r, c); this.pelem = pe; this.runit = ru; } /** * Constructor. * @param ar algebraic roots container * @param pe primitive element */ public AlgebraicRootsPrimElem(AlgebraicRoots ar, PrimitiveElement pe) { this(ar.p, ar.cp, ar.real, ar.complex, pe, null); } /** * Constructor. * @param ar algebraic roots container * @param pe primitive element * @param ru roots of unity of primitive element origin representations */ public AlgebraicRootsPrimElem(AlgebraicRoots ar, PrimitiveElement pe, List> ru) { this(ar.p, ar.cp, ar.real, ar.complex, pe, ru); } /** * String representation of AlgebraicRootsPrimElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (runit == null) { return super.toString(); } return super.toString() + ", " + runit.toString(); //return "[" + p + ", real=" + real + ", complex=" + complex + ", " + pelem + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Interval. */ public String toScript() { // any case StringBuffer sb = new StringBuffer(super.toScript()); if (runit == null) { return sb.toString(); } sb.append(" ["); boolean first = true; for (AlgebraicNumber a : runit) { if (first) { first = false; } else { sb.append(", "); } sb.append(a.toScript()); } sb.append("] "); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Interval. */ public String toDecimalScript() { // any case return super.toDecimalScript(); } /** * Copy this. * @return a copy of this. */ public AlgebraicRootsPrimElem copy() { return new AlgebraicRootsPrimElem(p, cp, real, complex, pelem, runit); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof AlgebraicRootsPrimElem)) { return false; } AlgebraicRootsPrimElem a = null; try { a = (AlgebraicRootsPrimElem) b; } catch (ClassCastException e) { return false; } // not really required, since depends on A, B return super.equals(a) && pelem.equals(a.pelem) && runit.equals(a.runit); } /** * Hash code for this AlgebraicRootsPrimElem. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // not really required, since depends on A, B return (161 * super.hashCode() + 37) * pelem.hashCode() + runit.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/application/CPair.java000066400000000000000000000072211445075545500240250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import edu.jas.structure.RingElem; /** * Serializable subclass to hold pairs of colored polynomials. * @param coefficient type * @author Heinz Kredel */ public class CPair> implements Serializable, Comparable> { public final ColorPolynomial pi; public final ColorPolynomial pj; public final int i; public final int j; protected int n; protected boolean toZero = false; protected boolean useCriterion4 = true; protected boolean useCriterion3 = true; /** * Pair constructor. * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. */ public CPair(ColorPolynomial a, ColorPolynomial b, int i, int j) { pi = a; pj = b; this.i = i; this.j = j; this.n = 0; toZero = false; // ok } /** * toString. */ @Override public String toString() { return "pair[" + n + "](" + i + "{" + pi.length() + "}," + j + "{" + pj.length() + "}" + ", r0=" + toZero + ", c4=" + useCriterion4 + ", c3=" + useCriterion3 + ")"; } /** * Set removed pair number. * @param n number of this pair generated in OrderedPairlist. */ public void pairNumber(int n) { this.n = n; } /** * Get removed pair number. * @return n number of this pair generated in OrderedPairlist. */ public int getPairNumber() { return n; } /** * Set zero reduction. The S-polynomial of this Pair was reduced to zero. */ public void setZero() { toZero = true; } /** * Is reduced to zero. * @return true if the S-polynomial of this Pair was reduced to zero, else * false. */ public boolean isZero() { return toZero; } /** * equals. * @param ob an Object. * @return true if this is equal to ob, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object ob) { CPair cp = null; try { cp = (CPair) ob; } catch ( ClassCastException e) { return false; } if ( cp == null ) { return false; } return 0 == compareTo(cp); } /** * compareTo used in TreeMap. * Comparison is based on the number of the pairs. * @param p a Pair. * @return 1 if (this < p), 0 if (this == o), -1 if (this > p). */ public int compareTo(CPair p) { // not used at moment int x = p.getPairNumber(); if (n > x) { return 1; } if (n < x) { return -1; } return 0; } /** * Hash code for this pair. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = getPairNumber(); return h; } /** * Set useCriterion4. * @param c boolean value to set. */ public void setUseCriterion4(boolean c) { this.useCriterion4 = c; } /** * Get useCriterion4. * @return boolean value. */ public boolean getUseCriterion4() { return this.useCriterion4; } /** * Set useCriterion3. * @param c boolean value to set. */ public void setUseCriterion3(boolean c) { this.useCriterion3 = c; } /** * Get useCriterion3. * @return boolean value. */ public boolean getUseCriterion3() { return this.useCriterion3; } } java-algebra-system-2.7.200/src/edu/jas/application/CReductionSeq.java000066400000000000000000000423441445075545500255440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; /** * Polynomial parametric ring reduction sequential use algorithm. Implements * normalform, condition construction and polynomial determination. * @param coefficient type * @author Heinz Kredel */ public class CReductionSeq> implements Serializable /* extends ReductionAbstract */ /* implements CReduction */{ private static final Logger logger = LogManager.getLogger(CReductionSeq.class); //private static final boolean debug = logger.isDebugEnabled(); private final boolean info = logger.isInfoEnabled(); /** * Greatest common divisor engine. */ protected final GreatestCommonDivisor engine; /** * Polynomial coefficient ring factory. */ protected final RingFactory cofac; /** * Flag if top-reduction only should be used. */ protected boolean top = true; // false; /** * Constructor. * @param rf coefficient factory. */ public CReductionSeq(RingFactory rf) { cofac = rf; // System.out.println("cofac = " + cofac); engine = GCDFactory. getImplementation(cofac); } /** * S-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return spol(Ap,Bp) the S-polynomial of Ap and Bp. */ public ColorPolynomial SPolynomial(ColorPolynomial Ap, ColorPolynomial Bp) { if (Bp == null || Bp.isZERO()) { return Bp; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry> ma = Ap.red.leadingMonomial(); Map.Entry> mb = Bp.red.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); // EVLCM(e,f); ExpVector e1 = g.subtract(e); // EVDIF(g,e); ExpVector f1 = g.subtract(f); // EVDIF(g,f); GenPolynomial a = ma.getValue(); GenPolynomial b = mb.getValue(); GenPolynomial c = engine.gcd(a, b); if (!c.isONE()) { // System.out.println("gcd =s " + c); a = a.divide(c); b = b.divide(c); } ColorPolynomial App = Ap.multiply(b, e1); // multiplyLeft in poly ColorPolynomial Bpp = Bp.multiply(a, f1); // multiplyLeft in poly ColorPolynomial Cp = App.subtract(Bpp); assert (! g.equals(Cp.getEssentialPolynomial().leadingExpVector())) : "g == lt(Cp)"; return Cp; } /** * Is top reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, ColorPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); for (ColorPolynomial p : P) { if (p == null) { return false; } ExpVector f = p.leadingExpVector(); if (f == null) { return false; } if (e == null) { return false; } mt = e.multipleOf(f); // EVMT( e, p.leadingExpVector() ); if (mt) { return true; } } return false; } /** * Is reducible. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is reducible with respect to Pp. */ public boolean isReducible(List> Pp, ColorPolynomial Ap) { return !isNormalform(Pp, Ap); } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") public boolean isNormalform(List> Pp, ColorPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; ColorPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new ColorPolynomial[l]; // P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; ColorPolynomial[] p = new ColorPolynomial[l]; Map.Entry> m; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].red.leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); j++; } } l = j; boolean mt = false; for (ExpVector e : Ap.red.getMap().keySet()) { for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); // EVMT( e, htl[i] ); if (mt) { System.out.println("not normalform " + Ap + ", P[i] = " + P[i]); return false; } } if (top) { return true; } } for (ExpVector e : Ap.white.getMap().keySet()) { for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); // EVMT( e, htl[i] ); if (mt) { System.out.println("not normalform " + Ap + ", P[i] = " + P[i]); return false; } } if (top) { return true; } } return true; } /** * Is in Normalform. * @param Pp polynomial list. * @return true if each Ap in Pp is in normalform with respect to Pp\{Ap}. */ public boolean isNormalform(List> Pp) { if (Pp == null || Pp.isEmpty()) { return true; } ColorPolynomial Ap; List> P = new LinkedList>(Pp); int s = P.size(); for (int i = 0; i < s; i++) { Ap = P.remove(i); if (!isNormalform(P, Ap)) { return false; } P.add(Ap); } return true; } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @param cond condition for these polynomials. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public ColorPolynomial normalform(Condition cond, List> Pp, ColorPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry> m; int l; ColorPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new ColorPolynomial[l]; // P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; Object[] lbc = new Object[l]; // want C[] ColorPolynomial[] p = new ColorPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].red.leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; GenPolynomial a; boolean mt = false; GenPolynomial> zero = p[0].red.ring.getZERO(); ColorPolynomial R = new ColorPolynomial(zero, zero, zero); // ColorPolynomial T = null; ColorPolynomial Q = null; ColorPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); Condition.Color col = cond.color(a); if (col == Condition.Color.GREEN) { // move to green terms GenPolynomial> g = S.green.sum(a, e); GenPolynomial> r = S.red; GenPolynomial> w = S.white; if (S.red.isZERO()) { w = w.subtract(a, e); } else { // only in minimalGB logger.info("green_red = {}", zero.sum(a, e)); r = r.subtract(a, e); } S = new ColorPolynomial(g, r, w); continue; } //if (col == Condition.Color.WHITE) { // refine condition // System.out.println("white = " + zero.sum(a,e)); // return S; // return for new case distinction //} // System.out.println("NF, e = " + e); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); // EVMT( e, htl[i] ); if (mt) break; } if (!mt) { // logger.debug("irred"); if (top) { return S; } R = R.sum(a, e); S = S.subtract(a, e); // System.out.println(" S = " + S); } else { f = e; e = e.subtract(htl[i]); // EVDIF( e, htl[i] ); // logger.info("red div = {}", e); GenPolynomial c = (GenPolynomial) lbc[i]; GenPolynomial g = engine.gcd(a, c); if (!g.isONE()) { // System.out.println("gcd = " + g); a = a.divide(g); c = c.divide(g); } S = S.multiply(c); R = R.multiply(c); Q = p[i].multiply(a, e); // multiplyLeft in poly S = S.subtract(Q); assert (! f.equals(S.getEssentialPolynomial().leadingExpVector()) ) : "f == lt(S)"; } } return R; } /* * -------- coloring and condition stuff ------------------------------ */ /** * Case distinction conditions of parametric polynomial list. The returned * condition determines the polynomial list. * @param L list of parametric polynomials. * @return list of conditions as case distinction. */ public List> caseDistinction(List>> L) { List> cd = new ArrayList>(); if (L == null || L.size() == 0) { return cd; } for (GenPolynomial> A : L) { if (A != null && !A.isZERO()) { cd = caseDistinction(cd, A); } } // System.out.println("cd = " + cd); return cd; } /** * Case distinction conditions of parametric polynomial list. * @param cd a list of conditions. * @param A a parametric polynomial. * @return list of conditions as case distinction extending the conditions * in cd. */ public List> caseDistinction(List> cd, GenPolynomial> A) { if (A == null || A.isZERO()) { return cd; } if (cd == null) { cd = new ArrayList>(); } if (cd.size() == 0) { // construct empty condition RingFactory> crfac = A.ring.coFac; GenPolynomialRing cfac = (GenPolynomialRing) crfac; Condition sc = new Condition(cfac); cd.add(sc); } GenPolynomial> Ap; GenPolynomial> Bp; List> C = new ArrayList>( /* leer! */); for (Condition cond : cd) { // System.out.println("caseDist: " + cond); Condition cz = cond; Ap = A; while (!Ap.isZERO()) { GenPolynomial c = Ap.leadingBaseCoefficient(); Bp = Ap.reductum(); //System.out.println("to color: " + c); switch (cz.color(c)) { case GREEN: // System.out.println("color green: " + c); Ap = Bp; continue; case RED: // System.out.println("color red: " + c); C.add(cz); // wrong: return C; Ap = A.ring.getZERO(); continue; // break; case WHITE: default: // System.out.println("color white: " + c); Condition nc = cz.extendNonZero(c); if (nc != null) { // no contradiction if (!cz.equals(nc)) { C.add(nc); } else { cz = null; Ap = A.ring.getZERO(); continue; } } else { // contradiction rechecked in determine(c) //System.out.println("this should not be printed, c = " + c); //System.out.println("this should not be printed, cz = " + cz); } Condition ez = cz.extendZero(c); if (ez != null) { cz = ez; } else { // contradiction cz = null; Ap = A.ring.getZERO(); continue; } Ap = Bp; } } // System.out.println("cond cz: " + cz); if (cz == null || cz.isContradictory() || C.contains(cz)) { // System.out.println("not added entry " + cz); } else { C.add(cz); } } // System.out.println("C = " + C); return C; } /** * Case distinction conditions of parametric polynomial list. * @param A a parametric polynomial. * @param cond a condition. * @return list of case distinction conditions. */ public List> caseDistinction(Condition cond, GenPolynomial> A) { List> cd = new ArrayList>(); if (A == null || A.isZERO()) { return cd; } cd.add(cond); cd = caseDistinction(cd, A); if (info) { StringBuffer s = new StringBuffer("extending condition: " + cond + "\n"); s.append("case distinctions: [ \n"); for (Condition c : cd) { s.append(c.toString() + "\n"); } s.append("]"); logger.info("{}", s); } return cd; } /** * Determine polynomial list. * @param H polynomial list. * @return new determined list of colored systems. */ public List> determine(List>> H) { if (H == null || H.size() == 0) { List> CS = new ArrayList>(); return CS; } //System.out.println("of determine = " + H); Collections.reverse(H); List> cd = caseDistinction(H); //System.out.println("case Distinction = " + cd); //System.out.println("of determine = " + H); return determine(cd, H); } /** * Determine polynomial list. * @param H polynomial list. * @param cd case distinction, a condition list. * @return new determined list of colored systems. */ public List> determine(List> cd, List>> H) { List> CS = new ArrayList>(); if (H == null || H.size() == 0) { return CS; } for (Condition cond : cd) { logger.info("determine wrt cond = {}", cond); if (cond.zero.isONE()) { // should not happen System.out.println("ideal is one = " + cond.zero); // continue; // can treat all coeffs as green } // if ( cond.isEmpty() ) { // do not use this code // continue; // can skip condition (?) // } List> S = cond.determine(H); ColoredSystem cs = new ColoredSystem(cond, S); CS.add(cs); } return CS; } } java-algebra-system-2.7.200/src/edu/jas/application/ColorPolynomial.java000066400000000000000000000314541445075545500261560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Colored Polynomials with green, red and white coefficients. Not implementing * RingElem. Note: not general purpose, use only in comprehensive GB. * @param coefficient type * @author Heinz Kredel */ public class ColorPolynomial> implements Serializable /* implements RingElem< ColorPolynomial > */ { private static final Logger logger = LogManager.getLogger(ColorPolynomial.class); /** * The part with green (= zero) terms and coefficients. */ public final GenPolynomial> green; /** * The part with red (= non zero) terms and coefficients. */ public final GenPolynomial> red; /** * The part with white (= unknown color) terms and coefficients. */ public final GenPolynomial> white; /** * The constructor creates a colored polynomial from the colored parts. * @param g green colored terms and coefficients. * @param r red colored terms and coefficients. * @param w white colored terms and coefficients. */ public ColorPolynomial(GenPolynomial> g, GenPolynomial> r, GenPolynomial> w) { if (g == null || r == null || w == null) { throw new IllegalArgumentException("g,r,w may not be null"); } green = g; red = r; white = w; } /** * String representation of ColorPolynomial. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(":green: "); s.append(green.toString()); s.append(" :red: "); s.append(red.toString()); s.append(" :white: "); s.append(white.toString()); return s.toString(); } /** * Script representation of ColorPolynomial. * @see edu.jas.structure.Element#toScript() */ public String toScript() { StringBuffer s = new StringBuffer(); s.append(":green: "); s.append(green.toScript()); s.append(" :red: "); s.append(red.toScript()); s.append(" :white: "); s.append(white.toScript()); return s.toString(); } /** * Is this polynomial ZERO. * @return true, if there are only green terms, else false. */ public boolean isZERO() { return (red.isZERO() && white.isZERO()); } /** * Is this polynomial ONE. * @return true, if the only non green term is 1, else false. */ public boolean isONE() { return ((red.isZERO() && white.isONE()) || (red.isONE() && white.isZERO())); } /** * Is this polynomial equal to other. * @param p other polynomial. * @return true, if this is equal to other, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object p) { ColorPolynomial cp = null; try { cp = (ColorPolynomial) p; } catch (ClassCastException e) { return false; } if (cp == null) { return false; } return (green.equals(cp.green) && red.equals(cp.red) && white.equals(cp.white)); } /** * Hash code for this colored polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = green.hashCode(); h = h << 11; h += red.hashCode(); h = h << 11; h += white.hashCode(); return h; } /** * Is this polynomial determined. * @return true, if there are nonzero red terms or if this == 0, else false. */ public boolean isDetermined() { return (!red.isZERO() || white.isZERO()); } /** * Check ordering invariants. TT(green) > LT(red) and TT(red) > * LT(white). * @return true, if all ordering invariants are met, else false. */ public boolean checkInvariant() { boolean t = true; ExpVector ttg, ltr, ttr, ltw; Comparator cmp; if (green.isZERO() && red.isZERO() && white.isZERO()) { return true; } if (green.isZERO() && red.isZERO()) { return true; } if (red.isZERO() && white.isZERO()) { return true; } if (!green.isZERO() && !red.isZERO()) { ttg = green.trailingExpVector(); ltr = red.leadingExpVector(); cmp = green.ring.tord.getDescendComparator(); t = t && (cmp.compare(ttg, ltr) < 0); } if (!red.isZERO() && !white.isZERO()) { ttr = red.trailingExpVector(); ltw = white.leadingExpVector(); cmp = white.ring.tord.getDescendComparator(); t = t && (cmp.compare(ttr, ltw) < 0); } if (red.isZERO() && !green.isZERO() && !white.isZERO()) { ttg = green.trailingExpVector(); ltw = white.leadingExpVector(); cmp = white.ring.tord.getDescendComparator(); t = t && (cmp.compare(ttg, ltw) < 0); } if (!t) { System.out.println("not invariant " + this); // throw new RuntimeException("test"); } return t; } /** * Get zero condition on coefficients. * @return green coefficients. */ public List> getGreenCoefficients() { Collection> c = green.getMap().values(); return new ArrayList>(c); } /** * Get non zero condition on coefficients. * @return red coefficients. */ public List> getRedCoefficients() { Collection> c = red.getMap().values(); return new ArrayList>(c); } /** * Get full polynomial. * @return sum of all parts. */ public GenPolynomial> getPolynomial() { GenPolynomial> f = green.sum(red).sum(white); int s = green.length() + red.length() + white.length(); int t = f.length(); if (t != s) { throw new RuntimeException("illegal coloring state " + s + " != " + t); } return f; } /** * Get essential polynomial. * @return sum of red and white parts. */ public GenPolynomial> getEssentialPolynomial() { GenPolynomial> f = red.sum(white); int s = red.length() + white.length(); int t = f.length(); if (t != s) { logger.warn("incomplete coloring state {} != {}", s, t); logger.info("f = {}, red = {}, white = {}", f, red, white); //throw new RuntimeException("illegal coloring state " + s + " != " + t); } return f; } /** * Length of red and white parts. * @return length of essential parts. */ public int length() { int s = red.length() + white.length(); return s; } /** * Get leading exponent vector. * @return LT of red or white parts. */ public ExpVector leadingExpVector() { if (!red.isZERO()) { return red.leadingExpVector(); } return white.leadingExpVector(); } /** * Get leading monomial. * @return LM of red or white parts. */ public Map.Entry> leadingMonomial() { if (!red.isZERO()) { return red.leadingMonomial(); } return white.leadingMonomial(); } /** * ColorPolynomial absolute value. * @return abs(this). */ public ColorPolynomial abs() { GenPolynomial> g, r, w; int s = green.signum(); if (s > 0) { return this; } if (s < 0) { g = green.negate(); r = red.negate(); w = white.negate(); return new ColorPolynomial(g, r, w); } // green == 0 g = green; s = red.signum(); if (s > 0) { return this; } if (s < 0) { r = red.negate(); w = white.negate(); return new ColorPolynomial(g, r, w); } // red == 0 r = red; s = white.signum(); if (s > 0) { return this; } if (s < 0) { w = white.negate(); return new ColorPolynomial(g, r, w); } // white == 0 w = white; return new ColorPolynomial(g, r, w); } /** * ColorPolynomial summation. Note: green coefficients stay green, * all others become white. * @param S ColorPolynomial. * @return this+S. */ public ColorPolynomial sum(ColorPolynomial S) { GenPolynomial> g, r, w; g = green.sum(S.green); r = red.ring.getZERO(); w = getEssentialPolynomial().sum(S.getEssentialPolynomial()); return new ColorPolynomial(g, r, w); } /** * ColorPolynomial summation. * @param s GenPolynomial. * @param e exponent vector. * @return this+(c e). */ public ColorPolynomial sum(GenPolynomial s, ExpVector e) { GenPolynomial> g, r, w; g = green; r = red; w = white; if (green.getMap().keySet().contains(e)) { g = green.sum(s, e); } else if (red.getMap().keySet().contains(e)) { r = red.sum(s, e); } else { w = white.sum(s, e); } return new ColorPolynomial(g, r, w); } /** * ColorPolynomial subtraction. Note: green coefficients stay green, * all others become white. * @param S ColorPolynomial. * @return this-S. */ public ColorPolynomial subtract(ColorPolynomial S) { GenPolynomial> g, r, w; g = green.subtract(S.green); r = red.ring.getZERO(); w = getEssentialPolynomial().subtract(S.getEssentialPolynomial()); return new ColorPolynomial(g, r, w); } /** * ColorPolynomial subtract. * @param s GenPolynomial. * @param e exponent vector. * @return this-(c e). */ public ColorPolynomial subtract(GenPolynomial s, ExpVector e) { GenPolynomial> g, r, w; g = green; r = red; w = white; if (green.getMap().keySet().contains(e)) { g = green.subtract(s, e); } else if (red.getMap().keySet().contains(e)) { r = red.subtract(s, e); } else { w = white.subtract(s, e); } return new ColorPolynomial(g, r, w); } /** * ColorPolynomial multiplication by monomial. * @param s Coefficient. * @param e Expvector. * @return this * (c t). */ public ColorPolynomial multiply(GenPolynomial s, ExpVector e) { GenPolynomial> g, r, w; if (green instanceof GenSolvablePolynomial) { logger.info("use left multiplication"); GenSolvablePolynomial> gs, rs, ws; gs = (GenSolvablePolynomial>) green; rs = (GenSolvablePolynomial>) red; ws = (GenSolvablePolynomial>) white; g = gs.multiplyLeft(s, e); r = rs.multiplyLeft(s, e); w = ws.multiplyLeft(s, e); } else { g = green.multiply(s, e); r = red.multiply(s, e); w = white.multiply(s, e); } return new ColorPolynomial(g, r, w); } /** * ColorPolynomial multiplication by coefficient. * @param s Coefficient. * @return this * (s). */ public ColorPolynomial multiply(GenPolynomial s) { GenPolynomial> g, r, w; // coefficients commute g = green.multiply(s); r = red.multiply(s); w = white.multiply(s); return new ColorPolynomial(g, r, w); } /** * ColorPolynomial division by coefficient. * @param s Coefficient. * @return this / (s). */ public ColorPolynomial divide(GenPolynomial s) { GenPolynomial> g, r, w; g = green.divide(s); r = red.divide(s); w = white.divide(s); return new ColorPolynomial(g, r, w); } } java-algebra-system-2.7.200/src/edu/jas/application/ColoredSystem.java000066400000000000000000000264521445075545500256320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for a condition, a corresponding colored polynomial list and a * Groebner base pair list. * @param coefficient type */ public class ColoredSystem> { private static final Logger logger = LogManager.getLogger(ColoredSystem.class); private static final boolean debug = logger.isDebugEnabled(); /** * Condition determinig this colored system. */ public final Condition condition; /** * Colored polynomials of this system. */ public final List> list; /** * Groebner base pair list of this system. */ public final OrderedCPairlist pairlist; /** * Constructor for a colored polynomial system. * @param cond a condition. * @param S a list of colored polynomials. */ public ColoredSystem(Condition cond, List> S) { this(cond, S, null); } /** * Constructor for a colored polynomial system. * @param cond a condition. * @param S a list of colored polynomials. * @param pl a ordered pair list. */ public ColoredSystem(Condition cond, List> S, OrderedCPairlist pl) { this.condition = cond; this.list = S; this.pairlist = pl; } /** * Copy this colored polynomial system. * @return a clone of this. */ public ColoredSystem copy() { return new ColoredSystem(condition, list, pairlist.copy()); } /** * Add to list of colored systems. This is added to the list of colored * systems, if a system with the same condition is not already contained. * @param L a list of colored systems. * @return L.add(this) if this not in L, else L. */ public List> addToList(List> L) { List> S = new ArrayList>(L.size() + 1); boolean contained = false; for (ColoredSystem x : L) { if (condition.equals(x.condition) && list.equals(x.list)) { logger.info("replaced system = {}", x.condition); S.add(this); contained = true; } else { // copy existing // System.out.println("kept system = " + x); S.add(x); } } if (!contained) { S.add(this); } return S; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("ColoredSystem: \n"); if (list.size() > 0) { s.append("polynomial ring : " + list.get(0).green.ring + "\n"); } else { s.append("parameter polynomial ring : " + condition.zero.getRing() + "\n"); } s.append("conditions == 0 : " + getConditionZero() + "\n"); s.append("conditions != 0 : " + getConditionNonZero() + "\n"); if (debug) { s.append("green coefficients:\n" + getGreenCoefficients() + "\n"); s.append("red coefficients:\n" + getRedCoefficients() + "\n"); } s.append("colored polynomials:\n" + list + "\n"); s.append("uncolored polynomials:\n" + getPolynomialList() + "\n"); if (debug) { s.append("essential polynomials:\n" + getEssentialPolynomialList() + "\n"); } if (pairlist != null) { s.append(pairlist.toString() + "\n"); } return s.toString(); } /** * Get the Script representation. * @see edu.jas.structure.Element#toScript() */ public String toScript() { StringBuffer s = new StringBuffer("ColoredSystem: \n"); if (list.size() > 0) { s.append("polynomial ring : " + list.get(0).green.ring.toScript() + "\n"); } else { s.append("parameter polynomial ring : " + condition.zero.getRing().toScript() + "\n"); } s.append("conditions == 0 : " + getConditionZero().toString() + "\n"); s.append("conditions != 0 : " + getConditionNonZero().toString() + "\n"); if (debug) { s.append("green coefficients:\n" + getGreenCoefficients().toString() + "\n"); s.append("red coefficients:\n" + getRedCoefficients().toString() + "\n"); } s.append("colored polynomials:\n" + list + "\n"); s.append("uncolored polynomials:\n" + getPolynomialList() + "\n"); if (debug) { s.append("essential polynomials:\n" + getEssentialPolynomialList() + "\n"); } if (pairlist != null) { s.append(pairlist.toString() + "\n"); } return s.toString(); } /** * Is this colored system equal to other. * @param c other colored system. * @return true, if this is equal to other, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object c) { ColoredSystem cs = null; try { cs = (ColoredSystem) c; } catch (ClassCastException e) { return false; } if (cs == null) { return false; } boolean t = (condition.equals(cs.condition) && list.equals(cs.list)); if (!t) { return t; } // now t == true t = pairlist.equals(cs.pairlist); if (!t) { System.out.println("pairlists not equal " + pairlist + ", " + cs.pairlist); } return true; // if lists are equal ignore pairlists } /** * Hash code for this colored system. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = condition.hashCode(); h = h << 17; h += list.hashCode(); // h = h << 11; // h += pairlist.hashCode(); return h; } /** * Get zero condition. * @return condition.zero. */ public List> getConditionZero() { return condition.zero.getList(); } /** * Get non zero condition. * @return condition.nonZero. */ public List> getConditionNonZero() { return condition.nonZero.mset; } /** * Get list of red coefficients of polynomials. * @return list of all red coefficients of polynomials. */ public List> getRedCoefficients() { Set> F = new HashSet>(); for (ColorPolynomial s : list) { F.addAll(s.red.getMap().values()); } List> M = new ArrayList>(F); return M; } /** * Get list of green coefficients of polynomials. * @return list of all green coefficients of polynomials. */ public List> getGreenCoefficients() { Set> F = new HashSet>(); for (ColorPolynomial s : list) { F.addAll(s.green.getMap().values()); } List> M = new ArrayList>(F); return M; } /** * Get list of full polynomials. * @return list of all full polynomials. */ public List>> getPolynomialList() { List>> F = new ArrayList>>(); for (ColorPolynomial s : list) { F.add(s.getPolynomial()); } return F; } /** * Get list of essential polynomials. * @return list of all essential polynomials. */ public List>> getEssentialPolynomialList() { List>> F = new ArrayList>>(); for (ColorPolynomial s : list) { F.add(s.getEssentialPolynomial()); } return F; } /** * Check invariants. Check if all polynomials are determined and if the * color of all coefficients is correct with respect to the condition. * @return true, if all invariants are met, else false. */ public boolean checkInvariant() { if (!isDetermined()) { return false; } if (!condition.isDetermined(list)) { return false; } // Condition cond = condition; for (ColorPolynomial s : list) { if (!s.checkInvariant()) { System.out.println("notInvariant " + s); System.out.println("condition: " + condition); return false; } for (GenPolynomial g : s.green.getMap().values()) { if (condition.color(g) != Condition.Color.GREEN) { System.out.println("notGreen " + g); System.out.println("condition: " + condition); System.out.println("colors: " + s); return false; } } for (GenPolynomial r : s.red.getMap().values()) { if (condition.color(r) != Condition.Color.RED) { System.out.println("notRed " + r); System.out.println("condition: " + condition); System.out.println("colors: " + s); return false; } } for (GenPolynomial w : s.white.getMap().values()) { if (condition.color(w) != Condition.Color.WHITE) { // System.out.println("notWhite " + w); // System.out.println("condition: " + condition); // System.out.println("colors: " + s); continue; // no error // return false; } } } return true; } /** * Is this colored system completely determined. * @return true, if each ColorPolynomial is determined, else false. */ public boolean isDetermined() { for (ColorPolynomial s : list) { if (s.isZERO()) { continue; } if (!s.isDetermined()) { System.out.println("not simple determined " + s); System.out.println("condition: " + condition); return false; } if (!condition.isDetermined(s)) { return false; } } return true; } /** * Re determine colorings of polynomials. * @return colored system with re determined colored polynomials. */ public ColoredSystem reDetermine() { if (condition == null || condition.zero.isONE()) { return this; } List> Sn = new ArrayList>(list.size()); for (ColorPolynomial c : list) { ColorPolynomial a = condition.reDetermine(c); // if ( !a.isZERO() ) { Sn.add(a); // must also add zeros // } } return new ColoredSystem(condition, Sn, pairlist); } } java-algebra-system-2.7.200/src/edu/jas/application/ComprehensiveGroebnerBaseSeq.java000066400000000000000000000622101445075545500305650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBase; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.SGBFactory; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Comprehensive Groebner Base sequential algorithm. Implements faithful * comprehensive Groebner bases via Groebner systems and CGB test. * @param coefficient type * @author Heinz Kredel */ public class ComprehensiveGroebnerBaseSeq> /* extends GroebnerBaseAbstract> */{ private static final Logger logger = LogManager.getLogger(ComprehensiveGroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Squarefree for coefficient content and primitive parts. */ protected final SquarefreeAbstract engine; /* * Flag if gcd engine should be used. */ //private final boolean notFaithfull = false; /** * Comprehensive reduction engine. */ protected final CReductionSeq cred; /** * Polynomial coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param rf base coefficient ring factory. */ public ComprehensiveGroebnerBaseSeq(RingFactory rf) { this(new CReductionSeq(rf), rf); } /** * Constructor. * @param red C-pseudo-Reduction engine * @param rf base coefficient ring factory. */ @SuppressWarnings("unchecked") public ComprehensiveGroebnerBaseSeq(CReductionSeq red, RingFactory rf) { // super(null); // red not possible since type of type cred = red; cofac = rf; // selection for C but used for R: //engine e = GCDFactory. getImplementation(cofac); engine = SquarefreeFactory. getImplementation(rf); } /** * Comprehensive-Groebner base test. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGB(List>> F) { return isGB(0, F); } /** * Comprehensive-Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGB(int modv, List>> F) { // return isGBcol( modv, F ); return isGBsubst(modv, F); } /** * Comprehensive-Groebner base test using colored systems. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGBcol(List>> F) { return isGBcol(0, F); } /** * Comprehensive-Groebner base test using colored systems. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGBcol(int modv, List>> F) { if (F == null || F.size() == 0) { return true; } List> CS = cred.determine(F); return isGBsys(modv, CS); } /** * Comprehensive-Groebner system test. * @param CS list of colored systems. * @return true, if CS is a Comprehensive-Groebner system, else false. */ // @Override public boolean isGBsys(List> CS) { return isGBsys(0, CS); } /** * Comprehensive-Groebner system test. * @param modv module variable number, unused. * @param CS list of colored systems. * @return true, if CS is a Comprehensive-Groebner system, else false. */ // @Override public boolean isGBsys(int modv, List> CS) { if (CS == null || CS.size() == 0) { return true; } if (modv != 0) { throw new IllegalArgumentException("modv !0 not supported."); } ColorPolynomial p, q, h, hp; for (ColoredSystem cs : CS) { if (debug) { if (!cs.isDetermined()) { System.out.println("not determined, cs = " + cs); return false; } if (!cs.checkInvariant()) { System.out.println("not invariant, cs = " + cs); return false; } } Condition cond = cs.condition; List> S = cs.list; int k = S.size(); for (int j = 0; j < k; j++) { p = S.get(j); for (int l = j + 1; l < k; l++) { q = S.get(l); h = cred.SPolynomial(p, q); // System.out.println("spol(a,b) = " + h); h = cred.normalform(cond, S, h); // System.out.println("NF(spol(a,b)) = " + h); if (debug) { if (!cred.isNormalform(S, h)) { System.out.println("not normalform, h = " + h); System.out.println("cs = " + cs); return false; } } if (!h.isZERO()) { hp = cond.reDetermine(h); if (!hp.isZERO()) { System.out.println("p = " + p); System.out.println("q = " + q); System.out.println("not zero: NF(spol(p,q)) = " + h); System.out.println("redetermine(NF(spol(p,q))) = " + hp); System.out.println("cs = " + cs); return false; } } } } } return true; } /** * Comprehensive-Groebner base test using substitution. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGBsubst(List>> F) { return isGBsubst(0, F); } /** * Comprehensive-Groebner base test using substitution. * @param modv module variable number, unused. * @param F polynomial list. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isGBsubst(int modv, List>> F) { if (F == null || F.isEmpty()) { return true; } if (modv != 0) { throw new IllegalArgumentException("modv !0 not supported."); } GenPolynomial> f = F.get(0); // assert non Zero GenPolynomialRing> cf = f.ring; List> CS = cred.determine(F); if (logger.isDebugEnabled()) { logger.info("determined polynomials =\n{}", CS); } // substitute zero conditions into parameter coefficients and test for (ColoredSystem cs : CS) { Ideal id = cs.condition.zero; ResidueRing r = new ResidueRing(id); // if (!r.isField()) { // System.out.println("condition zero ideal, no field = " + r.toScript()); // // no return true; // } //GroebnerBase> bb = new GroebnerBasePseudoSeq>(r); List>> list; boolean t; if (cf instanceof GenSolvablePolynomialRing) { GenSolvablePolynomialRing> rf = new GenSolvablePolynomialRing>(r, cf); List>> rel = ((GenSolvablePolynomialRing>) cf).table .relationList(); List>> relres = PolyUtilApp. toResidue(rf, PolynomialList.> castToList(rel)); rf.addRelations(relres); //System.out.println("rf = " + rf.toScript()); list = PolyUtilApp. toResidue(rf, F); SolvableGroebnerBase> bb = SGBFactory.getImplementation(r); t = bb.isLeftGB(PolynomialList.> castToSolvableList(list)); } else { GenPolynomialRing> rf = new GenPolynomialRing>(r, cf); //System.out.println("rf = " + rf.toScript()); list = PolyUtilApp. toResidue(rf, F); GroebnerBase> bb = GBFactory.getImplementation(r); t = bb.isGB(list); } if (!t) { System.out.println("test condition = " + cs.condition); System.out.println("test ideal = " + id.toScript()); System.out.println("test F = " + F); System.out.println("no GB for residue coefficients = " + list); return false; } } // substitute random ideal into parameter coefficients and test GenPolynomialRing ccf = (GenPolynomialRing) cf.coFac; int nv = ccf.nvar - 2; if (nv < 1) { nv = 1; } List> il = new ArrayList>(); int i = 0; //int j = 1; while (i < nv) { //j++; GenPolynomial p = ccf.random(3, 2, 3, 0.43f).monic(); //j + 1); //System.out.println("p = " + p); if (p.isConstant()) { continue; } if (p.isZERO()) { continue; } if (p.length() <= 1) { p = p.sum(ccf.getONE()); } p = engine.squarefreePart(p); il.add(p); i++; } logger.info("random ideal = {}", il); Ideal id = new Ideal(ccf, il); id.doGB(); ResidueRing r = new ResidueRing(id); if (!r.isField()) { //System.out.println("random ideal, no field = " + r.toScript()); return true; } //GroebnerBase> bb = new GroebnerBasePseudoSeq>(r); List>> list; boolean t; if (cf instanceof GenSolvablePolynomialRing) { GenSolvablePolynomialRing> rf = new GenSolvablePolynomialRing>(r, cf); List>> rel = ((GenSolvablePolynomialRing>) cf).table .relationList(); List>> relres = PolyUtilApp. toResidue(rf, PolynomialList.> castToList(rel)); rf.addRelations(relres); //System.out.println("rf = " + rf.toScript()); list = PolyUtilApp. toResidue(rf, F); SolvableGroebnerBase> bb = SGBFactory.getImplementation(r); t = bb.isLeftGB(PolynomialList.> castToSolvableList(list)); } else { GenPolynomialRing> rf = new GenPolynomialRing>(r, cf); //System.out.println("rf = " + rf.toScript()); list = PolyUtilApp. toResidue(rf, F); GroebnerBase> bb = GBFactory.getImplementation(r); t = bb.isGB(list); } if (!t) { System.out.println("test random ideal = " + id.toScript()); System.out.println("no GB for residue coefficients = " + list); return false; } return true; } /** * Comprehensive-Groebner system test. * @param F Groebner system. * @return true, if F is a Comprehensive-Groebner system, else false. */ // @Override public boolean isGBsys(GroebnerSystem F) { return isGBsys(0, F.list); } /** * Comprehensive-Groebner base test. * @param F Groebner system. * @return true, if F is a Comprehensive-Groebner base, else false. */ // @Override public boolean isCGB(GroebnerSystem F) { return isGB(F.getCGB()); } /** * Comprehensive-Groebner system and base test. * @param F Groebner system. * @return true, if F is a Comprehensive-Groebner system and base, else * false. */ // @Override public boolean isGB(GroebnerSystem F) { return isGBsys(0, F.list) && isGB(F.getCGB()); } /** * Comprehensive Groebner base system using pairlist class. * @param F polynomial list. * @return GBsys(F) a Comprehensive Groebner system of F. */ // @Override // @SuppressWarnings("unchecked") public GroebnerSystem GBsys(List>> F) { if (F == null) { return null; } List> CSp = new ArrayList>(); if (F.size() == 0) { return new GroebnerSystem(CSp); } // extract coefficient factory GenPolynomial> f = F.get(0); GenPolynomialRing> fac = f.ring; // determine polynomials List> CS = cred.determine(F); // System.out.println("CS = " + CS); // CS.remove(0); // empty colored system logger.info("determined polynomials =\n{}", CS); // setup pair lists List> CSs = new ArrayList>(); ColoredSystem css; for (ColoredSystem cs : CS) { OrderedCPairlist pairlist = new OrderedCPairlist(fac); for (ColorPolynomial p : cs.list) { // System.out.println("p = " + p); pairlist.put(p); } css = new ColoredSystem(cs.condition, cs.list, pairlist); CSs.add(css); } // main loop List> CSb = new ArrayList>(); List> ncs; List> CSh; //, CSbh; ColoredSystem cs; List> G; OrderedCPairlist pairlist; Condition cond; int si = 0; while (CSs.size() > 0) { cs = CSs.get(0); // remove(0); si++; logger.info("popped GBsys number {} with condition = {}", si, cs.condition); logger.info("popped GBsys (remaining {}) with pairlist = {}", (CSs.size() - 1), cs.pairlist); if (!cs.isDetermined()) { cs = cs.reDetermine(); } pairlist = cs.pairlist; G = cs.list; cond = cs.condition; // logger.info("{}", pairlist); CPair pair; ColorPolynomial pi; ColorPolynomial pj; ColorPolynomial S; // GenPolynomial> H; ColorPolynomial H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) continue; pi = pair.pi; pj = pair.pj; if (debug) { logger.info("pi = {}, pj = {}", pi, pj); } S = cred.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { // logger.info("ht(S) = {}", S.leadingExpVector() ); logger.info("S = {}", S); } H = cred.normalform(cond, G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = H.abs(); if (debug) { logger.debug("H = {}", H); } logger.info("H = {}", H); if (!H.isZERO()) { //CSh = new ArrayList>(); ncs = determineAddPairs(cs, H); if (ncs.size() == 0) { continue; } cs = ncs.remove(0); // remove other? pairlist = cs.pairlist; G = cs.list; cond = cs.condition; logger.info("replaced main branch = {}", cond); logger.info("#new systems = {}", ncs.size()); int yi = CSs.size(); for (ColoredSystem x : ncs) { if (!x.isDetermined()) { x = x.reDetermine(); } CSs = x.addToList(CSs); } logger.info("#new systems added = {}", (CSs.size() - yi)); } } // all s-pols reduce to zero in this branch if (!cs.isDetermined()) { cs = cs.reDetermine(); } CSb.add(cs); CSs.remove(0); logger.info("done with = {}", cs.condition); } // all branches done CSh = new ArrayList>(); for (ColoredSystem x : CSb) { // System.out.println("G = " + x.list ); if (!x.isDetermined()) { x = x.reDetermine(); } cs = minimalGB(x); // System.out.println("min(G) = " + cs.list ); if (!cs.isDetermined()) { cs = cs.reDetermine(); } // cs = new ColoredSystem( x.condition, G, x.pairlist ); CSh.add(cs); logger.info("#sequential done = {}", x.condition); logger.info("{}", x.pairlist); } CSb = new ArrayList>(CSh); return new GroebnerSystem(CSb); } /** * Determine polynomial relative to a condition of a colored system and add * pairs. * @param cs a colored system. * @param A color polynomial. * @return list of colored systems, the conditions extending the condition * of cs. */ public List> determineAddPairs(ColoredSystem cs, ColorPolynomial A) { List> NCS = new ArrayList>(); if (A == null || A.isZERO()) { // NCS.add( cs ); return NCS; } List> S = cs.list; Condition cond = cs.condition; // .clone(); done in Condition // itself OrderedCPairlist pl = cs.pairlist; List> Sp; ColorPolynomial nz; ColoredSystem NS; // if ( A.isDetermined() ) { ... } // dont use this // System.out.println("to determine = " + A); GenPolynomial> Ap = A.getPolynomial(); List> cd = cred.caseDistinction(cond, Ap); logger.info("# cases = {}", cd.size()); for (Condition cnd : cd) { //nz = cnd.determine(Ap); nz = cnd.reDetermine(A); if (nz.isZERO()) { logger.info("zero determined nz = {}", nz); Sp = new ArrayList>(S); OrderedCPairlist PL = pl.copy(); NS = new ColoredSystem(cnd, Sp, PL); try { if (!NS.isDetermined()) { NS = NS.reDetermine(); } } catch (RuntimeException e) { System.out.println("Contradiction in NS_0 = " + NS); //e.printStackTrace(); continue; } NCS = NS.addToList(NCS); continue; } if (S.contains(nz)) { System.out.println("*** S.contains(nz) ***"); continue; } logger.info("new determined nz = {}", nz); Sp = new ArrayList>(S); Sp.add(nz); OrderedCPairlist PL = pl.copy(); PL.put(nz); NS = new ColoredSystem(cnd, Sp, PL); try { if (!NS.isDetermined()) { NS = NS.reDetermine(); } } catch (RuntimeException e) { System.out.println("Contradiction in NS = " + NS); //e.printStackTrace(); continue; } NCS = NS.addToList(NCS); } // System.out.println("new determination = " + NCS); return NCS; } /** * Comprehensive Groebner base via Groebner system. * @param F polynomial list. * @return GB(F) a Comprehensive Groebner base of F. */ // @Override // @SuppressWarnings("unchecked") public List>> GB(List>> F) { if (F == null) { return F; } // compute Groebner system GroebnerSystem gs = GBsys(F); // System.out.println("\n\nGBsys = " + gs); return gs.getCGB(); } /** * Minimal ordered Groebner basis. * @param cs colored system. * @return a reduced Groebner base of Gp. */ // @Override public ColoredSystem minimalGB(ColoredSystem cs) { // List> Gp ) { if (cs == null || cs.list == null || cs.list.size() <= 1) { return cs; } // remove zero polynomials List> G = new ArrayList>(cs.list.size()); for (ColorPolynomial a : cs.list) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return new ColoredSystem(cs.condition, G, cs.pairlist); } // System.out.println("G check " + G); // remove top reducible polynomials Condition cond = cs.condition; ColorPolynomial a, b; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); b = a; // System.out.println("check " + b); //if (false) { // if (a.red.leadingBaseCoefficient().isConstant()) { // dont drop // // these // F.add(a); // continue; // } //} if (cred.isTopReducible(G, a) || cred.isTopReducible(F, a)) { // drop polynomial if (debug) { // System.out.println("trying to drop " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = cred.normalform(cond, ff, a); try { a = cond.reDetermine(a); } catch (RuntimeException ignored) { } if (!a.isZERO()) { logger.error("nf(a) != 0 {}, {}", b, a); F.add(b); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return new ColoredSystem(cs.condition, G, cs.pairlist); } Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int i = 0; while (i < len) { a = G.remove(0); b = a; ExpVector e = a.red.leadingExpVector(); // System.out.println("reducing " + a); a = cred.normalform(cond, G, a); // unchanged by top reduction // System.out.println("reduced " + a); try { a = cond.reDetermine(a); } catch (RuntimeException ignored) { } ExpVector f = a.red.leadingExpVector(); // a = ##engine.basePrimitivePart(a); //a.monic(); was not required // a = a.abs(); // a = red.normalform( F, a ); if (e.equals(f)) { G.add(a); // adds as last } else { // should not happen if (debug) { logger.error("nf(a) not determined {}, {}", b, a); } G.add(b); // adds as last } i++; } return new ColoredSystem(cs.condition, G, cs.pairlist); } } java-algebra-system-2.7.200/src/edu/jas/application/Condition.java000066400000000000000000000354431445075545500247640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gbufd.MultiplicativeSet; import edu.jas.gbufd.MultiplicativeSetSquarefree; //import edu.jas.gbufd.MultiplicativeSetFactors; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; /** * Condition. Container for an ideal of polynomials considered to be zero and a * multiplicative set of polynomials considered to be non-zero. * @param coefficient type * @author Heinz Kredel */ public class Condition> implements Serializable { private static final Logger logger = LogManager.getLogger(Condition.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Colors. */ public static enum Color { GREEN, RED, WHITE }; /** * Data structure for condition zero. */ public final Ideal zero; /** * Data structure for condition non-zero. */ public final MultiplicativeSet nonZero; /** * Condition constructor. Constructs an empty condition with squarefree * multiplicative set. * @param ring polynomial ring factory for coefficients. */ public Condition(GenPolynomialRing ring) { this(new Ideal(ring), new MultiplicativeSetSquarefree(ring)); //this(new Ideal(ring), new MultiplicativeSetFactors(ring)); //if (ring == null) { // too late to test // throw new IllegalArgumentException("only for non null rings"); //} } /** * Condition constructor. Constructs a condition with squarefree * multiplicative set. * @param z an ideal of zero polynomials. */ public Condition(Ideal z) { this(z, new MultiplicativeSetSquarefree(z.list.ring)); //this(z,new MultiplicativeSetFactors(z.list.ring)); } /** * Condition constructor. * @param nz a list of non-zero polynomials. */ public Condition(MultiplicativeSet nz) { this(new Ideal(nz.ring), nz); } /** * Condition constructor. * @param z an ideal of zero polynomials. * @param nz a list of non-zero polynomials. */ public Condition(Ideal z, MultiplicativeSet nz) { if (z == null || nz == null) { throw new IllegalArgumentException("only for non null condition parts"); } zero = z; nonZero = nz; } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "Condition[ 0 == " + zero.getList().toString() + ", 0 != " + nonZero.mset.toString() + " ]"; } /** * toScript. * @see edu.jas.structure.Element#toScript() */ public String toScript() { return "Condition[ 0 == " + zero.getList().toString() + ", 0 != " + nonZero.mset.toString() + " ]"; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object ob) { Condition c = null; try { c = (Condition) ob; } catch (ClassCastException e) { return false; } if (c == null) { return false; } if (!zero.equals(c.zero)) { return false; } if (!nonZero.equals(c.nonZero)) { return false; } // better: //if ( nonZero.removeFactors(c.nonZero).size() != 0 ) { // return false; //} //if ( c.nonZero.removeFactors(nonZero).size() != 0 ) { // return false; //} return true; } /** * Hash code for this condition. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = zero.getList().hashCode(); h = h << 17; h += nonZero.hashCode(); // h = h << 11; // h += pairlist.hashCode(); return h; } /** * Is empty condition. * @return true if this is the empty condition, else false. */ public boolean isEmpty() { return (zero.isZERO() && nonZero.isEmpty()); } /** * Is contradictory. * @return true if this condition is contradictory, else false. */ public boolean isContradictory() { if (zero.isZERO()) { return false; } boolean t = zero.isONE(); if (t) { logger.info("contradiction zero.isONE(): {}", this); return t; } for (GenPolynomial p : zero.getList()) { t = nonZero.contains(p); if (t) { logger.info("contradiction nonZero.contains(zero): {}, pol = {}", this, p); return t; } } for (GenPolynomial p : nonZero.mset) { t = zero.contains(p); if (t) { logger.info("contradiction zero.contains(nonZero): {}, pol = {}", this, p); return t; } } return false; } /** * Extend condition with zero polynomial. * @param z a polynomial to be treated as zero. * @return new condition. */ public Condition extendZero(GenPolynomial z) { // assert color(z) == white z = z.monic(); Ideal idz = zero.sum(z); logger.info("added to ideal: {}", z); Condition nc = new Condition(idz, nonZero); //if (true) { return nc.simplify(); //} //return nc; } /** * Extend condition with non-zero polynomial. * @param nz a polynomial to be treated as non-zero. * @return new condition. */ public Condition extendNonZero(GenPolynomial nz) { // assert color(nz) == white GenPolynomial n = zero.normalform(nz).monic(); if (n == null || n.isZERO()) { return this; } MultiplicativeSet ms = nonZero.add(n); logger.info("added to non zero: {}", n); Condition nc = new Condition(zero, ms); //if (true) { return nc.simplify(); //} //return nc; } /** * Simplify zero and non-zero polynomial conditions. * @return new simplified condition. */ public Condition simplify() { //if (false) { // no simplification // return this; //} Ideal idz = zero.squarefree(); if (!idz.getList().equals(zero.getList())) { logger.info("simplify squarefree: {} to {}", zero.getList(), idz.getList()); } List> ml = idz.normalform(nonZero.mset); MultiplicativeSet ms = nonZero; if (!ml.equals(nonZero.mset)) { if (ml.size() != nonZero.mset.size()) { logger.info("contradiction(==0):"); logger.info("simplify normalform contradiction: {} to {}", nonZero.mset, ml); return null; } logger.info("simplify normalform: {} to {}", nonZero.mset, ml); ms = nonZero.replace(ml); } List> Z = ms.removeFactors(idz.getList()); if (!Z.equals(idz.getList())) { if (Z.size() != idz.getList().size()) { // never true logger.info("contradiction(!=0):"); logger.info("simplify removeFactors contradiction: {} to {}", idz.getList(), Z); return null; } logger.info("simplify removeFactors: {} to {}", idz.getList(), Z); idz = new Ideal(zero.getRing(), Z); // changes ideal } Condition nc = new Condition(idz, ms); if (nc.isContradictory()) { // eventually a factor became 1 logger.info("simplify contradiction: {}", nc); return null; } if (idz.equals(zero) && ms.equals(nonZero)) { return this; } logger.info("condition simplified: {} to {}", this, nc); //if (false) { // no further simplification // return nc; //} return nc.simplify(); } /** * Determine color of polynomial. * @param c polynomial to be colored. * @return color of c. */ public Color color(GenPolynomial c) { GenPolynomial m = zero.normalform(c).monic(); //non-sense: m = nonZero.removeFactors(m); if (m.isZERO()) { // zero.contains(m) // System.out.println("m in id = " + m); return Color.GREEN; } if (m.isConstant()) { // System.out.println("m constant " + m); return Color.RED; } if (nonZero.contains(m) || nonZero.contains(c)) { // System.out.println("m or c in nonzero " + m); return Color.RED; } //System.out.println("m white " + m + ", c = " + c); return Color.WHITE; } /** * Determine polynomial. If this condition does not determine the * polynomial, then a run-time exception is thrown. * @param A polynomial. * @return new determined colored polynomial. */ public ColorPolynomial determine(GenPolynomial> A) { ColorPolynomial cp = null; if (A == null) { return cp; } GenPolynomial> zero = A.ring.getZERO(); GenPolynomial> green = zero; GenPolynomial> red = zero; GenPolynomial> white = zero; if (A.isZERO()) { cp = new ColorPolynomial(green, red, white); return cp; } GenPolynomial> Ap = A; GenPolynomial> Bp; while (!Ap.isZERO()) { Map.Entry> m = Ap.leadingMonomial(); ExpVector e = m.getKey(); GenPolynomial c = m.getValue(); Bp = Ap.reductum(); // System.out.println( "color(" + c + ") = " + color(c) ); switch (color(c)) { case GREEN: green = green.sum(c, e); Ap = Bp; continue; case RED: red = red.sum(c, e); white = Bp; return new ColorPolynomial(green, red, white); // since break is not possible case WHITE: default: logger.info("recheck undetermined coeff c = {}, cond = {}", c, this); if (extendZero(c) == null) { // contradiction if colored green logger.info("recheck assume red"); red = red.sum(c, e); // assume red white = Bp; return new ColorPolynomial(green, red, white); } if (extendNonZero(c) == null) { // contradiction if colored red logger.info("recheck assume green"); green = green.sum(c, e); // assume green Ap = Bp; continue; } System.out.println("undetermined cond = " + this); System.out.println("undetermined poly A = " + A); System.out.println("undetermined poly green = " + green); System.out.println("undetermined poly red = " + red); System.out.println("undetermined poly Bp = " + Bp); System.out.println("undetermined coeff c = " + c); throw new RuntimeException("undetermined, c is white = " + c); // is caught in minimalGB } } cp = new ColorPolynomial(green, red, white); // System.out.println("determined = " + cp); return cp; } /** * Determine list of polynomials. If this condition does not determine all * polynomials, then a run-time exception is thrown. The returned list does * not contain polynomials with all green terms. * @param L list of polynomial. * @return new determined list of colored polynomials. */ public List> determine(List>> L) { List> cl = null; if (L == null) { return cl; } cl = new ArrayList>(L.size()); for (GenPolynomial> A : L) { ColorPolynomial c = determine(A); if (c != null && !c.isZERO()) { cl.add(c); } } return cl; } /** * Re determine colored polynomial. * @param s colored polynomial. * @return determined colored polynomial wrt. this.conditions. */ public ColorPolynomial reDetermine(ColorPolynomial s) { ColorPolynomial p = determine(s.getEssentialPolynomial()); // assume green terms stay green wrt. this condition GenPolynomial> g = s.green.sum(p.green); p = new ColorPolynomial(g, p.red, p.white); return p; } /** * Re determine list of colored polynomials. * @param S list of colored polynomials. * @return list of determined colored polynomials wrt. this.conditions. */ public List> reDetermine(List> S) { if (S == null || S.isEmpty()) { return S; } List> P = new ArrayList>(); for (ColorPolynomial s : S) { ColorPolynomial p = reDetermine(s); P.add(p); } return P; } /** * Is determined colored polynomial. * @param s colored polynomial. * @return true if the colored polynomial is correctly determined wrt. * this.condition. */ public boolean isDetermined(ColorPolynomial s) { ColorPolynomial p = determine(s.getPolynomial()); boolean t = p.equals(s); if (!t) { System.out.println("not determined s = " + s); System.out.println("not determined p = " + p); System.out.println("not determined cond = " + this); } return t; } /** * Is determined list of colored polynomial. * @param S list of colored polynomials. * @return true if the colored polynomials in S are correctly determined * wrt. this.condition. */ public boolean isDetermined(List> S) { if (S == null) { return true; } for (ColorPolynomial p : S) { if (!isDetermined(p)) { return false; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/application/Dimension.java000066400000000000000000000040561445075545500247570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.Arrays; import java.util.Set; /** * Container for dimension parameters. * @author Heinz Kredel */ public class Dimension implements Serializable { /** * Ideal dimension. */ public final int d; /** * Indices of a maximal independent set (of variables). */ public final Set S; /** * Set of indices of all maximal independent sets (of variables). */ public final Set> M; /** * Names of all variables. */ public final String[] v; /** * Constructor. * @param d ideal dimension. * @param S indices of a maximal independent set (of variables) * @param M set of indices of all maximal independent sets (of variables) * @param v names of all variables */ public Dimension(int d, Set S, Set> M, String[] v) { this.d = d; this.S = S; this.M = M; this.v = Arrays.copyOf(v,v.length); // > Java-5 } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer("Dimension( " + d + ", "); if (v == null) { sb.append("" + S + ", " + M + " )"); return sb.toString(); } String[] s = new String[S.size()]; int j = 0; for (Integer i : S) { s[j] = v[i]; j++; } sb.append(Arrays.toString(s) + ", "); sb.append("[ "); boolean first = true; for (Set m : M) { if (first) { first = false; } else { sb.append(", "); } s = new String[m.size()]; j = 0; for (Integer i : m) { s[j] = v[i]; j++; } sb.append(Arrays.toString(s)); } sb.append(" ] )"); return sb.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/Examples.java000066400000000000000000000702021445075545500246040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.gb.Cyclic; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.RGroebnerBasePseudoSeq; import edu.jas.gbufd.RReductionSeq; import edu.jas.kern.ComputerThreads; import edu.jas.kern.Scripting; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Examples for application usage. * @author Christoph Zengler * @author Heinz Kredel */ public class Examples { /** * main. */ public static void main(String[] args) { if (args.length > 0) { example1(); example2(); example3(); example4(); } example5(); example6(); example10(); example11(); example12(); ComputerThreads.terminate(); } /** * example1. cyclic n-th roots polynomial systems. */ public static void example1() { int n = 4; Cyclic cy = new Cyclic(n); System.out.println("ring = " + cy.ring); List> cp = cy.cyclicPolys(); System.out.println("cp = " + cp + "\n"); List> gb; //GroebnerBase sgb = new GroebnerBaseSeq(); GroebnerBase sgb = GBFactory.getImplementation(cy.ring.coFac); gb = sgb.GB(cp); System.out.println("gb = " + gb); } /** * example2. abstract types: * List<GenPolynomial<Product<Residue<BigRational>>>>. */ public static void example2() { List>>> L = null; L = new ArrayList>>>(); BigRational bfac = new BigRational(1); String[] cvars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = null; pfac = new GenPolynomialRing(bfac, cvars); List> F = null; F = new ArrayList>(); GenPolynomial p = null; for (int i = 0; i < 2; i++) { p = pfac.random(5, 4, 3, 0.4f); if (!p.isConstant()) { F.add(p); } } //System.out.println("F = " + F); Ideal id = new Ideal(pfac, F); id.doGB(); if (id.isONE() || id.isZERO()) { System.out.println("id zero or one = " + id); return; } ResidueRing rr = new ResidueRing(id); System.out.println("rr = " + rr); ProductRing> pr = null; pr = new ProductRing>(rr, 3); String[] vars = new String[] { "a", "b" }; GenPolynomialRing>> fac; fac = new GenPolynomialRing>>(pr, vars); GenPolynomial>> pp; for (int i = 0; i < 1; i++) { pp = fac.random(2, 4, 4, 0.4f); if (!pp.isConstant()) { L.add(pp); } } System.out.println("L = " + L); //PolynomialList>> Lp = null; //Lp = new PolynomialList>>(fac,L); //System.out.println("Lp = " + Lp); GroebnerBase>> bb = new RGroebnerBasePseudoSeq>>( pr); System.out.println("isGB(L) = " + bb.isGB(L)); List>>> G = null; G = bb.GB(L); System.out.println("G = " + G); System.out.println("isGB(G) = " + bb.isGB(G)); } /** * example3. abstract types: GB of List<GenPolynomial<Residue<BigRational>>>. */ public static void example3() { List>> L = null; L = new ArrayList>>(); BigRational bfac = new BigRational(1); String[] cvars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = null; pfac = new GenPolynomialRing(bfac, cvars); List> F = null; F = new ArrayList>(); GenPolynomial p = null; for (int i = 0; i < 2; i++) { p = pfac.random(5, 5, 5, 0.4f); //p = pfac.parse("x0^2 -2" ); if (!p.isConstant()) { F.add(p); } } //System.out.println("F = " + F); Ideal id = new Ideal(pfac, F); id.doGB(); if (id.isONE() || id.isZERO()) { System.out.println("id zero or one = " + id); return; } ResidueRing rr = new ResidueRing(id); System.out.println("rr = " + rr); String[] vars = new String[] { "a", "b" }; GenPolynomialRing> fac; fac = new GenPolynomialRing>(rr, vars); GenPolynomial> pp; for (int i = 0; i < 2; i++) { pp = fac.random(2, 4, 6, 0.2f); if (!pp.isConstant()) { L.add(pp); } } System.out.println("L = " + L); GroebnerBase> bb; //bb = new GroebnerBasePseudoSeq>(rr); bb = GBFactory.getImplementation(rr); System.out.println("isGB(L) = " + bb.isGB(L)); List>> G = null; G = bb.GB(L); System.out.println("G = " + G); System.out.println("isGB(G) = " + bb.isGB(G)); } /** * example4. abstract types: comprehensive GB of * List<GenPolynomial<GenPolynomial<BigRational>>>. */ public static void example4() { int kl = 2; int ll = 3; int el = 3; float q = 0.2f; //0.4f GenPolynomialRing cfac; GenPolynomialRing> fac; List>> L; ComprehensiveGroebnerBaseSeq bb; GenPolynomial> a, b, c; BigRational coeff = new BigRational(kl); String[] cv = { "a", "b" }; cfac = new GenPolynomialRing(coeff, cv); String[] v = { "x", "y" }; fac = new GenPolynomialRing>(cfac, v); bb = new ComprehensiveGroebnerBaseSeq(coeff); L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a; //c = fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); System.out.println("CGB exam L = " + L); L = bb.GB(L); System.out.println("CGB( L ) = " + L); System.out.println("isCGB( L ) = " + bb.isGB(L)); L.add(b); System.out.println("CGB exam L = " + L); L = bb.GB(L); System.out.println("CGB( L ) = " + L); System.out.println("isCGB( L ) = " + bb.isGB(L)); L.add(c); System.out.println("CGB exam L = " + L); L = bb.GB(L); System.out.println("CGB( L ) = " + L); System.out.println("isCGB( L ) = " + bb.isGB(L)); } /** * example5. comprehensive GB of * List<GenPolynomial<GenPolynomial<BigRational>>> and GB for regular ring. */ public static void example5() { int kl = 2; int ll = 4; int el = 3; float q = 0.3f; //0.4f GenPolynomialRing cfac; GenPolynomialRing> fac; List>> L; ComprehensiveGroebnerBaseSeq bb; GenPolynomial> a; GenPolynomial> b; GenPolynomial> c; BigRational coeff = new BigRational(kl); String[] cv = { "a", "b" }; cfac = new GenPolynomialRing(coeff, cv); String[] v = { "x", "y" }; fac = new GenPolynomialRing>(cfac, v); bb = new ComprehensiveGroebnerBaseSeq(coeff); L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a; //c = fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); System.out.println("CGB exam L = " + L); GroebnerSystem sys = bb.GBsys(L); boolean ig = bb.isGB(sys.getCGB()); System.out.println("CGB( L ) = " + sys.getCGB()); System.out.println("isCGB( L ) = " + ig); List>>> Lr, bLr; RReductionSeq>> res = new RReductionSeq>>(); Lr = PolyUtilApp. toProductRes(sys.list); bLr = res.booleanClosure(Lr); System.out.println("booleanClosed(Lr) = " + bLr); if (bLr.size() > 0) { GroebnerBase>> rbb = new RGroebnerBasePseudoSeq>>( bLr.get(0).ring.coFac); System.out.println("isRegularGB(Lr) = " + rbb.isGB(bLr)); } } /** * Example GBase and real root. */ @SuppressWarnings("unchecked") public static void example6() { BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String exam = "(x,y,z) L " + "( " + "( x^2 - 2 ), ( y^2 - 3 ), ( z^2 + x * y )" + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } System.out.println("F = " + F); List> G = gb.GB(F.list); PolynomialList Gp = new PolynomialList(F.ring, G); System.out.println("G = " + Gp); // compute real roots of the ideal Ideal I = new Ideal(Gp); List> Ir = PolyUtilApp. realAlgebraicRoots(I); for (IdealWithRealAlgebraicRoots R : Ir) { R.doDecimalApproximation(); for (List Dr : R.decimalApproximation()) { System.out.println(Dr.toString()); } System.out.println(); } } /** * example7. Coefficients in Boolean residue class ring. */ public static void example7() { String[] vars = { "v3", "v2", "v1" }; ModIntegerRing z2 = new ModIntegerRing(2); GenPolynomialRing z2p = new GenPolynomialRing(z2, vars.length, new TermOrder( TermOrder.INVLEX), vars); List> fieldPolynomials = new ArrayList>(); //add v1^2 + v1, v2^2 + v2, v3^2 + v3 to fieldPolynomials for (int i = 0; i < vars.length; i++) { GenPolynomial var = z2p.univariate(i); fieldPolynomials.add(var.multiply(var).sum(var)); } Ideal fieldPolys = new Ideal(z2p, fieldPolynomials); ResidueRing ring = new ResidueRing(fieldPolys); String[] mvars = { "mv3", "mv2", "mv1" }; GenPolynomialRing> ringp = new GenPolynomialRing>(ring, mvars.length, mvars); List>> polynomials = new ArrayList>>(); GenPolynomial> v1 = ringp.univariate(0); GenPolynomial> v2 = ringp.univariate(1); GenPolynomial> v3 = ringp.univariate(2); GenPolynomial> notV1 = v1.sum(ringp.ONE); GenPolynomial> notV2 = v2.sum(ringp.ONE); GenPolynomial> notV3 = v3.sum(ringp.ONE); //v1*v2 GenPolynomial> p1 = v1.multiply(v2); //v1*v2 + v1 + v2 + 1 GenPolynomial> p2 = notV1.multiply(notV2); //v1*v3 + v1 + v3 + 1 GenPolynomial> p3 = notV1.multiply(notV3); polynomials.add(p1); polynomials.add(p2); polynomials.add(p3); //GroebnerBase> gb = new GroebnerBasePseudoSeq>(ring); GroebnerBase> gb = GBFactory.getImplementation(ring); List>> G = gb.GB(polynomials); System.out.println(G); } /** * example8. Coefficients in Boolean residue class ring with cuppling of * variables. */ public static void example8() { String[] vars = { "v3", "v2", "v1" }; ModIntegerRing z2 = new ModIntegerRing(2); GenPolynomialRing z2p = new GenPolynomialRing(z2, vars.length, new TermOrder( TermOrder.INVLEX), vars); List> fieldPolynomials = new ArrayList>(); //add v1^2 + v1, v2^2 + v2, v3^2 + v3 to fieldPolynomials for (int i = 0; i < vars.length; i++) { GenPolynomial var = z2p.univariate(i); fieldPolynomials.add(var.multiply(var).sum(var)); } Ideal fieldPolys = new Ideal(z2p, fieldPolynomials); ResidueRing ring = new ResidueRing(fieldPolys); String[] mvars = { "mv3", "mv2", "mv1" }; GenPolynomialRing> ringp = new GenPolynomialRing>(ring, mvars.length, mvars); List>> polynomials = new ArrayList>>(); GenPolynomial> v1 = ringp.univariate(0); GenPolynomial> v2 = ringp.univariate(1); GenPolynomial> v3 = ringp.univariate(2); GenPolynomial> notV1 = v1.sum(ringp.ONE); GenPolynomial> notV2 = v2.sum(ringp.ONE); GenPolynomial> notV3 = v3.sum(ringp.ONE); //v1*v2 GenPolynomial> p1 = v1.multiply(v2); //v1*v2 + v1 + v2 + 1 GenPolynomial> p2 = notV1.multiply(notV2); //v1*v3 + v1 + v3 + 1 GenPolynomial> p3 = notV1.multiply(notV3); polynomials.add(p1); polynomials.add(p2); polynomials.add(p3); List> gens = ring.generators(); System.out.println("gens = " + gens); GenPolynomial> mv3v3 = v3.subtract(gens.get(1)); GenPolynomial> mv2v2 = v2.subtract(gens.get(2)); GenPolynomial> mv1v1 = v1.subtract(gens.get(3)); System.out.println("mv3v3 = " + mv3v3); System.out.println("mv2v2 = " + mv2v2); System.out.println("mv1v1 = " + mv1v1); polynomials.add(mv3v3); polynomials.add(mv2v2); polynomials.add(mv1v1); //GroebnerBase> gb = new GroebnerBasePseudoSeq>(ring); GroebnerBase> gb = GBFactory.getImplementation(ring); List>> G = gb.GB(polynomials); System.out.println(G); } /** * example9. Groebner base and dimension. */ public static void example9() { String[] vars = { "d1", "d2", "d3", "p1a", "p1b", "p1c", "p2a", "p2b", "p2c", "p3a", "p3b", "p3c", "p4a", "p4b", "p4c", "A", "B", "C", "D" }; BigRational br = new BigRational(); GenPolynomialRing pring = new GenPolynomialRing(br, vars); //GenPolynomialRing pring = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); GenPolynomial e1 = pring.parse("A*p1a+B*p1b+C*p1c+D"); // (1) GenPolynomial e2 = pring.parse("A*p2a+B*p2b+C*p2c+D"); // (2) GenPolynomial e3 = pring.parse("A*p3a+B*p3b+C*p3c+D"); // (3) GenPolynomial e4 = pring.parse("A*p4a+B*p4b+C*p4c+D"); // (4) GenPolynomial e5 = pring.parse("p2a-p3a"); // (5) GenPolynomial e6 = pring.parse("p2b-p3b"); // (6) GenPolynomial e7 = pring.parse("p2c-p3c"); // (7) GenPolynomial e8 = pring.parse("(p2a-p1a)^2+(p2b-p1b)^2+(p2c-p1c)^2-d1^2"); // (8) GenPolynomial e9 = pring.parse("(p4a-p3a)^2+(p4b-p3b)^2+(p4c-p3c)^2-d2^2"); // (9) List> cp = new ArrayList>(9); cp.add(e1); cp.add(e2); cp.add(e3); cp.add(e4); cp.add(e5); cp.add(e6); cp.add(e7); cp.add(e8); cp.add(e9); GenPolynomial e10 = pring.parse("(p4a-p1a)^2+(p4b-p1b)^2+(p4c-p1c)^2-d3^2"); // (10) cp.add(e10); List> gb; GroebnerBase sgb = GBFactory.getImplementation(br); gb = sgb.GB(cp); //System.out.println("gb = " + gb); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); } /** * example10. abstract types: GB of * List<GenPolynomial<AlgebraicNumber<Quotient * <AlgebraicNumber<BigRational>>>>>. */ public static void example10() { Scripting.setLang(Scripting.Lang.Ruby); BigRational bfac = new BigRational(1); GenPolynomialRing pfac; pfac = new GenPolynomialRing(bfac, new String[] { "w2" }); System.out.println("pfac = " + pfac.toScript()); // p = w2^2 - 2 GenPolynomial p = pfac.univariate(0, 2).subtract(pfac.fromInteger(2L)); System.out.println("p = " + p.toScript()); AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(p, true); System.out.println("afac = " + afac.toScript()); GenPolynomialRing> pafac; pafac = new GenPolynomialRing>(afac, new String[] { "x" }); System.out.println("pafac = " + pafac.toScript()); QuotientRing> qafac; qafac = new QuotientRing>(pafac); System.out.println("qafac = " + qafac.toScript()); GenPolynomialRing>> pqafac; pqafac = new GenPolynomialRing>>(qafac, new String[] { "wx" }); System.out.println("pqafac = " + pqafac.toScript()); List>>> qgen = pqafac.generators(); System.out.println("qgen = " + qgen); // q = wx^2 - x GenPolynomial>> q; q = pqafac.univariate(0, 2).subtract(qgen.get(2)); System.out.println("q = " + q.toScript()); AlgebraicNumberRing>> aqafac; aqafac = new AlgebraicNumberRing>>(q, true); System.out.println("aqafac = " + aqafac.toScript()); GenPolynomialRing>>> paqafac; paqafac = new GenPolynomialRing>>>(aqafac, new String[] { "y", "z" }); System.out.println("paqafac = " + paqafac.toScript()); List>>>> L; L = new ArrayList>>>>(); GenPolynomial>>> pp; /* for (int i = 0; i < 2; i++) { pp = paqafac.random(2, 3, 3, 0.2f); System.out.println("pp = " + pp.toScript()); if (pp.isConstant()) { pp = paqafac.univariate(0,3); } L.add(pp); } */ pp = paqafac.parse("(( y^2 - x )*( z^2 - 2 ) )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = paqafac.parse("( y^2 z - x^3 z - w2*wx )"); System.out.println("pp = " + pp.toScript()); L.add(pp); //System.out.println("L = " + L); GroebnerBaseAbstract>>> bb; //bb = new GroebnerBaseSeq>>>(); //aqafac); bb = GBFactory.getImplementation(aqafac); //bb = GBFactory.getProxy(aqafac); System.out.println("isGB(L) = " + bb.isGB(L)); long t = System.currentTimeMillis(); List>>>> G = bb.GB(L); t = System.currentTimeMillis() - t; System.out.println("time = " + t + " milliseconds"); //System.out.println("G = " + G); for (GenPolynomial>>> g : G) { System.out.println("g = " + g.toScript()); } System.out.println("isGB(G) = " + bb.isGB(G)); bb.terminate(); } /** * example11. abstract types: GB of List<GenPolynomial<BigRational>>>. */ public static void example11() { Scripting.setLang(Scripting.Lang.Ruby); BigRational bfac = new BigRational(1); GenPolynomialRing pfac; String[] vars = new String[] { "w2", "xi", "x", "wx", "y", "z" }; TermOrder to = new TermOrder(TermOrder.INVLEX); pfac = new GenPolynomialRing(bfac, vars, to); System.out.println("pfac = " + pfac.toScript()); List> L = new ArrayList>(); GenPolynomial pp; pp = pfac.parse("( w2^2 - 2 )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("( wx^2 - x )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("( xi * x - 1 )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("(( y^2 - x )*( z^2 - 2 ) )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("( y^2 z - x^3 z - w2*wx )"); System.out.println("pp = " + pp.toScript()); L.add(pp); GroebnerBaseAbstract bb; //bb = new GroebnerBaseSeq(); //bfac); bb = GBFactory.getImplementation(bfac); //bb = GBFactory.getProxy(bfac); System.out.println("isGB(L) = " + bb.isGB(L)); long t = System.currentTimeMillis(); List> G = bb.GB(L); t = System.currentTimeMillis() - t; System.out.println("time = " + t + " milliseconds"); for (GenPolynomial g : G) { System.out.println("g = " + g.toScript()); } System.out.println("isGB(G) = " + bb.isGB(G)); bb.terminate(); } /** * example12. abstract types: GB of * List<GenPolynomial<Quotient<BigRational>>>>. */ public static void example12() { Scripting.setLang(Scripting.Lang.Ruby); BigRational bfac = new BigRational(1); GenPolynomialRing cfac; String[] cvars = new String[] { "x" }; TermOrder to = new TermOrder(TermOrder.INVLEX); cfac = new GenPolynomialRing(bfac, cvars, to); System.out.println("cfac = " + cfac.toScript()); QuotientRing qfac; qfac = new QuotientRing(cfac); System.out.println("qfac = " + qfac.toScript()); String[] vars = new String[] { "w2", "wx", "y", "z" }; GenPolynomialRing> pfac; pfac = new GenPolynomialRing>(qfac, vars, to); System.out.println("pfac = " + pfac.toScript()); List>> L = new ArrayList>>(); GenPolynomial> pp; pp = pfac.parse("( w2^2 - 2 )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("( wx^2 - x )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("(( y^2 - x )*( z^2 - 2 ) )"); System.out.println("pp = " + pp.toScript()); L.add(pp); pp = pfac.parse("( y^2 z - x^3 z - w2*wx )"); System.out.println("pp = " + pp.toScript()); L.add(pp); GroebnerBaseAbstract> bb; //bb = new GroebnerBaseSeq>(); //bfac); // sequential bb = GBFactory.getImplementation(qfac); System.out.println("isGB(L) = " + bb.isGB(L)); long t = System.currentTimeMillis(); List>> G = bb.GB(L); t = System.currentTimeMillis() - t; System.out.println("time = " + t + " milliseconds"); for (GenPolynomial> g : G) { System.out.println("g = " + g.toScript()); } System.out.println("isGB(G) = " + bb.isGB(G)); bb.terminate(); // parallel bb = GBFactory.getProxy(qfac); System.out.println("isGB(L) = " + bb.isGB(L)); t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; System.out.println("time = " + t + " milliseconds"); for (GenPolynomial> g : G) { System.out.println("g = " + g.toScript()); } System.out.println("isGB(G) = " + bb.isGB(G)); bb.terminate(); // builder bb = GBAlgorithmBuilder.polynomialRing(pfac).fractionFree().syzygyPairlist().parallel(3).build(); System.out.println("isGB(L) = " + bb.isGB(L)); t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; System.out.println("time = " + t + " milliseconds"); for (GenPolynomial> g : G) { System.out.println("g = " + g.toScript()); } System.out.println("isGB(G) = " + bb.isGB(G)); bb.terminate(); } } java-algebra-system-2.7.200/src/edu/jas/application/ExamplesGeoTheorems.java000066400000000000000000000326321445075545500267530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.GBOptimized; import edu.jas.gb.GBProxy; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gbufd.GBFactory; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; /** * ExamplesGeoTheorems for Groebner base usage. * @author GeoGebra developers * @author Kovács Zoltán * @author Heinz Kredel */ public class ExamplesGeoTheorems { /** * main. */ public static void main(String[] args) { example10(); example11(); example12(); example13(); example14(); example15(); example16(); example17(); ComputerThreads.terminate(); } /** * get Pappus Example. */ public static List> getExample() { String[] vars = { "a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2", "e1", "e2", "f1", "f2", "g1", "g2", "h1", "h2", "i1", "i2", "j1", "j2", "z1", "z2", "z3" }; BigRational br = new BigRational(); GenPolynomialRing pring = new GenPolynomialRing(br, vars); GenPolynomial e1 = pring.parse("(a1*(b2 - c2) + a2*( - b1 + c1) + b1*c2 - b2*c1)"); GenPolynomial e2 = pring.parse("(d1*(e2 - f2) + d2*( - e1 + f1) + e1*f2 - e2*f1)"); GenPolynomial e3 = pring.parse("(a1*( - e2 + h2) + a2*(e1 - h1) - e1*h2 + e2*h1)"); GenPolynomial e4 = pring.parse("(b1*(d2 - h2) + b2*( - d1 + h1) + d1*h2 - d2*h1)"); GenPolynomial e5 = pring.parse("(c1*(d2 - i2) + c2*( - d1 + i1) + d1*i2 - d2*i1)"); GenPolynomial e6 = pring.parse("(a1*( - f2 + i2) + a2*(f1 - i1) - f1*i2 + f2*i1)"); GenPolynomial e7 = pring.parse("(c1*(e2 - j2) + c2*( - e1 + j1) + e1*j2 - e2*j1)"); GenPolynomial e8 = pring.parse("(b1*( - f2 + j2) + b2*(f1 - j1) - f1*j2 + f2*j1)"); GenPolynomial e9 = pring .parse("(a1*(b2*z2 - d2*z2) + a2*( - b1*z2 + d1*z2) + b1*d2*z2 - b2*d1*z2 - 1)"); GenPolynomial e10 = pring .parse("(a1*(b2*z3 - e2*z3) + a2*( - b1*z3 + e1*z3) + b1*e2*z3 - b2*e1*z3 - 1)"); GenPolynomial e11 = pring .parse("(h1*(i2*z1 - j2*z1) + h2*( - i1*z1 + j1*z1) + i1*j2*z1 - i2*j1*z1 - 1)"); List> cp = new ArrayList>(11); cp.add(e1); cp.add(e2); cp.add(e3); cp.add(e4); cp.add(e5); cp.add(e6); cp.add(e7); cp.add(e8); cp.add(e9); cp.add(e10); cp.add(e11); return cp; } /** * Example Pappus, sequential. */ public static void example10() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBase sgb = GBFactory.getImplementation(br); List> gb; long t; t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(gb) = " + t); t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); } /** * Example Pappus, parallel proxy. */ public static void example11() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getProxy(br); List> gb; long t; t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(proxy-gb) = " + t); t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(proxy-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); sgb.terminate(); } /** * Example Pappus, optimized term order. */ public static void example12() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getImplementation(br); GroebnerBaseAbstract ogb = new GBOptimized(sgb, true); // false no change for GB == 1 List> gb; long t; t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-gb) = " + t); t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); ogb.terminate(); } /** * Example Pappus, optimized term order and parallel proxy. */ public static void example13() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getProxy(br); GroebnerBaseAbstract ogb = new GBOptimized(sgb, true); // false no change for GB == 1 List> gb; long t; t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-proxy-gb) = " + t); t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-proxy-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); ogb.terminate(); } /** * Example Pappus, fraction free. */ public static void example14() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getImplementation(br, GBFactory.Algo.ffgb); List> gb; long t; t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(fraction-free-gb) = " + t); t = System.currentTimeMillis(); gb = sgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(fraction-free-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); sgb.terminate(); } /** * Example Pappus, optimized and fraction free. */ public static void example15() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getImplementation(br, GBFactory.Algo.ffgb); GroebnerBaseAbstract ogb = new GBOptimized(sgb, true); // false no change for GB == 1 List> gb; long t; t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-fraction-free-gb) = " + t); t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-fraction-free-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); ogb.terminate(); } /** * Example Pappus, proxy, optimized and fraction free. */ public static void example16() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getImplementation(br, GBFactory.Algo.ffgb); GroebnerBaseAbstract ogb = new GBOptimized(sgb, true); // false no change for GB == 1 GroebnerBaseAbstract pgb = new GroebnerBaseParallel(); GroebnerBaseAbstract opgb = new GBOptimized(pgb, true); // false no change for GB == 1 GroebnerBaseAbstract popgb = new GBProxy(ogb, opgb); List> gb; long t; t = System.currentTimeMillis(); gb = popgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(proxy-optimized-fraction-free-gb) = " + t); t = System.currentTimeMillis(); gb = popgb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(proxy-optimized-fraction-free-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); popgb.terminate(); } /** * Example Pappus, optimized and parallel and fraction free. */ public static void example17() { List> cp = getExample(); BigRational br = new BigRational(); GenPolynomialRing pring = cp.get(0).ring; GroebnerBaseAbstract sgb = GBFactory.getImplementation(br, GBFactory.Algo.ffgb); GroebnerBaseAbstract pgb = new GroebnerBaseParallel(); GroebnerBaseAbstract ppgb = new GBProxy(sgb, pgb); GroebnerBaseAbstract ogb = new GBOptimized(ppgb, true); // false no change for GB == 1 List> gb; long t; t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-proxy-fraction-free-gb) = " + t); t = System.currentTimeMillis(); gb = ogb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("gb = " + gb); System.out.println("time(optimized-proxy-fraction-free-gb) = " + t); PolynomialList pl = new PolynomialList(pring, gb); Ideal id = new Ideal(pl, true); System.out.println("cp = " + cp); System.out.println("id = " + id); Dimension dim = id.dimension(); System.out.println("dim = " + dim); ogb.terminate(); } } java-algebra-system-2.7.200/src/edu/jas/application/ExtensionFieldBuilder.java000066400000000000000000000207111445075545500272550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Serializable; import java.io.StringReader; import java.util.List; import edu.jas.arith.Rational; import edu.jas.arith.PrimeInteger; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.TermOrder; import edu.jas.root.ComplexAlgebraicRing; import edu.jas.root.Interval; import edu.jas.root.RealAlgebraicRing; import edu.jas.root.Rectangle; import edu.jas.root.RootUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.QuotientRing; import edu.jas.ufd.PolyUfdUtil; import edu.jas.vector.GenMatrixRing; /** * Builder for extension field towers. * @author Heinz Kredel */ public class ExtensionFieldBuilder implements Serializable { /** * The current factory. */ public final RingFactory factory; // must be a raw type /** * Constructor not for use. */ protected ExtensionFieldBuilder() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param base the base field. */ public ExtensionFieldBuilder(RingFactory base) { factory = base; } /** * Build the field tower. TODO: optimize field tower for faster * computation. */ public RingFactory build() { return factory; } /** * Set base field. * @param base the base field for the extensions. */ public static ExtensionFieldBuilder baseField(RingFactory base) { return new ExtensionFieldBuilder(base); } /** * Transcendent field extension. * @param vars names for the transcendent generators. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder transcendentExtension(String vars) { String[] variables = GenPolynomialTokenizer.variableList(vars); GenPolynomialRing pfac = new GenPolynomialRing(factory, variables); QuotientRing qfac = new QuotientRing(pfac); RingFactory base = (RingFactory) qfac; return new ExtensionFieldBuilder(base); } /** * Polynomial ring extension. * @param vars names for the polynomial ring generators. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder polynomialExtension(String vars) { String[] variables = GenPolynomialTokenizer.variableList(vars); GenPolynomialRing pfac = new GenPolynomialRing(factory, variables); RingFactory base = (RingFactory) pfac; return new ExtensionFieldBuilder(base); } /** * Matrix ring extension. * @param n dimension of n x n matrix. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder matrixExtension(int n) { GenMatrixRing mfac = new GenMatrixRing(factory, n, n); RingFactory base = (RingFactory) mfac; return new ExtensionFieldBuilder(base); } /** * Finite field extension. * Construct a finite field with q = p**n elements, where * p is the characteristic of the base field. * @param n exponent. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder finiteFieldExtension(int n) { java.math.BigInteger p = factory.characteristic(); if (p.signum() != 1) { throw new IllegalArgumentException("characteristic not finite"); } if (!PrimeInteger.isPrime(p)) { //?? throw new IllegalArgumentException("characteristic not prime"); } RingFactory base = (RingFactory) PolyUfdUtil.algebraicNumberField(factory,n); return new ExtensionFieldBuilder(base); } /** * Algebraic field extension. * @param var name(s) for the algebraic generator(s). * @param expr generating expression, a univariate or multivariate polynomial * in vars. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder algebraicExtension(String var, String expr) { String[] variables = GenPolynomialTokenizer.variableList(var); if (variables.length < 1) { variables = GenPolynomialTokenizer.expressionVariables(expr); if (variables.length < 1) { throw new IllegalArgumentException("no variables in '" + var + "' and '" + expr + "'"); } } GenPolynomialRing pfac = new GenPolynomialRing(factory, variables); if (variables.length == 1) { // simple extension GenPolynomial gen = pfac.parse(expr); AlgebraicNumberRing afac = new AlgebraicNumberRing(gen); RingFactory base = (RingFactory) afac; return new ExtensionFieldBuilder(base); } GenPolynomialTokenizer pt = new GenPolynomialTokenizer(pfac, new StringReader(expr)); List gen = null; try { gen = pt.nextPolynomialList(); } catch (IOException e) { // should not happen throw new IllegalArgumentException(e); } Ideal agen = new Ideal(pfac, gen); if (agen.isONE()) { throw new IllegalArgumentException("ideal is 1: " + expr); } if (agen.isZERO()) { // transcendent extension QuotientRing qfac = new QuotientRing(pfac); RingFactory base = (RingFactory) qfac; return new ExtensionFieldBuilder(base); } // check if agen is prime? ResidueRing afac = new ResidueRing(agen); RingFactory base = (RingFactory) afac; return new ExtensionFieldBuilder(base); } /** * Real algebraic field extension. * @param var name for the algebraic generator. * @param expr generating expression, a univariate polynomial in var. * @param root isolating interval for a real root. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder realAlgebraicExtension(String var, String expr, String root) { String[] variables = new String[] { var }; RingElem one = (RingElem) factory.getONE(); if (!(one instanceof Rational)) { throw new IllegalArgumentException("base field not instance of Rational"); } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing pfac = new GenPolynomialRing(factory, to, variables); GenPolynomial gen = pfac.parse(expr); RingFactory cf = pfac.coFac; Interval iv = RootUtil.parseInterval(cf, root); //System.out.println("iv = " + iv); RealAlgebraicRing rfac = new RealAlgebraicRing(gen, iv); RingFactory base = (RingFactory) rfac; return new ExtensionFieldBuilder(base); } /** * Complex algebraic field extension. * @param var name for the algebraic generator. * @param expr generating expression, a univariate polynomial in var. * @param root isolating rectangle for a complex root. */ @SuppressWarnings("unchecked") public ExtensionFieldBuilder complexAlgebraicExtension(String var, String expr, String root) { String[] variables = new String[] { var }; RingElem one = (RingElem) factory.getONE(); if (!(one instanceof Complex)) { throw new IllegalArgumentException("base field not instance of Complex"); } GenPolynomialRing pfac = new GenPolynomialRing(factory, variables); //System.out.println("pfac = " + pfac); GenPolynomial gen = pfac.parse(expr); //System.out.println("gen = " + gen); RingFactory cf = pfac.coFac; Rectangle rt = RootUtil.parseRectangle(cf, root); //System.out.println("rt = " + rt); ComplexAlgebraicRing rfac = new ComplexAlgebraicRing(gen, rt); RingFactory base = (RingFactory) rfac; return new ExtensionFieldBuilder(base); } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(" "); s.append(factory.toString()); s.append(" "); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case StringBuffer s = new StringBuffer(" "); s.append(factory.toScript()); s.append(" "); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/FactorAlgebraicPrim.java000066400000000000000000000154421445075545500266730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.FactorAbsolute; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Squarefree; import edu.jas.ufd.SquarefreeFactory; /** * Algebraic number coefficients factorization algorithms. This class * implements factorization methods for polynomials over algebraic * numbers over rational numbers or over (prime) modular integers. The * algorithm uses zero dimensional ideal prime decomposition. * @author Heinz Kredel * @param coefficient type */ public class FactorAlgebraicPrim> extends FactorAbsolute> { //FactorAbstract> private static final Logger logger = LogManager.getLogger(FactorAlgebraicPrim.class); //private static final boolean debug = logger.isInfoEnabled(); /** * Factorization engine for base coefficients. */ public final FactorAbstract factorCoeff; /** * No argument constructor. Note: can't use this constructor. */ protected FactorAlgebraicPrim() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac algebraic number factory. */ public FactorAlgebraicPrim(AlgebraicNumberRing fac) { this(fac, FactorFactory. getImplementation(fac.ring.coFac)); } /** * Constructor. * @param fac algebraic number factory. * @param factorCoeff factorization engine for polynomials over base * coefficients. */ public FactorAlgebraicPrim(AlgebraicNumberRing fac, FactorAbstract factorCoeff) { super(fac); this.factorCoeff = factorCoeff; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<AlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> baseFactorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // Q(alpha)[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; AlgebraicNumber ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); if (logger.isDebugEnabled()) { Squarefree> sqengine = SquarefreeFactory .> getImplementation(afac); if (!sqengine.isSquarefree(P)) { throw new RuntimeException("P not squarefree: " + sqengine.squarefreeFactors(P)); } GenPolynomial modu = afac.modul; if (!factorCoeff.isIrreducible(modu)) { throw new RuntimeException("modul not irreducible: " + factorCoeff.factors(modu)); } System.out.println("P squarefree and modul irreducible via ideal decomposition"); //GreatestCommonDivisor> aengine //= GCDFactory.> getProxy(afac); // = new GreatestCommonDivisorSimple>( /*cfac.coFac*/ ); } GenPolynomial agen = afac.modul; GenPolynomialRing cfac = afac.ring; GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, pfac); TermOrder to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[2]; vars[0] = cfac.getVars()[0]; vars[1] = rfac.getVars()[0]; GenPolynomialRing dfac = new GenPolynomialRing(cfac.coFac, to, vars); // transform minimal polynomial to bi-variate polynomial GenPolynomial Ad = agen.extend(dfac, 0, 0L); // transform to bi-variate polynomial GenPolynomial> Pc = PolyUtil. fromAlgebraicCoefficients(rfac, P); //System.out.println("Pc = " + Pc.toScript()); GenPolynomial Pd = PolyUtil. distribute(dfac, Pc); //System.out.println("Ad = " + Ad.toScript()); //System.out.println("Pd = " + Pd.toScript()); List> id = new ArrayList>(2); id.add(Ad); id.add(Pd); Ideal I = new Ideal(dfac, id); List> Iul = I.zeroDimPrimeDecomposition(); //System.out.println("prime decomp = " + Iul); if (Iul.size() == 1) { factors.add(P); return factors; } GenPolynomial> f = pfac.getONE(); for (IdealWithUniv Iu : Iul) { List> pl = Iu.ideal.getList(); GenPolynomial ag = PolyUtil. selectWithVariable(pl, 1); GenPolynomial pg = PolyUtil. selectWithVariable(pl, 0); //System.out.println("ag = " + ag.toScript()); //System.out.println("pg = " + pg.toScript()); if (ag.equals(Ad)) { //System.out.println("found factor --------------------"); GenPolynomial> pgr = PolyUtil. recursive(rfac, pg); GenPolynomial> pga = PolyUtil. convertRecursiveToAlgebraicCoefficients( pfac, pgr); //System.out.println("pga = " + pga.toScript()); f = f.multiply(pga); factors.add(pga); } else { logger.warn("algebraic number mismatch: ag = {}, expected Ad = {}", ag, Ad); } } f = f.subtract(P); //System.out.println("f = " + f.toScript()); if (!f.isZERO()) { throw new RuntimeException("no factorization: " + f + ", factors = " + factors); } return factors; //return new edu.jas.ufd.FactorAlgebraic(afac).baseFactorsSquarefree(P); } } java-algebra-system-2.7.200/src/edu/jas/application/FactorFactory.java000066400000000000000000000204131445075545500255730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomialRing; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.RealAlgebraicRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.FactorAlgebraic; import edu.jas.ufd.FactorComplex; import edu.jas.ufd.FactorQuotient; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import edu.jas.ufdroot.FactorRealAlgebraic; /** * Factorization algorithms factory. Select appropriate factorization engine * based on the coefficient types. *

* Usage: To create objects that implement the Factorization * interface use the FactorFactory. It will select an appropriate * implementation based on the types of polynomial coefficients C. To obtain an * implementation use getImplementation(), it returns an object of * a class which extends the FactorAbstract class which implements * the Factorization interface. * *

 * Factorization<CT> engine;
 * engine = FactorFactory.<CT> getImplementation(cofac);
 * c = engine.factors(a);
 * 
*

* For example, if the coefficient type is BigInteger, the usage looks like * *

 * BigInteger cofac = new BigInteger();
 * Factorization<BigInteger> engine;
 * engine = FactorFactory.getImplementation(cofac);
 * Sm = engine.factors(poly);
 * 
* * @author Heinz Kredel * * @see edu.jas.ufd.Factorization#factors(edu.jas.poly.GenPolynomial P) * @see edu.jas.ufd.FactorFactory#getImplementation(edu.jas.structure.RingFactory * P) */ public class FactorFactory extends edu.jas.ufd.FactorFactory { private static final Logger logger = LogManager.getLogger(FactorFactory.class); /** * Protected factory constructor. */ protected FactorFactory() { } /** * Determine suitable implementation of factorization algorithms, case * AlgebraicNumber<C>. * @param fac AlgebraicNumberRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract> getImplementation( AlgebraicNumberRing fac) { return new FactorAlgebraic(fac, FactorFactory. getImplementation(fac.ring.coFac)); } /** * Determine suitable implementation of factorization algorithms, case * Complex<C>. * @param fac ComplexRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract> getImplementation( ComplexRing fac) { return new FactorComplex(fac); } /** * Determine suitable implementation of factorization algorithms, case * Quotient<C>. * @param fac QuotientRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract> getImplementation( QuotientRing fac) { return new FactorQuotient(fac, FactorFactory. getImplementation(fac.ring.coFac)); } /** * Determine suitable implementation of factorization algorithms, case * recursive GenPolynomial<C>. Use recursiveFactors(). * @param fac GenPolynomialRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract getImplementation(GenPolynomialRing fac) { return getImplementation(fac.coFac); } /** * Determine suitable implementation of factorization algorithms, case * RealAlgebraicNumber<C>. * @param fac RealAlgebraicRing<C>. * @param coefficient type, e.g. BigRational. * @return factorization algorithm implementation. */ public static & Rational> FactorAbstract> getImplementation( RealAlgebraicRing fac) { return new FactorRealAlgebraic(fac, FactorFactory.> getImplementation(fac.algebraic)); } /** * Determine suitable implementation of factorization algorithms, case * RealAlgebraicNumber<C>. * @param fac RealAlgebraicRing<C>. * @param coefficient type, e.g. BigRational. * @return factorization algorithm implementation. */ @SuppressWarnings("unchecked") public static & Rational> FactorAbstract> getImplementation( edu.jas.application.RealAlgebraicRing fac) { edu.jas.root.RealAlgebraicRing rar = (edu.jas.root.RealAlgebraicRing) (Object) fac.realRing; return new FactorRealReal(fac, FactorFactory.> getImplementation(rar)); } /** * Determine suitable implementation of factorization algorithms, other * cases. * @param coefficient type * @param fac RingFactory<C>. * @return factorization algorithm implementation. */ @SuppressWarnings("unchecked") public static > FactorAbstract getImplementation(RingFactory fac) { logger.info("app factor factory = {}", fac.getClass().getName()); FactorAbstract/*raw type*/ ufd = null; edu.jas.application.RealAlgebraicRing rrfac = null; RealAlgebraicRing rfac = null; AlgebraicNumberRing afac = null; ComplexRing cfac = null; QuotientRing qfac = null; GenPolynomialRing pfac = null; Object ofac = fac; if (ofac instanceof edu.jas.application.RealAlgebraicRing) { //System.out.println("rrfac_o = " + ofac); rrfac = (edu.jas.application.RealAlgebraicRing) ofac; //ofac = rrfac.realRing; ufd = new FactorRealReal/*raw */(rrfac, FactorFactory. getImplementation( rrfac.realRing)); } else if (ofac instanceof edu.jas.root.RealAlgebraicRing) { //System.out.println("rfac_o = " + ofac); rfac = (edu.jas.root.RealAlgebraicRing) ofac; //ofac = rfac.algebraic; ufd = new FactorRealAlgebraic/*raw */(rfac, FactorFactory.> getImplementation(rfac.algebraic)); } else if (ofac instanceof ComplexRing) { cfac = (ComplexRing) ofac; afac = cfac.algebraicRing(); ufd = new FactorComplex(cfac, FactorFactory. getImplementation(afac)); } else if (ofac instanceof AlgebraicNumberRing) { //System.out.println("afac_o = " + ofac); afac = (AlgebraicNumberRing) ofac; //ofac = afac.ring.coFac; ufd = new FactorAlgebraic/*raw */(afac, FactorFactory. getImplementation(afac.ring.coFac)); } else if (ofac instanceof QuotientRing) { //System.out.println("qfac_o = " + ofac); qfac = (QuotientRing) ofac; ufd = new FactorQuotient/*raw */(qfac, FactorFactory. getImplementation(qfac.ring.coFac)); } else if (ofac instanceof GenPolynomialRing) { //System.out.println("qfac_o = " + ofac); pfac = (GenPolynomialRing) ofac; ufd = getImplementation(pfac.coFac); } else { //System.out.println("no fac = " + fac.getClass().getName()); ufd = edu.jas.ufd.FactorFactory.getImplementation(fac); //return (FactorAbstract) ufd; } //logger.info("implementation = {}", ufd); return (FactorAbstract) ufd; } } java-algebra-system-2.7.200/src/edu/jas/application/FactorRealReal.java000066400000000000000000000107171445075545500256610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.Rational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.FactorAbstract; /** * Real algebraic number coefficients factorization algorithms. This class * implements factorization methods for polynomials over bi-variate real * algebraic numbers from package * *
 * edu.jas.application
 * 
* * . * @param coefficient type * @author Heinz Kredel */ public class FactorRealReal & Rational> extends FactorAbstract> { //TODO: absolute factorization would mean factorization to linear and quadratic factors //FactorAbsolute> //FactorAbstract> private static final Logger logger = LogManager.getLogger(FactorRealReal.class); private static final boolean debug = logger.isInfoEnabled(); /** * Factorization engine for base coefficients. */ public final FactorAbstract> factorAlgebraic; /** * No argument constructor. Note: can't use this constructor. */ protected FactorRealReal() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac algebraic number factory. */ @SuppressWarnings("unchecked") public FactorRealReal(RealAlgebraicRing fac) { // ignore recursion, as it is handled in FactorRealAlgebraic: this(fac, FactorFactory.> getImplementation( (edu.jas.root.RealAlgebraicRing) (Object) fac.realRing)); } /** * Constructor. * @param fac algebraic number factory. * @param factorAlgebraic factorization engine for polynomials over base * coefficients. */ public FactorRealReal(RealAlgebraicRing fac, FactorAbstract> factorAlgebraic) { super(fac); this.factorAlgebraic = factorAlgebraic; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<RealAlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override @SuppressWarnings("unchecked") public List>> baseFactorsSquarefree( GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // Q(alpha)[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } RealAlgebraicRing rere = (RealAlgebraicRing) pfac.coFac; edu.jas.root.RealAlgebraicRing rfac = (edu.jas.root.RealAlgebraicRing) (Object) rere.realRing; RealAlgebraicNumber ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); GenPolynomialRing> arfac = new GenPolynomialRing>( rfac, pfac); GenPolynomial> A = PolyUtilApp . realAlgFromRealCoefficients(arfac, P); // factor A: List>> afactors = factorAlgebraic .baseFactorsSquarefree(A); for (GenPolynomial> a : afactors) { GenPolynomial> p = PolyUtilApp. realFromRealAlgCoefficients(pfac, a); factors.add(p); } if (debug) { logger.info("rafactors = {}", factors); } return factors; } } java-algebra-system-2.7.200/src/edu/jas/application/GBAlgorithmBuilder.java000066400000000000000000000501511445075545500264750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.GBOptimized; import edu.jas.gb.GBProxy; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseArriSigSeqIter; import edu.jas.gb.GroebnerBaseF5zSigSeqIter; import edu.jas.gb.GroebnerBaseGGVSigSeqIter; import edu.jas.gb.GroebnerBaseParIter; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeqIter; import edu.jas.gb.OrderedMinPairlist; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.PairList; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.GroebnerBaseFGLM; import edu.jas.gbufd.GroebnerBasePseudoParallel; import edu.jas.gbufd.GroebnerBaseQuotient; import edu.jas.gbufd.GroebnerBaseRational; import edu.jas.gbufd.GroebnerBaseWalk; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Builder for commutative Gröbner bases algorithm implementations. *

* Usage: To create objects that implement the GroebnerBase * interface one can use the GBFactory or this * GBAlgorithmBuilder. This class will select and compose an * appropriate implementation based on the types of polynomial coefficients C * and the desired properties. To build an implementation start with the static * method polynomialRing() to define the polynomial ring. Then * continue to construct the algorithm with the methods *

    *
  • optimize() or optimize(boolean) for term order * (variable order) optimization (true for return of permuted polynomials),
  • *
  • normalPairlist() (default), syzygyPairlist() or * simplePairlist() for pair-list selection strategies,
  • *
  • fractionFree() for clearing denominators and computing with * pseudo reduction,
  • *
  • graded() for using the FGLM algorithm to first compute a * Gröbner base with respect to a graded term order and then constructing a * Gröbner base wrt. a lexicographical term order,
  • *
  • walk() for using the Gröbner walk algorithm to first * compute a Gröbner base with respect to a graded term order and then * constructing a Gröbner base wrt. a lexicographical term order,
  • *
  • iterated() for using the iterative GB algorithm to compute a * Gröbner base adding one polynomial after another,
  • *
  • F5(), GGV() and Arri() for using * the respective iterative signature based GB algorithm (over field * coefficients) to compute a Gröbner base adding one polynomial after * another,
  • *
  • parallel() additionally compute a Gröbner base over a * field or integral domain in parallel,
  • *
  • euclideanDomain() for computing a e-Gröbner base,
  • *
  • domainAlgorithm(Algo) for computing a d- or e-Gröbner * base,
  • *
*

* Finally call the method build() to obtain an implementation of * class GroebnerBaseAbstract. For example * *

 * GenPolynomialRing<C> pf = new GenPolynomialRing<C>(cofac, vars);
 * GroebnerBaseAbstract<C> engine;
 * engine = GBAlgorithmBuilder.<C> polynomialRing(pf).fractionFree().parallel().optimize().build();
 * c = engine.GB(A);
 * 
*

* For example, if the coefficient type is BigRational, the usage looks like * *

 * GenPolynomialRing<BigRational> pf = new GenPolynomialRing<BigRational>(cofac, vars);
 * GroebnerBaseAbstract<BigRational> engine;
 * engine = GBAlgorithmBuilder.<BigRational> polynomialRing(pf).fractionFree().parallel().optimize().build();
 * c = engine.GB(A);
 * 
* * Note: Not all combinations are meanigful * * @author Heinz Kredel * * @see edu.jas.gb.GroebnerBase * @see edu.jas.gbufd.GBFactory */ public class GBAlgorithmBuilder> implements Serializable { private static final Logger logger = LogManager.getLogger(GBAlgorithmBuilder.class); /** * The current GB algorithm implementation. */ private GroebnerBaseAbstract algo; /** * The current polynomial ring. */ public final GenPolynomialRing ring; /** * Requested pairlist strategy. */ public final PairList strategy; /** * Constructor not for use. */ protected GBAlgorithmBuilder() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param ring the polynomial ring. */ public GBAlgorithmBuilder(GenPolynomialRing ring) { this(ring, null); } /** * Constructor. * @param ring the polynomial ring. * @param algo already determined algorithm. */ public GBAlgorithmBuilder(GenPolynomialRing ring, GroebnerBaseAbstract algo) { this(ring, algo, null); } /** * Constructor. * @param ring the polynomial ring. * @param algo already determined algorithm. * @param strategy pairlist strategy. */ public GBAlgorithmBuilder(GenPolynomialRing ring, GroebnerBaseAbstract algo, PairList strategy) { if (ring == null) { throw new IllegalArgumentException("ring may not be null"); } this.ring = ring; if (strategy == null) { strategy = new OrderedPairlist(); } else { if (algo == null) { // or overwrite? algo = GBFactory. getImplementation(ring.coFac, strategy); } } this.algo = algo; // null accepted this.strategy = strategy; } /** * Build the GB algorithm implementation. * @return GB algorithm implementation as GroebnerBaseAbstract object. */ public GroebnerBaseAbstract build() { if (algo == null) { if (strategy == null) { // should not happen algo = GBFactory. getImplementation(ring.coFac); } else { algo = GBFactory. getImplementation(ring.coFac, strategy); } } return algo; } /** * Define polynomial ring. * @param fac the commutative polynomial ring. * @return GBAlgorithmBuilder object. */ public static > GBAlgorithmBuilder polynomialRing(GenPolynomialRing fac) { return new GBAlgorithmBuilder(fac); } /** * Select syzygy critical pair-list strategy. Gebauer and Möller * algorithm. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder syzygyPairlist() { return new GBAlgorithmBuilder(ring, algo, new OrderedSyzPairlist()); } /** * Select normal critical pair-list strategy. Buchberger, Winkler and Kredel * algorithm. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder normalPairlist() { return new GBAlgorithmBuilder(ring, algo, new OrderedPairlist()); } /** * Select simple critical pair-list strategy. Original Buchberger algorithm. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder simplePairlist() { return new GBAlgorithmBuilder(ring, algo, new OrderedMinPairlist()); } /** * Request term order optimization. Call optimize(true) for return of * permuted polynomials. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder optimize() { return optimize(true); } /** * Request term order optimization. * @param rP true for return of permuted polynomials, false for inverse * permuted polynomials and new GB computation. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder optimize(boolean rP) { if (algo == null) { algo = GBFactory. getImplementation(ring.coFac, strategy); } GroebnerBaseAbstract bb = new GBOptimized(algo, rP); return new GBAlgorithmBuilder(ring, bb, strategy); } /** * Request fraction free algorithm. For BigRational and Quotient * coefficients denominators are cleared and pseudo reduction is used. * @return GBAlgorithmBuilder object. */ @SuppressWarnings({ "cast", "unchecked" }) public GBAlgorithmBuilder fractionFree() { if (algo != null) { logger.warn("selected algorithm ignored: {}, use fractionFree before other requests", algo + ""); } if (((Object) ring.coFac) instanceof BigRational) { BigRational cf = (BigRational) (Object) ring.coFac; PairList sty = (PairList) strategy; GroebnerBaseAbstract bb = GBFactory.getImplementation(cf, GBFactory.Algo.ffgb, sty); GroebnerBaseAbstract cbb = (GroebnerBaseAbstract) (GroebnerBaseAbstract) bb; return new GBAlgorithmBuilder(ring, cbb, strategy); } if (((Object) ring.coFac) instanceof QuotientRing) { QuotientRing cf = (QuotientRing) (Object) ring.coFac; PairList> sty = (PairList) strategy; GroebnerBaseAbstract> bb = GBFactory. getImplementation(cf, GBFactory.Algo.ffgb, sty); GroebnerBaseAbstract cbb = (GroebnerBaseAbstract) (GroebnerBaseAbstract) bb; return new GBAlgorithmBuilder(ring, cbb, strategy); } logger.warn("no fraction free algorithm implemented for {}", ring); return this; } /** * Request e-GB algorithm. * @return GBAlgorithmBuilder object. */ public GBAlgorithmBuilder euclideanDomain() { return domainAlgorithm(GBFactory.Algo.egb); } /** * Request d-, e- or i-GB algorithm. * @param a algorithm from GBFactory.Algo. * @return GBAlgorithmBuilder object. */ @SuppressWarnings({ "cast", "unchecked" }) public GBAlgorithmBuilder domainAlgorithm(GBFactory.Algo a) { if (strategy != null) { logger.warn("strategy {} ignored for algorithm {}", strategy, a); } if (((Object) ring.coFac) instanceof BigInteger) { BigInteger cf = (BigInteger) (Object) ring.coFac; GroebnerBaseAbstract bb = GBFactory.getImplementation(cf, a); GroebnerBaseAbstract cbb = (GroebnerBaseAbstract) (GroebnerBaseAbstract) bb; return new GBAlgorithmBuilder(ring, cbb); } if (((Object) ring.coFac) instanceof GenPolynomial) { GenPolynomialRing cf = (GenPolynomialRing) (Object) ring.coFac; GroebnerBaseAbstract> bb = GBFactory. getImplementation(cf, a); GroebnerBaseAbstract cbb = (GroebnerBaseAbstract) (GroebnerBaseAbstract) bb; return new GBAlgorithmBuilder(ring, cbb); } logger.warn("no domain algorithm implemented for {}", ring); return this; } /** * Request parallel algorithm. Additionally run a parallel algorithm via * GBProxy. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder parallel() { return parallel(ComputerThreads.N_CPUS); } /** * Request parallel algorithm. Additionally run a parallel algorithm via * GBProxy. * @param threads number of threads requested. * @return GBAlgorithmBuilder object. */ @SuppressWarnings({ "cast", "unchecked" }) public GBAlgorithmBuilder parallel(int threads) { if (ComputerThreads.NO_THREADS) { logger.warn("parallel algorithms disabled"); return this; } if (algo == null) { algo = GBFactory. getImplementation(ring.coFac, strategy); } if (algo instanceof GroebnerBaseSeqIter) { // iterative requested GroebnerBaseAbstract bb; bb = (GroebnerBaseAbstract) new GroebnerBaseParIter(threads, strategy); GroebnerBaseAbstract pbb = new GBProxy(algo, bb); return new GBAlgorithmBuilder(ring, pbb, strategy); } else if (((RingFactory) ring.coFac) instanceof BigRational) { GroebnerBaseAbstract bb; if (algo instanceof GroebnerBaseRational) { // fraction free requested PairList pli; if (strategy instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist(); } else if (strategy instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist(); } else { pli = new OrderedPairlist(); } bb = (GroebnerBaseAbstract) new GroebnerBaseRational(threads, pli); } else { bb = (GroebnerBaseAbstract) new GroebnerBaseParallel(threads, strategy); } GroebnerBaseAbstract pbb = new GBProxy(algo, bb); return new GBAlgorithmBuilder(ring, pbb, strategy); } else if (((RingFactory) ring.coFac) instanceof QuotientRing) { GroebnerBaseAbstract bb; if (algo instanceof GroebnerBaseQuotient) { // fraction free requested PairList> pli; if (strategy instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist>(); } else if (strategy instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist>(); } else { pli = new OrderedPairlist>(); } QuotientRing fac = (QuotientRing) ring.coFac; bb = (GroebnerBaseAbstract) new GroebnerBaseQuotient(threads, fac, pli); // pl not possible } else { bb = (GroebnerBaseAbstract) new GroebnerBaseParallel(threads, strategy); } GroebnerBaseAbstract pbb = new GBProxy(algo, bb); return new GBAlgorithmBuilder(ring, pbb); } else if (ring.coFac.isField()) { GroebnerBaseAbstract bb = new GroebnerBaseParallel(threads, strategy); GroebnerBaseAbstract pbb = new GBProxy(algo, bb); return new GBAlgorithmBuilder(ring, pbb, strategy); } else if (ring.coFac.getONE() instanceof GcdRingElem) { GroebnerBaseAbstract bb = new GroebnerBasePseudoParallel(threads, ring.coFac, strategy); GroebnerBaseAbstract pbb = new GBProxy(algo, bb); return new GBAlgorithmBuilder(ring, pbb, strategy); } logger.warn("no parallel algorithm implemented for {}", ring); return this; } /** * Request FGLM algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder graded() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; if (algo == null) { bb = new GroebnerBaseFGLM(); } else { bb = new GroebnerBaseFGLM(algo); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no FGLM algorithm implemented for {}", ring); return this; } /** * Request Groebner walk algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder walk() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; if (algo == null) { bb = new GroebnerBaseWalk(); } else { bb = new GroebnerBaseWalk(algo); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no Groebner walk algorithm implemented for {}", ring); return this; } /** * Request iterated GB algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder iterated() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; bb = new GroebnerBaseSeqIter(strategy); if (algo != null) { logger.warn("algorithm {} ignored for {}", algo, bb); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no iterated GB algorithm implemented for {}", ring); return this; } /** * Request iterated F5 signature based GB algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder F5() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; bb = new GroebnerBaseF5zSigSeqIter(); if (algo != null) { logger.warn("algorithm {} ignored for {}", algo, bb); } if (strategy != null) { logger.warn("strategy {} ignored for {}", strategy, bb); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no iterated F5 GB algorithm implemented for {}", ring); return this; } /** * Request iterated GGV signature based GB algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder GGV() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; bb = new GroebnerBaseGGVSigSeqIter(); if (algo != null) { logger.warn("algorithm {} ignored for {}", algo, bb); } if (strategy != null) { logger.warn("strategy {} ignored for {}", strategy, bb); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no iterated GGV GB algorithm implemented for {}", ring); return this; } /** * Request iterated Arri signature based GB algorithm. * @return GBAlgorithmBuilder object. */ @SuppressWarnings("unchecked") public GBAlgorithmBuilder Arri() { if (ring.coFac.isField()) { GroebnerBaseAbstract bb; bb = new GroebnerBaseArriSigSeqIter(); if (algo != null) { logger.warn("algorithm {} ignored for {}", algo, bb); } if (strategy != null) { logger.warn("strategy {} ignored for {}", strategy, bb); } return new GBAlgorithmBuilder(ring, bb, strategy); } logger.warn("no iterated Arri GB algorithm implemented for {}", ring); return this; } /** * String representation of the GB algorithm implementation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(" "); if (algo != null) { s.append(algo.toString()); s.append(" for "); } s.append(ring.toString()); if (strategy != null) { s.append(" strategy="); s.append(strategy.toString()); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case StringBuffer s = new StringBuffer(" "); if (algo != null) { s.append(algo.toString()); // nonsense s.append(" "); } s.append(ring.toScript()); if (strategy != null) { s.append(",strategy="); s.append(strategy.toString()); } return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/GroebnerSystem.java000066400000000000000000000164461445075545500260100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.PolynomialList; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; /** * Container for a Groebner system. * It contains a list of colored systems and a * list of parametric polynomials representing the * corresponding comprehensive Groebner base. * @param coefficient type */ public class GroebnerSystem> { private static final Logger logger = LogManager.getLogger(GroebnerSystem.class); private static final boolean debug = logger.isDebugEnabled(); /** * List of colored systems. */ public final List> list; /** * List of conditions for this Groebner system. */ protected List> conds; /** * Comprehensive Groebner base for this Groebner system. */ protected PolynomialList> cgb; /** * Constructor for a Groebner system. * @param S a list of colored systems. */ public GroebnerSystem(List> S) { this.list = S; this.conds = null; this.cgb = null; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer("GroebnerSystem: \n"); boolean first = true; for (ColoredSystem cs : list) { if ( first ) { first = false; } else { sb.append("\n"); } sb.append( cs.toString() ); } sb.append("Conditions:\n"); first = true; for ( Condition cond : getConditions() ) { if ( first ) { first = false; } else { sb.append("\n"); } sb.append( cond.toString() ); } sb.append("\n"); if ( cgb == null ) { sb.append("Comprehensive Groebner Base not jet computed\n"); } else { sb.append("Comprehensive Groebner Base:\n"); first = true; for ( GenPolynomial> p : getCGB() ) { if ( first ) { first = false; } else { sb.append(",\n"); } sb.append( p.toString() ); } sb.append("\n"); } return sb.toString(); } /** * Get the Script representation. * @see edu.jas.structure.Element#toScript() */ public String toScript() { StringBuffer sb = new StringBuffer("GroebnerSystem: \n"); boolean first = true; for (ColoredSystem cs : list) { if ( first ) { first = false; } else { sb.append("\n"); } sb.append( cs.toScript() ); } sb.append("Conditions:\n"); first = true; for ( Condition cond : getConditions() ) { if ( first ) { first = false; } else { sb.append("\n"); } sb.append( cond.toScript() ); } sb.append("\n"); if ( cgb == null ) { sb.append("Comprehensive Groebner Base not jet computed\n"); } else { sb.append("Comprehensive Groebner Base:\n"); first = true; for ( GenPolynomial> p : getCGB() ) { if ( first ) { first = false; } else { sb.append(",\n"); } sb.append( p.toScript() ); } sb.append("\n"); } return sb.toString(); } /** * Is this Groebner system equal to other. * @param c other Groebner system. * @return true, if this is equal to other, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object c) { GroebnerSystem cs = null; try { cs = (GroebnerSystem) c; } catch (ClassCastException e) { return false; } if (cs == null) { return false; } boolean t = list.equals(cs.list); return t; } /** * Hash code for this colored system. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = list.hashCode(); return h; } /** * Check invariants. Check if all colored systems are determined and * all invariants are met. * @return true, if all invariants are met, else false. */ public boolean checkInvariant() { for (ColoredSystem s : list) { if (!s.checkInvariant()) { return false; } } return true; } /** * Is each colored system completely determined. * @return true, if each ColoredSystem is determined, else false. */ public boolean isDetermined() { for (ColoredSystem s : list) { if (!s.isDetermined()) { return false; } } return true; } /** * Get list of conditions determining this Groebner system. * @return list of determining conditions. */ public List> getConditions() { if ( conds != null ) { return conds; } List> cd = new ArrayList>( list.size() ); for (ColoredSystem cs : list) { cd.add(cs.condition); } conds = cd; return conds; } /** * Get comprehensive Groebner base. * @return the comprehensive Groebner base for this Groebner system. */ public List>> getCGB() { if ( cgb != null ) { return cgb.list; } // assure conditions are collected List> unused = getConditions(); if ( unused.isEmpty() ) { // use for findbugs logger.info("unused is empty"); } //System.out.println("unused "); // combine for CGB Set>> Gs = new HashSet>>(); for (ColoredSystem cs : list) { if (debug) { if (!cs.isDetermined()) { System.out.println("not determined, cs = " + cs); } if (!cs.checkInvariant()) { System.out.println("not invariant, cs = " + cs); } } for (ColorPolynomial p : cs.list) { GenPolynomial> f = p.getPolynomial(); Gs.add(f); } } List>> G = new ArrayList>>(Gs); GenPolynomialRing> ring = null; if ( G.size() > 0 ) { ring = G.get(0).ring; } cgb = new OrderedPolynomialList>(ring,G); return G; } } java-algebra-system-2.7.200/src/edu/jas/application/Ideal.java000066400000000000000000003174021445075545500240520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.ExtendedGB; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.Reduction; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.GroebnerBasePartial; import edu.jas.gbufd.PolyGBUtil; import edu.jas.gbufd.SyzygyAbstract; import edu.jas.gbufd.SyzygySeq; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OptimizedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderOptimization; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingFactory; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Ideal implements some methods for ideal arithmetic, for example intersection, * quotient and zero and positive dimensional ideal decomposition. * @author Heinz Kredel */ public class Ideal> implements Comparable>, Serializable { private static final Logger logger = LogManager.getLogger(Ideal.class); private static final boolean debug = logger.isDebugEnabled(); /** * The data structure is a PolynomialList. */ protected PolynomialList list; /** * Indicator if list is a Groebner Base. */ protected boolean isGB; /** * Indicator if test has been performed if this is a Groebner Base. */ protected boolean testGB; /** * Indicator if list has optimized term order. */ protected boolean isTopt; /** * Groebner base engine. */ protected final GroebnerBaseAbstract bb; /** * Reduction engine. */ protected final Reduction red; /** * Squarefree decomposition engine. */ protected final SquarefreeAbstract engine; /** * Constructor. * @param ring polynomial ring */ public Ideal(GenPolynomialRing ring) { this(ring, new ArrayList>()); } /** * Constructor. * @param ring polynomial ring * @param F list of polynomials */ public Ideal(GenPolynomialRing ring, List> F) { this(new PolynomialList(ring, F)); } /** * Constructor. * @param ring polynomial ring * @param F list of polynomials * @param gb true if F is known to be a Groebner Base, else false */ public Ideal(GenPolynomialRing ring, List> F, boolean gb) { this(new PolynomialList(ring, F), gb); } /** * Constructor. * @param ring polynomial ring * @param F list of polynomials * @param gb true if F is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false */ public Ideal(GenPolynomialRing ring, List> F, boolean gb, boolean topt) { this(new PolynomialList(ring, F), gb, topt); } /** * Constructor. * @param list polynomial list */ public Ideal(PolynomialList list) { this(list, false); } /** * Constructor. * @param list polynomial list * @param bb Groebner Base engine * @param red Reduction engine */ public Ideal(PolynomialList list, GroebnerBaseAbstract bb, Reduction red) { this(list, false, bb, red); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false */ public Ideal(PolynomialList list, boolean gb) { //this(list, gb, new GroebnerBaseSeqIter(new OrderedSyzPairlist()), new ReductionSeq() ); //this(list, gb, new GroebnerBaseSeq(new OrderedSyzPairlist()), new ReductionSeq() ); this(list, gb, GBFactory.getImplementation(list.ring.coFac)); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false */ public Ideal(PolynomialList list, boolean gb, boolean topt) { //this(list, gb, topt, new GroebnerBaseSeqIter(new OrderedSyzPairlist()), new ReductionSeq()); this(list, gb, topt, GBFactory.getImplementation(list.ring.coFac)); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine * @param red Reduction engine */ public Ideal(PolynomialList list, boolean gb, GroebnerBaseAbstract bb, Reduction red) { this(list, gb, false, bb, red); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine */ public Ideal(PolynomialList list, boolean gb, GroebnerBaseAbstract bb) { this(list, gb, false, bb, bb.red); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param bb Groebner Base engine */ public Ideal(PolynomialList list, boolean gb, boolean topt, GroebnerBaseAbstract bb) { this(list, gb, topt, bb, bb.red); } /** * Constructor. * @param list polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param bb Groebner Base engine * @param red Reduction engine */ public Ideal(PolynomialList list, boolean gb, boolean topt, GroebnerBaseAbstract bb, Reduction red) { if (list == null || list.list == null) { throw new IllegalArgumentException("list and list.list may not be null"); } this.list = list; this.isGB = gb; this.isTopt = topt; this.testGB = (gb ? true : false); // ?? this.bb = bb; this.red = red; this.engine = SquarefreeFactory. getImplementation(list.ring.coFac); } /** * Clone this. * @return a copy of this. */ public Ideal copy() { return new Ideal(list.copy(), isGB, isTopt, bb, red); } /** * Get the List of GenPolynomials. * @return list.list */ public List> getList() { return list.list; } /** * Get the GenPolynomialRing. * @return list.ring */ public GenPolynomialRing getRing() { return list.ring; } /** * Get the zero ideal. * @return ideal(0) */ public Ideal getZERO() { List> z = new ArrayList>(0); PolynomialList pl = new PolynomialList(getRing(), z); return new Ideal(pl, true, isTopt, bb, red); } /** * Get the one ideal. * @return ideal(1) */ public Ideal getONE() { List> one = new ArrayList>(1); one.add(list.ring.getONE()); PolynomialList pl = new PolynomialList(getRing(), one); return new Ideal(pl, true, isTopt, bb, red); } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { return list.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case return list.toScript(); } /** * Comparison with any other object. Note: If both ideals are not Groebner * Bases, then false may be returned even the ideals are equal. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof Ideal)) { logger.warn("equals no Ideal"); return false; } Ideal B = null; try { B = (Ideal) b; } catch (ClassCastException ignored) { return false; } //if ( isGB && B.isGB ) { // return list.equals( B.list ); requires also monic polys //} else { // compute GBs ? return this.contains(B) && B.contains(this); //} } /** * Ideal list comparison. * @param L other Ideal. * @return compareTo() of polynomial lists. */ public int compareTo(Ideal L) { return list.compareTo(L.list); } /** * Hash code for this ideal. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = list.hashCode(); if (isGB) { h = h << 1; } if (testGB) { h += 1; } return h; } /** * Test if ZERO ideal. * @return true, if this is the 0 ideal, else false */ public boolean isZERO() { return list.isZERO(); } /** * Test if ONE is contained in the ideal. To test for a proper ideal use * ! id.isONE(). * @return true, if this is the 1 ideal, else false */ public boolean isONE() { return list.isONE(); } /** * Optimize the term order. */ public void doToptimize() { if (isTopt) { return; } list = TermOrderOptimization. optimizeTermOrder(list); isTopt = true; if (isGB) { isGB = false; doGB(); } return; } /** * Test if this is a Groebner base. * @return true, if this is a Groebner base, else false */ public boolean isGB() { if (testGB) { return isGB; } logger.warn("isGB computing"); isGB = bb.isGB(getList()); testGB = true; return isGB; } /** * Do Groebner Base. compute the Groebner Base for this ideal. */ @SuppressWarnings("unchecked") public void doGB() { if (isGB && testGB) { return; } //logger.warn("GB computing"); List> G = getList(); logger.info("GB computing = {}", G); G = bb.GB(G); if (isTopt) { List perm = ((OptimizedPolynomialList) list).perm; list = new OptimizedPolynomialList(perm, getRing(), G); } else { list = new PolynomialList(getRing(), G); } isGB = true; testGB = true; return; } /** * Groebner Base. Get a Groebner Base for this ideal. * @return GB(this) */ public Ideal GB() { if (isGB) { return this; } doGB(); return this; } /** * Ideal containment. Test if B is contained in this ideal. Note: this is * eventually modified to become a Groebner Base. * @param B ideal * @return true, if B is contained in this, else false */ public boolean contains(Ideal B) { if (B == null || B.isZERO()) { return true; } return contains(B.getList()); } /** * Ideal containment. Test if b is contained in this ideal. Note: this is * eventually modified to become a Groebner Base. * @param b polynomial * @return true, if b is contained in this, else false */ public boolean contains(GenPolynomial b) { if (b == null || b.isZERO()) { return true; } if (this.isONE()) { return true; } if (this.isZERO()) { return false; } if (!isGB) { doGB(); } GenPolynomial z; z = red.normalform(getList(), b); if (z == null || z.isZERO()) { return true; } return false; } /** * Ideal containment. Test if each b in B is contained in this ideal. Note: * this is eventually modified to become a Groebner Base. * @param B list of polynomials * @return true, if each b in B is contained in this, else false */ public boolean contains(List> B) { if (B == null || B.size() == 0) { return true; } if (this.isONE()) { return true; } if (!isGB) { doGB(); } for (GenPolynomial b : B) { if (b == null) { continue; } GenPolynomial z = red.normalform(getList(), b); if (!z.isZERO()) { //System.out.println("contains nf(b) != 0: " + b); return false; } } return true; } /** * Summation. Generators for the sum of ideals. Note: if both ideals are * Groebner bases, a Groebner base is returned. * @param B ideal * @return ideal(this+B) */ public Ideal sum(Ideal B) { if (B == null || B.isZERO()) { return this; } if (this.isZERO()) { return B; } return sum(B.getList()); } /** * Summation. Generators for the sum of ideal and a polynomial. Note: if * this ideal is a Groebner base, a Groebner base is returned. * @param b polynomial * @return ideal(this+{b}) */ public Ideal sum(GenPolynomial b) { if (b == null || b.isZERO()) { return this; } int s = getList().size() + 1; List> c; c = new ArrayList>(s); c.addAll(getList()); c.add(b); Ideal I = new Ideal(getRing(), c, false); if (isGB) { I.doGB(); } return I; } /** * Summation. Generators for the sum of this ideal and a list of * polynomials. Note: if this ideal is a Groebner base, a Groebner base is * returned. * @param L list of polynomials * @return ideal(this+L) */ public Ideal sum(List> L) { if (L == null || L.isEmpty()) { return this; } int s = getList().size() + L.size(); List> c = new ArrayList>(s); c.addAll(getList()); c.addAll(L); Ideal I = new Ideal(getRing(), c, false); if (isGB) { I.doGB(); } return I; } /** * Product. Generators for the product of ideals. Note: if both ideals are * Groebner bases, a Groebner base is returned. * @param B ideal * @return ideal(this*B) */ public Ideal product(Ideal B) { if (B == null || B.isZERO()) { return B; } if (this.isZERO()) { return this; } int s = getList().size() * B.getList().size(); List> c; c = new ArrayList>(s); for (GenPolynomial p : getList()) { for (GenPolynomial q : B.getList()) { q = p.multiply(q); c.add(q); } } Ideal I = new Ideal(getRing(), c, false); if (isGB && B.isGB) { I.doGB(); } return I; } /** * Product. Generators for the product this ideal by a polynomial. Note: if * this ideal is a Groebner base, a Groebner base is returned. * @param b polynomial * @return ideal(this*b) */ public Ideal product(GenPolynomial b) { if (b == null || b.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } List> c; c = new ArrayList>(getList().size()); for (GenPolynomial p : getList()) { GenPolynomial q = p.multiply(b); c.add(q); } Ideal I = new Ideal(getRing(), c, false); if (isGB) { I.doGB(); } return I; } /** * Intersection. Generators for the intersection of ideals. Using an * iterative algorithm. * @param Bl list of ideals * @return ideal(cap_i B_i), a Groebner base */ public Ideal intersect(List> Bl) { if (Bl == null || Bl.size() == 0) { return getZERO(); } Ideal I = null; for (Ideal B : Bl) { if (I == null) { I = B; continue; } if (I.isONE()) { return I; } I = I.intersect(B); } return I; } /** * Intersection. Generators for the intersection of ideals. * @param B ideal * @return ideal(this \cap B), a Groebner base */ public Ideal intersect(Ideal B) { if (B == null || B.isZERO()) { // (0) return B; } if (this.isZERO()) { return this; } List> c = PolyGBUtil. intersect(getRing(), getList(), B.getList()); Ideal I = new Ideal(getRing(), c, true); return I; } /** * Intersection. Generators for the intersection of a ideal with a * polynomial ring. The polynomial ring of this ideal must be a contraction * of R and the TermOrder must be an elimination order. * @param R polynomial ring * @return ideal(this \cap R) */ public Ideal intersect(GenPolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } List> H = PolyUtil. intersect(R, getList()); return new Ideal(R, H, isGB, isTopt); } /** * Eliminate. Generators for the intersection of a ideal with a polynomial * ring. The polynomial rings must have variable names. * @param R polynomial ring * @return ideal(this \cap R) */ public Ideal eliminate(GenPolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } if (list.ring.equals(R)) { return this; } String[] ename = R.getVars(); Ideal I = eliminate(ename); return I.intersect(R); } /** * Eliminate. Preparation of generators for the intersection of a ideal with * a polynomial ring. * @param ename variables for the elimination ring. * @return ideal(this) in K[ename,{vars \ ename}]) */ public Ideal eliminate(String... ename) { //System.out.println("ename = " + Arrays.toString(ename)); if (ename == null) { throw new IllegalArgumentException("ename may not be null"); } String[] aname = getRing().getVars(); //System.out.println("aname = " + Arrays.toString(aname)); if (aname == null) { throw new IllegalArgumentException("aname may not be null"); } GroebnerBasePartial bbp = new GroebnerBasePartial(bb, null); String[] rname = GroebnerBasePartial.remainingVars(aname, ename); //System.out.println("rname = " + Arrays.toString(rname)); PolynomialList Pl = null; if (rname.length == 0) { if (Arrays.deepEquals(aname, ename)) { return this; } Pl = bbp.partialGB(getList(), ename); // normal GB } else { Pl = bbp.elimPartialGB(getList(), rname, ename); // reversed! } //System.out.println("Pl = " + Pl); logger.debug("elimination GB = {}", Pl); Ideal I = new Ideal(Pl, true); return I; } /** * Quotient. Generators for the ideal quotient. * @param h polynomial * @return ideal(this : h), a Groebner base */ public Ideal quotient(GenPolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } List> H; H = new ArrayList>(1); H.add(h); Ideal Hi = new Ideal(getRing(), H, true); Ideal I = this.intersect(Hi); List> Q; Q = new ArrayList>(I.getList().size()); for (GenPolynomial q : I.getList()) { q = q.divide(h); // remainder == 0 Q.add(q); } return new Ideal(getRing(), Q, true /*false?*/); } /** * Quotient. Generators for the ideal quotient. * @param H ideal * @return ideal(this : H), a Groebner base */ public Ideal quotient(Ideal H) { if (H == null) { // == (0) return this; } if (H.isZERO()) { return this; } if (this.isZERO()) { return this; } Ideal Q = null; for (GenPolynomial h : H.getList()) { Ideal Hi = this.quotient(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Infinite quotient. Generators for the infinite ideal quotient. * @param h polynomial * @return ideal(this : hs), a Groebner base */ public Ideal infiniteQuotientRab(GenPolynomial h) { if (h == null || h.isZERO()) { // == (0) return getONE(); } if (h.isONE()) { return this; } if (this.isZERO()) { return this; } Ideal I = this.GB(); // should be already List> a = I.getList(); List> c; c = new ArrayList>(a.size() + 1); GenPolynomialRing tfac = getRing().extend(1); // term order is also adjusted for (GenPolynomial p : a) { p = p.extend(tfac, 0, 0L); // p c.add(p); } GenPolynomial q = h.extend(tfac, 0, 1L); GenPolynomial r = tfac.getONE(); // h.extend( tfac, 0, 0L ); GenPolynomial hs = q.subtract(r); // 1 - t*h // (1-t)*h c.add(hs); logger.warn("infiniteQuotientRab computing GB "); List> g = bb.GB(c); if (debug) { logger.info("infiniteQuotientRab = {}, c = {}", tfac, c); logger.info("infiniteQuotientRab GB = {}", g); } Ideal E = new Ideal(tfac, g, true); Ideal Is = E.intersect(getRing()); return Is; } /** * Infinite quotient exponent. * @param h polynomial * @param Q quotient this : h^\infinity * @return s with Q = this : hs */ public int infiniteQuotientExponent(GenPolynomial h, Ideal Q) { int s = 0; if (h == null) { // == 0 return s; } if (h.isZERO() || h.isONE()) { return s; } if (this.isZERO() || this.isONE()) { return s; } //see below: if (this.contains(Q)) { // return s; //} GenPolynomial p = getRing().getONE(); for (GenPolynomial q : Q.getList()) { if (this.contains(q)) { continue; } //System.out.println("q = " + q + ", p = " + p + ", s = " + s); GenPolynomial qp = q.multiply(p); while (!this.contains(qp)) { p = p.multiply(h); s++; qp = q.multiply(p); } } return s; } /** * Infinite quotient. Generators for the infinite ideal quotient. * @param h polynomial * @return ideal(this : hs), a Groebner base */ public Ideal infiniteQuotient(GenPolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } int s = 0; Ideal I = this.GB(); // should be already GenPolynomial hs = h; Ideal Is = I; boolean eq = false; while (!eq) { Is = I.quotient(hs); Is = Is.GB(); // should be already logger.info("infiniteQuotient s = {}", s); eq = Is.contains(I); // I.contains(Is) always if (!eq) { I = Is; s++; // hs = hs.multiply( h ); } } return Is; } /** * Radical membership test. * @param h polynomial * @return true if h is contained in the radical of ideal(this), else false. */ public boolean isRadicalMember(GenPolynomial h) { if (h == null) { // == (0) return true; } if (h.isZERO()) { return true; } if (this.isZERO()) { return true; } Ideal x = infiniteQuotientRab(h); if (debug) { logger.debug("infiniteQuotientRab = {}", x); } return x.isONE(); } /** * Infinite quotient. Generators for the infinite ideal quotient. * @param h polynomial * @return ideal(this : hs), a Groebner base */ public Ideal infiniteQuotientOld(GenPolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } int s = 0; Ideal I = this.GB(); // should be already GenPolynomial hs = h; boolean eq = false; while (!eq) { Ideal Is = I.quotient(hs); Is = Is.GB(); // should be already logger.debug("infiniteQuotient s = {}", s); eq = Is.contains(I); // I.contains(Is) always if (!eq) { I = Is; s++; hs = hs.multiply(h); } } return I; } /** * Infinite Quotient. Generators for the ideal infinite quotient. * @param H ideal * @return ideal(this : Hs), a Groebner base */ public Ideal infiniteQuotient(Ideal H) { if (H == null) { // == (0) return this; } if (H.isZERO()) { return this; } if (this.isZERO()) { return this; } Ideal Q = null; for (GenPolynomial h : H.getList()) { Ideal Hi = this.infiniteQuotient(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Infinite Quotient. Generators for the ideal infinite quotient. * @param H ideal * @return ideal(this : Hs), a Groebner base */ public Ideal infiniteQuotientRab(Ideal H) { if (H == null) { // == (0) return this; } if (H.isZERO()) { return this; } if (this.isZERO()) { return this; } Ideal Q = null; for (GenPolynomial h : H.getList()) { Ideal Hi = this.infiniteQuotientRab(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Power. Generators for the power of this ideal. Note: if this ideal is a * Groebner base, a Groebner base is returned. * @param d integer * @return ideal(this^d) */ public Ideal power(int d) { if (d <= 0) { return getONE(); } if (this.isZERO() || this.isONE()) { return this; } Ideal c = this; for (int i = 1; i < d; i++) { c = c.product(this); } return c; } /** * Normalform for element. * @param h polynomial * @return normalform of h with respect to this */ public GenPolynomial normalform(GenPolynomial h) { if (h == null) { return h; } if (h.isZERO()) { return h; } if (this.isZERO()) { return h; } GenPolynomial r; r = red.normalform(list.list, h); return r; } /** * Normalform for list of elements. * @param L polynomial list * @return list of normalforms of the elements of L with respect to this */ public List> normalform(List> L) { if (L == null) { return L; } if (L.size() == 0) { return L; } if (this.isZERO()) { return L; } List> M = new ArrayList>(L.size()); for (GenPolynomial h : L) { GenPolynomial r = normalform(h); if (r != null && !r.isZERO()) { M.add(r); } } return M; } /** * Annihilator for element modulo this ideal. * @param h polynomial * @return annihilator of h with respect to this */ public Ideal annihilator(GenPolynomial h) { if (h == null || h.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } doGB(); List> F = new ArrayList>(1 + getList().size()); F.add(h); F.addAll(getList()); //System.out.println("F = " + F); SyzygyAbstract syz = new SyzygySeq(getRing().coFac); List>> S = syz.zeroRelationsArbitrary(F); //System.out.println("S = " + S); List> gen = new ArrayList>(S.size()); for (List> rel : S) { if (rel == null || rel.isEmpty()) { continue; } GenPolynomial p = rel.get(0); if (p == null || p.isZERO()) { continue; } gen.add(p); } Ideal ann = new Ideal(getRing(), gen); //System.out.println("ann = " + ann); return ann; } /** * Test for annihilator of element modulo this ideal. * @param h polynomial * @param A ideal * @return true, if A is the annihilator of h with respect to this */ public boolean isAnnihilator(GenPolynomial h, Ideal A) { Ideal B = A.product(h); return contains(B); } /** * Annihilator for ideal modulo this ideal. * @param H ideal * @return annihilator of H with respect to this */ public Ideal annihilator(Ideal H) { if (H == null || H.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } Ideal ann = null; for (GenPolynomial h : H.getList()) { Ideal Hi = this.annihilator(h); if (ann == null) { ann = Hi; } else { ann = ann.intersect(Hi); } } return ann; } /** * Test for annihilator of ideal modulo this ideal. * @param H ideal * @param A ideal * @return true, if A is the annihilator of H with respect to this */ public boolean isAnnihilator(Ideal H, Ideal A) { Ideal B = A.product(H); return contains(B); } /** * Inverse for element modulo this ideal. * @param h polynomial * @return inverse of h with respect to this, if defined */ public GenPolynomial inverse(GenPolynomial h) { if (h == null || h.isZERO()) { throw new NotInvertibleException("zero not invertible"); } if (this.isZERO()) { throw new NotInvertibleException("zero ideal"); } if (h.isUnit()) { return h.inverse(); } doGB(); List> F = new ArrayList>(1 + list.list.size()); F.add(h); F.addAll(list.list); //System.out.println("F = " + F); ExtendedGB x = bb.extGB(F); List> G = x.G; //System.out.println("G = " + G); GenPolynomial one = null; int i = -1; for (GenPolynomial p : G) { i++; if (p == null) { continue; } if (p.isUnit()) { one = p; break; } } if (one == null) { throw new NotInvertibleException(" h = " + h); } List> row = x.G2F.get(i); // != -1 GenPolynomial g = row.get(0); if (g == null || g.isZERO()) { throw new NotInvertibleException(" h = " + h); } // adjust g to get g*h == 1 GenPolynomial f = g.multiply(h); GenPolynomial k = red.normalform(list.list, f); if (!k.isONE()) { C lbc = k.leadingBaseCoefficient(); lbc = lbc.inverse(); g = g.multiply(lbc); } if (debug) { //logger.info("inv G = {}", G); //logger.info("inv G2F = {}", x.G2F); //logger.info("inv row {} = {}", i, row); //logger.info("inv h = {}", h); //logger.info("inv g = {}", g); //logger.info("inv f = {}", f); f = g.multiply(h); k = red.normalform(list.list, f); logger.debug("inv k = {}", k); if (!k.isUnit()) { throw new NotInvertibleException(" k = " + k); } } return g; } /** * Test if element is a unit modulo this ideal. * @param h polynomial * @return true if h is a unit with respect to this, else false */ public boolean isUnit(GenPolynomial h) { if (h == null || h.isZERO()) { return false; } if (this.isZERO()) { return false; } List> F = new ArrayList>(1 + list.list.size()); F.add(h); F.addAll(list.list); List> G = bb.GB(F); for (GenPolynomial p : G) { if (p == null) { continue; } if (p.isUnit()) { return true; } } return false; } /** * Radical approximation. Squarefree generators for the ideal. * @return squarefree(this), a Groebner base */ public Ideal squarefree() { if (this.isZERO()) { return this; } Ideal R = this; Ideal Rp = null; List> li, ri; while (true) { li = R.getList(); ri = new ArrayList>(li); //.size() ); for (GenPolynomial h : li) { GenPolynomial r = engine.squarefreePart(h); ri.add(r); } Rp = new Ideal(R.getRing(), ri, false); Rp.doGB(); if (R.equals(Rp)) { break; } R = Rp; } return R; } /** * Ideal common zero test. * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest() { if (this.isZERO()) { return 1; } if (!isGB) { doGB(); } if (this.isONE()) { return -1; } return bb.commonZeroTest(getList()); } /** * Test if this ideal is maximal. * @return true, if this is certainly maximal and not one, else false. */ public boolean isMaximal() { if (commonZeroTest() != 0) { return false; } long dm = 1L; for (Long d : univariateDegrees()) { if (d > 1L) { dm = d; } } if (dm == 1L) { return true; } // eventually prime decomposition of zero dimensional ideal if (list.ring.tord.getEvord() != TermOrder.INVLEX) { // skip test(?) logger.warn("TermOrder {} != INVLEX, isMaximal prime depomposition skipped", list.ring.tord); return false; } List> pdec = zeroDimPrimeDecompositionFE(); if (pdec.size() != 1) { // not prime return false; } return true; } /** * Univariate head term degrees. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees() { List ud = new ArrayList(); if (this.isZERO()) { return ud; } if (!isGB) { doGB(); } if (this.isONE()) { return ud; } return bb.univariateDegrees(getList()); } /** * Ideal dimension. * @return a dimension container (dim,maxIndep,list(maxIndep),vars). */ public Dimension dimension() { int t = commonZeroTest(); Set S = new HashSet(); Set> M = new HashSet>(); if (t <= 0) { return new Dimension(t, S, M, this.list.ring.getVars()); } int d = 0; Set U = new HashSet(); for (int i = 0; i < this.list.ring.nvar; i++) { U.add(i); } M = dimension(S, U, M); for (Set m : M) { int dp = m.size(); if (dp > d) { d = dp; S = m; } } return new Dimension(d, S, M, this.list.ring.getVars()); } /** * Ideal dimension. * @param S is a set of independent variables. * @param U is a set of variables of unknown status. * @param M is a list of maximal sets of independent variables. * @return a list of maximal sets of independent variables, eventually * containing S. */ protected Set> dimension(Set S, Set U, Set> M) { Set> MP = M; Set UP = new HashSet(U); for (Integer j : U) { UP.remove(j); Set SP = new HashSet(S); SP.add(j); if (!containsHT(SP, getList())) { MP = dimension(SP, UP, MP); } } boolean contained = false; for (Set m : MP) { if (m.containsAll(S)) { contained = true; break; } } if (!contained) { MP.add(S); } return MP; } /** * Ideal head term containment test. * @param G list of polynomials. * @param H index set. * @return true, if the variables of the head terms of each polynomial in G * are contained in H, else false. */ protected boolean containsHT(Set H, List> G) { Set S = null; for (GenPolynomial p : G) { if (p == null) { continue; } ExpVector e = p.leadingExpVector(); if (e == null) { continue; } int[] v = e.dependencyOnVariables(); if (v == null) { continue; } //System.out.println("v = " + Arrays.toString(v)); if (S == null) { // revert indices S = new HashSet(H.size()); int r = e.length() - 1; for (Integer i : H) { S.add(r - i); } } if (contains(v, S)) { // v \subset S return true; } } return false; } /** * Set containment. is v \subset H. * @param v index array. * @param H index set. * @return true, if each element of v is contained in H, else false . */ protected boolean contains(int[] v, Set H) { for (int i = 0; i < v.length; i++) { if (!H.contains(v[i])) { return false; } } return true; } /** * Construct univariate polynomials of minimal degree in all variables in * zero dimensional ideal(G). * @return list of univariate polynomial of minimal degree in each variable * in ideal(G) */ public List> constructUnivariate() { List> univs = new ArrayList>(); for (int i = list.ring.nvar - 1; i >= 0; i--) { GenPolynomial u = constructUnivariate(i); univs.add(u); } return univs; } /** * Construct univariate polynomial of minimal degree in variable i in zero * dimensional ideal(G). * @param i variable index. * @return univariate polynomial of minimal degree in variable i in ideal(G) */ public GenPolynomial constructUnivariate(int i) { doGB(); return bb.constructUnivariate(i, getList()); } /** * Zero dimensional radical decomposition. See Seidenbergs lemma 92, and * BWK lemma 8.13. * @return intersection of radical ideals G_i with ideal(this) subseteq * cap_i( ideal(G_i) ) */ public List> zeroDimRadicalDecomposition() { List> dec = new ArrayList>(); if (this.isZERO()) { return dec; } IdealWithUniv iwu = new IdealWithUniv(this, new ArrayList>()); dec.add(iwu); if (this.isONE()) { return dec; } if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { logger.warn("must use prime decomposition for char p and infinite coefficient rings, found {}", list.ring.coFac.toScript()); return zeroDimPrimeDecomposition(); } for (int i = list.ring.nvar - 1; i >= 0; i--) { List> part = new ArrayList>(); for (IdealWithUniv id : dec) { //System.out.println("id = " + id + ", i = " + i); GenPolynomial u = id.ideal.constructUnivariate(i); SortedMap, Long> facs = engine.baseSquarefreeFactors(u); if (facs == null || facs.size() == 0 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { List> iup = new ArrayList>(); iup.addAll(id.upolys); iup.add(u); IdealWithUniv Ipu = new IdealWithUniv(id.ideal, iup); part.add(Ipu); continue; // irreducible } logger.info("squarefree facs = {}", facs); GenPolynomialRing mfac = id.ideal.list.ring; int j = mfac.nvar - 1 - i; for (GenPolynomial p : facs.keySet()) { // make p multivariate GenPolynomial pm = p.extendUnivariate(mfac, j); // mfac.parse( p.toString() ); //System.out.println("pm = " + pm); Ideal Ip = id.ideal.sum(pm); List> iup = new ArrayList>(); iup.addAll(id.upolys); iup.add(p); IdealWithUniv Ipu = new IdealWithUniv(Ip, iup); if (debug) { logger.info("ideal with squarefree facs = {}", Ipu); } part.add(Ipu); } } dec = part; //part = new ArrayList>(); } return dec; } /** * Test for Zero dimensional radical. See Seidenbergs lemma 92, and BWK * lemma 8.13. * @return true if this is an zero dimensional radical ideal, else false */ public boolean isZeroDimRadical() { if (this.isZERO()) { return false; } if (this.isONE()) { return false; // not 0-dim } if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { logger.warn("radical only for char 0 or finite coefficient rings, but found {}", list.ring.coFac.toScript()); } for (int i = list.ring.nvar - 1; i >= 0; i--) { GenPolynomial u = constructUnivariate(i); boolean t = engine.isSquarefree(u); if (!t) { System.out.println("not squarefree " + engine.squarefreePart(u) + ", " + u); return false; } } return true; } /** * Test for radical ideal. * @param ru ideal with univariate polynomials * @return true if ru is a radical ideal, else false */ public boolean isRadical(IdealWithUniv ru) { if (this.isZERO()) { return false; } if (this.isONE()) { return false; // not 0-dim } if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { logger.warn("radical only for char 0 or finite coefficient rings, but found {}", list.ring.coFac.toScript()); } for (int i = ru.upolys.size() - 1; i >= 0; i--) { //list.ring.nvar GenPolynomial u = ru.upolys.get(i); boolean t = engine.isSquarefree(u); if (!t) { System.out.println("not squarefree " + engine.squarefreePart(u) + ", " + u); return false; } } return true; } /** * Zero dimensional ideal irreducible decomposition. See algorithm DIRGZD * of BGK 1986 and also PREDEC of the Gröbner bases book 1993. * @return intersection H, of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each ideal G_i has only irreducible minimal * univariate polynomials and the G_i are pairwise co-prime. */ public List> zeroDimDecomposition() { List> dec = new ArrayList>(); if (this.isZERO()) { return dec; } IdealWithUniv iwu = new IdealWithUniv(this, new ArrayList>()); dec.add(iwu); if (this.isONE()) { return dec; } FactorAbstract ufd = FactorFactory. getImplementation(list.ring.coFac); for (int i = list.ring.nvar - 1; i >= 0; i--) { List> part = new ArrayList>(); for (IdealWithUniv id : dec) { //System.out.println("id.ideal = " + id.ideal); GenPolynomial u = id.ideal.constructUnivariate(i); SortedMap, Long> facs = ufd.baseFactors(u); if (facs.size() == 0 || (facs.size() == 1 && facs.get(facs.firstKey()) == 1L)) { List> iup = new ArrayList>(); iup.addAll(id.upolys); iup.add(u); IdealWithUniv Ipu = new IdealWithUniv(id.ideal, iup); part.add(Ipu); continue; // irreducible } if (debug) { logger.info("irreducible facs = {}", facs); } GenPolynomialRing mfac = id.ideal.list.ring; int j = mfac.nvar - 1 - i; for (GenPolynomial p : facs.keySet()) { // make p multivariate GenPolynomial pm = p.extendUnivariate(mfac, j); // mfac.parse( p.toString() ); //System.out.println("pm = " + pm); Ideal Ip = id.ideal.sum(pm); List> iup = new ArrayList>(); iup.addAll(id.upolys); iup.add(p); IdealWithUniv Ipu = new IdealWithUniv(Ip, iup); part.add(Ipu); } } dec = part; //part = new ArrayList>(); } return dec; } /** * Zero dimensional ideal irreducible decomposition extension. One step * decomposition via a minimal univariate polynomial in the lowest variable, * used after each normalPosition step. * @param upol list of univariate polynomials * @param og list of other generators for the ideal * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and all minimal univariate polynomials of all G_i * are irreducible */ public List> zeroDimDecompositionExtension(List> upol, List> og) { if (upol == null || upol.size() + 1 != list.ring.nvar) { throw new IllegalArgumentException("univariate polynomial list not correct " + upol); } List> dec = new ArrayList>(); if (this.isZERO()) { return dec; } IdealWithUniv iwu = new IdealWithUniv(this, upol); if (this.isONE()) { dec.add(iwu); return dec; } FactorAbstract ufd = FactorFactory. getImplementation(list.ring.coFac); int i = list.ring.nvar - 1; //IdealWithUniv id = new IdealWithUniv(this,upol); GenPolynomial u = this.constructUnivariate(i); SortedMap, Long> facs = ufd.baseFactors(u); if (facs.size() == 1 && facs.get(facs.firstKey()) == 1L) { List> iup = new ArrayList>(); iup.add(u); // new polynomial first iup.addAll(upol); IdealWithUniv Ipu = new IdealWithUniv(this, iup, og); dec.add(Ipu); return dec; } logger.info("irreducible facs = {}", facs); GenPolynomialRing mfac = list.ring; int j = mfac.nvar - 1 - i; for (GenPolynomial p : facs.keySet()) { // make p multivariate GenPolynomial pm = p.extendUnivariate(mfac, j); //System.out.println("pm = " + pm); Ideal Ip = this.sum(pm); List> iup = new ArrayList>(); iup.add(p); // new polynomial first iup.addAll(upol); IdealWithUniv Ipu = new IdealWithUniv(Ip, iup, og); dec.add(Ipu); } return dec; } /** * Test for zero dimensional ideal decomposition. * @param L intersection of ideals G_i with ideal(G) subseteq cap_i( * ideal(G_i) ) and all minimal univariate polynomials of all G_i * are irreducible * @return true if L is a zero dimensional irreducible decomposition of * this, else false */ public boolean isZeroDimDecomposition(List> L) { if (L == null || L.size() == 0) { if (this.isZERO()) { return true; } return false; } // add lower variables if L contains ideals from field extensions GenPolynomialRing ofac = list.ring; int r = ofac.nvar; int rp = L.get(0).ideal.list.ring.nvar; int d = rp - r; //System.out.println("d = " + d); Ideal Id = this; if (d > 0) { GenPolynomialRing nfac = ofac.extendLower(d); //System.out.println("nfac = " + nfac); List> elist = new ArrayList>(list.list.size()); for (GenPolynomial p : getList()) { //System.out.println("p = " + p); GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); elist.add(q); } Id = new Ideal(nfac, elist, isGB, isTopt); } // test if this is contained in the intersection for (IdealWithUniv I : L) { boolean t = I.ideal.contains(Id); if (!t) { System.out.println("not contained " + this + " in " + I.ideal); return false; } } // test if all univariate polynomials are contained in the respective ideal //List> upprod = new ArrayList>(rp); for (IdealWithUniv I : L) { GenPolynomialRing mfac = I.ideal.list.ring; int i = 0; for (GenPolynomial p : I.upolys) { GenPolynomial pm = p.extendUnivariate(mfac, i++); //System.out.println("pm = " + pm + ", p = " + p); boolean t = I.ideal.contains(pm); if (!t) { System.out.println("not contained " + pm + " in " + I.ideal); return false; } } } return true; } /** * Compute normal position for variables i and j. * @param i first variable index * @param j second variable index * @param og other generators for the ideal * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] */ public IdealWithUniv normalPositionFor(int i, int j, List> og) { // extend variables by one GenPolynomialRing ofac = list.ring; if (ofac.tord.getEvord() != TermOrder.INVLEX) { throw new IllegalArgumentException("invalid term order for normalPosition " + ofac.tord); } if (ofac.characteristic().signum() == 0) { return normalPositionForChar0(i, j, og); } return normalPositionForCharP(i, j, og); } /** * Compute normal position for variables i and j, characteristic zero. * @param i first variable index * @param j second variable index * @param og other generators for the ideal * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] */ IdealWithUniv normalPositionForChar0(int i, int j, List> og) { // extend variables by one GenPolynomialRing ofac = list.ring; GenPolynomialRing nfac = ofac.extendLower(1); List> elist = new ArrayList>(list.list.size() + 1); for (GenPolynomial p : getList()) { GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); elist.add(q); } List> ogen = new ArrayList>(); if (og != null && og.size() > 0) { for (GenPolynomial p : og) { GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); ogen.add(q); } } Ideal I = new Ideal(nfac, elist, true); //System.out.println("I = " + I); int ip = list.ring.nvar - 1 - i; int jp = list.ring.nvar - 1 - j; GenPolynomial xi = nfac.univariate(ip); GenPolynomial xj = nfac.univariate(jp); GenPolynomial z = nfac.univariate(nfac.nvar - 1); // compute GBs until value of t is OK Ideal Ip; GenPolynomial zp; int t = 0; do { t--; // zp = z - ( xj - xi * t ) zp = z.subtract(xj.subtract(xi.multiply(nfac.fromInteger(t)))); zp = zp.monic(); Ip = I.sum(zp); //System.out.println("Ip = " + Ip); if (-t % 5 == 0) { logger.info("normal position, t = {}", t); } } while (!Ip.isNormalPositionFor(i + 1, j + 1)); if (debug) { logger.info("normal position = {}", Ip); } ogen.add(zp); IdealWithUniv Ips = new IdealWithUniv(Ip, null, ogen); return Ips; } /** * Compute normal position for variables i and j, positive characteristic. * @param i first variable index * @param j second variable index * @param og other generators for the ideal * @return this + (z - x_j - t x_i) in the ring C[z, x_1, ..., x_r] */ @SuppressWarnings({ "unchecked", "cast" }) IdealWithUniv normalPositionForCharP(int i, int j, List> og) { // extend variables by one GenPolynomialRing ofac = list.ring; GenPolynomialRing nfac = ofac.extendLower(1); List> elist = new ArrayList>(list.list.size() + 1); for (GenPolynomial p : getList()) { GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); elist.add(q); } List> ogen = new ArrayList>(); if (og != null && og.size() > 0) { for (GenPolynomial p : og) { GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); ogen.add(q); } } Ideal I = new Ideal(nfac, elist, true); //System.out.println("I = " + I); int ip = list.ring.nvar - 1 - i; int jp = list.ring.nvar - 1 - j; GenPolynomial xi = nfac.univariate(ip); GenPolynomial xj = nfac.univariate(jp); GenPolynomial z = nfac.univariate(nfac.nvar - 1); // compute GBs until value of t is OK Ideal Ip; GenPolynomial zp; AlgebraicNumberRing afac = null; Iterator> aiter = null; //String obr = ""; //String cbr = ""; int t = 0; do { t--; // zp = z - ( xj - xi * t ) GenPolynomial tn; if (afac == null) { tn = nfac.fromInteger(t); if (tn.isZERO()) { RingFactory fac = nfac.coFac; //int braces = 2; while (!(fac instanceof AlgebraicNumberRing)) { if (fac instanceof GenPolynomialRing) { GenPolynomialRing pfac = (GenPolynomialRing) (Object) fac; fac = pfac.coFac; } else if (fac instanceof QuotientRing) { QuotientRing pfac = (QuotientRing) (Object) fac; fac = pfac.ring.coFac; } else { throw new ArithmeticException( "field elements exhausted, need algebraic extension of base ring"); } //braces++; } //for (int ii = 0; ii < braces; ii++) { // obr += "{ "; // cbr += " }"; //} afac = (AlgebraicNumberRing) (Object) fac; logger.info("afac = {}", afac.toScript()); aiter = afac.iterator(); AlgebraicNumber an = aiter.next(); for (int kk = 0; kk < afac.characteristic().intValueExact(); kk++) { an = aiter.next(); } //System.out.println("an,iter = " + an); //tn = nfac.parse(obr + an.toString() + cbr); tn = nfac.parse(an.toString()); //System.out.println("tn = " + tn); //if (false) { // throw new RuntimeException("probe"); //} } } else { if (!aiter.hasNext()) { throw new ArithmeticException( "field elements exhausted, normal position not reachable: !aiter.hasNext(): " + t); } AlgebraicNumber an = aiter.next(); //System.out.println("an,iter = " + an); //tn = nfac.parse(obr + an.toString() + cbr); tn = nfac.parse(an.toString()); //System.out.println("tn = " + tn); } if (tn.isZERO()) { throw new ArithmeticException( "field elements exhausted, normal position not reachable: tn == 0: " + t); } zp = z.subtract(xj.subtract(xi.multiply(tn))); zp = zp.monic(); Ip = I.sum(zp); //System.out.println("Ip = " + Ip); if (-t % 4 == 0) { logger.info("normal position, t = {}", t); logger.info("normal position, GB = {}", Ip); if (t < -550) { throw new ArithmeticException("normal position not reached in " + t + " steps"); } } } while (!Ip.isNormalPositionFor(i + 1, j + 1)); if (debug) { logger.info("normal position = {}", Ip); } ogen.add(zp); IdealWithUniv Ips = new IdealWithUniv(Ip, null, ogen); return Ips; } /** * Test if this ideal is in normal position for variables i and j. * @param i first variable index * @param j second variable index * @return true if this is in normal position with respect to i and j */ public boolean isNormalPositionFor(int i, int j) { // called in extended ring! int ip = list.ring.nvar - 1 - i; int jp = list.ring.nvar - 1 - j; boolean iOK = false; boolean jOK = false; for (GenPolynomial p : getList()) { if (p.isZERO()) { continue; } ExpVector e = p.leadingExpVector(); int[] dov = e.dependencyOnVariables(); //System.out.println("dov = " + Arrays.toString(dov)); if (dov.length == 0) { throw new IllegalArgumentException("ideal dimension is not zero"); } if (dov[0] == ip) { if (e.totalDeg() != 1) { return false; } iOK = true; } else if (dov[0] == jp) { if (e.totalDeg() != 1) { return false; } jOK = true; } if (iOK && jOK) { return true; } } return iOK && jOK; } /** * Normal position index, separate for polynomials with more than 2 * variables. See also * mas.masring.DIPDEC0#DIGISR * @return (i,j) for non-normal variables */ public int[] normalPositionIndex2Vars() { int i = -1; int j = -1; for (GenPolynomial p : getList()) { if (p.isZERO()) { continue; } ExpVector e = p.leadingExpVector(); int[] dov = e.dependencyOnVariables(); //System.out.println("dov_head = " + Arrays.toString(dov)); if (dov.length == 0) { throw new IllegalArgumentException("ideal dimension is not zero " + p); } // search bi-variate head terms if (dov.length >= 2) { i = dov[0]; j = dov[1]; break; } int n = dov[0]; GenPolynomial q = p.reductum(); if (q.isZERO()) { continue; } e = q.degreeVector(); dov = e.dependencyOnVariables(); //System.out.println("dov_red = " + Arrays.toString(dov)); int k = Arrays.binarySearch(dov, n); int len = 2; if (k >= 0) { len = 3; } // search bi-variate reductas if (dov.length >= len) { switch (k) { case 0: i = dov[1]; j = dov[2]; break; case 1: i = dov[0]; j = dov[2]; break; case 2: i = dov[0]; j = dov[1]; break; default: i = dov[0]; j = dov[1]; break; } break; } } if (i < 0 || j < 0) { return (int[]) null; } // adjust index i = list.ring.nvar - 1 - i; j = list.ring.nvar - 1 - j; final int[] np = new int[] { j, i }; // reverse logger.info("normalPositionIndex2Vars, np = {}", () -> Arrays.toString(np)); return np; } /** * Normal position index, separate multiple univariate polynomials. See also * * mas.masring.DIPDEC0#DIGISM * @return (i,j) for non-normal variables */ public int[] normalPositionIndexUnivars() { //int[] np = null; //new int[] { -1, -1 }; int i = -1; int j = -1; // search multiple univariate polynomials with degree >= 2 for (GenPolynomial p : getList()) { if (p.isZERO()) { continue; } ExpVector e = p.degreeVector(); int[] dov = e.dependencyOnVariables(); long t = e.totalDeg(); // lt(p) would be enough //System.out.println("dov_univ = " + Arrays.toString(dov) + ", e = " + e); if (dov.length == 0) { throw new IllegalArgumentException("ideal dimension is not zero"); } if (dov.length == 1 && t >= 2L) { if (i == -1) { i = dov[0]; } else if (j == -1) { j = dov[0]; if (i > j) { int x = i; i = j; j = x; } } } if (i >= 0 && j >= 0) { break; } } if (i < 0 || j < 0) { // search polynomials with univariate head term and degree >= 2 for (GenPolynomial p : getList()) { if (p.isZERO()) { continue; } ExpVector e = p.leadingExpVector(); long t = e.totalDeg(); if (t >= 2) { e = p.degreeVector(); int[] dov = e.dependencyOnVariables(); //System.out.println("dov_univ2 = " + Arrays.toString(dov) + " e = " + e); if (dov.length == 0) { throw new IllegalArgumentException("ideal dimension is not zero"); } if (dov.length >= 2) { i = dov[0]; j = dov[1]; } } if (i >= 0 && j >= 0) { break; } } } if (i < 0 || j < 0) { return (int[]) null; } // adjust index i = list.ring.nvar - 1 - i; j = list.ring.nvar - 1 - j; final int[] np = new int[] { j, i }; // reverse logger.info("normalPositionIndexUnivars, np = {}", () -> Arrays.toString(np)); return np; } /** * Zero dimensional ideal decomposition for real roots. See algorithm * mas.masring.DIPDEC0#DINTSR. * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each G_i contains at most bi-variate polynomials * and all univariate minimal polynomials are irreducible */ public List> zeroDimRootDecomposition() { List> dec = zeroDimDecomposition(); if (this.isZERO()) { return dec; } if (this.isONE()) { return dec; } List> rdec = new ArrayList>(); while (dec.size() > 0) { IdealWithUniv id = dec.remove(0); int[] ri = id.ideal.normalPositionIndex2Vars(); if (ri == null || ri.length != 2) { rdec.add(id); } else { IdealWithUniv I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); List> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); //System.out.println("r_rd = " + rd); dec.addAll(rd); } } return rdec; } /** * Zero dimensional ideal prime decomposition. See algorithm * mas.masring.DIPDEC0#DINTSS. * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each G_i is a prime ideal */ public List> zeroDimPrimeDecomposition() { List> pdec = zeroDimPrimeDecompositionFE(); List> dec = new ArrayList>(); if (pdec.size() == 1) { // already prime IdealWithUniv Ip = pdec.get(0); int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys List> upol = Ip.upolys.subList(s, Ip.upolys.size()); Ip = new IdealWithUniv(this, upol); dec.add(Ip); return dec; } for (IdealWithUniv Ip : pdec) { if (Ip.ideal.getRing().nvar == getRing().nvar) { // no field extension dec.add(Ip); } else { // remove field extension // add other generators for performance Ideal Id = Ip.ideal; if (Ip.others != null) { //System.out.println("adding Ip.others = " + Ip.others); List> pp = new ArrayList>(); pp.addAll(Id.getList()); pp.addAll(Ip.others); Id = new Ideal(Id.getRing(), pp); } Ideal Is = Id.eliminate(getRing()); //System.out.println("Is = " + Is); int s = Ip.upolys.size() - getRing().nvar; // skip field ext univariate polys List> upol = Ip.upolys.subList(s, Ip.upolys.size()); IdealWithUniv Iu = new IdealWithUniv(Is, upol); //,Ip.others); used above and must be ignored here dec.add(Iu); } } return dec; } /** * Zero dimensional ideal prime decomposition, with field extension. See * algorithm mas.masring.DIPDEC0#DINTSS. * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each G_i is a prime ideal with eventually * containing field extension variables */ public List> zeroDimPrimeDecompositionFE() { List> dec = zeroDimRootDecomposition(); if (this.isZERO()) { return dec; } if (this.isONE()) { return dec; } List> rdec = new ArrayList>(); while (dec.size() > 0) { IdealWithUniv id = dec.remove(0); int[] ri = id.ideal.normalPositionIndexUnivars(); if (ri == null || ri.length != 2) { rdec.add(id); } else { IdealWithUniv I = id.ideal.normalPositionFor(ri[0], ri[1], id.others); List> rd = I.ideal.zeroDimDecompositionExtension(id.upolys, I.others); //System.out.println("rd = " + rd); dec.addAll(rd); } } return rdec; } /** * Zero dimensional ideal associated primary ideal. See algorithm * mas.masring.DIPIDEAL#DIRLPI. * @param P prime ideal associated to this * @return primary ideal of this with respect to the associated pime ideal P */ public Ideal primaryIdeal(Ideal P) { Ideal Qs = P; Ideal Q; int e = 0; do { Q = Qs; e++; Qs = Q.product(P); } while (Qs.contains(this)); boolean t; Ideal As; do { As = this.sum(Qs); t = As.contains(Q); if (!t) { Q = Qs; e++; Qs = Q.product(P); } } while (!t); logger.info("exponent = {}", e); return As; } /** * Zero dimensional ideal primary decomposition. * @return list of primary components of primary ideals G_i (pairwise * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with * the associated primes */ public List> zeroDimPrimaryDecomposition() { List> pdec = zeroDimPrimeDecomposition(); logger.info("prim decomp = {}", pdec); return zeroDimPrimaryDecomposition(pdec); } /** * Zero dimensional ideal elimination to original ring. * @param pdec list of prime ideals G_i * @return intersection of pairwise co-prime prime ideals G_i in the ring of * this with ideal(this) = cap_i( ideal(G_i) ) */ public List> zeroDimElimination(List> pdec) { List> dec = new ArrayList>(); if (this.isZERO()) { return dec; } if (this.isONE()) { dec.add(pdec.get(0)); return dec; } List> qdec = new ArrayList>(); for (IdealWithUniv Ip : pdec) { //System.out.println("Ip = " + Ip); List> epol = new ArrayList>(); epol.addAll(Ip.ideal.getList()); GenPolynomialRing mfac = Ip.ideal.list.ring; int j = 0; // add univariate polynomials for performance for (GenPolynomial p : Ip.upolys) { GenPolynomial pm = p.extendUnivariate(mfac, j++); if (j != 1) { // skip double epol.add(pm); } } // add other generators for performance if (Ip.others != null) { epol.addAll(Ip.others); } Ideal Ipp = new Ideal(mfac, epol); // logger.info("eliminate_1 = {}", Ipp); TermOrder to = null; if (mfac.tord.getEvord() != TermOrder.IGRLEX) { List> epols = new ArrayList>(); to = new TermOrder(TermOrder.IGRLEX); GenPolynomialRing smfac = new GenPolynomialRing(mfac.coFac, mfac.nvar, to, mfac.getVars()); for (GenPolynomial p : epol) { GenPolynomial pm = smfac.copy(p); epols.add(pm.monic()); } //epol = epols; Ipp = new Ideal(smfac, epols); } epol = red.irreducibleSet(Ipp.getList()); Ipp = new Ideal(Ipp.getRing(), epol); logger.info("eliminate = {}", Ipp); Ideal Is = Ipp.eliminate(list.ring); //System.out.println("Is = " + Is); if (to != null && !Is.list.ring.equals(list.ring)) { List> epols = new ArrayList>(); for (GenPolynomial p : Is.getList()) { GenPolynomial pm = list.ring.copy(p); epols.add(pm); } Is = new Ideal(list.ring, epols); //System.out.println("Is = " + Is); } int k = Ip.upolys.size() - list.ring.nvar; List> up = new ArrayList>(); for (int i = 0; i < list.ring.nvar; i++) { up.add(Ip.upolys.get(i + k)); } IdealWithUniv Ie = new IdealWithUniv(Is, up); qdec.add(Ie); } return qdec; } /** * Zero dimensional ideal primary decomposition. * @param pdec list of prime ideals G_i with no field extensions * @return list of primary components of primary ideals G_i (pairwise * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with * the associated primes */ public List> zeroDimPrimaryDecomposition(List> pdec) { List> dec = new ArrayList>(); if (this.isZERO()) { return dec; } if (this.isONE()) { PrimaryComponent pc = new PrimaryComponent(pdec.get(0).ideal, pdec.get(0)); dec.add(pc); return dec; } for (IdealWithUniv Ip : pdec) { Ideal Qs = this.primaryIdeal(Ip.ideal); PrimaryComponent pc = new PrimaryComponent(Qs, Ip); dec.add(pc); } return dec; } /** * Test for primary ideal decomposition. * @param L list of primary components G_i * @return true if ideal(this) == cap_i( ideal(G_i) ) */ public boolean isPrimaryDecomposition(List> L) { // test if this is contained in the intersection for (PrimaryComponent I : L) { boolean t = I.primary.contains(this); if (!t) { System.out.println("not contained " + this + " in " + I); return false; } } Ideal isec = null; for (PrimaryComponent I : L) { if (isec == null) { isec = I.primary; } else { isec = isec.intersect(I.primary); } } return this.contains(isec); } /** * Ideal extension. * @param vars list of variables for a polynomial ring for extension * @return ideal G, with coefficients in QuotientRing(GenPolynomialRing * (vars)) */ public IdealWithUniv> extension(String... vars) { GenPolynomialRing fac = getRing(); GenPolynomialRing efac = new GenPolynomialRing(fac.coFac, vars.length, fac.tord, vars); IdealWithUniv> ext = extension(efac); return ext; } /** * Ideal extension. * @param efac polynomial ring for extension * @return ideal G, with coefficients in QuotientRing(efac) */ public IdealWithUniv> extension(GenPolynomialRing efac) { QuotientRing qfac = new QuotientRing(efac); IdealWithUniv> ext = extension(qfac); return ext; } /** * Ideal extension. * @param qfac quotient polynomial ring for extension * @return ideal G, with coefficients in qfac */ public IdealWithUniv> extension(QuotientRing qfac) { GenPolynomialRing fac = getRing(); GenPolynomialRing efac = qfac.ring; String[] rvars = GroebnerBasePartial.remainingVars(fac.getVars(), efac.getVars()); //System.out.println("rvars = " + Arrays.toString(rvars)); GroebnerBasePartial bbp = new GroebnerBasePartial(); //wrong: OptimizedPolynomialList pgb = bbp.partialGB(getList(),rvars); OptimizedPolynomialList pgb = bbp.elimPartialGB(getList(), rvars, efac.getVars()); logger.info("rvars = {}", Arrays.toString(rvars)); logger.info("partialGB = {}", pgb); GenPolynomialRing> rfac = new GenPolynomialRing>(efac, rvars.length, fac.tord, rvars); List> plist = pgb.list; List>> rpgb = PolyUtil. recursive(rfac, plist); //System.out.println("rfac = " + rfac); GenPolynomialRing> qpfac = new GenPolynomialRing>(qfac, rfac); List>> qpgb = PolyUfdUtil. quotientFromIntegralCoefficients(qpfac, rpgb); //System.out.println("qpfac = " + qpfac); // compute f GreatestCommonDivisor ufd = GCDFactory.getImplementation(fac.coFac); GenPolynomial f = null; // qfac.ring.getONE(); for (GenPolynomial> p : rpgb) { if (f == null) { f = p.leadingBaseCoefficient(); } else { f = ufd.lcm(f, p.leadingBaseCoefficient()); } } //SquarefreeAbstract sqf = SquarefreeFactory.getImplementation(fac.coFac); //not required: f = sqf.squarefreePart(f); GenPolynomial> fp = rfac.getONE().multiply(f); GenPolynomial> fq = PolyUfdUtil. quotientFromIntegralCoefficients(qpfac, fp); logger.info("extension f = {}", f); logger.info("ext = {}", qpgb); List>> upols = new ArrayList>>(0); List>> opols = new ArrayList>>(1); opols.add(fq); qpgb = PolyUtil.> monic(qpgb); Ideal> ext = new Ideal>(qpfac, qpgb); IdealWithUniv> extu = new IdealWithUniv>(ext, upols, opols); return extu; } /** * Ideal contraction and permutation. * @param eideal extension ideal of this. * @return contraction ideal of eideal in this polynomial ring */ public IdealWithUniv permContraction(IdealWithUniv> eideal) { return Ideal. permutation(getRing(), Ideal. contraction(eideal)); } /** * Ideal contraction. * @param eid extension ideal of this. * @return contraction ideal of eid in distributed polynomial ring */ public static > IdealWithUniv contraction(IdealWithUniv> eid) { Ideal> eideal = eid.ideal; List>> qgb = eideal.getList(); QuotientRing qfac = (QuotientRing) eideal.getRing().coFac; GenPolynomialRing> rfac = new GenPolynomialRing>(qfac.ring, eideal.getRing()); GenPolynomialRing dfac = qfac.ring.extend(eideal.getRing().getVars()); TermOrder to = new TermOrder(qfac.ring.tord.getEvord()); dfac = new GenPolynomialRing(dfac.coFac, dfac.nvar, to, dfac.getVars()); //System.out.println("qfac = " + qfac); //System.out.println("rfac = " + rfac); //System.out.println("dfac = " + dfac); // convert polynomials List>> cgb = PolyUfdUtil. integralFromQuotientCoefficients(rfac, qgb); List> dgb = PolyUtil. distribute(dfac, cgb); Ideal cont = new Ideal(dfac, dgb); // convert other polynomials List> opols = new ArrayList>(); if (eid.others != null && eid.others.size() > 0) { List>> orpol = PolyUfdUtil . integralFromQuotientCoefficients(rfac, eid.others); List> opol = PolyUtil. distribute(dfac, orpol); opols.addAll(opol); } // convert univariate polynomials List> upols = new ArrayList>(0); int i = 0; for (GenPolynomial> p : eid.upolys) { GenPolynomial> pm = p.extendUnivariate(eideal.getRing(), i++); //System.out.println("pm = " + pm + ", p = " + p); GenPolynomial> urpol = PolyUfdUtil. integralFromQuotientCoefficients(rfac, pm); GenPolynomial upol = PolyUtil. distribute(dfac, urpol); upols.add(upol); //System.out.println("upol = " + upol); } // compute f GreatestCommonDivisor ufd = GCDFactory.getImplementation(qfac.ring.coFac); GenPolynomial f = null; // qfac.ring.getONE(); for (GenPolynomial> p : cgb) { if (f == null) { f = p.leadingBaseCoefficient(); } else { f = ufd.lcm(f, p.leadingBaseCoefficient()); } } GenPolynomial> fp = rfac.getONE().multiply(f); f = PolyUtil. distribute(dfac, fp); logger.info("contraction f = {}", f); logger.info("cont = {}", cont); opols.add(f); if (f.isONE()) { IdealWithUniv cf = new IdealWithUniv(cont, upols, opols); return cf; } // compute ideal quotient by f Ideal Q = cont.infiniteQuotientRab(f); IdealWithUniv Qu = new IdealWithUniv(Q, upols, opols); return Qu; } /** * Ideal permutation. * @param oring polynomial ring to which variables are back permuted. * @param Cont ideal to be permuted * @return permutation of cont in polynomial ring oring */ public static > IdealWithUniv permutation(GenPolynomialRing oring, IdealWithUniv Cont) { Ideal cont = Cont.ideal; GenPolynomialRing dfac = cont.getRing(); // (back) permutation of variables String[] ovars = oring.getVars(); String[] dvars = dfac.getVars(); //System.out.println("ovars = " + Arrays.toString(ovars)); //System.out.println("dvars = " + Arrays.toString(dvars)); if (Arrays.deepEquals(ovars, dvars)) { // nothing to do return Cont; } List perm = GroebnerBasePartial.getPermutation(dvars, ovars); //System.out.println("perm = " + perm); GenPolynomialRing pfac = cont.getRing().permutation(perm); logger.info("pfac = {}", pfac); List> ppolys = TermOrderOptimization. permutation(perm, pfac, cont.getList()); //System.out.println("ppolys = " + ppolys); cont = new Ideal(pfac, ppolys); if (logger.isDebugEnabled()) { logger.info("perm cont = {}", cont); } List> opolys = TermOrderOptimization. permutation(perm, pfac, Cont.others); //System.out.println("opolys = " + opolys); List> upolys = TermOrderOptimization. permutation(perm, pfac, Cont.upolys); //System.out.println("opolys = " + opolys); IdealWithUniv Cu = new IdealWithUniv(cont, upolys, opolys); return Cu; } /** * Ideal radical. * @return the radical ideal of this */ public Ideal radical() { List> rdec = radicalDecomposition(); List> dec = new ArrayList>(rdec.size()); for (IdealWithUniv ru : rdec) { dec.add(ru.ideal); } Ideal R = intersect(dec); return R; } /** * Ideal radical decomposition. * @return intersection of ideals G_i with radical(this) eq cap_i( * ideal(G_i) ) and each G_i is a radical ideal and the G_i are * pairwise co-prime */ public List> radicalDecomposition() { // check dimension int z = commonZeroTest(); List> dec = new ArrayList>(); List> ups = new ArrayList>(); // dimension -1 if (z < 0) { IdealWithUniv id = new IdealWithUniv(this, ups); dec.add(id); // see GB book return dec; } // dimension 0 if (z == 0) { dec = zeroDimRadicalDecomposition(); return dec; } // dimension > 0 if (this.isZERO()) { return dec; } if (list.ring.coFac.characteristic().signum() > 0 && !list.ring.coFac.isFinite()) { // must not be the case at this point logger.warn("must use prime decomposition for char p and infinite coefficient rings, found {}", list.ring.coFac.toScript()); return primeDecomposition(); } Dimension dim = dimension(); logger.info("dimension = {}", dim); // a short maximal independent set with small variables Set> M = dim.M; Set min = null; for (Set m : M) { if (min == null) { min = m; continue; } if (m.size() < min.size()) { min = m; } } int ms = min.size(); Integer[] ia = new Integer[0]; int mx = min.toArray(ia)[ms - 1]; for (Set m : M) { if (m.size() == ms) { int mxx = m.toArray(ia)[ms - 1]; if (mxx < mx) { min = m; mx = mxx; } } } //System.out.println("min = " + min); String[] mvars = new String[min.size()]; int j = 0; for (Integer i : min) { mvars[j++] = dim.v[i]; } logger.info("extension for variables = {}, indexes = {}", Arrays.toString(mvars), min); // reduce to dimension zero IdealWithUniv> Ext = extension(mvars); logger.info("extension = {}", Ext); List>> edec = Ext.ideal.zeroDimRadicalDecomposition(); logger.info("0-dim radical decomp = {}", edec); // remove field extensions are not required // reconstruct dimension for (IdealWithUniv> ep : edec) { IdealWithUniv cont = permContraction(ep); //System.out.println("cont = " + cont); dec.add(cont); } IdealWithUniv extcont = permContraction(Ext); //System.out.println("extcont = " + extcont); // get f List> ql = extcont.others; if (ql.size() == 0) { // should not happen return dec; } GenPolynomial fx = ql.get(0); //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); if (fx.isONE()) { return dec; } Ideal T = sum(fx); //System.out.println("T.rec = " + T.getList()); if (T.isONE()) { logger.info("1 in ideal for {}", fx); return dec; } logger.info("radical decomp ext-cont fx = {}", fx); logger.info("recursion radical decomp T = {}", T); // recursion: List> Tdec = T.radicalDecomposition(); logger.info("recursion radical decomp = {}", Tdec); dec.addAll(Tdec); return dec; } /** * Ideal irreducible decomposition. * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each G_i is an ideal with irreducible univariate * polynomials (after extension to a zero dimensional ideal) and the * G_i are pairwise co-prime */ public List> decomposition() { // check dimension int z = commonZeroTest(); List> dec = new ArrayList>(); // dimension -1 if (z < 0) { //List> ups = new ArrayList>(); //IdealWithUniv id = new IdealWithUniv(this, ups); //dec.add(id); see GB book return dec; } // dimension 0 if (z == 0) { dec = zeroDimDecomposition(); return dec; } // dimension > 0 if (this.isZERO()) { return dec; } Dimension dim = dimension(); logger.info("dimension = {}", dim); // shortest maximal independent set Set> M = dim.M; Set min = null; for (Set m : M) { if (min == null) { min = m; continue; } if (m.size() < min.size()) { min = m; } } //System.out.println("min = " + min); String[] mvars = new String[min.size()]; int j = 0; for (Integer i : min) { mvars[j++] = dim.v[i]; } logger.info("extension for variables = {}", Arrays.toString(mvars)); // reduce to dimension zero IdealWithUniv> Ext = extension(mvars); logger.info("extension = {}", Ext); List>> edec = Ext.ideal.zeroDimDecomposition(); logger.info("0-dim irred decomp = {}", edec); // remove field extensions are not required // reconstruct dimension for (IdealWithUniv> ep : edec) { IdealWithUniv cont = permContraction(ep); //System.out.println("cont = " + cont); dec.add(cont); } IdealWithUniv extcont = permContraction(Ext); //System.out.println("extcont = " + extcont); // get f List> ql = extcont.others; if (ql.size() == 0) { // should not happen return dec; } GenPolynomial fx = ql.get(0); //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); if (fx.isONE()) { return dec; } Ideal T = sum(fx); //System.out.println("T.rec = " + T.getList()); if (T.isONE()) { logger.info("1 in ideal for {}", fx); return dec; } logger.info("irred decomp ext-cont fx = {}", fx); logger.info("recursion irred decomp T = {}", T); // recursion: List> Tdec = T.decomposition(); logger.info("recursion irred decomposition = {}", Tdec); dec.addAll(Tdec); return dec; } /** * Ideal prime decomposition. * @return intersection of ideals G_i with ideal(this) subseteq cap_i( * ideal(G_i) ) and each G_i is a prime ideal and the G_i are * pairwise co-prime */ public List> primeDecomposition() { // check dimension int z = commonZeroTest(); List> dec = new ArrayList>(); // dimension -1 if (z < 0) { //List> ups = new ArrayList>(); //IdealWithUniv id = new IdealWithUniv(this, ups); //dec.add(id); see GB book return dec; } // dimension 0 if (z == 0) { dec = zeroDimPrimeDecomposition(); return dec; } // dimension > 0 if (this.isZERO()) { return dec; } Dimension dim = dimension(); logger.info("dimension = {}", dim); // shortest maximal independent set Set> M = dim.M; Set min = null; for (Set m : M) { if (min == null) { min = m; continue; } if (m.size() < min.size()) { min = m; } } //System.out.println("min = " + min); String[] mvars = new String[min.size()]; int j = 0; for (Integer i : min) { mvars[j++] = dim.v[i]; } logger.info("extension for variables = {}", Arrays.toString(mvars)); // reduce to dimension zero IdealWithUniv> Ext = extension(mvars); logger.info("extension = {}", Ext); List>> edec = Ext.ideal.zeroDimPrimeDecomposition(); logger.info("0-dim prime decomp = {}", edec); // remove field extensions, already done // reconstruct dimension for (IdealWithUniv> ep : edec) { IdealWithUniv cont = permContraction(ep); //System.out.println("cont = " + cont); dec.add(cont); } // get f IdealWithUniv extcont = permContraction(Ext); //System.out.println("extcont = " + extcont); List> ql = extcont.others; if (ql.size() == 0) { // should not happen return dec; } GenPolynomial fx = ql.get(0); //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); if (fx.isONE()) { return dec; } // compute exponent not required Ideal T = sum(fx); //System.out.println("T.rec = " + T.getList()); if (T.isONE()) { logger.info("1 in ideal for {}", fx); return dec; } logger.info("prime decomp ext-cont fx = {}", fx); logger.info("recursion prime decomp T = {}", T); // recursion: List> Tdec = T.primeDecomposition(); logger.info("recursion prime decomp = {}", Tdec); dec.addAll(Tdec); return dec; } /** * Test for ideal decomposition. * @param L intersection of ideals G_i with ideal(G) eq cap_i(ideal(G_i) ) * @return true if L is a decomposition of this, else false */ public boolean isDecomposition(List> L) { if (L == null || L.size() == 0) { if (this.isZERO()) { return true; } return false; } GenPolynomialRing ofac = list.ring; int r = ofac.nvar; int rp = L.get(0).ideal.list.ring.nvar; int d = rp - r; //System.out.println("d = " + d); Ideal Id = this; if (d > 0) { // add lower variables GenPolynomialRing nfac = ofac.extendLower(d); //System.out.println("nfac = " + nfac); List> elist = new ArrayList>(list.list.size()); for (GenPolynomial p : getList()) { //System.out.println("p = " + p); GenPolynomial q = p.extendLower(nfac, 0, 0L); //System.out.println("q = " + q); elist.add(q); } Id = new Ideal(nfac, elist, isGB, isTopt); } // test if this is contained in the intersection for (IdealWithUniv I : L) { boolean t = I.ideal.contains(Id); if (!t) { System.out.println("not contained " + this + " in " + I.ideal); return false; } } // // test if all univariate polynomials are contained in the respective ideal // for (IdealWithUniv I : L) { // GenPolynomialRing mfac = I.ideal.list.ring; // int i = 0; // for (GenPolynomial p : I.upolys) { // GenPolynomial pm = p.extendUnivariate(mfac, i++); // //System.out.println("pm = " + pm + ", p = " + p); // boolean t = I.ideal.contains(pm); // if (!t) { // System.out.println("not contained " + pm + " in " + I.ideal); // return false; // } // } // } return true; } /** * Ideal primary decomposition. * @return list of primary components of primary ideals G_i (pairwise * co-prime) with ideal(this) = cap_i( ideal(G_i) ) together with * the associated primes */ public List> primaryDecomposition() { // check dimension int z = commonZeroTest(); List> dec = new ArrayList>(); // dimension -1 if (z < 0) { //List> ups = new ArrayList>(); //IdealWithUniv id = new IdealWithUniv(this, ups); //PrimaryComponent pc = new PrimaryComponent(this, id); //dec.add(pc); see GB book return dec; } // dimension 0 if (z == 0) { dec = zeroDimPrimaryDecomposition(); return dec; } // dimension > 0 if (this.isZERO()) { return dec; } Dimension dim = dimension(); logger.info("dimension = {}", dim); // shortest maximal independent set Set> M = dim.M; Set min = null; for (Set m : M) { if (min == null) { min = m; continue; } if (m.size() < min.size()) { min = m; } } //System.out.println("min = " + min); String[] mvars = new String[min.size()]; int j = 0; for (Integer i : min) { mvars[j++] = dim.v[i]; } logger.info("extension for variables = {}", Arrays.toString(mvars)); // reduce to dimension zero IdealWithUniv> Ext = extension(mvars); logger.info("extension = {}", Ext); List>> edec = Ext.ideal.zeroDimPrimaryDecomposition(); logger.info("0-dim primary decomp = {}", edec); // remove field extensions, already done // reconstruct dimension List>> upq = new ArrayList>>(); for (PrimaryComponent> ep : edec) { IdealWithUniv> epu = new IdealWithUniv>(ep.primary, upq); IdealWithUniv contq = permContraction(epu); IdealWithUniv contp = permContraction(ep.prime); PrimaryComponent pc = new PrimaryComponent(contq.ideal, contp); //System.out.println("pc = " + pc); dec.add(pc); } // get f IdealWithUniv extcont = permContraction(Ext); if (debug) { logger.info("cont(Ext) = {}", extcont); } List> ql = extcont.others; if (ql.size() == 0) { // should not happen return dec; } GenPolynomial fx = ql.get(0); //System.out.println("cont(Ext) fx = " + fx + ", " + fx.ring); if (fx.isONE()) { return dec; } // compute exponent int s = this.infiniteQuotientExponent(fx, extcont.ideal); if (s == 0) { logger.info("exponent is 0 "); return dec; } if (s > 1) { fx = fx.power(s); } if (debug) { logger.info("exponent fx = {}", s + ", fx^s = {}", fx); } Ideal T = sum(fx); //System.out.println("T.rec = " + T.getList()); if (T.isONE()) { logger.info("1 in ideal for {}", fx); return dec; } logger.info("primmary decomp ext-cont fx = {}", fx); logger.info("recursion primary decomp T = {}", T); // recursion: List> Tdec = T.primaryDecomposition(); logger.info("recursion primary decomp = {}", Tdec); dec.addAll(Tdec); return dec; } } java-algebra-system-2.7.200/src/edu/jas/application/IdealWithComplexAlgebraicRoots.java000066400000000000000000000207101445075545500310500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; // import edu.jas.root.RealAlgebraicNumber; import edu.jas.structure.GcdRingElem; /** * Container for Ideals together with univariate polynomials and complex * algebraic roots. * @author Heinz Kredel */ public class IdealWithComplexAlgebraicRoots & Rational> extends IdealWithUniv { /** * The list of complex algebraic roots. */ public final List>>> can; /** * The list of decimal approximations of the complex algebraic roots. */ protected List>> droots = null; /** * Constructor not for use. */ protected IdealWithComplexAlgebraicRoots() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param id the ideal * @param up the list of univariate polynomials * @param cr the list of complex algebraic roots */ public IdealWithComplexAlgebraicRoots(Ideal id, List> up, List>>> cr) { super(id, up); can = cr; } /** * Constructor. * @param iu the ideal with univariate polynomials * @param cr the list of real algebraic roots */ public IdealWithComplexAlgebraicRoots(IdealWithUniv iu, List>>> cr) { super(iu.ideal, iu.upolys); can = cr; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(super.toString() + "\ncomplex roots:\n"); sb.append("["); boolean f1 = true; for (List>> lr : can) { if (!f1) { sb.append(", "); } else { f1 = false; } sb.append("["); boolean f2 = true; for (Complex> rr : lr) { if (!f2) { sb.append(", "); } else { f2 = false; } sb.append(rr.ring.toScript()); } sb.append("]"); } sb.append("]"); if (droots != null) { sb.append("\ndecimal complex root approximation:\n"); for (List> d : droots) { sb.append(d.toString()); sb.append("\n"); } } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return super.toScript() + ", " + can.toString(); } /** * Get decimal approximation of the complex root tuples. */ public synchronized List>> decimalApproximation() { if (this.droots != null) { return droots; } List>> rroots = new ArrayList>>(); ComplexRing cfac = new ComplexRing(new BigDecimal()); for (List>> rri : this.can) { List> r = new ArrayList>(); for (Complex> rr : rri) { BigDecimal dr = new BigDecimal(rr.getRe().magnitude()); BigDecimal di = new BigDecimal(rr.getIm().magnitude()); Complex d = new Complex(cfac, dr, di); r.add(d); } rroots.add(r); } droots = rroots; return rroots; } /** * compute decimal approximation of the complex root tuples. */ public void doDecimalApproximation() { List>> unused = decimalApproximation(); if (unused.isEmpty()) { // use for findbugs System.out.println("unused is empty"); } return; } /** * Is decimal approximation of the complex roots. * @return true, if the decimal complex roots approximate the complex roots. */ public synchronized boolean isDecimalApproximation() { doDecimalApproximation(); if (droots == null || droots.size() == 0) { return true; } if (upolys == null || upolys.size() == 0) { return true; } Complex dd = droots.get(0).get(0); ComplexRing dr = dd.ring; Complex c = new Complex(dr, new BigDecimal("0.15").power(BigDecimal.DEFAULT_PRECISION / 2)); c = c.norm(); //System.out.println("eps: c = " + c); Complex cc = new Complex(dr, new BigDecimal("0.1").power(BigDecimal.DEFAULT_PRECISION / 3)); cc = cc.norm(); ComplexRing cr = new ComplexRing(ideal.list.ring.coFac); List>> upds = new ArrayList>>( upolys.size()); for (GenPolynomial up : upolys) { GenPolynomialRing pfac = up.ring; GenPolynomialRing> cpfac = new GenPolynomialRing>(cr, pfac); GenPolynomialRing> dpfac = new GenPolynomialRing>(dr, cpfac); GenPolynomial> upc = PolyUtil. complexFromAny(cpfac, up); GenPolynomial> upd = PolyUtil. complexDecimalFromRational(dpfac, upc); //System.out.println("upd = " + upd); upds.add(upd); } for (List> rr : droots) { int i = 0; for (GenPolynomial> upd : upds) { Complex d = rr.get(i++); Complex z = PolyUtil.> evaluateMain(dr, upd, d); z = z.norm(); //System.out.println("z = " + z + ", d = " + d); if (z.getRe().compareTo(c.getRe()) >= 0) { //System.out.println("no root: z = " + z + ", c = " + c); if (z.getRe().compareTo(cc.getRe()) >= 0) { System.out.println("no root: z = " + z + ", cc = " + cc); return false; } } } //System.out.println(); } GenPolynomialRing pfac = ideal.list.ring; cr = new ComplexRing(pfac.coFac); GenPolynomialRing> cpfac = new GenPolynomialRing>(cr, pfac); GenPolynomialRing> dpfac = new GenPolynomialRing>(dr, cpfac); List> ips = ideal.list.list; c = new Complex(dr, new BigDecimal("0.15").power(BigDecimal.DEFAULT_PRECISION / 2 - 1)); for (GenPolynomial ip : ips) { GenPolynomial> ipc = PolyUtil. complexFromAny(cpfac, ip); GenPolynomial> ipd = PolyUtil. complexDecimalFromRational(dpfac, ipc); //System.out.println("ipd = " + ipd); for (List> rr : droots) { Complex z = PolyUtil.> evaluateAll(dr, ipd, rr); z = z.norm(); //System.out.println("z = " + z + ", rr = " + rr); if (z.getRe().compareTo(c.getRe()) >= 0) { //System.out.println("no root: z = " + z + ", c = " + c); if (z.getRe().compareTo(cc.getRe()) >= 0) { System.out.println("no root: z = " + z + ", cc = " + cc); System.out.println("ipd = " + ipd + ", rr = " + rr); return false; } } } //System.out.println(); } return true; } } java-algebra-system-2.7.200/src/edu/jas/application/IdealWithComplexRoots.java000066400000000000000000000035251445075545500272630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.poly.Complex; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for Ideals together with univariate polynomials and complex roots. * @author Heinz Kredel */ class IdealWithComplexRoots> extends IdealWithUniv { /** * The list of complex roots. */ public final List>> croots; /** * Constructor not for use. */ protected IdealWithComplexRoots() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param id the ideal * @param up the list of univaraite polynomials * @param cr the list of complex roots */ public IdealWithComplexRoots(Ideal id, List> up, List>> cr) { super(id, up); croots = cr; } /** * Constructor. * @param iu the ideal with univariate polynomials * @param cr the list of complex roots */ public IdealWithComplexRoots(IdealWithUniv iu, List>> cr) { super(iu.ideal, iu.upolys); croots = cr; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + "\ncomplex roots: " + croots.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return super.toScript() + ", " + croots.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/IdealWithRealAlgebraicRoots.java000066400000000000000000000161661445075545500303360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.Rational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.root.RealAlgebraicNumber; import edu.jas.structure.GcdRingElem; /** * Container for Ideals together with univariate polynomials and real algebraic * roots. * @author Heinz Kredel */ public class IdealWithRealAlgebraicRoots & Rational> extends IdealWithUniv { /** * The list of real algebraic roots. */ public final List>> ran; /** * The list of decimal approximations of the real algebraic roots. */ protected List> droots = null; /** * Constructor not for use. */ protected IdealWithRealAlgebraicRoots() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param id the ideal * @param up the list of univaraite polynomials * @param rr the list of real algebraic roots */ public IdealWithRealAlgebraicRoots(Ideal id, List> up, List>> rr) { super(id, up); ran = rr; } /** * Constructor. * @param iu the ideal with univariate polynomials * @param rr the list of real algebraic roots */ public IdealWithRealAlgebraicRoots(IdealWithUniv iu, List>> rr) { super(iu.ideal, iu.upolys); ran = rr; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(super.toString() + "\nreal roots:\n"); sb.append("["); boolean f1 = true; for (List> lr : ran) { if (!f1) { sb.append(", "); } else { f1 = false; } sb.append("["); boolean f2 = true; for (RealAlgebraicNumber rr : lr) { if (!f2) { sb.append(", "); } else { f2 = false; } sb.append(rr.ring.toScript()); } sb.append("]"); } sb.append("]"); if (droots != null) { sb.append("\ndecimal real root approximation:\n"); for (List d : droots) { sb.append(d.toString()); sb.append("\n"); } } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return super.toScript() + ", " + ran.toString(); } /** * Get decimal approximation of the real root tuples. */ public synchronized List> decimalApproximation() { if (this.droots != null) { return droots; } List> rroots = new ArrayList>(); for (List> rri : this.ran) { List r = new ArrayList(); for (RealAlgebraicNumber rr : rri) { BigDecimal d = new BigDecimal(rr.magnitude()); r.add(d); } rroots.add(r); } droots = rroots; return rroots; } /** * compute decimal approximation of the real root tuples. */ public void doDecimalApproximation() { List> unused = decimalApproximation(); if (unused.isEmpty()) { // use for findbugs System.out.println("unused is empty"); } return; } /** * Is decimal approximation of the real roots. * @return true, if the decimal real roots approximate the real roots. */ public synchronized boolean isDecimalApproximation() { doDecimalApproximation(); if (droots == null || droots.size() == 0) { return true; } if (upolys == null || upolys.size() == 0) { return true; } BigDecimal dr = droots.get(0).get(0); BigDecimal c = new BigDecimal("0.15").power(BigDecimal.DEFAULT_PRECISION / 2); //System.out.println("eps: c = " + c); List> upds = new ArrayList>(upolys.size()); for (GenPolynomial up : upolys) { GenPolynomialRing pfac = up.ring; GenPolynomialRing dpfac = new GenPolynomialRing(dr, pfac); GenPolynomial upd = PolyUtil. decimalFromRational(dpfac, up); //System.out.println("upd = " + upd); upds.add(upd); } for (List rr : droots) { int i = 0; for (GenPolynomial upd : upds) { BigDecimal d = rr.get(i++); BigDecimal z = PolyUtil. evaluateMain(dr, upd, d); z = z.abs(); //System.out.println("z = " + z + ", d = " + d); if (z.compareTo(c) >= 0) { //System.out.println("no root: z = " + z); BigDecimal cc = new BigDecimal("0.1").power(BigDecimal.DEFAULT_PRECISION / 3); if (z.compareTo(cc) >= 0) { System.out.println("no root: z = " + z + ", cc = " + cc); return false; } } } } GenPolynomialRing pfac = ideal.list.ring; GenPolynomialRing dpfac = new GenPolynomialRing(dr, pfac); List> ips = ideal.list.list; //List> ipds = new ArrayList>(ips.size()); c = new BigDecimal("0.15").power(BigDecimal.DEFAULT_PRECISION / 2 - 1); for (GenPolynomial ip : ips) { GenPolynomial ipd = PolyUtil. decimalFromRational(dpfac, ip); //System.out.println("ipd = " + ipd); //ipds.add(ipd); for (List rr : droots) { BigDecimal z = PolyUtil. evaluateAll(dr, ipd, rr); z = z.abs(); //System.out.println("z = " + z + ", rr = " + rr); if (z.compareTo(c) >= 0) { //System.out.println("no root: z = " + z + ", c = " + c); BigDecimal cc = new BigDecimal("0.1").power(BigDecimal.DEFAULT_PRECISION / 3); if (z.compareTo(cc) >= 0) { System.out.println("no root: z = " + z + ", cc = " + cc); System.out.println("ipd = " + ipd + ", rr = " + rr); return false; } } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/application/IdealWithRealRoots.java000066400000000000000000000034111445075545500265310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for Ideals together with univariate polynomials and real roots. * @author Heinz Kredel */ public class IdealWithRealRoots> extends IdealWithUniv { /** * The list of real roots. */ public final List> rroots; /** * Constructor not for use. */ protected IdealWithRealRoots() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param id the ideal * @param up the list of univaraite polynomials * @param rr the list of real roots */ public IdealWithRealRoots(Ideal id, List> up, List> rr) { super(id, up); rroots = rr; } /** * Constructor. * @param iu the ideal with univariate polynomials * @param rr the list of real roots */ public IdealWithRealRoots(IdealWithUniv iu, List> rr) { super(iu.ideal, iu.upolys); rroots = rr; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + "\nreal roots: " + rroots.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return super.toScript() + ", " + rroots.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/IdealWithUniv.java000066400000000000000000000065101445075545500255430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.List; import java.util.ArrayList; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for Ideals together with univariate polynomials. * @author Heinz Kredel */ public class IdealWithUniv> implements Serializable { /** * The ideal. */ public final Ideal ideal; /** * The list of univariate polynomials. Contains polynomials from several * rings, depending on the stage of the decomposition. 1) polynomials in a * ring of one variable, 2) polynomials depending on only one variable but * in a ring with multiple variables, 3) after contraction to a non-zero * dimensional ring multivariate polynomials depending on one significant * variable and multiple variables from the quotient coefficients. */ public final List> upolys; /** * A list of other useful polynomials. 1) field extension polynomials, 2) * generators for infinite quotients. */ public final List> others; /** * Constructor not for use. */ protected IdealWithUniv() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param id the ideal * @param up the list of univariate polynomials */ protected IdealWithUniv(Ideal id, List> up) { this(id, up, null); } /** * Constructor. * @param id the ideal * @param up the list of univariate polynomials * @param og the list of other polynomials */ protected IdealWithUniv(Ideal id, List> up, List> og) { ideal = id; upolys = up; others = og; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { String s = ideal.toString(); if (upolys != null) { s += "\nunivariate polynomials:\n" + upolys.toString(); } if (others == null) { return s; } return s + "\nother polynomials:\n" + others.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case String s = ideal.toScript(); if (upolys != null) { s += ", upolys=" + upolys.toString(); } if (others == null) { return s; } return s + ", others=" + others.toString(); } /** * Get list of ideals from list of ideals with univariates. * @param Bl list of ideals with univariate polynomials * @return list of ideals */ public static > List> asListOfIdeals(List> Bl) { List> L = new ArrayList>(Bl.size()); if (Bl.size() == 0) { return L; } for (IdealWithUniv B : Bl) { if (B == null) { continue; } Ideal I = B.ideal; L.add(I); } return L; } } java-algebra-system-2.7.200/src/edu/jas/application/IntegerProgram.java000066400000000000000000000323141445075545500257550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.Arrays; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.poly.ExpVector; import edu.jas.poly.ExpVectorLong; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; /** * Solution of Integer Programming problems using Groebner bases. Integer * Program is in standard form -> minimization of given Equation plus * restrictions. See chapter 8 in Cox, Little, O'Shea "Using Algebraic * Geometry", 1998. * @author Maximilian Nohr */ public class IntegerProgram implements java.io.Serializable { private static final Logger logger = LogManager.getLogger(IntegerProgram.class); private static boolean debug = logger.isDebugEnabled(); //false; private boolean negVars; private boolean success; /* Integer Program is in standard form -> minimization of given Equation + restrictions */ int n; // # of variables including slack variables int m; // # of restrictions long[] C; // List of Coefficients c_1...c_n of objective function long[] B; // List of b_1...b_m, restriction right hand side long[][] A; // m x n Matrix of a_{11}....a_{mn}, restriction matrix long[] D; // Polynomial degrees 1...n long[][] Aa; // restriction matrix a_{11}..a_{mn} after Laurent transformation Ideal I; //the Ideal Ideal GB; // the Groebner base for the ideal TermOrder to; // the Term order for the GB PolynomialList F; // The Polynomials that generate the Ideal GenPolynomial S; // The Polynomial that is reduced for the Solution /** * Constructor. Use one instance for every new problem since solve() is not * reentrant. */ public IntegerProgram() { } /** * Set debug flag to parameter value. * @param b */ public void setDebug(boolean b) { debug = b; } /* * Setup the Ideal corresponding to the Integer Program. */ @SuppressWarnings("unchecked") private void createIdeal() { Aa = A.clone(); negVars = negVarTest(); String[] w = new String[n]; String[] f = new String[n]; String[] z = new String[m]; String[] t = new String[n]; StringBuilder sb = new StringBuilder(); sb.append("Int("); if (negVars) { //A or B has negative values for (int i = 1; i <= n; i++) { w[i - 1] = "w" + i; } for (int i = 1; i <= m; i++) { z[i - 1] = "z" + i; } for (int i = 0; i < n; i++) { StringBuffer h = new StringBuffer(""); long min = 0; for (int j = 0; j < m; j++) { if (A[j][i] < min) { min = A[j][i]; } } if (min < 0) { long e = -min; h.append("t^" + e + " * "); for (int j = 0; j < m; j++) { Aa[j][i] = A[j][i] + e; h.append(z[j] + "^" + Aa[j][i] + " * "); } } else { for (int j = 0; j < m; j++) { if (A[j][i] != 0) { h.append(z[j] + "^" + A[j][i] + " * "); } } } f[i] = h.substring(0, h.length() - 3).toString(); } setDeg(); setTO(); for (int i = 0; i < n; i++) { t[i] = f[i] + " - " + w[i]; } sb.append("t"); for (int i = 0; i < m; i++) { sb.append(",").append(z[i]); } for (int i = 0; i < n; i++) { sb.append(",").append(w[i]); } sb.append(") W "); //sb.append(to.weightToString().substring(6, to.weightToString().length())); sb.append(to.weightToString()); sb.append(" ( ( t"); for (int i = 0; i < m; i++) { sb.append(" * ").append(z[i]); } sb.append(" - 1 )"); for (int i = 0; i < n; i++) { sb.append(", (").append(t[i]).append(" )"); } sb.append(") "); } else { //if neither A nor B contain negative values for (int i = 1; i <= n; i++) { w[i - 1] = "w" + i; } for (int i = 1; i <= m; i++) { z[i - 1] = "z" + i; } for (int i = 0; i < n; i++) { StringBuffer h = new StringBuffer(""); for (int j = 0; j < m; j++) { if (A[j][i] != 0) { h.append(z[j] + "^" + A[j][i] + " * "); } } f[i] = h.substring(0, h.length() - 3).toString(); } setDeg(); setTO(); for (int i = 0; i < n; i++) { t[i] = f[i] + " - " + w[i]; } sb.append(z[0]); for (int i = 1; i < m; i++) { sb.append(",").append(z[i]); } for (int i = 0; i < n; i++) { sb.append(",").append(w[i]); } sb.append(") W "); //sb.append(to.weightToString().substring(6, to.weightToString().length())); sb.append(to.weightToString()); sb.append(" ( (").append(t[0]).append(")"); for (int i = 1; i < n; i++) { sb.append(", (").append(t[i]).append(" )"); } sb.append(") "); } if (debug) { logger.debug("list = {}", sb); } Reader source = new StringReader(sb.toString()); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } if (debug) { logger.debug("F = {}", F); } I = new Ideal(F); return; } /** * @return true if the last calculation had a solution, else false */ public boolean getSuccess() { return success; } /** * Solve Integer Program. * @param A matrix of restrictions * @param B restrictions right hand side * @param C objective function * @return solution s, such that s*C -> minimal and A*s = B, or s = null * if no solution exists */ public long[] solve(long[][] A, long[] B, long[] C) { this.A = Arrays.copyOf(A, A.length); this.B = Arrays.copyOf(B, B.length); this.C = Arrays.copyOf(C, C.length); this.n = A[0].length; this.m = A.length; D = new long[n]; createIdeal(); GB = I.GB(); return solve(B); } /** * Solve Integer Program for new right hand side. Uses the GB (matrix A and * C) from the last calculation. * @param B restrictions right hand side * @return solution s, such that s*C -> minimal and A*s = B, or s = null * if no solution exists */ public long[] solve(long[] B) { long[] returnMe = new long[n]; if (B.length != m) { System.out.println("ERROR: Dimensions don't match: " + B.length + " != " + m); return returnMe; } long[] l; this.B = Arrays.copyOf(B, B.length); if (debug) { logger.debug("GB = {}", GB); } if (negVars) { l = new long[m + n + 1]; long min = findMin(B); if (min < 0) { long r = -min; l[m + n] = r; for (int i = 0; i < m; i++) { l[m + n - 1 - i] = B[i] + r; } } else { for (int i = 0; i < m; i++) { l[m + n - 1 - i] = B[i]; } } } else { l = new long[m + n]; for (int i = 0; i < m; i++) { l[m + n - 1 - i] = B[i]; } } ExpVector e = new ExpVectorLong(l); S = new GenPolynomial(I.getRing(), e); S = GB.normalform(S); ExpVector E = S.exponentIterator().next(); for (int i = 0; i < n; i++) { returnMe[n - 1 - i] = E.getVal(i); } success = true; for (int i = n; i < n + m; i++) { if (E.getVal(i) != 0) { success = false; break; } } if (success) { if (debug) { logger.debug("The solution is: {}", Arrays.toString(returnMe)); // or () -> toString(ll) } } else { logger.warn("The Problem does not have a feasible solution."); returnMe = null; } return returnMe; } /* * Set the degree. */ private void setDeg() { for (int j = 0; j < n; j++) { for (int i = 0; i < m; i++) { D[j] += Aa[i][j]; } } } /* * Set the term order. */ private void setTO() { int h; if (negVars) {//if A and/or B contains negative values h = m + n + 1; } else { h = m + n; } long[] u1 = new long[h]; long[] u2 = new long[h]; for (int i = 0; i < h - n; i++) { //m+1 because t needs another 1 u1[h - 1 - i] = 1; } long[] h1 = new long[h]; // help vectors to construct u2 out of long[] h2 = new long[h]; for (int i = h - n; i < h; i++) { h1[i] = C[i - (h - n)]; h2[i] = D[i - (h - n)]; } long min = h1[0]; for (int i = 0; i < h; i++) { u2[h - 1 - i] = h1[i] + h2[i]; if (u2[h - 1 - i] < min) { min = u2[h - 1 - i]; } } while (min < 0) { min = u2[0]; for (int i = 0; i < h; i++) { u2[h - 1 - i] += h2[i]; if (u2[h - 1 - i] < min) { min = u2[h - 1 - i]; } } } long[][] wv = { u1, u2 }; to = new TermOrder(wv); } /* * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Function to minimize:\n"); char c = 'A'; // variables are named A, B, C, ... boolean plus = false; for (int i = 0; i < n; i++) { if (C[i] != 0) { if (C[i] < 0) { sb.append("(").append(C[i]).append(")"); sb.append("*"); } else if (C[i] != 1) { sb.append(C[i]); sb.append("*"); } sb.append(c); sb.append(" + "); plus = true; } c++; } if (plus) { sb.delete(sb.lastIndexOf("+"), sb.length()); } sb.append("\nunder the Restrictions:\n"); for (int i = 0; i < m; i++) { c = 'A'; //System.out.println("A["+i+"] = " + Arrays.toString(A[i])); plus = false; for (int j = 0; j < n; j++) { if (A[i][j] != 0) { if (A[i][j] < 0) { sb.append("(").append(A[i][j]).append(")"); sb.append("*"); } else if (A[i][j] != 1) { sb.append(A[i][j]); sb.append("*"); } sb.append(c); sb.append(" + "); plus = true; } c++; } if (plus) { sb.delete(sb.lastIndexOf("+"), sb.length()); } else { sb.append("0 "); } sb.append("= ").append(B[i]).append("\n"); } return sb.toString(); } /* * Test for negative variables. * @return true if negative variables appear */ private boolean negVarTest() { for (int i = 0; i < m; i++) { if (B[i] < 0) { return true; } for (int j = 0; j < n; j++) { if (A[i][j] < 0) { return true; } } } return false; } /* * Find minimal element. * @param B vector of at least one element, B.length >= 1 * @return minimal element of B */ private long findMin(long[] B) { long min = B[0]; for (int i = 1; i < B.length; i++) { if (B[i] < min) { min = B[i]; } } return min; } } java-algebra-system-2.7.200/src/edu/jas/application/IntegerProgramExamples.java000066400000000000000000000171031445075545500274530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Arrays; /** * Examples for Integer Programming. * @author Maximilian Nohr */ public class IntegerProgramExamples { /** * Execute all examples. * @param args */ public static void main(String[] args) { example1(); example2(); example3(); example4(); example5(); example6(); example7(); example8(); // too big: example9(); // too big: example10(); } /** * Example p.360 CLOII */ public static void example1() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.360 CLOII long[][] A0 = { { 4, 5, 1, 0 }, { 2, 3, 0, 1 } }; long[] B0 = { 37, 20 }; long[] C0 = { -11, -15, 0, 0 }; long[] sol = IP.solve(A0, B0, C0); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); long[] BW = { 1, 2 }; //,3}; sol = IP.solve(BW); int count = 0; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { B0[0] = i; B0[1] = j; sol = IP.solve(A0, B0, C0); if (IP.getSuccess()) { count++; } } } System.out.println(count + " times successful!"); } /** * Example p.374 CLOII 10a */ public static void example2() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.374 CLOII 10a long[][] A = { { 3, 2, 1, 1 }, { 4, 1, 1, 0 } }; long[] B = { 10, 5 }; long[] C = { 2, 3, 1, 5 }; long[] sol = IP.solve(A, B, C); //10b long[] Bb = { 20, 14 }; sol = IP.solve(Bb); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example p.372 CLOII */ public static void example3() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.372 CLOII long[][] A2 = { { 3, -2, 1, 0 }, { 4, 1, -1, -1 } }; long[] B2 = { -1, 5 }; long[] C2 = { 1, 1000, 1, 100 }; long[] sol = IP.solve(A2, B2, C2); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } public static void example4() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.374 10c long[][] A3 = { { 3, 2, 1, 1, 0, 0 }, { 1, 2, 3, 0, 1, 0 }, { 2, 1, 1, 0, 0, 1 } }; long[] B3 = { 45, 21, 18 }; long[] C3 = { -3, -4, -2, 0, 0, 0 }; long[] sol = IP.solve(A3, B3, C3); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example p.138 AAECC-9 */ public static void example5() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.138 AAECC-9 long[][] A4 = { { 32, 45, -41, 22 }, { -82, -13, 33, -33 }, { 23, -21, 12, -12 } }; long[] B4 = { 214, 712, 331 }; //im Beispiel keine b genannt long[] C4 = { 1, 1, 1, 1 }; long[] sol = IP.solve(A4, B4, C4); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example from M. Nohr */ public static void example6() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //eigenes beispiel //System.out.println("example from mnohr:"); long[][] A5 = { { 4, 3, 1, 0 }, { 3, 1, 0, 1 } }; long[] B5 = { 200, 100 }; long[] C5 = { -5, -4, 0, 0 }; long[] sol = IP.solve(A5, B5, C5); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example unsolvable */ public static void example7() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); long[][] A9 = { { 1, 1, 1, 1 }, { -1, -1, -1, -1 } }; long[] B9 = { 1, 1 }; long[] C9 = { 1, 1, 0, 0 }; long[] sol = IP.solve(A9, B9, C9); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\nunsolvable: " + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example ? */ public static void example8() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); long[][] A8 = { { 4, 3, 1, 0 }, { 3, 1, 0, 1 } }; long[] B8 = { 200, 100 }; long[] C8 = { -5, -4, 0, 0 }; long[] sol = IP.solve(A8, B8, C8); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example p.137 AAECC-9, too many vars */ public static void example9() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); // bsp s.137 AAECC-9 auch too many vars long[][] A7 = { { 2, 5, -3, 1, -2 }, { 1, 7, 2, 3, 1 }, { 4, -2, -1, -5, 3 } }; long[] B7 = { 214, 712, 331 }; long[] C7 = { 1, 1, 1, 1, 1 }; long[] sol = IP.solve(A7, B7, C7); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } /** * Example, too big */ public static void example10() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //too many variables long[][] A6 = { { 5, 11, 23, -5, 4, -7, -4 }, { 1, -5, -14, 15, 7, -8, 10 }, { 3, 21, -12, 7, 9, 11, 8 } }; long[] B6 = { 23, 19, 31 }; long[] C6 = { 1, 1, 1, 1, 1, 1, 1 }; long[] sol = IP.solve(A6, B6, C6); long t1 = System.currentTimeMillis(); long t = t1 - t0; System.out.println("\n" + IP); System.out.println("The solution is: " + Arrays.toString(sol)); System.out.println("The computation needed " + t + " milliseconds."); } } java-algebra-system-2.7.200/src/edu/jas/application/Local.java000066400000000000000000000342751445075545500240720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; import edu.jas.structure.RingElem; /** * Local ring element based on GenPolynomial with RingElem interface. Objects of * this class are (nearly) immutable. * @author Heinz Kredel */ // To be fixed?: Not jet working because of monic GBs. public class Local> implements RingElem>, QuotPair> { private static final Logger logger = LogManager.getLogger(Local.class); private static final boolean debug = logger.isDebugEnabled(); /** * Local class factory data structure. */ public final LocalRing ring; /** * Numerator part of the element data structure. */ protected final GenPolynomial num; /** * Denominator part of the element data structure. */ protected final GenPolynomial den; /** * Flag to remember if this local element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a Local object from a ring factory. * @param r ring factory. */ public Local(LocalRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a Local object from a ring factory and a * numerator polynomial. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator polynomial. */ public Local(LocalRing r, GenPolynomial n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a Local object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. */ public Local(LocalRing r, GenPolynomial n, GenPolynomial d) { this(r, n, d, false); } /** * The constructor creates a Local object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. * @param isred true if gcd(n,d) == 1, else false. */ protected Local(LocalRing r, GenPolynomial n, GenPolynomial d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = n.negate(); d = d.negate(); } if (isred) { num = n; den = d; return; } GenPolynomial p = ring.ideal.normalform(d); if (p == null || p.isZERO()) { throw new IllegalArgumentException("denominator may not be in ideal"); } //d = p; can't do this C lc = d.leadingBaseCoefficient(); if (!lc.isONE() && lc.isUnit()) { lc = lc.inverse(); n = n.multiply(lc); d = d.multiply(lc); } if (n.compareTo(d) == 0) { num = ring.ring.getONE(); den = ring.ring.getONE(); return; } if (n.negate().compareTo(d) == 0) { num = ring.ring.getONE().negate(); den = ring.ring.getONE(); return; } if (n.isZERO()) { num = n; den = ring.ring.getONE(); return; } // must reduce to lowest terms //GenPolynomial gcd = ring.ring.getONE(); GenPolynomial gcd = ring.engine.gcd(n, d); if (debug) { logger.info("gcd = {}", gcd); } if (gcd.isONE()) { num = n; den = d; } else { // d not in ideal --> gcd not in ideal //p = ring.ideal.normalform( gcd ); //if ( p == null || p.isZERO() ) { // find nonzero factor // num = n; // den = d; //} else { num = n.divide(gcd); den = d.divide(gcd); //} } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public LocalRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public GenPolynomial numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public GenPolynomial denominator() { return den; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Local copy() { return new Local(ring, num, den, true); } /** * Is Local zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is Local one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.equals(den); } /** * Is Local unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known if (num.isZERO()) { isunit = 0; return false; } GenPolynomial p = ring.ideal.normalform(num); boolean u = (p != null && !p.isZERO()); if (u) { isunit = 1; } else { isunit = 0; } return (u); } /** * Is Qoutient a constant. * @return true, if this has constant numerator and denominator, else false. */ public boolean isConstant() { return num.isConstant() && den.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(ring.ring.getVars()); if (den.isONE()) { return s + " }"; } return s + "| " + den.toString(ring.ring.getVars()) + " }"; } return "Local[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case if (den.isONE()) { return num.toScript(); } return num.toScript() + " / " + den.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Local comparison. * @param b Local. * @return sign(this-b). */ @Override public int compareTo(Local b) { if (b == null || b.isZERO()) { return this.signum(); } if (this.isZERO()) { return -b.signum(); } // assume sign(den,b.den) > 0 int s1 = num.signum(); int s2 = b.num.signum(); int t = (s1 - s2) / 2; if (t != 0) { System.out.println("compareTo: t = " + t); return t; } if (den.compareTo(b.den) == 0) { return num.compareTo(b.num); } GenPolynomial r = num.multiply(b.den); GenPolynomial s = den.multiply(b.num); return r.compareTo(s); //GenPolynomial x = r.subtract(s); //return x.signum(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (!(b instanceof Local)) { return false; } Local a = null; try { a = (Local) b; } catch (ClassCastException e) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * Local absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Local abs() { return new Local(ring, num.abs(), den, true); } /** * Local summation. * @param S Local. * @return this+S. */ public Local sum(Local S) { if (S == null || S.isZERO()) { return this; } GenPolynomial n = num.multiply(S.den); n = n.sum(den.multiply(S.num)); GenPolynomial d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Local negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Local negate() { return new Local(ring, num.negate(), den, true); } /** * Local signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return num.signum(); } /** * Local subtraction. * @param S Local. * @return this-S. */ public Local subtract(Local S) { if (S == null || S.isZERO()) { return this; } GenPolynomial n = num.multiply(S.den); n = n.subtract(den.multiply(S.num)); GenPolynomial d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Local division. * @param S Local. * @return this/S. */ public Local divide(Local S) { return multiply(S.inverse()); } /** * Local inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public Local inverse() { if (isONE()) { return this; } if (isUnit()) { return new Local(ring, den, num, true); } throw new ArithmeticException("element not invertible " + this); } /** * Local remainder. * @param S Local. * @return this - (this/S)*S. */ public Local remainder(Local S) { if (S.isUnit()) { return ring.getZERO(); } throw new UnsupportedOperationException("remainder not implemented" + S); } /** * Local multiplication. * @param S Local. * @return this*S. */ public Local multiply(Local S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } GenPolynomial n = num.multiply(S.num); GenPolynomial d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Local multiplication by GenPolynomial. * @param b GenPolynomial. * @return this*b. */ public Local multiply(GenPolynomial b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenPolynomial n = num.multiply(b); return new Local(ring, n, den, false); } /** * Local multiplication by coefficient. * @param b coefficient. * @return this*b. */ public Local multiply(C b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenPolynomial n = num.multiply(b); return new Local(ring, n, den, false); } /** * Local multiplication by exponent. * @param e exponent vector. * @return this*b. */ public Local multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } if (num.isZERO()) { return this; } GenPolynomial n = num.multiply(e); return new Local(ring, n, den, false); } /** * Local monic. * @return this with monic value part. */ public Local monic() { if (num.isZERO()) { return this; } return this; // non sense: //C lbc = num.leadingBaseCoefficient(); //lbc = lbc.inverse(); //GenPolynomial n = num.multiply(lbc); //GenPolynomial d = den.multiply(lbc); //return new Local(ring, n, d, true); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public Local gcd(Local b) { GenPolynomial x = ring.engine.gcd(num, b.num); GenPolynomial y = ring.engine.gcd(den, b.den); return new Local(ring, x, y, true); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public Local[] egcd(Local b) { throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/application/LocalRing.java000066400000000000000000000224361445075545500247060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; /** * Local ring class based on GenPolynomial with RingElem interface. Objects of * this class are effective immutable. * @author Heinz Kredel */ public class LocalRing> implements RingFactory>, QuotPairFactory, Local> { private static final Logger logger = LogManager.getLogger(LocalRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisor engine; /** * Polynomial ideal for localization. */ public final Ideal ideal; /** * Polynomial ring of the factory. */ public final GenPolynomialRing ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a LocalRing object from an Ideal. * @param i localization polynomial ideal. */ public LocalRing(Ideal i) { if (i == null) { throw new IllegalArgumentException("ideal may not be null"); } ideal = i.GB(); // cheap if isGB if (ideal.isONE()) { throw new IllegalArgumentException("ideal may not be 1"); } if (ideal.isMaximal()) { isField = 1; } else { isField = 0; logger.warn("ideal not maximal"); //throw new IllegalArgumentException("ideal must be maximal"); } ring = ideal.list.ring; //engine = GCDFactory.getImplementation( ring.coFac ); engine = GCDFactory. getProxy(ring.coFac); } /** * Factory for base elements. */ public GenPolynomialRing pairFactory() { return ring; } /** * Create from numerator. */ public Local create(GenPolynomial n) { return new Local(this, n); } /** * Create from numerator, denominator pair. */ public Local create(GenPolynomial n, GenPolynomial d) { return new Local(this, n, d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.isFinite() && ideal.bb.commonZeroTest(ideal.getList()) <= 0; } /** * Copy Local element c. * @param c * @return a copy of c. */ public Local copy(Local c) { return new Local(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as Local. */ public Local getZERO() { return new Local(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Local. */ public Local getONE() { return new Local(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> pgens = ring.generators(); List> gens = new ArrayList>(pgens.size()); GenPolynomial one = ring.getONE(); for (GenPolynomial p : pgens) { Local q = new Local(this, p); gens.add(q); if (!p.isONE() && !ideal.contains(p)) { // q.isUnit() q = new Local(this, one, p); gens.add(q); } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } // not reached return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Local element from a BigInteger value. * @param a BigInteger. * @return a Local. */ public Local fromInteger(java.math.BigInteger a) { return new Local(this, ring.fromInteger(a)); } /** * Get a Local element from a long value. * @param a long. * @return a Local. */ public Local fromInteger(long a) { return new Local(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "LocalRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "LC(" + ideal.list.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") // not jet working public boolean equals(Object b) { if (!(b instanceof LocalRing)) { return false; } LocalRing a = null; try { a = (LocalRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this local ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * Local random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Local random(int n) { GenPolynomial r = ring.random(n).monic(); r = ideal.normalform(r); GenPolynomial s; do { s = ring.random(n).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new Local(this, r, s, false); } /** * Generate a random residum polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random residue polynomial. */ public Local random(int k, int l, int d, float q) { GenPolynomial r = ring.random(k, l, d, q).monic(); r = ideal.normalform(r); GenPolynomial s; do { s = ring.random(k, l, d, q).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new Local(this, r, s, false); } /** * Local random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public Local random(int n, Random rnd) { GenPolynomial r = ring.random(n, rnd).monic(); r = ideal.normalform(r); GenPolynomial s; do { s = ring.random(n).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new Local(this, r, s, false); } /** * Parse Local from String. * @param s String. * @return Local from s. */ public Local parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { GenPolynomial n = ring.parse(s); return new Local(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); GenPolynomial n = ring.parse(s1); GenPolynomial d = ring.parse(s2); return new Local(this, n, d); } /** * Parse Local from Reader. * @param r Reader. * @return next Local from r. */ public Local parse(Reader r) { String s = StringUtil.nextPairedString(r, '{', '}'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/application/LocalSolvablePolynomial.java000066400000000000000000000541771445075545500276310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.TableRelation; import edu.jas.structure.GcdRingElem; /** * LocalSolvablePolynomial generic recursive solvable polynomials implementing * RingElem. n-variate ordered solvable polynomials over solvable polynomial * coefficients. Objects of this class are intended to be immutable. The * implementation is based on TreeMap respectively SortedMap from exponents to * coefficients by extension of GenPolynomial. * Will be deprecated use QLRSolvablePolynomial. * @param coefficient type * @author Heinz Kredel */ public class LocalSolvablePolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final LocalSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(LocalSolvablePolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero LocalSolvablePolynomial. * @param r solvable polynomial ring factory. */ public LocalSolvablePolynomial(LocalSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for LocalSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public LocalSolvablePolynomial(LocalSolvablePolynomialRing r, SolvableLocal c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for LocalSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public LocalSolvablePolynomial(LocalSolvablePolynomialRing r, SolvableLocal c) { this(r, c, r.evzero); } /** * Constructor for LocalSolvablePolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public LocalSolvablePolynomial(LocalSolvablePolynomialRing r, GenSolvablePolynomial> S) { this(r, S.getMap()); } /** * Constructor for LocalSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected LocalSolvablePolynomial(LocalSolvablePolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public LocalSolvablePolynomialRing factory() { return ring; } /** * Clone this LocalSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public LocalSolvablePolynomial copy() { return new LocalSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof LocalSolvablePolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * LocalSolvablePolynomial multiplication. * @param Bp LocalSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // not @Override public LocalSolvablePolynomial multiply(LocalSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (Bp.isONE()) { return this; } if (this.isONE()) { return Bp; } assert (ring.nvar == Bp.ring.nvar); logger.debug("ring = {}", ring); //System.out.println("this = " + this + ", Bp = " + Bp); ExpVector Z = ring.evzero; LocalSolvablePolynomial Dp = ring.getZERO().copy(); LocalSolvablePolynomial zero = ring.getZERO().copy(); SolvableLocal one = ring.getONECoefficient(); //LocalSolvablePolynomial C1 = null; //LocalSolvablePolynomial C2 = null; Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); for (Map.Entry> y : A.entrySet()) { SolvableLocal a = y.getValue(); ExpVector e = y.getKey(); if (debug) { logger.info("e = {}, a = {}", e, a); } //int[] ep = e.dependencyOnVariables(); //int el1 = ring.nvar + 1; //if (ep.length > 0) { // el1 = ep[0]; //} //int el1s = ring.nvar + 1 - el1; for (Map.Entry> x : Bk) { SolvableLocal b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial with coefficient multiplication LocalSolvablePolynomial Cps = ring.getZERO().copy(); //LocalSolvablePolynomial Cs; LocalSolvablePolynomial qp; if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric Cps = new LocalSolvablePolynomial(ring, b, e); if (debug) logger.info("symmetric coeff: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff: b = {}, e = {}", b, e); // compute e * b as ( e * 1/b.den ) * b.num if (b.den.isONE()) { // recursion base // recursive polynomial coefficient multiplication : e * b.num RecSolvablePolynomial rsp1 = new RecSolvablePolynomial(ring.polCoeff, e); RecSolvablePolynomial rsp2 = new RecSolvablePolynomial(ring.polCoeff, b.num); RecSolvablePolynomial rsp3 = rsp1.multiply(rsp2); LocalSolvablePolynomial rsp = ring.fromPolyCoefficients(rsp3); Cps = rsp; } else { // b.den != 1 if (debug) logger.info("coeff-num: Cps = {}, num = {}, den = {}", Cps, b.num, b.den); Cps = new LocalSolvablePolynomial(ring, b.ring.getONE(), e); // coefficient multiplication with 1/den: LocalSolvablePolynomial qv = Cps; SolvableLocal qden = new SolvableLocal(b.ring, b.den); // den/1 //System.out.println("qv = " + qv + ", den = " + den); // recursion with den==1: LocalSolvablePolynomial v = qv.multiply(qden); LocalSolvablePolynomial vl = qv.multiplyLeft(qden); //System.out.println("v = " + v + ", vl = " + vl + ", qden = " + qden); LocalSolvablePolynomial vr = (LocalSolvablePolynomial) v.subtract(vl); if (qv.leadingExpVector().equals(vr.leadingExpVector())) { throw new IllegalArgumentException("qv !> vr: qv = " + qv + ", vr = " + vr); } SolvableLocal qdeni = new SolvableLocal(b.ring, b.ring.ring.getONE(), b.den); //System.out.println("vr = " + vr + ", qdeni = " + qdeni); // recursion with smaller head term: LocalSolvablePolynomial rq = vr.multiply(qdeni); qp = (LocalSolvablePolynomial) qv.subtract(rq); qp = qp.multiplyLeft(qdeni); //System.out.println("qp_i = " + qp); Cps = qp; if (!b.num.isONE()) { SolvableLocal qnum = new SolvableLocal(b.ring, b.num); // num/1 // recursion with den == 1: Cps = Cps.multiply(qnum); } } } // end coeff if (debug) logger.info("coeff-den: Cps = {}", Cps); // polynomial multiplication LocalSolvablePolynomial Dps = ring.getZERO().copy(); LocalSolvablePolynomial Ds = null; LocalSolvablePolynomial D1, D2; if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly: b = {}, e = {}", b, e); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = new LocalSolvablePolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 SolvableLocal c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (LocalSolvablePolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) { logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); logger.info("poly, g2 = {}, f2 = {}", g2, f2); } TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new LocalSolvablePolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = new LocalSolvablePolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = new LocalSolvablePolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = new LocalSolvablePolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = new LocalSolvablePolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // c * Ds Dps = (LocalSolvablePolynomial) Dps.sum(Ds); } // end Dps loop Ds = Dps; } Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric logger.debug("Ds = {}", Ds); Dp = (LocalSolvablePolynomial) Dp.sum(Ds); } // end B loop } // end A loop //System.out.println("this * Bp = " + Dp); return Dp; } /** * LocalSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S LocalSolvablePolynomial. * @param T LocalSolvablePolynomial. * @return S*this*T. */ // not @Override public LocalSolvablePolynomial multiply(LocalSolvablePolynomial S, LocalSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * LocalSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b solvable coefficient. * @return this*b, where * is coefficient multiplication. */ @Override public LocalSolvablePolynomial multiply(SolvableLocal b) { LocalSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (b.isONE()) { return this; } Cp = new LocalSolvablePolynomial(ring, b, ring.evzero); return multiply(Cp); } /** * LocalSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public LocalSolvablePolynomial multiply(SolvableLocal b, SolvableLocal c) { LocalSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } if (b.isONE() && c.isONE()) { return this; } Cp = new LocalSolvablePolynomial(ring, b, ring.evzero); LocalSolvablePolynomial Dp = new LocalSolvablePolynomial(ring, c, ring.evzero); return multiply(Cp, Dp); } /** * LocalSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableLocal b = ring.getONECoefficient(); return multiply(b, e); } /** * LocalSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public LocalSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } SolvableLocal b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * LocalSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiply(SolvableLocal b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO()) { return this; } LocalSolvablePolynomial Cp = new LocalSolvablePolynomial(ring, b, e); return multiply(Cp); } /** * LocalSolvablePolynomial left and right multiplication. Product with ring * element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public LocalSolvablePolynomial multiply(SolvableLocal b, ExpVector e, SolvableLocal c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO() && c.isONE() && f.isZERO()) { return this; } LocalSolvablePolynomial Cp = new LocalSolvablePolynomial(ring, b, e); LocalSolvablePolynomial Dp = new LocalSolvablePolynomial(ring, c, f); return multiply(Cp, Dp); } /** * LocalSolvablePolynomial multiplication. Left product with ring element * and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiplyLeft(SolvableLocal b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } LocalSolvablePolynomial Cp = new LocalSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * LocalSolvablePolynomial multiplication. Left product with exponent * vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableLocal b = ring.getONECoefficient(); LocalSolvablePolynomial Cp = new LocalSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * LocalSolvablePolynomial multiplication. Left product with coefficient * ring element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public LocalSolvablePolynomial multiplyLeft(SolvableLocal b) { LocalSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map> Cm = Cp.val; //getMap(); Map> Am = val; SolvableLocal c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); SolvableLocal a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * LocalSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * LocalSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public LocalSolvablePolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * LocalSolvablePolynomial multiplication. Left product with coefficient * ring element. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected LocalSolvablePolynomial shift(ExpVector f) { LocalSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); SolvableLocal a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/application/LocalSolvablePolynomialRing.java000066400000000000000000000652711445075545500304460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * LocalSolvablePolynomialRing generic recursive solvable polynomial factory * implementing RingFactory and extending GenSolvablePolynomialRing factory. * Factory for n-variate ordered solvable polynomials over solvable polynomial * coefficients. The non-commutative multiplication relations are maintained in * a relation table and the non-commutative multiplication relations between the * coefficients and the main variables are maintained in a coefficient relation * table. Almost immutable object, except variable names and relation table * contents. * @param coefficient type. * @author Heinz Kredel * will be deprecated use QLRSolvablePolynomialRing */ public class LocalSolvablePolynomialRing> extends GenSolvablePolynomialRing> { /** * Recursive solvable polynomial ring with polynomial coefficients. */ public final RecSolvablePolynomialRing polCoeff; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public final LocalSolvablePolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public final LocalSolvablePolynomial ONE; private static final Logger logger = LogManager.getLogger(LocalSolvablePolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public LocalSolvablePolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public LocalSolvablePolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public LocalSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } SolvableLocalRing cfring = (SolvableLocalRing) cf; // == coFac polCoeff = new RecSolvablePolynomialRing(cfring.ring, n, t, v); if (table.size() > 0) { List>> nt = new ArrayList>>(); for (GenSolvablePolynomial> q : table.relationList()) { nt.add( this.toPolyCoefficients(q) ); // only with den == 1 } polCoeff.table.addSolvRelations(nt); } ZERO = new LocalSolvablePolynomial(this); SolvableLocal coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new LocalSolvablePolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public LocalSolvablePolynomialRing(RingFactory> cf, GenSolvablePolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public LocalSolvablePolynomialRing(RingFactory> cf, LocalSolvablePolynomialRing o) { this(cf, (GenSolvablePolynomialRing) o); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + polCoeff.coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + polCoeff.coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } // if (polCoeff.coeffTable.size() > 0) { // String rel = polCoeff.coeffTable.toScript(); // s.append(",coeffrel="); // s.append(rel); // } s.append(")"); String cpol = polCoeff.toScript(); s.append("\n # "); s.append(cpol); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (!(other instanceof LocalSolvablePolynomialRing)) { return false; } LocalSolvablePolynomialRing oring = null; try { oring = (LocalSolvablePolynomialRing) other; } catch (ClassCastException ignored) { } if (oring == null) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!polCoeff.coeffTable.equals(oring.polCoeff.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + polCoeff.coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as LocalSolvablePolynomial. */ @Override public LocalSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 throw new RuntimeException("zero not 0: " + ZERO); } return ZERO; } /** * Get the one element. * @return 1 as LocalSolvablePolynomial. */ @Override public LocalSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { throw new RuntimeException("one not 1: " + ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (polCoeff.coeffTable.size() == 0) { return super.isCommutative(); } // check structure of relations? return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } LocalSolvablePolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (LocalSolvablePolynomial) gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = (LocalSolvablePolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (LocalSolvablePolynomial) gens.get(k); try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); } catch (IllegalArgumentException e) { //e.printStackTrace(); continue; } if (p.compareTo(q) != 0) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); logger.info("q-p = {}", p.subtract(q)); return false; } } } } return true; //coFac.isAssociative(); } /** * Get a (constant) LocalSolvablePolynomial<C> element from a long * value. * @param a long. * @return a LocalSolvablePolynomial<C>. */ @Override public LocalSolvablePolynomial fromInteger(long a) { return new LocalSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) LocalSolvablePolynomial<C> element from a * BigInteger value. * @param a BigInteger. * @return a LocalSolvablePolynomial<C>. */ @Override public LocalSolvablePolynomial fromInteger(BigInteger a) { return new LocalSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public LocalSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public LocalSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public LocalSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public LocalSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { LocalSolvablePolynomial r = getZERO(); // copy( ZERO ); ExpVector e; SolvableLocal a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (LocalSolvablePolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public LocalSolvablePolynomial copy(LocalSolvablePolynomial c) { return new LocalSolvablePolynomial(this, c.getMap()); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return LocalSolvablePolynomial from s. */ @Override public LocalSolvablePolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next LocalSolvablePolynomial from r. */ @Override @SuppressWarnings("unchecked") public LocalSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); LocalSolvablePolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new LocalSolvablePolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public LocalSolvablePolynomial univariate(int i) { return (LocalSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public LocalSolvablePolynomial univariate(int i, long e) { return (LocalSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public LocalSolvablePolynomial univariate(int modv, int i, long e) { return (LocalSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { LocalSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public LocalSolvablePolynomialRing extend(int i) { return extend(i,false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public LocalSolvablePolynomialRing extend(int i, boolean top) { GenPolynomialRing> pfac = super.extend(i, top); LocalSolvablePolynomialRing spfac = new LocalSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @return extended polynomial ring factory. */ @Override public LocalSolvablePolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ @Override public LocalSolvablePolynomialRing extend(String[] vn, boolean top) { GenPolynomialRing> pfac = super.extend(vn, top); LocalSolvablePolynomialRing spfac = new LocalSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public LocalSolvablePolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); LocalSolvablePolynomialRing spfac = new LocalSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.contract(this.table); spfac.polCoeff.coeffTable.contract(this.polCoeff.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public LocalSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public LocalSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); LocalSolvablePolynomialRing spfac = new LocalSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.partial = partial; spfac.table.reverse(this.table); spfac.polCoeff.coeffTable.reverse(this.polCoeff.coeffTable); return spfac; } /** * Rational function from integral polynomial coefficients. Represent as * polynomial with type SolvableLocal coefficients. * @param A polynomial with integral polynomial coefficients to be * converted. * @return polynomial with type SolvableLocal coefficients. */ public LocalSolvablePolynomial fromPolyCoefficients(GenSolvablePolynomial> A) { LocalSolvablePolynomial B = getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = coFac; SolvableLocalRing qfac = (SolvableLocalRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenSolvablePolynomial a = (GenSolvablePolynomial) y.getValue(); SolvableLocal p = new SolvableLocal(qfac, a); // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(LocalSolvablePolynomial A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableLocal a = y.getValue(); if (!a.den.isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.num; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(GenPolynomial> A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableLocal a = y.getValue(); if (!a.den.isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.num; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } } java-algebra-system-2.7.200/src/edu/jas/application/OrderedCPairlist.java000066400000000000000000000306261445075545500262330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Pair list management. Implemented for ColorPolynomials using TreeMap and * BitSet. * @author Heinz Kredel */ public class OrderedCPairlist> implements Serializable { private static final Logger logger = LogManager.getLogger(OrderedCPairlist.class); protected final GenPolynomialRing> ring; protected final List> P; protected final SortedMap>> pairlist; protected final List red; protected final CReductionSeq reduction; protected boolean oneInGB = false; protected boolean useCriterion4 = false; // unused protected int putCount; protected int remCount; protected final int moduleVars; // unused /** * Constructor for OrderedPairlist. * @param r polynomial factory. */ public OrderedCPairlist(GenPolynomialRing> r) { this(0, r); } /** * Constructor for OrderedPairlist. * @param m number of module variables. * @param r polynomial factory. */ public OrderedCPairlist(int m, GenPolynomialRing> r) { moduleVars = m; ring = r; P = new ArrayList>(); pairlist = new TreeMap>>(ring.tord.getAscendComparator()); // pairlist = new TreeMap( to.getSugarComparator() ); red = new ArrayList(); putCount = 0; remCount = 0; if (ring instanceof GenSolvablePolynomialRing) { useCriterion4 = false; } RingFactory> rf = ring.coFac; GenPolynomialRing cf = (GenPolynomialRing) rf; reduction = new CReductionSeq(cf.coFac); } /** * Internal constructor for OrderedPairlist. Used to clone this pair list. * @param m number of module variables. * @param r polynomial factory. * @param P list of color polynomials. * @param pl critical pair list. * @param red reduction matrix. * @param cred color polynomial reduction engine. * @param pc put count. * @param rc remove count. */ private OrderedCPairlist(int m, GenPolynomialRing> r, List> P, SortedMap>> pl, List red, CReductionSeq cred, int pc, int rc) { moduleVars = m; this.ring = r; this.P = P; pairlist = pl; this.red = red; reduction = cred; putCount = pc; remCount = rc; } /** * Clone this OrderedPairlist. * @return a 2 level clone of this. */ public synchronized OrderedCPairlist copy() { return new OrderedCPairlist(moduleVars, ring, new ArrayList>(P), clonePairlist(), cloneBitSet(), reduction, putCount, remCount); } /** * Clone this pairlist. * @return a 2 level clone of this pairlist. */ private SortedMap>> clonePairlist() { SortedMap>> pl = new TreeMap>>( ring.tord.getAscendComparator()); for (Map.Entry>> m : pairlist.entrySet()) { ExpVector e = m.getKey(); LinkedList> l = m.getValue(); l = new LinkedList>(l); pl.put(e, l); } return pl; } /** * Count remaining Pairs. * @return number of pairs remaining in this pairlist. */ public int pairCount() { int c = 0; for (Map.Entry>> m : pairlist.entrySet()) { LinkedList> l = m.getValue(); c += l.size(); } return c; } /** * Clone this reduction BitSet. * @return a 2 level clone of this reduction BitSet. */ private List cloneBitSet() { List r = new ArrayList(this.red.size()); for (BitSet b : red) { BitSet n = (BitSet) b.clone(); r.add(n); } return r; } /** * bitCount. * @return number of bits set in this bitset. */ public int bitCount() { int c = 0; for (BitSet b : red) { c += b.cardinality(); } return c; } /** * toString. * @return counters of this. */ @Override public String toString() { int p = pairCount(); int b = bitCount(); if (p != b) { return "OrderedCPairlist( pairCount=" + p + ", bitCount=" + b + ", putCount=" + putCount + ", remCount=" + remCount + " )"; } return "OrderedCPairlist( pairCount=" + p + ", putCount=" + putCount + ", remCount=" + remCount + " )"; } /** * Equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object ob) { OrderedCPairlist c = null; try { c = (OrderedCPairlist) ob; } catch (ClassCastException e) { return false; } if (c == null) { return false; } boolean t = getList().equals(c.getList()); if (!t) { return t; } t = pairCount() == c.pairCount(); if (!t) { return t; } return true; } /** * Hash code for this pair list. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = getList().hashCode(); h = h << 7; h += pairCount(); // findbugs return h; } /** * Put one Polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ public synchronized int put(ColorPolynomial p) { putCount++; if (oneInGB) { return P.size() - 1; } ExpVector e = p.leadingExpVector(); // System.out.println("p = " + p); int l = P.size(); for (int j = 0; j < l; j++) { ColorPolynomial pj = P.get(j); // System.out.println("pj = " + pj); ExpVector f = pj.leadingExpVector(); if (moduleVars > 0) { if (e.invLexCompareTo(f, 0, moduleVars) != 0) { continue; // skip pair } } // System.out.println("e = " + e + ", f = " + f); ExpVector g = e.lcm(f); // EVLCM( e, f ); CPair pair = new CPair(pj, p, j, l); // redi = (BitSet)red.get(j); // /if ( j < l ) redi.set( l ); // System.out.println("bitset."+j+" = " + redi ); // multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } // xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); } // System.out.println("pairlist.keys@put = " + pairlist.keySet() ); P.add(p); BitSet redi = new BitSet(); redi.set(0, l); // jdk 1.4 red.add(redi); return P.size() - 1; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ public synchronized CPair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); CPair pair = null; boolean c = false; int i, j; while (!c && ip.hasNext()) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); logger.info("g = {}", g); pair = null; while (!c && xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); //if (useCriterion4) { // c = reduction.criterion4( pair.pi, pair.pj, g ); // c = true; //} c = true; // System.out.println("c4 = " + c); //if (c) { // c = criterion3( i, j, g ); // System.out.println("c3 = " + c); //} red.get(j).clear(i); // set(i,false) jdk1.4 } if (xl.size() == 0) ip.remove(); // = pairlist.remove( g ); } if (!c) { pair = null; } else { remCount++; // count only real pairs } return pair; } /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public synchronized boolean hasNext() { return pairlist.size() > 0; } /** * Get the list of polynomials. * @return the polynomial list. */ public List> getList() { return P; } /** * Get the number of polynomials put to the pairlist. * @return the number of calls to put. */ public synchronized int putCount() { return putCount; } /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public synchronized int remCount() { return remCount; } /** * Put to ONE-Polynomial to the pairlist. * @param one polynomial. (no more required) * @return the index of the last polynomial. */ public synchronized int putOne(ColorPolynomial one) { putCount++; if (one == null) { return P.size() - 1; } if (!one.isONE()) { return P.size() - 1; } oneInGB = true; pairlist.clear(); P.clear(); P.add(one); red.clear(); return P.size() - 1; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s = red.get(j).get(i); if (!s) { logger.warn("c3.s false for j = {}, i = {}", j, i); return s; } // now s = true; for (int k = 0; k < P.size(); k++) { if (i != k && j != k) { ColorPolynomial A = P.get(k); ExpVector ek = A.leadingExpVector(); boolean m = eij.multipleOf(ek); // EVMT(eij,ek); if (m) { if (k < i) { // System.out.println("k < i "+k+" "+i); s = red.get(i).get(k) || red.get(j).get(k); } else if (i < k && k < j) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get(k).get(i) || red.get(j).get(k); } else if (j < k) { // System.out.println("j < k "+j+" "+k); s = red.get(k).get(i) || red.get(k).get(j); } // System.out.println("s."+k+" = " + s); if (!s) { return s; } } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/application/PolyUtilApp.java000066400000000000000000002062701445075545500252560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.root.ComplexRoots; import edu.jas.root.ComplexRootsAbstract; import edu.jas.root.ComplexRootsSturm; import edu.jas.root.Interval; import edu.jas.root.InvalidBoundaryException; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.RealAlgebraicRing; import edu.jas.root.RealRootTuple; import edu.jas.root.RealRootsAbstract; import edu.jas.root.RealRootsSturm; import edu.jas.root.Rectangle; import edu.jas.root.RootFactory; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; /** * Polynomial utilities for applications, for example conversion ExpVector to * Product or zero dimensional ideal root computation. * @param coefficient type * @author Heinz Kredel */ public class PolyUtilApp> { private static final Logger logger = LogManager.getLogger(PolyUtilApp.class); private static final boolean debug = logger.isDebugEnabled(); /** * Product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param L list of polynomials to be represented. * @return Product representation of L in the polynomial ring pfac. */ public static > List>>> toProductRes( GenPolynomialRing>> pfac, List>> L) { List>>> list = new ArrayList>>>(); if (L == null || L.size() == 0) { return list; } GenPolynomial>> b; for (GenPolynomial> a : L) { b = toProductRes(pfac, a); list.add(b); } return list; } /** * Product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param A polynomial to be represented. * @return Product representation of A in the polynomial ring pfac. */ public static > GenPolynomial>> toProductRes( GenPolynomialRing>> pfac, GenPolynomial> A) { GenPolynomial>> P = pfac.getZERO().copy(); if (A == null || A.isZERO()) { return P; } RingFactory>> rpfac = pfac.coFac; ProductRing> fac = (ProductRing>) rpfac; Product> p; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); p = toProductRes(fac, a); if (!p.isZERO()) { P.doPutToMap(e, p); } } return P; } /** * Product representation. * @param coefficient type. * @param pfac product ring factory. * @param c coefficient to be represented. * @return Product representation of c in the ring pfac. */ public static > Product> toProductRes(ProductRing> pfac, GenPolynomial c) { SortedMap> elem = new TreeMap>(); for (int i = 0; i < pfac.length(); i++) { RingFactory> rfac = pfac.getFactory(i); ResidueRing fac = (ResidueRing) rfac; Residue u = new Residue(fac, c); //fac.fromInteger( c.getVal() ); if (!u.isZERO()) { elem.put(i, u); } } return new Product>(pfac, elem); } /** * Product residue representation. * @param coefficient type. * @param CS list of ColoredSystems from comprehensive GB system. * @return Product residue representation of CS. */ public static > List>>> toProductRes( List> CS) { List>>> list = new ArrayList>>>(); if (CS == null || CS.isEmpty()) { return list; } GenPolynomialRing> pr = null; List>> rrl = new ArrayList>>(CS.size()); for (ColoredSystem cs : CS) { Ideal id = cs.condition.zero; ResidueRing r = new ResidueRing(id); if (!rrl.contains(r)) { rrl.add(r); } if (pr == null) { if (cs.list.size() > 0) { pr = cs.list.get(0).green.ring; } } } if (pr == null) { throw new IllegalArgumentException("no polynomial ring found"); } ProductRing> pfac; pfac = new ProductRing>(rrl); //System.out.println("pfac = " + pfac); GenPolynomialRing>> rf = new GenPolynomialRing>>(pfac, pr.nvar, pr.tord, pr.getVars()); GroebnerSystem gs = new GroebnerSystem(CS); List>> F = gs.getCGB(); list = PolyUtilApp. toProductRes(rf, F); return list; } /** * Residue coefficient representation. * @param pfac polynomial ring factory. * @param L list of polynomials to be represented. * @return Representation of L in the polynomial ring pfac. */ public static > List>> toResidue( GenPolynomialRing> pfac, List>> L) { List>> list = new ArrayList>>(); if (L == null || L.size() == 0) { return list; } GenPolynomial> b; for (GenPolynomial> a : L) { b = toResidue(pfac, a); if (!b.isZERO()) { list.add(b); } } return list; } /** * Residue coefficient representation. * @param pfac polynomial ring factory. * @param A polynomial to be represented. * @return Representation of A in the polynomial ring pfac. */ public static > GenPolynomial> toResidue( GenPolynomialRing> pfac, GenPolynomial> A) { GenPolynomial> P = pfac.getZERO().copy(); if (A == null || A.isZERO()) { return P; } RingFactory> rpfac = pfac.coFac; ResidueRing fac = (ResidueRing) rpfac; Residue p; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); p = new Residue(fac, a); if (!p.isZERO()) { P.doPutToMap(e, p); } } return P; } /** * Product slice. * @param coefficient type. * @param L list of polynomials with product coefficients. * @return Slices representation of L. */ public static > Map, PolynomialList>> productSlice( PolynomialList>> L) { Map, PolynomialList>> map; RingFactory>> fpr = L.ring.coFac; ProductRing> pr = (ProductRing>) fpr; int s = pr.length(); map = new TreeMap, PolynomialList>>(); List>> slist; List>>> plist = L.list; PolynomialList> spl; for (int i = 0; i < s; i++) { RingFactory> r = pr.getFactory(i); ResidueRing rr = (ResidueRing) r; Ideal id = rr.ideal; GenPolynomialRing cof = rr.ring; GenPolynomialRing> pfc; pfc = new GenPolynomialRing>(cof, L.ring); slist = fromProduct(pfc, plist, i); spl = new PolynomialList>(pfc, slist); PolynomialList> d = map.get(id); if (d != null) { throw new RuntimeException("ideal exists twice " + id); } map.put(id, spl); } return map; } /** * Product slice at i. * @param coefficient type. * @param L list of polynomials with product coefficients. * @param i index of slice. * @return Slice of of L at i. */ public static > PolynomialList> productSlice( PolynomialList>> L, int i) { RingFactory>> fpr = L.ring.coFac; ProductRing> pr = (ProductRing>) fpr; List>> slist; List>>> plist = L.list; PolynomialList> spl; RingFactory> r = pr.getFactory(i); ResidueRing rr = (ResidueRing) r; GenPolynomialRing cof = rr.ring; GenPolynomialRing> pfc; pfc = new GenPolynomialRing>(cof, L.ring); slist = fromProduct(pfc, plist, i); spl = new PolynomialList>(pfc, slist); return spl; } /** * From product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param L list of polynomials to be converted from product representation. * @param i index of product representation to be taken. * @return Representation of i-slice of L in the polynomial ring pfac. */ public static > List>> fromProduct( GenPolynomialRing> pfac, List>>> L, int i) { List>> list = new ArrayList>>(); if (L == null || L.size() == 0) { return list; } GenPolynomial> b; for (GenPolynomial>> a : L) { b = fromProduct(pfac, a, i); if (!b.isZERO()) { b = b.abs(); if (!list.contains(b)) { list.add(b); } } } return list; } /** * From product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param P polynomial to be converted from product representation. * @param i index of product representation to be taken. * @return Representation of i-slice of P in the polynomial ring pfac. */ public static > GenPolynomial> fromProduct( GenPolynomialRing> pfac, GenPolynomial>> P, int i) { GenPolynomial> b = pfac.getZERO().copy(); if (P == null || P.isZERO()) { return b; } for (Map.Entry>> y : P.getMap().entrySet()) { ExpVector e = y.getKey(); Product> a = y.getValue(); Residue r = a.get(i); if (r != null && !r.isZERO()) { GenPolynomial p = r.val; if (!p.isZERO()) { b.doPutToMap(e, p); } } } return b; } /** * Product slice to String. * @param coefficient type. * @param L list of polynomials with to be represented. * @return Product representation of L in the polynomial ring pfac. */ public static > String productSliceToString( Map, PolynomialList>> L) { //Set>> sl = new TreeSet>>(); PolynomialList> pl = null; StringBuffer sb = new StringBuffer(); //"\nproductSlice ----------------- begin"); for (Map.Entry, PolynomialList>> en : L.entrySet()) { sb.append("\n\ncondition == 0:\n"); sb.append(en.getKey().list.toScript()); pl = en.getValue(); //L.get(id); //sl.addAll(pl.list); sb.append("\ncorresponding ideal:\n"); sb.append(pl.toScript()); } //List>> sll // = new ArrayList>>( sl ); //pl = new PolynomialList>(pl.ring,sll); // sb.append("\nunion = " + pl.toString()); //sb.append("\nproductSlice ------------------------- end\n"); return sb.toString(); } /** * Product slice to String. * @param coefficient type. * @param L list of polynomials with product coefficients. * @return string representation of slices of L. */ public static > String productToString(PolynomialList>> L) { Map, PolynomialList>> M; M = productSlice(L); String s = productSliceToString(M); return s; } /** * Construct superset of complex roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @param eps desired precision. * @return list of coordinates of complex roots for ideal(G) */ public static & Rational> List>> complexRootTuples( Ideal I, BigRational eps) { List> univs = I.constructUnivariate(); logger.info("univs = {}", univs); return complexRoots(I, univs, eps); } /** * Construct superset of complex roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @param univs list of univariate polynomials. * @param eps desired precision. * @return list of coordinates of complex roots for ideal(G) */ public static & Rational> List>> complexRoots( Ideal I, List> univs, BigRational eps) { List>> croots = new ArrayList>>(); RingFactory cf = I.list.ring.coFac; ComplexRing cr = new ComplexRing(cf); ComplexRootsAbstract cra = new ComplexRootsSturm(cr); List>> cunivs = new ArrayList>>(); for (GenPolynomial p : univs) { GenPolynomialRing> pfac = new GenPolynomialRing>(cr, p.ring); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial> cp = PolyUtil. toComplex(pfac, p); cunivs.add(cp); //System.out.println("cp = " + cp); } for (int i = 0; i < I.list.ring.nvar; i++) { List> cri = cra.approximateRoots(cunivs.get(i), eps); //System.out.println("cri = " + cri); croots.add(cri); } croots = ListUtil.> tupleFromList(croots); return croots; } /** * Construct superset of complex roots for zero dimensional ideal(G). * @param Il list of zero dimensional ideals with univariate polynomials. * @param eps desired precision. * @return list of coordinates of complex roots for ideal(cap_i(G_i)) */ public static & Rational> List>> complexRootTuples( List> Il, BigRational eps) { List>> croots = new ArrayList>>(); for (IdealWithUniv I : Il) { List>> cr = complexRoots(I.ideal, I.upolys, eps); croots.addAll(cr); } return croots; } /** * Construct superset of complex roots for zero dimensional ideal(G). * @param Il list of zero dimensional ideals with univariate polynomials. * @param eps desired precision. * @return list of ideals with coordinates of complex roots for * ideal(cap_i(G_i)) */ public static & Rational> List> complexRoots( List> Il, BigRational eps) { List> Ic = new ArrayList>(Il.size()); for (IdealWithUniv I : Il) { List>> cr = complexRoots(I.ideal, I.upolys, eps); IdealWithComplexRoots ic = new IdealWithComplexRoots(I, cr); Ic.add(ic); } return Ic; } /** * Construct superset of complex roots for zero dimensional ideal(G). * @param G list of polynomials of a of zero dimensional ideal. * @param eps desired precision. * @return list of ideals with coordinates of complex roots for ideal(G) */ public static & Rational> List> complexRoots( Ideal G, BigRational eps) { List> Il = G.zeroDimDecomposition(); return complexRoots(Il, eps); } /** * Construct superset of real roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @param eps desired precision. * @return list of coordinates of real roots for ideal(G) */ public static & Rational> List> realRootTuples(Ideal I, BigRational eps) { List> univs = I.constructUnivariate(); logger.info("univs = {}", univs); return realRoots(I, univs, eps); } /** * Construct superset of real roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @param univs list of univariate polynomials. * @param eps desired precision. * @return list of coordinates of real roots for ideal(G) */ public static & Rational> List> realRoots(Ideal I, List> univs, BigRational eps) { List> roots = new ArrayList>(); //RingFactory cf = (RingFactory) I.list.ring.coFac; RealRootsAbstract rra = new RealRootsSturm(); for (int i = 0; i < I.list.ring.nvar; i++) { List rri = rra.approximateRoots(univs.get(i), eps); //System.out.println("rri = " + rri); roots.add(rri); } //System.out.println("roots-1 = " + roots); roots = ListUtil. tupleFromList(roots); //System.out.println("roots-2 = " + roots); return roots; } /** * Construct superset of real roots for zero dimensional ideal(G). * @param Il list of zero dimensional ideals with univariate polynomials. * @param eps desired precision. * @return list of coordinates of real roots for ideal(cap_i(G_i)) */ public static & Rational> List> realRootTuples( List> Il, BigRational eps) { List> rroots = new ArrayList>(); for (IdealWithUniv I : Il) { List> rr = realRoots(I.ideal, I.upolys, eps); rroots.addAll(rr); } return rroots; } /** * Construct superset of real roots for zero dimensional ideal(G). * @param Il list of zero dimensional ideals with univariate polynomials. * @param eps desired precision. * @return list of ideals with coordinates of real roots for * ideal(cap_i(G_i)) */ public static & Rational> List> realRoots( List> Il, BigRational eps) { List> Ir = new ArrayList>(Il.size()); for (IdealWithUniv I : Il) { List> rr = realRoots(I.ideal, I.upolys, eps); IdealWithRealRoots ir = new IdealWithRealRoots(I, rr); Ir.add(ir); } return Ir; } /** * Construct superset of real roots for zero dimensional ideal(G). * @param G list of polynomials of a of zero dimensional ideal. * @param eps desired precision. * @return list of ideals with coordinates of real roots for ideal(G) */ public static & Rational> List> realRoots(Ideal G, BigRational eps) { List> Il = G.zeroDimDecomposition(); return realRoots(Il, eps); } /** * Test for real roots of zero dimensional ideal(L). * @param L list of polynomials. * @param roots list of real roots for ideal(G). * @param eps desired precision. * @return true if root is a list of coordinates of real roots for ideal(L) */ public static boolean isRealRoots(List> L, List> roots, BigDecimal eps) { if (L == null || L.size() == 0) { return true; } // polynomials with decimal coefficients BigDecimal dc = BigDecimal.ONE; //GenPolynomialRing dfac = L.get(0).ring; //System.out.println("dfac = " + dfac); for (GenPolynomial dp : L) { //System.out.println("dp = " + dp); for (List r : roots) { //System.out.println("r = " + r); BigDecimal ev = PolyUtil. evaluateAll(dc, dp, r); if (ev.abs().compareTo(eps) > 0) { System.out.println("ev = " + ev); return false; } } } return true; } /** * Test for complex roots of zero dimensional ideal(L). * @param L list of polynomials. * @param roots list of complex roots for ideal(L). * @param eps desired precision. * @return true if root is a list of coordinates of complex roots for * ideal(L) */ public static boolean isComplexRoots(List>> L, List>> roots, BigDecimal eps) { if (L == null || L.size() == 0) { return true; } // polynomials with decimal coefficients BigDecimal dc = BigDecimal.ONE; ComplexRing dcc = new ComplexRing(dc); //GenPolynomialRing> dfac = L.get(0).ring; //System.out.println("dfac = " + dfac); for (GenPolynomial> dp : L) { //System.out.println("dp = " + dp); for (List> r : roots) { //System.out.println("r = " + r); Complex ev = PolyUtil.> evaluateAll(dcc, dp, r); if (ev.norm().getRe().compareTo(eps) > 0) { System.out.println("ev = " + ev); return false; } } } return true; } /** * Construct real roots for zero dimensional ideal(G). * @param I zero dimensional ideal with univariate irreducible polynomials * and bi-variate polynomials. * @return real algebraic roots for ideal(G) */ public static & Rational> IdealWithRealAlgebraicRoots realAlgebraicRoots( IdealWithUniv I) { List>> ran = new ArrayList>>(); if (I == null) { throw new IllegalArgumentException("null ideal not permitted"); } if (I.ideal == null || I.upolys == null) { throw new IllegalArgumentException("null ideal components not permitted " + I); } if (I.ideal.isZERO() || I.upolys.size() == 0) { return new IdealWithRealAlgebraicRoots(I, ran); } GenPolynomialRing fac = I.ideal.list.ring; // case i == 0: GenPolynomial p0 = I.upolys.get(0); GenPolynomial p0p = PolyUtil. selectWithVariable(I.ideal.list.list, fac.nvar - 1); if (p0p == null) { throw new RuntimeException("no polynomial found in " + (fac.nvar - 1) + " of " + I.ideal); } //System.out.println("p0 = " + p0); logger.info("p0p = {}", p0p); int[] dep0 = p0p.degreeVector().dependencyOnVariables(); //System.out.println("dep0 = " + Arrays.toString(dep0)); if (dep0.length != 1) { throw new RuntimeException("wrong number of variables " + Arrays.toString(dep0)); } List> rra = RootFactory. realAlgebraicNumbersIrred(p0); if (logger.isInfoEnabled()) { List> il = new ArrayList>(); for (RealAlgebraicNumber rr : rra) { il.add(rr.ring.getRoot()); } logger.info("roots(p0) = {}", il); } for (RealAlgebraicNumber rr : rra) { List> rl = new ArrayList>(); rl.add(rr); ran.add(rl); } // case i > 0: for (int i = 1; i < I.upolys.size(); i++) { List>> rn = new ArrayList>>(); GenPolynomial pi = I.upolys.get(i); GenPolynomial pip = PolyUtil.selectWithVariable(I.ideal.list.list, fac.nvar - 1 - i); if (pip == null) { throw new RuntimeException( "no polynomial found in " + (fac.nvar - 1 - i) + " of " + I.ideal); } //System.out.println("i = " + i); //System.out.println("pi = " + pi); //System.out.println("pip = " + pip); logger.info("pi = {}, pip = {}", pi, pip); int[] depi = pip.degreeVector().dependencyOnVariables(); //System.out.println("depi = " + Arrays.toString(depi)); if (depi.length < 1 || depi.length > 2) { throw new RuntimeException("wrong number of variables " + Arrays.toString(depi)); } rra = RootFactory. realAlgebraicNumbersIrred(pi); //System.out.println("rra = " + rra); if (logger.isInfoEnabled()) { List> il = new ArrayList>(); for (RealAlgebraicNumber rr : rra) { il.add(rr.ring.getRoot()); } logger.info("roots(pi) = {}", il); } if (depi.length == 1) { // all combinations are roots of the ideal I for (RealAlgebraicNumber rr : rra) { //System.out.println("rr.ring = " + rr.ring); for (List> rx : ran) { //System.out.println("rx = " + rx); List> ry = new ArrayList>(); ry.addAll(rx); ry.add(rr); rn.add(ry); } } } else { // depi.length == 2 // select roots of the ideal I GenPolynomial pip2 = PolyUtil. removeUnusedUpperVariables(pip); //System.out.println("pip2 = " + pip2.ring); GenPolynomialRing ufac = pip2.ring.contract(1); TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing> rfac = new GenPolynomialRing>(ufac, 1, to); // new vars GenPolynomial> pip2r = PolyUtil. recursive(rfac, pip2); int ix = fac.nvar - 1 - depi[depi.length - 1]; //System.out.println("ix = " + ix); for (RealAlgebraicNumber rr : rra) { //System.out.println("rr.ring = " + rr.ring); Interval rroot = rr.ring.getRoot(); GenPolynomial pip2el = PolyUtil. evaluateMainRecursive(ufac, pip2r, rroot.left); GenPolynomial pip2er = PolyUtil. evaluateMainRecursive(ufac, pip2r, rroot.right); GenPolynomialRing upfac = I.upolys.get(ix).ring; GenPolynomial pip2elc = convert(upfac, pip2el); GenPolynomial pip2erc = convert(upfac, pip2er); //System.out.println("pip2elc = " + pip2elc); //System.out.println("pip2erc = " + pip2erc); for (List> rx : ran) { //System.out.println("rx = " + rx); RealAlgebraicRing rar = rx.get(ix).ring; //System.out.println("rar = " + rar.toScript()); RealAlgebraicNumber rel = new RealAlgebraicNumber(rar, pip2elc); RealAlgebraicNumber rer = new RealAlgebraicNumber(rar, pip2erc); int sl = rel.signum(); int sr = rer.signum(); //System.out.println("sl = " + sl + ", sr = " + sr + ", sl*sr = " + (sl*sr)); if (sl * sr <= 0) { //System.out.println("sl * sr <= 0: rar = " + rar.toScript()); List> ry = new ArrayList>(); ry.addAll(rx); ry.add(rr); rn.add(ry); } } } } ran = rn; } //System.out.println("ran = " + ran); if (logger.isInfoEnabled()) { for (List> rz : ran) { List> il = new ArrayList>(); for (RealAlgebraicNumber rr : rz) { il.add(rr.ring.getRoot()); } logger.info("root-tuple = {}", il); } } IdealWithRealAlgebraicRoots Ir = new IdealWithRealAlgebraicRoots(I, ran); return Ir; } /** * Construct real roots for zero dimensional ideal(G). * @param I list of zero dimensional ideal with univariate irreducible * polynomials and bi-variate polynomials. * @return list of real algebraic roots for all ideal(I_i) */ public static & Rational> List> realAlgebraicRoots( List> I) { List> lir = new ArrayList>(I.size()); for (IdealWithUniv iu : I) { IdealWithRealAlgebraicRoots iur = PolyUtilApp. realAlgebraicRoots(iu); //System.out.println("iur = " + iur); lir.add(iur); } return lir; } /** * Construct complex roots for zero dimensional ideal(G). * @param I zero dimensional ideal with univariate irreducible polynomials * and bi-variate polynomials. * @return complex algebraic roots for ideal(G) Note: not jet * completed in all cases. */ public static & Rational> IdealWithComplexAlgebraicRoots complexAlgebraicRoots( IdealWithUniv I) { List>>> can; can = new ArrayList>>>(); if (I == null) { throw new IllegalArgumentException("null ideal not permitted"); } if (I.ideal == null || I.upolys == null) { throw new IllegalArgumentException("null ideal components not permitted " + I); } if (I.ideal.isZERO() || I.upolys.size() == 0) { return new IdealWithComplexAlgebraicRoots(I, can); } GenPolynomialRing fac = I.ideal.list.ring; if (fac.nvar == 0) { return new IdealWithComplexAlgebraicRoots(I, can); } if (fac.nvar != I.upolys.size()) { throw new IllegalArgumentException("ideal not zero dimnsional: " + I); } // case i == 0: GenPolynomial p0 = I.upolys.get(0); GenPolynomial p0p = PolyUtil. selectWithVariable(I.ideal.list.list, fac.nvar - 1); if (p0p == null) { throw new RuntimeException("no polynomial found in " + (fac.nvar - 1) + " of " + I.ideal); } logger.info("p0 = {}, p0p = {}", p0, p0p); int[] dep0 = p0p.degreeVector().dependencyOnVariables(); //System.out.println("dep0 = " + Arrays.toString(dep0)); if (dep0.length != 1) { throw new RuntimeException("wrong number of variables " + Arrays.toString(dep0)); } RingFactory cfac = p0.ring.coFac; ComplexRing ccfac = new ComplexRing(cfac); GenPolynomialRing> facc = new GenPolynomialRing>(ccfac, p0.ring); GenPolynomial> p0c = PolyUtil. complexFromAny(facc, p0); List>> cra; cra = edu.jas.application.RootFactoryApp. complexAlgebraicNumbersSquarefree(p0c); logger.info("#roots(p0c) = {}", cra.size()); for (Complex> cr : cra) { List>> cl; cl = new ArrayList>>(); cl.add(cr); can.add(cl); } if (fac.nvar == 1) { return new IdealWithComplexAlgebraicRoots(I, can); } // case i > 0: for (int i = 1; i < I.upolys.size(); i++) { List>>> cn; cn = new ArrayList>>>(); GenPolynomial pi = I.upolys.get(i); GenPolynomial pip = PolyUtil.selectWithVariable(I.ideal.list.list, fac.nvar - 1 - i); if (pip == null) { throw new RuntimeException( "no polynomial found in " + (fac.nvar - 1 - i) + " of " + I.ideal); } if (logger.isInfoEnabled()) { logger.info("pi({}) = {}", i, pi); logger.info("pip = {}", pip); } facc = new GenPolynomialRing>(ccfac, pi.ring); GenPolynomial> pic = PolyUtil. complexFromAny(facc, pi); int[] depi = pip.degreeVector().dependencyOnVariables(); //System.out.println("depi = " + Arrays.toString(depi)); if (depi.length < 1 || depi.length > 2) { throw new RuntimeException( "wrong number of variables " + Arrays.toString(depi) + " for " + pip); } cra = edu.jas.application.RootFactoryApp. complexAlgebraicNumbersSquarefree(pic); logger.info("#roots(pic) = {}", cra.size()); if (depi.length == 1) { // all combinations are roots of the ideal I for (Complex> cr : cra) { //System.out.println("cr.ring = " + cr.ring); for (List>> cx : can) { //System.out.println("cx = " + cx); List>> cy; cy = new ArrayList>>(); cy.addAll(cx); cy.add(cr); cn.add(cy); } } } else { // depi.length == 2 // select roots of the ideal I GenPolynomial pip2 = PolyUtil. removeUnusedUpperVariables(pip); pip2 = PolyUtil. removeUnusedLowerVariables(pip2); pip2 = PolyUtil. removeUnusedMiddleVariables(pip2); GenPolynomialRing> rfac = pip2.ring.recursive(1); GenPolynomialRing ufac = pip2.ring.contract(1); GenPolynomialRing> ucfac = new GenPolynomialRing>(ccfac, ufac); GenPolynomialRing> c2fac = new GenPolynomialRing>(ccfac, pip2.ring); GenPolynomial> pip2c = PolyUtil. complexFromAny(c2fac, pip2); GenPolynomialRing>> rcfac; rcfac = new GenPolynomialRing>>(ucfac, rfac); GenPolynomial>> pip2cr = PolyUtil.> recursive(rcfac, pip2c); //System.out.println("pip2cr = " + pip2cr); int ix = fac.nvar - 1 - depi[depi.length - 1]; //System.out.println("ix = " + ix); for (Complex> cr : cra) { //System.out.println("cr = " + toString(cr)); edu.jas.application.RealAlgebraicRing cring = (edu.jas.application.RealAlgebraicRing) cr.ring.ring; RealRootTuple rroot = cring.getRoot(); List> rlist = rroot.tuple; //System.out.println("rlist = " + rlist); Interval vr = rlist.get(0).ring.getRoot(); Interval vi = rlist.get(1).ring.getRoot(); //logger.info("vr = {}, vi = {}", vr, vi); edu.jas.application.RealAlgebraicNumber vrl, vil, vrr, vir; vrl = new edu.jas.application.RealAlgebraicNumber(cring, vr.left); vil = new edu.jas.application.RealAlgebraicNumber(cring, vi.left); vrr = new edu.jas.application.RealAlgebraicNumber(cring, vr.right); vir = new edu.jas.application.RealAlgebraicNumber(cring, vi.right); ComplexRing> crr; crr = new ComplexRing>(cring); Complex> csw, cne; csw = new Complex>(crr, vrl, vil); cne = new Complex>(crr, vrr, vir); //logger.info("csw = {}, cne = {}", toString(csw), toString(cne)); Rectangle> rec; rec = new Rectangle>(csw, cne); //System.out.println("rec = " + rec); for (List>> cx : can) { Complex> cax = cx.get(ix); //System.out.println("cax = " + toString(cax)); ComplexRing> car = cax.ring; //System.out.println("car = " + car); GenPolynomialRing>> pcrfac; pcrfac = new GenPolynomialRing>>( car, rcfac); GenPolynomial>> pcr; pcr = evaluateToComplexRealCoefficients(pcrfac, pip2cr, cax); //System.out.println("pcr = " + pcr); ComplexRoots> rengine; rengine = new ComplexRootsSturm>(car); long nr = 0; try { nr = rengine.complexRootCount(rec, pcr); //logger.info("rootCount = {}", nr); } catch (InvalidBoundaryException e) { e.printStackTrace(); } if (nr == 1) { // one root logger.info(" hit, cxi = {}, cr = {}", toString(cx.get(ix)), toString(cr)); List>> cy; cy = new ArrayList>>(); cy.addAll(cx); cy.add(cr); cn.add(cy); } else if (nr > 1) { logger.error("to many roots, cxi = {}, cr = {}", toString(cx.get(ix)), toString(cr)); } else { // no root logger.info("no hit, cxi = {}, cr = {}", toString(cx.get(ix)), toString(cr)); } } } } can = cn; } IdealWithComplexAlgebraicRoots Ic = new IdealWithComplexAlgebraicRoots(I, can); return Ic; } /** * String representation of a deximal approximation of a complex number. * @param c compelx number. * @return String representation of c */ public static & Rational> String toString( Complex> c) { edu.jas.application.RealAlgebraicNumber re = c.getRe(); edu.jas.application.RealAlgebraicNumber im = c.getIm(); String s = re.decimalMagnitude().toString(); if (!im.isZERO()) { s = s + "i" + im.decimalMagnitude(); } return s; } /** * String representation of a deximal approximation of a complex number. * @param c compelx number. * @return String representation of c */ public static & Rational> String toString1(Complex c) { D re = c.getRe(); D im = c.getIm(); String s = new BigDecimal(re.getRational()).toString(); if (!im.isZERO()) { s = s + "i" + new BigDecimal(im.getRational()); } return s; } /** * Construct complex roots for zero dimensional ideal(G). * @param I list of zero dimensional ideal with univariate irreducible * polynomials and bi-variate polynomials. * @return list of complex algebraic roots for ideal(G) */ public static & Rational> List> complexAlgebraicRoots( List> I) { List> lic = new ArrayList>(); for (IdealWithUniv iu : I) { IdealWithComplexAlgebraicRoots iuc = PolyUtilApp. complexAlgebraicRoots(iu); //System.out.println("iuc = " + iuc); lic.add(iuc); } return lic; } /** * Construct exact set of complex roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @return list of coordinates of complex roots for ideal(G) */ public static & Rational> List> complexAlgebraicRoots( Ideal I) { List> Ir = I.zeroDimRootDecomposition(); //System.out.println("Ir = " + Ir); List> roots = PolyUtilApp. complexAlgebraicRoots(Ir); return roots; } /* * Convert to a polynomial in given ring. * @param fac result polynomial ring. * @param p polynomial. * @return polynomial in ring fac Note: if p can not be represented * in fac then the results are unpredictable. */ static > GenPolynomial convert(GenPolynomialRing fac, GenPolynomial p) { if (fac.equals(p.factory())) { return p; } GenPolynomial q = fac.parse(p.toString()); if (!q.toString().equals(p.toString())) { throw new RuntimeException("convert(" + p + ") = " + q); } return q; } /* * Convert to a polynomial in given ring. * @param fac result polynomial ring. * @param p polynomial. * @return polynomial in ring fac Note: if p can not be represented * in fac then the results are unpredictable. */ static > GenPolynomial> convertComplex(GenPolynomialRing> fac, GenPolynomial p) { GenPolynomial> q = fac.parse(p.toString()); if (!q.toString().equals(p.toString())) { throw new RuntimeException("convert(" + p + ") = " + q); } return q; } /* * Convert to a polynomial in given ring. * @param fac result polynomial ring. * @param p complex polynomial. * @return polynomial in ring fac Note: if p can not be represented * in fac then the results are unpredictable. */ static > GenPolynomial> convertComplexComplex( GenPolynomialRing> fac, GenPolynomial> p) { if (fac.equals(p.factory())) { return p; } GenPolynomial> q = fac.parse(p.toString()); if (!q.toString().equals(p.toString())) { throw new RuntimeException("convert(" + p + ") = " + q); } return q; } /** * Construct exact set of real roots for zero dimensional ideal(G). * @param I zero dimensional ideal. * @return list of coordinates of real roots for ideal(G) */ public static & Rational> List> realAlgebraicRoots( Ideal I) { List> Ir = I.zeroDimRootDecomposition(); //System.out.println("Ir = " + Ir); List> roots = PolyUtilApp. realAlgebraicRoots(Ir); return roots; } /** * Construct primitive element for double field extension. * @param a algebraic number ring with squarefree monic minimal polynomial * @param b algebraic number ring with squarefree monic minimal polynomial * @return primitive element container with algebraic number ring c, with * Q(c) = Q(a,b) */ public static > PrimitiveElement primitiveElement(AlgebraicNumberRing a, AlgebraicNumberRing b) { GenPolynomial ap = a.modul; GenPolynomial bp = b.modul; // setup bivariate polynomial ring String[] cv = new String[2]; cv[0] = ap.ring.getVars()[0]; cv[1] = bp.ring.getVars()[0]; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing cfac = new GenPolynomialRing(ap.ring.coFac, 2, to, cv); GenPolynomial as = ap.extendUnivariate(cfac, 0); GenPolynomial bs = bp.extendUnivariate(cfac, 1); List> L = new ArrayList>(2); L.add(as); L.add(bs); List> Op = new ArrayList>(); Ideal id = new Ideal(cfac, L); //System.out.println("id = " + id); IdealWithUniv iu = id.normalPositionFor(0, 1, Op); //System.out.println("iu = " + iu); // extract result polynomials List> Np = iu.ideal.getList(); //System.out.println("Np = " + Np); as = PolyUtil. selectWithVariable(Np, 1); bs = PolyUtil. selectWithVariable(Np, 0); GenPolynomial cs = PolyUtil. selectWithVariable(Np, 2); //System.out.println("as = " + as); //System.out.println("bs = " + bs); //System.out.println("cs = " + cs); String[] ev = new String[] { cs.ring.getVars()[0] }; GenPolynomialRing efac = new GenPolynomialRing(ap.ring.coFac, 1, to, ev); //System.out.println("efac = " + efac); cs = cs.contractCoeff(efac); //System.out.println("cs = " + cs); as = as.reductum().contractCoeff(efac); as = as.negate(); //System.out.println("as = " + as); bs = bs.reductum().contractCoeff(efac); bs = bs.negate(); //System.out.println("bs = " + bs); AlgebraicNumberRing c = new AlgebraicNumberRing(cs); AlgebraicNumber ab = new AlgebraicNumber(c, as); AlgebraicNumber bb = new AlgebraicNumber(c, bs); PrimitiveElement pe = new PrimitiveElement(c, ab, bb, a, b); logger.info("primitive element = {}", c); return pe; } /** * Convert to primitive element ring. * @param cfac primitive element ring. * @param A algebraic number representing the generating element of a in the * new ring. * @param a algebraic number to convert. * @return a converted to the primitive element ring */ public static > AlgebraicNumber convertToPrimitiveElem( AlgebraicNumberRing cfac, AlgebraicNumber A, AlgebraicNumber a) { GenPolynomialRing aufac = a.ring.ring; GenPolynomialRing> ar = new GenPolynomialRing>(cfac, aufac); GenPolynomial> aps = PolyUtil. convertToAlgebraicCoefficients(ar, a.val); AlgebraicNumber ac = PolyUtil.> evaluateMain(cfac, aps, A); return ac; } /** * Convert coefficients to primitive element ring. * @param cfac primitive element ring. * @param A algebraic number representing the generating element of a in the * new ring. * @param a polynomial with coefficients algebraic number to convert. * @return a with coefficients converted to the primitive element ring */ public static > GenPolynomial> convertToPrimitiveElem( AlgebraicNumberRing cfac, AlgebraicNumber A, GenPolynomial> a) { GenPolynomialRing> cr = new GenPolynomialRing>(cfac, a.ring); return PolyUtil., AlgebraicNumber> map(cr, a, new CoeffConvertAlg(cfac, A)); } /** * Convert to primitive element ring. * @param cfac primitive element ring. * @param A algebraic number representing the generating element of a in the * new ring. * @param a recursive algebraic number to convert. * @return a converted to the primitive element ring */ public static > AlgebraicNumber convertToPrimitiveElem( AlgebraicNumberRing cfac, AlgebraicNumber A, AlgebraicNumber B, AlgebraicNumber> a) { GenPolynomial> aps = PolyUtilApp. convertToPrimitiveElem(cfac, A, a.val); AlgebraicNumber ac = PolyUtil.> evaluateMain(cfac, aps, B); return ac; } /** * Construct primitive element for double field extension. * @param b algebraic number ring with squarefree monic minimal polynomial * over Q(a) * @return primitive element container with algebraic number ring c, with * Q(c) = Q(a)(b) */ public static > PrimitiveElement primitiveElement( AlgebraicNumberRing> b) { GenPolynomial> bp = b.modul; AlgebraicNumberRing a = (AlgebraicNumberRing) b.ring.coFac; GenPolynomial ap = a.modul; // setup bivariate polynomial ring String[] cv = new String[2]; cv[0] = ap.ring.getVars()[0]; cv[1] = bp.ring.getVars()[0]; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing cfac = new GenPolynomialRing(ap.ring.coFac, 2, to, cv); GenPolynomialRing> rfac = new GenPolynomialRing>(a.ring, 1, bp.ring.getVars()); GenPolynomial as = ap.extendUnivariate(cfac, 0); GenPolynomial> bss = PolyUtil. fromAlgebraicCoefficients(rfac, bp); GenPolynomial bs = PolyUtil. distribute(cfac, bss); List> L = new ArrayList>(2); L.add(as); L.add(bs); List> Op = new ArrayList>(); Ideal id = new Ideal(cfac, L); //System.out.println("id = " + id); IdealWithUniv iu = id.normalPositionFor(0, 1, Op); //System.out.println("iu = " + iu); // extract result polynomials List> Np = iu.ideal.getList(); as = PolyUtil. selectWithVariable(Np, 1); bs = PolyUtil. selectWithVariable(Np, 0); GenPolynomial cs = PolyUtil. selectWithVariable(Np, 2); //System.out.println("as = " + as); //System.out.println("bs = " + bs); //System.out.println("cs = " + cs); String[] ev = new String[] { cs.ring.getVars()[0] }; GenPolynomialRing efac = new GenPolynomialRing(ap.ring.coFac, 1, to, ev); // System.out.println("efac = " + efac); cs = cs.contractCoeff(efac); // System.out.println("cs = " + cs); as = as.reductum().contractCoeff(efac); as = as.negate(); // System.out.println("as = " + as); bs = bs.reductum().contractCoeff(efac); bs = bs.negate(); //System.out.println("bs = " + bs); AlgebraicNumberRing c = new AlgebraicNumberRing(cs); AlgebraicNumber ab = new AlgebraicNumber(c, as); AlgebraicNumber bb = new AlgebraicNumber(c, bs); PrimitiveElement pe = new PrimitiveElement(c, ab, bb); // missing ,a,b); logger.info("primitive element = {}", pe); return pe; } /** * Convert to primitive element ring. * @param cfac primitive element ring. * @param A algebraic number representing the generating element of a in the * new ring. * @param a polynomial with recursive algebraic number coefficients to * convert. * @return a converted to the primitive element ring */ public static > GenPolynomial> convertToPrimitiveElem( AlgebraicNumberRing cfac, AlgebraicNumber A, AlgebraicNumber B, GenPolynomial>> a) { GenPolynomialRing> cr = new GenPolynomialRing>(cfac, a.ring); return PolyUtil.>, AlgebraicNumber> map(cr, a, new CoeffRecConvertAlg(cfac, A, B)); } /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients from package * edu.jas.root. * @param afac result polynomial factory. * @param A polynomial with RealAlgebraicNumber<C> coefficients to be * converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> realAlgFromRealCoefficients( GenPolynomialRing> afac, GenPolynomial> A) { edu.jas.root.RealAlgebraicRing cfac = (edu.jas.root.RealAlgebraicRing) afac.coFac; return PolyUtil., edu.jas.root.RealAlgebraicNumber> map( afac, A, new ReAlgFromRealCoeff(cfac)); } /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients from package * *
     * edu.jas.application
     * 
* * . * @param rfac result polynomial factory. * @param A polynomial with RealAlgebraicNumber<C> coefficients to be * converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> realFromRealAlgCoefficients( GenPolynomialRing> rfac, GenPolynomial> A) { edu.jas.application.RealAlgebraicRing cfac = (edu.jas.application.RealAlgebraicRing) rfac.coFac; return PolyUtil., edu.jas.application.RealAlgebraicNumber> map( rfac, A, new RealFromReAlgCoeff(cfac)); } /** * Convert to Complex<RealAlgebraicNumber> coefficients. Represent as * polynomial with Complex<RealAlgebraicNumber> coefficients, C is * e.g. BigRational. * @param pfac result polynomial factory. * @param A polynomial with Complex coefficients to be converted. * @return polynomial with Complex<RealAlgebraicNumber> coefficients. */ public static & Rational> GenPolynomial>> convertToComplexRealCoefficients( GenPolynomialRing>> pfac, GenPolynomial> A) { ComplexRing> afac; afac = (ComplexRing>) pfac.coFac; return PolyUtil., Complex>> map(pfac, A, new CoeffToComplexReal(afac)); } /** * Evaluate to Complex<RealAlgebraicNumber> coefficients. Represent as * polynomial with Complex<RealAlgebraicNumber> coefficients, C is * e.g. BigRational. * @param pfac result polynomial factory. * @param A = A(x,Y) a recursive polynomial with * GenPolynomial<Complex> coefficients to be converted. * @param r Complex<RealAlgebraicNumber> to be evaluated at. * @return A(r,Y), a polynomial with Complex<RealAlgebraicNumber> * coefficients. */ public static & Rational> GenPolynomial>> evaluateToComplexRealCoefficients( GenPolynomialRing>> pfac, GenPolynomial>> A, Complex> r) { return PolyUtil.>, Complex>> map( pfac, A, new EvaluateToComplexReal(pfac, r)); } } /** * Coefficient to convert algebriac functor. */ class CoeffConvertAlg> implements UnaryFunctor, AlgebraicNumber> { final protected AlgebraicNumberRing afac; final protected AlgebraicNumber A; public CoeffConvertAlg(AlgebraicNumberRing fac, AlgebraicNumber a) { if (fac == null || a == null) { throw new IllegalArgumentException("fac and a must not be null"); } afac = fac; A = a; } public AlgebraicNumber eval(AlgebraicNumber c) { if (c == null) { return afac.getZERO(); } return PolyUtilApp. convertToPrimitiveElem(afac, A, c); } } /** * Coefficient recursive to convert algebriac functor. */ class CoeffRecConvertAlg> implements UnaryFunctor>, AlgebraicNumber> { final protected AlgebraicNumberRing afac; final protected AlgebraicNumber A; final protected AlgebraicNumber B; public CoeffRecConvertAlg(AlgebraicNumberRing fac, AlgebraicNumber a, AlgebraicNumber b) { if (fac == null || a == null || b == null) { throw new IllegalArgumentException("fac, a and b must not be null"); } afac = fac; A = a; B = b; } public AlgebraicNumber eval(AlgebraicNumber> c) { if (c == null) { return afac.getZERO(); } return PolyUtilApp. convertToPrimitiveElem(afac, A, B, c); } } /** * Coefficient to real algebriac from real algebraic functor. */ class ReAlgFromRealCoeff & Rational> implements UnaryFunctor, edu.jas.root.RealAlgebraicNumber> { final protected edu.jas.root.RealAlgebraicRing afac; public ReAlgFromRealCoeff(edu.jas.root.RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; } @SuppressWarnings("unchecked") public edu.jas.root.RealAlgebraicNumber eval(edu.jas.application.RealAlgebraicNumber c) { if (c == null) { return afac.getZERO(); } return (edu.jas.root.RealAlgebraicNumber) (Object) c.number; // force ignore recursion } } /** * Coefficient to real algebriac from algebraic functor. */ class RealFromReAlgCoeff & Rational> implements UnaryFunctor, edu.jas.application.RealAlgebraicNumber> { final protected edu.jas.application.RealAlgebraicRing rfac; public RealFromReAlgCoeff(edu.jas.application.RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } rfac = fac; } @SuppressWarnings("unchecked") public edu.jas.application.RealAlgebraicNumber eval(edu.jas.root.RealAlgebraicNumber c) { if (c == null) { return rfac.getZERO(); } edu.jas.root.RealAlgebraicNumber> rrc = (edu.jas.root.RealAlgebraicNumber>) (Object) c; // force resurrect recursion return new edu.jas.application.RealAlgebraicNumber(rfac, rrc); } } /** * Coefficient to complex real algebriac functor. */ class CoeffToComplexReal & Rational> implements UnaryFunctor, Complex>> { final protected ComplexRing> cfac; final edu.jas.application.RealAlgebraicRing afac; final GenPolynomialRing pfac; public CoeffToComplexReal(ComplexRing> fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = fac; afac = (edu.jas.application.RealAlgebraicRing) cfac.ring; pfac = afac.univs.ideal.getRing(); } public Complex> eval(Complex c) { if (c == null) { return cfac.getZERO(); } GenPolynomial pr, pi; pr = new GenPolynomial(pfac, c.getRe()); pi = new GenPolynomial(pfac, c.getIm()); //System.out.println("pr = " + pr); //System.out.println("pi = " + pi); edu.jas.application.RealAlgebraicNumber re, im; re = new edu.jas.application.RealAlgebraicNumber(afac, pr); im = new edu.jas.application.RealAlgebraicNumber(afac, pi); //System.out.println("re = " + re); //System.out.println("im = " + im); return new Complex>(cfac, re, im); } } /** * Polynomial coefficient to complex real algebriac evaluation functor. */ class EvaluateToComplexReal & Rational> implements UnaryFunctor>, Complex>> { final protected GenPolynomialRing>> pfac; final protected ComplexRing> cfac; final protected Complex> root; public EvaluateToComplexReal(GenPolynomialRing>> fac, Complex> r) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } if (r == null) { throw new IllegalArgumentException("r must not be null"); } pfac = fac; cfac = (ComplexRing>) fac.coFac; root = r; //System.out.println("cfac = " + cfac); //System.out.println("root = " + root); } public Complex> eval(GenPolynomial> c) { if (c == null) { return cfac.getZERO(); } //System.out.println("c = " + c); GenPolynomial>> cp; cp = PolyUtilApp. convertToComplexRealCoefficients(pfac, c); Complex> cr; cr = PolyUtil.>> evaluateMain(cfac, cp, root); return cr; } } java-algebra-system-2.7.200/src/edu/jas/application/PrimaryComponent.java000066400000000000000000000042471445075545500263420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import edu.jas.structure.GcdRingElem; /** * Container for primary components of ideals. * @author Heinz Kredel */ public class PrimaryComponent> implements Serializable { /** * The primary ideal. */ public final Ideal primary; /** * The associated prime ideal. */ public final IdealWithUniv prime; /** * The exponent of prime for primary. */ protected int exponent; /** * Constructor not for use. */ protected PrimaryComponent() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param q the primary ideal * @param p the prime ideal. */ protected PrimaryComponent(Ideal q, IdealWithUniv p) { this(q, p, -1); } /** * Constructor. * @param q the primary ideal * @param p the prime ideal. * @param e the exponent of p for q. */ protected PrimaryComponent(Ideal q, IdealWithUniv p, int e) { primary = q; prime = p; exponent = e; } /** * Get exponent. * @return exponent. */ public int getExponent() { return exponent; } /** * Set exponent. * @param e the exponent. */ public void setExponent(int e) { exponent = e; } /** * String representation of the ideal. * @see java.lang.Object#toString() */ @Override public String toString() { String s = "\nprimary:\n" + primary.toString() + "\nprime:\n" + prime.toString(); if (exponent < 0) { return s; } return s + "\nexponent:\n" + exponent; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case String s = primary.toScript() + ", " + prime.toString(); if (exponent < 0) { return s; } return s + ", " + exponent; } } java-algebra-system-2.7.200/src/edu/jas/application/PrimitiveElement.java000066400000000000000000000057261445075545500263210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import edu.jas.structure.GcdRingElem; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; /** * Container for primitive elements. * @author Heinz Kredel */ public class PrimitiveElement> implements Serializable { /** * The primitive element. */ public final AlgebraicNumberRing primitiveElem; /** * The representation of the first algebraic element in the new ring. */ public final AlgebraicNumber A; /** * The representation of the second algebraic element in the new ring. */ public final AlgebraicNumber B; /** * The first original algebraic ring. */ public final AlgebraicNumberRing Aring; /** * The second original algebraic ring. */ public final AlgebraicNumberRing Bring; /** * Constructor not for use. */ protected PrimitiveElement() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param pe the primitive element * @param A the first element. * @param B the second element. */ protected PrimitiveElement(AlgebraicNumberRing pe, AlgebraicNumber A, AlgebraicNumber B) { this(pe, A, B, null, null); } /** * Constructor. * @param pe the primitive element * @param A the first element. * @param B the second element. */ protected PrimitiveElement(AlgebraicNumberRing pe, AlgebraicNumber A, AlgebraicNumber B, AlgebraicNumberRing ar, AlgebraicNumberRing br ) { primitiveElem = pe; this.A = A; this.B = B; this.Aring = ar; this.Bring = br; } /** * String representation of the primitive element. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("PrimitiveElement["); s.append(primitiveElem.toString()); s.append(", " + A.toString()); s.append(", " + B.toString()); if (Aring != null) { s.append(", " + Aring.toString()); } if (Bring != null) { s.append(", " + Bring.toString()); } return s + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // Python case StringBuffer s = new StringBuffer("PrimitiveElement("); s.append(primitiveElem.toScript()); s.append(", " + A.toScript()); s.append(", " + B.toScript()); if (Aring != null) { s.append(", " + Aring.toScript()); } if (Bring != null) { s.append(", " + Bring.toScript()); } return s + ")"; } } java-algebra-system-2.7.200/src/edu/jas/application/RealAlgebraicNumber.java000066400000000000000000000260661445075545500266650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Complex algebraic number class based on bi-variate real algebraic numbers. * Objects of this class are immutable. Bi-variate ideal implementation is in * version 3614 2011-04-28 09:20:34Z. * @author Heinz Kredel */ public class RealAlgebraicNumber & Rational> implements GcdRingElem>, Rational { /* * Representing Residue, unused. */ //private Residue numberRes; /** * Representing recursive RealAlgebraicNumber. */ public final edu.jas.root.RealAlgebraicNumber> number; /** * Ring part of the data structure. */ public final RealAlgebraicRing ring; /** * The constructor creates a zero RealAlgebraicNumber. * @param r ring RealAlgebraicRing. */ public RealAlgebraicNumber(RealAlgebraicRing r) { this(r, r.realRing.getZERO()); } /** * The constructor creates a RealAlgebraicNumber object from a GenPolynomial * value. * @param r ring RealAlgebraicRing. * @param a value element . */ public RealAlgebraicNumber(RealAlgebraicRing r, C a) { this(r, r.realRing.parse(a.toString())); } /** * The constructor creates a RealAlgebraicNumber object from a GenPolynomial * value. * @param r ring RealAlgebraicRing. * @param a value GenPolynomial. */ public RealAlgebraicNumber(RealAlgebraicRing r, GenPolynomial a) { this(r, r.realRing.parse(a.toString())); } /** * The constructor creates a RealAlgebraicNumber object from a recursive * real algebraic value. * @param r ring RealAlgebraicRing. * @param a recursive real algebraic number. */ public RealAlgebraicNumber(RealAlgebraicRing r, edu.jas.root.RealAlgebraicNumber> a) { number = a; ring = r; //number = ring.realRing.parse(number.val.toString()); // convert? //System.out.println("number = " + number); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public RealAlgebraicRing factory() { return ring; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public RealAlgebraicNumber copy() { return new RealAlgebraicNumber(ring, number); } /** * Return a BigRational approximation of this Element. * @return a BigRational approximation of this. * @see edu.jas.arith.Rational#getRational() */ @Override public BigRational getRational() { return magnitude(); } /** * Is RealAlgebraicNumber zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return number.isZERO(); } /** * Is RealAlgebraicNumber one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return number.isONE(); } /** * Is RealAlgebraicNumber unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return number.isUnit(); } /** * Is RealAlgebraicNumber a root of unity. * @return true if |this**i| == 1, for some 0 < i ≤ deg(modul), else false. */ public boolean isRootOfUnity() { return number.isRootOfUnity(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return "{ " + number.toString() + " }"; } return "Complex" + number.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return number.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * RealAlgebraicNumber comparison. * @param b RealAlgebraicNumber. * @return sign(this-b). */ @Override public int compareTo(RealAlgebraicNumber b) { int s = 0; if (number.ring != b.number.ring) { s = (number.ring.equals(b.number.ring) ? 0 : 1); System.out.println("s_mod = " + s); } if (s != 0) { return s; } s = number.compareTo(b.number); //System.out.println("s_real = " + s); return s; } /** * RealAlgebraicNumber comparison. * @param b AlgebraicNumber. * @return polynomial sign(this-b). */ public int compareTo(edu.jas.root.RealAlgebraicNumber> b) { int s = number.compareTo(b); //System.out.println("s_algeb = " + s); return s; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof RealAlgebraicNumber)) { return false; } RealAlgebraicNumber a = null; try { a = (RealAlgebraicNumber) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return number.equals(a.number); } /** * Hash code for this RealAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * number.hashCode() + ring.hashCode(); } /** * RealAlgebraicNumber absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public RealAlgebraicNumber abs() { if (this.signum() < 0) { return new RealAlgebraicNumber(ring, number.negate()); } return this; } /** * RealAlgebraicNumber summation. * @param S RealAlgebraicNumber. * @return this+S. */ public RealAlgebraicNumber sum(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.sum(S.number)); } /** * RealAlgebraicNumber summation. * @param c recursive real algebraic number. * @return this+c. */ public RealAlgebraicNumber sum(edu.jas.root.RealAlgebraicNumber> c) { return new RealAlgebraicNumber(ring, number.sum(c)); } /** * RealAlgebraicNumber negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public RealAlgebraicNumber negate() { return new RealAlgebraicNumber(ring, number.negate()); } /** * RealAlgebraicNumber subtraction. * @param S RealAlgebraicNumber. * @return this-S. */ public RealAlgebraicNumber subtract(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.subtract(S.number)); } /** * RealAlgebraicNumber division. * @param S RealAlgebraicNumber. * @return this/S. */ public RealAlgebraicNumber divide(RealAlgebraicNumber S) { return multiply(S.inverse()); } /** * RealAlgebraicNumber inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S = 1/this if defined. */ public RealAlgebraicNumber inverse() { return new RealAlgebraicNumber(ring, number.inverse()); } /** * RealAlgebraicNumber remainder. * @param S RealAlgebraicNumber. * @return this - (this/S)*S. */ public RealAlgebraicNumber remainder(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.remainder(S.number)); } /** * RealAlgebraicNumber multiplication. * @param S RealAlgebraicNumber. * @return this*S. */ public RealAlgebraicNumber multiply(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.multiply(S.number)); } /** * RealAlgebraicNumber multiplication. * @param c recursive real algebraic number. * @return this*c. */ public RealAlgebraicNumber multiply( edu.jas.root.RealAlgebraicNumber> c) { return new RealAlgebraicNumber(ring, number.multiply(c)); } /** * RealAlgebraicNumber monic. * @return this with monic value part. */ public RealAlgebraicNumber monic() { return new RealAlgebraicNumber(ring, number.monic()); } /** * RealAlgebraicNumber greatest common divisor. * @param S RealAlgebraicNumber. * @return gcd(this,S). */ public RealAlgebraicNumber gcd(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.gcd(S.number)); } /** * RealAlgebraicNumber extended greatest common divisor. * @param S RealAlgebraicNumber. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public RealAlgebraicNumber[] egcd(RealAlgebraicNumber S) { edu.jas.root.RealAlgebraicNumber>[] aret = number.egcd(S.number); RealAlgebraicNumber[] ret = new RealAlgebraicNumber[3]; ret[0] = new RealAlgebraicNumber(ring, aret[0]); ret[1] = new RealAlgebraicNumber(ring, aret[1]); ret[2] = new RealAlgebraicNumber(ring, aret[2]); return ret; } /** * RealAlgebraicNumber signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return number.signum(); } /** * RealAlgebraicNumber magnitude. * @return |this| as rational number. */ public BigRational magnitude() { return number.magnitude(); } /** * RealAlgebraicNumber decimal magnitude. * @return |this| as big decimal. */ public BigDecimal decimalMagnitude() { BigRational cr = magnitude(); return new BigDecimal(cr); } } java-algebra-system-2.7.200/src/edu/jas/application/RealAlgebraicRing.java000066400000000000000000000275601445075545500263340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.root.Interval; import edu.jas.root.PolyUtilRoot; import edu.jas.root.RealRootTuple; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Real algebraic number factory class based on bi-variate real algebraic * numbers. Objects of this class are immutable with the exception of the * isolating intervals. Bi-variate ideal implementation is in version 3614 * 2011-04-28 09:20:34Z. * @author Heinz Kredel */ public class RealAlgebraicRing & Rational> implements RingFactory> { /** * Representing ideal with univariate polynomials IdealWithUniv. */ /*package*/final IdealWithUniv univs; /** * Representing ResidueRing. */ /*package*/final ResidueRing algebraic; /** * Isolating intervals for the real algebraic roots of the real and * imaginary part. Note: intervals may shrink eventually. */ /*package*/RealRootTuple root; /** * Recursive real root ring. */ public final edu.jas.root.RealAlgebraicRing> realRing; /** * Epsilon of the isolating rectangle for a complex root. */ protected BigRational eps; /** * Precision of the isolating rectangle for a complex root. */ public final int PRECISION = 9; //BigDecimal.DEFAULT_PRECISION; private static final Logger logger = LogManager.getLogger(RealAlgebraicRing.class); /** * The constructor creates a RealAlgebraicNumber factory object from a * IdealWithUniv, ResidueRing and a root tuple. * @param m module IdealWithUniv<C>. * @param a module ResidueRing<C>. * @param r isolating rectangle for a complex root. */ public RealAlgebraicRing(IdealWithUniv m, ResidueRing a, RealRootTuple r) { univs = m; algebraic = a; root = r; if (algebraic.characteristic().signum() > 0) { throw new IllegalArgumentException("characteristic not zero"); } if (root.tuple.size() != 2) { throw new IllegalArgumentException("wrong tuple size: " + root.tuple.size()); } eps = BigRational.ONE; edu.jas.root.RealAlgebraicRing rfac1 = root.tuple.get(0).factory(); edu.jas.root.RealAlgebraicRing rfac2 = root.tuple.get(1).factory(); GenPolynomial p0 = PolyUtil. selectWithVariable(univs.ideal.list.list, 0); if (p0 == null) { throw new RuntimeException("no polynomial found in " + (0) + " of " + univs.ideal); } //System.out.println("realRing, pol = " + p0.toScript()); GenPolynomialRing pfac = p0.ring; GenPolynomialRing> prfac = pfac.recursive(1); //System.out.println("prfac = " + prfac); GenPolynomial> p0r = PolyUtil. recursive(prfac, p0); GenPolynomialRing> parfac = new GenPolynomialRing>( rfac1, prfac); GenPolynomial> p0ar = PolyUtilRoot . convertRecursiveToAlgebraicCoefficients(parfac, p0r); Interval r2 = rfac2.getRoot(); edu.jas.root.RealAlgebraicNumber rleft = rfac1.getZERO().sum(r2.left); edu.jas.root.RealAlgebraicNumber rright = rfac1.getZERO().sum(r2.right); Interval> r2r = new Interval>( rleft, rright); edu.jas.root.RealAlgebraicRing> rr = new edu.jas.root.RealAlgebraicRing>( p0ar, r2r); logger.info("realRing = {}", rr); realRing = rr; } /** * The constructor creates a RealAlgebraicNumber factory object from a * IdealWithUniv and a root tuple. * @param m module IdealWithUniv<C>. * @param root isolating rectangle for a complex root. */ public RealAlgebraicRing(IdealWithUniv m, RealRootTuple root) { this(m, new ResidueRing(m.ideal), root); } /** * The constructor creates a RealAlgebraicNumber factory object from a * IdealWithUniv and a root tuple. * @param m module IdealWithUniv<C>. * @param root isolating rectangle for a complex root. * @param isField indicator if m is maximal. */ public RealAlgebraicRing(IdealWithUniv m, RealRootTuple root, boolean isField) { this(m, new ResidueRing(m.ideal, isField), root); } /** * Set a refined rectangle for the complex root. Note: rectangle may * shrink eventually. * @param v rectangle. */ public synchronized void setRoot(RealRootTuple v) { assert root.contains(v) : "root contains v"; this.root = v; } /** * Get rectangle for the complex root. * @return v rectangle. */ public synchronized RealRootTuple getRoot() { return this.root; } /** * Get epsilon. * @return epsilon. */ public synchronized BigRational getEps() { return this.eps; } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(C e) { setEps(e.getRational()); } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(BigRational e) { this.eps = e; } /** * Refine root. * @param e epsilon. */ public synchronized void refineRoot(BigRational e) { setEps(e); root.refineRoot(this.eps); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return realRing.isFinite(); } /** * Copy RealAlgebraicNumber element c. * @param c * @return a copy of c. */ public RealAlgebraicNumber copy(RealAlgebraicNumber c) { return new RealAlgebraicNumber(this, c.number); } /** * Get the zero element. * @return 0 as RealAlgebraicNumber. */ public RealAlgebraicNumber getZERO() { return new RealAlgebraicNumber(this, realRing.getZERO()); } /** * Get the one element. * @return 1 as RealAlgebraicNumber. */ public RealAlgebraicNumber getONE() { return new RealAlgebraicNumber(this, realRing.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List>> agens = realRing .generators(); List> gens = new ArrayList>(agens.size()); for (edu.jas.root.RealAlgebraicNumber> a : agens) { gens.add(getZERO().sum(a)); } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return realRing.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return realRing.isAssociative(); } /** * Query if this ring is a field. * @return true if algebraic is prime, else false. */ public boolean isField() { return realRing.isField(); } /** * Assert that this ring is a field. * @param isField true if this ring is a field, else false. */ public void setField(boolean isField) { realRing.setField(isField); } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return realRing.characteristic(); } /** * Get a RealAlgebraicNumber element from a BigInteger value. * @param a BigInteger. * @return a RealAlgebraicNumber. */ public RealAlgebraicNumber fromInteger(java.math.BigInteger a) { return new RealAlgebraicNumber(this, realRing.fromInteger(a)); } /** * Get a RealAlgebraicNumber element from a long value. * @param a long. * @return a RealAlgebraicNumber. */ public RealAlgebraicNumber fromInteger(long a) { return new RealAlgebraicNumber(this, realRing.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public synchronized String toString() { return "RealAlgebraicRing[ " + realRing.toString() + " in " + root + " | isField=" + realRing.isField() + ", algebraic.ideal=" + algebraic.ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public synchronized String toScript() { // Python case return "RealRecN( " + realRing.toScript() + ", " + root.toScript() //+ ", " + realRing.isField() //+ ", " + realRing.ring.toScript() + " )"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public synchronized boolean equals(Object b) { if (!(b instanceof RealAlgebraicRing)) { return false; } RealAlgebraicRing a = null; try { a = (RealAlgebraicRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } return realRing.equals(a.realRing) && root.equals(a.getRoot()); } /** * Hash code for this RealAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public synchronized int hashCode() { return 37 * realRing.hashCode() + root.hashCode(); } /** * RealAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public RealAlgebraicNumber random(int n) { return new RealAlgebraicNumber(this, realRing.random(n)); } /** * RealAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public RealAlgebraicNumber random(int n, Random rnd) { return new RealAlgebraicNumber(this, realRing.random(n, rnd)); } /** * Parse RealAlgebraicNumber from String. * @param s String. * @return RealAlgebraicNumber from s. */ public RealAlgebraicNumber parse(String s) { return new RealAlgebraicNumber(this, realRing.parse(s)); } /** * Parse RealAlgebraicNumber from Reader. * @param r Reader. * @return next RealAlgebraicNumber from r. */ public RealAlgebraicNumber parse(Reader r) { return new RealAlgebraicNumber(this, realRing.parse(r)); } } java-algebra-system-2.7.200/src/edu/jas/application/Residue.java000066400000000000000000000222021445075545500244230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; /** * Residue ring element based on GenPolynomial with RingElem interface. Objects * of this class are (nearly) immutable. * @author Heinz Kredel */ public class Residue> implements GcdRingElem> { /** * Residue class factory data structure. */ public final ResidueRing ring; /** * Value part of the element data structure. */ public final GenPolynomial val; /** * Flag to remember if this residue element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a Residue object from a ring factory. * @param r residue ring factory. */ public Residue(ResidueRing r) { this(r, r.ring.getZERO(), 0); } /** * The constructor creates a Residue object from a ring factory and a * polynomial. * @param r residue ring factory. * @param a polynomial. */ public Residue(ResidueRing r, GenPolynomial a) { this(r, a, -1); } /** * The constructor creates a Residue object from a ring factory, a * polynomial and an indicator if a is a unit. * @param r residue ring factory. * @param a polynomial. * @param u isunit indicator, -1, 0, 1. */ public Residue(ResidueRing r, GenPolynomial a, int u) { ring = r; val = ring.ideal.normalform(a); //.monic() no go if (u == 0 || u == 1) { isunit = u; return; } if (val.isZERO()) { isunit = 0; return; } if (ring.isField()) { isunit = 1; return; } if (val.isUnit()) { isunit = 1; //} else { // not possible //isunit = 0; } isunit = -1; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ResidueRing factory() { return ring; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Residue copy() { return new Residue(ring, val, isunit); } /** * Is Residue zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.isZERO(); } /** * Is Residue one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.isONE(); } /** * Is Residue unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known boolean u = ring.ideal.isUnit(val); if (u) { isunit = 1; } else { isunit = 0; } return (u); } /** * Is Residue a constant. * @return true if this.val is a constant polynomial, else false. */ public boolean isConstant() { return val.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return val.toString(ring.ring.getVars()); } return "Residue[ " + val.toString() + " mod " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return val.toScript(); // return "PolyResidue( " + val.toScript() // + ", " + ring.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Residue comparison. * @param b Residue. * @return sign(this-b), 0 means that this and b are equivalent in this * residue class ring. */ @Override public int compareTo(Residue b) { GenPolynomial v = b.val; if (!ring.equals(b.ring)) { v = ring.ideal.normalform(v); } return val.compareTo(v); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) * @return true means that this and b are equivalent in this residue class * ring. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof Residue)) { return false; } Residue a = null; try { a = (Residue) b; } catch (ClassCastException e) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this residue. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + val.hashCode(); return h; } /** * Residue absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Residue abs() { return new Residue(ring, val.abs(), isunit); } /** * Residue summation. * @param S Residue. * @return this+S. */ public Residue sum(Residue S) { return new Residue(ring, val.sum(S.val)); } /** * Residue negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Residue negate() { return new Residue(ring, val.negate(), isunit); } /** * Residue signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * Residue subtraction. * @param S Residue. * @return this-S. */ public Residue subtract(Residue S) { return new Residue(ring, val.subtract(S.val)); } /** * Residue division. * @param S Residue. * @return this/S. */ public Residue divide(Residue S) { if (ring.isField()) { return multiply(S.inverse()); } GenPolynomial x = PolyUtil. basePseudoDivide(val, S.val); return new Residue(ring, x); } /** * Residue inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public Residue inverse() { GenPolynomial x = ring.ideal.inverse(val); return new Residue(ring, x, 1); } /** * Residue remainder. * @param S Residue. * @return this - (this/S)*S. */ public Residue remainder(Residue S) { //GenPolynomial x = val.remainder( S.val ); GenPolynomial x = PolyUtil. baseSparsePseudoRemainder(val, S.val); return new Residue(ring, x); } /** * Residue multiplication. * @param S Residue. * @return this*S. */ public Residue multiply(Residue S) { GenPolynomial x = val.multiply(S.val); int i = -1; if (isunit == 1 && S.isunit == 1) { i = 1; } else if (isunit == 0 || S.isunit == 0) { i = 0; } return new Residue(ring, x, i); } /** * Residue monic. * @return this with monic value part. */ public Residue monic() { return new Residue(ring, val.monic(), isunit); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public Residue gcd(Residue b) { GenPolynomial x = ring.engine.gcd(val, b.val); int i = -1; // gcd might become a unit if (x.isONE()) { i = 1; //} else { //System.out.println("Residue gcd = " + x); } if (isunit == 1 && b.isunit == 1) { i = 1; } return new Residue(ring, x, i); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public Residue[] egcd(Residue b) { throw new UnsupportedOperationException("egcd not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/application/ResidueRing.java000066400000000000000000000230021445075545500252420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; /** * Residue ring factory based on GenPolynomial with RingFactory interface. * Objects of this class are immutable. * @author Heinz Kredel */ public class ResidueRing> implements RingFactory> { private static final Logger logger = LogManager.getLogger(ResidueRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisor engine; /** * Polynomial ideal for the reduction. */ public final Ideal ideal; /** * Polynomial ring of the factory. Shortcut to ideal.list.ring. */ public final GenPolynomialRing ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a ResidueRing object from an Ideal. * @param i polynomial ideal. */ public ResidueRing(Ideal i) { this(i, false); } /** * The constructor creates a ResidueRing object from an Ideal. * @param i polynomial ideal. * @param isMaximal true, if ideal is maxmal. */ public ResidueRing(Ideal i, boolean isMaximal) { ideal = i.GB(); // cheap if isGB ring = ideal.list.ring; //engine = GCDFactory.getImplementation( ring.coFac ); engine = GCDFactory. getProxy(ring.coFac); if (isMaximal) { isField = 1; return; } //System.out.println("rr engine = " + engine.getClass().getName()); //System.out.println("rr ring = " + ring.getClass().getName()); //System.out.println("rr cofac = " + ring.coFac.getClass().getName()); if (ideal.isONE()) { logger.warn("ideal is one, so all residues are 0"); } } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ideal.commonZeroTest() <= 0 && ring.coFac.isFinite(); } /** * Copy Residue element c. * @param c * @return a copy of c. */ public Residue copy(Residue c) { //System.out.println("rr copy in = " + c.val); if (c == null) { // where does this happen? return getZERO(); // or null? } Residue r = new Residue(this, c.val); //System.out.println("rr copy out = " + r.val); //System.out.println("rr copy ideal = " + ideal.list.list); return r; //new Residue( c.ring, c.val ); } /** * Get the zero element. * @return 0 as Residue. */ public Residue getZERO() { return new Residue(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Residue. */ public Residue getONE() { Residue one = new Residue(this, ring.getONE()); if (one.isZERO()) { logger.warn("ideal is one, so all residues are 0"); } return one; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> pgens = ring.generators(); List> gens = new ArrayList>(pgens.size()); SortedSet> sgens = new TreeSet>(); List> rgens = new ArrayList>(pgens.size()); Ideal gi = new Ideal(ring, rgens); ResidueRing gr = new ResidueRing(gi); for (GenPolynomial p : pgens) { Residue r = new Residue(this, p); if (r.isZERO()) { continue; } if (!r.isONE() && r.val.isConstant()) { continue; } // avoid duplicate generators Residue x = new Residue(gr, r.val); if (x.isZERO()) { continue; } if (!x.isONE() && x.val.isConstant()) { continue; } r = new Residue(this, x.val); if (r.isZERO()) { continue; } r = r.monic(); if (!r.isONE() && !r.val.isConstant()) { rgens.add(r.val); //System.out.println("rgens = " + rgens); gi = new Ideal(ring, rgens); gr = new ResidueRing(gi); } sgens.add(r); } gens.addAll(sgens); return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (ideal.isMaximal()) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Residue element from a BigInteger value. * @param a BigInteger. * @return a Residue. */ public Residue fromInteger(java.math.BigInteger a) { return new Residue(this, ring.fromInteger(a)); } /** * Get a Residue element from a long value. * @param a long. * @return a Residue. */ public Residue fromInteger(long a) { return new Residue(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "ResidueRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "RC(" + ideal.list.toScript() + ")"; //return "RC(" + ideal.toScript() + "," + ring.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof ResidueRing)) { return false; } ResidueRing a = null; try { a = (ResidueRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this residue ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * Residue random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Residue random(int n) { GenPolynomial x = ring.random(n).monic(); return new Residue(this, x); } /** * Generate a random residum polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random residue polynomial. */ public Residue random(int k, int l, int d, float q) { GenPolynomial x = ring.random(k, l, d, q).monic(); return new Residue(this, x); } /** * Residue random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public Residue random(int n, Random rnd) { GenPolynomial x = ring.random(n, rnd).monic(); return new Residue(this, x); } /** * Parse Residue from String. * @param s String. * @return Residue from s. */ public Residue parse(String s) { GenPolynomial x = ring.parse(s); return new Residue(this, x); } /** * Parse Residue from Reader. * @param r Reader. * @return next Residue from r. */ public Residue parse(Reader r) { GenPolynomial x = ring.parse(r); return new Residue(this, x); } } java-algebra-system-2.7.200/src/edu/jas/application/ResidueSolvablePolynomial.java000066400000000000000000000477401445075545500301750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.TableRelation; import edu.jas.structure.GcdRingElem; /** * ResidueSolvablePolynomial generic solvable polynomials with solvable residue * coefficients implementing RingElem. n-variate ordered solvable polynomials * over solvable residue coefficients. Objects of this class are intended to be * immutable. The implementation is based on TreeMap respectively SortedMap from * exponents to coefficients by extension of GenPolynomial. * Will eventually be deprecated use QLRSolvablePolynomial. * @param coefficient type * @author Heinz Kredel */ public class ResidueSolvablePolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final ResidueSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(ResidueSolvablePolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. */ public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. * @param e exponent. */ public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r, ExpVector e) { this(r); val.put(e, ring.getONECoefficient()); } /** * Constructor for ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r, SolvableResidue c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r, SolvableResidue c) { this(r, c, r.evzero); } /** * Constructor for ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r, GenSolvablePolynomial> S) { this(r, S.getMap()); } /** * Constructor for ResidueSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected ResidueSolvablePolynomial(ResidueSolvablePolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public ResidueSolvablePolynomialRing factory() { return ring; } /** * Clone this ResidueSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public ResidueSolvablePolynomial copy() { return new ResidueSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ResidueSolvablePolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * ResidueSolvablePolynomial multiplication. * @param Bp ResidueSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ public ResidueSolvablePolynomial multiply(ResidueSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == Bp.ring.nvar); logger.debug("ring = {}", ring); ExpVector Z = ring.evzero; ResidueSolvablePolynomial Dp = ring.getZERO().copy(); ResidueSolvablePolynomial zero = ring.getZERO().copy(); SolvableResidue one = ring.getONECoefficient(); //ResidueSolvablePolynomial C1 = null; //ResidueSolvablePolynomial C2 = null; Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); for (Map.Entry> y : A.entrySet()) { SolvableResidue a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = {}", e, a); //int[] ep = e.dependencyOnVariables(); //int el1 = ring.nvar + 1; //if (ep.length > 0) { // el1 = ep[0]; //} //int el1s = ring.nvar + 1 - el1; for (Map.Entry> x : Bk) { SolvableResidue b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial coefficient multiplication ResidueSolvablePolynomial Cps = ring.getZERO().copy(); //ResidueSolvablePolynomial Cs = null; if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric Cps = new ResidueSolvablePolynomial(ring, b, e); if (debug) logger.info("symmetric coeff: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff: b = {}, e = {}", b, e); // recursive polynomial coefficient multiplication : e * b.val RecSolvablePolynomial rsp1 = new RecSolvablePolynomial(ring.polCoeff, e); RecSolvablePolynomial rsp2 = new RecSolvablePolynomial(ring.polCoeff, b.val); RecSolvablePolynomial rsp3 = rsp1.multiply(rsp2); Cps = ring.fromPolyCoefficients(rsp3); } if (debug) { logger.info("coeff-poly: Cps = {}", Cps); } // polynomial multiplication ResidueSolvablePolynomial Dps = ring.getZERO().copy(); ResidueSolvablePolynomial Ds = null; ResidueSolvablePolynomial D1, D2; if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly: b = {}, e = {}", b, e); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = new ResidueSolvablePolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 SolvableResidue c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (ResidueSolvablePolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); if (debug) logger.info("poly, g2 = {}, f2 = {}", g2, f2); TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new ResidueSolvablePolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = new ResidueSolvablePolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = new ResidueSolvablePolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = new ResidueSolvablePolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = new ResidueSolvablePolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // assume c commutes with Cs Dps = (ResidueSolvablePolynomial) Dps.sum(Ds); } // end Dps loop Ds = Dps; } Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric logger.debug("Ds = {}", Ds); Dp = (ResidueSolvablePolynomial) Dp.sum(Ds); } // end B loop } // end A loop return Dp; } /** * ResidueSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S ResidueSolvablePolynomial. * @param T ResidueSolvablePolynomial. * @return S*this*T. */ public ResidueSolvablePolynomial multiply(ResidueSolvablePolynomial S, ResidueSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * ResidueSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b coefficient polynomial. * @return this*b, where * is coefficient multiplication. */ @Override public ResidueSolvablePolynomial multiply(SolvableResidue b) { ResidueSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Cp = new ResidueSolvablePolynomial(ring, b, ring.evzero); return multiply(Cp); } /** * ResidueSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public ResidueSolvablePolynomial multiply(SolvableResidue b, SolvableResidue c) { ResidueSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } ResidueSolvablePolynomial Cb = new ResidueSolvablePolynomial(ring, b, ring.evzero); ResidueSolvablePolynomial Cc = new ResidueSolvablePolynomial(ring, c, ring.evzero); return Cb.multiply(this).multiply(Cc); } /** * ResidueSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableResidue b = ring.getONECoefficient(); return multiply(b, e); } /** * ResidueSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public ResidueSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } SolvableResidue b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * ResidueSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiply(SolvableResidue b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } ResidueSolvablePolynomial Cp = new ResidueSolvablePolynomial(ring, b, e); return multiply(Cp); } /** * ResidueSolvablePolynomial left and right multiplication. Product with * ring element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public ResidueSolvablePolynomial multiply(SolvableResidue b, ExpVector e, SolvableResidue c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } ResidueSolvablePolynomial Cp = new ResidueSolvablePolynomial(ring, b, e); ResidueSolvablePolynomial Dp = new ResidueSolvablePolynomial(ring, c, f); return multiply(Cp, Dp); } /** * ResidueSolvablePolynomial multiplication. Left product with ring element * and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiplyLeft(SolvableResidue b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } ResidueSolvablePolynomial Cp = new ResidueSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * ResidueSolvablePolynomial multiplication. Left product with exponent * vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableResidue b = ring.getONECoefficient(); ResidueSolvablePolynomial Cp = new ResidueSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * ResidueSolvablePolynomial multiplication. Left product with coefficient * ring element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public ResidueSolvablePolynomial multiplyLeft(SolvableResidue b) { ResidueSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map> Cm = Cp.val; //getMap(); Map> Am = val; SolvableResidue c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); SolvableResidue a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * ResidueSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * ResidueSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public ResidueSolvablePolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * ResidueSolvablePolynomial multiplication with exponent vector. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected ResidueSolvablePolynomial shift(ExpVector f) { ResidueSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); SolvableResidue a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/application/ResidueSolvablePolynomialRing.java000066400000000000000000000637071445075545500310160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * ResidueSolvablePolynomialRing generic solvable polynomial with residue * coefficients factory implementing RingFactory and extending * GenSolvablePolynomialRing factory. Factory for n-variate ordered solvable * polynomials over solvable residue coefficients. The non-commutative * multiplication relations are maintained in a relation table and the * non-commutative multiplication relations between the coefficients and the * main variables are maintained in a coefficient relation table. Almost * immutable object, except variable names and relation table contents. * Will eventually be deprecated use QLRSolvablePolynomialRing. * @param coefficient type. * @author Heinz Kredel */ public class ResidueSolvablePolynomialRing> extends GenSolvablePolynomialRing> { /** * Recursive solvable polynomial ring with polynomial coefficients. */ public final RecSolvablePolynomialRing polCoeff; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public final ResidueSolvablePolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public final ResidueSolvablePolynomial ONE; private static final Logger logger = LogManager.getLogger(ResidueSolvablePolynomialRing.class); private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public ResidueSolvablePolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public ResidueSolvablePolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public ResidueSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } SolvableResidueRing cfring = (SolvableResidueRing) cf; // == coFac polCoeff = new RecSolvablePolynomialRing(cfring.ring, n, t, v); if (table.size() > 0) { List>> nt = new ArrayList>>(); for (GenSolvablePolynomial> q : table.relationList()) { nt.add( this.toPolyCoefficients(q) ); // only with den == 1 } polCoeff.table.addSolvRelations(nt); } ZERO = new ResidueSolvablePolynomial(this); SolvableResidue coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new ResidueSolvablePolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public ResidueSolvablePolynomialRing(RingFactory> cf, ResidueSolvablePolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + polCoeff.coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + polCoeff.coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } // if (polCoeff.coeffTable.size() > 0) { // String rel = polCoeff.coeffTable.toScript(); // s.append(",coeffrel="); // s.append(rel); // } s.append(")"); String cpol = polCoeff.toScript(); s.append("\n # "); s.append(cpol); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (!(other instanceof ResidueSolvablePolynomialRing)) { return false; } ResidueSolvablePolynomialRing oring = null; try { oring = (ResidueSolvablePolynomialRing) other; } catch (ClassCastException ignored) { } if (oring == null) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!polCoeff.coeffTable.equals(oring.polCoeff.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + polCoeff.coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as ResidueSolvablePolynomial. */ @Override public ResidueSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 throw new RuntimeException("zero not 0: " + ZERO); } return ZERO; } /** * Get the one element. * @return 1 as ResidueSolvablePolynomial. */ @Override public ResidueSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { throw new RuntimeException("one not 1: " + ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (polCoeff.coeffTable.size() == 0) { return super.isCommutative(); } // check structure of relations? return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @SuppressWarnings("unused") @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } //System.out.println("polCoeff = " + polCoeff.toScript()); if (!polCoeff.isAssociative()) { // not done via generators?? return false; } ResidueSolvablePolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); //System.out.println("Residu gens = " + gens); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (ResidueSolvablePolynomial) gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = (ResidueSolvablePolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (ResidueSolvablePolynomial) gens.get(k); p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); return false; } } } } return true; } /** * Get a (constant) ResidueSolvablePolynomial<C> element from a long * value. * @param a long. * @return a ResidueSolvablePolynomial<C>. */ @Override public ResidueSolvablePolynomial fromInteger(long a) { return new ResidueSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) ResidueSolvablePolynomial<C> element from a * BigInteger value. * @param a BigInteger. * @return a ResidueSolvablePolynomial<C>. */ @Override public ResidueSolvablePolynomial fromInteger(BigInteger a) { return new ResidueSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public ResidueSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public ResidueSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public ResidueSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public ResidueSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { ResidueSolvablePolynomial r = getZERO(); // copy( ZERO ); ExpVector e; SolvableResidue a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (ResidueSolvablePolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public ResidueSolvablePolynomial copy(ResidueSolvablePolynomial c) { return new ResidueSolvablePolynomial(this, c.getMap()); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return ResidueSolvablePolynomial from s. */ @Override public ResidueSolvablePolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next ResidueSolvablePolynomial from r. */ @Override @SuppressWarnings("unchecked") public ResidueSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); ResidueSolvablePolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new ResidueSolvablePolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public ResidueSolvablePolynomial univariate(int i) { return (ResidueSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public ResidueSolvablePolynomial univariate(int i, long e) { return (ResidueSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public ResidueSolvablePolynomial univariate(int modv, int i, long e) { return (ResidueSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { ResidueSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvablePolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvablePolynomialRing extend(int i, boolean top) { GenPolynomialRing> pfac = super.extend(i, top); ResidueSolvablePolynomialRing spfac = new ResidueSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param vn names for extended variables. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvablePolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvablePolynomialRing extend(String[] vn, boolean top) { GenPolynomialRing> pfac = super.extend(vn, top); ResidueSolvablePolynomialRing spfac = new ResidueSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public ResidueSolvablePolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); ResidueSolvablePolynomialRing spfac = new ResidueSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.contract(this.table); spfac.polCoeff.coeffTable.contract(this.polCoeff.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public ResidueSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public ResidueSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); ResidueSolvablePolynomialRing spfac = new ResidueSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.partial = partial; spfac.table.reverse(this.table); spfac.polCoeff.coeffTable.reverse(this.polCoeff.coeffTable); return spfac; } /** * Solvable residue coefficients from integral polynomial coefficients. * Represent as polynomial with type SolvableResidue coefficients. * @param A polynomial with integral polynomial coefficients to be * converted. * @return polynomial with type SolvableResidue coefficients. */ public ResidueSolvablePolynomial fromPolyCoefficients(GenSolvablePolynomial> A) { ResidueSolvablePolynomial B = getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = coFac; SolvableResidueRing qfac = (SolvableResidueRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenSolvablePolynomial a = (GenSolvablePolynomial) y.getValue(); SolvableResidue p = new SolvableResidue(qfac, a); // can be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from solvable residue coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with solvable residue coefficients to be converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(ResidueSolvablePolynomial A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableResidue a = y.getValue(); GenPolynomial p = a.val; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from solvable residue coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with solvable residue coefficients to be converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(GenPolynomial> A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableResidue a = y.getValue(); GenPolynomial p = a.val; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } } java-algebra-system-2.7.200/src/edu/jas/application/ResidueSolvableWordPolynomial.java000066400000000000000000000500361445075545500310210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.RecSolvableWordPolynomial; import edu.jas.poly.TableRelation; import edu.jas.structure.GcdRingElem; /** * ResidueSolvableWordPolynomial solvable polynomials with WordResidue * coefficients implementing RingElem. n-variate ordered solvable polynomials * over non-commutative word residue coefficients. Objects of this class are * intended to be immutable. The implementation is based on TreeMap respectively * SortedMap from exponents to coefficients by extension of GenPolynomial. * Will eventually be deprecated. * @param base coefficient type * @author Heinz Kredel */ public class ResidueSolvableWordPolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final ResidueSolvableWordPolynomialRing ring; private static final Logger logger = LogManager.getLogger(ResidueSolvableWordPolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. */ public ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r) { super(r); ring = r; } /** * Constructor for ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param e exponent. */ public ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r, ExpVector e) { this(r); val.put(e, ring.getONECoefficient()); } /** * Constructor for ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param c coefficient word residue. * @param e exponent. */ public ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r, WordResidue c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param c coefficient word residue. */ public ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r, WordResidue c) { this(r, c, r.evzero); } /** * Constructor for ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r, GenSolvablePolynomial> S) { this(r, S.getMap()); } /** * Constructor for ResidueSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected ResidueSolvableWordPolynomial(ResidueSolvableWordPolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public ResidueSolvableWordPolynomialRing factory() { return ring; } /** * Clone this ResidueSolvableWordPolynomial. * @see java.lang.Object#clone() */ @Override public ResidueSolvableWordPolynomial copy() { return new ResidueSolvableWordPolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ResidueSolvableWordPolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * ResidueSolvableWordPolynomial multiplication. * @param Bp ResidueSolvableWordPolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // cannot @Override, @NoOverride public ResidueSolvableWordPolynomial multiply(ResidueSolvableWordPolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == Bp.ring.nvar); logger.debug("ring = {}", ring); ExpVector Z = ring.evzero; ResidueSolvableWordPolynomial Dp = ring.getZERO().copy(); ResidueSolvableWordPolynomial zero = ring.getZERO().copy(); WordResidue one = ring.getONECoefficient(); Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); for (Map.Entry> y : A.entrySet()) { WordResidue a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = {}", e, a); for (Map.Entry> x : Bk) { WordResidue b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial/residue coefficient multiplication ResidueSolvableWordPolynomial Cps = ring.getZERO().copy(); if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric Cps = new ResidueSolvableWordPolynomial(ring, b, e); if (debug) logger.info("symmetric coeff: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff: b = {}, e = {}", b, e); // recursive polynomial coefficient multiplication : e * b.val RecSolvableWordPolynomial rsp1 = new RecSolvableWordPolynomial(ring.polCoeff, e); RecSolvableWordPolynomial rsp2 = new RecSolvableWordPolynomial(ring.polCoeff, b.val); RecSolvableWordPolynomial rsp3 = rsp1.multiply(rsp2); Cps = ring.fromPolyCoefficients(rsp3); } if (debug) { logger.info("coeff-poly: Cps = {}", Cps); } // polynomial multiplication ResidueSolvableWordPolynomial Dps = ring.getZERO().copy(); ResidueSolvableWordPolynomial Ds = null; ResidueSolvableWordPolynomial D1, D2; if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly: b = {}, e = {}", b, e); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = new ResidueSolvableWordPolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 WordResidue c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (ResidueSolvableWordPolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); if (debug) logger.info("poly, g2 = {}, f2 = {}", g2, f2); TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new ResidueSolvableWordPolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = new ResidueSolvableWordPolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = new ResidueSolvableWordPolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = new ResidueSolvableWordPolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = new ResidueSolvableWordPolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // assume c commutes with Cs Dps = (ResidueSolvableWordPolynomial) Dps.sum(Ds); } // end Dps loop Ds = Dps; } Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric logger.debug("Ds = {}", Ds); Dp = (ResidueSolvableWordPolynomial) Dp.sum(Ds); } // end B loop } // end A loop return Dp; } /** * ResidueSolvableWordPolynomial left and right multiplication. Product with * two polynomials. * @param S ResidueSolvableWordPolynomial. * @param T ResidueSolvableWordPolynomial. * @return S*this*T. */ // cannot @Override, @NoOverride public ResidueSolvableWordPolynomial multiply(ResidueSolvableWordPolynomial S, ResidueSolvableWordPolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * ResidueSolvableWordPolynomial multiplication. Product with coefficient * ring element. * @param b coefficient polynomial. * @return this*b, where * is coefficient multiplication. */ @Override //public GenSolvablePolynomial> multiply(WordResidue b) { public ResidueSolvableWordPolynomial multiply(WordResidue b) { ResidueSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Cp = ring.valueOf(b); return multiply(Cp); } /** * ResidueSolvableWordPolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(WordResidue b, WordResidue c) { ResidueSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } ResidueSolvableWordPolynomial Cb = ring.valueOf(b); ResidueSolvableWordPolynomial Cc = ring.valueOf(c); return Cb.multiply(this).multiply(Cc); } /* * ResidueSolvableWordPolynomial multiplication. Product with coefficient ring * element. * @param b coefficient of coefficient. * @return this*b, where * is coefficient multiplication. */ //@Override not possible, @NoOverride //public ResidueSolvableWordPolynomial multiply(C b) { ... } /** * ResidueSolvableWordPolynomial multiplication. Product with exponent * vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } WordResidue b = ring.getONECoefficient(); return multiply(b, e); } /** * ResidueSolvableWordPolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } WordResidue b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * ResidueSolvableWordPolynomial multiplication. Product with ring element * and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(WordResidue b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } ResidueSolvableWordPolynomial Cp = ring.valueOf(b, e); return multiply(Cp); } /** * ResidueSolvableWordPolynomial left and right multiplication. Product with * ring element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(WordResidue b, ExpVector e, WordResidue c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } ResidueSolvableWordPolynomial Cp = ring.valueOf(b, e); ResidueSolvableWordPolynomial Dp = ring.valueOf(c, f); return multiply(Cp, Dp); } /** * ResidueSolvableWordPolynomial multiplication. Left product with ring * element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiplyLeft(WordResidue b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } ResidueSolvableWordPolynomial Cp = ring.valueOf(b, e); return Cp.multiply(this); } /** * ResidueSolvableWordPolynomial multiplication. Left product with exponent * vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } ResidueSolvableWordPolynomial Cp = ring.valueOf(e); return Cp.multiply(this); } /** * ResidueSolvableWordPolynomial multiplication. Left product with * coefficient ring element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public ResidueSolvableWordPolynomial multiplyLeft(WordResidue b) { ResidueSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map> Cm = Cp.val; //getMap(); Map> Am = val; WordResidue c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); WordResidue a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * ResidueSolvableWordPolynomial multiplication. Left product with * 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * ResidueSolvableWordPolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public ResidueSolvableWordPolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * ResidueSolvableWordPolynomial multiplication. Commutative product with * exponent vector. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected ResidueSolvableWordPolynomial shift(ExpVector f) { ResidueSolvableWordPolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); WordResidue a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/application/ResidueSolvableWordPolynomialRing.java000066400000000000000000000674551445075545500316560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.RecSolvableWordPolynomial; import edu.jas.poly.RecSolvableWordPolynomialRing; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * ResidueSolvableWordPolynomialRing solvable polynomial with word residue * coefficients factory. It implements RingFactory and extends * GenSolvablePolynomialRing factory. Factory for n-variate ordered solvable * polynomials over non-commutative word residue coefficients. The * non-commutative multiplication relations are maintained in a relation table * and the non-commutative multiplication relations between the coefficients and * the main variables are maintained in a coefficient relation table. Almost * immutable object, except variable names and relation table contents. * Will eventually be deprecated. * @param base coefficient type. * @author Heinz Kredel */ public class ResidueSolvableWordPolynomialRing> extends GenSolvablePolynomialRing> { /** * Recursive solvable polynomial ring with polynomial coefficients. */ public final RecSolvableWordPolynomialRing polCoeff; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public final ResidueSolvableWordPolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public final ResidueSolvableWordPolynomial ONE; private static final Logger logger = LogManager.getLogger(ResidueSolvableWordPolynomialRing.class); private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } WordResidueRing cfring = (WordResidueRing) cf; // == coFac polCoeff = new RecSolvableWordPolynomialRing(cfring.ring, n, t, v); if (table.size() > 0) { List>> nt = new ArrayList>>(); for (GenSolvablePolynomial> q : table.relationList()) { nt.add( this.toPolyCoefficients(q) ); // only with den == 1 } polCoeff.table.addSolvRelations(nt); } ZERO = new ResidueSolvableWordPolynomial(this); WordResidue coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new ResidueSolvableWordPolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public ResidueSolvableWordPolynomialRing(RingFactory> cf, ResidueSolvableWordPolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + polCoeff.coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + polCoeff.coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } // if (polCoeff.coeffTable.size() > 0) { // String rel = polCoeff.coeffTable.toScript(); // s.append(",coeffrel="); // s.append(rel); // } s.append(")"); String cpol = polCoeff.toScript(); s.append("\n # "); s.append(cpol); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof ResidueSolvableWordPolynomialRing)) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } ResidueSolvableWordPolynomialRing oring = (ResidueSolvableWordPolynomialRing) other; // check same base relations done in super if (!polCoeff.coeffTable.equals(oring.polCoeff.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + polCoeff.coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as ResidueSolvableWordPolynomial. */ @Override public ResidueSolvableWordPolynomial getZERO() { return ZERO; } /** * Get the one element. * @return 1 as ResidueSolvableWordPolynomial. */ @Override public ResidueSolvableWordPolynomial getONE() { return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (polCoeff.coeffTable.isEmpty()) { return super.isCommutative(); } return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @SuppressWarnings("unused") @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } ResidueSolvableWordPolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); //System.out.println("Rec word gens = " + gens); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (ResidueSolvableWordPolynomial) gens.get(i); if (Xi.isONE()) { continue; } for (int j = i + 1; j < ngen; j++) { Xj = (ResidueSolvableWordPolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (ResidueSolvableWordPolynomial) gens.get(k); try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); return false; } } catch (RuntimeException e) { e.printStackTrace(); System.out.println("Xk = " + Xk + ", Xj = " + Xj + ", Xi = " + Xi); } } } } return true; } /** * Get a (constant) ResidueSolvableWordPolynomial<C> element from a * coefficient value. * @param a coefficient. * @return a ResidueSolvableWordPolynomial<C>. */ @Override public ResidueSolvableWordPolynomial valueOf(WordResidue a) { return new ResidueSolvableWordPolynomial(this, a, evzero); } /** * Get a ResidueSolvableWordPolynomial<C> element from an ExpVector. * @param e exponent vector. * @return a ResidueSolvableWordPolynomial<C>. */ @Override public ResidueSolvableWordPolynomial valueOf(ExpVector e) { return valueOf(coFac.getONE(), e); } /** * Get a ResidueSolvableWordPolynomial<C> element from a coefficient * and an ExpVector. * @param a coefficient. * @param e exponent vector. * @return a ResidueSolvableWordPolynomial<C>. */ @Override public ResidueSolvableWordPolynomial valueOf(WordResidue a, ExpVector e) { return new ResidueSolvableWordPolynomial(this, a, e); } /** * Get a (constant) ResidueSolvableWordPolynomial<C> element from a * long value. * @param a long. * @return a ResidueSolvableWordPolynomial<C>. */ @Override public ResidueSolvableWordPolynomial fromInteger(long a) { return new ResidueSolvableWordPolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) ResidueSolvableWordPolynomial<C> element from a * BigInteger value. * @param a BigInteger. * @return a ResidueSolvableWordPolynomial<C>. */ @Override public ResidueSolvableWordPolynomial fromInteger(BigInteger a) { return new ResidueSolvableWordPolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public ResidueSolvableWordPolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public ResidueSolvableWordPolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public ResidueSolvableWordPolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public ResidueSolvableWordPolynomial random(int k, int l, int d, float q, Random rnd) { ResidueSolvableWordPolynomial r = getZERO(); // copy( ZERO ); ExpVector e; WordResidue a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (ResidueSolvableWordPolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public ResidueSolvableWordPolynomial copy(ResidueSolvableWordPolynomial c) { return new ResidueSolvableWordPolynomial(this, c.getMap()); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return ResidueSolvableWordPolynomial from s. */ @Override public ResidueSolvableWordPolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next ResidueSolvableWordPolynomial from r. */ @Override @SuppressWarnings("unchecked") public ResidueSolvableWordPolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); ResidueSolvableWordPolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new ResidueSolvableWordPolynomial(this, s); } catch (IOException e) { logger.error(e.toString() + " parse {}", this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public ResidueSolvableWordPolynomial univariate(int i) { return (ResidueSolvableWordPolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public ResidueSolvableWordPolynomial univariate(int i, long e) { return (ResidueSolvableWordPolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public ResidueSolvableWordPolynomial univariate(int modv, int i, long e) { return (ResidueSolvableWordPolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { ResidueSolvableWordPolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvableWordPolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public ResidueSolvableWordPolynomialRing extend(int i, boolean top) { GenSolvablePolynomialRing> pfac = super.extend(i, top); ResidueSolvableWordPolynomialRing spfac = new ResidueSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vs names for extended variables. * @return extended polynomial ring factory. */ @Override public ResidueSolvableWordPolynomialRing extend(String[] vs) { return extend(vs, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vs names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ @Override public ResidueSolvableWordPolynomialRing extend(String[] vs, boolean top) { GenSolvablePolynomialRing> pfac = super.extend(vs, top); ResidueSolvableWordPolynomialRing spfac = new ResidueSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public ResidueSolvableWordPolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); ResidueSolvableWordPolynomialRing spfac = new ResidueSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.contract(this.table); spfac.polCoeff.coeffTable.contract(this.polCoeff.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public ResidueSolvableWordPolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public ResidueSolvableWordPolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); ResidueSolvableWordPolynomialRing spfac = new ResidueSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); //, pfac.table); spfac.partial = partial; spfac.table.reverse(this.table); spfac.polCoeff.coeffTable.reverse(this.polCoeff.coeffTable); return spfac; } /* not possible: * Distributive representation as polynomial with all main variables. * @return distributive polynomial ring factory. @SuppressWarnings({"cast","unchecked"}) public static > // must be static because of types GenSolvablePolynomialRing distribute(ResidueSolvableWordPolynomialRing rf) { } */ /** * Permutation of polynomial ring variables. * @param P permutation. * @return P(this). */ @Override public GenSolvablePolynomialRing> permutation(List P) { if (!polCoeff.coeffTable.isEmpty()) { throw new UnsupportedOperationException("permutation with coeff relations: " + this); } GenSolvablePolynomialRing> pfac = (GenSolvablePolynomialRing>) super .permutation(P); return pfac; } /** * Word residue coefficients from integral word polynomial coefficients. * Represent as polynomial with type WordResidue coefficients. * @param A polynomial with integral word polynomial coefficients to be * converted. * @return polynomial with type WordResidue coefficients. */ public ResidueSolvableWordPolynomial fromPolyCoefficients(GenSolvablePolynomial> A) { ResidueSolvableWordPolynomial B = getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = coFac; WordResidueRing qfac = (WordResidueRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenWordPolynomial a = y.getValue(); WordResidue p = new WordResidue(qfac, a); // can be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral word function from word residue coefficients. Represent as * polynomial with type GenWordPolynomial coefficients. * @param A polynomial with word residue coefficients to be converted. * @return polynomial with type GenWordPolynomial coefficients. */ public RecSolvableWordPolynomial toPolyCoefficients(ResidueSolvableWordPolynomial A) { RecSolvableWordPolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); WordResidue a = y.getValue(); GenWordPolynomial p = a.val; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral word function from word residue coefficients. Represent as * polynomial with type GenWordPolynomial coefficients. * @param A polynomial with word residue coefficients to be converted. * @return polynomial with type GenWordPolynomial coefficients. */ public RecSolvableWordPolynomial toPolyCoefficients(GenPolynomial> A) { RecSolvableWordPolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); WordResidue a = y.getValue(); GenWordPolynomial p = a.val; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } } java-algebra-system-2.7.200/src/edu/jas/application/RingFactoryTokenizer.java000066400000000000000000000773341445075545500271650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StreamTokenizer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Scanner; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModLongRing; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.InvalidExpressionException; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * RingFactory Tokenizer. Used to read ring factories from input streams. It can * also read QuotientRing factory. * @see edu.jas.poly.GenPolynomialTokenizer * @author Heinz Kredel */ public class RingFactoryTokenizer { private static final Logger logger = LogManager.getLogger(RingFactoryTokenizer.class); private static final boolean debug = logger.isDebugEnabled(); private String[] vars; private int nvars = 1; private TermOrder tord; private RelationTable table; private final StreamTokenizer tok; private final Reader reader; private RingFactory fac; private static enum coeffType { BigRat, BigInt, ModInt, BigC, BigQ, BigD, ANrat, ANmod, RatFunc, ModFunc, IntFunc }; private coeffType parsedCoeff = coeffType.BigRat; private GenPolynomialRing pfac; private static enum polyType { PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolANrat, PolANmod, PolRatFunc, PolModFunc, PolIntFunc }; @SuppressWarnings("unused") private polyType parsedPoly = polyType.PolBigRat; private GenSolvablePolynomialRing spfac; /** * No-args constructor reads from System.in. */ public RingFactoryTokenizer() { this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8")))); } /** * Constructor with Ring and Reader. * @param rf ring factory. * @param r reader stream. */ public RingFactoryTokenizer(GenPolynomialRing rf, Reader r) { this(r); if (rf == null) { return; } if (rf instanceof GenSolvablePolynomialRing) { pfac = rf; spfac = (GenSolvablePolynomialRing) rf; } else { pfac = rf; spfac = null; } fac = rf.coFac; vars = rf.getVars(); if (vars != null) { nvars = vars.length; } tord = rf.tord; // relation table if (spfac != null) { table = spfac.table; } else { table = null; } } /** * Constructor with Reader. * @param r reader stream. */ @SuppressWarnings("unchecked") public RingFactoryTokenizer(Reader r) { vars = null; tord = new TermOrder(); nvars = 1; fac = new BigRational(1); pfac = new GenPolynomialRing(fac, nvars, tord, vars); spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); reader = r; tok = new StreamTokenizer(reader); tok.resetSyntax(); // tok.eolIsSignificant(true); no more tok.eolIsSignificant(false); tok.wordChars('0', '9'); tok.wordChars('a', 'z'); tok.wordChars('A', 'Z'); tok.wordChars('_', '_'); // for subscripts x_i tok.wordChars('/', '/'); // wg. rational numbers tok.wordChars('.', '.'); // wg. floats tok.wordChars('~', '~'); // wg. quaternions // unused in this class tok.wordChars(128 + 32, 255); tok.whitespaceChars(0, ' '); tok.commentChar('#'); tok.quoteChar('"'); tok.quoteChar('\''); //tok.slashStarComments(true); does not work } /** * Initialize coefficient and polynomial factories. * @param rf ring factory. * @param ct coefficient type. */ @SuppressWarnings("unchecked") public void initFactory(RingFactory rf, coeffType ct) { fac = rf; parsedCoeff = ct; switch (ct) { case BigRat: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; break; case BigInt: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigInt; break; case ModInt: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolModInt; break; case BigC: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigC; break; case BigQ: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigQ; break; case BigD: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigD; break; case RatFunc: pfac = new GenPolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolRatFunc; break; case ModFunc: pfac = new GenPolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolModFunc; break; case IntFunc: pfac = new GenPolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolIntFunc; break; default: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; } } /** * Initialize coefficient and solvable polynomial factories. * @param rf ring factory. * @param ct coefficient type. */ @SuppressWarnings("unchecked") public void initSolvableFactory(RingFactory rf, coeffType ct) { fac = rf; parsedCoeff = ct; switch (ct) { case BigRat: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; break; case BigInt: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigInt; break; case ModInt: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolModInt; break; case BigC: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigC; break; case BigQ: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigQ; break; case BigD: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigD; break; case RatFunc: spfac = new GenSolvablePolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolRatFunc; break; case ModFunc: spfac = new GenSolvablePolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolModFunc; break; case IntFunc: spfac = new GenSolvablePolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolIntFunc; break; default: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; } } /** * Parsing method for variable list. Syntax: * *
     * (a, b c, de)
     * 
* * gives [ "a", "b", "c", "de" ] * @return the next variable list. * @throws IOException */ public String[] nextVariableList() throws IOException { List l = new ArrayList(); int tt; tt = tok.nextToken(); //System.out.println("vList tok = " + tok); if (tt == '(' || tt == '{') { logger.debug("variable list"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')' || tt == '}') break; if (tt == StreamTokenizer.TT_WORD) { //System.out.println("TT_WORD: " + tok.sval); l.add(tok.sval); } tt = tok.nextToken(); } } else { tok.pushBack(); } Object[] ol = l.toArray(); String[] v = new String[ol.length]; for (int i = 0; i < v.length; i++) { v[i] = (String) ol[i]; } return v; } /** * Parsing method for coefficient ring. Syntax: * *
     * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat |
    AN[ (var) ( poly ) | AN[ modul (var) ( poly ) ] | 
    RatFunc (var_list) | ModFunc modul (var_list) | IntFunc (var_list)
     * 
* * @return the next coefficient factory. * @throws IOException */ @SuppressWarnings({ "unchecked", "cast" }) public RingFactory nextCoefficientRing() throws IOException { RingFactory coeff = null; coeffType ct = null; int tt; tt = tok.nextToken(); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("Q")) { coeff = new BigRational(0); ct = coeffType.BigRat; } else if (tok.sval.equalsIgnoreCase("Rat")) { coeff = new BigRational(0); ct = coeffType.BigRat; } else if (tok.sval.equalsIgnoreCase("D")) { coeff = new BigDecimal(0); ct = coeffType.BigD; } else if (tok.sval.equalsIgnoreCase("Z")) { coeff = new BigInteger(0); ct = coeffType.BigInt; } else if (tok.sval.equalsIgnoreCase("Int")) { coeff = new BigInteger(0); ct = coeffType.BigInt; } else if (tok.sval.equalsIgnoreCase("C")) { coeff = new BigComplex(0); ct = coeffType.BigC; } else if (tok.sval.equalsIgnoreCase("Complex")) { coeff = new BigComplex(0); ct = coeffType.BigC; } else if (tok.sval.equalsIgnoreCase("Quat")) { logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)"); coeff = new BigQuaternionRing(); ct = coeffType.BigQ; } else if (tok.sval.equalsIgnoreCase("Mod")) { tt = tok.nextToken(); boolean openb = false; if (tt == '[') { // optional openb = true; tt = tok.nextToken(); } if (tok.sval != null && tok.sval.length() > 0) { if (digit(tok.sval.charAt(0))) { BigInteger mo = new BigInteger(tok.sval); BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE); if (mo.compareTo(lm) < 0) { if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) { coeff = new ModIntRing(mo.getVal()); } else { coeff = new ModLongRing(mo.getVal()); } } else { coeff = new ModIntegerRing(mo.getVal()); } //System.out.println("coeff = " + coeff + " :: " + coeff.getClass()); ct = coeffType.ModInt; } else { tok.pushBack(); } } else { tok.pushBack(); } if (tt == ']' && openb) { // optional tt = tok.nextToken(); } } else if (tok.sval.equalsIgnoreCase("RatFunc")) { String[] rfv = nextVariableList(); //System.out.println("rfv = " + rfv.length + " " + rfv[0]); int vr = rfv.length; BigInteger bi = new BigInteger(); TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing pcf = new GenPolynomialRing(bi, vr, to, rfv); coeff = new QuotientRing(pcf); ct = coeffType.RatFunc; } else if (tok.sval.equalsIgnoreCase("ModFunc")) { tt = tok.nextToken(); RingFactory mi = new ModIntegerRing("19"); if (tok.sval != null && tok.sval.length() > 0) { if (digit(tok.sval.charAt(0))) { mi = new ModIntegerRing(tok.sval); } else { tok.pushBack(); } } else { tok.pushBack(); } String[] rfv = nextVariableList(); //System.out.println("rfv = " + rfv.length + " " + rfv[0]); int vr = rfv.length; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing pcf = new GenPolynomialRing(mi, vr, to, rfv); coeff = new QuotientRing(pcf); ct = coeffType.ModFunc; } else if (tok.sval.equalsIgnoreCase("IntFunc")) { String[] rfv = nextVariableList(); //System.out.println("rfv = " + rfv.length + " " + rfv[0]); int vr = rfv.length; BigRational bi = new BigRational(); TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing pcf = new GenPolynomialRing(bi, vr, to, rfv); coeff = pcf; ct = coeffType.IntFunc; } else if (tok.sval.equalsIgnoreCase("AN")) { tt = tok.nextToken(); if (tt == '[') { tt = tok.nextToken(); RingFactory tcfac = new ModIntegerRing("19"); if (tok.sval != null && tok.sval.length() > 0) { if (digit(tok.sval.charAt(0))) { tcfac = new ModIntegerRing(tok.sval); } else { tcfac = new BigRational(); tok.pushBack(); } } else { tcfac = new BigRational(); tok.pushBack(); } String[] anv = nextVariableList(); //System.out.println("anv = " + anv.length + " " + anv[0]); int vs = anv.length; if (vs != 1) { throw new InvalidExpressionException( "AlgebraicNumber only for univariate polynomials " + Arrays.toString(anv)); } String[] ovars = vars; vars = anv; GenPolynomialRing tpfac = pfac; RingFactory tfac = fac; fac = tcfac; // pfac and fac used in nextPolynomial() if (tcfac instanceof ModIntegerRing) { pfac = new GenPolynomialRing(tcfac, vs, new TermOrder(), anv); } else { pfac = new GenPolynomialRing(tcfac, vs, new TermOrder(), anv); } logger.debug("pfac = {}", pfac); GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader); GenPolynomial mod = ptok.nextPolynomial(); ptok = null; logger.debug("mod = {}", mod); pfac = tpfac; fac = tfac; vars = ovars; if (tcfac instanceof ModIntegerRing) { GenPolynomial gfmod; gfmod = (GenPolynomial) mod; coeff = new AlgebraicNumberRing(gfmod); ct = coeffType.ANmod; } else { GenPolynomial anmod; anmod = (GenPolynomial) mod; coeff = new AlgebraicNumberRing(anmod); ct = coeffType.ANrat; } logger.debug("coeff = {}", coeff); tt = tok.nextToken(); if (tt == ']') { //ok, no nextToken(); } else { tok.pushBack(); } } else { tok.pushBack(); } } } if (coeff == null) { tok.pushBack(); coeff = new BigRational(); ct = coeffType.BigRat; } parsedCoeff = ct; return coeff; } /** * Parsing method for weight list. Syntax: * *
     * (w1, w2, w3, ..., wn)
     * 
* * @return the next weight list. * @throws IOException */ public long[] nextWeightList() throws IOException { List l = new ArrayList(); long e; char first; int tt; tt = tok.nextToken(); if (tt == '(') { logger.debug("weight list"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')') break; if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Long.parseLong(tok.sval); l.add(Long.valueOf(e)); //System.out.println("w: " + e); } } tt = tok.nextToken(); // also comma } } else { tok.pushBack(); } Long[] ol = new Long[1]; ol = l.toArray(ol); long[] w = new long[ol.length]; for (int i = 0; i < w.length; i++) { w[i] = ol[ol.length - i - 1].longValue(); } return w; } /** * Parsing method for weight array. Syntax: * *
     * ( (w11, ...,w1n), ..., (wm1, ..., wmn) )
     * 
* * @return the next weight array. * @throws IOException */ public long[][] nextWeightArray() throws IOException { List l = new ArrayList(); long[][] w = null; long[] e; char first; int tt; tt = tok.nextToken(); if (tt == '(') { logger.debug("weight array"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')') break; if (tt == '(') { tok.pushBack(); e = nextWeightList(); l.add(e); //System.out.println("wa: " + e); } else if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { tok.pushBack(); tok.pushBack(); e = nextWeightList(); l.add(e); break; //System.out.println("w: " + e); } } tt = tok.nextToken(); // also comma } } else { tok.pushBack(); } Object[] ol = l.toArray(); w = new long[ol.length][]; for (int i = 0; i < w.length; i++) { w[i] = (long[]) ol[i]; } return w; } /** * Parsing method for split index. Syntax: * *
     * |i|
     * 
* * @return the next split index. * @throws IOException */ public int nextSplitIndex() throws IOException { int e = -1; // =unknown int e0 = -1; // =unknown char first; int tt; tt = tok.nextToken(); if (tt == '|') { logger.debug("split index"); tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } tt = tok.nextToken(); if (tt != '|') { tok.pushBack(); } } } else if (tt == '[') { logger.debug("split index"); tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e0 = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } tt = tok.nextToken(); if (tt == ',') { tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e0; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } } if (tt != ']') { tok.pushBack(); } } } } else { tok.pushBack(); } return e; } /** * Parsing method for term order name. Syntax: * *
     * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|'
     * 
* * @return the next term order. * @throws IOException */ public TermOrder nextTermOrder() throws IOException { int evord = TermOrder.DEFAULT_EVORD; int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { /* nop */ } else if (tt == StreamTokenizer.TT_WORD) { // System.out.println("TT_WORD: " + tok.sval); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("L")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("IL")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("INVLEX")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("LEX")) { evord = TermOrder.LEX; } else if (tok.sval.equalsIgnoreCase("G")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("IG")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("IGRLEX")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("GRLEX")) { evord = TermOrder.GRLEX; } else if (tok.sval.equalsIgnoreCase("REVITDG")) { evord = TermOrder.REVITDG; } else if (tok.sval.equalsIgnoreCase("W")) { long[][] w = nextWeightArray(); return new TermOrder(w); } } } else { tok.pushBack(); } int s = nextSplitIndex(); if (s <= 0) { return new TermOrder(evord); } return new TermOrder(evord, evord, nvars, s); } /** * Parsing method for solvable polynomial relation table. Syntax: * *
     * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} )
     * 
* * semantics: p_{n+1} * p_{n+2} = p_{n+3}. The next relation * table is stored into the solvable polynomial factory. * @throws IOException */ @SuppressWarnings("unchecked") public void nextRelationTable() throws IOException { if (spfac == null) { return; } RelationTable table = spfac.table; List rels = null; GenPolynomial p; GenSolvablePolynomial sp; int tt; tt = tok.nextToken(); logger.debug("start relation table: {}", tt); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("RelationTable")) { GenPolynomialTokenizer ptok = new GenPolynomialTokenizer(pfac, reader); rels = ptok.nextPolynomialList(); ptok = null; } } if (rels == null) { tok.pushBack(); return; } for (Iterator it = rels.iterator(); it.hasNext();) { p = it.next(); ExpVector e = p.leadingExpVector(); if (it.hasNext()) { p = it.next(); ExpVector f = p.leadingExpVector(); if (it.hasNext()) { p = it.next(); sp = new GenSolvablePolynomial(spfac); sp.doPutToMap(p.getMap()); table.update(e, f, sp); } } } if (debug) { logger.info("table = {}", table); } return; } /** * Parsing method for polynomial ring. Syntax: * *
     * coeffRing varList termOrderName (no polyList)
     * 
* * @return the next polynomial ring. * @throws IOException */ @SuppressWarnings("unchecked") public GenPolynomialRing nextPolynomialRing() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff); vars = nextVariableList(); final var vv = vars; logger.info("vars = {}", () -> Arrays.toString(vv)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // global: nvars, tord, vars // now pfac is initialized return pfac; } /** * Parsing method for solvable polynomial ring. Syntax: * *
     * varList termOrderName relationTable (no polyList)
     * 
* * @return the next solvable polynomial ring. * @throws IOException */ @SuppressWarnings("unchecked") public GenSolvablePolynomialRing nextSolvablePolynomialRing() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // must be because of symmetric read initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars //System.out.println("pfac = " + pfac); //System.out.println("spfac = " + spfac); nextRelationTable(); if (logger.isInfoEnabled()) { logger.info("table = {}", table + ", tok = {}", tok); } // now spfac is initialized return spfac; } static boolean digit(char x) { return '0' <= x && x <= '9'; } //static boolean letter(char x) { // return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z'); //} // unused public void nextComma() throws IOException { int tt; if (tok.ttype == ',') { tt = tok.nextToken(); if (debug) { logger.debug("after comma: {}", tt); } } } /** * Parsing method for module ring. Syntax: * *
     * coeffRing varList termOrderName (no moduleList)
     * 
* * @return the next module ring. * @throws IOException */ @SuppressWarnings("unchecked") public GenPolynomialRing nextSubModuleRing() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // global: nvars, tord, vars //List> m = null; //m = nextSubModuleList(); //logger.info("m = {}", m); return pfac; } /** * Parsing method for solvable module ring. Syntax: * *
     * varList termOrderName relationTable (no moduleList*)
     * 
* * @return the next solvable module ring. * @throws IOException */ @SuppressWarnings("unchecked") public GenSolvablePolynomialRing nextSolvableSubModuleRing() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // must be because of symmetric read initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars //System.out.println("spfac = " + spfac); nextRelationTable(); logger.info("table = {}", table); //List> s = null; //s = nextSolvableSubModuleList(); //logger.info("s = {}", s); //return new OrderedModuleList(spfac, s); // Ordered return spfac; } } java-algebra-system-2.7.200/src/edu/jas/application/RootFactoryApp.java000066400000000000000000000270001445075545500257400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.root.Interval; import edu.jas.root.RealRootTuple; import edu.jas.root.AlgebraicRoots; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Roots factory. * @author Heinz Kredel */ public class RootFactoryApp { private static final Logger logger = LogManager.getLogger(RootFactoryApp.class); private static final boolean debug = logger.isDebugEnabled(); /** * Is complex algebraic number a root of a polynomial. * @param f univariate polynomial. * @param r complex algebraic number. * @return true, if f(r) == 0, else false; */ public static & Rational> boolean isRootRealCoeff(GenPolynomial f, Complex> r) { RingFactory cfac = f.ring.coFac; ComplexRing ccfac = new ComplexRing(cfac); GenPolynomialRing> facc = new GenPolynomialRing>(ccfac, f.ring); GenPolynomial> fc = PolyUtil. complexFromAny(facc, f); return isRoot(fc, r); } /** * Is complex algebraic number a root of a polynomial. * @param f univariate polynomial. * @param r complex algebraic number. * @return true, if f(r) == 0, else false; */ public static & Rational> boolean isRoot(GenPolynomial> f, Complex> r) { ComplexRing> cr = r.factory(); GenPolynomialRing>> cfac = new GenPolynomialRing>>( cr, f.factory()); GenPolynomial>> p; p = PolyUtilApp. convertToComplexRealCoefficients(cfac, f); // test algebraic part Complex> a = PolyUtil.>> evaluateMain(cr, p, r); boolean t = a.isZERO(); if (!t) { logger.info("f(r) = {}, f = {}, r = {}", a, f, r); return t; } // test approximation? not working return true; } /** * Is complex algebraic number a root of a polynomial. * @param f univariate polynomial. * @param R list of complex algebraic numbers. * @return true, if f(r) == 0 for all r in R, else false; */ public static & Rational> boolean isRoot(GenPolynomial> f, List>> R) { for (Complex> r : R) { boolean t = isRoot(f, r); if (!t) { return false; } } return true; } /** * Complex algebraic number roots. * @param f univariate polynomial. * @return a list of different complex algebraic numbers, with f(c) == 0 for * c in roots. */ public static & Rational> List>> complexAlgebraicNumbersComplex( GenPolynomial> f) { GenPolynomialRing> pfac = f.factory(); if (pfac.nvar != 1) { throw new IllegalArgumentException("only for univariate polynomials"); } ComplexRing cfac = (ComplexRing) pfac.coFac; SquarefreeAbstract> engine = SquarefreeFactory.> getImplementation(cfac); Map>, Long> F = engine.squarefreeFactors(f.monic()); //System.out.println("S = " + F.keySet()); List>> list = new ArrayList>>(); for (Map.Entry>,Long> me : F.entrySet()) { GenPolynomial> sp = me.getKey(); if (sp.isConstant() || sp.isZERO()) { continue; } List>> ls = RootFactoryApp. complexAlgebraicNumbersSquarefree(sp); long m = me.getValue(); for (long i = 0L; i < m; i++) { list.addAll(ls); } } return list; } /** * Complex algebraic number roots. * @param f univariate squarefree polynomial. * @return a list of different complex algebraic numbers, with f(c) == 0 for * c in roots. */ public static & Rational> List>> complexAlgebraicNumbersSquarefree( GenPolynomial> f) { GenPolynomialRing> pfac = f.factory(); if (pfac.nvar != 1) { throw new IllegalArgumentException("only for univariate polynomials"); } ComplexRing cfac = (ComplexRing) pfac.coFac; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing> tfac = new GenPolynomialRing>(cfac, 2, to); //,new vars); //tord? //System.out.println("tfac = " + tfac); GenPolynomial> t = tfac.univariate(1, 1L).sum( tfac.univariate(0, 1L).multiply(cfac.getIMAG())); //System.out.println("t = " + t); // t = x + i y GenPolynomialRing rfac = new GenPolynomialRing(cfac.ring, tfac); //tord? //System.out.println("rfac = " + rfac); List>> list = new ArrayList>>(); GenPolynomial> sp = f; if (sp.isConstant() || sp.isZERO()) { return list; } // substitute t = x + i y GenPolynomial> su = PolyUtil.> substituteUnivariate(sp, t); //System.out.println("su = " + su); su = su.monic(); //System.out.println("su = " + su); GenPolynomial re = PolyUtil. realPartFromComplex(rfac, su); GenPolynomial im = PolyUtil. imaginaryPartFromComplex(rfac, su); if (debug) { logger.debug("rfac = {}", () -> rfac.toScript()); logger.debug("t = {}, re = {}, im = {}", t, re.toScript(), im.toScript()); // ()-> not possible } List> li = new ArrayList>(2); li.add(re); li.add(im); Ideal id = new Ideal(rfac, li); //System.out.println("id = " + id); List> idul = id.zeroDimRootDecomposition(); IdealWithRealAlgebraicRoots idr; for (IdealWithUniv idu : idul) { //System.out.println("---idu = " + idu); idr = PolyUtilApp. realAlgebraicRoots(idu); //System.out.println("---idr = " + idr); for (List> crr : idr.ran) { //System.out.println("crr = " + crr); RealRootTuple root = new RealRootTuple(crr); //System.out.println("root = " + root); RealAlgebraicRing car = new RealAlgebraicRing(idu, root); //System.out.println("car = " + car); List> gens = car.generators(); //System.out.println("gens = " + gens); int sg = gens.size(); RealAlgebraicNumber rre = gens.get(sg - 2); RealAlgebraicNumber rim = gens.get(sg - 1); ComplexRing> cring = new ComplexRing>(car); Complex> crn = new Complex>(cring, rre, rim); //System.out.println("crn = " + crn + " in " + crn.ring); // refine intervals if necessary, not meaningful list.add(crn); } } return list; } /* approximation ? List> complexAlgebraicNumbersComplex(GenPolynomial> f, BigRational eps) */ /** * Root reduce of real and complex algebraic numbers. * @param a container of real and complex algebraic numbers. * @param b container of real and complex algebraic numbers. * @return container of real and complex algebraic numbers * of the primitive element of a and b. */ public static & Rational> AlgebraicRootsPrimElem rootReduce(AlgebraicRoots a, AlgebraicRoots b) { return rootReduce(a.getAlgebraicRing(), b.getAlgebraicRing()); } /** * Root reduce of real and complex algebraic numbers. * @param a polynomial. * @param b polynomial. * @return container of real and complex algebraic numbers * of the primitive element of a and b. */ public static & Rational> AlgebraicRootsPrimElem rootReduce(GenPolynomial a, GenPolynomial b) { AlgebraicNumberRing anr = new AlgebraicNumberRing(a); AlgebraicNumberRing bnr = new AlgebraicNumberRing(b); return rootReduce(anr, bnr); } /** * Root reduce of real and complex algebraic numbers. * @param a algebraic number ring. * @param b algebraic number ring. * @return container of real and complex algebraic numbers * of the primitive element of a and b. */ public static & Rational> AlgebraicRootsPrimElem rootReduce(AlgebraicNumberRing a, AlgebraicNumberRing b) { PrimitiveElement pe = PolyUtilApp.primitiveElement(a, b); AlgebraicRoots ar = edu.jas.root.RootFactory.algebraicRoots(pe.primitiveElem.modul); return new AlgebraicRootsPrimElem(ar, pe); } /** * Roots of unity of real and complex algebraic numbers. * @param ar container of real and complex algebraic numbers with primitive element. * @return container of real and complex algebraic numbers which are roots * of unity. */ public static & Rational> AlgebraicRootsPrimElem rootsOfUnity(AlgebraicRootsPrimElem ar) { AlgebraicRoots ur = edu.jas.root.RootFactory.rootsOfUnity(ar); if (ar.pelem == null) { return new AlgebraicRootsPrimElem(ur, ar.pelem); } List> al = new ArrayList>(); long d = ar.pelem.primitiveElem.modul.degree(); AlgebraicNumber c = ar.pelem.A; AlgebraicNumber m = c.ring.getONE(); for (long i = 1; i <= d; i++) { m = m.multiply(c); if (m.isRootOfUnity()) { if (!al.contains(m)) { al.add(m); } } } c = ar.pelem.B; m = c.ring.getONE(); for (long i = 1; i <= d; i++) { m = m.multiply(c); if (m.isRootOfUnity()) { if (!al.contains(m)) { al.add(m); } } } return new AlgebraicRootsPrimElem(ur, ar.pelem, al); } } java-algebra-system-2.7.200/src/edu/jas/application/RunGB.java000066400000000000000000000466061445075545500240160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseDistributedEC; import edu.jas.gb.GroebnerBaseDistributedHybridEC; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.ReductionPar; import edu.jas.gb.ReductionSeq; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.GroebnerBasePseudoParallel; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.util.CatReader; import edu.jas.util.ExecutableServer; /** * Simple setup to run a GB example.
* Usage: RunGB [seq(+)|par(+)|build=string|disthyb|cli] <file> * #procs/#threadsPerNode [machinefile] <check>
* Build string can be any combination of method calls from GBAlgorithmBuilder. * Method polynomialRing() is called based on declaration from "file". Method * build() is called automatically. For example
* build=syzygyPairlist.iterated.graded.parallel(3) * @see edu.jas.application.GBAlgorithmBuilder * @author Heinz Kredel */ public class RunGB { /** * Check result GB if it is a GB. */ static boolean doCheck = false; /** * main method to be called from commandline
* Usage: RunGB [seq|par(+)|build=string|disthyb(+)|cli] <file> * #procs/#threadsPerNode [machinefile] <check> */ @SuppressWarnings("unchecked") public static void main(String[] args) { String[] allkinds = new String[] { "seq", "seq+", "par", "par+", "build=", "disthyb", "disthyb+", "cli" }; // must be last String usage = "Usage: RunGB [ " + join(allkinds, " | ") + "[port] ] " + " " + "#procs/#threadsPerNode " + "[machinefile] " + "[check] "; if (args.length < 1) { System.out.println("args: " + Arrays.toString(args)); System.out.println(usage); return; } boolean plusextra = false; String kind = args[0]; boolean sup = false; int k = -1; for (int i = 0; i < args.length; i++) { int j = indexOf(allkinds, args[i]); if (j < 0) { continue; } sup = true; k = i; kind = args[k]; break; } if (!sup) { System.out.println("args(sup): " + Arrays.toString(args)); System.out.println(usage); return; } if (kind.indexOf("+") >= 0) { plusextra = true; } System.out.println("kind: " + kind + ", k = " + k); final int GB_SERVER_PORT = 7114; int port = GB_SERVER_PORT; if (kind.equals("cli")) { if (args.length - k >= 2) { try { port = Integer.parseInt(args[k + 1]); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(port): " + Arrays.toString(args)); System.out.println(usage); return; } } runClient(port); return; } String filename = null; if (!kind.equals("cli")) { if (args.length - k < 2) { System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } filename = args[k + 1]; } int j = indexOf(args, "check"); if (j >= 0) { doCheck = true; } int threads = 0; int threadsPerNode = 1; if (kind.startsWith("par") || kind.startsWith("dist")) { if (args.length - k < 3) { System.out.println("args(par|dist): " + Arrays.toString(args)); System.out.println(usage); return; } String tup = args[k + 2]; String t = tup; int i = tup.indexOf("/"); if (i >= 0) { t = tup.substring(0, i).trim(); tup = tup.substring(i + 1).trim(); try { threadsPerNode = Integer.parseInt(tup); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threadsPerNode): " + Arrays.toString(args)); System.out.println(usage); return; } } try { threads = Integer.parseInt(t); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threads): " + Arrays.toString(args)); System.out.println(usage); return; } } String mfile = null; if (kind.startsWith("dist")) { if (args.length - k >= 4) { mfile = args[k + 3]; } else { mfile = "machines"; } } Reader problem = getReader(filename); if (problem == null) { System.out.println("args(file): " + filename); System.out.println("args(file): examples.jar(" + filename + ")"); System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } RingFactoryTokenizer rftok = new RingFactoryTokenizer(problem); GenPolynomialRing pfac = null; try { pfac = rftok.nextPolynomialRing(); rftok = null; } catch (IOException e) { e.printStackTrace(); return; } System.out.println("pfac: " + pfac.toScript()); Reader polyreader = new CatReader(new StringReader("("), problem); // ( has gone //Reader polyreader = problem; GenPolynomialTokenizer tok = new GenPolynomialTokenizer(pfac, polyreader); PolynomialList S = null; try { S = new PolynomialList(pfac, tok.nextPolynomialList()); } catch (IOException e) { e.printStackTrace(); return; } System.out.println("input S =\n" + S); GroebnerBaseAbstract gb = null; if (kind.startsWith("build")) { gb = getGBalgo(args, kind, S.ring); if (gb == null) { System.out.println(usage); return; } } if (kind.startsWith("seq")) { runSequential(S, plusextra); } else if (kind.startsWith("par")) { runParallel(S, threads, plusextra); } else if (kind.startsWith("disthyb")) { runMasterHyb(S, threads, threadsPerNode, mfile, port, plusextra); //} else if (kind.startsWith("dist")) { //runMaster(S, threads, mfile, port, plusextra); } else if (kind.startsWith("build")) { runGB(S, gb); } ComputerThreads.terminate(); try { problem.close(); } catch (IOException ignored) { } } // no more used @SuppressWarnings("unchecked") static void runMaster(PolynomialList S, int threads, String mfile, int port, boolean plusextra) { List L = S.list; List G = null; long t, t1; GroebnerBaseDistributedEC gbd = null; GroebnerBaseDistributedEC gbds = null; System.out.println("\nGroebner base distributed (" + threads + ", " + mfile + ", " + port + ") ..."); t = System.currentTimeMillis(); if (plusextra) { //gbds = new GroebnerBaseDistributedEC(threads,mfile, port); gbds = new GroebnerBaseDistributedEC(mfile, threads, new OrderedSyzPairlist(), port); } else { gbd = new GroebnerBaseDistributedEC(mfile, threads, port); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); //false); } else { gbd.terminate(); //false); } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("d+ "); } else { System.out.print("d "); } System.out.println("= " + threads + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); checkGB(S); System.out.println(""); } @SuppressWarnings("unchecked") static void runMasterHyb(PolynomialList S, int threads, int threadsPerNode, String mfile, int port, boolean plusextra) { List L = S.list; List G = null; long t, t1; GroebnerBaseDistributedHybridEC gbd = null; GroebnerBaseDistributedHybridEC gbds = null; System.out.println("\nGroebner base distributed hybrid (" + threads + "/" + threadsPerNode + ", " + mfile + ", " + port + ") ..."); t = System.currentTimeMillis(); if (plusextra) { // gbds = new GroebnerBaseDistributedHybridEC(mfile, threads,port); gbds = new GroebnerBaseDistributedHybridEC(mfile, threads, threadsPerNode, new OrderedSyzPairlist(), port); } else { gbd = new GroebnerBaseDistributedHybridEC(mfile, threads, threadsPerNode, port); } t1 = System.currentTimeMillis(); if (plusextra) { G = gbds.GB(L); } else { G = gbd.GB(L); } t1 = System.currentTimeMillis() - t1; if (plusextra) { gbds.terminate(); // true } else { gbd.terminate(); // false plus eventually killed by script } t = System.currentTimeMillis() - t; S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); if (plusextra) { System.out.print("d+ "); } else { System.out.print("d "); } System.out.println("= " + threads + ", ppn = " + threadsPerNode + ", time = " + t1 + " milliseconds, " + (t - t1) + " start-up " + ", total = " + t); checkGB(S); System.out.println(""); } static void runClient(int port) { System.out.println("\nGroebner base distributed client (" + port + ") ..."); ExecutableServer es = new ExecutableServer(port); es.init(); try { es.join(); } catch (InterruptedException e) { // ignored } finally { es.terminate(); } //System.out.println("runClient() done: " + es); } @SuppressWarnings("unchecked") static void runParallel(PolynomialList S, int threads, boolean plusextra) { List L = S.list; List G; long t; GroebnerBaseAbstract bb = null; GroebnerBaseAbstract bbs = null; if (plusextra) { //bbs = new GroebnerBaseSeqPairParallel(threads); bbs = new GroebnerBaseParallel(threads, new ReductionPar(), new OrderedSyzPairlist()); } else { if (S.ring.coFac.isField()) { bb = new GroebnerBaseParallel(threads); } else { bb = new GroebnerBasePseudoParallel(threads, S.ring.coFac); } } System.out.println("\nGroebner base parallel (" + threads + ") ..."); t = System.currentTimeMillis(); if (plusextra) { G = bbs.GB(L); } else { G = bb.GB(L); } t = System.currentTimeMillis() - t; S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); if (plusextra) { System.out.print("par+ "); } else { System.out.print("par "); } System.out.println("= " + threads + ", time = " + t + " milliseconds"); if (plusextra) { bbs.terminate(); } else { bb.terminate(); } checkGB(S); System.out.println(""); } @SuppressWarnings("unchecked") static void runSequential(PolynomialList S, boolean plusextra) { List L = S.list; List G; long t; GroebnerBaseAbstract bb = null; if (plusextra) { //bb = new GroebnerBaseSeqPlusextra(); bb = new GroebnerBaseSeq(new ReductionSeq(), new OrderedSyzPairlist()); } else { bb = GBFactory.getImplementation(S.ring.coFac); //new GroebnerBaseSeq(); } System.out.println("\nGroebner base sequential ..."); t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); if (plusextra) { System.out.print("seq+, "); } else { System.out.print("seq, "); } System.out.println("time = " + t + " milliseconds"); checkGB(S); System.out.println(""); } @SuppressWarnings("unchecked") static void runGB(PolynomialList S, GroebnerBaseAbstract bb) { List L = S.list; List G; long t; if (bb == null) { // should not happen bb = GBFactory.getImplementation(S.ring.coFac); } String bbs = bb.toString().replaceAll(" ", ""); System.out.println("\nGroebner base build=" + bbs + " ..."); t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; S = new PolynomialList(S.ring, G); bbs = bb.toString().replaceAll(" ", ""); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); System.out.print("build=" + bbs + ", "); System.out.println("time = " + t + " milliseconds"); checkGB(S); bb.terminate(); System.out.println(""); } @SuppressWarnings("unchecked") static void checkGB(PolynomialList S) { if (!doCheck) { return; } GroebnerBaseAbstract bb = GBFactory.getImplementation(S.ring.coFac); long t = System.currentTimeMillis(); boolean chk = bb.isGB(S.list, false); t = System.currentTimeMillis() - t; System.out.println("check isGB = " + chk + " in " + t + " milliseconds"); } static int indexOf(String[] args, String s) { for (int i = 0; i < args.length; i++) { if (s.startsWith(args[i])) { return i; } } return -1; } static String join(String[] args, String d) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < args.length; i++) { if (i > 0) { sb.append(d); } sb.append(args[i]); } return sb.toString(); } @SuppressWarnings("resource") static Reader getReader(String filename) { Reader problem = null; Exception fnf = null; try { problem = new InputStreamReader(new FileInputStream(filename), Charset.forName("UTF8")); problem = new BufferedReader(problem); } catch (FileNotFoundException e) { fnf = e; } if (problem != null) { return problem; } String examples = "examples.jar"; try { JarFile jf = new JarFile(examples); JarEntry je = jf.getJarEntry(filename); if (je == null) { jf.close(); fnf.printStackTrace(); return problem; } problem = new InputStreamReader(jf.getInputStream(je), Charset.forName("UTF8")); problem = new BufferedReader(problem); } catch (FileNotFoundException e) { fnf.printStackTrace(); e.printStackTrace(); } catch (IOException e) { fnf.printStackTrace(); e.printStackTrace(); //} finally { not possible, problem must remain open //jf.close(); } return problem; } @SuppressWarnings("unchecked") static GroebnerBaseAbstract getGBalgo(String[] args, String bstr, GenPolynomialRing ring) { GroebnerBaseAbstract gb = null; int i = bstr.indexOf("="); if (i < 0) { System.out.println("args(build): " + Arrays.toString(args)); return gb; } i += 1; String tb = bstr.substring(i); //System.out.println("build=" + tb); GBAlgorithmBuilder ab = GBAlgorithmBuilder.polynomialRing(ring); //System.out.println("ab = " + ab); while (!tb.isEmpty()) { int ii = tb.indexOf("."); String mth; if (ii >= 0) { mth = tb.substring(0, ii); tb = tb.substring(ii + 1); } else { mth = tb; tb = ""; } if (mth.startsWith("build")) { continue; } String parm = ""; int jj = mth.indexOf("()"); if (jj >= 0) { mth = mth.substring(0, jj); } else { jj = mth.indexOf("("); if (jj >= 0) { parm = mth.substring(jj + 1); mth = mth.substring(0, jj); jj = parm.indexOf(")"); parm = parm.substring(0, jj); } } //System.out.println("mth = " + mth + ", parm = " + parm); try { Method method; if (parm.isEmpty()) { method = ab.getClass().getMethod(mth, (Class[]) null); ab = (GBAlgorithmBuilder) method.invoke(ab, (Object[]) null); } else { int tparm = Integer.parseInt(parm); method = ab.getClass().getMethod(mth, int.class); ab = (GBAlgorithmBuilder) method.invoke(ab, tparm); } } catch (NoSuchMethodException e) { System.out.println("args(build,method): " + Arrays.toString(args)); return gb; } catch (IllegalAccessException e) { System.out.println("args(build,access): " + Arrays.toString(args)); return gb; } catch (InvocationTargetException e) { System.out.println("args(build,invocation): " + Arrays.toString(args)); return gb; } catch (NumberFormatException e) { System.out.println("args(build,number): " + Arrays.toString(args)); return gb; } } gb = ab.build(); //System.out.println("gb = " + gb); return gb; } } java-algebra-system-2.7.200/src/edu/jas/application/RunSGB.java000066400000000000000000000247001445075545500241300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.StringReader; import java.io.IOException; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.BufferedReader; import java.nio.charset.Charset; import java.util.List; import java.util.Arrays; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseParallel; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.gb.SolvableGroebnerBaseSeqPairParallel; import edu.jas.gb.SolvableReduction; import edu.jas.gb.SolvableReductionPar; import edu.jas.gb.SolvableReductionSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.util.CatReader; /** * Simple setup to run a solvable GB example.
Usage: RunSGB * [seq|par|par+] [irr|left|right|two] <file> #procs * @author Heinz Kredel */ public class RunSGB { /** * Check result GB if it is a GB. */ static boolean doCheck = false; /** * main method to be called from commandline
Usage: RunSGB * [seq|seq+|par|par+] [irr|left|right|two] <file> #procs */ @SuppressWarnings("unchecked") public static void main(String[] args) { String[] allkinds = new String[] { "seq", "seq+", "par", "par+", //"dist", "dist+", , //"disthyb", "disthyb+", //"cli" }; // must be last String[] allmeth = new String[] { "irr", "left", "right", "two" }; String usage = "Usage: RunSGB [ " + join(allkinds, " | ") //+ "[port] ] " + " ] [" + join(allmeth, " | ") + "] " + "#threads " //+ "#procs/#threadsPerNode " //+ "[machinefile] "; + "[check] "; if (args.length < 3) { System.out.println("args: " + Arrays.toString(args)); System.out.println(usage); return; } boolean plusextra = false; String kind = args[0]; boolean sup = false; int k = -1; for (int i = 0; i < args.length; i++) { int j = indexOf(allkinds, args[i]); if (j < 0) { continue; } sup = true; k = i; kind = args[k]; break; } if (!sup) { System.out.println("args(sup): " + Arrays.toString(args)); System.out.println(usage); return; } if (kind.indexOf("+") >= 0) { plusextra = true; } System.out.println("kind: " + kind + ", k = " + k); String action = args[k + 1]; sup = false; int j = indexOf(allmeth, action); if (j < 0) { System.out.println(usage); return; } String filename = args[k + 2]; int threads = 0; if (kind.startsWith("par")) { if (args.length < 4) { System.out.println("args(par): " + Arrays.toString(args)); System.out.println(usage); return; } String tup = args[k + 3]; String t = tup; try { threads = Integer.parseInt(t); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("args(threads): " + Arrays.toString(args)); System.out.println(usage); return; } if (threads < 1) { threads = 1; } } j = indexOf(args, "check"); if (j >= 0) { doCheck = true; } Reader problem = RunGB.getReader(filename); if (problem == null) { System.out.println("args(file): " + filename); System.out.println("args(file): examples.jar(" + filename + ")"); System.out.println("args(file): " + Arrays.toString(args)); System.out.println(usage); return; } RingFactoryTokenizer rftok = new RingFactoryTokenizer(problem); GenSolvablePolynomialRing spfac = null; try { spfac = rftok.nextSolvablePolynomialRing(); rftok = null; } catch (IOException e) { e.printStackTrace(); return; } Reader polyreader = new CatReader(new StringReader("("),problem); // ( has gone //Reader polyreader = problem; GenPolynomialTokenizer tok = new GenPolynomialTokenizer(spfac,polyreader); PolynomialList S = null; try { S = new PolynomialList(spfac,tok.nextSolvablePolynomialList()); } catch (IOException e) { e.printStackTrace(); return; } System.out.println("S =\n" + S); if (kind.startsWith("seq")) { runSequential(S, action, plusextra); } else if (kind.startsWith("par")) { runParallel(S, threads, action, plusextra); } ComputerThreads.terminate(); try { problem.close(); } catch (IOException ignored) { } } /** * run Sequential. * @param S polynomial list. * @param action what to to. */ @SuppressWarnings("unchecked") static void runSequential(PolynomialList S, String action, boolean plusextra) { List L = S.list; List G = null; long t; SolvableReduction sred = new SolvableReductionSeq(); SolvableGroebnerBase sbb = null; if (plusextra) { //sbb = new SolvableGroebnerBaseSeqPlusextra(); //System.out.println("SolvableGroebnerBaseSeqPlusextra not implemented using SolvableGroebnerBaseSeq"); sbb = new SolvableGroebnerBaseSeq(sred); } else { sbb = new SolvableGroebnerBaseSeq(); } t = System.currentTimeMillis(); System.out.println("\nSolvable GB [" + action + "] sequential ..."); if (action.equals("irr")) { G = sred.leftIrreducibleSet(L); } if (action.equals("left")) { G = sbb.leftGB(L); } if (action.equals("right")) { G = sbb.rightGB(L); } if (action.equals("two")) { G = sbb.twosidedGB(L); } if (G == null) { System.out.println("unknown action = " + action + "\n"); return; } S = new PolynomialList(S.ring, G); System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("seq+, "); } else { System.out.print("seq, "); } System.out.println("time = " + t + " milliseconds"); checkGB(S); System.out.println(""); } /** * run Parallel. * @param S polynomial list. * @param action what to to. */ @SuppressWarnings("unchecked") static void runParallel(PolynomialList S, int threads, String action, boolean plusextra) { List L = S.list; List G = null; long t; SolvableReduction sred = new SolvableReductionPar(); SolvableGroebnerBaseParallel sbb = null; SolvableGroebnerBaseSeqPairParallel sbbs = null; if (plusextra) { sbbs = new SolvableGroebnerBaseSeqPairParallel(threads); } else { sbb = new SolvableGroebnerBaseParallel(threads); } t = System.currentTimeMillis(); System.out.println("\nSolvable GB [" + action + "] parallel " + threads + " threads ..."); if (action.equals("irr")) { G = sred.leftIrreducibleSet(L); } if (action.equals("left")) { if (plusextra) { G = sbbs.leftGB(L); } else { G = sbb.leftGB(L); } } if (action.equals("right")) { if (plusextra) { G = sbbs.rightGB(L); } else { G = sbb.rightGB(L); } } if (action.equals("two")) { if (plusextra) { G = sbbs.twosidedGB(L); } else { G = sbb.twosidedGB(L); } } if (G == null) { System.out.println("unknown action = " + action + "\n"); return; } if (G.size() > 0) { S = new PolynomialList(G.get(0).ring, G); } else { S = new PolynomialList(S.ring, G); } System.out.println("G =\n" + S); System.out.println("G.size() = " + G.size()); t = System.currentTimeMillis() - t; if (plusextra) { System.out.print("p+ "); } else { System.out.print("p "); } System.out.println("= " + threads + ", time = " + t + " milliseconds"); checkGB(S); System.out.println(""); if (plusextra) { sbbs.terminate(); } else { sbb.terminate(); } } @SuppressWarnings("unchecked") static void checkGB(PolynomialList S) { if (!doCheck) { return; } SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); long t = System.currentTimeMillis(); boolean chk = sbb.isLeftGB(S.list,false); t = System.currentTimeMillis() - t; System.out.println("check isGB = " + chk + " in " + t + " milliseconds"); } static int indexOf(String[] args, String s) { for (int i = 0; i < args.length; i++) { if (s.equals(args[i])) { return i; } } return -1; } static String join(String[] args, String d) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < args.length; i++) { if (i > 0) { sb.append(d); } sb.append(args[i]); } return sb.toString(); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableIdeal.java000066400000000000000000001332051445075545500255370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableExtendedGB; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableReduction; import edu.jas.gb.SolvableReductionSeq; import edu.jas.gbufd.PolyGBUtil; import edu.jas.gbufd.SGBFactory; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Solvable Ideal implements some methods for ideal arithmetic, for example sum, * intersection, quotient. Note: only left ideals at the moment. * @author Heinz Kredel */ public class SolvableIdeal> implements Comparable>, Serializable { private static final Logger logger = LogManager.getLogger(SolvableIdeal.class); private static final boolean debug = logger.isDebugEnabled(); /** * Side variant of ideal. */ public static enum Side { left, right, twosided } /** * The data structure is a PolynomialList. */ protected PolynomialList list; /** * Indicator if list is a Groebner Base. */ protected boolean isGB; /** * Indicator of side of Groebner Base. */ protected Side sided; /** * Indicator if test has been performed if this is a Groebner Base. */ protected boolean testGB; /** * Indicator if list has optimized term order. */ protected boolean isTopt; /** * Groebner base engine. */ protected final SolvableGroebnerBaseAbstract bb; /** * Reduction engine. */ protected final SolvableReduction red; /** * Constructor. * @param ring solvable polynomial ring */ public SolvableIdeal(GenSolvablePolynomialRing ring) { this(ring, new ArrayList>()); } /** * Constructor. * @param ring solvable polynomial ring * @param F list of solvable polynomials */ public SolvableIdeal(GenSolvablePolynomialRing ring, List> F) { this(new PolynomialList(ring, F)); } /** * Constructor. * @param ring solvable polynomial ring * @param F list of solvable polynomials * @param gb true if F is known to be a Groebner Base, else false */ public SolvableIdeal(GenSolvablePolynomialRing ring, List> F, boolean gb) { this(new PolynomialList(ring, F), gb); } /** * Constructor. * @param ring solvable polynomial ring * @param F list of solvable polynomials * @param gb true if F is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false */ public SolvableIdeal(GenSolvablePolynomialRing ring, List> F, boolean gb, boolean topt) { this(new PolynomialList(ring, F), gb, topt); } /** * Constructor. * @param ring solvable polynomial ring * @param F list of solvable polynomials * @param s side variant of ideal or Groebner Base */ public SolvableIdeal(GenSolvablePolynomialRing ring, List> F, Side s) { this(new PolynomialList(ring, F), false, false, s); } /** * Constructor. * @param ring solvable polynomial ring * @param F list of solvable polynomials * @param gb true if F is known to be a Groebner Base, else false * @param s side variant of ideal or Groebner Base */ public SolvableIdeal(GenSolvablePolynomialRing ring, List> F, boolean gb, Side s) { this(new PolynomialList(ring, F), gb, false, s); } /** * Constructor. * @param list solvable polynomial list */ public SolvableIdeal(PolynomialList list) { this(list, false); } /** * Constructor. * @param list solvable polynomial list * @param bb Groebner Base engine * @param red Reduction engine */ public SolvableIdeal(PolynomialList list, SolvableGroebnerBaseAbstract bb, SolvableReduction red) { this(list, false, bb, red); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false */ public SolvableIdeal(PolynomialList list, boolean gb) { //this(list, gb, new SolvableGroebnerBaseSeq(), new SolvableReductionSeq()); this(list, gb, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq()); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false */ public SolvableIdeal(PolynomialList list, boolean gb, boolean topt) { //this(list, gb, topt, new SolvableGroebnerBaseSeq(), new SolvableReductionSeq()); this(list, gb, topt, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq()); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param s side variant of ideal or Groebner Base */ public SolvableIdeal(PolynomialList list, boolean gb, Side s) { //this(list, gb, false, new SolvableGroebnerBaseSeq(), new SolvableReductionSeq()); this(list, gb, false, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq(), s); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param s side variant of ideal or Groebner Base */ public SolvableIdeal(PolynomialList list, boolean gb, boolean topt, Side s) { //this(list, gb, topt, new SolvableGroebnerBaseSeq(), new SolvableReductionSeq()); this(list, gb, topt, SGBFactory.getImplementation(list.ring.coFac), new SolvableReductionSeq(), s); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine * @param red Reduction engine */ public SolvableIdeal(PolynomialList list, boolean gb, SolvableGroebnerBaseAbstract bb, SolvableReduction red) { this(list, gb, false, bb, red); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine */ public SolvableIdeal(PolynomialList list, boolean gb, SolvableGroebnerBaseAbstract bb) { this(list, gb, false, bb, bb.sred); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param bb Groebner Base engine */ public SolvableIdeal(PolynomialList list, boolean gb, boolean topt, SolvableGroebnerBaseAbstract bb) { this(list, gb, topt, bb, bb.sred); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param bb Groebner Base engine * @param red Reduction engine */ public SolvableIdeal(PolynomialList list, boolean gb, boolean topt, SolvableGroebnerBaseAbstract bb, SolvableReduction red) { this(list, gb, topt, bb, red, Side.left); } /** * Constructor. * @param list solvable polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param topt true if term order is optimized, else false * @param bb Groebner Base engine * @param red Reduction engine * @param s side variant of ideal or Groebner Base */ public SolvableIdeal(PolynomialList list, boolean gb, boolean topt, SolvableGroebnerBaseAbstract bb, SolvableReduction red, Side s) { if (list == null || list.list == null) { throw new IllegalArgumentException("list and list.list may not be null"); } this.list = list; this.isGB = gb; this.isTopt = topt; this.testGB = (gb ? true : false); // ?? this.bb = bb; this.red = red; if (s == null) { s = Side.left; // default } this.sided = s; } /** * Clone this. * @return a copy of this. */ public SolvableIdeal copy() { return new SolvableIdeal(list.copy(), isGB, isTopt, bb, red, sided); } /** * Get the List of GenSolvablePolynomials. * @return (cast) list.list */ public List> getList() { return list.getSolvableList(); } /** * Get the GenSolvablePolynomialRing. * @return (cast) list.ring */ public GenSolvablePolynomialRing getRing() { return list.getSolvableRing(); } /** * Get the zero ideal. * @return ideal(0) */ public SolvableIdeal getZERO() { List> z = new ArrayList>(0); PolynomialList pl = new PolynomialList(getRing(), z); return new SolvableIdeal(pl, true, isTopt, bb, red, sided); } /** * Get the one ideal. * @return ideal(1) */ public SolvableIdeal getONE() { List> one = new ArrayList>(1); one.add(getRing().getONE()); PolynomialList pl = new PolynomialList(getRing(), one); return new SolvableIdeal(pl, true, isTopt, bb, red, sided); } /** * String representation of the solvable ideal. * @see java.lang.Object#toString() */ @Override public String toString() { return list.toString() + " # " + sided + "-GB: " + isGB; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { // any script case return list.toScript() + " # " + sided + "-GB: " + isGB; } /** * Comparison with any other object. Note: If not both ideals are * Groebner Bases, then false may be returned even the ideals are equal. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof SolvableIdeal)) { logger.warn("equals no SolvableIdeal"); return false; } SolvableIdeal B = null; try { B = (SolvableIdeal) b; } catch (ClassCastException ignored) { return false; } //if ( isGB && B.isGB ) { // return list.equals( B.list ); requires also monic polys //} else { // compute GBs ? return this.contains(B) && B.contains(this); //} } /** * SolvableIdeal comparison. * @param L other solvable ideal. * @return compareTo() of polynomial lists. */ public int compareTo(SolvableIdeal L) { return list.compareTo(L.list); } /** * Hash code for this solvable ideal. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = list.hashCode(); if (isGB) { h = h << 1; } if (testGB) { h += 1; } return h; } /** * Test if ZERO ideal. * @return true, if this is the 0 ideal, else false */ public boolean isZERO() { return list.isZERO(); } /** * Test if ONE is contained in the ideal. To test for a proper ideal use * ! id.isONE(). * @return true, if this is the 1 ideal, else false */ public boolean isONE() { return list.isONE(); } /** * Test if this is a left Groebner base. * @return true, if this is a left/right/twosided Groebner base, else false */ public boolean isGB() { if (testGB) { return isGB; } testGB = true; boolean igb = false; if (sided == Side.left) { igb = bb.isLeftGB(getList()); } else if (sided == Side.right) { igb = bb.isRightGB(getList()); } else if (sided == Side.twosided) { igb = bb.isTwosidedGB(getList()); } isGB = igb; return isGB; } /** * Do Groebner Base. compute the left Groebner Base for this ideal. */ @SuppressWarnings("unchecked") public void doGB() { if (isGB && sided == Side.left) { return; } if (isGB && sided == Side.twosided) { return; } if (isGB && sided == Side.right) { return; } // if (sided == Side.right) { // logger.warn("wrong usage for left sided GB: {}", sided); // throw new IllegalArgumentException("wrong usage for left sided GB: " + sided); // } List> G = getList(); if (sided == Side.left) { logger.info("leftGB computing = {}", G); G = bb.leftGB(G); } else if (sided == Side.twosided) { logger.info("twosidedGB computing = {}", G); G = bb.twosidedGB(G); } else if (sided == Side.right) { logger.info("rightGB computing = {}", G); G = bb.rightGB(G); } //if (isTopt) { // List perm = ((OptimizedPolynomialList) list).perm; // list = new OptimizedPolynomialList(perm, getRing(), G); //} else { //} list = new PolynomialList(getRing(), G); isGB = true; testGB = true; return; } /** * Groebner Base. Get a left Groebner Base for this ideal. * @return leftGB(this) */ public SolvableIdeal GB() { if (isGB && sided == Side.left) { return this; } doGB(); return this; } /** * Test if this is a twosided Groebner base. * @return true, if this is a twosided Groebner base, else false */ public boolean isTwosidedGB() { if (testGB && sided == Side.twosided) { return isGB; } logger.warn("isTwosidedGB computing"); isGB = bb.isTwosidedGB(getList()); testGB = true; //sided = Side.twosided; return isGB; } /** * Groebner Base. Get a twosided Groebner Base for this ideal. * @return twosidedGB(this) */ public SolvableIdeal twosidedGB() { if (isGB && sided == Side.twosided) { return this; } //logger.warn("GB computing"); List> G = getList(); logger.info("twosidedGB computing = {}", G); G = bb.twosidedGB(G); PolynomialList li = new PolynomialList(getRing(), G); SolvableIdeal tsgb = new SolvableIdeal(li, true, true, bb, red, Side.twosided); return tsgb; } /** * Test if this is a right Groebner base. * @return true, if this is a right Groebner base, else false */ public boolean isRightGB() { if (testGB && sided == Side.right) { return isGB; } if (isGB && sided == Side.twosided) { return true; } logger.warn("isRightGB computing"); isGB = bb.isRightGB(getList()); testGB = true; //sided = Side.right; return isGB; } /** * Groebner Base. Get a right Groebner Base for this ideal. * @return rightGB(this) */ public SolvableIdeal rightGB() { if (isGB && sided == Side.twosided) { return this; } if (isGB && sided == Side.right) { return this; } //logger.warn("GB computing"); List> G = getList(); logger.info("rightGB computing = {}", G); G = bb.rightGB(G); PolynomialList li = new PolynomialList(getRing(), G); SolvableIdeal rgb = new SolvableIdeal(li, true, true, bb, red, Side.right); return rgb; } /** * Solvable ideal containment. Test if B is contained in this ideal. Note: * this is eventually modified to become a Groebner Base. * @param B solvable ideal * @return true, if B is contained in this, else false */ public boolean contains(SolvableIdeal B) { if (B == null || B.isZERO()) { return true; } return contains(B.getList()); } /** * Solvable ideal containment. Test if b is contained in this * left/right/twosided ideal. Note: this is eventually modified to * become a Groebner Base. * @param b solvable polynomial * @return true, if b is contained in this, else false */ public boolean contains(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return true; } if (this.isONE()) { return true; } if (this.isZERO()) { return false; } if (!isGB) { doGB(); } GenSolvablePolynomial z = normalform(b); // left/right/twosided if (z == null || z.isZERO()) { return true; } return false; } /** * Solvable ideal containment. Test if each b in B is contained in * this left/right/twosided ideal. Note: this is eventually * modified to become a Groebner Base. * @param B list of solvable polynomials * @return true, if each b in B is contained in this, else false */ public boolean contains(List> B) { if (B == null || B.size() == 0) { return true; } if (this.isONE()) { return true; } if (!isGB) { doGB(); } List> si = getList(); for (GenSolvablePolynomial b : B) { if (b == null) { continue; } if (! contains(b)) { return false; } } return true; } /** * Solvable ideal summation. Generators for the sum of ideals. Note: if both * ideals are Groebner bases, a Groebner base is returned. * @param B solvable ideal * @return ideal(this+B) */ public SolvableIdeal sum(SolvableIdeal B) { if (B == null || B.isZERO()) { return this; } if (this.isZERO()) { return B; } return sum(B.getList()); } /** * Solvable summation. Generators for the sum of ideal and a polynomial. * Note: if this ideal is a Groebner base, a Groebner base is returned. * @param b solvable polynomial * @return ideal(this+{b}) */ public SolvableIdeal sum(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return this; } List> B = new ArrayList>(1); B.add(b); return sum(B); } /** * Solvable summation. Generators for the sum of this ideal and a list of * polynomials. Note: if this ideal is a Groebner base, a Groebner base is * returned. * @param L list of solvable polynomials * @return ideal(this+L) */ public SolvableIdeal sum(List> L) { if (L == null || L.isEmpty()) { return this; } int s = getList().size() + L.size(); List> c = new ArrayList>(s); c.addAll(getList()); c.addAll(L); SolvableIdeal I = new SolvableIdeal(getRing(), c, false, sided); if (isGB) { I.doGB(); // left/right/twosided } return I; } /** * Product. Generators for the product of ideals. Note: if both ideals are * Groebner bases, a Groebner base is returned. * @param B solvable ideal * @return ideal(this*B) */ public SolvableIdeal product(SolvableIdeal B) { if (B == null || B.isZERO()) { return B; } if (this.isZERO()) { return this; } int s = getList().size() * B.getList().size(); List> c; c = new ArrayList>(s); for (GenSolvablePolynomial p : getList()) { for (GenSolvablePolynomial q : B.getList()) { q = p.multiply(q); c.add(q); } } SolvableIdeal I = new SolvableIdeal(getRing(), c, false, sided); if (isGB && B.isGB) { I.doGB(); // left/right/twosided } return I; } /** * Product. Generators for the product of this by a polynomial. * @param b solvable polynomial * @return ideal(this*b) */ public SolvableIdeal product(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } List> c; c = new ArrayList>(getList().size()); for (GenSolvablePolynomial p : getList()) { GenSolvablePolynomial q = p.multiply(b); c.add(q); } SolvableIdeal I = new SolvableIdeal(getRing(), c, false, sided); if (isGB) { I.doGB(); // left/right/twosided } return I; } /** * Left product. Generators for the product of a polynomial by this. * @param b solvable polynomial * @return ideal(b*this) */ public SolvableIdeal leftProduct(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } List> c; c = new ArrayList>(getList().size()); for (GenSolvablePolynomial p : getList()) { GenSolvablePolynomial q = b.multiply(p); c.add(q); } SolvableIdeal I = new SolvableIdeal(getRing(), c, false, sided); if (isGB) { I.doGB(); // left/right/twosided } return I; } /** * Intersection. Generators for the intersection of ideals. Using an * iterative algorithm. * @param Bl list of solvable ideals * @return ideal(cap_i B_i), a Groebner base */ public SolvableIdeal intersect(List> Bl) { if (Bl == null || Bl.size() == 0) { return getZERO(); } SolvableIdeal I = null; for (SolvableIdeal B : Bl) { if (I == null) { I = B; continue; } if (I.isONE()) { return I; } I = I.intersect(B); } return I; } /** * Intersection. Generators for the intersection of ideals. * @param B solvable ideal * @return ideal(this \cap B), a Groebner base */ public SolvableIdeal intersect(SolvableIdeal B) { if (B == null || B.isZERO()) { // (0) return B; } if (this.isZERO()) { return this; } List> c = PolyGBUtil. intersect(getRing(), getList(), B.getList()); SolvableIdeal I = new SolvableIdeal(getRing(), c, true, sided); return I; } /** * Intersection. Generators for the intersection of a ideal with a * polynomial ring. The polynomial ring R must be a contraction * of this ideal and the TermOrder must be an elimination order. * @param R solvable polynomial ring * @return ideal(this \cap R) */ public SolvableIdeal intersect(GenSolvablePolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } String[] rvars = R.getVars(); String[] tvars = getRing().getVars(); for (int i = 0; i < rvars.length; i++) { if (!rvars[i].equals(tvars[i])) { throw new IllegalArgumentException("no contraction: " + R.toScript() + " of " + getRing().toScript()); } } List> H = PolyUtil. intersect(R, getList()); return new SolvableIdeal(R, H, isGB, sided); } /** * Eliminate. Generators for the intersection of this ideal with a solvable * polynomial ring. The solvable polynomial ring of this ideal must be a * contraction of R and the TermOrder must be an elimination order. * @param R solvable polynomial ring * @return ideal(this \cap R) */ public SolvableIdeal eliminate(GenSolvablePolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } if (getRing().equals(R)) { return this; } return intersect(R); } /** * Quotient. Generators for the solvable ideal quotient. * @param h solvable polynomial * @return ideal(this : h), a Groebner base */ //@SuppressWarnings("unchecked") public SolvableIdeal quotient(GenSolvablePolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } List> H; H = new ArrayList>(1); H.add(h); SolvableIdeal Hi = new SolvableIdeal(getRing(), H, true, sided); SolvableIdeal I = this.intersect(Hi); List> Q; Q = new ArrayList>(I.getList().size()); GenSolvablePolynomial p; for (GenSolvablePolynomial q : I.getList()) { p = q.divide(h); // remainder == 0, (GenSolvablePolynomial) if (!p.isZERO()) { p = p.monic(); Q.add(p); } if (debug) { GenSolvablePolynomial r = q.remainder(h); // (GenSolvablePolynomial) if (!r.isZERO()) { System.out.println("error remainder !=0: " + r + ", q = " + q + ", h = " + h); throw new RuntimeException("remainder !=0"); } } } return new SolvableIdeal(getRing(), Q, true /*false?*/, sided); } /** * Quotient. Generators for the solvable ideal quotient. * @param H solvable ideal * @return ideal(this : H), a Groebner base */ public SolvableIdeal quotient(SolvableIdeal H) { if (H == null || H.isZERO()) { // == (0) return this; } if (this.isZERO()) { return this; } SolvableIdeal Q = null; for (GenSolvablePolynomial h : H.getList()) { SolvableIdeal Hi = this.quotient(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Infinite quotient. Generators for the infinite solvable ideal quotient. * @param h solvable polynomial * @return ideal(this : hs), a Groebner base */ public SolvableIdeal infiniteQuotientRab(GenSolvablePolynomial h) { if (h == null || h.isZERO()) { // == (0) return getONE(); } if (h.isONE()) { return this; } if (this.isZERO()) { return this; } if (!getRing().isCommutative()) { throw new UnsupportedOperationException("Rabinowich trick only for commutative polynomial rings"); } SolvableIdeal I = this.GB(); // should be already List> a = I.getList(); List> c; c = new ArrayList>(a.size() + 1); GenSolvablePolynomialRing tfac = getRing().extend(1); // term order is also adjusted for (GenSolvablePolynomial p : a) { p = (GenSolvablePolynomial) p.extend(tfac, 0, 0L); // p c.add(p); } GenSolvablePolynomial q = (GenSolvablePolynomial) h.extend(tfac, 0, 1L); GenSolvablePolynomial r = tfac.getONE(); // h.extend( tfac, 0, 0L ); GenSolvablePolynomial hs = (GenSolvablePolynomial) q.subtract(r); // 1 - t*h // (1-t)*h c.add(hs); logger.warn("infiniteQuotientRab computing GB "); List> g = bb.leftGB(c); if (debug) { logger.info("infiniteQuotientRab = {}, c = {}", tfac, c); logger.info("infiniteQuotientRab GB = {}", g); } SolvableIdeal E = new SolvableIdeal(tfac, g, true, sided); SolvableIdeal Is = E.intersect(getRing()); return Is; } /** * Infinite quotient exponent. * @param h solvable polynomial * @param Q quotient this : h^\infinity * @return s with Q = this : hs */ public int infiniteQuotientExponent(GenSolvablePolynomial h, SolvableIdeal Q) { int s = 0; if (h == null) { // == 0 return s; } if (h.isZERO() || h.isONE()) { return s; } if (this.isZERO() || this.isONE()) { return s; } //see below: if (this.contains(Q)) { // return s; //} GenSolvablePolynomial p = getRing().getONE(); for (GenSolvablePolynomial q : Q.getList()) { if (this.contains(q)) { continue; } //System.out.println("q = " + q + ", p = " + p + ", s = " + s); GenSolvablePolynomial qp = q.multiply(p); while (!this.contains(qp)) { p = p.multiply(h); s++; qp = q.multiply(p); } } return s; } /** * Infinite quotient. Generators for the infinite solvable ideal quotient. * @param h solvable polynomial * @return ideal(this : hs), a Groebner base */ public SolvableIdeal infiniteQuotient(GenSolvablePolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } int s = 0; SolvableIdeal I = this.GB(); // should be already GenSolvablePolynomial hs = h; SolvableIdeal Is = null; logger.info("infiniteQuotient hs = {}", hs); long dm = -1; boolean eq = false; while (!eq) { Is = I.quotient(hs); Is = Is.GB(); // should be already //logger.info("ideal Is = {}", Is); logger.info("infiniteQuotient s = {}", s); if (Is.isZERO()) { logger.warn("infiniteQuotient does not exist"); return I; } eq = Is.contains(I); // I.contains(Is) always if (!eq) { long ds = PolyUtil. totalDegree(Is.list.getList()); if (dm < 0) { dm = ds; } //System.out.println("deg(Is) = " + ds); if (ds > dm) { logger.warn("no convergence in infiniteQuotient (dm,ds): {} < {}", dm, ds); return I; //throw new RuntimeException("no convergence in infiniteQuotient"); } I = Is; s++; // hs = hs.multiply( h ); } } return Is; } /** * Radical membership test. * @param h solvable polynomial * @return true if h is contained in the radical of ideal(this), else false. */ public boolean isRadicalMember(GenSolvablePolynomial h) { if (h == null) { // == (0) return true; } if (h.isZERO()) { return true; } if (this.isZERO()) { return true; } SolvableIdeal x = infiniteQuotientRab(h); // may fail if (debug) { logger.debug("infiniteQuotientRab = {}", x); } return x.isONE(); } /** * Infinite Quotient. Generators for the solvable ideal infinite quotient. * @param H solvable ideal * @return ideal(this : Hs), a Groebner base */ public SolvableIdeal infiniteQuotient(SolvableIdeal H) { if (H == null) { // == (0) return this; } if (H.isZERO()) { return this; } if (this.isZERO()) { return this; } SolvableIdeal Q = null; for (GenSolvablePolynomial h : H.getList()) { SolvableIdeal Hi = this.infiniteQuotient(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Infinite Quotient. Generators for the solvable ideal infinite quotient. * @param H solvable ideal * @return ideal(this : Hs), a Groebner base */ public SolvableIdeal infiniteQuotientRab(SolvableIdeal H) { if (H == null) { // == (0) return this; } if (H.isZERO()) { return this; } if (this.isZERO()) { return this; } SolvableIdeal Q = null; for (GenSolvablePolynomial h : H.getList()) { SolvableIdeal Hi = this.infiniteQuotientRab(h); // may fail if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } /** * Power. Generators for the power of this solvable ideal. Note: if this * ideal is a Groebner base, a Groebner base is returned. * @param d integer * @return ideal(this^d) */ public SolvableIdeal power(int d) { if (d <= 0) { return getONE(); } if (this.isZERO() || this.isONE()) { return this; } SolvableIdeal c = this; for (int i = 1; i < d; i++) { c = c.product(this); } return c; } /** * Normalform for element. * @param h solvable polynomial * @return left/right/twosided normalform of h with respect to this */ public GenSolvablePolynomial normalform(GenSolvablePolynomial h) { if (h == null) { return h; } if (h.isZERO()) { return h; } if (this.isZERO()) { return h; } GenSolvablePolynomial r; if (sided == Side.left) { r = red.leftNormalform(getList(), h); } else if (sided == Side.right) { r = red.rightNormalform(getList(), h); } else { //if (sided == Side.twosided) { //r = red.twosidedNormalform(getList(), h); //r = red.normalform(getList(), h); r = red.leftNormalform(getList(), h); } return r; } /** * Normalform for list of solvable elements. * @param L solvable polynomial list * @return list of left normalforms of the elements of L with respect to * this */ public List> normalform(List> L) { if (L == null) { return L; } if (L.isEmpty()) { return L; } if (this.isZERO()) { return L; } List> M = new ArrayList>(L.size()); for (GenSolvablePolynomial h : L) { GenSolvablePolynomial r = normalform(h); if (r != null && !r.isZERO()) { M.add(r); } } return M; } /** * Annihilator for element modulo this ideal. * @param h solvable polynomial * @return annihilator of h with respect to this */ public SolvableIdeal annihilator(GenSolvablePolynomial h) { if (h == null || h.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } doGB(); List> F = new ArrayList>(1 + getList().size()); F.add(h); F.addAll(getList()); //System.out.println("F = " + F); SolvableSyzygyAbstract syz = new SolvableSyzygySeq(getRing().coFac); List>> S = syz.leftZeroRelationsArbitrary(F); //System.out.println("S = " + S); List> gen = new ArrayList>(S.size()); for (List> rel : S) { if (rel == null || rel.isEmpty()) { continue; } GenSolvablePolynomial p = rel.get(0); if (p == null || p.isZERO()) { continue; } gen.add(p); } SolvableIdeal ann = new SolvableIdeal(getRing(), gen, false, sided); //System.out.println("ann = " + ann); return ann; } /** * Test for annihilator of element modulo this ideal. * @param h solvable polynomial * @param A solvable ideal * @return true, if A is the annihilator of h with respect to this */ public boolean isAnnihilator(GenSolvablePolynomial h, SolvableIdeal A) { SolvableIdeal B = A.product(h); return contains(B); } /** * Annihilator for ideal modulo this ideal. * @param H solvable ideal * @return annihilator of H with respect to this */ public SolvableIdeal annihilator(SolvableIdeal H) { if (H == null || H.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } SolvableIdeal ann = null; for (GenSolvablePolynomial h : H.getList()) { SolvableIdeal Hi = this.annihilator(h); if (ann == null) { ann = Hi; } else { ann = ann.intersect(Hi); } } return ann; } /** * Test for annihilator of ideal modulo this ideal. * @param H solvable ideal * @param A solvable ideal * @return true, if A is the annihilator of H with respect to this */ public boolean isAnnihilator(SolvableIdeal H, SolvableIdeal A) { SolvableIdeal B = A.product(H); return contains(B); } /** * Inverse for element modulo this ideal. * @param h solvable polynomial * @return inverse of h with respect to this, if defined */ public GenSolvablePolynomial inverse(GenSolvablePolynomial h) { if (h == null || h.isZERO()) { throw new NotInvertibleException("zero not invertible"); } if (this.isZERO()) { throw new NotInvertibleException("zero ideal"); } doGB(); if (this.isONE()) { throw new NotInvertibleException("one ideal"); } if (h.isUnit()) { return (GenSolvablePolynomial) h.inverse(); } List> F = new ArrayList>(1 + list.list.size()); F.add(h); F.addAll(getList()); //System.out.println("F = " + F); SolvableExtendedGB x = bb.extLeftGB(F); List> G = x.G; //System.out.println("G = " + G); GenSolvablePolynomial one = null; int i = -1; for (GenSolvablePolynomial p : G) { i++; if (p == null) { continue; } if (p.isUnit()) { one = p; break; } } if (one == null) { throw new NotInvertibleException("one == null: h = " + h); } List> row = x.G2F.get(i); // != -1 //System.out.println("row = " + row); GenSolvablePolynomial g = row.get(0); if (g == null || g.isZERO()) { throw new NotInvertibleException("g == 0: h = " + h); } GenSolvablePolynomial gp = red.leftNormalform(getList(), g); if (gp.isZERO()) { // can happen with solvable rings throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); } // adjust leading coefficient of g to get g*h == 1 GenSolvablePolynomial f = g.multiply(h); //System.out.println("f = " + f); GenSolvablePolynomial k = red.leftNormalform(getList(), f); //System.out.println("k = " + k); if (!k.isONE()) { C lbc = k.leadingBaseCoefficient(); lbc = lbc.inverse(); g = g.multiply(lbc); } if (debug) { //logger.info("inv G = {}", G); //logger.info("inv G2F = {}", x.G2F); //logger.info("inv row {} = {}", i, row); //logger.info("inv h = {}", h); //logger.info("inv g = {}", g); //logger.info("inv f = {}", f); f = g.multiply(h); k = red.leftNormalform(getList(), f); logger.debug("inv k = {}", k); if (!k.isUnit()) { throw new NotInvertibleException(" k = " + k); } } return g; } /** * Test if element is a unit modulo this ideal. * @param h solvable polynomial * @return true if h is a unit with respect to this, else false */ public boolean isUnit(GenSolvablePolynomial h) { if (h == null || h.isZERO()) { return false; } if (this.isZERO()) { return false; } doGB(); if (this.isONE()) { return false; } List> F = new ArrayList>(1 + list.list.size()); F.add(h); F.addAll(getList()); List> G = bb.leftGB(F); for (GenSolvablePolynomial p : G) { if (p == null) { continue; } if (p.isUnit()) { return true; } } return false; } /** * Ideal common zero test. * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest() { if (this.isZERO()) { return 1; } if (!isGB) { doGB(); } if (this.isONE()) { return -1; } return bb.commonZeroTest(getList()); } /** * Test if this ideal is maximal. * @return true, if this is certainly maximal and not one, * false, if this is one, has dimension ≥ 1 or it is not jet determined if it is maximal. */ public boolean isMaximal() { if (commonZeroTest() != 0) { return false; } for (Long d : univariateDegrees()) { if (d > 1L) { return false; } } return true; } /** * Univariate head term degrees. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees() { List ud = new ArrayList(); if (this.isZERO()) { return ud; } if (!isGB) { doGB(); } if (this.isONE()) { return ud; } return bb.univariateDegrees(getList()); } /** * Ideal dimension. * @return a dimension container (dim,maxIndep,list(maxIndep),vars). */ public Dimension dimension() { Ideal ci = new Ideal(list); return ci.dimension(); } /** * Construct univariate polynomials of minimal degree in all variables in * zero dimensional ideal(G). * @return list of univariate solvable polynomial of minimal degree in each * variable in ideal(G) */ public List> constructUnivariate() { List> univs = new ArrayList>(); for (int i = getRing().nvar - 1; i >= 0; i--) { GenSolvablePolynomial u = constructUnivariate(i); univs.add(u); } return univs; } /** * Construct univariate polynomial of minimal degree in variable i in zero * dimensional ideal(G). * @param i variable index. * @return univariate solvable polynomial of minimal degree in variable i in * ideal(G) */ public GenSolvablePolynomial constructUnivariate(int i) { doGB(); return bb.constructUnivariate(i, getList()); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableLocal.java000066400000000000000000000424761445075545500255640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Arrays; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.fd.FDUtil; import edu.jas.gbufd.PolyModUtil; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; /** * SolvableLocal ring element based on pairs of GenSolvablePolynomial with * GcdRingElem interface. Objects of this class are immutable. * @author Heinz Kredel */ public class SolvableLocal> implements GcdRingElem>, QuotPair> { private static final Logger logger = LogManager.getLogger(SolvableLocal.class); private static final boolean debug = logger.isDebugEnabled(); /** * SolvableLocal class factory data structure. */ public final SolvableLocalRing ring; /** * Numerator part of the element data structure. */ public final GenSolvablePolynomial num; /** * Denominator part of the element data structure. */ public final GenSolvablePolynomial den; /** * Flag to remember if this local element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a SolvableLocal object from a ring factory. * @param r ring factory. */ public SolvableLocal(SolvableLocalRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a SolvableLocal object from a ring factory and a * numerator polynomial. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator polynomial. */ public SolvableLocal(SolvableLocalRing r, GenSolvablePolynomial n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a SolvableLocal object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. */ public SolvableLocal(SolvableLocalRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { this(r, n, d, false); } /** * The constructor creates a SolvableLocal object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. * @param isred true if gcd(n,d) == 1, else false. */ protected SolvableLocal(SolvableLocalRing r, GenSolvablePolynomial n, GenSolvablePolynomial d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = (GenSolvablePolynomial) n.negate(); d = (GenSolvablePolynomial) d.negate(); } if (isred) { num = n; den = d; return; } if (debug) { System.out.println("n = " + n + ", d = " + d); } GenSolvablePolynomial p = ring.ideal.normalform(d); if (p == null || p.isZERO()) { throw new IllegalArgumentException("denominator may not be in ideal, d = " + d); } //d = p; can't do this C lc = d.leadingBaseCoefficient(); if (!lc.isONE() && lc.isUnit()) { lc = lc.inverse(); n = n.multiplyLeft(lc); d = d.multiplyLeft(lc); } if (n.compareTo(d) == 0) { num = ring.ring.getONE(); den = ring.ring.getONE(); return; } if (n.negate().compareTo(d) == 0) { num = (GenSolvablePolynomial) ring.ring.getONE().negate(); den = ring.ring.getONE(); return; } if (n.isZERO()) { num = n; den = ring.ring.getONE(); return; } if (n.isONE()) { num = n; den = d; return; } // must reduce to lowest terms // not perfect, TODO improve //GenSolvablePolynomial[] gcd = PolyModUtil. syzGcdCofactors(r.ring, n, d); GenSolvablePolynomial[] gcd = ring.fdengine.leftGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } gcd = ring.fdengine.rightGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } // not perfect, TODO improve GenSolvablePolynomial[] simp = ring.engine.leftSimplifier(n, d); logger.info("simp: {}, {}, {}", Arrays.toString(simp), n, d); num = simp[0]; den = simp[1]; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public SolvableLocalRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public GenSolvablePolynomial numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public GenSolvablePolynomial denominator() { return den; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public SolvableLocal copy() { return new SolvableLocal(ring, num, den, true); } /** * Is SolvableLocal zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is SolvableLocal one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.compareTo(den) == 0; } /** * Is SolvableLocal unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known if (num.isZERO()) { isunit = 0; return false; } GenSolvablePolynomial p = ring.ideal.normalform(num); boolean u = (p != null && !p.isZERO()); if (u) { isunit = 1; } else { isunit = 0; } return u; } /** * Is Qoutient a constant. * @return true, if this has constant numerator and denominator, else false. */ public boolean isConstant() { return num.isConstant() && den.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(ring.ring.getVars()); if (den.isONE()) { return s + " }"; } return s + "| " + den.toString(ring.ring.getVars()) + " }"; } return "SolvableLocal[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case if (den.isONE()) { return num.toScript(); } return num.toScript() + " / " + den.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * SolvableLocal comparison. * @param b SolvableLocal. * @return sign(this-b). */ @Override public int compareTo(SolvableLocal b) { if (b == null || b.isZERO()) { return this.signum(); } if (this.isZERO()) { return -b.signum(); } // assume sign(den,b.den) > 0 int s1 = num.signum(); int s2 = b.num.signum(); int t = (s1 - s2) / 2; if (t != 0) { System.out.println("compareTo: t = " + t); return t; } if (den.compareTo(b.den) == 0) { return num.compareTo(b.num); } GenSolvablePolynomial r, s; // if (den.isONE()) { } // if (b.den.isONE()) { } GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den, b.den); if (debug) { System.out.println("oc[0] den =<>= oc[1] b.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" + b.den + ")"); } //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); r = oc[0].multiply(num); s = oc[1].multiply(b.num); return r.compareTo(s); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (!(b instanceof SolvableLocal)) { return false; } SolvableLocal a = null; try { a = (SolvableLocal) b; } catch (ClassCastException e) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * SolvableLocal absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public SolvableLocal abs() { return new SolvableLocal(ring, (GenSolvablePolynomial) num.abs(), den, true); } /** * SolvableLocal summation. * @param S SolvableLocal. * @return this+S. */ public SolvableLocal sum(SolvableLocal S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } GenSolvablePolynomial n, d, n1, n2; if (den.isONE() && S.den.isONE()) { n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableLocal(ring, n, den, true); } /* wrong: if (den.isONE()) { } if (S.den.isONE()) { } */ if (den.compareTo(S.den) == 0) { // correct ? n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableLocal(ring, n, den, false); } // general case GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den, S.den); if (debug) { System.out.println("oc[0] den =sum= oc[1] S.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" + S.den + ")"); } //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); d = oc[0].multiply(den); n1 = oc[0].multiply(num); n2 = oc[1].multiply(S.num); n = (GenSolvablePolynomial) n1.sum(n2); //System.out.println("n = " + n); //System.out.println("d = " + d); return new SolvableLocal(ring, n, d, false); } /** * SolvableLocal negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public SolvableLocal negate() { return new SolvableLocal(ring, (GenSolvablePolynomial) num.negate(), den, true); } /** * SolvableLocal signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return num.signum(); } /** * SolvableLocal subtraction. * @param S SolvableLocal. * @return this-S. */ public SolvableLocal subtract(SolvableLocal S) { return sum(S.negate()); } /** * SolvableLocal division. * @param S SolvableLocal. * @return this/S. */ public SolvableLocal divide(SolvableLocal S) { return multiply(S.inverse()); } /** * SolvableLocal inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public SolvableLocal inverse() { if (isONE()) { return this; } if (isUnit()) { return new SolvableLocal(ring, den, num, true); } throw new ArithmeticException("element not invertible " + this); } /** * SolvableLocal remainder. * @param S SolvableLocal. * @return this - (this/S)*S. */ public SolvableLocal remainder(SolvableLocal S) { if (S.isUnit()) { return ring.getZERO(); } throw new UnsupportedOperationException("remainder not implemented" + S); } /** * SolvableLocal multiplication. * @param S SolvableLocal. * @return this*S. */ public SolvableLocal multiply(SolvableLocal S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } GenSolvablePolynomial n, d; if (den.isONE() && S.den.isONE()) { n = num.multiply(S.num); return new SolvableLocal(ring, n, den, true); } /* wrong: if (den.isONE()) { } if (S.den.isONE()) { } if ( den.compareTo(S.den) == 0 ) { } */ GenSolvablePolynomial[] oc = ring.engine.leftOreCond(num, S.den); if (debug) { System.out.println("oc[0] num =mult= oc[1] S.den: (" + oc[0] + ") (" + num + ") = (" + oc[1] + ") (" + S.den + ")"); } //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); n = oc[1].multiply(S.num); d = oc[0].multiply(den); return new SolvableLocal(ring, n, d, false); } /** * SolvableLocal multiplication by GenSolvablePolynomial. * @param b GenSolvablePolynomial. * @return this*b. */ public SolvableLocal multiply(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } SolvableLocal B = new SolvableLocal(ring, b); return multiply(B); } /** * SolvableLocal multiplication by coefficient. * @param b coefficient. * @return this*b. */ public SolvableLocal multiply(C b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenSolvablePolynomial B = ring.ring.getONE().multiply(b); return multiply(B); } /** * SolvableLocal multiplication by exponent. * @param e exponent vector. * @return this*b. */ public SolvableLocal multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } if (num.isZERO()) { return this; } GenSolvablePolynomial B = ring.ring.getONE().multiply(e); return multiply(B); } /** * SolvableLocal monic. * @return this with monic value part. */ public SolvableLocal monic() { if (num.isZERO()) { return this; } return this; // non sense: //C lbc = num.leadingBaseCoefficient(); //lbc = lbc.inverse(); //GenSolvablePolynomial n = num.multiply(lbc); //GenSolvablePolynomial d = den.multiply(lbc); //return new SolvableLocal(ring, n, d, true); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public SolvableLocal gcd(SolvableLocal b) { throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName()); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public SolvableLocal[] egcd(SolvableLocal b) { throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableLocalResidue.java000066400000000000000000000441711445075545500270770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.Arrays; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.fd.FDUtil; import edu.jas.gbufd.PolyModUtil; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; /** * SolvableLocalResidue, that is a (left) rational function, based on pairs of * GenSolvablePolynomial with GcdRingElem interface. Objects of this class are * immutable. * @author Heinz Kredel */ public class SolvableLocalResidue> implements GcdRingElem>, QuotPair> { // Can not extend SolvableLocal or SolvableQuotient because of // different constructor semantics. private static final Logger logger = LogManager.getLogger(SolvableLocalResidue.class); private static final boolean debug = logger.isDebugEnabled(); /** * SolvableLocalResidue class factory data structure. */ public final SolvableLocalResidueRing ring; /** * Numerator part of the element data structure. */ public final GenSolvablePolynomial num; /** * Denominator part of the element data structure. */ public final GenSolvablePolynomial den; /** * The constructor creates a SolvableLocalResidue object from a ring * factory. * @param r ring factory. */ public SolvableLocalResidue(SolvableLocalResidueRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a SolvableLocalResidue object from a ring factory * and a numerator polynomial. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator solvable polynomial. */ public SolvableLocalResidue(SolvableLocalResidueRing r, GenSolvablePolynomial n) { this(r, n, r.ring.getONE(), false); // false because of normalform } /** * The constructor creates a SolvableLocalResidue object from a ring factory * and a numerator and denominator solvable polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. */ public SolvableLocalResidue(SolvableLocalResidueRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { this(r, n, d, false); } /** * The constructor creates a SolvableLocalResidue object from a ring factory * and a numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. * @param isred unused at the moment. */ protected SolvableLocalResidue(SolvableLocalResidueRing r, GenSolvablePolynomial n, GenSolvablePolynomial d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = (GenSolvablePolynomial) n.negate(); d = (GenSolvablePolynomial) d.negate(); } if (isred) { num = n; den = d; return; } GenSolvablePolynomial p = ring.ideal.normalform(d); if (p.isZERO()) { throw new IllegalArgumentException("denominator may not be in ideal, d = " + d); } //d = p; // not always working GenSolvablePolynomial nr = ring.ideal.normalform(n); // leftNF if (nr.isZERO()) { num = nr; den = ring.ring.getONE(); return; } //logger.info("constructor: n = {}, NF(n) = {}", n, nr); //n = nr; // not always working, failed C lc = d.leadingBaseCoefficient(); if (!lc.isONE() && lc.isUnit()) { lc = lc.inverse(); n = n.multiply(lc); d = d.multiply(lc); } if (n.compareTo(d) == 0) { num = ring.ring.getONE(); den = ring.ring.getONE(); return; } if (n.negate().compareTo(d) == 0) { num = (GenSolvablePolynomial) ring.ring.getONE().negate(); den = ring.ring.getONE(); return; } if (n.isZERO()) { num = n; den = ring.ring.getONE(); return; } if (n.isONE()) { num = n; den = d; return; } // must reduce to lowest terms // not perfect, TODO improve //GenSolvablePolynomial[] gcd = PolyModUtil. syzGcdCofactors(r.ring, n, d); GenSolvablePolynomial[] gcd = ring.fdengine.leftGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } gcd = ring.fdengine.rightGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } // not perfect, TODO improve GenSolvablePolynomial[] simp = ring.engine.leftSimplifier(n, d); logger.info("simp: {}, {}, {}", Arrays.toString(simp), n, d); num = simp[0]; den = simp[1]; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public SolvableLocalResidueRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public GenSolvablePolynomial numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public GenSolvablePolynomial denominator() { return den; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public SolvableLocalResidue copy() { return new SolvableLocalResidue(ring, num, den, true); } /** * Is SolvableLocalResidue zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is SolvableLocalResidue one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.compareTo(den) == 0; } /** * Is SolvableLocalResidue a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (num.isZERO()) { return false; } return true; } /** * Is Quotient a constant. * @return true, if this has constant numerator and denominator, else false. */ public boolean isConstant() { return num.isConstant() && den.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(ring.ring.getVars()); if (!den.isONE()) { s += " | " + den.toString(ring.ring.getVars()); } return s + " }"; } return "SolvableLocalResidue[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // any scripting case if (den.isONE()) { return num.toScript(); } return num.toScript() + " / " + den.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { return factory().toScript(); } /** * SolvableLocalResidue comparison. * @param b SolvableLocalResidue. * @return sign(this-b). */ @Override public int compareTo(SolvableLocalResidue b) { if (b == null || b.isZERO()) { return this.signum(); } if (this.isZERO()) { return -b.signum(); } return this.subtract(b).signum(); // GenSolvablePolynomial n, p, q; // if ( den.compareTo(b.den) == 0 ) { // n = (GenSolvablePolynomial) num.subtract(b.num); // //\\ p = ring.ideal.normalform(n); // //logger.info("p.signum() = {}", p.signum()); // return p.signum(); // } // GenSolvablePolynomial r, s; // // if (den.isONE()) { } // // if (b.den.isONE()) { } // GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den,b.den); // if (debug) { // logger.info("oc[0] den =<>= oc[1] b.den: ({}", oc[0] + ") ({}", den + ") = ({}", oc[1] // + ") ({}", b.den + ")"); // } // q = oc[0].multiply(den); // q = ring.ideal.normalform(q); // int t = q.signum(); //oc[0].signum() * den.signum(); // sign only // r = oc[0].multiply(num); // s = oc[1].multiply(b.num); // p = (GenSolvablePolynomial) r.subtract(s); // //\\ p = ring.ideal.normalform(p); // //logger.info("p.signum() = {}", p.signum()); // if ( t == 0 ) { // throw new RuntimeException("can not happen: denominator is zero: this " + this + ", b = " + b); // } // return t * p.signum(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (!(b instanceof SolvableLocalResidue)) { return false; } SolvableLocalResidue a = null; try { a = (SolvableLocalResidue) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (num.equals(a.num) && den.equals(a.den)) { // short cut return true; } return compareTo(a) == 0; } /** * Hash code for this element. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * SolvableLocalResidue absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public SolvableLocalResidue abs() { return new SolvableLocalResidue(ring, (GenSolvablePolynomial) num.abs(), den, true); } /** * SolvableLocalResidue summation. * @param S SolvableLocalResidue. * @return this+S. */ public SolvableLocalResidue sum(SolvableLocalResidue S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } GenSolvablePolynomial n, d, n1, n2; if (den.isONE() && S.den.isONE()) { n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableLocalResidue(ring, n, den, false); // true } /* wrong: if (den.isONE()) { } if (S.den.isONE()) { } */ if (den.compareTo(S.den) == 0) { // correct ? n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableLocalResidue(ring, n, den, false); } // general case GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den, S.den); if (debug) { logger.info("oc[0] den =sum= oc[1] S.den: ({}) ({}) = ({}) ({})", oc[0], den, oc[1], S.den); } d = oc[0].multiply(den); n1 = oc[0].multiply(num); n2 = oc[1].multiply(S.num); n = (GenSolvablePolynomial) n1.sum(n2); //logger.info("n = {}, d = {}", n, d); return new SolvableLocalResidue(ring, n, d, false); } /** * SolvableLocalResidue negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public SolvableLocalResidue negate() { return new SolvableLocalResidue(ring, (GenSolvablePolynomial) num.negate(), den, true); } /** * SolvableLocalResidue signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { // assume sign(den) > 0 return num.signum(); } /** * SolvableLocalResidue subtraction. * @param S SolvableLocalResidue. * @return this-S. */ public SolvableLocalResidue subtract(SolvableLocalResidue S) { return sum(S.negate()); } /** * SolvableLocalResidue division. * @param S SolvableLocalResidue. * @return this/S. */ public SolvableLocalResidue divide(SolvableLocalResidue S) { return multiply(S.inverse()); } /** * SolvableLocalResidue inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this. */ public SolvableLocalResidue inverse() { if (num.isZERO()) { throw new ArithmeticException("element not invertible " + this); } return new SolvableLocalResidue(ring, den, num, false); // true } /** * SolvableLocalResidue remainder. * @param S SolvableLocalResidue. * @return this - (this/S)*S. */ public SolvableLocalResidue remainder(SolvableLocalResidue S) { if (S.isZERO()) { throw new ArithmeticException("element not invertible " + S); } return ring.getZERO(); } /** * SolvableLocalResidue multiplication. * @param S SolvableLocalResidue. * @return this*S. */ public SolvableLocalResidue multiply(SolvableLocalResidue S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } GenSolvablePolynomial n, d; if (den.isONE() && S.den.isONE()) { n = num.multiply(S.num); return new SolvableLocalResidue(ring, n, den, false); // true } /* wrong: if (den.isONE()) { } if (S.den.isONE()) { } if ( den.compareTo(S.den) == 0 ) { } */ GenSolvablePolynomial[] oc = ring.engine.leftOreCond(num, S.den); if (debug) { System.out.println("oc[0] num =mult= oc[1] S.den: (" + oc[0] + ") (" + num + ") = (" + oc[1] + ") (" + S.den + ")"); } n = oc[1].multiply(S.num); d = oc[0].multiply(den); return new SolvableLocalResidue(ring, n, d, false); } /** * SolvableLocalResidue multiplication by GenSolvablePolynomial. * @param b GenSolvablePolynomial. * @return this*b. */ public SolvableLocalResidue multiply(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } SolvableLocalResidue B = new SolvableLocalResidue(ring, b); return multiply(B); } /** * SolvableLocalResidue multiplication by coefficient. * @param b coefficient. * @return this*b. */ public SolvableLocalResidue multiply(C b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenSolvablePolynomial B = ring.ring.getONE().multiply(b); return multiply(B); } /** * SolvableLocalResidue multiplication by exponent. * @param e exponent vector. * @return this*b. */ public SolvableLocalResidue multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } if (num.isZERO()) { return this; } GenSolvablePolynomial B = ring.ring.getONE().multiply(e); return multiply(B); } /** * SolvableLocalResidue monic. * @return this with monic value part. */ public SolvableLocalResidue monic() { if (num.isZERO()) { return this; } return this; } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public SolvableLocalResidue gcd(SolvableLocalResidue b) { if (b == null || b.isZERO()) { return this; } if (this.isZERO()) { return b; } return ring.getONE(); } /** * Extended greatest common divisor. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ @SuppressWarnings("unchecked") public SolvableLocalResidue[] egcd(SolvableLocalResidue b) { SolvableLocalResidue[] ret = (SolvableLocalResidue[]) new SolvableLocalResidue[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (b == null || b.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = b; return ret; } GenSolvablePolynomial two = ring.ring.fromInteger(2); ret[0] = ring.getONE(); ret[1] = (this.multiply(two)).inverse(); ret[2] = (b.multiply(two)).inverse(); return ret; } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableLocalResidueRing.java000066400000000000000000000321261445075545500277140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.fd.SGCDFactory; import edu.jas.fd.GreatestCommonDivisorAbstract; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gbufd.SGBFactory; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.kern.StringUtil; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; /** * SolvableLocalResidue ring factory for SolvableLocalResidue based on * GenSolvablePolynomial with GcdRingElem interface. Objects of this class are * immutable. It represents the "classical quotient ring modulo an ideal". * @author Heinz Kredel */ public class SolvableLocalResidueRing> implements RingFactory>, QuotPairFactory, SolvableLocalResidue> { // Can not extend SolvableLocalRing or SolvableQuotientRing // because of different constructor semantics. private static final Logger logger = LogManager.getLogger(SolvableLocalResidueRing.class); private static final boolean debug = logger.isDebugEnabled(); /** * Solvable polynomial ring of the factory. */ public final GenSolvablePolynomialRing ring; /** * Solvable polynomial ideal for the reduction. */ public final SolvableIdeal ideal; /** * Syzygy engine of the factory. */ public final SolvableSyzygyAbstract engine; /** * FD engine of the factory. */ public final GreatestCommonDivisorAbstract fdengine; /** * Groebner base engine. */ protected final SolvableGroebnerBaseAbstract bb; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a SolvableLocalResidueRing object from a * SolvableIdeal. * @param i ideal in solvable polynomial ring. */ public SolvableLocalResidueRing(SolvableIdeal i) { if (i == null) { throw new IllegalArgumentException("ideal may not be null"); } ring = i.getRing(); ideal = i.GB(); // cheap if isGB if (ideal.isONE()) { throw new IllegalArgumentException("ideal may not be 1"); } if (ideal.isMaximal()) { isField = 1; //} else if (ideal.isPrime()) { // isField = 1; } else { //isField = 0; logger.warn("ideal not maximal and not known to be prime"); //throw new IllegalArgumentException("ideal must be prime or maximal"); } engine = new SolvableSyzygySeq(ring.coFac); //fdengine = SGCDFactory. getImplementation(ring.coFac); fdengine = SGCDFactory. getFakeImplementation(ring.coFac); bb = SGBFactory.getImplementation(ring.coFac); //new SolvableGroebnerBaseSeq(); logger.debug("solvable local residue ring constructed"); } /** * Factory for base elements. */ public GenSolvablePolynomialRing pairFactory() { return ring; } /** * Create from numerator. */ @SuppressWarnings("unchecked") public SolvableLocalResidue create(GenPolynomial n) { return new SolvableLocalResidue(this, (GenSolvablePolynomial) n); } /** * Create from numerator, denominator pair. */ @SuppressWarnings("unchecked") public SolvableLocalResidue create(GenPolynomial n, GenPolynomial d) { return new SolvableLocalResidue(this, (GenSolvablePolynomial) n, (GenSolvablePolynomial) d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. */ public boolean isFinite() { return ring.isFinite() && bb.commonZeroTest(ideal.getList()) <= 0; } /** * Copy SolvableLocalResidue element c. * @param c * @return a copy of c. */ public SolvableLocalResidue copy(SolvableLocalResidue c) { return new SolvableLocalResidue(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as SolvableLocalResidue. */ public SolvableLocalResidue getZERO() { return new SolvableLocalResidue(this, ring.getZERO()); } /** * Get the one element. * @return 1 as SolvableLocalResidue. */ public SolvableLocalResidue getONE() { return new SolvableLocalResidue(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. */ public List> generators() { List> pgens = PolynomialList. castToSolvableList(ring.generators()); List> gens = new ArrayList>(pgens.size() * 2 - 1); GenSolvablePolynomial one = ring.getONE(); for (GenSolvablePolynomial p : pgens) { SolvableLocalResidue q = new SolvableLocalResidue(this, p); if (!q.isZERO() && !gens.contains(q)) { gens.add(q); if (!p.isONE() && !ideal.contains(p)) { q = new SolvableLocalResidue(this, one, p); gens.add(q); } } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ @SuppressWarnings("unused") public boolean isAssociative() { if (!ring.isAssociative()) { return false; } SolvableLocalResidue Xi, Xj, Xk, p, q; List> gens = generators(); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = gens.get(k); if (Xi.num.degree() == 0 && Xj.num.degree() == 0 && Xk.num.degree() == 0 && Xi.den.degree() == 0 && Xj.den.degree() == 0 && Xk.den.degree() == 0) { //System.out.println("lr degree == 0"); continue; // skip all base elements } try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); } catch (IllegalArgumentException e) { e.printStackTrace(); continue; // ignore undefined multiplication } if (p.num.equals(q.num) && p.den.equals(q.den)) { // short cut continue; } if (!p.equals(q)) { //System.out.println("lr assoc: p = " + p.toScript()); //System.out.println("lr assoc: q = " + q.toScript()); //System.out.println("lr assoc: Xk = " + Xk.toScript() + ", Xj = " + Xj.toScript() + ", Xi = " + Xi.toScript()); logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); return false; } } } } return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } // not reached return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a SolvableLocalResidue element from a BigInteger value. * @param a BigInteger. * @return a SolvableLocalResidue. */ public SolvableLocalResidue fromInteger(java.math.BigInteger a) { return new SolvableLocalResidue(this, ring.fromInteger(a)); } /** * Get a SolvableLocalResidue element from a long value. * @param a long. * @return a SolvableLocalResidue. */ public SolvableLocalResidue fromInteger(long a) { return new SolvableLocalResidue(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. */ @Override public String toString() { return "SolvableLocalResidueRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. */ @Override public String toScript() { // Python case return "SLR(" + ideal.list.toScript() + ")"; } /** * Comparison with any other object. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof SolvableLocalResidueRing)) { return false; } SolvableLocalResidueRing a = null; try { a = (SolvableLocalResidueRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } return ring.equals(a.ring); } /** * Hash code for this quotient ring. */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * SolvableLocalResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random quotient element. */ public SolvableLocalResidue random(int n) { GenSolvablePolynomial r = ring.random(n).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(n).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocalResidue(this, r, s, false); } /** * Generate a random quotient. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random quotient. */ public SolvableLocalResidue random(int k, int l, int d, float q) { GenSolvablePolynomial r = ring.random(k, l, d, q).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(k, l, d, q).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocalResidue(this, r, s, false); } /** * SolvableLocalResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random quotient element. */ public SolvableLocalResidue random(int n, Random rnd) { GenSolvablePolynomial r = ring.random(n, rnd).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(n, rnd).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocalResidue(this, r, s, false); } /** * Parse SolvableLocalResidue from String. Syntax: * "{ polynomial | polynomial }" or "{ polynomial }" or * " polynomial | polynomial " or " polynomial " * @param s String. * @return SolvableLocalResidue from s. */ public SolvableLocalResidue parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { GenSolvablePolynomial n = ring.parse(s); return new SolvableLocalResidue(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); GenSolvablePolynomial n = ring.parse(s1); GenSolvablePolynomial d = ring.parse(s2); return new SolvableLocalResidue(this, n, d); } /** * Parse SolvableLocalResidue from Reader. * @param r Reader. * @return next SolvableLocalResidue from r. */ public SolvableLocalResidue parse(Reader r) { String s = StringUtil.nextPairedString(r, '{', '}'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableLocalRing.java000066400000000000000000000271431445075545500263760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gbufd.SGBFactory; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.kern.StringUtil; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; import edu.jas.fd.GreatestCommonDivisorAbstract; import edu.jas.fd.SGCDFactory; /** * SolvableLocal ring factory for SolvableLocal with GcdRingElem interface. * Objects of this class are immutable. * @author Heinz Kredel */ public class SolvableLocalRing> implements RingFactory>, QuotPairFactory, SolvableLocal> { // Can not extend SolvableQuotientRing // because of different constructor semantics. private static final Logger logger = LogManager.getLogger(SolvableLocalRing.class); private static final boolean debug = logger.isDebugEnabled(); /** * Solvable polynomial ideal for localization. */ public final SolvableIdeal ideal; /** * Solvable polynomial ring of the factory. */ public final GenSolvablePolynomialRing ring; /** * Syzygy engine of the factory. */ public final SolvableSyzygyAbstract engine; /** * FD engine of the factory. */ public final GreatestCommonDivisorAbstract fdengine; /** * Groebner base engine. */ protected final SolvableGroebnerBaseAbstract bb; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a SolvableLocalRing object from a SolvableIdeal. * @param i solvable localization polynomial ideal. */ public SolvableLocalRing(SolvableIdeal i) { if (i == null) { throw new IllegalArgumentException("ideal may not be null"); } ring = i.getRing(); ideal = i.GB(); // cheap if isGB if (ideal.isONE()) { throw new IllegalArgumentException("ideal may not be 1"); } if (ideal.isMaximal()) { isField = 1; } else { isField = 0; logger.warn("ideal not maximal"); //throw new IllegalArgumentException("ideal must be maximal"); } engine = new SolvableSyzygySeq(ring.coFac); //fdengine = SGCDFactory. getImplementation(ring.coFac); fdengine = SGCDFactory. getFakeImplementation(ring.coFac); bb = SGBFactory.getImplementation(ring.coFac); // new SolvableGroebnerBaseSeq(); logger.debug("solvable local ring constructed"); } /** * Factory for base elements. */ public GenSolvablePolynomialRing pairFactory() { return ring; } /** * Create from numerator. */ @SuppressWarnings("unchecked") public SolvableLocal create(GenPolynomial n) { return new SolvableLocal(this, (GenSolvablePolynomial) n); } /** * Create from numerator, denominator pair. */ @SuppressWarnings("unchecked") public SolvableLocal create(GenPolynomial n, GenPolynomial d) { return new SolvableLocal(this, (GenSolvablePolynomial) n, (GenSolvablePolynomial) d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. */ public boolean isFinite() { return ring.isFinite() && bb.commonZeroTest(ideal.getList()) <= 0; } /** * Copy SolvableLocal element c. * @param c element to copy * @return a copy of c. */ public SolvableLocal copy(SolvableLocal c) { return new SolvableLocal(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as SolvableLocal. */ public SolvableLocal getZERO() { return new SolvableLocal(this, ring.getZERO()); } /** * Get the one element. * @return 1 as SolvableLocal. */ public SolvableLocal getONE() { return new SolvableLocal(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. */ public List> generators() { List> pgens = PolynomialList. castToSolvableList(ring.generators()); List> gens = new ArrayList>(pgens.size() * 2 - 1); GenSolvablePolynomial one = ring.getONE(); for (GenSolvablePolynomial p : pgens) { SolvableLocal q = new SolvableLocal(this, p); gens.add(q); if (!p.isONE() && !ideal.contains(p)) { // q.isUnit() q = new SolvableLocal(this, one, p); gens.add(q); } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ @SuppressWarnings("unused") public boolean isAssociative() { if (!ring.isAssociative()) { return false; } SolvableLocal Xi, Xj, Xk, p, q; List> gens = generators(); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = gens.get(k); try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); } catch (IllegalArgumentException e) { //e.printStackTrace(); continue; // ignore undefined multiplication } if (!p.equals(q)) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); return false; } } } } return true; } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } // not reached return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a SolvableLocal element from a BigInteger value. * @param a BigInteger. * @return a SolvableLocal. */ public SolvableLocal fromInteger(java.math.BigInteger a) { return new SolvableLocal(this, ring.fromInteger(a)); } /** * Get a SolvableLocal element from a long value. * @param a long. * @return a SolvableLocal. */ public SolvableLocal fromInteger(long a) { return new SolvableLocal(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. */ @Override public String toString() { return "SolvableLocalRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. */ @Override public String toScript() { // Python case return "SLC(" + ideal.list.toScript() + ")"; } /** * Comparison with any other object. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof SolvableLocalRing)) { return false; } SolvableLocalRing a = null; try { a = (SolvableLocalRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this local ring. */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * SolvableLocal random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public SolvableLocal random(int n) { GenSolvablePolynomial r = ring.random(n).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(n).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocal(this, r, s, false); } /** * Generate a random residum polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random residue polynomial. */ public SolvableLocal random(int k, int l, int d, float q) { GenSolvablePolynomial r = ring.random(k, l, d, q).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(k, l, d, q).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocal(this, r, s, false); } /** * SolvableLocal random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public SolvableLocal random(int n, Random rnd) { GenSolvablePolynomial r = ring.random(n, rnd).monic(); r = ideal.normalform(r); GenSolvablePolynomial s; do { s = ring.random(n).monic(); s = ideal.normalform(s); } while (s.isZERO()); return new SolvableLocal(this, r, s, false); } /** * Parse SolvableLocal from String. * @param s String. * @return SolvableLocal from s. */ public SolvableLocal parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { GenSolvablePolynomial n = ring.parse(s); return new SolvableLocal(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); GenSolvablePolynomial n = ring.parse(s1); GenSolvablePolynomial d = ring.parse(s2); return new SolvableLocal(this, n, d); } /** * Parse SolvableLocal from Reader. * @param r Reader. * @return next SolvableLocal from r. */ public SolvableLocal parse(Reader r) { String s = StringUtil.nextPairedString(r, '{', '}'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableResidue.java000066400000000000000000000325331445075545500261230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.QuotPair; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.Value; import edu.jas.structure.ValueFactory; /** * SolvableResidue ring element based on GenSolvablePolynomial with GcdRingElem * interface. Objects of this class are immutable. * @author Heinz Kredel */ public class SolvableResidue> implements GcdRingElem>, QuotPair>, Value> { /** * SolvableResidue class factory data structure. */ public final SolvableResidueRing ring; /** * Value part of the element data structure. */ public final GenSolvablePolynomial val; /** * Flag to remember if this residue element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a SolvableResidue object from a ring factory. * @param r solvable residue ring factory. */ public SolvableResidue(SolvableResidueRing r) { this(r, r.ring.getZERO(), 0); } /** * The constructor creates a SolvableResidue object from a ring factory and * a polynomial. * @param r solvable residue ring factory. * @param a solvable polynomial. */ public SolvableResidue(SolvableResidueRing r, GenSolvablePolynomial a) { this(r, a, -1); } /** * The constructor creates a SolvableResidue object from a ring factory, a * polynomial and an indicator if a is a unit. * @param r solvable residue ring factory. * @param a solvable polynomial. * @param u isunit indicator, -1, 0, 1. */ public SolvableResidue(SolvableResidueRing r, GenSolvablePolynomial a, int u) { ring = r; val = ring.ideal.normalform(a); //.monic() no go if (u == 0 || u == 1) { isunit = u; return; } if (val.isZERO()) { isunit = 0; return; } if (ring.isField()) { isunit = 1; return; } if (val.isUnit()) { isunit = 1; //} else { // not possible //isunit = 0; } isunit = -1; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public SolvableResidueRing factory() { return ring; } /** * Value. Returns the value. * @see edu.jas.structure.Value#value() */ public GenSolvablePolynomial value() { return val; } /** * Numerator. Returns the value. * @see edu.jas.structure.QuotPair#numerator() */ public GenSolvablePolynomial numerator() { return val; } /** * Denominator. Returns 1. * @see edu.jas.structure.QuotPair#denominator() */ public GenSolvablePolynomial denominator() { return ring.ring.getONE(); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public SolvableResidue copy() { return new SolvableResidue(ring, val, isunit); } /** * Is SolvableResidue zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.isZERO(); } /** * Is SolvableResidue one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.isONE(); } /** * Is SolvableResidue unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known boolean u = ring.ideal.isUnit(val); if (u) { isunit = 1; // seems to be wrong for solvable polynomial rings } else { isunit = 0; } return isunit > 0; } /** * Is SolvableResidue a constant. * @return true if this.val is a constant polynomial, else false. */ public boolean isConstant() { return val.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return val.toString(ring.ring.getVars()); } return "SolvableResidue[ " + val.toString() + " mod " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return val.toScript(); // return "PolySolvableResidue( " + val.toScript() // + ", " + ring.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * SolvableResidue comparison. * @param b SolvableResidue. * @return sign(this-b), 0 means that this and b are equivalent in this * residue class ring. */ @Override public int compareTo(SolvableResidue b) { GenSolvablePolynomial v = b.val; if (!ring.equals(b.ring)) { v = ring.ideal.normalform(v); } return val.compareTo(v); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) * @return true means that this and b are equivalent in this residue class * ring. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof SolvableResidue)) { return false; } SolvableResidue a = null; try { a = (SolvableResidue) b; } catch (ClassCastException e) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this residue. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + val.hashCode(); return h; } /** * SolvableResidue absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public SolvableResidue abs() { return new SolvableResidue(ring, (GenSolvablePolynomial) val.abs(), isunit); } /** * SolvableResidue summation. * @param S SolvableResidue. * @return this+S. */ public SolvableResidue sum(SolvableResidue S) { return new SolvableResidue(ring, (GenSolvablePolynomial) val.sum(S.val)); } /** * SolvableResidue negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public SolvableResidue negate() { return new SolvableResidue(ring, (GenSolvablePolynomial) val.negate(), isunit); } /** * SolvableResidue signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * SolvableResidue subtraction. * @param S SolvableResidue. * @return this-S. */ public SolvableResidue subtract(SolvableResidue S) { return new SolvableResidue(ring, (GenSolvablePolynomial) val.subtract(S.val)); } /** * SolvableResidue division. * @param S SolvableResidue. * @return this/S. */ public SolvableResidue divide(SolvableResidue S) { if (ring.isField()) { return multiply(S.inverse()); } try { return multiply(S.inverse()); } catch (NotInvertibleException ignored) { System.out.println("catch: " + ignored); //ignored.printStackTrace(); // ignored } List> Q = new ArrayList>(1); Q.add(ring.ring.getZERO()); List> V = new ArrayList>(1); V.add(S.val); GenSolvablePolynomial x = ring.bb.sred.leftNormalform(Q, V, val); GenSolvablePolynomial y = Q.get(0); System.out.println("SolvableResidue val = " + val + ", div = " + S.val + ", quotient = " + y + ", remainder = " + x); return new SolvableResidue(ring, y); } /** * SolvableResidue inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public SolvableResidue inverse() { GenSolvablePolynomial x = ring.ideal.inverse(val); SolvableResidue xp = new SolvableResidue(ring, x, 1); if (xp.isZERO()) { throw new NotInvertibleException("(" + x + ") * (" + val + ") = " + x.multiply(val) + " = 0 mod " + ring.ideal); } if (!xp.multiply(this).isONE()) { throw new NotInvertibleException("(" + x + ") * (" + val + ") = " + x.multiply(val) + " != 1 mod " + ring.ideal); } return xp; } /** * SolvableResidue remainder. * @param S SolvableResidue. * @return this - (this/S)*S. */ public SolvableResidue remainder(SolvableResidue S) { List> V = new ArrayList>(1); V.add(S.val); GenSolvablePolynomial x = ring.bb.sred.leftNormalform(V, val); return new SolvableResidue(ring, x); } /** * SolvableResidue multiplication. * @param S SolvableResidue. * @return this*S. */ public SolvableResidue multiply(SolvableResidue S) { GenSolvablePolynomial x = val.multiply(S.val); int i = -1; if (isunit == 1 && S.isunit == 1) { i = 1; } else if (isunit == 0 || S.isunit == 0) { i = 0; } return new SolvableResidue(ring, x, i); } /** * SolvableResidue multiplication. * @param S GenSolvablePolynomial. * @return this*S. */ public SolvableResidue multiply(GenSolvablePolynomial S) { GenSolvablePolynomial x = val.multiply(S); int i = -1; if (isunit == 1 && S.isUnit()) { i = 1; } else if (isunit == 0 || !S.isUnit()) { i = 0; } return new SolvableResidue(ring, x, i); } /* * SolvableResidue multiplication. * @param s coefficient. * @return this*s. */ public SolvableResidue multiply(C s) { GenSolvablePolynomial x = val.multiply(s); int i = -1; if (isunit == 1 && s.isUnit()) { i = 1; } else if (isunit == 0 || !s.isUnit()) { i = 0; } return new SolvableResidue(ring, x, i); } /** * SolvableResidue multiplication. * @param e exponent. * @return this*Xe. */ public SolvableResidue multiply(ExpVector e) { GenSolvablePolynomial x = val.multiply(e); int i = -1; if (isunit == 1 && e.isZERO()) { i = 1; } else if (isunit == 0 || !e.isZERO()) { i = 0; } return new SolvableResidue(ring, x, i); } /** * SolvableResidue monic. * @return this with monic value part. */ public SolvableResidue monic() { return new SolvableResidue(ring, val.monic(), isunit); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public SolvableResidue gcd(SolvableResidue b) { throw new UnsupportedOperationException("gcd not implemented"); // GenSolvablePolynomial x = ring.engine.gcd(val, b.val); // int i = -1; // gcd might become a unit // if (x.isONE()) { // i = 1; // } else { // System.out.println("SolvableResidue gcd = " + x); // } // if (isunit == 1 && b.isunit == 1) { // i = 1; // } // return new SolvableResidue(ring, x, i); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public SolvableResidue[] egcd(SolvableResidue b) { throw new UnsupportedOperationException("egcd not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/application/SolvableResidueRing.java000066400000000000000000000264471445075545500267520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.QuotPair; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.Value; import edu.jas.structure.ValueFactory; /** * SolvableResidue ring factory based on GenSolvablePolynomialRing with * GcdRingFactory interface. Objects of this class are immutable. * @author Heinz Kredel */ public class SolvableResidueRing> implements RingFactory>, QuotPairFactory, SolvableResidue>, ValueFactory, SolvableResidue> { private static final Logger logger = LogManager.getLogger(SolvableResidueRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Groebner base engine. */ protected final SolvableGroebnerBaseAbstract bb; /** * Solvable polynomial ideal for the reduction. */ public final SolvableIdeal ideal; /** * Polynomial ring of the factory. Shortcut to ideal.list.ring. */ public final GenSolvablePolynomialRing ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a SolvableResidueRing object from an Ideal. * @param i polynomial ideal. */ public SolvableResidueRing(SolvableIdeal i) { this(i, false); } /** * The constructor creates a SolvableResidueRing object from an * SolvableIdeal. * @param i solvable polynomial ideal. * @param isMaximal true, if ideal is maxmal. */ public SolvableResidueRing(SolvableIdeal i, boolean isMaximal) { ideal = i.GB(); // cheap if isGB ring = ideal.getRing(); bb = new SolvableGroebnerBaseSeq(); if (isMaximal) { isField = 1; return; } if (ideal.isONE()) { logger.warn("ideal is one, so all residues are 0"); } //System.out.println("rr ring = " + ring.getClass().getName()); //System.out.println("rr cofac = " + ring.coFac.getClass().getName()); } /** * Factory for base elements. */ public GenSolvablePolynomialRing pairFactory() { return ring; } /** * Factory for base elements. */ public GenSolvablePolynomialRing valueFactory() { return ring; } /** * Create from numerator. */ @SuppressWarnings("unchecked") public SolvableResidue create(GenPolynomial n) { return new SolvableResidue(this, (GenSolvablePolynomial) n); } /** * Create from numerator, denominator pair. */ @SuppressWarnings("unchecked") public SolvableResidue create(GenPolynomial n, GenPolynomial d) { if (d != null && !d.isONE()) { throw new UnsupportedOperationException("d must be 1, but d = " + d); } return new SolvableResidue(this, (GenSolvablePolynomial) n); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ideal.commonZeroTest() <= 0 && ring.coFac.isFinite(); } /** * Copy SolvableResidue element c. * @param c * @return a copy of c. */ public SolvableResidue copy(SolvableResidue c) { //System.out.println("rr copy in = " + c.val); if (c == null) { // where does this happen? return getZERO(); // or null? } SolvableResidue r = new SolvableResidue(this, c.val); //System.out.println("rr copy out = " + r.val); //System.out.println("rr copy ideal = " + ideal.list.list); return r; //new SolvableResidue( c.ring, c.val ); } /** * Get the zero element. * @return 0 as SolvableResidue. */ public SolvableResidue getZERO() { return new SolvableResidue(this, ring.getZERO()); } /** * Get the one element. * @return 1 as SolvableResidue. */ public SolvableResidue getONE() { SolvableResidue one = new SolvableResidue(this, ring.getONE()); if (one.isZERO()) { logger.warn("ideal is one, so all residues are 0"); } return one; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> pgens = ring.generators(); List> gens = new ArrayList>(pgens.size()); SortedSet> sgens = new TreeSet>(); List> rgens = new ArrayList>(pgens.size()); SolvableIdeal gi = new SolvableIdeal(ring, rgens); SolvableResidueRing gr = new SolvableResidueRing(gi); for (GenPolynomial p : pgens) { GenSolvablePolynomial s = (GenSolvablePolynomial) p; SolvableResidue r = new SolvableResidue(this, s); if (r.isZERO()) { continue; } if (!r.isONE() && r.val.isConstant()) { continue; } // avoid duplicate generators SolvableResidue x = new SolvableResidue(gr, r.val); if (x.isZERO()) { continue; } if (!x.isONE() && x.val.isConstant()) { continue; } r = new SolvableResidue(this, x.val); if (r.isZERO()) { continue; } r = r.monic(); if (!r.isONE() && !r.val.isConstant()) { rgens.add(r.val); //System.out.println("rgens = " + rgens); gi = new SolvableIdeal(ring, rgens); gr = new SolvableResidueRing(gi); } //gens.add(r); sgens.add(r); } gens.addAll(sgens); return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); // check also vector space structure } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); // sufficient ?? } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (ideal.isMaximal()) { isField = 1; return true; } return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a SolvableResidue element from a BigInteger value. * @param a BigInteger. * @return a SolvableResidue. */ public SolvableResidue fromInteger(java.math.BigInteger a) { return new SolvableResidue(this, ring.fromInteger(a)); } /** * Get a SolvableResidue element from a long value. * @param a long. * @return a SolvableResidue. */ public SolvableResidue fromInteger(long a) { return new SolvableResidue(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "SolvableResidueRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "SRC(" + ideal.list.toScript() + ")"; //return "SRC(" + ideal.toScript() + "," + ring.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof SolvableResidueRing)) { return false; } SolvableResidueRing a = null; try { a = (SolvableResidueRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this residue ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * SolvableResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public SolvableResidue random(int n) { GenSolvablePolynomial x = ring.random(n).monic(); return new SolvableResidue(this, x); } /** * Generate a random residum polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random residue polynomial. */ public SolvableResidue random(int k, int l, int d, float q) { GenSolvablePolynomial x = ring.random(k, l, d, q).monic(); return new SolvableResidue(this, x); } /** * SolvableResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public SolvableResidue random(int n, Random rnd) { GenSolvablePolynomial x = ring.random(n, rnd).monic(); return new SolvableResidue(this, x); } /** * Parse SolvableResidue from String. * @param s String. * @return SolvableResidue from s. */ public SolvableResidue parse(String s) { GenSolvablePolynomial x = ring.parse(s); return new SolvableResidue(this, x); } /** * Parse SolvableResidue from Reader. * @param r Reader. * @return next SolvableResidue from r. */ public SolvableResidue parse(Reader r) { GenSolvablePolynomial x = ring.parse(r); return new SolvableResidue(this, x); } } java-algebra-system-2.7.200/src/edu/jas/application/WordIdeal.java000066400000000000000000000705521445075545500247100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordGroebnerBaseSeq; import edu.jas.gb.WordReduction; import edu.jas.gb.WordReductionSeq; import edu.jas.gbufd.PolyGBUtil; import edu.jas.kern.Scripting; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.Word; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Word Ideal implements some methods for ideal arithmetic, for example * containment, sum or product. Note: only two-sided ideals. * @author Heinz Kredel */ public class WordIdeal> implements Comparable>, Serializable { private static final Logger logger = LogManager.getLogger(WordIdeal.class); private static final boolean debug = logger.isDebugEnabled(); /** * The data structure is a list of word polynomials. */ protected List> list; /** * Reference to the word polynomial ring. */ protected GenWordPolynomialRing ring; /** * Indicator if list is a Groebner Base. */ protected boolean isGB; /** * Indicator if test has been performed if this is a Groebner Base. */ protected boolean testGB; /** * Groebner base engine. */ protected final WordGroebnerBaseAbstract bb; /** * Reduction engine. */ protected final WordReduction red; /** * Constructor. * @param ring word polynomial ring */ public WordIdeal(GenWordPolynomialRing ring) { this(ring, new ArrayList>()); } /** * Constructor. * @param ring word polynomial ring * @param list word polynomial list */ public WordIdeal(GenWordPolynomialRing ring, List> list) { this(ring, list, false); } /** * Constructor. * @param ring word polynomial ring * @param list word polynomial list * @param bb Groebner Base engine * @param red Reduction engine */ public WordIdeal(GenWordPolynomialRing ring, List> list, WordGroebnerBaseAbstract bb, WordReduction red) { this(ring, list, false, bb, red); } /** * Constructor. * @param ring word polynomial ring * @param list word polynomial list * @param gb true if list is known to be a Groebner Base, else false */ public WordIdeal(GenWordPolynomialRing ring, List> list, boolean gb) { this(ring, list, gb, new WordGroebnerBaseSeq(), new WordReductionSeq()); //this(list, gb, topt, GBFactory.getImplementation(list.ring.coFac)); } /** * Constructor. * @param ring word polynomial ring * @param list word polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine */ public WordIdeal(GenWordPolynomialRing ring, List> list, boolean gb, WordGroebnerBaseAbstract bb) { this(ring, list, gb, bb, bb.red); } /** * Constructor. * @param ring word polynomial ring * @param list word polynomial list * @param gb true if list is known to be a Groebner Base, else false * @param bb Groebner Base engine * @param red Reduction engine */ public WordIdeal(GenWordPolynomialRing ring, List> list, boolean gb, WordGroebnerBaseAbstract bb, WordReduction red) { if (ring == null) { throw new IllegalArgumentException("ring may not be null"); } if (list == null) { throw new IllegalArgumentException("list may not be null"); } this.ring = ring; this.list = list; this.isGB = gb; this.testGB = (gb ? true : false); // ?? this.bb = bb; this.red = red; if (debug) { logger.info("constructed: {}", this); } } /** * Clone this. * @return a copy of this. */ public WordIdeal copy() { return new WordIdeal(ring, new ArrayList>(list), isGB, bb, red); } /** * Get the List of GenWordPolynomials. * @return (cast) list.list */ public List> getList() { return list; } /** * Get the GenWordPolynomialRing. * @return (cast) list.ring */ public GenWordPolynomialRing getRing() { return ring; } /** * Get the zero ideal. * @return ideal(0) */ public WordIdeal getZERO() { List> z = new ArrayList>(0); return new WordIdeal(ring, z, true, bb, red); } /** * Get the one ideal. * @return ideal(1) */ public WordIdeal getONE() { List> one = new ArrayList>(1); one.add(getRing().getONE()); return new WordIdeal(ring, one, true, bb, red); } /** * String representation of the word ideal. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer("("); boolean first = true; for (GenWordPolynomial p : list) { if (!first) { sb.append(","); } else { first = false; } sb.append(p.toString()); } sb.append(")"); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("WordPolyIdeal.new("); break; case Python: default: s.append("WordIdeal("); } if (ring != null) { s.append(ring.toScript()); } if (list == null) { s.append(")"); return s.toString(); } switch (Scripting.getLang()) { case Ruby: s.append(",\"\",["); break; case Python: default: s.append(",list=["); } boolean first = true; String sa = null; for (GenWordPolynomial oa : list) { sa = oa.toScript(); if (first) { first = false; } else { s.append(", "); } //s.append("( " + sa + " )"); s.append(sa); } s.append("])"); return s.toString(); } /** * Comparison with any other object. Note: If not both ideals are * Groebner Bases, then false may be returned even the ideals are equal. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof WordIdeal)) { logger.warn("equals no Ideal"); return false; } WordIdeal B = null; try { B = (WordIdeal) b; } catch (ClassCastException ignored) { return false; } SortedSet> s = new TreeSet>(list); SortedSet> t = new TreeSet>(B.list); if (isGB && B.isGB) { //requires also monic polys return s.equals(t); } if (s.equals(t)) { return true; } //System.out.println("no GBs contains"); return this.contains(B) && B.contains(this); } /** * WordIdeal comparison. * @param L other word ideal. * @return compareTo() of polynomial lists. */ public int compareTo(WordIdeal L) { int si = Math.min(L.list.size(), list.size()); int s = 0; final Comparator wc = ring.alphabet.getAscendComparator(); Comparator> cmp = new Comparator>() { public int compare(GenWordPolynomial p1, GenWordPolynomial p2) { Word w1 = p1.leadingWord(); Word w2 = p2.leadingWord(); if (w1 == null) { return -1; // dont care } if (w2 == null) { return 1; // dont care } if (w1.length() != w2.length()) { if (w1.length() > w2.length()) { return 1; // dont care } return -1; // dont care } return wc.compare(w1, w2); } }; List> l1 = new ArrayList>(list); List> l2 = new ArrayList>(L.list); //Collections.sort(l1); //Collections.sort(l2); Collections.sort(l1, cmp); Collections.sort(l2, cmp); for (int i = 0; i < si; i++) { GenWordPolynomial a = l1.get(i); GenWordPolynomial b = l2.get(i); s = a.compareTo(b); if (s != 0) { return s; } } if (list.size() > si) { return 1; } if (L.list.size() > si) { return -1; } return s; } /** * Hash code for this word ideal. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = list.hashCode(); if (isGB) { h = h << 1; } if (testGB) { h += 1; } return h; } /** * Test if ZERO ideal. * @return true, if this is the 0 ideal, else false */ public boolean isZERO() { //return list.isZERO(); if (list == null) { // never true return true; } for (GenWordPolynomial p : list) { if (p == null) { continue; } if (!p.isZERO()) { return false; } } return true; } /** * Test if ONE is contained in the ideal. To test for a proper ideal use * ! id.isONE(). * @return true, if this is the 1 ideal, else false */ public boolean isONE() { //return list.isONE(); if (list == null) { return false; } for (GenWordPolynomial p : list) { if (p == null) { continue; } if (p.isONE()) { return true; } } return false; } /** * Test if this is a twosided Groebner base. * @return true, if this is a twosided Groebner base, else false */ public boolean isGB() { if (testGB) { return isGB; } logger.warn("isGB computing"); isGB = bb.isGB(getList()); testGB = true; return isGB; } /** * Do Groebner Base. Compute the Groebner Base for this ideal. */ @SuppressWarnings("unchecked") public void doGB() { if (isGB && testGB) { return; } List> G = getList(); logger.info("doGB computing = {}", G); list = bb.GB(G); isGB = true; testGB = true; return; } /** * Groebner Base. Get a Groebner Base for this ideal. * @return twosidedGB(this) */ public WordIdeal GB() { if (isGB) { return this; } doGB(); return this; } /** * Word ideal containment. Test if B is contained in this ideal. Note: this * is eventually modified to become a Groebner Base. * @param B word ideal * @return true, if B is contained in this, else false */ public boolean contains(WordIdeal B) { if (B == null || B.isZERO()) { return true; } return contains(B.getList()); } /** * Word ideal containment. Test if b is contained in this ideal. Note: this * is eventually modified to become a Groebner Base. * @param b word polynomial * @return true, if b is contained in this, else false */ public boolean contains(GenWordPolynomial b) { if (b == null || b.isZERO()) { return true; } if (this.isONE()) { return true; } if (this.isZERO()) { return false; } if (!isGB) { doGB(); } GenWordPolynomial z = red.normalform(getList(), b); if (z == null || z.isZERO()) { return true; } return false; } /** * Word ideal containment. Test if each b in B is contained in this ideal. * Note: this is eventually modified to become a Groebner Base. * @param B list of word polynomials * @return true, if each b in B is contained in this, else false */ public boolean contains(List> B) { if (B == null || B.size() == 0) { return true; } if (this.isONE()) { return true; } if (!isGB) { doGB(); } for (GenWordPolynomial b : B) { if (b == null) { continue; } if (!contains(b)) { System.out.println("contains nf(b) != 0: " + b); return false; } } return true; } /** * Word ideal summation. Generators for the sum of ideals. Note: if both * ideals are Groebner bases, a Groebner base is returned. * @param B word ideal * @return ideal(this+B) */ public WordIdeal sum(WordIdeal B) { if (B == null || B.isZERO()) { return this; } if (this.isZERO()) { return B; } return sum(B.getList()); // int s = getList().size() + B.getList().size(); // List> c; // c = new ArrayList>(s); // c.addAll(getList()); // c.addAll(B.getList()); // WordIdeal I = new WordIdeal(getRing(), c, false, bb); // if (isGB && B.isGB) { // I.doGB(); // } // return I; } /** * Word summation. Generators for the sum of ideal and a polynomial. Note: * if this ideal is a Groebner base, a Groebner base is returned. * @param b word polynomial * @return ideal(this+{b}) */ public WordIdeal sum(GenWordPolynomial b) { if (b == null || b.isZERO()) { return this; } int s = getList().size() + 1; List> c; c = new ArrayList>(s); c.addAll(getList()); c.add(b); WordIdeal I = new WordIdeal(getRing(), c, false, bb); if (isGB) { I.doGB(); } return I; } /** * Word summation. Generators for the sum of this ideal and a list of * polynomials. Note: if this ideal is a Groebner base, a Groebner base is * returned. * @param L list of word polynomials * @return ideal(this+L) */ public WordIdeal sum(List> L) { if (L == null || L.isEmpty()) { return this; } int s = getList().size() + L.size(); List> c = new ArrayList>(s); c.addAll(getList()); c.addAll(L); WordIdeal I = new WordIdeal(getRing(), c, false, bb); if (isGB) { I.doGB(); } return I; } /** * Product. Generators for the product of ideals. Note: if both ideals are * Groebner bases, a Groebner base is returned. * @param B word ideal * @return ideal(this*B) */ public WordIdeal product(WordIdeal B) { if (B == null || B.isZERO()) { return B; } if (this.isZERO()) { return this; } int s = getList().size() * B.getList().size(); List> c; c = new ArrayList>(s); for (GenWordPolynomial p : getList()) { for (GenWordPolynomial q : B.getList()) { q = p.multiply(q); c.add(q); } } WordIdeal I = new WordIdeal(getRing(), c, false, bb); if (isGB && B.isGB) { I.doGB(); } return I; } /** * Left product. Generators for the product this by a polynomial. * @param b word polynomial * @return ideal(this*b) */ public WordIdeal product(GenWordPolynomial b) { if (b == null || b.isZERO()) { return getZERO(); } if (this.isZERO()) { return this; } List> c; c = new ArrayList>(getList().size()); for (GenWordPolynomial p : getList()) { GenWordPolynomial q = p.multiply(b); c.add(q); } WordIdeal I = new WordIdeal(getRing(), c, false, bb); if (isGB) { I.doGB(); } return I; } /* * Intersection. Generators for the intersection of ideals. Using an * iterative algorithm. * @param Bl list of word ideals * @return ideal(cap_i B_i), a Groebner base */ public WordIdeal intersect(List> Bl) { if (Bl == null || Bl.size() == 0) { return getZERO(); } WordIdeal I = null; for (WordIdeal B : Bl) { if (I == null) { I = B; continue; } if (I.isONE()) { return I; } I = I.intersect(B); } return I; } /* * Intersection. Generators for the intersection of ideals. * @param B word ideal * @return ideal(this cap B), a Groebner base */ public WordIdeal intersect(WordIdeal B) { if (B == null || B.isZERO()) { // (0) return B; } if (this.isZERO()) { return this; } List> c = PolyGBUtil. intersect(getRing(), getList(), B.getList(), bb); WordIdeal I = new WordIdeal(getRing(), c, true, bb); return I; } /* * Intersection. Generators for the intersection of a ideal with a * word polynomial ring. The polynomial ring of this ideal must be * a contraction of R and the TermOrder must be an elimination * order. * @param R word polynomial ring * @return ideal(this cap R) */ public WordIdeal intersect(GenWordPolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } List> H = PolyUtil. intersect(R, getList()); return new WordIdeal(R, H, isGB, bb); } /* * Eliminate. Generators for the intersection of this ideal with a word * polynomial ring. The word polynomial ring of this ideal must be a * contraction of R and the TermOrder must be an elimination order. * @param R word polynomial ring * @return ideal(this cap R) */ public WordIdeal eliminate(GenWordPolynomialRing R) { if (R == null) { throw new IllegalArgumentException("R may not be null"); } if (getRing().equals(R)) { return this; } return intersect(R); } /* * Quotient. Generators for the word ideal quotient. * @param h word polynomial * @return ideal(this : h), a Groebner base public WordIdeal quotient(GenWordPolynomial h) { if (h == null) { // == (0) return this; } if (h.isZERO()) { return this; } if (this.isZERO()) { return this; } List> H; H = new ArrayList>(1); H.add(h); WordIdeal Hi = new WordIdeal(getRing(), H, true, bb); WordIdeal I = this.intersect(Hi); List> Q; Q = new ArrayList>(I.getList().size()); for (GenWordPolynomial q : I.getList()) { q = (GenWordPolynomial) q.divide(h); // remainder == 0 Q.add(q); } return new WordIdeal(getRing(), Q, true, bb); } */ /* * Quotient. Generators for the word ideal quotient. * @param H word ideal * @return ideal(this : H), a Groebner base public WordIdeal quotient(WordIdeal H) { if (H == null || H.isZERO()) { // == (0) return this; } if (this.isZERO()) { return this; } WordIdeal Q = null; for (GenWordPolynomial h : H.getList()) { WordIdeal Hi = this.quotient(h); if (Q == null) { Q = Hi; } else { Q = Q.intersect(Hi); } } return Q; } */ /** * Power. Generators for the power of this word ideal. Note: if this ideal * is a Groebner base, a Groebner base is returned. * @param d integer * @return ideal(this^d) */ public WordIdeal power(int d) { if (d <= 0) { return getONE(); } if (this.isZERO() || this.isONE()) { return this; } WordIdeal c = this; for (int i = 1; i < d; i++) { c = c.product(this); } return c; } /** * Normalform for element. * @param h word polynomial * @return left normalform of h with respect to this */ public GenWordPolynomial normalform(GenWordPolynomial h) { if (h == null) { return h; } if (h.isZERO()) { return h; } if (this.isZERO()) { return h; } GenWordPolynomial r; r = red.normalform(getList(), h); return r; } /** * Normalform for list of word elements. * @param L word polynomial list * @return list of left normalforms of the elements of L with respect to * this */ public List> normalform(List> L) { if (L == null) { return L; } if (L.size() == 0) { return L; } if (this.isZERO()) { return L; } List> M = new ArrayList>(L.size()); for (GenWordPolynomial h : L) { GenWordPolynomial r = normalform(h); if (r != null && !r.isZERO()) { M.add(r); } } return M; } /** * Inverse for element modulo this ideal. * @param h word polynomial * @return inverse of h with respect to this, if defined */ public GenWordPolynomial inverse(GenWordPolynomial h) { if (h == null || h.isZERO()) { throw new NotInvertibleException("zero not invertible"); } if (this.isZERO()) { throw new NotInvertibleException("zero ideal"); } if (h.isUnit()) { return h.inverse(); } if (isUnit(h)) { logger.warn("{} is invertable, but inverse not computed", h); } throw new UnsupportedOperationException("inverse of " + h); /* TODO compute inverse doGB(); List> F = new ArrayList>(1 + list.list.size()); F.add(h); F.addAll(getList()); //System.out.println("F = " + F); WordExtendedGB x = bb.extLeftGB(F); List> G = x.G; //System.out.println("G = " + G); GenWordPolynomial one = null; int i = -1; for (GenWordPolynomial p : G) { i++; if (p == null) { continue; } if (p.isUnit()) { one = p; break; } } if (one == null) { throw new NotInvertibleException("one == null: h = " + h); } List> row = x.G2F.get(i); // != -1 //System.out.println("row = " + row); GenWordPolynomial g = row.get(0); if (g == null || g.isZERO()) { throw new NotInvertibleException("g == 0: h = " + h); } GenWordPolynomial gp = red.leftNormalform(getList(), g); if (gp.isZERO()) { // can happen with solvable rings throw new NotInvertibleException("solv|gp == 0: h = " + h + ", g = " + g); } // adjust leading coefficient of g to get g*h == 1 GenWordPolynomial f = g.multiply(h); //System.out.println("f = " + f); GenWordPolynomial k = red.leftNormalform(getList(), f); //System.out.println("k = " + k); if (!k.isONE()) { C lbc = k.leadingBaseCoefficient(); lbc = lbc.inverse(); g = g.multiply(lbc); } return g; */ } /** * Test if element is a unit modulo this ideal. * @param h word polynomial * @return true if h is a unit with respect to this, else false */ public boolean isUnit(GenWordPolynomial h) { if (h == null || h.isZERO()) { return false; } if (this.isZERO()) { return false; } if (h.isUnit()) { return true; } // test this + (h) == 1: then ex p, q: pp*this**qq + p*h*q = 1 List> F = new ArrayList>(1 + list.size()); F.add(h); F.addAll(getList()); List> G = bb.GB(F); if (debug) { logger.info("isUnit GB = {}", G); } for (GenWordPolynomial p : G) { if (p == null) { continue; } if (p.isUnit()) { return true; } } return false; } /** * Ideal common zero test. * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest() { if (this.isZERO()) { return 1; } if (!isGB) { doGB(); } if (this.isONE()) { return -1; } return bb.commonZeroTest(getList()); } /** * Test if this ideal is maximal. * @return true, if this is certainly maximal and not one, * false, if this is one, has dimension ≥ 1 or it is not jet determined if it is maximal. */ public boolean isMaximal() { if (commonZeroTest() != 0) { return false; } for (Long d : univariateDegrees()) { if (d > 1L) { return false; } } return true; } /** * Univariate head term degrees. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees() { List ud = new ArrayList(); if (this.isZERO()) { return ud; } if (!isGB) { doGB(); } if (this.isONE()) { return ud; } return bb.univariateDegrees(getList()); } /* * Construct univariate polynomials of minimal degree in all variables in * zero dimensional ideal(G). * @return list of univariate word polynomial of minimal degree in each * variable in ideal(G) */ /* * Construct univariate polynomial of minimal degree in variable i in zero * dimensional ideal(G). * @param i variable index. * @return univariate word polynomial of minimal degree in variable i in * ideal(G) */ } java-algebra-system-2.7.200/src/edu/jas/application/WordResidue.java000066400000000000000000000404011445075545500252600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.Word; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NoncomRingElem; import edu.jas.structure.NotDivisibleException; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.QuotPair; import edu.jas.structure.Value; /** * WordResidue ring element based on GenWordPolynomial with GcdRingElem * interface. Objects of this class are immutable. * @author Heinz Kredel */ public class WordResidue> implements GcdRingElem>, NoncomRingElem>, QuotPair>, Value> { /** * WordResidue class factory data structure. */ public final WordResidueRing ring; /** * Value part of the element data structure. */ public final GenWordPolynomial val; /** * Flag to remember if this residue element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a WordResidue object from a ring factory. * @param r solvable residue ring factory. */ public WordResidue(WordResidueRing r) { this(r, r.ring.getZERO(), 0); } /** * The constructor creates a WordResidue object from a ring factory and a * polynomial. * @param r solvable residue ring factory. * @param a solvable polynomial. */ public WordResidue(WordResidueRing r, GenWordPolynomial a) { this(r, a, -1); } /** * The constructor creates a WordResidue object from a ring factory, a * polynomial and an indicator if a is a unit. * @param r solvable residue ring factory. * @param a solvable polynomial. * @param u isunit indicator, -1, 0, 1. */ public WordResidue(WordResidueRing r, GenWordPolynomial a, int u) { ring = r; val = ring.ideal.normalform(a); //.monic() no go if (u == 0 || u == 1) { isunit = u; return; } if (val.isZERO()) { isunit = 0; return; } if (ring.isField()) { isunit = 1; return; } if (val.isUnit()) { isunit = 1; //} else { // not possible //isunit = 0; } isunit = -1; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public WordResidueRing factory() { return ring; } /** * Value. Returns the value. * @see edu.jas.structure.Value#value() */ public GenWordPolynomial value() { return val; } /** * Numerator. Returns the value. * @see edu.jas.structure.QuotPair#numerator() */ public GenWordPolynomial numerator() { return val; } /** * Denominator. Returns 1. * @see edu.jas.structure.QuotPair#denominator() */ public GenWordPolynomial denominator() { return ring.ring.getONE(); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public WordResidue copy() { return new WordResidue(ring, val, isunit); } /** * Is WordResidue zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.isZERO(); } /** * Is WordResidue one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.isONE(); } /** * Is WordResidue unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known boolean u = ring.ideal.isUnit(val); //System.out.println("WordResidue.isUnit " + val); if (u) { isunit = 1; // seems to be wrong for solvable polynomial rings } else { isunit = 0; } return isunit > 0; } /** * Is WordResidue a constant. * @return true if this.val is a constant polynomial, else false. */ public boolean isConstant() { return val.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return val.toString(); } return "WordResidue[ " + val.toString() + " mod " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return val.toScript(); // return "PolyWordResidue( " + val.toScript() // + ", " + ring.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * WordResidue comparison. * @param b WordResidue. * @return sign(this-b), 0 means that this and b are equivalent in this * residue class ring. */ @Override public int compareTo(WordResidue b) { GenWordPolynomial v = b.val; if (!ring.equals(b.ring)) { v = ring.ideal.normalform(v); } return val.compareTo(v); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) * @return true means that this and b are equivalent in this residue class * ring. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof WordResidue)) { return false; } WordResidue a = null; try { a = (WordResidue) b; } catch (ClassCastException e) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this residue. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + val.hashCode(); return h; } /** * WordResidue absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public WordResidue abs() { return new WordResidue(ring, val.abs(), isunit); } /** * WordResidue summation. * @param S WordResidue. * @return this+S. */ public WordResidue sum(WordResidue S) { return new WordResidue(ring, val.sum(S.val)); } /** * WordResidue negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public WordResidue negate() { return new WordResidue(ring, val.negate(), isunit); } /** * WordResidue signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * WordResidue subtraction. * @param S WordResidue. * @return this-S. */ public WordResidue subtract(WordResidue S) { return new WordResidue(ring, val.subtract(S.val)); } /** * WordResidue left division. * @param S WordResidue. * @return left, with left*S = this */ public WordResidue divide(WordResidue S) { if (ring.isField()) { return multiply(S.inverse()); } try { return multiply(S.inverse()); } catch (NotInvertibleException ignored) { System.out.println("catch: " + ignored); //ignored.printStackTrace(); // ignored } catch (UnsupportedOperationException ignored) { //System.out.println("catch: " + ignored); //ignored.printStackTrace(); // ignored } List> L = new ArrayList>(1); L.add(ring.ring.getZERO()); List> V = new ArrayList>(1); V.add(S.val); //@SuppressWarnings("unused") GenWordPolynomial x = ring.bb.red.leftNormalform(L, V, val); GenWordPolynomial y = L.get(0); GenWordPolynomial t = y.multiply(S.val).sum(x); if (!val.equals(t)) { throw new NotDivisibleException("val != t: val = " + val + ", t = " + t); } return new WordResidue(ring, y); } /** * WordResidue two-sided division. * @param S WordResidue. * @return [left, right] with left*S*right + remainder = this. */ @SuppressWarnings("unchecked") public WordResidue[] twosidedDivide(WordResidue S) { List> L = new ArrayList>(1); L.add(ring.ring.getZERO()); List> R = new ArrayList>(1); R.add(ring.ring.getZERO()); List> V = new ArrayList>(1); V.add(S.val); GenWordPolynomial x = ring.bb.red.normalform(L, R, V, val); GenWordPolynomial y = L.get(0); GenWordPolynomial z = R.get(0); if (!ring.bb.red.isReductionNF(L, R, V, val, x)) { throw new NotDivisibleException("val != x: val = " + val + ", S.val = " + S.val); } WordResidue[] ret = new WordResidue[2]; ret[0] = new WordResidue(ring, y); ret[1] = new WordResidue(ring, z); return ret; } /** * WordResidue right division. * @param S WordResidue. * @return right, with S * right = this */ public WordResidue rightDivide(WordResidue S) { if (ring.isField()) { return multiply(S.inverse()); } try { return multiply(S.inverse()); } catch (NotInvertibleException ignored) { System.out.println("catch: " + ignored); //ignored.printStackTrace(); // ignored } catch (UnsupportedOperationException ignored) { //System.out.println("catch: " + ignored); //ignored.printStackTrace(); // ignored } List> R = new ArrayList>(1); R.add(ring.ring.getZERO()); List> V = new ArrayList>(1); V.add(S.val); //@SuppressWarnings("unused") GenWordPolynomial x = ring.bb.red.rightNormalform(R, V, val); GenWordPolynomial y = R.get(0); GenWordPolynomial t = S.val.multiply(y).sum(x); if (!val.equals(t)) { throw new NotDivisibleException("val != t: val = " + val + ", t = " + t); } return new WordResidue(ring, y); } /** * WordResidue inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public WordResidue inverse() { GenWordPolynomial x = ring.ideal.inverse(val); WordResidue xp = new WordResidue(ring, x, 1); if (xp.isZERO()) { throw new NotInvertibleException( "(" + x + ") * (" + val + ") = " + x.multiply(val) + " = 0 mod " + ring.ideal); } if (!xp.multiply(this).isONE()) { throw new NotInvertibleException( "(" + x + ") * (" + val + ") = " + x.multiply(val) + " != 1 mod " + ring.ideal); } return xp; } /** * WordResidue remainder. * @param S WordResidue. * @return this - (this/S) * S. */ public WordResidue remainder(WordResidue S) { List> V = new ArrayList>(1); V.add(S.val); GenWordPolynomial x = ring.bb.red.leftNormalform(V, val); return new WordResidue(ring, x); } /** * WordResidue right remainder. * @param S WordResidue. * @return r = this - S * (S/right), where S * right = this. */ public WordResidue rightRemainder(WordResidue S) { List> V = new ArrayList>(1); V.add(S.val); GenWordPolynomial x = ring.bb.red.rightNormalform(V, val); return new WordResidue(ring, x); } /** * WordResidue two-sided remainder. * @param S WordResidue. * @return r = this - left*S*right. */ public WordResidue twosidedRemainder(WordResidue S) { List> V = new ArrayList>(1); V.add(S.val); GenWordPolynomial x = ring.bb.red.normalform(V, val); WordResidue ret = new WordResidue(ring, x); return ret; } /** * WordResidue multiplication. * @param S WordResidue. * @return this*S. */ public WordResidue multiply(WordResidue S) { GenWordPolynomial x = val.multiply(S.val); int i = -1; if (isunit == 1 && S.isunit == 1) { i = 1; } else if (isunit == 0 || S.isunit == 0) { i = 0; } return new WordResidue(ring, x, i); } /** * WordResidue multiplication. * @param S GenWordPolynomial. * @return this*S. */ public WordResidue multiply(GenWordPolynomial S) { GenWordPolynomial x = val.multiply(S); int i = -1; if (isunit == 1 && S.isUnit()) { i = 1; } else if (isunit == 0 || !S.isUnit()) { i = 0; } return new WordResidue(ring, x, i); } /* * WordResidue multiplication. * @param s coefficient. * @return this*s. */ public WordResidue multiply(C s) { GenWordPolynomial x = val.multiply(s); int i = -1; if (isunit == 1 && s.isUnit()) { i = 1; } else if (isunit == 0 || !s.isUnit()) { i = 0; } return new WordResidue(ring, x, i); } /** * WordResidue multiplication. * @param e word. * @return this*e. */ public WordResidue multiply(Word e) { GenWordPolynomial x = val.multiply(e); int i = -1; if (isunit == 1 && e.isONE()) { i = 1; } else if (isunit == 0 || !e.isONE()) { i = 0; } return new WordResidue(ring, x, i); } /** * WordResidue monic. * @return this with monic value part. */ public WordResidue monic() { return new WordResidue(ring, val.monic(), isunit); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public WordResidue gcd(WordResidue b) { throw new UnsupportedOperationException("gcd not implemented"); // GenWordPolynomial x = ring.engine.gcd(val, b.val); // int i = -1; // gcd might become a unit // if (x.isONE()) { // i = 1; // } else { // System.out.println("WordResidue gcd = " + x); // } // if (isunit == 1 && b.isunit == 1) { // i = 1; // } // return new WordResidue(ring, x, i); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public WordResidue[] egcd(WordResidue b) { throw new UnsupportedOperationException("egcd not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/application/WordResidueRing.java000066400000000000000000000253051445075545500261060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordGroebnerBaseSeq; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; import edu.jas.structure.ValueFactory; /** * WordResidue ring factory based on GenWordPolynomialRing with GcdRingFactory * interface. Objects of this class are immutable. * @author Heinz Kredel */ public class WordResidueRing> implements RingFactory>, QuotPairFactory, WordResidue>, ValueFactory, WordResidue> { private static final Logger logger = LogManager.getLogger(WordResidueRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Groebner base engine. */ protected final WordGroebnerBaseAbstract bb; /** * Word polynomial ideal for the reduction. */ public final WordIdeal ideal; /** * Polynomial ring of the factory. Shortcut to ideal.list.ring. */ public final GenWordPolynomialRing ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a WordResidueRing object from an Ideal. * @param i polynomial ideal. */ public WordResidueRing(WordIdeal i) { this(i, false); } /** * The constructor creates a WordResidueRing object from an WordIdeal. * @param i solvable polynomial ideal. * @param isMaximal true, if ideal is maxmal. */ public WordResidueRing(WordIdeal i, boolean isMaximal) { //System.out.println("i = " + i); ideal = i.GB(); // cheap if isGB //System.out.println("i.GB = " + ideal); ring = ideal.getRing(); bb = new WordGroebnerBaseSeq(); if (isMaximal) { isField = 1; return; } if (ideal.isONE()) { logger.warn("ideal is one, so all residues are 0"); } //System.out.println("rr ring = " + ring.getClass().getName()); //System.out.println("rr cofac = " + ring.coFac.getClass().getName()); } /** * Factory for base elements. */ public GenWordPolynomialRing pairFactory() { return ring; } /** * Factory for base elements. */ public GenWordPolynomialRing valueFactory() { return ring; } /** * Create from numerator. */ public WordResidue create(GenWordPolynomial n) { return new WordResidue(this, n); } /** * Create from numerator, denominator pair. */ public WordResidue create(GenWordPolynomial n, GenWordPolynomial d) { if (d != null && !d.isONE()) { throw new UnsupportedOperationException("d must be 1, but d = " + d); } return new WordResidue(this, n); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ideal.commonZeroTest() <= 0 && ring.coFac.isFinite(); } /** * Copy WordResidue element c. * @param c * @return a copy of c. */ public WordResidue copy(WordResidue c) { //System.out.println("rr copy in = " + c.val); if (c == null) { // where does this happen? return getZERO(); // or null? } WordResidue r = new WordResidue(this, c.val); //System.out.println("rr copy out = " + r.val); //System.out.println("rr copy ideal = " + ideal.list.list); return r; //new WordResidue( c.ring, c.val ); } /** * Get the zero element. * @return 0 as WordResidue. */ public WordResidue getZERO() { return new WordResidue(this, ring.getZERO()); } /** * Get the one element. * @return 1 as WordResidue. */ public WordResidue getONE() { WordResidue one = new WordResidue(this, ring.getONE()); if (one.isZERO()) { logger.warn("ideal is one, so all residues are 0"); } return one; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> pgens = ring.generators(); List> gens = new ArrayList>(pgens.size()); SortedSet> sgens = new TreeSet>(); List> rgens = new ArrayList>(pgens.size()); WordIdeal gi = new WordIdeal(ring, rgens); WordResidueRing gr = new WordResidueRing(gi); for (GenWordPolynomial s : pgens) { WordResidue r = new WordResidue(this, s); if (r.isZERO()) { continue; } if (!r.isONE() && r.val.isConstant()) { continue; } // avoid duplicate generators with sgens WordResidue x = new WordResidue(gr, r.val); if (x.isZERO()) { continue; } if (!x.isONE() && x.val.isConstant()) { continue; } r = new WordResidue(this, x.val); if (r.isZERO()) { continue; } r = r.monic(); if (!r.isONE() && !r.val.isConstant()) { rgens.add(r.val); //System.out.println("rgens = " + rgens); gi = new WordIdeal(ring, rgens); gr = new WordResidueRing(gi); } //gens.add(r); sgens.add(r); } gens.addAll(sgens); return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); // check also vector space structure } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); // sufficient ?? } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (ideal.isMaximal()) { isField = 1; return true; } return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a WordResidue element from a BigInteger value. * @param a BigInteger. * @return a WordResidue. */ public WordResidue fromInteger(java.math.BigInteger a) { return new WordResidue(this, ring.fromInteger(a)); } /** * Get a WordResidue element from a long value. * @param a long. * @return a WordResidue. */ public WordResidue fromInteger(long a) { return new WordResidue(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "WordResidueRing[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "WRC(" + ideal.toScript() + ")"; //return "WRC(" + ideal.toScript() + "," + ring.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof WordResidueRing)) { return false; } WordResidueRing a = null; try { a = (WordResidueRing) b; } catch (ClassCastException e) { } if (a == null) { return false; } if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this residue ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ideal.hashCode(); return h; } /** * WordResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public WordResidue random(int n) { GenWordPolynomial x = ring.random(n).monic(); return new WordResidue(this, x); } /** * Generate a random residum polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @return a random residue polynomial. */ public WordResidue random(int k, int l, int d) { GenWordPolynomial x = ring.random(k, l, d).monic(); return new WordResidue(this, x); } /** * WordResidue random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public WordResidue random(int n, Random rnd) { GenWordPolynomial x = ring.random(n, rnd).monic(); return new WordResidue(this, x); } /** * Parse WordResidue from String. * @param s String. * @return WordResidue from s. */ public WordResidue parse(String s) { GenWordPolynomial x = ring.parse(s); return new WordResidue(this, x); } /** * Parse WordResidue from Reader. * @param r Reader. * @return next WordResidue from r. */ public WordResidue parse(Reader r) { GenWordPolynomial x = ring.parse(r); return new WordResidue(this, x); } } java-algebra-system-2.7.200/src/edu/jas/application/package.html000066400000000000000000000022501445075545500244420ustar00rootroot00000000000000 GB application classes

Groebner base application package.

This package contains classes with applications of Groebner bases such as ideal intersections, ideal quotients or ideal dimension are implemented in Ideal and SolvableIdeal. Class Residue provides polynomials residues modulo an ideal defined in ResidueRing. Comprehensive Groebner bases for polynomial rings over parameter rings are implemented in ComprehensiveGroebnerBaseSeq.

Method rootReduce() from class RootFactoryApp computes a primitive element of two algebraic roots.


Heinz Kredel

Last modified: Wed Aug 17 23:35:02 CEST 2016

$Id$

java-algebra-system-2.7.200/src/edu/jas/arith/000077500000000000000000000000001445075545500207665ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/arith/ArithUtil.java000066400000000000000000000040671445075545500235450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Arithmetic utilities. * @author Heinz Kredel */ public class ArithUtil { private static final Logger logger = LogManager.getLogger(ArithUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Continued fraction. * @param A rational number. * @return continued fraction for A. */ public static List continuedFraction(BigRational A) { List cf = new ArrayList(); if (A == null) { return cf; } if (A.isZERO() || A.isONE()) { cf.add(new BigInteger(A.num)); return cf; } BigRational x = A; BigInteger q = new BigInteger(x.floor()); cf.add(q); BigRational xd = x.subtract(new BigRational(q)); while (!xd.isZERO()) { x = xd.inverse(); q = new BigInteger(x.floor()); cf.add(q); xd = x.subtract(new BigRational(q)); } if (debug) { logger.info("cf = {}", cf); } return cf; } /** * Continued fraction approximation. * @param A continued fraction. * @return ratonal number approximation for A. */ public static BigRational continuedFractionApprox(List A) { BigRational ab = BigRational.ZERO; if (A == null || A.isEmpty()) { return ab; } BigInteger a2, a1, b2, b1, a, b; a2 = BigInteger.ZERO; a1 = BigInteger.ONE; b2 = BigInteger.ONE; b1 = BigInteger.ZERO; for (BigInteger q : A) { a = q.multiply(a1).sum(a2); b = q.multiply(b1).sum(b2); //System.out.println("A/B = " + new BigRational(a,b)); a2 = a1; a1 = a; b2 = b1; b1 = b; } ab = new BigRational(a1, b1); return ab; } } java-algebra-system-2.7.200/src/edu/jas/arith/BigComplex.java000066400000000000000000000457661445075545500237040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.StarRingElem; /** * BigComplex class based on BigRational implementing the RingElem respectively * the StarRingElem interface. Objects of this class are immutable. The SAC2 * static methods are also provided. * @author Heinz Kredel */ public final class BigComplex implements StarRingElem, GcdRingElem, RingFactory { /** * Real part of the data structure. */ public final BigRational re; /** * Imaginary part of the data structure. */ public final BigRational im; private final static Random random = new Random(); private static final Logger logger = LogManager.getLogger(BigComplex.class); /** * The constructor creates a BigComplex object from two BigRational objects * real and imaginary part. * @param r real part. * @param i imaginary part. */ public BigComplex(BigRational r, BigRational i) { re = r; im = i; } /** * The constructor creates a BigComplex object from a BigRational object as * real part, the imaginary part is set to 0. * @param r real part. */ public BigComplex(BigRational r) { this(r, BigRational.ZERO); } /** * The constructor creates a BigComplex object from a long element as real * part, the imaginary part is set to 0. * @param r real part. */ public BigComplex(long r) { this(new BigRational(r), BigRational.ZERO); } /** * The constructor creates a BigComplex object with real part 0 and * imaginary part 0. */ public BigComplex() { this(BigRational.ZERO); } /** * The constructor creates a BigComplex object from a String representation. * @param s string of a BigComplex. * @throws NumberFormatException */ public BigComplex(String s) throws NumberFormatException { if (s == null || s.length() == 0) { re = BigRational.ZERO; im = BigRational.ZERO; return; } s = s.trim(); int i = s.indexOf("i"); if (i < 0) { re = new BigRational(s); im = BigRational.ZERO; return; } //logger.warn("String constructor not done"); String sr = ""; if (i > 0) { sr = s.substring(0, i); } String si = ""; if (i < s.length()) { si = s.substring(i + 1, s.length()); } //int j = sr.indexOf("+"); re = new BigRational(sr.trim()); im = new BigRational(si.trim()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigComplex factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(2); g.add(getONE()); g.add(getIMAG()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigComplex copy() { return new BigComplex(re, im); } /** * Copy BigComplex element c. * @param c BigComplex. * @return a copy of c. */ public BigComplex copy(BigComplex c) { return new BigComplex(c.re, c.im); } /** * Get the zero element. * @return 0 as BigComplex. */ public BigComplex getZERO() { return ZERO; } /** * Get the one element. * @return 1 as BigComplex. */ public BigComplex getONE() { return ONE; } /** * Get the i element. * @return i as BigComplex. */ public BigComplex getIMAG() { return I; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigComplex element from a BigInteger. * @param a BigInteger. * @return a BigComplex. */ public BigComplex fromInteger(BigInteger a) { return new BigComplex(new BigRational(a)); } /** * Get a BigComplex element from a long. * @param a long. * @return a BigComplex. */ public BigComplex fromInteger(long a) { return new BigComplex(new BigRational(a)); } /** * The constant 0. */ public static final BigComplex ZERO = new BigComplex(); /** * The constant 1. */ public static final BigComplex ONE = new BigComplex(BigRational.ONE); /** * The constant i. */ public static final BigComplex I = new BigComplex(BigRational.ZERO, BigRational.ONE); /** * Get the real part. * @return re. */ public BigRational getRe() { return re; } /** * Get the imaginary part. * @return im. */ public BigRational getIm() { return im; } /** * Get the String representation. */ @Override public String toString() { String s = "" + re; int i = im.compareTo(BigRational.ZERO); //logger.info("compareTo {} ? 0 = {}", im, i); if (i == 0) return s; s += "i" + im; return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case: re or re+im*i // was (re,im) or (re,) StringBuffer s = new StringBuffer(); boolean iz = im.isZERO(); if (iz) { s.append(re.toScript()); return s.toString(); } boolean rz = re.isZERO(); if (rz) { if (!im.isONE()) { if (im.signum() > 0) { s.append(im.toScript() + "*"); } else { s.append("-"); BigRational ii = im.negate(); if (!ii.isONE()) { s.append(ii.toScript() + "*"); } } } } else { s.append(re.toScript()); if (im.signum() > 0) { s.append("+"); if (!im.isONE()) { s.append(im.toScript() + "*"); } } else { s.append("-"); BigRational ii = im.negate(); if (!ii.isONE()) { s.append(ii.toScript() + "*"); } } } s.append("I"); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "CC()"; } /** * Complex number zero. * @param A is a complex number. * @return If A is 0 then true is returned, else false. */ public static boolean isCZERO(BigComplex A) { if (A == null) return false; return A.isZERO(); } /** * Is Complex number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return re.isZERO() && im.isZERO(); } /** * Complex number one. * @param A is a complex number. * @return If A is 1 then true is returned, else false. */ public static boolean isCONE(BigComplex A) { if (A == null) return false; return A.isONE(); } /** * Is Complex number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return re.isONE() && im.isZERO(); } /** * Is Complex imaginary one. * @return If this is i then true is returned, else false. */ public boolean isIMAG() { return re.isZERO() && im.isONE(); } /** * Is Complex unit element. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return (!isZERO()); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigComplex)) { return false; } BigComplex bc = (BigComplex) b; return re.equals(bc.re) && im.equals(bc.im); } /** * Hash code for this BigComplex. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * re.hashCode() + im.hashCode(); } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im * > b.im; -1 if re < b.re, or re == b.re and im < b.im */ @Override public int compareTo(BigComplex b) { int s = re.compareTo(b.re); if (s != 0) { return s; } return im.compareTo(b.im); } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > * 0; -1 if re < 0, or re == 0 and im < 0 * @see edu.jas.structure.RingElem#signum() */ public int signum() { int s = re.signum(); if (s != 0) { return s; } return im.signum(); } /* arithmetic operations: +, -, - */ /** * Complex number summation. * @param B a BigComplex number. * @return this+B. */ public BigComplex sum(BigComplex B) { return new BigComplex(re.sum(B.re), im.sum(B.im)); } /** * Complex number sum. * @param A and B are complex numbers. * @return A+B. */ public static BigComplex CSUM(BigComplex A, BigComplex B) { if (A == null) return null; return A.sum(B); } /** * Complex number difference. * @param A and B are complex numbers. * @return A-B. */ public static BigComplex CDIF(BigComplex A, BigComplex B) { if (A == null) return null; return A.subtract(B); } /** * Complex number subtract. * @param B a BigComplex number. * @return this-B. */ public BigComplex subtract(BigComplex B) { return new BigComplex(re.subtract(B.re), im.subtract(B.im)); } /** * Complex number negative. * @param A is a complex number. * @return -A */ public static BigComplex CNEG(BigComplex A) { if (A == null) return null; return A.negate(); } /** * Complex number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigComplex negate() { return new BigComplex(re.negate(), im.negate()); } /** * Complex number conjugate. * @param A is a complex number. * @return the complex conjugate of A. */ public static BigComplex CCON(BigComplex A) { if (A == null) return null; return A.conjugate(); } /* arithmetic operations: conjugate, absolute value */ /** * Complex number conjugate. * @return the complex conjugate of this. */ public BigComplex conjugate() { return new BigComplex(re, im.negate()); } /** * Complex number norm. * @see edu.jas.structure.StarRingElem#norm() * @return ||this||. */ public BigComplex norm() { // this.multiply(this.conjugate()); BigRational v = re.multiply(re); v = v.sum(im.multiply(im)); return new BigComplex(v); } /** * Complex number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|. */ public BigComplex abs() { BigComplex n = norm(); BigRational r = Roots.sqrt(n.re); logger.debug("abs() square root approximaton {}", r); return new BigComplex(r); } /** * Complex number absolute value. * @param A is a complex number. * @return the absolute value of A, a rational number. Note: The square root * is not jet implemented. */ public static BigRational CABS(BigComplex A) { if (A == null) return null; return A.abs().re; } /** * Complex number product. * @param A and B are complex numbers. * @return A*B. */ public static BigComplex CPROD(BigComplex A, BigComplex B) { if (A == null) return null; return A.multiply(B); } /* arithmetic operations: *, inverse, / */ /** * Complex number product. * @param B is a complex number. * @return this*B. */ public BigComplex multiply(BigComplex B) { return new BigComplex(re.multiply(B.re).subtract(im.multiply(B.im)), re.multiply(B.im).sum(im.multiply(B.re))); } /** * Complex number inverse. * @param A is a non-zero complex number. * @return S with S*A = 1. */ public static BigComplex CINV(BigComplex A) { if (A == null) return null; return A.inverse(); } /** * Complex number inverse. * @return S with S*this = 1. * @see edu.jas.structure.RingElem#inverse() */ public BigComplex inverse() { BigRational a = norm().re.inverse(); return new BigComplex(re.multiply(a), im.multiply(a.negate())); } /** * Complex number inverse. * @param S is a complex number. * @return 0. */ public BigComplex remainder(BigComplex S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } return ZERO; } /** * Complex number quotient. * @param A and B are complex numbers, B non-zero. * @return A/B. */ public static BigComplex CQ(BigComplex A, BigComplex B) { if (A == null) return null; return A.divide(B); } /** * Complex number divide. * @param B is a complex number, non-zero. * @return this/B. */ public BigComplex divide(BigComplex B) { return this.multiply(B.inverse()); } /** * Quotient and remainder by division of this by S. * @param S a complex number * @return [this/S, this - (this/S)*S]. */ public BigComplex[] quotientRemainder(BigComplex S) { return new BigComplex[] { divide(S), ZERO }; } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return R. */ public BigComplex random(int n) { return random(n, random); } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @param rnd is a source for random bits. * @return R. */ public BigComplex random(int n, Random rnd) { BigRational r = BigRational.ONE.random(n, rnd); BigRational i = BigRational.ONE.random(n, rnd); return new BigComplex(r, i); } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return R. */ public static BigComplex CRAND(int n) { return ONE.random(n, random); } /** * Parse complex number from string. * @param s String. * @return BigComplex from s. */ public BigComplex parse(String s) { return new BigComplex(s); } /** * Parse complex number from Reader. * @param r Reader. * @return next BigComplex from r. */ public BigComplex parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Complex number greatest common divisor. * @param S BigComplex. * @return gcd(this,S). */ public BigComplex gcd(BigComplex S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } return ONE; } /** * BigComplex extended greatest common divisor. * @param S BigComplex. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigComplex[] egcd(BigComplex S) { BigComplex[] ret = new BigComplex[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigComplex half = new BigComplex(new BigRational(1, 2)); ret[0] = ONE; ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } /** * Returns the number of bits in the representation of this BigComplex, * including a sign bit. It is equivalent to * {@code re.bitLength() + im.bitLength()}.) * @return number of bits in the representation of this BigComplex, * including a sign bit. */ public long bitLength() { return re.bitLength() + im.bitLength(); } } java-algebra-system-2.7.200/src/edu/jas/arith/BigDecimal.java000066400000000000000000000447241445075545500236240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.math.MathContext; import java.util.ArrayList; import java.util.List; import java.util.Random; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * BigDecimal class to make java.math.BigDecimal available with RingElem * interface. Objects of this class are immutable. Experimental, use with care, * compareTo is some times hacked. * @author Heinz Kredel * @see java.math.BigDecimal */ public final class BigDecimal implements GcdRingElem, RingFactory, Rational { /** * The data structure. */ public final java.math.BigDecimal val; public final MathContext context; // should be in factory public static final MathContext DEFAULT_CONTEXT = MathContext.DECIMAL64; //32; //64; //128; public static final int DEFAULT_PRECISION = DEFAULT_CONTEXT.getPrecision(); private final static Random random = new Random(); /** * If true, then use equals from java.math.BigDecimal, else use hacked * approximate compareTo(). */ public final static boolean EXACT_EQUAL = true; /** * The constant 0. */ // depends on math context, should be in factory public final static BigDecimal ZERO = new BigDecimal(java.math.BigDecimal.ZERO); /** * The constant 1. */ // depends on math context, should be in factory public final static BigDecimal ONE = new BigDecimal(java.math.BigDecimal.ONE); /** * Constructor for BigDecimal from math.BigDecimal. * @param a java.math.BigDecimal. */ public BigDecimal(java.math.BigDecimal a) { this(a, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from math.BigDecimal. * @param a java.math.BigDecimal. * @param mc MathContext. */ public BigDecimal(java.math.BigDecimal a, MathContext mc) { val = a; context = mc; } /** * Constructor for BigDecimal from long. * @param a long. */ public BigDecimal(long a) { this(a, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from long and a context. * @param a long. * @param mc MathContext. */ public BigDecimal(long a, MathContext mc) { this(new java.math.BigDecimal(String.valueOf(a)), mc); } /** * Constructor for BigDecimal from double. * @param a double. */ public BigDecimal(double a) { this(a, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from double and a context. * @param a double. * @param mc MathContext. */ public BigDecimal(double a, MathContext mc) { this(new java.math.BigDecimal(a, mc), mc); } /** * Constructor for BigDecimal from java.math.BigInteger. * @param a java.math.BigInteger. */ public BigDecimal(java.math.BigInteger a) { this(a, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from java.math.BigInteger. * @param a java.math.BigInteger. * @param mc MathContext. */ public BigDecimal(java.math.BigInteger a, MathContext mc) { this(new java.math.BigDecimal(a), mc); } /** * Constructor for BigDecimal from BigRational. * @param a edu.jas.arith.BigRational. */ public BigDecimal(BigRational a) { this(a, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from BigRational. * @param a edu.jas.arith.BigRational. * @param mc MathContext. */ public BigDecimal(BigRational a, MathContext mc) { this((new java.math.BigDecimal(a.num, mc)).divide(new java.math.BigDecimal(a.den, mc), mc), mc); } /** * Constructor for BigDecimal from String. * @param s String. */ public BigDecimal(String s) { this(s, DEFAULT_CONTEXT); } /** * Constructor for BigDecimal from String. * @param s String. * @param mc MathContext. */ public BigDecimal(String s, MathContext mc) { this(new java.math.BigDecimal(s.trim()), mc); } /** * Constructor for BigDecimal without parameters. */ public BigDecimal() { this(java.math.BigDecimal.ZERO, DEFAULT_CONTEXT); } /* * Get the value. * @return val java.math.BigDecimal. * public java.math.BigDecimal getVal() { * return val; } */ /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigDecimal factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() Note: is actually * finite but returns false. */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigDecimal copy() { return new BigDecimal(val, context); } /** * Copy BigDecimal element c. * @param c BigDecimal. * @return a copy of c. */ public BigDecimal copy(BigDecimal c) { return new BigDecimal(c.val, c.context); } /** * Get the zero element. * @return 0. */ public BigDecimal getZERO() { return ZERO; } /** * Get the one element. * @return 1. */ public BigDecimal getONE() { return ONE; } /** * Get the decimal representation. * @return decimal. */ public BigDecimal getDecimal() { return this; } /** * Get the rational representation. * @return rational number. */ public BigRational getRational() { return new BigRational(toString()); } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. Floating point number addition is not * associative, but multiplication is. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigDecimal element from a math.BigDecimal. * @param a math.BigDecimal. * @return a as BigDecimal. */ public BigDecimal fromInteger(java.math.BigInteger a) { return new BigDecimal(new java.math.BigDecimal(a), context); } /** * Get a BigDecimal element from a math.BigDecimal. * @param a math.BigDecimal. * @return a as BigDecimal. */ public static BigDecimal valueOf(java.math.BigDecimal a) { return new BigDecimal(a, DEFAULT_CONTEXT); } /** * Get a BigDecimal element from long. * @param a long. * @return a as BigDecimal. */ public BigDecimal fromInteger(long a) { return new BigDecimal(a, context); } /** * Get a BigDecimal element from long. * @param a long. * @return a as BigDecimal. */ public static BigDecimal valueOf(long a) { return new BigDecimal(a, DEFAULT_CONTEXT); } /** * Is BigDecimal number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { if (EXACT_EQUAL) { return val.compareTo(java.math.BigDecimal.ZERO) == 0; } return compareTo(ZERO) == 0; } /** * Is BigDecimal number one. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (EXACT_EQUAL) { return val.compareTo(java.math.BigDecimal.ONE) == 0; } return compareTo(ONE) == 0; } /** * Is BigDecimal number unit. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return (!isZERO()); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { //return val.toString() + "(ulp=" + val.ulp() + ")"; return val.toString(); } /** * Get this decimal as a double. * @return the decimal as a double * @see java.lang.Number#doubleValue() */ public double doubleValue() { return val.doubleValue(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python+Ruby case return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python+Ruby case return "DD()"; } /** * Compare to BigDecimal b. Experimental, is hacked. * @param b BigDecimal. * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < * b. */ @Override public int compareTo(BigDecimal b) { //return compareToAbsolute(b); //return compareToRelative(b); return val.compareTo(b.val); } /** * Compare absolute to BigDecimal b. Experimental, is hacked. * @param b BigDecimal. * @return 0 if abs(this-b) < epsilon, 1 if this > b, -1 if this < * b. */ public int compareToAbsolute(BigDecimal b) { //if (EXACT_EQUAL) { // return val.compareTo(b.val); //} java.math.BigDecimal s = val.subtract(b.val, context); java.math.BigDecimal u1 = val.ulp(); java.math.BigDecimal u2 = b.val.ulp(); int u = Math.min(u1.scale(), u2.scale()); //System.out.println("u = " + u + ", s = " + s); java.math.BigDecimal eps; if (u <= 0) { eps = u1.max(u2); } else { eps = u1.min(u2); } //eps = eps.movePointRight(1); //System.out.println("ctx = " + context); //System.out.println("eps = " + eps); int t = s.abs().compareTo(eps); if (t < 1) { return 0; } return s.signum(); } /** * Compare to relative BigDecimal b. Experimental, is hacked. * @param b BigDecimal. * @return 0 if abs(this-b)/max(this,b) < epsilon, 1 if this > b, -1 * if this < b. */ public int compareToRelative(BigDecimal b) { //if (EXACT_EQUAL) { // return val.compareTo(b.val); //} java.math.BigDecimal s = val.subtract(b.val, context); java.math.BigDecimal u1 = val.ulp(); java.math.BigDecimal u2 = b.val.ulp(); int u = Math.min(u1.scale(), u2.scale()); //System.out.println("u = " + u + ", s = " + s); java.math.BigDecimal eps; if (u <= 0) { eps = u1.max(u2); } else { eps = u1.min(u2); } eps = eps.movePointRight(1); //System.out.println("ctx = " + context); //System.out.println("eps = " + eps); java.math.BigDecimal m = val.abs().max(b.val.abs()); int t; if (m.compareTo(java.math.BigDecimal.ONE) <= 1) { t = s.abs().compareTo(eps); } else { t = s.abs().divide(m, context).compareTo(eps); } if (t < 1) { return 0; } return s.signum(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigDecimal)) { return false; } BigDecimal bi = (BigDecimal) b; if (EXACT_EQUAL) { return val.equals(bi.val); } return compareTo(bi) == 0; } /** * Hash code for this BigDecimal. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return val.hashCode(); } /** * Absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public BigDecimal abs() { return new BigDecimal(val.abs(), context); } /* Negative value of this. * @see edu.jas.structure.RingElem#negate() */ public BigDecimal negate() { return new BigDecimal(val.negate(), context); } /** * signum. * @see edu.jas.structure.RingElem#signum() */ public int signum() { return val.signum(); } /** * BigDecimal subtract. * @param S BigDecimal. * @return this-S. */ public BigDecimal subtract(BigDecimal S) { return new BigDecimal(val.subtract(S.val, context), context); } /** * BigDecimal divide. * @param S BigDecimal. * @return this/S. */ public BigDecimal divide(BigDecimal S) { return new BigDecimal(val.divide(S.val, context), context); } /** * Integer inverse. R is a non-zero integer. S=1/R if defined else 0. * @see edu.jas.structure.RingElem#inverse() */ public BigDecimal inverse() { return ONE.divide(this); } /** * BigDecimal remainder. * @param S BigDecimal. * @return this - (this/S)*S. */ public BigDecimal remainder(BigDecimal S) { return new BigDecimal(val.remainder(S.val, context), context); } /** * BigDecimal compute quotient and remainder. * @param S BigDecimal. * @return BigDecimal[] { q, r } with q = this/S and r = rem(this,S). */ public BigDecimal[] quotientRemainder(BigDecimal S) { BigDecimal[] qr = new BigDecimal[2]; java.math.BigDecimal[] C = val.divideAndRemainder(S.val, context); qr[0] = new BigDecimal(C[0], context); qr[1] = new BigDecimal(C[1], context); return qr; } /** * BigDecimal greatest common divisor. * @param S BigDecimal. * @return gcd(this,S). */ public BigDecimal gcd(BigDecimal S) { throw new UnsupportedOperationException("BigDecimal.gcd() not implemented"); //return new BigDecimal( val.gcd( S.val ) ); } /** * BigDecimal extended greatest common divisor. * @param S BigDecimal. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigDecimal[] egcd(BigDecimal S) { throw new UnsupportedOperationException("BigDecimal.egcd() not implemented"); } /** * BigDecimal random. * @param n such that 0 ≤ val(r) ≤ (2n-1). 0 ≤ exp(r) * ≤ (10-1). * @return r, a random BigDecimal. */ public BigDecimal random(int n) { return random(n, random); } /** * BigDecimal random. * @param n such that 0 ≤ val(r) ≤ (2n-1). 0 ≤ exp(r) * ≤ (10-1). * @param rnd is a source for random bits. * @return r, a random BigDecimal. */ public BigDecimal random(int n, Random rnd) { return random(n, 10, rnd); } /** * BigDecimal random. * @param n such that 0 ≤ val(r) ≤ (2n-1). * @param e such that 0 ≤ exp(r) ≤ (e-1). * @return r, a random BigDecimal. */ public BigDecimal random(int n, int e) { return random(n, e, random); } /** * BigDecimal random. * @param n such that 0 ≤ val(r) ≤ (2n-1). * @param e such that 0 ≤ exp(r) ≤ (e-1). * @param rnd is a source for random bits. * @return r, a random BigDecimal. */ public BigDecimal random(int n, int e, Random rnd) { java.math.BigInteger r = new java.math.BigInteger(n, rnd); if (rnd.nextBoolean()) { r = r.negate(); } int scale = rnd.nextInt(e); //if (rnd.nextBoolean()) { // not according to param spec // scale = -scale; //} java.math.BigDecimal d = new java.math.BigDecimal(r, scale, context); return new BigDecimal(d, context); } /** * BigDecimal multiply. * @param S BigDecimal. * @return this*S. */ public BigDecimal multiply(BigDecimal S) { return new BigDecimal(val.multiply(S.val, context), context); } /** * BigDecimal summation. * @param S BigDecimal. * @return this+S. */ public BigDecimal sum(BigDecimal S) { return new BigDecimal(val.add(S.val, context), context); } /** * BigDecimal parse from String. * @param s String. * @return BigDecimal from s. */ public BigDecimal parse(String s) { int i = s.indexOf("/"); if (i < 0) { // i = 0 also error return new BigDecimal(s, context); } String sd = s.substring(0,i); String sn = s.substring(i+1); //System.out.println("s = " + s + ", sd = " + sd + ", sn = " + sn); BigDecimal dd = new BigDecimal(sd, context); BigDecimal dn = new BigDecimal(sn, context); return dd.divide(dn); } /** * BigDecimal parse from Reader. * @param r Reader. * @return next BigDecimal from r. */ public BigDecimal parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Returns the number of bits in the representation of this BigDecimal, * including a sign bit. For positive BigDecimal, this is equivalent to * {@code val.unscaledValue().bitLength()}.) * @return number of bits in the representation of this BigDecimal, * including a sign bit. */ public long bitLength() { long n = val.unscaledValue().bitLength(); if (val.signum() < 0) { n++; } n++; n += BigInteger.bitLength(val.scale()); return n; } } java-algebra-system-2.7.200/src/edu/jas/arith/BigDecimalComplex.java000066400000000000000000000515331445075545500251500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.StarRingElem; /** * BigComplex class based on BigDecimal implementing the RingElem respectively * the StarRingElem interface. Objects of this class are immutable. * @author Heinz Kredel */ public final class BigDecimalComplex implements StarRingElem, GcdRingElem, RingFactory { /** * Real part of the data structure. */ public final BigDecimal re; /** * Imaginary part of the data structure. */ public final BigDecimal im; private final static Random random = new Random(); private static final Logger logger = LogManager.getLogger(BigDecimalComplex.class); /** * The constant 0. */ // depends on math context, should be in factory public final static BigDecimalComplex ZERO = new BigDecimalComplex(); /** * The constant 1. */ // depends on math context, should be in factory public final static BigDecimalComplex ONE = new BigDecimalComplex(1l); /** * The constant i. */ // depends on math context, should be in factory public final static BigDecimalComplex I = new BigDecimalComplex(0l,1l); /** * The constructor creates a BigDecimalComplex object from two BigDecimal * objects real and imaginary part. * @param r real part. * @param i imaginary part. */ public BigDecimalComplex(BigDecimal r, BigDecimal i) { re = r; im = i; } /** * The constructor creates a BigDecimalComplex object with real part 0 and * imaginary part 0. */ public BigDecimalComplex() { this(0l); } /** * The constructor creates a BigDecimalComplex object from a BigDecimal * object as real part, the imaginary part is set to 0. * @param r real part. */ public BigDecimalComplex(BigDecimal r) { this(r, r.getZERO()); } /** * The constructor creates a BigDecimalComplex object from a long element as * real part, the imaginary part is set to 0. * @param r real part. */ public BigDecimalComplex(long r) { this(new BigDecimal(r)); } /** * The constructor creates a BigDecimalComplex object from a long element as * real part and the imaginary part. * @param r real part. * @param i imaginary part. */ public BigDecimalComplex(long r, long i) { this(new BigDecimal(r), new BigDecimal(i)); } /** * The constructor creates a BigDecimalComplex object from a String * representation. * @param s string of a BigDecimalComplex. * @throws NumberFormatException */ public BigDecimalComplex(String s) throws NumberFormatException { if (s == null || s.length() == 0) { re = new BigDecimal(0l); im = re.getZERO(); return; } s = s.trim(); int i = s.indexOf("i"); if (i < 0) { re = new BigDecimal(s); im = re.getZERO(); return; } //logger.warn("String constructor not done"); String sr = ""; if (i > 0) { sr = s.substring(0, i); } String si = ""; if (i < s.length()) { si = s.substring(i + 1, s.length()); } //int j = sr.indexOf("+"); re = new BigDecimal(sr.trim()); im = new BigDecimal(si.trim()); } /** * The constructor creates a BigDecimalComplex object from a BigComplex * object. * @param a rational BigComplex. */ public BigDecimalComplex(BigComplex a) { this(new BigDecimal(a.re), new BigDecimal(a.im)); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigDecimalComplex factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(2); g.add(getONE()); g.add(getIMAG()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigDecimalComplex copy() { return new BigDecimalComplex(re, im); } /** * Copy BigDecimalComplex element c. * @param c BigDecimalComplex. * @return a copy of c. */ public BigDecimalComplex copy(BigDecimalComplex c) { return new BigDecimalComplex(c.re, c.im); } /** * Get the zero element. * @return 0 as BigDecimalComplex. */ public BigDecimalComplex getZERO() { return ZERO; } /** * Get the one element. * @return 1 as BigDecimalComplex. */ public BigDecimalComplex getONE() { return ONE; } /** * Get the i element. * @return i as BigDecimalComplex. */ public BigDecimalComplex getIMAG() { return I; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigDecimalComplex element from a BigInteger. * @param a BigInteger. * @return a BigDecimalComplex. */ public BigDecimalComplex fromInteger(BigInteger a) { return new BigDecimalComplex(new BigDecimal(a)); } /** * Get a BigDecimalComplex element from a long. * @param a long. * @return a BigDecimalComplex. */ public BigDecimalComplex fromInteger(long a) { return new BigDecimalComplex(new BigDecimal(a)); } /** * Get the real part. * @return re. */ public BigDecimal getRe() { return re; } /** * Get the imaginary part. * @return im. */ public BigDecimal getIm() { return im; } /** * Get the String representation. */ @Override public String toString() { String s = re.toString(); //int i = im.compareTo(BigDecimal.ZERO); //logger.info("compareTo {} ? 0 = {}", im, i); if (im.isZERO()) { return s; } s += "i" + im; return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case: re or re+im*i // was (re,im) or (re,) StringBuffer s = new StringBuffer(); boolean iz = im.isZERO(); if (iz) { s.append(re.toScript()); return s.toString(); } boolean rz = re.isZERO(); if (rz) { if (!im.isONE()) { if (im.signum() > 0) { s.append(im.toScript() + "*"); } else { s.append("-"); BigDecimal ii = im.negate(); if (!ii.isONE()) { s.append(ii.toScript() + "*"); } } } } else { s.append(re.toScript()); if (im.signum() > 0) { s.append("+"); if (!im.isONE()) { s.append(im.toScript() + "*"); } } else { s.append("-"); BigDecimal ii = im.negate(); if (!ii.isONE()) { s.append(ii.toScript() + "*"); } } } s.append("I"); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "CD()"; } /** * Complex number zero. * @param A is a complex number. * @return If A is 0 then true is returned, else false. */ public static boolean isCZERO(BigDecimalComplex A) { if (A == null) { return false; } return A.isZERO(); } /** * Is Complex number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return re.isZERO() && im.isZERO(); } /** * Complex number one. * @param A is a complex number. * @return If A is 1 then true is returned, else false. */ public static boolean isCONE(BigDecimalComplex A) { if (A == null) { return false; } return A.isONE(); } /** * Is Complex number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return re.isONE() && im.isZERO(); } /** * Is Complex imaginary one. * @return If this is i then true is returned, else false. */ public boolean isIMAG() { return re.isZERO() && im.isONE(); } /** * Is Complex unit element. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return (!isZERO()); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigDecimalComplex)) { return false; } BigDecimalComplex bc = (BigDecimalComplex) b; //return re.equals(bc.re) && im.equals(bc.im); return re.compareTo(bc.re) == 0 && im.compareTo(bc.im) == 0; } /** * Hash code for this BigDecimalComplex. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * re.hashCode() + im.hashCode(); } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im * > b.im; -1 if re < b.re, or re == b.re and im < b.im */ @Override public int compareTo(BigDecimalComplex b) { int s = re.compareTo(b.re); //System.out.println("compareTo(a.re,b.re) = " + s); if (s != 0) { return s; } s = im.compareTo(b.im); //System.out.println("compareTo(a.im,b.im) = " + s); return s; } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > * 0; -1 if re < 0, or re == 0 and im < 0 * @see edu.jas.structure.RingElem#signum() */ public int signum() { int s = re.signum(); if (s != 0) { return s; } return im.signum(); } /* arithmetic operations: +, -, - */ /** * Complex number summation. * @param B a BigDecimalComplex number. * @return this+B. */ public BigDecimalComplex sum(BigDecimalComplex B) { return new BigDecimalComplex(re.sum(B.re), im.sum(B.im)); } /** * Complex number sum. * @param A and B are complex numbers. * @return A+B. */ public static BigDecimalComplex CSUM(BigDecimalComplex A, BigDecimalComplex B) { if (A == null) { return null; } return A.sum(B); } /** * Complex number difference. * @param A and B are complex numbers. * @return A-B. */ public static BigDecimalComplex CDIF(BigDecimalComplex A, BigDecimalComplex B) { if (A == null) { return null; } return A.subtract(B); } /** * Complex number subtract. * @param B a BigDecimalComplex number. * @return this-B. */ public BigDecimalComplex subtract(BigDecimalComplex B) { return new BigDecimalComplex(re.subtract(B.re), im.subtract(B.im)); } /** * Complex number negative. * @param A is a complex number. * @return -A */ public static BigDecimalComplex CNEG(BigDecimalComplex A) { if (A == null) { return null; } return A.negate(); } /** * Complex number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigDecimalComplex negate() { return new BigDecimalComplex(re.negate(), im.negate()); } /** * Complex number conjugate. * @param A is a complex number. * @return the complex conjugate of A. */ public static BigDecimalComplex CCON(BigDecimalComplex A) { if (A == null) { return null; } return A.conjugate(); } /* arithmetic operations: conjugate, absolute value */ /** * Complex number conjugate. * @return the complex conjugate of this. */ public BigDecimalComplex conjugate() { return new BigDecimalComplex(re, im.negate()); } /** * Complex number norm. * @see edu.jas.structure.StarRingElem#norm() * @return ||this||. */ public BigDecimalComplex norm() { // this.multiply(this.conjugate()); BigDecimal v = re.multiply(re); if (!im.isZERO()) { v = v.sum(im.multiply(im)); } return new BigDecimalComplex(v); } /** * Complex number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|. */ public BigDecimalComplex abs() { if (im.isZERO()) { return new BigDecimalComplex(re.abs()); } BigDecimalComplex n = norm(); BigDecimal d = Roots.sqrt(n.re); logger.debug("sqrt(re) = {}", d); return new BigDecimalComplex(d); } /** * Complex number absolute value. * @param A is a complex number. * @return the absolute value of A, a rational number. Note: The square root * is not jet implemented. */ public static BigDecimal CABS(BigDecimalComplex A) { if (A == null) { return null; } return A.abs().re; } /** * Complex number product. * @param A and B are complex numbers. * @return A*B. */ public static BigDecimalComplex CPROD(BigDecimalComplex A, BigDecimalComplex B) { if (A == null) { return null; } return A.multiply(B); } /* arithmetic operations: *, inverse, / */ /** * Complex number product. * @param B is a complex number. * @return this*B. */ public BigDecimalComplex multiply(BigDecimalComplex B) { return new BigDecimalComplex(re.multiply(B.re).subtract(im.multiply(B.im)), re.multiply(B.im).sum( im.multiply(B.re))); } /** * Complex number inverse. * @param A is a non-zero complex number. * @return S with S*A = 1. */ public static BigDecimalComplex CINV(BigDecimalComplex A) { if (A == null) { return null; } return A.inverse(); } /** * Complex number inverse. * @return S with S*this = 1. * @see edu.jas.structure.RingElem#inverse() */ public BigDecimalComplex inverse() { BigDecimal a = norm().re.inverse(); return new BigDecimalComplex(re.multiply(a), im.multiply(a.negate())); } /** * Complex number inverse. * @param S is a complex number. * @return 0. */ public BigDecimalComplex remainder(BigDecimalComplex S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } return ZERO; } /** * Complex number quotient. * @param A and B are complex numbers, B non-zero. * @return A/B. */ public static BigDecimalComplex CQ(BigDecimalComplex A, BigDecimalComplex B) { if (A == null) { return null; } return A.divide(B); } /** * Complex number divide. * @param B is a complex number, non-zero. * @return this/B. */ public BigDecimalComplex divide(BigDecimalComplex B) { return this.multiply(B.inverse()); } /** * Quotient and remainder by division of this by S. * @param S a complex number * @return [this/S, this - (this/S)*S]. */ public BigDecimalComplex[] quotientRemainder(BigDecimalComplex S) { return new BigDecimalComplex[] { divide(S), ZERO }; } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return R. */ public BigDecimalComplex random(int n) { return random(n, random); } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @param rnd is a source for random bits. * @return R. */ public BigDecimalComplex random(int n, Random rnd) { BigDecimal r = ZERO.re.random(n, rnd); BigDecimal i = ZERO.re.random(n, rnd); return new BigDecimalComplex(r, i); } /** * Complex number, random. Random rational numbers A and B are generated * using random(n). Then R is the complex number with real part A and * imaginary part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return R. */ public static BigDecimalComplex CRAND(int n) { return new BigDecimalComplex().random(n, random); } /** * Parse complex number from string. * @param s String. * @return BigDecimalComplex from s. */ public BigDecimalComplex parse(String s) { return new BigDecimalComplex(s); } /** * Parse complex number from Reader. * @param r Reader. * @return next BigDecimalComplex from r. */ public BigDecimalComplex parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Complex number greatest common divisor. * @param S BigDecimalComplex. * @return gcd(this,S). */ public BigDecimalComplex gcd(BigDecimalComplex S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } return ONE; } /** * BigDecimalComplex extended greatest common divisor. * @param S BigDecimalComplex. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigDecimalComplex[] egcd(BigDecimalComplex S) { BigDecimalComplex[] ret = new BigDecimalComplex[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigDecimalComplex half = fromInteger(2).inverse(); ret[0] = ONE; ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } /** * Returns the number of bits in the representation of this * BigDecimalComplex, including a sign bit. It is equivalent to * {@code re.bitLength() + im.bitLength()}.) * @return number of bits in the representation of this BigDecimalComplex, * including a sign bit. */ public long bitLength() { return re.bitLength() + im.bitLength(); } } java-algebra-system-2.7.200/src/edu/jas/arith/BigInteger.java000066400000000000000000000466011445075545500236570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingFactory; /** * BigInteger class to make java.math.BigInteger available with RingElem * respectively the GcdRingElem interface. Objects of this class are immutable. * The SAC2 static methods are also provided. * @author Heinz Kredel * @see java.math.BigInteger */ public final class BigInteger implements GcdRingElem, RingFactory, Iterable, Rational { /** * The data structure. */ public final java.math.BigInteger val; private final static Random random = new Random(); /** * The constant 0. */ public final static BigInteger ZERO = new BigInteger(java.math.BigInteger.ZERO); /** * The constant 1. */ public final static BigInteger ONE = new BigInteger(java.math.BigInteger.ONE); /** * The constant 2. */ public final static BigInteger TWO = new BigInteger(2); /** * Constructor for BigInteger from math.BigInteger. * @param a java.math.BigInteger. */ public BigInteger(java.math.BigInteger a) { val = a; } /** * Constructor for BigInteger from long. * @param a long. */ public BigInteger(long a) { val = new java.math.BigInteger(String.valueOf(a)); } /** * Constructor for BigInteger from String. * @param s String. */ public BigInteger(String s) { val = new java.math.BigInteger(s.trim()); } /** * Constructor for BigInteger without parameters. */ public BigInteger() { val = java.math.BigInteger.ZERO; } /** * Get the value. * @return val java.math.BigInteger. */ public java.math.BigInteger getVal() { return val; } /** * Get the value as long. * @return val as long. */ public long longValue() { return val.longValue(); } /** * Get the value as long. * @return val as long if val fits in long. */ public long longValueExact() { return val.longValueExact(); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigInteger factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigInteger copy() { return new BigInteger(val); } /** * Copy BigInteger element c. * @param c BigInteger. * @return a copy of c. */ public BigInteger copy(BigInteger c) { return new BigInteger(c.val); } /** * Get the zero element. * @return 0. */ public BigInteger getZERO() { return ZERO; } /** * Get the one element. * @return 1. */ public BigInteger getONE() { return ONE; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return false. */ public boolean isField() { return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigInteger element from a math.BigInteger. * @param a math.BigInteger. * @return a as BigInteger. */ public BigInteger fromInteger(java.math.BigInteger a) { return new BigInteger(a); } /** * Get a BigInteger element from a math.BigInteger. * @param a math.BigInteger. * @return a as BigInteger. */ public static BigInteger valueOf(java.math.BigInteger a) { return new BigInteger(a); } /** * Get a BigInteger element from long. * @param a long. * @return a as BigInteger. */ public BigInteger fromInteger(long a) { return new BigInteger(a); } /** * Get a BigInteger element from long. * @param a long. * @return a as BigInteger. */ public static BigInteger valueOf(long a) { return new BigInteger(a); } /** * Is BigInteger number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.signum() == 0; //equals(java.math.BigInteger.ZERO); } /** * Is BigInteger number one. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.equals(java.math.BigInteger.ONE); } /** * Is BigInteger number unit. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return (this.isONE() || this.negate().isONE()); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return val.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "ZZ()"; } /** * Compare to BigInteger b. * @param b BigInteger. * @return 0 if this == b, 1 if this > b, -1 if this < b. */ @Override public int compareTo(BigInteger b) { return val.compareTo(b.val); } /** * Integer comparison. * @param A BigInteger. * @param B BigInteger. * @return 0 if A == B, 1 if A > B, -1 if A < B. */ public static int ICOMP(BigInteger A, BigInteger B) { if (A == null) return -B.signum(); return A.compareTo(B); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigInteger)) { return false; } BigInteger bi = (BigInteger) b; return val.equals(bi.val); } /** * Hash code for this BigInteger. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return val.hashCode(); } /** * Absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public BigInteger abs() { return new BigInteger(val.abs()); } /** * Absolute value. * @param A BigInteger. * @return abs(A). */ public static BigInteger IABS(BigInteger A) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.abs(); } /* Negative value of this. * @see edu.jas.structure.RingElem#negate() */ public BigInteger negate() { return new BigInteger(val.negate()); } /** * Negative value. * @param A BigInteger. * @return -A. */ public static BigInteger INEG(BigInteger A) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.negate(); } /** * signum. * @see edu.jas.structure.RingElem#signum() */ public int signum() { return val.signum(); } /** * Integer signum. * @param A BigInteger. * @return signum(A). */ public static int ISIGN(BigInteger A) { if (A == null) return 0; return A.signum(); } /** * BigInteger subtract. * @param S BigInteger. * @return this-S. */ public BigInteger subtract(BigInteger S) { return new BigInteger(val.subtract(S.val)); } /** * BigInteger subtract. * @param A BigInteger. * @param B BigInteger. * @return A-B. */ public static BigInteger IDIF(BigInteger A, BigInteger B) { if (A == null) return B.negate(); return A.subtract(B); } /** * BigInteger divide. * @param S BigInteger. * @return this/S. */ public BigInteger divide(BigInteger S) { return new BigInteger(val.divide(S.val)); } /** * BigInteger divide. * @param A BigInteger. * @param B BigInteger. * @return A/B. */ public static BigInteger IQ(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.divide(B); } /** * Integer inverse. R is a non-zero integer. S=1/R if defined else throws * not invertible exception. * @see edu.jas.structure.RingElem#inverse() */ public BigInteger inverse() { if (this.isONE() || this.negate().isONE()) { return this; } //return ZERO; throw new NotInvertibleException("element not invertible " + this + " :: BigInteger"); } /** * BigInteger remainder. * @param S BigInteger. * @return this - (this/S)*S. */ public BigInteger remainder(BigInteger S) { return new BigInteger(val.remainder(S.val)); } /** * BigInteger remainder. * @param A BigInteger. * @param B BigInteger. * @return A - (A/B)*B. */ public static BigInteger IREM(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.remainder(B); } /** * BigInteger compute quotient and remainder. Throws an exception, if S == * 0. * @param S BigInteger. * @return BigInteger[] { q, r } with this = q S + r and 0 ≤ r < |S|. */ //@Override public BigInteger[] quotientRemainder(BigInteger S) { BigInteger[] qr = new BigInteger[2]; java.math.BigInteger[] C = val.divideAndRemainder(S.val); qr[0] = new BigInteger(C[0]); qr[1] = new BigInteger(C[1]); return qr; } /** * Integer quotient and remainder. A and B are integers, B ne 0. Q is the * quotient, integral part of A/B, and R is the remainder A-B*Q. Throws an * exception, if B == 0. * @param A BigInteger. * @param B BigInteger. * @return BigInteger[] { q, r } with A = q B + r and 0 ≤ r < |B| */ public static BigInteger[] IQR(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.quotientRemainder(B); } /** * BigInteger greatest common divisor. * @param S BigInteger. * @return gcd(this,S). */ public BigInteger gcd(BigInteger S) { return new BigInteger(val.gcd(S.val)); } /** * BigInteger extended greatest common divisor. * @param S BigInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigInteger[] egcd(BigInteger S) { BigInteger[] ret = new BigInteger[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } //System.out.println("this = " + this + ", S = " + S); BigInteger[] qr; BigInteger q = this; BigInteger r = S; BigInteger c1 = ONE; BigInteger d1 = ZERO; BigInteger c2 = ZERO; BigInteger d2 = ONE; BigInteger x1; BigInteger x2; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); if (q.signum() < 0) { q = q.negate(); c1 = c1.negate(); c2 = c2.negate(); } ret[0] = q; ret[1] = c1; ret[2] = c2; return ret; } /** * BigInteger greatest common divisor. * @param A BigInteger. * @param B BigInteger. * @return gcd(A,B). */ public static BigInteger IGCD(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.gcd(B); } /** * BigInteger random. * @param n such that 0 ≤ r ≤ (2n-1). * @return r, a random BigInteger. */ public BigInteger random(int n) { return random(n, random); } /** * BigInteger random. * @param n such that 0 ≤ r ≤ (2n-1). * @param rnd is a source for random bits. * @return r, a random BigInteger. */ public BigInteger random(int n, Random rnd) { java.math.BigInteger r = new java.math.BigInteger(n, rnd); if (rnd.nextBoolean()) { r = r.negate(); } return new BigInteger(r); } /** * BigInteger random. * @param NL such that 0 ≤ r ≤ (2n-1). * @return r, a random BigInteger. */ public static BigInteger IRAND(int NL) { return ONE.random(NL, random); } /** * BigInteger multiply. * @param S BigInteger. * @return this*S. */ public BigInteger multiply(BigInteger S) { return new BigInteger(val.multiply(S.val)); } /** * BigInteger shift left. * @param n bits to shift. * @return this << n. */ public BigInteger shiftLeft(int n) { return new BigInteger(val.shiftLeft(n)); } /** * BigInteger multiply. * @param A BigInteger. * @param B BigInteger. * @return A*B. */ public static BigInteger IPROD(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.multiply(B); } /** * BigInteger summation. * @param S BigInteger. * @return this+S. */ public BigInteger sum(BigInteger S) { return new BigInteger(val.add(S.val)); } /** * BigInteger addition. * @param A BigInteger. * @param B BigInteger. * @return A+B. */ public static BigInteger ISUM(BigInteger A, BigInteger B) { if (A == null) { throw new IllegalArgumentException("null A not allowed"); } return A.sum(B); } /** * BigInteger parse from String. * @param s String. * @return Biginteger from s. */ public BigInteger parse(String s) { return new BigInteger(s); } /** * BigInteger parse from Reader. * @param r Reader. * @return next Biginteger from r. */ public BigInteger parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Get the decimal representation. * @return decimal. */ public BigDecimal getDecimal() { return new BigDecimal(val); } /** * Return a BigRational approximation of this Element. * @return a BigRational approximation of this. */ public BigRational getRational() { return new BigRational(val); } /** * Returns the number of bits in the representation of this BigInteger, * including a sign bit. For positive BigIntegers, this is equivalent to * {@code (ceil(log2(this+1))+1)}.) * @return number of bits in the representation of this BigInteger, * including a sign bit. */ public long bitLength() { long n = val.bitLength(); //System.out.println("sign(val) = " + val.signum()); if (val.signum() < 0) { n++; } return ++n; } /** * Returns the number of bits in the representation of a Long, including a * sign bit. * @param v value. * @return number of bits in the representation of a Long, including a sign * bit. */ public static long bitLength(long v) { // compare BigInteger.bitLengthForInt long n = 64 - Long.numberOfLeadingZeros(v); return ++n; } private boolean nonNegative = true; /** * Set the iteration algorithm to all elements. */ public void setAllIterator() { nonNegative = false; } /** * Set the iteration algorithm to non-negative elements. */ public void setNonNegativeIterator() { nonNegative = true; } /** * Get a BigInteger iterator. * @return a iterator over all integers. */ public Iterator iterator() { return new BigIntegerIterator(nonNegative); } } /** * Big integer iterator. * @author Heinz Kredel */ class BigIntegerIterator implements Iterator { /** * data structure. */ java.math.BigInteger curr; final boolean nonNegative; /** * BigInteger iterator constructor. */ public BigIntegerIterator() { this(false); } /** * BigInteger iterator constructor. * @param nn true for an iterator over non-negative longs, false for all * elements iterator. */ public BigIntegerIterator(boolean nn) { curr = java.math.BigInteger.ZERO; nonNegative = nn; } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public boolean hasNext() { return true; } /** * Get next integer. * @return next integer. */ public synchronized BigInteger next() { BigInteger i = new BigInteger(curr); if (nonNegative) { curr = curr.add(java.math.BigInteger.ONE); } else if (curr.signum() > 0 && !nonNegative) { curr = curr.negate(); } else { curr = curr.negate().add(java.math.BigInteger.ONE); } return i; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/arith/BigOctonion.java000066400000000000000000000511741445075545500240530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.StarRingElem; /** * BigOctonion class based on BigRational implementing the RingElem interface * and with the familiar MAS static method names. Objects of this class are * immutable. * @author Heinz Kredel */ public final class BigOctonion implements StarRingElem, GcdRingElem, RingFactory { /** * First part of the data structure. */ public final BigQuaternion or; /** * Second part of the data structure. */ public final BigQuaternion oi; private final static Random random = new Random(); private static final Logger logger = LogManager.getLogger(BigOctonion.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for a BigOctonion from Quaternions. * @param r BigQuaternion. * @param i BigQuaternion. */ public BigOctonion(BigQuaternion r, BigQuaternion i) { if (i == null) { throw new IllegalArgumentException("null i not allowed"); } this.or = r; this.oi = i; //if (ZERO == null) { //ZERO = new BigOctonion(r.ring.ZERO, i.ring.ZERO); //ONE = new BigOctonion(r.ring.ONE, i.ring.ZERO); //I = new BigOctonion(r.ring.ZERO, i.ring.ONE); //} } /** * Constructor for a BigOctonion from BigQuaternion. * @param r BigQuaternion. */ public BigOctonion(BigQuaternion r) { this(r, r.ring.ZERO); } /** * Constructor for a BigOctonion from BigComplex. * @param fac BigQuaternionRing. * @param r BigComplex. */ public BigOctonion(BigQuaternionRing fac, BigComplex r) { this(new BigQuaternion(fac, r)); } /** * Constructor for a BigOctonion from BigRational. * @param fac BigQuaternionRing. * @param r BigRational. */ public BigOctonion(BigQuaternionRing fac, BigRational r) { this(new BigQuaternion(fac, r)); } /** * Constructor for a BigOctonion from long. * @param fac BigQuaternionRing. * @param r long. */ public BigOctonion(BigQuaternionRing fac, long r) { this(new BigQuaternion(fac, r)); } /** * Constructor for a BigOctonion with no arguments. * @param fac BigQuaternionRing. */ public BigOctonion(BigQuaternionRing fac) { this(new BigQuaternion(fac)); } /** * The BigOctonion string constructor accepts the following formats: empty * string, "quaternion", or "quat o quat" with no blanks around o if used as * polynoial coefficient. * @param fac BigQuaternionRing. * @param s String. * @throws NumberFormatException */ public BigOctonion(BigQuaternionRing fac, String s) throws NumberFormatException { if (s == null || s.length() == 0) { or = getZERO().or; oi = getZERO().oi; return; } s = s.trim(); int o = s.indexOf("o"); if (o == -1) { or = new BigQuaternion(fac, s); oi = getZERO().oi; return; } String sr = s.substring(0, o - 1); String so = s.substring(o + 1, s.length()); or = new BigQuaternion(fac, sr.trim()); oi = new BigQuaternion(fac, so.trim()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigOctonion factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List qg = or.ring.generators(); List g = new ArrayList(qg.size() * 2); for (BigQuaternion q : qg) { g.add(new BigOctonion(q)); g.add(new BigOctonion(or.ring.ZERO, q)); } return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigOctonion copy() { return new BigOctonion(or, oi); } /** * Copy BigOctonion element c. * @param c BigOctonion. * @return a copy of c. */ public BigOctonion copy(BigOctonion c) { if (c == null) { throw new IllegalArgumentException("copy of null not allowed"); } return new BigOctonion(c.or, c.oi); } /** * Get the zero element. * @return 0 as BigOctonion. */ public BigOctonion getZERO() { if (ZERO == null) { ZERO = new BigOctonion(or.ring.ZERO, or.ring.ZERO); I = new BigOctonion(or.ring.ZERO, or.ring.ONE); } return ZERO; } /** * Get the one element. * @return q as BigOctonion. */ public BigOctonion getONE() { if (ONE == null) { ONE = new BigOctonion(or.ring.ONE, or.ring.ZERO); } return ONE; } /** * Query if this ring is commutative. * @return false. */ public boolean isCommutative() { return false; } /** * Query if this ring is associative. * @return false. */ public boolean isAssociative() { return false; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigOctonion element from a BigInteger. * @param a BigInteger. * @return a BigOctonion. */ public BigOctonion fromInteger(BigInteger a) { return new BigOctonion(or.ring.fromInteger(a)); } /** * Get a BigOctonion element from a long. * @param a long. * @return a BigOctonion. */ public BigOctonion fromInteger(long a) { return new BigOctonion(or.ring.fromInteger(a)); } /** * The constant 0. */ public BigOctonion ZERO; // = new BigOctonion(or.ring); /** * The constant 1. */ public BigOctonion ONE; // = new BigOctonion(or.ring.ONE); /** * The constant i. */ public BigOctonion I; // = new BigOctonion(or.ring.ZERO, oi.ring.ONE); /** * Get the or part. * @return or. */ public BigQuaternion getR() { return or; } /** * Get the oi part. * @return oi. */ public BigQuaternion getI() { return oi; } /** * Get the string representation. Is compatible with the string constructor. * @see java.lang.Object#toString() */ @Override public String toString() { String s = or.toString(); boolean i = oi.isZERO(); if (debug) { logger.debug("compareTo {} ? 0 = {}", oi, i); } if (i) { return s; } s += "o" + oi; return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case boolean i = oi.isZERO(); if (i && or.isZERO()) { return "0 "; } StringBuffer s = new StringBuffer(); if (!or.isZERO()) { String rs = or.toScript(); rs = rs.replaceAll("Q", "OR"); s.append(rs); s.append(" "); } if (!i) { if (s.length() > 0) { s.append("+ "); } String is = oi.toScript(); is = is.replaceAll("Q", "OI"); s.append(is); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "Oct()"; } /** * Is Octonion number zero. * @param A BigOctonion. * @return true if A is 0, else false. */ public static boolean isOZERO(BigOctonion A) { if (A == null) return false; return A.isZERO(); } /** * Is BigOctonion number zero. * @return true if this is 0, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return or.isZERO() && oi.isZERO(); } /** * Is BigOctonion number one. * @param A is a quaternion number. * @return true if A is 1, else false. */ public static boolean isOONE(BigOctonion A) { if (A == null) return false; return A.isONE(); } /** * Is BigOctonion number one. * @see edu.jas.structure.RingElem#isONE() * @return true if this is 1, else false. */ public boolean isONE() { return or.isONE() && oi.isZERO(); } /** * Is BigOctonion imaginary one. * @return true if this is i, else false. */ public boolean isIMAG() { return or.isZERO() && oi.isONE(); } /** * Is BigOctonion unit element. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return !isZERO(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigOctonion)) return false; BigOctonion B = (BigOctonion) b; return or.equals(B.or) && oi.equals(B.oi); } /** * Hash code for this BigOctonion. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = 41 * or.hashCode(); h += oi.hashCode(); return h; } /** * Since quaternion numbers are unordered, we use lexicographical order of * re, im, jm and km. * @param b BigOctonion. * @return 0 if b is equal to this, 1 if this is greater b and -1 else. */ @Override public int compareTo(BigOctonion b) { int s = or.compareTo(b.or); if (s != 0) { return s; } return oi.compareTo(b.oi); } /** * Since quaternion numbers are unordered, we use lexicographical order of * re, im, jm and km. * @return 0 if this is equal to 0; 1 if or > 0, or or == 0 and oi > * 0; -1 if or < 0, or or == 0 and oi < 0. * @see edu.jas.structure.RingElem#signum() */ public int signum() { int s = or.signum(); if (s != 0) { return s; } return oi.signum(); } /* arithmetic operations: +, -, - */ /** * BigOctonion summation. * @param B BigOctonion. * @return this+B. */ public BigOctonion sum(BigOctonion B) { return new BigOctonion(or.sum(B.or), oi.sum(B.oi)); } /** * Octonion number sum. * @param A BigOctonion. * @param B BigOctonion. * @return A+B. */ public static BigOctonion OSUM(BigOctonion A, BigOctonion B) { if (A == null) return null; return A.sum(B); } /** * Octonion number difference. * @param A BigOctonion. * @param B BigOctonion. * @return A-B. */ public static BigOctonion ODIF(BigOctonion A, BigOctonion B) { if (A == null) return null; return A.subtract(B); } /** * BigOctonion subtraction. * @param B BigOctonion. * @return this-B. */ public BigOctonion subtract(BigOctonion B) { return new BigOctonion(or.subtract(B.or), oi.subtract(B.oi)); } /** * Octonion number negative. * @param A is a octonion number * @return -A. */ public static BigOctonion ONEG(BigOctonion A) { if (A == null) return null; return A.negate(); } /** * BigOctonion number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigOctonion negate() { return new BigOctonion(or.negate(), oi.negate()); } /** * Octonion number conjugate. * @param A is a quaternion number. * @return the quaternion conjugate of A. */ public static BigOctonion OCON(BigOctonion A) { if (A == null) return null; return A.conjugate(); } /* arithmetic operations: conjugate, absolute value */ /** * BigOctonion conjugate. * @return conjugate(this). */ public BigOctonion conjugate() { return new BigOctonion(or.conjugate(), oi.negate()); } /** * Octonion number norm. * @see edu.jas.structure.StarRingElem#norm() * @return ||this||. */ public BigOctonion norm() { // this.multiply(this.conjugate()); BigQuaternion v = or.norm(); v = v.sum(oi.norm()); return new BigOctonion(v); } /** * Octonion number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|. */ public BigOctonion abs() { BigOctonion n = norm(); BigRational r = Roots.sqrt(n.or.re); //logger.error("abs() square root missing"); return new BigOctonion(new BigQuaternion(n.or.ring, r)); } /** * Octonion number absolute value. * @param A is a quaternion number. * @return the absolute value of A, a rational number. Note: The square root * is not jet implemented. */ public static BigRational OABS(BigOctonion A) { if (A == null) return null; return A.abs().or.re; } /** * Octonion number product. * @param A BigOctonion. * @param B BigOctonion. * @return A*B. */ public static BigOctonion OPROD(BigOctonion A, BigOctonion B) { if (A == null) return null; return A.multiply(B); } /* arithmetic operations: *, inverse, / */ /** * BigOctonion multiply. * @param B BigOctonion. * @return this*B. */ public BigOctonion multiply(BigOctonion B) { // (r1,i1)(r2,i2) = ( r1 r2 - i2 i1^, r1^ i2 + r2 i1 ) Baez, jas // (r1,i1)(r2,i2) = ( r1 r2 - i2^ i1, i1 r2^ + i2 r1 ) Dieudonne, mas BigQuaternion r = or.multiply(B.or); r = r.subtract(B.oi.multiply(oi.conjugate())); BigQuaternion i = or.conjugate().multiply(B.oi); i = i.sum(B.or.multiply(oi)); return new BigOctonion(r, i); } /** * Octonion number inverse. * @param A is a non-zero quaternion number. * @return S with S * A = 1. */ public static BigOctonion OINV(BigOctonion A) { if (A == null) return null; return A.inverse(); } /** * BigOctonion inverse. * @return S with S * this = 1. * @see edu.jas.structure.RingElem#inverse() */ public BigOctonion inverse() { BigRational a = norm().or.re; return conjugate().divide(a); } /** * BigOctonion remainder. * @param S BigOctonion. * @return 0. */ public BigOctonion remainder(BigOctonion S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } return ZERO; } /** * Octonion number quotient. * @param A BigOctonion. * @param B BigOctonion. * @return R/S. */ public static BigOctonion OQ(BigOctonion A, BigOctonion B) { if (A == null) return null; return A.divide(B); } /** * BigOctonion divide. * @param b BigOctonion. * @return this * b**(-1). */ public BigOctonion divide(BigOctonion b) { return rightDivide(b); } /** * BigOctonion right divide. * @param b BigOctonion. * @return this * b**(-1). */ public BigOctonion rightDivide(BigOctonion b) { return this.multiply(b.inverse()); } /** * BigOctonion left divide. * @param b BigOctonion. * @return b**(-1) * this. */ public BigOctonion leftDivide(BigOctonion b) { return b.inverse().multiply(this); } /** * BigOctonion divide. * @param b BigRational. * @return this/b. */ public BigOctonion divide(BigRational b) { BigRational bi = b.inverse(); return new BigOctonion(or.multiply(bi), oi.multiply(bi)); } /** * Quotient and remainder by division of this by S. * @param S a octonion number * @return [this/S, this - (this/S)*S]. */ public BigOctonion[] quotientRemainder(BigOctonion S) { return new BigOctonion[] { divide(S), ZERO }; } /** * BigOctonion random. Random rational numbers A, B, C and D are generated * using random(n). Then R is the quaternion number with real part A and * imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @return R, a random BigOctonion. */ public BigOctonion random(int n) { return random(n, random); } /** * BigOctonion random. Random rational numbers A, B, C and D are generated * using RNRAND(n). Then R is the quaternion number with real part A and * imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @param rnd is a source for random bits. * @return R, a random BigOctonion. */ public BigOctonion random(int n, Random rnd) { BigQuaternion rr = or.ring.random(n, rnd); BigQuaternion ir = oi.ring.random(n, rnd); return new BigOctonion(rr, ir); } /* * Octonion number, random. Random rational numbers A, B, C and D are * generated using RNRAND(n). Then R is the quaternion number with real part * A and imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @return R, a random BigOctonion. public static BigOctonion ORAND(int n) { return random(n, random); } */ /** * Parse quaternion number from String. * @param s String. * @return BigOctonion from s. */ public BigOctonion parse(String s) { return new BigOctonion(or.ring, s); } /** * Parse quaternion number from Reader. * @param r Reader. * @return next BigOctonion from r. */ public BigOctonion parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Octonion number greatest common divisor. * @param S BigOctonion. * @return gcd(this,S). */ public BigOctonion gcd(BigOctonion S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } return ONE; } /** * BigOctonion extended greatest common divisor. * @param S BigOctonion. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigOctonion[] egcd(BigOctonion S) { BigOctonion[] ret = new BigOctonion[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigOctonion half = new BigOctonion(or.ring, new BigRational(1, 2)); ret[0] = ONE; ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } /** * Returns the number of bits in the representation of this BigOctonion, * including a sign bit. It is equivalent to * {@code or.bitLength() + oi.bitLength()}.) * @return number of bits in the representation of this BigOctonion, * including a sign bit. */ public long bitLength() { return or.bitLength() + oi.bitLength(); } } java-algebra-system-2.7.200/src/edu/jas/arith/BigQuaternion.java000066400000000000000000000707351445075545500244140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.GcdRingElem; import edu.jas.structure.StarRingElem; /** * BigQuaternion class based on BigRational implementing the RingElem interface * and with the familiar MAS static method names. Objects of this class are * immutable. The integer quaternion methods are implemented after * https://de.wikipedia.org/wiki/Hurwitzquaternion see also * https://en.wikipedia.org/wiki/Hurwitz_quaternion * @author Heinz Kredel */ public /*final*/ class BigQuaternion implements StarRingElem, GcdRingElem { /** * Real part of the data structure. */ public final BigRational re; // real part /** * Imaginary part i of the data structure. */ public final BigRational im; // i imaginary part /** * Imaginary part j of the data structure. */ public final BigRational jm; // j imaginary part /** * Imaginary part k of the data structure. */ public final BigRational km; // k imaginary part /** * Corresponding BigQuaternion ring. */ public final BigQuaternionRing ring; protected final static Random random = new Random(); private static final Logger logger = LogManager.getLogger(BigQuaternion.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. * @param j BigRational. * @param k BigRational. */ public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j, BigRational k) { ring = fac; re = r; im = i; jm = j; km = k; } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. * @param j BigRational. */ public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j) { this(fac, r, i, j, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. */ public BigQuaternion(BigQuaternionRing fac, BigRational r, BigRational i) { this(fac, r, i, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. */ public BigQuaternion(BigQuaternionRing fac, BigRational r) { this(fac, r, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigComplex. * @param fac BigQuaternionRing. * @param r BigComplex. */ public BigQuaternion(BigQuaternionRing fac, BigComplex r) { this(fac, r.re, r.im); } /** * Constructor for a BigQuaternion from long. * @param fac BigQuaternionRing. * @param r long. */ public BigQuaternion(BigQuaternionRing fac, long r) { this(fac, new BigRational(r), BigRational.ZERO); } /** * Constructor for a BigQuaternion with no arguments. * @param fac BigQuaternionRing. */ public BigQuaternion(BigQuaternionRing fac) { this(fac, BigRational.ZERO); } /** * The BigQuaternion string constructor accepts the following formats: empty * string, "rational", or "rat i rat j rat k rat" with no blanks around i, j * or k if used as polynoial coefficient. * @param fac BigQuaternionRing. * @param s String. * @throws NumberFormatException */ public BigQuaternion(BigQuaternionRing fac, String s) throws NumberFormatException { ring = fac; if (s == null || s.length() == 0) { re = BigRational.ZERO; im = BigRational.ZERO; jm = BigRational.ZERO; km = BigRational.ZERO; return; } //System.out.println("init: s = " + s); s = s.trim(); int r = s.indexOf("i") + s.indexOf("j") + s.indexOf("k"); if (r == -3) { re = new BigRational(s); im = BigRational.ZERO; jm = BigRational.ZERO; km = BigRational.ZERO; return; } s = s.replaceAll("~", "-"); // when used with GenPolynomialTokenizer int i = s.indexOf("i"); String sr = ""; if (i > 0) { sr = s.substring(0, i); } else if (i < 0) { throw new NumberFormatException("BigQuaternion missing i: " + s); } String si = ""; if (i < s.length()) { s = s.substring(i + 1, s.length()); } int j = s.indexOf("j"); if (j > 0) { si = s.substring(0, j); } else if (j < 0) { throw new NumberFormatException("BigQuaternion missing j: " + s); } String sj = ""; if (j < s.length()) { s = s.substring(j + 1, s.length()); } int k = s.indexOf("k"); if (k > 0) { sj = s.substring(0, k); } else if (k < 0) { throw new NumberFormatException("BigQuaternion missing k: " + s); } String sk = ""; if (k < s.length()) { s = s.substring(k + 1, s.length()); } sk = s; re = new BigRational(sr.trim()); im = new BigRational(si.trim()); jm = new BigRational(sj.trim()); km = new BigRational(sk.trim()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigQuaternionRing factory() { return ring; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigQuaternion copy() { return new BigQuaternion(ring, re, im, jm, km); } /** * Get the real part. * @return re. */ public BigRational getRe() { return re; } /** * Get the imaginary part im. * @return im. */ public BigRational getIm() { return im; } /** * Get the imaginary part jm. * @return jm. */ public BigRational getJm() { return jm; } /** * Get the imaginary part km. * @return km. */ public BigRational getKm() { return km; } /** * Get the string representation. Is compatible with the string constructor. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); int r = re.compareTo(BigRational.ZERO); if (r != 0) { sb.append(re.toString()); } int i = im.compareTo(BigRational.ZERO); int j = jm.compareTo(BigRational.ZERO); int k = km.compareTo(BigRational.ZERO); if (debug) { logger.debug("compareTo {} ? 0 = {}", im, i); logger.debug("compareTo {} ? 0 = {}", jm, j); logger.debug("compareTo {} ? 0 = {}", km, k); } if (i == 0 && j == 0 && k == 0) { if (r == 0) { sb.append(re.toString()); } return sb.toString(); } if (i != 0) { sb.append("i" + im); } if (j != 0) { sb.append("j" + jm); } if (k != 0) { sb.append("k" + km); } String s = sb.toString(); //s = s.replaceAll("-","~"); return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer(); boolean i = im.isZERO(); boolean j = jm.isZERO(); boolean k = km.isZERO(); if (i && j && k) { if (re.isZERO()) { return "0 "; } if (!re.isONE()) { s.append(re.toScript() + "*"); } s.append("oneQ "); return s.toString(); } if (!re.isZERO()) { if (!re.isONE()) { s.append(re.toScript() + "*"); } s.append("oneQ "); } if (!i) { if (s.length() > 0) { s.append("+ "); } if (!im.isONE()) { s.append(im.toScript() + "*"); } s.append("IQ "); } if (!j) { if (s.length() > 0) { s.append("+ "); } if (!jm.isONE()) { s.append(jm.toScript() + "*"); } s.append("JQ "); } if (!k) { if (s.length() > 0) { s.append("+ "); } if (!km.isONE()) { s.append(km.toScript() + "*"); } s.append("KQ "); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return ring.toScript(); } /** * Is Quaternion number zero. * @param A BigQuaternion. * @return true if A is 0, else false. */ public static boolean isQZERO(BigQuaternion A) { if (A == null) return false; return A.isZERO(); } /** * Is BigQuaternion number zero. * @return true if this is 0, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return re.isZERO() && im.isZERO() && jm.isZERO() && km.isZERO(); } /** * Is BigQuaternion number one. * @param A is a quaternion number. * @return true if A is 1, else false. */ public static boolean isQONE(BigQuaternion A) { if (A == null) return false; return A.isONE(); } /** * Is BigQuaternion number one. * @see edu.jas.structure.RingElem#isONE() * @return true if this is 1, else false. */ public boolean isONE() { return re.isONE() && im.isZERO() && jm.isZERO() && km.isZERO(); } /** * Is BigQuaternion imaginary one. * @return true if this is i, else false. */ public boolean isIMAG() { return re.isZERO() && im.isONE() && jm.isZERO() && km.isZERO(); } /** * Is BigQuaternion unit element. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { //if (ring.integral) { not meaningful to test // System.out.println("*** entier isUnit case not implemented ***"); //} return !isZERO(); } /** * Is BigQuaternion entier element. * @return If this is an integer Hurwitz element then true is returned, else * false. */ public boolean isEntier() { if (re.isEntier() && im.isEntier() && jm.isEntier() && km.isEntier()) { return true; } java.math.BigInteger TWO = BigInteger.TWO.val; return re.den.equals(TWO) && im.den.equals(TWO) && jm.den.equals(TWO) && km.den.equals(TWO); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigQuaternion)) { return false; } BigQuaternion B = (BigQuaternion) b; // ring == B.ring ? return re.equals(B.re) && im.equals(B.im) && jm.equals(B.jm) && km.equals(B.km); } /** * Hash code for this BigQuaternion. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = re.hashCode(); h += h * 37 + im.hashCode(); h += h * 37 + jm.hashCode(); h += h * 37 + km.hashCode(); return h; } /** * Since quaternion numbers are unordered, we use lexicographical order of * re, im, jm and km. * @param b BigQuaternion. * @return 0 if b is equal to this, 1 if this is greater b and -1 else. */ @Override public int compareTo(BigQuaternion b) { int s = re.compareTo(b.re); if (s != 0) { return s; } s = im.compareTo(b.im); if (s != 0) { return s; } s = jm.compareTo(b.jm); if (s != 0) { return s; } return km.compareTo(b.km); } /** * Since quaternion numbers are unordered, we use lexicographical order of * re, im, jm and km. * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > * 0, or ...; -1 if re < 0, or re == 0 and im < 0, or ... * @see edu.jas.structure.RingElem#signum() */ public int signum() { int s = re.signum(); if (s != 0) { return s; } s = im.signum(); if (s != 0) { return s; } s = jm.signum(); if (s != 0) { return s; } return km.signum(); } /* arithmetic operations: +, -, - */ /** * BigQuaternion summation. * @param B BigQuaternion. * @return this+B. */ public BigQuaternion sum(BigQuaternion B) { return new BigQuaternion(ring, re.sum(B.re), im.sum(B.im), jm.sum(B.jm), km.sum(B.km)); } /** * Quaternion number sum. * @param A BigQuaternion. * @param B BigQuaternion. * @return A+B. */ public static BigQuaternion QSUM(BigQuaternion A, BigQuaternion B) { if (A == null) return null; return A.sum(B); } /** * Quaternion number difference. * @param A BigQuaternion. * @param B BigQuaternion. * @return A-B. */ public static BigQuaternion QDIF(BigQuaternion A, BigQuaternion B) { if (A == null) return null; return A.subtract(B); } /** * BigQuaternion subtraction. * @param B BigQuaternion. * @return this-B. */ public BigQuaternion subtract(BigQuaternion B) { return new BigQuaternion(ring, re.subtract(B.re), im.subtract(B.im), jm.subtract(B.jm), km.subtract(B.km)); } /** * Quaternion number negative. * @param A is a quaternion number * @return -A. */ public static BigQuaternion QNEG(BigQuaternion A) { if (A == null) return null; return A.negate(); } /** * BigQuaternion number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigQuaternion negate() { return new BigQuaternion(ring, re.negate(), im.negate(), jm.negate(), km.negate()); } /** * Quaternion number conjugate. * @param A is a quaternion number. * @return the quaternion conjugate of A. */ public static BigQuaternion QCON(BigQuaternion A) { if (A == null) return null; return A.conjugate(); } /* arithmetic operations: conjugate, absolute value */ /** * BigQuaternion conjugate. * @return conjugate(this). */ public BigQuaternion conjugate() { return new BigQuaternion(ring, re, im.negate(), jm.negate(), km.negate()); } /** * Quaternion number norm. * @see edu.jas.structure.StarRingElem#norm() * @return ||this||. */ public BigQuaternion norm() { // this.multiply(this.conjugate()); BigRational v = re.multiply(re); v = v.sum(im.multiply(im)); v = v.sum(jm.multiply(jm)); v = v.sum(km.multiply(km)); return new BigQuaternion(ring, v); } /** * Quaternion number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|. */ public BigQuaternion abs() { BigQuaternion n = norm(); BigRational r = Roots.sqrt(n.re); //logger.error("abs() square root missing"); return new BigQuaternion(ring, r); } /** * Quaternion number absolute value. * @param A is a quaternion number. * @return the absolute value of A, a rational number. Note: The square root * is not jet implemented. */ public static BigRational QABS(BigQuaternion A) { if (A == null) return null; return A.abs().re; } /** * Quaternion number product. * @param A BigQuaternion. * @param B BigQuaternion. * @return A*B. */ public static BigQuaternion QPROD(BigQuaternion A, BigQuaternion B) { if (A == null) return null; return A.multiply(B); } /* arithmetic operations: *, inverse, / */ /** * BigQuaternion multiply with BigRational. * @param b BigRational. * @return this*b. */ public BigQuaternion multiply(BigRational b) { BigRational r = re.multiply(b); BigRational i = im.multiply(b); BigRational j = jm.multiply(b); BigRational k = km.multiply(b); return new BigQuaternion(ring, r, i, j, k); } /** * BigQuaternion multiply. * @param B BigQuaternion. * @return this*B. */ public BigQuaternion multiply(BigQuaternion B) { BigRational r = re.multiply(B.re); r = r.subtract(im.multiply(B.im)); r = r.subtract(jm.multiply(B.jm)); r = r.subtract(km.multiply(B.km)); BigRational i = re.multiply(B.im); i = i.sum(im.multiply(B.re)); i = i.sum(jm.multiply(B.km)); i = i.subtract(km.multiply(B.jm)); BigRational j = re.multiply(B.jm); j = j.subtract(im.multiply(B.km)); j = j.sum(jm.multiply(B.re)); j = j.sum(km.multiply(B.im)); BigRational k = re.multiply(B.km); k = k.sum(im.multiply(B.jm)); k = k.subtract(jm.multiply(B.im)); k = k.sum(km.multiply(B.re)); return new BigQuaternion(ring, r, i, j, k); } /** * BigQuaternion multiply left. * @param B BigQuaternion. * @return B*this. */ public BigQuaternion multiplyLeft(BigQuaternion B) { return B.multiply(this); } /** * Quaternion number inverse. * @param A is a non-zero quaternion number. * @return S with S * A = A * S = 1. */ public static BigQuaternion QINV(BigQuaternion A) { if (A == null) return null; return A.inverse(); } /** * BigQuaternion inverse. * @return S with S * this = this * S = 1. * @see edu.jas.structure.RingElem#inverse() */ public BigQuaternion inverse() { BigRational a = norm().re.inverse(); return new BigQuaternion(ring, re.multiply(a), im.negate().multiply(a), jm.negate().multiply(a), km.negate().multiply(a)); } /** * BigQuaternion right remainder. * @param S BigQuaternion. * @return 0. */ public BigQuaternion rightRemainder(BigQuaternion S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } if (ring.integral) { //System.out.println( // "*** entier right remainder(" + this + ", " + S + "): " + ring + " ***"); BigQuaternionInteger c = new BigQuaternionInteger(ring, this); BigQuaternionInteger d = new BigQuaternionInteger(ring, S); return c.rightRemainder(d); } return ring.getZERO(); } /** * BigQuaternion (right) remainder. * @param S BigQuaternion. * @return 0. */ public BigQuaternion remainder(BigQuaternion S) { return rightRemainder(S); } /** * BigQuaternion left remainder. * @param S BigQuaternion. * @return 0. */ public BigQuaternion leftRemainder(BigQuaternion S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } if (ring.integral) { //System.out.println( // "*** entier right remainder(" + this + ", " + S + "): " + ring + " ***"); BigQuaternionInteger c = new BigQuaternionInteger(ring, this); BigQuaternionInteger d = new BigQuaternionInteger(ring, S); return c.leftRemainder(d); } return ring.getZERO(); } /** * Quaternion number quotient. * @param A BigQuaternion. * @param B BigQuaternion. * @return R/S. */ public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) { if (A == null) return null; return A.divide(B); } /** * BigQuaternion right divide. * @param b BigQuaternion. * @return this * b**(-1). */ public BigQuaternion divide(BigQuaternion b) { return rightDivide(b); } /** * BigQuaternion right divide. * @param b BigQuaternion. * @return q = this * b**(-1), such that q * b = this. */ @Override public BigQuaternion rightDivide(BigQuaternion b) { if (ring.integral) { //System.out.println("*** entier right divide(" + this + ", " + b + "): " + ring + " ***"); BigQuaternionInteger c = new BigQuaternionInteger(ring, this); BigQuaternionInteger d = new BigQuaternionInteger(ring, b); return c.rightDivide(d); } return this.multiply(b.inverse()); } /** * BigQuaternion left divide. * @param b BigQuaternion. * @return q = b**(-1) * this, such that b * q = this. */ @Override public BigQuaternion leftDivide(BigQuaternion b) { if (ring.integral) { //System.out.println("*** entier left divide(" + this + ", " + b + "): " + ring + " ***"); BigQuaternionInteger c = new BigQuaternionInteger(ring, this); BigQuaternionInteger d = new BigQuaternionInteger(ring, b); return c.leftDivide(d); } return b.inverse().multiply(this); } /** * BigQuaternion divide. * @param b BigRational. * @return this/b. */ public BigQuaternion divide(BigRational b) { BigRational bi = b.inverse(); return new BigQuaternion(ring, re.multiply(bi), im.multiply(bi), jm.multiply(bi), km.multiply(bi)); } /** * Quotient and remainder by division of this by S. * @param S a quaternion number * @return [this*S**(-1), this - (this*S**(-1))*S]. */ public BigQuaternion[] quotientRemainder(BigQuaternion S) { if (ring.integral) { //System.out.println( // "*** entier left quotient remainder(" + this + ", " + S + "): " + ring + " ***"); BigQuaternionInteger c = new BigQuaternionInteger(ring, this); BigQuaternionInteger d = new BigQuaternionInteger(ring, S); return c.rightQuotientAndRemainder(d); } return new BigQuaternion[] { divide(S), ring.getZERO() }; } /** * Quaternion number greatest common divisor. * @param S BigQuaternion. * @return gcd(this,S). */ public BigQuaternion gcd(BigQuaternion S) { return leftGcd(S); } /** * Quaternion number greatest common divisor. * @param S BigQuaternion. * @return leftCcd(this,S). */ public BigQuaternion leftGcd(BigQuaternion S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.integral) { //System.out.println("*** entier left gcd(" + this + ", " + S + "): " + ring + " ***"); BigQuaternionInteger a = new BigQuaternionInteger(ring, this); BigQuaternionInteger b = new BigQuaternionInteger(ring, S); return a.leftGcd(b); } return ring.getONE(); } /** * Quaternion number greatest common divisor. * @param S BigQuaternion. * @return rightCcd(this,S). */ public BigQuaternion rightGcd(BigQuaternion S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.integral) { //System.out.println("*** entier right gcd(" + this + ", " + S + "): " + ring + " ***"); BigQuaternionInteger a = new BigQuaternionInteger(ring, this); BigQuaternionInteger b = new BigQuaternionInteger(ring, S); return a.rightGcd(b); } return ring.getONE(); } /** * BigQuaternion extended greatest common divisor. * @param S BigQuaternion. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigQuaternion[] egcd(BigQuaternion S) { if (ring.integral) { System.out.println("*** entier egcd case not implemented ***"); } BigQuaternion[] ret = new BigQuaternion[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2)); ret[0] = ring.getONE(); ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } /** * Returns the number of bits in the representation of this BigQuaternion, * including a sign bit. It is equivalent to * {@code re.bitLength()+im.bitLength()+jm.bitLength()+km.bitLength()}.) * @return number of bits in the representation of this BigQuaternion, * including a sign bit. */ public long bitLength() { return re.bitLength() + im.bitLength() + jm.bitLength() + km.bitLength(); } /** * BigQuaternion ceiling, component wise. * @return ceiling of this. */ public BigQuaternion ceil() { BigRational r = new BigRational(re.ceil()); BigRational i = new BigRational(im.ceil()); BigRational j = new BigRational(jm.ceil()); BigRational k = new BigRational(km.ceil()); return new BigQuaternion(ring, r, i, j, k); } /** * BigQuaternion floor, component wise. * @return floor of this. */ public BigQuaternion floor() { BigRational r = new BigRational(re.floor()); BigRational i = new BigRational(im.floor()); BigRational j = new BigRational(jm.floor()); BigRational k = new BigRational(km.floor()); return new BigQuaternion(ring, r, i, j, k); } /** * BigQuaternion round to next Lipschitz integer. BigQuaternion with all * integer components. * @return Lipschitz integer of this. */ public BigQuaternionInteger roundToLipschitzian() { BigRational half = BigRational.HALF; BigRational r = new BigRational(re.sum(half).floor()); BigRational i = new BigRational(im.sum(half).floor()); BigRational j = new BigRational(jm.sum(half).floor()); BigRational k = new BigRational(km.sum(half).floor()); return new BigQuaternionInteger(ring, r, i, j, k); } /** * BigQuaternion round to next Hurwitz integer. BigQuaternion with all * integer or all 1/2 times integer components. * @return Hurwitz integer near this. */ public BigQuaternionInteger roundToHurwitzian() { if (isEntier()) { //System.out.println("*** short cut to round ***"); return new BigQuaternionInteger(ring, this); } BigQuaternionInteger g = this.roundToLipschitzian(); BigQuaternion d = ring.getZERO(); //BigRational half = BigRational.HALF; BigQuaternion s = this.subtract(g).norm(); //System.out.println("s = " + s.toScript()); //if (s.re.compareTo(half) < 0) { // wrong List units = ring.unitsOfHurwitzian(); BigQuaternion t = null; for (BigQuaternion ue : units) { //t = this.subtract(g).sum(ue).norm(); // bug t = this.subtract(g.sum(ue)).norm(); if (t.re.compareTo(s.re) < 0) { s = t; d = ue; } } //System.out.println("ring = " + ring); g = new BigQuaternionInteger(ring, g.sum(d)); return g; } } java-algebra-system-2.7.200/src/edu/jas/arith/BigQuaternionInteger.java000066400000000000000000000302101445075545500257120ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * Integer BigQuaternion class based on BigRational implementing the RingElem * interface and with the familiar MAS static method names. Objects of this * class are immutable. The integer quaternion methods are implemented after * https://de.wikipedia.org/wiki/Hurwitzquaternion see also * https://en.wikipedia.org/wiki/Hurwitz_quaternion * @author Heinz Kredel */ public final class BigQuaternionInteger extends BigQuaternion // implements StarRingElem, GcdRingElem { private static final Logger logger = LogManager.getLogger(BigQuaternionInteger.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. * @param j BigRational. * @param k BigRational. */ public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j, BigRational k) { super(fac, r, i, j, k); } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. * @param j BigRational. */ public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i, BigRational j) { this(fac, r, i, j, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. * @param i BigRational. */ public BigQuaternionInteger(BigQuaternionRing fac, BigRational r, BigRational i) { this(fac, r, i, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigRationals. * @param fac BigQuaternionRing. * @param r BigRational. */ public BigQuaternionInteger(BigQuaternionRing fac, BigRational r) { this(fac, r, BigRational.ZERO); } /** * Constructor for a BigQuaternion from BigComplex. * @param fac BigQuaternionRing. * @param r BigComplex. */ public BigQuaternionInteger(BigQuaternionRing fac, BigComplex r) { this(fac, r.re, r.im); } /** * Constructor for a BigQuaternionInteger from BigQuaternion. * @param fac BigQuaternionRing. * @param q BigQuaternion. */ public BigQuaternionInteger(BigQuaternionRing fac, BigQuaternion q) { this(fac, q.re, q.im, q.jm, q.km); } /** * Constructor for a BigQuaternion from long. * @param fac BigQuaternionRing. * @param r long. */ public BigQuaternionInteger(BigQuaternionRing fac, long r) { this(fac, new BigRational(r), BigRational.ZERO); } /** * Constructor for a BigQuaternion with no arguments. * @param fac BigQuaternionRing. */ public BigQuaternionInteger(BigQuaternionRing fac) { this(fac, BigRational.ZERO); } /** * The BigQuaternion string constructor accepts the following formats: empty * string, "rational", or "rat i rat j rat k rat" with no blanks around i, j * or k if used as polynoial coefficient. * @param fac BigQuaternionRing. * @param s String. * @throws NumberFormatException */ public BigQuaternionInteger(BigQuaternionRing fac, String s) throws NumberFormatException { super(fac, s); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public BigQuaternionRing factory() { return ring; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigQuaternionInteger copy() { return new BigQuaternionInteger(ring, re, im, jm, km); } /* arithmetic operations: +, -, - */ /* arithmetic operations: *, inverse, / */ /** * Quaternion number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|**2. Note: returns the norm(this). */ public BigQuaternion abs() { BigQuaternion n = norm(); //BigRational r = Roots.sqrt(n.re); logger.error("abs() square root missing"); return n; } /** * Quaternion number inverse. * @param A is a non-zero quaternion number. * @return S with S * A = A * S = 1. */ public static BigQuaternion QINV(BigQuaternion A) { if (A == null) return null; return A.inverse(); } /** * BigQuaternion inverse. * @return S with S * this = this * S = 1. * @see edu.jas.structure.RingElem#inverse() */ @Override public BigQuaternion inverse() { if (!isUnit()) { logger.info("ring = {}", ring); throw new ArithmeticException("not invertible: " + this); } return super.inverse(); } /** * BigQuaternion remainder. * @param S BigQuaternion. * @return this - this * b**(-1). */ @Override public BigQuaternion remainder(BigQuaternion S) { return rightRemainder(S); } /** * Quaternion number quotient. * @param A BigQuaternion. * @param B BigQuaternion. * @return R * B**(-1). */ public static BigQuaternion QQ(BigQuaternion A, BigQuaternion B) { if (A == null) return null; return A.divide(B); } /** * BigQuaternion right divide. * @param b BigQuaternion. * @return this * b**(-1). */ @Override public BigQuaternion divide(BigQuaternion b) { return rightDivide(b); } /** * BigQuaternion right divide. * @param b BigQuaternion. * @return this * b**(-1). */ @Override public BigQuaternion rightDivide(BigQuaternion b) { return rightQuotientAndRemainder(b)[0]; } /** * BigQuaternion left divide. * @param b BigQuaternion. * @return b**(-1) * this. */ @Override public BigQuaternion leftDivide(BigQuaternion b) { return leftQuotientAndRemainder(b)[0]; } /** * BigQuaternion divide. * @param b BigRational. * @return this/b. */ @Override public BigQuaternion divide(BigRational b) { BigQuaternion d = super.divide(b); if (!d.isEntier()) { throw new ArithmeticException("not divisible: " + this + " / " + b); } return d; } /** * Quotient and remainder by division of this by S. * @param S a quaternion number * @return [this*S**(-1), this - (this*S**(-1))*S]. */ @Override public BigQuaternion[] quotientRemainder(BigQuaternion S) { return new BigQuaternion[] { divide(S), remainder(S) }; } /** * Quaternion number greatest common divisor. * @param S BigQuaternion. * @return gcd(this,S). */ @Override public BigQuaternion gcd(BigQuaternion S) { return rightGcd(S); } /** * BigQuaternion extended greatest common divisor. * @param S BigQuaternion. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @Override public BigQuaternion[] egcd(BigQuaternion S) { throw new UnsupportedOperationException("not implemented: egcd"); /* BigQuaternion[] ret = new BigQuaternion[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigQuaternion half = new BigQuaternion(ring, new BigRational(1, 2)); ret[0] = ring.getONE(); ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; */ } /** * Integral quotient and remainder by left division of this by S. This must * be also an integral (Hurwitz) quaternion number. * @param b an integral (Hurwitz) quaternion number * @return [round(b**(-1)) this, this - b * (round(b**(-1)) this)]. */ public BigQuaternion[] leftQuotientAndRemainder(BigQuaternion b) { //System.out.println("left QR = " + this + ", " + b); if (!this.isEntier() || !b.isEntier()) { throw new IllegalArgumentException("entier elements required"); } BigQuaternion bi = b.inverse(); BigQuaternion m = bi.multiply(this); // left divide //System.out.println("m = " + m.toScript()); BigQuaternionInteger mh = m.roundToHurwitzian(); //System.out.println("mh = " + mh.toScript()); BigQuaternion n = this.subtract(b.multiply(mh)); BigQuaternion[] ret = new BigQuaternion[2]; ret[0] = mh; ret[1] = n; return ret; } /** * Integral quotient and remainder by right division of this by S. This must * be also an integral (Hurwitz) quaternion number. * @param b an integral (Hurwitz) quaternion number * @return [this round(b**(-1)), this - this (round(b**(-1)) b)]. */ public BigQuaternion[] rightQuotientAndRemainder(BigQuaternion b) { //System.out.println("right QR = " + this + ", " + b); if (!this.isEntier() || !b.isEntier()) { throw new IllegalArgumentException("entier elements required"); } BigQuaternion bi = b.inverse(); BigQuaternion m = this.multiply(bi); // right divide //System.out.println("m = " + m.toScript()); BigQuaternionInteger mh = m.roundToHurwitzian(); //System.out.println("mh = " + mh.toScript()); BigQuaternion n = this.subtract(mh.multiply(b)); BigQuaternion[] ret = new BigQuaternion[2]; ret[0] = mh; ret[1] = n; return ret; } /** * Left remainder. * @param a element. * @return r = this - (a/left) * a, where left * a = this. */ @Override public BigQuaternion leftRemainder(BigQuaternion a) { return leftQuotientAndRemainder(a)[1]; } /** * Right remainder. * @param a element. * @return r = this - a * (a/right), where a * right = this. */ @Override public BigQuaternion rightRemainder(BigQuaternion a) { return rightQuotientAndRemainder(a)[1]; } /** * Integer quaternion number left greatest common divisor. * @param S integer BigQuaternion. * @return leftGcd(this,S). */ @Override public BigQuaternion leftGcd(BigQuaternion S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } BigQuaternionInteger q; BigQuaternion r; q = this; r = S; while (!r.isZERO()) { BigQuaternion u = q.leftQuotientAndRemainder(r)[1]; //System.out.println("u = " + u.toScript()); q = new BigQuaternionInteger(ring, r); r = u; } return q; } /** * Integer quaternion number right greatest common divisor. * @param S integer BigQuaternion. * @return rightGcd(this,S). */ @Override public BigQuaternion rightGcd(BigQuaternion S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } BigQuaternionInteger q; BigQuaternion r; q = this; r = S; while (!r.isZERO()) { BigQuaternion u = q.rightQuotientAndRemainder(r)[1]; //System.out.println("u = " + u.toScript()); q = new BigQuaternionInteger(ring, r); r = u; } return q; } /** * Quaternion number test if it is a prime number. * @return isPrime(norm(this)) */ public boolean isPrime() { BigQuaternion n = norm(); BigRational r = n.re; java.math.BigInteger di = r.den; if (!di.equals(java.math.BigInteger.ONE)) { return false; } java.math.BigInteger ni = r.num; boolean p = PrimeInteger.isPrime(ni); return p; } } java-algebra-system-2.7.200/src/edu/jas/arith/BigQuaternionRing.java000066400000000000000000000224631445075545500252270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; // import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.StringUtil; import edu.jas.kern.Scripting; import edu.jas.structure.RingFactory; /** * BigQuaternion ring class based on BigRational implementing the RingElem * interface. * @author Heinz Kredel */ public final class BigQuaternionRing implements RingFactory { /** * List of all 24 integral units. */ static List entierUnits = null; //later: unitsOfHurwitzian(); /** * Flag to signal if this ring is integral. */ protected boolean integral = false; protected final static Random random = new Random(); private static final Logger logger = LogManager.getLogger(BigQuaternionRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for a BigQuaternion ring. */ public BigQuaternionRing() { this(false); } /** * Constructor for a BigQuaternion ring. */ public BigQuaternionRing(boolean i) { integral = i; logger.info("integral = {}", integral); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(4); g.add(getONE()); g.add(I); g.add(J); g.add(K); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Copy BigQuaternion element c. * @param c BigQuaternion. * @return a copy of c. */ public BigQuaternion copy(BigQuaternion c) { return new BigQuaternion(this, c.re, c.im, c.jm, c.km); } /** * Get the zero element. * @return 0 as BigQuaternion. */ public BigQuaternion getZERO() { return ZERO; } /** * Get the one element. * @return q as BigQuaternion. */ public BigQuaternion getONE() { return ONE; } /** * Query if this ring is commutative. * @return false. */ public boolean isCommutative() { return false; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return !integral; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return java.math.BigInteger.ZERO; } /** * Get a BigQuaternion element from a BigInteger. * @param a BigInteger. * @return a BigQuaternion. */ public BigQuaternion fromInteger(java.math.BigInteger a) { return new BigQuaternion(this, new BigRational(a)); } /** * Get a BigQuaternion element from a long. * @param a long. * @return a BigQuaternion. */ public BigQuaternion fromInteger(long a) { return new BigQuaternion(this, new BigRational(a)); } /** * Get a BigQuaternion element from a long vector. * @param a long vector. * @return a BigQuaternion. */ public BigQuaternion fromInteger(long[] a) { return new BigQuaternion(this, new BigRational(a[0]), new BigRational(a[1]), new BigRational(a[2]), new BigRational(a[3])); } /** * The constant 0. */ public final BigQuaternion ZERO = new BigQuaternion(this); /** * The constant 1. */ public final BigQuaternion ONE = new BigQuaternion(this, BigRational.ONE); /** * The constant i. */ public final BigQuaternion I = new BigQuaternion(this, BigRational.ZERO, BigRational.ONE); /** * The constant j. */ public final BigQuaternion J = new BigQuaternion(this, BigRational.ZERO, BigRational.ZERO, BigRational.ONE); /** * The constant k. */ public final BigQuaternion K = new BigQuaternion(this, BigRational.ZERO, BigRational.ZERO, BigRational.ZERO, BigRational.ONE); /** * Get the string representation. Is compatible with the string constructor. * @see java.lang.Object#toString() */ @Override public String toString() { String s = "BigQuaternionRing(" + integral + ")"; return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer("Quat("); switch (Scripting.getLang()) { case Ruby: s.append((integral ? "true" : "" )); break; case Python: default: s.append((integral ? "True" : "" )); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigQuaternionRing)) { return false; } BigQuaternionRing B = (BigQuaternionRing) b; return this.integral == B.integral; } /** * Hash code for this BigQuaternionRing. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = 4711; return h; } /** * BigQuaternion units of the Hurwitzian integers. BigQuaternion units with * all integer or all 1/2 times integer components. * @return list of all 24 units. */ public List unitsOfHurwitzian() { if (entierUnits != null) { return entierUnits; } BigRational half = BigRational.HALF; // Lipschitz integer units List units = generators(); List u = new ArrayList(units); for (BigQuaternion ue : u) { units.add(ue.negate()); } // Hurwitz integer units long[][] comb = new long[][] { { 1, 1, 1, 1 }, { -1, 1, 1, 1 }, { 1, -1, 1, 1 }, { -1, -1, 1, 1 }, { 1, 1, -1, 1 }, { -1, 1, -1, 1 }, { 1, -1, -1, 1 }, { -1, -1, -1, 1 }, { 1, 1, 1, -1 }, { -1, 1, 1, -1 }, { 1, -1, 1, -1 }, { -1, -1, 1, -1 }, { 1, 1, -1, -1 }, { -1, 1, -1, -1 }, { 1, -1, -1, -1 }, { -1, -1, -1, -1 } }; for (long[] row : comb) { BigQuaternion ue = fromInteger(row); ue = ue.multiply(half); units.add(ue); } //System.out.println("units = " + units); //for (BigQuaternion ue : units) { //System.out.println("unit = " + ue + ", norm = " + ue.norm()); //} entierUnits = units; return units; } /** * BigQuaternion random. Random rational numbers A, B, C and D are generated * using random(n). Then R is the quaternion number with real part A and * imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @return R, a random BigQuaternion. */ public BigQuaternion random(int n) { return random(n, random); } /** * BigQuaternion random. Random rational numbers A, B, C and D are generated * using RNRAND(n). Then R is the quaternion number with real part A and * imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @param rnd is a source for random bits. * @return R, a random BigQuaternion. */ public BigQuaternion random(int n, Random rnd) { BigRational r = BigRational.ONE.random(n, rnd); BigRational i = BigRational.ONE.random(n, rnd); BigRational j = BigRational.ONE.random(n, rnd); BigRational k = BigRational.ONE.random(n, rnd); BigQuaternion q = new BigQuaternion(this, r, i, j, k); if (integral) { q = q.roundToHurwitzian(); } return q; } /* * Quaternion number, random. Random rational numbers A, B, C and D are * generated using RNRAND(n). Then R is the quaternion number with real part * A and imaginary parts B, C and D. * @param n such that 0 ≤ A, B, C, D ≤ (2n-1). * @return R, a random BigQuaternion. public static BigQuaternion QRAND(int n) { return ONE.random(n, random); } */ /** * Parse quaternion number from String. * @param s String. * @return BigQuaternion from s. */ public BigQuaternion parse(String s) { return new BigQuaternion(this, s); } /** * Parse quaternion number from Reader. * @param r Reader. * @return next BigQuaternion from r. */ public BigQuaternion parse(Reader r) { return parse(StringUtil.nextString(r)); } } java-algebra-system-2.7.200/src/edu/jas/arith/BigRational.java000066400000000000000000001071611445075545500240320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.math.BigInteger; import java.math.MathContext; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.Set; import edu.jas.kern.Scripting; import edu.jas.kern.StringUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Immutable arbitrary-precision rational numbers. BigRational class based on * BigInteger and implementing the RingElem interface. BigInteger is from * java.math in the implementation. The SAC2 static methods are also provided. * @author Heinz Kredel */ public final class BigRational implements GcdRingElem, RingFactory, Rational, Iterable { /** * Numerator part of the data structure. */ public final BigInteger num; /** * Denominator part of the data structure. */ public final BigInteger den; /** * The Constant 0. */ public final static BigRational ZERO = new BigRational(BigInteger.ZERO); /** * The Constant 1. */ public final static BigRational ONE = new BigRational(BigInteger.ONE); /** * The Constant 1/2. */ public final static BigRational HALF = new BigRational(1, 2); private final static Random random = new Random(); /** * Constructor for a BigRational from math.BigIntegers. * @param n math.BigInteger. * @param d math.BigInteger. */ protected BigRational(BigInteger n, BigInteger d) { // assert gcd(n,d) == 1 num = n; den = d; } /** * Constructor for a BigRational from math.BigIntegers. * @param n math.BigInteger. */ public BigRational(BigInteger n) { num = n; den = BigInteger.ONE; // be aware of static initialization order } /** * Constructor for a BigRational from jas.arith.BigIntegers. * @param n edu.jas.arith.BigInteger. */ public BigRational(edu.jas.arith.BigInteger n) { this(n.getVal()); } /** * Constructor for a BigRational from jas.arith.BigIntegers. * @param n edu.jas.arith.BigInteger. * @param d edu.jas.arith.BigInteger. */ public BigRational(edu.jas.arith.BigInteger n, edu.jas.arith.BigInteger d) { BigInteger nu = n.getVal(); BigInteger de = d.getVal(); BigRational r = RNRED(nu, de); num = r.num; den = r.den; } /** * Constructor for a BigRational from longs. * @param n long. * @param d long. */ public BigRational(long n, long d) { BigInteger nu = BigInteger.valueOf(n); BigInteger de = BigInteger.valueOf(d); BigRational r = RNRED(nu, de); num = r.num; den = r.den; } /** * Constructor for a BigRational from longs. * @param n long. */ public BigRational(long n) { num = BigInteger.valueOf(n); den = BigInteger.ONE; } /** * Constructor for a BigRational with no arguments. */ public BigRational() { num = BigInteger.ZERO; den = BigInteger.ONE; } /** * Constructor for a BigRational from String. * @param s String. * @throws NumberFormatException */ public BigRational(String s) throws NumberFormatException { if (s == null) { num = BigInteger.ZERO; den = BigInteger.ONE; return; } if (s.length() == 0) { num = BigInteger.ZERO; den = BigInteger.ONE; return; } BigInteger n; BigInteger d; s = s.trim(); int i = s.indexOf('/'); if (i < 0) { i = s.indexOf('.'); if (i < 0) { num = new BigInteger(s); den = BigInteger.ONE; return; } if (s.charAt(0) == '-') { // case -0.11111 n = new BigInteger(s.substring(1, i)); } else { n = new BigInteger(s.substring(0, i)); } BigRational r = new BigRational(n); d = new BigInteger(s.substring(i + 1, s.length())); int j = s.length() - i - 1; //System.out.println("j = " + j); //System.out.println("n = " + n); //System.out.println("d = " + d); BigRational z = new BigRational(1, 10); z = z.power(j); //Power. positivePower(z, j); BigRational f = new BigRational(d); f = f.multiply(z); r = r.sum(f); if (s.charAt(0) == '-') { num = r.num.negate(); } else { num = r.num; } den = r.den; } else { String sn = s.substring(0, i); String sd = s.substring(i + 1, s.length()); BigRational r; if (s.indexOf(".") < 0) { // all integers n = new BigInteger(sn); d = new BigInteger(sd); r = RNRED(n, d); } else { // integers or decimal fractions BigRational rn = new BigRational(sn); BigRational rd = new BigRational(sd); r = rn.divide(rd); } num = r.num; den = r.den; return; } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public BigRational factory() { return this; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public BigRational copy() { return new BigRational(num, den); } /** * Copy BigRational element c. * @param c BigRational. * @return a copy of c. */ public BigRational copy(BigRational c) { return new BigRational(c.num, c.den); } /** * Return a BigRational approximation of this Element. * @return a BigRational approximation of this. * @see edu.jas.arith.Rational#getRational() */ public BigRational getRational() { return this; } /** * Get the numerator. * @return num. */ public BigInteger numerator() { return num; } /** * Get the denominator. * @return den. */ public BigInteger denominator() { return den; } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { if (Scripting.getPrecision() >= 0) { return toString(Scripting.getPrecision()); } StringBuffer s = new StringBuffer(); s.append(num); if (!den.equals(BigInteger.ONE)) { s.append("/").append(den); } return s.toString(); } /** * Get the decimal string representation with given precision. * @param n precision. * @return decimal approximation. */ public String toString(int n) { if (n < 0) { return toString(); } java.math.MathContext mc = new java.math.MathContext(n); BigDecimal d = new BigDecimal(this, mc); return d.toString(); } /** * Get the decimal representation. * @return decimal. */ public BigDecimal getDecimal() { BigDecimal d = new BigDecimal(this); return d; } /** * Get this as a double. * @return this as a double * @see java.lang.Number#doubleValue() */ public double doubleValue() { BigDecimal d = new BigDecimal(this, MathContext.DECIMAL64); return d.doubleValue(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case: (num,den) or num // Ruby case: num/den or num StringBuffer s = new StringBuffer(); if (den.equals(BigInteger.ONE)) { s.append(num.toString()); return s.toString(); } if (Scripting.getPrecision() >= 0) { return toString(Scripting.getPrecision()); } switch (Scripting.getLang()) { case Python: s.append("("); s.append(num.toString()); s.append(","); s.append(den.toString()); s.append(")"); break; case Ruby: default: s.append(num.toString()); s.append("/"); s.append(den.toString()); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python and Ruby case return "QQ()"; } /** * Get the zero element. * @return 0 as BigRational. */ public BigRational getZERO() { return ZERO; } /** * Get the one element. * @return 1 as BigRational. */ public BigRational getONE() { return ONE; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return BigInteger.ZERO; } /** * Get a BigRational element from a math.BigInteger. * @param a math.BigInteger. * @return BigRational from a. */ public BigRational fromInteger(BigInteger a) { return new BigRational(a); } /** * Get a BigRational element from a arith.BigInteger. * @param a arith.BigInteger. * @return BigRational from a. */ public BigRational fromInteger(edu.jas.arith.BigInteger a) { return new BigRational(a); } /** * Get a BigRational element from a math.BigInteger. * @param a math.BigInteger. * @return BigRational from a. */ public static BigRational valueOf(BigInteger a) { return new BigRational(a); } /** * Get a BigRational element from a long. * @param a long. * @return BigRational from a. */ public BigRational fromInteger(long a) { return new BigRational(a); } /** * Get a BigRational element from a long. * @param a long. * @return BigRational from a. */ public static BigRational valueOf(long a) { return new BigRational(a); } /** * Is BigRational zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.signum() == 0; //equals(BigInteger.ZERO); } /** * Is BigRational one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.equals(den); } /** * Is BigRational unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return !isZERO(); } /** * Is BigRational entier. * @return If this is an integer then true is returned, else false. */ public boolean isEntier() { return isZERO() || den.equals(BigInteger.ONE); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof BigRational)) { return false; } BigRational br = (BigRational) b; return num.equals(br.num) && den.equals(br.den); } /** * Hash code for this BigRational. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * num.hashCode() + den.hashCode(); } /** * Rational number reduction to lowest terms. * @param n BigInteger. * @param d BigInteger. * @return a/b ~ n/d, gcd(a,b) = 1, b > 0. */ public static BigRational RNRED(BigInteger n, BigInteger d) { BigInteger num; BigInteger den; if (d.equals(BigInteger.ZERO)) { throw new RuntimeException("rational number denominator is zero"); } if (n.equals(BigInteger.ZERO)) { num = n; den = BigInteger.ONE; return new BigRational(num, den); } if (n.equals(d)) { num = BigInteger.ONE; den = BigInteger.ONE; return new BigRational(num, den); } BigInteger c = n.gcd(d); if (c.equals(BigInteger.ONE)) { num = n; den = d; } else { num = n.divide(c); den = d.divide(c); } if (den.signum() < 0) { num = num.negate(); den = den.negate(); } return new BigRational(num, den); } /** * Rational number reduction to lowest terms. * @param n BigInteger. * @param d BigInteger. * @return a/b ~ n/d, gcd(a,b) = 1, b > 0. */ public static BigRational reduction(BigInteger n, BigInteger d) { return RNRED(n, d); } /** * Rational number absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public BigRational abs() { if (this.signum() >= 0) { return this; } return this.negate(); } /** * Rational number absolute value. * @param R is a rational number. * @return the absolute value of R. */ public static BigRational RNABS(BigRational R) { if (R == null) return null; return R.abs(); } /** * Rational number comparison. * @param S BigRational. * @return SIGN(this-S). */ @Override public int compareTo(BigRational S) { BigInteger J2Y; BigInteger J3Y; BigInteger R1; BigInteger R2; BigInteger S1; BigInteger S2; int J1Y; int SL; int TL; int RL; if (this.equals(ZERO)) { return -S.signum(); } if (S.equals(ZERO)) { return this.signum(); } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; RL = R1.signum(); SL = S1.signum(); J1Y = (RL - SL); TL = (J1Y / 2); if (TL != 0) { return TL; } J3Y = R1.multiply(S2); J2Y = R2.multiply(S1); TL = J3Y.compareTo(J2Y); return TL; } /** * Rational number comparison. * @param R BigRational. * @param S BigRational. * @return SIGN(R-S). */ public static int RNCOMP(BigRational R, BigRational S) { if (R == null) return Integer.MAX_VALUE; return R.compareTo(S); } /** * Rational number denominator. * @param R BigRational. * @return R.denominator(). */ public static BigInteger RNDEN(BigRational R) { if (R == null) return null; return R.den; } /** * Rational number difference. * @param S BigRational. * @return this-S. */ public BigRational subtract(BigRational S) { return this.sum(S.negate()); } /** * Rational number difference. * @param R BigRational. * @param S BigRational. * @return R-S. */ public static BigRational RNDIF(BigRational R, BigRational S) { if (R == null) return S.negate(); return R.subtract(S); } /** * Rational number decimal write. R is a rational number. n is a * non-negative integer. R is approximated by a decimal fraction D with n * decimal digits following the decimal point and D is written in the output * stream. The inaccuracy of the approximation is at most (1/2)*10**-n. * @param R * @param NL */ // If ABS(D) is greater than ABS(R) then the last digit is // followed by a minus sign, if ABS(D) is less than ABS(R) then by a // plus sign. public static void RNDWR(BigRational R, int NL) { //BigInteger num = R.num; //BigInteger den = R.den; java.math.MathContext mc = new java.math.MathContext(NL); BigDecimal d = new BigDecimal(R, mc); System.out.print(d.toString()); return; } /** * Rational number from integer. * @param A BigInteger. * @return A/1. */ public static BigRational RNINT(BigInteger A) { return new BigRational(A); } /** * Rational number inverse. * @return 1/this. * @see edu.jas.structure.RingElem#inverse() */ public BigRational inverse() { BigInteger R1 = num; BigInteger R2 = den; BigInteger S1; BigInteger S2; if (R1.signum() >= 0) { S1 = R2; S2 = R1; } else { S1 = R2.negate(); S2 = R1.negate(); } return new BigRational(S1, S2); } /** * Rational number inverse. * @param R BigRational. * @return 1/R. */ public static BigRational RNINV(BigRational R) { if (R == null) return null; return R.inverse(); } /** * Rational number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public BigRational negate() { BigInteger n = num.negate(); return new BigRational(n, den); } /** * Rational number negative. * @param R BigRational. * @return -R. */ public static BigRational RNNEG(BigRational R) { if (R == null) return null; return R.negate(); } /** * Rational number numerator. * @param R BigRational. * @return R.numerator(). */ public static BigInteger RNNUM(BigRational R) { if (R == null) return null; return R.num; } /** * Rational number product. * @param S BigRational. * @return this*S. */ public BigRational multiply(BigRational S) { BigInteger D1 = null; BigInteger D2 = null; BigInteger R1 = null; BigInteger R2 = null; BigInteger RB1 = null; BigInteger RB2 = null; BigInteger S1 = null; BigInteger S2 = null; BigInteger SB1 = null; BigInteger SB2 = null; BigRational T; BigInteger T1; BigInteger T2; if (this.equals(ZERO) || S.equals(ZERO)) { T = ZERO; return T; } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; if (R2.equals(BigInteger.ONE) && S2.equals(BigInteger.ONE)) { T1 = R1.multiply(S1); T = new BigRational(T1, BigInteger.ONE); return T; } if (R2.equals(BigInteger.ONE)) { if (R1.equals(S2)) { D1 = R1; } else { D1 = R1.gcd(S2); } RB1 = R1.divide(D1); SB2 = S2.divide(D1); T1 = RB1.multiply(S1); T = new BigRational(T1, SB2); return T; } if (S2.equals(BigInteger.ONE)) { if (S1.equals(R2)) { D2 = S1; } else { D2 = S1.gcd(R2); } SB1 = S1.divide(D2); RB2 = R2.divide(D2); T1 = SB1.multiply(R1); T = new BigRational(T1, RB2); return T; } if (R1.equals(S2)) { D1 = R1; } else { D1 = R1.gcd(S2); } RB1 = R1.divide(D1); SB2 = S2.divide(D1); if (S1.equals(R2)) { D2 = S1; } else { D2 = S1.gcd(R2); } SB1 = S1.divide(D2); RB2 = R2.divide(D2); T1 = RB1.multiply(SB1); T2 = RB2.multiply(SB2); T = new BigRational(T1, T2); return T; } /** * Rational number product. * @param R BigRational. * @param S BigRational. * @return R*S. */ public static BigRational RNPROD(BigRational R, BigRational S) { if (R == null) { return R; } return R.multiply(S); } /** * Rational number quotient. * @param S BigRational. * @return this/S. */ public BigRational divide(BigRational S) { return multiply(S.inverse()); } /** * Rational number quotient. * @param R BigRational. * @param S BigRational. * @return R/S. */ public static BigRational RNQ(BigRational R, BigRational S) { if (R == null) { return R; } return R.divide(S); } /** * Rational number remainder. * @param S BigRational. * @return this-(this/S)*S */ public BigRational remainder(BigRational S) { if (S.isZERO()) { throw new ArithmeticException("division by zero"); } return ZERO; } /** * Quotient and remainder by division of this by S. * @param S a rational number * @return [this/S, this - (this/S)*S]. */ public BigRational[] quotientRemainder(BigRational S) { return new BigRational[] { divide(S), ZERO }; } /** * Rational number, random. Random integers A, B and a random sign s are * generated using BigInteger(n,random) and random.nextBoolen(). Then R = * s*A/(B+1), reduced to lowest terms. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return a random BigRational. */ public BigRational random(int n) { return random(n, random); } /** * Rational number, random. Random integers A, B and a random sign s are * generated using BigInteger(n,random) and random.nextBoolen(). Then R = * s*A/(B+1), reduced to lowest terms. * @param n such that 0 ≤ A, B ≤ (2n-1). * @param rnd is a source for random bits. * @return a random BigRational. */ public BigRational random(int n, Random rnd) { BigInteger A; BigInteger B; A = new BigInteger(n, rnd); // always positive if (rnd.nextBoolean()) { A = A.negate(); } B = new BigInteger(n, rnd); // always positive B = B.add(BigInteger.ONE); return RNRED(A, B); } /** * Rational number, random. Random integers A, B and a random sign s are * generated using BigInteger(n,random) and random.nextBoolen(). Then R = * s*A/(B+1), reduced to lowest terms. * @param NL such that 0 ≤ A, B ≤ (2n-1). * @return a random BigRational. */ public static BigRational RNRAND(int NL) { return ONE.random(NL, random); } /** * Rational number sign. * @see edu.jas.structure.RingElem#signum() */ public int signum() { return num.signum(); } /** * Rational number sign. * @param R BigRational. * @return R.signum(). */ public static int RNSIGN(BigRational R) { if (R == null) { return 0; } return R.signum(); } /** * Rational number sum. * @param S BigRational. * @return this+S. */ public BigRational sum(BigRational S) { BigInteger D = null; BigInteger E, J1Y, J2Y; BigRational T; BigInteger R1 = null; BigInteger R2 = null; BigInteger RB2 = null; BigInteger S1 = null; BigInteger S2 = null; BigInteger SB2 = null; BigInteger T1; BigInteger T2; if (this.equals(ZERO)) { return S; } if (S.equals(ZERO)) { return this; } R1 = num; //this.numerator(); R2 = den; //this.denominator(); S1 = S.num; S2 = S.den; if (R2.equals(BigInteger.ONE) && S2.equals(BigInteger.ONE)) { T1 = R1.add(S1); T = new BigRational(T1, BigInteger.ONE); return T; } if (R2.equals(BigInteger.ONE)) { T1 = R1.multiply(S2); T1 = T1.add(S1); T = new BigRational(T1, S2); return T; } if (S2.equals(BigInteger.ONE)) { T1 = R2.multiply(S1); T1 = T1.add(R1); T = new BigRational(T1, R2); return T; } if (R2.equals(S2)) { D = R2; } else { D = R2.gcd(S2); } if (D.equals(BigInteger.ONE)) { RB2 = R2; SB2 = S2; } else { RB2 = R2.divide(D); SB2 = S2.divide(D); } J1Y = R1.multiply(SB2); J2Y = RB2.multiply(S1); T1 = J1Y.add(J2Y); if (T1.equals(BigInteger.ZERO)) { return ZERO; } if (!D.equals(BigInteger.ONE)) { if (T1.equals(D)) { E = D; } else { E = T1.gcd(D); } if (!E.equals(BigInteger.ONE)) { T1 = T1.divide(E); R2 = R2.divide(E); } } T2 = R2.multiply(SB2); T = new BigRational(T1, T2); return T; } /** * Rational number sum. * @param R BigRational. * @param S BigRational. * @return R+S. */ public static BigRational RNSUM(BigRational R, BigRational S) { if (R == null) { return S; } return R.sum(S); } /** * Parse rational number from String. * @param s String. * @return BigRational from s. */ public BigRational parse(String s) { return new BigRational(s); } /** * Parse rational number from Reader. * @param r Reader. * @return next BigRational from r. */ public BigRational parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Rational number greatest common divisor. * @param S BigRational. * @return gcd(this,S). */ public BigRational gcd(BigRational S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } return ONE; } /** * BigRational extended greatest common divisor. * @param S BigRational. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public BigRational[] egcd(BigRational S) { BigRational[] ret = new BigRational[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } BigRational half = new BigRational(1, 2); ret[0] = ONE; ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } /** * BigRational ceiling. * @return ceiling of this. */ public BigInteger ceil() { if (isEntier()) { return num; } BigInteger[] qr = num.divideAndRemainder(den); //System.out.println("ceil: " + this + ", q = " + qr[0] + ", r = " +qr[1]); BigInteger q = qr[0]; if (qr[1].signum() > 0) { q = q.add(BigInteger.ONE); } return q; } /** * BigRational floor. * @return floor of this. */ public BigInteger floor() { if (isEntier()) { return num; } BigInteger[] qr = num.divideAndRemainder(den); //System.out.println("floor: " + this + ", q = " + qr[0] + ", r = " +qr[1]); BigInteger q = qr[0]; if (qr[1].signum() < 0) { q = q.subtract(BigInteger.ONE); } return q; } /** * Returns the number of bits in the representation of this BigRational, * including a sign bit. For positive BigRational, this is equivalent to * {@code num.bitLength()+den.bitLength()}.) * @return number of bits in the representation of this BigRational, * including a sign bit. */ public long bitLength() { long n = num.bitLength(); if (num.signum() < 0) { n++; } n++; n += den.bitLength(); // den.signum() > 0 n++; return n; } private boolean nonNegative = true; private boolean duplicates = true; /** * Set the iteration algorithm to all elements. */ public void setAllIterator() { nonNegative = false; } /** * Set the iteration algorithm to non-negative elements. */ public void setNonNegativeIterator() { nonNegative = true; } /** * Set the iteration algorithm to no duplicate elements. */ public void setNoDuplicatesIterator() { duplicates = false; } /** * Set the iteration algorithm to allow duplicate elements. */ public void setDuplicatesIterator() { duplicates = true; } /** * Get a BigRational iterator. * @return a iterator over all rationals. */ public Iterator iterator() { if (duplicates) { return new BigRationalIterator(nonNegative); } return new BigRationalUniqueIterator(new BigRationalIterator(nonNegative)); } /** * Get a BigRational iterator with no duplicates. * @return a iterator over all rationals without duplicates. */ public Iterator uniqueIterator() { return new BigRationalUniqueIterator(new BigRationalIterator(nonNegative)); } } /** * Big rational iterator. Uses Cantors diagonal enumeration. * @author Heinz Kredel */ class BigRationalIterator implements Iterator { /** * data structure. */ BigRational curr; edu.jas.arith.BigInteger den; edu.jas.arith.BigInteger num; Iterator denit; Iterator numit; List denlist; List numlist; Iterator denlistit; Iterator numlistit; final boolean nonNegative; protected long level; /** * BigRational iterator constructor. */ public BigRationalIterator() { this(false); } /** * BigRational iterator constructor. * @param nn indicator for a non-negative iterator, if true, false for an * all iterator */ public BigRationalIterator(boolean nn) { nonNegative = nn; curr = edu.jas.arith.BigRational.ZERO; level = 0; den = new edu.jas.arith.BigInteger(); // ZERO num = edu.jas.arith.BigInteger.ONE.copy(); if (nonNegative) { den.setNonNegativeIterator(); } else { den.setAllIterator(); } num.setNonNegativeIterator(); denit = den.iterator(); numit = num.iterator(); denlist = new ArrayList(); numlist = new ArrayList(); edu.jas.arith.BigInteger unused = denit.next(); // skip zero denominator unused = numit.next(); if (unused == null) { // use for findbugs System.out.println("unused is null"); } denlist.add(denit.next()); numlist.add(numit.next()); denlistit = denlist.iterator(); numlistit = numlist.iterator(); } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public boolean hasNext() { return true; } /** * Get next rational. * @return next rational. */ public synchronized BigRational next() { BigRational r = curr; if (denlistit.hasNext() && numlistit.hasNext()) { BigInteger d = denlistit.next().val; BigInteger n = numlistit.next().val; //System.out.println(d + "//" + n); curr = BigRational.reduction(d, n); return r; } level++; if (level % 2 == 1) { Collections.reverse(denlist); } else { Collections.reverse(numlist); } denlist.add(denit.next()); numlist.add(numit.next()); if (level % 2 == 0) { Collections.reverse(denlist); } else { Collections.reverse(numlist); } //System.out.println("denlist = " + denlist); //System.out.println("numlist = " + numlist); denlistit = denlist.iterator(); numlistit = numlist.iterator(); BigInteger d = denlistit.next().val; BigInteger n = numlistit.next().val; //System.out.println(d + "//" + n); curr = BigRational.reduction(d, n); return r; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } /** * Big rational unique iterator. Uses Cantors diagonal enumeration, produces * distinct elements. * @author Heinz Kredel */ class BigRationalUniqueIterator implements Iterator { /** * data structure. */ final Set unique; final Iterator ratit; /** * BigRational iterator constructor. */ public BigRationalUniqueIterator() { this(BigRational.ONE.iterator()); } /** * BigRational iterator constructor. * @param rit backing rational iterator of non unique elements */ public BigRationalUniqueIterator(Iterator rit) { ratit = rit; unique = new HashSet(); } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public synchronized boolean hasNext() { return ratit.hasNext(); } /** * Get next rational. * @return next rational. */ public synchronized BigRational next() { // TODO: use curr = BigRational.reduction(d, n); // with curr.d == d to avoid unique BigRational r = ratit.next(); while (unique.contains(r)) { //System.out.println("duplicate " + r); r = ratit.next(); } unique.add(r); return r; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/arith/Combinatoric.java000066400000000000000000000045631445075545500242520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; /** * Combinatoric algorithms. Similar to ALDES/SAC2 SACCOMB module. * @author Heinz Kredel */ public class Combinatoric { /** * Integer binomial coefficient induction. n and k are integers with 0 * less than or equal to k less than or equal to n. A is the binomial * coefficient n over k. B is the binomial coefficient n over k+1. * @param A previous induction result. * @param n long. * @param k long. * @return the binomial coefficient n over k+1. */ public static BigInteger binCoeffInduction(BigInteger A, long n, long k) { BigInteger kp, np; np = new BigInteger(n - k); kp = new BigInteger(k + 1); BigInteger B = A.multiply(np).divide(kp); return B; } /** * Integer binomial coefficient. n and k are integers with 0 less than * or equal to k less than or equal to n. A is the binomial coefficient n * over k. * @param n long. * @param k long. * @return the binomial coefficient n over k+1. */ public static BigInteger binCoeff(int n, int k) { BigInteger A = BigInteger.ONE; int kp = (k < n - k ? k : n - k); for (int j = 0; j < kp; j++) { A = binCoeffInduction(A, n, j); } return A; } /** * Integer binomial coefficient partial sum. n and k are integers, 0 le k le * n. A is the sum on i, from 0 to k, of the binomial coefficient n over i. * @param n long. * @param k long. * @return the binomial coefficient partial sum n over i. */ public static BigInteger binCoeffSum(int n, int k) { BigInteger B, S; S = BigInteger.ONE; B = BigInteger.ONE; for (int j = 0; j < k; j++) { B = binCoeffInduction(B, n, j); S = S.sum(B); } return S; } /** * Factorial. * @param n integer. * @return n!, with 0! = 1. */ public static BigInteger factorial(long n) { if (n <= 1) { return BigInteger.ONE; } BigInteger f = BigInteger.ONE; if (n >= Integer.MAX_VALUE) { throw new UnsupportedOperationException(n + " >= Integer.MAX_VALUE = " + Integer.MAX_VALUE); } for (int i = 2; i <= n; i++) { f = f.multiply(new BigInteger(i)); } return f; } } java-algebra-system-2.7.200/src/edu/jas/arith/ModInt.java000066400000000000000000000337301445075545500230310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * ModInt class with RingElem interface. Objects of this class are immutable. * @author Heinz Kredel * @see ModInteger */ public final class ModInt implements GcdRingElem, Modular { /** * ModIntRing reference. */ public final ModIntRing ring; /** * Value part of the element data structure. */ public final int val; /** * The constructor creates a ModInt object from a ModIntRing and a value * part. * @param m ModIntRing. * @param a math.BigInteger. */ public ModInt(ModIntRing m, java.math.BigInteger a) { this(m, a.mod(m.getModul()).intValue()); } /** * The constructor creates a ModInt object from a ModIntRing and a int value * part. * @param m ModIntRing. * @param a int. */ public ModInt(ModIntRing m, int a) { ring = m; int v = a % ring.modul; val = (v >= 0 ? v : v + ring.modul); } /** * The constructor creates a ModInt object from a ModIntRing and a long * value part. * @param m ModIntRing. * @param a long. */ public ModInt(ModIntRing m, long a) { ring = m; int v = (int) (a % (long)ring.modul); val = (v >= 0 ? v : v + ring.modul); } /** * The constructor creates a ModInt object from a ModIntRing and a Int value * part. * @param m ModIntRing. * @param a Int. */ public ModInt(ModIntRing m, Integer a) { this(m, a.intValue()); } /** * The constructor creates a ModInt object from a ModIntRing and a Long * value part. * @param m ModIntRing. * @param a long. */ public ModInt(ModIntRing m, Long a) { this(m, a.longValue()); } /** * The constructor creates a ModInt object from a ModIntRing and a String * value part. * @param m ModIntRing. * @param s String. */ public ModInt(ModIntRing m, String s) { this(m, Integer.valueOf(s.trim())); } /** * The constructor creates a 0 ModInt object from a given ModIntRing. * @param m ModIntRing. */ public ModInt(ModIntRing m) { this(m, 0); } /** * Get the value part. * @return val. */ public int getVal() { return val; } /** * Get the module part. * @return modul. */ public int getModul() { return ring.modul; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ModIntRing factory() { return ring; } /** * Get the symmetric value part. * @return val with -modul/2 ≤ val < modul/2. */ public int getSymmetricVal() { if ((val + val) > ring.modul) { // val > m/2 as 2*val > m, make symmetric to 0 return val - ring.modul; } return val; } /** * Return a BigInteger from this Element. * @return a BigInteger of this. */ public BigInteger getInteger() { return new BigInteger(val); } /** * Return a symmetric BigInteger from this Element. * @return a symmetric BigInteger of this. */ public BigInteger getSymmetricInteger() { int v = val; if ((val + val) > ring.modul) { // val > m/2 as 2*val > m, make symmetric to 0 v = val - ring.modul; } return new BigInteger(v); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ModInt copy() { return new ModInt(ring, val); } /** * Is ModInt number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val == 0; } /** * Is ModInt number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val == 1L; } /** * Is ModInt number a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isZERO()) { return false; } if (ring.isField()) { return true; } int g = gcd(ring.modul, val); return (g == 1L || g == -1L); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return Integer.toString(val); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * ModInt comparison. * @param b ModInt. * @return sign(this-b). */ @Override public int compareTo(ModInt b) { int v = b.val; if (ring != b.ring) { v = v % ring.modul; } if (val > v) { return 1; } return (val < v ? -1 : 0); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModInt)) { return false; } return (0 == compareTo((ModInt) b)); } /** * Hash code for this ModInt. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return val; } /** * ModInt absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public ModInt abs() { return new ModInt(ring, (val < 0 ? -val : val)); } /** * ModInt negative. * @see edu.jas.structure.RingElem#negate() * @return -this. */ public ModInt negate() { return new ModInt(ring, -val); } /** * ModInt signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { if (val > 0) { return 1; } return (val < 0 ? -1 : 0); } /** * ModInt subtraction. * @param S ModInt. * @return this-S. */ public ModInt subtract(ModInt S) { return new ModInt(ring, val - S.val); } /** * ModInt divide. * @param S ModInt. * @return this/S. */ public ModInt divide(ModInt S) { try { return multiply(S.inverse()); } catch (NotInvertibleException e) { try { if ((val % S.val) == 0) { return new ModInt(ring, val / S.val); } throw new NotInvertibleException(e.getCause()); } catch (ArithmeticException a) { throw new NotInvertibleException(a.getCause()); } } } /** * ModInt inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S=1/this if defined. */ public ModInt inverse() /*throws NotInvertibleException*/ { try { return new ModInt(ring, modInverse(val, ring.modul)); } catch (ArithmeticException e) { int g = gcd(val, ring.modul); int f = ring.modul / g; throw new ModularNotInvertibleException(e, new BigInteger(ring.modul), new BigInteger(g), new BigInteger(f)); } } /** * ModInt remainder. * @param S ModInt. * @return remainder(this,S). */ public ModInt remainder(ModInt S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } if (S.isONE()) { return ring.getZERO(); } if (S.isUnit()) { return ring.getZERO(); } return new ModInt(ring, val % S.val); } /** * ModInt multiply. * @param S ModInt. * @return this*S. */ public ModInt multiply(ModInt S) { return new ModInt(ring, val * S.val); } /** * ModInt summation. * @param S ModInt. * @return this+S. */ public ModInt sum(ModInt S) { return new ModInt(ring, val + S.val); } /** * ModInteger greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public ModInt gcd(ModInt S) { if (S.isZERO()) { return this; } if (isZERO()) { return S; } if (isUnit() || S.isUnit()) { return ring.getONE(); } return new ModInt(ring, gcd(val, S.val)); } /** * ModInteger extended greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public ModInt[] egcd(ModInt S) { ModInt[] ret = new ModInt[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (isZERO()) { ret[0] = S; return ret; } if (isUnit() || S.isUnit()) { ret[0] = ring.getONE(); if (isUnit() && S.isUnit()) { //ModInt half = (new ModInt(ring, 2L)).inverse(); //ret[1] = this.inverse().multiply(half); //ret[2] = S.inverse().multiply(half); // (1-1*this)/S ret[1] = ring.getONE(); ModInt x = ret[0].subtract(ret[1].multiply(this)); ret[2] = x.divide(S); return ret; } if (isUnit()) { // oder inverse(S-1)? ret[1] = this.inverse(); ret[2] = ring.getZERO(); return ret; } // if ( s.isUnit() ) { // oder inverse(this-1)? ret[1] = ring.getZERO(); ret[2] = S.inverse(); return ret; //} } //System.out.println("this = " + this + ", S = " + S); int q = this.val; int r = S.val; int c1 = 1; // BigInteger.ONE.val; int d1 = 0; // BigInteger.ZERO.val; int c2 = 0; // BigInteger.ZERO.val; int d2 = 1; // BigInteger.ONE.val; int x1; int x2; while (r != 0) { //qr = q.divideAndRemainder(r); int a = q / r; int b = q % r; q = a; x1 = c1 - q * d1; x2 = c2 - q * d2; c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = b; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); ret[0] = new ModInt(ring, q); ret[1] = new ModInt(ring, c1); ret[2] = new ModInt(ring, c2); return ret; } /** * Int greatest common divisor. * @param T int. * @param S int. * @return gcd(T,S). */ public int gcd(int T, int S) { if (S == 0) { return T; } if (T == 0) { return S; } int a = T; int b = S; while (b != 0) { int r = a % b; a = b; b = r; } return a; } /** * Int half extended greatest common divisor. * @param T int. * @param S int. * @return [ gcd(T,S), a ] with a*T + b*S = gcd(T,S). */ public int[] hegcd(int T, int S) { int[] ret = new int[2]; if (S == 0) { ret[0] = T; ret[1] = 1; return ret; } if (T == 0) { ret[0] = S; ret[1] = 0; return ret; } //System.out.println("hegcd, T = " + T + ", S = " + S); int a = T; int b = S; int a1 = 1; int b1 = 0; while (b != 0) { int q = a / b; int r = a % b; a = b; b = r; int r1 = a1 - q * b1; a1 = b1; b1 = r1; } if (a1 < 0) { a1 += S; } ret[0] = a; ret[1] = a1; return ret; } /** * Int modular inverse. * @param T int. * @param m int. * @return a with with a*T = 1 mod m. */ public int modInverse(int T, int m) { if (T == 0) { throw new NotInvertibleException("zero is not invertible"); } int[] hegcd = hegcd(T, m); int a = hegcd[0]; if (!(a == 1L || a == -1L)) { // gcd != 1 throw new ModularNotInvertibleException("element not invertible, gcd != 1", new BigInteger(m), new BigInteger(a), new BigInteger(m / a)); } int b = hegcd[1]; if (b == 0) { // when m divides this, e.g. m.isUnit() throw new NotInvertibleException("element not invertible, divisible by modul"); } if (b < 0) { b += m; } return b; } /** * Returns the number of bits in the representation of this ModInt, * including a sign bit. * @return number of bits in the representation of this ModInt, including a * sign bit. */ public int bitLength() { return (int) BigInteger.bitLength(val); } } java-algebra-system-2.7.200/src/edu/jas/arith/ModIntRing.java000066400000000000000000000307121445075545500236460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import edu.jas.kern.StringUtil; /** * ModIntRing factory with RingFactory interface. Effectively immutable. * @author Heinz Kredel */ public final class ModIntRing implements ModularRingFactory, Iterable { /** * Module part of the factory data structure. */ public final int modul; /** * Random number generator. */ private final static Random random = new Random(); /** * Indicator if this ring is a field. */ private int isField = -1; // initially unknown /* * Certainty if module is probable prime. */ //private final int certainty = 10; /** * maximal representable integer. */ public final static java.math.BigInteger MAX_INT = new java.math.BigInteger( String.valueOf(Short.MAX_VALUE)); // not larger! /** * The constructor creates a ModIntRing object from a int integer as module * part. * @param m int integer. */ public ModIntRing(int m) { modul = m; } /** * The constructor creates a ModIntRing object from a int integer as module * part. * @param m int integer. * @param isField indicator if m is prime. */ public ModIntRing(int m, boolean isField) { modul = m; this.isField = (isField ? 1 : 0); } /** * The constructor creates a ModIntRing object from a Int integer as module * part. * @param m Int integer. */ public ModIntRing(Integer m) { this(m.intValue()); } /** * The constructor creates a ModIntRing object from a Int integer as module * part. * @param m Int integer. * @param isField indicator if m is prime. */ public ModIntRing(Integer m, boolean isField) { this(m.intValue(), isField); } /** * The constructor creates a ModIntRing object from a BigInteger converted * to int as module part. * @param m java.math.BigInteger. */ public ModIntRing(java.math.BigInteger m) { this(m.intValueExact()); if (MAX_INT.compareTo(m) < 0) { // m > max //System.out.println("modul to large for int " + m + ",max=" + MAX_INT); throw new IllegalArgumentException("modul to large for int " + m + ", max=" + MAX_INT); } } /** * The constructor creates a ModIntRing object from a BigInteger converted * to int as module part. * @param m java.math.BigInteger. * @param isField indicator if m is prime. */ public ModIntRing(java.math.BigInteger m, boolean isField) { this(m.intValueExact(), isField); if (MAX_INT.compareTo(m) < 0) { // m > max //System.out.println("modul to large for int " + m + ",max=" + MAX_INT); throw new IllegalArgumentException("modul to large for int " + m + ", max=" + MAX_INT); } } /** * The constructor creates a ModIntRing object from a String object as * module part. * @param m String. */ public ModIntRing(String m) { this(Integer.valueOf(m.trim())); } /** * The constructor creates a ModIntRing object from a String object as * module part. * @param m String. * @param isField indicator if m is prime. */ public ModIntRing(String m, boolean isField) { this(Integer.valueOf(m.trim()), isField); } /** * Get the module part as BigInteger. * @return modul. */ public java.math.BigInteger getModul() { return new java.math.BigInteger(Integer.toString(modul)); } /** * Get the module part as int. * @return modul. */ public int getIntModul() { return modul; } /** * Get the module part as BigInteger. * @return modul. */ public BigInteger getIntegerModul() { return new BigInteger(modul); } /** * Create ModInt element c. * @param c * @return a ModInt of c. */ public ModInt create(java.math.BigInteger c) { return new ModInt(this, c); } /** * Create ModInt element c. * @param c * @return a ModInt of c. */ public ModInt create(int c) { return new ModInt(this, c); } /** * Create ModInt element c. * @param c * @return a ModInt of c. */ public ModInt create(String c) { return parse(c); } /** * Copy ModInt element c. * @param c * @return a copy of c. */ public ModInt copy(ModInt c) { return new ModInt(this, c.val); } /** * Get the zero element. * @return 0 as ModInt. */ public ModInt getZERO() { return new ModInt(this, 0); } /** * Get the one element. * @return 1 as ModInt. */ public ModInt getONE() { return new ModInt(this, 1); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return true; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true if module is prime, else false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } //System.out.println("isProbablePrime " + modul + " = " + modul.isProbablePrime(certainty)); java.math.BigInteger m = new java.math.BigInteger(Integer.toString(modul)); if (m.isProbablePrime(m.bitLength())) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return new java.math.BigInteger(Integer.toString(modul)); } /** * Get a ModInt element from a BigInteger value. * @param a BigInteger. * @return a ModInt. */ public ModInt fromInteger(java.math.BigInteger a) { return new ModInt(this, a); } /** * Get a ModInt element from a int value. * @param a int. * @return a ModInt. */ public ModInt fromInteger(int a) { return new ModInt(this, a); } /** * Get a ModInt element from a long value. * @param a lon. * @return a ModInt. */ public ModInt fromInteger(long a) { return new ModInt(this, a); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return " mod(" + modul + ")"; //",max=" + MAX_INT + ")"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python and Ruby case if (isField()) { return "GFI(" + modul + ")"; } return "ZMI(" + modul + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModIntRing)) { return false; } ModIntRing m = (ModIntRing) b; return (modul == m.modul); } /** * Hash code for this ModIntRing. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return modul; } /** * ModInt random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public ModInt random(int n) { return random(n, random); } /** * ModInt random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public ModInt random(int n, Random rnd) { java.math.BigInteger v = new java.math.BigInteger(n, rnd); return new ModInt(this, v); // rnd.nextInt() not ok } /** * Parse ModInt from String. * @param s String. * @return ModInt from s. */ public ModInt parse(String s) { return new ModInt(this, s); } /** * Parse ModInt from Reader. * @param r Reader. * @return next ModInt from r. */ public ModInt parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * ModInt chinese remainder algorithm. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param c ModInt. * @param ci inverse of c.modul in ring of a. * @param a other ModInt. * @return S, with S mod c.modul == c and S mod a.modul == a. */ public ModInt chineseRemainder(ModInt c, ModInt ci, ModInt a) { //if (true) { // if (c.ring.modul < a.ring.modul) { // System.out.println("ModInt error " + c.ring + ", " + a.ring); // } //} ModInt b = a.ring.fromInteger(c.val); // c mod a.modul ModInt d = a.subtract(b); // a-c mod a.modul if (d.isZERO()) { return new ModInt(this, c.val); } b = d.multiply(ci); // b = (a-c)*ci mod a.modul // (c.modul*b)+c mod this.modul = c mod c.modul = // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul int s = c.ring.modul * b.val; s = s + c.val; return new ModInt(this, s); } /** * Modular digit list chinese remainder algorithm. m1 and m2 are positive * beta-integers, with GCD(m1,m2)=1 and m=m1*m2 less than beta. L1 and L2 * are lists of elements of Z(m1) and Z(m2) respectively. L is a list of all * a in Z(m) such that a is congruent to a1 modulo m1 and a is congruent to * a2 modulo m2 with a1 in L1 and a2 in L2. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param m1 ModInt. * @param m2 other ModInt. * @return L list of congruences. */ public static List chineseRemainder(ModInt m1, ModInt m2, List L1, List L2) { int mm = m1.ring.modul * m2.ring.modul; ModIntRing m = new ModIntRing(mm); ModInt m21 = m2.ring.fromInteger(m1.ring.modul); ModInt mi1 = m21.inverse(); List L = new ArrayList(); for (ModInt a : L1) { for (ModInt b : L2) { ModInt c = m.chineseRemainder(a, mi1, b); L.add(c); } } return L; } /** * Get a ModInt iterator. * @return a iterator over all modular integers in this ring. */ public Iterator iterator() { return new ModIntIterator(this); } } /** * Modular integer iterator. * @author Heinz Kredel */ class ModIntIterator implements Iterator { /** * data structure. */ int curr; final ModIntRing ring; /** * ModInt iterator constructor. * @param fac modular integer factory; */ public ModIntIterator(ModIntRing fac) { curr = 0; ring = fac; } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public synchronized boolean hasNext() { return curr < ring.modul; } /** * Get next integer. * @return next integer. */ public synchronized ModInt next() { ModInt i = new ModInt(ring, curr); curr++; return i; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/arith/ModInteger.java000066400000000000000000000406741445075545500237010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * ModInteger class with GcdRingElem interface. Objects of this class are * immutable. The SAC2 static methods are also provided. * @author Heinz Kredel * @see java.math.BigInteger */ public final class ModInteger implements GcdRingElem, Modular { /** * ModIntegerRing reference. */ public final ModIntegerRing ring; /** * Value part of the element data structure. */ public final java.math.BigInteger val; /** * The constructor creates a ModInteger object from a ModIntegerRing and a * value part. * @param m ModIntegerRing. * @param a math.BigInteger. */ public ModInteger(ModIntegerRing m, java.math.BigInteger a) { ring = m; val = a.mod(ring.modul); } /** * The constructor creates a ModInteger object from a ModIntegerRing and a * long value part. * @param m ModIntegerRing. * @param a long. */ public ModInteger(ModIntegerRing m, long a) { this(m, new java.math.BigInteger(String.valueOf(a))); } /** * The constructor creates a ModInteger object from a ModIntegerRing and a * String value part. * @param m ModIntegerRing. * @param s String. */ public ModInteger(ModIntegerRing m, String s) { this(m, new java.math.BigInteger(s.trim())); } /** * The constructor creates a 0 ModInteger object from a given * ModIntegerRing. * @param m ModIntegerRing. */ public ModInteger(ModIntegerRing m) { this(m, java.math.BigInteger.ZERO); } /** * Get the value part. * @return val. */ public java.math.BigInteger getVal() { return val; } /** * Get the module part. * @return modul. */ public java.math.BigInteger getModul() { return ring.modul; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ModIntegerRing factory() { return ring; } /** * Get the symmetric value part. * @return val with -modul/2 ≤ val < modul/2. */ public java.math.BigInteger getSymmetricVal() { if (val.add(val).compareTo(ring.modul) > 0) { // val > m/2 as 2*val > m, make symmetric to 0 return val.subtract(ring.modul); } return val; } /** * Return a BigInteger from this Element. * @return a BigInteger of this. */ public BigInteger getInteger() { return new BigInteger(val); } /** * Return a symmetric BigInteger from this Element. * @return a symmetric BigInteger of this. */ public BigInteger getSymmetricInteger() { java.math.BigInteger v = val; if (val.add(val).compareTo(ring.modul) > 0) { // val > m/2 as 2*val > m, make symmetric to 0 v = val.subtract(ring.modul); } return new BigInteger(v); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ModInteger copy() { return new ModInteger(ring, val); } /** * Is ModInteger number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.signum() == 0; } /** * Is ModInteger number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.equals(java.math.BigInteger.ONE); } /** * Is ModInteger number a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isZERO()) { return false; } if (ring.isField()) { return true; } java.math.BigInteger g = ring.modul.gcd(val).abs(); return (g.equals(java.math.BigInteger.ONE)); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return val.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * ModInteger comparison. * @param b ModInteger. * @return sign(this-b). */ @Override public int compareTo(ModInteger b) { java.math.BigInteger v = b.val; if (ring != b.ring) { v = v.mod(ring.modul); } return val.compareTo(v); } /** * ModInteger comparison. * @param A ModInteger. * @param B ModInteger. * @return sign(this-b). */ public static int MICOMP(ModInteger A, ModInteger B) { if (A == null) return -B.signum(); return A.compareTo(B); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModInteger)) { return false; } return (0 == compareTo((ModInteger) b)); } /** * Hash code for this ModInteger. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { //return 37 * val.hashCode(); return val.hashCode(); } /** * ModInteger absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public ModInteger abs() { return new ModInteger(ring, val.abs()); } /** * ModInteger absolute value. * @param A ModInteger. * @return the absolute value of A. */ public static ModInteger MIABS(ModInteger A) { if (A == null) return null; return A.abs(); } /** * ModInteger negative. * @see edu.jas.structure.RingElem#negate() * @return -this. */ public ModInteger negate() { return new ModInteger(ring, val.negate()); } /** * ModInteger negative. * @param A ModInteger. * @return -A. */ public static ModInteger MINEG(ModInteger A) { if (A == null) return null; return A.negate(); } /** * ModInteger signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * ModInteger signum. * @param A ModInteger * @return signum(A). */ public static int MISIGN(ModInteger A) { if (A == null) return 0; return A.signum(); } /** * ModInteger subtraction. * @param S ModInteger. * @return this-S. */ public ModInteger subtract(ModInteger S) { return new ModInteger(ring, val.subtract(S.val)); } /** * ModInteger subtraction. * @param A ModInteger. * @param B ModInteger. * @return A-B. */ public static ModInteger MIDIF(ModInteger A, ModInteger B) { if (A == null) return B.negate(); return A.subtract(B); } /** * ModInteger divide. * @param S ModInteger. * @return this/S. */ public ModInteger divide(ModInteger S) { try { return multiply(S.inverse()); } catch (NotInvertibleException e) { try { if (val.remainder(S.val).equals(java.math.BigInteger.ZERO)) { return new ModInteger(ring, val.divide(S.val)); } throw new NotInvertibleException(e); } catch (ArithmeticException a) { throw new NotInvertibleException(a); } } } /** * ModInteger quotient. * @param A ModInteger. * @param B ModInteger. * @return A/B. */ public static ModInteger MIQ(ModInteger A, ModInteger B) { if (A == null) return null; return A.divide(B); } /** * ModInteger inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S=1/this if defined. */ public ModInteger inverse() /*throws NotInvertibleException*/ { try { return new ModInteger(ring, val.modInverse(ring.modul)); } catch (ArithmeticException e) { java.math.BigInteger g = val.gcd(ring.modul); java.math.BigInteger f = ring.modul.divide(g); throw new ModularNotInvertibleException(e, new BigInteger(ring.modul), new BigInteger(g), new BigInteger(f)); } } /** * ModInteger inverse. * @param A is a non-zero integer. * @see edu.jas.structure.RingElem#inverse() * @return S with S=1/A if defined. */ public static ModInteger MIINV(ModInteger A) { if (A == null) return null; return A.inverse(); } /** * ModInteger remainder. * @param S ModInteger. * @return remainder(this,S). */ public ModInteger remainder(ModInteger S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } if (S.isONE()) { return ring.getZERO(); } if (S.isUnit()) { return ring.getZERO(); } return new ModInteger(ring, val.remainder(S.val)); } /** * ModInteger remainder. * @param A ModInteger. * @param B ModInteger. * @return A - (A/B)*B. */ public static ModInteger MIREM(ModInteger A, ModInteger B) { if (A == null) return null; return A.remainder(B); } /** * Quotient and remainder by division of this by S. * @param S a modular integer * @return [this/S, this - (this/S)*S]. */ public ModInteger[] quotientRemainder(ModInteger S) { return new ModInteger[] { divide(S), remainder(S) }; } /** * ModInteger multiply. * @param S ModInteger. * @return this*S. */ public ModInteger multiply(ModInteger S) { return new ModInteger(ring, val.multiply(S.val)); } /** * ModInteger product. * @param A ModInteger. * @param B ModInteger. * @return A*B. */ public static ModInteger MIPROD(ModInteger A, ModInteger B) { if (A == null) return null; return A.multiply(B); } /** * ModInteger summation. * @param S ModInteger. * @return this+S. */ public ModInteger sum(ModInteger S) { return new ModInteger(ring, val.add(S.val)); } /** * ModInteger summation. * @param A ModInteger. * @param B ModInteger. * @return A+B. */ public static ModInteger MISUM(ModInteger A, ModInteger B) { if (A == null) return null; return A.sum(B); } /** * ModInteger greatest common divisor. * @param S ModInteger. * @return gcd(this,S). */ public ModInteger gcd(ModInteger S) { if (S.isZERO()) { return this; } if (isZERO()) { return S; } if (isUnit() || S.isUnit()) { return ring.getONE(); } return new ModInteger(ring, val.gcd(S.val)); } /** * ModInteger half extended greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S) for some b. */ public ModInteger[] hegcd(ModInteger S) { ModInteger[] ret = new ModInteger[2]; ret[0] = null; ret[1] = null; if (S == null || S.isZERO()) { ret[0] = this; ret[1] = this.ring.getONE(); return ret; } if (isZERO()) { ret[0] = S; return ret; } //System.out.println("this = " + this + ", S = " + S); java.math.BigInteger[] qr; java.math.BigInteger q = this.val; java.math.BigInteger r = S.val; java.math.BigInteger c1 = BigInteger.ONE.val; java.math.BigInteger d1 = BigInteger.ZERO.val; java.math.BigInteger x1; while (!r.equals(java.math.BigInteger.ZERO)) { qr = q.divideAndRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); c1 = d1; d1 = x1; q = r; r = qr[1]; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); ret[0] = new ModInteger(ring, q); ret[1] = new ModInteger(ring, c1); //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); return ret; } /** * ModInteger extended greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public ModInteger[] egcd(ModInteger S) { ModInteger[] ret = new ModInteger[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (isZERO()) { ret[0] = S; return ret; } if (this.isUnit() || S.isUnit()) { ret[0] = ring.getONE(); if (this.isUnit() && S.isUnit()) { //ModInteger half = ring.fromInteger(2).inverse(); //ret[1] = this.inverse().multiply(half); //ret[2] = S.inverse().multiply(half); //System.out.println("gcd = " + (ret[1].multiply(this).sum(ret[2].multiply(S)))); // (1-1*this)/S ret[1] = ring.getONE(); ModInteger x = ret[0].subtract(ret[1].multiply(this)); ret[2] = x.divide(S); //System.out.println("gcd, a, b = " + (ret[1]) + ", " + ret[2]); //System.out.println("gcd = " + (ret[1].multiply(this).sum(ret[2].multiply(S)))); return ret; } if (this.isUnit()) { // oder inverse(S-1)? ret[1] = this.inverse(); ret[2] = ring.getZERO(); return ret; } // if ( S.isUnit() ) { // oder inverse(this-1)? ret[1] = ring.getZERO(); ret[2] = S.inverse(); return ret; //} } //System.out.println("this = " + this + ", S = " + S); java.math.BigInteger[] qr; java.math.BigInteger q = this.val; java.math.BigInteger r = S.val; java.math.BigInteger c1 = BigInteger.ONE.val; java.math.BigInteger d1 = BigInteger.ZERO.val; java.math.BigInteger c2 = BigInteger.ZERO.val; java.math.BigInteger d2 = BigInteger.ONE.val; java.math.BigInteger x1; java.math.BigInteger x2; while (!r.equals(java.math.BigInteger.ZERO)) { qr = q.divideAndRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); ret[0] = new ModInteger(ring, q); ret[1] = new ModInteger(ring, c1); ret[2] = new ModInteger(ring, c2); return ret; } /** * Returns the number of bits in the representation of this ModInteger, * including a sign bit. For positive ModIntegers, this is equivalent to * {@code val.bitLength()}.) * @return number of bits in the representation of this ModInteger, * including a sign bit. */ public long bitLength() { long n = val.bitLength(); if (val.signum() < 0) { n++; } n++; return n; } } java-algebra-system-2.7.200/src/edu/jas/arith/ModIntegerRing.java000066400000000000000000000267061445075545500245210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import edu.jas.kern.StringUtil; /** * ModIntegerRing factory with RingFactory interface. Effectively immutable. * @author Heinz Kredel */ public final class ModIntegerRing implements ModularRingFactory, Iterable { /** * Module part of the factory data structure. */ public final java.math.BigInteger modul; private final static Random random = new Random(); /** * Indicator if this ring is a field. */ private int isField = -1; // initially unknown /* * Certainty if module is probable prime. */ //private int certainty = 10; /** * The constructor creates a ModIntegerRing object from a BigInteger object * as module part. * @param m math.BigInteger. */ public ModIntegerRing(java.math.BigInteger m) { modul = m; } /** * The constructor creates a ModIntegerRing object from a BigInteger object * as module part. * @param m math.BigInteger. * @param isField indicator if m is prime. */ public ModIntegerRing(java.math.BigInteger m, boolean isField) { modul = m; this.isField = (isField ? 1 : 0); } /** * The constructor creates a ModIntegerRing object from a long as module * part. * @param m long. */ public ModIntegerRing(long m) { this(new java.math.BigInteger(String.valueOf(m))); } /** * The constructor creates a ModIntegerRing object from a long as module * part. * @param m long. * @param isField indicator if m is prime. */ public ModIntegerRing(long m, boolean isField) { this(new java.math.BigInteger(String.valueOf(m)), isField); } /** * The constructor creates a ModIntegerRing object from a String object as * module part. * @param m String. */ public ModIntegerRing(String m) { this(new java.math.BigInteger(m.trim())); } /** * The constructor creates a ModIntegerRing object from a String object as * module part. * @param m String. * @param isField indicator if m is prime. */ public ModIntegerRing(String m, boolean isField) { this(new java.math.BigInteger(m.trim()), isField); } /** * Get the module part. * @return modul. */ public java.math.BigInteger getModul() { return modul; } /** * Get the module part as BigInteger. * @return modul. */ public BigInteger getIntegerModul() { return new BigInteger(modul); } /** * Create ModInteger element c. * @param c * @return a ModInteger of c. */ public ModInteger create(java.math.BigInteger c) { return new ModInteger(this, c); } /** * Create ModInteger element c. * @param c * @return a ModInteger of c. */ public ModInteger create(long c) { return new ModInteger(this, c); } /** * Create ModInteger element c. * @param c * @return a ModInteger of c. */ public ModInteger create(String c) { return parse(c); } /** * Copy ModInteger element c. * @param c * @return a copy of c. */ public ModInteger copy(ModInteger c) { return new ModInteger(this, c.val); } /** * Get the zero element. * @return 0 as ModInteger. */ public ModInteger getZERO() { return new ModInteger(this, java.math.BigInteger.ZERO); } /** * Get the one element. * @return 1 as ModInteger. */ public ModInteger getONE() { return new ModInteger(this, java.math.BigInteger.ONE); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return true; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true if module is prime, else false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } //System.out.println("isProbablePrime " + modul + " = " + modul.isProbablePrime(certainty)); // if ( modul.isProbablePrime(certainty) ) { if (modul.isProbablePrime(modul.bitLength())) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return modul; } /** * Get a ModInteger element from a BigInteger value. * @param a BigInteger. * @return a ModInteger. */ public ModInteger fromInteger(java.math.BigInteger a) { return new ModInteger(this, a); } /** * Get a ModInteger element from a long value. * @param a long. * @return a ModInteger. */ public ModInteger fromInteger(long a) { return new ModInteger(this, a); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return " bigMod(" + modul.toString() + ")"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python and Ruby case if (isField()) { return "GF(" + modul.toString() + ")"; } return "ZM(" + modul.toString() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModIntegerRing)) { return false; } ModIntegerRing m = (ModIntegerRing) b; return (0 == modul.compareTo(m.modul)); } /** * Hash code for this ModIntegerRing. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return modul.hashCode(); } /** * ModInteger random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public ModInteger random(int n) { return random(n, random); } /** * ModInteger random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public ModInteger random(int n, Random rnd) { java.math.BigInteger v = new java.math.BigInteger(n, rnd); return new ModInteger(this, v); } /** * Parse ModInteger from String. * @param s String. * @return ModInteger from s. */ public ModInteger parse(String s) { return new ModInteger(this, s); } /** * Parse ModInteger from Reader. * @param r Reader. * @return next ModInteger from r. */ public ModInteger parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * ModInteger chinese remainder algorithm. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param c ModInteger. * @param ci inverse of c.modul in ring of a. * @param a other ModInteger. * @return S, with S mod c.modul == c and S mod a.modul == a. */ public ModInteger chineseRemainder(ModInteger c, ModInteger ci, ModInteger a) { //if (false) { // debug // if (c.ring.modul.compareTo(a.ring.modul) < 1) { // System.out.println("ModInteger error " + c + ", " + a); // } //} ModInteger b = a.ring.fromInteger(c.val); // c mod a.modul ModInteger d = a.subtract(b); // a-c mod a.modul if (d.isZERO()) { return fromInteger(c.val); } b = d.multiply(ci); // b = (a-c)*ci mod a.modul // (c.modul*b)+c mod this.modul = c mod c.modul = // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul java.math.BigInteger s = c.ring.modul.multiply(b.val); s = s.add(c.val); return fromInteger(s); } /** * Modular integer list chinese remainder algorithm. m1 and m2 are positive * integers, with GCD(m1,m2)=1 and m=m1*m2 less than beta. L1 and L2 are * lists of elements of Z(m1) and Z(m2) respectively. L is a list of all a * in Z(m) such that a is congruent to a1 modulo m1 and a is congruent to a2 * modulo m2 with a1 in L1 and a2 in L2. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param m1 modular integer. * @param m2 other modular integer. * @return L list of congruences. */ public static List chineseRemainder(ModInteger m1, ModInteger m2, List L1, List L2) { java.math.BigInteger mm = m1.ring.modul.multiply(m2.ring.modul); ModIntegerRing m = new ModIntegerRing(mm); ModInteger m21 = m2.ring.fromInteger(m1.ring.modul); ModInteger mi1 = m21.inverse(); List L = new ArrayList(); for (ModInteger a : L1) { for (ModInteger b : L2) { ModInteger c = m.chineseRemainder(a, mi1, b); L.add(c); } } return L; } /** * Get a ModInteger iterator. * @return a iterator over all modular integers in this ring. */ public Iterator iterator() { return new ModIntegerIterator(this); } } /** * Modular integer iterator. * @author Heinz Kredel */ class ModIntegerIterator implements Iterator { /** * data structure. */ java.math.BigInteger curr; final ModIntegerRing ring; /** * ModInteger iterator constructor. * @param fac modular integer factory; */ public ModIntegerIterator(ModIntegerRing fac) { curr = java.math.BigInteger.ZERO; ring = fac; } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public synchronized boolean hasNext() { return curr.compareTo(ring.modul) < 0; } /** * Get next integer. * @return next integer. */ public synchronized ModInteger next() { ModInteger i = new ModInteger(ring, curr); curr = curr.add(java.math.BigInteger.ONE); return i; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/arith/ModLong.java000066400000000000000000000331161445075545500231740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * ModLong class with RingElem interface. Objects of this class are immutable. * @author Heinz Kredel * @see ModInteger */ public final class ModLong implements GcdRingElem, Modular { /** * ModLongRing reference. */ public final ModLongRing ring; /** * Value part of the element data structure. */ public final long val; /** * The constructor creates a ModLong object from a ModLongRing and a value * part. * @param m ModLongRing. * @param a math.BigInteger. */ public ModLong(ModLongRing m, java.math.BigInteger a) { this(m, a.mod(m.getModul()).longValue()); } /** * The constructor creates a ModLong object from a ModLongRing and a long * value part. * @param m ModLongRing. * @param a long. */ public ModLong(ModLongRing m, long a) { ring = m; long v = a % ring.modul; val = (v >= 0L ? v : v + ring.modul); } /** * The constructor creates a ModLong object from a ModLongRing and a Long * value part. * @param m ModLongRing. * @param a Long. */ public ModLong(ModLongRing m, Long a) { this(m, a.longValue()); } /** * The constructor creates a ModLong object from a ModLongRing and a String * value part. * @param m ModLongRing. * @param s String. */ public ModLong(ModLongRing m, String s) { this(m, Long.valueOf(s.trim())); } /** * The constructor creates a 0 ModLong object from a given ModLongRing. * @param m ModLongRing. */ public ModLong(ModLongRing m) { this(m, 0L); } /** * Get the value part. * @return val. */ public long getVal() { return val; } /** * Get the module part. * @return modul. */ public long getModul() { return ring.modul; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ModLongRing factory() { return ring; } /** * Get the symmetric value part. * @return val with -modul/2 ≤ val < modul/2. */ public long getSymmetricVal() { if ((val + val) > ring.modul) { // val > m/2 as 2*val > m, make symmetric to 0 return val - ring.modul; } return val; } /** * Return a BigInteger from this Element. * @return a BigInteger of this. */ public BigInteger getInteger() { return new BigInteger(val); } /** * Return a symmetric BigInteger from this Element. * @return a symmetric BigInteger of this. */ public BigInteger getSymmetricInteger() { long v = val; if ((val + val) > ring.modul) { // val > m/2 as 2*val > m, make symmetric to 0 v = val - ring.modul; } return new BigInteger(v); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ModLong copy() { return new ModLong(ring, val); } /** * Is ModLong number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val == 0L; } /** * Is ModLong number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val == 1L; } /** * Is ModLong number a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isZERO()) { return false; } if (ring.isField()) { return true; } long g = gcd(ring.modul, val); return (g == 1L || g == -1L); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return Long.toString(val); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * ModLong comparison. * @param b ModLong. * @return sign(this-b). */ @Override public int compareTo(ModLong b) { long v = b.val; if (ring != b.ring) { v = v % ring.modul; } if (val > v) { return 1; } return (val < v ? -1 : 0); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModLong)) { return false; } return (0 == compareTo((ModLong) b)); } /** * Hash code for this ModLong. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (int) val; } /** * ModLong absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public ModLong abs() { return new ModLong(ring, (val < 0 ? -val : val)); } /** * ModLong negative. * @see edu.jas.structure.RingElem#negate() * @return -this. */ public ModLong negate() { return new ModLong(ring, -val); } /** * ModLong signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { if (val > 0L) { return 1; } return (val < 0L ? -1 : 0); } /** * ModLong subtraction. * @param S ModLong. * @return this-S. */ public ModLong subtract(ModLong S) { return new ModLong(ring, val - S.val); } /** * ModLong divide. * @param S ModLong. * @return this/S. */ public ModLong divide(ModLong S) { try { return multiply(S.inverse()); } catch (NotInvertibleException e) { try { if ((val % S.val) == 0L) { return new ModLong(ring, val / S.val); } throw new NotInvertibleException(e.getCause()); } catch (ArithmeticException a) { throw new NotInvertibleException(a.getCause()); } } } /** * ModLong inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S=1/this if defined. */ public ModLong inverse() /*throws NotInvertibleException*/ { try { return new ModLong(ring, modInverse(val, ring.modul)); } catch (ArithmeticException e) { long g = gcd(val, ring.modul); long f = ring.modul / g; throw new ModularNotInvertibleException(e, new BigInteger(ring.modul), new BigInteger(g), new BigInteger(f)); } } /** * ModLong remainder. * @param S ModLong. * @return remainder(this,S). */ public ModLong remainder(ModLong S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } if (S.isONE()) { return ring.getZERO(); } if (S.isUnit()) { return ring.getZERO(); } return new ModLong(ring, val % S.val); } /** * ModLong multiply. * @param S ModLong. * @return this*S. */ public ModLong multiply(ModLong S) { return new ModLong(ring, val * S.val); } /** * ModLong summation. * @param S ModLong. * @return this+S. */ public ModLong sum(ModLong S) { return new ModLong(ring, val + S.val); } /** * ModInteger greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public ModLong gcd(ModLong S) { if (S.isZERO()) { return this; } if (isZERO()) { return S; } if (isUnit() || S.isUnit()) { return ring.getONE(); } return new ModLong(ring, gcd(val, S.val)); } /** * ModInteger extended greatest common divisor. * @param S ModInteger. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public ModLong[] egcd(ModLong S) { ModLong[] ret = new ModLong[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (isZERO()) { ret[0] = S; return ret; } if (isUnit() || S.isUnit()) { ret[0] = ring.getONE(); if (isUnit() && S.isUnit()) { //ModLong half = (new ModLong(ring, 2L)).inverse(); //ret[1] = this.inverse().multiply(half); //ret[2] = S.inverse().multiply(half); // (1-1*this)/S ret[1] = ring.getONE(); ModLong x = ret[0].subtract(ret[1].multiply(this)); ret[2] = x.divide(S); return ret; } if (isUnit()) { // oder inverse(S-1)? ret[1] = this.inverse(); ret[2] = ring.getZERO(); return ret; } // if ( s.isUnit() ) { // oder inverse(this-1)? ret[1] = ring.getZERO(); ret[2] = S.inverse(); return ret; //} } //System.out.println("this = " + this + ", S = " + S); long q = this.val; long r = S.val; long c1 = 1L; // BigInteger.ONE.val; long d1 = 0L; // BigInteger.ZERO.val; long c2 = 0L; // BigInteger.ZERO.val; long d2 = 1L; // BigInteger.ONE.val; long x1; long x2; while (r != 0L) { //qr = q.divideAndRemainder(r); long a = q / r; long b = q % r; q = a; x1 = c1 - q * d1; x2 = c2 - q * d2; c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = b; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); ret[0] = new ModLong(ring, q); ret[1] = new ModLong(ring, c1); ret[2] = new ModLong(ring, c2); return ret; } /** * Long greatest common divisor. * @param T long. * @param S long. * @return gcd(T,S). */ public long gcd(long T, long S) { if (S == 0L) { return T; } if (T == 0L) { return S; } long a = T; long b = S; while (b != 0L) { long r = a % b; a = b; b = r; } return a; } /** * Long half extended greatest common divisor. * @param T long. * @param S long. * @return [ gcd(T,S), a ] with a*T + b*S = gcd(T,S). */ public long[] hegcd(long T, long S) { long[] ret = new long[2]; if (S == 0L) { ret[0] = T; ret[1] = 1L; return ret; } if (T == 0L) { ret[0] = S; ret[1] = 0L; return ret; } //System.out.println("hegcd, T = " + T + ", S = " + S); long a = T; long b = S; long a1 = 1L; long b1 = 0L; while (b != 0L) { long q = a / b; long r = a % b; a = b; b = r; long r1 = a1 - q * b1; a1 = b1; b1 = r1; } if (a1 < 0L) { a1 += S; } ret[0] = a; ret[1] = a1; return ret; } /** * Long modular inverse. * @param T long. * @param m long. * @return a with with a*T = 1 mod m. */ public long modInverse(long T, long m) { if (T == 0L) { throw new NotInvertibleException("zero is not invertible"); } long[] hegcd = hegcd(T, m); long a = hegcd[0]; if (!(a == 1L || a == -1L)) { // gcd != 1 throw new ModularNotInvertibleException("element not invertible, gcd != 1", new BigInteger(m), new BigInteger(a), new BigInteger(m / a)); } long b = hegcd[1]; if (b == 0L) { // when m divides this, e.g. m.isUnit() throw new NotInvertibleException("element not invertible, divisible by modul"); } if (b < 0L) { b += m; } return b; } /** * Returns the number of bits in the representation of this ModLong, * including a sign bit. * @return number of bits in the representation of this ModLong, including a * sign bit. */ public long bitLength() { return BigInteger.bitLength(val); } } java-algebra-system-2.7.200/src/edu/jas/arith/ModLongRing.java000066400000000000000000000306231445075545500240140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import edu.jas.kern.StringUtil; /** * ModLongRing factory with RingFactory interface. Effectively immutable. * @author Heinz Kredel */ public final class ModLongRing implements ModularRingFactory, Iterable { /** * Module part of the factory data structure. */ public final long modul; /** * Random number generator. */ private final static Random random = new Random(); /** * Indicator if this ring is a field. */ private int isField = -1; // initially unknown /* * Certainty if module is probable prime. */ //private final int certainty = 10; /** * maximal representable integer. */ public final static java.math.BigInteger MAX_LONG = new java.math.BigInteger( String.valueOf(Integer.MAX_VALUE)); // not larger! /** * The constructor creates a ModLongRing object from a long integer as * module part. * @param m long integer. */ public ModLongRing(long m) { modul = m; } /** * The constructor creates a ModLongRing object from a long integer as * module part. * @param m long integer. * @param isField indicator if m is prime. */ public ModLongRing(long m, boolean isField) { modul = m; this.isField = (isField ? 1 : 0); } /** * The constructor creates a ModLongRing object from a Long integer as * module part. * @param m Long integer. */ public ModLongRing(Long m) { this(m.longValue()); } /** * The constructor creates a ModLongRing object from a Long integer as * module part. * @param m Long integer. * @param isField indicator if m is prime. */ public ModLongRing(Long m, boolean isField) { this(m.longValue(), isField); } /** * The constructor creates a ModLongRing object from a BigInteger converted * to long as module part. * @param m java.math.BigInteger. */ public ModLongRing(java.math.BigInteger m) { this(m.longValueExact()); if (MAX_LONG.compareTo(m) < 0) { // m > max //System.out.println("modul to large for long " + m + ",max=" + MAX_LONG); throw new IllegalArgumentException("modul to large for long " + m + ", max=" + MAX_LONG); } } /** * The constructor creates a ModLongRing object from a BigInteger converted * to long as module part. * @param m java.math.BigInteger. * @param isField indicator if m is prime. */ public ModLongRing(java.math.BigInteger m, boolean isField) { this(m.longValueExact(), isField); if (MAX_LONG.compareTo(m) < 0) { // m > max //System.out.println("modul to large for long " + m + ",max=" + MAX_LONG); throw new IllegalArgumentException("modul to large for long " + m + ", max=" + MAX_LONG); } } /** * The constructor creates a ModLongRing object from a String object as * module part. * @param m String. */ public ModLongRing(String m) { this(Long.valueOf(m.trim())); } /** * The constructor creates a ModLongRing object from a String object as * module part. * @param m String. * @param isField indicator if m is prime. */ public ModLongRing(String m, boolean isField) { this(Long.valueOf(m.trim()), isField); } /** * Get the module part as BigInteger. * @return modul. */ public java.math.BigInteger getModul() { return new java.math.BigInteger(Long.toString(modul)); } /** * Get the module part as long. * @return modul. */ public long getLongModul() { return modul; } /** * Get the module part as BigInteger. * @return modul. */ public BigInteger getIntegerModul() { return new BigInteger(modul); } /** * Create ModLong element c. * @param c * @return a ModLong of c. */ public ModLong create(java.math.BigInteger c) { return new ModLong(this, c); } /** * Create ModLong element c. * @param c * @return a ModLong of c. */ public ModLong create(long c) { return new ModLong(this, c); } /** * Create ModLong element c. * @param c * @return a ModLong of c. */ public ModLong create(String c) { return parse(c); } /** * Copy ModLong element c. * @param c * @return a copy of c. */ public ModLong copy(ModLong c) { return new ModLong(this, c.val); } /** * Get the zero element. * @return 0 as ModLong. */ public ModLong getZERO() { return new ModLong(this, 0L); } /** * Get the one element. * @return 1 as ModLong. */ public ModLong getONE() { return new ModLong(this, 1L); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List generators() { List g = new ArrayList(1); g.add(getONE()); return g; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return true; } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return true; } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return true; } /** * Query if this ring is a field. * @return true if module is prime, else false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } //System.out.println("isProbablePrime " + modul + " = " + modul.isProbablePrime(certainty)); java.math.BigInteger m = new java.math.BigInteger(Long.toString(modul)); if (m.isProbablePrime(m.bitLength())) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return new java.math.BigInteger(Long.toString(modul)); } /** * Get a ModLong element from a BigInteger value. * @param a BigInteger. * @return a ModLong. */ public ModLong fromInteger(java.math.BigInteger a) { return new ModLong(this, a); } /** * Get a ModLong element from a long value. * @param a long. * @return a ModLong. */ public ModLong fromInteger(long a) { return new ModLong(this, a); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return " mod(" + modul + ")"; //",max=" + MAX_LONG + ")"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python and Ruby case if (isField()) { return "GFL(" + modul + ")"; } return "ZML(" + modul + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object b) { if (!(b instanceof ModLongRing)) { return false; } ModLongRing m = (ModLongRing) b; return (modul == m.modul); } /** * Hash code for this ModLongRing. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (int) modul; } /** * ModLong random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public ModLong random(int n) { return random(n, random); } /** * ModLong random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public ModLong random(int n, Random rnd) { java.math.BigInteger v = new java.math.BigInteger(n, rnd); return new ModLong(this, v); // rnd.nextLong() not ok } /** * Parse ModLong from String. * @param s String. * @return ModLong from s. */ public ModLong parse(String s) { return new ModLong(this, s); } /** * Parse ModLong from Reader. * @param r Reader. * @return next ModLong from r. */ public ModLong parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * ModLong chinese remainder algorithm. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param c ModLong. * @param ci inverse of c.modul in ring of a. * @param a other ModLong. * @return S, with S mod c.modul == c and S mod a.modul == a. */ public ModLong chineseRemainder(ModLong c, ModLong ci, ModLong a) { //if (true) { // if (c.ring.modul < a.ring.modul) { // System.out.println("ModLong error " + c.ring + ", " + a.ring); // } //} ModLong b = a.ring.fromInteger(c.val); // c mod a.modul ModLong d = a.subtract(b); // a-c mod a.modul if (d.isZERO()) { return new ModLong(this, c.val); } b = d.multiply(ci); // b = (a-c)*ci mod a.modul // (c.modul*b)+c mod this.modul = c mod c.modul = // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul long s = c.ring.modul * b.val; s = s + c.val; return new ModLong(this, s); } /** * Modular digit list chinese remainder algorithm. m1 and m2 are positive * beta-integers, with GCD(m1,m2)=1 and m=m1*m2 less than beta. L1 and L2 * are lists of elements of Z(m1) and Z(m2) respectively. L is a list of all * a in Z(m) such that a is congruent to a1 modulo m1 and a is congruent to * a2 modulo m2 with a1 in L1 and a2 in L2. This is a factory method. Assert * c.modul ≥ a.modul and c.modul * a.modul = this.modul. * @param m1 ModLong. * @param m2 other ModLong. * @return L list of congruences. */ public static List chineseRemainder(ModLong m1, ModLong m2, List L1, List L2) { long mm = m1.ring.modul * m2.ring.modul; ModLongRing m = new ModLongRing(mm); ModLong m21 = m2.ring.fromInteger(m1.ring.modul); ModLong mi1 = m21.inverse(); List L = new ArrayList(); for (ModLong a : L1) { for (ModLong b : L2) { ModLong c = m.chineseRemainder(a, mi1, b); L.add(c); } } return L; } /** * Get a ModLong iterator. * @return a iterator over all modular integers in this ring. */ public Iterator iterator() { return new ModLongIterator(this); } } /** * Modular integer iterator. * @author Heinz Kredel */ class ModLongIterator implements Iterator { /** * data structure. */ long curr; final ModLongRing ring; /** * ModLong iterator constructor. * @param fac modular integer factory; */ public ModLongIterator(ModLongRing fac) { curr = 0L; ring = fac; } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public synchronized boolean hasNext() { return curr < ring.modul; } /** * Get next integer. * @return next integer. */ public synchronized ModLong next() { ModLong i = new ModLong(ring, curr); curr++; return i; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/arith/Modular.java000066400000000000000000000007251445075545500232400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; /** * Interface with getInteger and getSymmetricInteger methods. * @author Heinz Kredel */ public interface Modular { /** * Return a BigInteger from this Element. * @return a BigInteger of this. */ public BigInteger getInteger(); /** * Return a symmetric BigInteger from this Element. * @return a symmetric BigInteger of this. */ public BigInteger getSymmetricInteger(); } java-algebra-system-2.7.200/src/edu/jas/arith/ModularNotInvertibleException.java000066400000000000000000000053501445075545500276230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Modular integer NotInvertibleException class. Runtime Exception to be thrown * for not invertible modular integers. Container for the non-trivial factors * found by the inversion algorithm. Note: cannot be generic because of * Throwable. * @author Heinz Kredel */ public class ModularNotInvertibleException extends NotInvertibleException { public final GcdRingElem f; // = f1 * f2 public final GcdRingElem f1; public final GcdRingElem f2; public ModularNotInvertibleException() { this(null, null, null); } public ModularNotInvertibleException(String c) { this(c, null, null, null); } public ModularNotInvertibleException(String c, Throwable t) { this(c, t, null, null, null); } public ModularNotInvertibleException(Throwable t) { this(t, null, null, null); } /** * Constructor. * @param f gcd ring element with f = f1 * f2. * @param f1 gcd ring element. * @param f2 gcd ring element. */ public ModularNotInvertibleException(GcdRingElem f, GcdRingElem f1, GcdRingElem f2) { super("ModularNotInvertibleException"); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f gcd ring element with f = f1 * f2. * @param f1 gcd ring element. * @param f2 gcd ring element. */ public ModularNotInvertibleException(String c, GcdRingElem f, GcdRingElem f1, GcdRingElem f2) { super(c); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f gcd ring element with f = f1 * f2. * @param f1 gcd ring element. * @param f2 gcd ring element. */ public ModularNotInvertibleException(String c, Throwable t, GcdRingElem f, GcdRingElem f1, GcdRingElem f2) { super(c, t); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f gcd ring element with f = f1 * f2. * @param f1 gcd ring element. * @param f2 gcd ring element. */ public ModularNotInvertibleException(Throwable t, GcdRingElem f, GcdRingElem f1, GcdRingElem f2) { super("ModularNotInvertibleException", t); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String s = super.toString(); if (f != null || f1 != null || f2 != null) { s += ", f = " + f + ", f1 = " + f1 + ", f2 = " + f2; } return s; } } java-algebra-system-2.7.200/src/edu/jas/arith/ModularRingFactory.java000066400000000000000000000015561445075545500254130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.lang.Iterable; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Modular ring factory interface. Defines Chinese remainder method and get * modul method. * @author Heinz Kredel */ public interface ModularRingFactory & Modular> extends RingFactory, Iterable { /** * Return the BigInteger modul for the factory. * @return a BigInteger of this.modul. */ public BigInteger getIntegerModul(); /** * Chinese remainder algorithm. Assert c.modul ≥ a.modul and c.modul * * a.modul = this.modul. * @param c modular. * @param ci inverse of c.modul in ring of a. * @param a other ModLong. * @return S, with S mod c.modul == c and S mod a.modul == a. */ public C chineseRemainder(C c, C ci, C a); } java-algebra-system-2.7.200/src/edu/jas/arith/PrimeInteger.java000066400000000000000000001056671445075545500242420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Random; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * Integer prime factorization. Code from ALDES/SAC2 and MAS module SACPRIM. * * See ALDES/SAC2 or MAS code in SACPRIM. * See Symja org/matheclipse/core/expression/Primality.java for Pollard * algorithm. * @author Heinz Kredel */ public final class PrimeInteger { private static final Logger logger = LogManager.getLogger(PrimeInteger.class); /** * Maximal long, which can be factored by IFACT(long). Has nothing to do * with SAC2.BETA. */ final public static long BETA = PrimeList.getLongPrime(61, 1).longValue(); /** * Medium prime divisor range. */ //final static long IMPDS_MIN = 1000; // SAC2/Aldes //final static long IMPDS_MAX = 5000; // " //final static long IMPDS_MIN = 2000; //final static long IMPDS_MAX = 10000; final static long IMPDS_MIN = 10000; final static long IMPDS_MAX = 128000; /** * List of small prime numbers. */ final public static List SMPRM = smallPrimes(2, (int) (IMPDS_MIN >> 1)); /** * List of units of Z mod 210. */ final public static List UZ210 = getUZ210(); /** * Digit prime generator. K and m are positive beta-integers. L is the list * (p(1),...,p(r)) of all prime numbers p such that m le p lt m+2*K, with * p(1) lt p(2) lt ... lt p(r). * See also SACPRIM.DPGEN. * @param m start integer * @param K number of integers * @return the list L of prime numbers p with m ≤ p < m + 2*K. */ public static List smallPrimes(long m, int K) { int k; long ms; ms = m; if (ms <= 1) { ms = 1; } m = ms; if (m % 2 == 0) { m++; K--; } //if (kp % 2 == 0) { // k = kp/2; //} else { // k = (kp+1)/2; //} k = K; /* init */ long h = 2L * ((long)k - 1L); long m2 = m + h; // mp BitSet p = new BitSet(k); p.set(0, k); //for (int i = 0; i < k; i++) { // p.set(i); //} /* compute */ int r, d = 0; int i, c = 0; while (true) { switch (c) { /* mark multiples of d for d=3 and d=6n-/+1 with d**2<=m2 */ case 2: d += 2; c = 3; break; case 3: d += 4; c = 2; break; case 0: d = 3; c = 1; break; case 1: d = 5; c = 2; break; default: throw new RuntimeException("this should not happen"); } if (d > (m2 / d)) { break; } r = (int) (m % d); if (r + h >= d || r == 0) { if (r == 0) { i = 0; } else { if (r % 2 == 0) { i = d - (r / 2); } else { i = (d - r) / 2; } } if (m <= d) { i += d; } while (i < k) { p.set(i, false); i += d; } } } /* output */ int l = p.cardinality(); // l = 0 //for (i=0; i po = new ArrayList(l); if (l == 0) { return po; } //l = 0; if (ms == 1) { //po.add(2); //l++; p.set(0, false); } if (ms <= 2) { po.add(2L); //l++; } long pl = m; //System.out.println("pl = " + pl + " p[0] = " + p[0]); //System.out.println("k-1 = " + (k-1) + " p[k-1] = " + p[k-1]); for (i = 0; i < k; i++) { if (p.get(i)) { po.add(pl); //l++; } pl += 2; } //System.out.println("SMPRM = " + po); return po; } /** * Integer small prime divisors. n is a positive integer. F is a list of * primes (q(1),q(2),...,q(h)), h non-negative, q(1) le q(2) le ... lt q(h), * such that n is equal to m times the product of the q(i) and m is not * divisible by any prime in SMPRM. Either m=1 or m gt 1,000,000. *
In JAS F is a map and m=1 or m > 4.000.000. * See also SACPRIM.ISPD. * @param n integer to factor. * @param F a map of pairs of prime numbers and multiplicities (p,e) with p**e * divides n and e maximal, F is modified. * @return n/F a factor of n not divisible by any prime number in SMPRM. */ public static long smallPrimeDivisors(long n, SortedMap F) { //SortedMap F = new TreeMap(); List LP; long QL = 0; long PL; long RL = 0; boolean TL; long ML = n; LP = SMPRM; //smallPrimes(2, 500); //SMPRM; TL = false; int i = 0; do { PL = LP.get(i); QL = ML / PL; RL = ML % PL; if (RL == 0) { Integer e = F.get(PL); if (e == null) { e = 1; } else { e++; } F.put(PL, e); ML = QL; } else { i++; } TL = (QL <= PL); } while (!(TL || (i >= LP.size()))); //System.out.println("TL = " + TL + ", ML = " + ML + ", PL = " + PL + ", QL = " + QL); if (TL && (ML != 1L)) { Integer e = F.get(ML); if (e == null) { e = 1; } else { e = e + 1; } F.put(ML, e); ML = 1; } //F.put(ML, 0); // hack return ML; } /** * Integer small prime divisors. n is a positive integer. F is a list of * primes (q(1),q(2),...,q(h)), h non-negative, q(1) le q(2) le ... lt q(h), * such that n is equal to m times the product of the q(i) and m is not * divisible by any prime in SMPRM. Either m=1 or m gt 1,000,000. *
In JAS F is a map and m=1 or m > 4.000.000. * See also SACPRIM.ISPD. * @param n integer to factor. * @param F a map of pairs of prime numbers and multiplicities (p,e) with p**e * divides n and e maximal, F is modified. * @return n/F a factor of n not divisible by any prime number in SMPRM. */ public static java.math.BigInteger smallPrimeDivisors(java.math.BigInteger n, SortedMap F) { List LP; java.math.BigInteger QL = java.math.BigInteger.ZERO; java.math.BigInteger PL; java.math.BigInteger RL = java.math.BigInteger.ZERO; boolean TL; java.math.BigInteger ML = n; LP = SMPRM; //smallPrimes(2, 500); //SMPRM; TL = false; int i = 0; do { PL = java.math.BigInteger.valueOf( LP.get(i) ); java.math.BigInteger[] xx = ML.divideAndRemainder(PL); QL = xx[0]; //ML.divide(PL); RL = xx[1]; //ML.remainder(PL); if (RL.equals(java.math.BigInteger.ZERO)) { Integer e = F.get(PL); if (e == null) { e = 1; } else { e++; } F.put(PL, e); ML = QL; } else { i++; } TL = (QL.compareTo(PL) <= 0); } while (!(TL || (i >= LP.size()))); //System.out.println("TL = " + TL + ", ML = " + ML + ", PL = " + PL + ", QL = " + QL); if (TL && (!ML.equals(java.math.BigInteger.ONE))) { Integer e = F.get(ML); if (e == null) { e = 1; } else { e = e + 1; } F.put(ML, e); ML = java.math.BigInteger.ONE; } //F.put(ML, 0); // hack return ML; } /** * Integer primality test. n is a positive integer. r is true, if n is * prime, else false. * @param n integer to test. * @return true if n is prime, else false. */ public static boolean isPrime(long n) { java.math.BigInteger N = java.math.BigInteger.valueOf(n); return isPrime(N); } /** * Integer primality test. n is a positive integer. r is true, if n is * prime, else false. * @param N integer to test. * @return true if N is prime, else false. */ public static boolean isPrime(java.math.BigInteger N) { if (N.isProbablePrime(N.bitLength())) { return true; } SortedMap F = factors(N); return (F.size() == 1) && F.values().contains(1); } /** * Test prime factorization. n is a positive integer. r is true, if n = * product_i(pi**ei) and each pi is prime, else false. * @param n integer to test. * @param F a map of pairs of prime numbers (p,e) with p**e divides n. * @return true if n = product_i(pi**ei) and each pi is prime, else false. */ public static boolean isPrimeFactorization(long n, SortedMap F) { long f = 1L; for (Map.Entry m : F.entrySet()) { long p = m.getKey(); if (!isPrime(p)) { return false; } int e = m.getValue(); long pe = java.math.BigInteger.valueOf(p).pow(e).longValueExact(); f *= pe; } return n == f; } /** * Test factorization. n is a positive integer. r is true, if n = * product_i(pi**ei), else false. * @param n integer to test. * @param F a map of pairs of numbers (p,e) with p**e divides n. * @return true if n = product_i(pi**ei), else false. */ public static boolean isFactorization(long n, SortedMap F) { long f = 1L; for (Map.Entry m : F.entrySet()) { long p = m.getKey(); int e = m.getValue(); long pe = java.math.BigInteger.valueOf(p).pow(e).longValueExact(); f *= pe; } return n == f; } /** * Integer factorization. n is a positive integer. F is a list (q(1), * q(2),...,q(h)) of the prime factors of n, q(1) le q(2) le ... le q(h), * with n equal to the product of the q(i).
In JAS F is a map. * See also SACPRIM.IFACT. * @param n integer to factor. * @return a map of pairs of numbers (p,e) with p**e divides n. */ public static SortedMap factors(long n) { if (n > BETA) { throw new UnsupportedOperationException("factors(long) only for longs less than BETA: " + BETA); } long ML, PL, AL, BL, CL, MLP, RL, SL; SortedMap F = new TreeMap(); SortedMap FP = null; // search small prime factors ML = smallPrimeDivisors(n, F); // , F, ML if (ML == 1L) { return F; } //System.out.println("F = " + F); // search medium prime factors AL = IMPDS_MIN; do { MLP = ML - 1; RL = (new ModLong(new ModLongRing(ML), 3)).power(MLP).getVal(); //(3**MLP) mod ML; if (RL == 1L) { FP = factors(MLP); SL = primalityTestSelfridge(ML, MLP, FP); if (SL == 1) { logger.info("primalityTestSelfridge: FP = {}", FP); Integer e = F.get(ML); if (e == null) { e = 1; } else { // will not happen e = e + 1; } F.put(ML, e); return F; } } CL = Roots.sqrtInt(new BigInteger(ML)).getVal().longValue(); //SACI.ISQRT( ML, CL, TL ); //System.out.println("CL = " + CL + ", ML = " + ML + ", CL^2 = " + (CL*CL)); BL = Math.max(IMPDS_MAX, CL / 3L); if (AL > BL) { PL = 1L; } else { logger.info("mediumPrimeDivisorSearch: a = {}, b = {}", AL, BL); PL = mediumPrimeDivisorSearch(ML, AL, BL); //, PL, ML ); //System.out.println("PL = " + PL); if (PL != 1L) { AL = PL; Integer e = F.get(PL); if (e == null) { e = 1; } else { e = e + 1; } F.put(PL, e); ML = ML / PL; } } } while (PL != 1L); // fixed: the ILPDS should also be in the while loop, was already wrong in SAC2/Aldes and MAS // seems to be okay for integers smaller than beta java.math.BigInteger N = java.math.BigInteger.valueOf(ML); if (N.isProbablePrime(N.bitLength())) { F.put(ML, 1); return F; } AL = BL; BL = CL; logger.info("largePrimeDivisorSearch: a = {}, b = {}, m = {}", AL, BL, ML); // search large prime factors do { //ILPDS( ML, AL, BL, PL, ML ); PL = largePrimeDivisorSearch(ML, AL, BL); if (PL != 1L) { Integer e = F.get(PL); if (e == null) { e = 1; } else { e++; } F.put(PL, e); ML = ML / PL; AL = PL; CL = Roots.sqrtInt(BigInteger.valueOf(ML)).getVal().longValue(); //SACI.ISQRT( ML, CL, TL ); //System.out.println("CL = " + CL + ", ML = " + ML + ", CL^2 = " + (CL*CL)); BL = Math.min(BL, CL); if (AL > BL) { PL = 1L; } } } while (PL != 1L); //System.out.println("PL = " + PL + ", ML = " + ML); if (ML != 1L) { Integer e = F.get(ML); if (e == null) { e = 1; } else { e = e + 1; } F.put(ML, e); } return F; } /** * Integer factorization, Pollard rho algorithm. n is a positive integer. F * is a list (q(1), q(2),...,q(h)) of the prime factors of n, q(1) le q(2) * le ... le q(h), with n equal to the product of the q(i).
In * JAS F is a map. * See also SACPRIM.IFACT. * @param n integer to factor. * @return a map F of pairs of numbers (p,e) with p**e divides n and p * probable prime. */ public static SortedMap factorsPollard(long n) { if (n > BETA) { throw new UnsupportedOperationException("factors(long) only for longs less than BETA: " + BETA); } SortedMap F = new TreeMap(); factorsPollardRho(n, F); return F; } /** * Integer medium prime divisor search. n, a and b are positive integers * such that a le b le n and n has no positive divisors less than a. If n * has a prime divisor in the closed interval from a to b then p is the * least such prime and q=n/p. Otherwise p=1 and q=n. * See also SACPRIM.IMPDS. * @param n integer to factor. * @param a lower bound. * @param b upper bound. * @return p a prime factor of n, with a ≤ p ≤ b < n. */ public static long mediumPrimeDivisorSearch(long n, long a, long b) { List LP; long R, J1Y, RL1, RL2, RL, PL; RL = a % 210; LP = UZ210; long ll = LP.size(); int i = 0; while (RL > LP.get(i)) { i++; } RL1 = LP.get(i); PL = a + (RL1 - RL); //System.out.println("PL = " + PL + ", BL = " + BL); while (PL <= b) { R = n % PL; //SACI.IQR( NL, PL, QL, R ); if (R == 0) { return PL; } i++; if (i >= ll) { LP = UZ210; RL2 = (RL1 - 210L); i = 0; } else { RL2 = RL1; } RL1 = LP.get(i); J1Y = (RL1 - RL2); PL = PL + J1Y; } PL = 1L; //SACI.IONE; //QL = NL; return PL; } /** * Integer selfridge primality test. m is an integer greater than or equal * to 3. mp=m-1. F is a list (q(1),q(2),...,q(k)), q(1) le q(2) le ... le * q(k), of the prime factors of mp, with mp equal to the product of the * q(i). An attempt is made to find a root of unity modulo m of order m-1. * If the existence of such a root is discovered then m is prime and s=1. If * it is discovered that no such root exists then m is not a prime and s=-1. * Otherwise the primality of m remains uncertain and s=0. * See also SACPRIM.ISPT. * @param m integer to test. * @param mp integer m-1. * @param F a map of pairs (p,e), with primes p, multiplicity e and with * p**e divides mp and e maximal. * @return s = -1 (not prime), 0 (unknown) or 1 (prime). */ public static int primalityTestSelfridge(long m, long mp, SortedMap F) { long AL, BL, QL, QL1, MLPP, PL1, PL; int SL; //List SMPRM = smallPrimes(2, 500); //SMPRM; List PP; List> FP = new ArrayList>(F.entrySet()); QL1 = 1L; //SACI.IONE; PL1 = 1L; int i = 0; while (true) { do { if (i == FP.size()) { logger.info("SL=1: m = {}", m); SL = 1; return SL; } QL = FP.get(i).getKey(); i++; } while (!(QL > QL1)); QL1 = QL; PP = SMPRM; int j = 0; do { if (j == PP.size()) { logger.info("SL=0: m = {}", m); SL = 0; return SL; } PL = PP.get(j); j++; if (PL > PL1) { PL1 = PL; AL = (new ModLong(new ModLongRing(m), PL)).power(mp).getVal(); //(PL**MLP) mod ML; if (AL != 1) { logger.info("SL=-1: m = {}", m); SL = (-1); return SL; } } MLPP = mp / QL; BL = (new ModLong(new ModLongRing(m), PL)).power(MLPP).getVal(); //(PL**MLPP) mod ML; } while (BL == 1L); } } /** * Integer large prime divisor search. n is a positive integer with no prime * divisors less than 17. 1 le a le b le n. A search is made for a divisor p * of the integer n, with a le p le b. If such a p is found then np=n/p, * otherwise p=1 and np=n. A modular version of Fermats method is used, and * the search goes from a to b. * See also SACPRIM.ILPDS. * @param n integer to factor. * @param a lower bound. * @param b upper bound. * @return p a prime factor of n, with a ≤ p ≤ b < n. */ public static long largePrimeDivisorSearch(long n, long a, long b) { // return PL, NLP ignored if (n > BETA) { throw new UnsupportedOperationException( "largePrimeDivisorSearch only for longs less than BETA: " + BETA); } List L = null; List LP; long RL1, RL2, J1Y, r, PL, TL; long RL, J2Y, XL1, XL2, QL, XL, YL, YLP; long ML = 0L; long SL = 0L; QL = n / b; RL = n % b; XL1 = b + QL; SL = XL1 % 2L; XL1 = XL1 / 2L; // after SL if ((RL != 0) || (SL != 0)) { XL1 = XL1 + 1L; } QL = n / a; XL2 = a + QL; XL2 = XL2 / 2L; L = residueListFermat(n); //FRESL( NL, ML, L ); // ML not returned if (L.isEmpty()) { return n; } ML = L.get(0).ring.getModul().longValue(); // sic // check is okay: sort: L = SACSET.LBIBMS( L ); revert: L = MASSTOR.INV( L ); Collections.sort(L); Collections.reverse(L); //System.out.println("FRESL: " + L); r = XL2 % ML; LP = L; int i = 0; while (i < LP.size() && r < LP.get(i).getVal()) { i++; } if (i == LP.size()) { i = 0; //LP = L; SL = ML; } else { SL = 0L; } RL1 = LP.get(i).getVal(); i++; SL = ((SL + r) - RL1); XL = XL2 - SL; TL = 0L; while (XL >= XL1) { J2Y = XL * XL; YLP = J2Y - n; //System.out.println("YLP = " + YLP + ", J2Y = " + J2Y); YL = Roots.sqrtInt(BigInteger.valueOf(YLP)).getVal().longValue(); // SACI.ISQRT( YLP, YL, TL ); //System.out.println("YL = sqrt(YLP) = " + YL); TL = YLP - YL * YL; if (TL == 0L) { PL = XL - YL; return PL; } if (i < LP.size()) { RL2 = LP.get(i).getVal(); i++; SL = (RL1 - RL2); } else { i = 0; RL2 = LP.get(i).getVal(); i++; J1Y = (ML + RL1); SL = (J1Y - RL2); } RL1 = RL2; XL = XL - SL; } PL = 1L; // unused NLP = NL; return PL; } /** * Fermat residue list, single modulus. m is a positive beta-integer. a * belongs to Z(m). L is a list of the distinct b in Z(m) such that b**2-a * is a square in Z(m). * See also SACPRIM.FRLSM. * @param m integer to factor. * @param a element of Z mod m. * @return Lp a list of Fermat residues for modul m. */ public static List residueListFermatSingle(long m, long a) { List Lp; SortedSet L; List S, SP; int MLP; ModLong SL, SLP, SLPP; ModLongRing ring = new ModLongRing(m); ModLong am = ring.fromInteger(a); MLP = (int) (m / 2L); S = new ArrayList(); for (int i = 0; i <= MLP; i++) { SL = ring.fromInteger(i); SL = SL.multiply(SL); //SACM.MDPROD( ML, IL, IL ); S.add(SL); } L = new TreeSet(); SP = S; for (int i = MLP; i >= 0; i -= 1) { SL = SP.get(i); SLP = SL.subtract(am); //SACM.MDDIF( ML, SL, AL ); int j = S.indexOf(SLP); if (j >= 0) { // != 0 SLP = ring.fromInteger(i); L.add(SLP); SLPP = SLP.negate(); if (!SLPP.equals(SLP)) { L.add(SLPP); } } } Lp = new ArrayList(L); return Lp; } /** * Fermat residue list. n is a positive integer with no prime divisors less * than 17. m is a positive beta-integer and L is an ordered list of the * elements of Z(m) such that if x**2-n is a square then x is congruent to a * (modulo m) for some a in L. * See also SACPRIM.FRESL. * @param n integer to factor. * @return Lp a list of Fermat residues for different modules. */ public static List residueListFermat(long n) { List L, L1; List H, M; long AL1, AL2, AL3, AL4, BL1, HL, J1Y, J2Y, KL, KL1, ML1, ML; //too large: long BETA = Long.MAX_VALUE - 1L; // modulus 2**5. BL1 = 0L; AL1 = n % 32L; AL2 = AL1 % 16L; AL3 = AL2 % 8L; AL4 = AL3 % 4L; if (AL4 == 3L) { ML = 4L; if (AL3 == 3L) { BL1 = 2L; } else { BL1 = 0L; } } else { if (AL3 == 1L) { ML = 8L; if (AL2 == 1L) { BL1 = 1L; } else { BL1 = 3L; } } else { ML = 16L; switch ((short) (AL1 / 8L)) { case (short) 0: BL1 = 3L; break; case (short) 1: BL1 = 7L; break; case (short) 2: BL1 = 5L; break; case (short) 3: BL1 = 1L; break; default: throw new RuntimeException("this should not happen"); } } } L = new ArrayList(); ModLongRing ring = new ModLongRing(ML); ModLongRing ring2; if (ML == 4L) { L.add(ring.fromInteger(BL1)); } else { J1Y = ML - BL1; L.add(ring.fromInteger(BL1)); L.add(ring.fromInteger(J1Y)); } KL = L.size(); // modulus 3**3. AL1 = n % 27L; AL2 = AL1 % 3L; if (AL2 == 2L) { ML1 = 3L; ring2 = new ModLongRing(ML1); KL1 = 1L; L1 = new ArrayList(); L1.add(ring2.fromInteger(0)); } else { ML1 = 27L; ring2 = new ModLongRing(ML1); KL1 = 4L; L1 = residueListFermatSingle(ML1, AL1); // ring2 == L1.get(0).ring } //L = SACM.MDLCRA( ML, ML1, L, L1 ); L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1); ML = (ML * ML1); ring = new ModLongRing(ML); // == L.get(0).ring KL = (KL * KL1); //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript()); // modulus 5**2. AL1 = n % 25L; AL2 = AL1 % 5L; if ((AL2 == 2L) || (AL2 == 3L)) { ML1 = 5L; ring2 = new ModLongRing(ML1); J1Y = (AL2 - 1L); J2Y = (6L - AL2); L1 = new ArrayList(); L1.add(ring2.fromInteger(J1Y)); L1.add(ring2.fromInteger(J2Y)); KL1 = 2L; } else { ML1 = 25L; ring2 = new ModLongRing(ML1); L1 = residueListFermatSingle(ML1, AL1); KL1 = 7L; } if (ML1 >= BETA / ML) { return L; } //L = SACM.MDLCRA( ML, ML1, L, L1 ); L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1); ML = (ML * ML1); ring = new ModLongRing(ML); KL = (KL * KL1); //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript()); // moduli 7,11,13. L1 = new ArrayList(); M = new ArrayList(3); H = new ArrayList(3); //M = MASSTOR.COMPi( 7, MASSTOR.COMPi( 11, 13 ) ); M.add(7L); M.add(11L); M.add(13L); //H = MASSTOR.COMPi( 64, MASSTOR.COMPi( 48, 0 ) ); H.add(64L); H.add(48L); H.add(0L); int i = 0; while (true) { ML1 = M.get(i); if (ML1 >= BETA / ML) { return L; } ring2 = new ModLongRing(ML1); AL1 = n % ML1; L1 = residueListFermatSingle(ML1, AL1); KL1 = L1.size(); //L = SACM.MDLCRA( ML, ML1, L, L1 ); L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1); ML = (ML * ML1); ring = new ModLongRing(ML); KL = (KL * KL1); //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript()); HL = H.get(i); i++; if (KL > HL) { return L; } } // return ? } /** * Compute units of Z sub 210. * See also SACPRIM.UZ210. * @return list of units of Z sub 210. */ public static List getUZ210() { List UZ = new ArrayList(); java.math.BigInteger z210 = java.math.BigInteger.valueOf(210); //for (int i = 209; i >= 1; i -= 2) { for (long i = 1; i <= 209; i += 2) { if (z210.gcd(java.math.BigInteger.valueOf(i)).equals(java.math.BigInteger.ONE)) { UZ.add(i); } } return UZ; } /** * Integer factorization. n is a positive integer. F is a list (q(1), * q(2),...,q(h)) of the prime factors of n, q(1) le q(2) le ... le q(h), * with n equal to the product of the q(i).
In JAS F is a map. * See also SACPRIM.IFACT, uses Pollards rho method. * @param n integer to factor. * @return a map of pairs of numbers (p,e) with p**e divides n. */ public static SortedMap factors(java.math.BigInteger n) { java.math.BigInteger b = java.math.BigInteger.valueOf(BETA); SortedMap F = new TreeMap(); if (n.compareTo(b) > 0) { n = smallPrimeDivisors(n, F); if (n.compareTo(b) > 0) { logger.info("run factorsPollardRho on n = {}", n); factorsPollardRho(n, F); return F; } } // n <= beta long s = n.longValue(); SortedMap ff = factors(s); // useless 2nd smallPrimeDiv search for (Map.Entry m : ff.entrySet()) { java.math.BigInteger mm = java.math.BigInteger.valueOf(m.getKey()); F.put(mm, m.getValue()); } return F; } /** * Integer factorization using Pollards rho algorithm. n is a positive * integer. F is a list (q(1), q(2),...,q(h)) of the prime factors of n, * q(1) le q(2) le ... le q(h), with n equal to the product of the q(i). *
In JAS F is a map. * @param n integer to factor. * @param F a map of pairs of numbers (p,e) with p**e divides n and p is * probable prime, F is modified. */ public static void factorsPollardRho(java.math.BigInteger n, SortedMap F) { java.math.BigInteger factor; java.math.BigInteger temp = n; int iterationCounter = 0; Integer count; while (!temp.isProbablePrime(32)) { factor = rho(temp); if (factor.equals(temp)) { if (iterationCounter++ > 4) { break; } } else { iterationCounter = 1; } count = F.get(factor); if (count == null) { F.put(factor, 1); } else { F.put(factor, count + 1); } temp = temp.divide(factor); } count = F.get(temp); if (count == null) { F.put(temp, 1); } else { F.put(temp, count + 1); } } /** * Random number generator. */ //final static SecureRandom random = new SecureRandom(); final static Random random = new Random(); /** * Search cycle with Pollards rho algorithm x**2 + c mod n. n is a positive * integer.
* @param n integer test. * @return x-y with gcd(x-y, n) = 1. */ static java.math.BigInteger rho(java.math.BigInteger n) { java.math.BigInteger divisor; java.math.BigInteger c = new java.math.BigInteger(n.bitLength(), random); java.math.BigInteger x = new java.math.BigInteger(n.bitLength(), random); java.math.BigInteger xx = x; do { x = x.multiply(x).mod(n).add(c).mod(n); xx = xx.multiply(xx).mod(n).add(c).mod(n); xx = xx.multiply(xx).mod(n).add(c).mod(n); divisor = x.subtract(xx).gcd(n); } while (divisor.equals(java.math.BigInteger.ONE)); return divisor; } /** * Integer factorization using Pollards rho algorithm. n is a positive * integer. F is a list (q(1), q(2),...,q(h)) of the prime factors of n, * q(1) le q(2) le ... le q(h), with n equal to the product of the q(i). *
In JAS F is a map. * @param n integer to factor. * @param F a map of pairs of numbers (p,e) with p**e divides n and p is * probable prime, F is modified. */ public static void factorsPollardRho(long n, SortedMap F) { long factor; long temp = n; int iterationCounter = 0; Integer count; while (!java.math.BigInteger.valueOf(temp).isProbablePrime(32)) { factor = rho(temp); if (factor == temp) { if (iterationCounter++ > 4) { break; } } else { iterationCounter = 1; } count = F.get(factor); if (count == null) { F.put(factor, 1); } else { F.put(factor, count + 1); } temp = temp / factor; } count = F.get(temp); if (count == null) { F.put(temp, 1); } else { F.put(temp, count + 1); } //System.out.println("random = " + random.getAlgorithm()); } /** * Search cycle with Pollards rho algorithm x**2 + c mod n. n is a positive * integer. c is a random constant. * @param n integer test. * @return x-y with gcd(x-y, n) == 1. */ static long rho(long n) { long divisor; int bl = java.math.BigInteger.valueOf(n).bitLength(); long c = new java.math.BigInteger(bl, random).longValue(); // .abs() long x = new java.math.BigInteger(bl, random).longValue(); // .abs() ModLongRing ring = new ModLongRing(n); ModLong cm = new ModLong(ring, c); ModLong xm = new ModLong(ring, x); ModLong xxm = xm; do { xm = xm.multiply(xm).sum(cm); xxm = xxm.multiply(xxm).sum(cm); xxm = xxm.multiply(xxm).sum(cm); divisor = gcd(xm.getVal() - xxm.getVal(), n); } while (divisor == 1L); return divisor; } static long gcd(long a, long b) { return BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).getVal().longValue(); } } java-algebra-system-2.7.200/src/edu/jas/arith/PrimeList.java000066400000000000000000000257001445075545500235450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * List of big primes. Provides an Iterator for generating prime numbers. * Similar to ALDES/SAC2 SACPOL.PRIME list. * See Knuth vol 2, page 390, for list of known primes. See also ALDES/SAC2 * SACPOL.PRIME * * @author Heinz Kredel */ public final class PrimeList implements Iterable { /** * Range of probable primes. */ public static enum Range { small, low, medium, large, mersenne }; /** * Cache the val list for different size */ private volatile static List SMALL_LIST = null; private volatile static List LOW_LIST = null; private volatile static List MEDIUM_LIST = null; private volatile static List LARGE_LIST = null; private volatile static List MERSENNE_LIST = null; /** * The list of probable primes in requested range. */ private List val = null; /** * The last prime in the list. */ private java.math.BigInteger last; /** * Constructor for PrimeList. */ public PrimeList() { this(Range.medium); } /** * Constructor for PrimeList. * * @param r size range for primes. */ public PrimeList(Range r) { // initialize with some known primes, see knuth (2,390) switch (r) { case small: if (SMALL_LIST != null) { val = SMALL_LIST; } else { val = new ArrayList(50); addSmall(); SMALL_LIST = val; } break; case low: if (LOW_LIST != null) { val = LOW_LIST; } else { val = new ArrayList(50); addLow(); LOW_LIST = val; } break; default: case medium: if (MEDIUM_LIST != null) { val = MEDIUM_LIST; } else { val = new ArrayList(50); addMedium(); MEDIUM_LIST = val; } break; case large: if (LARGE_LIST != null) { val = LARGE_LIST; } else { val = new ArrayList(50); addLarge(); LARGE_LIST = val; } break; case mersenne: if (MERSENNE_LIST != null) { val = MERSENNE_LIST; } else { val = new ArrayList(50); addMersenne(); MERSENNE_LIST = val; } break; } last = get(size() - 1); } /** * Add small primes. */ private void addSmall() { // really small val.add(java.math.BigInteger.valueOf(2L)); val.add(java.math.BigInteger.valueOf(3L)); val.add(java.math.BigInteger.valueOf(5L)); val.add(java.math.BigInteger.valueOf(7L)); val.add(java.math.BigInteger.valueOf(11L)); val.add(java.math.BigInteger.valueOf(13L)); val.add(java.math.BigInteger.valueOf(17L)); val.add(java.math.BigInteger.valueOf(19L)); val.add(java.math.BigInteger.valueOf(23L)); val.add(java.math.BigInteger.valueOf(29L)); } /** * Add low sized primes. */ private void addLow() { // 2^15-x val.add(getLongPrime(15, 19)); val.add(getLongPrime(15, 49)); val.add(getLongPrime(15, 51)); val.add(getLongPrime(15, 55)); val.add(getLongPrime(15, 61)); val.add(getLongPrime(15, 75)); val.add(getLongPrime(15, 81)); val.add(getLongPrime(15, 115)); val.add(getLongPrime(15, 121)); val.add(getLongPrime(15, 135)); // 2^16-x val.add(getLongPrime(16, 15)); val.add(getLongPrime(16, 17)); val.add(getLongPrime(16, 39)); val.add(getLongPrime(16, 57)); val.add(getLongPrime(16, 87)); val.add(getLongPrime(16, 89)); val.add(getLongPrime(16, 99)); val.add(getLongPrime(16, 113)); val.add(getLongPrime(16, 117)); val.add(getLongPrime(16, 123)); } /** * Add medium sized primes. */ private void addMedium() { // 2^28-x val.add(getLongPrime(28, 57)); val.add(getLongPrime(28, 89)); val.add(getLongPrime(28, 95)); val.add(getLongPrime(28, 119)); val.add(getLongPrime(28, 125)); val.add(getLongPrime(28, 143)); val.add(getLongPrime(28, 165)); val.add(getLongPrime(28, 183)); val.add(getLongPrime(28, 213)); val.add(getLongPrime(28, 273)); // 2^29-x val.add(getLongPrime(29, 3)); val.add(getLongPrime(29, 33)); val.add(getLongPrime(29, 43)); val.add(getLongPrime(29, 63)); val.add(getLongPrime(29, 73)); val.add(getLongPrime(29, 75)); val.add(getLongPrime(29, 93)); val.add(getLongPrime(29, 99)); val.add(getLongPrime(29, 121)); val.add(getLongPrime(29, 133)); // 2^32-x val.add(getLongPrime(32, 5)); val.add(getLongPrime(32, 17)); val.add(getLongPrime(32, 65)); val.add(getLongPrime(32, 99)); val.add(getLongPrime(32, 107)); val.add(getLongPrime(32, 135)); val.add(getLongPrime(32, 153)); val.add(getLongPrime(32, 185)); val.add(getLongPrime(32, 209)); val.add(getLongPrime(32, 267)); } /** * Add large sized primes. */ private void addLarge() { // 2^59-x val.add(getLongPrime(59, 55)); val.add(getLongPrime(59, 99)); val.add(getLongPrime(59, 225)); val.add(getLongPrime(59, 427)); val.add(getLongPrime(59, 517)); val.add(getLongPrime(59, 607)); val.add(getLongPrime(59, 649)); val.add(getLongPrime(59, 687)); val.add(getLongPrime(59, 861)); val.add(getLongPrime(59, 871)); // 2^60-x val.add(getLongPrime(60, 93)); val.add(getLongPrime(60, 107)); val.add(getLongPrime(60, 173)); val.add(getLongPrime(60, 179)); val.add(getLongPrime(60, 257)); val.add(getLongPrime(60, 279)); val.add(getLongPrime(60, 369)); val.add(getLongPrime(60, 395)); val.add(getLongPrime(60, 399)); val.add(getLongPrime(60, 453)); // 2^63-x val.add(getLongPrime(63, 25)); val.add(getLongPrime(63, 165)); val.add(getLongPrime(63, 259)); val.add(getLongPrime(63, 301)); val.add(getLongPrime(63, 375)); val.add(getLongPrime(63, 387)); val.add(getLongPrime(63, 391)); val.add(getLongPrime(63, 409)); val.add(getLongPrime(63, 457)); val.add(getLongPrime(63, 471)); // 2^64-x not possible } /** * Add Mersenne sized primes. */ private void addMersenne() { // 2^n-1 val.add(getMersennePrime(2)); val.add(getMersennePrime(3)); val.add(getMersennePrime(5)); val.add(getMersennePrime(7)); val.add(getMersennePrime(13)); val.add(getMersennePrime(17)); val.add(getMersennePrime(19)); val.add(getMersennePrime(31)); val.add(getMersennePrime(61)); val.add(getMersennePrime(89)); val.add(getMersennePrime(107)); val.add(getMersennePrime(127)); val.add(getMersennePrime(521)); val.add(getMersennePrime(607)); val.add(getMersennePrime(1279)); val.add(getMersennePrime(2203)); val.add(getMersennePrime(2281)); val.add(getMersennePrime(3217)); val.add(getMersennePrime(4253)); val.add(getMersennePrime(4423)); val.add(getMersennePrime(9689)); val.add(getMersennePrime(9941)); val.add(getMersennePrime(11213)); val.add(getMersennePrime(19937)); } /** * Method to compute a prime as 2**n - m. * @param n power for 2. * @param m for 2**n - m. * @return 2**n - m */ public static java.math.BigInteger getLongPrime(int n, int m) { if (n < 30) { return java.math.BigInteger.valueOf((1 << n) - m); } return java.math.BigInteger.ONE.shiftLeft(n).subtract(java.math.BigInteger.valueOf(m)); } /** * Method to compute a Mersenne prime as 2**n - 1. * @param n power for 2. * @return 2**n - 1 */ public static java.math.BigInteger getMersennePrime(int n) { return java.math.BigInteger.ONE.shiftLeft(n).subtract(java.math.BigInteger.ONE); } /** * Check if the list contains really prime numbers. * @return true if all checked numbers are prime */ protected boolean checkPrimes() { return checkPrimes(size()); } /** * Check if the list contains really prime numbers. * @param n number of primes to check. * @return true if all checked numbers are prime */ protected boolean checkPrimes(int n) { boolean isPrime; int i = 0; for (java.math.BigInteger p : val) { if (i++ >= n) { break; } isPrime = p.isProbablePrime(63); if (!isPrime) { System.out.println("not prime = " + p); return false; } } return true; } /** * {@inheritDoc} */ @Override public String toString() { return val.toString(); } /** * Size of current list. * @return current size of list. */ public int size() { return val.size(); } /** * Get prime at index i. * @param i index to get element. * @return prime at index i. */ public java.math.BigInteger get(int i) { java.math.BigInteger p; if (i < size()) { p = val.get(i); } else if (i == size()) { p = last.nextProbablePrime(); val.add(p); last = p; } else { p = get(i - 1); p = last.nextProbablePrime(); val.add(p); last = p; } return p; } /** * Iterator. * Always has next, will generate new primes if required. * @return iterator over the prime list. */ public Iterator iterator() { return new Iterator() { int index = -1; public boolean hasNext() { return true; } public void remove() { throw new UnsupportedOperationException("remove not implemented"); } public java.math.BigInteger next() { index++; return get(index); } }; } } java-algebra-system-2.7.200/src/edu/jas/arith/Product.java000066400000000000000000000520121445075545500232510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RegularRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Direct product element based on RingElem. Objects of this class are (nearly) * immutable. * @author Heinz Kredel */ public class Product> implements RegularRingElem> { private static final Logger logger = LogManager.getLogger(Product.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Product class factory data structure. */ public final ProductRing ring; /** * Value part of the element data structure. */ public final SortedMap val; /** * Flag to remember if this product element is a unit in each cmponent. -1 * is unknown, 1 is unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a Product object from a ring factory. * @param r ring factory. */ public Product(ProductRing r) { this(r, new TreeMap(), 0); } /** * The constructor creates a Product object from a ring factory and a ring * element. * @param r ring factory. * @param a ring element. */ public Product(ProductRing r, SortedMap a) { this(r, a, -1); } /** * The constructor creates a Product object from a ring factory, a ring * element and an indicator if a is a unit. * @param r ring factory. * @param a ring element. * @param u isunit indicator, -1, 0, 1. */ public Product(ProductRing r, SortedMap a, int u) { ring = r; val = a; isunit = u; } /** * Get component. * @param i index of component. * @return val(i). */ public C get(int i) { return val.get(i); // auto-boxing } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ProductRing factory() { return ring; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Product copy() { return new Product(ring, val, isunit); } /** * Is Product zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.size() == 0; } /** * Is Product one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (val.size() != ring.length()) { return false; } for (C e : val.values()) { if (!e.isONE()) { return false; } } return true; } /** * Is Product full. * @return If every component is non-zero, then true is returned, else * false. */ public boolean isFull() { if (val.size() != ring.length()) { return false; } return true; } /** * Is Product unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } if (isZERO()) { isunit = 0; return false; } for (C e : val.values()) { if (!e.isUnit()) { isunit = 0; return false; } } isunit = 1; return true; } /** * Is Product idempotent. * @return If this is a idempotent element then true is returned, else * false. */ public boolean isIdempotent() { for (C e : val.values()) { if (!e.isONE()) { return false; } } return true; } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { return val.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("( "); boolean first = true; for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C v = me.getValue(); if (first) { first = false; } else { if (v.signum() < 0) { s.append(" - "); v = v.negate(); } else { s.append(" + "); } } if (!v.isONE()) { s.append(v.toScript() + "*"); } s.append("pg" + i); } s.append(" )"); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Product comparison. * @param b Product. * @return sign(this-b). */ @Override public int compareTo(Product b) { if (!ring.equals(b.ring)) { logger.info("other ring {}", b.ring); throw new IllegalArgumentException("rings not comparable " + this); } SortedMap v = b.val; Iterator> ti = val.entrySet().iterator(); Iterator> bi = v.entrySet().iterator(); int s; while (ti.hasNext() && bi.hasNext()) { Map.Entry te = ti.next(); Map.Entry be = bi.next(); s = te.getKey().compareTo(be.getKey()); if (s != 0) { return s; } s = te.getValue().compareTo(be.getValue()); if (s != 0) { return s; } } if (ti.hasNext()) { return -1; } if (bi.hasNext()) { return 1; } return 0; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Product)) { return false; } Product a = (Product) b; return (0 == compareTo(a)); } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = ring.hashCode(); h = 37 * h + val.hashCode(); return h; } /** * Product extend. Add new component j with value of component i. * @param i from index. * @param j to index. * @return the extended value of this. */ public Product extend(int i, int j) { RingFactory rf = ring.getFactory(j); SortedMap elem = new TreeMap(val); C v = val.get(i); C w = rf.copy(v); // valueOf if (!w.isZERO()) { elem.put(j, w); } return new Product(ring, elem, isunit); } /** * Product absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Product abs() { SortedMap elem = new TreeMap(); for (Map.Entry e : val.entrySet()) { Integer i = e.getKey(); C v = e.getValue().abs(); elem.put(i, v); } return new Product(ring, elem, isunit); } /** * Product summation. * @param S Product. * @return this+S. */ public Product sum(Product S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } SortedMap elem = new TreeMap(val); // clone SortedMap sel = S.val; for (Map.Entry is : sel.entrySet()) { Integer i = is.getKey(); C x = elem.get(i); C y = is.getValue(); //sel.get( i ); // assert y != null if (x != null) { x = x.sum(y); if (!x.isZERO()) { elem.put(i, x); } else { elem.remove(i); } } else { elem.put(i, y); } } return new Product(ring, elem); } /** * Product negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Product negate() { SortedMap elem = new TreeMap(); for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C v = me.getValue().negate(); elem.put(i, v); } return new Product(ring, elem, isunit); } /** * Product signum. * @see edu.jas.structure.RingElem#signum() * @return signum of first non-zero component. */ public int signum() { if (val.size() == 0) { return 0; } C v = val.get(val.firstKey()); return v.signum(); } /** * Product subtraction. * @param S Product. * @return this-S. */ public Product subtract(Product S) { return sum(S.negate()); } /** * Product quasi-inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public Product inverse() { if (this.isZERO()) { return this; } int isu = 0; SortedMap elem = new TreeMap(); for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C x = me.getValue(); // is non zero try { x = x.inverse(); } catch (NotInvertibleException e) { // could happen for e.g. ModInteger or AlgebraicNumber x = null; //ring.getFactory(i).getZERO(); } if (x != null && !x.isZERO()) { // can happen elem.put(i, x); isu = 1; } } return new Product(ring, elem, isu); } /** * Product idempotent. * @return smallest S with this*S = this. */ public Product idempotent() { if (this.isZERO()) { return this; } SortedMap elem = new TreeMap(); for (Integer i : val.keySet()) { RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); } return new Product(ring, elem, 1); } /** * Product idempotent complement. * @return 1-this.idempotent(). */ public Product idemComplement() { if (this.isZERO()) { return ring.getONE(); } int isu = 0; SortedMap elem = new TreeMap(); for (int i = 0; i < ring.length(); i++) { C v = val.get(i); if (v == null) { RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); isu = 1; } } return new Product(ring, elem, isu); } /** * Product idempotent and. * @param S Product. * @return this.idempotent() and S.idempotent(). */ public Product idempotentAnd(Product S) { if (this.isZERO() && S.isZERO()) { return this; } int isu = 0; SortedMap elem = new TreeMap(); for (int i = 0; i < ring.length(); i++) { C v = val.get(i); C w = S.val.get(i); if (v != null && w != null) { RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); isu = 1; } } return new Product(ring, elem, isu); } /** * Product idempotent or. * @param S Product. * @return this.idempotent() or S.idempotent(). */ public Product idempotentOr(Product S) { if (this.isZERO() && S.isZERO()) { return this; } int isu = 0; SortedMap elem = new TreeMap(); for (int i = 0; i < ring.length(); i++) { C v = val.get(i); C w = S.val.get(i); if (v != null || w != null) { RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); isu = 1; } } return new Product(ring, elem, isu); } /** * Product fill with idempotent. * @param S Product. * @return fill this with S.idempotent(). */ public Product fillIdempotent(Product S) { if (S.isZERO()) { return this; } SortedMap elem = new TreeMap(val); for (int i = 0; i < ring.length(); i++) { C v = elem.get(i); if (v != null) { continue; } C w = S.val.get(i); if (w != null) { RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); } } return new Product(ring, elem, isunit); } /** * Product fill with one. * @return fill this with one. */ public Product fillOne() { if (this.isFull()) { return this; } if (this.isZERO()) { return ring.getONE(); } SortedMap elem = new TreeMap(val); for (int i = 0; i < ring.length(); i++) { C v = elem.get(i); if (v != null) { continue; } RingFactory f = ring.getFactory(i); C x = f.getONE(); elem.put(i, x); } return new Product(ring, elem, isunit); } /** * Product quasi-division. * @param S Product. * @return this/S. */ public Product divide(Product S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return S; } if (this.isZERO()) { return this; } SortedMap elem = new TreeMap(); SortedMap sel = S.val; for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C y = sel.get(i); if (y != null) { C x = me.getValue(); try { x = x.divide(y); } catch (NotInvertibleException e) { // should not happen any more System.out.println("product divide error: x = " + x + ", y = " + y); // could happen for e.g. ModInteger or AlgebraicNumber x = null; //ring.getFactory(i).getZERO(); } if (x != null && !x.isZERO()) { // can happen elem.put(i, x); } } } return new Product(ring, elem); } /** * Product quasi-remainder. * @param S Product. * @return this - (this/S)*S. */ public Product remainder(Product S) { if (S == null) { return this; //ring.getZERO(); } if (S.isZERO()) { return this; } if (this.isZERO()) { return this; } SortedMap elem = new TreeMap(); SortedMap sel = S.val; for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C y = sel.get(i); if (y != null) { C x = me.getValue(); x = x.remainder(y); if (x != null && !x.isZERO()) { // can happen elem.put(i, x); } } } return new Product(ring, elem); } /** * Quotient and remainder by division of this by S. * @param S a product * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public Product[] quotientRemainder(Product S) { return new Product[] { divide(S), remainder(S) }; } /** * Product multiplication. * @param S Product. * @return this*S. */ public Product multiply(Product S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return S; } if (this.isZERO()) { return this; } SortedMap elem = new TreeMap(); SortedMap sel = S.val; for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C y = sel.get(i); if (y != null) { C x = me.getValue(); x = x.multiply(y); if (x != null && !x.isZERO()) { elem.put(i, x); } } } return new Product(ring, elem); } /** * Product multiply by coefficient. * @param c coefficient. * @return this*c. */ public Product multiply(C c) { SortedMap elem = new TreeMap(); for (Map.Entry me : val.entrySet()) { Integer i = me.getKey(); C v = me.getValue().multiply(c); if (v != null && !v.isZERO()) { elem.put(i, v); } } return new Product(ring, elem); } /** * Greatest common divisor. * @param S other element. * @return gcd(this,S). */ public Product gcd(Product S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } SortedMap elem = new TreeMap(val); // clone SortedMap sel = S.val; for (Map.Entry is : sel.entrySet()) { Integer i = is.getKey(); C x = elem.get(i); C y = is.getValue(); //sel.get( i ); // assert y != null if (x != null) { x = x.gcd(y); if (x != null && !x.isZERO()) { elem.put(i, x); } else { elem.remove(i); } } else { elem.put(i, y); } } return new Product(ring, elem); } /** * Extended greatest common divisor. * @param S other element. * @return [ gcd(this,S), c1, c2 ] with c1*this + c2*b = gcd(this,S). */ @SuppressWarnings("unchecked") public Product[] egcd(Product S) { Product[] ret = new Product[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } SortedMap elem = new TreeMap(val); // clone SortedMap elem1 = this.idempotent().val; // init with 1 SortedMap elem2 = new TreeMap(); // zero SortedMap sel = S.val; for (Map.Entry is : sel.entrySet()) { Integer i = is.getKey(); C x = elem.get(i); C y = is.getValue(); //sel.get( i ); // assert y != null if (x != null) { C[] g = x.egcd(y); if (!g[0].isZERO()) { elem.put(i, g[0]); elem1.put(i, g[1]); elem2.put(i, g[2]); } else { elem.remove(i); } } else { elem.put(i, y); elem2.put(i, ring.getFactory(i).getONE()); } } ret[0] = new Product(ring, elem); ret[1] = new Product(ring, elem1); ret[2] = new Product(ring, elem2); return ret; } } java-algebra-system-2.7.200/src/edu/jas/arith/ProductRing.java000066400000000000000000000346001445075545500240740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Direct product ring factory based on RingElem and RingFactory module. Objects * of this class are mutable. * @author Heinz Kredel */ public class ProductRing> implements RingFactory> { private static final Logger logger = LogManager.getLogger(ProductRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Ring factory is n copies. */ protected int nCopies; /** * One Ring factory. */ protected final RingFactory ring; /** * Ring factory list. */ protected final List> ringList; /** * A default random sequence generator. */ protected final static Random random = new Random(); /** * The constructor creates a ProductRing object from an ring factory and a * modul. * @param r ring factory. * @param n number of copies. */ public ProductRing(RingFactory r, int n) { ring = r; nCopies = n; ringList = null; } /** * The constructor creates a ProductRing object from an ring factory and a * modul. * @param l list of ring factories. */ public ProductRing(List> l) { ringList = l; ring = null; nCopies = 0; } /** * Get ring factory at index i. * @param i index. * @return RingFactory_i. */ public RingFactory getFactory(int i) { if (nCopies != 0) { if (0 <= i && i < nCopies) { return ring; } logger.info("index: {}", i); throw new IllegalArgumentException("index out of bound " + this); } return ringList.get(i); } /** * Add a ring factory. * @param rf new ring factory. */ public synchronized void addFactory(RingFactory rf) { if (nCopies != 0) { if (ring.equals(rf)) { nCopies++; return; } throw new IllegalArgumentException("wrong RingFactory: " + rf + " != " + ring); } ringList.add(rf); } /** * Contains a ring factory. * @param rf ring factory. * @return true, if rf is contained in this, else false. */ public boolean containsFactory(RingFactory rf) { if (nCopies != 0) { if (ring.equals(rf)) { return true; } return false; // misleading } return ringList.contains(rf); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { if (nCopies != 0) { return ring.isFinite(); } for (RingFactory f : ringList) { boolean b = f.isFinite(); if (!b) { return false; } } return true; } /** * Copy Product element c. * @param c * @return a copy of c. */ public Product copy(Product c) { return new Product(c.ring, c.val, c.isunit); } /** * Get the zero element. * @return 0 as Product. */ public Product getZERO() { return new Product(this); } /** * Get the one element. * @return 1 as Product. */ public Product getONE() { SortedMap elem = new TreeMap(); if (nCopies != 0) { for (int i = 0; i < nCopies; i++) { elem.put(i, ring.getONE()); } } else { int i = 0; for (RingFactory f : ringList) { elem.put(i, f.getONE()); i++; } } return new Product(this, elem, 1); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> gens = new ArrayList>(/*nCopies*ring.generators.size()*/); int n = nCopies; if (n == 0) { n = ringList.size(); } for (int i = 0; i < n; i++) { //System.out.println("i = " + i + ", n = " + n); RingFactory f = getFactory(i); List rgens = f.generators(); for (C c : rgens) { SortedMap elem = new TreeMap(); elem.put(i, c); Product g = new Product(this, elem); //g = g.fillOne(); gens.add(g); } } return gens; } /** * Get an atomic element. * @param i index. * @return e_i as Product. */ public Product getAtomic(int i) { if (i < 0 || i >= length()) { throw new IllegalArgumentException("index out of bounds " + i); } SortedMap elem = new TreeMap(); if (nCopies != 0) { elem.put(i, ring.getONE()); } else { RingFactory f = ringList.get(i); elem.put(i, f.getONE()); } return new Product(this, elem, 1); } /** * Get the number of factors of this ring. * @return nCopies or ringList.size(). */ public int length() { if (nCopies != 0) { return nCopies; } return ringList.size(); } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { if (nCopies != 0) { return ring.isCommutative(); } for (RingFactory f : ringList) { if (!f.isCommutative()) { return false; } } return true; } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { if (nCopies != 0) { return ring.isAssociative(); } for (RingFactory f : ringList) { if (!f.isAssociative()) { return false; } } return true; } /** * Query if this ring is a field. * @return true or false. */ public boolean isField() { if (nCopies != 0) { if (nCopies == 1) { return ring.isField(); } } else { if (ringList.size() == 1) { return ringList.get(0).isField(); } } return false; } /** * Query if this ring consists only of fields. * @return true or false. */ public boolean onlyFields() { if (nCopies != 0) { return ring.isField(); } for (RingFactory f : ringList) { if (!f.isField()) { return false; } } return true; } /** * Characteristic of this ring. * @return minimal characteristic of ring component. */ public java.math.BigInteger characteristic() { if (nCopies != 0) { return ring.characteristic(); } java.math.BigInteger c = null; java.math.BigInteger d; for (RingFactory f : ringList) { if (c == null) { c = f.characteristic(); } else { d = f.characteristic(); if (c.compareTo(d) > 0) { // c > d c = d; } } } return c; } /** * Get a Product element from a BigInteger value. * @param a BigInteger. * @return a Product. */ public Product fromInteger(java.math.BigInteger a) { SortedMap elem = new TreeMap(); if (nCopies != 0) { C c = ring.fromInteger(a); for (int i = 0; i < nCopies; i++) { elem.put(i, c); } } else { int i = 0; for (RingFactory f : ringList) { elem.put(i, f.fromInteger(a)); i++; } } return new Product(this, elem); } /** * Get a Product element from a long value. * @param a long. * @return a Product. */ public Product fromInteger(long a) { return fromInteger(new java.math.BigInteger("" + a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { if (nCopies != 0) { String cf = ring.toString(); if (cf.matches("[0-9].*")) { cf = ring.getClass().getSimpleName(); } return "ProductRing[ " + cf + "^" + nCopies + " ]"; } StringBuffer sb = new StringBuffer("ProductRing[ "); int i = 0; for (RingFactory f : ringList) { if (i != 0) { sb.append(", "); } String cf = f.toString(); if (cf.matches("[0-9].*")) { cf = f.getClass().getSimpleName(); } sb.append(cf); i++; } sb.append(" ]"); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("RR( [ "); for (int i = 0; i < length(); i++) { if (i > 0) { s.append(", "); } RingFactory v = getFactory(i); String f = null; try { f = ((RingElem) v).toScriptFactory(); // sic } catch (Exception e) { f = v.toScript(); } s.append(f); } s.append(" ] )"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof ProductRing)) { return false; } ProductRing a = (ProductRing) b; if (nCopies != 0) { if (nCopies != a.nCopies || !ring.equals(a.ring)) { return false; } } else { if (ringList.size() != a.ringList.size()) { return false; } int i = 0; for (RingFactory f : ringList) { if (!f.equals(a.ringList.get(i))) { return false; } i++; } } return true; } /** * Hash code for this product ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = 0; if (nCopies != 0) { h = ring.hashCode(); h = 37 * h + nCopies; } else { for (RingFactory f : ringList) { h = 37 * h + f.hashCode(); } } return h; } /** * Product random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random product element v. */ public Product random(int n) { return random(n, 0.5f); } /** * Product random. * @param n such that 0 ≤ v ≤ (2n-1). * @param q density of nozero entries. * @return a random product element v. */ public Product random(int n, float q) { return random(n, q, random); } /** * Product random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random product element v. */ public Product random(int n, Random rnd) { return random(n, 0.5f, random); } /** * Product random. * @param n such that 0 ≤ v ≤ (2n-1). * @param q density of nozero entries. * @param rnd is a source for random bits. * @return a random product element v. */ public Product random(int n, float q, Random rnd) { SortedMap elem = new TreeMap(); float d; if (nCopies != 0) { for (int i = 0; i < nCopies; i++) { d = rnd.nextFloat(); if (d < q) { C r = ring.random(n, rnd); if (!r.isZERO()) { elem.put(i, r); } } } } else { int i = 0; for (RingFactory f : ringList) { d = rnd.nextFloat(); if (d < q) { C r = f.random(n, rnd); if (!r.isZERO()) { elem.put(i, r); } } i++; } } return new Product(this, elem); } /** * Parse Product from String. * @param s String. * @return Product from s. */ public Product parse(String s) { StringReader sr = new StringReader(s); return parse(sr); } /** * Parse Product from Reader. Syntax: p1 ... pn (no commas) * @param r Reader. * @return next Product from r. */ public Product parse(Reader r) { SortedMap elem = new TreeMap(); if (nCopies != 0) { for (int i = 0; i < nCopies; i++) { elem.put(i, ring.parse(r)); } } else { int i = 0; for (RingFactory f : ringList) { elem.put(i, f.parse(r)); i++; } } return new Product(this, elem); } } java-algebra-system-2.7.200/src/edu/jas/arith/Rational.java000066400000000000000000000005171445075545500234050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; /** * Interface with method to get a BigRational (approximation). * @author Heinz Kredel */ public interface Rational { /** * Return a BigRational approximation of this Element. * @return a BigRational approximation of this. */ public BigRational getRational(); } java-algebra-system-2.7.200/src/edu/jas/arith/Roots.java000066400000000000000000000244031445075545500227420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.math.MathContext; /** * Root computation algorithms. Roots for BigInteger and BigDecimals. * @author Heinz Kredel */ public class Roots { /** * Integer n-th root. Uses BigDecimal and newton iteration. R is the n-th * root of A. * @param A big integer. * @param n long. * @return the n-th root of A. */ public static BigInteger root(BigInteger A, int n) { if (n == 1) { return A; } if (n == 2) { return sqrt(A); } if (n < 1) { throw new IllegalArgumentException("negative root not defined"); } if (A == null || A.isZERO() || A.isONE()) { return A; } if (A.signum() < 0) { throw new ArithmeticException("root of negative not defined: " + A); } // ensure enough precision int s = A.val.bitLength() + 2; MathContext mc = new MathContext(s); //System.out.println("mc = " + mc); BigDecimal Ap = new BigDecimal(A.val, mc); //System.out.println("Ap = " + Ap); BigDecimal Ar = root(Ap, n); //System.out.println("Ar = " + Ar); java.math.BigInteger RP = Ar.val.toBigInteger(); BigInteger R = new BigInteger(RP); while (true) { BigInteger P = R.power(n); //Power.positivePower(R, n); //System.out.println("P = " + P); if (A.compareTo(P) >= 0) { break; } R = R.subtract(BigInteger.ONE); } return R; } /** * Integer square root. Uses BigDecimal and newton iteration. R is the * square root of A. * @param A big integer. * @return the square root of A. */ public static BigInteger sqrt(BigInteger A) { if (A == null || A.isZERO() || A.isONE()) { return A; } if (A.signum() < 0) { throw new ArithmeticException("root of negative not defined: " + A); } // ensure enough precision int s = A.val.bitLength() + 2; MathContext mc = new MathContext(s); //System.out.println("mc = " + mc); // newton iteration BigDecimal Ap = new BigDecimal(A.val, mc); //System.out.println("Ap = " + Ap); BigDecimal Ar = sqrt(Ap); //System.out.println("Ar = " + Ar); java.math.BigInteger RP = Ar.val.toBigInteger(); BigInteger R = new BigInteger(RP); while (true) { BigInteger P = R.multiply(R); //System.out.println("P = " + P); if (A.compareTo(P) >= 0) { break; } R = R.subtract(BigInteger.ONE); } return R; } /** * Integer square root. Uses BigInteger only. R is the square root of A. * @param A big integer. * @return the square root of A. */ public static BigInteger sqrtInt(BigInteger A) { if (A == null || A.isZERO() || A.isONE()) { return A; } int s = A.signum(); if (s < 0) { throw new ArithmeticException("root of negative not defined: " + A); } BigInteger R, R1, d; int log2 = A.val.bitLength(); //System.out.println("A = " + A + ", log2 = " + log2); int rootlog2 = log2 - log2 / 2; R = new BigInteger(A.val.shiftRight(rootlog2)); //System.out.println("R = " + R + ", rootlog2 = " + rootlog2); d = R; while (!d.isZERO()) { d = new BigInteger(d.val.shiftRight(1)); // div 2 R1 = R.sum(d); s = A.compareTo(R1.multiply(R1)); if (s == 0) { return R1; } if (s > 0) { R = R1; } //System.out.println("R1 = " + R1); //System.out.println("d = " + d); } while (true) { R1 = R.sum(BigInteger.ONE); //System.out.println("R1 = " + R1); s = A.compareTo(R1.multiply(R1)); if (s == 0) { return R1; } if (s > 0) { R = R1; } if (s < 0) { return R; } } //return R; } /** * Square root. R is the square root of A. * @param A big decimal. * @return the square root of A. */ public static BigDecimal sqrt(BigDecimal A) { if (A == null || A.isZERO() || A.isONE()) { return A; } if (A.signum() < 0) { throw new ArithmeticException("root of negative not defined: " + A); } // for small A use root of inverse if (A.abs().val.compareTo(BigDecimal.ONE.val) < 0) { BigDecimal Ap = A.inverse(); Ap = sqrt(Ap); Ap = Ap.inverse(); //System.out.println("sqrt(A).inverse() = " + Ap); return Ap; } // ensure enough precision MathContext mc = A.context; BigDecimal eps = new BigDecimal("0.1"); int p = Math.max(mc.getPrecision(), java.math.MathContext.DECIMAL64.getPrecision()); //java.math.MathContext.UNLIMITED.getPrecision() == 0 eps = eps.power(p / 2); // newton iteration BigDecimal Ap = new BigDecimal(A.val, mc); BigDecimal ninv = new BigDecimal(0.5, mc); BigDecimal R1, R = Ap.multiply(ninv); // initial guess BigDecimal d; int i = 0; while (true) { R1 = R.sum(Ap.divide(R)); R1 = R1.multiply(ninv); // div n d = R.subtract(R1).abs(); R = R1; if (d.val.compareTo(eps.val) <= 0) { //System.out.println("d = " + d + ", R = " + R); break; } if (i++ % 11 == 0) { eps = eps.sum(eps); } //System.out.println("eps = " + eps + ", d = " + d); } return R; } /** * N-th root. R is the n-th root of A. * @param A big decimal. * @param n long. * @return the n-th root of A. */ public static BigDecimal root(BigDecimal A, int n) { if (n == 1) { return A; } if (n == 2) { return sqrt(A); } if (n < 1) { throw new IllegalArgumentException("negative root not defined"); } if (A == null || A.isZERO() || A.isONE()) { return A; } if (A.signum() < 0) { throw new ArithmeticException("root of negative not defined: " + A); } // for small A use root of inverse if (A.abs().val.compareTo(BigDecimal.ONE.val) < 0) { BigDecimal Ap = A.inverse(); //System.out.println("A.inverse() = " + Ap); Ap = root(Ap, n); return Ap.inverse(); } // ensure enough precision MathContext mc = A.context; BigDecimal eps = new BigDecimal("0.1"); int p = Math.max(mc.getPrecision(), java.math.MathContext.DECIMAL64.getPrecision()); //java.math.MathContext.UNLIMITED.getPrecision() == 0 eps = eps.power((p / 3) * 2); // newton iteration BigDecimal Ap = A; BigDecimal N = new BigDecimal(n, mc); BigDecimal ninv = new BigDecimal(1.0 / n, mc); BigDecimal nsub = new BigDecimal(1.0, mc); // because of precision nsub = nsub.subtract(ninv); BigDecimal P, R1, R = Ap.multiply(ninv); // initial guess BigDecimal d; int i = 0; while (true) { P = R.power(n - 1); //Power.positivePower(R, n - 1); R1 = Ap.divide(P.multiply(N)); R1 = R.multiply(nsub).sum(R1); d = R.subtract(R1).abs(); R = R1; if (d.val.compareTo(eps.val) <= 0) { //System.out.println("d.val = " + d.val); break; } if (i++ % 11 == 0) { eps = eps.sum(eps); } } // System.out.println("eps = " + eps + ", d = " + d); return R; } /** * Complex decimal number square root. * @param a big decimal complex. * @return sqrt(a). */ public static BigDecimalComplex sqrt(BigDecimalComplex a) { if (a.isZERO() || a.isONE()) { return a; } if (a.im.isZERO() && a.re.signum() > 0) { BigDecimal v = Roots.sqrt(a.re); return new BigDecimalComplex(v); } BigDecimal r = a.re.abs().sum(a.abs().re); BigDecimal t = new BigDecimal(2); BigDecimal ti = new BigDecimal("0.5"); //BigDecimal u = r.divide(t); BigDecimal u = r.multiply(ti); BigDecimal v = Roots.sqrt(u); //System.out.println("r = " + r + ", a = " + a); //System.out.println("v = " + v + ", u = " + u); if (a.re.signum() >= 0) { return new BigDecimalComplex(v, a.im.divide(v.multiply(t))); } u = v; if (a.im.signum() < 0) { u = u.negate(); } return new BigDecimalComplex(a.im.abs().divide(v.multiply(t)), u); } /** * Square root. R is the square root approximation of A. * Convert to BigDecimal and compute square root. * @param A big rational. * @return the square root approximation of A. */ public static BigRational sqrt(BigRational A) { if (A == null || A.isZERO() || A.isONE()) { return A; } if (A.signum() < 0) { throw new ArithmeticException("root of negative not defined: " + A); } BigDecimal ad = new BigDecimal(A); BigDecimal s = sqrt(ad); //System.out.println("s = " + s); BigRational S = new BigRational(s.toString()); return S; } /** * Square root. R is the square root approximation of A. * Convert to BigDecimalComplex and compute square root. * @param A big complex rational. * @return the square root approximation of A. */ public static BigComplex sqrt(BigComplex A) { if (A == null || A.isZERO() || A.isONE()) { return A; } BigDecimalComplex ad = new BigDecimalComplex(A); BigDecimalComplex s = sqrt(ad); //System.out.println("s = " + s); BigComplex S = new BigComplex(s.toString()); return S; } } java-algebra-system-2.7.200/src/edu/jas/arith/package.html000066400000000000000000000020201445075545500232410ustar00rootroot00000000000000 Basic arithmetic package

Basic arithmetic package.

This package contains classes for arithmetic in the basic coefficient rings, e.g. BigRational, BigInteger, ModLong or ModInteger. All such classes implement the RingElem respectively the GcdRingElem interface. The class PrimeList provides a list of useful prime numbers. The Product class implements a finite product of other ring elements.


Heinz Kredel

Last modified: Thu Dec 15 22:56:05 CET 2011

$Id$

java-algebra-system-2.7.200/src/edu/jas/fd/000077500000000000000000000000001445075545500202505ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/fd/FDUtil.java000066400000000000000000001601511445075545500222460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.SortedMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Solvable polynomials factorization domain utilities, for example recursive * pseudo remainder. * @author Heinz Kredel */ public class FDUtil { private static final Logger logger = LogManager.getLogger(FDUtil.class); private static final boolean debug = true; //logger.isDebugEnabled(); //private static final boolean info = logger.isInfoEnabled(); /** * GenSolvablePolynomial sparse pseudo remainder for univariate polynomials. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return remainder with ore(ldcf(S)m') P = quotient * S + * remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial leftBaseSparsePseudoRemainder( GenSolvablePolynomial P, GenSolvablePolynomial S) { return leftBasePseudoQuotientRemainder(P, S)[1]; } /** * GenSolvablePolynomial sparse right pseudo remainder for univariate * polynomials. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return remainder with P ore(ldcf(S)m') = S * quotient + * remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial rightBaseSparsePseudoRemainder( GenSolvablePolynomial P, GenSolvablePolynomial S) { return rightBasePseudoQuotientRemainder(P, S)[1]; } /** * GenSolvablePolynomial sparse pseudo quotient for univariate polynomials * or exact division. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return quotient with ore(ldcf(S)m') P = quotient * S + * remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ public static > GenSolvablePolynomial leftBasePseudoQuotient( GenSolvablePolynomial P, GenSolvablePolynomial S) { return leftBasePseudoQuotientRemainder(P, S)[0]; } /** * GenSolvablePolynomial right sparse pseudo quotient for univariate * polynomials or exact division. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return quotient with P ore(ldcf(S)m') = S * quotient + * remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ public static > GenSolvablePolynomial rightBasePseudoQuotient( GenSolvablePolynomial P, GenSolvablePolynomial S) { return rightBasePseudoQuotientRemainder(P, S)[0]; } /** * GenSolvablePolynomial sparse pseudo quotient and remainder for univariate * polynomials or exact division. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return [ quotient, remainder ] with ore(ldcf(S)m') P = * quotient * S + remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial[] leftBasePseudoQuotientRemainder( final GenSolvablePolynomial P, final GenSolvablePolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException("univariate polynomials only"); //} GenSolvablePolynomial[] ret = new GenSolvablePolynomial[2]; ret[0] = null; ret[1] = null; if (P.isZERO() || S.isONE()) { ret[0] = P; ret[1] = S.ring.getZERO(); return ret; } if (P instanceof RecSolvablePolynomial) { RecSolvablePolynomial Pr = (RecSolvablePolynomial) P; if (!Pr.ring.coeffTable.isEmpty()) { throw new UnsupportedOperationException( "RecSolvablePolynomial with twisted coeffs not supported"); } } GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorFake(P.ring.coFac); final ExpVector e = S.leadingExpVector(); GenSolvablePolynomial h; GenSolvablePolynomial r = P; GenSolvablePolynomial q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); f = f.subtract(e); h = S.multiplyLeft(f); // coeff a C c = h.leadingBaseCoefficient(); // need ga, gc: ga a = gc c C[] oc = fd.leftOreCond(a, c); C ga = oc[0]; C gc = oc[1]; //logger.debug("left ga, gc = " + ga + ", " + gc); r = r.multiplyLeft(ga); // coeff ga a, exp f h = h.multiplyLeft(gc); // coeff gc c, exp f q = q.multiplyLeft(ga); // c q = (GenSolvablePolynomial) q.sum(gc, f); // a r = (GenSolvablePolynomial) r.subtract(h); } else { break; } //System.out.println("left q, r = " + q + ", " + r); } int sp = P.signum(); int ss = S.signum(); int sq = q.signum(); // sp = ss * sq if (sp != ss * sq) { q = (GenSolvablePolynomial) q.negate(); r = (GenSolvablePolynomial) r.negate(); } ret[0] = q; ret[1] = r; return ret; } /** * GenSolvablePolynomial right sparse pseudo quotient and remainder * for univariate polynomials or exact division. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return [ quotient, remainder ] with P ore(ldcf(S)m') = S * * quotient + remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial[] rightBasePseudoQuotientRemainder( GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException("univariate polynomials only"); //} GenSolvablePolynomial[] ret = new GenSolvablePolynomial[2]; ret[0] = null; ret[1] = null; if (P.isZERO() || S.isONE()) { ret[0] = P; ret[1] = S.ring.getZERO(); return ret; } if (P instanceof RecSolvablePolynomial) { RecSolvablePolynomial Pr = (RecSolvablePolynomial) P; if (!Pr.ring.coeffTable.isEmpty()) { throw new UnsupportedOperationException( "RecSolvablePolynomial with twisted coeffs not supported"); } } GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorFake(P.ring.coFac); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial h; GenSolvablePolynomial r = P; GenSolvablePolynomial q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); f = f.subtract(e); h = S.multiply(f); // coeff a C c = h.leadingBaseCoefficient(); // need ga, gc: a ga = c gc C[] oc = fd.rightOreCond(a, c); C ga = oc[0]; C gc = oc[1]; r = r.multiply(ga); // coeff a ga, exp f h = h.multiply(gc); // coeff c gc, exp f wanted but is exp f * coeff c gc, okay for base q = q.multiply(ga); // c q = (GenSolvablePolynomial) q.sum(gc, f); // a r = (GenSolvablePolynomial) r.subtract(h); } else { break; } } int sp = P.signum(); int ss = S.signum(); int sq = q.signum(); // sp = ss * sq if (sp != ss * sq) { q = (GenSolvablePolynomial) q.negate(); r = (GenSolvablePolynomial) r.negate(); } ret[0] = q; ret[1] = r; return ret; } /** * Is GenSolvablePolynomial left base pseudo quotient and * remainder. For univariate polynomials. todo: Ore condition * @param coefficient type. * @param P base GenSolvablePolynomial. * @param S nonzero base GenSolvablePolynomial. * @return true, if P = q * S + r, else false. * @see edu.jas.poly.GenSolvablePolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ public static > boolean isLeftBasePseudoQuotientRemainder(GenPolynomial P, GenPolynomial S, GenPolynomial q, GenPolynomial r) { GenPolynomial rhs = q.multiply(S).sum(r); //System.out.println("rhs,1 = " + rhs); GenPolynomial lhs = P; C ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,1 = " + lhs); return true; } lhs = lhs.multiply(ldcf); } GenPolynomial Pp = P; rhs = q.multiply(S); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = Pp.subtract(r); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiply(ldcf); } C a = P.leadingBaseCoefficient(); rhs = q.multiply(S).sum(r); C b = rhs.leadingBaseCoefficient(); C gcd = a.gcd(b); C p = a.multiply(b); C lcm = p.divide(gcd); C ap = lcm.divide(a); C bp = lcm.divide(b); if (P.multiply(ap).equals(rhs.multiply(bp))) { return true; } return false; } /** * Is GenSolvablePolynomial right base pseudo quotient and * remainder. For univariate polynomials. todo: Ore condition * @param coefficient type. * @param P base GenSolvablePolynomial. * @param S nonzero base GenSolvablePolynomial. * @return true, if P = S * q + r, else false. * @see edu.jas.poly.GenSolvablePolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ public static > boolean isRightBasePseudoQuotientRemainder(GenPolynomial P, GenPolynomial S, GenPolynomial q, GenPolynomial r) { GenPolynomial rhs = S.multiply(q).sum(r); //System.out.println("rhs,1 = " + rhs); GenPolynomial lhs = P; C ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,1 = " + lhs); return true; } lhs = lhs.multiply(ldcf); } GenPolynomial Pp = P; rhs = S.multiply(q); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = Pp.subtract(r); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiply(ldcf); } C a = P.leadingBaseCoefficient(); rhs = S.multiply(q).sum(r); C b = rhs.leadingBaseCoefficient(); C gcd = a.gcd(b); C p = a.multiply(b); C lcm = p.divide(gcd); C ap = lcm.divide(a); C bp = lcm.divide(b); if (P.multiply(ap).equals(rhs.multiply(bp))) { return true; } return false; } /** * Is recursive GenSolvablePolynomial pseudo quotient and remainder. For * recursive polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return true, if P ~= q * S + r, else false. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ @SuppressWarnings("unchecked") public static > boolean isRecursivePseudoQuotientRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S, GenSolvablePolynomial> q, GenSolvablePolynomial> r) { GenSolvablePolynomial> rhs, lhs; rhs = (GenSolvablePolynomial>) q.multiply(S).sum(r); lhs = P; GenPolynomial ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs = " + lhs); //System.out.println("rhs = " + rhs); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { return true; } lhs = lhs.multiply(ldcf); } GenSolvablePolynomial> Pp = P; rhs = q.multiply(S); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = (GenSolvablePolynomial>) Pp.subtract(r); //System.out.println("lhs = " + lhs); //System.out.println("rhs = " + rhs); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiply(ldcf); } GenPolynomialRing cofac = (GenPolynomialRing) P.ring.coFac; GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cofac.coFac); GenSolvablePolynomial a = (GenSolvablePolynomial) P.leadingBaseCoefficient(); rhs = (GenSolvablePolynomial>) q.multiply(S).sum(r); GenSolvablePolynomial b = (GenSolvablePolynomial) rhs.leadingBaseCoefficient(); GenSolvablePolynomial[] oc = fd.leftOreCond(a, b); GenSolvablePolynomial ga = oc[0]; GenSolvablePolynomial gb = oc[1]; //System.out.println("FDQR: OreCond: a = " + a + ", b = " + b); //System.out.println("FDQR: OreCond: ga = " + ga + ", gb = " + gb); // ga a = gd d GenSolvablePolynomial> Pa = P.multiplyLeft(ga); // coeff ga a GenSolvablePolynomial> Rb = rhs.multiplyLeft(gb); // coeff gb b GenSolvablePolynomial> D = (GenSolvablePolynomial>) Pa.subtract(Rb); if (D.isZERO()) { return true; } if (debug) { logger.info("not QR: D = {}", D); } //System.out.println("FDQR: Pa = " + Pa); //System.out.println("FDQR: Rb = " + Rb); //System.out.println("FDQR: Pa-Rb = " + D); return false; } /** * GenSolvablePolynomial sparse pseudo remainder for recursive solvable * polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return remainder with ore(ldcf(S)m') P = quotient * S + * remainder. * @see edu.jas.poly.PolyUtil#recursiveSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial> recursiveSparsePseudoRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { return recursivePseudoQuotientRemainder(P, S)[1]; } /** * GenSolvablePolynomial recursive pseudo quotient for recursive * polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return quotient with ore(ldcf(S)m') P = quotient * S + * remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenSolvablePolynomial> recursivePseudoQuotient( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { return recursivePseudoQuotientRemainder(P, S)[0]; } /** * GenSolvablePolynomial recursive pseudo quotient and remainder for * recursive polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return [ quotient, remainder ] with ore(ldcf(S)m') P = * quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial>[] recursivePseudoQuotientRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException("univariate polynomials only"); //} GenSolvablePolynomial>[] ret = new GenSolvablePolynomial[2]; if (P == null || P.isZERO()) { ret[0] = S.ring.getZERO(); ret[1] = S.ring.getZERO(); return ret; } if (S.isONE()) { ret[0] = P; ret[1] = S.ring.getZERO(); return ret; } GenPolynomialRing cofac = (GenPolynomialRing) P.ring.coFac; GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cofac.coFac); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial> h; GenSolvablePolynomial> r = P; GenSolvablePolynomial> q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector g = r.leadingExpVector(); ExpVector f = g; if (f.multipleOf(e)) { f = f.subtract(e); h = S.multiplyLeft(f); // coeff c, exp (f/e) e GenSolvablePolynomial a = (GenSolvablePolynomial) r.leadingBaseCoefficient(); GenSolvablePolynomial d = (GenSolvablePolynomial) h.leadingBaseCoefficient(); GenSolvablePolynomial[] oc = fd.leftOreCond(a, d); GenSolvablePolynomial ga = oc[0]; // a GenSolvablePolynomial gd = oc[1]; // d // ga * a = gd * d r = r.multiplyLeft(ga); // coeff ga a, exp g h = h.multiplyLeft(gd); // coeff gd d, exp f1 q = q.multiplyLeft(ga); // d q = (GenSolvablePolynomial>) q.sum(gd, f); // a r = (GenSolvablePolynomial>) r.subtract(h); if (!r.isZERO() && g.equals(r.leadingExpVector())) { System.out.println("lt(r) = g = " + g + ", leftOre: " + fd.isLeftOreCond(a, d, ga, gd)); //System.out.println("gd*d-ga*a = " + gd.multiply(d).subtract(ga.multiply(a))); throw new RuntimeException("degree not descending: r = " + r); } //System.out.println("r = " + r); } else { break; } } int sp = P.signum(); int ss = S.signum(); int sq = q.signum(); // sp = ss * sq if (sp != ss * sq) { q = (GenSolvablePolynomial>) q.negate(); r = (GenSolvablePolynomial>) r.negate(); } ret[0] = q; ret[1] = r; return ret; } /** * Is recursive GenSolvablePolynomial right pseudo quotient and remainder. * For recursive polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return true, if P ~= S * q + r, else false. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ @SuppressWarnings("unchecked") public static > boolean isRecursiveRightPseudoQuotientRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S, GenSolvablePolynomial> q, GenSolvablePolynomial> r) { GenSolvablePolynomial> rhs, lhs; rhs = (GenSolvablePolynomial>) S.multiply(q).sum(r); lhs = P; GenPolynomial ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs = " + lhs); //System.out.println("rhs = " + rhs); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { return true; } lhs = lhs.multiplyLeft(ldcf); // side? } GenSolvablePolynomial> Pp = P; rhs = S.multiply(q); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = (GenSolvablePolynomial>) Pp.subtract(r); //System.out.println("lhs = " + lhs); //System.out.println("rhs = " + rhs); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiplyLeft(ldcf); // side? } GenPolynomialRing cofac = (GenPolynomialRing) P.ring.coFac; GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cofac.coFac); //GenSolvablePolynomial> pr = P.rightRecursivePolynomial(); RecSolvablePolynomial pr = (RecSolvablePolynomial) P.rightRecursivePolynomial(); GenSolvablePolynomial a = (GenSolvablePolynomial) pr.leadingBaseCoefficient(); rhs = (GenSolvablePolynomial>) S.multiply(q).sum(r); //GenSolvablePolynomial> rr = rhs.rightRecursivePolynomial(); RecSolvablePolynomial rr = (RecSolvablePolynomial) rhs.rightRecursivePolynomial(); GenSolvablePolynomial b = (GenSolvablePolynomial) rr.leadingBaseCoefficient(); GenSolvablePolynomial[] oc = fd.rightOreCond(a, b); GenSolvablePolynomial ga = oc[0]; GenSolvablePolynomial gb = oc[1]; //System.out.println("FDQR: OreCond: a = " + a + ", b = " + b); //System.out.println("FDQR: OreCond: ga = " + ga + ", gb = " + gb); // a ga = d gd GenSolvablePolynomial> Pa = pr.multiplyRightComm(ga); // coeff a ga GenSolvablePolynomial> Rb = rr.multiplyRightComm(gb); // coeff b gb //System.out.println("right(P) = " + pr + ", P = " + P); //System.out.println("right(rhs)= " + rr + ", rhs = " + rhs); //System.out.println("Pa = " + Pa + ", ga = " + ga); //System.out.println("Rb = " + Rb + ", gb = " + gb); GenSolvablePolynomial> D = (GenSolvablePolynomial>) Pa.subtract(Rb); if (D.isZERO()) { return true; } System.out.println("Pa = " + Pa); System.out.println("Rb = " + Rb); logger.info("not right QR: Pa-Rb = {}", D); return false; } /** * GenSolvablePolynomial right sparse pseudo remainder for recursive * solvable polynomials. Note: uses right multiplication of P by * ldcf(S), not always applicable. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return remainder with P ore(ldcf(S)m') = quotient * S + * remainder. * @see edu.jas.poly.PolyUtil#recursiveSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ public static > GenSolvablePolynomial> recursiveRightSparsePseudoRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { return recursiveRightPseudoQuotientRemainder(P, S)[1]; } /** * GenSolvablePolynomial recursive right pseudo quotient for recursive * polynomials. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return quotient with P ore(ldcf(S)m') = S * quotient + * remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenSolvablePolynomial> recursiveRightPseudoQuotient( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { return recursiveRightPseudoQuotientRemainder(P, S)[0]; } /** * GenSolvablePolynomial right sparse pseudo quotient and remainder for * recursive solvable polynomials. Note: uses right multiplication of * P by ldcf(S), not always applicable. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param S nonzero recursive GenSolvablePolynomial. * @return remainder with P ore(ldcf(S)m') = S * quotient + * remainder. * @see edu.jas.poly.PolyUtil#recursiveSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial>[] recursiveRightPseudoQuotientRemainder( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } GenSolvablePolynomial>[] ret = new GenSolvablePolynomial[2]; if (P == null || P.isZERO()) { ret[0] = S.ring.getZERO(); ret[1] = S.ring.getZERO(); return ret; } if (S.isONE()) { ret[0] = P; ret[1] = S.ring.getZERO(); return ret; } //if (S.isConstant()) { // ret[0] = P.ring.getZERO(); // ret[1] = S.ring.getZERO(); // return ret; //} GenPolynomialRing cofac = (GenPolynomialRing) P.ring.coFac; GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cofac.coFac); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial> h, q, r; RecSolvablePolynomial hr, rr, qr; r = P; //System.out.println("zero = " + S.ring.getZERO().copy()); qr = (RecSolvablePolynomial) S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector g = r.leadingExpVector(); ExpVector f = g; if (f.multipleOf(e)) { f = f.subtract(e); //System.out.println("f = " + f); h = S.multiply(f); // coeff c, exp e (f/e) hr = (RecSolvablePolynomial) h.rightRecursivePolynomial(); rr = (RecSolvablePolynomial) r.rightRecursivePolynomial(); GenSolvablePolynomial a = (GenSolvablePolynomial) rr.leadingBaseCoefficient(); GenSolvablePolynomial d = (GenSolvablePolynomial) hr.leadingBaseCoefficient(); GenSolvablePolynomial[] oc = fd.rightOreCond(a, d); GenSolvablePolynomial ga = oc[0]; // a GenSolvablePolynomial gd = oc[1]; // d //System.out.println("OreCond: a = " + a + ", d = " + d); //System.out.println("OreCond: ga = " + ga + ", gd = " + gd); // a ga = d gd //rr = rr.multiply(ga); // exp f, coeff a ga //hr = hr.multiply(gd,f); // exp f, coeff d gd rr = rr.multiplyRightComm(ga); // exp f, coeff a ga hr = hr.multiplyRightComm(gd); // exp f, coeff d gd ///.shift(f) h = hr.evalAsRightRecursivePolynomial(); r = rr.evalAsRightRecursivePolynomial(); r = (GenSolvablePolynomial>) r.subtract(h); qr = qr.multiplyRightComm(ga); // d qr = (RecSolvablePolynomial) qr.sum(gd, f); // a // same for right coefficients //System.out.println("q = " + qr); //.leadingMonomial()); if (!r.isZERO() && g.equals(r.leadingExpVector())) { throw new RuntimeException("something is wrong: g == lc(r), terms not descending " + r); } //System.out.println("r = " + r + ", qr = " + qr); } else { break; } } q = qr.evalAsRightRecursivePolynomial(); int sp = P.signum(); int ss = S.signum(); int sq = q.signum(); // sp = ss * sq if (sp != ss * sq) { q = (GenSolvablePolynomial>) q.negate(); r = (GenSolvablePolynomial>) r.negate(); } ret[0] = q; ret[1] = r; return ret; } // ---------------------------------------------------------------------- /** * GenSolvablePolynomial recursive quotient for recursive polynomials and * exact division by coefficient ring element. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param s GenSolvablePolynomial. * @return P/s. */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial> recursiveDivideRightEval( GenSolvablePolynomial> P, GenSolvablePolynomial s) { if (s.isONE()) { return P; } GenSolvablePolynomial> Pr = P.rightRecursivePolynomial(); GenSolvablePolynomial> Qr = FDUtil. recursiveLeftDivide(Pr, s); // Left/Right GenSolvablePolynomial> Q = Qr.evalAsRightRecursivePolynomial(); if (debug) { if (!Qr.multiplyLeft(s).equals(Pr)) { System.out.println("rDivREval: Pr = " + Pr + ", P = " + P); System.out.println("rDivREval: Qr = " + Qr + ", Q = " + Q); System.out.println("rDivREval: s*Qr = " + Qr.multiplyLeft(s) + ", s = " + s); System.out.println("rDivREval: Qr*s = " + Qr.multiply(s)); //System.out.println("rDivREval: P.ring == Q.ring: " + P.ring.equals(Q.ring) ); throw new RuntimeException("rDivREval: s*Qr != Pr"); } if (!Q.multiply(s).equals(P)) { System.out.println("rDivREval: P = " + P + ", right(P) = " + Pr); System.out.println("rDivREval: Q = " + Q + ", right(Q) = " + Qr); System.out.println("rDivREval: Q*s = " + Q.multiply(s) + ", s = " + s); System.out.println("rDivREval: s*Q = " + Q.multiplyLeft(s)); //System.out.println("rDivREval: P.ring == Q.ring: " + P.ring.equals(Q.ring) ); throw new RuntimeException("rDivREval: Q*s != P"); } } return Q; } /** * GenSolvablePolynomial left recursive quotient for recursive polynomials * and exact division by coefficient ring element. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param s GenSolvablePolynomial. * @return q = this/s, with q * s = P. */ @SuppressWarnings({ "unchecked", "cast" }) public static > GenSolvablePolynomial> recursiveDivide( GenSolvablePolynomial> P, GenSolvablePolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } GenSolvablePolynomialRing> rfac = (GenSolvablePolynomialRing>) P.ring; GenSolvablePolynomial> onep = rfac.getONE(); ExpVector zero = rfac.evzero; GenSolvablePolynomial> q = rfac.getZERO(); GenSolvablePolynomial> r; GenSolvablePolynomial> p = P; //.ring.getZERO().copy(); while (!p.isZERO()) { // for (Map.Entry> m1 : P.getMap().entrySet()) { Map.Entry> m1 = p.leadingMonomial(); GenSolvablePolynomial c1 = (GenSolvablePolynomial) m1.getValue(); ExpVector e1 = m1.getKey(); GenSolvablePolynomial c = c1.divide(s); // c * s = c1 if (c.isZERO()) { throw new RuntimeException("something is wrong: c is zero, c1 = " + c1 + ", s = " + s); } //r = onep.multiplyLeft(c.multiply(s), e1); // right: (c e1) * 1 * (s zero) r = onep.multiply(c, e1, s, zero); // right: (c e1) * 1 * (s zero) if (!c1.equals(r.leadingBaseCoefficient())) { System.out.println("recRightDivide: lc(r) = " + r.leadingBaseCoefficient() + ", c1 = " + c1); System.out.println("recRightDivide: lc(r) = " + c.multiply(s) + ", c = " + c + ", s = " + s); throw new RuntimeException("something is wrong: lc(r) != c*s"); } p = (RecSolvablePolynomial) p.subtract(r); if (!p.isZERO() && e1.compareTo(p.leadingExpVector()) == 0) { System.out.println("recRightDivide: c = " + c); System.out.println("recRightDivide: lt(p) = " + p.leadingExpVector() + ", e1 = " + e1); System.out.println("recRightDivide: c1/s = " + c1.divide(s)); System.out.println("recRightDivide: s*c = " + s.multiply(c)); System.out.println("recRightDivide: c*s = " + c.multiply(s)); throw new RuntimeException("something is wrong: degree not descending"); } q = (RecSolvablePolynomial) q.sum(c, e1); } return q; } /** * GenSolvablePolynomial recursive quotient for recursive polynomials and * partial right exact division by coefficient ring element. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param s GenSolvablePolynomial. * @return Q with s * Q = P. */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial> recursiveRightDivide( GenSolvablePolynomial> P, GenSolvablePolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } if (!(P instanceof RecSolvablePolynomial)) { //return FDUtil. recursiveDivide(P,s); System.out.println("recRightDivide: not a RecSolvablePolynomial " + P.ring.toScript()); } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) P.ring; if (rfac.coeffTable.isEmpty()) { //return FDUtil. recursiveDivide(P,s); //System.out.println("recRightDivide: rfac.coeffTable.isEmpty()"); } RecSolvablePolynomial onep = rfac.getONE(); //ExpVector zero = rfac.evzero; RecSolvablePolynomial q = rfac.getZERO(); RecSolvablePolynomial r; RecSolvablePolynomial p = (RecSolvablePolynomial) P; //System.out.println("recRightDivide: p = " + p + ", s = " + s); while (!p.isZERO()) { Map.Entry> m1 = p.leadingMonomial(); GenSolvablePolynomial a = (GenSolvablePolynomial) m1.getValue(); ExpVector f = m1.getKey(); GenSolvablePolynomial c = (GenSolvablePolynomial) a.rightDivide(s); // s * c = a //GenSolvablePolynomial c = (GenSolvablePolynomial) a.leftDivide(s); // c * s = a //System.out.println("recRightDivide: " + s + " * " + c + " = " + a); if (c.isZERO()) { //logger.info("something is wrong: c is zero, a = {}, s = {}", a, s); throw new RuntimeException("something is wrong: c is zero, a = " + a + ", s = " + s); } r = onep.multiply(s.multiply(c), f); // left 1 * s * c * (1 f) if (!a.equals(r.leadingBaseCoefficient())) { System.out.println("recRightDivide: class(a) = " + a.getClass() + ", class(s) = " + s.getClass()); System.out.println("recRightDivide: a = " + a + ", lc(r) = " + r.leadingBaseCoefficient()); System.out.println("recRightDivide: c*s = " + c.multiply(s) + ", s = " + s + ", c = " + c); System.out.println("recRightDivide: s*c = " + s.multiply(c) + ", a%s = " + a.rightRemainder(s)); System.out.println("recRightDivide: c_l = " + a.rightDivide(s)); throw new RuntimeException("something is wrong: c*s != a: " + rfac.toScript()); } p = (RecSolvablePolynomial) p.subtract(r); if (!p.isZERO() && f.compareTo(p.leadingExpVector()) == 0) { System.out.println("recRightDivide: c = " + c); System.out.println("recRightDivide: lt(p) = " + p.leadingExpVector() + ", f = " + f); System.out.println("recRightDivide: a/s = " + a.divide(s)); System.out.println("recRightDivide: s*c = " + s.multiply(c)); System.out.println("recRightDivide: c*s = " + c.multiply(s)); throw new RuntimeException("something is wrong: degree not descending"); } q = (RecSolvablePolynomial) q.sum(c, f); } //System.out.println("recRightDivide: q = " + q); return q; } /** * GenSolvablePolynomial sparse pseudo divide. For univariate polynomials or exact * division. * @param coefficient type. * @param P GenSolvablePolynomial. * @param S nonzero GenSolvablePolynomial. * @return quotient with ldcf(S)m' P = quotient * S + remainder. * m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenSolvablePolynomial#divide(edu.jas.poly.GenSolvablePolynomial). */ public static > GenSolvablePolynomial basePseudoLeftDivide(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException(this.getClass().getName() // + " univariate polynomials only"); //} if (P.isZERO() || S.isONE()) { return P; } C c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial h; GenSolvablePolynomial r = P; GenSolvablePolynomial q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); f = f.subtract(e); C x = ((GcdRingElem)a).leftRemainder(c); if (x.isZERO()) { C y = a.leftDivide(c); q = (GenSolvablePolynomial) q.sum(y, f); h = S.multiplyLeft(y, f); // coeff a } else { q = q.multiplyLeft(c); q = (GenSolvablePolynomial) q.sum(a, f); r = r.multiplyLeft(c); // coeff ac h = S.multiplyLeft(a, f); // coeff ac } r = (GenSolvablePolynomial) r.subtract(h); } else { break; } } return q; } /** * GenSolvablePolynomial recursive quotient for recursive polynomials and * partial left exact division by coefficient ring element. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param s GenSolvablePolynomial. * @return Q with P = Q * s. */ @SuppressWarnings({ "unchecked", "cast" }) public static > GenSolvablePolynomial> recursiveLeftDivide( GenSolvablePolynomial> P, GenSolvablePolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } if (!(P instanceof RecSolvablePolynomial)) { //return FDUtil. recursiveDivide(P,s); System.out.println("recLeftDivide: not a RecSolvablePolynomial " + P.ring); } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) P.ring; if (rfac.coeffTable.isEmpty()) { //return FDUtil. recursiveDivide(P,s); //System.out.println("recLeftDivide: rfac.coeffTable.isEmpty()"); } GenSolvablePolynomial> p = P.ring.getZERO().copy(); //System.out.println("recLeftDivide: P = " + P + ", s = " + s + ", p = " + p); for (Map.Entry> m1 : P.getMap().entrySet()) { GenSolvablePolynomial c1 = (GenSolvablePolynomial) m1.getValue(); ExpVector e1 = m1.getKey(); GenPolynomial c = FDUtil. basePseudoLeftDivide(c1, s); //System.out.println("recLeftDivide: c = " + c); if (!c.isZERO()) { //System.out.println("recLeftDivide: e1 = " + e1); p.doPutToMap(e1, c); } else { System.out.println("recLeftDivide: c * s = " + c.multiply(s)); System.out.println("recLeftDivide: s * c = " + s.multiply(c)); logger.error("recLeftDivide, P = {}", P); logger.error("recLeftDivide, e1 = {}", e1); logger.error("recLeftDivide, c1 = {}", c1); logger.error("recLeftDivide, s = {}", s); logger.error("recLeftDivide, c = {}", c); throw new RuntimeException("something is wrong, c is zero"); } } return p; } /* * GenSolvablePolynomial recursive quotient for recursive polynomials and * partial left exact division by coefficient ring element. * @param coefficient type. * @param P recursive GenSolvablePolynomial. * @param s GenSolvablePolynomial. * @return Q with P = Q * s. */ @SuppressWarnings({ "unchecked", "cast" }) static > GenSolvablePolynomial> experimentalRecursiveLeftDivide( GenSolvablePolynomial> P, GenSolvablePolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } if (!(P instanceof RecSolvablePolynomial)) { //return FDUtil. recursiveDivide(P,s); System.out.println("not a RecSolvablePolynomial " + P.ring); } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) P.ring; if (rfac.coeffTable.isEmpty()) { //return FDUtil. recursiveDivide(P,s); //System.out.println("rfac.coeffTable.isEmpty()"); } RecSolvablePolynomial onep = rfac.getONE(); //ExpVector zero = rfac.evzero; RecSolvablePolynomial q = rfac.getZERO(); RecSolvablePolynomial r, Pp; RecSolvablePolynomial p = (RecSolvablePolynomial) P; //RecSolvablePolynomial p = (RecSolvablePolynomial) P.rightRecursivePolynomial(); //System.out.println("recLeftDivide: P = " + P + ", s = " + s); //System.out.println("recLeftDivide: p = " + p); Pp = p; while (!p.isZERO()) { ExpVector f = p.leadingExpVector(); GenSolvablePolynomial a = (GenSolvablePolynomial) p.leadingBaseCoefficient(); GenSolvablePolynomial c = (GenSolvablePolynomial) a.divide(s); // c * s = a ///GenSolvablePolynomial c = (GenSolvablePolynomial) a.rightDivide(s); // s * c = a //System.out.println("recLeftDivide: c * s = a: " + c + " * " + s + " = " + c.multiply(s) + " = " + a + ", c*s-a = " + c.multiply(s).subtract(a)); if (c.isZERO()) { throw new RuntimeException("something is wrong: c is zero, a = " + a + ", s = " + s); } //r = onep.multiply(c, f, s, zero); // right: (c f) * 1 * (s zero) r = onep.multiplyLeft(c.multiply(s), f); // right: (c*s f) * one ///r = onep.multiplyLeft(s.multiply(c), f); // left: (s*c f) * one if (!a.equals(r.leadingBaseCoefficient())) { System.out.println("recLeftDivide: a = " + a); System.out.println("recLeftDivide: lc(r) = " + r.leadingBaseCoefficient()); System.out.println("recLeftDivide: c = " + c); System.out.println("recLeftDivide: a.riDi.s = " + a.rightDivide(s)); System.out.println("recLeftDivide: s = " + s); System.out.println("recLeftDivide: c * s = " + c.multiply(s)); System.out.println("recLeftDivide: s * c = " + s.multiply(c)); C ac = a.leadingBaseCoefficient(); C rc = r.leadingBaseCoefficient().leadingBaseCoefficient(); C cc = rc.inverse().multiply(ac); System.out.println("recLeftDivide: cc = " + cc); //c = c.multiply(cc); r = onep.multiplyLeft(c.multiply(s), f); // right: (1 f) * c * s System.out.println("recLeftDivide: lc(r) = " + r.leadingBaseCoefficient()); System.out.println("recLeftDivide: deg(r) = " + r.degree()); throw new RuntimeException("something is wrong: a != lc(r): " + rfac.toScript()); } p = (RecSolvablePolynomial) p.subtract(r); if (!p.isZERO() && f.compareTo(p.leadingExpVector()) == 0) { System.out.println("recLeftDivide: P = " + P + ", s = " + s); System.out.println("recLeftDivide: right(P) = " + Pp); System.out.println("recLeftDivide: c = " + c); System.out.println("recLeftDivide: lt(p) = " + p.leadingExpVector() + ", f = " + f); System.out.println("recLeftDivide: a/s = " + a.divide(s)); System.out.println("recLeftDivide: a\\s = " + a.rightDivide(s)); System.out.println("recLeftDivide: s*c = " + s.multiply(c)); System.out.println("recLeftDivide: c*s = " + c.multiply(s)); throw new RuntimeException("something is wrong: degree not descending"); } q = (RecSolvablePolynomial) q.sum(c, f); } //System.out.println("recLeftDivide: q = " + q); //q = (RecSolvablePolynomial) q.evalAsRightRecursivePolynomial(); //System.out.println("recLeftDivide: q = " + q); return q; } /** * Integral solvable polynomial from solvable rational function * coefficients. Represent as polynomial with integral solvable polynomial * coefficients by multiplication with the lcm(??) of the numerators of the * rational function coefficients. * @param fac result polynomial factory. * @param A polynomial with solvable rational function coefficients to be * converted. * @return polynomial with integral solvable polynomial coefficients. */ @SuppressWarnings({ "unchecked", "cast" }) public static > GenSolvablePolynomial> integralFromQuotientCoefficients( GenSolvablePolynomialRing> fac, GenSolvablePolynomial> A) { GenSolvablePolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } GenSolvablePolynomial c = null; GenSolvablePolynomial d; GenSolvablePolynomial x; GenSolvablePolynomial z; GenPolynomialRing cofac = (GenPolynomialRing) fac.coFac; GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorPrimitive(cofac.coFac); int s = 0; // lcm/ore of denominators ?? Map> Am = A.getMap(); for (SolvableQuotient y : Am.values()) { x = y.den; // c = lcm(c,x) if (c == null) { c = x; s = x.signum(); } else { d = fd.leftGcd(c, x); z = (GenSolvablePolynomial) x.divide(d); // ?? c = z.multiply(c); // ?? multiplyLeft } } if (s < 0) { c = (GenSolvablePolynomial) c.negate(); } for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); SolvableQuotient a = y.getValue(); // p = n*(c/d) GenPolynomial b = c.divide(a.den); GenPolynomial p = a.num.multiply(b); //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } return B; } /** * Integral solvable polynomial from solvable rational function * coefficients. Represent as polynomial with integral solvable polynomial * coefficients by multiplication with the lcm(??) of the numerators of the * solvable rational function coefficients. * @param fac result polynomial factory. * @param L list of polynomials with solvable rational function coefficients * to be converted. * @return list of polynomials with integral solvable polynomial * coefficients. */ @SuppressWarnings("unchecked") public static > List>> integralFromQuotientCoefficients( GenSolvablePolynomialRing> fac, Collection>> L) { if (L == null) { return null; } List>> list = new ArrayList>>( L.size()); for (GenSolvablePolynomial> p : L) { list.add(integralFromQuotientCoefficients(fac, p)); } return list; } /** * Solvable rational function from integral solvable polynomial * coefficients. Represent as polynomial with type SolvableQuotient * coefficients. * @param fac result polynomial factory. * @param A polynomial with integral solvable polynomial coefficients to be * converted. * @return polynomial with type SolvableQuotient coefficients. */ @SuppressWarnings("unchecked") public static > GenSolvablePolynomial> quotientFromIntegralCoefficients( GenSolvablePolynomialRing> fac, GenSolvablePolynomial> A) { GenSolvablePolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = fac.coFac; SolvableQuotientRing qfac = (SolvableQuotientRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenSolvablePolynomial a = (GenSolvablePolynomial) y.getValue(); SolvableQuotient p = new SolvableQuotient(qfac, a); // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Solvable rational function from integral solvable polynomial * coefficients. Represent as polynomial with type SolvableQuotient * coefficients. * @param fac result polynomial factory. * @param L list of polynomials with integral solvable polynomial * coefficients to be converted. * @return list of polynomials with type SolvableQuotient coefficients. */ public static > List>> quotientFromIntegralCoefficients( GenSolvablePolynomialRing> fac, Collection>> L) { if (L == null) { return null; } List>> list = new ArrayList>>( L.size()); for (GenSolvablePolynomial> p : L) { list.add(quotientFromIntegralCoefficients(fac, p)); } return list; } } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisor.java000066400000000000000000000064651445075545500254150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; /** * (Non-unique) factorization domain greatest common divisor algorithm * interface. * @param coefficient type * @author Heinz Kredel */ public interface GreatestCommonDivisor> extends Serializable { /** * GenSolvablePolynomial left greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ public GenSolvablePolynomial leftGcd(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * GenSolvablePolynomial right greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ public GenSolvablePolynomial rightGcd(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * GenSolvablePolynomial left least common multiple. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return lcm(P,S) with lcm(P,S) = P'*P = S'*S. */ public GenSolvablePolynomial leftLcm(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * GenSolvablePolynomial right least common multiple. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return lcm(P,S) with lcm(P,S) = P*P' = S*S'. */ public GenSolvablePolynomial rightLcm(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * GenSolvablePolynomial right content. * @param P GenSolvablePolynomial. * @return cont(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial rightContent(GenSolvablePolynomial P); /** * GenSolvablePolynomial right primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial rightPrimitivePart(GenSolvablePolynomial P); /** * GenSolvablePolynomial left content. * @param P GenSolvablePolynomial. * @return cont(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial leftContent(GenSolvablePolynomial P); /** * GenSolvablePolynomial left primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial leftPrimitivePart(GenSolvablePolynomial P); /** * GenSolvablePolynomial left co-prime list. * @param A list of GenSolvablePolynomials. * @return B with leftGcd(b,c) = 1 for all b != c in B and for all * non-constant a in A there exists b in B with b|a. B does not * contain zero or constant polynomials. */ public List> leftCoPrime(List> A); /** * GenSolvablePolynomial test for left co-prime list. * @param A list of GenSolvablePolynomials. * @return true if leftGcd(b,c) = 1 for all b != c in B, else false. */ public boolean isLeftCoPrime(List> A); } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisorAbstract.java000066400000000000000000001635531445075545500271030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.StarRingElem; import edu.jas.ufd.GCDFactory; /** * (Non-unique) factorization domain greatest common divisor common algorithms. * @param coefficient type * @author Heinz Kredel */ public abstract class GreatestCommonDivisorAbstract> implements GreatestCommonDivisor { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Engine for syzygy computation, mainly for Ore conditions. */ final SolvableSyzygyAbstract syz; /** * Coefficient ring. */ final RingFactory coFac; /* * Engine for commutative gcd computation. */ //edu.jas.ufd.GreatestCommonDivisorAbstract cgcd; /** * Constructor. * @param cf coefficient ring. */ public GreatestCommonDivisorAbstract(RingFactory cf) { this(cf, new SolvableSyzygySeq(cf)); } /** * Constructor. * @param cf coefficient ring. * @param s algorithm for SolvableSyzygy computation. */ public GreatestCommonDivisorAbstract(RingFactory cf, SolvableSyzygyAbstract s) { coFac = cf; syz = s; //cgcd = GCDFactory. getImplementation(pfac.coFac); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName(); } /** * GenSolvablePolynomial base coefficient content. * @param P GenSolvablePolynomial. * @return cont(P) with pp(P)*cont(P) = P. */ public C leftBaseContent(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } if (P.ring.coFac.isField()) { // so to make monic return P.leadingBaseCoefficient(); } C d = null; for (C c : P.getMap().values()) { if (d == null) { d = c; } else { d = d.leftGcd(c); } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenSolvablePolynomial right base coefficient content. * @param P GenSolvablePolynomial. * @return cont(P) with cont(P)*pp(P) = P. */ public C rightBaseContent(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } if (P.ring.coFac.isField()) { // so to make monic return P.leadingBaseCoefficient(); // todo check move to right } C d = null; for (C c : P.getMap().values()) { if (d == null) { d = c; } else { d = d.rightGcd(c); // DONE does now exist } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenSolvablePolynomial base coefficient primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial leftBasePrimitivePart(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } C d = leftBaseContent(P); if (d.isONE()) { return P; } if (P.ring.coFac.isField()) { // make monic return P.multiplyLeft(d.inverse()); // avoid the divisions //return P.multiply( d.inverse() ); // avoid the divisions } //GenSolvablePolynomial pp = (GenSolvablePolynomial) P.rightDivideCoeff(d); // rightDivide TODO/done GenSolvablePolynomial pp = (GenSolvablePolynomial) P.leftDivideCoeff(d); // TODO if (debug) { GenSolvablePolynomial p = pp.multiplyLeft(d); if (!p.equals(P)) { throw new ArithmeticException("pp(p)*cont(p) != p: "); } } return pp; } /** * GenSolvablePolynomial right base coefficient primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial rightBasePrimitivePart(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } C d = rightBaseContent(P); if (d.isONE()) { return P; } if (P.ring.coFac.isField()) { // make monic return P.multiply(d.inverse()); // avoid the divisions } GenSolvablePolynomial pp = (GenSolvablePolynomial) P.rightDivideCoeff(d); // leftDivide TODO/done if (debug) { GenSolvablePolynomial p = pp.multiplyLeft(d); if (!p.equals(P)) { throw new ArithmeticException("pp(p)*cont(p) != p: "); } } return pp; } /** * Univariate GenSolvablePolynomial greatest common divisor. Uses sparse * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ public abstract GenSolvablePolynomial leftBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * Univariate GenSolvablePolynomial right greatest common divisor. Uses * sparse pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. */ public abstract GenSolvablePolynomial rightBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S); /** * GenSolvablePolynomial commuting recursive content. * @param P recursive GenSolvablePolynomial with commuting main and * coefficient variables. * @return cont(P) with cont(P)*pp(P) = pp(P)*cont(P). */ public GenSolvablePolynomial recursiveContent(GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P instanceof RecSolvablePolynomial) { RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) P.ring; if (!rfac.coeffTable.isEmpty()) { throw new UnsupportedOperationException("RecSolvablePolynomial with non empty coeffTable"); } } if (P.isZERO()) { return (GenSolvablePolynomial) P.ring.getZEROCoefficient(); } if (P.leadingBaseCoefficient().isONE()) { return (GenSolvablePolynomial) P.ring.getONECoefficient(); } GenSolvablePolynomial d = null; for (GenPolynomial cp : P.getMap().values()) { GenSolvablePolynomial c = (GenSolvablePolynomial) cp; if (d == null) { d = c; } else { ///d = leftGcd(d, c); // go to recursion d = rightGcd(d, c); // go to recursion } if (d.isONE()) { return d; } } return (GenSolvablePolynomial) d.abs(); } /** * GenSolvablePolynomial left recursive content. * @param P recursive GenSolvablePolynomial. * @return cont(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial leftRecursiveContent(GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P != null"); } if (P.isZERO()) { return (GenSolvablePolynomial) P.ring.getZEROCoefficient(); } if (P.leadingBaseCoefficient().isONE()) { return (GenSolvablePolynomial) P.ring.getONECoefficient(); } GenSolvablePolynomial d = null, cs = null; GenSolvablePolynomial> Pr = P; //FDUtil. rightRecursivePolynomial(P); logger.info("recCont: P = {}, left(P) = {}", P, Pr); for (GenPolynomial c : Pr.getMap().values()) { cs = (GenSolvablePolynomial) c; if (d == null) { d = cs; } else { d = leftGcd(d, cs); // go to recursion logger.info("recCont: cs = {}, d = {}", cs, d); } if (d.isONE()) { return d; } } return (GenSolvablePolynomial) d.abs(); } /** * GenSolvablePolynomial right recursive content. * @param P recursive GenSolvablePolynomial. * @return cont(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial rightRecursiveContent(GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P != null"); } if (P.isZERO()) { return (GenSolvablePolynomial) P.ring.getZEROCoefficient(); } if (P.leadingBaseCoefficient().isONE()) { return (GenSolvablePolynomial) P.ring.getONECoefficient(); } GenSolvablePolynomial d = null, cs = null, x; GenSolvablePolynomial> Pr = P.rightRecursivePolynomial(); logger.warn("RI-recCont: P = {}, right(P) = {}", P, Pr); for (GenPolynomial c : Pr.getMap().values()) { cs = (GenSolvablePolynomial) c; if (d == null) { d = cs; } else { x = d; d = leftGcd(d, cs); // go to recursion, P = P'*gcd(P,S) ///d = rightGcd(d, cs); // go to recursion, P = gcd(P,S)*P' logger.info("RI-recCont: d = {}, cs = {}, d = {}", x, cs, d); } if (d.isONE()) { return d; } } return (GenSolvablePolynomial) d.abs();// todo: eval right ? } /** * GenSolvablePolynomial left recursive primitive part. * @param P recursive GenSolvablePolynomial. * @return pp(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial> leftRecursivePrimitivePart( GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } GenSolvablePolynomial d = leftRecursiveContent(P); if (d.isONE()) { return P; } GenSolvablePolynomial> pp; //pp = FDUtil. recursiveRightDivide(P, d); pp = FDUtil. recursiveLeftDivide(P, d); if (debug) { // not checkable if (!P.equals(pp.multiplyLeft(d))) { System.out.println("ppart, P = " + P); System.out.println("ppart, cont(P) = " + d); System.out.println("ppart, pp(P) = " + pp); System.out.println("ppart, pp(P)c(P) = " + pp.multiplyLeft(d)); throw new RuntimeException("primitivePart: P != cont(P)*pp(P)"); } } return pp; } /** * GenSolvablePolynomial right recursive primitive part. * @param P recursive GenSolvablePolynomial. * @return pp(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial> rightRecursivePrimitivePart( GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } GenSolvablePolynomial d = rightRecursiveContent(P); if (d.isONE()) { return P; } GenSolvablePolynomial> pp; pp = FDUtil. recursiveRightDivide(P, d); //RightEval if (debug) { // not checkable if (!P.equals(pp.multiply(d))) { System.out.println("RI-ppart, P = " + P); System.out.println("RI-ppart, cont(P) = " + d); System.out.println("RI-ppart, pp(P) = " + pp); System.out.println("RI-ppart, pp(P)c(P) = " + pp.multiply(d)); throw new RuntimeException("RI-primitivePart: P != pp(P)*cont(P)"); } } return pp; } /** * GenSolvablePolynomial base recursive content. * @param P recursive GenSolvablePolynomial. * @return baseCont(P) with pp(P)*cont(P) = P. */ public C baseRecursiveContent(GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { GenSolvablePolynomialRing cf = (GenSolvablePolynomialRing) P.ring.coFac; return cf.coFac.getZERO(); } C d = null; for (GenPolynomial cp : P.getMap().values()) { GenSolvablePolynomial c = (GenSolvablePolynomial) cp; C cc = leftBaseContent(c); if (d == null) { d = cc; } else { d = gcd(d, cc); } if (d.isONE()) { return d; } } return d.abs(); } /** * GenSolvablePolynomial base recursive primitive part. * @param P recursive GenSolvablePolynomial. * @return basePP(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial> baseRecursivePrimitivePart( GenSolvablePolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } C d = baseRecursiveContent(P); if (d.isONE()) { return P; } GenSolvablePolynomial> pp = (GenSolvablePolynomial>) PolyUtil . baseRecursiveDivide(P, d); return pp; } /** * GenSolvablePolynomial left recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P recursive GenSolvablePolynomial. * @param S recursive GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial> leftRecursiveGcd(GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar == 1) { return leftRecursiveUnivariateGcd(P, S); } // distributed polynomials gcd GenSolvablePolynomialRing> rfac = P.ring; GenSolvablePolynomialRing dfac; if (rfac instanceof RecSolvablePolynomialRing) { RecSolvablePolynomialRing rf = (RecSolvablePolynomialRing) rfac; dfac = RecSolvablePolynomialRing. distribute(rf); } else { GenSolvablePolynomialRing df = (GenSolvablePolynomialRing) rfac; dfac = df.distribute(); } GenSolvablePolynomial Pd = (GenSolvablePolynomial) PolyUtil. distribute(dfac, P); GenSolvablePolynomial Sd = (GenSolvablePolynomial) PolyUtil. distribute(dfac, S); // left gcd GenSolvablePolynomial Dd = leftGcd(Pd, Sd); // convert back to recursive GenSolvablePolynomial> C = (GenSolvablePolynomial>) PolyUtil . recursive(rfac, Dd); return C; } /** * GenSolvablePolynomial right recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P recursive GenSolvablePolynomial. * @param S recursive GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial> rightRecursiveGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar == 1) { return rightRecursiveUnivariateGcd(P, S); } // distributed polynomials gcd GenSolvablePolynomialRing> rfac = P.ring; GenSolvablePolynomialRing dfac; if (rfac instanceof RecSolvablePolynomialRing) { RecSolvablePolynomialRing rf = (RecSolvablePolynomialRing) rfac; dfac = RecSolvablePolynomialRing. distribute(rf); } else { GenSolvablePolynomialRing df = (GenSolvablePolynomialRing) rfac; dfac = df.distribute(); } GenSolvablePolynomial Pd = (GenSolvablePolynomial) PolyUtil. distribute(dfac, P); GenSolvablePolynomial Sd = (GenSolvablePolynomial) PolyUtil. distribute(dfac, S); GenSolvablePolynomial Dd = rightGcd(Pd, Sd); // convert to recursive GenSolvablePolynomial> C = (GenSolvablePolynomial>) PolyUtil . recursive(rfac, Dd); return C; } /** * Univariate GenSolvablePolynomial recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ public abstract GenSolvablePolynomial> leftRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S); /** * Univariate GenSolvablePolynomial right recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ public abstract GenSolvablePolynomial> rightRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S); /** * GenSolvablePolynomial left content. * @param P GenSolvablePolynomial. * @return cont(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial leftContent(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { // baseContent not possible by return type throw new IllegalArgumentException("use baseContent() for univariate polynomials"); } GenSolvablePolynomialRing> rfac // = (RecSolvablePolynomialRing) = pfac.recursive(1); GenSolvablePolynomial> Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); GenSolvablePolynomial D = leftRecursiveContent(Pr); return D; } /** * GenSolvablePolynomial left primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with cont(P)*pp(P) = P. */ public GenSolvablePolynomial leftPrimitivePart(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return leftBasePrimitivePart(P); } GenSolvablePolynomialRing> rfac = /*(RecSolvablePolynomialRing)*/pfac .recursive(1); GenSolvablePolynomial> Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); GenSolvablePolynomial> PP = leftRecursivePrimitivePart(Pr); GenSolvablePolynomial D = (GenSolvablePolynomial) PolyUtil. distribute(pfac, PP); return D; } /** * GenSolvablePolynomial right content. * @param P GenSolvablePolynomial. * @return cont(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial rightContent(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { // baseContent not possible by return type throw new IllegalArgumentException("use baseContent() for univariate polynomials"); } GenSolvablePolynomialRing> rfac // = (RecSolvablePolynomialRing) = pfac.recursive(1); GenSolvablePolynomial> Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); GenSolvablePolynomial D = rightRecursiveContent(Pr); return D; } /** * GenSolvablePolynomial right primitive part. * @param P GenSolvablePolynomial. * @return pp(P) with pp(P)*cont(P) = P. */ public GenSolvablePolynomial rightPrimitivePart(GenSolvablePolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } if (P.isZERO()) { return P; } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return rightBasePrimitivePart(P); } GenSolvablePolynomialRing> rfac = /*(RecSolvablePolynomialRing)*/pfac .recursive(1); GenSolvablePolynomial> Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); GenSolvablePolynomial> PP = rightRecursivePrimitivePart(Pr); GenSolvablePolynomial D = (GenSolvablePolynomial) PolyUtil. distribute(pfac, PP); return D; } /** * GenSolvablePolynomial division. Indirection to GenSolvablePolynomial * method. * @param a GenSolvablePolynomial. * @param b coefficient. * @return a' = a/b with a = a'*b. */ public GenSolvablePolynomial divide(GenSolvablePolynomial a, C b) { if (b == null || b.isZERO()) { throw new IllegalArgumentException("division by zero"); } if (a == null || a.isZERO()) { return a; } return (GenSolvablePolynomial) a.leftDivideCoeff(b); } /** * GenSolvablePolynomial right division. Indirection to GenSolvablePolynomial * method. * @param a GenSolvablePolynomial. * @param b coefficient. * @return a' = a/b with a = b*a'. */ public GenSolvablePolynomial rightDivide(GenSolvablePolynomial a, C b) { if (b == null || b.isZERO()) { throw new IllegalArgumentException("division by zero"); } if (a == null || a.isZERO()) { return a; } return (GenSolvablePolynomial) a.rightDivideCoeff(b); } /** * Coefficient greatest common divisor. Indirection to coefficient method. * @param a coefficient. * @param b coefficient. * @return gcd(a,b) with a = gcd(a,b)*a' and b = gcd(a,b)*b'. */ public C gcd(C a, C b) { if (b == null || b.isZERO()) { return a; } if (a == null || a.isZERO()) { return b; } return a.gcd(b); } /** * Coefficient greatest common divisor. Indirection to coefficient method. * @param a coefficient. * @param b coefficient. * @return gcd(a,b) with a = gcd(a,b)*a' and b = gcd(a,b)*b'. */ public C leftGcd(C a, C b) { return a.leftGcd(b); } /** * GenSolvablePolynomial greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ public GenSolvablePolynomial leftGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.isONE()) { return P; } if (S.isONE()) { return S; } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { GenSolvablePolynomial T = leftBaseGcd(P, S); return T; } GenSolvablePolynomialRing> rfac = pfac.recursive(1); //RecSolvablePolynomialRing GenSolvablePolynomial> Pr, Sr, Dr; Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); Sr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, S); Dr = leftRecursiveUnivariateGcd(Pr, Sr); GenSolvablePolynomial D = (GenSolvablePolynomial) PolyUtil. distribute(pfac, Dr); if (debug) { // not checkable GenSolvablePolynomial ps = FDUtil. rightBaseSparsePseudoRemainder(P, D); GenSolvablePolynomial ss = FDUtil. rightBaseSparsePseudoRemainder(S, D); if (!ps.isZERO() || !ss.isZERO()) { System.out.println("fullGcd, D = " + D); System.out.println("fullGcd, P = " + P); System.out.println("fullGcd, S = " + S); System.out.println("fullGcd, ps = " + ps); System.out.println("fullGcd, ss = " + ss); throw new RuntimeException("fullGcd: not divisible"); } logger.info("fullGcd(P,S) okay: D = {}, P = {}, S = {}", D, P, S); } return D; } /** * GenSolvablePolynomial left least common multiple. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return lcm(P,S) with lcm(P,S) = P'*P = S'*S. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftLcm(GenSolvablePolynomial P, GenSolvablePolynomial S) { GenSolvablePolynomial[] oc = leftOreCond(P, S); return oc[0].multiply(P); } /** * Coefficient greatest common divisor. Indirection to coefficient method. * @param a coefficient. * @param b coefficient. * @return gcd(a,b) with a = gcd(a,b)*a' and b = gcd(a,b)*b'. */ public C rightGcd(C a, C b) { if (b == null || b.isZERO()) { return a; } if (a == null || a.isZERO()) { return b; } return a.rightGcd(b); // TODO } /** * GenSolvablePolynomial right greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.isONE()) { return P; } if (S.isONE()) { return S; } GenSolvablePolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { GenSolvablePolynomial T = rightBaseGcd(P, S); return T; } GenSolvablePolynomialRing> rfac = pfac.recursive(1); //RecSolvablePolynomialRing GenSolvablePolynomial> Pr, Sr, Dr; Pr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, P); Sr = (RecSolvablePolynomial) PolyUtil. recursive(rfac, S); Dr = rightRecursiveUnivariateGcd(Pr, Sr); GenSolvablePolynomial D = (GenSolvablePolynomial) PolyUtil. distribute(pfac, Dr); if (debug) { // not checkable GenSolvablePolynomial ps = FDUtil. leftBaseSparsePseudoRemainder(P, D); GenSolvablePolynomial ss = FDUtil. leftBaseSparsePseudoRemainder(S, D); if (!ps.isZERO() || !ss.isZERO()) { System.out.println("RI-fullGcd, D = " + D); System.out.println("RI-fullGcd, P = " + P); System.out.println("RI-fullGcd, S = " + S); System.out.println("RI-fullGcd, ps = " + ps); System.out.println("RI-fullGcd, ss = " + ss); throw new RuntimeException("RI-fullGcd: not divisible"); } logger.info("RI-fullGcd(P,S) okay: D = {}", D); } return D; } /** * GenSolvablePolynomial right least common multiple. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return lcm(P,S) with lcm(P,S) = P*P' = S*S'. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightLcm(GenSolvablePolynomial P, GenSolvablePolynomial S) { GenSolvablePolynomial[] oc = rightOreCond(P, S); return P.multiply(oc[0]); } /** * List of GenSolvablePolynomials left greatest common divisor. * @param A non empty list of GenSolvablePolynomials. * @return gcd(A_i) with A_i = A'_i*gcd(A_i)*a_i, where deg_main(a_i) == 0. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftGcd(List> A) { if (A == null || A.isEmpty()) { throw new IllegalArgumentException("A may not be empty"); } GenSolvablePolynomial g = A.get(0); for (int i = 1; i < A.size(); i++) { GenSolvablePolynomial f = A.get(i); g = leftGcd(g, f); } return g; } /** * GenSolvablePolynomial co-prime list. * @param A list of GenSolvablePolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a. B does not contain zero or * constant polynomials. */ public List> leftCoPrime(List> A) { if (A == null || A.isEmpty()) { return A; } List> B = new ArrayList>(A.size()); // make a coprime to rest of list GenSolvablePolynomial a = A.get(0); //System.out.println("a = " + a); if (!a.isZERO() && !a.isConstant()) { for (int i = 1; i < A.size(); i++) { GenSolvablePolynomial b = A.get(i); GenSolvablePolynomial g = leftGcd(a, b); if (!g.isONE()) { a = FDUtil. leftBasePseudoQuotient(a, g); b = FDUtil. leftBasePseudoQuotient(b, g); GenSolvablePolynomial gp = leftGcd(a, g); //.abs(); while (!gp.isONE()) { a = FDUtil. leftBasePseudoQuotient(a, gp); g = FDUtil. leftBasePseudoQuotient(g, gp); B.add(g); // gcd(a,g) == 1 g = gp; gp = leftGcd(a, gp); } if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 } } if (!b.isZERO() && !b.isConstant()) { B.add(b); // gcd(a,b) == 1 } } } else { B.addAll(A.subList(1, A.size())); } // make rest coprime B = leftCoPrime(B); //System.out.println("B = " + B); if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { a = (GenSolvablePolynomial) a.abs(); B.add(a); } return B; } /** * GenSolvablePolynomial left co-prime list. * @param A list of GenSolvablePolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a. B does not contain zero or * constant polynomials. */ public List> leftCoPrimeRec(List> A) { if (A == null || A.isEmpty()) { return A; } List> B = new ArrayList>(); // make a co-prime to rest of list for (GenSolvablePolynomial a : A) { //System.out.println("a = " + a); B = leftCoPrime(a, B); //System.out.println("B = " + B); } return B; } /** * GenSolvablePolynomial left co-prime list. * @param a GenSolvablePolynomial. * @param P co-prime list of GenSolvablePolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a * there exists b in P with b|a. B does not contain zero or constant * polynomials. */ public List> leftCoPrime(GenSolvablePolynomial a, List> P) { if (a == null || a.isZERO() || a.isConstant()) { return P; } List> B = new ArrayList>(P.size() + 1); // make a coprime to elements of the list P for (int i = 0; i < P.size(); i++) { GenSolvablePolynomial b = P.get(i); GenSolvablePolynomial g = leftGcd(a, b); if (!g.isONE()) { a = FDUtil. leftBasePseudoQuotient(a, g); b = FDUtil. leftBasePseudoQuotient(b, g); // make g co-prime to new a, g is co-prime to c != b in P, B GenSolvablePolynomial gp = leftGcd(a, g); while (!gp.isONE()) { a = FDUtil. leftBasePseudoQuotient(a, gp); g = FDUtil. leftBasePseudoQuotient(g, gp); if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } g = gp; gp = leftGcd(a, gp); } // make new g co-prime to new b gp = leftGcd(b, g); while (!gp.isONE()) { b = FDUtil. leftBasePseudoQuotient(b, gp); g = FDUtil. leftBasePseudoQuotient(g, gp); if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } g = gp; gp = leftGcd(b, gp); } if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } } if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) { B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B } } if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { B.add(a); } return B; } /** * GenSolvablePolynomial test for co-prime list. * @param A list of GenSolvablePolynomials. * @return true if gcd(b,c) = 1 for all b != c in A, else false. */ public boolean isLeftCoPrime(List> A) { if (A == null || A.isEmpty()) { return true; } if (A.size() == 1) { return true; } for (int i = 0; i < A.size(); i++) { GenSolvablePolynomial a = A.get(i); for (int j = i + 1; j < A.size(); j++) { GenSolvablePolynomial b = A.get(j); GenSolvablePolynomial g = leftGcd(a, b); if (!g.isONE()) { System.out.println("not co-prime, a: " + a); System.out.println("not co-prime, b: " + b); System.out.println("not co-prime, g: " + g); return false; } } } return true; } /** * GenSolvablePolynomial test for left co-prime list of given list. * @param P list of co-prime GenSolvablePolynomials. * @param A list of GenSolvablePolynomials. * @return true if isCoPrime(P) and for all a in A exists p in P with p | a, * else false. */ public boolean isLeftCoPrime(List> P, List> A) { if (!isLeftCoPrime(P)) { return false; } if (A == null || A.isEmpty()) { return true; } for (GenSolvablePolynomial q : A) { if (q.isZERO() || q.isConstant()) { continue; } boolean divides = false; for (GenSolvablePolynomial p : P) { GenSolvablePolynomial a = FDUtil. leftBaseSparsePseudoRemainder(q, p); if (a.isZERO()) { // p divides q divides = true; break; } } if (!divides) { System.out.println("no divisor for: " + q); return false; } } return true; } /** * Univariate GenSolvablePolynomial extended greatest common divisor. Uses * sparse pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S). */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] baseExtendedGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { //return P.egcd(S); GenSolvablePolynomial[] hegcd = baseHalfExtendedGcd(P, S); GenSolvablePolynomial[] ret = (GenSolvablePolynomial[]) new GenSolvablePolynomial[3]; ret[0] = hegcd[0]; ret[1] = hegcd[1]; if (ret[0].isZERO()) { ret[1] = P.ring.getZERO(); ret[2] = P.ring.getZERO(); return ret; } GenSolvablePolynomial x = (GenSolvablePolynomial) hegcd[0].subtract(hegcd[1].multiply(P)); GenSolvablePolynomial[] qr = FDUtil. leftBasePseudoQuotientRemainder(x, S); // assert qr[1].isZERO() if (!qr[1].isZERO()) { //GenSolvablePolynomial y = (GenSolvablePolynomial) qr[0].multiply(S).sum(qr[1]); //System.out.println("qr: " + Arrays.toString(qr)); //System.out.println("x: " + x); //System.out.println("y: " + y); throw new RuntimeException("qr[1] != 0: " + Arrays.toString(qr)); } ret[2] = qr[0]; return ret; } /** * Univariate GenSolvablePolynomial half extended greatest common divisor. * Uses sparse pseudoRemainder for remainder. * @param S GenSolvablePolynomial. * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S). */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] baseHalfExtendedGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (P == null || S == null) { throw new IllegalArgumentException("null P or S not allowed"); } GenSolvablePolynomial[] ret = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; ret[0] = null; ret[1] = null; if (S.isZERO()) { ret[0] = P; ret[1] = P.ring.getONE(); return ret; } if (P.isZERO()) { ret[0] = S; ret[1] = S.ring.getZERO(); return ret; } if (P.ring.nvar != 1) { throw new IllegalArgumentException("for univariate polynomials only " + P.ring); } GenSolvablePolynomial q = P; GenSolvablePolynomial r = S; GenSolvablePolynomial c1 = P.ring.getONE().copy(); GenSolvablePolynomial d1 = P.ring.getZERO().copy(); while (!r.isZERO()) { GenSolvablePolynomial[] qr = FDUtil. leftBasePseudoQuotientRemainder(q, r); //q.divideAndRemainder(r); q = qr[0]; GenSolvablePolynomial x = (GenSolvablePolynomial) c1.subtract(q.multiply(d1)); c1 = d1; d1 = x; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiply(h); c1 = c1.multiply(h); } //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); ret[0] = q; ret[1] = c1; return ret; } /** * Univariate GenSolvablePolynomial greatest common divisor diophantine * version. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @param c univariate GenSolvablePolynomial. * @return [ a, b ] with a*P + b*S = c and deg(a) < deg(S). */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] baseGcdDiophant(GenSolvablePolynomial P, GenSolvablePolynomial S, GenSolvablePolynomial c) { GenSolvablePolynomial[] egcd = baseExtendedGcd(P, S); GenSolvablePolynomial g = egcd[0]; GenSolvablePolynomial[] qr = FDUtil. leftBasePseudoQuotientRemainder(c, g); if (!qr[1].isZERO()) { throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g); } GenSolvablePolynomial q = qr[0]; GenSolvablePolynomial a = egcd[1].multiply(q); GenSolvablePolynomial b = egcd[2].multiply(q); if (!a.isZERO() && a.degree(0) >= S.degree(0)) { qr = FDUtil. leftBasePseudoQuotientRemainder(a, S); a = qr[1]; b = (GenSolvablePolynomial) b.sum(P.multiply(qr[0])); } GenSolvablePolynomial[] ret = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; ret[0] = a; ret[1] = b; if (debug) { GenSolvablePolynomial y = (GenSolvablePolynomial) ret[0].multiply(P) .sum(ret[1].multiply(S)); if (!y.equals(c)) { System.out.println("P = " + P); System.out.println("S = " + S); System.out.println("c = " + c); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("y = " + y); throw new ArithmeticException("not diophant, x = " + y.subtract(c)); } } return ret; } /** * Coefficient left Ore condition. Generators for the left Ore condition of * two coefficients. * @param a coefficient. * @param b coefficient. * @return [oa, ob] = leftOreCond(a,b), with oa*a == ob*b. */ @SuppressWarnings("unchecked") public C[] leftOreCond(C a, C b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } C[] oc = (C[]) new GcdRingElem[2]; if (a instanceof GenSolvablePolynomial && b instanceof GenSolvablePolynomial) { GenSolvablePolynomial ap = (GenSolvablePolynomial) a; GenSolvablePolynomial bp = (GenSolvablePolynomial) b; GenSolvablePolynomial[] ocp = leftOreCond(ap, bp); oc[0] = (C) ocp[0]; oc[1] = (C) ocp[1]; return oc; } RingFactory rf = coFac; // not usable: (RingFactory) a.factory(); if (a.equals(b)) { // required because of rationals gcd oc[0] = rf.getONE(); oc[1] = rf.getONE(); logger.info("Ore multiple ==: {}", Arrays.toString(oc)); return oc; } if (a.equals(b.negate())) { // required because of rationals gcd oc[0] = rf.getONE(); oc[1] = rf.getONE().negate(); logger.info("Ore multiple ==-: {}", Arrays.toString(oc)); return oc; } if (rf.isCommutative()) { if (debug) { logger.info("left Ore condition on coefficients, commutative case: {}, {}", a, b); } C gcd = a.gcd(b); if (gcd.isONE()) { oc[0] = b; oc[1] = a; if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) { oc[0] = oc[0].negate(); oc[1] = oc[1].negate(); } logger.info("Ore multiple: {}", Arrays.toString(oc)); return oc; } C p = a.multiply(b); C lcm = p.divide(gcd).abs(); oc[0] = lcm.divide(a); oc[1] = lcm.divide(b); if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) { oc[0] = oc[0].negate(); oc[1] = oc[1].negate(); } logger.info("Ore multiple: lcm={}, gcd={}, {}", lcm, gcd, Arrays.toString(oc)); return oc; } // now non-commutative if (rf.isField()) { logger.info("left Ore condition on coefficients, skew field {} case: {}, {}", rf, a, b); //C gcd = a.gcd(b); // always one //C lcm = rf.getONE(); oc[0] = a.inverse(); //lcm.divide(a); oc[1] = b.inverse(); //lcm.divide(b); logger.info("Ore multiple: {}", Arrays.toString(oc)); return oc; } if (b instanceof StarRingElem) { logger.info("left Ore condition on coefficients, StarRing case: {}, {}", a, b); C bs = (C) ((StarRingElem) b).conjugate(); oc[0] = bs.multiply(b); // bar(b) b a = s a oc[1] = a.multiply(bs); // a bar(b) b = t b logger.info("Ore multiple: {}", Arrays.toString(oc)); return oc; } throw new UnsupportedOperationException( "leftOreCond not implemented for " + rf.getClass() + ", rf = " + rf.toScript()); //return oc; } /** * Left Ore condition. Generators for the left Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with p*a = q*b */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] leftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomialRing pfac = a.ring; GenSolvablePolynomial[] oc = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; if (a.equals(b)) { oc[0] = pfac.getONE(); oc[1] = pfac.getONE(); return oc; } if (a.equals(b.negate())) { oc[0] = pfac.getONE(); oc[1] = (GenSolvablePolynomial) pfac.getONE().negate(); return oc; } if (pfac.isCommutative()) { logger.info("left Ore condition, polynomial commutative case: {}, {}", a, b); edu.jas.ufd.GreatestCommonDivisorAbstract cgcd = GCDFactory. getImplementation(pfac.coFac); GenSolvablePolynomial lcm = (GenSolvablePolynomial) cgcd.lcm(a, b); //oc[0] = FDUtil. basePseudoQuotient(lcm, a); //oc[1] = FDUtil. basePseudoQuotient(lcm, b); oc[0] = (GenSolvablePolynomial) PolyUtil. basePseudoDivide(lcm, a); oc[1] = (GenSolvablePolynomial) PolyUtil. basePseudoDivide(lcm, b); logger.info("Ore multiple: {}, {}", lcm, Arrays.toString(oc)); return oc; } oc = syz.leftOreCond(a, b); //logger.info("Ore multiple: {}, {}", oc[0].multiply(a), Arrays.toString(oc)); return oc; } /** * Coefficient right Ore condition. Generators for the right Ore condition * of two coefficients. * @param a coefficient. * @param b coefficient. * @return [oa, ob] = rightOreCond(a,b), with a*oa == b*ob. */ @SuppressWarnings("unchecked") public C[] rightOreCond(C a, C b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } C[] oc = (C[]) new GcdRingElem[2]; if (a instanceof GenSolvablePolynomial && b instanceof GenSolvablePolynomial) { GenSolvablePolynomial ap = (GenSolvablePolynomial) a; GenSolvablePolynomial bp = (GenSolvablePolynomial) b; GenSolvablePolynomial[] ocp = rightOreCond(ap, bp); oc[0] = (C) ocp[0]; oc[1] = (C) ocp[1]; return oc; } RingFactory rf = coFac; // not usable: (RingFactory) a.factory(); if (a.equals(b)) { // required because of rationals gcd oc[0] = rf.getONE(); oc[1] = rf.getONE(); return oc; } if (a.equals(b.negate())) { // required because of rationals gcd oc[0] = rf.getONE(); oc[1] = rf.getONE().negate(); return oc; } if (rf.isCommutative()) { logger.info("right Ore condition on coefficients, commutative case: {}, {}", a, b); C gcd = a.gcd(b); if (gcd.isONE()) { oc[0] = b; oc[1] = a; if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) { oc[0] = oc[0].negate(); oc[1] = oc[1].negate(); } return oc; } C p = a.multiply(b); C lcm = p.divide(gcd).abs(); oc[0] = lcm.divide(a); oc[1] = lcm.divide(b); if (oc[0].compareTo(rf.getZERO()) < 0 && oc[1].compareTo(rf.getZERO()) < 0) { oc[0] = oc[0].negate(); oc[1] = oc[1].negate(); } logger.info("Ore multiple: {}, {}", lcm, Arrays.toString(oc)); return oc; } // now non-commutative if (rf.isField()) { logger.info("right Ore condition on coefficients, skew field {} case: {}, {}", rf, a, b); //C gcd = a.gcd(b); // always one //C lcm = rf.getONE(); oc[0] = a.inverse(); //lcm.divide(a); oc[1] = b.inverse(); //lcm.divide(b); logger.info("Ore multiple: {}", Arrays.toString(oc)); return oc; } if (b instanceof StarRingElem) { logger.info("right Ore condition on coefficients, StarRing case: {}, {}", a, b); C bs = (C) ((StarRingElem) b).conjugate(); oc[0] = b.multiply(bs); // a b bar(b) = a s oc[1] = bs.multiply(a); // b bar(b) a = b t logger.info("Ore multiple: {}", Arrays.toString(oc)); return oc; } throw new UnsupportedOperationException( "rightOreCond not implemented for " + rf.getClass() + ", rf = {}" + rf.toScript()); //return oc; } /** * Right Ore condition. Generators for the right Ore condition of two * solvable polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with a*p = b*q */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] rightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomialRing pfac = a.ring; GenSolvablePolynomial[] oc = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; if (a.equals(b)) { oc[0] = pfac.getONE(); oc[1] = pfac.getONE(); return oc; } if (a.equals(b.negate())) { oc[0] = pfac.getONE(); oc[1] = (GenSolvablePolynomial) pfac.getONE().negate(); return oc; } if (pfac.isCommutative()) { logger.info("right Ore condition, polynomial commutative case: {}, {}", a, b); edu.jas.ufd.GreatestCommonDivisorAbstract cgcd = GCDFactory. getImplementation(pfac.coFac); GenSolvablePolynomial lcm = (GenSolvablePolynomial) cgcd.lcm(a, b); //oc[0] = FDUtil. basePseudoQuotient(lcm, a); //oc[1] = FDUtil. basePseudoQuotient(lcm, b); oc[0] = (GenSolvablePolynomial) PolyUtil. basePseudoDivide(lcm, a); oc[1] = (GenSolvablePolynomial) PolyUtil. basePseudoDivide(lcm, b); logger.info("Ore multiple: {}, {}", lcm, Arrays.toString(oc)); return oc; } oc = syz.rightOreCond(a, b); //logger.info("Ore multiple: {}, {}", oc[0].multiply(a), Arrays.toString(oc)); return oc; } /** * Is left Ore condition. Test left Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @param p solvable polynomial * @param q solvable polynomial * @return true, if p*a = q*b, else false */ public boolean isLeftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial p, GenSolvablePolynomial q) { return syz.isLeftOreCond(a, b, p, q); } /** * Is right Ore condition. Test right Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @param p solvable polynomial * @param q solvable polynomial * @return true, if a*p = b*q, else false */ public boolean isRightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial p, GenSolvablePolynomial q) { return syz.isRightOreCond(a, b, p, q); } /** * Left greatest common divisor and cofactors. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return [ g=leftGcd(n,d), n/g, d/g ] */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] leftGcdCofactors(GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { logger.info("leftGCD_in: {}, {}", n, d); GenSolvablePolynomial[] res = (GenSolvablePolynomial[]) new GenSolvablePolynomial[3]; res[0] = leftGcd(n, d); //res[0] = PolyModUtil. syzLeftGcd(r, n, d); res[1] = n; res[2] = d; if (res[0].isONE()) { return res; } logger.info("leftGCD_out: {}", res[0]); GenSolvablePolynomial[] nqr; nqr = FDUtil. rightBasePseudoQuotientRemainder(n, res[0]); if (!nqr[1].isZERO()) { res[0] = r.getONE(); return res; } GenSolvablePolynomial[] dqr; dqr = FDUtil. rightBasePseudoQuotientRemainder(d, res[0]); if (!dqr[1].isZERO()) { res[0] = r.getONE(); return res; } res[1] = nqr[0]; res[2] = dqr[0]; return res; } /** * Right greatest common divisor and cofactors. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return [ g=rightGcd(n,d), n/g, d/g ] */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] rightGcdCofactors(GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { logger.info("rightGCD_in: {}, {}", n, d); GenSolvablePolynomial[] res = (GenSolvablePolynomial[]) new GenSolvablePolynomial[3]; res[0] = rightGcd(n, d); //res[0] = PolyModUtil. syzRightGcd(r, n, d); res[1] = n; res[2] = d; if (res[0].isONE()) { return res; } logger.info("rightGCD_out: {}", res[0]); GenSolvablePolynomial[] nqr; nqr = FDUtil. leftBasePseudoQuotientRemainder(n, res[0]); if (!nqr[1].isZERO()) { res[0] = r.getONE(); return res; } GenSolvablePolynomial[] dqr; dqr = FDUtil. leftBasePseudoQuotientRemainder(d, res[0]); if (!dqr[1].isZERO()) { res[0] = r.getONE(); return res; } res[1] = nqr[0]; res[2] = dqr[0]; return res; } } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisorFake.java000066400000000000000000000103521445075545500261720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * (Non-unique) factorization domain greatest common divisor common algorithms * with monic polynomial remainder sequence. Fake implementation always returns * 1 for any gcds. * @param coefficient type * @author Heinz Kredel */ public class GreatestCommonDivisorFake> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorFake.class); //private static final boolean debug = true; //logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient ring. */ public GreatestCommonDivisorFake(RingFactory cf) { super(cf); } /** * Univariate GenSolvablePolynomial greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return 1 = gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial leftBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } logger.warn("fake gcd always returns 1"); return P.ring.getONE(); } /** * Univariate GenSolvablePolynomial right greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return 1 = gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. */ @Override public GenSolvablePolynomial rightBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } logger.warn("fake gcd always returns 1"); return P.ring.getONE(); } /** * Univariate GenSolvablePolynomial left recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return 1 = gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> leftRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } return P.ring.getONE(); } /** * Univariate GenSolvablePolynomial right recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return 1 = gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> rightRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } return P.ring.getONE(); } } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisorPrimitive.java000066400000000000000000000362611445075545500273030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * (Non-unique) factorization domain greatest common divisor common algorithms * with primitive polynomial remainder sequence. * @param coefficient type * @author Heinz Kredel */ public class GreatestCommonDivisorPrimitive> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorPrimitive.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient ring. */ public GreatestCommonDivisorPrimitive(RingFactory cf) { super(cf); } /** * Univariate GenSolvablePolynomial greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial leftBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.ring.coFac.isField(); System.out.println("baseGcd: field = " + field + ", is " + P.ring.coFac.toScript()); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial q; GenSolvablePolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } C c; if (field) { r = r.monic(); q = q.monic(); c = P.ring.getONECoefficient(); } else { r = (GenSolvablePolynomial) r.abs(); q = (GenSolvablePolynomial) q.abs(); C a = leftBaseContent(r); C b = leftBaseContent(q); r = divide(r, a); // indirection q = divide(q, b); // indirection c = gcd(a, b); // indirection } System.out.println("baseCont: gcd(cont) = " + c); if (r.isONE()) { return r.multiplyLeft(c); } if (q.isONE()) { return q.multiplyLeft(c); } GenSolvablePolynomial x; logger.info("baseGCD: q = {}", q); logger.info("baseGCD: r = {}", r); System.out.println("baseGcd: rem = " + r); while (!r.isZERO()) { x = FDUtil. leftBaseSparsePseudoRemainder(q, r); q = r; if (field) { r = x.monic(); } else { r = leftBasePrimitivePart(x); } System.out.println("baseGcd: rem = " + r); logger.info("baseGCD: q = {}", q); logger.info("baseGCD: r = {}", r); } System.out.println("baseGcd: quot = " + q); q = leftBasePrimitivePart(q); logger.info("baseGCD: pp(q) = {}", q); return (GenSolvablePolynomial) (q.multiply(c)).abs(); } /** * Univariate GenSolvablePolynomial right greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. */ @Override public GenSolvablePolynomial rightBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.ring.coFac.isField(); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial q; GenSolvablePolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } C c; if (field) { r = r.monic(); q = q.monic(); c = P.ring.getONECoefficient(); } else { r = (GenSolvablePolynomial) r.abs(); q = (GenSolvablePolynomial) q.abs(); C a = leftBaseContent(r); C b = leftBaseContent(q); r = divide(r, a); // indirection q = divide(q, b); // indirection c = gcd(a, b); // indirection } //System.out.println("baseCont: gcd(cont) = " + b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenSolvablePolynomial x; //System.out.println("baseGCD: q = " + q); //System.out.println("baseGCD: r = " + r); while (!r.isZERO()) { x = FDUtil. rightBaseSparsePseudoRemainder(q, r); q = r; if (field) { r = x.monic(); } else { r = rightBasePrimitivePart(x); } //System.out.println("baseGCD: q = " + q); //System.out.println("baseGCD: r = " + r); } q = leftBasePrimitivePart(q); // todo return (GenSolvablePolynomial) (q.multiplyLeft(c)).abs(); } /** * Univariate GenSolvablePolynomial left recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> leftRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } //boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); boolean field = P.ring.coFac.isField(); System.out.println("recursiveUnivGcd: field = " + field); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial> q, r, x, qs, rs; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else if (f < e) { q = P; r = S; } else { // f == e if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { q = P; r = S; } else { r = P; q = S; } } logger.debug("degrees: e = {}, f = {}", e, f); if (field) { r = PolyUtil. monic(r); q = PolyUtil. monic(q); } else { r = (GenSolvablePolynomial>) r.abs(); q = (GenSolvablePolynomial>) q.abs(); } GenSolvablePolynomial a = leftRecursiveContent(r); System.out.println("recursiveUnivGcd: a = " + a); rs = FDUtil. recursiveLeftDivide(r, a); System.out.println("recursiveUnivGcd: rs = " + rs); //logger.info("recCont a = {}, r = {}", a, r); if (!r.equals(rs.multiplyLeft(a))) { // todo: should be rs.multiplyLeft(a)) System.out.println("recursiveUnivGcd: r = " + r); System.out.println("recursiveUnivGcd: cont(r) = " + a); System.out.println("recursiveUnivGcd: pp(r) = " + rs); System.out.println("recursiveUnivGcd: pp(r)c(r) = " + rs.multiply(a)); System.out.println("recursiveUnivGcd: c(r)pp(r) = " + rs.multiplyLeft(a)); throw new RuntimeException("recursiveUnivGcd: r: not divisible"); } r = rs; GenSolvablePolynomial b = leftRecursiveContent(q); System.out.println("recursiveUnivGcd: b = " + b); qs = FDUtil. recursiveLeftDivide(q, b); System.out.println("recursiveUnivGcd: qs = " + qs); //logger.info("recCont b = {}, q = {}", b, q); if (!q.equals(qs.multiplyLeft(b))) { // todo: should be qs.multiplyLeft(b)) System.out.println("recursiveUnivGcd: q = " + q); System.out.println("recursiveUnivGcd: cont(q) = " + b); System.out.println("recursiveUnivGcd: pp(q) = " + qs); System.out.println("recursiveUnivGcd: pp(q)c(q) = " + qs.multiply(b)); System.out.println("recursiveUnivGcd: c(q)pp(q) = " + qs.multiplyLeft(b)); throw new RuntimeException("recursiveUnivGcd: q: not divisible"); } q = qs; GenSolvablePolynomial c = leftGcd(a, b); // go to recursion //GenSolvablePolynomial c = rightGcd(a, b); // go to recursion logger.info("Gcd(contents) c = {}, a = {}, b = {}", c, a, b); if (r.isONE()) { return r.multiplyLeft(c); } if (q.isONE()) { return q.multiplyLeft(c); } logger.info("r.ring = {}", r.ring.toScript()); System.out.println("recursiveUnivGcd: r = " + r); while (!r.isZERO()) { x = FDUtil. recursiveSparsePseudoRemainder(q, r); q = r; if (field) { r = PolyUtil. monic(x); } else { r = leftRecursivePrimitivePart(x); } System.out.println("recursiveUnivGcd: r = " + r); } if (debug) { logger.info("gcd(pp) = {}, ring = {}", q, P.ring.toScript()); } q = leftRecursivePrimitivePart(q); q = (GenSolvablePolynomial>) q.multiplyLeft(c).abs(); return q; } /** * Univariate GenSolvablePolynomial right recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> rightRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); //boolean field = P.ring.coFac.isField(); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial> q, r, x, qs, rs; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else if (f < e) { q = P; r = S; } else { // f == e if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { q = P; r = S; } else { r = P; q = S; } } if (debug) { logger.debug("RI-degrees: e = {}, f = {}", e, f); } if (field) { r = PolyUtil. monic(r); q = PolyUtil. monic(q); } else { r = (GenSolvablePolynomial>) r.abs(); q = (GenSolvablePolynomial>) q.abs(); } GenSolvablePolynomial a = leftRecursiveContent(r); rs = FDUtil. recursiveRightDivide(r, a); if (debug) { logger.info("RI-recCont a = {}, r = {}", a, r); logger.info("RI-recCont r/a = {}, r%a = {}", r, r.subtract(rs.multiplyLeft(a))); if (!r.equals(rs.multiplyLeft(a))) { System.out.println("RI-recGcd: r = " + r); System.out.println("RI-recGcd: cont(r) = " + a); System.out.println("RI-recGcd: pp(r) = " + rs); System.out.println("RI-recGcd: pp(r)c(r) = " + rs.multiply(a)); System.out.println("RI-recGcd: c(r)pp(r) = " + rs.multiplyLeft(a)); throw new RuntimeException("RI-recGcd: pp: not divisible"); } } r = rs; GenSolvablePolynomial b = leftRecursiveContent(q); qs = FDUtil. recursiveRightDivide(q, b); if (debug) { logger.info("RI-recCont b = {}, q = {}", b, q); logger.info("RI-recCont q/b = {}, q%b = {}", qs, q.subtract(qs.multiplyLeft(b))); if (!q.equals(qs.multiplyLeft(b))) { System.out.println("RI-recGcd: q = " + q); System.out.println("RI-recGcd: cont(q) = " + b); System.out.println("RI-recGcd: pp(q) = " + qs); System.out.println("RI-recGcd: pp(q)c(q) = " + qs.multiply(b)); System.out.println("RI-recGcd: c(q)pp(q) = " + qs.multiplyLeft(b)); throw new RuntimeException("RI-recGcd: pp: not divisible"); } } q = qs; //no: GenSolvablePolynomial c = rightGcd(a, b); // go to recursion GenSolvablePolynomial c = leftGcd(a, b); // go to recursion logger.info("RI-Gcd(contents) c = {}, a = {}, b = {}", c, a, b); if (r.isONE()) { return r.multiplyLeft(c); } if (q.isONE()) { return q.multiplyLeft(c); } if (debug) { logger.info("RI-r.ring = {}", r.ring.toScript()); } while (!r.isZERO()) { x = FDUtil. recursiveRightSparsePseudoRemainder(q, r); q = r; if (field) { r = PolyUtil. monic(x); } else { r = leftRecursivePrimitivePart(x); } } logger.info("RI-recGcd(P,S) pre pp okay: q = {}", q); //q = rightRecursivePrimitivePart(q); q = leftRecursivePrimitivePart(q); // sic System.out.println("RI-recGcd: pp(q) = " + q); if (debug) { logger.info("RI-gcd(pp) = {}, ring = {}", q, P.ring.toScript()); } q = (GenSolvablePolynomial>) q.multiplyLeft(c).abs(); return q; } } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisorSimple.java000066400000000000000000000432041445075545500265570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * (Non-unique) factorization domain greatest common divisor common algorithms * with monic polynomial remainder sequence. If C is a field, then the monic PRS * (on coefficients) is computed otherwise no simplifications in the reduction * are made. * @param coefficient type * @author Heinz Kredel */ public class GreatestCommonDivisorSimple> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorSimple.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient ring. */ public GreatestCommonDivisorSimple(RingFactory cf) { super(cf); } /** * Univariate GenSolvablePolynomial greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial leftBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.ring.coFac.isField(); System.out.println("baseGcd: field = " + field + ", is " + P.ring.coFac.toScript()); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial q; GenSolvablePolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } logger.info("degrees: e = {}, f = {}", e, f); C c; if (field) { r = r.monic(); q = q.monic(); c = P.ring.getONECoefficient(); } else { r = (GenSolvablePolynomial) r.abs(); q = (GenSolvablePolynomial) q.abs(); C a = leftBaseContent(r); C b = leftBaseContent(q); r = divide(r, a); // indirection q = divide(q, b); // indirection c = leftGcd(a, b); // indirection } System.out.println("baseCont: gcd(cont) = " + c); if (r.isONE()) { return r.multiplyLeft(c); } if (q.isONE()) { return q.multiplyLeft(c); } GenSolvablePolynomial x; logger.info("baseGCD: q = {}", q); logger.info("baseGCD: r = {}", r); System.out.println("baseGcd: rem = " + r); while (!r.isZERO()) { x = FDUtil. leftBaseSparsePseudoRemainder(q, r); q = r; if (field) { r = x.monic(); } else { r = x; } System.out.println("baseGcd: rem = " + r); logger.info("baseGCD_w: q = {}", q); logger.info("baseGCD_w: r = {}", r); } System.out.println("baseGcd: quot = " + q); q = leftBasePrimitivePart(q); logger.info("baseGCD: pp(q) = {}", q); return (GenSolvablePolynomial) (q.multiplyLeft(c)).abs(); } /** * Univariate GenSolvablePolynomial right greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. */ @Override public GenSolvablePolynomial rightBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.ring.coFac.isField(); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial q; GenSolvablePolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } logger.debug("degrees: e = {}, f = {}", e, f); C c; if (field) { r = r.monic(); q = q.monic(); c = P.ring.getONECoefficient(); } else { r = (GenSolvablePolynomial) r.abs(); q = (GenSolvablePolynomial) q.abs(); C a = rightBaseContent(r); C b = rightBaseContent(q); r = rightDivide(r, a); // indirection q = rightDivide(q, b); // indirection c = rightGcd(a, b); // indirection } //System.out.println("baseCont: gcd(cont) = " + b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenSolvablePolynomial x; //System.out.println("baseGCD: q = " + q); //System.out.println("baseGCD: r = " + r); while (!r.isZERO()) { x = FDUtil. rightBaseSparsePseudoRemainder(q, r); q = r; if (field) { r = x.monic(); } else { r = x; } //System.out.println("baseGCD: q = " + q); //System.out.println("baseGCD: r = " + r); } q = rightBasePrimitivePart(q); ///q = leftBasePrimitivePart(q); return (GenSolvablePolynomial) (q.multiply(c)).abs(); } /** * Univariate GenSolvablePolynomial left recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> leftRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } //boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); //boolean field = P.leadingBaseCoefficient().ring.isField(); boolean field = P.ring.coFac.isField(); System.out.println("recursiveUnivGcd: field = " + field); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial> q, r, x, qs, rs, qp, rp; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else if (f < e) { q = P; r = S; } else { // f == e if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { q = P; r = S; } else { r = P; q = S; } } logger.debug("degrees: e = {}, f = {}", e, f); if (field) { r = PolyUtil. monic(r); q = PolyUtil. monic(q); } else { r = (GenSolvablePolynomial>) r.abs(); q = (GenSolvablePolynomial>) q.abs(); } GenSolvablePolynomial a = leftRecursiveContent(r); System.out.println("recursiveUnivGcd: a = " + a); rs = FDUtil. recursiveLeftDivide(r, a); System.out.println("recursiveUnivGcd: rs = " + rs); //logger.info("recCont a = {}, r = {}", a, r); if (!r.equals(rs.multiplyLeft(a))) { // todo: should be rs.multiplyLeft(a)) System.out.println("recursiveUnivGcd: r = " + r); System.out.println("recursiveUnivGcd: cont(r) = " + a); System.out.println("recursiveUnivGcd: pp(r) = " + rs); System.out.println("recursiveUnivGcd: pp(r)c(r) = " + rs.multiply(a)); System.out.println("recursiveUnivGcd: c(r)pp(r) = " + rs.multiplyLeft(a)); throw new RuntimeException("recursiveUnivGcd: r: not divisible"); } r = rs; //GenSolvablePolynomial b = rightRecursiveContent(q); GenSolvablePolynomial b = leftRecursiveContent(q); System.out.println("recursiveUnivGcd: b = " + b); qs = FDUtil. recursiveLeftDivide(q, b); System.out.println("recursiveUnivGcd: qs = " + qs); //qs = FDUtil. recursiveRightDivide(q, b); //logger.info("recCont b = {}, q = {}", b, q); if (!q.equals(qs.multiplyLeft(b))) { // todo: should be qs.multiplyLeft(b)) System.out.println("recursiveUnivGcd: q = " + q); System.out.println("recursiveUnivGcd: cont(q) = " + b); System.out.println("recursiveUnivGcd: pp(q) = " + qs); System.out.println("recursiveUnivGcd: pp(q)c(q) = " + qs.multiply(b)); System.out.println("recursiveUnivGcd: c(q)pp(q) = " + qs.multiplyLeft(b)); throw new RuntimeException("recursiveUnivGcd: q: not divisible"); } q = qs; logger.info("Gcd(content).ring = {}, a = {}, b = {}", a.ring.toScript(), a, b); GenSolvablePolynomial c = leftGcd(a, b); // go to recursion //GenSolvablePolynomial c = rightGcd(a, b); // go to recursion logger.info("Gcd(contents) c = {}, a = {}, b = {}", c, a, b); if (r.isONE()) { return r.multiplyLeft(c); } if (q.isONE()) { return q.multiplyLeft(c); } if (debug) { logger.info("r.ring = {}", r.ring.toScript()); logger.info("gcd-loop, start: q = {}, r = {}", q, r); } System.out.println("recursiveUnivGcd: r = " + r); while (!r.isZERO()) { x = FDUtil. recursiveSparsePseudoRemainder(q, r); q = r; if (field) { r = PolyUtil. monic(x); //r = x.leftMonic(); } else { r = x; } System.out.println("recursiveUnivGcd: r = " + r); if (debug) { logger.info("gcd-loop, rem: q = {}, r = {}", q, r); } } logger.info("gcd(div) = {}, rs = {}, qs = {}", q, rs, qs); rp = FDUtil. recursiveSparsePseudoRemainder(rs, q); qp = FDUtil. recursiveSparsePseudoRemainder(qs, q); if (!qp.isZERO() || !rp.isZERO()) { logger.info("gcd(div): rem(r,g) = {}, rem(q,g) = {}", rp, qp); rp = FDUtil. recursivePseudoQuotient(rs, q); qp = FDUtil. recursivePseudoQuotient(qs, q); logger.info("gcd(div): r/g = {}, q/g = {}", rp, qp); throw new RuntimeException("recGcd: div: not divisible"); } qp = q; //q = rightRecursivePrimitivePart(q); q = leftRecursivePrimitivePart(q); if (!qp.equals(q)) { logger.info("gcd(pp) = {}, qp = {}", q, qp); } q = (GenSolvablePolynomial>) q.multiplyLeft(c).abs(); return q; } /** * Univariate GenSolvablePolynomial right recursive greatest common divisor. * Uses pseudoRemainder for remainder. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> rightRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } //boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); boolean field = P.ring.coFac.isField(); System.out.println("r_recursiveUnivGcd: field = " + field); long e = P.degree(0); long f = S.degree(0); GenSolvablePolynomial> q, r, x, qs, rs, qp, rp; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else if (f < e) { q = P; r = S; } else { // f == e if (P.leadingBaseCoefficient().degree() > S.leadingBaseCoefficient().degree()) { q = P; r = S; } else { r = P; q = S; } } logger.debug("RI-degrees: e = {}, f = {}", e, f); if (field) { r = PolyUtil. monic(r); q = PolyUtil. monic(q); } else { r = (GenSolvablePolynomial>) r.abs(); q = (GenSolvablePolynomial>) q.abs(); } GenSolvablePolynomial a = rightRecursiveContent(r); //no: rs = FDUtil. recursiveLeftDivide(r, a); rs = FDUtil. recursiveRightDivide(r, a); System.out.println("recursiveUnivGcd: rs = " + rs); System.out.println("recursiveUnivGcd: r = " + r + ", rs * a = " + rs.multiply(a)); System.out.println("recursiveUnivGcd: r = " + r + ", a * rs = " + rs.multiplyLeft(a)); //logger.info("RI-recCont a = {}, r = {}", a, r); //logger.info("RI-recCont r/a = {}, r%a = {}", r, r.subtract(rs.multiplyLeft(a))); if (!r.equals(rs.multiply(a))) { // Left System.out.println("RI-recGcd: r = " + r); System.out.println("RI-recGcd: cont(r) = " + a); System.out.println("RI-recGcd: pp(r) = " + rs); System.out.println("RI-recGcd: pp(r)c(r) = " + rs.multiply(a)); System.out.println("RI-recGcd: c(r)pp(r) = " + rs.multiplyLeft(a)); throw new RuntimeException("RI-recGcd: pp: not divisible"); } r = rs; GenSolvablePolynomial b = rightRecursiveContent(q); System.out.println("recursiveUnivGcd: b = " + b); qs = FDUtil. recursiveRightDivide(q, b); System.out.println("recursiveUnivGcd: qs = " + qs); System.out.println("recursiveUnivGcd: q = " + q + ", qs * b = " + qs.multiply(b)); System.out.println("recursiveUnivGcd: q = " + q + ", b * qs = " + qs.multiplyLeft(b)); //logger.info("RI-recCont b = {}, q = {}", b, q); //logger.info("RI-recCont q/b = {}, q%b = {}", qs, q.subtract(qs.multiplyLeft(b))); if (!q.equals(qs.multiply(b))) { // Left System.out.println("RI-recGcd: q = " + q); System.out.println("RI-recGcd: cont(q) = " + b); System.out.println("RI-recGcd: pp(q) = " + qs); System.out.println("RI-recGcd: pp(q)c(q) = " + qs.multiply(b)); System.out.println("RI-recGcd: c(q)pp(q) = " + qs.multiplyLeft(b)); throw new RuntimeException("RI-recGcd: pp: not divisible"); } q = qs; //no: GenSolvablePolynomial c = rightGcd(a, b); // go to recursion GenSolvablePolynomial c = rightGcd(a, b); // go to recursion logger.info("RI-Gcd(contents) c = {}, a = {}, b = {}", c, a, b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } if (debug) { logger.info("RI-r.ring = {}", r.ring.toScript()); logger.info("RI-gcd-loop, start: q = {}, r = {}", q, r); } while (!r.isZERO()) { x = FDUtil. recursiveRightSparsePseudoRemainder(q, r); q = r; if (field) { r = PolyUtil. monic(x); } else { r = x; } if (debug) { logger.info("RI-gcd-loop, rem: q = {}, r = {}", q, r); } } logger.info("RI-gcd(div) = {}, rs = {}, qs = {}", q, rs, qs); rp = FDUtil. recursiveRightSparsePseudoRemainder(rs, q); qp = FDUtil. recursiveRightSparsePseudoRemainder(qs, q); if (!qp.isZERO() || !rp.isZERO()) { logger.info("RI-gcd(div): rem(r,g) = {}, rem(q,g) = {}", rp, qp); rp = FDUtil. recursivePseudoQuotient(rs, q); qp = FDUtil. recursivePseudoQuotient(qs, q); logger.info("RI-gcd(div): r/g = {}, q/g = {}", rp, qp); //logger.info("gcd(div): rp*g = {}, qp*g = {}", rp.multiply(q), qp.multiply(q)); throw new RuntimeException("recGcd: div: not divisible"); } qp = q; logger.info("RI-recGcd(P,S) pre pp okay: qp = {}", qp); q = rightRecursivePrimitivePart(q); //q = leftRecursivePrimitivePart(q); // sic if (!qp.equals(q)) { logger.info("RI-gcd(pp) = {}, qp = {}", q, qp); // + ", ring = {}", P.ring.toScript()); } q = (GenSolvablePolynomial>) q.multiply(c).abs(); return q; } } java-algebra-system-2.7.200/src/edu/jas/fd/GreatestCommonDivisorSyzygy.java000066400000000000000000000171671445075545500266550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * (Non-unique) factorization domain greatest common divisor common algorithms * with syzygy computation. The implementation uses solvable syzygy gcd * computation. * @param coefficient type * @author Heinz Kredel */ public class GreatestCommonDivisorSyzygy> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorSyzygy.class); private static final boolean debug = true; //logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient ring. */ public GreatestCommonDivisorSyzygy(RingFactory cf) { super(cf); } /** * Left univariate GenSolvablePolynomial greatest common divisor. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial leftBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { return leftGcd(P, S); } /** * Right univariate GenSolvablePolynomial greatest common divisor. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial rightBaseGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { return rightGcd(P, S); } /** * Left GenSolvablePolynomial greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S) and S = S'*gcd(P,S). */ @Override public GenSolvablePolynomial leftGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.isConstant()) { return P.ring.getONE(); } if (S.isConstant()) { return P.ring.getONE(); } List> A = new ArrayList>(2); A.add(P); A.add(S); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); logger.info("left syzGcd computing GB: {}", A); List> G = sbb.rightGB(A); //not: leftGB, not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.info("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return P.ring.getONE(); } /** * Right GenSolvablePolynomial right greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return gcd(P,S) with P = gcd(P,S)*P' and S = gcd(P,S)*S'. */ @Override public GenSolvablePolynomial rightGcd(GenSolvablePolynomial P, GenSolvablePolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.isConstant()) { return P.ring.getONE(); } if (S.isConstant()) { return P.ring.getONE(); } List> A = new ArrayList>(2); A.add(P); A.add(S); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); logger.info("left syzGcd computing GB: {}", A); List> G = sbb.leftGB(A); //not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.info("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return P.ring.getONE(); } /** * Univariate GenSolvablePolynomial left recursive greatest common divisor. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = P'*gcd(P,S)*p and S = S'*gcd(P,S)*s, where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> leftRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } if (P.isConstant()) { return P.ring.getONE(); } if (S.isConstant()) { return P.ring.getONE(); } List>> A = new ArrayList>>( 2); A.add(P); A.add(S); SolvableGroebnerBaseAbstract> sbb = new SolvableGroebnerBaseSeq>(); logger.info("left syzGcd computing GB: {}", A); // will not work, not field List>> G = sbb.rightGB(A); //not: leftGB, not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.info("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return P.ring.getONE(); } /** * Univariate GenSolvablePolynomial right recursive greatest common divisor. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S) with P = p*gcd(P,S)*P' and S = s*gcd(P,S)*S', where * deg_main(p) = deg_main(s) == 0. */ @Override public GenSolvablePolynomial> rightRecursiveUnivariateGcd( GenSolvablePolynomial> P, GenSolvablePolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException("no univariate polynomial"); } if (P.isConstant()) { return P.ring.getONE(); } if (S.isConstant()) { return P.ring.getONE(); } List>> A = new ArrayList>>( 2); A.add(P); A.add(S); SolvableGroebnerBaseAbstract> sbb = new SolvableGroebnerBaseSeq>(); logger.info("right syzGcd computing GB: {}", A); // will not work, not field List>> G = sbb.leftGB(A); //not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.info("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return P.ring.getONE(); } } java-algebra-system-2.7.200/src/edu/jas/fd/QuotSolvablePolynomial.java000066400000000000000000000537451445075545500256150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.TableRelation; import edu.jas.structure.GcdRingElem; /** * QuotSolvablePolynomial generic recursive solvable polynomials implementing * RingElem. n-variate ordered solvable polynomials over solvable polynomial * coefficients. Objects of this class are intended to be immutable. The * implementation is based on TreeMap respectively SortedMap from exponents to * coefficients by extension of GenPolynomial. Will be deprecated use * QLRSolvablePolynomial. * @param coefficient type * @author Heinz Kredel */ public class QuotSolvablePolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final QuotSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(QuotSolvablePolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero QuotSolvablePolynomial. * @param r solvable polynomial ring factory. */ public QuotSolvablePolynomial(QuotSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for QuotSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public QuotSolvablePolynomial(QuotSolvablePolynomialRing r, SolvableQuotient c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for QuotSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public QuotSolvablePolynomial(QuotSolvablePolynomialRing r, SolvableQuotient c) { this(r, c, r.evzero); } /** * Constructor for QuotSolvablePolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public QuotSolvablePolynomial(QuotSolvablePolynomialRing r, GenSolvablePolynomial> S) { this(r, S.getMap()); } /** * Constructor for QuotSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected QuotSolvablePolynomial(QuotSolvablePolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public QuotSolvablePolynomialRing factory() { return ring; } /** * Clone this QuotSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public QuotSolvablePolynomial copy() { return new QuotSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof QuotSolvablePolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * QuotSolvablePolynomial multiplication. * @param Bp QuotSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // not @Override public QuotSolvablePolynomial multiply(QuotSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (Bp.isONE()) { return this; } if (this.isONE()) { return Bp; } assert (ring.nvar == Bp.ring.nvar); logger.debug("ring = {}", ring); //System.out.println("this = " + this + ", Bp = " + Bp); ExpVector Z = ring.evzero; QuotSolvablePolynomial Dp = ring.getZERO().copy(); QuotSolvablePolynomial zero = ring.getZERO().copy(); SolvableQuotient one = ring.getONECoefficient(); //QuotSolvablePolynomial C1 = null; //QuotSolvablePolynomial C2 = null; Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); for (Map.Entry> y : A.entrySet()) { SolvableQuotient a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = {}", e, a); // int[] ep = e.dependencyOnVariables(); // int el1 = ring.nvar + 1; // if (ep.length > 0) { // el1 = ep[0]; // } // int el1s = ring.nvar + 1 - el1; for (Map.Entry> x : Bk) { SolvableQuotient b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial with coefficient multiplication QuotSolvablePolynomial Cps = ring.getZERO().copy(); //QuotSolvablePolynomial Cs; QuotSolvablePolynomial qp; if (ring.polCoeff.coeffTable.isEmpty() || b.isConstant() || e.isZERO()) { // symmetric Cps = new QuotSolvablePolynomial(ring, b, e); if (debug) logger.info("symmetric coeff: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff: b = {}, e = {}", b, e); // compute e * b as ( e * 1/b.den ) * b.num if (b.den.isONE()) { // recursion base // recursive polynomial coefficient multiplication : e * b.num RecSolvablePolynomial rsp1 = new RecSolvablePolynomial(ring.polCoeff, e); RecSolvablePolynomial rsp2 = new RecSolvablePolynomial(ring.polCoeff, b.num); RecSolvablePolynomial rsp3 = rsp1.multiply(rsp2); QuotSolvablePolynomial rsp = ring.fromPolyCoefficients(rsp3); Cps = rsp; } else { // b.den != 1 if (debug) logger.info("coeff-num: Cps = {}, num = {}, den = {}", Cps, b.num, b.den); Cps = new QuotSolvablePolynomial(ring, b.ring.getONE(), e); // coefficient multiplication with 1/den: QuotSolvablePolynomial qv = Cps; SolvableQuotient qden = new SolvableQuotient(b.ring, b.den); // den/1 //System.out.println("qv = " + qv + ", den = " + den); // recursion with den==1: QuotSolvablePolynomial v = qv.multiply(qden); QuotSolvablePolynomial vl = qv.multiplyLeft(qden); //System.out.println("v = " + v + ", vl = " + vl + ", qden = " + qden); QuotSolvablePolynomial vr = (QuotSolvablePolynomial) v.subtract(vl); SolvableQuotient qdeni = new SolvableQuotient(b.ring, b.ring.ring.getONE(), b.den); //System.out.println("vr = " + vr + ", qdeni = " + qdeni); // recursion with smaller head term: QuotSolvablePolynomial rq = vr.multiply(qdeni); qp = (QuotSolvablePolynomial) qv.subtract(rq); qp = qp.multiplyLeft(qdeni); //System.out.println("qp_i = " + qp); Cps = qp; if (!b.num.isONE()) { SolvableQuotient qnum = new SolvableQuotient(b.ring, b.num); // num/1 // recursion with den == 1: Cps = Cps.multiply(qnum); } } } // end coeff if (debug) logger.info("coeff-den: Cps = {}", Cps); // polynomial multiplication QuotSolvablePolynomial Dps = ring.getZERO().copy(); QuotSolvablePolynomial Ds = null; QuotSolvablePolynomial D1, D2; if (ring.table.isEmpty() || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly: b = {}, e = {}", b, e); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = new QuotSolvablePolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 SolvableQuotient c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (QuotSolvablePolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) { logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); logger.info("poly, g2 = {}, f2 = {}", g2, f2); } TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new QuotSolvablePolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = new QuotSolvablePolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = new QuotSolvablePolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = new QuotSolvablePolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = new QuotSolvablePolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // c * Ds Dps = (QuotSolvablePolynomial) Dps.sum(Ds); } // end Dps loop Ds = Dps; } Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric logger.debug("Ds = {}", Ds); Dp = (QuotSolvablePolynomial) Dp.sum(Ds); } // end B loop } // end A loop //System.out.println("this * Bp = " + Dp); return Dp; } /** * QuotSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S QuotSolvablePolynomial. * @param T QuotSolvablePolynomial. * @return S*this*T. */ // not @Override public QuotSolvablePolynomial multiply(QuotSolvablePolynomial S, QuotSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * QuotSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b solvable coefficient. * @return this*b, where * is coefficient multiplication. */ @Override public QuotSolvablePolynomial multiply(SolvableQuotient b) { QuotSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (b.isONE()) { return this; } Cp = new QuotSolvablePolynomial(ring, b, ring.evzero); return multiply(Cp); } /** * QuotSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public QuotSolvablePolynomial multiply(SolvableQuotient b, SolvableQuotient c) { QuotSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } if (b.isONE() && c.isONE()) { return this; } Cp = new QuotSolvablePolynomial(ring, b, ring.evzero); QuotSolvablePolynomial Dp = new QuotSolvablePolynomial(ring, c, ring.evzero); return multiply(Cp, Dp); } /** * QuotSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableQuotient b = ring.getONECoefficient(); return multiply(b, e); } /** * QuotSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public QuotSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } SolvableQuotient b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * QuotSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiply(SolvableQuotient b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO()) { return this; } QuotSolvablePolynomial Cp = new QuotSolvablePolynomial(ring, b, e); return multiply(Cp); } /** * QuotSolvablePolynomial left and right multiplication. Product with ring * element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public QuotSolvablePolynomial multiply(SolvableQuotient b, ExpVector e, SolvableQuotient c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO() && c.isONE() && f.isZERO()) { return this; } QuotSolvablePolynomial Cp = new QuotSolvablePolynomial(ring, b, e); QuotSolvablePolynomial Dp = new QuotSolvablePolynomial(ring, c, f); return multiply(Cp, Dp); } /** * QuotSolvablePolynomial multiplication. Left product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiplyLeft(SolvableQuotient b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } QuotSolvablePolynomial Cp = new QuotSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * QuotSolvablePolynomial multiplication. Left product with exponent vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } SolvableQuotient b = ring.getONECoefficient(); QuotSolvablePolynomial Cp = new QuotSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * QuotSolvablePolynomial multiplication. Left product with coefficient ring * element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public QuotSolvablePolynomial multiplyLeft(SolvableQuotient b) { QuotSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map> Cm = Cp.val; //getMap(); Map> Am = val; SolvableQuotient c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); SolvableQuotient a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * QuotSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * QuotSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public QuotSolvablePolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * QuotSolvablePolynomial multiplication. Left product with coefficient ring * element. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected QuotSolvablePolynomial shift(ExpVector f) { QuotSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); SolvableQuotient a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/fd/QuotSolvablePolynomialRing.java000066400000000000000000000645221445075545500264300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * QuotSolvablePolynomialRing generic recursive solvable polynomial factory * implementing RingFactory and extending GenSolvablePolynomialRing factory. * Factory for n-variate ordered solvable polynomials over solvable polynomial * coefficients. The non-commutative multiplication relations are maintained in * a relation table and the non-commutative multiplication relations between the * coefficients and the main variables are maintained in a coefficient relation * table. Almost immutable object, except variable names and relation table * contents. Will be deprecated use QLRSolvablePolynomialRing * @param coefficient type * @author Heinz Kredel */ public class QuotSolvablePolynomialRing> extends GenSolvablePolynomialRing> { /* * The solvable multiplication relations between variables and coefficients. */ //public final RelationTable> coeffTable; /** * Recursive solvable polynomial ring with polynomial coefficients. */ public final RecSolvablePolynomialRing polCoeff; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public final QuotSolvablePolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public final QuotSolvablePolynomial ONE; private static final Logger logger = LogManager.getLogger(QuotSolvablePolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public QuotSolvablePolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public QuotSolvablePolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public QuotSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } SolvableQuotientRing cfring = (SolvableQuotientRing) cf; // == coFac polCoeff = new RecSolvablePolynomialRing(cfring.ring, n, t, v); if (table.size() > 0) { List>> nt = new ArrayList>>(); for (GenSolvablePolynomial> q : table.relationList()) { nt.add(this.toPolyCoefficients(q)); // only with den == 1 } polCoeff.table.addSolvRelations(nt); } ZERO = new QuotSolvablePolynomial(this); SolvableQuotient coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new QuotSolvablePolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public QuotSolvablePolynomialRing(RingFactory> cf, GenSolvablePolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public QuotSolvablePolynomialRing(RingFactory> cf, QuotSolvablePolynomialRing o) { this(cf, (GenSolvablePolynomialRing) o); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + polCoeff.coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + polCoeff.coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } if (polCoeff.coeffTable.size() > 0) { String rel = polCoeff.coeffTable.toScript(); s.append(",coeffrel="); s.append(rel); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof QuotSolvablePolynomialRing)) { return false; } QuotSolvablePolynomialRing oring = (QuotSolvablePolynomialRing) other; // do a super.equals( ) if (!super.equals(other)) { return false; } // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!polCoeff.coeffTable.equals(oring.polCoeff.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + polCoeff.coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as QuotSolvablePolynomial. */ @Override public QuotSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 throw new RuntimeException("zero not 0: " + ZERO); } return ZERO; } /** * Get the one element. * @return 1 as QuotSolvablePolynomial. */ @Override public QuotSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { throw new RuntimeException("one not 1: " + ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (polCoeff.coeffTable.size() == 0) { return super.isCommutative(); } // check structure of relations? return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } QuotSolvablePolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (QuotSolvablePolynomial) gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = (QuotSolvablePolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (QuotSolvablePolynomial) gens.get(k); p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); logger.info("q-p = {}", p.subtract(q)); return false; } } } } return true; //coFac.isAssociative(); } /** * Get a (constant) QuotSolvablePolynomial<C> element from a long * value. * @param a long. * @return a QuotSolvablePolynomial<C>. */ @Override public QuotSolvablePolynomial fromInteger(long a) { return new QuotSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) QuotSolvablePolynomial<C> element from a * BigInteger value. * @param a BigInteger. * @return a QuotSolvablePolynomial<C>. */ @Override public QuotSolvablePolynomial fromInteger(BigInteger a) { return new QuotSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public QuotSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public QuotSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public QuotSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public QuotSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { QuotSolvablePolynomial r = getZERO(); // copy( ZERO ); ExpVector e; SolvableQuotient a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (QuotSolvablePolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public QuotSolvablePolynomial copy(QuotSolvablePolynomial c) { return new QuotSolvablePolynomial(this, c.getMap()); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return QuotSolvablePolynomial from s. */ @Override public QuotSolvablePolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next QuotSolvablePolynomial from r. */ @Override @SuppressWarnings("unchecked") public QuotSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); QuotSolvablePolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new QuotSolvablePolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public QuotSolvablePolynomial univariate(int i) { return (QuotSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public QuotSolvablePolynomial univariate(int i, long e) { return (QuotSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public QuotSolvablePolynomial univariate(int modv, int i, long e) { return (QuotSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { QuotSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public QuotSolvablePolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public QuotSolvablePolynomialRing extend(int i, boolean top) { GenPolynomialRing> pfac = super.extend(i, top); QuotSolvablePolynomialRing spfac = new QuotSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param vn names for extended variables. * @return extended solvable polynomial ring factory. */ @Override public QuotSolvablePolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public QuotSolvablePolynomialRing extend(String[] vn, boolean top) { GenPolynomialRing> pfac = super.extend(vn, top); QuotSolvablePolynomialRing spfac = new QuotSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public QuotSolvablePolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); QuotSolvablePolynomialRing spfac = new QuotSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.contract(this.table); spfac.polCoeff.coeffTable.contract(this.polCoeff.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public QuotSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public QuotSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); QuotSolvablePolynomialRing spfac = new QuotSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.partial = partial; spfac.table.reverse(this.table); spfac.polCoeff.coeffTable.reverse(this.polCoeff.coeffTable); return spfac; } /** * Rational function from integral polynomial coefficients. Represent as * polynomial with type SolvableQuotient coefficients. * @param A polynomial with integral polynomial coefficients to be * converted. * @return polynomial with type SolvableQuotient coefficients. */ public QuotSolvablePolynomial fromPolyCoefficients(GenSolvablePolynomial> A) { QuotSolvablePolynomial B = getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = coFac; SolvableQuotientRing qfac = (SolvableQuotientRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenSolvablePolynomial a = (GenSolvablePolynomial) y.getValue(); SolvableQuotient p = new SolvableQuotient(qfac, a); // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(QuotSolvablePolynomial A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableQuotient a = y.getValue(); if (!a.den.isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.num; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(GenPolynomial> A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); SolvableQuotient a = y.getValue(); if (!a.den.isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.num; // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } } java-algebra-system-2.7.200/src/edu/jas/fd/SGCDFactory.java000066400000000000000000000302101445075545500231570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Solvable greatest common divisor algorithms factory. Select appropriate SGCD * engine based on the coefficient types. *

* Usage: To create objects that implement the * GreatestCommonDivisor interface use the * SGCDFactory. It will select an appropriate implementation based * on the types of polynomial coefficients C. There are two methods to obtain an * implementation: getProxy() and getImplementation(). * getImplementation() returns an object of a class which * implements the GreatestCommonDivisor interface. * getProxy() returns a proxy object of a class which implements * the GreatestCommonDivisor interface. The proxy will run two * implementations in parallel, return the first computed result and cancel the * second running task. On systems with one CPU the computing time will be two * times the time of the fastest algorithm implementation. On systems with more * than two CPUs the computing time will be the time of the fastest algorithm * implementation. * *

 * GreatestCommonDivisor<CT> engine;
 * engine = SGCDFactory.<CT> getImplementation(cofac);
 * or engine = SGCDFactory.<CT> getProxy(cofac);
 * c = engine.leftGcd(a, b);
 * 
*

* For example, if the coefficient type is BigInteger, the usage * looks like * *

 * BigInteger cofac = new BigInteger();
 * GreatestCommonDivisor<BigInteger> engine;
 * engine = SGCDFactory.getImplementation(cofac);
 * or engine = SGCDFactory.getProxy(cofac);
 * c = engine.leftGcd(a, b);
 * 
* * @author Heinz Kredel * * @see edu.jas.fd.GreatestCommonDivisor#leftGcd(edu.jas.poly.GenSolvablePolynomial * P, edu.jas.poly.GenSolvablePolynomial S) */ public class SGCDFactory { private static final Logger logger = LogManager.getLogger(SGCDFactory.class); /** * Protected factory constructor. */ protected SGCDFactory() { } /** * Determine suitable implementation of gcd algorithms, case ModLong. * @param fac ModLongRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(ModLongRing fac) { logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd; if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(fac); return ufd; } ufd = new GreatestCommonDivisorPrimitive(fac); return ufd; } /** * Determine suitable proxy for gcd algorithms, case ModLong. * @param fac ModLongRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(ModLongRing fac) { logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorPrimitive(fac); if (fac.isField()) { ufd2 = new GreatestCommonDivisorSimple(fac); } else { ufd2 = new GreatestCommonDivisorSyzygy(fac); } return new SGCDParallelProxy(fac, ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case ModInteger. * @param fac ModIntegerRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(ModIntegerRing fac) { logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd; if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(fac); return ufd; } ufd = new GreatestCommonDivisorPrimitive(fac); return ufd; } /** * Determine suitable proxy for gcd algorithms, case ModInteger. * @param fac ModIntegerRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(ModIntegerRing fac) { logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorPrimitive(fac); if (fac.isField()) { ufd2 = new GreatestCommonDivisorSimple(fac); } else { ufd2 = new GreatestCommonDivisorSyzygy(fac); } return new SGCDParallelProxy(fac, ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case BigInteger. * @param fac BigInteger. * @return gcd algorithm implementation. */ @SuppressWarnings("unused") public static GreatestCommonDivisorAbstract getImplementation(BigInteger fac) { GreatestCommonDivisorAbstract ufd; logger.info("fac = {}", fac.getClass().getName()); if (!fac.isField()) { // = false ufd = new GreatestCommonDivisorPrimitive(fac); } else { ufd = new GreatestCommonDivisorSimple(fac); } return ufd; } /** * Determine suitable proxy for gcd algorithms, case BigInteger. * @param fac BigInteger. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(BigInteger fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorPrimitive(fac); ufd2 = new GreatestCommonDivisorSyzygy(fac); return new SGCDParallelProxy(fac, ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case BigRational. * @param fac BigRational. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(BigRational fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd; if (fac.isField()) { // = true ufd = new GreatestCommonDivisorSimple(fac); return ufd; } ufd = new GreatestCommonDivisorPrimitive(fac); return ufd; } /** * Determine suitable proxy for gcd algorithms, case BigRational. * @param fac BigRational. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(BigRational fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } logger.info("fac = {}", fac.getClass().getName()); GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorPrimitive(fac); ufd2 = new GreatestCommonDivisorSimple(fac); return new SGCDParallelProxy(fac, ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, other cases. * @param fac RingFactory<C>. * @return gcd algorithm implementation. */ @SuppressWarnings("unchecked") public static > GreatestCommonDivisorAbstract getImplementation( RingFactory fac) { //System.out.println("SGCDFactory: " + fac.getClass().getName()); GreatestCommonDivisorAbstract/*raw type*/ ufd; logger.info("fac = {}", fac.getClass().getName()); Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new GreatestCommonDivisorPrimitive(fac); } else if (ofac instanceof ModIntegerRing) { if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(fac); } else { ufd = new GreatestCommonDivisorPrimitive(fac); } } else if (ofac instanceof ModLongRing) { if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(fac); } else { ufd = new GreatestCommonDivisorPrimitive(fac); } } else if (ofac instanceof BigRational) { ufd = new GreatestCommonDivisorSimple(fac); } else { if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(fac); } else { ufd = new GreatestCommonDivisorPrimitive(fac); } } //System.out.println("SGCDFactory: " + ufd.getClass().getName()); logger.debug("implementation = {}", ufd); return ufd; } /** * Determine fake implementation of gcd algorithms, other cases. * @param fac RingFactory<C>. * @return fake gcd algorithm implementation. */ @SuppressWarnings("unchecked") public static > GreatestCommonDivisorAbstract getFakeImplementation( RingFactory fac) { GreatestCommonDivisorAbstract/*raw type*/ ufd; logger.info("fac = {}", fac.getClass().getName()); //Object ofac = fac; ufd = new GreatestCommonDivisorFake(fac); if (!(fac instanceof BigRational)) { //System.out.println("SGCDFactory: " + fac.getClass().getName()); //System.out.println("SGCDFactory: " + ufd.getClass().getName()); } logger.debug("implementation = {}", ufd); return ufd; } /** * Determine suitable proxy for gcd algorithms, other cases. * @param fac RingFactory<C>. * @return gcd algorithm implementation. Note: This method contains a * hack for Google app engine to not use threads. * @see edu.jas.kern.ComputerThreads#NO_THREADS */ @SuppressWarnings("unchecked") public static > GreatestCommonDivisorAbstract getProxy(RingFactory fac) { if (ComputerThreads.NO_THREADS) { // hack for Google app engine return SGCDFactory. getImplementation(fac); } GreatestCommonDivisorAbstract/*raw type*/ ufd; logger.info("fac = {}", fac.getClass().getName()); Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorSimple(fac), new GreatestCommonDivisorPrimitive(fac)); } else if (ofac instanceof ModIntegerRing) { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorSimple(fac), new GreatestCommonDivisorPrimitive(fac)); } else if (ofac instanceof ModLongRing) { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorSimple(fac), new GreatestCommonDivisorPrimitive(fac)); } else if (ofac instanceof BigRational) { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorPrimitive(fac), new GreatestCommonDivisorSimple(fac)); } else { if (fac.isField()) { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorSimple(fac), new GreatestCommonDivisorPrimitive(fac)); } else { ufd = new SGCDParallelProxy(fac, new GreatestCommonDivisorSyzygy(fac), new GreatestCommonDivisorPrimitive(fac)); } } logger.debug("ufd = {}", ufd); return ufd; } } java-algebra-system-2.7.200/src/edu/jas/fd/SGCDParallelProxy.java000066400000000000000000000630021445075545500243530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeoutException; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PreemptingException; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Solvable greatest common divisor parallel proxy. Executes methods from two * implementations in parallel and returns the result from the fastest run. Uses * timeout on invokeAny() and return fake common divisor 1 * in case of timeout. * @author Heinz Kredel */ public class SGCDParallelProxy> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(SGCDParallelProxy.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GCD engines. */ public final GreatestCommonDivisorAbstract e0; public final GreatestCommonDivisorAbstract e1; public final GreatestCommonDivisorAbstract e2; /** * Thread pool. */ protected transient ExecutorService pool; /** * ParallelProxy constructor. * @param cf coefficient ring. */ public SGCDParallelProxy(RingFactory cf, GreatestCommonDivisorAbstract e1, GreatestCommonDivisorAbstract e2) { super(cf); this.e0 = new GreatestCommonDivisorFake(cf); this.e1 = e1; this.e2 = e2; pool = ComputerThreads.getPool(); //System.out.println("pool 2 = "+pool); } /** * Get the String representation with gcd engines. * @see java.lang.Object#toString() */ @Override public String toString() { return "SGCDParallelProxy[ " + e1.getClass().getName() + ", " + e2.getClass().getName() + " ]"; } /** * Left univariate GenSolvablePolynomial greatest common divisor. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S). */ @Override public GenSolvablePolynomial leftBaseGcd(final GenSolvablePolynomial P, final GenSolvablePolynomial S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial g = P.ring.getONE(); //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenSolvablePolynomial g = e1.leftBaseGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenSolvablePolynomial g = e2.leftBaseGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.leftBaseGcd(P, S); // fake returns 1 } return g; } /** * left univariate GenSolvablePolynomial recursive greatest common divisor. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S). */ @Override public GenSolvablePolynomial> leftRecursiveUnivariateGcd( final GenSolvablePolynomial> P, final GenSolvablePolynomial> S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial> g = P.ring.getONE(); //Callable>> c0; //Callable>> c1; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public GenSolvablePolynomial> call() { try { GenSolvablePolynomial> g = e1.leftRecursiveUnivariateGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public GenSolvablePolynomial> call() { try { GenSolvablePolynomial> g = e2.leftRecursiveUnivariateGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.leftRecursiveUnivariateGcd(P, S); // fake returns 1 } return g; } /** * Left GenSolvablePolynomial greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return leftGcd(P,S). */ @Override public GenSolvablePolynomial leftGcd(final GenSolvablePolynomial P, final GenSolvablePolynomial S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial g = P.ring.getONE(); //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenSolvablePolynomial g = e1.leftGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenSolvablePolynomial g = e2.leftGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.leftGcd(P, S); // fake returns 1 } return g; } /** * Right univariate GenSolvablePolynomial greatest common divisor. * @param P univariate GenSolvablePolynomial. * @param S univariate GenSolvablePolynomial. * @return gcd(P,S). */ @Override public GenSolvablePolynomial rightBaseGcd(final GenSolvablePolynomial P, final GenSolvablePolynomial S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial g = P.ring.getONE(); //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenSolvablePolynomial g = e1.rightBaseGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenSolvablePolynomial g = e2.rightBaseGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.rightBaseGcd(P, S); // fake returns 1 } return g; } /** * right univariate GenSolvablePolynomial recursive greatest common divisor. * @param P univariate recursive GenSolvablePolynomial. * @param S univariate recursive GenSolvablePolynomial. * @return gcd(P,S). */ @Override public GenSolvablePolynomial> rightRecursiveUnivariateGcd( final GenSolvablePolynomial> P, final GenSolvablePolynomial> S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial> g = P.ring.getONE(); //Callable>> c0; //Callable>> c1; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public GenSolvablePolynomial> call() { try { GenSolvablePolynomial> g = e1.rightRecursiveUnivariateGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public GenSolvablePolynomial> call() { try { GenSolvablePolynomial> g = e2.rightRecursiveUnivariateGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.rightRecursiveUnivariateGcd(P, S); // fake returns 1 } return g; } /** * Right GenSolvablePolynomial greatest common divisor. * @param P GenSolvablePolynomial. * @param S GenSolvablePolynomial. * @return rightGcd(P,S). */ @Override public GenSolvablePolynomial rightGcd(final GenSolvablePolynomial P, final GenSolvablePolynomial S) { if (debug) { if (ComputerThreads.NO_THREADS) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenSolvablePolynomial g = P.ring.getONE(); //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenSolvablePolynomial g = e1.rightGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e1 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenSolvablePolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenSolvablePolynomial g = e2.rightGcd(P, S); if (debug) { logger.info("SGCDParallelProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("SGCDParallelProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGCDParallelProxy e2 {}", e); logger.info("SGCDParallelProxy P = {}", P); logger.info("SGCDParallelProxy S = {}", S); throw new RuntimeException("SGCDParallelProxy e2 " + e); //return P.ring.getONE(); } } }); try { if (ComputerThreads.getTimeout() < 0) { g = pool.invokeAny(cs); } else { g = pool.invokeAny(cs, ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); } } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } catch (TimeoutException e) { logger.info("TimeoutException after {} {}", ComputerThreads.getTimeout(), ComputerThreads.getTimeUnit()); g = e0.rightGcd(P, S); // fake returns 1 } return g; } } java-algebra-system-2.7.200/src/edu/jas/fd/SolvableQuotient.java000066400000000000000000000504261445075545500244220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.Arrays; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.gbufd.PolyModUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; /** * SolvableQuotient, that is a (left) rational function, based on * GenSolvablePolynomial with RingElem interface. Objects of this class are * immutable. * @author Heinz Kredel */ public class SolvableQuotient> implements GcdRingElem>, QuotPair> { // should be QuotPair private static final Logger logger = LogManager.getLogger(SolvableQuotient.class); private static final boolean debug = logger.isDebugEnabled(); /** * SolvableQuotient class factory data structure. */ public final SolvableQuotientRing ring; /** * Numerator part of the element data structure. */ public final GenSolvablePolynomial num; /** * Denominator part of the element data structure. */ public final GenSolvablePolynomial den; /** * The constructor creates a SolvableQuotient object from a ring factory. * @param r ring factory. */ public SolvableQuotient(SolvableQuotientRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a SolvableQuotient object from a ring factory and * a numerator polynomial. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator solvable polynomial. */ public SolvableQuotient(SolvableQuotientRing r, GenSolvablePolynomial n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a SolvableQuotient object from a ring factory and * a numerator and denominator solvable polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. */ public SolvableQuotient(SolvableQuotientRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { this(r, n, d, false); } /** * The constructor creates a SolvableQuotient object from a ring factory and * a numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. * @param isred unused at the moment. */ protected SolvableQuotient(SolvableQuotientRing r, GenSolvablePolynomial n, GenSolvablePolynomial d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = (GenSolvablePolynomial) n.negate(); d = (GenSolvablePolynomial) d.negate(); } if (isred) { num = n; den = d; return; } C lc = d.leadingBaseCoefficient(); if (!lc.isONE() && lc.isUnit()) { lc = lc.inverse(); n = n.multiply(lc); d = d.multiply(lc); } if (n.compareTo(d) == 0) { num = ring.ring.getONE(); den = ring.ring.getONE(); return; } if (n.negate().compareTo(d) == 0) { num = (GenSolvablePolynomial) ring.ring.getONE().negate(); den = ring.ring.getONE(); return; } if (n.isZERO()) { num = n; den = ring.ring.getONE(); return; } //if (n.isONE() || d.isONE()) { if (n.isConstant() || d.isConstant()) { num = n; den = d; return; } // must reduce to lowest terms // not perfect, TODO //GenSolvablePolynomial[] gcd = PolyModUtil. syzGcdCofactors(r.ring, n, d); //GenSolvablePolynomial[] gcd = FDUtil. leftGcdCofactors(r.ring, n, d); GenSolvablePolynomial[] gcd = ring.fdengine.leftGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } //gcd = PolyModUtil. syzGcdCofactors(r.ring, n, d); //gcd = FDUtil. rightGcdCofactors(r.ring, n, d); gcd = ring.fdengine.rightGcdCofactors(r.ring, n, d); if (!gcd[0].isONE()) { logger.info("constructor: gcd = {}", Arrays.toString(gcd)); // + ", {}", n + ", " +d); n = gcd[1]; d = gcd[2]; } // not perfect, TODO GenSolvablePolynomial[] simp = ring.engine.leftSimplifier(n, d); logger.info("simp: {}, {}, {}", Arrays.toString(simp), n, d); num = simp[0]; den = simp[1]; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public SolvableQuotientRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public GenSolvablePolynomial numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public GenSolvablePolynomial denominator() { return den; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public SolvableQuotient copy() { return new SolvableQuotient(ring, num, den, true); } /** * Is SolvableQuotient zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is SolvableQuotient one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.compareTo(den) == 0; } /** * Is SolvableQuotient a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (num.isZERO()) { return false; } return true; } /** * Is Qoutient a constant. * @return true, if this has constant numerator and denominator, else false. */ public boolean isConstant() { return num.isConstant() && den.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(ring.ring.getVars()); if (!den.isONE()) { s += " | " + den.toString(ring.ring.getVars()); } return s + " }"; } return "SolvableQuotient[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // any scripting case if (den.isONE()) { return num.toScript(); } return num.toScript() + " / " + den.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { return factory().toScript(); } /** * SolvableQuotient comparison. * @param b SolvableQuotient. * @return sign(this-b). */ @Override public int compareTo(SolvableQuotient b) { if (b == null || b.isZERO()) { return this.signum(); } if (this.isZERO()) { return -b.signum(); } // assume sign(den,b.den) > 0 int s1 = num.signum(); int s2 = b.num.signum(); int t = (s1 - s2) / 2; if (t != 0) { return t; } if (den.compareTo(b.den) == 0) { return num.compareTo(b.num); } GenSolvablePolynomial r, s; // if (den.isONE()) { // r = b.den.multiply(num); // s = b.num; // return r.compareTo(s); // } // if (b.den.isONE()) { // r = num; // s = den.multiply(b.num); // return r.compareTo(s); // } GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den, b.den); if (debug) { System.out.println("oc[0] den =<>= oc[1] b.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" + b.den + ")"); } r = oc[0].multiply(num); s = oc[1].multiply(b.num); //System.out.println("r = " + r); //System.out.println("s = " + s); return r.compareTo(s); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof SolvableQuotient)) { return false; } SolvableQuotient a = (SolvableQuotient) b; if (num.equals(a.num) && den.equals(a.den)) { // short cut return true; } return compareTo(a) == 0; } /** * Hash code for this element. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * SolvableQuotient right fraction. Note: It is not possible to * distinguish right from left fractions in the current implementation. So * it is not possible to compute with right fractions. * @return SolvableQuotient(a,b), where den-1 num = a b * -1 */ public SolvableQuotient rightFraction() { if (isZERO() || isONE()) { return this; } GenSolvablePolynomial[] oc = ring.engine.rightOreCond(num, den); return new SolvableQuotient(ring, oc[1], oc[0], true); // reversed, true is wrong but okay } /** * Test if SolvableQuotient right fraction. Note: It is not possible * to distinguish right from left fractions in the current implementation. * So it is not possible to compute with right fractions. * @param s = SolvableQuotient(a,b) * @return true if s is a right fraction of this, i.e. den-1 num * = a b-1 */ public boolean isRightFraction(SolvableQuotient s) { if (isZERO()) { return s.isZERO(); } if (isONE()) { return s.isONE(); } GenSolvablePolynomial x = den.multiply(s.num); GenSolvablePolynomial y = num.multiply(s.den); return x.compareTo(y) == 0; } /** * SolvableQuotient absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public SolvableQuotient abs() { return new SolvableQuotient(ring, (GenSolvablePolynomial) num.abs(), den, true); } /** * SolvableQuotient summation. * @param S SolvableQuotient. * @return this+S. */ public SolvableQuotient sum(SolvableQuotient S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } GenSolvablePolynomial n, d, n1, n2; if (den.isONE() && S.den.isONE()) { n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableQuotient(ring, n, den, true); } /* wrong: if (den.isONE()) { n = S.den.multiply(num); n = (GenSolvablePolynomial) n.sum(S.num); return new SolvableQuotient(ring, n, S.den, false); } if (S.den.isONE()) { n = den.multiply(S.num); n = (GenSolvablePolynomial) n.sum(num); return new SolvableQuotient(ring, n, den, false); } */ if (den.compareTo(S.den) == 0) { // correct ? //d = den.multiply(den); //n1 = den.multiply(S.num); //n2 = S.den.multiply(num); n = (GenSolvablePolynomial) num.sum(S.num); return new SolvableQuotient(ring, n, den, false); } // general case GenSolvablePolynomial[] oc = ring.engine.leftOreCond(den, S.den); if (debug) { System.out.println("oc[0] den =sum= oc[1] S.den: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" + S.den + ")"); } d = oc[0].multiply(den); n1 = oc[0].multiply(num); n2 = oc[1].multiply(S.num); n = (GenSolvablePolynomial) n1.sum(n2); //System.out.println("n = " + n); //System.out.println("d = " + d); return new SolvableQuotient(ring, n, d, false); } /** * SolvableQuotient negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public SolvableQuotient negate() { return new SolvableQuotient(ring, (GenSolvablePolynomial) num.negate(), den, true); } /** * SolvableQuotient signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { // assume sign(den) > 0 return num.signum(); } /** * SolvableQuotient subtraction. * @param S SolvableQuotient. * @return this-S. */ public SolvableQuotient subtract(SolvableQuotient S) { return sum(S.negate()); } /** * SolvableQuotient division. * @param S SolvableQuotient. * @return this/S. */ public SolvableQuotient divide(SolvableQuotient S) { return multiply(S.inverse()); } /** * SolvableQuotient inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this. */ public SolvableQuotient inverse() { if (num.isZERO()) { throw new ArithmeticException("element not invertible " + this); } return new SolvableQuotient(ring, den, num, true); } /** * SolvableQuotient remainder. * @param S SolvableQuotient. * @return this - (this/S)*S. */ public SolvableQuotient remainder(SolvableQuotient S) { if (S.isZERO()) { throw new ArithmeticException("element not invertible " + S); } return ring.getZERO(); } /** * Quotient and remainder by division of this by S. * @param S a SolvableQuotient * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public SolvableQuotient[] quotientRemainder(SolvableQuotient S) { return new SolvableQuotient[] { divide(S), remainder(S) }; } /** * SolvableQuotient multiplication. * @param S SolvableQuotient. * @return this*S. */ public SolvableQuotient multiply(SolvableQuotient S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } GenSolvablePolynomial n, d; if (den.isONE() && S.den.isONE()) { n = num.multiply(S.num); return new SolvableQuotient(ring, n, den, true); } /* wrong: if (den.isONE()) { d = S.den; n = num.multiply(S.num); return new SolvableQuotient(ring, n, d, false); } if (S.den.isONE()) { d = den; n = num.multiply(S.num); return new SolvableQuotient(ring, n, d, false); } */ // if ( den.compareTo(S.den) == 0 ) { // not correct ? // d = den.multiply(den); // n = num.multiply(S.num); // return new SolvableQuotient(ring, n, d, false); // } GenSolvablePolynomial[] oc = ring.engine.leftOreCond(num, S.den); n = oc[1].multiply(S.num); d = oc[0].multiply(den); if (debug) { System.out.println("oc[0] num =mult= oc[1] S.den: (" + oc[0] + ") (" + num + ") = (" + oc[1] + ") (" + S.den + ")"); } return new SolvableQuotient(ring, n, d, false); } /** * SolvableQuotient multiplication by GenSolvablePolynomial. * @param b GenSolvablePolynomial. * @return this*b. */ public SolvableQuotient multiply(GenSolvablePolynomial b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenSolvablePolynomial n = num.multiply(b); return new SolvableQuotient(ring, n, den, false); } /** * SolvableQuotient multiplication by coefficient. * @param b coefficient. * @return this*b. */ public SolvableQuotient multiply(C b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenSolvablePolynomial n = num.multiply(b); return new SolvableQuotient(ring, n, den, true); } /** * SolvableQuotient multiplication by exponent. * @param e exponent vector. * @return this*b. */ public SolvableQuotient multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } if (num.isZERO()) { return this; } GenSolvablePolynomial n = num.multiply(e); return new SolvableQuotient(ring, n, den, false); } /** * SolvableQuotient monic. * @return this with monic value part. */ public SolvableQuotient monic() { if (num.isZERO()) { return this; } C lbc = num.leadingBaseCoefficient(); if (!lbc.isUnit()) { return this; } lbc = lbc.inverse(); //lbc = lbc.abs(); GenSolvablePolynomial n = num.multiply(lbc); //GenSolvablePolynomial d = (GenSolvablePolynomial) den.multiply(lbc); return new SolvableQuotient(ring, n, den, true); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public SolvableQuotient gcd(SolvableQuotient b) { if (b == null || b.isZERO()) { return this; } if (this.isZERO()) { return b; } if (this.equals(b)) { return this; } return ring.getONE(); } /** * Extended greatest common divisor. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ @SuppressWarnings("unchecked") public SolvableQuotient[] egcd(SolvableQuotient b) { @SuppressWarnings("cast") SolvableQuotient[] ret = (SolvableQuotient[]) new SolvableQuotient[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (b == null || b.isZERO()) { ret[0] = this; ret[1] = ring.getONE(); ret[2] = ring.getZERO(); return ret; } if (this.isZERO()) { ret[0] = b; ret[1] = ring.getZERO(); ret[2] = ring.getONE(); return ret; } GenSolvablePolynomial two = ring.ring.fromInteger(2); ret[0] = ring.getONE(); ret[1] = (this.multiply(two)).inverse(); ret[2] = (b.multiply(two)).inverse(); return ret; } } java-algebra-system-2.7.200/src/edu/jas/fd/SolvableQuotientRing.java000066400000000000000000000250261445075545500252400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.kern.StringUtil; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; /** * SolvableQuotient ring factory based on GenPolynomial with RingElem interface. * Objects of this class are immutable. * @author Heinz Kredel */ public class SolvableQuotientRing> implements RingFactory>, QuotPairFactory, SolvableQuotient> { // should be QuotPairFactory private static final Logger logger = LogManager.getLogger(SolvableQuotientRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Solvable polynomial ring of the factory. */ public final GenSolvablePolynomialRing ring; /** * Syzygy engine of the factory. */ public final SolvableSyzygyAbstract engine; /** * FD engine of the factory. */ public final GreatestCommonDivisorAbstract fdengine; /** * The constructor creates a SolvableQuotientRing object from a * GenSolvablePolynomialRing. * @param r solvable polynomial ring. */ public SolvableQuotientRing(GenSolvablePolynomialRing r) { ring = r; engine = new SolvableSyzygySeq(ring.coFac); //fdengine = SGCDFactory. getImplementation(ring.coFac); fdengine = SGCDFactory. getFakeImplementation(ring.coFac); logger.debug("quotient ring constructed"); //System.out.println(" engine = " + engine); //System.out.println("fdengine = " + fdengine); } /** * Factory for base elements. */ public GenSolvablePolynomialRing pairFactory() { return ring; } /** * Create from numerator. */ @SuppressWarnings("unchecked") public SolvableQuotient create(GenPolynomial n) { return new SolvableQuotient(this, (GenSolvablePolynomial) n); } /** * Create from numerator, denominator pair. */ @SuppressWarnings("unchecked") public SolvableQuotient create(GenPolynomial n, GenPolynomial d) { return new SolvableQuotient(this, (GenSolvablePolynomial) n, (GenSolvablePolynomial) d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. */ public boolean isFinite() { return ring.isFinite(); } /** * Copy SolvableQuotient element c. * @param c * @return a copy of c. */ public SolvableQuotient copy(SolvableQuotient c) { return new SolvableQuotient(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as SolvableQuotient. */ public SolvableQuotient getZERO() { return new SolvableQuotient(this, ring.getZERO()); } /** * Get the one element. * @return 1 as SolvableQuotient. */ public SolvableQuotient getONE() { return new SolvableQuotient(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. */ public List> generators() { List> pgens = PolynomialList. castToSolvableList(ring.generators()); List> gens = new ArrayList>(pgens.size() * 2 - 1); GenSolvablePolynomial one = ring.getONE(); for (GenSolvablePolynomial p : pgens) { SolvableQuotient q = new SolvableQuotient(this, p); gens.add(q); if (!p.isONE()) { q = new SolvableQuotient(this, one, p); gens.add(q); } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { if (!ring.isAssociative()) { return false; } SolvableQuotient Xi, Xj, Xk, p, q; List> gens = generators(); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = gens.get(k); p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { logger.info("Xk = {}, Xj = {}, Xi = {}", Xk, Xj, Xi); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); return false; } } } } return true; } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a SolvableQuotient element from a BigInteger value. * @param a BigInteger. * @return a SolvableQuotient. */ public SolvableQuotient fromInteger(java.math.BigInteger a) { return new SolvableQuotient(this, ring.fromInteger(a)); } /** * Get a SolvableQuotient element from a long value. * @param a long. * @return a SolvableQuotient. */ public SolvableQuotient fromInteger(long a) { return new SolvableQuotient(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. */ @Override public String toString() { String s = null; if (ring.coFac.characteristic().signum() == 0) { s = "RatFunc"; } else { s = "ModFunc"; } return s + "( " + ring.toString() + " )"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. */ @Override public String toScript() { // Python case return "SRF(" + ring.toScript() + ")"; } /** * Comparison with any other object. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof SolvableQuotientRing)) { return false; } SolvableQuotientRing a = (SolvableQuotientRing) b; return ring.equals(a.ring); } /** * Hash code for this quotient ring. */ @Override public int hashCode() { int h; h = ring.hashCode(); return h; } /** * SolvableQuotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random quotient element. */ public SolvableQuotient random(int n) { GenSolvablePolynomial r = ring.random(n).monic(); GenSolvablePolynomial s; int z = 0; do { s = ring.random(n).monic(); } while (s.isZERO() && z++ < 10); if (s.isZERO()) { s = ring.getONE(); } return new SolvableQuotient(this, r, s, false); } /** * Generate a random quotient. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random quotient. */ public SolvableQuotient random(int k, int l, int d, float q) { GenSolvablePolynomial r = ring.random(k, l, d, q).monic(); GenSolvablePolynomial s; int z = 0; do { s = ring.random(k, l, d, q).monic(); } while (s.isZERO() && z++ < 10); if (s.isZERO()) { s = ring.getONE(); } return new SolvableQuotient(this, r, s, false); } /** * SolvableQuotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random quotient element. */ public SolvableQuotient random(int n, Random rnd) { GenSolvablePolynomial r = ring.random(n, rnd).monic(); GenSolvablePolynomial s; int z = 0; do { s = ring.random(n, rnd).monic(); } while (s.isZERO() && z++ < 10); if (s.isZERO()) { s = ring.getONE(); } //System.out.println("r = " + r + ", s = " + s + ", z = " + z); return new SolvableQuotient(this, r, s, false); } /** * Parse SolvableQuotient from String. Syntax: "{ polynomial | polynomial }" * or "{ polynomial }" or " polynomial | polynomial " or " polynomial " * @param s String. * @return SolvableQuotient from s. */ public SolvableQuotient parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { GenSolvablePolynomial n = ring.parse(s); return new SolvableQuotient(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); GenSolvablePolynomial n = ring.parse(s1); GenSolvablePolynomial d = ring.parse(s2); return new SolvableQuotient(this, n, d); } /** * Parse SolvableQuotient from Reader. * @param r Reader. * @return next SolvableQuotient from r. */ public SolvableQuotient parse(Reader r) { String s = StringUtil.nextPairedString(r, '{', '}'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/fd/package.html000066400000000000000000000032071445075545500225330ustar00rootroot00000000000000 Factorization Domain package for solvable polynomial rings

Factorization domain package for solvable polynomial rings.

This package contains classes for solvable polynomials rings as (non-unique) factorization domains. Methods provided with interface GreatestCommonDivisor are e.g. left / right greatest common divisors leftGcd(), rightGcd(), left / right primitive part leftPrimitivePart() or leftCoPrime().

To choose the correct implementation it is best use the factory classes SGCDFactory with methods getImplementation() or getProxy(). These methods will take care of all possible (implemented) coefficient rings properties. The polynomial coefficients must implement the GcdRingElem interface and so must allow greatest common divisor computations. Greatest common divisor computation is completely generic and works for any implemented integral domain. If special, optimized implementations exist they will be used.


Heinz Kredel

Last modified: Fri May 13 19:57:34 CEST 2016

$Id$

java-algebra-system-2.7.200/src/edu/jas/gb/000077500000000000000000000000001445075545500202475ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/gb/AbstractPair.java000066400000000000000000000052261445075545500234760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; /** * Serializable abstract subclass to hold pairs of polynomials. * @param coefficient type * @author Heinz Kredel */ public abstract class AbstractPair > implements Serializable { public final ExpVector e; public final GenPolynomial pi; public final GenPolynomial pj; public final int i; public final int j; protected int s; /** * AbstractPair constructor. * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. */ public AbstractPair(GenPolynomial a, GenPolynomial b, int i, int j) { this(a.leadingExpVector().lcm(b.leadingExpVector()),a,b,i,j); } /** * AbstractPair constructor. * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. * @param s maximal index. */ public AbstractPair(GenPolynomial a, GenPolynomial b, int i, int j, int s) { this(a.leadingExpVector().lcm(b.leadingExpVector()),a,b,i,j,s); } /** * AbstractPair constructor. * @param lcm least common multiple of lt(a) and lt(b). * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. */ public AbstractPair(ExpVector lcm, GenPolynomial a, GenPolynomial b, int i, int j) { this(lcm,a,b,i,j,0); } /** * AbstractPair constructor. * @param lcm least common multiple of lt(a) and lt(b). * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. * @param s maximal index. */ public AbstractPair(ExpVector lcm, GenPolynomial a, GenPolynomial b, int i, int j, int s) { e = lcm; pi = a; pj = b; this.i = i; this.j = j; s = Math.max(i,s); s = Math.max(j,s); this.s = s; } /** * Set maximal index. * @param s maximal index for pair polynomials. */ public void maxIndex(int s) { s = Math.max(this.i,s); s = Math.max(this.j,s); this.s = s; } /** * toString. */ @Override public String toString() { return "pair(" + i + "," + j + "," + s + ",{" + pi.length() + "," + pj.length() + "}," + e + ")"; } } java-algebra-system-2.7.200/src/edu/jas/gb/CriticalPair.java000066400000000000000000000056401445075545500234650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; /** * Serializable subclass to hold critical pairs of polynomials. * Used also to manage reduction status of the pair. * @param coefficient type * @author Heinz Kredel */ public class CriticalPair > extends AbstractPair { protected volatile boolean inReduction; protected volatile GenPolynomial reductum; //public final ExpVector sugar; /** * CriticalPair constructor. * @param e lcm(lt(pi),lt(pj). * @param pi polynomial i. * @param pj polynomial j. * @param i index of pi. * @param j index pf pj. */ public CriticalPair(ExpVector e, GenPolynomial pi, GenPolynomial pj, int i, int j) { super(e,pi,pj,i,j); inReduction = false; reductum = null; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer(super.toString() + "[ "); if ( inReduction ) { s.append("," + inReduction); } if ( reductum != null ) { s.append("," + reductum.leadingExpVector()); } s.append(" ]"); return s.toString(); } /** * Set in reduction status. * inReduction is set to true. */ public void setInReduction() { if ( inReduction ) { throw new IllegalStateException("already in reduction " + this); } inReduction = true; } /** * Get in reduction status. * @return true if the polynomial is currently in reduction, else false. */ public boolean getInReduction() { return inReduction; } /** * Get reduced polynomial. * @return the reduced polynomial or null if not done. */ public GenPolynomial getReductum() { return reductum; } /** * Set reduced polynomial. * @param r the reduced polynomial. */ public void setReductum(GenPolynomial r) { if ( r == null ) { throw new IllegalArgumentException("reduction null not allowed " + this); } inReduction = false; reductum = r; } /** * Is reduced to zero. * @return true if the S-polynomial of this CriticalPair * was reduced to ZERO, else false. */ public boolean isZERO() { if ( reductum == null ) { // not jet done return false; } return reductum.isZERO(); } /** * Is reduced to one. * @return true if the S-polynomial of this CriticalPair was * reduced to ONE, else false. */ public boolean isONE() { if ( reductum == null ) { // not jet done return false; } return reductum.isONE(); } } java-algebra-system-2.7.200/src/edu/jas/gb/CriticalPairComparator.java000066400000000000000000000036021445075545500255110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.Comparator; import edu.jas.poly.TermOrder; import edu.jas.structure.RingElem; /** * Comparator for critical pairs of polynomials. Immutable objects. * @param coefficient type * @author Heinz Kredel */ public class CriticalPairComparator> implements Serializable, Comparator> { public final TermOrder tord; protected final TermOrder.EVComparator ec; /** * Constructor. * @param t TermOrder. */ public CriticalPairComparator(TermOrder t) { tord = t; ec = tord.getAscendComparator(); } /** * Compare. Compares exponents and if equal, compares polynomial indices. * @param p1 first critical pair. * @param p2 second critical pair. * @return 0 if ( p1 == p2 ), -1 if ( p1 < p2 ) and +1 if ( p1 > p2 ). */ public int compare(AbstractPair p1, AbstractPair p2) { int s = ec.compare(p1.e, p2.e); if (s == 0) { /* not ok if ( p1.j < p2.j ) { s = -1; } else if ( p1.j > p2.j ) { s = 1; } else if ( p1.i < p2.i ) { s = -1; } else if ( p1.i > p2.i ) { s = 1; } else { s = 0; } */ /* ok */ if (p1.j > p2.j) { s = -1; } else if (p1.j < p2.j) { s = 1; } else if (p1.i > p2.i) { s = -1; } else if (p1.i < p2.i) { s = 1; } else { s = 0; } /* */ } return s; } /** * toString. */ @Override public String toString() { return "CriticalPairComparator(" + tord + ")"; } } java-algebra-system-2.7.200/src/edu/jas/gb/CriticalPairList.java000066400000000000000000000227221445075545500243210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.BitSet; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.structure.RingElem; /** * Critical pair list management. * Makes some effort to produce the same sequence of critical pairs * as in the sequential case, when used in parallel. * However already reduced pairs are not re-reduced if new * polynomials appear. * Implemented using GenPolynomial, SortedSet / TreeSet and BitSet. * @author Heinz Kredel */ public class CriticalPairList> extends OrderedPairlist { protected final SortedSet< CriticalPair > pairlist; // hide super protected int recordCount; private static final Logger logger = LogManager.getLogger(CriticalPairList.class); /** * Constructor for CriticalPairList. */ public CriticalPairList() { super(); pairlist = null; } /** * Constructor for CriticalPairList. * @param r polynomial factory. */ public CriticalPairList(GenPolynomialRing r) { this(0,r); } /** * Constructor for CriticalPairList. * @param m number of module variables. * @param r polynomial factory. */ public CriticalPairList(int m, GenPolynomialRing r) { super(m,r); Comparator< AbstractPair > cpc; cpc = new CriticalPairComparator( ring.tord ); pairlist = new TreeSet< CriticalPair >( cpc ); recordCount = 0; } /** * Create a new PairList. * @param r polynomial ring. */ public PairList create(GenPolynomialRing r) { return new CriticalPairList(r); } /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ public PairList create(int m, GenPolynomialRing r) { return new CriticalPairList(m,r); } /** * Put a polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ public synchronized int put(GenPolynomial p) { putCount++; if ( oneInGB ) { return P.size()-1; } ExpVector e = p.leadingExpVector(); int len = P.size(); for ( int j = 0; j < len; j++ ) { GenPolynomial pj = P.get(j); ExpVector f = pj.leadingExpVector(); if ( moduleVars > 0 ) { // test moduleCriterion if ( !reduction.moduleCriterion( moduleVars, e, f) ) { continue; // skip pair } } ExpVector g = e.lcm( f ); CriticalPair pair = new CriticalPair( g, pj, p, j, len ); //System.out.println("put pair = " + pair ); pairlist.add( pair ); } P.add( p ); BitSet redi = new BitSet(); redi.set( 0, len ); // >= jdk 1.4 red.add( redi ); if ( recordCount < len ) { recordCount = len; } return len; } /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public synchronized boolean hasNext() { return pairlist.size() > 0; } /** * Get and remove the next required pair from the pairlist. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * The pair is not removed from the pair list. * @return the next pair if one exists, otherwise null. */ public synchronized Pair removeNext() { CriticalPair cp = getNext(); if ( cp == null ) { return null; } return new Pair(cp.pi,cp.pj,cp.i,cp.j); } /** * Get the next required pair from the pairlist. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * The pair is not removed from the pair list. * @return the next pair if one exists, otherwise null. */ public synchronized CriticalPair getNext() { if ( oneInGB ) { return null; } CriticalPair pair = null; Iterator< CriticalPair > ip = pairlist.iterator(); boolean c = false; while ( !c && ip.hasNext() ) { // findbugs pair = ip.next(); if ( pair.getInReduction() ) { continue; } if ( pair.getReductum() != null ) { continue; } if ( logger.isInfoEnabled() ) { logger.info("{}", pair); } if ( useCriterion4 ) { c = reduction.criterion4( pair.pi, pair.pj, pair.e ); // System.out.println("c4 = " + c); } else { c = true; } if ( c ) { c = criterion3( pair.i, pair.j, pair.e ); // System.out.println("c3 = " + c); } red.get( pair.j ).clear( pair.i ); // set(i,false) jdk1.4 if ( ! c ) { // set done pair.setReductum( ring.getZERO() ); } } if ( ! c ) { pair = null; } else { remCount++; // count only real pairs pair.setInReduction(); // set to work } return pair; } /** * Record reduced polynomial. * @param pair the corresponding critical pair. * @param p polynomial. * @return index of recorded polynomial, or -1 if not added. */ public int record(CriticalPair pair, GenPolynomial p) { if ( p == null ) { p = ring.getZERO(); } pair.setReductum(p); // trigger thread if ( ! p.isZERO() && ! p.isONE() ) { recordCount++; return recordCount; } return -1; } /** * Record reduced polynomial and update critical pair list. * Note: it is better to use record and uptate separately. * @param pair the corresponding critical pair. * @param p polynomial. * @return index of recorded polynomial */ public int update(CriticalPair pair, GenPolynomial p) { if ( p == null ) { p = ring.getZERO(); } pair.setReductum(p); if ( ! p.isZERO() && ! p.isONE() ) { recordCount++; } int c = update(); if (c < 0) { // use for findbugs System.out.println("c < 0"); } if ( ! p.isZERO() && ! p.isONE() ) { return recordCount; } return -1; } /** * Update pairlist. * Preserve the sequential pair sequence. * Remove pairs with completed reductions. * @return the number of added polynomials. */ public synchronized int update() { int num = 0; if ( oneInGB ) { return num; } while ( pairlist.size() > 0 ) { CriticalPair pair = pairlist.first(); GenPolynomial p = pair.getReductum(); if ( p != null ) { pairlist.remove( pair ); num++; if ( ! p.isZERO() ) { if ( p.isONE() ) { putOne(); // sets size = 1 } else { put( p ); // changes pair list } } } else { break; } } return num; } /** * In work pairs. List pairs which are currently reduced. * @return list of critical pairs which are in reduction. */ public synchronized List> inWork() { List> iw; iw = new ArrayList>(); if ( oneInGB ) { return iw; } for ( CriticalPair pair : pairlist ) { if ( pair.getInReduction() ) { iw.add( pair ); } } return iw; } /** * Update pairlist, several pairs at once. * This version does not preserve the sequential pair sequence. * Remove pairs with completed reductions. * @return the number of added polynomials. */ public synchronized int updateMany() { int num = 0; if ( oneInGB ) { return num; } List> rem = new ArrayList>(); for ( CriticalPair pair : pairlist ) { if ( pair.getReductum() != null ) { rem.add( pair ); num++; } else { break; } } // must work on a copy to avoid concurrent modification for ( CriticalPair pair : rem ) { // System.out.println("update = " + pair); pairlist.remove( pair ); GenPolynomial p = pair.getReductum(); if ( ! p.isZERO() ) { if ( p.isONE() ) { putOne(); } else { put( p ); } } } return num; } /** * Put the ONE-Polynomial to the pairlist. * @return the index of the last polynomial. */ public synchronized int putOne() { super.putOne(); pairlist.clear(); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gb/Cyclic.java000066400000000000000000000075141445075545500223270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; /** * Class to produce a system of equations defined as Cyclic. * * @author Heinz Kredel */ public class Cyclic { /** * main. */ public static void main(String[] args) { if ( args.length == 0 ) { System.out.println("usage: Cyclic N "); return; } int n = Integer.parseInt(args[0]); Cyclic k = null; if ( args.length == 1 ) { k = new Cyclic(n); } if ( args.length == 2 ) { k = new Cyclic("x",n, args[1]); } if ( args.length == 3 ) { k = new Cyclic(args[2],n, args[1]); } System.out.println("#Cyclic equations for N = " + n + ":"); System.out.println("" + k); } final int N; final String var; final String order; public final GenPolynomialRing ring; /** * Cyclic constructor. * @param n problem size. */ public Cyclic(int n) { this("x", n); } /** * Cyclic constructor. * @param v name of variables. * @param n problem size. */ public Cyclic(String v, int n) { this(v, n, "G"); } /** * Cyclic constructor. * @param var name of variables. * @param n problem size. * @param order term order letter for output. */ public Cyclic(String var, int n, String order) { this.var = var; this.N = n; this.order = order; BigInteger fac = new BigInteger(); ring = new GenPolynomialRing(fac, N); //,var); //System.out.println("ring = " + ring); } /** * toString. * @return Cyclic problem as string. */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(ring.toString().replace("BigInteger","Z")); s.append(System.getProperty("line.separator")); s.append( cyclicPolys(ring).toString() ); return s.toString(); } /** * Compute list of polynomials. * @return Cyclic problem as string of list of polynomials. */ public String polyList() { return cyclicPolys(ring).toString().replace("[","(").replace("]",")"); } /** * Compute list of polynomials. * @return Cyclic problem as list of polynomials. */ public List> cyclicPolys() { return cyclicPolys(ring); } /** * Compute list of polynomials. * @param ring polynomial ring. * @return Cyclic problem as list of polynomials. */ List> cyclicPolys(GenPolynomialRing ring) { int n = ring.nvar; List> cp = new ArrayList>(n); for (int i = 1; i <= n; i++) { GenPolynomial p = cyclicPoly(ring, n, i); cp.add(p); //System.out.println("p[" + i + "] = " + p); } return cp; } GenPolynomial cyclicPoly(GenPolynomialRing ring, int n, int i) { List> X = ring.univariateList(); GenPolynomial p = ring.getZERO(); for (int j = 1; j <= n; j++) { GenPolynomial pi = ring.getONE(); for (int k = j; k < j + i; k++) { pi = pi.multiply(X.get(k % n)); } p = p.sum(pi); if (i == n) { p = p.subtract(ring.getONE()); break; } } return p; } } java-algebra-system-2.7.200/src/edu/jas/gb/DGroebnerBaseSeq.java000066400000000000000000000527651445075545500242440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; import edu.jas.structure.NotInvertibleException; /** * D-Groebner Base sequential algorithm. Implements D-Groebner bases and GB * test. Note: Minimal reduced GBs are not unique. see BWK, section 10.1. * @param coefficient type * @author Heinz Kredel */ public class DGroebnerBaseSeq> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(DGroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ protected DReduction dred; // shadow super.red ?? /** * Constructor. */ public DGroebnerBaseSeq() { this(new DReductionSeq()); } /** * Constructor. * @param dred D-Reduction engine */ public DGroebnerBaseSeq(DReduction dred) { super(dred); this.dred = dred; assert this.dred == super.red; } /** * D-Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a D-Groebner base, else false. */ @Override public boolean isGB(int modv, List> F) { GenPolynomial pi, pj, s, d; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!dred.moduleCriterion(modv, pi, pj)) { continue; } d = dred.GPolynomial(pi, pj); if (!d.isZERO()) { // better check for top reduction only d = dred.normalform(F, d); } if (!d.isZERO()) { System.out.println("d-pol(" + pi + "," + pj + ") != 0: " + d); return false; } // works ok if (!dred.criterion4(pi, pj)) { continue; } s = dred.SPolynomial(pi, pj); if (!s.isZERO()) { s = dred.normalform(F, s); } if (!s.isZERO()) { System.out.println("s-pol(" + i + "," + j + ") != 0: " + s); return false; } } } return true; } /** * D-Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a D-Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); if (G.size() <= 1) { return G; } GenPolynomialRing ring = G.get(0).ring; OrderedDPairlist pairlist = new OrderedDPairlist(modv, ring); pairlist.put(G); Pair pair; GenPolynomial pi, pj, S, D, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //System.out.println("pair = " + pair); if (pair == null) continue; pi = pair.pi; pj = pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } H = null; // D-polynomial case ---------------------- D = dred.GPolynomial(pi, pj); //System.out.println("D_d = " + D); if (!D.isZERO() && !dred.isTopReducible(G, D)) { H = dred.normalform(G, D); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (!H.isZERO()) { logger.info("Dred = {}", H); //l++; G.add(H); pairlist.put(H); } } // S-polynomial case ----------------------- if (pair.getUseCriterion3() && pair.getUseCriterion4()) { S = dred.SPolynomial(pi, pj); //System.out.println("S_d = " + S); if (S.isZERO()) { pair.setZero(); //continue; } if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = dred.normalform(G, S); if (H.isZERO()) { pair.setZero(); //continue; } if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } logger.debug("H = {}", H); if (!H.isZERO()) { logger.info("Sred = {}", H); //len = G.size(); //l++; G.add(H); pairlist.put(H); } } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Extended Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return a container for an extended Groebner base of F. */ @Override public ExtendedGB extGB(int modv, List> F) { if (F == null || F.isEmpty()) { throw new IllegalArgumentException("null or empty F not allowed"); } List> G = new ArrayList>(); List>> F2G = new ArrayList>>(); List>> G2F = new ArrayList>>(); OrderedDPairlist pairlist = null; boolean oneInGB = false; int len = F.size(); List> row = null; List> rows = null; List> rowh = null; GenPolynomialRing ring = null; GenPolynomial H; GenPolynomial p; int nzlen = 0; for (GenPolynomial f : F) { if (f.length() > 0) { nzlen++; } if (ring == null) { ring = f.ring; } } GenPolynomial one = ring.getONE(); int k = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { row = blas.genVector(nzlen, null); row.set(k, one); k++; if (p.isUnit()) { G.clear(); G.add(p); G2F.clear(); G2F.add(row); oneInGB = true; break; } G.add(p); //logger.info("p row = {}", row); G2F.add(row); if (pairlist == null) { //pairlist = strategy.create(modv, p.ring); pairlist = new OrderedDPairlist(modv, p.ring); if (p.ring.coFac.isField()) { //throw new RuntimeException("coefficients from a field"); logger.warn("coefficients from a field " + p.ring.coFac); } } // putOne not required pairlist.put(p); } else { len--; } } ExtendedGB exgb; if (len <= 1 || oneInGB) { // adjust F2G for (GenPolynomial f : F) { row = blas.genVector(G.size(), null); H = dred.normalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero H = {}", H); } logger.info("f row = {}", row); F2G.add(row); } exgb = new ExtendedGB(F, G, F2G, G2F); //System.out.println("exgb #1 = " + exgb); return exgb; } Pair pair; int i, j; GenPolynomial pi, pj; GenPolynomial S, D; k = 0; while (pairlist.hasNext() && !oneInGB) { pair = pairlist.removeNext(); if (pair == null) { continue; } i = pair.i; j = pair.j; pi = pair.pi; pj = pair.pj; if (debug) { logger.info("i, pi = {}, {}", i, pi); logger.info("j, pj = {}, {}", j, pj); } H = null; // D-polynomial case ---------------------- rows = blas.genVector(G.size() + 1, null); D = dred.GPolynomial(rows, i, pi, j, pj); logger.info("Gpol = {}", D); if (debug) { logger.info("is reduction D = " + dred.isReductionNF(rows, G, D, ring.getZERO())); } if (!D.isZERO()) { //&& !dred.isTopReducible(G, D) //continue; rowh = blas.genVector(G.size() + 1, null); H = dred.normalform(rowh, G, D); if (debug) { logger.info("is reduction H = " + dred.isReductionNF(rowh, G, D, H)); } //H = H.monic(); int s = H.leadingBaseCoefficient().signum(); if (s < 0) { logger.info("negate: H_D rowd, rowh = {}, {}", rows, rowh); H = H.negate(); rows = blas.vectorNegate(rows); rowh = blas.vectorNegate(rowh); } if (H.isONE()) { // G.clear(); G.add(H); oneInGB = true; } else if (!H.isZERO()) { logger.info("H_G red = {}", H); G.add(H); pairlist.put(H); } //System.out.println("rowd = " + rows); //System.out.println("rowh = " + rowh); row = blas.vectorCombineRep(rows, rowh); logger.debug("H_G row = {}", row); if (!H.isZERO()) { G2F.add(row); } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); logger.info("is reduction D,H = " + dred.isReductionNF(row, G, H, ring.getZERO())); } } // S-polynomial case ---------------------- rows = blas.genVector(G.size() + 1, null); S = dred.SPolynomial(rows, i, pi, j, pj); logger.info("Spol = {}", S); if (debug) { logger.info("is reduction S = " + dred.isReductionNF(rows, G, S, ring.getZERO())); } rowh = blas.genVector(G.size() + 1, null); if (!S.isZERO()) { //&& !dred.isTopReducible(G, S) //continue; H = dred.normalform(rowh, G, S); if (debug) { logger.info("Spol_red = {}", H); logger.info("is reduction H = " + dred.isReductionNF(rowh, G, S, H)); } //H = H.monic(); int s = H.leadingBaseCoefficient().signum(); if (s < 0) { logger.info("negate: H_S rows, rowh = {}, {}", rows, rowh); H = H.negate(); //rowh = rowh.negate(); //rowh.set(G.size(), one.negate()); rows = blas.vectorNegate(rows); rowh = blas.vectorNegate(rowh); } //logger.info("Spol_red_norm = {}", H); if (H.isONE()) { //G.clear(); G.add(H); oneInGB = true; } else if (!H.isZERO()) { logger.info("H_S red = {}", H); G.add(H); pairlist.put(H); } //System.out.println("rows = " + rows); //System.out.println("rowh = " + rowh); row = blas.vectorCombineRep(rows, rowh); logger.debug("H_S row = {}", row); if (!H.isZERO()) { G2F.add(row); } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); logger.info("is reduction S,H = " + dred.isReductionNF(row, G, H, ring.getZERO())); } } } if (true || debug) { exgb = new ExtendedGB(F, G, F2G, G2F); boolean t = isReductionMatrix(exgb); if (!t) { logger.info("exgb unnorm = {}", exgb); logger.info("exgb t_1 = {}", t); } } G2F = normalizeMatrix(F.size(), G2F); if (debug) { exgb = new ExtendedGB(F, G, F2G, G2F); boolean t = isReductionMatrix(exgb); if (!t) { logger.info("exgb norm nonmin = {}", exgb); logger.info("exgb t_2 = {}", t); } } exgb = minimalExtendedGB(F.size(), G, G2F); G = exgb.G; G2F = exgb.G2F; if (true || debug) { exgb = new ExtendedGB(F, G, F2G, G2F); boolean t = isMinReductionMatrix(exgb); if (!t) { logger.info("exgb minGB = {}", exgb); logger.info("exgb t_3 = {}", t); } } exgb = new ExtendedGB(F, G, F2G, G2F); // setup matrices F and F2G for (GenPolynomial f : F) { row = blas.genVector(G.size() + 1, null); H = dred.normalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero H, G = {}, {}", H, G); throw new RuntimeException("H != 0"); } F2G.add(row); } exgb = new ExtendedGB(F, G, F2G, G2F); if (debug) { boolean t = isMinReductionMatrix(exgb); if (!t) { logger.info("exgb +F+F2G = {}", exgb); logger.info("exgb t_4 = {}", t); } } return exgb; } /** * Minimal extended groebner basis. * @param flen length of rows. * @param Gp a Groebner base. * @param M a reduction matrix. * @return a (partially) reduced Groebner base of Gp in a (fake) container. */ @Override public ExtendedGB minimalExtendedGB(int flen, List> Gp, List>> M) { if (Gp == null) { return null; //new ExtendedGB(null,Gp,null,M); } List> G, F, T; G = new ArrayList>(Gp); F = new ArrayList>(Gp.size()); List>> Mg, Mf; Mg = new ArrayList>>(M.size()); Mf = new ArrayList>>(M.size()); for (List> r : M) { // must be copied also List> row = new ArrayList>(r); Mg.add(row); } boolean mt; ListIterator> it; ArrayList ix = new ArrayList(); ArrayList jx = new ArrayList(); int k = 0; //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() ); GenPolynomialRing pfac = null; GenPolynomial pi, pj; ExpVector ei, ej; C ai, aj, r; while (G.size() > 0) { pi = G.remove(0); ei = pi.leadingExpVector(); ai = pi.leadingBaseCoefficient(); if (pfac == null) { pfac = pi.ring; } it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { pj = it.next(); ej = pj.leadingExpVector(); mt = ei.multipleOf(ej); if (mt) { aj = pj.leadingBaseCoefficient(); r = ai.remainder(aj); mt = r.isZERO(); // && mt } } it = F.listIterator(); while (it.hasNext() && !mt) { pj = it.next(); ej = pj.leadingExpVector(); mt = ei.multipleOf(ej); if (mt) { aj = pj.leadingBaseCoefficient(); r = ai.remainder(aj); mt = r.isZERO(); // && mt } } T = new ArrayList>(G); T.addAll(F); //GenPolynomial t = dred.normalform(T, pi); //System.out.println("t, mt, t==0: " + t + ", " + mt + ", " + t.isZERO()); if (!mt) { F.add(pi); ix.add(k); //System.out.println("ix: " + ix); } else { // drop polynomial and corresponding row and column ?? jx.add(k); //System.out.println("jx: " + jx); } k++; } logger.info("ix, jx, #M = {}, {}, {}", ix, jx, Mg.size()); int fix = -1; // copied polys // copy Mg to Mf as indicated by ix for (int i = 0; i < ix.size(); i++) { int u = ix.get(i); if (u >= flen && fix == -1) { fix = Mf.size(); } //System.out.println("copy u_ix, fix = " + u + ", " + fix); if (u >= 0) { List> row = Mg.get(u); Mf.add(row); } } // for (int i = 0; i < jx.size(); i++) { // int u = jx.get(i); // //System.out.println("copy u_jx = " + u); // if (u >= 0) { // List> row = blas.genVector(flen,null); // Mf.add(u, row); // F.add(u, pfac.getZERO()); // } // } if (F.size() <= 1 || fix == -1) { return new ExtendedGB(null, F, null, Mf); } // must return, since extended normalform has not correct order of polys return new ExtendedGB(null, F, null, Mf); /* G = F; F = new ArrayList>( G.size() ); List> temp; k = 0; final int len = G.size(); while ( G.size() > 0 ) { a = G.remove(0); if ( k >= fix ) { // dont touch copied polys row = Mf.get( k ); //System.out.println("doing k = " + k + ", " + a); // must keep order, but removed polys missing temp = new ArrayList>( len ); temp.addAll( F ); temp.add( a.ring.getZERO() ); // ?? temp.addAll( G ); //System.out.println("row before = " + row); a = red.normalform( row, temp, a ); //System.out.println("row after = " + row); } F.add( a ); k++; } // does Mf need renormalization? */ } /** * Inverse for element modulo ideal. * @param h polynomial * @param F polynomial list * @return inverse of h with respect to ideal(F), if defined */ public GenPolynomial inverse(GenPolynomial h, List> F) { if (h == null || h.isZERO()) { throw new NotInvertibleException("zero not invertible"); } if (F == null || F.size() == 0) { throw new NotInvertibleException("zero ideal"); } if (h.isUnit()) { return h.inverse(); } // prepare by GB precomputation List> G = GB(F); List> I = new ArrayList>(1 + G.size()); I.add(h); I.addAll(G); // now compute extended gcd(h,G) ExtendedGB X = extGB(I); List> hG = X.G; //System.out.println("hG = " + hG); GenPolynomial one = null; int i = -1; for (GenPolynomial p : hG) { i++; if (p == null) { continue; } if (p.isUnit()) { one = p; break; } } if (one == null) { throw new NotInvertibleException("h = " + h); } List> row = X.G2F.get(i); // != -1 GenPolynomial g = row.get(0); if (g == null || g.isZERO()) { throw new NotInvertibleException("h = " + h); } // adjust g to get g*h == 1 mod ideal(G) GenPolynomial f = g.multiply(h); GenPolynomial k = red.normalform(G, f); //System.out.println("g = " + g + ", h = " + h + ", f = " + f + ", k = " + k); if (k.signum() < 0) { // then is -1 or inv-G(0) //System.out.println("k < 0: " + G); g = g.sum(G.get(0)); //.negate(); } return g; } } java-algebra-system-2.7.200/src/edu/jas/gb/DReduction.java000066400000000000000000000020161445075545500231510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial D Reduction interface. Defines additionally G-Polynomial. * @param coefficient type * @author Heinz Kredel */ public interface DReduction> extends Reduction { /** * G-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return gpol(Ap,Bp) the g-polynomial of Ap and Bp. */ public GenPolynomial GPolynomial(GenPolynomial Ap, GenPolynomial Bp); /** * G-Polynomial with recording. * @param S recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return gpol(Ap, Bp), the g-Polynomial for Ap and Bp. */ public GenPolynomial GPolynomial(List> S, int i, GenPolynomial Ap, int j, GenPolynomial Bp); } java-algebra-system-2.7.200/src/edu/jas/gb/DReductionSeq.java000066400000000000000000000464331445075545500236350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Polynomial D-Reduction sequential use algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class DReductionSeq> extends ReductionAbstract implements DReduction { private static final Logger logger = LogManager.getLogger(DReductionSeq.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public DReductionSeq() { } /** * Is top reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ @Override public boolean isTopReducible(List> P, GenPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); C a = A.leadingBaseCoefficient(); for (GenPolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { C b = p.leadingBaseCoefficient(); C r = a.remainder(b); mt = r.isZERO(); if (mt) { return true; } } } return false; } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") @Override public boolean isNormalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; boolean mt = false; Map Am = Ap.getMap(); for (Map.Entry me : Am.entrySet()) { ExpVector e = me.getKey(); C a = me.getValue(); //Am.get(e); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { C r = a.remainder(lbc[i]); mt = r.isZERO(); if (mt) { return false; } } } } return true; } /** * Normalform using d-reduction. * @param Ap polynomial. * @param Pp polynomial list. * @return d-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") @Override public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); //.abs(); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; C r = null; boolean mt = false; GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { r = a.remainder(lbc[i]); mt = r.isZERO(); // && mt } if (mt) break; } if (!mt) { //logger.debug("irred"); R = R.sum(a, e); //S = S.subtract( a, e ); S = S.reductum(); //System.out.println(" S = " + S); } else { //logger.info("red div = {}", e); ExpVector f = e.subtract(htl[i]); C b = a.divide(lbc[i]); // r == 0: R = R.sum(r, e); Q = p[i].multiply(b, f); S = S.reductum().subtract(Q.reductum()); // ok also with reductum } } return R.abs(); // ok with d-reduction } /** * S-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return spol(Ap,Bp) the S-polynomial of Ap and Bp. */ @Override public GenPolynomial SPolynomial(GenPolynomial Ap, GenPolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { return Ap.ring.getZERO(); } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); //c = lcm(a,b) C c = a.gcd(b); C m = a.multiply(b); C l = m.divide(c); C a1 = l.divide(a); C b1 = l.divide(b); //Cp = a1 e1 * A - b1 f1 * B GenPolynomial Cp = Ap.scaleSubtractMultiple(a1, e1, b1, f1, Bp); return Cp; } /** * G-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return gpol(Ap,Bp) the g-polynomial of Ap and Bp. */ @Override public GenPolynomial GPolynomial(GenPolynomial Ap, GenPolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { return Ap.ring.getZERO(); } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); C[] c = a.egcd(b); // c[0] = c[1] a + c[2] b //System.out.println("egcd[0] " + c[0]); //Cp = c[1] e1 * A + c[2] f1 * B = c[1] e1 * A - (-c[2]) f1 * B GenPolynomial Cp = Ap.scaleSubtractMultiple(c[1], e1, c[2].negate(), f1, Bp); return Cp; // .negate() - } /** * S-Polynomial with recording. * @param row recording vector, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return spol(Ap, Bp), the s-Polynomial for Ap and Bp. */ @Override public GenPolynomial SPolynomial(List> row, int i, GenPolynomial Ap, int j, GenPolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { return Ap.ring.getZERO(); } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } //if ((row.get(i) != null && !row.get(i).isZERO()) || (row.get(j) != null && !row.get(j).isZERO())) { // throw new IllegalArgumentException("row(i), row(j): " + row.get(i) + ", " + row.get(j)); //} } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); //c = lcm(a,b) C c = a.gcd(b); C m = a.multiply(b); C l = m.divide(c); C a1 = l.divide(a); C b1 = l.divide(b); //Cp = a1 e1 * A - b1 f1 * B GenPolynomial Cp = Ap.scaleSubtractMultiple(a1, e1, b1, f1, Bp); GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial As = zero.sum(a1, e1); /*not correct .negate()*/ GenPolynomial Bs = zero.sum(b1.negate(), f1); /*correct */ row.set(i, As); row.set(j, Bs); return Cp; } /** * G-Polynomial with recording. * @param row recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return gpol(Ap, Bp), the g-Polynomial for Ap and Bp. */ @Override public GenPolynomial GPolynomial(List> row, int i, GenPolynomial Ap, int j, GenPolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { return Ap.ring.getZERO(); } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } //if ((row.get(i) != null && !row.get(i).isZERO()) || (row.get(j) != null && !row.get(j).isZERO())) { // throw new IllegalArgumentException("row(i), row(j): " + row.get(i) + ", " + row.get(j)); //} } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); C[] c = a.egcd(b); // c[0] = c[1] a + c[2] b //System.out.println("egcd[0] " + c[0]); //Cp = c[1] e1 * A + c[2] f1 * B = c[1] e1 * A - (-c[2]) f1 * B GenPolynomial Cp = Ap.scaleSubtractMultiple(c[1], e1, c[2].negate(), f1, Bp); GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial As = zero.sum(c[1], e1); // .negate() - GenPolynomial Bs = zero.sum(c[2], f1); // .negate() - row.set(i, As); row.set(j, Bs); return Cp; // .negate() - } /** * GB criterium 4. Use only for commutative polynomial rings. This version * works also for d-Groebner bases. * @param A polynomial. * @param B polynomial. * @param e = lcm(ht(A),ht(B)) * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B, ExpVector e) { if (logger.isInfoEnabled()) { if (!A.ring.equals(B.ring)) { logger.error("rings equal"); } if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) { logger.error("GBCriterion4 not applicabable to SolvablePolynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); ExpVector g = ei.sum(ej); // boolean t = g == e ; ExpVector h = g.subtract(e); int s = h.signum(); if (s == 0) { // disjoint ht C a = A.leadingBaseCoefficient(); C b = B.leadingBaseCoefficient(); C d = a.gcd(b); if (d.isONE()) { // disjoint hc //System.out.println("d1 = " + d + ", a = " + a + ", b = " + b); return false; // can skip pair } } return true; //! ( s == 0 ); } /** * GB criterium 4. Use only for commutative polynomial rings. This version * works also for d-Groebner bases. * @param A polynomial. * @param B polynomial. * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B) { if (logger.isInfoEnabled()) { if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) { logger.error("GBCriterion4 not applicabable to SolvablePolynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); ExpVector g = ei.sum(ej); ExpVector e = ei.lcm(ej); // boolean t = g == e ; ExpVector h = g.subtract(e); int s = h.signum(); if (s == 0) { // disjoint ht C a = A.leadingBaseCoefficient(); C b = B.leadingBaseCoefficient(); C d = a.gcd(b); if (d.isONE()) { // disjoint hc return false; // can skip pair } } return true; //! ( s == 0 ); } /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") @Override public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e = null; ExpVector f = null; C a = null; C b = null; C r = null; GenPolynomialRing pfac = Ap.ring; GenPolynomial R = pfac.getZERO(); GenPolynomial zero = pfac.getZERO(); GenPolynomial fac = null; // GenPolynomial T = null; GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { boolean mt = false; m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { r = a.remainder(lbc[i]); mt = r.isZERO(); } if (mt) break; } if (!mt) { //logger.debug("irred"); R = R.sum(a, e); S = S.subtract(a, e); //System.out.println("a = " + a + ", e = " + e); } else { //logger.info("red div = {}", e); f = e.subtract(htl[i]); b = a.divide(lbc[i]); //System.out.println("b = " + b + ", f = " + f); // r == 0: R = R.sum(r, f); Q = p[i].multiply(b, f); S = S.reductum().subtract(Q.reductum()); // ok also with reductum fac = row.get(i); if (fac == null) { fac = zero.sum(b, f); } else { fac = fac.sum(b, f); } row.set(i, fac); } } return R; } /** * Irreducible set. * @param Pp polynomial list. * @return a list P of polynomials which are in normalform wrt. P. */ @Override public List> irreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); if (Pp == null) { return null; } for (GenPolynomial a : Pp) { if (!a.isZERO()) { P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; ExpVector e; ExpVector f; GenPolynomial a; logger.debug("irr = "); while (irr != l) { a = P.remove(0); e = a.leadingExpVector(); a = normalform(P, a); logger.debug(String.valueOf(irr)); if (a.isZERO()) { l--; if (l <= 1) { return P; } } else { f = a.leadingExpVector(); if (e.equals(f)) { irr++; } else { irr = 0; } P.add(a); } } //System.out.println(); return P; } // inherit is okay: //public boolean isReductionNF(List> row, List> Pp, GenPolynomial Ap, // GenPolynomial Np) { } java-algebra-system-2.7.200/src/edu/jas/gb/EGroebnerBaseSeq.java000066400000000000000000000017661445075545500242400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import edu.jas.structure.RingElem; /** * E-Groebner Base sequential algorithm. Nearly empty class, only the * e-reduction is used instead of d-reduction. Note: Minimal reduced GBs * are again unique. see BWK, section 10.1. * @param coefficient type * @author Heinz Kredel */ public class EGroebnerBaseSeq> extends DGroebnerBaseSeq { //private static final Logger logger = LogManager.getLogger(EGroebnerBaseSeq.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ protected EReduction ered; // shadow super.red ?? /** * Constructor. */ public EGroebnerBaseSeq() { this(new EReductionSeq()); } /** * Constructor. * @param ered E-Reduction engine */ public EGroebnerBaseSeq(EReductionSeq ered) { super(ered); this.ered = ered; assert this.ered == super.red; } } java-algebra-system-2.7.200/src/edu/jas/gb/EReduction.java000066400000000000000000000005451445075545500231570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import edu.jas.structure.RingElem; /** * Polynomial E-Reduction interface. Empty marker interface since all required * methods are already defined in the DReduction interface. * @param coefficient type * @author Heinz Kredel */ public interface EReduction> extends DReduction { } java-algebra-system-2.7.200/src/edu/jas/gb/EReductionSeq.java000066400000000000000000000266421445075545500236360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Polynomial E-Reduction sequential use algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class EReductionSeq> extends DReductionSeq implements EReduction { private static final Logger logger = LogManager.getLogger(DReductionSeq.class); /** * Constructor. */ public EReductionSeq() { } /** * Is top reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ @Override public boolean isTopReducible(List> P, GenPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); C a = A.leadingBaseCoefficient(); for (GenPolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { C b = p.leadingBaseCoefficient(); C r = a.remainder(b); mt = !r.equals(a); if (mt) { return true; } } } return false; } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") @Override public boolean isNormalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; boolean mt = false; Map Am = Ap.getMap(); for (Map.Entry me : Am.entrySet()) { ExpVector e = me.getKey(); C a = me.getValue(); //Am.get(e); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { C r = a.remainder(lbc[i]); mt = !r.equals(a); if (mt) { return false; } } } } return true; } /** * Normalform using e-reduction. * @param Ap polynomial. * @param Pp polynomial list. * @return e-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") @Override public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); //.abs(); } } Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e = null; ExpVector f = null; C a = null; C b = null; C r = null; GenPolynomialRing pfac = Ap.ring; GenPolynomial R = pfac.getZERO(); //GenPolynomial T = pfac.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; //try { // required to avoid a compiler error in the while loop while (S.length() > 0) { boolean mt = false; m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { f = e.subtract(htl[i]); //logger.info("red div = {}", f); r = a.remainder(lbc[i]); b = a.divide(lbc[i]); if (f == null) { // compiler produced this case ??? still ? System.out.println("f = null: " + e + ", " + htl[i]); Q = p[i].multiply(b); } else { Q = p[i].multiply(b, f); } S = S.subtract(Q); // ok also with reductum //System.out.println(" r = " + r); a = r; if (r.isZERO()) { break; } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); //S = S.subtract( a, e ); S = S.reductum(); } //System.out.println(" R = " + R); //System.out.println(" S = " + S); } return R; //.abs(); not ok with e-reduction } /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @Override @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); //.abs(); } } ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e = null; ExpVector f = null; C a = null; C b = null; C r = null; GenPolynomialRing pfac = Ap.ring; GenPolynomial R = pfac.getZERO(); GenPolynomial zero = pfac.getZERO(); //System.out.println("row_in = " + row); GenPolynomial fac = null; // GenPolynomial T = null; GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { boolean mt = false; m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); //System.out.println("e = " + e); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { f = e.subtract(htl[i]); //logger.info("red div = {}", f); r = a.remainder(lbc[i]); b = a.divide(lbc[i]); //if (f == null) { // compiler produced this case ??? still ? // System.out.println("f = null: " + e + ", " + htl[i]); // f = pfac.evzero; //} Q = p[i].multiply(b, f); S = S.subtract(Q); fac = row.get(i); if (fac == null) { fac = zero.sum(b, f); } else { fac = fac.sum(b, f); } row.set(i, fac); //System.out.println("i = " + i); //System.out.println("r = " + r); a = r; if (r.isZERO()) { break; } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.subtract(a, e); //??S = S.reductum(); } } return R; } /** * Irreducible set. * @param Pp polynomial list. * @return a list P of polynomials which are in normalform wrt. P. */ @Override public List> irreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); if (Pp == null) { return null; } for (GenPolynomial a : Pp) { if (!a.isZERO()) { P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; ExpVector e; ExpVector f; C c; C d; GenPolynomial a; //Iterator> it; logger.debug("irr = "); while (irr != l) { //it = P.listIterator(); //a = P.get(0); //it.next(); a = P.remove(0); e = a.leadingExpVector(); c = a.leadingBaseCoefficient(); a = normalform(P, a); logger.debug(String.valueOf(irr)); if (a.isZERO()) { l--; if (l <= 1) { return P; } } else { f = a.leadingExpVector(); d = a.leadingBaseCoefficient(); if (e.equals(f) && c.equals(d)) { irr++; } else { irr = 0; } P.add(a); } } //System.out.println(); return P; } // inherit is okay: //public boolean isReductionNF(List> row, List> Pp, GenPolynomial Ap, // GenPolynomial Np) { } java-algebra-system-2.7.200/src/edu/jas/gb/ExtendedGB.java000066400000000000000000000044061445075545500230670ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Container for a GB and transformation matrices. A container for F, G, calG * and calF. Immutable objects. * @typeparam C coefficient type */ public class ExtendedGB> { public final List> F; public final List> G; public final List>> F2G; public final List>> G2F; public final GenPolynomialRing ring; /** * Container for a GB and transformation matrices. * @param F an ideal base. * @param G a Groebner base of F. * @param F2G a transformation matrix from F to G. * @param G2F a transformation matrix from G to F. */ public ExtendedGB(List> F, List> G, List>> F2G, List>> G2F) { this.F = F; this.G = G; this.F2G = F2G; this.G2F = G2F; GenPolynomialRing r = null; if (G != null) { for (GenPolynomial p : G) { if (p != null) { r = p.ring; break; } } if (r != null && r.getVars() == null) { r.setVars(r.newVars("y")); } } this.ring = r; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { PolynomialList P; ModuleList M; StringBuffer s = new StringBuffer("ExtendedGB: \n\n"); P = null; if (F != null) { P = new PolynomialList(ring, F); } s.append("F = " + P + "\n\n"); P = new PolynomialList(ring, G); s.append("G = " + P + "\n\n"); M = null; if (F2G != null) { M = new ModuleList(ring, F2G); } s.append("F2G = " + M + "\n\n"); M = new ModuleList(ring, G2F); s.append("G2F = " + M + "\n"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GBDistSP.java000066400000000000000000000060771445075545500225030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; import edu.jas.util.DistThreadPool; import edu.jas.util.RemoteExecutable; /** * Setup to run a distributed GB example. * @author Heinz Kredel * @see edu.jas.application.RunGB * @see edu.jas.application.RunSGB * @deprecated use RunGB or RunSGB for standalone execution */ @Deprecated public class GBDistSP> { /** * machine file to use. */ private final String mfile; /** * Number of threads to use. */ protected final int threads; /** * Server port to use. */ protected final int port; /** * GB algorithm to use. */ private final GroebnerBaseSeqPairDistributed bbd; /** * Distributed thread pool to use. */ private final DistThreadPool dtp; /** * Constructor. * @param threads number of threads respectively processes. * @param mfile name of the machine file. * @param port for GB server. */ public GBDistSP(int threads, String mfile, int port) { this.threads = threads; if (mfile == null || mfile.length() == 0) { this.mfile = "../util/machines"; } else { this.mfile = mfile; } this.port = port; bbd = new GroebnerBaseSeqPairDistributed(threads, this.port); dtp = new DistThreadPool(threads, this.mfile); } /** * Execute a distributed GB example. Distribute clients and start master. * @param F list of polynomials * @return GB(F) a Groebner base for F. */ public List> execute(List> F) { String master = dtp.getEC().getMasterHost(); int port = dtp.getEC().getMasterPort(); GBClientSP gbc = new GBClientSP(master, port); for (int i = 0; i < threads; i++) { // schedule remote clients dtp.addJob(gbc); } // run master List> G = bbd.GB(F); return G; } /** * Terminates the distributed thread pools. * @param shutDown true, if shut-down of the remote executable servers is * requested, false, if remote executable servers stay alive. */ public void terminate(boolean shutDown) { bbd.terminate(); dtp.terminate(shutDown); } } /** * Objects of this class are to be send to a ExecutableServer. */ class GBClientSP> implements RemoteExecutable { String host; int port; /** * GBClient. * @param host * @param port */ public GBClientSP(String host, int port) { this.host = host; this.port = port; } /** * run. */ public void run() { GroebnerBaseSeqPairDistributed bbd; bbd = new GroebnerBaseSeqPairDistributed(1, null, port); try { bbd.clientPart(host); } catch (IOException ignored) { } bbd.terminate(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GBOptimized.java000066400000000000000000000064031445075545500232720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OptimizedPolynomialList; import edu.jas.poly.TermOrderOptimization; import edu.jas.structure.GcdRingElem; /** * Groebner bases via optimized variable and term order. * @author Heinz Kredel */ public class GBOptimized> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GBOptimized.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GB engine. */ public final GroebnerBaseAbstract e1; /** * Indicator for return of permuted polynomials. */ public final boolean retPermuted; /** * GBOptimized constructor. * @param e1 Groebner base engine. */ public GBOptimized(GroebnerBaseAbstract e1) { this(e1, false); // true ?? } /** * GBOptimized constructor. * @param e1 Groebner base engine. * @param rP true for return of permuted polynomials, false for inverse * permuted polynomials and new GB computation. */ public GBOptimized(GroebnerBaseAbstract e1, boolean rP) { this.e1 = e1; this.retPermuted = rP; } /** * Get the String representation with GB engine. * @see java.lang.Object#toString() */ @Override public String toString() { return "GBOptimized[ " + e1.toString() + " ]"; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { e1.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { int s = e1.cancel(); return s; } /** * Groebner base. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List> GB(int modv, List> F) { if (F == null || F.isEmpty()) { return F; } if (modv != 0) { throw new UnsupportedOperationException("implemented only for modv = 0, not " + modv); } GenPolynomialRing pfac = F.get(0).ring; OptimizedPolynomialList opt = TermOrderOptimization. optimizeTermOrder(pfac, F); List> P = opt.list; if (debug) { logger.info("optimized polynomials: {}", P); } List iperm = TermOrderOptimization.inversePermutation(opt.perm); logger.info("optimize perm: {}, de-optimize perm: {}", opt.perm, iperm); // compute GB with backing engine List> G = e1.GB(modv, P); if (retPermuted || G.isEmpty()) { return G; } List> iopt = TermOrderOptimization. permutation(iperm, pfac, G); if (debug) { logger.info("de-optimized polynomials: {}", iopt); } if (iopt.size() == 1) { return iopt; } logger.warn("recomputing GB"); G = e1.GB(modv, iopt); return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/GBProxy.java000066400000000000000000000111761445075545500224520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PreemptingException; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Groebner bases parallel proxy. * @author Heinz Kredel */ public class GBProxy> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GBProxy.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GB engines. */ public final GroebnerBaseAbstract e1; public final GroebnerBaseAbstract e2; /** * Thread pool. */ protected transient ExecutorService pool; /** * Proxy constructor. * @param e1 Groebner base engine. * @param e2 Groebner base engine. */ public GBProxy(GroebnerBaseAbstract e1, GroebnerBaseAbstract e2) { this.e1 = e1; this.e2 = e2; pool = ComputerThreads.getPool(); //System.out.println("pool 2 = "+pool); } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return "GBProxy[ " + e1.toString() + ", " + e2.toString() + " ]"; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { e1.terminate(); e2.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { int s = e1.cancel(); s += e2.cancel(); return s; } /** * Groebner base. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List> GB(final int modv, final List> F) { if (F == null || F.isEmpty()) { return F; } // parallel case List> G = null; List>>> cs = new ArrayList>>>(2); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); List> G = e1.GB(modv, F); if (debug) { logger.info("GBProxy done e1 {}", e1.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("GBProxy e1 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GBProxy e1 {}", e); logger.info("Exception GBProxy F = {}", F); throw new RuntimeException("GBProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); List> G = e2.GB(modv, F); if (debug) { logger.info("GBProxy done e2 {}", e2.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("GBProxy e2 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GBProxy e2 {}", e); logger.info("Exception GBProxy F = {}", F); throw new RuntimeException("GBProxy e2 " + e); //return P.ring.getONE(); } } }); try { G = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/GBTransportMess.java000066400000000000000000000057431445075545500241600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Distributed GB transport message. This class and its subclasses are used for * transport of polynomials and pairs and as markers in distributed GB * algorithms. * @author Heinz Kredel */ public class GBTransportMess implements Serializable { public GBTransportMess() { } /** * toString. */ @Override public String toString() { return this.getClass().getName(); } } /** * Distributed GB transport message for requests. */ final class GBTransportMessReq extends GBTransportMess { public GBTransportMessReq() { } } /** * Distributed GB transport message for termination. */ final class GBTransportMessEnd extends GBTransportMess { public GBTransportMessEnd() { } } /** * Distributed GB transport message for polynomial. */ final class GBTransportMessPoly> extends GBTransportMess { /** * The polynomial to transport. */ public final GenPolynomial pol; /** * GBTransportMessPoly. * @param p polynomial to transferred. */ public GBTransportMessPoly(GenPolynomial p) { this.pol = p; } /** * toString. */ @Override public String toString() { return super.toString() + "( " + pol + " )"; } } /** * Distributed GB transport message for pairs. */ final class GBTransportMessPair> extends GBTransportMess { public final Pair pair; /** * GBTransportMessPair. * @param p pair for transfer. */ public GBTransportMessPair(Pair p) { this.pair = p; } /** * toString. */ @Override public String toString() { return super.toString() + "( " + pair + " )"; } } /** * Distributed GB transport message for index pairs. */ final class GBTransportMessPairIndex extends GBTransportMess { public final int i; public final int j; public final int s; /** * GBTransportMessPairIndex. * @param p pair for transport. */ public GBTransportMessPairIndex(Pair p) { this(p.i, p.j, p.s); } /** * GBTransportMessPairIndex. * @param i first index. * @param j second index. * @param s maximal index. */ public GBTransportMessPairIndex(int i, int j, int s) { this.i = i; this.j = j; s = Math.max(this.i, s); s = Math.max(this.j, s); this.s = s; } /** * GBTransportMessPairIndex. * @param i first index. * @param j second index. * @param s maximal index. */ public GBTransportMessPairIndex(Integer i, Integer j, Integer s) { this(i.intValue(), j.intValue(), s.intValue()); } /** * toString. */ @Override public String toString() { return super.toString() + "(" + i + "," + j + "," + s + ")"; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBase.java000066400000000000000000000062031445075545500234510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.io.Serializable; import edu.jas.structure.RingElem; import edu.jas.poly.GenPolynomial; import edu.jas.poly.ModuleList; /** * Groebner Bases interface. * Defines methods for Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public interface GroebnerBase> extends Serializable { /** * Groebner base test. * @param F polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(List> F); /** * Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(int modv, List> F); /** * Groebner base using pairlist class. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB( List> F ); /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB( int modv, List> F ); /** * isGB. * @param M a module basis. * @return true, if M is a Groebner base, else false. */ public boolean isGB(ModuleList M); /** * GB. * @param M a module basis. * @return GB(M), a Groebner base of M. */ public ModuleList GB(ModuleList M); /** * Extended Groebner base using critical pair class. * @param F polynomial list. * @return a container for a Groebner base G of F together with back-and-forth transformations. */ public ExtendedGB extGB(List> F); /** * Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for a Groebner base G of F together with back-and-forth transformations. */ public ExtendedGB extGB(int modv, List> F); /** * Minimal ordered groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ public List> minimalGB(List> Gp); /** * Test if reduction matrix. * @param exgb an ExtendedGB container. * @return true, if exgb contains a reduction matrix, else false. */ public boolean isReductionMatrix(ExtendedGB exgb); /** * Test if reduction matrix. * @param F a polynomial list. * @param G a Groebner base. * @param Mf a possible reduction matrix. * @param Mg a possible reduction matrix. * @return true, if Mg and Mf are reduction matrices, else false. */ public boolean isReductionMatrix(List> F, List> G, List>> Mf, List>> Mg); } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseAbstract.java000066400000000000000000000776361445075545500251570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.vector.BasicLinAlg; /** * Groebner Bases abstract class. Implements common Groebner bases and GB test * methods. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public abstract class GroebnerBaseAbstract> implements GroebnerBase { private static final Logger logger = LogManager.getLogger(GroebnerBaseAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ public final Reduction red; /** * Strategy for pair selection. */ public final PairList strategy; /** * linear algebra engine. */ public final BasicLinAlg> blas; /** * Constructor. */ public GroebnerBaseAbstract() { this(new ReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseAbstract(Reduction red) { this(red, new OrderedPairlist()); } /** * Constructor. * @param pl pair selection strategy */ public GroebnerBaseAbstract(PairList pl) { this(new ReductionSeq(), pl); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseAbstract(Reduction red, PairList pl) { if (red == null) { red = new ReductionSeq(); } this.red = red; if (pl == null) { pl = new OrderedPairlist(); } this.strategy = pl; blas = new BasicLinAlg>(); } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName(); } /** * Normalize polynomial list. * @param A list of polynomials. * @return list of polynomials with zeros removed and ones/units reduced. */ public List> normalizeZerosOnes(List> A) { if (A == null) { return A; } List> N = new ArrayList>(A.size()); if (A.isEmpty()) { return N; } for (GenPolynomial p : A) { if (p == null || p.isZERO()) { continue; } if (p.isUnit()) { N.clear(); N.add(p.ring.getONE()); return N; } N.add(p.abs()); } //N.trimToSize(); return N; } /** * Groebner base test. * @param F polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(List> F) { return isGB(0, F); } /** * Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(int modv, List> F) { return isGB(modv, F, true); } /** * Groebner base test. * @param F polynomial list. * @param b true for simple test, false for GB test. * @return true, if F is a Groebner base, else false. */ public boolean isGB(List> F, boolean b) { return isGB(0, F, b); } /** * Groebner base test. * @param modv module variable number. * @param F polynomial list. * @param b true for simple test, false for GB test. * @return true, if F is a Groebner base, else false. */ public boolean isGB(int modv, List> F, boolean b) { if (b) { return isGBsimple(modv, F); } return isGBidem(modv, F); } /** * Groebner base simple test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGBsimple(int modv, List> F) { if (F == null || F.isEmpty()) { return true; } GenPolynomial pi, pj, s, h; ExpVector ei, ej, eij; for (int i = 0; i < F.size(); i++) { pi = F.get(i); ei = pi.leadingExpVector(); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); ej = pj.leadingExpVector(); if (!red.moduleCriterion(modv, ei, ej)) { continue; } eij = ei.lcm(ej); if (!red.criterion4(ei, ej, eij)) { continue; } if (!criterion3(i, j, eij, F)) { continue; } s = red.SPolynomial(pi, pj); if (s.isZERO()) { continue; } //System.out.println("i, j = " + i + ", " + j); h = red.normalform(F, s); if (!h.isZERO()) { logger.info("no GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } } return true; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ boolean criterion3(int i, int j, ExpVector eij, List> P) { assert i < j; //for ( int k = 0; k < P.size(); k++ ) { // not of much use for (int k = 0; k < i; k++) { GenPolynomial A = P.get(k); ExpVector ek = A.leadingExpVector(); if (eij.multipleOf(ek)) { return false; } } return true; } /** * Groebner base idempotence test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isGBidem(int modv, List> F) { if (F == null || F.isEmpty()) { return true; } GenPolynomialRing pring = F.get(0).ring; List> G = GB(modv, F); PolynomialList Fp = new PolynomialList(pring, F); PolynomialList Gp = new PolynomialList(pring, G); return Fp.compareTo(Gp) == 0; } /** * Common zero test. * @param F polynomial list. * @return -1, 0 or 1 if dimension(ideal(F)) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest(List> F) { if (F == null || F.isEmpty()) { return 1; } GenPolynomialRing pfac = F.get(0).ring; if (pfac.nvar <= 0) { return -1; } //int uht = 0; Set v = new HashSet(); // for non reduced GBs for (GenPolynomial p : F) { if (p.isZERO()) { continue; } if (p.isConstant()) { // for non-monic lists return -1; } ExpVector e = p.leadingExpVector(); if (e == null) { continue; } int[] u = e.dependencyOnVariables(); if (u == null) { continue; } if (u.length == 1) { //uht++; v.add(u[0]); } } if (pfac.nvar == v.size()) { return 0; } return 1; } /** * Groebner base using pairlist class. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(List> F) { return GB(0, F); } /** * isGB. * @param M a module basis. * @return true, if M is a Groebner base, else false. */ public boolean isGB(ModuleList M) { return isGB(M, false); } /** * isGB. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return true, if M is a Groebner base, else false. */ public boolean isGB(ModuleList M, boolean top) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } PolynomialList F = M.getPolynomialList(top); int modv = M.cols; // > 0 return isGB(modv, F.list); } /** * GB. * @param M a module basis. * @return GB(M), a Groebner base of M. */ public ModuleList GB(ModuleList M) { return GB(M, false); } /** * GB. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return GB(M), a Groebner base of M wrt. TOP or POT. */ public ModuleList GB(ModuleList M, boolean top) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(top); int modv = M.cols; List> G = GB(modv, F.list); F = new PolynomialList(F.ring, G); N = F.getModuleList(modv); return N; } /** * Extended Groebner base using critical pair class. * @param F polynomial list. * @return a container for a Groebner base G of F together with * back-and-forth transformations. */ public ExtendedGB extGB(List> F) { return extGB(0, F); } /** * Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for a Groebner base G of F together with * back-and-forth transformations. */ public ExtendedGB extGB(int modv, List> F) { throw new UnsupportedOperationException( "extGB not implemented in " + this.getClass().getSimpleName()); } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ public List> minimalGB(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial a; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } // reduce remaining polynomials Collections.reverse(G); // important for lex GB int len = G.size(); if (debug) { System.out.println("#G " + len); for (GenPolynomial aa : G) { System.out.println("aa = " + aa.length() + ", lt = " + aa.getMap().keySet()); } } int i = 0; while (i < len) { a = G.remove(0); if (debug) { System.out.println("doing " + a.length() + ", lt = " + a.leadingExpVector()); } a = red.normalform(G, a); G.add(a); // adds as last i++; } Collections.reverse(G); // undo reverse return G; } /** * Test for minimal ordered Groebner basis. * @param Gp an ideal base. * @return true, if Gp is a reduced minimal Groebner base. */ public boolean isMinimalGB(List> Gp) { if (Gp == null || Gp.size() == 0) { return true; } // test for zero polynomials for (GenPolynomial a : Gp) { if (a == null || a.isZERO()) { if (debug) { logger.debug("zero polynomial {}", a); } return false; } } // test for top reducible polynomials List> G = new ArrayList>(Gp); List> F = new ArrayList>(G.size()); while (G.size() > 0) { GenPolynomial a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { if (debug) { logger.debug("top reducible polynomial {}", a); } return false; } F.add(a); } G = F; if (G.size() <= 1) { return true; } // test reducibility of polynomials int len = G.size(); int i = 0; while (i < len) { GenPolynomial a = G.remove(0); if (!red.isNormalform(G, a)) { if (debug) { logger.debug("reducible polynomial {}", a); } return false; } G.add(a); // re-adds as last i++; } return true; } /** * Test if reduction matrix. * @param exgb an ExtendedGB container. * @return true, if exgb contains a reduction matrix, else false. */ public boolean isReductionMatrix(ExtendedGB exgb) { if (exgb == null) { return true; } return isReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F); } /** * Test if minimal reduction matrix. * @param exgb an ExtendedGB container. * @return true, if exgb contains a minimal reduction matrix, else false. */ public boolean isMinReductionMatrix(ExtendedGB exgb) { if (exgb == null) { return true; } return isMinReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F); } /** * Test if reduction matrix. * @param F a polynomial list. * @param G a Groebner base, G starting with +/- elements of F. * @param Mf a possible reduction matrix. * @param Mg a possible reduction matrix. * @return true, if Mg and Mf are reduction matrices, else false. */ public boolean isReductionMatrix(List> F, List> G, List>> Mf, List>> Mg) { final int flen; if (F == null) { flen = -1; } else { flen = F.size(); } // no more check G and Mg: G * Mg[i] == 0 // i < #F: check F and Mg: Mg[i] * F == G[i] // i >= #F: check G and Mg: Mg[i] * G == G[i] int k = 0; for (List> row : Mg) { boolean t; if (k < flen) { t = red.isReductionNF(row, F, G.get(k), null); //logger.info("{} isReductionMatrix row, F, G(k), k = {}, {}, {}, {}", t, row, F, G.get(k), k); } else { t = red.isReductionNF(row, G, G.get(k), null); //logger.info("{} isReductionMatrix row, G, G(k), k = {}, {}, {}, {}", t, row, G, G.get(k), k); } if (!t) { logger.warn("isReductionMatrix row, F, G, k = {}, {}, {}, {}", row, F, G, k); return false; } k++; } // check G and Mf: Mf[i] * G == F[i] k = 0; for (List> row : Mf) { boolean t = red.isReductionNF(row, G, F.get(k), null); //logger.info("{} isMinReductionMatrix row, G, F(k), k = {}, {}, {}, {}", t, row, G, F.get(k), k); if (!t) { logger.warn("G isReductionMatrix row, G, F(k), k = {}, {}, {}, {}", row, G, F.get(k), k); return false; } k++; } return true; } /** * Test if minimal reduction matrix. * @param F a polynomial list. * @param G a minimal Groebner base of F. * @param Mf a possible reduction matrix. * @param Mg a possible reduction matrix. * @return true, if Mg and Mf are reduction matrices, else false. */ public boolean isMinReductionMatrix(List> F, List> G, List>> Mf, List>> Mg) { if (F == null || G == null) { throw new IllegalArgumentException("F or G may not be null or empty"); } //final int flen = F.size(); // no more check G and Mg: G * Mg[i] == 0 // check F and Mg: Mg[i] * F == G[i] int k = 0; for (List> row : Mg) { boolean t = red.isReductionNF(row, F, G.get(k), null); //logger.info("{} isMinReductionMatrix row, F, G(k), k = {}, {}, {}, {}", t, row, F, G.get(k), k); if (!t) { logger.warn("isMinReductionMatrix row, F, G, k = {}, {}, {}, {}", row, F, G, k); return false; } k++; } // check G and Mf: Mf[i] * G == F[i] k = 0; for (List> row : Mf) { boolean t = red.isReductionNF(row, G, F.get(k), null); //logger.info("{} isMinReductionMatrix row, G, F(k), k = {}, {}, {}, {}", t, row, G, F.get(k), k); if (!t) { logger.warn("G isMinReductionMatrix row, G, F(k), k = {}, {}, {}, {}", row, G, F.get(k), k); return false; } k++; } return true; } /** * Normalize M. Scale and shift right triangular matrix (new G elements) to * left and make all right column elements zero. Then truncate all rows to * the size of F. * @param flen length of rows. * @param M a reduction matrix. * @return normalized M. */ public List>> normalizeMatrix(int flen, List>> M) { if (M == null) { return M; } if (M.size() == 0) { return M; } List>> N = new ArrayList>>(); List>> K = new ArrayList>>(); int mlen = M.get(M.size() - 1).size(); // longest row //System.out.println("norm M pre reduc = " + M); // pad / extend rows for (List> row : M) { List> nrow = blas.genVector(mlen, null, row); N.add(nrow); } // System.out.println("norm N fill = " + N); // make zero right columns int k = flen; // right part for (int i = 0; i < N.size(); i++) { // 0 List> row = N.get(i); if (debug) { logger.info("row = {}", row); } K.add(row); if (i < flen) { // skip identity part?? continue; // what with -1 ? } //System.out.println("norm i = " + i + ", row = " + row); for (int j = i + 1; j < N.size(); j++) { List> nrow = N.get(j); //System.out.println("nrow j = " + j + ", nrow = " + nrow); if (k < nrow.size()) { // always true GenPolynomial a = nrow.get(k); // right matrix k ~ flen+i //System.out.println("k, a = " + k + ", " + a); if (a != null && !a.isZERO()) { List> xrow = blas.scalarProduct(a, row); xrow = blas.vectorAdd(xrow, nrow); //System.out.println("xrow = " + xrow); N.set(j, xrow); } } } k++; } //System.out.println("norm K reduc = " + K); // truncate N.clear(); for (List> row : K) { List> tr = blas.genVector(flen, null, row); N.add(tr); } K = N; //System.out.println("norm K trunc = " + K); return K; } /** * Minimal extended groebner basis. * @param flen length of rows. * @param Gp a Groebner base. * @param M a reduction matrix, is modified. * @return a (partially) reduced Groebner base of Gp in a (fake) container. */ public ExtendedGB minimalExtendedGB(int flen, List> Gp, List>> M) { if (Gp == null) { return null; //new ExtendedGB(null,Gp,null,M); } //if (Gp.size() <= 1) { // return new ExtendedGB(null, Gp, null, M); //} List> G, F; G = new ArrayList>(Gp); F = new ArrayList>(Gp.size()); List>> Mg, Mf; Mg = new ArrayList>>(M.size()); Mf = new ArrayList>>(M.size()); for (List> r : M) { // must be copied also List> row = new ArrayList>(r); Mg.add(row); } GenPolynomial a, p; ExpVector e, f; boolean mt; ListIterator> it; ArrayList ix = new ArrayList(); //??ArrayList jx = new ArrayList(); int k = 0; //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() ); while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } //System.out.println("k, mt = " + k + ", " + mt); if (!mt) { F.add(a); ix.add(k); //} else { // drop polynomial and corresponding row and column // F.add( a.ring.getZERO() ); //??jx.add(k); } k++; } if (debug) { logger.debug("ix, #M = {}, {}", ix, Mg.size()); //??, jx); } int fix = -1; // copied polys // copy Mg to Mf as indicated by ix for (int i = 0; i < ix.size(); i++) { int u = ix.get(i); if (u >= flen && fix == -1) { fix = Mf.size(); } //System.out.println("copy u, fix = " + u + ", " + fix); if (u >= 0) { List> row = Mg.get(u); Mf.add(row); } } if (F.size() <= 1 || fix == -1) { return new ExtendedGB(null, F, null, Mf); } // must return, since extended normalform has not correct order of polys /* G = F; F = new ArrayList>( G.size() ); List> temp; k = 0; final int len = G.size(); while ( G.size() > 0 ) { a = G.remove(0); if ( k >= fix ) { // dont touch copied polys row = Mf.get( k ); //System.out.println("doing k = " + k + ", " + a); // must keep order, but removed polys missing temp = new ArrayList>( len ); temp.addAll( F ); temp.add( a.ring.getZERO() ); // ?? temp.addAll( G ); //System.out.println("row before = " + row); a = red.normalform( row, temp, a ); //System.out.println("row after = " + row); } F.add( a ); k++; } // does Mf need renormalization? */ return new ExtendedGB(null, F, null, Mf); } /** * Univariate head term degrees. * @param A list of polynomials. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees(List> A) { List ud = new ArrayList(); if (A == null || A.size() == 0) { return ud; } GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 0) { return ud; } //int uht = 0; Map v = new TreeMap(); // for non reduced GBs for (GenPolynomial p : A) { ExpVector e = p.leadingExpVector(); if (e == null) { continue; } int[] u = e.dependencyOnVariables(); if (u == null) { continue; } if (u.length == 1) { //uht++; Long d = v.get(u[0]); if (d == null) { v.put(u[0], e.getVal(u[0])); } } } for (int i = 0; i < pfac.nvar; i++) { Long d = v.get(i); ud.add(d); } //Collections.reverse(ud); return ud; } /** * Construct univariate polynomial of minimal degree in variable i of a zero * dimensional ideal(G). * @param i variable index. * @param G list of polynomials, a monic reduced Gröbner base of a zero * dimensional ideal. * @return univariate polynomial of minimal degree in variable i in ideal(G) */ public GenPolynomial constructUnivariate(int i, List> G) { if (G == null || G.size() == 0) { throw new IllegalArgumentException("G may not be null or empty"); } //logger.info("G in = {}", G); //Collections.reverse(G); // test G = OrderedPolynomialList. sort(G); // better performance List ud = univariateDegrees(G); if (ud.size() <= i) { //logger.info("univ pol, ud = {}", ud); throw new IllegalArgumentException("ideal(G) not zero dimensional " + ud); } int ll = 0; Long di = ud.get(i); if (di != null) { ll = (int) (long) di; } else { throw new IllegalArgumentException("ideal(G) not zero dimensional"); } long vsdim = 1; for (Long d : ud) { if (d != null) { vsdim *= d; } } logger.info("univariate construction, deg = {}, vsdim = {}", ll, vsdim); GenPolynomialRing pfac = G.get(0).ring; RingFactory cfac = pfac.coFac; String var = pfac.getVars()[pfac.nvar - 1 - i]; GenPolynomialRing ufac = new GenPolynomialRing(cfac, 1, new TermOrder(TermOrder.INVLEX), new String[] { var }); GenPolynomialRing cpfac = new GenPolynomialRing(cfac, ll, new TermOrder(TermOrder.INVLEX)); GenPolynomialRing> rfac = new GenPolynomialRing>(cpfac, pfac); GenPolynomial> P = rfac.getZERO(); for (int k = 0; k < ll; k++) { GenPolynomial> Pp = rfac.univariate(i, k); GenPolynomial cp = cpfac.univariate(cpfac.nvar - 1 - k); Pp = Pp.multiply(cp); P = P.sum(Pp); } if (debug) { logger.info("univariate construction, P = {}", P); logger.info("univariate construction, deg_*(G) = {}", ud); //throw new RuntimeException("check"); } GenPolynomial X; GenPolynomial XP; // solve system of linear equations for the coefficients of the univariate polynomial List> ls; int z = -1; do { //System.out.println("ll = " + ll); GenPolynomial> Pp = rfac.univariate(i, ll); GenPolynomial cp = cpfac.univariate(cpfac.nvar - 1 - ll); Pp = Pp.multiply(cp); P = P.sum(Pp); X = pfac.univariate(i, ll); XP = red.normalform(G, X); if (debug) { logger.info("XP = {}", XP); } GenPolynomial> XPp = PolyUtil. toRecursive(rfac, XP); GenPolynomial> XPs = XPp.sum(P); ls = new ArrayList>(XPs.getMap().values()); //System.out.println("ls,1 = " + ls); ls = red.irreducibleSet(ls); z = commonZeroTest(ls); if (z != 0) { ll++; if (ll > vsdim) { logger.info("univariate construction, P = {}", P); logger.info("univariate construction, nf(P) = {}", XP); logger.info("G = {}", G); throw new ArithmeticException( "univariate polynomial degree greater than vector space dimansion"); } cpfac = cpfac.extend(1); rfac = new GenPolynomialRing>(cpfac, pfac); P = PolyUtil. extendCoefficients(rfac, P, 0, 0L); XPp = PolyUtil. extendCoefficients(rfac, XPp, 0, 1L); P = P.sum(XPp); } } while (z != 0); // && ll <= 5 && !XP.isZERO() // construct result polynomial GenPolynomial pol = ufac.univariate(0, ll); for (GenPolynomial pc : ls) { ExpVector e = pc.leadingExpVector(); if (e == null) { continue; } int[] v = e.dependencyOnVariables(); if (v == null || v.length == 0) { continue; } int vi = v[0]; C lc = pc.leadingBaseCoefficient(); C tc = pc.trailingBaseCoefficient(); tc = tc.negate(); if (!lc.isONE()) { tc = tc.divide(lc); } GenPolynomial pi = ufac.univariate(0, ll - 1 - vi); pi = pi.multiply(tc); pol = pol.sum(pi); } if (logger.isInfoEnabled()) { logger.info("univariate construction, pol = {}", pol); } return pol; } /** * Cleanup and terminate ThreadPool. */ public void terminate() { logger.info("terminate not implemented"); //throw new RuntimeException("get a stack trace"); } /** * Cancel ThreadPool. */ public int cancel() { logger.info("cancel not implemented"); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseArriSigSeqIter.java000066400000000000000000000150251445075545500262310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Groebner Base Arri signature based sequential iterative algorithm. Implements * Groebner bases. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseArriSigSeqIter> extends GroebnerBaseSigSeqIter { private static final Logger logger = LogManager.getLogger(GroebnerBaseArriSigSeqIter.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseArriSigSeqIter() { this(new SigReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseArriSigSeqIter(SigReductionSeq red) { super(red); } /** * S-Polynomial. * @param P pair. * @return spol(A,B) the S-polynomial of the pair (A,B). */ @Override GenPolynomial SPolynomial(SigPair P) { return P.pi.poly; } /** * Pair with signature. * @param A polynomial with signature. * @param B polynomial with signature. * @param G polynomial ith signature list. * @return signature pair according to algorithm. */ @Override SigPair newPair(SigPoly A, SigPoly B, List> G) { ExpVector e = A.poly.leadingExpVector().lcm(B.poly.leadingExpVector()) .subtract(A.poly.leadingExpVector()); GenPolynomial sp = SPolynomial(A, B); GenPolynomial sig = sp.ring.valueOf(e); return new SigPair(sig, new SigPoly(sig, sp), B, G); } /** * Pair with signature. * @param s signature for pair. * @param A polynomial with signature. * @param B polynomial with signature. * @param G polynomial ith signature list. * @return signature pair according to algorithm. */ @Override SigPair newPair(GenPolynomial s, SigPoly A, SigPoly B, List> G) { GenPolynomial sp = SPolynomial(A, B); return new SigPair(s, new SigPoly(s, sp), B, G); } /** * Top normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ @Override SigPoly sigNormalform(List> F, List> G, SigPoly A) { return sred.sigSemiNormalform(F, G, A); } /** * Prune total pair list P. * @param P pair list. * @param syz list of exponent vectors representing syzygies. * @return updated pair list. */ @Override List> pruneP(List> P, List syz) { List> res = new ArrayList>(P.size()); for (SigPair p : P) { ExpVector f = p.sigma.leadingExpVector(); if (f == null) { continue; } boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } res.add(p); } return res; } /** * Prune pair list of degree d. * @param S pair list. * @param syz list of exponent vectors representing syzygies. * @param done list of treated polynomials. * @param G polynomial with signature list. * @return updated pair list. */ @Override List> pruneS(List> S, List syz, List> done, List> G) { List> res = new ArrayList>(S.size()); for (SigPair p : S) { ExpVector f = p.sigma.leadingExpVector(); if (f == null) { continue; } boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } div = false; for (SigPair q : S) { if (p.sigma.equals(q.sigma)) { if (p.pi.poly.compareTo(q.pi.poly) > 0) { div = true; break; } } } if (div) { continue; } div = false; for (SigPoly q : done) { ExpVector e = q.sigma.leadingExpVector(); if (e == null) { continue; } if (f.multipleOf(e)) { ExpVector g = f.subtract(e); ExpVector f1 = g.sum(q.poly.leadingExpVector()); ExpVector e1 = p.pi.poly.leadingExpVector(); if (e1 == null) { continue; } if (f1.compareTo(e1) < 0) { div = true; break; } } } if (div) { continue; } res.add(p); logger.debug("added p = {}", p.sigma); } return res; } /** * Initializes syzygy list. * @param F polynomial list. * @param G polynomial with signature list. * @return list of exponent vectors representing syzygies. */ @Override List initializeSyz(List> F, List> G) { List P = new ArrayList(); for (GenPolynomial p : F) { if (p.isZERO()) { continue; } P.add(p.leadingExpVector()); } return P; } /** * Update syzygy list. * @param syz list of exponent vectors representing syzygies. * @param r polynomial. Note: szy is modified to represent updated * list of exponent vectors. */ @Override void updateSyz(List syz, SigPoly r) { if (r.poly.isZERO() && !r.sigma.isZERO()) { syz.add(r.sigma.leadingExpVector()); } return; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseDistributedEC.java000066400000000000000000000720761445075545500260770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.ChannelFactory; import edu.jas.util.DistHashTable; import edu.jas.util.DistHashTableServer; import edu.jas.util.DistThreadPool; import edu.jas.util.RemoteExecutable; import edu.jas.util.SocketChannel; import edu.jas.util.Terminator; /** * Groebner Base distributed algorithm. Implements a distributed memory parallel * version of Groebner bases with executable channels. Using pairlist class, * distributed tasks do reduction, one communication channel per task. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedEC> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedEC.class); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ protected static final int DEFAULT_THREADS = 2; /** * Pool of threads to use. Note: No ComputerThreads for one node * tests */ protected transient final ExecutorService pool; /** * Default server port. */ protected static final int DEFAULT_PORT = 55711; /** * Default distributed hash table server port. */ protected final int DHT_PORT; /** * Server port to use. */ protected final int port; /** * machine file to use. */ protected final String mfile; /** * Distributed thread pool to use. */ private final transient DistThreadPool dtp; /** * Distributed hash table server to use. */ private final transient DistHashTableServer dhts; /** * Constructor. * @param mfile name of the machine file. */ public GroebnerBaseDistributedEC(String mfile) { this(mfile, DEFAULT_THREADS, DEFAULT_PORT); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. */ public GroebnerBaseDistributedEC(String mfile, int threads) { this(mfile, threads, Executors.newFixedThreadPool(threads), DEFAULT_PORT); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param port server port to use. */ public GroebnerBaseDistributedEC(String mfile, int threads, int port) { this(mfile, threads, Executors.newFixedThreadPool(threads), port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param port server port to use. */ public GroebnerBaseDistributedEC(String mfile, int threads, ExecutorService pool, int port) { this(mfile, threads, pool, new OrderedPairlist(), port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param pl pair selection strategy * @param port server port to use. */ public GroebnerBaseDistributedEC(String mfile, int threads, PairList pl, int port) { this(mfile, threads, Executors.newFixedThreadPool(threads), pl, port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param pl pair selection strategy * @param port server port to use. */ public GroebnerBaseDistributedEC(String mfile, int threads, ExecutorService pool, PairList pl, int port) { super(new ReductionPar(), pl); this.threads = threads; if (mfile == null || mfile.length() == 0) { this.mfile = "../util/machines"; // contains localhost } else { this.mfile = mfile; } if (threads < 1) { threads = 1; } if (pool == null) { pool = Executors.newFixedThreadPool(threads); } this.pool = pool; this.port = port; logger.info("machine file {}, port = {}", mfile, port); this.dtp = new DistThreadPool(this.threads, this.mfile); logger.info("running {}", dtp); this.DHT_PORT = this.dtp.getEC().getMasterPort() + 100; this.dhts = new DistHashTableServer(this.DHT_PORT); this.dhts.init(); logger.info("running {}", dhts); } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { terminate(true); } /** * Terminates the distributed thread pools. * @param shutDown true, if shut-down of the remote executable servers is * requested, false, if remote executable servers stay alive. */ public void terminate(boolean shutDown) { pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("{}", pool); dtp.terminate(shutDown); logger.info("dhts.terminate()"); dhts.terminate(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ public List> GB(int modv, List> F) { List> Fp = normalizeZerosOnes(F); Fp = PolyUtil. monic(Fp); if (Fp.size() <= 1) { return Fp; } if (!Fp.get(0).ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } String master = dtp.getEC().getMasterHost(); //int port = dtp.getEC().getMasterPort(); // wrong port GBExerClient gbc = new GBExerClient(master, port, DHT_PORT); for (int i = 0; i < threads; i++) { // schedule remote clients dtp.addJob(gbc); } // run master List> G = GBMaster(modv, Fp); return G; } /** * Distributed Groebner base. * @param modv number of module variables. * @param F non empty monic polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ List> GBMaster(int modv, List> F) { ChannelFactory cf = new ChannelFactory(port); cf.init(); logger.info("GBMaster on {}", cf); List> G = F; if (G.isEmpty()) { throw new IllegalArgumentException("empty polynomial list not allowed"); } GenPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(G); /* GenPolynomial p; List> G = new ArrayList>(); PairList pairlist = null; boolean oneInGB = false; int l = F.size(); int unused; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; G.clear(); G.add(p); //return G; must signal termination to others } if (!oneInGB) { G.add(p); } if (pairlist == null) { //pairlist = new OrderedPairlist(modv, p.ring); pairlist = strategy.create(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { l--; } } logger.info("start {}", pairlist); //if (l <= 1) { //return G; must signal termination to others //} */ logger.debug("looking for clients"); DistHashTable> theList = new DistHashTable>( "localhost", DHT_PORT); theList.init(); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { GenPolynomial nn = theList.put(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials {}, nn = {}, al(i) = {}", i, nn, al.get(i)); } } // wait for arrival while (theList.size() < al.size()) { logger.info("#distributed list = {}, #pairlist list = {}", theList.size(), al.size()); @SuppressWarnings("unused") GenPolynomial nn = theList.getWait(al.size() - 1); } Terminator fin = new Terminator(threads); ReducerServerEC R; for (int i = 0; i < threads; i++) { R = new ReducerServerEC(fin, cf, theList, pairlist); pool.execute(R); } logger.debug("main loop waiting"); fin.waitDone(); int ps = theList.size(); logger.debug("#distributed list = {}", ps); // make sure all polynomials arrived: not needed in master G = pairlist.getList(); if (ps != G.size()) { logger.warn("#distributed list = {}, #pairlist list = {}", theList.size(), G.size()); } long time = System.currentTimeMillis(); List> Gp; Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi = {}", time); /* time = System.currentTimeMillis(); G = GroebnerBase.GBmi(G); // sequential time = System.currentTimeMillis() - time; logger.info("sequential gbmi = {}", time); */ G = Gp; logger.debug("cf.terminate()"); cf.terminate(); logger.debug("theList.terminate()"); theList.clear(); theList.terminate(); logger.info("{}", pairlist); return G; } /** * GB distributed client part. * @param host the server runs on. * @param port the server runs. * @param dhtport of the DHT server. * @throws IOException */ public static > void clientPart(String host, int port, int dhtport) throws IOException { ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost cf.init(); logger.info("clientPart connecting to {}, port = {}, dhtport = {}", host, port, dhtport); SocketChannel pairChannel = cf.getChannel(host, port); DistHashTable> theList = new DistHashTable>(host, dhtport); theList.init(); ReducerClientEC R = new ReducerClientEC(pairChannel, theList); logger.info("clientPart running on {}, pairChannel = {}", host, pairChannel); R.run(); pairChannel.close(); //master only: theList.clear(); theList.terminate(); cf.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB @SuppressWarnings("unchecked") MiReducerServerEC[] mirs = (MiReducerServerEC[]) new MiReducerServerEC[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiReducerServerEC(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker threads. * @param coefficient type */ class ReducerServerEC> implements Runnable { private final Terminator pool; private final ChannelFactory cf; private SocketChannel pairChannel; private final DistHashTable> theList; //private List> G; private final PairList pairlist; private static final Logger logger = LogManager.getLogger(ReducerServerEC.class); ReducerServerEC(Terminator fin, ChannelFactory cf, DistHashTable> dl, PairList L) { pool = fin; this.cf = cf; theList = dl; //this.G = G; pairlist = L; } @SuppressWarnings("unchecked") public void run() { logger.info("reducer server running with {}", cf); try { pairChannel = cf.getChannel(); } catch (InterruptedException e) { logger.debug("get pair channel interrupted"); e.printStackTrace(); return; } if (logger.isDebugEnabled()) { logger.debug("pairChannel = {}", pairChannel); } Pair pair; //GenPolynomial pi; //GenPolynomial pj; //GenPolynomial S; GenPolynomial H = null; boolean set = false; boolean goon = true; int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request logger.info("receive request"); Object req = null; try { req = pairChannel.receive(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } //logger.debug("received request, req = {}", req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!set) { pool.beIdle(); set = true; } if (!pool.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 10 == 0) { logger.info("reducer is sleeping, pool = {}", pool); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (Thread.currentThread().isInterrupted()) { goon = false; break; } if (!pairlist.hasNext() && !pool.hasJobs()) { goon = false; break; //continue; //break? } if (set) { set = false; pool.notIdle(); } pair = pairlist.removeNext(); /* * send pair to client, receive H */ logger.debug("send pair = {}", pair); GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); // ,pairlist.size()-1); // size-1 } else { msg = new GBTransportMess(); // not End(); at this time // goon ?= false; } try { pairChannel.send(msg); } catch (IOException e) { e.printStackTrace(); goon = false; break; } logger.debug("#distributed list = {}", theList.size()); Object rh = null; try { rh = pairChannel.receive(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; break; } //logger.debug("received H polynomial"); if (rh == null) { if (pair != null) { pair.setZero(); } } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; H = ((GBTransportMessPoly) rh).pol; if (logger.isDebugEnabled()) { logger.debug("H = {}", H); } if (H == null) { if (pair != null) { pair.setZero(); } } else { if (H.isZERO()) { pair.setZero(); } else { if (H.isONE()) { // pool.allIdle(); polIndex = pairlist.putOne(); theList.putWait(Integer.valueOf(polIndex), H); goon = false; break; } polIndex = pairlist.put(H); // use putWait ? but still not all distributed theList.putWait(Integer.valueOf(polIndex), H); } } } } logger.info("terminated, done {} reductions", red); /* * send end mark to client */ logger.debug("send end"); try { pairChannel.send(new GBTransportMessEnd()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } pool.beIdle(); pairChannel.close(); } } /** * Distributed clients reducing worker threads. */ class ReducerClientEC> implements Runnable { private final SocketChannel pairChannel; private final DistHashTable> theList; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(ReducerClientEC.class); ReducerClientEC(SocketChannel pc, DistHashTable> dl) { pairChannel = pc; theList = dl; red = new ReductionPar(); } public void run() { logger.debug("pairChannel = {} reducer client running", pairChannel); Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.debug("send request = {}", req); H = null; try { pairChannel.send(req); } catch (IOException e) { goon = false; e.printStackTrace(); break; } logger.debug("receive pair, goon = {}", goon); Object pp = null; try { pp = pairChannel.receive(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.debug("received pair = {}", pp); } if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { // obsolete, for tests @SuppressWarnings("unchecked") GBTransportMessPair tmp = (GBTransportMessPair) pp; pair = tmp.pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = {}, pjx = {}", pair.i, pair.j); } } if (pp instanceof GBTransportMessPairIndex) { GBTransportMessPairIndex tmpi = (GBTransportMessPairIndex) pp; pix = tmpi.i; pjx = tmpi.j; psx = tmpi.s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); //logger.info("pix = {}, pjx = {}, psx = {}", pix, pjx, psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //System.out.println("S = " + S); if (S.isZERO()) { // pair.setZero(); does not work in dist } else { if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } } } } else { logger.info("pi = {}, pj = {}, ps = {}", pi, pj, ps); } } // send H or must send null if (logger.isDebugEnabled()) { logger.debug("#distributed list = {}", theList.size()); logger.debug("send H polynomial = {}", H); } try { pairChannel.send(new GBTransportMessPoly(H)); } catch (IOException e) { goon = false; e.printStackTrace(); } } logger.info("terminated, {} reductions, {} polynomials", reduction, theList.size()); pairChannel.close(); } } /** * Distributed server reducing worker threads for minimal GB Not jet distributed * but threaded. */ class MiReducerServerEC> implements Runnable { private final List> G; private GenPolynomial H; private final Semaphore done = new Semaphore(0); private final Reduction red; private static final Logger logger = LogManager.getLogger(MiReducerServerEC.class); MiReducerServerEC(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } /** * Distributed clients reducing worker threads for minimal GB. Not jet used. */ class MiReducerClientEC> implements Runnable { private final List> G; private GenPolynomial H; private final Reduction red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducerClientEC.class); MiReducerClientEC(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException u) { Thread.currentThread().interrupt(); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } /** * Objects of this class are to be send to a ExecutableServer. */ class GBExerClient> implements RemoteExecutable { String host; int port; int dhtport; /** * GBExerClient. * @param host * @param port * @param dhtport */ public GBExerClient(String host, int port, int dhtport) { this.host = host; this.port = port; this.dhtport = dhtport; } /** * run. */ public void run() { //System.out.println("running " + this); try { GroebnerBaseDistributedEC. clientPart(host, port, dhtport); } catch (Exception e) { e.printStackTrace(); } } /** * String representation. */ @Override public String toString() { StringBuffer s = new StringBuffer("GBExerClient("); s.append("host=" + host); s.append(", port=" + port); s.append(", dhtport=" + dhtport); s.append(")"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseDistributedHybridEC.java000066400000000000000000001124371445075545500272350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.ChannelFactory; import edu.jas.util.DistHashTable; import edu.jas.util.DistHashTableServer; import edu.jas.util.DistThreadPool; import edu.jas.util.RemoteExecutable; import edu.jas.util.SocketChannel; import edu.jas.util.TaggedSocketChannel; import edu.jas.util.Terminator; /** * Groebner Base distributed hybrid algorithm. Implements a distributed memory * with multi-core CPUs parallel version of Groebner bases with executable * channels. Using pairlist class, distributed multi-threaded tasks do * reduction, one communication channel per remote node. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseDistributedHybridEC> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseDistributedHybridEC.class); private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ protected static final int DEFAULT_THREADS = 2; /** * Number of threads per node to use. */ protected final int threadsPerNode; /** * Default number of threads per compute node. */ protected static final int DEFAULT_THREADS_PER_NODE = 1; /** * Pool of threads to use. */ //protected final ExecutorService pool; // not for single node tests protected transient final ExecutorService pool; /** * Default server port. */ protected static final int DEFAULT_PORT = 55711; /** * Default distributed hash table server port. */ protected final int DHT_PORT; /** * machine file to use. */ protected final String mfile; /** * Server port to use. */ protected final int port; /** * Distributed thread pool to use. */ private final transient DistThreadPool dtp; /** * Distributed hash table server to use. */ private final transient DistHashTableServer dhts; /** * Message tag for pairs. */ public static final Integer pairTag = Integer.valueOf(1); /** * Message tag for results. */ public static final Integer resultTag = Integer.valueOf(2); /** * Message tag for acknowledgments. */ public static final Integer ackTag = Integer.valueOf(3); /** * Constructor. * @param mfile name of the machine file. */ public GroebnerBaseDistributedHybridEC(String mfile) { this(mfile, DEFAULT_THREADS, DEFAULT_PORT); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads) { this(mfile, threads, Executors.newFixedThreadPool(threads), DEFAULT_PORT); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, int port) { this(mfile, threads, Executors.newFixedThreadPool(threads), port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, int port) { this(mfile, threads, threadsPerNode, Executors.newFixedThreadPool(threads), port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, ExecutorService pool, int port) { this(mfile, threads, DEFAULT_THREADS_PER_NODE, pool, port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pl pair selection strategy * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, PairList pl, int port) { this(mfile, threads, threadsPerNode, Executors.newFixedThreadPool(threads), pl, port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ExecutorService pool, int port) { this(mfile, threads, threadsPerNode, pool, new OrderedPairlist(), port); } /** * Constructor. * @param mfile name of the machine file. * @param threads number of threads to use. * @param threadsPerNode threads per node to use. * @param pool ExecutorService to use. * @param pl pair selection strategy * @param port server port to use. */ public GroebnerBaseDistributedHybridEC(String mfile, int threads, int threadsPerNode, ExecutorService pool, PairList pl, int port) { super(new ReductionPar(), pl); this.threads = threads; if (mfile == null || mfile.length() == 0) { this.mfile = "../util/machines"; // contains localhost } else { this.mfile = mfile; } if (threads < 1) { threads = 1; } this.threadsPerNode = threadsPerNode; if (pool == null) { pool = Executors.newFixedThreadPool(threads); logger.error("pool must not be null: {}", pool); //throw new IllegalArgumentException("pool must not be null"); } this.pool = pool; this.port = port; logger.info("machine file {}, port = {}, pool = {}", mfile, port, pool); this.dtp = new DistThreadPool(this.threads, this.mfile); logger.info("running {}", dtp); this.DHT_PORT = this.dtp.getEC().getMasterPort() + 100; this.dhts = new DistHashTableServer(this.DHT_PORT); this.dhts.init(); logger.info("running {}", dhts); } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { terminate(true); } /** * Terminates the distributed thread pools. * @param shutDown true, if shut-down of the remote executable servers is * requested, false, if remote executable servers stay alive. */ public void terminate(boolean shutDown) { pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info(pool.toString()); dtp.terminate(shutDown); logger.info("dhts.terminate()"); dhts.terminate(); } /** * Distributed Groebner base. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ public List> GB(int modv, List> F) { List> Fp = normalizeZerosOnes(F); Fp = PolyUtil. monic(Fp); if (Fp.size() <= 1) { return Fp; } if (!Fp.get(0).ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } String master = dtp.getEC().getMasterHost(); //int port = dtp.getEC().getMasterPort(); // wrong port GBHybridExerClient gbc = new GBHybridExerClient(master, threadsPerNode, port, DHT_PORT); for (int i = 0; i < threads; i++) { // schedule remote clients dtp.addJob(gbc); } try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // run master List> G = GBMaster(modv, Fp); return G; } /** * Distributed hybrid Groebner base. * @param modv number of module variables. * @param F non empty monic polynomial list without zeros. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ List> GBMaster(int modv, List> F) { long t = System.currentTimeMillis(); ChannelFactory cf = new ChannelFactory(port); cf.init(); List> G = F; if (G.isEmpty()) { throw new IllegalArgumentException("empty polynomial list not allowed"); } GenPolynomialRing ring = G.get(0).ring; PairList pairlist = strategy.create(modv, ring); pairlist.put(G); logger.info("start {}", pairlist); DistHashTable> theList = new DistHashTable>( "localhost", DHT_PORT); theList.init(); List> al = pairlist.getList(); for (int i = 0; i < al.size(); i++) { // no wait required GenPolynomial nn = null; theList.putWait(Integer.valueOf(i), al.get(i)); if (nn != null) { logger.info("double polynomials {}, nn = {}, al(i) = {}", i, nn, al.get(i)); } } Terminator finner = new Terminator(threads * threadsPerNode); HybridReducerServerEC R; logger.info("using pool = {}", pool); for (int i = 0; i < threads; i++) { R = new HybridReducerServerEC(threadsPerNode, finner, cf, theList, pairlist); pool.execute(R); //logger.info("server submitted {}", R); } try { Thread.currentThread().sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("main loop waiting {}", finner); finner.waitDone(); int ps = theList.size(); logger.info("#distributed list = {}", ps); // make sure all polynomials arrived: not needed in master // G = (ArrayList)theList.values(); G = pairlist.getList(); if (ps != G.size()) { logger.info("#distributed list = {}, #pairlist list = {}", theList.size(), G.size()); } for (GenPolynomial q : theList.getValueList()) { if (debug && q != null && !q.isZERO()) { logger.debug("final q = {}", q.leadingExpVector()); } } logger.debug("distributed list end"); long time = System.currentTimeMillis(); List> Gp; Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.debug("parallel gbmi time = {}", time); G = Gp; logger.debug("server cf.terminate()"); cf.terminate(); logger.debug("server theList.terminate() {}", theList.size()); theList.clear(); theList.terminate(); t = System.currentTimeMillis() - t; logger.info("server GB end, time = {} with {}", t, pairlist.toString()); return G; } /** * GB distributed client part. * @param host the server runs on. * @param port the server runs. * @param dhtport of the DHT server. * @throws IOException */ public static > void clientPart(String host, int threadsPerNode, int port, int dhtport) throws IOException { ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost cf.init(); logger.info("clientPart connecting to {}, port = {}, dhtport = {}", host, port, dhtport); SocketChannel channel = cf.getChannel(host, port); TaggedSocketChannel pairChannel = new TaggedSocketChannel(channel); pairChannel.init(); DistHashTable> theList = new DistHashTable>(host, dhtport); theList.init(); ExecutorService pool = Executors.newFixedThreadPool(threadsPerNode); //ThreadPool pool = new ThreadPool(threadsPerNode); logger.info("client using pool = {}", pool); for (int i = 0; i < threadsPerNode; i++) { HybridReducerClientEC Rr = new HybridReducerClientEC(/*threadsPerNode,*/pairChannel, /*i,*/ theList); pool.execute(Rr); } logger.info("clients submitted"); pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } //pool.terminate(); logger.info("client pool.terminate()"); pairChannel.close(); logger.debug("client pairChannel.close()"); //master only: theList.clear(); theList.terminate(); cf.terminate(); logger.info("client cf.terminate()"); channel.close(); logger.info("client channel.close()"); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB @SuppressWarnings("unchecked") MiReducerServer[] mirs = (MiReducerServer[]) new MiReducerServer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiReducerServer(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker proxy threads. * @param coefficient type */ class HybridReducerServerEC> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerServerEC.class); private static final boolean debug = logger.isDebugEnabled(); private final Terminator finner; private final ChannelFactory cf; private TaggedSocketChannel pairChannel; private final DistHashTable> theList; private final PairList pairlist; private final int threadsPerNode; /** * Message tag for pairs. */ public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; /** * Message tag for results. */ public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; /** * Message tag for acknowledgments. */ public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; /** * Constructor. * @param tpn number of threads per node * @param fin terminator * @param cf channel factory * @param dl distributed hash table * @param L ordered pair list */ HybridReducerServerEC(int tpn, Terminator fin, ChannelFactory cf, DistHashTable> dl, PairList L) { threadsPerNode = tpn; finner = fin; this.cf = cf; theList = dl; pairlist = L; //logger.info("reducer server created {}", this); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override public void run() { logger.debug("reducer server running with {}", cf); SocketChannel channel = null; try { channel = cf.getChannel(); pairChannel = new TaggedSocketChannel(channel); pairChannel.init(); } catch (InterruptedException e) { logger.debug("get pair channel interrupted"); e.printStackTrace(); return; } if (logger.isInfoEnabled()) { logger.info("pairChannel = {}", pairChannel); } // record idle remote workers (minus one?) //finner.beIdle(threadsPerNode-1); finner.initIdle(threadsPerNode); AtomicInteger active = new AtomicInteger(0); // start receiver HybridReducerReceiverEC receiver = new HybridReducerReceiverEC(/*threadsPerNode,*/finner, active, pairChannel, theList, pairlist); receiver.start(); Pair pair; //boolean set = false; boolean goon = true; //int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request if thread is reported incactive logger.info("receive request"); Object req = null; try { req = pairChannel.receive(pairTag); } catch (InterruptedException e) { goon = false; //e.printStackTrace(); } catch (IOException e) { goon = false; //e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } logger.info("received request, req = {}", req); if (req == null) { goon = false; break; } if (!(req instanceof GBTransportMessReq)) { goon = false; break; } // find pair and manage termination status logger.debug("find pair"); while (!pairlist.hasNext()) { // wait if (!finner.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 3 == 0) { logger.info("waiting for reducers, remaining = {}", finner); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (Thread.currentThread().isInterrupted()) { goon = false; break; } if (!pairlist.hasNext() && !finner.hasJobs()) { logger.info("termination detection: no pairs and no jobs left"); goon = false; break; //continue; //break? } finner.notIdle(); // before pairlist get!! pair = pairlist.removeNext(); // send pair to client, even if null if (logger.isInfoEnabled()) { logger.info("active count = {}", active.get()); logger.info("send pair = {}", pair); } GBTransportMess msg = null; if (pair != null) { msg = new GBTransportMessPairIndex(pair); //,pairlist.size()-1); // size-1 } else { msg = new GBTransportMess(); // not End(); at this time // goon ?= false; } try { red++; pairChannel.send(pairTag, msg); @SuppressWarnings("unused") int a = active.getAndIncrement(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } //logger.debug("#distributed list = {}", theList.size()); } logger.info("terminated, send {} reduction pairs", red); /* * send end mark to clients */ logger.debug("send end"); try { for (int i = 0; i < threadsPerNode; i++) { // -1 //do not wait: Object rq = pairChannel.receive(pairTag); pairChannel.send(pairTag, new GBTransportMessEnd()); } // send also end to receiver pairChannel.send(resultTag, new GBTransportMessEnd()); //beware of race condition } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } receiver.terminate(); int d = active.get(); if (d > 0) { logger.info("remaining active tasks = {}", d); } //logger.info("terminated, send {} reduction pairs", red); pairChannel.close(); logger.debug("redServ pairChannel.close()"); finner.release(); channel.close(); logger.info("redServ channel.close()"); } } /** * Distributed server receiving worker thread. * @param coefficient type */ class HybridReducerReceiverEC> extends Thread { private static final Logger logger = LogManager.getLogger(HybridReducerReceiverEC.class); private static final boolean debug = logger.isDebugEnabled(); private final DistHashTable> theList; private final PairList pairlist; private final TaggedSocketChannel pairChannel; private final Terminator finner; //private final int threadsPerNode; private final AtomicInteger active; private volatile boolean goon; /** * Message tag for pairs. */ public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; /** * Message tag for results. */ public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; /** * Message tag for acknowledgments. */ public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; /** * Constructor. * @param fin terminator * @param a active remote tasks count * @param pc tagged socket channel * @param dl distributed hash table * @param L ordered pair list */ //param tpn number of threads per node HybridReducerReceiverEC(/*int tpn,*/Terminator fin, AtomicInteger a, TaggedSocketChannel pc, DistHashTable> dl, PairList L) { active = a; //threadsPerNode = tpn; finner = fin; pairChannel = pc; theList = dl; pairlist = L; goon = true; //logger.info("reducer server created {}", this); } /** * Work loop. * @see java.lang.Thread#run() */ @Override public void run() { //Pair pair = null; GenPolynomial H = null; int red = 0; int polIndex = -1; //Integer senderId; // obsolete // while more requests while (goon) { // receive request logger.info("receive result"); //senderId = null; Object rh = null; try { rh = pairChannel.receive(resultTag); @SuppressWarnings("unused") int i = active.getAndDecrement(); } catch (InterruptedException e) { goon = false; //e.printStackTrace(); //?? finner.initIdle(1); break; } catch (IOException e) { //e.printStackTrace(); goon = false; //finner.initIdle(1); break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; finner.initIdle(1); break; } logger.info("received H polynomial {}", rh); if (rh == null) { if (this.isInterrupted()) { goon = false; finner.initIdle(1); break; } //finner.initIdle(1); } else if (rh instanceof GBTransportMessEnd) { // should only happen from server logger.info("received GBTransportMessEnd"); goon = false; //?? finner.initIdle(1); break; } else if (rh instanceof GBTransportMessPoly) { // update pair list red++; @SuppressWarnings("unchecked") GBTransportMessPoly mpi = (GBTransportMessPoly) rh; H = mpi.pol; //senderId = mpi.threadId; if (H != null) { if (logger.isInfoEnabled()) { logger.info("H = {}", H.leadingExpVector()); } if (!H.isZERO()) { if (H.isONE()) { // finner.allIdle(); polIndex = pairlist.putOne(); theList.putWait(Integer.valueOf(polIndex), H); //goon = false; must wait for other clients //finner.initIdle(1); //break; } else { polIndex = pairlist.put(H); // use putWait ? but still not all distributed //GenPolynomial nn = theList.putWait(Integer.valueOf(polIndex), H); } } } } // only after recording in pairlist ! finner.initIdle(1); try { pairChannel.send(ackTag, new GBTransportMess()); logger.debug("send acknowledgement"); } catch (IOException e) { e.printStackTrace(); goon = false; break; } } // end while goon = false; logger.info("terminated, received {} reductions", red); } /** * Terminate. */ public void terminate() { goon = false; //this.interrupt(); try { this.join(); } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); } logger.debug("HybridReducerReceiver terminated"); } } /** * Distributed clients reducing worker threads. */ class HybridReducerClientEC> implements Runnable { private static final Logger logger = LogManager.getLogger(HybridReducerClientEC.class); private static final boolean debug = logger.isDebugEnabled(); private final TaggedSocketChannel pairChannel; private final DistHashTable> theList; private final ReductionPar red; //private final int threadsPerNode; /* * Identification number for this thread. */ //public final Integer threadId; // obsolete /** * Message tag for pairs. */ public final Integer pairTag = GroebnerBaseDistributedHybridEC.pairTag; /** * Message tag for results. */ public final Integer resultTag = GroebnerBaseDistributedHybridEC.resultTag; /** * Message tag for acknowledgments. */ public final Integer ackTag = GroebnerBaseDistributedHybridEC.ackTag; /** * Constructor. * @param tc tagged socket channel * @param dl distributed hash table */ //param tpn number of threads per node //param tid thread identification HybridReducerClientEC(/*int tpn,*/TaggedSocketChannel tc, /*Integer tid,*/ DistHashTable> dl) { //threadsPerNode = tpn; pairChannel = tc; //threadId = 100 + tid; // keep distinct from other tags theList = dl; red = new ReductionPar(); } /** * Work loop. * @see java.lang.Runnable#run() */ @Override public void run() { if (logger.isInfoEnabled()) { logger.info("pairChannel = {} reducer client running", pairChannel); } Pair pair = null; GenPolynomial pi, pj, ps; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; boolean doEnd = true; int reduction = 0; //int sleeps = 0; Integer pix, pjx, psx; while (goon) { /* protocol: * request pair, process pair, send result, receive acknowledgment */ // pair = (Pair) pairlist.removeNext(); Object req = new GBTransportMessReq(); logger.info("send request"); try { pairChannel.send(pairTag, req); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } logger.info("receive pair, IOexception "); break; } logger.info("receive on pairTag, goon = {}", goon); doEnd = true; Object pp = null; try { pp = pairChannel.receive(pairTag); } catch (InterruptedException e) { goon = false; e.printStackTrace(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (logger.isInfoEnabled()) { logger.info("received pair = {}", pp); } H = null; if (pp == null) { // should not happen continue; } if (pp instanceof GBTransportMessEnd) { goon = false; //doEnd = false; continue; } if (pp instanceof GBTransportMessPair || pp instanceof GBTransportMessPairIndex) { pi = pj = ps = null; if (pp instanceof GBTransportMessPair) { // obsolet, for tests @SuppressWarnings("unchecked") GBTransportMessPair tmp = (GBTransportMessPair) pp; pair = tmp.pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = {}, pjx = {}", pair.i, pair.j); } } if (pp instanceof GBTransportMessPairIndex) { GBTransportMessPairIndex tmpi = (GBTransportMessPairIndex) pp; pix = tmpi.i; pjx = tmpi.j; psx = tmpi.s; pi = theList.getWait(pix); pj = theList.getWait(pjx); ps = theList.getWait(psx); //logger.info("pix = {}, pjx = {}, psx = {}", pix, pjx, psx); } if (pi != null && pj != null) { S = red.SPolynomial(pi, pj); //logger.info("ht(S) = {}", S.leadingExpVector()); if (S.isZERO()) { // pair.setZero(); does not work in dist } else { if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(theList, S); //logger.info("ht(H) = {}", H.leadingExpVector()); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isInfoEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } } } } else { logger.info("pi = {}, pj = {}, ps = {}", pi, pj, ps); } } if (pp instanceof GBTransportMess) { logger.debug("null pair results in null H poly"); } // send H or must send null, if not at end if (logger.isDebugEnabled()) { logger.debug("#distributed list = {}", theList.size()); logger.debug("send H polynomial = {}", H); } try { pairChannel.send(resultTag, new GBTransportMessPoly(H)); //,threadId)); doEnd = false; } catch (IOException e) { goon = false; e.printStackTrace(); } //logger.info("done send poly message of {}", pp); try { //pp = pairChannel.receive(threadId); pp = pairChannel.receive(ackTag); } catch (InterruptedException e) { goon = false; e.printStackTrace(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (!(pp instanceof GBTransportMess)) { logger.error("invalid acknowledgement {}", pp); } logger.info("received acknowledgment "); } logger.info("terminated, {} reductions, {} polynomials", reduction, theList.size()); if (doEnd) { try { pairChannel.send(resultTag, new GBTransportMessEnd()); } catch (IOException e) { //e.printStackTrace(); } logger.debug("terminated, send done"); } } } /** * Objects of this class are to be send to a ExecutableServer. */ class GBHybridExerClient> implements RemoteExecutable { String host; int port; int dhtport; int threadsPerNode; /** * GBHybridExerClient. * @param host * @param port * @param dhtport */ public GBHybridExerClient(String host, int threadsPerNode, int port, int dhtport) { this.host = host; this.threadsPerNode = threadsPerNode; this.port = port; this.dhtport = dhtport; } /** * run. */ public void run() { try { GroebnerBaseDistributedHybridEC. clientPart(host, threadsPerNode, port, dhtport); } catch (Exception e) { e.printStackTrace(); } } /** * String representation. */ @Override public String toString() { StringBuffer s = new StringBuffer("GBHybridExerClient("); s.append("host=" + host); s.append(", threadsPerNode=" + threadsPerNode); s.append(", port=" + port); s.append(", dhtport=" + dhtport); s.append(")"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseF5zSigSeqIter.java000066400000000000000000000121751445075545500260030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Groebner Base F5z signature based sequential iterative algorithm. Implements * Groebner bases. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseF5zSigSeqIter> extends GroebnerBaseSigSeqIter { private static final Logger logger = LogManager.getLogger(GroebnerBaseF5zSigSeqIter.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseF5zSigSeqIter() { this(new SigReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseF5zSigSeqIter(SigReductionSeq red) { super(red); } /** * Top normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ @Override SigPoly sigNormalform(List> F, List> G, SigPoly A) { return sred.sigSemiNormalform(F, G, A); } /** * Prune total pair list P. * @param P pair list. * @param syz list of exponent vectors representing syzygies. * @return updated pair list. Note: stores polynomials not only * indices. */ @Override List> pruneP(List> P, List syz) { List> res = new ArrayList>(P.size()); for (SigPair p : P) { ExpVector f = p.sigma.leadingExpVector(); if (f == null) { continue; } boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } res.add(p); } return res; } /** * Prune pair list of degree d. * @param S pair list. * @param syz list of exponent vectors representing syzygies. * @param done list of treated polynomials. * @param G polynomial with signature list. * @return updated pair list. */ @Override List> pruneS(List> S, List syz, List> done, List> G) { List> res = new ArrayList>(S.size()); for (SigPair p : S) { if (p.sigma.isZERO()) { continue; } ExpVector f = p.sigma.leadingExpVector(); boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } if (p.pi.sigma.isZERO()) { logger.info("pruneS, p.pi.sigma = 0"); res.add(p); continue; } ExpVector fi = p.pi.poly.leadingExpVector(); ExpVector fj = p.pj.poly.leadingExpVector(); ExpVector fu = fi.lcm(fj).subtract(fi); f = p.pi.sigma.leadingExpVector(); fu = fu.sum(f); div = false; for (SigPoly q : done) { ExpVector e = q.sigma.leadingExpVector(); if (e == null) { continue; } if (fu.multipleOf(e)) { if (q.sigma.compareTo(p.pi.sigma) > 0) { div = true; break; } } } if (div) { continue; } res.add(p); logger.debug("added p = {}", p.sigma); } return res; } /** * Initializes syzygy list. * @param F polynomial list. * @param G polynomial with signature list. * @return list of exponent vectors representing syzygies. */ @Override List initializeSyz(List> F, List> G) { List P = new ArrayList(); for (GenPolynomial p : F) { if (p.isZERO()) { continue; } P.add(p.leadingExpVector()); } return P; } /** * Update syzygy list. * @param syz list of exponent vectors representing syzygies. * @param r polynomial. Note: szy is modified to represent updated * list of exponent vectors. */ @Override void updateSyz(List syz, SigPoly r) { if (r.poly.isZERO() && !r.sigma.isZERO()) { //logger.info("update_syz, sigma = {}", r.sigma); syz.add(r.sigma.leadingExpVector()); } return; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseGGVSigSeqIter.java000066400000000000000000000113011445075545500257500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Groebner Base GGV signature based sequential iterative algorithm. Implements * Groebner bases. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseGGVSigSeqIter> extends GroebnerBaseSigSeqIter { private static final Logger logger = LogManager.getLogger(GroebnerBaseGGVSigSeqIter.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseGGVSigSeqIter() { this(new SigReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseGGVSigSeqIter(SigReductionSeq red) { super(red); } /** * S-Polynomial. * @param A polynomial. * @param B polynomial. * @return spol(A,B) the S-polynomial of A and B. */ @Override GenPolynomial SPolynomial(SigPoly A, SigPoly B) { return sred.SPolynomialHalf(A, B); } /** * Prune total pair list P. * @param P pair list. * @param syz list of exponent vectors representing syzygies. * @return updated pair list. */ @Override List> pruneP(List> P, List syz) { List> res = new ArrayList>(P.size()); for (SigPair p : P) { ExpVector f = p.sigma.leadingExpVector(); if (f == null) { continue; } boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } res.add(p); } return res; } /** * Prune pair list of degree d. * @param S pair list. * @param syz list of exponent vectors representing syzygies. * @param done list of treated polynomials. * @param G polynomial with signature list. * @return updated pair list. */ @Override List> pruneS(List> S, List syz, List> done, List> G) { List> res = new ArrayList>(S.size()); for (SigPair p : S) { ExpVector f = p.sigma.leadingExpVector(); if (f == null) { continue; } boolean div = false; for (ExpVector e : syz) { if (f.multipleOf(e)) { div = true; break; } } if (div) { continue; } div = false; for (SigPair q : S) { if (f.equals(q.sigma.leadingExpVector())) { if (p.pi.poly.compareTo(q.pi.poly) < 0) { div = true; break; } } } if (div) { continue; } div = false; for (SigPair q : res) { if (f.equals(q.sigma.leadingExpVector())) { div = true; break; } } if (div) { continue; } res.add(p); logger.debug("added p = {}", p.sigma); } return res; } /** * Initializes syzygy list. * @param F polynomial list. * @param G polynomial with signature list. * @return list of exponent vectors representing syzygies. */ @Override List initializeSyz(List> F, List> G) { List P = new ArrayList(); for (GenPolynomial p : F) { if (p.isZERO()) { continue; } P.add(p.leadingExpVector()); } return P; } /** * Update syzygy list. * @param syz list of exponent vectors representing syzygies. * @param r polynomial. Note: szy is modified to represent updated * list of exponent vectors. */ @Override void updateSyz(List syz, SigPoly r) { if (r.poly.isZERO() && !r.sigma.isZERO()) { syz.add(r.sigma.leadingExpVector()); } return; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseParIter.java000066400000000000000000000355641445075545500247540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.Terminator; /** * Groebner Base parallel iterative algorithm. Implements a shared memory * parallel version of Groebner bases. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseParIter> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseParIter.class); private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Constructor. */ public GroebnerBaseParIter() { this(2); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseParIter(int threads) { this(threads, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param red parallelism aware reduction engine */ public GroebnerBaseParIter(int threads, Reduction red) { this(threads, Executors.newFixedThreadPool(threads), red); } /** * Constructor. * @param threads number of threads to use. * @param pl pair selection strategy */ public GroebnerBaseParIter(int threads, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), new ReductionPar(), pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. */ public GroebnerBaseParIter(int threads, ExecutorService pool) { this(threads, pool, new ReductionPar()); } /** * Constructor. * @param pool ExecutorService to use. * @param red Reduction engine */ public GroebnerBaseParIter(int threads, ExecutorService pool, Reduction red) { this(threads, pool, red, new OrderedPairlist()); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseParIter(int threads, Reduction red, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), red, pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param red parallelism aware reduction engine * @param pl pair selection strategy */ public GroebnerBaseParIter(int threads, ExecutorService pool, Reduction red, PairList pl) { super(red, pl); if (!(red instanceof ReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("{}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("{}", pool); return s; } /** * Parallel iterative Groebner base using pairlist class. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { return G; } // sort, no reverse G = OrderedPolynomialList. sort(G); //no: Collections.reverse(G); logger.info("G-sort = {}", G); List> Gp = new ArrayList>(); for (GenPolynomial p : G) { if (debug) { logger.info("p = {}", p); } Gp = GB(modv, Gp, p); //System.out.println("GB(Gp+p) = " + Gp); if (Gp.size() > 0) { if (Gp.get(0).isONE()) { return Gp; } } } return Gp; } /** * Groebner base using pairlist class. * @param modv module variable number. * @param G polynomial list of a Groebner base. * @param f polynomial. * @return GB(G,f) a Groebner base of G+(f). */ public List> GB(int modv, List> G, GenPolynomial f) { List> F = new ArrayList>(G); GenPolynomial g = f.monic(); if (F.isEmpty()) { F.add(g); return F; } if (g.isZERO()) { return F; } if (g.isONE()) { F.clear(); F.add(g); return F; } GenPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.setList(G); G.add(g); pairlist.put(g); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); for (int i = 0; i < threads; i++) { ReducerIter R = new ReducerIter(fin, G, pairlist); pool.execute(R); } fin.waitDone(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt before minimalGB"); } logger.debug("#parallel list = {}", G.size()); G = minimalGB(G); // not in this context // pool.terminate(); logger.info("end {}", pairlist); return G; } /** * Minimal ordered groebner basis, parallel. * @param Fp a Groebner base. * @return minimalGB(F) a minimal Groebner base of Fp. */ @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); // no thread at this point } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB @SuppressWarnings("unchecked") MiReducerIter[] mirs = (MiReducerIter[]) new MiReducerIter[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); // System.out.println("doing " + a.length()); mirs[i] = new MiReducerIter(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Reducing worker threads. */ class ReducerIter> implements Runnable { private final List> G; private final PairList pairlist; private final Terminator fin; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(ReducerIter.class); ReducerIter(Terminator fin, List> G, PairList L) { this.fin = fin; this.fin.initIdle(1); this.G = G; pairlist = L; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "ReducerIter"; } public void run() { Pair pair; GenPolynomial pi, pj, S, H; //boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || fin.hasJobs()) { while (!pairlist.hasNext()) { // wait //fin.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { fin.allIdle(); logger.info("shutdown {} after: {}", fin, e); //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); break; } if (Thread.currentThread().isInterrupted()) { //fin.initIdle(1); fin.allIdle(); logger.info("shutdown after .isInterrupted(): {}", fin); //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); break; } if (!fin.hasJobs()) { break; } } if (!pairlist.hasNext() && !fin.hasJobs()) { break; } //if ( set ) { //fin.notIdle(); set = false; //} fin.notIdle(); // before pairlist get pair = pairlist.removeNext(); if (Thread.currentThread().isInterrupted()) { fin.initIdle(1); throw new RuntimeException("interrupt after removeNext"); } if (pair == null) { fin.initIdle(1); continue; } pi = pair.pi; pj = pair.pj; if (logger.isDebugEnabled()) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); //mod reduction++; if (H.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (logger.isDebugEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { // putOne not required pairlist.put(H); synchronized (G) { G.clear(); G.add(H); } fin.allIdle(); return; } if (logger.isDebugEnabled()) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.put(H); fin.initIdle(1); } fin.allIdle(); logger.info("terminated, done {} reductions", reduction); } } /** * Reducing worker threads for minimal GB. */ class MiReducerIter> implements Runnable { private final List> G; private GenPolynomial H; private final ReductionPar red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducerIter.class); MiReducerIter(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "MiReducerIter"; } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { throw new RuntimeException("interrupt in getNF"); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } try { H = red.normalform(G, H); //mod done.release(); //done.V(); } catch (RuntimeException e) { Thread.currentThread().interrupt(); //throw new RuntimeException("interrupt in getNF"); } if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseParallel.java000066400000000000000000000331061445075545500251300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.Terminator; /** * Groebner Base parallel algorithm. Implements a shared memory parallel version * of Groebner bases. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseParallel> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseParallel.class); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Constructor. */ public GroebnerBaseParallel() { this(2); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseParallel(int threads) { this(threads, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param red parallelism aware reduction engine */ public GroebnerBaseParallel(int threads, Reduction red) { this(threads, Executors.newFixedThreadPool(threads), red); } /** * Constructor. * @param threads number of threads to use. * @param pl pair selection strategy */ public GroebnerBaseParallel(int threads, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), new ReductionPar(), pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ThreadPool to use. */ public GroebnerBaseParallel(int threads, ExecutorService pool) { this(threads, pool, new ReductionPar()); } /** * Constructor. * @param pool ThreadPool to use. * @param red Reduction engine */ public GroebnerBaseParallel(int threads, ExecutorService pool, Reduction red) { this(threads, pool, red, new OrderedPairlist()); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseParallel(int threads, Reduction red, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), red, pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param red parallelism aware reduction engine * @param pl pair selection strategy */ public GroebnerBaseParallel(int threads, ExecutorService pool, Reduction red, PairList pl) { super(red, pl); if (!(red instanceof ReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; int s = ((ThreadPoolExecutor) pool).getCorePoolSize(); if (threads != s) { logger.warn("#threads({}) and number of pool threads({}) differ:", threads, s); } } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("{}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("{}", pool); return s; } /** * Parallel Groebner base using pairlist class. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { return G; } GenPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(G); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); for (int i = 0; i < threads; i++) { Reducer R = new Reducer(fin, G, pairlist); pool.execute(R); } fin.waitDone(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt before minimalGB"); } logger.debug("#parallel list = {}", G.size()); G = minimalGB(G); // not in this context // pool.terminate(); logger.info("end {}", pairlist); return G; } /** * Minimal ordered groebner basis, parallel. * @param Fp a Groebner base. * @return minimalGB(F) a minimal Groebner base of Fp. */ @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); // no thread at this point } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB @SuppressWarnings("unchecked") MiReducer[] mirs = (MiReducer[]) new MiReducer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); // System.out.println("doing " + a.length()); mirs[i] = new MiReducer(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Reducing worker threads. */ class Reducer> implements Runnable { private final List> G; private final PairList pairlist; private final Terminator fin; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(Reducer.class); Reducer(Terminator fin, List> G, PairList L) { this.fin = fin; this.fin.initIdle(1); this.G = G; pairlist = L; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "Reducer"; } public void run() { Pair pair; GenPolynomial pi, pj, S, H; //boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || fin.hasJobs()) { while (!pairlist.hasNext()) { // wait //fin.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { fin.allIdle(); logger.info("shutdown {} after: {}", fin, e); //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); break; } if (Thread.currentThread().isInterrupted()) { //fin.initIdle(1); fin.allIdle(); logger.info("shutdown after .isInterrupted(): {}", fin); //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); break; } if (!fin.hasJobs()) { break; } } if (!pairlist.hasNext() && !fin.hasJobs()) { break; } //if ( set ) { //fin.notIdle(); set = false; //} fin.notIdle(); // before pairlist get pair = pairlist.removeNext(); if (Thread.currentThread().isInterrupted()) { fin.initIdle(1); throw new RuntimeException("interrupt after removeNext"); } if (pair == null) { fin.initIdle(1); continue; } pi = pair.pi; pj = pair.pj; if (logger.isDebugEnabled()) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); //mod reduction++; if (H.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (logger.isDebugEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { // putOne not required pairlist.put(H); synchronized (G) { G.clear(); G.add(H); } fin.allIdle(); return; } if (logger.isDebugEnabled()) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.put(H); fin.initIdle(1); } fin.allIdle(); logger.info("terminated, done {} reductions", reduction); } } /** * Reducing worker threads for minimal GB. */ class MiReducer> implements Runnable { private final List> G; private GenPolynomial H; private final ReductionPar red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducer.class); MiReducer(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "MiReducer"; } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { throw new RuntimeException("interrupt in getNF"); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } try { H = red.normalform(G, H); //mod done.release(); //done.V(); } catch (RuntimeException e) { Thread.currentThread().interrupt(); //throw new RuntimeException("interrupt in getNF"); } if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSeq.java000066400000000000000000000250311445075545500241220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.structure.RingElem; import edu.jas.gb.OrderedPairlist; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.vector.BasicLinAlg; /** * Groebner Base sequential algorithm. * Implements Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseSeq> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseSeq() { super(); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseSeq(Reduction red) { super(red); } /** * Constructor. * @param pl pair selection strategy */ public GroebnerBaseSeq(PairList pl) { super(pl); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseSeq(Reduction red, PairList pl) { super(red,pl); } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB( int modv, List> F ) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if ( G.size() <= 1 ) { return G; } GenPolynomialRing ring = G.get(0).ring; if ( ! ring.coFac.isField() ) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create( modv, ring ); pairlist.put(G); logger.info("start {}", pairlist); Pair pair; GenPolynomial pi, pj, S, H; while ( pairlist.hasNext() ) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if ( pair == null ) { continue; } pi = pair.pi; pj = pair.pj; if ( /*false &&*/ debug ) { logger.debug("pi = {}", pi ); logger.debug("pj = {}", pj ); } S = red.SPolynomial( pi, pj ); if ( S.isZERO() ) { pair.setZero(); continue; } if ( debug ) { logger.debug("ht(S) = {}", S.leadingExpVector() ); } H = red.normalform( G, S ); if ( debug ) { //logger.info("pair = {}", pair); //logger.info("ht(S) = {}", S.monic()); //.leadingExpVector() ); logger.info("ht(H) = {}", H.monic()); //.leadingExpVector() ); } if ( H.isZERO() ) { pair.setZero(); continue; } H = H.monic(); if ( debug ) { logger.info("ht(H) = {}", H.leadingExpVector() ); } H = H.monic(); if ( H.isONE() ) { G.clear(); G.add( H ); pairlist.putOne(); logger.info("end {}", pairlist); return G; // since no threads are activated } if ( debug ) { logger.info("H = {}", H ); } if ( H.length() > 0 ) { //l++; G.add( H ); pairlist.put( H ); } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("end {}", pairlist); return G; } /** * Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for an extended Groebner base of F. */ @Override public ExtendedGB extGB(int modv, List> F) { if ( F == null || F.isEmpty() ) { throw new IllegalArgumentException("null or empty F not allowed"); } List> G = new ArrayList>(); List>> F2G = new ArrayList>>(); List>> G2F = new ArrayList>>(); PairList pairlist = null; boolean oneInGB = false; int len = F.size(); List> row = null; List> rows = null; List> rowh = null; GenPolynomialRing ring = null; GenPolynomial H; GenPolynomial p; int nzlen = 0; for ( GenPolynomial f : F ) { if ( f.length() > 0 ) { nzlen++; } if ( ring == null ) { ring = f.ring; } } GenPolynomial mone = ring.getONE(); //.negate(); int k = 0; ListIterator> it = F.listIterator(); while ( it.hasNext() ) { p = it.next(); if ( p.length() > 0 ) { row = blas.genVector(nzlen, null); //C c = p.leadingBaseCoefficient(); //c = c.inverse(); //p = p.multiply( c ); row.set( k, mone ); //.multiply(c) ); k++; if ( p.isUnit() ) { G.clear(); G.add( p ); G2F.clear(); G2F.add( row ); oneInGB = true; break; } G.add( p ); G2F.add( row ); if ( pairlist == null ) { //pairlist = new OrderedPairlist( modv, p.ring ); pairlist = strategy.create( modv, p.ring ); if ( ! p.ring.coFac.isField() ) { throw new RuntimeException("coefficients not from a field"); } } // putOne not required pairlist.put( p ); } else { len--; } } ExtendedGB exgb; if ( len <= 1 || oneInGB ) { // adjust F2G for ( GenPolynomial f : F ) { row = blas.genVector(G.size(), null); H = red.normalform( row, G, f ); if ( ! H.isZERO() ) { logger.error("nonzero H = {}", H ); } F2G.add( row ); } exgb = new ExtendedGB(F,G,F2G,G2F); //System.out.println("exgb 1 = " + exgb); return exgb; } Pair pair; int i, j; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; GenPolynomial x; GenPolynomial y; //GenPolynomial z; while ( pairlist.hasNext() && ! oneInGB ) { pair = pairlist.removeNext(); if ( pair == null ) { continue; } i = pair.i; j = pair.j; pi = pair.pi; pj = pair.pj; if ( debug ) { logger.info("i, pi = {}, {}", i, pi ); logger.info("j, pj = {}, {}", j, pj ); } rows = blas.genVector(G.size(), null); S = red.SPolynomial( rows, i, pi, j, pj ); if ( debug ) { logger.debug("is reduction S = " + red.isReductionNF( rows, G, ring.getZERO(), S ) ); } if ( S.isZERO() ) { // do not add to G2F continue; } if ( debug ) { logger.debug("ht(S) = {}", S.leadingExpVector() ); } rowh = blas.genVector(G.size(), null); H = red.normalform( rowh, G, S ); if ( debug ) { logger.debug("is reduction H = " + red.isReductionNF( rowh, G, S, H ) ); } if ( H.isZERO() ) { // do not add to G2F continue; } if ( debug ) { logger.debug("ht(H) = {}", H.leadingExpVector() ); } row = blas.vectorCombineOld(rows,rowh); // if ( debug ) { // logger.debug("is reduction 0+sum(row,G) == H : " // + red.isReductionNF( row, G, H, ring.getZERO() ) ); // } // H = H.monic(); C c = H.leadingBaseCoefficient(); c = c.inverse(); H = H.multiply( c ); row = blas.scalarProduct( mone.multiply(c), row ); row.set( G.size(), mone ); if ( H.isONE() ) { // G.clear(); G.add( H ); G2F.add( row ); oneInGB = true; break; } if ( debug ) { logger.debug("H = {}", H ); } G.add( H ); pairlist.put( H ); G2F.add( row ); } if ( debug ) { exgb = new ExtendedGB(F,G,F2G,G2F); logger.info("exgb unnorm = {}", exgb); } G2F = normalizeMatrix( F.size(), G2F ); if ( debug ) { exgb = new ExtendedGB(F,G,F2G,G2F); logger.info("exgb nonmin = {}", exgb); boolean t2 = isReductionMatrix( exgb ); logger.info("exgb t2 = {}", t2); } exgb = minimalExtendedGB(F.size(),G,G2F); G = exgb.G; G2F = exgb.G2F; logger.debug("#sequential list = {}", G.size()); logger.info("{}", pairlist); // setup matrices F and F2G for ( GenPolynomial f : F ) { row = blas.genVector(G.size(), null); H = red.normalform( row, G, f ); if ( ! H.isZERO() ) { logger.error("nonzero H = {}", H ); } F2G.add( row ); } exgb = new ExtendedGB(F,G,F2G,G2F); if ( debug ) { logger.info("exgb nonmin = {}", exgb); boolean t2 = isReductionMatrix( exgb ); logger.info("exgb t2 = {}", t2); } return exgb; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSeqIter.java000066400000000000000000000127041445075545500247510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; // import java.util.Collections; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; /** * Groebner Base sequential iterative algorithm. Implements Groebner bases and * GB test. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseSeqIter> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqIter.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseSeqIter() { super(); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseSeqIter(Reduction red) { super(red); } /** * Constructor. * @param pl pair selection strategy */ public GroebnerBaseSeqIter(PairList pl) { super(pl); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseSeqIter(Reduction red, PairList pl) { super(red, pl); } /** * Groebner base using pairlist class, iterative algorithm. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { return G; } // sort, no reverse G = OrderedPolynomialList. sort(G); //no: Collections.reverse(G); logger.info("G-sort = {}", G); List> Gp = new ArrayList>(); for (GenPolynomial p : G) { if (debug) { logger.info("p = {}", p); } GenPolynomial pp = red.normalform(Gp, p); if (pp.isZERO()) { continue; } Gp = GB(modv, Gp, pp); //System.out.println("GB(Gp+p) = " + Gp); if (Gp.size() > 0) { if (Gp.get(0).isONE()) { return Gp; } } } return Gp; } /** * Groebner base using pairlist class. * @param modv module variable number. * @param G polynomial list of a Groebner base. * @param f polynomial. * @return GB(G,f) a Groebner base of G+(f). */ public List> GB(int modv, List> G, GenPolynomial f) { List> F = new ArrayList>(G); GenPolynomial g = f.monic(); if (F.isEmpty()) { F.add(g); return F; } if (g.isZERO()) { return F; } if (g.isONE()) { F.clear(); F.add(g); return F; } GenPolynomialRing ring = F.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } G = F; PairList pairlist = strategy.create(modv, ring); pairlist.setList(G); G.add(g); pairlist.put(g); logger.info("start {}", pairlist); Pair pair; GenPolynomial pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if (pair == null) { continue; } pi = pair.pi; pj = pair.pj; if ( /*false &&*/debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); if (debug) { //logger.info("pair = {}", pair); //logger.info("ht(S) = {}", S.monic()); //.leadingExpVector() ); logger.info("ht(H) = {}", H.monic()); //.leadingExpVector() ); } if (H.isZERO()) { pair.setZero(); continue; } H = H.monic(); if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); if (H.isONE()) { G.clear(); G.add(H); pairlist.putOne(); logger.info("end {}", pairlist); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("end {}", pairlist); return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSeqPairDistributed.java000066400000000000000000000733271445075545500271540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; import edu.jas.util.ChannelFactory; import edu.jas.util.DistHashTable; import edu.jas.util.DistHashTableServer; import edu.jas.util.SocketChannel; import edu.jas.util.Terminator; /** * Groebner Base distributed algorithm. Implements a distributed memory parallel * version of Groebner bases. Using pairlist class, distributed tasks do * reduction. Makes some effort to produce the same sequence of critical pairs * as in the sequential version. However already reduced pairs are not rereduced * if new polynomials appear. * @param coefficient type * @author Heinz Kredel * @deprecated no direct alternative * @see edu.jas.gb.GroebnerBaseDistributedEC * @see edu.jas.gb.GroebnerBaseDistributedHybridEC */ @Deprecated public class GroebnerBaseSeqPairDistributed> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqPairDistributed.class); /** * Number of threads to use. */ protected final int threads; /** * Default number of threads. */ protected static final int DEFAULT_THREADS = 2; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Default server port. */ protected static final int DEFAULT_PORT = 4711; /** * Server port to use. */ protected final int port; /** * Constructor. */ public GroebnerBaseSeqPairDistributed() { this(DEFAULT_THREADS, DEFAULT_PORT); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseSeqPairDistributed(int threads) { this(threads, Executors.newFixedThreadPool(threads), DEFAULT_PORT); } /** * Constructor. * @param threads number of threads to use. * @param red parallelism aware reduction engine */ public GroebnerBaseSeqPairDistributed(int threads, Reduction red) { this(threads, Executors.newFixedThreadPool(threads), DEFAULT_PORT, red); } /** * Constructor. * @param threads number of threads to use. * @param port server port to use. * @param red parallelism aware reduction engine */ public GroebnerBaseSeqPairDistributed(int threads, int port, Reduction red) { this(threads, Executors.newFixedThreadPool(threads), port, red); } /** * Constructor. * @param threads number of threads to use. * @param port server port to use. */ public GroebnerBaseSeqPairDistributed(int threads, int port) { this(threads, Executors.newFixedThreadPool(threads), port); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param port server port to use. */ public GroebnerBaseSeqPairDistributed(int threads, ExecutorService pool, int port) { this(threads, pool, port, new ReductionPar()); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param port server port to use. * @param red parallelism aware reduction engine */ public GroebnerBaseSeqPairDistributed(int threads, ExecutorService pool, int port, Reduction red) { super(red); if (!(red instanceof ReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; this.port = port; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } } /** * Distributed Groebner base. Slaves maintain pairlist. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F or null, if a IOException occurs. */ public List> GB(int modv, List> F) { final int DL_PORT = port + 100; ChannelFactory cf = new ChannelFactory(port); cf.init(); DistHashTableServer dls = new DistHashTableServer(DL_PORT); dls.init(); logger.debug("dist-list server running"); GenPolynomial p; //List> G = new ArrayList>(); CriticalPairList pairlist = null; boolean oneInGB = false; //int l = F.size(); @SuppressWarnings("unused") int unused; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { oneInGB = true; //G.clear(); //G.add(p); //return G; must signal termination to others } //if (!oneInGB) { // //G.add(p); //} if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); } // theList not updated here if (p.isONE()) { unused = pairlist.putOne(); } else { unused = pairlist.put(p); } } else { //l--; } } //if (l <= 1) { //return G; must signal termination to others //} logger.debug("looking for clients"); //long t = System.currentTimeMillis(); // now in DL, uses resend for late clients //while ( dls.size() < threads ) { sleep(); } DistHashTable> theList = new DistHashTable>( "localhost", DL_PORT); theList.init(); List> G = pairlist.getList(); for (int i = 0; i < G.size(); i++) { // no wait required GenPolynomial nn = theList.put(Integer.valueOf(i), G.get(i)); if (nn != null) { logger.info("double polynomials {}, nn = {}, G(i) = {}", i, nn, G.get(i)); } } Terminator fin = new Terminator(threads); ReducerServerSeqPair R; for (int i = 0; i < threads; i++) { R = new ReducerServerSeqPair(fin, cf, theList, pairlist); pool.execute(R); } logger.debug("main loop waiting"); fin.waitDone(); int ps = theList.size(); //logger.debug("#distributed list = {}", ps); // make sure all polynomials arrived: not needed in master // G = (ArrayList)theList.values(); G = pairlist.getList(); //logger.debug("#pairlist list = {}", G.size()); if (ps != G.size()) { logger.info("#distributed list = {} #pairlist list = {}", theList.size(), G.size()); } long time = System.currentTimeMillis(); List> Gp; Gp = minimalGB(G); // not jet distributed but threaded time = System.currentTimeMillis() - time; logger.info("parallel gbmi = {}", time); /* time = System.currentTimeMillis(); G = GroebnerBase.GBmi(G); // sequential time = System.currentTimeMillis() - time; logger.info("sequential gbmi = {}", time); */ G = Gp; //logger.info("cf.terminate()"); cf.terminate(); // no more required // pool.terminate(); logger.info("theList.terminate()"); theList.terminate(); logger.info("dls.terminate()"); dls.terminate(); logger.info("{}", pairlist); return G; } /** * GB distributed client. * @param host the server runs on. * @throws IOException */ public void clientPart(String host) throws IOException { ChannelFactory cf = new ChannelFactory(port + 10); // != port for localhost cf.init(); SocketChannel pairChannel = cf.getChannel(host, port); final int DL_PORT = port + 100; DistHashTable> theList = new DistHashTable>(host, DL_PORT); theList.init(); ReducerClientSeqPair R = new ReducerClientSeqPair(pairChannel, theList); R.run(); pairChannel.close(); theList.terminate(); cf.terminate(); return; } /** * Minimal ordered groebner basis. * @param Fp a Groebner base. * @return a reduced Groebner base of Fp. */ @SuppressWarnings("unchecked") @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB MiReducerServerSeqPair[] mirs = (MiReducerServerSeqPair[]) new MiReducerServerSeqPair[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiReducerServerSeqPair(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Distributed server reducing worker threads. * @param coefficient type */ class ReducerServerSeqPair> implements Runnable { private final Terminator pool; private final ChannelFactory cf; private SocketChannel pairChannel; private final DistHashTable> theList; //private List> G; private final CriticalPairList pairlist; private static final Logger logger = LogManager.getLogger(ReducerServerSeqPair.class); ReducerServerSeqPair(Terminator fin, ChannelFactory cf, DistHashTable> dl, CriticalPairList L) { pool = fin; this.cf = cf; theList = dl; //this.G = G; pairlist = L; } @SuppressWarnings("unchecked") public void run() { logger.debug("reducer server running"); try { pairChannel = cf.getChannel(); } catch (InterruptedException e) { logger.debug("get pair channel interrupted"); e.printStackTrace(); return; } if (logger.isDebugEnabled()) { logger.debug("pairChannel = {}", pairChannel); } CriticalPair pair; //GenPolynomial pi; //GenPolynomial pj; //GenPolynomial S; GenPolynomial H = null; boolean set = false; boolean goon = true; int polIndex = -1; int red = 0; int sleeps = 0; // while more requests while (goon) { // receive request logger.debug("receive request"); Object req = null; try { req = pairChannel.receive(); } catch (IOException e) { goon = false; e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } //logger.debug("received request, req = {}", req); if (req == null) { goon = false; break; } if (!(req instanceof GBSPTransportMessReq)) { goon = false; break; } // find pair if (logger.isDebugEnabled()) { logger.debug("find pair"); logger.debug("pool.hasJobs() {} pairlist.hasNext() {}", pool.hasJobs(), pairlist.hasNext()); } while (!pairlist.hasNext()) { // wait pairlist.update(); if (!set) { pool.beIdle(); set = true; } if (!pool.hasJobs() && !pairlist.hasNext()) { goon = false; break; } try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } Thread.sleep(100); } catch (InterruptedException e) { goon = false; break; } } if (!pairlist.hasNext() && !pool.hasJobs()) { goon = false; break; //continue; //break? } if (set) { set = false; pool.notIdle(); } pair = pairlist.getNext(); /* * send pair to client, receive H */ if (logger.isDebugEnabled()) { logger.debug("send pair = {}", pair); logger.info("theList keys {}", theList.keySet()); } if (logger.isDebugEnabled()) { logger.info("inWork {}", pairlist.inWork()); } GBSPTransportMess msg = null; if (pair != null) { msg = new GBSPTransportMessPairIndex(pair); } else { msg = new GBSPTransportMess(); //End(); // goon ?= false; } try { pairChannel.send(msg); } catch (IOException e) { e.printStackTrace(); goon = false; break; } // use idle time to update pairlist pairlist.update(); //logger.debug("#distributed list = {}", theList.size()); //logger.debug("receive H polynomial"); Object rh = null; try { rh = pairChannel.receive(); } catch (IOException e) { e.printStackTrace(); goon = false; break; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; break; } if (logger.isDebugEnabled()) { logger.info("received H polynomial rh = {}", rh); } if (rh == null) { if (pair != null) { polIndex = pairlist.record(pair, null); //pair.setZero(); } pairlist.update(); } else if (rh instanceof GBSPTransportMessPoly) { // update pair list red++; H = ((GBSPTransportMessPoly) rh).pol; //logger.info("H = {}", H); if (H == null) { if (pair != null) { polIndex = pairlist.record(pair, null); //pair.setZero(); } pairlist.update(); } else { if (H.isZERO()) { polIndex = pairlist.record(pair, H); //pair.setZero(); } else { if (H.isONE()) { // pool.allIdle(); pairlist.putOne(); theList.put(Integer.valueOf(0), H); goon = false; //break; } else { polIndex = pairlist.record(pair, H); // not correct: // polIndex = pairlist.getList().size(); // pairlist.update(); // polIndex = pairlist.put( H ); // use putWait ? but still not all distributed theList.put(Integer.valueOf(polIndex), H); } } } } else { if (pair != null) { polIndex = pairlist.record(pair, null); //pair.setZero(); } if (logger.isDebugEnabled()) { logger.debug("invalid message {}", rh); } } } logger.info("terminated, done {} reductions", red); /* * send end mark to client */ logger.debug("send end"); try { pairChannel.send(new GBSPTransportMessEnd()); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } pool.beIdle(); pairChannel.close(); } } /** * Distributed GB transport message. */ class GBSPTransportMess implements Serializable { /** * toString. */ @Override public String toString() { return "" + this.getClass().getName(); } } /** * Distributed GB transport message for requests. */ class GBSPTransportMessReq extends GBSPTransportMess { public GBSPTransportMessReq() { } } /** * Distributed GB transport message for termination. */ class GBSPTransportMessEnd extends GBSPTransportMess { public GBSPTransportMessEnd() { } } /** * Distributed GB transport message for polynomial. */ class GBSPTransportMessPoly> extends GBSPTransportMess { /** * The polynomial for transport. */ public final GenPolynomial pol; /** * GBSPTransportMessPoly. * @param p polynomial to transferred. */ public GBSPTransportMessPoly(GenPolynomial p) { this.pol = p; } /** * toString. */ @Override public String toString() { return super.toString() + "( " + pol + " )"; } } /** * Distributed GB transport message for pairs. */ class GBSPTransportMessPair> extends GBSPTransportMess { public final CriticalPair pair; /** * GBSPTransportMessPair. * @param p pair for transfer. */ public GBSPTransportMessPair(CriticalPair p) { this.pair = p; } /** * toString. */ @Override public String toString() { return super.toString() + "( " + pair + " )"; } } /** * Distributed GB transport message for index pairs. */ class GBSPTransportMessPairIndex extends GBSPTransportMess { public final Integer i; public final Integer j; /** * GBSPTransportMessPairIndex. * @param p pair for transport. */ public GBSPTransportMessPairIndex(CriticalPair p) { if (p == null) { throw new NullPointerException("pair may not be null"); } this.i = Integer.valueOf(p.i); this.j = Integer.valueOf(p.j); } /** * GBSPTransportMessPairIndex. * @param i first index. * @param j second index. */ public GBSPTransportMessPairIndex(int i, int j) { this.i = Integer.valueOf(i); this.j = Integer.valueOf(j); } /** * GBSPTransportMessPairIndex. * @param i first index. * @param j second index. */ public GBSPTransportMessPairIndex(Integer i, Integer j) { this.i = i; this.j = j; } /** * toString. */ @Override public String toString() { return super.toString() + "( " + i + "," + j + " )"; } } /** * Distributed clients reducing worker threads. */ class ReducerClientSeqPair> implements Runnable { private final SocketChannel pairChannel; private final DistHashTable> theList; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(ReducerClientSeqPair.class); ReducerClientSeqPair(SocketChannel pc, DistHashTable> dl) { pairChannel = pc; theList = dl; red = new ReductionPar(); } @SuppressWarnings("unchecked") public void run() { if (logger.isDebugEnabled()) { logger.debug("pairChannel = {} reducer client running", pairChannel); } CriticalPair pair = null; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; GenPolynomial H = null; //boolean set = false; boolean goon = true; int reduction = 0; //int sleeps = 0; Integer pix; Integer pjx; while (goon) { /* protocol: * request pair, process pair, send result */ // pair = (Pair) pairlist.removeNext(); Object req = new GBSPTransportMessReq(); if (logger.isDebugEnabled()) { logger.debug("send request = {}", req); } try { pairChannel.send(req); } catch (IOException e) { goon = false; e.printStackTrace(); break; } if (logger.isDebugEnabled()) { logger.debug("receive pair, goon = {}", goon); } Object pp = null; try { pp = pairChannel.receive(); } catch (IOException e) { goon = false; if (logger.isDebugEnabled()) { e.printStackTrace(); } break; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } if (logger.isDebugEnabled()) { logger.info("received pair = {}", pp); } H = null; if (pp == null) { // should not happen //logger.debug("received pair = {}", pp); continue; } if (pp instanceof GBSPTransportMessEnd) { goon = false; continue; } if (pp instanceof GBSPTransportMessPair || pp instanceof GBSPTransportMessPairIndex) { pi = pj = null; if (pp instanceof GBSPTransportMessPair) { pair = ((GBSPTransportMessPair) pp).pair; if (pair != null) { pi = pair.pi; pj = pair.pj; //logger.debug("pair: pix = {}", pair.i // + ", pjx = {}", pair.j); } } if (pp instanceof GBSPTransportMessPairIndex) { pix = ((GBSPTransportMessPairIndex) pp).i; pjx = ((GBSPTransportMessPairIndex) pp).j; //logger.info("waiting for pix = {}", pix); pi = theList.getWait(pix); //logger.info("waiting for pjx = {}", pjx); pj = theList.getWait(pjx); //logger.info("pix = {}, pjx = {}", pix, pjx); } if (pi != null && pj != null) { if (logger.isDebugEnabled()) { logger.info("pi = {}, pj = {}", pi.leadingExpVector(), pj.leadingExpVector()); } S = red.SPolynomial(pi, pj); //System.out.println("S = {}", S); if (S.isZERO()) { // pair.setZero(); does not work in dist H = S; } else { if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(theList, S); reduction++; if (H.isZERO()) { // pair.setZero(); does not work in dist } else { H = H.monic(); if (logger.isDebugEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } } } } } else { if (logger.isDebugEnabled()) { logger.debug("invalid message = {}", pp); } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } // send H or must send null //logger.debug("#distributed list = {}", theList.size()); if (logger.isDebugEnabled()) { logger.info("send H polynomial = {}", H); } try { pairChannel.send(new GBSPTransportMessPoly(H)); } catch (IOException e) { goon = false; e.printStackTrace(); break; } } logger.info("terminated, done {} reductions", reduction); pairChannel.close(); } } /** * Distributed server reducing worker threads for minimal GB Not jet distributed * but threaded. */ class MiReducerServerSeqPair> implements Runnable { private final List> G; private GenPolynomial H; private final Semaphore done = new Semaphore(0); private final Reduction red; private static final Logger logger = LogManager.getLogger(MiReducerServerSeqPair.class); MiReducerServerSeqPair(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } /** * Distributed clients reducing worker threads for minimal GB. Not jet used. */ class MiReducerClientSeqPair> implements Runnable { private final List> G; private GenPolynomial H; private final Reduction red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducerClientSeqPair.class); MiReducerClientSeqPair(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException u) { Thread.currentThread().interrupt(); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = red.normalform(G, H); // mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSeqPairParallel.java000066400000000000000000000324641445075545500264230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; import edu.jas.util.Terminator; /** * Groebner Base parallel algorithm. Makes some effort to produce the same * sequence of critical pairs as in the sequential version. However already * reduced pairs are not rereduced if new polynomials appear. Implements a * shared memory parallel version of Groebner bases. Slaves maintain pairlist. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseSeqPairParallel> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqPairParallel.class); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Constructor. */ public GroebnerBaseSeqPairParallel() { this(2); } /** * Constructor. * @param threads number of threads to use. */ public GroebnerBaseSeqPairParallel(int threads) { this(threads, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. */ public GroebnerBaseSeqPairParallel(int threads, ExecutorService pool) { this(threads, pool, new ReductionPar()); } /** * Constructor. * @param threads number of threads to use. * @param red parallelism aware reduction engine */ public GroebnerBaseSeqPairParallel(int threads, Reduction red) { this(threads, Executors.newFixedThreadPool(threads), red); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param red parallelism aware reduction engine */ public GroebnerBaseSeqPairParallel(int threads, ExecutorService pool, Reduction red) { super(red); if (!(red instanceof ReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info(pool.toString()); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info(pool.toString()); return s; } /** * Parallel Groebner base using sequential pair order class. Slaves maintain * pairlist. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { GenPolynomial p; List> G = new ArrayList>(); CriticalPairList pairlist = null; int l = F.size(); ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads activated jet } G.add(p); if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // putOne not required pairlist.put(p); } else { l--; } } if (l <= 1) { return G; // since no threads activated jet } Terminator fin = new Terminator(threads); ReducerSeqPair R; for (int i = 0; i < threads; i++) { R = new ReducerSeqPair(fin, G, pairlist); pool.execute(R); } fin.waitDone(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt before minimalGB"); } logger.debug("#parallel list = {}", G.size()); G = minimalGB(G); // not in this context // pool.terminate(); logger.info("{}", pairlist); return G; } /** * Minimal ordered groebner basis, parallel. * @param Fp a Groebner base. * @return minimalGB(F) a minimal Groebner base of Fp. */ @Override public List> minimalGB(List> Fp) { GenPolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenPolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); // no thread at this point } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB @SuppressWarnings("unchecked") MiReducerSeqPair[] mirs = (MiReducerSeqPair[]) new MiReducerSeqPair[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new MiReducerSeqPair(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } } /** * Reducing worker threads. */ class ReducerSeqPair> implements Runnable { private final List> G; private final CriticalPairList pairlist; private final Terminator fin; private final ReductionPar red; private static final Logger logger = LogManager.getLogger(ReducerSeqPair.class); ReducerSeqPair(Terminator fin, List> G, CriticalPairList L) { this.fin = fin; this.G = G; pairlist = L; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "ReducerSeqPair"; } public void run() { CriticalPair pair; GenPolynomial S; GenPolynomial H; boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || fin.hasJobs()) { while (!pairlist.hasNext()) { pairlist.update(); // wait fin.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { fin.allIdle(); logger.info("shutdown {} after: {}", fin, e); //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); break; } if (Thread.currentThread().isInterrupted()) { fin.allIdle(); logger.info("shutdown after .isInterrupted(): {}", fin); //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); break; } if (!fin.hasJobs()) { break; } } if (!pairlist.hasNext() && !fin.hasJobs()) { break; } if (set) { fin.notIdle(); set = false; } pair = pairlist.getNext(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt after getNext"); } if (pair == null) { pairlist.update(); continue; } if (logger.isDebugEnabled()) { logger.debug("pi = {}", pair.pi); logger.debug("pj = {}", pair.pj); } S = red.SPolynomial(pair.pi, pair.pj); if (S.isZERO()) { pairlist.record(pair, S); continue; } if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); //mod reduction++; if (H.isZERO()) { pairlist.record(pair, H); continue; } if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = {}", H); if (H.isONE()) { // pairlist.update( pair, H ); pairlist.putOne(); // not really required synchronized (G) { G.clear(); G.add(H); } fin.allIdle(); return; } if (logger.isDebugEnabled()) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.update(pair, H); //pairlist.record( pair, H ); //pairlist.update(); } logger.info("terminated, done {} reductions", reduction); } } /** * Reducing worker threads for minimal GB. */ class MiReducerSeqPair> implements Runnable { private final List> G; private GenPolynomial H; private final ReductionPar red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducerSeqPair.class); MiReducerSeqPair(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * to string */ @Override public String toString() { return "MiReducerSeqpair"; } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { throw new RuntimeException("interrupt in getNF"); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } try { H = red.normalform(G, H); //mod done.release(); //done.V(); } catch (RuntimeException e) { Thread.currentThread().interrupt(); //throw new RuntimeException("interrupt in getNF"); } if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSeqPairSeq.java000066400000000000000000000244521445075545500254150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Groebner Base sequential algorithm. Implements Groebner bases and GB test. * Uses sequential pair list class. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBaseSeqPairSeq> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSeqPairSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public GroebnerBaseSeqPairSeq() { super(); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseSeqPairSeq(Reduction red) { super(red); } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = new ArrayList>(); if (F == null) { return G; } GenPolynomial p; CriticalPairList pairlist = null; int len = F.size(); ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads are activated } G.add(p); if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); } // putOne not required pairlist.put(p); } else { len--; } } if (len <= 1) { return G; // since no threads are activated } CriticalPair pair; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; GenPolynomial H; while (pairlist.hasNext()) { pair = pairlist.getNext(); if (pair == null) { pairlist.update(); // ? continue; } pi = pair.pi; pj = pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); if (S.isZERO()) { pairlist.update(pair, S); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); if (H.isZERO()) { pairlist.update(pair, H); continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); if (H.isONE()) { // pairlist.record( pair, H ); G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.debug("H = {}", H); } G.add(H); pairlist.update(pair, H); //pairlist.update(); } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for an extended Groebner base of F. */ @Override public ExtendedGB extGB(int modv, List> F) { if ( F == null || F.isEmpty() ) { throw new IllegalArgumentException("null or empty F not allowed"); } List> G = new ArrayList>(); List>> F2G = new ArrayList>>(); List>> G2F = new ArrayList>>(); CriticalPairList pairlist = null; boolean oneInGB = false; int len = F.size(); List> row = null; List> rows = null; List> rowh = null; GenPolynomialRing ring = null; GenPolynomial H; GenPolynomial p; int nzlen = 0; for (GenPolynomial f : F) { if (f.length() > 0) { nzlen++; } if (ring == null) { ring = f.ring; } } GenPolynomial mone = ring.getONE(); //.negate(); int k = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { row = blas.genVector(nzlen, null); //C c = p.leadingBaseCoefficient(); //c = c.inverse(); //p = p.multiply( c ); row.set(k, mone); //.multiply(c) ); k++; if (p.isUnit()) { G.clear(); G.add(p); G2F.clear(); G2F.add(row); oneInGB = true; break; } G.add(p); G2F.add(row); if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); } // putOne not required pairlist.put(p); } else { len--; } } ExtendedGB exgb; if (len <= 1 || oneInGB) { // adjust F2G for (GenPolynomial f : F) { row = blas.genVector(G.size(), null); H = red.normalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero H = {}", H); } F2G.add(row); } exgb = new ExtendedGB(F, G, F2G, G2F); //System.out.println("exgb 1 = " + exgb); return exgb; } CriticalPair pair; int i, j; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; GenPolynomial x; GenPolynomial y; //GenPolynomial z; while (pairlist.hasNext() && !oneInGB) { pair = pairlist.getNext(); if (pair == null) { pairlist.update(); // ? continue; } i = pair.i; j = pair.j; pi = pair.pi; pj = pair.pj; if (debug) { logger.info("i, pi = {}, {}", i, pi); logger.info("j, pj = {}, {}", j, pj); } rows = new ArrayList>(G.size()); for (int m = 0; m < G.size(); m++) { rows.add(null); } S = red.SPolynomial(rows, i, pi, j, pj); if (debug) { logger.debug("is reduction S = {}", red.isReductionNF(rows, G, ring.getZERO(), S)); } if (S.isZERO()) { pairlist.update(pair, S); // do not add to G2F continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } rowh = new ArrayList>(G.size()); for (int m = 0; m < G.size(); m++) { rowh.add(null); } H = red.normalform(rowh, G, S); if (debug) { logger.debug("is reduction H = {}", red.isReductionNF(rowh, G, S, H)); } if (H.isZERO()) { pairlist.update(pair, H); // do not add to G2F continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } row = blas.vectorCombineOld(rows,rowh); // if (debug) { // logger.debug("is reduction 0+sum(row,G) == H : " // + red.isReductionNF(row, G, H, ring.getZERO())); // } // H = H.monic(); C c = H.leadingBaseCoefficient(); c = c.inverse(); H = H.multiply(c); row = blas.scalarProduct(mone.multiply(c), row); row.set(G.size(), mone); if (H.isONE()) { // pairlist.record( pair, H ); // G.clear(); G.add(H); G2F.add(row); oneInGB = true; break; } if (debug) { logger.debug("H = {}", H); } G.add(H); pairlist.update(pair, H); G2F.add(row); } if (debug) { exgb = new ExtendedGB(F, G, F2G, G2F); logger.info("exgb unnorm = {}", exgb); } G2F = normalizeMatrix(F.size(), G2F); if (debug) { exgb = new ExtendedGB(F, G, F2G, G2F); logger.info("exgb nonmin = {}", exgb); boolean t2 = isReductionMatrix(exgb); logger.info("exgb t2 = {}", t2); } exgb = minimalExtendedGB(F.size(), G, G2F); G = exgb.G; G2F = exgb.G2F; logger.debug("#sequential list = {}", G.size()); logger.info("{}", pairlist); // setup matrices F and F2G for (GenPolynomial f : F) { row = blas.genVector(G.size(), null); H = red.normalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero H = {}", H); } F2G.add(row); } exgb = new ExtendedGB(F, G, F2G, G2F); if (debug) { logger.info("exgb nonmin = {}", exgb); boolean t2 = isReductionMatrix(exgb); logger.info("exgb t2 = {}", t2); } return exgb; } } java-algebra-system-2.7.200/src/edu/jas/gb/GroebnerBaseSigSeqIter.java000066400000000000000000000316751445075545500254240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; /** * Groebner Base signature based sequential iterative algorithm. Implements * Groebner bases after the paper "Signature-based Algorithms to Compute Gröbner * Bases" by Christian Eder and John Perry, ISSAC 2011. Compare the jython+JAS * code in examples/basic_sigbased_gb.py. Originally the Python+Sage code is * from http://www.math.usm.edu/perry/Research/basic_sigbased_gb.py * * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory * @see edu.jas.gb.GroebnerBaseGGVSigSeqIter * @see edu.jas.gb.GroebnerBaseArriSigSeqIter * @see edu.jas.gb.GroebnerBaseF5zSigSeqIter */ public class GroebnerBaseSigSeqIter> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseSigSeqIter.class); private static final boolean debug = logger.isDebugEnabled(); final SigReductionSeq sred; /** * Constructor. */ public GroebnerBaseSigSeqIter() { this(new SigReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseSigSeqIter(SigReductionSeq red) { super(); sred = red; } /** * Groebner base signature iterative algorithm. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G.size() <= 1) { return G; } // sort, no reverse // G = OrderedPolynomialList. sort(G); G = OrderedPolynomialList. sortDegree(G); //no: Collections.reverse(G); logger.info("G-sort = {}", G); List> Gp = new ArrayList>(); for (GenPolynomial p : G) { if (logger.isInfoEnabled()) { logger.info("p = {}", p); } GenPolynomial pp = red.normalform(Gp, p); if (pp.isZERO()) { continue; } Gp = GB(modv, Gp, p); if (Gp.size() > 0) { if (Gp.get(0).isONE()) { return Gp; } } } return Gp; } /** * Groebner base iterated. * @param modv module variable number. * @param G polynomial list of a Groebner base. * @param f polynomial. * @return GB(G,f) a Groebner base of G+(f). */ public List> GB(int modv, List> G, GenPolynomial f) { List> F = new ArrayList>(G); GenPolynomial g = f.monic(); if (F.isEmpty()) { F.add(g); return F; // commutative } if (g.isZERO()) { return F; } if (g.isONE()) { F.clear(); F.add(g); return F; } GenPolynomialRing ring = F.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } if (modv != 0) { throw new UnsupportedOperationException("motv != 0 not implemented"); } // add signatures List> Gs = new ArrayList>(); for (GenPolynomial p : F) { Gs.add(new SigPoly(ring.getZERO(), p)); } SigPoly gs = new SigPoly(ring.getONE(), g); Gs.add(gs); //logger.info("Gs = {}", Gs); // construct critical pair list List> pairlist = new ArrayList>(); for (SigPoly p : Gs) { // F via continue if (p.poly.equals(g)) { continue; } pairlist.add(newPair(gs, p, Gs)); } //logger.info("start {}", pairlist.size()); logger.info("start {}", Gs); List syz = initializeSyz(F, Gs); List> done = new ArrayList>(); SigPair pair; //SigPoly pi, pj; GenPolynomial S, H, sigma; while (!pairlist.isEmpty()) { pairlist = pruneP(pairlist, syz); if (pairlist.isEmpty()) { continue; } List>[] spl = sred.minDegSubset(pairlist); List> Sl = spl[0]; long mdeg = sred.minimalSigDegree(Sl); pairlist = spl[1]; logger.info("treating {} signatures of degree {}", Sl.size(), mdeg); //logger.info("Sl({}) = {}", mdeg, Sl); while (!Sl.isEmpty()) { //logger.info("Sl_full = {}", sred.sigmas(Sl)); Sl = pruneS(Sl, syz, done, Gs); if (Sl.isEmpty()) { continue; } Sl = sred.sortSigma(Sl); //logger.info("Sl_sort = {}", Sl); pair = Sl.remove(0); if (pair == null) { continue; } //logger.info("sigma = {}", pair.sigma); S = SPolynomial(pair); SigPoly Ss = new SigPoly(pair.sigma, S); if (S.isZERO()) { updateSyz(syz, Ss); done.add(Ss); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } SigPoly Hs = sigNormalform(F, Gs, Ss); H = Hs.poly; sigma = Hs.sigma; if (debug) { logger.info("new polynomial = {}", Hs); //.leadingExpVector() ); } if (H.isZERO()) { updateSyz(syz, Hs); done.add(Hs); continue; } H = H.monic(); if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } if (H.isONE()) { G.clear(); G.add(H); logger.info("end {}", pairlist); return G; // since no threads are activated } if (sred.isSigRedundant(Gs, Hs)) { continue; } if (logger.isInfoEnabled()) { //logger.info("sigma::h = {} :: {}", sigma, ring.toScript(H.leadingExpVector())); logger.info("sigma::h = {} :: {}", sigma, H.leadingExpVector()); } if (H.length() > 0) { for (SigPoly p : Gs) { if (p.poly.isZERO()) { continue; } GenPolynomial tau = p.sigma; GenPolynomial[] mult = SPolynomialFactors(Hs, p); //System.out.print("sigma = " + sigma + " + tau = " + tau); //System.out.println(", mult = " + Arrays.toString(mult)); ExpVector se = sigma.leadingExpVector(); ExpVector te = tau.leadingExpVector(); if (mult[0].multiply(se).equals(mult[1].multiply(te))) { //logger.info("skip by sigma"); continue; } SigPair pp; //boolean xy = mult[0].multiply(se).compareTo(mult[1].multiply(te)) > 0; if (mult[0].multiply(se).compareTo(mult[1].multiply(te)) > 0) { pp = newPair(sigma.multiply(mult[0]), Hs, p, Gs); } else { pp = newPair(tau.multiply(mult[1]), p, Hs, Gs); } //System.out.println("new_pair " + pp.sigma + ", xy = " + xy + ", sigma = " + sigma + ", tau = " + tau + ", mult = " + Arrays.toString(mult) + ", m0*se = " + mult[0].multiply(se) + ", m1*te = " + mult[1].multiply(te) ); if (pp.sigma.degree() == mdeg) { // mdeg is sigma.degree() Sl.add(pp); // do not check contains } else { pairlist.add(pp); // do not check contains } } Gs.add(Hs); done.add(Hs); } } } logger.info("#sequential list before reduction = {}", Gs.size()); List> Gp = sred.polys(Gs); //logger.info("G_full = {}", Gp); G = minimalGB(Gp); //G = red.irreducibleSet(Gp); //G = OrderedPolynomialList. sortDegree(G); //logger.info("G_reduced = {}", G); logger.info("end {}", pairlist); return G; } /** * S-Polynomial. * @param A monic polynomial. * @param B monic polynomial. * @return spol(A,B) the S-polynomial of the A and B. */ GenPolynomial SPolynomial(SigPoly A, SigPoly B) { return sred.SPolynomial(A, B); } /** * S-Polynomial. * @param P pair. * @return spol(A,B) the S-polynomial of the pair (A,B). */ GenPolynomial SPolynomial(SigPair P) { return sred.SPolynomial(P.pi, P.pj); } /** * S-Polynomial polynomial factors. * @param A monic polynomial. * @param B monic polynomial. * @return polynomials [e,f] such that spol(A,B) = e*a - f*B. */ GenPolynomial[] SPolynomialFactors(SigPoly A, SigPoly B) { return sred.SPolynomialFactors(A, B); } /** * Pair with signature. * @param A polynomial with signature. * @param B polynomial with signature. * @param G polynomial ith signature list. * @return signature pair according to algorithm. */ SigPair newPair(SigPoly A, SigPoly B, List> G) { ExpVector e = A.poly.leadingExpVector().lcm(B.poly.leadingExpVector()) .subtract(A.poly.leadingExpVector()); return new SigPair(e, A, B, G); } /** * Pair with signature. * @param s signature for pair. * @param A polynomial with signature. * @param B polynomial with signature. * @param G polynomial ith signature list. * @return signature pair according to algorithm. */ SigPair newPair(GenPolynomial s, SigPoly A, SigPoly B, List> G) { return new SigPair(s, A, B, G); } /** * Top normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ SigPoly sigNormalform(List> F, List> G, SigPoly A) { return sred.sigNormalform(F, G, A); } /** * Prune total pair list P. * @param P pair list. * @param syz list of exponent vectors representing syzygies. * @return updated pair list. */ List> pruneP(List> P, List syz) { if (debug) { logger.debug("unused {}", syz); } return P; } /** * Prune pair list of degree d. * @param S pair list. * @param syz list of exponent vectors representing syzygies. * @param done list of treated polynomials. * @param G polynomial with signature list. * @return updated pair list. */ List> pruneS(List> S, List syz, List> done, List> G) { if (debug) { logger.debug("unused {} {} {}", syz, done, G); } return S; } /** * Initializes syzygy list. * @param F polynomial list. * @param G polynomial with signature list. * @return list of exponent vectors representing syzygies. */ List initializeSyz(List> F, List> G) { if (debug) { logger.debug("unused {} {}", G, F); } List P = new ArrayList(); return P; } /** * Update syzygy list. * @param syz list of exponent vectors representing syzygies. * @param r polynomial. Note: szy is modified to represent updated * list of exponent vectors. */ void updateSyz(List syz, SigPoly r) { if (debug) { logger.debug("unused {} {}", syz, r); } return; } } java-algebra-system-2.7.200/src/edu/jas/gb/Katsura.java000066400000000000000000000105121445075545500225230ustar00rootroot00000000000000/* * Created on 03.10.2004 * $Id$ */ package edu.jas.gb; /** * Class to produce a system of equations as defined by Katsura. * * @author Heinz Kredel * */ public class Katsura { /** * main. */ public static void main(String[] args) { if ( args.length == 0 ) { System.out.println("usage: Katsura N "); return; } int n = Integer.parseInt(args[0]); Katsura k = null; if ( args.length == 1 ) { k = new Katsura(n); } if ( args.length == 2 ) { k = new Katsura("u",n, args[1]); } if ( args.length == 3 ) { k = new Katsura(args[2],n, args[1]); } System.out.println("#Katsura equations for N = " + n + ":"); System.out.println("" + k); } final int N; final String var; final String order; /** * Katsura constructor. * @param n problem size. */ public Katsura(int n) { this("u", n); } /** * Katsura constructor. * @param v name of variables. * @param n problem size. */ public Katsura(String v, int n) { this(v, n, "G"); } /** * Katsura constructor. * @param var name of variables. * @param n problem size. * @param order term order letter for output. */ public Katsura(String var, int n, String order) { this.var = var; this.N = n; this.order = order; } String sum1() { StringBuffer s = new StringBuffer(); for (int i = -N; i <= N; i++) { s.append(variable(i)); if (i < N) { s.append(" + "); } } s.append(" - 1"); return s.toString(); } String sumUm(int m) { StringBuffer s = new StringBuffer(); for (int i = -N; i <= N; i++) { s.append(variable(i)); s.append("*"); s.append(variable(m - i)); if (i < N) { s.append(" + "); } } s.append(" - " + variable(m)); return s.toString(); } /** * Generate variable list. * @param order term order letter. * @return polynomial ring description. */ public String varList(String order) { return varList("Rat",order); } /** * Generate variable list. * @param order term order letter. * @param coeff coefficient ring name. * @return polynomial ring description. */ public String varList(String coeff, String order) { StringBuffer s = new StringBuffer(); s.append(coeff); s.append("("); // for (int i = 0; i <= N; i++) { for (int i = N; i >=0; i--) { s.append(variable(i)); if (i > 0) { s.append(","); } } s.append(") "); s.append(order); return s.toString(); } /** * toString. * @return Katsura problem as string. */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(varList(order)); s.append(System.getProperty("line.separator")); s.append(polyList()); return s.toString(); } /** * Generate polynomial list. * @return Katsura polynomials as string. */ public String polyList() { StringBuffer s = new StringBuffer(); s.append("("+System.getProperty("line.separator")); //for (int m = -N + 1; m <= N - 1; m++) { doubles polynomials for (int m = 0; m <= N - 1; m++) { s.append( sumUm(m) ); s.append(","+System.getProperty("line.separator")); } s.append( sum1() ); s.append(System.getProperty("line.separator")); s.append(")"+System.getProperty("line.separator")); return s.toString(); } /** * Generate variable string. * @return variable name as string. */ String variable(int i) { if (i < 0) { return variable(-i); } if (i > N) { return "0"; } return var + i; } } java-algebra-system-2.7.200/src/edu/jas/gb/MiReducerServer.java000066400000000000000000000053001445075545500241560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.util.concurrent.Semaphore; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Distributed server reducing worker threads for minimal GB Not jet distributed * but threaded. */ class MiReducerServer> implements Runnable { private final List> G; private GenPolynomial H; private final Semaphore done = new Semaphore(0); private final Reduction red; private static final Logger logger = LogManager.getLogger(MiReducerServer.class); MiReducerServer(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } /** * Distributed clients reducing worker threads for minimal GB. Note: Not * jet used. */ class MiReducerClient> implements Runnable { private final List> G; private GenPolynomial H; private final Reduction red; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(MiReducerClient.class); MiReducerClient(List> G, GenPolynomial p) { this.G = G; H = p; red = new ReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException u) { Thread.currentThread().interrupt(); } return H; } public void run() { if (logger.isDebugEnabled()) { logger.debug("ht(S) = {}", H.leadingExpVector()); } H = red.normalform(G, H); //mod done.release(); //done.V(); if (logger.isDebugEnabled()) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/OrderedDPairlist.java000066400000000000000000000121311445075545500243100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Pair list management for d-Groebner bases. * Implemented using GenPolynomial, TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedDPairlist > extends OrderedPairlist { private static final Logger logger = LogManager.getLogger(OrderedDPairlist.class); protected final DReduction dreduction; /** * Constructor for OrderedDPairlist. * @param r polynomial factory. */ public OrderedDPairlist(GenPolynomialRing r) { this(0,r); } /** * Constructor for OrderedDPairlist. * @param m number of module variables. * @param r polynomial factory. */ public OrderedDPairlist(int m, GenPolynomialRing r) { super(m,r); dreduction = new DReductionSeq(); } /** * Create a new PairList. * @param r polynomial ring. */ public PairList create(GenPolynomialRing r) { return new OrderedDPairlist(r); } /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ public PairList create(int m, GenPolynomialRing r) { return new OrderedDPairlist(m,r); } /** * Remove the next required pair from the pairlist and reduction matrix. * The results of the application of the criterions 3 and 4 to see if the S-polynomial * is required are recorded in the Pair. * @return the next pair if one exists, otherwise null. */ @Override public synchronized Pair removeNext() { if ( oneInGB ) { return null; } Iterator< Map.Entry>> > ip = pairlist.entrySet().iterator(); Pair pair = null; boolean c = false; int i, j; if ( ip.hasNext() ) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); if ( logger.isInfoEnabled() ) { logger.info("g = {}", g); } pair = null; if ( xl.size() > 0 ) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); if ( useCriterion4 ) { c = dreduction.criterion4( pair.pi, pair.pj, g ); } else { c = true; } pair.setUseCriterion4(c); //System.out.println("c4 = " + c); if ( c ) { c = criterion3( i, j, g ); //System.out.println("c3 = " + c); pair.setUseCriterion3(c); } red.get( j ).clear(i); // set(i,false) jdk1.4 } if ( xl.size() == 0 ) { ip.remove(); // = pairlist.remove( g ); } } remCount++; // count pairs return pair; } /** * GB criterium 3 with coefficient division test. * @return true if the S-polynomial(i,j) is required. */ @Override public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s; s = red.get( j ).get(i); if ( ! s ) { logger.warn("c3.s false for j, i = {}, {}", j, i); return s; } s = true; boolean m; GenPolynomial A; ExpVector ek; C ci = P.get(i).leadingBaseCoefficient(); C cj = P.get(j).leadingBaseCoefficient(); C c = ci.gcd(cj); for ( int k = 0; k < P.size(); k++ ) { A = P.get( k ); ek = A.leadingExpVector(); m = eij.multipleOf(ek); if ( m ) { C ck = A.leadingBaseCoefficient(); C r = c.remainder(ck); m = r.isZERO(); } if ( m ) { if ( k < i ) { // System.out.println("k < i "+k+" "+i); s = red.get( i ).get(k) || red.get( j ).get(k); } if ( i < k && k < j ) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get( k ).get(i) || red.get( j ).get(k); } if ( j < k ) { //System.out.println("j < k "+j+" "+k); s = red.get( k ).get(i) || red.get( k ).get(j); } //System.out.println("s."+k+" = " + s); if ( ! s ) return s; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gb/OrderedMinPairlist.java000066400000000000000000000160371445075545500246610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Pair list management. The original Buchberger algorithm with criterions using * early pair exclusion. Implemented using GenPolynomial, TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedMinPairlist> extends OrderedPairlist { private static final Logger logger = LogManager.getLogger(OrderedMinPairlist.class); /** * Constructor. */ public OrderedMinPairlist() { super(); } /** * Constructor. * @param r polynomial factory. */ public OrderedMinPairlist(GenPolynomialRing r) { this(0, r); } /** * Constructor. * @param m number of module variables. * @param r polynomial factory. */ public OrderedMinPairlist(int m, GenPolynomialRing r) { super(m, r); } /** * Create a new PairList. * @param r polynomial ring. */ @Override public PairList create(GenPolynomialRing r) { return new OrderedMinPairlist(r); } /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ @Override public PairList create(int m, GenPolynomialRing r) { return new OrderedMinPairlist(m, r); } /** * Put one Polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ @Override public synchronized int put(GenPolynomial p) { putCount++; if (oneInGB) { return P.size() - 1; } ExpVector e = p.leadingExpVector(); int l = P.size(); BitSet redi = new BitSet(); redi.set(0, l); // [0..l-1] = true red.add(redi); P.add(p); for (int j = 0; j < l; j++) { GenPolynomial pj = P.get(j); ExpVector f = pj.leadingExpVector(); if (moduleVars > 0) { if (!reduction.moduleCriterion(moduleVars, e, f)) { red.get(j).clear(l); continue; // skip pair } } ExpVector g = e.lcm(f); //System.out.println("g = " + g); Pair pair = new Pair(pj, p, j, l); boolean c = true; if (useCriterion4) { c = reduction.criterion4(pair.pi, pair.pj, g); } //System.out.println("c4 = " + c); if (c) { c = criterion3(j, l, g); //System.out.println("c3 = " + c); } if (!c) { // skip pair red.get(j).clear(l); //System.out.println("c_skip = " + g); continue; } //multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); } // System.out.println("pairlist.keys@put = " + pairlist.keySet() ); return P.size() - 1; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ @Override public synchronized Pair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); Pair pair = null; boolean c = false; int i, j; while (!c && ip.hasNext()) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); if (logger.isInfoEnabled()) { logger.info("g = {}", g); } pair = null; while (!c && xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); if (!red.get(j).get(i)) { System.out.println("c_y = " + g); // + ", " + red.get(j).get(i)); continue; } c = true; if (useCriterion4) { c = reduction.criterion4(pair.pi, pair.pj, g); } //System.out.println("c4_x = " + c); if (c) { c = criterion3(i, j, g); //System.out.println("c3_x = " + c); } if (!c) { //System.out.println("c_x = " + g); } red.get(j).clear(i); // set(i,false) jdk1.4 } if (xl.size() == 0) { ip.remove(); // = pairlist.remove( g ); } } if (!c) { pair = null; } else { pair.maxIndex(P.size() - 1); remCount++; // count only real pairs if (logger.isDebugEnabled()) { logger.info("pair({},{})", pair.j, pair.i); } } return pair; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ @Override public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s; s = red.get(j).get(i); if (!s) { logger.warn("c3.s false for j, i = {}, {}", j, i); return s; } s = true; boolean m; GenPolynomial A; ExpVector ek; for (int k = 0; k < P.size(); k++) { A = P.get(k); ek = A.leadingExpVector(); m = eij.multipleOf(ek) && eij.compareTo(ek) != 0; if (m) { if (k < i) { // System.out.println("k < i "+k+" "+i); s = red.get(i).get(k) || red.get(j).get(k); } if (i < k && k < j) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get(k).get(i) || red.get(j).get(k); } if (j < k) { //System.out.println("j < k "+j+" "+k); s = red.get(k).get(i) || red.get(k).get(j); } //System.out.println("s."+k+" = " + s); if (!s) return s; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gb/OrderedPairlist.java000066400000000000000000000253301445075545500242110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Pair list management. The original Buchberger algorithm with criterions * following Winkler in SAC-1, Kredel in ALDES/SAC-2, Kredel in MAS. Implemented * using GenPolynomial, TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedPairlist> implements PairList { protected final List> P; protected final SortedMap>> pairlist; protected final List red; protected final GenPolynomialRing ring; protected final Reduction reduction; protected boolean oneInGB = false; protected boolean useCriterion4 = true; protected int putCount; protected int remCount; protected final int moduleVars; private static final Logger logger = LogManager.getLogger(OrderedPairlist.class); /** * Constructor. */ public OrderedPairlist() { moduleVars = 0; ring = null; P = null; pairlist = null; red = null; reduction = null; putCount = 0; remCount = 0; } /** * Constructor. * @param r polynomial factory. */ public OrderedPairlist(GenPolynomialRing r) { this(0, r); } /** * Constructor. * @param m number of module variables. * @param r polynomial factory. */ public OrderedPairlist(int m, GenPolynomialRing r) { moduleVars = m; ring = r; P = new ArrayList>(); pairlist = new TreeMap>>(ring.tord.getAscendComparator()); //pairlist = new TreeMap( to.getSugarComparator() ); red = new ArrayList(); putCount = 0; remCount = 0; if (!ring.isCommutative()) {//ring instanceof GenSolvablePolynomialRing ) { useCriterion4 = false; } reduction = new ReductionSeq(); } /** * Create a new PairList. * @param r polynomial ring. */ public PairList create(GenPolynomialRing r) { return new OrderedPairlist(r); } /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ public PairList create(int m, GenPolynomialRing r) { return new OrderedPairlist(m, r); } /** * Get polynomial ring. * @return the polynomial ring. */ public GenPolynomialRing getRing() { return ring; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer(this.getClass().getSimpleName() + "("); //s.append("polys="+P.size()); s.append("#put=" + putCount); s.append(", #rem=" + remCount); if (pairlist != null && pairlist.size() != 0) { s.append(", size=" + pairlist.size()); } if (moduleVars > 0) { s.append(", modv=" + moduleVars); } s.append(")"); return s.toString(); } /** * Put one Polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ public synchronized int put(GenPolynomial p) { putCount++; if (oneInGB) { return P.size() - 1; } ExpVector e = p.leadingExpVector(); int l = P.size(); for (int j = 0; j < l; j++) { GenPolynomial pj = P.get(j); ExpVector f = pj.leadingExpVector(); if (moduleVars > 0) { if (!reduction.moduleCriterion(moduleVars, e, f)) { continue; // skip pair } } ExpVector g = e.lcm(f); Pair pair = new Pair(pj, p, j, l); //System.out.println("pair.new = " + pair); //multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); } //System.out.println("pairlist.keys@put = " + pairlist.keySet() ); P.add(p); BitSet redi = new BitSet(); redi.set(0, l); red.add(redi); //System.out.println("pairlist.red = " + red); //.get( pair.j )); //pair); //System.out.println("pairlist.key = " + pairlist.keySet() ); return P.size() - 1; } /** * Put all polynomials in F to the pairlist and reduction matrix. * @param F polynomial list. * @return the index of the last added polynomial. */ public int put(List> F) { int i = 0; for (GenPolynomial p : F) { i = put(p); } return i; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ public synchronized Pair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); Pair pair = null; boolean c = false; int i, j; while (!c && ip.hasNext()) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); if (logger.isInfoEnabled()) { logger.info("g = {}", g); } pair = null; while (!c && xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); if (useCriterion4) { c = reduction.criterion4(pair.pi, pair.pj, g); } else { c = true; } //System.out.println("c4_o = " + c); if (c) { c = criterion3(i, j, g); //System.out.println("c3_o = " + c); } red.get(j).clear(i); // set(i,false) jdk1.4 } if (xl.size() == 0) { ip.remove(); // = pairlist.remove( g ); } } if (!c) { pair = null; } else { pair.maxIndex(P.size() - 1); remCount++; // count only real pairs if (logger.isDebugEnabled()) { logger.info("pair({},{})", pair.j, pair.i); } } return pair; } /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public synchronized boolean hasNext() { return pairlist.size() > 0; } /** * Get the list of polynomials. * @return the polynomial list. */ public List> getList() { return P; } /** * Set the list of polynomials. * @param F the polynomial list. */ public void setList(List> F) { if (!P.isEmpty()) { throw new IllegalArgumentException("P not empty"); } P.addAll(F); for (int i = 0; i < P.size(); i++) { BitSet redi = new BitSet(); red.add(redi); } } /** * Get the size of the list of polynomials. * @return size of the polynomial list. */ public int size() { return P.size(); } /** * Get the number of polynomials put to the pairlist. * @return the number of calls to put. */ public synchronized int putCount() { return putCount; } /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public synchronized int remCount() { return remCount; } /** * Put the ONE-Polynomial to the pairlist. * @param one polynomial. (no more required) * @return the index of the last polynomial. */ public synchronized int putOne(GenPolynomial one) { if (one == null) { return P.size() - 1; } if (!one.isONE()) { return P.size() - 1; } return putOne(); } /** * Put the ONE-Polynomial to the pairlist. * @return the index of the last polynomial. */ public synchronized int putOne() { putCount++; oneInGB = true; pairlist.clear(); P.clear(); P.add(ring.getONE()); red.clear(); logger.info("outOne {}", this); return P.size() - 1; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s = red.get(j).get(i); if (!s) { logger.warn("c3.s false for j, i = {}, {}", j, i); return s; } // now s = true; for (int k = 0; k < P.size(); k++) { // System.out.println("i , k , j "+i+" "+k+" "+j); if (i != k && j != k) { GenPolynomial A = P.get(k); ExpVector ek = A.leadingExpVector(); boolean m = eij.multipleOf(ek); if (m) { if (k < i) { // System.out.println("k < i "+k+" "+i); s = red.get(i).get(k) || red.get(j).get(k); } else if (i < k && k < j) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get(k).get(i) || red.get(j).get(k); } else if (j < k) { //System.out.println("j < k "+j+" "+k); s = red.get(k).get(i) || red.get(k).get(j); } //System.out.println("s."+k+" = " + s); if (!s) { return s; } } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gb/OrderedSyzPairlist.java000066400000000000000000000232561445075545500247240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Pair list management. For the Buchberger algorithm following the syzygy * criterions by Gebauer & Möller. Implemented using GenPolynomial, * TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedSyzPairlist> extends OrderedPairlist { private static final Logger logger = LogManager.getLogger(OrderedSyzPairlist.class); /** * Constructor. */ public OrderedSyzPairlist() { super(); } /** * Constructor. * @param r polynomial factory. */ public OrderedSyzPairlist(GenPolynomialRing r) { this(0, r); } /** * Constructor. * @param m number of module variables. * @param r polynomial factory. */ public OrderedSyzPairlist(int m, GenPolynomialRing r) { super(m, r); } /** * Create a new PairList. * @param r polynomial ring. */ @Override public PairList create(GenPolynomialRing r) { return new OrderedSyzPairlist(r); } /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ @Override public PairList create(int m, GenPolynomialRing r) { return new OrderedSyzPairlist(m, r); } /** * Put one Polynomial to the pairlist and reduction matrix. Removes all * unnecessary pairs identified by the syzygy criterion and criterion 4. * @param p polynomial. * @return the index of the added polynomial. */ @Override public synchronized int put(GenPolynomial p) { putCount++; if (oneInGB) { return P.size() - 1; } ExpVector e = p.leadingExpVector(); int ps = P.size(); BitSet redi = new BitSet(); // all zeros //redi.set( 0, ps ); // [0..ps-1] = true, i.e. all ones red.add(redi); P.add(p); // remove from existing pairs: List es = new ArrayList(); for (Map.Entry>> me : pairlist.entrySet()) { ExpVector g = me.getKey(); if (moduleVars > 0) { if (!reduction.moduleCriterion(moduleVars, e, g)) { continue; // skip pair } } ExpVector ge = g.lcm(e); LinkedList> ll = me.getValue(); if (g.compareTo(ge) == 0) { LinkedList> lle = new LinkedList>(); for (Pair pair : ll) { ExpVector eil = pair.pi.leadingExpVector().lcm(e); if (g.compareTo(eil) == 0) { continue; } ExpVector ejl = pair.pj.leadingExpVector().lcm(e); if (g.compareTo(ejl) == 0) { continue; } // g == ge && g != eil && g != ejl red.get(pair.j).clear(pair.i); lle.add(pair); } if (lle.size() > 0) { for (Pair pair : lle) { ll.remove(pair); } if (!es.contains(g)) { es.add(g); } } } } for (ExpVector ei : es) { LinkedList> ll = pairlist.get(ei); if (ll != null && ll.size() == 0) { ll = pairlist.remove(ei); } } // generate new pairs: SortedMap>> npl = new TreeMap>>( ring.tord.getAscendComparator()); for (int j = 0; j < ps; j++) { GenPolynomial pj = P.get(j); ExpVector f = pj.leadingExpVector(); if (moduleVars > 0) { if (!reduction.moduleCriterion(moduleVars, e, f)) { //red.get(j).clear(l); continue; // skip pair } } ExpVector g = e.lcm(f); Pair pair = new Pair(pj, p, j, ps); //System.out.println("pair.new = " + pair); //multiple pairs under same keys -> list of pairs LinkedList> xl = npl.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs npl.put(g, xl); } //System.out.println("npl.new = " + npl.keySet()); // skip by divisibility: es = new ArrayList(npl.size()); for (ExpVector eil : npl.keySet()) { for (ExpVector ejl : npl.keySet()) { if (eil.compareTo(ejl) == 0) { continue; } if (eil.multipleOf(ejl)) { if (!es.contains(eil)) { es.add(eil); } } } } //System.out.println("npl.skip div = " + es); for (ExpVector ei : es) { @SuppressWarnings("unused") LinkedList> ignored = npl.remove(ei); } // skip by criterion 4: if (useCriterion4) { es = new ArrayList(npl.size()); for (Map.Entry>> me : npl.entrySet()) { ExpVector ei = me.getKey(); LinkedList> exl = me.getValue(); //npl.get( ei ); //System.out.println("exl = " + exl ); boolean c = true; for (Pair pair : exl) { c = c && reduction.criterion4(pair.pi, pair.pj, pair.e); } if (c) { if (exl.size() > 1) { Pair pair = exl.getFirst(); // or exl.getLast(); exl.clear(); exl.add(pair); //npl.put(ei,exl); } } else { if (!es.contains(ei)) { es.add(ei); } } } //System.out.println("npl.skip c4 = " + es); for (ExpVector ei : es) { @SuppressWarnings("unused") LinkedList> ignored = npl.remove(ei); } } // add to existing pairlist: //System.out.println("npl.put new = " + npl.keySet() ); for (Map.Entry>> me : npl.entrySet()) { ExpVector ei = me.getKey(); LinkedList> exl = me.getValue(); //npl.get( ei ); for (Pair pair : exl) { red.get(pair.j).set(pair.i); } LinkedList> ex = pairlist.get(ei); // wrong in findbugs if (ex != null) { exl.addAll(ex); // add new pairs first ex = exl; //ex.addAll(exl); // add old pairs first } else { ex = exl; } pairlist.put(ei, ex); // replace ex } return P.size() - 1; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ @Override public synchronized Pair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); Pair pair = null; //boolean c = false; int i, j; while (ip.hasNext()) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); if (logger.isInfoEnabled()) logger.info("g = {}", g); pair = null; while (xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; //System.out.println("pair.remove = " + pair ); if (!red.get(j).get(i)) { // should not happen logger.warn("c_red.get({}).get({}) = {}", j, i, g); pair = null; continue; } red.get(j).clear(i); break; } if (xl.size() == 0) { ip.remove(); // = pairlist.remove( g ); } if (pair != null) { break; } } if (pair != null) { pair.maxIndex(P.size() - 1); remCount++; // count only real pairs if (logger.isDebugEnabled()) { logger.info("pair({},{})", pair.j, pair.i); } } return pair; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ @Override public boolean criterion3(int i, int j, ExpVector eij) { throw new UnsupportedOperationException("not used in " + this.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/gb/OrderedWordPairlist.java000066400000000000000000000246141445075545500250510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Pair list management of word polynomials. Implemented using * GenWordPolynomial, TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedWordPairlist> implements WordPairList { protected final List> P; protected final SortedMap>> pairlist; protected final List red; protected final GenWordPolynomialRing ring; protected final WordReduction reduction; protected boolean oneInGB = false; protected int putCount; protected int remCount; private static final Logger logger = LogManager.getLogger(OrderedWordPairlist.class); /** * Constructor. */ public OrderedWordPairlist() { ring = null; P = null; pairlist = null; red = null; reduction = null; putCount = 0; remCount = 0; } /** * Constructor. * @param r word polynomial factory. */ public OrderedWordPairlist(GenWordPolynomialRing r) { ring = r; P = new ArrayList>(); pairlist = new TreeMap>>(ring.alphabet.getAscendComparator()); red = new ArrayList(); putCount = 0; remCount = 0; reduction = new WordReductionSeq(); } /** * Create a new WordPairList. * @param r word polynomial ring. */ public WordPairList create(GenWordPolynomialRing r) { return new OrderedWordPairlist(r); } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer(this.getClass().getSimpleName() + "("); //s.append("polys="+P.size()); s.append("#put=" + putCount); s.append(", #rem=" + remCount); if (pairlist != null && pairlist.size() != 0) { s.append(", size=" + pairlist.size()); } //if (red != null ) { // s.append(", bitmask=" + red); //} s.append(")"); return s.toString(); } /** * Put one Polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ public synchronized int put(GenWordPolynomial p) { putCount++; if (oneInGB) { return P.size() - 1; } if (p.isONE()) { return putOne(); } Word e = p.leadingWord(); Word g; int l = P.size(); BitSet redi = new BitSet(); //redi.set(0, l); // from -- to for (int j = 0; j < l; j++) { GenWordPolynomial pj = P.get(j); Word f = pj.leadingWord(); // pj, p g = f.lcm(e); //System.out.println("g(f,g) = " + g); if (g != null) { WordPair pair = new WordPair(pj, p, j, l); //System.out.println("pair.new = " + pair); //multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); redi.set(j); // = red.get(l).set(j); } // p, pj g = e.lcm(f); //System.out.println("g(e,f) = " + g); if (g != null) { WordPair pair = new WordPair(p, pj, l, j); //System.out.println("pair.new = " + pair); //multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); red.get(j).set(l); } } red.add(redi); //System.out.println("pairlist.keys@put = " + pairlist.keySet() ); //System.out.println("#pairlist = " + pairlist.size() ); P.add(p); //System.out.println("pairlist.key = " + pairlist.keySet() ); return l; //P.size() - 1; } /** * Put all word polynomials in F to the pairlist and reduction matrix. * @param F word polynomial list. * @return the index of the last added word polynomial. */ public int put(List> F) { //System.out.println("pairlist.F = " + F ); int i = 0; for (GenWordPolynomial p : F) { i = put(p); } return i; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterion 3 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ public synchronized WordPair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); WordPair pair = null; //boolean c = false; int i, j; //while (!c && ip.hasNext()) { if (ip.hasNext()) { Map.Entry>> me = ip.next(); Word g = me.getKey(); LinkedList> xl = me.getValue(); if (logger.isInfoEnabled()) { logger.info("g = {}", g); } pair = null; //while (!c && xl.size() > 0) { if (xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); //c = criterion3(i, j, g); // to check //if ( !c ) { // System.out.println("criterion 3"); //} red.get(j).clear(i); } if (xl.size() == 0) { ip.remove(); } } //if (!c) { // pair = null; //} else { remCount++; // count only real pairs //} return pair; } /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public synchronized boolean hasNext() { return pairlist.size() > 0; } /** * Get the list of polynomials. * @return the polynomial list. */ public List> getList() { return P; } /** * Get the number of polynomials put to the pairlist. * @return the number of calls to put. */ public synchronized int putCount() { return putCount; } /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public synchronized int remCount() { return remCount; } /** * Put the ONE-Polynomial to the pairlist. * @param one polynomial. (no more required) * @return the index of the last polynomial. */ public synchronized int putOne(GenWordPolynomial one) { if (one == null) { return P.size() - 1; } if (!one.isONE()) { return P.size() - 1; } return putOne(); } /** * Put the ONE-Polynomial to the pairlist. * @return the index of the last polynomial. */ public synchronized int putOne() { putCount++; oneInGB = true; pairlist.clear(); P.clear(); P.add(ring.getONE()); red.clear(); return P.size() - 1; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ public boolean criterion3(int i, int j, Word eij) { boolean s = red.get(j).get(i); //if (s) { // logger.warn("c3.s true for j, i = {} {}", j, i); // //return s; //} for (int k = 0; k < P.size(); k++) { // System.out.println("i , k , j "+i+" "+k+" "+j); if (i != k && j != k) { GenWordPolynomial A = P.get(k); Word ek = A.leadingWord(); boolean m = eij.multipleOf(ek); if (m) { if (i < j) { if (k < i) { // System.out.println("k < i "+k+" "+i); s = red.get(i).get(k) || red.get(j).get(k); } else if (i < k && k < j) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get(k).get(i) || red.get(j).get(k); } else if (j < k) { //System.out.println("j < k "+j+" "+k); s = red.get(k).get(i) || red.get(k).get(j); } } else { // j < i if (k < j) { //System.out.println("k < j "+k+" "+j); s = red.get(k).get(j) || red.get(k).get(i); } else if (j < k && k < i) { //System.out.println("j < k < i "+j+" "+k+" "+i); s = red.get(j).get(k) || red.get(k).get(i); } else if (i < k) { //System.out.println("i < k "+i+" "+k); s = red.get(j).get(k) || red.get(i).get(k); } } //System.out.println("s."+k+" = " + s); if (!s) { return s; } } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gb/Pair.java000066400000000000000000000107451445075545500220140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; /** * Serializable subclass to hold pairs of polynomials. * @param coefficient type * @author Heinz Kredel */ public class Pair > extends AbstractPair implements Comparable { protected int n; protected boolean toZero = false; protected boolean useCriterion4 = true; protected boolean useCriterion3 = true; /** * Pair constructor. * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. */ public Pair(GenPolynomial a, GenPolynomial b, int i, int j) { this(a,b,i,j,0); } /** * Pair constructor. * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. * @param s maximal index. */ public Pair(GenPolynomial a, GenPolynomial b, int i, int j, int s) { this(a.leadingExpVector().lcm(b.leadingExpVector()),a,b,i,j,s); } /** * Pair constructor. * @param lcm of lt(a) lt(b). * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. */ public Pair(ExpVector lcm, GenPolynomial a, GenPolynomial b, int i, int j) { this(lcm,a,b,i,j,0); } /** * Pair constructor. * @param lcm of lt(a) lt(b). * @param a polynomial i. * @param b polynomial j. * @param i first index. * @param j second index. * @param s maximal index. */ public Pair(ExpVector lcm, GenPolynomial a, GenPolynomial b, int i, int j, int s) { super(lcm,a,b,i,j,s); this.n = 0; toZero = false; // ok } /** * toString. */ @Override public String toString() { return super.toString() + "[" + n + ", r0=" + toZero + ", c4=" + useCriterion4 + ", c3=" + useCriterion3 + "]"; } /** * Set removed pair number. * @param n number of this pair generated in OrderedPairlist. */ public void pairNumber(int n) { this.n = n; } /** * Get removed pair number. * @return n number of this pair generated in OrderedPairlist. */ public int getPairNumber() { return n; } /** * Set zero reduction. * The S-polynomial of this Pair was reduced to zero. */ public void setZero() { toZero = true; } /** * Is reduced to zero. * @return true if the S-polynomial of this Pair was reduced to zero, else false. */ public boolean isZero() { return toZero; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override public boolean equals(Object ob) { if ( ! (ob instanceof Pair) ) { return false; // throw new ClassCastException("Pair "+n+" o "+o); } return 0 == compareTo( (Pair)ob ); } /** * compareTo used in TreeMap // not used at moment. * Comparison is based on the number of the pairs. * @param p a Pair. * @return 1 if (this < o), 0 if (this == o), -1 if (this > o). */ public int compareTo(Pair p) { int x = p.getPairNumber(); if ( n > x ) { return 1; } if ( n < x ) { return -1; } return 0; } /** * Hash code for this Pair. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (i << 16) + j; } /** * Set useCriterion4. * @param c boolean value to set. */ public void setUseCriterion4(boolean c) { this.useCriterion4 = c; } /** * Get useCriterion4. * @return boolean value. */ public boolean getUseCriterion4() { return this.useCriterion4; } /** * Set useCriterion3. * @param c boolean value to set. */ public void setUseCriterion3(boolean c) { this.useCriterion3 = c; } /** * Get useCriterion3. * @return boolean value. */ public boolean getUseCriterion3() { return this.useCriterion3; } } java-algebra-system-2.7.200/src/edu/jas/gb/PairList.java000066400000000000000000000053671445075545500226540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.io.Serializable; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; import edu.jas.poly.TermOrder; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; /** * Pair list management interface. * @author Heinz Kredel */ public interface PairList > extends Serializable { /** * Create a new PairList. * @param r polynomial ring. */ public PairList create(GenPolynomialRing r); /** * Create a new PairList. * @param m number of module variables. * @param r polynomial ring. */ public PairList create(int m, GenPolynomialRing r); /** * Get polynomial ring. * @return the polynomial ring. */ public GenPolynomialRing getRing(); /** * toString. */ @Override public String toString(); /** * Put one Polynomial to the pairlist and reduction matrix. * @param p polynomial. * @return the index of the added polynomial. */ public int put(GenPolynomial p); /** * Put all polynomials in F to the pairlist and reduction matrix. * @param F polynomial list. * @return the index of the last added polynomial. */ public int put(List> F); /** * Put to ONE-Polynomial to the pairlist. * @return the index of the last polynomial. */ public int putOne(); /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ public Pair removeNext(); /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public boolean hasNext(); /** * Get the size of the list of polynomials. * @return size of the polynomial list. */ public int size(); /** * Get the list of polynomials. * @return the polynomial list. */ public List> getList(); /** * Set the list of polynomials. * @param F the polynomial list. */ public void setList(List> F); /** * Get the number of polynomials put to the pairlist. * @return the number of calls to put. */ public int putCount(); /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public int remCount(); /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ public boolean criterion3(int i, int j, ExpVector eij); } java-algebra-system-2.7.200/src/edu/jas/gb/Reduction.java000066400000000000000000000121261445075545500230500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial Reduction interface. Defines S-Polynomial, normalform, criterion * 4, module criterion and irreducible set. * @param coefficient type * @author Heinz Kredel */ public interface Reduction> extends Serializable { /** * S-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return spol(Ap,Bp) the S-polynomial of Ap and Bp. */ public GenPolynomial SPolynomial(GenPolynomial Ap, GenPolynomial Bp); /** * S-Polynomial with recording. * @param S recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return Spol(Ap, Bp), the S-Polynomial for Ap and Bp. */ public GenPolynomial SPolynomial(List> S, int i, GenPolynomial Ap, int j, GenPolynomial Bp); /** * Module criterium. * @param modv number of module variables. * @param A polynomial. * @param B polynomial. * @return true if the module S-polynomial(i,j) is required. */ public boolean moduleCriterion(int modv, GenPolynomial A, GenPolynomial B); /** * Module criterium. * @param modv number of module variables. * @param ei ExpVector. * @param ej ExpVector. * @return true if the module S-polynomial(i,j) is required. */ public boolean moduleCriterion(int modv, ExpVector ei, ExpVector ej); /** * GB criterium 4. Use only for commutative polynomial rings. * @param A polynomial. * @param B polynomial. * @param e = lcm(ht(A),ht(B)) * @return true if the S-polynomial(i,j) is required, else false. */ public boolean criterion4(GenPolynomial A, GenPolynomial B, ExpVector e); /** * GB criterium 4. Use only for commutative polynomial rings. * @param A polynomial. * @param B polynomial. * @return true if the S-polynomial(i,j) is required, else false. */ public boolean criterion4(GenPolynomial A, GenPolynomial B); /** * GB criterium 4. * @param ei exponent vector. * @param ej exponent vector. * @param e = lcm(ei,ej) * @return true if the S-polynomial(i,j) is required, else false. */ public boolean criterion4(ExpVector ei, ExpVector ej, ExpVector e); /** * Is top reducible. Condition is lt(B) | lt(A) for some B in F. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, GenPolynomial A); /** * Is reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is reducible with respect to P. */ public boolean isReducible(List> P, GenPolynomial A); /** * Is in Normalform. * @param A polynomial. * @param P polynomial list. * @return true if A is in normalform with respect to P. */ public boolean isNormalform(List> P, GenPolynomial A); /** * Is in Normalform. * @param Pp polynomial list. * @return true if each A in Pp is in normalform with respect to Pp\{A}. */ public boolean isNormalform(List> Pp); /** * Normalform. * @param A polynomial. * @param P polynomial list. * @return nf(A) with respect to P. */ public GenPolynomial normalform(List> P, GenPolynomial A); /** * Normalform Set. * @param Ap polynomial list. * @param Pp polynomial list. * @return list of nf(a) with respect to Pp for all a in Ap. */ public List> normalform(List> Pp, List> Ap); /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap); /** * Irreducible set. * @param Pp polynomial list. * @return a list P of polynomials which are in normalform wrt. P and with * ideal(Pp) = ideal(P). */ public List> irreducibleSet(List> Pp); /** * Is reduction of normal form. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @param Np nf(Pp,Ap), a normal form of Ap wrt. Pp. * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false. */ public boolean isReductionNF(List> row, List> Pp, GenPolynomial Ap, GenPolynomial Np); } java-algebra-system-2.7.200/src/edu/jas/gb/ReductionAbstract.java000066400000000000000000000400411445075545500245310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.Monomial; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Polynomial Reduction abstract class. Implements common S-Polynomial, * normalform, criterion 4 module criterion and irreducible set. * @param coefficient type * @author Heinz Kredel */ public abstract class ReductionAbstract> implements Reduction { private static final Logger logger = LogManager.getLogger(ReductionAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public ReductionAbstract() { } /** * S-Polynomial. * @param A polynomial. * @param B polynomial. * @return spol(A,B) the S-polynomial of A and B. */ @Override public GenPolynomial SPolynomial(GenPolynomial A, GenPolynomial B) { if (B == null || B.isZERO()) { if (A == null) { return B; } return A.ring.getZERO(); } if (A == null || A.isZERO()) { return B.ring.getZERO(); } if (debug) { if (!A.ring.equals(B.ring)) { logger.error("rings not equal {}, {}", A.ring, B.ring); } } Map.Entry ma = A.leadingMonomial(); Map.Entry mb = B.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); //Cp = b e1 * A - a f1 * B; GenPolynomial Cp = A.scaleSubtractMultiple(b, e1, a, f1, B); return Cp; } /** * S-Polynomial with recording. * @param S recording matrix, is modified. Note the negative * S-polynomial is recorded as required by all applications. * @param i index of A in basis list. * @param A a polynomial. * @param j index of B in basis list. * @param B a polynomial. * @return Spol(A, B), the S-Polynomial for A and B. */ @Override public GenPolynomial SPolynomial(List> S, int i, GenPolynomial A, int j, GenPolynomial B) { if (debug) { if (B == null || B.isZERO()) { throw new ArithmeticException("Spol B is zero"); } if (A == null || A.isZERO()) { throw new ArithmeticException("Spol A is zero"); } if (!A.ring.equals(B.ring)) { logger.error("rings not equal {}, {}", A.ring, B.ring); } if ((S.get(i) != null && !S.get(i).isZERO()) || (S.get(j) != null && !S.get(j).isZERO())) { throw new IllegalArgumentException("S(i), S(j): " + S.get(i) + ", " + S.get(j)); } } Map.Entry ma = A.leadingMonomial(); Map.Entry mb = B.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); //Cp = b e1 * A - a f1 * B; GenPolynomial Cp = A.scaleSubtractMultiple(b, e1, a, f1, B); GenPolynomial zero = A.ring.getZERO(); GenPolynomial As = zero.sum(b.negate(), e1); /*not correct .negate()*/ GenPolynomial Bs = zero.sum(a, f1); /*correct .negate()*/ S.set(i, As); S.set(j, Bs); return Cp; } /** * Module criterium. * @param modv number of module variables. * @param A polynomial. * @param B polynomial. * @return true if the module S-polynomial(i,j) is required. */ @Override public boolean moduleCriterion(int modv, GenPolynomial A, GenPolynomial B) { if (modv == 0) { return true; } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); return moduleCriterion(modv, ei, ej); } /** * Module criterium. * @param modv number of module variables. * @param ei ExpVector. * @param ej ExpVector. * @return true if the module S-polynomial(i,j) is required. */ @Override public boolean moduleCriterion(int modv, ExpVector ei, ExpVector ej) { if (modv == 0) { return true; } if (ei.invLexCompareTo(ej, 0, modv) != 0) { return false; // skip pair } return true; } /** * GB criterium 4. Use only for commutative polynomial rings. * @param A polynomial. * @param B polynomial. * @param e = lcm(ht(A),ht(B)) * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B, ExpVector e) { if (logger.isInfoEnabled()) { if (!A.ring.equals(B.ring)) { logger.error("rings not equal {}, {}", A.ring, B.ring); } if (!A.ring.isCommutative()) { //B instanceof GenSolvablePolynomial ) { logger.error("GBCriterion4 not applicabable to non-commutative polynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); return criterion4(ei, ej, e); } /** * GB criterium 4. Use only for commutative polynomial rings. * @param ei exponent vector. * @param ej exponent vector. * @param e = lcm(ei,ej) * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(ExpVector ei, ExpVector ej, ExpVector e) { ExpVector g = ei.sum(ej); ExpVector h = g.subtract(e); int s = h.signum(); return s != 0; } /** * GB criterium 4. * @param A polynomial. * @param B polynomial. * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B) { if (logger.isInfoEnabled()) { if (!A.ring.isCommutative() || !B.ring.isCommutative()) { // A instanceof GenSolvablePolynomial logger.error("GBCriterion4 not applicabable to non-commutative polynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); ExpVector e = ei.lcm(ej); return criterion4(ei, ej, e); } /** * Normalform with respect to marked head terms. * @param Mp leading monomial list. * @param Pp polynomial list. * @param Ap polynomial. * @return nf(Ap) with respect to Mp+Pp. */ public GenPolynomial normalformMarked(List> Mp, List> Pp, GenPolynomial Ap) { throw new UnsupportedOperationException("not implemented: " + Mp + " " + Pp + " " + Ap); } /** * Normalform Set. * @param Ap polynomial list. * @param Pp polynomial list. * @return list of nf(a) with respect to Pp for all a in Ap. */ @Override public List> normalform(List> Pp, List> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isEmpty()) { return Ap; } ArrayList> red = new ArrayList>(); for (GenPolynomial A : Ap) { A = normalform(Pp, A); red.add(A); } return red; } /** * Module normalform set. * @param Ap module list. * @param Pp module list. * @return list of nf(a) with respect to Pp for all a in Ap. */ public ModuleList normalform(ModuleList Pp, ModuleList Ap) { return normalform(Pp, Ap, false); } /** * Module normalform set. * @param Ap module list. * @param Pp module list. * @param top true for TOP term order, false for POT term order. * @return list of nf(a) with respect to Pp for all a in Ap. */ public ModuleList normalform(ModuleList Pp, ModuleList Ap, boolean top) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isEmpty()) { return Ap; } int modv = Pp.cols; GenPolynomialRing pfac = Pp.ring.extend(modv, top); logger.debug("extended ring = {}", pfac); //System.out.println("extended ring = " + pfac); PolynomialList P = Pp.getPolynomialList(pfac); PolynomialList A = Ap.getPolynomialList(pfac); List> red = normalform(P.list, A.list); PolynomialList Fr = new PolynomialList(P.ring, red); ModuleList Nr = Fr.getModuleList(modv); return Nr; } /** * Is top reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ @Override public boolean isTopReducible(List> P, GenPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); for (GenPolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { return true; } } return false; } /** * Is reducible. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is reducible with respect to Pp. */ @Override public boolean isReducible(List> Pp, GenPolynomial Ap) { return !isNormalform(Pp, Ap); } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") @Override public boolean isNormalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); j++; } } l = j; boolean mt = false; for (ExpVector e : Ap.getMap().keySet()) { for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { return false; } } } return true; } /** * Is in Normalform. * @param Pp polynomial list. * @return true if each Ap in Pp is in normalform with respect to Pp\{Ap}. */ @Override public boolean isNormalform(List> Pp) { if (Pp == null || Pp.isEmpty()) { return true; } GenPolynomial Ap; List> P = new LinkedList>(Pp); int s = P.size(); for (int i = 0; i < s; i++) { Ap = P.remove(i); if (!isNormalform(P, Ap)) { return false; } P.add(Ap); } return true; } /** * Irreducible set. * @param Pp polynomial list. * @return a list P of monic polynomials which are in normalform wrt. P and * with ideal(Pp) = ideal(P). */ @Override public List> irreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); for (GenPolynomial a : Pp) { if (a.length() != 0) { a = a.monic(); if (a.isONE()) { P.clear(); P.add(a); return P; } P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; ExpVector e; ExpVector f; GenPolynomial a; logger.debug("irr = "); while (irr != l) { //it = P.listIterator(); //a = P.get(0); //it.next(); a = P.remove(0); e = a.leadingExpVector(); a = normalform(P, a); logger.debug(String.valueOf(irr)); if (a.length() == 0) { l--; if (l <= 1) { return P; } } else { f = a.leadingExpVector(); if (f.signum() == 0) { P = new ArrayList>(); P.add(a.monic()); return P; } if (e.equals(f)) { irr++; } else { irr = 0; a = a.monic(); } P.add(a); } } //System.out.println(); return P; } /** * Is reduction of normal form. * @param row recording matrix. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @param Np = nf(Pp,Ap), a normal form of Ap wrt. Pp. * @return true, if Ap == sum( row[i]*Pp[i] ) + Np, else false. //?? */ @Override public boolean isReductionNF(List> row, List> Pp, GenPolynomial Ap, GenPolynomial Np) { if (row == null && Pp == null) { if (Ap == null) { return Np == null || Np.isZERO(); } if (Np == null) { return Ap == null || Ap.isZERO(); } return Ap.equals(Np); } if (row == null || Pp == null) { return false; } if (row.size() < Pp.size()) { logger.debug("#r < #p = {}, {}", row.size(), Pp.size()); } GenPolynomial t = Np; //System.out.println("t0 = " + t ); GenPolynomial r; GenPolynomial p; int mm = Math.min(row.size(), Pp.size()); for (int m = 0; m < mm; m++) { r = row.get(m); p = Pp.get(m); if (r != null && p != null) { if (t == null) { t = r.multiply(p); } else { t = t.sum(r.multiply(p)); } } //System.out.println("r = " + r ); //System.out.println("p = " + p ); } //System.out.println("t+ = " + t); if (t == null) { // then also Np == null if (Ap == null) { return true; } return Ap.isZERO(); } r = t.subtract(Ap); //System.out.println("NF_r = " + r); boolean z = r.isZERO(); if (!z) { logger.info("a, n = {}, {}", Ap, Np); logger.info("t, t-a = {}, {}", t, r); logger.info("row = {}", row); logger.info("Pp = {}", Pp); } return z; } } java-algebra-system-2.7.200/src/edu/jas/gb/ReductionPar.java000066400000000000000000000152311445075545500235130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.util.Map; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial reduction parallel usable algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class ReductionPar> extends ReductionAbstract { //private static final Logger logger = LogManager.getLogger(ReductionPar.class); /** * Constructor. */ public ReductionPar() { } /** * Normalform. Allows concurrent modification of the list. * @param Ap polynomial. * @param Pp polynomial list, concurrent modification allowed. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { // required, ok in dist l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.values().toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Map.Entry m; Map.Entry m1; ExpVector e; ExpVector f = null; C a; boolean mt = false; GenPolynomial Rz = Ap.ring.getZERO(); GenPolynomial R = Rz.copy(); GenPolynomial p = null; //GenPolynomial Q = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != l) { //long t = System.currentTimeMillis(); synchronized (Pp) { // required, bad in parallel l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray() = {} ms, size() = {}", t, l); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); //System.out.println("S.e = " + e); for (int i = 0; i < P.length; i++) { p = P[i]; f = p.leadingExpVector(); if (f != null) { mt = e.multipleOf(f); if (mt) break; } } if (!mt) { //logger.debug("irred"); //R = R.sum( a, e ); //S = S.subtract( a, e ); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println("R = " + R); } else { //logger.debug("red"); m1 = p.leadingMonomial(); e = e.subtract(f); a = a.divide(m1.getValue()); //Q = p.multiply( a, e ); //S = S.subtract( Q ); S = S.subtractMultiple(a, e, p); } //System.out.println("S = " + S); } return R; } /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { throw new RuntimeException("normalform with recording not implemented"); } /** * Normalform. Allows concurrent modification of the DHT. * @param Ap polynomial. * @param mp a map from Integers to polynomials, e.g. a distributed hash * table, concurrent modification allowed. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(Map> mp, GenPolynomial Ap) { if (mp == null || mp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; //synchronized ( mp ) { // no more required l = mp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; P = mp.values().toArray(P); l = P.length; //} Map.Entry m; Map.Entry m1; ExpVector e; ExpVector f = null; C a; boolean mt = false; GenPolynomial Rz = Ap.ring.getZERO(); GenPolynomial R = Rz.copy(); GenPolynomial p = null; //GenPolynomial Q = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { if (mp.size() != l) { //long t = System.currentTimeMillis(); //synchronized ( mp ) { // no more required, ok in distributed P = mp.values().toArray(P); l = P.length; //} //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray() = {} ms, size() = {}", t, l); //logger.info("Pp.toArray() size() = {}", l); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (int i = 0; i < P.length; i++) { p = P[i]; f = p.leadingExpVector(); if (f != null) { mt = e.multipleOf(f); if (mt) break; } } if (!mt) { //logger.debug("irred"); //R = R.sum( a, e ); //S = S.subtract( a, e ); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //logger.debug("red"); m1 = p.leadingMonomial(); e = e.subtract(f); a = a.divide(m1.getValue()); //Q = p.multiply( a, e ); //S = S.subtract( Q ); S = S.subtractMultiple(a, e, p); } } return R; } } java-algebra-system-2.7.200/src/edu/jas/gb/ReductionSeq.java000066400000000000000000000230571445075545500235260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.Monomial; import edu.jas.structure.RingElem; /** * Polynomial reduction sequential use algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class ReductionSeq> // should be FieldElem> extends ReductionAbstract { private static final Logger logger = LogManager.getLogger(ReductionSeq.class); /** * Constructor. */ public ReductionSeq() { } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } Map.Entry m; int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; Object[] lbc = new Object[l]; // want C[] GenPolynomial[] p = new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenPolynomial R = Ap.ring.getZERO().copy(); //GenPolynomial T = null; //GenPolynomial Q = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { logger.debug("irred"); //R = R.sum( a, e ); //S = S.subtract( a, e ); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); a = a.divide((C) lbc[i]); //logger.info("red div: e = {}, a = {}", e, a); //Q = p[i].multiply( a, e ); //S = S.subtract( Q ); S = S.subtractMultiple(a, e, p[i]); } } return R; } /** * Normalform with respect to marked head terms. * @param Mp leading monomial list. * @param Pp polynomial list. * @param Ap polynomial. * @return nf(Ap) with respect to Mp+Pp. */ @Override @SuppressWarnings("unchecked") public GenPolynomial normalformMarked(List> Mp, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Mp == null || Mp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } Map.Entry m; int l; GenPolynomial[] P; Monomial[] M; synchronized (Pp) { l = Pp.size(); if (Mp.size() != l) { throw new IllegalArgumentException("#Mp != #Pp: " + l + ", " + Mp.size()); } P = new GenPolynomial[l]; M = new Monomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); M[i] = Mp.get(i); } } ExpVector[] htl = new ExpVector[l]; RingElem[] lbc = new RingElem[l]; GenPolynomial[] p = new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; if (M[i] != null) { p[j] = p[i]; htl[j] = M[i].exponent(); lbc[j] = M[i].coefficient(); j++; } } l = j; ExpVector e, f; C a, b; boolean mt = false; GenPolynomial R = Ap.ring.getZERO().copy(); GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); //System.out.println("NF a = " + a + ", e = " + e); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { logger.debug("irred"); R.doAddTo(a, e); // needed, or sum //R.doPutToMap(e, a); // not here //S = S.subtract( a, e ); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //System.out.println("i = "+i+", htl[i] = " + Ap.ring.toScript(htl[i]) + ", lbc[i] = " + lbc[i] + ", p[i] = " + p[i].ring.toScript(p[i].leadingExpVector())); f = e.subtract(htl[i]); b = a.divide((C) lbc[i]); //logger.info("red div: e = {}, a = {}, f = {}, b = {}", e, a, f, b); //Q = p[i].multiply( a, e ); //S = S.subtract( Q ); S.doRemoveFromMap(e, a); //S.doAddTo(a.negate(), e); S = S.subtractMultiple(b, f, p[i]); if (e.equals(S.leadingExpVector())) { throw new RuntimeException( "something is wrong: ht not descending e = " + e + ", S = " + S); } //System.out.println("NF R = " + R.leadingExpVector() + ", S = " + S.leadingExpVector() + ", e = " + e + ", f = " + f + ", #S = " + S.length()); } //System.out.println("NF R = " + R + ", S = " + S); } //System.out.println("NF Ap = " + Ap + " ==> " + R); return R; } /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } int l = Pp.size(); GenPolynomial[] P = new GenPolynomial[l]; synchronized (Pp) { //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; Object[] lbc = new Object[l]; // want C[] GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial R = Ap.ring.getZERO().copy(); GenPolynomial fac = null; // GenPolynomial T = null; //GenPolynomial Q = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum( a, e ); //S = S.subtract( a, e ); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); C c = (C) lbc[i]; a = a.divide(c); //Q = p[i].multiply( a, e ); //S = S.subtract( Q ); S = S.subtractMultiple(a, e, p[i]); fac = row.get(i); if (fac == null) { fac = zero.sum(a, e); } else { fac = fac.sum(a, e); } row.set(i, fac); } } return R; } } java-algebra-system-2.7.200/src/edu/jas/gb/SGBProxy.java000066400000000000000000000252311445075545500225720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PreemptingException; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; /** * Groebner bases parallel proxy. * @author Heinz Kredel */ public class SGBProxy> extends SolvableGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(SGBProxy.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GB engines. */ public final SolvableGroebnerBaseAbstract e1; public final SolvableGroebnerBaseAbstract e2; /** * Thread pool. */ protected transient ExecutorService pool; /** * Proxy constructor. * @param e1 Groebner base engine. * @param e2 Groebner base engine. */ public SGBProxy(SolvableGroebnerBaseAbstract e1, SolvableGroebnerBaseAbstract e2) { this.e1 = e1; this.e2 = e2; pool = ComputerThreads.getPool(); //System.out.println("pool 2 = "+pool); } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return "SGBProxy[ " + e1.toString() + ", " + e2.toString() + " ]"; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { e1.terminate(); e2.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { int s = e1.cancel(); s += e2.cancel(); return s; } /** * Groebner base. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List> leftGB(final int modv, final List> F) { if (F == null || F.isEmpty()) { return F; } // parallel case List> G = null; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); List> G = e1.leftGB(modv, F); if (debug) { logger.info("SGBProxy done e1 {}", e1.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e1 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e1 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); List> G = e2.leftGB(modv, F); if (debug) { logger.info("SGBProxy done e2 {}", e2.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e2 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e2 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e2 " + e); //return P.ring.getONE(); } } }); try { G = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return G; } /** * Right Groebner base. * @param modv module variable number. * @param F polynomial list. * @return rightGB(F) a Groebner base of F. */ @Override public List> rightGB(final int modv, final List> F) { if (F == null || F.isEmpty()) { return F; } // parallel case List> G = null; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); List> G = e1.rightGB(modv, F); if (debug) { logger.info("SGBProxy done e1 {}", e1.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e1 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e1 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); List> G = e2.rightGB(modv, F); if (debug) { logger.info("SGBProxy done e2 {}", e2.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e2 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e2 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e2 " + e); //return P.ring.getONE(); } } }); try { G = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return G; } /** * Groebner base. * @param modv module variable number. * @param F polynomial list. * @return twosidedGB(F) a Groebner base of F. */ @Override public List> twosidedGB(final int modv, final List> F) { if (F == null || F.isEmpty()) { return F; } // parallel case List> G = null; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); List> G = e1.twosidedGB(modv, F); if (debug) { logger.info("SGBProxy done e1 {}", e1.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e1 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e1 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public List> call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); List> G = e2.twosidedGB(modv, F); if (debug) { logger.info("SGBProxy done e2 {}", e2.getClass().getName()); } return G; } catch (PreemptingException e) { throw new RuntimeException("SGBProxy e2 preempted " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("SGBProxy e2 {}", e); logger.info("Exception SGBProxy F = {}", F); throw new RuntimeException("SGBProxy e2 " + e); //return P.ring.getONE(); } } }); try { G = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/SigPair.java000066400000000000000000000046151445075545500224560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Serializable subclass to hold pairs of polynomials. * @param coefficient type * @author Heinz Kredel */ public class SigPair> //extends AbstractSigPair implements Comparable> { public final GenPolynomial sigma; public final SigPoly pi; public final SigPoly pj; public final List> Gs; /** * SigPair constructor. * @param sig signature of pair. * @param a polynomial i. * @param b polynomial j. */ public SigPair(ExpVector sig, SigPoly a, SigPoly b, List> Gs) { this(a.poly.ring.valueOf(sig), a, b, Gs); } /** * SigPair constructor. * @param sig signature of pair. * @param a polynomial i. * @param b polynomial j. */ public SigPair(GenPolynomial sig, SigPoly a, SigPoly b, List> Gs) { this.sigma = sig; pi = a; pj = b; this.Gs = Gs; } /** * getter for sigma */ GenPolynomial getSigma() { return sigma; } /** * getter for sigma.degree */ long getSigmaDegree() { return sigma.degree(); } /** * toString. */ @Override public String toString() { return "pair(" + sigma + " @ " + pi + ", " + pj + ")"; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object ob) { if (!(ob instanceof SigPair)) { return false; // throw new ClassCastException("SigPair "+n+" o "+o); } return 0 == compareTo((SigPair) ob); } /** * compareTo used in TreeMap // not used at moment. Comparison is based on * the number of the pairs. * @param p a SigPair. * @return 1 if (this < o), 0 if (this == o), -1 if (this > o). */ public int compareTo(SigPair p) { return sigma.compareTo(p.sigma); } /** * Hash code for this SigPair. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (pi.hashCode() << 16) + pj.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/gb/SigPoly.java000066400000000000000000000020661445075545500225040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Container for a polynomial and its signature. * @typeparam coefficient type */ public class SigPoly> { public final GenPolynomial sigma; public final GenPolynomial poly; /** * Constructor. * @param s a polynomial signature. * @param p a polynomial. */ public SigPoly(GenPolynomial s, GenPolynomial p) { this.sigma = s; this.poly = p; } /** * getter for sigma */ GenPolynomial getSigma() { return sigma; } /** * getter for polynomial */ GenPolynomial getPoly() { return poly; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("sigma("); s.append(sigma.toString() + "):: "); s.append(poly.toString()); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gb/SigReduction.java000066400000000000000000000030021445075545500235040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial SigReduction interface. Defines S-Polynomial, normalform with * respect to signatures. * @param coefficient type * @author Heinz Kredel */ public interface SigReduction> extends Serializable { /** * S-Polynomial. * @param Ap polynomial. * @param Bp polynomial. * @return spol(Ap,Bp) the S-polynomial of Ap and Bp. */ public GenPolynomial SPolynomial(SigPoly Ap, SigPoly Bp); /** * Is top reducible. Condition is lt(B) | lt(A) for some B in F or G. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isSigReducible(List> F, List> G, SigPoly A); /** * Is in Normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return true if A is in normalform with respect to F and G. */ public boolean isSigNormalform(List> F, List> G, SigPoly A); /** * Normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ public SigPoly sigNormalform(List> F, List> G, SigPoly A); } java-algebra-system-2.7.200/src/edu/jas/gb/SigReductionSeq.java000066400000000000000000000367061445075545500241760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Polynomial SigReduction class. Implements common S-Polynomial, normalform * with respect to signatures. * @param coefficient type * @author Heinz Kredel */ public class SigReductionSeq> implements SigReduction { private static final Logger logger = LogManager.getLogger(SigReductionSeq.class); //private static final boolean debug = logger.isDebugEnabled(); final ReductionAbstract red; /** * Constructor. */ public SigReductionSeq() { red = new ReductionSeq(); } /** * S-Polynomial. * @param A polynomial. * @param B polynomial. * @return spol(A,B) the S-polynomial of A and B. */ public GenPolynomial SPolynomial(SigPoly A, SigPoly B) { GenPolynomial s = red.SPolynomial(A.poly, B.poly); return s; } /** * S-Polynomial factors. * @param A monic polynomial. * @param B monic polynomial. * @return exponent vectors [e,f] such that spol(A,B) = e*a - f*B. */ public ExpVector[] SPolynomialExpVectorFactors(SigPoly A, SigPoly B) { Map.Entry ma = A.poly.leadingMonomial(); Map.Entry mb = B.poly.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); ExpVector[] F = new ExpVector[] { e1, f1 }; return F; } /** * S-Polynomial half. * @param A monic polynomial. * @param B monic polynomial. * @return e*A "half" of an S-polynomial such that spol(A,B) = e*A - f*B. */ public GenPolynomial SPolynomialHalf(SigPoly A, SigPoly B) { Map.Entry ma = A.poly.leadingMonomial(); Map.Entry mb = B.poly.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); GenPolynomial F = A.poly.multiply(e1); return F; } /** * S-Polynomial polynomial factors. * @param A monic polynomial. * @param B monic polynomial. * @return polynomials [e,f] such that spol(A,B) = e*a - f*B. */ public GenPolynomial[] SPolynomialFactors(SigPoly A, SigPoly B) { ExpVector[] ev = SPolynomialExpVectorFactors(A, B); GenPolynomial e1 = A.poly.ring.valueOf(ev[0]); GenPolynomial f1 = A.poly.ring.valueOf(ev[1]); @SuppressWarnings("unchecked") GenPolynomial[] F = new GenPolynomial[] { e1, f1 }; return F; } /** * Is top reducible. Condition is lt(B) | lt(A) for some B in F or G. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return true if A is top reducible with respect to F and G. */ public boolean isSigReducible(List> F, List> G, SigPoly A) { return !isSigNormalform(F, G, A); } /** * Is in top normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return true if A is in top normalform with respect to F and G. */ public boolean isSigNormalform(List> F, List> G, SigPoly A) { if (F.isEmpty() && G.isEmpty()) { return true; } if (A.poly.isZERO()) { return true; } boolean mt = false; for (ExpVector e : A.poly.getMap().keySet()) { for (SigPoly p : F) { ExpVector f = p.poly.leadingExpVector(); mt = e.multipleOf(f); if (mt) { return false; } } for (SigPoly p : G) { if (p.poly.isZERO()) { continue; } ExpVector f = p.poly.leadingExpVector(); mt = e.multipleOf(f); if (mt) { ExpVector g = e.subtract(f); GenPolynomial sigma = p.sigma.multiply(g); if (sigma.leadingExpVector().compareTo(A.sigma.leadingExpVector()) < 0) { return false; } if (sigma.leadingExpVector().compareTo(A.sigma.leadingExpVector()) == 0 && sigma.leadingBaseCoefficient() .compareTo(A.sigma.leadingBaseCoefficient()) != 0) { return false; } } } } return true; } /** * Is sigma redundant. * @param A polynomial. * @param G polynomial list. * @return true if A is sigma redundant with respect to G. */ public boolean isSigRedundant(List> G, SigPoly A) { if (G.isEmpty()) { return false; } ExpVector e = A.sigma.leadingExpVector(); if (e == null) { e = A.poly.ring.evzero; } for (SigPoly p : G) { if (p.sigma.isZERO()) { continue; } ExpVector f = p.sigma.leadingExpVector(); if (f == null) { // does not happen f = p.poly.ring.evzero; } boolean mt = e.multipleOf(f); if (mt) { ExpVector g = e.subtract(f); ExpVector h = p.poly.leadingExpVector(); h = h.sum(g); if (h.compareTo(A.poly.leadingExpVector()) == 0) { return true; } } } return false; } /** * Is sigma redundant, alternative algorithm. * @param A polynomial. * @param G polynomial list. * @return true if A is sigma redundant per alternative algorithm with * respect to G. */ public boolean isSigRedundantAlt(List> G, SigPoly A) { if (G.isEmpty()) { return false; } ExpVector e = A.sigma.leadingExpVector(); if (e == null) { e = A.poly.ring.evzero; } for (SigPoly p : G) { if (p.sigma.isZERO()) { continue; } ExpVector f = p.sigma.leadingExpVector(); if (f == null) { // does not happen f = p.poly.ring.evzero; } boolean mt = e.multipleOf(f); if (mt) { if (p.poly.isZERO()) { continue; } ExpVector h = p.poly.leadingExpVector(); ExpVector g = A.poly.leadingExpVector(); if (g.multipleOf(h)) { return true; } } } return false; } /** * Top normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ public SigPoly sigNormalform(List> F, List> G, SigPoly A) { if (F.isEmpty() && G.isEmpty()) { return A; } if (A.poly.isZERO()) { return A; } List> ff = F; //polys(F); GenPolynomial a = A.poly; GenPolynomial sigma = A.sigma; GenPolynomialRing ring = a.ring; boolean reduced = true; while (!a.isZERO() && reduced) { reduced = false; a = red.normalform(ff, a); if (a.isZERO()) { continue; } ExpVector e = a.leadingExpVector(); for (SigPoly p : G) { if (p.poly.isZERO()) { continue; } ExpVector f = p.poly.leadingExpVector(); boolean mt = e.multipleOf(f); if (mt) { ExpVector g = e.subtract(f); C sc = a.leadingBaseCoefficient().divide(p.poly.leadingBaseCoefficient()); GenPolynomial sigup = p.sigma.multiply(sc, g); ExpVector se = sigma.leadingExpVector(); if (se == null) { se = ring.evzero; } ExpVector sp = sigup.leadingExpVector(); if (sp == null) { sp = ring.evzero; } //logger.info("sigup, sigma = {}, {}", sigup, sigma); boolean sigeq = (sigup.compareTo(sigma) < 0) || ((sp.compareTo(se) == 0 && (sigup.leadingBaseCoefficient() .compareTo(sigma.leadingBaseCoefficient()) != 0))); //logger.info("sigup < sigma = {}", sigup.compareTo(sigma)); if (sigeq) { reduced = true; a = a.subtractMultiple(sc, g, p.poly); if (sp.invGradCompareTo(se) == 0) { sigma = sigma.subtract(sigup); } if (a.isZERO()) { break; } e = a.leadingExpVector(); } else { //logger.info("not reduced: a = {}, p = {}", a, p.poly); } } } } if (!a.isZERO()) { C ac = a.leadingBaseCoefficient(); if (!ac.isONE()) { ac = ac.inverse(); a = a.multiply(ac); sigma = sigma.multiply(ac); } } return new SigPoly(sigma, a); } /** * Top semi-complete normalform. * @param A polynomial. * @param F polynomial list. * @param G polynomial list. * @return nf(A) with respect to F and G. */ public SigPoly sigSemiNormalform(List> F, List> G, SigPoly A) { if (F.isEmpty() && G.isEmpty()) { return A; } if (A.poly.isZERO()) { return A; } List> ff = F; //polys(F); GenPolynomial a = A.poly; GenPolynomial sigma = A.sigma; ExpVector esig = sigma.leadingExpVector(); if (esig == null) { logger.info("esig = null"); //esig = a.ring.evzero; } //GenPolynomialRing ring = a.ring; boolean reduced = true; while (!a.isZERO() && reduced) { reduced = false; a = red.normalform(ff, a); if (a.isZERO()) { continue; } ExpVector e = a.leadingExpVector(); for (SigPoly p : G) { if (p.poly.isZERO()) { continue; } ExpVector f = p.poly.leadingExpVector(); boolean mt = e.multipleOf(f); if (mt) { ExpVector g = e.subtract(f); C sc = a.leadingBaseCoefficient().divide(p.poly.leadingBaseCoefficient()); GenPolynomial sigup = p.sigma.multiply(sc, g); ExpVector eup = sigup.leadingExpVector(); if (eup == null) { logger.info("eup = null"); //eup = a.ring.evzero; throw new IllegalArgumentException("eup == null: " + sigup); } //wrong: boolean sigeq = (sigup.compareTo(sigma) < 0); boolean sigeq = (eup.compareTo(esig) < 0); if (sigeq) { //logger.info("reduced: sigup = {}, sigma = {}", sigup, sigma); reduced = true; a = a.subtractMultiple(sc, g, p.poly); if (a.isZERO()) { break; } e = a.leadingExpVector(); } else { //logger.info("not reduced: a = {}, p = {}", a, p.poly); } } } } if (!a.isZERO()) { C ac = a.leadingBaseCoefficient(); if (!ac.isONE()) { ac = ac.inverse(); a = a.multiply(ac); } } return new SigPoly(sigma, a); } /** * Select polynomials. * @param F list of signature polynomials. * @return the polynomials in F. */ public List> polys(List> F) { List> ff = new ArrayList>(); for (SigPoly p : F) { if (!p.poly.isZERO()) { ff.add(p.poly); } } return ff; } /** * Select signatures. * @param F list of signature polynomials. * @return the signatures in F. */ public List> sigmas(List> F) { List> ff = new ArrayList>(); for (SigPair p : F) { ff.add(p.sigma); } return ff; } /** * Minimal degree of signatures. * @param F list of signature polynomials. * @return the minimal degree of the signatures in F. */ public long minimalSigDegree(List> F) { long deg = Long.MAX_VALUE; for (SigPair p : F) { //long d = p.sigma.totalDegree(); long d = p.sigma.degree(); if (d < deg) { deg = d; } } return deg; } /** * Select signature polynomials of minimal degree and non minimal degree. * @param F list of signature polynomials. * @return [m,p] where m is the list of signature polynomials of F of * minimal degree and p contains the rest of the signature * polynomials with non minimal degree. */ public List>[] minDegSubset(List> F) { long mdeg = minimalSigDegree(F); List> ff = new ArrayList>(); List> pp = new ArrayList>(); for (SigPair p : F) { //if (p.sigma.totalDegree() == mdeg) { if (p.sigma.degree() == mdeg) { ff.add(p); } else { pp.add(p); } } @SuppressWarnings("unchecked") List>[] P = new List[2]; P[0] = ff; P[1] = pp; return P; } /** * Sort signature polynomials according to the degree its signatures. * @param F list of signature polynomials. * @return list of signature polynomials sorted by degree of sigma. */ public List> sortSigma(List> F) { //Comparator> sigcmp = Comparator.comparing(SigPair::getSigma::degree); Comparator> sigcmp = Comparator.comparingLong(SigPair::getSigmaDegree); List> ff = F.stream().sorted(sigcmp).collect(Collectors.toList()); return ff; } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableExtendedGB.java000066400000000000000000000045361445075545500245630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Container for a GB and transformation matrices. * A container for F, G, calG and calF. * Immutable objects. * @typeparam C coefficient type */ public class SolvableExtendedGB> { public final List> F; public final List> G; public final List>> F2G; public final List>> G2F; public final GenSolvablePolynomialRing ring; /** * Container for a GB and transformation matrices. * @param F an ideal base. * @param G a Groebner base of F. * @param F2G a transformation matrix from F to G. * @param G2F a transformation matrix from G to F. */ public SolvableExtendedGB( List> F, List> G, List>> F2G, List>> G2F) { this.F = F; this.G = G; this.F2G = F2G; this.G2F = G2F; GenSolvablePolynomialRing r = null; if ( G != null ) { for ( GenSolvablePolynomial p : G ) { if ( p != null ) { r = p.ring; break; } } if ( r != null && r.getVars() == null ) { r.setVars( r.newVars("y") ); } } this.ring = r; } /** Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { PolynomialList P; ModuleList M; StringBuffer s = new StringBuffer("SolvableExtendedGB: \n\n"); P = new PolynomialList( ring, F ); s.append("F = " + P + "\n\n"); P = new PolynomialList( ring, G ); s.append("G = " + P + "\n\n"); M = new ModuleList( ring, F2G ); s.append("F2G = " + M + "\n\n"); M = new ModuleList( ring, G2F ); s.append("G2F = " + M + "\n"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableGroebnerBase.java000066400000000000000000000146331445075545500251470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.ModuleList; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Solvable Groebner Bases interface. Defines methods for left, right and * twosided Groebner bases and left, right and twosided GB tests. * @param coefficient type * @author Heinz Kredel */ public interface SolvableGroebnerBase> extends Serializable { /** * Left Groebner base test. * @param F solvable polynomial list. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGB(List> F); /** * Left Groebner base test. * @param modv number of module variables. * @param F solvable polynomial list. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGB(int modv, List> F); /** * Twosided Groebner base test. * @param Fp solvable polynomial list. * @return true, if Fp is a two-sided Groebner base, else false. */ public boolean isTwosidedGB(List> Fp); /** * Twosided Groebner base test. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return true, if Fp is a two-sided Groebner base, else false. */ public boolean isTwosidedGB(int modv, List> Fp); /** * Right Groebner base test. * @param F solvable polynomial list. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(List> F); /** * Right Groebner base test. * @param modv number of module variables. * @param F solvable polynomial list. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(int modv, List> F); /** * Left Groebner base using pairlist class. * @param F solvable polynomial list. * @return leftGB(F) a left Groebner base of F. */ public List> leftGB(List> F); /** * Left Groebner base using pairlist class. * @param modv number of module variables. * @param F solvable polynomial list. * @return leftGB(F) a left Groebner base of F. */ public List> leftGB(int modv, List> F); /** * Solvable Extended Groebner base using critical pair class. * @param F solvable polynomial list. * @return a container for an extended left Groebner base of F. */ public SolvableExtendedGB extLeftGB(List> F); /** * Solvable Extended Groebner base using critical pair class. * @param modv module variable number. * @param F solvable polynomial list. * @return a container for an extended left Groebner base of F. */ public SolvableExtendedGB extLeftGB(int modv, List> F); /** * Left minimal ordered groebner basis. * @param Gp a left Groebner base. * @return leftGBmi(F) a minimal left Groebner base of Gp. */ public List> leftMinimalGB(List> Gp); /** * Twosided Groebner base using pairlist class. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ public List> twosidedGB(List> Fp); /** * Twosided Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ public List> twosidedGB(int modv, List> Fp); /** * Right Groebner base using opposite ring left GB. * @param F solvable polynomial list. * @return rightGB(F) a right Groebner base of F. */ public List> rightGB(List> F); /** * Right Groebner base using opposite ring left GB. * @param modv number of module variables. * @param F solvable polynomial list. * @return rightGB(F) a right Groebner base of F. */ public List> rightGB(int modv, List> F); /** * Test if left reduction matrix. * @param exgb an SolvableExtendedGB container. * @return true, if exgb contains a left reduction matrix, else false. */ public boolean isLeftReductionMatrix(SolvableExtendedGB exgb); /** * Test if left reduction matrix. * @param F a solvable polynomial list. * @param G a left Groebner base. * @param Mf a possible left reduction matrix. * @param Mg a possible left reduction matrix. * @return true, if Mg and Mf are left reduction matrices, else false. */ public boolean isLeftReductionMatrix(List> F, List> G, List>> Mf, List>> Mg); /** * Module left Groebner base test. * @param M a module basis. * @return true, if M is a left Groebner base, else false. */ public boolean isLeftGB(ModuleList M); /** * Left Groebner base using pairlist class. * @param M a module basis. * @return leftGB(M) a left Groebner base for M. */ public ModuleList leftGB(ModuleList M); /** * Module twosided Groebner base test. * @param M a module basis. * @return true, if M is a twosided Groebner base, else false. */ public boolean isTwosidedGB(ModuleList M); /** * Twosided Groebner base using pairlist class. * @param M a module basis. * @return tsGB(M) a twosided Groebner base for M. */ public ModuleList twosidedGB(ModuleList M); /** * Module right Groebner base test. * @param M a module basis. * @return true, if M is a right Groebner base, else false. */ public boolean isRightGB(ModuleList M); /** * Right Groebner base using pairlist class. * @param M a module basis. * @return rightGB(M) a right Groebner base for M. */ public ModuleList rightGB(ModuleList M); } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableGroebnerBaseAbstract.java000066400000000000000000001133121445075545500266250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.ModuleList; import edu.jas.poly.TermOrder; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.vector.BasicLinAlg; /** * Solvable Groebner Bases abstract class. Implements common left, right and * twosided Groebner bases and left, right and twosided GB tests. * @param coefficient type * @author Heinz Kredel */ public abstract class SolvableGroebnerBaseAbstract> implements SolvableGroebnerBase { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBaseAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Solvable reduction engine. */ public SolvableReduction sred; /** * Reduction engine. */ public final Reduction red; /** * Strategy for pair selection. */ public final PairList strategy; /** * Linear algebra engine. */ protected final BasicLinAlg> blas; /** * Commutative Groebner bases engine. */ public final GroebnerBaseAbstract cbb; /** * Constructor. */ public SolvableGroebnerBaseAbstract() { this(new SolvableReductionSeq()); } /** * Constructor. * @param sred Solvable reduction engine */ public SolvableGroebnerBaseAbstract(SolvableReduction sred) { this(sred, new OrderedPairlist()); } /** * Constructor. * @param pl pair selection strategy */ public SolvableGroebnerBaseAbstract(PairList pl) { this(new SolvableReductionSeq(), pl); } /** * Constructor. * @param sred Solvable reduction engine * @param pl pair selection strategy */ public SolvableGroebnerBaseAbstract(SolvableReduction sred, PairList pl) { this.red = new ReductionSeq(); this.sred = sred; this.strategy = pl; blas = new BasicLinAlg>(); cbb = new GroebnerBaseSeq(); } /** * Normalize polynomial list. * @param A list of polynomials. * @return list of polynomials with zeros removed and ones/units reduced. */ public List> normalizeZerosOnes(List> A) { //List> a = PolynomialList. castToList(A); //List> n = cbb.normalizeZeroOnes(a); //List> N = PolynomialList. castToSolvableList(n); if (A == null) { return A; } List> N = new ArrayList>(A.size()); if (A.isEmpty()) { return N; } for (GenSolvablePolynomial p : A) { if (p == null || p.isZERO()) { continue; } if (p.isUnit()) { N.clear(); N.add(p.ring.getONE()); return N; } N.add((GenSolvablePolynomial) p.abs()); } //N.trimToSize(); return N; } /** * Left Groebner base test. * @param F solvable polynomial list. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGB(List> F) { return isLeftGB(0, F, true); } /** * Left Groebner base test. * @param F solvable polynomial list. * @param b true for simple test, false for GB test. * @return true, if F is a Groebner base, else false. */ public boolean isLeftGB(List> F, boolean b) { return isLeftGB(0, F, b); } /** * Left Groebner base test. * @param modv module variable number. * @param F solvable polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isLeftGB(int modv, List> F) { return isLeftGB(modv, F, true); } /** * Left Groebner base test. * @param modv module variable number. * @param F solvable polynomial list. * @param b true for simple test, false for GB test. * @return true, if F is a Groebner base, else false. */ public boolean isLeftGB(int modv, List> F, boolean b) { if (b) { return isLeftGBsimple(modv, F); } return isLeftGBidem(modv, F); } /** * Left Groebner base test. * @param modv number of module variables. * @param F solvable polynomial list. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGBsimple(int modv, List> F) { GenSolvablePolynomial pi, pj, s, h; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } s = sred.leftSPolynomial(pi, pj); if (s.isZERO()) { continue; } h = sred.leftNormalform(F, s); if (!h.isZERO()) { logger.info("no left GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } } return true; } /** * Left Groebner base idempotence test. * @param modv module variable number. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isLeftGBidem(int modv, List> F) { if (F == null || F.isEmpty()) { return true; } GenSolvablePolynomialRing pring = F.get(0).ring; List> G = leftGB(modv, F); PolynomialList Fp = new PolynomialList(pring, F); PolynomialList Gp = new PolynomialList(pring, G); return Fp.compareTo(Gp) == 0; } /** * Twosided Groebner base test. * @param Fp solvable polynomial list. * @return true, if Fp is a two-sided Groebner base, else false. */ public boolean isTwosidedGB(List> Fp) { return isTwosidedGB(0, Fp); } /** * Twosided Groebner base test. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return true, if Fp is a two-sided Groebner base, else false. */ public boolean isTwosidedGB(int modv, List> Fp) { if (Fp == null || Fp.size() == 0) { // 0 not 1 return true; } if (Fp.size() == 1 && Fp.get(0).isONE()) { return true; } GenSolvablePolynomialRing ring = Fp.get(0).ring; // assert != null // add also coefficient generators List> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List> F = new ArrayList>(Fp.size() * (1 + X.size())); F.addAll(Fp); GenSolvablePolynomial p, q, x, pi, pj, s, h; for (int i = 0; i < Fp.size(); i++) { p = Fp.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } q = p.multiply(x); q = sred.leftNormalform(F, q); if (!q.isZERO()) { //System.out.println("is: q generated = " + q + ", p = " + p + ", x = " + x); return false; //F.add(q); } } } //System.out.println("F to check = " + F); for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } s = sred.leftSPolynomial(pi, pj); if (s.isZERO()) { continue; } h = sred.leftNormalform(F, s); if (!h.isZERO()) { logger.info("is not TwosidedGB: {}", h); //System.out.println("is: h = " + h + ", s = " + s); return false; } } } return true; } /** * Twosided Groebner base idempotence test. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isTwosidedGBidem(List> F) { return isTwosidedGBidem(0, F); } /** * Twosided Groebner base idempotence test. * @param modv module variable number. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isTwosidedGBidem(int modv, List> F) { if (F == null || F.isEmpty()) { return true; } GenSolvablePolynomialRing pring = F.get(0).ring; List> G = twosidedGB(modv, F); PolynomialList Fp = new PolynomialList(pring, F); PolynomialList Gp = new PolynomialList(pring, G); return Fp.compareTo(Gp) == 0; } /** * Right Groebner base test. * @param F solvable polynomial list. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(List> F) { return isRightGB(0, F); } /** * Right Groebner base test. * @param modv number of module variables. * @param F solvable polynomial list. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(int modv, List> F) { GenSolvablePolynomial pi, pj, s, h; for (int i = 0; i < F.size(); i++) { pi = F.get(i); //System.out.println("pi right = " + pi); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); //System.out.println("pj right = " + pj); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } s = sred.rightSPolynomial(pi, pj); if (s.isZERO()) { continue; } //System.out.println("s right = " + s); h = sred.rightNormalform(F, s); if (!h.isZERO()) { logger.info("isRightGB non zero h = {} :: {}, rspol = {}", h, h.ring.toScript(), s); logger.info("p{} = {}, p{} = {}", i, pi, j, pj); return false; } } } return true; } /** * Right Groebner base idempotence test. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isRightGBidem(List> F) { return isRightGBidem(0, F); } /** * Right Groebner base idempotence test. * @param modv module variable number. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ public boolean isRightGBidem(int modv, List> F) { if (F == null || F.isEmpty()) { return true; } GenSolvablePolynomialRing pring = F.get(0).ring; List> G = rightGB(modv, F); PolynomialList Fp = new PolynomialList(pring, F); PolynomialList Gp = new PolynomialList(pring, G); return Fp.compareTo(Gp) == 0; } /** * Left Groebner base using pairlist class. * @param F solvable polynomial list. * @return leftGB(F) a left Groebner base of F. */ public List> leftGB(List> F) { return leftGB(0, F); } /** * Solvable Extended Groebner base using critical pair class. * @param F solvable polynomial list. * @return a container for an extended left Groebner base of F. */ public SolvableExtendedGB extLeftGB(List> F) { return extLeftGB(0, F); } /** * Solvable Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for an extended left Groebner base G of F together * with back-and-forth transformations. */ public SolvableExtendedGB extLeftGB(int modv, List> F) { throw new UnsupportedOperationException("extLeftGB not implemented in " + this.getClass().getSimpleName()); } /** * Left minimal ordered groebner basis. * @param Gp a left Groebner base. * @return leftGBmi(F) a minimal left Groebner base of Gp. */ public List> leftMinimalGB(List> Gp) { ArrayList> G = new ArrayList>(); ListIterator> it = Gp.listIterator(); for (GenSolvablePolynomial a : Gp) { // a = (SolvablePolynomial) it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenSolvablePolynomial a, p; ArrayList> F = new ArrayList>(); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } F = new ArrayList>(); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); a = sred.leftNormalform(G, a); a = sred.leftNormalform(F, a); F.add(a); } return F; } /** * Right minimal ordered groebner basis. * @param Gp a right Groebner base. * @return rightGBmi(F) a minimal right Groebner base of Gp. */ public List> rightMinimalGB(List> Gp) { ArrayList> G = new ArrayList>(); ListIterator> it = Gp.listIterator(); for (GenSolvablePolynomial a : Gp) { if (a.length() != 0) { // always true G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenSolvablePolynomial a, p; ArrayList> F = new ArrayList>(); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } F = new ArrayList>(); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); a = sred.rightNormalform(G, a); a = sred.rightNormalform(F, a); F.add(a); } return F; } /** * Twosided Groebner base using pairlist class. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ public List> twosidedGB(List> Fp) { return twosidedGB(0, Fp); } /** * Right Groebner base using opposite ring left GB. * @param F solvable polynomial list. * @return rightGB(F) a right Groebner base of F. */ public List> rightGB(List> F) { return rightGB(0, F); } /** * Right Groebner base using opposite ring left GB. * @param modv number of module variables. * @param F solvable polynomial list. * @return rightGB(F) a right Groebner base of F. */ @SuppressWarnings("unchecked") public List> rightGB(int modv, List> F) { List> G = normalizeZerosOnes(F); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing ring = G.get(0).ring; // assert != null GenSolvablePolynomialRing rring = ring.reverse(true); //true //System.out.println("rightGB: ring = " + ring.toScript() + ", reversed ring = " + rring.toScript()); GenSolvablePolynomial q; List> rF; rF = new ArrayList>(F.size()); for (GenSolvablePolynomial p : F) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(rring); rF.add(q); } } if (logger.isInfoEnabled()) { PolynomialList pl = new PolynomialList(rring, rF); logger.info("reversed problem = {}", pl.toScript()); } List> rG = leftGB(modv, rF); if (debug) { //PolynomialList pl = new PolynomialList(rring,rG); //logger.info("reversed GB = {}", pl); long t = System.currentTimeMillis(); boolean isit = isLeftGB(rG); t = System.currentTimeMillis() - t; logger.info("is left GB = {}, in {} milliseconds", isit, t); } //System.out.println("reversed left GB = " + rG); ring = rring.reverse(true); // true G = new ArrayList>(rG.size()); for (GenSolvablePolynomial p : rG) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(ring); G.add(q); } } if (debug) { //PolynomialList pl = new PolynomialList(ring,G); //logger.info("GB = {}", pl); long t = System.currentTimeMillis(); boolean isit = isRightGB(G); t = System.currentTimeMillis() - t; logger.info("is right GB = {}, in {} milliseconds", isit, t); } return G; } /** * Solvable Extended Groebner base using critical pair class. * @param F solvable polynomial list. * @return a container for an extended right Groebner base of F. */ public SolvableExtendedGB extRightGB(List> F) { return extRightGB(0, F); } /** * Solvable Extended Groebner base using critical pair class. * @param modv module variable number. * @param F polynomial list. * @return a container for an extended right Groebner base G of F together * with back-and-forth transformations. */ public SolvableExtendedGB extRightGB(int modv, List> F) { throw new UnsupportedOperationException("extRightGB not implemented in " + this.getClass().getSimpleName()); } /** * Module left Groebner base test. * @param M a module basis. * @return true, if M is a left Groebner base, else false. */ public boolean isLeftGB(ModuleList M) { return isLeftGB(M,false); } /** * Module left Groebner base test. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return true, if M is a left Groebner base, else false. */ public boolean isLeftGB(ModuleList M, boolean top) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } int modv = M.cols; // > 0 PolynomialList F = M.getPolynomialList(top); return isLeftGB(modv, F.castToSolvableList()); } /** * Left Groebner base using pairlist class. * @param M a module basis. * @return leftGB(M) a left Groebner base for M. */ public ModuleList leftGB(ModuleList M) { return leftGB(M,false); } /** * Left Groebner base using pairlist class. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return leftGB(M) a left Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList leftGB(ModuleList M, boolean top) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(top); if (debug) { logger.info("F left +++++++++++++++++++ \n{}", F); } GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) F.ring; int modv = M.cols; List> G = leftGB(modv, F.castToSolvableList()); F = new PolynomialList(sring, G); if (debug) { logger.info("G left +++++++++++++++++++ \n{}", F); } N = F.getModuleList(modv); return N; } /** * Module twosided Groebner base test. * @param M a module basis. * @return true, if M is a twosided Groebner base, else false. */ public boolean isTwosidedGB(ModuleList M) { return isTwosidedGB(M,false); } /** * Module twosided Groebner base test. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return true, if M is a twosided Groebner base, else false. */ public boolean isTwosidedGB(ModuleList M, boolean top) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } PolynomialList F = M.getPolynomialList(top); int modv = M.cols; // > 0 return isTwosidedGB(modv, F.castToSolvableList()); } /** * Twosided Groebner base using pairlist class. * @param M a module basis. * @return twosidedGB(M) a twosided Groebner base for M. */ public ModuleList twosidedGB(ModuleList M) { return twosidedGB(M,false); } /** * Twosided Groebner base using pairlist class. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return tsGB(M) a twosided Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList twosidedGB(ModuleList M, boolean top) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(top); GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) F.ring; int modv = M.cols; List> G = twosidedGB(modv, F.castToSolvableList()); F = new PolynomialList(sring, G); N = F.getModuleList(modv); return N; } /** * Module right Groebner base test. * @param M a module basis. * @return true, if M is a right Groebner base, else false. */ public boolean isRightGB(ModuleList M) { return isRightGB(M,false); } /** * Module right Groebner base test. * @param M a module basis. * @param top true for TOP term order, false for POT term order. * @return true, if M is a right Groebner base, else false. */ public boolean isRightGB(ModuleList M, boolean top) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } if (top) { logger.warn("computation of rightGB with TOP not possible"); } int modv = M.cols; // > 0 PolynomialList F = M.getPolynomialList(top); //System.out.println("F test = " + F); return isRightGB(modv, F.castToSolvableList()); } /** * Right Groebner base using pairlist class. * @param M a module basis. * @return rightGB(M) a right Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList rightGB(ModuleList M) { // boolean top ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } if (debug) { logger.info("M ====================== \n{}", M); } TermOrder to = M.ring.tord; if (to.getSplit() <= M.ring.nvar) { throw new IllegalArgumentException("extended TermOrders not supported for rightGBs: " + to); } List>> mlist = M.castToSolvableList(); GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) M.ring; GenSolvablePolynomialRing rring = sring.reverse(true); //true sring = rring.reverse(true); // true List>> nlist = new ArrayList>>(M.rows); for (List> row : mlist) { List> nrow = new ArrayList>(row.size()); for (GenSolvablePolynomial elem : row) { GenSolvablePolynomial nelem = (GenSolvablePolynomial) elem.reverse(rring); nrow.add(nelem); } nlist.add(nrow); } ModuleList rM = new ModuleList(rring, nlist); if (debug) { logger.info("rM -------------------- \n{}", rM); } ModuleList rMg = leftGB(rM); // top ? if (debug) { logger.info("rMg -------------------- \n{}", rMg); logger.info("isLeftGB(rMg) ---------- {}", isLeftGB(rMg)); } mlist = rMg.castToSolvableList(); nlist = new ArrayList>>(rMg.rows); for (List> row : mlist) { List> nrow = new ArrayList>(row.size()); for (GenSolvablePolynomial elem : row) { GenSolvablePolynomial nelem = (GenSolvablePolynomial) elem.reverse(sring); nrow.add(nelem); } nlist.add(nrow); } ModuleList Mg = new ModuleList(sring, nlist); if (debug) { logger.info("Mg -------------------- \n{}", Mg); logger.info("isRightGB(Mg) --------- {}", isRightGB(Mg)); } return Mg; } /** * Test if left reduction matrix. * @param exgb an SolvableExtendedGB container. * @return true, if exgb contains a left reduction matrix, else false. */ public boolean isLeftReductionMatrix(SolvableExtendedGB exgb) { if (exgb == null) { return true; } return isLeftReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F); } /** * Test if left reduction matrix. * @param F a solvable polynomial list. * @param G a left Groebner base. * @param Mf a possible left reduction matrix. * @param Mg a possible left reduction matrix. * @return true, if Mg and Mf are left reduction matrices, else false. */ public boolean isLeftReductionMatrix(List> F, List> G, List>> Mf, List>> Mg) { // no more check G and Mg: G * Mg[i] == 0 // check F and Mg: F * Mg[i] == G[i] int k = 0; for (List> row : Mg) { boolean t = sred.isLeftReductionNF(row, F, G.get(k), null); if (!t) { System.out.println("row = " + row); System.out.println("F = " + F); System.out.println("G[" + k + "] = " + G.get(k)); logger.info("F isLeftReductionMatrix s, k = {}, {}", F.size(), k); System.out.println("F*row == G[k]: " + sred.isLeftReductionNF(F, row, G.get(k), null)); return false; } k++; } // check G and Mf: G * Mf[i] == F[i] k = 0; for (List> row : Mf) { boolean t = sred.isLeftReductionNF(row, G, F.get(k), null); if (!t) { System.out.println("row = " + row); System.out.println("G = " + G); System.out.println("F[" + k + "] = " + F.get(k)); logger.info("G isLeftReductionMatrix s, k = {}, {}", G.size(), k); return false; } k++; } return true; } /** * Ideal common zero test. * @return -1, 0 or 1 if dimension(this) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest(List> A) { List> cA = PolynomialList. castToList(A); return cbb.commonZeroTest(cA); } /** * Univariate head term degrees. * @param A list of solvable polynomials. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees(List> A) { List> cA = PolynomialList. castToList(A); return cbb.univariateDegrees(cA); } /** * Construct univariate solvable polynomial of minimal degree in variable i * of a zero dimensional ideal(G). * @param i variable index. * @param G list of solvable polynomials, a monic reduced left Gröbner * base of a zero dimensional ideal. * @return univariate solvable polynomial of minimal degree in variable i in * ideal_left(G) */ public GenSolvablePolynomial constructUnivariate(int i, List> G) { if (G == null || G.size() == 0) { throw new IllegalArgumentException("G may not be null or empty"); } List ud = univariateDegrees(G); if (ud.size() <= i) { //logger.info("univ pol, ud = {}", ud); throw new IllegalArgumentException("ideal(G) not zero dimensional " + ud); } int ll = 0; Long di = ud.get(i); if (di != null) { ll = (int) (long) di; } else { throw new IllegalArgumentException("ideal(G) not zero dimensional"); } long vsdim = 1; for (Long d : ud) { if (d != null) { vsdim *= d; } } logger.info("univariate construction, deg = {}, vsdim = {}", ll, vsdim); GenSolvablePolynomialRing pfac = G.get(0).ring; RingFactory cfac = pfac.coFac; GenPolynomialRing cpfac = new GenPolynomialRing(cfac, ll, new TermOrder(TermOrder.INVLEX)); GenSolvablePolynomialRing> rfac = new GenSolvablePolynomialRing>( cpfac, pfac); // relations GenSolvablePolynomial> P = rfac.getZERO(); for (int k = 0; k < ll; k++) { GenSolvablePolynomial> Pp = rfac.univariate(i, k); GenPolynomial cp = cpfac.univariate(cpfac.nvar - 1 - k); Pp = Pp.multiply(cp); P = (GenSolvablePolynomial>) P.sum(Pp); } if (debug) { logger.info("univariate construction, P = {}", P); logger.info("univariate construction, deg_*(G) = {}", ud); //throw new RuntimeException("check"); } GroebnerBaseAbstract bbc = new GroebnerBaseSeq(); GenSolvablePolynomial X; GenSolvablePolynomial XP; // solve system of linear equations for the coefficients of the univariate polynomial List> ls; int z = -1; do { //System.out.println("ll = " + ll); GenSolvablePolynomial> Pp = rfac.univariate(i, ll); GenPolynomial cp = cpfac.univariate(cpfac.nvar - 1 - ll); Pp = Pp.multiply(cp); P = (GenSolvablePolynomial>) P.sum(Pp); X = pfac.univariate(i, ll); XP = sred.leftNormalform(G, X); //System.out.println("XP = " + XP); GenSolvablePolynomial> XPp = PolyUtil. toRecursive(rfac, XP); GenSolvablePolynomial> XPs = (GenSolvablePolynomial>) XPp .sum(P); ls = new ArrayList>(XPs.getMap().values()); //System.out.println("ls,1 = " + ls); ls = red.irreducibleSet(ls); z = bbc.commonZeroTest(ls); if (z != 0) { ll++; if (ll > vsdim) { logger.info("univariate construction, P = {}", P); logger.info("univariate construction, nf(P) = {}", XP); logger.info("G = {}", G); throw new ArithmeticException( "univariate polynomial degree greater than vector space dimansion"); } cpfac = cpfac.extend(1); rfac = new GenSolvablePolynomialRing>(cpfac, pfac); P = PolyUtil. extendCoefficients(rfac, P, 0, 0L); XPp = PolyUtil. extendCoefficients(rfac, XPp, 0, 1L); P = (GenSolvablePolynomial>) P.sum(XPp); } } while (z != 0); // && ll <= 5 && !XP.isZERO() // construct result polynomial String var = pfac.getVars()[pfac.nvar - 1 - i]; GenSolvablePolynomialRing ufac = new GenSolvablePolynomialRing(cfac, 1, new TermOrder( TermOrder.INVLEX), new String[] { var }); GenSolvablePolynomial pol = ufac.univariate(0, ll); for (GenPolynomial pc : ls) { ExpVector e = pc.leadingExpVector(); if (e == null) { continue; } int[] v = e.dependencyOnVariables(); if (v == null || v.length == 0) { continue; } int vi = v[0]; C tc = pc.trailingBaseCoefficient(); tc = tc.negate(); GenSolvablePolynomial pi = ufac.univariate(0, ll - 1 - vi); pi = pi.multiply(tc); pol = (GenSolvablePolynomial) pol.sum(pi); } if (logger.isInfoEnabled()) { logger.info("univariate construction, pol = {}", pol); } return pol; } /** * Construct univariate solvable polynomials of minimal degree in all * variables in zero dimensional left ideal(G). * @return list of univariate polynomial of minimal degree in each variable * in ideal_left(G) */ public List> constructUnivariate(List> G) { List> univs = new ArrayList>(); if (G == null || G.isEmpty()) { return univs; } for (int i = G.get(0).ring.nvar - 1; i >= 0; i--) { GenSolvablePolynomial u = constructUnivariate(i, G); univs.add(u); } return univs; } /** * Cleanup and terminate ThreadPool. */ public void terminate() { logger.info("terminate not implemented"); //throw new RuntimeException("get a stack trace"); } /** * Cancel ThreadPool. */ public int cancel() { logger.info("cancel not implemented"); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableGroebnerBaseParallel.java000066400000000000000000000477311445075545500266310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.util.Terminator; /** * Solvable Groebner Base parallel algorithm. Implements a shared memory * parallel version of Groebner bases. Threads maintain pairlist. * @param coefficient type * @author Heinz Kredel */ public class SolvableGroebnerBaseParallel> extends SolvableGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBaseParallel.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Constructor. */ public SolvableGroebnerBaseParallel() { this(2); } /** * Constructor. * @param threads number of threads to use. */ public SolvableGroebnerBaseParallel(int threads) { this(threads, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. */ public SolvableGroebnerBaseParallel(int threads, ExecutorService pool) { this(threads, pool, new SolvableReductionPar()); } /** * Constructor. * @param threads number of threads to use. * @param sred parallelism aware reduction engine */ public SolvableGroebnerBaseParallel(int threads, SolvableReduction sred) { this(threads, Executors.newFixedThreadPool(threads), sred); } /** * Constructor. * @param threads number of threads to use. * @param pl pair selection strategy */ public SolvableGroebnerBaseParallel(int threads, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), new SolvableReductionPar(), pl); } /** * Constructor. * @param threads number of threads to use. * @param sred parallelism aware reduction engine * @param pl pair selection strategy */ public SolvableGroebnerBaseParallel(int threads, SolvableReduction sred, PairList pl) { this(threads, Executors.newFixedThreadPool(threads), sred, pl); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param sred parallelism aware reduction engine */ public SolvableGroebnerBaseParallel(int threads, ExecutorService pool, SolvableReduction sred) { this(threads, pool, sred, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param sred parallelism aware reduction engine * @param pl pair selection strategy */ public SolvableGroebnerBaseParallel(int threads, ExecutorService pool, SolvableReduction sred, PairList pl) { super(sred, pl); if (!(sred instanceof SolvableReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("{}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("{}", pool); return s; } /** * Parallel Groebner base using sequential pair order class. Threads * maintain pairlist. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> leftGB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolynomialList.castToSolvableList(PolyUtil. monic(PolynomialList.castToList(G))); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField() && ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.castToList(G)); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); LeftSolvableReducer R; for (int i = 0; i < threads; i++) { R = new LeftSolvableReducer(fin, G, pairlist); pool.execute(R); } fin.waitDone(); logger.debug("#parallel list = {}", G.size()); G = leftMinimalGB(G); // not in this context // pool.terminate(); logger.info("end {}", pairlist); return G; } /** * Minimal ordered groebner basis, parallel. * @param Fp a Groebner base. * @return minimalGB(F) a minimal Groebner base of Fp. */ @Override public List> leftMinimalGB(List> Fp) { GenSolvablePolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenSolvablePolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); // no thread at this point } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } @SuppressWarnings("unchecked") SolvableMiReducer[] mirs = (SolvableMiReducer[]) new SolvableMiReducer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new SolvableMiReducer(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } /** * Twosided Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of F. */ @SuppressWarnings("unchecked") public List> twosidedGB(int modv, List> Fp) { List> G = normalizeZerosOnes(Fp); G = PolynomialList.castToSolvableList(PolyUtil. monic(PolynomialList.castToList(G))); if (G.size() < 1) { // 0 not 1 return G; } if (G.size() <= 1) { if (G.get(0).isONE()) { return G; } } GenSolvablePolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField() && ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficients not from a field"); } // add also coefficient generators List> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List> F = new ArrayList>(G.size() * (1 + X.size())); F.addAll(G); GenSolvablePolynomial p, x, q; for (int i = 0; i < F.size(); i++) { // F changes p = F.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } q = p.multiply(x); q = sred.leftNormalform(F, q); if (!q.isZERO()) { q = q.monic(); if (q.isONE()) { G.clear(); G.add(q); return G; } F.add(q); } } } //System.out.println("F generated = " + F); G = F; if (G.size() <= 1) { // 1 okay here return G; } PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.castToList(G)); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); TwosidedSolvableReducer R; for (int i = 0; i < threads; i++) { R = new TwosidedSolvableReducer(fin, modv, X, G, pairlist); pool.execute(R); } fin.waitDone(); logger.debug("#parallel list = {}", G.size()); G = leftMinimalGB(G); // not in this context // pool.terminate(); logger.info("end {}", pairlist); return G; } } /** * Reducing left worker threads. * @param coefficient type */ class LeftSolvableReducer> implements Runnable { private final List> G; private final PairList pairlist; private final Terminator pool; private final SolvableReductionPar sred; private static final Logger logger = LogManager.getLogger(LeftSolvableReducer.class); private static final boolean debug = logger.isDebugEnabled(); LeftSolvableReducer(Terminator fin, List> G, PairList L) { pool = fin; this.G = G; pairlist = L; sred = new SolvableReductionPar(); } @SuppressWarnings("unchecked") public void run() { Pair pair; GenSolvablePolynomial S; GenSolvablePolynomial H; boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || pool.hasJobs()) { while (!pairlist.hasNext()) { // wait pool.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { pool.allIdle(); logger.info("shutdown {} after: {}", pool, e); //throw new RuntimeException("interrupt 1 in pairlist.hasNext loop"); break; } if (Thread.currentThread().isInterrupted()) { //pool.initIdle(1); pool.allIdle(); logger.info("shutdown after .isInterrupted(): {}", pool); //throw new RuntimeException("interrupt 2 in pairlist.hasNext loop"); break; } if (!pool.hasJobs()) { break; } } if (!pairlist.hasNext() && !pool.hasJobs()) { break; } if (set) { pool.notIdle(); set = false; } pair = pairlist.removeNext(); if (pair == null) { continue; } if (debug) { logger.debug("pi = {}", pair.pi); logger.debug("pj = {}", pair.pj); } S = sred.leftSPolynomial((GenSolvablePolynomial) pair.pi, (GenSolvablePolynomial) pair.pj); if (S.isZERO()) { continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); //mod reduction++; if (H.isZERO()) { continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { pairlist.putOne(); // not really required synchronized (G) { G.clear(); G.add(H); } pool.allIdle(); return; } if (debug) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.put(H); } logger.info("terminated, done {} reductions", reduction); } } /** * Reducing twosided worker threads. * @param coefficient type */ class TwosidedSolvableReducer> implements Runnable { private final List> X; private final List> G; private final PairList pairlist; private final int modv; private final Terminator pool; private final SolvableReductionPar sred; private static final Logger logger = LogManager.getLogger(TwosidedSolvableReducer.class); private static final boolean debug = logger.isDebugEnabled(); TwosidedSolvableReducer(Terminator fin, int modv, List> X, List> G, PairList L) { pool = fin; this.modv = modv; this.X = X; this.G = G; pairlist = L; sred = new SolvableReductionPar(); } public void run() { GenSolvablePolynomial p, x, S, H; Pair pair; boolean set = false; int reduction = 0; int sleeps = 0; logger.debug("modv = {}", modv); // avoid "unused" while (pairlist.hasNext() || pool.hasJobs()) { while (!pairlist.hasNext()) { // wait pool.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(50); } catch (InterruptedException e) { break; } if (!pool.hasJobs()) { break; } } if (!pairlist.hasNext() && !pool.hasJobs()) { break; } if (set) { pool.notIdle(); set = false; } pair = pairlist.removeNext(); if (pair == null) { continue; } if (debug) { logger.debug("pi = {}", pair.pi); logger.debug("pj = {}", pair.pj); } S = sred.leftSPolynomial((GenSolvablePolynomial) pair.pi, (GenSolvablePolynomial) pair.pj); if (S.isZERO()) { continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); //mod reduction++; if (H.isZERO()) { continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { pairlist.putOne(); // not really required synchronized (G) { G.clear(); G.add(H); } pool.allIdle(); return; } if (debug) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.put(H); for (int j = 0; j < X.size(); j++) { x = X.get(j); p = H.multiply(x); p = sred.leftNormalform(G, p); if (!p.isZERO()) { p = p.monic(); if (p.isONE()) { synchronized (G) { G.clear(); G.add(p); } pool.allIdle(); return; } synchronized (G) { G.add(p); } pairlist.put(p); } } } logger.info("terminated, done {} reductions", reduction); } } /** * Reducing worker threads for minimal GB. * @param coefficient type */ class SolvableMiReducer> implements Runnable { private final List> G; private GenSolvablePolynomial H; private final SolvableReductionPar sred; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(SolvableMiReducer.class); private static final boolean debug = logger.isDebugEnabled(); SolvableMiReducer(List> G, GenSolvablePolynomial p) { this.G = G; H = p; sred = new SolvableReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenSolvablePolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } public void run() { if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = sred.leftNormalform(G, H); //mod done.release(); //done.V(); if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableGroebnerBaseSeq.java000066400000000000000000000652551445075545500256260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Solvable Groebner bases sequential algorithms. Implements common left, right * and twosided Groebner bases and left, right and twosided GB tests. * @param coefficient type * @author Heinz Kredel */ public class SolvableGroebnerBaseSeq> extends SolvableGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public SolvableGroebnerBaseSeq() { super(); } /** * Constructor. * @param sred Solvable reduction engine */ public SolvableGroebnerBaseSeq(SolvableReduction sred) { super(sred); } /** * Constructor. * @param pl pair selection strategy */ public SolvableGroebnerBaseSeq(PairList pl) { super(pl); } /** * Constructor. * @param sred Solvable reduction engine * @param pl pair selection strategy */ public SolvableGroebnerBaseSeq(SolvableReduction sred, PairList pl) { super(sred, pl); } /** * Left Groebner base using pairlist class. * @param modv number of module variables. * @param F solvable polynomial list. * @return leftGB(F) a left Groebner base of F. */ @SuppressWarnings("unchecked") public List> leftGB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolynomialList.castToSolvableList(PolyUtil. monic(PolynomialList.castToList(G))); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField() && ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficients not from a field: " + ring.coFac.toScript()); } PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.castToList(G)); logger.info("start {}", pairlist); GenSolvablePolynomial pi, pj, S, H; Pair pair; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) { continue; } pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.info("pi = {}", pi.leadingExpVector()); logger.info("pj = {}", pj.leadingExpVector()); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); //logger.info("ht(H) = {}, lc(H) = {}", H.leadingExpVector(), H.leadingBaseCoefficient().toScript()); } H = H.monic(); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { // logger.info("H = {}", H); logger.info("#monic(H) = {}", H.length()); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("end {}", pairlist); return G; } /** * Solvable Extended Groebner base using critical pair class. * @param modv module variable number. * @param F solvable polynomial list. * @return a container for an extended left Groebner base of F. */ @Override @SuppressWarnings("unchecked") public SolvableExtendedGB extLeftGB(int modv, List> F) { if (F == null || F.isEmpty()) { throw new IllegalArgumentException("null or empty F not allowed"); } List> G = new ArrayList>(); List>> F2G = new ArrayList>>(); List>> G2F = new ArrayList>>(); PairList pairlist = null; boolean oneInGB = false; int len = F.size(); List> row = null; List> rows = null; List> rowh = null; GenSolvablePolynomialRing ring = null; GenSolvablePolynomial p, H; int nzlen = 0; for (GenSolvablePolynomial f : F) { if (f.length() > 0) { nzlen++; } if (ring == null) { ring = f.ring; } } GenSolvablePolynomial mone = ring.getONE(); //.negate(); int k = 0; ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { row = PolynomialList. castToSolvableList(blas.genVector(nzlen, null)); //C c = p.leadingBaseCoefficient(); //c = c.inverse(); //p = p.multiply( c ); row.set(k, mone); //.multiply(c) ); k++; if (p.isUnit()) { G.clear(); G.add(p); G2F.clear(); G2F.add(row); oneInGB = true; break; } G.add(p); G2F.add(row); if (pairlist == null) { //pairlist = new CriticalPairList( modv, p.ring ); pairlist = strategy.create(modv, p.ring); } // putOne not required pairlist.put(p); } else { len--; } } SolvableExtendedGB exgb; if (len <= 1 || oneInGB) { // adjust F2G for (GenSolvablePolynomial f : F) { row = PolynomialList. castToSolvableList(blas.genVector(G.size(), null)); H = sred.leftNormalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero_1 H = {}, G = {}, f = {}, row = {}", H, G, f, row); } F2G.add(row); } exgb = new SolvableExtendedGB(F, G, F2G, G2F); //System.out.println("exgb 1 = " + exgb); return exgb; } logger.info("start {}", pairlist); Pair pair; int i, j; GenSolvablePolynomial pi, pj, S; // x, y; //GenPolynomial z; while (pairlist.hasNext() && !oneInGB) { pair = pairlist.removeNext(); if (pair == null) { //pairlist.update(); // ? continue; } i = pair.i; j = pair.j; pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.info("i, pi = {}, {}", i, pi); logger.info("j, pj = {}, {}", j, pj); } rows = PolynomialList. castToSolvableList(blas.genVector(G.size(), null)); S = sred.leftSPolynomial(rows, i, pi, j, pj); if (debug) { logger.debug("is reduction S = {}", sred.isLeftReductionNF(rows, G, ring.getZERO(), S)); } if (S.isZERO()) { pair.setZero(); //pairlist.update( pair, S ); // do not add to G2F continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } rowh = PolynomialList. castToSolvableList(blas.genVector(G.size(), null)); H = sred.leftNormalform(rowh, G, S); if (debug) { //System.out.println("H = " + H); logger.debug("is reduction H = {}", sred.isLeftReductionNF(rowh, G, S, H)); } if (H.isZERO()) { pair.setZero(); //pairlist.update( pair, H ); // do not add to G2F continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } row = PolynomialList. castToSolvableList(blas.vectorCombineOld( PolynomialList. castToList(rows), PolynomialList. castToList(rowh))); // if (debug) { // logger.debug("is reduction 0+sum(row,G) == H : " // + sred.isLeftReductionNF(row, G, H, ring.getZERO())); // } //H = H.leftMonic(); //left C c = H.leadingBaseCoefficient(); c = c.inverse(); H = H.multiplyLeft(c); // 1*c*row, leads to wrong method dispatch: row = PolynomialList. castToSolvableList( blas.scalarProduct(mone.multiply(c), PolynomialList. castToList(row))); row.set(G.size(), mone); if (H.isONE()) { // pairlist.record( pair, H ); // G.clear(); G.add(H); G2F.add(row); oneInGB = true; break; } if (debug) { logger.debug("H = {}", H); } G.add(H); //pairlist.update( pair, H ); pairlist.put(H); G2F.add(row); } if (debug) { exgb = new SolvableExtendedGB(F, G, F2G, G2F); logger.info("exgb unnorm = {}", exgb); } G2F = normalizeMatrix(F.size(), G2F); if (debug) { exgb = new SolvableExtendedGB(F, G, F2G, G2F); logger.info("exgb nonmin = {}", exgb); boolean t2 = isLeftReductionMatrix(exgb); logger.debug("exgb t2 = {}", t2); } exgb = minimalSolvableExtendedGB(F.size(), G, G2F); G = exgb.G; G2F = exgb.G2F; logger.debug("#sequential list = {}", G.size()); logger.info("end {}", pairlist); // setup matrices F and F2G for (GenSolvablePolynomial f : F) { row = PolynomialList. castToSolvableList(blas.genVector(G.size(), null)); H = sred.leftNormalform(row, G, f); if (!H.isZERO()) { logger.error("nonzero_end H = {}, G = {}, f = {}, row = {}", H, G, f, row); logger.error("nonzero_end ring = {}", H.ring.toScript()); //throw new RuntimeException("nonzero_end H = " + H); } F2G.add(row); } logger.info("extLeftGB end"); return new SolvableExtendedGB(F, G, F2G, G2F); } /** * Twosided Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ @SuppressWarnings("unchecked") public List> twosidedGB(int modv, List> Fp) { List> F = normalizeZerosOnes(Fp); F = PolynomialList.castToSolvableList(PolyUtil. monic(PolynomialList.castToList(F))); if (F.size() < 1) { // 0 not 1 return F; } if (F.size() == 1 && F.get(0).isONE()) { return F; } GenSolvablePolynomialRing ring = F.get(0).ring; if (!ring.coFac.isField() && ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficients not from a field"); } // add also coefficient generators List> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List> G = new ArrayList>(F.size() * (1 + X.size())); G.addAll(F); logger.info("right multiply: G = {}", G); GenSolvablePolynomial p, q; for (int i = 0; i < G.size(); i++) { // G changes p = G.get(i); for (GenSolvablePolynomial x : X) { //x = X.get(j); if (x.isONE()) { continue; } q = p.multiply(x); logger.info("right multiply: p = {}, x = {}, q = {}", p, x, q); q = sred.leftNormalform(G, q); q = q.monic(); logger.info("right multiply: red(q) = {}", q); if (!q.isZERO()) { //System.out.println("q generating: = " + q + ", p = " + p + ", x = " + x); if (q.isONE()) { //System.out.println("G generated so far: " + G); G.clear(); G.add(q); return G; // since no threads are activated } if (!G.contains(q)) { // why? G.add(q); } else { logger.info("right multiply contained: q = {}", q); } } } } if (G.size() <= 1) { // 1 ok return G; // since no threads are activated } //System.out.println("G generated = " + G); PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.castToList(G)); logger.info("twosided start {}", pairlist); Pair pair; GenSolvablePolynomial pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) { continue; } pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.debug("H = {}", H); } if (H.length() > 0) { G.add(H); pairlist.put(H); //System.out.println("H generated = " + H); for (GenSolvablePolynomial x : X) { //x = X.get(j); if (x.isONE()) { continue; } q = H.multiply(x); p = sred.leftNormalform(G, q); if (!p.isZERO()) { //System.out.println("p generated = " + p + ", x = " + x); p = p.monic(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads are activated } G.add(p); pairlist.put(p); } } //System.out.println("G generated = " + G); } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("twosided end {}", pairlist); return G; } /** * Normalize M. Make all rows the same size and make certain column elements * zero. * @param M a reduction matrix. * @return normalized M. */ public List>> normalizeMatrix(int flen, List>> M) { if (M == null) { return M; } if (M.size() == 0) { return M; } List>> N = new ArrayList>>(); List>> K = new ArrayList>>(); int len = M.get(M.size() - 1).size(); // longest row // pad / extend rows for (List> row : M) { List> nrow = new ArrayList>(row); for (int i = row.size(); i < len; i++) { nrow.add(null); } N.add(nrow); } // System.out.println("norm N fill = " + N); // make zero columns int k = flen; for (int i = 0; i < N.size(); i++) { // 0 List> row = N.get(i); if (debug) { logger.info("row = {}", row); } K.add(row); if (i < flen) { // skip identity part continue; } List> xrow; GenSolvablePolynomial a; //System.out.println("norm i = " + i); for (int j = i + 1; j < N.size(); j++) { List> nrow = N.get(j); //System.out.println("nrow j = " +j + ", " + nrow); if (k < nrow.size()) { // always true a = nrow.get(k); //System.out.println("k, a = " + k + ", " + a); if (a != null && !a.isZERO()) { // a*row + nrow, leads to wrong method dispatch List> yrow = blas.scalarProduct(a, PolynomialList. castToList(row)); yrow = blas.vectorAdd(yrow, PolynomialList. castToList(nrow)); xrow = PolynomialList. castToSolvableList(yrow); N.set(j, xrow); } } } k++; } //System.out.println("norm K reduc = {}", K); // truncate N.clear(); for (List> row : K) { List> tr = new ArrayList>(); for (int i = 0; i < flen; i++) { tr.add(row.get(i)); } N.add(tr); } K = N; //System.out.println("norm K trunc = " + K); return K; } /** * Test if M is a left reduction matrix. * @param exgb an SolvableExtendedGB container. * @return true, if exgb contains a left reduction matrix, else false. */ @Override public boolean isLeftReductionMatrix(SolvableExtendedGB exgb) { if (exgb == null) { return true; } return isLeftReductionMatrix(exgb.F, exgb.G, exgb.F2G, exgb.G2F); } /** * Minimal solvable extended groebner basis. * @param Gp a left Groebner base. * @param M a left reduction matrix, is modified. * @return a (partially) reduced left Groebner base of Gp in a container. */ public SolvableExtendedGB minimalSolvableExtendedGB(int flen, List> Gp, List>> M) { if (Gp == null) { return null; //new SolvableExtendedGB(null,Gp,null,M); } if (Gp.size() <= 1) { return new SolvableExtendedGB(null, Gp, null, M); } List> G; List> F; G = new ArrayList>(Gp); F = new ArrayList>(Gp.size()); List>> Mg; List>> Mf; Mg = new ArrayList>>(M.size()); Mf = new ArrayList>>(M.size()); List> row; for (List> r : M) { // must be copied also row = new ArrayList>(r); Mg.add(row); } row = null; GenSolvablePolynomial a; ExpVector e; ExpVector f; GenSolvablePolynomial p; boolean mt; ListIterator> it; ArrayList ix = new ArrayList(); ArrayList jx = new ArrayList(); int k = 0; //System.out.println("flen, Gp, M = " + flen + ", " + Gp.size() + ", " + M.size() ); while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } //System.out.println("k, mt = " + k + ", " + mt); if (!mt) { F.add(a); ix.add(k); } else { // drop polynomial and corresponding row and column // F.add( a.ring.getZERO() ); jx.add(k); } k++; } if (debug) { logger.debug("ix, #M, jx = {}, {}, {}", ix, Mg.size(), jx); } int fix = -1; // copied polys // copy Mg to Mf as indicated by ix for (int i = 0; i < ix.size(); i++) { int u = ix.get(i); if (u >= flen && fix == -1) { fix = Mf.size(); } //System.out.println("copy u, fix = " + u + ", " + fix); if (u >= 0) { row = Mg.get(u); Mf.add(row); } } if (F.size() <= 1 || fix == -1) { return new SolvableExtendedGB(null, F, null, Mf); } // must return, since extended normalform has not correct order of polys /* G = F; F = new ArrayList>( G.size() ); List> temp; k = 0; final int len = G.size(); while ( G.size() > 0 ) { a = G.remove(0); if ( k >= fix ) { // dont touch copied polys row = Mf.get( k ); //System.out.println("doing k = " + k + ", " + a); // must keep order, but removed polys missing temp = new ArrayList>( len ); temp.addAll( F ); temp.add( a.ring.getZERO() ); // ?? temp.addAll( G ); //System.out.println("row before = " + row); a = sred.leftNormalform( row, temp, a ); //System.out.println("row after = " + row); } F.add( a ); k++; } // does Mf need renormalization? */ return new SolvableExtendedGB(null, F, null, Mf); } /** * Right Groebner base via right reduction using pairlist class. Overrides * rightGB() via opposite ring. * @param modv number of module variables. * @param F solvable polynomial list. * @return rightGB(F) a right Groebner base of F. */ @Override @SuppressWarnings("unchecked") public List> rightGB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolynomialList.castToSolvableList(PolyUtil. rightMonic(PolynomialList.castToList(G))); //G = PolyUtil. rightMonic(G); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField() && ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficients not from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.castToList(G)); logger.info("start {}", pairlist); GenSolvablePolynomial pi, pj, S, H; Pair pair; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) { continue; } pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.info("pi = {}", pi); logger.info("pj = {}", pj); } S = sred.rightSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", S.leadingExpVector()); //logger.info("S = {}", S); } H = sred.rightNormalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = H.rightMonic(); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); //G = rightMinimalGB(G); logger.info("end {}", pairlist); return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableGroebnerBaseSeqPairParallel.java000066400000000000000000000500211445075545500301000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; import edu.jas.util.Terminator; /** * Solvable Groebner Base parallel algorithm. Makes some effort to produce the * same sequence of critical pairs as in the sequential version. However already * reduced pairs are not rereduced if new polynomials appear. Implements a * shared memory parallel version of Groebner bases. Threads maintain pairlist. * @param coefficient type * @author Heinz Kredel */ public class SolvableGroebnerBaseSeqPairParallel> extends SolvableGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBaseSeqPairParallel.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Constructor. */ public SolvableGroebnerBaseSeqPairParallel() { this(2); } /** * Constructor. * @param threads number of threads to use. */ public SolvableGroebnerBaseSeqPairParallel(int threads) { this(threads, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. */ public SolvableGroebnerBaseSeqPairParallel(int threads, ExecutorService pool) { this(threads, pool, new SolvableReductionPar()); } /** * Constructor. * @param threads number of threads to use. * @param red parallelism aware reduction engine */ public SolvableGroebnerBaseSeqPairParallel(int threads, SolvableReduction red) { this(threads, Executors.newFixedThreadPool(threads), red); } /** * Constructor. * @param threads number of threads to use. * @param pool ExecutorService to use. * @param sred parallelism aware reduction engine */ public SolvableGroebnerBaseSeqPairParallel(int threads, ExecutorService pool, SolvableReduction sred) { super(sred); if (!(sred instanceof SolvableReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } if (threads < 1) { threads = 1; } this.threads = threads; this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("{}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("{}", pool); return s; } /** * Parallel Groebner base using sequential pair order class. Threads * maintain pairlist. * @param modv number of module variables. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> leftGB(int modv, List> F) { GenSolvablePolynomial p; List> G = new ArrayList>(); CriticalPairList pairlist = null; int l = F.size(); ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads activated jet } G.add(p); if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // putOne not required pairlist.put(p); } else { l--; } } if (l <= 1) { return G; // since no threads activated jet } Terminator fin = new Terminator(threads); LeftSolvableReducerSeqPair R; for (int i = 0; i < threads; i++) { R = new LeftSolvableReducerSeqPair(fin, G, pairlist); pool.execute(R); } fin.waitDone(); logger.debug("#parallel list = {}", G.size()); G = leftMinimalGB(G); // not in this context // pool.terminate(); logger.info("{}", pairlist); return G; } /** * Minimal ordered groebner basis, parallel. * @param Fp a Groebner base. * @return minimalGB(F) a minimal Groebner base of Fp. */ @Override public List> leftMinimalGB(List> Fp) { GenSolvablePolynomial a; ArrayList> G; G = new ArrayList>(Fp.size()); ListIterator> it = Fp.listIterator(); while (it.hasNext()) { a = it.next(); if (a.length() != 0) { // always true // already monic a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } ExpVector e; ExpVector f; GenSolvablePolynomial p; ArrayList> F; F = new ArrayList>(G.size()); boolean mt; while (G.size() > 0) { a = G.remove(0); e = a.leadingExpVector(); it = G.listIterator(); mt = false; while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } it = F.listIterator(); while (it.hasNext() && !mt) { p = it.next(); f = p.leadingExpVector(); mt = e.multipleOf(f); } if (!mt) { F.add(a); // no thread at this point } else { // System.out.println("dropped " + a.length()); } } G = F; if (G.size() <= 1) { return G; } @SuppressWarnings("unchecked") SolvableMiReducerSeqPair[] mirs = (SolvableMiReducerSeqPair[]) new SolvableMiReducerSeqPair[G .size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); // System.out.println("doing " + a.length()); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); mirs[i] = new SolvableMiReducerSeqPair(R, a); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } return F; } /** * Twosided Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of F. */ public List> twosidedGB(int modv, List> Fp) { if (Fp == null || Fp.size() == 0) { // 0 not 1 return new ArrayList>(); } GenSolvablePolynomialRing ring = Fp.get(0).ring; // assert != null // add also coefficient generators List> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List> F = new ArrayList>(Fp.size() * (1 + X.size())); F.addAll(Fp); GenSolvablePolynomial p, x, q; for (int i = 0; i < F.size(); i++) { // F changes p = F.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } q = p.multiply(x); q = sred.leftNormalform(F, q); if (!q.isZERO()) { F.add(q); } } } //System.out.println("F generated = " + F); List> G = new ArrayList>(); CriticalPairList pairlist = null; int l = F.size(); ListIterator> it = F.listIterator(); while (it.hasNext()) { p = it.next(); if (p.length() > 0) { p = p.monic(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads are activated } G.add(p); if (pairlist == null) { pairlist = new CriticalPairList(modv, p.ring); if (!p.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } } // putOne not required pairlist.put(p); } else { l--; } } //System.out.println("G to check = " + G); if (l <= 1) { // 1 ok return G; // since no threads are activated } Terminator fin = new Terminator(threads); TwosidedSolvableReducerSeqPair R; for (int i = 0; i < threads; i++) { R = new TwosidedSolvableReducerSeqPair(fin, X, G, pairlist); pool.execute(R); } fin.waitDone(); logger.debug("#parallel list = {}", G.size()); G = leftMinimalGB(G); // not in this context // pool.terminate(); logger.info("{}", pairlist); return G; } } /** * Reducing left worker threads. * @param coefficient type */ class LeftSolvableReducerSeqPair> implements Runnable { private final List> G; private final CriticalPairList pairlist; private final Terminator pool; private final SolvableReductionPar sred; private static final Logger logger = LogManager.getLogger(LeftSolvableReducerSeqPair.class); private static final boolean debug = logger.isDebugEnabled(); LeftSolvableReducerSeqPair(Terminator fin, List> G, CriticalPairList L) { pool = fin; this.G = G; pairlist = L; sred = new SolvableReductionPar(); } @SuppressWarnings("unchecked") public void run() { CriticalPair pair; GenSolvablePolynomial S; GenSolvablePolynomial H; boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || pool.hasJobs()) { while (!pairlist.hasNext()) { pairlist.update(); // wait pool.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { break; } if (!pool.hasJobs()) { break; } } if (!pairlist.hasNext() && !pool.hasJobs()) { break; } if (set) { pool.notIdle(); set = false; } pair = pairlist.getNext(); if (pair == null) { pairlist.update(); continue; } if (debug) { logger.debug("pi = {}", pair.pi); logger.debug("pj = {}", pair.pj); } S = sred.leftSPolynomial((GenSolvablePolynomial) pair.pi, (GenSolvablePolynomial) pair.pj); if (S.isZERO()) { pairlist.record(pair, S); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); //mod reduction++; if (H.isZERO()) { pairlist.record(pair, H); continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { // pairlist.update( pair, H ); pairlist.putOne(); // not really required synchronized (G) { G.clear(); G.add(H); } pool.allIdle(); return; } if (debug) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.update(pair, H); //pairlist.record( pair, H ); //pairlist.update(); } logger.info("terminated, done {} reductions", reduction); } } /** * Reducing twosided worker threads. * @param coefficient type */ class TwosidedSolvableReducerSeqPair> implements Runnable { private final List> X; private final List> G; private final CriticalPairList pairlist; private final Terminator pool; private final SolvableReductionPar sred; private static final Logger logger = LogManager.getLogger(TwosidedSolvableReducerSeqPair.class); private static final boolean debug = logger.isDebugEnabled(); TwosidedSolvableReducerSeqPair(Terminator fin, List> X, List> G, CriticalPairList L) { pool = fin; this.X = X; this.G = G; pairlist = L; sred = new SolvableReductionPar(); } public void run() { GenSolvablePolynomial p, x; CriticalPair pair; GenSolvablePolynomial S; GenSolvablePolynomial H; boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || pool.hasJobs()) { while (!pairlist.hasNext()) { pairlist.update(); // wait pool.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(50); } catch (InterruptedException e) { break; } if (!pool.hasJobs()) { break; } } if (!pairlist.hasNext() && !pool.hasJobs()) { break; } if (set) { pool.notIdle(); set = false; } pair = pairlist.getNext(); if (pair == null) { pairlist.update(); continue; } if (debug) { logger.debug("pi = {}", pair.pi); logger.debug("pj = {}", pair.pj); } S = sred.leftSPolynomial((GenSolvablePolynomial) pair.pi, (GenSolvablePolynomial) pair.pj); if (S.isZERO()) { pairlist.record(pair, S); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = sred.leftNormalform(G, S); //mod reduction++; if (H.isZERO()) { pairlist.record(pair, H); continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = H.monic(); // System.out.println("H = " + H); if (H.isONE()) { // pairlist.update( pair, H ); pairlist.putOne(); // not really required synchronized (G) { G.clear(); G.add(H); } pool.allIdle(); return; } if (debug) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.update(pair, H); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } p = H.multiply(x); p = sred.leftNormalform(G, p); if (!p.isZERO()) { p = p.monic(); if (p.isONE()) { synchronized (G) { G.clear(); G.add(p); } pool.allIdle(); return; } synchronized (G) { G.add(p); } pairlist.put(p); } } } logger.info("terminated, done {} reductions", reduction); } } /** * Reducing worker threads for minimal GB. * @param coefficient type */ class SolvableMiReducerSeqPair> implements Runnable { private final List> G; private GenSolvablePolynomial H; private final SolvableReductionPar sred; private final Semaphore done = new Semaphore(0); private static final Logger logger = LogManager.getLogger(SolvableMiReducerSeqPair.class); private static final boolean debug = logger.isDebugEnabled(); SolvableMiReducerSeqPair(List> G, GenSolvablePolynomial p) { this.G = G; H = p; sred = new SolvableReductionPar(); } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenSolvablePolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { } return H; } public void run() { if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = sred.leftNormalform(G, H); //mod done.release(); //done.V(); if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableReduction.java000066400000000000000000000133601445075545500245410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Solvable polynomial Reduction interface. Defines S-Polynomial, normalform and * irreducible set. * @param coefficient type * @author Heinz Kredel */ public interface SolvableReduction> extends Serializable { /** * Left S-Polynomial. * @param Ap solvable polynomial. * @param Bp solvable polynomial. * @return left-spol(Ap,Bp) the left S-polynomial of Ap and Bp. */ public GenSolvablePolynomial leftSPolynomial(GenSolvablePolynomial Ap, GenSolvablePolynomial Bp); /** * S-Polynomial with recording. * @param S recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return leftSpol(Ap, Bp), the left S-Polynomial for Ap and Bp. */ public GenSolvablePolynomial leftSPolynomial(List> S, int i, GenSolvablePolynomial Ap, int j, GenSolvablePolynomial Bp); /** * Left Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return left-nf(Ap) with respect to Pp. */ public GenSolvablePolynomial leftNormalform(List> Pp, GenSolvablePolynomial Ap); /** * LeftNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ public GenSolvablePolynomial leftNormalform(List> row, List> Pp, GenSolvablePolynomial Ap); /** * Left Normalform Set. * @param Ap solvable polynomial list. * @param Pp solvable polynomial list. * @return list of left-nf(a) with respect to Pp for all a in Ap. */ public List> leftNormalform(List> Pp, List> Ap); /** * Left irreducible set. * @param Pp solvable polynomial list. * @return a list P of solvable polynomials which are in normalform wrt. P. */ public List> leftIrreducibleSet(List> Pp); /** * Is reduction of normal form. * @param row recording matrix, is modified. * @param Pp a solvable polynomial list for reduction. * @param Ap a solvable polynomial. * @param Np nf(Pp,Ap), a left normal form of Ap wrt. Pp. * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false. */ public boolean isLeftReductionNF(List> row, List> Pp, GenSolvablePolynomial Ap, GenSolvablePolynomial Np); /** * Right S-Polynomial. * @param Ap solvable polynomial. * @param Bp solvable polynomial. * @return right-spol(Ap,Bp) the right S-polynomial of Ap and Bp. */ public GenSolvablePolynomial rightSPolynomial(GenSolvablePolynomial Ap, GenSolvablePolynomial Bp); /** * Right Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return right-nf(Ap) with respect to Pp. */ public GenSolvablePolynomial rightNormalform(List> Pp, GenSolvablePolynomial Ap); /** * RightNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ public GenSolvablePolynomial rightNormalform(List> row, List> Pp, GenSolvablePolynomial Ap); /** * Is top reducible. Condition is lt(B) | lt(A) for some B in F. Is left * right symmetric. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, GenSolvablePolynomial A); /** * Is reducible. Is left right symmetric. * @param A polynomial. * @param P polynomial list. * @return true if A is reducible with respect to P. */ public boolean isReducible(List> P, GenSolvablePolynomial A); /** * Is in normalform. Is left right symmetric. * @param A polynomial. * @param P polynomial list. * @return true if A is in normalform with respect to P. */ public boolean isNormalform(List> P, GenSolvablePolynomial A); /** * Is right reduction of normal form. * @param row recording matrix, is modified. * @param Pp a solvable polynomial list for reduction. * @param Ap a solvable polynomial. * @param Np nf(Pp,Ap), a right normal form of Ap wrt. Pp. * @return true, if Np + sum( Pp[i]*row[i] ) == Ap, else false. */ public boolean isRightReductionNF(List> row, List> Pp, GenSolvablePolynomial Ap, GenSolvablePolynomial Np); /** * Two-sided Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return two-sided-nf(Ap) with respect to Pp. */ public GenSolvablePolynomial normalform(List> Pp, GenSolvablePolynomial Ap); } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableReductionAbstract.java000066400000000000000000000436141445075545500262320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.Monomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Solvable polynomial Reduction abstract class. Implements common left, right * S-Polynomial, left normalform and left irreducible set. * @param coefficient type * @author Heinz Kredel */ public abstract class SolvableReductionAbstract> implements SolvableReduction { private static final Logger logger = LogManager.getLogger(SolvableReductionAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public SolvableReductionAbstract() { } /** * Left S-Polynomial. * @param Ap solvable polynomial. * @param Bp solvable polynomial. * @return left-spol(Ap,Bp) the left S-polynomial of Ap and Bp. */ public GenSolvablePolynomial leftSPolynomial(GenSolvablePolynomial Ap, GenSolvablePolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { if (Ap != null) { return Ap.ring.getZERO(); } return null; } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); GenSolvablePolynomial App = Ap.multiplyLeft(b, e1); GenSolvablePolynomial Bpp = Bp.multiplyLeft(a, f1); GenSolvablePolynomial Cp = (GenSolvablePolynomial) App.subtract(Bpp); return Cp; } /** * S-Polynomial with recording. * @param S recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return leftSpol(Ap, Bp), the left S-Polynomial for Ap and Bp. */ public GenSolvablePolynomial leftSPolynomial(List> S, int i, GenSolvablePolynomial Ap, int j, GenSolvablePolynomial Bp) { if (debug /*logger.isInfoEnabled()*/) { if (Bp == null || Bp.isZERO()) { throw new ArithmeticException("Spol B is zero"); } if (Ap == null || Ap.isZERO()) { throw new ArithmeticException("Spol A is zero"); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); GenSolvablePolynomial App = Ap.multiplyLeft(b, e1); GenSolvablePolynomial Bpp = Bp.multiplyLeft(a, f1); GenSolvablePolynomial Cp = (GenSolvablePolynomial) App.subtract(Bpp); GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial As = (GenSolvablePolynomial) zero.sum(b.negate(), e1); GenSolvablePolynomial Bs = (GenSolvablePolynomial) zero.sum(a, f1); S.set(i, As); S.set(j, Bs); return Cp; } /** * Left Normalform Set. * @param Ap solvable polynomial list. * @param Pp solvable polynomial list. * @return list of left-nf(a) with respect to Pp for all a in Ap. */ public List> leftNormalform(List> Pp, List> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isEmpty()) { return Ap; } ArrayList> red = new ArrayList>(); for (GenSolvablePolynomial A : Ap) { A = leftNormalform(Pp, A); red.add(A); } return red; } /** * Module left normalform set. * @param Ap module list. * @param Pp module list. * @return list of left-nf(a) with respect to Pp for all a in Ap. */ public ModuleList leftNormalform(ModuleList Pp, ModuleList Ap) { return leftNormalform(Pp, Ap, false); } /** * Module left normalform set. * @param Ap module list. * @param Pp module list. * @param top true for TOP term order, false for POT term order. * @return list of left-nf(a) with respect to Pp for all a in Ap. */ public ModuleList leftNormalform(ModuleList Pp, ModuleList Ap, boolean top) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isEmpty()) { return Ap; } GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) Pp.ring; int modv = Pp.cols; GenSolvablePolynomialRing pfac = sring.extend(modv, top); logger.debug("extended ring = {}", pfac.toScript()); //System.out.println("extended ring = " + pfac.toScript()); PolynomialList P = Pp.getPolynomialList(pfac); PolynomialList A = Ap.getPolynomialList(pfac); //System.out.println("P = " + P.toScript()); List> red = leftNormalform(P.castToSolvableList(), A.castToSolvableList()); PolynomialList Fr = new PolynomialList(pfac, red); ModuleList Nr = Fr.getModuleList(modv); return Nr; } /** * Left irreducible set. * @param Pp solvable polynomial list. * @return a list P of solvable polynomials which are in normalform wrt. P. */ public List> leftIrreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); for (GenSolvablePolynomial a : Pp) { if (a.length() != 0) { a = a.monic(); P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; ExpVector e; ExpVector f; GenSolvablePolynomial a; Iterator> it; logger.debug("irr = "); while (irr != l) { it = P.listIterator(); a = it.next(); P.remove(0); e = a.leadingExpVector(); a = leftNormalform(P, a); logger.debug(String.valueOf(irr)); if (a.length() == 0) { l--; if (l <= 1) { return P; } } else { f = a.leadingExpVector(); if (f.signum() == 0) { P = new ArrayList>(); P.add(a.monic()); return P; } if (e.equals(f)) { irr++; } else { irr = 0; a = a.monic(); } P.add(a); } } //System.out.println(); return P; } /** * Is reduction of normal form. * @param row recording matrix. * @param Pp a solvable polynomial list for reduction. * @param Ap a solvable polynomial. * @param Np nf(Pp,Ap), a left normal form of Ap wrt. Pp. * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false. */ @SuppressWarnings("unchecked") public boolean isLeftReductionNF(List> row, List> Pp, GenSolvablePolynomial Ap, GenSolvablePolynomial Np) { if (row == null && Pp == null) { if (Ap == null) { return Np == null; } return Ap.equals(Np); } if (row == null || Pp == null) { return false; } if (row.size() != Pp.size()) { return false; } GenSolvablePolynomial t = Np; GenSolvablePolynomial r; GenSolvablePolynomial p; for (int m = 0; m < Pp.size(); m++) { r = row.get(m); p = Pp.get(m); if (r != null && p != null) { if (t == null) { t = r.multiply(p); } else { t = (GenSolvablePolynomial) t.sum(r.multiply(p)); } } //System.out.println("r = " + r ); //System.out.println("p = " + p ); } if (debug) { logger.info("t = {}", t); logger.info("a = {}", Ap); } if (t == null) { if (Ap == null) { return true; } return Ap.isZERO(); } t = (GenSolvablePolynomial) t.subtract(Ap); return t.isZERO(); } /** * Right S-Polynomial. * @param Ap solvable polynomial. * @param Bp solvable polynomial. * @return right-spol(Ap,Bp) the right S-polynomial of Ap and Bp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightSPolynomial(GenSolvablePolynomial Ap, GenSolvablePolynomial Bp) { if (logger.isInfoEnabled()) { if (Bp == null || Bp.isZERO()) { if (Ap != null) { return Ap.ring.getZERO(); } return null; } if (Ap == null || Ap.isZERO()) { return Bp.ring.getZERO(); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } ExpVector e = Ap.leadingExpVector(); ExpVector f = Bp.leadingExpVector(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = Ap.leadingBaseCoefficient(); C b = Bp.leadingBaseCoefficient(); GenSolvablePolynomial App = Ap.multiply(b,e1); GenSolvablePolynomial Bpp = Bp.multiply(a,f1); // App = App.multiply(b); // Bpp = Bpp.multiply(a); if (!App.leadingMonomial().equals(Bpp.leadingMonomial()) ) { logger.info("lm(A) = " + new Monomial(App.leadingMonomial()) + ", lm(B) = " + new Monomial(Bpp.leadingMonomial())); logger.info("right S-polynomial with unequal leading monomials: " + Ap.ring.toScript()); //throw new UnsupportedOperationException("right S-polynomial with error"); } GenSolvablePolynomial Cp = (GenSolvablePolynomial) App.subtract(Bpp); return Cp; } /** * S-Polynomial with recording. * @param S recording matrix, is modified. * @param i index of Ap in basis list. * @param Ap a polynomial. * @param j index of Bp in basis list. * @param Bp a polynomial. * @return rightSpol(Ap, Bp), the right S-Polynomial for Ap and Bp. */ public GenSolvablePolynomial rightSPolynomial(List> S, int i, GenSolvablePolynomial Ap, int j, GenSolvablePolynomial Bp) { if (debug /*logger.isInfoEnabled()*/) { if (Bp == null || Bp.isZERO()) { throw new ArithmeticException("Spol B is zero"); } if (Ap == null || Ap.isZERO()) { throw new ArithmeticException("Spol A is zero"); } if (!Ap.ring.equals(Bp.ring)) { logger.error("rings not equal"); } } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); GenSolvablePolynomial App = Ap.multiply(b, e1); GenSolvablePolynomial Bpp = Bp.multiply(a, f1); if (!App.leadingMonomial().equals(Bpp.leadingMonomial()) ) { System.out.println("lm(A) = " + App.leadingMonomial() + ", lm(B) = " + Bpp.leadingMonomial()); throw new UnsupportedOperationException("right S-polynomial undefined "); } GenSolvablePolynomial Cp = (GenSolvablePolynomial) App.subtract(Bpp); GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial As = (GenSolvablePolynomial) zero.sum(b.negate(), e1); GenSolvablePolynomial Bs = (GenSolvablePolynomial) zero.sum(a, f1); S.set(i, As); S.set(j, Bs); return Cp; } /** * Is top reducible. Is left right symmetric. * @param A solvable polynomial. * @param P solvable polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, GenSolvablePolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); for (GenSolvablePolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { return true; } } return false; } /** * Is reducible. Is left right symmetric. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return true if Ap is reducible with respect to Pp. */ public boolean isReducible(List> Pp, GenSolvablePolynomial Ap) { return !isNormalform(Pp, Ap); } /** * Is in Normalform. Is left right symmetric. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") public boolean isNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; ExpVector f; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; f = p[i].leadingExpVector(); if (f != null) { p[j] = p[i]; htl[j] = f; j++; } } l = j; boolean mt = false; for (ExpVector e : Ap.getMap().keySet()) { for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { return false; } } } return true; } /** * Is right reduction of normal form. * @param row recording matrix. * @param Pp a solvable polynomial list for reduction. * @param Ap a solvable polynomial. * @param Np nf(Pp,Ap), a left normal form of Ap wrt. Pp. * @return true, if Np + sum( Pp[i]*row[i] ) == Ap, else false. */ @SuppressWarnings("unchecked") public boolean isRightReductionNF(List> row, List> Pp, GenSolvablePolynomial Ap, GenSolvablePolynomial Np) { if (row == null && Pp == null) { if (Ap == null) { return Np == null; } return Ap.equals(Np); } if (row == null || Pp == null) { return false; } if (row.size() != Pp.size()) { return false; } GenSolvablePolynomial t = Np; GenSolvablePolynomial r; GenSolvablePolynomial p; for (int m = 0; m < Pp.size(); m++) { r = row.get(m); p = Pp.get(m); if (r != null && p != null) { if (t == null) { t = p.multiply(r); //right } else { t = (GenSolvablePolynomial) t.sum(p.multiply(r)); //right } } //System.out.println("r = " + r ); //System.out.println("p = " + p ); } if (debug) { logger.info("t = {}", t); logger.info("a = {}", Ap); } if (t == null) { if (Ap == null) { return true; } return Ap.isZERO(); } t = (GenSolvablePolynomial) t.subtract(Ap); return t.isZERO(); } /** * Two-sided Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return two-sided-nf(Ap) with respect to Pp. */ public GenSolvablePolynomial normalform(List> Pp, GenSolvablePolynomial Ap) { throw new UnsupportedOperationException("two-sided normalform not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableReductionPar.java000066400000000000000000000172061445075545500252070ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.util.Map; // import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Solvable polynomial Reduction parallel usable algorithm. Implements left * normalform. * @param coefficient type * @author Heinz Kredel */ public class SolvableReductionPar> extends SolvableReductionAbstract { //private static final Logger logger = LogManager.getLogger(SolvableReductionPar.class); /** * Constructor. */ public SolvableReductionPar() { } /** * Left Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return left-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; Map.Entry m; GenSolvablePolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; //P = Pp.toArray(); for (int j = 0; j < Pp.size(); j++) { P[j] = Pp.get(j); } } ExpVector e; ExpVector f = null; C a; boolean mt = false; GenSolvablePolynomial Rz = Ap.ring.getZERO().copy(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial p = null; GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != l) { //long t = System.currentTimeMillis(); synchronized (Pp) { // required, bad in parallel l = Pp.size(); P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray() = {} ms, size() = {}", t, l); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (int i = 0; i < P.length; i++) { p = P[i]; f = p.leadingExpVector(); if (f != null) { mt = e.multipleOf(f); if (mt) break; } } if (!mt) { //logger.debug("irred"); //R = (GenSolvablePolynomial) R.sum(a, e); //S = (GenSolvablePolynomial) S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //logger.debug("red"); e = e.subtract(f); Q = p.multiplyLeft(e); a = a.divide(Q.leadingBaseCoefficient()); //Q = Q.multiplyLeft(a); //S = (GenSolvablePolynomial) S.subtract(Q); S = S.subtractMultiple(a, Q); } } return R; } /** * LeftNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ public GenSolvablePolynomial leftNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { throw new UnsupportedOperationException("normalform with recording not implemented"); } /** * Right Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return right-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; Map.Entry m; GenSolvablePolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; //P = Pp.toArray(); for (int j = 0; j < Pp.size(); j++) { P[j] = Pp.get(j); } } ExpVector e; ExpVector f = null; C a; boolean mt = false; GenSolvablePolynomial Rz = Ap.ring.getZERO().copy(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial p = null; GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != l) { //long t = System.currentTimeMillis(); synchronized (Pp) { // required, bad in parallel l = Pp.size(); P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray() = {} ms, size() = {}", t, l); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (int i = 0; i < P.length; i++) { p = P[i]; f = p.leadingExpVector(); if (f != null) { mt = e.multipleOf(f); if (mt) break; } } if (!mt) { //logger.debug("irred"); //R = (GenSolvablePolynomial) R.sum(a, e); //S = (GenSolvablePolynomial) S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //logger.debug("red"); e = e.subtract(f); Q = p.multiply(e); // p * (a e) TODO a = a.divide(Q.leadingBaseCoefficient()); Q = Q.multiply(a); // p * (e a) !! S = (GenSolvablePolynomial) S.subtract(Q); //S = S.subtractMultiple(Q, a); } } return R; } /** * RightNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ public GenSolvablePolynomial rightNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { throw new UnsupportedOperationException("normalform with recording not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/gb/SolvableReductionSeq.java000066400000000000000000000337411445075545500252170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.Monomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Solvable polynomial Reduction algorithm. Implements left, right normalform. * @param coefficient type * @author Heinz Kredel */ public class SolvableReductionSeq> extends SolvableReductionAbstract { private static final Logger logger = LogManager.getLogger(SolvableReductionSeq.class); /** * Constructor. */ public SolvableReductionSeq() { } /** * Left Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return left-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry m; GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; int i; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new RingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; //, f; C a, b; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); GenSolvablePolynomial Sp; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); logger.debug("red, e = {}", e); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = (GenSolvablePolynomial) R.sum(a, e); //S = (GenSolvablePolynomial) S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //f = e; e = e.subtract(htl[i]); //logger.debug("red div = {}", e); Q = p[i].multiplyLeft(e); b = a; a = a.divide(Q.leadingBaseCoefficient()); //Q = Q.multiplyLeft(a); //S = (GenSolvablePolynomial) S.subtract(Q); ExpVector g1 = S.leadingExpVector(); Sp = S; S = S.subtractMultiple(a, Q); //S = S.subtractMultiple(a, e, p[i]); ExpVector g2 = S.leadingExpVector(); if (g1.equals(g2)) { logger.info("g1.equals(g2): Pp = {}", Pp); logger.info("g1.equals(g2): Ap = {}", Ap); logger.info("g1.equals(g2): p[i] = {}", p[i]); logger.info("g1.equals(g2): Q = {}", Q); logger.info("g1.equals(g2): R = {}", R); logger.info("g1.equals(g2): Sp = {}", Sp); logger.info("g1.equals(g2): S = {}", S); throw new RuntimeException("g1.equals(g2): " + g1 + ", a = " + a + ", b = " + b); } } } return R; } /** * LeftNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial leftNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new RingElem[l]; GenSolvablePolynomial[] p = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; //GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial fac = null; GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = (GenSolvablePolynomial) R.sum(a, e); //S = (GenSolvablePolynomial) S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); //a = a.divide( (C)lbc[i] ); //Q = p[i].multiplyLeft( a, e ); Q = p[i].multiplyLeft(e); a = a.divide(Q.leadingBaseCoefficient()); //Q = Q.multiplyLeft(a); //S = (GenSolvablePolynomial) S.subtract(Q); ExpVector g1 = S.leadingExpVector(); S = S.subtractMultiple(a, Q); ExpVector g2 = S.leadingExpVector(); if (g1.equals(g2)) { throw new RuntimeException("g1.equals(g2): " + g1 + ", a = " + a + ", lc(S) = " + S.leadingBaseCoefficient()); } fac = row.get(i); if (fac == null) { //fac = (GenSolvablePolynomial) zero.sum(a, e); fac = Ap.ring.valueOf(a, e); } else { //fac = (GenSolvablePolynomial) fac.sum(a, e); fac.doAddTo(a, e); } row.set(i, fac); } } return R; } /** * Right Normalform. * @param Ap solvable polynomial. * @param Pp solvable polynomial list. * @return right-nf(Ap) with respect to Pp. */ @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial rightNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; Map.Entry m; GenSolvablePolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; //P = Pp.toArray(); for (int j = 0; j < Pp.size(); j++) { P[j] = Pp.get(j); } } int i; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new RingElem[l]; GenSolvablePolynomial[] p = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); //GenSolvablePolynomial T = null; GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); //logger.info("red = {}", e); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { //logger.debug("red"); ExpVector d = e.subtract(htl[i]); //a = a.divide( (C)lbc[i] ); Q = p[i].multiply(d); // p_i * (b d) TODO C b = a.divide(Q.leadingBaseCoefficient()); Q = Q.multiply(b); // p_i * (b d) !! if (!S.leadingMonomial().equals(Q.leadingMonomial()) ) { logger.info("S = " + S + ", Q = " + Q); logger.error("right reduction with un-equal leading terms: " + S.ring.toScript()); //throw new UnsupportedOperationException("right reduction undefined "); //and treat as irreducible R.doPutToMap(e, a); S.doRemoveFromMap(e, a); } else { S = (GenSolvablePolynomial) S.subtract(Q); } } } return R; } /** * RightNormalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial rightNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l = Pp.size(); GenSolvablePolynomial[] P = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; synchronized (Pp) { //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new RingElem[l]; GenSolvablePolynomial[] p = (GenSolvablePolynomial[]) new GenSolvablePolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial fac = null; // GenSolvablePolynomial T = null; GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = (GenSolvablePolynomial) R.sum(a, e); //S = (GenSolvablePolynomial) S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); //a = a.divide( (C)lbc[i] ); //Q = p[i].multiply( a, e ); Q = p[i].multiply(e); // p_i * (a e) TODO a = a.divide(Q.leadingBaseCoefficient()); Q = Q.multiply(a); // p_i * (e a) ExpVector g1 = S.leadingExpVector(); S = (GenSolvablePolynomial) S.subtract(Q); //S = S.subtractMultiple(Q, a); ExpVector g2 = S.leadingExpVector(); if (g1.equals(g2)) { throw new RuntimeException("g1.equals(g2): " + g1 + ", a = " + a + ", lc(S) = " + S.leadingBaseCoefficient()); } fac = row.get(i); if (fac == null) { //fac = (GenSolvablePolynomial) zero.sum(a, e); fac = Ap.ring.valueOf(a, e); } else { //fac = (GenSolvablePolynomial) fac.sum(a, e); fac.doAddTo(a, e); } row.set(i, fac); } } return R; } } java-algebra-system-2.7.200/src/edu/jas/gb/WordGroebnerBase.java000066400000000000000000000020761445075545500243110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenWordPolynomial; import edu.jas.structure.RingElem; /** * Non-commutative Groebner Bases interface for GenWordPolynomials. Defines * methods for Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel */ public interface WordGroebnerBase> extends Serializable { /** * Groebner base test. * @param F word polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(List> F); /** * Groebner base using pairlist class. * @param F word polynomial list. * @return GB(F) a non-commutative Groebner base of F. */ public List> GB(List> F); /** * Minimal ordered groebner basis. * @param Gp a Word Groebner base. * @return a reduced Word Groebner base of Gp. */ public List> minimalGB(List> Gp); } java-algebra-system-2.7.200/src/edu/jas/gb/WordGroebnerBaseAbstract.java000066400000000000000000000255411445075545500257770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Non-commutative Groebner Bases abstract class. Implements common Groebner * bases and GB test methods. * @param coefficient type * @author Heinz Kredel */ public abstract class WordGroebnerBaseAbstract> implements WordGroebnerBase { private static final Logger logger = LogManager.getLogger(WordGroebnerBaseAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ public final WordReduction red; /** * Strategy for pair selection. */ public final WordPairList strategy; /** * Constructor. */ public WordGroebnerBaseAbstract() { this(new WordReductionSeq()); } /** * Constructor. * @param red Word Reduction engine */ public WordGroebnerBaseAbstract(WordReduction red) { this(red, new OrderedWordPairlist()); } /** * Constructor. * @param red Word Reduction engine * @param pl Word pair selection strategy */ public WordGroebnerBaseAbstract(WordReduction red, WordPairList pl) { this.red = red; this.strategy = pl; } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName(); } /** * Normalize polynomial list. * @param A list of polynomials. * @return list of polynomials with zeros removed and ones/units reduced. */ public List> normalizeZerosOnes(List> A) { if (A == null) { return A; } List> N = new ArrayList>(A.size()); if (A.isEmpty()) { return N; } for (GenWordPolynomial p : A) { if (p == null || p.isZERO()) { continue; } if (p.isUnit()) { N.clear(); N.add(p.ring.getONE()); return N; } N.add(p.abs()); } //N.trimToSize(); return N; } /** * Common zero test, test if univariate leading words exist for all * variables. * @param F polynomial list. * @return -1, 0 or 1 if "dimension"(ideal(F)) &eq; -1, 0 or ≥ 1. */ public int commonZeroTest(List> F) { if (F == null || F.isEmpty()) { return 1; } GenWordPolynomialRing pfac = F.get(0).ring; if (pfac.alphabet.length() <= 0) { return -1; } Set v = new HashSet(); // for non reduced GBs for (GenWordPolynomial p : F) { if (p.isZERO()) { continue; } if (p.isConstant()) { // for non-monic lists return -1; } Word e = p.leadingWord(); if (e == null) { continue; } SortedMap u = e.dependencyOnVariables(); if (u == null) { continue; } if (u.size() == 1) { v.add(u.firstKey()); } } if (pfac.alphabet.length() == v.size()) { return 0; } return 1; } /** * Univariate head term degrees. * @param A list of polynomials. * @return a list of the degrees of univariate head terms. */ public List univariateDegrees(List> A) { List ud = new ArrayList(); if (A == null || A.size() == 0) { return ud; } GenWordPolynomialRing pfac = A.get(0).ring; if (pfac.alphabet.length() <= 0) { return ud; } SortedMap v = new TreeMap(); // for non reduced GBs for (GenWordPolynomial p : A) { Word e = p.leadingWord(); if (e == null) { continue; } SortedMap u = e.dependencyOnVariables(); if (u == null) { continue; } if (u.size() == 1) { Long d = v.get(u.firstKey()); if (d == null) { // record only once v.put(u.firstKey(), Long.valueOf(u.get(u.firstKey()))); } } } ud.addAll(v.values()); //Collections.reverse(ud); return ud; } /** * Word Groebner base test. * @param F Word polynomial list. * @return true, if F is a Groebner base, else false. */ public boolean isGB(List> F) { if (F == null || F.size() <= 1) { return true; } for (int i = 0; i < F.size(); i++) { GenWordPolynomial pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { GenWordPolynomial pj = F.get(j); List> S = red.SPolynomials(pi, pj); for (GenWordPolynomial s : S) { //System.out.println("s-pol("+i+","+j+"): " + s.leadingWord()); GenWordPolynomial h = red.normalform(F, s); if (!h.isZERO()) { logger.info("no GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } S = red.SPolynomials(pj, pi); for (GenWordPolynomial s : S) { //System.out.println("s-pol("+j+","+i+"): " + s.leadingWord()); GenWordPolynomial h = red.normalform(F, s); if (!h.isZERO()) { logger.info("no GB: pj = {}, pi = {}", pj, pi); logger.info("s = {}, h = {}", s, h); return false; } } } } return true; } /** * Groebner base using pairlist class. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public abstract List> GB(List> F); /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ public List> minimalGB(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenWordPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible polynomials GenWordPolynomial a; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } // reduce remaining polynomials Collections.reverse(G); // important for lex GB int len = G.size(); if (debug) { System.out.println("#G " + len); for (GenWordPolynomial aa : G) { System.out.println("aa = " + aa.length() + ", lt = " + aa.getMap().keySet()); } } int i = 0; while (i < len) { a = G.remove(0); if (debug) { System.out.println("doing " + a.length() + ", lt = " + a.leadingWord()); } a = red.normalform(G, a); G.add(a); // adds as last i++; } return G; } /** * Test for minimal ordered Groebner basis. * @param Gp an ideal base. * @return true, if Gp is a reduced minimal Groebner base. */ public boolean isMinimalGB(List> Gp) { if (Gp == null || Gp.size() == 0) { return true; } // test for zero polynomials for (GenWordPolynomial a : Gp) { if (a == null || a.isZERO()) { if (debug) { logger.debug("zero polynomial {}", a); } return false; } } // test for top reducible polynomials List> G = new ArrayList>(Gp); List> F = new ArrayList>(G.size()); while (G.size() > 0) { GenWordPolynomial a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { if (debug) { logger.debug("top reducible polynomial {}", a); } return false; } F.add(a); } G = F; if (G.size() <= 1) { return true; } // test reducibility of polynomials int len = G.size(); int i = 0; while (i < len) { GenWordPolynomial a = G.remove(0); if (!red.isNormalform(G, a)) { if (debug) { logger.debug("reducible polynomial {}", a); } return false; } G.add(a); // re-adds as last i++; } return true; } /** * Cleanup and terminate ThreadPool. */ public void terminate() { logger.info("terminate not implemented"); } /** * Cancel ThreadPool. */ public int cancel() { logger.info("cancel not implemented"); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gb/WordGroebnerBaseSeq.java000066400000000000000000000140651445075545500247630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.LocalTimeStatus; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; /** * Non-commutative word Groebner Base sequential algorithm. Implements * Groebner bases and GB test. Run-time for GB computation is limited * to 20 seconds. To change this limit use *
 *   wbb.timestatus.setLimit(newLimit);
 * 
* or decativate it for infinite running time *
 *   wbb.timestatus.setNotActive();
 * 
* @param coefficient type * @author Heinz Kredel */ public class WordGroebnerBaseSeq> extends WordGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(WordGroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); public final LocalTimeStatus timestatus; /** * Constructor. */ public WordGroebnerBaseSeq() { super(); timestatus = new LocalTimeStatus(true, 20*1000, false); } /** * Constructor. * @param red Reduction engine */ public WordGroebnerBaseSeq(WordReduction red) { super(red); timestatus = new LocalTimeStatus(true, 20*1000, false); } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public WordGroebnerBaseSeq(WordReduction red, WordPairList pl) { super(red, pl); timestatus = new LocalTimeStatus(true, 20*1000, false); } /** * Word Groebner base using word pairlist class. * @param F word polynomial list. * @return GB(F) a finite non-commutative Groebner base of F, if it exists. */ @Override public List> GB(List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. wordMonic(G); if (G.size() <= 1) { return G; } GenWordPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } //Collections.sort(G); OrderedWordPairlist pairlist = (OrderedWordPairlist) strategy.create(ring); pairlist.put(G); logger.info("start {}", pairlist); timestatus.restart(); //if (timestatus.isActive()) { // throw new RuntimeException("timestatus: " + timestatus); //} WordPair pair; GenWordPolynomial pi; GenWordPolynomial pj; List> S; GenWordPolynomial H; int infin = 0; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if (pair == null) { continue; } pi = pair.pi; pj = pair.pj; if (debug) { logger.info("pi = {}, pj = {}", pi, pj); } S = red.SPolynomials(pi, pj); if (S.isEmpty()) { continue; } for (GenWordPolynomial s : S) { if (s.isZERO()) { //pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", s.leadingWord()); } boolean t = pairlist.criterion3(pair.i, pair.j, s.leadingWord()); //System.out.println("criterion3(" + pair.i + "," + pair.j + ") = " + t); //if ( !t ) { // continue; //} H = red.normalform(G, s); if (debug) { //logger.info("pair = {}", pair); //logger.info("ht(S) = {}", S.monic()); //.leadingWord() ); logger.info("ht(H) = {}", H.monic()); //.leadingWord() ); } if (H.isZERO()) { //pair.setZero(); continue; } if (!t) { logger.info("criterion3({},{}) wrong: {} --> {}", pair.i, pair.j, s.leadingWord(), H.leadingWord()); } H = H.monic(); if (debug) { logger.info("ht(H) = {}", H.leadingWord()); } if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } if (H.degree() > 9) { //System.out.println("deg(H): " + H.degree()); //logger.warn("word GB too high degree {}", H.degree()); timestatus.checkTime("word GB degree > 9: " + H.degree()); } if (s.leadingWord().dependencyOnVariables().equals(H.leadingWord().dependencyOnVariables())) { logger.info("LT depend: {} --> {}", s.leadingWord().dependencyOnVariables(), H.leadingWord().dependencyOnVariables()); logger.info("LT depend: {} --> {}", s, H); infin++; if (infin > 500) { //System.out.println("deg(H): " + H.degree()); //throw new RuntimeException("no convergence in word GB: " + infin); timestatus.checkTime("no convergence in word GB: > 500: " + infin); } } } } //logger.info("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("end {}", pairlist); //Collections.sort(G); //Collections.reverse(G); return G; } } java-algebra-system-2.7.200/src/edu/jas/gb/WordPair.java000066400000000000000000000044541445075545500226500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import edu.jas.poly.GenWordPolynomial; import edu.jas.structure.RingElem; /** * Serializable subclass to hold pairs of word polynomials. * @param coefficient type * @author Heinz Kredel */ public class WordPair> implements Comparable { public final GenWordPolynomial pi; public final GenWordPolynomial pj; public final int i; public final int j; protected int n; /** * WordPair constructor. * @param a word polynomial i. * @param b word polynomial j. * @param i first index. * @param j second index. */ public WordPair(GenWordPolynomial a, GenWordPolynomial b, int i, int j) { pi = a; pj = b; this.i = i; this.j = j; this.n = 0; } /** * toString. */ @Override public String toString() { return "wordPair(" + i + "," + j + ",{" + pi.length() + "," + pj.length() + "}," + n + ")"; } /** * Set removed pair number. * @param n number of this pair generated in OrderedPairlist. */ public void pairNumber(int n) { this.n = n; } /** * Get removed pair number. * @return n number of this pair generated in OrderedPairlist. */ public int getPairNumber() { return n; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override public boolean equals(Object ob) { if (!(ob instanceof WordPair)) { return false; // throw new ClassCastException("Pair "+n+" o "+o); } return 0 == compareTo((WordPair) ob); } /** * compareTo used in TreeMap // not used at moment. Comparison is based on * the number of the pairs. * @param p a WordPair. * @return 1 if (this < o), 0 if (this == o), -1 if (this > o). */ public int compareTo(WordPair p) { int x = p.getPairNumber(); if (n > x) { return 1; } if (n < x) { return -1; } return 0; } /** * Hash code for this WordPair. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (i << 16) + j; } } java-algebra-system-2.7.200/src/edu/jas/gb/WordPairList.java000066400000000000000000000037651445075545500235100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.List; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.structure.RingElem; /** * WordPair list management interface. * @author Heinz Kredel */ public interface WordPairList> { /** * Create a new WordPairList. * @param r word polynomial ring. */ public WordPairList create(GenWordPolynomialRing r); /** * toString. */ @Override public String toString(); /** * Put one Word Polynomial to the pairlist and reduction matrix. * @param p word polynomial. * @return the index of the added word polynomial. */ public int put(GenWordPolynomial p); /** * Put all word polynomials in F to the pairlist and reduction matrix. * @param F word polynomial list. * @return the index of the last added word polynomial. */ public int put(List> F); /** * Put to ONE-Polynomial to the pairlist. * @return the index of the last polynomial. */ public int putOne(); /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ public WordPair removeNext(); /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public boolean hasNext(); /** * Get the list of word polynomials. * @return the word polynomial list. */ public List> getList(); /** * Get the number of polynomials put to the pairlist. * @return the number of calls to put. */ public int putCount(); /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public int remCount(); } java-algebra-system-2.7.200/src/edu/jas/gb/WordReduction.java000066400000000000000000000127731445075545500237140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Polynomial WordReduction interface. Defines S-Polynomial, normalform, module * criterion and irreducible set. * @param coefficient type * @author Heinz Kredel */ public interface WordReduction> extends Serializable { /** * S-Polynomials of non-commutative polynomials. * @param Ap word polynomial. * @param Bp word polynomial. * @return list of all spol(Ap,Bp) the S-polynomials of Ap and Bp. */ public List> SPolynomials(GenWordPolynomial Ap, GenWordPolynomial Bp); /** * S-Polynomials of non-commutative polynomials. * @param a leading base coefficient of B. * @param l1 word. * @param A word polynomial. * @param r1 word. * @param b leading base coefficient of A. * @param l2 word. * @param B word polynomial. * @param r2 word. * @return list of all spol(Ap,Bp) the S-polynomials of Ap and Bp. */ public GenWordPolynomial SPolynomial(C a, Word l1, GenWordPolynomial A, Word r1, C b, Word l2, GenWordPolynomial B, Word r2); /** * Is top reducible. Condition is lt(B) | lt(A) for some B in F. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, GenWordPolynomial A); /** * Is reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is reducible with respect to P. */ public boolean isReducible(List> P, GenWordPolynomial A); /** * Is in Normalform. * @param A polynomial. * @param P polynomial list. * @return true if A is in normalform with respect to P. */ public boolean isNormalform(List> P, GenWordPolynomial A); /** * Is in Normalform. * @param Pp polynomial list. * @return true if each A in Pp is in normalform with respect to Pp\{A}. */ public boolean isNormalform(List> Pp); /** * Normalform. * @param A polynomial. * @param P polynomial list. * @return nf(A) with respect to P. */ public GenWordPolynomial normalform(List> P, GenWordPolynomial A); /** * Normalform Set. * @param Ap polynomial list. * @param Pp polynomial list. * @return list of nf(a) with respect to Pp for all a in Ap. */ public List> normalform(List> Pp, List> Ap); /** * Normalform with left and right recording. * @param lrow left recording matrix, is modified. * @param rrow right recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ public GenWordPolynomial normalform(List> lrow, List> rrow, List> Pp, GenWordPolynomial Ap); /** * Normalform with left recording. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ public GenWordPolynomial leftNormalform(List> Pp, GenWordPolynomial Ap); /** * Normalform with left recording. * @param lrow left recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ public GenWordPolynomial leftNormalform(List> lrow, List> Pp, GenWordPolynomial Ap); /** * Irreducible set. * @param Pp polynomial list. * @return a list P of polynomials which are in normalform wrt. P and with * ideal(Pp) = ideal(P). */ public List> irreducibleSet(List> Pp); /** * Is reduction of normal form. * @param lrow left recording matrix. * @param rrow right recording matrix. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @param Np nf(Pp,Ap), a normal form of Ap wrt. Pp. * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false. */ public boolean isReductionNF(List> lrow, List> rrow, List> Pp, GenWordPolynomial Ap, GenWordPolynomial Np); /** * Right normalform with recording. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ public GenWordPolynomial rightNormalform(List> Pp, GenWordPolynomial Ap); /** * Right normalform with recording. * @param rrow right recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ public GenWordPolynomial rightNormalform(List> rrow, List> Pp, GenWordPolynomial Ap); } java-algebra-system-2.7.200/src/edu/jas/gb/WordReductionAbstract.java000066400000000000000000000255101445075545500253710ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.Overlap; import edu.jas.poly.OverlapList; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Polynomial word reduction abstract class. Implements common S-Polynomial, * normalform, module criterion and irreducible set. * @param coefficient type * @author Heinz Kredel */ public abstract class WordReductionAbstract> implements WordReduction { private static final Logger logger = LogManager.getLogger(WordReductionAbstract.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public WordReductionAbstract() { } /** * S-Polynomials of non-commutative polynomials. * @param Ap word polynomial. * @param Bp word polynomial. * @return list of all spol(Ap,Bp) the S-polynomials of Ap and Bp. */ public List> SPolynomials(GenWordPolynomial Ap, GenWordPolynomial Bp) { List> sp = new ArrayList>(); if (Bp == null || Bp.isZERO()) { if (Ap == null) { sp.add(Bp); return sp; } sp.add(Ap.ring.getZERO()); return sp; } if (Ap == null || Ap.isZERO()) { sp.add(Bp.ring.getZERO()); return sp; } Map.Entry ma = Ap.leadingMonomial(); Map.Entry mb = Bp.leadingMonomial(); Word e = ma.getKey(); Word f = mb.getKey(); C a = ma.getValue(); C b = mb.getValue(); OverlapList oll = e.overlap(f); if (oll.ols.isEmpty()) { return sp; } for (Overlap ol : oll.ols) { GenWordPolynomial s = SPolynomial(ol, b, Ap, a, Bp); sp.add(s); } return sp; } /** * S-Polynomials of non-commutative polynomials. * @param a leading base coefficient of B. * @param l1 word. * @param A word polynomial. * @param r1 word. * @param b leading base coefficient of A. * @param l2 word. * @param B word polynomial. * @param r2 word. * @return list of all spol(Ap,Bp) the S-polynomials of Ap and Bp. */ public GenWordPolynomial SPolynomial(C a, Word l1, GenWordPolynomial A, Word r1, C b, Word l2, GenWordPolynomial B, Word r2) { C one = A.ring.coFac.getONE(); GenWordPolynomial s1 = A.multiply(a, l1, one, r1); GenWordPolynomial s2 = B.multiply(b, l2, one, r2); GenWordPolynomial s = s1.subtract(s2); return s; } /** * S-Polynomials of non-commutative polynomials. * @param ol Overlap tuple. * @param a leading base coefficient of B. * @param A word polynomial. * @param b leading base coefficient of A. * @param B word polynomial. * @return list of all spol(Ap,Bp) the S-polynomials of Ap and Bp. */ public GenWordPolynomial SPolynomial(Overlap ol, C a, GenWordPolynomial A, C b, GenWordPolynomial B) { C one = A.ring.coFac.getONE(); GenWordPolynomial s1 = A.multiply(a, ol.l1, one, ol.r1); GenWordPolynomial s2 = B.multiply(b, ol.l2, one, ol.r2); GenWordPolynomial s = s1.subtract(s2); return s; } /** * Normalform Set. * @param Ap polynomial list. * @param Pp polynomial list. * @return list of nf(a) with respect to Pp for all a in Ap. */ public List> normalform(List> Pp, List> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isEmpty()) { return Ap; } ArrayList> red = new ArrayList>(); for (GenWordPolynomial A : Ap) { A = normalform(Pp, A); red.add(A); } return red; } /** * Is top reducible. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, GenWordPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; Word e = A.leadingWord(); for (GenWordPolynomial p : P) { mt = e.multipleOf(p.leadingWord()); if (mt) { return true; } } return false; } /** * Is reducible. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is reducible with respect to Pp. */ public boolean isReducible(List> Pp, GenWordPolynomial Ap) { return !isNormalform(Pp, Ap); } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @SuppressWarnings("unchecked") public boolean isNormalform(List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; GenWordPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenWordPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Word[] htl = new Word[l]; GenWordPolynomial[] p = new GenWordPolynomial[l]; Map.Entry m; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); j++; } } l = j; boolean mt = false; for (Word e : Ap.getMap().keySet()) { for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { return false; } } } return true; } /** * Is in Normalform. * @param Pp polynomial list. * @return true if each Ap in Pp is in normalform with respect to Pp\{Ap}. */ public boolean isNormalform(List> Pp) { if (Pp == null || Pp.isEmpty()) { return true; } GenWordPolynomial Ap; List> P = new LinkedList>(Pp); int s = P.size(); for (int i = 0; i < s; i++) { Ap = P.remove(i); if (!isNormalform(P, Ap)) { return false; } P.add(Ap); } return true; } /** * Irreducible set. * @param Pp polynomial list. * @return a list P of monic polynomials which are in normalform wrt. P and * with ideal(Pp) = ideal(P). */ public List> irreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); for (GenWordPolynomial a : Pp) { if (a.length() != 0) { a = a.monic(); if (a.isONE()) { P.clear(); P.add(a); return P; } P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; Word e; Word f; GenWordPolynomial a; logger.debug("irr = "); while (irr != l) { //it = P.listIterator(); //a = P.get(0); //it.next(); a = P.remove(0); e = a.leadingWord(); a = normalform(P, a); logger.debug(String.valueOf(irr)); if (a.length() == 0) { l--; if (l <= 1) { return P; } } else { f = a.leadingWord(); if (f.signum() == 0) { P = new ArrayList>(); P.add(a.monic()); return P; } if (e.equals(f)) { irr++; } else { irr = 0; a = a.monic(); } P.add(a); } } //System.out.println(); return P; } /** * Is reduction of normal form. * @param lrow left recording matrix. * @param rrow right recording matrix. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @param Np nf(Pp,Ap), a normal form of Ap wrt. Pp. * @return true, if Np + sum( row[i]*Pp[i] ) == Ap, else false. */ public boolean isReductionNF(List> lrow, List> rrow, List> Pp, GenWordPolynomial Ap, GenWordPolynomial Np) { if (lrow == null && rrow == null && Pp == null) { if (Ap == null) { return (Np == null); } return Ap.equals(Np); } if (lrow == null || rrow == null || Pp == null) { return false; } if (lrow.size() != Pp.size() || rrow.size() != Pp.size()) { return false; } GenWordPolynomial t = Np; //System.out.println("t0 = " + t ); GenWordPolynomial r, rl, rr; GenWordPolynomial p; for (int m = 0; m < Pp.size(); m++) { rl = lrow.get(m); rr = rrow.get(m); p = Pp.get(m); if (rl != null && rr != null && p != null) { if (t == null) { t = p.multiply(rl, rr); } else { t = t.sum(p.multiply(rl, rr)); } } //System.out.println("r = " + r ); //System.out.println("p = " + p ); } //System.out.println("t+ = " + t ); if (t == null) { if (Ap == null) { return true; } return Ap.isZERO(); } r = t.subtract(Ap); boolean z = r.isZERO(); if (!z) { logger.info("t = {}", t); logger.info("a = {}", Ap); logger.info("t-a = {}", r); } return z; } } java-algebra-system-2.7.200/src/edu/jas/gb/WordReductionSeq.java000066400000000000000000000421121445075545500243530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Polynomial word reduction sequential use algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class WordReductionSeq> // should be FieldElem> extends WordReductionAbstract { private static final Logger logger = LogManager.getLogger(WordReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public WordReductionSeq() { } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial normalform(List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } Map.Entry m; int l; GenWordPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenWordPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; // want C[] GenWordPolynomial[] p = new GenWordPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e, f, g; C a; boolean mt = false; GenWordPolynomial R = Ap.ring.getZERO(); C cone = Ap.ring.coFac.getONE(); //GenWordPolynomial T = null; GenWordPolynomial Q = null; GenWordPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //T = new OrderedMapPolynomial( a, e ); R = R.sum(a, e); S = S.subtract(a, e); // System.out.println(" S = " + S); } else { Word[] elr = e.divideWord(htl[i]); g = e; e = elr[0]; f = elr[1]; if (debug) { logger.info("red divideWord: e = {}, f = {}", e, f); } a = a.divide(lbc[i]); Q = p[i].multiply(a, e, cone, f); S = S.subtract(Q); if (!S.isZERO() && g.equals(S.leadingWord())) { throw new RuntimeException("HT(S) not descending"); } } } return R; } /** * Normalform with left and right recording. * @param lrow left recording matrix, is modified. * @param rrow right recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial normalform(List> lrow, List> rrow, List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } int l = Pp.size(); GenWordPolynomial[] P = new GenWordPolynomial[l]; synchronized (Pp) { //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; GenWordPolynomial[] p = new GenWordPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e, g; C a, b, lc, rc; boolean mt = false; GenWordPolynomial zero = Ap.ring.getZERO(); GenWordPolynomial one = Ap.ring.getONE(); GenWordPolynomial R = Ap.ring.getZERO(); C cone = Ap.ring.coFac.getONE(); // ensure polynomials at each index for (i = 0; i < lrow.size(); i++) { GenWordPolynomial w = lrow.get(i); if (w == null) { lrow.set(i, zero); } w = rrow.get(i); if (w == null) { rrow.set(i, zero); } } GenWordPolynomial fac = null; // GenWordPolynomial T = null; GenWordPolynomial Q = null; GenWordPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); R = R.sum(a, e); S = S.subtract(a, e); // System.out.println("S = " + S); } else { g = e; Word[] elr = e.divideWord(htl[i]); e = elr[0]; Word f = elr[1]; if (debug) { logger.info("redRec divideWord: e = {}, f = {}, htl = {}", e, f, htl[i]); } C c = lbc[i]; b = a.divide(c); if (e.isONE()) { // todo simplify multiply lc = cone; rc = b; } else { lc = b; rc = cone; } Q = p[i].multiply(lc, e, rc, f); S = S.subtract(Q); //logger.info("redRec: S = {}, R = {}, Q = {}", S, R, Q); if (!S.isZERO() && g.equals(S.leadingWord())) { System.out.println("divideWord: e = " + e + ", f = " + f); System.out.println("R = " + R); System.out.println("Q = " + Q + ", a = " + a + ", b = " + b + ", c = " + c); throw new RuntimeException("HT(S) not descending, S = " + S); } // left row fac = lrow.get(i); boolean doset = true; if (!lc.isONE() || !e.isONE()) { if (!fac.coefficient(e).isZERO()) { logger.warn("e exists in polynomial: {}, e = {}, lc = {}", fac, e, lc); logger.warn("f = {}, rc = {}", f, rc); logger.warn("S = {}, R = {}", S, R); } fac = fac.sum(lc, e); doset = false; } //logger.info("redRec: left = {}, lc = {}, e = {}", fac, lc, e); lrow.set(i, fac); // right row fac = rrow.get(i); if (!rc.isONE() || !f.isONE() || doset) { if (!fac.coefficient(f).isZERO()) { logger.warn("f exists in polynomial: {}, f = {}, rc = {}", fac, f, rc); logger.warn("e = {}, lc = {}", e, lc); logger.warn("S = {}, R = {}", S, R); } fac = fac.sum(rc, f); } //logger.info("redRec: right = {}, rc = {}, f = {}", fac, rc, f); rrow.set(i, fac); } } // set factor to one if other non-zero for (i = 0; i < lrow.size(); i++) { GenWordPolynomial lw = lrow.get(i); GenWordPolynomial rw = rrow.get(i); if (!lw.isZERO() && rw.isZERO()) { rrow.set(i, one); } if (lw.isZERO() && !rw.isZERO()) { lrow.set(i, one); } } return R; } /** * Left normalform with recording. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ public GenWordPolynomial leftNormalform(List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } List> lrow = new ArrayList>(Pp.size()); for (int i = 0; i < Pp.size(); i++) { lrow.add(Ap.ring.getZERO()); } GenWordPolynomial r = leftNormalform(lrow, Pp, Ap); return r; } /** * Left normalform with recording. * @param lrow left recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the left normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial leftNormalform(List> lrow, List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } int l = Pp.size(); GenWordPolynomial[] P = new GenWordPolynomial[l]; synchronized (Pp) { //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; // want C[] GenWordPolynomial[] p = new GenWordPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e; C a; boolean mt = false; GenWordPolynomial zero = Ap.ring.getZERO(); GenWordPolynomial R = Ap.ring.getZERO(); C cone = Ap.ring.coFac.getONE(); GenWordPolynomial fac = null; // GenWordPolynomial T = null; GenWordPolynomial Q = null; GenWordPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.info("irred_1"); R = R.sum(a, e); S = S.subtract(a, e); // System.out.println(" S = " + S); } else { Word g = e; Word[] elr = e.divideWord(htl[i]); e = elr[0]; Word f = elr[1]; if (debug) { logger.info("redRec divideWord: e = {}, f = {}", e, f); } if (f.isONE()) { C c = lbc[i]; //System.out.println("a = " + a + ", c = " + c); a = a.divide(c); //System.out.println("a/c = " + a); Q = p[i].multiply(a, e, cone, f); S = S.subtract(Q); // left row fac = lrow.get(i); if (fac == null) { fac = zero.sum(a, e); } else { fac = fac.sum(a, e); } lrow.set(i, fac); } else { //logger.info("irred_2"); R = R.sum(a, g); S = S.subtract(a, g); } } } return R; } /** * Right normalform with recording. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ public GenWordPolynomial rightNormalform(List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } List> lrow = new ArrayList>(Pp.size()); for (int i = 0; i < Pp.size(); i++) { lrow.add(Ap.ring.getZERO()); } GenWordPolynomial r = rightNormalform(lrow, Pp, Ap); return r; } /** * Right normalform with recording. * @param rrow right recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the right normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial rightNormalform(List> rrow, List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } int l = Pp.size(); GenWordPolynomial[] P = new GenWordPolynomial[l]; synchronized (Pp) { //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; // want C[] GenWordPolynomial[] p = new GenWordPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e; C a; boolean mt = false; GenWordPolynomial zero = Ap.ring.getZERO(); GenWordPolynomial R = Ap.ring.getZERO(); C cone = Ap.ring.coFac.getONE(); GenWordPolynomial fac = null; // GenWordPolynomial T = null; GenWordPolynomial Q = null; GenWordPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.info("irred_1"); R = R.sum(a, e); S = S.subtract(a, e); // System.out.println(" S = " + S); } else { Word g = e; Word[] elr = e.divideWord(htl[i]); e = elr[0]; Word f = elr[1]; if (debug) { logger.info("redRec divideWord: e = {}, f = {}", e, f); } if (e.isONE()) { C c = lbc[i]; //System.out.println("a = " + a + ", c = " + c); a = a.divide(c); //System.out.println("a/c = " + a); Q = p[i].multiply(cone, e, a, f); S = S.subtract(Q); // left row fac = rrow.get(i); if (fac == null) { fac = zero.sum(a, f); } else { fac = fac.sum(a, f); } rrow.set(i, fac); } else { //logger.info("irred_2"); R = R.sum(a, g); S = S.subtract(a, g); } } } return R; } } java-algebra-system-2.7.200/src/edu/jas/gb/package.html000066400000000000000000000025311445075545500225310ustar00rootroot00000000000000 Groebner bases classes

Groebner bases package.

This package contains classes for polynomial and solvable polynomial reduction, Groebner bases and ideal arithmetic as well as thread parallel and distributed versions of Buchbergers algorithm, e.g. ReductionSeq, GroebnerBaseAbstract, GroebnerBaseSeq, GroebnerBaseParallel and GroebnerBaseDistributed. Moreover there are Groebner bases in polynomial rings over principal ideal domains and Euclidean domains, so called D- and E-Groebner bases, see DGroebnerBaseSeq and EGroebnerBaseSeq. The latest additions include free non-commutative polynomial reduction, S-polynomials and two-sided Groebner bases, see WordReductionSeq and WordGroebnerBaseSeq.


Heinz Kredel

Last modified: Fri Sep 21 21:46:36 CEST 2012

$Id$

java-algebra-system-2.7.200/src/edu/jas/gbmod/000077500000000000000000000000001445075545500207475ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/gbmod/ModGroebnerBase.java000066400000000000000000000017051445075545500246130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.poly.ModuleList; import edu.jas.structure.RingElem; /** * Module Groebner Bases interface. Defines Groebner bases and GB test. * @author Heinz Kredel * @deprecated use respective methods from GroebnerBase */ @Deprecated public interface ModGroebnerBase> { /** * Module Groebner base test. */ public boolean isGB(int modv, List> F); /** * isGB. * @param M a module basis. * @return true, if M is a Groebner base, else false. */ public boolean isGB(ModuleList M); /** * Groebner base using pairlist class. */ public List> GB(int modv, List> F); /** * GB. * @param M a module basis. * @return GB(M), a Groebner base of M. */ public ModuleList GB(ModuleList M); } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModGroebnerBaseAbstract.java000066400000000000000000000037051445075545500263010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; /** * Module Groebner Bases abstract class. Implements Groebner bases and GB test. * @author Heinz Kredel * @deprecated use respective methods from GroebnerBaseAbstract */ @Deprecated public abstract class ModGroebnerBaseAbstract> implements ModGroebnerBase { private static final Logger logger = LogManager.getLogger(ModGroebnerBaseAbstract.class); /** * isGB. * @param M a module basis. * @return true, if M is a Groebner base, else false. */ public boolean isGB(ModuleList M) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 return isGB(modv, F.list); } /** * GB. * @param M a module basis. * @return GB(M), a Groebner base of M. */ public ModuleList GB(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(); int modv = M.cols; List> G = GB(modv, F.list); F = new PolynomialList(F.ring, G); N = F.getModuleList(modv); return N; } /** * Cleanup and terminate ThreadPool. */ public void terminate() { logger.info("terminate not implemented"); } /** * Cancel ThreadPool. */ public int cancel() { logger.info("cancel not implemented"); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModGroebnerBasePar.java000066400000000000000000000022071445075545500252540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gbufd.GBFactory; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Module Groebner Bases sequential algorithm. Implements Groebner bases and GB * test. * @author Heinz Kredel * @deprecated use respective methods from GroebnerBaseParallel */ @Deprecated public class ModGroebnerBasePar> extends ModGroebnerBaseSeq { //private static final Logger logger = LogManager.getLogger(ModGroebnerBasePar.class); /** * Constructor. * @param cf coefficient ring. */ public ModGroebnerBasePar(RingFactory cf) { this(GBFactory.getProxy(cf)); } /** * Constructor. * @param bb Groebner base algorithm. */ public ModGroebnerBasePar(GroebnerBaseAbstract bb) { super(bb); } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { bb.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { return bb.cancel(); } } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModGroebnerBaseSeq.java000066400000000000000000000025771445075545500252740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.util.List; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gbufd.GBFactory; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Module Groebner Bases sequential algorithm. Implements Groebner bases and GB * test. * @author Heinz Kredel * @deprecated use respective methods from GroebnerBaseSeq */ @Deprecated public class ModGroebnerBaseSeq> extends ModGroebnerBaseAbstract { //private static final Logger logger = LogManager.getLogger(ModGroebnerBaseSeq.class); /** * Used Groebner base algorithm. */ protected final GroebnerBaseAbstract bb; /** * Constructor. * @param cf coefficient ring. */ public ModGroebnerBaseSeq(RingFactory cf) { this(GBFactory.getImplementation(cf)); } /** * Constructor. * @param bb Groebner base algorithm. */ public ModGroebnerBaseSeq(GroebnerBaseAbstract bb) { this.bb = bb; } /** * Module Groebner base test. */ public boolean isGB(int modv, List> F) { return bb.isGB(modv, F); } /** * Groebner base using pairlist class. */ public List> GB(int modv, List> F) { return bb.GB(modv, F); } } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModSolvableGroebnerBase.java000066400000000000000000000066241445075545500263100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.ModuleList; import edu.jas.structure.RingElem; /** * Module solvable Groebner Bases interface. Defines modull solvabe Groebner * bases and GB test. * @param coefficient type * @author Heinz Kredel * @deprecated use respective methods from SolvableGroebnerBase */ @Deprecated public interface ModSolvableGroebnerBase> extends Serializable { /** * Module left Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGB(int modv, List> F); /** * Module left Groebner base test. * @param M a module basis. * @return true, if M is a left Groebner base, else false. */ public boolean isLeftGB(ModuleList M); /** * Left Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return leftGB(F) a left Groebner base for F. */ public List> leftGB(int modv, List> F); /** * Left Groebner base using pairlist class. * @param M a module basis. * @return leftGB(M) a left Groebner base for M. */ public ModuleList leftGB(ModuleList M); /** * Module twosided Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a twosided Groebner base, else false. */ public boolean isTwosidedGB(int modv, List> F); /** * Module twosided Groebner base test. * @param M a module basis. * @return true, if M is a twosided Groebner base, else false. */ public boolean isTwosidedGB(ModuleList M); /** * Twosided Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return tsGB(F) a twosided Groebner base for F. */ public List> twosidedGB(int modv, List> F); /** * Twosided Groebner base using pairlist class. * @param M a module basis. * @return tsGB(M) a twosided Groebner base for M. */ public ModuleList twosidedGB(ModuleList M); /** * Module right Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(int modv, List> F); /** * Module right Groebner base test. * @param M a module basis. * @return true, if M is a right Groebner base, else false. */ public boolean isRightGB(ModuleList M); /** * Right Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return rightGB(F) a right Groebner base for F. */ public List> rightGB(int modv, List> F); /** * Right Groebner base using pairlist class. * @param M a module basis. * @return rightGB(M) a right Groebner base for M. */ public ModuleList rightGB(ModuleList M); } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModSolvableGroebnerBaseAbstract.java000066400000000000000000000160121445075545500277640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.structure.RingElem; /** * Module solvable Groebner Bases abstract class. Implements module solvable * Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel * @deprecated use respective methods from SolvableGroebnerBaseAbstract */ @Deprecated public abstract class ModSolvableGroebnerBaseAbstract> implements ModSolvableGroebnerBase { private static final Logger logger = LogManager.getLogger(ModSolvableGroebnerBaseAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Module left Groebner base test. * @param M a module basis. * @return true, if M is a left Groebner base, else false. */ public boolean isLeftGB(ModuleList M) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } int modv = M.cols; // > 0 PolynomialList F = M.getPolynomialList(); return isLeftGB(modv, F.castToSolvableList()); } /** * Left Groebner base using pairlist class. * @param M a module basis. * @return leftGB(M) a left Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList leftGB(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(); if (debug) { logger.info("F left +++++++++++++++++++ \n{}", F); } GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) F.ring; int modv = M.cols; List> G = leftGB(modv, F.castToSolvableList()); F = new PolynomialList(sring, G); if (debug) { logger.info("G left +++++++++++++++++++ \n{}", F); } N = F.getModuleList(modv); return N; } /** * Module twosided Groebner base test. * @param M a module basis. * @return true, if M is a twosided Groebner base, else false. */ public boolean isTwosidedGB(ModuleList M) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 return isTwosidedGB(modv, F.castToSolvableList()); } /** * Twosided Groebner base using pairlist class. * @param M a module basis. * @return tsGB(M) a twosided Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList twosidedGB(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } PolynomialList F = M.getPolynomialList(); GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) F.ring; int modv = M.cols; List> G = twosidedGB(modv, F.castToSolvableList()); F = new PolynomialList(sring, G); N = F.getModuleList(modv); return N; } /** * Module right Groebner base test. * @param M a module basis. * @return true, if M is a right Groebner base, else false. */ public boolean isRightGB(ModuleList M) { if (M == null || M.list == null) { return true; } if (M.rows == 0 || M.cols == 0) { return true; } int modv = M.cols; // > 0 PolynomialList F = M.getPolynomialList(); //System.out.println("F test = " + F); return isRightGB(modv, F.castToSolvableList()); } /** * Right Groebner base using pairlist class. * @param M a module basis. * @return rightGB(M) a right Groebner base for M. */ @SuppressWarnings("unchecked") public ModuleList rightGB(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } if (debug) { logger.info("M ====================== \n{}", M); } TermOrder to = M.ring.tord; if (to.getSplit() <= M.ring.nvar) { throw new IllegalArgumentException("extended TermOrders not supported for rightGBs: " + to); } List>> mlist = M.castToSolvableList(); GenSolvablePolynomialRing sring = (GenSolvablePolynomialRing) M.ring; GenSolvablePolynomialRing rring = sring.reverse(true); //true sring = rring.reverse(true); // true List>> nlist = new ArrayList>>(M.rows); for (List> row : mlist) { List> nrow = new ArrayList>(row.size()); for (GenSolvablePolynomial elem : row) { GenSolvablePolynomial nelem = (GenSolvablePolynomial) elem.reverse(rring); nrow.add(nelem); } nlist.add(nrow); } ModuleList rM = new ModuleList(rring, nlist); if (debug) { logger.info("rM -------------------- \n{}", rM); } ModuleList rMg = leftGB(rM); if (debug) { logger.info("rMg -------------------- \n{}", rMg); logger.info("isLeftGB(rMg) ---------- {}", isLeftGB(rMg)); } mlist = rMg.castToSolvableList(); nlist = new ArrayList>>(rMg.rows); for (List> row : mlist) { List> nrow = new ArrayList>(row.size()); for (GenSolvablePolynomial elem : row) { GenSolvablePolynomial nelem = (GenSolvablePolynomial) elem.reverse(sring); nrow.add(nelem); } nlist.add(nrow); } ModuleList Mg = new ModuleList(sring, nlist); if (debug) { logger.info("Mg -------------------- \n{}", Mg); logger.info("isRightGB(Mg) --------- {}", isRightGB(Mg)); } return Mg; } /** * Cleanup and terminate ThreadPool. */ public void terminate() { logger.info("terminate not implemented"); } /** * Cancel ThreadPool. */ public int cancel() { logger.info("cancel not implemented"); return 0; } } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModSolvableGroebnerBasePar.java000066400000000000000000000026571445075545500267550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; // import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gbufd.SGBFactory; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Module solvable Groebner Bases parallel class. Implements module solvable * Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel * @deprecated use respective methods from SolvableGroebnerBaseParallel */ @Deprecated public class ModSolvableGroebnerBasePar> extends ModSolvableGroebnerBaseSeq { //private static final Logger logger = LogManager.getLogger(ModSolvableGroebnerBasePar.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient ring. */ public ModSolvableGroebnerBasePar(RingFactory cf) { this(SGBFactory.getProxy(cf)); } /** * Constructor. * @param sbb parallel solvable Groebner base algorithm. */ public ModSolvableGroebnerBasePar(SolvableGroebnerBaseAbstract sbb) { super(sbb); } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { sbb.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { return sbb.cancel(); } } java-algebra-system-2.7.200/src/edu/jas/gbmod/ModSolvableGroebnerBaseSeq.java000066400000000000000000000067361445075545500267650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbmod; import java.util.List; // import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gbufd.SGBFactory; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Module solvable Groebner Bases sequential class. Implements module solvable * Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel * @deprecated use respective methods from SolvableGroebnerBaseSeq */ @Deprecated public class ModSolvableGroebnerBaseSeq> extends ModSolvableGroebnerBaseAbstract { //private static final Logger logger = LogManager.getLogger(ModSolvableGroebnerBaseSeq.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Used Solvable Groebner base algorithm. */ protected final SolvableGroebnerBaseAbstract sbb; /** * Constructor. * @param cf coefficient ring. */ public ModSolvableGroebnerBaseSeq(RingFactory cf) { this(SGBFactory.getImplementation(cf)); } /** * Constructor. * @param sbb solvable Groebner base implementation. */ public ModSolvableGroebnerBaseSeq(SolvableGroebnerBaseAbstract sbb) { this.sbb = sbb; } /** * Module left Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a left Groebner base, else false. */ public boolean isLeftGB(int modv, List> F) { return sbb.isLeftGB(modv, F); } /** * Left Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return leftGB(F) a left Groebner base for F. */ public List> leftGB(int modv, List> F) { return sbb.leftGB(modv, F); } /** * Module twosided Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a twosided Groebner base, else false. */ public boolean isTwosidedGB(int modv, List> F) { return sbb.isTwosidedGB(modv, F); } /** * Twosided Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return tsGB(F) a twosided Groebner base for F. */ public List> twosidedGB(int modv, List> F) { return sbb.twosidedGB(modv, F); } /** * Module right Groebner base test. * @param modv number of modul variables. * @param F a module basis. * @return true, if F is a right Groebner base, else false. */ public boolean isRightGB(int modv, List> F) { return sbb.isRightGB(modv, F); } /** * Right Groebner base using pairlist class. * @param modv number of modul variables. * @param F a module basis. * @return rightGB(F) a right Groebner base for F. */ public List> rightGB(int modv, List> F) { if (modv == 0) { return sbb.rightGB(modv, F); } throw new UnsupportedOperationException("modv != 0 not jet implemented"); // return sbb.rightGB(modv,F); } } java-algebra-system-2.7.200/src/edu/jas/gbmod/package.html000066400000000000000000000020521445075545500232270ustar00rootroot00000000000000 Module Groebner base classes

Module Groebner base package.

This package is deprecated. It contained classes for module Groebner bases and syzygies over polynomials and solvable polynomials, e.g. ModGroebnerBase or SolvableSyzygy. The methods of Mod*GroebnerBase have been refactored to *GroebnerBase methods in package edu.jas.gb. The classes Syzygy* and SolvableSyzygy* have been moved to package edu.jas.gbufd.


Heinz Kredel

Last modified: Mon Jul 27 21:52:26 CEST 2015

$Id$

java-algebra-system-2.7.200/src/edu/jas/gbufd/000077500000000000000000000000001445075545500207465ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/gbufd/CharacteristicSet.java000066400000000000000000000027541445075545500252250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Characteristic Set interface. Defines methods for Characteristic Sets and * tests. * @param coefficient type * @author Heinz Kredel */ public interface CharacteristicSet> extends Serializable { /** * Characteristic set. According to the implementing algorithm (simple, Wu, etc). * @param A list of generic polynomials. * @return charSet(A) with at most one polynomial per main variable. */ public List> characteristicSet(List> A); /** * Characteristic set test. * @param A list of generic polynomials. * @return true, if A is (at least a simple) characteristic set, else false. */ public boolean isCharacteristicSet(List> A); /** * Characteristic set reduction. Pseudo remainder wrt. the main variable. * With further pseudo reduction of the leading coefficient depending on the implementing algorithm. * @param P generic polynomial. * @param A list of generic polynomials as characteristic set. * @return characteristicSetRemainder(A,P) or * characteristicSetReductionCoeff(A,characteristicSetRemainder(A,P)) depending on the algorithm. */ public GenPolynomial characteristicSetReduction(List> A, GenPolynomial P); } java-algebra-system-2.7.200/src/edu/jas/gbufd/CharacteristicSetSimple.java000066400000000000000000000150311445075545500263670ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Characteristic Set class according to the simple algorithm, where the * leading coefficients are not rereduced. Implements methods * for Characteristic Sets and tests. * @param coefficient type * @author Heinz Kredel */ public class CharacteristicSetSimple> implements CharacteristicSet { private static final Logger logger = LogManager.getLogger(CharacteristicSetSimple.class); private static final boolean debug = logger.isDebugEnabled(); /** * Characteristic set. According to the simple algorithm. The leading * coefficients are not rereduced. * @param A list of generic polynomials. * @return charSetWu(A). */ public List> characteristicSet(List> A) { List> S = new ArrayList>(); if (A == null || A.isEmpty()) { return S; } GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 1) { // take gcd GreatestCommonDivisorAbstract ufd = GCDFactory. getImplementation(pfac.coFac); GenPolynomial g = ufd.gcd(A).monic(); logger.info("charSet base gcd = {}", g); S.add(g); return S; } // sort polynomials according to the main variable GenPolynomialRing> rfac = pfac.recursive(1); List>> positiveDeg = new ArrayList>>(); List> zeroDeg = new ArrayList>(); for (GenPolynomial f : A) { if (f.isZERO()) { continue; } f = f.monic(); if (f.isONE()) { S.add(f); return S; } GenPolynomial> fr = PolyUtil. recursive(rfac, f); if (fr.degree(0) == 0) { zeroDeg.add(fr.leadingBaseCoefficient()); } else { positiveDeg.add(fr); } } if (positiveDeg.isEmpty() && zeroDeg.isEmpty()) { return S; } // do pseudo division wrt. the main variable OrderedPolynomialList> opl = new OrderedPolynomialList>(rfac, positiveDeg); List>> pd = new ArrayList>>(opl.list); Collections.reverse(pd); // change OrderedPolynomialList to avoid if (debug) { logger.info("positive degrees: {}", pd); } //System.out.println("positive degrees: " + pd); //System.out.println("zero degrees: " + zeroDeg); while (pd.size() > 1) { GenPolynomial> fr = pd.remove(0); GenPolynomial> qr = pd.get(0); // = get(1) logger.info("pseudo remainder by deg = {} in variable {}", qr.degree(), rfac.getVars()[0]); GenPolynomial> rr = PolyUtil. recursiveSparsePseudoRemainder(fr, qr); if (rr.isZERO()) { logger.warn("variety is reducible"); // replace qr by gcd(qr,fr) ? continue; } if (rr.degree(0) == 0) { zeroDeg.add(rr.leadingBaseCoefficient().monic()); } else { pd.add(rr); pd = OrderedPolynomialList.sort(rfac, pd); Collections.reverse(pd); // avoid } } // recursion for degree zero polynomials List> Sp = characteristicSet(zeroDeg); // recursion for (GenPolynomial f : Sp) { GenPolynomial fp = f.extend(pfac, 0, 0L); S.add(fp); } //logger.info("charSet recursion, Sp = {}", Sp); if (pd.isEmpty()) { return S; } GenPolynomial> rr = pd.get(0); GenPolynomial sr = PolyUtil. distribute(pfac, rr); sr = sr.monic(); // no rereduction of leading coefficient wrt. characteristic set. S.add(0, sr); return S; } /** * Characteristic set test. * @param A list of generic polynomials. * @return true, if A is (at least a simple) characteristic set, else false. */ public boolean isCharacteristicSet(List> A) { if (A == null || A.isEmpty()) { return true; // ? } GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 1) { return A.size() <= 1; } if (pfac.nvar < A.size()) { return false; } // select polynomials according to the main variable GenPolynomialRing> rfac = pfac.recursive(1); List> zeroDeg = new ArrayList>(); int positiveDeg = 0; for (GenPolynomial f : A) { if (f.isZERO()) { return false; } //f = f.monic(); GenPolynomial> fr = PolyUtil. recursive(rfac, f); if (fr.degree(0) == 0) { zeroDeg.add(fr.leadingBaseCoefficient()); } else { positiveDeg++; if (positiveDeg > 1) { return false; } } } return isCharacteristicSet(zeroDeg); } /** * Characteristic set reduction. Pseudo remainder wrt. the main variable. * @param P generic polynomial. * @param A list of generic polynomials as characteristic set. * @return characteristicSetRemainder(A,P) */ public GenPolynomial characteristicSetReduction(List> A, GenPolynomial P) { if (A == null || A.isEmpty()) { return P.monic(); } if (P.isZERO()) { return P; } GenPolynomial R = PolyGBUtil. topPseudoRemainder(A, P); R = R.monic(); //System.out.println("remainder, R = " + R); return R; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/CharacteristicSetWu.java000066400000000000000000000172061445075545500255370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Characteristic Set class according to Wu. Implements methods for * Characteristic Sets and tests. * @param coefficient type * @author Heinz Kredel */ public class CharacteristicSetWu> implements CharacteristicSet { private static final Logger logger = LogManager.getLogger(CharacteristicSetWu.class); private static final boolean debug = logger.isDebugEnabled(); /** * Characteristic set. According to Wu's algorithm with rereduction of * leading coefficients. * @param A list of generic polynomials. * @return charSetWu(A). */ public List> characteristicSet(List> A) { List> S = new ArrayList>(); if (A == null || A.isEmpty()) { return S; } GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 1) { // take gcd GreatestCommonDivisorAbstract ufd = GCDFactory. getImplementation(pfac.coFac); GenPolynomial g = ufd.gcd(A).monic(); logger.info("charSet base gcd = {}", g); S.add(g); return S; } // sort polynomials according to the main variable GenPolynomialRing> rfac = pfac.recursive(1); List>> positiveDeg = new ArrayList>>(); List> zeroDeg = new ArrayList>(); for (GenPolynomial f : A) { if (f.isZERO()) { continue; } f = f.monic(); if (f.isONE()) { S.add(f); return S; } GenPolynomial> fr = PolyUtil. recursive(rfac, f); if (fr.degree(0) == 0) { zeroDeg.add(fr.leadingBaseCoefficient()); } else { positiveDeg.add(fr); } } if (positiveDeg.isEmpty() && zeroDeg.isEmpty()) { return S; } // do pseudo division wrt. the main variable OrderedPolynomialList> opl = new OrderedPolynomialList>(rfac, positiveDeg); List>> pd = new ArrayList>>(opl.list); Collections.reverse(pd); // change OrderedPolynomialList to avoid if (debug) { logger.info("positive degrees: {}", pd); } //System.out.println("positive degrees: " + pd); //System.out.println("zero degrees: " + zeroDeg); while (pd.size() > 1) { GenPolynomial> fr = pd.remove(0); GenPolynomial> qr = pd.get(0); // = get(1) logger.info("pseudo remainder by deg = {} in variable {}", qr.degree(), rfac.getVars()[0]); GenPolynomial> rr = PolyUtil. recursiveSparsePseudoRemainder(fr, qr); if (rr.isZERO()) { logger.warn("variety is reducible {} reduces to zero mod {}", fr, pd); // replace qr by gcd(qr,fr) ? continue; } if (rr.degree(0) == 0) { zeroDeg.add(rr.leadingBaseCoefficient().monic()); } else { pd.add(rr); pd = OrderedPolynomialList.sort(rfac, pd); Collections.reverse(pd); // avoid } } // recursion for degree zero polynomials List> Sp = characteristicSet(zeroDeg); // recursion for (GenPolynomial f : Sp) { GenPolynomial fp = f.extend(pfac, 0, 0L); S.add(fp); } //logger.info("charSet recursion, Sp = {}", Sp); if (pd.isEmpty()) { return S; } // rereduction of leading coefficient wrt. characteristic set according to Wu GenPolynomial> rr = pd.get(0); GenPolynomial sr = PolyUtil. distribute(pfac, rr); sr = PolyGBUtil. topCoefficientPseudoRemainder(Sp, sr); logger.info("charSet rereduced sr = {}", sr); if (sr.isZERO()) { return S; } long d = sr.degree(pfac.nvar - 1); //System.out.println("deg(sr): " + d + ", degv(sr): " + sr.leadingExpVector()); if (d == 0) { // deg zero, invalid characteristic set, restart S.add(0, sr); logger.warn("reducible characteristic set, restarting with S = {}", S); return characteristicSet(S); } sr = sr.monic(); S.add(0, sr); return S; } /** * Characteristic set test. * @param A list of generic polynomials. * @return true, if A is (at least a simple) characteristic set, else false. */ public boolean isCharacteristicSet(List> A) { if (A == null || A.isEmpty()) { return true; // ? } GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 1) { //System.out.println("CS: pfac = " + pfac + ", A = " + A + ", A.size() = " + A.size()); return A.size() <= 1; } if (pfac.nvar < A.size()) { logger.info("not CS: pfac = {}, A = {}", pfac, A); return false; } // select polynomials according to the main variable GenPolynomialRing> rfac = pfac.recursive(1); List> zeroDeg = new ArrayList>(); int positiveDeg = 0; for (GenPolynomial f : A) { if (f.isZERO()) { logger.info("not CS: f = {}", f); return false; } //f = f.monic(); GenPolynomial> fr = PolyUtil. recursive(rfac, f); if (fr.degree(0) == 0) { zeroDeg.add(fr.leadingBaseCoefficient()); } else { positiveDeg++; if (positiveDeg > 1) { logger.info("not CS: f = {}, positiveDeg = {}", f, positiveDeg); return false; } } } return isCharacteristicSet(zeroDeg); } /** * Characteristic set reduction. Pseudo remainder wrt. the main variable * with further pseudo reduction of the leading coefficient. * @param P generic polynomial. * @param A list of generic polynomials as characteristic set. * @return * characteristicSetReductionCoeff(A,characteristicSetRemainder(A,P)) */ public GenPolynomial characteristicSetReduction(List> A, GenPolynomial P) { if (A == null || A.isEmpty()) { return P.monic(); } if (P.isZERO()) { return P; } GenPolynomial R = PolyGBUtil. topPseudoRemainder(A, P); //System.out.println("remainder, R = " + R); if (R.isZERO()) { return R; } List> Ap = PolyGBUtil. zeroDegrees(A); //System.out.println("Ap = " + Ap); R = PolyGBUtil. topCoefficientPseudoRemainder(Ap, R); //System.out.println("R = " + R); return R; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/Examples.java000066400000000000000000000144751445075545500234020ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.gb.GroebnerBase; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; /** * Examples for Groebner base usage. * @author Christoph Zengler * @author Heinz Kredel */ public class Examples { /** * main. */ public static void main(String[] args) { //example1(); //example2(); //example3(); exampleGB(); //exampleGB1(); //exampleGBTrinks(); } /** * example1. Coefficients in Boolean residue class ring. * */ public static void example1() { // moved to edu.jas.application.Examples } /* * example2. Coefficients in Boolean residue class ring with cuppling of * variables. * */ public static void example2() { // moved to edu.jas.application.Examples } /** * example3. Coefficients in Boolean ring and additional idempotent * generators. * */ public static void example3() { String[] vars = { "v3", "v2", "v1" }; ModIntegerRing z2 = new ModIntegerRing(2); GenPolynomialRing z2p = new GenPolynomialRing(z2, vars.length, new TermOrder( TermOrder.INVLEX), vars); List> fieldPolynomials = new ArrayList>(); //add v1^2 + v1, v2^2 + v2, v3^2 + v3 to fieldPolynomials for (int i = 0; i < vars.length; i++) { GenPolynomial var = z2p.univariate(i); fieldPolynomials.add(var.multiply(var).sum(var)); } List> polynomials = new ArrayList>(); GenPolynomial v1 = z2p.univariate(0); GenPolynomial v2 = z2p.univariate(1); GenPolynomial v3 = z2p.univariate(2); GenPolynomial notV1 = v1.sum(z2p.ONE); GenPolynomial notV2 = v2.sum(z2p.ONE); GenPolynomial notV3 = v3.sum(z2p.ONE); //v1*v2 GenPolynomial p1 = v1.multiply(v2); //v1*v2 + v1 + v2 + 1 GenPolynomial p2 = notV1.multiply(notV2); //v1*v3 + v1 + v3 + 1 GenPolynomial p3 = notV1.multiply(notV3); polynomials.add(p1); polynomials.add(p2); polynomials.add(p3); polynomials.addAll(fieldPolynomials); //GroebnerBase gb = new GroebnerBaseSeq(); GroebnerBase gb = GBFactory.getImplementation(z2); List> G = gb.GB(polynomials); System.out.println(G); } /** * Example GBase. * */ @SuppressWarnings("unchecked") static public void exampleGB1() { BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String exam = "(x1,x2,y) G " + "( " + "( x1 + x2 - 10 ), ( 2 x1 - x2 + 4 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } System.out.println("F = " + F); List> G = gb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + trinks); } /** * Example GBase. * */ @SuppressWarnings("unchecked") static public void exampleGB() { BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String exam = "(x,y) G " + "( " + "( y - ( x^2 - 1 ) ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } System.out.println("F = " + F); List> G = gb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + trinks); } /** * Example Trinks GBase. * */ @SuppressWarnings("unchecked") static public void exampleGBTrinks() { BigRational coeff = new BigRational(); GroebnerBase bb = GBFactory.getImplementation(coeff); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { e.printStackTrace(); return; } catch (IOException e) { e.printStackTrace(); return; } System.out.println("F = " + F); List> G = bb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GBFactory.java000066400000000000000000000521201445075545500234310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.gb.DGroebnerBaseSeq; import edu.jas.gb.EGroebnerBaseSeq; import edu.jas.gb.GBProxy; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.OrderedMinPairlist; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.PairList; import edu.jas.gb.ReductionSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Groebner bases algorithms factory. Select appropriate Groebner bases engine * based on the coefficient types. *

* Usage: To create objects that implement the GroebnerBase * interface use the GBFactory. It will select an appropriate * implementation based on the types of polynomial coefficients C. The method to * obtain an implementation is getImplementation(). * getImplementation() returns an object of a class which * implements the GroebnerBase interface, more precisely an object * of abstract class GroebnerBaseAbstract. * *

 * GroebnerBase<CT> engine;
 * engine = GBFactory.<CT> getImplementation(cofac);
 * c = engine.GB(A);
 * 
*

* For example, if the coefficient type is BigInteger, the usage looks like * *

 * BigInteger cofac = new BigInteger();
 * GroebnerBase<BigInteger> engine;
 * engine = GBFactory.getImplementation(cofac);
 * c = engine.GB(A);
 * 
* * @author Heinz Kredel * * @see edu.jas.gb.GroebnerBase * @see edu.jas.application.GBAlgorithmBuilder */ public class GBFactory { private static final Logger logger = LogManager.getLogger(GBFactory.class); /** * Algorithm indicators: igb = integerGB, egb = e-GB, dgb = d-GB, qgb = * fraction coefficients GB, ffgb = fraction free GB. */ public static enum Algo { igb, egb, dgb, qgb, ffgb }; /** * Protected factory constructor. */ protected GBFactory() { } /** * Determine suitable implementation of GB algorithms, no factory case. * @return GB algorithm implementation for field coefficients. */ public static > GroebnerBaseAbstract getImplementation() { logger.warn("no coefficient factory given, assuming field coefficients"); GroebnerBaseAbstract bba = new GroebnerBaseSeq(); return bba; } /** * Determine suitable implementation of GB algorithms, case ModLong. * @param fac ModLongRing. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModLongRing fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case ModLong. * @param fac ModLongRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModLongRing fac, PairList pl) { GroebnerBaseAbstract bba; if (fac.isField()) { bba = new GroebnerBaseSeq(pl); } else { bba = new GroebnerBasePseudoSeq(fac, pl); } return bba; } /** * Determine suitable implementation of GB algorithms, case ModInt. * @param fac ModIntRing. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModIntRing fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case ModInt. * @param fac ModIntRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModIntRing fac, PairList pl) { GroebnerBaseAbstract bba; if (fac.isField()) { bba = new GroebnerBaseSeq(pl); } else { bba = new GroebnerBasePseudoSeq(fac, pl); } return bba; } /** * Determine suitable implementation of GB algorithms, case ModInteger. * @param fac ModIntegerRing. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModIntegerRing fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case ModInteger. * @param fac ModIntegerRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(ModIntegerRing fac, PairList pl) { GroebnerBaseAbstract bba; if (fac.isField()) { bba = new GroebnerBaseSeq(pl); } else { bba = new GroebnerBasePseudoSeq(fac, pl); } return bba; } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigInteger fac) { return getImplementation(fac, Algo.igb); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param a algorithm, a = igb, egb, dgb. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigInteger fac, Algo a) { return getImplementation(fac, a, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigInteger fac, PairList pl) { return getImplementation(fac, Algo.igb, pl); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param a algorithm, a = igb, egb, dgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigInteger fac, Algo a, PairList pl) { GroebnerBaseAbstract bba; switch (a) { case igb: bba = new GroebnerBasePseudoSeq(fac, pl); break; case egb: bba = new EGroebnerBaseSeq(); // pl not suitable break; case dgb: bba = new DGroebnerBaseSeq(); // pl not suitable break; default: throw new IllegalArgumentException("algorithm not available for BigInteger " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigRational fac) { return getImplementation(fac, Algo.qgb); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param a algorithm, a = qgb, ffgb. * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigRational fac, Algo a) { return getImplementation(fac, a, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigRational fac, PairList pl) { return getImplementation(fac, Algo.qgb, pl); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param a algorithm, a = qgb, ffgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static GroebnerBaseAbstract getImplementation(BigRational fac, Algo a, PairList pl) { GroebnerBaseAbstract bba; switch (a) { case qgb: bba = new GroebnerBaseSeq(pl); break; case ffgb: PairList pli; if (pl instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist(); } else if (pl instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist(); } else { pli = new OrderedPairlist(); } bba = new GroebnerBaseRational(pli); // pl not possible break; default: throw new IllegalArgumentException( "algorithm not available for " + fac.toScriptFactory() + ", Algo = " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( QuotientRing fac) { return getImplementation(fac, Algo.qgb); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param a algorithm, a = qgb, ffgb. * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( QuotientRing fac, Algo a) { return getImplementation(fac, a, new OrderedPairlist>()); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( QuotientRing fac, PairList> pl) { return getImplementation(fac, Algo.qgb, pl); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param a algorithm, a = qgb, ffgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( QuotientRing fac, Algo a, PairList> pl) { GroebnerBaseAbstract> bba; switch (a) { case qgb: bba = new GroebnerBaseSeq>(new ReductionSeq>(), pl); break; case ffgb: PairList> pli; if (pl instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist>(); } else if (pl instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist>(); } else { pli = new OrderedPairlist>(); } bba = new GroebnerBaseQuotient(fac, pli); // pl not possible break; default: throw new IllegalArgumentException("algorithm not available for Quotient " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( GenPolynomialRing fac) { return getImplementation(fac, Algo.igb); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param a algorithm, a = igb or egb, dgb if fac is univariate over a * field. * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, Algo a) { return getImplementation(fac, a, new OrderedPairlist>()); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, PairList> pl) { return getImplementation(fac, Algo.igb, pl); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param a algorithm, a = igb or egb, dgb if fac is univariate over a * field. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, Algo a, PairList> pl) { GroebnerBaseAbstract> bba; switch (a) { case igb: bba = new GroebnerBasePseudoRecSeq(fac, pl); break; case egb: if (fac.nvar > 1 || !fac.coFac.isField()) { throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac); } bba = new EGroebnerBaseSeq>(); // pl not suitable break; case dgb: if (fac.nvar > 1 || !fac.coFac.isField()) { throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac); } bba = new DGroebnerBaseSeq>(); // pl not suitable break; default: throw new IllegalArgumentException("algorithm not available for GenPolynomial " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case regular rings. * @param fac RegularRing. * @return GB algorithm implementation. */ public static > GroebnerBaseAbstract> getImplementation( ProductRing fac) { GroebnerBaseAbstract> bba; if (fac.onlyFields()) { bba = new RGroebnerBaseSeq>(); } else { bba = new RGroebnerBasePseudoSeq>(fac); } return bba; } /** * Determine suitable implementation of GB algorithms, other cases. * @param fac RingFactory<C>. * @return GB algorithm implementation. */ public static > // interface RingElem not sufficient GroebnerBaseAbstract getImplementation(RingFactory fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, other cases. * @param fac RingFactory<C>. * @param pl pair selection strategy * @return GB algorithm implementation. */ @SuppressWarnings("unchecked") public static > // interface RingElem not sufficient GroebnerBaseAbstract getImplementation(RingFactory fac, PairList pl) { logger.debug("fac = {}", fac.getClass().getName()); if (fac.isField()) { return new GroebnerBaseSeq(pl); } GroebnerBaseAbstract bba = null; Object ofac = fac; if (ofac instanceof GenPolynomialRing) { PairList> pli; if (pl instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist>(); } else if (pl instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist>(); } else { pli = new OrderedPairlist>(); } GenPolynomialRing rofac = (GenPolynomialRing) ofac; GroebnerBaseAbstract> bbr = new GroebnerBasePseudoRecSeq(rofac, pli); // not pl bba = (GroebnerBaseAbstract) bbr; } else if (ofac instanceof ProductRing) { ProductRing pfac = (ProductRing) ofac; if (pfac.onlyFields()) { bba = new RGroebnerBaseSeq>(); } else { bba = new RGroebnerBasePseudoSeq>(pfac); } } else { bba = new GroebnerBasePseudoSeq(fac, pl); } logger.debug("bba = {}", bba.getClass().getName()); return bba; } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @return GB proxy algorithm implementation. */ public static > // interface RingElem not sufficient GroebnerBaseAbstract getProxy(RingFactory fac) { return getProxy(fac, new OrderedPairlist()); } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @param pl pair selection strategy * @return GB proxy algorithm implementation. */ @SuppressWarnings("unchecked") public static > // interface RingElem not sufficient GroebnerBaseAbstract getProxy(RingFactory fac, PairList pl) { if (ComputerThreads.NO_THREADS) { return GBFactory. getImplementation(fac, pl); } logger.debug("fac = {}", fac.getClass().getName()); int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2); if (fac.isField()) { GroebnerBaseAbstract e1 = new GroebnerBaseSeq(pl); GroebnerBaseAbstract e2 = new GroebnerBaseParallel(th, pl); return new GBProxy(e1, e2); } else if (fac.characteristic().signum() == 0) { if (fac instanceof GenPolynomialRing) { GenPolynomialRing pfac = (GenPolynomialRing) fac; OrderedPairlist ppl = new OrderedPairlist>(); GroebnerBaseAbstract e1 = new GroebnerBasePseudoRecSeq(pfac, ppl); GroebnerBaseAbstract e2 = new GroebnerBasePseudoRecParallel(th, pfac, ppl); return new GBProxy(e1, e2); } GroebnerBaseAbstract e1 = new GroebnerBasePseudoSeq(fac, pl); GroebnerBaseAbstract e2 = new GroebnerBasePseudoParallel(th, fac, pl); return new GBProxy(e1, e2); } return getImplementation(fac, pl); } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @return GB proxy algorithm implementation. */ @SuppressWarnings("unchecked") public static > // interface RingElem not sufficient GroebnerBaseAbstract> getProxy(GenPolynomialRing fac) { if (ComputerThreads.NO_THREADS) { //return GBFactory.> getImplementation(fac); return GBFactory.getImplementation(fac); } logger.debug("fac = {}", fac.getClass().getName()); int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2); OrderedPairlist> ppl = new OrderedPairlist>(); GroebnerBaseAbstract> e1 = new GroebnerBasePseudoRecSeq(fac, ppl); GroebnerBaseAbstract> e2 = new GroebnerBasePseudoRecParallel(th, fac, ppl); //return new GBProxy>(e1, e2); return new GBProxy(e1, e2); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBaseFGLM.java000066400000000000000000000374761445075545500246360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.PairList; import edu.jas.gb.Reduction; import edu.jas.gb.ReductionSeq; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Groebner Base sequential FGLM algorithm. Implements Groebner base computation * via FGLM algorithm. * @param coefficient type * @author Jan Suess * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseFGLM> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseFGLM.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The backing GB algorithm implementation. */ private GroebnerBaseAbstract sgb; /** * Constructor. */ public GroebnerBaseFGLM() { super(); sgb = null; } /** * Constructor. * @param red Reduction engine */ public GroebnerBaseFGLM(Reduction red) { super(red); sgb = null; } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy */ public GroebnerBaseFGLM(Reduction red, PairList pl) { super(red, pl); sgb = null; } /** * Constructor. * @param red Reduction engine * @param pl pair selection strategy * @param gb backing GB algorithm. */ public GroebnerBaseFGLM(Reduction red, PairList pl, GroebnerBaseAbstract gb) { super(red, pl); sgb = gb; } /** * Constructor. * @param gb backing GB algorithm. */ public GroebnerBaseFGLM(GroebnerBaseAbstract gb) { super(); sgb = gb; } /** * Get the String representation with GB engine. * @see java.lang.Object#toString() */ @Override public String toString() { if (sgb == null) { return "GroebnerBaseFGLM()"; } return "GroebnerBaseFGLM( " + sgb.toString() + " )"; } /** * Groebner base using FGLM algorithm. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a inv lex term order Groebner base of F. */ public List> GB(int modv, List> F) { if (modv != 0) { throw new UnsupportedOperationException("case modv != 0 not yet implemented"); } if (F == null || F.size() == 0) { return F; } List> G = new ArrayList>(); if (F.size() <= 1) { GenPolynomial p = F.get(0).monic(); G.add(p); return G; } // convert to graded term order List> Fp = new ArrayList>(F.size()); GenPolynomialRing pfac = F.get(0).ring; if (!pfac.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field: " + pfac.coFac); } TermOrder tord = new TermOrder(TermOrder.IGRLEX); GenPolynomialRing gfac = new GenPolynomialRing(pfac.coFac, pfac.nvar, tord, pfac.getVars()); for (GenPolynomial p : F) { GenPolynomial g = gfac.copy(p); // change term order Fp.add(g); } // compute graded term order Groebner base if (sgb == null) { sgb = GBFactory. getImplementation(pfac.coFac, strategy); } List> Gp = sgb.GB(modv, Fp); logger.info("graded GB = {}", Gp); if (tord.equals(pfac.tord)) { return Gp; } if (Gp.size() == 0) { return Gp; } if (Gp.size() == 1) { // also dimension -1 GenPolynomial p = pfac.copy(Gp.get(0)); // change term order G.add(p); return G; } // check dimension zero int z = commonZeroTest(Gp); if (z > 0) { logger.error("use Groebner Walk algorithm"); throw new IllegalArgumentException("ideal(G) not zero dimensional, dim = " + z); } // compute invlex Groebner base via FGLM G = convGroebnerToLex(Gp); return G; } /** * Algorithm CONVGROEBNER: Converts Groebner bases w.r.t. total degree * termorder into Groebner base w.r.t to inverse lexicographical term order * @return Groebner base w.r.t to inverse lexicographical term order */ public List> convGroebnerToLex(List> groebnerBasis) { if (groebnerBasis == null || groebnerBasis.size() == 0) { throw new IllegalArgumentException("G may not be null or empty"); } //Polynomial ring of input Groebnerbasis G GenPolynomialRing ring = groebnerBasis.get(0).ring; int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring String[] ArrayOfVariables = ring.getVars(); //Variables of given polynomial ring w.r.t. to input G RingFactory cfac = ring.coFac; //Main Algorithm //Initialization TermOrder invlex = new TermOrder(TermOrder.INVLEX); //Polynomial ring of newGB with invlex order GenPolynomialRing ufac = new GenPolynomialRing(cfac, numberOfVariables, invlex, ArrayOfVariables); //Local Lists List> newGB = new ArrayList>(); //Instantiate the return list of polynomials List> H = new ArrayList>(); //Instantiate a help list of polynomials List> redTerms = new ArrayList>();//Instantiate the return list of reduced terms //Local Polynomials GenPolynomial t = ring.ONE; //Create ONE polynom of original polynomial ring GenPolynomial h; //Create help polynomial GenPolynomial> hh; //h as polynomial in rfac GenPolynomial> p; //Create another help polynomial redTerms.add(t); //Add ONE to list of reduced terms //create new indeterminate Y1 int indeterminates = 1; //Number of indeterminates, starting with Y1 GenPolynomialRing cpfac = createRingOfIndeterminates(ring, indeterminates); GenPolynomialRing> rfac = new GenPolynomialRing>(cpfac, ring); GenPolynomial> q = rfac.getZERO().sum(cpfac.univariate(0)); //Main while loop int z = -1; t = lMinterm(H, t); while (t != null) { //System.out.println("t = " + t); h = red.normalform(groebnerBasis, t); //System.out.println("Zwischennormalform h = " + h.toString()); hh = PolyUtil. toRecursive(rfac, h); p = hh.sum(q); List> Cf = new ArrayList>(p.getMap().values()); Cf = red.irreducibleSet(Cf); //System.out.println("Cf = " + Cf); //System.out.println("Current Polynomial ring in Y_n: " + rfac.toString()); z = commonZeroTest(Cf); //System.out.println("z = " + z); if (z != 0) { //z=1 OR z=-1 --> Infinite number of solutions OR No solution indeterminates++; //then, increase number of indeterminates by one redTerms.add(t); //add current t to list of reduced terms cpfac = addIndeterminate(cpfac); rfac = new GenPolynomialRing>(cpfac, ring); hh = PolyUtil. toRecursive(rfac, h); GenPolynomial> Yt = rfac.getZERO().sum(cpfac.univariate(0)); GenPolynomial> Yth = hh.multiply(Yt); q = PolyUtil. extendCoefficients(rfac, q, 0, 0L); q = Yth.sum(q); } else { // z=0 --> one solution GenPolynomial g = ufac.getZERO(); for (GenPolynomial pc : Cf) { ExpVector e = pc.leadingExpVector(); //System.out.println("e = " + e); if (e == null) { continue; } int[] v = e.dependencyOnVariables(); if (v == null || v.length == 0) { continue; } int vi = v[0]; vi = indeterminates - vi; C tc = pc.trailingBaseCoefficient(); if (!tc.isZERO()) { tc = tc.negate(); GenPolynomial csRedterm = redTerms.get(vi - 1).multiply(tc); //System.out.println("csRedterm = " + csRedterm); g = g.sum(csRedterm); } } g = g.sum(t); g = ufac.copy(g); H.add(t); if (!g.isZERO()) { newGB.add(g); logger.info("new element for GB = {}", g.leadingExpVector()); } } t = lMinterm(H, t); // compute lMINTERM of current t (lexMinterm) } //logger.info("GB = {}", newGB); return newGB; } /** * Algorithm lMinterm: MINTERM algorithm for inverse lexicographical term * order. * @param t Term * @param G Groebner basis * @return Term that specifies condition (D) or null (Condition (D) in * "A computational approach to commutative algebra", Becker, * Weispfenning, Kredel 1993, p. 427) */ public GenPolynomial lMinterm(List> G, GenPolynomial t) { //not ok: if ( G == null || G.size() == 0 ) ... GenPolynomialRing ring = t.ring; int numberOfVariables = ring.nvar; GenPolynomial u = new GenPolynomial(ring, t.leadingBaseCoefficient(), t.leadingExpVector()); //HeadTerm of of input polynomial ReductionSeq redHelp = new ReductionSeq(); // Create instance of ReductionSeq to use method isReducible //not ok: if ( redHelp.isTopReducible(G,u) ) ... for (int i = numberOfVariables - 1; i >= 0; i--) { // Walk through all variables, starting with least w.r.t to lex-order GenPolynomial x = ring.univariate(i); // Create Linear Polynomial X_i u = u.multiply(x); // Multiply current u with x if (!redHelp.isTopReducible(G, u)) { // Check if any term in HT(G) divides current u return u; } GenPolynomial s = ring.univariate(i, u.degree(numberOfVariables - (i + 1))); //if not, eliminate variable x_i u = u.divide(s); } return null; } /** * Compute the residues to given polynomial list. * @return List of reduced terms */ public List> redTerms(List> groebnerBasis) { if (groebnerBasis == null || groebnerBasis.size() == 0) { throw new IllegalArgumentException("groebnerBasis may not be null or empty"); } GenPolynomialRing ring = groebnerBasis.get(0).ring; int numberOfVariables = ring.nvar; //Number of Variables of the given Polynomial Ring long[] degrees = new long[numberOfVariables]; //Array for the degree-limits for the reduced terms List> terms = new ArrayList>(); //Instantiate the return object for (GenPolynomial g : groebnerBasis) { //For each polynomial of G if (g.isONE()) { terms.clear(); return terms; //If 1 e G, return empty list terms } ExpVector e = g.leadingExpVector(); //Take the exponent of the leading monomial if (e.totalDeg() == e.maxDeg()) { //and check, whether a variable x_i is isolated for (int i = 0; i < numberOfVariables; i++) { long exp = e.getVal(i); if (exp > 0) { degrees[i] = exp; //if true, add the degree of univariate x_i to array degrees } } } } long max = maxArray(degrees); //Find maximum in Array degrees for (int i = 0; i < degrees.length; i++) { //Set all zero grades to maximum of array "degrees" if (degrees[i] == 0) { logger.info("dimension not zero, setting degree to {}", max); degrees[i] = max; //--> to "make" the ideal zero-dimensional } } terms.add(ring.ONE); //Add the one-polynomial of the ring to the list of reduced terms ReductionSeq s = new ReductionSeq(); //Create instance of ReductionSeq to use method isReducible //Main Algorithm for (int i = 0; i < numberOfVariables; i++) { GenPolynomial x = ring.univariate(i); //Create Linear Polynomial X_i List> S = new ArrayList>(terms); //Copy all entries of return list "terms" into list "S" for (GenPolynomial t : S) { for (int l = 1; l <= degrees[i]; l++) { t = t.multiply(x); //Multiply current element t with Linear Polynomial X_i if (!s.isReducible(groebnerBasis, t)) { //Check, if t is irreducible mod groebnerbase terms.add(t); //Add t to return list terms } } } } return terms; } /** * Internal method to create a polynomial ring in i indeterminates. Create * new ring over coefficients of ring with i variables Y1,...,Yi * (indeterminate) * @return polynomial ring with variables Y1...Yi and coefficient of ring. */ GenPolynomialRing createRingOfIndeterminates(GenPolynomialRing ring, int i) { RingFactory cfac = ring.coFac; int indeterminates = i; String[] stringIndeterminates = new String[indeterminates]; for (int j = 1; j <= indeterminates; j++) { stringIndeterminates[j - 1] = ("Y" + j); } TermOrder invlex = new TermOrder(TermOrder.INVLEX); GenPolynomialRing cpfac = new GenPolynomialRing(cfac, indeterminates, invlex, stringIndeterminates); return cpfac; } /** * Internal method to add new indeterminates. Add another variable * (indeterminate) Y_{i+1} to existing ring * @return polynomial ring with variables Y1,..,Yi,Yi+1 and coefficients of * ring. */ GenPolynomialRing addIndeterminate(GenPolynomialRing ring) { String[] stringIndeterminates = new String[1]; int number = ring.nvar + 1; stringIndeterminates[0] = ("Y" + number); ring = ring.extend(stringIndeterminates); return ring; } /** * Maximum of an array. * @return maximum of an array */ long maxArray(long[] t) { if (t.length == 0) { return 0L; } long maximum = t[0]; for (int i = 1; i < t.length; i++) { if (t[i] > maximum) { maximum = t[i]; } } return maximum; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { if (sgb == null) { return; } sgb.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { if (sgb == null) { return 0; } return sgb.cancel(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBaseFGLMExamples.java000066400000000000000000001256621445075545500263300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.gb.GroebnerBase; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.Monomial; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; /** * Groebner base FGLM examples. * @author Jan Suess */ public class GroebnerBaseFGLMExamples { /** * main */ public static void main(String[] args) { //junit.textui.TestRunner.run(suite()); GroebnerBaseFGLMExamples ex = new GroebnerBaseFGLMExamples(); ex.testC5(); /* ex.xtestFiveVarsOrder(); ex.xtestCAP(); ex.xtestAUX(); ex.xtestModC5(); ex.xtestC6(); ex.xtestIsaac(); ex.xtestNiermann(); ex.ytestWalkS7(); ex.ytestCassouMod1(); ex.ytestOmdi1(); ex.ytestLamm1(); ex.xtestEquilibrium(); ex.xtestTrinks2(); ex.xtestHairerRungeKutta_1(); */ } /* * Constructs a GroebnerBaseFGLMExamples object. * @param name String. public GroebnerBaseFGLMExamples(String name) { super(name); } */ /* * suite. public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseFGLMExamples.class); return suite; } */ //field Q String all = "Zahlbereich | Ordnung | Elements G | Elements L | bitHeight G | bitHeight L | Deg G | Deg L | Time G | Time FGLM | Time L"; String grad = "Zahlbereich | Ordnung | Elements G | bitHeight G | Deg G | Time G | vDim"; String lex = "Zahlbereich | Ordnung | Elements L | bitHeight L | Deg L | Time L"; String fglm = "Zahlbereich | Ordnung | Elements G | Elements L | bitHeight G | bitHeight L | Deg G | Deg L | Time G | Time FGLM"; //MOD 1831 String modAll = "Zahlbereich | Ordnung | Elements G | Elements L | Deg G | Deg L | Time G | Time FGLM | Time L"; //String modGrad = "Zahlbereich | Ordnung | Elements G | Deg G | Time G"; String modfglm = "Zahlbereich | Ordnung | Elements G | Elements L | Deg G | Deg L | Time G | Time FGLM"; /* @Override protected void setUp() { System.out.println("Setup"); } @Override protected void tearDown() { System.out.println("Tear Down"); } */ //Test with five variables and different variable orders public void xtestFiveVarsOrder() { String polynomials = "( " + " (v^8*x*y*z), ( w^3*x - 2*v), ( 4*x*y - 2 + y), ( 3*y^5 - 3 + z ), ( 8*y^2*z^2 + x * y^6 )" + ") "; String[] order = new String[] { "v", "w", "x", "y", "z" }; //String order1 = shuffle(order); String order2 = shuffle(order); //String order3 = shuffle(order); //String order4 = shuffle(order); //String order5 = shuffle(order); //String order6 = "(z,w,v,y,x)"; //langsam //String order7 = "(v,z,w,y,x)"; //langsam //String order8 = "(w,z,v,x,y)"; //langsam /* String erg1 = testGeneral(order1, polynomials); String erg2 = testGeneral(order2, polynomials); String erg3 = testGeneral(order3, polynomials); String erg4 = testGeneral(order4, polynomials); String erg5 = testGeneral(order5, polynomials); */ String ergM13 = modAll(order2, polynomials, 13); String ergM7 = modAll(order2, polynomials, 7); /* String ergOnlyL_1 = testOnlyLex(order1, polynomials); String ergOnlyL_2 = testOnlyLex(order2, polynomials); String ergOnlyL_3 = testOnlyLex(order3, polynomials); String ergOnlyL_4 = testOnlyLex(order4, polynomials); String ergOnlyL_5 = testOnlyLex(order5, polynomials); String erg6 = testGeneral(order6, polynomials); String erg7 = testGeneral(order7, polynomials); String erg8 = testGeneral(order8, polynomials); */ //langsam: (z,w,v,y,x), (v,z,w,y,x) /* System.out.println(categoryLex); System.out.println(ergOnlyL_1); System.out.println(ergOnlyL_2); System.out.println(ergOnlyL_3); System.out.println(ergOnlyL_4); System.out.println(ergOnlyL_5); System.out.println(category); System.out.println(erg6); System.out.println(erg7); System.out.println(erg8); System.out.println(erg1); System.out.println(erg2); System.out.println(erg3); System.out.println(erg4); System.out.println(erg5); */ System.out.println(all); System.out.println("Mod 13"); System.out.println(ergM13); System.out.println("Mod 7"); System.out.println(ergM7); } //=================================================================== //Examples taken from "Efficient Computation of Zero-Dimensional Gröbner Bases by Change of Ordering", // 1994, Faugere, Gianni, Lazard, Mora (FGLM) //=================================================================== public void xtestCAP() { String polynomials = "( " + " (y^2*z + 2*x*y*t - 2*x - z)," + "(-x^3*z + 4*x*y^2*z + 4*x^2*y*t + 2*y^3*t + 4*x^2 - 10*y^2 + 4*x*z - 10*y*t + 2)," + "(2*y*z*t + x*t^2 - x - 2*z)," + "(-x*z^3 + 4*y*z^2*t + 4*x*z*t^2 + 2*y*t^3 + 4*x*z + 4*z^2 - 10*y*t -10*t^2 + 2)" + ") "; String orderINV = "(x,y,z,t)"; String orderL = "(t,z,y,x)"; //Tests String erg_deg = grad(orderINV, polynomials); System.out.println(grad); System.out.println(erg_deg); String erg1 = all(orderINV, polynomials); String erg2 = all(orderL, polynomials); String ergMod1 = modAll(orderINV, polynomials, 1831); String ergMod2 = modAll(orderL, polynomials, 1831); System.out.println(all); System.out.println(erg1); System.out.println(erg2); System.out.println("\n"); System.out.println(modAll); System.out.println(ergMod1); System.out.println(ergMod2); } public void xtestAUX() { String polynomials = "( " + " (a^2*b*c + a*b^2*c + a*b*c^2 + a*b*c + a*b + a*c + b*c)," + "(a^2*b^2*c + a*b^2*c^2 + a^2*b*c + a*b*c + b*c + a + c )," + "(a^2*b^2*c^2 + a^2*b^2*c + a*b^2*c + a*b*c + a*c + c + 1)" + ") "; String orderINV = "(a,b,c)"; String orderL = "(c,b,a)"; //Tests String erg_deg = grad(orderINV, polynomials); System.out.println(grad); System.out.println(erg_deg); String erg1 = all(orderINV, polynomials); String erg2 = all(orderL, polynomials); String ergMod1 = modAll(orderINV, polynomials, 1831); String ergMod2 = modAll(orderL, polynomials, 1831); System.out.println(all); System.out.println(erg1); System.out.println(erg2); System.out.println("\n"); System.out.println(modAll); System.out.println(ergMod1); System.out.println(ergMod2); } public void testC5() { String polynomials = "( " + " (a + b + c + d + e)," + "(a*b + b*c + c*d + a*e + d*e)," + "(a*b*c + b*c*d + a*b*e + a*d*e + c*d*e)," + "(a*b*c*d + a*b*c*e + a*b*d*e + a*c*d*e + b*c*d*e)," + "(a*b*c*d*e -1)" + ") "; String orderINV = "(a,b,c,d,e)"; String orderL = "(e,d,c,b,a)"; //Tests String erg_deg = grad(orderINV, polynomials); //System.out.println(grad); //System.out.println(erg_deg); String erg1 = all(orderINV, polynomials); String erg2 = all(orderL, polynomials); String ergMod1 = modAll(orderINV, polynomials, 1831); String ergMod2 = modAll(orderL, polynomials, 1831); System.out.println(grad); System.out.println(erg_deg); System.out.println(""); System.out.println(all); System.out.println(erg1); System.out.println(erg2); System.out.println("\n"); System.out.println(modAll); System.out.println(ergMod1); System.out.println(ergMod2); } public void xtestModC5() { String polynomials = "( " + " (a + b + c + d + e)," + "(a*b + b*c + c*d + a*e + d*e)," + "(a*b*c + b*c*d + a*b*e + a*d*e + c*d*e)," + "(b*c*d + a*b*c*e + a*b*d*e + a*c*d*e + b*c*d*e)," + "(a*b*c*d*e -1)" + ") "; //String orderINV = "(a,b,c,d,e)"; String orderL = "(e,d,c,b,a)"; //Tests String erg_deg = grad(orderL, polynomials); System.out.println(grad); System.out.println(erg_deg); /* String ergOnlyFGLM_1 = fglm(orderINV, polynomials); System.out.println(fglm); System.out.println(ergOnlyFGLM_1); //Tests MODULO String ergOnlyG_1 = modGrad(orderINV, polynomials, 1831); System.out.println(modGrad); System.out.println(ergOnlyG_1); String erg1 = modfglm(orderINV, polynomials, 1831); System.out.println(modfglm); System.out.println(erg1); */ } public void xtestC6() { String polynomials = "( " + " (a + b + c + d + e + f)," + "(a*b + b*c + c*d + d*e + e*f + a*f)," + "(a*b*c + b*c*d + c*d*e + d*e*f + a*e*f + a*b*f)," + "(a*b*c*d + b*c*d*e + c*d*e*f + a*d*e*f + a*b*e*f + a*b*c*f)," + "(a*b*c*d*e + b*c*d*e*f + a*c*d*e*f + a*b*d*e*f + a*b*c*e*f + a*b*c*d*f)," + "(a*b*c*d*e*f - 1)" + ") "; String orderINV = "(a,b,c,d,e,f)"; //String orderL = "(f,e,d,c,b,a)"; //Tests String erg2 = modAll(orderINV, polynomials, 1831); System.out.println(modAll); System.out.println(erg2); /* String ergOnlyG_1 = modGrad(orderINV, polynomials, 1831); System.out.println(modGrad); System.out.println(ergOnlyG_1); String erg1 = modfglm(orderINV, polynomials, 1831); System.out.println(modfglm); System.out.println(erg1); */ } //=================================================================== //Examples taken from "Der FGLM-Algorithmus: verallgemeinert und implementiert in SINGULAR", 1997, Wichmann //=================================================================== public void xtestIsaac() { String polynomials = "( " + " (8*w^2 + 5*w*x - 4*w*y + 2*w*z + 3*w + 5*x^2 + 2*x*y - 7*x*z - 7*x + 7*y^2 -8*y*z - 7*y + 7*z^2 - 8*z + 8)," + "(3*w^2 - 5*w*x - 3*w*y - 6*w*z + 9*w + 4*x^2 + 2*x*y - 2*x*z + 7*x + 9*y^2 + 6*y*z + 5*y + 7*z^2 + 7*z + 5)," + "(-2*w^2 + 9*w*x + 9*w*y - 7*w*z - 4*w + 8*x^2 + 9*x*y - 3*x*z + 8*x + 6*y^2 - 7*y*z + 4*y - 6*z^2 + 8*z + 2)," + "(7*w^2 + 5*w*x + 3*w*y - 5*w*z - 5*w + 2*x^2 + 9*x*y - 7*x*z + 4*x -4*y^2 - 5*y*z + 6*y - 4*z^2 - 9*z + 2)" + ") "; //String orderINV = "(w,x,y,z)"; String orderL = "(z,y,x,w)"; //Tests String erg_deg = grad(orderL, polynomials); System.out.println(grad); System.out.println(erg_deg); /* String erg3 = all(orderINV, polynomials); System.out.println(all); System.out.println(erg3); String ergOnlyLex_1 = lex(orderINV, polynomials); String ergOnlyLex_2 = lex(orderL, polynomials); System.out.println(lex); System.out.println(ergOnlyLex_1); System.out.println(ergOnlyLex_2); String ergOnlyFGLM_1 = fglm(orderINV, polynomials); String ergOnlyFGLM_2 = fglm(orderL, polynomials); System.out.println(fglm); System.out.println(ergOnlyFGLM_1); System.out.println(ergOnlyFGLM_2); String ergm1 = modAll(orderINV, polynomials, 2147464751); String ergm2 = modAll(orderL, polynomials, 2147464751); System.out.println(modAll); System.out.println(ergm1); System.out.println(ergm2); */ } public void xtestNiermann() { String polynomials = "( " + " (x^2 + x*y^2*z - 2*x*y + y^4 + y^2 + z^2)," + "(-x^3*y^2 + x*y^2*z + x*y*z^3 - 2*x*y + y^4)," + "(-2*x^2*y + x*y^4 + y*z^4 - 3)" + ") "; String orderINV = "(x,y,z)"; String orderL = "(z,y,x)"; //Tests String erg_deg = grad(orderINV, polynomials); System.out.println(grad); System.out.println(erg_deg); /* String erg1 = fglm(orderINV, polynomials); String erg2 = fglm(orderL, polynomials); System.out.println(fglm); System.out.println(erg1); System.out.println(erg2); */ String ergm1 = modfglm(orderINV, polynomials, 1831); String ergm2 = modfglm(orderL, polynomials, 2147464751); System.out.println(modfglm); System.out.println(ergm1); System.out.println(ergm2); } public void ytestWalkS7() { String polynomials = "( " + " (2*g*b + 2*f*c + 2*e*d + a^2 + a)," + "(2*g*c + 2*f*d + e^2 + 2*b*a + b)," + "(2*g*d + 2*f*e + 2*c*a + c + b^2)," + "(2*g*e + f^2 + 2*d*a + d + 2*c*b)," + "(2*g*f + 2*e*a + e + 2*d*b + c^2)," + "(g^2 + 2*f*a + f + 2*e*b + 2*d*c)," + "(2*g*a + g + 2*f*b + 2*e*c + d^2)" + ") "; //String orderINV = "(a,b,c,d,e,f,g)"; String orderL = "(g,f,e,d,c,b,a)"; //Tests //String ergm1 = modAll(orderINV, polynomials, 2147464751); //String ergm2 = modfglm(orderL, polynomials, 1831); //System.out.println(modfglm); //System.out.println(ergm1); //System.out.println(ergm2); String erg2 = fglm(orderL, polynomials); System.out.println(fglm); System.out.println(erg2); } public void ytestCassouMod1() { String polynomials = "( " + " (15*a^4*b*c^2 + 6*a^4*b^3 + 21*a^4*b^2*c - 144*a^2*b - 8*a^2*b^2*d - 28*a^2*b*c*d - 648*a^2*c + 36*c^2*d + 9*a^4*c^3 - 120)," + "(30*b^3*a^4*c - 32*c*d^2*b - 720*c*a^2*b - 24*b^3*a^2*d - 432*b^2*a^2 + 576*d*b - 576*c*d + 16*b*a^2*c^2*d + 16*c^2*d^2 + 16*d^2*b^2 + 9*b^4*a^4 + 5184 + 39*c^2*a^4*b^2 + 18*c^3*a^4*b - 432*c^2*a^2 + 24*c^3*a^2*d - 16*b^2*a^2*c*d - 240*b)," + "(216*c*a^2*b - 162*c^2*a^2 - 81*b^2*a^2 + 5184 + 1008*d*b - 1008*c*d + 15*b^2*a^2*c*d - 15*b^3*a^2*d - 80*c*d^2*b + 40*c^2*d^2 + 40*d^2*b^2)," + "(261 + 4*c*a^2*b - 3*c^2*a^2 - 4*b^2*a^2 + 22*d*b - 22*c*d)" + ") "; String orderINV = "(a,b,c,d)"; String orderL = "(d,c,b,a)"; //Tests String ergm1 = modfglm(orderL, polynomials, 1831); String ergm2 = modfglm(orderINV, polynomials, 1831); System.out.println(modfglm); System.out.println(ergm1); System.out.println(ergm2); } public void ytestOmdi1() { String polynomials = "( " + " (a + c + v + 2*x - 1)," + "(a*b + c*u + 2*v*w + 2*x*y + 2*x*z -2/3)," + "(a*b^2 + c*u^2 + 2*v*w^2 + 2*x*y^2 + 2*x*z^2 - 2/5)," + "(a*b^3 + c*u^3 + 2*v*w^3 + 2*x*y^3 + 2*x*z^3 - 2/7)," + "(a*b^4 + c*u^4 + 2*v*w^4 + 2*x*y^4 + 2*x*z^4 - 2/9)," + "(v*w^2 + 2*x*y*z - 1/9)," + "(v*w^4 + 2*x*y^2*z^2 - 1/25)," + "(v*w^3 + 2*x*y*z^2 + x*y^2*z - 1/15)," + "(v*w^4 + x*y*z^3 + x*y^3*z -1/21)" + ") "; //String orderINV = "(a,b,c,u,v,w,x,y,z)"; String orderL = "(z,y,x,w,v,u,c,b,a)"; //Tests String erg_deg = grad(orderL, polynomials); System.out.println(grad); System.out.println(erg_deg); /* String ergm1 = modfglm(orderL, polynomials, 1831); String ergm2 = modfglm(orderINV, polynomials, 1831); System.out.println(modfglm); System.out.println(ergm1); System.out.println(ergm2); */ } public void ytestLamm1() { String polynomials = "( " + " (45*x^8 + 3*x^7 + 39*x^6 + 30*x^5 + 13*x^4 + 41*x^3 + 5*x^2 + 46*x + 7)," + "(49*x^7*y + 35*x*y^7 + 37*x*y^6 + 9*y^7 + 4*x^6 + 6*y^6 + 27*x^3*y^2 + 20*x*y^4 + 31*x^4 + 33*x^2*y + 24*x^2 + 49*y + 43)" + ") "; String orderINV = "(x,y)"; String orderL = "(y,x)"; //Tests String erg_deg = grad(orderINV, polynomials); System.out.println(grad); System.out.println(erg_deg); String erg1 = all(orderINV, polynomials); String erg2 = all(orderL, polynomials); String ergMod1 = modAll(orderINV, polynomials, 1831); String ergMod2 = modAll(orderL, polynomials, 1831); System.out.println(all); System.out.println(erg1); System.out.println(erg2); System.out.println("\n"); System.out.println(modAll); System.out.println(ergMod1); System.out.println(ergMod2); } //=================================================================== //Examples taken from "Some Examples for Solving Systems of Algebraic Equations by Calculating Gröbner Bases", 1984, Boege, Gebauer, Kredel //=================================================================== public void xtestEquilibrium() { String polynomials = "( " + " (y^4 - 20/7*z^2)," + "(z^2*x^4 + 7/10*z*x^4 + 7/48*x^4 - 50/27*z^2 - 35/27*z - 49/216)," + "(x^5*y^3 + 7/5*z^4*y^3 + 609/1000 *z^3*y^3 + 49/1250*z^2*y^3 - 27391/800000*z*y^3 - 1029/160000*y^3 + 3/7*z^5*x*y^2 +" + "3/5*z^6*x*y^2 + 63/200*z^3*x*y^2 + 147/2000*z^2*x*y^2 + 4137/800000*z*x*y^2 - 7/20*z^4*x^2*y - 77/125*z^3*x^2*y" + "- 23863/60000*z^2*x^2*y - 1078/9375*z*x^2*y - 24353/1920000*x^2*y - 3/20*z^4*x^3 - 21/100*z^3*x^3" + "- 91/800*z^2*x^3 - 5887/200000*z*x^3 - 343/128000*x^3)" + ") "; String order = "(x,y,z)"; //Tests String ergOnlyG_1 = grad(order, polynomials); System.out.println(grad); System.out.println(ergOnlyG_1); } public void xtestTrinks2() { String polynomials = "( " + " (45*p + 35*s - 165*b - 36)," + "(35*p + 40*z + 25*t - 27*s)," + "(15*w + 25*p*s + 30*z - 18*t - 165*b^2)," + "(-9*w + 15*p*t + 20*z*s)," + "(w*p + 2*z*t - 11*b^3)," + "(99*w - 11*s*b + 3*b^2)," + "(b^2 + 33/50*b + 2673/10000)" + ") "; String order1 = "(b,s,t,z,p,w)"; String order2 = "(s,b,t,z,p,w)"; String order3 = "(s,t,b,z,p,w)"; String order4 = "(s,t,z,p,b,w)"; String order5 = "(s,t,z,p,w,b)"; String order6 = "(s,z,p,w,b,t)"; String order7 = "(p,w,b,t,s,z)"; String order8 = "(z,w,b,s,t,p)"; String order9 = "(t,z,p,w,b,s)"; String order10 = "(z,p,w,b,s,t)"; String order11 = "(p,w,b,s,t,z)"; String order12 = "(w,b,s,t,z,p)"; //Tests String erg_1 = all(order1, polynomials); String erg_2 = all(order2, polynomials); String erg_3 = all(order3, polynomials); String erg_4 = all(order4, polynomials); String erg_5 = all(order5, polynomials); String erg_6 = all(order6, polynomials); String erg_7 = all(order7, polynomials); String erg_8 = all(order8, polynomials); String erg_9 = all(order9, polynomials); String erg_10 = all(order10, polynomials); String erg_11 = all(order11, polynomials); String erg_12 = all(order12, polynomials); System.out.println(all); System.out.println(erg_1); System.out.println(erg_2); System.out.println(erg_3); System.out.println(erg_4); System.out.println(erg_5); System.out.println(erg_6); System.out.println(erg_7); System.out.println(erg_8); System.out.println(erg_9); System.out.println(erg_10); System.out.println(erg_11); System.out.println(erg_12); } public void xtestHairerRungeKutta_1() { String polynomials = "( " + " (a-f),(b-h-g),(e+d+c-1),(d*a+c*b-1/2),(d*a^2+c*b^2-1/3),(c*g*a-1/6)" + ") "; String[] order = new String[] { "a", "b", "c", "d", "e", "f", "g", "h" }; String order1 = shuffle(order); String order2 = shuffle(order); String order3 = shuffle(order); String order4 = shuffle(order); String order5 = shuffle(order); // langsam (e,d,h,c,g,a,f,b), (h,d,b,e,c,g,a,f) um die 120 // sehr langsam (e,h,d,c,g,b,a,f) um die 1000 // sehr schnell (g,b,f,h,c,d,a,e), (h,c,a,g,d,f,e,b) 1 millisec String ergOnlyG_1 = grad(order1, polynomials); System.out.println(grad); System.out.println(ergOnlyG_1); String ergOnlyL_1 = lex(order1, polynomials); String ergOnlyL_2 = lex(order2, polynomials); String ergOnlyL_3 = lex(order3, polynomials); String ergOnlyL_4 = lex(order4, polynomials); String ergOnlyL_5 = lex(order5, polynomials); System.out.println(lex); System.out.println(ergOnlyL_1); System.out.println(ergOnlyL_2); System.out.println(ergOnlyL_3); System.out.println(ergOnlyL_4); System.out.println(ergOnlyL_5); //String ergGeneral = all(order, polynomials); //System.out.println(all); //System.out.println(ergGeneral); } //================================================================================================= //Internal methods //================================================================================================= @SuppressWarnings({ "unchecked", "cast" }) public String all(String order, String polynomials) { GroebnerBaseFGLM IdealObjectFGLM; BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String polynomials_Grad = order + " G " + polynomials; String polynomials_Lex = order + " L " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; Reader sourceL = new StringReader(polynomials_Lex); GenPolynomialTokenizer parserL = new GenPolynomialTokenizer(sourceL); PolynomialList L = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); L = (PolynomialList) parserL.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("Input " + G); System.out.println("Input " + L); //Computation of the Groebnerbase with Buchberger w.r.t INVLEX long buchberger_Lex = System.currentTimeMillis(); List> GL = gb.GB(L.list); buchberger_Lex = System.currentTimeMillis() - buchberger_Lex; //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); //PolynomialList GLL = new PolynomialList(L.ring, GL); IdealObjectFGLM = new GroebnerBaseFGLM(); //GGG); //IdealObjectLex = new GroebnerBaseSeq(GLL); long tconv = System.currentTimeMillis(); List> resultFGLM = IdealObjectFGLM.convGroebnerToLex(GG); tconv = System.currentTimeMillis() - tconv; OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); OrderedPolynomialList o2 = new OrderedPolynomialList( resultFGLM.get(0).ring, resultFGLM); //List> resultBuchberger = GL; OrderedPolynomialList o3 = new OrderedPolynomialList(GL.get(0).ring, GL); int grad_numberOfElements = GG.size(); int lex_numberOfElements = resultFGLM.size(); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); // IdealObjectFGLM.maxDegreeOfGB(); long lex_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GL); // IdealObjectLex.maxDegreeOfGB(); int grad_height = bitHeight(GG); int lex_height = bitHeight(resultFGLM); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); System.out.println("Groebnerbase FGML (INVLEX) computed from Buchberger (IGRLEX) " + o2); System.out.println("Groebnerbase Buchberger (INVLEX) " + o3); String erg = "BigRational |" + order + " |" + grad_numberOfElements + " |" + lex_numberOfElements + " |" + grad_height + " |" + lex_height + " |" + grad_maxPolyGrad + " |" + lex_maxPolyGrad + " |" + buchberger_Grad + " |" + tconv + " |" + buchberger_Lex; //assertEquals(o2, o3); if (!o2.equals(o3)) { throw new RuntimeException("FGLM != GB: " + o2 + " != " + o3); } return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String fglm(String order, String polynomials) { GroebnerBaseFGLM IdealObjectGrad; //GroebnerBaseAbstract IdealObjectLex; BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String polynomials_Grad = order + " G " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("Input " + G); //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); IdealObjectGrad = new GroebnerBaseFGLM(); //GGG); long tconv = System.currentTimeMillis(); List> resultFGLM = IdealObjectGrad.convGroebnerToLex(GG); tconv = System.currentTimeMillis() - tconv; //PolynomialList LLL = new PolynomialList(G.ring, resultFGLM); //IdealObjectLex = new GroebnerBaseSeq(); //LLL); OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); OrderedPolynomialList o2 = new OrderedPolynomialList( resultFGLM.get(0).ring, resultFGLM); int grad_numberOfElements = GG.size(); int lex_numberOfElements = resultFGLM.size(); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); //IdealObjectGrad.maxDegreeOfGB(); long lex_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(resultFGLM); //IdealObjectLex.maxDegreeOfGB(); int grad_height = bitHeight(GG); int lex_height = bitHeight(resultFGLM); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); System.out.println("Groebnerbase FGML (INVLEX) computed from Buchberger (IGRLEX) " + o2); String erg = "BigRational |" + order + " |" + grad_numberOfElements + " |" + lex_numberOfElements + " |" + grad_height + " |" + lex_height + " |" + grad_maxPolyGrad + " |" + lex_maxPolyGrad + " |" + buchberger_Grad + " |" + tconv; return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String grad(String order, String polynomials) { BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String polynomials_Grad = order + " G " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("Input " + G); //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); GroebnerBaseFGLM IdealObjectGrad; IdealObjectGrad = new GroebnerBaseFGLM(); //GGG); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); //IdealObjectGrad.maxDegreeOfGB(); List> reducedTerms = IdealObjectGrad.redTerms(GG); OrderedPolynomialList o4 = new OrderedPolynomialList( reducedTerms.get(0).ring, reducedTerms); int grad_numberOfReducedElements = reducedTerms.size(); int grad_numberOfElements = GG.size(); int grad_height = bitHeight(GG); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); System.out.println("Reduced Terms" + o4); String erg = "BigRational |" + order + " |" + grad_numberOfElements + " |" + grad_height + " |" + grad_maxPolyGrad + " |" + buchberger_Grad + " |" + grad_numberOfReducedElements; return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String lex(String order, String polynomials) { //GroebnerBaseAbstract IdealObjectLex; BigRational coeff = new BigRational(); GroebnerBase gb = GBFactory.getImplementation(coeff); String polynomials_Lex = order + " L " + polynomials; Reader sourceL = new StringReader(polynomials_Lex); GenPolynomialTokenizer parserL = new GenPolynomialTokenizer(sourceL); PolynomialList L = null; try { L = (PolynomialList) parserL.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("Input " + L); //Computation of the Groebnerbase with Buchberger w.r.t INVLEX long buchberger_Lex = System.currentTimeMillis(); List> GL = gb.GB(L.list); buchberger_Lex = System.currentTimeMillis() - buchberger_Lex; //PolynomialList GLL = new PolynomialList(L.ring, GL); //IdealObjectLex = new GroebnerBaseAbstract(GLL); OrderedPolynomialList o3 = new OrderedPolynomialList(GL.get(0).ring, GL); int lex_numberOfElements = GL.size(); long lex_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GL); //IdealObjectLex.maxDegreeOfGB(); int lexHeigth = bitHeight(GL); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbase Buchberger (INVLEX) " + o3); String erg = "BigRational" + order + "|" + lex_numberOfElements + " |" + lexHeigth + " |" + lex_maxPolyGrad + " |" + buchberger_Lex; return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String modAll(String order, String polynomials, Integer m) { GroebnerBaseFGLM IdealObjectFGLM; //GroebnerBaseAbstract IdealObjectLex; ModIntegerRing ring = new ModIntegerRing(m); GroebnerBase gb = GBFactory.getImplementation(ring); String polynomials_Grad = "Mod " + ring.modul + " " + order + " G " + polynomials; String polynomials_Lex = "Mod " + ring.modul + " " + order + " L " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; Reader sourceL = new StringReader(polynomials_Lex); GenPolynomialTokenizer parserL = new GenPolynomialTokenizer(sourceL); PolynomialList L = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); L = (PolynomialList) parserL.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("G= " + G); System.out.println("L= " + L); //Computation of the Groebnerbase with Buchberger w.r.t INVLEX long buchberger_Lex = System.currentTimeMillis(); List> GL = gb.GB(L.list); buchberger_Lex = System.currentTimeMillis() - buchberger_Lex; //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); //PolynomialList GLL = new PolynomialList(L.ring, GL); IdealObjectFGLM = new GroebnerBaseFGLM(); //GGG); //IdealObjectLex = new GroebnerBaseAbstract(GLL); long tconv = System.currentTimeMillis(); List> resultFGLM = IdealObjectFGLM.convGroebnerToLex(GG); tconv = System.currentTimeMillis() - tconv; OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); OrderedPolynomialList o2 = new OrderedPolynomialList(resultFGLM.get(0).ring, resultFGLM); List> resultBuchberger = GL; OrderedPolynomialList o3 = new OrderedPolynomialList( resultBuchberger.get(0).ring, resultBuchberger); int grad_numberOfElements = GG.size(); int lex_numberOfElements = resultFGLM.size(); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); //IdealObjectFGLM.maxDegreeOfGB(); long lex_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GL); //IdealObjectLex.maxDegreeOfGB(); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); System.out.println("Groebnerbase FGML (INVLEX) computed from Buchberger (IGRLEX) " + o2); System.out.println("Groebnerbase Buchberger (INVLEX) " + o3); String erg = "Mod " + m + " |" + order + " |" + grad_numberOfElements + " |" + lex_numberOfElements + " |" + grad_maxPolyGrad + " |" + lex_maxPolyGrad + " |" + buchberger_Grad + " |" + tconv + " |" + buchberger_Lex; //assertEquals(o2, o3); if (!o2.equals(o3)) { throw new RuntimeException("FGLM != GB: " + o2 + " != " + o3); } return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String modGrad(String order, String polynomials, Integer m) { //GroebnerBaseFGLM IdealObjectFGLM; ModIntegerRing ring = new ModIntegerRing(m); GroebnerBase gb = GBFactory.getImplementation(ring); String polynomials_Grad = "Mod " + ring.modul + " " + order + " G " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("G= " + G); //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); //IdealObjectFGLM = new GroebnerBaseFGLM(); //GGG); OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); int grad_numberOfElements = GG.size(); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); //IdealObjectFGLM.maxDegreeOfGB(); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); String erg = "Mod " + m + " |" + order + " |" + grad_numberOfElements + " |" + grad_maxPolyGrad + " |" + buchberger_Grad; return erg; } @SuppressWarnings({ "unchecked", "cast" }) public String modfglm(String order, String polynomials, Integer m) { GroebnerBaseFGLM IdealObjectFGLM; //GroebnerBaseAbstract IdealObjectLex; ModIntegerRing ring = new ModIntegerRing(m); GroebnerBase gb = GBFactory.getImplementation(ring); String polynomials_Grad = "Mod " + ring.modul + " " + order + " G " + polynomials; Reader sourceG = new StringReader(polynomials_Grad); GenPolynomialTokenizer parserG = new GenPolynomialTokenizer(sourceG); PolynomialList G = null; try { G = (PolynomialList) parserG.nextPolynomialSet(); } catch (IOException e) { e.printStackTrace(); return "fail"; } System.out.println("G= " + G); //Computation of the Groebnerbase with Buchberger w.r.t GRADLEX (Total degree + INVLEX) long buchberger_Grad = System.currentTimeMillis(); List> GG = gb.GB(G.list); buchberger_Grad = System.currentTimeMillis() - buchberger_Grad; //PolynomialList GGG = new PolynomialList(G.ring, GG); IdealObjectFGLM = new GroebnerBaseFGLM(); //GGG); long tconv = System.currentTimeMillis(); List> resultFGLM = IdealObjectFGLM.convGroebnerToLex(GG); tconv = System.currentTimeMillis() - tconv; //PolynomialList LLL = new PolynomialList(G.ring, resultFGLM); //IdealObjectLex = new GroebnerBaseAbstract(LLL); OrderedPolynomialList o1 = new OrderedPolynomialList(GG.get(0).ring, GG); OrderedPolynomialList o2 = new OrderedPolynomialList(resultFGLM.get(0).ring, resultFGLM); int grad_numberOfElements = GG.size(); int lex_numberOfElements = resultFGLM.size(); long grad_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(GG); //IdealObjectFGLM.maxDegreeOfGB(); long lex_maxPolyGrad = PolyUtil. totalDegreeLeadingTerm(resultFGLM); //IdealObjectLex.maxDegreeOfGB(); System.out.println("Order of Variables: " + order); System.out.println("Groebnerbases: "); System.out.println("Groebnerbase Buchberger (IGRLEX) " + o1); System.out.println("Groebnerbase FGML (INVLEX) computed from Buchberger (IGRLEX) " + o2); String erg = "Mod " + m + " |" + order + " |" + grad_numberOfElements + " |" + lex_numberOfElements + " |" + grad_maxPolyGrad + " |" + lex_maxPolyGrad + " |" + buchberger_Grad + " |" + tconv; return erg; } /** * Method shuffle returns a random permutation of a string of variables. */ public String shuffle(String[] tempOrder) { Collections.shuffle(Arrays.asList(tempOrder)); StringBuffer ret = new StringBuffer("("); ret.append(ExpVector.varsToString(tempOrder)); ret.append(")"); return ret.toString(); } /** * Method bitHeight returns the bitlength of the greatest number occurring * during the computation of a Groebner base. */ public int bitHeight(List> list) { BigInteger denom = BigInteger.ONE; BigInteger num = BigInteger.ONE; for (GenPolynomial g : list) { for (Monomial m : g) { BigRational bi = m.coefficient(); BigInteger i = bi.denominator().abs(); BigInteger j = bi.numerator().abs(); if (i.compareTo(denom) > 0) denom = i; if (j.compareTo(num) > 0) num = j; } } int erg; if (denom.compareTo(num) > 0) { erg = denom.bitLength(); } else { erg = num.bitLength(); } return erg; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBasePartial.java000066400000000000000000000522441445075545500254730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OptimizedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderOptimization; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Partial Groebner Bases for subsets of variables. Let pvars be a * subset of variables vars of the polynomial ring K[vars]. Methods * compute Groebner bases with coefficients from K[vars \ pvars] in the * polynomial ring K[vars \ pvars][pvars]. * @param coefficient type * @author Heinz Kredel */ public class GroebnerBasePartial> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBasePartial.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Backing Groebner base engine. */ protected GroebnerBaseAbstract bb; /** * Backing recursive Groebner base engine. */ protected GroebnerBaseAbstract> rbb; // can be null /** * Constructor. */ public GroebnerBasePartial() { this(new GroebnerBaseSeq(), null); } /** * Constructor. * @param rf coefficient ring factory. */ public GroebnerBasePartial(RingFactory> rf) { this(new GroebnerBaseSeq(), new GroebnerBasePseudoRecSeq(rf)); } /** * Constructor. * @param bb Groebner base engine * @param rbb recursive Groebner base engine */ public GroebnerBasePartial(GroebnerBaseAbstract bb, GroebnerBaseAbstract> rbb) { super(); this.bb = bb; this.rbb = rbb; //if (rbb == null) { //logger.warn("no recursive GB given"); //} } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { return bb.GB(modv, F); } /** * Groebner base test. * @param F polynomial list. * @return true, if F is a partial Groebner base, else false. */ public boolean isGBrec(List>> F) { return isGBrec(0, F); } /** * Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a partial Groebner base, else false. */ public boolean isGBrec(int modv, List>> F) { if (F == null || F.isEmpty()) { return true; } if (true) { rbb = new GroebnerBasePseudoRecSeq(F.get(0).ring.coFac); } return rbb.isGB(modv, F); } /** * Partial permutation for specific variables. Computes a permutation perm * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars). * Uses internal (reversed) variable sorting. * @param vars names for all variables. * @param pvars names for main variables, pvars subseteq vars. * @return permutation for vars, such that perm(vars) == pvars ... (vars \ * pvars). */ public static List partialPermutation(String[] vars, String[] pvars) { return partialPermutation(vars, pvars, null); //no: return getPermutation(vars,pvars); } /** * Permutation of variables for elimination. * @param aname variables for the full polynomial ring. * @param ename variables for the elimination ring, subseteq aname. * @return perm({vars \ ename},ename) */ public static List getPermutation(String[] aname, String[] ename) { if (aname == null || ename == null) { throw new IllegalArgumentException("aname or ename may not be null"); } List perm = new ArrayList(aname.length); // add ename permutation for (int i = 0; i < ename.length; i++) { int j = indexOf(ename[i], aname); if (j < 0) { throw new IllegalArgumentException("ename not contained in aname"); } perm.add(j); } //System.out.println("perm_low = " + perm); // add aname \ ename permutation for (int i = 0; i < aname.length; i++) { if (!perm.contains(i)) { perm.add(i); } } //System.out.println("perm_all = " + perm); // reverse permutation indices int n1 = aname.length - 1; List perm1 = new ArrayList(aname.length); for (Integer k : perm) { perm1.add(n1 - k); } perm = perm1; //System.out.println("perm_inv = " + perm1); Collections.reverse(perm); //System.out.println("perm_rev = " + perm); return perm; } /** * Index of s in A. * @param s search string * @param A string array * @return i if s == A[i] for some i, else -1. */ public static int indexOf(String s, String[] A) { for (int i = 0; i < A.length; i++) { if (s.equals(A[i])) { return i; } } return -1; } /** * Partial permutation for specific variables. Computes a permutation perm * for the variables vars, such that perm(vars) == pvars ... (vars \ pvars). * Uses internal (reversed) variable sorting. * @param vars names for all variables. * @param pvars names for main variables, pvars subseteq vars. * @param rvars names for remaining variables, rvars eq { vars \ pvars }. * @return permutation for vars, such that perm(vars) == (pvars, {vars \ * pvars}). */ public static List partialPermutation(String[] vars, String[] pvars, String[] rvars) { if (vars == null || pvars == null) { throw new IllegalArgumentException("no variable names found"); } List variables = new ArrayList(vars.length); List pvariables = new ArrayList(pvars.length); for (int i = 0; i < vars.length; i++) { variables.add(vars[i]); } for (int i = 0; i < pvars.length; i++) { pvariables.add(pvars[i]); } if (rvars == null) { rvars = remainingVars(vars, pvars); } List rvariables = new ArrayList(rvars.length); for (int i = 0; i < rvars.length; i++) { rvariables.add(rvars[i]); } if (rvars.length + pvars.length == vars.length) { //System.out.println("pvariables = " + pvariables); return getPermutation(vars, rvars); } logger.info("not implemented for {} != {} cup {}", variables, pvariables, rvariables); throw new UnsupportedOperationException("not implemented"); /* if (!variables.containsAll(pvariables) || !variables.containsAll(rvariables)) { throw new IllegalArgumentException("partial variables not contained in all variables "); } Collections.reverse(variables); Collections.reverse(pvariables); Collections.reverse(rvariables); System.out.println("variables = " + variables); System.out.println("pvariables = " + pvariables); System.out.println("rvariables = " + rvariables); List perm = new ArrayList(); List pv = new ArrayList(); for (String s : variables) { int j = pvariables.indexOf(s); if (j >= 0) { perm.add(j); } } int i = pvariables.size(); for (String s : variables) { if (!pvariables.contains(s)) { pv.add(i); } i++; } System.out.println("perm, 1 = " + perm); //System.out.println("pv = " + pv); // sort perm according to pvars int ps = perm.size(); // == pvars.length for (int k = 0; k < ps; k++) { for (int j = k + 1; j < ps; j++) { int kk = variables.indexOf(pvariables.get(k)); int jj = variables.indexOf(pvariables.get(j)); if (kk > jj) { // swap int t = perm.get(k); System.out.println("swap " + t + " with " + perm.get(j)); perm.set(k, perm.get(j)); perm.set(j, t); } } } //System.out.println("perm = " + perm); // sort pv according to rvars int rs = pv.size(); // == rvars.length for (int k = 0; k < rs; k++) { for (int j = k + 1; j < rs; j++) { int kk = variables.indexOf(rvariables.get(k)); int jj = variables.indexOf(rvariables.get(j)); if (kk > jj) { // swap int t = pv.get(k); //System.out.println("swap " + t + " with " + perm.get(j)); pv.set(k, pv.get(j)); pv.set(j, t); } } } //System.out.println("pv = " + pv); perm.addAll(pv); System.out.println("perm, 2 = " + perm); return perm; */ } /** * Partial permutation for specific variables. Computes a permutation perm * for the variables vars, such that perm(vars) == (evars, pvars, (vars \ { * evars, pvars }). Uses internal (reversed) variable sorting. * @param vars names for all variables. * @param evars names for elimination variables, evars subseteq vars. * @param pvars names for main variables, pvars subseteq vars. * @param rvars names for remaining variables, rvars eq {vars \ { evars, * pvars } }. * @return permutation for vars, such that perm(vars) == (evars,pvars, {vars * \ {evars,pvars}}. */ public static List partialPermutation(String[] vars, String[] evars, String[] pvars, String[] rvars) { if (vars == null || evars == null || pvars == null) { throw new IllegalArgumentException("not all variable names given"); } String[] uvars; if (rvars != null) { uvars = new String[pvars.length + rvars.length]; for (int i = 0; i < pvars.length; i++) { uvars[i] = pvars[i]; } for (int i = 0; i < rvars.length; i++) { uvars[pvars.length + i] = rvars[i]; } } else { uvars = pvars; } //System.out.println("uvars = " + Arrays.toString(uvars)); List perm = partialPermutation(vars, evars, uvars); return perm; } /** * Remaining variables vars \ pvars. Uses internal (reversed) variable * sorting, original order is preserved. * @param vars names for all variables. * @param pvars names for main variables, pvars subseteq vars. * @return remaining vars = (vars \ pvars). */ public static String[] remainingVars(String[] vars, String[] pvars) { if (vars == null || pvars == null) { throw new IllegalArgumentException("no variable names found"); } List variables = new ArrayList(vars.length); List pvariables = new ArrayList(pvars.length); for (int i = 0; i < vars.length; i++) { variables.add(vars[i]); } for (int i = 0; i < pvars.length; i++) { pvariables.add(pvars[i]); } if (!variables.containsAll(pvariables)) { throw new IllegalArgumentException("partial variables not contained in all variables "); } // variables.setMinus(pvariables) List rvariables = new ArrayList(variables); for (String s : pvariables) { rvariables.remove(s); } int cl = vars.length - pvars.length; String[] rvars = new String[cl]; int i = 0; for (String s : rvariables) { rvars[i++] = s; } return rvars; } /** * Partial recursive Groebner base for specific variables. Computes Groebner * base in K[vars \ pvars][pvars] with coefficients from K[vars \ pvars]. * @param F polynomial list. * @param pvars names for main variables of partial Groebner base * computation. * @return a container for a partial Groebner base of F wrt pvars. */ public OptimizedPolynomialList> partialGBrec(List> F, String[] pvars) { if (F == null || F.isEmpty()) { throw new IllegalArgumentException("empty F not allowed"); } GenPolynomialRing fac = F.get(0).ring; String[] vars = fac.getVars(); if (vars == null || pvars == null) { throw new IllegalArgumentException("not all variable names found"); } if (vars.length == pvars.length) { throw new IllegalArgumentException("use non recursive partialGB algorithm"); } // compute permutation (in reverse sorting) List perm = partialPermutation(vars, pvars); GenPolynomialRing pfac = fac.permutation(perm); logger.info("pfac = {}", pfac); List> ppolys = TermOrderOptimization. permutation(perm, pfac, F); //System.out.println("ppolys = " + ppolys); int cl = fac.nvar - pvars.length; // > 0 int pl = pvars.length; String[] rvars = remainingVars(vars, pvars); GenPolynomialRing cfac = new GenPolynomialRing(fac.coFac, cl, fac.tord, rvars); //System.out.println("cfac = " + cfac); GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, pl, fac.tord, pvars); logger.info("rfac = {}", rfac); //System.out.println("rfac = " + rfac); List>> Fr = PolyUtil. recursive(rfac, ppolys); //System.out.println("\nFr = " + Fr); if (true) { rbb = new GroebnerBasePseudoRecSeq(cfac); } List>> Gr = rbb.GB(Fr); //System.out.println("\nGr = " + Gr); //perm = perm.subList(0,pl); OptimizedPolynomialList> pgb = new OptimizedPolynomialList>(perm, rfac, Gr); return pgb; } /** * Partial Groebner base for specific variables. Computes Groebner base in * K[vars \ pvars][pvars] with coefficients from K[vars \ pvars] but returns * polynomials in K[vars \ pvars, pvars]. * @param F polynomial list. * @param pvars names for main variables of partial Groebner base * computation. * @return a container for a partial Groebner base of F wrt pvars. */ public OptimizedPolynomialList partialGB(List> F, String[] pvars) { if (F == null || F.isEmpty()) { throw new IllegalArgumentException("empty F not allowed"); } GenPolynomialRing fac = F.get(0).ring; String[] vars = fac.getVars(); // compute permutation (in reverse sorting) //String[] xvars = remainingVars(vars, pvars); //System.out.println("xvars = " + Arrays.toString(xvars)); List perm = partialPermutation(vars, pvars); //System.out.println("pGB, perm = " + perm); //System.out.println("pGB, perm,1 = " + getPermutation(vars, xvars)); GenPolynomialRing pfac = fac.permutation(perm); logger.info("pfac = {}", pfac); List> ppolys = TermOrderOptimization. permutation(perm, pfac, F); //System.out.println("ppolys = " + ppolys); int cl = fac.nvar - pvars.length; if (cl == 0) { // non recursive case //GroebnerBaseSeq bb = new GroebnerBaseSeq(); List> G = bb.GB(ppolys); OptimizedPolynomialList pgb = new OptimizedPolynomialList(perm, pfac, G); return pgb; } // recursive case int pl = pvars.length; String[] rvars = remainingVars(vars, pvars); GenPolynomialRing cfac = new GenPolynomialRing(fac.coFac, cl, fac.tord, rvars); //System.out.println("cfac = " + cfac); GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, pl, fac.tord, pvars); logger.info("rfac = {}", rfac); List>> Fr = PolyUtil. recursive(rfac, ppolys); //System.out.println("\nFr = " + Fr); if (true) { rbb = new GroebnerBasePseudoRecSeq(cfac); } List>> Gr = rbb.GB(Fr); //System.out.println("\nGr = " + Gr); List> G = PolyUtil. distribute(pfac, Gr); //System.out.println("\nG = " + G); OptimizedPolynomialList pgb = new OptimizedPolynomialList(perm, pfac, G); return pgb; } /** * Partial Groebner base for specific variables. Computes Groebner base with * coefficients from K[pvars] but returns polynomials in K[pvars, evars]. * @param F polynomial list. * @param evars names for upper main variables of partial Groebner base * computation. * @param pvars names for lower main variables of partial Groebner base * computation. * @return a container for a partial Groebner base of F wrt (pvars,evars). */ public OptimizedPolynomialList elimPartialGB(List> F, String[] evars, String[] pvars) { if (F == null || F.isEmpty()) { throw new IllegalArgumentException("empty F not allowed"); } GenPolynomialRing fac = F.get(0).ring; String[] vars = fac.getVars(); // compute permutation (in reverse sorting) //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("evars = " + Arrays.toString(evars)); //System.out.println("pvars = " + Arrays.toString(pvars)); List perm = partialPermutation(vars, evars, pvars); //System.out.println("perm = " + perm); GenPolynomialRing pfac = fac.permutation(perm); logger.info("pfac = {}", pfac); List> ppolys = TermOrderOptimization. permutation(perm, pfac, F); //System.out.println("ppolys = " + ppolys); int cl = fac.nvar - evars.length - pvars.length; if (cl == 0) { // non recursive case TermOrder to = pfac.tord; int ev = to.getEvord(); //ev = TermOrder.IGRLEX; TermOrder split = new TermOrder(ev, ev, pfac.nvar, evars.length); pfac = new GenPolynomialRing(pfac.coFac, pfac.nvar, split, pfac.getVars()); //logger.info("split = {}", split); logger.info("pfac = {}", pfac); List> Fs = new ArrayList>(ppolys.size()); for (GenPolynomial p : ppolys) { Fs.add(pfac.copy(p)); } List> G = bb.GB(Fs); OptimizedPolynomialList pgb = new OptimizedPolynomialList(perm, pfac, G); logger.info("pgb = {}", pgb); return pgb; } logger.warn("not meaningful for elimination {}", cl); // recursive case int pl = pvars.length + pvars.length; String[] rvars = remainingVars(vars, evars); rvars = remainingVars(rvars, pvars); String[] uvars = new String[evars.length + pvars.length]; for (int i = 0; i < pvars.length; i++) { uvars[i] = pvars[i]; } for (int i = 0; i < evars.length; i++) { uvars[pvars.length + i] = evars[i]; } GenPolynomialRing cfac = new GenPolynomialRing(fac.coFac, cl, fac.tord, rvars); //System.out.println("cfac = " + cfac); TermOrder to = pfac.tord; int ev = to.getEvord(); TermOrder split = new TermOrder(ev, ev, pl, evars.length); //GenPolynomialRing sfac = new GenPolynomialRing(pfac.coFac, pfac.nvar, split, pfac.getVars()); GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, pl, split, uvars); List>> Fr = PolyUtil. recursive(rfac, ppolys); logger.info("rfac = {}", rfac); logger.info("Fr = {}", Fr); if (true) { rbb = new GroebnerBasePseudoRecSeq(cfac); } List>> Gr = rbb.GB(Fr); //System.out.println("\nGr = " + Gr); List> G = PolyUtil. distribute(pfac, Gr); //System.out.println("\nG = " + G); OptimizedPolynomialList pgb = new OptimizedPolynomialList(perm, pfac, G); return pgb; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBasePseudoParallel.java000066400000000000000000000341421445075545500270100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.util.Terminator; /** * Groebner Base with pseudo reduction multi-threaded parallel algorithm. * Implements coefficient fraction free Groebner bases. * Coefficients can for example be integers or (commutative) univariate polynomials. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBasePseudoParallel> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBasePseudoParallel.class); private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final PseudoReduction red; /** * Coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. */ public GroebnerBasePseudoParallel(int threads, RingFactory rf) { this(threads, rf, new PseudoReductionPar()); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. */ public GroebnerBasePseudoParallel(int threads, RingFactory rf, PseudoReduction red) { this(threads, rf, red, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. * @param pool ExecutorService to use. */ public GroebnerBasePseudoParallel(int threads, RingFactory rf, PseudoReduction red, ExecutorService pool) { this(threads, rf, red, pool, new OrderedPairlist()); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param pl pair selection strategy */ public GroebnerBasePseudoParallel(int threads, RingFactory rf, PairList pl) { this(threads, rf, new PseudoReductionPar(), Executors.newFixedThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. * @param pool ExecutorService to use. * @param pl pair selection strategy */ public GroebnerBasePseudoParallel(int threads, RingFactory rf, PseudoReduction red, ExecutorService pool, PairList pl) { super(red, pl); if (!(red instanceof PseudoReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } this.red = red; cofac = rf; if (threads < 1) { threads = 1; } this.threads = threads; engine = GCDFactory. getImplementation(rf); //not used: engine = (GreatestCommonDivisorAbstract)GCDFactory.getProxy( rf ); this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("pool = {}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("pool = {}", pool); return s; } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = engine.basePrimitivePart(G); if ( G.size() <= 1 ) { return G; } GenPolynomialRing ring = G.get(0).ring; if ( ring.coFac.isField() ) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList pairlist = strategy.create( modv, ring ); pairlist.put(G); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); PseudoReducer R; for (int i = 0; i < threads; i++) { R = new PseudoReducer(fin, G, pairlist, engine); pool.execute(R); } fin.waitDone(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt before minimalGB"); } logger.debug("#parallel list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List> minimalGB(List> Gp) { List> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial a; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials @SuppressWarnings("unchecked") PseudoMiReducer[] mirs = (PseudoMiReducer[]) new PseudoMiReducer[G.size()]; int i = 0; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); List> R = new ArrayList>(G.size() + F.size()); R.addAll(G); R.addAll(F); // System.out.println("doing " + a.length()); mirs[i] = new PseudoMiReducer(R, a, engine); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } Collections.reverse(F); // undo reverse return F; } } /** * Pseudo GB Reducing worker threads. */ class PseudoReducer> implements Runnable { private final List> G; private final PairList pairlist; private final Terminator fin; private final PseudoReductionPar red; private final GreatestCommonDivisorAbstract engine; private static final Logger logger = LogManager.getLogger(PseudoReducer.class); private static final boolean debug = logger.isDebugEnabled(); PseudoReducer(Terminator fin, List> G, PairList L, GreatestCommonDivisorAbstract engine) { this.fin = fin; this.G = G; pairlist = L; red = new PseudoReductionPar(); this.engine = engine; fin.initIdle(1); } /** * to string */ @Override public String toString() { return "PseudoReducer"; } public void run() { Pair pair; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; GenPolynomial H; //boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || fin.hasJobs()) { while (!pairlist.hasNext()) { // wait //fin.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { break; } if (!fin.hasJobs()) { break; } } if (!pairlist.hasNext() && !fin.hasJobs()) { break; } fin.notIdle(); // before pairlist get pair = pairlist.removeNext(); if (Thread.currentThread().isInterrupted()) { fin.initIdle(1); throw new RuntimeException("interrupt after removeNext"); } if (pair == null) { fin.initIdle(1); continue; } pi = pair.pi; pj = pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); //mod reduction++; if (H.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = engine.basePrimitivePart(H); //H.monic(); H = H.abs(); // System.out.println("H = " + H); if (H.isONE()) { // putOne not required pairlist.put(H); synchronized (G) { G.clear(); G.add(H); } fin.allIdle(); return; } if (debug) { logger.debug("H = {}", H); } synchronized (G) { G.add(H); } pairlist.put(H); fin.initIdle(1); } fin.allIdle(); logger.info("terminated, done {} reductions", reduction); } } /** * Pseudo Reducing worker threads for minimal GB. */ class PseudoMiReducer> implements Runnable { private final List> G; private GenPolynomial H; private final PseudoReductionPar red; private final Semaphore done = new Semaphore(0); private final GreatestCommonDivisorAbstract engine; private static final Logger logger = LogManager.getLogger(PseudoMiReducer.class); private static final boolean debug = logger.isDebugEnabled(); PseudoMiReducer(List> G, GenPolynomial p, GreatestCommonDivisorAbstract engine) { this.G = G; this.engine = engine; H = p; red = new PseudoReductionPar(); } /** * to string */ @Override public String toString() { return "PseudoMiReducer"; } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { throw new RuntimeException("interrupt in getNF"); } return H; } public void run() { if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } try { H = red.normalform(G, H); //mod H = engine.basePrimitivePart(H); //H.monic(); H = H.abs(); done.release(); //done.V(); } catch (RuntimeException e) { Thread.currentThread().interrupt(); //throw new RuntimeException("interrupt in getNF"); } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBasePseudoRecParallel.java000066400000000000000000000421141445075545500274400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Semaphore; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.util.Terminator; /** * Groebner Base with recursive pseudo reduction multi-threaded parallel * algorithm. Implements coefficient fraction free Groebner bases. * Coefficients can for example be (commutative) multivariate polynomials. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBasePseudoRecParallel> extends GroebnerBaseAbstract> { private static final Logger logger = LogManager.getLogger(GroebnerBasePseudoRecParallel.class); private static final boolean debug = logger.isDebugEnabled(); /** * Number of threads to use. */ protected final int threads; /** * Pool of threads to use. */ protected transient final ExecutorService pool; /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final PseudoReduction redRec; /** * Pseudo reduction engine. */ protected final PseudoReduction> red; /** * Coefficient ring factory. */ protected final RingFactory> cofac; /** * Base coefficient ring factory. */ protected final RingFactory baseCofac; /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. */ public GroebnerBasePseudoRecParallel(int threads, RingFactory> rf) { this(threads, rf, new PseudoReductionPar>(), Executors.newFixedThreadPool(threads), new OrderedPairlist>(new GenPolynomialRing>(rf, 1))); // 1=hack } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. */ public GroebnerBasePseudoRecParallel(int threads, RingFactory> rf, PseudoReduction> red) { this(threads, rf, red, Executors.newFixedThreadPool(threads)); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. * @param pool ExecutorService to use. */ public GroebnerBasePseudoRecParallel(int threads, RingFactory> rf, PseudoReduction> red, ExecutorService pool) { this(threads, rf, red, pool, new OrderedPairlist>( new GenPolynomialRing>(rf, 1))); // 1=hack } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param pl pair selection strategy */ public GroebnerBasePseudoRecParallel(int threads, RingFactory> rf, PairList> pl) { this(threads, rf, new PseudoReductionPar>(), Executors.newFixedThreadPool(threads), pl); } /** * Constructor. * @param threads number of threads to use. * @param rf coefficient ring factory. Note: red must be an instance * of PseudoReductionPar. * @param red pseudo reduction engine. * @param pool ExecutorService to use. * @param pl pair selection strategy */ @SuppressWarnings("unchecked") public GroebnerBasePseudoRecParallel(int threads, RingFactory> rf, PseudoReduction> red, ExecutorService pool, PairList> pl) { super(red, pl); if (!(red instanceof PseudoReductionPar)) { logger.warn("parallel GB should use parallel aware reduction"); } this.red = red; this.redRec = (PseudoReduction) (PseudoReduction) red; cofac = rf; if (threads < 1) { threads = 1; } this.threads = threads; GenPolynomialRing rp = (GenPolynomialRing) cofac; baseCofac = rp.coFac; //engine = (GreatestCommonDivisorAbstract)GCDFactory.getImplementation( baseCofac ); //not used: engine = GCDFactory. getProxy(baseCofac); this.pool = pool; } /** * Cleanup and terminate ExecutorService. */ @Override public void terminate() { if (pool == null) { return; } pool.shutdown(); try { while (!pool.isTerminated()) { //logger.info("await"); boolean rest = pool.awaitTermination(1000L, TimeUnit.MILLISECONDS); } } catch (InterruptedException e) { e.printStackTrace(); } logger.info("pool = {}", pool); } /** * Cancel ExecutorService. */ @Override public int cancel() { if (pool == null) { return 0; } int s = pool.shutdownNow().size(); logger.info("pool = {}", pool); return s; } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List>> GB(int modv, List>> F) { List>> G = normalizeZerosOnes(F); G = engine.recursivePrimitivePart(G); if (G.size() <= 1) { return G; } GenPolynomialRing> ring = G.get(0).ring; if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList> pairlist = strategy.create(modv, ring); pairlist.put(G); logger.info("start {}", pairlist); Terminator fin = new Terminator(threads); PseudoReducerRec R; for (int i = 0; i < threads; i++) { R = new PseudoReducerRec(fin, G, pairlist, engine); pool.execute(R); } fin.waitDone(); if (Thread.currentThread().isInterrupted()) { throw new RuntimeException("interrupt before minimalGB"); } logger.debug("#parallel list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List>> minimalGB(List>> Gp) { List>> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial> a; List>> F; F = new ArrayList>>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List>> ff; ff = new ArrayList>>(G); ff.addAll(F); //a = red.normalform(ff, a); a = redRec.normalformRecursive(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials @SuppressWarnings("unchecked") PseudoMiReducerRec[] mirs = (PseudoMiReducerRec[]) new PseudoMiReducerRec[G.size()]; int i = 0; F = new ArrayList>>(G.size()); while (G.size() > 0) { a = G.remove(0); List>> R = new ArrayList>>(G.size() + F.size()); R.addAll(G); R.addAll(F); // System.out.println("doing " + a.length()); mirs[i] = new PseudoMiReducerRec(R, a, engine); pool.execute(mirs[i]); i++; F.add(a); } G = F; F = new ArrayList>>(G.size()); for (i = 0; i < mirs.length; i++) { a = mirs[i].getNF(); F.add(a); } Collections.reverse(F); // undo reverse return F; } /** * Groebner base simple test. * @param modv module variable number. * @param F recursive polynomial list. * @return true, if F is a Groebner base, else false. */ @Override public boolean isGBsimple(int modv, List>> F) { if (F == null || F.isEmpty()) { return true; } GenPolynomial> pi, pj, s, h; ExpVector ei, ej, eij; for (int i = 0; i < F.size(); i++) { pi = F.get(i); ei = pi.leadingExpVector(); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); ej = pj.leadingExpVector(); if (!red.moduleCriterion(modv, ei, ej)) { continue; } eij = ei.lcm(ej); if (!red.criterion4(ei, ej, eij)) { continue; } //if (!criterion3(i, j, eij, F)) { // continue; //} s = red.SPolynomial(pi, pj); if (s.isZERO()) { continue; } //System.out.println("i, j = " + i + ", " + j); h = redRec.normalformRecursive(F, s); if (!h.isZERO()) { logger.info("no GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } } return true; } } /** * Pseudo GB Reducing worker threads. */ class PseudoReducerRec> implements Runnable { private final List>> G; private final PairList> pairlist; private final Terminator fin; private final PseudoReductionPar> red; private final PseudoReductionPar redRec; private final GreatestCommonDivisorAbstract engine; private static final Logger logger = LogManager.getLogger(PseudoReducerRec.class); PseudoReducerRec(Terminator fin, List>> G, PairList> L, GreatestCommonDivisorAbstract engine) { this.fin = fin; this.G = G; pairlist = L; red = new PseudoReductionPar>(); redRec = new PseudoReductionPar(); this.engine = engine; fin.initIdle(1); } /** * to string */ @Override public String toString() { return "PseudoReducer"; } public void run() { Pair> pair; GenPolynomial> pi, pj, S, H; //boolean set = false; int reduction = 0; int sleeps = 0; while (pairlist.hasNext() || fin.hasJobs()) { while (!pairlist.hasNext()) { // wait //fin.beIdle(); set = true; try { sleeps++; if (sleeps % 10 == 0) { logger.info(" reducer is sleeping"); } else { logger.debug("r"); } Thread.sleep(100); } catch (InterruptedException e) { break; } if (!fin.hasJobs()) { break; } } if (!pairlist.hasNext() && !fin.hasJobs()) { break; } fin.notIdle(); // before pairlist get pair = pairlist.removeNext(); if (Thread.currentThread().isInterrupted()) { fin.initIdle(1); throw new RuntimeException("interrupt after removeNext"); } if (pair == null) { fin.initIdle(1); continue; } pi = pair.pi; pj = pair.pj; logger.debug("pi = {}, pj = {}", pi, pj); S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } logger.debug("ht(S) = {}", S.leadingExpVector()); //H = red.normalform(G, S); //mod H = redRec.normalformRecursive(G, S); reduction++; if (H.isZERO()) { pair.setZero(); fin.initIdle(1); continue; } if (logger.isDebugEnabled()) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = engine.recursivePrimitivePart(H); //H.monic(); H = H.abs(); // System.out.println("H = " + H); if (H.isONE()) { // putOne not required pairlist.put(H); synchronized (G) { G.clear(); G.add(H); } fin.allIdle(); return; } logger.debug("H = {}", H); synchronized (G) { G.add(H); } pairlist.put(H); fin.initIdle(1); } fin.allIdle(); logger.info("terminated, done {} reductions", reduction); } } /** * Pseudo Reducing worker threads for minimal GB. */ class PseudoMiReducerRec> implements Runnable { private final List>> G; private GenPolynomial> H; //private final PseudoReductionPar> red; private final PseudoReductionPar redRec; private final Semaphore done = new Semaphore(0); private final GreatestCommonDivisorAbstract engine; private static final Logger logger = LogManager.getLogger(PseudoMiReducerRec.class); PseudoMiReducerRec(List>> G, GenPolynomial> p, GreatestCommonDivisorAbstract engine) { this.G = G; this.engine = engine; H = p; //red = new PseudoReductionPar>(); redRec = new PseudoReductionPar(); } /** * to string */ @Override public String toString() { return "PseudoMiReducerRec"; } /** * getNF. Blocks until the normal form is computed. * @return the computed normal form. */ public GenPolynomial> getNF() { try { done.acquire(); //done.P(); } catch (InterruptedException e) { throw new RuntimeException("interrupt in getNF"); } return H; } public void run() { logger.debug("ht(H) = {}", H.leadingExpVector()); try { //H = red.normalform(G, H); //mod H = redRec.normalformRecursive(G, H); H = engine.recursivePrimitivePart(H); //H.monic(); H = H.abs(); done.release(); //done.V(); } catch (RuntimeException e) { Thread.currentThread().interrupt(); //throw new RuntimeException("interrupt in getNF"); } logger.debug("ht(H) = {}", H.leadingExpVector()); // H = H.monic(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBasePseudoRecSeq.java000066400000000000000000000216171445075545500264410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Groebner Base with pseudo reduction sequential algorithm for integral * function coefficients. Implements polynomial fraction free coefficients * Groebner bases. Coefficients can for example be * (commutative) multivariate polynomials. * @param base coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBasePseudoRecSeq> extends GroebnerBaseAbstract> { private static final Logger logger = LogManager.getLogger(GroebnerBasePseudoRecSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final PseudoReduction redRec; /** * Pseudo reduction engine. */ protected final PseudoReduction> red; /** * Coefficient ring factory. */ protected final RingFactory> cofac; /** * Base coefficient ring factory. */ protected final RingFactory baseCofac; /** * Constructor. * @param rf coefficient ring factory. */ public GroebnerBasePseudoRecSeq(RingFactory> rf) { this(new PseudoReductionSeq>(), rf, new OrderedPairlist>( new GenPolynomialRing>(rf, 1))); // 1=hack } /** * Constructor. * @param rf coefficient ring factory. * @param pl pair selection strategy */ public GroebnerBasePseudoRecSeq(RingFactory> rf, PairList> pl) { this(new PseudoReductionSeq>(), rf, pl); } /** * Constructor. * @param red pseudo reduction engine. Note: red must be an instance * of PseudoReductionSeq. * @param rf coefficient ring factory. * @param pl pair selection strategy */ @SuppressWarnings("unchecked") public GroebnerBasePseudoRecSeq(PseudoReduction> red, RingFactory> rf, PairList> pl) { super(red, pl); this.red = red; this.redRec = (PseudoReduction) (PseudoReduction) red; cofac = rf; GenPolynomialRing rp = (GenPolynomialRing) cofac; baseCofac = rp.coFac; //engine = (GreatestCommonDivisorAbstract)GCDFactory.getImplementation( baseCofac ); //not used: engine = GCDFactory. getProxy(baseCofac); } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ //@Override public List>> GB(int modv, List>> F) { List>> G = normalizeZerosOnes(F); G = engine.recursivePrimitivePart(G); if (G.size() <= 1) { return G; } GenPolynomialRing> ring = G.get(0).ring; if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList> pairlist = strategy.create(modv, ring); pairlist.put(G); Pair> pair; GenPolynomial> pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) continue; pi = pair.pi; pj = pair.pj; logger.debug("pi = {}, pj = {}", pi, pj); S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", S.leadingExpVector()); } H = redRec.normalformRecursive(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = engine.recursivePrimitivePart(H); H = H.abs(); if (H.isConstant()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.debug("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List>> minimalGB(List>> Gp) { List>> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial> a; List>> F; F = new ArrayList>>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List>> ff; ff = new ArrayList>>(G); ff.addAll(F); a = redRec.normalformRecursive(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int i = 0; while (i < len) { a = G.remove(0); //System.out.println("doing " + a.length()); a = redRec.normalformRecursive(G, a); a = engine.recursivePrimitivePart(a); //a.monic(); was not required a = a.abs(); //a = redRec.normalformRecursive( F, a ); G.add(a); // adds as last i++; } Collections.reverse(G); // undo reverse return G; } /** * Groebner base simple test. * @param modv module variable number. * @param F recursive polynomial list. * @return true, if F is a Groebner base, else false. */ @Override public boolean isGBsimple(int modv, List>> F) { if (F == null || F.isEmpty()) { return true; } GenPolynomial> pi, pj, s, h; ExpVector ei, ej, eij; for (int i = 0; i < F.size(); i++) { pi = F.get(i); ei = pi.leadingExpVector(); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); ej = pj.leadingExpVector(); if (!red.moduleCriterion(modv, ei, ej)) { continue; } eij = ei.lcm(ej); if (!red.criterion4(ei, ej, eij)) { continue; } //if (!criterion3(i, j, eij, F)) { // continue; //} s = red.SPolynomial(pi, pj); if (s.isZERO()) { continue; } //System.out.println("i, j = " + i + ", " + j); h = redRec.normalformRecursive(F, s); if (!h.isZERO()) { logger.info("no GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBasePseudoSeq.java000066400000000000000000000144541445075545500260100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Groebner Base with pseudo reduction sequential algorithm. Implements * coefficient fraction free Groebner bases. * Coefficients can for example be integers or (commutative) univariate polynomials. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBasePseudoSeq> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBasePseudoSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final PseudoReduction red; /** * Coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param rf coefficient ring factory. */ public GroebnerBasePseudoSeq(RingFactory rf) { this(new PseudoReductionSeq(), rf, new OrderedPairlist()); } /** * Constructor. * @param rf coefficient ring factory. * @param pl pair selection strategy */ public GroebnerBasePseudoSeq(RingFactory rf, PairList pl) { this(new PseudoReductionSeq(), rf, pl); } /** * Constructor. * @param red pseudo reduction engine. Note: red must be an instance * of PseudoReductionSeq. * @param rf coefficient ring factory. * @param pl pair selection strategy */ public GroebnerBasePseudoSeq(PseudoReduction red, RingFactory rf, PairList pl) { super(red, pl); this.red = red; cofac = rf; engine = GCDFactory. getImplementation(rf); //not used: engine = (GreatestCommonDivisorAbstract)GCDFactory.getProxy( rf ); } /** * Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = engine.basePrimitivePart(G); if (G.size() <= 1) { return G; } GenPolynomialRing ring = G.get(0).ring; if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(G); Pair pair; GenPolynomial pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) continue; pi = pair.pi; pj = pair.pj; logger.debug("pi = {}, pj = {}", pi, pj); S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.debug("ht(S) = {}", S.leadingExpVector()); } H = red.normalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.debug("ht(H) = {}", H.leadingExpVector()); } H = engine.basePrimitivePart(H); H = H.abs(); if (H.isConstant()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.debug("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List> minimalGB(List> Gp) { List> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial a; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int i = 0; while (i < len) { a = G.remove(0); //System.out.println("doing " + a.length()); a = red.normalform(G, a); a = engine.basePrimitivePart(a); //a.monic(); not possible a = a.abs(); //a = red.normalform( F, a ); G.add(a); // adds as last i++; } Collections.reverse(G); // undo reverse return G; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBaseQuotient.java000066400000000000000000000144501445075545500257040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.PairList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Groebner Base sequential algorithm for rational function coefficients, * fraction free computation. Implements Groebner bases. * @param Quotient coefficient type * @author Heinz Kredel */ public class GroebnerBaseQuotient> extends GroebnerBaseAbstract> { private static final Logger logger = LogManager.getLogger(GroebnerBaseQuotient.class); private static final boolean debug = logger.isDebugEnabled(); public final GroebnerBaseAbstract> bba; /** * Constructor. * @param rf quotient coefficient ring factory. */ public GroebnerBaseQuotient(QuotientRing rf) { this(new GroebnerBasePseudoRecSeq(rf.ring)); } /** * Constructor. * @param threads the number of parallel threads. * @param rf quotient coefficient ring factory. */ public GroebnerBaseQuotient(int threads, QuotientRing rf) { this(new GroebnerBasePseudoRecParallel(threads, rf.ring)); } /** * Constructor. * @param rf quotient coefficient ring factory. * @param pl pair selection strategy (for fraction parts). */ public GroebnerBaseQuotient(QuotientRing rf, PairList> pl) { this(new GroebnerBasePseudoRecSeq(rf.ring, pl)); } /** * Constructor. * @param threads the number of parallel threads. * @param rf quotient coefficient ring factory. * @param pl pair selection strategy (for fraction parts). */ public GroebnerBaseQuotient(int threads, QuotientRing rf, PairList> pl) { this(new GroebnerBasePseudoRecParallel(threads, rf.ring, pl)); } /** * Constructor. * @param bba Groebner base algorithm for GenPolynomial coefficients. */ public GroebnerBaseQuotient(GroebnerBaseAbstract> bba) { super(); this.bba = bba; } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName() + "(" + bba.toString() + ")"; } /** * Groebner base using fraction free computation. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List>> GB(int modv, List>> F) { List>> G = F; if (F == null || F.isEmpty()) { return G; } GenPolynomialRing> rring = F.get(0).ring; QuotientRing cf = (QuotientRing) rring.coFac; GenPolynomialRing> iring = new GenPolynomialRing>(cf.ring, rring); List>> Fi = PolyUfdUtil. integralFromQuotientCoefficients(iring, F); //System.out.println("Fi = " + Fi); logger.info("#Fi = {}", Fi.size()); List>> Gi = bba.GB(modv, Fi); //System.out.println("Gi = " + Gi); logger.info("#Gi = {}", Gi.size()); G = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Gi); G = PolyUtil.> monic(G); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List>> minimalGB(List>> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List>> G = new ArrayList>>(Gp.size()); for (GenPolynomial> a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial> a; List>> F; F = new ArrayList>>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List>> ff; ff = new ArrayList>>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } // reduce remaining polynomials GenPolynomialRing> rring = G.get(0).ring; QuotientRing cf = (QuotientRing) rring.coFac; GenPolynomialRing> iring = new GenPolynomialRing>(cf.ring, rring); List>> Fi = PolyUfdUtil.integralFromQuotientCoefficients(iring, F); logger.info("#Fi = {}", Fi.size()); List>> Gi = bba.minimalGB(Fi); logger.info("#Gi = {}", Gi.size()); G = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Gi); G = PolyUtil.> monic(G); return G; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { bba.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { return bba.cancel(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBaseRational.java000066400000000000000000000135071445075545500256470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.PairList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; /** * Groebner Base sequential algorithm for rational coefficients, fraction free * computation. Implements Groebner bases. * @param BigRational coefficient type * @author Heinz Kredel */ public class GroebnerBaseRational extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseRational.class); private static final boolean debug = logger.isDebugEnabled(); public final GroebnerBaseAbstract bba; /** * Constructor. */ public GroebnerBaseRational() { this(new GroebnerBasePseudoSeq(new BigInteger())); } /** * Constructor. * @param threads the number of parallel threads. */ public GroebnerBaseRational(int threads) { this(new GroebnerBasePseudoParallel(threads, new BigInteger())); } /** * Constructor. * @param pl pair selection strategy */ public GroebnerBaseRational(PairList pl) { this(new GroebnerBasePseudoSeq(new BigInteger(), pl)); } /** * Constructor. * @param threads the number of parallel threads. * @param pl pair selection strategy */ public GroebnerBaseRational(int threads, PairList pl) { this(new GroebnerBasePseudoParallel(threads, new BigInteger(), pl)); } /** * Constructor. * @param bba Groebner base algorithm for BigInteger coefficients. */ public GroebnerBaseRational(GroebnerBaseAbstract bba) { super(); this.bba = bba; } /** * Get the String representation with GB engines. * @see java.lang.Object#toString() */ @Override public String toString() { return this.getClass().getSimpleName() + "(" + bba.toString() + ")"; } /** * Groebner base using fraction free computation. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List> GB(int modv, List> F) { List> G = F; if (F == null || F.isEmpty()) { return G; } GenPolynomialRing rring = F.get(0).ring; BigInteger cf = new BigInteger(); GenPolynomialRing iring = new GenPolynomialRing(cf, rring); List> Fi = PolyUtil.integerFromRationalCoefficients(iring, F); //System.out.println("Fi = " + Fi); logger.info("#Fi = {}", Fi.size()); List> Gi = bba.GB(modv, Fi); //System.out.println("Gi = " + Gi); logger.info("#Gi = {}", Gi.size()); G = PolyUtil. fromIntegerCoefficients(rring, Gi); G = PolyUtil. monic(G); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List> minimalGB(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible polynomials GenPolynomial a; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } // reduce remaining polynomials GenPolynomialRing rring = G.get(0).ring; BigInteger cf = new BigInteger(); GenPolynomialRing iring = new GenPolynomialRing(cf, rring); List> Fi = PolyUtil.integerFromRationalCoefficients(iring, F); logger.info("#Fi = {}", Fi.size()); List> Gi = bba.minimalGB(Fi); logger.info("#Gi = {}", Gi.size()); G = PolyUtil. fromIntegerCoefficients(rring, Gi); G = PolyUtil. monic(G); return G; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { bba.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { return bba.cancel(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/GroebnerBaseWalk.java000066400000000000000000000402721445075545500247730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.SortedSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.ReductionAbstract; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Groebner Base sequential Groebner Walk algorithm. Implements Groebner base * computation via Groebner Walk algorithm. See "The generic Groebner walk" by * Fukuda, Jensen, Lauritzen, Thomas, 2005. * * The start term order t1 can be set by a constructor. The target term order t2 * is taken from the input polynomials term order. * * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class GroebnerBaseWalk> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(GroebnerBaseWalk.class); private static final boolean debug = logger.isDebugEnabled(); /** * The backing GB algorithm implementation. */ protected GroebnerBaseAbstract sgb; /** * The start term order t1. */ //protected TermOrder startTO = TermOrderByName.IGRLEX.blockOrder(2); protected TermOrder startTO = TermOrderByName.IGRLEX; /** * Print intermediate GB after this number of iterations. */ int iterPrint = 100; /** * Constructor. */ public GroebnerBaseWalk() { super(); sgb = null; } /** * Constructor. * @param coFac coefficient ring of polynomial ring. */ public GroebnerBaseWalk(RingFactory coFac) { this(GBFactory. getImplementation(coFac)); } /** * Constructor. * @param coFac coefficient ring of polynomial ring. * @param t1 start term order. */ public GroebnerBaseWalk(RingFactory coFac, TermOrder t1) { this(GBFactory. getImplementation(coFac), t1); } /** * Constructor. * @param gb backing GB algorithm. */ public GroebnerBaseWalk(GroebnerBaseAbstract gb) { super(gb.red, gb.strategy); sgb = gb; } /** * Constructor. * @param gb backing GB algorithm. * @param t1 start term order. */ public GroebnerBaseWalk(GroebnerBaseAbstract gb, TermOrder t1) { this(gb); startTO = t1; } /** * Get the String representation with GB engine. * @see java.lang.Object#toString() */ @Override public String toString() { if (sgb == null) { return "GroebnerBaseWalk(" + startTO.toScript() + ")"; } return "GroebnerBaseWalk( " + sgb.toString() + ", " + startTO.toScript() + " )"; } /** * Groebner base using Groebner Walk algorithm. * @param modv module variable number. * @param F polynomial list in target term order. * @return GB(F) a INVLEX / target term order Groebner base of F. */ public List> GB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolyUtil. monic(G); if (G == null || G.size() == 0) { return G; } GenPolynomialRing pfac = G.get(0).ring; if (!pfac.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field: " + pfac.coFac); } if (G.size() <= 1) { GenPolynomial p = pfac.copy(G.get(0)); // change term order G.clear(); G.add(p); return G; } // compute in graded / start term order TermOrder grord = startTO; //new TermOrder(TermOrder.IGRLEX); GenPolynomialRing gfac = new GenPolynomialRing(pfac, grord); if (debug) { logger.info("gfac = {}", gfac); //.toScript() } List> Fp = gfac.copy(F); logger.info("Term order: graded = {}, target = {}", grord, pfac.tord); // compute graded / start term order Groebner base if (sgb == null) { sgb = GBFactory. getImplementation(pfac.coFac, strategy); } List> Gp = sgb.GB(modv, Fp); logger.info("graded / start GB = {}", Gp); if (grord.equals(pfac.tord)) { return Gp; } if (Gp.size() == 1) { // also dimension -1 GenPolynomial p = pfac.copy(Gp.get(0)); // change term order G.clear(); G.add(p); return G; } // info on FGLM int z = commonZeroTest(Gp); if (z == 0) { logger.info("ideal zero dimensional, can use also FGLM algorithm"); } // compute target term order Groebner base via Groebner Walk G = walkGroebnerToTarget(modv, Gp, pfac); return G; } /** * Converts Groebner bases w.r.t. total degree / start term order to * Groebner base w.r.t to inverse lexicographical / target term order. * @param modv module variable number. * @param Gl Groebner base with respect to graded / start term order. * @param ufac target polynomial ring and term order. * @return Groebner base w.r.t inverse lexicographical / target term order */ public List> walkGroebnerToTarget(int modv, List> Gl, GenPolynomialRing ufac) { if (Gl == null || Gl.size() == 0) { throw new IllegalArgumentException("G may not be null or empty"); } //Polynomial ring of input Groebner basis Gl GenPolynomialRing ring = Gl.get(0).ring; if (debug) { logger.info("ring = {}", ring); //.toScript() } //Polynomial ring of newGB with INVLEX / target term order //TermOrder lexi = ufac.tord; //new TermOrder(TermOrder.INVLEX); logger.info("G walk from ev1 = {} to ev2 = {}", ring.tord.toScript(), ufac.tord.toScript()); List> Giter = Gl; // determine initial marks List marks = new ArrayList(); List> M = new ArrayList>(); for (GenPolynomial p : Giter) { marks.add(p.leadingExpVector()); M.add(new Monomial(p.leadingMonomial())); } logger.info("marks = {}", marks); List> Mp = new ArrayList>(M); // weight matrix for target term order long[][] ufweight = TermOrderByName.weightForOrder(ufac.tord, ring.nvar); //TermOrder word = TermOrder.reverseWeight(ufweight); TermOrder word = new TermOrder(ufweight); logger.info("weight order: {}", word); ufweight = word.getWeight(); // because of weightDeg usage // loop through term orders ExpVector w = null; int iter = 0; // count #loops boolean done = false; while (!done) { iter++; // determine V and w PolynomialList Pl = new PolynomialList(ring, Giter); SortedSet delta = Pl.deltaExpVectors(marks); //logger.info("delta(marks) = {}", delta); logger.info("w_old = {}", w); ExpVector v = facetNormal(ring.tord, ufac.tord, delta, ring.evzero, ufweight); logger.info("minimal v = {}", v); if (v == null) { done = true; break; // finished } w = v; // determine facet polynomials for w List> iG = new ArrayList>(); int i = 0; for (GenPolynomial f : Giter) { ExpVector h = marks.get(i++); GenPolynomial ing = f.leadingFacetPolynomial(h, w); if (debug) { logger.info("ing_g = [{}], lt(ing) = {}, f = {}", ing, ing.ring.toScript(ing.leadingExpVector()), f.ring.toScript(f.leadingExpVector())); } iG.add(ing); } List> inOmega = ufac.copy(iG); if (debug) { logger.info("inOmega = {}", inOmega); logger.info("inOmega.ring: {}", inOmega.get(0).ring.toScript()); } // INVLEX / target term order GB of inOmega List> inOG = sgb.GB(modv, inOmega); if (debug) { logger.info("GB(inOmega) = {}", inOG); } // remark polynomials marks.clear(); M.clear(); for (GenPolynomial p : inOG) { marks.add(p.leadingExpVector()); M.add(new Monomial(p.leadingMonomial())); } logger.info("new marks/M = {}", marks); // lift and reduce List> G = liftReductas(M, Mp, Giter, inOG); if (debug || (iter % iterPrint == 0)) { logger.info("lift({}) inOG, new GB: {}", iter, G); } if (G.size() == 1) { // will not happen GenPolynomial p = ufac.copy(G.get(0)); // change term order G.clear(); G.add(p); return G; } // iterate Giter = G; Mp.clear(); Mp.addAll(M); } return Giter; } /** * Determine new facet normal. * @param t1 old term order. * @param t2 new term order. * @param delta exponent vectors deltas. * @param zero exponent vector. * @param t2weight weight representation of t2. * @return new facet normal v or null if no new facet normal exists. */ public ExpVector facetNormal(TermOrder t1, TermOrder t2, Set delta, ExpVector zero, long[][] t2weight) { TermOrder.EVComparator ev1 = t1.getAscendComparator(); TermOrder.EVComparator ev2 = t2.getAscendComparator(); ExpVector v = null; long d = 0; // = Long.MIN_VALUE; for (ExpVector e : delta) { if (ev1.compare(zero, e) >= 0 || ev2.compare(zero, e) <= 0) { //ring.evzero //logger.info("skip e = {}", e); continue; } int s = 0; long d2 = 0; ExpVector vt = null; ExpVector et = null; if (v == null) { v = e; logger.info("init v = {}", v); continue; } for (long[] tau : t2weight) { //logger.info("current tau = {}", Arrays.toString(tau)); //compare d = v.weightDeg(tau); d2 = e.weightDeg(tau); vt = v.scalarMultiply(d2); et = e.scalarMultiply(d); s = ev1.compare(et, vt); if (s == 0) { continue; // next tau } else if (s > 0) { // <, (> by example) v = e; break; } else { break; } } //logger.info("step s = {}, d = {}, d2 = {}, e = {}, v = {}, et = {}, vt = {}", s, d, d2, e, // v, et, vt); } return v; } /** * Cleanup and terminate ThreadPool. */ @Override public void terminate() { if (sgb == null) { return; } sgb.terminate(); } /** * Cancel ThreadPool. */ @Override public int cancel() { if (sgb == null) { return 0; } return sgb.cancel(); } /** * Lift leading polynomials to full Groebner base with respect to term * order. * @param M new leading monomial list of polynomials as marks. * @param Mp old leading monomial list of polynomials as marks. * @param G Groebner base polynomials for lift. * @param A polynomial list of leading omega polynomials to lift. * @return lift(A) a Groebner base wrt M of ideal(G). */ public List> liftReductas(List> M, List> Mp, List> G, List> A) { if (G == null || M == null || Mp == null || G.isEmpty()) { throw new IllegalArgumentException("null or empty lists not allowed"); } if (A == null || A.isEmpty()) { return A; } if (G.size() != Mp.size() || A.size() != M.size()) { throw new IllegalArgumentException("equal sized lists required"); } GenPolynomial pol = G.get(0); if (pol == null) { throw new IllegalArgumentException("null polynomial not allowed"); } // remove mark monomials List> Gp = new ArrayList>(G.size()); int i = 0; int len = G.size(); for (i = 0; i < len; i++) { Monomial mon = Mp.get(i); GenPolynomial s = G.get(i).subtract(mon); Gp.add(s); } if (debug) { logger.info("lifter GB: Gp = {}, Mp = {}", Gp, Mp); } // compute f^Gp for f in A //GenPolynomialRing oring = pol.ring; logger.info("liftReductas: G = {}, Mp = {}", G.size(), Mp.size()); // ", old = {}", oring.toScript()); List> Ap = A; //oring.copy(A); //logger.info("to lift Ap = {}", Ap); ReductionAbstract sred = (ReductionAbstract) sgb.red; //new ReductionSeq(); List> red = new ArrayList>(); GenPolynomialRing tring = A.get(0).ring; len = Ap.size(); for (i = 0; i < len; i++) { GenPolynomial a = Ap.get(i); GenPolynomial r = sred.normalformMarked(Mp, Gp, a); red.add(r); } logger.info("liftReductas: red(A) = {}", red.size()); // combine f - f^Gp in tring if (debug) { logger.info("tring = {}", tring); //.toScript() + ", M = {}", M); } List> nb = new ArrayList>(red.size()); for (i = 0; i < A.size(); i++) { GenPolynomial x = tring.copy(A.get(i)); // Ap? A! GenPolynomial r = tring.copy(red.get(i)); GenPolynomial s = x.subtract(r); Monomial m = M.get(i); s.doAddTo(m.coefficient().negate(), m.exponent()); // remove marked term if (!s.coefficient(m.exponent()).isZERO()) { System.out.println("L-M: x = " + x + ", r = " + r); throw new IllegalArgumentException("mark not removed: " + s + ", m = " + m); } nb.add(s); } if (debug) { logger.info("lifted-M, nb = {}", nb.size()); } // minimal GB with preserved marks //Collections.reverse(nb); // important for lex GB len = nb.size(); i = 0; while (i < len) { GenPolynomial a = nb.remove(0); Monomial m = M.remove(0); // in step with element from nb if (debug) { logger.info("doing {}, lt = {}", a, tring.toScript(m.exponent())); } //a = sgb.red.normalform(nb, a); a = sred.normalformMarked(M, nb, a); if (debug) { logger.info("done, a = {}, lt = {}", a, tring.toScript(a.leadingExpVector())); } nb.add(a); // adds as last M.add(m); i++; } // re-add mark after minimal for (i = 0; i < len; i++) { GenPolynomial a = nb.get(i); Monomial m = M.get(i); a.doAddTo(m.coefficient(), m.exponent()); // re-add marked term nb.set(i, a); } logger.info("liftReductas: nb = {}, M = {}", nb.size(), M.size()); //Collections.reverse(nb); // undo reverse return nb; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/MultiplicativeSet.java000066400000000000000000000174441445075545500252720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; /** * Multiplicative set of polynomials. a, b in M implies a*b in M, 1 in M. * @param coefficient type * @author Heinz Kredel */ public class MultiplicativeSet> implements Serializable { private static final Logger logger = LogManager.getLogger(MultiplicativeSet.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Data structure. */ public final List> mset; /** * Polynomial ring factory. */ public final GenPolynomialRing ring; /** * MultiplicativeSet constructor. Constructs an empty multiplicative set. * @param ring polynomial ring factory for coefficients. */ public MultiplicativeSet(GenPolynomialRing ring) { this(ring, new ArrayList>()); if (ring == null) { throw new IllegalArgumentException("only for non null rings"); } } /** * MultiplicativeSet constructor. * @param ring polynomial ring factory for coefficients. * @param ms a list of non-zero polynomials. */ protected MultiplicativeSet(GenPolynomialRing ring, List> ms) { if (ms == null || ring == null) { throw new IllegalArgumentException("only for non null parts"); } this.ring = ring; mset = ms; } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "MultiplicativeSet" + mset; } /** * Equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object ob) { MultiplicativeSet c = null; try { c = (MultiplicativeSet) ob; } catch (ClassCastException e) { return false; } if (c == null) { return false; } if (!ring.equals(c.ring)) { return false; } return mset.equals(c.mset); } /** * Hash code for this condition. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = h << 17; h += mset.hashCode(); return h; } /** * Is set. * @return true if this is the empty set, else false. */ public boolean isEmpty() { return mset.size() == 0; } /** * Test if a polynomial is contained in this multiplicative set. * @param c polynomial searched in mset. * @return true, if c = prod_{m in mset} m, else false */ public boolean contains(GenPolynomial c) { if (c == null || c.isZERO()) { return false; } if (c.isConstant()) { return true; } if (mset.isEmpty()) { return false; } GenPolynomial d = c; for (GenPolynomial n : mset) { // System.out.println("mset n = " + n); if (n.isONE()) { // do not use 1 continue; } GenPolynomial q, r; do { GenPolynomial[] qr = d.quotientRemainder(n); q = qr[0]; r = qr[1]; // System.out.println("q = " + q + ", r = " + r + ", d = " + d + // ", n = " + n); if (!r.isZERO()) { continue; } if (q.isConstant()) { return true; } d = q; } while (r.isZERO() && !d.isConstant()); } return d.isConstant(); // false } /** * Test if a list of polynomials is contained in multiplicative set. * @param L list of polynomials to be searched in mset. * @return true, if all c in L are in mset, else false */ public boolean contains(List> L) { if (L == null || L.size() == 0) { return true; } for (GenPolynomial c : L) { if (!contains(c)) { return false; } } return true; } /** * Add polynomial to mset. * @param cc polynomial to be added to mset. * @return new multiplicative set. Note: must be overridden in * sub-classes. */ public MultiplicativeSet add(GenPolynomial cc) { if (cc == null || cc.isZERO() || cc.isConstant()) { return this; } if (ring.coFac.isField()) { cc = cc.monic(); } List> list; if (mset.size() == 0) { list = new ArrayList>(1); list.add(cc); return new MultiplicativeSet(ring, list); } GenPolynomial c = removeFactors(cc); if (c.isConstant()) { logger.info("skipped unit or constant = {}", c); return this; } if (ring.coFac.isField()) { c = c.monic(); } if (mset.size() == 0) { logger.info("added to empty mset = {}", c); } else { logger.info("added to mset = {}", c); } list = new ArrayList>(mset); list.add(c); return new MultiplicativeSet(ring, list); } /** * Replace polynomial list of mset. * @param L polynomial list to replace mset. * @return new multiplicative set. Note: must be overridden in * sub-classes. */ public MultiplicativeSet replace(List> L) { MultiplicativeSet ms = new MultiplicativeSet(ring); if (L == null || L.size() == 0) { return ms; } for (GenPolynomial p : L) { ms = ms.add(p); } return ms; } /** * Remove factors by mset factors division. * @param cc polynomial to be removed factors from mset. * @return quotient polynomial. */ public GenPolynomial removeFactors(GenPolynomial cc) { if (cc == null || cc.isZERO() || cc.isConstant()) { return cc; } if (mset.size() == 0) { return cc; } GenPolynomial c = cc; for (GenPolynomial n : mset) { if (n.isConstant()) { // do not use 1, should not be in mset continue; } GenPolynomial q, r; do { GenPolynomial[] qr = c.quotientRemainder(n); q = qr[0]; r = qr[1]; if (!r.isZERO()) { continue; } if (q.isConstant()) { return q; } c = q; } while (r.isZERO() && !c.isConstant()); } return c; } /** * Remove factors by mset factors division. * @param L list of polynomial to be removed factors from mset. * @return quotient polynomial list. */ public List> removeFactors(List> L) { if (L == null || L.size() == 0) { return L; } if (mset.size() == 0) { return L; } List> M = new ArrayList>(L.size()); for (GenPolynomial p : L) { p = removeFactors(p); // nono, really: if ( !p.isConstant() ) { M.add(p); } return M; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/MultiplicativeSetCoPrime.java000066400000000000000000000074521445075545500265470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Multiplicative set of co-prime polynomials. a, b in M implies a*b in M, 1 in * M. * @param coefficient type * @author Heinz Kredel */ public class MultiplicativeSetCoPrime> extends MultiplicativeSet { private static final Logger logger = LogManager.getLogger(MultiplicativeSetCoPrime.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Gcd computation engine. */ protected final GreatestCommonDivisorAbstract engine; /** * MultiplicativeSet constructor. Constructs an empty multiplicative set. * @param ring polynomial ring factory for coefficients. */ public MultiplicativeSetCoPrime(GenPolynomialRing ring) { super(ring); engine = GCDFactory.getProxy(ring.coFac); } /** * MultiplicativeSet constructor. * @param ring polynomial ring factory for coefficients. * @param ms a list of non-zero polynomials. * @param eng gcd computation engine. */ protected MultiplicativeSetCoPrime(GenPolynomialRing ring, List> ms, GreatestCommonDivisorAbstract eng) { super(ring, ms); engine = eng; } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "MultiplicativeSetCoPrime" + mset; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof MultiplicativeSetCoPrime)) { return false; } return super.equals(B); } /** * Hash code for this multiplicative set. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Add polynomial to mset. * @param cc polynomial to be added to mset. * @return new multiplicative set. */ @Override public MultiplicativeSetCoPrime add(GenPolynomial cc) { if (cc == null || cc.isZERO() || cc.isConstant()) { return this; } if (ring.coFac.isField()) { cc = cc.monic(); } List> list; if (mset.size() == 0) { list = engine.coPrime(cc, mset); if (ring.coFac.isField()) { list = PolyUtil. monic(list); } return new MultiplicativeSetCoPrime(ring, list, engine); } GenPolynomial c = removeFactors(cc); if (c.isConstant()) { logger.info("skipped unit or constant = {}", c); return this; } logger.info("added to co-prime mset = {}", c); list = engine.coPrime(c, mset); if (ring.coFac.isField()) { list = PolyUtil. monic(list); } return new MultiplicativeSetCoPrime(ring, list, engine); } /** * Replace polynomial list of mset. * @param L polynomial list to replace mset. * @return new multiplicative set. */ @Override public MultiplicativeSetCoPrime replace(List> L) { MultiplicativeSetCoPrime ms = new MultiplicativeSetCoPrime(ring); if (L == null || L.size() == 0) { return ms; } for (GenPolynomial p : L) { ms = ms.add(p); } return ms; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/MultiplicativeSetFactors.java000066400000000000000000000075631445075545500266150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.FactorFactory; /** * Multiplicative set of irreducible polynomials. a, b in M implies a*b in M, 1 * in M. * @param coefficient type * @author Heinz Kredel */ public class MultiplicativeSetFactors> extends MultiplicativeSet { private static final Logger logger = LogManager.getLogger(MultiplicativeSetFactors.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Factors decomposition engine. */ protected final FactorAbstract engine; /** * MultiplicativeSet constructor. Constructs an empty multiplicative set. * @param ring polynomial ring factory for coefficients. */ public MultiplicativeSetFactors(GenPolynomialRing ring) { super(ring); engine = FactorFactory.getImplementation(ring.coFac); } /** * MultiplicativeSet constructor. * @param ring polynomial ring factory for coefficients. * @param ms a list of non-zero polynomials. * @param eng factorization engine. */ protected MultiplicativeSetFactors(GenPolynomialRing ring, List> ms, FactorAbstract eng) { super(ring, ms); engine = eng; } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "MultiplicativeSetFactors" + mset; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof MultiplicativeSetFactors)) { return false; } return super.equals(B); } /** * Hash code for this multiplicative set. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Add polynomial to mset. * @param cc polynomial to be added to mset. * @return new multiplicative set. */ @Override public MultiplicativeSetFactors add(GenPolynomial cc) { if (cc == null || cc.isZERO() || cc.isConstant()) { return this; } if (ring.coFac.isField()) { cc = cc.monic(); } GenPolynomial c = removeFactors(cc); if (c.isConstant()) { logger.info("skipped unit or constant = {}", c); return this; } List> list = engine.factorsRadical(c); logger.info("factorsRadical = {}", list); if (ring.coFac.isField()) { list = PolyUtil. monic(list); } List> ms = new ArrayList>(mset); for (GenPolynomial p : list) { if (!p.isConstant() && !p.isZERO()) { if (!mset.contains(p)) { logger.info("added to irreducible mset = {}", p); ms.add(p); } } } return new MultiplicativeSetFactors(ring, ms, engine); } /** * Replace polynomial list of mset. * @param L polynomial list to replace mset. * @return new multiplicative set. */ @Override public MultiplicativeSetFactors replace(List> L) { MultiplicativeSetFactors ms = new MultiplicativeSetFactors(ring); if (L == null || L.size() == 0) { return ms; } for (GenPolynomial p : L) { ms = ms.add(p); } return ms; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/MultiplicativeSetSquarefree.java000066400000000000000000000075721445075545500273160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Multiplicative set of squarefree and co-prime polynomials. a, b in M implies * a*b in M, 1 in M. * @param coefficient type * @author Heinz Kredel */ public class MultiplicativeSetSquarefree> extends MultiplicativeSet { private static final Logger logger = LogManager.getLogger(MultiplicativeSetSquarefree.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Squarefree decomposition engine. */ protected final SquarefreeAbstract engine; /** * MultiplicativeSet constructor. Constructs an empty multiplicative set. * @param ring polynomial ring factory for coefficients. */ public MultiplicativeSetSquarefree(GenPolynomialRing ring) { super(ring); engine = SquarefreeFactory.getImplementation(ring.coFac); } /** * MultiplicativeSet constructor. * @param ring polynomial ring factory for coefficients. * @param ms a list of non-zero polynomials. * @param eng squarefree factorization engine. */ protected MultiplicativeSetSquarefree(GenPolynomialRing ring, List> ms, SquarefreeAbstract eng) { super(ring, ms); engine = eng; } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "MultiplicativeSetSquarefree" + mset; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof MultiplicativeSetSquarefree)) { return false; } return super.equals(B); } /** * Hash code for this multiplicative set. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Add polynomial to mset. * @param cc polynomial to be added to mset. * @return new multiplicative set. */ @Override public MultiplicativeSetSquarefree add(GenPolynomial cc) { if (cc == null || cc.isZERO() || cc.isConstant()) { return this; } if (ring.coFac.isField()) { cc = cc.monic(); } List> list; if (mset.size() == 0) { list = engine.coPrimeSquarefree(cc, mset); if (ring.coFac.isField()) { list = PolyUtil. monic(list); } return new MultiplicativeSetSquarefree(ring, list, engine); } GenPolynomial c = removeFactors(cc); if (c.isConstant()) { logger.info("skipped unit or constant = {}", c); return this; } logger.info("added to squarefree mset = {}", c); list = engine.coPrimeSquarefree(c, mset); if (ring.coFac.isField()) { list = PolyUtil. monic(list); } return new MultiplicativeSetSquarefree(ring, list, engine); } /** * Replace polynomial list of mset. * @param L polynomial list to replace mset. * @return new multiplicative set. */ @Override public MultiplicativeSetSquarefree replace(List> L) { MultiplicativeSetSquarefree ms = new MultiplicativeSetSquarefree(ring); if (L == null || L.size() == 0) { return ms; } for (GenPolynomial p : L) { ms = ms.add(p); } return ms; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/OrderedRPairlist.java000066400000000000000000000113171445075545500250320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RegularRingElem; /** * Pair list management for R-Groebner bases. * Implemented using GenPolynomial, TreeMap and BitSet. * @author Heinz Kredel */ public class OrderedRPairlist > extends OrderedPairlist { private static final Logger logger = LogManager.getLogger(OrderedRPairlist.class); protected final RReduction rreduction; /** * Constructor for OrderedRPairlist. * @param r polynomial factory. */ public OrderedRPairlist(GenPolynomialRing r) { this(0,r); } /** * Constructor for OrderedRPairlist. * @param m number of module variables. * @param r polynomial factory. */ public OrderedRPairlist(int m, GenPolynomialRing r) { super(m,r); rreduction = new RReductionSeq(); } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-polynomial is required. * @return the next pair if one exists, otherwise null. */ @Override public synchronized Pair removeNext() { if ( oneInGB ) { return null; } Iterator< Map.Entry>> > ip = pairlist.entrySet().iterator(); Pair pair = null; boolean c = false; int i, j; if ( ip.hasNext() ) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); if ( logger.isInfoEnabled() ) { logger.info("g = {}", g); } pair = null; if ( xl.size() > 0 ) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); if ( useCriterion4 ) { c = rreduction.criterion4( pair.pi, pair.pj, g ); } else { c = true; } pair.setUseCriterion4(c); //System.out.println("c4 = " + c); if ( c ) { c = criterion3( i, j, g ); //System.out.println("c3 = " + c); pair.setUseCriterion3(c); } red.get( j ).clear(i); // set(i,false) jdk1.4 } if ( xl.size() == 0 ) { ip.remove(); // = pairlist.remove( g ); } } remCount++; // count pairs return pair; } /** * GB criterium 3. * @return true if the S-polynomial(i,j) is required. */ @Override public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s; s = red.get( j ).get(i); if ( ! s ) { logger.warn("c3.s false for {} {}", j, i); return s; } s = true; boolean m; GenPolynomial A; ExpVector ek; C ci = P.get(i).leadingBaseCoefficient(); C cj = P.get(j).leadingBaseCoefficient(); C c = ci.multiply(cj); // a guess C ck; for ( int k = 0; k < P.size(); k++ ) { A = P.get( k ); ek = A.leadingExpVector(); m = eij.multipleOf(ek); if ( m ) { ck = A.leadingBaseCoefficient(); C r = c.multiply(ck); // a guess m = r.isZERO(); } if ( m ) { if ( k < i ) { // System.out.println("k < i "+k+" "+i); s = red.get( i ).get(k) || red.get( j ).get(k); } if ( i < k && k < j ) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get( k ).get(i) || red.get( j ).get(k); } if ( j < k ) { //System.out.println("j < k "+j+" "+k); s = red.get( k ).get(i) || red.get( k ).get(j); } //System.out.println("s."+k+" = " + s); if ( ! s ) return s; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/PolyGBUtil.java000066400000000000000000000725751445075545500236230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableReductionAbstract; import edu.jas.gb.SolvableReductionSeq; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordGroebnerBaseSeq; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; /** * Package gbufd utilities. * @author Heinz Kredel */ public class PolyGBUtil { private static final Logger logger = LogManager.getLogger(PolyGBUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Test for resultant. * @param A generic polynomial. * @param B generic polynomial. * @param r generic polynomial. * @return true if res(A,B) isContained in ideal(A,B), else false. */ public static > boolean isResultant(GenPolynomial A, GenPolynomial B, GenPolynomial r) { if (r == null || r.isZERO()) { return true; } GroebnerBaseAbstract bb = GBFactory. getImplementation(r.ring.coFac); List> F = new ArrayList>(2); F.add(A); F.add(B); List> G = bb.GB(F); //System.out.println("G = " + G); GenPolynomial n = bb.red.normalform(G, r); //System.out.println("n = " + n); return n.isZERO(); } /** * Top pseudo reduction wrt the main variables. * @param P generic polynomial. * @param A list of generic polynomials sorted according to appearing main * variables. * @return top pseudo remainder of P wrt. A for the appearing variables. */ public static > GenPolynomial topPseudoRemainder(List> A, GenPolynomial P) { if (A == null || A.isEmpty()) { return P.monic(); } if (P.isZERO()) { return P; } //System.out.println("remainder, P = " + P); GenPolynomialRing pfac = A.get(0).ring; if (pfac.nvar <= 1) { // recursion base GenPolynomial R = PolyUtil. baseSparsePseudoRemainder(P, A.get(0)); return R.monic(); } // select polynomials according to the main variable GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial Q = A.get(0); // wrong, must eventually search polynomial GenPolynomial> qr = PolyUtil. recursive(rfac, Q); GenPolynomial> pr = PolyUtil. recursive(rfac, P); GenPolynomial> rr; if (qr.isONE()) { return P.ring.getZERO(); } if (qr.degree(0) > 0) { rr = PolyUtil. recursiveSparsePseudoRemainder(pr, qr); //System.out.println("remainder, pr = " + pr); //System.out.println("remainder, qr = " + qr); //System.out.println("remainder, rr = " + rr); } else { rr = pr; } if (rr.degree(0) > 0) { GenPolynomial R = PolyUtil. distribute(pfac, rr); return R.monic(); // not further reduced wrt. other variables = top-reduction only } List> zeroDeg = zeroDegrees(A); GenPolynomial R = topPseudoRemainder(zeroDeg, rr.leadingBaseCoefficient()); R = R.extend(pfac, 0, 0L); return R.monic(); } /** * Top coefficient pseudo remainder of the leading coefficient of P wrt A in * the main variables. * @param P generic polynomial in n+1 variables. * @param A list of generic polynomials in n variables sorted according to * appearing main variables. * @return pseudo remainder of the leading coefficient of P wrt A. */ public static > GenPolynomial topCoefficientPseudoRemainder( List> A, GenPolynomial P) { if (A == null || A.isEmpty()) { return P.monic(); } if (P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; GenPolynomialRing pfac1 = A.get(0).ring; if (pfac1.nvar <= 1) { // recursion base GenPolynomial a = A.get(0); GenPolynomialRing> rfac = pfac.recursive(pfac.nvar - 1); GenPolynomial> pr = PolyUtil. recursive(rfac, P); // ldcf(P,x_m) = q a + r GenPolynomial> rr = PolyGBUtil. coefficientPseudoRemainderBase(pr, a); GenPolynomial R = PolyUtil. distribute(pfac, rr); return R.monic(); } // select polynomials according to the main variable GenPolynomialRing> rfac1 = pfac1.recursive(1); int nv = pfac.nvar - pfac1.nvar; GenPolynomialRing> rfac = pfac.recursive(1 + nv); GenPolynomialRing>> rfac2 = rfac.recursive(nv); if (debug) { logger.info("rfac = {}", rfac); } GenPolynomial> pr = PolyUtil. recursive(rfac, P); GenPolynomial>> pr2 = PolyUtil.> recursive(rfac2, pr); //System.out.println("recursion, pr2 = " + pr2); GenPolynomial Q = A.get(0); GenPolynomial> qr = PolyUtil. recursive(rfac1, Q); GenPolynomial>> rr; if (qr.isONE()) { return P.ring.getZERO(); } if (qr.degree(0) > 0) { // pseudo remainder: ldcf(P,x_m) = a q + r rr = PolyGBUtil. coefficientPseudoRemainder(pr2, qr); //System.out.println("recursion, qr = " + qr); //System.out.println("recursion, pr = " + pr2); //System.out.println("recursion, rr = " + rr); } else { rr = pr2; } // reduction wrt. the other variables List> zeroDeg = zeroDegrees(A); GenPolynomial> Rr = PolyUtil.> distribute(rfac, rr); GenPolynomial R = PolyUtil. distribute(pfac, Rr); R = topCoefficientPseudoRemainder(zeroDeg, R); return R.monic(); } /** * Polynomial leading coefficient pseudo remainder. * @param P generic polynomial in n+1 variables. * @param A generic polynomial in n variables. * @return pseudo remainder of the leading coefficient of P wrt A, with * ldcf(A)m' P = quotient * A + remainder. */ public static > GenPolynomial>> coefficientPseudoRemainder( GenPolynomial>> P, GenPolynomial> A) { if (A == null || A.isZERO()) { // findbugs throw new ArithmeticException(P + " division by zero " + A); } if (A.isONE()) { return P.ring.getZERO(); } if (P.isZERO() || P.isONE()) { return P; } GenPolynomialRing>> pfac = P.ring; GenPolynomialRing> afac = A.ring; // == pfac.coFac GenPolynomial>> r = P; GenPolynomial> h; GenPolynomial>> hr; GenPolynomial> ldcf = P.leadingBaseCoefficient(); long m = ldcf.degree(0); long n = A.degree(0); GenPolynomial c = A.leadingBaseCoefficient(); GenPolynomial> cc = afac.getZERO().sum(c); //System.out.println("cc = " + cc); ExpVector e = A.leadingExpVector(); for (long i = m; i >= n; i--) { if (r.isZERO()) { return r; } GenPolynomial> p = r.leadingBaseCoefficient(); ExpVector g = r.leadingExpVector(); long k = p.degree(0); if (i == k) { GenPolynomial pl = p.leadingBaseCoefficient(); ExpVector f = p.leadingExpVector(); f = f.subtract(e); r = r.multiply(cc); // coeff cc h = A.multiply(pl, f); // coeff ac hr = new GenPolynomial>>(pfac, h, g); r = r.subtract(hr); } else { r = r.multiply(cc); } //System.out.println("r = " + r); } if (r.degree(0) < P.degree(0)) { // recursion for degree r = coefficientPseudoRemainder(r, A); } return r; } /** * Polynomial leading coefficient pseudo remainder, base case. * @param P generic polynomial in 1+1 variables. * @param A generic polynomial in 1 variable. * @return pseudo remainder of the leading coefficient of P wrt. A, with * ldcf(A)m' P = quotient * A + remainder. */ public static > GenPolynomial> coefficientPseudoRemainderBase( GenPolynomial> P, GenPolynomial A) { if (A == null || A.isZERO()) { // findbugs throw new ArithmeticException(P + " division by zero " + A); } if (A.isONE()) { return P.ring.getZERO(); } if (P.isZERO() || P.isONE()) { return P; } GenPolynomialRing> pfac = P.ring; GenPolynomialRing afac = A.ring; // == pfac.coFac GenPolynomial> r = P; GenPolynomial h; GenPolynomial> hr; GenPolynomial ldcf = P.leadingBaseCoefficient(); long m = ldcf.degree(0); long n = A.degree(0); C c = A.leadingBaseCoefficient(); GenPolynomial cc = afac.getZERO().sum(c); //System.out.println("cc = " + cc); ExpVector e = A.leadingExpVector(); for (long i = m; i >= n; i--) { if (r.isZERO()) { return r; } GenPolynomial p = r.leadingBaseCoefficient(); ExpVector g = r.leadingExpVector(); long k = p.degree(0); if (i == k) { C pl = p.leadingBaseCoefficient(); ExpVector f = p.leadingExpVector(); f = f.subtract(e); r = r.multiply(cc); // coeff cc h = A.multiply(pl, f); // coeff ac hr = new GenPolynomial>(pfac, h, g); r = r.subtract(hr); } else { r = r.multiply(cc); } //System.out.println("r = " + r); } if (r.degree(0) < P.degree(0)) { // recursion for degree r = coefficientPseudoRemainderBase(r, A); } return r; } /** * Extract polynomials with degree zero in the main variable. * @param A list of generic polynomials in n variables. * @return Z = [a_i] with deg(a_i,x_n) = 0 and in n-1 variables. */ public static > List> zeroDegrees(List> A) { if (A == null || A.isEmpty()) { return A; } GenPolynomialRing pfac = A.get(0).ring; GenPolynomialRing> rfac = pfac.recursive(1); List> zeroDeg = new ArrayList>(A.size()); for (int i = 0; i < A.size(); i++) { GenPolynomial q = A.get(i); GenPolynomial> fr = PolyUtil. recursive(rfac, q); if (fr.degree(0) == 0) { zeroDeg.add(fr.leadingBaseCoefficient()); } } return zeroDeg; } /** * Intersection. Generators for the intersection of ideals. * @param pfac polynomial ring * @param A list of polynomials * @param B list of polynomials * @return generators for (A \cap B) */ public static > List> intersect(GenPolynomialRing pfac, List> A, List> B) { if (A == null || A.isEmpty()) { // (0) return B; } if (B == null || B.isEmpty()) { // (0) return A; } int s = A.size() + B.size(); List> c = new ArrayList>(s); GenPolynomialRing tfac = pfac.extend(1); // term order is also adjusted for (GenPolynomial p : A) { p = p.extend(tfac, 0, 1L); // t*p c.add(p); } for (GenPolynomial p : B) { GenPolynomial q = p.extend(tfac, 0, 1L); GenPolynomial r = p.extend(tfac, 0, 0L); p = r.subtract(q); // (1-t)*p c.add(p); } GroebnerBaseAbstract bb = GBFactory. getImplementation(tfac.coFac); logger.warn("intersect computing GB"); List> G = bb.GB(c); if (debug) { logger.debug("intersect GB = {}", G); } List> I = PolyUtil. intersect(pfac, G); return I; } /** * Intersection. Generators for the intersection of ideals. * @param pfac solvable polynomial ring * @param A list of polynomials * @param B list of polynomials * @return generators for (A \cap B) */ public static > List> intersect( GenSolvablePolynomialRing pfac, List> A, List> B) { if (A == null || A.isEmpty()) { // (0) return B; } if (B == null || B.isEmpty()) { // (0) return A; } int s = A.size() + B.size(); List> c = new ArrayList>(s); GenSolvablePolynomialRing tfac = pfac.extend(1); // term order is also adjusted for (GenSolvablePolynomial p : A) { p = (GenSolvablePolynomial) p.extend(tfac, 0, 1L); // t*p c.add(p); } for (GenSolvablePolynomial p : B) { GenSolvablePolynomial q = (GenSolvablePolynomial) p.extend(tfac, 0, 1L); GenSolvablePolynomial r = (GenSolvablePolynomial) p.extend(tfac, 0, 0L); p = (GenSolvablePolynomial) r.subtract(q); // (1-t)*p c.add(p); } SolvableGroebnerBaseAbstract sbb = SGBFactory. getImplementation(tfac.coFac); //new SolvableGroebnerBaseSeq(); logger.warn("intersect computing GB"); List> g = sbb.leftGB(c); //List> g = sbb.twosidedGB(c); if (debug) { logger.debug("intersect GB = {}", g); } List> I = PolyUtil. intersect(pfac, g); return I; } /** * Intersection. Generators for the intersection of word ideals. * @param pfac word polynomial ring * @param A list of word polynomials * @param B list of word polynomials * @return generators for (A \cap B) if it exists */ public static > List> intersect( GenWordPolynomialRing pfac, List> A, List> B) { logger.warn("new WordGroebnerBaseSeq generated"); return intersect(pfac, A, B, new WordGroebnerBaseSeq()); } /** * Intersection. Generators for the intersection of word ideals. * @param pfac word polynomial ring * @param A list of word polynomials * @param B list of word polynomials * @param bb Groebner Base engine * @return generators for (A \cap B) if it exists */ public static > List> intersect( GenWordPolynomialRing pfac, List> A, List> B, WordGroebnerBaseAbstract bb) { if (A == null || A.isEmpty()) { // (0) return B; } if (B == null || B.isEmpty()) { // (0) return A; } int s = A.size() + B.size(); List> L = new ArrayList>(s); GenWordPolynomialRing tfac = pfac.extend(1); List> gens = tfac.univariateList(); //System.out.println("gens = " + gens); GenWordPolynomial t = gens.get(gens.size() - 1); //System.out.println("t = " + t); // make t commute with other variables for (GenWordPolynomial p : gens) { if (t == p) { continue; } GenWordPolynomial c = t.multiply(p).subtract(p.multiply(t)); // t p - p t L.add(c); } for (GenWordPolynomial p : A) { p = tfac.valueOf(p).multiply(t); // t p L.add(p); } for (GenWordPolynomial p : B) { GenWordPolynomial q = tfac.valueOf(p).multiply(t); GenWordPolynomial r = tfac.valueOf(p); p = r.subtract(q); // (1-t) p L.add(p); } //System.out.println("L = " + L); //WordGroebnerBaseAbstract bb = new WordGroebnerBaseSeq(); // todo timestatus logger.warn("intersect computing GB"); List> G = bb.GB(L); //System.out.println("G = " + G); if (debug) { logger.debug("intersect GB = {}", G); } List> I = PolyUtil. intersect(pfac, G); return I; } /** * Solvable quotient and remainder via reduction. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return [ n/d, n - (n/d)*d ] */ @SuppressWarnings({"cast","unchecked"}) public static > GenSolvablePolynomial[] quotientRemainder( GenSolvablePolynomial n, GenSolvablePolynomial d) { GenSolvablePolynomial[] res = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; if (d.isZERO()) { throw new RuntimeException("division by zero: " + n + "/" + d); } if (n.isZERO()) { res[0] = n; res[1] = n; return res; } GenSolvablePolynomialRing r = n.ring; if (d.isONE()) { res[0] = n; res[1] = r.getZERO(); return res; } // divide List> Q = new ArrayList>(1); Q.add(r.getZERO()); List> D = new ArrayList>(1); D.add(d); SolvableReductionAbstract sred = new SolvableReductionSeq(); res[1] = sred.rightNormalform(Q, D, n); // left res[0] = Q.get(0); return res; } /** * Subring generators. * @param A list of polynomials in n variables. * @return a Groebner base of polynomials in m > n variables generating * the subring of K[A]. */ public static > List> subRing(List> A) { if (A == null || A.isEmpty()) { return A; } GenPolynomialRing pfac = A.get(0).ring; logger.debug("pfac = {}", pfac); //.toScript() int n = pfac.nvar; List> Ap = new ArrayList>(); for (GenPolynomial a : A) { if (a == null || a.isZERO() || a.isONE()) { continue; } Ap.add(a); } int k = Ap.size(); if (k == 0) { return Ap; } GenPolynomialRing rfac = pfac.extendLower(k); logger.debug("rfac = {}", rfac); //.toScript() assert rfac.nvar == n + k : "rfac.nvar == n+k"; List> sr = new ArrayList>(); int i = 0; for (GenPolynomial a : Ap) { GenPolynomial b = a.extendLower(rfac, 0, 0L); b = b.subtract(pfac.getONE().extendLower(rfac, i++, 1L)); //System.out.println("a = " + a); //System.out.println("b = " + b); sr.add(b); } GroebnerBaseAbstract bb = GBFactory. getImplementation(pfac.coFac); List> srg = bb.GB(sr); return srg; } /** * Subring membership. * @param A Groebner base of polynomials in m > n variables generating * the subring of elements of K[A]. * @param g polynomial in n variables. * @return true, if g \in K[A], else false. */ public static > boolean subRingMember(List> A, GenPolynomial g) { if (A == null || A.isEmpty()) { return true; } GenPolynomialRing pfac = A.get(0).ring; GenPolynomial m = g; if (pfac.nvar != g.ring.nvar) { m = m.extendLower(pfac, 0, 0L); } else { throw new IllegalArgumentException("g must be extended: " + pfac.nvar + " == " + g.ring.nvar + " did you mean method subRingAndMember()?"); } //ReductionAbstract red = new ReductionSeq(); GroebnerBaseAbstract bb = GBFactory. getImplementation(pfac.coFac); GenPolynomial r = bb.red.normalform(A, m); //System.out.println("r = " + r); GenPolynomialRing cfac = pfac.contract(g.ring.nvar); logger.debug("cfac = {}", cfac); //.toScript() Map> map = r.contract(cfac); //System.out.println("map = " + map); boolean t = map.size() == 1 && map.keySet().contains(g.ring.evzero); if (!t) { System.out.println("false: map = " + map); } return t; } /** * Subring and membership test. * @param A list of polynomials in n variables. * @param g polynomial in n variables. * @return true, if g \in K[A], else false. */ public static > boolean subRingAndMember(List> A, GenPolynomial g) { if (A == null || A.isEmpty()) { return true; } List> srg = PolyGBUtil. subRing(A); return PolyGBUtil. subRingMember(srg, g); } /** * Chinese remainder theorem. * @param F = ( F_i ) list of list of polynomials in n variables. * @param A = ( f_i ) list of polynomials in n variables. * @return p \in \Cap_i (f_i + ideal(F_i)) if it exists, else null. */ public static > GenPolynomial chineseRemainderTheorem( List>> F, List> A) { if (F == null || F.isEmpty() || A == null || A.isEmpty()) { throw new IllegalArgumentException("F and A may not be empty or null"); } int m = F.size(); if (m != A.size()) { throw new IllegalArgumentException("size(F) and size(A) must be equal"); } GenPolynomialRing pfac = A.get(0).ring; logger.debug("pfac = {}", pfac); //.toScript() GenPolynomialRing rfac = pfac.extend(m); logger.debug("rfac = {}", rfac); //.toScript() GenPolynomial y = rfac.getONE(); GenPolynomial f = rfac.getZERO(); int i = 0; List> Fp = new ArrayList>(); //m**2? //System.out.println("A = " + A); for (List> Fi : F) { GenPolynomial Yi = pfac.getONE().extend(rfac, i, 1L); y = y.subtract(Yi); List> Fip = new ArrayList>(Fi.size()); //System.out.println("Fi = " + Fi); for (GenPolynomial a : Fi) { GenPolynomial b = a.extend(rfac, i, 1L); Fip.add(b); } //System.out.println("Fip = " + Fip); Fp.addAll(Fip); GenPolynomial a = A.get(i); //System.out.println("a = " + a); f = f.sum(a.extend(rfac, i, 1L)); i++; } Fp.add(y); //System.out.println("f = " + f); //System.out.println("Fp = " + Fp); GroebnerBaseAbstract bb = GBFactory. getImplementation(pfac.coFac); List> Fpp = bb.GB(Fp); //System.out.println("Fpp = " + Fpp); GenPolynomial h = bb.red.normalform(Fpp, f); //System.out.println("h = " + h); ////PseudoReduction pr = new PseudoReductionSeq(); ////PseudoReductionEntry fz = pr.normalformFactor(Fpp, f); ////System.out.println("fz = " + fz); List> H = new ArrayList>(); H.add(h); H = PolyUtil. intersect(pfac, H); //System.out.println("H != (): " + (! H.isEmpty())); if (H.isEmpty()) { return null; } return H.get(0); } /** * Is Chinese remainder. * @param F = ( F_i ) list of list of polynomials in n variables. * @param A = ( f_i ) list of polynomials in n variables. * @param h polynomial in n variables. * @return true if h \in \Cap_i (f_i + ideal(F_i)), else false. */ public static > boolean isChineseRemainder(List>> F, List> A, GenPolynomial h) { if (h == null) { return false; } if (F == null || F.isEmpty() || A == null || A.isEmpty()) { return false; } if (F.size() != A.size()) { return false; } GenPolynomialRing pfac = h.ring; if (!pfac.coFac.isField()) { //System.out.println("pfac = " + pfac.toScript()); logger.error("only for field coefficients: {}", pfac); //.toScript() //throw new IllegalArgumentException("only for field coefficients: " + pfac.toScript()); } GroebnerBaseAbstract bb = GBFactory. getImplementation(pfac.coFac); int i = 0; for (List> Fi : F) { List> Fp = bb.GB(Fi); //System.out.println("Fp = " + Fp); GenPolynomial a = A.get(i); GenPolynomial fi = bb.red.normalform(Fp, h.subtract(a)); if (!fi.isZERO()) { //System.out.println("Fp = " + Fp + ", Fi = " + Fi); //System.out.println("h = " + h + ", a = " + a + ", fi = " + fi); logger.info("h-a = {}, fi = {}", h.subtract(a), fi); return false; } i++; } return true; } /** * Chinese remainder theorem, interpolation. * @param fac polynomial ring over K in n variables. * @param E = ( E_i ), E_i = ( e_ij ) list of list of elements of K, the evaluation points. * @param V = ( f_i ) list of elements of K, the evaluation values. * @return p \in K[X1,...,Xn], with p(E_i) = f_i, if it exists, else null. */ @SuppressWarnings({"cast","unchecked"}) public static > GenPolynomial CRTInterpolation( GenPolynomialRing fac, List> E, List V) { if (E == null || E.isEmpty() || V == null || V.isEmpty()) { throw new IllegalArgumentException("E and V may not be empty or null"); } int m = E.size(); if (m != V.size()) { throw new IllegalArgumentException("size(E) and size(V) must be equal"); } //System.out.println("fac = " + fac.toScript()); List>> F = new ArrayList>>(E.size()); List> A = new ArrayList>(V.size()); List> gen = (List>) fac.univariateList(); //System.out.println("gen = " + gen); int i = 0; for (List Ei : E) { List> Fi = new ArrayList>(); int j = 0; for (C eij : Ei) { GenPolynomial ep = gen.get(j); ep = ep.subtract( fac.valueOf(eij) ); Fi.add(ep); j++; } F.add(Fi); String ai = " " + V.get(i); // (sic) .toString() not possible //System.out.println("ai = " + ai); GenPolynomial ap = fac.valueOf(ai); A.add(ap); i++; } //System.out.println("F = " + F); //System.out.println("A = " + A); GenPolynomial p = PolyGBUtil. chineseRemainderTheorem(F,A); //System.out.println("p = " + p); //System.out.println("t = " + PolyGBUtil. isChineseRemainder(F,A,p)); return p; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/PolyModUtil.java000066400000000000000000000217361445075545500240430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; /** * Package gb and gbufd utilities. * @author Heinz Kredel */ public class PolyModUtil { private static final Logger logger = LogManager.getLogger(PolyModUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Least common multiple via ideal intersection. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return lcm(n,d) */ public static > GenSolvablePolynomial syzLcm(GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { if (n.isZERO()) { return n; } if (d.isZERO()) { return d; } if (n.isONE()) { return d; } if (d.isONE()) { return n; } List> A = new ArrayList>(1); A.add(n); List> B = new ArrayList>(1); B.add(d); List> c = PolyGBUtil. intersect(r, A, B); //if (c.size() != 1) { // SolvableSyzygyAbstract sz = new SolvableSyzygyAbstract(); // GenSolvablePolynomial[] oc = sz.leftOreCond(n,d); // GenSolvablePolynomial nc = oc[0].multiply(n); // System.out.println("nc = " + nc); // return nc; //} GenSolvablePolynomial lcm = null; for (GenSolvablePolynomial p : c) { if (p == null || p.isZERO()) { continue; } //System.out.println("p = " + p); if (lcm == null) { lcm = p; continue; } if (lcm.compareTo(p) > 0) { lcm = p; } } if (lcm == null) { throw new RuntimeException("this cannot happen: lcm == null: " + c); } return lcm; } /** * Greatest common divisor via least common multiple. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return gcd(n,d) */ public static > GenSolvablePolynomial syzGcd(GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { return syzLeftGcd(r, n, d); } /** * Left greatest common divisor via least common multiple. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return gcd(n,d) */ public static > GenSolvablePolynomial syzLeftGcd( GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { if (n.isZERO()) { return d; } if (d.isZERO()) { return n; } if (n.isConstant()) { return r.getONE(); } if (d.isConstant()) { return r.getONE(); } if (n.totalDegree() > 3 || d.totalDegree() > 3) { // how avoid too long running GBs ? //if (n.totalDegree() + d.totalDegree() > 6) { // how avoid too long running GBs ? // && n.length() < 10 && d.length() < 10 logger.warn("skipping GB computation: degs = {}, {}", n.totalDegree(), d.totalDegree()); return r.getONE(); } List> A = new ArrayList>(2); A.add(n); A.add(d); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); logger.warn("left syzGcd computing GB: {}", A); List> G = sbb.rightGB(A); //not: leftGB, not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.warn("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return r.getONE(); } /** * Right greatest common divisor via least common multiple. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return gcd(n,d) */ public static > GenSolvablePolynomial syzRightGcd( GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { if (n.isZERO()) { return d; } if (d.isZERO()) { return n; } if (n.isConstant()) { return r.getONE(); } if (d.isConstant()) { return r.getONE(); } if (n.totalDegree() > 3 || d.totalDegree() > 3) { // how avoid too long running GBs ? //if (n.totalDegree() + d.totalDegree() > 6) { // how avoid too long running GBs ? // && n.length() < 10 && d.length() < 10 logger.warn("skipping GB computation: degs = {}, {}", n.totalDegree(), d.totalDegree()); return r.getONE(); } List> A = new ArrayList>(2); A.add(n); A.add(d); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); logger.warn("right syzGcd computing GB: {}", A); List> G = sbb.leftGB(A); // not: sbb.twosidedGB(A); if (debug) { logger.info("G = {}", G); } if (G.size() == 1) { return G.get(0); } logger.warn("gcd not determined, set to 1: {}", G); // + ", A = {}", A); return r.getONE(); } /** * Greatest common divisor and cofactors via least common multiple and * reduction. * @param r solvable polynomial ring. * @param n first solvable polynomial. * @param d second solvable polynomial. * @return [ g=gcd(n,d), n/g, d/g ] */ @SuppressWarnings({ "unchecked", "cast" }) public static > GenSolvablePolynomial[] syzGcdCofactors( GenSolvablePolynomialRing r, GenSolvablePolynomial n, GenSolvablePolynomial d) { GenSolvablePolynomial[] res = (GenSolvablePolynomial[]) new GenSolvablePolynomial[3]; res[0] = PolyModUtil. syzGcd(r, n, d); res[1] = n; res[2] = d; if (res[0].isONE()) { return res; } GenSolvablePolynomial[] nqr = PolyGBUtil. quotientRemainder(n, res[0]); if (!nqr[1].isZERO()) { res[0] = r.getONE(); return res; } GenSolvablePolynomial[] dqr = PolyGBUtil. quotientRemainder(d, res[0]); if (!dqr[1].isZERO()) { res[0] = r.getONE(); return res; } res[1] = nqr[0]; res[2] = dqr[0]; return res; } /** * Least common multiple. Just for fun, is not efficient. * @param r polynomial ring. * @param n first polynomial. * @param d second polynomial. * @return lcm(n,d) */ public static > GenPolynomial syzLcm(GenPolynomialRing r, GenPolynomial n, GenPolynomial d) { List> A = new ArrayList>(1); A.add(n); List> B = new ArrayList>(1); B.add(d); List> c = PolyGBUtil. intersect(r, A, B); if (c.size() != 1) { logger.warn("lcm not unique: {}", c); //throw new RuntimeException("lcm not unique: " + c); } GenPolynomial lcm = c.get(0); return lcm; } /** * Greatest common divisor. Just for fun, is not efficient. * @param r polynomial ring. * @param n first polynomial. * @param d second polynomial. * @return gcd(n,d) */ public static > GenPolynomial syzGcd(GenPolynomialRing r, GenPolynomial n, GenPolynomial d) { if (n.isZERO()) { return d; } if (d.isZERO()) { return n; } if (n.isONE()) { return n; } if (d.isONE()) { return d; } GenPolynomial p = n.multiply(d); GenPolynomial lcm = syzLcm(r, n, d); GenPolynomial gcd = PolyUtil. basePseudoDivide(p, lcm); return gcd; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/PseudoReduction.java000066400000000000000000000020171445075545500247250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import edu.jas.gb.Reduction; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial pseudo reduction interface. Defines additionally normalformFactor. * @param coefficient type. * @author Heinz Kredel */ public interface PseudoReduction> extends Reduction { /** * Normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ public PseudoReductionEntry normalformFactor(List> Pp, GenPolynomial Ap); /** * Normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ public GenPolynomial> normalformRecursive(List>> Pp, GenPolynomial> Ap); } java-algebra-system-2.7.200/src/edu/jas/gbufd/PseudoReductionEntry.java000066400000000000000000000011771445075545500257550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial reduction container. Used as container for the return value of * normalformFactor. * @author Heinz Kredel */ public class PseudoReductionEntry> { public final GenPolynomial pol; public final C multiplicator; public PseudoReductionEntry(GenPolynomial pol, C multiplicator) { this.pol = pol; this.multiplicator = multiplicator; } @Override public String toString() { return " " + multiplicator + " times " + pol; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/PseudoReductionPar.java000066400000000000000000000263731445075545500254030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.ReductionAbstract; import edu.jas.poly.PolyUtil; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Polynomial pseudo reduction sequential use algorithm. Coefficients of * polynomials must not be from a field, i.e. the fraction free reduction is * implemented. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class PseudoReductionPar> extends ReductionAbstract implements PseudoReduction { private static final Logger logger = LogManager.getLogger(PseudoReductionPar.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public PseudoReductionPar() { } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } GenPolynomial[] P = new GenPolynomial[0]; List> Ppp; synchronized (Pp) { Ppp = new ArrayList>(Pp); // sic } P = Ppp.toArray(P); int ll = Ppp.size(); GenPolynomial Rz = Ap.ring.getZERO(); GenPolynomial R = Rz.copy(); GenPolynomial S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != ll) { //System.out.println("Pp.size() = " + Pp.size() + ", ll = " + ll); //long t = System.currentTimeMillis(); synchronized (Pp) { Ppp = new ArrayList>(Pp); // sic } P = Ppp.toArray(P); ll = Ppp.size(); //ll = P.length; // wrong //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray(): size() = {}, ll = {}", l, ll); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } boolean mt = false; Map.Entry m = S.leadingMonomial(); ExpVector e = m.getKey(); C a = m.getValue(); ExpVector f = null; int i; for (i = 0; i < ll; i++) { f = P[i].leadingExpVector(); mt = e.multipleOf(f); if (mt) break; } if (!mt) { //System.out.println("m = " + m); //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(f); //logger.info("red div = {}", e); C c = P[i].leadingBaseCoefficient(); if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); S = S.subtractMultiple(a, e, P[i]); } else { R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, e, P[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); } } return R; } /** * Normalform. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ @SuppressWarnings("unchecked") public PseudoReductionEntry normalformFactor(List> Pp, GenPolynomial Ap) { if (Ap == null) { return null; } C mfac = Ap.ring.getONECoefficient(); PseudoReductionEntry pf = new PseudoReductionEntry(Ap, mfac); if (Pp == null || Pp.isEmpty()) { return pf; } if (Ap.isZERO()) { return pf; } GenPolynomial[] P = new GenPolynomial[0]; List> Ppp; synchronized (Pp) { Ppp = new ArrayList>(Pp); // sic } P = Ppp.toArray(P); int l = Ppp.size(); boolean mt = false; GenPolynomial Rz = Ap.ring.getZERO(); GenPolynomial R = Rz.copy(); //GenPolynomial T = null; //GenPolynomial Q = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != l) { //long t = System.currentTimeMillis(); synchronized (Pp) { Ppp = new ArrayList>(Pp); } P = Ppp.toArray(P); l = Ppp.size(); //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray() = {} ms, size() = {}", t, l); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } Map.Entry m = S.leadingMonomial(); ExpVector e = m.getKey(); C a = m.getValue(); ExpVector f = null; int i; for (i = 0; i < l; i++) { f = P[i].leadingExpVector(); mt = e.multipleOf(f); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(f); //logger.info("red div = {}", e); C c = P[i].leadingBaseCoefficient(); if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); S = S.subtractMultiple(a, e, P[i]); } else { mfac = mfac.multiply(c); R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, e, P[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); } } logger.info("multiplicative factor = {}", mfac); pf = new PseudoReductionEntry(R, mfac); return pf; } /** * Normalform with recording. Note: Only meaningful if all divisions * are exact. Compute first the multiplication factor m with * normalform(Pp,Ap,m), then call this method with * normalform(row,Pp,m*Ap). * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { throw new RuntimeException("normalform with recording not implemented"); } /** * Normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial> normalformRecursive(List>> Pp, GenPolynomial> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } GenPolynomial>[] P = new GenPolynomial[0]; List>> Ppp; synchronized (Pp) { Ppp = new ArrayList>>(Pp); // sic } P = Ppp.toArray(P); int ll = Ppp.size(); GenPolynomial> Rz = Ap.ring.getZERO(); GenPolynomial> R = Rz.copy(); GenPolynomial> S = Ap.copy(); while (S.length() > 0) { if (Pp.size() != ll) { //System.out.println("Pp.size() = " + Pp.size() + ", ll = " + ll); //long t = System.currentTimeMillis(); synchronized (Pp) { Ppp = new ArrayList>>(Pp); // sic } P = Ppp.toArray(P); ll = Ppp.size(); //ll = P.length; // wrong //t = System.currentTimeMillis()-t; //logger.info("Pp.toArray(): size() = {}, ll = {}", l, ll); S = Ap.copy(); // S.add(R)? // restart reduction ? R = Rz.copy(); } boolean mt = false; Map.Entry> m = S.leadingMonomial(); ExpVector e = m.getKey(); GenPolynomial a = m.getValue(); ExpVector f = null; int i; for (i = 0; i < ll; i++) { f = P[i].leadingExpVector(); mt = e.multipleOf(f); if (mt) break; } if (!mt) { //System.out.println("m = " + m); //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { f = e.subtract(f); if (debug) { logger.info("red div = {}", e); } GenPolynomial c = P[i].leadingBaseCoefficient(); //if (a.remainder(c).isZERO()) { //c.isUnit() ) { if (PolyUtil. baseSparsePseudoRemainder(a,c).isZERO()) { if (debug) { logger.info("red c = {}", c); } //a = a.divide(c); GenPolynomial b = PolyUtil. basePseudoDivide(a,c); GenPolynomial> Sp = S.subtractMultiple(b, f, P[i]); if (e.equals(Sp.leadingExpVector())) { // TODO: avoid if possible //throw new RuntimeException("degree not descending"); logger.info("degree not descending: S = {}, Sp = {}", S, Sp); R = R.multiply(c); //S = S.multiply(c); Sp = S.scaleSubtractMultiple(c, a, f, P[i]); } S = Sp; } else { R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, f, P[i]); } //Q = p[i].multiply(a, f); //S = S.subtract(Q); } } return R; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/PseudoReductionSeq.java000066400000000000000000000322721445075545500254040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.ReductionAbstract; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; /** * Polynomial pseudo reduction sequential use algorithm. Coefficients of * polynomials must not be from a field, i.e. the fraction free reduction is * implemented. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class PseudoReductionSeq> extends ReductionAbstract implements PseudoReduction { private static final Logger logger = LogManager.getLogger(PseudoReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public PseudoReductionSeq() { } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry m; GenPolynomial[] P = new GenPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; GenPolynomial[] p = new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a, b; boolean mt = false; GenPolynomial R = Ap.ring.getZERO().copy(); GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { f = e.subtract(htl[i]); //logger.info("red div = {}", e); @SuppressWarnings("unchecked") C c = (C) lbc[i]; if (a.remainder(c).isZERO()) { //c.isUnit() ) { b = a.divide(c); GenPolynomial Sp = S.subtractMultiple(b, f, p[i]); if (e.equals(Sp.leadingExpVector())) { // TODO: avoid if possible logger.info("degree not descending: S = {}, Sp = {}", S, Sp); R = R.multiply(c); //S = S.multiply(c); Sp = S.scaleSubtractMultiple(c, a, f, p[i]); } S = Sp; } else { R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, f, p[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); } } return R; } /** * Normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial> normalformRecursive(List>> Pp, GenPolynomial> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry> m; GenPolynomial>[] P = new GenPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; GenPolynomial[] lbc = (GenPolynomial[]) new GenPolynomial[l]; GenPolynomial>[] p = new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; GenPolynomial a, b; boolean mt = false; GenPolynomial> R = Ap.ring.getZERO().copy(); GenPolynomial> S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { f = e.subtract(htl[i]); if (debug) { logger.info("red div = {}", f); //logger.info("red a = {}", a); } GenPolynomial c = (GenPolynomial) lbc[i]; //if (a.remainder(c).isZERO()) { //c.isUnit() ) { if (PolyUtil. baseSparsePseudoRemainder(a, c).isZERO()) { //c.isUnit() ) { if (debug) { logger.info("red c = {}", c); } //a = a.divide(c); b = PolyUtil. basePseudoDivide(a, c); GenPolynomial> Sp = S.subtractMultiple(b, f, p[i]); if (e.equals(Sp.leadingExpVector())) { // TODO: avoid if possible //throw new RuntimeException("degree not descending"); logger.info("degree not descending: S = {}, Sp = {}", S, Sp); R = R.multiply(c); //S = S.multiply(c); Sp = S.scaleSubtractMultiple(c, a, f, p[i]); } S = Sp; } else { R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, f, p[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); } } return R; } /** * Normalform with recording. Note: Only meaningful if all divisions * are exact. Compute first the multiplication factor m with * normalform(Pp,Ap,m), then call this method with * normalform(row,Pp,m*Ap). * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } GenPolynomial[] P = new GenPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; Object[] lbc = new Object[l]; // want C GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial R = Ap.ring.getZERO().copy(); GenPolynomial fac = null; GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); C c = (C) lbc[i]; if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); S = S.subtractMultiple(a, e, p[i]); //System.out.print("|"); } else { //System.out.print("*"); R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, e, p[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); fac = row.get(i); if (fac == null) { fac = zero.sum(a, e); } else { fac = fac.sum(a, e); } row.set(i, fac); } } return R; } /** * Normalform. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ @SuppressWarnings("unchecked") public PseudoReductionEntry normalformFactor(List> Pp, GenPolynomial Ap) { if (Ap == null) { return null; } C mfac = Ap.ring.getONECoefficient(); PseudoReductionEntry pf = new PseudoReductionEntry(Ap, mfac); if (Pp == null || Pp.isEmpty()) { return pf; } if (Ap.isZERO()) { return pf; } Map.Entry m; GenPolynomial[] P = new GenPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RingElem[l]; // want C[] GenPolynomial[] p = new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenPolynomial R = Ap.ring.getZERO().copy(); GenPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); C c = lbc[i]; if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); S = S.subtractMultiple(a, e, p[i]); } else { mfac = mfac.multiply(c); R = R.multiply(c); //S = S.multiply(c); S = S.scaleSubtractMultiple(c, a, e, p[i]); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); } } logger.info("multiplicative factor = {}", mfac); pf = new PseudoReductionEntry(R, mfac); return pf; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/RGroebnerBasePseudoSeq.java000066400000000000000000000375601445075545500261350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.Pair; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RegularRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Regular ring Groebner Base with pseudo reduction sequential algorithm. * Implements R-Groebner bases and GB test. * @param coefficient type * @author Heinz Kredel */ public class RGroebnerBasePseudoSeq> extends RGroebnerBaseSeq { private static final Logger logger = LogManager.getLogger(RGroebnerBasePseudoSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final RPseudoReduction red; /** * Coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param rf coefficient ring factory. */ public RGroebnerBasePseudoSeq(RingFactory rf) { this(new RPseudoReductionSeq(), rf); } /** * Constructor. * @param red R-pseudo-Reduction engine * @param rf coefficient ring factory. */ public RGroebnerBasePseudoSeq(RPseudoReduction red, RingFactory rf) { super(red); this.red = red; cofac = rf; engine = GCDFactory. getImplementation(rf); // not used: engine = // (GreatestCommonDivisorAbstract)GCDFactory.getProxy( rf ); } /** * R-Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a R-Groebner base of F. */ @Override public List> GB(int modv, List> F) { if (F == null) { return F; } /* boolean closure */ List> bcF = red.reducedBooleanClosure(F); logger.info("#bcF-#F = {}", (bcF.size() - F.size())); F = bcF; /* normalize input */ List> G = new ArrayList>(); OrderedRPairlist pairlist = null; for (GenPolynomial p : F) { if (!p.isZERO()) { p = engine.basePrimitivePart(p); // not monic, no field p = p.abs(); if (p.isConstant() && p.leadingBaseCoefficient().isFull()) { G.clear(); G.add(p); return G; // since boolean closed and no threads are activated } G.add(p); // G.add( 0, p ); //reverse list if (pairlist == null) { pairlist = new OrderedRPairlist(modv, p.ring); } // putOne not required pairlist.put(p); } } if (G.size() <= 1) { return G; // since boolean closed and no threads are activated } /* loop on critical pairs */ Pair pair; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; // GenPolynomial D; GenPolynomial H; List> bcH; while (pairlist.hasNext()) { pair = pairlist.removeNext(); // System.out.println("pair = " + pair); if (pair == null) continue; pi = pair.pi; pj = pair.pj; if (logger.isDebugEnabled()) { logger.info("pi = {}", pi); logger.info("pj = {}", pj); } if (!red.moduleCriterion(modv, pi, pj)) { continue; } // S-polynomial ----------------------- // Criterion3(), Criterion4() not applicable S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } logger.debug("ht(S) = {}", S.leadingExpVector()); H = red.normalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } logger.debug("ht(H) = {}", H.leadingExpVector()); H = engine.basePrimitivePart(H); H = H.abs(); // not monic, no field if (H.isConstant() && H.leadingBaseCoefficient().isFull()) { // mostly useless G.clear(); G.add(H); return G; // not boolean closed ok, no threads are activated } logger.debug("H = {}", H); if (!H.isZERO()) { // logger.info("Sred = {}", H); // len = G.size(); bcH = red.reducedBooleanClosure(G, H); // logger.info("#bcH = {}", bcH.size()); // G.addAll( bcH ); for (GenPolynomial h : bcH) { h = engine.basePrimitivePart(h); h = h.abs(); // monic() not ok, since no field logger.info("bc(Sred) = {}", h); G.add(h); pairlist.put(h); } if (debug) { if (!pair.getUseCriterion3() || !pair.getUseCriterion4()) { logger.info("H != 0 but: {}", pair); } } } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); // G = red.irreducibleSet(G); // not correct since not boolean closed logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List> minimalGB(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() a = a.abs(); // already positive in GB G.add(a); } } // remove top reducible polynomials logger.info("minGB start with {}", G.size()); GenPolynomial a, b; List> F; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); b = a; if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // try to drop polynomial List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (a.isZERO()) { //if (false && !isGB(ff)) { // is really required, but why? // logger.info("minGB not dropped {}", b); // F.add(b); //} else { logger.debug("minGB dropped {}", b); //} } else { // happens logger.info("minGB not zero {}", a); F.add(a); } } else { // not top reducible, keep polynomial F.add(a); } } G = F; Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int el = 0; while (el < len) { el++; a = G.remove(0); b = a; a = red.normalform(G, a); a = engine.basePrimitivePart(a); // not a.monic() since no field a = a.abs(); if (red.isBooleanClosed(a)) { //List> ff; //ff = new ArrayList>(G); //ff.add(a); //if (true || isGB(ff)) { if (debug) { logger.debug("minGB reduced {} to {}", b, a); } G.add(a); //} else { // logger.info("minGB not reduced {} to {}", b, a); // G.add(b); //} continue; } logger.info("minGB not boolean closed {}", a); G.add(b); // do not reduce } /* stratify: collect polynomials with equal leading terms */ ExpVector e, f; F = new ArrayList>(G.size()); List> ff; ff = new ArrayList>(G); for (int i = 0; i < ff.size(); i++) { a = ff.get(i); if (a == null || a.isZERO()) { continue; } e = a.leadingExpVector(); for (int j = i + 1; j < ff.size(); j++) { b = ff.get(j); if (b == null || b.isZERO()) { continue; } f = b.leadingExpVector(); if (e.equals(f)) { // System.out.println("minGB e == f: {}", a + ", {}", b); a = a.sum(b); ff.set(j, null); } } F.add(a); } //if (true || isGB(F)) { G = F; //} else { // logger.info("minGB not stratified {}", F); //} logger.info("minGB end with #G = {}", G.size()); return G; } /* * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ List> minimalGBtesting(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } //if (G.size() <= 1) { // wg monic do not return G; //} // remove top reducible polynomials GenPolynomial a, b; List> F; List> bcH; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); b = a; if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (logger.isInfoEnabled()) { List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("minGB nf(a) != 0 " + a); bcH = red.reducedBooleanClosure(G, a); if (bcH.size() > 1) { // never happened so far System.out.println("minGB not bc: bcH size = " + bcH.size()); F.add(b); // do not replace, stay with b } else { // System.out.println("minGB add bc(a): a = " + a + ", // bc(a) = " + bcH.get(0)); F.add(b); // do not replace, stay with b // F.addAll( bcH ); } } else { if (!isGB(ff)) { System.out.println("minGB not dropped " + b); F.add(b); } else { System.out.println("minGB dropped " + b); } } } } else { // not top reducible, keep polynomial F.add(a); } } G = F; //if (G.size() <= 1) { // wg monic return G; //} Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int el = 0; // System.out.println("minGB reducing " + len); while (el < len) { el++; a = G.remove(0); b = a; // System.out.println("minGB doing " + el + ", a = " + a); a = red.normalform(G, a); // use primitivePart a = engine.basePrimitivePart(a); // not a.monic() since no field // not bc: if (red.isBooleanClosed(a)) { List> ff; ff = new ArrayList>(G); ff.add(a); if (isGB(ff)) { System.out.println("minGB reduced " + b + " to " + a); G.add(a); } else { System.out.println("minGB not reduced " + b + " to " + a); G.add(b); } continue; } System.out.println("minGB not bc: a = " + a + "\n BC(a) = " + red.booleanClosure(a) + ", BR(a) = " + red.booleanRemainder(a)); bcH = red.reducedBooleanClosure(G, a); if (bcH.size() > 1) { System.out.println("minGB not bc: bcH size = " + bcH.size()); G.add(b); // do not reduce } else { // G.addAll( bcH ); G.add(b); // do not reduce for (GenPolynomial h : bcH) { // use primitivePart h = engine.basePrimitivePart(h); h = h.abs(); // monic() not ok, since no field // G.add( h ); } } } // make abs if possible F = new ArrayList>(G.size()); for (GenPolynomial p : G) { a = p.abs(); F.add(a); } G = F; //if (false) { // return G; //} // stratify: collect polynomials with equal leading terms ExpVector e, f; F = new ArrayList>(G.size()); for (int i = 0; i < G.size(); i++) { a = G.get(i); if (a == null || a.isZERO()) { continue; } e = a.leadingExpVector(); for (int j = i + 1; j < G.size(); j++) { b = G.get(j); if (b == null || b.isZERO()) { continue; } f = b.leadingExpVector(); if (e.equals(f)) { // System.out.println("minGB e == f: " + a + ", " + b); a = a.sum(b); G.set(j, null); } } F.add(a); } G = F; // info on boolean algebra element blocks Map>> bd = new TreeMap>>(); for (GenPolynomial p : G) { C cf = p.leadingBaseCoefficient(); cf = cf.idempotent(); List> block = bd.get(cf); if (block == null) { block = new ArrayList>(); } block.add(p); bd.put(cf, block); } System.out.println("\nminGB bd:"); for (Map.Entry>> me : bd.entrySet()) { System.out.println("\nkey = " + me.getKey() + ":"); System.out.println("val = " + me.getValue()); } System.out.println(); // return G; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/RGroebnerBaseSeq.java000066400000000000000000000260361445075545500247510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.Pair; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RegularRingElem; /** * Regular ring Groebner Base sequential algorithm. Implements R-Groebner bases * and GB test. * @param coefficient type * @author Heinz Kredel */ public class RGroebnerBaseSeq> extends GroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(RGroebnerBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ protected RReduction rred; // shadow super.red ?? /** * Constructor. */ public RGroebnerBaseSeq() { this(new RReductionSeq()); } /** * Constructor. * @param rred R-Reduction engine */ public RGroebnerBaseSeq(RReduction rred) { super(rred); this.rred = rred; assert super.red == this.rred; } /** * R-Groebner base test. * @param modv module variable number. * @param F polynomial list. * @return true, if F is a R-Groebner base, else false. */ @Override public boolean isGB(int modv, List> F) { if (F == null) { return true; } if (!rred.isBooleanClosed(F)) { if (debug) { logger.debug("not boolean closed"); } return false; } GenPolynomial pi, pj, s; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // red.criterion4 not applicable s = red.SPolynomial(pi, pj); if (s.isZERO()) { continue; } s = red.normalform(F, s); if (!s.isZERO()) { if (debug) { logger.debug("p{} = {}", i, pi); logger.debug("p{} = {}", j, pj); logger.debug("s-pol = {}", red.SPolynomial(pi, pj)); logger.debug("s-pol({},{}) != 0: {}", i, j, s); } return false; } } } return true; } /** * R-Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a R-Groebner base of F. */ public List> GB(int modv, List> F) { /* boolean closure */ List> bcF = rred.reducedBooleanClosure(F); logger.info("#bcF-#F = {}", (bcF.size() - F.size())); F = bcF; /* normalize input */ List> G = new ArrayList>(); OrderedRPairlist pairlist = null; for (GenPolynomial p : F) { if (!p.isZERO()) { p = p.monic(); //p.abs(); // not monic, monic if boolean closed if (p.isONE()) { G.clear(); G.add(p); return G; // since boolean closed and no threads are activated } G.add(p); //G.add( 0, p ); //reverse list if (pairlist == null) { pairlist = new OrderedRPairlist(modv, p.ring); } // putOne not required pairlist.put(p); } } if (G.size() <= 1) { return G; // since boolean closed and no threads are activated } /* loop on critical pairs */ Pair pair; GenPolynomial pi; GenPolynomial pj; GenPolynomial S; //GenPolynomial D; GenPolynomial H; List> bcH; //int len = G.size(); //System.out.println("len = " + len); while (pairlist.hasNext()) { pair = pairlist.removeNext(); //System.out.println("pair = " + pair); if (pair == null) continue; pi = pair.pi; pj = pair.pj; if (logger.isDebugEnabled()) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } if (!red.moduleCriterion(modv, pi, pj)) { continue; } // S-polynomial ----------------------- // Criterion3() Criterion4() not applicable S = red.SPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } logger.debug("ht(S) = {}", S.leadingExpVector()); H = red.normalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } //H = H.monic(); // only for boolean closed H logger.debug("ht(H) = {}", H.leadingExpVector()); if (H.isONE()) { // mostly useless G.clear(); G.add(H); return G; // not boolean closed ok, since no threads are activated } logger.debug("H = {}", H); if (!H.isZERO()) { logger.info("Sred = {}", H); //len = G.size(); bcH = rred.reducedBooleanClosure(G, H); logger.info("#bcH = {}", bcH.size()); for (GenPolynomial h : bcH) { h = h.monic(); // monic() ok, since boolean closed G.add(h); pairlist.put(h); } if (debug) { if (!pair.getUseCriterion3() || !pair.getUseCriterion4()) { logger.info("H != 0 but: {}", pair); } } } } logger.debug("#sequential list = {}", G.size()); G = minimalGB(G); //G = red.irreducibleSet(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List> minimalGB(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List> G = new ArrayList>(Gp.size()); for (GenPolynomial a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } //if (G.size() <= 1) { //wg monic do not return G; //} // remove top reducible polynomials GenPolynomial a, b; List> F; List> bcH; F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); b = a; if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (logger.isInfoEnabled()) { List> ff; ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { // happens logger.info("minGB not zero {}", a); bcH = rred.reducedBooleanClosure(G, a); if (bcH.size() > 1) { // never happened so far System.out.println("minGB not bc: bcH size = " + bcH.size()); F.add(b); // do not replace, stay with b } else { //System.out.println("minGB add bc(a): a = " + a + ", bc(a) = " + bcH.get(0)); F.addAll(bcH); } } else { //System.out.println("minGB dropped " + b); } } } else { F.add(a); } } G = F; //if (G.size() <= 1) { // wg monic return G; //} Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int el = 0; while (el < len) { a = G.remove(0); b = a; //System.out.println("doing " + a.length()); a = red.normalform(G, a); bcH = rred.reducedBooleanClosure(G, a); if (bcH.size() > 1) { System.out.println("minGB not bc: bcH size = " + bcH.size()); G.add(b); // do not reduce } else { G.addAll(bcH); } el++; } // make monic if possible F = new ArrayList>(G.size()); for (GenPolynomial p : G) { a = p.monic().abs(); if (p.length() != a.length()) { System.out.println("minGB not bc: #p != #a: a = " + a + ", p = " + p); a = p; // dont make monic for now } F.add(a); } G = F; /* stratify: collect polynomials with equal leading terms */ ExpVector e, f; F = new ArrayList>(G.size()); for (int i = 0; i < G.size(); i++) { a = G.get(i); if (a == null || a.isZERO()) { continue; } e = a.leadingExpVector(); for (int j = i + 1; j < G.size(); j++) { b = G.get(j); if (b == null || b.isZERO()) { continue; } f = b.leadingExpVector(); if (e.equals(f)) { //System.out.println("minGB e == f: " + a + ", " + b); a = a.sum(b); G.set(j, null); } } F.add(a); } G = F; /* info on boolean algebra element blocks Map>> bd = new TreeMap>>(); for ( GenPolynomial p : G ) { C cf = p.leadingBaseCoefficient(); cf = cf.idempotent(); List> block = bd.get( cf ); if ( block == null ) { block = new ArrayList>(); } block.add( p ); bd.put( cf, block ); } System.out.println("\nminGB bd:"); for( C k: bd.keySet() ) { System.out.println("\nkey = " + k + ":"); System.out.println("val = " + bd.get(k)); } System.out.println(); */ return G; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/RPseudoReduction.java000066400000000000000000000005441445075545500250520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import edu.jas.structure.RegularRingElem; /** * Polynomial R pseudo reduction interface. Combines RReduction and * PseudoReduction. * @param coefficient type * @author Heinz Kredel */ public interface RPseudoReduction> extends RReduction, PseudoReduction { } java-algebra-system-2.7.200/src/edu/jas/gbufd/RPseudoReductionSeq.java000066400000000000000000000302611445075545500255220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RegularRingElem; /** * Polynomial regular ring pseudo reduction sequential use algorithm. Implements * fraction free normalform algorithm. * @param coefficient type * @author Heinz Kredel */ public class RPseudoReductionSeq> extends RReductionSeq implements RPseudoReduction { private static final Logger logger = LogManager.getLogger(RPseudoReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public RPseudoReductionSeq() { } /** * Normalform using r-reduction. * @param Ap polynomial. * @param Pp polynomial list. * @return r-nf(Ap) with respect to Pp. */ @Override @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; //.abs(); m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a; C r = null; boolean mt = false; GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); //System.out.println("--a = " + a); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { C c = lbc[i]; //r = a.idempotent().multiply( c.idempotent() ); r = a.idempotentAnd(c); mt = !r.isZERO(); // && mt if (mt) { f = e.subtract(htl[i]); if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); if (a.isZERO()) { throw new ArithmeticException("a.isZERO()"); } } else { c = c.fillOne(); S = S.multiply(c); R = R.multiply(c); } Q = p[i].multiply(a, f); S = S.subtract(Q); f = S.leadingExpVector(); if (!e.equals(f)) { a = Ap.ring.coFac.getZERO(); break; } a = S.leadingBaseCoefficient(); } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.reductum(); } } return R; //.abs(); // not monic if not boolean closed } /** * Normalform using r-reduction. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ @SuppressWarnings("unchecked") public PseudoReductionEntry normalformFactor(List> Pp, GenPolynomial Ap) { if (Ap == null) { return null; } C mfac = Ap.ring.getONECoefficient(); PseudoReductionEntry pf = new PseudoReductionEntry(Ap, mfac); if (Pp == null || Pp.isEmpty()) { return pf; } if (Ap.isZERO()) { return pf; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; //.abs(); m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a; C r = null; boolean mt = false; GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); //System.out.println("--a = " + a); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { C c = lbc[i]; //r = a.idempotent().multiply( c.idempotent() ); r = a.idempotentAnd(c); mt = !r.isZERO(); // && mt if (mt) { f = e.subtract(htl[i]); if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); if (a.isZERO()) { throw new ArithmeticException("a.isZERO()"); } } else { c = c.fillOne(); S = S.multiply(c); R = R.multiply(c); mfac = mfac.multiply(c); } Q = p[i].multiply(a, f); S = S.subtract(Q); f = S.leadingExpVector(); if (!e.equals(f)) { a = Ap.ring.coFac.getZERO(); break; } a = S.leadingBaseCoefficient(); } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.reductum(); } } pf = new PseudoReductionEntry(R, mfac); //.abs(); // not monic if not boolean closed return pf; } /** * Normalform with recording. Note: Only meaningful if all divisions * are exact. Compute first the multiplication factor m with * normalform(Pp,Ap,m), then call this method with * normalform(row,Pp,m*Ap). * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @Override @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a, b; C r = null; boolean mt = false; GenPolynomial fac = null; GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { C c = lbc[i]; //r = a.idempotent().multiply( c.idempotent() ); r = a.idempotentAnd(c); //System.out.println("r = " + r); mt = !r.isZERO(); // && mt if (mt) { b = a.remainder(c); if (b.isZERO()) { a = a.divide(c); if (a.isZERO()) { throw new ArithmeticException("a.isZERO()"); } } else { c = c.fillOne(); S = S.multiply(c); R = R.multiply(c); } f = e.subtract(htl[i]); if (debug) { logger.info("red div = {}", f); } Q = p[i].multiply(a, f); S = S.subtract(Q); // not ok with reductum fac = row.get(i); if (fac == null) { fac = zero.sum(a, f); } else { fac = fac.sum(a, f); } row.set(i, fac); f = S.leadingExpVector(); if (!e.equals(f)) { a = Ap.ring.coFac.getZERO(); break; } a = S.leadingBaseCoefficient(); } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.reductum(); } } return R; //.abs(); // not monic if not boolean closed } /** * Normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial> normalformRecursive(List>> Pp, GenPolynomial> Ap) { throw new UnsupportedOperationException("not implemented"); } /* * -------- boolean closure stuff ----------------------------------------- * -------- is all in superclass */ } java-algebra-system-2.7.200/src/edu/jas/gbufd/RReduction.java000066400000000000000000000041471445075545500236750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import edu.jas.structure.RegularRingElem; import edu.jas.gb.Reduction; import edu.jas.poly.GenPolynomial; /** * Polynomial R Reduction interface. Defines additionally boolean closure * methods. * @param coefficient type * @author Heinz Kredel */ public interface RReduction> extends Reduction { /** * Is strong top reducible. Condition is idempotent(a) == idempotent(b), for * a=ldcf(A) and b=ldcf(B) and lt(B) | lt(A) for some B in F. * @param A polynomial. * @param P polynomial list. * @return true if A is string top reducible with respect to P. */ public boolean isStrongTopReducible(List> P, GenPolynomial A); /** * Is boolean closed, test if A == idempotent(ldcf(A)) A. * @param A polynomial. * @return true if A is boolean closed, else false. */ public boolean isBooleanClosed(GenPolynomial A); /** * Is boolean closed, test if all A in F are boolean closed. * @param F polynomial list. * @return true if F is boolean closed, else false. */ public boolean isBooleanClosed(List> F); /** * Boolean closure, compute idempotent(ldcf(A)) A. * @param A polynomial. * @return bc(A). */ public GenPolynomial booleanClosure(GenPolynomial A); /** * Boolean remainder, compute idemComplement(ldcf(A)) A. * @param A polynomial. * @return br(A) = A - bc(A). */ public GenPolynomial booleanRemainder(GenPolynomial A); /** * Reduced boolean closure, compute BC(A) for all A in F. * @param F polynomial list. * @return red(bc(F)) = bc(red(F)). */ public List> reducedBooleanClosure(List> F); /** * Reduced boolean closure, compute BC(A) modulo F. * @param A polynomial. * @param F polynomial list. * @return red(bc(A)). */ public List> reducedBooleanClosure(List> F, GenPolynomial A); } java-algebra-system-2.7.200/src/edu/jas/gbufd/RReductionSeq.java000066400000000000000000000533351445075545500243510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.ReductionAbstract; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RegularRingElem; /** * Polynomial Regular ring Reduction sequential use algorithm. Implements * normalform and boolean closure stuff. * @param coefficient type * @author Heinz Kredel */ public class RReductionSeq> extends ReductionAbstract implements RReduction { private static final Logger logger = LogManager.getLogger(RReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public RReductionSeq() { } /** * Is top reducible. Condition is a b != 0, for a=ldcf(A) and b=ldcf(B) and * lt(B) | lt(A) for some B in F. * @param A polynomial. * @param P polynomial list. * @return true if A is top reducible with respect to P. */ @Override public boolean isTopReducible(List> P, GenPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); C a = A.leadingBaseCoefficient(); a = a.idempotent(); for (GenPolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { C b = p.leadingBaseCoefficient(); //C r = a.multiply( b ); //C r = a.multiply( b.idempotent() ); C r = a.idempotentAnd(b); mt = !r.isZERO(); if (mt) { return true; } } } return false; } /** * Is strong top reducible. Condition is idempotent(a) == idempotent(b), for * a=ldcf(A) and b=ldcf(B) and lt(B) | lt(A) for some B in F. * @param A polynomial. * @param P polynomial list. * @return true if A is string top reducible with respect to P. */ public boolean isStrongTopReducible(List> P, GenPolynomial A) { if (P == null || P.isEmpty()) { return false; } if (A == null || A.isZERO()) { return false; } boolean mt = false; ExpVector e = A.leadingExpVector(); C a = A.leadingBaseCoefficient(); a = a.idempotent(); for (GenPolynomial p : P) { mt = e.multipleOf(p.leadingExpVector()); if (mt) { C b = p.leadingBaseCoefficient(); mt = a.equals(b.idempotent()); if (mt) { return true; } } } return false; } /** * Is in Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return true if Ap is in normalform with respect to Pp. */ @Override @SuppressWarnings("unchecked") public boolean isNormalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return true; } if (Ap == null || Ap.isZERO()) { return true; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = new GenPolynomial[l]; Map.Entry m; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; boolean mt = false; Map Am = Ap.getMap(); for (Map.Entry me : Am.entrySet()) { ExpVector e = me.getKey(); C a = me.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { //C r = a.multiply( lbc[i] ); //C r = a.idempotent().multiply( lbc[i].idempotent() ); C r = a.idempotentAnd(lbc[i]); mt = !r.isZERO(); if (mt) { return false; } } } } return true; } /** * Normalform using r-reduction. * @param Ap polynomial. * @param Pp polynomial list. * @return r-nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; //.abs(); m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a, b; C r = null; boolean mt = false; GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); if (debug) { if (a.isZERO()) { throw new RuntimeException("a.isZERO(): S = " + S); } } for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { //r = a.multiply( lbc[i] ); //r = a.idempotent().multiply( lbc[i].idempotent() ); r = a.idempotentAnd(lbc[i]); mt = !r.isZERO(); // && mt if (mt) { b = a.divide(lbc[i]); if (b.isZERO()) { // strange case in regular rings System.out.println("b == zero: r = " + r); continue; } f = e.subtract(htl[i]); //logger.info("red div = {}", f); Q = p[i].multiply(b, f); S = S.subtract(Q); // not ok with reductum f = S.leadingExpVector(); if (!e.equals(f)) { a = Ap.ring.coFac.getZERO(); break; } a = S.leadingBaseCoefficient(); } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.reductum(); } } return R; //.abs(); // not monic if not boolean closed } /** * GB criterium 4. Use only for commutative polynomial rings. Note: * Experimental version for r-Groebner bases. * @param A polynomial. * @param B polynomial. * @param e = lcm(ht(A),ht(B)) * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B, ExpVector e) { if (logger.isInfoEnabled()) { if (!A.ring.equals(B.ring)) { logger.error("rings equal"); } if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) { logger.error("GBCriterion4 not applicabable to SolvablePolynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); ExpVector g = ei.sum(ej); // boolean t = g == e ; ExpVector h = g.subtract(e); int s = h.signum(); if (s == 0) { // disjoint ht C a = A.leadingBaseCoefficient(); C b = B.leadingBaseCoefficient(); C d = a.multiply(b); if (d.isZERO()) { // a guess //System.out.println("d1 = " + d + ", a = " + a + ", b = " + b); return false; // can skip pair } } return true; //! ( s == 0 ); } /** * GB criterium 4. Use only for commutative polynomial rings. Note: * Experimental version for r-Groebner bases. * @param A polynomial. * @param B polynomial. * @return true if the S-polynomial(i,j) is required, else false. */ @Override public boolean criterion4(GenPolynomial A, GenPolynomial B) { if (logger.isInfoEnabled()) { if (A instanceof GenSolvablePolynomial || B instanceof GenSolvablePolynomial) { logger.error("GBCriterion4 not applicabable to SolvablePolynomials"); return true; } } ExpVector ei = A.leadingExpVector(); ExpVector ej = B.leadingExpVector(); ExpVector g = ei.sum(ej); ExpVector e = ei.lcm(ej); // boolean t = g == e ; ExpVector h = g.subtract(e); int s = h.signum(); if (s == 0) { // disjoint ht C a = A.leadingBaseCoefficient(); C b = B.leadingBaseCoefficient(); C d = a.multiply(b); if (d.isZERO()) { // a guess return false; // can skip pair } } return true; //! ( s == 0 ); } /** * Normalform with recording. * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return Ap - row*Pp = nf(Pp,Ap) , the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenPolynomial normalform(List> row, List> Pp, GenPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } int l; GenPolynomial[] P; synchronized (Pp) { l = Pp.size(); P = (GenPolynomial[]) new GenPolynomial[l]; //P = Pp.toArray(); for (int i = 0; i < Pp.size(); i++) { P[i] = Pp.get(i); } } //System.out.println("l = " + l); Map.Entry m; ExpVector[] htl = new ExpVector[l]; C[] lbc = (C[]) new RegularRingElem[l]; // want GenPolynomial[] p = (GenPolynomial[]) new GenPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; C a; C r = null; boolean mt = false; GenPolynomial fac = null; GenPolynomial zero = Ap.ring.getZERO(); GenPolynomial R = Ap.ring.getZERO(); GenPolynomial Q = null; GenPolynomial S = Ap; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) { //r = a.idempotent().multiply( lbc[i].idempotent() ); //r = a.multiply( lbc[i] ); r = a.idempotentAnd(lbc[i]); //System.out.println("r = " + r); mt = !r.isZERO(); // && mt if (mt) { a = a.divide(lbc[i]); if (a.isZERO()) { // strange case in regular rings System.out.println("b == zero: r = " + r); continue; } f = e.subtract(htl[i]); //logger.info("red div = {}", f); Q = p[i].multiply(a, f); S = S.subtract(Q); // not ok with reductum fac = row.get(i); if (fac == null) { fac = zero.sum(a, f); } else { fac = fac.sum(a, f); } row.set(i, fac); f = S.leadingExpVector(); if (!e.equals(f)) { a = Ap.ring.coFac.getZERO(); break; } a = S.leadingBaseCoefficient(); } } } if (!a.isZERO()) { //! mt ) { //logger.debug("irred"); R = R.sum(a, e); S = S.reductum(); } } return R; //.abs(); not for recording } /** * Irreducible set. May not be boolean closed. * @param Pp polynomial list. * @return a list P of polynomials which are in normalform wrt. P. */ @Override public List> irreducibleSet(List> Pp) { ArrayList> P = new ArrayList>(); if (Pp == null) { return null; } for (GenPolynomial a : Pp) { if (!a.isZERO()) { P.add(a); } } int l = P.size(); if (l <= 1) return P; int irr = 0; ExpVector e; ExpVector f; GenPolynomial a; logger.debug("irr = "); while (irr != l) { //a = P.get(0); a = P.remove(0); e = a.leadingExpVector(); a = normalform(P, a); // no not make monic because of boolean closure logger.debug(String.valueOf(irr)); if (a.isZERO()) { l--; if (l <= 1) { return P; } } else { f = a.leadingExpVector(); if (e.equals(f)) { // lbcf(a) eventually shorter // correct since longer coeffs can reduce shorter coeffs irr++; } else { irr = 0; } P.add(a); } } //System.out.println(); return P; } /* * -------- boolean closure stuff ----------------------------------------- */ /** * Is boolean closed, test if A == idempotent(ldcf(A)) A. * @param A polynomial. * @return true if A is boolean closed, else false. */ public boolean isBooleanClosed(GenPolynomial A) { if (A == null || A.isZERO()) { return true; } C a = A.leadingBaseCoefficient(); C i = a.idempotent(); GenPolynomial B = A.multiply(i); // better run idemAnd on coefficients if (A.equals(B)) { return true; } return false; } /** * Is boolean closed, test if all A in F are boolean closed. * @param F polynomial list. * @return true if F is boolean closed, else false. */ public boolean isBooleanClosed(List> F) { if (F == null || F.size() == 0) { return true; } for (GenPolynomial a : F) { if (a == null || a.isZERO()) { continue; } //System.out.println("a = " + a); if (!isBooleanClosed(a)) { return false; } } return true; } /** * Is reduced boolean closed, test if all A in F are boolean closed or br(A) * reduces to zero. * @param F polynomial list. * @return true if F is boolean closed, else false. */ public boolean isReducedBooleanClosed(List> F) { if (F == null || F.size() == 0) { return true; } GenPolynomial b; GenPolynomial r; for (GenPolynomial a : F) { //System.out.println("a = " + a); if (a == null) { continue; } while (!a.isZERO()) { if (!isBooleanClosed(a)) { b = booleanClosure(a); b = normalform(F, b); if (!b.isZERO()) { //F.contains(r) return false; } } r = booleanRemainder(a); r = normalform(F, r); if (!r.isZERO()) { //F.contains(r) return false; } //System.out.println("r = " + r); a = r; } } return true; } /** * Boolean closure, compute idempotent(ldcf(A)) A. * @param A polynomial. * @return bc(A). */ public GenPolynomial booleanClosure(GenPolynomial A) { if (A == null || A.isZERO()) { return A; } C a = A.leadingBaseCoefficient(); C i = a.idempotent(); GenPolynomial B = A.multiply(i); return B; } /** * Boolean remainder, compute idemComplement(ldcf(A)) A. * @param A polynomial. * @return br(A). */ public GenPolynomial booleanRemainder(GenPolynomial A) { if (A == null || A.isZERO()) { return A; } C a = A.leadingBaseCoefficient(); C i = a.idemComplement(); GenPolynomial B = A.multiply(i); return B; } /** * Boolean closure, compute BC(A) for all A in F. * @param F polynomial list. * @return bc(F). */ public List> booleanClosure(List> F) { if (F == null || F.size() == 0) { return F; } List> B = new ArrayList>(F.size()); for (GenPolynomial a : F) { if (a == null) { continue; } while (!a.isZERO()) { GenPolynomial b = booleanClosure(a); B.add(b); a = booleanRemainder(a); } } return B; } /** * Reduced boolean closure, compute BC(A) for all A in F. * @param F polynomial list. * @return red(bc(F)) = bc(red(F)). */ public List> reducedBooleanClosure(List> F) { if (F == null || F.size() == 0) { return F; } List> B = new ArrayList>(F); GenPolynomial a; GenPolynomial b; GenPolynomial c; int len = B.size(); for (int i = 0; i < len; i++) { // not B.size(), it changes a = B.remove(0); if (a == null) { continue; } while (!a.isZERO()) { //System.out.println("a = " + a); b = booleanClosure(a); //System.out.println("b = " + b); b = booleanClosure(normalform(B, b)); if (b.isZERO()) { break; } B.add(b); // adds as last c = a.subtract(b); // = BR(a mod B) //System.out.println("c = " + c); c = normalform(B, c); a = c; } } return B; } /** * Reduced boolean closure, compute BC(A) modulo F. * @param A polynomial. * @param F polynomial list. * @return red(bc(A)). */ public List> reducedBooleanClosure(List> F, GenPolynomial A) { List> B = new ArrayList>(); if (A == null || A.isZERO()) { return B; } GenPolynomial a = A; GenPolynomial b; GenPolynomial c; while (!a.isZERO()) { //System.out.println("a = " + a); b = booleanClosure(a); //System.out.println("b = " + b); b = booleanClosure(normalform(F, b)); if (b.isZERO()) { break; } B.add(b); // adds as last c = a.subtract(b); // = BR(a mod F) //System.out.println("c = " + c); c = normalform(F, c); //System.out.println("c = " + c); a = c; } return B; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SGBFactory.java000066400000000000000000000541151445075545500235620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.gb.OrderedMinPairlist; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.PairList; import edu.jas.gb.SGBProxy; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseParallel; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.gb.SolvableReductionSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; import edu.jas.structure.ValueFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; // import edu.jas.application.SolvableResidueRing; // package cycle /** * Solvable Groebner bases algorithms factory. Select appropriate Solvable * Groebner bases engine based on the coefficient types. *

* Usage: To create objects that implement the * SolvableGroebnerBase interface use the SGBFactory. * It will select an appropriate implementation based on the types of polynomial * coefficients C. The method to obtain an implementation is * getImplementation(). It returns an object of a class which * implements the SolvableGroebnerBase interface, more precisely an * object of abstract class SolvableGroebnerBaseAbstract. * *

 * SolvableGroebnerBase<CT> engine;
 * engine = SGBFactory.<CT> getImplementation(cofac);
 * c = engine.GB(A);
 * 
*

* For example, if the coefficient type is BigInteger, the usage looks like * *

 * BigInteger cofac = new BigInteger();
 * SolvableGroebnerBase<BigInteger> engine;
 * engine = SGBFactory.getImplementation(cofac);
 * c = engine.GB(A);
 * 
* * @author Heinz Kredel * * @see edu.jas.gb.GroebnerBase * @see edu.jas.gb.SolvableGroebnerBase * @see edu.jas.application.GBAlgorithmBuilder */ public class SGBFactory { private static final Logger logger = LogManager.getLogger(SGBFactory.class); private static final boolean debug = logger.isDebugEnabled(); /** * Protected factory constructor. */ protected SGBFactory() { } /** * Determine suitable implementation of GB algorithms, no factory case. * @return GB algorithm implementation for field coefficients. */ public static > SolvableGroebnerBaseAbstract getImplementation() { logger.warn("no coefficient factory given, assuming field coefficients"); SolvableGroebnerBaseAbstract bba = new SolvableGroebnerBaseSeq(); return bba; } /** * Determine suitable implementation of GB algorithms, case ModLong. * @param fac ModLongRing. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(ModLongRing fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case ModLong. * @param fac ModLongRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(ModLongRing fac, PairList pl) { SolvableGroebnerBaseAbstract bba; if (fac.isField()) { bba = new SolvableGroebnerBaseSeq(pl); } else { bba = new SolvableGroebnerBasePseudoSeq(fac, pl); } return bba; } /** * Determine suitable implementation of GB algorithms, case ModInteger. * @param fac ModIntegerRing. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(ModIntegerRing fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case ModInteger. * @param fac ModIntegerRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(ModIntegerRing fac, PairList pl) { SolvableGroebnerBaseAbstract bba; if (fac.isField()) { bba = new SolvableGroebnerBaseSeq(pl); } else { bba = new SolvableGroebnerBasePseudoSeq(fac, pl); } return bba; } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigInteger fac) { return getImplementation(fac, GBFactory.Algo.igb); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param a algorithm, a = igb, egb, dgb. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigInteger fac, GBFactory.Algo a) { return getImplementation(fac, a, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigInteger fac, PairList pl) { return getImplementation(fac, GBFactory.Algo.igb, pl); } /** * Determine suitable implementation of GB algorithms, case BigInteger. * @param fac BigInteger. * @param a algorithm, a = igb, egb, dgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigInteger fac, GBFactory.Algo a, PairList pl) { SolvableGroebnerBaseAbstract bba; switch (a) { case igb: bba = new SolvableGroebnerBasePseudoSeq(fac, pl); break; case egb: throw new UnsupportedOperationException("egb algorithm not available for BigInteger " + a); case dgb: throw new UnsupportedOperationException("dgb algorithm not available for BigInteger " + a); default: throw new IllegalArgumentException("algorithm not available for BigInteger " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigRational fac) { return getImplementation(fac, GBFactory.Algo.qgb); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param a algorithm, a = qgb, ffgb. * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigRational fac, GBFactory.Algo a) { return getImplementation(fac, a, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigRational fac, PairList pl) { return getImplementation(fac, GBFactory.Algo.qgb, pl); } /** * Determine suitable implementation of GB algorithms, case BigRational. * @param fac BigRational. * @param a algorithm, a = qgb, ffgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static SolvableGroebnerBaseAbstract getImplementation(BigRational fac, GBFactory.Algo a, PairList pl) { SolvableGroebnerBaseAbstract bba; switch (a) { case qgb: bba = new SolvableGroebnerBaseSeq(pl); break; case ffgb: throw new UnsupportedOperationException("ffgb algorithm not available for BigRational " + a); //PairList pli; //if (pl instanceof OrderedMinPairlist) { // pli = new OrderedMinPairlist(); //} else if (pl instanceof OrderedSyzPairlist) { // pli = new OrderedSyzPairlist(); //} else { // pli = new OrderedPairlist(); //} //bba = new SolvableGroebnerBaseRational(pli); // pl not possible //break; default: throw new IllegalArgumentException( "algorithm not available for " + fac.toScriptFactory() + ", Algo = " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( QuotientRing fac) { return getImplementation(fac, GBFactory.Algo.qgb); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param a algorithm, a = qgb, ffgb. * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( QuotientRing fac, GBFactory.Algo a) { return getImplementation(fac, a, new OrderedPairlist>()); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( QuotientRing fac, PairList> pl) { return getImplementation(fac, GBFactory.Algo.qgb, pl); } /** * Determine suitable implementation of GB algorithms, case Quotient * coefficients. * @param fac QuotientRing. * @param a algorithm, a = qgb, ffgb. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( QuotientRing fac, GBFactory.Algo a, PairList> pl) { SolvableGroebnerBaseAbstract> bba; logger.info("QuotientRing, fac = {}", fac); switch (a) { case qgb: bba = new SolvableGroebnerBaseSeq>(new SolvableReductionSeq>(), pl); break; case ffgb: throw new UnsupportedOperationException("ffgb algorithm not available for " + a); //PairList> pli; //if (pl instanceof OrderedMinPairlist) { // pli = new OrderedMinPairlist>(); //} else if (pl instanceof OrderedSyzPairlist) { // pli = new OrderedSyzPairlist>(); //} else { // pli = new OrderedPairlist>(); //} //bba = new SolvableGroebnerBaseQuotient(fac, pli); // pl not possible //break; default: throw new IllegalArgumentException("algorithm not available for Quotient " + a); } return bba; } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( GenPolynomialRing fac) { return getImplementation(fac, GBFactory.Algo.igb); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param a algorithm, a = igb or egb, dgb if fac is univariate over a * field. * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, GBFactory.Algo a) { return getImplementation(fac, a, new OrderedPairlist>()); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, PairList> pl) { return getImplementation(fac, GBFactory.Algo.igb, pl); } /** * Determine suitable implementation of GB algorithms, case (recursive) * polynomial. * @param fac GenPolynomialRing<C>. * @param a algorithm, a = igb or egb, dgb if fac is univariate over a * field. * @param pl pair selection strategy * @return GB algorithm implementation. */ public static > SolvableGroebnerBaseAbstract> getImplementation( GenPolynomialRing fac, GBFactory.Algo a, PairList> pl) { SolvableGroebnerBaseAbstract> bba; switch (a) { case igb: bba = new SolvableGroebnerBasePseudoRecSeq(fac, pl); break; case egb: throw new UnsupportedOperationException("egb algorithm not available for " + a); //if (fac.nvar > 1 || !fac.coFac.isField()) { // throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac); //} //bba = new ESolvableGroebnerBaseSeq>(); // pl not suitable //break; case dgb: throw new UnsupportedOperationException("dgb algorithm not available for " + a); //if (fac.nvar > 1 || !fac.coFac.isField()) { // throw new IllegalArgumentException("coefficients not univariate or not over a field" + fac); //} //bba = new DSolvableGroebnerBaseSeq>(); // pl not suitable //break; default: throw new IllegalArgumentException("algorithm not available for GenPolynomial " + a); } return bba; } /* * Determine suitable implementation of GB algorithms, case regular rings. * @param fac RegularRing. * @return GB algorithm implementation. public static > SolvableGroebnerBaseAbstract> getImplementation( ProductRing fac) { SolvableGroebnerBaseAbstract> bba; if (fac.onlyFields()) { bba = new RSolvableGroebnerBaseSeq>(); } else { bba = new RSolvableGroebnerBasePseudoSeq>(fac); } return bba; } */ /** * Determine suitable implementation of GB algorithms, other cases. * @param fac RingFactory<C>. * @return GB algorithm implementation. */ public static > // interface RingElem not sufficient SolvableGroebnerBaseAbstract getImplementation(RingFactory fac) { return getImplementation(fac, new OrderedPairlist()); } /** * Determine suitable implementation of GB algorithms, other cases. * @param fac RingFactory<C>. * @param pl pair selection strategy * @return GB algorithm implementation. */ @SuppressWarnings({ "cast", "unchecked" }) public static > // interface RingElem not sufficient SolvableGroebnerBaseAbstract getImplementation(RingFactory fac, PairList pl) { logger.debug("fac = {}", fac.getClass().getName()); // + ", fac = {}", fac.toScript()); if (fac.isField()) { return new SolvableGroebnerBaseSeq(pl); } if (fac instanceof ValueFactory) { return new SolvableGroebnerBasePseudoSeq(fac, pl); } if (fac instanceof QuotPairFactory) { return new SolvableGroebnerBaseSeq(pl); } SolvableGroebnerBaseAbstract bba = null; Object ofac = fac; if (ofac instanceof GenPolynomialRing) { PairList> pli; if (pl instanceof OrderedMinPairlist) { pli = new OrderedMinPairlist>(); } else if (pl instanceof OrderedSyzPairlist) { pli = new OrderedSyzPairlist>(); } else { pli = new OrderedPairlist>(); } GenPolynomialRing rofac = (GenPolynomialRing) ofac; SolvableGroebnerBaseAbstract> bbr = new SolvableGroebnerBasePseudoRecSeq( rofac, pli); // not pl bba = (SolvableGroebnerBaseAbstract) bbr; //} else if (ofac instanceof ProductRing) { // ProductRing pfac = (ProductRing) ofac; // if (pfac.onlyFields()) { // bba = new RSolvableGroebnerBaseSeq>(); // } else { // bba = new RSolvableGroebnerBasePseudoSeq>(pfac); // } } else { bba = new SolvableGroebnerBasePseudoSeq(fac, pl); } logger.info("bba = {}", bba.getClass().getName()); return bba; } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @return GB proxy algorithm implementation. */ public static > // interface RingElem not sufficient SolvableGroebnerBaseAbstract getProxy(RingFactory fac) { return getProxy(fac, new OrderedPairlist()); } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @param pl pair selection strategy * @return GB proxy algorithm implementation. */ @SuppressWarnings({ "unchecked" }) public static > // interface RingElem not sufficient SolvableGroebnerBaseAbstract getProxy(RingFactory fac, PairList pl) { if (ComputerThreads.NO_THREADS) { return SGBFactory. getImplementation(fac, pl); } logger.debug("proxy fac = {}", fac.getClass().getName()); int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2); if (fac.isField()) { SolvableGroebnerBaseAbstract e1 = new SolvableGroebnerBaseSeq(pl); SolvableGroebnerBaseAbstract e2 = new SolvableGroebnerBaseParallel(th, pl); return new SGBProxy(e1, e2); } else if (fac.characteristic().signum() == 0) { if (fac instanceof GenPolynomialRing) { GenPolynomialRing pfac = (GenPolynomialRing) fac; OrderedPairlist ppl = new OrderedPairlist>(); SolvableGroebnerBaseAbstract e1 = new SolvableGroebnerBasePseudoRecSeq(pfac, ppl); logger.warn("no parallel version available, returning sequential version"); return e1; //SolvableGroebnerBaseAbstract e2 = new SolvableGroebnerBasePseudoRecParallel(th, pfac, ppl); //return new SGBProxy(e1, e2); } SolvableGroebnerBaseAbstract e1 = new SolvableGroebnerBasePseudoSeq(fac, pl); logger.warn("no parallel version available, returning sequential version"); return e1; //SolvableGroebnerBaseAbstract e2 = new SolvableGroebnerBasePseudoParallel(th, fac, pl); //return new SGBProxy(e1, e2); } return getImplementation(fac, pl); } /** * Determine suitable parallel/concurrent implementation of GB algorithms if * possible. * @param fac RingFactory<C>. * @return GB proxy algorithm implementation. */ public static > // interface RingElem not sufficient SolvableGroebnerBaseAbstract> getProxy(GenPolynomialRing fac) { if (ComputerThreads.NO_THREADS) { //return SGBFactory.> getImplementation(fac); return SGBFactory.getImplementation(fac); } logger.debug("fac = {}", fac.getClass().getName()); //int th = (ComputerThreads.N_CPUS > 2 ? ComputerThreads.N_CPUS - 1 : 2); OrderedPairlist> ppl = new OrderedPairlist>(); SolvableGroebnerBaseAbstract> e1 = new SolvableGroebnerBasePseudoRecSeq(fac, ppl); logger.warn("no parallel version available, returning sequential version"); return e1; //SolvableGroebnerBaseAbstract> e2 = new SolvableGroebnerBasePseudoRecParallel(th, fac, ppl); //return new SGBProxy>(e1, e2); //return new SGBProxy(e1, e2); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvableGroebnerBasePseudoRecSeq.java000066400000000000000000000450431445075545500301300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.gb.SolvableExtendedGB; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.ufd.GreatestCommonDivisorFake; /** * Solvable Groebner Base with pseudo reduction sequential algorithm. Implements * coefficient fraction free Groebner bases. Coefficients can for example be * (commutative) multivariate polynomials. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class SolvableGroebnerBasePseudoRecSeq> extends SolvableGroebnerBaseAbstract> { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBasePseudoRecSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final SolvablePseudoReduction sredRec; /** * Pseudo reduction engine. */ protected final SolvablePseudoReduction> sred; /** * Coefficient ring factory. */ //protected final RingFactory cofac; protected final GenPolynomialRing cofac; /** * Constructor. * @param rf coefficient ring factory. */ public SolvableGroebnerBasePseudoRecSeq(RingFactory> rf) { this(rf, new SolvablePseudoReductionSeq()); } /** * Constructor. * @param rf coefficient ring factory. * @param pl pair selection strategy */ public SolvableGroebnerBasePseudoRecSeq(RingFactory> rf, PairList> pl) { this(rf, new SolvablePseudoReductionSeq(), pl); } /** * Constructor. * @param rf coefficient ring factory. * @param red pseudo reduction engine. Note: red must be an instance * of PseudoReductionSeq. */ public SolvableGroebnerBasePseudoRecSeq(RingFactory> rf, SolvablePseudoReduction red) { this(rf, red, new OrderedPairlist>()); } /** * Constructor. * @param rf coefficient ring factory. * @param red pseudo reduction engine. Note: red must be an instance * of PseudoReductionSeq. * @param pl pair selection strategy */ @SuppressWarnings("unchecked") public SolvableGroebnerBasePseudoRecSeq(RingFactory> rf, SolvablePseudoReduction red, PairList> pl) { super((SolvablePseudoReduction>) (SolvablePseudoReduction) red, pl); this.sred = (SolvablePseudoReduction>) (SolvablePseudoReduction) red; sredRec = red; //this.red = sred; GenSolvablePolynomialRing> ring = (GenSolvablePolynomialRing>) pl.getRing(); cofac = (GenPolynomialRing) rf; if (!cofac.isCommutative()) { logger.warn("right reduction not correct for {}", cofac); //.toScript() engine = new GreatestCommonDivisorFake(); } else if (ring instanceof QLRSolvablePolynomialRing) { // others ? // check that also coeffTable is empty for recursive solvable poly ring QLRSolvablePolynomialRing qring = (QLRSolvablePolynomialRing) ring; RecSolvablePolynomialRing rring = qring.polCoeff; if (!rring.coeffTable.isEmpty()) { logger.warn("right reduction not correct for {}", rring.coeffTable); engine = new GreatestCommonDivisorFake(); // only for Ore conditions } else { engine = GCDFactory. getImplementation(cofac.coFac); } } else { engine = GCDFactory. getProxy(cofac.coFac); } } /** * Left Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List>> leftGB(int modv, List>> F) { List>> G = normalizeZerosOnes(F); G = PolynomialList.> castToSolvableList(PolyUtil. monicRec(engine .recursivePrimitivePart(PolynomialList.> castToList(G)))); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing> ring = G.get(0).ring; if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList> pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.> castToList(G)); logger.info("leftGB start {}", pairlist); Pair> pair; GenSolvablePolynomial> pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) continue; pi = (GenSolvablePolynomial>) pair.pi; pj = (GenSolvablePolynomial>) pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", S.leadingExpVector()); } H = sredRec.leftNormalformRecursive(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector() + ", #(H) = {}", H.length()); } H = (GenSolvablePolynomial>) engine.recursivePrimitivePart(H); H = PolyUtil. monic(H); if (H.isConstant()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("lc(pp(H)) = {}", H.leadingBaseCoefficient().toScript()); } if (H.length() > 0) { G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("leftGB end {}", pairlist); return G; } /** * Minimal ordered Solvable Groebner basis. * @param Gp a Solvable Groebner base. * @return a reduced Solvable Groebner base of Gp. */ @Override public List>> leftMinimalGB( List>> Gp) { List>> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenSolvablePolynomial> a; List>> F = new ArrayList>>( G.size()); while (G.size() > 0) { a = G.remove(0); if (sred.isTopReducible(G, a) || sred.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List>> ff; ff = new ArrayList>>(G); ff.addAll(F); a = sredRec.leftNormalformRecursive(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int i = 0; while (i < len) { a = G.remove(0); //System.out.println("doing " + a.length()); a = sredRec.leftNormalformRecursive(G, a); a = (GenSolvablePolynomial>) engine.recursivePrimitivePart(a); //a.monic(); not possible a = PolyUtil. monic(a); G.add(a); // adds as last i++; } return G; } /** * Twosided Solvable Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ @Override public List>> twosidedGB(int modv, List>> Fp) { List>> G = normalizeZerosOnes(Fp); G = PolynomialList.> castToSolvableList(PolyUtil. monicRec(engine .recursivePrimitivePart(PolynomialList.> castToList(G)))); if (G.size() < 1) { // two-sided! return G; } //System.out.println("G = " + G); GenSolvablePolynomialRing> ring = G.get(0).ring; // assert != null if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } // add also coefficient generators List>> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List>> F = new ArrayList>>( G.size() * (1 + X.size())); F.addAll(G); GenSolvablePolynomial> p, x, q; for (int i = 0; i < F.size(); i++) { // F changes p = F.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } q = p.multiply(x); q = sredRec.leftNormalformRecursive(F, q); if (!q.isZERO()) { q = (GenSolvablePolynomial>) engine.recursivePrimitivePart(q); q = PolyUtil. monic(q); F.add(q); } } } G = F; //System.out.println("G generated = " + G); PairList> pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList.> castToList(G)); logger.info("twosidedGB start {}", pairlist); Pair> pair; GenSolvablePolynomial> pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) { continue; } pi = (GenSolvablePolynomial>) pair.pi; pj = (GenSolvablePolynomial>) pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", S.leadingExpVector()); } H = sredRec.leftNormalformRecursive(G, S); if (H.isZERO()) { pair.setZero(); continue; } if (debug) { logger.info("ht(H) = {}", H.leadingExpVector()); } H = (GenSolvablePolynomial>) engine.recursivePrimitivePart(H); H = PolyUtil. monic(H); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("lc(pp(H)) = {}", H.leadingBaseCoefficient()); } if (H.length() > 0) { G.add(H); pairlist.put(H); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } p = H.multiply(x); p = sredRec.leftNormalformRecursive(G, p); if (!p.isZERO()) { p = (GenSolvablePolynomial>) engine.recursivePrimitivePart(p); p = PolyUtil. monic(p); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads are activated } G.add(p); pairlist.put(p); } } } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("twosidedGB end {}", pairlist); return G; } /** * Left Groebner base test. * @param modv number of module variables. * @param F solvable polynomial list. * @return true, if F is a left Groebner base, else false. */ @Override public boolean isLeftGBsimple(int modv, List>> F) { //System.out.println("F to left check = " + F); GenSolvablePolynomial> pi, pj, s, h; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } s = sred.leftSPolynomial(pi, pj); if (s.isZERO()) { continue; } h = sredRec.leftNormalformRecursive(F, s); if (!h.isZERO()) { return false; } } } return true; } /** * Left Groebner base idempotence test. * @param modv module variable number. * @param F solvable polynomial list. * @return true, if F is equal to GB(F), else false. */ @Override public boolean isLeftGBidem(int modv, List>> F) { if (F == null || F.isEmpty()) { return true; } GenSolvablePolynomialRing> pring = F.get(0).ring; List>> G = leftGB(modv, F); PolynomialList> Fp = new PolynomialList>(pring, F); PolynomialList> Gp = new PolynomialList>(pring, G); return Fp.compareTo(Gp) == 0; } /** * Twosided Groebner base test. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return true, if Fp is a two-sided Groebner base, else false. */ @Override public boolean isTwosidedGB(int modv, List>> Fp) { //System.out.println("F to twosided check = " + Fp); if (Fp == null || Fp.size() == 0) { // 0 not 1 return true; } GenSolvablePolynomialRing> ring = Fp.get(0).ring; // assert != null //List> X = generateUnivar( modv, Fp ); List>> X, Y; X = PolynomialList.castToSolvableList(ring.generators()); // modv used below Y = new ArrayList>>(); for (GenSolvablePolynomial> x : X) { if (x.isConstant()) { Y.add(x); } } X = Y; X.addAll(ring.univariateList(modv)); logger.info("right multipliers = {}", X); List>> F = new ArrayList>>( Fp.size() * (1 + X.size())); F.addAll(Fp); GenSolvablePolynomial> p, x, pi, pj, s, h; for (int i = 0; i < Fp.size(); i++) { p = Fp.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); if (x.isONE()) { continue; } p = p.multiply(x); p = sredRec.leftNormalformRecursive(F, p); if (!p.isZERO()) { return false; //F.add(p); } } } //System.out.println("F to check = " + F); for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } s = sred.leftSPolynomial(pi, pj); if (s.isZERO()) { continue; } h = sredRec.leftNormalformRecursive(F, s); if (!h.isZERO()) { logger.info("is not TwosidedGB: {}", h); return false; } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvableGroebnerBasePseudoSeq.java000066400000000000000000000303251445075545500274730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.OrderedPairlist; import edu.jas.gb.Pair; import edu.jas.gb.PairList; import edu.jas.gb.SolvableExtendedGB; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.QuotPair; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.ufd.GreatestCommonDivisorFake; /** * Solvable Groebner Base with pseudo reduction sequential algorithm. Implements * coefficient fraction free Groebner bases. Coefficients can for example be * integers or (commutative) univariate polynomials. * @param coefficient type * @author Heinz Kredel * * @see edu.jas.application.GBAlgorithmBuilder * @see edu.jas.gbufd.GBFactory */ public class SolvableGroebnerBasePseudoSeq> extends SolvableGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(SolvableGroebnerBasePseudoSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Pseudo reduction engine. */ protected final SolvablePseudoReduction sred; /** * Coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param rf coefficient ring factory. */ public SolvableGroebnerBasePseudoSeq(RingFactory rf) { this(new SolvablePseudoReductionSeq(), rf, new OrderedPairlist()); } /** * Constructor. * @param rf coefficient ring factory. * @param pl pair selection strategy */ public SolvableGroebnerBasePseudoSeq(RingFactory rf, PairList pl) { this(new SolvablePseudoReductionSeq(), rf, pl); } /** * Constructor. * @param red pseudo reduction engine. Note: red must be an instance * of PseudoReductionSeq. * @param rf coefficient ring factory. * @param pl pair selection strategy */ @SuppressWarnings("unchecked") public SolvableGroebnerBasePseudoSeq(SolvablePseudoReduction red, RingFactory rf, PairList pl) { super(red, pl); this.sred = red; GenSolvablePolynomialRing ring = (GenSolvablePolynomialRing) pl.getRing(); cofac = rf; if (!cofac.isCommutative()) { logger.warn("right reduction not correct for {}", cofac); //.toScript() engine = new GreatestCommonDivisorFake(); // only for Ore conditions //System.out.println("stack trace = "); //Exception e = new RuntimeException("get stack trace"); //e.printStackTrace(); } else if (ring instanceof QLRSolvablePolynomialRing) { // others ? // check that also coeffTable is empty for recursive solvable poly ring QLRSolvablePolynomialRing qring = (QLRSolvablePolynomialRing) ring; RecSolvablePolynomialRing rring = qring.polCoeff; if (!rring.coeffTable.isEmpty()) { logger.warn("right reduction not correct for {}", rring.coeffTable); engine = new GreatestCommonDivisorFake(); // only for Ore conditions } else { engine = GCDFactory. getImplementation(cofac); } } else { engine = GCDFactory. getProxy(cofac); } } /** * Left Groebner base using pairlist class. * @param modv module variable number. * @param F polynomial list. * @return GB(F) a Groebner base of F. */ @Override public List> leftGB(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PolynomialList. castToSolvableList(engine.basePrimitivePart(PolynomialList. castToList(G))); if (G.size() <= 1) { return G; } GenSolvablePolynomialRing ring = G.get(0).ring; if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList. castToList(G)); Pair pair; GenSolvablePolynomial pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) continue; pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } logger.debug("ht(S) = {}", S.leadingExpVector()); H = sred.leftNormalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } logger.debug("ht(H) = {}", H.leadingExpVector()); H = (GenSolvablePolynomial) engine.basePrimitivePart(H); H = (GenSolvablePolynomial) H.abs(); if (H.isConstant()) { G.clear(); G.add(H); return G; // since no threads are activated } logger.debug("H = {}", H); if (H.length() > 0) { G.add(H); pairlist.put(H); } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("{}", pairlist); return G; } /** * Minimal ordered Solvable Groebner basis. * @param Gp a Solvable Groebner base. * @return a reduced Solvable Groebner base of Gp. */ @Override public List> leftMinimalGB(List> Gp) { List> G = normalizeZerosOnes(Gp); if (G.size() <= 1) { return G; } // remove top reducible polynomials GenSolvablePolynomial a; List> F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (sred.isTopReducible(G, a) || sred.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List> ff; ff = new ArrayList>(G); ff.addAll(F); a = sred.leftNormalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } Collections.reverse(G); // important for lex GB // reduce remaining polynomials int len = G.size(); int i = 0; while (i < len) { a = G.remove(0); //System.out.println("doing " + a.length()); a = sred.leftNormalform(G, a); a = (GenSolvablePolynomial) engine.basePrimitivePart(a); //a.monic(); not possible a = (GenSolvablePolynomial) a.abs(); //a = sred.normalform( F, a ); G.add(a); // adds as last i++; } return G; } /** * Twosided Solvable Groebner base using pairlist class. * @param modv number of module variables. * @param Fp solvable polynomial list. * @return tsGB(Fp) a twosided Groebner base of Fp. */ @Override public List> twosidedGB(int modv, List> Fp) { List> G = normalizeZerosOnes(Fp); G = PolynomialList. castToSolvableList(engine.basePrimitivePart(PolynomialList. castToList(G))); if (G.size() < 1) { // two-sided! return G; } //System.out.println("G = " + G); GenSolvablePolynomialRing ring = G.get(0).ring; // assert != null if (ring.coFac.isField()) { // remove ? throw new IllegalArgumentException("coefficients from a field"); } // add also coefficient generators List> X; X = PolynomialList.castToSolvableList(ring.generators(modv)); logger.info("right multipliers = {}", X); List> F = new ArrayList>(G.size() * (1 + X.size())); F.addAll(G); logger.info("right multiply: F = {}", F); GenSolvablePolynomial p, x, q; for (int i = 0; i < F.size(); i++) { // F changes p = F.get(i); for (int j = 0; j < X.size(); j++) { x = X.get(j); q = p.multiply(x); logger.info("right multiply: p = {}, x = {}, q = {}", p, x, q); q = sred.leftNormalform(F, q); if (!q.isZERO()) { q = (GenSolvablePolynomial) engine.basePrimitivePart(q); q = (GenSolvablePolynomial) q.abs(); logger.info("right multiply: red(q) = {}", q); F.add(q); } } } G = F; //System.out.println("G generated = " + G); PairList pairlist = strategy.create(modv, ring); pairlist.put(PolynomialList. castToList(G)); Pair pair; GenSolvablePolynomial pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); if (pair == null) { continue; } pi = (GenSolvablePolynomial) pair.pi; pj = (GenSolvablePolynomial) pair.pj; if (debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = sred.leftSPolynomial(pi, pj); if (S.isZERO()) { pair.setZero(); continue; } logger.debug("ht(S) = {}", S.leadingExpVector()); H = sred.leftNormalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } logger.debug("ht(H) = {}", H.leadingExpVector()); H = (GenSolvablePolynomial) engine.basePrimitivePart(H); H = (GenSolvablePolynomial) H.abs(); if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } logger.debug("H = {}", H); if (H.length() > 0) { G.add(H); pairlist.put(H); for (int j = 0; j < X.size(); j++) { x = X.get(j); p = H.multiply(x); p = sred.leftNormalform(G, p); if (!p.isZERO()) { p = (GenSolvablePolynomial) engine.basePrimitivePart(p); p = (GenSolvablePolynomial) p.abs(); if (p.isONE()) { G.clear(); G.add(p); return G; // since no threads are activated } G.add(p); pairlist.put(p); } } } } logger.debug("#sequential list = {}", G.size()); G = leftMinimalGB(G); logger.info("{}", pairlist); return G; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvablePseudoReduction.java000066400000000000000000000037461445075545500264270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import edu.jas.gb.SolvableReduction; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.structure.RingElem; /** * Polynomial pseudo reduction interface. Defines additionally normalformFactor * and normalformRecursive. * @param coefficient type. * @author Heinz Kredel */ public interface SolvablePseudoReduction> extends SolvableReduction { /** * Left normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ public PseudoReductionEntry leftNormalformFactor(List> Pp, GenSolvablePolynomial Ap); /** * Right normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ public PseudoReductionEntry rightNormalformFactor(List> Pp, GenSolvablePolynomial Ap); /** * Left normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ public GenSolvablePolynomial> leftNormalformRecursive( List>> Pp, GenSolvablePolynomial> Ap); /** * Right normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ public GenSolvablePolynomial> rightNormalformRecursive( List>> Pp, GenSolvablePolynomial> Ap); } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvablePseudoReductionSeq.java000066400000000000000000001010241445075545500270640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.SolvableReductionAbstract; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; /** * Polynomial pseudo reduction sequential use algorithm. Coefficients of * polynomials must not be from a field, i.e. the fraction free reduction is * implemented. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class SolvablePseudoReductionSeq> extends SolvableReductionAbstract implements SolvablePseudoReduction { private static final Logger logger = LogManager.getLogger(SolvablePseudoReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public SolvablePseudoReductionSeq() { } /** * Left normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry m; GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); Q = p[i].multiplyLeft(e); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { // && !c.isConstant()) { a = a.divide(c); S = S.subtractMultiple(a, Q); } else { R = R.multiplyLeft(c); S = S.scaleSubtractMultiple(c, a, Q); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("g==h: g = {}, c = {}", g, c); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c); } } } return R; } /** * Left normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings({ "unchecked" }) public GenSolvablePolynomial> leftNormalformRecursive( List>> Pp, GenSolvablePolynomial> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry> m; GenSolvablePolynomial>[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //GenPolynomial[] lbc = (GenPolynomial[]) new GenPolynomial[l]; GenSolvablePolynomial>[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; GenPolynomial a, b; boolean mt = false; GenSolvablePolynomialRing> ring = Ap.ring; final boolean commCoeff = ring.coFac.isCommutative(); final SolvableSyzygyAbstract ssy; if (commCoeff) { ssy = null; } else { ssy = new SolvableSyzygySeq(((GenPolynomialRing) ring.coFac).coFac); } GenSolvablePolynomial> R = Ap.ring.getZERO().copy(); GenSolvablePolynomial> Q = null; GenSolvablePolynomial> S = Ap.copy(); //GenSolvablePolynomial> Sp = null; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { f = e.subtract(htl[i]); if (debug) { logger.info("red div = {}", f); //logger.info("red a = {}", a); } Q = p[i].multiplyLeft(f); //if (a.remainder(c).isZERO()) { //c.isUnit() ) { ExpVector g = S.leadingExpVector(); GenPolynomial ap = a; if (commCoeff) { GenPolynomial c = Q.leadingBaseCoefficient(); if (!c.isConstant() && PolyUtil. baseSparsePseudoRemainder(a, c).isZERO()) { //a = a.divide(c); b = PolyUtil. basePseudoDivide(a, c); if (a.equals(b.multiply(c))) { S = S.subtractMultiple(b, Q); } else { R = R.multiplyLeft(c); S = S.scaleSubtractMultiple(c, a, Q); } } else { R = R.multiplyLeft(c); S = S.scaleSubtractMultiple(c, a, Q); } } else { // use Ore condition GenSolvablePolynomial cs = (GenSolvablePolynomial) Q.leadingBaseCoefficient(); GenSolvablePolynomial as = (GenSolvablePolynomial) a; GenPolynomial[] ore = ssy.leftOreCond(cs, as); //System.out.println("cs = " + cs + ", as = " + as); //System.out.println("ore[0] = " + ore[0] + "\nore[1] = " + ore[1]); R = R.multiplyLeft(ore[1]); S = S.scaleSubtractMultiple(ore[1], ore[0], Q); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // ! Ore cond logger.info("g==h: g = {}", g); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap); } } } //System.out.println("Ap = " + Ap + ", R = " + R); return R; } /** * Left normalform with recording. Note: Only meaningful if all * divisions are exact. Compute first the multiplication factor * mf with (nf,mf) = normalformfactor(Pp,Ap), then * call this method with normalform(row,Pp,mf*Ap). * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial leftNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { if (row == null || Pp == null || Ap == null) { throw new IllegalArgumentException("row, Pp or Ap == null not supported"); } if (Pp.isEmpty()) { return Ap; } if (Ap.isZERO()) { return Ap; } GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial fac = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); //throw new RuntimeException("Syzygy no GB"); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); Q = p[i].multiplyLeft(e); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); S = S.subtractMultiple(a, Q); //System.out.print("|"); } else { //System.out.print("*"); R = R.multiplyLeft(c); S = S.scaleSubtractMultiple(c, a, Q); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled System.out.println("g = " + g + ", h = " + h); System.out.println("c*ap = " + c.multiply(ap) + ", ap*c = " + ap.multiply(c)); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); fac = row.get(i); if (fac == null) { fac = (GenSolvablePolynomial) zero.sum(a, e); } else { // doAddTo ?? fac = (GenSolvablePolynomial) fac.sum(a, e); } row.set(i, fac); } } return R; } /** * Left normalform with factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ @SuppressWarnings("unchecked") public PseudoReductionEntry leftNormalformFactor(List> Pp, GenSolvablePolynomial Ap) { if (Ap == null) { return null; } C mfactor = Ap.ring.getONECoefficient(); PseudoReductionEntry pf = new PseudoReductionEntry(Ap, mfactor); if (Pp == null || Pp.isEmpty()) { return pf; } if (Ap.isZERO()) { return pf; } Map.Entry m; GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); Q = p[i].multiplyLeft(e); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { a = a.divide(c); S = S.subtractMultiple(a, Q); } else { mfactor = c.multiply(mfactor); // left R = R.multiplyLeft(c); S = S.scaleSubtractMultiple(c, a, Q); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("g==h: g = {}, c = {}", g, c); throw new RuntimeException("g==h: a = " + a + ", ap = " + ap); } } } logger.info("multiplicative factor = {}", mfactor); pf = new PseudoReductionEntry(R, mfactor); return pf; } /** * Right normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightNormalform(List> Pp, GenSolvablePolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } Map.Entry m; GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); // need pi * a * e, but only pi * e * a or a * pi * e available Q = p[i].multiply(e); assert Q.multiply(a).equals(Q.multiplyLeft(a)); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { a = a.divide(c); // left? //S = S.subtractMultiple(Q,a); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); } else { R = R.multiply(c); //S = S.scaleSubtractMultiple(c, Q, a); S = S.multiply(c); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("g==h: g = {}, c = {}", g, c); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap); } } } //System.out.println("R = " + R); return R; } /** * Right normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial> rightNormalformRecursive( List>> Pp, GenSolvablePolynomial> Ap) { if (Pp == null || Ap == null) { throw new IllegalArgumentException("Pp or Ap == null not supported"); } //throw new UnsupportedOperationException(); if (Pp.isEmpty()) { return Ap; } if (Ap.isZERO()) { return Ap; } Map.Entry> m; GenSolvablePolynomial>[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //GenPolynomial[] lbc = (GenPolynomial[]) new GenPolynomial[l]; GenSolvablePolynomial>[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e, f; GenPolynomial a, b; boolean mt = false; GenSolvablePolynomialRing> ring = Ap.ring; final boolean commCoeff = ring.coFac.isCommutative(); final SolvableSyzygyAbstract ssy; if (commCoeff) { ssy = null; } else { ssy = new SolvableSyzygySeq(((GenPolynomialRing) ring.coFac).coFac); } GenSolvablePolynomial> R = Ap.ring.getZERO().copy(); GenSolvablePolynomial> Q = null; GenSolvablePolynomial> S = Ap.copy(); //GenSolvablePolynomial> Sp = null; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { f = e.subtract(htl[i]); if (debug) { logger.info("red div = {}", f); //logger.info("red a = {}", a); } // need pi * a * e, but only pi * e * a or a * pi * e available Q = p[i].multiply(f); assert Q.multiply(a).equals(Q.multiplyLeft(a)); ExpVector g = S.leadingExpVector(); GenPolynomial ap = a; if (commCoeff) { GenPolynomial c = Q.leadingBaseCoefficient(); if (!c.isConstant() && PolyUtil. baseSparsePseudoRemainder(a, c).isZERO()) { //a = a.divide(c); b = PolyUtil. basePseudoDivide(a, c); if (a.equals(b.multiply(c))) { //S = S.subtractMultiple(b, Q); S = (GenSolvablePolynomial>) S.subtract(Q.multiply(b)); } else { R = R.multiply(c); //S = S.scaleSubtractMultiple(c, a, Q); S = S.multiply(c); S = (GenSolvablePolynomial>) S.subtract(Q.multiply(a)); } } else { R = R.multiply(c); //S = S.scaleSubtractMultiple(c, a, Q); S = S.multiply(c); S = (GenSolvablePolynomial>) S.subtract(Q.multiply(a)); } } else { // use Ore condition GenSolvablePolynomial cs = (GenSolvablePolynomial) Q.leadingBaseCoefficient(); GenSolvablePolynomial as = (GenSolvablePolynomial) a; GenPolynomial[] ore = ssy.rightOreCond(cs, as); //System.out.println("cs = " + cs + ", as = " + as); //System.out.println("ore[0] = " + ore[0] + "\nore[1] = " + ore[1]); R = R.multiply(ore[1]); //S = S.scaleSubtractMultiple(ore[1], ore[0], Q); S = S.multiply(ore[1]); S = (GenSolvablePolynomial>) S.subtract(Q.multiply(ore[0])); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("not Ore: g==h: g = {}", g); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap); } } } //System.out.println("Ap = " + Ap + ", R = " + R); return R; } /** * Right normalform with recording. Note: Only meaningful if all * divisions are exact. Compute first the multiplication factor * mf with (nf, mf) = * normalformfactor(Pp,Ap), then call this method with * normalform(row,Pp,mf*Ap). * @param row recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightNormalform(List> row, List> Pp, GenSolvablePolynomial Ap) { if (row == null || Pp == null || Ap == null) { throw new IllegalArgumentException("row, Pp or Ap == null not supported"); } //throw new UnsupportedOperationException(); if (Pp.isEmpty()) { return Ap; } if (Ap.isZERO()) { return Ap; } GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial zero = Ap.ring.getZERO(); GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial fac = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); //throw new RuntimeException("Syzygy no GB"); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); Q = p[i].multiply(e); assert Q.multiply(a).equals(Q.multiplyLeft(a)); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { //c.isUnit() ) { a = a.divide(c); //S = S.subtractMultiple(a, Q); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); //System.out.print("|"); } else { //System.out.print("*"); R = R.multiply(c); //S = S.scaleSubtractMultiple(c, a, Q); S = S.multiply(c); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("no Ore: g==h: g = {}, c = {}", g, c); System.out.println("c*ap = " + c.multiply(ap) + ", ap*c = " + ap.multiply(c)); throw new RuntimeException("g.equals(h): a = " + a + ", ap = " + ap + ", c = " + c); } //Q = p[i].multiply(a, e); //S = S.subtract(Q); fac = row.get(i); if (fac == null) { fac = (GenSolvablePolynomial) zero.sum(a, e); } else { // doAddTo ?? fac = (GenSolvablePolynomial) fac.sum(a, e); } row.set(i, fac); } } return R; } /** * Right normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ @SuppressWarnings("unchecked") public PseudoReductionEntry rightNormalformFactor(List> Pp, GenSolvablePolynomial Ap) { //throw new UnsupportedOperationException(); if (Ap == null) { throw new IllegalArgumentException("Ap == null not supported"); //return null; } C mfactor = Ap.ring.getONECoefficient(); PseudoReductionEntry pf = new PseudoReductionEntry(Ap, mfactor); if (Pp == null || Pp.isEmpty()) { return pf; } if (Ap.isZERO()) { return pf; } Map.Entry m; GenSolvablePolynomial[] P = new GenSolvablePolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; ExpVector[] htl = new ExpVector[l]; //C[] lbc = (C[]) new GcdRingElem[l]; GenSolvablePolynomial[] p = new GenSolvablePolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { if (P[i] == null) { continue; } p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); //lbc[j] = m.getValue(); j++; } } l = j; ExpVector e; C a; boolean mt = false; GenSolvablePolynomial R = Ap.ring.getZERO().copy(); GenSolvablePolynomial Q = null; GenSolvablePolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); //System.out.println(" S = " + S); } else { e = e.subtract(htl[i]); //logger.info("red div = {}", e); Q = p[i].multiply(e); assert Q.multiply(a).equals(Q.multiplyLeft(a)); C c = Q.leadingBaseCoefficient(); ExpVector g = S.leadingExpVector(); C ap = a; if (a.remainder(c).isZERO()) { a = a.divide(c); //S = S.subtractMultiple(a, Q); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); } else { mfactor = mfactor.multiply(c); // right R = R.multiply(c); //S = S.scaleSubtractMultiple(c, a, Q); S = S.multiply(c); S = (GenSolvablePolynomial) S.subtract(Q.multiply(a)); } ExpVector h = S.leadingExpVector(); if (g.equals(h)) { // Ore condition not fulfilled logger.info("no Ore: g==h: g = {}, c = {}", g, c); throw new RuntimeException("g==h: a = " + a + ", ap = " + ap); } } } logger.info("multiplicative factor = {}", mfactor); pf = new PseudoReductionEntry(R, mfactor); return pf; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvableSyzygy.java000066400000000000000000000143311445075545500246210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Syzygy interface for solvable polynomials. Defines syzygy computations and * tests. * @param coefficient type * @author Heinz Kredel */ public interface SolvableSyzygy> extends Serializable { /** * Left syzygy for left Groebner base. * @param F a Groebner base. * @return leftSyz(F), a basis for the left module of syzygies for F. */ public List>> leftZeroRelations(List> F); /** * Left syzygy for left Groebner base. * @param modv number of module variables. * @param F a Groebner base. * @return leftSyz(F), a basis for the left module of syzygies for F. */ public List>> leftZeroRelations(int modv, List> F); /** * Left syzygy for left module Groebner base. * @param M a Groebner base. * @return leftSyz(M), a basis for the left module of syzygies for M. */ public ModuleList leftZeroRelations(ModuleList M); /** * Test if left syzygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of left syzygies for F, else false. */ public boolean isLeftZeroRelation(List>> Z, List> F); /** * Test if right syzygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of right syzygies for F, else false. */ public boolean isRightZeroRelation(List>> Z, List> F); /** * Test if left sysygy of modules * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of left syzygies for F, else false. */ public boolean isLeftZeroRelation(ModuleList Z, ModuleList F); /** * Test if right sysygy of modules * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of right syzygies for F, else false. */ public boolean isRightZeroRelation(ModuleList Z, ModuleList F); /** * Resolution of a module. Only with direct GBs. * @param M a module list of a Groebner basis. * @return a resolution of M. */ public List> resolution(ModuleList M); /** * Resolution of a polynomial list. Only with direct GBs. * @param F a polynomial list of a Groebner basis. * @return a resolution of F. */ public List/*|SolvResPolPart>*/ resolution(PolynomialList F); /** * Resolution of a module. * @param M a module list of an arbitrary basis. * @return a resolution of M. */ public List> resolutionArbitrary(ModuleList M); /** * Resolution of a polynomial list. * @param F a polynomial list of an arbitrary basis. * @return a resolution of F. */ public List/*|SolvResPolPart>*/ resolutionArbitrary(PolynomialList F); /** * Left syzygy module from arbitrary base. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of left syzygies for F. */ public List>> leftZeroRelationsArbitrary(List> F); /** * Left syzygy module from arbitrary base. * @param modv number of module variables. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of left syzygies for F. */ public List>> leftZeroRelationsArbitrary(int modv, List> F); /** * Left syzygy for arbitrary left module base. * @param M an arbitrary base. * @return leftSyz(M), a basis for the left module of syzygies for M. */ public ModuleList leftZeroRelationsArbitrary(ModuleList M); /** * Right syzygy module from arbitrary base. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of right syzygies for F. */ public List>> rightZeroRelationsArbitrary(List> F); /** * Right syzygy module from arbitrary base. * @param modv number of module variables. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of right syzygies for F. */ public List>> rightZeroRelationsArbitrary(int modv, List> F); /** * Test left Ore condition. * @param a solvable polynomial * @param b solvable polynomial * @param oc = [p,q] two solvable polynomials * @return true if p*a = q*b, else false */ public boolean isLeftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial[] oc); /** * Test right Ore condition. * @param a solvable polynomial * @param b solvable polynomial * @param oc = [p,q] two solvable polynomials * @return true if a*p = b*q, else false */ public boolean isRightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial[] oc); /** * Left Ore condition. Generators for the left Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with p*a = q*b */ public GenSolvablePolynomial[] leftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b); /** * Right Ore condition. Generators for the right Ore condition of two * solvable polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with a*p = b*q */ public GenSolvablePolynomial[] rightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b); } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvableSyzygyAbstract.java000066400000000000000000000715021445075545500263100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.Reduction; import edu.jas.gb.ReductionSeq; import edu.jas.gb.SolvableReduction; import edu.jas.gb.SolvableReductionSeq; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.vector.BasicLinAlg; /** * Syzygy abstract class for solvable polynomials. Implements Syzygy * computations and tests. * @param coefficient type * @author Heinz Kredel */ public abstract class SolvableSyzygyAbstract> implements SolvableSyzygy { private static final Logger logger = LogManager.getLogger(SolvableSyzygyAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Solvable reduction engine. */ public final SolvableReduction sred; /** * Reduction engine. */ protected Reduction red; /** * Linear algebra engine. */ protected BasicLinAlg> blas; //protected BasicLinAlg> blas; /** * Constructor. */ public SolvableSyzygyAbstract() { red = new ReductionSeq(); sred = new SolvableReductionSeq(); blas = new BasicLinAlg>(); //blas = new BasicLinAlg>(); } /** * Left syzygy for left Groebner base. * @param F a Groebner base. * @return leftSyz(F), a basis for the left module of syzygies for F. */ public List>> leftZeroRelations(List> F) { return leftZeroRelations(0, F); } /** * Left syzygy for left Groebner base. * @param modv number of module variables. * @param F a Groebner base. * @return leftSyz(F), a basis for the left module of syzygies for F. */ public List>> leftZeroRelations(int modv, List> F) { List>> Z = new ArrayList>>(); ArrayList> S = new ArrayList>(F.size()); for (int i = 0; i < F.size(); i++) { S.add(null); } GenSolvablePolynomial pi, pj, s, h, zero; zero = null; for (int i = 0; i < F.size(); i++) { pi = F.get(i); if (zero == null) { zero = pi.ring.getZERO(); } for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); //logger.info("p{}, p{} = {}", j, i, pj); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) continue; List> row = new ArrayList>(S); s = sred.leftSPolynomial(row, i, pi, j, pj); //logger.info("row = {}", row); if (s.isZERO()) { Z.add(row); continue; } h = sred.leftNormalform(row, F, s); if (!h.isZERO()) { System.out.println("s = " + s); System.out.println("F = " + F); System.out.println("row = " + row); throw new ArithmeticException("Syzygy no leftGB: h != 0, " + h); } Z.add(row); } } // set null to zero for (List> vr : Z) { for (int j = 0; j < vr.size(); j++) { if (vr.get(j) == null) { vr.set(j, zero); } } } return Z; } /** * Left syzygy for left module Groebner base. * @param M a Groebner base. * @return leftSyz(M), a basis for the left module of syzygies for M. */ @SuppressWarnings("unchecked") public ModuleList leftZeroRelations(ModuleList M) { ModuleList N = null; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenSolvablePolynomial zero = (GenSolvablePolynomial) M.ring.getZERO(); //logger.info("zero = {}", zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 logger.info("modv = {}", modv); List>> G = leftZeroRelations(modv, F.castToSolvableList()); //if (G == null) { // return N; //} List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { List> Gi = G.get(i); List> Zi = new ArrayList>(); //System.out.println("\nG("+i+") = " + G.get(i)); for (int j = 0; j < Gi.size(); j++) { //System.out.println("\nG("+i+","+j+") = " + Gi.get(j)); GenSolvablePolynomial p = Gi.get(j); if (p != null) { Map> r = p.contract(M.ring); //System.out.println("map("+i+","+j+") = " + r + ", size = " + r.size() ); if (r.size() == 0) { Zi.add(zero); } else if (r.size() == 1) { GenSolvablePolynomial vi = (GenSolvablePolynomial) (r.values().toArray())[0]; Zi.add(vi); } else { // will not happen throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList((GenSolvablePolynomialRing) M.ring, Z); //System.out.println("\n\nN = " + N); return N; } /** * Right syzygy module from Groebner base. * @param F a solvable polynomial list, a Groebner base. * @return syz(F), a basis for the module of right syzygies for F. */ public List>> rightZeroRelations(List> F) { return rightZeroRelations(0, F); } /** * Right syzygy module from Groebner base. * @param modv number of module variables. * @param F a solvable polynomial list, a Groebner base. * @return syz(F), a basis for the module of right syzygies for F. */ @SuppressWarnings("unchecked") public List>> rightZeroRelations(int modv, List> F) { GenSolvablePolynomialRing ring = null; for (GenSolvablePolynomial p : F) { if (p != null) { ring = p.ring; break; } } List>> Z; if (ring == null) { // all null Z = new ArrayList>>(1); Z.add(F); return Z; } //System.out.println("ring to reverse = " + ring.toScript()); GenSolvablePolynomialRing rring = ring.reverse(true); GenSolvablePolynomial q; List> rF; rF = new ArrayList>(F.size()); for (GenSolvablePolynomial p : F) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(rring); rF.add(q); } } if (debug) { PolynomialList pl = new PolynomialList(rring, rF); logger.info("reversed problem = {}", pl); //.toScript() } List>> rZ = leftZeroRelations(modv, rF); if (debug) { boolean isit = isLeftZeroRelation(rZ, rF); logger.debug("isLeftZeroRelation = {}", isit); } GenSolvablePolynomialRing oring = rring.reverse(true); if (debug) { logger.debug("ring == oring: {}", ring.equals(oring)); } ring = oring; Z = new ArrayList>>(rZ.size()); for (List> z : rZ) { if (z == null) { continue; } List> s; s = new ArrayList>(z.size()); for (GenSolvablePolynomial p : z) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(ring); s.add(q); } } Z.add(s); } return Z; } /** * Right syzygy for right module Groebner base. * @param M a Groebner base. * @return rightSyz(M), a basis for the right module of syzygies for M. */ @SuppressWarnings("unchecked") public ModuleList rightZeroRelations(ModuleList M) { ModuleList N = null; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenSolvablePolynomial zero = (GenSolvablePolynomial) M.ring.getZERO(); //logger.info("zero = {}", zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 logger.info("modv = {}", modv); List>> G = rightZeroRelations(modv, F.castToSolvableList()); //if (G == null) { // return N; //} List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { List> Gi = G.get(i); List> Zi = new ArrayList>(); //System.out.println("\nG("+i+") = " + G.get(i)); for (int j = 0; j < Gi.size(); j++) { //System.out.println("\nG("+i+","+j+") = " + Gi.get(j)); GenSolvablePolynomial p = Gi.get(j); if (p != null) { Map> r = p.contract(M.ring); //System.out.println("map("+i+","+j+") = " + r + ", size = " + r.size() ); if (r.size() == 0) { Zi.add(zero); } else if (r.size() == 1) { GenSolvablePolynomial vi = (GenSolvablePolynomial) (r.values().toArray())[0]; Zi.add(vi); } else { // will not happen throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList((GenSolvablePolynomialRing) M.ring, Z); //System.out.println("\n\nN = " + N); return N; } /** * Test if left syzygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of left syzygies for F, else false. */ public boolean isLeftZeroRelation(List>> Z, List> F) { List> Fp = PolynomialList. castToList(F); for (List> row : Z) { List> yrow = PolynomialList. castToList(row); GenSolvablePolynomial p = (GenSolvablePolynomial) blas.scalarProduct(yrow, Fp); if (p == null) { continue; } if (!p.isZERO()) { logger.info("is not ZeroRelation = {}", p); return false; } } return true; } /** * Test if right syzygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of right syzygies for F, else false. */ public boolean isRightZeroRelation(List>> Z, List> F) { List> Fp = PolynomialList. castToList(F); for (List> row : Z) { List> yrow = PolynomialList. castToList(row); // param order: GenSolvablePolynomial p = (GenSolvablePolynomial) blas.scalarProduct(Fp, yrow); if (p == null) { continue; } if (!p.isZERO()) { logger.info("is not ZeroRelation = {}", p); return false; } } return true; } /** * Test if left sysygy of modules * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of left syzygies for F, else false. */ public boolean isLeftZeroRelation(ModuleList Z, ModuleList F) { if (Z == null || Z.list == null) { return true; } List>> Fp = F.list; //F.castToSolvableList(); for (List> row : Z.list) { List> zr = blas.leftScalarProduct(row, Fp); //List> zp = PolynomialList. castToSolvableList(zr); if (!blas.isZero(zr)) { logger.info("is not ZeroRelation ({}) = {}", zr.size(), zr); return false; } } return true; } /** * Test if right sysygy of modules * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of right syzygies for F, else false. */ public boolean isRightZeroRelation(ModuleList Z, ModuleList F) { if (Z == null || Z.list == null) { return true; } List>> Fp = F.list; //F.castToSolvableList(); for (List> row : Z.list) { List> zr = blas.rightScalarProduct(row, Fp); //List> zp = PolynomialList. castToSolvableList(zr); if (!blas.isZero(zr)) { logger.info("is not ZeroRelation ({}) = {}", zr.size(), zr); return false; } } return true; } /** * Left syzygy module from arbitrary base. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of left syzygies for F. */ public List>> leftZeroRelationsArbitrary(List> F) { return leftZeroRelationsArbitrary(0, F); } /** * Left syzygy for arbitrary left module base. * @param M an arbitrary base. * @return leftSyz(M), a basis for the left module of syzygies for M. */ @SuppressWarnings("unchecked") public ModuleList leftZeroRelationsArbitrary(ModuleList M) { ModuleList N = null; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenSolvablePolynomial zero = (GenSolvablePolynomial) M.ring.getZERO(); //logger.info("zero = {}", zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 logger.info("modv = {}", modv); List>> G = leftZeroRelationsArbitrary(modv, F.castToSolvableList()); if (G == null) { return N; } List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { List> Gi = G.get(i); List> Zi = new ArrayList>(); //System.out.println("\nG("+i+") = " + G.get(i)); for (int j = 0; j < Gi.size(); j++) { //System.out.println("\nG("+i+","+j+") = " + Gi.get(j)); GenSolvablePolynomial p = Gi.get(j); if (p != null) { Map> r = p.contract(M.ring); //System.out.println("map("+i+","+j+") = " + r + ", size = " + r.size() ); if (r.size() == 0) { Zi.add(zero); } else if (r.size() == 1) { GenSolvablePolynomial vi = (GenSolvablePolynomial) (r.values().toArray())[0]; Zi.add(vi); } else { // will not happen throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList((GenSolvablePolynomialRing) M.ring, Z); //System.out.println("\n\nN = " + N); return N; } /** * Right syzygy module from arbitrary base. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of right syzygies for F. */ public List>> rightZeroRelationsArbitrary( List> F) { return rightZeroRelationsArbitrary(0, F); } /** * Right syzygy module from arbitrary base. * @param modv number of module variables. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of right syzygies for F. */ @SuppressWarnings("unchecked") public List>> rightZeroRelationsArbitrary(int modv, List> F) { GenSolvablePolynomialRing ring = null; for (GenSolvablePolynomial p : F) { if (p != null) { ring = p.ring; break; } } List>> Z; if (ring == null) { // all null Z = new ArrayList>>(1); Z.add(F); return Z; } GenSolvablePolynomialRing rring = ring.reverse(true); //System.out.println("rightZeroRelationsArbitrary: ring = " + ring.toScript() + ", reversed ring = " + rring.toScript()); GenSolvablePolynomial q; List> rF; rF = new ArrayList>(F.size()); for (GenSolvablePolynomial p : F) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(rring); rF.add(q); } } if (debug) { PolynomialList pl = new PolynomialList(rring, rF); logger.info("reversed problem = {}", rF); //pl.toScript() } List>> rZ = leftZeroRelationsArbitrary(modv, rF); if (debug) { ModuleList pl = new ModuleList(rring, rZ); logger.info("reversed syzygies = {}", rZ); //pl.toScript() boolean isit = isLeftZeroRelation(rZ, rF); logger.info("isLeftZeroRelation = {}", isit); } GenSolvablePolynomialRing oring = rring.reverse(true); if (debug) { logger.info("ring == oring: {}", ring.equals(oring)); } ring = oring; Z = new ArrayList>>(rZ.size()); for (List> z : rZ) { if (z == null) { continue; } List> s; s = new ArrayList>(z.size()); for (GenSolvablePolynomial p : z) { if (p != null) { q = (GenSolvablePolynomial) p.reverse(ring); s.add(q); //System.out.println("p = " + p + "\nreverse(p) = " + q); } } Z.add(s); } return Z; } /** * Right syzygy for arbitrary base. * @param M an arbitrary base. * @return rightSyz(M), a basis for the right module of syzygies for M. */ @SuppressWarnings("unchecked") public ModuleList rightZeroRelationsArbitrary(ModuleList M) { ModuleList N = null; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenSolvablePolynomial zero = (GenSolvablePolynomial) M.ring.getZERO(); //logger.info("zero = {}", zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 logger.info("modv = {}", modv); List>> G = rightZeroRelationsArbitrary(modv, F.castToSolvableList()); //if (G == null) { // return N; //} List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { List> Gi = G.get(i); List> Zi = new ArrayList>(); //System.out.println("G("+i+") = " + Gi); for (int j = 0; j < Gi.size(); j++) { GenSolvablePolynomial p = Gi.get(j); //System.out.println("G("+i+","+j+") = " + p); if (p != null) { Map> r = p.contract(M.ring); //System.out.println("map("+i+","+j+") = " + r + ", size = " + r.size() ); if (r.size() == 0) { Zi.add(zero); } else if (r.size() == 1) { GenSolvablePolynomial vi = (GenSolvablePolynomial) (r.values().toArray())[0]; Zi.add(vi); } else { // will not happen logger.error("p = {}, r = {}", p, r); throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList((GenSolvablePolynomialRing) M.ring, Z); //System.out.println("\n\nN = " + N); return N; } /** * Test left Ore condition. * @param a solvable polynomial * @param b solvable polynomial * @param oc = [p,q] two solvable polynomials * @return true if p*a = q*b, else false */ public boolean isLeftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial[] oc) { if (oc == null) { throw new IllegalArgumentException("oc array must be non null"); } return isLeftOreCond(a, b, oc[0], oc[1]); } /** * Is left Ore condition. Test left Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @param p solvable polynomial * @param q solvable polynomial * @return true, if p*a = q*b, else false */ public boolean isLeftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial p, GenSolvablePolynomial q) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomial pa = p.multiply(a); GenSolvablePolynomial qb = q.multiply(b); return pa.equals(qb); } /** * Test right Ore condition. * @param a solvable polynomial * @param b solvable polynomial * @param oc = [p,q] two solvable polynomials * @return true if a*p = b*q, else false */ public boolean isRightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial[] oc) { if (oc == null) { throw new IllegalArgumentException("oc array must be non null"); } return isRightOreCond(a, b, oc[0], oc[1]); } /** * Is right Ore condition. Test right Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @param p solvable polynomial * @param q solvable polynomial * @return true, if a*p = b*q, else false */ public boolean isRightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b, GenSolvablePolynomial p, GenSolvablePolynomial q) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomial ap = a.multiply(p); GenSolvablePolynomial bq = b.multiply(q); return ap.equals(bq); } /** * Left simplifier. Method of Apel & Lassner (1987). * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with a/b = p/q and q is minimal and monic */ public abstract GenSolvablePolynomial[] leftSimplifier(GenSolvablePolynomial a, GenSolvablePolynomial b); /** * Comparison like SolvableLocal or SolvableQuotient. * @param num SolvablePolynomial. * @param den SolvablePolynomial. * @param n SolvablePolynomial. * @param d SolvablePolynomial. * @return sign((num/den)-(n/d)). */ public int compare(GenSolvablePolynomial num, GenSolvablePolynomial den, GenSolvablePolynomial n, GenSolvablePolynomial d) { if (n == null || n.isZERO()) { return num.signum(); } if (num.isZERO()) { return -n.signum(); } // assume sign(den,b.den) > 0 int s1 = num.signum(); int s2 = n.signum(); int t = (s1 - s2) / 2; if (t != 0) { System.out.println("compareTo: t = " + t); //return t; } if (den.compareTo(d) == 0) { return num.compareTo(n); } GenSolvablePolynomial r, s; // if (den.isONE()) { } // if (b.den.isONE()) { } GenSolvablePolynomial[] oc = leftOreCond(den, d); if (debug) { System.out.println("oc[0] den =<>= oc[1] d: (" + oc[0] + ") (" + den + ") = (" + oc[1] + ") (" + d + ")"); } //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); r = oc[0].multiply(num); s = oc[1].multiply(n); logger.info("compare: r = {}, s = {}", r, s); return r.compareTo(s); } } /** * Container for module resolution components. * @param coefficient type */ class SolvResPart> implements Serializable { public final ModuleList module; public final ModuleList GB; public final ModuleList syzygy; /** * SolvResPart. * @param m a module list. * @param g a module list GB. * @param z a syzygy module list. */ public SolvResPart(ModuleList m, ModuleList g, ModuleList z) { module = m; GB = g; syzygy = z; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("SolvResPart(\n"); s.append("module = " + module); s.append("\n GB = " + GB); s.append("\n syzygy = " + syzygy); s.append(")"); return s.toString(); } } /** * Container for polynomial resolution components. * @param coefficient type */ class SolvResPolPart> implements Serializable { public final PolynomialList ideal; public final PolynomialList GB; public final ModuleList syzygy; /** * SolvResPolPart. * @param m a polynomial list. * @param g a polynomial list GB. * @param z a syzygy module list. */ public SolvResPolPart(PolynomialList m, PolynomialList g, ModuleList z) { ideal = m; GB = g; syzygy = z; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("SolvResPolPart(\n"); s.append("ideal = " + ideal); s.append("\n GB = " + GB); s.append("\n syzygy = " + syzygy); s.append(")"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SolvableSyzygySeq.java000066400000000000000000000523711445075545500253000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.SolvableExtendedGB; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Syzygy sequential class for solvable polynomials. Implements Syzygy * computations and tests with Groebner bases. * @param coefficient type * @author Heinz Kredel */ public class SolvableSyzygySeq> extends SolvableSyzygyAbstract { private static final Logger logger = LogManager.getLogger(SolvableSyzygySeq.class); private static final boolean debug = logger.isDebugEnabled(); private static boolean assertEnabled = false; static { assert assertEnabled = true; // official hack to check assertions enabled } /** * Groebner basis engine. */ protected SolvableGroebnerBase sbb; /* * Module Groebner basis engine. //protected ModSolvableGroebnerBase msbb; */ /** * Constructor. * @param cf coefficient ring. */ public SolvableSyzygySeq(RingFactory cf) { sbb = SGBFactory.getImplementation(cf); //msbb = new ModSolvableGroebnerBaseSeq(cf); } /** * Resolution of a module. Only with direct GBs. * @param M a module list of a Groebner basis. * @return a resolution of M. */ public List> resolution(ModuleList M) { List> R = new ArrayList>(); ModuleList MM = M; ModuleList GM; ModuleList Z; while (true) { GM = sbb.leftGB(MM); Z = leftZeroRelations(GM); R.add(new SolvResPart(MM, GM, Z)); if (Z == null || Z.list == null || Z.list.size() == 0) { break; } MM = Z; } return R; } /** * Resolution of a polynomial list. Only with direct GBs. * @param F a polynomial list of a Groebner basis. * @return a resolution of F. */ @SuppressWarnings("unchecked") public List/*|SolvResPolPart>*/ resolution(PolynomialList F) { List>> Z; ModuleList Zm; List> G; PolynomialList Gl; G = sbb.leftGB(F.castToSolvableList()); Z = leftZeroRelations(G); Gl = new PolynomialList((GenSolvablePolynomialRing) F.ring, G); Zm = new ModuleList((GenSolvablePolynomialRing) F.ring, Z); List R = resolution(Zm); R.add(0, new SolvResPolPart(F, Gl, Zm)); return R; } /** * Resolution of a module. * @param M a module list of an arbitrary basis. * @return a resolution of M. */ public List> resolutionArbitrary(ModuleList M) { List> R = new ArrayList>(); ModuleList MM = M; ModuleList GM = null; ModuleList Z; while (true) { //GM = sbb.leftGB(MM); Z = leftZeroRelationsArbitrary(MM); R.add(new SolvResPart(MM, GM, Z)); if (Z == null || Z.list == null || Z.list.size() == 0) { break; } MM = Z; } return R; } /** * Resolution of a polynomial list. * @param F a polynomial list of an arbitrary basis. * @return a resolution of F. */ @SuppressWarnings("unchecked") public List/*|SolvResPolPart>*/ resolutionArbitrary(PolynomialList F) { List>> Z; ModuleList Zm; PolynomialList Gl = null; //List> G = sbb.leftGB( F.castToSolvableList() ); //Gl = new PolynomialList((GenSolvablePolynomialRing)F.ring, G); Z = leftZeroRelationsArbitrary(F.castToSolvableList()); Zm = new ModuleList((GenSolvablePolynomialRing) F.ring, Z); List R = resolutionArbitrary(Zm); R.add(0, new SolvResPolPart(F, Gl, Zm)); return R; } /** * Left syzygy module from arbitrary base. * @param modv number of module variables. * @param F a solvable polynomial list. * @return syz(F), a basis for the module of left syzygies for F. */ @SuppressWarnings("unchecked") public List>> leftZeroRelationsArbitrary(int modv, List> F) { if (F == null) { return null; //leftZeroRelations( modv, F ); } if (F.size() <= 1) { return leftZeroRelations(modv, F); } final int lenf = F.size(); SolvableExtendedGB exgb = sbb.extLeftGB(modv, F); //System.out.println("isLeftZeroRelation leftGB: " + sbb.isLeftGB(exgb.G)); if (debug) { logger.info("exgb = {}", exgb); } if (assertEnabled) { logger.info("check1 exgb start"); if (!sbb.isLeftReductionMatrix(exgb)) { logger.error("is reduction matrix ? false"); } logger.info("check1 exgb end"); } List> G = exgb.G; List>> G2F = exgb.G2F; List>> F2G = exgb.F2G; List>> sg = leftZeroRelations(modv, G); GenSolvablePolynomialRing ring = G.get(0).ring; ModuleList S = new ModuleList(ring, sg); if (debug) { logger.info("syz = {}", S); } if (assertEnabled) { logger.info("check2 left syz start"); if (!isLeftZeroRelation(sg, G)) { logger.error("is syzygy ? false"); } logger.info("check2 left syz end"); } //System.out.println("isLeftZeroRelation extGB: " + isLeftZeroRelation(sg, G)); List>> sf; sf = new ArrayList>>(sg.size()); for (List> r : sg) { Iterator> it = r.iterator(); Iterator>> jt = G2F.iterator(); List> rf; rf = new ArrayList>(lenf); for (int m = 0; m < lenf; m++) { rf.add(ring.getZERO()); } while (it.hasNext() && jt.hasNext()) { GenSolvablePolynomial si = it.next(); List> ai = jt.next(); //System.out.println("si = " + si); //System.out.println("ai = " + ai); if (si == null || ai == null) { continue; } // pi has wrong type: List> pi = blas.scalarProduct(si, PolynomialList. castToList(ai)); //System.out.println("pi = " + pi); rf = PolynomialList. castToSolvableList( blas.vectorAdd(PolynomialList. castToList(rf), pi)); } if (it.hasNext() || jt.hasNext()) { logger.error("leftZeroRelationsArbitrary wrong sizes"); } //System.out.println("\nrf = " + rf + "\n"); sf.add(rf); } if (assertEnabled) { logger.info("check3 left syz start"); if (!isLeftZeroRelation(sf, F)) { logger.error("is partial syz sf ? false"); } logger.info("check3 left syz end"); } //System.out.println("isLeftZeroRelation backtrans: " + isLeftZeroRelation(sf, F)); List>> M; M = new ArrayList>>(lenf); for (List> r : F2G) { Iterator> it = r.iterator(); Iterator>> jt = G2F.iterator(); List> rf; rf = new ArrayList>(lenf); for (int m = 0; m < lenf; m++) { rf.add(ring.getZERO()); } while (it.hasNext() && jt.hasNext()) { GenSolvablePolynomial si = it.next(); List> ai = jt.next(); //System.out.println("si = " + si); //System.out.println("ai = " + ai); if (si == null || ai == null) { continue; } //pi has wrong type, should be: List> List> pi = blas.scalarProduct(si, PolynomialList. castToList(ai)); //--List> pi = blas.scalarProduct(PolynomialList. castToList(ai), si); //System.out.println("pi = " + pi); rf = PolynomialList. castToSolvableList( blas.vectorAdd(PolynomialList. castToList(rf), pi)); } if (it.hasNext() || jt.hasNext()) { logger.error("zeroRelationsArbitrary wrong sizes"); } //System.out.println("\nMg Mf = " + rf + "\n"); M.add(rf); } /* not true in general, debug only: List> F2 = new ArrayList>( F.size() ); List> Fp = PolynomialList.castToList(F); for ( List> rr: M ) { GenSolvablePolynomial rrg = (GenSolvablePolynomial) blas.scalarProduct(PolynomialList.castToList(rr), Fp); F2.add( rrg ); } if ( ! F.equals( F2 ) ) { logger.error("is FAB = F ? false"); System.out.println("F = " + F); System.out.println("F2 = " + F2); } System.out.println("isLeftZeroRelation F == F2: " + F.equals(F2)); */ int sflen = sf.size(); int i = 0; for (List> ri : M) { List> r2i; r2i = new ArrayList>(ri.size()); int j = 0; for (GenSolvablePolynomial rij : ri) { GenSolvablePolynomial p = null; if (i == j) { p = (GenSolvablePolynomial) ring.getONE().subtract(rij); } else { if (rij != null) { p = (GenSolvablePolynomial) rij.negate(); } } r2i.add(p); j++; } if (!blas.isZero( PolynomialList. castToList(r2i)) ) { sf.add(r2i); } i++; } if (assertEnabled) { logger.info("check4 left syz start"); if (!isLeftZeroRelation(sf, F)) { logger.error("is syz sf ? false"); } logger.info("check4 left syz end"); } //System.out.println("isLeftZeroRelation diagonal sf: " + isLeftZeroRelation(sf, F)); return sf; } /** * Left Ore condition. Generators for the left Ore condition of two solvable * polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with p*a = q*b */ @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial[] leftOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomialRing pfac = a.ring; GenSolvablePolynomial[] oc = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; if (a.equals(b)) { oc[0] = pfac.getONE(); oc[1] = pfac.getONE(); return oc; } if (a.equals(b.negate())) { oc[0] = pfac.getONE(); oc[1] = (GenSolvablePolynomial) pfac.getONE().negate(); return oc; } if (a.isConstant()) { if (pfac.coFac.isCommutative()) { // ?? oc[0] = b; oc[1] = a; return oc; } C c = a.leadingBaseCoefficient().inverse(); oc[0] = b.multiply(c); // was Left oc[1] = pfac.getONE(); return oc; } if (b.isConstant()) { if (pfac.coFac.isCommutative()) { // ?? oc[0] = b; oc[1] = a; return oc; } oc[0] = pfac.getONE(); C c = b.leadingBaseCoefficient().inverse(); oc[1] = a.multiply(c); // was Left return oc; } logger.info("computing left Ore condition: {}, {}", a, b); List> F = new ArrayList>(2); F.add(a); F.add(b); List>> Gz = leftZeroRelationsArbitrary(F); boolean zr = isLeftZeroRelation(Gz, F); //System.out.println("isLeftZeroRelation: " + zr); //isLeftZeroRelation(Gz, F)); // if (false) { // //System.out.println("Gz = " + Gz); // ModuleList M = new ModuleList(pfac, Gz); // System.out.println("M = " + M.list); // ModuleList GM = sbb.leftGB(M); // System.out.println("GM = " + GM.list); // Gz = GM.castToSolvableList(); // } List> G1 = null; GenSolvablePolynomial g1 = null; for (List> Gi : Gz) { //System.out.println("Gil = " + Gi); if (Gi.get(0).isZERO()) { continue; } if (G1 == null) { G1 = Gi; } if (g1 == null) { g1 = G1.get(0); } else if (g1.compareTo(Gi.get(0)) > 0) { //g1.degree() > Gi.get(0).degree() G1 = Gi; g1 = G1.get(0); } } oc[0] = g1; //G1.get(0); oc[1] = (GenSolvablePolynomial) G1.get(1).negate(); //logger.info("Ore multiple: {}, {}", oc[0].multiply(a), Arrays.toString(oc)); return oc; } /** * Right Ore condition. Generators for the right Ore condition of two * solvable polynomials. * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with a*p = b*q */ @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial[] rightOreCond(GenSolvablePolynomial a, GenSolvablePolynomial b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomialRing pfac = a.ring; GenSolvablePolynomial[] oc = (GenSolvablePolynomial[]) new GenSolvablePolynomial[2]; if (a.equals(b)) { oc[0] = pfac.getONE(); oc[1] = pfac.getONE(); return oc; } if (a.equals(b.negate())) { oc[0] = pfac.getONE(); oc[1] = (GenSolvablePolynomial) pfac.getONE().negate(); return oc; } if (a.isConstant()) { if (pfac.coFac.isCommutative()) { // ?? oc[0] = b; oc[1] = a; return oc; } C c = a.leadingBaseCoefficient().inverse(); oc[0] = b.multiplyLeft(c); oc[1] = pfac.getONE(); return oc; } if (b.isConstant()) { if (pfac.coFac.isCommutative()) { // ?? oc[0] = b; oc[1] = a; return oc; } oc[0] = pfac.getONE(); C c = b.leadingBaseCoefficient().inverse(); oc[1] = a.multiplyLeft(c); return oc; } logger.info("computing right Ore condition: {}, {}", a, b); List> F = new ArrayList>(2); F.add(a); F.add(b); List>> Gz = rightZeroRelationsArbitrary(F); //System.out.println("isRightZeroRelation: " + isRightZeroRelation(Gz, F)); List> G1 = null; GenSolvablePolynomial g1 = null; for (List> Gi : Gz) { //System.out.println("Gir = " + Gi); if (Gi.get(0).isZERO()) { continue; } if (G1 == null) { G1 = Gi; } if (g1 == null) { g1 = G1.get(0); } else if (g1.compareTo(Gi.get(0)) > 0) { G1 = Gi; g1 = G1.get(0); } } oc[0] = g1; //G1.get(0); oc[1] = (GenSolvablePolynomial) G1.get(1).negate(); //logger.info("Ore multiple: {}, {}", a.multiply(oc[0]), Arrays.toString(oc)); return oc; } /** * Left simplifier. Method of Apel & Lassner (1987). * @param a solvable polynomial * @param b solvable polynomial * @return [p,q] with a/b = p/q and q is minimal and monic */ @Override @SuppressWarnings({ "unchecked" }) public GenSolvablePolynomial[] leftSimplifier(GenSolvablePolynomial a, GenSolvablePolynomial b) { if (a == null || a.isZERO() || b == null || b.isZERO()) { throw new IllegalArgumentException("a and b must be non zero"); } GenSolvablePolynomial[] oc = null; if (a.isConstant() || b.isConstant()) { oc = new GenSolvablePolynomial[] { a, b }; return oc; } if (a.totalDegree() > 3 || b.totalDegree() > 3) { // how avoid too long running GBs ? //if (a.totalDegree() + b.totalDegree() > 6) { // && a.length() < 10 && b.length() < 10 logger.info("skipping simplifier GB computation: degs = {}, {}", a.totalDegree(), b.totalDegree()); oc = new GenSolvablePolynomial[] { a, b }; return oc; } //GenSolvablePolynomialRing pfac = a.ring; oc = rightOreCond(a, b); logger.info("oc = {}", Arrays.toString(oc)); // + ", a = {}, b = {}", a, b); List> F = new ArrayList>(oc.length); // opposite order and undo negation F.add((GenSolvablePolynomial) oc[1].negate()); F.add(oc[0]); //logger.info("F = {}", F); List>> Gz = leftZeroRelationsArbitrary(F); //logger.info("Gz: {}", Gz); List> G1 = new ArrayList>(Gz.size()); List> G2 = new ArrayList>(Gz.size()); for (List> ll : Gz) { if (!ll.get(0).isZERO()) { // && !ll.get(1).isZERO() G1.add(ll.get(0)); // denominators G2.add(ll.get(1)); // numerators } } logger.info("G1(den): {}, G2(num): {}", G1, G2); SolvableExtendedGB exgb = sbb.extLeftGB(G1); logger.info("exgb.F: {}, exgb.G: {}", exgb.F, exgb.G); List> G = exgb.G; int m = 0; GenSolvablePolynomial min = null; for (int i = 0; i < G.size(); i++) { if (min == null) { min = G.get(i); m = i; } else if (min.compareTo(G.get(i)) > 0) { min = G.get(i); m = i; } } //wrong: blas.scalarProduct(G2,exgb.G2F.get(m)); GenSolvablePolynomial min2 = (GenSolvablePolynomial) blas.scalarProduct( PolynomialList. castToList(exgb.G2F.get(m)), PolynomialList. castToList(G2)); logger.info("min(den): {}, min(num): {}, m = {}, {}", min, min2, m, exgb.G2F.get(m)); // opposite order GenSolvablePolynomial n = min2; // nominator GenSolvablePolynomial d = min; // denominator // normalize if (d.signum() < 0) { n = (GenSolvablePolynomial) n.negate(); d = (GenSolvablePolynomial) d.negate(); } C lc = d.leadingBaseCoefficient(); if (!lc.isONE() && lc.isUnit()) { lc = lc.inverse(); n = n.multiplyLeft(lc); d = d.multiplyLeft(lc); } if (debug) { int t = compare(a, b, n, d); if (t != 0) { oc[0] = a; // nominator oc[1] = b; // denominator throw new RuntimeException("simp wrong, giving up: t = " + t); //logger.error("simp wrong, giving up: t = {}", t); //return oc; } } oc[0] = n; // nominator oc[1] = d; // denominator return oc; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/Syzygy.java000066400000000000000000000074431445075545500231370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; import edu.jas.vector.GenVector; /** * Syzygy interface. Defines Syzygy computations and tests. * @param coefficient type * @author Heinz Kredel */ public interface Syzygy> extends Serializable { /** * Syzygy module from Groebner base. F must be a Groebner base. * @param F a Groebner base. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelations(List> F); /** * Syzygy module from Groebner base. F must be a Groebner base. * @param modv number of module variables. * @param F a Groebner base. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelations(int modv, List> F); /** * Syzygy module from Groebner base. v must be a Groebner base. * @param modv number of module variables. * @param v a Groebner base. * @return syz(v), a basis for the module of syzygies for v. */ public List>> zeroRelations(int modv, GenVector> v); /** * Syzygy module from module Groebner base. M must be a module Groebner * base. * @param M a module Groebner base. * @return syz(M), a basis for the module of syzygies for M. */ public ModuleList zeroRelations(ModuleList M); /** * Test if sysygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of syzygies for F, else false. */ public boolean isZeroRelation(List>> Z, List> F); /** * Test if sysygy of modules. * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of syzygies for F, else false. */ public boolean isZeroRelation(ModuleList Z, ModuleList F); /** * Resolution of a module. Only with direct GBs. * @param M a module list of a Groebner basis. * @return a resolution of M. */ public List> resolution(ModuleList M); /** * Resolution of a polynomial list. Only with direct GBs. * @param F a polynomial list of a Groebner basis. * @return a resolution of F. */ public List // |ResPolPart> resolution(PolynomialList F); /** * Resolution of a polynomial list. * @param F a polynomial list of an arbitrary basis. * @return a resolution of F. */ public List // |ResPolPart> resolutionArbitrary(PolynomialList F); /** * Resolution of a module. * @param M a module list of an arbitrary basis. * @return a resolution of M. */ public List> resolutionArbitrary(ModuleList M); /** * Syzygy module from arbitrary base. * @param F a polynomial list. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelationsArbitrary(List> F); /** * Syzygy module from arbitrary base. * @param modv number of module variables. * @param F a polynomial list. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelationsArbitrary(int modv, List> F); /** * Syzygy module from arbitrary module base. * @param M an arbitrary module base. * @return syz(M), a basis for the module of syzygies for M. */ public ModuleList zeroRelationsArbitrary(ModuleList M); } java-algebra-system-2.7.200/src/edu/jas/gbufd/SyzygyAbstract.java000066400000000000000000000275271445075545500246300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.Reduction; import edu.jas.gb.ReductionSeq; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.vector.BasicLinAlg; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * SyzygyAbstract class. Implements Syzygy computations and tests. * @param coefficient type * @author Heinz Kredel */ public abstract class SyzygyAbstract> implements Syzygy { private static final Logger logger = LogManager.getLogger(SyzygyAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ protected Reduction red; /** * Linear algebra engine. */ protected BasicLinAlg> blas; /** * Constructor. */ public SyzygyAbstract() { red = new ReductionSeq(); blas = new BasicLinAlg>(); } /** * Syzygy module from Groebner base. F must be a Groebner base. * @param F a Groebner base. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelations(List> F) { return zeroRelations(0, F); } /** * Syzygy module from Groebner base. F must be a Groebner base. * @param modv number of module variables. * @param F a Groebner base. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelations(int modv, List> F) { List>> Z = new ArrayList>>(); if (F == null) { return Z; } GenVectorModul> mfac = null; int i = 0; while (mfac == null && i < F.size()) { GenPolynomial p = F.get(i); if (p != null) { mfac = new GenVectorModul>(p.ring, F.size()); } } if (mfac == null) { return Z; } GenVector> v = mfac.fromList(F); //System.out.println("F = " + F + " v = " + v); return zeroRelations(modv, v); } /** * Syzygy module from Groebner base. v must be a Groebner base. * @param modv number of module variables. * @param v a Groebner base. * @return syz(v), a basis for the module of syzygies for v. */ public List>> zeroRelations(int modv, GenVector> v) { List>> Z = new ArrayList>>(); GenVectorModul> mfac = v.modul; List> F = v.val; GenVector> S = mfac.getZERO(); GenPolynomial pi, pj, s, h; //zero = mfac.coFac.getZERO(); for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); //logger.info("p{}, p{} = {}, {}", i, j, pi, pj); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { continue; } List> row = S.copy().val; s = red.SPolynomial(row, i, pi, j, pj); if (s.isZERO()) { Z.add(row); continue; } h = red.normalform(row, F, s); if (!h.isZERO()) { throw new RuntimeException("Syzygy no GB"); } if (debug) { logger.info("row = {}", row.size()); } Z.add(row); } } return Z; } /** * Syzygy module from module Groebner base. M must be a module Groebner * base. * @param M a module Groebner base. * @return syz(M), a basis for the module of syzygies for M. */ public ModuleList zeroRelations(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenPolynomial zero = M.ring.getZERO(); //System.out.println("zero = " + zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 //System.out.println("modv = " + modv); List>> G = zeroRelations(modv, F.list); List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { //F = new PolynomialList(F.ring,(List)G.get(i)); List> Gi = G.get(i); List> Zi = new ArrayList>(); // System.out.println("\nG("+i+") = " + G.get(i)); for (int j = 0; j < Gi.size(); j++) { //System.out.println("\nG("+i+","+j+") = " + Gi.get(j)); GenPolynomial p = Gi.get(j); if (p != null) { Map> r = p.contract(M.ring); int s = 0; for (GenPolynomial vi : r.values()) { Zi.add(vi); s++; } if (s == 0) { Zi.add(zero); } else if (s > 1) { // will not happen System.out.println("p = " + p); System.out.println("map(" + i + "," + j + ") = " + r + ", size = " + r.size()); throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList(M.ring, Z); //System.out.println("\n\nN = " + N); return N; } /** * Test if sysygy. * @param Z list of sysygies. * @param F a polynomial list. * @return true, if Z is a list of syzygies for F, else false. */ public boolean isZeroRelation(List>> Z, List> F) { for (List> row : Z) { GenPolynomial p = blas.scalarProduct(row, F); if (p == null) { continue; } if (!p.isZERO()) { logger.info("is not ZeroRelation = {}", p.toString(p.ring.getVars())); logger.info("row = {}", row); //logger.info("F = {}", F); return false; } } return true; } /** * Test if sysygy of modules. * @param Z list of sysygies. * @param F a module list. * @return true, if Z is a list of syzygies for F, else false. */ public boolean isZeroRelation(ModuleList Z, ModuleList F) { if (Z == null || Z.list == null) { return true; } for (List> row : Z.list) { List> zr = blas.leftScalarProduct(row, F.list); if (!blas.isZero(zr)) { logger.info("is not ZeroRelation ({}) = {}", zr.size(), zr); return false; } } return true; } /** * Syzygy module from arbitrary base. * @param F a polynomial list. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelationsArbitrary(List> F) { return zeroRelationsArbitrary(0, F); } /** * Syzygy module from arbitrary module base. * @param M an arbitrary module base. * @return syz(M), a basis for the module of syzygies for M. */ public ModuleList zeroRelationsArbitrary(ModuleList M) { ModuleList N = M; if (M == null || M.list == null) { return N; } if (M.rows == 0 || M.cols == 0) { return N; } GenPolynomial zero = M.ring.getZERO(); //System.out.println("zero = " + zero); //ModuleList Np = null; PolynomialList F = M.getPolynomialList(); int modv = M.cols; // > 0 //System.out.println("modv = " + modv); List>> G = zeroRelationsArbitrary(modv, F.list); List>> Z = new ArrayList>>(); for (int i = 0; i < G.size(); i++) { //F = new PolynomialList(F.ring,(List)G.get(i)); List> Gi = G.get(i); List> Zi = new ArrayList>(); // System.out.println("\nG("+i+") = " + G.get(i)); for (int j = 0; j < Gi.size(); j++) { //System.out.println("\nG("+i+","+j+") = " + Gi.get(j)); GenPolynomial p = Gi.get(j); if (p != null) { Map> r = p.contract(M.ring); int s = 0; for (GenPolynomial vi : r.values()) { Zi.add(vi); s++; } if (s == 0) { Zi.add(zero); } else if (s > 1) { // will not happen System.out.println("p = " + p); System.out.println("map(" + i + "," + j + ") = " + r + ", size = " + r.size()); throw new RuntimeException("Map.size() > 1 = " + r.size()); } } } //System.out.println("\nZ("+i+") = " + Zi); Z.add(Zi); } N = new ModuleList(M.ring, Z); //System.out.println("\n\nN = " + N); return N; } } /** * Container for module resolution components. * @param coefficient type */ class ResPart> implements Serializable { public final ModuleList module; public final ModuleList GB; public final ModuleList syzygy; /** * ResPart. * @param m a module list. * @param g a module list GB. * @param z a syzygy module list. */ public ResPart(ModuleList m, ModuleList g, ModuleList z) { module = m; GB = g; syzygy = z; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("ResPart(\n"); s.append("module = " + module); s.append("\n GB = " + GB); s.append("\n syzygy = " + syzygy); s.append(")"); return s.toString(); } } /** * Container for polynomial resolution components. */ class ResPolPart> implements Serializable { public final PolynomialList ideal; public final PolynomialList GB; public final ModuleList syzygy; /** * ResPolPart. * @param m a polynomial list. * @param g a polynomial list GB. * @param z a syzygy module list. */ public ResPolPart(PolynomialList m, PolynomialList g, ModuleList z) { ideal = m; GB = g; syzygy = z; } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("ResPolPart(\n"); s.append("ideal = " + ideal); s.append("\n GB = " + GB); s.append("\n syzygy = " + syzygy); s.append(")"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/SyzygySeq.java000066400000000000000000000235001445075545500236000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.ExtendedGB; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * SyzygySeq class. Implements Syzygy computations and tests. * @param coefficient type * @author Heinz Kredel */ public class SyzygySeq> extends SyzygyAbstract { private static final Logger logger = LogManager.getLogger(SyzygySeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Groebner base engine. */ protected GroebnerBaseAbstract bb; /* * Module Groebner base engine. //protected ModGroebnerBaseAbstract mbb; */ /** * Constructor. * @param cf coefficient ring. */ public SyzygySeq(RingFactory cf) { super(); bb = GBFactory.getImplementation(cf); //mbb = new ModGroebnerBaseSeq(cf); } /** * Resolution of a module. Only with direct GBs. * @param M a module list of a Groebner basis. * @return a resolution of M. */ public List> resolution(ModuleList M) { List> R = new ArrayList>(); ModuleList MM = M; ModuleList GM; ModuleList Z; //ModGroebnerBase mbb = new ModGroebnerBaseSeq(M.ring.coFac); //assert cf == M.ring.coFac; while (true) { GM = bb.GB(MM); Z = zeroRelations(GM); R.add(new ResPart(MM, GM, Z)); if (Z == null || Z.list == null || Z.list.size() == 0) { break; } MM = Z; } return R; } /** * Resolution of a polynomial list. Only with direct GBs. * @param F a polynomial list of a Groebner basis. * @return a resolution of F. */ @SuppressWarnings("unchecked") public List // |ResPolPart> resolution(PolynomialList F) { List>> Z; ModuleList Zm; List> G; PolynomialList Gl; //GroebnerBase gb = GBFactory.getImplementation(F.ring.coFac); //assert cf == F.ring.coFac; G = bb.GB(F.list); Z = zeroRelations(G); Gl = new PolynomialList(F.ring, G); Zm = new ModuleList(F.ring, Z); List R = resolution(Zm); //// |ResPolPart> R.add(0, new ResPolPart(F, Gl, Zm)); return R; } /** * Resolution of a polynomial list. * @param F a polynomial list of an arbitrary basis. * @return a resolution of F. */ @SuppressWarnings("unchecked") public List // |ResPolPart> resolutionArbitrary(PolynomialList F) { List>> Z; ModuleList Zm; //List> G; PolynomialList Gl = null; //G = bb.GB(F.list); Z = zeroRelationsArbitrary(F.list); //Gl = new PolynomialList(F.ring, F.list); Zm = new ModuleList(F.ring, Z); List R = resolutionArbitrary(Zm); //// |ResPolPart> R.add(0, new ResPolPart(F, Gl, Zm)); return R; } /** * Resolution of a module. * @param M a module list of an arbitrary basis. * @return a resolution of M. */ public List> resolutionArbitrary(ModuleList M) { List> R = new ArrayList>(); ModuleList MM = M; ModuleList GM = null; ModuleList Z; while (true) { //GM = bb.GB(MM); Z = zeroRelationsArbitrary(MM); R.add(new ResPart(MM, GM, Z)); if (Z == null || Z.list == null || Z.list.size() == 0) { break; } MM = Z; } return R; } /** * Syzygy module from arbitrary base. * @param modv number of module variables. * @param F a polynomial list. * @return syz(F), a basis for the module of syzygies for F. */ public List>> zeroRelationsArbitrary(int modv, List> F) { if (F == null) { return new ArrayList>>(); //return zeroRelations(modv, F); } if (F.size() <= 1) { return zeroRelations(modv, F); } //GroebnerBase gb = GBFactory.getImplementation(F.get(0).ring.coFac); // assert cf == F.get(0).ring.coFac; final int lenf = F.size(); ExtendedGB exgb = bb.extGB(F); if (debug) { logger.debug("exgb = {}", exgb); if (!bb.isReductionMatrix(exgb)) { logger.error("is reduction matrix ? false"); } } List> G = exgb.G; List>> G2F = exgb.G2F; List>> F2G = exgb.F2G; List>> sg = zeroRelations(modv, G); GenPolynomialRing ring = G.get(0).ring; ModuleList S = new ModuleList(ring, sg); if (debug) { logger.debug("syz = {}", S); if (!isZeroRelation(sg, G)) { logger.error("is syzygy ? false"); } } List>> sf; sf = new ArrayList>>(sg.size()); //List> row; for (List> r : sg) { Iterator> it = r.iterator(); Iterator>> jt = G2F.iterator(); List> rf; rf = new ArrayList>(lenf); for (int m = 0; m < lenf; m++) { rf.add(ring.getZERO()); } while (it.hasNext() && jt.hasNext()) { GenPolynomial si = it.next(); List> ai = jt.next(); //System.out.println("si = " + si); //System.out.println("ai = " + ai); if (si == null || ai == null) { continue; } List> pi = blas.scalarProduct(si, ai); //System.out.println("pi = " + pi); rf = blas.vectorAdd(rf, pi); } if (it.hasNext() || jt.hasNext()) { logger.error("zeroRelationsArbitrary wrong sizes"); } //System.out.println("\nrf = " + rf + "\n"); sf.add(rf); } List>> M; M = new ArrayList>>(lenf); for (List> r : F2G) { Iterator> it = r.iterator(); Iterator>> jt = G2F.iterator(); List> rf; rf = new ArrayList>(lenf); for (int m = 0; m < lenf; m++) { rf.add(ring.getZERO()); } while (it.hasNext() && jt.hasNext()) { GenPolynomial si = it.next(); List> ai = jt.next(); //System.out.println("si = " + si); //System.out.println("ai = " + ai); if (si == null || ai == null) { continue; } List> pi = blas.scalarProduct(ai, si); //System.out.println("pi = " + pi); rf = blas.vectorAdd(rf, pi); } if (it.hasNext() || jt.hasNext()) { logger.error("zeroRelationsArbitrary wrong sizes"); } //System.out.println("\nMg Mf = " + rf + "\n"); M.add(rf); } //ModuleList ML = new ModuleList( ring, M ); //System.out.println("syz ML = " + ML); // debug only: /* not true in general List> F2 = new ArrayList>( F.size() ); for ( List> rr: M ) { GenPolynomial rrg = blas.scalarProduct( F, rr ); F2.add( rrg ); } PolynomialList pF = new PolynomialList( ring, F ); PolynomialList pF2 = new PolynomialList( ring, F2 ); if ( ! pF.equals( pF2 ) ) { logger.error("is FAB = F ? false"); } */ int sflen = sf.size(); List>> M2; M2 = new ArrayList>>(lenf); int i = 0; for (List> ri : M) { List> r2i; r2i = new ArrayList>(ri.size()); int j = 0; for (GenPolynomial rij : ri) { GenPolynomial p = null; if (i == j) { p = ring.getONE().subtract(rij); } else { if (rij != null) { p = rij.negate(); } } r2i.add(p); j++; } M2.add(r2i); if (!blas.isZero(r2i)) { sf.add(r2i); } i++; } if (debug) { ModuleList M2L = new ModuleList(ring, M2); logger.debug("syz M2L = {}", M2L); ModuleList SF = new ModuleList(ring, sf); logger.debug("syz sf = {}", SF); logger.debug("#syz {}, {}", sflen, sf.size()); if (!isZeroRelation(sf, F)) { logger.error("is syz sf ? false"); } } return sf; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/WordGroebnerBasePseudoRecSeq.java000066400000000000000000000316321445075545500272730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.OrderedWordPairlist; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordPair; import edu.jas.gb.WordPairList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; /** * Non-commutative word Groebner Base sequential algorithm. Implements Groebner * bases and GB test. Coefficients can for example be (commutative) multivariate * polynomials. * @param coefficient type * @author Heinz Kredel */ public class WordGroebnerBasePseudoRecSeq> extends WordGroebnerBaseAbstract> { private static final Logger logger = LogManager.getLogger(WordGroebnerBasePseudoRecSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Greatest common divisor engine for coefficient content and primitive * parts. */ protected final GreatestCommonDivisorAbstract engine; /** * Reduction engine. */ protected final WordPseudoReduction redRec; /** * Reduction engine. */ protected final WordPseudoReduction> red; /** * Coefficient ring factory. */ //protected final RingFactory> cofac; protected final GenPolynomialRing cofac; /** * Constructor. * @param rf coefficient ring factory. */ public WordGroebnerBasePseudoRecSeq(RingFactory> rf) { this(rf, new WordPseudoReductionSeq>()); } /** * Constructor. * @param rf coefficient ring factory. * @param red Reduction engine */ public WordGroebnerBasePseudoRecSeq(RingFactory> rf, WordPseudoReductionSeq> red) { this(rf, red, new OrderedWordPairlist>()); } /** * Constructor. * @param rf coefficient ring factory. * @param red Reduction engine * @param pl pair selection strategy */ @SuppressWarnings("unchecked") public WordGroebnerBasePseudoRecSeq(RingFactory> rf, WordPseudoReductionSeq> red, WordPairList> pl) { super(red, pl); this.red = red; redRec = (WordPseudoReduction) (WordPseudoReduction) red; cofac = (GenPolynomialRing) rf; if (!cofac.isCommutative()) { logger.warn("reduction not correct for {}", cofac); //.toScript() } engine = GCDFactory. getImplementation(cofac.coFac); //not used: engine = GCDFactory.getProxy(cofac.coFac); } /** * Word Groebner base using word pairlist class. * @param F word polynomial list. * @return GB(F) a finite non-commutative Groebner base of F, if it exists. */ @Override public List>> GB(List>> F) { List>> G = normalizeZerosOnes(F); //G = PolyUtil. wordMonic(G); G = recursivePrimitivePart(G); G = normalizeZerosOnes(G); if (G.size() <= 1) { return G; } GenWordPolynomialRing> ring = G.get(0).ring; if (!ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficient ring not commutative"); } //Collections.sort(G); OrderedWordPairlist> pairlist = (OrderedWordPairlist>) strategy .create(ring); pairlist.put(G); logger.info("start {}", pairlist); WordPair> pair; GenWordPolynomial> pi; GenWordPolynomial> pj; List>> S; GenWordPolynomial> H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if (pair == null) { continue; } pi = pair.pi; pj = pair.pj; if (debug) { logger.info("pi = {}, pj = {}", pi, pj); } S = red.SPolynomials(pi, pj); if (S.isEmpty()) { continue; } for (GenWordPolynomial> s : S) { if (s.isZERO()) { //pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", s.leadingWord()); } boolean t = pairlist.criterion3(pair.i, pair.j, s.leadingWord()); //System.out.println("criterion3(" + pair.i + "," + pair.j + ") = " + t); //if ( !t ) { // continue; //} H = redRec.normalformRecursive(G, s); if (debug) { //logger.info("pair = {}", pair); //logger.info("ht(S) = {}", S.monic()); //.leadingWord() ); logger.info("ht(H) = {}", H.monic()); //.leadingWord() ); } if (H.isZERO()) { //pair.setZero(); continue; } if (!t) { logger.info("criterion3({},{}) wrong: {} --> '{}'", pair.i, pair.j, s.leadingWord(), H.leadingWord()); } //H = H.monic(); H = recursivePrimitivePart(H); H = H.abs(); if (debug) { logger.info("ht(H) = {}", H.leadingWord()); } if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } } //logger.info("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); //Collections.sort(G); //Collections.reverse(G); return G; } /** * Minimal ordered Groebner basis. * @param Gp a Groebner base. * @return a reduced Groebner base of Gp. */ @Override public List>> minimalGB(List>> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero polynomials List>> G = new ArrayList>>( Gp.size()); for (GenWordPolynomial> a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // already positive a = a.abs(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible polynomials GenWordPolynomial> a; List>> F; F = new ArrayList>>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop polynomial if (debug) { System.out.println("dropped " + a); List>> ff; ff = new ArrayList>>(G); ff.addAll(F); a = redRec.normalformRecursive(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; if (G.size() <= 1) { return G; } // reduce remaining polynomials Collections.reverse(G); // important for lex GB int len = G.size(); if (debug) { System.out.println("#G " + len); for (GenWordPolynomial> aa : G) { System.out.println("aa = " + aa.length() + ", lt = " + aa.getMap().keySet()); } } int i = 0; while (i < len) { a = G.remove(0); if (debug) { System.out.println("doing " + a.length() + ", lt = " + a.leadingWord()); } a = redRec.normalformRecursive(G, a); G.add(a); // adds as last i++; } return G; } /** * Wird Groebner base simple test. * @param F recursive polynomial list. * @return true, if F is a Groebner base, else false. */ @Override public boolean isGB(List>> F) { if (F == null || F.isEmpty()) { return true; } GenWordPolynomial> pi, pj, h; List>> S; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = 0; j < F.size(); j++) { if (i == j) { continue; } pj = F.get(j); S = red.SPolynomials(pi, pj); if (S.isEmpty()) { continue; } for (GenWordPolynomial> s : S) { //System.out.println("i, j = " + i + ", " + j); h = redRec.normalformRecursive(F, s); if (!h.isZERO()) { logger.info("no GB: pi = {}, pj = {}", pi, pj); logger.info("s = {}, h = {}", s, h); return false; } } } } return true; } /** * GenWordPolynomial recursive coefficient content. * @param P recursive GenWordPolynomial. * @return cont(P). */ public GenPolynomial recursiveContent(GenWordPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } GenPolynomial d = null; for (GenPolynomial c : P.getMap().values()) { //System.out.println("value c = " + c.leadingExpVector()); if (d == null) { d = c; } else { d = engine.gcd(d, c); } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenWordPolynomial recursive coefficient primitive part. * @param P recursive GenWordPolynomial. * @return pp(P). */ public GenWordPolynomial> recursivePrimitivePart(GenWordPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomial d = recursiveContent(P); if (d.isONE()) { return P; } //GenWordPolynomial> pp = P.divide(d); GenWordPolynomial> pp = PolyUtil. recursiveDivide(P, d); if (debug) { GenWordPolynomial> p = pp.multiply(d); if (!p.equals(P)) { throw new ArithmeticException("pp(p)*cont(p) != p: "); } } return pp; } /** * List of GenWordPolynomial recursive coefficient primitive part. * @param F list of recursive GenWordPolynomials. * @return pp(F). */ public List>> recursivePrimitivePart( List>> F) { if (F == null || F.isEmpty()) { return F; } List>> Pp = new ArrayList>>( F.size()); for (GenWordPolynomial> f : F) { GenWordPolynomial> p = recursivePrimitivePart(f); Pp.add(p); } return Pp; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/WordGroebnerBasePseudoSeq.java000066400000000000000000000167611445075545500266470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.OrderedWordPairlist; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordPair; import edu.jas.gb.WordPairList; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Non-commutative word Groebner Base sequential algorithm. Implements Groebner * bases and GB test. Coefficients can for example be integers or (commutative) * univariate polynomials. * @param coefficient type * @author Heinz Kredel */ public class WordGroebnerBasePseudoSeq> extends WordGroebnerBaseAbstract { private static final Logger logger = LogManager.getLogger(WordGroebnerBasePseudoSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Coefficient ring factory. */ protected final RingFactory cofac; /** * Constructor. * @param rf coefficient ring factory. */ public WordGroebnerBasePseudoSeq(RingFactory rf) { this(rf, new WordPseudoReductionSeq()); } /** * Constructor. * @param rf coefficient ring factory. * @param red Reduction engine */ public WordGroebnerBasePseudoSeq(RingFactory rf, WordPseudoReductionSeq red) { this(rf, red, new OrderedWordPairlist()); } /** * Constructor. * @param rf coefficient ring factory. * @param red Reduction engine * @param pl pair selection strategy */ public WordGroebnerBasePseudoSeq(RingFactory rf, WordPseudoReductionSeq red, WordPairList pl) { super(red, pl); cofac = rf; if (!cofac.isCommutative()) { logger.warn("reduction not correct for {}", cofac); //.toScript() } //engine = GCDFactory. getImplementation(rf); //not used: engine = (GreatestCommonDivisorAbstract)GCDFactory.getProxy( rf ); } /** * Word Groebner base using word pairlist class. * @param F word polynomial list. * @return GB(F) a finite non-commutative Groebner base of F, if it exists. */ @Override public List> GB(List> F) { List> G = normalizeZerosOnes(F); //G = PolyUtil. wordMonic(G); G = basePrimitivePart(G); if (G.size() <= 1) { return G; } GenWordPolynomialRing ring = G.get(0).ring; if (!ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficient ring not commutative"); } //Collections.sort(G); OrderedWordPairlist pairlist = (OrderedWordPairlist) strategy.create(ring); pairlist.put(G); logger.info("start {}", pairlist); WordPair pair; GenWordPolynomial pi; GenWordPolynomial pj; List> S; GenWordPolynomial H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if (pair == null) { continue; } pi = pair.pi; pj = pair.pj; if (debug) { logger.info("pi = {}, pj = {}", pi, pj); } S = red.SPolynomials(pi, pj); if (S.isEmpty()) { continue; } for (GenWordPolynomial s : S) { if (s.isZERO()) { //pair.setZero(); continue; } if (debug) { logger.info("ht(S) = {}", s.leadingWord()); } boolean t = pairlist.criterion3(pair.i, pair.j, s.leadingWord()); //System.out.println("criterion3(" + pair.i + "," + pair.j + ") = " + t); //if ( !t ) { // continue; //} H = red.normalform(G, s); if (debug) { //logger.info("pair = {}", pair); //logger.info("ht(S) = {}", S.monic()); //.leadingWord() ); logger.info("ht(H) = {}", H.monic()); //.leadingWord() ); } if (H.isZERO()) { //pair.setZero(); continue; } if (!t) { logger.info("criterion3({},{}) wrong: {} --> {}", pair.i, pair.j, s.leadingWord(), H.leadingWord()); } //H = H.monic(); H = basePrimitivePart(H); H = H.abs(); if (debug) { logger.info("ht(H) = {}", H.leadingWord()); } if (H.isONE()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } if (H.length() > 0) { //l++; G.add(H); pairlist.put(H); } } } //logger.info("#sequential list = {}", G.size()); G = minimalGB(G); logger.info("{}", pairlist); //Collections.sort(G); //Collections.reverse(G); return G; } /** * GenWordPolynomial base coefficient content. * @param P GenWordPolynomial. * @return cont(P). */ public C baseContent(GenWordPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } C d = null; for (C c : P.getMap().values()) { if (d == null) { d = c; } else { d = d.gcd(c); } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenWordPolynomial base coefficient primitive part. * @param P GenWordPolynomial. * @return pp(P). */ public GenWordPolynomial basePrimitivePart(GenWordPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } C d = baseContent(P); if (d.isONE()) { return P; } GenWordPolynomial pp = P.divide(d); if (debug) { GenWordPolynomial p = pp.multiply(d); if (!p.equals(P)) { throw new ArithmeticException("pp(p)*cont(p) != p: "); } } return pp; } /** * List of GenWordPolynomial base coefficient primitive part. * @param F list of GenWordPolynomials. * @return pp(F). */ public List> basePrimitivePart(List> F) { if (F == null || F.isEmpty()) { return F; } List> Pp = new ArrayList>(F.size()); for (GenWordPolynomial f : F) { GenWordPolynomial p = basePrimitivePart(f); Pp.add(p); } return Pp; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/WordPseudoReduction.java000066400000000000000000000022261445075545500255630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import edu.jas.gb.WordReduction; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenWordPolynomial; import edu.jas.structure.RingElem; /** * Polynomial pseudo reduction interface. Defines additionally normalformFactor * and normalformRecursive. * @param coefficient type. * @author Heinz Kredel */ public interface WordPseudoReduction> extends WordReduction { /** * Left normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ public WordPseudoReductionEntry normalformFactor(List> Pp, GenWordPolynomial Ap); /** * Left normalform recursive. * @param Ap recursive polynomial. * @param Pp recursive polynomial list. * @return nf(Ap) with respect to Pp. */ public GenWordPolynomial> normalformRecursive( List>> Pp, GenWordPolynomial> Ap); } java-algebra-system-2.7.200/src/edu/jas/gbufd/WordPseudoReductionEntry.java000066400000000000000000000010551445075545500266040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import edu.jas.poly.GenWordPolynomial; import edu.jas.structure.RingElem; /** * Word polynomial reduction container. Used as container for the return value * of normalformFactor. * @author Heinz Kredel */ public class WordPseudoReductionEntry> { public final GenWordPolynomial pol; public final C multiplicator; public WordPseudoReductionEntry(GenWordPolynomial pol, C multiplicator) { this.pol = pol; this.multiplicator = multiplicator; } } java-algebra-system-2.7.200/src/edu/jas/gbufd/WordPseudoReductionSeq.java000066400000000000000000000276661445075545500262530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.gb.WordReductionAbstract; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.poly.Word; import edu.jas.structure.RingElem; /** * Polynomial word reduction sequential use algorithm. Implements normalform. * @param coefficient type * @author Heinz Kredel */ public class WordPseudoReductionSeq> extends WordReductionAbstract implements WordPseudoReduction { private static final Logger logger = LogManager.getLogger(WordPseudoReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public WordPseudoReductionSeq() { } /** * Normalform. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial normalform(List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficient ring not commutative"); } Map.Entry m; GenWordPolynomial[] P = new GenWordPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; GenWordPolynomial[] p = new GenWordPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e; C a; boolean mt = false; GenWordPolynomial R = Ap.ring.getZERO().copy(); C cone = Ap.ring.coFac.getONE(); GenWordPolynomial Q = null; GenWordPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { Word[] elr = e.divideWord(htl[i]); e = elr[0]; Word f = elr[1]; if (debug) { logger.info("red divideWord: e = {}, f = {}", e, f); } C c = lbc[i]; if (a.remainder(c).isZERO()) { a = a.divide(c); Q = p[i].multiply(a, e, cone, f); } else { R = R.multiply(c); S = S.multiply(c); Q = p[i].multiply(a, e, cone, f); } S = S.subtract(Q); } } return R; } /** * Normalform with left and right recording. * @param lrow left recording matrix, is modified. * @param rrow right recording matrix, is modified. * @param Pp a polynomial list for reduction. * @param Ap a polynomial. * @return nf(Pp,Ap), the normal form of Ap wrt. Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial normalform(List> lrow, List> rrow, List> Pp, GenWordPolynomial Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficient ring not commutative"); } GenWordPolynomial[] P = new GenWordPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; Word[] htl = new Word[l]; C[] lbc = (C[]) new RingElem[l]; GenWordPolynomial[] p = new GenWordPolynomial[l]; Map.Entry m; int j = 0; int i; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e; C a; boolean mt = false; GenWordPolynomial zero = Ap.ring.getZERO().copy(); GenWordPolynomial R = Ap.ring.getZERO(); C cone = Ap.ring.coFac.getONE(); GenWordPolynomial fac = null; GenWordPolynomial Q = null; GenWordPolynomial S = Ap.copy(); while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { Word[] elr = e.divideWord(htl[i]); e = elr[0]; Word f = elr[1]; if (debug) { logger.info("redRec divideWord: e = {}, f = {}", e, f); } C c = lbc[i]; if (a.remainder(c).isZERO()) { a = a.divide(c); Q = p[i].multiply(a, e, cone, f); } else { R = R.multiply(c); S = S.multiply(c); Q = p[i].multiply(a, e, cone, f); } S = S.subtract(Q); // left row fac = lrow.get(i); if (fac == null) { fac = zero.sum(cone, e); } else { fac = fac.sum(cone, e); } lrow.set(i, fac); // right row fac = rrow.get(i); if (fac == null) { fac = zero.sum(a, f); } else { fac = fac.sum(a, f); } rrow.set(i, fac); } } return R; } /** * Normalform with multiplication factor. * @param Pp polynomial list. * @param Ap polynomial. * @return ( nf(Ap), mf ) with respect to Pp and mf as multiplication factor * for Ap. */ public WordPseudoReductionEntry normalformFactor(List> Pp, GenWordPolynomial Ap) { throw new UnsupportedOperationException("normalformFactor not implemented"); } /** * Normalform with polynomial coefficients. * @param Ap polynomial. * @param Pp polynomial list. * @return nf(Ap) with respect to Pp. */ @SuppressWarnings("unchecked") public GenWordPolynomial> normalformRecursive( List>> Pp, GenWordPolynomial> Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isCommutative()) { throw new IllegalArgumentException("coefficient ring not commutative"); } Map.Entry> m; GenWordPolynomial>[] P = new GenWordPolynomial[0]; synchronized (Pp) { P = Pp.toArray(P); } int l = P.length; Word[] htl = new Word[l]; GenPolynomial[] lbc = new GenPolynomial[l]; //(GenPolynomial[]) GenWordPolynomial>[] p = new GenWordPolynomial[l]; int i; int j = 0; for (i = 0; i < l; i++) { p[i] = P[i]; m = p[i].leadingMonomial(); if (m != null) { p[j] = p[i]; htl[j] = m.getKey(); lbc[j] = m.getValue(); j++; } } l = j; Word e, fr, fl; GenPolynomial a, b = null; boolean mt = false; GenWordPolynomial> R = Ap.ring.getZERO().copy(); GenPolynomial cone = Ap.ring.coFac.getONE(); GenWordPolynomial> Q = null; GenWordPolynomial> S = Ap.copy(); GenWordPolynomial> Sp; while (S.length() > 0) { m = S.leadingMonomial(); e = m.getKey(); a = m.getValue(); for (i = 0; i < l; i++) { mt = e.multipleOf(htl[i]); if (mt) break; } if (!mt) { //logger.debug("irred"); //R = R.sum(a, e); //S = S.subtract(a, e); R.doPutToMap(e, a); S.doRemoveFromMap(e, a); // System.out.println(" S = " + S); } else { Word[] elr = e.divideWord(htl[i]); fl = elr[0]; fr = elr[1]; if (debug) { logger.info("redRec divideWord: e = {}, fl = {}, fr = {}", e, fl, fr); } GenPolynomial c = lbc[i]; if (PolyUtil. baseSparsePseudoRemainder(a, c).isZERO()) { b = PolyUtil. basePseudoDivide(a, c); Q = p[i].multiply(b, fl, cone, fr); } else { R = R.multiply(c); S = S.multiply(c); Q = p[i].multiply(a, fl, cone, fr); } Sp = S.subtract(Q); if (e.equals(Sp.leadingWord())) { // TODO: avoid, not possible in general //logger.info("redRec: e = {}, hti = {}, fl = {}, fr = {}", e, htl[i], fl, fr); //logger.info("redRec: S = {}, Sp = {}, a = {}, b = {}, c = {}", S, Sp, a, b, c); //throw new RuntimeException("degree not descending"); R = R.multiply(c); S = S.multiply(c); Q = p[i].multiply(a, fl, cone, fr); Sp = S.subtract(Q); } S = Sp; } } return R; } @Override public GenWordPolynomial leftNormalform(List> Pp, GenWordPolynomial Ap) { throw new UnsupportedOperationException("leftNormalform not implemented"); } @Override public GenWordPolynomial leftNormalform(List> lrow, List> Pp, GenWordPolynomial Ap) { throw new UnsupportedOperationException("leftNormalform not implemented"); } @Override public GenWordPolynomial rightNormalform(List> Pp, GenWordPolynomial Ap) { throw new UnsupportedOperationException("rightNormalform not implemented"); } @Override public GenWordPolynomial rightNormalform(List> rrow, List> Pp, GenWordPolynomial Ap) { throw new UnsupportedOperationException("rightNormalform not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/gbufd/package.html000066400000000000000000000017711445075545500232350ustar00rootroot00000000000000 Groebner bases using unique factorization

Groebner bases using unique factorization package.

This package contains classes for polynomial pseudo reduction and Groebner bases using pseudo reduction GroebnerBasePseudoSeq and GroebnerBasePseudoRecSeq. Groebner bases for polynomial rings over regular rings (direct products of fields or integral domains) are implemented in RGroebnerBaseSeq and RGroebnerBasePseudoSeq.


Heinz Kredel

Last modified: Fri Dec 24 15:00:40 CET 2010

$Id$

java-algebra-system-2.7.200/src/edu/jas/integrate/000077500000000000000000000000001445075545500216415ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/integrate/ElementaryIntegration.java000066400000000000000000000466401445075545500270270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.FactorFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.ufd.GreatestCommonDivisorSubres; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Methods related to elementary integration. In particular there are methods * for Hermite reduction and Rothstein-Trager integration of the logarithmic * part. * * @author Axel Kramer * @author Heinz Kredel * @param coefficient type */ public class ElementaryIntegration> { private static final Logger logger = LogManager.getLogger(ElementaryIntegration.class); private static final boolean debug = logger.isDebugEnabled(); /** * Engine for factorization. */ public final FactorAbstract irr; /** * Engine for squarefree decomposition. */ public final SquarefreeAbstract sqf; /** * Engine for greatest common divisors. */ public final GreatestCommonDivisorAbstract ufd; /** * Flag for irreducible input to integrateLogPart. */ public boolean irredLogPart = true; /** * Constructor. */ public ElementaryIntegration(RingFactory br) { ufd = GCDFactory. getProxy(br); sqf = SquarefreeFactory. getImplementation(br); irr = /*(FactorAbsolute)*/FactorFactory. getImplementation(br); irredLogPart = true; } /** * Integration of a rational function. * @param r rational function * @return Integral container, such that integrate(r) = sum_i(g_i) + sum_j( * an_j log(hd_j) ) */ public QuotIntegral integrate(Quotient r) { Integral integral = integrate(r.num, r.den); return new QuotIntegral(r.ring, integral); } /** * Integration of a rational function. * @param a numerator * @param d denominator * @return Integral container, such that integrate(a/d) = sum_i(gn_i/gd_i) + * integrate(h0) + sum_j( an_j log(hd_j) ) */ public Integral integrate(GenPolynomial a, GenPolynomial d) { if (d == null || a == null || d.isZERO()) { throw new IllegalArgumentException("zero or null not allowed"); } if (a.isZERO()) { return new Integral(a, d, a); } if (d.isONE()) { GenPolynomial pi = PolyUtil. baseIntegral(a); return new Integral(a, d, pi); } GenPolynomialRing pfac = d.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients " + pfac); } GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(a, d); GenPolynomial p = qr[0]; GenPolynomial r = qr[1]; GenPolynomial c = ufd.gcd(r, d); if (!c.isONE()) { r = PolyUtil. basePseudoQuotientRemainder(r, c)[0]; d = PolyUtil. basePseudoQuotientRemainder(d, c)[0]; } List>[] ih = integrateHermite(r, d); List> rat = ih[0]; List> log = ih[1]; GenPolynomial pp = log.remove(0); p = p.sum(pp); GenPolynomial pi = PolyUtil. baseIntegral(p); if (debug) { logger.debug("pi = {}", pi); logger.debug("rat = {}", rat); logger.debug("log = {}", log); } if (log.size() == 0) { return new Integral(a, d, pi, rat); } List> logi = new ArrayList>(log.size() / 2); for (int i = 0; i < log.size(); i++) { GenPolynomial ln = log.get(i++); GenPolynomial ld = log.get(i); LogIntegral pf = integrateLogPartPrepare(ln, ld); logi.add(pf); } logger.debug("logi = {}", logi); return new Integral(a, d, pi, rat, logi); } /** * Integration of the rational part, Hermite reduction step. * @param a numerator * @param d denominator, gcd(a,d) == 1 * @return [ [ gn_i, gd_i ], [ h0, hn_j, hd_j ] ] such that integrate(a/d) = * sum_i(gn_i/gd_i) + integrate(h0) + sum_j( integrate(hn_j/hd_j) ) */ @SuppressWarnings({ "unchecked", "cast" }) public List>[] integrateHermite(GenPolynomial a, GenPolynomial d) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("d == null or d == 0"); } if (a == null || a.isZERO()) { throw new IllegalArgumentException("a == null or a == 0"); } // get squarefree decomposition SortedMap, Long> sfactors = sqf.squarefreeFactors(d); List> D = new ArrayList>(sfactors.keySet()); List> DP = new ArrayList>(); for (GenPolynomial f : D) { long e = sfactors.get(f); GenPolynomial dp = f.power(e); //Power.> positivePower(f, e); DP.add(dp); } //System.out.println("D: " + D); //System.out.println("DP: " + DP); // get partial fraction decomposition List> Ai = ufd.basePartialFraction(a, DP); //System.out.println("Ai: " + Ai); List> G = new ArrayList>(); List> H = new ArrayList>(); H.add(Ai.remove(0)); // P GenPolynomialRing fac = d.ring; int i = 0; for (GenPolynomial v : D) { //System.out.println("V:" + v.toString()); GenPolynomial Ak = Ai.get(i++); //System.out.println("Ak: " + Ak.toString()); long k = sfactors.get(v); // assert low power for (long j = k - 1; j >= 1; j--) { //System.out.println("Step(" + k + "," + j + ")"); GenPolynomial DV_dx = PolyUtil. baseDerivative(v); GenPolynomial Aik = Ak.divide(fac.fromInteger(-j)); GenPolynomial[] BC = ufd.baseGcdDiophant(DV_dx, v, Aik); GenPolynomial b = BC[0]; GenPolynomial c = BC[1]; GenPolynomial vj = v.power(j); G.add(b); // B G.add(vj); // v^j Ak = fac.fromInteger(-j).multiply(c).subtract(PolyUtil. baseDerivative(b)); //System.out.println("B: " + b.toString()); //System.out.println("C: " + c.toString()); } //System.out.println("V:" + v.toString()); //System.out.println("Ak: " + Ak.toString()); if (!Ak.isZERO()) { H.add(Ak); // A_k H.add(v); // v } } List>[] ret = (List>[]) new List[2]; ret[0] = G; ret[1] = H; return ret; } /** * Univariate GenPolynomial integration of the logarithmic part, eventual * preparation for irreducible factorization of P. * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1. * @return logarithmic part container. */ public LogIntegral integrateLogPartPrepare(GenPolynomial A, GenPolynomial P) { if (!irredLogPart) { return integrateLogPart(A, P); } if (P == null || P.isZERO()) { throw new IllegalArgumentException(" P == null or P == 0"); } if (A == null || A.isZERO()) { throw new IllegalArgumentException(" A == null or A == 0"); } //System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients " + pfac); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } List> Pfac = irr.baseFactorsSquarefree(P); //System.out.println("\nPfac = " + Pfac); List> Afac = ufd.basePartialFraction(A, Pfac); GenPolynomial A0 = Afac.remove(0); if (!A0.isZERO()) { throw new RuntimeException(" A0 != 0: deg(A)>= deg(P)"); } // algebraic and linear factors int i = 0; for (GenPolynomial pi : Pfac) { GenPolynomial ai = Afac.get(i++); if (pi.degree(0) <= 1) { cfactors.add(ai.leadingBaseCoefficient()); cdenom.add(pi); continue; } LogIntegral pf = integrateLogPart(ai, pi); cfactors.addAll(pf.cfactors); cdenom.addAll(pf.cdenom); afactors.addAll(pf.afactors); adenom.addAll(pf.adenom); } return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } /** * Univariate GenPolynomial integration of the logarithmic part, * Rothstein-Trager algorithm. * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate squarefree or irreducible GenPolynomial. // gcd(A,P) * == 1 automatic * @return logarithmic part container. */ public LogIntegral integrateLogPart(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException("P == null or P == 0"); } //System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients " + pfac); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } // derivative GenPolynomial Pp = PolyUtil. baseDerivative(P); //no: Pp = Pp.monic(); //System.out.println("\nP = " + P); //System.out.println("Pp = " + Pp); // Q[t] String[] vars = new String[] { "t" }; GenPolynomialRing cfac = new GenPolynomialRing(pfac.coFac, 1, pfac.tord, vars); GenPolynomial t = cfac.univariate(0); //System.out.println("t = " + t); // Q[x][t] GenPolynomialRing> rfac = new GenPolynomialRing>(pfac, cfac); // sic //System.out.println("rfac = " + rfac.toScript()); // transform polynomials to bi-variate polynomial GenPolynomial> Ac = PolyUfdUtil. introduceLowerVariable(rfac, A); //System.out.println("Ac = " + Ac); GenPolynomial> Pc = PolyUfdUtil. introduceLowerVariable(rfac, P); //System.out.println("Pc = " + Pc); GenPolynomial> Pcp = PolyUfdUtil. introduceLowerVariable(rfac, Pp); //System.out.println("Pcp = " + Pcp); // Q[t][x] GenPolynomialRing> rfac1 = Pc.ring; //System.out.println("rfac1 = " + rfac1.toScript()); // A - t P' GenPolynomial> tc = rfac1.getONE().multiply(t); //System.out.println("tc = " + tc); GenPolynomial> At = Ac.subtract(tc.multiply(Pcp)); //System.out.println("At = " + At); GreatestCommonDivisorSubres engine = new GreatestCommonDivisorSubres(); // = GCDFactory.getImplementation( cfac.coFac ); GreatestCommonDivisorAbstract> aengine = null; GenPolynomial> Rc = engine.recursiveUnivariateResultant(Pc, At); //System.out.println("Rc = " + Rc); GenPolynomial res = Rc.leadingBaseCoefficient(); //no: res = res.monic(); //System.out.println("\nres = " + res); SortedMap, Long> resfac = irr.baseFactors(res); //System.out.println("resfac = " + resfac + "\n"); for (GenPolynomial r : resfac.keySet()) { //System.out.println("\nr(t) = " + r); if (r.isConstant()) { continue; } //vars = new String[] { "z_" + Math.abs(r.hashCode() % 1000) }; vars = pfac.newVars("z_"); pfac = pfac.copy(); @SuppressWarnings("unused") String[] unused = pfac.setVars(vars); r = pfac.copy(r); // hack to exchange the variables //System.out.println("r(z_) = " + r); AlgebraicNumberRing afac = new AlgebraicNumberRing(r, true); // since irreducible logger.debug("afac = {}", afac); //.toScript() AlgebraicNumber a = afac.getGenerator(); //no: a = a.negate(); //System.out.println("a = " + a); // K(alpha)[x] GenPolynomialRing> pafac = new GenPolynomialRing>(afac, Pc.ring); //System.out.println("pafac = " + pafac.toScript()); // convert to K(alpha)[x] GenPolynomial> Pa = PolyUtil. convertToAlgebraicCoefficients(pafac, P); //System.out.println("Pa = " + Pa); GenPolynomial> Pap = PolyUtil. convertToAlgebraicCoefficients(pafac, Pp); //System.out.println("Pap = " + Pap); GenPolynomial> Aa = PolyUtil. convertToAlgebraicCoefficients(pafac, A); //System.out.println("Aa = " + Aa); // A - a P' GenPolynomial> Ap = Aa.subtract(Pap.multiply(a)); //System.out.println("Ap = " + Ap); if (aengine == null) { aengine = GCDFactory.> getImplementation(afac); } GenPolynomial> Ga = aengine.baseGcd(Pa, Ap); //System.out.println("Ga = " + Ga); if (Ga.isConstant()) { //System.out.println("warning constant gcd ignored"); continue; } // If a is equal to zero if (a.isZERO()) { continue; } afactors.add(a); adenom.add(Ga); // special quadratic case // todo: eventually implement special cases deg = 3, 4 } return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } /** * Derivation of a univariate rational function. * @param r rational function * @return dr/dx * @deprecated(forRemoval=true) use PolyUfdUtil.derivative() */ @Deprecated public Quotient derivative(Quotient r) { return PolyUfdUtil. derivative(r); } /** * Test of integration of a rational function. * @param ri integral * @return true, if ri is an integral, else false. */ public boolean isIntegral(QuotIntegral ri) { Quotient r = ri.quot; QuotientRing qr = r.ring; Quotient i = r.ring.getZERO(); for (Quotient q : ri.rational) { Quotient qd = derivative(q); i = i.sum(qd); } if (ri.logarithm.size() == 0) { return r.equals(i); } for (LogIntegral li : ri.logarithm) { Quotient q = new Quotient(qr, li.num, li.den); i = i.sum(q); } boolean t = r.equals(i); if (!t) { return false; } for (LogIntegral li : ri.logarithm) { t = isIntegral(li); if (!t) { return false; } } return true; } /** * Test of integration of the logarithmic part of a rational function. * @param rl logarithmic part of an integral * @return true, if rl is an integral, else false. */ public boolean isIntegral(LogIntegral rl) { QuotientRing qr = new QuotientRing(rl.den.ring); Quotient r = new Quotient(qr, rl.num, rl.den); Quotient i = qr.getZERO(); int j = 0; for (GenPolynomial d : rl.cdenom) { GenPolynomial dp = PolyUtil. baseDerivative(d); dp = dp.multiply(rl.cfactors.get(j++)); Quotient f = new Quotient(qr, dp, d); i = i.sum(f); } if (rl.afactors.size() == 0) { return r.equals(i); } r = r.subtract(i); QuotientRing> aqr = new QuotientRing>(rl.adenom.get(0).ring); Quotient> ai = aqr.getZERO(); GenPolynomial> aqn = PolyUtil. convertToAlgebraicCoefficients(aqr.ring, r.num); GenPolynomial> aqd = PolyUtil. convertToAlgebraicCoefficients(aqr.ring, r.den); Quotient> ar = new Quotient>(aqr, aqn, aqd); j = 0; for (GenPolynomial> d : rl.adenom) { GenPolynomial> dp = PolyUtil.> baseDerivative(d); dp = dp.multiply(rl.afactors.get(j++)); Quotient> f = new Quotient>(aqr, dp, d); ai = ai.sum(f); } boolean t = ar.equals(ai); if (t) { return true; } logger.warn("log integral not verified"); //System.out.println("r = " + r); //System.out.println("afactors = " + rl.afactors); //System.out.println("adenom = " + rl.adenom); //System.out.println("ar = " + ar); //System.out.println("ai = " + ai); return true; } } java-algebra-system-2.7.200/src/edu/jas/integrate/ElementaryIntegrationBernoulli.java000066400000000000000000000061071445075545500306750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.FactorAbsolute; import edu.jas.ufd.PartialFraction; /** * Methods related to the Bernoulli algorithm for elementary integration. The * denominator is factored into linear factors over iterated algebraic * extensions over the rational numbers. * * @author Heinz Kredel * @param coefficient type */ public class ElementaryIntegrationBernoulli> extends ElementaryIntegration { private static final Logger logger = LogManager.getLogger(ElementaryIntegrationBernoulli.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public ElementaryIntegrationBernoulli(RingFactory br) { super(br); if (!(irr instanceof FactorAbsolute)) { logger.error("no absolute factorization available for coefficient ring {}", br); throw new IllegalArgumentException( "no absolute factorization available for coefficient ring " + br); } irredLogPart = true; // force to true? } /** * Univariate GenPolynomial integration of the logarithmic part, Bernoulli * linear factorization algorithm. * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate squarefree or irreducible GenPolynomial. // gcd(A,P) * == 1 automatic * @return logarithmic part container. */ @Override public LogIntegral integrateLogPart(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException("P == null or P == 0"); } //System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } // pfac.coFac.isField() by FactorAbsolute List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } // complete factorization to linear factors PartialFraction F = ((FactorAbsolute) irr).baseAlgebraicPartialFraction(A, P); //System.out.println("\npartial fraction " + F); return new LogIntegral(A, P, F.cfactors, F.cdenom, F.afactors, F.adenom); } } java-algebra-system-2.7.200/src/edu/jas/integrate/ElementaryIntegrationCzichowski.java000066400000000000000000000150371445075545500310610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gbufd.GBFactory; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.PolyUfdUtil; /** * Method related to elementary integration. Czichowski integration based on * Groebner bases for the logarithmic part. * * @author Youssef Elbarbary * @param coefficient type */ public class ElementaryIntegrationCzichowski> extends ElementaryIntegration { private static final Logger logger = LogManager.getLogger(ElementaryIntegrationCzichowski.class); /** * Engine for Groebner basis. */ public final GroebnerBaseAbstract red; /** * Constructor. */ public ElementaryIntegrationCzichowski(RingFactory br) { super(br); red = GBFactory. getImplementation(br); } /** * Univariate GenPolynomial integration of the logarithmic part, Czichowski * * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate irreducible GenPolynomial. // gcd(A,P) == 1 automatic * @return logarithmic part container. */ @Override public LogIntegral integrateLogPart(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException("P == null or P == 0"); } // System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients " + pfac); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } // derivative GenPolynomial Pp = PolyUtil. baseDerivative(P); // no: Pp = Pp.monic(); // System.out.println("Pp = " + Pp); // Q[t] String[] vars = new String[] { "t" }; GenPolynomialRing cfac = new GenPolynomialRing(pfac.coFac, 1, pfac.tord, vars); GenPolynomial t = cfac.univariate(0); // Q[x][t] GenPolynomialRing> rfac = new GenPolynomialRing>(pfac, cfac); // sic // System.out.println("rfac = " + rfac.toScript()); // transform polynomials to bi-variate polynomial GenPolynomial> Ac = PolyUfdUtil. introduceLowerVariable(rfac, A); // System.out.println("Ac = " + Ac); GenPolynomial> Pc = PolyUfdUtil. introduceLowerVariable(rfac, P); // System.out.println("Pc = " + Pc); GenPolynomial> Pcp = PolyUfdUtil. introduceLowerVariable(rfac, Pp); // System.out.println("Pcp = " + Pcp); // Q[t][x] GenPolynomialRing> rfac1 = Pc.ring; // System.out.println("rfac1 = " + rfac1.toScript()); // A - t P' GenPolynomial> tc = rfac1.getONE().multiply(t); // System.out.println("tc = " + tc); GenPolynomial> At = Ac.subtract(tc.multiply(Pcp)); // System.out.println("At = " + At); // Q[t][x] to Q[t,x] GenPolynomialRing dfac = pfac.distribute(); GenPolynomial Atd = PolyUtil.distribute(dfac, At); GenPolynomial Pcd = PolyUtil.distribute(dfac, Pc); // Groebner Basis List> myList = new ArrayList>(); myList.add(Atd); myList.add(Pcd); List> mGB = red.GB(myList); Collections.sort(mGB); // OrderedPolynomialList // Q[t,x] to Q[t][x] List>> gbList = PolyUtil.recursive(rfac1, mGB); // Content & Primitive Part int counter = 1; for (GenPolynomial> tmGB : gbList) { if (counter == gbList.size()) { continue; } GenPolynomial content = ufd.recursiveContent(tmGB); // Content of GB i+1 GenPolynomial c = ufd.recursiveContent(gbList.get(counter)); GenPolynomial Q = content.divide(c); // Primitive Part of GB i+1 GenPolynomial> ppS = ufd.baseRecursivePrimitivePart(gbList.get(counter)); // System.out.println("pp(S) = " + ppS); counter++; // vars = new String[] { "z_" + Math.abs(r.hashCode() % 1000) }; vars = pfac.newVars("z_"); pfac = pfac.copy(); @SuppressWarnings("unused") String[] unused = pfac.setVars(vars); if (Q.degreeMin() == 1) { Q = Q.divide(t); } Q = pfac.copy(Q); // hack to exchange the variables AlgebraicNumberRing afac = new AlgebraicNumberRing(Q); logger.debug("afac = {}", afac); //.toScript() AlgebraicNumber a = afac.getGenerator(); // no: a = a.negate(); // System.out.println("a = " + a); // K(alpha)[x] GenPolynomialRing> pafac = new GenPolynomialRing>(afac, ppS.ring); // System.out.println("pafac = " + pafac.toScript()); // convert to K(alpha)[x] GenPolynomial> Sa = PolyUtil.convertRecursiveToAlgebraicCoefficients(pafac, ppS); // System.out.println("Sa = " + Sa); afactors.add(a); adenom.add(Sa); // adenom.add(Sa.monic()); } return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } } java-algebra-system-2.7.200/src/edu/jas/integrate/ElementaryIntegrationLazard.java000066400000000000000000000200631445075545500301540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.ufd.GreatestCommonDivisorSubres; import edu.jas.ufd.PolyUfdUtil; /** * Method related to elementary integration. Lazard-Rioboo-Trager integration of * the logarithmic part. * * @author Youssef Elbarbary * @param coefficient type */ public class ElementaryIntegrationLazard> extends ElementaryIntegration { private static final Logger logger = LogManager.getLogger(ElementaryIntegrationLazard.class); /** * Constructor. */ public ElementaryIntegrationLazard(RingFactory br) { super(br); } /** * Univariate GenPolynomial integration of the logarithmic part, Lazard - * Rioboo - Trager * * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate irreducible GenPolynomial. // gcd(A,P) == 1 automatic * @return logarithmic part container. */ @Override public LogIntegral integrateLogPart(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException("P == null or P == 0"); } // System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials " + pfac); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients " + pfac); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } // derivative GenPolynomial Pp = PolyUtil. baseDerivative(P); // no: Pp = Pp.monic(); // System.out.println("\nP = " + P); // Q[t] String[] vars = new String[] { "t" }; GenPolynomialRing cfac = new GenPolynomialRing(pfac.coFac, 1, pfac.tord, vars); GenPolynomial t = cfac.univariate(0); // System.out.println("t = " + t); // Q[x][t] GenPolynomialRing> rfac = new GenPolynomialRing>(pfac, cfac); // sic // System.out.println("rfac = " + rfac.toScript()); // transform polynomials to bi-variate polynomial GenPolynomial> Ac = PolyUfdUtil. introduceLowerVariable(rfac, A); GenPolynomial> Pc = PolyUfdUtil. introduceLowerVariable(rfac, P); GenPolynomial> Pcp = PolyUfdUtil. introduceLowerVariable(rfac, Pp); // Q[t][x] GenPolynomialRing> rfac1 = Pc.ring; // System.out.println("rfac1 = " + rfac1.toScript()); // A - t P' GenPolynomial> tc = rfac1.getONE().multiply(t); // System.out.println("tc = " + tc); GenPolynomial> At = Ac.subtract(tc.multiply(Pcp)); // System.out.println("A - tP' = " + At); GreatestCommonDivisorSubres engine = new GreatestCommonDivisorSubres(); // = GCDFactory.getImplementation( cfac.coFac ); GreatestCommonDivisorAbstract> aengine = null; // Subresultant von A - t P' List>> RcList = engine.recursiveUnivariateSubResultantList(Pc, At); // returning GenPolynomial> Rc = RcList.get(RcList.size() - 1); // just getting R //System.out.println("R = " + Rc); // SquareFree(R) SortedMap, Long> resSquareFree = sqf.squarefreeFactors(Rc.leadingBaseCoefficient()); logger.info("SquareFree(R) = {}", resSquareFree); // First Loop SortedMap, Long> sfactors = null; GenPolynomial> Sa = null; GenPolynomial> S = null; GenPolynomial Q = null; for (Entry, Long> qi : resSquareFree.entrySet()) { Q = qi.getKey(); // System.out.println("\nr(t) = " + r); if (Q.isConstant()) { continue; } if (Q.degreeMin() == 1) { Q = Q.divide(t); } vars = pfac.newVars("z_"); pfac = pfac.copy(); @SuppressWarnings("unused") String[] unused = pfac.setVars(vars); GenPolynomial qi2 = pfac.copy(Q); // hack to exchange the variables // System.out.println("r(z_) = " + r); AlgebraicNumberRing afac = new AlgebraicNumberRing(qi2); logger.debug("afac = {}", afac); //.toScript() AlgebraicNumber a = afac.getGenerator(); // no: a = a.negate(); // System.out.println("a = " + a); // K(alpha)[x] GenPolynomialRing> pafac = new GenPolynomialRing>(afac, Pc.ring); // 1Condition 2Condition i = deg(D) + Check condition again! if (qi2.degree() > 0) { if (qi.getValue() == Pc.degree()) { GenPolynomial sExp = P; // convert to K(alpha)[x] Sa = PolyUtil. convertToAlgebraicCoefficients(pafac, sExp); afactors.add(a); adenom.add(Sa); return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } int countj = 1; // RcList.remove(RcList.size()-1); for (GenPolynomial> Ri : RcList) { if (qi.getValue() == Ri.degree()) { S = Ri; // convert to K(alpha)[x] Sa = PolyUtil.convertRecursiveToAlgebraicCoefficients(pafac, S); sfactors = sqf.squarefreeFactors(S.leadingBaseCoefficient()); logger.info("SquareFree(S){}", sfactors); } } for (GenPolynomial ai : sfactors.keySet()) { GenPolynomial> aiC = PolyUtil. convertToAlgebraicCoefficients(pafac, ai); GenPolynomial> qiC = PolyUtil. convertToAlgebraicCoefficients(pafac, qi2); if (aengine == null) { aengine = GCDFactory.> getImplementation(afac); } GenPolynomial> gcd = aengine.baseGcd(aiC, qiC); gcd = gcd.power(countj); Sa = (Sa.divide(gcd)); countj++; if (Sa.isZERO() || a.isZERO()) { System.out.println("warning constant Sa ignored"); continue; } } //System.out.println("S = " + Sa); afactors.add(a); adenom.add(Sa.monic()); // adenom.add(Sa.monic()); } } return new LogIntegral(A, P, cfactors, cdenom, afactors, adenom); } } java-algebra-system-2.7.200/src/edu/jas/integrate/Examples.java000066400000000000000000000211521445075545500242630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Examples related to elementary integration. * * @author Axel Kramer * @author Heinz Kredel */ public class Examples { /** * Main program. * * @param args */ public static void main(String[] args) { example1(); example2(); example3(); } /** * Example rationals. */ public static void example1() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); ElementaryIntegration eIntegrator = new ElementaryIntegration(br); GenPolynomial a = fac.parse("x^7 - 24 x^4 - 4 x^2 + 8 x - 8"); System.out.println("A: " + a.toString()); GenPolynomial d = fac.parse("x^8 + 6 x^6 + 12 x^4 + 8 x^2"); System.out.println("D: " + d.toString()); GenPolynomial gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); List>[] ret = eIntegrator.integrateHermite(a, d); System.out.println("Result: " + ret[0] + " , " + ret[1]); System.out.println("-----"); a = fac.parse("10 x^2 - 63 x + 29"); System.out.println("A: " + a.toString()); d = fac.parse("x^3 - 11 x^2 + 40 x -48"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrateHermite(a, d); System.out.println("Result: " + ret[0] + " , " + ret[1]); System.out.println("-----"); a = fac.parse("x+3"); System.out.println("A: " + a.toString()); d = fac.parse("x^2 - 3 x - 40"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrateHermite(a, d); System.out.println("Result: " + ret[0] + " , " + ret[1]); System.out.println("-----"); a = fac.parse("10 x^2+12 x + 20"); System.out.println("A: " + a.toString()); d = fac.parse("x^3 - 8"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrateHermite(a, d); System.out.println("Result: " + ret[0] + " , " + ret[1]); System.out.println("------------------------------------------------------\n"); ComputerThreads.terminate(); } /** * Example rational plus logarithm. */ public static void example2() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); ElementaryIntegration eIntegrator = new ElementaryIntegration(br); GenPolynomial a = fac.parse("x^7 - 24 x^4 - 4 x^2 + 8 x - 8"); System.out.println("A: " + a.toString()); GenPolynomial d = fac.parse("x^8 + 6 x^6 + 12 x^4 + 8 x^2"); System.out.println("D: " + d.toString()); GenPolynomial gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); Integral ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("10 x^2 - 63 x + 29"); System.out.println("A: " + a.toString()); d = fac.parse("x^3 - 11 x^2 + 40 x -48"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("x+3"); System.out.println("A: " + a.toString()); d = fac.parse("x^2 - 3 x - 40"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("10 x^2+12 x + 20"); System.out.println("A: " + a.toString()); d = fac.parse("x^3 - 8"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("1"); System.out.println("A: " + a.toString()); d = fac.parse("(x**5 + x - 7)"); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("1"); d = fac.parse("(x**5 + x - 7)"); a = a.sum(d); System.out.println("A: " + a.toString()); System.out.println("D: " + d.toString()); gcd = a.gcd(d); System.out.println("GCD: " + gcd.toString()); ret = eIntegrator.integrate(a, d); System.out.println("Result: " + ret); System.out.println("-----"); ComputerThreads.terminate(); } /** * Example quotients with rational plus logarithm. */ public static void example3() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); QuotientRing qfac = new QuotientRing(fac); ElementaryIntegration eIntegrator = new ElementaryIntegration(br); GenPolynomial a = fac.parse("x^7 - 24 x^4 - 4 x^2 + 8 x - 8"); GenPolynomial d = fac.parse("x^8 + 6 x^6 + 12 x^4 + 8 x^2"); Quotient q = new Quotient(qfac, a, d); System.out.println("q = " + q); QuotIntegral ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("10 x^2 - 63 x + 29"); d = fac.parse("x^3 - 11 x^2 + 40 x -48"); q = new Quotient(qfac, a, d); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("x+3"); d = fac.parse("x^2 - 3 x - 40"); q = new Quotient(qfac, a, d); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("10 x^2+12 x + 20"); d = fac.parse("x^3 - 8"); q = new Quotient(qfac, a, d); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("1"); d = fac.parse("(x**5 + x - 7)"); q = new Quotient(qfac, a, d); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); a = fac.parse("1"); d = fac.parse("(x**5 + x - 7)"); a = a.sum(d); q = new Quotient(qfac, a, d); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); System.out.println("-----"); Quotient qi = qfac.random(7); //qi = qi.sum( qfac.random(5) ); q = eIntegrator.derivative(qi); System.out.println("qi = " + qi); System.out.println("q = " + q); ret = eIntegrator.integrate(q); System.out.println("Result: " + ret); boolean t = eIntegrator.isIntegral(ret); System.out.println("isIntegral = " + t); System.out.println("-----"); ComputerThreads.terminate(); } } java-algebra-system-2.7.200/src/edu/jas/integrate/ExamplesMore.java000066400000000000000000000172511445075545500251130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * More examples for integrating rational functions. * * @author Youssef Elbarbary */ public class ExamplesMore { /** * Main program. * * @param args */ public static void main(String[] args) { exampleRothstein(); exampleLazard(); exampleCzichwoski(); exampleBernoulli(); ComputerThreads.terminate(); } /** * Example for integrating a rational function using Rothstein-Trager * algorithm. */ public static void exampleRothstein() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); QuotientRing qfac = new QuotientRing(fac); ElementaryIntegration eIntegrator = new ElementaryIntegration(br); GenPolynomial a = fac.parse("x^4 - 3 x^2 + 6"); GenPolynomial d = fac.parse("x^6 - 5 x^4 + 5 x^2 + 4"); // GenPolynomial a = fac.parse("36"); // GenPolynomial d = fac.parse("x^5 - 2 x^4 - 2 x^3 + 4 x^2 + x - 2"); // GenPolynomial a = fac.parse("8 x^9 + x^8 - 12 x^7 - 4 x^6 - 26 x^5 - 6 x^4 + 30 x^3 + 23 x^2 - 2 x - 7"); // GenPolynomial d = fac.parse("x^10 - 2 x^8 - 2 x^7 - 4 x^6 + 7 x^4 + 10 x^3 + 3 x^2 - 4 x - 2"); // GenPolynomial a = fac.parse("x^5 - x^4 + 4 x^3 + x^2 - x + 5"); // GenPolynomial d = fac.parse("x^4 - 2 x^3 + 5 x^2 - 4 x + 4"); Quotient q = new Quotient(qfac, a, d); eIntegrator.irredLogPart = true; double startTime = System.currentTimeMillis(); edu.jas.integrate.QuotIntegral ret = eIntegrator.integrate(q); double endTime = System.currentTimeMillis(); System.out.println("Rothstein took " + ((endTime - startTime) / 1000) + " seconds"); System.out.println("Result: " + ret); boolean testAnswer = eIntegrator.isIntegral(ret); System.out.println(testAnswer); } /** * Example for integrating a rational function using Lazard algorithm. */ public static void exampleLazard() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); QuotientRing qfac = new QuotientRing(fac); ElementaryIntegration eIntegratorLaz = new ElementaryIntegrationLazard(br); GenPolynomial a = fac.parse("x^4 - 3 x^2 + 6"); GenPolynomial d = fac.parse("x^6 - 5 x^4 + 5 x^2 + 4"); // GenPolynomial a = fac.parse("36"); // GenPolynomial d = fac.parse("x^5 - 2 x^4 - 2 x^3 + 4 x^2 + x - 2"); // GenPolynomial a = fac.parse("8 x^9 + x^8 - 12 x^7 - 4 x^6 - 26 x^5 - 6 x^4 + 30 x^3 + 23 x^2 - 2 x - 7"); // GenPolynomial d = fac.parse("x^10 - 2 x^8 - 2 x^7 - 4 x^6 + 7 x^4 + 10 x^3 + 3 x^2 - 4 x - 2"); // GenPolynomial a = fac.parse("x^5 - x^4 + 4 x^3 + x^2 - x + 5"); // GenPolynomial d = fac.parse("x^4 - 2 x^3 + 5 x^2 - 4 x + 4"); Quotient q = new Quotient(qfac, a, d); eIntegratorLaz.irredLogPart = true; double startTime = System.currentTimeMillis(); QuotIntegral ret = eIntegratorLaz.integrate(q); double endTime = System.currentTimeMillis(); System.out.println("Lazard took " + ((endTime - startTime) / 1000) + " seconds"); System.out.println("Result: " + ret); boolean testAnswer = eIntegratorLaz.isIntegral(ret); System.out.println(testAnswer); // System.out.println("-----"); } /** * Example for integrating a rational function using Czichowski algorithm. */ public static void exampleCzichwoski() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); QuotientRing qfac = new QuotientRing(fac); ElementaryIntegration eIntegratorCzi = new ElementaryIntegrationCzichowski( br); // GenPolynomial a = fac.parse("x^4 - 3 x^2 + 6"); // GenPolynomial d = fac.parse("x^6 - 5 x^4 + 5 x^2 + 4"); // GenPolynomial a = fac.parse("36"); // GenPolynomial d = fac.parse("x^5 - 2 x^4 - 2 x^3 + 4 x^2 + x - 2"); // GenPolynomial a = fac.parse("8 x^9 + x^8 - 12 x^7 - 4 x^6 - 26 x^5 - 6 x^4 + 30 x^3 + 23 x^2 - 2 x - 7"); // GenPolynomial d = fac.parse("x^10 - 2 x^8 - 2 x^7 - 4 x^6 + 7 x^4 + 10 x^3 + 3 x^2 - 4 x - 2"); GenPolynomial a = fac.parse("x^5 - x^4 + 4 x^3 + x^2 - x + 5"); GenPolynomial d = fac.parse("x^4 - 2 x^3 + 5 x^2 - 4 x + 4"); Quotient q = new Quotient(qfac, a, d); eIntegratorCzi.irredLogPart = true; double startTime = System.currentTimeMillis(); QuotIntegral ret = eIntegratorCzi.integrate(q); // double endTime = System.currentTimeMillis(); System.out.println("Czichowski took " + ((endTime - startTime) / 1000) + " seconds"); System.out.println("Result: " + ret); boolean testAnswer = eIntegratorCzi.isIntegral(ret); System.out.println(testAnswer); } /** * Example for integrating a rational function using Bernoulli algorithm. */ public static void exampleBernoulli() { BigRational br = new BigRational(0); String[] vars = new String[] { "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(br, vars.length, new TermOrder(TermOrder.INVLEX), vars); QuotientRing qfac = new QuotientRing(fac); ElementaryIntegration eIntegratorBer = new ElementaryIntegrationBernoulli( br); GenPolynomial a = fac.parse("x^4 - 3 x^2 + 6"); GenPolynomial d = fac.parse("x^6 - 5 x^4 + 5 x^2 + 4"); // GenPolynomial a = fac.parse("36"); // GenPolynomial d = fac.parse("x^5 - 2 x^4 - 2 x^3 + 4 x^2 + x - 2"); // GenPolynomial a = fac.parse("x^5 - x^4 + 4 x^3 + x^2 - x + 5"); // GenPolynomial d = fac.parse("x^4 - 2 x^3 + 5 x^2 - 4 x + 4"); Quotient q = new Quotient(qfac, a, d); double startTime = System.currentTimeMillis(); edu.jas.integrate.QuotIntegral ret = eIntegratorBer.integrate(q); double endTime = System.currentTimeMillis(); System.out.println("Bernoulli took " + ((endTime - startTime) / 1000) + " seconds"); System.out.println("Result: " + ret); // boolean testAnswer = eIntegratorBer.isIntegral(ret); // System.out.println(testAnswer); } } java-algebra-system-2.7.200/src/edu/jas/integrate/Integral.java000066400000000000000000000110161445075545500242500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for a rational function integral, polynomial version. * integral(num/den) = pol + sum_rat( rat_i/rat_{i+1} ) + sum_log( a_i log ( d_i * ) ) * @author Heinz Kredel * @param coefficient type */ public class Integral> implements Serializable { /** * Original numerator polynomial with coefficients from C. */ public final GenPolynomial num; /** * Original denominator polynomial with coefficients from C. */ public final GenPolynomial den; /** * Integral of the polynomial part. */ public final GenPolynomial pol; /** * Integral of the rational part. */ public final List> rational; /** * Integral of the logarithmic part. */ public final List> logarithm; /** * Constructor. * @param n numerator GenPolynomial over C. * @param d denominator GenPolynomial over C. * @param p integral of polynomial part. n/d = */ public Integral(GenPolynomial n, GenPolynomial d, GenPolynomial p) { this(n, d, p, new ArrayList>()); } /** * Constructor. * @param n numerator GenPolynomial over C. * @param d denominator GenPolynomial over C. * @param p integral of polynomial part. * @param rat list of rational integrals. n/d = */ public Integral(GenPolynomial n, GenPolynomial d, GenPolynomial p, List> rat) { this(n, d, p, rat, new ArrayList>()); } /** * Constructor. * @param n numerator GenPolynomial over C. * @param d denominator GenPolynomial over C. * @param p integral of polynomial part. * @param rat list of rational integrals. * @param log list of logarithmic part. n/d = */ public Integral(GenPolynomial n, GenPolynomial d, GenPolynomial p, List> rat, List> log) { num = n; den = d; pol = p; rational = rat; logarithm = log; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("integral( (" + num.toString()); sb.append(") / ("); sb.append(den.toString() + ") )"); sb.append(" =\n"); if (!pol.isZERO()) { sb.append(pol.toString()); } boolean first = true; if (rational.size() != 0) { if (!pol.isZERO()) { sb.append(" + "); } for (int i = 0; i < rational.size(); i++) { if (first) { first = false; } else { sb.append(" + "); } sb.append("(" + rational.get(i++) + ")/("); sb.append(rational.get(i) + ")"); } } if (logarithm.size() != 0) { if (!pol.isZERO() || rational.size() != 0) { sb.append(" + "); } first = true; for (LogIntegral pf : logarithm) { if (first) { first = false; } else { sb.append(" + "); } sb.append(pf); } sb.append("\n"); } return sb.toString(); } /** * Hash code for Integral. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = num.hashCode(); h = h * 37 + den.hashCode(); h = h * 37 + pol.hashCode(); h = h * 37 + rational.hashCode(); h = h * 37 + logarithm.hashCode(); return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { Integral b = null; try { b = (Integral) B; } catch (ClassCastException ignored) { } if (b == null) { return false; } return num.equals(b.num) && den.equals(b.den) && pol.equals(b.pol) && rational.equals(b.rational) && logarithm.equals(b.logarithm); } } java-algebra-system-2.7.200/src/edu/jas/integrate/LogIntegral.java000066400000000000000000000151641445075545500247220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.io.Serializable; import java.util.List; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for the logarithmic part of a rational function integral. num/den = * sum( a_i ( der(d_i) / d_i ) ) integrate(num/den) = sum( a_i log ( d_i ) ) * @author Heinz Kredel * @param coefficient type */ public class LogIntegral> implements Serializable { /** * Original numerator polynomial with coefficients from C and deg(num) < * deg(den). */ public final GenPolynomial num; /** * Original (irreducible) denominator polynomial with coefficients from C. */ public final GenPolynomial den; /** * List of numbers from C. */ public final List cfactors; /** * List of linear factors of the denominator with coefficients from C. */ public final List> cdenom; /** * List of algebraic numbers of an algebraic field extension over C. */ public final List> afactors; /** * List of factors of the denominator with coefficients from an * AlgebraicNumberRing<C>. */ public final List>> adenom; /** * Constructor. * @param n numerator GenPolynomial over C. * @param d irreducible denominator GenPolynomial over C. * @param cf list of elements a_i. * @param cd list of linear factors d_i of d. * @param af list of algebraic elements a_i. * @param ad list of irreducible factors d_i of d with algebraic * coefficients. n/d = sum( a_i ( der(d_i) / d_i ) ) */ public LogIntegral(GenPolynomial n, GenPolynomial d, List cf, List> cd, List> af, List>> ad) { num = n; den = d; cfactors = cf; cdenom = cd; afactors = af; adenom = ad; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); // sb.append("(" + num.toString() + ")"); // sb.append(" / "); // sb.append("(" + den.toString() + ")"); // sb.append(" =\n"); boolean first = true; for (int i = 0; i < cfactors.size(); i++) { C cp = cfactors.get(i); if (first) { first = false; } else { sb.append(" + "); } sb.append("(" + cp.toString() + ")"); GenPolynomial p = cdenom.get(i); sb.append(" log( " + p.toString() + ")"); } if (!first && afactors.size() > 0) { sb.append(" + "); } first = true; for (int i = 0; i < afactors.size(); i++) { if (first) { first = false; } else { sb.append(" + "); } AlgebraicNumber ap = afactors.get(i); AlgebraicNumberRing ar = ap.factory(); //sb.append(" ## over " + ap.factory() + "\n"); GenPolynomial> p = adenom.get(i); if (p.degree(0) < ar.modul.degree(0) && ar.modul.degree(0) > 2) { sb.append("sum_(" + ar.getGenerator() + " in "); sb.append("rootOf(" + ar.modul + ") ) "); } else { //sb.append("sum_("+ar+") "); } sb.append("(" + ap.toString() + ")"); sb.append(" log( " + p.toString() + ")"); } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); sb.append(num.toScript()); sb.append(" / "); sb.append(den.toScript()); sb.append(" = "); boolean first = true; for (C cp : cfactors) { if (first) { first = false; } else { sb.append(", "); } sb.append(cp.toScript()); } if (!first) { sb.append(" linear denominators: "); } first = true; for (GenPolynomial cp : cdenom) { if (first) { first = false; } else { sb.append(", "); } sb.append(cp.toScript()); } if (!first) { sb.append(", "); } first = true; for (AlgebraicNumber ap : afactors) { if (first) { first = false; } else { //sb.append(", "); } sb.append(ap.toScript()); sb.append(" ## over " + ap.toScriptFactory() + "\n"); } sb.append(" denominators: "); first = true; for (GenPolynomial> ap : adenom) { if (first) { first = false; } else { sb.append(", "); } sb.append(ap.toScript()); } return sb.toString(); } /** * Hash code for this Factors. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = num.hashCode(); h = h * 37 + den.hashCode(); h = h * 37 + cfactors.hashCode(); h = h * 37 + cdenom.hashCode(); h = h * 37 + afactors.hashCode(); h = h * 37 + adenom.hashCode(); return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof LogIntegral)) { return false; } LogIntegral a = (LogIntegral) B; boolean t = num.equals(a.num) && den.equals(a.den); if (!t) { return t; } t = cfactors.equals(a.cfactors); if (!t) { return t; } t = cdenom.equals(a.cdenom); if (!t) { return t; } t = afactors.equals(a.afactors); if (!t) { return t; } t = adenom.equals(a.adenom); return t; } } java-algebra-system-2.7.200/src/edu/jas/integrate/QuotIntegral.java000066400000000000000000000103471445075545500251270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Container for a rational function integral, quotient version . * integral(num/den) = pol + sum_rat( rat_i/rat_{i+1} ) + sum_log( a_i log ( d_i * ) ) * @author Heinz Kredel * @param coefficient type */ public class QuotIntegral> implements Serializable { /** * Original rational function with coefficients from C. */ public final Quotient quot; /** * Integral of the polynomial and rational part. */ public final List> rational; /** * Integral of the logarithmic part. */ public final List> logarithm; /** * Constructor. * @param ri integral. */ public QuotIntegral(Integral ri) { this(new QuotientRing(ri.den.ring), ri); } /** * Constructor. * @param r rational function QuotientRing over C. * @param ri integral. */ public QuotIntegral(QuotientRing r, Integral ri) { this(new Quotient(r, ri.num, ri.den), ri.pol, ri.rational, ri.logarithm); } /** * Constructor. * @param r rational function Quotient over C. * @param p integral of polynomial part. * @param rat list of rational integrals. */ public QuotIntegral(Quotient r, GenPolynomial p, List> rat) { this(r, p, rat, new ArrayList>()); } /** * Constructor. * @param r rational function Quotient over C. * @param p integral of polynomial part. * @param rat list of rational integrals. * @param log list of logarithmic part. */ public QuotIntegral(Quotient r, GenPolynomial p, List> rat, List> log) { quot = r; QuotientRing qr = r.ring; rational = new ArrayList>(); if (!p.isZERO()) { rational.add(new Quotient(qr, p)); } for (int i = 0; i < rat.size(); i++) { GenPolynomial rn = rat.get(i++); GenPolynomial rd = rat.get(i); rational.add(new Quotient(qr, rn, rd)); } logarithm = log; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("integral( " + quot.toString() + " )"); sb.append(" =\n"); boolean first = true; if (rational.size() != 0) { for (int i = 0; i < rational.size(); i++) { if (first) { first = false; } else { sb.append(" + "); } sb.append("(" + rational.get(i) + ")"); } } if (logarithm.size() != 0) { if (rational.size() != 0) { sb.append(" + "); } first = true; for (LogIntegral pf : logarithm) { if (first) { first = false; } else { sb.append(" + "); } sb.append(pf); } sb.append("\n"); } return sb.toString(); } /** * Hash code for QuotIntegral. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = quot.hashCode(); h = h * 37 + rational.hashCode(); h = h * 37 + logarithm.hashCode(); return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { QuotIntegral b = null; try { b = (QuotIntegral) B; } catch (ClassCastException ignored) { } if (b == null) { return false; } return quot.equals(b.quot) && rational.equals(b.rational) && logarithm.equals(b.logarithm); } } java-algebra-system-2.7.200/src/edu/jas/integrate/package.html000066400000000000000000000014631445075545500241260ustar00rootroot00000000000000 Elementary Integration package

Elementary Integration package.

This package contains classes for elementary integration of (univariate) polynomials and rational functions.

The implementation follows Bronstein Symbolic Integration I - Transcendental Functions.


Heinz Kredel

Last modified: Fri Nov 27 22:23:52 CET 2009

$Id$

java-algebra-system-2.7.200/src/edu/jas/kern/000077500000000000000000000000001445075545500206165ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/kern/ComputerThreads.java000066400000000000000000000121301445075545500245670ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * ComputerThreads, provides global thread / executor service. *

* Usage: To obtain a reference to the thread pool use * ComputerThreads.getPool(). Once a pool has been created it must * be shutdown with ComputerThreads.terminate() to exit JAS. *

* @author Heinz Kredel */ public class ComputerThreads { private static final Logger logger = LogManager.getLogger(ComputerThreads.class); // private static final boolean debug = logger.isInfoEnabled(); /** * Flag for thread usage. Note: Only introduced because Google app * engine does not support threads. * @see edu.jas.ufd.GCDFactory#getProxy(edu.jas.structure.RingFactory) */ public static boolean NO_THREADS = false; /** * Number of processors. */ public static final int N_CPUS = Runtime.getRuntime().availableProcessors(); /* * Core number of threads. * N_CPUS x 1.5, x 2, x 2.5, min 3, ?. */ public static final int N_THREADS = (N_CPUS < 3 ? 3 : N_CPUS + N_CPUS / 2); //public static final int N_THREADS = ( N_CPUS < 3 ? 5 : 3*N_CPUS ); /** * Timeout for timed execution. * @see edu.jas.fd.SGCDParallelProxy */ static long timeout = 10L; //-1L; /** * TimeUnit for timed execution. * @see edu.jas.fd.SGCDParallelProxy */ static TimeUnit timeunit = TimeUnit.SECONDS; /* * Saturation policy. */ //public static final RejectedExecutionHandler REH = new ThreadPoolExecutor.CallerRunsPolicy(); //public static final RejectedExecutionHandler REH = new ThreadPoolExecutor.AbortPolicy(); /** * ExecutorService thread pool. */ //static ThreadPoolExecutor pool = null; static ExecutorService pool = null; /** * No public constructor. */ private ComputerThreads() { } /** * Test if a pool is running. * @return true if a thread pool has been started or is running, else false. */ public static synchronized boolean isRunning() { if (pool == null) { return false; } if (pool.isTerminated() || pool.isShutdown()) { return false; } return true; } /** * Get the thread pool. * @return pool ExecutorService. */ public static synchronized ExecutorService getPool() { if (pool == null) { pool = Executors.newCachedThreadPool(); } //System.out.println("pool_init = " + pool); return pool; //return Executors.unconfigurableExecutorService(pool); /* not useful, is not run from jython Runtime.getRuntime().addShutdownHook( ); */ } /** * Stop execution. */ public static synchronized void terminate() { if (pool == null) { return; } if (pool instanceof ThreadPoolExecutor) { ThreadPoolExecutor tpe = (ThreadPoolExecutor) pool; //logger.info("task queue size {}", Q_CAPACITY); logger.info("number of CPUs {}", N_CPUS); logger.info("core number of threads {}", N_THREADS); logger.info("current number of threads {}", tpe.getPoolSize()); logger.info("maximal number of threads {}", tpe.getLargestPoolSize()); BlockingQueue workpile = tpe.getQueue(); if (workpile != null) { logger.info("queued tasks {}", workpile.size()); } List r = tpe.shutdownNow(); if (r.size() != 0) { logger.info("unfinished tasks {}", r.size()); } logger.info("number of scheduled tasks {}", tpe.getTaskCount()); logger.info("number of completed tasks {}", tpe.getCompletedTaskCount()); } pool = null; //workpile = null; } /** * Set no thread usage. */ public static synchronized void setNoThreads() { NO_THREADS = true; } /** * Set thread usage. */ public static synchronized void setThreads() { NO_THREADS = false; } /** * Set timeout. * @param t time value to set */ public static synchronized void setTimeout(long t) { timeout = t; } /** * Get timeout. * @return timeout value */ public static synchronized long getTimeout() { return timeout; } /** * Set TimeUnit. * @param t TimeUnit value to set */ public static synchronized void setTimeUnit(TimeUnit t) { timeunit = t; } /** * Get TimeUnit. * @return timeunit value */ public static synchronized TimeUnit getTimeUnit() { return timeunit; } } java-algebra-system-2.7.200/src/edu/jas/kern/JASConfig.java000066400000000000000000000015671445075545500232350ustar00rootroot00000000000000package edu.jas.kern; import edu.jas.ufd.FactorAbstract; /** * Configuration options to truncate long running Kronecker factorization. * @author Axel Kramer */ public class JASConfig { /** * {@linkFactorAbstract#factorsSquarefreeKronecker(edu.jas.poly.GenPolynomial)} * will throw an {@link ArithmeticException}, if this parameter is * greater than 0 and the Kronecker substitution * degree is greater than this value. */ public static int MAX_DEGREE_KRONECKER_FACTORIZATION = -1; /** * {@link FactorAbstract#factorsSquarefreeKronecker(edu.jas.poly.GenPolynomial)} * will throw an {@link ArithmeticException}, if this parameter is greater * than 0 and the Kronecker iteration counter is greater than * this value. */ public static int MAX_ITERATIONS_KRONECKER_FACTORIZATION = -1; } java-algebra-system-2.7.200/src/edu/jas/kern/LocalTimeStatus.java000066400000000000000000000075361445075545500245510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.concurrent.Callable; /** * Run-time status, defines local status and handling for local run time limits. * @see edu.jas.kern.TimeStatus * @author Heinz Kredel */ public class LocalTimeStatus { /** * Local status flag. */ private boolean allowTime = false; /** * Local run-time limit in milliseconds. */ private long limitTime = Long.MAX_VALUE; /** * Local run-time limit in milliseconds. */ private long startTime = System.currentTimeMillis(); /** * Local call back method. true means continue, false means throw exception. */ private Callable callBack = null; /** * Public constructor. */ public LocalTimeStatus() { this(false, Long.MAX_VALUE, false); } /** * Public constructor. * @param a true for active, false for inactive * @param d time limit before exception * @param r true for continue, false for exception */ public LocalTimeStatus(boolean a, long d, boolean r) { allowTime = a; limitTime = d; callBack = new LocalTimeStatus.TSCall(r); startTime = System.currentTimeMillis(); } /** * To String. * @return String representation of this. */ @Override public String toString() { StringBuffer sb = new StringBuffer("LocalTimeStatus("); sb.append("" + allowTime); sb.append(", " + limitTime); try { sb.append(", " + (callBack == null ? "null" : callBack.call())); } catch (Exception e) { } sb.append(", " + startTime); sb.append(")"); return sb.toString(); } /** * isActive. * @return true, if run-time interruption is active, else false. */ public synchronized boolean isActive() { return allowTime; } /** * setAllow, set run-time interruption to allowed status. */ public synchronized void setActive() { allowTime = true; } /** * setNotActive, set run-time interruption to not active status. */ public synchronized void setNotActive() { allowTime = false; } /** * setLimit, set run-time limit in milliseconds. */ public synchronized void setLimit(long t) { limitTime = t; } /** * Restart timer, set run-time to current time. */ public synchronized void restart() { startTime = System.currentTimeMillis(); } /** * set call back, set the Callabe object. */ public synchronized void setCallBack(Callable cb) { callBack = cb; } /** * Check for exceeded time, test if time has exceeded and throw an exception * if so. * @param msg the message to be send with the exception. */ public synchronized void checkTime(String msg) { if (!allowTime) { return; } if (limitTime == Long.MAX_VALUE) { return; } long tt = (System.currentTimeMillis() - startTime - limitTime); //System.out.println("tt = " + (limitTime+tt)); if (tt <= 0L) { return; } if (callBack != null) { try { boolean t = callBack.call(); if (t) { return; } } catch (Exception e) { } } if (msg != null) { msg = msg + ", "; } throw new TimeExceededException(msg + "elapsed time >= " + (limitTime + tt) + " ms"); } /** * A default call back class. */ public static class TSCall implements Callable { boolean flag = true; public TSCall(boolean b) { flag = b; } public Boolean call() { return flag; } } } java-algebra-system-2.7.200/src/edu/jas/kern/PreemptStatus.java000066400000000000000000000016401445075545500243020ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; /** * PreemptStatus, defines global status for preemptive interruption handling. * @author Heinz Kredel */ public class PreemptStatus { /** * Global status flag. */ private static volatile boolean allowPreempt = true; /** * No public constructor. */ protected PreemptStatus() { } /** * isAllowed. * @return true, preemtive interruption is allowed, else false. */ public static boolean isAllowed() { //System.out.println("allowPreempt: " + allowPreempt); return allowPreempt; } /** * setAllow, set preemtive interruption to allowed status. */ public static void setAllow() { allowPreempt = true; } /** * setNotAllow, set preemtive interruption to not allowed status. */ public static void setNotAllow() { allowPreempt = false; } } java-algebra-system-2.7.200/src/edu/jas/kern/PreemptingException.java000066400000000000000000000010611445075545500254500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; /** * Preempting Exception class. Runtime Exception to be thrown when a thread is * interrupted. * @author Heinz Kredel */ public class PreemptingException extends RuntimeException { public PreemptingException() { super("PreemptingException"); } public PreemptingException(String c) { super(c); } public PreemptingException(String c, Throwable t) { super(c, t); } public PreemptingException(Throwable t) { super("PreemptingException", t); } } java-algebra-system-2.7.200/src/edu/jas/kern/PrettyPrint.java000066400000000000000000000012611445075545500237650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; /** * PrettyPrint, defines global pretty print status. * @author Heinz Kredel */ public class PrettyPrint { private static volatile boolean doPretty = true; protected PrettyPrint() { } /** * isTrue. * @return true, if to use pretty printing, else false. */ public static boolean isTrue() { return doPretty; } /** * setPretty. Set use pretty printing to true. */ public static void setPretty() { doPretty = true; } /** * setInternal. Set use pretty printing to false. */ public static void setInternal() { doPretty = false; } } java-algebra-system-2.7.200/src/edu/jas/kern/Scripting.java000066400000000000000000000034431445075545500234270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; /** * Scripting, defines script language for output in toScript() method. * @author Heinz Kredel */ public class Scripting { public static enum Lang { Python, Ruby }; private static Lang script = Lang.Python; public static enum CAS { JAS, Math, Sage, Singular }; private static CAS cas = CAS.JAS; private static int precision = -1; // == fraction output protected Scripting() { } /** * Get scripting language which is in effect. * @return language which is to be used for toScript(). */ public static Lang getLang() { return script; } /** * Set scripting language. * @param s language which is to be used for toScript() * @return old language setting. */ public static Lang setLang(Lang s) { Lang o = script; script = s; return o; } /** * Get CAS for Order which is in effect. * @return CAS which is to be used for toScript(). */ public static CAS getCAS() { return cas; } /** * Set CAS for order. * @param s CAS which is to be used for toScript() * @return old CAS setting. */ public static CAS setCAS(CAS s) { CAS o = cas; cas = s; return o; } /** * Get decimal approximation precision for scripting. * @return number of decimals after '.'. */ public static int getPrecision() { return precision; } /** * Set decimal approximation precision for scripting. * @param p number of decimals after '.' * @return old number of decimals after '.'. */ public static int setPrecision(int p) { int o = precision; precision = p; return o; } } java-algebra-system-2.7.200/src/edu/jas/kern/StringUtil.java000066400000000000000000000076471445075545500236030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.IOException; import java.io.Reader; import java.io.StringWriter; /** * Static String and Reader methods. * @author Heinz Kredel */ public class StringUtil { /** * Parse white space delimited String from Reader. * @param r Reader. * @return next non white space String from r. */ public static String nextString(Reader r) { StringWriter sw = new StringWriter(); try { char buffer; int i; // skip white space while ((i = r.read()) > -1) { buffer = (char) i; if (!Character.isWhitespace(buffer)) { sw.write(buffer); break; } } // read non white space, ignore new lines ? while ((i = r.read()) > -1) { buffer = (char) i; if (Character.isWhitespace(buffer)) { break; } sw.write(buffer); } } catch (IOException e) { e.printStackTrace(); } return sw.toString(); } /** * Parse String with given delimiter from Reader. * @param c delimiter. * @param r Reader. * @return next String up to c from r. */ public static String nextString(Reader r, char c) { StringWriter sw = new StringWriter(); try { char buffer; int i; // read chars != c, ignore new lines ? while ((i = r.read()) > -1) { buffer = (char) i; if (buffer == c) { break; } sw.write(buffer); } } catch (IOException e) { e.printStackTrace(); } return sw.toString().trim(); } /** * Parse paired String with given delimiters from Reader. * @param b opposite delimiter. * @param c delimiter, != b. * @param r Reader. * @return next nested matching String from b up to c from r. */ public static String nextPairedString(Reader r, char b, char c) { if (b == c) { throw new IllegalArgumentException("b == c, not allowed " + b); } StringWriter sw = new StringWriter(); try { int level = 0; boolean first = true; char buffer; int i; // read chars != c, ignore new lines ? while ((i = r.read()) > -1) { buffer = (char) i; if (buffer == b) { level++; if (first) { // skip first opening 'brace' first = false; continue; } } if (buffer == c) { level--; if (level <= 0) { break; // skip last closing 'brace' } } if (level > 0) { sw.write(buffer); } } } catch (IOException e) { e.printStackTrace(); } return sw.toString().trim(); } /** * Select stack trace parts. * @param expr regular matching expression. * @return stack trace with elements matching expr. */ public static String selectStackTrace(String expr) { StackTraceElement[] stack = Thread.currentThread().getStackTrace(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < stack.length; i++) { String s = stack[i].toString(); if (s.indexOf("selectStackTrace") >= 0) { continue; } if (s.matches(expr)) { sb.append("\nstack[" + i + "] = "); sb.append(s); } //System.out.println("stack["+i+"] = " + s); } return sb.toString(); } } java-algebra-system-2.7.200/src/edu/jas/kern/TimeExceededException.java000066400000000000000000000011241445075545500256630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; /** * Time exceeded exception class. Runtime Exception to be thrown when the * run-time has exceeded a certain limit. * @author Heinz Kredel */ public class TimeExceededException extends RuntimeException { public TimeExceededException() { super("TimeExceededException"); } public TimeExceededException(String c) { super(c); } public TimeExceededException(String c, Throwable t) { super(c, t); } public TimeExceededException(Throwable t) { super("TimeExceededException", t); } } java-algebra-system-2.7.200/src/edu/jas/kern/TimeStatus.java000066400000000000000000000054621445075545500235720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.concurrent.Callable; /** * Run-time status, defines global status and handling for run time limits. * @author Heinz Kredel */ public class TimeStatus { /** * Global status flag. */ private static boolean allowTime = false; /** * Global run-time limit in milliseconds. */ private static long limitTime = Long.MAX_VALUE; /** * Global run-time limit in milliseconds. */ private static long startTime = System.currentTimeMillis(); /** * Call back method. true means continue, false means throw exception. */ private static Callable callBack = null; /** * No public constructor. */ protected TimeStatus() { } /** * isActive. * @return true, if run-time interruption is active, else false. */ public static boolean isActive() { return allowTime; } /** * setAllow, set run-time interruption to allowed status. */ public static void setActive() { allowTime = true; } /** * setNotActive, set run-time interruption to not active status. */ public static void setNotActive() { allowTime = false; } /** * setLimit, set run-time limit in milliseconds. */ public static void setLimit(long t) { limitTime = t; } /** * Restart timer, set run-time to current time. */ public static void restart() { startTime = System.currentTimeMillis(); } /** * set call back, set the Callabe object. */ public static void setCallBack(Callable cb) { callBack = cb; } /** * Check for exceeded time, test if time has exceeded and throw an exception * if so. * @param msg the message to be send with the exception. */ public static void checkTime(String msg) { if (!allowTime) { return; } if (limitTime == Long.MAX_VALUE) { return; } long tt = (System.currentTimeMillis() - startTime - limitTime); //System.out.println("tt = " + tt); if (tt <= 0L) { return; } if (callBack != null) { try { boolean t = callBack.call(); if (t) { return; } } catch (Exception e) { } } if (msg != null) { msg = msg + ", "; } throw new TimeExceededException(msg + "elapsed time >= " + limitTime + " ms"); } public static class TSCall implements Callable { boolean flag = true; public TSCall(boolean b) { flag = b; } public Boolean call() { return flag; } } } java-algebra-system-2.7.200/src/edu/jas/kern/package.html000066400000000000000000000016031445075545500230770ustar00rootroot00000000000000 JAS run-time kernel package

JAS run-time kernel package.

This package contains classes used in global execution of all JAS packages. E.g. PrettyPrint is used to control the print (i.e. the toString()) of many classes. PreemptingException and PreemptStatus are used to preemptively cancel long running computations.


Heinz Kredel

Last modified: Wed Jul 11 19:06:14 CEST 2007

$Id$

java-algebra-system-2.7.200/src/edu/jas/poly/000077500000000000000000000000001445075545500206425ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/poly/AlgebraicNotInvertibleException.java000066400000000000000000000053031445075545500277430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.structure.NotInvertibleException; /** * Algebraic number NotInvertibleException class. Runtime Exception to be thrown * for not invertible algebraic numbers. Container for the non-trivial factors * found by the inversion algorithm. Note: cannot be generic because of * Throwable. * @author Heinz Kredel */ public class AlgebraicNotInvertibleException extends NotInvertibleException { public final GenPolynomial f; // = f1 * f2 public final GenPolynomial f1; public final GenPolynomial f2; public AlgebraicNotInvertibleException() { this(null, null, null); } public AlgebraicNotInvertibleException(String c) { this(c, null, null, null); } public AlgebraicNotInvertibleException(String c, Throwable t) { this(c, t, null, null, null); } public AlgebraicNotInvertibleException(Throwable t) { this(t, null, null, null); } /** * Constructor. * @param f polynomial with f = f1 * f2. * @param f1 polynomial. * @param f2 polynomial. */ public AlgebraicNotInvertibleException(GenPolynomial f, GenPolynomial f1, GenPolynomial f2) { super("AlgebraicNotInvertibleException"); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f polynomial with f = f1 * f2. * @param f1 polynomial. * @param f2 polynomial. */ public AlgebraicNotInvertibleException(String c, GenPolynomial f, GenPolynomial f1, GenPolynomial f2) { super(c); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f polynomial with f = f1 * f2. * @param f1 polynomial. * @param f2 polynomial. */ public AlgebraicNotInvertibleException(String c, Throwable t, GenPolynomial f, GenPolynomial f1, GenPolynomial f2) { super(c, t); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Constructor. * @param f polynomial with f = f1 * f2. * @param f1 polynomial. * @param f2 polynomial. */ public AlgebraicNotInvertibleException(Throwable t, GenPolynomial f, GenPolynomial f1, GenPolynomial f2) { super("AlgebraicNotInvertibleException", t); this.f = f; this.f1 = f1; this.f2 = f2; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String s = super.toString(); if (f != null || f1 != null || f2 != null) { s += ", f = " + f + ", f1 = " + f1 + ", f2 = " + f2; } return s; } } java-algebra-system-2.7.200/src/edu/jas/poly/AlgebraicNumber.java000066400000000000000000000314341445075545500245340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.kern.PrettyPrint; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; /** * Algebraic number class. Based on GenPolynomial with RingElem interface. * Objects of this class are immutable. * @author Heinz Kredel */ public class AlgebraicNumber> implements GcdRingElem> { /** * Ring part of the data structure. */ public final AlgebraicNumberRing ring; /** * Value part of the element data structure. */ public final GenPolynomial val; /** * Flag to remember if this algebraic number is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a AlgebraicNumber object from AlgebraicNumberRing * modul and a GenPolynomial value. * @param r ring AlgebraicNumberRing. * @param a value GenPolynomial. */ public AlgebraicNumber(AlgebraicNumberRing r, GenPolynomial a) { ring = r; // assert r != 0 val = a.remainder(ring.modul); //.monic() no go if (val.isZERO()) { isunit = 0; } if (ring.isField()) { isunit = 1; } } /** * The constructor creates a AlgebraicNumber object from a GenPolynomial * object module. * @param r ring AlgebraicNumberRing. */ public AlgebraicNumber(AlgebraicNumberRing r) { this(r, r.ring.getZERO()); } /** * Get the value part. * @return val. */ public GenPolynomial getVal() { return val; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public AlgebraicNumberRing factory() { return ring; } /** * Copy this. * @see edu.jas.structure.Element#copy() */ @Override public AlgebraicNumber copy() { return new AlgebraicNumber(ring, val); } /** * Is AlgebraicNumber zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.equals(ring.ring.getZERO()); } /** * Is AlgebraicNumber one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.equals(ring.ring.getONE()); } /** * Is AlgebraicNumber unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known if (val.isZERO()) { isunit = 0; return false; } if (ring.isField()) { isunit = 1; return true; } boolean u = val.gcd(ring.modul).isUnit(); if (u) { isunit = 1; } else { isunit = 0; } return u; } /** * Is AlgebraicNumber a root of unity. * @return true if |this**i| == 1, for some 0 < i ≤ deg(modul), else * false. */ public boolean isRootOfUnity() { long d = ring.modul.degree(); AlgebraicNumber t = ring.getONE(); for (long i = 1; i <= d; i++) { t = t.multiply(this); if (t.abs().isONE()) { //System.out.println("isRootOfUnity for i = " + i); return true; } } return false; } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return val.toString(ring.ring.vars); } return "AlgebraicNumber[ " + val.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return val.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * AlgebraicNumber comparison. * @param b AlgebraicNumber. * @return sign(this-b). */ @Override public int compareTo(AlgebraicNumber b) { int s = 0; if (ring.modul != b.ring.modul) { // avoid compareTo if possible s = ring.modul.compareTo(b.ring.modul); } if (s != 0) { return s; } return val.compareTo(b.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof AlgebraicNumber)) { return false; } AlgebraicNumber a = (AlgebraicNumber) b; if (!ring.equals(a.ring)) { return false; } return (0 == compareTo(a)); } /** * Hash code for this AlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * val.hashCode() + ring.hashCode(); } /** * AlgebraicNumber absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public AlgebraicNumber abs() { return new AlgebraicNumber(ring, val.abs()); } /** * AlgebraicNumber summation. * @param S AlgebraicNumber. * @return this+S. */ public AlgebraicNumber sum(AlgebraicNumber S) { return new AlgebraicNumber(ring, val.sum(S.val)); } /** * AlgebraicNumber summation. * @param c coefficient. * @return this+c. */ public AlgebraicNumber sum(GenPolynomial c) { return new AlgebraicNumber(ring, val.sum(c)); } /** * AlgebraicNumber summation. * @param c polynomial. * @return this+c. */ public AlgebraicNumber sum(C c) { return new AlgebraicNumber(ring, val.sum(c)); } /** * AlgebraicNumber negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public AlgebraicNumber negate() { return new AlgebraicNumber(ring, val.negate()); } /** * AlgebraicNumber signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * AlgebraicNumber subtraction. * @param S AlgebraicNumber. * @return this-S. */ public AlgebraicNumber subtract(AlgebraicNumber S) { return new AlgebraicNumber(ring, val.subtract(S.val)); } /** * AlgebraicNumber division. * @param S AlgebraicNumber. * @return this/S. */ public AlgebraicNumber divide(AlgebraicNumber S) { return multiply(S.inverse()); } /** * AlgebraicNumber inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S = 1/this if defined. */ public AlgebraicNumber inverse() { try { return new AlgebraicNumber(ring, val.modInverse(ring.modul)); } catch (AlgebraicNotInvertibleException e) { //System.out.println(e); throw e; } catch (NotInvertibleException e) { throw new AlgebraicNotInvertibleException(e + ", val = " + val + ", modul = " + ring.modul + ", gcd = " + val.gcd(ring.modul), e); } } /** * AlgebraicNumber remainder. * @param S AlgebraicNumber. * @return this - (this/S)*S. */ public AlgebraicNumber remainder(AlgebraicNumber S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } if (S.isONE()) { return ring.getZERO(); } if (S.isUnit()) { return ring.getZERO(); } GenPolynomial x = val.remainder(S.val); return new AlgebraicNumber(ring, x); } /** * Quotient and remainder by division of this by S. * @param S a AlgebraicNumber * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public AlgebraicNumber[] quotientRemainder(AlgebraicNumber S) { return new AlgebraicNumber[] { divide(S), remainder(S) }; } /** * AlgebraicNumber multiplication. * @param S AlgebraicNumber. * @return this*S. */ public AlgebraicNumber multiply(AlgebraicNumber S) { GenPolynomial x = val.multiply(S.val); return new AlgebraicNumber(ring, x); } /** * AlgebraicNumber multiplication. * @param c coefficient. * @return this*c. */ public AlgebraicNumber multiply(C c) { GenPolynomial x = val.multiply(c); return new AlgebraicNumber(ring, x); } /** * AlgebraicNumber multiplication. * @param c polynomial. * @return this*c. */ public AlgebraicNumber multiply(GenPolynomial c) { GenPolynomial x = val.multiply(c); return new AlgebraicNumber(ring, x); } /** * AlgebraicNumber monic. * @return this with monic value part. */ public AlgebraicNumber monic() { return new AlgebraicNumber(ring, val.monic()); } /** * AlgebraicNumber greatest common divisor. * @param S AlgebraicNumber. * @return gcd(this,S). */ public AlgebraicNumber gcd(AlgebraicNumber S) { if (S.isZERO()) { return this; } if (isZERO()) { return S; } if (isUnit() || S.isUnit()) { return ring.getONE(); } return new AlgebraicNumber(ring, val.gcd(S.val)); } /** * AlgebraicNumber extended greatest common divisor. * @param S AlgebraicNumber. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public AlgebraicNumber[] egcd(AlgebraicNumber S) { AlgebraicNumber[] ret = new AlgebraicNumber[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (isZERO()) { ret[0] = S; return ret; } if (this.isUnit() || S.isUnit()) { ret[0] = ring.getONE(); if (this.isUnit() && S.isUnit()) { AlgebraicNumber half = ring.fromInteger(2).inverse(); ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } if (this.isUnit()) { // oder inverse(S-1)? ret[1] = this.inverse(); ret[2] = ring.getZERO(); return ret; } // if ( S.isUnit() ) { // oder inverse(this-1)? ret[1] = ring.getZERO(); ret[2] = S.inverse(); return ret; //} } //System.out.println("this = " + this + ", S = " + S); GenPolynomial[] qr; GenPolynomial q = this.val; GenPolynomial r = S.val; GenPolynomial c1 = ring.ring.getONE(); GenPolynomial d1 = ring.ring.getZERO(); GenPolynomial c2 = ring.ring.getZERO(); GenPolynomial d2 = ring.ring.getONE(); GenPolynomial x1; GenPolynomial x2; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } //System.out.println("q = " + q + "\n c1 = " + c1 + "\n c2 = " + c2); ret[0] = new AlgebraicNumber(ring, q); ret[1] = new AlgebraicNumber(ring, c1); ret[2] = new AlgebraicNumber(ring, c2); return ret; } } java-algebra-system-2.7.200/src/edu/jas/poly/AlgebraicNumberRing.java000066400000000000000000000422621445075545500253550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.util.CartesianProduct; import edu.jas.util.CartesianProductInfinite; /** * Algebraic number factory. Based on GenPolynomial factory with RingElem * interface. Objects of this class are immutable. * @author Heinz Kredel */ public class AlgebraicNumberRing> implements RingFactory>, Iterable> { /** * Ring part of the factory data structure. */ public final GenPolynomialRing ring; /** * Module part of the factory data structure. */ public final GenPolynomial modul; /** * Indicator if this ring is a field */ protected int isField = -1; // initially unknown private static final Logger logger = LogManager.getLogger(AlgebraicNumberRing.class); // private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a AlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial. */ public AlgebraicNumberRing(GenPolynomial m) { ring = m.ring; modul = m; // assert m != 0 if (ring.nvar > 1) { throw new IllegalArgumentException("only univariate polynomials allowed"); } } /** * The constructor creates a AlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial. * @param isField indicator if m is prime. */ public AlgebraicNumberRing(GenPolynomial m, boolean isField) { ring = m.ring; modul = m; // assert m != 0 this.isField = (isField ? 1 : 0); if (ring.nvar > 1) { throw new IllegalArgumentException("only univariate polynomials allowed"); } } /** * Get the module part. * @return modul. */ public GenPolynomial getModul() { return modul; } /** * Copy AlgebraicNumber element c. * @param c algebraic number to copy. * @return a copy of c. */ public AlgebraicNumber copy(AlgebraicNumber c) { return new AlgebraicNumber(this, c.val); } /** * Get the zero element. * @return 0 as AlgebraicNumber. */ public AlgebraicNumber getZERO() { return new AlgebraicNumber(this, ring.getZERO()); } /** * Get the one element. * @return 1 as AlgebraicNumber. */ public AlgebraicNumber getONE() { return new AlgebraicNumber(this, ring.getONE()); } /** * Get the generating element. * @return alpha as AlgebraicNumber. */ public AlgebraicNumber getGenerator() { return new AlgebraicNumber(this, ring.univariate(0)); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> gc = ring.generators(); List> gens = new ArrayList>(gc.size()); for (GenPolynomial g : gc) { gens.add(new AlgebraicNumber(this, g)); } return gens; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.coFac.isFinite(); } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return true if modul is prime, else false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (!ring.coFac.isField()) { isField = 0; return false; } return false; } /** * Set field property of this ring. * @param field true, if this ring is determined to be a field, false, if it * is determined that it is not a field. */ public void setField(boolean field) { if (isField > 0 && field) { return; } if (isField == 0 && !field) { return; } if (field) { isField = 1; } else { isField = 0; } return; } /** * Get the internal field indicator. * @return internal field indicator. */ public int getField() { return isField; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get an AlgebraicNumber element from a BigInteger value. * If a = a_k p^k + ... + a_0 p^0 then b = a_k x^k + ... + a_0 x^0, * where p = characteristic( this ). * @param a BigInteger. * @return b an AlgebraicNumber. */ public AlgebraicNumber fillFromInteger(java.math.BigInteger a) { if (characteristic().signum() == 0) { return new AlgebraicNumber(this, ring.fromInteger(a)); } java.math.BigInteger p = characteristic(); java.math.BigInteger b = a; GenPolynomial v = ring.getZERO(); GenPolynomial x = ring.univariate(0, 1L); GenPolynomial t = ring.getONE(); do { java.math.BigInteger[] qr = b.divideAndRemainder(p); java.math.BigInteger q = qr[0]; java.math.BigInteger r = qr[1]; //System.out.println("q = " + q + ", r = " +r); GenPolynomial rp = ring.fromInteger(r); v = v.sum(t.multiply(rp)); t = t.multiply(x); b = q; } while (!b.equals(java.math.BigInteger.ZERO)); AlgebraicNumber an = new AlgebraicNumber(this, v); logger.info("fill({}) = {}, mod: {}", a, v, an); //RuntimeException e = new RuntimeException("hihihi"); //e.printStackTrace(); return an; } /** * Get a AlgebraicNumber element from a long value. * @param a long. * @return a AlgebraicNumber. */ public AlgebraicNumber fillFromInteger(long a) { return fillFromInteger(new java.math.BigInteger("" + a)); } /** * Get a AlgebraicNumber element from a BigInteger value. * @param a BigInteger. * @return a AlgebraicNumber. */ public AlgebraicNumber fromInteger(java.math.BigInteger a) { return new AlgebraicNumber(this, ring.fromInteger(a)); } /** * Get a AlgebraicNumber element from a long value. * @param a long. * @return a AlgebraicNumber. */ public AlgebraicNumber fromInteger(long a) { return new AlgebraicNumber(this, ring.fromInteger(a)); // if ( characteristic().signum() == 0 ) { // } // return fromInteger( new java.math.BigInteger(""+a) ); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "AlgebraicNumberRing[ " + modul.toString() + " | isField=" + isField + " :: " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); s.append("AN("); s.append(modul.toScript()); switch (Scripting.getLang()) { case Ruby: s.append((isField() ? ",true" : ",false")); break; case Python: default: s.append((isField() ? ",True" : ",False")); } s.append(","); s.append(ring.toScript()); s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") // not jet working public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof AlgebraicNumberRing)) { return false; } AlgebraicNumberRing a = (AlgebraicNumberRing) b; return modul.equals(a.modul); } /** * Hash code for this AlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * modul.hashCode() + ring.hashCode(); } /** * AlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public AlgebraicNumber random(int n) { GenPolynomial x = ring.random(n).monic(); return new AlgebraicNumber(this, x); } /** * AlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public AlgebraicNumber random(int n, Random rnd) { GenPolynomial x = ring.random(n, rnd).monic(); return new AlgebraicNumber(this, x); } /** * Parse AlgebraicNumber from String. * @param s String. * @return AlgebraicNumber from s. */ public AlgebraicNumber parse(String s) { GenPolynomial x = ring.parse(s); return new AlgebraicNumber(this, x); } /** * Parse AlgebraicNumber from Reader. * @param r Reader. * @return next AlgebraicNumber from r. */ public AlgebraicNumber parse(Reader r) { GenPolynomial x = ring.parse(r); return new AlgebraicNumber(this, x); } /** * AlgebraicNumber chinese remainder algorithm. Assert deg(c.modul) ≥ * deg(a.modul) and c.modul * a.modul = this.modul. * @param c AlgebraicNumber. * @param ci inverse of c.modul in ring of a. * @param a other AlgebraicNumber. * @return S, with S mod c.modul == c and S mod a.modul == a. */ public AlgebraicNumber chineseRemainder(AlgebraicNumber c, AlgebraicNumber ci, AlgebraicNumber a) { if (true) { // debug if (c.ring.modul.compareTo(a.ring.modul) < 1) { System.out.println("AlgebraicNumber error " + c + ", " + a); } } AlgebraicNumber b = new AlgebraicNumber(a.ring, c.val); // c mod a.modul // c( tbcf(a.modul) ) if deg(a.modul)==1 AlgebraicNumber d = a.subtract(b); // a-c mod a.modul if (d.isZERO()) { return new AlgebraicNumber(this, c.val); } b = d.multiply(ci); // b = (a-c)*ci mod a.modul // (c.modul*b)+c mod this.modul = c mod c.modul = // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul GenPolynomial s = c.ring.modul.multiply(b.val); s = s.sum(c.val); return new AlgebraicNumber(this, s); } /** * AlgebraicNumber interpolation algorithm. Assert deg(c.modul) ≥ * deg(A.modul) and c.modul * A.modul = this.modul. Special case with * deg(A.modul) == 1. Similar algorithm as chinese remainder algorithm. * @param c AlgebraicNumber. * @param ci inverse of (c.modul)(a) in ring of A. * @param am trailing base coefficient of modul of other AlgebraicNumber A. * @param a value of other AlgebraicNumber A. * @return S, with S(c) == c and S(A) == a. */ public AlgebraicNumber interpolate(AlgebraicNumber c, C ci, C am, C a) { C b = PolyUtil. evaluateMain(ring.coFac /*a*/, c.val, am); // c mod a.modul // c( tbcf(a.modul) ) if deg(a.modul)==1 C d = a.subtract(b); // a-c mod a.modul if (d.isZERO()) { return new AlgebraicNumber(this, c.val); } b = d.multiply(ci); // b = (a-c)*ci mod a.modul // (c.modul*b)+c mod this.modul = c mod c.modul = // (c.modul*ci*(a-c)+c) mod a.modul = a mod a.modul GenPolynomial s = c.ring.modul.multiply(b); s = s.sum(c.val); return new AlgebraicNumber(this, s); } /** * Depth of extension field tower. * @return number of nested algebraic extension fields */ @SuppressWarnings({ "unchecked", "cast" }) public int depth() { AlgebraicNumberRing arr = this; int depth = 1; RingFactory cf = arr.ring.coFac; if (cf instanceof AlgebraicNumberRing) { arr = (AlgebraicNumberRing) (Object) cf; depth += arr.depth(); } return depth; } /** * Degree of extension field. * @return degree of this algebraic extension field */ public long extensionDegree() { long degree = modul.degree(0); return degree; } /** * Total degree of nested extension fields. * @return degree of tower of algebraic extension fields */ @SuppressWarnings({ "unchecked", "cast" }) public long totalExtensionDegree() { long degree = modul.degree(0); AlgebraicNumberRing arr = this; RingFactory cf = arr.ring.coFac; if (cf instanceof AlgebraicNumberRing) { arr = (AlgebraicNumberRing) (Object) cf; if (degree == 0L) { degree = arr.totalExtensionDegree(); } else { degree *= arr.totalExtensionDegree(); } } return degree; } /** * Get a AlgebraicNumber iterator. Note: Only for finite field * coefficients or fields which are iterable. * @return a iterator over all algebraic numbers in this ring. */ public Iterator> iterator() { return new AlgebraicNumberIterator(this); } } /** * Algebraic number iterator. * @author Heinz Kredel */ class AlgebraicNumberIterator> implements Iterator> { /** * data structure. */ final Iterator> iter; final List> powers; final AlgebraicNumberRing aring; private static final Logger logger = LogManager.getLogger(AlgebraicNumberIterator.class); // private static final boolean debug = logger.isDebugEnabled(); /** * CartesianProduct iterator constructor. * @param aring AlgebraicNumberRing components of the Cartesian product. */ @SuppressWarnings("unchecked") public AlgebraicNumberIterator(AlgebraicNumberRing aring) { RingFactory cf = aring.ring.coFac; this.aring = aring; long d = aring.modul.degree(0); //System.out.println("d = " + d); powers = new ArrayList>((int) d); for (long j = d - 1; j >= 0L; j--) { powers.add(aring.ring.univariate(0, j)); } //System.out.println("powers = " + powers); if (!(cf instanceof Iterable)) { throw new IllegalArgumentException("only for iterable coefficients implemented"); } List> comps = new ArrayList>((int) d); Iterable cfi = (Iterable) cf; for (long j = 0L; j < d; j++) { comps.add(cfi); } if (cf.isFinite()) { CartesianProduct tuples = new CartesianProduct(comps); iter = tuples.iterator(); } else { CartesianProductInfinite tuples = new CartesianProductInfinite(comps); iter = tuples.iterator(); } logger.info("iterator for degree {}, finite = {}", d, cf.isFinite()); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public boolean hasNext() { return iter.hasNext(); } /** * Get next tuple. * @return next tuple. */ public AlgebraicNumber next() { List coeffs = iter.next(); //System.out.println("coeffs = " + coeffs); GenPolynomial pol = aring.ring.getZERO(); int i = 0; for (GenPolynomial f : powers) { C c = coeffs.get(i++); if (c.isZERO()) { continue; } pol = pol.sum(f.multiply(c)); } return new AlgebraicNumber(aring, pol); } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } java-algebra-system-2.7.200/src/edu/jas/poly/Complex.java000066400000000000000000000375171445075545500231310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.StarRingElem; /** * Generic Complex class implementing the RingElem interface. Objects of this * class are immutable. * @param base type of RingElem (for complex polynomials). * @author Heinz Kredel */ public class Complex> implements StarRingElem>, GcdRingElem> { private static final Logger logger = LogManager.getLogger(Complex.class); private static final boolean debug = logger.isDebugEnabled(); /** * Complex class factory data structure. */ public final ComplexRing ring; /** * Real part of the data structure. */ protected final C re; /** * Imaginary part of the data structure. */ protected final C im; /** * The constructor creates a Complex object from two C objects as real and * imaginary part. * @param ring factory for Complex objects. * @param r real part. * @param i imaginary part. */ public Complex(ComplexRing ring, C r, C i) { this.ring = ring; re = r; im = i; } /** * The constructor creates a Complex object from a C object as real part, * the imaginary part is set to 0. * @param r real part. */ public Complex(ComplexRing ring, C r) { this(ring, r, ring.ring.getZERO()); } /** * The constructor creates a Complex object from a long element as real * part, the imaginary part is set to 0. * @param r real part. */ public Complex(ComplexRing ring, long r) { this(ring, ring.ring.fromInteger(r)); } /** * The constructor creates a Complex object with real part 0 and imaginary * part 0. */ public Complex(ComplexRing ring) { this(ring, ring.ring.getZERO()); } /** * The constructor creates a Complex object from a String representation. * @param s string of a Complex. * @throws NumberFormatException */ public Complex(ComplexRing ring, String s) throws NumberFormatException { this.ring = ring; if (s == null || s.length() == 0) { re = ring.ring.getZERO(); im = ring.ring.getZERO(); return; } s = s.trim(); int i = s.indexOf("i"); if (i < 0) { re = ring.ring.parse(s); im = ring.ring.getZERO(); return; } String sr = ""; if (i > 0) { sr = s.substring(0, i); } String si = ""; if (i < s.length()) { si = s.substring(i + 1, s.length()); } re = ring.ring.parse(sr.trim()); im = ring.ring.parse(si.trim()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ComplexRing factory() { return ring; } /** * Get the real part. * @return re. */ public C getRe() { return re; } /** * Get the imaginary part. * @return im. */ public C getIm() { return im; } /** * Copy this. * @see edu.jas.structure.Element#copy() */ @Override public Complex copy() { return new Complex(ring, re, im); } /** * Get the String representation. */ @Override public String toString() { String s = re.toString(); if (im.isZERO()) { return s; } s += "i" + im; return s; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer(); if (im.isZERO()) { s.append(re.toScript()); } else { C mi = im; //s.append(""); if (!re.isZERO()) { s.append(re.toScript()); if (mi.signum() > 0) { s.append(" + "); } else { s.append(" - "); mi = mi.negate(); } } if (mi.isONE()) { s.append("I"); } else { s.append(mi.toScript()).append(" * I"); } s.append(""); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return ring.toScript(); } /** * Is Complex number zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return re.isZERO() && im.isZERO(); } /** * Is Complex number one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return re.isONE() && im.isZERO(); } /** * Is Complex imaginary one. * @return If this is i then true is returned, else false. */ public boolean isIMAG() { return re.isZERO() && im.isONE(); } /** * Is Complex unit element. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isZERO()) { return false; } if (ring.isField()) { return true; } return norm().re.isUnit(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Complex)) { return false; } Complex bc = (Complex) b; if (!ring.equals(bc.ring)) { return false; } return re.equals(bc.re) && im.equals(bc.im); } /** * Hash code for this Complex. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * re.hashCode() + im.hashCode(); } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to b; 1 if re > b.re, or re == b.re and im * > b.im; -1 if re < b.re, or re == b.re and im < b.im */ @Override public int compareTo(Complex b) { int s = re.compareTo(b.re); if (s != 0) { return s; } return im.compareTo(b.im); } /** * Since complex numbers are unordered, we use lexicographical order of re * and im. * @return 0 if this is equal to 0; 1 if re > 0, or re == 0 and im > * 0; -1 if re < 0, or re == 0 and im < 0 * @see edu.jas.structure.RingElem#signum() */ public int signum() { int s = re.signum(); if (s != 0) { return s; } return im.signum(); } /* arithmetic operations: +, -, - */ /** * Complex number summation. * @param B a Complex number. * @return this+B. */ public Complex sum(Complex B) { return new Complex(ring, re.sum(B.re), im.sum(B.im)); } /** * Complex number subtract. * @param B a Complex number. * @return this-B. */ public Complex subtract(Complex B) { return new Complex(ring, re.subtract(B.re), im.subtract(B.im)); } /** * Complex number negative. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Complex negate() { return new Complex(ring, re.negate(), im.negate()); } /* arithmetic operations: conjugate, absolute value */ /** * Complex number conjugate. * @return the complex conjugate of this. */ public Complex conjugate() { return new Complex(ring, re, im.negate()); } /** * Complex number norm. * @see edu.jas.structure.StarRingElem#norm() * @return ||this||. */ public Complex norm() { // this.multiply(this.conjugate()); C v = re.multiply(re); v = v.sum(im.multiply(im)); return new Complex(ring, v); } /** * Complex number absolute value. * @see edu.jas.structure.RingElem#abs() * @return |this|^2. Note: The square root is not jet implemented. */ public Complex abs() { Complex n = norm(); logger.error("abs() square root missing"); // n = n.sqrt(); return n; } /* arithmetic operations: *, inverse, / */ /** * Complex number product. * @param B is a complex number. * @return this*B. */ public Complex multiply(Complex B) { return new Complex(ring, re.multiply(B.re).subtract(im.multiply(B.im)), re.multiply(B.im).sum(im.multiply(B.re))); } /** * Complex number inverse. * @return S with S*this = 1, if it is defined. * @see edu.jas.structure.RingElem#inverse() */ public Complex inverse() { C a = norm().re.inverse(); return new Complex(ring, re.multiply(a), im.multiply(a.negate())); } /** * Complex number remainder. * @param S is a complex number. * @return 0. */ public Complex remainder(Complex S) { if (ring.isField()) { return ring.getZERO(); } return quotientRemainder(S)[1]; } /** * Complex number divide. * @param B is a complex number, non-zero. * @return this/B. */ public Complex divide(Complex B) { if (ring.isField()) { return this.multiply(B.inverse()); } return quotientRemainder(B)[0]; } /** * Complex number quotient and remainder. * @param S Complex. * @return Complex[] { q, r } with q = this/S and r = rem(this,S). */ @SuppressWarnings({ "unchecked", "cast" }) public Complex[] quotientRemainder(Complex S) { Complex[] ret = new Complex[2]; C n = S.norm().re; Complex Sp = this.multiply(S.conjugate()); // == this*inv(S)*n C qr = Sp.re.divide(n); C rr = Sp.re.remainder(n); C qi = Sp.im.divide(n); C ri = Sp.im.remainder(n); C rr1 = rr; C ri1 = ri; if (rr.signum() < 0) { rr = rr.negate(); } if (ri.signum() < 0) { ri = ri.negate(); } C one = n.factory().fromInteger(1); if (rr.sum(rr).compareTo(n) > 0) { // rr > n/2 if (rr1.signum() < 0) { qr = qr.subtract(one); } else { qr = qr.sum(one); } } if (ri.sum(ri).compareTo(n) > 0) { // ri > n/2 if (ri1.signum() < 0) { qi = qi.subtract(one); } else { qi = qi.sum(one); } } Sp = new Complex(ring, qr, qi); Complex Rp = this.subtract(Sp.multiply(S)); if (debug && n.compareTo(Rp.norm().re) < 0) { System.out.println("n = " + n); System.out.println("qr = " + qr); System.out.println("qi = " + qi); System.out.println("rr = " + rr); System.out.println("ri = " + ri); System.out.println("rr1 = " + rr1); System.out.println("ri1 = " + ri1); System.out.println("this = " + this); System.out.println("S = " + S); System.out.println("Sp = " + Sp); BigInteger tr = (BigInteger) (Object) this.re; BigInteger ti = (BigInteger) (Object) this.im; BigInteger sr = (BigInteger) (Object) S.re; BigInteger si = (BigInteger) (Object) S.im; BigComplex tc = new BigComplex(new BigRational(tr), new BigRational(ti)); BigComplex sc = new BigComplex(new BigRational(sr), new BigRational(si)); BigComplex qc = tc.divide(sc); System.out.println("qc = " + qc); BigDecimal qrd = new BigDecimal(qc.getRe()); BigDecimal qid = new BigDecimal(qc.getIm()); System.out.println("qrd = " + qrd); System.out.println("qid = " + qid); throw new ArithmeticException("QR norm not decreasing " + Rp + ", " + Rp.norm()); } ret[0] = Sp; ret[1] = Rp; return ret; } /** * Complex number greatest common divisor. * @param S Complex. * @return gcd(this,S). */ public Complex gcd(Complex S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.isField()) { return ring.getONE(); } Complex a = this; Complex b = S; if (a.re.signum() < 0) { a = a.negate(); } if (b.re.signum() < 0) { b = b.negate(); } while (!b.isZERO()) { if (debug) { logger.info("norm(b), a, b = {}, {}, {}", b.norm(), a, b); } Complex[] qr = a.quotientRemainder(b); if (qr[0].isZERO()) { System.out.println("a = " + a); } a = b; b = qr[1]; } if (a.re.signum() < 0) { a = a.negate(); } return a; } /** * Complex extended greatest common divisor. * @param S Complex. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public Complex[] egcd(Complex S) { Complex[] ret = new Complex[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = S; return ret; } if (ring.isField()) { Complex half = new Complex(ring, ring.ring.fromInteger(1).divide(ring.ring.fromInteger(2))); ret[0] = ring.getONE(); ret[1] = this.inverse().multiply(half); ret[2] = S.inverse().multiply(half); return ret; } Complex[] qr; Complex q = this; Complex r = S; Complex c1 = ring.getONE(); Complex d1 = ring.getZERO(); Complex c2 = ring.getZERO(); Complex d2 = ring.getONE(); Complex x1; Complex x2; while (!r.isZERO()) { if (debug) { logger.info("norm(r), q, r = {}, {}, {}", r.norm(), q, r); } qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } if (q.re.signum() < 0) { q = q.negate(); c1 = c1.negate(); c2 = c2.negate(); } ret[0] = q; ret[1] = c1; ret[2] = c2; return ret; } } java-algebra-system-2.7.200/src/edu/jas/poly/ComplexRing.java000066400000000000000000000162151445075545500237410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Generic Complex ring factory implementing the RingFactory interface. Objects * of this class are immutable. * @param base type. * @author Heinz Kredel */ public class ComplexRing> implements RingFactory> { private final static Random random = new Random(); @SuppressWarnings("unused") private static final Logger logger = LogManager.getLogger(ComplexRing.class); /** * Complex class elements factory data structure. */ public final RingFactory ring; /** * The constructor creates a ComplexRing object. * @param ring factory for Complex real and imaginary parts. */ public ComplexRing(RingFactory ring) { this.ring = ring; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List gens = ring.generators(); List> g = new ArrayList>(gens.size() + 1); for (C x : gens) { Complex cx = new Complex(this, x); g.add(cx); } g.add(getIMAG()); return g; } /** * Corresponding algebraic number ring. * @return algebraic number ring. not jet possible. */ public AlgebraicNumberRing algebraicRing() { GenPolynomialRing pfac = new GenPolynomialRing(ring, TermOrderByName.INVLEX, new String[] { "I" }); GenPolynomial I = pfac.univariate(0, 2L).sum(pfac.getONE()); AlgebraicNumberRing afac = new AlgebraicNumberRing(I, ring.isField()); // must indicate field return afac; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.isFinite(); } /** * Copy Complex element c. * @param c Complex<C>. * @return a copy of c. */ public Complex copy(Complex c) { return new Complex(this, c.re, c.im); } /** * Get the zero element. * @return 0 as Complex<C>. */ public Complex getZERO() { return new Complex(this); } /** * Get the one element. * @return 1 as Complex<C>. */ public Complex getONE() { return new Complex(this, ring.getONE()); } /** * Get the i element. * @return i as Complex<C>. */ public Complex getIMAG() { return new Complex(this, ring.getZERO(), ring.getONE()); } /** * Query if this ring is commutative. * @return true. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return ring.isField(); } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Complex element from a BigInteger. * @param a BigInteger. * @return a Complex<C>. */ public Complex fromInteger(BigInteger a) { return new Complex(this, ring.fromInteger(a)); } /** * Get a Complex element from a long. * @param a long. * @return a Complex<C>. */ public Complex fromInteger(long a) { return new Complex(this, ring.fromInteger(a)); } /** * Get the String representation. */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("Complex["); if (ring instanceof RingElem) { RingElem ri = (RingElem) ring; sb.append(ri.toScriptFactory()); } else { sb.append(ring.toString()); } sb.append("]"); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer(); s.append("CR("); if (ring instanceof RingElem) { RingElem ri = (RingElem) ring; s.append(ri.toScriptFactory()); } else { s.append(ring.toScript()); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof ComplexRing)) { return false; } ComplexRing a = (ComplexRing) b; if (!ring.equals(a.ring)) { return false; } return true; } /** * Hash code for this ComplexRing<C>. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return ring.hashCode(); } /** * Complex number random. Random base numbers A and B are generated using * random(n). Then R is the complex number with real part A and imaginary * part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @return R. */ public Complex random(int n) { return random(n, random); // C r = ring.random( n ).abs(); // C i = ring.random( n ).abs(); // return new Complex(this, r, i ); } /** * Complex number random. Random base numbers A and B are generated using * random(n). Then R is the complex number with real part A and imaginary * part B. * @param n such that 0 ≤ A, B ≤ (2n-1). * @param rnd is a source for random bits. * @return R. */ public Complex random(int n, Random rnd) { C r = ring.random(n, rnd); C i = ring.random(n, rnd); return new Complex(this, r, i); } /** * Parse complex number from string. * @param s String. * @return Complex from s. */ public Complex parse(String s) { return new Complex(this, s); } /** * Parse complex number from Reader. * @param r Reader. * @return next Complex from r. */ public Complex parse(Reader r) { return parse(StringUtil.nextString(r)); } } java-algebra-system-2.7.200/src/edu/jas/poly/Examples.java000066400000000000000000000566651445075545500233050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; /** * Examples for polynomials usage. * @author Heinz Kredel */ public class Examples { /** * main. */ public static void main(String[] args) { //example0(); /* example1(); example2(); example3(); example4(); example5(); */ //example6(); example7(); example7(); //example8(); //example9(); //example10(); //example11(); //example12(); //example13(); example14(); } /** * example0. for PPPJ 2006. */ public static void example0() { BigInteger z = new BigInteger(); TermOrder to = new TermOrder(); String[] vars = new String[] { "x1", "x2", "x3" }; GenPolynomialRing ring; ring = new GenPolynomialRing(z, 3, to, vars); System.out.println("ring = " + ring); GenPolynomial pol; pol = ring.parse("3 x1^2 x3^4 + 7 x2^5 - 61"); System.out.println("pol = " + pol); System.out.println("pol = " + pol.toString(ring.getVars())); GenPolynomial one; one = ring.parse("1"); System.out.println("one = " + one); System.out.println("one = " + one.toString(ring.getVars())); GenPolynomial p; p = pol.subtract(pol); System.out.println("p = " + p); System.out.println("p = " + p.toString(ring.getVars())); p = pol.multiply(pol); System.out.println("p = " + p); System.out.println("p = " + p.toString(ring.getVars())); } /** * example1. random polynomial with rational coefficients. Q[x_1,...x_7] */ public static void example1() { System.out.println("\n\n example 1"); BigRational cfac = new BigRational(); System.out.println("cfac = " + cfac); String[] vars = new String[] { "x1", "x2", "x3", "x4", "x5", "x6", "x7" }; GenPolynomialRing fac; fac = new GenPolynomialRing(cfac, 7, vars); //System.out.println("fac = " + fac); System.out.println("fac = " + fac); GenPolynomial a = fac.random(10); System.out.println("a = " + a); } /** * example2. random polynomial with coefficients of rational polynomials. * Q[x_1,...x_7][y_1,...,y_3] */ public static void example2() { System.out.println("\n\n example 2"); BigRational cfac = new BigRational(); System.out.println("cfac = " + cfac); String[] cvars = new String[] { "x1", "x2", "x3", "x4", "x5", "x6", "x7" }; GenPolynomialRing fac; fac = new GenPolynomialRing(cfac, 7, cvars); System.out.println("fac = " + fac); String[] vars = new String[] { "y1", "y2", "y3" }; GenPolynomialRing> gfac; gfac = new GenPolynomialRing>(fac, 3, vars); System.out.println("gfac = " + gfac); GenPolynomial> a = gfac.random(10); System.out.println("a = " + a); } /** * example3. random rational algebraic number. Q(alpha) */ public static void example3() { System.out.println("\n\n example 3"); BigRational cfac = new BigRational(); System.out.println("cfac = " + cfac); String[] vars = new String[] { "alpha" }; GenPolynomialRing mfac; mfac = new GenPolynomialRing(cfac, 1, vars); System.out.println("mfac = " + mfac); GenPolynomial modul = mfac.random(8).monic(); // assume !mo.isUnit() System.out.println("modul = " + modul); AlgebraicNumberRing fac; fac = new AlgebraicNumberRing(modul); System.out.println("fac = " + fac); AlgebraicNumber a = fac.random(15); System.out.println("a = " + a); } protected static long getPrime() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //System.out.println("prime = " + prime); return prime; } /** * example4. random modular algebraic number. Z_p(alpha) */ public static void example4() { System.out.println("\n\n example 4"); long prime = getPrime(); ModIntegerRing cfac = new ModIntegerRing(prime); System.out.println("cfac = " + cfac); String[] vars = new String[] { "alpha" }; GenPolynomialRing mfac; mfac = new GenPolynomialRing(cfac, 1, vars); System.out.println("mfac = " + mfac); GenPolynomial modul = mfac.random(8).monic(); // assume !modul.isUnit() System.out.println("modul = " + modul); AlgebraicNumberRing fac; fac = new AlgebraicNumberRing(modul); System.out.println("fac = " + fac); AlgebraicNumber a = fac.random(12); System.out.println("a = " + a); } /** * example5. random solvable polynomial with rational coefficients. * Q{x_1,...x_6, {x_2 * x_1 = x_1 x_2 +1, ...} } */ public static void example5() { System.out.println("\n\n example 5"); BigRational cfac = new BigRational(); System.out.println("cfac = " + cfac); GenSolvablePolynomialRing sfac; sfac = new GenSolvablePolynomialRing(cfac, 6); //System.out.println("sfac = " + sfac); RelationGenerator wl = new WeylRelations(); //wl.generate(sfac); sfac.addRelations(wl); System.out.println("sfac = " + sfac); GenSolvablePolynomial a = sfac.random(5); System.out.println("a = " + a); System.out.println("a = " + a.toString(sfac.vars)); GenSolvablePolynomial b = a.multiply(a); System.out.println("b = " + b); System.out.println("b = " + b.toString(sfac.vars)); System.out.println("sfac = " + sfac); } /** * example6. Fateman benchmark: p = (x+y+z)^20; q = p * (p+1) Z[z,y,x] */ public static void example6() { System.out.println("\n\n example 6"); BigInteger cfac = new BigInteger(); System.out.println("cfac = " + cfac); TermOrder to = new TermOrder(TermOrder.INVLEX); System.out.println("to = " + to); GenPolynomialRing fac; fac = new GenPolynomialRing(cfac, 3, to); System.out.println("fac = " + fac); fac.setVars(new String[] { "z", "y", "x" }); System.out.println("fac = " + fac); GenPolynomial x = fac.univariate(0); GenPolynomial y = fac.univariate(1); GenPolynomial z = fac.univariate(2); System.out.println("x = " + x); System.out.println("x = " + x.toString(fac.vars)); System.out.println("y = " + y); System.out.println("y = " + y.toString(fac.vars)); System.out.println("z = " + z); System.out.println("z = " + z.toString(fac.vars)); GenPolynomial p = x.sum(y).sum(z).sum(fac.getONE()); //BigInteger f = cfac.fromInteger(10000000001L); // p = p.multiply( f ); System.out.println("p = " + p); System.out.println("p = " + p.toString(fac.vars)); GenPolynomial q = p; for (int i = 1; i < 20; i++) { q = q.multiply(p); } //System.out.println("q = " + q.toString( fac.vars ) ); System.out.println("q = " + q.length()); GenPolynomial q1 = q.sum(fac.getONE()); GenPolynomial q2; long t = System.currentTimeMillis(); q2 = q.multiply(q1); t = System.currentTimeMillis() - t; System.out.println("q2 = " + q2.length()); System.out.println("time = " + t + " ms"); } /** * example7. Fateman benchmark: p = (x+y+z)^20; q = p * (p+1) Q[z,y,x] */ public static void example7() { System.out.println("\n\n example 7"); BigRational cfac = new BigRational(); System.out.println("cfac = " + cfac); TermOrder to = new TermOrder(TermOrder.INVLEX); System.out.println("to = " + to); GenPolynomialRing fac; fac = new GenPolynomialRing(cfac, 3, to); System.out.println("fac = " + fac); fac.setVars(new String[] { "z", "y", "x" }); System.out.println("fac = " + fac); long mi = 1L; //long mi = Integer.MAX_VALUE; GenPolynomial x = fac.univariate(0, mi); GenPolynomial y = fac.univariate(1, mi); GenPolynomial z = fac.univariate(2, mi); // System.out.println("x = " + x); System.out.println("x = " + x.toString(fac.vars)); // System.out.println("y = " + y); System.out.println("y = " + y.toString(fac.vars)); // System.out.println("z = " + z); System.out.println("z = " + z.toString(fac.vars)); GenPolynomial p = x.sum(y).sum(z).sum(fac.getONE()); //BigRational f = cfac.fromInteger(10000000001L); // f = f.multiply( f ); //p = p.multiply( f ); // System.out.println("p = " + p); System.out.println("p = " + p.toString(fac.vars)); int mpow = 20; System.out.println("mpow = " + mpow); GenPolynomial q = p; for (int i = 1; i < mpow; i++) { q = q.multiply(p); } //System.out.println("q = " + q.toString( fac.vars ) ); System.out.println("len(q) = " + q.length()); System.out.println("deg(q) = " + q.degree()); GenPolynomial q1 = q.sum(fac.getONE()); GenPolynomial q2; long t = System.currentTimeMillis(); q2 = q.multiply(q1); t = System.currentTimeMillis() - t; System.out.println("len(q2) = " + q2.length()); System.out.println("deg(q2) = " + q2.degree()); System.out.println("LeadEV(q2) = " + q2.leadingExpVector()); System.out.println("time = " + t + " ms"); } /** * example8. Chebyshev polynomials * * T(0) = 1 T(1) = x T(n) = 2x * T(n-1) - T(n-2) */ public static void example8() { int m = 10; BigInteger fac = new BigInteger(); String[] var = new String[] { "x" }; GenPolynomialRing ring = new GenPolynomialRing(fac, 1, var); List> T = new ArrayList>(m); GenPolynomial t, one, x, x2, x2b; one = ring.getONE(); x = ring.univariate(0); //x2 = ring.parse("2 x"); //x2a = x.multiply( fac.fromInteger(2) ); x2b = x.multiply(new BigInteger(2)); x2 = x2b; T.add(one); T.add(x); for (int n = 2; n < m; n++) { t = x2.multiply(T.get(n - 1)).subtract(T.get(n - 2)); T.add(t); } for (int n = 0 /*m-2*/; n < m; n++) { System.out.println("T[" + n + "] = " + T.get(n)); //.toString(var) ); } } /** * example9. Legendre polynomials * * P(0) = 1 P(1) = x P(n) = 1/n [ (2n-1) * x * P(n-1) - (n-1) * P(n-2) ] */ // P(n+1) = 1/(n+1) [ (2n+1) * x * P(n) - n * P(n-1) ] public static void example9() { int n = 10; BigRational fac = new BigRational(); String[] var = new String[] { "x" }; GenPolynomialRing ring = new GenPolynomialRing(fac, 1, var); List> P = new ArrayList>(n); GenPolynomial t, one, x, xc; BigRational n21, nn; one = ring.getONE(); x = ring.univariate(0); P.add(one); P.add(x); for (int i = 2; i < n; i++) { n21 = new BigRational(2 * i - 1); xc = x.multiply(n21); t = xc.multiply(P.get(i - 1)); nn = new BigRational(i - 1); xc = P.get(i - 2).multiply(nn); t = t.subtract(xc); nn = new BigRational(1, i); t = t.multiply(nn); P.add(t); } for (int i = 0; i < n; i++) { System.out.println("P[" + i + "] = " + P.get(i).toString(var)); System.out.println(); } } /** * example10. Hermite polynomials * * H(0) = 1 H(1) = 2 x H(n) = 2 * x * H(n-1) - 2 * (n-1) * H(n-2) */ // H(n+1) = 2 * x * H(n) - 2 * n * H(n-1) public static void example10() { int n = 100; BigInteger fac = new BigInteger(); String[] var = new String[] { "x" }; GenPolynomialRing ring = new GenPolynomialRing(fac, 1, var); List> H = new ArrayList>(n); GenPolynomial t, one, x2, xc, x; BigInteger n2, nn; one = ring.getONE(); x = ring.univariate(0); n2 = new BigInteger(2); x2 = x.multiply(n2); H.add(one); H.add(x2); for (int i = 2; i < n; i++) { t = x2.multiply(H.get(i - 1)); nn = new BigInteger(2 * (i - 1)); xc = H.get(i - 2).multiply(nn); t = t.subtract(xc); H.add(t); } for (int i = n - 1; i < n; i++) { System.out.println("H[" + i + "] = " + H.get(i).toString(var)); System.out.println(); } } /** * example11. degree matrix; */ @SuppressWarnings("unchecked") public static void example11() { int n = 50; BigRational fac = new BigRational(); GenPolynomialRing ring = new GenPolynomialRing(fac, n); System.out.println("ring = " + ring + "\n"); GenPolynomial p = ring.random(5, 3, 6, 0.5f); System.out.println("p = " + p + "\n"); List> dem = TermOrderOptimization. degreeMatrix(p); System.out.println("dem = " + dem + "\n"); List> polys = new ArrayList>(); polys.add(p); for (int i = 0; i < 5; i++) { polys.add(ring.random(5, 3, 6, 0.1f)); } System.out.println("polys = " + polys + "\n"); dem = TermOrderOptimization. degreeMatrix(polys); System.out.println("dem = " + dem + "\n"); List perm; perm = TermOrderOptimization.optimalPermutation(dem); System.out.println("perm = " + perm + "\n"); List> pdem; pdem = TermOrderOptimization.> listPermutation(perm, dem); System.out.println("pdem = " + pdem + "\n"); GenPolynomialRing pring; pring = TermOrderOptimization. permutation(perm, ring); System.out.println("ring = " + ring); System.out.println("pring = " + pring + "\n"); List> ppolys; ppolys = TermOrderOptimization. permutation(perm, pring, polys); System.out.println("ppolys = " + ppolys + "\n"); dem = TermOrderOptimization. degreeMatrix(ppolys); //System.out.println("pdem = " + dem + "\n"); perm = TermOrderOptimization.optimalPermutation(dem); //System.out.println("pperm = " + perm + "\n"); int i = 0; for (Integer j : perm) { if (i != (int) j) { System.out.println("error = " + i + " != " + j + "\n"); } i++; } OptimizedPolynomialList op; op = TermOrderOptimization. optimizeTermOrder(ring, polys); System.out.println("op:\n" + op); if (!op.equals(new PolynomialList(pring, ppolys))) { System.out.println("error = " + "\n" + op); } } /** * example12. type games. */ public static void example12() { System.out.println("\n\n example 12"); BigRational t1 = new BigRational(); System.out.println("t1 = " + t1); BigInteger t2 = new BigInteger(); System.out.println("t2 = " + t2); System.out.println("t1.isAssignableFrom(t2) = " + t1.getClass().isAssignableFrom(t2.getClass())); System.out.println("t2.isAssignableFrom(t1) = " + t2.getClass().isAssignableFrom(t1.getClass())); String[] vars = new String[] { "x1", "x2", "x3" }; GenPolynomialRing t3 = new GenPolynomialRing(t2, 3, vars); System.out.println("t3 = " + t3); GenSolvablePolynomialRing t4 = new GenSolvablePolynomialRing(t2, vars); System.out.println("t4 = " + t4); System.out.println("t3.isAssignableFrom(t4) = " + t3.getClass().isAssignableFrom(t4.getClass())); System.out.println("t4.isAssignableFrom(t3) = " + t4.getClass().isAssignableFrom(t3.getClass())); GenPolynomialRing t5 = new GenPolynomialRing(t1, 3, vars); System.out.println("t5 = " + t5); System.out.println("t3.isAssignableFrom(t5) = " + t3.getClass().isAssignableFrom(t5.getClass())); System.out.println("t5.isAssignableFrom(t3) = " + t5.getClass().isAssignableFrom(t3.getClass())); } /** * example13. poly parser for strange syntax. */ public static void example13() { System.out.println("\n\n example 13"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfraction = new BigRational(1); String[] vars = new String[] { "x" }; //Scripting.setPrecision(5); GenPolynomialRing pfac = new GenPolynomialRing(cfraction, 1, to, vars); GenPolynomial FF0 = pfac.parse("19(6)/10"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("19(6)1/10"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("19 6/10"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("19*6/10"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("19+6/10"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("(x).2"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("4.0/9.0"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("4/9.0"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("4.0/9"); System.out.println("FF0 = " + FF0); FF0 = pfac.parse("-4.0/9"); System.out.println("FF0 = " + FF0); } /* * Old example after Blonski, 1983. */ public static void example14() { BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf.toScriptFactory()); // non-commuting indexes: 1 2 3 4 //String ss = "E(1,2,3,4)"; IndexFactory wf = new IndexFactory(4); // (1,4) //System.out.println("wf = " + wf.toScript()); // index list polynomials over integers GenExteriorPolynomialRing pf; pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); System.out.println("not commutative" + pf.isCommutative()); System.out.println("associative" + pf.isAssociative()); System.out.println("not field" + pf.isField()); GenExteriorPolynomial emaxd, p1, p2, q1, q2, s, g1, g2, e1, e2, e1dual, e2dual, q, qs, qt, g1dual, g2dual, s1, s2; // parse points in 4-space as polynomials emaxd = pf.parse("E(1,2,3,4)"); // wf.imax System.out.println("emaxd = " + emaxd + ", imax = " + pf.ixfac.imax); p1 = pf.parse("1 E(1) + 5 E(2) - 2 E(3) + 1 E(4)"); p2 = pf.parse("4 E(1) + 3 E(2) + 6 E(3) + 1 E(4)"); System.out.println("p1 = " + p1); System.out.println("p2 = " + p2); q1 = pf.parse("3 E(1) - 2 E(2) - 1 E(3) + 1 E(4)"); q2 = pf.parse("1 E(2) + 5 E(3) + 1 E(4)"); System.out.println("q1 = " + q1); System.out.println("q2 = " + q2); s = pf.parse("1 E(3) + 1 E(4)"); System.out.println("s = " + s); // compute line(gerade) p1..p2 and q1..q2 g1 = p1.multiply(p2).abs(); g2 = q1.multiply(q2).abs().divide(new BigInteger(3)); System.out.println("g1 = p1 /\\ p2 = " + g1); System.out.println("g2 = q1 /\\ q2 = " + g2); System.out.println("pp(g2) = " + q1.multiply(q2).coeffPrimitivePart()); System.out.println("g2 == pp(g2): " + g2 + " == " + q1.multiply(q2).coeffPrimitivePart()); // compute plane(ebene) g1..s and g2..s e1 = g1.multiply(s).abs().divide(new BigInteger(17)); e2 = g2.multiply(s); System.out.println("e1 = g1 /\\ s = " + e1); System.out.println("e2 = g2 /\\ s = " + e2); System.out.println("e1 == pp(e1): " + e1 + " == " + g1.multiply(s).coeffPrimitivePart()); // compute dual planes of e1, e2 as e1..emaxd and e2..emaxd e1dual = e1.interiorRightProduct(emaxd).abs(); e2dual = e2.interiorRightProduct(emaxd).abs(); System.out.println("e1dual = e1 |_ emaxd = " + e1dual); System.out.println("e2dual = e2 |_ emaxd = " + e2dual); // compute intersection of plane e1, e2 via dual plane sum q = e1dual.multiply(e2dual).abs().divide(new BigInteger(5)); System.out.println("q = (e1dual /\\ e2dual) = " + q); System.out.println("q == pp(q): " + q + " == " + e1dual.multiply(e2dual).coeffPrimitivePart()); qs = q.interiorRightProduct(emaxd).abs(); System.out.println("qs = (e1dual /\\ e2dual) |_ emaxd = " + qs); qt = e1.interiorLeftProduct(e2dual).abs().divide(new BigInteger(5)); System.out.println("qt = e1 _| e2dual = " + qt); System.out.println("qt == pp(qt): " + qt + " == " + e1.interiorLeftProduct(e2dual).coeffPrimitivePart()); System.out.println("qs == qt: " + qs + " == " + qt); // compute dual line(gerade) of g1, g2 g1dual = g1.interiorRightProduct(emaxd); g2dual = g2.interiorRightProduct(emaxd).abs(); System.out.println("g1dual = g1 |_ emaxd = " + g1dual); System.out.println("g2dual = g2 |_ emaxd = " + g2dual); // compute intersection of g1..e2 and g2..e1 s1 = e2.interiorLeftProduct(g1dual).abs().divide(new BigInteger(5)); System.out.println("s1 = e2 _| g1dual = " + s1); s2 = e1.interiorLeftProduct(g2dual).abs().divide(new BigInteger(5)); System.out.println("s2 = e1 _| g2dual = " + s2); // check intersection of s..qs, qs..e1 and qs..e2 System.out.println(" s /\\ qs = s \\in qs = " + s.multiply(qs)); System.out.println("qs /\\ e1 = qs \\in e1 = " + qs.multiply(e1)); System.out.println("qs /\\ e2 = qs \\in e2 = " + qs.multiply(e2)); System.out.println("qs /\\ s == 0: " + qs.multiply(s).isZERO()); System.out.println("qs /\\ e1 == 0: " + qs.multiply(e1).isZERO()); System.out.println("qs /\\ e2 == 0: " + qs.multiply(e2).isZERO()); } } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVector.java000066400000000000000000000762571445075545500234450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Collection; import java.util.List; import java.util.Random; import edu.jas.arith.BigInteger; import edu.jas.structure.AbelianGroupElem; import edu.jas.structure.AbelianGroupFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * ExpVector implements exponent vectors for polynomials. Exponent vectors are * implemented as arrays of Java elementary types, like long, int, short and * byte. ExpVector provides also the familiar MAS static method names. The * implementation is only tested for nonnegative exponents but should work also * for negative exponents. Objects of this class are intended to be immutable, * but exponents can be set (during construction); also the hash code is only * computed once, when needed. The different storage unit implementations are * ExpVectorLong ExpVectorInteger, * ExpVectorShort and ExpVectorByte. The static * factory methods create() of ExpVector select the * respective storage unit. The selection of the desired storage unit is * internally done via the static variable storunit. This variable * should not be changed dynamically. * @author Heinz Kredel */ public abstract class ExpVector implements AbelianGroupElem { /** * Stored hash code. */ transient protected int hash = -1; /** * Stored bitLength. */ transient protected long blen = -1; /** * Random number generator. */ private final static Random random = new Random(); /** * Storage representation of exponent arrays. */ public static enum StorUnit { LONG, INT, SHORT, BYTE }; /** * Used storage representation of exponent arrays. Note: Set this * only statically and not dynamically. */ public final static StorUnit storunit = StorUnit.LONG; /** * Constructor for ExpVector. */ public ExpVector() { //bug: hash = 0; } /** * Factory constructor for ExpVector. * @param n length of exponent vector. */ public final static ExpVector create(int n) { switch (storunit) { case INT: return new ExpVectorInteger(n); case LONG: return new ExpVectorLong(n); case SHORT: return new ExpVectorShort(n); case BYTE: return new ExpVectorByte(n); default: return new ExpVectorInteger(n); } } /** * Factory constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public final static ExpVector create(int n, int i, long e) { switch (storunit) { case INT: return new ExpVectorInteger(n, i, e); case LONG: return new ExpVectorLong(n, i, e); case SHORT: return new ExpVectorShort(n, i, e); case BYTE: return new ExpVectorByte(n, i, e); default: return new ExpVectorInteger(n, i, e); } } /** * Internal factory constructor for ExpVector. Sets val. * @param v internal representation array. */ public final static ExpVector create(long[] v) { switch (storunit) { case INT: return new ExpVectorInteger(v); case LONG: return new ExpVectorLong(v); case SHORT: return new ExpVectorShort(v); case BYTE: return new ExpVectorByte(v); default: return new ExpVectorInteger(v); } } /** * Factory constructor for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. */ public final static ExpVector create(String s) { switch (storunit) { case INT: return new ExpVectorInteger(s); case LONG: return new ExpVectorLong(s); case SHORT: return new ExpVectorShort(s); case BYTE: return new ExpVectorByte(s); default: return new ExpVectorInteger(s); } } /** * Factory constructor for ExpVector. Sets val. * @param v collection of exponents. */ public final static ExpVector create(Collection v) { long[] w = new long[v.size()]; int i = 0; for (Long k : v) { w[i++] = k; } return create(w); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public AbelianGroupFactory factory() { throw new UnsupportedOperationException("no factory implemented for ExpVector"); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() Note: returns true * because of finite set of values in each index. */ public boolean isFinite() { return true; } /** * Value of other. * @param e other ExpVector. * @return value in sub class of ExpVector. */ public static ExpVector valueOf(ExpVector e) { //return ExpVector.create(e.getVal()); throw new UnsupportedOperationException("no general conversion"); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public abstract ExpVector copy(); /** * Get the exponent vector. * @return val. */ public abstract long[] getVal(); /** * Get the exponent at position i. * @param i position. * @return val[i]. */ public abstract long getVal(int i); /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ protected abstract long setVal(int i, long e); /** * Get the length of this exponent vector. * @return val.length. */ public abstract int length(); /** * Extend variables. Used e.g. in module embedding. Extend this by i * elements and set val[j] to e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ public abstract ExpVector extend(int i, int j, long e); /** * Extend lower variables. Extend this by i lower elements and set val[j] to * e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ public abstract ExpVector extendLower(int i, int j, long e); /** * Contract variables. Used e.g. in module embedding. Contract this to len * elements. * @param i position of first element to be copied. * @param len new length. * @return contracted exponent vector. */ public abstract ExpVector contract(int i, int len); /** * Reverse variables. Used e.g. in opposite rings. * @return reversed exponent vector. */ public abstract ExpVector reverse(); /** * Reverse lower j variables. Used e.g. in opposite rings. Reverses the * first j-1 variables, the rest is unchanged. * @param j index of first variable reversed. * @return reversed exponent vector. */ public abstract ExpVector reverse(int j); /** * Combine with ExpVector. Combine this with the other ExpVector V. * @param V the other exponent vector. * @return combined exponent vector. */ public abstract ExpVector combine(ExpVector V); /** * Permutation of exponent vector. * @param P permutation. * @return P(e). */ public abstract ExpVector permutation(List P); /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("("); for (int i = 0; i < length(); i++) { s.append(getVal(i)); if (i < length() - 1) { s.append(","); } } s.append(")"); return s.toString(); } /** * Get the string representation with variable names. * @param vars names of variables. * @see java.lang.Object#toString() */ public String toString(String[] vars) { StringBuffer s = new StringBuffer(); boolean pit; int r = length(); if (r != vars.length) { return toString(); } if (r == 0) { return s.toString(); } long vi; for (int i = r - 1; i > 0; i--) { vi = getVal(i); if (vi != 0) { s.append(vars[r - 1 - i]); if (vi != 1) { s.append("^" + vi); } pit = false; for (int j = i - 1; j >= 0; j--) { if (getVal(j) != 0) { pit = true; } } if (pit) { s.append(" * "); } } } vi = getVal(0); if (vi != 0) { s.append(vars[r - 1]); if (vi != 1) { s.append("^" + vi); } } return s.toString(); } /** * Get the string representation of the variables. * @param vars names of variables. * @return string representation of the variables. * @see java.util.Arrays#toString() */ public final static String varsToString(String[] vars) { if (vars == null) { return "null"; } StringBuffer s = new StringBuffer(); for (int i = 0; i < vars.length; i++) { s.append(vars[i]); if (i < vars.length - 1) { s.append(","); } } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { return toScript(stdVars()); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ // @Override public String toScript(String[] vars) { // Python case int r = length(); if (r != vars.length) { return toString(); } StringBuffer s = new StringBuffer(); boolean pit; long vi; for (int i = r - 1; i > 0; i--) { vi = getVal(i); if (vi != 0) { s.append(vars[r - 1 - i]); if (vi != 1) { s.append("**" + vi); } pit = false; for (int j = i - 1; j >= 0; j--) { if (getVal(j) != 0) { pit = true; } } if (pit) { s.append(" * "); } } } vi = getVal(0); if (vi != 0) { s.append(vars[r - 1]); if (vi != 1) { s.append("**" + vi); } } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "ExpVector()"; } /** * Get the variable name at index. * @param idx index of the variable * @param vars array of names of variables * @return name of variable at the given index. */ public String indexVarName(int idx, String... vars) { return vars[length() - idx - 1]; } /** * Get the array index of a variable at index. * @param idx index of the variable * @return array index of the variable. */ public int varIndex(int idx) { return length() - idx - 1; } /** * Get the index of a variable. * @param x variable name to be searched. * @param vars array of names of variables * @return index of x in vars. */ public int indexVar(String x, String... vars) { for (int i = 0; i < length(); i++) { if (x.equals(vars[i])) { return length() - i - 1; } } return -1; // not found } /** * Evaluate. * @param cf ring factory for elements of a. * @param a list of values. * @return a_1^{e_1} * ... * a_n^{e_n}. */ public > C evaluate(RingFactory cf, List a) { C c = cf.getONE(); for (int i = 0; i < length(); i++) { long ei = getVal(i); if (ei == 0L) { continue; } C ai = a.get(length() - 1 - i); if (ai.isZERO()) { return ai; } C pi = ai.power(ei); c = c.multiply(pi); } return c; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ExpVector)) { return false; } ExpVector b = (ExpVector) B; int t = this.invLexCompareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode. Optimized for small exponents, i.e. ≤ 24 and * small number of variables, i.e. ≤ 8. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { if (hash < 0) { int h = 0; int len = length(); for (int i = 0; i < len; i++) { h = (h << 3) + (int) getVal(i); } hash = h; } return hash; } /** * Returns the number of bits in the representation of this exponent vector. * @return number of bits in the representation of this ExpVector, including * sign bits. */ public long bitLength() { if (blen < 0L) { long n = 0L; for (int i = 0; i < length(); i++) { n += BigInteger.bitLength(getVal(i)); } blen = n; //System.out.println("bitLength(ExpVector) = " + blen); } return blen; } /** * Is ExpVector zero. * @return If this has all elements 0 then true is returned, else false. */ public boolean isZERO() { return (0 == this.signum()); } /** * Standard variable names. Generate standard names for variables, i.e. x0 * to x(n-1). * @return standard names. */ public String[] stdVars() { return STDVARS("x", length()); } /** * Generate variable names. Generate names for variables, i.e. prefix0 to * prefix(n-1). * @param prefix name prefix. * @return standard names. */ public String[] stdVars(String prefix) { return STDVARS(prefix, length()); } /** * Standard variable names. Generate standard names for variables, i.e. x0 * to x(n-1). * @param n size of names array * @return standard names. */ public final static String[] STDVARS(int n) { return STDVARS("x", n); } /** * Generate variable names. Generate names for variables from given prefix. * i.e. prefix0 to prefix(n-1). * @param n size of names array. * @param prefix name prefix. * @return vatiable names. */ public final static String[] STDVARS(String prefix, int n) { String[] vars = new String[n]; if (prefix == null || prefix.length() == 0) { prefix = "x"; } for (int i = 0; i < n; i++) { vars[i] = prefix + i; //(n-1-i); } return vars; } /** * ExpVector absolute value. * @param U * @return abs(U). */ public final static ExpVector EVABS(ExpVector U) { return U.abs(); } /** * ExpVector absolute value. * @return abs(this). */ public abstract ExpVector abs(); /** * ExpVector negate. * @param U * @return -U. */ public final static ExpVector EVNEG(ExpVector U) { return U.negate(); } /** * ExpVector negate. * @return -this. */ public abstract ExpVector negate(); /** * ExpVector summation. * @param U * @param V * @return U+V. */ public final static ExpVector EVSUM(ExpVector U, ExpVector V) { return U.sum(V); } /** * ExpVector summation. * @param V * @return this+V. */ public abstract ExpVector sum(ExpVector V); /** * ExpVector difference. Result may have negative entries. * @param U * @param V * @return U-V. */ public final static ExpVector EVDIF(ExpVector U, ExpVector V) { return U.subtract(V); } /** * ExpVector subtract. Result may have negative entries. * @param V * @return this-V. */ public abstract ExpVector subtract(ExpVector V); /** * ExpVector multiply by scalar. * @param s scalar * @return s*this. */ public abstract ExpVector scalarMultiply(long s); /** * ExpVector substitution. Clone and set exponent to d at position i. * @param U * @param i position. * @param d new exponent. * @return substituted ExpVector. */ public final static ExpVector EVSU(ExpVector U, int i, long d) { return U.subst(i, d); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ public ExpVector subst(int i, long d) { ExpVector V = this.copy(); //long e = V.setVal(i, d); return V; } /** * Generate a random ExpVector. * @param r length of new ExpVector. * @param k maximal degree in each exponent. * @param q density of nozero exponents. * @return random ExpVector. */ public final static ExpVector EVRAND(int r, long k, float q) { return random(r, k, q, random); } /** * Generate a random ExpVector. * @param r length of new ExpVector. * @param k maximal degree in each exponent. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return random ExpVector. */ public final static ExpVector EVRAND(int r, long k, float q, Random rnd) { return random(r, k, q, rnd); } /** * Generate a random ExpVector. * @param r length of new ExpVector. * @param k maximal degree in each exponent. * @param q density of nozero exponents. * @return random ExpVector. */ public final static ExpVector random(int r, long k, float q) { return random(r, k, q, random); } /** * Generate a random ExpVector. * @param r length of new ExpVector. * @param k maximal degree in each exponent. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return random ExpVector. */ public final static ExpVector random(int r, long k, float q, Random rnd) { long[] w = new long[r]; long e; float f; for (int i = 0; i < w.length; i++) { f = rnd.nextFloat(); if (f > q) { e = 0; } else { e = rnd.nextLong() % k; if (e < 0) { e = -e; } } w[i] = e; } return create(w); } /** * ExpVector sign. * @param U * @return 0 if U is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ public final static int EVSIGN(ExpVector U) { return U.signum(); } /** * ExpVector signum. * @return 0 if this is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ public abstract int signum(); /** * ExpVector total degree. * @param U * @return sum of all exponents. */ public final static long EVTDEG(ExpVector U) { return U.totalDeg(); } /** * ExpVector degree. * @return total degree of all exponents. */ public long degree() { return totalDeg(); } /** * ExpVector total degree. * @return sum of all exponents. */ public abstract long totalDeg(); /** * ExpVector maximal degree. * @param U * @return maximal exponent. */ public final static long EVMDEG(ExpVector U) { return U.maxDeg(); } /** * ExpVector maximal degree. * @return maximal exponent. */ public abstract long maxDeg(); /** * ExpVector minimal degree. * @param U * @return minimal exponent. */ public final static long EVMINDEG(ExpVector U) { return U.minDeg(); } /** * ExpVector minimal degree. * @return minimal exponent. */ public abstract long minDeg(); /** * ExpVector weighted degree. * @param w weights. * @param U * @return weighted sum of all exponents. */ public final static long EVWDEG(long[][] w, ExpVector U) { return U.weightDeg(w); } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ public abstract long weightDeg(long[][] w); /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ public abstract long weightDeg(long[] w); /** * ExpVector least common multiple. * @param U * @param V * @return component wise maximum of U and V. */ public final static ExpVector EVLCM(ExpVector U, ExpVector V) { return U.lcm(V); } /** * ExpVector least common multiple. * @param V * @return component wise maximum of this and V. */ public abstract ExpVector lcm(ExpVector V); /** * ExpVector greatest common divisor. * @param U * @param V * @return component wise minimum of U and V. */ public final static ExpVector EVGCD(ExpVector U, ExpVector V) { return U.gcd(V); } /** * ExpVector greatest common divisor. * @param V * @return component wise minimum of this and V. */ public abstract ExpVector gcd(ExpVector V); /** * ExpVector dependency on variables. * @param U * @return array of indices where U has positive exponents. */ public final static int[] EVDOV(ExpVector U) { return U.dependencyOnVariables(); } /** * ExpVector dependent variables. * @return number of indices where val has positive exponents. */ public abstract int dependentVariables(); /** * ExpVector dependency on variables. * @return array of indices where val has positive exponents. */ public abstract int[] dependencyOnVariables(); /** * ExpVector multiple test. Test if U is component wise greater or equal to * V. * @param U * @param V * @return true if U is a multiple of V, else false. */ public final static boolean EVMT(ExpVector U, ExpVector V) { return U.multipleOf(V); } /** * ExpVector multiple test. Test if this is component wise greater or equal * to V. * @param V * @return true if this is a multiple of V, else false. */ public abstract boolean multipleOf(ExpVector V); /** * ExpVector divides test. Test if V is component wise greater or equal to * this. * @param V * @return true if this divides V, else false. */ public boolean divides(ExpVector V) { return V.multipleOf(this); } /** * ExpVector compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(ExpVector V) { return this.invLexCompareTo(V); } /** * Inverse lexicographical compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVILCP(ExpVector U, ExpVector V) { return U.invLexCompareTo(V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invLexCompareTo(ExpVector V); /** * Inverse lexicographical compare part. Compare entries between begin and * end (-1). * @param U * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVILCP(ExpVector U, ExpVector V, int begin, int end) { return U.invLexCompareTo(V, begin, end); } /** * ExpVector inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invLexCompareTo(ExpVector V, int begin, int end); /** * Inverse graded lexicographical compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVIGLC(ExpVector U, ExpVector V) { return U.invGradCompareTo(V); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invGradCompareTo(ExpVector V); /** * Inverse graded lexicographical compare part. Compare entries between * begin and end (-1). * @param U * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVIGLC(ExpVector U, ExpVector V, int begin, int end) { return U.invGradCompareTo(V, begin, end); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invGradCompareTo(ExpVector V, int begin, int end); /** * Reverse inverse lexicographical compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVRILCP(ExpVector U, ExpVector V) { return U.revInvLexCompareTo(V); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int revInvLexCompareTo(ExpVector V); /** * Reverse inverse lexicographical compare part. Compare entries between * begin and end (-1). * @param U * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVRILCP(ExpVector U, ExpVector V, int begin, int end) { return U.revInvLexCompareTo(V, begin, end); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int revInvLexCompareTo(ExpVector V, int begin, int end); /** * Reverse inverse graded lexicographical compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVRIGLC(ExpVector U, ExpVector V) { return U.revInvGradCompareTo(V); } /** * ExpVector reverse inverse graded compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int revInvGradCompareTo(ExpVector V); /** * Reverse inverse graded lexicographical compare part. Compare entries * between begin and end (-1). * @param U * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVRIGLC(ExpVector U, ExpVector V, int begin, int end) { return U.revInvGradCompareTo(V, begin, end); } /** * ExpVector reverse inverse graded compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int revInvGradCompareTo(ExpVector V, int begin, int end); /** * Inverse total degree lexicographical compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVITDEGLC(ExpVector U, ExpVector V) { return U.invTdegCompareTo(V); } /** * ExpVector inverse total degree lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invTdegCompareTo(ExpVector V); /** * Reverse lexicographical inverse total degree compare. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVRLITDEGC(ExpVector U, ExpVector V) { return U.revLexInvTdegCompareTo(V); } /** * ExpVector reverse lexicographical inverse total degree compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int revLexInvTdegCompareTo(ExpVector V); /** * Inverse weighted lexicographical compare. * @param w weight array. * @param U * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVIWLC(long[][] w, ExpVector U, ExpVector V) { return U.invWeightCompareTo(w, V); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invWeightCompareTo(long[][] w, ExpVector V); /** * Inverse weighted lexicographical compare part. Compare entries between * begin and end (-1). * @param w weight array. * @param U * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public final static int EVIWLC(long[][] w, ExpVector U, ExpVector V, int begin, int end) { return U.invWeightCompareTo(w, V, begin, end); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public abstract int invWeightCompareTo(long[][] w, ExpVector V, int begin, int end); } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVectorByte.java000066400000000000000000000663411445075545500242620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; /** * ExpVectorByte implements exponent vectors for polynomials using arrays of * byte as storage unit. This class is used by ExpVector internally, there is no * need to use this class directly. * @see ExpVector * @author Heinz Kredel */ public final class ExpVectorByte extends ExpVector /*implements AbelianGroupElem*/{ /** * The data structure is an array of byte. */ /*package*/final byte[] val; /** * Largest byte. */ public static final long maxByte = (long) Byte.MAX_VALUE / 2; /** * Smallest byte. */ public static final long minByte = (long) Byte.MIN_VALUE / 2; /** * Constructor for ExpVector. * @param n length of exponent vector. */ public ExpVectorByte(int n) { this(new byte[n]); } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorByte(int n, int i, byte e) { this(n); val[i] = e; } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorByte(int n, int i, long e) { this(n); if (e >= maxByte || e <= minByte) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (byte) e; } /** * Internal constructor for ExpVector. Sets val. * @param v internal representation array. */ protected ExpVectorByte(byte[] v) { super(); val = v; } /** * Constructor for ExpVector. Sets val, converts from long array. * @param v long representation array. */ public ExpVectorByte(long[] v) { this(v.length); for (int i = 0; i < v.length; i++) { if (v[i] >= maxByte || v[i] <= minByte) { throw new IllegalArgumentException("exponent to large: " + v[i]); } val[i] = (byte) v[i]; } } /** * Constructor for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. */ public ExpVectorByte(String s) throws NumberFormatException { super(); // first format = (1,2,3,4,5,6,7) List exps = new ArrayList(); s = s.trim(); int b = s.indexOf('('); int e = s.indexOf(')', b + 1); String teil; int k; byte a; if (b >= 0 && e >= 0) { b++; while ((k = s.indexOf(',', b)) >= 0) { teil = s.substring(b, k); a = Byte.parseByte(teil); exps.add(Byte.valueOf(a)); b = k + 1; } if (b <= e) { teil = s.substring(b, e); a = Byte.parseByte(teil); exps.add(Byte.valueOf(a)); } int length = exps.size(); val = new byte[length]; for (int j = 0; j < length; j++) { val[j] = exps.get(j).byteValue(); } } else { // not implemented val = null; // length = -1; //Vector names = new Vector(); //vars = s; } } /** * Value of other. * @param e other ExpVector. * @return value in sub class of ExpVector. */ //@Override public static ExpVector valueOf(ExpVector e) { return new ExpVectorByte(e.getVal()); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ExpVectorByte copy() { byte[] w = new byte[val.length]; System.arraycopy(val, 0, w, 0, val.length); return new ExpVectorByte(w); } /** * Get the exponent vector. * @return val as long. */ @Override public long[] getVal() { long v[] = new long[val.length]; for (int i = 0; i < val.length; i++) { v[i] = val[i]; } return v; } /** * Get the exponent at position i. * @param i position. * @return val[i]. */ @Override public long getVal(int i) { return val[i]; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ @Override protected long setVal(int i, long e) { byte x = val[i]; if (e >= maxByte || e <= minByte) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (byte) e; hash = -1; // beware of race condition return x; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ protected byte setVal(int i, byte e) { byte x = val[i]; val[i] = e; hash = -1; // beware of race condition return x; } /** * Get the length of this exponent vector. * @return val.length. */ @Override public int length() { return val.length; } /** * Extend variables. Used e.g. in module embedding. Extend this by i * elements and set val[j] to e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorByte extend(int i, int j, long e) { byte[] w = new byte[val.length + i]; System.arraycopy(val, 0, w, i, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } if (e >= maxByte || e <= minByte) { throw new IllegalArgumentException("exponent to large: " + e); } w[j] = (byte) e; return new ExpVectorByte(w); } /** * Extend lower variables. Extend this by i lower elements and set val[j] to * e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorByte extendLower(int i, int j, long e) { byte[] w = new byte[val.length + i]; System.arraycopy(val, 0, w, 0, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } w[val.length + j] = (byte) e; return new ExpVectorByte(w); } /** * Contract variables. Used e.g. in module embedding. Contract this to len * elements. * @param i position of first element to be copied. * @param len new length. * @return contracted exponent vector. */ @Override public ExpVectorByte contract(int i, int len) { if (i + len > val.length) { throw new IllegalArgumentException("len " + len + " > val.len " + val.length); } byte[] w = new byte[len]; System.arraycopy(val, i, w, 0, len); return new ExpVectorByte(w); } /** * Reverse variables. Used e.g. in opposite rings. * @return reversed exponent vector. */ @Override public ExpVectorByte reverse() { byte[] w = new byte[val.length]; for (int i = 0; i < val.length; i++) { w[i] = val[val.length - 1 - i]; } return new ExpVectorByte(w); } /** * Reverse lower j variables. Used e.g. in opposite rings. Reverses the * first j-1 variables, the rest is unchanged. * @param j index of first variable reversed. * @return reversed exponent vector. */ @Override public ExpVectorByte reverse(int j) { if (j < 0 || j > val.length) { return this; } byte[] w = new byte[val.length]; for (int i = 0; i < j; i++) { w[i] = val[i]; } for (int i = j; i < val.length; i++) { w[i] = val[val.length + j - 1 - i]; } return new ExpVectorByte(w); } /** * Combine with ExpVector. Combine this with the other ExpVector V. * @param V the other exponent vector. * @return combined exponent vector. */ @Override public ExpVectorByte combine(ExpVector V) { if (V == null || V.length() == 0) { return this; } ExpVectorByte Vi = (ExpVectorByte) V; if (val.length == 0) { return Vi; } byte[] w = new byte[val.length + Vi.val.length]; System.arraycopy(val, 0, w, 0, val.length); System.arraycopy(Vi.val, 0, w, val.length, Vi.val.length); return new ExpVectorByte(w); } /** * Permutation of exponent vector. * @param P permutation. * @return P(e). */ @Override public ExpVectorByte permutation(List P) { byte[] w = new byte[val.length]; int j = 0; for (Integer i : P) { w[j++] = val[i]; } return new ExpVectorByte(w); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + ":byte"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ExpVectorByte)) { return false; } ExpVectorByte b = (ExpVectorByte) B; int t = this.invLexCompareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode for this exponent vector. * @see java.lang.Object#hashCode() Only for findbugs. */ @Override public int hashCode() { return super.hashCode(); } /** * ExpVector absolute value. * @return abs(this). */ @Override public ExpVectorByte abs() { byte[] u = val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { if (u[i] >= 0L) { w[i] = u[i]; } else { w[i] = (byte) (-u[i]); } } return new ExpVectorByte(w); //return EVABS(this); } /** * ExpVector negate. * @return -this. */ @Override public ExpVectorByte negate() { byte[] u = val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (byte) (-u[i]); } return new ExpVectorByte(w); // return EVNEG(this); } /** * ExpVector summation. * @param V * @return this+V. */ @Override public ExpVectorByte sum(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (byte) (u[i] + v[i]); } return new ExpVectorByte(w); // return EVSUM(this, V); } /** * ExpVector subtract. Result may have negative entries. * @param V * @return this-V. */ @Override public ExpVectorByte subtract(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (byte) (u[i] - v[i]); } return new ExpVectorByte(w); //return EVDIF(this, V); } /** * ExpVector multiply by scalar. * @param s scalar * @return s*this. */ @Override public ExpVectorByte scalarMultiply(long s) { if (s >= maxByte || s <= minByte) { throw new IllegalArgumentException("scalar to large: " + s); } byte[] u = val; byte[] w = new byte[u.length]; byte sb = (byte) s; for (int i = 0; i < u.length; i++) { w[i] = (byte) (sb * u[i]); } return new ExpVectorByte(w); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ public ExpVectorByte subst(int i, byte d) { ExpVectorByte V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ @Override public ExpVectorByte subst(int i, long d) { ExpVectorByte V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector signum. * @return 0 if this is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ @Override public int signum() { int t = 0; byte[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < 0) { return -1; } if (u[i] > 0) { t = 1; } } return t; //return EVSIGN(this); } /** * ExpVector total degree. * @return sum of all exponents. */ @Override public long totalDeg() { long t = 0; byte[] u = val; // U.val; for (int i = 0; i < u.length; i++) { t += u[i]; } return t; //return EVTDEG(this); } /** * ExpVector maximal degree. * @return maximal exponent. */ @Override public long maxDeg() { long t = 0; byte[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] > t) { t = u[i]; } } return t; //return EVMDEG(this); } /** * ExpVector minimal degree. * @return minimal exponent. */ @Override public long minDeg() { long t = Byte.MAX_VALUE; byte[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < t) { t = u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[][] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; byte[] u = val; for (int j = 0; j < w.length; j++) { long[] wj = w[j]; for (int i = 0; i < u.length; i++) { t += wj[i] * u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; byte[] u = val; for (int i = 0; i < w.length; i++) { t += w[i] * u[i]; } return t; } /** * ExpVector least common multiple. * @param V * @return component wise maximum of this and V. */ @Override public ExpVectorByte lcm(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] >= v[i] ? u[i] : v[i]); } return new ExpVectorByte(w); //return EVLCM(this, V); } /** * ExpVector greatest common divisor. * @param V * @return component wise minimum of this and V. */ @Override public ExpVectorByte gcd(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; byte[] w = new byte[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] <= v[i] ? u[i] : v[i]); } return new ExpVectorByte(w); //return EVGCD(this, V); } /** * ExpVector dependent variables. * @return number of indices where val has positive exponents. */ public int dependentVariables() { int l = 0; for (int i = 0; i < val.length; i++) { if (val[i] > 0) { l++; } } return l; } /** * ExpVector dependency on variables. * @return array of indices where val has positive exponents. */ @Override public int[] dependencyOnVariables() { byte[] u = val; int l = dependentVariables(); int[] dep = new int[l]; if (l == 0) { return dep; } int j = 0; for (int i = 0; i < u.length; i++) { if (u[i] > 0) { dep[j] = i; j++; } } return dep; } /** * ExpVector multiple test. Test if this is component wise greater or equal * to V. * @param V * @return true if this is a multiple of V, else false. */ @Override public boolean multipleOf(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; boolean t = true; for (int i = 0; i < u.length; i++) { if (u[i] < v[i]) { return false; } } return t; //return EVMT(this, V); } /** * ExpVector compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(ExpVector V) { return this.invLexCompareTo(V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; int t = 0; for (int i = 0; i < u.length; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V, int begin, int end) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = begin; i < end; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V, begin, end); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V, int begin, int end) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V, begin, end); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; int t = 0; for (int i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V, int begin, int end) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = end - 1; i >= begin; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V, begin, end); } /** * ExpVector reverse inverse graded compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V); } /** * ExpVector reverse inverse graded compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V, int begin, int end) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = end - 1; i >= begin; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= begin; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V, begin, end); } /** * ExpVector inverse total degree lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invTdegCompareTo(ExpVector V) { throw new UnsupportedOperationException("not implemented for byte ExpVector"); } /** * ExpVector reverse lexicographical inverse total degree compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revLexInvTdegCompareTo(ExpVector V) { throw new UnsupportedOperationException("not implemented for byte ExpVector"); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V, int begin, int end) { byte[] u = val; byte[] v = ((ExpVectorByte) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V, begin, end); } } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVectorInteger.java000066400000000000000000000707141445075545500247530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; /** * ExpVectorInteger implements exponent vectors for polynomials using arrays of * int as storage unit. This class is used by ExpVector internally, there is no * need to use this class directly. * @see ExpVector * @author Heinz Kredel */ public final class ExpVectorInteger extends ExpVector /*implements AbelianGroupElem*/{ /** * The data structure is an array of int. */ /*package*/final int[] val; /** * Largest integer. */ public static final long maxInt = (long) Integer.MAX_VALUE / 2; /** * Smallest integer. */ public static final long minInt = (long) Integer.MIN_VALUE / 2; /** * Constructor for ExpVector. * @param n length of exponent vector. */ public ExpVectorInteger(int n) { this(new int[n]); } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorInteger(int n, int i, int e) { this(n); val[i] = e; } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorInteger(int n, int i, long e) { this(n); if (e >= maxInt || e <= minInt) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (int) e; } /** * Internal constructor for ExpVector. Sets val. * @param v internal representation array. */ protected ExpVectorInteger(int[] v) { super(); val = v; } /** * Constructor for ExpVector. Sets val, converts from long array. * @param v long representation array. */ public ExpVectorInteger(long[] v) { this(v.length); for (int i = 0; i < v.length; i++) { if (v[i] >= maxInt || v[i] <= minInt) { throw new IllegalArgumentException("exponent to large: " + v[i]); } val[i] = (int) v[i]; } } /** * Constructor for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. */ public ExpVectorInteger(String s) throws NumberFormatException { super(); // first format = (1,2,3,4,5,6,7) List exps = new ArrayList(); s = s.trim(); int b = s.indexOf('('); int e = s.indexOf(')', b + 1); String teil; int k; int a; if (b >= 0 && e >= 0) { b++; while ((k = s.indexOf(',', b)) >= 0) { teil = s.substring(b, k); a = Integer.parseInt(teil); exps.add(Integer.valueOf(a)); b = k + 1; } if (b <= e) { teil = s.substring(b, e); a = Integer.parseInt(teil); exps.add(Integer.valueOf(a)); } int length = exps.size(); val = new int[length]; for (int j = 0; j < length; j++) { val[j] = exps.get(j).intValue(); } } else { // not implemented val = null; // length = -1; //Vector names = new Vector(); //vars = s; } } /** * Value of other. * @param e other ExpVector. * @return value in sub class of ExpVector. */ //@Override public static ExpVector valueOf(ExpVector e) { return new ExpVectorInteger(e.getVal()); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ExpVectorInteger copy() { int[] w = new int[val.length]; System.arraycopy(val, 0, w, 0, val.length); return new ExpVectorInteger(w); } /** * Get the exponent vector. * @return val as long. */ @Override public long[] getVal() { long v[] = new long[val.length]; for (int i = 0; i < val.length; i++) { v[i] = val[i]; } return v; } /** * Get the exponent at position i. * @param i position. * @return val[i]. */ @Override public long getVal(int i) { return val[i]; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ @Override protected long setVal(int i, long e) { int x = val[i]; if (e >= maxInt || e <= minInt) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (int) e; hash = -1; // beware of race condition return x; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ protected int setVal(int i, int e) { int x = val[i]; val[i] = e; hash = -1; // beware of race condition return x; } /** * Get the length of this exponent vector. * @return val.length. */ @Override public int length() { return val.length; } /** * Extend variables. Used e.g. in module embedding. Extend this by i * elements and set val[j] to e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorInteger extend(int i, int j, long e) { int[] w = new int[val.length + i]; System.arraycopy(val, 0, w, i, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } if (e >= maxInt || e <= minInt) { throw new IllegalArgumentException("exponent to large: " + e); } w[j] = (int) e; return new ExpVectorInteger(w); } /** * Extend lower variables. Extend this by i lower elements and set val[j] to * e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorInteger extendLower(int i, int j, long e) { int[] w = new int[val.length + i]; System.arraycopy(val, 0, w, 0, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } w[val.length + j] = (int) e; return new ExpVectorInteger(w); } /** * Contract variables. Used e.g. in module embedding. Contract this to len * elements. * @param i position of first element to be copied. * @param len new length. * @return contracted exponent vector. */ @Override public ExpVectorInteger contract(int i, int len) { if (i + len > val.length) { throw new IllegalArgumentException("len " + len + " > val.len " + val.length); } int[] w = new int[len]; System.arraycopy(val, i, w, 0, len); return new ExpVectorInteger(w); } /** * Reverse variables. Used e.g. in opposite rings. * @return reversed exponent vector. */ @Override public ExpVectorInteger reverse() { int[] w = new int[val.length]; for (int i = 0; i < val.length; i++) { w[i] = val[val.length - 1 - i]; } return new ExpVectorInteger(w); } /** * Reverse lower j variables. Used e.g. in opposite rings. Reverses the * first j-1 variables, the rest is unchanged. * @param j index of first variable reversed. * @return reversed exponent vector. */ @Override public ExpVectorInteger reverse(int j) { if (j < 0 || j > val.length) { return this; } int[] w = new int[val.length]; for (int i = 0; i < j; i++) { w[i] = val[i]; } // copy rest for (int i = j; i < val.length; i++) { w[i] = val[val.length + j - 1 - i]; } return new ExpVectorInteger(w); } /** * Combine with ExpVector. Combine this with the other ExpVector V. * @param V the other exponent vector. * @return combined exponent vector. */ @Override public ExpVectorInteger combine(ExpVector V) { if (V == null || V.length() == 0) { return this; } ExpVectorInteger Vi = (ExpVectorInteger) V; if (val.length == 0) { return Vi; } int[] w = new int[val.length + Vi.val.length]; System.arraycopy(val, 0, w, 0, val.length); System.arraycopy(Vi.val, 0, w, val.length, Vi.val.length); return new ExpVectorInteger(w); } /** * Permutation of exponent vector. * @param P permutation. * @return P(e). */ @Override public ExpVectorInteger permutation(List P) { int[] w = new int[val.length]; int j = 0; for (Integer i : P) { w[j++] = val[i]; } return new ExpVectorInteger(w); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + ":int"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ExpVectorInteger)) { return false; } ExpVectorInteger b = (ExpVectorInteger) B; int t = this.invLexCompareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode for this exponent vector. * @see java.lang.Object#hashCode() Only for findbugs. */ @Override public int hashCode() { return super.hashCode(); } /** * ExpVector absolute value. * @return abs(this). */ @Override public ExpVectorInteger abs() { int[] u = val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { if (u[i] >= 0L) { w[i] = u[i]; } else { w[i] = -u[i]; } } return new ExpVectorInteger(w); //return EVABS(this); } /** * ExpVector negate. * @return -this. */ @Override public ExpVectorInteger negate() { int[] u = val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { w[i] = -u[i]; } return new ExpVectorInteger(w); // return EVNEG(this); } /** * ExpVector summation. * @param V * @return this+V. */ @Override public ExpVectorInteger sum(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { w[i] = u[i] + v[i]; } return new ExpVectorInteger(w); // return EVSUM(this, V); } /** * ExpVector subtract. Result may have negative entries. * @param V * @return this-V. */ @Override public ExpVectorInteger subtract(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { w[i] = u[i] - v[i]; } return new ExpVectorInteger(w); } /** * ExpVector multiply by scalar. * @param s scalar * @return s*this. */ @Override public ExpVectorInteger scalarMultiply(long s) { if (s >= maxInt || s <= minInt) { throw new IllegalArgumentException("scalar to large: " + s); } int[] u = val; int[] w = new int[u.length]; int si = (int)s; for (int i = 0; i < u.length; i++) { w[i] = si * u[i]; } return new ExpVectorInteger(w); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ @Override public ExpVectorInteger subst(int i, long d) { ExpVectorInteger V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ public ExpVectorInteger subst(int i, int d) { ExpVectorInteger V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector signum. * @return 0 if this is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ @Override public int signum() { int t = 0; int[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < 0) { return -1; } if (u[i] > 0) { t = 1; } } return t; //return EVSIGN(this); } /** * ExpVector total degree. * @return sum of all exponents. */ @Override public long totalDeg() { long t = 0; int[] u = val; // U.val; for (int i = 0; i < u.length; i++) { t += u[i]; } return t; //return EVTDEG(this); } /** * ExpVector maximal degree. * @return maximal exponent. */ @Override public long maxDeg() { long t = 0; int[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] > t) { t = u[i]; } } return t; //return EVMDEG(this); } /** * ExpVector minimal degree. * @return minimal exponent. */ @Override public long minDeg() { long t = Integer.MAX_VALUE; int[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < t) { t = u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[][] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; int[] u = val; for (int j = 0; j < w.length; j++) { long[] wj = w[j]; for (int i = 0; i < u.length; i++) { t += wj[i] * u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; int[] u = val; for (int i = 0; i < w.length; i++) { t += w[i] * u[i]; } return t; } /** * ExpVector least common multiple. * @param V * @return component wise maximum of this and V. */ @Override public ExpVectorInteger lcm(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] >= v[i] ? u[i] : v[i]); } return new ExpVectorInteger(w); //return EVLCM(this, V); } /** * ExpVector greatest common divisor. * @param V * @return component wise minimum of this and V. */ @Override public ExpVectorInteger gcd(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int[] w = new int[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] <= v[i] ? u[i] : v[i]); } return new ExpVectorInteger(w); //return EVGCD(this, V); } /** * ExpVector dependent variables. * @return number of indices where val has positive exponents. */ public int dependentVariables() { int l = 0; for (int i = 0; i < val.length; i++) { if (val[i] > 0) { l++; } } return l; } /** * ExpVector dependency on variables. * @return array of indices where val has positive exponents. */ @Override public int[] dependencyOnVariables() { int[] u = val; int l = dependentVariables(); int[] dep = new int[l]; if (l == 0) { return dep; } int j = 0; for (int i = 0; i < u.length; i++) { if (u[i] > 0) { dep[j] = i; j++; } } return dep; } /** * ExpVector multiple test. Test if this is component wise greater or equal * to V. * @param V * @return true if this is a multiple of V, else false. */ @Override public boolean multipleOf(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; boolean t = true; for (int i = 0; i < u.length; i++) { if (u[i] < v[i]) { return false; } } return t; //return EVMT(this, V); } /** * ExpVector compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(ExpVector V) { return this.invLexCompareTo(V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; for (int i = 0; i < u.length; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V, int begin, int end) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = begin; i < end; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V, begin, end); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V, int begin, int end) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V, begin, end); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; for (int i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V, int begin, int end) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = end - 1; i >= begin; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V, begin, end); } /** * ExpVector reverse inverse graded compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V); } /** * ExpVector reverse inverse graded compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V, int begin, int end) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = end - 1; i >= begin; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= begin; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V, begin, end); } /** * ExpVector inverse total degree lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invTdegCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] < v[i]) { t = 1; break; } if (u[i] > v[i]) { t = -1; break; } } if (t == 0) { return t; } int up = 0; int vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector reverse lexicographical inverse total degree compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revLexInvTdegCompareTo(ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] < v[i]) { t = 1; break; } if (u[i] > v[i]) { t = -1; break; } } if (t == 0) { return t; } int up = 0; int vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V, int begin, int end) { int[] u = val; int[] v = ((ExpVectorInteger) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V, begin, end); } } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVectorLong.java000066400000000000000000000660401445075545500242520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * ExpVectorLong implements exponent vectors for polynomials using arrays of * long as storage unit. This class is used by ExpVector internally, there is no * need to use this class directly. * @see ExpVector * @author Heinz Kredel */ public final class ExpVectorLong extends ExpVector /*implements AbelianGroupElem*/{ /** * The data structure is an array of longs. */ /*package*/final long[] val; /** * Constructor for ExpVector. * @param n length of exponent vector. */ public ExpVectorLong(int n) { this(new long[n], true); } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorLong(int n, int i, long e) { this(new long[n], true); val[i] = e; } /** * Constructor for ExpVector. Sets val. * @param v representation array. */ public ExpVectorLong(long[] v) { this(v, false); } /** * Internal constructor for ExpVector. Sets val. * @param v internal representation array. * @param alloc true if internal representation array is newly * allocated, else false. */ protected ExpVectorLong(long[] v, boolean alloc) { super(); if (v == null) { throw new IllegalArgumentException("null val not allowed"); } if (alloc) { val = v; } else { val = Arrays.copyOf(v, v.length); // > Java-5 } } /** * Constructor for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. */ public ExpVectorLong(String s) throws NumberFormatException { this(parse(s).val, true); } /** * parser for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. * @return paresed ExpVector */ public static ExpVectorLong parse(String s) throws NumberFormatException { long[] v = null; // first format = (1,2,3,4,5,6,7) List exps = new ArrayList(); s = s.trim(); int b = s.indexOf('('); int e = s.indexOf(')', b + 1); String teil; int k; long a; if (b >= 0 && e >= 0) { b++; while ((k = s.indexOf(',', b)) >= 0) { teil = s.substring(b, k); a = Long.parseLong(teil); exps.add(Long.valueOf(a)); b = k + 1; } if (b <= e) { teil = s.substring(b, e); a = Long.parseLong(teil); exps.add(Long.valueOf(a)); } int length = exps.size(); v = new long[length]; for (int j = 0; j < length; j++) { v[j] = exps.get(j).longValue(); } } return new ExpVectorLong(v,true); } /** * Value of other. * @param e other ExpVector. * @return value in sub class of ExpVector. */ //@Override public static ExpVector valueOf(ExpVector e) { return new ExpVectorLong(e.getVal()); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ExpVectorLong copy() { long[] w = new long[val.length]; System.arraycopy(val, 0, w, 0, val.length); return new ExpVectorLong(w, true); } /** * Get the exponent vector. * @return val. */ @Override public long[] getVal() { long[] w = new long[val.length]; System.arraycopy(val, 0, w, 0, val.length); return w; //return val; } /** * Get the exponent at position i. * @param i position. * @return val[i]. */ @Override public long getVal(int i) { return val[i]; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ @Override protected long setVal(int i, long e) { long x = val[i]; val[i] = e; hash = -1; // beware of race condition return x; } /** * Get the length of this exponent vector. * @return val.length. */ @Override public int length() { return val.length; } /** * Extend variables. Used e.g. in module embedding. Extend this by i * elements and set val[j] to e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorLong extend(int i, int j, long e) { long[] w = new long[val.length + i]; System.arraycopy(val, 0, w, i, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } w[j] = e; return new ExpVectorLong(w, true); } /** * Extend lower variables. Extend this by i lower elements and set val[j] to * e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorLong extendLower(int i, int j, long e) { long[] w = new long[val.length + i]; System.arraycopy(val, 0, w, 0, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } w[val.length + j] = e; return new ExpVectorLong(w, true); } /** * Contract variables. Used e.g. in module embedding. Contract this to len * elements. * @param i position of first element to be copied. * @param len new length. * @return contracted exponent vector. */ @Override public ExpVectorLong contract(int i, int len) { if (i + len > val.length) { throw new IllegalArgumentException("len " + len + " > val.len " + val.length); } long[] w = new long[len]; System.arraycopy(val, i, w, 0, len); return new ExpVectorLong(w, true); } /** * Reverse variables. Used e.g. in opposite rings. * @return reversed exponent vector. */ @Override public ExpVectorLong reverse() { long[] w = new long[val.length]; for (int i = 0; i < val.length; i++) { w[i] = val[val.length - 1 - i]; } return new ExpVectorLong(w, true); } /** * Reverse lower j variables. Used e.g. in opposite rings. Reverses the * first j-1 variables, the rest is unchanged. * @param j index of first variable reversed. * @return reversed exponent vector. */ @Override public ExpVectorLong reverse(int j) { if (j < 0 || j > val.length) { return this; } long[] w = new long[val.length]; // copy first for (int i = 0; i < j; i++) { w[i] = val[i]; } // reverse rest for (int i = j; i < val.length; i++) { w[i] = val[val.length + j - 1 - i]; } //System.out.println("val = " + Arrays.toString(val)); //System.out.println("w = " + Arrays.toString(w)); return new ExpVectorLong(w, true); } /** * Reverse upper j variables. Reverses the last j-1 variables, the rest is * unchanged. * @param j index of first variable not reversed. * @return reversed exponent vector. */ public ExpVectorLong reverseUpper(int j) { if (j < 0 || j > val.length) { return this; } long[] w = new long[val.length]; for (int i = 0; i < j; i++) { w[i] = val[j - 1 - i]; } // copy rest for (int i = j; i < val.length; i++) { w[i] = val[i]; } return new ExpVectorLong(w, true); } /** * Combine with ExpVector. Combine this with the other ExpVector V. * @param V the other exponent vector. * @return combined exponent vector. */ @Override public ExpVectorLong combine(ExpVector V) { if (V == null || V.length() == 0) { return this; } ExpVectorLong Vl = (ExpVectorLong) V; if (val.length == 0) { return Vl; } long[] w = new long[val.length + Vl.val.length]; System.arraycopy(val, 0, w, 0, val.length); System.arraycopy(Vl.val, 0, w, val.length, Vl.val.length); return new ExpVectorLong(w, true); } /** * Permutation of exponent vector. * @param P permutation. * @return P(e). */ @Override public ExpVectorLong permutation(List P) { long[] w = new long[val.length]; int j = 0; for (Integer i : P) { w[j++] = val[i]; } return new ExpVectorLong(w, true); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + ":long"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ExpVectorLong)) { return false; } ExpVectorLong b = (ExpVectorLong) B; int t = this.invLexCompareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode for this exponent vector. * @see java.lang.Object#hashCode() Only for findbugs. */ @Override public int hashCode() { return super.hashCode(); } /** * ExpVector absolute value. * @return abs(this). */ @Override public ExpVectorLong abs() { long[] u = val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { if (u[i] >= 0L) { w[i] = u[i]; } else { w[i] = -u[i]; } } return new ExpVectorLong(w, true); } /** * ExpVector negate. * @return -this. */ @Override public ExpVectorLong negate() { long[] u = val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = -u[i]; } return new ExpVectorLong(w, true); } /** * ExpVector summation. * @param V * @return this+V. */ @Override public ExpVectorLong sum(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = u[i] + v[i]; } return new ExpVectorLong(w, true); } /** * ExpVector subtract. Result may have negative entries. * @param V * @return this-V. */ @Override public ExpVectorLong subtract(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = u[i] - v[i]; } return new ExpVectorLong(w, true); } /** * ExpVector multiply by scalar. * @param s scalar * @return s*this. */ @Override public ExpVectorLong scalarMultiply(long s) { long[] u = val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = s * u[i]; } return new ExpVectorLong(w, true); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ @Override public ExpVectorLong subst(int i, long d) { ExpVectorLong V = this.copy(); //long e = V.setVal(i, d); return V; } /** * ExpVector signum. * @return 0 if this is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ @Override public int signum() { int t = 0; long[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < 0) { return -1; } if (u[i] > 0) { t = 1; } } return t; } /** * ExpVector total degree. * @return sum of all exponents. */ @Override public long totalDeg() { long t = 0; long[] u = val; // U.val; for (int i = 0; i < u.length; i++) { t += u[i]; } return t; } /** * ExpVector maximal degree. * @return maximal exponent. */ @Override public long maxDeg() { long t = 0; long[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] > t) { t = u[i]; } } return t; } /** * ExpVector minimal degree. * @return minimal exponent. */ @Override public long minDeg() { long t = Long.MAX_VALUE; long[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < t) { t = u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[][] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; long[] u = val; for (int j = 0; j < w.length; j++) { long[] wj = w[j]; for (int i = 0; i < u.length; i++) { t += wj[i] * u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; long[] u = val; for (int i = 0; i < w.length; i++) { t += w[i] * u[i]; } return t; } /** * ExpVector least common multiple. * @param V * @return component wise maximum of this and V. */ @Override public ExpVectorLong lcm(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] >= v[i] ? u[i] : v[i]); } return new ExpVectorLong(w, true); } /** * ExpVector greatest common divisor. * @param V * @return component wise minimum of this and V. */ @Override public ExpVectorLong gcd(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; long[] w = new long[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] <= v[i] ? u[i] : v[i]); } return new ExpVectorLong(w, true); } /** * ExpVector dependent variables. * @return number of indices where val has positive exponents. */ public int dependentVariables() { int l = 0; for (int i = 0; i < val.length; i++) { if (val[i] > 0) { l++; } } return l; } /** * ExpVector dependency on variables. * @return array of indices where val has positive exponents. */ @Override public int[] dependencyOnVariables() { long[] u = val; int l = dependentVariables(); int[] dep = new int[l]; if (l == 0) { return dep; } int j = 0; for (int i = 0; i < u.length; i++) { if (u[i] > 0) { dep[j] = i; j++; } } return dep; } /** * ExpVector multiple test. Test if this is component wise greater or equal * to V. * @param V * @return true if this is a multiple of V, else false. */ @Override public boolean multipleOf(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; for (int i = 0; i < u.length; i++) { if (u[i] < v[i]) { return false; } } return true; } /** * ExpVector compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(ExpVector V) { return this.invLexCompareTo(V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; for (int i = 0; i < u.length; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; } /** * ExpVector inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V, int begin, int end) { long[] u = val; long[] v = ((ExpVectorLong) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = begin; i < end; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V, int begin, int end) { long[] u = val; long[] v = ((ExpVectorLong) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; for (int i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V, int begin, int end) { long[] u = val; long[] v = ((ExpVectorLong) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = end - 1; i >= begin; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; } /** * ExpVector reverse inverse graded compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector reverse inverse graded compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V, int begin, int end) { long[] u = val; long[] v = ((ExpVectorLong) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = end - 1; i >= begin; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= begin; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector inverse total degree lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invTdegCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] < v[i]) { t = 1; break; } if (u[i] > v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector reverse lexicographical inverse total degree compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revLexInvTdegCompareTo(ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] < v[i]) { t = 1; break; } if (u[i] > v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V) { long[] u = val; long[] v = ((ExpVectorLong) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V, int begin, int end) { long[] u = val; long[] v = ((ExpVectorLong) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; } } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVectorPair.java000066400000000000000000000043561445075545500242500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; /** * ExpVectorPair * implements pairs of exponent vectors for S-polynomials. * Objects of this class are immutable. * @author Heinz Kredel */ public class ExpVectorPair implements Serializable { private final ExpVector e1; private final ExpVector e2; /** * Constructors for ExpVectorPair. * @param e first part. * @param f second part. */ public ExpVectorPair(ExpVector e, ExpVector f) { e1 = e; e2 = f; } /** * @return first part. */ public ExpVector getFirst() { return e1; } /** * @return second part. */ public ExpVector getSecond() { return e2; } /** * @return total degree of both parts. */ public long totalDeg() { return e1.totalDeg() + e2.totalDeg(); } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("ExpVectorPair["); s.append(e1.toString()); s.append(","); s.append(e2.toString()); s.append("]"); return s.toString(); } /** * equals. * @param B other. * @return true, if this == b, else false. */ @Override public boolean equals(Object B) { if ( ! (B instanceof ExpVectorPair) ) return false; return equals( (ExpVectorPair)B ); } /** * equals. * @param b other. * @return true, if this == b, else false. */ public boolean equals(ExpVectorPair b) { boolean t = e1.equals( b.getFirst() ); t = t && e2.equals( b.getSecond() ); return t; } /** hash code. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (e1.hashCode() << 16) + e2.hashCode(); } /** * isMultiple. * @param p other. * @return true, if this is a multiple of b, else false. */ public boolean isMultiple(ExpVectorPair p) { boolean w = e1.multipleOf( p.getFirst() ); if ( !w ) { return w; } w = e2.multipleOf( p.getSecond() ); if ( !w ) { return w; } return true; } } java-algebra-system-2.7.200/src/edu/jas/poly/ExpVectorShort.java000066400000000000000000000667261445075545500244650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; /** * ExpVectorShort implements exponent vectors for polynomials using arrays of * short as storage unit. This class is used by ExpVector internally, there is * no need to use this class directly. * @see ExpVector * @author Heinz Kredel */ public final class ExpVectorShort extends ExpVector /*implements AbelianGroupElem*/{ /** * The data structure is an array of short. */ /*package*/final short[] val; /** * Largest short. */ public static final long maxShort = (long) Short.MAX_VALUE / 2; /** * Smallest short. */ public static final long minShort = (long) Short.MIN_VALUE / 2; /** * Constructor for ExpVector. * @param n length of exponent vector. */ public ExpVectorShort(int n) { this(new short[n]); } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorShort(int n, int i, short e) { this(n); val[i] = e; } /** * Constructor for ExpVector. Sets exponent i to e. * @param n length of exponent vector. * @param i index of exponent to be set. * @param e exponent to be set. */ public ExpVectorShort(int n, int i, long e) { this(n); if (e >= maxShort || e <= minShort) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (short) e; } /** * Internal constructor for ExpVector. Sets val. * @param v internal representation array. */ protected ExpVectorShort(short[] v) { super(); val = v; } /** * Constructor for ExpVector. Sets val, converts from long array. * @param v long representation array. */ public ExpVectorShort(long[] v) { this(v.length); for (int i = 0; i < v.length; i++) { if (v[i] >= maxShort || v[i] <= minShort) { throw new IllegalArgumentException("exponent to large: " + v[i]); } val[i] = (short) v[i]; } } /** * Constructor for ExpVector. Converts a String representation to an * ExpVector. Accepted format = (1,2,3,4,5,6,7). * @param s String representation. */ public ExpVectorShort(String s) throws NumberFormatException { super(); // first format = (1,2,3,4,5,6,7) List exps = new ArrayList(); s = s.trim(); int b = s.indexOf('('); int e = s.indexOf(')', b + 1); String teil; int k; short a; if (b >= 0 && e >= 0) { b++; while ((k = s.indexOf(',', b)) >= 0) { teil = s.substring(b, k); a = Short.parseShort(teil); exps.add(Short.valueOf(a)); b = k + 1; } if (b <= e) { teil = s.substring(b, e); a = Short.parseShort(teil); exps.add(Short.valueOf(a)); } int length = exps.size(); val = new short[length]; for (int j = 0; j < length; j++) { val[j] = exps.get(j).shortValue(); } } else { // not implemented val = null; // length = -1; //Vector names = new Vector(); //vars = s; } } /** * Value of other. * @param e other ExpVector. * @return value in sub class of ExpVector. */ //@Override public static ExpVector valueOf(ExpVector e) { return new ExpVectorShort(e.getVal()); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public ExpVectorShort copy() { short[] w = new short[val.length]; System.arraycopy(val, 0, w, 0, val.length); return new ExpVectorShort(w); } /** * Get the exponent vector. * @return val as long. */ @Override public long[] getVal() { long v[] = new long[val.length]; for (int i = 0; i < val.length; i++) { v[i] = val[i]; } return v; } /** * Get the exponent at position i. * @param i position. * @return val[i]. */ @Override public long getVal(int i) { return val[i]; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ @Override protected long setVal(int i, long e) { short x = val[i]; if (e >= maxShort || e <= minShort) { throw new IllegalArgumentException("exponent to large: " + e); } val[i] = (short) e; hash = -1; // beware of race condition return x; } /** * Set the exponent at position i to e. * @param i * @param e * @return old val[i]. */ protected short setVal(int i, short e) { short x = val[i]; val[i] = e; hash = -1; // beware of race condition return x; } /** * Get the length of this exponent vector. * @return val.length. */ @Override public int length() { return val.length; } /** * Extend variables. Used e.g. in module embedding. Extend this by i * elements and set val[j] to e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorShort extend(int i, int j, long e) { short[] w = new short[val.length + i]; System.arraycopy(val, 0, w, i, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } if (e >= maxShort || e <= minShort) { throw new IllegalArgumentException("exponent to large: " + e); } w[j] = (short) e; return new ExpVectorShort(w); } /** * Extend lower variables. Extend this by i lower elements and set val[j] to * e. * @param i number of elements to extend. * @param j index of element to be set. * @param e new exponent for val[j]. * @return extended exponent vector. */ @Override public ExpVectorShort extendLower(int i, int j, long e) { short[] w = new short[val.length + i]; System.arraycopy(val, 0, w, 0, val.length); if (j >= i) { throw new IllegalArgumentException("i " + i + " <= j " + j + " invalid"); } w[val.length + j] = (short) e; return new ExpVectorShort(w); } /** * Contract variables. Used e.g. in module embedding. Contract this to len * elements. * @param i position of first element to be copied. * @param len new length. * @return contracted exponent vector. */ @Override public ExpVectorShort contract(int i, int len) { if (i + len > val.length) { throw new IllegalArgumentException("len " + len + " > val.len " + val.length); } short[] w = new short[len]; System.arraycopy(val, i, w, 0, len); return new ExpVectorShort(w); } /** * Reverse variables. Used e.g. in opposite rings. * @return reversed exponent vector. */ @Override public ExpVectorShort reverse() { short[] w = new short[val.length]; for (int i = 0; i < val.length; i++) { w[i] = val[val.length - 1 - i]; } return new ExpVectorShort(w); } /** * Reverse lower j variables. Used e.g. in opposite rings. Reverses the * first j-1 variables, the rest is unchanged. * @param j index of first variable reversed. * @return reversed exponent vector. */ @Override public ExpVectorShort reverse(int j) { if (j < 0 || j > val.length) { return this; } short[] w = new short[val.length]; for (int i = 0; i < j; i++) { w[i] = val[i]; } // copy rest for (int i = j; i < val.length; i++) { w[i] = val[val.length + j - 1 - i]; } return new ExpVectorShort(w); } /** * Combine with ExpVector. Combine this with the other ExpVector V. * @param V the other exponent vector. * @return combined exponent vector. */ @Override public ExpVectorShort combine(ExpVector V) { if (V == null || V.length() == 0) { return this; } ExpVectorShort Vi = (ExpVectorShort) V; if (val.length == 0) { return Vi; } short[] w = new short[val.length + Vi.val.length]; System.arraycopy(val, 0, w, 0, val.length); System.arraycopy(Vi.val, 0, w, val.length, Vi.val.length); return new ExpVectorShort(w); } /** * Permutation of exponent vector. * @param P permutation. * @return P(e). */ @Override public ExpVectorShort permutation(List P) { short[] w = new short[val.length]; int j = 0; for (Integer i : P) { w[j++] = val[i]; } return new ExpVectorShort(w); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { return super.toString() + ":short"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof ExpVectorShort)) { return false; } ExpVectorShort b = (ExpVectorShort) B; int t = this.invLexCompareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode for this exponent vector. * @see java.lang.Object#hashCode() Only for findbugs. */ @Override public int hashCode() { return super.hashCode(); } /** * ExpVector absolute value. * @return abs(this). */ @Override public ExpVectorShort abs() { short[] u = val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { if (u[i] >= 0L) { w[i] = u[i]; } else { w[i] = (short) (-u[i]); } } return new ExpVectorShort(w); //return EVABS(this); } /** * ExpVector negate. * @return -this. */ @Override public ExpVectorShort negate() { short[] u = val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (short) (-u[i]); } return new ExpVectorShort(w); // return EVNEG(this); } /** * ExpVector summation. * @param V * @return this+V. */ @Override public ExpVectorShort sum(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (short) (u[i] + v[i]); } return new ExpVectorShort(w); // return EVSUM(this, V); } /** * ExpVector subtract. Result may have negative entries. * @param V * @return this-V. */ @Override public ExpVectorShort subtract(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (short) (u[i] - v[i]); } return new ExpVectorShort(w); //return EVDIF(this, V); } /** * ExpVector multiply by scalar. * @param s scalar * @return s*this. */ @Override public ExpVectorShort scalarMultiply(long s) { if (s >= maxShort || s <= minShort) { throw new IllegalArgumentException("scalar to large: " + s); } short[] u = val; short[] w = new short[u.length]; short ss = (short) s; for (int i = 0; i < u.length; i++) { w[i] = (short) (ss * u[i]); } return new ExpVectorShort(w); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ public ExpVectorShort subst(int i, short d) { ExpVectorShort V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector substitution. Clone and set exponent to d at position i. * @param i position. * @param d new exponent. * @return substituted ExpVector. */ @Override public ExpVectorShort subst(int i, long d) { ExpVectorShort V = this.copy(); //long e = V.setVal(i, d); return V; //return EVSU(this, i, d); } /** * ExpVector signum. * @return 0 if this is zero, -1 if some entry is negative, 1 if no entry is * negative and at least one entry is positive. */ @Override public int signum() { int t = 0; short[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < 0) { return -1; } if (u[i] > 0) { t = 1; } } return t; //return EVSIGN(this); } /** * ExpVector total degree. * @return sum of all exponents. */ @Override public long totalDeg() { long t = 0; short[] u = val; // U.val; for (int i = 0; i < u.length; i++) { t += u[i]; } return t; //return EVTDEG(this); } /** * ExpVector maximal degree. * @return maximal exponent. */ @Override public long maxDeg() { long t = 0; short[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] > t) { t = u[i]; } } return t; //return EVMDEG(this); } /** * ExpVector minimal degree. * @return minimal exponent. */ @Override public long minDeg() { long t = Short.MAX_VALUE; short[] u = val; for (int i = 0; i < u.length; i++) { if (u[i] < t) { t = u[i]; } } return t; } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[][] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; short[] u = val; for (int j = 0; j < w.length; j++) { long[] wj = w[j]; for (int i = 0; i < u.length; i++) { t += wj[i] * u[i]; } } return t; //return EVWDEG( w, this ); } /** * ExpVector weighted degree. * @param w weights. * @return weighted sum of all exponents. */ @Override public long weightDeg(long[] w) { if (w == null || w.length == 0) { return totalDeg(); // assume weight 1 } long t = 0; short[] u = val; for (int i = 0; i < w.length; i++) { t += w[i] * u[i]; } return t; } /** * ExpVector least common multiple. * @param V * @return component wise maximum of this and V. */ @Override public ExpVectorShort lcm(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] >= v[i] ? u[i] : v[i]); } return new ExpVectorShort(w); //return EVLCM(this, V); } /** * ExpVector greatest common divisor. * @param V * @return component wise minimum of this and V. */ @Override public ExpVectorShort gcd(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; short[] w = new short[u.length]; for (int i = 0; i < u.length; i++) { w[i] = (u[i] <= v[i] ? u[i] : v[i]); } return new ExpVectorShort(w); //return EVGCD(this, V); } /** * ExpVector dependent variables. * @return number of indices where val has positive exponents. */ public int dependentVariables() { int l = 0; for (int i = 0; i < val.length; i++) { if (val[i] > 0) { l++; } } return l; } /** * ExpVector dependency on variables. * @return array of indices where val has positive exponents. */ @Override public int[] dependencyOnVariables() { short[] u = val; int l = dependentVariables(); int[] dep = new int[l]; if (l == 0) { return dep; } int j = 0; for (int i = 0; i < u.length; i++) { if (u[i] > 0) { dep[j] = i; j++; } } return dep; } /** * ExpVector multiple test. Test if this is component wise greater or equal * to V. * @param V * @return true if this is a multiple of V, else false. */ @Override public boolean multipleOf(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; boolean t = true; for (int i = 0; i < u.length; i++) { if (u[i] < v[i]) { return false; } } return t; //return EVMT(this, V); } /** * ExpVector compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(ExpVector V) { return this.invLexCompareTo(V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; int t = 0; for (int i = 0; i < u.length; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V); } /** * ExpVector inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invLexCompareTo(ExpVector V, int begin, int end) { short[] u = val; short[] v = ((ExpVectorShort) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = begin; i < end; i++) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVILCP(this, V, begin, end); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V); } /** * ExpVector inverse graded lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invGradCompareTo(ExpVector V, int begin, int end) { short[] u = val; short[] v = ((ExpVectorShort) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVIGLC(this, V, begin, end); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; int t = 0; for (int i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V); } /** * ExpVector reverse inverse lexicographical compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvLexCompareTo(ExpVector V, int begin, int end) { short[] u = val; short[] v = ((ExpVectorShort) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; for (int i = end - 1; i >= begin; i--) { if (u[i] > v[i]) return 1; if (u[i] < v[i]) return -1; } return t; //return EVRILCP(this, V, begin, end); } /** * ExpVector reverse inverse graded compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; int t = 0; int i; for (i = u.length - 1; i >= 0; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= 0; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V); } /** * ExpVector reverse inverse graded compareTo. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revInvGradCompareTo(ExpVector V, int begin, int end) { short[] u = val; short[] v = ((ExpVectorShort) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = end - 1; i >= begin; i--) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } long up = 0; long vp = 0; for (int j = i; j >= begin; j--) { up += u[j]; vp += v[j]; } if (up > vp) { t = 1; } else { if (up < vp) { t = -1; } } return t; //return EVRIGLC(this, V, begin, end); } /** * ExpVector inverse total degree lexicographical compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invTdegCompareTo(ExpVector V) { throw new UnsupportedOperationException("not implemented for short ExpVector"); } /** * ExpVector reverse lexicographical inverse total degree compareTo. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int revLexInvTdegCompareTo(ExpVector V) { throw new UnsupportedOperationException("not implemented for short ExpVector"); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V) { short[] u = val; short[] v = ((ExpVectorShort) V).val; int t = 0; int i; for (i = 0; i < u.length; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < u.length; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V); } /** * ExpVector inverse weighted lexicographical compareTo. * @param w weight array. * @param V * @param begin * @param end * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int invWeightCompareTo(long[][] w, ExpVector V, int begin, int end) { short[] u = val; short[] v = ((ExpVectorShort) V).val; if (begin < 0) { begin = 0;; } if (end >= val.length) { end = val.length; } int t = 0; int i; for (i = begin; i < end; i++) { if (u[i] > v[i]) { t = 1; break; } if (u[i] < v[i]) { t = -1; break; } } if (t == 0) { return t; } for (int k = 0; k < w.length; k++) { long[] wk = w[k]; long up = 0; long vp = 0; for (int j = i; j < end; j++) { up += wk[j] * u[j]; vp += wk[j] * v[j]; } if (up > vp) { return 1; } else if (up < vp) { return -1; } } return t; //return EVIWLC(w, this, V, begin, end); } } java-algebra-system-2.7.200/src/edu/jas/poly/GenExteriorPolynomial.java000066400000000000000000001412031445075545500260050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PreemptingException; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; import edu.jas.structure.UnaryFunctor; /** * GenExteriorPolynomial generic polynomials implementing RingElem. * Antisymmetric polynomials (in fact vectors) over C. Objects of this class are * intended to be immutable. The implementation is based on TreeMap respectively * SortedMap from index lists to coefficients. Only the coefficients are modeled * with generic types, the "exponents" are fixed to IndexList. C can also be a * non integral domain, e.g. a ModInteger, i.e. it may contain zero divisors, * since multiply() does check for zero coefficients and index lists. * @see "masnc.DIPE.mi#EIVEPR from SAC2/MAS" * @param coefficient type * @author Heinz Kredel */ public final class GenExteriorPolynomial> implements RingElem>, Iterable> { /** * The factory for the polynomial ring. */ public final GenExteriorPolynomialRing ring; /** * The data structure for polynomials. */ final SortedMap val; // do not change to TreeMap private static final Logger logger = LogManager.getLogger(GenExteriorPolynomial.class); private static final boolean debug = logger.isDebugEnabled(); // protected GenExteriorPolynomial() { ring = null; val = null; } // don't use /** * Private constructor for GenExteriorPolynomial. * @param r polynomial ring factory. * @param t TreeMap with correct ordering. */ private GenExteriorPolynomial(GenExteriorPolynomialRing r, TreeMap t) { ring = r; val = t; if (ring.checkPreempt) { if (Thread.currentThread().isInterrupted()) { logger.debug("throw PreemptingException"); throw new PreemptingException(); } } } /** * Constructor for zero GenExteriorPolynomial. * @param r polynomial ring factory. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r) { this(r, new TreeMap(r.ixfac.getDescendComparator())); } /** * Constructor for GenExteriorPolynomial c * xe. * @param r polynomial ring factory. * @param c coefficient. * @param e word. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r, C c, IndexList e) { this(r); if (!c.isZERO() && !e.isZERO()) { val.put(e, c); } } /** * Constructor for GenExteriorPolynomial c * x0. * @param r polynomial ring factory. * @param c coefficient. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r, C c) { this(r, c, r.wone); } /** * Constructor for GenExteriorPolynomial xe. * @param r polynomial ring factory. * @param e index list. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r, IndexList e) { this(r, r.coFac.getONE(), e); } /** * Constructor for GenExteriorPolynomial xe. * @param r polynomial ring factory. * @param e exponent vector. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r, ExpVector e) { this(r, r.coFac.getONE(), r.ixfac.valueOf(e)); } /** * Constructor for GenExteriorPolynomial c * xe. * @param r polynomial ring factory. * @param c coefficient. * @param e exponent vector. */ public GenExteriorPolynomial(GenExteriorPolynomialRing r, C c, ExpVector e) { this(r, c, r.ixfac.valueOf(e)); } /** * Constructor for GenExteriorPolynomial. * @param r polynomial ring factory. * @param v the SortedMap of some other polynomial. */ protected GenExteriorPolynomial(GenExteriorPolynomialRing r, SortedMap v) { this(r); val.putAll(v); // assume no zero coefficients and index lists } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public GenExteriorPolynomialRing factory() { return ring; } /** * Copy this GenExteriorPolynomial. * @return copy of this. */ public GenExteriorPolynomial copy() { return new GenExteriorPolynomial(ring, this.val); } /** * Length of GenExteriorPolynomial. * @return number of coefficients of this GenExteriorPolynomial. */ public int length() { return val.size(); } /** * IndexList to coefficient map of GenExteriorPolynomial. * @return val as unmodifiable SortedMap. */ public SortedMap getMap() { // return val; return Collections. unmodifiableSortedMap(val); } /** * Put a IndexList to coefficient entry into the internal map of this * GenExteriorPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param c coefficient. * @param e index list. */ public void doPutToMap(IndexList e, C c) { if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, c); } } if (!c.isZERO() && !e.isZERO()) { val.put(e, c); } } /** * Remove a IndexList to coefficient entry from the internal map of this * GenExteriorPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param e IndexList. * @param c expected coefficient, null for ignore. */ public void doRemoveFromMap(IndexList e, C c) { C b = val.remove(e); if (debug) { if (c == null) { // ignore b return; } if (!c.equals(b)) { logger.error("map entry wrong {} to {} old {}", e, c, b); } } } /** * Put an a sorted map of index list to coefficients into the internal map * of this GenExteriorPolynomial. Note: Do not use this method unless * you are constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param vals sorted map of index list and coefficients. */ public void doPutToMap(SortedMap vals) { for (Map.Entry me : vals.entrySet()) { IndexList e = me.getKey(); if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, me.getValue()); } } C c = me.getValue(); if (!c.isZERO() && !e.isZERO()) { val.put(e, c); } } } /** * String representation of GenExteriorPolynomial. * @see java.lang.Object#toString() */ @Override public String toString() { if (isZERO()) { return "0"; } if (isONE()) { return "1"; } StringBuffer s = new StringBuffer(); if (val.size() > 1) { s.append("( "); } boolean parenthesis = false; boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } IndexList e = m.getKey(); if (!c.isONE() || e.isONE()) { if (parenthesis) { s.append("( "); } String cs = c.toString(); if (cs.indexOf("+") >= 0 || cs.indexOf("-") >= 0) { s.append("( " + cs + " )"); } else { s.append(cs); } if (parenthesis) { s.append(" )"); } //if (!e.isONE()) { // s.append(" "); //} } s.append(" "); s.append(e.toString()); } if (val.size() > 1) { s.append(" )"); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { if (isZERO()) { return "0"; } if (isONE()) { return "1"; } StringBuffer s = new StringBuffer(); if (val.size() > 1) { s.append("( "); } final boolean parenthesis = false; boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } IndexList e = m.getKey(); if (!c.isONE() || e.isONE()) { if (parenthesis) { s.append("( "); } String cs = c.toScript(); if (cs.indexOf("+") >= 0 || cs.indexOf("-") >= 0) { s.append("( " + cs + " )"); } else { s.append(cs); } if (parenthesis) { s.append(" )"); } if (!e.isONE()) { s.append(" * "); } } s.append(e.toScript()); } if (val.size() > 1) { s.append(" )"); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Is GenExteriorPolynomial<C> zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return (val.size() == 0); } /** * Is GenExteriorPolynomial<C> one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return c.isONE(); } /** * Is GenExteriorPolynomial<C> a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return c.isUnit(); } /** * Is GenExteriorPolynomial<C> a constant. * @return If this is a constant polynomial then true is returned, else * false. */ public boolean isConstant() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return true; } /** * Is GenExteriorPolynomial<C> homogeneous. * @return true, if this is homogeneous, else false. */ public boolean isHomogeneous() { if (val.size() <= 1) { return true; } long deg = -1; for (IndexList e : val.keySet()) { if (deg < 0) { deg = e.degree(); } else if (deg != e.degree()) { return false; } } return true; } /** * k-form part. * @param k requested k-form part. * @return k-form part of given degree of this. */ public GenExteriorPolynomial form(long k) { return homogeneousPart(k); } /** * Homogeneous part. * @param tdeg requested degree of part. * @return polynomial part of given degree. */ public GenExteriorPolynomial homogeneousPart(long tdeg) { if (isZERO()) { return this; } GenExteriorPolynomial h = ring.getZERO().copy(); SortedMap hv = h.val; for (Map.Entry me : val.entrySet()) { IndexList e = me.getKey(); C y = me.getValue(); // assert y != null if (e.degree() != tdeg) { continue; } else { hv.put(e, y); } } return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof GenExteriorPolynomial)) { return false; } GenExteriorPolynomial a = (GenExteriorPolynomial) B; return this.compareTo(a) == 0; } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = (ring.hashCode() << 27); h += val.hashCode(); return h; } /** * GenExteriorPolynomial comparison. * @param b GenExteriorPolynomial. * @return sign(this-b). */ public int compareTo(GenExteriorPolynomial b) { if (b == null) { return 1; } SortedMap av = this.val; SortedMap bv = b.val; Iterator> ai = av.entrySet().iterator(); Iterator> bi = bv.entrySet().iterator(); int s = 0; int c = 0; while (ai.hasNext() && bi.hasNext()) { Map.Entry aie = ai.next(); Map.Entry bie = bi.next(); IndexList ae = aie.getKey(); IndexList be = bie.getKey(); s = ae.compareTo(be); //System.out.println("s = " + s + ", " + ae + ", " +be); if (s != 0) { return s; } //if (c == 0) { // ?? C ac = aie.getValue(); //av.get(ae); C bc = bie.getValue(); //bv.get(be); c = ac.compareTo(bc); //} } if (ai.hasNext()) { return 1; } if (bi.hasNext()) { return -1; } // now all keys are equal return c; } /** * GenExteriorPolynomial signum. * @return sign(ldcf(this)). */ public int signum() { if (this.isZERO()) { return 0; } IndexList t = val.firstKey(); C c = val.get(t); return c.signum(); } /** * Number of variables. * @return ring.ixfac.length(). */ public int numberOfVariables() { return ring.ixfac.length(); // some times } /** * Leading monomial. * @return first map entry. */ public Map.Entry leadingMonomial() { if (val.size() == 0) return null; Iterator> ai = val.entrySet().iterator(); return ai.next(); } /** * Leading index list. * @return first highest index list. */ public IndexList leadingIndexList() { if (val.size() == 0) { return ring.wone; // null? needs changes? } return val.firstKey(); } /** * Trailing index list. * @return last lowest index list. */ public IndexList trailingIndexList() { if (val.size() == 0) { return ring.wone; // or null ?; } return val.lastKey(); } /** * Leading base coefficient. * @return first coefficient. */ public C leadingBaseCoefficient() { if (val.size() == 0) { return ring.coFac.getZERO(); } return val.get(val.firstKey()); } /** * Trailing base coefficient. * @return coefficient of constant term. */ public C trailingBaseCoefficient() { C c = val.get(ring.wone); if (c == null) { return ring.coFac.getZERO(); } return c; } /** * Coefficient. * @param e index list. * @return coefficient for given index list. */ public C coefficient(IndexList e) { C c = val.get(e); if (c == null) { c = ring.coFac.getZERO(); } return c; } /** * Reductum. * @return this - leading monomial. */ public GenExteriorPolynomial reductum() { if (val.size() <= 1) { return ring.getZERO(); } Iterator ai = val.keySet().iterator(); IndexList lt = ai.next(); lt = ai.next(); // size > 1 SortedMap red = val.tailMap(lt); return new GenExteriorPolynomial(ring, red); } /** * Index degree. * @return maximal length of indexes. */ public long degree() { if (val.size() == 0) { return 0; // 0 or -1 ?; } long deg = 0; for (IndexList e : val.keySet()) { long d = e.degree(); if (d > deg) { deg = d; } } return deg; } /** * Index maximal degree. * @return maximal degree of indexes. */ public long maxDegree() { if (val.size() == 0) { return 0; // 0 or -1 ?; } long deg = 0; for (IndexList e : val.keySet()) { long d = e.maxDeg(); if (d > deg) { deg = d; } } return deg; } /** * GenExteriorPolynomial maximum norm. * @return ||this||. */ public C maxNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); if (n.compareTo(x) < 0) { n = x; } } return n; } /** * GenExteriorPolynomial sum norm. * @return sum of all absolute values of coefficients. */ public C sumNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); n = n.sum(x); } return n; } /** * GenExteriorPolynomial summation. * @param S GenExteriorPolynomial. * @return this+S. */ public GenExteriorPolynomial sum(GenExteriorPolynomial S) { if (S == null) { return this; } if (S.isZERO()) { return this; } if (this.isZERO()) { return S; } assert (ring.ixfac == S.ring.ixfac); GenExteriorPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { IndexList e = me.getKey(); C y = me.getValue(); // assert y != null C x = nv.get(e); if (x != null) { x = x.sum(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y); } } return n; } /** * GenExteriorPolynomial addition. This method is not very efficient, since * this is copied. * @param a coefficient. * @param e index list. * @return this + a e. */ public GenExteriorPolynomial sum(C a, IndexList e) { if (a == null) { return this; } if (a.isZERO()) { return this; } if (e == null) { return this; } if (e.isZERO()) { return this; } GenExteriorPolynomial n = this.copy(); SortedMap nv = n.val; C x = nv.get(e); if (x != null) { x = x.sum(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a); } return n; } /** * GenExteriorPolynomial addition. This method is not very efficient, since * this is copied. * @param a coefficient. * @return this + a x0. */ public GenExteriorPolynomial sum(C a) { return sum(a, ring.wone); } /** * GenExteriorPolynomial subtraction. * @param S GenExteriorPolynomial. * @return this-S. */ public GenExteriorPolynomial subtract(GenExteriorPolynomial S) { if (S == null) { return this; } if (S.isZERO()) { return this; } if (this.isZERO()) { return S.negate(); } assert (ring.ixfac == S.ring.ixfac); GenExteriorPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { IndexList e = me.getKey(); C y = me.getValue(); // assert y != null C x = nv.get(e); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y.negate()); } } return n; } /** * GenExteriorPolynomial subtraction. This method is not very efficient, * since this is copied. * @param a coefficient. * @param e index list. * @return this - a e. */ public GenExteriorPolynomial subtract(C a, IndexList e) { if (a == null) { return this; } if (a.isZERO()) { return this; } if (e == null) { return this; } if (e.isZERO()) { return this; } GenExteriorPolynomial n = this.copy(); SortedMap nv = n.val; C x = nv.get(e); if (x != null) { x = x.subtract(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a.negate()); } return n; } /** * GenExteriorPolynomial subtract. This method is not very efficient, since * this is copied. * @param a coefficient. * @return this + a x0. */ public GenExteriorPolynomial subtract(C a) { return subtract(a, ring.wone); } /** * GenExteriorPolynomial negation. * @return -this. */ public GenExteriorPolynomial negate() { GenExteriorPolynomial n = ring.getZERO().copy(); SortedMap v = n.val; for (Map.Entry m : val.entrySet()) { C x = m.getValue(); // != null, 0 v.put(m.getKey(), x.negate()); } return n; } /** * GenExteriorPolynomial absolute value, i.e. leadingCoefficient > 0. * @return abs(this). */ public GenExteriorPolynomial abs() { if (leadingBaseCoefficient().signum() < 0) { return this.negate(); } return this; } /** * GenExteriorPolynomial multiplication. * @param S GenExteriorPolynomial. * @return this /\\ S. */ public GenExteriorPolynomial multiply(GenExteriorPolynomial S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.ixfac == S.ring.ixfac) : " " + ring + " != " + S.ring; GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); for (Map.Entry m2 : S.val.entrySet()) { C c2 = m2.getValue(); IndexList e2 = m2.getKey(); C c = c1.multiply(c2); // check non zero if not domain if (!c.isZERO()) { IndexList e = e1.multiply(e2); if (e.isZERO()) { // since exterior algebra continue; } if (e.sign < 0) { // propagate sign to coefficient c = c.negate(); e = e.negate(); } C c0 = pv.get(e); if (c0 == null) { pv.put(e, c); } else { c0 = c0.sum(c); if (!c0.isZERO()) { pv.put(e, c0); } else { pv.remove(e); } } } } } return p; } /** * GenExteriorPolynomial interior left multiplication. * @param S GenExteriorPolynomial. * @return this _| S. */ public GenExteriorPolynomial interiorLeftProduct(GenExteriorPolynomial S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.ixfac == S.ring.ixfac) : " " + ring + " != " + S.ring; GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); for (Map.Entry m2 : S.val.entrySet()) { C c2 = m2.getValue(); IndexList e2 = m2.getKey(); C c = c1.multiply(c2); // check non zero if not domain if (!c.isZERO()) { IndexList e = e1.interiorLeftProduct(e2); if (e.isZERO()) { // since exterior algebra continue; } if (e.sign < 0) { // propagate sign to coefficient c = c.negate(); e = e.negate(); } C c0 = pv.get(e); if (c0 == null) { pv.put(e, c); } else { c0 = c0.sum(c); if (!c0.isZERO()) { pv.put(e, c0); } else { pv.remove(e); } } } } } return p; } /** * GenExteriorPolynomial interior right multiplication. * @param S GenExteriorPolynomial. * @return this |_ S. */ public GenExteriorPolynomial interiorRightProduct(GenExteriorPolynomial S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.ixfac == S.ring.ixfac) : " " + ring + " != " + S.ring; GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); for (Map.Entry m2 : S.val.entrySet()) { C c2 = m2.getValue(); IndexList e2 = m2.getKey(); C c = c1.multiply(c2); // check non zero if not domain if (!c.isZERO()) { IndexList e = e1.interiorRightProduct(e2); if (e.isZERO()) { // since exterior algebra continue; } if (e.sign < 0) { // propagate sign to coefficient c = c.negate(); e = e.negate(); } C c0 = pv.get(e); if (c0 == null) { pv.put(e, c); } else { c0 = c0.sum(c); if (!c0.isZERO()) { pv.put(e, c0); } else { pv.remove(e); } } } } } return p; } /** * GenExteriorPolynomial left and right multiplication. Product with two * polynomials. * @param S GenExteriorPolynomial. * @param T GenExteriorPolynomial. * @return S*this*T. */ public GenExteriorPolynomial multiply(GenExteriorPolynomial S, GenExteriorPolynomial T) { if (S.isZERO() || T.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * GenExteriorPolynomial multiplication. Product with coefficient ring * element. * @param s coefficient. * @return this*s. */ public GenExteriorPolynomial multiply(C s) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); C c = c1.multiply(s); // check non zero if not domain if (!c.isZERO()) { pv.put(e1, c); // or m1.setValue( c ) } } return p; } /** * GenExteriorPolynomial multiplication. Product with coefficient ring * element. * @param s coefficient. * @param t coefficient. * @return s*this*t. */ public GenExteriorPolynomial multiply(C s, C t) { if (s == null || t == null) { return ring.getZERO(); } if (s.isZERO() || t.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e = m1.getKey(); C c = s.multiply(c1).multiply(t); // check non zero if not domain if (!c.isZERO()) { pv.put(e, c); // or m1.setValue( c ) } } return p; } /** * GenExteriorPolynomial monic, i.e. leadingCoefficient == 1. If * leadingCoefficient is not invertible returns this unmodified. * @return monic(this). */ public GenExteriorPolynomial monic() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lc = "+lc); return this; } C lm = lc.inverse(); return multiply(lm); } /** * GenExteriorPolynomial multiplication. Product with ring element and index * list. * @param s coefficient. * @param e left index list. * @return this * s e. */ public GenExteriorPolynomial multiply(C s, IndexList e) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (e == null) { return ring.getZERO(); } if (e.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); C c = c1.multiply(s); // check non zero if not domain if (!c.isZERO()) { IndexList e2 = e1.multiply(e); if (e2.isZERO()) { // since exterior algebra continue; } if (e2.sign < 0) { // propagate sign to coefficient c = c.negate(); e2 = e2.negate(); } pv.put(e2, c); } } return p; } /** * GenExteriorPolynomial left and right multiplication. Product with ring * element and two index lists. * @param e left index list. * @param f right index list. * @return e * this * f. */ public GenExteriorPolynomial multiply(IndexList e, IndexList f) { if (e == null) { return ring.getZERO(); } if (e.isZERO()) { return ring.getZERO(); } if (f == null) { return ring.getZERO(); } if (f.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (e.isONE()) { return multiply(f); } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c = m1.getValue(); IndexList e1 = m1.getKey(); IndexList ef = e1.multiply(f); if (ef.isZERO()) { // since exterior algebra continue; } if (ef.sign < 0) { // propagate sign to coefficient c = c.negate(); ef = ef.negate(); } IndexList e2 = e.multiply(ef); if (e2.isZERO()) { // since exterior algebra continue; } if (e2.sign < 0) { // propagate sign to coefficient c = c.negate(); e2 = e2.negate(); } pv.put(e2, c); } return p; } /** * GenExteriorPolynomial left and right multiplication. Product with ring * element and two index lists. * @param s coefficient. * @param e left index list. * @param f right index list. * @return e * this * s * f. */ public GenExteriorPolynomial multiply(C s, IndexList e, IndexList f) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (e == null) { return ring.getZERO(); } if (e.isZERO()) { return ring.getZERO(); } if (f == null) { return ring.getZERO(); } if (f.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (e.isONE()) { return multiply(s, f); } C c = ring.coFac.getONE(); return multiply(c, e, s, f); // sic, history } /** * GenExteriorPolynomial left and right multiplication. Product with ring * element and two index lists. * @param s coefficient. * @param e left index list. * @param t coefficient. * @param f right index list. * @return s * e * this * t * f. */ public GenExteriorPolynomial multiply(C s, IndexList e, C t, IndexList f) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (t == null) { return ring.getZERO(); } if (t.isZERO()) { return ring.getZERO(); } if (e == null) { return ring.getZERO(); } if (e.isZERO()) { return ring.getZERO(); } if (f == null) { return ring.getZERO(); } if (f.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); C c = s.multiply(c1).multiply(t); // check non zero if not domain if (!c.isZERO()) { IndexList e1 = m1.getKey(); //IndexList e2 = e.multiply(e1).multiply(f); IndexList ef = e1.multiply(f); if (ef.isZERO()) { // since exterior algebra continue; } if (ef.sign < 0) { // propagate sign to coefficient c = c.negate(); ef = ef.negate(); } IndexList e2 = e.multiply(ef); if (e2.isZERO()) { // since exterior algebra continue; } if (e2.sign < 0) { // propagate sign to coefficient c = c.negate(); e2 = e2.negate(); } pv.put(e2, c); } } return p; } /** * GenExteriorPolynomial multiplication. Product with index list. * @param e index list (!= null). * @return this * e. */ public GenExteriorPolynomial multiply(IndexList e) { if (e == null) { return ring.getZERO(); } if (e.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); IndexList e1 = m1.getKey(); IndexList e2 = e1.multiply(e); if (e2.isZERO()) { // since exterior algebra continue; } if (e2.sign < 0) { // propagate sign to coefficient c1 = c1.negate(); e2 = e2.negate(); } pv.put(e2, c1); } return p; } /** * GenExteriorPolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m. */ public GenExteriorPolynomial multiply(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * GenExteriorPolynomial division. Division by coefficient ring element. * Fails, if exact division is not possible. * @param s coefficient. * @return this/s. */ public GenExteriorPolynomial divide(C s) { if (s == null || s.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " division by zero"); } if (this.isZERO() || s.isONE()) { return this; } //C t = s.inverse(); //return multiply(t); GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { IndexList e = m.getKey(); C c1 = m.getValue(); C c = c1.divide(s); // is divideLeft if (debug) { C x = c1.remainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException( this.getClass().getName() + " no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1 + "/" + s + ", in " + this); } pv.put(e, c); // or m1.setValue( c ) } return p; } /** * GenExteriorPolynomial coefficient primitive part. Division by gcd of * coefficients. * @return this/gcd(coeff(this)). */ public GenExteriorPolynomial coeffPrimitivePart() { if (this.isZERO() || this.isONE()) { return this; } C s = ring.coFac.getZERO(); for (C c : val.values()) { s = s.gcd(c); } return divide(s).abs(); } /** * GenExteriorPolynomial division with remainder. Fails, if exact division * by leading base coefficient is not possible. Meaningful only for * univariate polynomials over fields, but works in any case. * @param S nonzero GenExteriorPolynomial with invertible leading * coefficient. * @return [ quotient , remainder ] with this = quotient * S + remainder and * deg(remainder) < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ @SuppressWarnings("unchecked") public GenExteriorPolynomial[] quotientRemainder(GenExteriorPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } GenExteriorPolynomial[] ret = new GenExteriorPolynomial[2]; if (this.isZERO()) { ret[0] = ring.getZERO(); ret[1] = ring.getZERO(); return ret; } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException("lbcf not invertible " + c); } C ci = c.inverse(); C one = ring.coFac.getONE(); assert (ring.ixfac == S.ring.ixfac); IndexFactory.IndexListComparator cmp = ring.ixfac.getDescendComparator(); IndexList e = S.leadingIndexList(); GenExteriorPolynomial h; GenExteriorPolynomial q = ring.getZERO().copy(); GenExteriorPolynomial r = this.copy(); while (!r.isZERO()) { IndexList f = r.leadingIndexList(); if (e.divides(f)) { C a = r.leadingBaseCoefficient(); //IndexList gl = e.interiorLeftProduct(f); IndexList g = e.interiorRightProduct(f); //System.out.println("divRem: f = " + f + ", e = " + e + ", g = " + g); a = a.multiply(ci); q = q.sum(a, g); // q + a g h = S.multiply(a, g); // a g * S r = r.subtract(h); IndexList fr = r.leadingIndexList(); if (cmp.compare(f, fr) > 0) { // non noetherian reduction // todo throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr); } } else { break; } } ret[0] = q; ret[1] = r; return ret; } /** * GenExteriorPolynomial division. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenExteriorPolynomial with invertible leading * coefficient. * @return quotient with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ public GenExteriorPolynomial divide(GenExteriorPolynomial S) { return quotientRemainder(S)[0]; } /** * GenExteriorPolynomial remainder. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenExteriorPolynomial with invertible leading * coefficient. * @return remainder with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ public GenExteriorPolynomial remainder(GenExteriorPolynomial S) { return quotientRemainder(S)[1]; } /** * GenExteriorPolynomial greatest common divisor. Note: not * implemented. * @param S GenExteriorPolynomial. * @return gcd(this,S). */ public GenExteriorPolynomial gcd(GenExteriorPolynomial S) { throw new UnsupportedOperationException("no gcd for exterior polynomials"); } /** * GenExteriorPolynomial extended greatest common divisor. Note: not * implemented. * @param S GenExteriorPolynomial. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ public GenExteriorPolynomial[] egcd(GenExteriorPolynomial S) { throw new UnsupportedOperationException("no gcd for exterior polynomials"); } /** * GenExteriorPolynomial inverse. Required by RingElem. Throws not * invertible exception. */ public GenExteriorPolynomial inverse() { if (isUnit()) { // only possible if ldbcf is unit C c = leadingBaseCoefficient().inverse(); return ring.getONE().multiply(c); } throw new NotInvertibleException("element not invertible " + this + " :: " + ring); } /** * GenExteriorPolynomial shift index. Add number to each index. * @param s shift index by this number. * @return this.shift(s). */ public GenExteriorPolynomial shiftIndex(int s) { //if (ring.ixfac.length() != 1) { // throw new IllegalArgumentException("only 'univariate' polynomials"); //} if (s == 0) { return this; } if (this.isZERO()) { return this; } List gen = ring.ixfac.generators(); //System.out.println("gen = " + gen); long d = maxDegree(); //System.out.println("d = " + d); if (d + s >= gen.size()) { throw new IllegalArgumentException("ixfac to small: " + (d + s) + " >= " + gen.size()); } GenExteriorPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c = m1.getValue(); IndexList ei = m1.getKey(); int e = ei.getVal(0); e = e + s; IndexList fi = gen.get(e); pv.put(fi, c); } return p; } /** * Iterator over coefficients. * @return val.values().iterator(). */ public Iterator coefficientIterator() { return val.values().iterator(); } /** * Iterator over index lists. * @return val.keySet().iterator(). */ public Iterator indexListIterator() { return val.keySet().iterator(); } /** * Iterator over monomials. * @return a PolyIterator. */ public Iterator> iterator() { return new IndexListPolyIterator(val); } /** * Map a unary function to the coefficients. * @param f evaluation functor. * @return new polynomial with coefficients f(this(e)). */ public GenExteriorPolynomial map(final UnaryFunctor f) { GenExteriorPolynomial n = ring.getZERO().copy(); SortedMap nv = n.val; for (Map.Entry m : this.val.entrySet()) { //logger.info("m = {}", m); C c = f.eval(m.getValue()); if (c != null && !c.isZERO()) { nv.put(m.getKey(), c); } } return n; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenExteriorPolynomialRing.java000066400000000000000000000604651445075545500266370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PreemptStatus; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenVector; /** * GenExteriorPolynomialRing generic antisymmetric polynomial factory * implementing RingFactory; Factory for antisymmetric polynomials (in fact * vectors) over C. Objects of this class are intended to be immutable. Only the * coefficients are modeled with generic types, the "exponents" are fixed to * IndexList. C can also be a non integral domain, e.g. a ModInteger, i.e. it * may contain zero divisors, since multiply() does check for zero coefficients * and index lists. * @see "masnc.DIPE.mi from SAC2/MAS" * @param coefficient type * @author Heinz Kredel */ public final class GenExteriorPolynomialRing> implements RingFactory> { /*, Iterable>*/ /** * The factory for the coefficients. */ public final RingFactory coFac; /** * The factory for the IndexList. */ public final IndexFactory ixfac; /** * The constant polynomial 0 for this ring. */ public final GenExteriorPolynomial ZERO; /** * The constant polynomial 1 for this ring. */ public final GenExteriorPolynomial ONE; /** * The constant empty index lists exponent for this ring. */ public final IndexList wone; /** * A default random sequence generator. */ final static Random random = new Random(); /** * Indicator if this ring is a field. */ private int isField = -1; // initially unknown /** * Log4j logger object. */ private static final Logger logger = LogManager.getLogger(GenExteriorPolynomialRing.class); /** * Flag to enable if preemptive interrupt is checked. */ final boolean checkPreempt = PreemptStatus.isAllowed(); /** * The constructor creates a polynomial factory object with the default term * order. * @param cf factory for coefficients of type C. * @param wf factory for index list. */ public GenExteriorPolynomialRing(RingFactory cf, IndexFactory wf) { coFac = cf; ixfac = wf; ZERO = new GenExteriorPolynomial(this); C coeff = coFac.getONE(); wone = ixfac.getONE(); ONE = new GenExteriorPolynomial(this, coeff, wone); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param s array of variable names. */ public GenExteriorPolynomialRing(RingFactory cf, String[] s) { this(cf, new IndexFactory(s.length)); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param s string of single letter variable names. */ public GenExteriorPolynomialRing(RingFactory cf, String s) { this(cf, new IndexFactory(s.length())); // todo } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param o other polynomial ring. */ public GenExteriorPolynomialRing(RingFactory cf, GenExteriorPolynomialRing o) { this(cf, o.ixfac); } /** * The constructor creates a polynomial factory object. * @param fac polynomial ring. */ public GenExteriorPolynomialRing(GenPolynomialRing fac) { this(fac.coFac, new IndexFactory(fac.nvar)); } /** * Copy this factory. * @return a clone of this. */ public GenExteriorPolynomialRing copy() { return new GenExteriorPolynomialRing(coFac, this); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append("ExteriorPolyRing("); if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toString().trim()); } s.append(", \""); s.append(ixfac.toString()); s.append("\")"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("ExtPolyRing.new("); break; case Python: default: s.append("ExtPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(", \""); s.append(ixfac.toScript()); s.append("\")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof GenExteriorPolynomialRing)) { return false; } GenExteriorPolynomialRing oring = (GenExteriorPolynomialRing) other; if (!coFac.equals(oring.coFac)) { return false; } if (!ixfac.equals(oring.ixfac)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = (coFac.hashCode() << 11); h += ixfac.hashCode(); return h; } /* * Get the variable names. * @return vars. public String[] getVars() { return ixfac.getVars(); // Java-5: Arrays.copyOf(vars,vars.length); } */ /** * Get the zero element from the coefficients. * @return 0 as C. */ public C getZEROCoefficient() { return coFac.getZERO(); } /** * Get the one element from the coefficients. * @return 1 as C. */ public C getONECoefficient() { return coFac.getONE(); } /** * Get the zero element. * @return 0 as GenExteriorPolynomial. */ public GenExteriorPolynomial getZERO() { return ZERO; } /** * Get the one element. * @return 1 as GenExteriorPolynomial. */ public GenExteriorPolynomial getONE() { return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return coFac.isCommutative() && ixfac.length() < 1; } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return coFac.isAssociative(); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return coFac.isFinite(); // ixfac.isFinite() is true } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (coFac.isField() && ixfac.length() < 1) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Get a (constant) GenExteriorPolynomial element from a coefficient value. * @param a coefficient. * @return a constant GenExteriorPolynomial. */ public GenExteriorPolynomial valueOf(C a) { return new GenExteriorPolynomial(this, a); } /** * Get a GenExteriorPolynomial element from a index list. * @param e index list. * @return a GenExteriorPolynomial. */ public GenExteriorPolynomial valueOf(IndexList e) { return valueOf(coFac.getONE(), ixfac.valueOf(e)); } /** * Get a GenExteriorPolynomial from an ExpVector. * @param e exponent vector. * @return a GenExteriorPolynomial, if exponents are > 1 return ZERO. */ public GenExteriorPolynomial valueOf(ExpVector e) { return valueOf(coFac.getONE(), ixfac.valueOf(e)); } /** * Get a GenExteriorPolynomial from a coefficient and a IndexList. * @param a coefficient. * @param e word. * @return a GenExteriorPolynomial. */ public GenExteriorPolynomial valueOf(C a, IndexList e) { return new GenExteriorPolynomial(this, a, e); } /** * Get a GenExteriorPolynomial from a coefficient and an ExpVector. * @param a coefficient. * @param e exponent vector. * @return a GenExteriorPolynomial, if exponents are > 1 return ZERO. */ public GenExteriorPolynomial valueOf(C a, ExpVector e) { return new GenExteriorPolynomial(this, a, ixfac.valueOf(e)); } /** * Get a GenExteriorPolynomial from a multivariate GenPolynomial, terms with * exponents > 1 are set to zero. * @param a multivariate GenPolynomial. * @return multivariate a GenExteriorPolynomial. */ public GenExteriorPolynomial valueOf(GenPolynomial a) { if (a.isZERO()) { return getZERO(); } if (a.isONE()) { return getONE(); } GenExteriorPolynomial p = this.getZERO().copy(); for (Map.Entry m : a.val.entrySet()) { C c = m.getValue(); ExpVector e = m.getKey(); IndexList w = ixfac.valueOf(e); if (!w.isZERO()) { p.doPutToMap(w, c); } } return p; } /** * Get a GenExteriorPolynomial from a GenExteriorPolynomial with conformant * index lists. * @param a GenExteriorPolynomial. * @return a GenExteriorPolynomial with conformant index lists. */ public GenExteriorPolynomial valueOf(GenExteriorPolynomial a) { if (a.isZERO()) { return getZERO(); } if (a.isONE()) { return getONE(); } GenExteriorPolynomial p = this.getZERO().copy(); for (Map.Entry m : a.val.entrySet()) { C c = m.getValue(); IndexList e = m.getKey(); if (!e.isZERO()) { IndexList w = ixfac.valueOf(e.val); if (!w.isZERO()) { p.doPutToMap(w, c); } } } return p; } /** * Get a list of GenExteriorPolynomials from a list of GenPolynomials. * @param A GenPolynomial list. * @return a GenExteriorPolynomial list. */ public List> valueOf(List> A) { List> B = new ArrayList>(A.size()); if (A.isEmpty()) { return B; } for (GenPolynomial a : A) { GenExteriorPolynomial b = valueOf(a); B.add(b); } return B; } /** * Get a GenExteriorPolynomial maximal index list element. * @return a GenExteriorPolynomial with maximal index list. */ public GenExteriorPolynomial getIMAX() { return valueOf(coFac.getONE(), ixfac.imax); } /** * Get a (constant) GenExteriorPolynomial from a long value. * @param a long. * @return a GenExteriorPolynomial. */ public GenExteriorPolynomial fromInteger(long a) { return new GenExteriorPolynomial(this, coFac.fromInteger(a), wone); } /** * Get a (constant) GenExteriorPolynomial from a BigInteger value. * @param a BigInteger. * @return a GenExteriorPolynomial<C>. */ public GenExteriorPolynomial fromInteger(BigInteger a) { return new GenExteriorPolynomial(this, coFac.fromInteger(a), wone); } /** * Get a GenExteriorPolynomial from a GenVector. * @param a GenVector. * @return a GenExteriorPolynomial. */ public GenExteriorPolynomial fromVector(GenVector a) { if (a == null || a.isZERO()) { return ZERO; } List gen = ixfac.generators(); //System.out.println("gen = " + gen); GenExteriorPolynomial ret = copy(ZERO); SortedMap tm = ret.val; int i = -1; for (C m : a.val) { i++; if (m.isZERO()) { continue; } IndexList ix = gen.get(i); //new IndexList(ixfac, new int[]{ i }); tm.put(ix, m); } return ret; } /** * Get a list of GenExteriorPolynomials from a GenMatrix. * @param A GenMatrix * @return a list of GenExteriorPolynomials. */ public List> fromMatrix(GenMatrix A) { List> L = new ArrayList>(); if (A == null || A.isZERO()) { //|| A.isZERO() return L; } for (int i = 0; i < A.ring.rows; i++) { GenVector v = A.getRow(i); if (v.isZERO()) { continue; } GenExteriorPolynomial ep = fromVector(v); //System.out.println("ep = " + ep); L.add(ep); } return L; } /** * Determinant form exterior polynomial / matrix. * @param A list of GenExteriorPolynomials * @return determinant of 'matrix' A. */ public C determinant(List> A) { C det = coFac.getZERO(); if (A == null || A.isEmpty()) { return det; } GenExteriorPolynomial p = getONE(); for (GenExteriorPolynomial ep : A) { if (ep.isZERO()) { return det; } p = p.multiply(ep); //System.out.println("p = " + p); if (p.isZERO()) { return det; } } if (p.length() > 1) { return det; } det = p.leadingBaseCoefficient(); // IndexList di = p.leadingIndexList(); // if (di.equals(ixfac.imax)) { // to big // det = p.leadingBaseCoefficient(); // } else { // System.out.println("p in det = " + p); // } return det; } /** * Get a GenExteriorPolynomial from a univariate GenPolynomial. Different * exponents are converted to different indexes. * @param a univariate GenPolynomial. * @return a multivariate GenExteriorPolynomial. */ @SuppressWarnings("unchecked") public GenExteriorPolynomial fromPolynomial(GenPolynomial a) { if (a == null || a.isZERO()) { return ZERO; } if (a.ring.nvar != 1) { throw new IllegalArgumentException("no univariate polynomial"); } int deg = (int) a.degree(); if (deg > ixfac.imax.maxDeg()) { throw new IllegalArgumentException( "ensure deg <= ixfax.maxDeg: " + deg + " > " + ixfac.imax.maxDeg()); } if (ixfac.imax.minDeg() > 0) { throw new IllegalArgumentException("ensure ixfax.minDeg == 0: " + ixfac.imax.minDeg()); } List gen = ixfac.generators(); //System.out.println("gen = " + gen); GenExteriorPolynomial ret = copy(ZERO); SortedMap tm = ret.val; for (Monomial m : a) { int e = (int) m.e.getVal(0); IndexList ix = gen.get(e); //new IndexList(ixfac, new int[]{ e }); C co = (C) m.c; tm.put(ix, co); } return ret; } /** * Resultant of two commutative polynaomials. * @param A GenPolynomial * @param B GenPolynomial * @return res(A,B). */ public C resultant(GenPolynomial A, GenPolynomial B) { C det = coFac.getZERO(); if (A == null || A.isZERO() || B == null || B.isZERO()) { return det; } int m = (int) A.degree(); int n = (int) B.degree(); GenExteriorPolynomial a, b; a = fromPolynomial(A); b = fromPolynomial(B); if (m < n) { GenExteriorPolynomial c = a; a = b; b = c; int t = m; m = n; n = t; } //System.out.println("a = " + a); //System.out.println("b = " + b); List> mat = new ArrayList>(m + n); for (int i = n - 1; i >= 0; i--) { GenExteriorPolynomial c = a.shiftIndex(i); mat.add(c); } for (int i = m - 1; i >= 0; i--) { GenExteriorPolynomial c = b.shiftIndex(i); mat.add(c); } //System.out.println("mat = " + mat); det = determinant(mat); return det; } /** * Random polynomial. Generates a random polynomial. * @param n number of terms. * @return a random polynomial. */ public GenExteriorPolynomial random(int n) { return random(n, random); } /** * Random polynomial. Generates a random polynomial with k = 5, l = n, d = * 3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenExteriorPolynomial random(int n, Random rnd) { return random(5, n, 3, rnd); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal length of a random word. * @return a random polynomial. */ public GenExteriorPolynomial random(int k, int l, int d) { return random(k, l, d, random); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal length of a random word. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenExteriorPolynomial random(int k, int l, int d, Random rnd) { GenExteriorPolynomial r = getZERO(); //.clone() or copy( ZERO ); // add l random coeffs and words of maximal length d int dm = Math.min(d, ixfac.imaxlength); //length()); for (int i = 0; i < l; i++) { int di = Math.abs(rnd.nextInt() % dm); IndexList e = ixfac.random(di, 0.5f, rnd).abs(); // s only = 0, 1 //System.out.println("e++ = " + e); C a = coFac.random(k, rnd); //System.out.println("e = " + e + " a = " + a); r = r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Generate a random k-form polynomial. * @param kl bitsize of random coefficients. * @param l number of terms. * @param k length of any random word. * @return a random k-form polynomial. */ public GenExteriorPolynomial randomForm(int kl, int l, int k) { return randomForm(kl, l, k, random); } /** * Generate a random k-form polynomial. * @param kl bitsize of random coefficients. * @param l number of terms. * @param k length of any random word. * @param rnd is a source for random bits. * @return a random k-form polynomial. */ public GenExteriorPolynomial randomForm(int kl, int l, int k, Random rnd) { GenExteriorPolynomial r = getZERO(); //.copy(); // or copy( ZERO ); // add l random coeffs and index lists of length k if (k > ixfac.imaxlength || k < 0) { return r; } if (k == 0) { return getZERO(); } for (int i = 0; i < l; i++) { IndexList e = ixfac.random(k, 0.5f, rnd).abs(); // s only = 0, 1 //System.out.println("e_k = " + e); if (e.length() != k) { continue; } C a = coFac.random(kl, rnd); //System.out.println("e = " + e + " a = " + a); r = r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c polynomial to copy. * @return a copy of c. */ public GenExteriorPolynomial copy(GenExteriorPolynomial c) { return new GenExteriorPolynomial(this, c.val); } /** * Parse a polynomial with the use of GenExteriorPolynomialTokenizer. * @param s String. * @return GenExteriorPolynomial from s. */ public GenExteriorPolynomial parse(String s) { String val = s; if (!s.contains("|")) { val = val.replace("{", "").replace("}", ""); } return parse(new StringReader(val)); } /** * Parse a polynomial with the use of GenPolynomialTokenizer. * @param r Reader. * @return next GenExteriorPolynomial from r. */ @SuppressWarnings("unchecked") public GenExteriorPolynomial parse(Reader r) { GenPolynomialTokenizer tok = new GenPolynomialTokenizer(r); GenExteriorPolynomial a; try { a = tok.nextExteriorPolynomial(this); } catch (IOException e) { a = null; e.printStackTrace(); logger.error("{} parse {}", e, this); } return a; //throw new UnsupportedOperationException("not implemented"); } /** * Generate univariate polynomial in a given variable. * @param i the index of the variable. * @return X_i as univariate polynomial. */ public GenExteriorPolynomial univariate(int i) { GenExteriorPolynomial p = getZERO(); List wgen = ixfac.generators(); if (0 <= i && i < wgen.size()) { C one = coFac.getONE(); IndexList f = wgen.get(i); p = p.sum(one, f); } return p; } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ public List> univariateList() { int n = ixfac.length(); List> pols = new ArrayList>(n); for (int i = 0; i < n; i++) { GenExteriorPolynomial p = univariate(i); pols.add(p); } return pols; } /** * Get the generating elements excluding the generators for the * coefficient ring. * @return a list of generating elements for this ring. */ public List> getGenerators() { List> univs = univariateList(); List> gens = new ArrayList>(univs.size() + 1); gens.add(getONE()); gens.addAll(univs); return gens; } /** * Get a list of all generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List cogens = coFac.generators(); List> univs = univariateList(); List> gens = new ArrayList>( univs.size() + cogens.size()); for (C c : cogens) { gens.add(getONE().multiply(c)); } gens.addAll(univs); return gens; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenPolynomial.java000066400000000000000000002356041445075545500242740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.Spliterator; import java.util.TreeMap; import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PreemptingException; import edu.jas.kern.PrettyPrint; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; import edu.jas.structure.StarRingElem; import edu.jas.structure.UnaryFunctor; import edu.jas.util.MapEntry; /** * GenPolynomial generic polynomials implementing RingElem. n-variate ordered * polynomials over coefficients C. The variables commute with each other and * with the coefficients. For non-commutative coefficients some care is taken to * respect the multiplication order. * * Objects of this class are intended to be immutable. The implementation is * based on TreeMap respectively SortedMap from exponents to coefficients. Only * the coefficients are modeled with generic types, the exponents are fixed to * ExpVector with long entries (@see edu.jas.poly.ExpVector StorUnit). C can * also be a non integral domain, e.g. a ModInteger, i.e. it may contain zero * divisors, since multiply() does check for zeros. Note: multiply() now * checks for wrong method dispatch for GenSolvablePolynomial. * @param coefficient type * @author Heinz Kredel */ public class GenPolynomial> implements RingElem>, /* not yet Polynomial */ Iterable> { /** * The factory for the polynomial ring. */ public final GenPolynomialRing ring; /** * The data structure for polynomials. */ protected final SortedMap val; // do not change to TreeMap /** * Stored hash code. */ transient protected int hash = -1; /** * Stored bitLength. */ transient protected long blen = -1; private static final Logger logger = LogManager.getLogger(GenPolynomial.class); private static final boolean debug = logger.isDebugEnabled(); // protected GenPolynomial() { ring = null; val = null; } // don't use /** * Private constructor for GenPolynomial. * @param r polynomial ring factory. * @param t TreeMap with correct ordering. */ private GenPolynomial(GenPolynomialRing r, TreeMap t) { ring = r; val = t; if (ring.checkPreempt) { if (Thread.currentThread().isInterrupted()) { logger.debug("throw PreemptingException"); throw new PreemptingException(); } } } /** * Constructor for zero GenPolynomial. * @param r polynomial ring factory. */ public GenPolynomial(GenPolynomialRing r) { this(r, new TreeMap(r.tord.getDescendComparator())); } /** * Constructor for GenPolynomial c * xe. * @param r polynomial ring factory. * @param c coefficient. * @param e exponent. */ public GenPolynomial(GenPolynomialRing r, C c, ExpVector e) { this(r); if (!c.isZERO()) { val.put(e, c); } } /** * Constructor for GenPolynomial c * x0. * @param r polynomial ring factory. * @param c coefficient. */ public GenPolynomial(GenPolynomialRing r, C c) { this(r, c, r.evzero); } /** * Constructor for GenPolynomial xe. * @param r polynomial ring factory. * @param e exponent. */ public GenPolynomial(GenPolynomialRing r, ExpVector e) { this(r, r.coFac.getONE(), e); } /** * Constructor for GenPolynomial. * @param r polynomial ring factory. * @param v the SortedMap of some other polynomial. */ protected GenPolynomial(GenPolynomialRing r, SortedMap v) { this(r); if (v.size() > 0) { GenPolynomialRing.creations++; val.putAll(v); // assume no zero coefficients and val is empty assert !val.values().contains(r.coFac.getZERO()) : "illegal coefficient zero: " + v; } } /** * Constructor for GenPolynomial. * @param r polynomial ring factory. * @param v some Map from ExpVector to coefficients. */ protected GenPolynomial(GenPolynomialRing r, Map v) { this(r); if (v.size() > 0) { GenPolynomialRing.creations++; val.putAll(v); // assume no zero coefficients and val is empty assert !val.values().contains(r.coFac.getZERO()) : "illegal coefficient zero: " + v; } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public GenPolynomialRing factory() { return ring; } /** * Copy this GenPolynomial. * @return copy of this. */ public GenPolynomial copy() { return new GenPolynomial(ring, this.val); } /** * Length of GenPolynomial. * @return number of coefficients of this GenPolynomial. */ public int length() { return val.size(); } /** * ExpVector to coefficient map of GenPolynomial. * @return val as unmodifiable SortedMap. */ public SortedMap getMap() { // return val; return Collections. unmodifiableSortedMap(val); } /** * Put an ExpVector to coefficient entry into the internal map of this * GenPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param c coefficient. * @param e exponent. */ public void doPutToMap(ExpVector e, C c) { if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, c); } hash = -1; blen = -1; } if (!c.isZERO()) { val.put(e, c); } } /** * Remove an ExpVector to coefficient entry from the internal map of this * GenPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param e exponent. * @param c expected coefficient, null for ignore. */ public void doRemoveFromMap(ExpVector e, C c) { C b = val.remove(e); if (true) { //||debug hash = -1; blen = -1; if (c == null) { // ignore b return; } if (!c.equals(b)) { logger.error("map entry wrong {} to {} old {}", e, c, b); throw new RuntimeException("c != b"); } } } /** * Put an a sorted map of exponents to coefficients into the internal map of * this GenPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param vals sorted map of exponents and coefficients. */ public void doPutToMap(SortedMap vals) { for (Map.Entry me : vals.entrySet()) { ExpVector e = me.getKey(); if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, me.getValue()); } hash = -1; blen = -1; } C c = me.getValue(); if (!c.isZERO()) { val.put(e, c); } } } /** * String representation of GenPolynomial. * @see java.lang.Object#toString() */ @Override public String toString() { if (ring.vars != null) { return toString(ring.vars); } StringBuffer s = new StringBuffer(); s.append(this.getClass().getSimpleName() + ":"); s.append(ring.coFac.getClass().getSimpleName()); if (ring.coFac.characteristic().signum() != 0) { s.append("(" + ring.coFac.characteristic() + ")"); } s.append("[ "); boolean first = true; for (Map.Entry m : val.entrySet()) { if (first) { first = false; } else { s.append(", "); } s.append(m.getValue().toString()); s.append(" "); s.append(m.getKey().toString()); } s.append(" ] "); // no not use: ring.toString() ); return s.toString(); } /** * String representation of GenPolynomial. * @param v names for variables. * @see java.lang.Object#toString() */ public String toString(String[] v) { StringBuffer s = new StringBuffer(); if (PrettyPrint.isTrue()) { if (val.isEmpty()) { s.append("0"); } else { // s.append( "( " ); boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } ExpVector e = m.getKey(); if (!c.isONE() || e.isZERO()) { String cs = c.toString(); //if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { if (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0) { s.append("( "); s.append(cs); s.append(" )"); } else { s.append(cs); } s.append(" "); } if (e != null && v != null) { s.append(e.toString(v)); } else { s.append(e); } } //s.append(" )"); } } else { s.append(this.getClass().getSimpleName() + "[ "); if (val.isEmpty()) { s.append("0"); } else { boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } ExpVector e = m.getKey(); if (!c.isONE() || e.isZERO()) { s.append(c.toString()); s.append(" "); } s.append(e.toString(v)); } } s.append(" ] "); // no not use: ring.toString() ); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case if (isZERO()) { return "0"; } StringBuffer s = new StringBuffer(); if (val.size() > 1) { s.append("( "); } String[] v = ring.vars; if (v == null) { v = GenPolynomialRing.newVars("x", ring.nvar); } Pattern klammern = Pattern.compile("\\s*\\(.+\\)\\s*"); boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } ExpVector e = m.getKey(); String cs = c.toScript(); boolean parenthesis = (cs.indexOf("-") >= 0 || cs.indexOf("+") >= 0) && !klammern.matcher(cs).matches(); if (!c.isONE() || e.isZERO()) { if (parenthesis) { s.append("( "); } s.append(cs); if (parenthesis) { s.append(" )"); } if (!e.isZERO()) { s.append(" * "); } } s.append(e.toScript(v)); } if (val.size() > 1) { s.append(" )"); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Is GenPolynomial<C> zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.isEmpty(); } /** * Is GenPolynomial<C> one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (val.size() != 1) { return false; } C c = val.get(ring.evzero); if (c == null) { return false; } return c.isONE(); } /** * Is GenPolynomial<C> a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (val.size() != 1) { return false; } C c = val.get(ring.evzero); if (c == null) { return false; } return c.isUnit(); } /** * Is GenPolynomial<C> a constant. * @return If this is a constant polynomial then true is returned, else * false. */ public boolean isConstant() { if (val.size() != 1) { return false; } C c = val.get(ring.evzero); if (c == null) { return false; } return true; } /** * Is GenPolynomial<C> homogeneous. * @return true, if this is homogeneous, else false. */ public boolean isHomogeneous() { if (val.size() <= 1) { return true; } long deg = -1; for (ExpVector e : val.keySet()) { if (deg < 0) { deg = e.totalDeg(); } else if (deg != e.totalDeg()) { return false; } } return true; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof GenPolynomial)) { return false; } GenPolynomial a = (GenPolynomial) B; return this.compareTo(a) == 0; } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = hash; if (h == -1) { //not in sync with equals(): h = (ring.hashCode() << 27); h = val.hashCode(); hash = h; //System.out.println("GenPolynomial.hashCode: " + h); } return h; } /** * GenPolynomial comparison. * @param b GenPolynomial. * @return sign(this-b). */ public int compareTo(GenPolynomial b) { if (b == null) { return 1; } SortedMap av = this.val; SortedMap bv = b.val; Iterator> ai = av.entrySet().iterator(); Iterator> bi = bv.entrySet().iterator(); int s = 0; int c = 0; while (ai.hasNext() && bi.hasNext()) { Map.Entry aie = ai.next(); Map.Entry bie = bi.next(); ExpVector ae = aie.getKey(); ExpVector be = bie.getKey(); s = ae.compareTo(be); if (s != 0) { //System.out.println("s = " + s + ", " + ring.toScript(ae) + ", " + ring.toScript(be)); return s; } if (c == 0) { C ac = aie.getValue(); //av.get(ae); C bc = bie.getValue(); //bv.get(be); c = ac.compareTo(bc); } } if (ai.hasNext()) { //System.out.println("ai = " + ai); return 1; } if (bi.hasNext()) { //System.out.println("bi = " + bi); return -1; } //if (c != 0) { //System.out.println("c = " + c); //} // now all keys are equal return c; } /** * GenPolynomial signum. * @return sign(ldcf(this)). */ public int signum() { if (this.isZERO()) { return 0; } ExpVector t = val.firstKey(); C c = val.get(t); return c.signum(); } /** * Number of variables. * @return ring.nvar. */ public int numberOfVariables() { return ring.nvar; } /** * Leading monomial. * @return first map entry. */ public Map.Entry leadingMonomial() { if (val.isEmpty()) { return null; } //Iterator> ai = val.entrySet().iterator(); //return ai.next(); ExpVector e = val.firstKey(); return new MapEntry(e, val.get(e)); } /** * Leading exponent vector. * @return first exponent. */ public ExpVector leadingExpVector() { if (val.isEmpty()) { return null; // ring.evzero? needs many changes } return val.firstKey(); } /** * Trailing exponent vector. * @return last exponent. */ public ExpVector trailingExpVector() { if (val.isEmpty()) { return null; //ring.evzero; // or null ?; } return val.lastKey(); } /** * Leading base coefficient. * @return first coefficient. */ public C leadingBaseCoefficient() { if (val.isEmpty()) { return ring.coFac.getZERO(); } return val.get(val.firstKey()); } /** * Trailing base coefficient. * @return coefficient of constant term. */ public C trailingBaseCoefficient() { C c = val.get(ring.evzero); if (c == null) { return ring.coFac.getZERO(); } return c; } /** * Coefficient. * @param e exponent. * @return coefficient for given exponent. */ public C coefficient(ExpVector e) { C c = val.get(e); if (c == null) { c = ring.coFac.getZERO(); } return c; } /** * Reductum. * @return this - leading monomial. */ public GenPolynomial reductum() { if (val.size() <= 1) { return ring.getZERO(); } Iterator ai = val.keySet().iterator(); ExpVector lt = ai.next(); lt = ai.next(); // size > 1 SortedMap red = val.tailMap(lt); GenPolynomial r = ring.getZERO().copy(); r.doPutToMap(red); // new GenPolynomial(ring, red); return r; } /** * Degree in variable i. * @return maximal degree in the variable i. */ public long degree(int i) { if (val.isEmpty()) { return -1L; // 0 or -1 ?; } int j; if (i >= 0) { j = ring.nvar - 1 - i; } else { // python like -1 means main variable j = ring.nvar + i; } long deg = 0; if (j < 0) { return deg; } for (ExpVector e : val.keySet()) { long d = e.getVal(j); if (d > deg) { deg = d; } } return deg; } /** * Maximal degree. * @return maximal degree in any variables. */ public long degree() { if (val.isEmpty()) { return -1L; // 0 or -1 ?; } long deg = 0; for (ExpVector e : val.keySet()) { long d = e.maxDeg(); if (d > deg) { deg = d; } } return deg; } /** * Minimal degree. Author: Youssef Elbarbary * @return minimal degree in any variables. */ public long degreeMin() { if (val.isEmpty()) { return -1L; // 0 or -1 ?; } long deg = Long.MAX_VALUE; for (ExpVector e : val.keySet()) { long d = e.minDeg(); if (d < deg) { deg = d; } } return deg; } /** * Total degree. * @return total degree in any variables. */ public long totalDegree() { if (val.isEmpty()) { return -1L; // 0 or -1 ?; } long deg = 0; for (ExpVector e : val.keySet()) { long d = e.totalDeg(); if (d > deg) { deg = d; } } return deg; } /** * Weight degree. * @return weight degree in all variables. */ public long weightDegree() { long[][] w = ring.tord.getWeight(); if (w == null || w.length == 0) { return totalDegree(); // assume weight 1 } if (val.isEmpty()) { return -1L; // 0 or -1 ?; } long deg = 0; for (ExpVector e : val.keySet()) { long d = e.weightDeg(w); if (d > deg) { deg = d; } } return deg; } /** * Leading weight polynomial. * @return polynomial with terms of maximal weight degree. */ public GenPolynomial leadingWeightPolynomial() { if (val.isEmpty()) { return ring.getZERO(); } long[][] w = ring.tord.getWeight(); long maxw = weightDegree(); GenPolynomial wp = ring.getZERO().copy(); for (Map.Entry m : val.entrySet()) { ExpVector e = m.getKey(); long d = e.weightDeg(w); if (d >= maxw) { wp.val.put(e, m.getValue()); } } return wp; } /** * Leading facet normal polynomial. * @param u leading exponent vector. * @param uv exponent vector of facet normal. * @return polynomial with terms of facet normal. */ public GenPolynomial leadingFacetPolynomial(ExpVector u, ExpVector uv) { if (val.isEmpty()) { return ring.getZERO(); } long[] normal = uv.getVal(); GenPolynomial fp = ring.getZERO().copy(); for (Map.Entry m : val.entrySet()) { ExpVector e = m.getKey(); if (u.equals(e)) { fp.val.put(e, m.getValue()); } else { ExpVector v = u.subtract(e); if (v.compareTo(uv) == 0) { // || v.negate().compareTo(uv) == 0 fp.val.put(e, m.getValue()); } else { // check for v parallel to uv long ab = v.weightDeg(normal); //scalarProduct(v, uv); long a = v.weightDeg(v.getVal()); //scalarProduct(v, v); long b = uv.weightDeg(normal); //scalarProduct(uv, uv); if (ab * ab == a * b) { // cos == 1 fp.val.put(e, m.getValue()); if (logger.isInfoEnabled()) { logger.info("ab = {}, a = {}, b = {}, u = {}, e = {}, v = {}", ab, a, b, u, e, v); } } } } } return fp; } /** * Is GenPolynomial<C> homogeneous with respect to a weight. * @return true, if this is weight homogeneous, else false. */ public boolean isWeightHomogeneous() { if (val.size() <= 1) { return true; } long[][] w = ring.tord.getWeight(); if (w == null || w.length == 0) { return isHomogeneous(); // assume weights = 1 } long deg = -1; for (ExpVector e : val.keySet()) { if (deg < 0) { deg = e.weightDeg(w); } else if (deg != e.weightDeg(w)) { return false; } } return true; } /** * Maximal degree vector. * @return maximal degree vector of all variables. */ public ExpVector degreeVector() { if (val.isEmpty()) { return null; //deg; } ExpVector deg = ring.evzero; for (ExpVector e : val.keySet()) { deg = deg.lcm(e); } return deg; } /** * Delta of exponent vectors. * @return list of u-v, where u = lt() and v != u in this. */ public List deltaExpVectors() { List de = new ArrayList(val.size()); if (val.isEmpty()) { return de; } ExpVector u = null; for (ExpVector e : val.keySet()) { if (u == null) { u = e; } else { ExpVector v = u.subtract(e); de.add(v); } } return de; } /** * Delta of exponent vectors. * @param u marked ExpVector in this.expVectors * @return list of u-v, where v != u in this.expVectors. */ public List deltaExpVectors(ExpVector u) { List de = new ArrayList(val.size()); if (val.isEmpty()) { return de; } for (ExpVector e : val.keySet()) { ExpVector v = u.subtract(e); if (v.isZERO()) { continue; } de.add(v); } return de; } /** * GenPolynomial maximum norm. * @return ||this|| the maximum of all absolute values of coefficients. */ public C maxNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); if (n.compareTo(x) < 0) { n = x; } } return n; } /** * GenPolynomial sum norm. * @return sum of all absolute values of coefficients. */ public C sumNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); n = n.sum(x); } return n; } /** * GenPolynomial square norm. * @return the sum all squared values of coefficients. */ public C squareNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); x = x.multiply(x); n = n.sum(x); } return n; } /** * GenPolynomial summation. * @param S GenPolynomial. * @return this+S. */ //public > T sum(T /*GenPolynomial*/ S) { public GenPolynomial sum(GenPolynomial S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (this.length() < (3 * S.length()) / 5) { return S.sum(this); // performance } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector e = me.getKey(); C y = me.getValue(); // assert y != null C x = nv.get(e); if (x != null) { x = x.sum(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y); } } return n; } /** * GenPolynomial addition. This method is not very efficient, since this is * copied. * @param a coefficient. * @param e exponent. * @return this + a xe. */ public GenPolynomial sum(C a, ExpVector e) { if (a == null) { return this; } if (a.isZERO()) { return this; } GenPolynomial n = this.copy(); SortedMap nv = n.val; //if ( nv.size() == 0 ) { nv.put(e,a); return n; } C x = nv.get(e); if (x != null) { x = x.sum(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a); } return n; } /** * GenPolynomial addition. This method is not very efficient, since this is * copied. * @param m monomial. * @return this + m. */ public GenPolynomial sum(Monomial m) { return sum(m.coefficient(), m.exponent()); } /** * GenPolynomial addition. This method is not very efficient, since this is * copied. * @param a coefficient. * @return this + a x0. */ public GenPolynomial sum(C a) { return sum(a, ring.evzero); } /** * GenPolynomial destructive summation. * @param S GenPolynomial. */ public void doAddTo(GenPolynomial S) { if (S == null || S.isZERO()) { return; } if (this.isZERO()) { this.val.putAll(S.val); return; } assert (ring.nvar == S.ring.nvar); SortedMap nv = this.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector e = me.getKey(); C y = me.getValue(); // assert y != null C x = nv.get(e); if (x != null) { x = x.sum(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y); } } return; } /** * GenPolynomial destructive summation. * @param a coefficient. * @param e exponent. */ public void doAddTo(C a, ExpVector e) { if (a == null || a.isZERO()) { return; } SortedMap nv = this.val; C x = nv.get(e); if (x != null) { x = x.sum(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a); } return; } /** * GenPolynomial destructive summation. * @param a coefficient. */ public void doAddTo(C a) { doAddTo(a, ring.evzero); } /** * GenPolynomial subtraction. * @param S GenPolynomial. * @return this-S. */ public GenPolynomial subtract(GenPolynomial S) { if (S == null) { return this; } if (S.isZERO()) { return this; } if (this.isZERO()) { return S.negate(); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector e = me.getKey(); C y = me.getValue(); // assert y != null C x = nv.get(e); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y.negate()); } } return n; } /** * GenPolynomial subtraction. This method is not very efficient, since this * is copied. * @param a coefficient. * @param e exponent. * @return this - a xe. */ public GenPolynomial subtract(C a, ExpVector e) { if (a == null || a.isZERO()) { return this; } GenPolynomial n = this.copy(); SortedMap nv = n.val; C x = nv.get(e); if (x != null) { x = x.subtract(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a.negate()); } return n; } /** * GenPolynomial subtraction. This method is not very efficient, since this * is copied. * @param m monomial. * @return this - m. */ public GenPolynomial subtract(Monomial m) { return subtract(m.coefficient(), m.exponent()); } /** * GenPolynomial subtract. This method is not very efficient, since this is * copied. * @param a coefficient. * @return this + a x0. */ public GenPolynomial subtract(C a) { return subtract(a, ring.evzero); } /** * GenPolynomial subtract a multiple. * @param a coefficient. * @param S GenPolynomial. * @return this - a S. */ public GenPolynomial subtractMultiple(C a, GenPolynomial S) { if (a == null || a.isZERO()) { return this; } if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S.multiply(a.negate()); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); C y = me.getValue(); // assert y != null y = a.multiply(y); C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenPolynomial subtract a multiple. * @param a coefficient. * @param e exponent. * @param S GenPolynomial. * @return this - a xe S. */ public GenPolynomial subtractMultiple(C a, ExpVector e, GenPolynomial S) { if (a == null || a.isZERO()) { return this; } if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S.multiply(a.negate(), e); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenPolynomial scale and subtract a multiple. * @param b scale factor. * @param a coefficient. * @param S GenPolynomial. * @return this * b - a S. */ public GenPolynomial scaleSubtractMultiple(C b, C a, GenPolynomial S) { if (a == null || S == null) { return this.multiply(b); } if (a.isZERO() || S.isZERO()) { return this.multiply(b); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiply(a.negate()); //left? } if (b.isONE()) { return subtractMultiple(a, S); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.multiply(b); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); //f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // now y can be zero C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenPolynomial scale and subtract a multiple. * @param b scale factor. * @param a coefficient. * @param e exponent. * @param S GenPolynomial. * @return this * b - a xe S. */ public GenPolynomial scaleSubtractMultiple(C b, C a, ExpVector e, GenPolynomial S) { if (a == null || S == null) { return this.multiply(b); } if (a.isZERO() || S.isZERO()) { return this.multiply(b); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiply(a.negate(), e); } if (b.isONE()) { return subtractMultiple(a, e, S); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.multiply(b); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // now y can be zero C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenPolynomial scale and subtract a multiple. * @param b scale factor. * @param g scale exponent. * @param a coefficient. * @param e exponent. * @param S GenPolynomial. * @return this * a xg - a xe S. */ public GenPolynomial scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e, GenPolynomial S) { if (a == null || S == null) { return this.multiply(b, g); } if (a.isZERO() || S.isZERO()) { return this.multiply(b, g); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiply(a.negate(), e); } if (b.isONE() && g.isZERO()) { return subtractMultiple(a, e, S); } assert (ring.nvar == S.ring.nvar); GenPolynomial n = this.multiply(b, g); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // y can be zero now C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenPolynomial negation, alternative implementation. * @return -this. */ public GenPolynomial negateAlt() { GenPolynomial n = ring.getZERO().copy(); SortedMap v = n.val; for (Map.Entry m : val.entrySet()) { C x = m.getValue(); // != null, 0 v.put(m.getKey(), x.negate()); } return n; } /** * GenPolynomial negation. * @return -this. */ public GenPolynomial negate() { GenPolynomial n = this.copy(); SortedMap v = n.val; for (Map.Entry m : v.entrySet()) { C x = m.getValue(); // != null, 0 m.setValue(x.negate()); // okay } return n; } /** * GenPolynomial absolute value, i.e. leadingCoefficient > 0. * @return abs(this). */ public GenPolynomial abs() { if (leadingBaseCoefficient().signum() < 0) { return this.negate(); } return this; } /** * GenPolynomial multiplication. * @param S GenPolynomial. * @return this*S. */ public GenPolynomial multiply(GenPolynomial S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == S.ring.nvar); if (this instanceof GenSolvablePolynomial && S instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; GenSolvablePolynomial Sp = (GenSolvablePolynomial) S; return T.multiply(Sp); } GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); ExpVector e1 = m1.getKey(); for (Map.Entry m2 : S.val.entrySet()) { C c2 = m2.getValue(); ExpVector e2 = m2.getKey(); C c = c1.multiply(c2); // check non zero if not domain if (!c.isZERO()) { ExpVector e = e1.sum(e2); C c0 = pv.get(e); if (c0 == null) { pv.put(e, c); } else { c0 = c0.sum(c); if (!c0.isZERO()) { pv.put(e, c0); } else { pv.remove(e); } } } } } return p; } /** * GenPolynomial multiplication. Product with coefficient ring element. * @param s coefficient. * @return this*s. */ public GenPolynomial multiply(C s) { if (s == null || s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (this instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; return T.multiply(s); } GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { C a = m.getValue(); ExpVector e = m.getKey(); C c = a.multiply(s); // check non zero if not domain if (!c.isZERO()) { pv.put(e, c); // not m1.setValue( c ) } } return p; } /** * GenPolynomial left multiplication. Left product with coefficient ring * element. * @param s coefficient. * @return s*this. */ public GenPolynomial multiplyLeft(C s) { if (s == null || s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (this instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(s) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; return T.multiplyLeft(s); } GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { C a = m.getValue(); ExpVector e = m.getKey(); C c = s.multiply(a); if (!c.isZERO()) { pv.put(e, c); } } return p; } /** * GenPolynomial monic, i.e. leadingCoefficient == 1. If leadingCoefficient * is not invertible returns this unmodified. * @return monic(this). */ public GenPolynomial monic() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lc = "+lc); return this; } C lm = lc.inverse(); return multiplyLeft(lm); } /** * GenPolynomial monic, i.e. leadingCoefficient == 1. If leadingCoefficient * is not invertible returns this unmodified. * @return monic(this). */ public GenPolynomial monicRight() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lc = "+lc); return this; } C lm = lc.inverse(); return multiply(lm); } /** * GenPolynomial multiplication. Product with ring element and exponent * vector. * @param s coefficient. * @param e exponent. * @return this * s xe. */ public GenPolynomial multiply(C s, ExpVector e) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (e == null) { // exp vector of zero polynomial return ring.getZERO(); } if (this instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(s,e) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; return T.multiply(s, e); } GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); ExpVector e1 = m1.getKey(); C c = c1.multiply(s); // check non zero if not domain if (!c.isZERO()) { ExpVector e2 = e1.sum(e); pv.put(e2, c); } } return p; } /** * GenPolynomial multiplication. Product with exponent vector. * @param e exponent (!= null). * @return this * xe. */ public GenPolynomial multiply(ExpVector e) { if (e == null) { // exp vector of zero polynomial return ring.getZERO(); } // assert e != null. This is seldom allowed. if (this.isZERO()) { return this; } if (this instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(e) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; return T.multiply(e); } GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); ExpVector e1 = m1.getKey(); ExpVector e2 = e1.sum(e); pv.put(e2, c1); } return p; } /** * GenPolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m. */ public GenPolynomial multiply(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * GenPolynomial division. Division by coefficient ring element. Fails, if * exact division is not possible. * @param s coefficient. * @return s**(-1) * this. */ public GenPolynomial divide(C s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero"); } if (this.isZERO()) { return this; } //C t = s.inverse(); //return multiply(t); GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { ExpVector e = m.getKey(); C c1 = m.getValue(); C c = c1.divide(s); if (debug) { C x = c1.remainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); } pv.put(e, c); // not m1.setValue( c ) } return p; } /** * GenPolynomial right division. Right division by coefficient ring element. * Fails, if exact division is not possible. * @param s coefficient. * @return this * s**(-1). */ public GenPolynomial rightDivideCoeff(C s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero"); } if (this.isZERO()) { return this; } //C t = s.inverse(); //return multiply(t); GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { ExpVector e = m.getKey(); C c1 = m.getValue(); C c = c1.rightDivide(s); if (debug) { C x = c1.rightRemainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); } pv.put(e, c); // not m1.setValue( c ) } return p; } /** * GenPolynomial left division. Left division by coefficient ring element. * Fails, if exact division is not possible. * @param s coefficient. * @return s**(-1) * this. */ public GenPolynomial leftDivideCoeff(C s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero"); } if (this.isZERO()) { return this; } //C t = s.inverse(); //return multiply(t); GenPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { ExpVector e = m.getKey(); C c1 = m.getValue(); C c = c1.leftDivide(s); if (debug) { C x = c1.leftRemainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { throw new ArithmeticException("no exact division: " + c1 + "/" + s + ", in " + this); } pv.put(e, c); // not m1.setValue( c ) } return p; } /** * GenPolynomial coefficient primitive part. Division by * gcd of coefficients. * @return this/gcd(coeff(this)). */ public GenPolynomial coeffPrimitivePart() { if (this.isZERO() || this.isONE()) { return this; } C s = ring.coFac.getZERO(); for (C c : val.values()) { s = s.gcd(c); } return divide(s).abs(); } /** * GenPolynomial division with remainder. Fails, if exact division by * leading base coefficient is not possible. Meaningful only for univariate * polynomials over fields, but works in any case. * @param S nonzero GenPolynomial with invertible leading coefficient. * @return [ quotient , remainder ] with this = quotient * S + remainder and * deg(remainder) < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ @SuppressWarnings("unchecked") public GenPolynomial[] quotientRemainder(GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException("lbcf not invertible " + c); } C ci = c.inverse(); assert (ring.nvar == S.ring.nvar); ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial q = ring.getZERO().copy(); GenPolynomial r = this.copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); ExpVector g = f.subtract(e); a = a.multiply(ci); q = q.sum(a, g); h = S.multiply(a, g); r = r.subtract(h); assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f; } else { break; } } GenPolynomial[] ret = new GenPolynomial[2]; ret[0] = q; ret[1] = r; return ret; } /** * GenPolynomial division. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenPolynomial with invertible leading coefficient. * @return quotient with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ public GenPolynomial divide(GenPolynomial S) { if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; GenSolvablePolynomial Sp = (GenSolvablePolynomial) S; return T.quotientRemainder(Sp)[0]; } return quotientRemainder(S)[0]; } /** * GenPolynomial remainder. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenPolynomial with invertible leading coefficient. * @return remainder with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ public GenPolynomial remainder(GenPolynomial S) { if (this instanceof GenSolvablePolynomial || S instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); //logger.debug("warn: wrong method dispatch in JRE multiply(S) - trying to fix"); GenSolvablePolynomial T = (GenSolvablePolynomial) this; GenSolvablePolynomial Sp = (GenSolvablePolynomial) S; return T.quotientRemainder(Sp)[1]; } if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException("lbc not invertible " + c); } C ci = c.inverse(); assert (ring.nvar == S.ring.nvar); ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial r = this.copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); ExpVector g = f.subtract(e); //logger.info("red div = {}", e); a = a.multiply(ci); h = S.multiply(a, g); r = r.subtract(h); assert (!f.equals(r.leadingExpVector())) : "leadingExpVector not descending: " + f; } else { break; } } return r; } /** * GenPolynomial greatest common divisor. Only for univariate polynomials * over fields. * @param S GenPolynomial. * @return gcd(this,S). */ public GenPolynomial gcd(GenPolynomial S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.nvar != 1) { throw new IllegalArgumentException("not univariate polynomials" + ring); } GenPolynomial x; GenPolynomial q = this; GenPolynomial r = S; while (!r.isZERO()) { x = q.remainder(r); q = r; r = x; } return q.monic(); // normalize } /** * GenPolynomial extended greatest common divisor. Only for univariate * polynomials over fields. * @param S GenPolynomial. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public GenPolynomial[] egcd(GenPolynomial S) { GenPolynomial[] ret = new GenPolynomial[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; ret[1] = this.ring.getONE(); ret[2] = this.ring.getZERO(); return ret; } if (this.isZERO()) { ret[0] = S; ret[1] = this.ring.getZERO(); ret[2] = this.ring.getONE(); return ret; } if (ring.nvar != 1) { throw new IllegalArgumentException( this.getClass().getName() + " not univariate polynomials" + ring); } if (this.isConstant() && S.isConstant()) { C t = this.leadingBaseCoefficient(); C s = S.leadingBaseCoefficient(); C[] gg = t.egcd(s); //System.out.println("coeff gcd = " + Arrays.toString(gg)); GenPolynomial z = this.ring.getZERO(); ret[0] = z.sum(gg[0]); ret[1] = z.sum(gg[1]); ret[2] = z.sum(gg[2]); return ret; } GenPolynomial[] qr; GenPolynomial q = this; GenPolynomial r = S; GenPolynomial c1 = ring.getONE().copy(); GenPolynomial d1 = ring.getZERO().copy(); GenPolynomial c2 = ring.getZERO().copy(); GenPolynomial d2 = ring.getONE().copy(); GenPolynomial x1; GenPolynomial x2; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiplyLeft(h); c1 = c1.multiplyLeft(h); c2 = c2.multiplyLeft(h); } //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); ret[0] = q; ret[1] = c1; ret[2] = c2; return ret; } /** * GenPolynomial half extended greatest common divisor. Only for univariate * polynomials over fields. * @param S GenPolynomial. * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public GenPolynomial[] hegcd(GenPolynomial S) { GenPolynomial[] ret = new GenPolynomial[2]; ret[0] = null; ret[1] = null; if (S == null || S.isZERO()) { ret[0] = this; ret[1] = this.ring.getONE(); return ret; } if (this.isZERO()) { ret[0] = S; return ret; } if (ring.nvar != 1) { throw new IllegalArgumentException( this.getClass().getName() + " not univariate polynomials" + ring); } GenPolynomial[] qr; GenPolynomial q = this; GenPolynomial r = S; GenPolynomial c1 = ring.getONE().copy(); GenPolynomial d1 = ring.getZERO().copy(); GenPolynomial x1; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); c1 = d1; d1 = x1; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiplyLeft(h); c1 = c1.multiplyLeft(h); } //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); ret[0] = q; ret[1] = c1; return ret; } /** * GenPolynomial inverse. Required by RingElem. Throws not invertible * exception. */ public GenPolynomial inverse() { if (isUnit()) { // only possible if ldbcf is unit C c = leadingBaseCoefficient().inverse(); return ring.getONE().multiply(c); } throw new NotInvertibleException("element not invertible " + this + " :: " + ring); } /** * GenPolynomial modular inverse. Only for univariate polynomials over * fields. * @param m GenPolynomial. * @return a with with a*this = 1 mod m. */ public GenPolynomial modInverse(GenPolynomial m) { if (this.isZERO()) { throw new NotInvertibleException("zero is not invertible"); } GenPolynomial[] hegcd = this.hegcd(m); GenPolynomial a = hegcd[0]; if (!a.isUnit()) { // gcd != 1 throw new AlgebraicNotInvertibleException("element not invertible, gcd != 1", m, a, m.divide(a)); } GenPolynomial b = hegcd[1]; if (b.isZERO()) { // when m divides this, e.g. m.isUnit() throw new NotInvertibleException("element not invertible, divisible by modul"); } return b; } /** * GenPolynomial greatest common divisor. Only for univariate polynomials * over fields. * @param S GenPolynomial. * @return right gcd(this,S). */ public GenPolynomial rightGcd(GenPolynomial S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.nvar != 1) { throw new IllegalArgumentException("not univariate polynomials" + ring); } GenPolynomial x; GenPolynomial q = this; GenPolynomial r = S; while (!r.isZERO()) { x = q.rightRemainder(r); q = r; r = x; } return q.monicRight(); // normalize } /** * Extend variables. Used e.g. in module embedding. Extend all ExpVectors by * i elements and multiply by x_j^k. * @param pfac extended polynomial ring factory (by i variables). * @param j index of variable to be used for multiplication. * @param k exponent for x_j. * @return extended polynomial. */ public GenPolynomial extend(GenPolynomialRing pfac, int j, long k) { if (ring.equals(pfac)) { // nothing to do return this; } GenPolynomial Cp = pfac.getZERO().copy(); if (this.isZERO()) { return Cp; } int i = pfac.nvar - ring.nvar; Map C = Cp.val; //getMap(); Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector f = e.extend(i, j, k); C.put(f, a); } return Cp; } /** * Extend lower variables. Used e.g. in module embedding. Extend all * ExpVectors by i lower elements and multiply by x_j^k. * @param pfac extended polynomial ring factory (by i variables). * @param j index of variable to be used for multiplication. * @param k exponent for x_j. * @return extended polynomial. */ public GenPolynomial extendLower(GenPolynomialRing pfac, int j, long k) { if (ring.equals(pfac)) { // nothing to do return this; } GenPolynomial Cp = pfac.getZERO().copy(); if (this.isZERO()) { return Cp; } int i = pfac.nvar - ring.nvar; Map C = Cp.val; //getMap(); Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector f = e.extendLower(i, j, k); C.put(f, a); } return Cp; } /** * Contract variables. Used e.g. in module embedding. Remove i elements of * each ExpVector. * @param pfac contracted polynomial ring factory (by i variables). * @return Map of exponents and contracted polynomials. Note: could * return SortedMap */ public Map> contract(GenPolynomialRing pfac) { GenPolynomial zero = pfac.getZERO(); //not pfac.coFac; TermOrder t = new TermOrder(TermOrder.INVLEX); Map> B = new TreeMap>( t.getAscendComparator()); if (this.isZERO()) { return B; } int i = ring.nvar - pfac.nvar; Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector f = e.contract(0, i); ExpVector g = e.contract(i, e.length() - i); GenPolynomial p = B.get(f); if (p == null) { p = zero; } p = p.sum(a, g); B.put(f, p); } return B; } /** * Contract variables to coefficient polynomial. Remove i elements of each * ExpVector, removed elements must be zero. * @param pfac contracted polynomial ring factory (by i variables). * @return contracted coefficient polynomial. */ public GenPolynomial contractCoeff(GenPolynomialRing pfac) { Map> ms = contract(pfac); GenPolynomial c = pfac.getZERO(); for (Map.Entry> m : ms.entrySet()) { if (m.getKey().isZERO()) { c = m.getValue(); } else { throw new RuntimeException("wrong coefficient contraction " + m + ", pol = " + c); } } return c; } /** * Extend univariate to multivariate polynomial. This is an univariate * polynomial in variable i of the polynomial ring, it is extended to the * given polynomial ring. * @param pfac extended polynomial ring factory. * @param i index of the variable of this polynomial in pfac. * @return extended multivariate polynomial. */ public GenPolynomial extendUnivariate(GenPolynomialRing pfac, int i) { if (i < 0 || pfac.nvar < i) { throw new IllegalArgumentException("index " + i + "out of range " + pfac.nvar); } if (ring.nvar != 1) { throw new IllegalArgumentException("polynomial not univariate " + ring.nvar); } if (this.isONE()) { return pfac.getONE(); } int j = pfac.nvar - 1 - i; GenPolynomial Cp = pfac.getZERO().copy(); if (this.isZERO()) { return Cp; } Map C = Cp.val; //getMap(); Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); long n = e.getVal(0); C a = y.getValue(); ExpVector f = ExpVector.create(pfac.nvar, j, n); C.put(f, a); // assert not contained } return Cp; } /** * Make homogeneous. * @param pfac extended polynomial ring factory (by 1 variable). * @return homogeneous polynomial. */ public GenPolynomial homogenize(GenPolynomialRing pfac) { if (ring.equals(pfac)) { // not implemented throw new UnsupportedOperationException("case with same ring not implemented"); } GenPolynomial Cp = pfac.getZERO().copy(); if (this.isZERO()) { return Cp; } long deg = totalDegree(); //int i = pfac.nvar - ring.nvar; Map C = Cp.val; //getMap(); Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); long d = deg - e.totalDeg(); ExpVector f = e.extend(1, 0, d); C.put(f, a); } return Cp; } /** * Dehomogenize. * @param pfac contracted polynomial ring factory (by 1 variable). * @return in homogeneous polynomial. */ public GenPolynomial deHomogenize(GenPolynomialRing pfac) { if (ring.equals(pfac)) { // not implemented throw new UnsupportedOperationException("case with same ring not implemented"); } GenPolynomial Cp = pfac.getZERO().copy(); if (this.isZERO()) { return Cp; } Map C = Cp.val; //getMap(); Map A = val; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector f = e.contract(1, pfac.nvar); C.put(f, a); } return Cp; } /** * Reverse variables. Used e.g. in opposite rings. * @return polynomial with reversed variables. */ public GenPolynomial reverse(GenPolynomialRing oring) { GenPolynomial Cp = oring.getZERO().copy(); if (this.isZERO()) { return Cp; } int k = -1; if (oring.tord.getEvord2() != 0 && oring.partial) { k = oring.tord.getSplit(); } Map C = Cp.val; //getMap(); Map A = val; ExpVector f; for (Map.Entry y : A.entrySet()) { ExpVector e = y.getKey(); if (k >= 0) { f = e.reverse(k); } else { f = e.reverse(); } C a = y.getValue(); C.put(f, a); } if (oring.coFac.isCommutative()) { return Cp; } if (oring.coFac.getONE() instanceof StarRingElem) { Cp = PolyUtil. conjugateCoeff(Cp); } // other coFac ignore return Cp; } /** * GenPolynomial inflate. Only for univariate polynomials over fields. * @param e exponent. * @return this(x**e) */ public GenPolynomial inflate(long e) { if (e == 1) { return this; } if (this.isZERO()) { return this; } if (ring.nvar != 1) { throw new IllegalArgumentException( this.getClass().getName() + " not univariate polynomial" + ring); } GenPolynomial Cp = ring.getZERO().copy(); Map C = Cp.val; //getMap(); Map A = val; ExpVector f; for (Map.Entry y : A.entrySet()) { ExpVector g = y.getKey(); f = g.scalarMultiply(e); C a = y.getValue(); C.put(f, a); } return Cp; } /** * Iterator over coefficients. * @return val.values().iterator(). */ public Iterator coefficientIterator() { return val.values().iterator(); } /** * Iterator over exponents. * @return val.keySet().iterator(). */ public Iterator exponentIterator() { return val.keySet().iterator(); } /** * Iterator over monomials. * @return a PolyIterator. */ public Iterator> iterator() { return new PolyIterator(val); } /** * Spliterator over monomials. * @return a PolySpliterator. */ public Spliterator> spliterator() { return new PolySpliterator(val); } /** * Map a unary function to the coefficients. * @param f evaluation functor. * @return new polynomial with coefficients f(this.coefficients). */ public GenPolynomial map(final UnaryFunctor f) { GenPolynomial n = ring.getZERO().copy(); SortedMap nv = n.val; for (Map.Entry m : this.val.entrySet()) { //logger.info("m = {}", m); C c = f.eval(m.getValue()); if (c != null && !c.isZERO()) { nv.put(m.getKey(), c); } } return n; } /* * Map a unary function to the coefficients. * @param f evaluation functor. * @return new polynomial with coefficients f(this.coefficients). */ GenPolynomial mapWrong(final UnaryFunctor f) { GenPolynomial n = this.copy(); SortedMap nv = n.val; for (Map.Entry m : nv.entrySet()) { //logger.info("m = {}", m); C c = f.eval(m.getValue()); if (c != null && !c.isZERO()) { m.setValue(c); // not okay } else { // not possible nv.remove(m.getKey()); } } return n; } /** * Map a function to the polynomial stream entries. * @param f evaluation functor. * @return new polynomial with f(this.entries). */ public GenPolynomial mapOnStream( final Function, ? extends Map.Entry> f) { return mapOnStream(f, false); } /** * Map a function to the polynomial stream entries. * @param f evaluation functor. * @return new polynomial with f(this.entries). */ public GenPolynomial mapOnStream( final Function, ? extends Map.Entry> f, boolean parallel) { Stream> st; if (parallel) { st = val.entrySet().parallelStream(); } else { st = val.entrySet().stream(); } Map m = st.map(f).filter(me -> !me.getValue().isZERO()) .collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue())); //Stream> stp = st.map(f); //Stream> stf = stp.filter(me -> !me.getValue().isZERO()); //Map m = stf.collect(Collectors.toMap(me -> me.getKey(), me -> me.getValue())); return new GenPolynomial(ring, m); } /** * Returns the number of bits in the representation of this polynomial. * @return number of bits in the representation of this polynomial, * including sign bits. */ public long bitLength() { if (blen < 0L) { long n = 0L; for (Monomial m : this) { n += m.e.bitLength(); //n += m.c.bitLength(); // todo add bitLength to Element try { // hack Method method = m.c.getClass().getMethod("bitLength", (Class[]) null); n += (Long) method.invoke(m.c, (Object[]) null); } catch (NoSuchMethodException e) { logger.error("Exception, class: {}", m.c.getClass()); throw new RuntimeException(e); } catch (IllegalAccessException e) { logger.error("Exception, class: {}", m.c.getClass()); throw new RuntimeException(e); } catch (InvocationTargetException e) { logger.error("Exception, class: {}", m.c.getClass()); throw new RuntimeException(e); } } blen = n; //System.out.println("bitLength(poly) = " + blen); } return blen; } //private void writeObject(java.io.ObjectOutputStream out) throws IOException { // out.defaultWriteObject(); //} private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); blen = -1; hash = -1; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenPolynomialRing.java000066400000000000000000001425411445075545500251110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.SortedMap; import java.util.concurrent.atomic.AtomicLong; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.PreemptStatus; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.StarRingElem; import edu.jas.structure.RingFactory; import edu.jas.util.CartesianProduct; import edu.jas.util.CartesianProductInfinite; import edu.jas.util.LongIterable; import edu.jas.vector.GenVector; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; /** * GenPolynomialRing generic polynomial factory. It implements RingFactory for * n-variate ordered polynomials over coefficients C. The variables commute with * each other and with the coefficients. For non-commutative coefficients some * care is taken to respect the multiplication order. * * Almost immutable object, except variable names. * @param coefficient type * @author Heinz Kredel */ public class GenPolynomialRing> implements RingFactory>, Iterable> { /** * The factory for the coefficients. */ public final RingFactory coFac; /** * The number of variables. */ public final int nvar; /** * The term order. */ public final TermOrder tord; /** * True for partially reversed variables. */ protected boolean partial; /** * The names of the variables. This value can be modified. */ protected String[] vars; /** * Counter to distinguish new variables. */ private static AtomicLong varCounter = new AtomicLong(0L); /** * The constant polynomial 0 for this ring. */ public /*final*/ GenPolynomial ZERO; // volatile not meaningful by DL /** * The constant polynomial 1 for this ring. */ public /*final*/ GenPolynomial ONE; // volatile not meaningful by DL /** * The constant exponent vector 0 for this ring. */ public final ExpVector evzero; // volatile not meaningful by DL /** * A default random sequence generator. */ protected final static Random random = new Random(); /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * Log4j logger object. */ private static final Logger logger = LogManager.getLogger(GenPolynomialRing.class); /** * Count for number of polynomial creations. */ static int creations = 0; /** * Flag to enable if preemptive interrupt is checked. */ volatile boolean checkPreempt = PreemptStatus.isAllowed(); /** * The constructor creates a polynomial factory object with the default term * order. * @param cf factory for coefficients of type C. * @param n number of variables. */ public GenPolynomialRing(RingFactory cf, int n) { this(cf, n, new TermOrder(), null); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public GenPolynomialRing(RingFactory cf, int n, TermOrder t) { this(cf, n, t, null); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public GenPolynomialRing(RingFactory cf, String[] v) { this(cf, v.length, v); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param n number of variables. * @param v names for the variables. */ public GenPolynomialRing(RingFactory cf, int n, String[] v) { this(cf, n, new TermOrder(), v); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public GenPolynomialRing(RingFactory cf, TermOrder t, String[] v) { this(cf, v.length, t, v); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param v names for the variables. * @param t a term order. */ public GenPolynomialRing(RingFactory cf, String[] v, TermOrder t) { this(cf, v.length, t, v); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public GenPolynomialRing(RingFactory cf, int n, TermOrder t, String[] v) { coFac = cf; nvar = n; tord = t; partial = false; if (v == null) { vars = null; } else { vars = Arrays.copyOf(v, v.length); // > Java-5 } C coeff = coFac.getONE(); synchronized (this) { evzero = ExpVector.create(nvar); ZERO = new GenPolynomial(this); ONE = new GenPolynomial(this, coeff, evzero); } //logger.debug("ZERO {} {}", ZERO.toString(), ZERO.val); //System.out.println("thread@ZERO: " + Thread.currentThread()); if (vars == null) { if (PrettyPrint.isTrue()) { vars = newVars("x", nvar); } } else { if (vars.length != nvar) { throw new IllegalArgumentException("incompatible variable size " + vars.length + ", " + nvar); } // addVars(vars); } } /** * The constructor creates a polynomial factory object with the the same * term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ. * @param cf factory for coefficients of type C. * @param o other polynomial ring. */ public GenPolynomialRing(RingFactory cf, GenPolynomialRing o) { this(cf, o.nvar, o.tord, o.vars); } /** * The constructor creates a polynomial factory object with the the same * coefficient factory, number of variables and variable names as the given * polynomial factory, only the term order differs. * @param to term order. * @param o other polynomial ring. */ public GenPolynomialRing(GenPolynomialRing o, TermOrder to) { this(o.coFac, o.nvar, to, o.vars); } /** * Copy this factory. * @return a clone of this. */ public GenPolynomialRing copy() { return new GenPolynomialRing(coFac, this); } /** * Get the String representation. * @see java.lang.Object#toString() */ @SuppressWarnings("cast") @Override public String toString() { String res = null; if (PrettyPrint.isTrue()) { // wrong: && coFac != null String scf = coFac.getClass().getSimpleName(); if (coFac instanceof AlgebraicNumberRing) { AlgebraicNumberRing an = (AlgebraicNumberRing) coFac; res = "AN[ (" + an.ring.varsToString() + ") (" + an.toString() + ") ]"; } if (coFac instanceof GenPolynomialRing) { GenPolynomialRing rf = (GenPolynomialRing) coFac; //String[] v = rf.vars; //RingFactory cf = rf.coFac; //String cs; //if (cf instanceof ModIntegerRing) { // cs = cf.toString(); //} else { // cs = " " + cf.getClass().getSimpleName(); //} //res = "IntFunc" + "{" + cs + "( " + rf.varsToString() + " )" + " } "; res = "IntFunc" + "( " + rf.toString() + " )"; } if (((Object) coFac) instanceof ModIntegerRing) { ModIntegerRing mn = (ModIntegerRing) ((Object) coFac); res = "Mod " + mn.getModul() + " "; } if (res == null) { res = coFac.toString(); if (res.matches("[0-9].*")) { res = scf; } } res += "( " + varsToString() + " ) " + tord.toString() + " "; } else { res = this.getClass().getSimpleName() + "[ " + coFac.toString() + " "; if (coFac instanceof AlgebraicNumberRing) { AlgebraicNumberRing an = (AlgebraicNumberRing) coFac; res = "AN[ (" + an.ring.varsToString() + ") (" + an.modul + ") ]"; } if (coFac instanceof GenPolynomialRing) { GenPolynomialRing rf = (GenPolynomialRing) coFac; //String[] v = rf.vars; //RingFactory cf = rf.coFac; //String cs; //if (cf instanceof ModIntegerRing) { // cs = cf.toString(); //} else { // cs = " " + cf.getClass().getSimpleName(); //} //res = "IntFunc{ " + cs + "( " + rf.varsToString() + " )" + " } "; res = "IntFunc" + "( " + rf.toString() + " )"; } if (((Object) coFac) instanceof ModIntegerRing) { ModIntegerRing mn = (ModIntegerRing) ((Object) coFac); res = "Mod " + mn.getModul() + " "; } //res += ", " + nvar + ", " + tord.toString() + ", " + varsToString() + ", " + partial + " ]"; res += "( " + varsToString() + " ) " + tord.toString() + " ]"; } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("PolyRing.new("); break; case Python: default: s.append("PolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\""); String to = tord.toScript(); s.append("," + to); s.append(")"); return s.toString(); } /** * Get a scripting compatible string representation of an ExpVector of this * ring. * @param e exponent vector * @return script compatible representation for the ExpVector. */ public String toScript(ExpVector e) { if (e == null) { return "null"; } if (vars != null) { return e.toScript(vars); } return e.toScript(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof GenPolynomialRing)) { return false; } GenPolynomialRing oring = (GenPolynomialRing) other; if (nvar != oring.nvar) { return false; } if (!coFac.equals(oring.coFac)) { return false; } if (!tord.equals(oring.tord)) { return false; } // same variables required ? if (!Arrays.deepEquals(vars, oring.vars)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = (nvar << 27); h += (coFac.hashCode() << 11); h += (tord.hashCode() << 9); h += Arrays.hashCode(vars); //System.out.println("GenPolynomialRing.hashCode: " + h); return h; } /** * Get the number of polynomial creations. * @return creations. */ public int getCreations() { return creations; } /** * Get the variable names. * @return vars. */ public String[] getVars() { return Arrays.copyOf(vars, vars.length); // > Java-5 } /** * Set the variable names. * @return old vars. */ public String[] setVars(String[] v) { if (v.length != nvar) { throw new IllegalArgumentException( "v not matching number of variables: " + Arrays.toString(v) + ", nvar " + nvar); } String[] t = vars; vars = Arrays.copyOf(v, v.length); // > Java-5 return t; } /** * Get a String representation of the variable names. * @return names separated by commas. */ public String varsToString() { if (vars == null) { return "#" + nvar; } //return Arrays.toString(vars); return ExpVector.varsToString(vars); } /** * Get the zero element from the coefficients. * @return 0 as C. */ public C getZEROCoefficient() { return coFac.getZERO(); } /** * Get the one element from the coefficients. * @return 1 as C. */ public C getONECoefficient() { return coFac.getONE(); } /** * Get the zero element. * @return 0 as GenPolynomial. */ public synchronized GenPolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 GenPolynomial x = ZERO; ZERO = new GenPolynomial(this); logger.info("warn: ZERO@get |{}| wrong fix to {}", x, ZERO); } return ZERO; } /** * Get the one element. * @return 1 as GenPolynomial. */ public synchronized GenPolynomial getONE() { if (ONE == null || !ONE.isONE()) { ONE = new GenPolynomial(this, coFac.getONE(), evzero); logger.info("warn: ONE@get {}", ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return coFac.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return coFac.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (coFac.isField() && nvar == 0) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Get a (constant) GenPolynomial<C> element from a coefficient value. * @param a coefficient. * @return a GenPolynomial<C>. */ public GenPolynomial valueOf(C a) { return new GenPolynomial(this, a); } /** * Get a GenPolynomial<C> element from an exponent vector. * @param e exponent vector. * @return a GenPolynomial<C>. */ public GenPolynomial valueOf(ExpVector e) { if (e == null) { return getZERO(); } return new GenPolynomial(this, coFac.getONE(), e); } /** * Get a GenPolynomial<C> element from a list of exponent vectors. * @param E list of exponent vector. * @return a GenPolynomial<C>. */ public List> valueOf(Iterable E) { if (E == null) { return null; } List> P = new ArrayList>(); //E.size()); for (ExpVector e : E) { GenPolynomial p = valueOf(e); P.add(p); } return P; } /** * Get a GenPolynomial<C> element from a coefficient and an exponent * vector. * @param a coefficient. * @param e exponent vector. * @return a GenPolynomial<C>. */ public GenPolynomial valueOf(C a, ExpVector e) { return new GenPolynomial(this, a, e); } /** * Get a GenPolynomial<C> element from a monomial. * @param m monomial. * @return a GenPolynomial<C>. */ public GenPolynomial valueOf(Monomial m) { return new GenPolynomial(this, m.c, m.e); } /** * Get a (constant) GenPolynomial<C> element from a long value. * @param a long. * @return a GenPolynomial<C>. */ public GenPolynomial fromInteger(long a) { return new GenPolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) GenPolynomial<C> element from a BigInteger value. * @param a BigInteger. * @return a GenPolynomial<C>. */ public GenPolynomial fromInteger(BigInteger a) { return new GenPolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a GenPolynomial<C> from a GenVector<C>. * @param a GenVector<C>. * @return a GenPolynomial<C>. */ public GenPolynomial fromVector(GenVector a) { if (a == null || a.isZERO()) { return ZERO; } if (nvar != 1) { throw new IllegalArgumentException("no univariate polynomial ring"); } GenPolynomial ret = copy(ZERO); SortedMap tm = ret.val; long i = -1; for (C m : a.val) { i++; if (m.isZERO()) { continue; } ExpVector e = ExpVector.create(1, 0, i); tm.put(e, m); } return ret; } /** * Random polynomial. Generates a random polynomial with k = 5, l = n, d = * (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random polynomial. */ public GenPolynomial random(int n) { return random(n, random); } /** * Random polynomial. Generates a random polynomial with k = 5, l = n, d = * n, q = (nvar == 1) ? 0.5 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenPolynomial random(int n, Random rnd) { if (nvar == 1) { return random(3, n, n, 0.5f, rnd); } return random(3, n, n, 0.3f, rnd); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random polynomial. */ public GenPolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenPolynomial random(int k, int l, int d, float q, Random rnd) { GenPolynomial r = getZERO(); //.clone() or copy( ZERO ); ExpVector e; C a; // add l random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = r.sum(a, e); // somewhat inefficient but clean //System.out.println("e = " + e + " a = " + a); } // System.out.println("r = " + r); return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public GenPolynomial copy(GenPolynomial c) { //System.out.println("GP copy = " + this); return new GenPolynomial(this, c.val); } /** * Copy polynomial list. * @param L polynomial list * @return a copy of L in this ring. */ public List> copy(List> L) { if (L == null) { return L; } List> R = new ArrayList>(L.size()); for (GenPolynomial a : L) { R.add(copy(a)); } return R; } /** * Parse a polynomial with the use of GenPolynomialTokenizer. * @param s String. * @return GenPolynomial from s. */ public GenPolynomial parse(String s) { String val = s; if (!s.contains("|")) { val = val.replace("{", "").replace("}", ""); } return parse(new StringReader(val)); } /** * Parse a polynomial with the use of GenPolynomialTokenizer. * @param r Reader. * @return next GenPolynomial from r. */ @SuppressWarnings({ "unchecked", "cast" }) public GenPolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); GenPolynomial p = null; try { p = (GenPolynomial) pt.nextPolynomial(); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate polynomial in a given variable with given exponent. * @param x the name of a variable. * @return x as univariate polynomial. */ public GenPolynomial univariate(String x) { return univariate(x, 1L); } /** * Generate univariate polynomial in a given variable with given exponent. * @param x the name of the variable. * @param e the exponent of the variable. * @return x^e as univariate polynomial. */ public GenPolynomial univariate(String x, long e) { if (vars == null) { // should not happen throw new IllegalArgumentException("no variables defined for polynomial ring"); } if (x == null || x.isEmpty()) { throw new IllegalArgumentException("no variable name given"); } int i; for (i = 0; i < vars.length; i++) { if (x.equals(vars[i])) { // use HashMap or TreeMap break; } } if (i >= vars.length) { throw new IllegalArgumentException("variable '" + x + "' not defined in polynomial ring"); } return univariate(0, nvar - i - 1, e); } /** * Generate univariate polynomial in a given variable. * @param i the index of the variable. * @return X_i as univariate polynomial. */ public GenPolynomial univariate(int i) { return univariate(0, i, 1L); } /** * Generate univariate polynomial in a given variable with given exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as univariate polynomial. */ public GenPolynomial univariate(int i, long e) { return univariate(0, i, e); } /** * Generate univariate polynomial in a given variable with given exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as univariate polynomial. */ public GenPolynomial univariate(int modv, int i, long e) { GenPolynomial p = getZERO(); int r = nvar - modv; if (0 <= i && i < r) { C one = coFac.getONE(); ExpVector f = ExpVector.create(r, i, e); if (modv > 0) { f = f.extend(modv, 0, 0l); } p = p.sum(one, f); } return p; } /** * Get the generating elements excluding the generators for the coefficient * ring. * @return a list of generating elements for this ring. */ public List> getGenerators() { List> univs = univariateList(); List> gens = new ArrayList>(univs.size() + 1); gens.add(getONE()); gens.addAll(univs); return gens; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List cogens = coFac.generators(); List> univs = univariateList(); List> gens = new ArrayList>(univs.size() + cogens.size()); for (C c : cogens) { gens.add(getONE().multiply(c)); } gens.addAll(univs); return gens; } /** * Get a list of the generating elements excluding the module variables. * @param modv number of module variables * @return list of generators for the polynomial ring. */ public List> generators(int modv) { List cogens = coFac.generators(); List> univs = univariateList(modv); List> gens = new ArrayList>(univs.size() + cogens.size()); for (C c : cogens) { gens.add(getONE().multiply(c)); } gens.addAll(univs); return gens; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return (nvar == 0) && coFac.isFinite(); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { GenPolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended polynomial ring factory. */ public GenPolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ public GenPolynomialRing extend(int i, boolean top) { // add module variable names String[] v = newVars("e", i); return extend(v, top); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). * @param vn names for extended variables. * @return extended polynomial ring factory. */ public GenPolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ public GenPolynomialRing extend(String[] vn, boolean top) { if (vn == null || vars == null) { throw new IllegalArgumentException("vn and vars may not be null"); } int i = vn.length; String[] v = new String[vars.length + i]; for (int k = 0; k < vars.length; k++) { v[k] = vars[k]; } for (int k = 0; k < vn.length; k++) { v[vars.length + k] = vn[k]; } TermOrder to = tord.extend(nvar, i, top); GenPolynomialRing pfac = new GenPolynomialRing(coFac, nvar + i, to, v); return pfac; } /** * Extend lower variables. Extend number of variables by i. * @param i number of variables to extend. * @return extended polynomial ring factory. */ public GenPolynomialRing extendLower(int i) { String[] v = newVars("e", i); return extendLower(v); } /** * Extend lower variables. Extend number of variables by length(vn). * @param vn names for extended lower variables. * @return extended polynomial ring factory. */ public GenPolynomialRing extendLower(String[] vn) { return extendLower(vn, false); } /** * Extend lower variables. Extend number of variables by length(vn). * @param vn names for extended lower variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ public GenPolynomialRing extendLower(String[] vn, boolean top) { if (vn == null || vars == null) { throw new IllegalArgumentException("vn and vars may not be null"); } int i = vn.length; String[] v = new String[vars.length + i]; for (int k = 0; k < vn.length; k++) { v[k] = vn[k]; } for (int k = 0; k < vars.length; k++) { v[vn.length + k] = vars[k]; } TermOrder to = tord.extendLower(nvar, i, top); GenPolynomialRing pfac = new GenPolynomialRing(coFac, nvar + i, to, v); return pfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted polynomial ring factory. */ public GenPolynomialRing contract(int i) { String[] v = null; if (vars != null) { v = new String[vars.length - i]; for (int j = 0; j < vars.length - i; j++) { v[j] = vars[j]; } } TermOrder to = tord.contract(i, nvar - i); GenPolynomialRing pfac = new GenPolynomialRing(coFac, nvar - i, to, v); return pfac; } /** * Recursive representation as polynomial with i main variables. * @param i number of main variables. * @return recursive polynomial ring factory. */ public GenPolynomialRing> recursive(int i) { if (i <= 0 || i >= nvar) { throw new IllegalArgumentException("wrong: 0 < " + i + " < " + nvar); } GenPolynomialRing cfac = contract(i); String[] v = null; if (vars != null) { v = new String[i]; int k = 0; for (int j = nvar - i; j < nvar; j++) { v[k++] = vars[j]; } } TermOrder to = tord.contract(0, i); // ?? GenPolynomialRing> pfac = new GenPolynomialRing>(cfac, i, to, v); return pfac; } /** * Distributive representation as polynomial with all main variables. * @return distributive polynomial ring factory. */ @SuppressWarnings("unchecked") public GenPolynomialRing distribute() { if (!(coFac instanceof GenPolynomialRing)) { return this; } RingFactory cf = coFac; RingFactory> cfp = (RingFactory>) cf; GenPolynomialRing cr = (GenPolynomialRing) cfp; GenPolynomialRing pfac; if (cr.vars != null) { pfac = extend(cr.vars); } else { pfac = extend(cr.nvar); } return pfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return polynomial ring factory with reversed variables. */ public GenPolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. The coefficient * ring must be commuative. * @param partial true for partially reversed term orders. * @return polynomial ring factory with reversed variables. */ public GenPolynomialRing reverse(boolean partial) { if (!coFac.isCommutative() && !(coFac.getONE() instanceof StarRingElem)) { //throw new IllegalArgumentException("reverse coefficients must be commutative or StarRing: " + coFac); logger.warn("reverse coefficients should be commutative or StarRing elements: " + coFac); } String[] v = null; if (vars != null) { // vars are not inversed v = new String[vars.length]; int k = tord.getSplit(); if (partial && k < vars.length) { // copy upper for (int j = 0; j < k; j++) { //v[vars.length - k + j] = vars[vars.length - 1 - j]; // reverse upper v[vars.length - k + j] = vars[vars.length - k + j]; } // reverse lower for (int j = 0; j < vars.length - k; j++) { //v[j] = vars[j]; // copy upper v[j] = vars[vars.length - k - j - 1]; } } else { for (int j = 0; j < vars.length; j++) { v[j] = vars[vars.length - 1 - j]; } } //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("v = " + Arrays.toString(v)); } TermOrder to = tord.reverse(partial); GenPolynomialRing pfac = new GenPolynomialRing(coFac, nvar, to, v); pfac.partial = partial; return pfac; } /** * Get PolynomialComparator. * @return polynomial comparator. */ public PolynomialComparator getComparator() { return new PolynomialComparator(tord, false); } /** * Get PolynomialComparator. * @param rev for reverse comparator. * @return polynomial comparator. */ public PolynomialComparator getComparator(boolean rev) { return new PolynomialComparator(tord, rev); } /** * New variable names. Generate new names for variables, * @param prefix name prefix. * @param n number of variables. * @return new variable names. */ public static String[] newVars(String prefix, int n) { String[] vars = new String[n]; for (int i = 0; i < n; i++) { long m = varCounter.getAndIncrement(); vars[i] = prefix + m; } return vars; } /** * New variable names. Generate new names for variables, * @param prefix name prefix. * @return new variable names. */ public String[] newVars(String prefix) { return newVars(prefix, nvar); } /** * New variable names. Generate new names for variables, * @param n number of variables. * @return new variable names. */ public static String[] newVars(int n) { return newVars("x", n); } /** * New variable names. Generate new names for variables, * @return new variable names. */ public String[] newVars() { return newVars(nvar); } /* * Add variable names. * @param vars variable names to be recorded. public static void addVars(String[] vars) { if (vars == null) { return; } // synchronized (knownVars) { // for (int i = 0; i < vars.length; i++) { // knownVars.add(vars[i]); // eventually names 'overwritten' // } // } } */ /** * Permute variable names. * @param vars variable names. * @param P permutation. * @return P(vars). */ public static String[] permuteVars(List P, String[] vars) { if (vars == null || vars.length <= 1) { return vars; } String[] b = new String[vars.length]; int j = 0; for (Integer i : P) { b[j++] = vars[i]; } return b; } /** * Permutation of polynomial ring variables. * @param P permutation. * @return P(this). */ public GenPolynomialRing permutation(List P) { if (nvar <= 1) { return this; } TermOrder tp = tord.permutation(P); if (vars == null) { return new GenPolynomialRing(coFac, nvar, tp); } String[] v1 = new String[vars.length]; for (int i = 0; i < v1.length; i++) { v1[i] = vars[v1.length - 1 - i]; } String[] vp = permuteVars(P, v1); String[] v2 = new String[vp.length]; for (int i = 0; i < vp.length; i++) { v2[i] = vp[vp.length - 1 - i]; } return new GenPolynomialRing(coFac, nvar, tp, v2); } /** * Characteristic polynomial of matrix. * Note: using Faddeev–LeVerrier algorithm * @see https://en.wikipedia.org/wiki/Faddeev%E2%80%93LeVerrier_algorithm * @param A a square matrix. * @return characteristic polynomial of A. */ public GenPolynomial charPolynomial(GenMatrix A) { if (A == null || A.isZERO()) { return ZERO; } if (nvar != 1) { throw new IllegalArgumentException("no univariate polynomial ring"); } GenMatrixRing mfac = A.ring; int n = mfac.rows; java.math.BigInteger c0 = coFac.characteristic(); if (c0.signum() > 0 && c0.compareTo(java.math.BigInteger.valueOf(n)) <= 0) { throw new UnsupportedOperationException("characteristic <= n: " + c0 + " <= " + n); } GenPolynomial ret = copy(ZERO); //SortedMap tm = ret.val; GenMatrix M = mfac.getZERO(); //new GenMatrix(A.ring); GenMatrix I = mfac.getONE(); ExpVector e = ExpVector.create(1, 0, n); C one = coFac.getONE(); ret = ret.sum(one, e); C c = coFac.getONE(); GenMatrix Ms = null; GenMatrix Mp = null, Mc; // M_0 = 0, c_n = 1 // k = 1..n: M_k = A*M_{k-1} + c_{n-k+1}*I, c_{n-k} = -1/k*trace(A*M_k) for (int k = 1; k <= n; k++) { if (Ms == null) { Mp = A.multiply(M); // reuse A*Mp? todo } else { Mp = Ms; } Mc = I.multiply(c); Mp = Mp.sum(Mc); Ms = A.multiply(Mp); C cp = Ms.trace(); C ki = coFac.fromInteger(k).inverse(); // characteristic != k cp = cp.multiply(ki).negate(); M = Mp; c = cp; e = ExpVector.create(1, 0, n-k); ret = ret.sum(c, e); //System.out.println("k = " + k + ", c = " + c + ", M = " + M); } // only for demonstrating how to get the determinant, trace and inverse: // C det = coFac.getZERO(); //ret.trailingBaseCoefficient(); // //System.out.println("n = " + n + ", deg = " + ret.degree()); // if (n % 2 != 0) { // det = det.negate(); // } // if (! det.isZERO()) { // C d = det.inverse(); // if ((n-1) % 2 != 0) { // d = d.negate(); // } // Mc = Mp.multiply(d); // } else { // Mc = null; // } // //System.out.println("det = " + det + ", trace = " + c + ", A^{-1} = " + Mc); return ret; } /** * Determinant of matrix from characteristic polynomial. * Note: using Faddeev–LeVerrier algorithm * @see https://en.wikipedia.org/wiki/Faddeev%E2%80%93LeVerrier_algorithm * @param P characteristic polynomial of a matrix. * @return determinant from characteristic polynomial. */ public C determinantFromCharPol(GenPolynomial P) { C det = coFac.getZERO(); if (P == null || P.isZERO()) { return det; } det = P.trailingBaseCoefficient(); if (P.degree() % 2 != 0) { det = det.negate(); } return det; } /** * Determinant of matrix via characteristic polynomial. * Note: using Faddeev–LeVerrier algorithm * @see https://en.wikipedia.org/wiki/Faddeev%E2%80%93LeVerrier_algorithm * @param A square matrix. * @return determinant of A from characteristic polynomial of A. */ public C determinant(GenMatrix A) { GenPolynomial P = charPolynomial(A); return determinantFromCharPol(P); } /** * Trace of matrix from characteristic polynomial. * @param P characteristic polynomial of a matrix. * @return trace from characteristic polynomial. */ public C traceFromCharPol(GenPolynomial P) { if (P == null || P.isZERO()) { return coFac.getZERO(); } long n = P.degree(); ExpVector e = ExpVector.create(1, 0, n-1); C t = P.coefficient(e).negate(); return t; } /** * Get a GenPolynomial iterator. * @return an iterator over all polynomials. */ public Iterator> iterator() { if (coFac.isFinite()) { return new GenPolynomialIterator(this); } logger.warn("ring of coefficients {} is infinite, constructing iterator only over monomials", coFac); return new GenPolynomialMonomialIterator(this); //throw new IllegalArgumentException("only for finite iterable coefficients implemented"); } } /** * Polynomial iterator. * @author Heinz Kredel */ class GenPolynomialIterator> implements Iterator> { /** * data structure. */ final GenPolynomialRing ring; final Iterator> eviter; final List powers; final List> coeffiter; Iterator> itercoeff; GenPolynomial current; /** * Polynomial iterator constructor. */ @SuppressWarnings("unchecked") public GenPolynomialIterator(GenPolynomialRing fac) { ring = fac; LongIterable li = new LongIterable(); li.setNonNegativeIterator(); List> tlist = new ArrayList>(ring.nvar); for (int i = 0; i < ring.nvar; i++) { tlist.add(li); } CartesianProductInfinite ei = new CartesianProductInfinite(tlist); eviter = ei.iterator(); RingFactory cf = ring.coFac; coeffiter = new ArrayList>(); if (cf instanceof Iterable && cf.isFinite()) { Iterable cfi = (Iterable) cf; coeffiter.add(cfi); } else { throw new IllegalArgumentException("only for finite iterable coefficients implemented"); } CartesianProduct tuples = new CartesianProduct(coeffiter); itercoeff = tuples.iterator(); powers = new ArrayList(); ExpVector e = ExpVector.create(eviter.next()); powers.add(e); //System.out.println("new e = " + e); //System.out.println("powers = " + powers); List c = itercoeff.next(); //System.out.println("coeffs = " + c); current = new GenPolynomial(ring, c.get(0), e); } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public boolean hasNext() { return true; } /** * Get next polynomial. * @return next polynomial. */ public synchronized GenPolynomial next() { GenPolynomial res = current; if (!itercoeff.hasNext()) { ExpVector e = ExpVector.create(eviter.next()); powers.add(0, e); // add new ev at beginning //System.out.println("new e = " + e); //System.out.println("powers = " + powers); if (coeffiter.size() == 1) { // shorten first iterator by one element coeffiter.add(coeffiter.get(0)); Iterable it = coeffiter.get(0); List elms = new ArrayList(); for (C elm : it) { elms.add(elm); } elms.remove(0); coeffiter.set(0, elms); } else { coeffiter.add(coeffiter.get(1)); } CartesianProduct tuples = new CartesianProduct(coeffiter); itercoeff = tuples.iterator(); } List coeffs = itercoeff.next(); // while ( coeffs.get(0).isZERO() ) { // System.out.println(" skip zero "); // coeffs = itercoeff.next(); // skip tuples with zero in first component // } //System.out.println("coeffs = " + coeffs); GenPolynomial pol = ring.getZERO().copy(); int i = 0; for (ExpVector f : powers) { C c = coeffs.get(i++); if (c.isZERO()) { continue; } if (pol.val.get(f) != null) { System.out.println("error f in pol = " + f + ", " + pol.getMap().get(f)); throw new RuntimeException("error in iterator"); } pol.doPutToMap(f, c); } current = pol; return res; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } /** * Polynomial monomial iterator. * @author Heinz Kredel */ class GenPolynomialMonomialIterator> implements Iterator> { /** * data structure. */ final GenPolynomialRing ring; final Iterator iter; GenPolynomial current; /** * Polynomial iterator constructor. */ @SuppressWarnings("unchecked") public GenPolynomialMonomialIterator(GenPolynomialRing fac) { ring = fac; LongIterable li = new LongIterable(); li.setNonNegativeIterator(); List> tlist = new ArrayList>(ring.nvar); for (int i = 0; i < ring.nvar; i++) { tlist.add(li); } CartesianProductInfinite ei = new CartesianProductInfinite(tlist); //Iterator> eviter = ei.iterator(); RingFactory cf = ring.coFac; Iterable coeffiter; if (cf instanceof Iterable && !cf.isFinite()) { Iterable cfi = (Iterable) cf; coeffiter = cfi; } else { throw new IllegalArgumentException("only for infinite iterable coefficients implemented"); } // Cantor iterator for exponents and coefficients List eci = new ArrayList(2); // no type parameter eci.add(ei); eci.add(coeffiter); CartesianProductInfinite ecp = new CartesianProductInfinite(eci); iter = ecp.iterator(); List ec = iter.next(); List ecl = (List) ec.get(0); C c = (C) ec.get(1); // zero ExpVector e = ExpVector.create(ecl); //System.out.println("exp = " + e); //System.out.println("coeffs = " + c); current = new GenPolynomial(ring, c, e); } /** * Test for availability of a next element. * @return true if the iteration has more elements, else false. */ public boolean hasNext() { return true; } /** * Get next polynomial. * @return next polynomial. */ @SuppressWarnings("unchecked") public synchronized GenPolynomial next() { GenPolynomial res = current; List ec = iter.next(); C c = (C) ec.get(1); while (c.isZERO()) { // zero already done in first next ec = iter.next(); c = (C) ec.get(1); } List ecl = (List) ec.get(0); ExpVector e = ExpVector.create(ecl); //System.out.println("exp = " + e); //System.out.println("coeffs = " + c); current = new GenPolynomial(ring, c, e); return res; } /** * Remove an element if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/poly/GenPolynomialTokenizer.java000066400000000000000000002434661445075545500261740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StreamTokenizer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Scanner; import java.util.Set; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigOctonion; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.arith.BigRational; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.structure.Power; import edu.jas.structure.MonoidElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * GenPolynomial Tokenizer. Used to read rational polynomials and lists of * polynomials from input streams. Arbitrary polynomial rings and coefficient * rings can be read with RingFactoryTokenizer. Note: Can no more read * QuotientRing since end of 2010, revision 3441. Quotient coefficients and * others can still be read if the respective factory is provided via the * constructor. * @see edu.jas.application.RingFactoryTokenizer * @author Heinz Kredel */ public class GenPolynomialTokenizer { private static final Logger logger = LogManager.getLogger(GenPolynomialTokenizer.class); private static final boolean debug = logger.isDebugEnabled(); private String[] vars; private int nvars = 1; private TermOrder tord; private RelationTable table; private final StreamTokenizer tok; private final Reader reader; private RingFactory fac; private static enum coeffType { BigRat, BigInt, ModInt, BigC, BigQ, BigO, BigD, ANrat, ANmod, IntFunc }; private coeffType parsedCoeff = coeffType.BigRat; private GenPolynomialRing pfac; private static enum polyType { PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolBigO, PolANrat, PolANmod, PolIntFunc }; @SuppressWarnings("unused") private polyType parsedPoly = polyType.PolBigRat; private GenSolvablePolynomialRing spfac; /** * No-args constructor reads from System.in. */ public GenPolynomialTokenizer() { this(new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF8")))); } /** * Constructor with Ring and Reader. * @param rf ring factory. * @param r reader stream. */ public GenPolynomialTokenizer(GenPolynomialRing rf, Reader r) { this(r); if (rf == null) { return; } if (rf instanceof GenSolvablePolynomialRing) { pfac = rf; spfac = (GenSolvablePolynomialRing) rf; } else { pfac = rf; spfac = null; } fac = rf.coFac; vars = rf.vars; if (vars != null) { nvars = vars.length; } tord = rf.tord; // relation table if (spfac != null) { table = spfac.table; } else { table = null; } if (!pfac.getZERO().isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless // Version : 11.0.15.0 // Release : 150000.3.80.1 //System.out.println("thread@tokenizer: " + Thread.currentThread()); throw new RuntimeException("zero not 0: " + pfac.getZERO() + " " + pfac.getZERO().val); } } /** * Constructor with Reader. * @param r reader stream. */ @SuppressWarnings("unchecked") public GenPolynomialTokenizer(Reader r) { vars = null; tord = new TermOrder(); nvars = 1; fac = new BigRational(1); pfac = new GenPolynomialRing(fac, nvars, tord, vars); spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); reader = r; tok = new StreamTokenizer(reader); tok.resetSyntax(); // tok.eolIsSignificant(true); no more tok.eolIsSignificant(false); tok.wordChars('0', '9'); tok.wordChars('a', 'z'); tok.wordChars('A', 'Z'); tok.wordChars('_', '_'); // for subscripts x_i tok.wordChars('/', '/'); // wg. rational numbers tok.wordChars('.', '.'); // wg. floats tok.wordChars('~', '~'); // wg. quaternions tok.wordChars(128 + 32, 255); tok.whitespaceChars(0, ' '); tok.commentChar('#'); tok.quoteChar('"'); tok.quoteChar('\''); //tok.slashStarComments(true); does not work } /** * Initialize coefficient and polynomial factories. * @param rf ring factory. * @param ct coefficient type. */ @SuppressWarnings("unchecked") public void initFactory(RingFactory rf, coeffType ct) { fac = rf; parsedCoeff = ct; switch (ct) { case BigRat: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; break; case BigInt: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigInt; break; case ModInt: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolModInt; break; case BigC: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigC; break; case BigQ: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigQ; break; case BigO: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigO; break; case BigD: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigD; break; case IntFunc: pfac = new GenPolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolIntFunc; break; default: pfac = new GenPolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; } } /** * Initialize coefficient and solvable polynomial factories. * @param rf ring factory. * @param ct coefficient type. */ @SuppressWarnings("unchecked") public void initSolvableFactory(RingFactory rf, coeffType ct) { fac = rf; parsedCoeff = ct; switch (ct) { case BigRat: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; break; case BigInt: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigInt; break; case ModInt: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolModInt; break; case BigC: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigC; break; case BigQ: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigQ; break; case BigO: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigO; break; case BigD: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigD; break; case IntFunc: spfac = new GenSolvablePolynomialRing>(fac, nvars, tord, vars); parsedPoly = polyType.PolIntFunc; break; default: spfac = new GenSolvablePolynomialRing(fac, nvars, tord, vars); parsedPoly = polyType.PolBigRat; } } /** * Parsing method for GenPolynomial. Syntax depends also on the syntax of * the coefficients, as the respective parser is used. Basic term/monomial * syntax: * *
     ... coefficient variable**exponent ... variable^exponent + ... - ....
     * 
* * Juxtaposition means multiplication *. Then terms/monomials * can be added or subtracted +, - and grouped by parenthesis * (). There are some heuristics to detect when a coefficient * should be parsed. To force parsing of a coefficient enclose it in braces * {}. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenPolynomial nextPolynomial() throws IOException { logger.debug("torder = {}", tord); GenPolynomial a = pfac.getZERO(); GenPolynomial a1 = pfac.getONE(); ExpVector leer = pfac.evzero; if (debug) { logger.debug("pfac = {}", pfac.toScript()); logger.debug("a = {}", a); logger.debug("a1 = {}", a1); } GenPolynomial b = a1; GenPolynomial c; int tt; //, oldtt; //String rat = ""; char first; RingElem r; ExpVector e; int ix; long ie; while (true) { // next input. determine next action tt = tok.nextToken(); //System.out.println("while tt = " + tok); logger.debug("while tt = {}", tok); if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { case ')': case ',': return a; // do not change or remove case '-': b = b.negate(); case '+': case '*': tt = tok.nextToken(); break; default: // skip } // read coefficient, monic monomial and polynomial if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { // case '_': removed case '}': throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); case '{': // recursion StringBuffer rf = new StringBuffer(); int level = 0; do { tt = tok.nextToken(); //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); if (tt == StreamTokenizer.TT_EOF) { throw new InvalidExpressionException( "mismatch of braces after " + a + ", error at " + b); } if (tt == '{') { level++; } if (tt == '}') { level--; if (level < 0) { continue; // skip last closing brace } } if (tok.sval != null) { if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { rf.append(" "); } rf.append(tok.sval); // " " + } else { rf.append((char) tt); } } while (level >= 0); //System.out.println("coeff{} = " + rf.toString() ); try { r = (RingElem) fac.parse(rf.toString()); } catch (NumberFormatException re) { throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); } logger.debug("coeff {}", r); ie = nextExponent(); logger.debug("ie {}", ie); r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; //case '.': // eventually a float //System.out.println("start . = " + reader); //throw new InvalidExpressionException("float must start with a digit "); case StreamTokenizer.TT_WORD: //System.out.println("TT_WORD: " + tok.sval); if (tok.sval == null || tok.sval.length() == 0) break; // read coefficient first = tok.sval.charAt(0); if (digit(first) || first == '/' || first == '.' || first == '~') { //System.out.println("coeff 0 = " + tok.sval ); StringBuffer df = new StringBuffer(); df.append(tok.sval); if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { //System.out.println("start / or . = " + tok.sval); if (first == '/') { // let x/2 be x 1/2 df.insert(0, "1"); } if (first == '.') { // let x.2 be x 0.2 df.insert(0, "0"); } } if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number tt = tok.nextToken(); logger.debug("tt,im = {}", tok); if (tok.sval != null || tt == '-') { if (tok.sval != null) { df.append(tok.sval); } else { df.append("-"); } if (tt == '-') { tt = tok.nextToken(); // todo: decimal number if (tok.sval != null && digit(tok.sval.charAt(0))) { df.append(tok.sval); } else { tok.pushBack(); } } } else { tok.pushBack(); } } if (tok.sval.charAt(tok.sval.length() - 1) == 'j') { // quaternion number tt = tok.nextToken(); logger.debug("tt,jm = {}", tok); if (tok.sval != null || tt == '-') { if (tok.sval != null) { df.append(tok.sval); } else { df.append("-"); } if (tt == '-') { tt = tok.nextToken(); // todo: decimal number if (tok.sval != null && digit(tok.sval.charAt(0))) { df.append(tok.sval); } else { tok.pushBack(); } } } else { tok.pushBack(); } } if (tok.sval.charAt(tok.sval.length() - 1) == 'k') { // quaternion number tt = tok.nextToken(); logger.debug("tt,km = {}", tok); if (tok.sval != null || tt == '-') { if (tok.sval != null) { df.append(tok.sval); } else { df.append("-"); } if (tt == '-') { tt = tok.nextToken(); // todo: decimal number if (tok.sval != null && digit(tok.sval.charAt(0))) { df.append(tok.sval); } else { tok.pushBack(); } } } else { tok.pushBack(); } } tt = tok.nextToken(); if (tt == '.') { // decimal number, obsolete by word char? tt = tok.nextToken(); logger.debug("tt,dot = {}", tok); if (tok.sval != null) { df.append("."); df.append(tok.sval); } else { tok.pushBack(); tok.pushBack(); } } else { tok.pushBack(); } try { //System.out.println("df = " + df + ", fac = " + fac.getClass()); r = (RingElem) fac.parse(df.toString()); //System.out.println("r = " + r); } catch (NumberFormatException re) { //System.out.println("re = " + re); throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); } logger.debug("coeff {}", r); //System.out.println("r = " + r.toScriptFactory()); ie = nextExponent(); logger.debug("ie {}", ie); // r = r^ie; r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); } if (tt == StreamTokenizer.TT_EOF) break; if (tok.sval == null) break; // read monomial or recursion first = tok.sval.charAt(0); if (letter(first)) { ix = leer.indexVar(tok.sval, vars); //indexVar( tok.sval ); if (ix < 0) { // not found try { r = (RingElem) fac.parse(tok.sval); } catch (NumberFormatException re) { throw new InvalidExpressionException("recursively unknown variable " + tok.sval); } logger.info("coeff {}", r); //if (r.isONE() || r.isZERO()) { //logger.error("Unknown variable {}", tok.sval); //break; //throw new InvalidExpressionException("recursively unknown variable " + tok.sval); //} ie = nextExponent(); // System.out.println("ie: " + ie); r = (RingElem) r.power(ie); b = b.multiply(r); } else { // found // System.out.println("ix: " + ix); ie = nextExponent(); // System.out.println("ie: " + ie); e = ExpVector.create(vars.length, ix, ie); b = b.multiply(e); } tt = tok.nextToken(); logger.debug("tt,letter = {}", tok); } break; case '(': c = nextPolynomial(); logger.debug("factor {}", c); ie = nextExponent(); logger.debug("ie {}", ie); c = (GenPolynomial) c.power(ie); logger.debug("factor^ie {}", c); b = b.multiply(c); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; default: //skip } if (tt == StreamTokenizer.TT_EOF) break; // complete polynomial tok.pushBack(); switch (tt) { case '-': case '+': case ')': case ',': logger.debug("b, = {}", b); a = a.sum(b); b = a1; break; case '*': logger.debug("b, = {}", b); //a = a.sum(b); //b = a1; break; case '\n': tt = tok.nextToken(); logger.debug("tt,nl = {}", tt); break; default: // skip or finish ? logger.debug("default: {}", tok); } } logger.debug("b = {}", b); a = a.sum(b); logger.debug("a = {}", a); // b = a1; return a; } /** * Parsing method for exponent (of variable). Syntax: *
     * ^long | **long
     * 
* * @return the next exponent or 1. * @throws IOException */ public long nextExponent() throws IOException { long e = 1; char first; int tt; tt = tok.nextToken(); if (tt == '^') { logger.debug("exponent ^"); tt = tok.nextToken(); if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Long.parseLong(tok.sval); logger.debug("exponent ^{}", e); return e; } } } if (tt == '*') { tt = tok.nextToken(); if (tt == '*') { logger.debug("exponent **"); tt = tok.nextToken(); if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Long.parseLong(tok.sval); logger.debug("exponent **{}", e); return e; } } } tok.pushBack(); } tok.pushBack(); return e; } /** * Parsing method for comments. Syntax: * *
     * (* comment *) | /_* comment *_/
     * 
* * without _. Unused, as it does not work with this pushBack(). */ public String nextComment() throws IOException { // syntax: (* comment *) | /* comment */ StringBuffer c = new StringBuffer(); int tt; logger.debug("comment: {}", tok); tt = tok.nextToken(); logger.debug("comment: {}", tok); if (tt == '(') { tt = tok.nextToken(); logger.debug("comment: {}", tok); if (tt == '*') { logger.debug("comment: "); while (true) { tt = tok.nextToken(); if (tt == '*') { tt = tok.nextToken(); if (tt == ')') { return c.toString(); } tok.pushBack(); } c.append(tok.sval); } } tok.pushBack(); logger.debug("comment: {}", tok); } tok.pushBack(); logger.debug("comment: {}", tok); return c.toString(); } /** * Parsing method for variable list. Syntax: * *
     * (a, b c, de)
     * 
* * gives [ "a", "b", "c", "de" ] * @return the next variable list. * @throws IOException */ public String[] nextVariableList() throws IOException { List l = new ArrayList(); int tt; tt = tok.nextToken(); //System.out.println("vList tok = " + tok); if (tt == '(' || tt == '{') { logger.debug("variable list"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')' || tt == '}') break; if (tt == StreamTokenizer.TT_WORD) { //System.out.println("TT_WORD: " + tok.sval); l.add(tok.sval); } tt = tok.nextToken(); } } else { tok.pushBack(); } Object[] ol = l.toArray(); String[] v = new String[ol.length]; for (int i = 0; i < v.length; i++) { v[i] = (String) ol[i]; } return v; } /** * Parsing method for coefficient ring. Syntax: * *
     * Rat | Q | Int | Z | Mod modul | Complex | C | D | Quat | AN[ (var) ( poly ) ] | AN[ modul (var) ( poly ) ] | IntFunc (var_list)
     * 
* * @return the next coefficient factory. * @throws IOException */ @SuppressWarnings({ "unchecked", "cast" }) public RingFactory nextCoefficientRing() throws IOException { RingFactory coeff = null; coeffType ct = null; int tt; tt = tok.nextToken(); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("Q")) { coeff = new BigRational(0); ct = coeffType.BigRat; } else if (tok.sval.equalsIgnoreCase("Rat")) { coeff = new BigRational(0); ct = coeffType.BigRat; } else if (tok.sval.equalsIgnoreCase("D")) { coeff = new BigDecimal(0); ct = coeffType.BigD; } else if (tok.sval.equalsIgnoreCase("Z")) { coeff = new BigInteger(0); ct = coeffType.BigInt; } else if (tok.sval.equalsIgnoreCase("Int")) { coeff = new BigInteger(0); ct = coeffType.BigInt; } else if (tok.sval.equalsIgnoreCase("C")) { coeff = new BigComplex(0); ct = coeffType.BigC; } else if (tok.sval.equalsIgnoreCase("Complex")) { coeff = new BigComplex(0); ct = coeffType.BigC; } else if (tok.sval.equalsIgnoreCase("Quat")) { logger.warn("parse of quaternion coefficients may fail for negative components (use ~ for -)"); coeff = new BigQuaternionRing(); ct = coeffType.BigQ; } else if (tok.sval.equalsIgnoreCase("Oct")) { logger.warn("parse of octonion coefficients may fail for negative components (use ~ for -)"); coeff = new BigOctonion(new BigQuaternionRing()); ct = coeffType.BigO; } else if (tok.sval.equalsIgnoreCase("Mod")) { tt = tok.nextToken(); boolean openb = false; if (tt == '[') { // optional openb = true; tt = tok.nextToken(); } if (tok.sval != null && tok.sval.length() > 0) { if (digit(tok.sval.charAt(0))) { BigInteger mo = new BigInteger(tok.sval); BigInteger lm = new BigInteger(ModLongRing.MAX_LONG); //wrong: Long.MAX_VALUE); if (mo.compareTo(lm) < 0) { if (mo.compareTo(new BigInteger(ModIntRing.MAX_INT)) < 0) { coeff = new ModIntRing(mo.getVal()); } else { coeff = new ModLongRing(mo.getVal()); } } else { coeff = new ModIntegerRing(mo.getVal()); } //System.out.println("coeff = " + coeff + " :: " + coeff.getClass()); ct = coeffType.ModInt; } else { tok.pushBack(); } } else { tok.pushBack(); } if (tt == ']' && openb) { // optional tt = tok.nextToken(); } } else if (tok.sval.equalsIgnoreCase("RatFunc") || tok.sval.equalsIgnoreCase("ModFunc")) { //logger.error("RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); throw new InvalidExpressionException( "RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer."); } else if (tok.sval.equalsIgnoreCase("IntFunc")) { String[] rfv = nextVariableList(); //System.out.println("rfv = " + rfv.length + " " + rfv[0]); int vr = rfv.length; BigRational bi = new BigRational(); TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing pcf = new GenPolynomialRing(bi, vr, to, rfv); coeff = pcf; ct = coeffType.IntFunc; } else if (tok.sval.equalsIgnoreCase("AN")) { tt = tok.nextToken(); if (tt == '[') { tt = tok.nextToken(); RingFactory tcfac = new ModIntegerRing("19"); if (tok.sval != null && tok.sval.length() > 0) { if (digit(tok.sval.charAt(0))) { tcfac = new ModIntegerRing(tok.sval); } else { tcfac = new BigRational(); tok.pushBack(); } } else { tcfac = new BigRational(); tok.pushBack(); } String[] anv = nextVariableList(); //System.out.println("anv = " + anv.length + " " + anv[0]); int vs = anv.length; if (vs != 1) { throw new InvalidExpressionException( "AlgebraicNumber only for univariate polynomials " + Arrays.toString(anv)); } String[] ovars = vars; vars = anv; GenPolynomialRing tpfac = pfac; RingFactory tfac = fac; fac = tcfac; // pfac and fac used in nextPolynomial() if (tcfac instanceof ModIntegerRing) { pfac = new GenPolynomialRing(tcfac, vs, new TermOrder(), anv); } else { pfac = new GenPolynomialRing(tcfac, vs, new TermOrder(), anv); } logger.debug("pfac = {}", pfac); tt = tok.nextToken(); GenPolynomial mod; if (tt == '(') { mod = nextPolynomial(); tt = tok.nextToken(); if (tok.ttype != ')') tok.pushBack(); } else { tok.pushBack(); mod = nextPolynomial(); } logger.debug("mod = {}", mod); pfac = tpfac; fac = tfac; vars = ovars; if (tcfac instanceof ModIntegerRing) { GenPolynomial gfmod; gfmod = (GenPolynomial) mod; coeff = new AlgebraicNumberRing(gfmod); ct = coeffType.ANmod; } else { GenPolynomial anmod; anmod = (GenPolynomial) mod; coeff = new AlgebraicNumberRing(anmod); ct = coeffType.ANrat; } logger.debug("coeff = {}", coeff); tt = tok.nextToken(); if (tt == ']') { //ok, no nextToken(); } else { tok.pushBack(); } } else { tok.pushBack(); } } } if (coeff == null) { tok.pushBack(); coeff = new BigRational(); ct = coeffType.BigRat; } parsedCoeff = ct; return coeff; } /** * Parsing method for weight list. Syntax: * *
     * (w1, w2, w3, ..., wn)
     * 
* * @return the next weight list. * @throws IOException */ public long[] nextWeightList() throws IOException { List l = new ArrayList(); long e; char first; int tt; tt = tok.nextToken(); if (tt == '(') { logger.debug("weight list"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')') break; if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Long.parseLong(tok.sval); l.add(Long.valueOf(e)); //System.out.println("w: " + e); } } tt = tok.nextToken(); // also comma } } else { tok.pushBack(); } Long[] ol = new Long[1]; ol = l.toArray(ol); long[] w = new long[ol.length]; for (int i = 0; i < w.length; i++) { w[i] = ol[ol.length - i - 1].longValue(); } return w; } /** * Parsing method for weight array. Syntax: * *
     * ( (w11, ...,w1n), ..., (wm1, ..., wmn) )
     * 
* * @return the next weight array. * @throws IOException */ public long[][] nextWeightArray() throws IOException { List l = new ArrayList(); long[] e; char first; int tt; tt = tok.nextToken(); if (tt == '(') { logger.debug("weight array"); tt = tok.nextToken(); while (true) { if (tt == StreamTokenizer.TT_EOF) break; if (tt == ')') break; if (tt == '(') { tok.pushBack(); e = nextWeightList(); l.add(e); //System.out.println("wa: " + e); } else if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { tok.pushBack(); tok.pushBack(); e = nextWeightList(); l.add(e); break; //System.out.println("w: " + e); } } tt = tok.nextToken(); // also comma } } else { tok.pushBack(); } Object[] ol = l.toArray(); long[][] w = new long[ol.length][]; for (int i = 0; i < w.length; i++) { w[i] = (long[]) ol[i]; } return w; } /** * Parsing method for split index. Syntax: * *
     * |i|
     * 
* * @return the next split index. * @throws IOException */ public int nextSplitIndex() throws IOException { int e = -1; // =unknown int e0 = -1; // =unknown char first; int tt; tt = tok.nextToken(); if (tt == '|') { logger.debug("split index"); tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } tt = tok.nextToken(); if (tt != '|') { tok.pushBack(); } } } else if (tt == '[') { logger.debug("split index"); tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e0 = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } tt = tok.nextToken(); if (tt == ',') { tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { return e0; } if (tok.sval != null) { first = tok.sval.charAt(0); if (digit(first)) { e = Integer.parseInt(tok.sval); //System.out.println("w: " + i); } } if (tt != ']') { tok.pushBack(); } } } } else { tok.pushBack(); } return e; } /** * Parsing method for term order name. Syntax: * *
     * L | IL | LEX | G | IG | GRLEX | W(weights) | '|'split index'|'
     * 
* * @return the next term order. * @throws IOException */ public TermOrder nextTermOrder() throws IOException { int evord = TermOrder.DEFAULT_EVORD; int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) { /* nop */ } else if (tt == StreamTokenizer.TT_WORD) { // System.out.println("TT_WORD: " + tok.sval); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("L")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("IL")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("INVLEX")) { evord = TermOrder.INVLEX; } else if (tok.sval.equalsIgnoreCase("LEX")) { evord = TermOrder.LEX; } else if (tok.sval.equalsIgnoreCase("G")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("IG")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("IGRLEX")) { evord = TermOrder.IGRLEX; } else if (tok.sval.equalsIgnoreCase("GRLEX")) { evord = TermOrder.GRLEX; } else if (tok.sval.equalsIgnoreCase("REVITDG")) { evord = TermOrder.REVITDG; } else if (tok.sval.equalsIgnoreCase("REVILEX")) { evord = TermOrder.REVILEX; } else if (tok.sval.equalsIgnoreCase("W")) { long[][] w = nextWeightArray(); return new TermOrder(w); } } } else { tok.pushBack(); } int s = nextSplitIndex(); if (s <= 0) { return new TermOrder(evord); } return new TermOrder(evord, evord, nvars, s); } /** * Parsing method for polynomial list. Syntax: * *
     * ( p1, p2, p3, ..., pn )
     * 
* * @return the next polynomial list. * @throws IOException */ public List nextPolynomialList() throws IOException { GenPolynomial a; List L = new ArrayList(); int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) return L; if (tt != '(') return L; logger.debug("polynomial list"); while (true) { tt = tok.nextToken(); if (tok.ttype == ',') continue; if (tt == '(') { a = nextPolynomial(); tt = tok.nextToken(); if (tok.ttype != ')') tok.pushBack(); } else { tok.pushBack(); a = nextPolynomial(); } logger.info("next pol = {}", a); L.add(a); if (tok.ttype == StreamTokenizer.TT_EOF) break; if (tok.ttype == ')') break; } return L; } /** * Parsing method for submodule list. Syntax: * *
     * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) )
     * 
* * @return the next list of polynomial lists. * @throws IOException */ public List> nextSubModuleList() throws IOException { List> L = new ArrayList>(); int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) return L; if (tt != '(') return L; logger.debug("module list"); List v = null; while (true) { tt = tok.nextToken(); if (tok.ttype == ',') continue; if (tok.ttype == ')') break; if (tok.ttype == StreamTokenizer.TT_EOF) break; if (tt == '(') { tok.pushBack(); v = nextPolynomialList(); logger.info("next vect = {}", v); L.add(v); } } return L; } /** * Parsing method for solvable polynomial relation table. Syntax: * *
     * ( p_1, p_2, p_3, ..., p_{n+1}, p_{n+2}, p_{n+3} )
     * 
* * semantics: p_{n+1} * p_{n+2} = p_{n+3}. The next relation * table is stored into the solvable polynomial factory. * @throws IOException */ @SuppressWarnings("unchecked") public void nextRelationTable() throws IOException { if (spfac == null) { return; } RelationTable table = spfac.table; List rels = null; GenPolynomial p; GenSolvablePolynomial sp; int tt; tt = tok.nextToken(); logger.debug("start relation table: {}", tt); if (tok.sval != null) { if (tok.sval.equalsIgnoreCase("RelationTable")) { rels = nextPolynomialList(); } } if (rels == null) { tok.pushBack(); return; } for (Iterator it = rels.iterator(); it.hasNext();) { p = it.next(); ExpVector e = p.leadingExpVector(); if (it.hasNext()) { p = it.next(); ExpVector f = p.leadingExpVector(); if (it.hasNext()) { p = it.next(); sp = new GenSolvablePolynomial(spfac, p.val); table.update(e, f, sp); } } } logger.info("table = {}", table); return; } /** * Parsing method for polynomial set. Syntax: * *
     * coeffRing varList termOrderName polyList
     * 
* * @return the next polynomial set. * @throws IOException */ @SuppressWarnings("unchecked") public PolynomialList nextPolynomialSet() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // global: nvars, tord, vars List s = null; s = nextPolynomialList(); logger.info("s = {}", s); // comments += nextComment(); return new PolynomialList(pfac, s); } /** * Parsing method for module set. Syntax: * *
     * coeffRing varList termOrderName moduleList
     * 
* * @return the next module set. * @throws IOException */ @SuppressWarnings("unchecked") public ModuleList nextSubModuleSet() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // global: nvars, tord, vars List> m = null; m = nextSubModuleList(); logger.info("m = {}", m); // comments += nextComment(); return new ModuleList(pfac, m); } /** * Parsing method for solvable polynomial list. Syntax: * *
     * ( p1, p2, p3, ..., pn )
     * 
* * @return the next solvable polynomial list. * @throws IOException */ @SuppressWarnings("unchecked") public List nextSolvablePolynomialList() throws IOException { List s = nextPolynomialList(); logger.info("s = {}", s); // comments += nextComment(); GenPolynomial p; GenSolvablePolynomial ps; List sp = new ArrayList(s.size()); for (Iterator it = s.iterator(); it.hasNext();) { p = it.next(); ps = new GenSolvablePolynomial(spfac, p.val); //System.out.println("ps = " + ps); sp.add(ps); } return sp; } /** * Parsing method for solvable polynomial. Syntax: same as for polynomial. * If the relation table is set-up, then multiplication will mean * solvable-multiplication. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenSolvablePolynomial nextSolvablePolynomial() throws IOException { GenPolynomial p = nextPolynomial(); //logger.info("nextPolynomial = {}", p); // comments += nextComment(); GenSolvablePolynomial ps = new GenSolvablePolynomial(spfac, p.val); logger.info("nextSolvablePolynomial = {}", ps); return ps; } /** * Parsing method for solvable polynomial set. Syntax: * *
     * varList termOrderName relationTable polyList
     * 
* * @return the next solvable polynomial set. * @throws IOException */ @SuppressWarnings("unchecked") public PolynomialList nextSolvablePolynomialSet() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // must be because of symmetric read initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars //System.out.println("pfac = " + pfac); //System.out.println("spfac = " + spfac); nextRelationTable(); logger.info("table = {}", table); List s = null; s = nextSolvablePolynomialList(); logger.info("s = {}", s); // comments += nextComment(); return new PolynomialList(spfac, s); // Ordered ? } /** * Parsing method for solvable submodule list. Syntax: * *
     * ( ( p11, p12, p13, ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) )
     * 
* * @return the next list of solvable polynomial lists. * @throws IOException */ public List> nextSolvableSubModuleList() throws IOException { List> L = new ArrayList>(); int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) return L; if (tt != '(') return L; logger.debug("module list"); List v = null; while (true) { tt = tok.nextToken(); if (tok.ttype == ',') continue; if (tok.ttype == ')') break; if (tok.ttype == StreamTokenizer.TT_EOF) break; if (tt == '(') { tok.pushBack(); v = nextSolvablePolynomialList(); logger.info("next vect = {}", v); L.add(v); } } return L; } /** * Parsing method for solvable module set. Syntax: * *
     * varList termOrderName relationTable moduleList
     * 
* * @return the next solvable module set. * @throws IOException */ @SuppressWarnings("unchecked") public ModuleList nextSolvableSubModuleSet() throws IOException { //String comments = ""; //comments += nextComment(); //if (debug) logger.debug("comment = {}", comments); RingFactory coeff = nextCoefficientRing(); logger.info("coeff = {}", coeff.getClass().getSimpleName()); vars = nextVariableList(); logger.info("vars = {}", Arrays.toString(vars)); if (vars != null) { nvars = vars.length; } tord = nextTermOrder(); logger.info("tord = {}", tord); // check more TOs initFactory(coeff, parsedCoeff); // must be because of symmetric read initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars //System.out.println("spfac = " + spfac); nextRelationTable(); logger.info("table = {}", table); List> s = null; s = nextSolvableSubModuleList(); logger.info("s = {}", s); // comments += nextComment(); return new OrderedModuleList(spfac, s); // Ordered } /** * Parsing method for word polynomial. Syntax: same as for polynomial. * Multiplication will be non commutative. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenWordPolynomial nextWordPolynomial() throws IOException { GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac); return nextWordPolynomial(wfac); } /** * Parsing method for word polynomial. Syntax: same as for polynomial. * Multiplication will be non commutative. * @param wfac word polynomial ring. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenWordPolynomial nextWordPolynomial(GenWordPolynomialRing wfac) throws IOException { //logger.info("wfac = {}", wfac); WordFactory wf = wfac.alphabet; GenWordPolynomial a = wfac.getZERO(); GenWordPolynomial a1 = wfac.getONE(); Word leer = wfac.wone; RingFactory fac = wfac.coFac; if (debug) { logger.debug("a = {}", a); logger.debug("a1 = {}", a1); } GenWordPolynomial b = a1; GenWordPolynomial c; int tt; char first; RingElem r; Word e; //int ix; long ie; while (true) { // next input. determine next action tt = tok.nextToken(); //System.out.println("while tt = " + tok); logger.debug("while tt = {}", tok); if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { case ')': case ',': logger.info("nextWordPolynomial = {}", a); return a; // do not change or remove case '-': b = b.negate(); case '+': case '*': tt = tok.nextToken(); break; default: // skip } // read coefficient, monic monomial and polynomial if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { // case '_': removed case '}': throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); case '{': // recursion StringBuffer rf = new StringBuffer(); int level = 0; do { tt = tok.nextToken(); //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); if (tt == StreamTokenizer.TT_EOF) { throw new InvalidExpressionException( "mismatch of braces after " + a + ", error at " + b); } if (tt == '{') { level++; } if (tt == '}') { level--; if (level < 0) { continue; // skip last closing brace } } if (tok.sval != null) { if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { rf.append(" "); } rf.append(tok.sval); // " " + } else { rf.append((char) tt); } } while (level >= 0); //System.out.println("coeff{} = " + rf.toString() ); try { r = (RingElem) fac.parse(rf.toString()); } catch (NumberFormatException re) { throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); } logger.debug("coeff {}", r); ie = nextExponent(); logger.debug("ie {}", ie); r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; //case '.': // eventually a float //System.out.println("start . = " + reader); //throw new InvalidExpressionException("float must start with a digit "); case StreamTokenizer.TT_WORD: //System.out.println("TT_WORD: " + tok.sval); if (tok.sval == null || tok.sval.length() == 0) break; // read coefficient first = tok.sval.charAt(0); if (digit(first) || first == '/' || first == '.' || first == '~') { //System.out.println("coeff 0 = " + tok.sval ); StringBuffer df = new StringBuffer(); df.append(tok.sval); if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { //System.out.println("start / or . = " + tok.sval); if (first == '/') { // let x/2 be x 1/2 df.insert(0, "1"); } if (first == '.') { // let x.2 be x 0.2 df.insert(0, "0"); } } if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number tt = tok.nextToken(); logger.debug("tt,im = {}", tok); if (tok.sval != null || tt == '-') { if (tok.sval != null) { df.append(tok.sval); } else { df.append("-"); } if (tt == '-') { tt = tok.nextToken(); // todo: decimal number if (tok.sval != null && digit(tok.sval.charAt(0))) { df.append(tok.sval); } else { tok.pushBack(); } } } else { tok.pushBack(); } } tt = tok.nextToken(); if (tt == '.') { // decimal number, obsolete by word char? tt = tok.nextToken(); logger.debug("tt,dot = {}", tok); if (tok.sval != null) { df.append("."); df.append(tok.sval); } else { tok.pushBack(); tok.pushBack(); } } else { tok.pushBack(); } try { //System.out.println("df = " + df + ", fac = " + fac.getClass()); r = (RingElem) fac.parse(df.toString()); //System.out.println("r = " + r); } catch (NumberFormatException re) { //System.out.println("re = " + re); throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); } logger.debug("coeff {}", r); //System.out.println("r = " + r.toScriptFactory()); ie = nextExponent(); logger.debug("ie {}", ie); // r = r^ie; r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); } if (tt == StreamTokenizer.TT_EOF) break; if (tok.sval == null) break; // read monomial or recursion first = tok.sval.charAt(0); if (letter(first)) { //ix = leer.indexVar(tok.sval, vars); try { e = wf.parse(tok.sval); } catch (IllegalArgumentException ee) { e = null; } logger.info("monom {}", e); if (e == null) { // not found, look for coeff var try { r = (RingElem) fac.parse(tok.sval); } catch (NumberFormatException re) { throw new InvalidExpressionException("recursively unknown variable " + tok.sval); } ie = nextExponent(); // System.out.println("ie: " + ie); r = (RingElem) r.power(ie); // System.out.println("re: " + r); b = b.multiply(r, leer); } else { // found ie = nextExponent(); // System.out.println("ie: " + ie); e = e.power(ie); // System.out.println("e: " + e); b = b.multiply(e); } tt = tok.nextToken(); logger.debug("tt,letter = {}", tok); } break; case '(': c = nextWordPolynomial(wfac); logger.debug("factor {}", c); ie = nextExponent(); logger.debug("ie {}", ie); c = (GenWordPolynomial) c.power(ie); logger.debug("factor^ie {}", c); b = b.multiply(c); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; default: //skip } if (tt == StreamTokenizer.TT_EOF) break; // complete polynomial tok.pushBack(); switch (tt) { case '-': case '+': case ')': case ',': logger.debug("b, = {}", b); a = a.sum(b); b = a1; break; case '*': logger.debug("b, = {}", b); //a = a.sum(b); //b = a1; break; case '\n': tt = tok.nextToken(); logger.debug("tt,nl = {}", tt); break; default: // skip or finish ? logger.debug("default: {}", tok); } } logger.debug("b = {}", b); a = a.sum(b); logger.info("nextWordPolynomial = {}", a); // b = a1; return a; } /** * Parsing method for word polynomial list. Syntax: * *
     * ( p1, p2, p3, ..., pn )
     * 
* * @return the next word polynomial list. * @throws IOException */ @SuppressWarnings("unchecked") public List nextWordPolynomialList() throws IOException { GenWordPolynomialRing wfac = new GenWordPolynomialRing(pfac); return nextWordPolynomialList(wfac); } /** * Parsing method for word polynomial list. Syntax: * *
     * ( p1, p2, p3, ..., pn )
     * 
* * @param wfac word polynomial ring. * @return the next word polynomial list. * @throws IOException */ public List nextWordPolynomialList(GenWordPolynomialRing wfac) throws IOException { GenWordPolynomial a; List L = new ArrayList(); int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) return L; if (tt != '(') return L; logger.debug("word polynomial list"); while (true) { tt = tok.nextToken(); if (tok.ttype == ',') continue; if (tt == '(') { a = nextWordPolynomial(wfac); tt = tok.nextToken(); if (tok.ttype != ')') tok.pushBack(); } else { tok.pushBack(); a = nextWordPolynomial(wfac); } logger.info("next pol = {}", a); L.add(a); if (tok.ttype == StreamTokenizer.TT_EOF) break; if (tok.ttype == ')') break; } return L; } /** * Parsing method for exterior polynomial. Syntax: same as for polynomial. * Multiplication will be non commutative. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenExteriorPolynomial nextExteriorPolynomial() throws IOException { GenExteriorPolynomialRing wfac = new GenExteriorPolynomialRing(pfac); return nextExteriorPolynomial(wfac); } /** * Parsing method for exterior polynomial. Syntax: except for * index list same as for polynomial. Multiplication will be * anti-commutative. * @param wfac exterior polynomial ring. * @return the next polynomial. * @throws IOException */ @SuppressWarnings("unchecked") public GenExteriorPolynomial nextExteriorPolynomial(GenExteriorPolynomialRing wfac) throws IOException { logger.info("wfac = {}", wfac); IndexFactory wf = wfac.ixfac; GenExteriorPolynomial a = wfac.getZERO(); GenExteriorPolynomial a1 = wfac.getONE(); IndexList leer = wfac.wone; RingFactory fac = wfac.coFac; if (debug) { logger.debug("a = {}", a); logger.debug("a1 = {}", a1); } GenExteriorPolynomial b = a1; GenExteriorPolynomial c; int tt; char first; RingElem r; IndexList e; //int ix; long ie; while (true) { // next input. determine next action tt = tok.nextToken(); //System.out.println("while tt = " + tok); logger.debug("while tt = {}", tok); if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { case ')': case ',': logger.info("nextExteriorPolynomial = {}", a); return a; // do not change or remove case '-': b = b.negate(); case '+': case '*': tt = tok.nextToken(); break; default: // skip } // read coefficient, monic monomial and polynomial if (tt == StreamTokenizer.TT_EOF) break; switch (tt) { // case '_': removed case '}': throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b); case '{': // recursion StringBuffer rf = new StringBuffer(); int level = 0; do { tt = tok.nextToken(); //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level); if (tt == StreamTokenizer.TT_EOF) { throw new InvalidExpressionException( "mismatch of braces after " + a + ", error at " + b); } if (tt == '{') { level++; } if (tt == '}') { level--; if (level < 0) { continue; // skip last closing brace } } if (tok.sval != null) { if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') { rf.append(" "); } rf.append(tok.sval); // " " + } else { rf.append((char) tt); } } while (level >= 0); //System.out.println("coeff{} = " + rf.toString() ); try { r = (RingElem) fac.parse(rf.toString()); } catch (NumberFormatException re) { throw new InvalidExpressionException("not a number :" + rf + ": " + fac, re); } logger.debug("coeff {}", r); ie = nextExponent(); logger.debug("ie {}", ie); r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; //case '.': // eventually a float //System.out.println("start . = " + reader); //throw new InvalidExpressionException("float must start with a digit "); case StreamTokenizer.TT_WORD: //System.out.println("TT_WORD: " + tok.sval); if (tok.sval == null || tok.sval.length() == 0) break; // read coefficient first = tok.sval.charAt(0); if (digit(first) || first == '/' || first == '.' || first == '~') { //System.out.println("coeff 0 = " + tok.sval ); StringBuffer df = new StringBuffer(); df.append(tok.sval); if (tok.sval.length() > 1 && digit(tok.sval.charAt(1))) { //System.out.println("start / or . = " + tok.sval); if (first == '/') { // let x/2 be x 1/2 df.insert(0, "1"); } if (first == '.') { // let x.2 be x 0.2 df.insert(0, "0"); } } if (tok.sval.charAt(tok.sval.length() - 1) == 'i') { // complex number tt = tok.nextToken(); logger.debug("tt,im = {}", tok); if (tok.sval != null || tt == '-') { if (tok.sval != null) { df.append(tok.sval); } else { df.append("-"); } if (tt == '-') { tt = tok.nextToken(); // todo: decimal number if (tok.sval != null && digit(tok.sval.charAt(0))) { df.append(tok.sval); } else { tok.pushBack(); } } } else { tok.pushBack(); } } tt = tok.nextToken(); if (tt == '.') { // decimal number, obsolete by word char? tt = tok.nextToken(); logger.debug("tt,dot = {}", tok); if (tok.sval != null) { df.append("."); df.append(tok.sval); } else { tok.pushBack(); tok.pushBack(); } } else { tok.pushBack(); } try { //System.out.println("df = " + df + ", fac = " + fac.getClass()); r = (RingElem) fac.parse(df.toString()); //System.out.println("r = " + r); } catch (NumberFormatException re) { //System.out.println("re = " + re); throw new InvalidExpressionException("not a number :" + df + ": " + fac, re); } logger.debug("coeff {}", r); //System.out.println("r = " + r.toScriptFactory()); ie = nextExponent(); logger.debug("ie {}", ie); // r = r^ie; r = (RingElem) r.power(ie); logger.debug("coeff^ie {}", r); b = b.multiply(r, leer); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); } if (tt == StreamTokenizer.TT_EOF) break; if (tok.sval == null) break; // read monomial, index list or recursion first = tok.sval.charAt(0); //System.out.println("first = '" + first + "'"); if (letter(first)) { //ix = leer.indexVar(tok.sval, vars); if ("E".charAt(0) == first) { StringBuffer ri = new StringBuffer(); ri.append(tok.sval); //System.out.println("index tok.sval " + tok.sval); while (true) { tt = tok.nextToken(); //System.out.println("index tok.token " + tt + ", tok.sval " + tok.sval); if (tt == '(') { ri.append("("); continue; } if (tt == ',') { ri.append(","); continue; } if (tok.sval != null) { ri.append(tok.sval); //System.out.println("index tok.sval " + tok.sval); } if (tt == ')') { ri.append(")"); break; } } //System.out.println("index list, ri " + ri.toString()); try { e = wf.parse(ri.toString()); } catch (IllegalArgumentException ee) { e = null; } } else { e = null; //wf.valueOf(tok.sval); } logger.info("monom {}", e); //System.out.println("index list, e " + e); if (e == null) { // not found, look for coeff var try { r = (RingElem) fac.parse(tok.sval); } catch (NumberFormatException re) { throw new InvalidExpressionException("recursively unknown variable " + tok.sval); } ie = nextExponent(); // System.out.println("ie: " + ie); r = (RingElem) r.power(ie); // System.out.println("re: " + r); b = b.multiply(r, leer); } else { // found ie = nextExponent(); // System.out.println("ie: " + ie); //no RingElem: e = e.power(ie); //no RingElem: e = Power. positivePower(e, ie); if (ie > 1) { // exterior product is 0 e = wf.getZERO(); } if (ie <= 0) { e = wf.getONE(); } //System.out.println("e: " + e); b = b.multiply(e); } tt = tok.nextToken(); logger.debug("tt,letter = {}", tok); } break; case '(': c = nextExteriorPolynomial(wfac); logger.debug("factor {}", c); ie = nextExponent(); logger.debug("ie {}", ie); c = (GenExteriorPolynomial) c.power(ie); logger.debug("factor^ie {}", c); b = b.multiply(c); tt = tok.nextToken(); logger.debug("tt,digit = {}", tok); //no break; break; default: //skip } if (tt == StreamTokenizer.TT_EOF) break; // complete polynomial tok.pushBack(); switch (tt) { case '-': case '+': case ')': case ',': logger.debug("b, = {}", b); a = a.sum(b); b = a1; break; case '*': logger.debug("b, = {}", b); //a = a.sum(b); //b = a1; break; case '\n': tt = tok.nextToken(); logger.debug("tt,nl = {}", tt); break; default: // skip or finish ? logger.debug("default: {}", tok); } } logger.debug("b = {}", b); a = a.sum(b); logger.info("nextExteriorPolynomial = {}", a); // b = a1; return a; } /** * Parsing method for exterior polynomial list. Syntax: *
     * ( p1, p2, p3, ..., pn )
     * 
* * @return the next exterior polynomial list. * @throws IOException */ @SuppressWarnings("unchecked") public List nextExteriorPolynomialList() throws IOException { GenExteriorPolynomialRing wfac = new GenExteriorPolynomialRing(pfac); return nextExteriorPolynomialList(wfac); } /** * Parsing method for exterior polynomial list. Syntax: *
     * ( p1, p2, p3, ..., pn )
     * 
* * @param wfac exterior polynomial ring. * @return the next exterior polynomial list. * @throws IOException */ public List nextExteriorPolynomialList(GenExteriorPolynomialRing wfac) throws IOException { GenExteriorPolynomial a; List L = new ArrayList(); int tt; tt = tok.nextToken(); if (tt == StreamTokenizer.TT_EOF) return L; if (tt != '(') return L; logger.debug("exterior polynomial list"); while (true) { tt = tok.nextToken(); if (tok.ttype == ',') continue; if (tt == '(') { a = nextExteriorPolynomial(wfac); tt = tok.nextToken(); if (tok.ttype != ')') tok.pushBack(); } else { tok.pushBack(); a = nextExteriorPolynomial(wfac); } logger.info("next pol = {}", a); L.add(a); if (tok.ttype == StreamTokenizer.TT_EOF) break; if (tok.ttype == ')') break; } return L; } // must also allow +/- // does not work with tokenizer //private static boolean number(char x) { // return digit(x) || x == '-' || x == '+'; //} static boolean digit(char x) { return '0' <= x && x <= '9'; } static boolean letter(char x) { return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z'); } // unused public void nextComma() throws IOException { int tt; if (tok.ttype == ',') { tt = tok.nextToken(); logger.debug("after comma: {}", tt); } } /** * Parse variable list from String. * @param s String. Syntax: * *
     * (n1,...,nk)
     *            
* * or * *
     * (n1 ... nk)
     *            
* * parenthesis are optional. * @return array of variable names found in s. */ public static String[] variableList(String s) { String[] vl = null; if (s == null) { return vl; } String st = s.trim(); if (st.length() == 0) { return new String[0]; } if (st.charAt(0) == '(') { st = st.substring(1); } if (st.charAt(st.length() - 1) == ')') { st = st.substring(0, st.length() - 1); } st = st.replaceAll(",", " "); List sl = new ArrayList(); Scanner sc = new Scanner(st); while (sc.hasNext()) { String sn = sc.next(); sl.add(sn); } sc.close(); vl = new String[sl.size()]; int i = 0; for (String si : sl) { vl[i] = si; i++; } return vl; } /** * Extract variable list from expression. * @param s String. Syntax: any polynomial expression. * @return array of variable names found in s. */ public static String[] expressionVariables(String s) { String[] vl = null; if (s == null) { return vl; } String st = s.trim(); if (st.length() == 0) { return new String[0]; } st = st.replaceAll(",", " "); st = st.replaceAll("\\+", " "); st = st.replaceAll("-", " "); st = st.replaceAll("\\*", " "); st = st.replaceAll("/", " "); st = st.replaceAll("\\(", " "); st = st.replaceAll("\\)", " "); st = st.replaceAll("\\{", " "); st = st.replaceAll("\\}", " "); st = st.replaceAll("\\[", " "); st = st.replaceAll("\\]", " "); st = st.replaceAll("\\^", " "); //System.out.println("st = " + st); Set sl = new TreeSet(); Scanner sc = new Scanner(st); while (sc.hasNext()) { String sn = sc.next(); if (sn == null || sn.length() == 0) { continue; } //System.out.println("sn = " + sn); int i = 0; while (digit(sn.charAt(i)) && i < sn.length() - 1) { i++; } //System.out.println("sn = " + sn + ", i = " + i); if (i > 0) { sn = sn.substring(i, sn.length()); } //System.out.println("sn = " + sn); if (sn.length() == 0) { continue; } if (!letter(sn.charAt(0))) { continue; } //System.out.println("sn = " + sn); sl.add(sn); } sc.close(); vl = new String[sl.size()]; int i = 0; for (String si : sl) { vl[i] = si; i++; } return vl; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenSolvablePolynomial.java000066400000000000000000001124601445075545500257560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; /** * GenSolvablePolynomial generic solvable polynomials implementing RingElem. * n-variate ordered solvable polynomials over C. Objects of this class are * intended to be immutable. The implementation is based on TreeMap respectively * SortedMap from exponents to coefficients by extension of GenPolybomial. Only * the coefficients are modeled with generic types, the exponents are fixed to * ExpVector with long, int, short entries (@see edu.jas.poly.ExpVector * StorUnit). * @param coefficient type * @author Heinz Kredel */ public class GenSolvablePolynomial> extends GenPolynomial { //not possible: implements RingElem< GenSolvablePolynomial > { private static final Logger logger = LogManager.getLogger(GenSolvablePolynomial.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The factory for the solvable polynomial ring. Hides super.ring. */ public final GenSolvablePolynomialRing ring; /** * Constructor for zero GenSolvablePolynomial. * @param r solvable polynomial ring factory. */ public GenSolvablePolynomial(GenSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for GenSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient. * @param e exponent. */ public GenSolvablePolynomial(GenSolvablePolynomialRing r, C c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for GenSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient. */ public GenSolvablePolynomial(GenSolvablePolynomialRing r, C c) { this(r, c, r.evzero); } /** * Constructor for GenSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected GenSolvablePolynomial(GenSolvablePolynomialRing r, SortedMap v) { this(r); if (v.size() > 0) { GenPolynomialRing.creations++; val.putAll(v); // assume val is empty and no zero coefficients in v } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public GenSolvablePolynomialRing factory() { return ring; } /** * Clone this GenSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public GenSolvablePolynomial copy() { return new GenSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof GenSolvablePolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * GenSolvablePolynomial multiplication. * @param Bp GenSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // cannot @Override @SuppressWarnings("unchecked") public GenSolvablePolynomial multiply(GenSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == Bp.ring.nvar); logger.debug("ring = {}", ring); if (this instanceof RecSolvablePolynomial && Bp instanceof RecSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE Rec.multiply(Rec Bp) - trying to fix"); RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no RecSolvablePolynomial Sp = (RecSolvablePolynomial) Bp; return T.multiply(Sp); } if (this instanceof QLRSolvablePolynomial && Bp instanceof QLRSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE QLR.multiply(QLR Bp) - trying to fix"); QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no QLRSolvablePolynomial Sp = (QLRSolvablePolynomial) Bp; return T.multiply(Sp); } final boolean commute = ring.table.isEmpty(); GenSolvablePolynomial Cp = ring.getZERO().copy(); // needed for doPutToMap and doAddTo ExpVector Z = ring.evzero; GenSolvablePolynomial C1 = null; GenSolvablePolynomial C2 = null; Map A = val; Map B = Bp.val; Set> Bk = B.entrySet(); for (Map.Entry y : A.entrySet()) { C a = y.getValue(); ExpVector e = y.getKey(); logger.debug("e = {}", e); int[] ep = e.dependencyOnVariables(); int el1 = ring.nvar + 1; if (ep.length > 0) { el1 = ep[0]; } int el1s = ring.nvar + 1 - el1; for (Map.Entry x : Bk) { C b = x.getValue(); ExpVector f = x.getKey(); logger.debug("f = {}", f); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; logger.debug("el1s = {} fl1s = {}", el1s, fl1s); GenSolvablePolynomial Cs = null; if (commute || el1s <= fl1s) { // symmetric ExpVector g = e.sum(f); Cs = ring.valueOf(g); // symmetric! //no: Cs = new GenSolvablePolynomial(ring, one, g); //System.out.println("Cs(sym) = " + Cs + ", g = " + g); } else { // unsymmetric // split e = e1 * e2, f = f1 * f2 ExpVector e1 = e.subst(el1, 0); ExpVector e2 = Z.subst(el1, e.getVal(el1)); ExpVector e4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); TableRelation rel = ring.table.lookup(e2, f2); //logger.info("relation = {}", rel); Cs = rel.p; // do not clone() if (rel.f != null) { C2 = ring.valueOf(rel.f); Cs = Cs.multiply(C2); if (rel.e == null) { e4 = e2; } else { e4 = e2.subtract(rel.e); } ring.table.update(e4, f2, Cs); } if (rel.e != null) { C1 = ring.valueOf(rel.e); Cs = C1.multiply(Cs); ring.table.update(e2, f2, Cs); } if (!f1.isZERO()) { C2 = ring.valueOf(f1); Cs = Cs.multiply(C2); //ring.table.update(?,f1,Cs) } if (!e1.isZERO()) { C1 = ring.valueOf(e1); Cs = C1.multiply(Cs); //ring.table.update(e1,?,Cs) } } //System.out.println("Cs = " + Cs + ", a = " + a + ", b = " + b); Cs = Cs.multiply(a, b); // now non-symmetric // Cs.multiply(c); is symmetric! Cp.doAddTo(Cs); } } return Cp; } /** * GenSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S GenSolvablePolynomial. * @param T GenSolvablePolynomial. * @return S*this*T. */ // new method, @NoOverride public GenSolvablePolynomial multiply(GenSolvablePolynomial S, GenSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * GenSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b coefficient. * @return this*b, where * is coefficient multiplication. */ @Override @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial multiply(C b) { GenSolvablePolynomial Cp = ring.getZERO(); if (b == null || b.isZERO()) { return Cp; } if (this instanceof RecSolvablePolynomial && b instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE Rec.multiply(b) - trying to fix"); RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no GenSolvablePolynomial Sp = (GenSolvablePolynomial) b; return (GenSolvablePolynomial) T.recMultiply(Sp); } if (this instanceof QLRSolvablePolynomial && b instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE QLR.multiply(Bp) - trying to fix"); QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no GenSolvablePolynomial Sp = (GenSolvablePolynomial) b; return (GenSolvablePolynomial) T.multiply(Sp); } Cp = Cp.copy(); Map Cm = Cp.val; Map Am = val; for (Map.Entry y : Am.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); C c = a.multiply(b); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * GenSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient. * @param c coefficient. * @return b*this*c, where * is coefficient multiplication. */ // new method, @NoOverride @SuppressWarnings({ "cast", "unchecked" }) public GenSolvablePolynomial multiply(C b, C c) { GenSolvablePolynomial Cp = ring.getZERO(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } if (this instanceof RecSolvablePolynomial && b instanceof GenSolvablePolynomial && c instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE Rec.multiply(b,c) - trying to fix"); RecSolvablePolynomial T = (RecSolvablePolynomial) this; // no GenSolvablePolynomial Bp = (GenSolvablePolynomial) b; GenSolvablePolynomial Dp = (GenSolvablePolynomial) c; return (GenSolvablePolynomial) T.multiply(Bp, Dp); } if (this instanceof QLRSolvablePolynomial && b instanceof GenSolvablePolynomial && c instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.info("warn: wrong method dispatch in JRE QLR.multiply(b,c) - trying to fix"); QLRSolvablePolynomial T = (QLRSolvablePolynomial) this; // no GenSolvablePolynomial Bp = (GenSolvablePolynomial) b; GenSolvablePolynomial Dp = (GenSolvablePolynomial) c; return (GenSolvablePolynomial) T.multiply(Bp, Dp); } Cp = Cp.copy(); Map Cm = Cp.val; Map Am = val; for (Map.Entry y : Am.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); C d = b.multiply(a).multiply(c); if (!d.isZERO()) { Cm.put(e, d); } } return Cp; } /** * GenSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public GenSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } C b = ring.getONECoefficient(); return multiply(b, e); } /** * GenSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ // new method, @NoOverride public GenSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } C b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * GenSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public GenSolvablePolynomial multiply(C b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } GenSolvablePolynomial Cp = ring.valueOf(b, e); //new GenSolvablePolynomial(ring, b, e); return multiply(Cp); } /** * GenSolvablePolynomial left and right multiplication. Product with ring * element and exponent vector. * @param b coefficient. * @param e exponent. * @param c coefficient. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ // new method, @NoOverride public GenSolvablePolynomial multiply(C b, ExpVector e, C c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } GenSolvablePolynomial Cp = ring.valueOf(b, e); //new GenSolvablePolynomial(ring, b, e); GenSolvablePolynomial Dp = ring.valueOf(c, f); //new GenSolvablePolynomial(ring, c, f); return multiply(Cp, Dp); } /** * GenSolvablePolynomial multiplication. Left product with ring element and * exponent vector. * @param b coefficient. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ public GenSolvablePolynomial multiplyLeft(C b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } GenSolvablePolynomial Cp = ring.valueOf(b, e); return Cp.multiply(this); } /** * GenSolvablePolynomial multiplication. Left product with exponent vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ public GenSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } C b = ring.getONECoefficient(); return multiplyLeft(b, e); } /** * GenSolvablePolynomial multiplication. Left product with coefficient ring * element. * @param b coefficient. * @return b*this, where * is coefficient multiplication. */ @Override public GenSolvablePolynomial multiplyLeft(C b) { GenSolvablePolynomial Cp = ring.getZERO(); if (b == null || b.isZERO()) { return Cp; } Cp = Cp.copy(); Map Cm = Cp.val; //getMap(); Map Am = val; for (Map.Entry y : Am.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); C c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * GenSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ // new method, @NoOverride public GenSolvablePolynomial multiplyLeft(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * GenSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public GenSolvablePolynomial multiply(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * GenSolvablePolynomial subtract a multiple. * @param a coefficient. * @param S GenSolvablePolynomial. * @return this - a * S. */ public GenSolvablePolynomial subtractMultiple(C a, GenSolvablePolynomial S) { if (a == null || a.isZERO()) { return this; } if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S.multiplyLeft(a.negate()); } assert (ring.nvar == S.ring.nvar); GenSolvablePolynomial n = this.copy(); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); C y = me.getValue(); // assert y != null y = a.multiply(y); C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenSolvablePolynomial subtract a multiple. * @param a coefficient. * @param e exponent. * @param S GenSolvablePolynomial. * @return this - a * xe * S. */ public GenSolvablePolynomial subtractMultiple(C a, ExpVector e, GenSolvablePolynomial S) { if (a == null || a.isZERO()) { return this; } if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S.multiplyLeft(a.negate(), e); } assert (ring.nvar == S.ring.nvar); GenSolvablePolynomial n = this.copy(); SortedMap nv = n.val; GenSolvablePolynomial s = S.multiplyLeft(e); SortedMap sv = s.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); //f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenSolvablePolynomial scale and subtract a multiple. * @param b scale factor. * @param a coefficient. * @param S GenSolvablePolynomial. * @return b * this - a * S. */ public GenSolvablePolynomial scaleSubtractMultiple(C b, C a, GenSolvablePolynomial S) { if (a == null || S == null) { return this.multiplyLeft(b); } if (a.isZERO() || S.isZERO()) { return this.multiplyLeft(b); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiplyLeft(a.negate()); } if (b.isONE()) { return subtractMultiple(a, S); } assert (ring.nvar == S.ring.nvar); GenSolvablePolynomial n = this.multiplyLeft(b); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); //f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // now y can be zero C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenSolvablePolynomial scale and subtract a multiple. * @param b scale factor. * @param a coefficient. * @param e exponent. * @param S GenSolvablePolynomial. * @return b * this - a * xe * S. */ public GenSolvablePolynomial scaleSubtractMultiple(C b, C a, ExpVector e, GenSolvablePolynomial S) { if (a == null || S == null) { return this.multiplyLeft(b); } if (a.isZERO() || S.isZERO()) { return this.multiplyLeft(b); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiplyLeft(a.negate(), e); } if (b.isONE()) { return subtractMultiple(a, e, S); } assert (ring.nvar == S.ring.nvar); GenSolvablePolynomial n = this.multiplyLeft(b); SortedMap nv = n.val; GenSolvablePolynomial s = S.multiplyLeft(e); SortedMap sv = s.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); //f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // now y can be zero C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenSolvablePolynomial scale and subtract a multiple. * @param b scale factor. * @param g scale exponent. * @param a coefficient. * @param e exponent. * @param S GenSolvablePolynomial. * @return a * xg * this - a * xe * S. */ public GenSolvablePolynomial scaleSubtractMultiple(C b, ExpVector g, C a, ExpVector e, GenSolvablePolynomial S) { if (a == null || S == null) { return this.multiplyLeft(b, g); } if (a.isZERO() || S.isZERO()) { return this.multiplyLeft(b, g); } if (this.isZERO() || b == null || b.isZERO()) { return S.multiplyLeft(a.negate(), e); } if (b.isONE() && g.isZERO()) { return subtractMultiple(a, e, S); } assert (ring.nvar == S.ring.nvar); GenSolvablePolynomial n = this.multiplyLeft(b, g); SortedMap nv = n.val; GenSolvablePolynomial s = S.multiplyLeft(e); SortedMap sv = s.val; for (Map.Entry me : sv.entrySet()) { ExpVector f = me.getKey(); //f = e.sum(f); C y = me.getValue(); // assert y != null y = a.multiply(y); // y can be zero now C x = nv.get(f); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(f, x); } else { nv.remove(f); } } else if (!y.isZERO()) { nv.put(f, y.negate()); } } return n; } /** * GenSolvablePolynomial left monic, i.e. leadingCoefficient == 1. If * leadingCoefficient is not invertible returns this abs value. * @return ldcf(this)**(-1) * this. */ @Override public GenSolvablePolynomial monic() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lc = "+lc); return this; //return (GenSolvablePolynomial) this.abs(); } C lm = lc.inverse(); return (GenSolvablePolynomial) multiplyLeft(lm); //.abs(); } /** * GenSolvablePolynomial left monic, i.e. leadingCoefficient == 1. If * leadingCoefficient is not invertible returns this abs value. * @return ldcf(this)**(-1) * this. */ //@Override public GenSolvablePolynomial leftMonic() { return monic(); } /** * GenSolvablePolynomial right monic, i.e. leadingCoefficient == 1. If * leadingCoefficient is not invertible returns this abs value. * @return this * ldcf(this)**(-1). */ //@Override public GenSolvablePolynomial rightMonic() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lm = "+lm); return this; //return (GenSolvablePolynomial) this.abs(); } C lm = lc.inverse(); return (GenSolvablePolynomial) multiply(lm); //.abs(); } /** * GenSolvablePolynomial left division. Fails, if exact division by leading * base coefficient is not possible. Meaningful only for univariate * polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return quotient with this = quotient * S + remainder and deg(remainder) * < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ // cannot @Override @SuppressWarnings("unchecked") public GenSolvablePolynomial divide(GenSolvablePolynomial S) { return quotientRemainder(S)[0]; } /** * GenSolvablePolynomial remainder by left division. Fails, if exact * division by leading base coefficient is not possible. Meaningful only for * univariate polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return remainder with this = quotient * S + remainder and deg(remainder) * < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ // cannot @Override @SuppressWarnings("unchecked") public GenSolvablePolynomial remainder(GenSolvablePolynomial S) { return quotientRemainder(S)[1]; } /** * GenSolvablePolynomial left division with remainder. Fails, if exact * division by leading base coefficient is not possible. Meaningful only for * univariate polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return [ quotient , remainder ] with this = quotient * S + remainder and * deg(remainder) < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ // cannot @Override @SuppressWarnings("unchecked") public GenSolvablePolynomial[] quotientRemainder(GenSolvablePolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException("lbcf not invertible " + c); } C ci = c.inverse(); assert (ring.nvar == S.ring.nvar); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial h; GenSolvablePolynomial q = ring.getZERO().copy(); GenSolvablePolynomial r = this.copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); //System.out.println("FDQR: f = " + f + ", a = " + a); f = f.subtract(e); //a = ci.multiply(a); // multiplyLeft a = a.multiply(ci); // this is correct! q = (GenSolvablePolynomial) q.sum(a, f); h = S.multiplyLeft(a, f); if (!h.leadingBaseCoefficient().equals(r.leadingBaseCoefficient())) { throw new RuntimeException("something is wrong: r = " + r + ", h = " + h); } r = (GenSolvablePolynomial) r.subtract(h); } else { break; } } //System.out.println("(left)QR: q = " + q + ", r = " + r); GenSolvablePolynomial[] ret = new GenSolvablePolynomial[2]; ret[0] = q; ret[1] = r; return ret; } /** * GenSolvablePolynomial right division. Fails, if exact division by leading * base coefficient is not possible. Meaningful only for univariate * polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return quotient with this = S * quotient + remainder and deg(remainder) * < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightDivide(GenSolvablePolynomial S) { return rightQuotientRemainder(S)[0]; } /** * GenSolvablePolynomial remainder by right division. Fails, if exact * division by leading base coefficient is not possible. Meaningful only for * univariate polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return remainder with this = S * quotient + remainder and deg(remainder) * < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightRemainder(GenSolvablePolynomial S) { return rightQuotientRemainder(S)[1]; } /** * GenSolvablePolynomial right division with remainder. Fails, if exact * division by leading base coefficient is not possible. Meaningful only for * univariate polynomials over fields, but works in any case. * @param S nonzero GenSolvablePolynomial with invertible leading * coefficient. * @return [ quotient , remainder ] with this = S * quotient + remainder and * deg(remainder) < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) */ @SuppressWarnings("unchecked") public GenSolvablePolynomial[] rightQuotientRemainder(GenSolvablePolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException("division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException("lbcf not invertible " + c); } C ci = c.inverse(); assert (ring.nvar == S.ring.nvar); ExpVector e = S.leadingExpVector(); GenSolvablePolynomial h; GenSolvablePolynomial q = ring.getZERO().copy(); GenSolvablePolynomial r = this.copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); //System.out.println("FDQR: f = " + f + ", a = " + a); f = f.subtract(e); //a = a.multiplyLeft(ci); // not existing a = ci.multiply(a); // this is correct! q = (GenSolvablePolynomial) q.sum(a, f); h = S.multiply(a, f); if (!h.leadingBaseCoefficient().equals(r.leadingBaseCoefficient())) { throw new RuntimeException("something is wrong: r = " + r + ", h = " + h); } r = (GenSolvablePolynomial) r.subtract(h); } else { break; } } System.out.println("rightQR: q = " + q + ", r = " + r); GenSolvablePolynomial[] ret = new GenSolvablePolynomial[2]; ret[0] = q; ret[1] = r; return ret; } /** * RecSolvablePolynomial right coefficients from left coefficients. * Note: R is represented as a polynomial with left coefficients, the * implementation can at the moment not distinguish between left and right * coefficients. * @return R = sum( Xi bi ), with P = * sum(ai Xi ) and eval(sum(Xi * bi)) == sum(ai Xi) */ @SuppressWarnings("unchecked") public GenSolvablePolynomial rightRecursivePolynomial() { if (this.isONE() || this.isZERO()) { return this; } if (!(this instanceof RecSolvablePolynomial)) { return this; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { return this; } RecSolvablePolynomial p = (RecSolvablePolynomial) this; RecSolvablePolynomial R = (RecSolvablePolynomial) p.rightRecursivePolynomial(); return (GenSolvablePolynomial) R; } /** * Evaluate RecSolvablePolynomial as right coefficients polynomial. * Note: R is represented as a polynomial with left coefficients, the * implementation can at the moment not distinguish between left and right * coefficients. * @return this as evaluated polynomial R. R = sum( Xi * bi ), this = sum(ai Xi ) = * eval(sum(Xi bi)) */ @SuppressWarnings("unchecked") public GenSolvablePolynomial evalAsRightRecursivePolynomial() { if (this.isONE() || this.isZERO()) { return this; } if (!(this instanceof RecSolvablePolynomial)) { return this; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { return this; } RecSolvablePolynomial p = (RecSolvablePolynomial) this; RecSolvablePolynomial R = (RecSolvablePolynomial) p.evalAsRightRecursivePolynomial(); return (GenSolvablePolynomial) R; } /** * Test RecSolvablePolynomial right coefficients polynomial. Note: R * is represented as a polynomial with left coefficients, the implementation * can at the moment not distinguish between left and right coefficients. * @param R GenSolvablePolynomial with right coefficients. * @return true, if R is polynomial with right coefficients of this. R = * sum( Xi bi ), with this = sum(ai * Xi ) and eval(sum(Xi bi)) == * sum(ai Xi) */ @SuppressWarnings("unchecked") public boolean isRightRecursivePolynomial(GenSolvablePolynomial R) { if (this.isZERO()) { return R.isZERO(); } if (this.isONE()) { return R.isONE(); } if (!(this instanceof RecSolvablePolynomial)) { return !(R instanceof RecSolvablePolynomial); } if (!(R instanceof RecSolvablePolynomial)) { return false; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { RecSolvablePolynomialRing rf = (RecSolvablePolynomialRing) R.ring; return rf.coeffTable.isEmpty(); } RecSolvablePolynomial p = (RecSolvablePolynomial) this; RecSolvablePolynomial q = (RecSolvablePolynomial) R; return p.isRightRecursivePolynomial(q); } } java-algebra-system-2.7.200/src/edu/jas/poly/GenSolvablePolynomialRing.java000066400000000000000000000640341445075545500266010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * GenSolvablePolynomialRing generic solvable polynomial factory implementing * RingFactory and extending GenPolynomialRing factory. Factory for n-variate * ordered solvable polynomials over C. The non-commutative multiplication * relations are maintained in a relation table. Almost immutable object, except * variable names and relation table contents. * @param coefficient type. * @author Heinz Kredel */ public class GenSolvablePolynomialRing> extends GenPolynomialRing { // implements RingFactory< GenSolvablePolynomial > { /** * The solvable multiplication relations. */ public final RelationTable table; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public /*final*/ GenSolvablePolynomial ZERO; //volatile not meaningful by DL /** * The constant polynomial 1 for this ring. Hides super ONE. */ public /*final*/ GenSolvablePolynomial ONE; //volatile not meaningful by DL private static final Logger logger = LogManager.getLogger(GenSolvablePolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public GenSolvablePolynomialRing(RingFactory cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public GenSolvablePolynomialRing(RingFactory cf, int n, RelationTable rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public GenSolvablePolynomialRing(RingFactory cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public GenSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, RelationTable rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public GenSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public GenSolvablePolynomialRing(RingFactory cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public GenSolvablePolynomialRing(RingFactory cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public GenSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, String[] v, RelationTable rt) { super(cf, n, t, v); if (rt == null) { table = new RelationTable(this); } else { table = rt; } C coeff = coFac.getONE(); synchronized (this) { ZERO = new GenSolvablePolynomial(this); //evzero = ExpVector.create(nvar); // from super ONE = new GenSolvablePolynomial(this, coeff, evzero); } } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other (solvable) polynomial ring. */ public GenSolvablePolynomialRing(RingFactory cf, GenPolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * Generate the relation table of the solvable polynomial ring from a * relation generator. * @param rg relation generator. */ public void addRelations(RelationGenerator rg) { rg.generate(this); } /** * Generate the relation table of the solvable polynomial ring from a * polynomial list of relations. * @param rel polynomial list of relations [..., ei, fj, pij, ... ] with ei * * fj = pij. */ public void addRelations(List> rel) { table.addRelations(rel); } /** * Generate the relation table of the solvable polynomial ring from a * solvable polynomial list of relations. * @param rel solvable polynomial list of relations [..., ei, fj, pij, ... ] * with ei * fj = pij. */ public void addSolvRelations(List> rel) { table.addSolvRelations(rel); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { res += "\n" + table.toString(vars); } else { res += ", #rel = " + table.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof GenSolvablePolynomialRing)) { return false; } GenSolvablePolynomialRing oring = (GenSolvablePolynomialRing) other; if (!super.equals(other)) { return false; } // check same base relations if (!table.equals(oring.table)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); //System.out.println("GenSolvablePolynomialRing.hashCode: " + h); return h; } /** * Get the zero element. * @return 0 as GenSolvablePolynomial. */ @Override public synchronized GenSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 GenSolvablePolynomial x = ZERO; ZERO = new GenSolvablePolynomial(this); logger.info("warn: ZERO@get |{}| wrong fix to {}", x, ZERO); } return ZERO; } /** * Get the one element. * @return 1 as GenSolvablePolynomial. */ @Override public synchronized GenSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { ONE = new GenSolvablePolynomial(this, coFac.getONE(), evzero); logger.info("warn: ONE@get {}", ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (table.isEmpty()) { return super.isCommutative(); } return false; } /** * Query if this ring is associative. Test if the relations define an * associative solvable ring. * @return true, if this ring is associative, else false. */ @SuppressWarnings("unused") @Override public boolean isAssociative() { GenSolvablePolynomial Xi, Xj, Xk, p, q; for (int i = 0; i < nvar; i++) { Xi = univariate(i); for (int j = i + 1; j < nvar; j++) { Xj = univariate(j); for (int k = j + 1; k < nvar; k++) { Xk = univariate(k); p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { if (logger.isInfoEnabled()) { logger.info("Xi = {}, Xj = {}, Xk = {}", Xi, Xj, Xk); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); } return false; } } } } return coFac.isAssociative(); } /** * Get a (constant) GenPolynomial<C> element from a coefficient value. * @param a coefficient. * @return a GenPolynomial<C>. */ @Override public GenSolvablePolynomial valueOf(C a) { return new GenSolvablePolynomial(this, a); } /** * Get a GenPolynomial<C> element from an exponent vector. * @param e exponent vector. * @return a GenPolynomial<C>. */ @Override public GenSolvablePolynomial valueOf(ExpVector e) { return new GenSolvablePolynomial(this, coFac.getONE(), e); } /** * Get a GenPolynomial<C> element from a coefficient and an exponent * vector. * @param a coefficient. * @param e exponent vector. * @return a GenPolynomial<C>. */ @Override public GenSolvablePolynomial valueOf(C a, ExpVector e) { return new GenSolvablePolynomial(this, a, e); } /** * Get a (constant) GenSolvablePolynomial<C> element from a long * value. * @param a long. * @return a GenSolvablePolynomial<C>. */ @Override public GenSolvablePolynomial fromInteger(long a) { return new GenSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) GenSolvablePolynomial<C> element from a BigInteger * value. * @param a BigInteger. * @return a GenSolvablePolynomial<C>. */ @Override public GenSolvablePolynomial fromInteger(BigInteger a) { return new GenSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public GenSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public GenSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public GenSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public GenSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { GenSolvablePolynomial r = getZERO(); ExpVector e; C a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); //System.out.println("i = " + i + ", e = " + e + ", a = " + a); //if (!r.val.keySet().contains(e)) { r = (GenSolvablePolynomial) r.sum(a, e); //somewhat inefficient but clean //r.doPutToMap(e, a); //} } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public GenSolvablePolynomial copy(GenSolvablePolynomial c) { return new GenSolvablePolynomial(this, c.val); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return GenSolvablePolynomial from s. */ @Override public GenSolvablePolynomial parse(String s) { //return getZERO(); return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next GenSolvablePolynomial from r. */ @Override @SuppressWarnings({ "unchecked", "cast" }) public GenSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); GenSolvablePolynomial p = null; try { p = (GenSolvablePolynomial) pt.nextSolvablePolynomial(); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public GenSolvablePolynomial univariate(int i) { return (GenSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public GenSolvablePolynomial univariate(int i, long e) { return (GenSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public GenSolvablePolynomial univariate(int modv, int i, long e) { return (GenSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { //return castToSolvableList( super.univariateList() ); return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { GenSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. New variables commute with the exiting variables. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public GenSolvablePolynomialRing extend(int i) { return extend(i,false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. New variables commute with the exiting variables. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public GenSolvablePolynomialRing extend(int i, boolean top) { GenPolynomialRing pfac = super.extend(i, top); GenSolvablePolynomialRing spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.table.extend(this.table); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @return extended polynomial ring factory. */ @Override public GenSolvablePolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ @Override public GenSolvablePolynomialRing extend(String[] vn, boolean top) { GenPolynomialRing pfac = super.extend(vn, top); GenSolvablePolynomialRing spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); //GenSolvablePolynomialRing spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac); spfac.table.extend(this.table); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public GenSolvablePolynomialRing contract(int i) { GenPolynomialRing pfac = super.contract(i); GenSolvablePolynomialRing spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.table.contract(this.table); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public GenSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public GenSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing pfac = super.reverse(partial); GenSolvablePolynomialRing spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.partial = partial; spfac.table.reverse(this.table); return spfac; } /** * Recursive representation as polynomial ring with i main variables. * @param i number of main variables. * @return recursive polynomial ring factory. */ @Override public GenSolvablePolynomialRing> recursive(int i) { if (i <= 0 || i >= nvar) { throw new IllegalArgumentException("wrong: 0 < " + i + " < " + nvar); } GenSolvablePolynomialRing cfac = contract(i); //System.out.println("cvars = " + Arrays.toString(cfac.vars)); //System.out.println("vars = " + Arrays.toString(vars)); String[] v = null; if (vars != null) { v = new String[i]; int k = 0; for (int j = nvar - i; j < nvar; j++) { v[k++] = vars[j]; } } //System.out.println("v = " + Arrays.toString(v)); TermOrder to = tord.contract(0, i); // ?? RecSolvablePolynomialRing pfac = new RecSolvablePolynomialRing(cfac, i, to, v); //System.out.println("pfac = " + pfac.toScript()); pfac.table.recursive(table); pfac.coeffTable.recursive(table); return pfac; } /** * Distributive representation as polynomial with all main variables. * @return distributive polynomial ring factory. */ @SuppressWarnings({ "unchecked", "cast" }) @Override public GenSolvablePolynomialRing distribute() { if (!(coFac instanceof GenPolynomialRing)) { return this; } RingFactory cf = coFac; RingFactory> cfp = (RingFactory>) cf; GenPolynomialRing cr = (GenPolynomialRing) cfp; //System.out.println("cr = " + cr.toScript()); GenPolynomialRing fac; if (cr.vars != null) { fac = cr.extend(vars); } else { fac = cr.extend(nvar); } //System.out.println("fac = " + fac.toScript()); // fac could be a commutative polynomial ring, coefficient relations GenSolvablePolynomialRing pfac = new GenSolvablePolynomialRing(fac.coFac, fac.nvar, this.tord, fac.vars); //System.out.println("pfac = " + pfac.toScript()); if (fac instanceof GenSolvablePolynomialRing) { GenSolvablePolynomialRing sfac = (GenSolvablePolynomialRing) fac; List> rlc = sfac.table.relationList(); pfac.table.addSolvRelations(rlc); //System.out.println("pfac = " + pfac.toScript()); } // main relations List>> rl = (List>>) (List) PolynomialList .castToList(table.relationList()); List> rld = PolyUtil. distribute(pfac, rl); pfac.table.addRelations(rld); //System.out.println("pfac = " + pfac.toScript()); // coeffTable not available here return pfac; } /** * Permutation of polynomial ring variables. * @param P permutation, must be compatible with the commutator relations. * @return P(this). */ @Override public GenPolynomialRing permutation(List P) { GenPolynomialRing pfac = super.permutation(P); GenSolvablePolynomialRing spfac; spfac = new GenSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); List> rl = this.table.relationList(); PolynomialList prl = new PolynomialList(spfac,rl); List> pl = prl.getList(); pl = TermOrderOptimization.permutation(P, spfac, pl); spfac.table.addRelations(pl); return spfac; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenWordPolynomial.java000066400000000000000000001315121445075545500251210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PreemptingException; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; import edu.jas.structure.UnaryFunctor; /** * GenWordPolynomial generic polynomials implementing RingElem. Non-commutative * string polynomials over C. Objects of this class are intended to be * immutable. The implementation is based on TreeMap respectively SortedMap from * words to coefficients. Only the coefficients are modeled with generic types, * the "exponents" are fixed to Word. C can also be a non integral domain, e.g. * a ModInteger, i.e. it may contain zero divisors, since multiply() does check * for zeros. * @param coefficient type * @author Heinz Kredel */ public final class GenWordPolynomial> implements RingElem>, Iterable> { /** * The factory for the polynomial ring. */ public final GenWordPolynomialRing ring; /** * The data structure for polynomials. */ final SortedMap val; // do not change to TreeMap private static final Logger logger = LogManager.getLogger(GenWordPolynomial.class); private static final boolean debug = logger.isDebugEnabled(); // protected GenWordPolynomial() { ring = null; val = null; } // don't use /** * Private constructor for GenWordPolynomial. * @param r polynomial ring factory. * @param t TreeMap with correct ordering. */ private GenWordPolynomial(GenWordPolynomialRing r, TreeMap t) { ring = r; val = t; if (ring.checkPreempt) { if (Thread.currentThread().isInterrupted()) { logger.debug("throw PreemptingException"); throw new PreemptingException(); } } } /** * Constructor for zero GenWordPolynomial. * @param r polynomial ring factory. */ public GenWordPolynomial(GenWordPolynomialRing r) { this(r, new TreeMap(r.alphabet.getDescendComparator())); } /** * Constructor for GenWordPolynomial c * xe. * @param r polynomial ring factory. * @param c coefficient. * @param e word. */ public GenWordPolynomial(GenWordPolynomialRing r, C c, Word e) { this(r); if (!c.isZERO()) { val.put(e, c); } } /** * Constructor for GenWordPolynomial c * x0. * @param r polynomial ring factory. * @param c coefficient. */ public GenWordPolynomial(GenWordPolynomialRing r, C c) { this(r, c, r.wone); } /** * Constructor for GenWordPolynomial xe. * @param r polynomial ring factory. * @param e word. */ public GenWordPolynomial(GenWordPolynomialRing r, Word e) { this(r, r.coFac.getONE(), e); } /** * Constructor for GenWordPolynomial xe. * @param r polynomial ring factory. * @param e exponent vector. */ public GenWordPolynomial(GenWordPolynomialRing r, ExpVector e) { this(r, r.coFac.getONE(), r.alphabet.valueOf(e)); } /** * Constructor for GenWordPolynomial c * xe. * @param r polynomial ring factory. * @param c coefficient. * @param e exponent vector. */ public GenWordPolynomial(GenWordPolynomialRing r, C c, ExpVector e) { this(r, c, r.alphabet.valueOf(e)); } /** * Constructor for GenWordPolynomial. * @param r polynomial ring factory. * @param v the SortedMap of some other polynomial. */ protected GenWordPolynomial(GenWordPolynomialRing r, SortedMap v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public GenWordPolynomialRing factory() { return ring; } /** * Copy this GenWordPolynomial. * @return copy of this. */ public GenWordPolynomial copy() { return new GenWordPolynomial(ring, this.val); } /** * Length of GenWordPolynomial. * @return number of coefficients of this GenWordPolynomial. */ public int length() { return val.size(); } /** * Word to coefficient map of GenWordPolynomial. * @return val as unmodifiable SortedMap. */ public SortedMap getMap() { // return val; return Collections. unmodifiableSortedMap(val); } /** * Put a Word to coefficient entry into the internal map of this * GenWordPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param c coefficient. * @param e word. */ public void doPutToMap(Word e, C c) { if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, c); } } if (!c.isZERO()) { val.put(e, c); } } /** * Remove a Word to coefficient entry from the internal map of this * GenWordPolynomial. Note: Do not use this method unless you are * constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param e Word. * @param c expected coefficient, null for ignore. */ public void doRemoveFromMap(Word e, C c) { C b = val.remove(e); if (debug) { if (c == null) { // ignore b return; } if (!c.equals(b)) { logger.error("map entry wrong {} to {} old {}", e, c, b); } } } /** * Put an a sorted map of words to coefficients into the internal map of * this GenWordPolynomial. Note: Do not use this method unless you * are constructing a new polynomial. this is modified and breaks the * immutability promise of this class. * @param vals sorted map of wordss and coefficients. */ public void doPutToMap(SortedMap vals) { for (Map.Entry me : vals.entrySet()) { Word e = me.getKey(); if (debug) { C a = val.get(e); if (a != null) { logger.error("map entry exists {} to {} new {}", e, a, me.getValue()); } } C c = me.getValue(); if (!c.isZERO()) { val.put(e, c); } } } /** * String representation of GenWordPolynomial. * @see java.lang.Object#toString() */ @Override public String toString() { if (isZERO()) { return "0"; } if (isONE()) { return "1"; } StringBuffer s = new StringBuffer(); if (val.size() > 1) { s.append("( "); } boolean parenthesis = false; boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } Word e = m.getKey(); if (!c.isONE() || e.isONE()) { if (parenthesis) { s.append("( "); } String cs = c.toString(); if (cs.indexOf("+") >= 0 || cs.indexOf("-") >= 0) { s.append("( " + cs + " )"); } else { s.append(cs); } if (parenthesis) { s.append(" )"); } if (!e.isONE()) { s.append(" "); } } s.append(e.toString()); } if (val.size() > 1) { s.append(" )"); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { if (isZERO()) { return "0"; } if (isONE()) { return "1"; } StringBuffer s = new StringBuffer(); if (val.size() > 1) { s.append("( "); } final boolean parenthesis = false; boolean first = true; for (Map.Entry m : val.entrySet()) { C c = m.getValue(); if (first) { first = false; } else { if (c.signum() < 0) { s.append(" - "); c = c.negate(); } else { s.append(" + "); } } Word e = m.getKey(); if (!c.isONE() || e.isONE()) { if (parenthesis) { s.append("( "); } String cs = c.toScript(); if (cs.indexOf("+") >= 0 || cs.indexOf("-") >= 0) { s.append("( " + cs + " )"); } else { s.append(cs); } if (parenthesis) { s.append(" )"); } if (!e.isONE()) { s.append(" * "); } } s.append(e.toScript()); } if (val.size() > 1) { s.append(" )"); } return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Is GenWordPolynomial<C> zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return (val.size() == 0); } /** * Is GenWordPolynomial<C> one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return c.isONE(); } /** * Is GenWordPolynomial<C> a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return c.isUnit(); } /** * Is GenWordPolynomial<C> a constant. * @return If this is a constant polynomial then true is returned, else * false. */ public boolean isConstant() { if (val.size() != 1) { return false; } C c = val.get(ring.wone); if (c == null) { return false; } return true; } /** * Is GenWordPolynomial<C> homogeneous. * @return true, if this is homogeneous, else false. */ public boolean isHomogeneous() { if (val.size() <= 1) { return true; } long deg = -1; for (Word e : val.keySet()) { if (deg < 0) { deg = e.degree(); } else if (deg != e.degree()) { return false; } } return true; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof GenWordPolynomial)) { return false; } GenWordPolynomial a = (GenWordPolynomial) B; return this.compareTo(a) == 0; } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = (ring.hashCode() << 27); h += val.hashCode(); return h; } /** * GenWordPolynomial comparison. * @param b GenWordPolynomial. * @return sign(this-b). */ public int compareTo(GenWordPolynomial b) { if (b == null) { return 1; } SortedMap av = this.val; SortedMap bv = b.val; Iterator> ai = av.entrySet().iterator(); Iterator> bi = bv.entrySet().iterator(); int s = 0; int c = 0; while (ai.hasNext() && bi.hasNext()) { Map.Entry aie = ai.next(); Map.Entry bie = bi.next(); Word ae = aie.getKey(); Word be = bie.getKey(); s = ae.compareTo(be); //System.out.println("s = " + s + ", " + ae + ", " +be); if (s != 0) { return s; } if (c == 0) { C ac = aie.getValue(); //av.get(ae); C bc = bie.getValue(); //bv.get(be); c = ac.compareTo(bc); } } if (ai.hasNext()) { return 1; } if (bi.hasNext()) { return -1; } // now all keys are equal return c; } /** * GenWordPolynomial signum. * @return sign(ldcf(this)). */ public int signum() { if (this.isZERO()) { return 0; } Word t = val.firstKey(); C c = val.get(t); return c.signum(); } /** * Number of variables. * @return ring.alphabet.length(). */ public int numberOfVariables() { return ring.alphabet.length(); } /** * Leading monomial. * @return first map entry. */ public Map.Entry leadingMonomial() { if (val.size() == 0) return null; Iterator> ai = val.entrySet().iterator(); return ai.next(); } /** * Leading word. * @return first highest word. */ public Word leadingWord() { if (val.size() == 0) { return ring.wone; // null? needs changes? } return val.firstKey(); } /** * Trailing word. * @return last lowest word. */ public Word trailingWord() { if (val.size() == 0) { return ring.wone; // or null ?; } return val.lastKey(); } /** * Leading base coefficient. * @return first coefficient. */ public C leadingBaseCoefficient() { if (val.size() == 0) { return ring.coFac.getZERO(); } return val.get(val.firstKey()); } /** * Trailing base coefficient. * @return coefficient of constant term. */ public C trailingBaseCoefficient() { C c = val.get(ring.wone); if (c == null) { return ring.coFac.getZERO(); } return c; } /** * Coefficient. * @param e word. * @return coefficient for given word. */ public C coefficient(Word e) { C c = val.get(e); if (c == null) { c = ring.coFac.getZERO(); } return c; } /** * Reductum. * @return this - leading monomial. */ public GenWordPolynomial reductum() { if (val.size() <= 1) { return ring.getZERO(); } Iterator ai = val.keySet().iterator(); Word lt = ai.next(); lt = ai.next(); // size > 1 SortedMap red = val.tailMap(lt); return new GenWordPolynomial(ring, red); } /** * Maximal degree. * @return maximal degree in any variables. */ public long degree() { if (val.size() == 0) { return 0; // 0 or -1 ?; } long deg = 0; for (Word e : val.keySet()) { long d = e.degree(); if (d > deg) { deg = d; } } return deg; } /** * GenWordPolynomial maximum norm. * @return ||this||. */ public C maxNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); if (n.compareTo(x) < 0) { n = x; } } return n; } /** * GenWordPolynomial sum norm. * @return sum of all absolute values of coefficients. */ public C sumNorm() { C n = ring.getZEROCoefficient(); for (C c : val.values()) { C x = c.abs(); n = n.sum(x); } return n; } /** * GenWordPolynomial summation. * @param S GenWordPolynomial. * @return this+S. */ public GenWordPolynomial sum(GenWordPolynomial S) { if (S == null) { return this; } if (S.isZERO()) { return this; } if (this.isZERO()) { return S; } assert (ring.alphabet == S.ring.alphabet); GenWordPolynomial n = this.copy(); //new GenWordPolynomial(ring, val); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { Word e = me.getKey(); C y = me.getValue(); //sv.get(e); // assert y != null C x = nv.get(e); if (x != null) { x = x.sum(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y); } } return n; } /** * GenWordPolynomial addition. This method is not very efficient, since this * is copied. * @param a coefficient. * @param e word. * @return this + a e. */ public GenWordPolynomial sum(C a, Word e) { if (a == null) { return this; } if (a.isZERO()) { return this; } GenWordPolynomial n = this.copy(); //new GenWordPolynomial(ring, val); SortedMap nv = n.val; C x = nv.get(e); if (x != null) { x = x.sum(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a); } return n; } /** * GenWordPolynomial addition. This method is not very efficient, since this * is copied. * @param a coefficient. * @return this + a x0. */ public GenWordPolynomial sum(C a) { return sum(a, ring.wone); } /** * GenWordPolynomial subtraction. * @param S GenWordPolynomial. * @return this-S. */ public GenWordPolynomial subtract(GenWordPolynomial S) { if (S == null) { return this; } if (S.isZERO()) { return this; } if (this.isZERO()) { return S.negate(); } assert (ring.alphabet == S.ring.alphabet); GenWordPolynomial n = this.copy(); //new GenWordPolynomial(ring, val); SortedMap nv = n.val; SortedMap sv = S.val; for (Map.Entry me : sv.entrySet()) { Word e = me.getKey(); C y = me.getValue(); //sv.get(e); // assert y != null C x = nv.get(e); if (x != null) { x = x.subtract(y); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, y.negate()); } } return n; } /** * GenWordPolynomial subtraction. This method is not very efficient, since * this is copied. * @param a coefficient. * @param e word. * @return this - a e. */ public GenWordPolynomial subtract(C a, Word e) { if (a == null) { return this; } if (a.isZERO()) { return this; } GenWordPolynomial n = this.copy(); //new GenWordPolynomial(ring, val); SortedMap nv = n.val; C x = nv.get(e); if (x != null) { x = x.subtract(a); if (!x.isZERO()) { nv.put(e, x); } else { nv.remove(e); } } else { nv.put(e, a.negate()); } return n; } /** * GenWordPolynomial subtract. This method is not very efficient, since this * is copied. * @param a coefficient. * @return this + a x0. */ public GenWordPolynomial subtract(C a) { return subtract(a, ring.wone); } /** * GenWordPolynomial negation. * @return -this. */ public GenWordPolynomial negate() { GenWordPolynomial n = ring.getZERO().copy(); SortedMap v = n.val; for (Map.Entry m : val.entrySet()) { C x = m.getValue(); // != null, 0 v.put(m.getKey(), x.negate()); } return n; } /** * GenWordPolynomial absolute value, i.e. leadingCoefficient > 0. * @return abs(this). */ public GenWordPolynomial abs() { if (leadingBaseCoefficient().signum() < 0) { return this.negate(); } return this; } /** * GenWordPolynomial multiplication. * @param S GenWordPolynomial. * @return this*S. */ public GenWordPolynomial multiply(GenWordPolynomial S) { if (S == null) { return ring.getZERO(); } if (S.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.alphabet == S.ring.alphabet) : " " + ring + " != " + S.ring; GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); Word e1 = m1.getKey(); for (Map.Entry m2 : S.val.entrySet()) { C c2 = m2.getValue(); Word e2 = m2.getKey(); C c = c1.multiply(c2); // check non zero if not domain if (!c.isZERO()) { Word e = e1.multiply(e2); C c0 = pv.get(e); if (c0 == null) { pv.put(e, c); } else { c0 = c0.sum(c); if (!c0.isZERO()) { pv.put(e, c0); } else { pv.remove(e); } } } } } return p; } /** * GenWordPolynomial left and right multiplication. Product with two * polynomials. * @param S GenWordPolynomial. * @param T GenWordPolynomial. * @return S*this*T. */ public GenWordPolynomial multiply(GenWordPolynomial S, GenWordPolynomial T) { if (S.isZERO() || T.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * GenWordPolynomial multiplication. Product with coefficient ring element. * @param s coefficient. * @return this*s. */ public GenWordPolynomial multiply(C s) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); Word e1 = m1.getKey(); C c = c1.multiply(s); // check non zero if not domain if (!c.isZERO()) { pv.put(e1, c); // or m1.setValue( c ) } } return p; } /** * GenWordPolynomial multiplication. Product with coefficient ring element. * @param s coefficient. * @param t coefficient. * @return s*this*t. */ public GenWordPolynomial multiply(C s, C t) { if (s == null || t == null) { return ring.getZERO(); } if (s.isZERO() || t.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); Word e = m1.getKey(); C c = s.multiply(c1).multiply(t); // check non zero if not domain if (!c.isZERO()) { pv.put(e, c); // or m1.setValue( c ) } } return p; } /** * GenWordPolynomial monic, i.e. leadingCoefficient == 1. If * leadingCoefficient is not invertible returns this unmodified. * @return monic(this). */ public GenWordPolynomial monic() { if (this.isZERO()) { return this; } C lc = leadingBaseCoefficient(); if (!lc.isUnit()) { //System.out.println("lc = "+lc); return this; } C lm = lc.inverse(); return multiply(lm); } /** * GenWordPolynomial multiplication. Product with ring element and word. * @param s coefficient. * @param e left word. * @return this * s e. */ public GenWordPolynomial multiply(C s, Word e) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); Word e1 = m1.getKey(); C c = c1.multiply(s); // check non zero if not domain if (!c.isZERO()) { Word e2 = e1.multiply(e); pv.put(e2, c); } } return p; } /** * GenWordPolynomial left and right multiplication. Product with ring * element and two words. * @param e left word. * @param f right word. * @return e * this * f. */ public GenWordPolynomial multiply(Word e, Word f) { if (this.isZERO()) { return this; } if (e.isONE()) { return multiply(f); } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c = m1.getValue(); Word e1 = m1.getKey(); Word e2 = e.multiply(e1.multiply(f)); pv.put(e2, c); } return p; } /** * GenWordPolynomial left and right multiplication. Product with ring * element and two words. * @param s coefficient. * @param e left word. * @param f right word. * @return e * this * s * f. */ public GenWordPolynomial multiply(C s, Word e, Word f) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (e.isONE()) { return multiply(s, f); } C c = ring.coFac.getONE(); return multiply(c, e, s, f); // sic, history } /** * GenWordPolynomial left and right multiplication. Product with ring * element and two words. * @param s coefficient. * @param e left word. * @param t coefficient. * @param f right word. * @return s * e * this * t * f. */ public GenWordPolynomial multiply(C s, Word e, C t, Word f) { if (s == null) { return ring.getZERO(); } if (s.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); C c = s.multiply(c1).multiply(t); // check non zero if not domain if (!c.isZERO()) { Word e1 = m1.getKey(); Word e2 = e.multiply(e1).multiply(f); pv.put(e2, c); } } return p; } /** * GenWordPolynomial multiplication. Product with word. * @param e word (!= null). * @return this * e. */ public GenWordPolynomial multiply(Word e) { if (this.isZERO()) { return this; } GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m1 : val.entrySet()) { C c1 = m1.getValue(); Word e1 = m1.getKey(); Word e2 = e1.multiply(e); pv.put(e2, c1); } return p; } /** * GenWordPolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m. */ public GenWordPolynomial multiply(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * GenWordPolynomial division. Division by coefficient ring element. Fails, * if exact division is not possible. * @param s coefficient. * @return this/s. */ public GenWordPolynomial divide(C s) { if (s == null || s.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " division by zero"); } if (this.isZERO()) { return this; } //C t = s.inverse(); //return multiply(t); GenWordPolynomial p = ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : val.entrySet()) { Word e = m.getKey(); C c1 = m.getValue(); C c = c1.divide(s); // is divideLeft if (debug) { C x = c1.remainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException( this.getClass().getName() + " no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " no exact division: " + c1 + "/" + s + ", in " + this); } pv.put(e, c); // or m1.setValue( c ) } return p; } /** * GenWordPolynomial division with remainder. Fails, if exact division by * leading base coefficient is not possible. Meaningful only for univariate * polynomials over fields, but works in any case. * @param S nonzero GenWordPolynomial with invertible leading coefficient. * @return [ quotient , remainder ] with this = quotient * S + remainder and * deg(remainder) < deg(S) or remainder = 0. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ @SuppressWarnings("unchecked") public GenWordPolynomial[] quotientRemainder(GenWordPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException(this.getClass().getName() + " lbcf not invertible " + c); } C ci = c.inverse(); C one = ring.coFac.getONE(); assert (ring.alphabet == S.ring.alphabet); WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator(); Word e = S.leadingWord(); GenWordPolynomial h; GenWordPolynomial q = ring.getZERO().copy(); GenWordPolynomial r = this.copy(); while (!r.isZERO()) { Word f = r.leadingWord(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); Word[] g = f.divideWord(e); // divide not sufficient //logger.info("div: f = {}, e = {}, g = {}, {}", f, e, g[0], g[1]); a = a.multiply(ci); q = q.sum(a, g[0].multiply(g[1])); h = S.multiply(a, g[0], one, g[1]); r = r.subtract(h); Word fr = r.leadingWord(); if (cmp.compare(f, fr) > 0) { // non noetherian reduction throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr); } } else { break; } } GenWordPolynomial[] ret = new GenWordPolynomial[2]; ret[0] = q; ret[1] = r; return ret; } /** * GenWordPolynomial division. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenWordPolynomial with invertible leading coefficient. * @return quotient with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ public GenWordPolynomial divide(GenWordPolynomial S) { return quotientRemainder(S)[0]; } /** * GenWordPolynomial remainder. Fails, if exact division by leading base * coefficient is not possible. Meaningful only for univariate polynomials * over fields, but works in any case. * @param S nonzero GenWordPolynomial with invertible leading coefficient. * @return remainder with this = quotient * S + remainder. * @see edu.jas.poly.PolyUtil#baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial) * . */ public GenWordPolynomial remainder(GenWordPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(this.getClass().getName() + " division by zero"); } C c = S.leadingBaseCoefficient(); if (!c.isUnit()) { throw new ArithmeticException(this.getClass().getName() + " lbc not invertible " + c); } C ci = c.inverse(); C one = ring.coFac.getONE(); assert (ring.alphabet == S.ring.alphabet); WordFactory.WordComparator cmp = ring.alphabet.getDescendComparator(); Word e = S.leadingWord(); GenWordPolynomial h; GenWordPolynomial r = this.copy(); while (!r.isZERO()) { Word f = r.leadingWord(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); Word[] g = f.divideWord(e); // divide not sufficient //logger.info("rem: f = {}, e = {}, g = {}, {}", f, e, g[0], g[1]); a = a.multiply(ci); h = S.multiply(a, g[0], one, g[1]); r = r.subtract(h); Word fr = r.leadingWord(); if (cmp.compare(f, fr) > 0) { // non noetherian reduction throw new RuntimeException("possible infinite loop: f = " + f + ", fr = " + fr); } } else { break; } } return r; } /** * GenWordPolynomial greatest common divisor. Only for univariate * polynomials over fields. * @param S GenWordPolynomial. * @return gcd(this,S). */ public GenWordPolynomial gcd(GenWordPolynomial S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } if (ring.alphabet.length() != 1) { throw new IllegalArgumentException("no univariate polynomial " + ring); } GenWordPolynomial x; GenWordPolynomial q = this; GenWordPolynomial r = S; while (!r.isZERO()) { x = q.remainder(r); q = r; r = x; } return q.monic(); // normalize } /** * GenWordPolynomial extended greatest common divisor. Only for univariate * polynomials over fields. * @param S GenWordPolynomial. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public GenWordPolynomial[] egcd(GenWordPolynomial S) { GenWordPolynomial[] ret = new GenWordPolynomial[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (S == null || S.isZERO()) { ret[0] = this; ret[1] = this.ring.getONE(); ret[2] = this.ring.getZERO(); return ret; } if (this.isZERO()) { ret[0] = S; ret[1] = this.ring.getZERO(); ret[2] = this.ring.getONE(); return ret; } if (ring.alphabet.length() != 1) { throw new IllegalArgumentException("no univariate polynomial " + ring); } if (this.isConstant() && S.isConstant()) { C t = this.leadingBaseCoefficient(); C s = S.leadingBaseCoefficient(); C[] gg = t.egcd(s); //System.out.println("coeff gcd = " + Arrays.toString(gg)); GenWordPolynomial z = this.ring.getZERO(); ret[0] = z.sum(gg[0]); ret[1] = z.sum(gg[1]); ret[2] = z.sum(gg[2]); return ret; } GenWordPolynomial[] qr; GenWordPolynomial q = this; GenWordPolynomial r = S; GenWordPolynomial c1 = ring.getONE().copy(); GenWordPolynomial d1 = ring.getZERO().copy(); GenWordPolynomial c2 = ring.getZERO().copy(); GenWordPolynomial d2 = ring.getONE().copy(); GenWordPolynomial x1; GenWordPolynomial x2; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiply(h); c1 = c1.multiply(h); c2 = c2.multiply(h); } //assert ( ((c1.multiply(this)).sum( c2.multiply(S)).equals(q) )); ret[0] = q; ret[1] = c1; ret[2] = c2; return ret; } /** * GenWordPolynomial half extended greatest common divisor. Only for * univariate polynomials over fields. * @param S GenWordPolynomial. * @return [ gcd(this,S), a ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public GenWordPolynomial[] hegcd(GenWordPolynomial S) { GenWordPolynomial[] ret = new GenWordPolynomial[2]; ret[0] = null; ret[1] = null; if (S == null || S.isZERO()) { ret[0] = this; ret[1] = this.ring.getONE(); return ret; } if (this.isZERO()) { ret[0] = S; return ret; } if (ring.alphabet.length() != 1) { throw new IllegalArgumentException("no univariate polynomial " + ring); } GenWordPolynomial[] qr; GenWordPolynomial q = this; GenWordPolynomial r = S; GenWordPolynomial c1 = ring.getONE().copy(); GenWordPolynomial d1 = ring.getZERO().copy(); GenWordPolynomial x1; while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); c1 = d1; d1 = x1; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiply(h); c1 = c1.multiply(h); } //assert ( ((c1.multiply(this)).remainder(S).equals(q) )); ret[0] = q; ret[1] = c1; return ret; } /** * GenWordPolynomial inverse. Required by RingElem. Throws not invertible * exception. */ public GenWordPolynomial inverse() { if (isUnit()) { // only possible if ldbcf is unit C c = leadingBaseCoefficient().inverse(); return ring.getONE().multiply(c); } throw new NotInvertibleException("element not invertible " + this + " :: " + ring); } /** * GenWordPolynomial modular inverse. Only for univariate polynomials over * fields. * @param m GenWordPolynomial. * @return a with with a*this = 1 mod m. */ public GenWordPolynomial modInverse(GenWordPolynomial m) { if (this.isZERO()) { throw new NotInvertibleException("zero is not invertible"); } GenWordPolynomial[] hegcd = this.hegcd(m); GenWordPolynomial a = hegcd[0]; if (!a.isUnit()) { // gcd != 1 throw new NotInvertibleException("element not invertible, gcd != 1"); } GenWordPolynomial b = hegcd[1]; if (b.isZERO()) { // when m divides this, e.g. m.isUnit() throw new NotInvertibleException("element not invertible, divisible by modul"); } return b; } /** * Iterator over coefficients. * @return val.values().iterator(). */ public Iterator coefficientIterator() { return val.values().iterator(); } /** * Iterator over words. * @return val.keySet().iterator(). */ public Iterator wordIterator() { return val.keySet().iterator(); } /** * Iterator over monomials. * @return a PolyIterator. */ public Iterator> iterator() { return new WordPolyIterator(val); } /** * Map a unary function to the coefficients. * @param f evaluation functor. * @return new polynomial with coefficients f(this(e)). */ public GenWordPolynomial map(final UnaryFunctor f) { GenWordPolynomial n = ring.getZERO().copy(); SortedMap nv = n.val; for (WordMonomial m : this) { //logger.info("m = {}", m); C c = f.eval(m.c); if (c != null && !c.isZERO()) { nv.put(m.e, c); } } return n; } /** * GenWordPolynomial contraction. * @param fac GenWordPolynomialRing. * @return this contracted to fac ring, if this in fac ring, null else. */ public GenWordPolynomial contract(GenWordPolynomialRing fac) { if (fac == null) { throw new IllegalArgumentException("fac ring may not be null"); } GenWordPolynomial S = fac.getZERO(); if (this.isZERO()) { return S; } WordFactory wfac = fac.alphabet; //eventually: assert (ring.alphabet.isSubFactory(fac.alphabet)); S = S.copy(); SortedMap sv = S.val; SortedMap nv = this.val; for (Map.Entry me : nv.entrySet()) { Word e = me.getKey(); Word ec = wfac.contract(e); if (ec == null) { // not contractable return fac.getZERO(); // or null? } C y = me.getValue(); if (sv.get(ec) != null) { // eventually need sum throw new RuntimeException("x != null: need sum " + sv.get(ec) + " + " + y); } sv.put(ec, y); } return S; } } java-algebra-system-2.7.200/src/edu/jas/poly/GenWordPolynomialRing.java000066400000000000000000000466441445075545500257540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PreemptStatus; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * GenWordPolynomialRing generic polynomial factory implementing RingFactory; * Factory for non-commutative string polynomials over C. * @param coefficient type * @author Heinz Kredel */ public final class GenWordPolynomialRing> implements RingFactory> /*, Iterable>*/ { /** * The factory for the coefficients. */ public final RingFactory coFac; /** * The factory for the alphabet. */ public final WordFactory alphabet; /** * The constant polynomial 0 for this ring. */ public final GenWordPolynomial ZERO; /** * The constant polynomial 1 for this ring. */ public final GenWordPolynomial ONE; /** * The constant empty word exponent for this ring. */ public final Word wone; /** * A default random sequence generator. */ final static Random random = new Random(); /** * Indicator if this ring is a field. */ private int isField = -1; // initially unknown /** * Log4j logger object. */ private static final Logger logger = LogManager.getLogger(GenWordPolynomialRing.class); /** * Flag to enable if preemptive interrupt is checked. */ final boolean checkPreempt = PreemptStatus.isAllowed(); /** * The constructor creates a polynomial factory object with the default term * order. * @param cf factory for coefficients of type C. * @param wf factory for strings. */ public GenWordPolynomialRing(RingFactory cf, WordFactory wf) { coFac = cf; alphabet = wf; ZERO = new GenWordPolynomial(this); C coeff = coFac.getONE(); wone = wf.getONE(); ONE = new GenWordPolynomial(this, coeff, wone); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param s array of variable names. */ public GenWordPolynomialRing(RingFactory cf, String[] s) { this(cf, new WordFactory(s)); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param s string of single letter variable names. */ public GenWordPolynomialRing(RingFactory cf, String s) { this(cf, new WordFactory(s)); } /** * The constructor creates a polynomial factory object. * @param cf factory for coefficients of type C. * @param o other polynomial ring. */ public GenWordPolynomialRing(RingFactory cf, GenWordPolynomialRing o) { this(cf, o.alphabet); } /** * The constructor creates a polynomial factory object. * @param fac polynomial ring. */ public GenWordPolynomialRing(GenPolynomialRing fac) { this(fac.coFac, new WordFactory(fac.vars)); } /** * Copy this factory. * @return a clone of this. */ public GenWordPolynomialRing copy() { return new GenWordPolynomialRing(coFac, this); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append("WordPolyRing("); if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toString().trim()); } s.append(","); s.append(alphabet.toString()); s.append(")"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("WordPolyRing.new("); break; case Python: default: s.append("WordPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(","); s.append(alphabet.toScript()); s.append(")"); return s.toString(); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended word polynomial ring factory. */ public GenWordPolynomialRing extend(int i) { // add module variable names String[] v = GenPolynomialRing.newVars("t", i); return extend(v); } /** * Extend variables. Extend number of variables by length(vn). * @param vn names for extended variables. * @return extended polynomial ring factory. */ public GenWordPolynomialRing extend(String[] vn) { WordFactory wfe = alphabet.extend(vn); return new GenWordPolynomialRing(coFac, wfe); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof GenWordPolynomialRing)) { return false; } GenWordPolynomialRing oring = (GenWordPolynomialRing) other; if (!coFac.equals(oring.coFac)) { return false; } if (!alphabet.equals(oring.alphabet)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = (coFac.hashCode() << 11); h += alphabet.hashCode(); return h; } /** * Get the variable names. * @return vars. */ public String[] getVars() { return alphabet.getVars(); // Java-5: Arrays.copyOf(vars,vars.length); } /** * Get the zero element from the coefficients. * @return 0 as C. */ public C getZEROCoefficient() { return coFac.getZERO(); } /** * Get the one element from the coefficients. * @return 1 as C. */ public C getONECoefficient() { return coFac.getONE(); } /** * Get the zero element. * @return 0 as GenWordPolynomial. */ public GenWordPolynomial getZERO() { return ZERO; } /** * Get the one element. * @return 1 as GenWordPolynomial. */ public GenWordPolynomial getONE() { return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return coFac.isCommutative() && alphabet.isFinite(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return coFac.isAssociative(); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return alphabet.isFinite() && coFac.isFinite(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } if (coFac.isField() && alphabet.isFinite()) { isField = 1; return true; } isField = 0; return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Get a (constant) GenWordPolynomial<C> element from a coefficient * value. * @param a coefficient. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(C a) { return new GenWordPolynomial(this, a); } /** * Get a GenWordPolynomial<C> element from a word. * @param e word. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(Word e) { return valueOf(coFac.getONE(), e); } /** * Get a GenWordPolynomial<C> element from an ExpVector. * @param e exponent vector. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(ExpVector e) { return valueOf(coFac.getONE(), e); } /** * Get a GenWordPolynomial<C> element from a coefficient and a word. * @param a coefficient. * @param e word. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(C a, Word e) { return new GenWordPolynomial(this, a, e); } /** * Get a GenWordPolynomial<C> element from a coefficient and an * ExpVector. * @param a coefficient. * @param e exponent vector. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(C a, ExpVector e) { return new GenWordPolynomial(this, a, alphabet.valueOf(e)); } /** * Get a GenWordPolynomial<C> element from a GenPolynomial<C>. * @param a GenPolynomial. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(GenPolynomial a) { if (a.isZERO()) { return getZERO(); } if (a.isONE()) { return getONE(); } GenWordPolynomial p = this.getZERO().copy(); for (Map.Entry m : a.val.entrySet()) { C c = m.getValue(); ExpVector e = m.getKey(); Word w = alphabet.valueOf(e); p.doPutToMap(w, c); } return p; } /** * Get a GenWordPolynomial<C> element from a * GenWordPolynomial<C>. * @param a GenWordPolynomial. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial valueOf(GenWordPolynomial a) { if (a.isZERO()) { return getZERO(); } if (a.isONE()) { return getONE(); } GenWordPolynomial p = this.getZERO().copy(); for (Map.Entry m : a.val.entrySet()) { C c = m.getValue(); Word e = m.getKey(); Word w = alphabet.valueOf(e); p.doPutToMap(w, c); } return p; } /** * Get a list of GenWordPolynomial<C> element from a list of * GenPolynomial<C>. * @param A GenPolynomial list. * @return a GenWordPolynomial<C> list. */ public List> valueOf(List> A) { List> B = new ArrayList>(A.size()); if (A.isEmpty()) { return B; } for (GenPolynomial a : A) { GenWordPolynomial b = valueOf(a); B.add(b); } return B; } /** * Get a (constant) GenWordPolynomial<C> element from a long value. * @param a long. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial fromInteger(long a) { return new GenWordPolynomial(this, coFac.fromInteger(a), wone); } /** * Get a (constant) GenWordPolynomial<C> element from a BigInteger * value. * @param a BigInteger. * @return a GenWordPolynomial<C>. */ public GenWordPolynomial fromInteger(BigInteger a) { return new GenWordPolynomial(this, coFac.fromInteger(a), wone); } /** * Random polynomial. Generates a random polynomial. * @param n number of terms. * @return a random polynomial. */ public GenWordPolynomial random(int n) { return random(n, random); } /** * Random polynomial. Generates a random polynomial with k = 5, l = n, d = * 3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenWordPolynomial random(int n, Random rnd) { return random(5, n, 3, rnd); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal length of a random word. * @return a random polynomial. */ public GenWordPolynomial random(int k, int l, int d) { return random(k, l, d, random); } /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal length of a random word. * @param rnd is a source for random bits. * @return a random polynomial. */ public GenWordPolynomial random(int k, int l, int d, Random rnd) { GenWordPolynomial r = getZERO(); //.clone() or copy( ZERO ); // add l random coeffs and words of maximal length d for (int i = 0; i < l; i++) { int di = Math.abs(rnd.nextInt() % d); Word e = alphabet.random(di, rnd); C a = coFac.random(k, rnd); r = r.sum(a, e); // somewhat inefficient but clean //System.out.println("e = " + e + " a = " + a); } return r; } /** * Copy polynomial c. * @param c polynomial to copy. * @return a copy of c. */ public GenWordPolynomial copy(GenWordPolynomial c) { return new GenWordPolynomial(this, c.val); } /** * Parse a polynomial with the use of GenWordPolynomialTokenizer. * @param s String. * @return GenWordPolynomial from s. */ public GenWordPolynomial parse(String s) { String val = s; if (!s.contains("|")) { val = val.replace("{", "").replace("}", ""); } return parse(new StringReader(val)); } /** * Parse a polynomial with the use of GenWordPolynomialTokenizer. * @param r Reader. * @return next GenWordPolynomial from r. */ @SuppressWarnings("unchecked") public GenWordPolynomial parse(Reader r) { if (alphabet.length() <= 1) { // hack for univariate = commuative like cases // obsolete case GenPolynomialRing cr = new GenPolynomialRing(coFac, alphabet.getVars()); GenPolynomialTokenizer pt = new GenPolynomialTokenizer(cr, r); GenPolynomial p = cr.getZERO(); try { p = pt.nextPolynomial(); } catch (IOException e) { logger.error("{} parse {}", e, this); } GenWordPolynomial wp = this.valueOf(p); return wp; } GenPolynomialTokenizer tok = new GenPolynomialTokenizer(r); GenWordPolynomial a; try { a = tok.nextWordPolynomial(this); } catch (IOException e) { a = null; e.printStackTrace(); logger.error("{} parse {}", e, this); } return a; //throw new UnsupportedOperationException("not implemented"); } /** * Generate univariate polynomial in a given variable. * @param i the index of the variable. * @return X_i as univariate polynomial. */ public GenWordPolynomial univariate(int i) { GenWordPolynomial p = getZERO(); List wgen = alphabet.generators(); if (0 <= i && i < wgen.size()) { C one = coFac.getONE(); Word f = wgen.get(i); p = p.sum(one, f); } return p; } /** * Generate commute polynomial in two variables. * @param i the index of the first variable. * @param j the index of the second variable. * @return X_i * x_j - X_j * X_i as polynomial. */ public GenWordPolynomial commute(int i, int j) { GenWordPolynomial p = getZERO(); List wgen = alphabet.generators(); if (0 <= i && i < wgen.size() && 0 <= j && j < wgen.size()) { C one = coFac.getONE(); Word f = wgen.get(i); Word e = wgen.get(j); p = p.sum(one, e.multiply(f)); p = p.subtract(one, f.multiply(e)); if (i > j) { p = p.negate(); } } return p; } /** * Generate commute polynomials for given variable. * @param i the index of the variable. * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials. */ public List> commute(int i) { int n = alphabet.length(); List> pols = new ArrayList>(n - 1); for (int j = 0; j < n; j++) { if (i != j) { pols.add(commute(i, j)); } } return pols; } /** * Generate commute polynomials for all variables. * @return [X_i * x_j - X_j * X_i, i != j] as list of polynomials. */ public List> commute() { int n = alphabet.length(); List> pols = new ArrayList>(n * (n - 1)); for (int i = 0; i < n; i++) { pols.addAll(commute(i)); } return pols; } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ public List> univariateList() { int n = alphabet.length(); List> pols = new ArrayList>(n); for (int i = 0; i < n; i++) { GenWordPolynomial p = univariate(i); pols.add(p); } return pols; } /** * Get the generating elements excluding the generators for the * coefficient ring. * @return a list of generating elements for this ring. */ public List> getGenerators() { List> univs = univariateList(); List> gens = new ArrayList>(univs.size() + 1); gens.add(getONE()); gens.addAll(univs); return gens; } /** * Get a list of all generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List cogens = coFac.generators(); List> univs = univariateList(); List> gens = new ArrayList>(univs.size() + cogens.size()); for (C c : cogens) { gens.add(getONE().multiply(c)); } gens.addAll(univs); return gens; } } java-algebra-system-2.7.200/src/edu/jas/poly/IndexFactory.java000066400000000000000000000427131445075545500241130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.MonoidFactory; /** * IndexList factory implements a factory for index lists for exterior * polynomials. Objects of this class are intended to be immutable. If in doubt * use valueOf to get a conformant index list. * @see "masnc.DIPE.mi#ILEXPR from SAC2/MAS" * @author Heinz Kredel */ public class IndexFactory implements MonoidFactory { /** * The maximal length index list for this factory. */ public final int imaxlength; /** * The coordinate variable name. */ public final String vname; /** * The maximal index list for this factory. */ public final IndexList imax; /** * Defined index list comparison. * Strong compare: false, weak compare: true. */ final boolean weak; /** * Random number generator. */ private final static Random random = new Random(); /** * Log4j logger object. */ private static final Logger logger = LogManager.getLogger(WordFactory.class); /** * The one element index list. */ public final IndexList ONE; /** * The default coordinate variable name. */ public static final String DEFAULT_VNAME = "E"; /** * The default imaxlength for this index lists. */ public static final int DEFAULT_SIZE = 4; /** * Constructor for IndexFactory. No argument constructor . */ public IndexFactory() { this(DEFAULT_SIZE, DEFAULT_VNAME); } /** * Constructor for IndexFactory. * @param r length of index lists, starting with index 1. */ public IndexFactory(int r) { this(1, r, DEFAULT_VNAME, false); } /** * Constructor for IndexFactory. * @param r length of index lists, starting with index 1. * @param w termorder for index lists: true for weak, false for strong. */ public IndexFactory(int r, boolean w) { this(1, r, DEFAULT_VNAME, w); } /** * Constructor for IndexFactory. * @param r length of index lists, starting with index 1. * @param v coordinate vname. */ public IndexFactory(int r, String v) { this(1, r, v, false); } /** * Constructor for IndexFactory. * @param r length of index lists, starting with index 1. * @param v coordinate vname. * @param w termorder for index lists: true for weak, false for strong. */ public IndexFactory(int r, String v, boolean w) { this(1, r, v, w); } /** * Constructor for IndexFactory. * @param s start index. * @param t length of index lists. */ public IndexFactory(int s, int t) { this(s, t, DEFAULT_VNAME, false); } /** * Constructor for IndexFactory. * @param s start index. * @param t length of index lists. * @param v coordinate vname. * @param w termorder for index lists: true for weak, false for strong. */ public IndexFactory(int s, int t, String v, boolean w) { // not possible: this(new IndexList(this, 1, sequenceArray(s, t)), v); if (t < 0) { throw new IllegalArgumentException("negative length index not allowed"); } if (s < 0) { throw new IllegalArgumentException("negative start index not allowed"); } imaxlength = t; vname = v; weak = w; imax = new IndexList(this, 1, sequenceArray(s, imaxlength)); ONE = new IndexList(this, 1, sequenceArray(s, 0)); } // /** not meaningful // * Constructor for IndexFactory. // * @param o some index list. // * @param v coordinate vname. // */ // public IndexFactory(IndexList o, String v) { // if (o == null) { // throw new IllegalArgumentException("null index list not allowed"); // } // int b = o.minDeg(); // int e = o.maxDeg(); // imaxlength = e - b + 1; // vname = v; // imax = new IndexList(this, 1, sequenceArray(b, imaxlength)); // if (imaxlength != o.length()) { // logger.warn("length do not match: {} != {}", imaxlength, o.length()); // } // ONE = new IndexList(this, 1, sequenceArray(1, 0)); // } // /** // * Constructor for IndexFactory. // * @param o some index list. // */ // public IndexFactory(IndexList o) { // this(o, o.mono.vname); // } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() Note: returns true * because of finite set of values in each index. */ public boolean isFinite() { return true; } /** * Query if this monoid is commutative. * @return true if this monoid is commutative, else false. */ public boolean isCommutative() { if (imaxlength == 0) { return true; } return false; } /** * Query if this monoid is associative. * @return true if this monoid is associative, else false. */ public boolean isAssociative() { return true; } /** * Get the Element for a. * @param a long * @return element corresponding to a. */ @Override public IndexList fromInteger(long a) { throw new UnsupportedOperationException("not implemented for IndexFactory"); } /** * Get the Element for a. * @param a java.math.BigInteger. * @return element corresponding to a. */ @Override public IndexList fromInteger(java.math.BigInteger a) { throw new UnsupportedOperationException("not implemented for IndexFactory"); } /** * Value of other. * @param e other ExpVector. * @return value as IndexList. */ public IndexList valueOf(ExpVector e) { if (e == null) { return getZERO(); } int r = e.length(); int[] w = new int[r]; int ii = 0; for (int i = 0; i < r; i++) { long x = e.getVal(i); if (x <= 0l) { continue; } if (x > 1l) { return getZERO(); } w[ii++] = i; } int[] v = Arrays.copyOf(w, ii); return new IndexList(this, v); } /** * Value of other. * @param var String of index names. * @return value as IndexList. */ public IndexList valueOf(String var) { return sequence(0, var.length()); } /** * Value of other. * @param e other Collection of Integer indexes. * @return value as IndexList. */ public IndexList valueOf(Collection e) { if (e == null) { return getZERO(); } int r = e.size(); int[] w = new int[r]; int ii = 0; for (Integer x : e) { int xi = (int) x; if (xi < 0) { continue; } w[ii++] = xi; } int[] v = Arrays.copyOf(w, ii); return new IndexList(this, v); } /** * Value of other. * @param e other int[] of indexes, may not be conform to IndexList * specification. * @return value as IndexList. */ public IndexList valueOf(int[] e) { if (e == null) { return getZERO(); } int r = e.length; IndexList w = new IndexList(this, new int[] {}); // = 1 int[] v = new int[1]; for (int i = 0; i < r; i++) { v[0] = e[i]; IndexList vs = new IndexList(this, v); w = w.exteriorProduct(vs); if (w.isZERO()) { return w; } } //System.out.println("valueOf: " + w); return w; } /** * Value of other. * @param e other IndexList, may not be conform to IndexList specification. * @return value as IndexList. */ public IndexList valueOf(IndexList e) { if (e == null) { return getZERO(); } return valueOf(e.val); } /** * Generators. * @return list of generators for this index list. */ public List generators() { List gens = new ArrayList(); //IndexList one = getONE(); //gens.add(one); for (int i = 0; i < imax.val.length; i++) { int[] v = new int[1]; v[0] = imax.val[i]; IndexList vs = new IndexList(this, v); gens.add(vs); } //System.out.println("gens: " + gens + ", val = " + Arrays.toString(val)); return gens; } /** * Clone IndexList. * @see java.lang.Object#clone() */ @Override public IndexList copy(IndexList o) { if (o == null) { return o; } return o.copy(); } /** * Get the maximal length of index lists of this factory. * @return imaxlength. */ public int length() { return imaxlength; } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { if (! weak) { return imax.toString(); } StringBuffer s = new StringBuffer(imax.toString()); s.append("[" + weak + "]"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { if (! weak) { return imax.toScript(); } StringBuffer s = new StringBuffer(imax.toScript()); s.append("[" + weak + "]"); return s.toString(); } /** * Constructor for IndexList. Converts a String representation to an * IndexList. Accepted format = E(1,2,3,4,5,6,7). * @param s String representation. */ // public IndexFactory(String s) throws NumberFormatException { // this(parse(s).val); // } /** * Parser for IndexList. Converts a String representation to an IndexList. * Accepted format = E(1,2,3,4,5,6,7). * @param s String representation. * @return parsed IndexList */ public IndexList parse(String s) throws NumberFormatException { int[] v = null; // first format = (1,2,3,4,5,6,7) List idxs = new ArrayList(); s = s.trim(); int b = s.indexOf('('); int e = s.indexOf(')', b + 1); String teil; int k; int a; if (b >= 0 && e >= 0) { b++; while ((k = s.indexOf(',', b)) >= 0) { teil = s.substring(b, k); a = Integer.parseInt(teil); idxs.add(Integer.valueOf(a)); b = k + 1; } if (b <= e) { teil = s.substring(b, e); a = Integer.parseInt(teil); idxs.add(Integer.valueOf(a)); } int length = idxs.size(); v = new int[length]; for (int j = 0; j < length; j++) { v[j] = idxs.get(j).intValue(); } } return valueOf(v); // sort and compute sign } /** * Parse from Reader. White space is delimiter for index list. * @param r Reader. * @return the next Element found on r. */ public IndexList parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof IndexFactory)) { return false; } IndexFactory b = (IndexFactory) B; int t = imax.compareTo(b.imax); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode. Optimized for small indexes, i.e. ≤ 24 and small * number of variables, i.e. ≤ 8. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hash = imax.hashCode(); return hash; } /** * Get IndexList zero. * @return 0 IndexList. */ public IndexList getZERO() { return new IndexList(this); } /** * Get IndexList one. * @return 1 IndexList. */ public IndexList getONE() { return ONE; //?? .copy() } /** * Generate a random IndexList. * @param r length of new IndexList. * @return random IndexList. */ public final IndexList random(int r) { return random(r, 0.5f, random); } /** * Generate a random IndexList. * @param r length of new IndexList. * @param rnd is a source for random bits. * @return random IndexList. */ public final IndexList random(int r, Random rnd) { return random(r, 0.5f, rnd); } /** * Generate a random IndexList. * @param r length of new IndexList. * @param q density of nozero indexes. * @return random IndexList. */ public final IndexList random(int r, float q) { return random(r, q, random); } /** * Generate a random IndexList. * @param r length of new IndexList. * @param q density of nozero indexes. * @param rnd is a source for random bits. * @return random IndexList. */ public final IndexList random(int r, float q, Random rnd) { if (r > imaxlength || r < 0) { throw new IllegalArgumentException("r > imaxlength not allowed: " + r + " > " + imaxlength); } if (r == 0) { return getZERO(); } int[] w = new int[r]; int s = 1; float f; f = rnd.nextFloat(); if (f < q * 0.001f) { return getONE(); // = 0, 1 ?? } if (f < q * q) { s = -1; } int ii = 0; int b = Math.max(Math.min(Math.abs(rnd.nextInt()) % imaxlength, imaxlength - r - 1), 1); for (int i = b; i <= imaxlength && ii < r; i++) { f = rnd.nextFloat(); if (f < q) { w[ii++] = i; } } int[] v = Arrays.copyOf(w, ii); //System.out.println("v = " + Arrays.toString(v)); //System.out.println("this = " + this); return new IndexList(this, s, v); } /** * Generate a sequence IndexList. * @param s starting index. * @param r length of new IndexList. * @return sequence (s, s+1, ..., s+r-1) IndexList. */ public final IndexList sequence(int s, int r) { return new IndexList(this, 1, sequenceArray(s, r)); } /** * Generate a sequence array. * @param s starting index. * @param r length of array. * @return sequence (s, s+1, ..., s+r-1) array. */ public static int[] sequenceArray(int s, int r) { if (s < 0) { throw new IllegalArgumentException("s < 0 not allowed: " + s + " < 0"); } int[] w = new int[r]; for (int i = 0; i < w.length; i++) { w[i] = s + i; } //System.out.println("v = " + Arrays.toString(w)); return w; } /** * Comparator for IndexLists. */ public static abstract class IndexListComparator implements Comparator, Serializable { public abstract int compare(IndexList e1, IndexList e2); } /** * Defined descending order comparator. Sorts the highest terms first. */ private final IndexListComparator horder = new IndexListComparator() { @Override public int compare(IndexList e1, IndexList e2) { return -e1.strongCompareTo(e2); } }; /** * Defined ascending order comparator. Sorts the lowest terms first. */ private final IndexListComparator lorder = new IndexListComparator() { @Override public int compare(IndexList e1, IndexList e2) { return e1.strongCompareTo(e2); } }; /** * Defined descending weak order comparator. Sorts the highest terms first. */ private final IndexListComparator hweak = new IndexListComparator() { @Override public int compare(IndexList e1, IndexList e2) { return -e1.weakCompareTo(e2); } }; /** * Defined ascending weak order comparator. Sorts the lowest terms first. */ private final IndexListComparator lweak = new IndexListComparator() { @Override public int compare(IndexList e1, IndexList e2) { return e1.weakCompareTo(e2); } }; /** * Get the descending order comparator. Sorts the highest terms first. * @return horder. */ public IndexListComparator getDescendComparator() { if (weak) { return hweak; } return horder; } /** * Get the ascending order comparator. Sorts the lowest terms first. * @return lorder. */ public IndexListComparator getAscendComparator() { if (weak) { return lweak; } return lorder; } } java-algebra-system-2.7.200/src/edu/jas/poly/IndexList.java000066400000000000000000000351401445075545500234130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Arrays; import edu.jas.arith.BigInteger; import edu.jas.structure.MonoidElem; import edu.jas.structure.MonoidFactory; /** * IndexList implements index lists for exterior polynomials. Index lists are * implemented as arrays of Java int type. Objects of this class are intended to * be immutable, except for the sign. If in doubt use valueOf to * get a conformant index list. * @see "masnc.DIPE.mi#ILEXPR from SAC2/MAS" * @author Heinz Kredel */ public class IndexList implements MonoidElem { /** * Representation of index list as int arrays. */ public final int[] val; // != null, when s != 0 /** * Sign of index list. */ public int sign; // = -1, 0, 1 /** * Reference to IndexFactory. */ public final IndexFactory mono; /** * Constructor for IndexList. No argument constructor defining 0 index list. */ public IndexList(IndexFactory m) { this(m, 0, null); } /** * Constructor for IndexList. * @param v array with indices. */ public IndexList(IndexFactory m, int[] v) { this(m, 1, v); } /** * Constructor for IndexList. Note: A copy of v is internally * created. * @param s sign of index list. * @param v array with indices. */ public IndexList(IndexFactory m, int s, int[] v) { sign = s; mono = m; if (v == null) { if (s != 0) { throw new IllegalArgumentException("inconsistent: s = " + s + ", v = " + v); } val = v; sign = 0; // only when exception deactivated } else { val = Arrays.copyOf(v, v.length); } //if (v != null && v.length > 0) System.out.println("v[0]: " + v[0]); } /** * Constructor for IndexList. Converts a String representation to an * IndexList. Accepted format = E(1,2,3,4,5,6,7). * @param s String representation. */ public IndexList(IndexFactory m, String s) throws NumberFormatException { this(m, m.parse(s).val); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public MonoidFactory factory() { return mono; //(MonoidFactory) this; //throw new UnsupportedOperationException("no factory implemented for IndexList"); } /** * Check for IndexList conformant specification. * @return true if this a a conformant IndexList, else false. */ public boolean isConformant() { if (sign == 0 && val == null) { return true; } IndexList ck = mono.valueOf(val); return this.abs().equals(ck.abs()); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public IndexList copy() { return new IndexList(mono, sign, val); } /** * Get the index vector. * @return val. */ public int[] getVal() { return val; } /** * Get the index at position i. * @param i position. * @return val[i]. */ public int getVal(int i) { return val[i]; } /** * Set the index at position i to e. * @param i position * @param e new index * @return old val[i]. */ protected int setVal(int i, int e) { int v = val[i]; val[i] = e; return v; } /** * Get the length of this index list. * @return val.length or -1 for 0 index list. */ public int length() { if (sign == 0) { return -1; } return val.length; } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { //System.out.println("(" + sign + ", " + Arrays.toString(val) + ")"); if (sign == 0) { return "0"; } StringBuffer s = new StringBuffer(); if (sign > 0) { s.append(mono.vname + "("); } else { s.append(mono.vname + "[-1]("); } for (int i = 0; i < length(); i++) { s.append(getVal(i)); if (i < length() - 1) { s.append(","); } } s.append(")"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { return toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return "IndexFactory()"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof IndexList)) { return false; } IndexList b = (IndexList) B; int t = this.compareTo(b); //System.out.println("equals: this = " + this + " B = " + B + " t = " + t); return (0 == t); } /** * hashCode. Optimized for small indexes, i.e. ≤ 24 and small * number of variables, i.e. ≤ 8. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hash = Arrays.hashCode(val) + sign; return hash; } /** * Returns the number of bits in the representation of this index vector. * @return number of bits in the representation of this IndexList, including * sign bits. */ public long bitLength() { long blen = 2; // sign for (int i = 0; i < val.length; i++) { blen += BigInteger.bitLength(val[i]); } return blen; } /** * Is IndexList zero. * @return If this sign is 0 then true is returned, else false. */ public boolean isZERO() { return (sign == 0); } /** * Is IndexList one. * @return If this sign != 0 and length val is zero then true returned, else * false. */ public boolean isONE() { return (sign != 0 && val.length == 0); } /** * Is IndexList a unit. * @return If this is a unit then true is returned, else false. */ public boolean isUnit() { return isONE() || negate().isONE(); } /** * IndexList absolute value. * @return abs(this). */ public IndexList abs() { if (sign >= 0) { return this; } return new IndexList(mono, 1, val); } /** * IndexList negate. * @return -this. */ public IndexList negate() { if (sign == 0) { return this; } return new IndexList(mono, -sign, val); } /** * IndexList exterior product. Also called wegde product. * @param V other index list * @return this /\ V. */ public IndexList exteriorProduct(IndexList V) { if (isZERO() || V.isZERO()) { return mono.getZERO(); // = 0 } int s = 1; int m = 0, n = 0; // todo: remove or rename int[] u = val; int[] v = V.val; int ii = 0; int[] w = new int[u.length + v.length]; int i = 0, j = 0; while (i < u.length && j < v.length) { int ul = u[i]; int vl = v[j]; if (ul == vl) { return mono.getZERO(); // = 0 } if (ul < vl) { w[ii++] = ul; i++; m++; } else { w[ii++] = vl; j++; n++; if (m % 2 != 0) { s = -s; } } } if (i == u.length) { while (j < v.length) { w[ii++] = v[j++]; } } else { m += u.length - i; // - 1; while (i < u.length) { w[ii++] = u[i++]; } } if (m % 2 != 0 && n % 2 != 0) { s = -s; } //System.out.println("i = " + i + ", j = " + j + ", m = " + m + ", n = " + n); //System.out.println("s = " + s + ", w = " + Arrays.toString(w)); //int[] x = Arrays.copyOf(w, ii); return new IndexList(mono, s, w); } /** * IndexList multiply. Note: implemented by exteriorProduct. * @param V other index list * @return this * V. */ public IndexList multiply(IndexList V) { return exteriorProduct(V); } /** * IndexList interior left product. * @param V other index list * @return this _| V. */ public IndexList interiorLeftProduct(IndexList V) { return V.interiorRightProduct(this); } /** * IndexList interior right product. * @param V other index list * @return this |_ V. */ public IndexList interiorRightProduct(IndexList V) { if (!this.divides(V)) { return mono.getZERO(); // = 0 } int[] u = val; int[] v = V.val; int[] w = new int[v.length - u.length]; int ii = 0; int s = 1; int m = 0; // todo: remove or rename for (int i = 0; i < v.length; i++) { int vl = v[i]; boolean found = false; for (int j = 0; j < u.length; j++) { if (vl == u[j]) { found = true; break; } } if (!found) { w[ii++] = vl; m++; } else { if (m % 2 != 0) { s = -s; } } } //int[] x = Arrays.copyOf(w, ii); return new IndexList(mono, s, w); } /** * IndexList divides test. Test if this is contained in V. * @param V other index list * @return true if this divides V, else false. */ public boolean divides(IndexList V) { if (isZERO() || V.isZERO()) { return false; } if (val.length > V.val.length) { return false; } int[] vval = V.val; for (int i = 0; i < val.length; i++) { int v = val[i]; boolean found = false; for (int j = i; j < vval.length; j++) { if (v == vval[j]) { found = true; break; } } if (!found) { return false; } } return true; } /** * IndexList inverse. Note: not implemented. * @return 1 / this. */ public IndexList inverse() { throw new UnsupportedOperationException("inverse not implemented"); } /** * IndexList divide. Note: experimental. * @param V other IndexList. * @return this/V. Note: computed as interiorRightProduct, eventually * useful. */ public IndexList divide(IndexList V) { return interiorRightProduct(V); //throw new UnsupportedOperationException("divide not implemented"); } /** * IndexList remainder. Note: not implemented. * @param V other IndexList. * @return this - (this/V). Note: not useful. */ public IndexList remainder(IndexList V) { throw new UnsupportedOperationException("remainder not implemented"); } /** * IndexList signum. * @return sign; */ public int signum() { return sign; } /** * IndexList degree. * @return number of of all indexes. */ public int degree() { if (sign == 0) { return -1; } return val.length; } /** * IndexList maximal degree. * @return maximal index. */ public int maxDeg() { if (degree() < 1) { return -1; } return val[val.length - 1]; } /** * IndexList minimal degree. * @return minimal index. */ public int minDeg() { if (degree() < 1) { return -1; } return val[0]; } /** * IndexList compareTo. * @param V other index list * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(IndexList V) { return strongCompareTo(V); } /** * IndexList weakCompareTo. Ignoring the degree in first pass. * @param V other index list * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public int weakCompareTo(IndexList V) { if (sign == 0 && V.sign == 0) { return 0; } if (sign == 0) { return -1; } if (V.sign == 0) { return +1; } // both not zero if (sign < V.sign) { return -1; } if (sign > V.sign) { return 1; } // both have same sign int[] vval = V.val; int m = Math.min(val.length, vval.length); for (int i = 0; i < m; i++) { if (val[i] < vval[i]) { return -1; } if (val[i] > vval[i]) { return 1; } } if (val.length < vval.length) { return -1; } if (val.length > vval.length) { return 1; } return 0; } /** * IndexList strongCompareTo. Sort by degree in first pass, then by indices. * @param V other index list * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public int strongCompareTo(IndexList V) { if (sign == 0 && V.sign == 0) { return 0; } if (sign == 0) { return -1; } if (V.sign == 0) { return +1; } // both not zero :: ignore sign int[] vval = V.val; if (val.length < vval.length) { return -1; } if (val.length > vval.length) { return 1; } int m = Math.min(val.length, vval.length); int tl = 0; for (int i = 0; i < m; i++) { if (val[i] < vval[i]) { tl = -1; break; } if (val[i] > vval[i]) { tl = 1; break; } } // now val.length == vval.length return tl; } } java-algebra-system-2.7.200/src/edu/jas/poly/IndexListMonomial.java000066400000000000000000000024441445075545500251100ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Map; import edu.jas.structure.RingElem; /** * IndexListMonomial class. Represents pairs of index lists and coefficients. * Adaptor for Map.Entry. * @author Heinz Kredel */ public final class IndexListMonomial> { /** * IndexList of monomial. */ public final IndexList e; /** * Coefficient of monomial. */ public final C c; /** * Constructor of word monomial. * @param me a MapEntry. */ public IndexListMonomial(Map.Entry me) { this(me.getKey(), me.getValue()); } /** * Constructor of word monomial. * @param e index list. * @param c coefficient. */ public IndexListMonomial(IndexList e, C c) { this.e = e; this.c = c; } /** * Getter for index list. * @return index list. */ public IndexList indexlist() { return e; } /** * Getter for coefficient. * @return coefficient. */ public C coefficient() { return c; } /** * String representation of Monomial. * @see java.lang.Object#toString() */ @Override public String toString() { return c.toString() + " " + e.toString(); } } java-algebra-system-2.7.200/src/edu/jas/poly/IndexListPolyIterator.java000066400000000000000000000023301445075545500257640ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import edu.jas.structure.RingElem; /** * Iterator over monomials of a polynomial. Adaptor for * val.entrySet().iterator(). * @author Heinz Kredel */ public class IndexListPolyIterator> implements Iterator> { /** * Internal iterator over polynomial map. */ protected final Iterator> ms; /** * Constructor of polynomial iterator. * @param m SortetMap of a polynomial. */ public IndexListPolyIterator(SortedMap m) { ms = m.entrySet().iterator(); } /** * Test for availability of a next monomial. * @return true if the iteration has more monomials, else false. */ public boolean hasNext() { return ms.hasNext(); } /** * Get next monomial element. * @return next monomial. */ public IndexListMonomial next() { return new IndexListMonomial(ms.next()); } /** * Remove the last monomial returned from underlying set if allowed. */ public void remove() { ms.remove(); } } java-algebra-system-2.7.200/src/edu/jas/poly/InvalidExpressionException.java000066400000000000000000000011741445075545500270350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; /** * Invalid expression exception class. * Runtime Exception to be thrown for invalid algebraic / polynomial expressions. * @author Heinz Kredel */ public class InvalidExpressionException extends RuntimeException { public InvalidExpressionException() { super("InvalidExpressionException"); } public InvalidExpressionException(String c) { super(c); } public InvalidExpressionException(String c, Throwable t) { super(c, t); } public InvalidExpressionException(Throwable t) { super("InvalidExpressionException", t); } } java-algebra-system-2.7.200/src/edu/jas/poly/Local.java000066400000000000000000000264051445075545500225460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; import edu.jas.structure.RingElem; /** * Local element based on RingElem pairs. Objects of this class are (nearly) * immutable. * @author Heinz Kredel */ public class Local> implements RingElem>, QuotPair { private static final Logger logger = LogManager.getLogger(Local.class); private static final boolean debug = logger.isDebugEnabled(); /** * Local class factory data structure. */ protected final LocalRing ring; /** * Numerator part of the element data structure. */ protected final C num; /** * Denominator part of the element data structure. */ protected final C den; /** * Flag to remember if this local element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a Local object from a ring factory. * @param r ring factory. */ public Local(LocalRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a Local object from a ring factory and a * numerator element. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator. */ public Local(LocalRing r, C n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a Local object from a ring factory and a * numerator and denominator element. * @param r ring factory. * @param n numerator. * @param d denominator. */ public Local(LocalRing r, C n, C d) { this(r, n, d, false); } /** * The constructor creates a Local object from a ring factory and a * numerator and denominator element. * @param r ring factory. * @param n numerator. * @param d denominator. * @param isred true if gcd(n,d) == 1, else false. */ @SuppressWarnings("unchecked") protected Local(LocalRing r, C n, C d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = n.negate(); d = d.negate(); } if (isred) { num = n; den = d; return; } C p = d.remainder(ring.ideal); if (p == null || p.isZERO()) { throw new IllegalArgumentException("denominator may not be in ideal"); } // must reduce to lowest terms if (n instanceof GcdRingElem && d instanceof GcdRingElem) { GcdRingElem ng = (GcdRingElem) n; GcdRingElem dg = (GcdRingElem) d; C gcd = (C) ng.gcd(dg); if (debug) { logger.info("gcd = {}", gcd); } //RingElem gcd = ring.ring.getONE(); if (gcd.isONE()) { num = n; den = d; } else { num = n.divide(gcd); den = d.divide(gcd); } // } else { // univariate polynomial? } else { logger.warn("gcd = ????: {}, {}", n.getClass(), d.getClass()); num = n; den = d; } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public LocalRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public C numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public C denominator() { return den; } /** * Is Local a constant. Not implemented. * @throws UnsupportedOperationException. */ public boolean isConstant() { throw new UnsupportedOperationException("isConstant not implemented"); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Local copy() { return new Local(ring, num, den, true); } /** * Is Local zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is Local one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.equals(den); } /** * Is Local unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (isunit > 0) { return true; } if (isunit == 0) { return false; } // not jet known if (num.isZERO()) { isunit = 0; return false; } C p = num.remainder(ring.ideal); boolean u = (p != null && !p.isZERO()); if (u) { isunit = 1; } else { isunit = 0; } return (u); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(); if (den.isONE()) { return s + " }"; } return s + "| " + den.toString() + " }"; } return "Local[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return "Local( " + num.toScript() + " , " + den.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Local comparison. * @param b Local. * @return sign(this-b). */ @Override public int compareTo(Local b) { if (b == null || b.isZERO()) { return this.signum(); } C r = num.multiply(b.den); C s = den.multiply(b.num); C x = r.subtract(s); return x.signum(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Local)) { return false; } Local a = (Local) b; return (0 == compareTo(a)); } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * Local absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Local abs() { return new Local(ring, num.abs(), den, true); } /** * Local summation. * @param S Local. * @return this+S. */ public Local sum(Local S) { if (S == null || S.isZERO()) { return this; } C n = num.multiply(S.den); n = n.sum(den.multiply(S.num)); C d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Local negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Local negate() { return new Local(ring, num.negate(), den, true); } /** * Local signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return num.signum(); } /** * Local subtraction. * @param S Local. * @return this-S. */ public Local subtract(Local S) { if (S == null || S.isZERO()) { return this; } C n = num.multiply(S.den); n = n.subtract(den.multiply(S.num)); C d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Local division. * @param S Local. * @return this/S. */ public Local divide(Local S) { return multiply(S.inverse()); } /** * Local inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ public Local inverse() { if (isONE()) { return this; } if (isUnit()) { return new Local(ring, den, num, true); } throw new ArithmeticException("element not invertible " + this); } /** * Local remainder. * @param S Local. * @return this - (this/S)*S. */ public Local remainder(Local S) { if (num.isZERO()) { throw new ArithmeticException("element not invertible " + this); } if (S.isUnit()) { return ring.getZERO(); } throw new UnsupportedOperationException("remainder not implemented" + S); } /** * Quotient and remainder by division of this by S. * @param S a Local * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public Local[] quotientRemainder(Local S) { return new Local[] { divide(S), remainder(S) }; } /** * Local multiplication. * @param S Local. * @return this*S. */ public Local multiply(Local S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } C n = num.multiply(S.num); C d = den.multiply(S.den); return new Local(ring, n, d, false); } /** * Greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return gcd(this,b). */ public Local gcd(Local b) { throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName()); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public Local[] egcd(Local b) { throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/poly/LocalRing.java000066400000000000000000000167111445075545500233650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Local ring factory based on RingElem principal ideal. Objects of this class * are immutable. * @author Heinz Kredel */ public class LocalRing> implements RingFactory>, QuotPairFactory> { private static final Logger logger = LogManager.getLogger(LocalRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Ideal generator for localization. */ protected final C ideal; /** * Ring factory. */ protected final RingFactory ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * A default random sequence generator. */ protected final static Random random = new Random(); /** * The constructor creates a LocalRing object from a RingFactory and a * RingElem. * @param i localization ideal generator. */ public LocalRing(RingFactory r, C i) { ring = r; if (i == null) { throw new IllegalArgumentException("ideal may not be null"); } ideal = i; if (ideal.isONE()) { throw new IllegalArgumentException("ideal may not be 1"); } } /** * Factory for base elements. */ public RingFactory pairFactory() { return ring; } /** * Create from numerator. */ public Local create(C n) { return new Local(this, n); } /** * Create from numerator, denominator pair. */ public Local create(C n, C d) { return new Local(this, n, d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.isFinite(); } /** * Copy Local element c. * @param c * @return a copy of c. */ public Local copy(Local c) { return new Local(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as Local. */ public Local getZERO() { return new Local(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Local. */ public Local getONE() { return new Local(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = ring.generators(); List> gens = new ArrayList>(rgens.size() - 1); C one = ring.getONE(); for (C c : rgens) { gens.add(new Local(this, c)); if (!c.isONE()) { gens.add(new Local(this, one, c)); } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } // ?? return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Local element from a BigInteger value. * @param a BigInteger. * @return a Local. */ public Local fromInteger(java.math.BigInteger a) { return new Local(this, ring.fromInteger(a)); } /** * Get a Local element from a long value. * @param a long. * @return a Local. */ public Local fromInteger(long a) { return new Local(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "Local[ " + ideal.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "LocalRing(" + ideal.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override // not jet working @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof LocalRing)) { return false; } LocalRing a = (LocalRing) b; if (!ring.equals(a.ring)) { return false; } return ideal.equals(a.ideal); } /** * Hash code for this local ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + ideal.hashCode(); return h; } /** * Local random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Local random(int n) { return random(n, random); } /** * Local random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public Local random(int n, Random rnd) { C r = ring.random(n, rnd); C s = ring.random(n, rnd); s = s.remainder(ideal); while (s.isZERO()) { logger.debug("zero was in ideal"); s = ring.random(n, rnd); s = s.remainder(ideal); } return new Local(this, r, s, false); } /** * Parse Local from String. * @param s String. * @return Local from s. */ public Local parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { C n = ring.parse(s); return new Local(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); C n = ring.parse(s1); C d = ring.parse(s2); return new Local(this, n, d); } /** * Parse Local from Reader. * @param r Reader. * @return next Local from r. */ public Local parse(Reader r) { C x = ring.parse(r); return new Local(this, x); } } java-algebra-system-2.7.200/src/edu/jas/poly/ModuleList.java000066400000000000000000000321041445075545500235660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * List of vectors of polynomials. Mainly for storage and printing / toString * and conversions to other representations. * @author Heinz Kredel */ public class ModuleList> implements Serializable { /** * The factory for the solvable polynomial ring. */ public final GenPolynomialRing ring; /** * The data structure is a List of Lists of polynomials. */ public final List>> list; /** * Number of rows in the data structure. */ public final int rows; // -1 is undefined /** * Number of columns in the data structure. */ public final int cols; // -1 is undefined private static final Logger logger = LogManager.getLogger(ModuleList.class); /** * Constructor. * @param r polynomial ring factory. * @param l list of list of polynomials. */ public ModuleList(GenPolynomialRing r, List>> l) { ring = r; list = ModuleList. padCols(r, l); if (list == null) { rows = -1; cols = -1; } else { rows = list.size(); if (rows > 0) { cols = list.get(0).size(); } else { cols = -1; } } } /** * Constructor. * @param r solvable polynomial ring factory. * @param l list of list of solvable polynomials. */ public ModuleList(GenSolvablePolynomialRing r, List>> l) { this(r, ModuleList. castToList(l)); } /** * Constructor. * @param r polynomial ring factory. * @param l list of vectors of polynomials. */ public ModuleList(GenVectorModul> r, List>> l) { this((GenPolynomialRing) r.coFac, ModuleList. vecToList(l)); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") // not jet working public boolean equals(Object m) { if (m == null) { return false; } if (!(m instanceof ModuleList)) { //System.out.println("ModuleList"); return false; } ModuleList ml = (ModuleList) m; if (!ring.equals(ml.ring)) { //System.out.println("Ring"); return false; } if (list == ml.list) { return true; } if (list == null || ml.list == null) { //System.out.println("List, null"); return false; } if (list.size() != ml.list.size()) { //System.out.println("List, size"); return false; } // compare sorted lists List otl = OrderedModuleList.sort(ring, list); List oml = OrderedModuleList.sort(ring, ml.list); if (!otl.equals(oml)) { return false; } return true; } /** * Hash code for this module list. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + (list == null ? 0 : list.hashCode()); return h; } /** * Test if list is empty. * @return true if this is empty, else false. */ public boolean isEmpty() { if (list == null) { return true; } if (rows <= 0) { return true; } return false; } /** * Test all elements are zero. * @return true if all elements are zero, else false. */ public boolean isZERO() { if (list == null) { return true; } if (rows <= 0) { return true; } for (List> row : list) { for (GenPolynomial oa : row) { if (!oa.isZERO()) { return false; } } } return true; } /** * String representation of the module list. * @see java.lang.Object#toString() */ @Override //@SuppressWarnings("unchecked") public String toString() { StringBuffer erg = new StringBuffer(); String[] vars = null; if (ring != null) { erg.append(ring.toString()); vars = ring.getVars(); } if (list == null) { erg.append(")"); return erg.toString(); } boolean first = true; erg.append("(\n"); for (List> row : list) { if (first) { first = false; } else { erg.append(",\n"); } boolean ifirst = true; erg.append(" ( "); String os; for (GenPolynomial oa : row) { if (oa == null) { os = "0"; } else if (vars != null) { os = oa.toString(vars); } else { os = oa.toString(); } if (ifirst) { ifirst = false; } else { erg.append(", "); if (os.length() > 100) { erg.append("\n"); } } erg.append(os); } erg.append(" )"); } erg.append("\n)"); return erg.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this ModuleList. */ public String toScript() { StringBuffer s = new StringBuffer(); if (ring instanceof GenSolvablePolynomialRing) { s.append("Solvable"); } switch (Scripting.getLang()) { case Ruby: s.append("SubModule.new("); break; case Python: default: s.append("SubModule("); } if (ring != null) { s.append(ring.toScript()); } if (list == null) { s.append(")"); return s.toString(); } switch (Scripting.getLang()) { case Ruby: s.append(",\"\",["); break; case Python: default: s.append(",list=["); } boolean first = true; for (List> row : list) { if (first) { first = false; } else { s.append(","); } boolean ifirst = true; s.append(" ( "); String os; for (GenPolynomial oa : row) { if (oa == null) { os = "0"; } else { os = oa.toScript(); } if (ifirst) { ifirst = false; } else { s.append(", "); } s.append(os); } s.append(" )"); } s.append(" ])"); return s.toString(); } /** * Pad columns and remove zero rows. Make all rows have the same number of * columns. * @param ring polynomial ring factory. * @param l list of list of polynomials. * @return list of list of polynomials with same number of columns. */ public static > List>> padCols(GenPolynomialRing ring, List>> l) { if (l == null) { return l; } int mcols = 0; int rs = 0; for (List> row : l) { if (row != null) { rs++; if (row.size() > mcols) { mcols = row.size(); } } } List>> norm = new ArrayList>>(rs); for (List> row : l) { if (row != null) { List> rn = new ArrayList>(row); while (rn.size() < mcols) { rn.add(ring.getZERO()); } norm.add(rn); } } return norm; } /** * Get PolynomialList. Embed module in a polynomial ring. * @see edu.jas.poly.PolynomialList * @return polynomial list corresponding to this. */ public PolynomialList getPolynomialList() { return getPolynomialList(false); } /** * Get PolynomialList. Embed module in a polynomial ring. * @see edu.jas.poly.PolynomialList * @param top true for TOP term order, false for POT term order. * @return polynomial list corresponding to this. */ public PolynomialList getPolynomialList(boolean top) { GenPolynomialRing pfac = ring.extend(cols, top); logger.debug("extended ring = {}", pfac); //System.out.println("extended ring = " + pfac); return getPolynomialList(pfac); } /** * Get PolynomialList. Embed module in a polynomial ring. * @see edu.jas.poly.PolynomialList * @param pfac polynomial ring. * @return polynomial list corresponding to pfac and this. */ public PolynomialList getPolynomialList(GenPolynomialRing pfac) { List> pols = null; if (list == null) { // rows < 0 return new PolynomialList(pfac, pols); } pols = new ArrayList>(rows); if (rows == 0) { // nothing to do return new PolynomialList(pfac, pols); } GenPolynomial zero = pfac.getZERO(); GenPolynomial d = null; for (List> r : list) { GenPolynomial ext = zero; //int m = cols-1; int m = 0; for (GenPolynomial c : r) { d = c.extend(pfac, m, 1l); ext = ext.sum(d); m++; } pols.add(ext); } return new PolynomialList(pfac, pols); } /** * Get list as List of GenSolvablePolynomials. Required because no List * casts allowed. Equivalent to cast * (List<List<GenSolvablePolynomial<C>>>) list. * @return list of solvable polynomial lists from this. */ public List>> castToSolvableList() { List>> slist = null; if (list == null) { return slist; } slist = new ArrayList>>(list.size()); for (List> row : list) { List> srow = new ArrayList>(row.size()); for (GenPolynomial p : row) { if (!(p instanceof GenSolvablePolynomial)) { throw new RuntimeException("no solvable polynomial " + p); } GenSolvablePolynomial s = (GenSolvablePolynomial) p; srow.add(s); } slist.add(srow); } return slist; } /** * Get a solvable polynomials list as List of GenPolynomials. Required * because no List casts allowed. Equivalent to cast * (List<List<GenPolynomial<C>>>) list. * @param slist list of solvable polynomial lists. * @return list of polynomial lists from slist. */ public static > List>> castToList( List>> slist) { List>> list = null; if (slist == null) { return list; } list = new ArrayList>>(slist.size()); for (List> srow : slist) { List> row = new ArrayList>(srow.size()); for (GenSolvablePolynomial s : srow) { row.add(s); } list.add(row); } return list; } /** * Get a list of vectors as List of list of GenPolynomials. * @param vlist list of vectors of polynomials. * @return list of polynomial lists from vlist. */ public static > List>> vecToList( List>> vlist) { List>> list = null; if (vlist == null) { return list; } list = new ArrayList>>(vlist.size()); for (GenVector> srow : vlist) { List> row = srow.val; list.add(row); } return list; } } java-algebra-system-2.7.200/src/edu/jas/poly/Monomial.java000066400000000000000000000072331445075545500232650ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Map; import edu.jas.structure.ElemFactory; // import edu.jas.structure.RingFactory; import edu.jas.structure.Element; import edu.jas.structure.RingElem; /** * Monomial class. Represents pairs of exponent vectors and coefficients. * Adaptor for Map.Entry. * @author Heinz Kredel */ public final class Monomial> implements Element> { /** * Exponent of monomial. */ public final ExpVector e; /** * Coefficient of monomial. */ public final C c; /** * Constructor of monomial. * @param me a MapEntry. */ public Monomial(Map.Entry me) { this(me.getKey(), me.getValue()); } /** * Constructor of monomial. * @param e exponent. * @param c coefficient. */ public Monomial(ExpVector e, C c) { this.e = e; this.c = c; } /** * Getter for exponent. * @return exponent. */ public ExpVector exponent() { return e; } /** * Getter for coefficient. * @return coefficient. */ public C coefficient() { return c; } /** * Clone this Element. * @return Creates and returns a copy of this Element. */ public Monomial copy() { return new Monomial(e, c); } /** * String representation of Monomial. * @see java.lang.Object#toString() */ @Override public String toString() { return c.toString() + " " + e.toString(); } /** * Script representation of Monomial. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { if (c.isZERO()) { return "0"; } StringBuffer sb = new StringBuffer(); if (!c.isONE()) { sb.append(c.toScript()); if (e.signum() != 0) { sb.append(" * "); } } sb.append(e.toScript()); return sb.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python and Ruby case throw new UnsupportedOperationException("no factory for Monomial"); } /** * Get the corresponding element factory. * @return null, factory for this Element. * @see edu.jas.structure.Element#factory() */ public ElemFactory> factory() { //return new GenPolynomialRing((RingFactory)c.factory(), e.length()); throw new UnsupportedOperationException("no factory for Monomial"); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (!(B instanceof Monomial)) { return false; } Monomial b = (Monomial) B; return (compareTo(b) == 0); } /** * hashCode. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = e.hashCode(); h = (h << 4) + c.hashCode(); return h; } /** * Monomial comparison. * @param S Monomial. * @return SIGN(this-S). */ @Override public int compareTo(Monomial S) { if (S == null) { return 1; } int s = e.compareTo(S.e); if (s != 0) { return s; } return c.compareTo(S.c); } } java-algebra-system-2.7.200/src/edu/jas/poly/OptimizedModuleList.java000066400000000000000000000022431445075545500254540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.structure.RingElem; /** * Container for optimization results. * @author Heinz Kredel */ public class OptimizedModuleList> extends ModuleList { /** * Permutation vector used to optimize term order. */ public final List perm; /** * Constructor. */ public OptimizedModuleList(List P, GenPolynomialRing R, List>> L) { super(R, L); perm = P; } /** * String representation. */ @Override public String toString() { return "permutation = " + perm + "\n" + super.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof OptimizedModuleList)) { return false; } return super.equals(B); } /** * Hash code for this module list. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/poly/OptimizedPolynomialList.java000066400000000000000000000022621445075545500263530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.structure.RingElem; /** * Container for optimization results. * @author Heinz Kredel */ public class OptimizedPolynomialList> extends PolynomialList { /** * Permutation vector used to optimize term order. */ public final List perm; /** * Constructor. */ public OptimizedPolynomialList(List P, GenPolynomialRing R, List> L) { super(R, L); perm = P; } /** * String representation. */ @Override public String toString() { return "permutation = " + perm + "\n" + super.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof OptimizedPolynomialList)) { return false; } return super.equals(B); } /** * Hash code for this polynomial list. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/poly/OrderedModuleList.java000066400000000000000000000105471445075545500251020ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import edu.jas.structure.RingElem; /** * Ordered list of vectors of polynomials. Mainly for storage and printing / * toString and conversions to other representations. Lists of polynomials in * this list are sorted according to the head terms of the first column. * @author Heinz Kredel */ public class OrderedModuleList> extends ModuleList { /** * Constructor. * @param r polynomial ring factory. * @param l list of list of polynomials. */ public OrderedModuleList(GenPolynomialRing r, List>> l) { super(r, sort(r, ModuleList.padCols(r, l))); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") // not jet working public boolean equals(Object m) { if (!super.equals(m)) { return false; } OrderedModuleList ml = null; try { ml = (OrderedModuleList) m; } catch (ClassCastException ignored) { } if (ml == null) { return false; } // compare sorted lists, done already in super.equals() return true; } /** * Hash code for OrderedModuleList. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Sort a list of vectors of polynomials with respect to the ascending order * of the leading Exponent vectors of the first column. The term order is * taken from the ring. * @param r polynomial ring factory. * @param l list of polynomial lists. * @return sorted list of polynomial lists from l. */ @SuppressWarnings({ "unchecked", "cast" }) public static > List>> sort(GenPolynomialRing r, List>> l) { if (l == null) { return l; } if (l.size() <= 1) { // nothing to sort return l; } final Comparator evc = r.tord.getAscendComparator(); Comparator>> cmp = new Comparator>>() { public int compare(List> l1, List> l2) { int c = 0; for (int i = 0; i < l1.size(); i++) { GenPolynomial p1 = l1.get(i); GenPolynomial p2 = l2.get(i); ExpVector e1 = p1.leadingExpVector(); ExpVector e2 = p2.leadingExpVector(); if (e1 == e2) { continue; } if (e1 == null && e2 != null) { return -1; } if (e1 != null && e2 == null) { return 1; } if (e1 == null || e2 == null) { // for findbugs continue; // cannot happen } if (e1.length() != e2.length()) { if (e1.length() > e2.length()) { return 1; } return -1; } c = evc.compare(e1, e2); if (c != 0) { return c; } } return c; } }; List>[] s = null; try { s = (List>[]) new List[l.size()]; //System.out.println("s.length = " + s.length ); //s = l.toArray(s); does not work //for ( int i = 0; i < l.size(); i++ ) { // s[i] = l.get(i); //} int i = 0; for (List> p : l) { s[i++] = p; } Arrays.>> sort(s, cmp); return new ArrayList>>(Arrays.>> asList(s)); } catch (ClassCastException ok) { System.out.println("Warning: polynomials not sorted"); } return l; // unsorted } } java-algebra-system-2.7.200/src/edu/jas/poly/OrderedPolynomialList.java000066400000000000000000000125321445075545500257740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import edu.jas.structure.RingElem; /** * Ordered list of polynomials. Mainly for storage and printing / toString and * conversions to other representations. Polynomials in this list are sorted * according to their head terms. * @author Heinz Kredel */ public class OrderedPolynomialList> extends PolynomialList { /** * Constructor. * @param r polynomial ring factory. * @param l list of polynomials. */ public OrderedPolynomialList(GenPolynomialRing r, List> l) { super(r, sort(r, l)); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object p) { if (!super.equals(p)) { return false; } OrderedPolynomialList pl = null; try { pl = (OrderedPolynomialList) p; } catch (ClassCastException ignored) { } if (pl == null) { return false; } // compare sorted lists // done already in super.equals() return true; } /** * Hash code for OrderedPolynomialList. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * Sort a list of polynomials with respect to the ascending order of the * leading Exponent vectors. The term order is taken from the ring. * @param L polynomial list. * @return sorted polynomial list from L. */ public static > List> sort(List> L) { if (L == null) { return L; } if (L.size() <= 1) { // nothing to sort return L; } GenPolynomialRing r = L.get(0).ring; return sort(r,L); } /** * Sort a list of polynomials with respect to the ascending order of the * leading Exponent vectors. The term order is taken from the ring. * @param r polynomial ring factory. * @param L polynomial list. * @return sorted polynomial list from L. */ @SuppressWarnings({ "unchecked", "cast" }) public static > List> sort(GenPolynomialRing r, List> L) { if (L == null) { return L; } if (L.size() <= 1) { // nothing to sort return L; } final Comparator evc = r.tord.getAscendComparator(); Comparator> cmp = new Comparator>() { public int compare(GenPolynomial p1, GenPolynomial p2) { ExpVector e1 = p1.leadingExpVector(); ExpVector e2 = p2.leadingExpVector(); if (e1 == null) { return -1; // dont care } if (e2 == null) { return 1; // dont care } if (e1.length() != e2.length()) { if (e1.length() > e2.length()) { return 1; // dont care } return -1; // dont care } return evc.compare(e1, e2); } }; GenPolynomial[] s = null; try { s = (GenPolynomial[]) new GenPolynomial[L.size()]; int i = 0; for (GenPolynomial p : L) { s[i++] = p; } Arrays.> sort(s, cmp); return new ArrayList>(Arrays.> asList(s)); } catch (ClassCastException ok) { System.out.println("Warning: polynomials not sorted"); } return L; // unsorted } /** * Sort a list of polynomials with respect to the ascending order of the * degree. * @param L polynomial list. * @return sorted polynomial list from L. */ @SuppressWarnings({ "unchecked", "cast" }) public static > List> sortDegree(List> L) { if (L == null) { return L; } if (L.size() <= 1) { // nothing to sort return L; } Comparator> cmp = new Comparator>() { public int compare(GenPolynomial p1, GenPolynomial p2) { long d1 = p1.degree(); long d2 = p2.degree(); if (d1 > d2) { return -1; } else if (d1 < d2) { return 1; } return 0; } }; GenPolynomial[] s = null; try { s = (GenPolynomial[]) new GenPolynomial[L.size()]; int i = 0; for (GenPolynomial p : L) { s[i++] = p; } Arrays.> sort(s, cmp); return new ArrayList>(Arrays.> asList(s)); } catch (ClassCastException ok) { System.out.println("Warning: polynomials not sorted"); } return L; // unsorted } } java-algebra-system-2.7.200/src/edu/jas/poly/Overlap.java000066400000000000000000000025361445075545500231230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; /** * Container for overlap words. * A container of four words l1, r1, l2, r2. * @author Heinz Kredel */ public class Overlap implements Serializable { public final Word l1; public final Word r1; public final Word l2; public final Word r2; /** * Constructor. */ public Overlap(Word l1, Word r1, Word l2, Word r2) { this.l1 = l1; this.r1 = r1; this.l2 = l2; this.r2 = r2; } /** * Is word overlap. * @param u word * @param v word * @return true if l1 * u * r1 = l2 * v * r2, else false. */ public boolean isOverlap(Word u, Word v) { Word a = l1.multiply(u).multiply(r1); Word b = l2.multiply(v).multiply(r2); boolean t = a.equals(b); if ( !t ) { System.out.println("a = " + a + " != b = " + b); } return t; } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("Overlap["); s.append(l1); s.append(", "); s.append(r1); s.append(", "); s.append(l2); s.append(", "); s.append(r2); s.append("]"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/poly/OverlapList.java000066400000000000000000000020521445075545500237500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.List; import java.util.ArrayList; /** * Container for lists of overlap words. * List of Overlaps. * @author Heinz Kredel */ public class OverlapList implements Serializable { public final List ols; /** * Constructor. */ public OverlapList() { ols = new ArrayList(); } /** * Add to list. */ public void add(Overlap ol) { ols.add(ol); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { return ols.toString(); } /** * Is word overlap list. * @param u word * @param v word * @return true if l1 * u * r1 = l2 * v * r2 for all overlaps, else false. */ public boolean isOverlap(Word u, Word v) { for (Overlap ol : ols ) { if ( !ol.isOverlap(u,v) ) { return false; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/poly/PolyIterator.java000066400000000000000000000023451445075545500241460ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.SortedMap; import java.util.Iterator; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; /** * Iterator over monomials of a polynomial. * Adaptor for val.entrySet().iterator(). * @author Heinz Kredel */ public class PolyIterator > implements Iterator< Monomial > { /** * Internal iterator over polynomial map. */ protected final Iterator< Map.Entry > ms; /** * Constructor of polynomial iterator. * @param m SortetMap of a polynomial. */ public PolyIterator( SortedMap m ) { ms = m.entrySet().iterator(); } /** * Test for availability of a next monomial. * @return true if the iteration has more monomials, else false. */ public boolean hasNext() { return ms.hasNext(); } /** * Get next monomial element. * @return next monomial. */ public Monomial next() { return new Monomial( ms.next() ); } /** * Remove the last monomial returned from underlying set if allowed. */ public void remove() { ms.remove(); } } java-algebra-system-2.7.200/src/edu/jas/poly/PolySpliterator.java000066400000000000000000000067461445075545500246760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.SortedMap; import java.util.Comparator; import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; /** * Spliterator over monomials of a polynomial. * Adaptor for val.entrySet().spliterator(). * @author Heinz Kredel */ public class PolySpliterator > implements Spliterator< Monomial > { /** * Internal spliterator over polynomial map. */ protected Spliterator< Map.Entry > ms; /** * Polynomial sorted map. */ protected SortedMap sm; /** * Constructor of polynomial spliterator. * @param m SortedMap of a polynomial. */ public PolySpliterator( SortedMap m ) { //this(Spliterators.spliterator(m.entrySet(), Spliterator.NONNULL), m); this(m.entrySet().spliterator(), m); } /** * Constructor of polynomial spliterator. * @param mse Spliterator a polynomial. * @param m SortedMap of a polynomial. */ protected PolySpliterator( Spliterator> mse, SortedMap m ) { sm = m; ms = mse; } /** * String representation of PolySpliterator. * @see java.lang.Object#toString() */ @Override public String toString() { return "PolySpliterator(" + estimateSize() + ", " + characteristics() + ")"; } /** * Returns a set of characteristics of this Spliterator and its * elements. * @return ORed value of the characteristics. */ public int characteristics() { return ms.characteristics(); } /** * Returns an estimate of the number of elements of this Spliterator. * @return size of the sorted map. */ public long estimateSize() { return ms.estimateSize(); } /** * Get the monomial comparator. * @return monomial comparator. */ public Comparator> getComparator() { return new Comparator>() { @Override public int compare(Monomial a, Monomial b) { if (sm == null) { throw new RuntimeException("sm == null"); } int s = sm.comparator().compare(a.e, b.e); if (s != 0) { // always true return s; } return a.c.compareTo(b.c); } }; } /** * Try to split this spliterator. * @return polynomial spliterator or null. */ public PolySpliterator trySplit() { Spliterator< Map.Entry > part = ms.trySplit(); //System.out.println("PolySplit(" + part.characteristics() + ")"); return new PolySpliterator(part, sm); } /** * If a remaining element exists perform the action on it. * @return true if the polynomial spliterator could be advanced, else false. */ public boolean tryAdvance(Consumer> action) { Consumer> mact = new Consumer>() { public void accept(Map.Entry me) { action.accept( new Monomial(me.getKey(), me.getValue()) ); } }; return ms.tryAdvance(mact); } } java-algebra-system-2.7.200/src/edu/jas/poly/PolyUtil.java000066400000000000000000004265001445075545500232750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigDecimalComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.arith.Rational; import edu.jas.arith.Roots; import edu.jas.structure.Element; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.StarRingElem; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; /** * Polynomial utilities, for example conversion between different * representations, evaluation and interpolation. * @author Heinz Kredel */ public class PolyUtil { private static final Logger logger = LogManager.getLogger(PolyUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Recursive representation. Represent as polynomial in i variables with * coefficients in n-i variables. Works for arbitrary term orders. * @param coefficient type. * @param rfac recursive polynomial ring factory. * @param A polynomial to be converted. * @return Recursive representations of this in the ring rfac. */ public static > GenPolynomial> recursive( GenPolynomialRing> rfac, GenPolynomial A) { GenPolynomial> B = rfac.getZERO().copy(); if (A.isZERO()) { return B; } int i = rfac.nvar; GenPolynomial zero = rfac.getZEROCoefficient(); Map> Bv = B.val; //getMap(); for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector f = e.contract(0, i); ExpVector g = e.contract(i, e.length() - i); GenPolynomial p = Bv.get(f); if (p == null) { p = zero; } p = p.sum(a, g); Bv.put(f, p); } return B; } /** * Distribute a recursive polynomial to a generic polynomial. Works for * arbitrary term orders. * @param coefficient type. * @param dfac combined polynomial ring factory of coefficients and this. * @param B polynomial to be converted. * @return distributed polynomial. */ public static > GenPolynomial distribute(GenPolynomialRing dfac, GenPolynomial> B) { GenPolynomial C = dfac.getZERO().copy(); if (B.isZERO()) { return C; } Map Cm = C.val; //getMap(); for (Map.Entry> y : B.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial A = y.getValue(); for (Map.Entry x : A.val.entrySet()) { ExpVector f = x.getKey(); C b = x.getValue(); ExpVector g = e.combine(f); assert (Cm.get(g) == null); Cm.put(g, b); } } return C; } /** * Recursive representation. Represent as polynomials in i variables with * coefficients in n-i variables. Works for arbitrary term orders. * @param coefficient type. * @param rfac recursive polynomial ring factory. * @param L list of polynomials to be converted. * @return Recursive representations of the list in the ring rfac. */ public static > List>> recursive( GenPolynomialRing> rfac, List> L) { return ListUtil., GenPolynomial>> map(L, new DistToRec(rfac)); } /** * Distribute a recursive polynomial list to a generic polynomial list. * Works for arbitrary term orders. * @param coefficient type. * @param dfac combined polynomial ring factory of coefficients and this. * @param L list of polynomials to be converted. * @return distributed polynomial list. */ public static > List> distribute(GenPolynomialRing dfac, List>> L) { return ListUtil.>, GenPolynomial> map(L, new RecToDist(dfac)); } /** * BigInteger from ModInteger coefficients, symmetric. Represent as * polynomial with BigInteger coefficients by removing the modules and * making coefficients symmetric to 0. * @param fac result polynomial factory. * @param A polynomial with ModInteger coefficients to be converted. * @return polynomial with BigInteger coefficients. */ public static & Modular> GenPolynomial integerFromModularCoefficients( GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new ModSymToInt()); } /** * BigInteger from ModInteger coefficients, symmetric. Represent as * polynomial with BigInteger coefficients by removing the modules and * making coefficients symmetric to 0. * @param fac result polynomial factory. * @param L list of polynomials with ModInteger coefficients to be * converted. * @return list of polynomials with BigInteger coefficients. */ public static & Modular> List> integerFromModularCoefficients( final GenPolynomialRing fac, List> L) { return ListUtil., GenPolynomial> map(L, new UnaryFunctor, GenPolynomial>() { public GenPolynomial eval(GenPolynomial c) { return PolyUtil. integerFromModularCoefficients(fac, c); } }); } /** * BigInteger from ModInteger coefficients, positive. Represent as * polynomial with BigInteger coefficients by removing the modules. * @param fac result polynomial factory. * @param A polynomial with ModInteger coefficients to be converted. * @return polynomial with BigInteger coefficients. */ public static & Modular> GenPolynomial integerFromModularCoefficientsPositive( GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new ModToInt()); } /** * BigInteger from BigRational coefficients. Represent as polynomial with * BigInteger coefficients by multiplication with the lcm of the numerators * of the BigRational coefficients. * @param fac result polynomial factory. * @param A polynomial with BigRational coefficients to be converted. * @return polynomial with BigInteger coefficients. */ public static GenPolynomial integerFromRationalCoefficients(GenPolynomialRing fac, GenPolynomial A) { if (A == null || A.isZERO()) { return fac.getZERO(); } java.math.BigInteger c = null; int s = 0; // lcm of denominators for (BigRational y : A.val.values()) { java.math.BigInteger x = y.denominator(); // c = lcm(c,x) if (c == null) { c = x; s = x.signum(); } else { java.math.BigInteger d = c.gcd(x); c = c.multiply(x.divide(d)); } } if (s < 0) { c = c.negate(); } return PolyUtil. map(fac, A, new RatToInt(c)); } /** * BigInteger from BigRational coefficients. Represent as polynomial with * BigInteger coefficients by multiplication with the gcd of the numerators * and the lcm of the denominators of the BigRational coefficients.
* Author: Axel Kramer * @param fac result polynomial factory. * @param A polynomial with BigRational coefficients to be converted. * @return Object[] with 3 entries: [0]=gcd [1]=lcm and [2]=polynomial with * BigInteger coefficients. */ public static Object[] integerFromRationalCoefficientsFactor(GenPolynomialRing fac, GenPolynomial A) { Object[] result = new Object[3]; if (A == null || A.isZERO()) { result[0] = java.math.BigInteger.ONE; result[1] = java.math.BigInteger.ZERO; result[2] = fac.getZERO(); return result; } java.math.BigInteger gcd = null; java.math.BigInteger lcm = null; int sLCM = 0; int sGCD = 0; // lcm of denominators for (BigRational y : A.val.values()) { java.math.BigInteger numerator = y.numerator(); java.math.BigInteger denominator = y.denominator(); // lcm = lcm(lcm,x) if (lcm == null) { lcm = denominator; sLCM = denominator.signum(); } else { java.math.BigInteger d = lcm.gcd(denominator); lcm = lcm.multiply(denominator.divide(d)); } // gcd = gcd(gcd,x) if (gcd == null) { gcd = numerator; sGCD = numerator.signum(); } else { gcd = gcd.gcd(numerator); } } if (sLCM < 0) { lcm = lcm.negate(); } if (sGCD < 0) { gcd = gcd.negate(); } //System.out.println("gcd* = " + gcd + ", lcm = " + lcm); result[0] = gcd; result[1] = lcm; result[2] = PolyUtil. map(fac, A, new RatToIntFactor(gcd, lcm)); return result; } /** * BigInteger from BigRational coefficients. Represent as polynomial with * BigInteger coefficients by multiplication with the gcd of the numerators * and the lcm of the denominators of the BigRational coefficients.
* @param fac result polynomial factory. * @param gcd of rational coefficient numerators. * @param lcm of rational coefficient denominators. * @param A polynomial with BigRational coefficients to be converted. * @return polynomial with BigInteger coefficients. */ public static GenPolynomial integerFromRationalCoefficients(GenPolynomialRing fac, java.math.BigInteger gcd, java.math.BigInteger lcm, GenPolynomial A) { //System.out.println("gcd = " + gcd + ", lcm = " + lcm); GenPolynomial Ai = PolyUtil. map(fac, A, new RatToIntFactor(gcd, lcm)); return Ai; } /** * BigInteger from BigRational coefficients. Represent as list of * polynomials with BigInteger coefficients by multiplication with the lcm * of the numerators of the BigRational coefficients of each polynomial. * @param fac result polynomial factory. * @param L list of polynomials with BigRational coefficients to be * converted. * @return polynomial list with BigInteger coefficients. */ public static List> integerFromRationalCoefficients( GenPolynomialRing fac, List> L) { return ListUtil., GenPolynomial> map(L, new RatToIntPoly(fac)); } /** * From BigInteger coefficients. Represent as polynomial with type C * coefficients, e.g. ModInteger or BigRational. * @param coefficient type. * @param fac result polynomial factory. * @param A polynomial with BigInteger coefficients to be converted. * @return polynomial with type C coefficients. */ public static > GenPolynomial fromIntegerCoefficients(GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new FromInteger(fac.coFac)); } /** * From BigInteger coefficients. Represent as list of polynomials with type * C coefficients, e.g. ModInteger or BigRational. * @param coefficient type. * @param fac result polynomial factory. * @param L list of polynomials with BigInteger coefficients to be * converted. * @return list of polynomials with type C coefficients. */ public static > List> fromIntegerCoefficients( GenPolynomialRing fac, List> L) { return ListUtil., GenPolynomial> map(L, new FromIntegerPoly(fac)); } /** * Convert to decimal coefficients. * @param fac result polynomial factory. * @param A polynomial with Rational coefficients to be converted. * @return polynomial with BigDecimal coefficients. */ public static & Rational> GenPolynomial decimalFromRational( GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new RatToDec()); } /** * Convert to complex decimal coefficients. * @param fac result polynomial factory. * @param A polynomial with complex Rational coefficients to be converted. * @return polynomial with Complex BigDecimal coefficients. */ public static & Rational> GenPolynomial> complexDecimalFromRational( GenPolynomialRing> fac, GenPolynomial> A) { return PolyUtil., Complex> map(fac, A, new CompRatToDec(fac.coFac)); } /** * Real part. * @param fac result polynomial factory. * @param A polynomial with BigComplex coefficients to be converted. * @return polynomial with real part of the coefficients. */ public static GenPolynomial realPart(GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new RealPart()); } /** * Imaginary part. * @param fac result polynomial factory. * @param A polynomial with BigComplex coefficients to be converted. * @return polynomial with imaginary part of coefficients. */ public static GenPolynomial imaginaryPart(GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new ImagPart()); } /** * Conjugate coefficients. * @param A polynomial with StarRingElem coefficients to be conjugated. * @return polynomial with conjugate coefficients. */ @SuppressWarnings("unchecked") public static > GenPolynomial conjugateCoeff(GenPolynomial A) { //return PolyUtil. map(A, new ConjugPart()); if (! (A.ring.coFac.getONE() instanceof StarRingElem)) { return A; } return PolyUtil. map(A.ring, A, (a) -> (C)(((StarRingElem)a).conjugate())); } /** * Real part. * @param fac result polynomial factory. * @param A polynomial with BigComplex coefficients to be converted. * @return polynomial with real part of the coefficients. */ public static > GenPolynomial realPartFromComplex(GenPolynomialRing fac, GenPolynomial> A) { return PolyUtil., C> map(fac, A, new RealPartComplex()); } /** * Imaginary part. * @param fac result polynomial factory. * @param A polynomial with BigComplex coefficients to be converted. * @return polynomial with imaginary part of coefficients. */ public static > GenPolynomial imaginaryPartFromComplex(GenPolynomialRing fac, GenPolynomial> A) { return PolyUtil., C> map(fac, A, new ImagPartComplex()); } /** * Complex from real polynomial. * @param fac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with Complex coefficients. */ public static > GenPolynomial> toComplex( GenPolynomialRing> fac, GenPolynomial A) { return PolyUtil.> map(fac, A, new ToComplex(fac.coFac)); } /** * Complex from rational coefficients. * @param fac result polynomial factory. * @param A polynomial with BigRational coefficients to be converted. * @return polynomial with BigComplex coefficients. */ public static GenPolynomial complexFromRational(GenPolynomialRing fac, GenPolynomial A) { return PolyUtil. map(fac, A, new RatToCompl()); } /** * Complex from ring element coefficients. * @param fac result polynomial factory. * @param A polynomial with RingElem coefficients to be converted. * @return polynomial with Complex coefficients. */ public static > GenPolynomial> complexFromAny( GenPolynomialRing> fac, GenPolynomial A) { ComplexRing cr = (ComplexRing) fac.coFac; return PolyUtil.> map(fac, A, new AnyToComplex(cr)); } /** * From AlgebraicNumber coefficients. Represent as polynomial with type * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. * @param rfac result polynomial factory. * @param A polynomial with AlgebraicNumber coefficients to be converted. * @return polynomial with type GenPolynomial<C> coefficients. */ public static > GenPolynomial> fromAlgebraicCoefficients( GenPolynomialRing> rfac, GenPolynomial> A) { return PolyUtil., GenPolynomial> map(rfac, A, new AlgToPoly()); } /** * Convert to AlgebraicNumber coefficients. Represent as polynomial with * AlgebraicNumber coefficients, C is e.g. ModInteger or BigRational. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with AlgebraicNumber<C> coefficients. */ public static > GenPolynomial> convertToAlgebraicCoefficients( GenPolynomialRing> pfac, GenPolynomial A) { AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; return PolyUtil.> map(pfac, A, new CoeffToAlg(afac)); } /** * Convert to recursive AlgebraicNumber coefficients. Represent as * polynomial with recursive AlgebraicNumber coefficients, C is e.g. * ModInteger or BigRational. * @param depth recursion depth of AlgebraicNumber coefficients. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with AlgebraicNumber<C> coefficients. */ public static > GenPolynomial> convertToRecAlgebraicCoefficients( int depth, GenPolynomialRing> pfac, GenPolynomial A) { AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; return PolyUtil.> map(pfac, A, new CoeffToRecAlg(depth, afac)); } /** * Convert to AlgebraicNumber coefficients. Represent as polynomial with * AlgebraicNumber coefficients, C is e.g. ModInteger or BigRational. * @param pfac result polynomial factory. * @param A recursive polynomial with GenPolynomial<BigInteger> * coefficients to be converted. * @return polynomial with AlgebraicNumber<C> coefficients. */ public static > GenPolynomial> convertRecursiveToAlgebraicCoefficients( GenPolynomialRing> pfac, GenPolynomial> A) { AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; return PolyUtil., AlgebraicNumber> map(pfac, A, new PolyToAlg(afac)); } /** * Complex from algebraic coefficients. * @param fac result polynomial factory. * @param A polynomial with AlgebraicNumber coefficients Q(i) to be * converted. * @return polynomial with Complex coefficients. */ public static > GenPolynomial> complexFromAlgebraic( GenPolynomialRing> fac, GenPolynomial> A) { ComplexRing cfac = (ComplexRing) fac.coFac; return PolyUtil., Complex> map(fac, A, new AlgebToCompl(cfac)); } /** * AlgebraicNumber from complex coefficients. * @param fac result polynomial factory over Q(i). * @param A polynomial with Complex coefficients to be converted. * @return polynomial with AlgebraicNumber coefficients. */ public static > GenPolynomial> algebraicFromComplex( GenPolynomialRing> fac, GenPolynomial> A) { AlgebraicNumberRing afac = (AlgebraicNumberRing) fac.coFac; return PolyUtil., AlgebraicNumber> map(fac, A, new ComplToAlgeb(afac)); } /** * ModInteger chinese remainder algorithm on coefficients. * @param fac GenPolynomial<ModInteger> result factory with * A.coFac.modul*B.coFac.modul = C.coFac.modul. * @param A GenPolynomial<ModInteger>. * @param B other GenPolynomial<ModInteger>. * @param mi inverse of A.coFac.modul in ring B.coFac. * @return S = cra(A,B), with S mod A.coFac.modul == A and S mod * B.coFac.modul == B. */ public static & Modular> GenPolynomial chineseRemainder( GenPolynomialRing fac, GenPolynomial A, C mi, GenPolynomial B) { ModularRingFactory cfac = (ModularRingFactory) fac.coFac; // get RingFactory GenPolynomial S = fac.getZERO().copy(); GenPolynomial Ap = A.copy(); SortedMap av = Ap.val; //getMap(); SortedMap bv = B.getMap(); SortedMap sv = S.val; //getMap(); C c = null; for (Map.Entry me : bv.entrySet()) { ExpVector e = me.getKey(); C y = me.getValue(); //bv.get(e); // assert y != null C x = av.get(e); if (x != null) { av.remove(e); c = cfac.chineseRemainder(x, mi, y); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); } } else { //c = cfac.fromInteger( y.getVal() ); c = cfac.chineseRemainder(A.ring.coFac.getZERO(), mi, y); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); // c != null } } } // assert bv is empty = done for (Map.Entry me : av.entrySet()) { // rest of av ExpVector e = me.getKey(); C x = me.getValue(); // av.get(e); // assert x != null //c = cfac.fromInteger( x.getVal() ); c = cfac.chineseRemainder(x, mi, B.ring.coFac.getZERO()); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); // c != null } } return S; } /** * GenPolynomial monic, i.e. leadingBaseCoefficient == 1. If * leadingBaseCoefficient is not invertible returns this unmodified. * @param coefficient type. * @param p recursive GenPolynomial<GenPolynomial>. * @return monic(p). */ public static > GenPolynomial> monic( GenPolynomial> p) { if (p == null || p.isZERO()) { return p; } C lc = p.leadingBaseCoefficient().leadingBaseCoefficient(); if (!lc.isUnit()) { return p; } C lm = lc.inverse(); GenPolynomial L = p.ring.coFac.getONE(); L = L.multiply(lm); return p.multiplyLeft(L); } /** * GenSolvablePolynomial monic, i.e. leadingBaseCoefficient == 1. If * leadingBaseCoefficient is not invertible returns this unmodified. * @param coefficient type. * @param p recursive GenSolvablePolynomial<GenPolynomial>. * @return monic(p). */ public static > GenSolvablePolynomial> monic( GenSolvablePolynomial> p) { if (p == null || p.isZERO()) { return p; } C lc = p.leadingBaseCoefficient().leadingBaseCoefficient(); if (!lc.isUnit()) { return p; } C lm = lc.inverse(); GenPolynomial L = p.ring.coFac.getONE(); L = L.multiply(lm); return p.multiplyLeft(L); } /** * Polynomial list monic. * @param coefficient type. * @param L list of polynomials with field coefficients. * @return list of polynomials with leading coefficient 1. */ public static > List> monic(List> L) { return ListUtil., GenPolynomial> map(L, new UnaryFunctor, GenPolynomial>() { public GenPolynomial eval(GenPolynomial c) { if (c == null) { return null; } return c.monic(); } }); } /** * Solvable polynomial list right monic. * @param coefficient type. * @param L list of solvable polynomials with field coefficients. * @return list of solvable polynomials with leading coefficient 1. */ public static > List> rightMonic(List> L) { return ListUtil., GenPolynomial> map(L, new UnaryFunctor, GenPolynomial>() { public GenPolynomial eval(GenPolynomial c) { if (c == null) { return null; } GenSolvablePolynomial d = (GenSolvablePolynomial) c; return (GenPolynomial) d.rightMonic(); } }); } /** * Word polynomial list monic. * @param coefficient type. * @param L list of word polynomials with field coefficients. * @return list of word polynomials with leading coefficient 1. */ public static > List> wordMonic(List> L) { return ListUtil., GenWordPolynomial> map(L, new UnaryFunctor, GenWordPolynomial>() { public GenWordPolynomial eval(GenWordPolynomial c) { if (c == null) { return null; } return c.monic(); } }); } /** * Recursive polynomial list monic. * @param coefficient type. * @param L list of recursive polynomials with field coefficients. * @return list of polynomials with leading base coefficient 1. */ public static > List>> monicRec( List>> L) { return ListUtil.>, GenPolynomial>> map(L, new UnaryFunctor>, GenPolynomial>>() { public GenPolynomial> eval(GenPolynomial> c) { if (c == null) { return null; } return PolyUtil. monic(c); } }); } /** * Polynomial list leading exponent vectors. * @param coefficient type. * @param L list of polynomials. * @return list of leading exponent vectors. */ public static > List leadingExpVector(List> L) { return ListUtil., ExpVector> map(L, new UnaryFunctor, ExpVector>() { public ExpVector eval(GenPolynomial c) { if (c == null) { return null; } return c.leadingExpVector(); } }); } /** * Extend coefficient variables. Extend all coefficient ExpVectors by i * elements and multiply by x_j^k. * @param pfac extended polynomial ring factory (by i variables in the * coefficients). * @param j index of variable to be used for multiplication. * @param k exponent for x_j. * @return extended polynomial. */ public static > GenPolynomial> extendCoefficients( GenPolynomialRing> pfac, GenPolynomial> A, int j, long k) { GenPolynomial> Cp = pfac.getZERO().copy(); if (A.isZERO()) { return Cp; } GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; //GenPolynomialRing acfac = (GenPolynomialRing) A.ring.coFac; //int i = cfac.nvar - acfac.nvar; Map> CC = Cp.val; //getMap(); for (Map.Entry> y : A.val.entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); GenPolynomial f = a.extend(cfac, j, k); CC.put(e, f); } return Cp; } /** * Extend coefficient variables. Extend all coefficient ExpVectors by i * elements and multiply by x_j^k. * @param pfac extended polynomial ring factory (by i variables in the * coefficients). * @param j index of variable to be used for multiplication. * @param k exponent for x_j. * @return extended polynomial. */ public static > GenSolvablePolynomial> extendCoefficients( GenSolvablePolynomialRing> pfac, GenSolvablePolynomial> A, int j, long k) { GenSolvablePolynomial> Cp = pfac.getZERO().copy(); if (A.isZERO()) { return Cp; } GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; //GenPolynomialRing acfac = (GenPolynomialRing) A.ring.coFac; //int i = cfac.nvar - acfac.nvar; Map> CC = Cp.val; //getMap(); for (Map.Entry> y : A.val.entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); GenPolynomial f = a.extend(cfac, j, k); CC.put(e, f); } return Cp; } /** * To recursive representation. Represent as polynomial in i+r variables * with coefficients in i variables. Works for arbitrary term orders. * @param coefficient type. * @param rfac recursive polynomial ring factory. * @param A polynomial to be converted. * @return Recursive representations of A in the ring rfac. */ public static > GenPolynomial> toRecursive( GenPolynomialRing> rfac, GenPolynomial A) { GenPolynomial> B = rfac.getZERO().copy(); if (A.isZERO()) { return B; } //int i = rfac.nvar; //GenPolynomial zero = rfac.getZEROCoefficient(); GenPolynomial one = rfac.getONECoefficient(); Map> Bv = B.val; //getMap(); for (Monomial m : A) { ExpVector e = m.e; C a = m.c; GenPolynomial p = one.multiply(a); Bv.put(e, p); } return B; } /** * To recursive representation. Represent as solvable polynomial in i+r * variables with coefficients in i variables. Works for arbitrary term * orders. * @param coefficient type. * @param rfac recursive solvable polynomial ring factory. * @param A solvable polynomial to be converted. * @return Recursive representations of A in the ring rfac. */ public static > GenSolvablePolynomial> toRecursive( GenSolvablePolynomialRing> rfac, GenSolvablePolynomial A) { GenSolvablePolynomial> B = rfac.getZERO().copy(); if (A.isZERO()) { return B; } //int i = rfac.nvar; //GenPolynomial zero = rfac.getZEROCoefficient(); GenPolynomial one = rfac.getONECoefficient(); Map> Bv = B.val; //getMap(); for (Monomial m : A) { ExpVector e = m.e; C a = m.c; GenPolynomial p = one.multiply(a); Bv.put(e, p); } return B; } /** * GenPolynomial coefficient wise remainder. * @param coefficient type. * @param P GenPolynomial. * @param s nonzero coefficient. * @return coefficient wise remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial baseRemainderPoly(GenPolynomial P, C s) { if (s == null || s.isZERO()) { throw new ArithmeticException(P + " division by zero " + s); } GenPolynomial h = P.ring.getZERO().copy(); Map hm = h.val; //getMap(); for (Map.Entry m : P.getMap().entrySet()) { ExpVector f = m.getKey(); C a = m.getValue(); C x = a.remainder(s); hm.put(f, x); } return h; } /** * GenPolynomial sparse pseudo remainder. For univariate polynomials. * @param coefficient type. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return remainder with ldcf(S)m' P = quotient * S + remainder. * m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * @deprecated(forRemoval=true) Use * {@link #baseSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)} * instead */ @Deprecated public static > GenPolynomial basePseudoRemainder(GenPolynomial P, GenPolynomial S) { return baseSparsePseudoRemainder(P, S); } /** * GenPolynomial sparse pseudo remainder. For univariate polynomials. * @param coefficient type. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return remainder with ldcf(S)m' P = quotient * S + remainder. * m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial baseSparsePseudoRemainder(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } if (P.isZERO()) { return P; } if (S.isConstant()) { return P.ring.getZERO(); } C c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial r = P; while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); ExpVector fe = f.subtract(e); C x = a.remainder(c); if (x.isZERO()) { C y = a.divide(c); h = S.multiply(y, fe); // coeff a } else { r = r.multiply(c); // coeff ac h = S.multiply(a, fe); // coeff ac } r = r.subtract(h); } else { break; } } return r; } /** * GenPolynomial dense pseudo remainder. For univariate polynomials. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return remainder with ldcf(S)m P = quotient * S + remainder. * m == deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial baseDensePseudoRemainder(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } if (P.isZERO()) { return P; } if (S.isConstant()) { return P.ring.getZERO(); } long m = P.degree(0); long n = S.degree(0); C c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial r = P; for (long i = m; i >= n; i--) { if (r.isZERO()) { return r; } long k = r.degree(0); if (i == k) { ExpVector f = r.leadingExpVector(); C a = r.leadingBaseCoefficient(); f = f.subtract(e); // EVDIF( f, e ); //System.out.println("red div = " + f); r = r.multiply(c); // coeff ac h = S.multiply(a, f); // coeff ac r = r.subtract(h); } else { r = r.multiply(c); } } return r; } /** * GenPolynomial dense pseudo quotient. For univariate polynomials. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return quotient with ldcf(S)m P = quotient * S + remainder. m * == deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial baseDensePseudoQuotient(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } if (P.isZERO()) { return P; } //if (S.degree() <= 0) { // return l^n P; //P.ring.getZERO(); //} long m = P.degree(0); long n = S.degree(0); C c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial q = P.ring.getZERO(); GenPolynomial h; GenPolynomial r = P; for (long i = m; i >= n; i--) { if (r.isZERO()) { return q; } long k = r.degree(0); if (i == k) { ExpVector f = r.leadingExpVector(); C a = r.leadingBaseCoefficient(); f = f.subtract(e); // EVDIF( f, e ); //System.out.println("red div = " + f); r = r.multiply(c); // coeff ac h = S.multiply(a, f); // coeff ac r = r.subtract(h); q = q.multiply(c); q = q.sum(a, f); } else { q = q.multiply(c); r = r.multiply(c); } } return q; } /** * GenPolynomial sparse pseudo divide. For univariate polynomials or exact * division. * @param coefficient type. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return quotient with ldcf(S)m' P = quotient * S + remainder. * m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial basePseudoDivide(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException(this.getClass().getName() // + " univariate polynomials only"); //} if (P.isZERO() || S.isONE()) { return P; } C c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial r = P; GenPolynomial q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); f = f.subtract(e); C x = a.remainder(c); if (x.isZERO()) { C y = a.divide(c); q = q.sum(y, f); h = S.multiply(y, f); // coeff a } else { q = q.multiply(c); q = q.sum(a, f); r = r.multiply(c); // coeff ac h = S.multiply(a, f); // coeff ac } r = r.subtract(h); } else { break; } } return q; } /** * GenPolynomial sparse pseudo quotient and remainder. For univariate * polynomials or exact division. * @param coefficient type. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return [ quotient, remainder ] with ldcf(S)m' P = quotient * * S + remainder. m' ≤ deg(P)-deg(S) * @see edu.jas.poly.GenPolynomial#divide(edu.jas.poly.GenPolynomial). */ @SuppressWarnings("unchecked") public static > GenPolynomial[] basePseudoQuotientRemainder( final GenPolynomial P, final GenPolynomial S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P.toString() + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException(this.getClass().getName() // + " univariate polynomials only"); //} GenPolynomial[] ret = new GenPolynomial[2]; ret[0] = null; ret[1] = null; if (P.isZERO() || S.isONE()) { ret[0] = P; ret[1] = S.ring.getZERO(); return ret; } //logger.debug("P, S = " + P + ", " + S); final C c = S.leadingBaseCoefficient(); final ExpVector e = S.leadingExpVector(); GenPolynomial h; GenPolynomial r = P; GenPolynomial q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { C a = r.leadingBaseCoefficient(); f = f.subtract(e); C x = a.remainder(c); if (x.isZERO()) { C y = a.divide(c); q = q.sum(y, f); h = S.multiply(y, f); // coeff a } else { q = q.multiply(c); q = q.sum(a, f); r = r.multiply(c); // coeff a c h = S.multiply(a, f); // coeff c a } r = r.subtract(h); //logger.debug("q, r = " + q + ", " + r); } else { break; } } //GenPolynomial rhs = q.multiply(S).sum(r); //GenPolynomial lhs = P; ret[0] = q; ret[1] = r; return ret; } /** * Is GenPolynomial pseudo quotient and remainder. For univariate * polynomials. * @param coefficient type. * @param P base GenPolynomial. * @param S nonzero base GenPolynomial. * @return true, if P = q * S + r, else false. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ public static > boolean isBasePseudoQuotientRemainder(GenPolynomial P, GenPolynomial S, GenPolynomial q, GenPolynomial r) { GenPolynomial rhs = q.multiply(S).sum(r); //System.out.println("rhs,1 = " + rhs); GenPolynomial lhs = P; C ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,1 = " + lhs); return true; } lhs = lhs.multiply(ldcf); } GenPolynomial Pp = P; rhs = q.multiply(S); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = Pp.subtract(r); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs) || lhs.negate().equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiply(ldcf); } C a = P.leadingBaseCoefficient(); rhs = q.multiply(S).sum(r); C b = rhs.leadingBaseCoefficient(); C gcd = a.gcd(b); C p = a.multiply(b); C lcm = p.divide(gcd); C ap = lcm.divide(a); C bp = lcm.divide(b); if (P.multiply(ap).equals(rhs.multiply(bp))) { return true; } return false; } /** * GenPolynomial divide. For recursive polynomials. Division by coefficient * ring element. * @param coefficient type. * @param P recursive GenPolynomial. * @param s GenPolynomial. * @return this/s. */ public static > GenPolynomial> recursiveDivide( GenPolynomial> P, GenPolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } GenPolynomial> p = P.ring.getZERO().copy(); SortedMap> pv = p.val; //getMap(); for (Map.Entry> m1 : P.getMap().entrySet()) { GenPolynomial c1 = m1.getValue(); ExpVector e1 = m1.getKey(); GenPolynomial c = PolyUtil. basePseudoDivide(c1, s); if (!c.isZERO()) { pv.put(e1, c); // or m1.setValue( c ) } else { logger.warn("rDiv, P = {}", P); logger.warn("rDiv, c1 = {}", c1); logger.warn("rDiv, s = {}", s); logger.warn("rDiv, c = {}", c); throw new RuntimeException("something is wrong"); } } return p; } /** * GenPolynomial divide. For recursive polynomials. Division by coefficient * ring element. * @param coefficient type. * @param P recursive GenPolynomial. * @param s GenPolynomial. * @return this/s. */ public static > GenWordPolynomial> recursiveDivide( GenWordPolynomial> P, GenPolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } GenWordPolynomial> p = P.ring.getZERO().copy(); SortedMap> pv = p.val; //getMap(); for (Map.Entry> m1 : P.getMap().entrySet()) { GenPolynomial c1 = m1.getValue(); Word e1 = m1.getKey(); GenPolynomial c = PolyUtil. basePseudoDivide(c1, s); if (!c.isZERO()) { pv.put(e1, c); // or m1.setValue( c ) } else { logger.warn("rDiv, P = {}", P); logger.warn("rDiv, c1 = {}", c1); logger.warn("rDiv, s = {}", s); logger.warn("rDiv, c = {}", c); throw new RuntimeException("something is wrong"); } } return p; } /** * GenPolynomial base divide. For recursive polynomials. Division by * coefficient ring element. * @param coefficient type. * @param P recursive GenPolynomial. * @param s coefficient. * @return this/s. */ public static > GenPolynomial> baseRecursiveDivide( GenPolynomial> P, C s) { if (s == null || s.isZERO()) { throw new ArithmeticException("division by zero " + P + ", " + s); } if (P.isZERO()) { return P; } if (s.isONE()) { return P; } GenPolynomial> p = P.ring.getZERO().copy(); SortedMap> pv = p.val; //getMap(); for (Map.Entry> m1 : P.getMap().entrySet()) { GenPolynomial c1 = m1.getValue(); ExpVector e1 = m1.getKey(); GenPolynomial c = PolyUtil. coefficientBasePseudoDivide(c1, s); if (!c.isZERO()) { pv.put(e1, c); // or m1.setValue( c ) } else { logger.warn("pu, c1 = {}", c1); logger.warn("pu, s = {}", s); logger.warn("pu, c = {}", c); throw new RuntimeException("something is wrong"); } } return p; } /** * GenPolynomial sparse pseudo remainder. For recursive polynomials. * @param coefficient type. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return remainder with ldcf(S)m' P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * @deprecated(forRemoval=true) Use * {@link #recursiveSparsePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)} * instead */ @Deprecated public static > GenPolynomial> recursivePseudoRemainder( GenPolynomial> P, GenPolynomial> S) { return recursiveSparsePseudoRemainder(P, S); } /** * GenPolynomial sparse pseudo remainder. For recursive polynomials. * @param coefficient type. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return remainder with ldcf(S)m' P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial> recursiveSparsePseudoRemainder( GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } if (P == null || P.isZERO()) { return P; } if (S.isConstant()) { return P.ring.getZERO(); } GenPolynomial c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial> h; GenPolynomial> r = P; while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { GenPolynomial a = r.leadingBaseCoefficient(); f = f.subtract(e); GenPolynomial x = c; //test basePseudoRemainder(a,c); if (x.isZERO()) { GenPolynomial y = PolyUtil. basePseudoDivide(a, c); h = S.multiply(y, f); // coeff a } else { r = r.multiply(c); // coeff a c h = S.multiply(a, f); // coeff c a } r = r.subtract(h); } else { break; } } return r; } /** * GenPolynomial dense pseudo remainder. For recursive polynomials. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return remainder with ldcf(S)m' P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial> recursiveDensePseudoRemainder( GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } if (P == null || P.isZERO()) { return P; } if (S.isConstant()) { return P.ring.getZERO(); } long m = P.degree(0); long n = S.degree(0); GenPolynomial c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial> h; GenPolynomial> r = P; for (long i = m; i >= n; i--) { if (r.isZERO()) { return r; } long k = r.degree(0); if (i == k) { ExpVector f = r.leadingExpVector(); GenPolynomial a = r.leadingBaseCoefficient(); f = f.subtract(e); //EVDIF( f, e ); //System.out.println("red div = " + f); r = r.multiply(c); // coeff ac h = S.multiply(a, f); // coeff ac r = r.subtract(h); } else { r = r.multiply(c); } } return r; } /** * GenPolynomial recursive pseudo divide. For recursive polynomials. * @param coefficient type. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return quotient with ldcf(S)m' P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial> recursivePseudoDivide( GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { throw new ArithmeticException(P + " division by zero " + S); } //if (S.ring.nvar != 1) { // ok if exact division // throw new RuntimeException(this.getClass().getName() // + " univariate polynomials only"); //} if (P == null || P.isZERO()) { return P; } if (S.isONE()) { return P; } GenPolynomial c = S.leadingBaseCoefficient(); ExpVector e = S.leadingExpVector(); GenPolynomial> h; GenPolynomial> r = P; GenPolynomial> q = S.ring.getZERO().copy(); while (!r.isZERO()) { ExpVector f = r.leadingExpVector(); if (f.multipleOf(e)) { GenPolynomial a = r.leadingBaseCoefficient(); f = f.subtract(e); GenPolynomial x = PolyUtil. baseSparsePseudoRemainder(a, c); if (x.isZERO() && !c.isConstant()) { GenPolynomial y = PolyUtil. basePseudoDivide(a, c); q = q.sum(y, f); h = S.multiply(y, f); // coeff a } else { q = q.multiply(c); q = q.sum(a, f); r = r.multiply(c); // coeff ac h = S.multiply(a, f); // coeff ac } r = r.subtract(h); } else { break; } } return q; } /** * Is recursive GenPolynomial pseudo quotient and remainder. For recursive * polynomials. * @param coefficient type. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return true, if P ~= q * S + r, else false. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * Note: not always meaningful and working */ public static > boolean isRecursivePseudoQuotientRemainder( GenPolynomial> P, GenPolynomial> S, GenPolynomial> q, GenPolynomial> r) { GenPolynomial> rhs = q.multiply(S).sum(r); GenPolynomial> lhs = P; GenPolynomial ldcf = S.leadingBaseCoefficient(); long d = P.degree(0) - S.degree(0) + 1; d = (d > 0 ? d : -d + 2); for (long i = 0; i <= d; i++) { //System.out.println("lhs = " + lhs); //System.out.println("rhs = " + rhs); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { return true; } lhs = lhs.multiply(ldcf); } GenPolynomial> Pp = P; rhs = q.multiply(S); //System.out.println("rhs,2 = " + rhs); for (long i = 0; i <= d; i++) { lhs = Pp.subtract(r); //System.out.println("lhs-rhs = " + lhs.subtract(rhs)); if (lhs.equals(rhs)) { //System.out.println("lhs,2 = " + lhs); return true; } Pp = Pp.multiply(ldcf); } GenPolynomial a = P.leadingBaseCoefficient(); rhs = q.multiply(S).sum(r); GenPolynomial b = rhs.leadingBaseCoefficient(); GenPolynomial> Pb = P.multiply(b); GenPolynomial> rhsa = rhs.multiply(a); if (Pb.equals(rhsa)) { return true; } //System.out.println("b = " + b); //System.out.println("a = " + a); System.out.println("P*b = " + Pb); System.out.println("rhs*a = " + rhsa); if (Pb.degree() != rhsa.degree() || !Pb.leadingBaseCoefficient().equals(rhsa.leadingBaseCoefficient())) { return false; } return false; } /** * GenPolynomial pseudo divide. For recursive polynomials. * @param coefficient type. * @param P recursive GenPolynomial. * @param s nonzero GenPolynomial. * @return quotient with ldcf(s)m P = quotient * s + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial> coefficientPseudoDivide( GenPolynomial> P, GenPolynomial s) { if (s == null || s.isZERO()) { throw new ArithmeticException(P + " division by zero " + s); } if (P.isZERO()) { return P; } GenPolynomial> p = P.ring.getZERO().copy(); SortedMap> pv = p.val; for (Map.Entry> m : P.getMap().entrySet()) { ExpVector e = m.getKey(); GenPolynomial c1 = m.getValue(); GenPolynomial c = basePseudoDivide(c1, s); if (debug) { GenPolynomial x = c1.remainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { //logger.warn("no exact division: {}/{}", c1, s); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } pv.put(e, c); // or m1.setValue( c ) } return p; } /** * GenPolynomial pseudo divide. For polynomials. * @param coefficient type. * @param P GenPolynomial. * @param s nonzero coefficient. * @return quotient with ldcf(s)m P = quotient * s + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). */ public static > GenPolynomial coefficientBasePseudoDivide(GenPolynomial P, C s) { if (s == null || s.isZERO()) { throw new ArithmeticException(P + " division by zero " + s); } if (P.isZERO()) { return P; } GenPolynomial p = P.ring.getZERO().copy(); SortedMap pv = p.val; for (Map.Entry m : P.getMap().entrySet()) { ExpVector e = m.getKey(); C c1 = m.getValue(); C c = c1.divide(s); if (debug) { C x = c1.remainder(s); if (!x.isZERO()) { logger.info("divide x = {}", x); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } } if (c.isZERO()) { //logger.warn("no exact division: {}/{}", c1, s); throw new ArithmeticException("no exact division: " + c1 + "/" + s); } pv.put(e, c); // or m1.setValue( c ) } return p; } /** * GenExteriorPolynomial polynomial exterior derivative. * @param coefficient type. * @param P GenExteriorPolynomial. * @return exteriorDerivative(P). */ public static > GenExteriorPolynomial exteriorDerivative( GenExteriorPolynomial P) { if (P == null || P.isZERO()) { return P; } GenExteriorPolynomialRing pfac = P.ring; IndexFactory ifac = pfac.ixfac; int im = ifac.imaxlength; if (im == 0) { return pfac.getZERO(); } //RingFactory rf = pfac.coFac; GenExteriorPolynomial d = pfac.getZERO().copy(); Map dm = d.val; for (Map.Entry m : P.getMap().entrySet()) { //if (P.length() == 1) { //Map.Entry m = P.leadingMonomial(); C a = m.getValue(); IndexList il = m.getKey(); C b; IndexList bi; for (int i = 1; i <= im; i++) { IndexList di = new IndexList(ifac, new int[] { i }); bi = di.multiply(il); if (bi.signum() == 0) { continue; } b = a; // b = a.derivative(); if (bi.signum() < 0) { bi = bi.negate(); b = b.negate(); } dm.put(bi, b); } } return d; } /** * GenExteriorPolynomial over polynomial exterior derivative. * @param coefficient type. * @param P GenExteriorPolynomial. * @return exteriorDerivativePoly(P). */ public static > GenExteriorPolynomial> exteriorDerivativePoly( GenExteriorPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenExteriorPolynomialRing> pfac = P.ring; IndexFactory ifac = pfac.ixfac; int im = ifac.imaxlength; if (im == 0) { return pfac.getZERO(); } //RingFactory> rf = pfac.coFac; GenExteriorPolynomial> d = pfac.getZERO().copy(); Map> dm = d.val; for (Map.Entry> m : P.getMap().entrySet()) { //if (P.length() == 1) { //Map.Entry m = P.leadingMonomial(); GenPolynomial a = m.getValue(); IndexList il = m.getKey(); GenPolynomial b; IndexList bi; for (int i = 1; i <= im; i++) { IndexList di = new IndexList(ifac, new int[] { i }); bi = di.multiply(il); if (bi.signum() == 0) { continue; } b = PolyUtil. baseDerivative(a, i - 1); //a.derivative(); //System.out.println("baseDerivative a = " + a + ", i-1 = " + (i-1) + ", b = " + b); if (b.isZERO()) { continue; } if (bi.signum() < 0) { bi = bi.negate(); b = b.negate(); } dm.put(bi, b); } } return d; } /** * GenPolynomial polynomial derivative main variable. * @param coefficient type. * @param P GenPolynomial. * @return derivative(P). */ public static > GenPolynomial baseDerivative(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 0) { return pfac.getZERO(); } if (pfac.nvar > 1) { // baseContent not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory rf = pfac.coFac; GenPolynomial d = pfac.getZERO().copy(); Map dm = d.val; //getMap(); for (Map.Entry m : P.getMap().entrySet()) { ExpVector f = m.getKey(); long fl = f.getVal(0); if (fl > 0) { C cf = rf.fromInteger(fl); C a = m.getValue(); C x = a.multiply(cf); if (x != null && !x.isZERO()) { ExpVector e = ExpVector.create(1, 0, fl - 1L); dm.put(e, x); } } } return d; } /** * GenPolynomial polynomial partial derivative variable r. * @param coefficient type. * @param P GenPolynomial. * @param r variable for partial deriviate. * @return derivative(P,r). */ public static > GenPolynomial baseDerivative(GenPolynomial P, int r) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (r < 0 || pfac.nvar <= r) { throw new IllegalArgumentException( P.getClass().getName() + " derivative variable out of bound " + r); } int rp = pfac.nvar - 1 - r; RingFactory rf = pfac.coFac; GenPolynomial d = pfac.getZERO().copy(); Map dm = d.val; //getMap(); for (Map.Entry m : P.getMap().entrySet()) { ExpVector f = m.getKey(); long fl = f.getVal(rp); if (fl > 0) { C cf = rf.fromInteger(fl); C a = m.getValue(); C x = a.multiply(cf); if (x != null && !x.isZERO()) { ExpVector e = f.subst(rp, fl - 1L); dm.put(e, x); } } } return d; } /** * GenPolynomial polynomial integral main variable. * @param coefficient type. * @param P GenPolynomial. * @return integral(P). */ public static > GenPolynomial baseIntegral(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 0) { return pfac.getONE(); } if (pfac.nvar > 1) { // baseContent not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory rf = pfac.coFac; GenPolynomial d = pfac.getZERO().copy(); Map dm = d.val; //getMap(); for (Map.Entry m : P.getMap().entrySet()) { ExpVector f = m.getKey(); long fl = f.getVal(0); fl++; C cf = rf.fromInteger(fl); C a = m.getValue(); C x = a.divide(cf); if (x != null && !x.isZERO()) { ExpVector e = ExpVector.create(1, 0, fl); dm.put(e, x); } } return d; } /** * GenPolynomial recursive polynomial derivative main variable. * @param coefficient type. * @param P recursive GenPolynomial. * @return derivative(P). */ public static > GenPolynomial> recursiveDerivative( GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar == 0) { return pfac.getZERO(); } if (pfac.nvar > 1) { // baseContent not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } GenPolynomialRing pr = (GenPolynomialRing) pfac.coFac; RingFactory rf = pr.coFac; GenPolynomial> d = pfac.getZERO().copy(); Map> dm = d.val; //getMap(); for (Map.Entry> m : P.getMap().entrySet()) { ExpVector f = m.getKey(); long fl = f.getVal(0); if (fl > 0) { C cf = rf.fromInteger(fl); GenPolynomial a = m.getValue(); GenPolynomial x = a.multiply(cf); if (x != null && !x.isZERO()) { ExpVector e = ExpVector.create(1, 0, fl - 1L); dm.put(e, x); } } } return d; } /** * Factor coefficient bound. The product of all maxNorms of potential * factors is less than or equal to 2**b times the maxNorm of A. Gelfonds * bound is used. * @param e degree vector of a GenPolynomial A. * @return 2**b. * @see "maspoly.SACIPOL.mi#IPFCB from SAC2/MAS" */ public static BigInteger factorBound(ExpVector e) { long n = 0; java.math.BigInteger p = java.math.BigInteger.ONE; java.math.BigInteger v; if (e == null || e.isZERO()) { return BigInteger.ONE; } for (int i = 0; i < e.length(); i++) { if (e.getVal(i) > 0L) { n += (2 * e.getVal(i) - 1); v = new java.math.BigInteger("" + (e.getVal(i) - 1)); p = p.multiply(v); } } n += (p.bitCount() + 1); // log2(p) n /= 2; v = new java.math.BigInteger("" + 2); while (n >= 16) { n -= 16; v = v.shiftLeft(16); } if (n > 0) { v = v.shiftLeft((int) n); // n < 16 } BigInteger N = new BigInteger(v); return N; } /** * Absolute norm. Square root of the sum of the squared coefficients. * @param p GenPolynomial * @return sqrt( sumi |ci|2 ). */ @SuppressWarnings("unchecked") public static > C absNorm(GenPolynomial p) { if (p == null) { return null; } C a = p.ring.getZEROCoefficient(); if (a instanceof StarRingElem) { //System.out.println("StarRingElem case"); for (C c : p.val.values()) { C n = (C) ((StarRingElem) c).norm(); a = a.sum(n); } } else { for (C c : p.val.values()) { C n = c.multiply(c); a = a.sum(n); } } // compute square root if possible // refactor for sqrt in RingElem ? if (a instanceof BigRational) { BigRational b = (BigRational) a; a = (C) Roots.sqrt(b); } else if (a instanceof BigComplex) { BigComplex b = (BigComplex) a; a = (C) Roots.sqrt(b); } else if (a instanceof BigInteger) { BigInteger b = (BigInteger) a; a = (C) Roots.sqrt(b); } else if (a instanceof BigDecimal) { BigDecimal b = (BigDecimal) a; a = (C) Roots.sqrt(b); } else if (a instanceof BigDecimalComplex) { BigDecimalComplex b = (BigDecimalComplex) a; a = (C) Roots.sqrt(b); } else { logger.error("no square root implemented for {}", a.toScriptFactory()); } return a; } /** * Polynomial reciprocal transformation. * @param coefficient type. * @param A is a non-zero polynomial, with n=DEG(A). * @return B with B(x) = x**n*A(1/x), where x is the main variable of A. * @see "maspoly.SACPOL.mi#PRT from SAC2/MAS" */ public static > GenPolynomial reciprocalTransformation(GenPolynomial A) { return reciprocalTransformation(A, 0); } /** * Polynomial reciprocal transformation. * @param coefficient type. * @param A is a non-zero polynomial, with n=DEG(A,i), A(x_r, ..., x_0). * @param i variable to be transformed, 0 is the main variable. * @return B with B(x) = x_i**n*A(1/x_i), where x_i is the i-th variable of * A. * @see "maspoly.SACPOL.mi#PRT from SAC2/MAS" */ public static > GenPolynomial reciprocalTransformation(GenPolynomial A, int i) { if (A == null) { return null; } GenPolynomialRing pfac = A.ring; GenPolynomial B = pfac.getZERO().copy(); if (A.isZERO()) { return B; } int m = i; long d = A.degree(m); //System.out.println("d = " + d + ", m = " + m); Map val = A.val; Map valb = B.val; for (Map.Entry me : val.entrySet()) { ExpVector e = me.getKey(); long de = d - e.getVal(m); ExpVector f = e.subst(m, de); C c = me.getValue(); valb.put(f, c); } return B; } /** * Polynomial translation, main variable. * @param coefficient type. * @param A is a non-zero polynomial in r variables, A(x_1, ..., x(r-1), * x_r). * @param h is a coefficient ring element. * @return B with B(x1, ..., x(r-1), xr) = A(x1, ..., x(r-1), xr+h). * @see "maspoly.SACIPOL.mi#IPTRAN from SAC2/MAS" */ public static > GenPolynomial translationMain(GenPolynomial A, C h) { if (A == null) { return null; } if (A.isZERO() || h.isZERO()) { return A; } GenPolynomialRing pfac = A.ring; GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Ar = recursive(rfac, A); GenPolynomial> Br = translationMainRecursive(Ar, h); GenPolynomial B = distribute(pfac, Br); return B; } /** * Polynomial translation, main variable. * @param coefficient type. * @param A is a non-zero recursive polynomial in r variables, A(x_1, ..., * x(r-1))(x_r). * @param h is a coefficient ring element. * @return B with B(x1, ..., x(r-1))(xr) = A(x1, ..., x(r-1))(xr+h). * @see "maspoly.SACIPOL.mi#IPTRAN from SAC2/MAS" */ public static > GenPolynomial> translationMainRecursive( GenPolynomial> A, C h) { if (A == null) { return null; } GenPolynomialRing> pfac = A.ring; if (pfac.nvar != 1) { throw new IllegalArgumentException("translationMainRecursive no univariate polynomial"); } if (A.isZERO() || h.isZERO()) { return A; } // assert descending exponents, i.e. compatible term order Map> val = A.val; GenPolynomial> c = null; ExpVector z = pfac.evzero; ExpVector x = pfac.evzero.subst(0, 1L); GenPolynomial H = pfac.getONECoefficient().multiply(h); long el1 = -1; // undefined long el2 = -1; for (Map.Entry> me : val.entrySet()) { ExpVector e = me.getKey(); el2 = e.getVal(0); GenPolynomial b = me.getValue(); if (c == null) { c = pfac.valueOf(b, z); } else { for (long i = el2; i < el1; i++) { // i = 0, el1-el2. GenPolynomial> d1 = c.multiply(x); GenPolynomial> d2 = c.multiply(H); c = d1.sum(d2); } c = c.sum(b); } el1 = el2; } for (long i = 0; i < el2; i++) { GenPolynomial> d1 = c.multiply(x); GenPolynomial> d2 = c.multiply(H); c = d1.sum(d2); } return c; } /** * Polynomial translation, base univariate. * @param coefficient type. * @param A is a non-zero polynomial in 1 variables, A(x_1). * @param h is a coefficient ring element. * @return B with B(x1) = A(x1+h1). * @see "maspoly.SACIPOL.mi#IPTRAN from SAC2/MAS" */ public static > GenPolynomial translationBase(GenPolynomial A, C h) { if (A == null) { return null; } GenPolynomialRing pfac = A.ring; if (pfac.nvar != 1) { throw new IllegalArgumentException("translationBase no univariate polynomial"); } if (A.isZERO()) { return A; } // assert descending exponents, i.e. compatible term order Map val = A.val; GenPolynomial c = null; ExpVector z = pfac.evzero; ExpVector x = pfac.evzero.subst(0, 1L); long el1 = -1; // undefined long el2 = -1; for (Map.Entry me : val.entrySet()) { ExpVector e = me.getKey(); el2 = e.getVal(0); C b = me.getValue(); if (c == null) { c = pfac.valueOf(b, z); } else { for (long i = el2; i < el1; i++) { // i = 0, el1-el2. GenPolynomial d1 = c.multiply(x); GenPolynomial d2 = c.multiply(h); c = d1.sum(d2); } c = c.sum(b); } el1 = el2; } for (long i = 0; i < el2; i++) { GenPolynomial d1 = c.multiply(x); GenPolynomial d2 = c.multiply(h); c = d1.sum(d2); } return c; } /** * Polynomial translation, all variables. * @param coefficient type. * @param A is a non-zero polynomial in r variables, A(x_1, ..., x(r-1), * x_r). * @param H is a list of coefficient ring elements H = (h1, ..., hr). * @return B with B(x1, ..., x(r-1), xr) = A(x1+h1, ..., x(r-1)+h(r-1), * xr+hr). * @see "maspoly.SACIPOL.mi#IPTRAN from SAC2/MAS" */ public static > GenPolynomial translation(GenPolynomial A, List H) { if (A == null) { return null; } if (A.isZERO()) { return A; } GenPolynomialRing pfac = A.ring; if (pfac.nvar <= 1) { return translationBase(A, H.get(0)); } if (H == null || pfac.nvar != H.size()) { throw new IllegalArgumentException( "number of translation points do not match number of variables " + pfac.nvar + " != " + H.size()); } C h = H.get(0); List L = H.subList(1, H.size()); GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Ar = recursive(rfac, A); GenPolynomial> Br = translationMainRecursive(Ar, h); GenPolynomial> Cr = rfac.getZERO().copy(); Map> val = Br.val; Map> cval = Cr.val; for (Map.Entry> me : val.entrySet()) { ExpVector e = me.getKey(); GenPolynomial b = me.getValue(); GenPolynomial c = translation(b, L); cval.put(e, c); } GenPolynomial B = distribute(pfac, Cr); return B; } /** * Polynomial translation, r-1 variables. * @param coefficient type. * @param A is a non-zero polynomial in r variables, A(x_1, ..., x(r-1), * x_r). * @param H is a list of coefficient ring elements H = (h2, ..., hr). * @return B with B(x1, ..., x(r-1), xr) = A(x1, x2+h2, ..., x(r-1)+h(r-1), * xr+hr). * @see "maspoly.SACIPOL.mi#IPTRAN from SAC2/MAS" */ public static > GenPolynomial translation1(GenPolynomial A, List H) { if (A == null) { return null; } if (A.isZERO()) { return A; } GenPolynomialRing pfac = A.ring; if (pfac.nvar <= 1) { return A; //translationBase(A, H.get(0)); } if (H == null || pfac.nvar - 1 != H.size()) { throw new IllegalArgumentException( "number of translation points do not match number of variables " + (pfac.nvar - 1) + " != " + H.size()); } C h = H.get(0); List L = H.subList(1, H.size()); GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Ar = recursive(rfac, A); GenPolynomial> Br = translationMainRecursive(Ar, h); GenPolynomial> Cr = rfac.getZERO().copy(); Map> val = Br.val; Map> cval = Cr.val; for (Map.Entry> me : val.entrySet()) { ExpVector e = me.getKey(); GenPolynomial b = me.getValue(); GenPolynomial c = translation1(b, L); cval.put(e, c); } GenPolynomial B = distribute(pfac, Cr); return B; } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient polynomial ring factory. * @param A recursive polynomial to be evaluated. * @param a value to evaluate at. * @return A( x_1, ..., x_{n-1}, a ). */ public static > GenPolynomial evaluateMainRecursive(GenPolynomialRing cfac, GenPolynomial> A, C a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } if (A.ring.nvar != 1) { throw new IllegalArgumentException("evaluateMain no univariate polynomial"); } if (a == null || a.isZERO()) { return A.trailingBaseCoefficient(); } // assert descending exponents, i.e. compatible term order Map> val = A.getMap(); GenPolynomial B = null; long el1 = -1; // undefined long el2 = -1; for (Map.Entry> me : val.entrySet()) { ExpVector e = me.getKey(); el2 = e.getVal(0); if (B == null /*el1 < 0*/) { // first turn B = me.getValue(); } else { for (long i = el2; i < el1; i++) { B = B.multiply(a); } B = B.sum(me.getValue()); } el1 = el2; } for (long i = 0; i < el2; i++) { B = B.multiply(a); } return B; } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient polynomial ring factory. * @param A distributed polynomial to be evaluated. * @param a value to evaluate at. * @return A( x_1, ..., x_{n-1}, a ). */ public static > GenPolynomial evaluateMain(GenPolynomialRing cfac, GenPolynomial A, C a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } GenPolynomialRing> rfac = A.ring.recursive(1); if (rfac.nvar + cfac.nvar != A.ring.nvar) { throw new IllegalArgumentException("evaluateMain number of variables mismatch"); } GenPolynomial> Ap = recursive(rfac, A); return PolyUtil. evaluateMainRecursive(cfac, Ap, a); } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient ring factory. * @param L list of univariate polynomials to be evaluated. * @param a value to evaluate at. * @return list( A( x_1, ..., x_{n-1}, a ) ) for A in L. */ public static > List> evaluateMain(GenPolynomialRing cfac, List> L, C a) { return ListUtil., GenPolynomial> map(L, new EvalMainPol(cfac, a)); } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient ring factory. * @param A univariate polynomial to be evaluated. * @param a value to evaluate at. * @return A( a ). */ public static > C evaluateMain(RingFactory cfac, GenPolynomial A, C a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } if (A.ring.nvar != 1) { throw new IllegalArgumentException("evaluateMain no univariate polynomial"); } if (a == null || a.isZERO()) { return A.trailingBaseCoefficient(); } // assert decreasing exponents, i.e. compatible term order Map val = A.getMap(); C B = null; long el1 = -1; // undefined long el2 = -1; for (Map.Entry me : val.entrySet()) { ExpVector e = me.getKey(); el2 = e.getVal(0); if (B == null /*el1 < 0*/) { // first turn B = me.getValue(); } else { for (long i = el2; i < el1; i++) { B = B.multiply(a); } B = B.sum(me.getValue()); } el1 = el2; } for (long i = 0; i < el2; i++) { B = B.multiply(a); } return B; } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient ring factory. * @param L list of univariate polynomial to be evaluated. * @param a value to evaluate at. * @return list( A( a ) ) for A in L. */ public static > List evaluateMain(RingFactory cfac, List> L, C a) { return ListUtil., C> map(L, new EvalMain(cfac, a)); } /** * Evaluate at k-th variable. * @param coefficient type. * @param cfac coefficient polynomial ring in k variables C[x_1, ..., x_k] * factory. * @param rfac coefficient polynomial ring C[x_1, ..., x_{k-1}] [x_k] * factory, a recursive polynomial ring in 1 variable with * coefficients in k-1 variables. * @param nfac polynomial ring in n-1 variables C[x_1, ..., x_{k-1}] * [x_{k+1}, ..., x_n] factory, a recursive polynomial ring in * n-k+1 variables with coefficients in k-1 variables. * @param dfac polynomial ring in n-1 variables. C[x_1, ..., x_{k-1}, * x_{k+1}, ..., x_n] factory. * @param A polynomial to be evaluated. * @param a value to evaluate at. * @return A( x_1, ..., x_{k-1}, a, x_{k+1}, ..., x_n). */ public static > GenPolynomial evaluate(GenPolynomialRing cfac, GenPolynomialRing> rfac, GenPolynomialRing> nfac, GenPolynomialRing dfac, GenPolynomial A, C a) { if (rfac.nvar != 1) { throw new IllegalArgumentException("evaluate coefficient ring not univariate"); } if (A == null || A.isZERO()) { return cfac.getZERO(); } Map> Ap = A.contract(cfac); GenPolynomialRing rcf = (GenPolynomialRing) rfac.coFac; GenPolynomial> Ev = nfac.getZERO().copy(); Map> Evm = Ev.val; //getMap(); for (Map.Entry> m : Ap.entrySet()) { ExpVector e = m.getKey(); GenPolynomial b = m.getValue(); GenPolynomial> c = recursive(rfac, b); GenPolynomial d = evaluateMainRecursive(rcf, c, a); if (d != null && !d.isZERO()) { Evm.put(e, d); } } GenPolynomial B = distribute(dfac, Ev); return B; } /** * Evaluate at first (lowest) variable. * @param coefficient type. * @param cfac coefficient polynomial ring in first variable C[x_1] factory. * @param dfac polynomial ring in n-1 variables. C[x_2, ..., x_n] factory. * @param A polynomial to be evaluated. * @param a value to evaluate at. * @return A( a, x_2, ..., x_n). */ public static > GenPolynomial evaluateFirst(GenPolynomialRing cfac, GenPolynomialRing dfac, GenPolynomial A, C a) { if (A == null || A.isZERO()) { return dfac.getZERO(); } Map> Ap = A.contract(cfac); //RingFactory rcf = cfac.coFac; // == dfac.coFac GenPolynomial B = dfac.getZERO().copy(); Map Bm = B.val; //getMap(); for (Map.Entry> m : Ap.entrySet()) { ExpVector e = m.getKey(); GenPolynomial b = m.getValue(); C d = evaluateMain(cfac.coFac, b, a); if (d != null && !d.isZERO()) { Bm.put(e, d); } } return B; } /** * Evaluate at first (lowest) variable. Could also be called * evaluateFirst(), but type erasure of parameter * A does not allow the same name. * @param coefficient type. * @param cfac coefficient polynomial ring in first variable C[x_1] factory. * @param dfac polynomial ring in n-1 variables. C[x_2, ..., x_n] factory. * @param A recursive polynomial to be evaluated. * @param a value to evaluate at. * @return A( a, x_2, ..., x_n). */ public static > GenPolynomial evaluateFirstRec(GenPolynomialRing cfac, GenPolynomialRing dfac, GenPolynomial> A, C a) { if (A == null || A.isZERO()) { return dfac.getZERO(); } Map> Ap = A.getMap(); GenPolynomial B = dfac.getZERO().copy(); Map Bm = B.val; //getMap(); for (Map.Entry> m : Ap.entrySet()) { ExpVector e = m.getKey(); GenPolynomial b = m.getValue(); C d = evaluateMain(cfac.coFac, b, a); if (d != null && !d.isZERO()) { Bm.put(e, d); } } return B; } /** * Evaluate all variables. * @param coefficient type. * @param cfac coefficient ring factory. * @param L list of polynomials to be evaluated. * @param a = (a_1, a_2, ..., a_n) a tuple of values to evaluate at. * @return L = ( A_1(a_1, a_2, ..., a_n), ... A_k(a_1, a_2, ..., a_n)). */ public static > List evaluateAll(RingFactory cfac, List> L, List a) { return ListUtil., C> map(L, new EvalAllPol(cfac, a)); } /** * Evaluate all variables. * @param coefficient type. * @param cfac coefficient ring factory. * @param A polynomial to be evaluated. * @param a = (a_1, a_2, ..., a_n) a tuple of values to evaluate at. * @return A(a_1, a_2, ..., a_n). */ public static > C evaluateAll(RingFactory cfac, GenPolynomial A, List a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } GenPolynomialRing dfac = A.ring; if (a == null || a.size() != dfac.nvar) { throw new IllegalArgumentException("evaluate tuple size not equal to number of variables"); } if (dfac.nvar == 0) { return A.trailingBaseCoefficient(); } if (dfac.nvar == 1) { return evaluateMain(cfac, A, a.get(0)); } C b = cfac.getZERO(); GenPolynomial Ap = A; for (int k = 0; k < dfac.nvar - 1; k++) { C ap = a.get(k); GenPolynomialRing c1fac = new GenPolynomialRing(cfac, 1); // no vars GenPolynomialRing cnfac = new GenPolynomialRing(cfac, dfac.nvar - 1 - k); // no vars GenPolynomial Bp = evaluateFirst(c1fac, cnfac, Ap, ap); if (Bp.isZERO()) { return b; } Ap = Bp; //System.out.println("Ap = " + Ap); } C ap = a.get(dfac.nvar - 1); b = evaluateMain(cfac, Ap, ap); return b; } /** * Substitute main variable. * @param A univariate polynomial. * @param s polynomial for substitution. * @return polynomial A(x <- s). */ public static > GenPolynomial substituteMain(GenPolynomial A, GenPolynomial s) { return substituteUnivariate(A, s); } /** * Substitute univariate polynomial. * @param f univariate polynomial. * @param t polynomial for substitution. * @return polynomial f(x <- t). */ public static > GenPolynomial substituteUnivariate(GenPolynomial f, GenPolynomial t) { if (f == null || t == null) { return null; } GenPolynomialRing fac = f.ring; if (fac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomial f"); } if (f.isZERO() || f.isConstant()) { return f; } if (t.ring.nvar > 1) { fac = t.ring; } // assert descending exponents, i.e. compatible term order Map val = f.getMap(); GenPolynomial s = null; long el1 = -1; // undefined long el2 = -1; for (Map.Entry me : val.entrySet()) { ExpVector e = me.getKey(); el2 = e.getVal(0); if (s == null /*el1 < 0*/) { // first turn s = fac.getZERO().sum(me.getValue()); } else { for (long i = el2; i < el1; i++) { s = s.multiply(t); } s = s.sum(me.getValue()); } el1 = el2; } for (long i = 0; i < el2; i++) { s = s.multiply(t); } //System.out.println("s = " + s); return s; } /** * Substitute univariate polynomial with multivariate coefficients. * @param f univariate polynomial with multivariate coefficients. * @param t polynomial for substitution. * @return polynomial f(x <- t). */ public static > GenPolynomial substituteUnivariateMult(GenPolynomial f, GenPolynomial t) { if (f == null || t == null) { return null; } GenPolynomialRing fac = f.ring; if (fac.nvar == 1) { return substituteUnivariate(f, t); } GenPolynomialRing> rfac = fac.recursive(1); GenPolynomial> fr = PolyUtil. recursive(rfac, f); GenPolynomial> tr = PolyUtil. recursive(rfac, t); //System.out.println("fr = " + fr); //System.out.println("tr = " + tr); GenPolynomial> sr = PolyUtil.> substituteUnivariate(fr, tr); //System.out.println("sr = " + sr); GenPolynomial s = PolyUtil. distribute(fac, sr); return s; } /** * Taylor series for polynomial. * @param f univariate polynomial. * @param a expansion point. * @return Taylor series (a polynomial) of f at a. */ public static > GenPolynomial seriesOfTaylor(GenPolynomial f, C a) { if (f == null) { return null; } GenPolynomialRing fac = f.ring; if (fac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } if (f.isZERO() || f.isConstant()) { return f; } GenPolynomial s = fac.getZERO(); C fa = PolyUtil. evaluateMain(fac.coFac, f, a); s = s.sum(fa); long n = 1; long i = 0; GenPolynomial g = PolyUtil. baseDerivative(f); //GenPolynomial p = fac.getONE(); while (!g.isZERO()) { i++; n *= i; fa = PolyUtil. evaluateMain(fac.coFac, g, a); GenPolynomial q = fac.univariate(0, i); //p; q = q.multiply(fa); q = q.divide(fac.fromInteger(n)); s = s.sum(q); g = PolyUtil. baseDerivative(g); } //System.out.println("s = " + s); return s; } /** * ModInteger interpolate on first variable. * @param coefficient type. * @param fac GenPolynomial result factory. * @param A GenPolynomial. * @param M GenPolynomial interpolation modul of A. * @param mi inverse of M(am) in ring fac.coFac. * @param B evaluation of other GenPolynomial. * @param am evaluation point (interpolation modul) of B, i.e. P(am) = B. * @return S, with S mod M == A and S(am) == B. */ public static > GenPolynomial> interpolate( GenPolynomialRing> fac, GenPolynomial> A, GenPolynomial M, C mi, GenPolynomial B, C am) { GenPolynomial> S = fac.getZERO().copy(); GenPolynomial> Ap = A.copy(); SortedMap> av = Ap.val; //getMap(); SortedMap bv = B.getMap(); SortedMap> sv = S.val; //getMap(); GenPolynomialRing cfac = (GenPolynomialRing) fac.coFac; RingFactory bfac = cfac.coFac; GenPolynomial c = null; for (Map.Entry me : bv.entrySet()) { ExpVector e = me.getKey(); C y = me.getValue(); //bv.get(e); // assert y != null GenPolynomial x = av.get(e); if (x != null) { av.remove(e); c = PolyUtil. interpolate(cfac, x, M, mi, y, am); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); } } else { c = PolyUtil. interpolate(cfac, cfac.getZERO(), M, mi, y, am); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); // c != null } } } // assert bv is empty = done for (Map.Entry> me : av.entrySet()) { // rest of av ExpVector e = me.getKey(); GenPolynomial x = me.getValue(); //av.get(e); // assert x != null c = PolyUtil. interpolate(cfac, x, M, mi, bfac.getZERO(), am); if (!c.isZERO()) { // 0 cannot happen sv.put(e, c); // c != null } } return S; } /** * Univariate polynomial interpolation. * @param coefficient type. * @param fac GenPolynomial result factory. * @param A GenPolynomial. * @param M GenPolynomial interpolation modul of A. * @param mi inverse of M(am) in ring fac.coFac. * @param a evaluation of other GenPolynomial. * @param am evaluation point (interpolation modul) of a, i.e. P(am) = a. * @return S, with S mod M == A and S(am) == a. */ public static > GenPolynomial interpolate(GenPolynomialRing fac, GenPolynomial A, GenPolynomial M, C mi, C a, C am) { GenPolynomial s; C b = PolyUtil. evaluateMain(fac.coFac, A, am); // A mod a.modul C d = a.subtract(b); // a-A mod a.modul if (d.isZERO()) { return A; } b = d.multiply(mi); // b = (a-A)*mi mod a.modul // (M*b)+A mod M = A mod M = // (M*mi*(a-A)+A) mod a.modul = a mod a.modul s = M.multiply(b); s = s.sum(A); return s; } /** * Recursive GenPolynomial switch variable blocks. * @param coefficient type. * @param P recursive GenPolynomial in R[X,Y]. * @return this in R[Y,X]. */ public static > GenPolynomial> switchVariables( GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException("P == null"); } GenPolynomialRing> rfac1 = P.ring; GenPolynomialRing cfac1 = (GenPolynomialRing) rfac1.coFac; GenPolynomialRing cfac2 = new GenPolynomialRing(cfac1.coFac, rfac1); GenPolynomial zero = cfac2.getZERO(); GenPolynomialRing> rfac2 = new GenPolynomialRing>(cfac2, cfac1); GenPolynomial> B = rfac2.getZERO().copy(); if (P.isZERO()) { return B; } for (Monomial> mr : P) { GenPolynomial cr = mr.c; for (Monomial mc : cr) { GenPolynomial c = zero.sum(mc.c, mr.e); B = B.sum(c, mc.e); } } return B; } /** * Maximal degree of leading terms of a polynomial list. * @return maximum degree of the leading terms of a polynomial list. */ public static > long totalDegreeLeadingTerm(List> P) { long degree = 0; for (GenPolynomial g : P) { long total = g.leadingExpVector().totalDeg(); if (degree < total) { degree = total; } } return degree; } /** * Total degree of polynomial list. * @return total degree of the polynomial list. */ public static > long totalDegree(List> P) { long degree = 0; for (GenPolynomial g : P) { long total = g.totalDegree(); if (degree < total) { degree = total; } } return degree; } /** * Maximal degree of polynomial list. * @return maximal degree of the polynomial list. */ public static > long maxDegree(List> P) { long degree = 0; for (GenPolynomial g : P) { long total = g.degree(); if (degree < total) { degree = total; } } return degree; } /** * Maximal degree in the coefficient polynomials. * @param coefficient type. * @return maximal degree in the coefficients. */ public static > long coeffMaxDegree(GenPolynomial> A) { if (A.isZERO()) { return 0; // 0 or -1 ?; } long deg = 0; for (GenPolynomial a : A.getMap().values()) { long d = a.degree(); if (d > deg) { deg = d; } } return deg; } /** * Map a unary function to the coefficients. * @param ring result polynomial ring factory. * @param p polynomial. * @param f evaluation functor. * @return new polynomial with coefficients f(p(e)). */ public static , D extends RingElem> GenPolynomial map( GenPolynomialRing ring, GenPolynomial p, UnaryFunctor f) { GenPolynomial n = ring.getZERO().copy(); SortedMap nv = n.val; for (Monomial m : p) { D c = f.eval(m.c); if (c != null && !c.isZERO()) { nv.put(m.e, c); } } return n; } /** * Product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param L list of polynomials to be represented. * @return Product representation of L in the polynomial ring pfac. */ public static > List>> toProductGen( GenPolynomialRing> pfac, List> L) { List>> list = new ArrayList>>(); if (L == null || L.size() == 0) { return list; } for (GenPolynomial a : L) { GenPolynomial> b = toProductGen(pfac, a); list.add(b); } return list; } /** * Product representation. * @param coefficient type. * @param pfac polynomial ring factory. * @param A polynomial to be represented. * @return Product representation of A in the polynomial ring pfac. */ public static > GenPolynomial> toProductGen( GenPolynomialRing> pfac, GenPolynomial A) { GenPolynomial> P = pfac.getZERO().copy(); if (A == null || A.isZERO()) { return P; } RingFactory> rpfac = pfac.coFac; ProductRing rfac = (ProductRing) rpfac; for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); Product p = toProductGen(rfac, a); if (!p.isZERO()) { P.doPutToMap(e, p); } } return P; } /** * Product representation. * @param coefficient type. * @param pfac product ring factory. * @param c coefficient to be represented. * @return Product representation of c in the ring pfac. */ public static > Product toProductGen(ProductRing pfac, C c) { SortedMap elem = new TreeMap(); for (int i = 0; i < pfac.length(); i++) { RingFactory rfac = pfac.getFactory(i); C u = rfac.copy(c); if (u != null && !u.isZERO()) { elem.put(i, u); } } return new Product(pfac, elem); } /** * Product representation. * @param coefficient type. * @param pfac product polynomial ring factory. * @param c coefficient to be used. * @param e exponent vector. * @return Product representation of c X^e in the ring pfac. */ public static > Product> toProduct( ProductRing> pfac, C c, ExpVector e) { SortedMap> elem = new TreeMap>(); for (int i = 0; i < e.length(); i++) { RingFactory> rfac = pfac.getFactory(i); GenPolynomialRing fac = (GenPolynomialRing) rfac; //GenPolynomialRing cfac = fac.ring; long a = e.getVal(i); GenPolynomial u; if (a == 0) { u = fac.getONE(); } else { u = fac.univariate(0, a); } u = u.multiply(c); elem.put(i, u); } return new Product>(pfac, elem); } /** * Product representation. * @param coefficient type. * @param pfac product polynomial ring factory. * @param A polynomial. * @return Product representation of the terms of A in the ring pfac. */ public static > Product> toProduct( ProductRing> pfac, GenPolynomial A) { Product> P = pfac.getZERO(); if (A == null || A.isZERO()) { return P; } for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); Product> p = toProduct(pfac, a, e); P = P.sum(p); } return P; } /** * Product representation. * @param pfac product ring factory. * @param c coefficient to be represented. * @return Product representation of c in the ring pfac. */ public static Product toProduct(ProductRing pfac, BigInteger c) { SortedMap elem = new TreeMap(); for (int i = 0; i < pfac.length(); i++) { RingFactory rfac = pfac.getFactory(i); ModIntegerRing fac = (ModIntegerRing) rfac; ModInteger u = fac.fromInteger(c.getVal()); if (!u.isZERO()) { elem.put(i, u); } } return new Product(pfac, elem); } /** * Product representation. * @param pfac polynomial ring factory. * @param A polynomial to be represented. * @return Product representation of A in the polynomial ring pfac. */ public static GenPolynomial> toProduct(GenPolynomialRing> pfac, GenPolynomial A) { GenPolynomial> P = pfac.getZERO().copy(); if (A == null || A.isZERO()) { return P; } RingFactory> rpfac = pfac.coFac; ProductRing fac = (ProductRing) rpfac; for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); BigInteger a = y.getValue(); Product p = toProduct(fac, a); if (!p.isZERO()) { P.doPutToMap(e, p); } } return P; } /** * Product representation. * @param pfac polynomial ring factory. * @param L list of polynomials to be represented. * @return Product representation of L in the polynomial ring pfac. */ public static List>> toProduct( GenPolynomialRing> pfac, List> L) { List>> list = new ArrayList>>(); if (L == null || L.size() == 0) { return list; } for (GenPolynomial a : L) { GenPolynomial> b = toProduct(pfac, a); list.add(b); } return list; } /** * Intersection. Intersection of a list of polynomials with a polynomial * ring. The polynomial ring must be a contraction of the polynomial ring of * the list of polynomials and the TermOrder must be an elimination order. * @param R polynomial ring * @param F list of polynomials * @return R \cap F */ public static > List> intersect(GenPolynomialRing R, List> F) { if (F == null || F.isEmpty()) { return F; } GenPolynomialRing pfac = F.get(0).ring; int d = pfac.nvar - R.nvar; if (d <= 0) { return F; } List> H = new ArrayList>(F.size()); for (GenPolynomial p : F) { Map> m = null; m = p.contract(R); logger.debug("intersect contract m = {}", m); if (m.size() == 1) { // contains one power of variables for (Map.Entry> me : m.entrySet()) { ExpVector e = me.getKey(); if (e.isZERO()) { H.add(me.getValue()); } } } } GenPolynomialRing tfac = pfac.contract(d); if (tfac.equals(R)) { // check return H; } logger.warn("tfac != R: tfac = {}, R = {}, pdac = {}", tfac.toScript(), R.toScript(), pfac.toScript()); // throw new RuntimeException("contract(pfac) != R"); return H; } /** * Intersection. Intersection of a list of solvable polynomials with a * solvable polynomial ring. The solvable polynomial ring must be a * contraction of the solvable polynomial ring of the list of polynomials * and the TermOrder must be an elimination order. * @param R solvable polynomial ring * @param F list of solvable polynomials * @return R \cap F */ @SuppressWarnings("cast") public static > List> intersect( GenSolvablePolynomialRing R, List> F) { List> Fp = PolynomialList. castToList(F); GenPolynomialRing Rp = (GenPolynomialRing) R; List> H = intersect(Rp, Fp); return PolynomialList. castToSolvableList(H); } /** * Intersection. Intersection of a list of word polynomials with a word * polynomial ring. The polynomial ring must be a contraction of the * polynomial ring of the list of polynomials, * @param R word polynomial ring * @param F list of word polynomials * @return R \cap F */ public static > List> intersect(GenWordPolynomialRing R, List> F) { if (F == null || F.isEmpty()) { return F; } GenWordPolynomialRing pfac = F.get(0).ring; assert pfac.alphabet.isSubFactory(R.alphabet) : "pfac=" + pfac.alphabet + ", R=" + R.alphabet; List> H = new ArrayList>(F.size()); for (GenWordPolynomial p : F) { if (p == null || p.isZERO()) { continue; } GenWordPolynomial m = p.contract(R); logger.debug("intersect contract m = {}", m); if (!m.isZERO()) { H.add(m); } } // throw new RuntimeException("contract(pfac) != R"); return H; } /** * Remove all upper variables which do not occur in polynomial. * @param p polynomial. * @return polynomial with removed variables */ public static > GenPolynomial removeUnusedUpperVariables(GenPolynomial p) { GenPolynomialRing fac = p.ring; if (fac.nvar <= 1) { // univariate return p; } int[] dep = p.degreeVector().dependencyOnVariables(); if (fac.nvar == dep.length) { // all variables appear return p; } if (dep.length == 0) { // no variables GenPolynomialRing fac0 = new GenPolynomialRing(fac.coFac, 0); GenPolynomial p0 = new GenPolynomial(fac0, p.leadingBaseCoefficient()); return p0; } int l = dep[0]; // higher variable int r = dep[dep.length - 1]; // lower variable if (l == 0 /*|| l == fac.nvar-1*/) { // upper variable appears return p; } int n = l; GenPolynomialRing facr = fac.contract(n); Map> mpr = p.contract(facr); if (mpr.size() != 1) { logger.warn("upper ex, l = {}, r = {}, p = {}, fac = {}", l, r, p, fac.toScript()); throw new RuntimeException("this should not happen " + mpr); } GenPolynomial pr = mpr.values().iterator().next(); n = fac.nvar - 1 - r; if (n == 0) { return pr; } // else case not implemented return pr; } /** * Remove all lower variables which do not occur in polynomial. * @param p polynomial. * @return polynomial with removed variables */ public static > GenPolynomial removeUnusedLowerVariables(GenPolynomial p) { GenPolynomialRing fac = p.ring; if (fac.nvar <= 1) { // univariate return p; } int[] dep = p.degreeVector().dependencyOnVariables(); if (fac.nvar == dep.length) { // all variables appear return p; } if (dep.length == 0) { // no variables GenPolynomialRing fac0 = new GenPolynomialRing(fac.coFac, 0); GenPolynomial p0 = new GenPolynomial(fac0, p.leadingBaseCoefficient()); return p0; } int l = dep[0]; // higher variable int r = dep[dep.length - 1]; // lower variable if (r == fac.nvar - 1) { // lower variable appears return p; } int n = r + 1; GenPolynomialRing> rfac = fac.recursive(n); GenPolynomial> mpr = recursive(rfac, p); if (mpr.length() != p.length()) { logger.warn("lower ex, l = {}, r = {}, p = {}, fac = {}", l, r, p, fac.toScript()); throw new RuntimeException("this should not happen " + mpr); } RingFactory cf = fac.coFac; GenPolynomialRing facl = new GenPolynomialRing(cf, rfac); GenPolynomial pr = facl.getZERO().copy(); for (Monomial> m : mpr) { ExpVector e = m.e; GenPolynomial a = m.c; if (!a.isConstant()) { throw new RuntimeException("this can not happen " + a); } C c = a.leadingBaseCoefficient(); pr.doPutToMap(e, c); } return pr; } /** * Remove upper block of middle variables which do not occur in polynomial. * @param p polynomial. * @return polynomial with removed variables */ public static > GenPolynomial removeUnusedMiddleVariables(GenPolynomial p) { GenPolynomialRing fac = p.ring; if (fac.nvar <= 2) { // univariate or bi-variate return p; } int[] dep = p.degreeVector().dependencyOnVariables(); if (fac.nvar == dep.length) { // all variables appear return p; } if (dep.length == 0) { // no variables GenPolynomialRing fac0 = new GenPolynomialRing(fac.coFac, 0); GenPolynomial p0 = new GenPolynomial(fac0, p.leadingBaseCoefficient()); return p0; } ExpVector e1 = p.leadingExpVector(); if (dep.length == 1) { // one variable TermOrder to = new TermOrder(fac.tord.getEvord()); int i = dep[0]; String v1 = e1.indexVarName(i, fac.getVars()); String[] vars = new String[] { v1 }; GenPolynomialRing fac1 = new GenPolynomialRing(fac.coFac, to, vars); GenPolynomial p1 = fac1.getZERO().copy(); for (Monomial m : p) { ExpVector e = m.e; ExpVector f = ExpVector.create(1, 0, e.getVal(i)); p1.doPutToMap(f, m.c); } return p1; } GenPolynomialRing> rfac = fac.recursive(1); GenPolynomial> mpr = recursive(rfac, p); int l = dep[0]; // higher variable int r = fac.nvar - dep[1]; // next variable //System.out.println("l = " + l); //System.out.println("r = " + r); TermOrder to = new TermOrder(fac.tord.getEvord()); String[] vs = fac.getVars(); String[] vars = new String[r + 1]; for (int i = 0; i < r; i++) { vars[i] = vs[i]; } vars[r] = e1.indexVarName(l, vs); //System.out.println("fac = " + fac); GenPolynomialRing dfac = new GenPolynomialRing(fac.coFac, to, vars); //System.out.println("dfac = " + dfac); GenPolynomialRing> fac2 = dfac.recursive(1); GenPolynomialRing cfac = (GenPolynomialRing) fac2.coFac; GenPolynomial> p2r = fac2.getZERO().copy(); for (Monomial> m : mpr) { ExpVector e = m.e; GenPolynomial a = m.c; Map> cc = a.contract(cfac); for (Map.Entry> me : cc.entrySet()) { ExpVector f = me.getKey(); if (f.isZERO()) { GenPolynomial c = me.getValue(); //cc.get(f); p2r.doPutToMap(e, c); } else { throw new RuntimeException("this should not happen " + cc); } } } GenPolynomial p2 = distribute(dfac, p2r); return p2; } /** * Select polynomial with univariate leading term in variable i. * @param i variable index. * @return polynomial with head term in variable i */ public static > GenPolynomial selectWithVariable(List> P, int i) { for (GenPolynomial p : P) { int[] dep = p.leadingExpVector().dependencyOnVariables(); if (dep.length == 1 && dep[0] == i) { return p; } } return null; // not found } } /** * Conversion of distributive to recursive representation. */ class DistToRec> implements UnaryFunctor, GenPolynomial>> { GenPolynomialRing> fac; public DistToRec(GenPolynomialRing> fac) { this.fac = fac; } public GenPolynomial> eval(GenPolynomial c) { if (c == null) { return fac.getZERO(); } return PolyUtil. recursive(fac, c); } } /** * Conversion of recursive to distributive representation. */ class RecToDist> implements UnaryFunctor>, GenPolynomial> { GenPolynomialRing fac; public RecToDist(GenPolynomialRing fac) { this.fac = fac; } public GenPolynomial eval(GenPolynomial> c) { if (c == null) { return fac.getZERO(); } return PolyUtil. distribute(fac, c); } } /** * BigRational numerator functor. */ class RatNumer implements UnaryFunctor { public BigInteger eval(BigRational c) { if (c == null) { return new BigInteger(); } return new BigInteger(c.numerator()); } } /** * Conversion of symmetric ModInteger to BigInteger functor. */ class ModSymToInt & Modular> implements UnaryFunctor { public BigInteger eval(C c) { if (c == null) { return new BigInteger(); } return c.getSymmetricInteger(); } } /** * Conversion of ModInteger to BigInteger functor. */ class ModToInt & Modular> implements UnaryFunctor { public BigInteger eval(C c) { if (c == null) { return new BigInteger(); } return c.getInteger(); } } /** * Conversion of BigRational to BigInteger with division by lcm functor. result * = num*(lcm/denom). */ class RatToInt implements UnaryFunctor { java.math.BigInteger lcm; public RatToInt(java.math.BigInteger lcm) { this.lcm = lcm; //.getVal(); } public BigInteger eval(BigRational c) { if (c == null) { return new BigInteger(); } // p = num*(lcm/denom) java.math.BigInteger b = lcm.divide(c.denominator()); return new BigInteger(c.numerator().multiply(b)); } } /** * Conversion of BigRational to BigInteger. result = (num/gcd)*(lcm/denom). */ class RatToIntFactor implements UnaryFunctor { final java.math.BigInteger lcm; final java.math.BigInteger gcd; public RatToIntFactor(java.math.BigInteger gcd, java.math.BigInteger lcm) { this.gcd = gcd; this.lcm = lcm; // .getVal(); } public BigInteger eval(BigRational c) { if (c == null) { return new BigInteger(); } if (gcd.equals(java.math.BigInteger.ONE)) { // p = num*(lcm/denom) java.math.BigInteger b = lcm.divide(c.denominator()); return new BigInteger(c.numerator().multiply(b)); } // p = (num/gcd)*(lcm/denom) java.math.BigInteger a = c.numerator().divide(gcd); java.math.BigInteger b = lcm.divide(c.denominator()); return new BigInteger(a.multiply(b)); } } /** * Conversion of Rational to BigDecimal. result = decimal(r). */ class RatToDec & Rational> implements UnaryFunctor { public BigDecimal eval(C c) { if (c == null) { return new BigDecimal(); } return new BigDecimal(c.getRational()); } } /** * Conversion of Complex Rational to Complex BigDecimal. result = decimal(r). */ class CompRatToDec & Rational> implements UnaryFunctor, Complex> { ComplexRing ring; public CompRatToDec(RingFactory> ring) { this.ring = (ComplexRing) ring; } public Complex eval(Complex c) { if (c == null) { return ring.getZERO(); } BigDecimal r = new BigDecimal(c.getRe().getRational()); BigDecimal i = new BigDecimal(c.getIm().getRational()); return new Complex(ring, r, i); } } /** * Conversion from BigInteger functor. */ class FromInteger> implements UnaryFunctor { RingFactory ring; public FromInteger(RingFactory ring) { this.ring = ring; } public D eval(BigInteger c) { if (c == null) { return ring.getZERO(); } return ring.fromInteger(c.getVal()); } } /** * Conversion from GenPolynomial functor. */ class FromIntegerPoly> implements UnaryFunctor, GenPolynomial> { GenPolynomialRing ring; FromInteger fi; public FromIntegerPoly(GenPolynomialRing ring) { if (ring == null) { throw new IllegalArgumentException("ring must not be null"); } this.ring = ring; fi = new FromInteger(ring.coFac); } public GenPolynomial eval(GenPolynomial c) { if (c == null) { return ring.getZERO(); } return PolyUtil. map(ring, c, fi); } } /** * Conversion from GenPolynomial to GenPolynomial * functor. */ class RatToIntPoly implements UnaryFunctor, GenPolynomial> { GenPolynomialRing ring; public RatToIntPoly(GenPolynomialRing ring) { if (ring == null) { throw new IllegalArgumentException("ring must not be null"); } this.ring = ring; } public GenPolynomial eval(GenPolynomial c) { if (c == null) { return ring.getZERO(); } return PolyUtil.integerFromRationalCoefficients(ring, c); } } /** * Real part functor. */ class RealPart implements UnaryFunctor { public BigRational eval(BigComplex c) { if (c == null) { return new BigRational(); } return c.getRe(); } } /** * Imaginary part functor. */ class ImagPart implements UnaryFunctor { public BigRational eval(BigComplex c) { if (c == null) { return new BigRational(); } return c.getIm(); } } /** * Real part functor. */ class RealPartComplex> implements UnaryFunctor, C> { public C eval(Complex c) { if (c == null) { return null; } return c.getRe(); } } /** * Imaginary part functor. */ class ImagPartComplex> implements UnaryFunctor, C> { public C eval(Complex c) { if (c == null) { return null; } return c.getIm(); } } /** * Rational to complex functor. */ class ToComplex> implements UnaryFunctor> { final protected ComplexRing cfac; @SuppressWarnings("unchecked") public ToComplex(RingFactory> fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = (ComplexRing) fac; } public Complex eval(C c) { if (c == null) { return cfac.getZERO(); } return new Complex(cfac, c); } } /** * Rational to complex functor. */ class RatToCompl implements UnaryFunctor { public BigComplex eval(BigRational c) { if (c == null) { return new BigComplex(); } return new BigComplex(c); } } /** * Any ring element to generic complex functor. */ class AnyToComplex> implements UnaryFunctor> { final protected ComplexRing cfac; public AnyToComplex(ComplexRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = fac; } public AnyToComplex(RingFactory fac) { this(new ComplexRing(fac)); } public Complex eval(C a) { if (a == null || a.isZERO()) { // should not happen return cfac.getZERO(); } else if (a.isONE()) { return cfac.getONE(); } else { return new Complex(cfac, a); } } } /** * Algebraic to generic complex functor. */ class AlgebToCompl> implements UnaryFunctor, Complex> { final protected ComplexRing cfac; public AlgebToCompl(ComplexRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = fac; } public Complex eval(AlgebraicNumber a) { if (a == null || a.isZERO()) { // should not happen return cfac.getZERO(); } else if (a.isONE()) { return cfac.getONE(); } else { GenPolynomial p = a.getVal(); C real = cfac.ring.getZERO(); C imag = cfac.ring.getZERO(); for (Monomial m : p) { if (m.exponent().getVal(0) == 1L) { imag = m.coefficient(); } else if (m.exponent().getVal(0) == 0L) { real = m.coefficient(); } else { throw new IllegalArgumentException("unexpected monomial " + m); } } //Complex c = new Complex(cfac,real,imag); return new Complex(cfac, real, imag); } } } /** * Ceneric complex to algebraic number functor. */ class ComplToAlgeb> implements UnaryFunctor, AlgebraicNumber> { final protected AlgebraicNumberRing afac; final protected AlgebraicNumber I; public ComplToAlgeb(AlgebraicNumberRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; I = afac.getGenerator(); } public AlgebraicNumber eval(Complex c) { if (c == null || c.isZERO()) { // should not happen return afac.getZERO(); } else if (c.isONE()) { return afac.getONE(); } else if (c.isIMAG()) { return I; } else { return I.multiply(c.getIm()).sum(c.getRe()); } } } /** * Algebraic to polynomial functor. */ class AlgToPoly> implements UnaryFunctor, GenPolynomial> { public GenPolynomial eval(AlgebraicNumber c) { if (c == null) { return null; } return c.val; } } /** * Polynomial to algebriac functor. */ class PolyToAlg> implements UnaryFunctor, AlgebraicNumber> { final protected AlgebraicNumberRing afac; public PolyToAlg(AlgebraicNumberRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; } public AlgebraicNumber eval(GenPolynomial c) { if (c == null) { return afac.getZERO(); } return new AlgebraicNumber(afac, c); } } /** * Coefficient to algebriac functor. */ class CoeffToAlg> implements UnaryFunctor> { final protected AlgebraicNumberRing afac; final protected GenPolynomial zero; public CoeffToAlg(AlgebraicNumberRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; GenPolynomialRing pfac = afac.ring; zero = pfac.getZERO(); } public AlgebraicNumber eval(C c) { if (c == null) { return afac.getZERO(); } return new AlgebraicNumber(afac, zero.sum(c)); } } /** * Coefficient to recursive algebriac functor. */ class CoeffToRecAlg> implements UnaryFunctor> { final protected List> lfac; final int depth; @SuppressWarnings("unchecked") public CoeffToRecAlg(int depth, AlgebraicNumberRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } AlgebraicNumberRing afac = fac; this.depth = depth; lfac = new ArrayList>(this.depth); lfac.add(fac); for (int i = 1; i < this.depth; i++) { RingFactory rf = afac.ring.coFac; if (!(rf instanceof AlgebraicNumberRing)) { throw new IllegalArgumentException("fac depth to low"); } afac = (AlgebraicNumberRing) (Object) rf; lfac.add(afac); } } @SuppressWarnings("unchecked") public AlgebraicNumber eval(C c) { if (c == null) { return lfac.get(0).getZERO(); } C ac = c; AlgebraicNumberRing af = lfac.get(lfac.size() - 1); GenPolynomial zero = af.ring.getZERO(); AlgebraicNumber an = new AlgebraicNumber(af, zero.sum(ac)); for (int i = lfac.size() - 2; i >= 0; i--) { af = lfac.get(i); zero = af.ring.getZERO(); ac = (C) (Object) an; an = new AlgebraicNumber(af, zero.sum(ac)); } return an; } } /** * Evaluate main variable functor. */ class EvalMain> implements UnaryFunctor, C> { final RingFactory cfac; final C a; public EvalMain(RingFactory cfac, C a) { this.cfac = cfac; this.a = a; } public C eval(GenPolynomial c) { if (c == null) { return cfac.getZERO(); } return PolyUtil. evaluateMain(cfac, c, a); } } /** * Evaluate main variable functor. */ class EvalMainPol> implements UnaryFunctor, GenPolynomial> { final GenPolynomialRing cfac; final C a; public EvalMainPol(GenPolynomialRing cfac, C a) { this.cfac = cfac; this.a = a; } public GenPolynomial eval(GenPolynomial c) { if (c == null) { return cfac.getZERO(); } return PolyUtil. evaluateMain(cfac, c, a); } } /** * Evaluate all variable functor. */ class EvalAllPol> implements UnaryFunctor, C> { final RingFactory cfac; final List a; public EvalAllPol(RingFactory cfac, List a) { this.cfac = cfac; this.a = a; } public C eval(GenPolynomial c) { if (c == null) { return cfac.getZERO(); } return PolyUtil. evaluateAll(cfac, c, a); } } java-algebra-system-2.7.200/src/edu/jas/poly/Polynomial.java000066400000000000000000000045561445075545500236420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.Iterator; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Polynomial interface. * Adds methods specific to polynomials. * @param ring element type * @author Heinz Kredel */ public interface Polynomial> extends RingElem< Polynomial > { /** * Leading monomial. * @return first map entry. */ public Map.Entry leadingMonomial(); /** * Leading exponent vector. * @return first exponent. */ public ExpVector leadingExpVector(); /** * Leading base coefficient. * @return first coefficient. */ public C leadingBaseCoefficient(); /** * Trailing base coefficient. * @return coefficient of constant term. */ public C trailingBaseCoefficient(); /** * Reductum. * @return this - leading monomial. */ public Polynomial reductum(); /** * Extend variables. Used e.g. in module embedding. * Extend all ExpVectors by i elements and multiply by x_j^k. * @param pfac extended polynomial ring factory (by i variables). * @param j index of variable to be used for multiplication. * @param k exponent for x_j. * @return extended polynomial. */ public Polynomial extend(PolynomialRing pfac, int j, long k); /** * Contract variables. Used e.g. in module embedding. * remove i elements of each ExpVector. * @param pfac contracted polynomial ring factory (by i variables). * @return Map of exponents and contracted polynomials. * Note: could return SortedMap */ public Map> contract(PolynomialRing pfac); /** * Reverse variables. Used e.g. in opposite rings. * @return polynomial with reversed variables. */ public Polynomial reverse(PolynomialRing oring); /** * Iterator over coefficients. * @return val.values().iterator(). */ public Iterator coefficientIterator(); /** * Iterator over exponents. * @return val.keySet().iterator(). */ public Iterator exponentIterator(); /** * Iterator over monomials. * @return a PolyIterator. */ public Iterator> monomialIterator(); } java-algebra-system-2.7.200/src/edu/jas/poly/PolynomialComparator.java000066400000000000000000000036371445075545500256710ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.Comparator; import edu.jas.structure.RingElem; /** * Comparator for polynomials. * @param coefficient type * @author Heinz Kredel */ public class PolynomialComparator> implements Serializable, Comparator> { public final TermOrder tord; public final boolean reverse; /** * Constructor. * @param t TermOrder. * @param reverse flag if reverse ordering is requested. */ public PolynomialComparator(TermOrder t, boolean reverse) { tord = t; this.reverse = reverse; } /** * Compare polynomials. * @param p1 first polynomial. * @param p2 second polynomial. * @return 0 if ( p1 == p2 ), -1 if ( p1 < p2 ) and +1 if ( p1 > p2 ). */ public int compare(GenPolynomial p1, GenPolynomial p2) { // check if p1.tord = p2.tord = tord ? int s = p1.compareTo(p2); //System.out.println("p1.compareTo(p2) = " + s); if (reverse) { return -s; } return s; } /** * Equals test of comparator. * @param o other object. * @return true if this = o, else false. */ @Override public boolean equals(Object o) { PolynomialComparator pc = null; try { pc = (PolynomialComparator) o; } catch (ClassCastException ignored) { return false; } if (pc == null) { return false; } return tord.equals(pc.tord); } /** * Hash code for this PolynomialComparator. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return tord.hashCode(); } /** * toString. */ @Override public String toString() { return "PolynomialComparator(" + tord + ")"; } } java-algebra-system-2.7.200/src/edu/jas/poly/PolynomialList.java000066400000000000000000000417641445075545500245000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; /** * List of polynomials. Mainly for storage and printing / toString and * conversions to other representations. * @author Heinz Kredel */ public class PolynomialList> implements Comparable>, Serializable { /** * The factory for the solvable polynomial ring. */ public final GenPolynomialRing ring; /** * The data structure is a List of polynomials. */ public final List> list; private static final Logger logger = LogManager.getLogger(PolynomialList.class); /** * Constructor. * @param r polynomial ring factory. * @param l list of polynomials. */ public PolynomialList(GenPolynomialRing r, List> l) { ring = r; list = l; } /** * Constructor. * @param r solvable polynomial ring factory. * @param l list of solvable polynomials. */ public PolynomialList(GenSolvablePolynomialRing r, List> l) { this(r, PolynomialList. castToList(l)); } /** * Copy this. * @return a copy of this. */ public PolynomialList copy() { return new PolynomialList(ring, new ArrayList>(list)); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object p) { if (p == null) { return false; } if (!(p instanceof PolynomialList)) { System.out.println("no PolynomialList"); return false; } PolynomialList pl = (PolynomialList) p; if (!ring.equals(pl.ring)) { System.out.println("not same Ring " + ring.toScript() + ", " + pl.ring.toScript()); return false; } return (compareTo(pl) == 0); // otherwise tables may be different } /** * Polynomial list comparison. * @param L other PolynomialList. * @return lexicographical comparison, sign of first different polynomials. */ public int compareTo(PolynomialList L) { int si = L.list.size(); if (list.size() < si) { // minimum si = list.size(); } int s = 0; List> l1 = OrderedPolynomialList. sort(ring, list); List> l2 = OrderedPolynomialList. sort(ring, L.list); for (int i = 0; i < si; i++) { GenPolynomial a = l1.get(i); GenPolynomial b = l2.get(i); s = a.compareTo(b); if (s != 0) { return s; } } if (list.size() > si) { return 1; } if (L.list.size() > si) { return -1; } return s; } /** * Hash code for this polynomial list. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + (list == null ? 0 : list.hashCode()); return h; } /** * Test if list is empty. * @return true if this is empty, else false. */ public boolean isEmpty() { if (list == null) { return true; } return list.isEmpty(); } /** * String representation of the polynomial list. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer erg = new StringBuffer(); String[] vars = null; if (ring != null) { erg.append(ring.toString()); vars = ring.getVars(); } boolean first = true; erg.append("\n(\n"); String sa = null; for (GenPolynomial oa : list) { if (vars != null) { sa = oa.toString(vars); } else { sa = oa.toString(); } if (first) { first = false; } else { erg.append(", "); if (sa.length() > 10) { erg.append("\n"); } } erg.append("( " + sa + " )"); } erg.append("\n)"); return erg.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this polynomial list. */ public String toScript() { StringBuffer s = new StringBuffer(); if (ring instanceof GenSolvablePolynomialRing) { switch (Scripting.getLang()) { case Ruby: s.append("SolvIdeal.new("); break; case Python: default: s.append("SolvableIdeal("); } } else { switch (Scripting.getLang()) { case Ruby: s.append("SimIdeal.new("); break; case Python: default: s.append("Ideal("); } } if (ring != null) { s.append(ring.toScript()); } if (list == null) { s.append(")"); return s.toString(); } switch (Scripting.getLang()) { case Ruby: s.append(",\"\",["); break; case Python: default: s.append(",list=["); } boolean first = true; String sa = null; for (GenPolynomial oa : list) { sa = oa.toScript(); if (first) { first = false; } else { s.append(", "); } //s.append("( " + sa + " )"); s.append(sa); } s.append("])"); return s.toString(); } /** * Get ModuleList from PolynomialList. Extract module from polynomial ring. * @see edu.jas.poly.ModuleList * @param i number of variables to be contract form the polynomials. * @return module list corresponding to this. */ @SuppressWarnings("unchecked") public ModuleList getModuleList(int i) { GenPolynomialRing pfac = ring.contract(i); logger.debug("contracted ring = {}", pfac); //System.out.println("contracted ring = " + pfac); List>> vecs = null; if (list == null) { return new ModuleList(pfac, vecs); } int rows = list.size(); vecs = new ArrayList>>(rows); if (rows == 0) { // nothing to do return new ModuleList(pfac, vecs); } ArrayList> zr = new ArrayList>(i - 1); GenPolynomial zero = pfac.getZERO(); for (int j = 0; j < i; j++) { zr.add(j, zero); } for (GenPolynomial p : list) { if (p != null) { Map> r = p.contract(pfac); //System.out.println("r = " + r ); List> row = new ArrayList>(zr); //zr.clone(); for (Map.Entry> me : r.entrySet()) { ExpVector e = me.getKey(); int[] dov = e.dependencyOnVariables(); int ix = 0; if (dov.length > 1) { throw new IllegalArgumentException("wrong dependencyOnVariables " + e); } else if (dov.length == 1) { ix = dov[0]; } //ix = i-1 - ix; // revert //System.out.println("ix = " + ix ); GenPolynomial vi = me.getValue(); //r.get( e ); row.set(ix, vi); } //System.out.println("row = " + row ); vecs.add(row); } } return new ModuleList(pfac, vecs); } /** * Get list. * @return list from this. */ public List> getList() { return list; } /** * Get list as List of GenSolvablePolynomials. Required because no List * casts allowed. Equivalent to cast * (List<GenSolvablePolynomial<C>>) list. * @return solvable polynomial list from this. */ public List> castToSolvableList() { return castToSolvableList(list); } /** * Get list as List of GenSolvablePolynomials. Required because no List * casts allowed. Equivalent to cast * (List<GenSolvablePolynomial<C>>) list. * @return solvable polynomial list from this. */ public List> getSolvableList() { return castToSolvableList(list); } /** * Get ring as GenSolvablePolynomialRing. * @return solvable polynomial ring list from this. */ public GenSolvablePolynomialRing getSolvableRing() { return (GenSolvablePolynomialRing) ring; } /** * Get list as List of GenSolvablePolynomials. Required because no List * casts allowed. Equivalent to cast * (List<GenSolvablePolynomial<C>>) list. * @param list list of extensions of polynomials. * @return solvable polynomial list from this. */ public static > List> castToSolvableList( List> list) { List> slist = null; if (list == null) { return slist; } slist = new ArrayList>(list.size()); GenSolvablePolynomial s; for (GenPolynomial p : list) { if (p == null) { s = null; } else { if (!(p instanceof GenSolvablePolynomial)) { throw new IllegalArgumentException("no solvable polynomial " + p); } s = (GenSolvablePolynomial) p; } slist.add(s); } return slist; } /** * Get list of list as List of List of GenSolvablePolynomials. Required * because no List casts allowed. Equivalent to cast * (List<GenSolvablePolynomial<C>>) list. * @param list list of extensions of polynomials. * @return solvable polynomial list from this. */ public static > List>> castToSolvableMatrix( List>> list) { List>> slist = null; if (list == null) { return slist; } slist = new ArrayList>>(list.size()); List> s; for (List> p : list) { s = PolynomialList. castToSolvableList(p); slist.add(s); } return slist; } /** * Get list of extensions of polynomials as List of GenPolynomials. Required * because no List casts allowed. Equivalent to cast * (List<GenPolynomial<C>>) list. Mainly used for lists of * GenSolvablePolynomials. * @param slist list of extensions of polynomials. * @return polynomial list from slist. */ public static > List> castToList( List> slist) { logger.debug("warn: can lead to wrong method dispatch"); List> list = null; if (slist == null) { return list; } list = new ArrayList>(slist.size()); for (GenPolynomial p : slist) { list.add(p); } return list; } /** * Get list of list of extensions of polynomials as List of List of * GenPolynomials. Required because no List casts allowed. Equivalent to * cast (List<GenPolynomial<C>>) list. Mainly used for lists of * GenSolvablePolynomials. * @param slist list of extensions of polynomials. * @return polynomial list from slist. */ public static > List>> castToMatrix( List>> slist) { logger.debug("warn: can lead to wrong method dispatch"); List>> list = null; if (slist == null) { return list; } list = new ArrayList>>(slist.size()); for (List> p : slist) { list.add(PolynomialList. castToList(p)); } return list; } /** * Test if list contains only ZEROs. * @return true, if this is the 0 list, else false */ public boolean isZERO() { if (list == null) { return true; } for (GenPolynomial p : list) { if (p == null) { continue; } if (!p.isZERO()) { return false; } } return true; } /** * Test if list contains a ONE. * @return true, if this contains 1, else false */ public boolean isONE() { if (list == null) { return false; } for (GenPolynomial p : list) { if (p == null) { continue; } if (p.isONE()) { return true; } } return false; } /** * Make homogeneous. * @return polynomial list of homogeneous polynomials. */ public PolynomialList homogenize() { GenPolynomialRing pfac = ring.extend(1); List> hom = new ArrayList>(list.size()); for (GenPolynomial p : list) { GenPolynomial h = p.homogenize(pfac); hom.add(h); } return new PolynomialList(pfac, hom); } /** * Dehomogenize. * @return polynomial list of de-homogenized polynomials. */ public PolynomialList deHomogenize() { GenPolynomialRing pfac = ring.contract(1); List> dehom = new ArrayList>(list.size()); for (GenPolynomial p : list) { GenPolynomial h = p.deHomogenize(pfac); dehom.add(h); } return new PolynomialList(pfac, dehom); } /** * Test if all polynomials are homogeneous. * @return true, if all polynomials are homogeneous, else false */ public boolean isHomogeneous() { if (list == null) { return true; } for (GenPolynomial p : list) { if (p == null) { continue; } if (!p.isHomogeneous()) { return false; } } return true; } /** * Union of the delta of exponent vectors of all polynomials. * @return list of u-v, where u = lt() and v != u in p in list. */ public SortedSet deltaExpVectors() { SortedSet de = new TreeSet(ring.tord.getAscendComparator()); if (list.isEmpty()) { return de; } for (GenPolynomial p : list) { List pe = p.deltaExpVectors(); de.addAll(pe); } return de; } /** * Union of the delta of exponent vectors of all polynomials. * @param mark list of marked exp vectors of polynomials. * @return list of u-v, where u in mark and v != u in p.expVectors in list. */ public SortedSet deltaExpVectors(List mark) { SortedSet de = new TreeSet(ring.tord.getAscendComparator()); if (list.isEmpty()) { return de; } if (mark.isEmpty()) { return deltaExpVectors(); } if (list.size() != mark.size()) { throw new IllegalArgumentException("#list != #mark"); } int i = 0; for (GenPolynomial p : list) { ExpVector u = mark.get(i); List pe = p.deltaExpVectors(u); de.addAll(pe); i++; } return de; } /** * Leading weight polynomials. * @return list of polynomials with terms of maximal weight degree. */ public List> leadingWeightPolynomials() { List> lw = new ArrayList>(list.size()); if (list.isEmpty()) { return lw; } for (GenPolynomial p : list) { GenPolynomial pw = p.leadingWeightPolynomial(); lw.add(pw); } return lw; } } java-algebra-system-2.7.200/src/edu/jas/poly/PolynomialRing.java000066400000000000000000000052451445075545500244560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import java.util.Random; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Polynomial factory interface. * Defines polynomial specific factory methods. * @author Heinz Kredel */ public interface PolynomialRing> extends RingFactory< Polynomial > { /** * Number of variables. * @return the number of variables. */ public int numberOfVariables(); /** Get the variable names. * @return vars. */ public String[] getVars(); /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random polynomial. */ public Polynomial random(int k, int l, int d, float q); /** * Generate a random polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random polynomial. */ public Polynomial random(int k, int l, int d, float q, Random rnd); /** * Generate univariate polynomial in a given variable. * @param i the index of the variable. * @return X_i as univariate polynomial. */ public Polynomial univariate(int i); /** * Generate univariate polynomial in a given variable with given exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as univariate polynomial. */ public Polynomial univariate(int i, long e); /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ public List> univariateList(); /** * Extend variables. Used e.g. in module embedding. * Extend number of variables by i. * @param i number of variables to extend. * @return extended polynomial ring factory. */ public PolynomialRing extend(int i); /** * Contract variables. Used e.g. in module embedding. * Contract number of variables by i. * @param i number of variables to remove. * @return contracted polynomial ring factory. */ public PolynomialRing contract(int i); /** * Reverse variables. Used e.g. in opposite rings. * @return polynomial ring factory with reversed variables. */ public PolynomialRing reverse(); } java-algebra-system-2.7.200/src/edu/jas/poly/QLRSolvablePolynomial.java000066400000000000000000000540551445075545500257100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; import edu.jas.structure.RingFactory; /** * QLRSolvablePolynomial generic recursive solvable polynomials implementing * RingElem. n-variate ordered solvable polynomials over solvable quotient, * local and local-residue coefficients. Objects of this class are intended to * be immutable. The implementation is based on TreeMap respectively SortedMap * from exponents to coefficients by extension of GenPolynomial. * @param polynomial coefficient type * @param quotient coefficient type * @author Heinz Kredel */ public class QLRSolvablePolynomial & QuotPair>, D extends GcdRingElem> extends GenSolvablePolynomial { private static final Logger logger = LogManager.getLogger(QLRSolvablePolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final QLRSolvablePolynomialRing ring; /** * Constructor for zero QLRSolvablePolynomial. * @param r solvable polynomial ring factory. */ public QLRSolvablePolynomial(QLRSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for QLRSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public QLRSolvablePolynomial(QLRSolvablePolynomialRing r, C c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for QLRSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public QLRSolvablePolynomial(QLRSolvablePolynomialRing r, C c) { this(r, c, r.evzero); } /** * Constructor for QLRSolvablePolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public QLRSolvablePolynomial(QLRSolvablePolynomialRing r, GenSolvablePolynomial S) { this(r, S.getMap()); } /** * Constructor for QLRSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected QLRSolvablePolynomial(QLRSolvablePolynomialRing r, SortedMap v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public QLRSolvablePolynomialRing factory() { return ring; } /** * Clone this QLRSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public QLRSolvablePolynomial copy() { return new QLRSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof QLRSolvablePolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * QLRSolvablePolynomial multiplication. * @param Bp QLRSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // not @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial multiply(QLRSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } if (Bp.isONE()) { return this; } if (this.isONE()) { return Bp; } assert (ring.nvar == Bp.ring.nvar); if (debug) { logger.debug("ring = {}", ring); } //System.out.println("this = " + this + ", Bp = " + Bp); ExpVector Z = ring.evzero; QLRSolvablePolynomial Dp = ring.getZERO().copy(); QLRSolvablePolynomial zero = ring.getZERO().copy(); C one = ring.getONECoefficient(); Map A = val; Map B = Bp.val; Set> Bk = B.entrySet(); for (Map.Entry y : A.entrySet()) { C a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = {}", e, a); //int[] ep = e.dependencyOnVariables(); //int el1 = ring.nvar + 1; //if (ep.length > 0) { // el1 = ep[0]; //} //int el1s = ring.nvar + 1 - el1; for (Map.Entry x : Bk) { C b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial with coefficient multiplication QLRSolvablePolynomial Cps = ring.getZERO().copy(); //QLRSolvablePolynomial Cs; QLRSolvablePolynomial qp; if (ring.polCoeff.isCommutative() || b.isConstant() || e.isZERO()) { // symmetric Cps = new QLRSolvablePolynomial(ring, b, e); if (debug) logger.info("symmetric coeff: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff: b = {}, e = {}", b, e); // compute e * b as ( e * 1/b.den ) * b.num if (b.denominator().isONE()) { // recursion base // recursive polynomial coefficient multiplication : e * b.num RecSolvablePolynomial rsp1 = new RecSolvablePolynomial(ring.polCoeff, e); RecSolvablePolynomial rsp2 = new RecSolvablePolynomial(ring.polCoeff, b.numerator()); RecSolvablePolynomial rsp3 = rsp1.multiply(rsp2); QLRSolvablePolynomial rsp = ring.fromPolyCoefficients(rsp3); Cps = rsp; } else { // b.denominator() != 1 if (debug) logger.info("coeff-num: Cps = {}, num = {}, den = {}", Cps, b.numerator(), b.denominator()); RingFactory bfq = (RingFactory) b.factory(); Cps = new QLRSolvablePolynomial(ring, bfq.getONE(), e); // coefficient multiplication with 1/den: QLRSolvablePolynomial qv = Cps; //C qden = new C(b.denominator().factory(), b.denominator()); // den/1 C qden = ring.qpfac.create(b.denominator()); // den/1 //System.out.println("qv = " + qv + ", den = " + den); // recursion with den==1: QLRSolvablePolynomial v = qv.multiply(qden); QLRSolvablePolynomial vl = qv.multiplyLeft(qden); //System.out.println("v = " + v + ", vl = " + vl + ", qden = " + qden); QLRSolvablePolynomial vr = (QLRSolvablePolynomial) v.subtract(vl); //C qdeni = new C(b.factory(), b.factory().getONE().numerator(), b.denominator()); C qdeni = ring.qpfac.create(ring.qpfac.pairFactory().getONE(), b.denominator()); // 1/den //System.out.println("vr = " + vr + ", qdeni = " + qdeni); // recursion with smaller head term: if (qv.leadingExpVector().equals(vr.leadingExpVector())) { throw new IllegalArgumentException("qv !> vr: qv = " + qv + ", vr = " + vr); } QLRSolvablePolynomial rq = vr.multiply(qdeni); qp = (QLRSolvablePolynomial) qv.subtract(rq); qp = qp.multiplyLeft(qdeni); //System.out.println("qp_i = " + qp); Cps = qp; if (!b.numerator().isONE()) { //C qnum = new C(b.denominator().factory(), b.numerator()); // num/1 C qnum = ring.qpfac.create(b.numerator()); // num/1 // recursion with den == 1: Cps = Cps.multiply(qnum); } } } // end coeff if (debug) logger.info("coeff-den: Cps = {}", Cps); // polynomial multiplication QLRSolvablePolynomial Dps = ring.getZERO().copy(); QLRSolvablePolynomial Ds = null; QLRSolvablePolynomial D1, D2; if (ring.isCommutative() || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly: b = {}, e = {}", b, e); if (Cps.isConstant()) { ExpVector g = e.sum(f); Ds = new QLRSolvablePolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly: Cps = {}, f = {}", Cps, f); for (Map.Entry z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 C c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (QLRSolvablePolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) { logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); logger.info("poly, g2 = {}, f2 = {}", g2, f2); } TableRelation rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new QLRSolvablePolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = new QLRSolvablePolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = new QLRSolvablePolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = new QLRSolvablePolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = new QLRSolvablePolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // c * Ds //Dps = (QLRSolvablePolynomial) Dps.sum(Ds); Dps.doAddTo(Ds); } // end Dps loop Ds = Dps; } Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric if (debug) logger.debug("Ds = {}", Ds); //Dp = (QLRSolvablePolynomial) Dp.sum(Ds); Dp.doAddTo(Ds); } // end B loop } // end A loop //System.out.println("this * Bp = " + Dp); return Dp; } /** * QLRSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S QLRSolvablePolynomial. * @param T QLRSolvablePolynomial. * @return S*this*T. */ // not @Override public QLRSolvablePolynomial multiply(QLRSolvablePolynomial S, QLRSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * QLRSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b solvable coefficient. * @return this*b, where * is coefficient multiplication. */ @Override public QLRSolvablePolynomial multiply(C b) { QLRSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (b.isONE()) { return this; } Cp = new QLRSolvablePolynomial(ring, b, ring.evzero); return multiply(Cp); } /** * QLRSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public QLRSolvablePolynomial multiply(C b, C c) { QLRSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } if (b.isONE() && c.isONE()) { return this; } Cp = new QLRSolvablePolynomial(ring, b, ring.evzero); QLRSolvablePolynomial Dp = new QLRSolvablePolynomial(ring, c, ring.evzero); return multiply(Cp, Dp); } /** * QLRSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } C b = ring.getONECoefficient(); return multiply(b, e); } /** * QLRSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public QLRSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } C b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * QLRSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiply(C b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO()) { return this; } QLRSolvablePolynomial Cp = new QLRSolvablePolynomial(ring, b, e); return multiply(Cp); } /** * QLRSolvablePolynomial left and right multiplication. Product with ring * element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public QLRSolvablePolynomial multiply(C b, ExpVector e, C c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } if (b.isONE() && e.isZERO() && c.isONE() && f.isZERO()) { return this; } QLRSolvablePolynomial Cp = new QLRSolvablePolynomial(ring, b, e); QLRSolvablePolynomial Dp = new QLRSolvablePolynomial(ring, c, f); return multiply(Cp, Dp); } /** * QLRSolvablePolynomial multiplication. Left product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiplyLeft(C b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } QLRSolvablePolynomial Cp = new QLRSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * QLRSolvablePolynomial multiplication. Left product with exponent vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } C b = ring.getONECoefficient(); QLRSolvablePolynomial Cp = new QLRSolvablePolynomial(ring, b, e); return Cp.multiply(this); } /** * QLRSolvablePolynomial multiplication. Left product with coefficient ring * element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public QLRSolvablePolynomial multiplyLeft(C b) { QLRSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map Cm = Cp.val; //getMap(); Map Am = val; C c; for (Map.Entry y : Am.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * QLRSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiplyLeft(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * QLRSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public QLRSolvablePolynomial multiply(Map.Entry m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * QLRSolvablePolynomial multiplication with exponent vector. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected QLRSolvablePolynomial shift(ExpVector f) { QLRSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map Cm = C.val; Map Bm = this.val; for (Map.Entry y : Bm.entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/poly/QLRSolvablePolynomialRing.java000066400000000000000000000701541445075545500265260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * QLRSolvablePolynomialRing generic recursive solvable polynomial factory * implementing RingFactory and extending GenSolvablePolynomialRing factory. * Factory for n-variate ordered solvable polynomials over solvable quotient, * local and local-residue coefficients. The non-commutative multiplication * relations are maintained in a relation table and the non-commutative * multiplication relations between the coefficients and the main variables are * maintained in a coefficient relation table. Almost immutable object, except * variable names and relation table contents. * @param polynomial coefficient type * @param quotient coefficient type * @author Heinz Kredel */ public class QLRSolvablePolynomialRing & QuotPair>, D extends GcdRingElem> extends GenSolvablePolynomialRing { private static final Logger logger = LogManager.getLogger(QLRSolvablePolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Recursive solvable polynomial ring with polynomial coefficients. */ public final RecSolvablePolynomialRing polCoeff; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public /*final*/ QLRSolvablePolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public /*final*/ QLRSolvablePolynomial ONE; /** * Factory to create coefficients. */ public final QuotPairFactory, C> qpfac; /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public QLRSolvablePolynomialRing(RingFactory cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public QLRSolvablePolynomialRing(RingFactory cf, int n, RelationTable rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public QLRSolvablePolynomialRing(RingFactory cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public QLRSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, RelationTable rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public QLRSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public QLRSolvablePolynomialRing(RingFactory cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public QLRSolvablePolynomialRing(RingFactory cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public QLRSolvablePolynomialRing(RingFactory cf, GenSolvablePolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public QLRSolvablePolynomialRing(RingFactory cf, QLRSolvablePolynomialRing o) { this(cf, (GenSolvablePolynomialRing) o); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ @SuppressWarnings("unchecked") public QLRSolvablePolynomialRing(RingFactory cf, int n, TermOrder t, String[] v, RelationTable rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } qpfac = (QuotPairFactory, C>) cf; // crucial part of type RingFactory> cfring = qpfac.pairFactory(); // == coFac.ring polCoeff = new RecSolvablePolynomialRing(cfring, n, t, v); if (table.size() > 0) { List>> nt = new ArrayList>>(); for (GenSolvablePolynomial q : table.relationList()) { nt.add( this.toPolyCoefficients(q) ); // only with den == 1 } polCoeff.table.addSolvRelations(nt); } ZERO = new QLRSolvablePolynomial(this); C coeff = coFac.getONE(); ONE = new QLRSolvablePolynomial(this, coeff, evzero); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { res += "\n" + polCoeff.coeffTable.toString(vars); res += "\n" + polCoeff.table.toString(vars); } else { res += ", #rel = " + table.size() + " + " + polCoeff.coeffTable.size() + " + " + polCoeff.table.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); String rel = ""; if (table.size() > 0) { rel = table.toScript(); s.append(",rel="); s.append(rel); } // if (polCoeff.coeffTable.size() > 0) { // String crel = polCoeff.coeffTable.toScript(); // s.append(",coeffrel="); // s.append(crel); // } // if (polCoeff.table.size() > 0) { // should not be printed // String polrel = polCoeff.table.toScript(); // if (!rel.equals(polrel)) { // s.append(",polrel="); // s.append(polrel); // } // } s.append(")"); String cpol = polCoeff.toScript(); s.append("\n # "); s.append(cpol); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (!(other instanceof QLRSolvablePolynomialRing)) { return false; } QLRSolvablePolynomialRing oring = null; try { oring = (QLRSolvablePolynomialRing) other; } catch (ClassCastException ignored) { } if (oring == null) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!polCoeff.coeffTable.equals(oring.polCoeff.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + polCoeff.coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as QLRSolvablePolynomial. */ @Override public QLRSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 QLRSolvablePolynomial x = ZERO; ZERO = new QLRSolvablePolynomial(this); logger.info("warn: ZERO@get |{}| wrong fix to {}", x, ZERO); } return ZERO; } /** * Get the one element. * @return 1 as QLRSolvablePolynomial. */ @Override public QLRSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { ONE = new QLRSolvablePolynomial(this, coFac.getONE(), evzero); logger.info("warn: ONE@get {}", ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (polCoeff.isCommutative()) { return super.isCommutative(); } return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @Override @SuppressWarnings("unchecked") public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } //System.out.println("polCoeff = " + polCoeff.toScript()); if (!polCoeff.isAssociative()) { // not done via generators?? return false; } QLRSolvablePolynomial Xi, Xj, Xk, p, q; List> gens = generators(); //System.out.println("QLR gens = " + gens); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (QLRSolvablePolynomial) gens.get(i); if (Xi.degree() == 0) { C lbc = Xi.leadingBaseCoefficient(); if (lbc.numerator().degree() == 0 && lbc.denominator().degree() == 0) { //System.out.println("qlr assoc skip: Xi = " + lbc); continue; // skip } } for (int j = i + 1; j < ngen; j++) { Xj = (QLRSolvablePolynomial) gens.get(j); if (Xj.degree() == 0) { C lbc = Xi.leadingBaseCoefficient(); if (lbc.numerator().degree() == 0 && lbc.denominator().degree() == 0) { //System.out.println("qlr assoc skip: Xj = " + lbc); continue; // skip } } for (int k = j + 1; k < ngen; k++) { Xk = (QLRSolvablePolynomial) gens.get(k); if (Xi.degree() == 0 && Xj.degree() == 0 && Xk.degree() == 0) { //System.out.println("qlr assoc degree == 0"); continue; // skip } try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); //System.out.println("qlr assoc: p = " + p); //System.out.println("qlr assoc: q = " + q); } catch (IllegalArgumentException e) { System.out.println("qlr assoc: Xi = " + Xi); System.out.println("qlr assoc: Xj = " + Xj); System.out.println("qlr assoc: Xk = " + Xk); e.printStackTrace(); continue; } if (!p.equals(q)) { if (logger.isInfoEnabled()) { //System.out.println("qlr assoc: Xk = " + Xk + ", Xj = " + Xj + ", Xi = " + Xi); logger.info("Xi = {}, Xj = {}, Xk = {}", Xi, Xj, Xk); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); logger.info("q-p = {}", p.subtract(q)); } return false; } } } } return true; } /** * Get a (constant) QLRSolvablePolynomial<C> element from a long * value. * @param a long. * @return a QLRSolvablePolynomial<C>. */ @Override public QLRSolvablePolynomial fromInteger(long a) { return new QLRSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) QLRSolvablePolynomial<C> element from a BigInteger * value. * @param a BigInteger. * @return a QLRSolvablePolynomial<C>. */ @Override public QLRSolvablePolynomial fromInteger(BigInteger a) { return new QLRSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public QLRSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public QLRSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public QLRSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { QLRSolvablePolynomial r = getZERO(); // copy( ZERO ); ExpVector e; C a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (QLRSolvablePolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public QLRSolvablePolynomial copy(QLRSolvablePolynomial c) { return new QLRSolvablePolynomial(this, c.getMap()); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return QLRSolvablePolynomial from s. */ @Override public QLRSolvablePolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next QLRSolvablePolynomial from r. */ @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); QLRSolvablePolynomial p = null; try { GenSolvablePolynomial s = pt.nextSolvablePolynomial(); p = new QLRSolvablePolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial univariate(int i) { return (QLRSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial univariate(int i, long e) { return (QLRSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override @SuppressWarnings("unchecked") public QLRSolvablePolynomial univariate(int modv, int i, long e) { return (QLRSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { QLRSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public QLRSolvablePolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public QLRSolvablePolynomialRing extend(int i, boolean top) { GenPolynomialRing pfac = super.extend(i, top); QLRSolvablePolynomialRing spfac = new QLRSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @return extended polynomial ring factory. */ @Override public QLRSolvablePolynomialRing extend(String[] vn) { return extend(vn, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vn names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ @Override public QLRSolvablePolynomialRing extend(String[] vn, boolean top) { GenPolynomialRing pfac = super.extend(vn, top); QLRSolvablePolynomialRing spfac = new QLRSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.table.extend(this.table); spfac.polCoeff.coeffTable.extend(this.polCoeff.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public QLRSolvablePolynomialRing contract(int i) { GenPolynomialRing pfac = super.contract(i); QLRSolvablePolynomialRing spfac = new QLRSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.table.contract(this.table); spfac.polCoeff.coeffTable.contract(this.polCoeff.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public QLRSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public QLRSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing pfac = super.reverse(partial); QLRSolvablePolynomialRing spfac = new QLRSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.getVars()); spfac.partial = partial; spfac.table.reverse(this.table); spfac.polCoeff.coeffTable.reverse(this.polCoeff.coeffTable); return spfac; } /** * Rational function from integral polynomial coefficients. Represent as * polynomial with type C coefficients. * @param A polynomial with integral polynomial coefficients to be * converted. * @return polynomial with type C coefficients. */ public QLRSolvablePolynomial fromPolyCoefficients(GenSolvablePolynomial> A) { QLRSolvablePolynomial B = getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenSolvablePolynomial a = (GenSolvablePolynomial) y.getValue(); //C p = new C(qfac, a); C p = qpfac.create(a); if (!p.isZERO()) { B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(QLRSolvablePolynomial A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); if (!a.denominator().isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.numerator(); // can not be zero if (!p.isZERO()) { B.doPutToMap(e, p); } } return B; } /** * Integral function from rational polynomial coefficients. Represent as * polynomial with type GenSolvablePolynomial coefficients. * @param A polynomial with rational polynomial coefficients to be * converted. * @return polynomial with type GenSolvablePolynomial coefficients. */ public RecSolvablePolynomial toPolyCoefficients(GenPolynomial A) { RecSolvablePolynomial B = polCoeff.getZERO().copy(); if (A == null || A.isZERO()) { return B; } for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); if (!a.denominator().isONE()) { throw new IllegalArgumentException("den != 1 not supported: " + a); } GenPolynomial p = a.numerator(); // can not be zero if (!p.isZERO()) { B.doPutToMap(e, p); } } return B; } } java-algebra-system-2.7.200/src/edu/jas/poly/Quotient.java000066400000000000000000000273261445075545500233270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; import edu.jas.structure.RingElem; /** * Quotient element based on RingElem pairs. Objects of this class are * immutable. * @author Heinz Kredel */ public class Quotient> implements RingElem>, QuotPair { private static final Logger logger = LogManager.getLogger(Quotient.class); private static final boolean debug = logger.isDebugEnabled(); /** * Quotient class factory data structure. */ public final QuotientRing ring; /** * Numerator part of the element data structure. */ public final C num; /** * Denominator part of the element data structure. */ public final C den; /** * The constructor creates a Quotient object from a ring factory. * @param r ring factory. */ public Quotient(QuotientRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a Quotient object from a ring factory and a * numerator element. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator. */ public Quotient(QuotientRing r, C n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a Quotient object from a ring factory and a * numerator and denominator element. * @param r ring factory. * @param n numerator. * @param d denominator. */ public Quotient(QuotientRing r, C n, C d) { this(r, n, d, false); } /** * The constructor creates a Quotient object from a ring factory and a * numerator and denominator element. * @param r ring factory. * @param n numerator. * @param d denominator. * @param isred true if gcd(n,d) == 1, else false. */ @SuppressWarnings("unchecked") protected Quotient(QuotientRing r, C n, C d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = n.negate(); d = d.negate(); } if (isred) { num = n; den = d; return; } // must reduce to lowest terms if (n instanceof GcdRingElem && d instanceof GcdRingElem) { GcdRingElem ng = (GcdRingElem) n; GcdRingElem dg = (GcdRingElem) d; C gcd = (C) ng.gcd(dg); if (debug) { logger.info("gcd = {}", gcd); } //RingElem gcd = ring.ring.getONE(); if (gcd.isONE()) { num = n; den = d; } else { num = n.divide(gcd); den = d.divide(gcd); } // } else { // univariate polynomial? } else { logger.warn("gcd = ????: {}, {}", n.getClass(), d.getClass()); num = n; den = d; } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public QuotientRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public C numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public C denominator() { return den; } /** * Is Quotient a constant. Not implemented. * @throws UnsupportedOperationException. */ public boolean isConstant() { throw new UnsupportedOperationException("isConstant not implemented"); } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Quotient copy() { return new Quotient(ring, num, den, true); } /** * Is Quotient zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is Quotient one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.equals(den); } /** * Is Quotient unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (num.isZERO()) { return false; } return true; } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(); if (den.isONE()) { return s + " }"; } return s + "| " + den.toString() + " }"; } return "Quotient[ " + num.toString() + " / " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return "Quotient( " + num.toScript() + " , " + den.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Quotient comparison. * @param b Quotient. * @return sign(this-b). */ @Override public int compareTo(Quotient b) { if (b == null || b.isZERO()) { return this.signum(); } C r = num.multiply(b.den); C s = den.multiply(b.num); C x = r.subtract(s); return x.signum(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Quotient)) { return false; } Quotient a = (Quotient) b; return (0 == compareTo(a)); } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * Quotient absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Quotient abs() { return new Quotient(ring, num.abs(), den, true); } /** * Quotient summation. * @param S Quotient. * @return this+S. */ public Quotient sum(Quotient S) { if (S == null || S.isZERO()) { return this; } C n = num.multiply(S.den); n = n.sum(den.multiply(S.num)); C d = den.multiply(S.den); return new Quotient(ring, n, d, false); } /** * Quotient negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Quotient negate() { return new Quotient(ring, num.negate(), den, true); } /** * Quotient signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return num.signum(); } /** * Quotient subtraction. * @param S Quotient. * @return this-S. */ public Quotient subtract(Quotient S) { if (S == null || S.isZERO()) { return this; } C n = num.multiply(S.den); n = n.subtract(den.multiply(S.num)); C d = den.multiply(S.den); return new Quotient(ring, n, d, false); } /** * Quotient division. * @param S Quotient. * @return this/S. */ public Quotient divide(Quotient S) { return multiply(S.inverse()); } /** * Quotient inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this. */ public Quotient inverse() { return new Quotient(ring, den, num, true); } /** * Quotient remainder. * @param S Quotient. * @return this - (this/S)*S. */ public Quotient remainder(Quotient S) { if (num.isZERO()) { throw new ArithmeticException("element not invertible " + this); } return ring.getZERO(); } /** * Quotient and remainder by division of this by S. * @param S a Quotient * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public Quotient[] quotientRemainder(Quotient S) { return new Quotient[] { divide(S), remainder(S) }; } /** * Quotient multiplication. * @param S Quotient. * @return this*S. */ public Quotient multiply(Quotient S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } C n = num.multiply(S.num); C d = den.multiply(S.den); return new Quotient(ring, n, d, false); } /** * Quotient monic. * @return this with monic value part. */ public Quotient monic() { logger.info("monic not implemented"); return this; } /** * Greatest common divisor. Note: If not defined, throws * UnsupportedOperationException. * @param b other element. * @return gcd(this,b). */ public Quotient gcd(Quotient b) { if (b == null || b.isZERO()) { return this; } if (this.isZERO()) { return b; } if (num instanceof GcdRingElem && den instanceof GcdRingElem && b.num instanceof GcdRingElem && b.den instanceof GcdRingElem) { return ring.getONE(); } throw new UnsupportedOperationException("gcd not implemented " + num.getClass().getName()); } /** * Extended greatest common divisor. Note: If not defined, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ @SuppressWarnings("unchecked") public Quotient[] egcd(Quotient b) { Quotient[] ret = (Quotient[]) new Quotient[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (b == null || b.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = b; return ret; } if (num instanceof GcdRingElem && den instanceof GcdRingElem && b.num instanceof GcdRingElem && b.den instanceof GcdRingElem) { Quotient two = ring.fromInteger(2); ret[0] = ring.getONE(); ret[1] = (this.multiply(two)).inverse(); ret[2] = (b.multiply(two)).inverse(); return ret; } throw new UnsupportedOperationException("egcd not implemented " + num.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/poly/QuotientRing.java000066400000000000000000000156401445075545500241430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; // import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Quotient ring factory using RingElem and RingFactory. Objects of this class * are immutable. * @author Heinz Kredel */ public class QuotientRing> implements RingFactory>, QuotPairFactory> { private static final Logger logger = LogManager.getLogger(QuotientRing.class); private static final boolean debug = logger.isDebugEnabled(); /** * Ring factory of this factory. */ public final RingFactory ring; /** * The constructor creates a QuotientRing object from a RingFactory. * @param r ring factory. */ public QuotientRing(RingFactory r) { ring = r; } /** * Factory for base elements. */ public RingFactory pairFactory() { return ring; } /** * Create from numerator. */ public Quotient create(C n) { return new Quotient(this, n); } /** * Create from numerator, denominator pair. */ public Quotient create(C n, C d) { return new Quotient(this, n, d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.isFinite(); } /** * Copy Quotient element c. * @param c * @return a copy of c. */ public Quotient copy(Quotient c) { return new Quotient(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as Quotient. */ public Quotient getZERO() { return new Quotient(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Quotient. */ public Quotient getONE() { return new Quotient(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = ring.generators(); List> gens = new ArrayList>(rgens.size()); C one = ring.getONE(); for (C c : rgens) { gens.add(new Quotient(this, c)); if (!c.isONE()) { gens.add(new Quotient(this, one, c)); } } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Quotient element from a BigInteger value. * @param a BigInteger. * @return a Quotient. */ public Quotient fromInteger(java.math.BigInteger a) { return new Quotient(this, ring.fromInteger(a)); } /** * Get a Quotient element from a long value. * @param a long. * @return a Quotient. */ public Quotient fromInteger(long a) { return new Quotient(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "Quotient[ " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "QuotientRing(" + ring.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof QuotientRing)) { return false; } QuotientRing a = (QuotientRing) b; return ring.equals(a.ring); } /** * Hash code for this quotient ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); return h; } /** * Quotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Quotient random(int n) { C r = ring.random(n); C s = ring.random(n); while (s.isZERO()) { s = ring.random(n); } return new Quotient(this, r, s, false); } /** * Quotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public Quotient random(int n, Random rnd) { C r = ring.random(n, rnd); C s = ring.random(n, rnd); while (s.isZERO()) { s = ring.random(n, rnd); } return new Quotient(this, r, s, false); } /** * Parse Quotient from String. * @param s String. * @return Quotient from s. */ public Quotient parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { C n = ring.parse(s); return new Quotient(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); C n = ring.parse(s1); C d = ring.parse(s2); return new Quotient(this, n, d); } /** * Parse Quotient from Reader. * @param r Reader. * @return next Quotient from r. */ public Quotient parse(Reader r) { C x = ring.parse(r); if (debug) { logger.debug("x = {}", x); } return new Quotient(this, x); } } java-algebra-system-2.7.200/src/edu/jas/poly/RecSolvablePolynomial.java000066400000000000000000000754551445075545500257720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.RingElem; /** * RecSolvablePolynomial generic recursive solvable polynomials implementing * RingElem. n-variate ordered solvable polynomials over solvable polynomial * coefficients. Objects of this class are intended to be immutable. The * implementation is based on TreeMap respectively SortedMap from exponents to * coefficients by extension of GenPolynomial. * @param coefficient type * @author Heinz Kredel */ public class RecSolvablePolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final RecSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(RecSolvablePolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero RecSolvablePolynomial. * @param r solvable polynomial ring factory. */ public RecSolvablePolynomial(RecSolvablePolynomialRing r) { super(r); ring = r; } /** * Constructor for RecSolvablePolynomial. * @param r solvable polynomial ring factory. * @param e exponent. */ public RecSolvablePolynomial(RecSolvablePolynomialRing r, ExpVector e) { this(r); val.put(e, ring.getONECoefficient()); } /** * Constructor for RecSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public RecSolvablePolynomial(RecSolvablePolynomialRing r, GenPolynomial c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for RecSolvablePolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public RecSolvablePolynomial(RecSolvablePolynomialRing r, GenPolynomial c) { this(r, c, r.evzero); } /** * Constructor for RecSolvablePolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public RecSolvablePolynomial(RecSolvablePolynomialRing r, GenSolvablePolynomial> S) { this(r, S.val); } /** * Constructor for RecSolvablePolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected RecSolvablePolynomial(RecSolvablePolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public RecSolvablePolynomialRing factory() { return ring; } /** * Clone this RecSolvablePolynomial. * @see java.lang.Object#clone() */ @Override public RecSolvablePolynomial copy() { return new RecSolvablePolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof RecSolvablePolynomial)) { return false; } // compare also coeffTable? return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * RecSolvablePolynomial multiplication. * @param Bp RecSolvablePolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // cannot @Override, @NoOverride public RecSolvablePolynomial multiply(RecSolvablePolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == Bp.ring.nvar); if (debug) { logger.info("ring = {}", ring.toScript()); } final boolean commute = ring.table.isEmpty(); final boolean commuteCoeff = ring.coeffTable.isEmpty(); GenPolynomialRing cfac = (GenPolynomialRing) ring.coFac; RecSolvablePolynomial Dp = ring.getZERO().copy(); ExpVector Z = ring.evzero; ExpVector Zc = cfac.evzero; GenPolynomial one = ring.getONECoefficient(); RecSolvablePolynomial C1 = null; RecSolvablePolynomial C2 = null; Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); if (debug) logger.info("input A = {}", this); for (Map.Entry> y : A.entrySet()) { GenPolynomial a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = {}", e, a); int[] ep = e.dependencyOnVariables(); int el1 = ring.nvar + 1; if (ep.length > 0) { el1 = ep[0]; } //int el1s = ring.nvar + 1 - el1; if (debug) logger.info("input B = {}", Bp); for (Map.Entry> x : Bk) { GenPolynomial b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial coefficient multiplication e*b = P_eb, for a*((e*b)*f) RecSolvablePolynomial Cps = ring.getZERO().copy(); RecSolvablePolynomial Cs = null; if (commuteCoeff || b.isConstant() || e.isZERO()) { // symmetric Cps.doAddTo(b, e); if (debug) logger.info("symmetric coeff, e*b: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff, e*b: b = {}, e = {}", b, e); for (Map.Entry z : b.val.entrySet()) { C c = z.getValue(); GenPolynomial cc = b.ring.valueOf(c); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = 0; if (gp.length > 0) { gl1 = gp[gp.length - 1]; } int gl1s = b.ring.nvar + 1 - gl1; if (debug) { logger.info("gl1s = {}", gl1s); } // split e = e1 * e2, g = g2 * g1 (= g1 * g2) ExpVector e1 = e; ExpVector e2 = Z; if (!e.isZERO()) { e1 = e.subst(el1, 0); e2 = Z.subst(el1, e.getVal(el1)); } ExpVector e4; ExpVector g1 = g; ExpVector g2 = Zc; if (!g.isZERO()) { g1 = g.subst(gl1, 0); g2 = Zc.subst(gl1, g.getVal(gl1)); } if (debug) { logger.info("coeff, e1 = {}, e2 = {}, Cps = {}", e1, e2, Cps); logger.info("coeff, g1 = {}, g2 = {}", g1, g2); } TableRelation> crel = ring.coeffTable.lookup(e2, g2); if (debug) logger.info("coeff, crel = {}", crel.p); //logger.info("coeff, e = {}, g = {}, crel = {}", e, g, crel); Cs = new RecSolvablePolynomial(ring, crel.p); // rest of multiplication and update relations if (crel.f != null) { // process remaining right power GenPolynomial c2 = b.ring.valueOf(crel.f); C2 = new RecSolvablePolynomial(ring, c2, Z); Cs = Cs.multiply(C2); if (crel.e == null) { e4 = e2; } else { e4 = e2.subtract(crel.e); } ring.coeffTable.update(e4, g2, Cs); } if (crel.e != null) { // process remaining left power C1 = new RecSolvablePolynomial(ring, one, crel.e); Cs = C1.multiply(Cs); ring.coeffTable.update(e2, g2, Cs); } if (!g1.isZERO()) { // process remaining right part GenPolynomial c2 = b.ring.valueOf(g1); C2 = new RecSolvablePolynomial(ring, c2, Z); Cs = Cs.multiply(C2); } if (!e1.isZERO()) { // process remaining left part C1 = new RecSolvablePolynomial(ring, one, e1); Cs = C1.multiply(Cs); } //System.out.println("e1*Cs*g1 = " + Cs); Cs = Cs.multiplyLeft(cc); // assume c, coeff(cc) commutes with Cs //Cps = (RecSolvablePolynomial) Cps.sum(Cs); Cps.doAddTo(Cs); } // end b loop if (debug) logger.info("coeff, Cs = {}, Cps = {}", Cs, Cps); } if (debug) logger.info("coeff-poly: Cps = {}", Cps); // polynomial multiplication P_eb*f, for a*(P_eb*f) RecSolvablePolynomial Dps = ring.getZERO().copy(); RecSolvablePolynomial Ds = null; RecSolvablePolynomial D1, D2; if (commute || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly, P_eb*f: Cps = {}, f = {}", Cps, f); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = new RecSolvablePolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly, P_eb*f: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 GenPolynomial c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = ring.valueOf(h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) { logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); logger.info("poly, g2 = {}, g2 = {}", g2, f2); } TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new RecSolvablePolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = ring.valueOf(rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = ring.valueOf(rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = ring.valueOf(f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = ring.valueOf(g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } Ds = Ds.multiplyLeft(c); // assume c commutes with Cs Dps.doAddTo(Ds); } // end Dps loop Ds = Dps; } if (debug) { logger.info("recursion+: Ds = {}, a = {}", Ds, a); } // polynomial coefficient multiplication a*(P_eb*f) = a*Ds Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric if (debug) logger.info("recursion-: Ds = {}", Ds); Dp.doAddTo(Ds); if (debug) logger.info("end B loop: Dp = {}", Dp); } // end B loop if (debug) logger.info("end A loop: Dp = {}", Dp); } // end A loop return Dp; } /** * RecSolvablePolynomial left and right multiplication. Product with two * polynomials. * @param S RecSolvablePolynomial. * @param T RecSolvablePolynomial. * @return S*this*T. */ // cannot @Override, @NoOverride public RecSolvablePolynomial multiply(RecSolvablePolynomial S, RecSolvablePolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * RecSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b coefficient polynomial. * @return this*b, where * is coefficient multiplication. */ // cannot @Override //public RecSolvablePolynomial multiply(GenPolynomial b) { //public GenSolvablePolynomial> multiply(GenPolynomial b) { public RecSolvablePolynomial recMultiply(GenPolynomial b) { RecSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Cp = new RecSolvablePolynomial(ring, b, ring.evzero); return multiply(Cp); // wrong: // Map> Cm = Cp.val; //getMap(); // Map> Am = val; // for (Map.Entry> y : Am.entrySet()) { // ExpVector e = y.getKey(); // GenPolynomial a = y.getValue(); // GenPolynomial c = a.multiply(b); // if (!c.isZERO()) { // Cm.put(e, c); // } // } // return Cp; } /** * RecSolvablePolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public RecSolvablePolynomial multiply(GenPolynomial b, GenPolynomial c) { RecSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } RecSolvablePolynomial Cb = ring.valueOf(b); RecSolvablePolynomial Cc = ring.valueOf(c); return Cb.multiply(this).multiply(Cc); // wrong: // Map> Cm = Cp.val; //getMap(); // Map> Am = val; // for (Map.Entry> y : Am.entrySet()) { // ExpVector e = y.getKey(); // GenPolynomial a = y.getValue(); // GenPolynomial d = b.multiply(a).multiply(c); // if (!d.isZERO()) { // Cm.put(e, d); // } // } // return Cp; } /* * RecSolvablePolynomial multiplication. Product with coefficient ring * element. * @param b coefficient of coefficient. * @return this*b, where * is coefficient multiplication. */ //@Override not possible, @NoOverride //public RecSolvablePolynomial multiply(C b) { ... } /** * RecSolvablePolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } GenPolynomial b = ring.getONECoefficient(); return multiply(b, e); } /** * RecSolvablePolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public RecSolvablePolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } GenPolynomial b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * RecSolvablePolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiply(GenPolynomial b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } RecSolvablePolynomial Cp = ring.valueOf(b, e); return multiply(Cp); } /** * RecSolvablePolynomial left and right multiplication. Product with ring * element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public RecSolvablePolynomial multiply(GenPolynomial b, ExpVector e, GenPolynomial c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } RecSolvablePolynomial Cp = ring.valueOf(b, e); RecSolvablePolynomial Dp = ring.valueOf(c, f); return multiply(Cp, Dp); } /** * RecSolvablePolynomial multiplication. Left product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiplyLeft(GenPolynomial b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } RecSolvablePolynomial Cp = ring.valueOf(b, e); return Cp.multiply(this); } /** * RecSolvablePolynomial multiplication. Left product with exponent vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } RecSolvablePolynomial Cp = ring.valueOf(e); return Cp.multiply(this); } /** * RecSolvablePolynomial multiplication. Left product with coefficient ring * element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public RecSolvablePolynomial multiplyLeft(GenPolynomial b) { RecSolvablePolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } GenSolvablePolynomial bb = null; if (b instanceof GenSolvablePolynomial) { //throw new RuntimeException("wrong method dispatch in JRE "); logger.debug("warn: wrong method dispatch in JRE multiply(b) - trying to fix"); bb = (GenSolvablePolynomial) b; } Map> Cm = Cp.val; //getMap(); Map> Am = val; GenPolynomial c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); if (bb != null) { GenSolvablePolynomial aa = (GenSolvablePolynomial) a; c = bb.multiply(aa); } else { c = b.multiply(a); } if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * RecSolvablePolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * RecSolvablePolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public RecSolvablePolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * RecSolvablePolynomial multiplication. Commutative product with exponent * vector. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ public RecSolvablePolynomial shift(ExpVector f) { RecSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } /** * RecSolvablePolynomial multiplication. Commutative product with * coefficient. * @param b coefficient. * @return B*b, where * is commutative multiplication with respect to main * variables. */ public RecSolvablePolynomial multiplyRightComm(GenPolynomial b) { RecSolvablePolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (b == null || b.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); a = a.multiply(b); if (!a.isZERO()) { Cm.put(e, a); } } return C; } /** * RecSolvablePolynomial right coefficients from left coefficients. * Note: R is represented as a polynomial with left coefficients, the * implementation can at the moment not distinguish between left and right * coefficients. * @return R = sum( Xi bi ), with this = * sum(ai Xi ) and eval(sum(Xi * bi)) == sum(ai Xi) */ @SuppressWarnings("cast") @Override public GenSolvablePolynomial> rightRecursivePolynomial() { if (this.isZERO()) { return this; } if (!(this instanceof RecSolvablePolynomial)) { return this; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { return this; } RecSolvablePolynomial R = rfac.getZERO().copy(); RecSolvablePolynomial p = this; RecSolvablePolynomial r; while (!p.isZERO()) { ExpVector f = p.leadingExpVector(); GenPolynomial a = p.leadingBaseCoefficient(); //r = h.multiply(a); // wrong method dispatch // right: f*a //okay: r = onep.multiply(one, f, a, zero); // right: (1 f) * 1 * (a zero) r = rfac.valueOf(f).multiply(rfac.valueOf(a)); // right: (1 f) * 1 * (a zero) //System.out.println("a,f = " + a + ", " + f); // + ", h.ring = " + h.ring.toScript()); //System.out.println("f*a = " + r); // + ", r.ring = " + r.ring.toScript()); p = (RecSolvablePolynomial) p.subtract(r); R = (RecSolvablePolynomial) R.sum(a, f); //R.doPutToMap(f, a); } return R; } /** * Evaluate RecSolvablePolynomial as right coefficients polynomial. * Note: R is represented as a polynomial with left coefficients, the * implementation can at the moment not distinguish between left and right * coefficients. * @return this as evaluated polynomial R. R = sum( Xi * bi ), this = sum(ai Xi ) = * eval(sum(Xi bi)) */ @SuppressWarnings("cast") @Override public GenSolvablePolynomial> evalAsRightRecursivePolynomial() { if (this.isONE() || this.isZERO()) { return this; } if (!(this instanceof RecSolvablePolynomial)) { return this; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { return this; } RecSolvablePolynomial q = rfac.getZERO(); RecSolvablePolynomial s; RecSolvablePolynomial r = (RecSolvablePolynomial) this; for (Map.Entry> y : r.getMap().entrySet()) { ExpVector f = y.getKey(); GenPolynomial a = y.getValue(); // f.multiply(a); // wrong method dispatch // right: f*a // onep.multiply(f).multiply(a) // should do now //okay: s = onep.multiply(one, f, a, zero); // right: (1 f) * 1 * (a zero) s = rfac.valueOf(f).multiply(rfac.valueOf(a)); // right: (1 f) * 1 * (a zero) q = (RecSolvablePolynomial) q.sum(s); } return q; } /** * Test RecSolvablePolynomial right coefficients polynomial. Note: R * is represented as a polynomial with left coefficients, the implementation * can at the moment not distinguish between left and right coefficients. * @param R GenSolvablePolynomial with right coefficients. * @return true, if R is polynomial with right coefficients of this. R = * sum( Xi bi ), with this = sum(ai * Xi ) and eval(sum(Xi bi)) == * sum(ai Xi) */ @SuppressWarnings("cast") @Override public boolean isRightRecursivePolynomial(GenSolvablePolynomial> R) { if (this.isZERO()) { return R.isZERO(); } if (this.isONE()) { return R.isONE(); } if (!(this instanceof RecSolvablePolynomial)) { return !(R instanceof RecSolvablePolynomial); } if (!(R instanceof RecSolvablePolynomial)) { return false; } RecSolvablePolynomialRing rfac = (RecSolvablePolynomialRing) ring; if (rfac.coeffTable.isEmpty()) { RecSolvablePolynomialRing rf = (RecSolvablePolynomialRing) R.ring; return rf.coeffTable.isEmpty(); } RecSolvablePolynomial p = (RecSolvablePolynomial) this; RecSolvablePolynomial q = (RecSolvablePolynomial) R.evalAsRightRecursivePolynomial(); p = (RecSolvablePolynomial) PolyUtil. monic(p); q = (RecSolvablePolynomial) PolyUtil. monic(q); return p.equals(q); } } java-algebra-system-2.7.200/src/edu/jas/poly/RecSolvablePolynomialRing.java000066400000000000000000000616261445075545500266050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * RecSolvablePolynomialRing generic recursive solvable polynomial factory * implementing RingFactory and extending GenSolvablePolynomialRing factory. * Factory for n-variate ordered solvable polynomials over solvable polynomial * coefficients. The non-commutative multiplication relations are maintained in * a relation table and the non-commutative multiplication relations between the * coefficients and the variables are maintained in a coefficient-polynomial * relation table. Almost immutable object, except variable names and relation * table contents. * @param coefficient type. * @author Heinz Kredel */ public class RecSolvablePolynomialRing> extends GenSolvablePolynomialRing> { /** * The solvable multiplication relations between variables and coefficients. */ public final RelationTable> coeffTable; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public /*final*/ RecSolvablePolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public /*final*/ RecSolvablePolynomial ONE; private static final Logger logger = LogManager.getLogger(RecSolvablePolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public RecSolvablePolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public RecSolvablePolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public RecSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public RecSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public RecSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public RecSolvablePolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public RecSolvablePolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public RecSolvablePolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } coeffTable = new RelationTable>(this, true); ZERO = new RecSolvablePolynomial(this); GenPolynomial coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new RecSolvablePolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public RecSolvablePolynomialRing(RingFactory> cf, RecSolvablePolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * Generate the coefficient relation table of the solvable * polynomial ring from a polynomial list of relations. * @param rel polynomial list of relations [..., ei, fj, pij, ... ] with ei * * fj = pij. */ public void addCoeffRelations(List>> rel) { coeffTable.addRelations(rel); } /** * Generate the coefficient relation table of the solvable * polynomial ring from a solvable polynomial list of relations. * @param rel solvable polynomial list of relations [..., ei, fj, pij, ... ] * with ei * fj = pij. */ public void addSolvCoeffRelations(List>> rel) { coeffTable.addSolvRelations(rel); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (coeffTable.size() > 0) { String rel = coeffTable.toScript(); s.append(",coeffpolrel="); s.append(rel); } if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof RecSolvablePolynomialRing)) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } RecSolvablePolynomialRing oring = (RecSolvablePolynomialRing) other; // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!coeffTable.equals(oring.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as RecSolvablePolynomial. */ @Override public RecSolvablePolynomial getZERO() { if (ZERO == null || !ZERO.isZERO()) { // happened since May 5 2022 // Name : java-11-openjdk-headless, java-17-openjdk-headless // Version : 11.0.15.0, 17.0.4 // Release : 150000.3.80.1, 150400.3.3.1 RecSolvablePolynomial x = ZERO; ZERO = new RecSolvablePolynomial(this); logger.info("warn: ZERO@get |{}| wrong fix to {}", x, ZERO); } return ZERO; } /** * Get the one element. * @return 1 as RecSolvablePolynomial. */ @Override public RecSolvablePolynomial getONE() { if (ONE == null || !ONE.isONE()) { ONE = new RecSolvablePolynomial(this, coFac.getONE(), evzero); logger.info("warn: ONE@get {}", ONE); } return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (coeffTable.isEmpty()) { return super.isCommutative(); } return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @SuppressWarnings("unused") @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } RecSolvablePolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); //System.out.println("Rec gens = " + gens); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (RecSolvablePolynomial) gens.get(i); for (int j = i + 1; j < ngen; j++) { Xj = (RecSolvablePolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (RecSolvablePolynomial) gens.get(k); p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { if (logger.isInfoEnabled()) { logger.info("Xi = {}, Xj = {}, Xk = {}", Xi, Xj, Xk); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); } return false; } } } } return true; } /** * Get a (constant) RecSolvablePolynomial<C> element from a * coefficient value. * @param a coefficient. * @return a RecSolvablePolynomial<C>. */ @Override public RecSolvablePolynomial valueOf(GenPolynomial a) { return new RecSolvablePolynomial(this, a); } /** * Get a RecSolvablePolynomial<C> element from an exponent vector. * @param e exponent vector. * @return a RecSolvablePolynomial<C>. */ @Override public RecSolvablePolynomial valueOf(ExpVector e) { return new RecSolvablePolynomial(this, coFac.getONE(), e); } /** * Get a RecSolvablePolynomial<C> element from a coefficient and an * exponent vector. * @param a coefficient. * @param e exponent vector. * @return a RecSolvablePolynomial<C>. */ @Override public RecSolvablePolynomial valueOf(GenPolynomial a, ExpVector e) { return new RecSolvablePolynomial(this, a, e); } /** * Get a (constant) RecSolvablePolynomial<C> element from a long value * @param a long. * @return a RecSolvablePolynomial<C>. */ @Override public RecSolvablePolynomial fromInteger(long a) { return new RecSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) RecSolvablePolynomial<C> element from a BigInteger * value. * @param a BigInteger. * @return a RecSolvablePolynomial<C>. */ @Override public RecSolvablePolynomial fromInteger(BigInteger a) { return new RecSolvablePolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public RecSolvablePolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public RecSolvablePolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(2, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public RecSolvablePolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public RecSolvablePolynomial random(int k, int l, int d, float q, Random rnd) { RecSolvablePolynomial r = getZERO(); // copy( ZERO ); ExpVector e; GenPolynomial a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); //System.out.println("a_random = " + a); r = (RecSolvablePolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public RecSolvablePolynomial copy(RecSolvablePolynomial c) { return new RecSolvablePolynomial(this, c.val); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return RecSolvablePolynomial from s. */ @Override public RecSolvablePolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next RecSolvablePolynomial from r. */ @Override @SuppressWarnings("unchecked") public RecSolvablePolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); RecSolvablePolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new RecSolvablePolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public RecSolvablePolynomial univariate(int i) { return (RecSolvablePolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public RecSolvablePolynomial univariate(int i, long e) { return (RecSolvablePolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public RecSolvablePolynomial univariate(int modv, int i, long e) { return (RecSolvablePolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { //return castToSolvableList( super.univariateList() ); return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { RecSolvablePolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public RecSolvablePolynomialRing extend(int i) { return extend(i, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended solvable polynomial ring factory. */ @Override public RecSolvablePolynomialRing extend(int i, boolean top) { GenSolvablePolynomialRing> pfac = super.extend(i, top); RecSolvablePolynomialRing spfac = new RecSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars, pfac.table); //spfac.table.extend(this.table); // pfac.table spfac.coeffTable.extend(this.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vs names for extended variables. * @return extended polynomial ring factory. */ @Override public RecSolvablePolynomialRing extend(String[] vs) { return extend(vs, false); } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vs names for extended variables. * @param top true for TOP term order, false for POT term order. * @return extended polynomial ring factory. */ @Override public RecSolvablePolynomialRing extend(String[] vs, boolean top) { GenSolvablePolynomialRing> pfac = super.extend(vs, top); RecSolvablePolynomialRing spfac = new RecSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars, pfac.table); //spfac.table.extend(this.table); // is in pfac.table spfac.coeffTable.extend(this.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public RecSolvablePolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); RecSolvablePolynomialRing spfac = new RecSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.table.contract(this.table); spfac.coeffTable.contract(this.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public RecSolvablePolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public RecSolvablePolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); RecSolvablePolynomialRing spfac = new RecSolvablePolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.partial = partial; spfac.table.reverse(this.table); spfac.coeffTable.reverse(this.coeffTable); return spfac; } /** * Distributive representation as polynomial with all main variables. * @return distributive polynomial ring factory. */ @SuppressWarnings({ "cast", "unchecked" }) public static > // must be static because of types GenSolvablePolynomialRing distribute(RecSolvablePolynomialRing rf) { // setup solvable polynomial ring GenSolvablePolynomialRing fring = (GenSolvablePolynomialRing) (GenSolvablePolynomialRing) rf; GenSolvablePolynomialRing pfd = fring.distribute(); // add coefficient relations: List>> rl = (List>>) (List) PolynomialList .castToList(rf.coeffTable.relationList()); List> rld = PolyUtil. distribute(pfd, rl); pfd.table.addRelations(rld); //System.out.println("pfd = " + pfd.toScript()); return pfd; } /** * Permutation of polynomial ring variables. * @param P permutation. * @return P(this). */ @Override public GenSolvablePolynomialRing> permutation(List P) { if (!coeffTable.isEmpty()) { throw new UnsupportedOperationException("permutation with coeff relations: " + this); } GenSolvablePolynomialRing> pfac = (GenSolvablePolynomialRing>) super.permutation( P); return pfac; } } java-algebra-system-2.7.200/src/edu/jas/poly/RecSolvableWordPolynomial.java000066400000000000000000000622161445075545500266150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.Set; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.RingElem; /** * RecSolvableWordPolynomial generic recursive solvable polynomials implementing * RingElem. n-variate ordered solvable polynomials over non-commutative word * polynomial coefficients. Objects of this class are intended to be immutable. * The implementation is based on TreeMap respectively SortedMap from exponents * to coefficients by extension of GenPolynomial. * @param base coefficient type * @author Heinz Kredel */ public class RecSolvableWordPolynomial> extends GenSolvablePolynomial> { /** * The factory for the recursive solvable polynomial ring. Hides super.ring. */ public final RecSolvableWordPolynomialRing ring; private static final Logger logger = LogManager.getLogger(RecSolvableWordPolynomial.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for zero RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. */ public RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r) { super(r); ring = r; } /** * Constructor for RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param e exponent. */ public RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r, ExpVector e) { this(r); val.put(e, ring.getONECoefficient()); } /** * Constructor for RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. * @param e exponent. */ public RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r, GenWordPolynomial c, ExpVector e) { this(r); if (c != null && !c.isZERO()) { val.put(e, c); } } /** * Constructor for RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param c coefficient polynomial. */ public RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r, GenWordPolynomial c) { this(r, c, r.evzero); } /** * Constructor for RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param S solvable polynomial. */ public RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r, GenSolvablePolynomial> S) { this(r, S.val); } /** * Constructor for RecSolvableWordPolynomial. * @param r solvable polynomial ring factory. * @param v the SortedMap of some other (solvable) polynomial. */ protected RecSolvableWordPolynomial(RecSolvableWordPolynomialRing r, SortedMap> v) { this(r); val.putAll(v); // assume no zero coefficients } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ @Override public RecSolvableWordPolynomialRing factory() { return ring; } /** * Clone this RecSolvableWordPolynomial. * @see java.lang.Object#clone() */ @Override public RecSolvableWordPolynomial copy() { return new RecSolvableWordPolynomial(ring, this.val); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof RecSolvableWordPolynomial)) { return false; } return super.equals(B); } /** * Hash code for this polynomial. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return super.hashCode(); } /** * RecSolvableWordPolynomial multiplication. * @param Bp RecSolvableWordPolynomial. * @return this*Bp, where * denotes solvable multiplication. */ // cannot @Override, @NoOverride public RecSolvableWordPolynomial multiply(RecSolvableWordPolynomial Bp) { if (Bp == null || Bp.isZERO()) { return ring.getZERO(); } if (this.isZERO()) { return this; } assert (ring.nvar == Bp.ring.nvar); if (debug) { logger.info("ring = {}", ring.toScript()); } final boolean commute = ring.table.isEmpty(); final boolean commuteCoeff = ring.coeffTable.isEmpty(); //GenWordPolynomialRing cfac = (GenWordPolynomialRing) ring.coFac; RecSolvableWordPolynomial Dp = ring.getZERO().copy(); RecSolvableWordPolynomial zero = ring.getZERO(); //.copy(); not needed ExpVector Z = ring.evzero; //Word Zc = cfac.wone; GenWordPolynomial one = ring.getONECoefficient(); RecSolvableWordPolynomial C1 = null; RecSolvableWordPolynomial C2 = null; Map> A = val; Map> B = Bp.val; Set>> Bk = B.entrySet(); if (debug) logger.info("input A = {}", this); for (Map.Entry> y : A.entrySet()) { GenWordPolynomial a = y.getValue(); ExpVector e = y.getKey(); if (debug) logger.info("e = {}, a = ", e, a); int[] ep = e.dependencyOnVariables(); int el1 = ring.nvar + 1; if (ep.length > 0) { el1 = ep[0]; } //int el1s = ring.nvar + 1 - el1; if (debug) logger.info("input B = {}", Bp); for (Map.Entry> x : Bk) { GenWordPolynomial b = x.getValue(); ExpVector f = x.getKey(); if (debug) logger.info("f = {}, b = {}", f, b); int[] fp = f.dependencyOnVariables(); int fl1 = 0; if (fp.length > 0) { fl1 = fp[fp.length - 1]; } int fl1s = ring.nvar + 1 - fl1; // polynomial coefficient multiplication e*b = P_eb, for a*((e*b)*f) RecSolvableWordPolynomial Cps = ring.getZERO().copy(); RecSolvableWordPolynomial Cs = null; if (commuteCoeff || b.isConstant() || e.isZERO()) { // symmetric //Cps = (RecSolvableWordPolynomial) zero.sum(b, e); Cps.doAddTo(b, e); if (debug) logger.info("symmetric coeff, e*b: b = {}, e = {}", b, e); } else { // unsymmetric if (debug) logger.info("unsymmetric coeff, e*b: b = {}, e = {}", b, e); for (Map.Entry z : b.val.entrySet()) { C c = z.getValue(); GenWordPolynomial cc = b.ring.getONE().multiply(c); Word g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); // split e = e1 * e2, g = g2 * g1 ExpVector g2 = g.leadingExpVector(); Word g1 = g.reductum(); //ExpVector g1; //System.out.println("c = " + c + ", g = " + g + ", g1 = " + g1 + ", g1 == 1: " + g1.isONE()); ExpVector e1 = e; ExpVector e2 = Z; if (!e.isZERO()) { e1 = e.subst(el1, 0); e2 = Z.subst(el1, e.getVal(el1)); } if (debug) { logger.info("coeff, e1 = {}, e2 = {}, Cps = {}", e1, e2, Cps); logger.info("coeff, g2 = {}, g2 = {}", g2, g1); } TableRelation> crel = ring.coeffTable.lookup(e2, g2); if (debug) logger.info("coeff, crel = {}", crel.p); //System.out.println("coeff, e = " + e + ", g = " + g + ", crel = " + crel); Cs = new RecSolvableWordPolynomial(ring, crel.p); // rest of multiplication and update relations if (crel.f != null) { // process remaining right power //GenWordPolynomial c2 = b.ring.getONE().multiply(crel.f); GenWordPolynomial c2 = b.ring.valueOf(crel.f); C2 = ring.valueOf(c2); //new RecSolvableWordPolynomial(ring, c2, Z); Cs = Cs.multiply(C2); ExpVector e4; if (crel.e == null) { e4 = e2; } else { e4 = e2.subtract(crel.e); } ring.coeffTable.update(e4, g2, Cs); } if (crel.e != null) { // process remaining left power C1 = ring.valueOf(crel.e); //new RecSolvableWordPolynomial(ring, one, crel.e); Cs = C1.multiply(Cs); ring.coeffTable.update(e2, g2, Cs); } if (!g1.isONE()) { // process remaining right part //GenWordPolynomial c2 = b.ring.getONE().multiply(g1); GenWordPolynomial c2 = b.ring.valueOf(g1); C2 = ring.valueOf(c2); //new RecSolvableWordPolynomial(ring, c2, Z); Cs = Cs.multiply(C2); } if (!e1.isZERO()) { // process remaining left part C1 = ring.valueOf(e1); //new RecSolvableWordPolynomial(ring, one, e1); Cs = C1.multiply(Cs); } //System.out.println("e1*Cs*g1 = " + Cs); Cs = Cs.multiplyLeft(cc); // assume c, coeff(cc) commutes with Cs //Cps = (RecSolvableWordPolynomial) Cps.sum(Cs); Cps.doAddTo(Cs); } // end b loop if (debug) logger.info("coeff, Cs = {}, Cps = {}", Cs, Cps); //System.out.println("coeff loop end, Cs = " + Cs + ", Cps = " + Cps); } if (debug) logger.info("coeff-poly: Cps = {}", Cps); // polynomial multiplication P_eb*f, for a*(P_eb*f) RecSolvableWordPolynomial Dps = ring.getZERO().copy(); RecSolvableWordPolynomial Ds = null; RecSolvableWordPolynomial D1, D2; if (commute || Cps.isConstant() || f.isZERO()) { // symmetric if (debug) logger.info("symmetric poly, P_eb*f: Cps = {}, f = {}", Cps, f); ExpVector g = e.sum(f); if (Cps.isConstant()) { Ds = ring.valueOf(Cps.leadingBaseCoefficient(), g); //new RecSolvableWordPolynomial(ring, Cps.leadingBaseCoefficient(), g); // symmetric! } else { Ds = Cps.shift(f); // symmetric } } else { // eventually unsymmetric if (debug) logger.info("unsymmetric poly, P_eb*f: Cps = {}, f = {}", Cps, f); for (Map.Entry> z : Cps.val.entrySet()) { // split g = g1 * g2, f = f1 * f2 GenWordPolynomial c = z.getValue(); ExpVector g = z.getKey(); if (debug) logger.info("g = {}, c = {}", g, c); int[] gp = g.dependencyOnVariables(); int gl1 = ring.nvar + 1; if (gp.length > 0) { gl1 = gp[0]; } int gl1s = ring.nvar + 1 - gl1; if (gl1s <= fl1s) { // symmetric ExpVector h = g.sum(f); if (debug) logger.info("disjoint poly: g = {}, f = {}, h = {}", g, f, h); Ds = (RecSolvableWordPolynomial) zero.sum(one, h); // symmetric! } else { ExpVector g1 = g.subst(gl1, 0); ExpVector g2 = Z.subst(gl1, g.getVal(gl1)); // bug el1, gl1 ExpVector g4; ExpVector f1 = f.subst(fl1, 0); ExpVector f2 = Z.subst(fl1, f.getVal(fl1)); if (debug) { logger.info("poly, g1 = {}, f1 = {}, Dps = {}", g1, f1, Dps); logger.info("poly, g2 = {}, f2 = {}", g2, f2); } TableRelation> rel = ring.table.lookup(g2, f2); if (debug) logger.info("poly, g = {}, f = {}, rel = {}", g, f, rel); Ds = new RecSolvableWordPolynomial(ring, rel.p); //ring.copy(rel.p); if (rel.f != null) { D2 = ring.valueOf(rel.f); //new RecSolvableWordPolynomial(ring, one, rel.f); Ds = Ds.multiply(D2); if (rel.e == null) { g4 = g2; } else { g4 = g2.subtract(rel.e); } ring.table.update(g4, f2, Ds); } if (rel.e != null) { D1 = ring.valueOf(rel.e); //new RecSolvableWordPolynomial(ring, one, rel.e); Ds = D1.multiply(Ds); ring.table.update(g2, f2, Ds); } if (!f1.isZERO()) { D2 = ring.valueOf(f1); //new RecSolvableWordPolynomial(ring, one, f1); Ds = Ds.multiply(D2); //ring.table.update(?,f1,Ds) } if (!g1.isZERO()) { D1 = ring.valueOf(g1); //new RecSolvableWordPolynomial(ring, one, g1); Ds = D1.multiply(Ds); //ring.table.update(e1,?,Ds) } } //System.out.println("main loop, Cs = " + Cs + ", c = " + c); Ds = Ds.multiplyLeft(c); // assume c commutes with Cs //Dps = (RecSolvableWordPolynomial) Dps.sum(Ds); Dps.doAddTo(Ds); } // end Dps loop Ds = Dps; } if (debug) { logger.info("recursion+: Ds = {}, a = {}", Ds, a); } // polynomial coefficient multiplication a*(P_eb*f) = a*Ds //System.out.println("main loop, Ds = " + Ds + ", a = " + a); Ds = Ds.multiplyLeft(a); // multiply(a,b); // non-symmetric if (debug) logger.info("recursion-: Ds = {}", Ds); //Dp = (RecSolvableWordPolynomial) Dp.sum(Ds); Dp.doAddTo(Ds); if (debug) logger.info("end B loop: Dp = {}", Dp); } // end B loop if (debug) logger.info("end A loop: Dp = {}", Dp); } // end A loop return Dp; } /** * RecSolvableWordPolynomial left and right multiplication. Product with two * polynomials. * @param S RecSolvableWordPolynomial. * @param T RecSolvableWordPolynomial. * @return S*this*T. */ // cannot @Override, @NoOverride public RecSolvableWordPolynomial multiply(RecSolvableWordPolynomial S, RecSolvableWordPolynomial T) { if (S.isZERO() || T.isZERO() || this.isZERO()) { return ring.getZERO(); } if (S.isONE()) { return multiply(T); } if (T.isONE()) { return S.multiply(this); } return S.multiply(this).multiply(T); } /** * RecSolvableWordPolynomial multiplication. Product with coefficient ring * element. * @param b coefficient polynomial. * @return this*b, where * is coefficient multiplication. */ // cannot @Override //public RecSolvableWordPolynomial multiply(GenWordPolynomial b) { //public GenSolvablePolynomial> multiply(GenWordPolynomial b) { public RecSolvableWordPolynomial recMultiply(GenWordPolynomial b) { RecSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Cp = new RecSolvableWordPolynomial(ring, b, ring.evzero); return multiply(Cp); } /** * RecSolvableWordPolynomial left and right multiplication. Product with * coefficient ring element. * @param b coefficient polynomial. * @param c coefficient polynomial. * @return b*this*c, where * is coefficient multiplication. */ @Override public RecSolvableWordPolynomial multiply(GenWordPolynomial b, GenWordPolynomial c) { RecSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } if (c == null || c.isZERO()) { return Cp; } RecSolvableWordPolynomial Cb = ring.valueOf(b); //new RecSolvableWordPolynomial(ring, b, ring.evzero); RecSolvableWordPolynomial Cc = ring.valueOf(c); //new RecSolvableWordPolynomial(ring, c, ring.evzero); return Cb.multiply(this).multiply(Cc); } /* * RecSolvableWordPolynomial multiplication. Product with coefficient ring * element. * @param b coefficient of coefficient. * @return this*b, where * is coefficient multiplication. */ //@Override not possible, @NoOverride //public RecSolvableWordPolynomial multiply(C b) { ... } /** * RecSolvableWordPolynomial multiplication. Product with exponent vector. * @param e exponent. * @return this * xe, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiply(ExpVector e) { if (e == null || e.isZERO()) { return this; } GenWordPolynomial b = ring.getONECoefficient(); return multiply(b, e); } /** * RecSolvableWordPolynomial left and right multiplication. Product with * exponent vector. * @param e exponent. * @param f exponent. * @return xe * this * xf, where * denotes solvable * multiplication. */ @Override public RecSolvableWordPolynomial multiply(ExpVector e, ExpVector f) { if (e == null || e.isZERO()) { return this; } if (f == null || f.isZERO()) { return this; } GenWordPolynomial b = ring.getONECoefficient(); return multiply(b, e, b, f); } /** * RecSolvableWordPolynomial multiplication. Product with ring element and * exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return this * b xe, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiply(GenWordPolynomial b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } RecSolvableWordPolynomial Cp = ring.valueOf(b, e); //new RecSolvableWordPolynomial(ring, b, e); return multiply(Cp); } /** * RecSolvableWordPolynomial left and right multiplication. Product with * ring element and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @param c coefficient polynomial. * @param f exponent. * @return b xe * this * c xf, where * denotes * solvable multiplication. */ @Override public RecSolvableWordPolynomial multiply(GenWordPolynomial b, ExpVector e, GenWordPolynomial c, ExpVector f) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (c == null || c.isZERO()) { return ring.getZERO(); } RecSolvableWordPolynomial Cp = ring.valueOf(b, e); //new RecSolvableWordPolynomial(ring, b, e); RecSolvableWordPolynomial Dp = ring.valueOf(c, f); //new RecSolvableWordPolynomial(ring, c, f); return multiply(Cp, Dp); } /** * RecSolvableWordPolynomial multiplication. Left product with ring element * and exponent vector. * @param b coefficient polynomial. * @param e exponent. * @return b xe * this, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiplyLeft(GenWordPolynomial b, ExpVector e) { if (b == null || b.isZERO()) { return ring.getZERO(); } RecSolvableWordPolynomial Cp = ring.valueOf(b, e); //new RecSolvableWordPolynomial(ring, b, e); return Cp.multiply(this); } /** * RecSolvableWordPolynomial multiplication. Left product with exponent * vector. * @param e exponent. * @return xe * this, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiplyLeft(ExpVector e) { if (e == null || e.isZERO()) { return this; } //GenWordPolynomial b = ring.getONECoefficient(); RecSolvableWordPolynomial Cp = ring.valueOf(e); //new RecSolvableWordPolynomial(ring, b, e); return Cp.multiply(this); } /** * RecSolvableWordPolynomial multiplication. Left product with coefficient * ring element. * @param b coefficient polynomial. * @return b*this, where * is coefficient multiplication. */ @Override public RecSolvableWordPolynomial multiplyLeft(GenWordPolynomial b) { RecSolvableWordPolynomial Cp = ring.getZERO().copy(); if (b == null || b.isZERO()) { return Cp; } Map> Cm = Cp.val; //getMap(); Map> Am = val; GenWordPolynomial c; for (Map.Entry> y : Am.entrySet()) { ExpVector e = y.getKey(); GenWordPolynomial a = y.getValue(); c = b.multiply(a); if (!c.isZERO()) { Cm.put(e, c); } } return Cp; } /** * RecSolvableWordPolynomial multiplication. Left product with 'monomial'. * @param m 'monomial'. * @return m * this, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiplyLeft(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiplyLeft(m.getValue(), m.getKey()); } /** * RecSolvableWordPolynomial multiplication. Product with 'monomial'. * @param m 'monomial'. * @return this * m, where * denotes solvable multiplication. */ @Override public RecSolvableWordPolynomial multiply(Map.Entry> m) { if (m == null) { return ring.getZERO(); } return multiply(m.getValue(), m.getKey()); } /** * RecSolvableWordPolynomial multiplication. Commutative product with * exponent vector. * @param f exponent vector. * @return B*f, where * is commutative multiplication. */ protected RecSolvableWordPolynomial shift(ExpVector f) { RecSolvableWordPolynomial C = ring.getZERO().copy(); if (this.isZERO()) { return C; } if (f == null || f.isZERO()) { return this; } Map> Cm = C.val; Map> Bm = this.val; for (Map.Entry> y : Bm.entrySet()) { ExpVector e = y.getKey(); GenWordPolynomial a = y.getValue(); ExpVector d = e.sum(f); if (!a.isZERO()) { Cm.put(d, a); } } return C; } } java-algebra-system-2.7.200/src/edu/jas/poly/RecSolvableWordPolynomialRing.java000066400000000000000000000555031445075545500274360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.kern.Scripting; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * RecSolvableWordPolynomialRing generic recursive solvable polynomial factory * implementing RingFactory and extending GenSolvablePolynomialRing factory. * Factory for n-variate ordered solvable polynomials over non-commutative word * polynomial coefficients. The non-commutative multiplication relations are * maintained in a relation table and the non-commutative multiplication * relations between the coefficients and the main variables are maintained in a * coefficient relation table. Almost immutable object, except variable names * and relation table contents. * @param base coefficient type. * @author Heinz Kredel */ public class RecSolvableWordPolynomialRing> extends GenSolvablePolynomialRing> { /** * The solvable multiplication relations between variables and coefficients. */ public final RelationTable> coeffTable; /** * The constant polynomial 0 for this ring. Hides super ZERO. */ public final RecSolvableWordPolynomial ZERO; /** * The constant polynomial 1 for this ring. Hides super ONE. */ public final RecSolvableWordPolynomial ONE; private static final Logger logger = LogManager.getLogger(RecSolvableWordPolynomialRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * The constructor creates a solvable polynomial factory object with the * default term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n) { this(cf, n, new TermOrder(), null, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param rt solvable multiplication relations. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n, RelationTable> rt) { this(cf, n, new TermOrder(), null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t) { this(cf, n, t, null, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param rt solvable multiplication relations. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, RelationTable> rt) { this(cf, n, t, null, rt); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v) { this(cf, n, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order and commutative relations. * @param cf factory for coefficients of type C. * @param t a term order. * @param v names for the variables. */ public RecSolvableWordPolynomialRing(RingFactory> cf, TermOrder t, String[] v) { this(cf, v.length, t, v, null); } /** * The constructor creates a solvable polynomial factory object with the * default term order. * @param cf factory for coefficients of type C. * @param v names for the variables. */ public RecSolvableWordPolynomialRing(RingFactory> cf, String[] v) { this(cf, v.length, new TermOrder(), v, null); } /** * The constructor creates a solvable polynomial factory object with the * given term order. * @param cf factory for coefficients of type C. * @param n number of variables. * @param t a term order. * @param v names for the variables. * @param rt solvable multiplication relations. */ public RecSolvableWordPolynomialRing(RingFactory> cf, int n, TermOrder t, String[] v, RelationTable> rt) { super(cf, n, t, v, rt); //if (rt == null) { // handled in super } coeffTable = new RelationTable>(this, true); ZERO = new RecSolvableWordPolynomial(this); GenWordPolynomial coeff = coFac.getONE(); //evzero = ExpVector.create(nvar); // from super ONE = new RecSolvableWordPolynomial(this, coeff, evzero); } /** * The constructor creates a solvable polynomial factory object with the the * same term order, number of variables and variable names as the given * polynomial factory, only the coefficient factories differ and the * solvable multiplication relations are empty. * @param cf factory for coefficients of type C. * @param o other solvable polynomial ring. */ public RecSolvableWordPolynomialRing(RingFactory> cf, RecSolvableWordPolynomialRing o) { this(cf, o.nvar, o.tord, o.getVars(), null); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { String res = super.toString(); if (PrettyPrint.isTrue()) { //res += "\n" + table.toString(vars); res += "\n" + coeffTable.toString(vars); } else { res += ", #rel = " + table.size() + " + " + coeffTable.size(); } return res; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { StringBuffer s = new StringBuffer(); switch (Scripting.getLang()) { case Ruby: s.append("SolvPolyRing.new("); break; case Python: default: s.append("SolvPolyRing("); } if (coFac instanceof RingElem) { s.append(((RingElem>) coFac).toScriptFactory()); } else { s.append(coFac.toScript().trim()); } s.append(",\"" + varsToString() + "\","); String to = tord.toScript(); s.append(to); if (table.size() > 0) { String rel = table.toScript(); s.append(",rel="); s.append(rel); } if (coeffTable.size() > 0) { String rel = coeffTable.toScript(); s.append(",coeffrel="); s.append(rel); } s.append(")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (other == null) { return false; } if (!(other instanceof RecSolvableWordPolynomialRing)) { return false; } // do a super.equals( ) if (!super.equals(other)) { return false; } RecSolvableWordPolynomialRing oring = (RecSolvableWordPolynomialRing) other; // check same base relations //if ( ! table.equals(oring.table) ) { // done in super // return false; //} if (!coeffTable.equals(oring.coeffTable)) { return false; } return true; } /** * Hash code for this polynomial ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = super.hashCode(); h = 37 * h + table.hashCode(); // may be different after some computations h = 37 * h + coeffTable.hashCode(); // may be different return h; } /** * Get the zero element. * @return 0 as RecSolvableWordPolynomial. */ @Override public RecSolvableWordPolynomial getZERO() { return ZERO; } /** * Get the one element. * @return 1 as RecSolvableWordPolynomial. */ @Override public RecSolvableWordPolynomial getONE() { return ONE; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ @Override public boolean isCommutative() { if (coeffTable.isEmpty()) { return super.isCommutative(); } return false; } /** * Query if this ring is associative. Test if the relations between the mian * variables and the coefficient generators define an associative solvable * ring. * @return true, if this ring is associative, else false. */ @SuppressWarnings("unused") @Override public boolean isAssociative() { if (!coFac.isAssociative()) { return false; } RecSolvableWordPolynomial Xi, Xj, Xk, p, q; List>> gens = generators(); //System.out.println("Rec word gens = " + gens); int ngen = gens.size(); for (int i = 0; i < ngen; i++) { Xi = (RecSolvableWordPolynomial) gens.get(i); if (Xi.isONE()) { continue; } for (int j = i + 1; j < ngen; j++) { Xj = (RecSolvableWordPolynomial) gens.get(j); for (int k = j + 1; k < ngen; k++) { Xk = (RecSolvableWordPolynomial) gens.get(k); try { p = Xk.multiply(Xj).multiply(Xi); q = Xk.multiply(Xj.multiply(Xi)); if (!p.equals(q)) { if (logger.isInfoEnabled()) { logger.info("Xi = {}, Xj = {}, Xk = {}", Xi, Xj, Xk); logger.info("p = ( Xk * Xj ) * Xi = {}", p); logger.info("q = Xk * ( Xj * Xi ) = {}", q); } return false; } } catch (RuntimeException e) { e.printStackTrace(); System.out.println("Xk = " + Xk + ", Xj = " + Xj + ", Xi = " + Xi); } } } } return true; } /** * Get a (constant) RecSolvableWordPolynomial<C> element from a * coefficient value. * @param a coefficient. * @return a RecSolvableWordPolynomial<C>. */ @Override public RecSolvableWordPolynomial valueOf(GenWordPolynomial a) { return new RecSolvableWordPolynomial(this, a); } /** * Get a RecSolvableWordPolynomial<C> element from an ExpVector. * @param e exponent vector. * @return a RecSolvableWordPolynomial<C>. */ @Override public RecSolvableWordPolynomial valueOf(ExpVector e) { return valueOf(coFac.getONE(), e); } /** * Get a RecSolvableWordPolynomial<C> element from a coefficient and an * ExpVector. * @param a coefficient. * @param e exponent vector. * @return a RecSolvableWordPolynomial<C>. */ @Override public RecSolvableWordPolynomial valueOf(GenWordPolynomial a, ExpVector e) { return new RecSolvableWordPolynomial(this, a, e); } /** * Get a (constant) RecSolvableWordPolynomial<C> element from a long * value. * @param a long. * @return a RecSolvableWordPolynomial<C>. */ @Override public RecSolvableWordPolynomial fromInteger(long a) { return new RecSolvableWordPolynomial(this, coFac.fromInteger(a), evzero); } /** * Get a (constant) RecSolvableWordPolynomial<C> element from a * BigInteger value. * @param a BigInteger. * @return a RecSolvableWordPolynomial<C>. */ @Override public RecSolvableWordPolynomial fromInteger(BigInteger a) { return new RecSolvableWordPolynomial(this, coFac.fromInteger(a), evzero); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @return a random solvable polynomial. */ @Override public RecSolvableWordPolynomial random(int n) { return random(n, random); } /** * Random solvable polynomial. Generates a random solvable polynomial with k * = 5, l = n, d = (nvar == 1) ? n : 3, q = (nvar == 1) ? 0.7 : 0.3. * @param n number of terms. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public RecSolvableWordPolynomial random(int n, Random rnd) { if (nvar == 1) { return random(5, n, n, 0.7f, rnd); } return random(5, n, 3, 0.3f, rnd); } /** * Generate a random solvable polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random solvable polynomial. */ @Override public RecSolvableWordPolynomial random(int k, int l, int d, float q) { return random(k, l, d, q, random); } /** * Random solvable polynomial. * @param k size of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @param rnd is a source for random bits. * @return a random solvable polynomial. */ @Override public RecSolvableWordPolynomial random(int k, int l, int d, float q, Random rnd) { RecSolvableWordPolynomial r = getZERO(); // copy( ZERO ); ExpVector e; GenWordPolynomial a; // add random coeffs and exponents for (int i = 0; i < l; i++) { e = ExpVector.random(nvar, d, q, rnd); a = coFac.random(k, rnd); r = (RecSolvableWordPolynomial) r.sum(a, e); // somewhat inefficient but clean } return r; } /** * Copy polynomial c. * @param c * @return a copy of c. */ public RecSolvableWordPolynomial copy(RecSolvableWordPolynomial c) { return new RecSolvableWordPolynomial(this, c.val); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param s String. * @return RecSolvableWordPolynomial from s. */ @Override public RecSolvableWordPolynomial parse(String s) { return parse(new StringReader(s)); } /** * Parse a solvable polynomial with the use of GenPolynomialTokenizer * @param r Reader. * @return next RecSolvableWordPolynomial from r. */ @Override @SuppressWarnings("unchecked") public RecSolvableWordPolynomial parse(Reader r) { GenPolynomialTokenizer pt = new GenPolynomialTokenizer(this, r); RecSolvableWordPolynomial p = null; try { GenSolvablePolynomial> s = pt.nextSolvablePolynomial(); p = new RecSolvableWordPolynomial(this, s); } catch (IOException e) { logger.error("{} parse {}", e, this); p = ZERO; } return p; } /** * Generate univariate solvable polynomial in a given variable. * @param i the index of the variable. * @return X_i as solvable univariate polynomial. */ @Override public RecSolvableWordPolynomial univariate(int i) { return (RecSolvableWordPolynomial) super.univariate(i); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public RecSolvableWordPolynomial univariate(int i, long e) { return (RecSolvableWordPolynomial) super.univariate(i, e); } /** * Generate univariate solvable polynomial in a given variable with given * exponent. * @param modv number of module variables. * @param i the index of the variable. * @param e the exponent of the variable. * @return X_i^e as solvable univariate polynomial. */ @Override public RecSolvableWordPolynomial univariate(int modv, int i, long e) { return (RecSolvableWordPolynomial) super.univariate(modv, i, e); } /** * Generate list of univariate polynomials in all variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList() { //return castToSolvableList( super.univariateList() ); return univariateList(0, 1L); } /** * Generate list of univariate polynomials in all variables. * @param modv number of module variables. * @return List(X_1,...,X_n) a list of univariate polynomials. */ @Override public List> univariateList(int modv) { return univariateList(modv, 1L); } /** * Generate list of univariate polynomials in all variables with given * exponent. * @param modv number of module variables. * @param e the exponent of the variables. * @return List(X_1^e,...,X_n^e) a list of univariate polynomials. */ @Override public List> univariateList(int modv, long e) { List> pols = new ArrayList>(nvar); int nm = nvar - modv; for (int i = 0; i < nm; i++) { RecSolvableWordPolynomial p = univariate(modv, nm - 1 - i, e); pols.add(p); } return pols; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by i. * @param i number of variables to extend. * @return extended solvable polynomial ring factory. */ @Override public RecSolvableWordPolynomialRing extend(int i) { GenSolvablePolynomialRing> pfac = super.extend(i); RecSolvableWordPolynomialRing spfac = new RecSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars, pfac.table); //spfac.table.extend(this.table); // pfac.table spfac.coeffTable.extend(this.coeffTable); return spfac; } /** * Extend variables. Used e.g. in module embedding. Extend number of * variables by length(vn). New variables commute with the exiting * variables. * @param vs names for extended variables. * @return extended polynomial ring factory. */ @Override public RecSolvableWordPolynomialRing extend(String[] vs) { GenSolvablePolynomialRing> pfac = super.extend(vs); RecSolvableWordPolynomialRing spfac = new RecSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars, pfac.table); //spfac.table.extend(this.table); // pfac.table?? spfac.coeffTable.extend(this.coeffTable); return spfac; } /** * Contract variables. Used e.g. in module embedding. Contract number of * variables by i. * @param i number of variables to remove. * @return contracted solvable polynomial ring factory. */ @Override public RecSolvableWordPolynomialRing contract(int i) { GenPolynomialRing> pfac = super.contract(i); RecSolvableWordPolynomialRing spfac = new RecSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.table.contract(this.table); spfac.coeffTable.contract(this.coeffTable); return spfac; } /** * Reverse variables. Used e.g. in opposite rings. * @return solvable polynomial ring factory with reversed variables. */ @Override public RecSolvableWordPolynomialRing reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return solvable polynomial ring factory with reversed variables. */ @Override public RecSolvableWordPolynomialRing reverse(boolean partial) { GenPolynomialRing> pfac = super.reverse(partial); RecSolvableWordPolynomialRing spfac = new RecSolvableWordPolynomialRing(pfac.coFac, pfac.nvar, pfac.tord, pfac.vars); spfac.partial = partial; spfac.table.reverse(this.table); spfac.coeffTable.reverse(this.coeffTable); return spfac; } /* not possible: * Distributive representation as polynomial with all main variables. * @return distributive polynomial ring factory. @SuppressWarnings({"cast","unchecked"}) public static > // must be static because of types GenSolvablePolynomialRing distribute(RecSolvableWordPolynomialRing rf) { } */ /** * Permutation of polynomial ring variables. * @param P permutation. * @return P(this). */ @Override public GenSolvablePolynomialRing> permutation(List P) { if (!coeffTable.isEmpty()) { throw new UnsupportedOperationException("permutation with coeff relations: " + this); } GenSolvablePolynomialRing> pfac = (GenSolvablePolynomialRing>) super.permutation( P); return pfac; } } java-algebra-system-2.7.200/src/edu/jas/poly/RelationGenerator.java000066400000000000000000000012611445075545500251310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.structure.RingElem; /** * Generate Relation Tables for solvable polynomial rings. Adds the respective * relations to the relation table of the given solvable ring factory. Relations * are of the form xj * xi = xi xj + * pij for 1 ≤ i < j ≤ n = number of variables. * @author Heinz Kredel */ public interface RelationGenerator> { /** * Generates the relation table of a solvable polynomial ring. * @param ring solvable polynomial ring factory. */ public abstract void generate(GenSolvablePolynomialRing ring); } java-algebra-system-2.7.200/src/edu/jas/poly/RelationTable.java000066400000000000000000001165011445075545500242360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.RingElem; /** * RelationTable for solvable polynomials. This class maintains the * non-commutative multiplication relations of solvable polynomial rings. The * table entries are initialized with relations of the form xj * * xi = pij. During multiplication the relations are * updated by relations of the form xjk * * xil = pijkl. If no relation for * xj * xi is found in the table, this multiplication is * assumed to be commutative xi xj. Can also be used for * relations between coefficients and main variables. * @author Heinz Kredel */ public class RelationTable> implements Serializable { /** * The data structure for the relations. */ public final Map, List> table; /** * The factory for the solvable polynomial ring. */ public final GenSolvablePolynomialRing ring; /** * Usage indicator: table or coeffTable. */ public final boolean coeffTable; private static final Logger logger = LogManager.getLogger(RelationTable.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor for RelationTable requires ring factory. Note: This * constructor is called within the constructor of the ring factory, so * methods of this class can only be used after the other constructor has * terminated. * @param r solvable polynomial ring factory. */ public RelationTable(GenSolvablePolynomialRing r) { this(r, false); } /** * Constructor for RelationTable requires ring factory. Note: This * constructor is called within the constructor of the ring factory, so * methods of this class can only be used after the other constructor has * terminated. * @param r solvable polynomial ring factory. * @param coeffTable indicator for coeffTable. */ public RelationTable(GenSolvablePolynomialRing r, boolean coeffTable) { table = new HashMap, List>(); ring = r; if (ring == null) { throw new IllegalArgumentException("RelationTable no ring"); } this.coeffTable = coeffTable; } /** * RelationTable equals. Tests same keySets and base relations. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object p) { if (p == null) { return false; } if (!(p instanceof RelationTable)) { logger.info("no RelationTable"); return false; } RelationTable tab = (RelationTable) p; // not possible because of infinite recursion: //if (!ring.equals(tab.ring)) { // logger.info("not same Ring {} != {}", ring, tab.ring); // return false; //} if (!table.keySet().equals(tab.table.keySet())) { logger.info("keySet != : a = {} != b = {}", table.keySet(), tab.table.keySet()); return false; } for (Map.Entry, List> me : table.entrySet()) { List k = me.getKey(); List a = me.getValue(); List b = tab.table.get(k); // check contents, but only base relations Map> t1ex = fromListDeg2(a); Map> t2ex = fromListDeg2(b); if (!equalMaps(t1ex, t2ex)) { //System.out.println("a != b, a = " + t1ex + ", b = " + t2ex); return false; } } return true; } /** * Convert mixed list to map for base relations. * @param a mixed list * @returns a map constructed from the list with deg(key) == 2. */ @SuppressWarnings("unchecked") Map> fromListDeg2(List a) { Map> tex = new HashMap>(); Iterator ait = a.iterator(); while (ait.hasNext()) { ExpVectorPair ae = (ExpVectorPair) ait.next(); if (!ait.hasNext()) { break; } GenPolynomial p = (GenPolynomial) ait.next(); if (ae.totalDeg() == 2) { // only base relations //System.out.println("ae => p: " + ae + " => " + p); tex.put(ae, p); } } return tex; } /** * Hash code for base relations. * @param a mixed list * @returns hashCode(a) */ @SuppressWarnings("unchecked") int fromListDeg2HashCode(List a) { int h = 0; Iterator ait = a.iterator(); while (ait.hasNext()) { ExpVectorPair ae = (ExpVectorPair) ait.next(); h = 31 * h + ae.hashCode(); if (!ait.hasNext()) { break; } GenPolynomial p = (GenPolynomial) ait.next(); if (ae.totalDeg() == 2) { // only base relations //System.out.println("ae => p: " + ae + " => " + p); h = 31 * h + p.val.hashCode(); // avoid hash of ring } } return h; } /** * Equals for special maps. * @param m1 first map * @param m2 second map * @returns true if both maps are equal */ @SuppressWarnings("unchecked") boolean equalMaps(Map> m1, Map> m2) { if (!m1.keySet().equals(m2.keySet())) { return false; } for (Map.Entry> me : m1.entrySet()) { GenPolynomial p1 = me.getValue(); ExpVectorPair ep = me.getKey(); GenPolynomial p2 = m2.get(ep); if (p1.compareTo(p2) != 0) { // not working: !p1.equals(p2) logger.info("ep = {}, p1 = {}, p2 = {}", ep, p1, p2); //logger.info("p1.compareTo(p2) = {}", p1.compareTo(p2)); //logger.info("p1.equals(p2) = {}", p1.equals(p2)); return false; } } return true; } /** * Hash code for this relation table. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { //int h = ring.hashCode(); // infinite recursion int h = 0; //table.hashCode(); h = table.keySet().hashCode(); for (Map.Entry, List> me : table.entrySet()) { //List k = me.getKey(); List a = me.getValue(); int t1 = fromListDeg2HashCode(a); h = 31 * h + t1; } return h; } /** * Test if the table is empty. * @return true if the table is empty, else false. */ public boolean isEmpty() { return table.isEmpty(); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { List v; StringBuffer s = new StringBuffer("RelationTable["); boolean first = true; for (Map.Entry, List> me : table.entrySet()) { List k = me.getKey(); if (first) { first = false; } else { s.append(", "); } s.append(k.toString()); v = me.getValue(); s.append("="); s.append(v.toString()); } s.append("]"); return s.toString(); } /** * Get the String representation. * @param vars names for the variables. * @see java.lang.Object#toString() */ @SuppressWarnings({ "unchecked", "cast" }) public String toString(String[] vars) { if (vars == null) { return toString(); } StringBuffer s = new StringBuffer(""); String[] cvars = null; if (coeffTable) { if (ring.coFac instanceof GenPolynomialRing) { cvars = ((GenPolynomialRing) (Object) ring.coFac).getVars(); } else if (ring.coFac instanceof GenWordPolynomialRing) { cvars = ((GenWordPolynomialRing) (Object) ring.coFac).getVars(); } s.append("Coefficient "); } s.append("RelationTable\n("); List v; if (PrettyPrint.isTrue()) { boolean first = true; for (Map.Entry, List> me : table.entrySet()) { //List k = me.getKey(); if (first) { first = false; s.append("\n"); } else { s.append(",\n"); } v = me.getValue(); for (Iterator jt = v.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); if (ep.totalDeg() != 2) { // only base relations continue; } s.append("( " + ep.getFirst().toString(vars) + " ), "); if (cvars == null) { s.append("( " + ep.getSecond().toString(vars) + " ), "); } else { s.append("( " + ep.getSecond().toString(cvars) + " ), "); } s.append("( " + p.toString(vars) + " )"); if (jt.hasNext()) { s.append(",\n"); } } } } else { boolean first = true; for (Map.Entry, List> me : table.entrySet()) { //List k = me.getKey(); if (first) { first = false; } else { s.append(",\n"); } v = me.getValue(); for (Iterator jt = v.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); s.append("( " + ep.getFirst().toString(vars) + " ), "); if (cvars == null) { s.append("( " + ep.getSecond().toString(vars) + " ), "); } else { s.append("( " + ep.getSecond().toString(cvars) + " ), "); } GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); //s.append("( " + p.toString(vars) + " )"); s.append(" " + p.toString(vars)); if (jt.hasNext()) { s.append(",\n"); } } } } s.append("\n)\n"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this relation table. */ @SuppressWarnings({ "unchecked", "cast" }) public String toScript() { // Python case String[] vars = ring.vars; String[] cvars = null; if (coeffTable) { if (ring.coFac instanceof GenPolynomialRing) { cvars = ((GenPolynomialRing) (Object) ring.coFac).getVars(); } else if (ring.coFac instanceof GenWordPolynomialRing) { cvars = ((GenWordPolynomialRing) (Object) ring.coFac).getVars(); } } List v; StringBuffer s = new StringBuffer("["); boolean first = true; for (Map.Entry, List> me : table.entrySet()) { //List k = me.getKey(); if (first) { first = false; s.append(""); } else { s.append(", "); } v = me.getValue(); for (Iterator jt = v.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); GenPolynomial p = (GenPolynomial) jt.next(); if (ep.totalDeg() > 2) { // only base relations continue; } s.append("" + ep.getFirst().toScript(vars) + ", "); if (coeffTable) { String eps = ep.getSecond().toScript(cvars); if (eps.isEmpty()) { // if from a deeper down ring eps = p.leadingBaseCoefficient().abs().toScript(); } s.append("" + eps + ", "); } else { s.append("" + ep.getSecond().toScript(vars) + ", "); } //s.append("( " + p.toScript() + " )"); s.append(" " + p.toScript()); if (jt.hasNext()) { s.append(", "); } } } s.append("]"); return s.toString(); } /** * Update or initialize RelationTable with new relation. relation is e * f = * p. * @param e first term. * @param f second term. * @param p solvable product polynomial. */ @SuppressWarnings({ "unchecked", "cast" }) public synchronized void update(ExpVector e, ExpVector f, GenSolvablePolynomial p) { if (p == null || e == null || f == null) { throw new IllegalArgumentException("RelationTable update e|f|p == null"); } GenSolvablePolynomialRing sring = p.ring; if (debug) { logger.info("new relation = {} .*. {} = {}", sring.toScript(e), sring.toScript(f), p.toScript()); } // test equal HTs for left and right side if (!coeffTable) { // old case int[] de = e.dependencyOnVariables(); int[] df = f.dependencyOnVariables(); if (debug) { logger.info("update e ? f {} {} : {} ? {}", Arrays.toString(de), Arrays.toString(df), sring.toScript(e), sring.toScript(f)); } if (de.length != 1 || df.length != 1) { // can this be relaxed? throw new IllegalArgumentException("RelationTable no univariate relations"); } if (de[de.length - 1] == df[0]) { // error throw new IllegalArgumentException("RelationTable update e == f"); } if (de[de.length - 1] > df[0]) { // invalid update throw new IllegalArgumentException("RelationTable update e < f"); // ExpVector tmp = e; // e = f; // f = tmp; // Map.Entry m = p.leadingMonomial(); // ExpVector ef = e.sum(f); // if (!ef.equals(m.getKey())) { // throw new IllegalArgumentException("update e*f != lt(p): " + sring.toScript(ef) // + ", lt = " + sring.toScript(m.getKey())); // } // GenPolynomial r = p.reductum(); //subtract(m.getValue(), m.getKey()); // r = r.negate(); // //p = (GenSolvablePolynomial) r.sum(m.getValue(), m.getKey()); // p = (GenSolvablePolynomial) r; // p.doPutToMap(m.getKey(), m.getValue()); } ExpVector ef = e.sum(f); ExpVector lp = p.leadingExpVector(); if (!ef.equals(lp)) { // check for suitable term order logger.error("relation term order = {}", ring.tord); throw new IllegalArgumentException( "update e*f != lt(p): " + sring.toScript(ef) + " != " + sring.toScript(lp)); } } else { // is coeffTable ExpVector lp = p.leadingExpVector(); if (!e.equals(lp)) { // check for suitable term order logger.error("relation term order = {}", ring.tord); throw new IllegalArgumentException("Coefficient RelationTable update e != lt(p): " + sring.toScript(e) + " != " + sring.toScript(lp)); } if (p.leadingBaseCoefficient() instanceof GenPolynomial) { lp = ((GenPolynomial) (Object) p.leadingBaseCoefficient()).leadingExpVector(); if (!f.equals(lp)) { // check for suitable term order logger.error("relation term order = {}", ring.tord); logger.error("Coefficient RelationTable update f != lt(lfcd(p)): {}, f = {}, p = {}", sring.toScript(e), f, p.toScript()); throw new IllegalArgumentException("Coefficient RelationTable update f != lt(lfcd(p)): " + e + ", f = " + f + ", p = " + p); } } else if (p.leadingBaseCoefficient() instanceof GenWordPolynomial) { lp = ((GenWordPolynomial) (Object) p.leadingBaseCoefficient()).leadingWord() .leadingExpVector(); if (!f.equals(lp)) { // check for suitable term order and word structure logger.error("relation term order = {}", ring.tord); logger.error("Coefficient RelationTable update f != lt(lfcd(p)): {}, f = {}, p = {}", sring.toScript(e), f, p.toScript()); throw new IllegalArgumentException("Coefficient RelationTable update f != lt(lfcd(p)): " + e + ", f = " + f + ", p = " + p); } } } // now insert key-value List key = makeKey(e, f); ExpVectorPair evp = new ExpVectorPair(e, f); // beware of leadingWord != leadingExpVector if (key.size() != 2) { logger.warn("key = {}, evp = {}", key, evp); } List part = table.get(key); if (part == null) { // initialization part = new LinkedList(); part.add(evp); part.add(p); table.put(key, part); return; } @SuppressWarnings("unused") Object skip; int index = -1; synchronized (part) { // with lookup() for (ListIterator it = part.listIterator(); it.hasNext();) { ExpVectorPair look = (ExpVectorPair) it.next(); skip = it.next(); // skip poly if (look.isMultiple(evp)) { index = it.nextIndex(); // last index of or first index of: break } } if (index < 0) { index = 0; } part.add(index, evp); part.add(index + 1, p); } // table.put( key, part ); // required?? } /** * Update or initialize RelationTable with new relation. relation is e * f = * p. * @param E first term polynomial. * @param F second term polynomial. * @param p solvable product polynomial. */ @SuppressWarnings({ "unchecked", "cast" }) public void update(GenPolynomial E, GenPolynomial F, GenSolvablePolynomial p) { if (E.isZERO() || F.isZERO()) { throw new IllegalArgumentException("polynomials may not be zero: " + E + ", " + F); } C ce = E.leadingBaseCoefficient(); C cf = F.leadingBaseCoefficient(); if (!ce.isONE()) { throw new IllegalArgumentException( "lbcf of polynomials must be one: " + ce + ", " + cf + ", p = " + p); } ExpVector e = E.leadingExpVector(); ExpVector f = F.leadingExpVector(); if (coeffTable && f.isZERO()) { if (cf instanceof GenPolynomial) { f = ((GenPolynomial) (Object) cf).leadingExpVector(); } else if (cf instanceof GenWordPolynomial) { f = ((GenWordPolynomial) (Object) cf).leadingWord().leadingExpVector(); } } //logger.info("update: {} .*. {} = {}", e, f, p); update(e, f, p); } /** * Update or initialize RelationTable with new relation. relation is e * f = * p. * @param E first term polynomial. * @param F second term polynomial. * @param p product polynomial. */ public void update(GenPolynomial E, GenPolynomial F, GenPolynomial p) { if (p.isZERO()) { throw new IllegalArgumentException("polynomial may not be zero: " + p); } if (p.isONE()) { throw new IllegalArgumentException("product of polynomials may not be one: " + p); } GenSolvablePolynomial sp = new GenSolvablePolynomial(ring, p.val); update(E, F, sp); } /** * Update or initialize RelationTable with new relation. relation is e * f = * p. * @param e first term. * @param f second term. * @param p solvable product polynomial. */ public void update(ExpVector e, ExpVector f, GenPolynomial p) { if (p.isZERO()) { throw new IllegalArgumentException("polynomial may not be zero: " + p); } if (p.isONE()) { throw new IllegalArgumentException("product of polynomials may not be one: " + p); } GenSolvablePolynomial sp = new GenSolvablePolynomial(ring, p.val); update(e, f, sp); } /** * Lookup RelationTable for existing relation. Find p with e * f = p. If no * relation for e * f is contained in the table then return the symmetric * product p = 1 e f. * @param e first term. * @param f second term. * @return t table relation container, contains e' and f' with e f = e' * lt(p) f'. */ @SuppressWarnings({ "unchecked", "cast" }) public TableRelation lookup(ExpVector e, ExpVector f) { List key = makeKey(e, f); List part = table.get(key); if (part == null) { // symmetric product GenSolvablePolynomial p = null; C c = null; if (!coeffTable) { ExpVector ef = e.sum(f); //p = new GenSolvablePolynomial(ring, ring.getONECoefficient(), ef); p = ring.valueOf(ef); } else { if (ring.coFac instanceof GenPolynomialRing) { GenPolynomialRing cofac = (GenPolynomialRing) (Object) ring.coFac; //System.out.println("f = " + f + ", e = " + e); GenPolynomial pc = cofac.valueOf(f); c = (C) (Object) pc; } else if (ring.coFac instanceof GenWordPolynomialRing) { GenWordPolynomialRing cofac = (GenWordPolynomialRing) (Object) ring.coFac; //System.out.println("f = " + f + ", e = " + e); GenWordPolynomial pc = cofac.valueOf(f); c = (C) (Object) pc; } p = new GenSolvablePolynomial(ring, c, e); //System.out.println("pc = " + pc + ", p = " + p); } return new TableRelation(null, null, p); } // no distinction between coefficient f or polynomial f ExpVectorPair evp = new ExpVectorPair(e, f); ExpVector ep = null; ExpVector fp = null; ExpVectorPair look = null; GenSolvablePolynomial p = null; synchronized (part) { // with update() for (Iterator it = part.iterator(); it.hasNext();) { look = (ExpVectorPair) it.next(); p = (GenSolvablePolynomial) it.next(); if (evp.isMultiple(look)) { ep = e.subtract(look.getFirst()); fp = f.subtract(look.getSecond()); if (ep.isZERO()) { ep = null; } if (fp.isZERO()) { fp = null; } if (debug) { if (p != null && p.ring.vars != null) { logger.info("found relation = {} .*. {} = {}", e.toString(p.ring.vars), f.toString(p.ring.vars), p); } else { logger.info("found relation = {} .*. {} = {}", e, f, p); } } return new TableRelation(ep, fp, p); } } } // unreachable code! throw new RuntimeException("no entry found in relation table for " + evp); } /** * Construct a key for (e,f). * @param e first term. * @param f second term. * @return k key for (e,f). */ protected List makeKey(ExpVector e, ExpVector f) { int[] de = e.dependencyOnVariables(); int[] df = f.dependencyOnVariables(); List key = new ArrayList(de.length + df.length); for (int i = 0; i < de.length; i++) { key.add(Integer.valueOf(de[i])); } for (int i = 0; i < df.length; i++) { key.add(Integer.valueOf(df[i])); } return key; } /** * Size of the table. * @return n number of non-commutative relations. */ public int size() { int s = 0; if (table == null || table.isEmpty()) { return s; } for (Iterator it = table.values().iterator(); it.hasNext();) { List list = it.next(); s += list.size() / 2; } return s; } /** * Extend variables. Used e.g. in module embedding. Extend all ExpVectors * and polynomials of the given relation table by i elements and put the * relations into this table, i.e. this should be empty. * @param tab a relation table to be extended and inserted into this. */ @SuppressWarnings("unchecked") public void extend(RelationTable tab) { if (tab.table.isEmpty()) { return; } // assert this.size() == 0 int i = ring.nvar - tab.ring.nvar; int j = 0; long k = 0l; List val; for (List key : tab.table.keySet()) { val = tab.table.get(key); for (Iterator jt = val.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); ExpVector e = ep.getFirst(); ExpVector f = ep.getSecond(); GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); ExpVector ex = e.extend(i, j, k); ExpVector fx; if (coeffTable) { fx = f; } else { fx = f.extend(i, j, k); } GenSolvablePolynomial px = (GenSolvablePolynomial) p.extend(ring, j, k); this.update(ex, fx, px); } } return; } /** * Contract variables. Used e.g. in module embedding. Contract all * ExpVectors and polynomials of the given relation table by i elements and * put the relations into this table, i.e. this should be empty. * @param tab a relation table to be contracted and inserted into this. */ @SuppressWarnings("unchecked") public void contract(RelationTable tab) { if (tab.table.isEmpty()) { return; } // assert this.size() == 0 int i = tab.ring.nvar - ring.nvar; List val; for (List key : tab.table.keySet()) { val = tab.table.get(key); //System.out.println("key = " + key + ", val = " + val); for (Iterator jt = val.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); ExpVector e = ep.getFirst(); ExpVector f = ep.getSecond(); GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); ExpVector ec = e.contract(i, e.length() - i); ExpVector fc; if (coeffTable) { fc = f; } else { fc = f.contract(i, f.length() - i); } //System.out.println("ec = " + ec + ", fc = " + fc); if (ec.isZERO()) { continue; } Map> mc = p.contract(ring); if (mc.size() != 1) { continue; } GenPolynomial pc = mc.values().iterator().next(); this.update(ec, fc, pc); } } return; } /** * Recursive representation. Split all ExpVectors and polynomials of the * given relation table to lower elements and upper elements and put the * relations into this table or this as coefficient table, i.e. this should * be empty. * @param tab a relation table to be contracted and inserted into this. */ @SuppressWarnings({ "unchecked", "cast" }) public void recursive(RelationTable tab) { // if (tab.table.isEmpty()) { return; } //System.out.println("rel ring = " + ring.toScript()); // assert this.size() == 0 GenPolynomialRing cring = (GenPolynomialRing) (Object) ring.coFac; //System.out.println("cring = " + cring.toScript()); GenSolvablePolynomial pc; int i = ring.nvar; // tab.ring.nvar - for (Object okey : tab.table.keySet()) { List key = (List) okey; List val = (List) tab.table.get(key); //System.out.println("key = " + key + ", val = " + val); for (Iterator jt = val.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); // ?? concurrent mod exception ExpVector e = ep.getFirst(); ExpVector f = ep.getSecond(); GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); ExpVector ec = e.contract(0, i); ExpVector fc; if (coeffTable) { fc = f; } else { fc = f.contract(0, i); } //System.out.println("ec = " + ec + ", fc = " + fc); if (ec.isZERO()) { continue; } Map> mc = p.contract(cring); //System.out.println("mc = " + mc + ", p = " + p); //System.out.println("mc.ring = " + mc.values().iterator().next().ring.toScript()); if (mc.size() == 1) { // < 1 only for p == 0 pc = (GenSolvablePolynomial) mc.values().iterator().next(); this.update(ec, fc, pc); } else { // construct recursive polynomial GenSolvablePolynomial qr = ring.getZERO(); for (Map.Entry> mce : mc.entrySet()) { ExpVector g = mce.getKey(); GenPolynomial q = mce.getValue(); C cq = (C) (Object) q; GenSolvablePolynomial qp = new GenSolvablePolynomial(ring, cq, g); qr = (GenSolvablePolynomial) qr.sum(qp); } if (coeffTable) { fc = ((GenPolynomial) (Object) qr.leadingBaseCoefficient()).leadingExpVector(); } if (fc.isZERO()) { continue; } //System.out.println("ec = " + ec + ", fc = " + fc + ", qr = " + qr); if (coeffTable) { String qrs = ring.toScript(ec) + " * " + qr.leadingBaseCoefficient() + " = " + qr.toScript(); logger.info("coeffTable: adding {}", qrs); } else { String qrs = ring.toScript(ec) + " * " + ring.toScript(fc) + " = " + qr.toScript(); logger.info("table: adding {}", qrs); } this.update(ec, fc, qr); } } } return; } /** * Reverse variables and relations. Used e.g. in opposite rings. Reverse all * ExpVectors and polynomials of the given relation table and put the * modified relations into this table, i.e. this should be empty. * @param tab a relation table to be reverted and inserted into this. */ @SuppressWarnings("unchecked") public void reverse(RelationTable tab) { if (tab.table.isEmpty()) { return; } if (!table.isEmpty()) { logger.error("reverse table not empty"); } int k = -1; if (ring.tord.getEvord2() != 0 && ring.partial) { k = ring.tord.getSplit(); } logger.debug("k split = {}", k); //System.out.println("k split = " + k ); //System.out.println("reversed ring = " + ring.toScript() ); for (List key : tab.table.keySet()) { List val = tab.table.get(key); for (Iterator jt = val.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); ExpVector e = ep.getFirst(); ExpVector f = ep.getSecond(); GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); //logger.info("e pre reverse = {}", e ); //logger.info("f pre reverse = {}", f ); //logger.info("p pre reverse = {}", p ); //if (e.degree() > 1 || f.degree() > 1) { // not required // continue; // revert only base relations //} ExpVector ex; ExpVector fx; GenSolvablePolynomial px; boolean change = true; // if relevant vars reversed if (k >= 0) { ex = e.reverse(k); if (coeffTable) { fx = f; } else { fx = f.reverse(k); } // todo check non-com / relevant vars for change //int[] ed = ex.dependencyOnVariables(); // = e //if (ed.length == 0 || ed[0] >= k) { // k >= 0 // change = false; //} //int[] fd = fx.dependencyOnVariables(); // = f //if (fd.length == 0 || fd[0] >= k) { // k >= 0 // change = false; //} } else { ex = e.reverse(); if (coeffTable) { fx = f; } else { fx = f.reverse(); } } px = (GenSolvablePolynomial) p.reverse(ring); //System.out.println("update, p, px: " + p.toScript() + " reverse:" + px.toScript() ); if (!change) { this.update(e, f, px); // same order } else { if (coeffTable) { this.update(ex, fx, px); // same order } else { this.update(fx, ex, px); // opposite order } } } } return; } /** * Convert relation table to list of polynomial triples. * @return rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations. */ @SuppressWarnings({ "unchecked", "cast" }) public List> relationList() { List> rels = new ArrayList>(); for (Map.Entry, List> me : table.entrySet()) { List v = me.getValue(); for (Iterator jt = v.iterator(); jt.hasNext();) { ExpVectorPair ep = (ExpVectorPair) jt.next(); ExpVector e = ep.getFirst(); GenSolvablePolynomial pe = ring.valueOf(e); ExpVector f = ep.getSecond(); GenSolvablePolynomial pf = null; if (coeffTable) { C cf = null; if (ring.coFac instanceof GenPolynomialRing) { GenPolynomial cpf; cpf = ((GenPolynomialRing) (Object) ring.coFac).valueOf(f); cf = (C) (Object) cpf; // down cast } else if (ring.coFac instanceof GenWordPolynomialRing) { GenWordPolynomial cpf; cpf = ((GenWordPolynomialRing) (Object) ring.coFac).valueOf(f); cf = (C) (Object) cpf; // down cast } pf = ring.valueOf(cf); } else { pf = ring.valueOf(f); } GenSolvablePolynomial p = (GenSolvablePolynomial) jt.next(); rels.add(pe); rels.add(pf); rels.add(p); } } return rels; } /** * Add list of polynomial triples as relations. * @param rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations. * Note: Only because of type erasure, equivalent to * addRelations(). */ public void addSolvRelations(List> rel) { PolynomialList Prel = new PolynomialList(ring, rel); addRelations(Prel.getList()); } /** * Add list of polynomial triples as relations. * @param rel = (e1,f1,p1, ...) where ei * fi = pi are solvable relations. */ @SuppressWarnings({ "unchecked", "cast" }) public void addRelations(List> rel) { if (rel == null || rel.isEmpty()) { return; } Iterator> relit = rel.iterator(); while (relit.hasNext()) { GenPolynomial E = relit.next(); ExpVector e = E.leadingExpVector(); ExpVector f = null; if (!relit.hasNext()) { throw new IllegalArgumentException("F and poly part missing"); } GenPolynomial F = relit.next(); if (!relit.hasNext()) { throw new IllegalArgumentException("poly part missing"); } GenPolynomial P = relit.next(); if (coeffTable) { if (!F.isConstant()) { throw new IllegalArgumentException("F not constant for coeffTable: " + F); } if (ring.coFac instanceof GenPolynomialRing) { f = ((GenPolynomial) (Object) F.leadingBaseCoefficient()).leadingExpVector(); } else if (ring.coFac instanceof GenWordPolynomialRing) { f = ((GenWordPolynomial) (Object) F.leadingBaseCoefficient()).leadingWord() .leadingExpVector(); } } else { f = F.leadingExpVector(); } update(e, f, P); } return; } } java-algebra-system-2.7.200/src/edu/jas/poly/Residue.java000066400000000000000000000237011445075545500231100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; /** * Residue element based on RingElem residue. Objects of this class are (nearly) * immutable. * @author Heinz Kredel */ public class Residue> implements RingElem> { private static final Logger logger = LogManager.getLogger(Residue.class); private static final boolean debug = logger.isDebugEnabled(); /** * Residue class factory data structure. */ protected final ResidueRing ring; /** * Value part of the element data structure. */ protected final C val; /** * Flag to remember if this residue element is a unit. -1 is unknown, 1 is * unit, 0 not a unit. */ protected int isunit = -1; // initially unknown /** * The constructor creates a Residue object from a ring factory. * @param r ring factory. */ public Residue(ResidueRing r) { this(r, r.ring.getZERO(), 0); } /** * The constructor creates a Residue object from a ring factory and a ring * element. * @param r ring factory. * @param a ring element. */ public Residue(ResidueRing r, C a) { this(r, a, -1); } /** * The constructor creates a Residue object from a ring factory, a ring * element and an indicator if a is a unit. * @param r ring factory. * @param a ring element. * @param u isunit indicator, -1, 0, 1. */ public Residue(ResidueRing r, C a, int u) { ring = r; C v = a.remainder(ring.modul); if (v.signum() < 0) { v = v.sum(ring.modul); } val = v; if (u == 0 || u == 1) { isunit = u; return; } if (val.isZERO()) { isunit = 0; return; } if (val.isUnit()) { isunit = 1; //} else { // not possible //isunit = 0; } isunit = -1; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ResidueRing factory() { return ring; } /** * Copy this. * @see edu.jas.structure.Element#copy() */ @Override public Residue copy() { return new Residue(ring, val); } /** * Is Residue zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return val.equals(ring.ring.getZERO()); } /** * Is Residue one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return val.equals(ring.ring.getONE()); } /** * Is Residue unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ @SuppressWarnings("unchecked") public boolean isUnit() { if (isunit == 1) { return true; } if (isunit == 0) { return false; } // val.isUnit() already tested // not jet known if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) { GcdRingElem v = (GcdRingElem) val; GcdRingElem m = (GcdRingElem) ring.modul; C gcd = (C) v.gcd(m); if (debug) { logger.info("gcd = {}", gcd); } boolean u = gcd.isONE(); if (u) { isunit = 1; } else { isunit = 0; } return u; } // still unknown return false; } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + val.toString() + " }"; return s; } return "Residue[ " + val.toString() + " mod " + ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return "Residue( " + val.toScript() + " , " + ring.toScript() + " )"; } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Residue comparison. * @param b Residue. * @return sign(this-b), 0 means that this and b are equivalent in this * residue class ring. */ @Override public int compareTo(Residue b) { C v = b.val; if (!ring.equals(b.ring)) { v = v.remainder(ring.modul); } return val.compareTo(v); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) * @return true means that this and b are equivalent in this residue class * ring. */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Residue)) { return false; } Residue a = (Residue) b; return (0 == compareTo(a)); } /** * Hash code for this local. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + val.hashCode(); return h; } /** * Residue absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Residue abs() { return new Residue(ring, val.abs()); } /** * Residue summation. * @param S Residue. * @return this+S. */ public Residue sum(Residue S) { return new Residue(ring, val.sum(S.val)); } /** * Residue negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Residue negate() { return new Residue(ring, val.negate()); } /** * Residue signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { return val.signum(); } /** * Residue subtraction. * @param S Residue. * @return this-S. */ public Residue subtract(Residue S) { return new Residue(ring, val.subtract(S.val)); } /** * Residue division. * @param S Residue. * @return this/S. */ public Residue divide(Residue S) { return multiply(S.inverse()); } /** * Residue inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this if defined. */ @SuppressWarnings("unchecked") public Residue inverse() { if (isunit == 0) { throw new NotInvertibleException("element not invertible (0) " + this); } if (val instanceof GcdRingElem && ring.modul instanceof GcdRingElem) { GcdRingElem v = (GcdRingElem) val; GcdRingElem m = (GcdRingElem) ring.modul; C[] egcd = (C[]) v.egcd(m); //System.out.println("v = " + v + ", m = " + m + ", e[0] = " + egcd[0] + ", e[1] = " + egcd[1]); if (debug) { logger.info("egcd = {}, f = {}", egcd[0], egcd[1]); } if (!egcd[0].isONE()) { isunit = 0; throw new NotInvertibleException("element not invertible (gcd)" + this); } isunit = 1; C x = egcd[1]; return new Residue(ring, x); } if (val.isUnit()) { C x = val.inverse(); return new Residue(ring, x); } //System.out.println("isunit = " + isunit + ", isUnit() = " + this.isUnit()); throw new NotInvertibleException("element not invertible (!gcd)" + this); } /** * Residue remainder. * @param S Residue. * @return this - (this/S)*S. */ public Residue remainder(Residue S) { C x = val.remainder(S.val); return new Residue(ring, x); } /** * Quotient and remainder by division of this by S. * @param S a Residue * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public Residue[] quotientRemainder(Residue S) { return new Residue[] { divide(S), remainder(S) }; } /** * Residue multiplication. * @param S Residue. * @return this*S. */ public Residue multiply(Residue S) { return new Residue(ring, val.multiply(S.val)); } /** * Greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return gcd(this,b). */ public Residue gcd(Residue b) { throw new UnsupportedOperationException("gcd not implemented " + this.getClass().getName()); } /** * Extended greatest common divisor. Note: Not implemented, throws * UnsupportedOperationException. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public Residue[] egcd(Residue b) { throw new UnsupportedOperationException("egcd not implemented " + this.getClass().getName()); } } java-algebra-system-2.7.200/src/edu/jas/poly/ResidueRing.java000066400000000000000000000165601445075545500237350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Residue ring factory based on RingElem and RingFactory module. Objects of * this class are immutable. * @author Heinz Kredel */ public class ResidueRing> implements RingFactory> { private static final Logger logger = LogManager.getLogger(ResidueRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Ring element for reduction. */ protected final C modul; /** * Ring factory. */ protected final RingFactory ring; /** * Indicator if this ring is a field. */ protected int isField = -1; // initially unknown /** * The constructor creates a ResidueRing object from an ring factory and a * modul. * @param r ring factory. * @param m modul. */ public ResidueRing(RingFactory r, C m) { ring = r; if (m == null || m.isZERO()) { throw new IllegalArgumentException("modul may not be null"); } if (m.isONE()) { logger.warn("modul is one"); } if (m.signum() < 0) { m = m.negate(); } modul = m; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { //if (ring instanceof GenPolynomialRing pr) { // Java 17 if (ring instanceof GenPolynomialRing) { GenPolynomialRing pr = (GenPolynomialRing) ring; return pr.coFac.isFinite(); /* always true: modul.degree() < \infinity */ } return true; // modul < Long.MAX_VALUE; //throw new UnsupportedOperationException("not implemented"); } /** * Copy Residue element c. * @param c * @return a copy of c. */ public Residue copy(Residue c) { return new Residue(c.ring, c.val); } /** * Get the zero element. * @return 0 as Residue. */ public Residue getZERO() { return new Residue(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Residue. */ public Residue getONE() { Residue one = new Residue(this, ring.getONE()); if (one.isZERO()) { logger.warn("one is zero, so all residues are 0"); } return one; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = ring.generators(); List> gens = new ArrayList>(rgens.size()); for (C c : rgens) { gens.add(new Residue(this, c)); } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { if (isField > 0) { return true; } if (isField == 0) { return false; } // ideal is prime ? return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { //if (ring instanceof GenPolynomialRing pr) { // Java 17 if (ring instanceof GenPolynomialRing) { GenPolynomialRing pr = (GenPolynomialRing) ring; return pr.characteristic(); /* always true: modul.degree() < \infinity */ } // modul < Long.MAX_VALUE; java.math.BigInteger m = new java.math.BigInteger(modul.toString()); return m; } /** * Get a Residue element from a BigInteger value. * @param a BigInteger. * @return a Residue. */ public Residue fromInteger(java.math.BigInteger a) { return new Residue(this, ring.fromInteger(a)); } /** * Get a Residue element from a long value. * @param a long. * @return a Residue. */ public Residue fromInteger(long a) { return new Residue(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "Residue[ " + modul.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "ResidueRing(" + modul.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof ResidueRing)) { return false; } ResidueRing a = (ResidueRing) b; if (!ring.equals(a.ring)) { return false; } return modul.equals(a.modul); } /** * Hash code for this residue ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + modul.hashCode(); return h; } /** * Residue random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Residue random(int n) { C x = ring.random(n); // x = x.sum( ring.getONE() ); return new Residue(this, x); } /** * Residue random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random residue element. */ public Residue random(int n, Random rnd) { C x = ring.random(n, rnd); // x = x.sum( ring.getONE() ); return new Residue(this, x); } /** * Parse Residue from String. * @param s String. * @return Residue from s. */ public Residue parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } C x = ring.parse(s); return new Residue(this, x); } /** * Parse Residue from Reader. * @param r Reader. * @return next Residue from r. */ public Residue parse(Reader r) { C x = ring.parse(r); return new Residue(this, x); } } java-algebra-system-2.7.200/src/edu/jas/poly/TableRelation.java000066400000000000000000000024101445075545500242270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import edu.jas.structure.RingElem; /** * TableRelation container for storage and printing in RelationTable. * @author Heinz Kredel */ public class TableRelation> implements Serializable { /** * First ExpVector of the data structure. */ public final ExpVector e; /** * Second ExpVector of the data structure. */ public final ExpVector f; /** * GenSolvablePolynomial of the data structure. */ public final GenSolvablePolynomial p; /** * Constructor to setup the data structure. * @param e first term. * @param f second term. * @param p product polynomial. */ public TableRelation(ExpVector e, ExpVector f, GenSolvablePolynomial p) { this.e = e; this.f = f; this.p = p; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("TableRelation["); s.append("" + e); s.append(" .*. "); s.append("" + f); s.append(" = "); s.append("" + p); s.append("]"); return s.toString(); } } java-algebra-system-2.7.200/src/edu/jas/poly/TermOrder.java000066400000000000000000001772721445075545500234300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.Scripting; /** * Term order class for ordered polynomials. Implements the most used term * orders: graded, lexicographical, weight array and block orders. For the * definitions see for example the articles * Kredel "Admissible term * orderings used in computer algebra systems" and * Sit, "Some comments on * term-ordering in Gröbner basis computations". Note: the * naming is not quite easy to understand: in case of doubt use the term orders * with "I" in the name, like IGRLEX (the default) or INVLEX. Not all algorithms * may work with all term orders since not all are well-founded, so watch your * step. This class does not implement orders by linear forms over Q[t]. Objects * of this class are immutable. * * @author Heinz Kredel */ public final class TermOrder implements Serializable { private static final Logger logger = LogManager.getLogger(TermOrder.class); private static final boolean debug = logger.isDebugEnabled(); // TermOrder index values public static final int LEX = 1; public final static int MIN_EVORD = LEX; public static final int INVLEX = 2; public static final int GRLEX = 3; public static final int IGRLEX = 4; public static final int REVLEX = 5; public static final int REVILEX = 6; public static final int REVTDEG = 7; public static final int REVITDG = 8; public static final int ITDEGLEX = 9; public static final int REVITDEG = 10; public final static int MAX_EVORD = REVITDEG; public final static int DEFAULT_EVORD = IGRLEX; //public final static int DEFAULT_EVORD = INVLEX; // instance variables private final int evord; // for split termorders private final int evord2; private final int evbeg1; private final int evend1; private final int evbeg2; private final int evend2; /** * Defined array of weight vectors. */ private final long[][] weight; /** * Defined descending order comparator. Sorts the highest terms first. */ private final EVComparator horder; /** * Defined ascending order comparator. Sorts the lowest terms first. */ private final EVComparator lorder; /** * Defined sugar order comparator. Sorts the graded lowest terms first. */ private final EVComparator sugar; /** * Termorders for modules: TOP or POT. POT: position over term (default) * TOP: term over position (new) */ public final boolean TOP; /** * Comparator for ExpVectors. */ public static abstract class EVComparator implements Comparator, Serializable { public abstract int compare(ExpVector e1, ExpVector e2); } /** * Constructor for default term order. */ public TermOrder() { this(DEFAULT_EVORD); } /** * Constructor for given term order. * @param evord requested term order indicator / enumerator. */ public TermOrder(int evord) { if (evord < MIN_EVORD || MAX_EVORD < evord) { throw new IllegalArgumentException("invalid term order: " + evord); } this.evord = evord; this.evord2 = 0; weight = null; evbeg1 = 0; evend1 = Integer.MAX_VALUE; evbeg2 = evend1; evend2 = evend1; TOP = false; switch (evord) { // horder = new EVhorder(); case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.invLexCompareTo(e2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.invLexCompareTo(e2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.invGradCompareTo(e2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.invGradCompareTo(e2); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.revInvLexCompareTo(e2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.revInvLexCompareTo(e2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.revInvGradCompareTo(e2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.revInvGradCompareTo(e2); } }; break; } case TermOrder.ITDEGLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.invTdegCompareTo(e2); // okay +/- } }; break; } case TermOrder.REVITDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.revLexInvTdegCompareTo(e2); // okay +/- } }; break; } default: { horder = null; } } if (horder == null) { throw new IllegalArgumentException("invalid term order: " + evord); } // lorder = new EVlorder(); lorder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -horder.compare(e1, e2); } }; // sugar = new EVsugar(); sugar = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.invGradCompareTo(e2); } }; } /** * Constructor for given exponent weights. * @param w weight vector of longs. */ public TermOrder(long[] w) { this(new long[][] { w }); } /** * Constructor for given exponent weights. * @param w weight array of longs. */ public TermOrder(long[][] w) { if (w == null || w.length == 0) { throw new IllegalArgumentException("invalid term order weight"); } weight = Arrays.copyOf(w, w.length); // > Java-5 this.evord = 0; this.evord2 = 0; evbeg1 = 0; evend1 = weight[0].length; evbeg2 = evend1; evend2 = evend1; TOP = false; horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -e1.invWeightCompareTo(weight, e2); } }; // lorder = new EVlorder(); lorder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return +e1.invWeightCompareTo(weight, e2); // return - horder.compare( e1, e2 ); } }; // sugar = new EVsugar(); sugar = horder; } /** * Test if this term order is a split order. * @return true if this is a split term order, else false. */ public boolean isSplit() { //System.out.println("isSplit: " + evend2 + " == " + evbeg2); if (evend2 == evbeg2 || evend1 == Integer.MAX_VALUE) { return false; } return true; } /** * Constructor for given split order. * @param ev1 requested term order indicator for first block. * @param ev2 requested term order indicator for second block. * @param r max number of exponents to compare. * @param split index. */ public TermOrder(int ev1, int ev2, int r, int split) { this(ev1, ev2, r, split, false); } /** * Constructor for given split order. * @param ev1 requested term order indicator for first block. * @param ev2 requested term order indicator for second block. * @param r max number of exponents to compare. * @param split index. * @param top module termorder, if true, default false. */ public TermOrder(int ev1, int ev2, int r, int split, boolean top) { if (ev1 < MIN_EVORD || MAX_EVORD - 2 < ev1) { throw new IllegalArgumentException("invalid split term order 1: " + ev1); } if (ev2 < MIN_EVORD || MAX_EVORD - 2 < ev2) { throw new IllegalArgumentException("invalid split term order 2: " + ev2); } this.evord = ev1; this.evord2 = ev2; weight = null; evbeg1 = 0; evend1 = split; // excluded evbeg2 = split; evend2 = r; if (evbeg2 < 0 || evbeg2 > evend2) { throw new IllegalArgumentException("invalid term order split, r = " + r + ", split = " + split); } //System.out.println("evbeg2 " + evbeg2 + ", evend2 " + evend2); TOP = top; if (debug) { logger.info("module TermOrder is {}. split = {}, evord = {}, evord2 = {}", (TOP ? "TOP" : "POT"), split, toScriptOrder(evord), toScriptOrder(evord2)); } switch (evord) { // horder = new EVhorder(); case TermOrder.LEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.INVLEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { if (!TOP) { horder = new EVComparator() { // POT @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } horder = new EVComparator() { // TOP @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg2, evend2); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg1, evend1); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { if (!TOP) { horder = new EVComparator() { // POT @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } horder = new EVComparator() { // TOP @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg2, evend2); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg1, evend1); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.GRLEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.IGRLEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { if (!TOP) { horder = new EVComparator() { // POT @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } horder = new EVComparator() { // TOP @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invLexCompareTo(e2, evbeg2, evend2); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg1, evend1); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { if (!TOP) { horder = new EVComparator() { // POT @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } horder = new EVComparator() { // TOP @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg2, evend2); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg1, evend1); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.invGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } //----- begin reversed ----------- case TermOrder.REVLEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.REVILEX: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvLexCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.REVTDEG: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } case TermOrder.REVITDG: { switch (evord2) { case TermOrder.LEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.INVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.GRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.IGRLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.invGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVLEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVILEX: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvLexCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVTDEG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } case TermOrder.REVITDG: { horder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { int t = -e1.revInvGradCompareTo(e2, evbeg1, evend1); if (t != 0) { return t; } return -e1.revInvGradCompareTo(e2, evbeg2, evend2); } }; break; } default: { horder = null; } } break; } //----- end reversed----------- default: { horder = null; } } if (horder == null) { throw new IllegalArgumentException("invalid term order: " + evord + " 2 " + evord2); } lorder = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return -horder.compare(e1, e2); } }; // sugar = new EVsugar(); sugar = new EVComparator() { @Override public int compare(ExpVector e1, ExpVector e2) { return e1.invGradCompareTo(e2); } }; } /* * Constructor for default split order. * @param r max number of exponents to compare. * @param split index. public TermOrder(int r, int split) { this(DEFAULT_EVORD, DEFAULT_EVORD, r, split); } */ /** * Create block term order at split index. * @param s split index. * @return block TermOrder with split index. */ public TermOrder blockOrder(int s) { return blockOrder(s, Integer.MAX_VALUE); } /** * Create block term order at split index. * @param s split index. * @param len length of ExpVectors to compare * @return block TermOrder with split index. */ public TermOrder blockOrder(int s, int len) { return new TermOrder(evord, evord, len, s); } /** * Create block term order at split index. * @param s split index. * @param t second term order. * @return block TermOrder with split index. */ public TermOrder blockOrder(int s, TermOrder t) { return blockOrder(s, t, Integer.MAX_VALUE); } /** * Create block term order at split index. * @param s split index. * @param t second term order. * @param len length of ExpVectors to compare * @return block TermOrder with split index. */ public TermOrder blockOrder(int s, TermOrder t, int len) { return new TermOrder(evord, t.evord, len, s); } /** * Get the first defined order indicator. * @return evord. */ public int getEvord() { return evord; } /** * Get the second defined order indicator. * @return evord2. */ public int getEvord2() { return evord2; } /** * Get the split index. * @return split. */ public int getSplit() { return evend1; // = evbeg2 } /** * Get the exponent vector size. Note: can be INTEGER.MAX_VALUE. * @return size. */ public int getSize() { return evend2; // can be INTEGER.MAX_VALUE } /** * Get the weight array. * @return weight. */ public long[][] getWeight() { if (weight == null) { return null; } return Arrays.copyOf(weight, weight.length); // > Java-5 } /** * Get the descending order comparator. Sorts the highest terms first. * @return horder. */ public EVComparator getDescendComparator() { return horder; } /** * Get the ascending order comparator. Sorts the lowest terms first. * @return lorder. */ public EVComparator getAscendComparator() { return lorder; } /** * Get the sugar order comparator. Sorts the graded lowest terms first. * @return sugar. */ public EVComparator getSugarComparator() { return sugar; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof TermOrder)) { return false; } TermOrder b = (TermOrder) B; boolean t = evord == b.getEvord() && evord2 == b.evord2 && evbeg1 == b.evbeg1 && evend1 == b.evend1 && evbeg2 == b.evbeg2 && evend2 == b.evend2; if (!t) { return t; } if (!Arrays.deepEquals(weight, b.weight)) { return false; } return true; } /** * Hash code. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = evord; h = (h << 3) + evord2; h = (h << 4) + evbeg1; h = (h << 4) + evend1; h = (h << 4) + evbeg2; h = (h << 4) + evend2; if (weight == null) { return h; } h = h * 7 + Arrays.deepHashCode(weight); return h; } /** * String representation of weight matrix. * @return string representation of weight matrix. */ public String weightToString() { StringBuffer erg = new StringBuffer(); if (weight != null) { erg.append("("); for (int j = 0; j < weight.length; j++) { if (j > 0) { erg.append(","); } long[] wj = weight[j]; erg.append("("); for (int i = 0; i < wj.length; i++) { if (i > 0) { erg.append(","); } erg.append(String.valueOf(wj[wj.length - 1 - i])); } erg.append(")"); } erg.append(")"); } return erg.toString(); } /** * Script representation of weight matrix. * @return script representation of weight matrix. */ public String weightToScript() { // cases Python and Ruby StringBuffer erg = new StringBuffer(); if (weight != null) { erg.append("["); for (int j = 0; j < weight.length; j++) { if (j > 0) { erg.append(","); } long[] wj = weight[j]; erg.append("["); for (int i = 0; i < wj.length; i++) { if (i > 0) { erg.append(","); } erg.append(String.valueOf(wj[wj.length - 1 - i])); } erg.append("]"); } erg.append("]"); } return erg.toString(); } /** * String representation of TermOrder. * @return script representation of TermOrder. */ public String toScript() { // cases Python and Ruby if (weight != null) { StringBuffer erg = new StringBuffer(); //erg.append("TermOrder( "); erg.append(weightToScript()); if (evend1 == evend2) { //erg.append(" )"); return erg.toString(); } erg.append("[" + evbeg1 + "," + evend1 + "]"); erg.append("[" + evbeg2 + "," + evend2 + "]"); //erg.append(" )"); return erg.toString(); } return toScriptPlain(); } /** * String representation of TermOrder. * @see java.lang.Object#toString() */ @Override public String toString() { if (weight != null) { StringBuffer erg = new StringBuffer(); erg.append("W( "); erg.append(weightToString()); if (evend1 == evend2) { erg.append(" )"); return erg.toString(); } erg.append("[" + evbeg1 + "," + evend1 + "]"); erg.append("[" + evbeg2 + "," + evend2 + "]"); erg.append(" )"); return erg.toString(); } return toStringPlain(); } /** * String representation of TermOrder without prefix and weight matrix. */ public String toStringPlain() { StringBuffer erg = new StringBuffer(); if (weight != null) { return erg.toString(); } erg.append(toScriptOrder(evord)); // JAS only if (evord2 <= 0) { return erg.toString(); } erg.append("[" + evbeg1 + "," + evend1 + "]"); erg.append(toScriptOrder(evord2)); // JAS only erg.append("[" + evbeg2 + "," + evend2 + "]"); return erg.toString(); } /** * Script representation of TermOrder without prefix and weight matrix. */ public String toScriptPlain() { StringBuffer erg = new StringBuffer(); if (weight != null) { return toScript(); } erg.append("Order"); switch (Scripting.getLang()) { case Ruby: erg.append("::"); break; case Python: default: erg.append("."); } erg.append(toScriptOrder(evord)); if (evord2 <= 0) { return erg.toString(); } if (evord == evord2) { erg.append(".blockOrder(" + evend1 + ")"); return erg.toString(); } erg.append(".blockOrder("); erg.append(evend1 + ","); erg.append("Order"); switch (Scripting.getLang()) { case Ruby: erg.append("::"); break; case Python: default: erg.append("."); } erg.append(toScriptOrder(evord2)); erg.append(")"); return erg.toString(); } /** * Script and String representation of TermOrder name. */ public String toScriptOrder(int ev) { switch (Scripting.getCAS()) { case Math: switch (ev) { case LEX: return "NegativeReverseLexicographic"; case INVLEX: return "ReverseLexicographic"; case GRLEX: return "NegativeDegreeReverseLexicographic"; case ITDEGLEX: //IGRLEX: return "DegreeReverseLexicographic"; case REVLEX: return "NegativeLexicographic"; case REVILEX: return "Lexicographic"; case REVITDEG: //REVTDEG: return "NegativeDegreeLexicographic"; case REVITDG: return "DegreeLexicographic"; default: return "invalid(" + ev + ")"; } case Sage: switch (ev) { case LEX: return "negrevlex"; case INVLEX: return "invlex"; case GRLEX: return "negdegrevlex"; case ITDEGLEX: //IGRLEX: return "degrevlex"; case REVLEX: return "neglex"; case REVILEX: return "lex"; case REVITDEG: //REVTDEG: return "negdeglex"; case REVITDG: return "deglex"; default: return "invalid(" + ev + ")"; } case Singular: switch (ev) { //case LEX: // missing //return "negrevlex"; case INVLEX: return "rp"; case GRLEX: return "ds"; case ITDEGLEX: //IGRLEX: return "dp"; case REVLEX: return "ls"; case REVILEX: return "lp"; case REVITDEG: //REVTDEG: return "Ds"; case REVITDG: return "Dp"; default: return "invalid(" + ev + ")"; } case JAS: default: switch (ev) { case LEX: return "LEX"; case INVLEX: return "INVLEX"; case GRLEX: return "GRLEX"; case IGRLEX: return "IGRLEX"; case REVLEX: return "REVLEX"; case REVILEX: return "REVILEX"; case REVTDEG: return "REVTDEG"; case REVITDG: return "REVITDG"; case ITDEGLEX: return "ITDEGLEX"; case REVITDEG: return "REVITDEG"; default: return "invalid(" + ev + ")"; } } //return "invalid(" + ev + ")"; } /** * Extend variables. Used e.g. in module embedding. Extend TermOrder by k * elements. Note: Use POT module term order. * @param r current number of variables. * @param k number of variables to extend. * @return extended TermOrder. */ public TermOrder extend(int r, int k) { return extend(r, k, false); } /** * Extend variables. Used e.g. in module embedding. Extend TermOrder by k * elements. Note: Now TOP and POT orders are distinguished. * @param r current number of variables. * @param k number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended TermOrder. */ public TermOrder extend(int r, int k, boolean top) { if (weight != null) { long[][] w = new long[weight.length][]; for (int i = 0; i < weight.length; i++) { long[] wi = weight[i]; long max = 0; // long min = Long.MAX_VALUE; for (int j = 0; j < wi.length; j++) { if (wi[j] > max) max = wi[j]; //if ( wi[j] < min ) min = wi[j]; } max++; long[] wj = new long[wi.length + k]; for (int j = 0; j < k; j++) { //i#k wj[j] = max; } System.arraycopy(wi, 0, wj, k, wi.length); w[i] = wj; } return new TermOrder(w); } if (evord2 != 0) { logger.debug("warn: TermOrder is already extended"); if (debug) { throw new IllegalArgumentException("TermOrder is already extended: " + this); } return new TermOrder(evord, evord2, r + k, evend1 + k, top); } //System.out.println("evord = " + evord); //System.out.println("DEFAULT_EVORD = " + DEFAULT_EVORD); //System.out.println("tord = " + this); return new TermOrder(DEFAULT_EVORD/*evord*/, evord, r + k, k, top); // don't change to evord, cause REVITDG || set evord1 per parameter? } /** * Extend lower variables. Extend TermOrder by k elements. Note: Use * POT module term order. * @param r current number of variables. * @param k number of variables to extend. * @return extended TermOrder. */ public TermOrder extendLower(int r, int k) { return extendLower(r, k, false); } /** * Extend lower variables. Extend TermOrder by k elements. Note: Now * TOP and POT orders are distinguished. * @param r current number of variables. * @param k number of variables to extend. * @param top true for TOP term order, false for POT term order. * @return extended TermOrder. */ public TermOrder extendLower(int r, int k, boolean top) { if (weight != null) { long[][] w = new long[weight.length][]; for (int i = 0; i < weight.length; i++) { long[] wi = weight[i]; //long max = 0; long min = Long.MAX_VALUE; for (int j = 0; j < wi.length; j++) { //if ( wi[j] > max ) max = wi[j]; if (wi[j] < min) min = wi[j]; } //max++; long[] wj = new long[wi.length + k]; for (int j = 0; j < k; j++) { //i#k wj[wi.length + j] = min; } System.arraycopy(wi, 0, wj, 0, wi.length); w[i] = wj; } return new TermOrder(w); } if (evord2 != 0) { if (debug) { logger.warn("TermOrder is already extended"); } return new TermOrder(evord, evord2, r + k, evend1 + k, top); } //System.out.println("evord = " + evord); //System.out.println("DEFAULT_EVORD = " + DEFAULT_EVORD); //System.out.println("tord = " + this); return new TermOrder(evord, DEFAULT_EVORD, r + k, r, top); // set evord2 per parameter? } /** * Contract variables. Used e.g. in module embedding. Contract TermOrder to * non split status. * @param k position of first element to be copied. * @param len new length. * @return contracted TermOrder. */ public TermOrder contract(int k, int len) { if (weight != null) { long[][] w = new long[weight.length][]; for (int i = 0; i < weight.length; i++) { long[] wi = weight[i]; long[] wj = new long[len]; System.arraycopy(wi, k, wj, 0, len); w[i] = wj; } return new TermOrder(w); } if (evord2 == 0) { if (debug) { logger.warn("TermOrder is already contracted"); } return new TermOrder(evord); } if (evend1 > k) { // < IntMax since evord2 != 0 int el = evend1 - k; while (el > len) { el -= len; } if (el == 0L) { return new TermOrder(evord); } if (el == len) { return new TermOrder(evord); } return new TermOrder(evord, evord2, len, el); } return new TermOrder(evord2); } /** * Reverse variables. Used e.g. in opposite rings. * @return TermOrder for reversed variables. */ public TermOrder reverse() { return reverse(false); } /** * Reverse variables. Used e.g. in opposite rings. * @param partial true for partially reversed term orders. * @return TermOrder for reversed variables. */ public TermOrder reverse(boolean partial) { TermOrder t; if (weight != null) { if (partial) { logger.error("partial reversed weight order not implemented"); } long[][] w = new long[weight.length][]; for (int i = 0; i < weight.length; i++) { long[] wi = weight[i]; long[] wj = new long[wi.length]; for (int j = 0; j < wj.length; j++) { wj[j] = wi[wj.length - 1 - j]; } w[i] = wj; } t = new TermOrder(w); logger.info("reverse = {}, from = {}", t, this); return t; } if (evord2 == 0) { t = new TermOrder(revert(evord)); return t; } if (partial) { t = new TermOrder(revert(evord), revert(evord2), evend2, evend1); } else { t = new TermOrder(revert(evord2), revert(evord), evend2, evend2 - evbeg2); } logger.info("reverse = {}, from = {}", t, this); return t; } /** * Revert exponent order. Used e.g. in opposite rings. * @param evord exponent order to be reverted. * @return reverted exponent order. */ public static int revert(int evord) { int i = evord; switch (evord) { case LEX: i = REVLEX; break; case INVLEX: i = REVILEX; break; case GRLEX: i = REVTDEG; break; case IGRLEX: i = REVITDG; break; case REVLEX: i = LEX; break; case REVILEX: i = INVLEX; break; case REVTDEG: i = GRLEX; break; case REVITDG: i = IGRLEX; break; default: // REVITDEG, ITDEGLEX logger.error("can not revert {}", evord); break; } return i; } /** * Permutation of a long array. * @param a array of long. * @param P permutation. * @return P(a). */ public static long[] longArrayPermutation(List P, long[] a) { if (a == null || a.length <= 1) { return a; } long[] b = new long[a.length]; int j = 0; for (Integer i : P) { b[j] = a[i]; j++; } return b; } /** * Permutation of the termorder. * @param P permutation. * @return P(a). */ public TermOrder permutation(List P) { TermOrder tord = this; if (getEvord2() != 0) { //throw new IllegalArgumentException("split term orders not permutable"); tord = new TermOrder(getEvord2()); logger.warn("split term order '{}' not permutable, resetting to most base term order {}", this, tord); } long[][] weight = getWeight(); if (weight != null) { long[][] w = new long[weight.length][]; for (int i = 0; i < weight.length; i++) { w[i] = longArrayPermutation(P, weight[i]); } tord = new TermOrder(w); } return tord; } /** * Weight TermOrder with reversed weight vectors. * @param w weight matrix * @return TermOrder with reversed weight vectors */ public static TermOrder reverseWeight(long[][] w) { if (w == null) { logger.warn("null weight matrix ignored"); return new TermOrder(); } long[][] wr = new long[w.length][]; for (int j = 0; j < w.length; j++) { long[] wj = w[j]; //System.out.println("reverseWeight: " + wj); long[] wrj = new long[wj.length]; for (int i = 0; i < wj.length; i++) { wrj[i] = wj[wj.length - 1 - i]; } wr[j] = wrj; } return new TermOrder(wr); } } java-algebra-system-2.7.200/src/edu/jas/poly/TermOrderByName.java000066400000000000000000000352111445075545500245060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Term order names for ordered polynomials. Defines names for the most used * term orders: graded and lexicographical orders. For the definitions see for * example the articles Kredel, * Admissible term orderings used in computer algebra systems and * Sit, Some comments on * term-ordering in Gröbner basis computations. Not all algorithms may * work with all term orders since not all are well-founded, so watch your step. * * Note: Variables in printed JAS polynomial (low, ..., medium, ..., * high) Variables in other CAS polynomial (high, ..., medium, ..., * low) with low < medium < high. Example: for * variables x1, ..., xr it is assumed in JAS that * x1 < ... < xr in other CAS it means x1 * > ... > xr. * * @author Heinz Kredel */ public class TermOrderByName { private static final Logger logger = LogManager.getLogger(TermOrderByName.class); /** * TermOrder named LEX. */ public static final TermOrder LEX = new TermOrder(TermOrder.LEX); /** * TermOrder named INVLEX. */ public static final TermOrder INVLEX = new TermOrder(TermOrder.INVLEX); /** * TermOrder named GRLEX. */ public static final TermOrder GRLEX = new TermOrder(TermOrder.GRLEX); /** * TermOrder named IGRLEX. */ public static final TermOrder IGRLEX = new TermOrder(TermOrder.IGRLEX); /** * TermOrder named REVLEX. */ public static final TermOrder REVLEX = new TermOrder(TermOrder.REVLEX); /** * TermOrder named REVILEX. */ public static final TermOrder REVILEX = new TermOrder(TermOrder.REVILEX); /** * TermOrder named REVTDEG. */ public static final TermOrder REVTDEG = new TermOrder(TermOrder.REVTDEG); /** * TermOrder named REVITDG. */ public static final TermOrder REVITDG = new TermOrder(TermOrder.REVITDG); /** * TermOrder named ITDEGLEX. */ public static final TermOrder ITDEGLEX = new TermOrder(TermOrder.ITDEGLEX); /** * TermOrder named REVITDEG. */ public static final TermOrder REVITDEG = new TermOrder(TermOrder.REVITDEG); /** * Default TermOrder. */ public final static TermOrder DEFAULT = new TermOrder(TermOrder.DEFAULT_EVORD); // Math like term orders: /** * TermOrder name Lexicographic of Math like CAS. */ public final static TermOrder Lexicographic = REVILEX; /** * TermOrder name NegativeLexicographic of Math like CAS. */ public final static TermOrder NegativeLexicographic = REVLEX; /** * TermOrder name DegreeLexicographic of Math like CAS. */ public final static TermOrder DegreeLexicographic = REVITDG; /** * TermOrder name NegativeDegreeLexicographic of Math like CAS. */ public final static TermOrder NegativeDegreeLexicographic = REVITDEG; // was REVTDEG; /** * TermOrder name ReverseLexicographic of Math like CAS. */ public final static TermOrder ReverseLexicographic = INVLEX; /** * TermOrder name DegreeReverseLexicographic of Math like CAS. */ public final static TermOrder DegreeReverseLexicographic = ITDEGLEX; // was IGRLEX; /** * TermOrder name NegativeReverseLexicographic of Math like CAS. */ public final static TermOrder NegativeReverseLexicographic = LEX; /** * TermOrder name NegativeDegreeReverseLexicographic of Math like CAS. */ public final static TermOrder NegativeDegreeReverseLexicographic = GRLEX; // Sage term orders: /** * TermOrder name lex of Sage. */ public final static TermOrder lex = Lexicographic; // = REVILEX; /** * TermOrder name degrevlex of Sage. */ public final static TermOrder degrevlex = DegreeReverseLexicographic; // = IGRLEX; /** * TermOrder name deglex of Sage. */ public final static TermOrder deglex = DegreeLexicographic; // = REVITDG; /** * TermOrder name invlex of Sage. */ public final static TermOrder invlex = INVLEX; //ReverseLexicographic /** * TermOrder name neglex of Sage. */ public final static TermOrder neglex = NegativeLexicographic; // = REVLEX; /** * TermOrder name negdegrevlex of Sage. */ public final static TermOrder negdegrevlex = NegativeDegreeReverseLexicographic; // = GRLEX; /** * TermOrder name negdeglex of Sage. */ public final static TermOrder negdeglex = NegativeDegreeLexicographic; // = REVTDEG; /** * TermOrder name negrevlex of Sage. */ public final static TermOrder negrevlex = NegativeReverseLexicographic; // = LEX; // Singular term orders: /** * TermOrder name lp of Singular. */ public final static TermOrder lp = lex; // = REVILEX; /** * TermOrder name dp of Singular. */ public final static TermOrder dp = degrevlex; // = IGRLEX; /** * TermOrder name Dp of Singular. */ public final static TermOrder Dp = deglex; // = REVITDG; /** * TermOrder name rp of Singular. */ public final static TermOrder rp = invlex; // = INVLEX; /** * TermOrder name ls of Singular. */ public final static TermOrder ls = neglex; // = REVLEX; /** * TermOrder name ds of Singular. */ public final static TermOrder ds = negdegrevlex; // = GRLEX; /** * TermOrder name Ds of Singular. */ public final static TermOrder Ds = negdeglex; // = REVTDEG; // missing: public final static TermOrder negrevlex; // = LEX; /** * Construct elimination block TermOrder. Variables {x1, ..., x * s-1} < {xs, ..., xr} * * @param t1 term order for both blocks * @param s split index * @return constructed term order */ public final static TermOrder blockOrder(TermOrder t1, int s) { return t1.blockOrder(s); } /** * Construct elimination block TermOrder. Variables {x1, ..., x * s-1} < {xs, ..., xr} * * @param t1 term order for both blocks * @param e exponent vector of desired length, r = length(e) * @param s split index * @return constructed term order */ public final static TermOrder blockOrder(TermOrder t1, ExpVector e, int s) { return t1.blockOrder(s, e.length()); } /** * Construct elimination block TermOrder. Variables {x1, ..., x * s-1} < {xs, ..., xr} * * @param t1 term order for lower valiables * @param t2 term order for higher variables * @param s split index * @return constructed term order */ public final static TermOrder blockOrder(TermOrder t1, TermOrder t2, int s) { return new TermOrder(t1.getEvord(), t2.getEvord(), Integer.MAX_VALUE, s); } /** * Construct elimination block TermOrder. Variables {x1, ..., x * s-1} < {xs, ..., xr} * * @param t1 term order for lower valiables * @param t2 term order for higher variables * @param e exponent vector of desired length, r = length(e) * @param s split index * @return constructed term order */ public final static TermOrder blockOrder(TermOrder t1, TermOrder t2, ExpVector e, int s) { return new TermOrder(t1.getEvord(), t2.getEvord(), e.length(), s); } /** * Construct weight TermOrder. * * @param v weight vector * @return constructed term order */ public final static TermOrder weightOrder(long[] v) { return TermOrder.reverseWeight(new long[][] { v }); } /** * Construct weight TermOrder. * * @param w weight matrix * @return constructed term order */ public final static TermOrder weightOrder(long[][] w) { return TermOrder.reverseWeight(w); } /** * Construct weight TermOrder. * * @param wa weight matrix as List * @return constructed term order */ public final static TermOrder weightOrder(List> wa) { int n = wa.size(); long[][] w = new long[n][]; for (int i = 0; i < n; i++) { List row = wa.get(i); int m = row.size(); long[] wi = new long[m]; for (int j = 0; j < m; j++) { wi[j] = row.get(j); } w[i] = wi; } //return TermOrder.reverseWeight(w); return weightOrder(w); } /** * Construct weight for term order. * @param to term order * @param n exponent vector size * @return weight matrix */ public final static long[][] weightForOrder(TermOrder to, int n) { if (to.isSplit()) { return weightForSplitOrder(to.getEvord(), to.getEvord2(), n, to.getSplit()); } return weightForOrder(to.getEvord(), n); } /** * Construct weight for term order. * @param to term order indicator * @param n exponent vector size * @return weight matrix */ /*public*/ final static long[][] weightForOrder(int to, int n) { int k = 0; switch (to) { case TermOrder.IGRLEX: k = n + 1; break; case TermOrder.REVILEX: // no break case TermOrder.INVLEX: k = n; break; default: } logger.info("to = {}, k = {}", to, k); long[][] w = new long[k][]; long[] wi; switch (to) { case TermOrder.INVLEX: for (int i = 0; i < n; i++) { w[i] = new long[n]; wi = w[i]; for (int j = 0; j < n; j++) { if (i == j) { //n - 1 - wi[j] = 1L; } else { wi[j] = 0L; } } } break; case TermOrder.IGRLEX: w[0] = new long[n]; wi = w[0]; for (int j = 0; j < n; j++) { wi[j] = 1L; } for (int i = 0; i < n; i++) { w[i + 1] = new long[n]; wi = w[i + 1]; for (int j = 0; j < n; j++) { if (i == j) { //n - 1 - wi[j] = 1L; } else { wi[j] = 0L; } } } break; case TermOrder.REVILEX: for (int i = 0; i < n; i++) { w[i] = new long[n]; wi = w[i]; for (int j = 0; j < n; j++) { if ((n - 1 - i) == j) { wi[j] = 1L; } else { wi[j] = 0L; } } } break; default: throw new UnsupportedOperationException("case " + to + " not implemented for weightForOrder"); } return w; } /** * Construct weight for split term order. * @param to first term order indicator * @param to2 second term order indicator * @param n exponent vector size * @param s slpit index * @return weight matrix */ /*public*/ final static long[][] weightForSplitOrder(int to, int to2, int n, int s) { int k = 0; switch (to) { case TermOrder.IGRLEX: k += 1; break; case TermOrder.INVLEX: k += s; break; default: } //System.out.println("to = " + to + ", k = " + k); switch (to2) { case TermOrder.IGRLEX: k += 1; break; case TermOrder.INVLEX: k += n - s; break; default: } logger.info("to = {}, k = {}", to, k); long[][] w = new long[k + n][]; boolean done = true; switch (to) { case TermOrder.IGRLEX: w[0] = new long[n]; long[] wi = w[0]; int j; for (j = 0; j < s; j++) { wi[j] = 1L; } for (; j < n; j++) { wi[j] = 0L; } break; case TermOrder.INVLEX: for (int i = 0; i < s; i++) { w[i] = new long[n]; wi = w[i]; // long[] for (j = 0; j < n; j++) { if ((n - 1 - i) == j) { wi[j] = 1L; } else { wi[j] = 0L; } } } break; default: done = false; // compiler/run time error: //throw new UnsupportedOperationException("case " + to + "/" + to2 + " not implemented for weightForOrder"); break; } switch (to2) { case TermOrder.IGRLEX: w[k - 1] = new long[n]; long[] wi = w[k - 1]; int j; for (j = 0; j < s; j++) { wi[j] = 0L; } for (; j < n; j++) { wi[j] = 1L; } break; case TermOrder.INVLEX: for (int i = 0; i < s; i++) { w[s + i] = new long[n]; wi = w[s + i]; // long[] for (j = 0; j < n; j++) { if ((n - 1 - i) == (s + j)) { wi[j] = 1L; } else { wi[j] = 0L; } } } break; default: done = false; break; } if (!done) { //System.out.println("weightForSplitOrder case " + to + "/" + to2); throw new UnsupportedOperationException( "case " + to + "/" + to2 + " not implemented for weightForOrder"); } //System.out.println("weight: " + Arrays.toString(w)); // break ties by inv lex term order for (int i = 0; i < n; i++) { w[k + i] = new long[n]; long[] wi = w[k + i]; for (int j = 0; j < n; j++) { if ((i) == j) { //n - 1 - wi[j] = 1L; } else { wi[j] = 0L; } } } return w; } } java-algebra-system-2.7.200/src/edu/jas/poly/TermOrderOptimization.java000066400000000000000000000512641445075545500260270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.structure.RingElem; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * Term order optimization. See mas10/maspoly/DIPTOO.m{di}. * @author Heinz Kredel */ public class TermOrderOptimization { private static final Logger logger = LogManager.getLogger(TermOrderOptimization.class); private static final boolean debug = logger.isDebugEnabled(); /** * Degree matrix. * @param A polynomial to be considered. * @return degree matrix. */ public static > List> degreeMatrix(GenPolynomial A) { List> dem = null; if (A == null) { return dem; } BigInteger cfac = new BigInteger(); GenPolynomialRing ufac = new GenPolynomialRing(cfac, new String[] {"dm"} ); int nvar = A.numberOfVariables(); dem = new ArrayList>(nvar); for (int i = 0; i < nvar; i++) { dem.add(ufac.getZERO()); } if (A.isZERO()) { return dem; } for (ExpVector e : A.getMap().keySet()) { dem = expVectorAdd(dem, e); } return dem; } /** * Degree matrix exponent vector add. * @param dm degree matrix. * @param e exponent vector. * @return degree matrix + e. */ public static List> expVectorAdd(List> dm, ExpVector e) { for (int i = 0; i < dm.size() && i < e.length(); i++) { GenPolynomial p = dm.get(i); long u = e.getVal(i); ExpVector f = ExpVector.create(1, 0, u); p = p.sum(p.ring.getONECoefficient(), f); dm.set(i, p); } return dm; } /** * Degree matrix of coefficient polynomials. * @param A polynomial to be considered. * @return degree matrix for the coefficients. */ public static > List> degreeMatrixOfCoefficients( GenPolynomial> A) { if (A == null) { throw new IllegalArgumentException("polynomial must not be null"); } return degreeMatrix(A.getMap().values()); } /** * Degree matrix. * @param L list of polynomial to be considered. * @return degree matrix. */ public static > List> degreeMatrix( Collection> L) { if (L == null) { throw new IllegalArgumentException("list must be non null"); } GenVectorModul> vmblas = null; GenVector> vdem = null; for (GenPolynomial p : L) { List> dm = degreeMatrix(p); if (vdem == null) { vmblas = new GenVectorModul>(dm.get(0).ring, dm.size()); vdem = new GenVector>(vmblas, dm); } else { vdem = vdem.sum(new GenVector>(vmblas, dm)); } } return vdem.val; } /** * Degree matrix of coefficient polynomials. * @param L list of polynomial to be considered. * @return degree matrix for the coefficients. */ public static > List> degreeMatrixOfCoefficients( Collection>> L) { if (L == null) { throw new IllegalArgumentException("list must not be null"); } GenVectorModul> vmblas = null; GenVector> vdem = null; for (GenPolynomial> p : L) { List> dm = degreeMatrixOfCoefficients(p); if (vdem == null) { vmblas = new GenVectorModul>(dm.get(0).ring, dm.size()); vdem = new GenVector>(vmblas, dm); } else { vdem = vdem.sum(new GenVector>(vmblas, dm)); } } return vdem.val; } /** * Optimal permutation for the Degree matrix. * @param D degree matrix. * @return optimal permutation for D. */ public static List optimalPermutation(List> D) { if (D == null) { throw new IllegalArgumentException("list must be non null"); } List P = new ArrayList(D.size()); if (D.size() == 0) { return P; } if (D.size() == 1) { P.add(0); return P; } SortedMap, List> map = new TreeMap, List>(); int i = 0; for (GenPolynomial p : D) { List il = map.get(p); if (il == null) { il = new ArrayList(3); } il.add(i); map.put(p, il); i++; } List> V = new ArrayList>(map.values()); //System.out.println("V = " + V); if (debug) { logger.info("V,opt = {}", V); } //for ( int j = V.size()-1; j >= 0; j-- ) { for (int j = 0; j < V.size(); j++) { List v = V.get(j); for (Integer k : v) { P.add(k); } } return P; } /** * Inverse of a permutation. * @param P permutation. * @return S with S*P = id. */ public static List inversePermutation(List P) { if (P == null || P.size() <= 1) { return P; } List ip = new ArrayList(P); // ensure size and content for (int i = 0; i < P.size(); i++) { ip.set(P.get(i), i); // inverse } return ip; } /** * Test for identity permutation. * @param P permutation. * @return true , if P = id, else false. */ public static boolean isIdentityPermutation(List P) { if (P == null || P.size() <= 1) { return true; } for (int i = 0; i < P.size(); i++) { if (P.get(i).intValue() != i) { return false; } } return true; } /** * Multiplication permutations. * @param P permutation. * @param S permutation. * @return P*S. */ public static List multiplyPermutation(List P, List S) { if (P == null || S == null) { return null; } if (P.size() != S.size()) { throw new IllegalArgumentException("#P != #S: P =" + P + ", S = " + S); } List ip = new ArrayList(P); // ensure size and content for (int i = 0; i < P.size(); i++) { ip.set(i, S.get(P.get(i))); } return ip; } /** * Permutation of a list. * @param L list. * @param P permutation. * @return P(L). */ @SuppressWarnings("cast") public static List listPermutation(List P, List L) { if (L == null || L.size() <= 1) { return L; } List pl = new ArrayList(L.size()); for (Integer i : P) { pl.add(L.get((int) i)); } return pl; } /** * Permutation of an array. Compiles, but does not work, requires JDK 1.6 to * work. * @param a array. * @param P permutation. * @return P(a). */ @SuppressWarnings({ "unchecked", "cast" }) public static T[] arrayPermutation(List P, T[] a) { if (a == null || a.length <= 1) { return a; } //T[] b = (T[]) new Object[a.length]; // jdk 1.5 T[] b = Arrays. copyOf( a, a.length ); // jdk 1.6, works int j = 0; for (Integer i : P) { b[j] = a[(int) i]; j++; } return b; } /** * Permutation of polynomial exponent vectors. * @param A polynomial. * @param R polynomial ring. * @param P permutation. * @return P(A). */ public static > GenPolynomial permutation(List P, GenPolynomialRing R, GenPolynomial A) { if (A == null) { return A; } GenPolynomial B = R.getZERO().copy(); Map Bv = B.val; //getMap(); for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); //System.out.println("e = " + e); ExpVector f = e.permutation(P); //System.out.println("f = " + f); Bv.put(f, a); // assert f not in Bv } return B; } /** * Permutation of polynomial exponent vectors. * @param L list of polynomials. * @param R polynomial ring. * @param P permutation. * @return P(L). */ public static > List> permutation(List P, GenPolynomialRing R, List> L) { if (L == null || L.size() == 0) { return L; } List> K = new ArrayList>(L.size()); for (GenPolynomial a : L) { GenPolynomial b = permutation(P, R, a); K.add(b); } return K; } /** * Permutation of solvable polynomial exponent vectors. * @param L list of solvable polynomials. * @param R solvable polynomial ring. * @param P permutation, must be compatible with the commutator relations. * @return P(L). */ public static > List> permutation(List P, GenSolvablePolynomialRing R, List> L) { if (L == null || L.size() == 0) { return L; } List> K = new ArrayList>(L.size()); for (GenSolvablePolynomial a : L) { GenSolvablePolynomial b; b = (GenSolvablePolynomial) permutation(P, (GenPolynomialRing) R, (GenPolynomial) a); K.add(b); } return K; } /** * Permutation of polynomial exponent vectors of coefficient polynomials. * @param A polynomial. * @param R polynomial ring. * @param P permutation. * @return P(A). */ public static > GenPolynomial> permutationOnCoefficients( List P, GenPolynomialRing> R, GenPolynomial> A) { if (A == null) { return A; } GenPolynomial> B = R.getZERO().copy(); GenPolynomialRing cf = (GenPolynomialRing) R.coFac; Map> Bv = B.val; //getMap(); for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); //System.out.println("e = " + e); GenPolynomial b = permutation(P, cf, a); //System.out.println("b = " + b); Bv.put(e, b); // assert e not in Bv } return B; } /** * Permutation of polynomial exponent vectors of coefficients. * @param L list of polynomials. * @param R polynomial ring. * @param P permutation. * @return P(L). */ public static > List>> permutationOnCoefficients( List P, GenPolynomialRing> R, List>> L) { if (L == null || L.size() == 0) { return L; } List>> K = new ArrayList>>(L.size()); for (GenPolynomial> a : L) { GenPolynomial> b = permutationOnCoefficients(P, R, a); K.add(b); } return K; } /** * Permutation of polynomial ring variables. * @param R polynomial ring. * @param P permutation. * @return P(R). */ public static > GenPolynomialRing permutation(List P, GenPolynomialRing R) { return R.permutation(P); } /** * Optimize variable order. * @param R polynomial ring. * @param L list of polynomials. * @return optimized polynomial list. */ public static > OptimizedPolynomialList optimizeTermOrder( GenPolynomialRing R, List> L) { List> Lp = new ArrayList>(L); if (R instanceof GenSolvablePolynomialRing) { // look also on solvable relations GenSolvablePolynomialRing Rs = (GenSolvablePolynomialRing) R; Lp.addAll(Rs.table.relationList()); } List perm = optimalPermutation(degreeMatrix(Lp)); GenPolynomialRing pring = R.permutation(perm); List> ppolys = permutation(perm, pring, L); OptimizedPolynomialList op = new OptimizedPolynomialList(perm, pring, ppolys); return op; } /** * Optimize variable order. * @param P polynomial list. * @return optimized polynomial list. */ public static > OptimizedPolynomialList optimizeTermOrder(PolynomialList P) { if (P == null) { return null; } return optimizeTermOrder(P.ring, P.list); } /** * Optimize variable order on coefficients. * @param P polynomial list. * @return optimized polynomial list. */ public static > OptimizedPolynomialList> optimizeTermOrderOnCoefficients( PolynomialList> P) { return optimizeTermOrderOnCoefficients(P.ring, P.list); } /** * Optimize variable order on coefficients. * @param ring polynomial ring. * @param L list of polynomials. * @return optimized polynomial list. */ @SuppressWarnings("cast") public static > OptimizedPolynomialList> optimizeTermOrderOnCoefficients( GenPolynomialRing> ring, List>> L) { if (L == null) { return null; } List>> Lp = new ArrayList>>(L); //GenPolynomialRing> ring = P.ring; if (ring instanceof GenSolvablePolynomialRing) { // look also on solvable relations GenSolvablePolynomialRing> Rs = (GenSolvablePolynomialRing>) ring; Lp.addAll(Rs.table.relationList()); } List perm = optimalPermutation(degreeMatrixOfCoefficients(Lp)); GenPolynomialRing coFac = (GenPolynomialRing) ring.coFac; GenPolynomialRing pFac = coFac.permutation(perm); GenSolvablePolynomialRing> sring, psring; GenPolynomialRing> pring; if (ring instanceof GenSolvablePolynomialRing) { // permute also solvable relations sring = (GenSolvablePolynomialRing>) ring; psring = new GenSolvablePolynomialRing>(pFac, sring); List>> ir = PolynomialList .> castToList(sring.table.relationList()); ir = permutationOnCoefficients(perm, psring, ir); psring.addRelations(ir); pring = (GenPolynomialRing>) psring; } else { pring = new GenPolynomialRing>(pFac, ring); } List>> ppolys; ppolys = permutationOnCoefficients(perm, pring, L); OptimizedPolynomialList> op; op = new OptimizedPolynomialList>(perm, pring, ppolys); return op; } /** * Optimize variable order. * @param P module list. * @return optimized module list. */ public static > OptimizedModuleList optimizeTermOrder(ModuleList P) { if (P == null) { return null; } return optimizeTermOrderModule(P.ring, P.list); } /** * Optimize variable order. * @param R polynomial ring. * @param L list of lists of polynomials. * @return optimized module list. */ public static > OptimizedModuleList optimizeTermOrderModule( GenPolynomialRing R, List>> L) { List> M = new ArrayList>(); for (List> ll : L) { M.addAll(ll); } if (R instanceof GenSolvablePolynomialRing) { // look also on solvable relations GenSolvablePolynomialRing Rs = (GenSolvablePolynomialRing) R; M.addAll(Rs.table.relationList()); } List perm = optimalPermutation(degreeMatrix(M)); GenPolynomialRing pring = R.permutation(perm); List>> mpolys = new ArrayList>>(); List> pp; for (List> ll : L) { pp = permutation(perm, pring, ll); mpolys.add(pp); } OptimizedModuleList op = new OptimizedModuleList(perm, pring, mpolys); return op; } /** * Optimize variable order on coefficients. * @param P module list. * @return optimized module list. */ @SuppressWarnings("cast") public static > OptimizedModuleList> optimizeTermOrderOnCoefficients( ModuleList> P) { if (P == null) { return null; } GenPolynomialRing> ring = P.ring; List>> M = new ArrayList>>(); for (List>> ll : P.list) { M.addAll(ll); } if (ring instanceof GenSolvablePolynomialRing) { // look also on solvable relations GenSolvablePolynomialRing> Rs = (GenSolvablePolynomialRing>) ring; M.addAll(Rs.table.relationList()); } List perm = optimalPermutation(degreeMatrixOfCoefficients(M)); GenPolynomialRing coFac = (GenPolynomialRing) ring.coFac; GenPolynomialRing pFac = coFac.permutation(perm); GenSolvablePolynomialRing> sring, psring; GenPolynomialRing> pring; if (ring instanceof GenSolvablePolynomialRing) { // permute also solvable relations sring = (GenSolvablePolynomialRing>) ring; psring = new GenSolvablePolynomialRing>(pFac, sring); List>> ir = PolynomialList .> castToList(sring.table.relationList()); ir = permutationOnCoefficients(perm, psring, ir); psring.addRelations(ir); pring = (GenPolynomialRing>) psring; } else { pring = new GenPolynomialRing>(pFac, ring); } List>> pp; List>>> mpolys; mpolys = new ArrayList>>>(); for (List>> ll : P.list) { pp = permutationOnCoefficients(perm, pring, ll); mpolys.add(pp); } OptimizedModuleList> op = new OptimizedModuleList>(perm, pring, mpolys); return op; } } java-algebra-system-2.7.200/src/edu/jas/poly/WeylRelations.java000066400000000000000000000072301445075545500243100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.structure.RingElem; /** * Generate Relation Table for Weyl Algebras Adds the respective relations to * the relation table of the given solvable ring factory. Relations are of the * form xj * xi = xi xj + 1. * Block form: R{x1,...,xn,y1,...,yn; yi*xi = xi yi + 1}. * @author Heinz Kredel */ public class WeylRelations> implements RelationGenerator { /** * The factory for the solvable polynomial ring. */ private final GenSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(WeylRelations.class); /** * The no argument constructor. The relation table of this ring is setup to * a Weyl Algebra. */ public WeylRelations() { ring = null; } /** * The constructor requires a ring factory. The relation table of this ring * is setup to a Weyl Algebra. * @param r solvable polynomial ring factory, r must have even number of * variables. */ public WeylRelations(GenSolvablePolynomialRing r) { if (r == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } ring = r; if (ring.nvar <= 1 || (ring.nvar % 2) != 0) { throw new IllegalArgumentException("WeylRelations, wrong nvar = " + ring.nvar); } } /** * Generates the relation table of this ring. Block form: * R{x1,...,xn,y1,...,yn; yi*xi = xi yi + 1}. */ public void generate() { if (ring == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } generate(ring); } /** * Generates the relation table of this ring. Block form: * R{x1,...,xn,y1,...,yn; yi*xi = xi yi + 1}. * @param ring solvable polynomial ring factory, ring must have even number * of variables. * @see edu.jas.poly.RelationGenerator#generate(edu.jas.poly.GenSolvablePolynomialRing) */ @Override public void generate(GenSolvablePolynomialRing ring) { if (ring == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } if (ring.nvar <= 1 || (ring.nvar % 2) != 0) { throw new IllegalArgumentException("WeylRelations, wrong nvar = " + ring.nvar); } RelationTable table = ring.table; int r = ring.nvar; int m = r / 2; GenSolvablePolynomial one = ring.getONE().copy(); GenSolvablePolynomial zero = ring.getZERO().copy(); for (int i = m; i < r; i++) { ExpVector f = ExpVector.create(r, i, 1); int j = i - m; ExpVector e = ExpVector.create(r, j, 1); ExpVector ef = e.sum(f); GenSolvablePolynomial b = one.multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) b.sum(one); // = (GenSolvablePolynomial)b.subtract(one); if (rel.isZERO()) { logger.info("ring = {}", ring); logger.info("one = {}", one); logger.info("zero = {}", zero); logger.info("b = {}", b); logger.info("rel = {}", rel); //System.exit(1); throw new RuntimeException("rel.isZERO()"); } //System.out.println("rel = " + rel.toString(ring.vars)); table.update(e, f, rel); } logger.debug("\nWeyl relations = {}", table); return; } } java-algebra-system-2.7.200/src/edu/jas/poly/WeylRelationsIterated.java000066400000000000000000000071221445075545500257720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.structure.RingElem; /** * Generate Relation Table for Weyl Algebras Adds the respective relations to * the relation table of the given solvable ring factory. Relations are of the * form xj * xi = xi xj + 1. * Iterated form: R{x1,y1,...,xn,yn; yi*xi = xi yi + 1}. * @author Heinz Kredel */ public class WeylRelationsIterated> implements RelationGenerator { /** * The factory for the solvable polynomial ring. */ private final GenSolvablePolynomialRing ring; private static final Logger logger = LogManager.getLogger(WeylRelationsIterated.class); /** * The no argument constructor. The relation table of this ring is setup to * a Weyl Algebra. */ public WeylRelationsIterated() { ring = null; } /** * The constructor requires a ring factory. The relation table of this ring * is setup to a Weyl Algebra. * @param r solvable polynomial ring factory, r must have even number of * variables. */ public WeylRelationsIterated(GenSolvablePolynomialRing r) { if (r == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } ring = r; if (ring.nvar <= 1 || (ring.nvar % 2) != 0) { throw new IllegalArgumentException("WeylRelations, wrong nvar = " + ring.nvar); } } /** * Generates the relation table of this ring. Iterated form: * R{x1,y1,...,xn,yn; yi*xi = xi yi + 1}. */ public void generate() { if (ring == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } generate(ring); } /** * Generates the relation table of this ring. Iterated form: * R{x1,y1,...,xn,yn; yi*xi = xi yi + 1}. * @param ring solvable polynomial ring factory, ring must have even number * of variables. */ public void generate(GenSolvablePolynomialRing ring) { if (ring == null) { throw new IllegalArgumentException("WeylRelations, ring == null"); } if (ring.nvar <= 1 || (ring.nvar % 2) != 0) { throw new IllegalArgumentException("WeylRelations, wrong nvar = " + ring.nvar); } RelationTable table = ring.table; int r = ring.nvar; //int m = r / 2; GenSolvablePolynomial one = ring.getONE().copy(); GenSolvablePolynomial zero = ring.getZERO().copy(); for (int i = 1; i <= r; i += 2) { ExpVector f = ExpVector.create(r, i, 1); int j = i - 1; ExpVector e = ExpVector.create(r, j, 1); ExpVector ef = e.sum(f); GenSolvablePolynomial b = one.multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) b.sum(one); // = (GenSolvablePolynomial)b.subtract(one); if (rel.isZERO()) { logger.info("ring = {}", ring); logger.info("one = {}", one); logger.info("zero = {}", zero); logger.info("b = {}", b); logger.info("rel = {}", rel); //System.exit(1); throw new RuntimeException("rel.isZERO()"); } //System.out.println("rel = " + rel.toString(ring.vars)); table.update(e, f, rel); } logger.debug("\nWeyl relations = {}", table); return; } } java-algebra-system-2.7.200/src/edu/jas/poly/Word.java000066400000000000000000000422561445075545500224310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.SortedMap; import java.util.TreeMap; import edu.jas.structure.MonoidElem; import edu.jas.structure.MonoidFactory; import edu.jas.structure.NotInvertibleException; /** * Word implements strings of letters for polynomials. * @author Heinz Kredel */ public final class Word implements MonoidElem { /** * Defining alphabet in WordFactory. */ public final WordFactory mono; /** * The data structure is a String of characters. */ /*package*/final String val; /** * Stored hash code. */ protected int hash = 0; /** * Constructor for Word. * @param m factory for words. */ public Word(WordFactory m) { this(m, ""); } /** * Constructor for Word. * @param m factory for words. * @param s String */ public Word(WordFactory m, String s) { this(m, s, true); } /** * Constructor for Word. * @param m factory for words. * @param s String * @param translate indicator if s needs translation */ public Word(WordFactory m, String s, boolean translate) { mono = m; hash = 0; if (s == null) { throw new IllegalArgumentException("null string not allowed"); } if (translate) { if (mono.translation != null) { //System.out.println("s = " + s); String[] S = GenPolynomialTokenizer.variableList(s); //System.out.println("S = " + Arrays.toString(S)); val = mono.translate(S); //System.out.println("val = " + val); } else { val = WordFactory.cleanSpace(s); //?? } } else { val = s; } } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public MonoidFactory factory() { return mono; } /** * Copy this. * @return copy of this. */ @Override public Word copy() { return new Word(mono, val, false); } /** * Get the word String. * @return val. */ /*package*/String getVal() { return val; } /** * Get the letter at position i. * @param i position. * @return val[i]. */ public char getVal(int i) { return val.charAt(i); } /** * Get the length of this word. * @return val.length. */ public int length() { return val.length(); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { if (val.length() == 0) { return ""; } StringBuffer s = new StringBuffer("\""); if (mono.translation == null) { for (int i = 0; i < length(); i++) { if (i != 0) { s.append(" "); } s.append(getVal(i)); } } else { for (int i = 0; i < length(); i++) { if (i != 0) { s.append(" "); } s.append(mono.transVar(getVal(i))); } } s.append("\""); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { if (val.length() == 0) { return ""; } StringBuffer s = new StringBuffer(""); if (mono.translation == null) { for (int i = 0; i < length(); i++) { if (i != 0) { s.append("*"); // checked for python vs ruby } s.append(getVal(i)); } } else { for (int i = 0; i < length(); i++) { if (i != 0) { s.append("*"); // checked for python vs ruby } s.append(mono.transVar(getVal(i))); } } s.append(""); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return mono.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof Word)) { return false; } Word b = (Word) B; // mono == b.mono ?? int t = this.compareTo(b); //System.out.println("equals: this = " + this.val + " b = " + b.val + " t = " + t); return (0 == t); } /** * hashCode. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { if (hash == 0) { hash = val.hashCode(); } return hash; } /** * Is Word one. * @return If this is the empty word then true is returned, else false. */ public boolean isONE() { return val.isEmpty(); } /** * Is Word unit. * @return If this is a unit then true is returned, else false. */ public boolean isUnit() { return isONE(); } /** * Word multiplication. * @param V other word. * @return this * V. */ public Word multiply(Word V) { return new Word(mono, this.val + V.val, false); } /** * Word divide. * @param V other word. * @return this / V. */ public Word divide(Word V) { return divideLeft(V); } /** * Word divide left. * @param V other word. * @return this / V = left, with left * V = this. */ public Word divideLeft(Word V) { Word[] ret = divideWord(V,false); // fail if right is non zero if (!ret[1].isONE()) { throw new IllegalArgumentException("not simple left dividable: left = " + ret[0] + ", right = " + ret[1] + ", use divideWord"); } return ret[0]; } /** * Word divide right. * @param V other word. * @return this / V = right, with V * right = this. */ public Word divideRight(Word V) { Word[] ret = divideWord(V,true); // fail if left is non zero if (!ret[0].isONE()) { throw new IllegalArgumentException("not simple right dividable: left = " + ret[0] + ", right = " + ret[1] + ", use divideWord"); } return ret[1]; } /** * Word divide with prefix and suffix. * @param V other word. * @return [left,right] with left * V * right = this. */ public Word[] divideWord(Word V) { return divideWord(V,true); } /** * Word divide with prefix and suffix. * @param V other word. * @param first is true for first index, false for last index. * @return [left,right] with left * V * right = this. */ public Word[] divideWord(Word V, boolean first) { int i; if (first) { i = this.val.indexOf(V.val); } else { i = this.val.lastIndexOf(V.val); } if (i < 0) { throw new NotInvertibleException("not dividable: " + this + ", other " + V); } int len = V.val.length(); String pre = this.val.substring(0, i); String suf = this.val.substring(i + len); Word[] ret = new Word[2]; ret[0] = new Word(mono, pre, false); ret[1] = new Word(mono, suf, false); return ret; } /** * Word remainder. * @param V other word. * @return this - (this/V). Note: not useful. */ public Word remainder(Word V) { int i = this.val.indexOf(V.val); if (i < 0) { throw new NotInvertibleException("not dividable: " + this + ", other " + V); } return V; } /** * Quotient and remainder by division of this by S. * @param S a Word * @return [this/S, this - (this/S)*S]. Note: not useful. */ public Word[] quotientRemainder(Word S) { return new Word[] { divide(S), remainder(S) }; } /** * Word inverse. * @return 1 / this. */ public Word inverse() { if (val.length() == 0) { return this; } throw new NotInvertibleException("not inversible " + this); } /** * Word signum. * @return 0 if this is one, 1 if it is non empty. */ public int signum() { int i = val.length(); if (i > 0) { i = 1; } assert i >= 0; return i; } /** * Word degree. * @return total degree of all letters. */ public long degree() { return val.length(); } /** * Word dependency on letters. * @return sorted map of letters and the number of its occurrences. */ public SortedMap dependencyOnVariables() { return histogram(val); } /** * String dependency on letters. * @param v string. * @return sorted map of letters and the number of its occurrences. */ public static SortedMap histogram(String v) { SortedMap map = new TreeMap(); for (int i = 0; i < v.length(); i++) { String s = String.valueOf(v.charAt(i)); Integer n = map.get(s); if (n == null) { n = 0; } n = n + 1; map.put(s, n); } return map; } /** * Word leading exponent vector. * @return an ExpVector for the first power of a letter. */ public ExpVector leadingExpVector() { long n = 0; char letter = ' '; for (int i = 0; i < val.length(); i++) { char s = val.charAt(i); if (n == 0) { letter = s; n++; } else if (letter == s) { n++; } else { break; } } int k = mono.length(); if (n == 0L){ // == isONE() return ExpVector.create(k); } int j = k - mono.indexOf(letter) - 1; return ExpVector.create(k,j,n); } /** * Word without leading exponent vector. * @return an Word without the first power of a letter. */ public Word reductum() { if (isONE()) { return this; } int n = 0; char letter = ' '; for (int i = 0; i < val.length(); i++) { char s = val.charAt(i); if (n == 0) { letter = s; n++; } else if (letter == s) { n++; } else { break; } } // n != 0 String r = val.substring(n); // n-1+1 return new Word(mono, r, false); } /** * Word multiple test. * @param V other word. * @return true if this is a multiple of V, else false. */ public boolean multipleOf(Word V) { return this.val.contains(V.val); } /** * Word divides test. * @param V other word. * @return true if this divides V, else false. */ public boolean divides(Word V) { return V.val.contains(this.val); } /** * Word compareTo. Uses String.compareTo. * @param V other word. * @return 0 if U == V, -1 if U < V, 1 if U > V. */ @Override public int compareTo(Word V) { if (mono == V.mono) { return val.compareTo(V.val); } //System.out.println("compareTo: mono " + mono + ", V = " + V.mono); return toString().compareTo(V.toString()); } /** * Word graded comparison. Compares first be degree, then lexicographical. * @param V other word. * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public int gradCompareTo(Word V) { long e = this.degree(); long f = V.degree(); if (e < f) { return 1; } else if (e > f) { return -1; } return this.compareTo(V); } /** * Word graded comparison. Compares first be degree, then inverse * lexicographical. * @param V other word. * @return 0 if U == V, -1 if U < V, 1 if U > V. */ public int gradInvlexCompareTo(Word V) { long e = this.degree(); long f = V.degree(); if (e < f) { return 1; } else if (e > f) { return -1; } return -this.compareTo(V); } /** * Is word overlap. * @param ol = [l1,r1,l2,r2] an Overlap container of four words * @param V word * @return true if l1 * this * r1 = l2 * V * r2, else false. */ public boolean isOverlap(Overlap ol, Word V) { return ol.isOverlap(this, V); } /** * Word overlap list. * @param V other word. * @return list of overlaps [l1,r1,l2,r2] with l1 * this * r1 = l2 * V * r2. * If no such overlaps exist the empty overlap list is returned. */ public OverlapList overlap(Word V) { OverlapList ret = new OverlapList(); Word wone = mono.getONE(); String a = this.val; String b = V.val; int ai = a.length(); int bi = b.length(); int j = b.indexOf(a); if (j >= 0) { while (j >= 0) { String pre = b.substring(0, j); String suf = b.substring(j + ai); Word wpre = new Word(mono, pre, false); Word wsuf = new Word(mono, suf, false); ret.add(new Overlap(wpre, wsuf, wone, wone)); j = b.indexOf(a, j + ai); // +1 also inner overlaps ? } return ret; } j = a.indexOf(b); if (j >= 0) { while (j >= 0) { String pre = a.substring(0, j); String suf = a.substring(j + bi); Word wpre = new Word(mono, pre, false); Word wsuf = new Word(mono, suf, false); ret.add(new Overlap(wone, wone, wpre, wsuf)); j = a.indexOf(b, j + bi); // +1 also inner overlaps ? } return ret; } if (ai >= bi) { for (int i = 0; i < bi; i++) { String as = a.substring(0, i + 1); String bs = b.substring(bi - i - 1, bi); //System.out.println("i = " + i + ", bs = " + bs + ", as = " + as); if (as.equals(bs)) { Word w1 = new Word(mono, b.substring(0, bi - i - 1), false); Word w2 = new Word(mono, a.substring(i + 1), false); ret.add(new Overlap(w1, wone, wone, w2)); break; } } for (int i = 0; i < bi; i++) { String as = a.substring(ai - i - 1, ai); String bs = b.substring(0, i + 1); //System.out.println("i = " + i + ", bs = " + bs + ", as = " + as); if (as.equals(bs)) { Word w1 = new Word(mono, b.substring(i + 1), false); Word w2 = new Word(mono, a.substring(0, ai - i - 1), false); ret.add(new Overlap(wone, w1, w2, wone)); break; } } } else { // ai < bi for (int i = 0; i < ai; i++) { String as = a.substring(ai - i - 1, ai); String bs = b.substring(0, i + 1); //System.out.println("i = " + i + ", bs = " + bs + ", as = " + as); if (as.equals(bs)) { Word w1 = new Word(mono, b.substring(i + 1), false); Word w2 = new Word(mono, a.substring(0, ai - i - 1), false); ret.add(new Overlap(wone, w1, w2, wone)); break; } } for (int i = 0; i < ai; i++) { String as = a.substring(0, i + 1); String bs = b.substring(bi - i - 1, bi); //System.out.println("i = " + i + ", bs = " + bs + ", as = " + as); if (as.equals(bs)) { Word w1 = new Word(mono, b.substring(0, bi - i - 1), false); Word w2 = new Word(mono, a.substring(i + 1), false); ret.add(new Overlap(w1, wone, wone, w2)); break; } } } return ret; } /** * Word pseudo least common multiple. * @param V other word. * @return w = l1*this*r1, with l1*this*r1 == l2*V*r2, if l1, r1, l2, r2 * exist, else null is returned. */ public Word lcm(Word V) { OverlapList oll = overlap(V); if (oll.ols.isEmpty()) { return null; } Overlap ol = oll.ols.get(0); Word w = ol.l1.multiply(this).multiply(ol.r1); return w; } } java-algebra-system-2.7.200/src/edu/jas/poly/WordFactory.java000066400000000000000000000417261445075545500237620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.Reader; import java.io.Serializable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Map; //import java.util.Set; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.StringUtil; import edu.jas.structure.MonoidFactory; /** * WordFactory implements alphabet related methods. * @author Heinz Kredel */ public final class WordFactory implements MonoidFactory { /** * The data structure is a String of characters which defines the alphabet. */ /*package*/final String alphabet; /** * The empty word for this monoid. */ public final Word ONE; /** * The translation reference string. */ public static final String transRef = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /** * The translation array of Strings. */ public final String[] translation; /** * Random number generator. */ private final static Random random = new Random(); /** * Log4j logger object. */ private static final Logger logger = LogManager.getLogger(WordFactory.class); /** * Comparator for Words. */ public static abstract class WordComparator implements Comparator, Serializable { public abstract int compare(Word e1, Word e2); } /** * Defined descending order comparator. Sorts the highest terms first. */ private static final WordComparator horder = new WordComparator() { @Override public int compare(Word e1, Word e2) { //return e1.gradCompareTo(e2); return e1.gradInvlexCompareTo(e2); } }; /** * Defined ascending order comparator. Sorts the lowest terms first. */ private static final WordComparator lorder = new WordComparator() { @Override public int compare(Word e1, Word e2) { //return -e1.gradCompareTo(e2); return -e1.gradInvlexCompareTo(e2); } }; /** * Constructor for WordFactory. */ public WordFactory() { this(""); } /** * Constructor for WordFactory. * @param s String of single letters for alphabet */ public WordFactory(String s) { if (s == null) { throw new IllegalArgumentException("null string not allowed"); } String alp = cleanSpace(s); translation = null; Map hist = Word.histogram(alp); if (hist.size() != alp.length()) { logger.warn("multiple characters in String: {}", hist); //Set k = hist.keySet(); String[] ka = hist.keySet().toArray(new String[hist.size()]); alphabet = concat(ka); } else { alphabet = alp; } //System.out.println("hist = " + hist); ONE = new Word(this, "", false); } /** * Constructor for WordFactory. * @param S String array for alphabet */ public WordFactory(String[] S) { String[] V = cleanAll(S); if (isSingleLetters(V)) { alphabet = concat(V); translation = null; } else { alphabet = transRef.substring(0, V.length); translation = V; logger.info("alphabet = {}, translation = {}", alphabet, Arrays.toString(translation)); } ONE = new Word(this, "", false); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { if (alphabet.length() == 0) { return true; } return false; } /** * Query if this monoid is commutative. * @return true if this monoid is commutative, else false. */ public boolean isCommutative() { if (alphabet.length() == 0) { return true; } return false; } /** * Query if this monoid is associative. * @return true if this monoid is associative, else false. */ public boolean isAssociative() { return true; } /** * Get the one element, the empty word. * @return 1 as Word. */ public Word getONE() { return ONE; } /** * Copy word. * @param w word to copy. * @return copy of w. */ @Override public Word copy(Word w) { return new Word(this, w.getVal(), false); } /** * Get the alphabet length. * @return alphabet.length. */ public int length() { return alphabet.length(); } /** * Get the alphabet String. * @return alphabet. */ /*package*/String getVal() { return alphabet; } /** * Get the translation array of Strings. * @return alphabet. */ /*package*/String[] getTrans() { return translation; } /** * Get the alphabet letter at position i. * @param i position. * @return val[i]. */ public char getVal(int i) { return alphabet.charAt(i); } /** * Get the variable names. * @return array of variable names */ public String[] getVars() { String[] vars = new String[alphabet.length()]; if (translation == null) { for (int i = 0; i < alphabet.length(); i++) { vars[i] = String.valueOf(getVal(i)); } } else { for (int i = 0; i < alphabet.length(); i++) { vars[i] = translation[i]; } } return vars; } /** * Extend variables. Extend number of variables by length(vn). * @param vn names for extended variables. * @return extended word ring factory. */ public WordFactory extend(String[] vn) { String[] vars = new String[length() + vn.length]; int i = 0; for (String v : getVars()) { vars[i++] = v; } for (String v : vn) { vars[i++] = v; } return new WordFactory(vars); } /** * Get the string representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer("\""); if (translation == null) { for (int i = 0; i < alphabet.length(); i++) { if (i != 0) { s.append(","); } s.append(getVal(i)); } } else { for (int i = 0; i < alphabet.length(); i++) { if (i != 0) { s.append(","); } s.append(translation[i]); } } s.append("\""); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { return toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object B) { if (!(B instanceof WordFactory)) { return false; } WordFactory b = (WordFactory) B; return alphabet.equals(b.alphabet); } /** * hashCode. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return alphabet.hashCode(); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. */ public List generators() { int len = alphabet.length(); List gens = new ArrayList(len); // ONE is not a word generator for (int i = 0; i < len; i++) { Word w = new Word(this, String.valueOf(alphabet.charAt(i)), false); gens.add(w); } return gens; } /** * Get the Element for a. * @param a long * @return element corresponding to a. */ public Word fromInteger(long a) { throw new UnsupportedOperationException("not implemented for WordFactory"); } /** * Get the Element for a. * @param a java.math.BigInteger. * @return element corresponding to a. */ public Word fromInteger(BigInteger a) { throw new UnsupportedOperationException("not implemented for WordFactory"); } /** * Get the Element for an ExpVector. * @param e ExpVector. * @return element corresponding to e. */ public Word valueOf(ExpVector e) { Word w = ONE; List gens = generators(); int n = alphabet.length(); int m = e.length(); if (m > n) { throw new IllegalArgumentException("alphabet to short for exponent " + e + ", alpahbet = " + alphabet); } for (int i = 0; i < m; i++) { int x = (int) e.getVal(m - i - 1); Word y = gens.get(i); Word u = ONE; for (int j = 0; j < x; j++) { u = u.multiply(y); } w = w.multiply(u); } return w; } /** * Get the element from an other word. * @param w other word. * @return w in this word factory. */ public Word valueOf(Word w) { String s = w.toString(); return parse(s); } /** * IndexOf for letter in alphabet. * @param s letter character. * @return index of s in the alphabet, or -1 if s is not contained in the alphabet. */ public int indexOf(char s) { return alphabet.indexOf(s); } /** * Generate a random Element with size less equal to n. * @param n * @return a random element. */ public Word random(int n) { return random(n, random); } /** * Generate a random Element with size less equal to n. * @param n * @param random is a source for random bits. * @return a random element. */ public Word random(int n, Random random) { StringBuffer sb = new StringBuffer(); int len = alphabet.length(); for (int i = 0; i < n; i++) { int r = Math.abs(random.nextInt() % len); sb.append(alphabet.charAt(r)); } return new Word(this, sb.toString(), false); } /** * Parse from String. * @param s String. * @return a Element corresponding to s. */ public Word parse(String s) { String st = clean(s); String regex; if (translation == null) { regex = "[" + alphabet + " ]*"; } else { regex = "[" + concat(translation) + " ]*"; } if (!st.matches(regex)) { throw new IllegalArgumentException("word '" + st + "' contains letters not from: " + alphabet + " or from " + concat(translation)); } // now only alphabet or translation chars are contained in st return new Word(this, st, true); } /** * Parse from Reader. White space is delimiter for word. * @param r Reader. * @return the next Element found on r. */ public Word parse(Reader r) { return parse(StringUtil.nextString(r)); } /** * Test if the alphabet of w is a subalphabet of this. * @param w other word factory to test. * @return true, if w is a subalphabet of this, else false. */ public boolean isSubFactory(WordFactory w) { if (w == null) { throw new IllegalArgumentException("w may not be null"); } String s = w.toString().replace(",", " "); Word c = null; try { c = parse(s); } catch (IllegalArgumentException ignored) { // ignore } //System.out.println("c: " + c + ", s = " + s); if (c != null) { return true; } return false; } /** * Contract word to this word factory. * this.isSubFactory(w.mono) must be true, otherwise null is returned. * @param w other word to contract. * @return w with this factory, or null if not contractable. */ public Word contract(Word w) { if (w == null) { throw new IllegalArgumentException("w may not be null"); } Word c = null; try { c = parse(w.toString()); } catch (IllegalArgumentException ignored) { // ignore } return c; } /** * Get the descending order comparator. Sorts the highest terms first. * @return horder. */ public WordComparator getDescendComparator() { return horder; } /** * Get the ascending order comparator. Sorts the lowest terms first. * @return lorder. */ public WordComparator getAscendComparator() { return lorder; } /** * Prepare parse from String. * @param s String. * @return a Element corresponding to s. */ public static String cleanSpace(String s) { String st = s.trim(); st = st.replaceAll("\\*", ""); st = st.replaceAll("\\s", ""); st = st.replaceAll("\\(", ""); st = st.replaceAll("\\)", ""); st = st.replaceAll("\\\"", ""); return st; } /** * Prepare parse from String. * @param s String. * @return a Element corresponding to s. */ public static String clean(String s) { String st = s.trim(); st = st.replaceAll("\\*", " "); //st = st.replaceAll("\\s", ""); st = st.replaceAll("\\(", ""); st = st.replaceAll("\\)", ""); st = st.replaceAll("\\\"", ""); return st; } /** * Prepare parse from String array. * @param v String array. * @return an array of cleaned strings. */ public static String[] cleanAll(String[] v) { String[] t = new String[v.length]; for (int i = 0; i < v.length; i++) { t[i] = cleanSpace(v[i]); if (t[i].length() == 0) { logger.error("empty v[i]: '{}'", v[i]); } //System.out.println("clean all: " + v[i] + " --> " + t[i]); } return t; } /** * Concat variable names. * @param v an array of strings. * @return the concatenation of the strings in v. */ public static String concat(String[] v) { StringBuffer s = new StringBuffer(); if (v == null) { return s.toString(); } for (int i = 0; i < v.length; i++) { s.append(v[i]); } return s.toString(); } /** * Trim all variable names. * @param v an array of strings. * @return an array of strings with all elements trimmed. */ public static String[] trimAll(String[] v) { String[] t = new String[v.length]; for (int i = 0; i < v.length; i++) { t[i] = v[i].trim(); if (t[i].length() == 0) { logger.error("empty v[i]: '{}'", v[i]); } } return t; } /** * IndexOf for String array. * @param v an array of strings. * @param s string. * @return index of s in v, or -1 if s is not contained in v. */ public static int indexOf(String[] v, String s) { for (int i = 0; i < v.length; i++) { if (s.equals(v[i])) { return i; } } return -1; } /** * Test if all variables are single letters. * @param v an array of strings. * @return true, if all variables have length 1, else false. */ public static boolean isSingleLetters(String[] v) { for (int i = 0; i < v.length; i++) { if (v[i].length() != 1) { return false; } } return true; } /** * Translate variable names. * @param v an array of strings. * @return the translated string of v with respect to t. */ public String translate(String[] v) { StringBuffer s = new StringBuffer(); for (int i = 0; i < v.length; i++) { String a = v[i]; int k = indexOf(translation, a); if (k < 0) { System.out.println("t = " + Arrays.toString(translation)); System.out.println("v = " + Arrays.toString(v)); logger.error("v[i] not found in t: {}", a); //continue; throw new IllegalArgumentException("v[i] not found in t: " + a); } s.append(transRef.charAt(k)); } return s.toString(); } /** * Translate variable name. * @param c internal char. * @return the external translated string. */ public String transVar(char c) { int k = alphabet.indexOf(c); return translation[k]; } } java-algebra-system-2.7.200/src/edu/jas/poly/WordMonomial.java000066400000000000000000000024711445075545500241200ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.SortedMap; import java.util.Iterator; import edu.jas.structure.RingElem; import edu.jas.poly.ExpVector; /** * WordMonomial class. * Represents pairs of words and coefficients. * Adaptor for Map.Entry. * @author Heinz Kredel */ public final class WordMonomial > { /** * Word of monomial. */ public final Word e; /** * Coefficient of monomial. */ public final C c; /** * Constructor of word monomial. * @param me a MapEntry. */ public WordMonomial(Map.Entry me){ this( me.getKey(), me.getValue() ); } /** * Constructor of word monomial. * @param e word. * @param c coefficient. */ public WordMonomial(Word e, C c) { this.e = e; this.c = c; } /** * Getter for word. * @return word. */ public Word word() { return e; } /** * Getter for coefficient. * @return coefficient. */ public C coefficient() { return c; } /** * String representation of Monomial. * @see java.lang.Object#toString() */ @Override public String toString() { return c.toString() + " " + e.toString(); } } java-algebra-system-2.7.200/src/edu/jas/poly/WordPolyIterator.java000066400000000000000000000023521445075545500250000ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.SortedMap; import java.util.Iterator; import edu.jas.structure.RingElem; import edu.jas.poly.Word; /** * Iterator over monomials of a polynomial. * Adaptor for val.entrySet().iterator(). * @author Heinz Kredel */ public class WordPolyIterator > implements Iterator< WordMonomial > { /** * Internal iterator over polynomial map. */ protected final Iterator< Map.Entry > ms; /** * Constructor of polynomial iterator. * @param m SortetMap of a polynomial. */ public WordPolyIterator( SortedMap m ) { ms = m.entrySet().iterator(); } /** * Test for availability of a next monomial. * @return true if the iteration has more monomials, else false. */ public boolean hasNext() { return ms.hasNext(); } /** * Get next monomial element. * @return next monomial. */ public WordMonomial next() { return new WordMonomial( ms.next() ); } /** * Remove the last monomial returned from underlying set if allowed. */ public void remove() { ms.remove(); } } java-algebra-system-2.7.200/src/edu/jas/poly/package.html000066400000000000000000000032671445075545500231330ustar00rootroot00000000000000 Generic coefficients polynomial package

Generic coefficients polynomial package.

This package contains classes for polynomial, solvable polynomial and free non-commutative polynomial arithmetic, e.g. GenPolynomial, GenSolvablePolynomial or GenWordPolynomial over coefficient rings which implement the RingElem interface. For arithmetic of commutative exponents and words over arbitrary alphabets are the classes ExpVector and Word with WordFactory. Other classes contained in this package are AlgebraicNumber, PolyUtil and a polynomial parser GenPolynomialTokenizer. Some classes implement quotient rings or residue class rings, etc., based only on the interfaces in the edu.jas.structure package.

Polynomial overview
Polynomial overview

Polynomial ring overview
Polynomial ring overview


Heinz Kredel

Last modified: Mon Sep 22 00:25:48 CEST 2014

$Id$

java-algebra-system-2.7.200/src/edu/jas/ps/000077500000000000000000000000001445075545500203015ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/ps/Coefficients.java000066400000000000000000000027561445075545500235570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.io.Serializable; import java.util.HashMap; import edu.jas.structure.RingElem; /** * Abstract class for generating functions for coefficients of power series. Was * an interface, now this class handles the caching itself. * @param ring element type * @author Heinz Kredel */ public abstract class Coefficients> implements Serializable { /** * Cache for already computed coefficients. */ public final HashMap coeffCache; /** * Public no arguments constructor. */ public Coefficients() { this(new HashMap()); } /** * Public constructor with pre-filled cache. * @param cache pre-filled coefficient cache. */ public Coefficients(HashMap cache) { coeffCache = cache; } /** * Get cached coefficient or generate coefficient. * @param index of requested coefficient. * @return coefficient at index. */ public C get(int index) { if (coeffCache == null) { return generate(index); } Integer i = index; C c = coeffCache.get(i); if (c != null) { return c; } c = generate(index); coeffCache.put(i, c); return c; } /** * Generate coefficient. * @param index of requested coefficient. * @return coefficient at index. */ protected abstract C generate(int index); } java-algebra-system-2.7.200/src/edu/jas/ps/Examples.java000066400000000000000000000457131445075545500227340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.BinaryFunctor; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.Selector; import edu.jas.structure.UnaryFunctor; /** * Examples for univariate power series implementations. * @author Heinz Kredel */ public class Examples { public static void main(String[] args) { example2(); example4(); example6(); example8(); example9(); example10(); example11(); example1(); example3(); example5(); example7(); if ( args.length > 0 ) { example12(); } example13(); example14(); } static UnivPowerSeries integersFrom(final int start) { UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(new BigInteger()); return new UnivPowerSeries(pfac, new Coefficients() { @Override public BigInteger generate(int i) { return new BigInteger(start + i); } }); } //---------------------- static class Sum> implements BinaryFunctor { public C eval(C c1, C c2) { return c1.sum(c2); } } static class Odds> implements Selector { C two; RingFactory fac; public Odds(RingFactory fac) { this.fac = fac; two = this.fac.fromInteger(2); //System.out.println("two = " + two); } public boolean select(C c) { //System.out.print("c = " + c); if (c.remainder(two).isONE()) { //System.out.println(" odd"); return true; } //System.out.println(" even"); return false; } } //---------------------- public static void example1() { UnivPowerSeries integers = integersFrom(0); BigInteger e = new BigInteger(1); BigInteger v = integers.evaluate(e); System.out.println("integers(" + e + ") = " + v); e = new BigInteger(0); v = integers.evaluate(e); System.out.println("integers(" + e + ") = " + v); e = new BigInteger(2); v = integers.evaluate(e); System.out.println("integers(" + e + ") = " + v); } public static void example2() { UnivPowerSeries integers = integersFrom(0); System.out.print("integer coefficients = "); UnivPowerSeries s = integers; for (int i = 0; i < 20; i++) { BigInteger c = s.leadingCoefficient(); System.out.print(c.toString() + ", "); s = s.reductum(); } System.out.println("..."); } public static void example3() { RingFactory fac = new BigInteger(1); UnivPowerSeriesRing ups = new UnivPowerSeriesRing(fac); System.out.println("ups = " + ups); System.out.println("ups.isCommutative() = " + ups.isCommutative()); System.out.println("ups.isAssociative() = " + ups.isAssociative()); System.out.println("ups.isField() = " + ups.isField()); System.out.println("ups.getZERO() = " + ups.getZERO()); System.out.println("ups.getONE() = " + ups.getONE()); UnivPowerSeries rnd = ups.random(); System.out.println("rnd = " + rnd); System.out.println("rnd = " + rnd); System.out.println("rnd.isUnit() = " + rnd.isUnit()); } public static void example4() { UnivPowerSeries integers = integersFrom(0); System.out.println("integers = " + integers); } public static void example6() { UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(new BigInteger()); UnivPowerSeries integers; integers = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries ps) { return ps.map(new UnaryFunctor() { public BigInteger eval(BigInteger s) { return s.sum(new BigInteger(1)); } }).prepend(new BigInteger(0)); } }); System.out.println("integers1 = " + integers); System.out.println("integers2 = " + integers); } public static void example8() { final BigInteger z = new BigInteger(0); final BigInteger one = new BigInteger(1); UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(z); UnivPowerSeries fibs; fibs = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries ps) { return ps.zip(new Sum(), ps.prepend(one)).prepend(z); } }); System.out.println("fibs1 = " + fibs.toString(/*20*/)); System.out.println("fibs2 = " + fibs.toString(/*20*/)); } public static void example9() { UnivPowerSeries integers = integersFrom(0); System.out.println(" integers = " + integers); UnivPowerSeries doubleintegers = integers.sum(integers); System.out.println("doubleintegers = " + doubleintegers); UnivPowerSeries nulls = integers.subtract(integers); System.out.println("null integers = " + nulls); doubleintegers = integers.multiply(new BigInteger(2)); System.out.println("doubleintegers = " + doubleintegers); nulls = integers.multiply(new BigInteger(0)); System.out.println("null integers = " + nulls); UnivPowerSeries odds = integers.select(new Odds(new BigInteger())); System.out.println("odd integers = " + odds); } public static void example10() { final BigInteger fac = new BigInteger(); UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(fac); UnivPowerSeries integers = integersFrom(0); System.out.println(" integers = " + integers); UnivPowerSeries ONE = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigInteger generate(int i) { if (i == 0) { return fac.getONE(); } return fac.getZERO(); } }//, null ); System.out.println("ONE = " + ONE); UnivPowerSeries ZERO = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigInteger generate(int i) { return fac.getZERO(); } }//, null ); System.out.println("ZERO = " + ZERO); UnivPowerSeries ints = integers.multiply(ONE); System.out.println("integers = " + ints); UnivPowerSeries nulls = integers.multiply(ZERO); System.out.println("null integers = " + nulls); UnivPowerSeries nints = integers.negate(); System.out.println("-integers = " + nints); UnivPowerSeries one = ONE.multiply(ONE); System.out.println("integers one = " + one); UnivPowerSeries ints2 = integers.multiply(integers); System.out.println("integers 2 = " + ints2); UnivPowerSeries inv1 = ONE.inverse(); System.out.println("integers inv1 = " + inv1); UnivPowerSeries intr = integers.reductum(); System.out.println("integers intr = " + intr); UnivPowerSeries ints2inv = ONE.sum(ZERO).inverse(); System.out.println("integers ints2inv = " + ints2inv); UnivPowerSeries one1 = ints2.multiply(ints2inv); System.out.println("integers one1 = " + one1); UnivPowerSeries ii = ints2inv.inverse(); System.out.println("integers ii = " + ii); UnivPowerSeries rem = integers.subtract(integers.divide(ints2).multiply(ints2)); System.out.println("integers rem = " + rem); } public static void example11() { //final BigInteger fac = new BigInteger(); UnivPowerSeries integers = integersFrom(0); System.out.println(" integers = " + integers); UnivPowerSeries int2 = integers.multiply(new BigInteger(2)); System.out.println(" 2*integers = " + int2); System.out.println("integers < 2*integers = " + integers.compareTo(int2)); System.out.println("2*integers > integers = " + int2.compareTo(integers)); System.out.println("2*integers == integers = " + int2.equals(integers)); System.out.println("integers == integers = " + integers.equals(integers.copy())); System.out.println("integers.hashCode() = " + integers.hashCode()); } public static void example5() { //final BigInteger fac = new BigInteger(); //UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(fac); UnivPowerSeries integers = integersFrom(0); System.out.println(" integers = " + integers); UnivPowerSeries ints2 = integers.multiply(integers); System.out.println("integers 2 = " + ints2); UnivPowerSeries q1 = ints2.divide(integers); System.out.println("q1 = " + q1); UnivPowerSeries q2 = integers.divide(ints2); System.out.println("q2 = " + q2); UnivPowerSeries r1 = ints2.remainder(integers); System.out.println("r1 = " + r1); UnivPowerSeries r2 = integers.remainder(ints2); System.out.println("r2 = " + r2); UnivPowerSeries qr1 = q1.multiply(integers).sum(r1); System.out.println("qr1 = " + qr1); UnivPowerSeries qr2 = q2.multiply(ints2).sum(r2); System.out.println("qr2 = " + qr2); System.out.println("sign(qr1-ints2) = " + qr1.compareTo(ints2)); System.out.println("sign(qr2-integers) = " + qr2.compareTo(integers)); UnivPowerSeries g = ints2.gcd(integers); System.out.println("g = " + g); } public static void example7() { final BigRational fac = new BigRational(); final UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(fac, 11, "y"); UnivPowerSeries exp = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.integrate(fac.getONE()); } }); System.out.println("exp = " + exp); UnivPowerSeries tan = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries t) { return t.multiply(t).sum(pfac.getONE()).integrate(fac.getZERO()); } }); System.out.println("tan = " + tan); UnivPowerSeries sin = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigRational generate(int i) { BigRational c; if (i == 0) { c = fac.getZERO(); } else if (i == 1) { c = fac.getONE(); } else { c = get(i - 2).negate(); c = c.divide(fac.fromInteger(i)).divide(fac.fromInteger(i - 1)); } return c; } }); System.out.println("sin = " + sin); UnivPowerSeries sin1 = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.negate().integrate(fac.getONE()).integrate(fac.getZERO()); } }); System.out.println("sin1 = " + sin1); UnivPowerSeries cos = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigRational generate(int i) { BigRational c; if (i == 0) { c = fac.getONE(); } else if (i == 1) { c = fac.getZERO(); } else { c = get(i - 2).negate(); c = c.divide(fac.fromInteger(i)).divide(fac.fromInteger(i - 1)); } return c; } }); System.out.println("cos = " + cos); UnivPowerSeries cos1 = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.negate().integrate(fac.getZERO()).integrate(fac.getONE()); } }); System.out.println("cos1 = " + cos1); UnivPowerSeries cos2 = pfac.solveODE(sin1.negate(), fac.getONE()); System.out.println("cos2 = " + cos2); UnivPowerSeries sin2 = pfac.solveODE(cos1, fac.getZERO()); System.out.println("sin2 = " + sin2); UnivPowerSeries sinh = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigRational generate(int i) { BigRational c; if (i == 0) { c = fac.getZERO(); } else if (i == 1) { c = fac.getONE(); } else { c = get(i - 2); c = c.divide(fac.fromInteger(i)).divide(fac.fromInteger(i - 1)); } return c; } }); System.out.println("sinh = " + sinh); UnivPowerSeries cosh = new UnivPowerSeries(pfac, new Coefficients() { @Override public BigRational generate(int i) { BigRational c; if (i == 0) { c = fac.getONE(); } else if (i == 1) { c = fac.getZERO(); } else { c = get(i - 2); c = c.divide(fac.fromInteger(i)).divide(fac.fromInteger(i - 1)); } return c; } }//, null ); System.out.println("cosh = " + cosh); UnivPowerSeries sinhcosh = sinh.sum(cosh); System.out.println("sinh+cosh = " + sinhcosh); System.out.println("sinh+cosh == exp: " + sinhcosh.equals(exp)); } public static void example12() { final BigComplex fac = new BigComplex(); final BigComplex I = BigComplex.I; final UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(fac); UnivPowerSeries exp = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.integrate(I); } }); System.out.println("exp = " + exp); UnivPowerSeries sin = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.negate().integrate(fac.getONE()).integrate(fac.getZERO()); } }); System.out.println("sin = " + sin); UnivPowerSeries cos = pfac.fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.negate().integrate(fac.getZERO()).integrate(fac.getONE()); } }); System.out.println("cos = " + cos); UnivPowerSeries cpis = cos.sum(sin.multiply(I)); System.out.println("cpis = " + cpis); } public static void example13() { BigRational fac = new BigRational(); UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(fac, 11, "y"); UnivPowerSeries exp = pfac.getEXP(); System.out.println("exp = " + exp); System.out.println("exp(1) = " + exp.evaluate(fac.getONE())); System.out.println("exp(0) = " + exp.evaluate(fac.getZERO())); BigDecimal dfac = new BigDecimal(); UnivPowerSeriesRing dpfac = new UnivPowerSeriesRing(dfac, 11, "z"); UnivPowerSeries dexp = dpfac.getEXP(); System.out.println("exp = " + dexp); System.out.println("exp(1) = " + dexp.evaluate(dfac.getONE())); System.out.println("exp(0) = " + dexp.evaluate(dfac.getZERO())); } public static void example14() { BigRational cfac = new BigRational(); UnivPowerSeriesRing pfac = new UnivPowerSeriesRing(cfac, 11, "t"); System.out.println("pfac = " + pfac); System.out.println("pfac = " + pfac.toScript()); GenPolynomialRing> fac = new GenPolynomialRing>(pfac,new String[] { "x"} ); System.out.println("fac = " + fac); System.out.println("fac = " + fac.toScript()); List> gens = pfac.generators(); System.out.println("gens = " + gens); GenPolynomial> p = fac.parse("x^2 - x"); System.out.println("p = " + p); GenPolynomial> s = p.sum(gens.get(1).multiply(gens.get(1))); System.out.println("s = " + s); GenPolynomial> q = p.multiply(s); System.out.println("q = " + q); GenPolynomial> r = q.gcd(s); System.out.println("r = " + r); } } java-algebra-system-2.7.200/src/edu/jas/ps/ExamplesMulti.java000066400000000000000000000465231445075545500237470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; /** * Examples for multivariate power series implementations. * @author Heinz Kredel */ public class ExamplesMulti { public static void main(String[] args) { if ( args.length > 0 ) { example1(); example2(); example3(); example4(); example5(); example6(); example7(); example8(); example9(); example10(); } example11(); } public static void example1() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x^2 + x y"); GenPolynomial b = pfac.parse("y^2 + x y"); GenPolynomial c = pfac.parse("x^3 + x^2"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); ReductionSeq red = new ReductionSeq(); MultiVarPowerSeries dp = red.normalform(L, cp); System.out.println("dp = " + dp); } public static void example2() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x - x y"); GenPolynomial b = pfac.parse("y^2 + x^3"); GenPolynomial c = pfac.parse("x^2 + y^2"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); ReductionSeq red = new ReductionSeq(); MultiVarPowerSeries dp = red.normalform(L, cp); System.out.println("dp = " + dp); } public static void example3() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x"); GenPolynomial b = pfac.parse("y"); GenPolynomial c = pfac.parse("x^2 + y^2 + z^3 + x^4 + y^5"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); ReductionSeq red = new ReductionSeq(); MultiVarPowerSeries dp = red.normalform(L, cp); System.out.println("dp = " + dp); } public static void example4() { BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x + x^3 + x^5"); GenPolynomial c = pfac.parse("x + x^2"); System.out.println("a = " + a); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); //fac.setTruncate(11); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); ReductionSeq red = new ReductionSeq(); MultiVarPowerSeries dp = red.normalform(L, cp); System.out.println("dp = " + dp); } public static void example5() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial c = pfac.parse("x^2 + y^2 - 1"); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); //fac.setTruncate(19); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.getSIN(0); MultiVarPowerSeries bp = fac.getCOS(1); MultiVarPowerSeries ep = fac.getCOS(0); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("ep = " + ep); System.out.println("cp = " + cp); System.out.println("ap^2 + ep^2 = " + ap.multiply(ap).sum(ep.multiply(ep))); List> L = new ArrayList>(); L.add(ap); L.add(bp); ReductionSeq red = new ReductionSeq(); MultiVarPowerSeries dp = red.normalform(L, cp); System.out.println("dp = " + dp); } public static void example6() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x^5 - x y^6 + z^7"); GenPolynomial b = pfac.parse("x y + y^3 + z^3"); GenPolynomial c = pfac.parse("x^2 + y^2 - z^2"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); //fac.setTruncate(11); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); L.add(cp); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("S contains L = " + s); } public static void example7() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x^10 + x^9 y^2"); GenPolynomial b = pfac.parse("y^8 - x^2 y^7"); System.out.println("a = " + a); System.out.println("b = " + b); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); fac.setTruncate(12); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); System.out.println("ap = " + ap); System.out.println("bp = " + bp); List> L = new ArrayList>(); L.add(ap); L.add(bp); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("\nS contains L = " + s); } public static void example8() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial c = pfac.parse("x^2 + y^2"); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); //fac.setTruncate(19); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.getSIN(0); MultiVarPowerSeries bp = fac.getTAN(0); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); //L.add(cp); System.out.println("\nL = " + L); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("S contains L = " + s); } public static void example9() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x z - y z - y^2 z"); GenPolynomial b = pfac.parse("x z - y z + y^2 z"); GenPolynomial c = pfac.parse("z + y^2 z"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); fac.setTruncate(11); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); L.add(cp); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("S contains L = " + s); } public static void example10() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x^2 z^2 - y^6"); GenPolynomial b = pfac.parse("x y z^2 + y^4 z - x^5 z - x^4 y^3"); GenPolynomial c = pfac.parse("x z - y^3 + x^2 z - x y^3"); GenPolynomial d = pfac.parse("y z + x y z - x^4 - x^5"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); System.out.println("d = " + d); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); fac.setTruncate(9); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); MultiVarPowerSeries dp = fac.fromPolynomial(d); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); System.out.println("dp = " + dp); List> L = new ArrayList>(); L.add(ap); L.add(bp); L.add(cp); L.add(dp); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("S contains L = " + s); List> R = red.totalNormalform(S); System.out.println("R = " + R); s = red.contains(R, L); System.out.println("R contains L = " + s); s = red.contains(R, S); System.out.println("R contains S = " + s); } public static void example11() { BigRational br = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); System.out.println("pfac = " + pfac.toScript()); GenPolynomial a = pfac.parse("x^5 - x y^6 - z^7"); GenPolynomial b = pfac.parse("x y + y^3 + z^3"); GenPolynomial c = pfac.parse("x^2 + y^2 - z^2"); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("c = " + c); MultiVarPowerSeriesRing fac = new MultiVarPowerSeriesRing(pfac); //fac.setTruncate(9); System.out.println("fac = " + fac.toScript()); MultiVarPowerSeries ap = fac.fromPolynomial(a); MultiVarPowerSeries bp = fac.fromPolynomial(b); MultiVarPowerSeries cp = fac.fromPolynomial(c); System.out.println("ap = " + ap); System.out.println("bp = " + bp); System.out.println("cp = " + cp); List> L = new ArrayList>(); L.add(ap); L.add(bp); L.add(cp); StandardBaseSeq tm = new StandardBaseSeq(); List> S = tm.STD(L); for (MultiVarPowerSeries ps : S) { System.out.println("ps = " + ps); } System.out.println("\nS = " + S); boolean s = tm.isSTD(S); System.out.println("\nisSTD = " + s); ReductionSeq red = new ReductionSeq(); s = red.contains(S, L); System.out.println("S contains L = " + s); List> R = red.totalNormalform(S); for (MultiVarPowerSeries ps : R) { System.out.println("ps = " + ps); } System.out.println("\nR = " + R); s = tm.isSTD(R); System.out.println("\nisSTD = " + s); s = red.contains(R, L); System.out.println("R contains L = " + s); s = red.contains(R, S); System.out.println("R contains S = " + s); s = red.contains(S,R); System.out.println("S contains R = " + s); s = red.contains(S,L); System.out.println("S contains L = " + s); List> Rs = tm.STD(R); for (MultiVarPowerSeries ps : Rs) { System.out.println("ps = " + ps); } System.out.println("\nRs = " + Rs); s = tm.isSTD(Rs); System.out.println("\nisSTD = " + s); s = red.contains(Rs, R); System.out.println("Rs contains R = " + s); s = red.contains(Rs, S); System.out.println("Rs contains S = " + s); } } java-algebra-system-2.7.200/src/edu/jas/ps/ExpVectorIterable.java000066400000000000000000000130611445075545500245340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.List; import java.util.ArrayList; import edu.jas.poly.ExpVector; import edu.jas.util.CartesianProductLong; import edu.jas.util.LongIterable; /** * Iterable for ExpVector, using total degree enumeration. * @author Heinz Kredel */ public class ExpVectorIterable implements Iterable { protected long upperBound; final boolean infinite; final int nvar; /** * Constructor. * @param nv number of variables. */ public ExpVectorIterable(int nv) { this(nv,true,Long.MAX_VALUE); } /** * Constructor. * @param nv number of variables. * @param ub upper bound for the components. */ public ExpVectorIterable(int nv, long ub) { this(nv,false,ub); } /** * Constructor. * @param nv number of variables. * @param all true, if all elements between 0 and upper bound are enumerated, false, if only elements of exact upper bund are to be processed. * @param ub upper bound for the components. */ public ExpVectorIterable(int nv, boolean all, long ub) { upperBound = ub; infinite = all; nvar = nv; } /** Set the upper bound for the iterator. * @param ub an upper bound for the iterator elements. */ public void setUpperBound(long ub) { upperBound = ub; } /** Get the upper bound for the iterator. * @return the upper bound for the iterator elements. */ public long getUpperBound() { return upperBound; } /** * Get an iterator over ExpVector. * @return an iterator. */ public Iterator iterator() { return new ExpVectorIterator(nvar,infinite,upperBound); } } /** * ExpVector iterator using CartesianProductLongIterator. * @author Heinz Kredel */ class ExpVectorIterator implements Iterator { /** * data structure. */ ExpVector current; Iterator> liter; protected int totalDegree; protected boolean empty; final long upperBound; final boolean infinite; final int nvar; /** * ExpVector iterator constructor. * @param nv number of variables. */ public ExpVectorIterator(int nv) { this(nv,true,Long.MAX_VALUE); } /** * ExpVector iterator constructor. * @param nv number of variables. * @param ub upper bound for the components. */ public ExpVectorIterator(int nv,long ub) { this(nv,false,ub); } /** * ExpVector iterator constructor. * @param nv number of variables. * @param inf true, if all elements between 0 and upper bound are enumerated, false, if only elements of exact upper bund are to be processed. * @param ub an upper bound for the entries. */ protected ExpVectorIterator(int nv, boolean inf, long ub) { infinite = inf; upperBound = ub; if (upperBound < 0L) { throw new IllegalArgumentException("negative upper bound not allowed"); } totalDegree = 0; if ( !infinite ) { totalDegree = (int)upperBound; } //System.out.println("totalDegree = " + totalDegree + ", upperBound = " + upperBound); LongIterable li = new LongIterable(); li.setNonNegativeIterator(); li.setUpperBound(totalDegree); List tlist = new ArrayList(nv); for (int i = 0; i < nv; i++) { tlist.add(li); // can reuse li } Iterable> ib = new CartesianProductLong(tlist,totalDegree); liter = ib.iterator(); empty = (totalDegree > upperBound) || !liter.hasNext(); current = ExpVector.create(nv); if ( !empty ) { List el = liter.next(); current = ExpVector.create(el); //System.out.println("current = " + current); } nvar = nv; } /** * Test for availability of a next long. * @return true if the iteration has more ExpVectors, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next ExpVector. * @return next ExpVector. */ public synchronized ExpVector next() { ExpVector res = current; if ( liter.hasNext() ) { List el = liter.next(); current = ExpVector.create(el); //System.out.println("current, liter = " + current); return res; } if ( totalDegree >= upperBound ) { empty = true; return res; } totalDegree++; //System.out.println("totalDegree,b = " + totalDegree); if ( totalDegree >= upperBound && !infinite ) { throw new NoSuchElementException("invalid call of next()"); } LongIterable li = new LongIterable(); li.setNonNegativeIterator(); li.setUpperBound(totalDegree); List tlist = new ArrayList(nvar); for (int i = 0; i < nvar; i++) { tlist.add(li); // can reuse li } Iterable> ib = new CartesianProductLong(tlist,totalDegree); liter = ib.iterator(); List el = liter.next(); current = ExpVector.create(el); return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/ps/MultiVarCoefficients.java000066400000000000000000000146561445075545500252450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.io.Serializable; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Abstract class for generating functions for coefficients of multivariate * power series. This class handles the caching itself. * @param ring element type * @author Heinz Kredel */ public abstract class MultiVarCoefficients> implements Serializable { /** * Ring factory for polynomials. */ public final GenPolynomialRing pfac; /** * Cache for already computed coefficients. */ public final HashMap> coeffCache; /** * Indicator if all coefficients of a homogeneous degree have been * constructed. */ public final BitSet homCheck; /** * Cache for known zero coefficients. Required because zero coefficients are * not stored in the polynomials. */ public final HashSet zeroCache; /** * Public constructor. * @param pf multivariate power series ring factory. */ public MultiVarCoefficients(MultiVarPowerSeriesRing pf) { this(pf.polyRing(), new HashMap>(), new HashSet()); } /* * Public constructor with some pre-filled caches. * @param pf multivariate power series ring factory. * @param hc pre-filled homogeneous check bit-set. public MultiVarCoefficients(MultiVarPowerSeriesRing pf, BitSet hc) { this(pf.polyRing(), new HashMap>(), new HashSet(), hc); } */ /** * Public constructor. * @param pf polynomial ring factory. */ public MultiVarCoefficients(GenPolynomialRing pf) { this(pf, new HashMap>(), new HashSet()); } /** * Public with pre-filled coefficient cache. * @param pf polynomial ring factory. * @param cache pre-filled coefficient cache. */ public MultiVarCoefficients(GenPolynomialRing pf, HashMap> cache) { this(pf, cache, new HashSet()); } /** * Public constructor with pre-filled caches. * @param pf polynomial ring factory. * @param cache pre-filled coefficient cache. * @param zeros pre-filled zero coefficient cache. */ public MultiVarCoefficients(GenPolynomialRing pf, HashMap> cache, HashSet zeros) { this(pf, cache, zeros, new BitSet()); } /* * Public constructor with pre-filled caches. * @param pf polynomial ring factory. * @param hc pre-filled homogeneous check bit-set. public MultiVarCoefficients(GenPolynomialRing pf, BitSet hc) { this(pf, new HashMap>(), new HashSet(), hc); } */ /** * Public constructor with pre-filled caches. * @param pf polynomial ring factory. * @param cache pre-filled coefficient cache. * @param hc pre-filled homogeneous check bit-set. */ public MultiVarCoefficients(GenPolynomialRing pf, HashMap> cache, BitSet hc) { this(pf, cache, new HashSet(), hc); } /** * Public constructor with pre-filled caches. * @param pf polynomial ring factory. * @param cache pre-filled coefficient cache. * @param zeros pre-filled zero coefficient cache. * @param hc pre-filled homogeneous check bit-set. */ public MultiVarCoefficients(GenPolynomialRing pf, HashMap> cache, HashSet zeros, BitSet hc) { pfac = pf; coeffCache = cache; zeroCache = zeros; homCheck = hc; } /** * Get cached coefficient or generate coefficient. * @param index of requested coefficient. * @return coefficient at index. */ public C get(ExpVector index) { //if (index.signum() < 0) { // better assert // throw new IllegalArgumentException("negative signum not allowed " + index); //} //if (coeffCache == null) { // not possible // return generate(index); //} long tdeg = index.totalDeg(); GenPolynomial p = coeffCache.get(tdeg); if (p == null) { p = pfac.getZERO().copy(); coeffCache.put(tdeg, p); } C c = p.coefficient(index); if (!c.isZERO()) { return c; } if (homCheck.get((int) tdeg)) { // rely on p return c; } if (zeroCache.contains(index)) { return c; } C g = generate(index); if (g.isZERO()) { zeroCache.add(index); } else { p.doPutToMap(index, g); } return g; } /** * Homogeneous part. * @param tdeg requested degree. * @return polynomial part of given degree. */ public GenPolynomial getHomPart(long tdeg) { if (coeffCache == null) { throw new IllegalArgumentException("null cache not allowed"); } GenPolynomial p = coeffCache.get(tdeg); if (p == null) { p = pfac.getZERO().copy(); coeffCache.put(tdeg, p); } // trust contents? if (homCheck.get((int) tdeg)) { return p; } // check correct contents or generate coefficients ExpVectorIterable eiter = new ExpVectorIterable(pfac.nvar, tdeg); for (ExpVector e : eiter) { if (zeroCache.contains(e)) { if ( !zeroCache.remove(e) ) { // clean-up unused System.out.println("not removed e = " + e); // cannot happen } continue; } if (!p.coefficient(e).isZERO()) { continue; } C g = generate(e); if (!g.isZERO()) { p.doPutToMap(e, g); } } homCheck.set((int) tdeg); //System.out.println("homCheck = " + homCheck); //System.out.println("coeffCache = " + coeffCache.keySet()); return p; } /** * Generate coefficient. * @param index of requested coefficient. * @return coefficient at index. */ protected abstract C generate(ExpVector index); } java-algebra-system-2.7.200/src/edu/jas/ps/MultiVarPowerSeries.java000066400000000000000000001220501445075545500250770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.structure.BinaryFunctor; import edu.jas.structure.RingElem; import edu.jas.structure.Selector; import edu.jas.structure.UnaryFunctor; import edu.jas.util.MapEntry; /** * Multivariate power series implementation. Uses inner classes and lazy * evaluated generating function for coefficients. All ring element methods use * lazy evaluation except where noted otherwise. Eager evaluated methods are * toString(), compareTo(), equals(), * evaluate(), or methods which use the order() or * orderExpVector() methods, like signum(), * abs(), divide(), remainder() and * gcd(). Note: Currently the term order is fixed to the * order defined by the iterator over exponent vectors in class * ExpVectorIterator. * @param ring element type * @author Heinz Kredel */ public class MultiVarPowerSeries> implements RingElem> { /** * Power series ring factory. */ public final MultiVarPowerSeriesRing ring; /** * Data structure / generating function for coefficients. Cannot be final * because of fixPoint, must be accessible in factory. */ /*package*/MultiVarCoefficients lazyCoeffs; /** * Truncation of computations. */ private int truncate; /** * Order of power series. */ private int order = -1; // == unknown /** * ExpVector of order of power series. */ private ExpVector evorder = null; // == unknown /** * Private constructor. */ @SuppressWarnings("unused") private MultiVarPowerSeries() { throw new IllegalArgumentException("do not use no-argument constructor"); } /** * Package constructor. Use in fixPoint only, must be accessible in factory. * @param ring power series ring. */ /*package*/ MultiVarPowerSeries(MultiVarPowerSeriesRing ring) { this.ring = ring; this.lazyCoeffs = null; this.truncate = ring.truncate; } /** * Constructor. * @param ring power series ring. * @param lazyCoeffs generating function for coefficients. */ public MultiVarPowerSeries(MultiVarPowerSeriesRing ring, MultiVarCoefficients lazyCoeffs) { this(ring, lazyCoeffs, ring.truncate); } /** * Constructor. * @param ring power series ring. * @param lazyCoeffs generating function for coefficients. * @param trunc truncate parameter for this power series. */ public MultiVarPowerSeries(MultiVarPowerSeriesRing ring, MultiVarCoefficients lazyCoeffs, int trunc) { if (lazyCoeffs == null || ring == null) { throw new IllegalArgumentException( "null not allowed: ring = " + ring + ", lazyCoeffs = " + lazyCoeffs); } this.ring = ring; this.lazyCoeffs = lazyCoeffs; this.truncate = Math.min(trunc, ring.truncate); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public MultiVarPowerSeriesRing factory() { return ring; } /** * Clone this power series. * @see java.lang.Object#clone() */ @Override public MultiVarPowerSeries copy() { return new MultiVarPowerSeries(ring, lazyCoeffs); } /** * String representation of power series. * @see java.lang.Object#toString() */ @Override public String toString() { return toString(truncate); } /** * To String with given truncate. * @param trunc truncate parameter for this power series. * @return string representation of this to given truncate. */ public String toString(int trunc) { StringBuffer sb = new StringBuffer(); MultiVarPowerSeries s = this; String[] vars = ring.vars; //System.out.println("cache1 = " + s.lazyCoeffs.coeffCache); for (ExpVector i : new ExpVectorIterable(ring.nvar, true, trunc)) { C c = s.coefficient(i); //System.out.println("i = " + i + ", c = " +c); int si = c.signum(); if (si != 0) { if (si > 0) { if (sb.length() > 0) { sb.append(" + "); } } else { c = c.negate(); sb.append(" - "); } if (!c.isONE() || i.isZERO()) { if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append("{ "); } sb.append(c.toString()); if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append(" }"); } if (!i.isZERO()) { sb.append(" * "); } } if (i.isZERO()) { //skip; sb.append(" "); } else { sb.append(i.toString(vars)); } //sb.append(c.toString() + ", "); } //System.out.println("cache = " + s.coeffCache); } if (sb.length() == 0) { sb.append("0"); } sb.append(" + BigO( (" + ring.varsToString() + ")^" + (trunc + 1) + "(" + (ring.truncate + 1) + ") )"); //sb.append("..."); //System.out.println("cache2 = " + s.lazyCoeffs.coeffCache); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer sb = new StringBuffer(""); MultiVarPowerSeries s = this; String[] vars = ring.vars; //System.out.println("cache = " + s.coeffCache); for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { C c = s.coefficient(i); int si = c.signum(); if (si != 0) { if (si > 0) { if (sb.length() > 0) { sb.append(" + "); } } else { c = c.negate(); sb.append(" - "); } if (!c.isONE() || i.isZERO()) { if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append("( "); } sb.append(c.toScript()); if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append(" )"); } if (!i.isZERO()) { sb.append(" * "); } } if (i.isZERO()) { //skip; sb.append(" "); } else { sb.append(i.toScript(vars)); } //sb.append(c.toString() + ", "); } //System.out.println("cache = " + s.coeffCache); } if (sb.length() == 0) { sb.append("0"); } sb.append(" + BigO( (" + ring.varsToString() + ")**" + (truncate + 1) + " )"); // sb.append("," + truncate + ""); return sb.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Get coefficient. * @param index number of requested coefficient. * @return coefficient at index. */ public C coefficient(ExpVector index) { if (index == null) { throw new IndexOutOfBoundsException("null index not allowed"); } return lazyCoeffs.get(index); } /** * Homogeneous part. * @param tdeg requested degree. * @return polynomial part of given degree. */ public GenPolynomial homogeneousPart(long tdeg) { return lazyCoeffs.getHomPart(tdeg); } /** * Get a GenPolynomial<C> from this. * @return a GenPolynomial<C> from this up to truncate homogeneous * parts. */ public GenPolynomial asPolynomial() { GenPolynomial p = homogeneousPart(0L); for (int i = 1; i <= truncate; i++) { p = p.sum(homogeneousPart(i)); } return p; } /** * Leading base coefficient. * @return first coefficient. */ public C leadingCoefficient() { return coefficient(ring.EVZERO); } /** * Prepend a new leading coefficient. * @param r variable for the direction. * @param h new coefficient. * @return new power series. */ public MultiVarPowerSeries prepend(final C h, final int r) { if (r < 0 || ring.nvar < r) { throw new IllegalArgumentException("variable index out of bound"); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return h; } ExpVector e = i.subst(r, i.getVal(r) - 1); if (e.signum() < 0) { return pfac.coFac.getZERO(); } return coefficient(e); } }); } /** * Shift coefficients. * @param k shift index. * @param r variable for the direction. * @return new power series with coefficient(i) = old.coefficient(i-k). */ public MultiVarPowerSeries shift(final int k, final int r) { if (r < 0 || ring.nvar < r) { throw new IllegalArgumentException("variable index out of bound"); } int nt = Math.min(truncate + k, ring.truncate); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { long d = i.getVal(r); if (d - k < 0) { return ring.coFac.getZERO(); } ExpVector e = i.subst(r, i.getVal(r) - k); return coefficient(e); } }, nt); } /** * Reductum. * @param r variable for taking the reductum. * @return this - leading monomial in the direction of r. */ public MultiVarPowerSeries reductum(final int r) { if (r < 0 || ring.nvar < r) { throw new IllegalArgumentException("variable index out of bound"); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { ExpVector e = i.subst(r, i.getVal(r) + 1); return coefficient(e); } }); } /** * Reductum. * @return this - leading monomial. */ public MultiVarPowerSeries reductum() { Map.Entry m = orderMonomial(); if (m == null) { return ring.getZERO(); } ExpVector e = m.getKey(); long d = e.totalDeg(); MultiVarCoefficients mc = lazyCoeffs; HashMap> cc = new HashMap>(mc.coeffCache); GenPolynomial p = cc.get(d); if (p != null && !p.isZERO()) { p = p.subtract(m.getValue(), e); // p contains this term after orderMonomial() cc.put(d, p); } HashSet z = new HashSet(mc.zeroCache); if (!mc.homCheck.get((int) d)) { z.add(e); //System.out.println("e = " + e); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(mc.pfac, cc, z, mc.homCheck) { @Override public C generate(ExpVector i) { return coefficient(i); } }); } /** * Shift coefficients. Multiply by exponent vector. * @param k shift ExpVector. * @return new power series with coefficient(i) = old.coefficient(i-k). */ public MultiVarPowerSeries shift(final ExpVector k) { if (k == null) { throw new IllegalArgumentException("null ExpVector not allowed"); } if (k.signum() == 0) { return this; } int nt = Math.min(truncate + (int) k.totalDeg(), ring.truncate); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { ExpVector d = i.subtract(k); if (d.signum() < 0) { return ring.coFac.getZERO(); } return coefficient(d); } }, nt); } /** * Multiply by exponent vector and coefficient. * @param k shift ExpVector. * @param c coefficient multiplier. * @return new power series with coefficient(i) = old.coefficient(i-k)*c. */ public MultiVarPowerSeries multiply(final C c, final ExpVector k) { if (k == null) { throw new IllegalArgumentException("null ExpVector not allowed"); } if (k.signum() == 0) { return this.multiply(c); } if (c.signum() == 0) { return ring.getZERO(); } int nt = Math.min(ring.truncate, truncate + (int) k.totalDeg()); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { ExpVector d = i.subtract(k); if (d.signum() < 0) { return ring.coFac.getZERO(); } long tdegd = d.totalDeg(); if (lazyCoeffs.homCheck.get((int) tdegd)) { GenPolynomial p = homogeneousPart(tdegd).multiply(c, k); long tdegi = i.totalDeg(); coeffCache.put(tdegi, p); // overwrite homCheck.set((int) tdegi); C b = p.coefficient(i); //System.out.println("b = " + b + ", i = " + i + ", tdegi = " + tdegi+ ", tdegd = " + tdegd); //System.out.println("p = " + p + ", i = " + i); return b; } return coefficient(d).multiply(c); } }, nt); } /** * Sum monomial. * @param m ExpVector , coefficient pair * @return this + ONE.multiply(m.coefficient,m.exponent). */ public MultiVarPowerSeries sum(Map.Entry m) { if (m == null) { throw new IllegalArgumentException("null Map.Entry not allowed"); } return sum(m.getValue(), m.getKey()); } /** * Sum exponent vector and coefficient. * @param k ExpVector. * @param c coefficient. * @return this + ONE.multiply(c,k). */ public MultiVarPowerSeries sum(final C c, final ExpVector k) { if (k == null) { throw new IllegalArgumentException("null ExpVector not allowed"); } if (c.signum() == 0) { return this; } long d = k.totalDeg(); MultiVarCoefficients mc = lazyCoeffs; HashMap> cc = new HashMap>(mc.coeffCache); GenPolynomial p = cc.get(d); if (p == null) { p = mc.pfac.getZERO(); } p = p.sum(c, k); //System.out.println("p = " + p); cc.put(d, p); HashSet z = new HashSet(mc.zeroCache); //System.out.println("z = " + z); if (p.coefficient(k).isZERO() && !mc.homCheck.get((int) d)) { z.add(k); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(mc.pfac, cc, z, mc.homCheck) { @Override public C generate(ExpVector i) { return coefficient(i); } }); } /** * Subtract exponent vector and coefficient. * @param k ExpVector. * @param c coefficient. * @return this - ONE.multiply(c,k). */ public MultiVarPowerSeries subtract(final C c, final ExpVector k) { if (k == null) { throw new IllegalArgumentException("null ExpVector not allowed"); } if (c.signum() == 0) { return this; } long d = k.totalDeg(); MultiVarCoefficients mc = lazyCoeffs; HashMap> cc = new HashMap>(mc.coeffCache); GenPolynomial p = cc.get(d); if (p == null) { p = mc.pfac.getZERO(); } p = p.subtract(c, k); cc.put(d, p); HashSet z = new HashSet(mc.zeroCache); //System.out.println("z = " + z); if (p.coefficient(k).isZERO() && !mc.homCheck.get((int) d)) { z.add(k); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(mc.pfac, cc, z, mc.homCheck) { @Override public C generate(ExpVector i) { return coefficient(i); } }); } /** * Sum exponent vector and coefficient. * @param mvc cached coefficients. * @return this + mvc. */ public MultiVarPowerSeries sum(MultiVarCoefficients mvc) { MultiVarCoefficients mc = lazyCoeffs; TreeMap> cc = new TreeMap>(mc.coeffCache); TreeMap> ccv = new TreeMap>(mvc.coeffCache); long d1 = (cc.size() > 0 ? cc.lastKey() : 0); long d2 = (ccv.size() > 0 ? ccv.lastKey() : 0); HashSet z = new HashSet(mc.zeroCache); z.addAll(mvc.zeroCache); long d = Math.max(d1, d2); BitSet hc = new BitSet((int) d); for (long i = 0; i <= d; i++) { GenPolynomial p1 = cc.get(i); GenPolynomial p2 = mvc.coeffCache.get(i); if (p1 == null) { p1 = mc.pfac.getZERO(); } if (p2 == null) { p2 = mc.pfac.getZERO(); } GenPolynomial p = p1.sum(p2); //System.out.println("p = " + p); cc.put(i, p); if (mc.homCheck.get((int) i) && mvc.homCheck.get((int) i)) { hc.set((int) i); } else { Set ev = new HashSet(p1.getMap().keySet()); ev.addAll(p2.getMap().keySet()); ev.removeAll(p.getMap().keySet()); z.addAll(ev); } } //System.out.println("cc = " + cc); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(mc.pfac, new HashMap>(cc), z, hc) { @Override public C generate(ExpVector i) { return coefficient(i); } }); } /** * Select coefficients. * @param sel selector functor. * @return new power series with selected coefficients. */ public MultiVarPowerSeries select(final Selector sel) { return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { C c = coefficient(i); if (sel.select(c)) { return c; } return ring.coFac.getZERO(); } }); } /** * Shift select coefficients. Not selected coefficients are removed from the * result series. * @param sel selector functor. * @return new power series with shifted selected coefficients. */ public MultiVarPowerSeries shiftSelect(final Selector sel) { return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { ExpVectorIterable ib = new ExpVectorIterable(ring.nvar, true, truncate); Iterator pos = ib.iterator(); @Override public C generate(ExpVector i) { C c; if (i.signum() > 0) { int[] deps = i.dependencyOnVariables(); ExpVector x = i.subst(deps[0], i.getVal(deps[0]) - 1L); c = get(x); // ensure all coefficients are generated } do { c = null; if (pos.hasNext()) { ExpVector e = pos.next(); c = coefficient(e); } else { break; } } while (!sel.select(c)); if (c == null) { // not correct because not known c = ring.coFac.getZERO(); } return c; } }); } /** * Map a unary function to this power series. * @param f evaluation functor. * @return new power series with coefficients f(this(i)). */ public MultiVarPowerSeries map(final UnaryFunctor f) { return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { return f.eval(coefficient(i)); } }); } /** * Map a binary function to this and another power series. * @param f evaluation functor with coefficients f(this(i),other(i)). * @param ps other power series. * @return new power series. */ public MultiVarPowerSeries zip(final BinaryFunctor f, final MultiVarPowerSeries ps) { int m = Math.min(ring.truncate, Math.max(truncate, ps.truncate())); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { return f.eval(coefficient(i), ps.coefficient(i)); } }, m); } /** * Sum of two power series, using zip(). * @param ps other power series. * @return this + ps. */ public MultiVarPowerSeries sumZip(MultiVarPowerSeries ps) { return zip(new BinaryFunctor() { @Override public C eval(C c1, C c2) { return c1.sum(c2); } }, ps); } /** * Subtraction of two power series, using zip(). * @param ps other power series. * @return this - ps. */ public MultiVarPowerSeries subtractZip(MultiVarPowerSeries ps) { return zip(new BinaryFunctor() { @Override public C eval(C c1, C c2) { return c1.subtract(c2); } }, ps); } /** * Multiply by coefficient. * @param a coefficient. * @return this * a. */ public MultiVarPowerSeries multiply(final C a) { if (a.isZERO()) { return ring.getZERO(); } if (a.isONE()) { return this; } return map(new UnaryFunctor() { @Override public C eval(C c) { return c.multiply(a); } }); } /** * Monic. * @return 1/orderCoeff() * this. */ public MultiVarPowerSeries monic() { ExpVector e = orderExpVector(); if (e == null) { return this; } C a = coefficient(e); if (a.isONE()) { return this; } if (a.isZERO()) { // sic return this; } final C b = a.inverse(); return map(new UnaryFunctor() { @Override public C eval(C c) { return b.multiply(c); } }); } /** * Negate. * @return - this. */ public MultiVarPowerSeries negate() { return map(new UnaryFunctor() { @Override public C eval(C c) { return c.negate(); } }); } /** * Absolute value. * @return abs(this). */ public MultiVarPowerSeries abs() { if (signum() < 0) { return negate(); } return this; } /** * Evaluate at given point. * @return ps(a). */ public C evaluate(List a) { C v = ring.coFac.getZERO(); for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { C c = coefficient(i); if (c.isZERO()) { continue; } c = c.multiply(i.evaluate(ring.coFac, a)); v = v.sum(c); } return v; } /** * Order. * @return index of first non zero coefficient. */ public int order() { if (order >= 0) { return order; } // must compute it GenPolynomial p = null; int t = 0; while (lazyCoeffs.homCheck.get(t)) { p = lazyCoeffs.coeffCache.get((long) t); if (p == null || p.isZERO()) { // ?? t++; continue; } order = t; evorder = p.trailingExpVector(); //System.out.println("order = " + t); return order; } for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { if (!coefficient(i).isZERO()) { order = (int) i.totalDeg(); //ord; evorder = i; //System.out.println("order = " + order + ", evorder = " + evorder); return order; } } order = truncate + 1; // evorder is null return order; } /** * Order ExpVector. * @return ExpVector of first non zero coefficient. */ public ExpVector orderExpVector() { //int x = order(); // ensure evorder is set return evorder; } /** * Order monomial. * @return first map entry or null. */ public Map.Entry orderMonomial() { ExpVector e = orderExpVector(); if (e == null) { return null; } //JAVA6only: //return new AbstractMap.SimpleImmutableEntry(e, coefficient(e)); return new MapEntry(e, coefficient(e)); } /** * Truncate. * @return truncate index of power series. */ public int truncate() { return truncate; } /** * Set truncate. * @param t new truncate index. * @return old truncate index of power series. */ public int setTruncate(int t) { if (t < 0) { throw new IllegalArgumentException("negative truncate not allowed"); } int ot = truncate; if (order >= 0) { if (order > truncate) { order = -1; // reset evorder = null; } } truncate = t; return ot; } /** * Ecart. * @return ecart. */ public long ecart() { ExpVector e = orderExpVector(); if (e == null) { return 0L; } long d = e.totalDeg(); long hd = d; for (long i = d + 1L; i <= truncate; i++) { if (!homogeneousPart(i).isZERO()) { hd = i; } } //System.out.println("d = " + d + ", hd = " + hd + ", coeffCache = " + lazyCoeffs.coeffCache + ", this = " + this); return hd - d; } /** * Signum. * @return sign of first non zero coefficient. */ public int signum() { ExpVector ev = orderExpVector(); if (ev != null) { return coefficient(ev).signum(); } return 0; } /** * Compare to. Note: compare only up to max(truncates). * @return sign of first non zero coefficient of this-ps. */ @Override public int compareTo(MultiVarPowerSeries ps) { final int m = truncate(); final int n = ps.truncate(); final int pos = Math.min(ring.truncate, Math.min(m, n)); int s = 0; //System.out.println("coeffCache_c1 = " + lazyCoeffs.coeffCache); //System.out.println("coeffCache_c2 = " + ps.lazyCoeffs.coeffCache); // test homogeneous parts first is slower for (ExpVector i : new ExpVectorIterable(ring.nvar, true, pos)) { s = coefficient(i).compareTo(ps.coefficient(i)); if (s != 0) { //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); return s; } } for (int j = pos + 1; j <= Math.min(ring.truncate, Math.max(m, n)); j++) { for (ExpVector i : new ExpVectorIterable(ring.nvar, j)) { s = coefficient(i).compareTo(ps.coefficient(i)); //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); if (s != 0) { //System.out.println("i = " + i + ", coeff = " + coefficient(i) + ", ps.coeff = " + ps.coefficient(i)); return s; } } } return s; } /** * Is power series zero. Note: compare only up to truncate. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return (signum() == 0); } /** * Is power series one. Note: compare only up to truncate. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { if (!leadingCoefficient().isONE()) { return false; } return (compareTo(ring.ONE) == 0); //return reductum().isZERO(); } /** * Comparison with any other object. Note: compare only up to * truncate. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof MultiVarPowerSeries)) { return false; } MultiVarPowerSeries a = (MultiVarPowerSeries) B; return compareTo(a) == 0; } /** * Hash code for this polynomial. Note: only up to truncate. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = 0; //h = ( ring.hashCode() << 23 ); //h += val.hashCode(); for (ExpVector i : new ExpVectorIterable(ring.nvar, true, truncate)) { C c = coefficient(i); //System.out.print(" i = " + i + " c = " + c); //System.out.println(" #i = " + i.hashCode() + " #c = " + c.hashCode() + "# = " + h); if (!c.isZERO()) { h += i.hashCode(); h = Math.abs(h << 1); } h += c.hashCode(); h = Math.abs(h); // << 3); } return h; } /** * Is unit. * @return true, if this power series is invertible, else false. */ public boolean isUnit() { return leadingCoefficient().isUnit(); } /** * Sum a another power series. * @param ps other power series. * @return this + ps. */ public MultiVarPowerSeries sum(final MultiVarPowerSeries ps) { //final MultiVarPowerSeries ps1 = this; // method name was ambiguous in generate int nt = Math.min(ring.truncate, Math.max(truncate(), ps.truncate())); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector e) { long tdeg = e.totalDeg(); if (lazyCoeffs.homCheck.get((int) tdeg)) { // generate respective homogeneous polynomial GenPolynomial p = homogeneousPart(tdeg).sum(ps.homogeneousPart(tdeg)); coeffCache.put(tdeg, p); // overwrite homCheck.set((int) tdeg); C c = p.coefficient(e); //System.out.println("c = " + c + ", e = " + e + ", tdeg = " + tdeg); return c; } return coefficient(e).sum(ps.coefficient(e)); } }, nt); } /** * Subtract a another power series. * @param ps other power series. * @return this - ps. */ public MultiVarPowerSeries subtract(final MultiVarPowerSeries ps) { //final MultiVarPowerSeries ps1 = this; // method name was ambiguous in generate int nt = Math.min(ring.truncate, Math.max(truncate(), ps.truncate())); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector e) { long tdeg = e.totalDeg(); if (lazyCoeffs.homCheck.get((int) tdeg)) { // generate respective homogeneous polynomial GenPolynomial p = homogeneousPart(tdeg).subtract(ps.homogeneousPart(tdeg)); coeffCache.put(tdeg, p); // overwrite homCheck.set((int) tdeg); C c = p.coefficient(e); //System.out.println("p = " + p + ", e = " + e + ", tdeg = " + tdeg); return c; } return coefficient(e).subtract(ps.coefficient(e)); } }, nt); } /** * Multiply by another power series. * @param ps other power series. * @return this * ps. */ public MultiVarPowerSeries multiply(final MultiVarPowerSeries ps) { //final MultiVarPowerSeries ps1 = this; // method name was ambiguous in generate int nt = Math.min(ring.truncate, truncate() + ps.truncate()); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector e) { long tdeg = e.totalDeg(); // generate respective homogeneous polynomial GenPolynomial p = null; //fac.getZERO(); for (int k = 0; k <= tdeg; k++) { GenPolynomial m = homogeneousPart(k).multiply(ps.homogeneousPart(tdeg - k)); if (p == null) { p = m; } else { p = p.sum(m); } } coeffCache.put(tdeg, p); // overwrite homCheck.set((int) tdeg); C c = p.coefficient(e); return c; } }, nt); } /** * Inverse power series. * @return ps with this * ps = 1. */ public MultiVarPowerSeries inverse() { return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector e) { long tdeg = e.totalDeg(); C d = leadingCoefficient().inverse(); // may fail if (tdeg == 0) { return d; } GenPolynomial p = null; //fac.getZERO(); for (int k = 0; k < tdeg; k++) { GenPolynomial m = getHomPart(k).multiply(homogeneousPart(tdeg - k)); if (p == null) { p = m; } else { p = p.sum(m); } } p = p.multiply(d.negate()); //System.out.println("tdeg = " + tdeg + ", p = " + p); coeffCache.put(tdeg, p); // overwrite homCheck.set((int) tdeg); C c = p.coefficient(e); return c; } }); } /** * Divide by another power series. * @param ps nonzero power series with invertible coefficient. * @return this / ps. */ public MultiVarPowerSeries divide(MultiVarPowerSeries ps) { if (ps.isUnit()) { return multiply(ps.inverse()); } int m = order(); int n = ps.order(); if (m < n) { return ring.getZERO(); } ExpVector em = orderExpVector(); ExpVector en = ps.orderExpVector(); if (!ps.coefficient(en).isUnit()) { throw new ArithmeticException("division by non unit coefficient " + ps.coefficient(ps.evorder) + ", evorder = " + ps.evorder); } // now m >= n MultiVarPowerSeries st, sps, q, sq; if (m == 0) { st = this; } else { st = this.shift(em.negate()); } if (n == 0) { sps = ps; } else { sps = ps.shift(en.negate()); } q = st.multiply(sps.inverse()); sq = q.shift(em.subtract(en)); return sq; } /** * Power series remainder. * @param ps nonzero power series with invertible leading coefficient. * @return remainder with this = quotient * ps + remainder. */ public MultiVarPowerSeries remainder(MultiVarPowerSeries ps) { int m = order(); int n = ps.order(); if (m >= n) { return ring.getZERO(); } return this; } /** * Quotient and remainder by division of this by S. * @param S a MultiVarPowerSeries * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public MultiVarPowerSeries[] quotientRemainder(MultiVarPowerSeries S) { return new MultiVarPowerSeries[] { divide(S), remainder(S) }; } /** * Differentiate with respect to variable r. * @param r variable for the direction. * @return differentiate(this). */ public MultiVarPowerSeries differentiate(final int r) { if (r < 0 || ring.nvar < r) { throw new IllegalArgumentException("variable index out of bound"); } return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { long d = i.getVal(r); ExpVector e = i.subst(r, d + 1); C v = coefficient(e); v = v.multiply(ring.coFac.fromInteger(d + 1)); return v; } }); } /** * Integrate with respect to variable r and with given constant. * @param c integration constant. * @param r variable for the direction. * @return integrate(this). */ public MultiVarPowerSeries integrate(final C c, final int r) { if (r < 0 || ring.nvar < r) { throw new IllegalArgumentException("variable index out of bound"); } int nt = Math.min(ring.truncate, truncate + 1); return new MultiVarPowerSeries(ring, new MultiVarCoefficients(ring) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return c; } long d = i.getVal(r); if (d > 0) { ExpVector e = i.subst(r, d - 1); C v = coefficient(e); v = v.divide(ring.coFac.fromInteger(d)); return v; } return ring.coFac.getZERO(); } }, nt); } /** * Power series greatest common divisor. * @param ps power series. * @return gcd(this,ps). */ public MultiVarPowerSeries gcd(MultiVarPowerSeries ps) { if (ps.isZERO()) { return this; } if (this.isZERO()) { return ps; } ExpVector em = orderExpVector(); ExpVector en = ps.orderExpVector(); return ring.getONE().shift(em.gcd(en)); } /** * Power series extended greatest common divisor. Note: not * implemented. * @param S power series. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ //SuppressWarnings("unchecked") public MultiVarPowerSeries[] egcd(MultiVarPowerSeries S) { throw new UnsupportedOperationException("egcd for power series not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/ps/MultiVarPowerSeriesMap.java000066400000000000000000000007221445075545500255360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import edu.jas.structure.RingElem; /** * Multivariate power series map interface. Defines method for mapping of power * series. * @param ring element type * @author Heinz Kredel */ public interface MultiVarPowerSeriesMap> { /** * Map. * @return new power series resulting from mapping elements of ps. */ public MultiVarPowerSeries map(MultiVarPowerSeries ps); } java-algebra-system-2.7.200/src/edu/jas/ps/MultiVarPowerSeriesRing.java000066400000000000000000000520761445075545500257310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.function.Function; import edu.jas.kern.PrettyPrint; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; /** * Multivariate power series ring implementation. Uses lazy evaluated generating * function for coefficients. * @param ring element type * @author Heinz Kredel */ public class MultiVarPowerSeriesRing> implements RingFactory> { /** * A default random sequence generator. */ protected final static Random random = new Random(); /** * Default truncate. */ public final static int DEFAULT_TRUNCATE = 7; /** * Truncate. */ int truncate; /** * Zero ExpVector. */ public final ExpVector EVZERO; /** * Coefficient ring factory. */ public final RingFactory coFac; /** * The number of variables. */ public final int nvar; /** * The names of the variables. This value can be modified. */ protected String[] vars; /** * The constant power series 1 for this ring. */ public final MultiVarPowerSeries ONE; /** * The constant power series 0 for this ring. */ public final MultiVarPowerSeries ZERO; /** * No argument constructor. */ @SuppressWarnings("unused") private MultiVarPowerSeriesRing() { throw new IllegalArgumentException("do not use no-argument constructor"); } /** * Constructor. * @param fac polynomial ring factory. */ public MultiVarPowerSeriesRing(GenPolynomialRing fac) { this(fac.coFac, fac.nvar, fac.getVars()); } /** * Constructor. * @param coFac coefficient ring factory. */ public MultiVarPowerSeriesRing(RingFactory coFac, int nv) { this(coFac, nv, DEFAULT_TRUNCATE); } /** * Constructor. * @param coFac coefficient ring factory. * @param truncate index of truncation. */ public MultiVarPowerSeriesRing(RingFactory coFac, int nv, int truncate) { this(coFac, nv, truncate, null); } /** * Constructor. * @param coFac coefficient ring factory. * @param names of the variables. */ public MultiVarPowerSeriesRing(RingFactory coFac, String[] names) { this(coFac, names.length, DEFAULT_TRUNCATE, names); } /** * Constructor. * @param cofac coefficient ring factory. * @param nv number of variables. * @param names of the variables. */ public MultiVarPowerSeriesRing(RingFactory cofac, int nv, String[] names) { this(cofac, nv, DEFAULT_TRUNCATE, names); } /** * Constructor. * @param cofac coefficient ring factory. * @param truncate index of truncation. * @param names of the variables. */ public MultiVarPowerSeriesRing(RingFactory cofac, int nv, int truncate, String[] names) { this.coFac = cofac; this.nvar = nv; this.truncate = truncate; if (names == null) { vars = null; } else { vars = Arrays.copyOf(names, names.length); // > Java-5 } if (vars == null) { if (PrettyPrint.isTrue()) { vars = GenPolynomialRing.newVars("x", nvar); } } else { if (vars.length != nvar) { throw new IllegalArgumentException("incompatible variable size " + vars.length + ", " + nvar); } // GenPolynomialRing.addVars(vars); } EVZERO = ExpVector.create(nvar); ONE = new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return coFac.getONE(); } return coFac.getZERO(); } }); ZERO = new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { return coFac.getZERO(); } }); } /** * Fixed point construction. * @param map a mapping of power series. * @return fix point wrt map. */ // Cannot be a static method because a power series ring is required. public MultiVarPowerSeries fixPoint(MultiVarPowerSeriesMap map) { MultiVarPowerSeries ps1 = new MultiVarPowerSeries(this); MultiVarPowerSeries ps2 = map.map(ps1); ps1.lazyCoeffs = ps2.lazyCoeffs; return ps2; } /** * To String. * @return string representation of this. */ @Override public String toString() { StringBuffer sb = new StringBuffer(); String scf = coFac.getClass().getSimpleName(); sb.append(scf + "((" + varsToString() + "))"); return sb.toString(); } /** * Get a String representation of the variable names. * @return names separated by commas. */ public String varsToString() { if (vars == null) { return "#" + nvar; } return ExpVector.varsToString(vars); //return Arrays.toString(vars); } /** * Get the variable names. * @return names. */ public String[] getVars() { return Arrays.copyOf(vars, vars.length); // > Java-5 } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("MPS("); String f = null; try { f = ((RingElem) coFac).toScriptFactory(); // sic } catch (Exception e) { f = coFac.toScript(); } s.append(f + ",\"" + varsToString() + "\"," + truncate + ")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { MultiVarPowerSeriesRing a = null; try { a = (MultiVarPowerSeriesRing) B; } catch (ClassCastException ignored) { } if (a == null) { return false; } if (!coFac.equals(a.coFac)) { return false; } if (Arrays.deepEquals(vars, a.vars)) { return true; } return false; } /** * Hash code for this . * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = coFac.hashCode(); h = h << 7; h += (Arrays.hashCode(vars) << 17); h += truncate; return h; } /** * Get the zero element. * @return 0 as MultiVarPowerSeries. */ public MultiVarPowerSeries getZERO() { return ZERO; } /** * Get the one element. * @return 1 as MultiVarPowerSeries. */ public MultiVarPowerSeries getONE() { return ONE; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = coFac.generators(); List> gens = new ArrayList>(rgens.size()); for (final C cg : rgens) { MultiVarPowerSeries g = new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return cg; } return coFac.getZERO(); } }); gens.add(g); } for (int i = 0; i < nvar; i++) { gens.add(ONE.shift(1, nvar - 1 - i)); } return gens; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Truncate. * @return truncate index of power series. */ public int truncate() { return truncate; } /** * Set truncate. * @param t new truncate index. * @return old truncate index of power series. */ public int setTruncate(int t) { if (t < 0) { throw new IllegalArgumentException("negative truncate not allowed"); } int ot = truncate; truncate = t; ONE.setTruncate(t); ZERO.setTruncate(t); return ot; } /** * Get the power series of the exponential function. * @param r variable for the direction. * @return exp(x_r) as MultiVarPowerSeries. */ public MultiVarPowerSeries getEXP(final int r) { return fixPoint(new MultiVarPowerSeriesMap() { public MultiVarPowerSeries map(MultiVarPowerSeries e) { return e.integrate(coFac.getONE(), r); } }); } /** * Get the power series of the sinus function. * @param r variable for the direction. * @return sin(x_r) as MultiVarPowerSeries. */ public MultiVarPowerSeries getSIN(final int r) { return fixPoint(new MultiVarPowerSeriesMap() { public MultiVarPowerSeries map(MultiVarPowerSeries s) { return s.negate().integrate(coFac.getONE(), r).integrate(coFac.getZERO(), r); } }); } /** * Get the power series of the cosinus function. * @param r variable for the direction. * @return cos(x_r) as MultiVarPowerSeries. */ public MultiVarPowerSeries getCOS(final int r) { return fixPoint(new MultiVarPowerSeriesMap() { public MultiVarPowerSeries map(MultiVarPowerSeries c) { return c.negate().integrate(coFac.getZERO(), r).integrate(coFac.getONE(), r); } }); } /** * Get the power series of the tangens function. * @param r variable for the direction. * @return tan(x_r) as MultiVarPowerSeries. */ public MultiVarPowerSeries getTAN(final int r) { return fixPoint(new MultiVarPowerSeriesMap() { public MultiVarPowerSeries map(MultiVarPowerSeries t) { return t.multiply(t).sum(getONE()).integrate(coFac.getZERO(), r); } }); } /** * Solve an partial differential equation. y_r' = f(y_r) with y_r(0) = c. * @param f a MultiVarPowerSeries. * @param c integration constant. * @param r variable for the direction. * @return f.integrate(c). */ public MultiVarPowerSeries solvePDE(MultiVarPowerSeries f, C c, int r) { return f.integrate(c, r); } /** * Query if this ring is commuative. * @return true, if this ring is commutative, else false. */ public boolean isCommutative() { return coFac.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return coFac.isAssociative(); } /** * Query if this ring is a field. * @return true if this ring is a field, else false. */ public boolean isField() { return (nvar == 0) && coFac.isField(); //false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Get a (constant) MultiVarPowerSeries<C> from a long value. * @param a long. * @return a MultiVarPowerSeries<C>. */ public MultiVarPowerSeries fromInteger(final long a) { return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return coFac.fromInteger(a); } return coFac.getZERO(); } }); } /** * Get a (constant) MultiVarPowerSeries<C> from a * java.math.BigInteger. * @param a BigInteger. * @return a MultiVarPowerSeries<C>. */ public MultiVarPowerSeries fromInteger(final java.math.BigInteger a) { return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return coFac.fromInteger(a); } return coFac.getZERO(); } }); } /** * Get the corresponding GenPolynomialRing<C>. * @return GenPolynomialRing<C>. */ public GenPolynomialRing polyRing() { return new GenPolynomialRing(coFac, nvar, vars); } /** * Get a MultiVarPowerSeries<C> from a GenPolynomial<C>. * @param a GenPolynomial<C>. * @return a MultiVarPowerSeries<C>. */ public MultiVarPowerSeries fromPolynomial(GenPolynomial a) { if (a == null || a.isZERO()) { return ZERO; } if (a.isONE()) { return ONE; } GenPolynomialRing pfac = polyRing(); HashMap> cache = new HashMap>(); int mt = 0; for (Monomial m : a) { ExpVector e = m.exponent(); long t = e.totalDeg(); mt = Math.max(mt, (int) t); GenPolynomial p = cache.get(t); if (p == null) { p = pfac.getZERO().copy(); cache.put(t, p); } p.doPutToMap(e, m.coefficient()); } mt++; if (mt > truncate()) { setTruncate(mt); } BitSet check = new BitSet(); for (int i = 0; i <= truncate(); i++) { check.set(i); if (cache.get((long) i) == null) { GenPolynomial p = pfac.getZERO().copy(); cache.put((long) i, p); //System.out.println("p zero for deg i = " + i); } } return new MultiVarPowerSeries(this, new MultiVarCoefficients(pfac, cache, check) { @Override public C generate(ExpVector e) { // cached coefficients returned by get return coFac.getZERO(); } }); } /** * Get a list of MultiVarPowerSeries<C> from a list of * GenPolynomial<C>. * @param A list of GenPolynomial<C>. * @return a list of MultiVarPowerSeries<C>. */ public List> fromPolynomial(List> A) { return ListUtil., MultiVarPowerSeries> map(A, new UnaryFunctor, MultiVarPowerSeries>() { public MultiVarPowerSeries eval(GenPolynomial c) { return fromPolynomial(c); } }); } /** * Get a MultiVarPowerSeries<C> from a univariate power series. * @param ps UnivPowerSeries<C>. * @param r variable for the direction. * @return a MultiVarPowerSeries<C>. */ public MultiVarPowerSeries fromPowerSeries(final UnivPowerSeries ps, final int r) { if (ps == null) { return ZERO; } return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { if (i.isZERO()) { return ps.coefficient(0); } int[] dep = i.dependencyOnVariables(); if (dep.length != 1) { return coFac.getZERO(); } if (dep[0] != r) { return coFac.getZERO(); } int j = (int) i.getVal(r); if (j > 0) { return ps.coefficient(j); } return coFac.getZERO(); } }); } /** * Generate a random power series with k = 5, d = 0.7. * @return a random power series. */ public MultiVarPowerSeries random() { return random(5, 0.7f, random); } /** * Generate a random power series with d = 0.7. * @param k bit-size of random coefficients. * @return a random power series. */ public MultiVarPowerSeries random(int k) { return random(k, 0.7f, random); } /** * Generate a random power series with d = 0.7. * @param k bit-size of random coefficients. * @param rnd is a source for random bits. * @return a random power series. */ public MultiVarPowerSeries random(int k, Random rnd) { return random(k, 0.7f, rnd); } /** * Generate a random power series. * @param k bit-size of random coefficients. * @param d density of non-zero coefficients. * @return a random power series. */ public MultiVarPowerSeries random(int k, float d) { return random(k, d, random); } /** * Generate a random power series. * @param k bit-size of random coefficients. * @param d density of non-zero coefficients. * @param rnd is a source for random bits. * @return a random power series. */ public MultiVarPowerSeries random(final int k, final float d, final Random rnd) { return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { // cached coefficients returned by get C c; float f = rnd.nextFloat(); if (f < d) { c = coFac.random(k, rnd); } else { c = coFac.getZERO(); } return c; } }); } /** * Generate a power series via lambda expression. * @param gener lambda expression. * @return a generated power series. */ public MultiVarPowerSeries generate(final Function gener) { return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { @Override public C generate(ExpVector i) { // cached coefficients returned by get C c = gener.apply(i); return c; } }); } /** * Copy power series. * @param c a power series. * @return a copy of c. */ public MultiVarPowerSeries copy(MultiVarPowerSeries c) { return new MultiVarPowerSeries(this, c.lazyCoeffs); } /** * Parse a power series. Note: not implemented. * @param s String. * @return power series from s. */ public MultiVarPowerSeries parse(String s) { throw new UnsupportedOperationException("parse for power series not implemented"); } /** * Parse a power series. Note: not implemented. * @param r Reader. * @return next power series from r. */ public MultiVarPowerSeries parse(Reader r) { throw new UnsupportedOperationException("parse for power series not implemented"); } /** * Taylor power series. * @param f function. * @param a expansion point. * @return Taylor series of f. */ public MultiVarPowerSeries seriesOfTaylor(final TaylorFunction f, final List a) { return new MultiVarPowerSeries(this, new MultiVarCoefficients(this) { TaylorFunction der = f; // Map> pderCache = ... final List v = a; @Override public C generate(ExpVector i) { C c; int s = i.signum(); if (s == 0) { c = der.evaluate(v); return c; } TaylorFunction pder = der.derivative(i); if (pder.isZERO()) { return coFac.getZERO(); } c = pder.evaluate(v); if (c.isZERO()) { return c; } long f = pder.getFacul(); c = c.divide(coFac.fromInteger(f)); return c; } }); } } java-algebra-system-2.7.200/src/edu/jas/ps/OrderedPairlist.java000066400000000000000000000211331445075545500242400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.structure.RingElem; /** * Pair list management. Implemented using MultiVarPowerSeries, TreeMap and * BitSet. * @author Heinz Kredel */ public class OrderedPairlist> { protected final ArrayList> P; protected final TreeMap>> pairlist; protected final ArrayList red; protected final MultiVarPowerSeriesRing ring; protected final ReductionSeq reduction; protected boolean oneInGB = false; protected boolean useCriterion4 = true; protected boolean useCriterion3 = true; protected int putCount; protected int remCount; protected final int moduleVars; private static final Logger logger = LogManager.getLogger(OrderedPairlist.class); /** * Constructor for OrderedPairlist. * @param r power series factory. */ public OrderedPairlist(MultiVarPowerSeriesRing r) { this(0, r); } /** * Constructor for OrderedPairlist. * @param m number of module variables. * @param r power series factory. */ public OrderedPairlist(int m, MultiVarPowerSeriesRing r) { moduleVars = m; ring = r; P = new ArrayList>(); pairlist = new TreeMap>>(ring.polyRing().tord.getAscendComparator()); //pairlist = new TreeMap>>(ring.polyRing().tord.getDescendComparator()); red = new ArrayList(); putCount = 0; remCount = 0; reduction = new ReductionSeq(); } /** * toString. */ @Override public String toString() { StringBuffer s = new StringBuffer("OrderedPairlist("); //s.append("ps="+P.size()); s.append("#put=" + putCount); s.append(", #rem=" + remCount); if (pairlist.size() != 0) { s.append(", size=" + pairlist.size()); } s.append(")"); return s.toString(); } /** * Put one power Series to the pairlist and reduction matrix. * @param p power series. * @return the index of the added power series. */ public synchronized int put(MultiVarPowerSeries p) { putCount++; if (oneInGB) { return P.size() - 1; } ExpVector e = p.orderExpVector(); int l = P.size(); for (int j = 0; j < l; j++) { MultiVarPowerSeries pj = P.get(j); ExpVector f = pj.orderExpVector(); if (moduleVars > 0) { if (!reduction.moduleCriterion(moduleVars, e, f)) { continue; // skip pair } } ExpVector g = e.lcm(f); Pair pair = new Pair(pj, p, j, l); // redi = (BitSet)red.get(j); ///if ( j < l ) redi.set( l ); // System.out.println("bitset."+j+" = " + redi ); //multiple pairs under same keys -> list of pairs LinkedList> xl = pairlist.get(g); if (xl == null) { xl = new LinkedList>(); } //xl.addLast( pair ); // first or last ? xl.addFirst(pair); // first or last ? better for d- e-GBs pairlist.put(g, xl); } // System.out.println("pairlist.keys@put = " + pairlist.keySet() ); P.add(p); BitSet redi = new BitSet(); redi.set(0, l); // jdk 1.4 red.add(redi); return P.size() - 1; } /** * Put all power series in F to the pairlist and reduction matrix. * @param F power series list. * @return the index of the last added power series. */ public int put(List> F) { int i = 0; for (MultiVarPowerSeries p : F) { i = put(p); } return i; } /** * Remove the next required pair from the pairlist and reduction matrix. * Apply the criterions 3 and 4 to see if the S-power-series is required. * @return the next pair if one exists, otherwise null. */ public synchronized Pair removeNext() { if (oneInGB) { return null; } Iterator>>> ip = pairlist.entrySet().iterator(); Pair pair = null; boolean c = false; int i, j; while (!c && ip.hasNext()) { Map.Entry>> me = ip.next(); ExpVector g = me.getKey(); LinkedList> xl = me.getValue(); logger.info("g = {}", g); pair = null; while (!c && xl.size() > 0) { pair = xl.removeFirst(); // xl is also modified in pairlist i = pair.i; j = pair.j; // System.out.println("pair(" + j + "," +i+") "); c = true; if (useCriterion4) { c = reduction.criterion4(pair.pi, pair.pj, g); } //System.out.println("c4 = " + c); if (c && useCriterion3) { c = criterion3(i, j, g); //System.out.println("c3 = " + c); } red.get(j).clear(i); // set(i,false) jdk1.4 } if (xl.size() == 0) ip.remove(); // = pairlist.remove( g ); } if (!c) { pair = null; } else { remCount++; // count only real pairs } return pair; } /** * Test if there is possibly a pair in the list. * @return true if a next pair could exist, otherwise false. */ public synchronized boolean hasNext() { return pairlist.size() > 0; } /** * Get the list of power series. * @return the power series list. */ public List> getList() { return P; } /** * Get the number of power series put to the pairlist. * @return the number of calls to put. */ public synchronized int putCount() { return putCount; } /** * Get the number of required pairs removed from the pairlist. * @return the number of non null pairs delivered. */ public synchronized int remCount() { return remCount; } /** * Put to ONE-power-series to the pairlist. * @param one power series. (no more required) * @return the index of the last power series. */ public synchronized int putOne(MultiVarPowerSeries one) { putCount++; if (one == null) { return P.size() - 1; } if (!one.isONE()) { return P.size() - 1; } return putOne(); } /** * Put the ONE-power-series to the pairlist. * @return the index of the last power-series. */ public synchronized int putOne() { oneInGB = true; pairlist.clear(); P.clear(); P.add(ring.getONE()); red.clear(); return P.size() - 1; } /** * GB criterion 3. * @return true if the S-power-series(i,j) is required. */ public boolean criterion3(int i, int j, ExpVector eij) { // assert i < j; boolean s = red.get(j).get(i); if (!s) { logger.warn("c3.s false for {} {}", j, i); return s; } // now s = true; for (int k = 0; k < P.size(); k++) { MultiVarPowerSeries A = P.get(k); ExpVector ek = A.orderExpVector(); boolean m = eij.multipleOf(ek); if (m) { if (k < i) { // System.out.println("k < i "+k+" "+i); s = red.get(i).get(k) || red.get(j).get(k); } else if (i < k && k < j) { // System.out.println("i < k < j "+i+" "+k+" "+j); s = red.get(k).get(i) || red.get(j).get(k); } else if (j < k) { //System.out.println("j < k "+j+" "+k); s = red.get(k).get(i) || red.get(k).get(j); } //System.out.println("s."+k+" = " + s); if (!s) { return s; } } } return true; } } java-algebra-system-2.7.200/src/edu/jas/ps/PSUtil.java000066400000000000000000000036501445075545500223300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import edu.jas.structure.RingElem; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; /** * Power series utilities. For example monic power series. * @author Heinz Kredel */ public class PSUtil { /** * Power series list monic. * @param coefficient type. * @param L list of power series with field coefficients. * @return list of power series with leading coefficient 1. */ public static > List> monic(List> L) { return ListUtil., MultiVarPowerSeries> map(L, new UnaryFunctor, MultiVarPowerSeries>() { public MultiVarPowerSeries eval(MultiVarPowerSeries c) { if (c == null) { return null; } return c.monic(); } }); } /** * Univariate power series list monic. * @param coefficient type. * @param L list of univariate power series with field coefficients. * @return list of univariate power series with leading coefficient 1. */ public static > List> monicUniv(List> L) { return ListUtil., UnivPowerSeries> map(L, new UnaryFunctor, UnivPowerSeries>() { public UnivPowerSeries eval(UnivPowerSeries c) { if (c == null) { return null; } return c.monic(); } }); } } java-algebra-system-2.7.200/src/edu/jas/ps/Pair.java000066400000000000000000000066771445075545500220570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.io.Serializable; import edu.jas.structure.RingElem; /** * Serializable subclass to hold pairs of power series. * @param coefficient type * @author Heinz Kredel */ public class Pair> implements Serializable, Comparable { public final MultiVarPowerSeries pi; public final MultiVarPowerSeries pj; public final int i; public final int j; protected int n; protected boolean toZero = false; protected boolean useCriterion4 = false; protected boolean useCriterion3 = false; /** * Pair constructor. * @param a power series i. * @param b power series j. * @param i first index. * @param j second index. */ public Pair(MultiVarPowerSeries a, MultiVarPowerSeries b, int i, int j) { pi = a; pj = b; this.i = i; this.j = j; this.n = 0; toZero = false; // ok } /** * toString. */ @Override public String toString() { return "pair[" + n + "](" + i + j + ", r0=" + toZero + ", c4=" + useCriterion4 + ", c3=" + useCriterion3 + ")"; } /** * Set removed pair number. * @param n number of this pair generated in OrderedPairlist. */ public void pairNumber(int n) { this.n = n; } /** * Get removed pair number. * @return n number of this pair generated in OrderedPairlist. */ public int getPairNumber() { return n; } /** * Set zero reduction. The S-power-series of this Pair was reduced to zero. */ public void setZero() { toZero = true; } /** * Is reduced to zero. * @return true if the S-power-series of this Pair was reduced to zero, else * false. */ public boolean isZero() { return toZero; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override public boolean equals(Object ob) { if (!(ob instanceof Pair)) { return false; // throw new ClassCastException("Pair "+n+" o "+o); } return 0 == compareTo((Pair) ob); } /** * compareTo used in TreeMap // not used at moment. Comparison is based on * the number of the pairs. * @param p a Pair. * @return 1 if (this < o), 0 if (this == o), -1 if (this > o). */ public int compareTo(Pair p) { int x = p.getPairNumber(); if (n > x) { return 1; } if (n < x) { return -1; } return 0; } /** * Hash code for this Pair. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (i << 16) + j; } /** * Set useCriterion4. * @param c boolean value to set. */ public void setUseCriterion4(boolean c) { this.useCriterion4 = c; } /** * Get useCriterion4. * @return boolean value. */ public boolean getUseCriterion4() { return this.useCriterion4; } /** * Set useCriterion3. * @param c boolean value to set. */ public void setUseCriterion3(boolean c) { this.useCriterion3 = c; } /** * Get useCriterion3. * @return boolean value. */ public boolean getUseCriterion3() { return this.useCriterion3; } } java-algebra-system-2.7.200/src/edu/jas/ps/PolynomialTaylorFunction.java000066400000000000000000000057731445075545500262040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; /** * Polynomial functions capable for Taylor series expansion. * @param ring element type * @author Heinz Kredel */ public class PolynomialTaylorFunction> implements TaylorFunction { final GenPolynomial pol; final long facul; public PolynomialTaylorFunction(GenPolynomial p) { this(p, 1L); } public PolynomialTaylorFunction(GenPolynomial p, long f) { pol = p; facul = f; } /** * To String. * @return string representation of this. */ @Override public String toString() { return pol.toString(); } /** * Get the factorial coefficient. * @return factorial coefficient. */ @Override public long getFacul() { return facul; } /** * Test if this is zero. * @return true if this is 0, else false. */ public boolean isZERO() { return pol.isZERO(); } /** * Derivative. * @return derivative of this. */ @Override public TaylorFunction derivative() { return new PolynomialTaylorFunction(PolyUtil. baseDerivative(pol)); } /* * Partial derivative. * @param r index of the variable. * @return partial derivative of this with respect to variable r. public TaylorFunction derivative(int r) { return new PolynomialTaylorFunction(PolyUtil. baseDerivative(pol,r)); } */ /** * Multi-partial derivative. * @param i exponent vector. * @return partial derivative of this with respect to all variables. */ public TaylorFunction derivative(ExpVector i) { GenPolynomial p = pol; long f = 1L; if (i.signum() == 0 || pol.isZERO()) { return new PolynomialTaylorFunction(p, f); } for (int j = 0; j < i.length(); j++) { long e = i.getVal(j); if (e == 0) { continue; } int jl = i.length() - 1 - j; for (long k = 0; k < e; k++) { p = PolyUtil. baseDerivative(p, jl); f *= (k + 1); if (p.isZERO()) { return new PolynomialTaylorFunction(p, f); } } } //System.out.println("i = " + i + ", f = " + f + ", der = " + p); return new PolynomialTaylorFunction(p, f); } /** * Evaluate. * @param a element. * @return this(a). */ @Override public C evaluate(C a) { return PolyUtil. evaluateMain(pol.ring.coFac, pol, a); } /** * Evaluate at a tuple of elements. * @param a tuple of elements. * @return this(a). */ public C evaluate(List a) { return PolyUtil. evaluateAll(pol.ring.coFac, pol, a); } } java-algebra-system-2.7.200/src/edu/jas/ps/ReductionSeq.java000066400000000000000000000275061445075545500235630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingElem; /** * Multivariate power series reduction sequential use algorithm. Implements Mora * normal-form algorithm. * @param coefficient type * @author Heinz Kredel */ public class ReductionSeq> // should be FieldElem> /* extends ReductionAbstract */{ private static final Logger logger = LogManager.getLogger(ReductionSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public ReductionSeq() { } /** * Module criterium. * @param modv number of module variables. * @param A power series. * @param B power series. * @return true if the module S-power-series(i,j) is required. */ public boolean moduleCriterion(int modv, MultiVarPowerSeries A, MultiVarPowerSeries B) { if (modv == 0) { return true; } ExpVector ei = A.orderExpVector(); ExpVector ej = B.orderExpVector(); return moduleCriterion(modv, ei, ej); } /** * Module criterion. * @param modv number of module variables. * @param ei ExpVector. * @param ej ExpVector. * @return true if the module S-power-series(i,j) is required. */ public boolean moduleCriterion(int modv, ExpVector ei, ExpVector ej) { if (modv == 0) { return true; } if (ei.invLexCompareTo(ej, 0, modv) != 0) { return false; // skip pair } return true; } /** * GB criterion 4. Use only for commutative power series rings. * @param A power series. * @param B power series. * @param e = lcm(ht(A),ht(B)) * @return true if the S-power-series(i,j) is required, else false. */ public boolean criterion4(MultiVarPowerSeries A, MultiVarPowerSeries B, ExpVector e) { if (logger.isInfoEnabled()) { if (!A.ring.equals(B.ring)) { logger.error("rings not equal: {} != {}", A.ring, B.ring); } if (!A.ring.isCommutative()) { logger.error("GBCriterion4 not applicabable to non-commutative power series"); return true; } } ExpVector ei = A.orderExpVector(); ExpVector ej = B.orderExpVector(); ExpVector g = ei.sum(ej); // boolean t = g == e ; ExpVector h = g.subtract(e); int s = h.signum(); return !(s == 0); } /** * S-Power-series, S-polynomial. * @param A power series. * @param B power series. * @return spol(A,B) the S-power-series of A and B. */ public MultiVarPowerSeries SPolynomial(MultiVarPowerSeries A, MultiVarPowerSeries B) { if (B == null || B.isZERO()) { if (A == null) { return B; } return A.ring.getZERO(); } if (A == null || A.isZERO()) { return B.ring.getZERO(); } if (debug) { if (!A.ring.equals(B.ring)) { logger.error("rings not equal: {} != {}", A.ring, B.ring); } } Map.Entry ma = A.orderMonomial(); Map.Entry mb = B.orderMonomial(); ExpVector e = ma.getKey(); ExpVector f = mb.getKey(); ExpVector g = e.lcm(f); ExpVector e1 = g.subtract(e); ExpVector f1 = g.subtract(f); C a = ma.getValue(); C b = mb.getValue(); MultiVarPowerSeries Ap = A.multiply(b, e1); MultiVarPowerSeries Bp = B.multiply(a, f1); MultiVarPowerSeries C = Ap.subtract(Bp); return C; } /** * Top normal-form with Mora's algorithm. * @param Ap power series. * @param Pp power series list. * @return top-nf(Ap) with respect to Pp. */ public MultiVarPowerSeries normalform(List> Pp, MultiVarPowerSeries Ap) { if (Pp == null || Pp.isEmpty()) { return Ap; } if (Ap == null || Ap.isZERO()) { return Ap; } if (!Ap.ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } List> P = new ArrayList>(Pp.size()); synchronized (Pp) { P.addAll(Pp); } ArrayList htl = new ArrayList(P.size()); ArrayList lbc = new ArrayList(P.size()); ArrayList> p = new ArrayList>(P.size()); ArrayList ecart = new ArrayList(P.size()); Map.Entry m; //int j = 0; for (int i = 0; i < P.size(); i++) { m = P.get(i).orderMonomial(); //System.out.println("m_i = " + m); if (m != null) { p.add(P.get(i)); //System.out.println("e = " + m.getKey().toString(Ap.ring.vars)); htl.add(m.getKey()); lbc.add(m.getValue()); ecart.add(P.get(i).ecart()); //j++; } } //int ll = j; MultiVarPowerSeries S = Ap; //S.setTruncate(Ap.ring.truncate()); // ?? m = S.orderMonomial(); while (true) { //System.out.println("m = " + m); //System.out.println("S = " + S); if (m == null) { return S; } if (S.isZERO()) { return S; } ExpVector e = m.getKey(); if (debug) { logger.debug("e = {}", e.toString(Ap.ring.vars)); } // search ps with ht(ps) | ht(S) List li = new ArrayList(); int i; for (i = 0; i < htl.size(); i++) { if (e.multipleOf(htl.get(i))) { //System.out.println("m = " + m); li.add(i); } } if (li.isEmpty()) { return S; } //System.out.println("li = " + li); // select ps with smallest ecart long mi = Long.MAX_VALUE; //String es = ""; for (int k = 0; k < li.size(); k++) { int ki = li.get(k); long x = ecart.get(ki); //p.get( ki ).ecart(); //es = es + x + " "; if (x < mi) { // first < or last <= ? mi = x; i = ki; } } //System.out.println("li = " + li + ", ecarts = " + es); //System.out.println("i = " + i + ", p_i = " + p.get(i)); //if ( i <= ll ) { //} else { // System.out.println("i = " + i + ", ll = " + ll); //} long si = S.ecart(); if (mi > si) { //System.out.println("ecart_i = " + mi + ", ecart_S = " + si + ", S+ = " + S); p.add(S); htl.add(m.getKey()); lbc.add(m.getValue()); ecart.add(si); } e = e.subtract(htl.get(i)); C a = m.getValue().divide(lbc.get(i)); MultiVarPowerSeries Q = p.get(i).multiply(a, e); S = S.subtract(Q); m = S.orderMonomial(); } } /** * Total reduced normal-form with Mora's algorithm. * @param A power series. * @param P power series list. * @return total-nf(A) with respect to P. */ public MultiVarPowerSeries totalNormalform(List> P, MultiVarPowerSeries A) { if (P == null || P.isEmpty()) { return A; } if (A == null) { return A; } MultiVarPowerSeries R = normalform(P, A); if (R.isZERO()) { return R; } MultiVarCoefficients Rc = new MultiVarCoefficients(A.ring) { @Override public C generate(ExpVector i) { // will not be used return pfac.coFac.getZERO(); } }; GenPolynomialRing pfac = A.lazyCoeffs.pfac; while (!R.isZERO()) { Map.Entry m = R.orderMonomial(); if (m == null) { break; } R = R.reductum(); ExpVector e = m.getKey(); long t = e.totalDeg(); GenPolynomial p = Rc.coeffCache.get(t); if (p == null) { p = pfac.getZERO(); } p = p.sum(m.getValue(), e); Rc.coeffCache.put(t, p); // zeros need never update R = normalform(P, R); } R = R.sum(Rc); //System.out.println("R+Rc = " + R); return R; } /** * Total reduced normalform with Mora's algorithm. * @param P power series list. * @return total-nf(p) for p with respect to P\{p}. */ public List> totalNormalform(List> P) { if (P == null || P.isEmpty()) { return P; } //StandardBaseSeq std = new StandardBaseSeq(); List> R = new ArrayList>(P.size()); List> S = new ArrayList>(P); for (MultiVarPowerSeries a : P) { //S.remove(a); //if ( !std.isSTD(S) ) { // System.out.println("a = " + a); //} Map.Entry m = a.orderMonomial(); if (m == null) { //S.add(a); continue; } MultiVarPowerSeries r = a.reductum(); MultiVarPowerSeries b = normalform(S, r); // need also unit of reduction: u r --> b // b = b.multiply(u); b = b.sum(m); if (!b.isZERO()) { R.add(b); } } return R; } /** * Is top reducible. * @param A power series. * @param P power series list. * @return true if A is top reducible with respect to P. */ public boolean isTopReducible(List> P, MultiVarPowerSeries A) { if (P == null || P.isEmpty()) { return false; } if (A == null) { return false; } ExpVector e = A.orderExpVector(); if (e == null) { return false; } for (MultiVarPowerSeries p : P) { ExpVector ep = p.orderExpVector(); if (ep == null) { // found by findbugs continue; } if (e.multipleOf(ep)) { return true; } } return false; } /** * Ideal containment. Test if each b in B is contained in ideal S. * @param S standard base. * @param B list of power series * @return true, if each b in B is contained in ideal(S), else false */ public boolean contains(List> S, List> B) { if (B == null || B.size() == 0) { return true; } if (S == null || S.size() == 0) { return true; } for (MultiVarPowerSeries b : B) { if (b == null) { continue; } MultiVarPowerSeries z = normalform(S, b); if (!z.isZERO()) { System.out.println("contains nf(b) != 0: " + b + ", z = " + z); return false; } } return true; } } java-algebra-system-2.7.200/src/edu/jas/ps/StandardBaseSeq.java000066400000000000000000000175061445075545500241610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.ExpVector; import edu.jas.structure.RingElem; /** * Standard Base sequential algorithm. Implements Standard bases and GB test. * Note: Currently the term order is fixed to the order defined by the * iterator over exponent vectors ExpVectorIterator. * @param coefficient type * @author Heinz Kredel */ public class StandardBaseSeq> /* extends StandardBaseAbstract */{ private static final Logger logger = LogManager.getLogger(StandardBaseSeq.class); private static final boolean debug = logger.isDebugEnabled(); /** * Reduction engine. */ public final ReductionSeq red; /** * Constructor. */ public StandardBaseSeq() { //super(); this(new ReductionSeq()); } /** * Constructor. * @param red Reduction engine */ public StandardBaseSeq(ReductionSeq red) { this.red = red; //super(red); } /** * Normalize power series list. * @param A list of power series. * @return list of power series with zeros removed and ones/units reduced. */ public List> normalizeZerosOnes(List> A) { if (A == null) { return A; } List> N = new ArrayList>(A.size()); if (A.isEmpty()) { return N; } for (MultiVarPowerSeries p : A) { if (p == null || p.isZERO()) { continue; } if (p.isUnit()) { N.clear(); N.add(p.ring.getONE()); return N; } N.add(p.abs()); } //N.trimToSize(); return N; } /** * Standard base test. * @param F power series list. * @return true, if F is a Standard base, else false. */ public boolean isSTD(List> F) { return isSTD(0, F); } /** * Standard base test. * @param modv module variable number. * @param F power series list. * @return true, if F is a Standard base, else false. */ public boolean isSTD(int modv, List> F) { if (F == null) { return true; } MultiVarPowerSeries pi, pj, s, h; for (int i = 0; i < F.size(); i++) { pi = F.get(i); for (int j = i + 1; j < F.size(); j++) { pj = F.get(j); if (!red.moduleCriterion(modv, pi, pj)) { continue; } // if ( ! red.criterion4( pi, pj ) ) { // continue; // } s = red.SPolynomial(pi, pj); if (s.isZERO()) { continue; } h = red.normalform(F, s); if (!h.isZERO()) { System.out.println("pi = " + pi + ", pj = " + pj); System.out.println("s = " + s + ", h = " + h); return false; } } } return true; } /** * Standard base using pairlist class. * @param F power series list. * @return STD(F) a Standard base of F. */ public List> STD(List> F) { return STD(0, F); } /** * Standard base using pairlist class. * @param modv module variable number. * @param F power series list. * @return STD(F) a Standard base of F. */ public List> STD(int modv, List> F) { List> G = normalizeZerosOnes(F); G = PSUtil. monic(G); if (G.size() <= 1) { return G; } MultiVarPowerSeriesRing ring = G.get(0).ring; if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficients not from a field"); } OrderedPairlist pairlist = new OrderedPairlist(modv, ring); //strategy.create( modv, ring ); pairlist.put(G); logger.info("start {}", pairlist); Pair pair; MultiVarPowerSeries pi, pj, S, H; while (pairlist.hasNext()) { pair = pairlist.removeNext(); //logger.debug("pair = {}", pair); if (pair == null) { continue; } pi = pair.pi; pj = pair.pj; if ( /*false &&*/debug) { logger.debug("pi = {}", pi); logger.debug("pj = {}", pj); } S = red.SPolynomial(pi, pj); //S.setTruncate(p.ring.truncate()); // ?? if (S.isZERO()) { pair.setZero(); continue; } if (logger.isInfoEnabled()) { ExpVector es = S.orderExpVector(); logger.info("ht(S) = {}, {}", es.toString(S.ring.vars), es); // + ", S = {}", S); } //long t = System.currentTimeMillis(); H = red.normalform(G, S); if (H.isZERO()) { pair.setZero(); continue; } //t = System.currentTimeMillis() - t; //System.out.println("time = " + t); if (logger.isInfoEnabled()) { ExpVector eh = H.orderExpVector(); logger.info("ht(H) = {}, {}", eh.toString(S.ring.vars), eh); // + ", coeff(HT(H)) = {}", H.coefficient(eh)); } //H = H.monic(); if (H.isUnit()) { G.clear(); G.add(H); return G; // since no threads are activated } if (debug) { logger.info("H = {}", H); } //if (!H.isZERO()) { //l++; G.add(H); pairlist.put(H); //} } logger.debug("#sequential list = {}", G.size()); G = minimalSTD(G); logger.info("end {}", pairlist); return G; } /** * Minimal ordered Standard basis. * @param Gp a Standard base. * @return a minimal Standard base of Gp, not auto reduced. */ public List> minimalSTD(List> Gp) { if (Gp == null || Gp.size() <= 1) { return Gp; } // remove zero power series List> G = new ArrayList>(Gp.size()); for (MultiVarPowerSeries a : Gp) { if (a != null && !a.isZERO()) { // always true in GB() // make positive a = a.abs(); ? a = a.monic(); G.add(a); } } if (G.size() <= 1) { return G; } // remove top reducible power series MultiVarPowerSeries a; List> F = new ArrayList>(G.size()); while (G.size() > 0) { a = G.remove(0); if (red.isTopReducible(G, a) || red.isTopReducible(F, a)) { // drop power series if (debug) { System.out.println("dropped " + a); List> ff = new ArrayList>(G); ff.addAll(F); a = red.normalform(ff, a); if (!a.isZERO()) { System.out.println("error, nf(a) " + a); } } } else { F.add(a); } } G = F; // power series not reduced return G; } } java-algebra-system-2.7.200/src/edu/jas/ps/TaylorFunction.java000066400000000000000000000022001445075545500241160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.structure.RingElem; /** * Interface for functions capable for Taylor series expansion. * @param ring element type * @author Heinz Kredel */ public interface TaylorFunction> { /** * Get the factorial coefficient. * @return factorial coefficient. */ public long getFacul(); /** * Test if this is zero. * @return true if this is 0, else false. */ public boolean isZERO(); /** * Derivative. * @return derivative of this. */ public TaylorFunction derivative(); /** * Multi-partial derivative. * @param i exponent vector. * @return partial derivative of this with respect to all variables. */ public TaylorFunction derivative(ExpVector i); /** * Evaluate. * @param a element. * @return this(a). */ public C evaluate(C a); /** * Evaluate at a tuple of elements. * @param a tuple of elements. * @return this(a). */ public C evaluate(List a); } java-algebra-system-2.7.200/src/edu/jas/ps/TaylorFunctionAdapter.java000066400000000000000000000030701445075545500254250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.structure.RingElem; /** * Adapter for functions capable for Taylor series expansion. * @param ring element type * @author Heinz Kredel */ public abstract class TaylorFunctionAdapter> implements TaylorFunction { /** * Get the factorial coefficient. * @return factorial coefficient. */ public long getFacul() { return 1L; } /** * Test if this is zero. * @return true if this is 0, else false. */ public boolean isZERO() { throw new UnsupportedOperationException("not implemented"); } /** * Derivative. * @return derivative of this. */ public TaylorFunction derivative() { throw new UnsupportedOperationException("not implemented"); } /** * Multi-partial derivative. * @param i exponent vector. * @return partial derivative of this with respect to all variables. */ public TaylorFunction derivative(ExpVector i) { throw new UnsupportedOperationException("not implemented"); } /** * Evaluate. * @param a element. * @return this(a). */ public C evaluate(C a) { throw new UnsupportedOperationException("not implemented"); } /** * Evaluate at a tuple of elements. * @param a tuple of elements. * @return this(a). */ public C evaluate(List a) { throw new UnsupportedOperationException("not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/ps/UnivPowerSeries.java000066400000000000000000000567561445075545500243000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.List; import java.util.ArrayList; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; import edu.jas.structure.BinaryFunctor; import edu.jas.structure.RingElem; import edu.jas.structure.Selector; import edu.jas.structure.UnaryFunctor; /** * Univariate power series implementation. Uses inner classes and lazy evaluated * generating function for coefficients. All ring element methods use lazy * evaluation except where noted otherwise. Eager evaluated methods are * toString(), compareTo(), equals(), * evaluate(), or they use the order() method, like * signum(), abs(), divide(), * remainder() and gcd(). * @param ring element type * @author Heinz Kredel */ public class UnivPowerSeries> implements RingElem> { /** * Power series ring factory. */ public final UnivPowerSeriesRing ring; /** * Data structure / generating function for coefficients. Cannot be final * because of fixPoint, must be accessible in factory. */ /*package*/Coefficients lazyCoeffs; /** * Truncation of computations. */ private int truncate = 11; /** * Order of power series. */ private int order = -1; // == unknown /** * Private constructor. */ @SuppressWarnings("unused") private UnivPowerSeries() { throw new IllegalArgumentException("do not use no-argument constructor"); } /** * Package constructor. Use in fixPoint only, must be accessible in factory. * @param ring power series ring. */ /*package*/ UnivPowerSeries(UnivPowerSeriesRing ring) { this.ring = ring; this.lazyCoeffs = null; } /** * Constructor. * @param ring power series ring. * @param lazyCoeffs generating function for coefficients. */ public UnivPowerSeries(UnivPowerSeriesRing ring, Coefficients lazyCoeffs) { if (lazyCoeffs == null || ring == null) { throw new IllegalArgumentException( "null not allowed: ring = " + ring + ", lazyCoeffs = " + lazyCoeffs); } this.ring = ring; this.lazyCoeffs = lazyCoeffs; this.truncate = ring.truncate; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public UnivPowerSeriesRing factory() { return ring; } /** * Clone this power series. * @see java.lang.Object#clone() */ @Override public UnivPowerSeries copy() { return new UnivPowerSeries(ring, lazyCoeffs); } /** * String representation of power series. * @see java.lang.Object#toString() */ @Override public String toString() { return toString(truncate); } /** * To String with given truncate. * @return string representation of this to given truncate. */ public String toString(int truncate) { StringBuffer sb = new StringBuffer(); UnivPowerSeries s = this; String var = ring.var; //System.out.println("cache = " + s.coeffCache); for (int i = 0; i < truncate; i++) { C c = s.coefficient(i); int si = c.signum(); if (si != 0) { if (si > 0) { if (sb.length() > 0) { sb.append(" + "); } } else { c = c.negate(); sb.append(" - "); } if (!c.isONE() || i == 0) { if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append("{ "); } sb.append(c.toString()); if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append(" }"); } if (i > 0) { sb.append(" * "); } } if (i == 0) { //skip; sb.append(" "); } else if (i == 1) { sb.append(var); } else { sb.append(var + "^" + i); } //sb.append(c.toString() + ", "); } //System.out.println("cache = " + s.coeffCache); } if (sb.length() == 0) { sb.append("0"); } sb.append(" + BigO(" + var + "^" + truncate + ")"); //sb.append("..."); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer sb = new StringBuffer(""); UnivPowerSeries s = this; String var = ring.var; //System.out.println("cache = " + s.coeffCache); for (int i = 0; i < truncate; i++) { C c = s.coefficient(i); int si = c.signum(); if (si != 0) { if (si > 0) { if (sb.length() > 0) { sb.append(" + "); } } else { c = c.negate(); sb.append(" - "); } if (!c.isONE() || i == 0) { if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append("{ "); } sb.append(c.toScript()); if (c instanceof GenPolynomial || c instanceof AlgebraicNumber) { sb.append(" }"); } if (i > 0) { sb.append(" * "); } } if (i == 0) { //skip; sb.append(" "); } else if (i == 1) { sb.append(var); } else { sb.append(var + "**" + i); } //sb.append(c.toString() + ", "); } //System.out.println("cache = " + s.coeffCache); } if (sb.length() == 0) { sb.append("0"); } // sb.append("," + truncate + ""); return sb.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Get coefficient. * @param index number of requested coefficient. * @return coefficient at index. */ public C coefficient(int index) { if (index < 0) { throw new IndexOutOfBoundsException("negative index not allowed"); } //System.out.println("cache = " + coeffCache); return lazyCoeffs.get(index); } /** * Get a GenPolynomial<C> from this. * @return a GenPolynomial<C> from this up to truncate parts. */ public GenPolynomial asPolynomial() { GenPolynomial p = ring.polyRing().getZERO(); for (int i = 0; i < truncate; i++) { C c = coefficient(i); ExpVector e = ExpVector.create(1, 0, i); p = p.sum(c, e); } return p; } /** * Get a GenVector<C> from this. * @return a GenVector<C> from this up to truncate parts. */ public GenVector asVector() { GenVectorModul vr = new GenVectorModul(ring.coFac, truncate); List v = new ArrayList<>(truncate); for (int i = 0; i < truncate; i++) { C c = coefficient(i); v.add(c); } GenVector vv = new GenVector(vr,v); return vv; } /** * Leading base coefficient. * @return first coefficient. */ public C leadingCoefficient() { return coefficient(0); } /** * Reductum. * @return this - leading monomial. */ public UnivPowerSeries reductum() { final int m = order(); //System.out.println("order = " + m); return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { if (m == i) { return ring.coFac.getZERO(); } else { return coefficient(i); } } }); } /** * Prepend a new leading coefficient. * @param h new coefficient. * @return new power series. */ public UnivPowerSeries prepend(final C h) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { if (i == 0) { return h; } return coefficient(i - 1); } }); } /** * Shift coefficients. * @param k shift index. * @return new power series with coefficient(i) = old.coefficient(i-k). */ public UnivPowerSeries shift(final int k) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { if (i - k < 0) { return ring.coFac.getZERO(); } return coefficient(i - k); } }); } /** * Select coefficients. * @param sel selector functor. * @return new power series with selected coefficients. */ public UnivPowerSeries select(final Selector sel) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { C c = coefficient(i); if (sel.select(c)) { return c; } return ring.coFac.getZERO(); } }); } /** * Shift select coefficients. Not selected coefficients are removed from the * result series. * @param sel selector functor. * @return new power series with shifted selected coefficients. */ public UnivPowerSeries shiftSelect(final Selector sel) { return new UnivPowerSeries(ring, new Coefficients() { int pos = 0; @Override public C generate(int i) { C c; if (i > 0) { c = get(i - 1); // ensure coeffs are all generated } do { c = coefficient(pos++); } while (!sel.select(c)); return c; } }); } /** * Map a unary function to this power series. * @param f evaluation functor. * @return new power series with coefficients f(this(i)). */ public UnivPowerSeries map(final UnaryFunctor f) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { return f.eval(coefficient(i)); } }); } /** * Map a binary function to this and another power series. * @param f evaluation functor with coefficients f(this(i),other(i)). * @param ps other power series. * @return new power series. */ public > UnivPowerSeries zip(final BinaryFunctor f, final UnivPowerSeries ps) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { return f.eval(coefficient(i), ps.coefficient(i)); } }); } /** * Sum of two power series. * @param ps other power series. * @return this + ps. */ public UnivPowerSeries sum(UnivPowerSeries ps) { return zip(new Sum(), ps); } /** * Subtraction of two power series. * @param ps other power series. * @return this - ps. */ public UnivPowerSeries subtract(UnivPowerSeries ps) { return zip(new Subtract(), ps); } /** * Multiply by coefficient. * @param c coefficient. * @return this * c. */ public UnivPowerSeries multiply(C c) { return map(new Multiply(c)); } /** * Monic. * @return 1/orderCoeff() * this. */ public UnivPowerSeries monic() { int i = order(); C a = coefficient(i); if (a.isONE()) { return this; } if (a.isZERO()) { // sic return this; } final C b = a.inverse(); return map(new UnaryFunctor() { @Override public C eval(C c) { return b.multiply(c); } }); } /** * Negate. * @return - this. */ public UnivPowerSeries negate() { return map(new Negate()); } /** * Absolute value. * @return abs(this). */ public UnivPowerSeries abs() { if (signum() < 0) { return negate(); } return this; } /** * Evaluate at given point. * @return ps(c). */ public C evaluate(C e) { C v = coefficient(0); C p = e; for (int i = 1; i < truncate; i++) { C c = coefficient(i).multiply(p); v = v.sum(c); p = p.multiply(e); } return v; } /** * Order. * @return index of first non zero coefficient. */ public int order() { if (order < 0) { // compute it for (int i = 0; i < truncate; i++) { if (!coefficient(i).isZERO()) { order = i; return order; } } order = truncate/* + 1*/; } return order; } /** * Truncate. * @return truncate index of power series. */ public int truncate() { return truncate; } /** * Set truncate. * @param t new truncate index. * @return old truncate index of power series. */ public int setTruncate(int t) { if (t < 0) { throw new IllegalArgumentException("negative truncate not allowed"); } int ot = truncate; truncate = t; return ot; } /** * Signum. * @return sign of first non zero coefficient. */ public int signum() { return coefficient(order()).signum(); } /** * Compare to. Note: compare only up to truncate. * @return sign of first non zero coefficient of this-ps. */ @Override public int compareTo(UnivPowerSeries ps) { int m = order(); int n = ps.order(); int pos = (m <= n) ? m : n; int s = 0; do { s = coefficient(pos).compareTo(ps.coefficient(pos)); pos++; } while (s == 0 && pos < truncate); return s; } /** * Is power series zero. Note: compare only up to truncate. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return (compareTo(ring.ZERO) == 0); } /** * Is power series one. Note: compare only up to truncate. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return (compareTo(ring.ONE) == 0); } /** * Comparison with any other object. Note: compare only up to * truncate. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { UnivPowerSeries a = null; try { a = (UnivPowerSeries) B; } catch (ClassCastException ignored) { } if (a == null) { return false; } return compareTo(a) == 0; } /** * Hash code for this polynomial. Note: only up to truncate. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = 0; //h = ( ring.hashCode() << 23 ); //h += val.hashCode(); for (int i = 0; i < truncate; i++) { C c = coefficient(i); if (!c.isZERO()) { h += i; h = Math.abs(h << 1); } h += c.hashCode(); h = Math.abs(h); // << 3); } return h; } /** * Is unit. * @return true, if this power series is invertible, else false. */ public boolean isUnit() { return leadingCoefficient().isUnit(); } /** * Multiply by another power series. * @return this * ps. */ public UnivPowerSeries multiply(final UnivPowerSeries ps) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { C c = null; //fac.getZERO(); for (int k = 0; k <= i; k++) { C m = coefficient(k).multiply(ps.coefficient(i - k)); if (c == null) { c = m; } else { c = c.sum(m); } } return c; } }); } /** * Inverse power series. * @return ps with this * ps = 1. */ public UnivPowerSeries inverse() { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { C d = leadingCoefficient().inverse(); // may fail if (i == 0) { return d; } C c = null; //fac.getZERO(); for (int k = 0; k < i; k++) { C m = get(k).multiply(coefficient(i - k)); if (c == null) { c = m; } else { c = c.sum(m); } } c = c.multiply(d.negate()); return c; } }); } /** * Divide by another power series. * @return this / ps. */ public UnivPowerSeries divide(UnivPowerSeries ps) { if (ps.isUnit()) { return multiply(ps.inverse()); } int m = order(); int n = ps.order(); if (m < n) { return ring.getZERO(); } if (!ps.coefficient(n).isUnit()) { throw new ArithmeticException( "division by non unit coefficient " + ps.coefficient(n) + ", n = " + n); } // now m >= n UnivPowerSeries st, sps, q, sq; if (m == 0) { st = this; } else { st = this.shift(-m); } if (n == 0) { sps = ps; } else { sps = ps.shift(-n); } q = st.multiply(sps.inverse()); if (m == n) { sq = q; } else { sq = q.shift(m - n); } return sq; } /** * Power series remainder. * @param ps nonzero power series with invertible leading coefficient. * @return remainder with this = quotient * ps + remainder. */ public UnivPowerSeries remainder(UnivPowerSeries ps) { int m = order(); int n = ps.order(); if (m >= n) { return ring.getZERO(); } return this; } /** * Quotient and remainder by division of this by S. * @param S a UnivPowerSeries * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public UnivPowerSeries[] quotientRemainder(UnivPowerSeries S) { return new UnivPowerSeries[] { divide(S), remainder(S) }; } /** * Differentiate. * @return differentiate(this). */ public UnivPowerSeries differentiate() { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { C v = coefficient(i + 1); v = v.multiply(ring.coFac.fromInteger(i + 1)); return v; } }); } /** * Integrate with given constant. * @param c integration constant. * @return integrate(this). */ public UnivPowerSeries integrate(final C c) { return new UnivPowerSeries(ring, new Coefficients() { @Override public C generate(int i) { if (i == 0) { return c; } C v = coefficient(i - 1); v = v.divide(ring.coFac.fromInteger(i)); return v; } }); } /** * Power series greatest common divisor. * @param ps power series. * @return gcd(this,ps). */ public UnivPowerSeries gcd(UnivPowerSeries ps) { if (ps.isZERO()) { return this; } if (this.isZERO()) { return ps; } int m = order(); int n = ps.order(); int ll = (m < n) ? m : n; return ring.getONE().shift(ll); } /** * Power series extended greatest common divisor. Note: not * implemented. * @param S power series. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ //SuppressWarnings("unchecked") public UnivPowerSeries[] egcd(UnivPowerSeries S) { throw new UnsupportedOperationException("egcd for power series not implemented"); } } /* arithmetic method functors */ /** * Internal summation functor. */ class Sum> implements BinaryFunctor { public C eval(C c1, C c2) { return c1.sum(c2); } } /** * Internal subtraction functor. */ class Subtract> implements BinaryFunctor { public C eval(C c1, C c2) { return c1.subtract(c2); } } /** * Internal scalar multiplication functor. */ class Multiply> implements UnaryFunctor { C x; public Multiply(C x) { this.x = x; } public C eval(C c) { return c.multiply(x); } } /** * Internal negation functor. */ class Negate> implements UnaryFunctor { public C eval(C c) { return c.negate(); } } /* only for sequential access: class Abs> implements UnaryFunctor { int sign = 0; public C eval(C c) { int s = c.signum(); if ( s == 0 ) { return c; } if ( sign > 0 ) { return c; } else if ( sign < 0 ) { return c.negate(); } // first non zero coefficient: sign = s; if ( s > 0 ) { return c; } return c.negate(); } } */ java-algebra-system-2.7.200/src/edu/jas/ps/UnivPowerSeriesMap.java000066400000000000000000000007041445075545500247140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import edu.jas.structure.RingElem; /** * Univariate power series map interface. Defines method for mapping of power * series. * @param ring element type * @author Heinz Kredel */ public interface UnivPowerSeriesMap> { /** * Map. * @return new power series resulting from mapping elements of ps. */ public UnivPowerSeries map(UnivPowerSeries ps); } java-algebra-system-2.7.200/src/edu/jas/ps/UnivPowerSeriesRing.java000066400000000000000000000374331445075545500251070ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Random; import java.util.function.IntFunction; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.vector.GenVector; /** * Univariate power series ring implementation. Uses lazy evaluated generating * function for coefficients. * @param ring element type * @author Heinz Kredel */ public class UnivPowerSeriesRing> implements RingFactory> { /** * A default random sequence generator. */ protected final static Random random = new Random(); /** * Default truncate. */ public final static int DEFAULT_TRUNCATE = 11; /** * Truncate. */ int truncate; /** * Default variable name. */ public final static String DEFAULT_NAME = "x"; /** * Variable name. */ String var; /** * Coefficient ring factory. */ public final RingFactory coFac; /** * The constant power series 1 for this ring. */ public final UnivPowerSeries ONE; /** * The constant power series 0 for this ring. */ public final UnivPowerSeries ZERO; /** * No argument constructor. */ @SuppressWarnings("unused") private UnivPowerSeriesRing() { throw new IllegalArgumentException("do not use no-argument constructor"); } /** * Constructor. * @param coFac coefficient ring factory. */ public UnivPowerSeriesRing(RingFactory coFac) { this(coFac, DEFAULT_TRUNCATE, DEFAULT_NAME); } /** * Constructor. * @param coFac coefficient ring factory. * @param truncate index of truncation. */ public UnivPowerSeriesRing(RingFactory coFac, int truncate) { this(coFac, truncate, DEFAULT_NAME); } /** * Constructor. * @param coFac coefficient ring factory. * @param name of the variable. */ public UnivPowerSeriesRing(RingFactory coFac, String name) { this(coFac, DEFAULT_TRUNCATE, name); } /** * Constructor. * @param pfac polynomial ring factory. */ public UnivPowerSeriesRing(GenPolynomialRing pfac) { this(pfac.coFac, DEFAULT_TRUNCATE, pfac.getVars()[0]); } /** * Constructor. * @param cofac coefficient ring factory. * @param truncate index of truncation. * @param name of the variable. */ public UnivPowerSeriesRing(RingFactory cofac, int truncate, String name) { this.coFac = cofac; this.truncate = truncate; this.var = name; this.ONE = new UnivPowerSeries(this, new Coefficients() { @Override public C generate(int i) { if (i == 0) { return coFac.getONE(); } return coFac.getZERO(); } }); this.ZERO = new UnivPowerSeries(this, new Coefficients() { @Override public C generate(int i) { return coFac.getZERO(); } }); } /** * Fixed point construction. * @param map a mapping of power series. * @return fix point wrt map. */ // Cannot be a static method because a power series ring is required. public UnivPowerSeries fixPoint(UnivPowerSeriesMap map) { UnivPowerSeries ps1 = new UnivPowerSeries(this); UnivPowerSeries ps2 = map.map(ps1); ps1.lazyCoeffs = ps2.lazyCoeffs; return ps2; } /** * To String. * @return string representation of this. */ @Override public String toString() { StringBuffer sb = new StringBuffer(); String scf = coFac.getClass().getSimpleName(); sb.append(scf + "((" + var + "))"); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("PS("); String f = null; try { f = ((RingElem) coFac).toScriptFactory(); // sic } catch (Exception e) { f = coFac.toScript(); } s.append(f + ",\"" + var + "\"," + truncate + ")"); return s.toString(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { UnivPowerSeriesRing a = null; try { a = (UnivPowerSeriesRing) B; } catch (ClassCastException ignored) { } if (a == null) { return false; } if (!coFac.equals(a.coFac)) { return false; } if (!var.equals(a.var)) { return false; } return true; } /** * Hash code for this . * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = coFac.hashCode(); h += (var.hashCode() << 27); h += truncate; return h; } /** * Get the zero element. * @return 0 as UnivPowerSeries. */ public UnivPowerSeries getZERO() { return ZERO; } /** * Get the one element. * @return 1 as UnivPowerSeries. */ public UnivPowerSeries getONE() { return ONE; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = coFac.generators(); List> gens = new ArrayList>(rgens.size()); for (final C cg : rgens) { UnivPowerSeries g = new UnivPowerSeries(this, new Coefficients() { @Override public C generate(int i) { if (i == 0) { return cg; } return coFac.getZERO(); } }); gens.add(g); } gens.add(ONE.shift(1)); return gens; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return false; } /** * Get the power series of the exponential function. * @return exp(x) as UnivPowerSeries. */ public UnivPowerSeries getEXP() { return fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries e) { return e.integrate(coFac.getONE()); } }); } /** * Get the power series of the sinus function. * @return sin(x) as UnivPowerSeries. */ public UnivPowerSeries getSIN() { return fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries s) { return s.negate().integrate(coFac.getONE()).integrate(coFac.getZERO()); } }); } /** * Get the power series of the cosine function. * @return cos(x) as UnivPowerSeries. */ public UnivPowerSeries getCOS() { return fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries c) { return c.negate().integrate(coFac.getZERO()).integrate(coFac.getONE()); } }); } /** * Get the power series of the tangens function. * @return tan(x) as UnivPowerSeries. */ public UnivPowerSeries getTAN() { return fixPoint(new UnivPowerSeriesMap() { public UnivPowerSeries map(UnivPowerSeries t) { return t.multiply(t).sum(getONE()).integrate(coFac.getZERO()); } }); } /** * Solve an ordinary differential equation. y' = f(y) with y(0) = c. * @param f a UnivPowerSeries. * @param c integration constant. * @return f.integrate(c). */ public UnivPowerSeries solveODE(final UnivPowerSeries f, final C c) { return f.integrate(c); } /** * Is commutative. * @return true, if this ring is commutative, else false. */ public boolean isCommutative() { return coFac.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return coFac.isAssociative(); } /** * Query if this ring is a field. * @return false. */ public boolean isField() { return false; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Get a (constant) UnivPowerSeries<C> from a long value. * @param a long. * @return a UnivPowerSeries<C>. */ public UnivPowerSeries fromInteger(long a) { return ONE.multiply(coFac.fromInteger(a)); } /** * Get a (constant) UnivPowerSeries<C> from a java.math.BigInteger. * @param a BigInteger. * @return a UnivPowerSeries<C>. */ public UnivPowerSeries fromInteger(java.math.BigInteger a) { return ONE.multiply(coFac.fromInteger(a)); } /** * Get the corresponding GenPolynomialRing<C>. * @return GenPolynomialRing<C>. */ public GenPolynomialRing polyRing() { return new GenPolynomialRing(coFac, 1, new String[] { var }); } /** * Get a UnivPowerSeries<C> from a GenPolynomial<C>. * @param a GenPolynomial<C>. * @return a UnivPowerSeries<C>. */ public UnivPowerSeries fromPolynomial(GenPolynomial a) { if (a == null || a.isZERO()) { return ZERO; } if (a.isONE()) { return ONE; } if (a.ring.nvar != 1) { throw new IllegalArgumentException("only for univariate polynomials"); } HashMap cache = new HashMap(a.length()); for (Monomial m : a) { long e = m.exponent().getVal(0); cache.put((int) e, m.coefficient()); } return new UnivPowerSeries(this, new Coefficients(cache) { @Override public C generate(int i) { // cached coefficients returned by get return coFac.getZERO(); } }); } /** * Get a UnivPowerSeries<C> from a GenVector<C>. * @param a GenVector<C>. * @return a UnivPowerSeries<C>. */ public UnivPowerSeries fromVector(GenVector a) { if (a == null || a.isZERO()) { return ZERO; } HashMap cache = new HashMap(a.val.size()); int i = 0; for (C m : a.val) { cache.put(i++, m); } return new UnivPowerSeries(this, new Coefficients(cache) { @Override public C generate(int i) { // cached coefficients returned by get return coFac.getZERO(); } }); } /** * Generate a random power series with k = 5, d = 0.7. * @return a random power series. */ public UnivPowerSeries random() { return random(5, 0.7f, random); } /** * Generate a random power series with d = 0.7. * @param k bitsize of random coefficients. * @return a random power series. */ public UnivPowerSeries random(int k) { return random(k, 0.7f, random); } /** * Generate a random power series with d = 0.7. * @param k bit-size of random coefficients. * @param rnd is a source for random bits. * @return a random power series. */ public UnivPowerSeries random(int k, Random rnd) { return random(k, 0.7f, rnd); } /** * Generate a random power series. * @param k bit-size of random coefficients. * @param d density of non-zero coefficients. * @return a random power series. */ public UnivPowerSeries random(int k, float d) { return random(k, d, random); } /** * Generate a random power series. * @param k bit-size of random coefficients. * @param d density of non-zero coefficients. * @param rnd is a source for random bits. * @return a random power series. */ public UnivPowerSeries random(final int k, final float d, final Random rnd) { return new UnivPowerSeries(this, new Coefficients() { @Override public C generate(int i) { // cached coefficients returned by get C c; float f = rnd.nextFloat(); if (f < d) { c = coFac.random(k, rnd); } else { c = coFac.getZERO(); } return c; } }); } /** * Generate a power series via lambda expression. * @param gener lambda expression. * @return a generated power series. */ public UnivPowerSeries generate(final IntFunction gener) { return new UnivPowerSeries(this, new Coefficients() { @Override public C generate(int i) { // cached coefficients returned by get C c = gener.apply(i); return c; } }); } /** * Copy power series. * @param c a power series. * @return a copy of c. */ public UnivPowerSeries copy(UnivPowerSeries c) { return new UnivPowerSeries(this, c.lazyCoeffs); } /** * Parse a power series. Note: not implemented. * @param s String. * @return power series from s. */ public UnivPowerSeries parse(String s) { throw new UnsupportedOperationException("parse for power series not implemented"); } /** * Parse a power series. Note: not implemented. * @param r Reader. * @return next power series from r. */ public UnivPowerSeries parse(Reader r) { throw new UnsupportedOperationException("parse for power series not implemented"); } /** * Taylor power series. * @param f function. * @param a expansion point. * @return Taylor series of f. */ public UnivPowerSeries seriesOfTaylor(final TaylorFunction f, final C a) { return new UnivPowerSeries(this, new Coefficients() { TaylorFunction der = f; long k = 0; long n = 1; @Override public C generate(int i) { C c; if (i == 0) { c = der.evaluate(a); der = der.derivative(); return c; } if (i > 0) { c = get(i - 1); // ensure deriv is updated } k++; n *= k; c = der.evaluate(a); //System.out.println("n = " + n + ", i = " +i); c = c.divide(coFac.fromInteger(n)); der = der.derivative(); return c; } }); } } java-algebra-system-2.7.200/src/edu/jas/ps/package.html000066400000000000000000000022371445075545500225660ustar00rootroot00000000000000 Generic coefficients power series package

Generic coefficients power series package.

This package contains classes for univariate and multivariate power series arithmetic in classes UnivPowerSeries, UnivPowerSeriesRing, MultiVarPowerSeries and MultiVarPowerSeriesRing over coefficient rings which implement the RingElem interface. It contains also classes for reduction (with Mora's tangent cone algorithm) and standard base computations. Currently the term order is fixed to the order defined by the iterator over exponent vectors ExpVectorIterator.


Heinz Kredel

Last modified: Sat Sep 18 14:15:26 CEST 2010

$Id$

java-algebra-system-2.7.200/src/edu/jas/root/000077500000000000000000000000001445075545500206425ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/root/AlgebraicRoots.java000066400000000000000000000126721445075545500244150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.List; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.Complex; import edu.jas.structure.GcdRingElem; /** * Container for the real and complex algebraic roots of a univariate * polynomial. * @param coefficient type. * @author Heinz Kredel */ public class AlgebraicRoots & Rational> implements Serializable { /** * Univariate polynomial. */ public final GenPolynomial p; /** * Real algebraic roots. */ public final List> real; /** * Univariate polynomial with complex coefficients equivalent to p. */ public final GenPolynomial> cp; /** * Complex algebraic roots. */ public final List> complex; /** * Constructor not for use. */ protected AlgebraicRoots() { throw new IllegalArgumentException("do not use this constructor"); } /** * Constructor. * @param p univariate polynomial * @param cp univariate polynomial with compelx coefficients * @param r list of real algebraic roots * @param c list of complex algebraic roots */ public AlgebraicRoots(GenPolynomial p, GenPolynomial> cp, List> r, List> c) { this.p = p; this.cp = cp; this.real = r; this.complex = c; } /** * String representation of AlgebraicRoots. * @see java.lang.Object#toString() */ @Override public String toString() { return "[" + p + ", real=" + real + ", complex=" + complex + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this roots. */ public String toScript() { // Python case StringBuffer sb = new StringBuffer("["); sb.append(p.toScript()); //sb.append(", "); //sb.append(cp.toScript()); if (!real.isEmpty()) { sb.append(", real=["); boolean first = true; for (RealAlgebraicNumber r : real) { if (first) { first = false; } else { sb.append(", "); } sb.append(r.ring.root.toScript()); } sb.append("]"); } if (!complex.isEmpty()) { sb.append(", complex=["); boolean first = true; for (ComplexAlgebraicNumber c : complex) { if (first) { first = false; } else { sb.append(", "); } sb.append(c.ring.root.toScript()); } sb.append("]"); } sb.append("]"); return sb.toString(); } /** * Get a decimal number scripting compatible string representation. * @return decimal number script compatible representation for this roots. */ public String toDecimalScript() { // Python case StringBuffer sb = new StringBuffer("["); sb.append(p.toScript()); //sb.append(", "); //sb.append(cp.toScript()); if (!real.isEmpty()) { sb.append(", real=["); boolean first = true; for (RealAlgebraicNumber r : real) { if (first) { first = false; } else { sb.append(", "); } r.ring.refineRoot(); sb.append(r.ring.root.toDecimal().toScript()); } sb.append("]"); } if (!complex.isEmpty()) { sb.append(", complex=["); boolean first = true; for (ComplexAlgebraicNumber c : complex) { if (first) { first = false; } else { sb.append(", "); } c.ring.refineRoot(); sb.append(c.ring.root.getDecimalCenter().toScript()); } sb.append("]"); } sb.append("]"); return sb.toString(); } /** * Copy this. * @return a copy of this. */ public AlgebraicRoots copy() { return new AlgebraicRoots(p, cp, real, complex); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof AlgebraicRoots)) { return false; } AlgebraicRoots a = null; try { a = (AlgebraicRoots) b; } catch (ClassCastException e) { return false; } return p.equals(a.p) && real.equals(a.real) && complex.equals(a.complex); } /** * Hash code for this AlgebraicRoots. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (161 * p.hashCode() + 37) * real.hashCode() + complex.hashCode(); } /** * Algebraic number ring. * @return algebraic ring of roots. */ public AlgebraicNumberRing getAlgebraicRing() { AlgebraicNumberRing anr = new AlgebraicNumberRing(p); return anr; } } java-algebra-system-2.7.200/src/edu/jas/root/Boundary.java000066400000000000000000000125541445075545500232770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; /** * Boundary determined by a rectangle and a polynomial. * * For a given complex polynomial A a closed path through the corners of the * given rectangle is constructed. The path is represented by four polynomials, * one for each side of the rectangle. For a real t in [0,1] the i-th polynomial * describes the path of A from corner[i] to corner[i+1]. In particular * polys[i](0) = A(corner[i]) and polys[i](1) = A(corner[i+1]), with corner[4] = * corner[0]. If A would be zero on a point of the path, an * InvalidBoundaryException is thrown. * @param coefficient type. * @author Heinz Kredel */ public class Boundary & Rational> implements Serializable { /** * Rectangle. */ public final Rectangle rect; /** * Polynomial. */ public final GenPolynomial> A; /** * Boundary polynomials. */ public final GenPolynomial>[] polys; /** * Factory for real polynomials. */ GenPolynomialRing rfac; /** * Constructor. * @param r rectangle of of corners. * @param p non constant polynomial. */ @SuppressWarnings("unchecked") public Boundary(Rectangle r, GenPolynomial> p) throws InvalidBoundaryException { if (p.isConstant() || p.isZERO()) { throw new InvalidBoundaryException("p is constant or 0 " + p); } rect = r; A = p; GreatestCommonDivisor> ufd = GCDFactory.> getImplementation(A.ring.coFac); polys = (GenPolynomial>[]) new GenPolynomial[5]; Complex[] corner = rect.corners; for (int i = 0; i < 4; i++) { Complex t = corner[i + 1].subtract(corner[i]); GenPolynomial> tp = A.ring.univariate(0, 1L).multiply(t); //System.out.println("t = " + t); GenPolynomial> pc = PolyUtil.> seriesOfTaylor(A, corner[i]); pc = PolyUtil.> substituteUnivariate(pc, tp); GenPolynomial> gcd = ufd.gcd(A, pc); if (!gcd.isONE()) { //System.out.println("A = " + A); //System.out.println("PC["+i+"] = " + pc); //System.out.println("gcd = " + gcd); throw new InvalidBoundaryException("A has a zero on rectangle " + rect + ", A = " + A); } polys[i] = pc; } polys[4] = polys[0]; // setup factory for real and imaginary parts ComplexRing cr = (ComplexRing) A.ring.coFac; RingFactory cf = cr.ring; rfac = new GenPolynomialRing(cf, A.ring); } /** * Constructor. * @param r rectangle of of corners. * @param p polynomial. * @param b boundary polynomials. */ protected Boundary(Rectangle r, GenPolynomial> p, GenPolynomial>[] b) { rect = r; A = p; polys = b; // setup factory for real and imaginary parts ComplexRing cr = (ComplexRing) A.ring.coFac; RingFactory cf = cr.ring; rfac = new GenPolynomialRing(cf, A.ring); } /** * String representation of Boundary. * @see java.lang.Object#toString() */ @Override public String toString() { return rect.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Boundary. */ public String toScript() { // Python case return rect.toScript(); } /** * Get real part for polynomial i. * @param i index of polynomial. * @return real part for polynomial i. */ public GenPolynomial getRealPart(int i) { GenPolynomial f = PolyUtil. realPartFromComplex(rfac, polys[i]); return f; } /** * Get imaginary part for polynomial i. * @param i index of polynomial. * @return imaginary part for polynomial i. */ public GenPolynomial getImagPart(int i) { GenPolynomial g = PolyUtil. imaginaryPartFromComplex(rfac, polys[i]); return g; } /** * Copy this. * @return a copy of this. */ public Boundary copy() { return new Boundary(rect, A, polys); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { Boundary a = null; try { a = (Boundary) b; } catch (ClassCastException e) { } if (a == null) { return false; } return rect.equals(a.rect) && A.equals(a.A); } /** * Hash code for this Rectangle. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hc = 0; hc += 37 * rect.hashCode(); return 37 * hc + A.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/root/ComplexAlgebraicNumber.java000066400000000000000000000313731445075545500260660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.kern.PrettyPrint; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Complex algebraic number class based on AlgebraicNumber. Objects of this * class are immutable. * @author Heinz Kredel */ public class ComplexAlgebraicNumber & Rational> /*extends AlgebraicNumber*/ implements GcdRingElem> { /** * Representing AlgebraicNumber. */ public final AlgebraicNumber> number; /** * Ring part of the data structure. */ public final ComplexAlgebraicRing ring; /** * The constructor creates a ComplexAlgebraicNumber object from * ComplexAlgebraicRing modul and a GenPolynomial value. * @param r ring ComplexAlgebraicRing. * @param a value GenPolynomial. */ public ComplexAlgebraicNumber(ComplexAlgebraicRing r, GenPolynomial> a) { number = new AlgebraicNumber>(r.algebraic, a); ring = r; } /** * The constructor creates a ComplexAlgebraicNumber object from * ComplexAlgebraicRing modul and a AlgebraicNumber value. * @param r ring ComplexAlgebraicRing. * @param a value AlgebraicNumber. */ public ComplexAlgebraicNumber(ComplexAlgebraicRing r, AlgebraicNumber> a) { number = a; ring = r; } /** * The constructor creates a ComplexAlgebraicNumber object from a * GenPolynomial object module. * @param r ring ComplexAlgebraicRing. */ public ComplexAlgebraicNumber(ComplexAlgebraicRing r) { this(r, r.algebraic.getZERO()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public ComplexAlgebraicRing factory() { return ring; } /** * Copy this. * @see edu.jas.structure.Element#copy() */ @Override public ComplexAlgebraicNumber copy() { return new ComplexAlgebraicNumber(ring, number); } /** * Is ComplexAlgebraicNumber zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return number.isZERO(); } /** * Is ComplexAlgebraicNumber one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return number.isONE(); } /** * Is ComplexAlgebraicNumber unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return number.isUnit(); } /** * Is ComplexAlgebraicNumber a root of unity. * @return true if |this**i| == 1, for some 0 < i ≤ deg(modul), else * false. */ public boolean isRootOfUnity() { return number.isRootOfUnity(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return "{ " + number.toString() + " }"; } return "Complex" + number.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return number.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * ComplexAlgebraicNumber comparison. * @param b ComplexAlgebraicNumber. * @return sign(this-b). */ @Override public int compareTo(ComplexAlgebraicNumber b) { int s = 0; if (number.ring != b.number.ring) { // avoid compareTo if possible s = number.ring.modul.compareTo(b.number.ring.modul); System.out.println("s_mod = " + s); } if (s != 0) { return s; } s = number.compareTo(b.number); // TODO //System.out.println("s_real = " + s); return s; } /** * ComplexAlgebraicNumber comparison. * @param b AlgebraicNumber. * @return polynomial sign(this-b). */ public int compareTo(AlgebraicNumber> b) { int s = number.compareTo(b); //System.out.println("s_algeb = " + s); return s; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof ComplexAlgebraicNumber)) { return false; } ComplexAlgebraicNumber a = (ComplexAlgebraicNumber) b; if (!ring.equals(a.ring)) { return false; } return number.equals(a.number); } /** * Hash code for this ComplexAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * number.val.hashCode() + ring.hashCode(); } /** * ComplexAlgebraicNumber absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public ComplexAlgebraicNumber abs() { if (this.signum() < 0) { return new ComplexAlgebraicNumber(ring, number.negate()); } return this; } /** * ComplexAlgebraicNumber summation. * @param S ComplexAlgebraicNumber. * @return this+S. */ public ComplexAlgebraicNumber sum(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber(ring, number.sum(S.number)); } /** * ComplexAlgebraicNumber summation. * @param c complex polynomial. * @return this+c. */ public ComplexAlgebraicNumber sum(GenPolynomial> c) { return new ComplexAlgebraicNumber(ring, number.sum(c)); } /** * ComplexAlgebraicNumber summation. * @param c algebraic number. * @return this+c. */ public ComplexAlgebraicNumber sum(AlgebraicNumber> c) { return new ComplexAlgebraicNumber(ring, number.sum(c)); } /** * ComplexAlgebraicNumber summation. * @param c coefficient. * @return this+c. */ public ComplexAlgebraicNumber sum(Complex c) { return new ComplexAlgebraicNumber(ring, number.sum(c)); } /** * ComplexAlgebraicNumber negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public ComplexAlgebraicNumber negate() { return new ComplexAlgebraicNumber(ring, number.negate()); } /** * ComplexAlgebraicNumber subtraction. * @param S ComplexAlgebraicNumber. * @return this-S. */ public ComplexAlgebraicNumber subtract(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber(ring, number.subtract(S.number)); } /** * ComplexAlgebraicNumber division. * @param S ComplexAlgebraicNumber. * @return this/S. */ public ComplexAlgebraicNumber divide(ComplexAlgebraicNumber S) { return multiply(S.inverse()); } /** * ComplexAlgebraicNumber inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S = 1/this if defined. */ public ComplexAlgebraicNumber inverse() { return new ComplexAlgebraicNumber(ring, number.inverse()); } /** * ComplexAlgebraicNumber remainder. * @param S ComplexAlgebraicNumber. * @return this - (this/S)*S. */ public ComplexAlgebraicNumber remainder(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber(ring, number.remainder(S.number)); } /** * Quotient and remainder by division of this by S. * @param S a ComplexAlgebraicNumber * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public ComplexAlgebraicNumber[] quotientRemainder(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber[] { divide(S), remainder(S) }; } /** * ComplexAlgebraicNumber multiplication. * @param S ComplexAlgebraicNumber. * @return this*S. */ public ComplexAlgebraicNumber multiply(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber(ring, number.multiply(S.number)); } /** * ComplexAlgebraicNumber multiplication. * @param c coefficient. * @return this*c. */ public ComplexAlgebraicNumber multiply(Complex c) { return new ComplexAlgebraicNumber(ring, number.multiply(c)); } /** * ComplexAlgebraicNumber multiplication. * @param c polynomial. * @return this*c. */ public ComplexAlgebraicNumber multiply(GenPolynomial> c) { return new ComplexAlgebraicNumber(ring, number.multiply(c)); } /** * ComplexAlgebraicNumber monic. * @return this with monic value part. */ public ComplexAlgebraicNumber monic() { return new ComplexAlgebraicNumber(ring, number.monic()); } /** * ComplexAlgebraicNumber greatest common divisor. * @param S ComplexAlgebraicNumber. * @return gcd(this,S). */ public ComplexAlgebraicNumber gcd(ComplexAlgebraicNumber S) { return new ComplexAlgebraicNumber(ring, number.gcd(S.number)); } /** * ComplexAlgebraicNumber extended greatest common divisor. * @param S ComplexAlgebraicNumber. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public ComplexAlgebraicNumber[] egcd(ComplexAlgebraicNumber S) { AlgebraicNumber>[] aret = number.egcd(S.number); ComplexAlgebraicNumber[] ret = new ComplexAlgebraicNumber[3]; ret[0] = new ComplexAlgebraicNumber(ring, aret[0]); ret[1] = new ComplexAlgebraicNumber(ring, aret[1]); ret[2] = new ComplexAlgebraicNumber(ring, aret[2]); return ret; } /** * ComplexAlgebraicNumber signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { ring.ensureEngine(); try { Rectangle v = ring.engine.invariantRectangle(ring.root, ring.algebraic.modul, number.val); ring.setRoot(v); Complex c = v.getCenter(); return c.signum(); } catch (InvalidBoundaryException e) { // should not happen e.printStackTrace(); throw new RuntimeException(e); } } /** * ComplexAlgebraicNumber magnitude. * @return |this| as complex rational number. */ public Complex magnitude() { ring.ensureEngine(); try { Rectangle v = ring.engine.invariantMagnitudeRectangle(ring.root, ring.algebraic.modul, number.val, ring.getEps()); ring.setRoot(v); //System.out.println("new v = " + v); Complex ev = ring.engine.complexRectangleMagnitude(v, ring.algebraic.modul, number.val); //, ring.eps); BigRational er = ev.getRe().getRational(); BigRational ei = ev.getIm().getRational(); ComplexRing cr = new ComplexRing(er.factory()); return new Complex(cr, er, ei); } catch (InvalidBoundaryException e) { // should not happen e.printStackTrace(); throw new RuntimeException(e); } } /** * ComplexAlgebraicNumber magnitude. * @return |this| as complex big decimal. */ public Complex decimalMagnitude() { Complex cr = magnitude(); ComplexRing dr = new ComplexRing(BigDecimal.ZERO); return new Complex(dr, new BigDecimal(cr.getRe()), new BigDecimal(cr.getIm())); } } java-algebra-system-2.7.200/src/edu/jas/root/ComplexAlgebraicRing.java000066400000000000000000000255441445075545500255400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigRational; import edu.jas.arith.BigDecimal; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Complex algebraic number factory class based on AlgebraicNumberRing with * RingFactory interface. Objects of this class are immutable with the exception * of the isolating intervals. * @author Heinz Kredel */ public class ComplexAlgebraicRing & Rational> /*extends AlgebraicNumberRing*/ implements RingFactory> { private static final Logger logger = LogManager.getLogger(ComplexAlgebraicRing.class); /** * Representing AlgebraicNumberRing. */ public final AlgebraicNumberRing> algebraic; /** * Isolating rectangle for a complex root. Note: interval may shrink * eventually. */ /*package*/Rectangle root; /** * Epsilon of the isolating rectangle for a complex root. */ protected BigRational eps; /** * Precision of the isolating rectangle for a complex root. */ public static final int PRECISION = BigDecimal.DEFAULT_PRECISION; /** * Complex root computation engine. */ protected ComplexRootsSturm engine = null; /** * The constructor creates a ComplexAlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial<C>. * @param root isolating rectangle for a complex root. */ public ComplexAlgebraicRing(GenPolynomial> m, Rectangle root) { algebraic = new AlgebraicNumberRing>(m); this.root = root; if (m.ring.characteristic().signum() > 0) { throw new IllegalArgumentException("characteristic not zero"); } BigRational e = new BigRational(10L); //m.ring.coFac.fromInteger(10L).getRe(); e = e.power( - PRECISION/2 ); //Power.positivePower(e, PRECISION); eps = e; //BigRational.ONE; // initially ensureEngine(); } /** * The constructor creates a ComplexAlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial<C>. * @param root isolating rectangle for a complex root. * @param isField indicator if m is prime. */ public ComplexAlgebraicRing(GenPolynomial> m, Rectangle root, boolean isField) { this(m, root); setField(isField); } /** * Set a refined rectangle for the complex root. Note: rectangle may * shrink eventually. * @param v rectangle. */ public synchronized void setRoot(Rectangle v) { // assert v is contained in root assert root.contains(v) : "root contains v"; this.root = v; } /** * Get rectangle for the complex root. * @return v rectangle. */ public synchronized Rectangle getRoot() { return this.root; } /** * Get epsilon. * @return epsilon. */ public synchronized BigRational getEps() { return this.eps; } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(C e) { setEps(e.getRational()); } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(BigRational e) { this.eps = e; //algebraic.ring.coFac.parse(e.toString()).getRe(); } /** * Refine root. */ public synchronized void refineRoot() { refineRoot(eps); } /** * Ensure engine is initialized. */ public synchronized void ensureEngine() { if (engine == null) { engine = new ComplexRootsSturm(algebraic.ring.coFac); } } /** * Refine root. * @param e epsilon. */ public synchronized void refineRoot(BigRational e) { ensureEngine(); try { root = engine.complexRootRefinement(root, algebraic.modul, e); } catch (InvalidBoundaryException e1) { logger.warn("new eps not set: {}", e); //e1.printStackTrace(); return; // ignore new eps } this.eps = e; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return algebraic.isFinite(); } /** * Copy ComplexAlgebraicNumber element c. * @param c * @return a copy of c. */ public ComplexAlgebraicNumber copy(ComplexAlgebraicNumber c) { return new ComplexAlgebraicNumber(this, c.number); } /** * Get the zero element. * @return 0 as ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber getZERO() { return new ComplexAlgebraicNumber(this, algebraic.getZERO()); } /** * Get the one element. * @return 1 as ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber getONE() { return new ComplexAlgebraicNumber(this, algebraic.getONE()); } /** * Get the i element. * @return i as ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber getIMAG() { ComplexRing cr = (ComplexRing) algebraic.ring.coFac; Complex I = cr.getIMAG(); return new ComplexAlgebraicNumber(this, algebraic.getZERO().sum(I)); } /** * Get the generating element. * @return alpha as ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber getGenerator() { return new ComplexAlgebraicNumber(this, algebraic.getGenerator()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List>> agens = algebraic.generators(); List> gens = new ArrayList>(agens.size()); for (AlgebraicNumber> a : agens) { gens.add(getZERO().sum(a.getVal())); } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return algebraic.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return algebraic.isAssociative(); } /** * Query if this ring is a field. * @return true if algebraic is prime, else false. */ public boolean isField() { return algebraic.isField(); } /** * Assert that this ring is a field. * @param isField true if this ring is a field, else false. */ public void setField(boolean isField) { algebraic.setField(isField); } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return algebraic.characteristic(); } /** * Get a ComplexAlgebraicNumber element from a BigInteger value. * @param a BigInteger. * @return a ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber fromInteger(java.math.BigInteger a) { return new ComplexAlgebraicNumber(this, algebraic.fromInteger(a)); } /** * Get a ComplexAlgebraicNumber element from a long value. * @param a long. * @return a ComplexAlgebraicNumber. */ public ComplexAlgebraicNumber fromInteger(long a) { return new ComplexAlgebraicNumber(this, algebraic.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "ComplexAlgebraicRing[ " + algebraic.modul.toString() + " in " + root + " | isField=" + algebraic.isField() + " :: " + algebraic.ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "ComplexN( " + algebraic.modul.toScript() + ", " + root.toScript() //+ ", " + algebraic.isField() //+ ", " + algebraic.ring.toScript() + " )"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof ComplexAlgebraicRing)) { return false; } ComplexAlgebraicRing a = (ComplexAlgebraicRing) b; return algebraic.equals(a.algebraic) && root.equals(a.root); } /** * Hash code for this ComplexAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * algebraic.hashCode() + root.hashCode(); } /** * ComplexAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public ComplexAlgebraicNumber random(int n) { return new ComplexAlgebraicNumber(this, algebraic.random(n)); } /** * ComplexAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public ComplexAlgebraicNumber random(int n, Random rnd) { return new ComplexAlgebraicNumber(this, algebraic.random(n, rnd)); } /** * Parse ComplexAlgebraicNumber from String. * @param s String. * @return ComplexAlgebraicNumber from s. */ public ComplexAlgebraicNumber parse(String s) { return new ComplexAlgebraicNumber(this, algebraic.parse(s)); } /** * Parse ComplexAlgebraicNumber from Reader. * @param r Reader. * @return next ComplexAlgebraicNumber from r. */ public ComplexAlgebraicNumber parse(Reader r) { return new ComplexAlgebraicNumber(this, algebraic.parse(r)); } } java-algebra-system-2.7.200/src/edu/jas/root/ComplexRoots.java000066400000000000000000000040751445075545500241510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Complex roots interface. * @param coefficient type. * @author Heinz Kredel */ public interface ComplexRoots & Rational> extends Serializable { /** * Root bound. With f(-M + i M) * f(-M - i M) * f(M - i M) * f(M + i M) != * 0. * @param f univariate polynomial. * @return M such that root(f) is contained in the rectangle spanned by M. */ public Complex rootBound(GenPolynomial> f); /** * Complex root count of complex polynomial on rectangle. * @param rect rectangle. * @param a univariate complex polynomial. * @return root count of a in rectangle. */ public long complexRootCount(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException; /** * List of complex roots of complex polynomial a on rectangle. * @param rect rectangle. * @param a univariate squarefree complex polynomial. * @return list of complex roots. */ public List> complexRoots(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException; /** * List of complex roots of complex polynomial. * @param a univariate complex polynomial. * @return list of complex roots. */ public List> complexRoots(GenPolynomial> a); /** * Complex root refinement of complex polynomial a on rectangle. * @param rect rectangle containing exactly one complex root. * @param a univariate squarefree complex polynomial. * @param len rational length for refinement. * @return refined complex root. */ public Rectangle complexRootRefinement(Rectangle rect, GenPolynomial> a, BigRational len) throws InvalidBoundaryException; } java-algebra-system-2.7.200/src/edu/jas/root/ComplexRootsAbstract.java000066400000000000000000000762061445075545500256420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; import edu.jas.ufd.Squarefree; import edu.jas.ufd.SquarefreeFactory; /** * Complex roots abstract class. * @param coefficient type. * @author Heinz Kredel */ public abstract class ComplexRootsAbstract & Rational> implements ComplexRoots { private static final Logger logger = LogManager.getLogger(ComplexRootsAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Engine for square free decomposition. */ public final Squarefree> engine; /** * Constructor. * @param cf coefficient factory. */ public ComplexRootsAbstract(RingFactory> cf) { if (!(cf instanceof ComplexRing)) { throw new IllegalArgumentException("cf not supported coefficients " + cf); } engine = SquarefreeFactory.> getImplementation(cf); } /** * Root bound. With f(-M + i M) * f(-M - i M) * f(M - i M) * f(M + i M) != * 0. * @param f univariate polynomial. * @return M such that root(f) is contained in the rectangle spanned by M. */ public Complex rootBound(GenPolynomial> f) { if (f == null) { return null; } RingFactory> cfac = f.ring.coFac; Complex M = cfac.getONE(); if (f.isZERO() || f.isConstant()) { return M; } Complex a = f.leadingBaseCoefficient().norm(); for (Complex c : f.getMap().values()) { Complex d = c.norm().divide(a); if (M.compareTo(d) < 0) { M = d; } } M = M.sum(cfac.getONE()); //System.out.println("M = " + M); return M; } /** * Magnitude bound. * @param rect rectangle. * @param f univariate polynomial. * @return B such that |f(c)| < B for c in rect. */ public C magnitudeBound(Rectangle rect, GenPolynomial> f) { if (f == null) { return null; } if (f.isZERO()) { return f.ring.coFac.getONE().getRe(); } //System.out.println("f = " + f); if (f.isConstant()) { Complex c = f.leadingBaseCoefficient(); return c.norm().getRe(); } GenPolynomial> fa = f.map(new UnaryFunctor, Complex>() { public Complex eval(Complex a) { return a.norm(); } }); //System.out.println("fa = " + fa); Complex Mc = rect.getNW().norm(); C M = Mc.getRe(); //System.out.println("M = " + M); Complex M1c = rect.getSW().norm(); C M1 = M1c.getRe(); if (M.compareTo(M1) < 0) { M = M1; Mc = M1c; } M1c = rect.getSE().norm(); M1 = M1c.getRe(); if (M.compareTo(M1) < 0) { M = M1; Mc = M1c; } M1c = rect.getNE().norm(); M1 = M1c.getRe(); if (M.compareTo(M1) < 0) { //M = M1; Mc = M1c; } //System.out.println("M = " + M); Complex B = PolyUtil.> evaluateMain(f.ring.coFac, fa, Mc); //System.out.println("B = " + B); return B.getRe(); } /** * Complex root count of complex polynomial on rectangle. * @param rect rectangle. * @param a univariate complex polynomial. * @return root count of a in rectangle. */ public abstract long complexRootCount(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException; /** * List of complex roots of complex polynomial a on rectangle. * @param rect rectangle. * @param a univariate squarefree complex polynomial. * @return list of complex roots. */ public abstract List> complexRoots(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException; /** * List of complex roots of complex polynomial. * @param a univariate complex polynomial. * @return list of complex roots. */ @SuppressWarnings("unchecked") public List> complexRoots(GenPolynomial> a) { List> roots = new ArrayList>((int) a.degree()); if (a.isConstant() || a.isZERO()) { return roots; } ComplexRing cr = (ComplexRing) a.ring.coFac; // roots of square-free part GenPolynomial> as = engine.squarefreePart(a); //System.out.println("sqf(a) = " + as); Complex Mb = rootBound(as); C M = Mb.getRe(); C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin //System.out.println("M = " + M); if (debug) { logger.info("rootBound = {}", M); } Complex[] corner = (Complex[]) new Complex[4]; corner[0] = new Complex(cr, M1.negate(), M); // nw corner[1] = new Complex(cr, M1.negate(), M1.negate()); // sw corner[2] = new Complex(cr, M, M1.negate()); // se corner[3] = new Complex(cr, M, M); // ne Rectangle rect = new Rectangle(corner); List> asr = null; try { asr = complexRoots(rect, as); // must be squarefree } catch (InvalidBoundaryException ex) { //logger.error("invalid boundary {} for as = {}", rect, as); throw new RuntimeException("this should never happen " + ex); } //System.out.println("roots(sqf(a)) = " + asr); // check roots of square-free factors SortedMap>, Long> sa = engine.squarefreeFactors(a); // with multiplicity //System.out.println("squarefree factors = " + sa + ", of a = " + a + ", deg(a) = " + a.degree()); for (Map.Entry>, Long> me : sa.entrySet()) { GenPolynomial> p = me.getKey(); // is squarefree long d = p.degree(0); if (p.isConstant() || p.isZERO()) { continue; } long e = me.getValue(); Iterator> rit = asr.iterator(); while (rit.hasNext()) { Rectangle rsi = rit.next(); long w = 0L; try { w = complexRootCount(rsi, p); // roots of p not required } catch (InvalidBoundaryException ex) { //logger.error("invalid boundary {} for p = {}", rsi, p); throw new RuntimeException("this should never happen " + ex); } if (w == 1) { // since roots of as are separated and must belong to only one p for (int i = 0; i < e; i++) { // add with multiplicity roots.add(rsi); } rit.remove(); // rsi // removes last object from next() d--; if (d <= 0L) { break; // all roots identified } } } } //System.out.println("#roots = " + roots.size() + ", roots = " + roots); return roots; } /** * Complex root refinement of complex polynomial a on rectangle. * @param rect rectangle containing exactly one complex root. * @param a univariate squarefree complex polynomial. * @param len rational length for refinement. * @return refined complex root. */ @SuppressWarnings({ "cast", "unchecked" }) public Rectangle complexRootRefinement(Rectangle rect, GenPolynomial> a, BigRational len) throws InvalidBoundaryException { ComplexRing cr = (ComplexRing) a.ring.coFac; Rectangle root = rect; long w; if (debug) { w = complexRootCount(root, a); if (w != 1) { System.out.println("#root = " + w + ", root = " + root); System.out.println("deg(a) = " + a.degree() + ", a = " + a); throw new ArithmeticException("no initial isolating rectangle " + rect); } } Complex eps = cr.fromInteger(1); eps = eps.divide(cr.fromInteger(1000)); // 1/1000 BigRational length = len.multiply(len); Complex delta = null; boolean work = true; while (work) { try { while (root.rationalLength().compareTo(length) > 0) { //System.out.println("root = " + root + ", len = " + new BigDecimal(root.rationalLength())); if (delta == null) { delta = root.corners[3].subtract(root.corners[1]); delta = delta.divide(cr.fromInteger(2)); //System.out.println("delta = " + toDecimal(delta)); } Complex center = root.corners[1].sum(delta); //System.out.println("refine center = " + toDecimal(center)); if (debug) { logger.info("new center = {}", center); } Complex[] cp = (Complex[]) copyOfComplex(root.corners, 4); // cp[0] fix cp[1] = new Complex(cr, cp[1].getRe(), center.getIm()); cp[2] = center; cp[3] = new Complex(cr, center.getRe(), cp[3].getIm()); Rectangle nw = new Rectangle(cp); w = complexRootCount(nw, a); if (w == 1) { root = nw; delta = null; continue; } cp = (Complex[]) copyOfComplex(root.corners, 4); cp[0] = new Complex(cr, cp[0].getRe(), center.getIm()); // cp[1] fix cp[2] = new Complex(cr, center.getRe(), cp[2].getIm()); cp[3] = center; Rectangle sw = new Rectangle(cp); w = complexRootCount(sw, a); //System.out.println("#swr = " + w); if (w == 1) { root = sw; delta = null; continue; } cp = (Complex[]) copyOfComplex(root.corners, 4); cp[0] = center; cp[1] = new Complex(cr, center.getRe(), cp[1].getIm()); // cp[2] fix cp[3] = new Complex(cr, cp[3].getRe(), center.getIm()); Rectangle se = new Rectangle(cp); w = complexRootCount(se, a); //System.out.println("#ser = " + w); if (w == 1) { root = se; delta = null; continue; } cp = (Complex[]) copyOfComplex(root.corners, 4); cp[0] = new Complex(cr, center.getRe(), cp[0].getIm()); cp[1] = center; cp[2] = new Complex(cr, cp[2].getRe(), center.getIm()); // cp[3] fix Rectangle ne = new Rectangle(cp); w = complexRootCount(ne, a); //System.out.println("#ner = " + w); if (w == 1) { root = ne; delta = null; continue; } if (true) { w = complexRootCount(root, a); System.out.println("#root = " + w); System.out.println("root = " + root); } throw new ArithmeticException("no isolating rectangle " + rect); } work = false; } catch (InvalidBoundaryException e) { // repeat with new center delta = delta.sum(delta.multiply(eps)); // distort //System.out.println("new refine delta = " + toDecimal(delta)); eps = eps.sum(eps.multiply(cr.getIMAG())); } } return root; } /** * List of complex roots of complex polynomial. * @param a univariate complex polynomial. * @param len rational length for refinement. * @return list of complex roots to desired precision. */ @SuppressWarnings({ "cast", "unchecked" }) public List> complexRoots(GenPolynomial> a, BigRational len) { ComplexRing cr = (ComplexRing) a.ring.coFac; SortedMap>, Long> sa = engine.squarefreeFactors(a); List> roots = new ArrayList>(); for (Map.Entry>, Long> me : sa.entrySet()) { GenPolynomial> p = me.getKey(); Complex Mb = rootBound(p); C M = Mb.getRe(); C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin if (debug) { logger.info("rootBound = {}", M); } Complex[] corner = (Complex[]) new Complex[4]; corner[0] = new Complex(cr, M1.negate(), M); // nw corner[1] = new Complex(cr, M1.negate(), M1.negate()); // sw corner[2] = new Complex(cr, M, M1.negate()); // se corner[3] = new Complex(cr, M, M); // ne Rectangle rect = new Rectangle(corner); try { List> rs = complexRoots(rect, p); List> rf = new ArrayList>(rs.size()); for (Rectangle r : rs) { Rectangle rr = complexRootRefinement(r, p, len); rf.add(rr); } long e = me.getValue(); // sa.get(p); for (int i = 0; i < e; i++) { // add with multiplicity roots.addAll(rf); } } catch (InvalidBoundaryException e) { throw new RuntimeException("this should never happen " + e); } } return roots; } /** * Invariant rectangle for algebraic number. * @param rect root isolating rectangle for f which contains exactly one * root. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return v with v a new rectangle contained in iv such that g(w) != 0 for * w in v. */ public abstract Rectangle invariantRectangle(Rectangle rect, GenPolynomial> f, GenPolynomial> g) throws InvalidBoundaryException; /** * Get decimal approximation. * @param a complex number. * @return decimal(a). */ public String toDecimal(Complex a) { C r = a.getRe(); String s = r.toString(); BigRational rs = new BigRational(s); BigDecimal rd = new BigDecimal(rs); C i = a.getIm(); s = i.toString(); BigRational is = new BigRational(s); BigDecimal id = new BigDecimal(is); //System.out.println("rd = " + rd); //System.out.println("id = " + id); return rd.toString() + " i " + id.toString(); } /** * Approximate complex root. * @param rt root isolating rectangle. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, * v in rt. */ public Complex approximateRoot(Rectangle rt, GenPolynomial> f, BigRational eps) throws NoConvergenceException { if (rt == null) { throw new IllegalArgumentException("null interval not allowed"); } Complex d = rt.getDecimalCenter(); //System.out.println("d = " + d); if (f == null || f.isZERO() || f.isConstant() || eps == null) { return d; } if (rt.rationalLength().compareTo(eps) < 0) { return d; } ComplexRing cr = d.ring; Complex sw = rt.getSW(); BigDecimal swr = new BigDecimal(sw.getRe().getRational()); BigDecimal swi = new BigDecimal(sw.getIm().getRational()); Complex ll = new Complex(cr, swr, swi); Complex ne = rt.getNE(); BigDecimal ner = new BigDecimal(ne.getRe().getRational()); BigDecimal nei = new BigDecimal(ne.getIm().getRational()); Complex ur = new Complex(cr, ner, nei); BigDecimal e = new BigDecimal(eps.getRational()); Complex q = new Complex(cr, new BigDecimal("0.25")); e = e.multiply(d.norm().getRe()); // relative error //System.out.println("e = " + e); // polynomials with decimal coefficients GenPolynomialRing> dfac = new GenPolynomialRing>(cr, f.ring); GenPolynomial> df = PolyUtil. complexDecimalFromRational(dfac, f); GenPolynomial> fp = PolyUtil.> baseDerivative(f); GenPolynomial> dfp = PolyUtil. complexDecimalFromRational(dfac, fp); // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) int i = 0; final int MITER = 50; int dir = -1; while (i++ < MITER) { Complex fx = PolyUtil.> evaluateMain(cr, df, d); // f(d) //BigDecimal fs = fx.norm().getRe(); //System.out.println("fs = " + fs); if (fx.isZERO()) { return d; } Complex fpx = PolyUtil.> evaluateMain(cr, dfp, d); // f'(d) if (fpx.isZERO()) { throw new NoConvergenceException("zero derivative should not happen"); } Complex x = fx.divide(fpx); Complex dx = d.subtract(x); //System.out.println("dx = " + dx); if (d.subtract(dx).norm().getRe().compareTo(e) <= 0) { return dx; } // if ( false ) { // not useful: // Complex fxx = PolyUtil.> evaluateMain(cr, df, dx); // f(dx) // //System.out.println("fxx = " + fxx); // BigDecimal fsx = fxx.norm().getRe(); // System.out.println("fsx = " + fsx); // while ( fsx.compareTo( fs ) >= 0 ) { // System.out.println("trying to increase f(d) "); // if ( i++ > MITER ) { // dx > right: dx - right > 0 // throw new NoConvergenceException("no convergence after " + i + " steps"); // } // x = x.multiply(q); // x * 1/4 // dx = d.subtract(x); // //System.out.println(" x = " + x); // System.out.println("dx = " + dx); // fxx = PolyUtil.> evaluateMain(cr, df, dx); // f(dx) // //System.out.println("fxx = " + fxx); // fsx = fxx.norm().getRe(); // System.out.println("fsx = " + fsx); // } // } // check interval bounds while (dx.getRe().compareTo(ll.getRe()) < 0 || dx.getIm().compareTo(ll.getIm()) < 0 || dx.getRe().compareTo(ur.getRe()) > 0 || dx.getIm().compareTo(ur.getIm()) > 0) { // dx < ll: dx - ll < 0 // dx > ur: dx - ur > 0 if (i++ > MITER) { // dx > right: dx - right > 0 throw new NoConvergenceException("no convergence after " + i + " steps"); } if (i > MITER / 2 && dir == 0) { Complex cc = rt.getCenter(); Rectangle nrt = rt.exchangeSE(cc); Complex sd = nrt.getDecimalCenter(); d = sd; x = cr.getZERO(); logger.info("trying new SE starting point {}", d); i = 0; dir = 1; } if (i > MITER / 2 && dir == 1) { Complex cc = rt.getCenter(); Rectangle nrt = rt.exchangeNW(cc); Complex sd = nrt.getDecimalCenter(); d = sd; x = cr.getZERO(); logger.info("trying new NW starting point {}", d); i = 0; dir = 2; } if (i > MITER / 2 && dir == 2) { Complex cc = rt.getCenter(); Rectangle nrt = rt.exchangeSW(cc); Complex sd = nrt.getDecimalCenter(); d = sd; x = cr.getZERO(); logger.info("trying new SW starting point {}", d); i = 0; dir = 3; } if (i > MITER / 2 && dir == 3) { Complex cc = rt.getCenter(); Rectangle nrt = rt.exchangeNE(cc); Complex sd = nrt.getDecimalCenter(); d = sd; x = cr.getZERO(); logger.info("trying new NE starting point {}", d); i = 0; dir = 4; } if (i > MITER / 2 && (dir == -1 || dir == 4 || dir == 5)) { Complex sr = rt.randomPoint(); BigDecimal srr = new BigDecimal(sr.getRe().getRational()); BigDecimal sri = new BigDecimal(sr.getIm().getRational()); Complex sd = new Complex(cr, srr, sri); d = sd; x = cr.getZERO(); logger.info("trying new random starting point {}", d); if (dir == -1) { i = 0; dir = 0; } else if (dir == 4) { i = 0; dir = 5; } else { //i = 0; dir = 6; // end } } x = x.multiply(q); // x * 1/4 dx = d.subtract(x); //System.out.println(" x = " + x); //System.out.println("dx = " + dx); } d = dx; } throw new NoConvergenceException("no convergence after " + i + " steps"); } /** * List of decimal approximations of complex roots of complex polynomial. * @param a univariate complex polynomial. * @param eps length for refinement. * @return list of complex decimal root approximations to desired precision. */ @SuppressWarnings({ "cast", "unchecked" }) public List> approximateRoots(GenPolynomial> a, BigRational eps) { ComplexRing cr = (ComplexRing) a.ring.coFac; SortedMap>, Long> sa = engine.squarefreeFactors(a); List> roots = new ArrayList>(); for (Map.Entry>, Long> me : sa.entrySet()) { GenPolynomial> p = me.getKey(); List> rf = null; if (p.degree(0) <= 1) { Complex tc = p.trailingBaseCoefficient(); tc = tc.negate(); BigDecimal rr = new BigDecimal(tc.getRe().getRational()); BigDecimal ri = new BigDecimal(tc.getIm().getRational()); ComplexRing crf = new ComplexRing(rr); Complex r = new Complex(crf, rr, ri); rf = new ArrayList>(1); rf.add(r); } else { Complex Mb = rootBound(p); C M = Mb.getRe(); C M1 = M.sum(M.factory().fromInteger(1)); // asymmetric to origin if (debug) { logger.info("rootBound = {}", M); } Complex[] corner = (Complex[]) new Complex[4]; corner[0] = new Complex(cr, M1.negate(), M); // nw corner[1] = new Complex(cr, M1.negate(), M1.negate()); // sw corner[2] = new Complex(cr, M, M1.negate()); // se corner[3] = new Complex(cr, M, M); // ne Rectangle rect = new Rectangle(corner); List> rs = null; try { rs = complexRoots(rect, p); } catch (InvalidBoundaryException e) { throw new RuntimeException("this should never happen " + e); } rf = new ArrayList>(rs.size()); for (Rectangle r : rs) { Complex rr = null; while (rr == null) { try { rr = approximateRoot(r, p, eps); rf.add(rr); } catch (NoConvergenceException e) { // fall back to exact algorithm BigRational len = r.rationalLength(); len = len.multiply(new BigRational(1, 1000)); try { r = complexRootRefinement(r, p, len); logger.info("fall back rootRefinement = {}", r); //System.out.println("len = " + len); } catch (InvalidBoundaryException ee) { throw new RuntimeException("this should never happen " + ee); } } } } } long e = me.getValue(); // sa.get(p); for (int i = 0; i < e; i++) { // add with multiplicity roots.addAll(rf); } } return roots; } /** * Copy the specified array. * @param original array. * @param newLength new array length. * @return copy of this. */ public Complex[] copyOfComplex(Complex[] original, int newLength) { Complex[] copy = new Complex[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } /** * Invariant rectangle for algebraic number magnitude. * @param rect root isolating rectangle for f which contains exactly one * root. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @param eps length limit for rectangle length. * @return v with v a new rectangle contained in rect such that |g(a) - * g(b)| < eps for a, b in v in rect. */ public Rectangle invariantMagnitudeRectangle(Rectangle rect, GenPolynomial> f, GenPolynomial> g, BigRational eps) throws InvalidBoundaryException { Rectangle v = rect; if (g == null || g.isZERO()) { return v; } if (g.isConstant()) { return v; } if (f == null || f.isZERO() || f.isConstant()) { // ? return v; } GenPolynomial> gp = PolyUtil.> baseDerivative(g); //System.out.println("g = " + g); //System.out.println("gp = " + gp); BigRational B = magnitudeBound(rect, gp).getRational(); //System.out.println("B = " + B + " : " + B.getClass()); BigRational len = v.rationalLength(); BigRational half = new BigRational(1, 2); BigRational vlen = v.rationalLength(); vlen = vlen.multiply(vlen); //eps = eps.multiply(eps); //System.out.println("v = " + v); //System.out.println("vlen = " + vlen); while (B.multiply(vlen).compareTo(eps) >= 0) { // TODO: test squared len = len.multiply(half); v = complexRootRefinement(v, f, len); //System.out.println("v = " + v); vlen = v.rationalLength(); vlen = vlen.multiply(vlen); //System.out.println("vlen = " + vlen); } //System.out.println("vlen = " + vlen); return v; } /** * Complex algebraic number magnitude. * @param rect root isolating rectangle for f which contains exactly one * root, with rect such that |g(a) - g(b)| < eps for a, b in * rect. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return g(rect) . */ public Complex complexRectangleMagnitude(Rectangle rect, GenPolynomial> f, GenPolynomial> g) { if (g.isZERO() || g.isConstant()) { return g.leadingBaseCoefficient(); } RingFactory> cfac = f.ring.coFac; //System.out.println("cfac = " + cfac + " : " + cfac.getClass()); Complex c = rect.getCenter(); Complex ev = PolyUtil.> evaluateMain(cfac, g, c); return ev; } /** * Complex algebraic number magnitude. * @param rect root isolating rectangle for f which contains exactly one * root, with rect such that |g(a) - g(b)| < eps for a, b in * rect. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @param eps length limit for rectangle length. * @return g(rect) . */ public Complex complexMagnitude(Rectangle rect, GenPolynomial> f, GenPolynomial> g, BigRational eps) throws InvalidBoundaryException { if (g.isZERO() || g.isConstant()) { return g.leadingBaseCoefficient(); } Rectangle v = invariantMagnitudeRectangle(rect, f, g, eps); //System.out.println("ref = " + ref); return complexRectangleMagnitude(v, f, g); } } java-algebra-system-2.7.200/src/edu/jas/root/ComplexRootsSturm.java000066400000000000000000000435131445075545500252040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; // import java.util.Arrays; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Complex roots implemented by Sturm sequences. Algorithms use exact method * derived from Wilf's numeric Routh-Hurwitz method. * @param coefficient type. * @author Heinz Kredel */ public class ComplexRootsSturm & Rational> extends ComplexRootsAbstract { private static final Logger logger = LogManager.getLogger(ComplexRootsSturm.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. * @param cf coefficient factory. */ public ComplexRootsSturm(RingFactory> cf) { super(cf); //ufd = GCDFactory.> getImplementation(cf); } /** * Cauchy index of rational function f/g on interval. * @param a interval bound for I = [a,b]. * @param b interval bound for I = [a,b]. * @param f univariate polynomial. * @param g univariate polynomial. * @return winding number of f/g in I. */ public long indexOfCauchy(C a, C b, GenPolynomial f, GenPolynomial g) { List> S = sturmSequence(g, f); //System.out.println("S = " + S); if (debug) { logger.info("sturmSeq = {}", S); } RingFactory cfac = f.ring.coFac; List l = PolyUtil. evaluateMain(cfac, S, a); List r = PolyUtil. evaluateMain(cfac, S, b); long v = RootUtil. signVar(l) - RootUtil. signVar(r); //System.out.println("v = " + v); // if (v < 0L) { // v = -v; // } return v; } /** * Routh index of complex function f + i g on interval. * @param a interval bound for I = [a,b]. * @param b interval bound for I = [a,b]. * @param f univariate polynomial. * @param g univariate polynomial != 0. * @return index number of f + i g. */ public long[] indexOfRouth(C a, C b, GenPolynomial f, GenPolynomial g) { List> S = sturmSequence(f, g); //System.out.println("S = " + S); RingFactory cfac = f.ring.coFac; List l = PolyUtil. evaluateMain(cfac, S, a); List r = PolyUtil. evaluateMain(cfac, S, b); long v = RootUtil. signVar(l) - RootUtil. signVar(r); //System.out.println("v = " + v); long d = f.degree(0); if (d < g.degree(0)) { d = g.degree(0); } //System.out.println("d = " + d); long ui = (d - v) / 2; long li = (d + v) / 2; //System.out.println("upper = " + ui); //System.out.println("lower = " + li); return new long[] { ui, li }; } /** * Sturm sequence. * @param f univariate polynomial. * @param g univariate polynomial. * @return a Sturm sequence for f and g. */ public List> sturmSequence(GenPolynomial f, GenPolynomial g) { List> S = new ArrayList>(); if (f == null || f.isZERO()) { return S; } if (f.isConstant()) { S.add(f.monic()); return S; } GenPolynomial F = f; S.add(F); GenPolynomial G = g; //PolyUtil. baseDerivative(f); while (!G.isZERO()) { GenPolynomial r = F.remainder(G); F = G; G = r.negate(); S.add(F/*.monic()*/); } //System.out.println("F = " + F); if (F.isConstant()) { return S; } // make squarefree List> Sp = new ArrayList>(S.size()); for (GenPolynomial p : S) { p = p.divide(F); Sp.add(p); } return Sp; } /** * Complex root count of complex polynomial on rectangle. * @param rect rectangle. * @param a univariate complex polynomial. * @return root count of a in rectangle. */ @Override public long complexRootCount(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException { C rl = rect.lengthReal(); C il = rect.lengthImag(); //System.out.println("complexRootCount: rl = " + rl + ", il = " + il); // only linear polynomials have zero length intervals if (rl.isZERO() && il.isZERO()) { Complex e = PolyUtil.> evaluateMain(a.ring.coFac, a, rect.getSW()); if (e.isZERO()) { return 1; } return 0; } if (rl.isZERO() || il.isZERO()) { //RingFactory cf = (RingFactory) rl.factory(); //GenPolynomialRing rfac = new GenPolynomialRing(cf,a.ring); //cf = (RingFactory) il.factory(); //GenPolynomialRing ifac = new GenPolynomialRing(cf,a.ring); //GenPolynomial rp = PolyUtil. realPartFromComplex(rfac, a); //GenPolynomial ip = PolyUtil. imaginaryPartFromComplex(ifac, a); //RealRoots rr = new RealRootsSturm(); if (rl.isZERO()) { //logger.info("lengthReal == 0: {}", rect); //Complex r = rect.getSW(); //r = new Complex(r.ring,r.getRe()/*,0*/); //Complex e = PolyUtil.> evaluateMain(a.ring.coFac, a, r); //logger.info("a(re(rect)): {}", e); //if ( !e.getRe().isZERO() ) { // return 0; //} //C ev = PolyUtil. evaluateMain(rp.ring.coFac, rp, rl); //logger.info("re(a)(re(rect)): {}", ev); //Interval iv = new Interval(rect.getSW().getIm(),rect.getNE().getIm()); //logger.info("iv: {}", iv); //long ic = rr.realRootCount(iv,ip); //logger.info("ic: {}", ic); Complex sw = rect.getSW(); Complex ne = rect.getNE(); C delta = sw.ring.ring.getONE(); //parse("1"); // works since linear polynomial Complex cd = new Complex(sw.ring, delta/*, 0*/); sw = sw.subtract(cd); ne = ne.sum(cd); rect = rect.exchangeSW(sw); rect = rect.exchangeNE(ne); logger.info("new rectangle: {}", rect.toScript()); } if (il.isZERO()) { //logger.info("lengthImag == 0: {}", rect); //Interval rv = new Interval(rect.getSW().getRe(),rect.getNE().getRe()); //logger.info("rv: {}", rv); //long rc = rr.realRootCount(rv,rp); //logger.info("rc: {}", rc); Complex sw = rect.getSW(); Complex ne = rect.getNE(); C delta = sw.ring.ring.getONE(); //parse("1"); // works since linear polynomial Complex cd = new Complex(sw.ring, sw.ring.ring.getZERO(), delta); sw = sw.subtract(cd); ne = ne.sum(cd); rect = rect.exchangeSW(sw); rect = rect.exchangeNE(ne); logger.info("new rectangle: {}", rect.toScript()); } } long wn = windingNumber(rect, a); //System.out.println("complexRootCount: wn = " + wn); return wn; } /** * Winding number of complex function A on rectangle. * @param rect rectangle. * @param A univariate complex polynomial. * @return winding number of A around rect. */ public long windingNumber(Rectangle rect, GenPolynomial> A) throws InvalidBoundaryException { Boundary bound = new Boundary(rect, A); // throws InvalidBoundaryException ComplexRing cr = (ComplexRing) A.ring.coFac; RingFactory cf = cr.ring; C zero = cf.getZERO(); C one = cf.getONE(); long ix = 0L; for (int i = 0; i < 4; i++) { long ci = indexOfCauchy(zero, one, bound.getRealPart(i), bound.getImagPart(i)); //System.out.println("ci[" + i + "," + (i + 1) + "] = " + ci); ix += ci; } if (ix % 2L != 0) { throw new InvalidBoundaryException("odd winding number " + ix); } return ix / 2L; } /** * List of complex roots of complex polynomial a on rectangle. * @param rect rectangle. * @param a univariate squarefree complex polynomial. * @return list of complex roots. */ @SuppressWarnings({ "cast", "unchecked" }) @Override public List> complexRoots(Rectangle rect, GenPolynomial> a) throws InvalidBoundaryException { ComplexRing cr = (ComplexRing) a.ring.coFac; List> roots = new ArrayList>(); if (a.isConstant() || a.isZERO()) { return roots; } //System.out.println("rect = " + rect); long n = windingNumber(rect, a); if (n < 0) { // can this happen? throw new RuntimeException("negative winding number " + n); //System.out.println("negative winding number " + n); //return roots; } if (n == 0) { return roots; } if (n == 1) { //not ok: rect = excludeZero(rect, a); roots.add(rect); return roots; } Complex eps = cr.fromInteger(1); eps = eps.divide(cr.fromInteger(1000)); // 1/1000 //System.out.println("eps = " + eps); //System.out.println("rect = " + rect); // construct new center Complex delta = rect.corners[3].subtract(rect.corners[1]); delta = delta.divide(cr.fromInteger(2)); //System.out.println("delta = " + delta); boolean work = true; while (work) { Complex center = rect.corners[1].sum(delta); //System.out.println("center = " + toDecimal(center)); if (debug) { logger.info("new center = {}", center); } try { Complex[] cp = (Complex[]) copyOfComplex(rect.corners, 4); // (Complex[]) new Complex[4]; cp[0] = rect.corners[0]; // cp[0] fix cp[1] = new Complex(cr, cp[1].getRe(), center.getIm()); cp[2] = center; cp[3] = new Complex(cr, center.getRe(), cp[3].getIm()); Rectangle nw = new Rectangle(cp); //System.out.println("nw = " + nw); List> nwr = complexRoots(nw, a); //System.out.println("#nwr = " + nwr.size()); roots.addAll(nwr); if (roots.size() == a.degree(0)) { work = false; break; } cp = (Complex[]) copyOfComplex(rect.corners, 4); cp[0] = new Complex(cr, cp[0].getRe(), center.getIm()); // cp[1] fix cp[2] = new Complex(cr, center.getRe(), cp[2].getIm()); cp[3] = center; Rectangle sw = new Rectangle(cp); //System.out.println("sw = " + sw); List> swr = complexRoots(sw, a); //System.out.println("#swr = " + swr.size()); roots.addAll(swr); if (roots.size() == a.degree(0)) { work = false; break; } cp = (Complex[]) copyOfComplex(rect.corners, 4); cp[0] = center; cp[1] = new Complex(cr, center.getRe(), cp[1].getIm()); // cp[2] fix cp[3] = new Complex(cr, cp[3].getRe(), center.getIm()); Rectangle se = new Rectangle(cp); //System.out.println("se = " + se); List> ser = complexRoots(se, a); //System.out.println("#ser = " + ser.size()); roots.addAll(ser); if (roots.size() == a.degree(0)) { work = false; break; } cp = (Complex[]) copyOfComplex(rect.corners, 4); cp[0] = new Complex(cr, center.getRe(), cp[0].getIm()); cp[1] = center; cp[2] = new Complex(cr, cp[2].getRe(), center.getIm()); // cp[3] fix Rectangle ne = new Rectangle(cp); //System.out.println("ne = " + ne); List> ner = complexRoots(ne, a); //System.out.println("#ner = " + ner.size()); roots.addAll(ner); work = false; } catch (InvalidBoundaryException e) { // repeat with new center delta = delta.sum(delta.multiply(eps)); // distort //System.out.println("new delta = " + toDecimal(delta)); eps = eps.sum(eps.multiply(cr.getIMAG())); } } return roots; } /** * Invariant rectangle for algebraic number. * @param rect root isolating rectangle for f which contains exactly one * root. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return v a new rectangle contained in rect such that g(w) != 0 for w in * v. */ @Override public Rectangle invariantRectangle(Rectangle rect, GenPolynomial> f, GenPolynomial> g) throws InvalidBoundaryException { Rectangle v = rect; if (g == null || g.isZERO()) { return v; } if (g.isConstant()) { return v; } if (f == null || f.isZERO() || f.isConstant()) { // ? return v; } BigRational len = v.rationalLength(); BigRational half = new BigRational(1, 2); while (true) { long n = windingNumber(v, g); //System.out.println("n = " + n); if (n < 0) { // can this happen? throw new RuntimeException("negative winding number " + n); } if (n == 0) { return v; } len = len.multiply(half); Rectangle v1 = v; v = complexRootRefinement(v, f, len); if (v.equals(v1)) { //System.out.println("len = " + len); if (!f.gcd(g).isONE()) { System.out.println("f.gcd(g) = " + f.gcd(g)); throw new RuntimeException("no convergence " + v); } //break; // no convergence } } //return v; } /** * Exclude zero. If an axis intersects with the rectangle, it is shrunk to * exclude the axis. Not used. * @param rect root isolating rectangle for f which contains exactly one * root. * @return a new rectangle r such that re(r) < 0 or (re)r > 0 and * im(r) < 0 or (im)r > 0. */ public Rectangle excludeZero(Rectangle rect, GenPolynomial> f) throws InvalidBoundaryException { if (f == null || f.isZERO()) { return rect; } System.out.println("\nexcludeZero: rect = " + rect + ", f = " + f); Complex zero = f.ring.coFac.getZERO(); ComplexRing cr = zero.ring; Complex sw = rect.getSW(); Complex ne = rect.getNE(); Interval ir = new Interval(sw.getRe(), ne.getRe()); Interval ii = new Interval(sw.getIm(), ne.getIm()); System.out.println("intervals, ir = " + ir + ", ii = " + ii); if (!(ir.contains(zero.getRe()) || ii.contains(zero.getIm()))) { // !rect.contains(zero) not correct return rect; } //System.out.println("contains: ir = " + ir.contains(zero.getRe()) + ", ii = " + ii.contains(zero.getIm()) ); Rectangle rn = rect; // shrink real part if (ir.contains(zero.getRe())) { Complex sw0 = new Complex(cr, zero.getRe(), sw.getIm()); Complex ne0 = new Complex(cr, zero.getRe(), ne.getIm()); Rectangle rl = new Rectangle(sw, ne0); Rectangle rr = new Rectangle(sw0, ne); System.out.println("rectangle, rl = " + rl + ", rr = " + rr); if (complexRootCount(rr, f) == 1) { rn = rr; } else { // complexRootCount(rl,f) == 1 rn = rl; } System.out.println("rectangle, real = " + rn); } // shrink imaginary part sw = rn.getSW(); ne = rn.getNE(); ii = new Interval(sw.getIm(), ne.getIm()); System.out.println("interval, ii = " + ii); if (ii.contains(zero.getIm())) { Complex sw1 = new Complex(cr, sw.getRe(), zero.getIm()); Complex ne1 = new Complex(cr, ne.getRe(), zero.getIm()); Rectangle iu = new Rectangle(sw1, ne); Rectangle il = new Rectangle(sw, ne1); System.out.println("rectangle, il = " + il + ", iu = " + iu); if (complexRootCount(il, f) == 1) { rn = il;; } else { // complexRootCount(iu,f) == 1 rn = iu; } System.out.println("rectangle, imag = " + rn); } return rn; } } java-algebra-system-2.7.200/src/edu/jas/root/DecimalRoots.java000066400000000000000000000070431445075545500240760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.List; import edu.jas.arith.Rational; import edu.jas.arith.BigDecimal; import edu.jas.poly.GenPolynomial; import edu.jas.poly.Complex; import edu.jas.structure.GcdRingElem; /** * Container for the real and complex algebraic roots of a univariate * polynomial. * @param coefficient type. * @author Heinz Kredel */ public class DecimalRoots & Rational> implements Serializable { /** * univariate polynomial. */ public final GenPolynomial p; /** * real decimal roots. */ public final List real; /** * univariate polynomial with complex coefficients. */ public final GenPolynomial> cp; /** * complex decimal roots. */ public final List> complex; /** * Constructor. * @param p univariate polynomial * @param cp univariate complex polynomial * @param r list of real decimal roots * @param c list of complex decimal roots */ public DecimalRoots(GenPolynomial p, GenPolynomial> cp, List r, List> c) { this.p = p; this.cp = cp; this.real = r; this.complex = c; } /** * String representation of AlgebraicRoots. * @see java.lang.Object#toString() */ @Override public String toString() { return "[" + p + ", real=" + real + ", complex=" + complex + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Interval. */ public String toScript() { // Python case StringBuffer sb = new StringBuffer("["); sb.append(p.toScript()); if (!real.isEmpty()) { sb.append(", real=["); boolean first = true; for (BigDecimal r : real) { if (first) { first = false; } else { sb.append(", "); } sb.append(r.toScript()); } sb.append("]"); } if (!complex.isEmpty()) { sb.append(", complex=["); boolean first = true; for (Complex c : complex) { if (first) { first = false; } else { sb.append(", "); } sb.append(c.toScript()); } sb.append("]"); } sb.append("]"); return sb.toString(); } /** * Copy this. * @return a copy of this. */ public DecimalRoots copy() { return new DecimalRoots(p, cp, real, complex); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof DecimalRoots)) { return false; } DecimalRoots a = null; try { a = (DecimalRoots) b; } catch (ClassCastException e) { return false; } return p.equals(a.p) && real.equals(a.real) && complex.equals(a.complex); } /** * Hash code for this AlgebraicRoots. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return (161 * p.hashCode() + 37) * real.hashCode() + complex.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/root/Interval.java000066400000000000000000000133641445075545500233000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.SortedSet; import java.util.TreeSet; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Interval. For example isolating interval for real roots. * @param coefficient type. * @author Heinz Kredel */ public class Interval & Rational> implements Serializable { //findbugs /** * left interval border. */ public final C left; /** * right interval border. */ public final C right; /** * Constructor. * @param left interval border. * @param right interval border. */ public Interval(C left, C right) { this.left = left; this.right = right; } /** * Constructor. * @param mid left and right interval border. */ public Interval(C mid) { this(mid, mid); } /** * String representation of Interval. * @see java.lang.Object#toString() */ @Override public String toString() { return "[" + left + ", " + right + "]"; //return "[" + left.getRational().getDecimal() + ", " + right.getRational().getDecimal() + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Interval. */ public String toScript() { // Python case return "[ " + left.toScript() + ", " + right.toScript() + " ]"; } /** * Copy this. * @return a copy of this. */ public Interval copy() { return new Interval(left, right); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof Interval)) { return false; } Interval a = null; try { a = (Interval) b; } catch (ClassCastException e) { return false; } return left.equals(a.left) && right.equals(a.right); } /** * Hash code for this Interval. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * left.hashCode() + right.hashCode(); } /** * Test if an element is contained in this interval. * @param c element to test. * @return true, if left ≤ b ≤ right; */ public boolean contains(C c) { return left.compareTo(c) <= 0 && c.compareTo(right) <= 0; } /** * Test if an interval is contained in this interval. * @param vc interval to test. * @return true, if left ≤ vc.left and vc.right ≤ right; */ public boolean contains(Interval vc) { return contains(vc.left) && contains(vc.right); } /** * Length. * @return |left-right|; */ public C length() { C m = right.subtract(left); return m.abs(); } /** * BigRational Length. * @return |left-right|; */ public BigRational rationalLength() { return length().getRational(); } /** * BigDecimal representation of Interval. */ public BigDecimal toDecimal() { BigDecimal l = new BigDecimal(left.getRational()); BigDecimal r = new BigDecimal(right.getRational()); BigDecimal two = new BigDecimal(2); BigDecimal v = l.sum(r).divide(two); return v; } /** * Rational middle point. * @return (left+right)/2; */ public BigRational rationalMiddle() { BigRational m = left.getRational().sum(right.getRational()); BigRational t = new BigRational(1L, 2L); m = m.multiply(t); return m; } /** * Middle point. * @return (left+right)/2; */ public C middle() { C m = left.sum(right); C h = left.factory().parse("1/2"); m = m.multiply(h); return m; } /** * Random point of interval. * @return a random point contained in this interval. */ public C randomPoint() { C dr = right.subtract(left); RingFactory fac = (RingFactory) dr.factory(); C r = fac.random(13); r = r.abs(); if (!r.isZERO()) { if (r.compareTo(fac.getONE()) > 0) { r = r.inverse(); } } // 0 <= r <= 1 dr = dr.multiply(r); C rv = left.sum(dr); //System.out.println("rv = " + new BigDecimal(rv.getRational()) ); return rv; } /** * Sum of intervals. * @param o other interval. * @return this+other */ public Interval sum(Interval o) { C l = left.sum(o.left); C r = right.sum(o.right); Interval v = new Interval(l, r); return v; } /** * Subtract intervals. * @param o other interval. * @return this-other */ public Interval subtract(Interval o) { C l = left.subtract(o.right); C r = right.subtract(o.left); Interval v = new Interval(l, r); return v; } /** * Multiply intervals. * @param o other interval. * @return this*other */ public Interval multiply(Interval o) { C v1 = left.multiply(o.left); C v2 = left.multiply(o.right); C v3 = right.multiply(o.left); C v4 = right.multiply(o.right); SortedSet so = new TreeSet(); so.add(v1); so.add(v2); so.add(v3); so.add(v4); //System.out.println("sorted set = " + so); Interval v = new Interval(so.first(), so.last()); return v; } } java-algebra-system-2.7.200/src/edu/jas/root/InvalidBoundaryException.java000066400000000000000000000011321445075545500264530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; /** * Invalid boundary exception class. Exception to be thrown when a valid * boundary cannot be constructed. * @author Heinz Kredel */ public class InvalidBoundaryException extends Exception { public InvalidBoundaryException() { super("InvalidBoundaryException"); } public InvalidBoundaryException(String c) { super(c); } public InvalidBoundaryException(String c, Throwable t) { super(c, t); } public InvalidBoundaryException(Throwable t) { super("InvalidBoundaryException", t); } } java-algebra-system-2.7.200/src/edu/jas/root/NoConvergenceException.java000066400000000000000000000011021445075545500261110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; /** * No convergence exception class. Exception to be thrown when an iteration does * not converge. * @author Heinz Kredel */ public class NoConvergenceException extends Exception { public NoConvergenceException() { super("NoConvergenceException"); } public NoConvergenceException(String c) { super(c); } public NoConvergenceException(String c, Throwable t) { super(c, t); } public NoConvergenceException(Throwable t) { super("NoConvergenceException", t); } } java-algebra-system-2.7.200/src/edu/jas/root/PolyUtilRoot.java000066400000000000000000000353141445075545500241400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; /** * Polynomial utilities related to real and complex roots. * @author Heinz Kredel */ public class PolyUtilRoot { private static final Logger logger = LogManager.getLogger(PolyUtilRoot.class); private static final boolean debug = logger.isDebugEnabled(); /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients, C is e.g. ModInteger or BigRational. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertToAlgebraicCoefficients( GenPolynomialRing> pfac, GenPolynomial A) { RealAlgebraicRing afac = (RealAlgebraicRing) pfac.coFac; if (debug) { logger.info("afac = {}", afac); } return PolyUtil.> map(pfac, A, new CoeffToReAlg(afac)); } /** * Convert to recursive RealAlgebraicNumber coefficients. Represent as * polynomial with recursive RealAlgebraicNumber coefficients, C is e.g. * ModInteger or BigRational. * @param depth recursion depth of RealAlgebraicNumber coefficients. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertToRecAlgebraicCoefficients( int depth, GenPolynomialRing> pfac, GenPolynomial A) { RealAlgebraicRing afac = (RealAlgebraicRing) pfac.coFac; return PolyUtil.> map(pfac, A, new CoeffToRecReAlg(depth, afac)); } /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients, C is e.g. ModInteger or BigRational. * @param pfac result polynomial factory. * @param A recursive polynomial with GenPolynomial<BigInteger> * coefficients to be converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertRecursiveToAlgebraicCoefficients( GenPolynomialRing> pfac, GenPolynomial> A) { RealAlgebraicRing afac = (RealAlgebraicRing) pfac.coFac; return PolyUtil., RealAlgebraicNumber> map(pfac, A, new PolyToReAlg(afac)); } /** * Convert to AlgebraicNumber coefficients. Represent as polynomial with * AlgebraicNumber coefficients. * @param afac result polynomial factory. * @param A polynomial with RealAlgebraicNumber<C> coefficients to be * converted. * @return polynomial with AlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> algebraicFromRealCoefficients( GenPolynomialRing> afac, GenPolynomial> A) { AlgebraicNumberRing cfac = (AlgebraicNumberRing) afac.coFac; return PolyUtil., AlgebraicNumber> map(afac, A, new AlgFromRealCoeff(cfac)); } /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients. * @param rfac result polynomial factory. * @param A polynomial with AlgebraicNumber<C> coefficients to be * converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> realFromAlgebraicCoefficients( GenPolynomialRing> rfac, GenPolynomial> A) { RealAlgebraicRing cfac = (RealAlgebraicRing) rfac.coFac; return PolyUtil., RealAlgebraicNumber> map(rfac, A, new RealFromAlgCoeff(cfac)); } /** * Convert to RealAlgebraicNumber coefficients. Represent as polynomial with * RealAlgebraicNumber coefficients, C is e.g. BigRational. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with RealAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertToRealCoefficients( GenPolynomialRing> pfac, GenPolynomial A) { RealAlgebraicRing afac = (RealAlgebraicRing) pfac.coFac; return PolyUtil.> map(pfac, A, new CoeffToReal(afac)); } /** * Convert to ComplexAlgebraicNumber coefficients. Represent as polynomial * with ComplexAlgebraicNumber coefficients, C is e.g. BigRational. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with ComplexAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertToComplexCoefficients( GenPolynomialRing> pfac, GenPolynomial A) { ComplexAlgebraicRing afac = (ComplexAlgebraicRing) pfac.coFac; return PolyUtil.> map(pfac, A, new CoeffToComplex(afac)); } /** * Convert to ComplexAlgebraicNumber coefficients. Represent as polynomial * with ComplexAlgebraicNumber coefficients, C is e.g. BigRational. * @param pfac result polynomial factory. * @param A polynomial with C coefficients to be converted. * @return polynomial with ComplexAlgebraicNumber<C> coefficients. */ public static & Rational> GenPolynomial> convertToComplexCoefficientsFromComplex( GenPolynomialRing> pfac, GenPolynomial> A) { ComplexAlgebraicRing afac = (ComplexAlgebraicRing) pfac.coFac; return PolyUtil., ComplexAlgebraicNumber> map(pfac, A, new CoeffToComplexFromComplex(afac)); } /** * Convert to Complex coefficients. Represent as polynomial * with Complex<C> coefficients. * @param f univariate polynomial. * @return f with complex coefficients */ public static & Rational> GenPolynomial> complexFromAny(GenPolynomial f) { if (f.ring.coFac instanceof ComplexRing) { throw new IllegalArgumentException("f already has ComplexRing coefficients " + f.ring); } if (f.ring.coFac instanceof ComplexAlgebraicRing) { throw new UnsupportedOperationException( "unsupported ComplexAlgebraicRing coefficients " + f.ring); } ComplexRing cr = new ComplexRing(f.ring.coFac); GenPolynomialRing> fac = new GenPolynomialRing>(cr, f.ring); GenPolynomial> fc = PolyUtil. complexFromAny(fac, f); return fc; } } /** * Polynomial to algebraic functor. */ class PolyToReAlg & Rational> implements UnaryFunctor, RealAlgebraicNumber> { final protected RealAlgebraicRing afac; public PolyToReAlg(RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; } public RealAlgebraicNumber eval(GenPolynomial c) { if (c == null) { return afac.getZERO(); } return new RealAlgebraicNumber(afac, c); } } /** * Coefficient to algebraic functor. */ class CoeffToReAlg & Rational> implements UnaryFunctor> { final protected RealAlgebraicRing afac; final protected GenPolynomial zero; public CoeffToReAlg(RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; GenPolynomialRing pfac = afac.algebraic.ring; zero = pfac.getZERO(); } public RealAlgebraicNumber eval(C c) { if (c == null) { return afac.getZERO(); } return new RealAlgebraicNumber(afac, zero.sum(c)); } } /** * Coefficient to recursive algebraic functor. */ class CoeffToRecReAlg & Rational> implements UnaryFunctor> { final protected List> lfac; final int depth; @SuppressWarnings({ "unchecked", "cast" }) public CoeffToRecReAlg(int depth, RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } RealAlgebraicRing afac = fac; this.depth = depth; lfac = new ArrayList>(this.depth); lfac.add(fac); for (int i = 1; i < this.depth; i++) { RingFactory rf = afac.algebraic.ring.coFac; if (!(rf instanceof RealAlgebraicRing)) { throw new IllegalArgumentException("fac depth to low"); } afac = (RealAlgebraicRing) (Object) rf; lfac.add(afac); } } @SuppressWarnings("unchecked") public RealAlgebraicNumber eval(C c) { if (c == null) { return lfac.get(0).getZERO(); } C ac = c; RealAlgebraicRing af = lfac.get(lfac.size() - 1); GenPolynomial zero = af.algebraic.ring.getZERO(); RealAlgebraicNumber an = new RealAlgebraicNumber(af, zero.sum(ac)); for (int i = lfac.size() - 2; i >= 0; i--) { af = lfac.get(i); zero = af.algebraic.ring.getZERO(); ac = (C) (Object) an; an = new RealAlgebraicNumber(af, zero.sum(ac)); } return an; } } /** * Coefficient to algebraic from real algebraic functor. */ class AlgFromRealCoeff & Rational> implements UnaryFunctor, AlgebraicNumber> { final protected AlgebraicNumberRing afac; public AlgFromRealCoeff(AlgebraicNumberRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } afac = fac; } public AlgebraicNumber eval(RealAlgebraicNumber c) { if (c == null) { return afac.getZERO(); } return c.number; } } /** * Coefficient to real algebriac from algebraic functor. */ class RealFromAlgCoeff & Rational> implements UnaryFunctor, RealAlgebraicNumber> { final protected RealAlgebraicRing rfac; public RealFromAlgCoeff(RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } rfac = fac; } public RealAlgebraicNumber eval(AlgebraicNumber c) { if (c == null) { return rfac.getZERO(); } return new RealAlgebraicNumber(rfac, c); } } /** * Coefficient to real algebraic functor. */ class CoeffToReal & Rational> implements UnaryFunctor> { final protected RealAlgebraicRing rfac; final protected AlgebraicNumber zero; public CoeffToReal(RealAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } rfac = fac; AlgebraicNumberRing afac = rfac.algebraic; zero = afac.getZERO(); } public RealAlgebraicNumber eval(C c) { if (c == null) { return rfac.getZERO(); } return new RealAlgebraicNumber(rfac, zero.sum(c)); } } /** * Coefficient to complex algebraic functor. */ class CoeffToComplex & Rational> implements UnaryFunctor> { final protected ComplexAlgebraicRing cfac; final protected AlgebraicNumber> zero; final protected ComplexRing cr; public CoeffToComplex(ComplexAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = fac; AlgebraicNumberRing> afac = cfac.algebraic; zero = afac.getZERO(); cr = (ComplexRing) afac.ring.coFac; } public ComplexAlgebraicNumber eval(C c) { if (c == null) { return cfac.getZERO(); } return new ComplexAlgebraicNumber(cfac, zero.sum(new Complex(cr, c))); } } /** * Coefficient to complex algebraic from complex functor. */ class CoeffToComplexFromComplex & Rational> implements UnaryFunctor, ComplexAlgebraicNumber> { final protected ComplexAlgebraicRing cfac; final protected AlgebraicNumber> zero; //final protected ComplexRing cr; public CoeffToComplexFromComplex(ComplexAlgebraicRing fac) { if (fac == null) { throw new IllegalArgumentException("fac must not be null"); } cfac = fac; AlgebraicNumberRing> afac = cfac.algebraic; zero = afac.getZERO(); //cr = (ComplexRing) afac.ring.coFac; } public ComplexAlgebraicNumber eval(Complex c) { if (c == null) { return cfac.getZERO(); } return new ComplexAlgebraicNumber(cfac, zero.sum(c)); } } java-algebra-system-2.7.200/src/edu/jas/root/RealAlgebraicNumber.java000066400000000000000000000303741445075545500253420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.math.BigInteger; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.kern.PrettyPrint; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; /** * Real algebraic number class based on AlgebraicNumber. Objects of this class * are immutable. * @author Heinz Kredel */ public class RealAlgebraicNumber & Rational> /*extends AlgebraicNumber*/ implements GcdRingElem>, Rational { /** * Representing AlgebraicNumber. */ public final AlgebraicNumber number; /** * Ring part of the data structure. */ public final RealAlgebraicRing ring; /** * The constructor creates a RealAlgebraicNumber object from * RealAlgebraicRing modul and a GenPolynomial value. * @param r ring RealAlgebraicRing. * @param a value GenPolynomial. */ public RealAlgebraicNumber(RealAlgebraicRing r, GenPolynomial a) { number = new AlgebraicNumber(r.algebraic, a); ring = r; } /** * The constructor creates a RealAlgebraicNumber object from * RealAlgebraicRing modul and a AlgebraicNumber value. * @param r ring RealAlgebraicRing. * @param a value AlgebraicNumber. */ public RealAlgebraicNumber(RealAlgebraicRing r, AlgebraicNumber a) { number = a; ring = r; } /** * The constructor creates a RealAlgebraicNumber object from a GenPolynomial * object module. * @param r ring RealAlgebraicRing. */ public RealAlgebraicNumber(RealAlgebraicRing r) { this(r, r.algebraic.getZERO()); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public RealAlgebraicRing factory() { return ring; } /** * Copy this. * @see edu.jas.structure.Element#copy() */ @Override public RealAlgebraicNumber copy() { return new RealAlgebraicNumber(ring, number); } /** * Return a BigRational approximation of this Element. * @return a BigRational approximation of this. * @see edu.jas.arith.Rational#getRational() */ public BigRational getRational() { return magnitude(); } /** * Is RealAlgebraicNumber zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return number.isZERO(); //return magnitude().isZERO(); } /** * Is RealAlgebraicNumber one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return number.isONE(); } /** * Is RealAlgebraicNumber unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { return number.isUnit(); } /** * Is RealAlgebraicNumber a root of unity. * @return true if |this**i| == 1, for some 0 < i ≤ deg(modul), else * false. */ public boolean isRootOfUnity() { return number.isRootOfUnity(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { return "{ " + number.toString() + " }"; } return "Real" + number.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case return number.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * RealAlgebraicNumber comparison. * @param b RealAlgebraicNumber. * @return real sign(this-b). */ @Override public int compareTo(RealAlgebraicNumber b) { int s = 0; if (number.ring != b.number.ring) { // avoid compareTo if possible s = number.ring.modul.compareTo(b.number.ring.modul); System.out.println("s_mod = " + s); } if (s != 0) { return s; } s = this.subtract(b).signum(); // avoid subtract if possible //System.out.println("s_real = " + s); return s; } /** * RealAlgebraicNumber comparison. * @param b AlgebraicNumber. * @return polynomial sign(this-b). */ public int compareTo(AlgebraicNumber b) { int s = number.compareTo(b); System.out.println("s_algeb = " + s); return s; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof RealAlgebraicNumber)) { return false; } RealAlgebraicNumber a = (RealAlgebraicNumber) b; if (!ring.equals(a.ring)) { return false; } return number.equals(a.number); } /** * Hash code for this RealAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * number.val.hashCode() + ring.hashCode(); } /** * RealAlgebraicNumber absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public RealAlgebraicNumber abs() { if (this.signum() < 0) { return new RealAlgebraicNumber(ring, number.negate()); } return this; } /** * RealAlgebraicNumber summation. * @param S RealAlgebraicNumber. * @return this+S. */ public RealAlgebraicNumber sum(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.sum(S.number)); } /** * RealAlgebraicNumber summation. * @param c coefficient. * @return this+c. */ public RealAlgebraicNumber sum(GenPolynomial c) { return new RealAlgebraicNumber(ring, number.sum(c)); } /** * RealAlgebraicNumber summation. * @param c polynomial. * @return this+c. */ public RealAlgebraicNumber sum(C c) { return new RealAlgebraicNumber(ring, number.sum(c)); } /** * RealAlgebraicNumber negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public RealAlgebraicNumber negate() { return new RealAlgebraicNumber(ring, number.negate()); } /** * RealAlgebraicNumber signum. Note: Modifies ring.root eventually. * @see edu.jas.structure.RingElem#signum() * @return real signum(this). */ public int signum() { Interval v = ring.engine.invariantSignInterval(ring.root, ring.algebraic.modul, number.val); ring.setRoot(v); return ring.engine.realIntervalSign(v, ring.algebraic.modul, number.val); } /** * RealAlgebraicNumber half interval. */ public void halfInterval() { Interval v = ring.engine.halfInterval(ring.root, ring.algebraic.modul); //System.out.println("old v = " + ring.root + ", new v = " + v); ring.setRoot(v); } /** * RealAlgebraicNumber floor. * @return floor of this. */ public BigInteger floor() { BigRational f = magnitude(); BigInteger fi = f.floor(); // todo: ensure int not in interval return fi; } /** * RealAlgebraicNumber magnitude. * @return |this|. */ public BigRational magnitude() { Interval v = ring.engine.invariantMagnitudeInterval(ring.root, ring.algebraic.modul, number.val, ring.getEps()); //System.out.println("old v = " + ring.root + ", new v = " + v); ring.setRoot(v); C ev = ring.engine.realIntervalMagnitude(v, ring.algebraic.modul, number.val); //, ring.eps); //Interval ev = ring.engine.realIntervalMagnitudeInterval(v, ring.algebraic.modul, number.val); BigRational er = ev.getRational(); //middle(). return er; } /** * RealAlgebraicNumber magnitude. * @return |this| as big decimal. */ public BigDecimal decimalMagnitude() { return new BigDecimal(magnitude()); } /** * RealAlgebraicNumber subtraction. * @param S RealAlgebraicNumber. * @return this-S. */ public RealAlgebraicNumber subtract(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.subtract(S.number)); } /** * RealAlgebraicNumber division. * @param S RealAlgebraicNumber. * @return this/S. */ public RealAlgebraicNumber divide(RealAlgebraicNumber S) { return multiply(S.inverse()); } /** * RealAlgebraicNumber inverse. * @see edu.jas.structure.RingElem#inverse() * @throws NotInvertibleException if the element is not invertible. * @return S with S = 1/this if defined. */ public RealAlgebraicNumber inverse() { return new RealAlgebraicNumber(ring, number.inverse()); } /** * RealAlgebraicNumber remainder. * @param S RealAlgebraicNumber. * @return this - (this/S)*S. */ public RealAlgebraicNumber remainder(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.remainder(S.number)); } /** * Quotient and remainder by division of this by S. * @param S a RealAlgebraicNumber * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public RealAlgebraicNumber[] quotientRemainder(RealAlgebraicNumber S) { return new RealAlgebraicNumber[] { divide(S), remainder(S) }; } /** * RealAlgebraicNumber multiplication. * @param S RealAlgebraicNumber. * @return this*S. */ public RealAlgebraicNumber multiply(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.multiply(S.number)); } /** * RealAlgebraicNumber multiplication. * @param c coefficient. * @return this*c. */ public RealAlgebraicNumber multiply(C c) { return new RealAlgebraicNumber(ring, number.multiply(c)); } /** * RealAlgebraicNumber multiplication. * @param c polynomial. * @return this*c. */ public RealAlgebraicNumber multiply(GenPolynomial c) { return new RealAlgebraicNumber(ring, number.multiply(c)); } /** * RealAlgebraicNumber monic. * @return this with monic value part. */ public RealAlgebraicNumber monic() { return new RealAlgebraicNumber(ring, number.monic()); } /** * RealAlgebraicNumber greatest common divisor. * @param S RealAlgebraicNumber. * @return gcd(this,S). */ public RealAlgebraicNumber gcd(RealAlgebraicNumber S) { return new RealAlgebraicNumber(ring, number.gcd(S.number)); } /** * RealAlgebraicNumber extended greatest common divisor. * @param S RealAlgebraicNumber. * @return [ gcd(this,S), a, b ] with a*this + b*S = gcd(this,S). */ @SuppressWarnings("unchecked") public RealAlgebraicNumber[] egcd(RealAlgebraicNumber S) { AlgebraicNumber[] aret = number.egcd(S.number); RealAlgebraicNumber[] ret = new RealAlgebraicNumber[3]; ret[0] = new RealAlgebraicNumber(ring, aret[0]); ret[1] = new RealAlgebraicNumber(ring, aret[1]); ret[2] = new RealAlgebraicNumber(ring, aret[2]); return ret; } } java-algebra-system-2.7.200/src/edu/jas/root/RealAlgebraicRing.java000066400000000000000000000247411445075545500250120ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Real algebraic number factory class based on AlgebraicNumberRing with * RingFactory interface. Objects of this class are immutable with the exception * of the isolating intervals. * @author Heinz Kredel */ public class RealAlgebraicRing & Rational> /*extends AlgebraicNumberRing*/ implements RingFactory> { /** * Representing AlgebraicNumberRing. */ public final AlgebraicNumberRing algebraic; /** * Isolating interval for a real root. Note: interval may shrink * eventually. */ /*package*/Interval root; /** * Precision of the isolating rectangle for a complex root. */ public static final int PRECISION = BigDecimal.DEFAULT_PRECISION; /** * Precision of the isolating interval for a real root. */ protected BigRational eps; /** * Real root computation engine. */ public final RealRootsSturm engine; /** * The constructor creates a RealAlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial. * @param root isolating interval for a real root. */ public RealAlgebraicRing(GenPolynomial m, Interval root) { algebraic = new AlgebraicNumberRing(m); this.root = root; engine = new RealRootsSturm(); if (m.ring.characteristic().signum() > 0) { throw new RuntimeException("characteristic not zero"); } BigRational e = new BigRational(10L); //m.ring.coFac.fromInteger(10L); e = e.power(-PRECISION / 2); // better not too much for speed eps = e; //BigRational.ONE; // initially } /** * The constructor creates a RealAlgebraicNumber factory object from a * GenPolynomial objects module. * @param m module GenPolynomial. * @param root isolating interval for a real root. * @param isField indicator if m is prime. */ public RealAlgebraicRing(GenPolynomial m, Interval root, boolean isField) { this(m, root); setField(isField); } /** * Get the interval for the real root. Note: interval may shrink * later. * @return real root isolating interval */ public synchronized Interval getRoot() { return root; } /** * Set a refined interval for the real root. Note: interval may * shrink eventually. * @param v interval. */ public synchronized void setRoot(Interval v) { assert root.contains(v) : "root contains v"; this.root = v; } /** * Get the epsilon. * @return eps. */ public synchronized BigRational getEps() { return this.eps; } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(C e) { setEps(e.getRational()); } /** * Set a new epsilon. * @param e epsilon. */ public synchronized void setEps(BigRational e) { this.eps = e; //algebraic.ring.coFac.parse(e.toString()); } /** * Refine root. */ public synchronized void refineRoot() { refineRoot(eps); } /** * Refine root. * @param e epsilon. */ public synchronized void refineRoot(BigRational e) { root = engine.refineInterval(root, algebraic.modul, e); eps = e; } /** * RealAlgebraicRing half interval. */ public void halfInterval() { Interval v = engine.halfInterval(root, algebraic.modul); //System.out.println("old v = " + ring.root + ", new v = " + v); setRoot(v); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return algebraic.isFinite(); } /** * Copy RealAlgebraicNumber element c. * @param c * @return a copy of c. */ public RealAlgebraicNumber copy(RealAlgebraicNumber c) { return new RealAlgebraicNumber(this, c.number); } /** * Copy this RealAlgebraicRing. * @return a copy of this. */ public RealAlgebraicRing copy() { if (algebraic.isField()) { return new RealAlgebraicRing(algebraic.modul, root, algebraic.isField()); } return new RealAlgebraicRing(algebraic.modul, root); } /** * Get the zero element. * @return 0 as RealAlgebraicNumber. */ public RealAlgebraicNumber getZERO() { return new RealAlgebraicNumber(this, algebraic.getZERO()); } /** * Get the one element. * @return 1 as RealAlgebraicNumber. */ public RealAlgebraicNumber getONE() { return new RealAlgebraicNumber(this, algebraic.getONE()); } /** * Get the generating element. * @return alpha as RealAlgebraicNumber. */ public RealAlgebraicNumber getGenerator() { return new RealAlgebraicNumber(this, algebraic.getGenerator()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> agens = algebraic.generators(); List> gens = new ArrayList>(agens.size()); for (AlgebraicNumber a : agens) { gens.add(getZERO().sum(a.getVal())); } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return algebraic.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return algebraic.isAssociative(); } /** * Query if this ring is a field. * @return true if algebraic is prime, else false. */ public boolean isField() { return algebraic.isField(); } /** * Assert that this ring is a field. * @param isField true if this ring is a field, else false. */ public void setField(boolean isField) { algebraic.setField(isField); } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return algebraic.characteristic(); } /** * Get a RealAlgebraicNumber element from a BigInteger value. * @param a BigInteger. * @return a RealAlgebraicNumber. */ public RealAlgebraicNumber fromInteger(java.math.BigInteger a) { return new RealAlgebraicNumber(this, algebraic.fromInteger(a)); } /** * Get a RealAlgebraicNumber element from a BigRational value. * @param a BigRational. * @return a RealAlgebraicNumber. */ public RealAlgebraicNumber fromRational(BigRational a) { return new RealAlgebraicNumber(this, algebraic.parse(a.toString())); } /** * Get a RealAlgebraicNumber element from a long value. * @param a long. * @return a RealAlgebraicNumber. */ public RealAlgebraicNumber fromInteger(long a) { return new RealAlgebraicNumber(this, algebraic.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { return "RealAlgebraicRing[ " + algebraic.modul.toString() + " in " + root + " | isField=" + algebraic.isField() + " :: " + algebraic.ring.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "RealN( " + algebraic.modul.toScript() + ", " + root.toScript() //+ ", " + algebraic.isField() //+ ", " + algebraic.ring.toScript() + " )"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof RealAlgebraicRing)) { return false; } RealAlgebraicRing a = (RealAlgebraicRing) b; return algebraic.equals(a.algebraic) && root.equals(a.root); } /** * Hash code for this RealAlgebraicNumber. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * algebraic.hashCode() + root.hashCode(); } /** * RealAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random integer mod modul. */ public RealAlgebraicNumber random(int n) { return new RealAlgebraicNumber(this, algebraic.random(n)); } /** * RealAlgebraicNumber random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random integer mod modul. */ public RealAlgebraicNumber random(int n, Random rnd) { return new RealAlgebraicNumber(this, algebraic.random(n, rnd)); } /** * Parse RealAlgebraicNumber from String. * @param s String. * @return RealAlgebraicNumber from s. */ public RealAlgebraicNumber parse(String s) { return new RealAlgebraicNumber(this, algebraic.parse(s)); } /** * Parse RealAlgebraicNumber from Reader. * @param r Reader. * @return next RealAlgebraicNumber from r. */ public RealAlgebraicNumber parse(Reader r) { return new RealAlgebraicNumber(this, algebraic.parse(r)); } } java-algebra-system-2.7.200/src/edu/jas/root/RealArithUtil.java000066400000000000000000000041361445075545500242220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.ArithUtil; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; /** * Real arithmetic utilities. * @author Heinz Kredel */ public class RealArithUtil { private static final Logger logger = LogManager.getLogger(RealArithUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Continued fraction. * @param A real algebraic number. * @param M approximation, length of continued fraction. * @return continued fraction for A. */ public static List continuedFraction(RealAlgebraicNumber A, final int M) { List cf = new ArrayList(); if (A == null) { return cf; } RealAlgebraicRing fac = A.ring; if (A.isZERO()) { cf.add(BigInteger.ZERO); return cf; } if (A.isONE()) { cf.add(BigInteger.ONE); return cf; } RealAlgebraicNumber x = A; BigInteger q = new BigInteger(x.floor()); cf.add(q); RealAlgebraicNumber xd = x.subtract(fac.fromInteger(q.val)); int m = 0; while (!xd.isZERO() && m++ < M) { //System.out.println("xd = " + xd + " :: " + xd.ring); // + ", q = " + q + ", x = " + x); //System.out.println("xd = " + xd.decimalMagnitude()); x = xd.inverse(); q = new BigInteger(x.floor()); cf.add(q); xd = x.subtract(fac.fromInteger(q.val)); } if (debug) { logger.info("cf = {}", cf); } return cf; } /** * Continued fraction approximation. * @param A continued fraction. * @return ratonal number approximation for A. */ public static BigRational continuedFractionApprox(List A) { return ArithUtil.continuedFractionApprox(A); } } java-algebra-system-2.7.200/src/edu/jas/root/RealRootTuple.java000066400000000000000000000122111445075545500242430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.structure.GcdRingElem; /** * RealAlgebraicNumber root tuple. * @param coefficient type. * @author Heinz Kredel */ public class RealRootTuple & Rational> implements Serializable { /** * Tuple of RealAlgebraicNumbers. */ public final List> tuple; /** * Constructor. * @param t list of roots. */ public RealRootTuple(List> t) { if (t == null) { throw new IllegalArgumentException("null tuple not allowed"); } tuple = t; } /** * String representation of tuple. * @see java.lang.Object#toString() */ @Override public String toString() { return tuple.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Rectangle. */ public String toScript() { // Python case StringBuffer sb = new StringBuffer("["); boolean first = true; for (RealAlgebraicNumber r : tuple) { if (first) { first = false; } else { sb.append(","); } sb.append(r.toScript()); } sb.append("]"); return sb.toString(); } /** * Contains a point. * @param c real root tuple representing a point. * @return true if c is contained in this root tuple, else false. */ public boolean contains(RealRootTuple c) { return contains(c.tuple); } /** * Contains a point. * @param c list of real algebraic numbers representing a point. * @return true if c is contained in this root tuple, else false. */ public boolean contains(List> c) { int i = 0; for (RealAlgebraicNumber r : tuple) { RealAlgebraicNumber cn = c.get(i++); boolean t = r.ring.root.contains(cn.ring.root); if (!t) { return false; } } return true; } /** * Random point of real root tuple. * @return a random point contained in this real root tuple. */ public List randomPoint() { List tp = new ArrayList(tuple.size()); for (RealAlgebraicNumber r : tuple) { C rp = r.ring.root.randomPoint(); tp.add(rp); } return tp; } /** * Refine root isolating intervals. * @param eps desired interval length. */ public void refineRoot(BigRational eps) { for (RealAlgebraicNumber r : tuple) { r.ring.refineRoot(eps); } return; } /** * Copy this. * @return a copy of this. */ public RealRootTuple copy() { return new RealRootTuple(new ArrayList>(tuple)); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { RealRootTuple a = null; try { a = (RealRootTuple) b; } catch (ClassCastException e) { } if (a == null) { return false; } return tuple.equals(a.tuple); } /** * Hash code for this Rectangle. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return tuple.hashCode(); } /** * Rational approximation of each coordinate. * @return list of coordinate points. */ public List getRational() { List center = new ArrayList(tuple.size()); for (RealAlgebraicNumber rr : tuple) { BigRational r = rr.getRational(); center.add(r); } return center; } /** * Decimal approximation of each coordinate. * @return list of coordinate points. */ public List decimalMagnitude() { List center = new ArrayList(tuple.size()); for (RealAlgebraicNumber rr : tuple) { BigDecimal r = rr.decimalMagnitude(); center.add(r); } return center; } /** * Rational Length. * @return max |v_i|; */ public BigRational rationalLength() { BigRational len = new BigRational(); for (RealAlgebraicNumber rr : tuple) { BigRational r = rr.ring.root.rationalLength(); int s = len.compareTo(r); if (s < 0) { len = r; } } return len; } /** * Signum. * @return ?; */ public int signum() { int s = 0; for (RealAlgebraicNumber rr : tuple) { int rs = rr.signum(); if (rs != 0) { s = rs; } } return s; } } java-algebra-system-2.7.200/src/edu/jas/root/RealRoots.java000066400000000000000000000067601445075545500234300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Real roots interface. * @param coefficient type. * @author Heinz Kredel */ public interface RealRoots & Rational> extends Serializable { /** * Real root bound. With f(M) * f(-M) != 0. * @param f univariate polynomial. * @return M such that -M < root(f) > M. */ public C realRootBound(GenPolynomial f); /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @return a list of isolating intervals for the real roots of f. */ public List> realRoots(GenPolynomial f); /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @param eps requested intervals length. * @return a list of isolating intervals v such that |v| < eps. */ public List> realRoots(GenPolynomial f, C eps); /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @param eps requested intervals length. * @return a list of isolating intervals v such that |v| < eps. */ public List> realRoots(GenPolynomial f, BigRational eps); /** * Sign changes on interval bounds. * @param iv root isolating interval with f(left) * f(right) != 0. * @param f univariate polynomial. * @return true if f(left) * f(right) < 0, else false */ public boolean signChange(Interval iv, GenPolynomial f); /** * Number of real roots in interval. * @param iv interval with f(left) * f(right) != 0. * @param f univariate polynomial. * @return number of real roots of f in I. */ public long realRootCount(Interval iv, GenPolynomial f); /** * Refine interval. * @param iv root isolating interval with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a new interval v such that |v| < eps. */ public Interval refineInterval(Interval iv, GenPolynomial f, BigRational eps); /** * Refine intervals. * @param V list of isolating intervals with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested intervals length. * @return a list of new intervals v such that |v| < eps. */ public List> refineIntervals(List> V, GenPolynomial f, BigRational eps); /** * Real algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return sign(g(v)), with v a new interval contained in iv such that g(v) * != 0. */ public int realSign(Interval iv, GenPolynomial f, GenPolynomial g); /** * Real algebraic number magnitude. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @param eps length limit for interval length. * @return g(iv). */ public C realMagnitude(Interval iv, GenPolynomial f, GenPolynomial g, BigRational eps); } java-algebra-system-2.7.200/src/edu/jas/root/RealRootsAbstract.java000066400000000000000000000664121445075545500251140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; /** * Real roots abstract class. * @param coefficient type. * @author Heinz Kredel */ public abstract class RealRootsAbstract & Rational> implements RealRoots { private static final Logger logger = LogManager.getLogger(RealRootsAbstract.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Real root bound. With f(-M) * f(M) != 0. * @param f univariate polynomial. * @return M such that -M < root(f) < M. */ public C realRootBound(GenPolynomial f) { if (f == null) { return null; } RingFactory cfac = f.ring.coFac; C M = cfac.getONE(); if (f.isZERO()) { return M; } if (f.isConstant()) { M = f.leadingBaseCoefficient().abs().sum(cfac.getONE()); return M; } C a = f.leadingBaseCoefficient().abs(); for (C c : f.getMap().values()) { C d = c.abs().divide(a); if (M.compareTo(d) < 0) { M = d; } } BigRational r = M.getRational(); logger.info("rational root bound: {}", r); BigInteger i = new BigInteger(r.numerator().divide(r.denominator())); i = i.sum(BigInteger.ONE); // ceiling M = cfac.fromInteger(i.getVal()); M = M.sum(f.ring.coFac.getONE()); logger.info("integer root bound: {}", M); return M; } /** * Magnitude bound. * @param iv interval. * @param f univariate polynomial. * @return B such that |f(c)| < B for c in iv. */ @SuppressWarnings("unchecked") public C magnitudeBound(Interval iv, GenPolynomial f) { if (f == null) { return null; } if (f.isZERO()) { return f.ring.coFac.getONE(); } if (f.isConstant()) { return f.leadingBaseCoefficient().abs(); } GenPolynomial fa = f.map(new UnaryFunctor() { public C eval(C a) { return a.abs(); } }); //System.out.println("fa = " + fa); C M = iv.left.abs(); if (M.compareTo(iv.right.abs()) < 0) { M = iv.right.abs(); } //System.out.println("M = " + M); RingFactory cfac = f.ring.coFac; C B = PolyUtil. evaluateMain(cfac, fa, M); // works also without this case, only for optimization // to use rational number interval end points // can fail if real root is in interval [r,r+1] // for too low precision or too big r, since r is approximation //if ((Object) B instanceof RealAlgebraicNumber) { // RealAlgebraicNumber Br = (RealAlgebraicNumber) B; // BigRational r = Br.magnitude(); // B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); //} BigRational r = B.getRational(); B = cfac.fromInteger(r.numerator()).divide(cfac.fromInteger(r.denominator())); //System.out.println("B = " + B); return B; } /** * Real minimal root bound. * @param f univariate polynomial. * @return M such that abs(xi) > M for f(xi) == 0. */ public C realMinimalRootBound(GenPolynomial f) { if (f == null) { return null; } RingFactory cfac = f.ring.coFac; // maxNorm root bound BigRational mr = f.maxNorm().getRational().sum(BigRational.ONE); BigRational di = mr.sum(BigRational.ONE).inverse(); C B = cfac.fromInteger(di.numerator()).divide(cfac.fromInteger(di.denominator())); //System.out.println("B = " + B + ", sign(B) = " + B.signum()); return B; } /** * Real minimal root separation. * @param f univariate polynomial. * @return M such that abs(xi-xj) > M for roots xi, xj of f. */ public C realMinimalRootSeparation(GenPolynomial f) { if (f == null) { return null; } RingFactory cfac = f.ring.coFac; // sumNorm root bound BigRational pr = f.sumNorm().getRational(); pr = pr.sum(BigRational.ONE); BigRational sep = BigRational.ZERO; long n = f.degree(); if (n > 0) { sep = pr.power(2 * n).multiply(pr.fromInteger(n).power(n + 1)).inverse(); } //System.out.println("sep = " + sep + ", sign(sep) = " + sep.signum()); C M = cfac.fromInteger(sep.numerator()).divide(cfac.fromInteger(sep.denominator())); return M; } /** * Bi-section point. * @param iv interval with f(left) * f(right) != 0. * @param f univariate polynomial, non-zero. * @return a point c in the interval iv such that f(c) != 0. */ public C bisectionPoint(Interval iv, GenPolynomial f) { if (f == null) { return null; } RingFactory cfac = f.ring.coFac; C two = cfac.fromInteger(2); C c = iv.left.sum(iv.right); c = c.divide(two); if (f.isZERO() || f.isConstant()) { return c; } C m = PolyUtil. evaluateMain(cfac, f, c); while (m.isZERO()) { C d = iv.left.sum(c); d = d.divide(two); if (d.equals(c)) { d = iv.right.sum(c); d = d.divide(two); if (d.equals(c)) { throw new RuntimeException("should not happen " + iv); } } c = d; m = PolyUtil. evaluateMain(cfac, f, c); //System.out.println("c = " + c); } //System.out.println("c = " + c); return c; } /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @return a list of isolating intervals for the real roots of f. */ public abstract List> realRoots(GenPolynomial f); /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @param eps requested intervals length. * @return a list of isolating intervals v such that |v| < eps. */ public List> realRoots(GenPolynomial f, C eps) { return realRoots(f, eps.getRational()); } /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @param eps requested intervals length. * @return a list of isolating intervals v such that |v| < eps. */ public List> realRoots(GenPolynomial f, BigRational eps) { List> iv = realRoots(f); return refineIntervals(iv, f, eps); } /** * Sign changes on interval bounds. * @param iv root isolating interval with f(left) * f(right) != 0. * @param f univariate polynomial. * @return true if f(left) * f(right) < 0, else false */ public boolean signChange(Interval iv, GenPolynomial f) { if (f == null) { return false; } RingFactory cfac = f.ring.coFac; C l = PolyUtil. evaluateMain(cfac, f, iv.left); C r = PolyUtil. evaluateMain(cfac, f, iv.right); return l.signum() * r.signum() < 0; } /** * Number of real roots in interval. * @param iv interval with f(left) * f(right) != 0. * @param f univariate polynomial. * @return number of real roots of f in I. */ public abstract long realRootCount(Interval iv, GenPolynomial f); /** * Half interval. * @param iv root isolating interval with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @return a new interval v such that |v| < |iv|/2. */ public Interval halfInterval(Interval iv, GenPolynomial f) { if (f == null || f.isZERO()) { return iv; } BigRational len = iv.rationalLength(); BigRational two = len.factory().fromInteger(2); BigRational eps = len.divide(two); return refineInterval(iv, f, eps); } /** * Refine interval. * @param iv root isolating interval with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a new interval v such that |v| < eps. */ public Interval refineInterval(Interval iv, GenPolynomial f, BigRational eps) { if (f == null || f.isZERO() || f.isConstant() || eps == null) { return iv; } if (iv.rationalLength().compareTo(eps) < 0) { return iv; } RingFactory cfac = f.ring.coFac; C two = cfac.fromInteger(2); Interval v = iv; while (v.rationalLength().compareTo(eps) >= 0) { C c = v.left.sum(v.right); c = c.divide(two); //System.out.println("c = " + c); //c = RootUtil.bisectionPoint(v,f); if (PolyUtil. evaluateMain(cfac, f, c).isZERO()) { v = new Interval(c, c); break; } Interval iv1 = new Interval(v.left, c); if (signChange(iv1, f)) { v = iv1; } else { v = new Interval(c, v.right); } } return v; } /** * Refine intervals. * @param V list of isolating intervals with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested intervals length. * @return a list of new intervals v such that |v| < eps. */ public List> refineIntervals(List> V, GenPolynomial f, BigRational eps) { if (f == null || f.isZERO() || f.isConstant() || eps == null) { return V; } List> IV = new ArrayList>(); for (Interval v : V) { Interval iv = refineInterval(v, f, eps); IV.add(iv); } return IV; } /** * Invariant interval for algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return v with v a new interval contained in iv such that g(v) != 0. */ public abstract Interval invariantSignInterval(Interval iv, GenPolynomial f, GenPolynomial g); /** * Real algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0, * with iv such that g(iv) != 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return sign(g(iv)) . */ public int realIntervalSign(Interval iv, GenPolynomial f, GenPolynomial g) { if (g == null || g.isZERO()) { return 0; } if (f == null || f.isZERO() || f.isConstant()) { return g.signum(); } if (g.isConstant()) { return g.signum(); } RingFactory cfac = f.ring.coFac; C c = iv.left.sum(iv.right); c = c.divide(cfac.fromInteger(2)); C ev = PolyUtil. evaluateMain(cfac, g, c); //System.out.println("ev = " + ev); return ev.signum(); } /** * Real algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return sign(g(v)), with v a new interval contained in iv such that g(v) * != 0. */ public int realSign(Interval iv, GenPolynomial f, GenPolynomial g) { if (g == null || g.isZERO()) { return 0; } if (f == null || f.isZERO() || f.isConstant()) { return g.signum(); } if (g.isConstant()) { return g.signum(); } Interval v = invariantSignInterval(iv, f, g); return realIntervalSign(v, f, g); } /** * Invariant interval for algebraic number magnitude. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @param eps length limit for interval length. * @return v with v a new interval contained in iv such that |g(a) - g(b)| * < eps for a, b in v in iv. */ public Interval invariantMagnitudeInterval(Interval iv, GenPolynomial f, GenPolynomial g, BigRational eps) { Interval v = iv; if (g == null || g.isZERO()) { return v; } if (g.isConstant()) { return v; } if (f == null || f.isZERO() || f.isConstant()) { // ? return v; } GenPolynomial gp = PolyUtil. baseDerivative(g); //System.out.println("g = " + g); //System.out.println("gp = " + gp); C B = magnitudeBound(iv, gp); //System.out.println("B = " + B); RingFactory cfac = f.ring.coFac; C two = cfac.fromInteger(2); while (B.multiply(v.length()).getRational().compareTo(eps) >= 0) { C c = v.left.sum(v.right); c = c.divide(two); Interval im = new Interval(c, v.right); if (signChange(im, f)) { v = im; } else { v = new Interval(v.left, c); } //System.out.println("v = " + v.toDecimal()); } return v; } /** * Real algebraic number magnitude. * @param iv root isolating interval for f, with f(left) * f(right) < 0, * with iv such that |g(a) - g(b)| < eps for a, b in iv. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return g(iv) . */ public C realIntervalMagnitude(Interval iv, GenPolynomial f, GenPolynomial g) { if (g.isZERO() || g.isConstant()) { return g.leadingBaseCoefficient(); } RingFactory cfac = f.ring.coFac; C evl = PolyUtil. evaluateMain(cfac, g, iv.left); C evr = PolyUtil. evaluateMain(cfac, g, iv.right); C ev = evl; if (evl.compareTo(evr) <= 0) { ev = evr; } //System.out.println("ev = " + ev + ", evl = " + evl + ", evr = " + evr + ", iv = " + iv); return ev; } /** * Real algebraic number magnitude. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @param eps length limit for interval length. * @return g(iv) . */ public C realMagnitude(Interval iv, GenPolynomial f, GenPolynomial g, BigRational eps) { if (g.isZERO() || g.isConstant()) { return g.leadingBaseCoefficient(); } Interval v = invariantMagnitudeInterval(iv, f, g, eps); return realIntervalMagnitude(v, f, g); } /** * Real algebraic number magnitude. * @param iv root isolating interval for f, with f(left) * f(right) < 0, * with iv such that |g(a) - g(b)| < eps for a, b in iv. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return Interval( g(iv.left), g(iv.right) ) . */ public Interval realIntervalMagnitudeInterval(Interval iv, GenPolynomial f, GenPolynomial g) { if (g.isZERO() || g.isConstant()) { return iv; } RingFactory cfac = f.ring.coFac; C evl = PolyUtil. evaluateMain(cfac, g, iv.left); C evr = PolyUtil. evaluateMain(cfac, g, iv.right); Interval ev = new Interval(evr, evl); if (evl.compareTo(evr) <= 0) { ev = new Interval(evl, evr); } System.out.println("ev = " + ev + ", iv = " + iv); return ev; } /** * Approximate real root. * @param iv real root isolating interval with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a decimal approximation d such that |d-v| < eps, for f(v) = 0, * v real. */ public BigDecimal approximateRoot(Interval iv, GenPolynomial f, BigRational eps) throws NoConvergenceException { if (iv == null) { throw new IllegalArgumentException("null interval not allowed"); } BigDecimal d = iv.toDecimal(); if (f == null || f.isZERO() || f.isConstant() || eps == null) { return d; } if (iv.rationalLength().compareTo(eps) < 0) { return d; } BigDecimal left = new BigDecimal(iv.left.getRational()); BigDecimal right = new BigDecimal(iv.right.getRational()); BigRational reps = eps.getRational(); BigDecimal e = new BigDecimal(reps); BigDecimal q = new BigDecimal("0.25"); //System.out.println("left = " + left); //System.out.println("right = " + right); e = e.multiply(d); // relative error //System.out.println("e = " + e); BigDecimal dc = BigDecimal.ONE; // polynomials with decimal coefficients GenPolynomialRing dfac = new GenPolynomialRing(dc, f.ring); GenPolynomial df = PolyUtil. decimalFromRational(dfac, f); GenPolynomial fp = PolyUtil. baseDerivative(f); GenPolynomial dfp = PolyUtil. decimalFromRational(dfac, fp); // Newton Raphson iteration: x_{n+1} = x_n - f(x_n)/f'(x_n) int i = 0; final int MITER = 50; int dir = 0; while (i++ < MITER) { BigDecimal fx = PolyUtil. evaluateMain(dc, df, d); // f(d) if (fx.isZERO()) { return d; } BigDecimal fpx = PolyUtil. evaluateMain(dc, dfp, d); // f'(d) if (fpx.isZERO()) { throw new NoConvergenceException("zero derivative should not happen"); } BigDecimal x = fx.divide(fpx); BigDecimal dx = d.subtract(x); //System.out.println("dx = " + dx + ", d = " + d); if (d.subtract(dx).abs().compareTo(e) <= 0) { return dx; } while (dx.compareTo(left) < 0 || dx.compareTo(right) > 0) { // dx < left: dx - left < 0 // dx > right: dx - right > 0 //System.out.println("trying to leave interval"); if (i++ > MITER) { // dx > right: dx - right > 0 throw new NoConvergenceException("no convergence after " + i + " steps"); } if (i > MITER / 2 && dir == 0) { BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); d = sd; x = sd.getZERO(); logger.info("trying new random starting point {}", d); i = 0; dir = 1; } if (i > MITER / 2 && dir == 1) { BigDecimal sd = new BigDecimal(iv.randomPoint().getRational()); d = sd; x = sd.getZERO(); logger.info("trying new random starting point {}", d); //i = 0; dir = 2; // end } x = x.multiply(q); // x * 1/4 dx = d.subtract(x); //System.out.println(" x = " + x); //System.out.println("dx = " + dx); } d = dx; } throw new NoConvergenceException("no convergence after " + i + " steps"); } /** * Approximate real roots. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return a list of decimal approximations d such that |d-v| < eps for * all real v with f(v) = 0. */ public List approximateRoots(GenPolynomial f, BigRational eps) { List> iv = realRoots(f); List roots = new ArrayList(iv.size()); for (Interval i : iv) { BigDecimal r = null; //approximateRoot(i, f, eps); roots.add(r); while (r == null) { try { r = approximateRoot(i, f, eps); roots.add(r); } catch (NoConvergenceException e) { // fall back to exact algorithm //System.out.println("" + e); BigRational len = i.rationalLength(); len = len.divide(len.factory().fromInteger(1000)); i = refineInterval(i, f, len); logger.info("fall back rootRefinement = {}", i); } } } return roots; } /** * Test if x is an approximate real root. * @param x approximate real root. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return true if x is a decimal approximation of a real v with f(v) = 0 * with |d-v| < eps, else false. */ public boolean isApproximateRoot(BigDecimal x, GenPolynomial f, C eps) { if (x == null) { throw new IllegalArgumentException("null root not allowed"); } if (f == null || f.isZERO() || f.isConstant() || eps == null) { return true; } BigDecimal e = new BigDecimal(eps.getRational()); e = e.multiply(new BigDecimal("1000")); // relax BigDecimal dc = BigDecimal.ONE; // polynomials with decimal coefficients GenPolynomialRing dfac = new GenPolynomialRing(dc, f.ring); GenPolynomial df = PolyUtil. decimalFromRational(dfac, f); GenPolynomial fp = PolyUtil. baseDerivative(f); GenPolynomial dfp = PolyUtil. decimalFromRational(dfac, fp); // return isApproximateRoot(x, df, dfp, e); } /** * Test if x is an approximate real root. * @param x approximate real root. * @param f univariate polynomial, non-zero. * @param fp univariate polynomial, non-zero, derivative of f. * @param eps requested interval length. * @return true if x is a decimal approximation of a real v with f(v) = 0 * with |d-v| < eps, else false. */ public boolean isApproximateRoot(BigDecimal x, GenPolynomial f, GenPolynomial fp, BigDecimal eps) { if (x == null) { throw new IllegalArgumentException("null root not allowed"); } if (f == null || f.isZERO() || f.isConstant() || eps == null) { return true; } BigDecimal dc = BigDecimal.ONE; // only for clarity // f(x) BigDecimal fx = PolyUtil. evaluateMain(dc, f, x); //System.out.println("fx = " + fx); if (fx.isZERO()) { return true; } // f'(x) BigDecimal fpx = PolyUtil. evaluateMain(dc, fp, x); // f'(d) //System.out.println("fpx = " + fpx); if (fpx.isZERO()) { return false; } BigDecimal d = fx.divide(fpx); if (d.isZERO()) { return true; } if (d.abs().compareTo(eps) <= 0) { return true; } System.out.println("x = " + x); System.out.println("d = " + d); return false; } /** * Test if each x in R is an approximate real root. * @param R ist of approximate real roots. * @param f univariate polynomial, non-zero. * @param eps requested interval length. * @return true if each x in R is a decimal approximation of a real v with * f(v) = 0 with |d-v| < eps, else false. */ public boolean isApproximateRoot(List R, GenPolynomial f, BigRational eps) { if (R == null) { throw new IllegalArgumentException("null root not allowed"); } if (f == null || f.isZERO() || f.isConstant() || eps == null) { return true; } BigDecimal e = new BigDecimal(eps.getRational()); e = e.multiply(new BigDecimal("1000")); // relax BigDecimal dc = BigDecimal.ONE; // polynomials with decimal coefficients GenPolynomialRing dfac = new GenPolynomialRing(dc, f.ring); GenPolynomial df = PolyUtil. decimalFromRational(dfac, f); GenPolynomial fp = PolyUtil. baseDerivative(f); GenPolynomial dfp = PolyUtil. decimalFromRational(dfac, fp); for (BigDecimal x : R) { if (!isApproximateRoot(x, df, dfp, e)) { return false; } } return true; } /** * Fourier sequence. * @param f univariate polynomial. * @return (f, f', ..., f(n)) a Fourier sequence for f. */ public List> fourierSequence(GenPolynomial f) { List> S = new ArrayList>(); if (f == null || f.isZERO()) { return S; } long d = f.degree(); GenPolynomial F = f; S.add(F); while (d-- > 0) { GenPolynomial G = PolyUtil. baseDerivative(F); F = G; S.add(F); } //System.out.println("F = " + F); return S; } /** * Thom sign sequence. * @param f univariate polynomial. * @param v interval for a real root, f(v.left) * f(v.right) < 0. * @return (s1, s2, ..., sn) = (sign(f'(v)), .... sign(f(n)(v))) a Thom sign * sequence for the real root in v of f. */ public List signSequence(GenPolynomial f, Interval v) { List S = new ArrayList(); GenPolynomial fp = PolyUtil. baseDerivative(f); List> fs = fourierSequence(fp); for (GenPolynomial p : fs) { int s = realSign(v, f, p); S.add(s); } return S; } /** * Root number. * @param f univariate polynomial. * @param v interval for a real root, f(v.left) * f(v.right) < 0. * @return r the number of this root in the sequence a1 < a2 < ..., * < am of all real roots of f */ public Long realRootNumber(GenPolynomial f, Interval v) { C M = realRootBound(f); Interval iv = new Interval(M.negate(), v.right); long r = realRootCount(iv, f); if (r <= 0) { logger.warn("no real root in interval {}", v); } return r; } } java-algebra-system-2.7.200/src/edu/jas/root/RealRootsSturm.java000066400000000000000000000331131445075545500244530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Real root isolation using Sturm sequences. * @param coefficient type. * @author Heinz Kredel */ public class RealRootsSturm & Rational> extends RealRootsAbstract { private static final Logger logger = LogManager.getLogger(RealRootsSturm.class); private static final boolean debug = logger.isDebugEnabled(); /** * Sturm sequence. * @param f univariate polynomial. * @return a Sturm sequence for f. */ public List> sturmSequence(GenPolynomial f) { List> S = new ArrayList>(); if (f == null || f.isZERO()) { return S; } if (f.isConstant()) { S.add(f.monic()); return S; } GenPolynomial F = f; S.add(F); GenPolynomial G = PolyUtil. baseDerivative(f); while (!G.isZERO()) { GenPolynomial r = F.remainder(G); F = G; G = r.negate(); S.add(F/*.monic()*/); } //System.out.println("F = " + F); if (F.isConstant()) { return S; } // make squarefree List> Sp = new ArrayList>(S.size()); for (GenPolynomial p : S) { p = p.divide(F); Sp.add(p); } return Sp; } /** * Isolating intervals for the real roots. * @param f univariate polynomial. * @return a list of isolating intervals for the real roots of f. */ @SuppressWarnings("cast") @Override public List> realRoots(GenPolynomial f) { List> R = new ArrayList>(); if (f == null) { return R; } GenPolynomialRing pfac = f.ring; if (f.isZERO()) { C z = pfac.coFac.getZERO(); R.add(new Interval(z)); return R; } // check trailing degree ExpVector et = f.trailingExpVector(); if (!et.isZERO()) { GenPolynomial tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); f = PolyUtil. basePseudoDivide(f, tr); R.add(new Interval(pfac.coFac.getZERO())); } if (f.isConstant()) { return R; } if (f.degree(0) == 1L) { C z = f.monic().trailingBaseCoefficient().negate(); R.add(new Interval(z)); return R; } //if (f.degree(0) == 2L) ... GenPolynomial F = f; C M = realRootBound(F); // M != 0, since >= 2 Interval iv = new Interval(M.negate(), M); //System.out.println("iv = " + iv); List> S = sturmSequence(F); //System.out.println("S = " + S); //System.out.println("f_S = " + S.get(0)); List> Rp = realRoots(iv, S); if (!(((Object) f.ring.coFac) instanceof BigRational)) { //logger.info("realRoots bound: {}", iv); logger.info("realRoots: {}", Rp); } R.addAll(Rp); return R; } /** * Isolating intervals for the real roots. * @param iv interval with f(left) * f(right) != 0. * @param S sturm sequence for f and I. * @return a list of isolating intervals for the real roots of f in I. */ public List> realRoots(Interval iv, List> S) { List> R = new ArrayList>(); GenPolynomial f = S.get(0); // squarefree part if (f.isZERO()) { C z = f.leadingBaseCoefficient(); if (!iv.contains(z)) { throw new IllegalArgumentException( "root not in interval: f = " + f + ", iv = " + iv + ", z = " + z); } Interval iv1 = new Interval(z); R.add(iv1); return R; } if (f.isConstant()) { return R; //throw new IllegalArgumentException("f has no root: f = " + f + ", iv = " + iv); } if (f.degree(0) == 1L) { C z = f.monic().trailingBaseCoefficient().negate(); if (!iv.contains(z)) { return R; //throw new IllegalArgumentException("root not in interval: f = " + f + ", iv = " + iv + ", z = " + z); } Interval iv1 = new Interval(z); R.add(iv1); return R; } //System.out.println("iv = " + iv); // check sign variations at interval bounds long v = realRootCount(iv, S); //System.out.println("v = " + v); if (v == 0) { return R; } if (v == 1) { iv = excludeZero(iv, S); R.add(iv); return R; } // now v > 1 // bi-sect interval, such that f(c) != 0 C c = bisectionPoint(iv, f); //System.out.println("c = " + c); // recursion on both sub-intervals Interval iv1 = new Interval(iv.left, c); Interval iv2 = new Interval(c, iv.right); List> R1 = realRoots(iv1, S); //System.out.println("R1 = " + R1); if (debug) { logger.info("R1 = {}", R1); } List> R2 = realRoots(iv2, S); //System.out.println("R2 = " + R2); if (debug) { logger.info("R2 = {}", R2); } // refine isolating intervals if adjacent if (R1.isEmpty()) { R.addAll(R2); return R; } if (R2.isEmpty()) { R.addAll(R1); return R; } iv1 = R1.get(R1.size() - 1); // last iv2 = R2.get(0); // first if (iv1.right.compareTo(iv2.left) < 0) { R.addAll(R1); R.addAll(R2); return R; } // now iv1.right == iv2.left //System.out.println("iv1 = " + iv1); //System.out.println("iv2 = " + iv2); R1.remove(iv1); R2.remove(iv2); while (iv1.right.equals(iv2.left)) { C d1 = bisectionPoint(iv1, f); C d2 = bisectionPoint(iv2, f); Interval iv11 = new Interval(iv1.left, d1); Interval iv12 = new Interval(d1, iv1.right); Interval iv21 = new Interval(iv2.left, d2); Interval iv22 = new Interval(d2, iv2.right); boolean b11 = signChange(iv11, f); boolean b12 = signChange(iv12, f); // TODO check unnecessary //boolean b21 = signChange(iv21, f); // TODO check unused or unnecessary boolean b22 = signChange(iv22, f); if (b11) { iv1 = iv11; if (b22) { iv2 = iv22; } else { iv2 = iv21; } break; // done, refine } if (b22) { iv2 = iv22; if (b12) { iv1 = iv12; } else { iv1 = iv11; } break; // done, refine } iv1 = iv12; iv2 = iv21; //System.out.println("iv1 = " + iv1); //System.out.println("iv2 = " + iv2); } R.addAll(R1); R.add(iv1); R.add(iv2); R.addAll(R2); return R; } /** * Number of real roots in interval. * @param iv interval with f(left) * f(right) != 0. * @param S sturm sequence for f and I. * @return number of real roots of f in I. */ public long realRootCount(Interval iv, List> S) { // check sign variations at interval bounds GenPolynomial f = S.get(0); // squarefree part //System.out.println("iv = " + iv); RingFactory cfac = f.ring.coFac; List l = PolyUtil. evaluateMain(cfac, S, iv.left); List r = PolyUtil. evaluateMain(cfac, S, iv.right); long v = RootUtil. signVar(l) - RootUtil. signVar(r); //System.out.println("v = " + v); if (v < 0L) { v = -v; } return v; } /** * Number of real roots in interval. * @param iv interval with f(left) * f(right) != 0. * @param f univariate polynomial. * @return number of real roots of f in I. */ @Override public long realRootCount(Interval iv, GenPolynomial f) { if (f == null || f.isConstant()) { // ? return 0L; } if (f.isZERO()) { C z = f.leadingBaseCoefficient(); if (!iv.contains(z)) { return 0L; } return 1L; } List> S = sturmSequence(f); return realRootCount(iv, S); } /** * Invariant interval for algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param g univariate polynomial, gcd(f,g) == 1. * @return v with v a new interval contained in iv such that g(w) != 0 for w * in v. */ @Override public Interval invariantSignInterval(Interval iv, GenPolynomial f, GenPolynomial g) { Interval v = iv; if (g == null || g.isZERO()) { //throw new IllegalArgumentException("g == 0"); return v; } if (g.isConstant()) { return v; } if (f == null || f.isZERO()) { // ? || f.isConstant() throw new IllegalArgumentException("f == 0"); //return v; } List> Sg = sturmSequence(g.monic()); Interval ivp = invariantSignInterval(iv, f, Sg); return ivp; } /** * Invariant interval for algebraic number sign. * @param iv root isolating interval for f, with f(left) * f(right) < 0. * @param f univariate polynomial, non-zero. * @param Sg Sturm sequence for (f,g), a univariate polynomial with gcd(f,g) == * 1. * @return v with v a new interval contained in iv such that g(w) != 0 for w * in v. */ public Interval invariantSignInterval(Interval iv, GenPolynomial f, List> Sg) { Interval v = iv; GenPolynomial g = Sg.get(0); if (g == null || g.isZERO()) { return v; } if (g.isConstant()) { return v; } if (f == null || f.isZERO()) { // ? || f.isConstant() return v; } RingFactory cfac = f.ring.coFac; C two = cfac.fromInteger(2); while (true) { long n = realRootCount(v, Sg); logger.debug("n = {}", n); if (n == 0) { return v; } C c = v.left.sum(v.right); c = c.divide(two); Interval im = new Interval(c, v.right); if (signChange(im, f)) { v = im; } else { v = new Interval(v.left, c); } } // return v; } /** * Exclude zero, old version. * @param iv root isolating interval with f(left) * f(right) < 0. * @param S sturm sequence for f and I. * @return a new interval v such that v < 0 or v > 0. */ public Interval excludeZeroOld(Interval iv, List> S) { if (S == null || S.isEmpty()) { return iv; } C zero = S.get(0).ring.coFac.getZERO(); if (!iv.contains(zero)) { return iv; } Interval vn = new Interval(iv.left, zero); if (realRootCount(vn,S) == 1) { return vn; } vn = new Interval(zero, iv.right); return vn; } /** * Exclude zero v2. * @param iv root isolating interval with f(left) * f(right) < 0. * @param S sturm sequence for f and I. * @return a new interval v such that v < 0 or v > 0 or v == 0. */ public Interval excludeZero(Interval iv, List> S) { if (S == null || S.isEmpty()) { return iv; } GenPolynomial f = S.get(0); C zero = f.ring.coFac.getZERO(); if (!iv.contains(zero)) { // left <= 0 <= right return iv; } if (iv.left.isZERO() && iv.right.isZERO()) { // (0, 0) return iv; } C m = realMinimalRootBound(f); Interval vi = iv; Interval vn; if (vi.left.isZERO()) { vi = new Interval(m, vi.right); } else if (vi.right.isZERO()) { vi = new Interval(vi.left, m.negate()); } vn = new Interval(vi.left, m.negate()); // l != 0 if (realRootCount(vn, S) == 1) { return vn; } vn = new Interval(m, vi.right); // r != 0 if (realRootCount(vn, S) == 1) { return vn; } vn = new Interval(zero); logger.warn("interval is zero: iv = {}, trail = {}, vi = {}, vn = {}", iv, f.trailingExpVector().degree(), vi, vn); return vn; } } java-algebra-system-2.7.200/src/edu/jas/root/Rectangle.java000066400000000000000000000252031445075545500234130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.io.Serializable; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.structure.ElemFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Rectangle. For example isolating rectangle for complex roots. * @param coefficient type. * @author Heinz Kredel */ public class Rectangle & Rational> implements Serializable { /** * rectangle corners. */ public final Complex[] corners; /** * Constructor. * @param c array of corners. */ @SuppressWarnings("unchecked") /*package*/ Rectangle(Complex[] c) { if (c.length < 5) { corners = (Complex[]) new Complex[5]; for (int i = 0; i < 4; i++) { corners[i] = c[i]; } } else { corners = c; } if (corners[4] == null) { corners[4] = corners[0]; } } /** * Constructor. * @param mid corner. */ @SuppressWarnings("unchecked") public Rectangle(Complex mid) { this(mid, mid); } /** * Constructor. * @param sw corner. * @param ne corner. */ @SuppressWarnings("unchecked") public Rectangle(Complex sw, Complex ne) { this(new Complex(sw.ring, sw.getRe(), ne.getIm()), sw, new Complex(sw.ring, ne.getRe(), sw.getIm()), ne); } /** * Constructor. * *
     *  nw|0 ne|3
     *  sw|1 se|2
     * 
* * @param nw corner. * @param sw corner. * @param se corner. * @param ne corner. */ @SuppressWarnings("unchecked") public Rectangle(Complex nw, Complex sw, Complex se, Complex ne) { this((Complex[]) new Complex[] { nw, sw, se, ne }); } /** * String representation of Rectangle. * @see java.lang.Object#toString() */ @Override public String toString() { //return "[" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + "]"; return "[" + corners[1] + ", " + corners[3] + "]"; //return centerApprox() + " = [" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + "]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Rectangle. */ public String toScript() { // Python case //return "(" + corners[0] + ", " + corners[1] + ", " + corners[2] + ", " + corners[3] + ")"; return "(" + corners[1].toScript() + ", " + corners[3].toScript() + ")"; } /** * Get north west corner. * @return north west corner of this rectangle. */ public Complex getNW() { return corners[0]; } /** * Get south west corner. * @return south west corner of this rectangle. */ public Complex getSW() { return corners[1]; } /** * Get south east corner. * @return south east corner of this rectangle. */ public Complex getSE() { return corners[2]; } /** * Get north east corner. * @return north east corner of this rectangle. */ public Complex getNE() { return corners[3]; } /** * Exchange NW corner. * @param c new NW corner. * @return rectangle with north west corner c of this rectangle. */ public Rectangle exchangeNW(Complex c) { Complex d = getSE(); Complex sw = new Complex(c.factory(), c.getRe(), d.getIm()); Complex ne = new Complex(c.factory(), d.getRe(), c.getIm()); return new Rectangle(c, sw, d, ne); } /** * Exchange SW corner. * @param c new SW corner. * @return rectangle with south west corner c of this rectangle. */ public Rectangle exchangeSW(Complex c) { Complex d = getNE(); Complex nw = new Complex(c.factory(), c.getRe(), d.getIm()); Complex se = new Complex(c.factory(), d.getRe(), c.getIm()); return new Rectangle(nw, c, se, d); } /** * Exchange SE corner. * @param c new SE corner. * @return rectangle with south east corner c of this rectangle. */ public Rectangle exchangeSE(Complex c) { Complex d = getNW(); Complex sw = new Complex(c.factory(), d.getRe(), c.getIm()); Complex ne = new Complex(c.factory(), c.getRe(), d.getIm()); return new Rectangle(d, sw, c, ne); } /** * Exchange NE corner. * @param c new NE corner. * @return rectangle with north east corner c of this rectangle. */ public Rectangle exchangeNE(Complex c) { Complex d = getSW(); Complex nw = new Complex(c.factory(), d.getRe(), c.getIm()); Complex se = new Complex(c.factory(), c.getRe(), d.getIm()); return new Rectangle(nw, d, se, c); } /** * Contains a point. * @param c point. * @return true if c is contained in this rectangle, else false. */ public boolean contains(Complex c) { Complex ll = getSW(); Complex ur = getNE(); // ?? Fix ?? getSW(); C cre = c.getRe(); C cim = c.getIm(); return cre.compareTo(ll.getRe()) >= 0 && cim.compareTo(ll.getIm()) >= 0 && cre.compareTo(ur.getRe()) <= 0 && cim.compareTo(ur.getIm()) <= 0; } /** * Contains a rectangle. * @param r rectangle. * @return true if r is contained in this rectangle, else false. */ public boolean contains(Rectangle r) { return contains(r.getSW()) && contains(r.getNE()); // && contains(r.getSE()) && contains(r.getNW()) } /** * Random point of recatangle. * @return a random point contained in this rectangle. */ public Complex randomPoint() { Complex sw = getSW(); Complex se = getSE(); Complex nw = getNW(); Complex r = sw.factory().random(13); C dr = se.getRe().subtract(sw.getRe()); // >= 0 C di = nw.getIm().subtract(sw.getIm()); // >= 0 C rr = r.getRe().abs(); C ri = r.getIm().abs(); C one = ((RingFactory) dr.factory()).getONE(); if (!rr.isZERO()) { if (rr.compareTo(one) > 0) { rr = rr.inverse(); } } if (!ri.isZERO()) { if (ri.compareTo(one) > 0) { ri = ri.inverse(); } } // 0 <= rr, ri <= 1 rr = rr.multiply(dr); ri = ri.multiply(di); Complex rp = new Complex(sw.factory(), rr, ri); //System.out.println("rp = " + rp); rp = sw.sum(rp); return rp; } /** * Copy this. * @return a copy of this. */ public Rectangle copy() { return new Rectangle(corners); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof Rectangle)) { return false; } Rectangle a = null; try { a = (Rectangle) b; } catch (ClassCastException e) { return false; } for (int i = 0; i < 4; i++) { if (!corners[i].equals(a.corners[i])) { return false; } } return true; } /** * Hash code for this Rectangle. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hc = 0; for (int i = 0; i < 3; i++) { hc += 37 * corners[i].hashCode(); } return 37 * hc + corners[3].hashCode(); } /** * Complex center. * @return r + i m of the center. */ public Complex getCenter() { C r = corners[2].getRe().subtract(corners[1].getRe()); C m = corners[0].getIm().subtract(corners[1].getIm()); ElemFactory rf = r.factory(); C two = rf.fromInteger(2); r = r.divide(two); m = m.divide(two); r = corners[1].getRe().sum(r); m = corners[1].getIm().sum(m); return new Complex(corners[0].factory(), r, m); } /** * Complex of BigRational approximation of center. * @return r + i m as rational approximation of the center. */ public Complex getRationalCenter() { Complex cm = getCenter(); BigRational rs = cm.getRe().getRational(); BigRational ms = cm.getIm().getRational(); ComplexRing cf = new ComplexRing(rs.factory()); Complex c = new Complex(cf, rs, ms); return c; } /** * Complex of BigDecimal approximation of center. * @return r + i m as decimal approximation of the center. */ public Complex getDecimalCenter() { Complex rc = getRationalCenter(); BigDecimal rd = new BigDecimal(rc.getRe()); BigDecimal md = new BigDecimal(rc.getIm()); ComplexRing cf = new ComplexRing(rd.factory()); Complex c = new Complex(cf, rd, md); return c; } /** * Approximation of center. * @return r + i m as string of decimal approximation of the center. */ public String centerApprox() { Complex c = getDecimalCenter(); StringBuffer s = new StringBuffer(); s.append("[ "); s.append(c.getRe().toString()); s.append(" i "); s.append(c.getIm().toString()); s.append(" ]"); return s.toString(); } /** * Length. * @return |ne-sw|**2; */ public C length() { Complex m = corners[3].subtract(corners[1]); return m.norm().getRe(); } /** * Rational Length. * @return rational(|ne-sw|**2); */ public BigRational rationalLength() { //BigRational r = new BigRational(length().toString()); return length().getRational(); } /** * Length real side. * @return |re(ne)-re(sw)|; */ public C lengthReal() { C m = corners[3].getRe().subtract(corners[1].getRe()); return m.abs(); } /** * Length imaginary side. * @return |im(ne)-im(sw)|; */ public C lengthImag() { C m = corners[3].getIm().subtract(corners[1].getIm()); return m.abs(); } } java-algebra-system-2.7.200/src/edu/jas/root/RootFactory.java000066400000000000000000000616531445075545500237730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.FactorFactory; import edu.jas.ufd.SquarefreeAbstract; import edu.jas.ufd.SquarefreeFactory; /** * Roots factory. Generate real and complex algebraic numbers from root * intervals or rectangles. * @author Heinz Kredel */ public class RootFactory { /** * Is real algebraic number a root of a polynomial. * @param f univariate polynomial. * @param r real algebraic number. * @return true, if f(r) == 0, else false; */ public static & Rational> boolean isRoot(GenPolynomial f, RealAlgebraicNumber r) { RealAlgebraicRing rr = r.factory(); GenPolynomialRing> rfac = new GenPolynomialRing>(rr, f.factory()); GenPolynomial> p; p = PolyUtilRoot. convertToRealCoefficients(rfac, f); RealAlgebraicNumber a = PolyUtil.> evaluateMain(rr, p, r); return a.isZERO(); } /** * Real algebraic numbers. * @param f univariate polynomial. * @return a list of different real algebraic numbers. */ public static & Rational> List> realAlgebraicNumbers( GenPolynomial f) { RealRoots rr = new RealRootsSturm(); SquarefreeAbstract engine = SquarefreeFactory. getImplementation(f.ring.coFac); Map, Long> SF = engine.squarefreeFactors(f); //Set> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry, Long> me : SF.entrySet()) { GenPolynomial sp = me.getKey(); List> iv = rr.realRoots(sp); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(sp, I); RealAlgebraicNumber rn = rar.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(rn); } } } return list; } /** * Real algebraic numbers. * @param f univariate polynomial. * @param eps rational precision. * @return a list of different real algebraic numbers. */ public static & Rational> List> realAlgebraicNumbers( GenPolynomial f, BigRational eps) { RealRoots rr = new RealRootsSturm(); SquarefreeAbstract engine = SquarefreeFactory. getImplementation(f.ring.coFac); Map, Long> SF = engine.squarefreeFactors(f); //Set> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry, Long> me : SF.entrySet()) { GenPolynomial sp = me.getKey(); List> iv = rr.realRoots(sp, eps); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(sp, I); rar.setEps(eps); RealAlgebraicNumber rn = rar.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(rn); } } } return list; } /** * Real algebraic numbers from a field. * @param f univariate polynomial. * @return a list of different real algebraic numbers from a field. */ public static & Rational> List> realAlgebraicNumbersField( GenPolynomial f) { RealRoots rr = new RealRootsSturm(); FactorAbstract engine = FactorFactory. getImplementation(f.ring.coFac); Map, Long> SF = engine.baseFactors(f); //Set> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry, Long> me : SF.entrySet()) { GenPolynomial sp = me.getKey(); List> iv = rr.realRoots(sp); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(sp, I, true);//field RealAlgebraicNumber rn = rar.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(rn); } } } return list; } /** * Real algebraic numbers from a field. * @param f univariate polynomial. * @param eps rational precision. * @return a list of different real algebraic numbers from a field. */ public static & Rational> List> realAlgebraicNumbersField( GenPolynomial f, BigRational eps) { RealRoots rr = new RealRootsSturm(); FactorAbstract engine = FactorFactory. getImplementation(f.ring.coFac); Map, Long> SF = engine.baseFactors(f); //Set> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry, Long> me : SF.entrySet()) { GenPolynomial sp = me.getKey(); List> iv = rr.realRoots(sp, eps); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(sp, I, true);//field rar.setEps(eps); RealAlgebraicNumber rn = rar.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(rn); } } } return list; } /** * Real algebraic numbers from a irreducible polynomial. * @param f univariate irreducible polynomial. * @return a list of different real algebraic numbers from a field. */ public static & Rational> List> realAlgebraicNumbersIrred( GenPolynomial f) { RealRoots rr = new RealRootsSturm(); List> list = new ArrayList>(); List> iv = rr.realRoots(f); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(f, I, true);//field RealAlgebraicNumber rn = rar.getGenerator(); list.add(rn); } return list; } /** * Real algebraic numbers from a irreducible polynomial. * @param f univariate irreducible polynomial. * @param eps rational precision. * @return a list of different real algebraic numbers from a field. */ public static & Rational> List> realAlgebraicNumbersIrred( GenPolynomial f, BigRational eps) { RealRoots rr = new RealRootsSturm(); List> list = new ArrayList>(); List> iv = rr.realRoots(f, eps); for (Interval I : iv) { RealAlgebraicRing rar = new RealAlgebraicRing(f, I, true);//field rar.setEps(eps); RealAlgebraicNumber rn = rar.getGenerator(); list.add(rn); } return list; } /** * Is complex algebraic number a root of a polynomial. * @param f univariate polynomial. * @param r complex algebraic number. * @return true, if f(r) == 0, else false; */ public static & Rational> boolean isRoot(GenPolynomial f, ComplexAlgebraicNumber r) { ComplexAlgebraicRing cr = r.factory(); GenPolynomialRing> cfac = new GenPolynomialRing>( cr, f.factory()); GenPolynomial> p; p = PolyUtilRoot. convertToComplexCoefficients(cfac, f); ComplexAlgebraicNumber a = PolyUtil.> evaluateMain(cr, p, r); return a.isZERO(); } /** * Is complex algebraic number a root of a complex polynomial. * @param f univariate complex polynomial. * @param r complex algebraic number. * @return true, if f(r) == 0, else false; */ public static & Rational> boolean isRootComplex(GenPolynomial> f, ComplexAlgebraicNumber r) { ComplexAlgebraicRing cr = r.factory(); GenPolynomialRing> cfac = new GenPolynomialRing>( cr, f.factory()); GenPolynomial> p; p = PolyUtilRoot. convertToComplexCoefficientsFromComplex(cfac, f); ComplexAlgebraicNumber a = PolyUtil.> evaluateMain(cr, p, r); return a.isZERO(); } /** * Is complex algebraic number a real root of a polynomial. * @param f univariate polynomial. * @param c complex algebraic number. * @param r real algebraic number. * @return true, if f(c) == 0 and c == r, else false; */ public static & Rational> boolean isRealRoot(GenPolynomial f, ComplexAlgebraicNumber c, RealAlgebraicNumber r) { boolean t = isRoot(f, c) && isRoot(f, r); if (!t) { return t; } Rectangle rc = c.ring.root; Interval ivci = new Interval(rc.getSW().getIm(), rc.getNE().getIm()); t = ivci.contains(f.ring.coFac.getZERO()); if (!t) { return t; } //System.out.println("imag = 0"); Interval ivc = new Interval(rc.getSW().getRe(), rc.getNE().getRe()); Interval ivr = r.ring.root; // disjoint intervals if (ivc.right.compareTo(ivr.left) < 0 || ivr.right.compareTo(ivc.left) < 0) { //System.out.println("disjoint: ivc = " + ivc + ", ivr = " + ivr); return false; } //System.out.println("not disjoint"); // full containement t = ivc.contains(ivr) || ivr.contains(ivc); if (t) { return t; } //System.out.println("with overlap"); // overlap, refine to smaller interval C left = ivc.left; if (left.compareTo(ivr.left) > 0) { left = ivr.left; } C right = ivc.right; if (right.compareTo(ivr.right) < 0) { right = ivr.right; } Interval ref = new Interval(left, right); //System.out.println("refined interval " + ref); RealRoots reng = r.ring.engine; //new RealRootsSturm(); long z = reng.realRootCount(ref, f); if (z != 1) { return false; } ComplexRing cr = rc.getSW().ring; Complex sw = new Complex(cr, left, rc.getSW().getIm()); Complex ne = new Complex(cr, right, rc.getNE().getIm()); //Complex sw = new Complex(cr, left, cr.ring.getZERO()); //Complex ne = new Complex(cr, right, cr.ring.getZERO()); Rectangle rec = new Rectangle(sw, ne); //System.out.println("refined rectangle " + rec); ComplexRoots ceng = c.ring.engine; //new ComplexRootsSturm(); GenPolynomial> p = PolyUtilRoot. complexFromAny(f); try { z = ceng.complexRootCount(rec, p); } catch (InvalidBoundaryException e) { System.out.println("should not happen, rec = " + rec + ", p = " + p); e.printStackTrace(); z = 0; } //System.out.println("complexRootCount: " + z); if (z != 1) { return false; } return true; } /** * Is complex decimal number a real root of a polynomial. * @param f univariate polynomial. * @param c complex decimal number. * @param r real decimal number. * @param eps desired precision. * @return true, if f(c) == 0 and c == r, else false; */ public static & Rational> boolean isRealRoot(GenPolynomial f, Complex c, BigDecimal r, BigRational eps) { BigDecimal e = new BigDecimal(eps); if (c.getIm().abs().compareTo(e) > 0) { return false; } if (c.getRe().subtract(r).abs().compareTo(e) > 0) { return false; } GenPolynomialRing> cfac = new GenPolynomialRing>( new ComplexRing(f.ring.coFac), f.ring); GenPolynomial> cf = PolyUtil. complexFromAny(cfac, f); ComplexRing cd = new ComplexRing(e); GenPolynomialRing> rfac = new GenPolynomialRing>(cd, cf.ring); GenPolynomial> cdf = PolyUtil. complexDecimalFromRational(rfac, cf); Complex z = PolyUtil.evaluateMain(cd, cdf, c); if (z.isZERO()) { return true; } if (z.getIm().abs().compareTo(e) <= 0 && z.getRe().abs().compareTo(e) <= 0) { return true; } System.out.println("z != 0: " + z); return false; } /** * Complex algebraic numbers. * @param f univariate polynomial. * @return a list of different complex algebraic numbers. */ public static & Rational> List> complexAlgebraicNumbersComplex( GenPolynomial> f) { ComplexRoots cr = new ComplexRootsSturm(f.ring.coFac); SquarefreeAbstract> engine = SquarefreeFactory .> getImplementation(f.ring.coFac); Map>, Long> SF = engine.squarefreeFactors(f); //Set>> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry>, Long> me : SF.entrySet()) { GenPolynomial> sp = me.getKey(); List> iv = cr.complexRoots(sp); for (Rectangle I : iv) { ComplexAlgebraicRing car = new ComplexAlgebraicRing(sp, I); ComplexAlgebraicNumber cn = car.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(cn); } } } return list; } /** * Complex algebraic numbers. * @param f univariate polynomial. * @param eps rational precision. * @return a list of different complex algebraic numbers. */ public static & Rational> List> complexAlgebraicNumbersComplex( GenPolynomial> f, BigRational eps) { ComplexRoots cr = new ComplexRootsSturm(f.ring.coFac); SquarefreeAbstract> engine = SquarefreeFactory .> getImplementation(f.ring.coFac); Map>, Long> SF = engine.squarefreeFactors(f); //Set>> S = SF.keySet(); List> list = new ArrayList>(); for (Map.Entry>, Long> me : SF.entrySet()) { GenPolynomial> sp = me.getKey(); List> iv = cr.complexRoots(sp); for (Rectangle I : iv) { Rectangle Iv = I; try { Iv = cr.complexRootRefinement(I, sp, eps); } catch (InvalidBoundaryException e) { e.printStackTrace(); } ComplexAlgebraicRing car = new ComplexAlgebraicRing(sp, Iv); car.setEps(eps); ComplexAlgebraicNumber cn = car.getGenerator(); long mult = me.getValue(); for (int i = 0; i < mult; i++) { list.add(cn); } } } return list; } /** * Complex algebraic numbers. * @param f univariate (rational) polynomial. * @return a list of different complex algebraic numbers. */ public static & Rational> List> complexAlgebraicNumbers( GenPolynomial f) { GenPolynomial> fc = PolyUtilRoot. complexFromAny(f); return complexAlgebraicNumbersComplex(fc); } /** * Complex algebraic numbers. * @param f univariate (rational) polynomial. * @param eps rational precision. * @return a list of different complex algebraic numbers. */ public static & Rational> List> complexAlgebraicNumbers( GenPolynomial f, BigRational eps) { GenPolynomial> fc = PolyUtilRoot. complexFromAny(f); return complexAlgebraicNumbersComplex(fc, eps); } /** * Filter real roots from complex roots. * @param f univariate polynomial. * @param c list of complex algebraic numbers. * @param r list of real algebraic numbers. * @return c minus the real roots from r */ public static & Rational> List> filterOutRealRoots( GenPolynomial f, List> c, List> r) { if (c.isEmpty()) { return c; } if (r.isEmpty()) { return c; } List> cmr = new ArrayList>(); if (c.size() == r.size() /*&& r.size() == f.degree()*/ ) { return cmr; } List> rl = new LinkedList>(r); for (ComplexAlgebraicNumber cn : c) { RealAlgebraicNumber rm = null; // ~boolean for (RealAlgebraicNumber rn : rl) { if (isRealRoot(f, cn, rn)) { //System.out.println("filterOutRealRoots, cn = " + cn + ", rn = " + rn); rm = rn; break; // remove from r } } if (rm == null) { cmr.add(cn); } else { rl.remove(rm); } } return cmr; } /** * Filter real roots from complex roots. * @param f univariate polynomial. * @param c list of complex decimal numbers. * @param r list of real decimal numbers. * @param eps desired precision. * @return c minus the real roots from r */ public static & Rational> List> filterOutRealRoots( GenPolynomial f, List> c, List r, BigRational eps) { if (c.isEmpty()) { return c; } if (r.isEmpty()) { return c; } List> cmr = new ArrayList>(); if (c.size() == r.size() /*&& r.size() == f.degree()*/ ) { return cmr; } List rl = new LinkedList(r); for (Complex cn : c) { BigDecimal rm = null; // ~boolean for (BigDecimal rn : rl) { if (isRealRoot(f, cn, rn, eps)) { //System.out.println("filterOutRealRoots, cn = " + cn + ", rn = " + rn); rm = rn; break; // remove from r } } if (rm == null) { cmr.add(cn); } else { rl.remove(rm); } } return cmr; } /** * Roots as real and complex algebraic numbers. * @param f univariate polynomial. * @return container of real and complex algebraic numbers. */ public static & Rational> AlgebraicRoots algebraicRoots(GenPolynomial f) { List> rl = realAlgebraicNumbers(f); List> cl = complexAlgebraicNumbers(f); GenPolynomial> cf = null; if (!cl.isEmpty()) { cf = cl.get(0).ring.algebraic.modul; } cl = filterOutRealRoots(f, cl, rl); AlgebraicRoots ar = new AlgebraicRoots(f, cf, rl, cl); return ar; } /** * Roots of unity of real and complex algebraic numbers. * @param ar container of real and complex algebraic numbers. * @return container of real and complex algebraic numbers which are roots * of unity. */ public static & Rational> AlgebraicRoots rootsOfUnity(AlgebraicRoots ar) { List> rl = new ArrayList>(); for (RealAlgebraicNumber r : ar.real) { if (r.isRootOfUnity()) { rl.add(r); } } List> cl = new ArrayList>(); for (ComplexAlgebraicNumber c : ar.complex) { if (c.isRootOfUnity()) { cl.add(c); } } AlgebraicRoots ur = new AlgebraicRoots(ar.p, ar.cp, rl, cl); return ur; } /** * Root refinement of real and complex algebraic numbers. * @param a container of real and complex algebraic numbers. * @param eps desired precision for root intervals and rectangles. */ public static & Rational> void rootRefine(AlgebraicRoots a, BigRational eps) { for (RealAlgebraicNumber r : a.real) { r.ring.refineRoot(eps); } for (ComplexAlgebraicNumber c : a.complex) { c.ring.refineRoot(eps); } return; // a or void? } /** * Roots as real and complex decimal numbers. * @param f univariate polynomial. * @param eps desired precision. * @return container of real and complex decimal numbers. */ public static & Rational> DecimalRoots decimalRoots(GenPolynomial f, BigRational eps) { RealRootsAbstract rengine = new RealRootsSturm(); List rl = rengine.approximateRoots(f, eps); GenPolynomial> fc = PolyUtilRoot. complexFromAny(f); ComplexRootsAbstract cengine = new ComplexRootsSturm(fc.ring.coFac); List> cl = cengine.approximateRoots(fc, eps); cl = filterOutRealRoots(f, cl, rl, eps); DecimalRoots ar = new DecimalRoots(f, fc, rl, cl); return ar; } /** * Roots as real and complex decimal numbers. * @param ar container for real and complex algebraic roots. * @param eps desired precision. * @return container of real and complex decimal numbers. */ public static & Rational> DecimalRoots decimalRoots(AlgebraicRoots ar, BigRational eps) { //no: rootRefine(ar, eps); RealRootsAbstract rengine = new RealRootsSturm(); List rl = new ArrayList(ar.real.size()); for (RealAlgebraicNumber r : ar.real) { try { BigDecimal d = rengine.approximateRoot(r.ring.root, ar.p, eps); rl.add(d); } catch (NoConvergenceException e) { System.out.println("should not happen: " + e); } } ComplexRootsAbstract cengine = new ComplexRootsSturm(ar.cp.ring.coFac); List> cl = new ArrayList>(ar.complex.size()); for (ComplexAlgebraicNumber c : ar.complex) { try { Complex d = cengine.approximateRoot(c.ring.root, ar.cp, eps); cl.add(d); } catch (NoConvergenceException e) { System.out.println("should not happen: " + e); } } DecimalRoots dr = new DecimalRoots(ar.p, ar.cp, rl, cl); return dr; } } java-algebra-system-2.7.200/src/edu/jas/root/RootUtil.java000066400000000000000000000110111445075545500232600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.Rational; import edu.jas.poly.Complex; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * Real root utilities. For example real root count. * @author Heinz Kredel */ public class RootUtil { private static final Logger logger = LogManager.getLogger(RootUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Count changes in sign. * @param coefficient type. * @param L list of coefficients. * @return number of sign changes in L. */ public static > long signVar(List L) { long v = 0; if (L == null || L.isEmpty()) { return v; } C A = L.get(0); for (int i = 1; i < L.size(); i++) { C B = L.get(i); while (B == null || B.signum() == 0) { i++; if (i >= L.size()) { return v; } B = L.get(i); } if (A.signum() * B.signum() < 0) { v++; } A = B; } return v; } /** * Parse interval for a real root from String. * @param s String, syntax: [left, right] or [mid]. * @return Interval from s. */ public static & Rational> Interval parseInterval(RingFactory fac, String s) { int r = s.length(); int el = s.indexOf("["); if (el >= 0) { int ri = s.indexOf("]"); if (ri > 0) { r = ri; } } else { el = -1; } //System.out.println("s = " + s); String iv = s.substring(el + 1, r).trim(); //System.out.println("iv = " + iv); int k = iv.indexOf(","); if (k < 0) { k = s.indexOf(" "); } if (k < 0) { C mid = fac.parse(iv); return new Interval(mid); } //System.out.println("k = " + k + ", len = " + iv.length()); String ls = iv.substring(0, k).trim(); String rs = iv.substring(k + 1, iv.length()).trim(); //System.out.println("ls = " + ls + ", rs = " + rs); C left = fac.parse(ls); C right = fac.parse(rs); logger.debug("Interval: left = {}, right = {}", left, right); return new Interval(left, right); } /** * Parse rectangle for a complex root from String. * @param s String, syntax: [south-west, north-east] or [mid]. * @return Interval from s. */ @SuppressWarnings("unchecked") public static & Rational> Rectangle parseRectangle(RingFactory> fac, String s) { int r = s.length(); int el = s.indexOf("["); if (el >= 0) { int ri = s.indexOf("]"); if (ri > 0) { r = ri; } } else { el = -1; } //System.out.println("s = " + s); String iv = s.substring(el + 1, r).trim(); //System.out.println("iv = " + iv); int k = iv.indexOf(","); if (k < 0) { k = s.indexOf(" "); } if (k < 0) { Complex mid = fac.parse(iv); return new Rectangle(mid); } //System.out.println("k = " + k + ", len = " + iv.length()); String ls = iv.substring(0, k).trim(); String rs = iv.substring(k + 1, iv.length()).trim(); //System.out.println("ls = " + ls + ", rs = " + rs); Object osw = fac.parse(ls); Object one = fac.parse(rs); //System.out.println("osw = " + osw + ", one = " + one); Complex sw; Complex ne; if (osw instanceof Complex) { sw = (Complex)osw; ne = (Complex)one; } else if (osw instanceof ComplexAlgebraicNumber) { ComplexAlgebraicNumber csw = (ComplexAlgebraicNumber) osw; ComplexAlgebraicNumber cne = (ComplexAlgebraicNumber) one; //System.out.println("csw::ring = " + csw.ring.algebraic.toScript()); sw = (Complex) csw.magnitude(); ne = (Complex) cne.magnitude(); } else { sw = fac.getONE().negate(); ne = fac.getONE(); } logger.debug("Rectangle: sw = {}, ne = {}", sw, ne); return new Rectangle(sw, ne); } } java-algebra-system-2.7.200/src/edu/jas/root/package.html000066400000000000000000000050171445075545500231260ustar00rootroot00000000000000 Real and Complex Root Computation package

Real and Complex Root Computation package.

This package contains classes for the computation of isolating and refining intervals of real roots and complex roots of univariate polynomials.

Method algebraicRoots() from class RootFactory computes both the real and complex algebraic roots of a univariate polynomial. Method decimalRoots() computes isolating intervals (or rectangles) for the roots and then uses a numerical algorithm to get a decimal approximation of the roots.

For the computation of real roots the main interface is RealRoots and main implementing class is RealRootsSturm. The implementation follows in part section 8.8 "Computation of real zeroes of Polynomial Systems" in Gröbner Bases, A computational Approach to Commutative Algebra, by Becker et al.
The class RealAlgebraicNumber is based on AlgebraicNumber with factory class RealAlgebraicRing based on AlgebraicNumberRing. They implement real algebraic numbers, which are algebraic numbers plus an isolating interval for a real root of the generator. RealRootsSturm can be applied to polynomials with real algebraic numbers as coefficients.

For the computation of complex roots the main interface is ComplexRoots and the main implementing class is ComplexRootsSturm. The implementation provides an exact infallible method which follows the numeric method of Wilf (see Wilf: A global bisection algorithm for computing the zeros of polynomials in the complex plane). It uses Sturm sequences following the Routh-Hurwitz Method to count the number of complex roots within a rectangle in the complex plane. For a (eventually) more efficient method see: Collins and Krandick: An efficient algorithm for infallible polynomial complex root isolation, in ISSAC'92.


Heinz Kredel

Last modified: Wed Aug 17 23:32:35 CEST 2016

$Id$

java-algebra-system-2.7.200/src/edu/jas/structure/000077500000000000000000000000001445075545500217175ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/structure/AbelianGroupElem.java000066400000000000000000000016221445075545500257360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Abelian group element interface. Defines the additive methods. * @param element type * @author Heinz Kredel */ public interface AbelianGroupElem> extends Element { /** * Test if this is zero. * @return true if this is 0, else false. */ public boolean isZERO(); /** * Signum. * @return the sign of this. */ public int signum(); /** * Sum of this and S. * @param S * @return this + S. */ public C sum(C S); //public T sum(T S); /** * Subtract S from this. * @param S * @return this - S. */ public C subtract(C S); /** * Negate this. * @return - this. */ public C negate(); /** * Absolute value of this. * @return |this|. */ public C abs(); } java-algebra-system-2.7.200/src/edu/jas/structure/AbelianGroupFactory.java000066400000000000000000000005301445075545500264600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Abelian group factory interface. Defines get zero. * @author Heinz Kredel */ public interface AbelianGroupFactory> extends ElemFactory { /** * Get the constant zero for the AbelianGroupElem. * @return 0. */ public C getZERO(); } java-algebra-system-2.7.200/src/edu/jas/structure/AlgebraElem.java000066400000000000000000000014351445075545500247250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Algabra element interface. * @param algebra type * @param scalar type * @author Heinz Kredel */ public interface AlgebraElem, C extends RingElem> extends RingElem { /** * Scalar multiplication. Multiply this by a scalar. * @param s scalar * @return this * s. */ public A scalarMultiply(C s); /** * Linear combination. * @param a scalar * @param b algebra element * @param s scalar * @return a * b + this * s. */ public A linearCombination(C a, A b, C s); /** * Linear combination. * @param b algebra element * @param s scalar * @return b + this * s. */ public A linearCombination(A b, C s); } java-algebra-system-2.7.200/src/edu/jas/structure/AlgebraFactory.java000066400000000000000000000013561445075545500254540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.util.List; /** * Algebra factory interface. Defines conversion from list of lists and sparse * random. * @param algebra type * @param coefficient type * @author Heinz Kredel */ public interface AlgebraFactory, C extends RingElem> extends RingFactory { /** * Convert list of list to matrix. * @param m list of list of ring elements. * @return a matrix with the elements from m. */ public A fromList(List> m); /** * Random Matrix. * @param k size of coefficients. * @param q fraction of non zero elements. * @return a random matrix. */ public A random(int k, float q); } java-algebra-system-2.7.200/src/edu/jas/structure/BinaryFunctor.java000066400000000000000000000006161445075545500253520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Binary functor interface. * @param element type * @param element type * @param element type * @author Heinz Kredel */ public interface BinaryFunctor, C2 extends Element, D extends Element> { /** * Evaluate. * @return evaluated element. */ public D eval(C1 c1, C2 c2); } java-algebra-system-2.7.200/src/edu/jas/structure/ElemFactory.java000066400000000000000000000041621445075545500247770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.io.Reader; import java.io.Serializable; import java.math.BigInteger; import java.util.List; import java.util.Random; /** * Element factory interface. Defines embedding of integers, parsing and random * element construction. * @author Heinz Kredel */ public interface ElemFactory> extends Serializable { /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. */ public List generators(); /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. */ public boolean isFinite(); /** * Get the Element for a. * @param a long * @return element corresponding to a. */ public C fromInteger(long a); /** * Get the Element for a. * @param a java.math.BigInteger. * @return element corresponding to a. */ public C fromInteger(BigInteger a); /** * Generate a random Element with size less equal to n. * @param n * @return a random element. */ public C random(int n); /** * Generate a random Element with size less equal to n. * @param n * @param random is a source for random bits. * @return a random element. */ public C random(int n, Random random); /** * Create a copy of Element c. * @param c * @return a copy of c. */ public C copy(C c); /** * Value from String. * @param s String. * @return a Element corresponding to s. */ default public C valueOf(String s) { return parse(s); } /** * Parse from String. * @param s String. * @return a Element corresponding to s. */ public C parse(String s); /** * Parse from Reader. * @param r Reader. * @return the next Element found on r. */ public C parse(Reader r); /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. */ public String toScript(); } java-algebra-system-2.7.200/src/edu/jas/structure/Element.java000066400000000000000000000033221445075545500241530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.io.Serializable; /** * Element interface. Basic functionality of elements, e.g. compareTo, equals, * clone. *

* Note: extension of Cloneable removed in 2012-08-18, * clone() is renamed to copy(). See also the * discussion in Bloch on * Cloning. * @param element type. * @author Heinz Kredel */ public interface Element> extends Comparable, Serializable { /** * Clone this Element. * @return Creates and returns a copy of this Element. */ public C copy(); /** * Test if this is equal to b. * @param b * @return true if this is equal to b, else false. */ public boolean equals(Object b); /** * Hashcode of this Element. * @return the hashCode. */ public int hashCode(); /** * Compare this to b. I.e. this < b iff this.compareTo(b) < 0. * Note: may not be meaningful if structure has no order. * @param b * @return 0 if this is equal to b, -1 if this is less then b, else +1. */ public int compareTo(C b); /** * Get the corresponding element factory. * @return factory for this Element. */ public ElemFactory factory(); /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. */ public String toScript(); /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. */ public String toScriptFactory(); } java-algebra-system-2.7.200/src/edu/jas/structure/FieldElem.java000066400000000000000000000004201445075545500244040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Field element interface. Empty interface since inverse is already in * RingElem. * @param field element type * @author Heinz Kredel */ public interface FieldElem> extends RingElem { } java-algebra-system-2.7.200/src/edu/jas/structure/FieldFactory.java000066400000000000000000000003601445075545500251340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Field factory interface. Defines test for field and access of characteristic. * @author Heinz Kredel */ public interface FieldFactory> extends RingFactory { } java-algebra-system-2.7.200/src/edu/jas/structure/GcdRingElem.java000066400000000000000000000005311445075545500247010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Gcd ring element interface. Empty interface since gcd and egcd is now in * RingElem. Adds greatest common divisor and extended greatest common divisor. * @param gcd element type * @author Heinz Kredel */ public interface GcdRingElem> extends RingElem { } java-algebra-system-2.7.200/src/edu/jas/structure/ModulElem.java000066400000000000000000000024001445075545500244410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.util.List; /** * Module element interface. Defines scalar operations. * @param module type * @param scalar type * @author Heinz Kredel */ public interface ModulElem, C extends RingElem> extends AbelianGroupElem { /** * Scalar multiplication. Multiply this by a scalar. * @param s scalar * @return this * s. */ public M scalarMultiply(C s); /** * Linear combination. * @param a scalar * @param b module element * @param s scalar * @return a * b + this * s. */ public M linearCombination(C a, M b, C s); /** * Linear combination. * @param b module element * @param s scalar * @return b + this * s. */ public M linearCombination(M b, C s); /** * Scalar product. Multiply two vectors to become a scalar. * @param b module element * @return this * b, a scalar. */ public C scalarProduct(M b); /** * Scalar product. Multiply this vectors by list of vectors to become a * vector. * @param b list of module elements * @return this * b, a list of scalars, a module element. */ public M scalarProduct(List b); } java-algebra-system-2.7.200/src/edu/jas/structure/ModulFactory.java000066400000000000000000000013461445075545500251760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.util.List; /** * Module factory interface. Defines conversion from list and sparse random. * @param module type * @param coefficient type * @author Heinz Kredel */ public interface ModulFactory, C extends RingElem> extends AbelianGroupFactory { /** * Convert list to module. * @param v list of ring elements. * @return a module element with the elements from v. */ public M fromList(List v); /** * Random vector. * @param k size of coefficients. * @param q fraction of non zero elements. * @return a random vector. */ public M random(int k, float q); } java-algebra-system-2.7.200/src/edu/jas/structure/MonoidElem.java000066400000000000000000000106021445075545500246110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Monoid element interface. Defines the multiplicative methods. * @param element type * @author Heinz Kredel */ public interface MonoidElem> extends Element { /** * Test if this is one. * @return true if this is 1, else false. */ public boolean isONE(); /** * Test if this is a unit. I.e. there exists x with this.multiply(x).isONE() * == true. * @return true if this is a unit, else false. */ public boolean isUnit(); /** * Multiply this with S. * @param S * @return this * S. */ public C multiply(C S); /** * Divide this by S. * @param S * @return this / S. */ public C divide(C S); /** * Remainder after division of this by S. * @param S * @return this - (this / S) * S. */ public C remainder(C S); /** * Quotient and remainder by division of this by S. * @param S * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") default public C[] quotientRemainder(C S) { return (C[]) new MonoidElem[] { divide(S), remainder(S) }; } /** * Right division. * Returns commutative divide if not overwritten. * @param a element. * @return right, with a * right = this */ default public C rightDivide(C a) { if (((MonoidFactory)factory()).isCommutative()) { return divide(a); } throw new UnsupportedOperationException("operation not implemented"); } /** * Left division. * Returns commutative divide if not overwritten. * @param a element. * @return left, with left * a = this */ default public C leftDivide(C a) { if (((MonoidFactory)factory()).isCommutative()) { return divide(a); } throw new UnsupportedOperationException("operation not implemented"); } /** * Right remainder. * Returns commutative remainder if not overwritten. * @param a element. * @return r = this - a * (1/right), where a * right = this. */ default public C rightRemainder(C a) { if (((MonoidFactory)factory()).isCommutative()) { return remainder(a); } throw new UnsupportedOperationException("operation not implemented"); } /** * Left remainder. * Returns commutative remainder if not overwritten. * @param a element. * @return r = this - (1/left) * a, where left * a = this. */ default public C leftRemainder(C a) { if (((MonoidFactory)factory()).isCommutative()) { return remainder(a); } throw new UnsupportedOperationException("operation not implemented"); } /** * Two-sided division. * Returns commutative divide if not overwritten. * @param a element. * @return [left,right], with left * a * right = this */ @SuppressWarnings("unchecked") default public C[] twosidedDivide(C a) { if (((MonoidFactory)factory()).isCommutative()) { C[] ret = (C[]) new MonoidElem[2]; ret[0] = divide(a); ret[1] = ((MonoidFactory)factory()).getONE(); return ret; } throw new UnsupportedOperationException("operation not implemented"); } /** * Two-sided remainder. * Returns commutative remainder if not overwritten. * @param a element. * @return r = this - (a/left) * a * (a/right), where left * a * right = this. */ default public C twosidedRemainder(C a){ if (((MonoidFactory)factory()).isCommutative()) { return remainder(a); } throw new UnsupportedOperationException("operation not implemented"); } /** * Inverse of this. Some implementing classes will throw * NotInvertibleException if the element is not invertible. * @return x with this * x = 1, if it exists. */ public C inverse(); /*throws NotInvertibleException*/ /** * Power of this to the n-th. * @param n integer exponent. * @return a**n, with a**0 = 1 and a**{-n} = {1/a}**n. * Java 8 only */ @SuppressWarnings("unchecked") default public C power(long n) { //System.out.println("this = " + this + ", n = " + n); return Power.power((MonoidFactory)factory(), (C)this, n); } } java-algebra-system-2.7.200/src/edu/jas/structure/MonoidFactory.java000066400000000000000000000012571445075545500253440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Monoid factory interface. Defines get one and tests for associativity and * commutativity. * @author Heinz Kredel */ public interface MonoidFactory> extends ElemFactory { /** * Get the constant one for the MonoidElem. * @return 1. */ public C getONE(); /** * Query if this monoid is commutative. * @return true if this monoid is commutative, else false. */ public boolean isCommutative(); /** * Query if this monoid is associative. * @return true if this monoid is associative, else false. */ public boolean isAssociative(); } java-algebra-system-2.7.200/src/edu/jas/structure/NoncomRingElem.java000066400000000000000000000016571445075545500254470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Non-commutative ring element interface. Defines right divide and right remainder. * @param ring element type * @author Heinz Kredel */ public interface NoncomRingElem> extends RingElem { /** * Right division. * @param a element. * @return right, with a * right = this */ public C rightDivide(C a); /** * Right remainder. * @param a element. * @return r = this - a * (a/right), where a * right = this. */ public C rightRemainder(C a); /** * Two-sided division. * @param a element. * @return [left,right], with left * a * right = this */ public C[] twosidedDivide(C a); /** * Two-sided remainder. * @param a element. * @return r = this - (a/left) * a * (a/right), where left * a * right = this. */ public C twosidedRemainder(C a); } java-algebra-system-2.7.200/src/edu/jas/structure/NotDivisibleException.java000066400000000000000000000011121445075545500270270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * NotDivisibleException class. Runtime Exception to be thrown for not * divisible monoid elements. * @author Heinz Kredel */ public class NotDivisibleException extends RuntimeException { public NotDivisibleException() { super("NotDivisibleException"); } public NotDivisibleException(String c) { super(c); } public NotDivisibleException(String c, Throwable t) { super(c, t); } public NotDivisibleException(Throwable t) { super("NotDivisibleException", t); } } java-algebra-system-2.7.200/src/edu/jas/structure/NotInvertibleException.java000066400000000000000000000011231445075545500272220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * NotInvertibleException class. Runtime Exception to be thrown for not * invertible monoid elements. * @author Heinz Kredel */ public class NotInvertibleException extends RuntimeException { public NotInvertibleException() { super("NotInvertibleException"); } public NotInvertibleException(String c) { super(c); } public NotInvertibleException(String c, Throwable t) { super(c, t); } public NotInvertibleException(Throwable t) { super("NotInvertibleException", t); } } java-algebra-system-2.7.200/src/edu/jas/structure/Power.java000066400000000000000000000305321445075545500236610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Power class to compute powers of RingElem. * @author Heinz Kredel */ public class Power> { private static final Logger logger = LogManager.getLogger(Power.class); private static final boolean debug = logger.isDebugEnabled(); private final RingFactory fac; /** * The constructor creates a Power object. */ public Power() { this(null); } /** * The constructor creates a Power object. * @param fac ring factory */ public Power(RingFactory fac) { this.fac = fac; } /** * power of a to the n-th, n positive. * @param a element. * @param n integer exponent ≥ 0. * @return a^n. */ public static > C positivePower(C a, long n) { if (n <= 0) { throw new IllegalArgumentException("only positive n allowed"); } if (a.isZERO() || a.isONE()) { return a; } C b = a; long i = n - 1; C p = b; do { if (i % 2 == 1) { p = p.multiply(b); } i = i / 2; if (i > 0) { b = b.multiply(b); } } while (i > 0); return p; } /** * power of a to the n-th, n positive. * @param a element. * @param n java.math.BigInteger exponent ≥ 0. * @return a^n. */ public static > C positivePower(C a, java.math.BigInteger n) { if (n.signum() <= 0) { throw new IllegalArgumentException("only positive n allowed"); } if (a.isZERO() || a.isONE()) { return a; } C b = a; if (n.compareTo(java.math.BigInteger.ONE) == 0) { return b; } if (n.bitLength() <= 63) { long l = n.longValue(); return positivePower(a, l); } C p = a; java.math.BigInteger i = n.subtract(java.math.BigInteger.ONE); do { if (i.testBit(0)) { p = p.multiply(b); } i = i.shiftRight(1); if (i.signum() > 0) { b = b.multiply(b); } } while (i.signum() > 0); return p; } /** * power of a to the n-th, n positive, modulo m. * @param a element. * @param n integer exponent ≥ 0. * @param m modulus. * @return a^n mod m. */ public static > C modPositivePower(C a, long n, C m) { if (n <= 0) { throw new IllegalArgumentException("only positive n allowed"); } if (a.isZERO() || a.isONE()) { return a; } C b = a.remainder(m); long i = n - 1; C p = b; do { if (i % 2 == 1) { p = p.multiply(b).remainder(m); } i = i / 2; if (i > 0) { b = b.multiply(b).remainder(m); } } while (i > 0); return p; } /** * power of a to the n-th, n positive, modulo m. * @param a element. * @param n big integer exponent ≥ 0. * @param m modulus. * @return a^n mod m. */ public static > C modPositivePower(C a, java.math.BigInteger n, C m) { if (n.signum() <= 0) { throw new IllegalArgumentException("only positive n allowed"); } if (a.isZERO() || a.isONE()) { return a; } C b = a.remainder(m); java.math.BigInteger i = n.subtract(java.math.BigInteger.ONE); C p = b; do { if (i.testBit(0)) { // i % 2 == 1 p = p.multiply(b).remainder(m); } i = i.shiftRight(1); // / 2; if (i.signum() > 0) { b = b.multiply(b).remainder(m); } } while (i.signum() > 0); return p; } /** * power of a to the n-th. * @param a element. * @param n integer exponent. * @param fac ring factory. * @return a^n, with 0^0 = 0 and a^{-n} = {1/a}^n. */ @SuppressWarnings("unchecked") public static > C power(RingFactory fac, C a, long n) { if (a == null || a.isZERO()) { return a; } //return a; return (C) Power. power((MonoidFactory) fac, a, n); } /** * power of a to the n-th. * @param a element. * @param n integer exponent. * @param fac monoid factory. * @return a^n, with a^{-n} = {1/a}^n. */ public static > C power(MonoidFactory fac, C a, long n) { if (n == 0) { if (fac == null) { throw new IllegalArgumentException("fac may not be null for a^0"); } return fac.getONE(); } if (a.isONE()) { return a; } C b = a; if (n < 0) { b = a.inverse(); n = -n; } if (n == 1) { return b; } if (fac == null) { throw new IllegalArgumentException("fac may not be null for n > 1"); } C p = fac.getONE(); long i = n; do { if (i % 2 == 1) { p = p.multiply(b); } i = i / 2; if (i > 0) { b = b.multiply(b); } } while (i > 0); if (n > 11 && debug) { logger.info("n = {}, p = {} ", n, p); } return p; } /** * power of a to the n-th modulo m. * @param a element. * @param n integer exponent. * @param m modulus. * @param fac monoid factory. * @return a^n mod m, with a^{-n} = {1/a}^n. */ public static > C modPower(MonoidFactory fac, C a, long n, C m) { if (n == 0) { if (fac == null) { throw new IllegalArgumentException("fac may not be null for a^0"); } return fac.getONE(); } if (a.isONE()) { return a; } C b = a.remainder(m); if (n < 0) { b = a.inverse().remainder(m); n = -n; } if (n == 1) { return b; } if (fac == null) { throw new IllegalArgumentException("fac may not be null for n > 1"); } C p = fac.getONE(); long i = n; do { if (i % 2 == 1) { p = p.multiply(b).remainder(m); } i = i / 2; if (i > 0) { b = b.multiply(b).remainder(m); } } while (i > 0); if (n > 11 && debug) { logger.info("n = {}, p = {} ", n, p); } return p; } /** * power of a to the n-th modulo m. * @param a element. * @param n integer exponent. * @param m modulus. * @param fac monoid factory. * @return a^n mod m, with a^{-n} = {1/a}^n. */ public static > C modPower(MonoidFactory fac, C a, java.math.BigInteger n, C m) { if (n.signum() == 0) { if (fac == null) { throw new IllegalArgumentException("fac may not be null for a^0"); } return fac.getONE(); } if (a.isONE()) { return a; } C b = a.remainder(m); if (n.signum() < 0) { b = a.inverse().remainder(m); n = n.negate(); } if (n.compareTo(java.math.BigInteger.ONE) == 0) { return b; } if (n.bitLength() <= 63) { long l = n.longValue(); return modPower(fac, a, l, m); } if (fac == null) { throw new IllegalArgumentException("fac may not be null for n > 1"); } C p = fac.getONE(); java.math.BigInteger i = n; do { if (i.testBit(0)) { p = p.multiply(b).remainder(m); } i = i.shiftRight(1); if (i.signum() > 0) { b = b.multiply(b).remainder(m); } } while (i.signum() > 0); logger.debug("n = {}, p = {} ", n, p); return p; } /** * power of a to the n-th. * @param a element. * @param n integer exponent. * @return a^n, with 0^0 = 0. */ public C power(C a, long n) { return power(fac, a, n); } /** * power of a to the n-th. * @param a long. * @param n integer exponent. * @return a^n, with a^0 = 1. */ public static long power(long a, long n) { if (n == 0) { return 1L; } if (a == 1L) { return a; } long b = a; if (n == 1L) { return b; } long p = 1L; long i = n; do { if (i % 2 == 1) { p = p * b; } i = i / 2; if (i > 0) { b = b * b; } } while (i > 0); if (n > 11 && debug) { logger.info("n = {}, p = {} ", n, p); } return p; } /** * power of a to the n-th mod m. * @param a element. * @param n integer exponent. * @param m modulus. * @return a^n mod m, with 0^0 = 0. */ public C modPower(C a, long n, C m) { return modPower(fac, a, n, m); } /** * power of a to the n-th mod m. * @param a element. * @param n integer exponent. * @param m modulus. * @return a^n mod m, with 0^0 = 0. */ public C modPower(C a, java.math.BigInteger n, C m) { return modPower(fac, a, n, m); } /** * Logarithm. * @param p logarithm base. * @param a element. * @return k ≥ 1 minimal with p^k ≥ a. */ public static > long logarithm(C p, C a) { //if ( p.compareTo(a) < 0 ) { // return 0L; //} long k = 1L; C m = p; while (m.compareTo(a) < 0) { m = m.multiply(p); k++; } return k; } /** * Logarithm. * @param p logarithm base. * @param a element. * @return k ≥ 1 minimal with p^k ≥ a. */ public static > long logarithm(long p, long a) { long k = 1; long m = p; while (m < a) { m = m * p; k++; } return k; } /** * Multiply elements in list. * @param A list of elements (a_0,...,a_k). * @param fac ring factory. * @return prod(i=0,...k) a_i. */ public static > C multiply(RingFactory fac, List A) { return multiply((MonoidFactory) fac, A); } /** * Multiply elements in list. * @param A list of elements (a_0,...,a_k). * @param fac monoid factory. * @return prod(i=0,...k) a_i. */ public static > C multiply(MonoidFactory fac, List A) { if (fac == null) { throw new IllegalArgumentException("fac may not be null for empty list"); } C res = fac.getONE(); if (A == null || A.isEmpty()) { return res; } for (C a : A) { res = res.multiply(a); } return res; } /** * Sum elements in list. * @param A list of elements (a_0,...,a_k). * @param fac ring factory. * @return sum(i=0,...k) a_i. */ public static > C sum(RingFactory fac, List A) { return sum((AbelianGroupFactory) fac, A); } /** * Sum elements in list. * @param A list of elements (a_0,...,a_k). * @param fac monoid factory. * @return sum(i=0,...k) a_i. */ public static > C sum(AbelianGroupFactory fac, List A) { if (fac == null) { throw new IllegalArgumentException("fac may not be null for empty list"); } C res = fac.getZERO(); if (A == null || A.isEmpty()) { return res; } for (C a : A) { res = res.sum(a); } return res; } } java-algebra-system-2.7.200/src/edu/jas/structure/QuotPair.java000066400000000000000000000007161445075545500243320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Quotient pair interface. Defines selectors for numerator and denominator. * @typeparam C base element type * @author Heinz Kredel */ public interface QuotPair> { /** * Numerator. */ public C numerator(); /** * Denominator. */ public C denominator(); /** * Test if element type is constant. */ public boolean isConstant(); } java-algebra-system-2.7.200/src/edu/jas/structure/QuotPairFactory.java000066400000000000000000000011151445075545500256540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Quotient pair factory interface. Defines constructors from numerators and * denominators. * @typeparam C base element type * @typeparam D result element type * @author Heinz Kredel */ public interface QuotPairFactory, D extends RingElem> { /** * Create from numerator. */ public D create(C n); /** * Create from numerator, denominator pair. */ public D create(C n, C d); /** * Factory for base elements. */ public RingFactory pairFactory(); } java-algebra-system-2.7.200/src/edu/jas/structure/RegularRingElem.java000066400000000000000000000032261445075545500256110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Regular ring element interface. Defines idempotent operations and idempotent * tests. * @param regular ring element type * @author Heinz Kredel */ public interface RegularRingElem> extends GcdRingElem { /* Get component. * Not possible to define in interface. * @param i index of component. * @return val(i). public C get(int i); */ /** * Is regular ring element full. * @return If every component is non zero, then true is returned, else * false. */ public boolean isFull(); /** * Is idempotent. * @return If this is a idempotent element then true is returned, else * false. */ public boolean isIdempotent(); /** * Idempotent. * @return S with this*S = this. */ public C idempotent(); /** * Regular ring element idempotent complement. * @return 1-this.idempotent(). */ public C idemComplement(); /** * Regular ring element idempotent and. * @param S Product. * @return this.idempotent() and S.idempotent(). */ public C idempotentAnd(C S); /** * Regular ring element idempotent or. * @param S Product. * @return this.idempotent() or S.idempotent(). */ public C idempotentOr(C S); /** * Regular ring element fill with idempotent. * @param S Product. * @return fill this with S.idempotent(). */ public C fillIdempotent(C S); /** * Regular ring element fill with one. * @return fill this with one. */ public C fillOne(); } java-algebra-system-2.7.200/src/edu/jas/structure/RingElem.java000066400000000000000000000022021445075545500242600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Ring element interface. Combines additive and multiplicative methods. Adds * also gcd because of polynomials. * @param ring element type * @author Heinz Kredel */ public interface RingElem> extends AbelianGroupElem, MonoidElem { /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public C gcd(C b); /** * Extended greatest common divisor. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public C[] egcd(C b); /** * Left greatest common divisor. * Returns commutative greatest common divisor if not overwritten. * @param b other element. * @return leftGcd(this,b). */ default public C leftGcd(C b) { return gcd(b); } /** * Right greatest common divisor. * Returns commutative greatest common divisor if not overwritten. * @param b other element. * @return rightGcd(this,b). */ default public C rightGcd(C b) { return gcd(b); } } java-algebra-system-2.7.200/src/edu/jas/structure/RingFactory.java000066400000000000000000000012131445075545500250060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Ring factory interface. Defines test for field and query of characteristic. * @author Heinz Kredel */ public interface RingFactory> extends AbelianGroupFactory, MonoidFactory { /** * Query if this ring is a field. May return false if it is too hard to * determine if this ring is a field. * @return true if it is known that this ring is a field, else false. */ public boolean isField(); /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic(); } java-algebra-system-2.7.200/src/edu/jas/structure/Selector.java000066400000000000000000000004761445075545500243510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Selector interface. * @param ring element type * @author Heinz Kredel */ public interface Selector> { /** * Select. * @return true, if the element is selected, otherwise false. */ public boolean select(C c); } java-algebra-system-2.7.200/src/edu/jas/structure/StarRingElem.java000066400000000000000000000006661445075545500251260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Star ring element interface. Defines norm and conjugation. * @param ring element type * @author Heinz Kredel */ public interface StarRingElem> extends RingElem { /** * Conjugate of this. * @return conj(this). */ public C conjugate(); /** * Norm of this. * @return norm(this). */ public C norm(); } java-algebra-system-2.7.200/src/edu/jas/structure/UnaryFunctor.java000066400000000000000000000005141445075545500252210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Unary functor interface. * @param element type * @param element type * @author Heinz Kredel */ public interface UnaryFunctor, D extends Element> { /** * Evaluate. * @return evaluated element. */ public D eval(C c); } java-algebra-system-2.7.200/src/edu/jas/structure/Value.java000066400000000000000000000005531445075545500236410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Value interface. Defines selector for value. * @typeparam C base element type * @author Heinz Kredel */ public interface Value> { /** * Value getter. */ public C value(); /** * Test if element type is constant. */ public boolean isConstant(); } java-algebra-system-2.7.200/src/edu/jas/structure/ValueFactory.java000066400000000000000000000007051445075545500251700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.structure; /** * Value factory interface. Defines constructor from value. * @typeparam C base element type * @typeparam D result element type * @author Heinz Kredel */ public interface ValueFactory, D extends RingElem> { /** * Create from value. */ public D create(C n); /** * Factory for value elements. */ public RingFactory valueFactory(); } java-algebra-system-2.7.200/src/edu/jas/structure/package.html000066400000000000000000000017611445075545500242050ustar00rootroot00000000000000 Basic structural interfaces

Basic structural interfaces.

This package contains interfaces for the most general algebraic structures used in JAS, e.g. RingElem and RingFactory. The Power class implements exponentiation of monoid and ring elements.

RingElem and Ring overview
RingElem, Ring and polynomial overview


Heinz Kredel

Last modified: Sun Sep 21 18:29:11 CEST 2014

$Id$

java-algebra-system-2.7.200/src/edu/jas/ufd/000077500000000000000000000000001445075545500204355ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/ufd/CycloUtil.java000066400000000000000000000206711445075545500232150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.arith.PrimeInteger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.structure.Power; /** * Cyclotomic polynomial utilities. Adapted from Sympy Python codes. * @author Heinz Kredel */ public class CycloUtil { private static final Logger logger = LogManager.getLogger(CycloUtil.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Compute n-th cyclotomic polynomial. * @param n number of polynomial. * @param ring univariate polynomial ring of cyclotomic polynomial. * @return n-th cyclotomic polynomial. */ public static GenPolynomial cyclotomicPolynomial(GenPolynomialRing ring, long n) { GenPolynomialRing pfac = ring; if (pfac == null) { throw new IllegalArgumentException("ring must be non null"); } GenPolynomial h = pfac.univariate(0).subtract(pfac.getONE()); //System.out.println("h = " + h); SortedMap fac = PrimeInteger.factors(n); logger.info("factors = {}", fac); for (Map.Entry m : fac.entrySet()) { // h = dup_quo(dup_inflate(h, p, K), h, K) // h = dup_inflate(h, p**(k - 1), K) long p = m.getKey(); int k = m.getValue(); GenPolynomial ih = h.inflate(p); //System.out.println("ih = " + ih); h = ih.divide(h); //System.out.println("h = " + h); h = h.inflate(Power.power(p, k - 1)); //System.out.println("h = " + h + ", power = " + Power.power(p, k-1)); } return h; } /** * Compute the factors of the n-th cyclotomic polynomial. * @param n number of polynomial. * @param ring univariate polynomial ring of cyclotomic polynomial. * @return list of factors of n-th cyclotomic polynomial. */ public static List> cyclotomicDecompose(GenPolynomialRing ring, long n) { GenPolynomialRing pfac = ring; if (pfac == null) { throw new IllegalArgumentException("ring must be non null"); } GenPolynomial q = pfac.univariate(0).subtract(pfac.getONE()); //System.out.println("q = " + q); List> H = new ArrayList>(); H.add(q); SortedMap fac = PrimeInteger.factors(n); logger.info("factors = {}", fac); for (Map.Entry m : fac.entrySet()) { //Q = [ dup_quo(dup_inflate(h, p, K), h, K) for h in H ] //H.extend(Q) long p = m.getKey(); int k = m.getValue(); List> Q = new ArrayList>(); for (GenPolynomial h : H) { GenPolynomial g = h.inflate(p).divide(h); Q.add(g); } //System.out.println("Q = " + Q); H.addAll(Q); //for i in xrange(1, k): // Q = [ dup_inflate(q, p, K) for q in Q ] // H.extend(Q) for (int i = 1; i < k; i++) { List> P = new ArrayList>(); for (GenPolynomial h : Q) { GenPolynomial g = h.inflate(p); P.add(g); } //System.out.println("P = " + P); Q = P; H.addAll(P); } } return H; } /** * Compute the factors of the cyclotomic polynomial. * @param p cyclotomic polynomial. * @return list of factors of cyclotomic polynomial p or empty list. */ public static List> cyclotomicFactors(GenPolynomial p) { List> H = new ArrayList>(); long n = p.degree(); if (n <= 0) { return H; } BigInteger lc, tc; lc = p.leadingBaseCoefficient(); tc = p.trailingBaseCoefficient(); if (!lc.isONE() || (!tc.isONE() && !tc.negate().isONE())) { return H; } if (p.length() != 2) { // other coefficients must be zero return H; } // only case: x**n +/- 1 //F = _dup_cyclotomic_decompose(n, K) //if not K.is_one(tc_f): // return F GenPolynomialRing pfac = p.ring; List> F = cyclotomicDecompose(pfac, n); if (!tc.isONE()) { return F; } //else: // H = [] // for h in _dup_cyclotomic_decompose(2*n, K): // if h not in F: // H.append(h) //return H H = new ArrayList>(); List> F2 = cyclotomicDecompose(pfac, 2L * n); for (GenPolynomial h : F2) { if (!F.contains(h)) { H.add(h); } } return H; } /** * Test for cyclotomic polynomial. * @param p polynomial. * @return true if p is a cyclotomic polynomial, else false. */ public static boolean isCyclotomicPolynomial(GenPolynomial p) { long n = p.degree(); if (n <= 0) { return false; } BigInteger lc, tc; lc = p.leadingBaseCoefficient(); tc = p.trailingBaseCoefficient(); if (!lc.isONE() || (!tc.isONE() && !tc.negate().isONE())) { //System.out.println("!lc.isONE() || (!tc.isONE() && !tc.negate().isONE())"); return false; } if (p.length() == 2) { // other coefficients must be zero return true; } // ignore: if not irreducible: GenPolynomialRing ring = p.ring; if (ring.nvar != 1) { throw new IllegalArgumentException("not univariate polynomial"); } GenPolynomial g, h, f; g = ring.getZERO().copy(); h = ring.getZERO().copy(); long x = n % 2; for (Monomial m : p) { ExpVector e = m.e; long d = e.getVal(0); ExpVector e2 = e.subst(0, d / 2L); if (d % 2 == x) { g.doPutToMap(e2, m.c); } else { h.doPutToMap(e2, m.c); } } //g = dup_sqr(dup_strip(g), K) //h = dup_sqr(dup_strip(h), K) g = g.multiply(g); h = h.multiply(h); //System.out.println("g = " + g); //System.out.println("h = " + h); //F = dup_sub(g, dup_lshift(h, 1, K), K) ExpVector on = ExpVector.create(1, 0, 1L); f = g.subtract(h.multiply(on)).abs(); //System.out.println("f = " + f + ", f==p: " + f.equals(p)); //if F == f: return True if (f.equals(p)) { return true; } //g = dup_mirror(f, K) //if F == g and dup_cyclotomic_p(g, K): // return True g = ring.getZERO().copy(); for (Monomial m : p) { ExpVector e = m.e; long d = e.getVal(0); if (d % 2 == 1) { g.doPutToMap(e, m.c.negate()); } else { g.doPutToMap(e, m.c); } } g = g.abs(); //System.out.println("g = " + g + ", f==g: " + f.equals(g)); if (f.equals(g) && isCyclotomicPolynomial(g)) { return true; } //G = dup_sqf_part(F, K) Squarefree engine; engine = SquarefreeFactory.getImplementation(lc); GenPolynomial G; G = engine.squarefreePart(f); //System.out.println("G = " + G + ", G^2==f: " + G.multiply(G).equals(f)); //if dup_sqr(G, K) == F and dup_cyclotomic_p(G, K): // return True if (G.multiply(G).equals(f) && isCyclotomicPolynomial(G)) { return true; } return false; } } java-algebra-system-2.7.200/src/edu/jas/ufd/EvalPoints.java000066400000000000000000000042471445075545500233730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.List; import edu.jas.kern.Scripting; import edu.jas.poly.GenPolynomial; import edu.jas.structure.RingElem; /** * Container for the evaluation points of a polynomial. * @author Heinz Kredel * @param coefficient type */ public class EvalPoints> implements Serializable { /** * Original multivariate polynomial to be evaluated. */ public final GenPolynomial poly; /** * Evaluated univariate polynomial as evaluated. */ public final GenPolynomial upoly; /** * Evaluation points. */ public final List evalPoints; /** * Constructor. * @param p given GenPolynomial in r variables, x_{r+1}, x_{r}, ..., x_{1}. * @param u evaluated GenPolynomial = p(x_{r+1}, lr, ..., l1). * @param ep list of evaluation points, (l1, ..., lr). */ public EvalPoints(GenPolynomial p, GenPolynomial u, List ep) { poly = p; upoly = u; evalPoints = ep; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer("EvalPoints("); sb.append(poly.toString()); sb.append(", "); sb.append(upoly.toString()); sb.append(", "); sb.append(evalPoints.toString()); sb.append(")"); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { StringBuffer sb = new StringBuffer(); switch (Scripting.getLang()) { case Python: sb.append("EvalPoints("); break; case Ruby: sb.append("EvalPoints.new("); default: } sb.append(poly.toScript()); sb.append(", "); sb.append(upoly.toScript()); sb.append(", "); sb.append(evalPoints.toString()); sb.append(")"); return sb.toString(); } } java-algebra-system-2.7.200/src/edu/jas/ufd/Examples.java000066400000000000000000000230511445075545500230570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; /** * Examples for ufd and elementaty integration usage. * @author Heinz Kredel */ public class Examples { /** * main. */ public static void main(String[] args) { //// no go: example6(); //example9(); example1(); example2(); example10(); example11(); ComputerThreads.terminate(); } /** * example1 with GenMatrix. */ public static void example1() { System.out.println("\n\n example 1"); BigInteger cfac; GenPolynomialRing fac; QuotientRing efac; GenPolynomialRing> qfac; GenMatrixRing>> mfac; cfac = new BigInteger(); System.out.println("cfac = " + cfac); String[] vc = new String[] { "a", "b" }; fac = new GenPolynomialRing(cfac, vc); System.out.println(" fac = " + fac.toScript()); efac = new QuotientRing(fac); System.out.println("efac = " + efac.toScript()); String[] v = new String[] { "x", "y", "z" }; qfac = new GenPolynomialRing>(efac, 3, v); System.out.println("qfac = " + qfac.toScript()); mfac = new GenMatrixRing>>(qfac, 3, 3); System.out.println("mfac = " + mfac.toScript()); GenPolynomial> p; p = qfac.random(3, 4, 2, 0.3f); System.out.println("\np = " + p); GenMatrix>> m; m = mfac.random(3, 0.4f); System.out.println("\nm = " + m.toScript()); } /** * example2 with GenPolynomial. */ public static void example2() { System.out.println("\n\n example 2"); BigInteger fac = new BigInteger(); String[] var = new String[] { "a", "b", "c", "d" }; int numvars = var.length; //not needed: TermOrder tord = new TermOrder(TermOrder.INVLEX); GenPolynomialRing ring = new GenPolynomialRing(fac, var); List> vars = new ArrayList>(); // Build up the polynomial from vars. for (int i = 0; i < numvars; i++) vars.add(ring.univariate(i)); System.out.println("vars = " + vars); // Silly demo one first. // ab+ac+db+dc -> (a+d)(b+c) GenPolynomial tmp = (vars.get(0).multiply(vars.get(1))) .sum(vars.get(0).multiply(vars.get(2))).sum(vars.get(3).multiply(vars.get(1))) .sum(vars.get(3).multiply(vars.get(2))); //alternative: tmp = ring.parse("a b + a c + d b + d c"); System.out.println("tmp = " + tmp); Factorization engine = FactorFactory.getImplementation(fac); SortedMap, Long> factors = engine.factors(tmp); System.out.println("factors = " + factors); } /** * example6. Partial fraction decomposition. */ public static void example6() { System.out.println("\n\nexample 6"); // http://www.apmaths.uwo.ca/~rcorless/AM563/NOTES/Nov_16_95/node13.html TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); //String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // ( 7 x^6 + 1 ) / ( x^7 + x + 1 ) GenPolynomial D = pfac.parse("x^7 + x + 1"); GenPolynomial N = PolyUtil. baseDerivative(D); FactorRational engine = new FactorRational(); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\nintegral " + F); } /** * example9. Rothstein-Trager and absolute factorization algorithm. */ public static void example9() { System.out.println("\n\nexample 9"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); //String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^5 + x - 7 ) GenPolynomial D = pfac.parse("( x^5 + x - 7 )"); GenPolynomial N = pfac.getONE(); FactorRational engine = new FactorRational(); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\nintegral " + F); //PartialFraction Fa = engine.baseAlgebraicPartialFractionIrreducibleAbsolute(N,D); //System.out.println("\nintegral_a " + Fa); } /** * example10. factorization in Q(sqrt(2))(x)(sqrt(x))[y]. */ public static void example10() { System.out.println("\n\nexample 10"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] var_w2 = new String[] { "w2" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, var_w2); System.out.println("pfac = " + pfac.toScript()); GenPolynomial w2 = pfac.parse(" w2^2 - 2 "); System.out.println("w2 = " + w2); AlgebraicNumberRing a2fac = new AlgebraicNumberRing(w2, true); System.out.println("a2fac = " + a2fac.toScript()); String[] var_x = new String[] { "x" }; GenPolynomialRing> apfac = new GenPolynomialRing>( a2fac, 1, to, var_x); System.out.println("apfac = " + apfac.toScript()); QuotientRing> qfac = new QuotientRing>( apfac); System.out.println("qfac = " + qfac.toScript()); String[] var_wx = new String[] { "wx" }; GenPolynomialRing>> pqfac = new GenPolynomialRing>>( qfac, 1, to, var_wx); System.out.println("pqfac = " + pqfac.toScript()); GenPolynomial>> wx = pqfac.parse(" wx^2 - { x } "); System.out.println("wx = " + wx); AlgebraicNumberRing>> axfac = new AlgebraicNumberRing>>( wx, true); System.out.println("axfac = " + axfac.toScript()); String[] var_y = new String[] { "y" }; GenPolynomialRing>>> apqfac = new GenPolynomialRing>>>( axfac, 1, to, var_y); System.out.println("apqfac = " + apqfac.toScript()); // ( y^2 - x ) * ( y^2 - 2 ), need {} for recursive coefficients GenPolynomial>>> f; f = apqfac.parse(" ( y^2 - { { x } } ) * ( y^2 - 2 )^2 "); System.out.println("f = " + f); FactorAbstract>>> engine = FactorFactory .getImplementation(axfac); System.out.println("engine = " + engine); SortedMap>>>, Long> F = engine .factors(f); System.out.println("factors(f) = " + F); } /** * example11. factorization in Z[a,c,d,e,x]. */ public static void example11() { System.out.println("\n\nexample 11"); for (int i = 0; i < 10; i++) { //100000 String[] vars = new String[] { "a", "c", "d", "e", "x" }; GenPolynomialRing fac; fac = new GenPolynomialRing(edu.jas.arith.BigInteger.ZERO, vars.length, new TermOrder(TermOrder.INVLEX), vars); GenPolynomial poly = fac.parse("a*d*e + c*d^2*x + a*e^2*x + c*d*e*x^2"); //System.out.println("Run " + i + ": " + poly.toString()); FactorAbstract factorAbstract = FactorFactory .getImplementation(edu.jas.arith.BigInteger.ZERO); long ts = System.currentTimeMillis(); SortedMap, Long> map = factorAbstract.factors(poly); ts = System.currentTimeMillis() - ts; //System.out.println("Run Factors " + ts + "ms: " + map.toString()); boolean t = factorAbstract.isFactorization(poly, map); if (!t) { System.out.println("Run " + i + ": " + poly.toString()); System.out.println("Run not Factors " + ts + "ms: " + map.toString()); } } } } java-algebra-system-2.7.200/src/edu/jas/ufd/ExamplesPartialFraction.java000066400000000000000000000136141445075545500260660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Examples related to partial fraction decomposition. * * @author Heinz Kredel */ public class ExamplesPartialFraction { /** * Main program. * * @param args */ public static void main(String[] args) { example11(); example12(); example13(); example14(); example15(); example16(); example17(); ComputerThreads.terminate(); } /** * example11. */ public static void example11() { System.out.println("\n\nexample 11"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^2 - 2 ) GenPolynomial D = pfac.parse("x^2 - 2"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example12. */ public static void example12() { System.out.println("\n\nexample 12"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^3 + x ) GenPolynomial D = pfac.parse("x^3 + x"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example13. */ public static void example13() { System.out.println("\n\nexample 13"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^6 - 5 x^4 + 5 x^2 + 4 ) GenPolynomial D = pfac.parse("x^6 - 5 x^4 + 5 x^2 + 4"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example14. */ public static void example14() { System.out.println("\n\nexample 14"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^4 + 4 ) GenPolynomial D = pfac.parse("x^4 + 4"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example15. */ public static void example15() { System.out.println("\n\nexample 15"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^3 - 2 ) GenPolynomial D = pfac.parse("x^3 - 2"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example16. */ public static void example16() { System.out.println("\n\nexample 16"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x - 1 ) ( x - 2 ) ( x - 3 ) GenPolynomial D = pfac.parse("( x - 1 ) * ( x - 2 ) * ( x - 3 )"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFraction(N, D); System.out.println("\npartial fraction " + F); } /** * example17. Absolute factorization of example15. */ public static void example17() { System.out.println("\n\nexample 17"); TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); // 1 / ( x^3 - 2 ) GenPolynomial D = pfac.parse("x^3 - 2"); GenPolynomial N = pfac.getONE(); FactorRational engine = (FactorRational) FactorFactory.getImplementation(cfac); PartialFraction F = engine.baseAlgebraicPartialFractionIrreducibleAbsolute(N, D); System.out.println("\npartial fraction " + F); } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorAbsolute.java000066400000000000000000001012141445075545500242140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Absolute factorization algorithms class. This class contains implementations * of methods for factorization over algebraically closed fields. The required * field extension is computed along with the factors. The methods have been * tested for prime fields of characteristic zero, that is for * BigRational. It might eventually also be used for prime fields * of non-zero characteristic, that is with ModInteger. The field * extension may yet not be minimal. * @author Heinz Kredel * @param coefficient type */ public abstract class FactorAbsolute> extends FactorAbstract { private static final Logger logger = LogManager.getLogger(FactorAbsolute.class); private static final boolean debug = logger.isDebugEnabled(); /* * Factorization engine for algebraic number coefficients. */ //not possible here because of recursion AN -> Int|Mod -> AN -> ... //public final FactorAbstract> aengine; /** * No argument constructor. Note: can't use this constructor. */ protected FactorAbsolute() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param cfac coefficient ring factory. */ public FactorAbsolute(RingFactory cfac) { super(cfac); //GenPolynomialRing fac = new GenPolynomialRing(cfac,1); //GenPolynomial p = fac.univariate(0); //AlgebraicNumberRing afac = new AlgebraicNumberRing(p); //aengine = null; //FactorFactory.getImplementation(afac); // hack } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName(); } /** * GenPolynomial test if is absolute irreducible. * @param P GenPolynomial. * @return true if P is absolute irreducible, else false. */ public boolean isAbsoluteIrreducible(GenPolynomial P) { if (!isIrreducible(P)) { return false; } Factors F = factorsAbsoluteIrreducible(P); if (F.afac == null) { return true; } else if (F.afactors.size() > 2) { return false; } else { //F.size() == 2 boolean cnst = false; for (GenPolynomial> p : F.afactors) { if (p.isConstant()) { cnst = true; } } return cnst; } } /** * GenPolynomial absolute base factorization of a polynomial. * @param P univariate GenPolynomial. * @return factors map container: [p_1 -> e_1, ..., p_k -> e_k] with P * = prod_{i=1,...,k} p_i**e_i. Note: K(alpha) not yet * minimal. */ // @Override public FactorsMap baseFactorsAbsolute(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } SortedMap, Long> factors = new TreeMap, Long>(); if (P.isZERO()) { return new FactorsMap(P, factors); } //System.out.println("\nP_base = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { //System.out.println("\nfacs_base: univ"); throw new IllegalArgumentException("only for univariate polynomials"); } if (!pfac.coFac.isField()) { //System.out.println("\nfacs_base: field"); throw new IllegalArgumentException("only for field coefficients"); } if (P.degree(0) <= 1) { factors.put(P, 1L); return new FactorsMap(P, factors); } // factor over K (=C) SortedMap, Long> facs = baseFactors(P); if (debug && !isFactorization(P, facs)) { System.out.println("facs = " + facs); throw new ArithmeticException("isFactorization = false"); } logger.info("all K factors = {}", facs); // Q[X] // factor over some K(alpha) SortedMap, Long> afactors = new TreeMap, Long>(); for (Map.Entry, Long> me : facs.entrySet()) { GenPolynomial p = me.getKey(); Long e = me.getValue(); //facs.get(p); if (p.degree(0) <= 1) { factors.put(p, e); } else { Factors afacs = baseFactorsAbsoluteIrreducible(p); //System.out.println("afacs = " + afacs); afactors.put(afacs, e); } } //System.out.println("K(alpha) factors = " + factors); return new FactorsMap(P, factors, afactors); } /** * GenPolynomial absolute base factorization of a squarefree polynomial. * @param P squarefree and primitive univariate GenPolynomial. * @return factors list container: [p_1,...,p_k] with P = prod_{i=1, ..., k} * p_i. Note: K(alpha) not yet minimal. */ // @Override public FactorsList baseFactorsAbsoluteSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return new FactorsList(P, factors); } //System.out.println("\nP_base_sqf = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { //System.out.println("facs_base_sqf: univ"); throw new IllegalArgumentException("only for univariate polynomials"); } if (!pfac.coFac.isField()) { //System.out.println("facs_base_sqf: field"); throw new IllegalArgumentException("only for field coefficients"); } if (P.degree(0) <= 1) { factors.add(P); return new FactorsList(P, factors); } // factor over K (=C) List> facs = baseFactorsSquarefree(P); //System.out.println("facs_base_irred = " + facs); if (debug && !isFactorization(P, facs)) { throw new ArithmeticException("isFactorization = false"); } logger.info("all K factors = {}", facs); // Q[X] // factor over K(alpha) List> afactors = new ArrayList>(); for (GenPolynomial p : facs) { //System.out.println("facs_base_sqf_p = " + p); if (p.degree(0) <= 1) { factors.add(p); } else { Factors afacs = baseFactorsAbsoluteIrreducible(p); //System.out.println("afacs_base_sqf = " + afacs); logger.info("K(alpha) factors = {}", afacs); // K(alpha)[X] afactors.add(afacs); } } //System.out.println("K(alpha) factors = " + factors); return new FactorsList(P, factors, afactors); } /** * GenPolynomial base absolute factorization of a irreducible polynomial. * @param P irreducible! univariate GenPolynomial. * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i * in K(alpha)[x] for suitable alpha and p_i irreducible over L[x], * where K \subset K(alpha) \subset L is an algebraically closed * field over K. Note: K(alpha) not yet minimal. */ public Factors baseFactorsAbsoluteIrreducible(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } if (P.isZERO()) { return new Factors(P); } //System.out.println("\nP_base_irred = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { //System.out.println("facs_base_irred: univ"); throw new IllegalArgumentException("only for univariate polynomials"); } if (!pfac.coFac.isField()) { //System.out.println("facs_base_irred: field"); throw new IllegalArgumentException("only for field coefficients"); } if (P.degree(0) <= 1) { return new Factors(P); } // setup field extension K(alpha) where alpha = z_xx //String[] vars = new String[] { "z_" + Math.abs(P.hashCode() % 1000) }; String[] vars = pfac.newVars("z_"); pfac = pfac.copy(); vars = pfac.setVars(vars); GenPolynomial aP = pfac.copy(P); // hack to exchange the variables AlgebraicNumberRing afac = new AlgebraicNumberRing(aP, true); // since irreducible if (logger.isInfoEnabled()) { logger.info("K(alpha) = {}", afac); logger.info("K(alpha) = {}", afac.toScript()); } GenPolynomialRing> pafac = new GenPolynomialRing>(afac, aP.ring.nvar, aP.ring.tord, /*old*/vars); // convert to K(alpha) GenPolynomial> Pa = PolyUtil. convertToAlgebraicCoefficients(pafac, P); logger.info("P over K(alpha) = {}", Pa); // factor over K(alpha) FactorAbstract> engine = FactorFactory. getImplementation(afac); //System.out.println("K(alpha) engine = " + engine); List>> factors = engine.baseFactorsSquarefree(Pa); //System.out.println("factors = " + factors); logger.info("factors over K(alpha) = {}", factors); List>> faca = new ArrayList>>( factors.size()); List>> facar = new ArrayList>>(); for (GenPolynomial> fi : factors) { if (fi.degree(0) <= 1) { faca.add(fi); } else { //System.out.println("fi.deg > 1 = " + fi); FactorAbsolute> aengine = (FactorAbsolute>) FactorFactory . getImplementation(afac); Factors> fif = aengine.baseFactorsAbsoluteIrreducible(fi); //System.out.println("fif = " + fif); facar.add(fif); } } if (facar.size() == 0) { facar = null; } // find minimal field extension K(beta) \subset K(alpha) return new Factors(P, afac, Pa, faca, facar); } /** * Univariate GenPolynomial algebraic partial fraction decomposition, * Absolute factorization for elementary integration algorithm to linear * factors. * @param A univariate GenPolynomial, deg(A) ≤ deg(P). * @param P univariate squarefree GenPolynomial, gcd(A,P) == 1. * @return partial fraction container. */ public PartialFraction baseAlgebraicPartialFraction(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException(" P == null or P == 0"); } if (A == null || A.isZERO()) { throw new IllegalArgumentException(" A == null or A == 0"); // PartialFraction(A,P,al,pl,empty,empty) } //System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { //System.out.println("facs_base_irred: univ"); throw new IllegalArgumentException("only for univariate polynomials"); } if (!pfac.coFac.isField()) { //System.out.println("facs_base_irred: field"); throw new IllegalArgumentException("only for field coefficients"); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new PartialFraction(A, P, cfactors, cdenom, afactors, adenom); } List> Pfac = baseFactorsSquarefree(P); //System.out.println("\nPfac = " + Pfac); List> Afac = engine.basePartialFraction(A, Pfac); GenPolynomial A0 = Afac.remove(0); if (!A0.isZERO()) { throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)"); } // algebraic and linear factors int i = 0; for (GenPolynomial pi : Pfac) { GenPolynomial ai = Afac.get(i++); if (pi.degree(0) <= 1) { cfactors.add(ai.leadingBaseCoefficient()); cdenom.add(pi); continue; } PartialFraction pf = baseAlgebraicPartialFractionIrreducibleAbsolute(ai, pi); //PartialFraction pf = baseAlgebraicPartialFractionIrreducible(ai,pi); cfactors.addAll(pf.cfactors); cdenom.addAll(pf.cdenom); afactors.addAll(pf.afactors); adenom.addAll(pf.adenom); } return new PartialFraction(A, P, cfactors, cdenom, afactors, adenom); } /** * Univariate GenPolynomial algebraic partial fraction decomposition, via * absolute factorization to linear factors. * @param A univariate GenPolynomial, deg(A) < deg(P). * @param P univariate irreducible GenPolynomial, gcd(A,P) == 1. * @return partial fraction container. */ @SuppressWarnings("unchecked") public PartialFraction baseAlgebraicPartialFractionIrreducibleAbsolute(GenPolynomial A, GenPolynomial P) { if (P == null || P.isZERO()) { throw new IllegalArgumentException(" P == null or P == 0"); } //System.out.println("\nP_base_algeb_part = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar > 1) { //System.out.println("facs_base_irred: univ"); throw new IllegalArgumentException("only for univariate polynomials"); } if (!pfac.coFac.isField()) { //System.out.println("facs_base_irred: field"); throw new IllegalArgumentException("only for field coefficients"); } List cfactors = new ArrayList(); List> cdenom = new ArrayList>(); List> afactors = new ArrayList>(); List>> adenom = new ArrayList>>(); // P linear if (P.degree(0) <= 1) { cfactors.add(A.leadingBaseCoefficient()); cdenom.add(P); return new PartialFraction(A, P, cfactors, cdenom, afactors, adenom); } // non linear case Factors afacs = factorsAbsoluteIrreducible(P); //System.out.println("linear algebraic factors = " + afacs); //System.out.println("afactors = " + afacs.afactors); //System.out.println("arfactors = " + afacs.arfactors); //System.out.println("arfactors pol = " + afacs.arfactors.get(0).poly); //System.out.println("arfactors2 = " + afacs.arfactors.get(0).afactors); List>> fact = afacs.getFactors(); //System.out.println("factors = " + fact); GenPolynomial> Pa = afacs.apoly; GenPolynomial> Aa = PolyUtil. convertToRecAlgebraicCoefficients(1, Pa.ring, A); GreatestCommonDivisorAbstract> aengine = GCDFactory.getProxy(afacs.afac); //System.out.println("denom = " + Pa); //System.out.println("number = " + Aa); List>> numbers = aengine.basePartialFraction(Aa, fact); //System.out.println("part frac = " + numbers); GenPolynomial> A0 = numbers.remove(0); if (!A0.isZERO()) { throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)"); } int i = 0; for (GenPolynomial> fa : fact) { GenPolynomial> an = numbers.get(i++); if (fa.degree(0) <= 1) { afactors.add(an.leadingBaseCoefficient()); adenom.add(fa); continue; } System.out.println("fa = " + fa); Factors> faf = afacs.getFactor(fa); System.out.println("faf = " + faf); List>>> fafact = faf.getFactors(); GenPolynomial>> Aaa = PolyUtil .> convertToRecAlgebraicCoefficients(1, faf.apoly.ring, an); GreatestCommonDivisorAbstract>> aaengine = GCDFactory .getImplementation(faf.afac); List>>> anumers = aaengine .basePartialFraction(Aaa, fafact); System.out.println("algeb part frac = " + anumers); GenPolynomial>> A0a = anumers.remove(0); if (!A0a.isZERO()) { throw new ArithmeticException(" A0 != 0: deg(A)>= deg(P)"); } int k = 0; for (GenPolynomial>> faa : fafact) { GenPolynomial>> ana = anumers.get(k++); System.out.println("faa = " + faa); System.out.println("ana = " + ana); if (faa.degree(0) > 1) { throw new ArithmeticException(" faa not linear"); } GenPolynomial> ana1 = (GenPolynomial>) (GenPolynomial) ana; GenPolynomial> faa1 = (GenPolynomial>) (GenPolynomial) faa; afactors.add(ana1.leadingBaseCoefficient()); adenom.add(faa1); } } return new PartialFraction(A, P, cfactors, cdenom, afactors, adenom); } /** * GenPolynomial absolute factorization of a polynomial. * @param P GenPolynomial. * @return factors map container: [p_1 -> e_1, ..., p_k -> e_k] with P * = prod_{i=1,...,k} p_i**e_i. Note: K(alpha) not yet * minimal. */ public FactorsMap factorsAbsolute(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } SortedMap, Long> factors = new TreeMap, Long>(); if (P.isZERO()) { return new FactorsMap(P, factors); } //System.out.println("\nP_mult = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar <= 1) { return baseFactorsAbsolute(P); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients"); } if (P.degree() <= 1) { factors.put(P, 1L); return new FactorsMap(P, factors); } // factor over K (=C) SortedMap, Long> facs = factors(P); if (debug && !isFactorization(P, facs)) { throw new ArithmeticException("isFactorization = false"); } logger.info("all K factors = {}", facs); // Q[X] SortedMap, Long> afactors = new TreeMap, Long>(); // factor over K(alpha) for (Map.Entry, Long> me : facs.entrySet()) { GenPolynomial p = me.getKey(); Long e = me.getValue(); //facs.get(p); if (p.degree() <= 1) { factors.put(p, e); } else { Factors afacs = factorsAbsoluteIrreducible(p); if (afacs.afac == null) { // absolute irreducible factors.put(p, e); } else { afactors.put(afacs, e); } } } //System.out.println("K(alpha) factors multi = " + factors); return new FactorsMap(P, factors, afactors); } /** * GenPolynomial absolute factorization of a squarefree polynomial. * @param P squarefree and primitive GenPolynomial. * @return factors list container: [p_1,...,p_k] with P = prod_{i=1, ..., k} * p_i. Note: K(alpha) not yet minimal. */ // @Override public FactorsList factorsAbsoluteSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return new FactorsList(P, factors); } //System.out.println("\nP = " + P); GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar <= 1) { return baseFactorsAbsoluteSquarefree(P); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients"); } if (P.degree() <= 1) { factors.add(P); return new FactorsList(P, factors); } // factor over K (=C) List> facs = factorsSquarefree(P); if (debug && !isFactorization(P, facs)) { throw new ArithmeticException("isFactorization = false"); } logger.info("all K factors = {}", facs); // Q[X] List> afactors = new ArrayList>(); // factor over K(alpha) for (GenPolynomial p : facs) { if (p.degree() <= 1) { factors.add(p); } else { Factors afacs = factorsAbsoluteIrreducible(p); if (debug) { logger.info("K(alpha) factors = {}", afacs); // K(alpha)[X] } if (afacs.afac == null) { // absolute irreducible factors.add(p); } else { afactors.add(afacs); } } } //System.out.println("K(alpha) factors = " + factors); return new FactorsList(P, factors, afactors); } /** * GenPolynomial absolute factorization of a irreducible polynomial. * @param P irreducible! GenPolynomial. * @return factors container: [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i * in K(alpha)[x] for suitable alpha and p_i irreducible over L[x], * where K \subset K(alpha) \subset L is an algebraically closed * field over K. Note: K(alpha) not yet minimal. */ public Factors factorsAbsoluteIrreducible(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } if (P.isZERO()) { return new Factors(P); } GenPolynomialRing pfac = P.ring; // K[x] if (pfac.nvar <= 1) { return baseFactorsAbsoluteIrreducible(P); } if (!pfac.coFac.isField()) { throw new IllegalArgumentException("only for field coefficients"); } //List> factors = new ArrayList>(); if (P.degree() <= 1) { return new Factors(P); } // find field extension K(alpha) GenPolynomial up = P; RingFactory cf = pfac.coFac; long cr = cf.characteristic().longValueExact(); // char might be larger if (cr == 0L) { cr = Long.MAX_VALUE; } long rp = 0L; for (int i = 0; i < (pfac.nvar - 1); i++) { rp = 0L; GenPolynomialRing nfac = pfac.contract(1); String[] vn = new String[] { pfac.getVars()[pfac.nvar - 1] }; GenPolynomialRing> rfac = new GenPolynomialRing>(nfac, 1, pfac.tord, vn); GenPolynomial> upr = PolyUtil. recursive(rfac, up); //System.out.println("upr = " + upr); GenPolynomial ep; do { if (rp >= cr) { throw new ArithmeticException("elements of prime field exhausted: " + cr); } C r = cf.fromInteger(rp); //cf.random(rp); //System.out.println("r = " + r); ep = PolyUtil. evaluateMainRecursive(nfac, upr, r); //System.out.println("ep = " + ep); rp++; } while (!isSquarefree(ep) /*todo: || ep.degree() <= 1*/); // max deg up = ep; pfac = nfac; } up = up.monic(); if (debug) { logger.info("P({}) = {}", rp, up); //System.out.println("up = " + up); } if (debug && !isSquarefree(up)) { throw new ArithmeticException("not irreducible up = " + up); } if (up.degree(0) <= 1) { return new Factors(P); } // find irreducible factor of up List> UF = baseFactorsSquarefree(up); //System.out.println("UF = " + UF); FactorsList aUF = baseFactorsAbsoluteSquarefree(up); //System.out.println("aUF = " + aUF); AlgebraicNumberRing arfac = aUF.findExtensionField(); //System.out.println("arfac = " + arfac); long e = up.degree(0); // search factor polynomial with smallest degree for (int i = 0; i < UF.size(); i++) { GenPolynomial upi = UF.get(i); long d = upi.degree(0); if (1 <= d && d <= e) { up = upi; e = up.degree(0); } } if (up.degree(0) <= 1) { return new Factors(P); } if (debug) { logger.info("field extension by {}", up); } List>> afactors = new ArrayList>>(); // setup field extension K(alpha) //String[] vars = new String[] { "z_" + Math.abs(up.hashCode() % 1000) }; String[] vars = pfac.newVars("z_"); pfac = pfac.copy(); //String[] ovars = pfac.setVars(vars); // side effects! //GenPolynomial aup = pfac.copy(up); // hack to exchange the variables //AlgebraicNumberRing afac = new AlgebraicNumberRing(aup,true); // since irreducible AlgebraicNumberRing afac = arfac; int depth = afac.depth(); //System.out.println("afac = " + afac); GenPolynomialRing> pafac = new GenPolynomialRing>(afac, P.ring.nvar, P.ring.tord, P.ring.getVars()); //System.out.println("pafac = " + pafac); // convert to K(alpha) GenPolynomial> Pa = PolyUtil. convertToRecAlgebraicCoefficients(depth, pafac, P); //System.out.println("Pa = " + Pa); // factor over K(alpha) FactorAbstract> engine = FactorFactory. getImplementation(afac); afactors = engine.factorsSquarefree(Pa); if (debug) { logger.info("K(alpha) factors multi = {}", afactors); } if (afactors.size() <= 1) { return new Factors(P); } // normalize first factor to monic GenPolynomial> p1 = afactors.get(0); AlgebraicNumber p1c = p1.leadingBaseCoefficient(); if (!p1c.isONE()) { GenPolynomial> p2 = afactors.get(1); afactors.remove(p1); afactors.remove(p2); p1 = p1.divide(p1c); p2 = p2.multiply(p1c); afactors.add(p1); afactors.add(p2); } // recursion for splitting field // find minimal field extension K(beta) \subset K(alpha) return new Factors(P, afac, Pa, afactors); } /** * GenPolynomial is absolute factorization. * @param facs factors container. * @return true if P = prod_{i=1,...,r} p_i, else false. */ public boolean isAbsoluteFactorization(Factors facs) { if (facs == null) { throw new IllegalArgumentException("facs may not be null"); } if (facs.afac == null) { return true; } GenPolynomial> fa = facs.apoly; GenPolynomialRing> pafac = fa.ring; GenPolynomial> t = pafac.getONE(); for (GenPolynomial> f : facs.afactors) { t = t.multiply(f); } //return fa.equals(t) || fa.equals(t.negate()); boolean b = fa.equals(t) || fa.equals(t.negate()); if (b) { return b; } if (facs.arfactors == null) { return false; } for (Factors> arp : facs.arfactors) { t = t.multiply(arp.poly); } b = fa.equals(t) || fa.equals(t.negate()); if (!b) { System.out.println("\nFactors: " + facs); System.out.println("fa = " + fa); System.out.println("t = " + t); } return b; } /** * GenPolynomial is absolute factorization. * @param facs factors list container. * @return true if P = prod_{i=1,...,r} p_i, else false. */ public boolean isAbsoluteFactorization(FactorsList facs) { if (facs == null) { throw new IllegalArgumentException("facs may not be null"); } GenPolynomial P = facs.poly; GenPolynomial t = P.ring.getONE(); for (GenPolynomial f : facs.factors) { t = t.multiply(f); } if (P.equals(t) || P.equals(t.negate())) { return true; } if (facs.afactors == null) { return false; } for (Factors fs : facs.afactors) { if (!isAbsoluteFactorization(fs)) { return false; } t = t.multiply(facs.poly); } //return P.equals(t) || P.equals(t.negate()); boolean b = P.equals(t) || P.equals(t.negate()); if (!b) { System.out.println("\nFactorsList: " + facs); System.out.println("P = " + P); System.out.println("t = " + t); } return b; } /** * GenPolynomial is absolute factorization. * @param facs factors map container. * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. */ public boolean isAbsoluteFactorization(FactorsMap facs) { if (facs == null) { throw new IllegalArgumentException("facs may not be null"); } GenPolynomial P = facs.poly; GenPolynomial t = P.ring.getONE(); for (Map.Entry, Long> me : facs.factors.entrySet()) { GenPolynomial f = me.getKey(); long e = me.getValue(); GenPolynomial g = f.power(e); t = t.multiply(g); } if (P.equals(t) || P.equals(t.negate())) { return true; } if (facs.afactors == null) { return false; } for (Map.Entry, Long> me : facs.afactors.entrySet()) { Factors fs = me.getKey(); if (!isAbsoluteFactorization(fs)) { return false; } long e = me.getValue(); GenPolynomial g = fs.poly.power(e); t = t.multiply(g); } boolean b = P.equals(t) || P.equals(t.negate()); if (!b) { System.out.println("\nFactorsMap: " + facs); System.out.println("P = " + P); System.out.println("t = " + t); } return b; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorAbstract.java000066400000000000000000000733001445075545500242050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.JASConfig; import edu.jas.kern.TimeStatus; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OptimizedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrderByName; import edu.jas.poly.TermOrderOptimization; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; import edu.jas.util.KsubSet; /** * Abstract factorization algorithms class. This class contains implementations * of all methods of the Factorization interface, except the method * for factorization of a squarefree polynomial. The methods to obtain * squarefree polynomials delegate the computation to the * GreatestCommonDivisor classes and are included for convenience. * @param coefficient type * @author Heinz Kredel * @see edu.jas.ufd.FactorFactory */ public abstract class FactorAbstract> implements Factorization { private static final Logger logger = LogManager.getLogger(FactorAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Gcd engine for base coefficients. */ protected final GreatestCommonDivisorAbstract engine; /** * Squarefree decompositon engine for base coefficients. */ protected final SquarefreeAbstract sengine; /** * No argument constructor. */ protected FactorAbstract() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param cfac coefficient ring factory. */ public FactorAbstract(RingFactory cfac) { engine = GCDFactory. getProxy(cfac); //engine = GCDFactory. getImplementation(cfac); sengine = SquarefreeFactory. getImplementation(cfac); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName(); } /** * GenPolynomial test if is irreducible. * @param P GenPolynomial. * @return true if P is irreducible, else false. */ @Override public boolean isIrreducible(GenPolynomial P) { if (!isSquarefree(P)) { return false; } List> F = factorsSquarefree(P); if (F.size() == 1) { return true; } else if (F.size() > 2) { return false; } else { //F.size() == 2 boolean cnst = false; for (GenPolynomial p : F) { if (p.isConstant()) { cnst = true; } } return cnst; } } /** * GenPolynomial test if a non trivial factorization exists. * @param P GenPolynomial. * @return true if P is reducible, else false. */ @Override public boolean isReducible(GenPolynomial P) { return !isIrreducible(P); } /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ @Override public boolean isSquarefree(GenPolynomial P) { return sengine.isSquarefree(P); } /** * GenPolynomial factorization of a multivariate squarefree polynomial, * using Kronecker substitution and variable order optimization. * @param P squarefree and primitive! (respectively monic) multivariate * GenPolynomial over the ring C. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> factorsSquarefreeOptimize(GenPolynomial P) { GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseFactorsSquarefree(P); } List> topt = new ArrayList>(1); topt.add(P); OptimizedPolynomialList opt = TermOrderOptimization. optimizeTermOrder(pfac, topt); P = opt.list.get(0); logger.info("optimized polynomial: {}", P); List iperm = TermOrderOptimization.inversePermutation(opt.perm); logger.info("optimize perm: {}, de-optimize perm: {}", opt.perm, iperm); ExpVector degv = P.degreeVector(); int[] donv = degv.dependencyOnVariables(); List> facs = null; if (degv.length() == donv.length) { // all variables appear logger.info("do.full factorsSquarefreeKronecker: {}", P); facs = factorsSquarefreeKronecker(P); } else { // not all variables appear, remove unused variables GenPolynomial pu = PolyUtil. removeUnusedUpperVariables(P); //GenPolynomial pl = PolyUtil. removeUnusedLowerVariables(pu); // not useful after optimize logger.info("do.sparse factorsSquarefreeKronecker: {}", pu); facs = factorsSquarefreeKronecker(pu); // pl List> fs = new ArrayList>(facs.size()); GenPolynomialRing pf = P.ring; //GenPolynomialRing pfu = pu.ring; for (GenPolynomial p : facs) { //GenPolynomial pel = p.extendLower(pfu, 0, 0L); GenPolynomial pe = p.extend(pf, 0, 0L); // pel fs.add(pe); } //System.out.println("fs = " + fs); facs = fs; } List> iopt = TermOrderOptimization. permutation(iperm, pfac, facs); logger.info("de-optimized polynomials: {}", iopt); facs = normalizeFactorization(iopt); return facs; } /** * GenPolynomial factorization of a squarefree polynomial, using Kronecker * substitution. * @param P squarefree and primitive! (respectively monic) GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @Override public List> factorsSquarefree(GenPolynomial P) { if (P != null && P.ring.nvar > 1) { logger.warn("no multivariate factorization for {}: falling back to Kronecker algorithm in {}", P, P.ring.toScript()); //if (P.ring.characteristic().signum() == 0) { // throw new IllegalArgumentException("P.ring.characteristic().signum() == 0"); //} //throw new RuntimeException("get stack trace"); } //if (logger.isInfoEnabled()) { // logger.info(StringUtil.selectStackTrace("edu\\.jas.*")); //} return factorsSquarefreeKronecker(P); //return factorsSquarefreeOptimize(P); // test only } /** * GenPolynomial factorization of a squarefree polynomial, using Kronecker * substitution. * @param P squarefree and primitive! (respectively monic) GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> factorsSquarefreeKronecker(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 1) { return baseFactorsSquarefree(P); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.degreeVector().totalDeg() <= 1L) { factors.add(P); return factors; } long d = P.degree() + 1L; GenPolynomial kr = PolyUfdUtil. substituteKronecker(P, d); GenPolynomialRing ufac = kr.ring; ufac.setVars(ufac.newVars("zz")); // side effects logger.info("deg(subs(P,d={})) = {}, original degrees: {}", d, kr.degree(0), P.degreeVector()); if (debug) { logger.info("subs(P,d={}) = {}", d, kr); } if (kr.degree(0) > 100) { logger.warn("Kronecker substitution has too high degree {}", kr.degree(0)); TimeStatus.checkTime("degree > 100"); } if (JASConfig.MAX_DEGREE_KRONECKER_FACTORIZATION > 0 && JASConfig.MAX_DEGREE_KRONECKER_FACTORIZATION < kr.degree(0)) { throw new ArithmeticException( "Kronecker substitution maximum degree (see JASConfig) exceeded: " + kr.degree(0)); } // factor Kronecker polynomial List> ulist = new ArrayList>(); // kr might not be squarefree so complete factor univariate SortedMap, Long> slist = baseFactors(kr); if (debug && !isFactorization(kr, slist)) { logger.warn("kr = {}", kr); logger.warn("slist = {}", slist); throw new ArithmeticException("no factorization"); } for (Map.Entry, Long> me : slist.entrySet()) { GenPolynomial g = me.getKey(); long e = me.getValue(); // slist.get(g); for (int i = 0; i < e; i++) { // is this really required? yes! ulist.add(g); } } //System.out.println("ulist = " + ulist); if (ulist.size() == 1 && ulist.get(0).degree() == P.degree()) { factors.add(P); return factors; } //wrong: List> klist = PolyUfdUtil. backSubstituteKronecker(pfac, ulist, d); //System.out.println("back(klist) = " + PolyUfdUtil. backSubstituteKronecker(pfac, ulist, d)); logger.info("ulist = {}", ulist); // combine trial factors int dl = ulist.size() - 1; //(ulist.size() + 1) / 2; //System.out.println("dl = " + dl); int ti = 0; GenPolynomial u = P; long deg = (u.degree() + 1L) / 2L; // max deg ExpVector evl = u.leadingExpVector(); ExpVector evt = u.trailingExpVector(); //System.out.println("deg = " + deg); for (int j = 1; j <= dl; j++) { KsubSet> ps = new KsubSet>(ulist, j); for (List> flist : ps) { //System.out.println("flist = " + flist); GenPolynomial utrial = ufac.getONE(); for (int k = 0; k < flist.size(); k++) { utrial = utrial.multiply(flist.get(k)); } GenPolynomial trial = PolyUfdUtil. backSubstituteKronecker(pfac, utrial, d); ti++; if (ti % 2000 == 0) { logger.warn("ti({})", ti); TimeStatus.checkTime(ti + " % 2000 == 0"); } if (JASConfig.MAX_ITERATIONS_KRONECKER_FACTORIZATION > 0 && JASConfig.MAX_ITERATIONS_KRONECKER_FACTORIZATION < ti) { throw new ArithmeticException( "Kronecker substitution iteration limit (see JASConfig) exceeeded: " + ti); } if (!evl.multipleOf(trial.leadingExpVector())) { continue; } if (!evt.multipleOf(trial.trailingExpVector())) { continue; } if (trial.degree() > deg || trial.isConstant()) { continue; } trial = trial.monic(); if (ti % 15000 == 0) { logger.warn("ndl = {}, deg(u) = {}", dl, deg); logger.warn("ulist = {}", ulist); logger.warn("kr = {}", kr); logger.warn("u = {}", u); logger.warn("trial = {}", trial); } GenPolynomial rem = PolyUtil. baseSparsePseudoRemainder(u, trial); //System.out.println(" rem = " + rem); if (rem.isZERO()) { logger.info("trial = {}", trial); //System.out.println("trial = " + trial); factors.add(trial); u = PolyUtil. basePseudoDivide(u, trial); //u = u.divide( trial ); evl = u.leadingExpVector(); evt = u.trailingExpVector(); if (u.isConstant()) { j = dl + 1; break; } //if (ulist.removeAll(flist)) { // wrong ulist = removeOnce(ulist, flist); //System.out.println("new ulist = " + ulist); dl = (ulist.size() + 1) / 2; j = 0; // since j++ break; } } } if (!u.isONE() && !u.equals(P)) { logger.info("rest u = {}", u); factors.add(u); } if (factors.size() == 0) { logger.info("irred P = {}", P); factors.add(P); // == u } return normalizeFactorization(factors); } /** * Remove one occurrence of elements. * @param a list of objects. * @param b list of objects. * @return remove every element of b from a, but only one occurrence. * Note: not available in java.util. */ static List removeOnce(List a, List b) { List res = new ArrayList(); res.addAll(a); for (T e : b) { @SuppressWarnings("unused") boolean t = res.remove(e); } return res; } /** * Univariate GenPolynomial factorization ignoring multiplicities. * @param P GenPolynomial in one variable. * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some * e_i. */ public List> baseFactorsRadical(GenPolynomial P) { return new ArrayList>(baseFactors(P).keySet()); } /** * Univariate GenPolynomial factorization. * @param P GenPolynomial in one variable. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i. */ public SortedMap, Long> baseFactors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; SortedMap, Long> factors = new TreeMap, Long>(pfac.getComparator()); if (P.isZERO()) { return factors; } if (pfac.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " only for univariate polynomials"); } if (P.isConstant()) { factors.put(P, 1L); return factors; } C c; if (pfac.coFac.isField()) { //pfac.characteristic().signum() > 0 c = P.leadingBaseCoefficient(); } else { c = engine.baseContent(P); // move sign to the content if (P.signum() < 0 && c.signum() > 0) { c = c.negate(); //P = P.negate(); } } if (!c.isONE()) { GenPolynomial pc = pfac.getONE().multiply(c); factors.put(pc, 1L); P = P.divide(c); // make primitive or monic } logger.info("base facs for P = {}", P); SortedMap, Long> facs = sengine.baseSquarefreeFactors(P); if (facs == null || facs.size() == 0) { facs = new TreeMap, Long>(); facs.put(P, 1L); } if (logger.isInfoEnabled() && (facs.size() > 1 || (facs.size() == 1 && facs.get(facs.firstKey()) > 1))) { logger.info("squarefree facs = {}", facs); //System.out.println("sfacs = " + facs); //boolean tt = isFactorization(P,facs); //System.out.println("sfacs tt = " + tt); } for (Map.Entry, Long> me : facs.entrySet()) { GenPolynomial g = me.getKey(); Long k = me.getValue(); //facs.get(g); //System.out.println("g = " + g); if (pfac.coFac.isField() && !g.leadingBaseCoefficient().isONE()) { g = g.monic(); // how can this happen? logger.warn("squarefree facs mon = {}", g); } if (g.degree(0) <= 1) { if (!g.isONE()) { factors.put(g, k); } } else { List> sfacs = baseFactorsSquarefree(g); if (debug) { logger.info("factors of squarefree = {}", sfacs); } for (GenPolynomial h : sfacs) { Long j = factors.get(h); // evtl. constants if (j != null) { k += j; } if (!h.isONE()) { factors.put(h, k); } } } } //System.out.println("factors = " + factors); return factors; } /** * Univariate GenPolynomial factorization of a squarefree polynomial. * @param P squarefree and primitive! GenPolynomial in one variable. * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i. */ public abstract List> baseFactorsSquarefree(GenPolynomial P); /** * GenPolynomial factorization ignoring multiplicities. * @param P GenPolynomial. * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some * e_i. */ @Override public List> factorsRadical(GenPolynomial P) { return new ArrayList>(factors(P).keySet()); } /** * GenPolynomial list factorization ignoring multiplicities. * @param L list of GenPolynomials. * @return [p_1, ..., p_k] with p = prod_{i=1,...,k} p_i**{e_i} for some e_i * for all p in L. */ public List> factorsRadical(List> L) { SortedSet> facs = new TreeSet>(); for (GenPolynomial p : L) { List> fs = factorsRadical(p); facs.addAll(fs); } return new ArrayList>(facs); } /** * GenPolynomial factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i. */ @Override public SortedMap, Long> factors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 1) { return baseFactors(P); } SortedMap, Long> factors = new TreeMap, Long>(pfac.getComparator()); if (P.isZERO()) { return factors; } if (P.isConstant()) { factors.put(P, 1L); return factors; } if (!pfac.tord.equals(TermOrderByName.INVLEX)) { logger.warn("wrong term order {}, factorization may not be correct, better use {}", pfac.tord, TermOrderByName.INVLEX); } C c; if (pfac.coFac.isField()) { c = P.leadingBaseCoefficient(); } else { c = engine.baseContent(P); // move sign to the content if (P.signum() < 0 && c.signum() > 0) { c = c.negate(); //P = P.negate(); } } if (!c.isONE()) { GenPolynomial pc = pfac.getONE().multiply(c); factors.put(pc, 1L); P = P.divide(c); // make base primitive or base monic } logger.info("base primitive part P = {}", P); GenPolynomial[] cpp = engine.contentPrimitivePart(P); GenPolynomial pc = cpp[0]; if (!pc.isONE()) { SortedMap, Long> rec = factors(pc); // recursion for (Map.Entry, Long> me : rec.entrySet()) { GenPolynomial g = me.getKey(); Long d = me.getValue(); GenPolynomial pn = g.extend(pfac,0,0L); factors.put(pn,d); } logger.info("content factors = {}", factors); } P = cpp[1]; logger.info("primitive part P = {}", P); if (P.isONE()) { return factors; } SortedMap, Long> facs = sengine.squarefreeFactors(P); if (facs == null || facs.size() == 0) { facs = new TreeMap, Long>(); facs.put(P, 1L); throw new RuntimeException("this should not happen, facs is empty: " + facs); } if (logger.isInfoEnabled()) { if (facs.size() > 1) { logger.info("squarefree mfacs = {}", facs); } else if (facs.size() == 1 && facs.get(facs.firstKey()) > 1L) { logger.info("squarefree #mfacs 1-n = {}", facs); } else { logger.info("squarefree #mfacs 1-1 = {}", facs); } } for (Map.Entry, Long> me : facs.entrySet()) { GenPolynomial g = me.getKey(); if (g.isONE()) { // skip 1 continue; } Long d = me.getValue(); // facs.get(g); List> sfacs = factorsSquarefree(g); logger.info("factors of squarefree ^{} = {}", d, sfacs); for (GenPolynomial h : sfacs) { long dd = d; Long j = factors.get(h); // evtl. constants if (j != null) { dd += j; } factors.put(h, dd); } } //System.out.println("factors = " + factors); return factors; } /** * GenPolynomial greatest squarefree divisor. Delegates computation to a * GreatestCommonDivisor class. * @param P GenPolynomial. * @return squarefree(P). */ @Override public GenPolynomial squarefreePart(GenPolynomial P) { return sengine.squarefreePart(P); } /** * GenPolynomial primitive part. Delegates computation to a * GreatestCommonDivisor class. * @param P GenPolynomial. * @return primitivePart(P). */ public GenPolynomial primitivePart(GenPolynomial P) { return engine.primitivePart(P); } /** * GenPolynomial base primitive part. Delegates computation to a * GreatestCommonDivisor class. * @param P GenPolynomial. * @return basePrimitivePart(P). */ public GenPolynomial basePrimitivePart(GenPolynomial P) { return engine.basePrimitivePart(P); } /** * GenPolynomial squarefree factorization. Delegates computation to a * GreatestCommonDivisor class. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i. */ @Override public SortedMap, Long> squarefreeFactors(GenPolynomial P) { return sengine.squarefreeFactors(P); } /** * GenPolynomial is factorization. * @param P GenPolynomial. * @param F = [p_1,...,p_k]. * @return true if P = prod_{i=1,...,r} p_i, else false. */ @Override public boolean isFactorization(GenPolynomial P, List> F) { return sengine.isFactorization(P, F); // test irreducible } /** * GenPolynomial is factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. */ @Override public boolean isFactorization(GenPolynomial P, SortedMap, Long> F) { return sengine.isFactorization(P, F); // test irreducible } /** * Degree of a factorization. * @param F a factors map [p_1 -> e_1, ..., p_k -> e_k]. * @return sum_{i=1,...,k} degree(p_i)*e_i. */ public long factorsDegree(SortedMap, Long> F) { long d = 0; for (Map.Entry, Long> me : F.entrySet()) { GenPolynomial p = me.getKey(); long e = me.getValue(); //F.get(p); d += p.degree() * e; } return d; } /** * GenPolynomial is factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. */ public boolean isRecursiveFactorization(GenPolynomial> P, SortedMap>, Long> F) { return sengine.isRecursiveFactorization(P, F); // test irreducible } /** * Recursive GenPolynomial factorization of a squarefree polynomial. * @param P squarefree recursive GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ public List>> recursiveFactorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; GenPolynomialRing qi = (GenPolynomialRing) pfac.coFac; GenPolynomialRing ifac = qi.extend(pfac.getVars()); GenPolynomial Pi = PolyUtil. distribute(ifac, P); //System.out.println("Pi = " + Pi); C ldcf = Pi.leadingBaseCoefficient(); if (!ldcf.isONE() && ldcf.isUnit()) { //System.out.println("ldcf = " + ldcf); Pi = Pi.monic(); } // factor in C[x_1,...,x_n,y_1,...,y_m] List> ifacts = factorsSquarefree(Pi); logger.info("ifacts = {}", ifacts); if (ifacts.size() <= 1) { factors.add(P); return factors; } if (!ldcf.isONE() && ldcf.isUnit()) { GenPolynomial r = ifacts.get(0); ifacts.remove(r); r = r.multiply(ldcf); ifacts.add(0, r); } List>> rfacts = PolyUtil. recursive(pfac, ifacts); //System.out.println("rfacts = " + rfacts); if (logger.isDebugEnabled()) { logger.info("recfacts = {}", rfacts); } factors.addAll(rfacts); return factors; } /** * Recursive GenPolynomial factorization. * @param P recursive GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i. */ public SortedMap>, Long> recursiveFactors(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing> pfac = P.ring; SortedMap>, Long> factors = new TreeMap>, Long>( pfac.getComparator()); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.put(P, 1L); return factors; } GenPolynomialRing qi = (GenPolynomialRing) pfac.coFac; GenPolynomialRing ifac = qi.extend(pfac.getVars()); GenPolynomial Pi = PolyUtil. distribute(ifac, P); //System.out.println("Pi = " + Pi); C ldcf = Pi.leadingBaseCoefficient(); if (!ldcf.isONE() && ldcf.isUnit()) { //System.out.println("ldcf = " + ldcf); Pi = Pi.monic(); } // factor in C[x_1,...,x_n,y_1,...,y_m] SortedMap, Long> dfacts = factors(Pi); logger.info("dfacts = {}", dfacts); if (!ldcf.isONE() && ldcf.isUnit()) { GenPolynomial r = dfacts.firstKey(); Long E = dfacts.remove(r); r = r.multiply(ldcf); dfacts.put(r, E); } for (Map.Entry, Long> me : dfacts.entrySet()) { GenPolynomial f = me.getKey(); Long E = me.getValue(); //dfacts.get(f); GenPolynomial> rp = PolyUtil. recursive(pfac, f); factors.put(rp, E); } //System.out.println("rfacts = " + rfacts); logger.info("recursive factors = {}", factors); return factors; } /** * Normalize factorization. p'_i > 0 for i > 1 and p'_1 != 1 if k > * 1. * @param F = [p_1,...,p_k]. * @return F' = [p'_1,...,p'_k]. */ public List> normalizeFactorization(List> F) { if (F == null || F.size() <= 1) { return F; } List> Fp = new ArrayList>(F.size()); GenPolynomial f0 = F.get(0); for (int i = 1; i < F.size(); i++) { GenPolynomial fi = F.get(i); if (fi.signum() < 0) { fi = fi.negate(); f0 = f0.negate(); } if (!fi.isONE()) { Fp.add(fi); } } if (!f0.isONE()) { Fp.add(0, f0); } return Fp; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorAlgebraic.java000066400000000000000000000253731445075545500243220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; /** * Algebraic number coefficients factorization algorithms. This class implements * factorization methods for polynomials over algebraic numbers over rational * numbers or over (prime) modular integers. * @author Heinz Kredel * @param coefficient type */ public class FactorAlgebraic> extends FactorAbsolute> { private static final Logger logger = LogManager.getLogger(FactorAlgebraic.class); private static final boolean debug = logger.isDebugEnabled(); /** * Factorization engine for base coefficients. */ public final FactorAbstract factorCoeff; /** * No argument constructor. Note: can't use this constructor. */ protected FactorAlgebraic() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac algebraic number factory. */ public FactorAlgebraic(AlgebraicNumberRing fac) { this(fac, FactorFactory. getImplementation(fac.ring.coFac)); } /** * Constructor. * @param fac algebraic number factory. * @param factorCoeff factorization engine for polynomials over base * coefficients. */ public FactorAlgebraic(AlgebraicNumberRing fac, FactorAbstract factorCoeff) { super(fac); this.factorCoeff = factorCoeff; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<AlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> baseFactorsSquarefree( GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // Q(alpha)[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; AlgebraicNumber ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); if (debug) { Squarefree> sqengine = SquarefreeFactory .> getImplementation(afac); if (!sqengine.isSquarefree(P)) { throw new RuntimeException("P not squarefree: " + sqengine.squarefreeFactors(P)); } GenPolynomial modu = afac.modul; if (!factorCoeff.isIrreducible(modu)) { throw new RuntimeException("modul not irreducible: " + factorCoeff.factors(modu)); } System.out.println("P squarefree and modul irreducible"); //GreatestCommonDivisor> aengine //= GCDFactory.> getProxy(afac); // = new GreatestCommonDivisorSimple>( /*cfac.coFac*/ ); } // search squarefree norm long k = 0L; long ks = k; GenPolynomial res = null; boolean sqf = false; //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 101, -101, 1001, -1001 }; //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 23, -23, 167, -167 }; //int[] klist = new int[] { 0, -1, -2, 1, 2, -3, 3 }; int[] klist = new int[] { 0, -1, -2, 1, 2 }; int ki = 0; while (!sqf) { // k = 0,1,2,-1,-2 if (ki >= klist.length) { break; } k = klist[ki]; ki++; // compute norm with x -> ( y - k x ) ks = k; res = PolyUfdUtil. norm(P, ks); //System.out.println("res = " + res); if (res.isZERO() || res.isConstant()) { continue; } sqf = factorCoeff.isSquarefree(res); } // if Res is now squarefree, else must take radical factorization List> nfacs; if (!sqf) { //System.out.println("\nres = " + res); logger.warn("sqf({}) = {}", ks, res.degree()); //res = factorCoeff.squarefreePart(res); // better use obtained factors //res = factorCoeff.baseFactors(res).lastKey(); } //res = res.monic(); logger.info("res = {}", res); nfacs = factorCoeff.baseFactorsRadical(res); logger.info("res facs = {}", nfacs); // Q[X] if (nfacs.size() == 1) { factors.add(P); return factors; } // compute gcds of factors with polynomial in Q(alpha)[X] GenPolynomial> Pp = P; //System.out.println("Pp = " + Pp); GenPolynomial> Ni; for (GenPolynomial nfi : nfacs) { //System.out.println("nfi = " + nfi); Ni = PolyUfdUtil. substituteConvertToAlgebraicCoefficients(pfac, nfi, ks); if (logger.isInfoEnabled()) { logger.info("Ni = {}", Ni); //System.out.println("Pp = " + Pp); } // compute gcds of factors with polynomial GenPolynomial> pni = engine.gcd(Ni, Pp); if (!pni.leadingBaseCoefficient().isONE()) { pni = pni.monic(); } logger.info("gcd(Ni,Pp) = {}", pni); if (!pni.isONE()) { factors.add(pni); Pp = Pp.divide(pni); } } if (!Pp.isZERO() && !Pp.isONE()) { // irreducible rest factors.add(Pp); } //System.out.println("afactors = " + factors); return factors; } /** * GenPolynomial factorization of a squarefree polynomial. * @param P squarefree and primitive! (respectively monic) * GenPolynomial<AlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> factorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // Q(alpha)[x1,...,xn] if (pfac.nvar <= 1) { throw new IllegalArgumentException("only for multivariate polynomials"); } //AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; AlgebraicNumber ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } if (P.degreeVector().totalDeg() <= 1L) { factors.add(P); return factors; } //System.out.println("\nP = " + P); // search squarefree norm long k = 0L; long ks = k; GenPolynomial res = null; boolean sqf = false; //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 101, -101, 1001, -1001 }; //int[] klist = new int[]{ 0, 1, 2, 3, -1, -2, -3 , 5, -5, 7, -7, 23, -23, 167, -167 }; //int[] klist = new int[] { 0, -1, -2, 1, 2, -3, 3 }; int[] klist = new int[] { 0, -1, -2, 1, 2 }; int ki = 0; while (!sqf) { // k = 0,1,2,-1,-2 if (ki >= klist.length) { logger.warn("sqf({}) = {}", ks, res.degree()); break; } k = klist[ki]; ki++; // compute norm with x -> ( y - k x ) ks = k; res = PolyUfdUtil. norm(P, ks); //System.out.println("res = " + res); if (res.isZERO() || res.isConstant()) { continue; } sqf = factorCoeff.isSquarefree(res); //System.out.println("resfact = " + factorCoeff.factors(res) + "\n"); } // if Res is now squarefree, else must take radical factorization List> nfacs; if (!sqf) { System.out.println("sqf_" + pfac.nvar + "(" + ks + ") = " + res.degree()); } //res = res.monic(); logger.info("res = {}", res); logger.info("factorCoeff = {}", factorCoeff); nfacs = factorCoeff.factorsRadical(res); //System.out.println("\nnfacs = " + nfacs); // Q[X] logger.info("res facs = {}", nfacs); // Q[X] if (nfacs.size() == 1) { factors.add(P); return factors; } // compute gcds of factors with polynomial in Q(alpha)[X] GenPolynomial> Pp = P; //System.out.println("Pp = " + Pp); GenPolynomial> Ni; for (GenPolynomial nfi : nfacs) { //System.out.println("nfi = " + nfi); Ni = PolyUfdUtil. substituteConvertToAlgebraicCoefficients(pfac, nfi, ks); if (logger.isInfoEnabled()) { logger.info("Ni = {}", Ni); //System.out.println("Pp = " + Pp); } // compute gcds of factors with polynomial GenPolynomial> pni = engine.gcd(Ni, Pp); if (!pni.leadingBaseCoefficient().isONE()) { //System.out.println("gcd(Ni,Pp) not monic " + pni); pni = pni.monic(); } logger.info("gcd(Ni,Pp) = {}", pni); //System.out.println("gcd(Ni,Pp) = " + pni); if (!pni.isONE()) { factors.add(pni); Pp = Pp.divide(pni); } } if (!Pp.isZERO() && !Pp.isONE()) { // irreducible rest factors.add(Pp); } //factors.add(P); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorComplex.java000066400000000000000000000145651445075545500240610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Complex coefficients factorization algorithms. This class implements * factorization methods for polynomials over Complex numbers via the algebraic * number C(i) over rational numbers or over (prime) modular integers. Note: * Decomposition to linear factors is only via absolute factorization since * Complex are not the analytic complex numbers. * @author Heinz Kredel * @param coefficient type */ public class FactorComplex> extends FactorAbsolute> { private static final Logger logger = LogManager.getLogger(FactorComplex.class); private static final boolean debug = logger.isDebugEnabled(); /** * Factorization engine for algebraic coefficients. */ public final FactorAbstract> factorAlgeb; /** * Complex algebraic factory. */ public final AlgebraicNumberRing afac; /** * No argument constructor. Note: can't use this constructor. */ protected FactorComplex() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac complex number factory. */ public FactorComplex(RingFactory> fac) { // why is this constructor required? this((ComplexRing) fac); } /** * Constructor. * @param fac complex number factory. */ public FactorComplex(ComplexRing fac) { super(fac); this.afac = fac.algebraicRing(); this.factorAlgeb = FactorFactory. getImplementation(afac); } /** * Constructor. * @param fac complex number factory. * @param factorAlgeb factorization engine for polynomials over algebraic coefficients. */ public FactorComplex(ComplexRing fac, FactorAbstract> factorAlgeb) { super(fac); this.afac = fac.algebraicRing(); this.factorAlgeb = factorAlgeb; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<AlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> baseFactorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // CC[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } ComplexRing cfac = (ComplexRing) pfac.coFac; if (!afac.ring.coFac.equals(cfac.ring)) { throw new IllegalArgumentException("coefficient rings do not match"); } Complex ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); GenPolynomialRing> pafac = new GenPolynomialRing>(afac, pfac); GenPolynomial> A = PolyUtil. algebraicFromComplex(pafac, P); //System.out.println("A = " + A); List>> afactors = factorAlgeb.baseFactorsSquarefree(A); if (debug) { logger.info("complex afactors = {}", afactors); } for (GenPolynomial> pa : afactors) { GenPolynomial> pc = PolyUtil. complexFromAlgebraic(pfac, pa); factors.add(pc); } //System.out.println("cfactors = " + factors); return factors; } /** * GenPolynomial factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<AlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> factorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // CC[x] if (pfac.nvar <= 1) { throw new IllegalArgumentException("only for multivariate polynomials"); } ComplexRing cfac = (ComplexRing) pfac.coFac; if (!afac.ring.coFac.equals(cfac.ring)) { throw new IllegalArgumentException("coefficient rings do not match"); } Complex ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); GenPolynomialRing> pafac = new GenPolynomialRing>(afac, pfac); GenPolynomial> A = PolyUtil. algebraicFromComplex(pafac, P); //System.out.println("A = " + A); List>> afactors = factorAlgeb.factorsSquarefree(A); if (debug) { logger.info("complex afactors = {}", afactors); } for (GenPolynomial> pa : afactors) { GenPolynomial> pc = PolyUtil. complexFromAlgebraic(pfac, pa); factors.add(pc); } //System.out.println("cfactors = " + factors); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorFactory.java000066400000000000000000000203421445075545500240470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Factorization algorithms factory. Select appropriate factorization engine * based on the coefficient types. *

* Usage: To create objects that implement the Factorization * interface use the FactorFactory. It will select an appropriate * implementation based on the types of polynomial coefficients C. To obtain an * implementation use getImplementation(), it returns an object of * a class which extends the FactorAbstract class which implements * the Factorization interface. * *

 * Factorization<CT> engine;
 * engine = FactorFactory.<CT> getImplementation(cofac);
 * c = engine.factors(a);
 * 
* *

* For example, if the coefficient type is BigInteger, the usage looks like * *

 * BigInteger cofac = new BigInteger();
 * Factorization<BigInteger> engine;
 * engine = FactorFactory.getImplementation(cofac);
 * Sm = engine.factors(poly);
 * 
* * @author Heinz Kredel * @see edu.jas.ufd.Factorization#factors(edu.jas.poly.GenPolynomial P) */ public class FactorFactory { private static final Logger logger = LogManager.getLogger(FactorFactory.class); /** * Protected factory constructor. */ protected FactorFactory() { } /** * Determine suitable implementation of factorization algorithm, case * ModInteger. * @param fac ModIntegerRing. * @return factorization algorithm implementation. */ public static FactorAbstract getImplementation(ModIntegerRing fac) { return new FactorModular(fac); } /** * Determine suitable implementation of factorization algorithm, case * ModInteger. * @param fac ModIntegerRing. * @return factorization algorithm implementation. */ public static FactorAbstract getImplementation(ModLongRing fac) { return new FactorModular(fac); } /** * Determine suitable implementation of factorization algorithm, case * ModInteger. * @param fac ModIntegerRing. * @return factorization algorithm implementation. */ public static FactorAbstract getImplementation(ModIntRing fac) { return new FactorModular(fac); } /** * Determine suitable implementation of factorization algorithm, case * BigInteger. * @param fac BigInteger. * @return factorization algorithm implementation. */ public static FactorAbstract getImplementation(BigInteger fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } return new FactorInteger(); } /** * Determine suitable implementation of factorization algorithms, case * BigRational. * @param fac BigRational. * @return factorization algorithm implementation. */ public static FactorAbstract getImplementation(BigRational fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } return new FactorRational(); } /** * Determine suitable implementation of factorization algorithms, case * AlgebraicNumber<C>. * @param fac AlgebraicNumberRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ @SuppressWarnings("unchecked") public static > FactorAbstract> getImplementation( AlgebraicNumberRing fac) { int s = fac.characteristic().signum(); if (s > 0) { return new FactorModularBerlekamp/*>*/((RingFactory)fac); } else { return new FactorAlgebraic(fac); } } /** * Determine suitable implementation of factorization algorithms, case * Complex<C>. * @param fac ComplexRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract> getImplementation( ComplexRing fac) { return new FactorComplex(fac); } /** * Determine suitable implementation of factorization algorithms, case * Quotient<C>. * @param fac QuotientRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract> getImplementation( QuotientRing fac) { return new FactorQuotient(fac); } /** * Determine suitable implementation of factorization algorithms, case * recursive GenPolynomial<C>. Use recursiveFactors(). * @param fac GenPolynomialRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return factorization algorithm implementation. */ public static > FactorAbstract getImplementation(GenPolynomialRing fac) { return getImplementation(fac.coFac); } /** * Determine suitable implementation of factorization algorithms, other * cases. * @param coefficient type * @param fac RingFactory<C>. * @return factorization algorithm implementation. */ @SuppressWarnings( "unchecked" ) public static > FactorAbstract getImplementation(RingFactory fac) { logger.info("factor factory = {}", fac.getClass().getName()); //System.out.println("fac_o_ufd = " + fac.getClass().getName()); FactorAbstract/*raw type*/ ufd = null; AlgebraicNumberRing afac = null; ComplexRing cfac = null; QuotientRing qfac = null; GenPolynomialRing pfac = null; Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new FactorInteger(); } else if (ofac instanceof BigRational) { ufd = new FactorRational(); } else if (ofac instanceof ModIntegerRing) { ufd = new FactorModular(fac); } else if (ofac instanceof ModLongRing) { ufd = new FactorModular(fac); } else if (ofac instanceof ModIntRing) { ufd = new FactorModular(fac); } else if (ofac instanceof ComplexRing) { cfac = (ComplexRing) ofac; ufd = new FactorComplex(cfac); } else if (ofac instanceof AlgebraicNumberRing) { //System.out.println("afac_o = " + ofac); afac = (AlgebraicNumberRing) ofac; //ofac = afac.ring.coFac; int s = afac.characteristic().signum(); if (s > 0) { ufd = new FactorModularBerlekamp/*raw */(afac); } else { ufd = new FactorAlgebraic/*raw */(afac); } } else if (ofac instanceof QuotientRing) { //System.out.println("qfac_o = " + ofac); qfac = (QuotientRing) ofac; ufd = new FactorQuotient/*raw */(qfac); } else if (ofac instanceof GenPolynomialRing) { //System.out.println("qfac_o = " + ofac); pfac = (GenPolynomialRing) ofac; ufd = getImplementation(pfac.coFac); } else { throw new IllegalArgumentException( "no factorization implementation for " + fac.getClass().getName()); } //logger.info("implementation = {}", ufd); return (FactorAbstract) ufd; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorFraction.java000066400000000000000000000137161445075545500242140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.QuotPair; import edu.jas.structure.QuotPairFactory; /** * Fraction factorization algorithms. This class implements * factorization methods for fractions represended as pairs of * polynomials. * @author Heinz Kredel */ public class FactorFraction, D extends GcdRingElem & QuotPair> > { private static final Logger logger = LogManager.getLogger(FactorFraction.class); /** * Quotient pairs ring factory. * D == QuotPair<GenPolynomial<C>> must hold. */ protected final QuotPairFactory, D> qfac; /** * Factorization engine for normal coefficients. */ protected final FactorAbstract nengine; /** * No argument constructor. */ protected FactorFraction() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac coefficient quotient ring factory. */ public FactorFraction(QuotPairFactory,D> fac) { this(fac, FactorFactory. getImplementation(((GenPolynomialRing) fac.pairFactory()).coFac)); } /** * Constructor. * @param fac coefficient quotient ring factory. * @param nengine factorization engine for polynomials over base * coefficients. */ public FactorFraction(QuotPairFactory,D> fac, FactorAbstract nengine) { this.qfac = fac; this.nengine = nengine; logger.info("qfac.fac: {}", qfac.pairFactory()); //.toScript() } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName(); } /** * Test if a quotient pair is irreducible. * @param P quotient pair (num,den), with gcd(num,den) == 1. * @return true if P is irreducible, else false. */ public boolean isIrreducible(D P) { SortedMap F = factors(P); for (Long e : F.values()) { if (e == null || e != 1L) { return false; } } if (F.size() <= 1) { // x/1 return true; } else if (F.size() == 2) { // x/1, 1/y List pp = new ArrayList( F.keySet() ); D f = pp.get(0); D g = pp.get(1); if ((f.numerator().isONE() && g.denominator().isONE()) || (g.numerator().isONE() && f.denominator().isONE())) { return true; } return false; } else if (F.size() > 2) { return false; } return false; } /** * Test if a non trivial factorization exists. * @param P quotient pair (num,den), with gcd(num,den) == 1. * @return true if P is reducible, else false. */ public boolean isReducible(D P) { return !isIrreducible(P); } /** * Quotient pair factorization. * @param P quotient pair (num,den), with gcd(num,den) == 1. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} p_i**e_i. */ public SortedMap factors(D P) { // D == QuotPair> SortedMap facs = new TreeMap(); if (P == null) { return facs; } GenPolynomial n = P.numerator(); GenPolynomial d = P.denominator(); if (n.isZERO() || d.isZERO()) { return facs; } if (n.isONE() && d.isONE()) { facs.put(P,1L); return facs; } // assert gcd(n,d) == 1 GenPolynomial one = qfac.pairFactory().getONE(); if (!n.isONE()) { SortedMap, Long> nfacs = nengine.factors(n); for (Map.Entry,Long> m : nfacs.entrySet()) { D q = qfac.create(m.getKey(), one); facs.put(q, m.getValue()); } } if (!d.isONE()) { SortedMap, Long> dfacs = nengine.factors(d); for (Map.Entry,Long> m : dfacs.entrySet()) { D q = qfac.create(one, m.getKey()); facs.put(q, m.getValue()); } } return facs; } /** * Test quotient pair factorization. * @param P quotient pair. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. */ public boolean isFactorization(D P, SortedMap F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } D t = null; //P.ring.getONE(); for (Map.Entry me : F.entrySet()) { D f = me.getKey(); Long E = me.getValue(); long e = E.longValue(); D g = f.power(e); if (t == null) { t = g; } else { t = t.multiply(g); } } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { System.out.println("\nfactorization(map): " + f); System.out.println("F = " + F); System.out.println("P = " + P); System.out.println("t = " + t); //RuntimeException e = new RuntimeException("fac-map"); //e.printStackTrace(); //throw e; } return f; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorInteger.java000066400000000000000000002063361445075545500240460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.SortedMap; import java.util.Set; import java.util.HashSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.arith.PrimeInteger; import edu.jas.arith.PrimeList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.OptimizedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.TermOrderOptimization; import edu.jas.structure.GcdRingElem; import edu.jas.structure.Power; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.util.KsubSet; /** * Integer coefficients factorization algorithms. This class implements * factorization methods for polynomials over integers. * @param * @author Heinz Kredel */ public class FactorInteger & Modular> extends FactorAbstract { private static final Logger logger = LogManager.getLogger(FactorInteger.class); private static final boolean debug = logger.isDebugEnabled(); /** * Factorization engine for modular base coefficients. */ protected final FactorAbstract mfactor; /** * Gcd engine for modular base coefficients. */ protected final GreatestCommonDivisorAbstract mengine; /** * No argument constructor. */ public FactorInteger() { this(BigInteger.ONE); } /** * Constructor. * @param cfac coefficient ring factory. */ @SuppressWarnings("unchecked") public FactorInteger(RingFactory cfac) { super(cfac); ModularRingFactory mcofac = (ModularRingFactory) (Object) new ModLongRing(13, true); // hack mfactor = FactorFactory.getImplementation(mcofac); //new FactorModular(mcofac); mengine = GCDFactory.getImplementation(mcofac); //mengine = GCDFactory.getProxy(mcofac); } /** * GenPolynomial test if is irreducible. * @param P GenPolynomial. * @return true if P is irreducible, else false. */ @Override public boolean isIrreducible(GenPolynomial P) { if (P.ring.nvar == 1) { if (isIrreducibleEisenstein(P)) { return true; } // else unknown } return super.isIrreducible(P); } /** * GenPolynomial test if is irreducible with Eisenstein criterion. * @param P univariate polynomial. * @return true if P is irreducible, else false if it is unknown. */ public boolean isIrreducibleEisenstein(GenPolynomial P) { if (P.ring.nvar != 1) { throw new IllegalArgumentException("only for univariate polynomials"); } if (P.degree(0) <= 1L) { // linear or constant is irreducible return true; } GenPolynomial Pred = P.reductum(); BigInteger rcont = engine.baseContent(Pred); if (rcont.isZERO() || rcont.isONE()) { // case x**n + Pred return false; } if (rcont.compareTo(BigInteger.valueOf(PrimeInteger.BETA)) >= 0) { // integer too big return false; } long lcont = rcont.getVal().longValue(); BigInteger lc = P.leadingBaseCoefficient().abs(); BigInteger tc = P.trailingBaseCoefficient().abs(); SortedMap fac = PrimeInteger.factors(lcont); // test divisiblity for (Long p : fac.keySet()) { BigInteger pi = BigInteger.valueOf(p); if (!lc.remainder(pi).isZERO() && !tc.remainder(pi.power(2)).isZERO()) { logger.info("isIrreducibleEisenstein: fac = {}, lc = {}, tc = {}", fac, lc, tc); return true; } } return false; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree and primitive! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @SuppressWarnings("unchecked") @Override public List> baseFactorsSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } if (!engine.baseContent(P).isONE()) { throw new IllegalArgumentException(this.getClass().getName() + " P not primitive"); } if (P.degree(0) <= 1L) { // linear is irreducible factors.add(P); return normalizeFactorization(factors); } if (isIrreducibleEisenstein(P)) { factors.add(P); return normalizeFactorization(factors); } // check cyclotomic factorization //if (CycloUtil.isCyclotomicPolynomial(P)) { //System.out.println("isCyclotomicPolynomial = " + P); factors = CycloUtil.cyclotomicFactors(P); if (factors.size() > 0) { logger.info("cyclotomicFactors: #factors = {}", factors.size()); return normalizeFactorization(factors); } //} // compute norm BigInteger an = P.maxNorm(); BigInteger ac = P.leadingBaseCoefficient(); //compute factor coefficient bounds ExpVector degv = P.degreeVector(); int degi = (int) P.degree(0); BigInteger M = an.multiply(PolyUtil.factorBound(degv)); M = M.multiply(ac.abs().multiply(ac.fromInteger(8))); //System.out.println("M = " + M); //M = M.multiply(M); // test //initialize prime list and degree vector PrimeList primes = new PrimeList(PrimeList.Range.small); int pn = 30; //primes.size(); ModularRingFactory cofac = null; GenPolynomial am = null; GenPolynomialRing mfac = null; int TT = 5; // 7 if (degi > 100) { TT += 2; } List>[] modfac = new List[TT]; List>[] intfac = new List[TT]; BigInteger[] plist = new BigInteger[TT]; List> mlist = null; List> ilist = null; int i = 0; if (debug) { logger.debug("an = {}", an); logger.debug("ac = {}", ac); logger.debug("M = {}", M); logger.info("degv = {}", degv); } Iterator pit = primes.iterator(); pit.next(); // skip p = 2 pit.next(); // skip p = 3 MOD nf = null; for (int k = 0; k < TT; k++) { if (k == TT - 1) { // -2 primes = new PrimeList(PrimeList.Range.medium); pit = primes.iterator(); } //if (k == TT + 1) { // -1 // primes = new PrimeList(PrimeList.Range.large); // pit = primes.iterator(); //} while (pit.hasNext()) { java.math.BigInteger p = pit.next(); //System.out.println("next run ++++++++++++++++++++++++++++++++++"); if (++i >= pn) { logger.error("prime list exhausted, pn = {}", pn); throw new ArithmeticException("prime list exhausted"); } if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cofac = (ModularRingFactory) new ModLongRing(p, true); } else { cofac = (ModularRingFactory) new ModIntegerRing(p, true); } logger.info("prime = {}", cofac); nf = cofac.fromInteger(ac.getVal()); if (nf.isZERO()) { logger.info("unlucky prime (nf) = {}", p); continue; } // initialize polynomial factory and map polynomial mfac = new GenPolynomialRing(cofac, pfac); am = PolyUtil. fromIntegerCoefficients(mfac, P); if (!am.degreeVector().equals(degv)) { // always true logger.info("unlucky prime (deg) = {}", p); continue; } GenPolynomial ap = PolyUtil. baseDerivative(am); if (ap.isZERO()) { logger.info("unlucky prime (a')= {}", p); continue; } GenPolynomial g = mengine.baseGcd(am, ap); if (g.isONE()) { logger.info("**lucky prime = {}", p); break; } } // now am is squarefree mod p, make monic and factor mod p if (!nf.isONE()) { //System.out.println("nf = " + nf); am = am.divide(nf); // make monic } mlist = mfactor.baseFactorsSquarefree(am); logger.info("modlist = {}", mlist); if (mlist.size() <= 1) { factors.add(P); return factors; } if (!nf.isONE()) { GenPolynomial mp = mfac.getONE(); //mlist.get(0); //System.out.println("mp = " + mp); mp = mp.multiply(nf); //System.out.println("mp = " + mp); mlist.add(0, mp); // set(0,mp); } modfac[k] = mlist; plist[k] = cofac.getIntegerModul(); // p } // search shortest factor list int min = Integer.MAX_VALUE; BitSet AD = null; for (int k = 0; k < TT; k++) { List ev = PolyUtil. leadingExpVector(modfac[k]); BitSet D = factorDegrees(ev, degi); if (AD == null) { AD = D; } else { AD.and(D); } int s = modfac[k].size(); logger.info("mod({}) #s = {}, D = {}", plist[k], s, D); if (s < min) { min = s; mlist = modfac[k]; } } logger.info("min = {}, AD = {}", min, AD); if (mlist.size() <= 1) { logger.info("mlist.size() = 1"); factors.add(P); return factors; } if (AD.cardinality() <= 2) { // only one possible factor logger.info("degree set cardinality = {}", AD.cardinality()); factors.add(P); return factors; } final boolean allLists = false; //true; //false; if (allLists) { // try each factor list for (int k = 0; k < TT; k++) { mlist = modfac[k]; if (debug) { logger.info("lifting from {}", mlist); } if (P.leadingBaseCoefficient().isONE()) { // monic case factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases if (factors.size() == 1) { factors = searchFactorsNonMonic(P, M, mlist, AD); } } else { factors = searchFactorsNonMonic(P, M, mlist, AD); } intfac[k] = factors; } } else { // try only shortest factor list if (debug) { logger.info("lifting shortest from {}", mlist); } if (P.leadingBaseCoefficient().isONE()) { long t = System.currentTimeMillis(); try { mlist = PolyUtil. monic(mlist); factors = searchFactorsMonic(P, M, mlist, AD); // does now work in all cases t = System.currentTimeMillis() - t; //System.out.println("monic time = " + t); intfac[0] = factors; if (debug) { t = System.currentTimeMillis(); List> fnm = searchFactorsNonMonic(P, M, mlist, AD); t = System.currentTimeMillis() - t; System.out.println("non monic time = " + t); if (!factors.equals(fnm)) { System.out.println("monic factors = " + intfac[0]); //factors); System.out.println("non monic factors = " + fnm); } } } catch (RuntimeException e) { t = System.currentTimeMillis(); factors = searchFactorsNonMonic(P, M, mlist, AD); t = System.currentTimeMillis() - t; //System.out.println("only non monic time = " + t); } } else { long t = System.currentTimeMillis(); factors = searchFactorsNonMonic(P, M, mlist, AD); t = System.currentTimeMillis() - t; //System.out.println("non monic time = " + t); } return normalizeFactorization(factors); } // search longest factor list int max = 0; for (int k = 0; k < TT; k++) { int s = intfac[k].size(); logger.info("int s = {}", s); if (s > max) { max = s; ilist = intfac[k]; } } factors = normalizeFactorization(ilist); return factors; } /** * BitSet for factor degree list. * @param E exponent vector list. * @return {b_0,...,b_k} a BitSet of possible factor degrees. */ public BitSet factorDegrees(List E, int deg) { BitSet D = new BitSet(deg + 1); D.set(0); // constant factor for (ExpVector e : E) { int i = (int) e.getVal(0); BitSet s = new BitSet(deg + 1); for (int k = 0; k < deg + 1 - i; k++) { // shift by i places s.set(i + k, D.get(k)); } //System.out.println("s = " + s); D.or(s); //System.out.println("D = " + D); } return D; } /** * Sum of all degrees. * @param L univariate polynomial list. * @return sum deg(p) for p in L. */ public static > long degreeSum(List> L) { long s = 0L; for (GenPolynomial p : L) { ExpVector e = p.leadingExpVector(); long d = e.getVal(0); s += d; } return s; } /** * Factor search with modular Hensel lifting algorithm. Let p = * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1} * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j * @param C GenPolynomial. * @param M bound on the coefficients of g_i as factors of C. * @param F = [f_0,...,f_{n-1}] List<GenPolynomial>. * @param D bit set of possible factor degrees. * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod * p**e. Note: does not work in all cases. */ List> searchFactorsMonic(GenPolynomial C, BigInteger M, List> F, BitSet D) { //System.out.println("*** monic factor combination ***"); if (C == null || C.isZERO() || F == null || F.size() == 0) { throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); } GenPolynomialRing pfac = C.ring; if (pfac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } List> factors = new ArrayList>(F.size()); List> mlist = F; List> lift; //MOD nf = null; GenPolynomial ct = mlist.get(0); if (ct.isConstant()) { //nf = ct.leadingBaseCoefficient(); mlist.remove(ct); //System.out.println("=== nf = " + nf); if (mlist.size() <= 1) { factors.add(C); return factors; } } else { //nf = ct.ring.coFac.getONE(); } //System.out.println("modlist = " + mlist); // includes not ldcf ModularRingFactory mcfac = (ModularRingFactory) ct.ring.coFac; BigInteger m = mcfac.getIntegerModul(); long k = 1; BigInteger pi = m; while (pi.compareTo(M) < 0) { k++; pi = pi.multiply(m); } logger.info("p^k = {}^{}", m, k); GenPolynomial PP = C, P = C; // lift via Hensel try { lift = HenselUtil. liftHenselMonic(PP, mlist, k); //System.out.println("lift = " + lift); } catch (NoLiftingException e) { throw new RuntimeException(e); } logger.info("lifted modlist = {}", lift); GenPolynomialRing mpfac = lift.get(0).ring; // combine trial factors int dl = (lift.size() + 1) / 2; //System.out.println("dl = " + dl); GenPolynomial u = PP; long deg = (u.degree(0) + 1L) / 2L; //System.out.println("deg = " + deg); //BigInteger ldcf = u.leadingBaseCoefficient(); //System.out.println("ldcf = " + ldcf); for (int j = 1; j <= dl; j++) { //System.out.println("j = " + j + ", dl = " + dl + ", lift = " + lift); KsubSet> ps = new KsubSet>(lift, j); for (List> flist : ps) { //System.out.println("degreeSum = " + degreeSum(flist)); if (!D.get((int) FactorInteger. degreeSum(flist))) { logger.info("skipped by degree set {}, deg = {}", D, degreeSum(flist)); continue; } GenPolynomial mtrial = Power.> multiply(mpfac, flist); //GenPolynomial mtrial = mpfac.getONE(); //for (int kk = 0; kk < flist.size(); kk++) { // GenPolynomial fk = flist.get(kk); // mtrial = mtrial.multiply(fk); //} //System.out.println("+flist = " + flist + ", mtrial = " + mtrial); if (mtrial.degree(0) > deg) { // this test is sometimes wrong logger.info("degree {} > deg {}", mtrial.degree(0), deg); //continue; } //System.out.println("+flist = " + flist); GenPolynomial trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial); //System.out.println("+trial = " + trial); //trial = engine.basePrimitivePart( trial.multiply(ldcf) ); trial = engine.basePrimitivePart(trial); //System.out.println("pp(trial)= " + trial); if (PolyUtil. baseSparsePseudoRemainder(u, trial).isZERO()) { logger.info("successful trial = {}", trial); //System.out.println("trial = " + trial); //System.out.println("flist = " + flist); //trial = engine.basePrimitivePart(trial); //System.out.println("pp(trial)= " + trial); factors.add(trial); u = PolyUtil. basePseudoDivide(u, trial); //u.divide( trial ); //System.out.println("u = " + u); //if (lift.removeAll(flist)) { lift = removeOnce(lift, flist); logger.info("new lift= {}", lift); dl = (lift.size() + 1) / 2; //System.out.println("dl = " + dl); j = 0; // since j++ break; //} logger.error("error removing flist from lift = {}", lift); } } } if (!u.isONE() && !u.equals(P)) { logger.info("rest u = {}", u); //System.out.println("rest u = " + u); factors.add(u); } if (factors.size() == 0) { logger.info("irred u = {}", u); //System.out.println("irred u = " + u); factors.add(PP); } return normalizeFactorization(factors); } /** * Factor search with modular Hensel lifting algorithm. Let p = * f_i.ring.coFac.modul() i = 0, ..., n-1 and assume C == prod_{0,...,n-1} * f_i mod p with ggt(f_i,f_j) == 1 mod p for i != j * @param C GenPolynomial. * @param M bound on the coefficients of g_i as factors of C. * @param F = [f_0,...,f_{n-1}] List<GenPolynomial>. * @param D bit set of possible factor degrees. * @return [g_0,...,g_{n-1}] = lift(C,F), with C = prod_{0,...,n-1} g_i mod * p**e. */ List> searchFactorsNonMonic(GenPolynomial C, BigInteger M, List> F, BitSet D) { //System.out.println("*** non monic factor combination ***"); if (C == null || C.isZERO() || F == null || F.size() == 0) { throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); } GenPolynomialRing pfac = C.ring; if (pfac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } List> factors = new ArrayList>(F.size()); List> mlist = F; MOD nf = null; GenPolynomial ct = mlist.get(0); if (ct.isConstant()) { nf = ct.leadingBaseCoefficient(); mlist.remove(ct); //System.out.println("=== nf = " + nf); //System.out.println("=== ldcf = " + C.leadingBaseCoefficient()); if (mlist.size() <= 1) { factors.add(C); return factors; } } else { nf = ct.ring.coFac.getONE(); } //System.out.println("modlist = " + mlist); // includes not ldcf GenPolynomialRing mfac = ct.ring; GenPolynomial Pm = PolyUtil. fromIntegerCoefficients(mfac, C); GenPolynomial PP = C, P = C; // combine trial factors int dl = (mlist.size() + 1) / 2; GenPolynomial u = PP; long deg = (u.degree(0) + 1L) / 2L; GenPolynomial um = Pm; //BigInteger ldcf = u.leadingBaseCoefficient(); //System.out.println("ldcf = " + ldcf); HenselApprox ilist = null; for (int j = 1; j <= dl; j++) { //System.out.println("j = " + j + ", dl = " + dl + ", ilist = " + ilist); KsubSet> ps = new KsubSet>(mlist, j); for (List> flist : ps) { //System.out.println("degreeSum = " + degreeSum(flist)); if (!D.get((int) FactorInteger. degreeSum(flist))) { logger.info("skipped by degree set {}, deg = {}", D, degreeSum(flist)); continue; } GenPolynomial trial = mfac.getONE().multiply(nf); for (int kk = 0; kk < flist.size(); kk++) { GenPolynomial fk = flist.get(kk); trial = trial.multiply(fk); } if (trial.degree(0) > deg) { // this test is sometimes wrong logger.info("degree > deg {}, degree = {}", deg, trial.degree(0)); //continue; } GenPolynomial cofactor = um.divide(trial); //System.out.println("trial = " + trial); //System.out.println("cofactor = " + cofactor); // lift via Hensel try { // ilist = HenselUtil.liftHenselQuadraticFac(PP, M, trial, cofactor); ilist = HenselUtil. liftHenselQuadratic(PP, M, trial, cofactor); //ilist = HenselUtil. liftHensel(PP, M, trial, cofactor); } catch (NoLiftingException e) { // no liftable factors if ( /*debug*/logger.isDebugEnabled()) { logger.info("no liftable factors {}", e); //e.printStackTrace(); } continue; } GenPolynomial itrial = ilist.A; GenPolynomial icofactor = ilist.B; if (logger.isDebugEnabled()) { logger.info(" modlist = {}, cofactor {}", trial, cofactor); logger.info("lifted intlist = {}, cofactor {}", itrial, icofactor); } //System.out.println("lifted intlist = " + itrial + ", cofactor " + icofactor); itrial = engine.basePrimitivePart(itrial); //System.out.println("pp(trial)= " + itrial); if (PolyUtil. baseSparsePseudoRemainder(u, itrial).isZERO()) { logger.info("successful trial = {}", itrial); //System.out.println("trial = " + itrial); //System.out.println("cofactor = " + icofactor); //System.out.println("flist = " + flist); //itrial = engine.basePrimitivePart(itrial); //System.out.println("pp(itrial)= " + itrial); factors.add(itrial); //u = PolyUtil. basePseudoDivide(u, itrial); //u.divide( trial ); u = icofactor; PP = u; // fixed finally on 2009-05-03 um = cofactor; //System.out.println("u = " + u); //System.out.println("um = " + um); //if (mlist.removeAll(flist)) { mlist = removeOnce(mlist, flist); logger.info("new mlist= {}", mlist); dl = (mlist.size() + 1) / 2; j = 0; // since j++ break; //} logger.error("error removing flist from ilist = {}", mlist); } } } if (!u.isONE() && !u.equals(P)) { logger.info("rest u = {}", u); factors.add(u); } if (factors.size() == 0) { logger.info("irred u = {}", PP); factors.add(PP); } return normalizeFactorization(factors); } /** * GenPolynomial factorization of a multivariate squarefree polynomial, * using Hensel lifting if possible. * @param P squarefree and primitive! (respectively monic) multivariate * GenPolynomial over the integers. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @Override public List> factorsSquarefree(GenPolynomial P) { GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseFactorsSquarefree(P); } List> factors; factors = factorsSquarefreeOptions(P, false, false); if (factors != null) { return factors; } factors = factorsSquarefreeOptions(P, false, true); if (factors != null) { return factors; } factors = factorsSquarefreeOptions(P, true, false); if (factors != null) { return factors; } factors = factorsSquarefreeOptions(P, true, true); if (factors != null) { return factors; } logger.warn("factorsSquarefreeHensel not applicable or failed, reverting to Kronecker for: {}", P); factors = super.factorsSquarefree(P); return factors; } /** * GenPolynomial factorization of a multivariate squarefree polynomial, * using Hensel lifting if possible. * @param P squarefree and primitive! (respectively monic) multivariate * GenPolynomial over the integers. * @param opti true, if polynomial variables should be optimized, else false. * @param tlex true, if INVLEX term order should be forced, else false. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> factorsSquarefreeOptions(GenPolynomial P, boolean opti, boolean tlex) { GenPolynomial Pp = P; GenPolynomialRing pfac = Pp.ring; if (pfac.nvar <= 1) { return baseFactorsSquarefree(Pp); } if (tlex) { if (! pfac.tord.equals(TermOrderByName.INVLEX)) { pfac = new GenPolynomialRing(pfac,TermOrderByName.INVLEX); Pp = pfac.copy(Pp); logger.warn("invlexed polynomial: {}, from ring {}", Pp, P.ring); } else { tlex = false; } } OptimizedPolynomialList opt = null; List iperm = null; final boolean USE_OPT = opti; if (USE_OPT) { List> topt = new ArrayList>(1); topt.add(Pp); opt = TermOrderOptimization. optimizeTermOrder(pfac, topt); if (!TermOrderOptimization.isIdentityPermutation(opt.perm)) { iperm = TermOrderOptimization.inversePermutation(opt.perm); Pp = opt.list.get(0); logger.info("optimized polynomial: {}", Pp); logger.warn("optimized ring: {}, original ring: {}", opt.ring, pfac); } } ExpVector degv = Pp.degreeVector(); int[] donv = degv.dependencyOnVariables(); List> facs = null; if (degv.length() == donv.length) { // all variables appear, hack for Hensel, check try { logger.info("try factorsSquarefreeHensel: {}", Pp); facs = factorsSquarefreeHensel(Pp); } catch (Exception e) { logger.info("exception {}", e); //e.printStackTrace(); } } else { // not all variables appear, remove unused variables, hack for Hensel, check GenPolynomial pu = PolyUtil. removeUnusedUpperVariables(Pp); //GenPolynomial pl = PolyUtil. removeUnusedLowerVariables(pu); // not useful try { logger.info("try factorsSquarefreeHensel: {}", pu); facs = factorsSquarefreeHensel(pu); List> fs = new ArrayList>(facs.size()); GenPolynomialRing pf = Pp.ring; //GenPolynomialRing pfu = pu.ring; for (GenPolynomial p : facs) { //GenPolynomial pel = p.extendLower(pfu, 0, 0L); GenPolynomial pe = p.extend(pf, 0, 0L); fs.add(pe); } //System.out.println("fs = " + fs); facs = fs; } catch (Exception e) { logger.info("exception {}", e); //e.printStackTrace(); } } if (facs == null) { return facs; } if (USE_OPT && iperm != null) { facs = TermOrderOptimization. permutation(iperm, pfac, facs); logger.warn("de-optimized polynomials: {}", facs); } if (tlex) { facs = P.ring.copy(facs); logger.warn("de-invlexed polynomials: {}", facs); } facs = normalizeFactorization(facs); return facs; } /** * GenPolynomial factorization of a multivariate squarefree polynomial, * using Hensel lifting. * @param P squarefree and primitive! (respectively monic) multivariate * GenPolynomial over the integers. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @SuppressWarnings("unchecked") public List> factorsSquarefreeHensel(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 1) { return baseFactorsSquarefree(P); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.degreeVector().totalDeg() <= 1L) { factors.add(P); return factors; } GenPolynomial pd = P; //System.out.println("pd = " + pd); // ldcf(pd) BigInteger ac = pd.leadingBaseCoefficient(); // factor leading coefficient as polynomial in the lowest! variable GenPolynomialRing> rnfac = pfac.recursive(pfac.nvar - 1); GenPolynomial> pr = PolyUtil. recursive(rnfac, pd); GenPolynomial> prr = PolyUtil. switchVariables(pr); GenPolynomial prrc = engine.recursiveContent(prr); // can have content wrt this variable List> cfactors = null; if (!prrc.isONE()) { prr = PolyUtil. recursiveDivide(prr, prrc); GenPolynomial prrcu = prrc.extendLower(pfac, 0, 0L); // since switched vars pd = PolyUtil. basePseudoDivide(pd, prrcu); logger.info("recursive content = {}, new P = {}", prrc, pd); cfactors = factorsSquarefree(prrc); List> cff = new ArrayList>(cfactors.size()); for (GenPolynomial fs : cfactors) { GenPolynomial fsp = fs.extendLower(pfac, 0, 0L); // since switched vars cff.add(fsp); } cfactors = cff; logger.info("cfactors = {}", cfactors); } GenPolynomial lprr = prr.leadingBaseCoefficient(); //System.out.println("prr = " + prr); logger.info("leading coefficient = {}", lprr); boolean isMonic = false; // multivariate monic if (lprr.isConstant()) { // isONE ? isMonic = true; } SortedMap, Long> lfactors = factors(lprr); //System.out.println("lfactors = " + lfactors); List> lfacs = new ArrayList>(lfactors.keySet()); logger.info("leading coefficient factors = {}", lfacs); // search evaluation point and evaluate GenPolynomialRing cpfac = pfac; GenPolynomial pe = pd; GenPolynomial pep; GenPolynomialRing ccpfac = lprr.ring; List> ce = lfacs; List> cep = null; List cei = null; List dei = new ArrayList(); BigInteger pec = null; BigInteger pecw = null; BigInteger ped = null; List> ufactors = null; List tParts = new ArrayList(); List> lf = null; GenPolynomial lpx = null; List> ln = null; List> un = null; GenPolynomial pes = null; List V = null; long evStart = 0L; //3L * 5L; List Evs = new ArrayList(pfac.nvar + 1); // Evs(0), Evs(1) unused for (int j = 0; j <= pfac.nvar; j++) { //Evs.add(evStart++); // bug Evs.add(evStart); if (evStart > 0) { evStart = - evStart; } else { evStart = 1L - evStart; } } //no: Collections.reverse(Evs); evStart = Evs.get(0); final int trials = 4; int countSeparate = 0; final int COUNT_MAX = 50; double ran = 1.001; // higher values not good boolean isPrimitive = true; boolean notLucky = true; while (notLucky) { // for Wang's test if (Math.abs(evStart) > 371L) { logger.warn("found points : V = {}, dei = {}", V, dei); //if (tParts != null && tParts.size() > 0) { // at least one successful eval point // logger.warn("some evaluation points found after {} iterations, tParts = {}", Math.abs(evStart), tParts); // break; //} logger.warn("no evaluation point for: P = {}, prr = {}, lprr = {}, lfacs = {}", P, prr, lprr, lfacs); throw new RuntimeException( "no evaluation point found after " + Math.abs(evStart) + " iterations"); } if (Math.abs(evStart) % 100L <= 3L) { ran = ran * (Math.PI - 2.14); } //System.out.println("-------------------------------------------- Evs = " + Evs); notLucky = false; V = new ArrayList(); cpfac = pfac; pe = pd; ccpfac = lprr.ring; ce = lfacs; cep = null; cei = null; pec = null; ped = null; long vi = 0L; for (int j = pfac.nvar; j > 1; j--) { // evaluation up to univariate case long degp = pe.degree(cpfac.nvar - 2); cpfac = cpfac.contract(1); ccpfac = ccpfac.contract(1); //vi = evStart; // + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p vi = Evs.get(j); //evStart + j;//0L; //(long)(pfac.nvar-j); // 1L; 0 not so good for small p BigInteger Vi; // search evaluation point boolean doIt = true; Vi = null; pep = null; while (doIt) { logger.info("vi({}) = {}", j, vi); Vi = new BigInteger(vi); pep = PolyUtil. evaluateMain(cpfac, pe, Vi); //System.out.println("pep = " + pep); //System.out.println("degp = " + degp + ", dege = " + pep.degree(cpfac.nvar - 1)); // check lucky evaluation point if (degp == pep.degree(cpfac.nvar - 1)) { logger.info("pep = {}", pep); //System.out.println("deg(pe) = " + degp + ", deg(pep) = " + pep.degree(cpfac.nvar-1)); // check squarefree if (sengine.isSquarefree(pep)) { // cpfac.nvar == 1 && ?? no, must test on each variable //if ( isNearlySquarefree(pep) ) { //System.out.println("squarefeee(pep)"); // + pep); doIt = false; //break; } else { logger.info("pep not squarefree "); } } if (vi > 0L) { vi = -vi; } else { vi = 1L - vi; } } //if ( !isMonic ) { if (ccpfac.nvar >= 1) { cep = PolyUtil. evaluateMain(ccpfac, ce, Vi); } else { cei = PolyUtil. evaluateMain(ccpfac.coFac, ce, Vi); } //} int jj = (int) Math.round(ran + 0.52 * Math.random()); // j, random increment //jj = 0; // ...4 test //System.out.print("minimal jj = " + jj + ", vi_a " + vi); if (vi > 0L) { Evs.set(j, vi + jj); // record last tested value plus increment evStart = vi + jj; } else { Evs.set(j, vi - jj); // record last tested value minus increment evStart = vi - jj; } // ensure different evaluation points Set Evset = new HashSet(Evs); while (Evset.size() != Evs.size()) { //logger.warn("same eval points: {} != {}", Evs, Evset); long vgi = Evs.get(j); if (vgi > 0L) { vgi += 1L; } else { vgi -= 1L; } Evs.set(j, vgi); Evset.clear(); Evset.addAll(Evs); //= new HashSet(Evs); evStart = vgi; //logger.warn("same eval points: {}, j = {}", Evs, j); } //System.out.println(", j = " + j + ", vi_b " + Vi); //evStart = vi+1L; V.add(Vi); pe = pep; ce = cep; } //System.out.println("ce = " + ce + ", pe = " + pe + ", V = " + V); pecw = engine.baseContent(pe); // original Wang isPrimitive = pecw.isONE(); ped = ccpfac.coFac.getONE(); pec = pe.ring.coFac.getONE(); //System.out.println("cei = " + cei + ", pecw = " + pecw); if (!isMonic) { if (countSeparate > COUNT_MAX) { pec = pe.ring.coFac.getONE(); // hack is sometimes better } else { pec = pecw; } //pec = pecw; //System.out.println("cei = " + cei + ", pec = " + pec + ", pe = " + pe); if (lfacs.get(0).isConstant()) { ped = cei.remove(0); //lfacs.remove(0); // later } //System.out.println("lfacs = " + lfacs + ", cei = " + cei + ", ped = " + ped + ", pecw = " + pecw); // test Wang's condition dei = new ArrayList(); dei.add(pec.multiply(ped).abs()); // .abs() int i = 1; for (BigInteger ci : cei) { if (ci.isZERO()) { logger.info("condition (0) not met for cei = {}", cei); // + ", dei = {}", dei); notLucky = true; break; } BigInteger q = ci.abs(); //System.out.println("q = " + q); for (int ii = i - 1; ii >= 0; ii--) { BigInteger r = dei.get(ii); //System.out.println("r = " + r); while (!r.isONE()) { r = r.gcd(q); q = q.divide(r); //System.out.println("r = " + r + ", q = " + q); } } dei.add(q); if (q.isONE()) { logger.info("condition (1) not met for dei = {}, cei = {}", dei, cei); if (!testSeparate(cei, pecw)) { countSeparate++; if (countSeparate > COUNT_MAX) { logger.info("too many inseparable evaluation points: {}, removing {}", countSeparate, pecw); } } notLucky = true; break; } i++; } //System.out.println("dei = " + dei); } if (notLucky) { continue; } logger.info("evaluation points = {}, dei = {}", V, dei); //System.out.println("Evs = " + Evs); logger.info("univariate polynomial = {}, pecw = {}", pe, pecw); //pe = pe.abs(); //ufactors = baseFactorsRadical(pe); //baseFactorsSquarefree(pe); wrong since not primitive ufactors = baseFactorsSquarefree(pe.divide(pecw)); //wrong if not primitive if (!pecw.isONE()) { ufactors.add(0, cpfac.getONE().multiply(pecw)); } if (ufactors.size() <= 1) { logger.info("irreducible univariate polynomial"); factors.add(pd); // P if (cfactors != null) { cfactors.addAll(factors); factors = cfactors; } return factors; } logger.info("univariate factors = {}", ufactors); // + ", of {}", pe); //System.out.println("lfacs = " + lfacs); //System.out.println("cei = " + cei); //System.out.println("pecw = " + pecw); // determine leading coefficient polynomials for factors lf = new ArrayList>(); lpx = lprr.ring.getONE(); for (int i = 0; i < ufactors.size(); i++) { lf.add(lprr.ring.getONE()); } //System.out.println("lf = " + lf); if (!isMonic || !pecw.isONE()) { if (lfacs.size() > 0 && lfacs.get(0).isConstant()) { //GenPolynomial unused = lfacs.remove(0); //BigInteger xxi = xx.leadingBaseCoefficient(); //System.out.println("xx = " + xx + " == ped = " +ped); } for (int i = ufactors.size() - 1; i >= 0; i--) { GenPolynomial pp = ufactors.get(i); BigInteger ppl = pp.leadingBaseCoefficient(); //System.out.println("ppl = " + ppl + ", pp = " + pp); ppl = ppl.multiply(pec); // content GenPolynomial lfp = lf.get(i); int ii = 0; for (BigInteger ci : cei) { //System.out.println("ci = " + ci + ", lfp = " + lfp + ", lfacs.get(ii) = " + lfacs.get(ii)); if (ci.abs().isONE()) { System.out.println("ppl = " + ppl + ", ci = " + ci + ", lfp = " + lfp + ", lfacs.get(ii) = " + lfacs.get(ii)); notLucky = true; throw new RuntimeException("something is wrong, ci is a unit"); } while (ppl.remainder(ci).isZERO() && lfacs.size() > ii) { ppl = ppl.divide(ci); lfp = lfp.multiply(lfacs.get(ii)); } ii++; } //System.out.println("ppl = " + ppl + ", lfp = " + lfp); lfp = lfp.multiply(ppl); lf.set(i, lfp); } // adjust if pec != 1 pec = pecw; lpx = Power.> multiply(lprr.ring, lf); // test only, not used //System.out.println("lpx = " + lpx); if (!lprr.degreeVector().equals(lpx.degreeVector())) { logger.info("deg(lprr) != deg(lpx): lprr = {}, lpx = {}", lprr, lpx); notLucky = true; continue; } if (!pec.isONE()) { // content, was always false by hack // evaluate factors of ldcf List> lfe = lf; List lfei = null; ccpfac = lprr.ring; for (int j = lprr.ring.nvar; j > 0; j--) { ccpfac = ccpfac.contract(1); BigInteger Vi = V.get(lprr.ring.nvar - j); if (ccpfac.nvar >= 1) { lfe = PolyUtil. evaluateMain(ccpfac, lfe, Vi); } else { lfei = PolyUtil. evaluateMain(ccpfac.coFac, lfe, Vi); } } //System.out.println("lfe = " + lfe + ", lfei = " + lfei + ", V = " + V); ln = new ArrayList>(lf.size()); un = new ArrayList>(lf.size()); for (int jj = 0; jj < lf.size(); jj++) { GenPolynomial up = ufactors.get(jj); BigInteger ui = up.leadingBaseCoefficient(); BigInteger li = lfei.get(jj); BigInteger di = ui.gcd(li).abs(); BigInteger udi = ui.divide(di); BigInteger ldi = li.divide(di); GenPolynomial lp = lf.get(jj); GenPolynomial lpd = lp.multiply(udi); GenPolynomial upd = up.multiply(ldi); if (pec.isONE()) { ln.add(lp); un.add(up); } else { ln.add(lpd); un.add(upd); BigInteger pec1 = pec.divide(ldi); //System.out.println("pec = " + pec + ", pec1 = " + pec1); pec = pec1; } } if (!lf.equals(ln) || !un.equals(ufactors)) { logger.debug("!lf.equals(ln) || !un.equals(ufactors)"); //System.out.println("pe = " + pe); //System.out.println("#ln = " + ln + ", #lf = " + lf); //System.out.println("#un = " + un + ", #ufactors = " + ufactors); //lf = ln; //ufactors = un; // adjust pe } if (!pec.isONE()) { // still not 1 ln = new ArrayList>(lf.size()); un = new ArrayList>(lf.size()); pes = pe; for (int jj = 0; jj < lf.size(); jj++) { GenPolynomial up = ufactors.get(jj); GenPolynomial lp = lf.get(jj); //System.out.println("up = " + up + ", lp = " + lp); if (!up.isConstant()) { up = up.multiply(pec); } lp = lp.multiply(pec); if (jj != 0) { pes = pes.multiply(pec); } un.add(up); ln.add(lp); } if (pes.equals(Power.> multiply(pe.ring, un))) { //System.out.println("*pe = " + pes + ", pec = " + pec); //System.out.println("*ln = " + ln + ", *lf = " + lf); //System.out.println("*un = " + un + ", *ufactors = " + ufactors); //System.out.println("*pe == prod(un) "); isPrimitive = false; //pe = pes; //lf = ln; //ufactors = un; } else { //System.out.println("*pe != prod(un): " + Power.> multiply(pe.ring,un)); } } } //if (notLucky) { // continue; //} logger.info("distributed factors of leading coefficient = {}", lf); lpx = Power.> multiply(lprr.ring, lf); if (!lprr.abs().equals(lpx.abs())) { // not correctly distributed if (!lprr.degreeVector().equals(lpx.degreeVector())) { logger.info("lprr != lpx: lprr = {}, lpx = {}", lprr, lpx); notLucky = true; } } //logger.warn("V = {}, pe = {}, cei = {}, lf = {}, ln = {}", V, pe, cei, lf, ln); } // end determine leading coefficients for factors if (!notLucky) { TrialParts tp = null; if (isPrimitive) { tp = new TrialParts(V, pe, ufactors, cei, lf); } else { tp = new TrialParts(V, pes, un, cei, ln); } //System.out.println("trialParts = " + tp); if (tp.univPoly != null) { if (tp.ldcfEval.size() != 0) { tParts.add(tp); } } if (tParts.size() < trials) { notLucky = true; } } } // end notLucky loop logger.warn("end notLucky loop, trial parts = {}", tParts.size()); // search TrialParts with shortest factorization of univariate polynomial int min = Integer.MAX_VALUE; TrialParts tpmin = null; for (TrialParts tp : tParts) { //logger.info("tp.univFactors.size() = {}", tp.univFactors.size()); if (tp.univFactors.size() < min) { min = tp.univFactors.size(); tpmin = tp; } } for (TrialParts tp : tParts) { if (tp.univFactors.size() == min) { if (!tp.univFactors.get(0).isConstant()) { logger.info("tp.univFactors = {}", tp.univFactors); tpmin = tp; break; } } } // set to (first) shortest V = tpmin.evalPoints; pe = tpmin.univPoly; ufactors = tpmin.univFactors; cei = tpmin.ldcfEval; // unused lf = tpmin.ldcfFactors; logger.info("iterations = {}", Math.abs(evStart)); logger.info("minimal trial = {}", tpmin); GenPolynomialRing ufac = pe.ring; //initialize prime list PrimeList primes = new PrimeList(PrimeList.Range.medium); // PrimeList.Range.medium); Iterator primeIter = primes.iterator(); int pn = 50; //primes.size(); BigInteger ae = pe.leadingBaseCoefficient(); GenPolynomial Pm = null; ModularRingFactory cofac = null; GenPolynomialRing mufac = null; // search lucky prime for (int i = 0; i < 11; i++) { // prime meta loop //for ( int i = 0; i < 1; i++ ) { // meta loop java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next(); // 2 small, 5 medium and 4 large size primes if (i == 0) { // medium size primes = new PrimeList(PrimeList.Range.medium); primeIter = primes.iterator(); } if (i == 5) { // small size primes = new PrimeList(PrimeList.Range.small); primeIter = primes.iterator(); p = primeIter.next(); // 2 p = primeIter.next(); // 3 p = primeIter.next(); // 5 p = primeIter.next(); // 7 } if (i == 7) { // large size primes = new PrimeList(PrimeList.Range.large); primeIter = primes.iterator(); } int pi = 0; while (pi++ < pn && primeIter.hasNext()) { p = primeIter.next(); logger.info("prime = {}", p); // initialize coefficient factory and map normalization factor and polynomials ModularRingFactory cf = null; if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cf = (ModularRingFactory) new ModLongRing(p, true); } else { cf = (ModularRingFactory) new ModIntegerRing(p, true); } MOD nf = cf.fromInteger(ae.getVal()); if (nf.isZERO()) { continue; } mufac = new GenPolynomialRing(cf, ufac); //System.out.println("mufac = " + mufac.toScript()); Pm = PolyUtil. fromIntegerCoefficients(mufac, pe); //System.out.println("Pm = " + Pm); if (!mfactor.isSquarefree(Pm)) { continue; } cofac = cf; break; } if (cofac != null) { break; } } // end prime meta loop if (cofac == null) { // no lucky prime found throw new RuntimeException("giving up on Hensel preparation, no lucky prime found"); } logger.info("lucky prime = {}", cofac.getIntegerModul()); logger.debug("univariate modulo p: = {}", Pm); // coefficient bound BigInteger an = pd.maxNorm(); BigInteger mn = an.multiply(ac.abs()).multiply(new BigInteger(2L)); long k = Power.logarithm(cofac.getIntegerModul(), mn) + 1L; //System.out.println("mn = " + mn + ", k = " +k); BigInteger q = cofac.getIntegerModul().power(k); ModularRingFactory muqfac; if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) { muqfac = (ModularRingFactory) new ModLongRing(q.getVal()); } else { muqfac = (ModularRingFactory) new ModIntegerRing(q.getVal()); } //System.out.println("muqfac = " + muqfac); GenPolynomialRing mucpfac = new GenPolynomialRing(muqfac, ufac); List> muqfactors = PolyUtil. fromIntegerCoefficients(mucpfac, ufactors); GenPolynomial peqq = PolyUtil. fromIntegerCoefficients(mucpfac, pe); if (debug) { if (!mfactor.isFactorization(peqq, muqfactors)) { // should not happen System.out.println("muqfactors = " + muqfactors); System.out.println("peqq = " + peqq); throw new RuntimeException("something is wrong, no modular p^k factorization"); } } logger.info("univariate modulo p^k: {} = {}", peqq, muqfactors); // convert C from Z[...] to Z_q[...] GenPolynomialRing qcfac = new GenPolynomialRing(muqfac, pd.ring); GenPolynomial pq = PolyUtil. fromIntegerCoefficients(qcfac, pd); //System.out.println("pd = " + pd); logger.info("multivariate modulo p^k: {}", pq); //List Vm = new ArrayList(V.size()); //for (BigInteger v : V) { // MOD vm = muqfac.fromInteger(v.getVal()); // Vm.add(vm); //} //System.out.println("Vm = " + Vm); // Hensel lifting of factors List> mlift; try { mlift = HenselMultUtil. liftHensel(pd, pq, muqfactors, V, k, lf); logger.info("mlift = {}", mlift); } catch (NoLiftingException nle) { //System.out.println("exception : " + nle); //nle.printStackTrace(); //mlift = new ArrayList>(); throw new RuntimeException(nle); } catch (ArithmeticException aex) { //System.out.println("exception : " + aex); //aex.printStackTrace(); //mlift = new ArrayList>(); throw aex; } if (mlift.size() <= 1) { // irreducible mod I, p^k, can this happen? logger.info("modular lift size == 1: {}", mlift); factors.add(pd); // P if (cfactors != null) { cfactors.addAll(factors); factors = cfactors; } return factors; } // combine trial factors GenPolynomialRing mfac = mlift.get(0).ring; int dl = (mlift.size() + 1) / 2; GenPolynomial u = P; long deg = (u.degree() + 1L) / 2L; GenPolynomial ui = pd; for (int j = 1; j <= dl; j++) { //System.out.println("j = " + j + ", dl = " + dl + ", mlift = " + mlift); KsubSet> subs = new KsubSet>(mlift, j); for (List> flist : subs) { //System.out.println("degreeSum = " + degreeSum(flist)); GenPolynomial mtrial = Power.> multiply(mfac, flist); if (mtrial.degree() > deg) { // this test is sometimes wrong logger.info("degree > deg {}, degree = {}", deg, mtrial.degree()); //continue; } GenPolynomial trial = PolyUtil.integerFromModularCoefficients(pfac, mtrial); trial = engine.basePrimitivePart(trial); //if ( ! isPrimitive ) { //} if (debug) { logger.info("trial = {}", trial); // + ", mtrial = {}", mtrial); } if (PolyUtil. baseSparsePseudoRemainder(ui, trial).isZERO()) { logger.info("successful trial = {}", trial); factors.add(trial); ui = PolyUtil. basePseudoDivide(ui, trial); //System.out.println("ui = " + ui); mlift = removeOnce(mlift, flist); logger.info("new mlift= {}", mlift); //System.out.println("dl = " + dl); if (mlift.size() > 1) { dl = (mlift.size() + 1) / 2; j = 0; // since j++ break; } logger.info("last factor = {}", ui); factors.add(ui); if (cfactors != null) { cfactors.addAll(factors); factors = cfactors; } return normalizeFactorization(factors); } } } if (!ui.isONE() && !ui.equals(pd)) { logger.info("rest factor = {}", ui); // pp(ui) ?? no ?? factors.add(ui); } if (factors.size() == 0) { logger.info("irreducible P = {}", P); factors.add(pd); // P } if (cfactors != null) { cfactors.addAll(factors); factors = cfactors; } return normalizeFactorization(factors); } /** * Test if b has a prime factor different to the elements of A. * @param A list of integer with at least one different prime factor. * @param b integer to test with A. * @return true, if b hase a prime factor different to elements of A */ boolean testSeparate(List A, BigInteger b) { int i = 0; //List gei = new ArrayList(A.size()); for (BigInteger c : A) { BigInteger g = c.gcd(b).abs(); //gei.add(g); if (!g.isONE()) { i++; } } //if ( i >= 1 ) { //System.out.println("gei = " + gei + ", cei = " + cei + ", pec(w) = " + pec); //} return (i <= 1); } // not usable boolean isNearlySquarefree(GenPolynomial P) { // unused // in main variable GenPolynomialRing pfac = P.ring; if (pfac.nvar >= 0) { // always true return sengine.isSquarefree(P); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial> Ps = PolyUtil. recursiveDerivative(Pr); System.out.println("Pr = " + Pr); System.out.println("Ps = " + Ps); GenPolynomial> g = engine.recursiveUnivariateGcd(Pr, Ps); System.out.println("g_m = " + g); if (!g.isONE()) { return false; } // in lowest variable rfac = pfac.recursive(pfac.nvar - 1); Pr = PolyUtil. recursive(rfac, P); Pr = PolyUtil. switchVariables(Pr); Ps = PolyUtil. recursiveDerivative(Pr); System.out.println("Pr = " + Pr); System.out.println("Ps = " + Ps); g = engine.recursiveUnivariateGcd(Pr, Ps); System.out.println("g_1 = " + g); if (!g.isONE()) { return false; } return true; } } /** * Container for factorization trial lifting parameters. */ class TrialParts { /** * evaluation points */ public final List evalPoints; /** * univariate polynomial */ public final GenPolynomial univPoly; /** * irreducible factors of univariate polynomial */ public final List> univFactors; /** * irreducible factors of leading coefficient */ public final List> ldcfFactors; /** * evaluated factors of leading coefficient factors by evaluation points */ public final List ldcfEval; /** * Constructor. * @param ev evaluation points. * @param up univariate polynomial. * @param uf irreducible factors of up. * @param le irreducible factors of leading coefficient. * @param lf evaluated le by evaluation points. */ public TrialParts(List ev, GenPolynomial up, List> uf, List le, List> lf) { evalPoints = ev; univPoly = up; univFactors = uf; //ldcfPoly = lp; ldcfFactors = lf; ldcfEval = le; } /** * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("TrialParts["); sb.append("evalPoints = " + evalPoints); sb.append(", univPoly = " + univPoly); sb.append(", univFactors = " + univFactors); sb.append(", ldcfEval = " + ldcfEval); sb.append(", ldcfFactors = " + ldcfFactors); sb.append("]"); return sb.toString(); } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorModular.java000066400000000000000000000202341445075545500240430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.Power; import edu.jas.structure.RingFactory; /** * Modular coefficients factorization algorithms. This class implements * factorization methods for polynomials over (prime) modular integers. * @author Heinz Kredel */ public class FactorModular & Modular> extends FactorAbsolute { private static final Logger logger = LogManager.getLogger(FactorModular.class); private static final boolean debug = logger.isDebugEnabled(); /** * No argument constructor, do not use. */ @SuppressWarnings({ "unchecked", "unused" }) private FactorModular() { this((RingFactory) (Object) new ModLongRing(13, true)); // hack, 13 unimportant } /** * Constructor. * @param cfac coefficient ring factory. */ public FactorModular(RingFactory cfac) { super(cfac); } /** * GenPolynomial base distinct degree factorization. * @param P squarefree and monic GenPolynomial. * @return [e_1 -> p_1, ..., e_k -> p_k] with P = prod_{i=1,...,k} p_i * and p_i has only irreducible factors of degree e_i. */ public SortedMap> baseDistinctDegreeFactors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } SortedMap> facs = new TreeMap>(); if (P.isZERO()) { return facs; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } ModularRingFactory mr = (ModularRingFactory) pfac.coFac; java.math.BigInteger m = mr.getIntegerModul().getVal(); //if (m.longValue() == 2L) { // logger.warn(this.getClass().getName() + " case p = 2 not implemented"); //} GenPolynomial x = pfac.univariate(0); GenPolynomial h = x; GenPolynomial f = P; GenPolynomial g; Power> pow = new Power>(pfac); long d = 0; while (d + 1 <= f.degree(0) / 2) { d++; h = pow.modPower(h, m, f); g = engine.gcd(h.subtract(x), f); if (!g.isONE()) { facs.put(d, g); f = f.divide(g); } } if (!f.isONE()) { d = f.degree(0); facs.put(d, f); } return facs; } /** * GenPolynomial base equal degree factorization. * @param P squarefree and monic GenPolynomial. * @param deg such that P has only irreducible factors of degree deg. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> baseEqualDegreeFactors(GenPolynomial P, long deg) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } List> facs = new ArrayList>(); if (P.isZERO()) { return facs; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } if (P.degree(0) == deg) { facs.add(P); return facs; } ModularRingFactory mr = (ModularRingFactory) pfac.coFac; java.math.BigInteger m = mr.getIntegerModul().getVal(); //System.out.println("m = " + m); boolean p2 = false; if (m.equals(java.math.BigInteger.valueOf(2L))) { p2 = true; //throw new RuntimeException(this.getClass().getName() + " case p = 2 not implemented"); } GenPolynomial one = pfac.getONE(); GenPolynomial t = pfac.univariate(0, 1L); GenPolynomial r; GenPolynomial h; GenPolynomial f = P; //GreatestCommonDivisor engine = GCDFactory. getImplementation(pfac.coFac); Power> pow = new Power>(pfac); GenPolynomial g = null; int degi = (int) deg; //f.degree(0); //System.out.println("deg = " + deg); BigInteger di = (new BigInteger(m)).power(deg); //System.out.println("di = " + di); java.math.BigInteger d = di.getVal(); //.longValue()-1; //System.out.println("d = " + d); d = d.shiftRight(1); // divide by 2 do { if (p2) { h = t; for (int i = 1; i < degi; i++) { h = t.sum(h.multiply(h)); h = h.remainder(f); } t = t.multiply(pfac.univariate(0, 2L)); //System.out.println("h = " + h); } else { r = pfac.random(17, degi, 2 * degi, 1.0f); if (r.degree(0) >= f.degree(0)) { r = r.remainder(f); } r = r.monic(); //System.out.println("r = " + r); h = pow.modPower(r, d, f).subtract(one); degi++; } g = engine.gcd(h, f); //System.out.println("g = " + g); } while (g.degree(0) == 0 || g.degree(0) == f.degree(0)); f = f.divide(g); facs.addAll(baseEqualDegreeFactors(f, deg)); facs.addAll(baseEqualDegreeFactors(g, deg)); return facs; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree and monic! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @Override public List> baseFactorsSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } if (!P.leadingBaseCoefficient().isONE()) { throw new IllegalArgumentException("ldcf(P) != 1: " + P); } SortedMap> dfacs = baseDistinctDegreeFactors(P); if (debug) { logger.info("dfacs = {}", dfacs); //System.out.println("dfacs = " + dfacs); } for (Map.Entry> me : dfacs.entrySet()) { Long e = me.getKey(); GenPolynomial f = me.getValue(); // dfacs.get(e); List> efacs = baseEqualDegreeFactors(f, e); if (debug) { logger.info("efacs {} = {}", e, efacs); //System.out.println("efacs " + e + " = " + efacs); } factors.addAll(efacs); } //System.out.println("factors = " + factors); factors = PolyUtil. monic(factors); SortedSet> ss = new TreeSet>(factors); //System.out.println("sorted = " + ss); factors.clear(); factors.addAll(ss); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorModularBerlekamp.java000066400000000000000000000275411445075545500256760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.ModLongRing; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.Power; import edu.jas.structure.RingFactory; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; import edu.jas.vector.LinAlg; /** * Modular coefficients Berlekamp factorization algorithms. This class * implements Berlekamp, Cantor and Zassenhaus factorization methods for * polynomials over (prime) modular integers. * @author Heinz Kredel */ public class FactorModularBerlekamp> extends FactorAbsolute { private static final Logger logger = LogManager.getLogger(FactorModularBerlekamp.class); //private static final boolean debug = logger.isDebugEnabled(); /** * No argument constructor, do not use. */ @SuppressWarnings({ "unchecked", "unused" }) private FactorModularBerlekamp() { this((RingFactory) (Object) new ModLongRing(13, true)); // hack, 13 unimportant } /** * Constructor. * @param cfac coefficient ring factory. */ public FactorModularBerlekamp(RingFactory cfac) { super(cfac); } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree and monic! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @Override public List> baseFactorsSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null not allowed"); } //ModularRingFactory cfac = (ModularRingFactory) P.ring.coFac; long q = P.ring.coFac.characteristic().longValueExact(); if (q < 100) { // todo, 32003 too high return baseFactorsSquarefreeSmallPrime(P); } return baseFactorsSquarefreeBigPrime(P); } /** * GenPolynomial base factorization of a squarefree polynomial. Small prime * version of Berlekamps algorithm. * @param P squarefree and monic! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ @SuppressWarnings("unchecked") public List> baseFactorsSquarefreeSmallPrime(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } if (!P.leadingBaseCoefficient().isONE()) { throw new IllegalArgumentException("ldcf(P) != 1: " + P); } if (P.isONE() || P.degree(0) <= 1) { factors.add(P); return factors; } ArrayList> Q = PolyUfdUtil. constructQmatrix(P); //System.out.println("Q = " + Q); int n = Q.size(); int m = Q.get(0).size(); GenMatrixRing mfac = new GenMatrixRing(pfac.coFac, n, m); GenMatrix Qm = new GenMatrix(mfac, Q); GenMatrix Qm1 = Qm.subtract(mfac.getONE()); //System.out.println("Qm1 = " + Qm1); LinAlg lu = new LinAlg(); List> Nsb = lu.nullSpaceBasis(Qm1); logger.info("Nsb = {}", Nsb); int k = Nsb.size(); if (k == 1) { factors.add(P); return factors; } //int d = (int) P.degree(0); GenMatrix Ns = mfac.fromVectors(Nsb); GenMatrix L1 = Ns.negate(); //mfac.getONE().subtract(Ns); //System.out.println("L1 = " + L1); List> trials = new ArrayList>(); for (int i = 0; i < L1.ring.rows; i++) { GenVector rv = L1.getRow(i); GenPolynomial rp = pfac.fromVector(rv); if (!rp.isONE()) { trials.add(rp); } } logger.info("#ofFactors k = {}", k); logger.info("trials = {}", trials); factors.add(P); for (GenPolynomial t : trials) { if (factors.size() == k) { break; } //System.out.println("t = " + t); // depth first search, since Iterator is finite GenPolynomial a = factors.remove(0); //System.out.println("a = " + a); MOD s = null; Iterator eit = null; if (pfac.coFac instanceof ModularRingFactory) { eit = ((ModularRingFactory) pfac.coFac).iterator(); } else if (pfac.coFac instanceof AlgebraicNumberRing) { eit = ((AlgebraicNumberRing) pfac.coFac).iterator(); } else { throw new IllegalArgumentException("no iterator for: " + pfac.coFac); } //System.out.println("eit = " + eit); while (eit.hasNext()) { s = eit.next(); //System.out.println("s = " + s); GenPolynomial v = t.subtract(s); GenPolynomial g = v.gcd(a); if (g.isONE() || g.equals(a)) { continue; } factors.add(g); a = a.divide(g); logger.info("s = {}, g = {}, a = {}", s, g, a); if (a.isONE()) { break; } } if (!a.isONE()) { factors.add(a); } } //System.out.println("factors = " + factors); factors = PolyUtil. monic(factors); SortedSet> ss = new TreeSet>(factors); //System.out.println("sorted = " + ss); factors.clear(); factors.addAll(ss); return factors; } /** * GenPolynomial base factorization of a squarefree polynomial. Big prime * version of Berlekamps algorithm. * @param P squarefree and monic! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> baseFactorsSquarefreeBigPrime(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException("P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } if (!P.leadingBaseCoefficient().isONE()) { throw new IllegalArgumentException("ldcf(P) != 1: " + P); } if (P.isONE() || P.degree(0) <= 1) { factors.add(P); return factors; } ArrayList> Q = PolyUfdUtil. constructQmatrix(P); //System.out.println("Q = " + Q); int n = Q.size(); int m = Q.get(0).size(); GenMatrixRing mfac = new GenMatrixRing(pfac.coFac, n, m); GenMatrix Qm = new GenMatrix(mfac, Q); GenMatrix Qm1 = Qm.subtract(mfac.getONE()); //System.out.println("Qm1 = " + Qm1); LinAlg lu = new LinAlg(); List> Nsb = lu.nullSpaceBasis(Qm1); logger.info("Nsb = {}", Nsb); int k = Nsb.size(); if (k == 1) { factors.add(P); return factors; } //int d = (int) P.degree(0); GenMatrix Ns = mfac.fromVectors(Nsb); GenMatrix L1 = Ns.negate(); //mfac.getONE().subtract(Ns); //System.out.println("L1 = " + L1); List> trials = new ArrayList>(); for (int i = 0; i < L1.ring.rows; i++) { GenVector rv = L1.getRow(i); GenPolynomial rp = pfac.fromVector(rv); trials.add(rp); } logger.info("#ofFactors k = {}", k); logger.info("trials = {}", trials); factors.add(P); GenVectorModul vfac = new GenVectorModul(pfac.coFac, k); //long q = pfac.coFac.characteristic().longValueExact(); //long lq = Power.logarithm(2, q); java.math.BigInteger q = pfac.coFac.characteristic(); //.longValueExact(); int lq = q.bitLength(); //Power.logarithm(2, q); if (pfac.coFac instanceof AlgebraicNumberRing) { lq = (int) ((AlgebraicNumberRing) pfac.coFac).extensionDegree(); q = q.pow(lq); //Power.power(q, lq); } logger.info("char = {}, q = {}, lq = {}", pfac.coFac.characteristic(), q, lq); do { // breadth first search, since some a might be irreducible GenPolynomial a = factors.remove(0); //System.out.println("a = " + a); if (a.degree(0) <= 1) { factors.add(a); continue; } GenVector rv = vfac.random(8, 0.95f); //System.out.println("rv = " + rv.toScript()); GenPolynomial rpol = pfac.getZERO(); int i = 0; for (GenPolynomial t : trials) { MOD c = rv.get(i++); GenPolynomial s = t.multiply(c); rpol = rpol.sum(s); } rpol = rpol.monic(); if (rpol.isONE()) { factors.add(a); continue; } //System.out.println("rpol = " + rpol.toScript()); if (!q.testBit(0)) { // q % 2 == 0 long e = lq - 1; //System.out.println("q = " + q + ", e = " + e); GenPolynomial pow = rpol; GenPolynomial v = rpol; for (int l = 1; l < e; l++) { pow = pow.multiply(pow).remainder(a); v = v.sum(pow); } rpol = v.remainder(a).monic(); // automatic monic //System.out.println("sum_l rpol^l = " + rpol.toScript()); } else { //long e = (q - 1) / 2; java.math.BigInteger e = q.subtract(java.math.BigInteger.ONE).shiftRight(1); //System.out.println("q = " + q + ", e = " + e); GenPolynomial pow = Power.> modPositivePower(rpol, e, a); rpol = pow.subtract(pfac.getONE()).monic(); //System.out.println("rpol^e-1 = " + rpol.toScript()); } if (rpol.isZERO() || rpol.isONE()) { factors.add(a); continue; } GenPolynomial g = rpol.gcd(a); if (g.isONE()) { factors.add(a); continue; } factors.add(g); //System.out.println("a = " + a); a = a.divide(g); logger.info("rv = {}, g = {}, a/g = {}", rv, g, a); if (!a.isONE()) { factors.add(a); } //System.out.println("factors = " + factors); } while (factors.size() < k); //System.out.println("factors = " + factors); factors = PolyUtil. monic(factors); SortedSet> ss = new TreeSet>(factors); //System.out.println("sorted = " + ss); factors.clear(); factors.addAll(ss); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorQuotient.java000066400000000000000000000101471445075545500242520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; /** * Rational function coefficients factorization algorithms. This class * implements factorization methods for polynomials over rational functions, * that is, with coefficients from class application.Quotient. * @author Heinz Kredel */ public class FactorQuotient> extends FactorAbstract> { private static final Logger logger = LogManager.getLogger(FactorQuotient.class); //private static final boolean debug = logger.isInfoEnabled(); /** * Factorization engine for normal coefficients. */ protected final FactorAbstract nengine; /** * No argument constructor. */ protected FactorQuotient() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac coefficient quotient ring factory. */ public FactorQuotient(QuotientRing fac) { this(fac, FactorFactory. getImplementation(fac.ring.coFac)); } /** * Constructor. * @param fac coefficient quotient ring factory. * @param nengine factorization engine for polynomials over base * coefficients. */ public FactorQuotient(QuotientRing fac, FactorAbstract nengine) { super(fac); this.nengine = nengine; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> baseFactorsSquarefree(GenPolynomial> P) { return factorsSquarefree(P); } /** * GenPolynomial factorization of a squarefree polynomial. * @param P squarefree GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> factorsSquarefree(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } //System.out.println("factorsSquarefree, P = " + P); List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; GenPolynomial> Pr = P; Quotient ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { //System.out.println("ldcf = " + ldcf); Pr = Pr.monic(); } QuotientRing qi = (QuotientRing) pfac.coFac; GenPolynomialRing ci = qi.ring; GenPolynomialRing> ifac = new GenPolynomialRing>(ci, pfac); GenPolynomial> Pi = PolyUfdUtil. integralFromQuotientCoefficients(ifac, Pr); //System.out.println("Pi = " + Pi); // factor in C[x_1,...,x_n][y_1,...,y_m] List>> irfacts = nengine.recursiveFactorsSquarefree(Pi); logger.info("irfacts = {}", irfacts); if (irfacts.size() <= 1) { factors.add(P); return factors; } List>> qfacts = PolyUfdUtil. quotientFromIntegralCoefficients(pfac, irfacts); //System.out.println("qfacts = " + qfacts); //qfacts = PolyUtil.monic(qfacts); //System.out.println("qfacts = " + qfacts); if (!ldcf.isONE()) { GenPolynomial> r = qfacts.get(0); qfacts.remove(r); r = r.multiply(ldcf); qfacts.add(0, r); } logger.info("qfacts = {}", qfacts); factors.addAll(qfacts); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorRational.java000066400000000000000000000160461445075545500242170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; /** * Rational number coefficients factorization algorithms. This class implements * factorization methods for polynomials over rational numbers. * @author Heinz Kredel */ public class FactorRational extends FactorAbsolute { private static final Logger logger = LogManager.getLogger(FactorRational.class); private static final boolean debug = logger.isInfoEnabled(); /** * Factorization engine for integer base coefficients. */ protected final FactorAbstract iengine; /** * No argument constructor. */ protected FactorRational() { super(BigRational.ONE); iengine = FactorFactory.getImplementation(BigInteger.ONE); } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List> baseFactorsSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial Pr = P; BigRational ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { //System.out.println("ldcf = " + ldcf); Pr = Pr.monic(); } BigInteger bi = BigInteger.ONE; GenPolynomialRing ifac = new GenPolynomialRing(bi, pfac); GenPolynomial Pi = PolyUtil.integerFromRationalCoefficients(ifac, Pr); if (debug) { logger.info("Pi = {}", Pi); } List> ifacts = iengine.baseFactorsSquarefree(Pi); logger.info("ifacts = {}", ifacts); if (ifacts.size() <= 1) { factors.add(P); return factors; } List> rfacts = PolyUtil.fromIntegerCoefficients(pfac, ifacts); //System.out.println("rfacts = " + rfacts); rfacts = PolyUtil.monic(rfacts); //System.out.println("rfacts = " + rfacts); if (!ldcf.isONE()) { GenPolynomial r = rfacts.get(0); rfacts.remove(r); r = r.multiply(ldcf); rfacts.set(0, r); } logger.info("rfacts = {}", rfacts); factors.addAll(rfacts); return factors; } /** * GenPolynomial factorization of a squarefree polynomial. * @param P squarefree GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List> factorsSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List> factors = new ArrayList>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing pfac = P.ring; if (pfac.nvar == 1) { return baseFactorsSquarefree(P); } GenPolynomial Pr = P; BigRational ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { //System.out.println("ldcf = " + ldcf); Pr = Pr.monic(); } BigInteger bi = BigInteger.ONE; GenPolynomialRing ifac = new GenPolynomialRing(bi, pfac); GenPolynomial Pi = PolyUtil.integerFromRationalCoefficients(ifac, Pr); if (debug) { logger.info("Pi = {}", Pi); } List> ifacts = iengine.factorsSquarefree(Pi); logger.info("ifacts = {}", ifacts); if (ifacts.size() <= 1) { factors.add(P); return factors; } List> rfacts = PolyUtil.fromIntegerCoefficients(pfac, ifacts); //System.out.println("rfacts = " + rfacts); rfacts = PolyUtil.monic(rfacts); //System.out.println("rfacts = " + rfacts); if (!ldcf.isONE()) { GenPolynomial r = rfacts.get(0); rfacts.remove(r); r = r.multiply(ldcf); rfacts.set(0, r); } logger.info("rfacts = {}", rfacts); factors.addAll(rfacts); return factors; } /** * GenPolynomial factorization of a polynomial. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i and p_i irreducible. */ @Override public SortedMap, Long> factors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } GenPolynomialRing pfac = P.ring; SortedMap, Long> factors = new TreeMap, Long>( pfac.getComparator()); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.put(P, 1L); return factors; } if (pfac.nvar == 1) { return baseFactors(P); } GenPolynomial Pr = P; BigInteger bi = BigInteger.ONE; GenPolynomialRing ifac = new GenPolynomialRing(bi, pfac); GenPolynomial Pi = PolyUtil.integerFromRationalCoefficients(ifac, Pr); if (debug) { logger.info("Pi = {}", Pi); } SortedMap, Long> ifacts = iengine.factors(Pi); logger.info("ifacts = {}", ifacts); for (Map.Entry, Long> me : ifacts.entrySet()) { GenPolynomial g = me.getKey(); if (g.isONE()) { // skip 1 continue; } Long d = me.getValue(); // facs.get(g); GenPolynomial rp = PolyUtil.fromIntegerCoefficients(pfac, g); factors.put(rp, d); } return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufd/Factorization.java000066400000000000000000000073021445075545500241160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.List; import java.util.SortedMap; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Factorization algorithms interface. *

* Usage: To create objects that implement the Factorization * interface use the FactorFactory. It will select an appropriate * implementation based on the types of polynomial coefficients C. To obtain an * implementation use getImplementation(), it returns an object of * a class which extends the FactorAbstract class which implements * the Factorization interface. *

* *

 * Factorization<CT> engine;
 * engine = FactorFactory.<CT> getImplementation(cofac);
 * c = engine.factors(a);
 * 
*

* For example, if the coefficient type is BigInteger, the usage looks like * *

 * BigInteger cofac = new BigInteger();
 * Factorization<BigInteger> engine;
 * engine = FactorFactory.getImplementation(cofac);
 * Sm = engine.factors(poly);
 * 
* * @author Heinz Kredel * @see edu.jas.ufd.FactorFactory#getImplementation */ public interface Factorization> extends Serializable { /** * GenPolynomial test if is irreducible. * @param P GenPolynomial. * @return true if P is irreducible, else false. */ public boolean isIrreducible(GenPolynomial P); /** * GenPolynomial test if a non trivial factorization exists. * @param P GenPolynomial. * @return true if P is reducible, else false. */ public boolean isReducible(GenPolynomial P); /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isSquarefree(GenPolynomial P); /** * GenPolynomial factorization of a squarefree polynomial. * @param P squarefree and primitive! or monic! GenPolynomial. * @return [p_1,...,p_k] with P = prod_{i=1,...,r} p_i. */ public List> factorsSquarefree(GenPolynomial P); /** * GenPolynomial factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i**e_i. */ public SortedMap, Long> factors(GenPolynomial P); /** * GenPolynomial factorization ignoring multiplicities. * @param P GenPolynomial. * @return [p_1, ..., p_k] with P = prod_{i=1,...,k} p_i**{e_i} for some * e_i. */ public List> factorsRadical(GenPolynomial P); /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(P). */ public GenPolynomial squarefreePart(GenPolynomial P); /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree. */ public SortedMap, Long> squarefreeFactors(GenPolynomial P); /** * GenPolynomial is factorization. * @param P GenPolynomial * @param F = [p_1,...,p_k]. * @return true if P = prod_{i=1,...,r} p_i, else false. */ public boolean isFactorization(GenPolynomial P, List> F); /** * GenPolynomial is factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i , else false. */ public boolean isFactorization(GenPolynomial P, SortedMap, Long> F); } java-algebra-system-2.7.200/src/edu/jas/ufd/Factors.java000066400000000000000000000244561445075545500227140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.GcdRingElem; /** * Container for the factors of absolute factorization. * @author Heinz Kredel * @param coefficient type */ public class Factors> implements Comparable>, Serializable { /** * Original (irreducible) polynomial to be factored with coefficients from * C. */ public final GenPolynomial poly; /** * Algebraic field extension over C. Should be null, if p is absolutely * irreducible. */ public final AlgebraicNumberRing afac; /** * Original polynomial to be factored with coefficients from * AlgebraicNumberRing<C>. Should be null, if p is absolutely * irreducible. */ public final GenPolynomial> apoly; /** * List of factors with coefficients from AlgebraicNumberRing<C>. * Should be null, if p is absolutely irreducible. */ public final List>> afactors; /** * List of factors with coefficients from * AlgebraicNumberRing<AlgebraicNumber<C>>. Should be null, if p * is absolutely irreducible. */ public final List>> arfactors; /** * Constructor. * @param p absolute irreducible GenPolynomial. */ public Factors(GenPolynomial p) { this(p, null, null, null, null); } /** * Constructor. * @param p irreducible GenPolynomial over C. * @param af algebraic extension field of C where p has factors from afact. * @param ap GenPolynomial p represented with coefficients from af. * @param afact absolute irreducible factors of p with coefficients from af. */ public Factors(GenPolynomial p, AlgebraicNumberRing af, GenPolynomial> ap, List>> afact) { this(p, af, ap, afact, null); } /** * Constructor. * @param p irreducible GenPolynomial over C. * @param af algebraic extension field of C where p has factors from afact. * @param ap GenPolynomial p represented with coefficients from af. * @param afact absolute irreducible factors of p with coefficients from af. * @param arfact further absolute irreducible factors of p with coefficients * from extensions of af. */ public Factors(GenPolynomial p, AlgebraicNumberRing af, GenPolynomial> ap, List>> afact, List>> arfact) { poly = p; afac = af; apoly = ap; afactors = afact; arfactors = arfact; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(poly.toString()); if (afac == null) { return sb.toString(); } sb.append(" = "); boolean first = true; for (GenPolynomial> ap : afactors) { if (first) { first = false; } else { sb.append(", "); } sb.append(ap.toString()); } sb.append("\n ## over " + afac.toString() + "\n"); if (arfactors == null) { return sb.toString(); } first = true; for (Factors> arp : arfactors) { if (first) { first = false; } else { sb.append(",\n"); } sb.append(arp.toString()); } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); //sb.append(poly.toScript()); if (afac == null) { return sb.toString(); } //sb.append(" =\n"); boolean first = true; for (GenPolynomial> ap : afactors) { if (first) { first = false; } else { sb.append("\n * "); } //sb.append("( " + ap.toScript() + " )"); sb.append(ap.toScript()); } sb.append(" #:: " + afac.toScript() + ""); if (arfactors == null) { return sb.toString(); } for (Factors> arp : arfactors) { if (first) { first = false; } else { sb.append("\n * "); } sb.append(arp.toScript()); } return sb.toString(); } /** * Length. Number of factors. * @return number of factors. */ public int length() { int i = 0; if (afac == null) { return i; } i += afactors.size(); if (arfactors == null) { return i; } for (Factors> f : arfactors) { i += f.length(); } return i; } /** * Hash code for this Factors. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = poly.hashCode(); if (afac == null) { return h; } h = (h << 27); h += afac.hashCode(); if (afactors != null) { h = (h << 27); h += afactors.hashCode(); } if (arfactors != null) { h = (h << 27); h += arfactors.hashCode(); } return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof Factors)) { return false; } Factors a = (Factors) B; return this.compareTo(a) == 0; } /** * Comparison. * @param facs factors container. * @return sign(this.poly-facs.poly) lexicographic > * sign(afac.modul-facs.afac.modul) lexicographic > * afactors.compareTo(facs.afactors) lexicographic > * arfactors[i].compareTo(facs.arfactors[i]) */ public int compareTo(Factors facs) { int s = poly.compareTo(facs.poly); //System.out.println("s1 = " + s); if (s != 0) { return s; } if (afac == null) { return -1; } if (facs.afac == null) { return +1; } s = afac.modul.compareTo(facs.afac.modul); //System.out.println("s2 = " + s); if (s != 0) { return s; } GenPolynomialRing> ar = afactors.get(0).ring; GenPolynomialRing> br = facs.afactors.get(0).ring; PolynomialList> ap = new PolynomialList>(ar, afactors); PolynomialList> bp = new PolynomialList>(br, facs.afactors); s = ap.compareTo(bp); //System.out.println("s3 = " + s); if (s != 0) { return s; } if (arfactors == null && facs.arfactors == null) { return 0; } if (arfactors == null) { return -1; } if (facs.arfactors == null) { return +1; } // lexicographic (?) int i = 0; for (Factors> arp : arfactors) { if (i >= facs.arfactors.size()) { return +1; } Factors> brp = facs.arfactors.get(i); //System.out.println("arp = " + arp); //System.out.println("brp = " + brp); s = arp.compareTo(brp); //System.out.println("s4 = " + s); if (s != 0) { return s; } i++; } if (i < facs.arfactors.size()) { return -1; } return 0; } /** * Find largest extension field. * @return largest extension field or null if no extension field */ @SuppressWarnings("unchecked") public AlgebraicNumberRing findExtensionField() { if (afac == null) { return null; } if (arfactors == null) { return afac; } AlgebraicNumberRing arr = afac; int depth = 1; for (Factors> af : arfactors) { AlgebraicNumberRing> aring = af.findExtensionField(); if (aring == null) { continue; } int d = aring.depth(); if (d > depth) { depth = d; arr = (AlgebraicNumberRing) (Object) aring; } } return arr; } /** * Get the list of factors at one level. * @return list of algebraic factors */ public List>> getFactors() { List>> af = new ArrayList>>(); if (afac == null) { return af; } af.addAll(afactors); if (arfactors == null) { return af; } for (Factors> arp : arfactors) { af.add(arp.poly); } return af; } /** * Get the factor for polynomial. * @return algebraic factor */ public Factors> getFactor(GenPolynomial> p) { if (afac == null) { return null; } for (Factors> arp : arfactors) { if (p.equals(arp.poly)) { return arp; } } return null; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorsList.java000066400000000000000000000075001445075545500235370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.List; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for the factors of a squarefree factorization. * @author Heinz Kredel * @param coefficient type */ public class FactorsList> implements Serializable { /** * Original polynomial to be factored with coefficients from C. */ public final GenPolynomial poly; /** * List of factors with coefficients from C. */ public final List> factors; /** * List of factors with coefficients from AlgebraicNumberRings. */ public final List> afactors; /** * Constructor. * @param p given GenPolynomial over C. * @param list irreducible factors of p with coefficients from C. */ public FactorsList(GenPolynomial p, List> list) { this(p, list, null); } /** * Constructor. * @param p given GenPolynomial over C. * @param list irreducible factors of p with coefficients from C. * @param alist irreducible factors of p with coefficients from an algebraic * number field. */ public FactorsList(GenPolynomial p, List> list, List> alist) { poly = p; factors = list; afactors = alist; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); //sb.append(poly.toString()); //sb.append(" =\n"); boolean first = true; for (GenPolynomial p : factors) { if (first) { first = false; } else { sb.append(",\n "); } sb.append(p.toString()); } if (afactors == null) { return sb.toString(); } for (Factors f : afactors) { if (first) { first = false; } else { sb.append(",\n "); } sb.append(f.toString()); } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); sb.append(poly.toScript()); sb.append(" =\n"); boolean first = true; for (GenPolynomial p : factors) { if (first) { first = false; } else { sb.append("\n * "); } sb.append(p.toScript()); } if (afactors == null) { return sb.toString(); } for (Factors f : afactors) { if (first) { first = false; } else { sb.append("\n * "); } sb.append(f.toScript()); } return sb.toString(); } /** * Find largest extension field. * @return largest extension field or null if no extension field */ public AlgebraicNumberRing findExtensionField() { if (afactors == null) { return null; } AlgebraicNumberRing ar = null; int depth = 0; for (Factors f : afactors) { AlgebraicNumberRing aring = f.findExtensionField(); if (aring == null) { continue; } int d = aring.depth(); if (d > depth) { depth = d; ar = aring; } } return ar; } } java-algebra-system-2.7.200/src/edu/jas/ufd/FactorsMap.java000066400000000000000000000126021445075545500233400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.SortedMap; import java.util.Map; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for the factors of a eventually non-squarefree factorization. * @author Heinz Kredel * @param coefficient type */ public class FactorsMap> implements Serializable { /** * Original polynomial to be factored with coefficients from C. */ public final GenPolynomial poly; /** * List of factors with coefficients from C. */ public final SortedMap, Long> factors; /** * List of factors with coefficients from AlgebraicNumberRings. */ public final SortedMap, Long> afactors; /** * Constructor. * @param p given GenPolynomial over C. * @param map irreducible factors of p with coefficients from C. */ public FactorsMap(GenPolynomial p, SortedMap, Long> map) { this(p, map, null); } /** * Constructor. * @param p given GenPolynomial over C. * @param map irreducible factors of p with coefficients from C. * @param amap irreducible factors of p with coefficients from an algebraic * number field. */ public FactorsMap(GenPolynomial p, SortedMap, Long> map, SortedMap, Long> amap) { poly = p; factors = map; afactors = amap; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(poly.toString()); sb.append(" =\n"); boolean first = true; for (Map.Entry,Long> me : factors.entrySet()) { GenPolynomial p = me.getKey(); if (first) { first = false; } else { sb.append(",\n "); } sb.append(p.toString()); long e = me.getValue(); if (e > 1) { sb.append("**" + e); } } if (afactors == null) { return sb.toString(); } for (Map.Entry,Long> me : afactors.entrySet()) { Factors f = me.getKey(); if (first) { first = false; } else { sb.append(",\n "); } sb.append(f.toString()); Long e = me.getValue(); if (e == null) { continue; } if (e > 1) { sb.append("**" + e); } } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); //sb.append(poly.toScript()); //sb.append(" =\n"); boolean first = true; for (Map.Entry,Long> me : factors.entrySet()) { GenPolynomial p = me.getKey(); if (first) { first = false; } else { sb.append("\n * "); } sb.append(p.toScript()); long e = me.getValue(); if (e > 1) { sb.append("**" + e); } } if (afactors == null) { return sb.toString(); } for (Map.Entry,Long> me : afactors.entrySet()) { Factors f = me.getKey(); if (first) { first = false; } else { sb.append("\n * "); } Long e = me.getValue(); if (e == null) { // should not happen System.out.println("f = " + f); System.out.println("afactors = " + afactors); throw new RuntimeException("this should not happen"); } if (e == 1) { sb.append(f.toScript()); } else { sb.append("(\n"); sb.append(f.toScript()); sb.append("\n)**" + e); } } return sb.toString(); } /** * Length. Number of factors. * @return number of distinct factors. */ public int length() { int i = factors.keySet().size(); if (afactors == null) { return i; } for (Factors f : afactors.keySet()) { i += f.length(); } return i; } /** * Find largest extension field. * @return largest extension field or null if no extension field */ public AlgebraicNumberRing findExtensionField() { if (afactors == null) { return null; } AlgebraicNumberRing ar = null; int depth = 0; for (Factors f : afactors.keySet()) { AlgebraicNumberRing aring = f.findExtensionField(); if (aring == null) { continue; } int d = aring.depth(); if (d > depth) { depth = d; ar = aring; } } return ar; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GCDFactory.java000066400000000000000000000317031445075545500232310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms factory. Select appropriate GCD engine * based on the coefficient types. *

* Usage: To create objects that implement the * GreatestCommonDivisor interface use the GCDFactory. * It will select an appropriate implementation based on the types of polynomial * coefficients C. There are two methods to obtain an implementation: * getProxy() and getImplementation(). * getImplementation() returns an object of a class which * implements the GreatestCommonDivisor interface. * getProxy() returns a proxy object of a class which implements * the GreatestCommonDivisorr interface. The proxy will run two * implementations in parallel, return the first computed result and cancel the * second running task. On systems with one CPU the computing time will be two * times the time of the fastest algorithm implementation. On systems with more * than two CPUs the computing time will be the time of the fastest algorithm * implementation. * *

 * GreatestCommonDivisor<CT> engine;
 * engine = GCDFactory.<CT> getImplementation(cofac);
 * or engine = GCDFactory.<CT> getProxy(cofac);
 * c = engine.gcd(a, b);
 * 
* *

* For example, if the coefficient type is BigInteger, the usage * looks like * *

 * BigInteger cofac = new BigInteger();
 * GreatestCommonDivisor<BigInteger> engine;
 * engine = GCDFactory.getImplementation(cofac);
 * or engine = GCDFactory.getProxy(cofac);
 * c = engine.gcd(a, b);
 * 
* *

* TODO: Base decision also on degree vectors and number of variables of * polynomials. Incorporate also number of CPUs / threads available (done with * GCDProxy). * * @author Heinz Kredel * @see edu.jas.ufd.GreatestCommonDivisor#gcd(edu.jas.poly.GenPolynomial P, * edu.jas.poly.GenPolynomial S) */ public class GCDFactory { private static final Logger logger = LogManager.getLogger(GCDFactory.class); /** * Protected factory constructor. */ protected GCDFactory() { } /** * Determine suitable implementation of gcd algorithms, case ModLong. * @param fac ModLongRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(ModLongRing fac) { GreatestCommonDivisorAbstract ufd; if (fac.isField()) { ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorModEval(); //ufd = new GreatestCommonDivisorSimple(); return ufd; } ufd = new GreatestCommonDivisorPrimitive(); return ufd; } /** * Determine suitable proxy for gcd algorithms, case ModLong. * @param fac ModLongRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(ModLongRing fac) { GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorSubres(); if (fac.isField()) { ufd2 = new GreatestCommonDivisorPrimitive(); //ufd2 = new GreatestCommonDivisorModEval(); } else { ufd2 = new GreatestCommonDivisorPrimitive(); //ufd2 = new GreatestCommonDivisorSimple(); } return new GCDProxy(ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case ModInt. * @param fac ModIntRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(ModIntRing fac) { GreatestCommonDivisorAbstract ufd; if (fac.isField()) { ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorModEval(); //ufd = new GreatestCommonDivisorSimple(); return ufd; } ufd = new GreatestCommonDivisorPrimitive(); //ufd = new GreatestCommonDivisorSubres(); return ufd; } /** * Determine suitable proxy for gcd algorithms, case ModInt. * @param fac ModIntRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(ModIntRing fac) { GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorSubres(); if (fac.isField()) { ufd2 = new GreatestCommonDivisorPrimitive(); //ufd2 = new GreatestCommonDivisorModEval(); } else { ufd2 = new GreatestCommonDivisorPrimitive(); //ufd2 = new GreatestCommonDivisorSimple(); } return new GCDProxy(ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case ModInteger. * @param fac ModIntegerRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(ModIntegerRing fac) { GreatestCommonDivisorAbstract ufd; if (fac.isField()) { ufd = new GreatestCommonDivisorModEval(); //ufd = new GreatestCommonDivisorSimple(); return ufd; } ufd = new GreatestCommonDivisorSubres(); return ufd; } /** * Determine suitable proxy for gcd algorithms, case ModInteger. * @param fac ModIntegerRing. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(ModIntegerRing fac) { GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorSubres(); if (fac.isField()) { ufd2 = new GreatestCommonDivisorModEval(); } else { ufd2 = new GreatestCommonDivisorPrimitive(); //ufd2 = new GreatestCommonDivisorSubres(); } return new GCDProxy(ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case BigInteger. * @param fac BigInteger. * @return gcd algorithm implementation. */ @SuppressWarnings("unused") public static GreatestCommonDivisorAbstract getImplementation(BigInteger fac) { GreatestCommonDivisorAbstract ufd; if (true) { ufd = new GreatestCommonDivisorModular(); // dummy type } else { ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorPrimitive(); } return ufd; } /** * Determine suitable procy for gcd algorithms, case BigInteger. * @param fac BigInteger. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(BigInteger fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorSubres(); ufd2 = new GreatestCommonDivisorModular(); // dummy type return new GCDProxy(ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, case BigRational. * @param fac BigRational. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getImplementation(BigRational fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } GreatestCommonDivisorAbstract ufd; ufd = new GreatestCommonDivisorPrimitive(); return ufd; } /** * Determine suitable proxy for gcd algorithms, case BigRational. * @param fac BigRational. * @return gcd algorithm implementation. */ public static GreatestCommonDivisorAbstract getProxy(BigRational fac) { if (fac == null) { throw new IllegalArgumentException("fac == null not supported"); } GreatestCommonDivisorAbstract ufd1, ufd2; ufd1 = new GreatestCommonDivisorSubres(); ufd2 = new GreatestCommonDivisorSimple(); return new GCDProxy(ufd1, ufd2); } /** * Determine suitable implementation of gcd algorithms, other cases. * @param fac RingFactory<C>. * @return gcd algorithm implementation. */ @SuppressWarnings("unchecked") public static > GreatestCommonDivisorAbstract getImplementation( RingFactory fac) { GreatestCommonDivisorAbstract/*raw type*/ ufd; logger.debug("fac = {}", fac.getClass().getName()); Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new GreatestCommonDivisorModular(); //ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorModular(true); } else if (ofac instanceof ModIntegerRing) { ufd = new GreatestCommonDivisorModEval(); //ufd = new GreatestCommonDivisorSimple(); } else if (ofac instanceof ModLongRing) { ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorSimple(); } else if (ofac instanceof ModIntRing) { ufd = new GreatestCommonDivisorSubres(); //ufd = new GreatestCommonDivisorSimple(); } else if (ofac instanceof BigRational) { ufd = new GreatestCommonDivisorSubres(); } else { if (fac.isField()) { ufd = new GreatestCommonDivisorSimple(); } else { ufd = new GreatestCommonDivisorSubres(); } } logger.debug("implementation = {}", ufd); return ufd; } /** * Determine suitable proxy for gcd algorithms, other cases. * @param fac RingFactory<C>. * @return gcd algorithm implementation. Note: This method contains a * hack for Google app engine to not use threads. * @see edu.jas.kern.ComputerThreads#NO_THREADS */ @SuppressWarnings("unchecked") public static > GreatestCommonDivisorAbstract getProxy(RingFactory fac) { if (ComputerThreads.NO_THREADS) { // hack for Google app engine return GCDFactory. getImplementation(fac); } GreatestCommonDivisorAbstract/*raw type*/ ufd; logger.debug("fac = {}", fac.getClass().getName()); Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new GCDProxy(new GreatestCommonDivisorSubres(), new GreatestCommonDivisorModular()); } else if (ofac instanceof ModIntegerRing) { ufd = new GCDProxy(new GreatestCommonDivisorSubres(), // or Primitive new GreatestCommonDivisorModEval()); } else if (ofac instanceof ModLongRing) { ufd = new GCDProxy(new GreatestCommonDivisorSimple(), // or Primitive new GreatestCommonDivisorSubres()); } else if (ofac instanceof ModIntRing) { ufd = new GCDProxy(new GreatestCommonDivisorSimple(), // or Primitive new GreatestCommonDivisorSubres()); } else if (ofac instanceof BigRational) { ufd = new GCDProxy(new GreatestCommonDivisorSubres(), new GreatestCommonDivisorPrimitive()); //Simple } else { if (fac.isField()) { ufd = new GCDProxy(new GreatestCommonDivisorSimple(), new GreatestCommonDivisorSubres()); } else { ufd = new GCDProxy(new GreatestCommonDivisorSubres(), new GreatestCommonDivisorPrimitive()); // no resultant } } logger.debug("ufd = {}", ufd); return ufd; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GCDProxy.java000066400000000000000000000515131445075545500227440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PreemptingException; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Greatest common divisor parallel proxy. * Executes methods from two implementations in parallel and * returns the result from the fastest run. * @author Heinz Kredel */ public class GCDProxy> extends GreatestCommonDivisorAbstract { // implements GreatestCommonDivisor { private static final Logger logger = LogManager.getLogger(GCDProxy.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /** * GCD and resultant engines. */ public final GreatestCommonDivisorAbstract e1; public final GreatestCommonDivisorAbstract e2; /** * Thread pool. */ protected transient ExecutorService pool; /** * Proxy constructor. */ public GCDProxy(GreatestCommonDivisorAbstract e1, GreatestCommonDivisorAbstract e2) { this.e1 = e1; this.e2 = e2; pool = ComputerThreads.getPool(); //System.out.println("pool 2 = "+pool); } /** * Get the String representation with gcd engines. * @see java.lang.Object#toString() */ @Override public String toString() { return "GCDProxy[ " + e1.getClass().getName() + ", " + e2.getClass().getName() + " ]"; } /** * Univariate GenPolynomial greatest common divisor. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(final GenPolynomial P, final GenPolynomial S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenPolynomial g = null; //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenPolynomial g = e1.baseGcd(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenPolynomial g = e2.baseGcd(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } /** * Univariate GenPolynomial recursive greatest common divisor. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(final GenPolynomial> P, final GenPolynomial> S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenPolynomial> g = null; //Callable>> c0; //Callable>> c1; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public GenPolynomial> call() { try { GenPolynomial> g = e1.recursiveUnivariateGcd(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public GenPolynomial> call() { try { GenPolynomial> g = e2.recursiveUnivariateGcd(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } /** * GenPolynomial greatest common divisor. * @param P GenPolynomial. * @param S GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial gcd(final GenPolynomial P, final GenPolynomial S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } // parallel case GenPolynomial g = null; //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenPolynomial g = e1.gcd(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenPolynomial g = e2.gcd(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } /** * Univariate GenPolynomial resultant. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial baseResultant(final GenPolynomial P, final GenPolynomial S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } // parallel case GenPolynomial g = null; //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenPolynomial g = e1.baseResultant(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenPolynomial g = e2.baseResultant(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } /** * Univariate GenPolynomial resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial> recursiveUnivariateResultant(final GenPolynomial> P, final GenPolynomial> S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } // parallel case GenPolynomial> g = null; //Callable>> c0; //Callable>> c1; List>>> cs = new ArrayList>>>( 2); cs.add(new Callable>>() { public GenPolynomial> call() { try { GenPolynomial> g = e1.recursiveUnivariateResultant(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>>() { public GenPolynomial> call() { try { GenPolynomial> g = e2.recursiveUnivariateResultant(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } /** * GenPolynomial resultant. Main entry driver method. * @param P GenPolynomial. * @param S GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial resultant(final GenPolynomial P, final GenPolynomial S) { if ( debug ) { if ( ComputerThreads.NO_THREADS ) { throw new RuntimeException("this should not happen"); } } if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } // parallel case GenPolynomial g = null; //Callable> c0; //Callable> c1; List>> cs = new ArrayList>>(2); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e1 " + e1.getClass().getName()); GenPolynomial g = e1.resultant(P, S); if (debug) { logger.info("GCDProxy done e1 {}", e1.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e1 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e1 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e1 " + e); //return P.ring.getONE(); } } }); cs.add(new Callable>() { public GenPolynomial call() { try { //System.out.println("starting e2 " + e2.getClass().getName()); GenPolynomial g = e2.resultant(P, S); if (debug) { logger.info("GCDProxy done e2 {}", e2.getClass().getName()); } return g; } catch (PreemptingException e) { throw new RuntimeException("GCDProxy e2 pre " + e); //return P.ring.getONE(); } catch (Exception e) { //e.printStackTrace(); logger.info("GCDProxy e2 {}", e); logger.info("GCDProxy P = {}", P); logger.info("GCDProxy S = {}", S); throw new RuntimeException("GCDProxy e2 " + e); //return P.ring.getONE(); } } }); try { g = pool.invokeAny(cs); } catch (InterruptedException ignored) { logger.info("InterruptedException {}", ignored); Thread.currentThread().interrupt(); } catch (ExecutionException e) { logger.info("ExecutionException {}", e); Thread.currentThread().interrupt(); } return g; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisor.java000066400000000000000000000053751445075545500256010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.List; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Greatest common divisor algorithm interface. *

* Usage: To create classes that implement this interface use the * GreatestCommonDivisorFactory. It will select an appropriate implementation * based on the types of polynomial coefficients CT. *

* *

 * 
 * GreatestCommonDivisor<CT> engine = GCDFactory.<CT> getImplementation(cofac);
 * c = engine.gcd(a, b);
 * 
* *

* For example, if the coefficient type is BigInteger, the usage looks like * *

* *

 * BigInteger cofac = new BigInteger();
 * GreatestCommonDivisor<BigInteger> engine = GCDFactory.getImplementation(cofac);
 * c = engine.gcd(a, b);
 * 
* * @author Heinz Kredel * @see edu.jas.ufd.GCDFactory#getImplementation */ public interface GreatestCommonDivisor> extends Serializable { /** * GenPolynomial content. * @param P GenPolynomial. * @return cont(P). */ public GenPolynomial content(GenPolynomial P); /** * GenPolynomial primitive part. * @param P GenPolynomial. * @return pp(P). */ public GenPolynomial primitivePart(GenPolynomial P); /** * GenPolynomial greatest common divisor. * @param P GenPolynomial. * @param S GenPolynomial. * @return gcd(P,S). */ public GenPolynomial gcd(GenPolynomial P, GenPolynomial S); /** * GenPolynomial least common multiple. * @param P GenPolynomial. * @param S GenPolynomial. * @return lcm(P,S). */ public GenPolynomial lcm(GenPolynomial P, GenPolynomial S); /** * GenPolynomial resultant. The input polynomials are considered as * univariate polynomials in the main variable. * @param P GenPolynomial. * @param S GenPolynomial. * @return res(P,S). * @throws UnsupportedOperationException if there is no implementation in * the sub-class. */ public GenPolynomial resultant(GenPolynomial P, GenPolynomial S); /** * GenPolynomial co-prime list. * @param A list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a. B does not contain zero or * constant polynomials. */ public List> coPrime(List> A); /** * GenPolynomial test for co-prime list. * @param A list of GenPolynomials. * @return true if gcd(b,c) = 1 for all b != c in B, else false. */ public boolean isCoPrime(List> A); } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorAbstract.java000066400000000000000000001101611445075545500272530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms. * @author Heinz Kredel */ public abstract class GreatestCommonDivisorAbstract> implements GreatestCommonDivisor { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorAbstract.class); private static final boolean debug = logger.isDebugEnabled(); /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName(); } /** * GenPolynomial base coefficient content. * @param P GenPolynomial. * @return cont(P). */ public C baseContent(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } C d = null; for (C c : P.getMap().values()) { if (d == null) { d = c; } else { d = d.gcd(c); } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenPolynomial base coefficient primitive part. * @param P GenPolynomial. * @return pp(P). */ public GenPolynomial basePrimitivePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } C d = baseContent(P); if (d.isONE()) { return P; } GenPolynomial pp = P.divide(d); if (debug) { GenPolynomial p = pp.multiply(d); if (!p.equals(P)) { throw new ArithmeticException("pp(p)*cont(p) != p: "); } } return pp; } /** * List of GenPolynomial base coefficient primitive part. * @param F list of GenPolynomials. * @return pp(F). */ public List> basePrimitivePart(List> F) { if (F == null || F.isEmpty()) { return F; } List> Pp = new ArrayList>(F.size()); for (GenPolynomial f : F) { GenPolynomial p = basePrimitivePart(f); Pp.add(p); } return Pp; } /** * Univariate GenPolynomial greatest common divisor. Uses sparse * pseudoRemainder for remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ public abstract GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S); /** * GenPolynomial recursive content. * @param P recursive GenPolynomial. * @return cont(P). */ public GenPolynomial recursiveContent(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } GenPolynomial d = null; for (GenPolynomial c : P.getMap().values()) { if (d == null) { d = c; } else { d = gcd(d, c); // go to recursion } if (d.isONE()) { return d; } } return d.abs(); } /** * GenPolynomial recursive primitive part. * @param P recursive GenPolynomial. * @return pp(P). */ public GenPolynomial> recursivePrimitivePart(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomial d = recursiveContent(P); if (d.isONE()) { return P; } GenPolynomial> pp = PolyUtil. recursiveDivide(P, d); return pp; } /** * List of recursive GenPolynomial base coefficient primitive part. * @param F list of recursive GenPolynomials. * @return pp(F). */ public List>> recursivePrimitivePart( List>> F) { if (F == null || F.isEmpty()) { return F; } List>> Pp = new ArrayList>>(F.size()); for (GenPolynomial> f : F) { GenPolynomial> p = recursivePrimitivePart(f); Pp.add(p); } return Pp; } /** * GenPolynomial base recursive content. * @param P recursive GenPolynomial. * @return baseCont(P). */ public C baseRecursiveContent(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { GenPolynomialRing cf = (GenPolynomialRing) P.ring.coFac; return cf.coFac.getZERO(); } C d = null; for (GenPolynomial c : P.getMap().values()) { C cc = baseContent(c); if (d == null) { d = cc; } else { d = gcd(d, cc); } if (d.isONE()) { return d; } } if (d.signum() < 0) { d = d.negate(); } return d; } /** * GenPolynomial base recursive primitive part. * @param P recursive GenPolynomial. * @return basePP(P). */ public GenPolynomial> baseRecursivePrimitivePart(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } C d = baseRecursiveContent(P); if (d.isONE()) { return P; } GenPolynomial> pp = PolyUtil. baseRecursiveDivide(P, d); return pp; } /** * GenPolynomial recursive greatest common divisor. Uses pseudoRemainder for * remainder. * @param P recursive GenPolynomial. * @param S recursive GenPolynomial. * @return gcd(P,S). */ public GenPolynomial> recursiveGcd(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar <= 1) { return recursiveUnivariateGcd(P, S); } // distributed polynomials gcd GenPolynomialRing> rfac = P.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.nvar); GenPolynomial Pd = PolyUtil. distribute(dfac, P); GenPolynomial Sd = PolyUtil. distribute(dfac, S); GenPolynomial Dd = gcd(Pd, Sd); // convert to recursive GenPolynomial> C = PolyUtil. recursive(rfac, Dd); return C; } /** * Univariate GenPolynomial recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ public abstract GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S); /** * GenPolynomial content. * @param P GenPolynomial. * @return cont(P). */ public GenPolynomial content(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { // baseContent not possible by return type throw new IllegalArgumentException( this.getClass().getName() + " use baseContent for univariate polynomials"); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial D = recursiveContent(Pr); return D; } /** * GenPolynomial primitive part. * @param P GenPolynomial. * @return pp(P). */ public GenPolynomial primitivePart(GenPolynomial P) { return contentPrimitivePart(P)[1]; } /** * GenPolynomial content and primitive part. * @param P GenPolynomial. * @return { cont(P), pp(P) } */ @SuppressWarnings("unchecked") public GenPolynomial[] contentPrimitivePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomial[] ret = new GenPolynomial[2]; GenPolynomialRing pfac = P.ring; if (P.isZERO()) { ret[0] = pfac.getZERO(); ret[1] = pfac.getZERO(); return ret; } if (pfac.nvar <= 1) { C Pc = baseContent(P); GenPolynomial Pp = P; if (!Pc.isONE()) { Pp = P.divide(Pc); } ret[0] = pfac.valueOf(Pc); ret[1] = Pp; return ret; } GenPolynomialRing> rfac = pfac.recursive(1); //GenPolynomialRing cfac = rfac.coFac; GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial Pc = recursiveContent(Pr); // primitive part GenPolynomial> Pp = Pr; if (!Pc.isONE()) { Pp = PolyUtil. recursiveDivide(Pr, Pc); } GenPolynomial Ppd = PolyUtil. distribute(pfac, Pp); ret[0] = Pc; // sic! ret[1] = Ppd; return ret; } /** * GenPolynomial division. Indirection to GenPolynomial method. * @param a GenPolynomial. * @param b coefficient. * @return a/b. */ public GenPolynomial divide(GenPolynomial a, C b) { if (b == null || b.isZERO()) { throw new IllegalArgumentException("division by zero"); } if (a == null || a.isZERO()) { return a; } return a.divide(b); } /** * Coefficient greatest common divisor. Indirection to coefficient method. * @param a coefficient. * @param b coefficient. * @return gcd(a,b). */ public C gcd(C a, C b) { if (b == null || b.isZERO()) { return a; } if (a == null || a.isZERO()) { return b; } return a.gcd(b); } /** * GenPolynomial greatest common divisor. * @param P GenPolynomial. * @param S GenPolynomial. * @return gcd(P,S). */ public GenPolynomial gcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { GenPolynomial T = baseGcd(P, S); return T; } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial> Sr = PolyUtil. recursive(rfac, S); GenPolynomial> Dr = recursiveUnivariateGcd(Pr, Sr); GenPolynomial D = PolyUtil. distribute(pfac, Dr); return D; } /** * GenPolynomial least common multiple. * @param P GenPolynomial. * @param S GenPolynomial. * @return lcm(P,S). */ public GenPolynomial lcm(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } GenPolynomial C = gcd(P, S); GenPolynomial A = P.multiply(S); return PolyUtil. basePseudoDivide(A, C); } /** * List of GenPolynomials greatest common divisor. * @param A non empty list of GenPolynomials. * @return gcd(A_i). */ public GenPolynomial gcd(List> A) { if (A == null || A.isEmpty()) { throw new IllegalArgumentException("A may not be empty"); } GenPolynomial g = A.get(0); for (int i = 1; i < A.size(); i++) { GenPolynomial f = A.get(i); g = gcd(g, f); } return g; } /** * Univariate GenPolynomial resultant. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). * @throws UnsupportedOperationException if there is no implementation in * the sub-class. */ @SuppressWarnings("unused") public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) { throw new UnsupportedOperationException("not implemented"); } /** * Univariate GenPolynomial recursive resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). * @throws UnsupportedOperationException if there is no implementation in * the sub-class. */ @SuppressWarnings("unused") public GenPolynomial> recursiveUnivariateResultant(GenPolynomial> P, GenPolynomial> S) { throw new UnsupportedOperationException("not implemented"); } /** * GenPolynomial recursive resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). * @throws UnsupportedOperationException if there is no implementation in * the sub-class. */ public GenPolynomial> recursiveResultant(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } GenPolynomialRing> rfac = P.ring; GenPolynomialRing cfac = (GenPolynomialRing) rfac.coFac; GenPolynomialRing dfac = cfac.extend(rfac.getVars()); GenPolynomial Pp = PolyUtil. distribute(dfac, P); GenPolynomial Sp = PolyUtil. distribute(dfac, S); GenPolynomial res = resultant(Pp, Sp); GenPolynomial> Rr = PolyUtil. recursive(rfac, res); return Rr; } /** * GenPolynomial resultant. The input polynomials are considered as * univariate polynomials in the main variable. * @param P GenPolynomial. * @param S GenPolynomial. * @return res(P,S). * @see edu.jas.ufd.GreatestCommonDivisorSubres#recursiveResultant * @throws UnsupportedOperationException if there is no implementation in * the sub-class. */ public GenPolynomial resultant(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } // no more hacked: GreatestCommonDivisorSubres ufd_sr = new GreatestCommonDivisorSubres(); GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseResultant(P, S); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial> Sr = PolyUtil. recursive(rfac, S); GenPolynomial> Dr = recursiveUnivariateResultant(Pr, Sr); GenPolynomial D = PolyUtil. distribute(pfac, Dr); return D; } /** * GenPolynomial co-prime list. * @param A list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a. B does not contain zero or * constant polynomials. */ public List> coPrime(List> A) { if (A == null || A.isEmpty()) { return A; } List> B = new ArrayList>(A.size()); // make a coprime to rest of list GenPolynomial a = A.get(0); //System.out.println("a = " + a); if (!a.isZERO() && !a.isConstant()) { for (int i = 1; i < A.size(); i++) { GenPolynomial b = A.get(i); GenPolynomial g = gcd(a, b).abs(); if (!g.isONE()) { a = PolyUtil. basePseudoDivide(a, g); b = PolyUtil. basePseudoDivide(b, g); GenPolynomial gp = gcd(a, g).abs(); while (!gp.isONE()) { a = PolyUtil. basePseudoDivide(a, gp); g = PolyUtil. basePseudoDivide(g, gp); B.add(g); // gcd(a,g) == 1 g = gp; gp = gcd(a, gp).abs(); } if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 } } if (!b.isZERO() && !b.isConstant()) { B.add(b); // gcd(a,b) == 1 } } } else { B.addAll(A.subList(1, A.size())); } // make rest coprime B = coPrime(B); //System.out.println("B = " + B); if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { a = a.abs(); B.add(a); } return B; } /** * GenPolynomial co-prime list. * @param A list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a. B does not contain zero or * constant polynomials. */ public List> coPrimeRec(List> A) { if (A == null || A.isEmpty()) { return A; } List> B = new ArrayList>(); // make a co-prime to rest of list for (GenPolynomial a : A) { //System.out.println("a = " + a); B = coPrime(a, B); //System.out.println("B = " + B); } return B; } /** * GenPolynomial co-prime list. * @param a GenPolynomial. * @param P co-prime list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a * there exists b in P with b|a. B does not contain zero or constant * polynomials. */ public List> coPrime(GenPolynomial a, List> P) { if (a == null || a.isZERO() || a.isConstant()) { return P; } List> B = new ArrayList>(P.size() + 1); // make a coprime to elements of the list P for (int i = 0; i < P.size(); i++) { GenPolynomial b = P.get(i); GenPolynomial g = gcd(a, b).abs(); if (!g.isONE()) { a = PolyUtil. basePseudoDivide(a, g); b = PolyUtil. basePseudoDivide(b, g); // make g co-prime to new a, g is co-prime to c != b in P, B GenPolynomial gp = gcd(a, g).abs(); while (!gp.isONE()) { a = PolyUtil. basePseudoDivide(a, gp); g = PolyUtil. basePseudoDivide(g, gp); if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } g = gp; gp = gcd(a, gp).abs(); } // make new g co-prime to new b gp = gcd(b, g).abs(); while (!gp.isONE()) { b = PolyUtil. basePseudoDivide(b, gp); g = PolyUtil. basePseudoDivide(g, gp); if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } g = gp; gp = gcd(b, gp).abs(); } if (!g.isZERO() && !g.isConstant() /*&& !B.contains(g)*/) { B.add(g); // gcd(a,g) == 1 and gcd(g,c) == 1 for c != b in P, B } } if (!b.isZERO() && !b.isConstant() /*&& !B.contains(b)*/) { B.add(b); // gcd(a,b) == 1 and gcd(b,c) == 1 for c != b in P, B } } if (!a.isZERO() && !a.isConstant() /*&& !B.contains(a)*/) { B.add(a); } return B; } /** * GenPolynomial test for co-prime list. * @param A list of GenPolynomials. * @return true if gcd(b,c) = 1 for all b != c in B, else false. */ public boolean isCoPrime(List> A) { if (A == null || A.isEmpty()) { return true; } if (A.size() == 1) { return true; } for (int i = 0; i < A.size(); i++) { GenPolynomial a = A.get(i); for (int j = i + 1; j < A.size(); j++) { GenPolynomial b = A.get(j); GenPolynomial g = gcd(a, b); if (!g.isONE()) { System.out.println("not co-prime, a: " + a); System.out.println("not co-prime, b: " + b); System.out.println("not co-prime, g: " + g); return false; } } } return true; } /** * GenPolynomial test for co-prime list of given list. * @param A list of GenPolynomials. * @param P list of co-prime GenPolynomials. * @return true if isCoPrime(P) and for all a in A exists p in P with p | a, * else false. */ public boolean isCoPrime(List> P, List> A) { if (!isCoPrime(P)) { return false; } if (A == null || A.isEmpty()) { return true; } for (GenPolynomial q : A) { if (q.isZERO() || q.isConstant()) { continue; } boolean divides = false; for (GenPolynomial p : P) { GenPolynomial a = PolyUtil. baseSparsePseudoRemainder(q, p); if (a.isZERO()) { // p divides q divides = true; break; } } if (!divides) { System.out.println("no divisor for: " + q); return false; } } return true; } /** * Univariate GenPolynomial extended greatest common divisor. Uses sparse * pseudoRemainder for remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return [ gcd(P,S), a, b ] with a*P + b*S = gcd(P,S). */ @SuppressWarnings("unchecked") public GenPolynomial[] baseExtendedGcd(GenPolynomial P, GenPolynomial S) { //return P.egcd(S); GenPolynomial[] hegcd = baseHalfExtendedGcd(P, S); GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[3]; ret[0] = hegcd[0]; ret[1] = hegcd[1]; GenPolynomial x = hegcd[0].subtract(hegcd[1].multiply(P)); GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(x, S); // assert qr[1].isZERO() ret[2] = qr[0]; return ret; } /** * Univariate GenPolynomial half extended greatest common divisor. Uses * sparse pseudoRemainder for remainder. * @param S GenPolynomial. * @return [ gcd(P,S), a ] with a*P + b*S = gcd(P,S). */ @SuppressWarnings("unchecked") public GenPolynomial[] baseHalfExtendedGcd(GenPolynomial P, GenPolynomial S) { //if ( P == null ) { // throw new IllegalArgumentException("null P not allowed"); //} GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[2]; ret[0] = null; ret[1] = null; if (S == null || S.isZERO()) { ret[0] = P; ret[1] = P.ring.getONE(); return ret; } if (P == null || P.isZERO()) { ret[0] = S; ret[1] = S.ring.getZERO(); return ret; } if (P.ring.nvar != 1) { throw new IllegalArgumentException( this.getClass().getName() + " not univariate polynomials " + P.ring); } GenPolynomial q = P; GenPolynomial r = S; GenPolynomial c1 = P.ring.getONE().copy(); GenPolynomial d1 = P.ring.getZERO().copy(); while (!r.isZERO()) { GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(q, r); //q.divideAndRemainder(r); q = qr[0]; GenPolynomial x = c1.subtract(q.multiply(d1)); c1 = d1; d1 = x; q = r; r = qr[1]; } // normalize ldcf(q) to 1, i.e. make monic C g = q.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); q = q.multiply(h); c1 = c1.multiply(h); } //assert ( ((c1.multiply(P)).remainder(S).equals(q) )); ret[0] = q; ret[1] = c1; return ret; } /** * Univariate GenPolynomial greatest common divisor diophantine version. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @param c univariate GenPolynomial. * @return [ a, b ] with a*P + b*S = c and deg(a) < deg(S). */ @SuppressWarnings("unchecked") public GenPolynomial[] baseGcdDiophant(GenPolynomial P, GenPolynomial S, GenPolynomial c) { GenPolynomial[] egcd = baseExtendedGcd(P, S); GenPolynomial g = egcd[0]; GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(c, g); if (!qr[1].isZERO()) { throw new ArithmeticException("not solvable, r = " + qr[1] + ", c = " + c + ", g = " + g); } GenPolynomial q = qr[0]; GenPolynomial a = egcd[1].multiply(q); GenPolynomial b = egcd[2].multiply(q); if (!a.isZERO() && a.degree(0) >= S.degree(0)) { qr = PolyUtil. basePseudoQuotientRemainder(a, S); a = qr[1]; b = b.sum(P.multiply(qr[0])); } GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[2]; ret[0] = a; ret[1] = b; if (debug) { GenPolynomial y = ret[0].multiply(P).sum(ret[1].multiply(S)); if (!y.equals(c)) { System.out.println("P = " + P); System.out.println("S = " + S); System.out.println("c = " + c); System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("y = " + y); throw new ArithmeticException("not diophant, x = " + y.subtract(c)); } } return ret; } /** * Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return [ A0, Ap, As ] with A/(P*S) = A0 + Ap/P + As/S with deg(Ap) < * deg(P) and deg(As) < deg(S). */ @SuppressWarnings("unchecked") public GenPolynomial[] basePartialFraction(GenPolynomial A, GenPolynomial P, GenPolynomial S) { GenPolynomial[] ret = (GenPolynomial[]) new GenPolynomial[3]; ret[0] = null; ret[1] = null; ret[2] = null; GenPolynomial ps = P.multiply(S); GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, ps); ret[0] = qr[0]; GenPolynomial r = qr[1]; GenPolynomial[] diop = baseGcdDiophant(S, P, r); // switch arguments // GenPolynomial x = diop[0].multiply(S).sum( diop[1].multiply(P) ); // if ( !x.equals(r) ) { // System.out.println("r = " + r); // System.out.println("x = " + x); // throw new RuntimeException("not partial fraction, x = " + x); // } ret[1] = diop[0]; ret[2] = diop[1]; if (ret[1].degree(0) >= P.degree(0)) { qr = PolyUtil. basePseudoQuotientRemainder(ret[1], P); ret[0] = ret[0].sum(qr[0]); ret[1] = qr[1]; } if (ret[2].degree(0) >= S.degree(0)) { qr = PolyUtil. basePseudoQuotientRemainder(ret[2], S); ret[0] = ret[0].sum(qr[0]); ret[2] = qr[1]; } return ret; } /** * Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param P univariate GenPolynomial. * @param e exponent for P. * @return [ F0, F1, ..., Fe ] with A/(P^e) = sum( Fi / P^i ) with deg(Fi) < * deg(P). */ public List> basePartialFraction(GenPolynomial A, GenPolynomial P, int e) { if (A == null || P == null || e == 0) { throw new IllegalArgumentException("null A, P or e = 0 not allowed"); } List> pf = new ArrayList>(e); if (A.isZERO()) { for (int i = 0; i < e; i++) { pf.add(A); } return pf; } if (e == 1) { GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, P); pf.add(qr[0]); pf.add(qr[1]); return pf; } GenPolynomial a = A; for (int j = e; j > 0; j--) { GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(a, P); a = qr[0]; pf.add(0, qr[1]); } pf.add(0, a); return pf; } /** * Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param D list of co-prime univariate GenPolynomials. * @return [ A0, A1,..., An ] with A/prod(D) = A0 + sum( Ai/Di ) with * deg(Ai) < deg(Di). */ public List> basePartialFraction(GenPolynomial A, List> D) { if (D == null || A == null) { throw new IllegalArgumentException("null A or D not allowed"); } List> pf = new ArrayList>(D.size() + 1); if (A.isZERO() || D.size() == 0) { pf.add(A); for (int i = 0; i < D.size(); i++) { pf.add(A); } return pf; } List> Dp = new ArrayList>(D.size() - 1); GenPolynomial P = A.ring.getONE(); GenPolynomial d1 = null; for (GenPolynomial d : D) { if (d1 == null) { d1 = d; } else { P = P.multiply(d); Dp.add(d); } } GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(A, P.multiply(d1)); GenPolynomial A0 = qr[0]; GenPolynomial r = qr[1]; if (D.size() == 1) { pf.add(A0); pf.add(r); return pf; } GenPolynomial[] diop = baseGcdDiophant(P, d1, r); // switch arguments GenPolynomial A1 = diop[0]; GenPolynomial S = diop[1]; List> Fr = basePartialFraction(S, Dp); A0 = A0.sum(Fr.remove(0)); pf.add(A0); pf.add(A1); pf.addAll(Fr); return pf; } /** * Test for Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param D list of (co-prime) univariate GenPolynomials. * @param F list of univariate GenPolynomials from a partial fraction * computation. * @return true if A/prod(D) = F0 + sum( Fi/Di ) with deg(Fi) < deg(Di), Fi * in F, else false. */ public boolean isBasePartialFraction(GenPolynomial A, List> D, List> F) { if (D == null || A == null || F == null) { throw new IllegalArgumentException("null A, F or D not allowed"); } if (D.size() != F.size() - 1) { return false; } // A0*prod(D) + sum( Ai * Dip ), Dip = prod(D,j!=i) GenPolynomial P = A.ring.getONE(); for (GenPolynomial d : D) { P = P.multiply(d); } List> Fp = new ArrayList>(F); GenPolynomial A0 = Fp.remove(0).multiply(P); //System.out.println("A0 = " + A0); int j = 0; for (GenPolynomial Fi : Fp) { P = A.ring.getONE(); int i = 0; for (GenPolynomial d : D) { if (i != j) { P = P.multiply(d); } i++; } //System.out.println("Fi = " + Fi); //System.out.println("P = " + P); A0 = A0.sum(Fi.multiply(P)); //System.out.println("A0 = " + A0); j++; } boolean t = A.equals(A0); if (!t) { System.out.println("not isPartFrac = " + A0); } return t; } /** * Test for Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param P univariate GenPolynomial. * @param e exponent for P. * @param F list of univariate GenPolynomials from a partial fraction * computation. * @return true if A/(P^e) = F0 + sum( Fi / P^i ) with deg(Fi) < deg(P), Fi * in F, else false. */ public boolean isBasePartialFraction(GenPolynomial A, GenPolynomial P, int e, List> F) { if (A == null || P == null || F == null || e == 0) { throw new IllegalArgumentException("null A, P, F or e = 0 not allowed"); } GenPolynomial A0 = basePartialFractionValue(P, e, F); boolean t = A.equals(A0); if (!t) { System.out.println("not isPartFrac = " + A0); } return t; } /** * Test for Univariate GenPolynomial partial fraction decomposition. * @param P univariate GenPolynomial. * @param e exponent for P. * @param F list of univariate GenPolynomials from a partial fraction * computation. * @return (F0 + sum( Fi / P^i )) * P^e. */ public GenPolynomial basePartialFractionValue(GenPolynomial P, int e, List> F) { if (P == null || F == null || e == 0) { throw new IllegalArgumentException("null P, F or e = 0 not allowed"); } GenPolynomial A0 = P.ring.getZERO(); for (GenPolynomial Fi : F) { A0 = A0.multiply(P); A0 = A0.sum(Fi); } return A0; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorFake.java000066400000000000000000000103551445075545500263620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Greatest common divisor algorithms with gcd always 1. The computation is * faked as the gcd is always 1. * @author Heinz Kredel */ public class GreatestCommonDivisorFake> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorFake.class); //private static final boolean debug = logger.isDebugEnabled(); /** * GenPolynomial base coefficient content. Always returns 1. * @param P GenPolynomial. * @return cont(P). */ @Override public C baseContent(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } return P.ring.getONECoefficient(); } /** * GenPolynomial base coefficient primitive part. Always returns P. * @param P GenPolynomial. * @return pp(P). */ @Override public GenPolynomial basePrimitivePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } if (P.isConstant()) { return P.ring.getONE(); } if (P.length() == 1) { // one term //System.out.println("P = " + P); return P.ring.valueOf(P.leadingExpVector()); } return P; } /** * Univariate GenPolynomial greatest common divisor. Always returns 1. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } return P.ring.getONE(); } /** * GenPolynomial recursive content. Always returns 1. * @param P recursive GenPolynomial. * @return cont(P). */ @Override public GenPolynomial recursiveContent(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P.ring.getZEROCoefficient(); } return P.ring.getONECoefficient(); } /** * GenPolynomial recursive primitive part. Always returns P. * @param P recursive GenPolynomial. * @return pp(P). */ @Override public GenPolynomial> recursivePrimitivePart(GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } if (P.isConstant()) { return P.ring.getONE(); } if (P.length() == 1) { // one term //System.out.println("P = " + P); return P.ring.valueOf(P.leadingExpVector()); } return P; } /** * Univariate GenPolynomial recursive greatest common divisor. Always returns * 1. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } logger.debug("returning 1"); return P.ring.getONE(); } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorHensel.java000066400000000000000000000722531445075545500267370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.arith.PrimeList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.Power; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms with subresultant polynomial remainder * sequence and univariate Hensel lifting. * @author Heinz Kredel */ public class GreatestCommonDivisorHensel & Modular> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorHensel.class); private static final boolean debug = logger.isDebugEnabled(); /** * Flag for linear or quadratic Hensel lift. */ public final boolean quadratic; /** * Fall back gcd algorithm. */ public final GreatestCommonDivisorAbstract iufd; /* * Internal dispatcher. */ private final GreatestCommonDivisorAbstract ufd; /** * Constructor. */ public GreatestCommonDivisorHensel() { this(true); } /** * Constructor. * @param quadratic use quadratic Hensel lift. */ public GreatestCommonDivisorHensel(boolean quadratic) { this.quadratic = quadratic; iufd = new GreatestCommonDivisorSubres(); ufd = this; //iufd; } /** * Univariate GenPolynomial greatest common divisor. Uses univariate Hensel * lifting. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override @SuppressWarnings("unchecked") public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } GenPolynomialRing fac = P.ring; long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); // compute contents and primitive parts BigInteger a = baseContent(r); BigInteger b = baseContent(q); // gcd of coefficient contents BigInteger c = gcd(a, b); // indirection r = divide(r, a); // indirection q = divide(q, b); // indirection if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } // compute normalization factor BigInteger ac = r.leadingBaseCoefficient(); BigInteger bc = q.leadingBaseCoefficient(); BigInteger cc = gcd(ac, bc); // indirection // compute degree vectors, only univeriate ExpVector rdegv = r.degreeVector(); ExpVector qdegv = q.degreeVector(); //initialize prime list and degree vector PrimeList primes = new PrimeList(PrimeList.Range.medium); int pn = 50; //primes.size(); ModularRingFactory cofac; GenPolynomial qm; GenPolynomial qmf; GenPolynomial rm; GenPolynomial rmf; GenPolynomial cmf; GenPolynomialRing mfac; GenPolynomial cm = null; GenPolynomial[] ecm = null; GenPolynomial sm = null; GenPolynomial tm = null; HenselApprox lift = null; if (debug) { logger.debug("c = {}", c); logger.debug("cc = {}", cc); logger.debug("primes = {}", primes); } int i = 0; for (java.math.BigInteger p : primes) { //System.out.println("next run ++++++++++++++++++++++++++++++++++"); if (++i >= pn) { logger.error("prime list exhausted, pn = {}", pn); //logger.info("primes = {}", primes); return iufd.baseGcd(P, S); //throw new ArithmeticException("prime list exhausted"); } // initialize coefficient factory and map normalization factor //cofac = new ModIntegerRing(p, true); if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cofac = (ModularRingFactory) new ModLongRing(p, true); } else { cofac = (ModularRingFactory) new ModIntegerRing(p, true); } MOD nf = cofac.fromInteger(cc.getVal()); if (nf.isZERO()) { continue; } nf = cofac.fromInteger(q.leadingBaseCoefficient().getVal()); if (nf.isZERO()) { continue; } nf = cofac.fromInteger(r.leadingBaseCoefficient().getVal()); if (nf.isZERO()) { continue; } // initialize polynomial factory and map polynomials mfac = new GenPolynomialRing(cofac, fac.nvar, fac.tord, fac.getVars()); qm = PolyUtil. fromIntegerCoefficients(mfac, q); if (!qm.degreeVector().equals(qdegv)) { continue; } rm = PolyUtil. fromIntegerCoefficients(mfac, r); if (!rm.degreeVector().equals(rdegv)) { continue; } if (debug) { logger.info("cofac = {}", cofac.getIntegerModul()); } // compute univariate modular gcd cm = qm.gcd(rm); // test for constant g.c.d if (cm.isConstant()) { logger.debug("cm, constant = {}", cm); return fac.getONE().multiply(c); } // compute factors and gcd with factor GenPolynomial crq; rmf = rm.divide(cm); // rm = cm * rmf ecm = cm.egcd(rmf); if (ecm[0].isONE()) { //logger.debug("gcd() first factor {}", rmf); crq = r; cmf = rmf; sm = ecm[1]; tm = ecm[2]; } else { qmf = qm.divide(cm); // qm = cm * qmf ecm = cm.egcd(qmf); if (ecm[0].isONE()) { //logger.debug("gcd() second factor {}", qmf); crq = q; cmf = qmf; sm = ecm[1]; tm = ecm[2]; } else { logger.info("both gcd != 1: Hensel not applicable"); return iufd.baseGcd(P, S); } } BigInteger cn = crq.maxNorm(); cn = cn.multiply(crq.leadingBaseCoefficient().abs()); cn = cn.multiply(cn.fromInteger(2)); if (debug) { System.out.println("crq = " + crq); System.out.println("cm = " + cm); System.out.println("cmf = " + cmf); System.out.println("sm = " + sm); System.out.println("tm = " + tm); System.out.println("cn = " + cn); } try { if (quadratic) { lift = HenselUtil.liftHenselQuadratic(crq, cn, cm, cmf, sm, tm); } else { lift = HenselUtil.liftHensel(crq, cn, cm, cmf, sm, tm); } } catch (NoLiftingException nle) { logger.info("giving up on Hensel gcd reverting to Subres gcd {}", nle); return iufd.baseGcd(P, S); } q = lift.A; if (debug) { System.out.println("q = " + q); System.out.println("qf = " + lift.B); } q = basePrimitivePart(q); q = q.multiply(c).abs(); if (PolyUtil. baseSparsePseudoRemainder(P, q).isZERO() && PolyUtil. baseSparsePseudoRemainder(S, q).isZERO()) { break; } logger.info("final division not successful"); //System.out.println("P rem q = " + PolyUtil.baseSparsePseudoRemainder(P,q)); //System.out.println("S rem q = " + PolyUtil.baseSparsePseudoRemainder(S,q)); //break; } return q; } /** * Univariate GenPolynomial recursive greatest common divisor. Uses * multivariate Hensel list. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override @SuppressWarnings("unchecked") public GenPolynomial> recursiveUnivariateGcd( GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial> q, r; //, s; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); //logger.info("r: {}, q: {}", r, q); GenPolynomial a = ufd.recursiveContent(r); GenPolynomial b = ufd.recursiveContent(q); GenPolynomial c = ufd.gcd(a, b); // go to recursion //System.out.println("rgcd c = " + c); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); //a = PolyUtil. basePseudoDivide(a, c); // unused ? //b = PolyUtil. basePseudoDivide(b, c); // unused ? if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } // check constant ldcf, TODO general case GenPolynomial la, lb, lc, lh; la = r.leadingBaseCoefficient(); lb = q.leadingBaseCoefficient(); lc = ufd.gcd(la, lb); //logger.info("la = {}, lb = {}, lc = {}", la, lb, lc); if (!lc.isConstant()) { //continue; // easy way out GenPolynomial> T = iufd.recursiveUnivariateGcd(r, q); T = T.abs().multiply(c); logger.info("non monic ldcf ({}) not implemented: {} = gcd({},{}) * {}", lc, T, r, q, c); return T; } // convert from Z[y1,...,yr][x] to Z[x][y1,...,yr] to Z[x,y1,...,yr] GenPolynomial> qs = PolyUtil. switchVariables(q); GenPolynomial> rs = PolyUtil. switchVariables(r); GenPolynomialRing> rfac = qs.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.getVars()); //System.out.println("pfac = " + P.ring.toScript()); //System.out.println("rfac = " + rfac.toScript()); //System.out.println("dfac = " + dfac.toScript()); GenPolynomial qd = PolyUtil. distribute(dfac, qs); GenPolynomial rd = PolyUtil. distribute(dfac, rs); // compute normalization factor BigInteger ac = rd.leadingBaseCoefficient(); BigInteger bc = qd.leadingBaseCoefficient(); BigInteger cc = gcd(ac, bc); // indirection //initialize prime list PrimeList primes = new PrimeList(PrimeList.Range.medium); Iterator primeIter = primes.iterator(); int pn = 50; //primes.size(); // double check variables // need qe,re,qd,rd,a,b GenPolynomial ce0 = null; // qe0, re0, for (int i = 0; i < 11; i++) { // meta loop //System.out.println("======== run " + dfac.nvar + ", " + i); java.math.BigInteger p = null; //new java.math.BigInteger("19"); //primes.next(); // 5 small, 4 medium and 2 large size primes if (i == 0) { // medium size primes = new PrimeList(PrimeList.Range.medium); primeIter = primes.iterator(); } if (i == 4) { // small size primes = new PrimeList(PrimeList.Range.small); primeIter = primes.iterator(); p = primeIter.next(); // 2 p = primeIter.next(); // 3 p = primeIter.next(); // 5 p = primeIter.next(); // 7 } if (i == 9) { // large size primes = new PrimeList(PrimeList.Range.large); primeIter = primes.iterator(); } ModularRingFactory cofac = null; int pi = 0; while (pi++ < pn && primeIter.hasNext()) { p = primeIter.next(); //p = new java.math.BigInteger("19"); logger.info("prime = {}", p); // initialize coefficient factory and map normalization factor and polynomials ModularRingFactory cf = null; if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cf = (ModularRingFactory) new ModLongRing(p, true); } else { cf = (ModularRingFactory) new ModIntegerRing(p, true); } MOD nf = cf.fromInteger(cc.getVal()); if (nf.isZERO()) { continue; } nf = cf.fromInteger(q.leadingBaseCoefficient().leadingBaseCoefficient().getVal()); if (nf.isZERO()) { continue; } nf = cf.fromInteger(r.leadingBaseCoefficient().leadingBaseCoefficient().getVal()); if (nf.isZERO()) { continue; } cofac = cf; break; } if (cofac == null) { // no lucky prime found GenPolynomial> T = iufd.recursiveUnivariateGcd(q, r); logger.info("no lucky prime, gave up on Hensel: {}= gcd({},{})", T, r, q); return T.abs().multiply(c); //.abs(); } //System.out.println("cofac = " + cofac); // search evaluation points and evaluate List V = new ArrayList(P.ring.nvar); GenPolynomialRing ckfac = dfac; GenPolynomial qe = qd; GenPolynomial re = rd; GenPolynomial qei; GenPolynomial rei; for (int j = dfac.nvar; j > 1; j--) { // evaluation to univariate case long degq = qe.degree(ckfac.nvar - 2); long degr = re.degree(ckfac.nvar - 2); ckfac = ckfac.contract(1); long vi = 1L; //(long)(dfac.nvar-j); // 1L; 0 not so good for small p if (p.longValueExact() > 1000L) { //vi = (long)j+1L; vi = 0L; } // search small evaluation point while (true) { MOD vp = cofac.fromInteger(vi++); //System.out.println("vp = " + vp); if (vp.isZERO() && vi != 1L) { // all elements of Z_p exhausted qe = null; re = null; break; } BigInteger vii = new BigInteger(vi - 1); qei = PolyUtil. evaluateMain(ckfac, qe, vii); rei = PolyUtil. evaluateMain(ckfac, re, vii); //System.out.println("qei = " + qei); //System.out.println("rei = " + rei); // check lucky evaluation point if (degq != qei.degree(ckfac.nvar - 1)) { //System.out.println("degv(qe) = " + qe.degreeVector()); //System.out.println("deg(qe) = " + degq + ", deg(qe) = " + qei.degree(ckfac.nvar-1)); continue; } if (degr != rei.degree(ckfac.nvar - 1)) { //System.out.println("degv(re) = " + re.degreeVector()); //System.out.println("deg(re) = " + degr + ", deg(re) = " + rei.degree(ckfac.nvar-1)); continue; } V.add(vii); qe = qei; re = rei; break; } if (qe == null && re == null) { break; } } if (qe == null && re == null) { continue; } logger.info("evaluation points = {}", V); // recursion base: GenPolynomial ce = ufd.baseGcd(qe, re); if (ce.isConstant()) { return P.ring.getONE().multiply(c); } logger.info("base gcd = {}", ce); // double check // need qe,re,qd,rd,a,b if (i == 0) { //qe0 = qe; //re0 = re; ce0 = ce; continue; } long d0 = ce0.degree(0); long d1 = ce.degree(0); //System.out.println("d0, d1 = " + d0 + ", " + d1); if (d1 < d0) { //qe0 = qe; //re0 = re; ce0 = ce; continue; } else if (d1 > d0) { continue; } // d0 == d1 is ok long dx = r.degree(0); //System.out.println("d0, dx = " + d0 + ", " + dx); if (d0 == dx) { // gcd == r ? if (PolyUtil. recursiveSparsePseudoRemainder(q, r).isZERO()) { r = r.abs().multiply(c); //.abs(); logger.info("exit with r | q : {}", r); return r; } continue; } // norm BigInteger mn = null; //mn = mn.multiply(cc).multiply(mn.fromInteger(2)); // prepare lifting, chose factor polynomials GenPolynomial re1 = PolyUtil. basePseudoDivide(re, ce); GenPolynomial qe1 = PolyUtil. basePseudoDivide(qe, ce); GenPolynomial ui, he; //, pe; GenPolynomial g, gi, lui; GenPolynomial gcr, gcq; gcr = ufd.baseGcd(re1, ce); gcq = ufd.baseGcd(qe1, ce); if (gcr.isONE() && gcq.isONE()) { // both gcds == 1: chose smaller ldcf if (la.totalDegree() > lb.totalDegree()) { ui = qd; //s = q; he = qe1; //pe = qe; BigInteger bn = qd.maxNorm(); mn = bn.multiply(cc).multiply(new BigInteger(2L)); g = lb; logger.debug("select deg: ui = qd, g = b"); //, qe1 = {}", qe1); // + ", qe = {}", qe); } else { ui = rd; //s = r; he = re1; //pe = re; BigInteger an = rd.maxNorm(); mn = an.multiply(cc).multiply(new BigInteger(2L)); g = la; logger.debug("select deg: ui = rd, g = a"); //, re1 = {}", re1); // + ", re = {}", re); } } else if (gcr.isONE()) { ui = rd; //s = r; he = re1; //pe = re; BigInteger an = rd.maxNorm(); mn = an.multiply(cc).multiply(new BigInteger(2L)); g = la; logger.debug("select: ui = rd, g = a"); //, re1 = {}", re1); // + ", re = {}", re); } else if (gcq.isONE()) { ui = qd; //s = q; he = qe1; //pe = qe; BigInteger bn = qd.maxNorm(); mn = bn.multiply(cc).multiply(new BigInteger(2L)); g = lb; logger.debug("select: ui = qd, g = b"); //, qe1 = {}", qe1); // + ", qe = {}", qe); } else { // both gcds != 1: method not applicable logger.info("both gcds != 1: method not applicable"); break; } lui = lc; //s.leadingBaseCoefficient(); lh = PolyUtil. basePseudoDivide(g, lui); BigInteger ge = PolyUtil. evaluateAll(g.ring.coFac, lui, V); if (ge.isZERO()) { continue; } BigInteger geh = PolyUtil. evaluateAll(g.ring.coFac, lh, V); if (geh.isZERO()) { continue; } BigInteger gg = PolyUtil. evaluateAll(g.ring.coFac, g, V); if (gg.isZERO()) { continue; } //System.out.println("ge = " + ge + ", geh = " + geh + ", gg = " + gg + ", pe = " + pe); // //ce = ce.multiply(geh); //ge); // he = he.multiply(ge); //gg); //ge); //geh); // gi = lui.extendLower(dfac, 0, 0L); //lui. // g. // ui = ui.multiply(gi); // gi !.multiply(gi) //System.out.println("ui = " + ui + ", deg(ui) = " + ui.degreeVector()); //System.out.println("ce = " + ce + ", he = " + he + ", ge = " + ge); logger.info("gcd(ldcf): {}, ldcf cofactor: {}, base cofactor: {}", lui, lh, he); long k = Power.logarithm(new BigInteger(p), mn); //System.out.println("mn = " + mn); //System.out.println("k = " + k); BigInteger qp = cofac.getIntegerModul().power(k); ModularRingFactory muqfac; if (ModLongRing.MAX_LONG.compareTo(qp.getVal()) > 0) { muqfac = (ModularRingFactory) new ModLongRing(qp.getVal(), true); // nearly a field } else { muqfac = (ModularRingFactory) new ModIntegerRing(qp.getVal(), true); // nearly a field } GenPolynomialRing mucpfac = new GenPolynomialRing(muqfac, ckfac); //System.out.println("mucpfac = " + mucpfac.toScript()); if (muqfac.fromInteger(ge.getVal()).isZERO()) { continue; } //GenPolynomial xxx = invertPoly(muqfac,lui,V); //System.out.println("inv(lui) = " + xxx + ", muqfac = " + muqfac + ", lui = " + lui); //ce = ce.multiply(xxx); //.leadingBaseCoefficient()); //xxx = invertPoly(muqfac,lh,V); //System.out.println("inv(lh) = " + xxx + ", muqfac = " + muqfac + ", lh = " + lh); //he = he.multiply(xxx); //.leadingBaseCoefficient()); GenPolynomial cm = PolyUtil. fromIntegerCoefficients(mucpfac, ce); GenPolynomial hm = PolyUtil. fromIntegerCoefficients(mucpfac, he); if (cm.degree(0) != ce.degree(0) || hm.degree(0) != he.degree(0)) { continue; } if (cm.isZERO() || hm.isZERO()) { continue; } logger.info("univariate modulo p^k: {}, {}", cm, hm); // convert C from Z[...] to Z_q[...] GenPolynomialRing qcfac = new GenPolynomialRing(muqfac, dfac); GenPolynomial uq = PolyUtil. fromIntegerCoefficients(qcfac, ui); if (!ui.leadingExpVector().equals(uq.leadingExpVector())) { logger.info("ev(ui) = {}, ev(uq) = {}", ui.leadingExpVector(), uq.leadingExpVector()); continue; } logger.info("multivariate modulo p^k: {}", uq); List> F = new ArrayList>(2); F.add(cm); F.add(hm); List> G = new ArrayList>(2); G.add(lui.ring.getONE()); //lui: lui.ring.getONE()); // TODO G.add(lui.ring.getONE()); //lh: lui); List> lift; try { //lift = HenselMultUtil. liftHenselFull(ui, F, V, k, G); lift = HenselMultUtil. liftHensel(ui, uq, F, V, k, G); logger.info("lift = {}", lift); } catch (NoLiftingException nle) { logger.info("NoLiftingException"); //System.out.println("exception : " + nle); continue; } catch (ArithmeticException ae) { logger.info("ArithmeticException"); //System.out.println("exception : " + ae); continue; } catch (NotInvertibleException ni) { logger.info("NotInvertibleException"); //System.out.println("exception : " + ni); continue; } //if (!HenselMultUtil. isHenselLift(ui, uq, F, k, lift)) { // not meaningful test // logger.info("isHenselLift: false"); // //continue; //} // convert Ci from Z_{p^k}[x,y1,...,yr] to Z[x,y1,...,yr] to Z[x][y1,...,yr] to Z[y1,...,yr][x] GenPolynomial ci = PolyUtil.integerFromModularCoefficients(dfac, lift.get(0)); ci = basePrimitivePart(ci); GenPolynomial> Cr = PolyUtil. recursive(rfac, ci); GenPolynomial> Cs = PolyUtil. switchVariables(Cr); if (!Cs.ring.equals(P.ring)) { System.out.println("Cs.ring = " + Cs.ring + ", P.ring = " + P.ring); } GenPolynomial> Q = ufd.recursivePrimitivePart(Cs); Q = ufd.baseRecursivePrimitivePart(Q); Q = Q.abs().multiply(c); //.abs(); GenPolynomial> Pq, Sq; Pq = PolyUtil. recursiveSparsePseudoRemainder(P, Q); Sq = PolyUtil. recursiveSparsePseudoRemainder(S, Q); if (Pq.isZERO() && Sq.isZERO()) { logger.info("gcd normal exit: {}", Q); return Q; } logger.info("bad Q = {}", Q); // + ", Pq = {}", Pq + ", Sq = {}", Sq); } // end for meta loop // Hensel gcd failed GenPolynomial> T = iufd.recursiveUnivariateGcd(r, q); T = T.abs().multiply(c); logger.info("no lucky prime or evaluation points, gave up on Hensel: {} = gcd({},{})", T, r, q); return T; } /* move to Ideal ? GenPolynomial invertPoly(ModularRingFactory mfac, GenPolynomial li, List V) { if (li == null || li.isZERO()) { throw new RuntimeException("li not invertible: " + li); } if (li.isONE()) { return li; } //System.out.println("mfac = " + mfac + ", V = " + V +", li = " + li); GenPolynomialRing pfac = li.ring; GenPolynomialRing mpfac = new GenPolynomialRing(mfac, pfac); GenPolynomial lm = PolyUtil. fromIntegerCoefficients(mpfac, li); //System.out.println("pfac = " + pfac + ", lm = " + lm); List> lid = new ArrayList>(V.size()); int i = 0; for (BigInteger bi : V) { MOD m = mfac.fromInteger(bi.getVal()); GenPolynomial mp = mpfac.univariate(i); mp = mp.subtract(m); // X_i - v_i lid.add(mp); i++; } //System.out.println("lid = " + lid); //Ideal id = new Ideal(mpfac,lid,true); // is a GB //System.out.println("id = " + id); GenPolynomial mi = lm; //id.inverse(lm); //System.out.println("mi = " + mi); GenPolynomial inv = PolyUtil.integerFromModularCoefficients(pfac, mi); return inv; } */ } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorModEval.java000066400000000000000000000441721445075545500270470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms with modular evaluation algorithm for * recursion. * @author Heinz Kredel */ public class GreatestCommonDivisorModEval & Modular> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorModEval.class); private static final boolean debug = logger.isDebugEnabled(); /** * Modular gcd algorithm to use. */ protected final GreatestCommonDivisorAbstract mufd = new GreatestCommonDivisorSimple(); // not okay = new GreatestCommonDivisorPrimitive(); // not okay = new GreatestCommonDivisorSubres(); /** * Univariate GenPolynomial greatest common divisor. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { // required as recursion base return mufd.baseGcd(P, S); } /** * Recursive univariate GenPolynomial greatest common divisor. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S) { //return mufd.recursiveUnivariateGcd(P, S); // distributed polynomials gcd GenPolynomialRing> rfac = P.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.nvar); GenPolynomial Pd = PolyUtil. distribute(dfac, P); GenPolynomial Sd = PolyUtil. distribute(dfac, S); GenPolynomial Dd = gcd(Pd, Sd); // convert to recursive GenPolynomial> C = PolyUtil. recursive(rfac, Dd); return C; } /** * GenPolynomial greatest common divisor, modular evaluation algorithm. * @param P GenPolynomial. * @param S GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial gcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } GenPolynomialRing fac = P.ring; // recursion base case for univariate polynomials if (fac.nvar <= 1) { GenPolynomial T = baseGcd(P, S); return T; } long e = P.degree(fac.nvar - 1); long f = S.degree(fac.nvar - 1); if (e == 0 && f == 0) { GenPolynomialRing> rfac = fac.recursive(1); GenPolynomial Pc = PolyUtil. recursive(rfac, P).leadingBaseCoefficient(); GenPolynomial Sc = PolyUtil. recursive(rfac, S).leadingBaseCoefficient(); GenPolynomial r = gcd(Pc, Sc); return r.extend(fac, 0, 0L); } GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); // setup factories ModularRingFactory cofac = (ModularRingFactory) P.ring.coFac; if (!cofac.isField()) { logger.warn("cofac is not a field: {}", cofac); } GenPolynomialRing> rfac = fac.recursive(fac.nvar - 1); GenPolynomialRing mfac = new GenPolynomialRing(cofac, rfac); GenPolynomialRing ufac = (GenPolynomialRing) rfac.coFac; // convert polynomials GenPolynomial> qr; GenPolynomial> rr; qr = PolyUtil. recursive(rfac, q); rr = PolyUtil. recursive(rfac, r); // compute univariate contents and primitive parts GenPolynomial a = recursiveContent(rr); GenPolynomial b = recursiveContent(qr); // gcd of univariate coefficient contents GenPolynomial c = gcd(a, b); rr = PolyUtil. recursiveDivide(rr, a); qr = PolyUtil. recursiveDivide(qr, b); if (rr.isONE()) { rr = rr.multiply(c); r = PolyUtil. distribute(fac, rr); return r; } if (qr.isONE()) { qr = qr.multiply(c); q = PolyUtil. distribute(fac, qr); return q; } // compute normalization factor GenPolynomial ac = rr.leadingBaseCoefficient(); GenPolynomial bc = qr.leadingBaseCoefficient(); GenPolynomial cc = gcd(ac, bc); // compute degrees and degree vectors ExpVector rdegv = rr.degreeVector(); ExpVector qdegv = qr.degreeVector(); long rd0 = PolyUtil. coeffMaxDegree(rr); long qd0 = PolyUtil. coeffMaxDegree(qr); long cd0 = cc.degree(0); long G = (rd0 < qd0 ? rd0 : qd0) + cd0 + 1L; // >= //long Gm = (e < f ? e : f); // initialize element and degree vector ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); // +1 seems to be a hack for the unlucky evaluation point test MOD inc = cofac.getONE(); long i = 0; long en = cofac.getIntegerModul().longValueExact() - 1; // just a stopper MOD end = cofac.fromInteger(en); MOD mi; GenPolynomial M = null; GenPolynomial mn; GenPolynomial qm; GenPolynomial rm; GenPolynomial cm; GenPolynomial> cp = null; if (debug) { logger.debug("c = {}", c); logger.debug("cc = {}", cc); logger.debug("G = {}", G); logger.info("wdegv = {}", wdegv + ", in {}", rfac.toScript()); } for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { if (++i >= en) { logger.warn("elements of Z_p exhausted, en = {}", en); return mufd.gcd(P, S); //throw new ArithmeticException("elements of Z_p exhausted, en = " + en); } // map normalization factor MOD nf = PolyUtil. evaluateMain(cofac, cc, d); if (nf.isZERO()) { continue; } // map polynomials qm = PolyUtil. evaluateFirstRec(ufac, mfac, qr, d); if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { continue; } rm = PolyUtil. evaluateFirstRec(ufac, mfac, rr, d); if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { continue; } if (debug) { logger.debug("eval d = {}", d); } // compute modular gcd in recursion cm = gcd(rm, qm); if (debug) { logger.debug("cm = {}, rm = {}, qm = {}", cm, rm, qm); //cm = mufd.gcd(rm,qm); //logger.debug("cm = {}, rm = {}, qm = {}", cm, rm, qm); } // test for constant g.c.d if (cm.isConstant()) { logger.debug("cm.isConstant = {}, c = {}", cm, c); if (c.ring.nvar < cm.ring.nvar) { c = c.extend(mfac, 0, 0); } cm = cm.abs().multiply(c); q = cm.extend(fac, 0, 0); //logger.debug("q = {}, c = {}", q, c); return q; } // test for unlucky evaluation point ExpVector mdegv = cm.degreeVector(); if (wdegv.equals(mdegv)) { // TL = 0 // evaluation point ok, next round if (M != null) { if (M.degree(0) > G) { logger.info("deg(M) > G: {} > {}", M.degree(0), G); // continue; // why should this be required? } } } else { // TL = 3 boolean ok = false; if (wdegv.multipleOf(mdegv)) { // TL = 2 M = null; // init chinese remainder ok = true; // evaluation point ok } if (mdegv.multipleOf(wdegv)) { // TL = 1 continue; // skip this evaluation point } if (!ok) { M = null; // discard chinese remainder and previous work continue; // evaluation point not ok } } // prepare interpolation algorithm cm = cm.multiply(nf); if (M == null) { // initialize interpolation M = ufac.getONE(); cp = rfac.getZERO(); wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); } // interpolate mi = PolyUtil. evaluateMain(cofac, M, d); mi = mi.inverse(); // mod p cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); if (debug) { logger.debug("cp = {}, cm = {} :: {}", cp, cm, M); } mn = ufac.getONE().multiply(d); mn = ufac.univariate(0).subtract(mn); M = M.multiply(mn); // M * (x-d) // test for divisibility boolean tt = false; if (cp.leadingBaseCoefficient().equals(cc)) { cp = recursivePrimitivePart(cp).abs(); logger.debug("test cp == cc: {} == {}", cp, cc); tt = PolyUtil. recursiveSparsePseudoRemainder(qr, cp).isZERO(); tt = tt && PolyUtil. recursiveSparsePseudoRemainder(rr, cp).isZERO(); if (tt) { logger.debug("break: is gcd"); break; } if (M.degree(0) > G) { // no && cp.degree(0) > Gm logger.debug("break: fail 1, cp = {}", cp); cp = rfac.getONE(); break; } } // test for completion if (M.degree(0) > G) { // no && cp.degree(0) > Gm logger.debug("break: M = {}, G = {}, mn = {}, M.deg(0) = {}", M, G, mn, M.degree(0)); cp = recursivePrimitivePart(cp).abs(); tt = PolyUtil. recursiveSparsePseudoRemainder(qr, cp).isZERO(); tt = tt && PolyUtil. recursiveSparsePseudoRemainder(rr, cp).isZERO(); if (!tt) { logger.debug("break: fail 2, cp = {}", cp); cp = rfac.getONE(); } break; } //long cmn = PolyUtil.coeffMaxDegree(cp); //if ( M.degree(0) > cmn ) { // does not work: only if cofactors are also considered? // break; //} } // remove normalization cp = recursivePrimitivePart(cp).abs(); cp = cp.multiply(c); q = PolyUtil. distribute(fac, cp); return q; } /** * Univariate GenPolynomial resultant. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) { // required as recursion base return mufd.baseResultant(P, S); } /** * Univariate GenPolynomial recursive resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial> recursiveUnivariateResultant(GenPolynomial> P, GenPolynomial> S) { // only in this class return recursiveResultant(P, S); } /** * GenPolynomial resultant, modular evaluation algorithm. * @param P GenPolynomial. * @param S GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial resultant(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } GenPolynomialRing fac = P.ring; // recursion base case for univariate polynomials if (fac.nvar <= 1) { GenPolynomial T = baseResultant(P, S); return T; } long e = P.degree(fac.nvar - 1); long f = S.degree(fac.nvar - 1); if (e == 0 && f == 0) { GenPolynomialRing> rfac = fac.recursive(1); GenPolynomial Pc = PolyUtil. recursive(rfac, P).leadingBaseCoefficient(); GenPolynomial Sc = PolyUtil. recursive(rfac, S).leadingBaseCoefficient(); GenPolynomial r = resultant(Pc, Sc); return r.extend(fac, 0, 0L); } GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } // setup factories ModularRingFactory cofac = (ModularRingFactory) P.ring.coFac; if (!cofac.isField()) { logger.warn("cofac is not a field: {}", cofac); } GenPolynomialRing> rfac = fac.recursive(fac.nvar - 1); GenPolynomialRing mfac = new GenPolynomialRing(cofac, rfac); GenPolynomialRing ufac = (GenPolynomialRing) rfac.coFac; // convert polynomials GenPolynomial> qr = PolyUtil. recursive(rfac, q); GenPolynomial> rr = PolyUtil. recursive(rfac, r); // compute degrees and degree vectors ExpVector qdegv = qr.degreeVector(); ExpVector rdegv = rr.degreeVector(); long qd0 = PolyUtil. coeffMaxDegree(qr); long rd0 = PolyUtil. coeffMaxDegree(rr); qd0 = (qd0 == 0 ? 1 : qd0); rd0 = (rd0 == 0 ? 1 : rd0); long qd1 = qr.degree(); long rd1 = rr.degree(); qd1 = (qd1 == 0 ? 1 : qd1); rd1 = (rd1 == 0 ? 1 : rd1); long G = qd0 * rd1 + rd0 * qd1 + 1; // initialize element MOD inc = cofac.getONE(); long i = 0; long en = cofac.getIntegerModul().longValueExact() - 1; // just a stopper MOD end = cofac.fromInteger(en); MOD mi; GenPolynomial M = null; GenPolynomial mn; GenPolynomial qm; GenPolynomial rm; GenPolynomial cm; GenPolynomial> cp = null; if (debug) { //logger.info("qr = {}, q = {}", qr, q); //logger.info("rr = {}, r = {}", rr, r); //logger.info("qd0 = {}", qd0); //logger.info("rd0 = {}", rd0); logger.info("G = {}", G); //logger.info("rdegv = {}", rdegv); // + ", rr.degree(0) = {}", rr.degree(0)); //logger.info("qdegv = {}", qdegv); // + ", qr.degree(0) = {}", qr.degree(0)); } for (MOD d = cofac.getZERO(); d.compareTo(end) <= 0; d = d.sum(inc)) { if (++i >= en) { logger.warn("elements of Z_p exhausted, en = {}, p = {}", en, cofac.getIntegerModul()); return mufd.resultant(P, S); //throw new ArithmeticException("prime list exhausted"); } // map polynomials qm = PolyUtil. evaluateFirstRec(ufac, mfac, qr, d); //logger.info("qr({}) = {}, qr = {}", d, qm, qr); if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { if (debug) { logger.info("un-lucky evaluation point {}, qm = {} < {}", d, qm.degreeVector(), qdegv); } continue; } rm = PolyUtil. evaluateFirstRec(ufac, mfac, rr, d); //logger.info("rr({}) = {}, rr = {}", d, rm, rr); if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { if (debug) { logger.info("un-lucky evaluation point {}, rm = {} < {}", d, rm.degreeVector(), rdegv); } continue; } // compute modular resultant in recursion cm = resultant(rm, qm); //System.out.println("cm = " + cm); // prepare interpolation algorithm if (M == null) { // initialize interpolation M = ufac.getONE(); cp = rfac.getZERO(); } // interpolate mi = PolyUtil. evaluateMain(cofac, M, d); mi = mi.inverse(); // mod p cp = PolyUtil.interpolate(rfac, cp, M, mi, cm, d); //logger.info("cp = {}", cp); mn = ufac.getONE().multiply(d); mn = ufac.univariate(0).subtract(mn); M = M.multiply(mn); // test for completion if (M.degree(0) > G) { if (debug) { logger.info("last lucky evaluation point {}", d); } break; } //logger.info("M = {}", M); } // distribute q = PolyUtil. distribute(fac, cp); return q; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorModular.java000066400000000000000000000523021445075545500271150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.Combinatoric; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.arith.PrimeList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms with modular computation and Chinese * remainder algorithm. * @author Heinz Kredel */ public class GreatestCommonDivisorModular & Modular> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorModular.class); private static final boolean debug = logger.isDebugEnabled(); //logger.isInfoEnabled(); /* * Modular gcd algorithm to use. */ protected final GreatestCommonDivisorAbstract mufd; /* * Integer gcd algorithm for fall back. */ protected final GreatestCommonDivisorAbstract iufd = new GreatestCommonDivisorSubres(); /** * Constructor to set recursive algorithm. Use modular evaluation GCD * algorithm. */ public GreatestCommonDivisorModular() { this(false); } /** * Constructor to set recursive algorithm. * @param simple , true if the simple PRS should be used. */ public GreatestCommonDivisorModular(boolean simple) { if (simple) { mufd = new GreatestCommonDivisorSimple(); } else { mufd = new GreatestCommonDivisorModEval(); } } /** * Univariate GenPolynomial greatest common divisor. Delegate to subresultant * baseGcd, should not be needed. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { return iufd.baseGcd(P, S); } /** * Univariate GenPolynomial recursive greatest common divisor. Delegate to * subresultant recursiveGcd, should not be needed. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd( GenPolynomial> P, GenPolynomial> S) { //return iufd.recursiveUnivariateGcd(P, S); // bad performance // distributed polynomials gcd GenPolynomialRing> rfac = P.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.getVars()); GenPolynomial Pd = PolyUtil. distribute(dfac, P); GenPolynomial Sd = PolyUtil. distribute(dfac, S); GenPolynomial Dd = gcd(Pd, Sd); // convert to recursive GenPolynomial> C = PolyUtil. recursive(rfac, Dd); return C; } /** * GenPolynomial greatest common divisor, modular algorithm. * @param P GenPolynomial. * @param S GenPolynomial. * @return gcd(P,S). */ @Override @SuppressWarnings("unchecked") public GenPolynomial gcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } GenPolynomialRing fac = P.ring; // special case for univariate polynomials if (fac.nvar <= 1) { GenPolynomial T = baseGcd(P, S); return T; } long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); // compute contents and primitive parts BigInteger a = baseContent(r); BigInteger b = baseContent(q); // gcd of coefficient contents BigInteger c = gcd(a, b); // indirection r = divide(r, a); // indirection q = divide(q, b); // indirection if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } // compute normalization factor BigInteger ac = r.leadingBaseCoefficient(); BigInteger bc = q.leadingBaseCoefficient(); BigInteger cc = gcd(ac, bc); // indirection // compute norms BigInteger an = r.maxNorm(); BigInteger bn = q.maxNorm(); BigInteger n = (an.compareTo(bn) < 0 ? bn : an); n = n.multiply(cc).multiply(n.fromInteger(2)); // compute degree vectors ExpVector rdegv = r.degreeVector(); ExpVector qdegv = q.degreeVector(); //compute factor coefficient bounds BigInteger af = an.multiply(PolyUtil.factorBound(rdegv)); BigInteger bf = bn.multiply(PolyUtil.factorBound(qdegv)); BigInteger cf = (af.compareTo(bf) < 0 ? bf : af); cf = cf.multiply(cc.multiply(cc.fromInteger(8))); //initialize prime list and degree vector PrimeList primes = new PrimeList(); int pn = 10; //primes.size(); ExpVector wdegv = rdegv.subst(0, rdegv.getVal(0) + 1); // +1 seems to be a hack for the unlucky prime test ModularRingFactory cofac; ModularRingFactory cofacM = null; GenPolynomial qm; GenPolynomial rm; GenPolynomialRing mfac; GenPolynomialRing rfac = null; int i = 0; BigInteger M = null; BigInteger cfe = null; GenPolynomial cp = null; GenPolynomial cm = null; GenPolynomial cpi = null; if (debug) { logger.debug("c = {}", c); logger.debug("cc = {}", cc); logger.debug("n = {}", n); logger.debug("cf = {}", cf); logger.info("wdegv = {}, in {}", wdegv, fac.toScript()); } for (java.math.BigInteger p : primes) { //System.out.println("next run ++++++++++++++++++++++++++++++++++"); if (p.longValue() == 2L) { // skip 2 continue; } if (++i >= pn) { logger.warn("prime list exhausted, pn = {}", pn); return iufd.gcd(P, S); //throw new ArithmeticException("prime list exhausted"); } // initialize coefficient factory and map normalization factor if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cofac = (ModularRingFactory) new ModLongRing(p, true); } else { cofac = (ModularRingFactory) new ModIntegerRing(p, true); } MOD nf = cofac.fromInteger(cc.getVal()); if (nf.isZERO()) { continue; } // initialize polynomial factory and map polynomials mfac = new GenPolynomialRing(cofac, fac.nvar, fac.tord, fac.getVars()); qm = PolyUtil. fromIntegerCoefficients(mfac, q); if (qm.isZERO() || !qm.degreeVector().equals(qdegv)) { continue; } rm = PolyUtil. fromIntegerCoefficients(mfac, r); if (rm.isZERO() || !rm.degreeVector().equals(rdegv)) { continue; } if (debug) { logger.info("cofac = {}", cofac.getIntegerModul()); } // compute modular gcd cm = mufd.gcd(rm, qm); // test for constant g.c.d if (cm.isConstant()) { logger.debug("cm, constant = {}", cm); return fac.getONE().multiply(c); //return cm.abs().multiply( c ); } // test for unlucky prime ExpVector mdegv = cm.degreeVector(); if (wdegv.equals(mdegv)) { // TL = 0 // prime ok, next round if (M != null) { if (M.compareTo(cfe) > 0) { System.out.println("M > cfe: " + M + " > " + cfe); // continue; // why should this be required? } } } else { // TL = 3 boolean ok = false; if (wdegv.multipleOf(mdegv)) { // TL = 2 // EVMT(wdegv,mdegv) M = null; // init chinese remainder ok = true; // prime ok } if (mdegv.multipleOf(wdegv)) { // TL = 1 // EVMT(mdegv,wdegv) continue; // skip this prime } if (!ok) { M = null; // discard chinese remainder and previous work continue; // prime not ok } } //--wdegv = mdegv; // prepare chinese remainder algorithm cm = cm.multiply(nf); if (M == null) { // initialize chinese remainder algorithm M = new BigInteger(p); cofacM = cofac; rfac = mfac; cp = cm; wdegv = wdegv.gcd(mdegv); //EVGCD(wdegv,mdegv); cfe = cf; for (int k = 0; k < wdegv.length(); k++) { cfe = cfe.multiply(new BigInteger(wdegv.getVal(k) + 1)); } } else { // apply chinese remainder algorithm BigInteger Mp = M; MOD mi = cofac.fromInteger(Mp.getVal()); mi = mi.inverse(); // mod p M = M.multiply(new BigInteger(p)); if (ModLongRing.MAX_LONG.compareTo(M.getVal()) > 0) { cofacM = (ModularRingFactory) new ModLongRing(M.getVal()); } else { cofacM = (ModularRingFactory) new ModIntegerRing(M.getVal()); } rfac = new GenPolynomialRing(cofacM, fac); if (!cofac.getClass().equals(cofacM.getClass())) { logger.info("adjusting coefficients: cofacM = {}, cofacP = {}", cofacM.getClass(), cofac.getClass()); cofac = (ModularRingFactory) new ModIntegerRing(p); mfac = new GenPolynomialRing(cofac, fac); GenPolynomial mm = PolyUtil. integerFromModularCoefficients(fac, cm); cm = PolyUtil. fromIntegerCoefficients(mfac, mm); mi = cofac.fromInteger(Mp.getVal()); mi = mi.inverse(); // mod p } if (!cp.ring.coFac.getClass().equals(cofacM.getClass())) { logger.info("adjusting coefficients: cofacM = {}, cofacM' = {}", cofacM.getClass(), cp.ring.coFac.getClass()); ModularRingFactory cop = (ModularRingFactory) cp.ring.coFac; cofac = (ModularRingFactory) new ModIntegerRing(cop.getIntegerModul().getVal()); mfac = new GenPolynomialRing(cofac, fac); GenPolynomial mm = PolyUtil. integerFromModularCoefficients(fac, cp); cp = PolyUtil. fromIntegerCoefficients(mfac, mm); } cp = PolyUtil. chineseRemainder(rfac, cp, mi, cm); } // test for completion if (n.compareTo(M) <= 0) { break; } // must use integer.sumNorm cpi = PolyUtil. integerFromModularCoefficients(fac, cp); BigInteger cmn = cpi.sumNorm(); cmn = cmn.multiply(cmn.fromInteger(4)); //if ( cmn.compareTo( M ) <= 0 ) { // does not work: only if cofactors are also considered? // break; //} if (i % 2 != 0 && !cp.isZERO()) { // check if done on every second prime GenPolynomial x; x = PolyUtil. integerFromModularCoefficients(fac, cp); x = basePrimitivePart(x); if (!PolyUtil. baseSparsePseudoRemainder(q, x).isZERO()) { continue; } if (!PolyUtil. baseSparsePseudoRemainder(r, x).isZERO()) { continue; } logger.info("done on exact division, #primes = {}", i); break; } } if (debug) { logger.info("done on M = {}, #primes = {}", M, i); } // remove normalization q = PolyUtil. integerFromModularCoefficients(fac, cp); q = basePrimitivePart(q); return q.abs().multiply(c); } /** * Univariate GenPolynomial resultant. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) { // not a special case here return resultant(P, S); } /** * Univariate GenPolynomial recursive resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial> recursiveUnivariateResultant( GenPolynomial> P, GenPolynomial> S) { // only in this class return recursiveResultant(P, S); } /** * GenPolynomial resultant, modular algorithm. * @param P GenPolynomial. * @param S GenPolynomial. * @return res(P,S). */ @Override @SuppressWarnings("unchecked") public GenPolynomial resultant(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } GenPolynomialRing fac = P.ring; // no special case for univariate polynomials in this class ! //if (fac.nvar <= 1) { // GenPolynomial T = iufd.baseResultant(P, S); // return T; //} long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } // compute norms BigInteger an = r.maxNorm(); BigInteger bn = q.maxNorm(); an = an.power(f); bn = bn.power(e); BigInteger cn = Combinatoric.factorial(e + f); BigInteger n = cn.multiply(an).multiply(bn); // compute degree vectors ExpVector rdegv = r.leadingExpVector(); //degreeVector(); ExpVector qdegv = q.leadingExpVector(); //degreeVector(); //initialize prime list and degree vector PrimeList primes = new PrimeList(); int pn = 30; //primes.size(); ModularRingFactory cofac; ModularRingFactory cofacM = null; GenPolynomial qm; GenPolynomial rm; GenPolynomialRing mfac; GenPolynomialRing rfac = null; int i = 0; BigInteger M = null; GenPolynomial cp = null; GenPolynomial cm = null; //GenPolynomial cpi = null; if (debug) { logger.debug("an = {}", an); logger.debug("bn = {}", bn); logger.debug("e+f = {}", (e + f)); logger.debug("cn = {}", cn); logger.info("n = {}", n); //logger.info("q = {}", q); //logger.info("r = {}", r); //logger.info("rdegv = {}", rdegv.toString(fac.getVars())); //logger.info("qdegv = {}", qdegv.toString(fac.getVars())); } for (java.math.BigInteger p : primes) { //System.out.println("next run ++++++++++++++++++++++++++++++++++"); if (p.longValue() == 2L) { // skip 2 continue; } if (++i >= pn) { logger.warn("prime list exhausted, pn = {}", pn); return iufd.resultant(P, S); //throw new ArithmeticException("prime list exhausted"); } // initialize coefficient factory and map normalization factor if (ModLongRing.MAX_LONG.compareTo(p) > 0) { cofac = (ModularRingFactory) new ModLongRing(p, true); } else { cofac = (ModularRingFactory) new ModIntegerRing(p, true); } // initialize polynomial factory and map polynomials mfac = new GenPolynomialRing(cofac, fac); qm = PolyUtil. fromIntegerCoefficients(mfac, q); if (qm.isZERO() || !qm.leadingExpVector().equals(qdegv)) { //degreeVector() //logger.info("qm = {}", qm); if (debug) { logger.info("unlucky prime = {}, degv = {}", cofac.getIntegerModul(), qm.leadingExpVector()); } continue; } rm = PolyUtil. fromIntegerCoefficients(mfac, r); if (rm.isZERO() || !rm.leadingExpVector().equals(rdegv)) { //degreeVector() //logger.info("rm = {}", rm); if (debug) { logger.info("unlucky prime = {}, degv = ", cofac.getIntegerModul(), rm.leadingExpVector()); } continue; } logger.info("lucky prime = {}", cofac.getIntegerModul()); // compute modular resultant cm = mufd.resultant(qm, rm); if (debug) { logger.info("res_p = {}", cm); } // prepare chinese remainder algorithm if (M == null) { // initialize chinese remainder algorithm M = new BigInteger(p); cofacM = cofac; //rfac = mfac; cp = cm; } else { // apply chinese remainder algorithm BigInteger Mp = M; MOD mi = cofac.fromInteger(Mp.getVal()); mi = mi.inverse(); // mod p M = M.multiply(new BigInteger(p)); if (ModLongRing.MAX_LONG.compareTo(M.getVal()) > 0) { cofacM = (ModularRingFactory) new ModLongRing(M.getVal()); } else { cofacM = (ModularRingFactory) new ModIntegerRing(M.getVal()); } rfac = new GenPolynomialRing(cofacM, fac); if (!cofac.getClass().equals(cofacM.getClass())) { logger.info("adjusting coefficients: cofacM = {}, cofacP = {}", cofacM.getClass(), cofac.getClass()); cofac = (ModularRingFactory) new ModIntegerRing(p); mfac = new GenPolynomialRing(cofac, fac); GenPolynomial mm = PolyUtil. integerFromModularCoefficients(fac, cm); cm = PolyUtil. fromIntegerCoefficients(mfac, mm); mi = cofac.fromInteger(Mp.getVal()); mi = mi.inverse(); // mod p } if (!cp.ring.coFac.getClass().equals(cofacM.getClass())) { logger.info("adjusting coefficients: cofacM = {}, cofacM' = {}", cofacM.getClass(), cp.ring.coFac.getClass()); ModularRingFactory cop = (ModularRingFactory) cp.ring.coFac; cofac = (ModularRingFactory) new ModIntegerRing(cop.getIntegerModul().getVal()); mfac = new GenPolynomialRing(cofac, fac); GenPolynomial mm = PolyUtil. integerFromModularCoefficients(fac, cp); cp = PolyUtil. fromIntegerCoefficients(mfac, mm); } cp = PolyUtil. chineseRemainder(rfac, cp, mi, cm); } // test for completion if (n.compareTo(M) <= 0) { break; } } if (debug) { logger.info("done on M = {}, #primes = {}", M, i); } // convert to integer polynomial q = PolyUtil. integerFromModularCoefficients(fac, cp); return q; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorPrimitive.java000066400000000000000000000102631445075545500274620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; /** * Greatest common divisor algorithms with primitive polynomial remainder * sequence. * @author Heinz Kredel */ public class GreatestCommonDivisorPrimitive> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorPrimitive.class); private static final boolean debug = logger.isDebugEnabled(); /** * Univariate GenPolynomial greatest common divisor. Uses pseudoRemainder for * remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); C a = baseContent(r); C b = baseContent(q); C c = gcd(a, b); // indirection r = divide(r, a); // indirection q = divide(q, b); // indirection if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenPolynomial x; while (!r.isZERO()) { x = PolyUtil. baseSparsePseudoRemainder(q, r); q = r; r = basePrimitivePart(x); } return (q.multiply(c)).abs(); } /** * Univariate GenPolynomial recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial> q; GenPolynomial> r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); GenPolynomial a = recursiveContent(r); GenPolynomial b = recursiveContent(q); GenPolynomial c = gcd(a, b); // go to recursion //System.out.println("rgcd c = " + c); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenPolynomial> x; while (!r.isZERO()) { x = PolyUtil. recursiveSparsePseudoRemainder(q, r); if (logger.isDebugEnabled()) { logger.info("recursiveSparsePseudoRemainder.bits = {}", x.bitLength()); } q = r; r = recursivePrimitivePart(x); } return q.abs().multiply(c); //.abs(); } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorSimple.java000066400000000000000000000242411445075545500267440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms with monic polynomial remainder sequence. * If C is a field, then the monic PRS (on coefficients) is computed otherwise * no simplifications in the reduction are made. * @author Heinz Kredel */ public class GreatestCommonDivisorSimple> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorSimple.class); private static final boolean debug = logger.isDebugEnabled(); /** * Univariate GenPolynomial greatest common divisor. Uses pseudoRemainder for * remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.ring.coFac.isField(); long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } C c; if (field) { r = r.monic(); q = q.monic(); c = P.ring.getONECoefficient(); } else { r = r.abs(); q = q.abs(); C a = baseContent(r); C b = baseContent(q); c = gcd(a, b); // indirection r = divide(r, a); // indirection q = divide(q, b); // indirection } if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenPolynomial x; //System.out.println("q = " + q); //System.out.println("r = " + r); while (!r.isZERO()) { x = PolyUtil. baseSparsePseudoRemainder(q, r); q = r; if (field) { r = x.monic(); } else { r = x; } //System.out.println("q = " + q); //System.out.println("r = " + r); } q = basePrimitivePart(q); return (q.multiply(c)).abs(); } /** * Univariate GenPolynomial recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } boolean field = P.leadingBaseCoefficient().ring.coFac.isField(); long e = P.degree(0); long f = S.degree(0); GenPolynomial> q; GenPolynomial> r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } if (field) { r = PolyUtil. monic(r); q = PolyUtil. monic(q); } else { r = r.abs(); q = q.abs(); } GenPolynomial a = recursiveContent(r); GenPolynomial b = recursiveContent(q); GenPolynomial c = gcd(a, b); // go to recursion //System.out.println("rgcd c = " + c); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenPolynomial> x; while (!r.isZERO()) { x = PolyUtil. recursiveSparsePseudoRemainder(q, r); if (logger.isDebugEnabled()) { logger.info("recursiveSparsePseudoRemainder.bits = {}", x.bitLength()); } q = r; if (field) { r = PolyUtil. monic(x); } else { r = x; } } q = recursivePrimitivePart(q); q = q.abs().multiply(c); return q; } /** * Univariate GenPolynomial resultant. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } if (P.ring.nvar > 1 || P.ring.nvar == 0) { throw new IllegalArgumentException("no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); if (f == 0 && e == 0) { return P.ring.getONE(); } if (e == 0) { return P.power(f); } if (f == 0) { return S.power(e); } GenPolynomial q; GenPolynomial r; int s = 0; // sign is +, 1 for sign is - if (e < f) { r = P; q = S; long t = e; e = f; f = t; if ((e % 2 != 0) && (f % 2 != 0)) { // odd(e) && odd(f) s = 1; } } else { q = P; r = S; } RingFactory cofac = P.ring.coFac; boolean field = cofac.isField(); C c = cofac.getONE(); GenPolynomial x; long g; do { if (field) { x = q.remainder(r); } else { x = PolyUtil. baseSparsePseudoRemainder(q, r); //System.out.println("x_s = " + x + ", lbcf(r) = " + r.leadingBaseCoefficient()); } if (x.isZERO()) { return x; } //System.out.println("x = " + x); e = q.degree(0); f = r.degree(0); if ((e % 2 != 0) && (f % 2 != 0)) { // odd(e) && odd(f) s = 1 - s; } g = x.degree(0); C c2 = r.leadingBaseCoefficient(); for (int i = 0; i < (e - g); i++) { c = c.multiply(c2); } q = r; r = x; } while (g != 0); C c2 = r.leadingBaseCoefficient(); for (int i = 0; i < f; i++) { c = c.multiply(c2); } if (s == 1) { c = c.negate(); } x = P.ring.getONE().multiply(c); return x; } /** * Univariate GenPolynomial recursive resultant. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial> recursiveUnivariateResultant(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } if (P.ring.nvar > 1 || P.ring.nvar == 0) { throw new IllegalArgumentException("no recursive univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); if (f == 0 && e == 0) { // if coeffs are multivariate (and non constant) // otherwise it would be 1 GenPolynomial t = resultant(P.leadingBaseCoefficient(), S.leadingBaseCoefficient()); return P.ring.getONE().multiply(t); } if (e == 0) { return P.power(f); } if (f == 0) { return S.power(e); } GenPolynomial> q; GenPolynomial> r; int s = 0; // sign is +, 1 for sign is - if (f > e) { r = P; q = S; long g = f; f = e; e = g; if ((e % 2 != 0) && (f % 2 != 0)) { // odd(e) && odd(f) s = 1; } } else { q = P; r = S; } GenPolynomial> x; RingFactory> cofac = P.ring.coFac; GenPolynomial c = cofac.getONE(); long g; do { x = PolyUtil. recursiveSparsePseudoRemainder(q, r); //x = PolyUtil.recursiveDensePseudoRemainder(q,r); if (x.isZERO()) { return x; } //no: x = recursivePrimitivePart(x); //System.out.println("x = " + x); e = q.degree(0); f = r.degree(0); if ((e % 2 != 0) && (f % 2 != 0)) { // odd(e) && odd(f) s = 1 - s; } g = x.degree(0); GenPolynomial c2 = r.leadingBaseCoefficient(); for (int i = 0; i < (e - g); i++) { c = c.multiply(c2); } q = r; r = x; } while (g != 0); GenPolynomial c2 = r.leadingBaseCoefficient(); for (int i = 0; i < f; i++) { c = c.multiply(c2); } if (s == 1) { c = c.negate(); } x = P.ring.getONE().multiply(c); return x; } } java-algebra-system-2.7.200/src/edu/jas/ufd/GreatestCommonDivisorSubres.java000066400000000000000000000427701445075545500267650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Greatest common divisor algorithms with subresultant polynomial remainder * sequence. * @author Heinz Kredel * @author Youssef Elbarbary */ public class GreatestCommonDivisorSubres> extends GreatestCommonDivisorAbstract { private static final Logger logger = LogManager.getLogger(GreatestCommonDivisorSubres.class); private static final boolean debug = logger.isDebugEnabled(); /** * GenPolynomial pseudo remainder. For univariate polynomials. * @param P GenPolynomial. * @param S nonzero GenPolynomial. * @return remainder with ldcf(S)m P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * @deprecated(forRemoval=true) Use * {@link edu.jas.poly.PolyUtil#baseDensePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)} * instead */ @Deprecated public GenPolynomial basePseudoRemainder(GenPolynomial P, GenPolynomial S) { return PolyUtil. baseDensePseudoRemainder(P, S); } /** * GenPolynomial pseudo remainder. For recursive polynomials. * @param P recursive GenPolynomial. * @param S nonzero recursive GenPolynomial. * @return remainder with ldcf(S)m P = quotient * S + remainder. * @see edu.jas.poly.GenPolynomial#remainder(edu.jas.poly.GenPolynomial). * @deprecated(forRemoval=true) Use * {@link edu.jas.poly.PolyUtil#recursiveDensePseudoRemainder(edu.jas.poly.GenPolynomial,edu.jas.poly.GenPolynomial)} * instead */ @Deprecated public GenPolynomial> recursivePseudoRemainder(GenPolynomial> P, GenPolynomial> S) { return PolyUtil. recursiveDensePseudoRemainder(P, S); } /** * Univariate GenPolynomial greatest common divisor. Uses pseudoRemainder for * remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial baseGcd(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); C a = baseContent(r); C b = baseContent(q); C c = gcd(a, b); // indirection r = divide(r, a); // indirection q = divide(q, b); // indirection if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } C g = r.ring.getONECoefficient(); C h = r.ring.getONECoefficient(); GenPolynomial x; C z; while (!r.isZERO()) { long delta = q.degree(0) - r.degree(0); //System.out.println("delta = " + delta); x = PolyUtil. baseDensePseudoRemainder(q, r); q = r; if (!x.isZERO()) { z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta)); //System.out.println("z = " + z); r = x.divide(z); g = q.leadingBaseCoefficient(); z = g.power(delta); //power(P.ring.coFac, g, delta); h = z.divide(h.power(delta - 1)); //power(P.ring.coFac, h, delta - 1)); //System.out.println("g = " + g); //System.out.println("h = " + h); } else { r = x; } } q = basePrimitivePart(q); return (q.multiply(c)).abs(); } /** * Univariate GenPolynomial recursive greatest common divisor. Uses * pseudoRemainder for remainder. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return gcd(P,S). */ @Override public GenPolynomial> recursiveUnivariateGcd(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return P; } if (P == null || P.isZERO()) { return S; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial> q; GenPolynomial> r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } if (debug) { logger.debug("degrees: e = {}, f = {}", e, f); } r = r.abs(); q = q.abs(); GenPolynomial a = recursiveContent(r); GenPolynomial b = recursiveContent(q); GenPolynomial c = gcd(a, b); // go to recursion //System.out.println("rgcd c = " + c); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); if (r.isONE()) { return r.multiply(c); } if (q.isONE()) { return q.multiply(c); } GenPolynomial g = r.ring.getONECoefficient(); GenPolynomial h = r.ring.getONECoefficient(); GenPolynomial> x; GenPolynomial z = null; while (!r.isZERO()) { long delta = q.degree(0) - r.degree(0); //System.out.println("rgcd delta = " + delta); x = PolyUtil. recursiveDensePseudoRemainder(q, r); if (logger.isDebugEnabled()) { logger.info("recursiveDensePseudoRemainder.bits = {}", x.bitLength()); } q = r; if (!x.isZERO()) { z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta)); r = PolyUtil. recursiveDivide(x, z); g = q.leadingBaseCoefficient(); z = g.power(delta); //power(P.ring.coFac, g, delta); h = PolyUtil. basePseudoDivide(z, h.power(delta - 1)); // power(P.ring.coFac, h, delta - 1) } else { r = x; } } q = recursivePrimitivePart(q); return q.abs().multiply(c); //.abs(); } /** * Univariate GenPolynomial resultant. Uses pseudoRemainder for remainder. * @param P univariate GenPolynomial. * @param S univariate GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial baseResultant(GenPolynomial P, GenPolynomial S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial q; GenPolynomial r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } //r = r.abs(); //q = q.abs(); C a = baseContent(r); C b = baseContent(q); r = divide(r, a); // indirection q = divide(q, b); // indirection RingFactory cofac = P.ring.coFac; C g = cofac.getONE(); C h = cofac.getONE(); C t = a.power(e); //power(cofac, a, e); t = t.multiply(b.power(f)); //power(cofac, b, f)); long s = 1; GenPolynomial x; C z; while (r.degree(0) > 0) { long delta = q.degree(0) - r.degree(0); //System.out.println("delta = " + delta); if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) { s = -s; } x = PolyUtil. baseDensePseudoRemainder(q, r); //System.out.println("x = " + x); q = r; if (x.degree(0) > 0) { z = g.multiply(h.power(delta)); //power(cofac, h, delta)); //System.out.println("z = " + z); r = x.divide(z); g = q.leadingBaseCoefficient(); z = g.power(delta); //power(cofac, g, delta); h = z.divide(h.power(delta - 1)); } else { r = x; } } z = r.leadingBaseCoefficient().power(q.degree(0)); //power(cofac, r.leadingBaseCoefficient(), q.degree(0)); h = z.divide(h.power(q.degree() - 1)); //power(cofac, h, q.degree(0) - 1)); z = h.multiply(t); if (s < 0) { z = z.negate(); } x = P.ring.getONE().multiply(z); return x; } /** * Univariate GenPolynomial recursive resultant. Uses pseudoRemainder for * remainder. * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return res(P,S). */ @Override public GenPolynomial> recursiveUnivariateResultant(GenPolynomial> P, GenPolynomial> S) { if (S == null || S.isZERO()) { return S; } if (P == null || P.isZERO()) { return P; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial> q; GenPolynomial> r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } r = r.abs(); q = q.abs(); GenPolynomial a = recursiveContent(r); GenPolynomial b = recursiveContent(q); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); RingFactory> cofac = P.ring.coFac; GenPolynomial g = cofac.getONE(); GenPolynomial h = cofac.getONE(); GenPolynomial> x; GenPolynomial t; if (f == 0 && e == 0 && g.ring.nvar > 0) { // if coeffs are multivariate (and non constant) // otherwise it would be 1 t = resultant(a, b); x = P.ring.getONE().multiply(t); return x; } t = a.power(e); //power(cofac, a, e); t = t.multiply(b.power(f)); //power(cofac, b, f)); long s = 1; GenPolynomial z; while (r.degree(0) > 0) { long delta = q.degree(0) - r.degree(0); //System.out.println("delta = " + delta); if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) { s = -s; } x = PolyUtil. recursiveDensePseudoRemainder(q, r); //System.out.println("x = " + x); q = r; if (x.degree(0) > 0) { z = g.multiply(h.power(delta)); //power(P.ring.coFac, h, delta)); r = PolyUtil. recursiveDivide(x, z); g = q.leadingBaseCoefficient(); z = g.power(delta); //power(cofac, g, delta); h = PolyUtil. basePseudoDivide(z, h.power(delta - 1)); //power(cofac, h, delta - 1)); } else { r = x; } } z = r.leadingBaseCoefficient().power(q.degree(0)); //power(cofac, r.leadingBaseCoefficient(), q.degree(0)); h = PolyUtil. basePseudoDivide(z, h.power(q.degree() - 1)); //power(cofac, h, q.degree(0) - 1)); z = h.multiply(t); if (s < 0) { z = z.negate(); } x = P.ring.getONE().multiply(z); return x; } /** * Univariate GenPolynomial recursive Subresultant list. Uses * pseudoRemainder for remainder. Author: Youssef Elbarbary * @param P univariate recursive GenPolynomial. * @param S univariate recursive GenPolynomial. * @return subResList(P,S). */ public List>> recursiveUnivariateSubResultantList( GenPolynomial> P, GenPolynomial> S) { List>> myList = new ArrayList>>(); if (S == null || S.isZERO()) { myList.add(S); return myList; } if (P == null || P.isZERO()) { myList.add(P); return myList; } if (P.ring.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " no univariate polynomial"); } long e = P.degree(0); long f = S.degree(0); GenPolynomial> q; GenPolynomial> r; if (f > e) { r = P; q = S; long g = f; f = e; e = g; } else { q = P; r = S; } r = r.abs(); q = q.abs(); GenPolynomial a = recursiveContent(r); GenPolynomial b = recursiveContent(q); r = PolyUtil. recursiveDivide(r, a); q = PolyUtil. recursiveDivide(q, b); RingFactory> cofac = P.ring.coFac; GenPolynomial g = cofac.getONE(); GenPolynomial h = cofac.getONE(); GenPolynomial> x; GenPolynomial t; if (f == 0 && e == 0 && g.ring.nvar > 0) { // if coeffs are multivariate (and non constant) // otherwise it would be 1 t = resultant(a, b); x = P.ring.getONE().multiply(t); myList.add(x); return myList; } t = a.power(e); // power(cofac, a, e); t = t.multiply(b.power(f)); // power(cofac, b, f)); long s = 1; GenPolynomial z; myList.add(P); // adding R0 myList.add(S); // adding R1 while (r.degree(0) > 0) { long delta = q.degree(0) - r.degree(0); if ((q.degree(0) % 2 != 0) && (r.degree(0) % 2 != 0)) { s = -s; } x = PolyUtil. recursiveDensePseudoRemainder(q, r); q = r; if (x.degree(0) >= 0) { // fixed: this was changed from > to >= z = g.multiply(h.power(delta)); // power(P.ring.coFac, h, delta)); r = PolyUtil. recursiveDivide(x, z); myList.add(r); g = q.leadingBaseCoefficient(); z = g.power(delta); // power(cofac, g, delta); h = PolyUtil. basePseudoDivide(z, h.power(delta - 1)); // power(cofac, h, delta - 1)); } else { r = x; myList.add(r); } } z = r.leadingBaseCoefficient().power(q.degree(0)); // power(cofac, r.leadingBaseCoefficient(), q.degree(0)); h = PolyUtil. basePseudoDivide(z, h.power(q.degree() - 1)); // power(cofac, h, q.degree(0) - 1)); z = h.multiply(t); if (s < 0) { z = z.negate(); } x = P.ring.getONE().multiply(z); myList.add(x); // Printing the Subresultant List //System.out.println("Liste von den SubResultanten(A - tD'):"); //for (int i = 0; i < myList.size(); i++) { // just for printing the list // System.out.println(myList.get(i)); //} if (logger.isInfoEnabled()) { System.out.println("subResCoeffs: " + myList); //logger.info("subResCoeffs: {}", myList); } return myList; } /** * GenPolynomial base coefficient discriminant. * @param P GenPolynomial. * @return discriminant(P). */ public GenPolynomial baseDiscriminant(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException(this.getClass().getName() + " P not univariate"); } C a = P.leadingBaseCoefficient(); a = a.inverse(); GenPolynomial Pp = PolyUtil. baseDerivative(P); GenPolynomial res = baseResultant(P, Pp); GenPolynomial disc = res.multiply(a); long n = P.degree(0); n = n * (n - 1); n = n / 2; if (n % 2L != 0L) { disc = disc.negate(); } return disc; } } java-algebra-system-2.7.200/src/edu/jas/ufd/HenselApprox.java000066400000000000000000000065541445075545500237220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import edu.jas.arith.BigInteger; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Container for the approximation result from a Hensel algorithm. * @author Heinz Kredel * @param coefficient type */ public class HenselApprox & Modular> implements Serializable { /** * Approximated polynomial with integer coefficients. */ public final GenPolynomial A; /** * Approximated polynomial with integer coefficients. */ public final GenPolynomial B; /** * Modular approximated polynomial with modular coefficients. */ public final GenPolynomial Am; /** * Modular approximated polynomial with modular coefficients. */ public final GenPolynomial Bm; /** * Constructor. * @param A approximated polynomial. * @param B approximated polynomial. * @param Am approximated modular polynomial. * @param Bm approximated modular polynomial. */ public HenselApprox(GenPolynomial A, GenPolynomial B, GenPolynomial Am, GenPolynomial Bm) { this.A = A; this.B = B; this.Am = Am; this.Bm = Bm; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(A.toString()); sb.append(","); sb.append(B.toString()); sb.append(","); sb.append(Am.toString()); sb.append(","); sb.append(Bm.toString()); return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); sb.append(A.toScript()); sb.append(","); sb.append(B.toScript()); sb.append(","); sb.append(Am.toScript()); sb.append(","); sb.append(Bm.toScript()); return sb.toString(); } /** * Hash code for this Factors. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = A.hashCode(); h = 37 * h + B.hashCode(); h = 37 * h + Am.hashCode(); h = 37 * h + Bm.hashCode(); return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof HenselApprox)) { return false; } HenselApprox a = (HenselApprox) B; return A.equals(a.A) && B.equals(a.B) && Am.equals(a.Am) && Bm.equals(a.Bm); } /** * Get modul of modular polynomial. * @return coefficient modul of polynomial mpol. */ public BigInteger approximationSize() { ModularRingFactory fac = (ModularRingFactory) Am.ring.coFac; return fac.getIntegerModul(); } } java-algebra-system-2.7.200/src/edu/jas/ufd/HenselMultUtil.java000066400000000000000000001464651445075545500242360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.ps.PolynomialTaylorFunction; import edu.jas.ps.TaylorFunction; import edu.jas.ps.UnivPowerSeries; import edu.jas.ps.UnivPowerSeriesRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Hensel multivariate lifting utilities. * @author Heinz Kredel */ public class HenselMultUtil { private static final Logger logger = LogManager.getLogger(HenselMultUtil.class); private static final boolean debug = logger.isInfoEnabled(); /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume ggt(A,B) == 1 mod p. * @param A modular GenPolynomial, mod p^k * @param B modular GenPolynomial, mod p^k * @param C modular GenPolynomial, mod p^k * @param V list of substitution values, mod p^k * @param d desired approximation exponent (x_i-v_i)^d. * @param k desired approximation exponent p^k. * @return [s, t] with s A' + t B' = C mod p^k, with A' = B, B' = A. */ public static & Modular> List> liftDiophant( GenPolynomial A, GenPolynomial B, GenPolynomial C, List V, long d, long k) throws NoLiftingException { GenPolynomialRing pkfac = C.ring; if (pkfac.nvar == 1) { // V, d ignored return HenselUtil. liftDiophant(A, B, C, k); } if (!pkfac.equals(A.ring)) { throw new IllegalArgumentException("A.ring != pkfac: " + A.ring + " != " + pkfac); } // evaluate at v_n: List Vp = new ArrayList(V); MOD v = Vp.remove(Vp.size() - 1); //GenPolynomial zero = pkfac.getZERO(); // (x_n - v) GenPolynomial mon = pkfac.getONE(); GenPolynomial xv = pkfac.univariate(0, 1); xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal())); //System.out.println("xv = " + xv); // A(v), B(v), C(v) ModularRingFactory cf = (ModularRingFactory) pkfac.coFac; MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal()); //System.out.println("v = " + v + ", vp = " + vp); GenPolynomialRing ckfac = pkfac.contract(1); GenPolynomial Ap = PolyUtil. evaluateMain(ckfac, A, vp); GenPolynomial Bp = PolyUtil. evaluateMain(ckfac, B, vp); GenPolynomial Cp = PolyUtil. evaluateMain(ckfac, C, vp); //System.out.println("Ap = " + Ap); //System.out.println("Bp = " + Bp); //System.out.println("Cp = " + Cp); // recursion: List> su = HenselMultUtil. liftDiophant(Ap, Bp, Cp, Vp, d, k); //System.out.println("su@p^" + k + " = " + su); //System.out.println("coFac = " + su.get(0).ring.coFac.toScript()); if (pkfac.nvar == 2 && !HenselUtil. isDiophantLift(Bp, Ap, su.get(0), su.get(1), Cp)) { //System.out.println("isDiophantLift: false"); throw new NoLiftingException("isDiophantLift: false"); } if (!ckfac.equals(su.get(0).ring)) { throw new IllegalArgumentException("qfac != ckfac: " + su.get(0).ring + " != " + ckfac); } GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pkfac); //System.out.println("ifac = " + ifac.toScript()); String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] }; GenPolynomialRing> qrfac = new GenPolynomialRing>(ckfac, 1, mn); //System.out.println("qrfac = " + qrfac); List> sup = new ArrayList>(su.size()); List> supi = new ArrayList>(su.size()); for (GenPolynomial s : su) { GenPolynomial sp = s.extend(pkfac, 0, 0L); sup.add(sp); GenPolynomial spi = PolyUtil.integerFromModularCoefficients(ifac, sp); supi.add(spi); } //System.out.println("sup = " + sup); //System.out.println("supi = " + supi); GenPolynomial Ai = PolyUtil.integerFromModularCoefficients(ifac, A); GenPolynomial Bi = PolyUtil.integerFromModularCoefficients(ifac, B); GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(ifac, C); //System.out.println("Ai = " + Ai); //System.out.println("Bi = " + Bi); //System.out.println("Ci = " + Ci); //GenPolynomial aq = PolyUtil. fromIntegerCoefficients(pkfac, Ai); //GenPolynomial bq = PolyUtil. fromIntegerCoefficients(pkfac, Bi); //System.out.println("aq = " + aq); //System.out.println("bq = " + bq); // compute error: GenPolynomial E = Ci; // - sum_i s_i b_i E = E.subtract(Bi.multiply(supi.get(0))); E = E.subtract(Ai.multiply(supi.get(1))); //System.out.println("E = " + E); if (E.isZERO()) { logger.info("liftDiophant leaving on zero E"); return sup; } GenPolynomial Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); logger.info("Ep(0,{}) = {}", pkfac.nvar, Ep); if (Ep.isZERO()) { logger.info("liftDiophant leaving on zero Ep mod p^k"); return sup; } for (int e = 1; e <= d; e++) { //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar); GenPolynomial> Epr = PolyUtil. recursive(qrfac, Ep); //System.out.println("Epr = " + Epr); UnivPowerSeriesRing> psfac = new UnivPowerSeriesRing>( qrfac); //System.out.println("psfac = " + psfac); TaylorFunction> F = new PolynomialTaylorFunction>(Epr); //System.out.println("F = " + F); //List> Vs = new ArrayList>(1); GenPolynomial vq = ckfac.fromInteger(v.getSymmetricInteger().getVal()); //Vs.add(vq); //System.out.println("Vs = " + Vs); UnivPowerSeries> Epst = psfac.seriesOfTaylor(F, vq); //System.out.println("Epst = " + Epst); GenPolynomial cm = Epst.coefficient(e); //System.out.println("cm = " + cm + ", cm.ring = " + cm.ring.toScript()); // recursion: List> S = HenselMultUtil. liftDiophant(Ap, Bp, cm, Vp, d, k); //System.out.println("S = " + S); if (!ckfac.coFac.equals(S.get(0).ring.coFac)) { throw new IllegalArgumentException( "ckfac != pkfac: " + ckfac.coFac + " != " + S.get(0).ring.coFac); } if (pkfac.nvar == 2 && !HenselUtil. isDiophantLift(Ap, Bp, S.get(1), S.get(0), cm)) { //System.out.println("isDiophantLift: false"); throw new NoLiftingException("isDiophantLift: false"); } mon = mon.multiply(xv); // Power.> power(pkfac,xv,e); //System.out.println("mon = " + mon); //List> Sp = new ArrayList>(S.size()); int i = 0; supi = new ArrayList>(su.size()); for (GenPolynomial dd : S) { //System.out.println("dd = " + dd); GenPolynomial de = dd.extend(pkfac, 0, 0L); GenPolynomial dm = de.multiply(mon); //Sp.add(dm); de = sup.get(i).sum(dm); //System.out.println("dd = " + dd); sup.set(i++, de); GenPolynomial spi = PolyUtil.integerFromModularCoefficients(ifac, dm); supi.add(spi); } //System.out.println("Sp = " + Sp); //System.out.println("sup = " + sup); //System.out.println("supi = " + supi); // compute new error //E = E; // - sum_i s_i b_i E = E.subtract(Bi.multiply(supi.get(0))); E = E.subtract(Ai.multiply(supi.get(1))); //System.out.println("E = " + E); if (E.isZERO()) { logger.info("liftDiophant leaving on zero E"); return sup; } Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); //System.out.println("Ep(" + e + "," + pkfac.nvar + ") = " + Ep); logger.info("Ep({},{}) = {}", e, pkfac.nvar, Ep); if (Ep.isZERO()) { logger.info("liftDiophant leaving on zero Ep mod p^k"); return sup; } } //System.out.println("*** done: " + pkfac.nvar); return sup; } /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume ggt(a,b) == 1 mod p, for a, b in A. * @param A list of modular GenPolynomials, mod p^k * @param C modular GenPolynomial, mod p^k * @param V list of substitution values, mod p^k * @param d desired approximation exponent (x_i-v_i)^d. * @param k desired approximation exponent p^k. * @return [s_1,..., s_n] with sum_i s_i A_i' = C mod p^k, with Ai' = * prod_{j!=i} A_j. */ public static & Modular> List> liftDiophant( List> A, GenPolynomial C, List V, long d, long k) throws NoLiftingException { GenPolynomialRing pkfac = C.ring; if (pkfac.nvar == 1) { // V, d ignored return HenselUtil. liftDiophant(A, C, k); } if (!pkfac.equals(A.get(0).ring)) { throw new IllegalArgumentException("A.ring != pkfac: " + A.get(0).ring + " != " + pkfac); } // co-products GenPolynomial As = pkfac.getONE(); for (GenPolynomial a : A) { As = As.multiply(a); } List> Bp = new ArrayList>(A.size()); for (GenPolynomial a : A) { GenPolynomial b = PolyUtil. basePseudoDivide(As, a); Bp.add(b); } // evaluate at v_n: List Vp = new ArrayList(V); MOD v = Vp.remove(Vp.size() - 1); // (x_n - v) GenPolynomial mon = pkfac.getONE(); GenPolynomial xv = pkfac.univariate(0, 1); xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal())); //System.out.println("xv = " + xv); // A(v), B(v), C(v) ModularRingFactory cf = (ModularRingFactory) pkfac.coFac; MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal()); //System.out.println("v = " + v + ", vp = " + vp); GenPolynomialRing ckfac = pkfac.contract(1); List> Ap = new ArrayList>(A.size()); for (GenPolynomial a : A) { GenPolynomial ap = PolyUtil. evaluateMain(ckfac, a, vp); Ap.add(ap); } GenPolynomial Cp = PolyUtil. evaluateMain(ckfac, C, vp); //System.out.println("Ap = " + Ap); //System.out.println("Cp = " + Cp); // recursion: List> su = HenselMultUtil. liftDiophant(Ap, Cp, Vp, d, k); //System.out.println("su@p^" + k + " = " + su); //System.out.println("coFac = " + su.get(0).ring.coFac.toScript()); if (pkfac.nvar == 2 && !HenselUtil. isDiophantLift(Ap, su, Cp)) { //System.out.println("isDiophantLift: false"); throw new NoLiftingException("isDiophantLift: false"); } if (!ckfac.equals(su.get(0).ring)) { throw new IllegalArgumentException("qfac != ckfac: " + su.get(0).ring + " != " + ckfac); } GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pkfac); //System.out.println("ifac = " + ifac.toScript()); String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] }; GenPolynomialRing> qrfac = new GenPolynomialRing>(ckfac, 1, mn); //System.out.println("qrfac = " + qrfac); List> sup = new ArrayList>(su.size()); List> supi = new ArrayList>(su.size()); for (GenPolynomial s : su) { GenPolynomial sp = s.extend(pkfac, 0, 0L); sup.add(sp); GenPolynomial spi = PolyUtil.integerFromModularCoefficients(ifac, sp); supi.add(spi); } //System.out.println("sup = " + sup); //System.out.println("supi = " + supi); //List> Ai = new ArrayList>(A.size()); //for (GenPolynomial a : A) { // GenPolynomial ai = PolyUtil.integerFromModularCoefficients(ifac, a); // Ai.add(ai); //} List> Bi = new ArrayList>(A.size()); for (GenPolynomial b : Bp) { GenPolynomial bi = PolyUtil.integerFromModularCoefficients(ifac, b); Bi.add(bi); } GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(ifac, C); //System.out.println("Ai = " + Ai); //System.out.println("Ci = " + Ci); //List> Aq = new ArrayList>(A.size()); //for (GenPolynomial ai : Ai) { // GenPolynomial aq = PolyUtil. fromIntegerCoefficients(pkfac, ai); // Aq.add(aq); //} //System.out.println("Aq = " + Aq); // compute error: GenPolynomial E = Ci; // - sum_i s_i b_i int i = 0; for (GenPolynomial bi : Bi) { E = E.subtract(bi.multiply(supi.get(i++))); } //System.out.println("E = " + E); if (E.isZERO()) { logger.info("liftDiophant leaving on zero E"); return sup; } GenPolynomial Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); logger.info("Ep(0,{}) = {}", pkfac.nvar, Ep); if (Ep.isZERO()) { logger.info("liftDiophant leaving on zero Ep mod p^k"); return sup; } for (int e = 1; e <= d; e++) { //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar); GenPolynomial> Epr = PolyUtil. recursive(qrfac, Ep); //System.out.println("Epr = " + Epr); UnivPowerSeriesRing> psfac = new UnivPowerSeriesRing>( qrfac); //System.out.println("psfac = " + psfac); TaylorFunction> F = new PolynomialTaylorFunction>(Epr); //System.out.println("F = " + F); //List> Vs = new ArrayList>(1); GenPolynomial vq = ckfac.fromInteger(v.getSymmetricInteger().getVal()); //Vs.add(vq); //System.out.println("Vs = " + Vs); UnivPowerSeries> Epst = psfac.seriesOfTaylor(F, vq); //System.out.println("Epst = " + Epst); GenPolynomial cm = Epst.coefficient(e); //System.out.println("cm = " + cm + ", cm.ring = " + cm.ring.toScript()); if (cm.isZERO()) { continue; } // recursion: List> S = HenselMultUtil. liftDiophant(Ap, cm, Vp, d, k); //System.out.println("S = " + S); if (!ckfac.coFac.equals(S.get(0).ring.coFac)) { throw new IllegalArgumentException( "ckfac != pkfac: " + ckfac.coFac + " != " + S.get(0).ring.coFac); } if (pkfac.nvar == 2 && !HenselUtil. isDiophantLift(Ap, S, cm)) { //System.out.println("isDiophantLift: false"); throw new NoLiftingException("isDiophantLift: false"); } mon = mon.multiply(xv); // Power.> power(pkfac,xv,e); //System.out.println("mon = " + mon); //List> Sp = new ArrayList>(S.size()); i = 0; supi = new ArrayList>(su.size()); for (GenPolynomial dd : S) { //System.out.println("dd = " + dd); GenPolynomial de = dd.extend(pkfac, 0, 0L); GenPolynomial dm = de.multiply(mon); //Sp.add(dm); de = sup.get(i).sum(dm); //System.out.println("dd = " + dd); sup.set(i++, de); GenPolynomial spi = PolyUtil.integerFromModularCoefficients(ifac, dm); supi.add(spi); } //System.out.println("Sp = " + Sp); //System.out.println("sup = " + sup); //System.out.println("supi = " + supi); // compute new error //E = E; // - sum_i s_i b_i i = 0; for (GenPolynomial bi : Bi) { E = E.subtract(bi.multiply(supi.get(i++))); } //System.out.println("E = " + E); if (E.isZERO()) { logger.info("liftDiophant leaving on zero E"); return sup; } Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); logger.info("Ep({},{}) = {}", e, pkfac.nvar, Ep); if (Ep.isZERO()) { logger.info("liftDiophant leaving on zero Ep mod p^k"); return sup; } } //System.out.println("*** done: " + pkfac.nvar); return sup; } /** * Modular Hensel lifting algorithm on coefficients test. Let p = * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with * gcd(f_i,f_j) == 1 mod p for i != j * @param C integer polynomial * @param Cp GenPolynomial mod p^k * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials. * @param L = [g_0,...,g_{n-1}] list of lifted modular polynomials. * @return true if C = prod_{0,...,n-1} g_i mod p^k, else false. */ @SuppressWarnings("unused") public static & Modular> boolean isHenselLift(GenPolynomial C, GenPolynomial Cp, List> F, List> L) { boolean t = true; GenPolynomialRing qfac = L.get(0).ring; GenPolynomial q = qfac.getONE(); for (GenPolynomial fi : L) { q = q.multiply(fi); } t = Cp.equals(q); if (!t) { System.out.println("Cp = " + Cp); System.out.println("q = " + q); System.out.println("Cp != q: " + Cp.subtract(q)); return t; } GenPolynomialRing dfac = C.ring; GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(dfac, q); t = C.equals(Ci); if (!t) { System.out.println("C = " + C); System.out.println("Ci = " + Ci); System.out.println("C != Ci: " + C.subtract(Ci)); return t; } // test L mod id(V) == F return t; } /** * Modular Hensel lifting algorithm, monic case. Let p = * A_i.ring.coFac.modul() and assume ggt(a,b) == 1 mod p, for a, b in A. * @param C monic GenPolynomial with integer coefficients * @param Cp GenPolynomial mod p^k * @param F list of modular GenPolynomials, mod (I_v, p^k ) * @param V list of integer substitution values * @param k desired approximation exponent p^k. * @return [g'_1,..., g'_n] with prod_i g'_i = Cp mod p^k. */ public static & Modular> List> liftHenselMonic( GenPolynomial C, GenPolynomial Cp, List> F, List V, long k) throws NoLiftingException { GenPolynomialRing pkfac = Cp.ring; //if (pkfac.nvar == 1) { // V ignored // return HenselUtil. liftHenselMonic(C,F,k); //} long d = C.degree(); //System.out.println("d = " + d); // prepare stack of polynomial rings and polynomials List> Pfac = new ArrayList>(); List> Ap = new ArrayList>(); List Vb = new ArrayList(); MOD v = pkfac.coFac.fromInteger(V.get(0).getVal()); Pfac.add(pkfac); Ap.add(Cp); Vb.add(v); GenPolynomialRing pf = pkfac; GenPolynomial ap = Cp; for (int j = pkfac.nvar; j > 2; j--) { pf = pf.contract(1); Pfac.add(0, pf); //MOD vp = pkfac.coFac.fromInteger(V.get(j - 2).getSymmetricInteger().getVal()); MOD vp = pkfac.coFac.fromInteger(V.get(j - 2).getVal()); //System.out.println("vp = " + vp); Vb.add(1, vp); ap = PolyUtil. evaluateMain(pf, ap, vp); Ap.add(0, ap); } logger.debug("Pfac = {}", Pfac); //System.out.println("Ap = " + Ap); //System.out.println("V = " + V); //System.out.println("Vb = " + Vb); // setup bi-variate base case GenPolynomialRing pk1fac = F.get(0).ring; if (!pkfac.coFac.equals(pk1fac.coFac)) { throw new IllegalArgumentException("F.ring != pkfac: " + pk1fac + " != " + pkfac); } // TODO: adjust leading coefficients pkfac = Pfac.get(0); //Cp = Ap.get(0); //System.out.println("pkfac = " + pkfac.toScript()); //System.out.println("pk1fac = " + pk1fac.toScript()); GenPolynomialRing i1fac = new GenPolynomialRing(new BigInteger(), pk1fac); //System.out.println("i1fac = " + i1fac.toScript()); List> Bi = new ArrayList>(F.size()); for (GenPolynomial b : F) { GenPolynomial bi = PolyUtil.integerFromModularCoefficients(i1fac, b); Bi.add(bi); } //System.out.println("Bi = " + Bi); // evaluate Cp at v_n: //ModularRingFactory cf = (ModularRingFactory) pkfac.coFac; //MOD vp = cf.fromInteger(v.getSymmetricInteger().getVal()); //System.out.println("v = " + v + ", vp = " + vp); GenPolynomialRing ckfac; // = pkfac.contract(1); //GenPolynomial Cs = PolyUtil. evaluateMain(ckfac, Cp, vp); //System.out.println("Cp = " + Cp); //System.out.println("Cs = " + Cs); List> U = new ArrayList>(F.size()); for (GenPolynomial b : F) { GenPolynomial bi = b.extend(pkfac, 0, 0L); U.add(bi); } //System.out.println("U = " + U); List> U1 = F; //System.out.println("U1 = " + U1); GenPolynomial E = C.ring.getZERO(); List Vh = new ArrayList(); while (Pfac.size() > 0) { // loop through stack of polynomial rings pkfac = Pfac.remove(0); Cp = Ap.remove(0); v = Vb.remove(0); //Vh.add(0,v); //System.out.println("\npkfac = " + pkfac.toScript() + " ================================== " + Vh); // (x_n - v) GenPolynomial mon = pkfac.getONE(); GenPolynomial xv = pkfac.univariate(0, 1); xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal())); //System.out.println("xv = " + xv); long deg = Cp.degree(pkfac.nvar - 1); //System.out.println("deg = " + deg); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pkfac); //System.out.println("ifac = " + ifac.toScript()); List> Bip = new ArrayList>(F.size()); for (GenPolynomial b : Bi) { GenPolynomial bi = b.extend(ifac, 0, 0L); Bip.add(bi); } Bi = Bip; //System.out.println("Bi = " + Bi); GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(ifac, Cp); //System.out.println("Ci = " + Ci); // compute error: E = ifac.getONE(); for (GenPolynomial bi : Bi) { E = E.multiply(bi); } E = Ci.subtract(E); //System.out.println("E = " + E); GenPolynomial Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); logger.info("Ep(0,{},{}) = {}", deg, pkfac.nvar, Ep); String[] mn = new String[] { pkfac.getVars()[pkfac.nvar - 1] }; ckfac = pkfac.contract(1); GenPolynomialRing> pkrfac = new GenPolynomialRing>(ckfac, 1, mn); //System.out.println("pkrfac = " + pkrfac.toScript()); for (int e = 1; e <= deg && !Ep.isZERO(); e++) { //System.out.println("\ne = " + e + " -------------------------------------- " + pkfac.nvar); GenPolynomial> Epr = PolyUtil. recursive(pkrfac, Ep); //System.out.println("Epr = " + Epr); UnivPowerSeriesRing> psfac = new UnivPowerSeriesRing>( pkrfac); //System.out.println("psfac = " + psfac); TaylorFunction> T = new PolynomialTaylorFunction>(Epr); //System.out.println("T = " + T); //List> Vs = new ArrayList>(1); GenPolynomial vq = ckfac.fromInteger(v.getSymmetricInteger().getVal()); //Vs.add(vq); //System.out.println("Vs = " + Vs + ", Vh = " + Vh); UnivPowerSeries> Epst = psfac.seriesOfTaylor(T, vq); //System.out.println("Epst = " + Epst); logger.info("Epst({},{},{}) = {}", e, deg, pkfac.nvar, Epst); GenPolynomial cm = Epst.coefficient(e); //System.out.println("cm = " + cm); if (cm.isZERO()) { continue; } List> Ud = HenselMultUtil. liftDiophant(U1, cm, Vh, d, k); //System.out.println("Ud = " + Ud); mon = mon.multiply(xv); //System.out.println("mon = " + mon); //List> Sd = new ArrayList>(Ud.size()); int i = 0; List> Si = new ArrayList>(Ud.size()); for (GenPolynomial dd : Ud) { //System.out.println("dd = " + dd); GenPolynomial de = dd.extend(pkfac, 0, 0L); GenPolynomial dm = de.multiply(mon); //Sd.add(dm); de = U.get(i).sum(dm); //System.out.println("de = " + de); U.set(i++, de); GenPolynomial si = PolyUtil.integerFromModularCoefficients(ifac, de); Si.add(si); } //System.out.println("Sd = " + Sd); //System.out.println("U = " + U); //System.out.println("Si = " + Si); // compute new error: E = ifac.getONE(); for (GenPolynomial bi : Si) { E = E.multiply(bi); } E = Ci.subtract(E); //System.out.println("E = " + E); Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep); logger.info("Ep({},{},{}) = {}", e, deg, pkfac.nvar, Ep); } Vh.add(v); U1 = U; if (Pfac.size() > 0) { List> U2 = new ArrayList>(U.size()); pkfac = Pfac.get(0); for (GenPolynomial b : U) { GenPolynomial bi = b.extend(pkfac, 0, 0L); U2.add(bi); } U = U2; //System.out.println("U = " + U); } } if (E.isZERO()) { logger.info("liftHensel leaving with zero E"); } return U; } /** * Modular Hensel lifting algorithm. Let p = A_i.ring.coFac.modul() and * assume ggt(a,b) == 1 mod p, for a, b in A. * @param C GenPolynomial with integer coefficients * @param Cp GenPolynomial C mod p^k * @param F list of modular GenPolynomials, mod (I_v, p^k ) * @param V list of integral substitution values * @param k desired approximation exponent p^k. * @param G list of leading coefficients of the factors of C. * @return [g'_1,..., g'_n] with prod_i g'_i = Cp mod p^k. */ public static & Modular> List> liftHensel( GenPolynomial C, GenPolynomial Cp, List> F, List V, long k, List> G) throws NoLiftingException { GenPolynomialRing pkfac = Cp.ring; long d = C.degree(); //System.out.println("C = " + C); //System.out.println("Cp = " + Cp); //System.out.println("G = " + G); //GenPolynomial cd = G.get(0); // 1 //System.out.println("cd = " + cd + ", ring = " + C.ring); //if ( cd.equals(C.ring.univariate(0)) ) { // System.out.println("cd == G[1]"); //} // G mod p^k, in all variables GenPolynomialRing pkfac1 = new GenPolynomialRing(pkfac.coFac, G.get(0).ring); List> Lp = new ArrayList>(G.size()); for (GenPolynomial cd1 : G) { GenPolynomial cdq = PolyUtil. fromIntegerCoefficients(pkfac1, cd1); cdq = cdq.extendLower(pkfac, 0, 0L); // reintroduce lower variable Lp.add(cdq); } logger.info("G modulo p^k: {}", Lp); // + ", ring = {}", pkfac1); // prepare stack of polynomial rings, polynomials and evaluated leading coefficients List> Pfac = new ArrayList>(); List> Ap = new ArrayList>(); List>> Gp = new ArrayList>>(); List Vb = new ArrayList(); //MOD v = V.get(0); // fromInteger Pfac.add(pkfac); Ap.add(Cp); Gp.add(Lp); GenPolynomialRing pf = pkfac; //GenPolynomialRing pf1 = pkfac1; GenPolynomial ap = Cp; List> Lpp = Lp; for (int j = pkfac.nvar; j > 2; j--) { pf = pf.contract(1); Pfac.add(0, pf); //MOD vp = pkfac.coFac.fromInteger(V.get(pkfac.nvar - j).getSymmetricInteger().getVal()); MOD vp = pkfac.coFac.fromInteger(V.get(pkfac.nvar - j).getVal()); //System.out.println("vp = " + vp); Vb.add(vp); ap = PolyUtil. evaluateMain(pf, ap, vp); Ap.add(0, ap); List> Lps = new ArrayList>(Lpp.size()); for (GenPolynomial qp : Lpp) { GenPolynomial qpe = PolyUtil. evaluateMain(pf, qp, vp); Lps.add(qpe); } //System.out.println("Lps = " + Lps); Lpp = Lps; Gp.add(0, Lpp); } Vb.add(pkfac.coFac.fromInteger(V.get(pkfac.nvar - 2).getVal())); //System.out.println("Pfac = " + Pfac); logger.debug("Pfac = {}", Pfac); //System.out.println("Ap = " + Ap); //System.out.println("Gp = " + Gp); //System.out.println("Gp[0] = " + Gp.get(0) + ", Gp[0].ring = " + Gp.get(0).get(0).ring); //System.out.println("V = " + V); //System.out.println("Vb = " + Vb + ", V == Vb: " + V.equals(Vb)); // check bi-variate base case GenPolynomialRing pk1fac = F.get(0).ring; if (!pkfac.coFac.equals(pk1fac.coFac)) { throw new IllegalArgumentException("F.ring != pkfac: " + pk1fac + " != " + pkfac); } // init recursion List> U = F; //logger.info("to lift U = {}", U); // + ", U1.ring = {}", U1.get(0).ring); GenPolynomial E = C.ring.getZERO(); List Vh = new ArrayList(); List> Si; // = new ArrayList>(F.size()); MOD v = null; while (Pfac.size() > 0) { // loop through stack of polynomial rings pkfac = Pfac.remove(0); Cp = Ap.remove(0); Lpp = Gp.remove(0); v = Vb.remove(Vb.size() - 1); // last in stack //System.out.println("\npkfac = " + pkfac.toScript() + " ================================== " + v); logger.info("stack loop: pkfac = {} v = {}", pkfac.toScript(), v); List> U1 = U; logger.info("to lift U1 = {}", U1); // + ", U1.ring = {}", U1.get(0).ring); U = new ArrayList>(U1.size()); // update U, replace leading coefficient if required int j = 0; for (GenPolynomial b : U1) { //System.out.println("b = " + b + ", b.ring = " + b.ring); GenPolynomial bi = b.extend(pkfac, 0, 0L); GenPolynomial li = Lpp.get(j); if (!li.isONE()) { //System.out.println("li = " + li + ", li.ring = " + li.ring); //System.out.println("bi = " + bi); GenPolynomialRing> pkrfac = pkfac.recursive(pkfac.nvar - 1); //System.out.println("pkrfac = " + pkrfac); GenPolynomial> br = PolyUtil. recursive(pkrfac, bi); //System.out.println("br = " + br); GenPolynomial> bs = PolyUtil. switchVariables(br); //System.out.println("bs = " + bs + ", bs.ring = " + bs.ring); GenPolynomial> lr = PolyUtil. recursive(pkrfac, li); //System.out.println("lr = " + lr); GenPolynomial> ls = PolyUtil. switchVariables(lr); //System.out.println("ls = " + ls + ", ls.ring = " + ls.ring); if (!ls.isConstant() && !ls.isZERO()) { throw new RuntimeException("ls not constant " + ls + ", li = " + li); } bs.doPutToMap(bs.leadingExpVector(), ls.leadingBaseCoefficient()); //System.out.println("bs = " + bs + ", bs.ring = " + bs.ring); br = PolyUtil. switchVariables(bs); //System.out.println("br = " + br); bi = PolyUtil. distribute(pkfac, br); //System.out.println("bi = " + bi); } U.add(bi); j++; } logger.info("U with leading coefficient replaced = {}", U); // + ", U.ring = {}", U.get(0).ring); // (x_n - v) GenPolynomial mon = pkfac.getONE(); GenPolynomial xv = pkfac.univariate(0, 1); xv = xv.subtract(pkfac.fromInteger(v.getSymmetricInteger().getVal())); //System.out.println("xv = " + xv); long deg = Cp.degree(pkfac.nvar - 1); //System.out.println("deg = " + deg + ", degv = " + Cp.degreeVector()); // convert to integer polynomials GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pkfac); //System.out.println("ifac = " + ifac.toScript()); List> Bi = PolyUtil.integerFromModularCoefficients(ifac, U); //System.out.println("Bi = " + Bi); GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(ifac, Cp); //System.out.println("Ci = " + Ci); // compute error: E = ifac.getONE(); for (GenPolynomial bi : Bi) { E = E.multiply(bi); } //System.out.println("E = " + E); E = Ci.subtract(E); //System.out.println("E = " + E); GenPolynomial Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); logger.info("Ep(0,{},{}) = {}", deg, pkfac.nvar, Ep); GenPolynomialRing> pkrfac = pkfac.recursive(1); GenPolynomialRing ckfac = (GenPolynomialRing) pkrfac.coFac; //System.out.println("pkrfac = " + pkrfac.toScript()); for (int e = 1; e <= deg && !Ep.isZERO(); e++) { //System.out.println("\ne = " + e + " -------------------------------------- " + deg); logger.info("approximation loop: e = {} of deg = {}", e, deg); GenPolynomial> Epr = PolyUtil. recursive(pkrfac, Ep); //System.out.println("Epr = " + Epr); UnivPowerSeriesRing> psfac = new UnivPowerSeriesRing>( pkrfac); //System.out.println("psfac = " + psfac); TaylorFunction> T = new PolynomialTaylorFunction>(Epr); //System.out.println("T = " + T); GenPolynomial vq = ckfac.fromInteger(v.getSymmetricInteger().getVal()); //System.out.println("vq = " + vq + ", Vh = " + Vh); UnivPowerSeries> Epst = psfac.seriesOfTaylor(T, vq); //System.out.println("Epst = " + Epst); logger.info("Epst({},{},{}) = {}", e, deg, pkfac.nvar, Epst); GenPolynomial cm = Epst.coefficient(e); if (cm.isZERO()) { //System.out.println("cm = " + cm); continue; } List> Ud = HenselMultUtil. liftDiophant(U1, cm, Vh, d, k); //System.out.println("Ud = " + Ud); mon = mon.multiply(xv); //System.out.println("mon = " + mon); //List> Sd = new ArrayList>(Ud.size()); int i = 0; Si = new ArrayList>(Ud.size()); for (GenPolynomial dd : Ud) { //System.out.println("dd = " + dd); GenPolynomial de = dd.extend(pkfac, 0, 0L); GenPolynomial dm = de.multiply(mon); //Sd.add(dm); de = U.get(i).sum(dm); //System.out.println("de = " + de); U.set(i++, de); GenPolynomial si = PolyUtil.integerFromModularCoefficients(ifac, de); Si.add(si); } //System.out.println("Sd = " + Sd); //System.out.println("U = " + U + ", U.ring = " + U.get(0).ring); //System.out.println("Si = " + Si); // compute new error: E = ifac.getONE(); for (GenPolynomial bi : Si) { E = E.multiply(bi); } E = Ci.subtract(E); //System.out.println("E = " + E); Ep = PolyUtil. fromIntegerCoefficients(pkfac, E); //System.out.println("Ep(0," + pkfac.nvar + ") = " + Ep); logger.info("Ep({},{},{}) = {}", e, deg, pkfac.nvar, Ep); } Vh.add(v); GenPolynomial Uf = U.get(0).ring.getONE(); for (GenPolynomial Upp : U) { Uf = Uf.multiply(Upp); } if (false && !Cp.leadingExpVector().equals(Uf.leadingExpVector())) { // not meaningful test System.out.println("\nU = " + U); System.out.println("Cp = " + Cp); System.out.println("Uf = " + Uf); //System.out.println("Cp.ring = " + Cp.ring.toScript() + ", Uf.ring = " + Uf.ring.toScript() + "\n"); System.out.println(""); //throw new NoLiftingException("no factorization, Cp != Uf"); } } if (E.isZERO()) { logger.info("liftHensel leaving with zero E, Ep"); } if (false && debug) { // remove normalization required ?? GreatestCommonDivisorAbstract ufd = GCDFactory.getImplementation(new BigInteger()); List> Fii = new ArrayList>(U.size()); for (GenPolynomial bi : Si) { GenPolynomial ci = ufd.content(bi); //ufd.primitivePart(bi); // ?? if (!ci.isONE()) { System.out.println("bi = " + bi + ", cont(bi) = " + ci); } //Fii.add(ci); } //Si = Fii; //System.out.println("Si = " + Si); } logger.info("multivariate lift: U = {}, of {}", U, F); return U; } /** * Modular Hensel full lifting algorithm. Let p = A_i.ring.coFac.modul() and * assume ggt(a,b) == 1 mod p, for a, b in A. * @param C GenPolynomial with integer coefficients * @param F list of modular GenPolynomials, mod (I_v, p ) * @param V list of integer substitution values * @param k desired approximation exponent p^k. * @param G = [g_1,...,g_n] list of factors of leading coefficients. * @return [c_1,..., c_n] with prod_i c_i = C mod p^k. */ @SuppressWarnings("unchecked") public static & Modular> List> liftHenselFull( GenPolynomial C, List> F, List V, long k, List> G) throws NoLiftingException { if (F == null || F.size() == 0) { return new ArrayList>(); } GenPolynomialRing pkfac = F.get(0).ring; //long d = C.degree(); // setup q = p^k RingFactory cfac = pkfac.coFac; ModularRingFactory pcfac = (ModularRingFactory) cfac; //System.out.println("pcfac = " + pcfac); BigInteger p = pcfac.getIntegerModul(); BigInteger q = p.power(k); ModularRingFactory mcfac; if (ModLongRing.MAX_LONG.compareTo(q.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(q.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(q.getVal()); } //System.out.println("mcfac = " + mcfac); // convert C from Z[...] to Z_q[...] GenPolynomialRing qcfac = new GenPolynomialRing(mcfac, C.ring); GenPolynomial Cq = PolyUtil. fromIntegerCoefficients(qcfac, C); //System.out.println("C = " + C); //System.out.println("Cq = " + Cq); // convert g_i from Z[...] to Z_q[...] GenPolynomialRing gcfac = new GenPolynomialRing(mcfac, G.get(0).ring); List> GQ = new ArrayList>(); boolean allOnes = true; for (GenPolynomial g : G) { if (!g.isONE()) { allOnes = false; } GenPolynomial gq = PolyUtil. fromIntegerCoefficients(gcfac, g); GQ.add(gq); } //System.out.println("G = " + G); //System.out.println("GQ = " + GQ); // evaluate C to Z_q[x] GenPolynomialRing pf = qcfac; GenPolynomial ap = Cq; for (int j = C.ring.nvar; j > 1; j--) { pf = pf.contract(1); //MOD vp = mcfac.fromInteger(V.get(C.ring.nvar - j).getSymmetricInteger().getVal()); MOD vp = mcfac.fromInteger(V.get(C.ring.nvar - j).getVal()); //System.out.println("vp = " + vp); ap = PolyUtil. evaluateMain(pf, ap, vp); //System.out.println("ap = " + ap); } GenPolynomial Cq1 = ap; //System.out.println("Cq1 = " + Cq1); if (Cq1.isZERO()) { throw new NoLiftingException("C mod (I, p^k) == 0: " + C); } GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pf); GenPolynomial Ci = PolyUtil.integerFromModularCoefficients(ifac, Cq1); //System.out.println("Ci = " + Ci); GreatestCommonDivisorAbstract ufd = GCDFactory.getImplementation(new BigInteger()); Ci = Ci.abs(); BigInteger cCi = ufd.baseContent(Ci); Ci = Ci.divide(cCi); //System.out.println("cCi = " + cCi); //System.out.println("Ci = " + Ci); ////System.out.println("F.fac = " + F.get(0).ring); // evaluate G to Z_q //List> GP = new ArrayList>(); for (GenPolynomial gq : GQ) { GenPolynomialRing gf = gcfac; GenPolynomial gp = gq; for (int j = gcfac.nvar; j > 1; j--) { gf = gf.contract(1); //MOD vp = mcfac.fromInteger(V.get(gcfac.nvar - j).getSymmetricInteger().getVal()); MOD vp = mcfac.fromInteger(V.get(gcfac.nvar - j).getVal()); //System.out.println("vp = " + vp); gp = PolyUtil. evaluateMain(gf, gp, vp); //System.out.println("gp = " + gp); } //GP.add(gp); } //System.out.println("GP = " + GP); // + ", GP.ring = " + GP.get(0).ring); // leading coefficient for recursion base, for Cq1 and list GP BigInteger gi0 = Ci.leadingBaseCoefficient(); // gq0.getSymmetricInteger(); //System.out.println("gi0 = " + gi0); // lift F to Z_{p^k}[x] //System.out.println("Ci = " + Ci + ", F = " + F + ", k = " + k + ", p = " + F.get(0).ring + ", gi0 = " + gi0); List> U1 = null; if (gi0.isONE()) { U1 = HenselUtil. liftHenselMonic(Ci, F, k); } else { U1 = HenselUtil. liftHensel(Ci, F, k, gi0); // gi0 TODO ?? } logger.info("univariate lift: Ci = {}, F = {}, U1 = {}", Ci, F, U1); //System.out.println("U1.fac = " + U1.get(0).ring); // adjust leading coefficients of U1 with F List> U1i = PolyUtil. integerFromModularCoefficients(Ci.ring, U1); //System.out.println("U1i = " + U1i); boolean t = HenselUtil.isHenselLift(Ci, q, p, U1i); //System.out.println("isLift(U1) = " + t); if (!t) { //System.out.println("NoLiftingException, Ci = " + Ci + ", U1i = " + U1i); throw new NoLiftingException("Ci = " + Ci + ", U1i = " + U1i); } MOD cC = mcfac.fromInteger(cCi.getVal()); List> U1f = PolyUtil. fromIntegerCoefficients(F.get(0).ring, U1i); //System.out.println("U1f = " + U1f); List> U1s = new ArrayList>(U1.size()); int j = 0; int s = 0; for (GenPolynomial u : U1) { GenPolynomial uf = U1f.get(j); GenPolynomial f = F.get(j); GenPolynomial ui = U1i.get(j); GenPolynomial gi = G.get(j); if (ui.signum() != gi.signum()) { //System.out.println("ui = " + ui + ", gi = " + gi); u = u.negate(); uf = uf.negate(); s++; } j++; if (uf.isConstant()) { //System.out.println("u = " + u); u = u.monic(); //System.out.println("u = " + u); u = u.multiply(cC); cC = cC.divide(cC); //System.out.println("u = " + u); } else { MOD x = f.leadingBaseCoefficient().divide(uf.leadingBaseCoefficient()); //System.out.println("x = " + x + ", xi = " + x.getSymmetricInteger()); if (!x.isONE()) { MOD xq = mcfac.fromInteger(x.getSymmetricInteger().getVal()); //System.out.println("xq = " + xq); u = u.multiply(xq); cC = cC.divide(xq); //System.out.println("cC = " + cC); } } U1s.add(u); } //if ( s % 2 != 0 || !cC.isONE()) { if (!cC.isONE()) { throw new NoLiftingException("s = " + s + ", Ci = " + Ci + ", U1i = " + U1i + ", cC = " + cC); } U1 = U1s; U1i = PolyUtil. integerFromModularCoefficients(Ci.ring, U1); //System.out.println("U1i = " + U1i); U1f = PolyUtil. fromIntegerCoefficients(F.get(0).ring, U1i); if (!F.equals(U1f)) { // evtl loop until reached System.out.println("F = " + F); System.out.println("U1f = " + U1f); throw new NoLiftingException("F = " + F + ", U1f = " + U1f); } logger.info("multivariate lift: U1 = {}", U1); // lift U to Z_{p^k}[x,...] //System.out.println("C = " + C + ", U1 = " + U1 + ", V = " + V + ", k = " + k + ", q = " + U1.get(0).ring + ", G = " + G); List> U = null; if (allOnes) { U = HenselMultUtil. liftHenselMonic(C, Cq, U1, V, k); } else { U = HenselMultUtil. liftHensel(C, Cq, U1, V, k, G); } logger.info("multivariate lift: C = {}, U1 = {}, U = {}", C, U1, U); //System.out.println("U = " + U); //System.out.println("U.fac = " + U.get(0).ring); return U; } } java-algebra-system-2.7.200/src/edu/jas/ufd/HenselUtil.java000066400000000000000000002357751445075545500233770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLongRing; import edu.jas.arith.Modular; import edu.jas.arith.ModularRingFactory; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Hensel utilities for ufd. * @author Heinz Kredel */ public class HenselUtil { private static final Logger logger = LogManager.getLogger(HenselUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Modular Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See Algorithm 6.1. in * Geddes et.al.. Linear version, as it does not lift S A + T B == 1 mod * p^{e+1}. * @param C GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param S GenPolynomial * @param T GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1,Am,Bm] = lift(C,A,B), with C = A1 * B1 mod p^e, Am = A1 * mod p^e, Bm = B1 mod p^e . */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHensel( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B, GenPolynomial S, GenPolynomial T) throws NoLiftingException { if (C == null || C.isZERO()) { return new HenselApprox(C, C, A, B); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // setup factories GenPolynomialRing pfac = A.ring; RingFactory p = pfac.coFac; RingFactory q = p; ModularRingFactory P = (ModularRingFactory) p; ModularRingFactory Q = (ModularRingFactory) q; BigInteger Qi = Q.getIntegerModul(); BigInteger M2 = M.multiply(M.fromInteger(2)); BigInteger Mq = Qi; // normalize c and a, b factors, assert p is prime GenPolynomial Ai; GenPolynomial Bi; BigInteger c = C.leadingBaseCoefficient(); C = C.multiply(c); // sic MOD a = A.leadingBaseCoefficient(); if (!a.isONE()) { // A = A.monic(); A = A.divide(a); S = S.multiply(a); } MOD b = B.leadingBaseCoefficient(); if (!b.isONE()) { // B = B.monic(); B = B.divide(b); T = T.multiply(b); } MOD cm = P.fromInteger(c.getVal()); A = A.multiply(cm); B = B.multiply(cm); T = T.divide(cm); S = S.divide(cm); Ai = PolyUtil.integerFromModularCoefficients(fac, A); Bi = PolyUtil.integerFromModularCoefficients(fac, B); // replace leading base coefficients ExpVector ea = Ai.leadingExpVector(); ExpVector eb = Bi.leadingExpVector(); Ai.doPutToMap(ea, c); Bi.doPutToMap(eb, c); // polynomials mod p GenPolynomial Ap; GenPolynomial Bp; GenPolynomial A1p = A; GenPolynomial B1p = B; GenPolynomial Ep; // polynomials over the integers GenPolynomial E; GenPolynomial Ea; GenPolynomial Eb; GenPolynomial Ea1; GenPolynomial Eb1; while (Mq.compareTo(M2) < 0) { // compute E=(C-AB)/q over the integers E = C.subtract(Ai.multiply(Bi)); if (E.isZERO()) { logger.info("leaving on zero E"); break; } try { E = E.divide(Qi); } catch (RuntimeException e) { // useful in debugging //System.out.println("C = " + C ); //System.out.println("Ai = " + Ai ); //System.out.println("Bi = " + Bi ); //System.out.println("E = " + E ); //System.out.println("Qi = " + Qi ); throw e; } // E mod p Ep = PolyUtil. fromIntegerCoefficients(pfac, E); //logger.info("Ep = {}", Ep); // construct approximation mod p Ap = S.multiply(Ep); // S,T ++ T,S Bp = T.multiply(Ep); GenPolynomial[] QR; QR = Ap.quotientRemainder(B); GenPolynomial Qp; GenPolynomial Rp; Qp = QR[0]; Rp = QR[1]; A1p = Rp; B1p = Bp.sum(A.multiply(Qp)); // construct q-adic approximation, convert to integer Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); Ea1 = Ea.multiply(Qi); Eb1 = Eb.multiply(Qi); Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required Eb = Bi.sum(Ea1); //-------------------------- assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0)); //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); //} // prepare for next iteration Mq = Qi; Qi = Q.getIntegerModul().multiply(P.getIntegerModul()); // Q = new ModIntegerRing(Qi.getVal()); if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); } else { Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); } Ai = Ea; Bi = Eb; } GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); // remove normalization BigInteger ai = ufd.baseContent(Ai); Ai = Ai.divide(ai); BigInteger bi = null; try { bi = c.divide(ai); Bi = Bi.divide(bi); // divide( c/a ) } catch (RuntimeException e) { //System.out.println("C = " + C ); //System.out.println("Ai = " + Ai ); //System.out.println("Bi = " + Bi ); //System.out.println("c = " + c ); //System.out.println("ai = " + ai ); //System.out.println("bi = " + bi ); //System.out.println("no exact lifting possible " + e); throw new NoLiftingException("no exact lifting possible " + e); } return new HenselApprox(Ai, Bi, A1p, B1p); } /** * Modular Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and * algorithms 3.5.{5,6} in Cohen. * @param C GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHensel( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B) throws NoLiftingException { if (C == null || C.isZERO()) { return new HenselApprox(C, C, A, B); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // one Hensel step on part polynomials try { GenPolynomial[] gst = A.egcd(B); if (!gst[0].isONE()) { throw new NoLiftingException( "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); } GenPolynomial s = gst[1]; GenPolynomial t = gst[2]; HenselApprox ab = HenselUtil. liftHensel(C, M, A, B, s, t); return ab; } catch (ArithmeticException e) { throw new NoLiftingException("coefficient error " + e); } } /** * Modular quadratic Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it * also lifts S A + T B == 1 mod p^{e+1}. * @param C GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param S GenPolynomial * @param T GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHenselQuadratic( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B, GenPolynomial S, GenPolynomial T) throws NoLiftingException { if (C == null || C.isZERO()) { return new HenselApprox(C, C, A, B); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // setup factories GenPolynomialRing pfac = A.ring; RingFactory p = pfac.coFac; RingFactory q = p; ModularRingFactory P = (ModularRingFactory) p; ModularRingFactory Q = (ModularRingFactory) q; BigInteger Qi = Q.getIntegerModul(); BigInteger M2 = M.multiply(M.fromInteger(2)); BigInteger Mq = Qi; GenPolynomialRing qfac; qfac = new GenPolynomialRing(Q, pfac); // normalize c and a, b factors, assert p is prime GenPolynomial Ai; GenPolynomial Bi; BigInteger c = C.leadingBaseCoefficient(); C = C.multiply(c); // sic MOD a = A.leadingBaseCoefficient(); if (!a.isONE()) { // A = A.monic(); A = A.divide(a); S = S.multiply(a); } MOD b = B.leadingBaseCoefficient(); if (!b.isONE()) { // B = B.monic(); B = B.divide(b); T = T.multiply(b); } MOD cm = P.fromInteger(c.getVal()); A = A.multiply(cm); B = B.multiply(cm); T = T.divide(cm); S = S.divide(cm); Ai = PolyUtil.integerFromModularCoefficients(fac, A); Bi = PolyUtil.integerFromModularCoefficients(fac, B); // replace leading base coefficients ExpVector ea = Ai.leadingExpVector(); ExpVector eb = Bi.leadingExpVector(); Ai.doPutToMap(ea, c); Bi.doPutToMap(eb, c); // polynomials mod p GenPolynomial Ap; GenPolynomial Bp; GenPolynomial A1p = A; GenPolynomial B1p = B; GenPolynomial Ep; GenPolynomial Sp = S; GenPolynomial Tp = T; // polynomials mod q GenPolynomial Aq; GenPolynomial Bq; //GenPolynomial Eq; // polynomials over the integers GenPolynomial E; GenPolynomial Ea; GenPolynomial Eb; GenPolynomial Ea1; GenPolynomial Eb1; GenPolynomial Si; GenPolynomial Ti; Si = PolyUtil.integerFromModularCoefficients(fac, S); Ti = PolyUtil.integerFromModularCoefficients(fac, T); Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai); Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi); while (Mq.compareTo(M2) < 0) { // compute E=(C-AB)/q over the integers E = C.subtract(Ai.multiply(Bi)); if (E.isZERO()) { logger.info("leaving on zero E"); break; } E = E.divide(Qi); // E mod p Ep = PolyUtil. fromIntegerCoefficients(qfac, E); //logger.info("Ep = {}, qfac = {}", Ep, qfac); //if (Ep.isZERO()) { //System.out.println("leaving on zero error"); //??logger.info("leaving on zero Ep"); //??break; //} // construct approximation mod p Ap = Sp.multiply(Ep); // S,T ++ T,S Bp = Tp.multiply(Ep); GenPolynomial[] QR; //logger.info("Ap = {}, Bp = {}, fac(Ap) = {}", Ap, Bp, Ap.ring); QR = Ap.quotientRemainder(Bq); GenPolynomial Qp; GenPolynomial Rp; Qp = QR[0]; Rp = QR[1]; //logger.info("Qp = {}, Rp = {}", Qp, Rp); A1p = Rp; B1p = Bp.sum(Aq.multiply(Qp)); // construct q-adic approximation, convert to integer Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); Ea1 = Ea.multiply(Qi); Eb1 = Eb.multiply(Qi); Ea = Ai.sum(Eb1); // Eb1 and Ea1 are required Eb = Bi.sum(Ea1); //-------------------------- assert (Ea.degree(0) + Eb.degree(0) <= C.degree(0)); //if ( Ea.degree(0)+Eb.degree(0) > C.degree(0) ) { // debug // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); //} Ai = Ea; Bi = Eb; // gcd representation factors error -------------------------------- // compute E=(1-SA-TB)/q over the integers E = fac.getONE(); E = E.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi)); E = E.divide(Qi); // E mod q Ep = PolyUtil. fromIntegerCoefficients(qfac, E); //logger.info("Ep2 = {}", Ep); // construct approximation mod q Ap = Sp.multiply(Ep); // S,T ++ T,S Bp = Tp.multiply(Ep); QR = Bp.quotientRemainder(Aq); // Ai == A mod p ? Qp = QR[0]; Rp = QR[1]; B1p = Rp; A1p = Ap.sum(Bq.multiply(Qp)); //if (debug) { // Eq = A1p.multiply(Aq).sum(B1p.multiply(Bq)).subtract(Ep); // if (!Eq.isZERO()) { // System.out.println("A*A1p+B*B1p-Ep2 != 0 " + Eq); // throw new RuntimeException("A*A1p+B*B1p-Ep2 != 0 mod " + Q.getIntegerModul()); // } //} // construct q-adic approximation, convert to integer Ea = PolyUtil.integerFromModularCoefficients(fac, A1p); Eb = PolyUtil.integerFromModularCoefficients(fac, B1p); Ea1 = Ea.multiply(Qi); Eb1 = Eb.multiply(Qi); Ea = Si.sum(Ea1); // Eb1 and Ea1 are required Eb = Ti.sum(Eb1); //-------------------------- Si = Ea; Ti = Eb; // prepare for next iteration Mq = Qi; Qi = Q.getIntegerModul().multiply(Q.getIntegerModul()); if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); } else { Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); } //Q = new ModIntegerRing(Qi.getVal()); //System.out.println("Q = " + Q + ", from Q = " + Mq); qfac = new GenPolynomialRing(Q, pfac); Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai); Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi); Sp = PolyUtil. fromIntegerCoefficients(qfac, Si); Tp = PolyUtil. fromIntegerCoefficients(qfac, Ti); //if (debug) { // E = Ai.multiply(Si).sum(Bi.multiply(Ti)); // Eq = PolyUtil. fromIntegerCoefficients(qfac, E); // if (!Eq.isONE()) { // System.out.println("Ai*Si+Bi*Ti=1 " + Eq); // throw new RuntimeException("Ai*Si+Bi*Ti != 1 mod " + Q.getIntegerModul()); // } //} } GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); // remove normalization if possible BigInteger ai = ufd.baseContent(Ai); Ai = Ai.divide(ai); BigInteger bi = null; try { bi = c.divide(ai); Bi = Bi.divide(bi); // divide( c/a ) } catch (RuntimeException e) { //System.out.println("C = " + C ); //System.out.println("Ai = " + Ai ); //System.out.println("Bi = " + Bi ); //System.out.println("c = " + c ); //System.out.println("ai = " + ai ); //System.out.println("bi = " + bi ); //System.out.println("no exact lifting possible " + e); throw new NoLiftingException("no exact lifting possible " + e); } return new HenselApprox(Ai, Bi, A1p, B1p); } /** * Modular quadratic Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and * algorithms 3.5.{5,6} in Cohen. Quadratic version. * @param C GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHenselQuadratic( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B) throws NoLiftingException { if (C == null || C.isZERO()) { return new HenselApprox(C, C, A, B); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // one Hensel step on part polynomials try { GenPolynomial[] gst = A.egcd(B); if (!gst[0].isONE()) { throw new NoLiftingException( "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); } GenPolynomial s = gst[1]; GenPolynomial t = gst[2]; HenselApprox ab = HenselUtil. liftHenselQuadratic(C, M, A, B, s, t); return ab; } catch (ArithmeticException e) { throw new NoLiftingException("coefficient error " + e); } } /** * Modular Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p. See algorithm 6.1. in Geddes et.al. and * algorithms 3.5.{5,6} in Cohen. Quadratic version. * @param C GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHenselQuadraticFac( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B) throws NoLiftingException { if (C == null || C.isZERO()) { throw new IllegalArgumentException("C must be nonzero"); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // one Hensel step on part polynomials try { GenPolynomial[] gst = A.egcd(B); if (!gst[0].isONE()) { throw new NoLiftingException( "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); } GenPolynomial s = gst[1]; GenPolynomial t = gst[2]; HenselApprox ab = HenselUtil. liftHenselQuadraticFac(C, M, A, B, s, t); return ab; } catch (ArithmeticException e) { throw new NoLiftingException("coefficient error " + e); } } /** * Modular Hensel lifting algorithm on coefficients. Let p = * A.ring.coFac.modul() = B.ring.coFac.modul() and assume C == A*B mod p * with gcd(A,B) == 1 mod p and S A + T B == 1 mod p. See algorithm 6.1. in * Geddes et.al. and algorithms 3.5.{5,6} in Cohen. Quadratic version, as it * also lifts S A + T B == 1 mod p^{e+1}. * @param C primitive GenPolynomial * @param A GenPolynomial * @param B other GenPolynomial * @param S GenPolynomial * @param T GenPolynomial * @param M bound on the coefficients of A1 and B1 as factors of C. * @return [A1,B1] = lift(C,A,B), with C = A1 * B1. */ @SuppressWarnings("unchecked") public static & Modular> HenselApprox liftHenselQuadraticFac( GenPolynomial C, BigInteger M, GenPolynomial A, GenPolynomial B, GenPolynomial S, GenPolynomial T) throws NoLiftingException { //System.out.println("*** version for factorization *** "); //GenPolynomial[] AB = new GenPolynomial[2]; if (C == null || C.isZERO()) { throw new IllegalArgumentException("C must be nonzero"); } if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // setup factories GenPolynomialRing pfac = A.ring; RingFactory p = pfac.coFac; RingFactory q = p; ModularRingFactory P = (ModularRingFactory) p; ModularRingFactory Q = (ModularRingFactory) q; BigInteger PP = Q.getIntegerModul(); BigInteger Qi = PP; BigInteger M2 = M.multiply(M.fromInteger(2)); if (debug) { //System.out.println("M2 = " + M2); logger.debug("M2 = {}", M2); } BigInteger Mq = Qi; GenPolynomialRing qfac; qfac = new GenPolynomialRing(Q, pfac); // mod p GenPolynomialRing mfac; BigInteger Mi = Q.getIntegerModul().multiply(Q.getIntegerModul()); ModularRingFactory Qmm; // = new ModIntegerRing(Mi.getVal()); if (ModLongRing.MAX_LONG.compareTo(Mi.getVal()) > 0) { Qmm = (ModularRingFactory) new ModLongRing(Mi.getVal()); } else { Qmm = (ModularRingFactory) new ModIntegerRing(Mi.getVal()); } mfac = new GenPolynomialRing(Qmm, qfac); // mod p^e MOD Qm = Qmm.fromInteger(Qi.getVal()); // partly normalize c and a, b factors, assert p is prime GenPolynomial Ai; GenPolynomial Bi; BigInteger c = C.leadingBaseCoefficient(); C = C.multiply(c); // sic MOD a = A.leadingBaseCoefficient(); if (!a.isONE()) { // A = A.monic(); A = A.divide(a); S = S.multiply(a); } MOD b = B.leadingBaseCoefficient(); if (!b.isONE()) { // B = B.monic(); B = B.divide(b); T = T.multiply(b); } MOD cm = P.fromInteger(c.getVal()); if (cm.isZERO()) { System.out.println("c = " + c); System.out.println("P = " + P); throw new ArithmeticException("c mod p == 0 not meaningful"); } // mod p A = A.multiply(cm); S = S.divide(cm); B = B.multiply(cm); T = T.divide(cm); Ai = PolyUtil.integerFromModularCoefficients(fac, A); Bi = PolyUtil.integerFromModularCoefficients(fac, B); // replace leading base coefficients ExpVector ea = Ai.leadingExpVector(); ExpVector eb = Bi.leadingExpVector(); Ai.doPutToMap(ea, c); Bi.doPutToMap(eb, c); // polynomials mod p GenPolynomial Ap; GenPolynomial Bp; GenPolynomial A1p = A; GenPolynomial B1p = B; GenPolynomial Sp = S; GenPolynomial Tp = T; // polynomials mod q GenPolynomial Aq; GenPolynomial Bq; // polynomials mod p^e GenPolynomial Cm; GenPolynomial Am; GenPolynomial Bm; GenPolynomial Em; GenPolynomial Emp; GenPolynomial Sm; GenPolynomial Tm; GenPolynomial Ema; GenPolynomial Emb; GenPolynomial Ema1; GenPolynomial Emb1; // polynomials over the integers GenPolynomial Ei; GenPolynomial Si; GenPolynomial Ti; Si = PolyUtil.integerFromModularCoefficients(fac, S); Ti = PolyUtil.integerFromModularCoefficients(fac, T); Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai); Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi); // polynomials mod p^e Cm = PolyUtil. fromIntegerCoefficients(mfac, C); Am = PolyUtil. fromIntegerCoefficients(mfac, Ai); Bm = PolyUtil. fromIntegerCoefficients(mfac, Bi); Sm = PolyUtil. fromIntegerCoefficients(mfac, Si); Tm = PolyUtil. fromIntegerCoefficients(mfac, Ti); //System.out.println("Cm = " + Cm); //System.out.println("Am = " + Am); //System.out.println("Bm = " + Bm); //System.out.println("Ai = " + Ai); //System.out.println("Bi = " + Bi); //System.out.println("mfac = " + mfac); while (Mq.compareTo(M2) < 0) { // compute E=(C-AB)/p mod p^e if (debug) { //System.out.println("mfac = " + Cm.ring); logger.debug("mfac = {}", Cm.ring); } Em = Cm.subtract(Am.multiply(Bm)); //System.out.println("Em = " + Em); if (Em.isZERO()) { if (C.subtract(Ai.multiply(Bi)).isZERO()) { logger.info("leaving on zero E"); break; } } // Em = Em.divide( Qm ); Ei = PolyUtil.integerFromModularCoefficients(fac, Em); Ei = Ei.divide(Qi); //System.out.println("Ei = " + Ei); // Ei mod p Emp = PolyUtil. fromIntegerCoefficients(qfac, Ei); // Emp = PolyUtil.fromIntegerCoefficients(qfac, // PolyUtil.integerFromModularCoefficients(fac,Em) ); //System.out.println("Emp = " + Emp); //logger.info("Emp = {}", Emp); if (Emp.isZERO()) { if (C.subtract(Ai.multiply(Bi)).isZERO()) { logger.info("leaving on zero Emp"); break; } } // construct approximation mod p Ap = Sp.multiply(Emp); // S,T ++ T,S Bp = Tp.multiply(Emp); GenPolynomial[] QR = null; QR = Ap.quotientRemainder(Bq); // Bq ! GenPolynomial Qp = QR[0]; GenPolynomial Rp = QR[1]; A1p = Rp; B1p = Bp.sum(Aq.multiply(Qp)); // Aq ! //System.out.println("A1p = " + A1p); //System.out.println("B1p = " + B1p); // construct q-adic approximation Ema = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, A1p)); Emb = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, B1p)); //System.out.println("Ema = " + Ema); //System.out.println("Emb = " + Emb); Ema1 = Ema.multiply(Qm); Emb1 = Emb.multiply(Qm); Ema = Am.sum(Emb1); // Eb1 and Ea1 are required Emb = Bm.sum(Ema1); //-------------------------- assert (Ema.degree(0) + Emb.degree(0) <= Cm.degree(0)); //if ( Ema.degree(0)+Emb.degree(0) > Cm.degree(0) ) { // debug // throw new RuntimeException("deg(A)+deg(B) > deg(C)"); //} Am = Ema; Bm = Emb; Ai = PolyUtil.integerFromModularCoefficients(fac, Am); Bi = PolyUtil.integerFromModularCoefficients(fac, Bm); //System.out.println("Am = " + Am); //System.out.println("Bm = " + Bm); //System.out.println("Ai = " + Ai); //System.out.println("Bi = " + Bi + "\n"); // gcd representation factors error -------------------------------- // compute E=(1-SA-TB)/p mod p^e Em = mfac.getONE(); Em = Em.subtract(Sm.multiply(Am)).subtract(Tm.multiply(Bm)); //System.out.println("Em = " + Em); // Em = Em.divide( Pm ); Ei = PolyUtil.integerFromModularCoefficients(fac, Em); Ei = Ei.divide(Qi); //System.out.println("Ei = " + Ei); // Ei mod p Emp = PolyUtil. fromIntegerCoefficients(qfac, Ei); //Emp = PolyUtil.fromIntegerCoefficients(qfac, // PolyUtil.integerFromModularCoefficients(fac,Em) ); //System.out.println("Emp = " + Emp); // construct approximation mod p Ap = Sp.multiply(Emp); // S,T ++ T,S // Ep Eqp Bp = Tp.multiply(Emp); // Ep Eqp QR = Bp.quotientRemainder(Aq); // Ap Aq ! // Ai == A mod p ? Qp = QR[0]; Rp = QR[1]; B1p = Rp; A1p = Ap.sum(Bq.multiply(Qp)); //System.out.println("A1p = " + A1p); //System.out.println("B1p = " + B1p); // construct p^e-adic approximation Ema = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, A1p)); Emb = PolyUtil. fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, B1p)); Ema1 = Ema.multiply(Qm); Emb1 = Emb.multiply(Qm); Ema = Sm.sum(Ema1); // Emb1 and Ema1 are required Emb = Tm.sum(Emb1); //-------------------------- Sm = Ema; Tm = Emb; Si = PolyUtil.integerFromModularCoefficients(fac, Sm); Ti = PolyUtil.integerFromModularCoefficients(fac, Tm); //System.out.println("Sm = " + Sm); //System.out.println("Tm = " + Tm); //System.out.println("Si = " + Si); //System.out.println("Ti = " + Ti + "\n"); // prepare for next iteration Qi = Q.getIntegerModul().multiply(Q.getIntegerModul()); Mq = Qi; //lmfac = mfac; // Q = new ModIntegerRing(Qi.getVal()); if (ModLongRing.MAX_LONG.compareTo(Qi.getVal()) > 0) { Q = (ModularRingFactory) new ModLongRing(Qi.getVal()); } else { Q = (ModularRingFactory) new ModIntegerRing(Qi.getVal()); } qfac = new GenPolynomialRing(Q, pfac); BigInteger Qmmi = Qmm.getIntegerModul().multiply(Qmm.getIntegerModul()); //Qmm = new ModIntegerRing(Qmmi.getVal()); if (ModLongRing.MAX_LONG.compareTo(Qmmi.getVal()) > 0) { Qmm = (ModularRingFactory) new ModLongRing(Qmmi.getVal()); } else { Qmm = (ModularRingFactory) new ModIntegerRing(Qmmi.getVal()); } mfac = new GenPolynomialRing(Qmm, qfac); Qm = Qmm.fromInteger(Qi.getVal()); Cm = PolyUtil. fromIntegerCoefficients(mfac, C); Am = PolyUtil. fromIntegerCoefficients(mfac, Ai); Bm = PolyUtil. fromIntegerCoefficients(mfac, Bi); Sm = PolyUtil. fromIntegerCoefficients(mfac, Si); Tm = PolyUtil. fromIntegerCoefficients(mfac, Ti); assert (isHenselLift(C, Mi, PP, Ai, Bi)); Mi = Mi.fromInteger(Qmm.getIntegerModul().getVal()); Aq = PolyUtil. fromIntegerCoefficients(qfac, Ai); Bq = PolyUtil. fromIntegerCoefficients(qfac, Bi); Sp = PolyUtil. fromIntegerCoefficients(qfac, Si); Tp = PolyUtil. fromIntegerCoefficients(qfac, Ti); //System.out.println("Am = " + Am); //System.out.println("Bm = " + Bm); //System.out.println("Sm = " + Sm); //System.out.println("Tm = " + Tm); //System.out.println("mfac = " + mfac); //System.out.println("Qmm = " + Qmm + ", M2 = " + M2 + ", Mq = " + Mq + "\n"); } //System.out.println("*Ai = " + Ai); //System.out.println("*Bi = " + Bi); Em = Cm.subtract(Am.multiply(Bm)); if (!Em.isZERO()) { System.out.println("Em = " + Em); //throw new NoLiftingException("no exact lifting possible"); } // remove normalization not possible when not exact factorization GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); // remove normalization if possible BigInteger ai = ufd.baseContent(Ai); Ai = Ai.divide(ai); // Ai=pp(Ai) BigInteger[] qr = c.quotientRemainder(ai); BigInteger bi = null; boolean exact = true; if (qr[1].isZERO()) { bi = qr[0]; try { Bi = Bi.divide(bi); // divide( c/a ) } catch (RuntimeException e) { System.out.println("*catch: no exact factorization: " + bi + ", e = " + e); exact = false; } } else { System.out.println("*remainder: no exact factorization: q = " + qr[0] + ", r = " + qr[1]); exact = false; } if (!exact) { System.out.println("*Ai = " + Ai); System.out.println("*ai = " + ai); System.out.println("*Bi = " + Bi); System.out.println("*bi = " + bi); System.out.println("*c = " + c); throw new NoLiftingException("no exact lifting possible"); } return new HenselApprox(Ai, Bi, Aq, Bq); } /** * Modular Hensel lifting test. Let p be a prime number and assume C == * prod_{0,...,n-1} g_i mod p with gcd(g_i,g_j) == 1 mod p for i != j. * @param C GenPolynomial * @param G = [g_0,...,g_{n-1}] list of GenPolynomial * @param M bound on the coefficients of g_i as factors of C. * @param p prime number. * @return true if C = prod_{0,...,n-1} g_i mod p^e, else false. */ public static// & Modular> boolean isHenselLift(GenPolynomial C, BigInteger M, BigInteger p, List> G) { if (C == null || C.isZERO()) { return false; } GenPolynomialRing pfac = C.ring; ModIntegerRing pm = new ModIntegerRing(p.getVal(), true); GenPolynomialRing mfac = new GenPolynomialRing(pm, pfac); // check mod p GenPolynomial cl = mfac.getONE(); GenPolynomial hlp; for (GenPolynomial hl : G) { //System.out.println("hl = " + hl); hlp = PolyUtil. fromIntegerCoefficients(mfac, hl); //System.out.println("hl mod p = " + hlp); cl = cl.multiply(hlp); } GenPolynomial cp = PolyUtil. fromIntegerCoefficients(mfac, C); if (!cp.equals(cl)) { System.out.println("Hensel precondition wrong!"); if (debug) { System.out.println("cl = " + cl); System.out.println("cp = " + cp); System.out.println("mon(cl) = " + cl.monic()); System.out.println("mon(cp) = " + cp.monic()); System.out.println("cp-cl = " + cp.subtract(cl)); System.out.println("M = " + M + ", p = " + p); } return false; } // check mod p^e BigInteger mip = p; while (mip.compareTo(M) < 0) { mip = mip.multiply(mip); // p } // mip = mip.multiply(p); pm = new ModIntegerRing(mip.getVal(), false); mfac = new GenPolynomialRing(pm, pfac); cl = mfac.getONE(); for (GenPolynomial hl : G) { //System.out.println("hl = " + hl); hlp = PolyUtil. fromIntegerCoefficients(mfac, hl); //System.out.println("hl mod p^e = " + hlp); cl = cl.multiply(hlp); } cp = PolyUtil. fromIntegerCoefficients(mfac, C); if (!cp.equals(cl)) { System.out.println("Hensel post condition wrong!"); System.out.println("cl = " + cl); System.out.println("cp = " + cp); System.out.println("cp-cl = " + cp.subtract(cl)); System.out.println("M = " + M + ", p = " + p + ", p^e = " + mip); return false; } return true; } /** * Modular Hensel lifting test. Let p be a prime number and assume C == A * * B mod p with gcd(A,B) == 1 mod p. * @param C GenPolynomial * @param A GenPolynomial * @param B GenPolynomial * @param M bound on the coefficients of A and B as factors of C. * @param p prime number. * @return true if C = A * B mod p**e, else false. */ public static// & Modular> boolean isHenselLift(GenPolynomial C, BigInteger M, BigInteger p, GenPolynomial A, GenPolynomial B) { List> G = new ArrayList>(2); G.add(A); G.add(B); return isHenselLift(C, M, p, G); } /** * Modular Hensel lifting test. Let p be a prime number and assume C == A * * B mod p with gcd(A,B) == 1 mod p. * @param C GenPolynomial * @param Ha Hensel approximation. * @param M bound on the coefficients of A and B as factors of C. * @param p prime number. * @return true if C = A * B mod p^e, else false. */ public static & Modular> boolean isHenselLift(GenPolynomial C, BigInteger M, BigInteger p, HenselApprox Ha) { List> G = new ArrayList>(2); G.add(Ha.A); G.add(Ha.B); return isHenselLift(C, M, p, G); } /** * Constructing and lifting algorithm for extended Euclidean relation. Let p * = A.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. * @param A modular GenPolynomial * @param B modular GenPolynomial * @param k desired approximation exponent p^k. * @return [s,t] with s A + t B = 1 mod p^k. */ @SuppressWarnings("unchecked") public static & Modular> GenPolynomial[] liftExtendedEuclidean( GenPolynomial A, GenPolynomial B, long k) throws NoLiftingException { if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B); } GenPolynomialRing fac = A.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // start with extended Euclidean relation mod p GenPolynomial[] gst = null; try { gst = A.egcd(B); if (!gst[0].isONE()) { throw new NoLiftingException( "A and B not coprime, gcd = " + gst[0] + ", A = " + A + ", B = " + B); } } catch (ArithmeticException e) { throw new NoLiftingException("coefficient error " + e); } GenPolynomial S = gst[1]; GenPolynomial T = gst[2]; //System.out.println("eeS = " + S + ": " + S.ring.coFac); //System.out.println("eeT = " + T + ": " + T.ring.coFac); // setup integer polynomial ring GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); GenPolynomial one = ifac.getONE(); GenPolynomial Ai = PolyUtil.integerFromModularCoefficients(ifac, A); GenPolynomial Bi = PolyUtil.integerFromModularCoefficients(ifac, B); GenPolynomial Si = PolyUtil.integerFromModularCoefficients(ifac, S); GenPolynomial Ti = PolyUtil.integerFromModularCoefficients(ifac, T); //System.out.println("Ai = " + Ai); //System.out.println("Bi = " + Bi); //System.out.println("Si = " + Si); //System.out.println("Ti = " + Ti); // approximate mod p^i ModularRingFactory mcfac = (ModularRingFactory) fac.coFac; BigInteger p = mcfac.getIntegerModul(); BigInteger modul = p; GenPolynomialRing mfac; // = new GenPolynomialRing(mcfac, fac); for (int i = 1; i < k; i++) { // e = 1 - s a - t b in Z[x] GenPolynomial e = one.subtract(Si.multiply(Ai)).subtract(Ti.multiply(Bi)); //System.out.println("\ne = " + e); if (e.isZERO()) { logger.info("leaving on zero e in liftExtendedEuclidean"); break; } e = e.divide(modul); // move to Z_p[x] and compute next approximation GenPolynomial c = PolyUtil. fromIntegerCoefficients(fac, e); //System.out.println("c = " + c + ": " + c.ring.coFac); GenPolynomial s = S.multiply(c); GenPolynomial t = T.multiply(c); //System.out.println("s = " + s + ": " + s.ring.coFac); //System.out.println("t = " + t + ": " + t.ring.coFac); GenPolynomial[] QR = s.quotientRemainder(B); // watch for ordering GenPolynomial q = QR[0]; s = QR[1]; t = t.sum(q.multiply(A)); //System.out.println("s = " + s + ": " + s.ring.coFac); //System.out.println("t = " + t + ": " + t.ring.coFac); GenPolynomial si = PolyUtil.integerFromModularCoefficients(ifac, s); GenPolynomial ti = PolyUtil.integerFromModularCoefficients(ifac, t); //System.out.println("si = " + si); //System.out.println("ti = " + si); // add approximation to solution Si = Si.sum(si.multiply(modul)); Ti = Ti.sum(ti.multiply(modul)); //System.out.println("Si = " + Si); //System.out.println("Ti = " + Ti); modul = modul.multiply(p); //System.out.println("modul = " + modul + ", " + p + "^" + i + ", p^i = " + p.power(i)); } //System.out.println("Si = " + Si + ", Ti = " + Ti); // setup ring mod p^i if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); } //System.out.println("mcfac = " + mcfac); mfac = new GenPolynomialRing(mcfac, fac); S = PolyUtil. fromIntegerCoefficients(mfac, Si); T = PolyUtil. fromIntegerCoefficients(mfac, Ti); //System.out.println("S = " + S + ": " + S.ring.coFac); //System.out.println("T = " + T + ": " + T.ring.coFac); if (debug) { List> AP = new ArrayList>(); AP.add(B); AP.add(A); List> SP = new ArrayList>(); SP.add(S); SP.add(T); if (!HenselUtil. isExtendedEuclideanLift(AP, SP)) { System.out.println("isExtendedEuclideanLift: false"); } } @SuppressWarnings("cast") GenPolynomial[] rel = (GenPolynomial[]) new GenPolynomial[2]; rel[0] = S; rel[1] = T; return rel; } /** * Constructing and lifting algorithm for extended Euclidean relation. Let p * = A_i.ring.coFac.modul() and assume gcd(A_i,A_j) == 1 mod p, i != j. * @param A list of modular GenPolynomials * @param k desired approximation exponent p^k. * @return [s_0,...,s_n-1] with sum_i s_i * B_i = 1 mod p^k, with B_i = * prod_{i!=j} A_j. */ public static & Modular> List> liftExtendedEuclidean( List> A, long k) throws NoLiftingException { if (A == null || A.size() <= 1) { throw new IllegalArgumentException("A must be non null and non empty"); } GenPolynomialRing fac = A.get(0).ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } GenPolynomial zero = fac.getZERO(); int r = A.size(); List> Q = new ArrayList>(r); for (int i = 0; i < r; i++) { Q.add(zero); } //System.out.println("A = " + A); Q.set(r - 2, A.get(r - 1)); for (int j = r - 3; j >= 0; j--) { GenPolynomial q = A.get(j + 1).multiply(Q.get(j + 1)); Q.set(j, q); } //System.out.println("Q = " + Q); List> B = new ArrayList>(r + 1); List> lift = new ArrayList>(r); for (int i = 0; i < r; i++) { B.add(zero); lift.add(zero); } GenPolynomial one = fac.getONE(); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); B.add(0, one); //System.out.println("B(0) = " + B.get(0)); GenPolynomial b = one; for (int j = 0; j < r - 1; j++) { //System.out.println("Q("+(j)+") = " + Q.get(j)); //System.out.println("A("+(j)+") = " + A.get(j)); //System.out.println("B("+(j)+") = " + B.get(j)); List> S = liftDiophant(Q.get(j), A.get(j), B.get(j), k); //System.out.println("\nSb = " + S); b = S.get(0); GenPolynomial bb = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b)); B.set(j + 1, bb); lift.set(j, S.get(1)); //System.out.println("B("+(j+1)+") = " + B.get(j+1)); if (debug) { logger.info("lift({}) = {}", j, lift.get(j)); } } //System.out.println("liftb = " + lift); lift.set(r - 1, b); if (debug) { logger.info("lift({}) = {}", (r - 1), b); } //System.out.println("B("+(r-1)+") = " + B.get(r-1) + " : " + B.get(r-1).ring.coFac + ", b = " + b + " : " + b.ring.coFac); //System.out.println("B = " + B); //System.out.println("liftb = " + lift); return lift; } /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. * @param A modular GenPolynomial, mod p^k * @param B modular GenPolynomial, mod p^k * @param C modular GenPolynomial, mod p^k * @param k desired approximation exponent p^k. * @return [s, t] with s A' + t B' = C mod p^k, with A' = B, B' = A. */ public static & Modular> List> liftDiophant( GenPolynomial A, GenPolynomial B, GenPolynomial C, long k) throws NoLiftingException { if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException( "A and B must be nonzero, A = " + A + ", B = " + B + ", C = " + C); } List> sol = new ArrayList>(); GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } //System.out.println("C = " + C); GenPolynomial zero = fac.getZERO(); for (int i = 0; i < 2; i++) { sol.add(zero); } GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); for (Monomial m : C) { //System.out.println("monomial = " + m); long e = m.e.getVal(0); List> S = liftDiophant(A, B, e, k); //System.out.println("Se = " + S); MOD a = m.c; //System.out.println("C.fac = " + fac.toScript()); a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal()); int i = 0; for (GenPolynomial d : S) { //System.out.println("d = " + d); d = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, d)); d = d.multiply(a); d = sol.get(i).sum(d); //System.out.println("d = " + d); sol.set(i++, d); } //System.out.println("sol = " + sol + ", for " + m); } if (debug) { //GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); A = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); B = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); C = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C)); GenPolynomial y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1))); if (!y.equals(C)) { System.out.println("A = " + A + ", B = " + B); System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1)); System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac); } } return sol; } /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A. * @param A list of modular GenPolynomials, mod p^k * @param C modular GenPolynomial, mod p^k * @param k desired approximation exponent p^k. * @return [s_1,..., s_n] with sum_i s_i A_i' = C mod p^k, with Ai' = * prod_{j!=i} A_j. */ public static & Modular> List> liftDiophant( List> A, GenPolynomial C, long k) throws NoLiftingException { if (false && A.size() <= 2) { return HenselUtil. liftDiophant(A.get(0), A.get(1), C, k); } List> sol = new ArrayList>(); GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } //System.out.println("C = " + C); GenPolynomial zero = fac.getZERO(); for (int i = 0; i < A.size(); i++) { sol.add(zero); } GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); for (Monomial m : C) { //System.out.println("monomial = " + m); long e = m.e.getVal(0); List> S = liftDiophant(A, e, k); //System.out.println("Se = " + S); MOD a = m.c; //System.out.println("C.fac = " + fac.toScript()); a = fac.coFac.fromInteger(a.getSymmetricInteger().getVal()); int i = 0; for (GenPolynomial d : S) { //System.out.println("d = " + d); d = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, d)); d = d.multiply(a); d = sol.get(i).sum(d); //System.out.println("d = " + d); sol.set(i++, d); } //System.out.println("sol = " + sol + ", for " + m); } /* if (true || debug) { //GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); A = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); B = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); C = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, C)); GenPolynomial y = B.multiply(sol.get(0)).sum(A.multiply(sol.get(1))); if (!y.equals(C)) { System.out.println("A = " + A + ", B = " + B); System.out.println("s1 = " + sol.get(0) + ", s2 = " + sol.get(1)); System.out.println("Error: A*r1 + B*r2 = " + y + " : " + fac.coFac); } } */ return sol; } /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume gcd(A,B) == 1 mod p. * @param A modular GenPolynomial * @param B modular GenPolynomial * @param e exponent for x^e * @param k desired approximation exponent p^k. * @return [s, t] with s A' + t B' = x^e mod p^k, with A' = B, B' = A. */ public static & Modular> List> liftDiophant( GenPolynomial A, GenPolynomial B, long e, long k) throws NoLiftingException { if (A == null || A.isZERO() || B == null || B.isZERO()) { throw new IllegalArgumentException("A and B must be nonzero, A = " + A + ", B = " + B); } List> sol = new ArrayList>(); GenPolynomialRing fac = A.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // lift EE relation to p^k GenPolynomial[] lee = liftExtendedEuclidean(B, A, k); GenPolynomial s1 = lee[0]; GenPolynomial s2 = lee[1]; if (e == 0L) { sol.add(s1); sol.add(s2); //System.out.println("sol@0 = " + sol); return sol; } fac = s1.ring; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); A = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); B = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); // this is the wrong sequence: // GenPolynomial xe = fac.univariate(0,e); // GenPolynomial q = s1.multiply(xe); // GenPolynomial[] QR = q.quotientRemainder(B); // q = QR[0]; // GenPolynomial r1 = QR[1]; // GenPolynomial r2 = s2.multiply(xe).sum( q.multiply(A) ); GenPolynomial xe = fac.univariate(0, e); GenPolynomial q = s1.multiply(xe); GenPolynomial[] QR = q.quotientRemainder(A); q = QR[0]; //System.out.println("ee coeff qr = " + Arrays.toString(QR)); GenPolynomial r1 = QR[1]; GenPolynomial r2 = s2.multiply(xe).sum(q.multiply(B)); //System.out.println("r1 = " + r1 + ", r2 = " + r2); sol.add(r1); sol.add(r2); //System.out.println("sol@"+ e + " = " + sol); if (debug) { GenPolynomial y = B.multiply(r1).sum(A.multiply(r2)); if (!y.equals(xe)) { System.out.println("A = " + A + ", B = " + B); System.out.println("r1 = " + r1 + ", r2 = " + r2); System.out.println("Error: A*r1 + B*r2 = " + y); } } return sol; } /** * Modular diophantine equation solution and lifting algorithm. Let p = * A_i.ring.coFac.modul() and assume gcd(a,b) == 1 mod p, for a, b in A. * @param A list of modular GenPolynomials * @param e exponent for x^e * @param k desired approximation exponent p^k. * @return [s_1,..., s_n] with sum_i s_i A_i' = x^e mod p^k, with Ai' = * prod_{j!=i} A_j. */ public static & Modular> List> liftDiophant( List> A, long e, long k) throws NoLiftingException { if (false && A.size() <= 2) { return HenselUtil. liftDiophant(A.get(0), A.get(1), e, k); } List> sol = new ArrayList>(); GenPolynomialRing fac = A.get(0).ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } // lift EE relation to p^k List> lee = liftExtendedEuclidean(A, k); if (e == 0L) { //System.out.println("sol@0 = " + sol); return lee; } fac = lee.get(0).ring; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); List> S = new ArrayList>(lee.size()); for (GenPolynomial a : lee) { a = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, a)); S.add(a); } GenPolynomial xe = fac.univariate(0, e); //List> Sr = new ArrayList>(lee.size()); int i = 0; for (GenPolynomial s : S) { GenPolynomial q = s.multiply(xe); GenPolynomial r = q.remainder(A.get(i++)); //System.out.println("r = " + r); sol.add(r); } //System.out.println("sol@"+ e + " = " + sol); /* if (true || debug) { GenPolynomial y = B.multiply(r1).sum(A.multiply(r2)); if (!y.equals(xe)) { System.out.println("A = " + A + ", B = " + B); System.out.println("r1 = " + r1 + ", r2 = " + r2); System.out.println("Error: A*r1 + B*r2 = " + y); } } */ return sol; } /** * Modular Diophant relation lifting test. * @param A modular GenPolynomial * @param B modular GenPolynomial * @param C modular GenPolynomial * @param S1 modular GenPolynomial * @param S2 modular GenPolynomial * @return true if A*S1 + B*S2 = C, else false. */ public static & Modular> boolean isDiophantLift(GenPolynomial A, GenPolynomial B, GenPolynomial S1, GenPolynomial S2, GenPolynomial C) { GenPolynomialRing fac = C.ring; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); GenPolynomial a = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, A)); GenPolynomial b = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, B)); GenPolynomial s1 = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, S1)); GenPolynomial s2 = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, S2)); GenPolynomial t = a.multiply(s1).sum(b.multiply(s2)); if (t.equals(C)) { return true; } if (debug) { System.out.println("a = " + a); System.out.println("b = " + b); System.out.println("s1 = " + s1); System.out.println("s2 = " + s2); System.out.println("t = " + t); System.out.println("C = " + C); } return false; } /** * Modular extended Euclidean relation lifting test. * @param A list of GenPolynomials * @param S = [s_0,...,s_{n-1}] list of GenPolynomial * @return true if prod_{0,...,n-1} s_i * B_i = 1 mod p^e, with B_i = * prod_{i!=j} A_j, else false. */ public static & Modular> boolean isExtendedEuclideanLift( List> A, List> S) { GenPolynomialRing fac = A.get(0).ring; GenPolynomial C = fac.getONE(); return isDiophantLift(A, S, C); } /** * Modular Diophant relation lifting test. * @param A list of GenPolynomials * @param S = [s_0,...,s_{n-1}] list of GenPolynomials * @param C = GenPolynomial * @return true if prod_{0,...,n-1} s_i * B_i = C mod p^k, with B_i = * prod_{i!=j} A_j, else false. */ public static & Modular> boolean isDiophantLift(List> A, List> S, GenPolynomial C) { GenPolynomialRing fac = A.get(0).ring; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); List> B = new ArrayList>(A.size()); int i = 0; for (GenPolynomial ai : A) { GenPolynomial b = fac.getONE(); int j = 0; for (GenPolynomial aj : A) { if (i != j /*!ai.equals(aj)*/) { b = b.multiply(aj); } j++; } //System.out.println("b = " + b); b = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b)); B.add(b); i++; } //System.out.println("B = " + B); // check mod p^e GenPolynomial t = fac.getZERO(); i = 0; for (GenPolynomial a : B) { GenPolynomial b = S.get(i++); b = PolyUtil. fromIntegerCoefficients(fac, PolyUtil.integerFromModularCoefficients(ifac, b)); GenPolynomial s = a.multiply(b); t = t.sum(s); } if (!t.equals(C)) { if (debug) { System.out.println("no diophant lift!"); System.out.println("A = " + A); System.out.println("B = " + B); System.out.println("S = " + S); System.out.println("C = " + C); System.out.println("t = " + t); } return false; } return true; } /** * Modular Hensel lifting algorithm on coefficients. Let p = * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with * gcd(f_i,f_j) == 1 mod p for i != j * @param C monic integer polynomial * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials. * @param k approximation exponent. * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k. */ @SuppressWarnings("unchecked") public static & Modular> List> liftHenselMonic( GenPolynomial C, List> F, long k) throws NoLiftingException { if (C == null || C.isZERO() || F == null || F.size() == 0) { throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } List> lift = new ArrayList>(F.size()); GenPolynomialRing pfac = F.get(0).ring; RingFactory pcfac = pfac.coFac; ModularRingFactory PF = (ModularRingFactory) pcfac; BigInteger P = PF.getIntegerModul(); int n = F.size(); if (n == 1) { // lift F_0, this case will probably never be used GenPolynomial f = F.get(0); ModularRingFactory mcfac; if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(P.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal()); } GenPolynomialRing mfac = new GenPolynomialRing(mcfac, fac); f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f)); lift.add(f); return lift; } // if (n == 2) { // only one step // HenselApprox ab = HenselUtil. liftHenselQuadratic(C, M, F.get(0), F.get(1)); // lift.add(ab.Am); // lift.add(ab.Bm); // return lift; // } // setup integer polynomial ring GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); List> Fi = PolyUtil.integerFromModularCoefficients(ifac, F); //System.out.println("Fi = " + Fi); List> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this //System.out.println("Sext = " + S); if (debug) { logger.info("EE lift = {}", S); // adjust coefficients List> Sx = PolyUtil.fromIntegerCoefficients(pfac, PolyUtil.integerFromModularCoefficients(ifac, S)); try { boolean il = HenselUtil. isExtendedEuclideanLift(F, Sx); //System.out.println("islift = " + il); } catch (RuntimeException e) { e.printStackTrace(); } } List> Si = PolyUtil.integerFromModularCoefficients(ifac, S); //System.out.println("Si = " + Si); //System.out.println("C = " + C); // approximate mod p^i ModularRingFactory mcfac = PF; BigInteger p = mcfac.getIntegerModul(); BigInteger modul = p; GenPolynomialRing mfac = new GenPolynomialRing(mcfac, fac); List> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si); //System.out.println("Sp = " + Sp); for (int i = 1; i < k; i++) { //System.out.println("i = " + i); GenPolynomial e = fac.getONE(); for (GenPolynomial fi : Fi) { e = e.multiply(fi); } e = C.subtract(e); //System.out.println("\ne = " + e); if (e.isZERO()) { logger.info("leaving on zero e"); break; } try { e = e.divide(modul); } catch (RuntimeException ex) { ex.printStackTrace(); throw ex; } //System.out.println("e = " + e); // move to in Z_p[x] GenPolynomial c = PolyUtil. fromIntegerCoefficients(mfac, e); //System.out.println("c = " + c + ": " + c.ring.coFac); List> s = new ArrayList>(S.size()); int j = 0; for (GenPolynomial f : Sp) { f = f.multiply(c); //System.out.println("f = " + f + " : " + f.ring.coFac); //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac); f = f.remainder(F.get(j++)); //System.out.println("f = " + f + " : " + f.ring.coFac); s.add(f); } //System.out.println("s = " + s); List> si = PolyUtil.integerFromModularCoefficients(ifac, s); //System.out.println("si = " + si); List> Fii = new ArrayList>(F.size()); j = 0; for (GenPolynomial f : Fi) { f = f.sum(si.get(j++).multiply(modul)); Fii.add(f); } //System.out.println("Fii = " + Fii); Fi = Fii; modul = modul.multiply(p); if (i >= k - 1) { logger.info("e != 0 for k = {}", k); } } // setup ring mod p^k modul = p.power(k); if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); } //System.out.println("mcfac = " + mcfac); mfac = new GenPolynomialRing(mcfac, fac); lift = PolyUtil. fromIntegerCoefficients(mfac, Fi); //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac); return lift; } /** * Modular Hensel lifting algorithm on coefficients. Let p = * f_i.ring.coFac.modul() and assume C == prod_{0,...,n-1} f_i mod p with * gcd(f_i,f_j) == 1 mod p for i != j * @param C integer polynomial * @param F = [f_0,...,f_{n-1}] list of monic modular polynomials. * @param k approximation exponent. * @param g leading coefficient. * @return [g_0,...,g_{n-1}] with C = prod_{0,...,n-1} g_i mod p^k. */ @SuppressWarnings("unchecked") public static & Modular> List> liftHensel( GenPolynomial C, List> F, long k, BigInteger g) throws NoLiftingException { if (C == null || C.isZERO() || F == null || F.size() == 0) { throw new IllegalArgumentException("C must be nonzero and F must be nonempty"); } GenPolynomialRing fac = C.ring; if (fac.nvar != 1) { // assert ? throw new IllegalArgumentException("polynomial ring not univariate"); } List> lift = new ArrayList>(F.size()); GenPolynomialRing pfac = F.get(0).ring; RingFactory pcfac = pfac.coFac; ModularRingFactory PF = (ModularRingFactory) pcfac; BigInteger P = PF.getIntegerModul(); int n = F.size(); if (n == 1) { // lift F_0, this case will probably never be used GenPolynomial f = F.get(0); ModularRingFactory mcfac; if (ModLongRing.MAX_LONG.compareTo(P.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(P.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(P.getVal()); } GenPolynomialRing mfac = new GenPolynomialRing(mcfac, fac); f = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(fac, f)); lift.add(f); return lift; } // if (n == 2) { // only one step // HenselApprox ab = HenselUtil. liftHenselQuadratic(C, M, F.get(0), F.get(1)); // lift.add(ab.Am); // lift.add(ab.Bm); // return lift; // } // normalize C and F_i factors BigInteger cc = g; //C.leadingBaseCoefficient(); // == g ?? for (int i = 1; i < F.size(); i++) { // #F-1 C = C.multiply(cc); // sic } MOD cm = PF.fromInteger(cc.getVal()); List> Fp = new ArrayList>(F.size()); for (GenPolynomial fm : F) { GenPolynomial am = fm.monic(); am = am.multiply(cm); Fp.add(am); } F = Fp; // setup integer polynomial ring GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), fac); List> Fi = PolyUtil.integerFromModularCoefficients(ifac, F); //System.out.println("Fi = " + Fi); // inplace modify polynomials, replace leading coefficient for (GenPolynomial ai : Fi) { if (ai.isZERO()) { continue; } ExpVector ea = ai.leadingExpVector(); ai.doPutToMap(ea, cc); } //System.out.println("Fi = " + Fi); List> S = liftExtendedEuclidean(F, k + 1); // lift works for any k, use this //System.out.println("Sext = " + S); if (debug) { logger.info("EE lift = {}", S); // adjust coefficients List> Sx = PolyUtil.fromIntegerCoefficients(pfac, PolyUtil.integerFromModularCoefficients(ifac, S)); try { boolean il = HenselUtil. isExtendedEuclideanLift(F, Sx); //System.out.println("islift = " + il); } catch (RuntimeException e) { e.printStackTrace(); } } List> Si = PolyUtil.integerFromModularCoefficients(ifac, S); //System.out.println("Si = " + Si); //System.out.println("C = " + C); // approximate mod p^i ModularRingFactory mcfac = PF; BigInteger p = mcfac.getIntegerModul(); BigInteger modul = p; GenPolynomialRing mfac = new GenPolynomialRing(mcfac, fac); List> Sp = PolyUtil.fromIntegerCoefficients(mfac, Si); //System.out.println("Sp = " + Sp); for (int i = 1; i < k; i++) { //System.out.println("i = " + i); GenPolynomial e = fac.getONE(); for (GenPolynomial fi : Fi) { e = e.multiply(fi); } e = C.subtract(e); //System.out.println("\ne = " + e); if (e.isZERO()) { logger.info("leaving on zero e"); break; } try { e = e.divide(modul); } catch (RuntimeException ex) { ex.printStackTrace(); throw ex; } //System.out.println("e = " + e); // move to in Z_p[x] GenPolynomial c = PolyUtil. fromIntegerCoefficients(mfac, e); //System.out.println("c = " + c + ": " + c.ring.coFac); List> s = new ArrayList>(S.size()); int j = 0; for (GenPolynomial f : Sp) { f = f.multiply(c); //System.out.println("f = " + f + " : " + f.ring.coFac); //System.out.println("F,i = " + F.get(j) + " : " + F.get(j).ring.coFac); f = f.remainder(F.get(j++)); //System.out.println("f = " + f + " : " + f.ring.coFac); s.add(f); } //System.out.println("s = " + s); List> si = PolyUtil.integerFromModularCoefficients(ifac, s); //System.out.println("si = " + si); List> Fii = new ArrayList>(F.size()); j = 0; for (GenPolynomial f : Fi) { f = f.sum(si.get(j++).multiply(modul)); Fii.add(f); } //System.out.println("Fii = " + Fii); Fi = Fii; modul = modul.multiply(p); if (i >= k - 1) { logger.info("e != 0 for k = {}", k); } } //System.out.println("Fi = " + Fi); // remove normalization GreatestCommonDivisorAbstract ufd = GCDFactory.getImplementation(cc); //BigInteger ai = ufd.baseContent(Fi.get(0)); //System.out.println("ai = " + ai + ", cc = " + cc); List> Fii = new ArrayList>(F.size()); //int j = 0; for (GenPolynomial bi : Fi) { GenPolynomial ci = null; //if ( j++ == 0 ) { // ci = bi.divide(ai); //} else { // BigInteger i = cc.divide(ai); // ci = bi.divide(i); //} ci = ufd.basePrimitivePart(bi); // ?? //System.out.println("bi = " + bi + ", ci = " + ci); Fii.add(ci); } Fi = Fii; // setup ring mod p^k modul = p.power(k); if (ModLongRing.MAX_LONG.compareTo(modul.getVal()) > 0) { mcfac = (ModularRingFactory) new ModLongRing(modul.getVal()); } else { mcfac = (ModularRingFactory) new ModIntegerRing(modul.getVal()); } //System.out.println("mcfac = " + mcfac); mfac = new GenPolynomialRing(mcfac, fac); lift = PolyUtil. fromIntegerCoefficients(mfac, Fi); //System.out.println("lift = " + lift + ": " + lift.get(0).ring.coFac); return lift; } } java-algebra-system-2.7.200/src/edu/jas/ufd/NoLiftingException.java000066400000000000000000000010601445075545500250450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; /** * Non existing Hensel lifting. Exception to be thrown when a valid * Hensel lifting cannot be constructed. * @author Heinz Kredel */ public class NoLiftingException extends Exception { public NoLiftingException() { super("NoLiftingException"); } public NoLiftingException(String c) { super(c); } public NoLiftingException(String c, Throwable t) { super(c, t); } public NoLiftingException(Throwable t) { super("NoLiftingException", t); } } java-algebra-system-2.7.200/src/edu/jas/ufd/PartialFraction.java000066400000000000000000000314351445075545500243700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; /** * Container for the partial fraction decomposition of a squarefree denominator. * num/den = sum( a_i / d_i ) * @author Heinz Kredel * @param coefficient type */ public class PartialFraction> implements Serializable { private static final Logger logger = LogManager.getLogger(PartialFraction.class); /** * Original numerator polynomial coefficients from C and deg(num) < * deg(den). */ public final GenPolynomial num; /** * Original (irreducible) denominator polynomial coefficients from C. */ public final GenPolynomial den; /** * List of numbers from C. */ public final List cfactors; /** * List of linear factors of the denominator with coefficients from C. */ public final List> cdenom; /** * List of algebraic numbers of an algebraic field extension over C. */ public final List> afactors; /** * List of factors of the denominator with coefficients from an * AlgebraicNumberRing<C>. */ public final List>> adenom; /** * Constructor. * @param n numerator GenPolynomial over C. * @param d irreducible denominator GenPolynomial over C. * @param cf list of elements a_i. * @param cd list of linear factors d_i of d. * @param af list of algebraic elements a_i. * @param ad list of linear (irreducible) factors d_i of d with algebraic * coefficients. n/d = sum( a_i / d_i ) */ public PartialFraction(GenPolynomial n, GenPolynomial d, List cf, List> cd, List> af, List>> ad) { num = n; den = d; cfactors = cf; cdenom = cd; afactors = af; adenom = ad; for (GenPolynomial p : cdenom) { if (p.degree(0) > 1) { throw new IllegalArgumentException("polynomial not linear, p = " + p); } } for (GenPolynomial> a : adenom) { if (a.degree(0) > 1) { throw new IllegalArgumentException("polynomial not linear, a = " + a); } } } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("(" + num.toString() + ")"); sb.append(" / "); sb.append("(" + den.toString() + ")"); sb.append(" =\n"); boolean first = true; for (int i = 0; i < cfactors.size(); i++) { C cp = cfactors.get(i); if (first) { first = false; } else { sb.append(" + "); } sb.append("(" + cp.toString() + ")"); GenPolynomial p = cdenom.get(i); sb.append(" / (" + p.toString() + ")"); } if (!first && afactors.size() > 0) { sb.append(" + "); } first = true; for (int i = 0; i < afactors.size(); i++) { if (first) { first = false; } else { sb.append(" + "); } AlgebraicNumber ap = afactors.get(i); AlgebraicNumberRing ar = ap.factory(); GenPolynomial> p = adenom.get(i); if (p.degree(0) < ar.modul.degree(0) && ar.modul.degree(0) > 2) { sb.append("sum_(" + ar.getGenerator() + " in "); sb.append("rootOf(" + ar.modul + ") ) "); } else { //sb.append("sum_("+ar+") "); } sb.append("(" + ap.toString() + ")"); sb.append(" / (" + p.toString() + ")"); //sb.append(" ## over " + ap.factory() + "\n"); } return sb.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this container. * @see edu.jas.structure.ElemFactory#toScript() */ public String toScript() { // Python case StringBuffer sb = new StringBuffer(); sb.append(num.toScript()); sb.append(" / "); sb.append(den.toScript()); sb.append(" = "); boolean first = true; int i = 0; for (C cp : cfactors) { if (first) { first = false; } else { sb.append(" + "); } sb.append(cp.toScript()); GenPolynomial p = cdenom.get(i); sb.append(" / " + p.toScript()); } if (!first) { sb.append(" + "); } first = true; i = 0; for (AlgebraicNumber ap : afactors) { if (first) { first = false; } else { sb.append(" + "); } AlgebraicNumberRing ar = ap.factory(); GenPolynomial> p = adenom.get(i); if (p.degree(0) < ar.modul.degree(0) && ar.modul.degree(0) > 2) { sb.append("sum_(" + ar.getGenerator().toScript() + " in "); sb.append("rootOf(" + ar.modul.toScript() + ") ) "); } else { //sb.append("sum_("+ar+") "); } sb.append(ap.toScript()); sb.append(" / " + p.toScript()); //sb.append(" ## over " + ap.toScriptFactory() + "\n"); } return sb.toString(); } /** * Hash code for this Factors. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h = num.hashCode(); h = h * 37 + den.hashCode(); h = h * 37 + cfactors.hashCode(); h = h * 37 + cdenom.hashCode(); h = h * 37 + afactors.hashCode(); h = h * 37 + adenom.hashCode(); return h; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object B) { if (B == null) { return false; } if (!(B instanceof PartialFraction)) { return false; } PartialFraction a = (PartialFraction) B; boolean t = num.equals(a.num) && den.equals(a.den); if (!t) { return t; } t = cfactors.equals(a.cfactors); if (!t) { return t; } t = cdenom.equals(a.cdenom); if (!t) { return t; } t = afactors.equals(a.afactors); if (!t) { return t; } t = adenom.equals(a.adenom); return t; } /** * Test if correct partial fraction. num/den = sum( a_i / d_i ) */ @SuppressWarnings("unchecked") public boolean isPartialFraction() { QuotientRing qfac = new QuotientRing(num.ring); // num / den Quotient q = new Quotient(qfac, num, den); //System.out.println("q = " + q); Quotient qs = qfac.getZERO(); int i = 0; for (C c : cfactors) { GenPolynomial cp = cdenom.get(i++); // plus c / cp GenPolynomial cd = num.ring.getONE().multiply(c); Quotient qq = new Quotient(qfac, cd, cp); qs = qs.sum(qq); } //System.out.println("qs = " + qs); if (afactors.isEmpty()) { return q.compareTo(qs) == 0; } // sort by extension field Set> fields = new HashSet>(); for (AlgebraicNumber ap : afactors) { if (ap.ring.depth() > 1) { logger.warn("extension field depth to high"); // todo } fields.add(ap.ring); } //System.out.println("fields = " + fields); Map, List>> facs = new HashMap, List>>(); for (AlgebraicNumber ap : afactors) { List> cf = facs.get(ap.ring); if (cf == null) { cf = new ArrayList>(); } cf.add(ap); facs.put(ap.ring, cf); } //System.out.println("facs = " + facs); Map, List>>> pfacs = new HashMap, List>>>(); for (GenPolynomial> ap : adenom) { AlgebraicNumberRing ar = (AlgebraicNumberRing) ap.ring.coFac; List>> cf = pfacs.get(ar); if (cf == null) { cf = new ArrayList>>(); } cf.add(ap); pfacs.put(ar, cf); } //System.out.println("pfacs = " + pfacs); // check algebraic parts boolean sumMissing = false; for (AlgebraicNumberRing ar : fields) { if (ar.modul.degree(0) > 2) { //&& p.degree(0) < ar.modul.degree(0) ? sumMissing = true; } List> cf = facs.get(ar); List>> cfp = pfacs.get(ar); GenPolynomialRing> apfac = cfp.get(0).ring; QuotientRing> aqfac = new QuotientRing>(apfac); Quotient> aq = aqfac.getZERO(); i = 0; for (AlgebraicNumber c : cf) { GenPolynomial> cp = cfp.get(i++); // plus c / cp GenPolynomial> cd = apfac.getONE().multiply(c); Quotient> qq = new Quotient>(aqfac, cd, cp); //System.out.println("qq = " + qq); aq = aq.sum(qq); } //System.out.println("aq = " + aq); GenPolynomialRing cfac = ar.ring; GenPolynomialRing> prfac = new GenPolynomialRing>(cfac, apfac); GenPolynomial> pqnum = PolyUtil. fromAlgebraicCoefficients(prfac, aq.num); GenPolynomial> pqden = PolyUtil. fromAlgebraicCoefficients(prfac, aq.den); //System.out.println("pq = (" + pqnum + ") / (" + pqden + ")"); C one = cfac.coFac.getONE(); // variable should no more occur in coefficient GenPolynomialRing pfac = new GenPolynomialRing(cfac.coFac, prfac); GenPolynomial pnum = PolyUtil. evaluateFirstRec(cfac, pfac, pqnum, one); GenPolynomial pden = PolyUtil. evaluateFirstRec(cfac, pfac, pqden, one); //System.out.println("p = (" + pnum + ") / (" + pden + ")"); // iterate if multiple field extensions while (cfac.coFac instanceof AlgebraicNumberRing) { //System.out.println("cfac.coFac = " + cfac.coFac.toScript()); AlgebraicNumberRing ar2 = (AlgebraicNumberRing) cfac.coFac; cfac = ar2.ring; prfac = new GenPolynomialRing>(cfac, apfac); GenPolynomial> prnum = (GenPolynomial>) pnum; GenPolynomial> prden = (GenPolynomial>) pden; pqnum = PolyUtil. fromAlgebraicCoefficients(prfac, prnum); pqden = PolyUtil. fromAlgebraicCoefficients(prfac, prden); one = cfac.coFac.getONE(); // variable should no more occur in coefficient pfac = new GenPolynomialRing(cfac.coFac, prfac); pnum = PolyUtil. evaluateFirstRec(cfac, pfac, pqnum, one); pden = PolyUtil. evaluateFirstRec(cfac, pfac, pqden, one); } Quotient qq = new Quotient(qfac, pnum, pden); //System.out.println("qq = " + qq); qs = qs.sum(qq); } boolean cmp = q.compareTo(qs) == 0; if (!cmp) { System.out.println("q != qs: " + q + " != " + qs); } return cmp || sumMissing; } } java-algebra-system-2.7.200/src/edu/jas/ufd/PolyUfdUtil.java000066400000000000000000001327731445075545500235350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenExteriorPolynomial; import edu.jas.poly.GenExteriorPolynomialRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.IndexFactory; import edu.jas.poly.IndexList; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrderByName; import edu.jas.ps.TaylorFunction; import edu.jas.ps.UnivPowerSeries; import edu.jas.ps.UnivPowerSeriesRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.Power; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; /** * Polynomial ufd utilities. For example conversion between different * representations and Kronecker substitution. * @author Heinz Kredel */ public class PolyUfdUtil { private static final Logger logger = LogManager.getLogger(PolyUfdUtil.class); private static final boolean debug = logger.isDebugEnabled(); /** * Derivation of a univariate rational function. * @param r rational function * @return dr/dx */ public static > Quotient derivative(Quotient r) { if (r == null || r.isZERO()) { return r; } GenPolynomial num = r.num; GenPolynomial den = r.den; GenPolynomial nump = PolyUtil. baseDerivative(num); if (den.isONE()) { return new Quotient(r.ring, nump); } GenPolynomial denp = PolyUtil. baseDerivative(den); // (n/d)' = (n' d - n d')/ d**2 GenPolynomial n = den.multiply(nump).subtract(num.multiply(denp)); GenPolynomial d = den.multiply(den); Quotient der = new Quotient(r.ring, n, d); //System.out.println("der = " + der); return der; } /** * Polynomial quotient partial derivative variable r. * @param coefficient type. * @param Q Quotient. * @param r variable for partial deriviate. * @return dq/dx_r = derivative(Q,r). */ public static > Quotient derivative(Quotient Q, int r) { if (Q == null || Q.isZERO()) { return Q; } QuotientRing qfac = Q.ring; if (r < 0 || qfac.ring.nvar <= r) { throw new IllegalArgumentException("derivative variable out of bound " + r); } GenPolynomial num = Q.num; GenPolynomial den = Q.den; GenPolynomial nump = PolyUtil. baseDerivative(num, r); if (den.isONE()) { return new Quotient(Q.ring, nump); } GenPolynomial denp = PolyUtil. baseDerivative(den, r); // (n/d)' = (n' d - n d')/ d**2 GenPolynomial n = den.multiply(nump).subtract(num.multiply(denp)); GenPolynomial d = den.multiply(den); Quotient der = new Quotient(Q.ring, n, d); return der; } /** * GenExteriorPolynomial over polynomial quotient exterior derivative. * @param <C> coefficient type. * @param P GenExteriorPolynomial<Quotient>. * @return exteriorDerivative(P). */ public static > GenExteriorPolynomial> exteriorDerivativeQuot( GenExteriorPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenExteriorPolynomialRing> pfac = P.ring; IndexFactory ifac = pfac.ixfac; int im = ifac.imaxlength; if (im == 0) { return pfac.getZERO(); } //RingFactory> rf = pfac.coFac; GenExteriorPolynomial> d = pfac.getZERO().copy(); //Map> dm = d.getMap(); for (Map.Entry> m : P.getMap().entrySet()) { //if (P.length() == 1) { //Map.Entry m = P.leadingMonomial(); Quotient a = m.getValue(); IndexList il = m.getKey(); Quotient b; IndexList bi; for (int i = 1; i <= im; i++) { IndexList di = new IndexList(ifac, new int[] { i }); bi = di.multiply(il); if (bi.signum() == 0) { continue; } b = PolyUfdUtil. derivative(a, i - 1); //a.derivative(); //System.out.println("baseDerivative a = " + a + ", i-1 = " + (i-1) + ", b = " + b); if (b.isZERO()) { continue; } if (bi.signum() < 0) { bi = bi.negate(); b = b.negate(); } d.doPutToMap(bi, b); } } return d; } /** * Evaluate at main variable. * @param coefficient type. * @param cfac coefficient polynomial ring factory. * @param A polynomial quotient to be evaluated. * @param a value to evaluate at. * @return A( x_1, ..., x_{n-1}, a ). */ public static > C evaluateMain(RingFactory cfac, Quotient A, C a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } C num = PolyUtil. evaluateMain(cfac, A.num, a); C den = PolyUtil. evaluateMain(cfac, A.den, a); if (den.isZERO()) { throw new NotInvertibleException("den == 0"); } return num.divide(den); } /** * Evaluate all variables. * @param coefficient type. * @param cfac coefficient ring factory. * @param A polynomial quotient to be evaluated. * @param a = (a_1, a_2, ..., a_n) a tuple of values to evaluate at. * @return A(a_1, a_2, ..., a_n). */ public static > C evaluateAll(RingFactory cfac, Quotient A, List a) { if (A == null || A.isZERO()) { return cfac.getZERO(); } C num = PolyUtil. evaluateAll(cfac, A.num, a); C den = PolyUtil. evaluateAll(cfac, A.den, a); if (den.isZERO()) { throw new NotInvertibleException("den == 0"); } return num.divide(den); } /** * Pade approximant [m/n] of function f. Computed using Taylor power series * expansion of f. * @see https://en.wikipedia.org/wiki/Pad%C3%A9_approximant * @param upr univariate power series ring. * @param f function. * @param a expansion point. * @param m degree of approximant numerator. * @param n degree of approximant denominator. * @return Pade approximation of f. */ public static > Quotient approximantOfPade(final UnivPowerSeriesRing upr, final TaylorFunction f, final C a, int m, int n) { int mn = m + n; GenPolynomialRing pfac = upr.polyRing(); QuotientRing qfac = new QuotientRing(pfac); UnivPowerSeries tps = upr.seriesOfTaylor(f, a); int t = mn + 1; if (tps.truncate() != t) { tps.setTruncate(t); //System.out.println("t = " + t + ", default = " + tps.ring.DEFAULT_TRUNCATE); } if (tps.isZERO()) { throw new IllegalArgumentException("Taylor series may not be zero: " + tps); } //System.out.println("tps = " + tps); GenPolynomial Tmn = tps.asPolynomial(); GenPolynomial Xmn1 = pfac.univariate(0, mn + 1); //System.out.println("Tmn = " + Tmn); //System.out.println("Xmn1 = " + Xmn1); GenPolynomial[] exg = PolyUfdUtil. agcd(Tmn, Xmn1, n); GenPolynomial p = exg[0]; GenPolynomial q = exg[1]; //System.out.println("a = " + exg[2]); Quotient pa = new Quotient(qfac, p, q); return pa; } /** * GenPolynomial approximate common divisor. Only for univariate polynomials * over fields. * @param R GenPolynomial. * @param S GenPolynomial. * @param n maximal degree of a. * @return [ agcd(R,S), a ] with a*R + b*S = agcd(R,S) and deg(a) ≤ n. */ @SuppressWarnings("unchecked") public static > GenPolynomial[] agcd(GenPolynomial R, GenPolynomial S, int n) { GenPolynomial[] ret = new GenPolynomial[2]; ret[0] = null; ret[1] = null; if (R == null) { return ret; } GenPolynomialRing ring = R.ring; if (R.isZERO()) { ret[0] = S; ret[1] = ring.getZERO(); //ret[2] = ring.getONE(); return ret; } if (S == null || S.isZERO()) { ret[0] = R; ret[1] = ring.getONE(); //ret[2] = ring.getZERO(); return ret; } if (ring.nvar != 1) { throw new IllegalArgumentException("not univariate polynomials" + ring); } if (R.isConstant() && S.isConstant()) { C t = R.leadingBaseCoefficient(); C s = S.leadingBaseCoefficient(); C[] gg = t.egcd(s); //System.out.println("coeff gcd = " + Arrays.toString(gg)); GenPolynomial z = R.ring.getZERO(); ret[0] = z.sum(gg[0]); ret[1] = z.sum(gg[1]); //ret[2] = z.sum(gg[2]); return ret; } GenPolynomial[] qr; GenPolynomial q = R; GenPolynomial r = S; GenPolynomial c1 = ring.getONE().copy(); GenPolynomial d1 = ring.getZERO().copy(); GenPolynomial c2 = ring.getZERO().copy(); GenPolynomial d2 = ring.getONE().copy(); GenPolynomial x1; GenPolynomial x2; GenPolynomial num = ring.getONE(); GenPolynomial den = ring.getONE(); while (!r.isZERO()) { qr = q.quotientRemainder(r); q = qr[0]; x1 = c1.subtract(q.multiply(d1)); x2 = c2.subtract(q.multiply(d2)); c1 = d1; c2 = d2; d1 = x1; d2 = x2; q = r; r = qr[1]; //System.out.println("q = " + q + ", c1 = " + c1); if (c1.degree() <= n) { num = q; den = c1; } else { break; } } // normalize ldcf(q) to 1, i.e. make monic C g = num.leadingBaseCoefficient(); if (g.isUnit()) { C h = g.inverse(); num = num.multiply(h); den = den.multiply(h); c2 = c2.multiply(h); } //System.out.println("num = " + num); //System.out.println("den = " + den); //assert ( ((c1.multiply(R)).sum( c2.multiply(S)).equals(q) )); ret[0] = num; //q; ret[1] = den; //c1; //ret[2] = c2; return ret; } /** * Factors of Quotient rational function. * @param A rational function to be factored. * @return list of irreducible rational function parts. */ public static > SortedMap, Long> factors(Quotient A) { SortedMap, Long> factors = new TreeMap, Long>(); if (A == null || A.isZERO()) { return factors; } if (A.abs().isONE()) { factors.put(A, 1L); return factors; } QuotientRing qfac = A.ring; GenPolynomialRing fac = qfac.ring; FactorAbstract eng = FactorFactory. getImplementation(fac.coFac); GenPolynomial n = A.num; SortedMap, Long> numfactors = eng.factors(n); for (Map.Entry, Long> me : numfactors.entrySet()) { GenPolynomial f = me.getKey(); Long e = me.getValue(); Quotient q = new Quotient(qfac, f); factors.put(q, e); } GenPolynomial d = A.den; if (d.isONE()) { return factors; } GenPolynomial one = fac.getONE(); SortedMap, Long> denfactors = eng.factors(d); for (Map.Entry, Long> me : denfactors.entrySet()) { GenPolynomial f = me.getKey(); Long e = me.getValue(); Quotient q = new Quotient(qfac, one, f); factors.put(q, e); } return factors; } /** * Quotient is (squarefree) factorization. * @param P Quotient. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. */ public static > boolean isFactorization(Quotient P, SortedMap, Long> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } Quotient t = P.ring.getONE(); for (Map.Entry, Long> me : F.entrySet()) { Quotient f = me.getKey(); Long E = me.getValue(); long e = E.longValue(); Quotient g = f.power(e); t = t.multiply(g); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { P = P.monic(); t = t.monic(); f = P.equals(t) || P.equals(t.negate()); if (f) { return f; } logger.info("no factorization(map): F = {}, P = {}, t = {}", F, P, t); } return f; } /** * Integral polynomial from rational function coefficients. Represent as * polynomial with integral polynomial coefficients by multiplication with * the lcm of the numerators of the rational function coefficients. * @param fac result polynomial factory. * @param A polynomial with rational function coefficients to be converted. * @return polynomial with integral polynomial coefficients. */ public static > GenPolynomial> integralFromQuotientCoefficients( GenPolynomialRing> fac, GenPolynomial> A) { GenPolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } GenPolynomial c = null; GenPolynomial d; GenPolynomial x; GreatestCommonDivisor ufd = new GreatestCommonDivisorSubres(); int s = 0; // lcm of denominators for (Quotient y : A.getMap().values()) { x = y.den; // c = lcm(c,x) if (c == null) { c = x; s = x.signum(); } else { d = ufd.gcd(c, x); c = c.multiply(x.divide(d)); } } if (s < 0) { c = c.negate(); } for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); Quotient a = y.getValue(); // p = n*(c/d) GenPolynomial b = c.divide(a.den); GenPolynomial p = a.num.multiply(b); //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } return B; } /** * Integral polynomial from rational function coefficients. Represent as * polynomial with integral polynomial coefficients by multiplication with * the lcm of the numerators of the rational function coefficients. * @param fac result polynomial factory. * @param L list of polynomial with rational function coefficients to be * converted. * @return list of polynomials with integral polynomial coefficients. */ public static > List>> integralFromQuotientCoefficients( GenPolynomialRing> fac, Collection>> L) { if (L == null) { return null; } List>> list = new ArrayList>>(L.size()); for (GenPolynomial> p : L) { list.add(integralFromQuotientCoefficients(fac, p)); } return list; } /** * Rational function from integral polynomial coefficients. Represent as * polynomial with type Quotient coefficients. * @param fac result polynomial factory. * @param A polynomial with integral polynomial coefficients to be * converted. * @return polynomial with type Quotient coefficients. */ public static > GenPolynomial> quotientFromIntegralCoefficients( GenPolynomialRing> fac, GenPolynomial> A) { GenPolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = fac.coFac; QuotientRing qfac = (QuotientRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); Quotient p = new Quotient(qfac, a); // can not be zero if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * Rational function from integral polynomial coefficients. Represent as * polynomial with type Quotient coefficients. * @param fac result polynomial factory. * @param L list of polynomials with integral polynomial coefficients to be * converted. * @return list of polynomials with type Quotient coefficients. */ public static > List>> quotientFromIntegralCoefficients( GenPolynomialRing> fac, Collection>> L) { if (L == null) { return null; } List>> list = new ArrayList>>(L.size()); for (GenPolynomial> p : L) { list.add(quotientFromIntegralCoefficients(fac, p)); } return list; } /** * From BigInteger coefficients. Represent as polynomial with type * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. * @param fac result polynomial factory. * @param A polynomial with GenPolynomial<BigInteger> coefficients to * be converted. * @return polynomial with type GenPolynomial<C> coefficients. */ public static > GenPolynomial> fromIntegerCoefficients( GenPolynomialRing> fac, GenPolynomial> A) { GenPolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } RingFactory> cfac = fac.coFac; GenPolynomialRing rfac = (GenPolynomialRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); GenPolynomial p = PolyUtil. fromIntegerCoefficients(rfac, a); if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * From BigInteger coefficients. Represent as polynomial with type * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. * @param fac result polynomial factory. * @param L polynomial list with GenPolynomial<BigInteger> * coefficients to be converted. * @return polynomial list with polynomials with type GenPolynomial<C> * coefficients. */ public static > List>> fromIntegerCoefficients( GenPolynomialRing> fac, List>> L) { List>> K = null; if (L == null) { return K; } K = new ArrayList>>(L.size()); if (L.size() == 0) { return K; } for (GenPolynomial> a : L) { GenPolynomial> b = fromIntegerCoefficients(fac, a); K.add(b); } return K; } //------------------------------ /** * BigInteger from BigRational coefficients. Represent as polynomial with * type GenPolynomial<BigInteger> coefficients. * @param fac result polynomial factory. * @param A polynomial with GenPolynomial<BigRational> coefficients to * be converted. * @return polynomial with type GenPolynomial<BigInteger> * coefficients. */ public static GenPolynomial> integerFromRationalCoefficients( GenPolynomialRing> fac, GenPolynomial> A) { GenPolynomial> B = fac.getZERO().copy(); if (A == null || A.isZERO()) { return B; } java.math.BigInteger gcd = null; java.math.BigInteger lcm = null; int sLCM = 0; int sGCD = 0; // lcm of all denominators for (GenPolynomial av : A.getMap().values()) { for (BigRational y : av.getMap().values()) { java.math.BigInteger numerator = y.numerator(); java.math.BigInteger denominator = y.denominator(); // lcm = lcm(lcm,x) if (lcm == null) { lcm = denominator; sLCM = denominator.signum(); } else { java.math.BigInteger d = lcm.gcd(denominator); lcm = lcm.multiply(denominator.divide(d)); } // gcd = gcd(gcd,x) if (gcd == null) { gcd = numerator; sGCD = numerator.signum(); } else { gcd = gcd.gcd(numerator); } } //System.out.println("gcd = " + gcd + ", lcm = " + lcm); } if (sLCM < 0) { lcm = lcm.negate(); } if (sGCD < 0) { gcd = gcd.negate(); } //System.out.println("gcd** = " + gcd + ", lcm = " + lcm); RingFactory> cfac = fac.coFac; GenPolynomialRing rfac = (GenPolynomialRing) cfac; for (Map.Entry> y : A.getMap().entrySet()) { ExpVector e = y.getKey(); GenPolynomial a = y.getValue(); // common denominator over all coefficients GenPolynomial p = PolyUtil.integerFromRationalCoefficients(rfac, gcd, lcm, a); if (!p.isZERO()) { //B = B.sum( p, e ); // inefficient B.doPutToMap(e, p); } } return B; } /** * BigInteger from BigRational coefficients. Represent as polynomial with * type GenPolynomial<BigInteger> coefficients. * @param fac result polynomial factory. * @param L polynomial list with GenPolynomial<BigRational> * coefficients to be converted. * @return polynomial list with polynomials with type * GenPolynomial<BigInteger> coefficients. */ public static List>> integerFromRationalCoefficients( GenPolynomialRing> fac, List>> L) { List>> K = null; if (L == null) { return K; } K = new ArrayList>>(L.size()); if (L.isEmpty()) { return K; } for (GenPolynomial> a : L) { GenPolynomial> b = integerFromRationalCoefficients(fac, a); K.add(b); } return K; } /** * Introduce lower variable. Represent as polynomial with type * GenPolynomial<C> coefficients. * @param rfac result polynomial factory. * @param A polynomial to be extended. * @return polynomial with type GenPolynomial<C> coefficients. */ public static > GenPolynomial> introduceLowerVariable( GenPolynomialRing> rfac, GenPolynomial A) { if (A == null || rfac == null) { return null; } GenPolynomial> Pc = rfac.getONE().multiply(A); if (Pc.isZERO()) { return Pc; } Pc = PolyUtil. switchVariables(Pc); return Pc; } /** * From AlgebraicNumber coefficients. Represent as polynomial with type * GenPolynomial<C> coefficients, e.g. ModInteger or BigRational. * @param rfac result polynomial factory. * @param A polynomial with AlgebraicNumber coefficients to be converted. * @param k for (y-k x) substitution. * @return polynomial with type GenPolynomial<C> coefficients. */ public static > GenPolynomial> substituteFromAlgebraicCoefficients( GenPolynomialRing> rfac, GenPolynomial> A, long k) { if (A == null || rfac == null) { return null; } if (A.isZERO()) { return rfac.getZERO(); } // setup x - k alpha GenPolynomialRing> apfac = A.ring; GenPolynomial> x = apfac.univariate(0); AlgebraicNumberRing afac = (AlgebraicNumberRing) A.ring.coFac; AlgebraicNumber alpha = afac.getGenerator(); AlgebraicNumber ka = afac.fromInteger(k); GenPolynomial> s = x.subtract(ka.multiply(alpha)); // x - k alpha //System.out.println("x - k alpha = " + s); //System.out.println("s.ring = " + s.ring.toScript()); if (debug) { logger.info("x - k alpha: {}", s); } // substitute, convert and switch //System.out.println("Asubs = " + A); GenPolynomial> B; if (s.ring.nvar <= 1) { B = PolyUtil.> substituteMain(A, s); } else { B = PolyUtil.> substituteUnivariateMult(A, s); } //System.out.println("Bsubs = " + B); GenPolynomial> Pc = PolyUtil. fromAlgebraicCoefficients(rfac, B); // Q[alpha][x] //System.out.println("Pc[a,x] = " + Pc); Pc = PolyUtil. switchVariables(Pc); // Q[x][alpha] //System.out.println("Pc[x,a] = " + Pc); return Pc; } /** * Convert to AlgebraicNumber coefficients. Represent as polynomial with * AlgebraicNumber coefficients, C is e.g. ModInteger or BigRational. * @param pfac result polynomial factory. * @param A polynomial with GenPolynomial<BigInteger> coefficients to * be converted. * @param k for (y-k x) substitution. * @return polynomial with AlgebraicNumber<C> coefficients. */ public static > GenPolynomial> substituteConvertToAlgebraicCoefficients( GenPolynomialRing> pfac, GenPolynomial A, long k) { if (A == null || pfac == null) { return null; } if (A.isZERO()) { return pfac.getZERO(); } // convert to Q(alpha)[x] GenPolynomial> B = PolyUtil. convertToAlgebraicCoefficients(pfac, A); // setup x .+. k alpha for back substitution GenPolynomial> x = pfac.univariate(0); AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; AlgebraicNumber alpha = afac.getGenerator(); AlgebraicNumber ka = afac.fromInteger(k); GenPolynomial> s = x.sum(ka.multiply(alpha)); // x + k alpha // substitute //System.out.println("s.ring = " + s.ring.toScript()); GenPolynomial> N; if (s.ring.nvar <= 1) { N = PolyUtil.> substituteMain(B, s); } else { N = PolyUtil.> substituteUnivariateMult(B, s); } return N; } /** * Norm of a polynomial with AlgebraicNumber coefficients. * @param A uni or multivariate polynomial from * GenPolynomial<AlgebraicNumber<C>>. * @param k for (y - k x) substitution. * @return norm(A) = res_x(A(x,y),m(x)) in GenPolynomialRing<C>. */ public static > GenPolynomial norm(GenPolynomial> A, long k) { if (A == null) { return null; } GenPolynomialRing> pfac = A.ring; // Q(alpha)[x] //if (pfac.nvar > 1) { // throw new IllegalArgumentException("only for univariate polynomials"); //} AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; GenPolynomial agen = afac.modul; GenPolynomialRing cfac = afac.ring; if (A.isZERO()) { return cfac.getZERO(); } AlgebraicNumber ldcf = A.leadingBaseCoefficient(); if (!ldcf.isONE()) { A = A.monic(); } GenPolynomialRing> rfac = new GenPolynomialRing>(cfac, pfac); //System.out.println("rfac = " + rfac.toScript()); // transform minimal polynomial to bi-variate polynomial GenPolynomial> Ac = PolyUfdUtil. introduceLowerVariable(rfac, agen); // transform to bi-variate polynomial, // switching variable sequence from Q[alpha][x] to Q[X][alpha] GenPolynomial> Pc = PolyUfdUtil. substituteFromAlgebraicCoefficients(rfac, A, k); Pc = PolyUtil. monic(Pc); //System.out.println("Pc = " + Pc.toScript() + " :: " + Pc.ring.toScript()); GreatestCommonDivisorSubres engine = new GreatestCommonDivisorSubres( /*cfac.coFac*/); // = (GreatestCommonDivisorAbstract)GCDFactory.getImplementation( cfac.coFac ); GenPolynomial> Rc = engine.recursiveUnivariateResultant(Pc, Ac); //System.out.println("Rc = " + Rc.toScript()); GenPolynomial res = Rc.leadingBaseCoefficient(); res = res.monic(); return res; } /** * Norm of a polynomial with AlgebraicNumber coefficients. * @param A polynomial from GenPolynomial<AlgebraicNumber<C>>. * @return norm(A) = resultant_x( A(x,y), m(x) ) in K[y]. */ public static > GenPolynomial norm(GenPolynomial> A) { return norm(A, 0L); } /** * Ensure that the field property is determined. Checks if modul is * irreducible and modifies the algebraic number ring. * @param afac algebraic number ring. */ public static > void ensureFieldProperty(AlgebraicNumberRing afac) { if (afac.getField() != -1) { return; } if (!afac.ring.coFac.isField()) { afac.setField(false); return; } Factorization mf = FactorFactory. getImplementation(afac.ring); if (mf.isIrreducible(afac.modul)) { afac.setField(true); } else { afac.setField(false); } } /** * Construct a random irreducible univariate polynomial of degree d. * @param cfac coefficient polynomial ring. * @param degree of random polynomial. * @return irreducible univariate polynomial. */ public static > GenPolynomial randomIrreduciblePolynomial(RingFactory cfac, int degree) { if (!cfac.isField()) { throw new IllegalArgumentException("coefficient ring must be a field " + cfac); } GenPolynomialRing ring = new GenPolynomialRing(cfac, 1, TermOrderByName.INVLEX); return randomIrreduciblePolynomial(ring, degree); } /** * Construct a random irreducible univariate polynomial of degree d. * @param ring coefficient ring. * @param degree of random polynomial. * @return irreducible univariate polynomial. */ public static > GenPolynomial randomIrreduciblePolynomial( GenPolynomialRing ring, int degree) { if (!ring.coFac.isField()) { throw new IllegalArgumentException("coefficient ring must be a field " + ring.coFac); } Factorization eng = FactorFactory. getImplementation(ring); GenPolynomial mod = ring.getZERO(); int k = ring.coFac.characteristic().bitLength(); // log if (k < 3) { k = 7; } int l = degree / 2 + 2; int d = degree + 1; float q = 0.55f; for (;;) { mod = ring.random(k, l, d, q).monic(); if (mod.degree() != degree) { mod = mod.sum(ring.univariate(0, degree)); } if (mod.trailingBaseCoefficient().isZERO()) { mod = mod.sum(ring.getONE()); } //System.out.println("algebriacNumberField: mod = " + mod + ", k = " + k); if (eng.isIrreducible(mod)) { break; } } return mod; } /** * Construct an algebraic number field of degree d. Uses a random * irreducible polynomial of degree d as modulus of the algebraic number * ring. * @param cfac coefficient ring. * @param degree of random polynomial. * @return algebraic number field. */ public static > AlgebraicNumberRing algebraicNumberField(RingFactory cfac, int degree) { GenPolynomial mod = randomIrreduciblePolynomial(cfac, degree); AlgebraicNumberRing afac = new AlgebraicNumberRing(mod, true); return afac; } /** * Construct an algebraic number field of degree d. Uses a random * irreducible polynomial of degree d as modulus of the algebraic number * ring. * @param ring coefficient polynomial ring. * @param degree of random polynomial. * @return algebraic number field. */ public static > AlgebraicNumberRing algebraicNumberField( GenPolynomialRing ring, int degree) { GenPolynomial mod = randomIrreduciblePolynomial(ring, degree); AlgebraicNumberRing afac = new AlgebraicNumberRing(mod, true); return afac; } /** * Construct Berlekamp Q matrix. * @param A univariate modular polynomial. * @return Q matrix. */ public static > ArrayList> constructQmatrix(GenPolynomial A) { ArrayList> Q = new ArrayList>(); if (A == null || A.isZERO()) { return Q; } GenPolynomialRing pfac = A.ring; //System.out.println("pfac = " + pfac.toScript()); java.math.BigInteger q = pfac.coFac.characteristic(); //.longValueExact(); int lq = q.bitLength(); //Power.logarithm(2, q); if (pfac.coFac instanceof AlgebraicNumberRing) { lq = (int) ((AlgebraicNumberRing) pfac.coFac).extensionDegree(); q = q.pow(lq); //Power.power(q, lq); } logger.info("Q matrix for cfac = {}", q); long d = A.degree(0); GenPolynomial x = pfac.univariate(0); //System.out.println("x = " + x.toScript()); GenPolynomial r = pfac.getONE(); //System.out.println("r = " + r.toScript()); List> Qp = new ArrayList>(); Qp.add(r); GenPolynomial pow = Power.> modPositivePower(x, q, A); //System.out.println("pow = " + pow.toScript()); Qp.add(pow); r = pow; for (int i = 2; i < d; i++) { r = r.multiply(pow).remainder(A); Qp.add(r); } //System.out.println("Qp = " + Qp); UnivPowerSeriesRing psfac = new UnivPowerSeriesRing(pfac); //System.out.println("psfac = " + psfac.toScript()); for (GenPolynomial p : Qp) { UnivPowerSeries ps = psfac.fromPolynomial(p); //System.out.println("ps = " + ps.toScript()); ArrayList pr = new ArrayList(); for (int i = 0; i < d; i++) { C c = ps.coefficient(i); pr.add(c); } Q.add(pr); } //System.out.println("Q = " + Q); return Q; } /** * Polynomial suitable evaluation points. deg(B) = deg(A(x_1,...)) and B is * also squarefree. * @param A squarefree polynomial in r variables. * @return L list of evaluation points and a squarefree univariate * Polynomial B = A(x_1,L_1,...L_{r-2}). * @see "sacring.SACPFAC.mi#IPCEVP from SAC2/MAS" */ @SuppressWarnings("unchecked") public static > EvalPoints evaluationPoints(GenPolynomial A) { ArrayList L = new ArrayList(); if (A == null) { throw new IllegalArgumentException("A is null"); } GenPolynomialRing pfac = A.ring; if (pfac.nvar <= 1) { return new EvalPoints(A, A, L); } GenPolynomial B = A; if (A.isZERO() || A.isONE()) { return new EvalPoints(A, A, L); } SquarefreeAbstract sengine = SquarefreeFactory. getImplementation(pfac.coFac); //long dega = A.degree(0); GenPolynomialRing rpfac = pfac; GenPolynomial ape = A; C one = pfac.coFac.getONE(); C ll = pfac.coFac.getZERO(); //logger.info("ape = {}, squarefree: {}", ape, sengine.isSquarefree(ape)); for (int i = pfac.nvar; i > 1; i--) { //System.out.println("rpfac = " + rpfac.toScript()); GenPolynomialRing> rfac = rpfac.recursive(1); GenPolynomialRing cpfac = (GenPolynomialRing) rfac.coFac; GenPolynomial> ap = PolyUtil. recursive(rfac, ape); //System.out.println("ap = " + ap); long degd = ape.degree(rpfac.nvar - 2); boolean unlucky = true; long s = 0; C Vi = null; while (unlucky) { //System.out.println("ll = " + ll); Vi = ll; if (ll.signum() > 0) { ll = ll.negate(); } else { ll = one.subtract(ll); } ape = PolyUtil. evaluateMainRecursive(cpfac, ap, Vi); //logger.info("loop: ap, Vi, ape = {}, {}, {}, squarefree: {}", ap, Vi, ape, sengine.isSquarefree(ape)); //long degp = ape.degree(0); long degc = ape.degree(cpfac.nvar - 1); //System.out.println("degc = " + degc + ", degd = " + degd); if (degd != degc) { continue; } if (!sengine.isSquarefree(ape)) { if (s++ > 30l) { throw new RuntimeException(s + " evaluations not squarefree: " + Vi + ", " + ape + ", squarefree(A): " + sengine.isSquarefree(A)); } //System.out.println("not squarefree"); continue; } //System.out.println("isSquarefree"); //ap = ape; unlucky = false; } L.add(Vi); rpfac = cpfac; } B = ape; return new EvalPoints(A, B, L); } /** * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a * univariate polynomial. * @param A polynomial to be converted. * @return a univariate polynomial. */ public static > GenPolynomial substituteKronecker(GenPolynomial A) { if (A == null) { return A; } long d = A.degree() + 1L; return substituteKronecker(A, d); } /** * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct a * univariate polynomial. * @param A polynomial to be converted. * @return a univariate polynomial. */ public static > GenPolynomial substituteKronecker(GenPolynomial A, long d) { if (A == null) { return A; } RingFactory cfac = A.ring.coFac; GenPolynomialRing ufac = new GenPolynomialRing(cfac, 1); GenPolynomial B = ufac.getZERO().copy(); if (A.isZERO()) { return B; } for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); long f = 0L; long h = 1L; for (int i = 0; i < e.length(); i++) { long j = e.getVal(i) * h; f += j; h *= d; } ExpVector g = ExpVector.create(1, 0, f); B.doPutToMap(g, a); } return B; } /** * Kronecker substitution. Substitute x_i by x**d**(i-1) to construct * univariate polynomials. * @param A list of polynomials to be converted. * @return a list of univariate polynomials. */ public static > List> substituteKronecker( List> A, int d) { if (A == null || A.get(0) == null) { return null; } return ListUtil., GenPolynomial> map(A, new SubstKronecker(d)); } /** * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct a * multivariate polynomial. * @param A polynomial to be converted. * @param fac result polynomial factory. * @return a multivariate polynomial. */ public static > GenPolynomial backSubstituteKronecker( GenPolynomialRing fac, GenPolynomial A, long d) { if (A == null) { return A; } if (fac == null) { throw new IllegalArgumentException("null factory not allowed "); } int n = fac.nvar; GenPolynomial B = fac.getZERO().copy(); if (A.isZERO()) { return B; } for (Map.Entry y : A.getMap().entrySet()) { ExpVector e = y.getKey(); C a = y.getValue(); long f = e.getVal(0); ExpVector g = ExpVector.create(n); for (int i = 0; i < n; i++) { long j = f % d; f /= d; g = g.subst(i, j); } B.doPutToMap(g, a); } return B; } /** * Kronecker back substitution. Substitute x**d**(i-1) to x_i to construct * multivariate polynomials. * @param A list of polynomials to be converted. * @param fac result polynomial factory. * @return a list of multivariate polynomials. */ public static > List> backSubstituteKronecker( GenPolynomialRing fac, List> A, long d) { return ListUtil., GenPolynomial> map(A, new BackSubstKronecker(fac, d)); } } /** * Kronecker substitutuion functor. */ class SubstKronecker> implements UnaryFunctor, GenPolynomial> { final long d; public SubstKronecker(long d) { this.d = d; } public GenPolynomial eval(GenPolynomial c) { if (c == null) { return null; } return PolyUfdUtil. substituteKronecker(c, d); } } /** * Kronecker back substitutuion functor. */ class BackSubstKronecker> implements UnaryFunctor, GenPolynomial> { final long d; final GenPolynomialRing fac; public BackSubstKronecker(GenPolynomialRing fac, long d) { this.d = d; this.fac = fac; } public GenPolynomial eval(GenPolynomial c) { if (c == null) { return null; } return PolyUfdUtil. backSubstituteKronecker(fac, c, d); } } java-algebra-system-2.7.200/src/edu/jas/ufd/Quotient.java000066400000000000000000000401061445075545500231110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPair; /** * Quotient, that is a rational function, based on GenPolynomial with RingElem * interface. Objects of this class are immutable. * @author Heinz Kredel */ public class Quotient> implements GcdRingElem>, QuotPair> { private static final Logger logger = LogManager.getLogger(Quotient.class); private static final boolean debug = logger.isDebugEnabled(); /** * Quotient class factory data structure. */ public final QuotientRing ring; /** * Numerator part of the element data structure. */ public final GenPolynomial num; /** * Denominator part of the element data structure. */ public final GenPolynomial den; /** * The constructor creates a Quotient object from a ring factory. * @param r ring factory. */ public Quotient(QuotientRing r) { this(r, r.ring.getZERO()); } /** * The constructor creates a Quotient object from a ring factory and a * numerator polynomial. The denominator is assumed to be 1. * @param r ring factory. * @param n numerator polynomial. */ public Quotient(QuotientRing r, GenPolynomial n) { this(r, n, r.ring.getONE(), true); } /** * The constructor creates a Quotient object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. */ public Quotient(QuotientRing r, GenPolynomial n, GenPolynomial d) { this(r, n, d, false); } /** * The constructor creates a Quotient object from a ring factory and a * numerator and denominator polynomial. * @param r ring factory. * @param n numerator polynomial. * @param d denominator polynomial. * @param isred true if gcd(n,d) == 1, else false. */ protected Quotient(QuotientRing r, GenPolynomial n, GenPolynomial d, boolean isred) { if (d == null || d.isZERO()) { throw new IllegalArgumentException("denominator may not be zero"); } ring = r; if (d.signum() < 0) { n = n.negate(); d = d.negate(); } if (!isred) { // must reduce to lowest terms GenPolynomial gcd = ring.gcd(n, d); if (debug) { logger.debug("gcd = {}", gcd); } //GenPolynomial gcd = ring.ring.getONE(); if (!gcd.isONE()) { //logger.debug("gcd = {}", gcd); n = ring.divide(n, gcd); d = ring.divide(d, gcd); } } C coeff; switch (QuotientRing.quoNorm) { //ring.quoNorm case normNumLead: coeff = n.leadingBaseCoefficient(); break; case normNumTrail: coeff = n.trailingBaseCoefficient(); break; case normDenTrail: coeff = d.trailingBaseCoefficient(); break; case normDenLead: default: coeff = d.leadingBaseCoefficient(); break; } if (!coeff.isONE() && coeff.isUnit()) { coeff = coeff.inverse(); n = n.multiply(coeff); d = d.multiply(coeff); } num = n; den = d; } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public QuotientRing factory() { return ring; } /** * Numerator. * @see edu.jas.structure.QuotPair#numerator() */ public GenPolynomial numerator() { return num; } /** * Denominator. * @see edu.jas.structure.QuotPair#denominator() */ public GenPolynomial denominator() { return den; } /** * Clone this. * @see java.lang.Object#clone() */ @Override public Quotient copy() { return new Quotient(ring, num, den, true); } /** * Is Quotient zero. * @return If this is 0 then true is returned, else false. * @see edu.jas.structure.RingElem#isZERO() */ public boolean isZERO() { return num.isZERO(); } /** * Is Quotient one. * @return If this is 1 then true is returned, else false. * @see edu.jas.structure.RingElem#isONE() */ public boolean isONE() { return num.equals(den); } /** * Is Quotient a unit. * @return If this is a unit then true is returned, else false. * @see edu.jas.structure.RingElem#isUnit() */ public boolean isUnit() { if (num.isZERO()) { return false; } return true; } /** * Is Qoutient a constant. * @return true, if this has constant numerator and denominator, else false. */ public boolean isConstant() { return num.isConstant() && den.isConstant(); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { if (PrettyPrint.isTrue()) { String s = "{ " + num.toString(ring.ring.getVars()); if (!den.isONE()) { s += " | " + den.toString(ring.ring.getVars()); } return s + " }"; } return "Quotient[ " + num.toString() + " | " + den.toString() + " ]"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case if (den.isONE()) { return num.toScript(); } if (den.length() == 1 && den.totalDegree() > 1) { return num.toScript() + " / (" + den.toScript() + " )"; } return num.toScript() + " / " + den.toScript(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Quotient comparison. * @param b Quotient. * @return sign(this-b). */ @Override public int compareTo(Quotient b) { if (b == null || b.isZERO()) { return this.signum(); } if (this.isZERO()) { return -b.signum(); } // assume sign(den,b.den) > 0 int s1 = num.signum(); int s2 = b.num.signum(); int t = (s1 - s2) / 2; if (t != 0) { return t; } if (den.compareTo(b.den) == 0) { return num.compareTo(b.num); } GenPolynomial r = num.multiply(b.den); GenPolynomial s = den.multiply(b.num); return r.compareTo(s); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @SuppressWarnings("unchecked") @Override public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof Quotient)) { return false; } Quotient a = (Quotient) b; return compareTo(a) == 0; //return num.equals(a.num) && den.equals(a.den); } /** * Hash code for this quotient. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); h = 37 * h + num.hashCode(); h = 37 * h + den.hashCode(); return h; } /** * Quotient absolute value. * @return the absolute value of this. * @see edu.jas.structure.RingElem#abs() */ public Quotient abs() { return new Quotient(ring, num.abs(), den, true); } /** * Quotient summation. * @param S Quotient. * @return this+S. */ public Quotient sum(Quotient S) { if (S == null || S.isZERO()) { return this; } if (this.isZERO()) { return S; } GenPolynomial n; if (den.isONE() && S.den.isONE()) { n = num.sum(S.num); return new Quotient(ring, n); } if (den.isONE()) { n = num.multiply(S.den); n = n.sum(S.num); return new Quotient(ring, n, S.den, false); } if (S.den.isONE()) { n = S.num.multiply(den); n = n.sum(num); return new Quotient(ring, n, den, false); } if (den.compareTo(S.den) == 0) { n = num.sum(S.num); return new Quotient(ring, n, den, false); } GenPolynomial d; GenPolynomial sd; GenPolynomial g; g = ring.gcd(den, S.den); if (g.isONE()) { d = den; sd = S.den; } else { d = ring.divide(den, g); sd = ring.divide(S.den, g); } n = num.multiply(sd); n = n.sum(d.multiply(S.num)); if (n.isZERO()) { return ring.getZERO(); } GenPolynomial f; GenPolynomial dd; dd = den; if (!g.isONE()) { f = ring.gcd(n, g); if (!f.isONE()) { n = ring.divide(n, f); dd = ring.divide(den, f); } } d = dd.multiply(sd); return new Quotient(ring, n, d, true); } /** * Quotient negate. * @return -this. * @see edu.jas.structure.RingElem#negate() */ public Quotient negate() { return new Quotient(ring, num.negate(), den, true); } /** * Quotient signum. * @see edu.jas.structure.RingElem#signum() * @return signum(this). */ public int signum() { // assume sign(den) > 0 return num.signum(); } /** * Quotient subtraction. * @param S Quotient. * @return this-S. */ public Quotient subtract(Quotient S) { return sum(S.negate()); } /** * Quotient division. * @param S Quotient. * @return this/S. */ public Quotient divide(Quotient S) { return multiply(S.inverse()); } /** * Quotient inverse. * @see edu.jas.structure.RingElem#inverse() * @return S with S = 1/this. */ public Quotient inverse() { if (num.isZERO()) { throw new ArithmeticException("element not invertible " + this); } return new Quotient(ring, den, num, true); } /** * Quotient remainder. * @param S Quotient. * @return this - (this/S)*S. */ public Quotient remainder(Quotient S) { if (S.isZERO()) { throw new ArithmeticException("element not invertible " + S); } return ring.getZERO(); } /** * Quotient and remainder by division of this by S. * @param S a Quotient * @return [this/S, this - (this/S)*S]. */ @SuppressWarnings("unchecked") public Quotient[] quotientRemainder(Quotient S) { return new Quotient[] { divide(S), remainder(S) }; } /** * Quotient multiplication. * @param S Quotient. * @return this*S. */ public Quotient multiply(Quotient S) { if (S == null || S.isZERO()) { return S; } if (num.isZERO()) { return this; } if (S.isONE()) { return this; } if (this.isONE()) { return S; } GenPolynomial n; if (den.isONE() && S.den.isONE()) { n = num.multiply(S.num); return new Quotient(ring, n, den, true); } GenPolynomial g; GenPolynomial d; if (den.isONE()) { g = ring.gcd(num, S.den); n = ring.divide(num, g); d = ring.divide(S.den, g); n = n.multiply(S.num); return new Quotient(ring, n, d, true); } if (S.den.isONE()) { g = ring.gcd(S.num, den); n = ring.divide(S.num, g); d = ring.divide(den, g); n = n.multiply(num); return new Quotient(ring, n, d, true); } if (den.compareTo(S.den) == 0) { // correct ? d = den.multiply(den); n = num.multiply(S.num); return new Quotient(ring, n, d, true); } GenPolynomial f; GenPolynomial sd; GenPolynomial sn; g = ring.gcd(num, S.den); n = ring.divide(num, g); sd = ring.divide(S.den, g); f = ring.gcd(den, S.num); d = ring.divide(den, f); sn = ring.divide(S.num, f); n = n.multiply(sn); d = d.multiply(sd); return new Quotient(ring, n, d, true); } /** * Quotient multiplication by GenPolynomial. * @param b GenPolynomial. * @return this*b. */ public Quotient multiply(GenPolynomial b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenPolynomial gcd = ring.gcd(b, den); GenPolynomial d = den; if (!gcd.isONE()) { b = ring.divide(b, gcd); d = ring.divide(d, gcd); } if (this.isONE()) { return new Quotient(ring, b, d, true); } GenPolynomial n = num.multiply(b); return new Quotient(ring, n, d, true); } /** * Quotient multiplication by coefficient. * @param b coefficient. * @return this*b. */ public Quotient multiply(C b) { if (b == null || b.isZERO()) { return ring.getZERO(); } if (num.isZERO()) { return this; } if (b.isONE()) { return this; } GenPolynomial n = num.multiply(b); return new Quotient(ring, n, den, true); } /** * Quotient monic. * @return this with monic value part. */ public Quotient monic() { if (num.isZERO()) { return this; } C lbc = num.leadingBaseCoefficient(); if (!lbc.isUnit()) { return this; } lbc = lbc.inverse(); //lbc = lbc.abs(); GenPolynomial n = num.multiply(lbc); //GenPolynomial d = den.multiply(lbc); return new Quotient(ring, n, den, true); } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public Quotient gcd(Quotient b) { if (b == null || b.isZERO()) { return this; } if (this.isZERO()) { return b; } if (this.equals(b)) { return this; } return ring.getONE(); } /** * Extended greatest common divisor. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ @SuppressWarnings("unchecked") public Quotient[] egcd(Quotient b) { Quotient[] ret = (Quotient[]) new Quotient[3]; ret[0] = null; ret[1] = null; ret[2] = null; if (b == null || b.isZERO()) { ret[0] = this; return ret; } if (this.isZERO()) { ret[0] = b; return ret; } GenPolynomial two = ring.ring.fromInteger(2); ret[0] = ring.getONE(); ret[1] = (this.multiply(two)).inverse(); ret[2] = (b.multiply(two)).inverse(); return ret; } } java-algebra-system-2.7.200/src/edu/jas/ufd/QuotientRing.java000066400000000000000000000243571445075545500237430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Reader; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; // import edu.jas.gbufd.PolyGBUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.QuotPairFactory; import edu.jas.structure.RingFactory; /** * Quotient ring factory based on GenPolynomial with RingElem interface. Objects * of this class are immutable. * @author Heinz Kredel */ public class QuotientRing> implements RingFactory>, QuotPairFactory, Quotient> { private static final Logger logger = LogManager.getLogger(QuotientRing.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Quotient polynomial normalization, simplification. */ public static enum QuoNorm { normNumLead, // normalize ldcf(numerator) == 1 normNumTrail, // normalize trcf(numerator) == 1 normDenLead, // normalize ldcf(denominator) == 1 normDenTrail // normalize trcf(denominator) == 1 }; /** * Default quotient polynomial normalization, simplification. */ public final static QuoNorm quoNorm = QuoNorm.normDenLead; // must be the default // see https://github.com/kredel/java-algebra-system/issues/29 /** * Polynomial ring of the factory. */ public final GenPolynomialRing ring; /** * GCD engine of the factory. */ public final GreatestCommonDivisor engine; /** * Use GCD of package edu.jas.ufd. */ public final boolean ufdGCD; /** * The constructor creates a QuotientRing object from a GenPolynomialRing. * @param r polynomial ring. */ public QuotientRing(GenPolynomialRing r) { this(r, true); } /** * The constructor creates a QuotientRing object from a GenPolynomialRing. * @param r polynomial ring. * @param ufdGCD flag, if syzygy or gcd based algorithm used for engine. */ public QuotientRing(GenPolynomialRing r, boolean ufdGCD) { ring = r; this.ufdGCD = ufdGCD; // if (!ufdGCD) { // engine = null; // return; // } engine = GCDFactory. getProxy(ring.coFac); logger.debug("quotient ring constructed"); } /** * Factory for base elements. */ public GenPolynomialRing pairFactory() { return ring; } /** * Create from numerator. */ public Quotient create(GenPolynomial n) { return new Quotient(this, n); } /** * Create from numerator, denominator pair. */ public Quotient create(GenPolynomial n, GenPolynomial d) { return new Quotient(this, n, d); } /** * Divide. * @param n first polynomial. * @param d second polynomial. * @return divide(n,d) */ protected GenPolynomial divide(GenPolynomial n, GenPolynomial d) { return PolyUtil. basePseudoDivide(n, d); } /** * Greatest common divisor. * @param n first polynomial. * @param d second polynomial. * @return gcd(n,d) */ protected GenPolynomial gcd(GenPolynomial n, GenPolynomial d) { if (ufdGCD) { return engine.gcd(n, d); } return engine.gcd(n, d); //return PolyGBUtil. syzGcd(ring, n, d); } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return ring.isFinite(); } /** * Copy Quotient element c. * @param c * @return a copy of c. */ public Quotient copy(Quotient c) { return new Quotient(c.ring, c.num, c.den, true); } /** * Get the zero element. * @return 0 as Quotient. */ public Quotient getZERO() { return new Quotient(this, ring.getZERO()); } /** * Get the one element. * @return 1 as Quotient. */ public Quotient getONE() { return new Quotient(this, ring.getONE()); } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List> pgens = ring.generators(); List> gens = new ArrayList>(pgens.size()); for (GenPolynomial p : pgens) { Quotient q = new Quotient(this, p); gens.add(q); } return gens; } /** * Query if this ring is commutative. * @return true if this ring is commutative, else false. */ public boolean isCommutative() { return ring.isCommutative(); } /** * Query if this ring is associative. * @return true if this ring is associative, else false. */ public boolean isAssociative() { return ring.isAssociative(); } /** * Query if this ring is a field. * @return true. */ public boolean isField() { return true; } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return ring.characteristic(); } /** * Get a Quotient element from a BigInteger value. * @param a BigInteger. * @return a Quotient. */ public Quotient fromInteger(java.math.BigInteger a) { return new Quotient(this, ring.fromInteger(a)); } /** * Get a Quotient element from a long value. * @param a long. * @return a Quotient. */ public Quotient fromInteger(long a) { return new Quotient(this, ring.fromInteger(a)); } /** * Get the String representation as RingFactory. * @see java.lang.Object#toString() */ @Override public String toString() { String s = null; if (ring.coFac.characteristic().signum() == 0) { s = "RatFunc"; } else { s = "ModFunc"; } return s + "( " + ring.toString() + " )"; } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case return "RF(" + ring.toScript() + ")"; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (b == null) { return false; } if (!(b instanceof QuotientRing)) { return false; } QuotientRing a = (QuotientRing) b; return ring.equals(a.ring); } /** * Hash code for this quotient ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = ring.hashCode(); return h; } /** * Quotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @return a random residue element. */ public Quotient random(int n) { GenPolynomial r = ring.random(n).monic(); GenPolynomial s = ring.random(n).monic(); while (s.isZERO()) { s = ring.random(n).monic(); } return new Quotient(this, r, s, false); } /** * Generate a random quotient polynomial. * @param k bitsize of random coefficients. * @param l number of terms. * @param d maximal degree in each variable. * @param q density of nozero exponents. * @return a random quotient polynomial. */ public Quotient random(int k, int l, int d, float q) { GenPolynomial r = ring.random(k, l, d, q).monic(); GenPolynomial s = ring.random(k, l, d, q).monic(); while (s.isZERO()) { s = ring.random(k, l, d, q).monic(); } return new Quotient(this, r, s, false); } /** * Quotient random. * @param n such that 0 ≤ v ≤ (2n-1). * @param rnd is a source for random bits. * @return a random quotient element. */ public Quotient random(int n, Random rnd) { GenPolynomial r = ring.random(n, rnd).monic(); GenPolynomial s = ring.random(n, rnd).monic(); while (s.isZERO()) { s = ring.random(n, rnd).monic(); } return new Quotient(this, r, s, false); } /** * Parse Quotient from String. Syntax: "{ polynomial | polynomial }" or "{ * polynomial }" or " polynomial | polynomial " or " polynomial " * @param s String. * @return Quotient from s. */ public Quotient parse(String s) { int i = s.indexOf("{"); if (i >= 0) { s = s.substring(i + 1); } i = s.lastIndexOf("}"); if (i >= 0) { s = s.substring(0, i); } i = s.indexOf("|"); if (i < 0) { GenPolynomial n = ring.parse(s); return new Quotient(this, n); } String s1 = s.substring(0, i); String s2 = s.substring(i + 1); GenPolynomial n = ring.parse(s1); GenPolynomial d = ring.parse(s2); return new Quotient(this, n, d); } /** * Parse Quotient from Reader. * @param r Reader. * @return next Quotient from r. */ public Quotient parse(Reader r) { String s = StringUtil.nextPairedString(r, '{', '}'); return parse(s); } /** * Degree of extension field. * @return degree of this extension field, -1 for transcendental extension. */ public long extensionDegree() { long degree = -1L; if (ring.nvar <= 0) { degree = 0L; } return degree; } } java-algebra-system-2.7.200/src/edu/jas/ufd/QuotientTaylorFunction.java000066400000000000000000000057461445075545500260250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.List; import edu.jas.poly.ExpVector; import edu.jas.ps.TaylorFunction; import edu.jas.structure.GcdRingElem; /** * Polynomial quotient functions capable for Taylor series expansion. * @param ring element type * @author Heinz Kredel */ public class QuotientTaylorFunction> implements TaylorFunction { final Quotient quo; final long facul; public QuotientTaylorFunction(Quotient q) { this(q, 1L); } public QuotientTaylorFunction(Quotient q, long f) { quo = q; facul = f; } /** * To String. * @return string representation of this. */ @Override public String toString() { return quo.toString(); } /** * Get the factorial coefficient. * @return factorial coefficient. */ @Override public long getFacul() { return facul; } /** * Test if this is zero. * @return true if this is 0, else false. */ public boolean isZERO() { return quo.isZERO(); } /** * Derivative. * @return derivative of this. */ @Override public TaylorFunction derivative() { return new QuotientTaylorFunction(PolyUfdUtil. derivative(quo)); } /** * Partial derivative. * @param r index of the variable. * @return partial derivative of this with respect to variable r. */ public TaylorFunction derivative(int r) { return new QuotientTaylorFunction(PolyUfdUtil. derivative(quo, r)); } /** * Multi-partial derivative. * @param i exponent vector. * @return partial derivative of this with respect to all variables. */ public TaylorFunction derivative(ExpVector i) { Quotient q = quo; long f = 1L; if (i.signum() == 0 || quo.isZERO()) { return new QuotientTaylorFunction(q, f); } for (int j = 0; j < i.length(); j++) { long e = i.getVal(j); if (e == 0) { continue; } int jl = i.length() - 1 - j; for (long k = 0; k < e; k++) { q = PolyUfdUtil. derivative(q, jl); f *= (k + 1); if (q.isZERO()) { return new QuotientTaylorFunction(q, f); } } } //System.out.println("i = " + i + ", f = " + f + ", der = " + q); return new QuotientTaylorFunction(q, f); } /** * Evaluate. * @param a element. * @return this(a). */ @Override public C evaluate(C a) { C e = PolyUfdUtil. evaluateMain(quo.ring.ring.coFac, quo, a); return e; } /** * Evaluate at a tuple of elements. * @param a tuple of elements. * @return this(a). */ public C evaluate(List a) { return PolyUfdUtil. evaluateAll(quo.ring.ring.coFac, quo, a); } } java-algebra-system-2.7.200/src/edu/jas/ufd/Squarefree.java000066400000000000000000000076361445075545500234160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.io.Serializable; import java.util.List; import java.util.SortedMap; import edu.jas.poly.GenPolynomial; import edu.jas.structure.GcdRingElem; /** * Squarefree decomposition interface. *

* Usage: To create objects that implement the Squarefree * interface use the SquarefreeFactory. It will select an * appropriate implementation based on the types of polynomial coefficients C. * To obtain an implementation use getImplementation(), it returns * an object of a class which extends the SquarefreeAbstract class * which implements the Squarefree interface. *

* *

 * Squarefree<CT> engine;
 * engine = SquarefreeFactory.<CT> getImplementation(cofac);
 * c = engine.squarefreeFactors(a);
 * 
* *

* For example, if the coefficient type is BigInteger, the usage looks like * *

* *

 * BigInteger cofac = new BigInteger();
 * Squarefree<BigInteger> engine;
 * engine = SquarefreeFactory.getImplementation(cofac);
 * Sm = engine.sqaurefreeFactors(poly);
 * 
* * @author Heinz Kredel * @see edu.jas.ufd.SquarefreeFactory#getImplementation */ public interface Squarefree> extends Serializable { /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ public GenPolynomial squarefreePart(GenPolynomial P); /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isSquarefree(GenPolynomial P); /** * GenPolynomial list test if squarefree. * @param L list of GenPolynomial. * @return true if each P in L is squarefree, else false. */ public boolean isSquarefree(List> L); /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree. */ public SortedMap, Long> squarefreeFactors(GenPolynomial P); /** * GenPolynomial is (squarefree) factorization. * @param P GenPolynomial. * @param F = [p_1,...,p_k]. * @return true if P = prod_{i=1,...,r} p_i, else false. */ public boolean isFactorization(GenPolynomial P, List> F); /** * GenPolynomial is (squarefree) factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. */ public boolean isFactorization(GenPolynomial P, SortedMap, Long> F); /** * GenPolynomial squarefree and co-prime list. * @param A list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a and each b in B is * squarefree. B does not contain zero or constant polynomials. */ public List> coPrimeSquarefree(List> A); /** * GenPolynomial squarefree and co-prime list. * @param a polynomial. * @param P squarefree co-prime list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a * there exists b in P with b|a. B does not contain zero or constant * polynomials. */ public List> coPrimeSquarefree(GenPolynomial a, List> P); /** * Test if list of GenPolynomials is squarefree and co-prime. * @param B list of GenPolynomials. * @return true, if for all b != c in B gcd(b,c) = 1 and each b in B is * squarefree, else false. */ public boolean isCoPrimeSquarefree(List> B); } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeAbstract.java000066400000000000000000000542071445075545500250760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.Set; import java.util.HashSet; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Abstract squarefree decomposition class. * @author Heinz Kredel */ public abstract class SquarefreeAbstract> implements Squarefree { private static final Logger logger = LogManager.getLogger(SquarefreeAbstract.class); /** * GCD engine for respective base coefficients. */ protected final GreatestCommonDivisorAbstract engine; /** * Constructor. */ public SquarefreeAbstract(GreatestCommonDivisorAbstract engine) { this.engine = engine; } /** * GenPolynomial polynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ public abstract GenPolynomial baseSquarefreePart(GenPolynomial P); /** * GenPolynomial polynomial squarefree factorization. * @param A GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with A = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ public abstract SortedMap, Long> baseSquarefreeFactors(GenPolynomial A); /** * GenPolynomial recursive polynomial greatest squarefree divisor. * @param P recursive univariate GenPolynomial. * @return squarefree(pp(P)). */ public abstract GenPolynomial> recursiveUnivariateSquarefreePart( GenPolynomial> P); /** * GenPolynomial recursive univariate polynomial squarefree factorization. * @param P recursive univariate GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ public abstract SortedMap>, Long> recursiveUnivariateSquarefreeFactors( GenPolynomial> P); /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(P) a primitive respectively monic polynomial. */ public abstract GenPolynomial squarefreePart(GenPolynomial P); /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isSquarefree(GenPolynomial P) { SortedMap, Long> sm = squarefreeFactors(P); Set ex = new HashSet( sm.values() ); //System.out.println("exponents: " + ex + ", sm = " + sm + ", P = " + P); if (ex.size() != 1) { return false; } if (ex.contains(Long.valueOf(1L))) { return true; } return false; } /*public*/ boolean isSquarefreeAlternative(GenPolynomial P) { GenPolynomial S = squarefreePart(P); GenPolynomial Ps = P; if (P.ring.coFac.isField()) { Ps = Ps.monic(); } else { Ps = engine.basePrimitivePart(Ps); } boolean f = Ps.equals(S); return f; } /** * GenPolynomial list test if squarefree. * @param L list of GenPolynomial. * @return true if each P in L is squarefree, else false. */ public boolean isSquarefree(List> L) { if (L == null || L.isEmpty()) { return true; } for (GenPolynomial P : L) { if (!isSquarefree(P)) { return false; } } return true; } /** * Recursive GenPolynomial test if is squarefree. * @param P recursive univariate GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isRecursiveSquarefree(GenPolynomial> P) { GenPolynomial> S = recursiveUnivariateSquarefreePart(P); boolean f = P.equals(S); if (!f) { logger.info("not Squarefree, S != P: {} != {}", P, S); } return f; } /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ public abstract SortedMap, Long> squarefreeFactors(GenPolynomial P); /** * GenPolynomial squarefree and co-prime list. * @param A list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for all non-constant * a in A there exists b in B with b|a and each b in B is * squarefree. B does not contain zero or constant polynomials. */ public List> coPrimeSquarefree(List> A) { if (A == null || A.isEmpty()) { return A; } List> S = new ArrayList>(); for (GenPolynomial g : A) { SortedMap, Long> sm = squarefreeFactors(g); S.addAll(sm.keySet()); } List> B = engine.coPrime(S); return B; } /** * GenPolynomial squarefree and co-prime list. * @param a polynomial. * @param P squarefree co-prime list of GenPolynomials. * @return B with gcd(b,c) = 1 for all b != c in B and for non-constant a * there exists b in P with b|a. B does not contain zero or constant * polynomials. */ public List> coPrimeSquarefree(GenPolynomial a, List> P) { if (a == null || a.isZERO() || a.isConstant()) { return P; } SortedMap, Long> sm = squarefreeFactors(a); List> B = P; for (GenPolynomial f : sm.keySet()) { B = engine.coPrime(f, B); } return B; } /** * Test if list of GenPolynomials is squarefree and co-prime. * @param B list of GenPolynomials. * @return true, if for all b != c in B gcd(b,c) = 1 and each b in B is * squarefree, else false. */ public boolean isCoPrimeSquarefree(List> B) { if (B == null || B.isEmpty()) { return true; } if (!engine.isCoPrime(B)) { return false; } return isSquarefree(B); } /** * Normalize factorization. p'_i > 0 for i > 1 and p'_1 != 1 if k > * 1. * @param F = [p_1->e_1;, ..., p_k->e_k]. * @return F' = [p'_1->e_1, ..., p'_k->e_k]. */ public SortedMap, Long> normalizeFactorization(SortedMap, Long> F) { if (F == null || F.size() <= 1) { return F; } List> Fp = new ArrayList>(F.keySet()); GenPolynomial f0 = Fp.get(0); if (f0.ring.characteristic().signum() != 0) { // only ordered coefficients return F; } long e0 = F.get(f0); SortedMap, Long> Sp = new TreeMap, Long>(); for (int i = 1; i < Fp.size(); i++) { GenPolynomial fi = Fp.get(i); long ei = F.get(fi); if (fi.signum() < 0) { //System.out.println("e0 = " + e0 + ", f0 = " + f0); //System.out.println("ei = " + ei + ", fi = " + fi); if (ei % 2 != 0 && e0 % 2 != 0) { // bug fi = fi.negate(); f0 = f0.negate(); } } Sp.put(fi, ei); } if (!f0.isONE()) { Sp.put(f0, e0); } return Sp; } /** * GenPolynomial is (squarefree) factorization. * @param P GenPolynomial. * @param F = [p_1, ..., p_k]. * @return true if P = prod_{i=1,...,r} p_i, else false. */ public boolean isFactorization(GenPolynomial P, List> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } GenPolynomial t = P.ring.getONE(); for (GenPolynomial f : F) { t = t.multiply(f); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { logger.info("no factorization(list): F = {}, P = {}, t = {}", F, P, t); } return f; } /** * Count number of factors in a (squarefree) factorization. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return sum_{i=1,...,k} e_i. */ public long factorCount(SortedMap, Long> F) { if (F == null || F.isEmpty()) { return 0L; } long f = 0L; for (Long e : F.values()) { f += e; } return f; } /** * GenPolynomial is (squarefree) factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. */ public boolean isFactorization(GenPolynomial P, SortedMap, Long> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } GenPolynomial t = P.ring.getONE(); for (Map.Entry, Long> me : F.entrySet()) { GenPolynomial f = me.getKey(); Long E = me.getValue(); long e = E.longValue(); GenPolynomial g = f.power(e); t = t.multiply(g); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { P = P.monic(); t = t.monic(); f = P.equals(t) || P.equals(t.negate()); if (f) { return f; } logger.info("no factorization(map): F = {}, P = {}, t = {}", F, P, t); //RuntimeException e = new RuntimeException("fac-map"); //e.printStackTrace(); //throw e; } return f; } /** * GenPolynomial is (squarefree) factorization. * @param P GenPolynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**e_i, else false. */ public boolean isRecursiveFactorization(GenPolynomial> P, SortedMap>, Long> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } GenPolynomial> t = P.ring.getONE(); for (Map.Entry>, Long> me : F.entrySet()) { GenPolynomial> f = me.getKey(); Long E = me.getValue(); // F.get(f); long e = E.longValue(); GenPolynomial> g = f.power(e); t = t.multiply(g); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { GenPolynomialRing cf = (GenPolynomialRing) P.ring.coFac; GreatestCommonDivisorAbstract engine = GCDFactory.getProxy(cf.coFac); GenPolynomial> Pp = engine.recursivePrimitivePart(P); Pp = PolyUtil. monic(Pp); GenPolynomial> tp = engine.recursivePrimitivePart(t); tp = PolyUtil. monic(tp); f = Pp.equals(tp) || Pp.equals(tp.negate()); if (f) { return f; } logger.info("no factorization(map): F = {}, P = {}, t = {}, Pp = {}, tp = {}", F, P, t, Pp, tp); //RuntimeException e = new RuntimeException("fac-map"); //e.printStackTrace(); //throw e; } return f; } /** * GenPolynomial recursive polynomial greatest squarefree divisor. * @param P recursive GenPolynomial. * @return squarefree(pp(P)). */ public GenPolynomial> recursiveSquarefreePart(GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } if (P.ring.nvar <= 1) { return recursiveUnivariateSquarefreePart(P); } // distributed polynomials squarefree part GenPolynomialRing> rfac = P.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.nvar); GenPolynomial Pd = PolyUtil. distribute(dfac, P); GenPolynomial Dd = squarefreePart(Pd); // convert to recursive GenPolynomial> C = PolyUtil. recursive(rfac, Dd); return C; } /** * GenPolynomial recursive polynomial squarefree factorization. * @param P recursive GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ public SortedMap>, Long> recursiveSquarefreeFactors( GenPolynomial> P) { SortedMap>, Long> factors; factors = new TreeMap>, Long>(); if (P == null || P.isZERO()) { return factors; } if (P.ring.nvar <= 1) { return recursiveUnivariateSquarefreeFactors(P); } // distributed polynomials squarefree part GenPolynomialRing> rfac = P.ring; RingFactory> rrfac = rfac.coFac; GenPolynomialRing cfac = (GenPolynomialRing) rrfac; GenPolynomialRing dfac = cfac.extend(rfac.nvar); GenPolynomial Pd = PolyUtil. distribute(dfac, P); SortedMap, Long> dfacs = squarefreeFactors(Pd); // convert to recursive for (Map.Entry, Long> Dm : dfacs.entrySet()) { GenPolynomial Dd = Dm.getKey(); Long e = Dm.getValue(); GenPolynomial> C = PolyUtil. recursive(rfac, Dd); factors.put(C, e); } return factors; } /** * Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param D sorted map [d_1 -> e_1, ..., d_k -> e_k] with d_i * squarefree. * @return [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] with A/prod(D) = A0 + sum( * sum ( Aij/di^j ) ) with deg(Aij) < deg(di). */ public List>> basePartialFraction(GenPolynomial A, SortedMap, Long> D) { if (D == null || A == null) { throw new IllegalArgumentException("null A or D not allowed"); } List>> pf = new ArrayList>>(D.size() + 1); if (D.size() == 0) { return pf; } //List> fi; if (A.isZERO()) { for (Map.Entry, Long> me : D.entrySet()) { long e = me.getValue(); int e1 = (int) e + 1; List> fi = new ArrayList>(e1); for (int i = 0; i < e1; i++) { fi.add(A); } pf.add(fi); } List> fi = new ArrayList>(1); fi.add(A); pf.add(0, fi); return pf; } // A != 0, D != empty List> Dp = new ArrayList>(D.size()); for (Map.Entry, Long> me : D.entrySet()) { GenPolynomial d = me.getKey(); long e = me.getValue(); //D.get(d); GenPolynomial f = d.power(e); Dp.add(f); } List> F = engine.basePartialFraction(A, Dp); //System.out.println("fraction list = " + F.size()); GenPolynomial A0 = F.remove(0); List> fi = new ArrayList>(1); fi.add(A0); pf.add(fi); int i = 0; for (Map.Entry, Long> me : D.entrySet()) { // assume fixed sequence order GenPolynomial d = me.getKey(); long e = me.getValue(); int ei = (int) e; GenPolynomial gi = F.get(i); // assume fixed sequence order List> Fi = engine.basePartialFraction(gi, d, ei); pf.add(Fi); i++; } return pf; } /** * Test for Univariate GenPolynomial partial fraction decomposition. * @param A univariate GenPolynomial. * @param D sorted map [d_1 -> e_1, ..., d_k -> e_k] with d_i * squarefree. * @param F a list of lists [ [Ai0, Ai1,..., Aie_i], i=0,...,k ] * @return true, if A/prod(D) = A0 + sum( sum ( Aij/di^j ) ), else false. */ public boolean isBasePartialFraction(GenPolynomial A, SortedMap, Long> D, List>> F) { if (D == null || A == null || F == null) { throw new IllegalArgumentException("null A, D or F not allowed"); } if (D.isEmpty() && F.isEmpty()) { return true; } if (D.isEmpty() || F.isEmpty()) { return false; } List> Dp = new ArrayList>(D.size()); for (Map.Entry, Long> me : D.entrySet()) { GenPolynomial d = me.getKey(); long e = me.getValue(); // D.get(d); GenPolynomial f = d.power(e); Dp.add(f); } List> fi = F.get(0); if (fi.size() != 1) { logger.info("size(fi) != 1 {}", fi); return false; } boolean t; GenPolynomial A0 = fi.get(0); //System.out.println("A0 = " + A0); List> Qp = new ArrayList>(D.size() + 1); Qp.add(A0); // List> Fp = engine.basePartialFraction(A,Dp); // System.out.println("fraction list = " + F.size()); // t = engine.isBasePartialFraction(A,Dp,Fp); // if ( ! t ) { // System.out.println("not recursion isPartFrac = " + Fp); // return false; // } // GenPolynomial A0p = Fp.remove(0); // if ( ! A0.equals(A0p) ) { // System.out.println("A0 != A0p " + A0p); // return false; // } int i = 0; for (Map.Entry, Long> me : D.entrySet()) { // assume fixed sequence order GenPolynomial d = me.getKey(); long e = me.getValue(); int ei = (int) e; List> Fi = F.get(i + 1); // assume fixed sequence order // GenPolynomial pi = Fp.get(i); // assume fixed sequence order // t = engine.isBasePartialFraction(pi,d,ei,Fi); // if ( ! t ) { // System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei); // System.out.println("not isPartFrac exp = " + Fi); // return false; // } GenPolynomial qi = engine.basePartialFractionValue(d, ei, Fi); Qp.add(qi); // t = qi.equals(pi); // if ( ! t ) { // System.out.println("not isPartFrac exp = " + pi + ", d = " + d + ", e = " + ei + ", qi = " + qi); // } i++; } t = engine.isBasePartialFraction(A, Dp, Qp); if (!t) { System.out.println("not final isPartFrac " + Qp); } return t; } /** * Coefficients greatest squarefree divisor. * @param P coefficient. * @return squarefree part of P. */ public C squarefreePart(C P) { if (P == null) { return null; } C s = null; SortedMap factors = squarefreeFactors(P); //if (logger.isWarnEnabled()) { // logger.warn("sqfPart, better use sqfFactors, factors = {}", factors); //} for (C sp : factors.keySet()) { if (s == null) { s = sp; } else { s = s.multiply(sp); } } return s; } /** * Coefficients squarefree factorization. * @param P coefficient. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ public abstract SortedMap squarefreeFactors(C P); /* not possible: { if (P == null) { return null; } SortedMap factors = new TreeMap(); SquarefreeAbstract reng = SquarefreeFactory.getImplementation((RingFactory) P.factory()); System.out.println("fcp,reng = " + reng); SortedMap rfactors = reng.squarefreeFactors(P); for (C c : rfactors.keySet()) { if (!c.isONE()) { C cr = (C) (Object) c; Long rk = rfactors.get(c); factors.put(cr, rk); } } return factors; } */ } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeFactory.java000066400000000000000000000237001445075545500247340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree factorization algorithms factory. Select appropriate squarefree * factorization engine based on the coefficient types. *

* Usage: To create objects that implement the Squarefree * interface use the SquarefreeFactory. It will select an * appropriate implementation based on the types of polynomial coefficients C. * To obtain an implementation use getImplementation(), it returns * an object of a class which extends the SquarefreeAbstract class * which implements the Squarefree interface. * *

 * Squarefree<CT> engine;
 * engine = SquarefreeFactory.<CT> getImplementation(cofac);
 * c = engine.squarefreeFactors(a);
 * 
* * For example, if the coefficient type is BigInteger, the usage looks like * *
 * BigInteger cofac = new BigInteger();
 * Squarefree<BigInteger> engine;
 * engine = SquarefreeFactory.getImplementation(cofac);
 * Sm = engine.sqaurefreeFactors(poly);
 * 
* * @author Heinz Kredel * @see edu.jas.ufd.Squarefree#squarefreeFactors(edu.jas.poly.GenPolynomial P) */ public class SquarefreeFactory { private static final Logger logger = LogManager.getLogger(SquarefreeFactory.class); /** * Protected factory constructor. */ protected SquarefreeFactory() { } /** * Determine suitable implementation of factorization algorithm, case * ModInteger. * @param fac ModIntegerRing. * @return squarefree factorization algorithm implementation. */ public static SquarefreeAbstract getImplementation(ModIntegerRing fac) { // fac.isField() checked in constructor return new SquarefreeFiniteFieldCharP(fac); } /** * Determine suitable implementation of factorization algorithm, case * ModLong. * @param fac ModLongRing. * @return squarefree factorization algorithm implementation. */ public static SquarefreeAbstract getImplementation(ModLongRing fac) { // fac.isField() checked in constructor return new SquarefreeFiniteFieldCharP(fac); } /** * Determine suitable implementation of factorization algorithm, case * ModInt. * @param fac ModIntRing. * @return squarefree factorization algorithm implementation. */ public static SquarefreeAbstract getImplementation(ModIntRing fac) { // fac.isField() checked in constructor return new SquarefreeFiniteFieldCharP(fac); } /** * Determine suitable implementation of squarefree factorization algorithm, * case BigInteger. * @param fac BigInteger. * @return squarefree factorization algorithm implementation. */ public static SquarefreeAbstract getImplementation(BigInteger fac) { return new SquarefreeRingChar0(fac); } /** * Determine suitable implementation of squarefree factorization algorithms, * case BigRational. * @param fac BigRational. * @return squarefree factorization algorithm implementation. */ public static SquarefreeAbstract getImplementation(BigRational fac) { return new SquarefreeFieldChar0Yun(fac); } /** * Determine suitable implementation of squarefree factorization algorithms, * case AlgebraicNumber<C>. * @param fac AlgebraicNumberRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return squarefree factorization algorithm implementation. */ public static > SquarefreeAbstract> getImplementation( AlgebraicNumberRing fac) { PolyUfdUtil. ensureFieldProperty(fac); if (fac.isField()) { if (fac.characteristic().signum() == 0) { return new SquarefreeFieldChar0Yun>(fac); } if (fac.isFinite()) { return new SquarefreeFiniteFieldCharP>(fac); } return new SquarefreeInfiniteAlgebraicFieldCharP(fac); } throw new ArithmeticException("eventually no integral domain " + fac.getClass().getName()); } /** * Determine suitable implementation of squarefree factorization algorithms, * case Quotient<C>. * @param fac QuotientRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return squarefree factorization algorithm implementation. */ public static > SquarefreeAbstract> getImplementation( QuotientRing fac) { if (fac.characteristic().signum() == 0) { return new SquarefreeFieldChar0Yun>(fac); } return new SquarefreeInfiniteFieldCharP(fac); } /** * Determine suitable implementation of squarefree factorization algorithms, * case GenPolynomial<C>. * @param fac GenPolynomialRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return squarefree factorization algorithm implementation. */ public static > SquarefreeAbstract getImplementation( GenPolynomialRing fac) { return getImplementationPoly(fac); } /* * Determine suitable implementation of squarefree factorization algorithms, * case GenPolynomial<C>. * @param fac GenPolynomialRing<C>. * @param coefficient type, e.g. BigRational, ModInteger. * @return squarefree factorization algorithm implementation. */ @SuppressWarnings({ "unchecked", "cast" }) protected static > SquarefreeAbstract getImplementationPoly( GenPolynomialRing fac) { if (fac.characteristic().signum() == 0) { if (fac.coFac.isField()) { return new SquarefreeFieldChar0Yun(fac.coFac); } return new SquarefreeRingChar0(fac.coFac); } if (fac.coFac.isFinite()) { return new SquarefreeFiniteFieldCharP(fac.coFac); } Object ocfac = fac.coFac; SquarefreeAbstract saq = null; if (ocfac instanceof QuotientRing) { QuotientRing qf = (QuotientRing) ocfac; saq = new SquarefreeInfiniteFieldCharP(qf); } else if (ocfac instanceof AlgebraicNumberRing) { AlgebraicNumberRing af = (AlgebraicNumberRing) ocfac; saq = new SquarefreeInfiniteAlgebraicFieldCharP(af); } if (saq == null) { throw new IllegalArgumentException("no squarefree factorization " + fac.coFac); } SquarefreeAbstract sa = (SquarefreeAbstract) saq; return sa; } /** * Determine suitable implementation of squarefree factorization algorithms, * other cases. * @param coefficient type * @param fac RingFactory<C>. * @return squarefree factorization algorithm implementation. */ @SuppressWarnings({ "unchecked", "cast" }) public static > SquarefreeAbstract getImplementation(RingFactory fac) { //logger.info("fac = {}", fac.getClass().getName()); //System.out.println("fac_o = " + fac.getClass().getName()); SquarefreeAbstract/*raw type*/ ufd = null; AlgebraicNumberRing afac = null; QuotientRing qfac = null; GenPolynomialRing pfac = null; Object ofac = fac; if (ofac instanceof BigInteger) { ufd = new SquarefreeRingChar0(fac); } else if (ofac instanceof BigRational) { ufd = new SquarefreeFieldChar0Yun(fac); } else if (ofac instanceof ModIntegerRing) { ufd = new SquarefreeFiniteFieldCharP(fac); } else if (ofac instanceof ModLongRing) { ufd = new SquarefreeFiniteFieldCharP(fac); } else if (ofac instanceof ModIntRing) { ufd = new SquarefreeFiniteFieldCharP(fac); } else if (ofac instanceof AlgebraicNumberRing) { afac = (AlgebraicNumberRing) ofac; //ofac = afac.ring.coFac; //System.out.println("o_afac = " + ofac); ufd = getImplementation(afac); } else if (ofac instanceof QuotientRing) { qfac = (QuotientRing) ofac; ufd = getImplementation(qfac); } else if (ofac instanceof GenPolynomialRing) { pfac = (GenPolynomialRing) ofac; ufd = getImplementationPoly(pfac); } else if (fac.isField()) { //System.out.println("fac_field = " + fac); if (fac.characteristic().signum() == 0) { ufd = new SquarefreeFieldChar0Yun(fac); } else { if (fac.isFinite()) { ufd = new SquarefreeFiniteFieldCharP(fac); } else { ufd = new SquarefreeInfiniteFieldCharP/*raw*/(fac); } } } else if (fac.characteristic().signum() == 0) { ufd = new SquarefreeRingChar0(fac); } else { throw new IllegalArgumentException( "no squarefree factorization implementation for " + fac.getClass().getName()); } logger.debug("ufd = {}", ufd); return (SquarefreeAbstract) ufd; } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeFieldChar0.java000066400000000000000000000454171445075545500252370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for coefficient fields of characteristic 0. * @author Heinz Kredel */ public class SquarefreeFieldChar0> extends SquarefreeAbstract { private static final Logger logger = LogManager.getLogger(SquarefreeFieldChar0.class); private static final boolean debug = logger.isDebugEnabled(); /** * Factory for field of characteristic 0 coefficients. */ protected final RingFactory coFac; /** * Constructor. */ public SquarefreeFieldChar0(RingFactory fac) { super(GCDFactory. getProxy(fac)); if (!fac.isField()) { throw new IllegalArgumentException("fac must be a field"); } if (fac.characteristic().signum() != 0) { throw new IllegalArgumentException("characteristic(fac) must be zero"); } coFac = fac; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + " with " + engine + " over " + coFac; } /** * GenPolynomial polynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(P). */ @Override public GenPolynomial baseSquarefreePart(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial pp = P.monic(); if (pp.isConstant()) { return pp; } GenPolynomial d = PolyUtil. baseDerivative(pp); d = d.monic(); //System.out.println("d = " + d); GenPolynomial g = engine.baseGcd(pp, d); g = g.monic(); GenPolynomial q = PolyUtil. basePseudoDivide(pp, g); q = q.monic(); return q; } /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isBaseSquarefree(GenPolynomial P) { if (P == null || P.isZERO()) { return true; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial pp = P.monic(); if (pp.isConstant()) { return true; } GenPolynomial d = PolyUtil. baseDerivative(pp); d = d.monic(); //System.out.println("d = " + d); GenPolynomial g = engine.baseGcd(pp, d); //g = g.monic(); //System.out.println("baseGcd: g = " + g); if (g.isONE()) { return true; } if (g.degree() >= 1) { // 1 here okay return false; } //return g.isONE(); return true; } /** * GenPolynomial polynomial squarefree factorization. * @param A GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with A = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> baseSquarefreeFactors(GenPolynomial A) { SortedMap, Long> sfactors = new TreeMap, Long>(); if (A == null || A.isZERO()) { return sfactors; } if (A.isConstant()) { sfactors.put(A, 1L); return sfactors; } GenPolynomialRing pfac = A.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } C ldbcf = A.leadingBaseCoefficient(); if (!ldbcf.isONE()) { A = A.divide(ldbcf); GenPolynomial f1 = pfac.getONE().multiply(ldbcf); //System.out.println("gcda sqf f1 = " + f1); sfactors.put(f1, 1L); ldbcf = pfac.coFac.getONE(); } // divide by trailing term ExpVector et = A.trailingExpVector(); if (!et.isZERO()) { GenPolynomial tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); A = PolyUtil. basePseudoDivide(A, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); logger.info("tr, ep = {}, {}", tr, ep); sfactors.put(tr, ep); if (A.length() == 1) { return sfactors; } } GenPolynomial T0 = A; GenPolynomial Tp; GenPolynomial T = null; GenPolynomial V = null; long k = 0L; boolean init = true; while (true) { if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. baseDerivative(T0); T = engine.baseGcd(T0, Tp); T = T.monic(); V = PolyUtil. basePseudoDivide(T0, T); //System.out.println("iT0 = " + T0); //System.out.println("iTp = " + Tp); //System.out.println("iT = " + T); //System.out.println("iV = " + V); k = 0L; init = false; } if (V.isConstant()) { break; } k++; GenPolynomial W = engine.baseGcd(T, V); W = W.monic(); GenPolynomial z = PolyUtil. basePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. basePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); if (z.degree(0) > 0) { if (ldbcf.isONE() && !z.leadingBaseCoefficient().isONE()) { z = z.monic(); //logger.info("z,monic = {}", z); } logger.info("z, k = {}, {}", z, k); sfactors.put(z, k); } } return normalizeFactorization(sfactors); } /** * GenPolynomial recursive univariate polynomial greatest squarefree * divisor. * @param P recursive univariate GenPolynomial. * @return squarefree(P). */ @Override public GenPolynomial> recursiveUnivariateSquarefreePart( GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate recursive polynomials"); } // remove content GenPolynomial> pp = P; GenPolynomial Pc = engine.recursiveContent(P); //?? Pc = Pc.monic(); if (!Pc.isONE()) { pp = PolyUtil. coefficientPseudoDivide(pp, Pc); //System.out.println("P/cont = " + pp + ", cont = " + Pc); } // squarefree content GenPolynomial Ps = squarefreePart(Pc); //System.out.println("Pc = " + Pc + ", Ps = " + Ps); if (pp.leadingExpVector().getVal(0) < 1) { //System.out.println("pp = " + pp); //System.out.println("Ps = " + Ps); pp = pp.multiply(Ps); pp = PolyUtil. monic(pp); return pp; } GenPolynomial> d = PolyUtil. recursiveDerivative(pp); //System.out.println("d = " + d); GenPolynomial> g = engine.recursiveUnivariateGcd(pp, d); //System.out.println("g,rec = " + g); //??g = PolyUtil. monic(g); GenPolynomial> q = PolyUtil. recursivePseudoDivide(pp, g); q = q.multiply(Ps); q = PolyUtil. monic(q); return q; } /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ public boolean isRecursiveUnivariateSquarefree(GenPolynomial> P) { if (P == null || P.isZERO()) { return true; } if (P.isConstant() || (P.degree(0) == 1 && P.length() == 1)) { return isSquarefree(P.leadingBaseCoefficient()); } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate recursive polynomials"); } GenPolynomial> pp = P; GenPolynomial> d = PolyUtil. recursiveDerivative(pp); //System.out.println("d = " + d); if (d.isZERO()) { return false; } GenPolynomial> g = engine.recursiveUnivariateGcd(pp, d); //logger.info("gcd = {} :: {}, pp={}, d={}", g, g.ring.toScript(), pp, d); //System.out.println("g,rec = " + g); if (g.isONE()) { return true; } if (g.degree() >= 1) { // 1 here okay return false; } GenPolynomial lcg = g.leadingBaseCoefficient(); logger.info("lcg = {}, degree {}, g = {}", lcg, lcg.degree(), g); if (isSquarefree(lcg)) { return true; } return false; } /** * GenPolynomial recursive univariate polynomial squarefree factorization. * @param P recursive univariate GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap>, Long> recursiveUnivariateSquarefreeFactors( GenPolynomial> P) { SortedMap>, Long> sfactors = new TreeMap>, Long>(); if (P == null || P.isZERO()) { return sfactors; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // recursiveContent not possible by return type throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } // if base coefficient ring is a field, make monic GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; C ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); if (!ldbcf.isONE()) { GenPolynomial lc = cfac.getONE().multiply(ldbcf); GenPolynomial> pl = pfac.getONE().multiply(lc); sfactors.put(pl, 1L); C li = ldbcf.inverse(); //System.out.println("li = " + li); P = P.multiply(cfac.getONE().multiply(li)); //System.out.println("P,monic = " + P); ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); } // factors of content GenPolynomial Pc = engine.recursiveContent(P); logger.info("recursiveContent = {}", Pc); Pc = Pc.monic(); if (!Pc.isONE()) { P = PolyUtil. coefficientPseudoDivide(P, Pc); } SortedMap, Long> rsf = squarefreeFactors(Pc); logger.info("squarefreeFactors = {}", rsf); // add factors of content for (Map.Entry, Long> me : rsf.entrySet()) { GenPolynomial c = me.getKey(); if (!c.isONE()) { GenPolynomial> cr = pfac.getONE().multiply(c); Long rk = me.getValue(); // rsf.get(c); sfactors.put(cr, rk); } } // divide by trailing term ExpVector et = P.trailingExpVector(); if (!et.isZERO()) { GenPolynomial> tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); P = PolyUtil. recursivePseudoDivide(P, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); sfactors.put(tr, ep); } // factors of recursive polynomial GenPolynomial> T0 = P; GenPolynomial> Tp; GenPolynomial> T = null; GenPolynomial> V = null; long k = 0L; boolean init = true; while (true) { if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. recursiveDerivative(T0); T = engine.recursiveUnivariateGcd(T0, Tp); T = PolyUtil. monic(T); V = PolyUtil. recursivePseudoDivide(T0, T); //System.out.println("iT0 = " + T0); //System.out.println("iTp = " + Tp); //System.out.println("iT = " + T); //System.out.println("iV = " + V); k = 0L; init = false; } if (V.isConstant()) { break; } k++; GenPolynomial> W = engine.recursiveUnivariateGcd(T, V); W = PolyUtil. monic(W); GenPolynomial> z = PolyUtil. recursivePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. recursivePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); //was: if ( z.degree(0) > 0 ) { if (!z.isONE() && !z.isZERO()) { if (ldbcf.isONE()) { z = PolyUtil. monic(z); logger.info("z,monic = {}", z); } sfactors.put(z, k); } } return sfactors; } /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ @Override public GenPolynomial squarefreePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseSquarefreePart(P); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial Pc = engine.recursiveContent(Pr); Pr = PolyUtil. coefficientPseudoDivide(Pr, Pc); GenPolynomial Ps = squarefreePart(Pc); logger.info("content = {}, squarefreePart = {}", Pc, Ps); GenPolynomial> PP = recursiveUnivariateSquarefreePart(Pr); GenPolynomial> PS = PP.multiply(Ps); GenPolynomial D = PolyUtil. distribute(pfac, PS); logger.info("univRec = {}, squarefreePart = {}", Pr, PP); return D; } /** * GenPolynomial test if is squarefree. * @param P GenPolynomial. * @return true if P is squarefree, else false. */ @Override public boolean isSquarefree(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return true; } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return isBaseSquarefree(P); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); boolean s1 = isRecursiveUnivariateSquarefree(Pr); if (debug) { boolean s2 = super.isSquarefree(P); if (s1 != s2) { logger.info("s_rec != s2_sup: {}", P); throw new RuntimeException("s_rec != s2_sup: " + s1 + ", " + s2); } } return s1; } /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> squarefreeFactors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return normalizeFactorization(baseSquarefreeFactors(P)); } SortedMap, Long> sfactors = new TreeMap, Long>(); if (P.isZERO()) { return normalizeFactorization(sfactors); } if (P.isONE()) { sfactors.put(P, 1L); return normalizeFactorization(sfactors); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); SortedMap>, Long> PP = recursiveUnivariateSquarefreeFactors(Pr); for (Map.Entry>, Long> m : PP.entrySet()) { Long i = m.getValue(); GenPolynomial> Dr = m.getKey(); GenPolynomial D = PolyUtil. distribute(pfac, Dr); sfactors.put(D, i); } logger.info("squarefreeFactors({}) = {}", P, sfactors); return normalizeFactorization(sfactors); } /** * Coefficients squarefree factorization. * @param P coefficient. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap squarefreeFactors(C P) { throw new UnsupportedOperationException("method not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeFieldChar0Yun.java000066400000000000000000000202371445075545500257240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for coefficient fields of characteristic 0, * algorithm of Yun. * @author Heinz Kredel */ public class SquarefreeFieldChar0Yun> extends SquarefreeFieldChar0 { private static final Logger logger = LogManager.getLogger(SquarefreeFieldChar0Yun.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public SquarefreeFieldChar0Yun(RingFactory fac) { super(fac); } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + " with " + engine + " over " + coFac; } /** * GenPolynomial polynomial squarefree factorization. * @param A GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with A = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> baseSquarefreeFactors(GenPolynomial A) { SortedMap, Long> sfactors = new TreeMap, Long>(); if (A == null || A.isZERO()) { return sfactors; } if (A.isConstant()) { sfactors.put(A, 1L); return sfactors; } GenPolynomialRing pfac = A.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } C ldbcf = A.leadingBaseCoefficient(); if (!ldbcf.isONE()) { A = A.divide(ldbcf); GenPolynomial f1 = pfac.getONE().multiply(ldbcf); //System.out.println("gcda sqf f1 = " + f1); sfactors.put(f1, 1L); ldbcf = pfac.coFac.getONE(); } // divide by trailing term ExpVector et = A.trailingExpVector(); if (!et.isZERO()) { GenPolynomial tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); A = PolyUtil. basePseudoDivide(A, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); logger.info("tr, ep = {}, {}", tr, ep); sfactors.put(tr, ep); if (A.length() == 1) { return sfactors; } } GenPolynomial Tp, T, W, Y, Z; long k = 1L; //0L Tp = PolyUtil. baseDerivative(A); T = engine.baseGcd(A, Tp); T = T.monic(); if (T.isConstant()) { sfactors.put(A, k); return sfactors; } W = PolyUtil. basePseudoDivide(A, T); //if (W.isConstant()) { // return sfactors; //} Y = PolyUtil. basePseudoDivide(Tp, T); GenPolynomial Wp = PolyUtil. baseDerivative(W); Z = Y.subtract(Wp); while (!Z.isZERO()) { GenPolynomial g = engine.baseGcd(W, Z); g = g.monic(); if (!g.isONE()) { sfactors.put(g, k); } W = PolyUtil. basePseudoDivide(W, g); //System.out.println("W = " + W); //System.out.println("g = " + g); Y = PolyUtil. basePseudoDivide(Z, g); Wp = PolyUtil. baseDerivative(W); Z = Y.subtract(Wp); k++; } logger.info("W, k = {}, {}", W, k); if (!W.isONE()) { sfactors.put(W, k); } return normalizeFactorization(sfactors); } /** * GenPolynomial recursive univariate polynomial squarefree factorization. * @param P recursive univariate GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap>, Long> recursiveUnivariateSquarefreeFactors( GenPolynomial> P) { SortedMap>, Long> sfactors = new TreeMap>, Long>(); if (P == null || P.isZERO()) { return sfactors; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // recursiveContent not possible by return type throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } // if base coefficient ring is a field, make monic GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; C ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); if (!ldbcf.isONE()) { GenPolynomial lc = cfac.getONE().multiply(ldbcf); GenPolynomial> pl = pfac.getONE().multiply(lc); sfactors.put(pl, 1L); C li = ldbcf.inverse(); //System.out.println("li = " + li); P = P.multiply(cfac.getONE().multiply(li)); //System.out.println("P,monic = " + P); ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); } // factors of content GenPolynomial Pc = engine.recursiveContent(P); logger.info("recursiveContent = {}", Pc); Pc = Pc.monic(); if (!Pc.isONE()) { P = PolyUtil. coefficientPseudoDivide(P, Pc); } SortedMap, Long> rsf = squarefreeFactors(Pc); logger.info("squarefreeFactors = {}", rsf); // add factors of content for (Map.Entry, Long> me : rsf.entrySet()) { GenPolynomial c = me.getKey(); if (!c.isONE()) { GenPolynomial> cr = pfac.getONE().multiply(c); Long rk = me.getValue(); sfactors.put(cr, rk); } } // divide by trailing term ExpVector et = P.trailingExpVector(); if (!et.isZERO()) { GenPolynomial> tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); P = PolyUtil. recursivePseudoDivide(P, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); sfactors.put(tr, ep); //P.length == 1 ?? } // factors of recursive polynomial GenPolynomial> Tp, T, W, Y, Z; long k = 1L; //0L Tp = PolyUtil. recursiveDerivative(P); T = engine.recursiveUnivariateGcd(P, Tp); T = PolyUtil. monic(T); if (T.isConstant()) { sfactors.put(P, k); return sfactors; } W = PolyUtil. recursivePseudoDivide(P, T); //if (W.isConstant()) { // return sfactors; //} Y = PolyUtil. recursivePseudoDivide(Tp, T); GenPolynomial> Wp = PolyUtil. recursiveDerivative(W); Z = Y.subtract(Wp); while (!Z.isZERO()) { GenPolynomial> g = engine.recursiveGcd(W, Z); g = PolyUtil. monic(g); if (!g.isONE()) { sfactors.put(g, k); } W = PolyUtil. recursivePseudoDivide(W, g); //System.out.println("W = " + W); //System.out.println("g = " + g); Y = PolyUtil. recursivePseudoDivide(Z, g); Wp = PolyUtil. recursiveDerivative(W); Z = Y.subtract(Wp); k++; } logger.info("W, k = {}, {}", W, k); if (!W.isONE()) { sfactors.put(W, k); } return sfactors; //normalizeFactorization(sfactors); } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeFieldCharP.java000066400000000000000000000645271445075545500253020ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for coefficient fields of characteristic p. * @author Heinz Kredel */ public abstract class SquarefreeFieldCharP> extends SquarefreeAbstract { private static final Logger logger = LogManager.getLogger(SquarefreeFieldCharP.class); //private static final boolean debug = logger.isDebugEnabled(); /* * Squarefree engine for characteristic p base coefficients. */ //protected final SquarefreeAbstract rengine; /** * Factory for finite field of characteristic p coefficients. */ protected final RingFactory coFac; /** * Factory for a algebraic extension of a finite field of characteristic p * coefficients. If coFac is an algebraic extension, then * aCoFac is equal to coFac, else * aCoFac is null. */ protected final AlgebraicNumberRing aCoFac; /** * Factory for a transcendental extension of a finite field of * characteristic p coefficients. If coFac is an transcendental * extension, then qCoFac is equal to coFac, else * qCoFac is null. */ protected final QuotientRing qCoFac; /** * Constructor. */ @SuppressWarnings("unchecked") public SquarefreeFieldCharP(RingFactory fac) { super(GCDFactory. getProxy(fac)); if (!fac.isField()) { //throw new IllegalArgumentException("fac must be a field: " + fac.toScript()); logger.warn("fac should be a field: {}", fac.toScript()); } if (fac.characteristic().signum() == 0) { throw new IllegalArgumentException("characteristic(fac) must be non-zero"); } coFac = fac; Object oFac = coFac; if (oFac instanceof AlgebraicNumberRing) { aCoFac = (AlgebraicNumberRing) oFac; // is not correct //rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(aCoFac.ring); qCoFac = null; } else { aCoFac = null; if (oFac instanceof QuotientRing) { qCoFac = (QuotientRing) oFac; // is not correct //rengine = (SquarefreeAbstract) SquarefreeFactory.getImplementation(qCoFac.ring); } else { qCoFac = null; } } } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + " with " + engine + " over " + coFac; } /** * GenPolynomial polynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ @Override public GenPolynomial baseSquarefreePart(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial s = pfac.getONE(); SortedMap, Long> factors = baseSquarefreeFactors(P); //if (logger.isWarnEnabled()) { // logger.warn("sqfPart, better use sqfFactors, factors = {}", factors); //} for (GenPolynomial sp : factors.keySet()) { s = s.multiply(sp); } s = s.monic(); return s; } /** * GenPolynomial polynomial squarefree factorization. * @param A GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with A = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> baseSquarefreeFactors(GenPolynomial A) { SortedMap, Long> sfactors = new TreeMap, Long>(); if (A == null || A.isZERO()) { return sfactors; } GenPolynomialRing pfac = A.ring; if (A.isConstant()) { C coeff = A.leadingBaseCoefficient(); //System.out.println("coeff = " + coeff + " @ " + coeff.factory()); SortedMap rfactors = squarefreeFactors(coeff); //System.out.println("rfactors,const = " + rfactors); if (rfactors != null && rfactors.size() > 0) { for (Map.Entry me : rfactors.entrySet()) { C c = me.getKey(); if (!c.isONE()) { GenPolynomial cr = pfac.getONE().multiply(c); Long rk = me.getValue(); // rfactors.get(c); sfactors.put(cr, rk); } } } if (sfactors.isEmpty()) { sfactors.put(A, 1L); } return sfactors; } if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } C ldbcf = A.leadingBaseCoefficient(); if (!ldbcf.isONE()) { A = A.divide(ldbcf); SortedMap rfactors = squarefreeFactors(ldbcf); //System.out.println("rfactors,ldbcf = " + rfactors); if (rfactors != null && rfactors.size() > 0) { for (Map.Entry me : rfactors.entrySet()) { C c = me.getKey(); if (!c.isONE()) { GenPolynomial cr = pfac.getONE().multiply(c); Long rk = me.getValue(); //rfactors.get(c); sfactors.put(cr, rk); } } } else { GenPolynomial f1 = pfac.getONE().multiply(ldbcf); //System.out.println("gcda sqf f1 = " + f1); sfactors.put(f1, 1L); } ldbcf = pfac.coFac.getONE(); } // divide by trailing term ExpVector et = A.trailingExpVector(); if (!et.isZERO()) { GenPolynomial tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); A = PolyUtil. basePseudoDivide(A, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); logger.info("tr, ep = {}, {}", tr, ep); sfactors.put(tr, ep); if (A.length() == 1) { return sfactors; } } GenPolynomial T0 = A; long e = 1L; GenPolynomial Tp; GenPolynomial T = null; GenPolynomial V = null; long k = 0L; long mp = 0L; boolean init = true; while (true) { //System.out.println("T0 = " + T0); if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. baseDerivative(T0); T = engine.baseGcd(T0, Tp); T = T.monic(); V = PolyUtil. basePseudoDivide(T0, T); //System.out.println("iT0 = " + T0); //System.out.println("iTp = " + Tp); //System.out.println("iT = " + T); //System.out.println("iV = " + V); //System.out.println("const(iV) = " + V.isConstant()); k = 0L; mp = 0L; init = false; } if (V.isConstant()) { mp = pfac.characteristic().longValueExact(); // assert != 0 //T0 = PolyUtil. baseModRoot(T,mp); T0 = baseRootCharacteristic(T); logger.info("char root: T0 = {}, T = {}", T0, T); if (T0 == null) { //break; T0 = pfac.getZERO(); } e = e * mp; init = true; continue; } k++; if (mp != 0L && k % mp == 0L) { T = PolyUtil. basePseudoDivide(T, V); System.out.println("k = " + k); //System.out.println("T = " + T); k++; } GenPolynomial W = engine.baseGcd(T, V); W = W.monic(); GenPolynomial z = PolyUtil. basePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. basePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); if (z.degree(0) > 0) { if (ldbcf.isONE() && !z.leadingBaseCoefficient().isONE()) { z = z.monic(); //logger.info("z,monic = {}", z); } logger.info("z, k = {}, {}", z, k); sfactors.put(z, (e * k)); } } logger.info("exit char root: T0 = {}, T = {}", T0, T); return sfactors; } /** * GenPolynomial recursive univariate polynomial greatest squarefree * divisor. * @param P recursive univariate GenPolynomial. * @return squarefree(pp(P)). */ @Override public GenPolynomial> recursiveUnivariateSquarefreePart( GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial> s = pfac.getONE(); SortedMap>, Long> factors = recursiveUnivariateSquarefreeFactors(P); if (logger.isWarnEnabled()) { logger.info("sqfPart, better use sqfFactors, factors = {}", factors); } for (GenPolynomial> sp : factors.keySet()) { s = s.multiply(sp); } s = PolyUtil. monic(s); return s; } /** * GenPolynomial recursive univariate polynomial squarefree factorization. * @param P recursive univariate GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap>, Long> recursiveUnivariateSquarefreeFactors( GenPolynomial> P) { SortedMap>, Long> sfactors = new TreeMap>, Long>(); if (P == null || P.isZERO()) { return sfactors; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // recursiveContent not possible by return type throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } // if base coefficient ring is a field, make monic GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; C ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); if (!ldbcf.isONE()) { GenPolynomial lc = cfac.getONE().multiply(ldbcf); GenPolynomial> pl = pfac.getONE().multiply(lc); sfactors.put(pl, 1L); C li = ldbcf.inverse(); //System.out.println("li = " + li); P = P.multiply(cfac.getONE().multiply(li)); //System.out.println("P,monic = " + P); ldbcf = P.leadingBaseCoefficient().leadingBaseCoefficient(); logger.debug("new ldbcf: {}", ldbcf); } // factors of content GenPolynomial Pc = engine.recursiveContent(P); logger.info("Pc = {}", Pc); Pc = Pc.monic(); if (!Pc.isONE()) { P = PolyUtil. coefficientPseudoDivide(P, Pc); } SortedMap, Long> rsf = squarefreeFactors(Pc); logger.info("rsf = {}", rsf); // add factors of content for (Map.Entry, Long> me : rsf.entrySet()) { GenPolynomial c = me.getKey(); if (!c.isONE()) { GenPolynomial> cr = pfac.getONE().multiply(c); Long rk = me.getValue(); //rsf.get(c); sfactors.put(cr, rk); } } // divide by trailing term ExpVector et = P.trailingExpVector(); if (!et.isZERO()) { GenPolynomial> tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); P = PolyUtil. recursivePseudoDivide(P, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); sfactors.put(tr, ep); } // factors of recursive polynomial GenPolynomial> T0 = P; long e = 1L; GenPolynomial> Tp; GenPolynomial> T = null; GenPolynomial> V = null; long k = 0L; long mp = 0L; boolean init = true; while (true) { if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. recursiveDerivative(T0); //System.out.println("iT0 = " + T0); //System.out.println("iTp = " + Tp); T = engine.recursiveUnivariateGcd(T0, Tp); T = PolyUtil. monic(T); V = PolyUtil. recursivePseudoDivide(T0, T); //System.out.println("iT = " + T); //System.out.println("iV = " + V); k = 0L; mp = 0L; init = false; } if (V.isConstant()) { mp = pfac.characteristic().longValueExact(); // assert != 0 //T0 = PolyUtil. recursiveModRoot(T,mp); T0 = recursiveUnivariateRootCharacteristic(T); logger.info("char root: T0r = {}, Tr = {}", T0, T); if (T0 == null) { //break; T0 = pfac.getZERO(); } e = e * mp; init = true; //continue; } k++; if (mp != 0L && k % mp == 0L) { T = PolyUtil. recursivePseudoDivide(T, V); System.out.println("k = " + k); //System.out.println("T = " + T); k++; } GenPolynomial> W = engine.recursiveUnivariateGcd(T, V); W = PolyUtil. monic(W); GenPolynomial> z = PolyUtil. recursivePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. recursivePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); //was: if ( z.degree(0) > 0 ) { if (!z.isONE() && !z.isZERO()) { z = PolyUtil. monic(z); logger.info("z,put = {}", z); sfactors.put(z, (e * k)); } } logger.info("exit char root: T0 = {}, T = {}", T0, T); if (sfactors.size() == 0) { sfactors.put(pfac.getONE(), 1L); } return sfactors; } /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ @Override public GenPolynomial squarefreePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseSquarefreePart(P); } GenPolynomial s = pfac.getONE(); SortedMap, Long> factors = squarefreeFactors(P); if (logger.isWarnEnabled()) { logger.info("sqfPart, better use sqfFactors, factors = {}", factors); } for (GenPolynomial sp : factors.keySet()) { if (sp.isConstant()) { continue; } s = s.multiply(sp); } return s.monic(); } /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> squarefreeFactors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseSquarefreeFactors(P); } SortedMap, Long> sfactors = new TreeMap, Long>(); if (P.isZERO()) { return sfactors; } if (P.isONE()) { sfactors.put(P, 1L); return sfactors; } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); SortedMap>, Long> PP = recursiveUnivariateSquarefreeFactors(Pr); for (Map.Entry>, Long> m : PP.entrySet()) { Long i = m.getValue(); GenPolynomial> Dr = m.getKey(); GenPolynomial D = PolyUtil. distribute(pfac, Dr); sfactors.put(D, i); } return sfactors; } /** * Coefficient squarefree factorization. * @param coeff coefficient. * @return [p_1 -> e_1, ..., p_k -> e_k] with coeff = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @SuppressWarnings("unchecked") @Override public SortedMap squarefreeFactors(C coeff) { if (coeff == null) { return null; } SortedMap factors = new TreeMap(); RingFactory cfac = (RingFactory) coeff.factory(); if (aCoFac != null) { AlgebraicNumber an = (AlgebraicNumber) (Object) coeff; if (cfac.isFinite()) { SquarefreeFiniteFieldCharP reng = (SquarefreeFiniteFieldCharP) SquarefreeFactory .getImplementation(cfac); SortedMap rfactors = reng.rootCharacteristic(coeff); // ?? logger.info("rfactors,finite = {}", rfactors); factors.putAll(rfactors); //return factors; } else { SquarefreeInfiniteAlgebraicFieldCharP reng = (SquarefreeInfiniteAlgebraicFieldCharP) SquarefreeFactory .getImplementation(cfac); SortedMap, Long> rfactors = reng.squarefreeFactors(an); logger.info("rfactors,infinite,algeb = {}", rfactors); for (Map.Entry, Long> me : rfactors.entrySet()) { AlgebraicNumber c = me.getKey(); if (!c.isONE()) { C cr = (C) (Object) c; Long rk = me.getValue(); factors.put(cr, rk); } } } } else if (qCoFac != null) { Quotient q = (Quotient) (Object) coeff; SquarefreeInfiniteFieldCharP reng = (SquarefreeInfiniteFieldCharP) SquarefreeFactory .getImplementation(cfac); SortedMap, Long> rfactors = reng.squarefreeFactors(q); logger.info("rfactors,infinite = {}", rfactors); for (Map.Entry, Long> me : rfactors.entrySet()) { Quotient c = me.getKey(); if (!c.isONE()) { C cr = (C) (Object) c; Long rk = me.getValue(); factors.put(cr, rk); } } } else if (cfac.isFinite()) { SquarefreeFiniteFieldCharP reng = (SquarefreeFiniteFieldCharP) SquarefreeFactory .getImplementation(cfac); SortedMap rfactors = reng.rootCharacteristic(coeff); // ?? logger.info("rfactors,finite = {}", rfactors); factors.putAll(rfactors); //return factors; } else { logger.warn("case {} not implemented", cfac); } return factors; } /* --------- char-th roots --------------------- */ /** * GenPolynomial char-th root univariate polynomial. * @param P GenPolynomial. * @return char-th_rootOf(P), or null if no char-th root. */ public abstract GenPolynomial baseRootCharacteristic(GenPolynomial P); /** * GenPolynomial char-th root univariate polynomial with polynomial * coefficients. * @param P recursive univariate GenPolynomial. * @return char-th_rootOf(P), or null if P is no char-th root. */ public abstract GenPolynomial> recursiveUnivariateRootCharacteristic( GenPolynomial> P); /** * Polynomial is char-th root. * @param P polynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**(e_i*p), else false. */ public boolean isCharRoot(GenPolynomial P, SortedMap, Long> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } GenPolynomial t = P.ring.getONE(); long p = P.ring.characteristic().longValueExact(); for (Map.Entry, Long> me : F.entrySet()) { GenPolynomial f = me.getKey(); Long E = me.getValue(); long e = E.longValue(); GenPolynomial g = f.power(e); if (!f.isConstant()) { g = g.power(p); } t = t.multiply(g); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { System.out.println("\nfactorization(map): " + f); System.out.println("P = " + P); System.out.println("t = " + t); P = P.monic(); t = t.monic(); f = P.equals(t) || P.equals(t.negate()); if (f) { return f; } System.out.println("\nfactorization(map): " + f); System.out.println("P = " + P); System.out.println("t = " + t); } return f; } /** * Recursive polynomial is char-th root. * @param P recursive polynomial. * @param F = [p_1 -> e_1, ..., p_k -> e_k]. * @return true if P = prod_{i=1,...,k} p_i**(e_i*p), else false. */ public boolean isRecursiveCharRoot(GenPolynomial> P, SortedMap>, Long> F) { if (P == null || F == null) { throw new IllegalArgumentException("P and F may not be null"); } if (P.isZERO() && F.size() == 0) { return true; } GenPolynomial> t = P.ring.getONE(); long p = P.ring.characteristic().longValueExact(); for (Map.Entry>, Long> me : F.entrySet()) { GenPolynomial> f = me.getKey(); Long E = me.getValue(); long e = E.longValue(); GenPolynomial> g = f.power(e); if (!f.isConstant()) { g = g.power(p); } t = t.multiply(g); } boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { System.out.println("\nfactorization(map): " + f); System.out.println("P = " + P); System.out.println("t = " + t); P = P.monic(); t = t.monic(); f = P.equals(t) || P.equals(t.negate()); if (f) { return f; } System.out.println("\nfactorization(map): " + f); System.out.println("P = " + P); System.out.println("t = " + t); } return f; } /** * Recursive polynomial is char-th root. * @param P recursive polynomial. * @param r = recursive polynomial. * @return true if P = r**p, else false. */ public boolean isRecursiveCharRoot(GenPolynomial> P, GenPolynomial> r) { if (P == null || r == null) { throw new IllegalArgumentException("P and r may not be null"); } if (P.isZERO() && r.isZERO()) { return true; } long p = P.ring.characteristic().longValueExact(); GenPolynomial> t = r.power(p); boolean f = P.equals(t) || P.equals(t.negate()); if (!f) { System.out.println("\nisCharRoot: " + f); System.out.println("P = " + P); System.out.println("t = " + t); P = P.monic(); t = t.monic(); f = P.equals(t) || P.equals(t.negate()); if (f) { return f; } System.out.println("\nisCharRoot: " + f); System.out.println("P = " + P); System.out.println("t = " + t); } return f; } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeFiniteFieldCharP.java000066400000000000000000000227361445075545500264350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigInteger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.structure.GcdRingElem; import edu.jas.structure.Power; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for finite coefficient fields of characteristic p. * @author Heinz Kredel */ public class SquarefreeFiniteFieldCharP> extends SquarefreeFieldCharP { private static final Logger logger = LogManager.getLogger(SquarefreeFiniteFieldCharP.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public SquarefreeFiniteFieldCharP(RingFactory fac) { super(fac); // isFinite() predicate now present if (!fac.isFinite()) { throw new IllegalArgumentException("fac must be finite"); } } /* --------- char-th roots --------------------- */ /** * Characteristics root of a coefficient. Note: not needed at the * moment. * @param p coefficient. * @return [p -> k] if exists k with e=k*characteristic(c) and c = p**e, * else null. */ public SortedMap rootCharacteristic(C p) { if (p == null) { throw new IllegalArgumentException(this.getClass().getName() + " p == null"); } // already checked in constructor: //java.math.BigInteger c = p.factory().characteristic(); //if ( c.signum() == 0 ) { // return null; //} SortedMap root = new TreeMap(); if (p.isZERO()) { return root; } // true for finite fields: root.put(p, 1L); return root; } /** * Characteristics root of a coefficient. * @param c coefficient. * @return r with r**p == c, if such an r exists, else null. */ public C coeffRootCharacteristic(C c) { if (c == null || c.isZERO()) { return c; } C r = c; if (aCoFac == null && qCoFac == null) { // case ModInteger: c**p == c return r; } if (aCoFac != null) { // case AlgebraicNumber: r = c**(p**(d-1)), r**p == c long d = aCoFac.totalExtensionDegree(); //System.out.println("d = " + d); if (d <= 1) { return r; } BigInteger p = new BigInteger(aCoFac.characteristic()); BigInteger q = p.power(d - 1); //System.out.println("p**(d-1) = " + q); r = Power. positivePower(r, q.getVal()); // r = r.power(q.getVal()); //System.out.println("r**q = " + r); return r; } if (qCoFac != null) { throw new UnsupportedOperationException("case QuotientRing not yet implemented"); } return r; } /** * Characteristics root of a polynomial. Note: call only in * recursion. * @param P polynomial. * @return [p -> k] if exists k with e=k*characteristic(P) and P = p**e, * else null. */ public SortedMap, Long> rootCharacteristic(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } java.math.BigInteger c = P.ring.characteristic(); if (c.signum() == 0) { return null; } SortedMap, Long> root = new TreeMap, Long>(); if (P.isZERO()) { return root; } if (P.isONE()) { root.put(P, 1L); return root; } SortedMap, Long> sf = squarefreeFactors(P); logger.info("sf = {}", sf); // better: test if sf.size() == 1 // not ok Long k = null; for (Map.Entry, Long> me : sf.entrySet()) { GenPolynomial p = me.getKey(); if (p.isConstant()) { //System.out.println("p,const = " + p); continue; } Long e = me.getValue(); //sf.get(p); java.math.BigInteger E = new java.math.BigInteger(e.toString()); java.math.BigInteger r = E.remainder(c); if (!r.equals(java.math.BigInteger.ZERO)) { //System.out.println("r = " + r); return null; } if (k == null) { k = e; } else if (k.compareTo(e) >= 0) { k = e; } } // now c divides all exponents long cl = c.longValueExact(); GenPolynomial rp = P.ring.getONE(); for (Map.Entry, Long> me : sf.entrySet()) { GenPolynomial q = me.getKey(); Long e = me.getValue(); // sf.get(q); if (q.isConstant()) { // ensure p-th root C qc = q.leadingBaseCoefficient(); //System.out.println("qc,const = " + qc + ", e = " + e); if (e > 1L) { qc = qc.power(e); //Power. positivePower(qc, e); //e = 1L; } C qr = coeffRootCharacteristic(qc); //System.out.println("qr,const = " + qr); q = P.ring.getONE().multiply(qr); root.put(q, 1L); continue; } if (e > k) { long ep = e / cl; q = q.power(ep); //Power.> positivePower(q, ep); } rp = rp.multiply(q); } if (k != null) { k = k / cl; root.put(rp, k); } //System.out.println("sf,root = " + root); return root; } /** * GenPolynomial char-th root univariate polynomial. Base coefficient type * must be finite field, that is ModInteger or * AlgebraicNumber<ModInteger> etc. * @param P GenPolynomial. * @return char-th_rootOf(P), or null if no char-th root. */ @Override public GenPolynomial baseRootCharacteristic(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial d = pfac.getZERO().copy(); for (Monomial m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; ExpVector e = ExpVector.create(1, 0, fl); // for m.c exists a char-th root, since finite field C r = coeffRootCharacteristic(m.c); d.doPutToMap(e, r); } return d; } /** * GenPolynomial char-th root univariate polynomial with polynomial * coefficients. * @param P recursive univariate GenPolynomial. * @return char-th_rootOf(P), or null if P is no char-th root. */ @Override public GenPolynomial> recursiveUnivariateRootCharacteristic( GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial> d = pfac.getZERO().copy(); for (Monomial> m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; SortedMap, Long> sm = rootCharacteristic(m.c); if (sm == null) { return null; } logger.info("sm,rec = {}", sm); GenPolynomial r = rf.getONE(); for (Map.Entry, Long> me : sm.entrySet()) { GenPolynomial rp = me.getKey(); long gl = me.getValue(); //sm.get(rp); if (gl > 1) { rp = rp.power(gl); //Power.> positivePower(rp, gl); } r = r.multiply(rp); } ExpVector e = ExpVector.create(1, 0, fl); //System.out.println("put-root r = " + r + ", e = " + e); d.doPutToMap(e, r); } return d; } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeInfiniteAlgebraicFieldCharP.java000066400000000000000000000423141445075545500305500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.Reduction; import edu.jas.gb.ReductionSeq; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.Power; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for algebraic extensions of infinite coefficient * fields of characteristic p > 0. * @author Heinz Kredel */ public class SquarefreeInfiniteAlgebraicFieldCharP> extends SquarefreeFieldCharP> { private static final Logger logger = LogManager.getLogger(SquarefreeInfiniteAlgebraicFieldCharP.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Squarefree engine for infinite ring of characteristic p base * coefficients. */ protected final SquarefreeAbstract aengine; /** * Constructor. */ public SquarefreeInfiniteAlgebraicFieldCharP(RingFactory> fac) { super(fac); // isFinite() predicate now present if (fac.isFinite()) { throw new IllegalArgumentException("fac must be in-finite"); } AlgebraicNumberRing afac = (AlgebraicNumberRing) fac; GenPolynomialRing rfac = afac.ring; //System.out.println("rfac = " + rfac); //System.out.println("rfac = " + rfac.coFac); aengine = SquarefreeFactory. getImplementation(rfac); //System.out.println("aengine = " + aengine); } /* --------- algebraic number char-th roots --------------------- */ /** * Squarefree factors of a AlgebraicNumber. * @param P AlgebraicNumber. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1, ..., k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> squarefreeFactors(AlgebraicNumber P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } SortedMap, Long> factors = new TreeMap, Long>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.put(P, 1L); return factors; } GenPolynomial an = P.val; AlgebraicNumberRing pfac = P.ring; if (!an.isONE()) { //System.out.println("an = " + an); //System.out.println("aengine = " + aengine); SortedMap, Long> nfac = aengine.squarefreeFactors(an); //System.out.println("nfac = " + nfac); for (Map.Entry, Long> me : nfac.entrySet()) { GenPolynomial nfp = me.getKey(); AlgebraicNumber nf = new AlgebraicNumber(pfac, nfp); factors.put(nf, me.getValue()); //nfac.get(nfp)); } } if (factors.size() == 0) { factors.put(P, 1L); } return factors; } /** * Characteristics root of a AlgebraicNumber. * @param P AlgebraicNumber. * @return [p -> k] if exists k with e=characteristic(P)*k and P = p**e, * else null. */ @SuppressWarnings("unchecked") public SortedMap, Long> rootCharacteristic(AlgebraicNumber P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } java.math.BigInteger c = P.ring.characteristic(); if (c.signum() == 0) { return null; } SortedMap, Long> root = new TreeMap, Long>(); if (P.isZERO()) { return root; } if (P.isONE()) { root.put(P, 1L); return root; } // generate system of equations AlgebraicNumberRing afac = P.ring; long deg = afac.modul.degree(0); int d = (int) deg; String[] vn = GenPolynomialRing.newVars("c", d); GenPolynomialRing> pfac = new GenPolynomialRing>(afac, d, vn); List>> uv = (List>>) pfac .univariateList(); GenPolynomial> cp = pfac.getZERO(); GenPolynomialRing apfac = afac.ring; long i = 0; for (GenPolynomial> pa : uv) { GenPolynomial ca = apfac.univariate(0, i++); GenPolynomial> pb = pa.multiply(new AlgebraicNumber(afac, ca)); cp = cp.sum(pb); } GenPolynomial> cpp = Power.>> positivePower(cp, c); if (logger.isInfoEnabled()) { logger.info("cp = {}", cp); logger.info("cp^p = {}", cpp); logger.info("P = {}", P); } GenPolynomialRing ppfac = new GenPolynomialRing(apfac.coFac, pfac); List> gl = new ArrayList>(); if (deg == c.longValueExact() && afac.modul.length() == 2) { logger.info("deg({}) == char_p({})", deg, c.longValueExact()); for (Monomial> m : cpp) { ExpVector f = m.e; AlgebraicNumber a = m.c; //System.out.println("a = " + a + " : " + a.toScriptFactory()); GenPolynomial ap = a.val; for (Monomial ma : ap) { ExpVector e = ma.e; C cc = ma.c; C pc = P.val.coefficient(e); C cc1 = ((RingFactory) pc.factory()).getONE(); C pc1 = ((RingFactory) pc.factory()).getZERO(); //System.out.println("cc = " + cc + ", e = " + e); //System.out.println("pc = " + pc + " : " + cc.toScriptFactory()); if (cc instanceof AlgebraicNumber && pc instanceof AlgebraicNumber) { throw new UnsupportedOperationException( "case multiple algebraic extensions not implemented"); } else if (cc instanceof Quotient && pc instanceof Quotient) { Quotient ccp = (Quotient) (Object) cc; Quotient pcp = (Quotient) (Object) pc; if (pcp.isConstant()) { //logger.error("finite field not allowed here {}", afac.toScript()); throw new ArithmeticException("finite field not allowed here " + afac.toScript()); } //C dc = cc.divide(pc); Quotient dcp = ccp.divide(pcp); if (dcp.isConstant()) { // not possible: dc.isConstant() //System.out.println("dcp = " + dcp + " : " + cc.toScriptFactory()); // + ", dc = " + dc); //if ( dcp.num.isConstant() ) cc1 = cc; pc1 = pc; } GenPolynomial r = new GenPolynomial(ppfac, cc1, f); r = r.subtract(pc1); //System.out.println("r = " + r); gl.add(r); } } } } else { for (Monomial> m : cpp) { ExpVector f = m.e; AlgebraicNumber a = m.c; //System.out.println("m = " + m); GenPolynomial ap = a.val; for (Monomial ma : ap) { ExpVector e = ma.e; C cc = ma.c; C pc = P.val.coefficient(e); GenPolynomial r = new GenPolynomial(ppfac, cc, f); r = r.subtract(pc); //System.out.println("r = " + r); gl.add(r); } } } logger.info("equations = {}", gl); // solve system of equations and construct result Reduction red = new ReductionSeq(); gl = red.irreducibleSet(gl); GroebnerBaseAbstract bb = new GroebnerBaseSeq(); //GBFactory.getImplementation(); int z = bb.commonZeroTest(gl); if (z < 0) { // no solution return null; } logger.info("solution = {}", gl); GenPolynomial car = apfac.getZERO(); for (GenPolynomial pl : gl) { if (pl.length() <= 1) { continue; } if (pl.length() > 2) { throw new IllegalArgumentException("dim > 0 not implemented " + pl); } //System.out.println("pl = " + pl); ExpVector e = pl.leadingExpVector(); int[] v = e.dependencyOnVariables(); if (v == null || v.length == 0) { continue; } int vi = v[0]; //System.out.println("vi = " + vi); GenPolynomial ca = apfac.univariate(0, deg - 1 - vi); //System.out.println("ca = " + ca); C tc = pl.trailingBaseCoefficient(); tc = tc.negate(); if (e.maxDeg() == c.longValueExact()) { // p-th root of tc ... //SortedMap br = aengine.rootCharacteristic(tc); SortedMap br = aengine.squarefreeFactors(tc); //System.out.println("br = " + br); if (br != null && br.size() > 0) { C cc = apfac.coFac.getONE(); for (Map.Entry me : br.entrySet()) { C bc = me.getKey(); long ll = me.getValue(); if (ll % c.longValueExact() == 0L) { long fl = ll / c.longValueExact(); cc = cc.multiply(bc.power(fl)); } else { // fail ? cc = cc.multiply(bc); } } //System.out.println("cc = " + cc); tc = cc; } } ca = ca.multiply(tc); car = car.sum(ca); } AlgebraicNumber rr = new AlgebraicNumber(afac, car); if (logger.isInfoEnabled()) { logger.info("solution AN = {}", rr); //System.out.println("rr = " + rr); } root.put(rr, 1L); return root; } /** * GenPolynomial char-th root main variable. * @param P univariate GenPolynomial with AlgebraicNumber coefficients. * @return char-th_rootOf(P), or null, if P is no char-th root. */ public GenPolynomial> rootCharacteristic(GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // go to recursion GenPolynomialRing>> rfac = pfac.recursive(1); GenPolynomial>> Pr = PolyUtil .> recursive(rfac, P); GenPolynomial>> Prc = recursiveUnivariateRootCharacteristic(Pr); if (Prc == null) { return null; } GenPolynomial> D = PolyUtil.> distribute(pfac, Prc); return D; } RingFactory> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException( P.getClass().getName() + " only for ModInteger polynomials " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial> d = pfac.getZERO().copy(); for (Monomial> m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; SortedMap, Long> sm = rootCharacteristic(m.c); if (sm == null) { return null; } logger.info("sm_alg,root = {}", sm); AlgebraicNumber r = rf.getONE(); for (Map.Entry, Long> me : sm.entrySet()) { AlgebraicNumber rp = me.getKey(); long gl = me.getValue(); if (gl > 1) { rp = rp.power(gl); } r = r.multiply(rp); } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } logger.info("sm_alg,root,d = {}", d); return d; } /** * GenPolynomial char-th root univariate polynomial. * @param P GenPolynomial. * @return char-th_rootOf(P). */ @Override public GenPolynomial> baseRootCharacteristic(GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial> d = pfac.getZERO().copy(); for (Monomial> m : P) { //System.out.println("m = " + m); ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; SortedMap, Long> sm = rootCharacteristic(m.c); if (sm == null) { return null; } logger.info("sm_alg,base,root = {}", sm); AlgebraicNumber r = rf.getONE(); for (Map.Entry, Long> me : sm.entrySet()) { AlgebraicNumber rp = me.getKey(); //System.out.println("rp = " + rp); long gl = me.getValue(); //System.out.println("gl = " + gl); AlgebraicNumber re = rp; if (gl > 1) { re = rp.power(gl); } //System.out.println("re = " + re); r = r.multiply(re); } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } logger.info("sm_alg,base,d = {}", d); return d; } /** * GenPolynomial char-th root univariate polynomial with polynomial * coefficients. * @param P recursive univariate GenPolynomial. * @return char-th_rootOf(P), or null if P is no char-th root. */ @Override public GenPolynomial>> recursiveUnivariateRootCharacteristic( GenPolynomial>> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing>> pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException( P.getClass().getName() + " only for univariate recursive polynomials"); } RingFactory>> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial>> d = pfac.getZERO().copy(); for (Monomial>> m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; GenPolynomial> r = rootCharacteristic(m.c); if (r == null) { return null; } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } return d; } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeInfiniteFieldCharP.java000066400000000000000000000274441445075545500267650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.Monomial; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for infinite coefficient fields of characteristic p. * @author Heinz Kredel */ public class SquarefreeInfiniteFieldCharP> extends SquarefreeFieldCharP> { private static final Logger logger = LogManager.getLogger(SquarefreeInfiniteFieldCharP.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Squarefree engine for infinite ring of characteristic p base * coefficients. */ protected final SquarefreeAbstract qengine; /** * Constructor. */ @SuppressWarnings("unchecked") public SquarefreeInfiniteFieldCharP(RingFactory> fac) { super(fac); // isFinite() predicate now present if (fac.isFinite()) { throw new IllegalArgumentException("fac must be in-finite"); } QuotientRing qfac = (QuotientRing) fac; GenPolynomialRing rfac = qfac.ring; qengine = (SquarefreeAbstract) SquarefreeFactory. getImplementation(rfac); //qengine = new SquarefreeFiniteFieldCharP(rfac.coFac); //qengine = new SquarefreeInfiniteRingCharP( rfac.coFac ); } /* --------- quotient char-th roots --------------------- */ /** * Squarefree factors of a Quotient. * @param P Quotient. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1, ..., k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> squarefreeFactors(Quotient P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } SortedMap, Long> factors = new TreeMap, Long>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.put(P, 1L); return factors; } GenPolynomial num = P.num; GenPolynomial den = P.den; QuotientRing pfac = P.ring; GenPolynomial one = pfac.ring.getONE(); if (!num.isONE()) { SortedMap, Long> nfac = qengine.squarefreeFactors(num); //System.out.println("nfac = " + nfac); for (Map.Entry, Long> me : nfac.entrySet()) { GenPolynomial nfp = me.getKey(); Quotient nf = new Quotient(pfac, nfp); factors.put(nf, me.getValue()); //nfac.get(nfp)); } } if (den.isONE()) { if (factors.size() == 0) { factors.put(P, 1L); } return factors; } SortedMap, Long> dfac = qengine.squarefreeFactors(den); //System.out.println("dfac = " + dfac); for (Map.Entry, Long> me : dfac.entrySet()) { GenPolynomial dfp = me.getKey(); Quotient df = new Quotient(pfac, one, dfp); factors.put(df, me.getValue()); //dfac.get(dfp)); } if (factors.size() == 0) { factors.put(P, 1L); } return factors; } /** * Characteristics root of a Quotient. * @param P Quotient. * @return [p -> k] if exists k with e=characteristic(P)*k and P = p**e, * else null. */ public SortedMap, Long> rootCharacteristic(Quotient P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } java.math.BigInteger c = P.ring.characteristic(); if (c.signum() == 0) { return null; } SortedMap, Long> root = new TreeMap, Long>(); if (P.isZERO()) { return root; } if (P.isONE()) { root.put(P, 1L); return root; } SortedMap, Long> sf = squarefreeFactors(P); if (sf.size() == 0) { return null; } logger.info("sf,quot = {}", sf); // better: test if sf.size() == 2 // no, since num and den factors Long k = null; long cl = c.longValueExact(); for (Map.Entry, Long> me : sf.entrySet()) { Quotient p = me.getKey(); //System.out.println("p = " + p); if (p.isConstant()) { // todo: check for non-constants in coefficients continue; } Long e = me.getValue(); //sf.get(p); long E = e.longValue(); long r = E % cl; if (r != 0) { //System.out.println("r = " + r); return null; } if (k == null) { k = e; } else if (k >= e) { k = e; } } if (k == null) { k = 1L; //return null; } // now c divides all exponents of non constant elements for (Map.Entry, Long> me : sf.entrySet()) { Quotient q = me.getKey(); Long e = me.getValue(); //sf.get(q); //System.out.println("q = " + q + ", e = " + e); if (e >= k) { e = e / cl; //q = q.power(e); root.put(q, e); } else { // constant case root.put(q, e); } } //System.out.println("root = " + root); return root; } /** * GenPolynomial char-th root main variable. * @param P univariate GenPolynomial with Quotient coefficients. * @return char-th_rootOf(P), or null, if P is no char-th root. */ public GenPolynomial> rootCharacteristic(GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // go to recursion GenPolynomialRing>> rfac = pfac.recursive(1); GenPolynomial>> Pr = PolyUtil.> recursive(rfac, P); GenPolynomial>> Prc = recursiveUnivariateRootCharacteristic(Pr); if (Prc == null) { return null; } GenPolynomial> D = PolyUtil.> distribute(pfac, Prc); return D; } RingFactory> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException( P.getClass().getName() + " only for ModInteger polynomials " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial> d = pfac.getZERO().copy(); for (Monomial> m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; SortedMap, Long> sm = rootCharacteristic(m.c); if (sm == null) { return null; } logger.info("sm,root = {}", sm); Quotient r = rf.getONE(); for (Map.Entry, Long> me : sm.entrySet()) { Quotient rp = me.getKey(); long gl = me.getValue(); // sm.get(rp); if (gl > 1) { rp = rp.power(gl); } r = r.multiply(rp); } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } logger.info("sm,root,d = {}", d); return d; } /** * GenPolynomial char-th root univariate polynomial. * @param P GenPolynomial. * @return char-th_rootOf(P). */ @Override public GenPolynomial> baseRootCharacteristic(GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException(P.getClass().getName() + " only for univariate polynomials"); } RingFactory> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial> d = pfac.getZERO().copy(); for (Monomial> m : P) { //System.out.println("m = " + m); ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; SortedMap, Long> sm = rootCharacteristic(m.c); if (sm == null) { return null; } logger.info("sm,base,root = {}", sm); Quotient r = rf.getONE(); for (Map.Entry, Long> me : sm.entrySet()) { Quotient rp = me.getKey(); //System.out.println("rp = " + rp); long gl = me.getValue(); //sm.get(rp); //System.out.println("gl = " + gl); Quotient re = rp; if (gl > 1) { re = rp.power(gl); } //System.out.println("re = " + re); r = r.multiply(re); } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } logger.info("sm,base,d = {}", d); return d; } /** * GenPolynomial char-th root univariate polynomial with polynomial * coefficients. * @param P recursive univariate GenPolynomial. * @return char-th_rootOf(P), or null if P is no char-th root. */ @Override public GenPolynomial>> recursiveUnivariateRootCharacteristic( GenPolynomial>> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing>> pfac = P.ring; if (pfac.nvar > 1) { // basePthRoot not possible by return type throw new IllegalArgumentException( P.getClass().getName() + " only for univariate recursive polynomials"); } RingFactory>> rf = pfac.coFac; if (rf.characteristic().signum() != 1) { // basePthRoot not possible throw new IllegalArgumentException(P.getClass().getName() + " only for char p > 0 " + rf); } long mp = rf.characteristic().longValueExact(); GenPolynomial>> d = pfac.getZERO().copy(); for (Monomial>> m : P) { ExpVector f = m.e; long fl = f.getVal(0); if (fl % mp != 0) { return null; } fl = fl / mp; GenPolynomial> r = rootCharacteristic(m.c); if (r == null) { return null; } ExpVector e = ExpVector.create(1, 0, fl); d.doPutToMap(e, r); } return d; } } java-algebra-system-2.7.200/src/edu/jas/ufd/SquarefreeRingChar0.java000066400000000000000000000366261445075545500251150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.GcdRingElem; import edu.jas.structure.RingFactory; /** * Squarefree decomposition for coefficient rings of characteristic 0. * @author Heinz Kredel */ public class SquarefreeRingChar0> extends SquarefreeAbstract /*implements Squarefree*/ { private static final Logger logger = LogManager.getLogger(SquarefreeRingChar0.class); private static final boolean debug = logger.isDebugEnabled(); /** * Factory for ring of characteristic 0 coefficients. */ protected final RingFactory coFac; /** * Constructor. */ public SquarefreeRingChar0(RingFactory fac) { super(GCDFactory. getProxy(fac)); if (fac.isField()) { throw new IllegalArgumentException("fac is a field: use SquarefreeFieldChar0"); } if (fac.characteristic().signum() != 0) { throw new IllegalArgumentException("characteristic(fac) must be zero"); } coFac = fac; } /** * Get the String representation. * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + " with " + engine + " over " + coFac; } /** * GenPolynomial polynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(pp(P)). */ @Override public GenPolynomial baseSquarefreePart(GenPolynomial P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } GenPolynomial pp = engine.basePrimitivePart(P); if (pp.isConstant()) { return pp; } GenPolynomial d = PolyUtil. baseDerivative(pp); d = engine.basePrimitivePart(d); GenPolynomial g = engine.baseGcd(pp, d); g = engine.basePrimitivePart(g); GenPolynomial q = PolyUtil. basePseudoDivide(pp, g); q = engine.basePrimitivePart(q); return q; } /** * GenPolynomial polynomial squarefree factorization. * @param A GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with A = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> baseSquarefreeFactors(GenPolynomial A) { SortedMap, Long> sfactors = new TreeMap, Long>(); if (A == null || A.isZERO()) { return sfactors; } if (A.isConstant()) { sfactors.put(A, 1L); return sfactors; } GenPolynomialRing pfac = A.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } C ldbcf = A.leadingBaseCoefficient(); if (!ldbcf.isONE()) { C cc = engine.baseContent(A); A = A.divide(cc); GenPolynomial f1 = pfac.getONE().multiply(cc); //System.out.println("gcda sqf f1 = " + f1); sfactors.put(f1, 1L); } // divide by trailing term ExpVector et = A.trailingExpVector(); if (!et.isZERO()) { GenPolynomial tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); A = PolyUtil. basePseudoDivide(A, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); logger.info("tr, ep = {}, {}", tr, ep); sfactors.put(tr, ep); if (A.length() == 1) { return sfactors; } } GenPolynomial T0 = A; GenPolynomial Tp; GenPolynomial T = null; GenPolynomial V = null; long k = 0L; boolean init = true; while (true) { if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. baseDerivative(T0); T = engine.baseGcd(T0, Tp); T = engine.basePrimitivePart(T); V = PolyUtil. basePseudoDivide(T0, T); //System.out.println("iT0 = " + T0); //System.out.println("iTp = " + Tp); //System.out.println("iT = " + T); //System.out.println("iV = " + V); k = 0L; init = false; } if (V.isConstant()) { break; } k++; GenPolynomial W = engine.baseGcd(T, V); W = engine.basePrimitivePart(W); GenPolynomial z = PolyUtil. basePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. basePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); if (z.degree(0) > 0) { if (ldbcf.isONE() && !z.leadingBaseCoefficient().isONE()) { z = engine.basePrimitivePart(z); //logger.info("z,pp = {}", z); } logger.info("z, k = {}, {}", z, k); sfactors.put(z, k); } } return normalizeFactorization(sfactors); } /** * GenPolynomial recursive univariate polynomial greatest squarefree * divisor. * @param P recursive univariate GenPolynomial. * @return squarefree(P). */ @Override public GenPolynomial> recursiveUnivariateSquarefreePart( GenPolynomial> P) { if (P == null || P.isZERO()) { return P; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { throw new IllegalArgumentException( this.getClass().getName() + " only for multivariate polynomials"); } // remove content GenPolynomial> pp = P; GenPolynomial Pc = engine.recursiveContent(P); Pc = engine.basePrimitivePart(Pc); if (!Pc.isONE()) { pp = PolyUtil. coefficientPseudoDivide(pp, Pc); //System.out.println("pp/cont = " + pp); } // squarefree content GenPolynomial Ps = squarefreePart(Pc); Ps = engine.basePrimitivePart(Ps); //System.out.println("Pc = " + Pc + ", Ps = " + Ps); if (pp.leadingExpVector().getVal(0) < 1) { //System.out.println("pp = " + pp); //System.out.println("Ps = " + Ps); pp = pp.multiply(Ps); pp = engine.baseRecursivePrimitivePart(pp); return pp; } GenPolynomial> d = PolyUtil. recursiveDerivative(pp); //System.out.println("d = " + d); GenPolynomial> g = engine.recursiveUnivariateGcd(pp, d); //System.out.println("g,rec = " + g); g = engine.baseRecursivePrimitivePart(g); //System.out.println("g,bPP = " + g); GenPolynomial> q = PolyUtil. recursivePseudoDivide(pp, g); //System.out.println("q,bPP = " + q); q = q.multiply(Ps); //q = engine.basePrimitivePart(q); q = engine.baseRecursivePrimitivePart(q); return q; } /** * GenPolynomial recursive univariate polynomial squarefree factorization. * @param P recursive univariate GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap>, Long> recursiveUnivariateSquarefreeFactors( GenPolynomial> P) { SortedMap>, Long> sfactors = new TreeMap>, Long>(); if (P == null || P.isZERO()) { return sfactors; } GenPolynomialRing> pfac = P.ring; if (pfac.nvar > 1) { // recursiveContent not possible by return type throw new IllegalArgumentException( this.getClass().getName() + " only for univariate polynomials"); } // if base coefficient ring is a field, make monic GenPolynomialRing cfac = (GenPolynomialRing) pfac.coFac; C bcc = engine.baseRecursiveContent(P); if (!bcc.isONE()) { GenPolynomial lc = cfac.getONE().multiply(bcc); GenPolynomial> pl = pfac.getONE().multiply(lc); sfactors.put(pl, 1L); P = PolyUtil. baseRecursiveDivide(P, bcc); } // factors of content GenPolynomial Pc = engine.recursiveContent(P); logger.info("Pc = {}", Pc); Pc = engine.basePrimitivePart(Pc); //System.out.println("Pc,PP = " + Pc); if (!Pc.isONE()) { P = PolyUtil. coefficientPseudoDivide(P, Pc); } SortedMap, Long> rsf = squarefreeFactors(Pc); logger.info("rsf = {}", rsf); // add factors of content for (Map.Entry, Long> me : rsf.entrySet()) { GenPolynomial c = me.getKey(); if (!c.isONE()) { GenPolynomial> cr = pfac.getONE().multiply(c); Long rk = me.getValue(); //rsf.get(c); sfactors.put(cr, rk); } } // divide by trailing term ExpVector et = P.trailingExpVector(); if (!et.isZERO()) { GenPolynomial> tr = pfac.valueOf(et); logger.info("trailing term = {}", tr); P = PolyUtil. recursivePseudoDivide(P, tr); long ep = et.getVal(0); // univariate et = et.subst(0, 1); tr = pfac.valueOf(et); sfactors.put(tr, ep); } // factors of recursive polynomial GenPolynomial> T0 = P; GenPolynomial> Tp; GenPolynomial> T = null; GenPolynomial> V = null; long k = 0L; boolean init = true; while (true) { if (init) { if (T0.isConstant() || T0.isZERO()) { break; } Tp = PolyUtil. recursiveDerivative(T0); //System.out.println("iTp = " + Tp); T = engine.recursiveUnivariateGcd(T0, Tp); //System.out.println("iT = " + T); if (debug) { logger.info("T0 = {}, Tp = {}, T = {}", T0, Tp, T); } T = engine.baseRecursivePrimitivePart(T); //System.out.println("iT = " + T); V = PolyUtil. recursivePseudoDivide(T0, T); //System.out.println("iT0 = " + T0); //System.out.println("iV = " + V); k = 0L; init = false; } if (V.isConstant()) { break; } k++; GenPolynomial> W = engine.recursiveUnivariateGcd(T, V); if (debug) { logger.info("T = {}, V = {}, W = {}", T, V, W); } W = engine.baseRecursivePrimitivePart(W); GenPolynomial> z = PolyUtil. recursivePseudoDivide(V, W); //System.out.println("W = " + W); //System.out.println("z = " + z); V = W; T = PolyUtil. recursivePseudoDivide(T, V); //System.out.println("V = " + V); //System.out.println("T = " + T); //was: if ( z.degree(0) > 0 ) { if (!z.isONE() && !z.isZERO()) { z = engine.baseRecursivePrimitivePart(z); logger.info("z = {}, k = {}", z, k); sfactors.put(z, k); } } return sfactors; } /** * GenPolynomial greatest squarefree divisor. * @param P GenPolynomial. * @return squarefree(P). */ @Override public GenPolynomial squarefreePart(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } if (P.isZERO()) { return P; } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseSquarefreePart(P); } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); GenPolynomial Pc = engine.recursiveContent(Pr); Pr = PolyUtil. coefficientPseudoDivide(Pr, Pc); GenPolynomial Ps = squarefreePart(Pc); GenPolynomial> PP = recursiveUnivariateSquarefreePart(Pr); GenPolynomial> PS = PP.multiply(Ps); GenPolynomial D = PolyUtil. distribute(pfac, PS); return D; } /** * GenPolynomial squarefree factorization. * @param P GenPolynomial. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap, Long> squarefreeFactors(GenPolynomial P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P != null"); } GenPolynomialRing pfac = P.ring; if (pfac.nvar <= 1) { return baseSquarefreeFactors(P); } SortedMap, Long> sfactors = new TreeMap, Long>(); if (P.isZERO()) { return sfactors; } if (P.isONE()) { sfactors.put(P, 1L); return sfactors; } GenPolynomialRing> rfac = pfac.recursive(1); GenPolynomial> Pr = PolyUtil. recursive(rfac, P); SortedMap>, Long> PP = recursiveUnivariateSquarefreeFactors(Pr); for (Map.Entry>, Long> m : PP.entrySet()) { Long i = m.getValue(); GenPolynomial> Dr = m.getKey(); GenPolynomial D = PolyUtil. distribute(pfac, Dr); sfactors.put(D, i); } return normalizeFactorization(sfactors); } /** * Coefficients squarefree factorization. * @param P coefficient. * @return [p_1 -> e_1, ..., p_k -> e_k] with P = prod_{i=1,...,k} * p_i^{e_i} and p_i squarefree and gcd(p_i, p_j) = 1, for i != j. */ @Override public SortedMap squarefreeFactors(C P) { throw new UnsupportedOperationException("method not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/ufd/package.html000066400000000000000000000077011445075545500227230ustar00rootroot00000000000000 Unique Factorization Domain package

Unique factorization domain package.

This package contains classes for polynomials rings as unique factorization domains. Provided methods with interface GreatestCommonDivisor are e.g. greatest common divisors gcd(), primitive part primitivePart() or coPrime(). The different classes implement variants of polynomial remainder sequences (PRS) and modular methods. Interface Squarefree provides the greatest squarefree factor squarefreeFactor() and a complete squarefree decomposition can be obtained with method squarefreeFactors(). There is a Factorization interface with an FactorAbstract class with common codes. Factorization of univariate polynomials exists for several coefficient rings: modulo primes in class FactorModular, over integers in class FactorInteger, over rational numbers in class FactorRational, over algebraic numbers in class FactorAlgebraic<C> and over rational functions in class FactorQuotient<C> (where for the last two classes C can be any other ring for which the FactorFactory. getImplementation returns an implementation). Multivatiate polynomials over the integers (and rational numbers) are factored using the algorithm of P. Wang. For other coefficients the multivatiate polynomials are reduced to univariate polynomials via Kronecker substitution. The rational function class Quotient computes quotients of polynomials reduced to lowest terms.

To choose the correct implementation always use the factory classes GCDFactory, SquarefreeFactory and FactorFactory with methods getImplementation() or getProxy(). These methods will take care of all possible (implemented) coefficient rings properties. The polynomial coefficients must implement the GcdRingElem interface and so must allow greatest common divisor computations. Greatest common divisor computation is completely generic and works for any implemented integral domain. If special, optimized implementations exist they will be used. Squarefree decomposition is also completely generic and works for any implemented integral domain. There are no special, optimized implementations. Factorization is generic relative to the implemented ring constructions: algebraic field extensions and transcendent field extensions. Implemented base cases are modular coefficient, integer coefficients and rational number coefficients.

The implementation follows Geddes & Czapor & Labahn Algorithms for Computer Algebra and Cohen A Curse in Computational Algebraic Number Theory. See also Kaltofen Factorization of Polynomials in Computing Supplement, Springer, 1982, Davenport & Gianni & Trager Scratchpad's View of Algebra II: A Categorical View of Factorization in ISSAC'91 and the ALDES/SAC2 code as contained in MAS.


Heinz Kredel

Last modified: Fri Sep 21 21:56:48 CEST 2012

$Id$

java-algebra-system-2.7.200/src/edu/jas/ufdroot/000077500000000000000000000000001445075545500213415ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/ufdroot/FactorRealAlgebraic.java000066400000000000000000000101471445075545500260230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufdroot; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.Rational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.root.PolyUtilRoot; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.RealAlgebraicRing; import edu.jas.structure.GcdRingElem; import edu.jas.ufd.FactorAbstract; import edu.jas.ufd.FactorFactory; /** * Real algebraic number coefficients factorization algorithms. This class * implements factorization methods for polynomials over real algebraic numbers * from package edu.jas.root. * * @param coefficient type * @author Heinz Kredel */ public class FactorRealAlgebraic & Rational> extends FactorAbstract> { //TODO: absolute factorization would mean factorization to linear and quadratic factors //FactorAbsolute> //FactorAbstract> private static final Logger logger = LogManager.getLogger(FactorRealAlgebraic.class); //private static final boolean debug = logger.isInfoEnabled(); /** * Factorization engine for base coefficients. */ public final FactorAbstract> factorAlgebraic; /** * No argument constructor. Note: can't use this constructor. */ protected FactorRealAlgebraic() { throw new IllegalArgumentException("don't use this constructor"); } /** * Constructor. * @param fac algebraic number factory. */ public FactorRealAlgebraic(RealAlgebraicRing fac) { this(fac, FactorFactory.> getImplementation(fac.algebraic)); } /** * Constructor. * @param fac algebraic number factory. * @param factorAlgebraic factorization engine for polynomials over base * coefficients. */ public FactorRealAlgebraic(RealAlgebraicRing fac, FactorAbstract> factorAlgebraic) { super(fac); this.factorAlgebraic = factorAlgebraic; } /** * GenPolynomial base factorization of a squarefree polynomial. * @param P squarefree GenPolynomial<RealAlgebraicNumber<C>>. * @return [p_1,...,p_k] with P = prod_{i=1, ..., k} p_i. */ @Override public List>> baseFactorsSquarefree( GenPolynomial> P) { if (P == null) { throw new IllegalArgumentException(this.getClass().getName() + " P == null"); } List>> factors = new ArrayList>>(); if (P.isZERO()) { return factors; } if (P.isONE()) { factors.add(P); return factors; } GenPolynomialRing> pfac = P.ring; // Q(alpha)[x] if (pfac.nvar > 1) { throw new IllegalArgumentException("only for univariate polynomials"); } RealAlgebraicRing rfac = (RealAlgebraicRing) pfac.coFac; RealAlgebraicNumber ldcf = P.leadingBaseCoefficient(); if (!ldcf.isONE()) { P = P.monic(); factors.add(pfac.getONE().multiply(ldcf)); } //System.out.println("\nP = " + P); GenPolynomialRing> afac = new GenPolynomialRing>( rfac.algebraic, pfac); GenPolynomial> A = PolyUtilRoot. algebraicFromRealCoefficients(afac, P); // factor A: List>> afactors = factorAlgebraic.baseFactorsSquarefree(A); for (GenPolynomial> a : afactors) { GenPolynomial> p = PolyUtilRoot. realFromAlgebraicCoefficients(pfac, a); factors.add(p); } logger.info("real algebraic factors = {}", factors); return factors; } } java-algebra-system-2.7.200/src/edu/jas/ufdroot/package.html000066400000000000000000000014021445075545500236170ustar00rootroot00000000000000 Unique Factorization Domain and Roots package

Unique Factorization Domain and Roots package.

This package contains classes for factorization in structures used in roots computation, for example FactorRealAlgebraic.


Heinz Kredel

Last modified: Sat Feb 4 12:45:33 CET 2012

$Id$

java-algebra-system-2.7.200/src/edu/jas/util/000077500000000000000000000000001445075545500206345ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/util/ArrayUtil.java000066400000000000000000000021621445075545500234140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import org.apache.logging.log4j.LogManager; /** * Array utilities. For example copyOf from Java 6. Note: unused at the * moment since it is not working in Java 5, use java.util.Arrays.copyOf(). * @author Heinz Kredel * @deprecated(forRemoval=true) */ @Deprecated public class ArrayUtil { //private static final Logger logger = LogManager.getLogger(ArrayUtil.class); // private static final boolean debug = logger.isDebugEnabled(); /** * Copy the specified array. * @param original array. * @param newLength new array length. * @return copy of original. */ public static T[] copyOf(T[] original, int newLength) { @SuppressWarnings("unchecked") T[] copy = (T[]) new Object[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } /** * Copy the specified array. * @param original array. * @return copy of original. */ public static T[] copyOf(T[] original) { return copyOf(original, original.length); } } java-algebra-system-2.7.200/src/edu/jas/util/CartesianProduct.java000066400000000000000000000076121445075545500247570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Cartesian product with iterator. * @author Heinz Kredel */ public class CartesianProduct implements Iterable> { /** * data structure. */ public final List> comps; /** * CartesianProduct constructor. * @param comps components of the Cartesian product. */ public CartesianProduct(List> comps) { if (comps == null) { throw new IllegalArgumentException("null components not allowed"); } this.comps = comps; } // /** // * CartesianProduct constructor. // * @param comps components of the Cartesian product. // */ // public CartesianProduct(List> comps) { // this( listToIterable(comps) ); // } /** * Get an iterator over subsets. * @return an iterator. */ public Iterator> iterator() { return new CartesianProductIterator(comps); } /** * Transform list to iterables. * @param comp components of the Cartesian product. * @return iterables taken from lists. */ static List> listToIterable(List> comp) { List> iter = new ArrayList>(comp.size()); for (List list : comp) { iter.add(list); } return iter; } } /** * Cartesian product iterator. * @author Heinz Kredel */ class CartesianProductIterator implements Iterator> { /** * data structure. */ final List> comps; final List> compit; List current; boolean empty; /** * CartesianProduct iterator constructor. * @param comps components of the Cartesian product. */ public CartesianProductIterator(List> comps) { if (comps == null) { throw new IllegalArgumentException("null comps not allowed"); } this.comps = comps; current = new ArrayList(comps.size()); compit = new ArrayList>(comps.size()); empty = false; for (Iterable ci : comps) { Iterator it = ci.iterator(); if (!it.hasNext()) { empty = true; current.clear(); break; } current.add(it.next()); compit.add(it); } //System.out.println("current = " + current); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next tuple. * @return next tuple. */ public synchronized List next() { if (empty) { throw new NoSuchElementException("invalid call of next()"); } List res = new ArrayList(current); // search iterator which hasNext int i = compit.size() - 1; for (; i >= 0; i--) { Iterator iter = compit.get(i); if (iter.hasNext()) { break; } } if (i < 0) { empty = true; return res; } // update iterators for (int j = i + 1; j < compit.size(); j++) { Iterator iter = comps.get(j).iterator(); compit.set(j, iter); } // update current for (int j = i; j < compit.size(); j++) { Iterator iter = compit.get(j); E el = iter.next(); current.set(j, el); } return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } java-algebra-system-2.7.200/src/edu/jas/util/CartesianProductInfinite.java000066400000000000000000000226661445075545500264530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Cartesian product of infinite components with iterator. Works also for finite * iterables. * @author Heinz Kredel */ public class CartesianProductInfinite implements Iterable> { /** * data structure. */ public final List> comps; /** * CartesianProduct constructor. * @param comps components of the Cartesian product. */ public CartesianProductInfinite(List> comps) { if (comps == null || comps.size() == 0) { throw new IllegalArgumentException("null components not allowed"); } this.comps = comps; } /** * Get an iterator over subsets. * @return an iterator. */ public Iterator> iterator() { if (comps.size() == 1) { return new CartesianOneProductInfiniteIterator(comps.get(0)); } // if ( comps.size() == 2 ) { // this part is not really required // return new CartesianTwoProductInfiniteIterator(comps.get(0),comps.get(1)); // } int n = comps.size(); int k = n / 2 + n % 2; // ceiling Iterable> c0 = new CartesianProductInfinite(comps.subList(0, k)); Iterable> c1 = new CartesianProductInfinite(comps.subList(k, n)); return new CartesianTwoProductInfiniteIteratorList(c0, c1); } } /** * Cartesian product infinite iterator, one factor. * @author Heinz Kredel */ class CartesianOneProductInfiniteIterator implements Iterator> { /** * data structure. */ final Iterator compit; /** * CartesianProduct iterator constructor. * @param comps components of the cartesian product. */ public CartesianOneProductInfiniteIterator(Iterable comps) { if (comps == null) { throw new IllegalArgumentException("null comps not allowed"); } compit = comps.iterator(); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public synchronized boolean hasNext() { return compit.hasNext(); } /** * Get next tuple. * @return next tuple. */ public synchronized List next() { List res = new ArrayList(1); res.add(compit.next()); return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } /** * Cartesian product infinite iterator, two factors. * @author Heinz Kredel */ class CartesianTwoProductInfiniteIterator implements Iterator> { /** * data structure. */ final Iterator compit0; final Iterator compit1; final List fincomps0; final List fincomps1; Iterator fincompit0; Iterator fincompit1; List current; boolean empty; long level; /** * CartesianProduct iterator constructor. * @param comps0 first components of the Cartesian product. * @param comps1 second components of the Cartesian product. */ public CartesianTwoProductInfiniteIterator(Iterable comps0, Iterable comps1) { if (comps0 == null || comps1 == null) { throw new IllegalArgumentException("null comps not allowed"); } empty = false; level = 0; current = new ArrayList(2); compit0 = comps0.iterator(); E e = compit0.next(); current.add(e); fincomps0 = new ArrayList(); fincomps0.add(e); fincompit0 = fincomps0.iterator(); //E d = fincompit0.next(); // remove current compit1 = comps1.iterator(); e = compit1.next(); current.add(e); fincomps1 = new ArrayList(); fincomps1.add(e); fincompit1 = fincomps1.iterator(); //@SuppressWarnings("unused") //d = fincompit1.next(); // remove current //System.out.println("current = " + current); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next tuple. * @return next tuple. */ public synchronized List next() { if (empty) { throw new NoSuchElementException("invalid call of next()"); } List res = current; // new ArrayList(current); // copy if (fincompit0.hasNext() && fincompit1.hasNext()) { E e0 = fincompit0.next(); E e1 = fincompit1.next(); current = new ArrayList(); current.add(e0); current.add(e1); return res; } level++; if (level % 2 == 1) { Collections.reverse(fincomps0); } else { Collections.reverse(fincomps1); } if (compit0.hasNext() && compit1.hasNext()) { fincomps0.add(compit0.next()); fincomps1.add(compit1.next()); } else { empty = true; return res; } if (level % 2 == 0) { Collections.reverse(fincomps0); } else { Collections.reverse(fincomps1); } //System.out.println("list(0) = " + fincomps0); //System.out.println("list(1) = " + fincomps1); fincompit0 = fincomps0.iterator(); fincompit1 = fincomps1.iterator(); E e0 = fincompit0.next(); E e1 = fincompit1.next(); current = new ArrayList(); current.add(e0); current.add(e1); return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } /** * Cartesian product infinite iterator, two factors list version. * @author Heinz Kredel */ class CartesianTwoProductInfiniteIteratorList implements Iterator> { /** * data structure. */ final Iterator> compit0; final Iterator> compit1; final List> fincomps0; final List> fincomps1; Iterator> fincompit0; Iterator> fincompit1; List current; boolean empty; long level; /** * CartesianProduct iterator constructor. * @param comps0 first components of the Cartesian product. * @param comps1 second components of the Cartesian product. */ public CartesianTwoProductInfiniteIteratorList(Iterable> comps0, Iterable> comps1) { if (comps0 == null || comps1 == null) { throw new IllegalArgumentException("null comps not allowed"); } current = new ArrayList(); empty = false; level = 0; compit0 = comps0.iterator(); List e = compit0.next(); current.addAll(e); fincomps0 = new ArrayList>(); fincomps0.add(e); fincompit0 = fincomps0.iterator(); //List d = fincompit0.next(); // remove current compit1 = comps1.iterator(); e = compit1.next(); current.addAll(e); fincomps1 = new ArrayList>(); fincomps1.add(e); fincompit1 = fincomps1.iterator(); //@SuppressWarnings("unused") //d = fincompit1.next(); // remove current //System.out.println("current = " + current); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next tuple. * @return next tuple. */ public synchronized List next() { if (empty) { throw new NoSuchElementException("invalid call of next()"); } List res = current; // new ArrayList(current); if (fincompit0.hasNext() && fincompit1.hasNext()) { List e0 = fincompit0.next(); List e1 = fincompit1.next(); current = new ArrayList(); current.addAll(e0); current.addAll(e1); return res; } level++; if (level % 2 == 1) { Collections.reverse(fincomps0); } else { Collections.reverse(fincomps1); } if (compit0.hasNext() && compit1.hasNext()) { fincomps0.add(compit0.next()); fincomps1.add(compit1.next()); } else { empty = true; return res; } if (level % 2 == 0) { Collections.reverse(fincomps0); } else { Collections.reverse(fincomps1); } //System.out.println("list(0) = " + fincomps0); //System.out.println("list(1) = " + fincomps1); fincompit0 = fincomps0.iterator(); fincompit1 = fincomps1.iterator(); List e0 = fincompit0.next(); List e1 = fincompit1.next(); current = new ArrayList(); current.addAll(e0); current.addAll(e1); return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } java-algebra-system-2.7.200/src/edu/jas/util/CartesianProductLong.java000066400000000000000000000146161445075545500256010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Cartesian product for Long with iterator. Similar to CartesianProduct but * returns only tuples of given total degree. * @author Heinz Kredel */ public class CartesianProductLong implements Iterable> { /** * data structure. */ public final List comps; public final long upperBound; /** * CartesianProduct constructor. * @param comps components of the Cartesian product. * @param ub an upper bound for the total degree of the elements. */ public CartesianProductLong(List comps, long ub) { if (comps == null) { throw new IllegalArgumentException("null components not allowed"); } this.comps = comps; this.upperBound = ub; } /** * Get an iterator over subsets. * @return an iterator. */ public Iterator> iterator() { return new CartesianProductLongIterator(comps, upperBound); } } /** * Cartesian product iterator for Longs. Similar to CartesianProductIterator but * returns only tuples of given total degree. * @author Heinz Kredel */ class CartesianProductLongIterator implements Iterator> { /** * data structure. */ final List comps; final List compit; List current; boolean empty; public final long upperBound; /** * CartesianProduct iterator constructor. * @param comps components of the Cartesian product. * @param ub an upper bound for the total degree of the elements. */ public CartesianProductLongIterator(List comps, long ub) { if (comps == null) { throw new IllegalArgumentException("null comps not allowed"); } this.comps = comps; this.upperBound = ub; current = new ArrayList(comps.size()); compit = new ArrayList(comps.size()); empty = false; for (LongIterable ci : comps) { LongIterator it = (LongIterator) ci.iterator(); if (it.getUpperBound() < this.upperBound) { throw new IllegalArgumentException("each iterator (" + it.getUpperBound() + ") must be able to reach total upper bound " + upperBound); } if (!it.hasNext()) { empty = true; current.clear(); return; } current.add(it.next()); compit.add(it); } // start with last component equal to upper bound LongIterator it = compit.get(compit.size() - 1); long d = -1L; while (it.hasNext()) { d = it.next(); if (d >= upperBound) { break; } } if (d >= 0L) { current.set(current.size() - 1, d); } if (totalDegree(current) != upperBound) { empty = true; current.clear(); } //System.out.println("current = " + current); } /** * Test for availability of a next tuple. * @return true if the iteration has more tuples, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next tuple. * @return next tuple. */ public synchronized List next() { if (empty) { throw new NoSuchElementException("invalid call of next()"); } List res = new ArrayList(current); //int waist = 0; while (true) { // search iterator which hasNext int i = compit.size() - 1; for (; i >= 0; i--) { LongIterator iter = compit.get(i); if (iter.hasNext()) { break; } } if (i < 0) { empty = true; //System.out.println("inner waist = " + waist); return res; } long pd = 0L; for (int j = 0; j < i; j++) { pd += current.get(j); } if (pd >= upperBound) { if (current.get(0) == upperBound) { empty = true; //System.out.println("inner waist = " + waist); return res; } pd = upperBound; } long rd = upperBound - pd; // update iterators for (int j = i + 1; j < compit.size(); j++) { LongIterator iter = (LongIterator) comps.get(j).iterator(); iter.setUpperBound(rd); compit.set(j, iter); } // update current for (int j = i; j < compit.size(); j++) { LongIterator iter = compit.get(j); Long el = iter.next(); current.set(j, el); } long td = totalDegree(current); if (td == upperBound) { //System.out.println("inner waist = " + waist); return res; } //System.out.println("current = " + current + ", td = " + td); if (td > upperBound) { //waist++; continue; } // adjust last component to total degree LongIterator it = compit.get(compit.size() - 1); long d = -1L; while (td < upperBound && it.hasNext()) { td++; d = it.next(); } //System.out.println("d = " + d); if (d >= 0L) { current.set(current.size() - 1, d); } if (td == upperBound) { //System.out.println("inner waist = " + waist); return res; } //waist++; // continue search } //return res; } /** * Total degree of a tuple. * @param e list of Longs. * @return sum of all elements in e. */ public long totalDegree(List e) { long d = 0L; for (Long i : e) { d += i; } return d; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove tuples"); } } java-algebra-system-2.7.200/src/edu/jas/util/CatReader.java000066400000000000000000000031771445075545500233410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.io.Reader; // import org.apache.logging.log4j.Logger; // import org.apache.logging.log4j.LogManager; /** * Reader to conncat two readers. Read from first reader until it is empty, then * read from second reader. * @author Heinz Kredel */ public class CatReader extends Reader { // private static final Logger logger = LogManager.getLogger(CatReader.class); // private static final boolean debug = logger.isDebugEnabled(); private final Reader first; private final Reader second; private boolean doFirst; /** * Constructor. * @param f first Reader. * @param s second Reader. */ public CatReader(Reader f, Reader s) { first = f; second = s; doFirst = true; } /** * Read char array. * @param cbuf array. * @param off start offset. * @param len number of chars to read. * @return number of chars read, or -1. */ @Override public int read(char[] cbuf, int off, int len) throws IOException { int i = -1; if (doFirst) { i = first.read(cbuf, off, len); if (i < 0) { doFirst = false; i = second.read(cbuf, off, len); } } else { i = second.read(cbuf, off, len); } //System.out.println("i = " + i); return i; } /** * Close this Reader. */ @Override public void close() throws IOException { try { first.close(); } finally { second.close(); } } } java-algebra-system-2.7.200/src/edu/jas/util/ChannelFactory.java000066400000000000000000000161461445075545500244070ustar00rootroot00000000000000/* * $Id$ */ //package edu.unima.ky.parallel; package edu.jas.util; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.BindException; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; //import java.util.concurrent.ArrayBlockingQueue; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * ChannelFactory implements a symmetric and non blocking way of setting up * sockets on the client and server side. The constructor sets up a ServerSocket * and accepts and stores any Socket creation requests from clients. The created * Sockets can the be retrieved from the store without blocking. Refactored for * java.util.concurrent. * @author Akitoshi Yoshida * @author Heinz Kredel * @see SocketChannel */ public class ChannelFactory extends Thread { private static final Logger logger = LogManager.getLogger(ChannelFactory.class); private static final boolean debug = logger.isDebugEnabled(); /** * default port of socket. */ public final static int DEFAULT_PORT = 4711; /** * port of socket. */ private final int port; /** * BoundedBuffer for sockets. */ private final BlockingQueue buf; /** * local server socket. */ private volatile ServerSocket srv; /** * is local server up and running. */ private volatile boolean srvrun = false; /** * is thread started. */ private volatile boolean srvstart = false; /** * Constructs a ChannelFactory on the DEFAULT_PORT. */ public ChannelFactory() { this(DEFAULT_PORT); } /** * Constructs a ChannelFactory. * @param p port. */ public ChannelFactory(int p) { buf = new LinkedBlockingQueue(/*infinite*/); if (p <= 0) { port = DEFAULT_PORT; } else { port = p; } try { srv = new ServerSocket(port); //this.start(); moved to init and getChannel logger.info("server bound to port {}", port); } catch (BindException e) { srv = null; logger.warn("server not started, port used {}", port); if (debug) { e.printStackTrace(); } } catch (IOException e) { logger.info("IOException {}", e); if (debug) { e.printStackTrace(); } } } /** * toString. */ @Override public String toString() { return this.getClass().getSimpleName() + "(" + srv + ", buf = " + buf.size() + ")"; } /** * thread initialization and start. */ public void init() { if (srv != null && ! srvstart ) { this.start(); srvstart = true; logger.info("ChannelFactory at {}", srv); } } /** * Get a new socket channel from a server socket. */ public SocketChannel getChannel() throws InterruptedException { // return (SocketChannel)buf.get(); if (srv == null) { if (srvrun) { throw new IllegalArgumentException("dont call when no server listens"); } } else if ( ! srvstart ) { init(); } return buf.take(); } /** * Get a new socket channel to a given host. * @param h hostname */ public SocketChannel getChannel(String h) throws IOException { return getChannel(h,DEFAULT_PORT); } /** * Get a new socket channel to a given host. * @param h hostname * @param p port */ public SocketChannel getChannel(String h, int p) throws IOException { if (p <= 0) { p = port; } SocketChannel c = null; int i = 0; int delay = 5; // 50 logger.debug("connecting to {}", h); while (c == null) { try { c = new SocketChannel(new Socket(h, p)); } catch (IOException e) { //System.out.println(e); // wait server ready i++; if (i % 50 == 0) { delay += delay; logger.info("Server on {}:{} not ready in {} ms", h, p, delay); } try { Thread.sleep(delay); if (i % 50 == 0 && debug) { throw new Exception("time wait, host = " + h + ", port = " + port); } } catch (InterruptedException w) { Thread.currentThread().interrupt(); throw new IOException("Interrupted during IO wait " + w); } catch (Exception ee) { // debug only ee.printStackTrace(); } } } logger.debug("connected, iter = {}", i); return c; } /** * Run the servers accept() in an infinite loop. */ @Override public void run() { if (srv == null) { return; // nothing to do } srvrun = true; while (true) { try { logger.info("waiting for connection on {}", srv); Socket s = srv.accept(); if (this.isInterrupted()) { //System.out.println("ChannelFactory interrupted"); srvrun = false; if (s != null) { // by code-spotter s.close(); } return; } //logger.debug("Socket = {}", s); logger.debug("connection accepted"); SocketChannel c = new SocketChannel(s); buf.put(c); } catch (IOException e) { //logger.debug("ChannelFactory IO terminating"); srvrun = false; return; } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); //logger.debug("ChannelFactory IE terminating"); srvrun = false; return; } } } /** * Terminate the Channel Factory */ public void terminate() { if ( ! srvstart ) { logger.debug("server not started"); return; } this.interrupt(); try { if (srv != null) { srv.close(); srvrun = false; } this.interrupt(); while (!buf.isEmpty()) { logger.debug("closing unused SocketChannel"); SocketChannel c = buf.poll(); if ( c != null ) { c.close(); } } } catch (IOException e) { //} catch (InterruptedException e) { // Thread.currentThread().interrupt(); } try { this.join(); } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); } logger.debug("ChannelFactory terminated"); } } java-algebra-system-2.7.200/src/edu/jas/util/DHTTransport.java000066400000000000000000000155511445075545500240420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.Serializable; import java.io.IOException; import java.rmi.MarshalledObject; /** * Transport container for a distributed version of a HashTable. * Note: Contains code for timing of marshalled versus plain * object serialization which can be removed later. * @author Heinz Kredel */ public abstract class DHTTransport implements Serializable { static long etime = 0L; // encode marshalled static long dtime = 0L; // decode marshalled static long ertime = 0L; // encode plain raw static long drtime = 0L; // decode plain raw public static enum Stor { // storage and transport class marshal, plain }; public static final Stor stor = Stor.marshal; //Stor.plain; /** * protected constructor. */ protected DHTTransport() { } /** * Create a new DHTTransport Container. * @param key * @param value */ public static DHTTransport create(K key, V value) throws IOException { switch (stor) { case marshal: return new DHTTransportMarshal(key,value); case plain: return new DHTTransportPlain(key,value); default: throw new IllegalArgumentException("this should not happen"); } } /** * Get the key from this DHTTransport Container. */ public abstract K key() throws IOException, ClassNotFoundException; /** * Get the value from this DHTTransport Container. */ public abstract V value() throws IOException, ClassNotFoundException; /** * toString. */ @Override public String toString() { return this.getClass().getName(); } } /** * Transport container to signal termination for a distributed version * of a HashTable. Contains no objects. */ class DHTTransportTerminate extends DHTTransport { /** * Get the key from this DHTTransport Container. */ public K key() throws IOException, ClassNotFoundException { throw new UnsupportedOperationException("this should not happen"); } /** * Get the value from this DHTTransport Container. */ public V value() throws IOException, ClassNotFoundException { throw new UnsupportedOperationException("this should not happen"); } } /** * Transport container to signal clearing contents of the * other HashTables including the server. Contains no objects. */ class DHTTransportClear extends DHTTransport { /** * Get the key from this DHTTransport Container. */ public K key() throws IOException, ClassNotFoundException { throw new UnsupportedOperationException("this should not happen"); } /** * Get the value from this DHTTransport Container. */ public V value() throws IOException, ClassNotFoundException { throw new UnsupportedOperationException("this should not happen"); } } /** * Transport container for a distributed version of a HashTable. Immutable * objects. Uses MarshalledObject to avoid deserialization on server side. */ class DHTTransportMarshal extends DHTTransport { protected final MarshalledObject/**/ key; protected final MarshalledObject/**/ value; /** * Constructs a new DHTTransport Container. * @param key * @param value */ @SuppressWarnings("unchecked") public DHTTransportMarshal(K key, V value) throws IOException { long t = System.currentTimeMillis(); this.key = new MarshalledObject/**/(key); this.value = new MarshalledObject/**/(value); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { etime += t; } //System.out.println(" marshal time = " + t); } /** * Get the key from this DHTTransport Container. */ @SuppressWarnings("unchecked") public K key() throws IOException, ClassNotFoundException { long t = System.currentTimeMillis(); K k = (K) this.key.get(); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { dtime += t; } return k; } /** * Get the value from this DHTTransport Container. */ @SuppressWarnings("unchecked") public V value() throws IOException, ClassNotFoundException { long t = System.currentTimeMillis(); V v = (V) this.value.get(); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { dtime += t; } return v; } /** * toString. */ @Override public String toString() { return super.toString() + "(" + key + "," + value + ")"; } private void writeObject(java.io.ObjectOutputStream out) throws IOException { long t = System.currentTimeMillis(); out.defaultWriteObject(); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { ertime += t; } } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { long t = System.currentTimeMillis(); in.defaultReadObject(); t = System.currentTimeMillis() - t; // not meaningful, includes waiting time synchronized( DHTTransport.class ) { drtime += t; } } } /** * Transport container for a distributed version of a HashTable. Immutable * objects. Uses plain objects. */ class DHTTransportPlain extends DHTTransport { protected final K key; protected final V value; /** * Constructs a new DHTTransport Container. * @param key * @param value */ public DHTTransportPlain(K key, V value) throws IOException { this.key = key; this.value = value; } /** * Get the key from this DHTTransport Container. */ public K key() throws IOException, ClassNotFoundException { return this.key; } /** * Get the value from this DHTTransport Container. */ public V value() throws IOException, ClassNotFoundException { return this.value; } /** * toString. */ @Override public String toString() { return super.toString() + "(" + key + "," + value + ")"; } private void writeObject(java.io.ObjectOutputStream out) throws IOException { long t = System.currentTimeMillis(); out.defaultWriteObject(); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { ertime += t; } } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { long t = System.currentTimeMillis(); in.defaultReadObject(); t = System.currentTimeMillis() - t; synchronized( DHTTransport.class ) { drtime += t; } } } java-algebra-system-2.7.200/src/edu/jas/util/DistHashTable.java000066400000000000000000000265461445075545500241730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; //import java.util.concurrent.ConcurrentSkipListMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * Distributed version of a HashTable. Implemented with a SortedMap / TreeMap to * keep the sequence order of elements. * @author Heinz Kredel */ public class DistHashTable extends AbstractMap /* implements Map */{ private static final Logger logger = LogManager.getLogger(DistHashTable.class); private static final boolean debug = logger.isDebugEnabled(); protected final SortedMap theList; protected final ChannelFactory cf; protected SocketChannel channel = null; protected DHTListener listener = null; /** * Constructs a new DistHashTable. * @param host name or IP of server host. */ public DistHashTable(String host) { this(host, DistHashTableServer.DEFAULT_PORT); } /** * DistHashTable. * @param host name or IP of server host. * @param port on server. */ public DistHashTable(String host, int port) { this(new ChannelFactory(port + 1), host, port); } /** * DistHashTable. * @param cf ChannelFactory to use. * @param host name or IP of server host. * @param port on server. */ public DistHashTable(ChannelFactory cf, String host, int port) { this.cf = cf; cf.init(); // why? see constructor try { channel = cf.getChannel(host, port); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } if (debug) { logger.debug("dl channel = {}", channel); } //theList = new ConcurrentSkipListMap(); // Java 1.6 theList = new TreeMap(); listener = new DHTListener(channel, theList); // listener.start() is in initialize() } /** * DistHashTable. * @param sc SocketChannel to use. */ public DistHashTable(SocketChannel sc) { cf = null; channel = sc; //theList = new ConcurrentSkipListMap(); // Java 1.6 theList = new TreeMap(); listener = new DHTListener(channel, theList); // listener.start() is in initialize() } /** * Hash code. */ @Override public int hashCode() { return theList.hashCode(); } /** * Equals. */ @Override public boolean equals(Object o) { return theList.equals(o); } /** * Contains key. */ @Override public boolean containsKey(Object o) { return theList.containsKey(o); } /** * Contains value. */ @Override public boolean containsValue(Object o) { return theList.containsValue(o); } /** * Get the values as Collection. */ @Override public Collection values() { synchronized (theList) { return new ArrayList(theList.values()); //return theList.values(); } } /** * Get the keys as set. */ @Override public Set keySet() { synchronized (theList) { return theList.keySet(); } } /** * Get the entries as Set. */ @Override public Set> entrySet() { synchronized (theList) { return theList.entrySet(); } } /** * Get the internal list, convert from Collection. */ // To be fixed?, but is ok. public List getValueList() { synchronized (theList) { return new ArrayList(theList.values()); } } /** * Get the internal sorted map. For synchronization purpose in normalform. */ public SortedMap getList() { return theList; } /** * Size of the (local) list. */ @Override public int size() { synchronized (theList) { return theList.size(); } } /** * Is the List empty? */ @Override public boolean isEmpty() { synchronized (theList) { return theList.isEmpty(); } } /** * List key iterator. */ public Iterator iterator() { synchronized (theList) { return theList.keySet().iterator(); } } /** * List value iterator. */ public Iterator valueIterator() { synchronized (theList) { return theList.values().iterator(); } } /** * Put object to the distributed hash table. Blocks until the key value pair * is send and received from the server. * @param key * @param value */ public void putWait(K key, V value) { //V o = put(key, value); // = send // assume key does not change multiple times before test: while (!value.equals(getWait(key))) { //System.out.print("#"); } } /** * Put object to the distributed hash table. Returns immediately after * sending, does not block. * @param key * @param value */ @Override public V put(K key, V value) { if (key == null || value == null) { throw new NullPointerException("null keys or values not allowed"); } try { DHTTransport tc = DHTTransport. create(key, value); channel.send(tc); //System.out.println("send: "+tc+" @ "+listener); } catch (IOException e) { logger.info("send, exception {}", e); e.printStackTrace(); } catch (Exception e) { logger.info("send, exception {}", e); e.printStackTrace(); } return null; } /** * Get value under key from DHT. Blocks until the object is send and * received from the server (actually it blocks until some value under key * is received). * @param key * @return the value stored under the key. */ public V getWait(K key) { V value = null; try { synchronized (theList) { //value = theList.get(key); value = get(key); while (value == null) { //System.out.print("^"); theList.wait(100); value = theList.get(key); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } return value; } /** * Get value under key from DHT. If no value is jet available null is * returned. * @param key * @return the value stored under the key. */ @Override public V get(Object key) { synchronized (theList) { return theList.get(key); } } /** * Clear the List. * Clearance request is distributed to all clients. */ @Override public void clear() { synchronized (theList) { theList.clear(); } // done after 11 month: send clear message to others try { DHTTransport tc = new DHTTransportClear(); channel.send(tc); //System.out.println("send: "+tc+" @ "+listener); } catch (IOException e) { logger.info("send, exception {}", e); e.printStackTrace(); } catch (Exception e) { logger.info("send, exception {}", e); e.printStackTrace(); } } /** * Initialize and start the list thread. */ public void init() { if (listener == null) { return; } if (listener.isDone()) { return; } if (debug) { logger.debug("initialize {}", listener); } synchronized (theList) { listener.start(); } } /** * Terminate the list thread. */ public void terminate() { if (cf != null) { cf.terminate(); } if (channel != null) { channel.close(); } //theList.clear(); if (listener == null) { return; } if (debug) { logger.debug("terminate {}", listener); } listener.setDone(); try { while (listener.isAlive()) { //System.out.print("+"); listener.interrupt(); listener.join(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } listener = null; } } /** * Thread to communicate with the list server. */ class DHTListener extends Thread { private static final Logger logger = LogManager.getLogger(DHTListener.class); private static final boolean debug = logger.isDebugEnabled(); private final SocketChannel channel; private final SortedMap theList; private boolean goon; DHTListener(SocketChannel s, SortedMap list) { channel = s; theList = list; goon = true; } boolean isDone() { return !goon; } void setDone() { goon = false; } /** * run. */ @SuppressWarnings("unchecked") @Override public void run() { logger.debug("running "); Object o; DHTTransport tc; //goon = true; while (goon) { tc = null; o = null; try { o = channel.receive(); if (debug) { logger.debug("receive({})", o); } if (this.isInterrupted()) { goon = false; break; } if (o == null) { goon = false; break; } if (o instanceof DHTTransportClear) { logger.debug("receive, clear"); synchronized (theList) { theList.clear(); theList.notifyAll(); } continue; } if (o instanceof DHTTransport) { tc = (DHTTransport) o; K key = tc.key(); if (key != null) { logger.info("receive, put(key={})", key); V val = tc.value(); synchronized (theList) { theList.put(key, val); theList.notifyAll(); } } } } catch (IOException e) { goon = false; logger.info("receive, IO exception {}", e); //e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; logger.info("receive, CNF exception {}", e); e.printStackTrace(); } catch (Exception e) { goon = false; logger.info("receive, exception {}", e); e.printStackTrace(); } } } } java-algebra-system-2.7.200/src/edu/jas/util/DistHashTableServer.java000066400000000000000000000330611445075545500253500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Server for the distributed version of a list. TODO: redistribute list for * late coming clients, removal of elements. * @author Heinz Kredel */ public class DistHashTableServer extends Thread { private static final Logger logger = LogManager.getLogger(DistHashTableServer.class); private static final boolean debug = logger.isDebugEnabled(); public final static int DEFAULT_PORT = 9009; //ChannelFactory.DEFAULT_PORT + 99; protected final ChannelFactory cf; protected List> servers; private volatile boolean goon = true; private volatile Thread mythread = null; protected final SortedMap theList; private long etime; private long dtime; private long ertime; private long drtime; /** * Constructs a new DistHashTableServer. */ public DistHashTableServer() { this(DEFAULT_PORT); } /** * DistHashTableServer. * @param port to run server on. */ public DistHashTableServer(int port) { this(new ChannelFactory(port)); } /** * DistHashTableServer. * @param cf ChannelFactory to use. */ public DistHashTableServer(ChannelFactory cf) { this.cf = cf; cf.init(); servers = new ArrayList>(); theList = new TreeMap(); etime = DHTTransport.etime; dtime = DHTTransport.dtime; ertime = DHTTransport.ertime; drtime = DHTTransport.drtime; } /** * main. Usage: DistHashTableServer <port> */ public static void main(String[] args) throws InterruptedException { int port = DEFAULT_PORT; if (args.length < 1) { System.out.println("Usage: DistHashTableServer "); } else { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { } } DistHashTableServer dhts = new DistHashTableServer/*raw: */(port); dhts.init(); dhts.join(); // until CRTL-C } /** * thread initialization and start. */ public void init() { this.start(); } /** * main server method. */ @Override public void run() { SocketChannel channel = null; DHTBroadcaster s = null; mythread = Thread.currentThread(); Entry e; DHTTransport tc; while (goon) { //logger.debug("list server {} go on", this); try { channel = cf.getChannel(); if (debug) { logger.debug("dls channel = {}", channel); } if (mythread.isInterrupted()) { goon = false; //logger.info("list server {} interrupted", this); } else { s = new DHTBroadcaster(channel, servers, /*listElem,*/theList); int ls = 0; synchronized (servers) { if (goon) { servers.add(s); ls = theList.size(); s.start(); } } if (debug) { logger.info("server {} started {}", s, s.isAlive()); } if (ls > 0) { //logger.debug("sending {} list elements", ls); synchronized (theList) { Iterator> it = theList.entrySet().iterator(); for (int i = 0; i < ls; i++) { e = it.next(); // n = e.getKey(); // findbugs, already in tc tc = e.getValue(); //DHTTransport tc = (DHTTransport) o; try { s.sendChannel(tc); } catch (IOException ioe) { // stop s } } } } } } catch (InterruptedException end) { goon = false; Thread.currentThread().interrupt(); } } if (debug) { logger.info("DHTserver {} terminated", this); } } /** * terminate all servers. */ public void terminate() { goon = false; logger.info("terminating"); if (cf != null) { cf.terminate(); } int svs = 0; List> scopy = null; if (servers != null) { synchronized (servers) { svs = servers.size(); scopy = new ArrayList>(servers); Iterator> it = scopy.iterator(); while (it.hasNext()) { DHTBroadcaster br = it.next(); br.goon = false; br.closeChannel(); try { int c = 0; while (br.isAlive()) { c++; if (c > 10) { logger.warn("giving up on {}", br); break; } //System.out.print("."); br.interrupt(); br.join(50); } if (debug) { logger.info("server {} terminated", br); } // now possible: servers.remove(br); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } servers.clear(); } logger.info("{} broadcasters terminated {}", svs, scopy); //? servers = null; } logger.debug("DHTBroadcasters terminated"); long enc = DHTTransport.etime - etime; long dec = DHTTransport.dtime - dtime; long encr = DHTTransport.ertime - ertime; long decr = DHTTransport.drtime - drtime; long drest = (encr * dec) / (enc + 1); long sumest = enc + dec + encr + drest; // +decr not meaningful logger.info("DHT time: encode = {}, decode = {}, enc raw = {}, dec raw wait = {}, dec raw est = {}, sum est = {}", enc, dec, encr, decr, drest, sumest); if (mythread == null) { return; } try { while (mythread.isAlive()) { //System.out.print("-"); mythread.interrupt(); mythread.join(100); } logger.warn("server terminated {}", mythread); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } mythread = null; logger.info("terminated"); } /** * number of servers. */ public int size() { if (servers == null) { return -1; } //synchronized (servers) removed return servers.size(); } /** * toString. * @return a string representation of this. */ @Override public String toString() { return "DHTServer(" + servers.size() + ", " + cf + ", " + super.toString() + ")"; } } /** * Thread for broadcasting all incoming objects to the list clients. */ class DHTBroadcaster extends Thread /*implements Runnable*/ { private static final Logger logger = LogManager.getLogger(DHTBroadcaster.class); private static final boolean debug = logger.isDebugEnabled(); private final SocketChannel channel; private final List> bcaster; private final SortedMap theList; volatile boolean goon = true; /** * DHTBroadcaster. * @param s SocketChannel to use. * @param bc list of broadcasters. * @param sm SortedMap with key value pairs. */ public DHTBroadcaster(SocketChannel s, List> bc, SortedMap sm) { channel = s; bcaster = bc; theList = sm; } /** * closeChannel. */ public void closeChannel() { channel.close(); } /** * sendChannel. * @param tc DHTTransport. * @throws IOException */ public void sendChannel(DHTTransport tc) throws IOException { if (goon) { channel.send(tc); } } /** * broadcast. * @param o DHTTransport element to broadcast. */ @SuppressWarnings({ "unchecked", "cast" }) public void broadcast(DHTTransport o) { if (debug) { logger.debug("broadcast = {}", o); } DHTTransport tc = null; if (o == null) { return; } //if ( ! (o instanceof DHTTransport) ) { // return; //} tc = (DHTTransport) o; K key = null; synchronized (theList) { //test //Object x = theList.get( tc.key ); //if ( x != null ) { // logger.info("theList duplicate key {}", tc.key ); //} try { if (!(o instanceof DHTTransportClear)) { key = tc.key(); theList.put(key, tc); } } catch (IOException e) { logger.warn("IO exception: tc.key() not ok {}", tc); e.printStackTrace(); } catch (ClassNotFoundException e) { logger.warn("CNF exception: tc.key() not ok {}", tc); e.printStackTrace(); } catch (Exception e) { logger.warn("exception: tc.key() not ok {}", tc); e.printStackTrace(); } } logger.info("sending key={} to {} nodes", key, bcaster.size()); List> bccopy = null; synchronized (bcaster) { bccopy = new ArrayList>(bcaster); } Iterator> it = bccopy.iterator(); while (it.hasNext()) { DHTBroadcaster br = it.next(); try { if (debug) { logger.debug("bcasting to {}", br); } br.sendChannel(tc); } catch (IOException e) { logger.info("bcaster, IOexception {}", e); synchronized (bcaster) { bcaster.remove(br); //no more: ConcurrentModificationException } try { br.goon = false; br.closeChannel(); while (br.isAlive()) { br.interrupt(); br.join(100); } } catch (InterruptedException w) { Thread.currentThread().interrupt(); } // logger.info("bcaster.remove() {}", br); } catch (Exception e) { logger.info("bcaster, exception {}", e); } } } /** * run. */ @Override public void run() { goon = true; while (goon) { try { logger.debug("trying to receive"); Object o = channel.receive(); if (this.isInterrupted()) { goon = false; break; } if (debug) { logger.debug("received = {}", o); } if (!(o instanceof DHTTransport)) { logger.warn("wrong object type: {}", o); goon = false; break; //continue; } if (o instanceof DHTTransportClear) { logger.info("receive, clear"); synchronized (theList) { theList.clear(); theList.notifyAll(); } } DHTTransport tc = (DHTTransport) o; broadcast(tc); if (this.isInterrupted()) { goon = false; } } catch (IOException e) { goon = false; logger.info("receive, IO exception {}", e); //e.printStackTrace(); } catch (ClassNotFoundException e) { goon = false; logger.info("receive, CNF exception {}", e); e.printStackTrace(); } catch (Exception e) { goon = false; logger.info("receive, exception {}", e); e.printStackTrace(); } } logger.info("ending {}", this); synchronized (bcaster) { bcaster.remove(this); } channel.close(); } /** * toString. * @return a string representation of this. */ @Override public String toString() { return "DHTBroadcaster(" + channel + "," + bcaster.size() + ")"; } } java-algebra-system-2.7.200/src/edu/jas/util/DistThreadPool.java000066400000000000000000000305721445075545500243730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.FileNotFoundException; import java.io.IOException; import java.util.LinkedList; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * Distributed thread pool. Using stack / list work-pile and Executable Channels * and Servers. * @author Heinz Kredel */ public class DistThreadPool /*extends ThreadPool*/{ /** * machine file to use. */ private final String mfile; /** * default machine file for test. */ private final static String DEFAULT_MFILE = ExecutableChannels.DEFAULT_MFILE; /** * Number of threads to use. */ protected final int threads; /** * Default number of threads to use. */ static final int DEFAULT_SIZE = 3; /** * Channels to remote executable servers. */ final ExecutableChannels ec; /** * Array of workers. */ protected DistPoolThread[] workers; /** * Number of idle workers. */ protected int idleworkers = 0; /** * Work queue / stack. */ // should be expressed using strategy pattern // List or Collection is not appropriate // LIFO strategy for recursion protected LinkedList jobstack; // FIFO strategy for GB protected StrategyEnumeration strategy = StrategyEnumeration.LIFO; private static final Logger logger = LogManager.getLogger(DistThreadPool.class); private static final boolean debug = true; //logger.isDebugEnabled(); /** * Constructs a new DistThreadPool with strategy StrategyEnumeration.FIFO * and size DEFAULT_SIZE. */ public DistThreadPool() { this(StrategyEnumeration.FIFO, DEFAULT_SIZE, null); } /** * Constructs a new DistThreadPool with size DEFAULT_SIZE. * @param strategy for job processing. */ public DistThreadPool(StrategyEnumeration strategy) { this(strategy, DEFAULT_SIZE, null); } /** * Constructs a new DistThreadPool with strategy StrategyEnumeration.FIFO. * @param size of the pool. */ public DistThreadPool(int size) { this(StrategyEnumeration.FIFO, size, null); } /** * Constructs a new DistThreadPool with strategy StrategyEnumeration.FIFO. * @param size of the pool. * @param mfile machine file. */ public DistThreadPool(int size, String mfile) { this(StrategyEnumeration.FIFO, size, mfile); } /** * Constructs a new DistThreadPool. * @param strategy for job processing. * @param size of the pool. * @param mfile machine file. */ public DistThreadPool(StrategyEnumeration strategy, int size, String mfile) { this.strategy = strategy; if (size < 0) { this.threads = 0; } else { this.threads = size; } if (mfile == null || mfile.length() == 0) { this.mfile = DEFAULT_MFILE; } else { this.mfile = mfile; } jobstack = new LinkedList(); // ok for all strategies ? try { ec = new ExecutableChannels(this.mfile); } catch (FileNotFoundException e) { e.printStackTrace(); throw new IllegalArgumentException("DistThreadPool " + e); } if (debug) { logger.info("ec = {}", ec); } try { ec.open(threads); } catch (IOException e) { e.printStackTrace(); throw new IllegalArgumentException("DistThreadPool " + e); } if (debug) { logger.info("ec = {}", ec); } workers = new DistPoolThread[0]; } /** * String representation. */ @Override public String toString() { StringBuffer s = new StringBuffer("DistThreadPool("); s.append("threads="+threads); s.append(", strategy="+strategy); s.append(", exchan="+ec); s.append(", workers="+workers.length); s.append(")"); return s.toString(); } /** * thread initialization and start. */ public void init() { if (workers == null || workers.length == 0) { workers = new DistPoolThread[threads]; for (int i = 0; i < workers.length; i++) { workers[i] = new DistPoolThread(this, ec, i); workers[i].start(); } logger.info("init: {}", this); } } /** * number of worker threads. */ public int getNumber() { if (workers == null || workers.length < threads) { init(); // start threads } return workers.length; // not null } /** * get used strategy. */ public StrategyEnumeration getStrategy() { return strategy; } /** * the used executable channel. */ public ExecutableChannels getEC() { return ec; // not null } /** * Terminates the threads. * @param shutDown true, if shut-down of the remote executable servers is * requested, false, if remote executable servers stay alive. */ public void terminate(boolean shutDown) { if (shutDown) { logger.info("shutdown = {}", this); ShutdownRequest sdr = new ShutdownRequest(); for (int i = 0; i < workers.length; i++) { addJob(sdr); } try { Thread.sleep(20); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } logger.info("remaining jobs = {}", jobstack.size()); try { for (int i = 0; i < workers.length; i++) { while (workers[i].isAlive()) { workers[i].interrupt(); workers[i].join(100); } } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } ec.close(); } else { terminate(); } logger.info("terminated = {}", this); } /** * Terminates the threads. */ public void terminate() { logger.info("terminate = {}", this); while (hasJobs()) { try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } for (int i = 0; i < workers.length; i++) { try { while (workers[i].isAlive()) { workers[i].interrupt(); workers[i].join(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } ec.close(); logger.info("terminated = {}", this); } /** * adds a job to the workpile. * @param job */ public synchronized void addJob(Runnable job) { if (workers == null || workers.length < threads) { init(); // start threads } jobstack.addLast(job); logger.debug("adding job"); if (idleworkers > 0) { logger.debug("notifying a jobless worker"); notifyAll(); // findbugs } } /** * get a job for processing. */ protected synchronized Runnable getJob() throws InterruptedException { while (jobstack.isEmpty()) { idleworkers++; logger.debug("waiting"); wait(); idleworkers--; } // is expressed using strategy enumeration if (strategy == StrategyEnumeration.LIFO) { return jobstack.removeLast(); // LIFO } return jobstack.removeFirst(); // FIFO } /** * check if there are jobs for processing. */ public boolean hasJobs() { if (jobstack.size() > 0) { return true; } for (int i = 0; i < workers.length; i++) { if (workers[i].working) { return true; } } return false; } /** * check if there are more than n jobs for processing. * @param n Integer * @return true, if there are possibly more than n jobs. */ public boolean hasJobs(int n) { int j = jobstack.size(); if (j > 0 && (j + workers.length > n)) { return true; // if j > 0 no worker should be idle // ( ( j > 0 && ( j+workers.length > n ) ) || ( j > n ) } int x = 0; for (int i = 0; i < workers.length; i++) { if (workers[i].working) { x++; } } if ((j + x) > n) { return true; } return false; } } /** * Implements a shutdown task. */ class ShutdownRequest implements Runnable { /** * Run the thread. */ public void run() { System.out.println("running ShutdownRequest"); } /** * toString. * @see java.lang.Object#toString() */ @Override public String toString() { return "ShutdownRequest"; } } /** * Implements one local part of the distributed thread. */ class DistPoolThread extends Thread { final DistThreadPool pool; final ExecutableChannels ec; final int myId; private static final Logger logger = LogManager.getLogger(DistPoolThread.class); private static final boolean debug = logger.isDebugEnabled(); boolean working = false; /** * @param pool DistThreadPool. */ public DistPoolThread(DistThreadPool pool, ExecutableChannels ec, int i) { this.pool = pool; this.ec = ec; myId = i; } /** * Run the thread. */ @Override public void run() { logger.info("ready, myId = {}", myId); Runnable job; int done = 0; long time = 0; long t; boolean running = true; while (running) { try { logger.debug("looking for a job"); job = pool.getJob(); working = true; if (debug) { logger.info("working {} on {}", myId, job); } t = System.currentTimeMillis(); // send and wait, like rmi try { if (job instanceof ShutdownRequest) { ec.send(myId, ExecutableServer.STOP); } else { ec.send(myId, job); } if (debug) { logger.info("send {} at {} send job {}", myId, ec, job); } } catch (IOException e) { e.printStackTrace(); logger.info("error send {} at {} e = {}", myId, ec, e); working = false; } // remote: job.run(); Object o = null; try { if (working) { logger.info("waiting {} on {}", myId, job); o = ec.receive(myId); if (debug) { logger.info("receive {} at {} send job {} received {}", myId, ec, job, o); } } } catch (IOException e) { logger.info("receive exception {} send job {}, e = {}", myId, job, e); //e.printStackTrace(); running = false; } catch (ClassNotFoundException e) { logger.info("receive exception {} send job {}, e = {}", myId, job, e); //e.printStackTrace(); running = false; } finally { if (debug) { logger.info("receive finally {} at {} send job {} received {} running {}", myId, ec, job, o, running); } } working = false; time += System.currentTimeMillis() - t; done++; if (debug) { logger.info("done {} with {}", myId, o); } } catch (InterruptedException e) { running = false; Thread.currentThread().interrupt(); } } logger.info("terminated {}, done {} jobs in {} milliseconds", myId, done, time); } } java-algebra-system-2.7.200/src/edu/jas/util/DistributedList.java000066400000000000000000000130251445075545500246160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Iterator; //import java.util.Collection; import java.util.List; import java.util.ArrayList; import java.util.SortedMap; import java.util.TreeMap; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; //import edu.unima.ky.parallel.ChannelFactory; //import edu.unima.ky.parallel.SocketChannel; /** * Distributed version of a List. * Implemented with a SortedMap / TreeMap to keep the sequence order of elements. * @author Heinz Kredel */ public class DistributedList /* implements List not jet */ { private static final Logger logger = LogManager.getLogger(DistributedList.class); protected final SortedMap theList; protected final ChannelFactory cf; protected SocketChannel channel = null; protected Listener listener = null; /** * Constructor for DistributedList. * @param host name or IP of server host. */ public DistributedList(String host) { this(host,DistributedListServer.DEFAULT_PORT); } /** * Constructor for DistributedList. * @param host name or IP of server host. * @param port of server. */ public DistributedList(String host,int port) { this(new ChannelFactory(port+1),host,port); } /** * Constructor for DistributedList. * @param cf ChannelFactory to use. * @param host name or IP of server host. * @param port of server. */ public DistributedList(ChannelFactory cf,String host,int port) { this.cf = cf; cf.init(); try { channel = cf.getChannel(host,port); } catch (IOException e) { e.printStackTrace(); } logger.debug("dl channel = {}", channel); theList = new TreeMap(); } /** * Constructor for DistributedList. * @param sc SocketChannel to use. */ public DistributedList(SocketChannel sc) { cf = null; channel = sc; theList = new TreeMap(); } /** * List thread initialization and start. */ public void init() { listener = new Listener(channel,theList); listener.start(); } /** * Terminate the list thread. */ public void terminate() { if ( cf != null ) { cf.terminate(); //logger.warn("terminating {}", cf); } if ( channel != null ) { channel.close(); } //theList.clear(); if ( listener == null ) { return; } logger.debug("terminate {}", listener); listener.setDone(); try { while ( listener.isAlive() ) { listener.interrupt(); listener.join(100); } } catch (InterruptedException u) { Thread.currentThread().interrupt(); } listener = null; } /** * Get the internal list, convert from Collection. */ public List getList() { return new ArrayList( theList.values() ); } /** * Size of the (local) list. */ public int size() { return theList.size(); } /** * Add object to the list and distribute to other lists. * Blocks until the object is send and received from the server * (actually it blocks until some object is received). * @param o */ public synchronized void add(Object o) { int sz1 = theList.size() + 1; try { channel.send(o); //System.out.println("send: "+o+" @ "+listener); } catch (IOException e) { e.printStackTrace(); } try { while ( theList.size() < sz1 ) { this.wait(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); e.printStackTrace(); } } /** * Clear the List. * caveat: must be called on all clients. */ public synchronized void clear() { theList.clear(); } /** * Is the List empty? */ public boolean isEmpty() { return theList.isEmpty(); } /** * List iterator. */ public Iterator iterator() { return theList.values().iterator(); } } /** * Thread to communicate with the list server. */ class Listener extends Thread { private SocketChannel channel; private SortedMap theList; private volatile boolean goon; Listener(SocketChannel s, SortedMap list) { channel = s; theList = list; } void setDone() { goon = false; } @Override public void run() { Counter n; Object o; goon = true; while (goon) { n = null; o = null; try { n = (Counter) channel.receive(); if ( this.isInterrupted() ) { goon = false; } else { o = channel.receive(); //System.out.println("receive("+n+","+o+" @ "+Thread.currentThread()); if ( this.isInterrupted() ) { goon = false; } theList.put(n,o); } } catch (IOException e) { goon = false; } catch (ClassNotFoundException e) { e.printStackTrace(); goon = false; } } } } java-algebra-system-2.7.200/src/edu/jas/util/DistributedListServer.java000066400000000000000000000251011445075545500260030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.io.Serializable; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map.Entry; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; //import edu.unima.ky.parallel.ChannelFactory; //import edu.unima.ky.parallel.SocketChannel; /** * Server for the distributed version of a list. * @author Heinz Kredel * TODO: redistribute list for late coming clients, removal of elements. */ public class DistributedListServer extends Thread { private static final Logger logger = LogManager.getLogger(DistributedListServer.class); public final static int DEFAULT_PORT = ChannelFactory.DEFAULT_PORT + 99; protected final ChannelFactory cf; protected List servers; private volatile boolean goon = true; private volatile Thread mythread = null; private Counter listElem = null; protected final SortedMap theList; /** * Constructs a new DistributedListServer. */ public DistributedListServer() { this(DEFAULT_PORT); } /** * DistributedListServer. * @param port to run server on. */ public DistributedListServer(int port) { this( new ChannelFactory(port) ); } /** * DistributedListServer. * @param cf ChannelFactory to use. */ public DistributedListServer(ChannelFactory cf) { listElem = new Counter(0); this.cf = cf; cf.init(); servers = new ArrayList(); theList = new TreeMap(); } /** * main. * Usage: DistributedListServer <port> */ public static void main(String[] args) throws InterruptedException { int port = DEFAULT_PORT; if ( args.length < 1 ) { System.out.println("Usage: DistributedListServer "); } else { try { port = Integer.parseInt( args[0] ); } catch (NumberFormatException e) { } } DistributedListServer dls = new DistributedListServer(port); dls.init(); dls.join(); // until CRTL-C } /** * thread initialization and start. */ public void init() { this.start(); } /** * main server method. */ @Override public void run() { SocketChannel channel = null; Broadcaster s = null; mythread = Thread.currentThread(); Entry e; Object n; Object o; while (goon) { // logger.debug("list server {} go on", this); try { channel = cf.getChannel(); logger.debug("dls channel = {}", channel); if ( mythread.isInterrupted() ) { goon = false; //logger.info("list server {} interrupted", this); } else { s = new Broadcaster(channel,servers,listElem,theList); int ls = 0; synchronized (servers) { servers.add( s ); ls = theList.size(); s.start(); } //logger.debug("server {} started", s); if ( ls > 0 ) { logger.info("sending {} list elements", ls); synchronized (theList) { Iterator it = theList.entrySet().iterator(); for ( int i = 0; i < ls; i++ ) { e = (Entry)it.next(); n = e.getKey(); o = e.getValue(); try { s.sendChannel( n,o ); } catch (IOException ioe) { // stop s } } } } } } catch (InterruptedException end) { goon = false; Thread.currentThread().interrupt(); } } //logger.debug("listserver {} terminated", this); } /** * terminate all servers. */ public void terminate() { goon = false; logger.debug("terminating ListServer"); if ( cf != null ) cf.terminate(); if ( servers != null ) { Iterator it = servers.iterator(); while ( it.hasNext() ) { Broadcaster br = (Broadcaster) it.next(); br.closeChannel(); try { while ( br.isAlive() ) { //System.out.print("."); br.interrupt(); br.join(100); } //logger.debug("server {} terminated", br); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } servers = null; } logger.debug("Broadcasters terminated"); if ( mythread == null ) return; try { while ( mythread.isAlive() ) { // System.out.print("-"); mythread.interrupt(); mythread.join(100); } //logger.debug("server {} terminated", mythread); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } mythread = null; logger.debug("ListServer terminated"); } /** * number of servers. */ public int size() { if ( servers == null ) { return -1; } return servers.size(); } } /** * Class for holding the list index used as key in TreeMap. * Implemented since Integer has no add() method. * Must implement Comparable so that TreeMap works with correct ordering. */ class Counter implements Serializable, Comparable { private int value; /** * Counter. */ public Counter() { this(0); } /** * Counter. * @param v */ public Counter(int v) { value = v; } /** * intValue. * @return the value. */ public int intValue() { return value; } /** * add. * @param v */ public void add(int v) { // synchronized elsewhere value += v; } /** * equals. * @param ob an Object. * @return true if this is equal to o, else false. */ @Override public boolean equals(Object ob) { if ( ! (ob instanceof Counter) ) { return false; } return 0 == compareTo( (Counter)ob ); } /** * compareTo. * @param c a Counter. * @return 1 if (this < c), 0 if (this == c), -1 if (this > c). */ public int compareTo(Counter c) { int x = c.intValue(); if ( value > x ) { return 1; } if ( value < x ) { return -1; } return 0; } /** * Hash code for this Counter. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return value; } /** * toString. */ @Override public String toString() { return "Counter("+value+")"; } } /** * Thread for broadcasting all incoming objects to the list clients. */ class Broadcaster extends Thread /*implements Runnable*/ { private static final Logger logger = LogManager.getLogger(Broadcaster.class); private final SocketChannel channel; private final List bcaster; private Counter listElem; private final SortedMap theList; /** * Broadcaster. * @param s SocketChannel to use. * @param p list of broadcasters. * @param le counter * @param sm SortedMap with counter value pairs. */ public Broadcaster(SocketChannel s, List p, Counter le, SortedMap sm) { channel = s; bcaster = p; listElem = le; theList = sm; } /** * closeChannel. */ public void closeChannel() { channel.close(); } /** * sendChannel. * @param n counter. * @param o value. * @throws IOException */ public void sendChannel(Object n, Object o) throws IOException { synchronized (channel) { channel.send(n); channel.send(o); } } /** * broadcast. * @param o object to store and send. */ public void broadcast(Object o) { Counter li = null; synchronized (listElem) { listElem.add(1); li = new Counter( listElem.intValue() ); } synchronized (theList) { theList.put( li, o ); } synchronized (bcaster) { Iterator it = bcaster.iterator(); while ( it.hasNext() ) { Broadcaster br = (Broadcaster) it.next(); try { br.sendChannel(li,o); //System.out.println("bcast: "+o+" to "+x.channel); } catch (IOException e) { try { br.closeChannel(); while ( br.isAlive() ) { br.interrupt(); br.join(100); } } catch (InterruptedException u) { Thread.currentThread().interrupt(); } bcaster.remove( br ); } } } } /** * run. */ @Override public void run() { Object o; boolean goon = true; while (goon) { try { o = channel.receive(); //System.out.println("receive: "+o+" from "+channel); broadcast(o); if ( this.isInterrupted() ) { goon = false; } } catch (IOException e) { goon = false; } catch (ClassNotFoundException e) { goon = false; e.printStackTrace(); } } logger.debug("broadcaster terminated {}", this); channel.close(); } /** * toString. * @return a string representation of this. */ @Override public String toString() { return "Broadcaster("+channel+","+bcaster.size()+","+listElem+")"; } } java-algebra-system-2.7.200/src/edu/jas/util/ExecutableChannels.java000066400000000000000000000201751445075545500252410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; // import edu.unima.ky.parallel.ChannelFactory; // import edu.unima.ky.parallel.SocketChannel; /** * ExecutableChannels used to receive and execute classes. * @author Heinz Kredel */ public class ExecutableChannels { private static final Logger logger = LogManager.getLogger(ExecutableChannels.class); /** * default port. */ protected final static int DEFAULT_PORT = 7114; //ChannelFactory.DEFAULT_PORT; /** * default machine file. */ protected final static String DEFAULT_MFILE = "examples/machines.test"; protected final ChannelFactory cf; protected SocketChannel[] channels = null; protected String[] servers = null; protected int[] ports = null; /** * Internal constructor. */ protected ExecutableChannels() { cf = new ChannelFactory(); cf.init(); } /** * Constructor from array of server:port strings. * @param srvs A String array. */ public ExecutableChannels(String[] srvs) { this(); if (srvs == null) { return; } servers = new String[srvs.length]; ports = new int[srvs.length]; for (int i = 0; i < srvs.length; i++) { setServerPort(i, srvs[i]); } } /** * Constructor from machine file. * @param mfile * @throws FileNotFoundException. */ public ExecutableChannels(String mfile) throws FileNotFoundException { this(); if (mfile == null || mfile.length() == 0) { mfile = DEFAULT_MFILE; } InputStreamReader isr = new InputStreamReader(new FileInputStream(mfile),Charset.forName("UTF8")); BufferedReader in = new BufferedReader(isr); String line = null; List list = new ArrayList(); int x; try { while (true) { if (!in.ready()) { break; } line = in.readLine(); if (line == null) { break; } x = line.indexOf("#"); if (x >= 0) { line = line.substring(0, x); } line = line.trim(); if (line.length() == 0) { continue; } list.add(line); } } catch (IOException ignored) { } finally { try { in.close(); isr.close(); } catch (IOException ignore) { } } logger.debug("list.size() in {} = {}", mfile, list.size()); if (list.size() == 0) { return; } servers = new String[list.size()]; ports = new int[list.size()]; for (int i = 0; i < servers.length; i++) { setServerPort(i, list.get(i)); } } /* * internal method */ protected void setServerPort(int i, String srv) { int x = srv.indexOf(":"); ports[i] = DEFAULT_PORT; if (x < 0) { servers[i] = srv; } else { servers[i] = srv.substring(0, x); String p = srv.substring(x + 1, srv.length()); try { ports[i] = Integer.parseInt(p); } catch (NumberFormatException ignored) { } } } /** * String representation. */ @Override public String toString() { StringBuffer s = new StringBuffer("ExecutableChannels("); if (servers != null) { for (int i = 0; i < servers.length; i++) { s.append(servers[i] + ":" + ports[i]); if (i < servers.length - 1) { s.append(" "); } } } if (channels != null) { s.append(" channels = "); for (int i = 0; i < channels.length; i++) { s.append(channels[i]); if (i < channels.length - 1) { s.append(" "); } } } s.append(")"); return s.toString(); } /** * number of servers. */ public int numServers() { if (servers != null) { return servers.length; } return -1; } /** * get master host. */ public String getMasterHost() { if (servers != null && servers.length > 0) { return servers[0]; } return null; } /** * get master port. */ public int getMasterPort() { if (ports != null && ports.length > 0) { return ports[0]; } return 0; } /** * number of channels. */ public int numChannels() { if (channels != null) { return channels.length; } return -1; } /** * open, setup of SocketChannels. * @throws IOException. */ public void open() throws IOException { logger.debug("opening {} channels", servers.length); if (servers.length <= 1) { throw new IOException("to few servers"); } channels = new SocketChannel[servers.length - 1]; for (int i = 1; i < servers.length; i++) { channels[i - 1] = cf.getChannel(servers[i], ports[i]); } } /** * open, setup of SocketChannels. If nc > servers.length open in round * robin fashion. * @param nc number of channels to open. * @throws IOException. */ public void open(int nc) throws IOException { logger.debug("opening {} channels", nc); if (servers.length <= 1) { throw new IOException("to few servers"); } channels = new SocketChannel[nc]; int j = 1; // 0 is master for (int i = 0; i < channels.length; i++) { if (j >= servers.length) { // modulo #servers j = 1; } channels[i] = cf.getChannel(servers[j], ports[j]); j++; } } /** * close all channels and ChannelFactory. */ public void close() { logger.debug("closing ExecutableChannels"); if (cf != null) { cf.terminate(); } if (channels != null) { for (int i = 0; i < channels.length; i++) { if (channels[i] != null) { try { channels[i].send(ExecutableServer.STOP); } catch (IOException e) { if (logger.isDebugEnabled()) { e.printStackTrace(); } } finally { channels[i].close(); } channels[i] = null; } } channels = null; } logger.debug("ExecuteChannels closed"); } /** * getChannel. * @param i channel number. */ public SocketChannel getChannel(int i) { if (channels != null && 0 <= i && i < channels.length) { return channels[i]; } return null; } /** * getChannels. */ /*package*/SocketChannel[] getChannels() { return channels; } /** * send on channel i. * @param i channel number. * @param o object to send. */ public void send(int i, Object o) throws IOException { if (channels != null && 0 <= i && i < channels.length) { channels[i].send(o); } } /** * receive on channel i. * @param i channel number. * @return object received. */ public Object receive(int i) throws IOException, ClassNotFoundException { if (channels != null && 0 <= i && i < channels.length) { return channels[i].receive(); } return null; } } java-algebra-system-2.7.200/src/edu/jas/util/ExecutableServer.java000066400000000000000000000215001445075545500247450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * ExecutableServer is used to receive and execute classes. * @author Heinz Kredel */ public class ExecutableServer extends Thread { private static final Logger logger = LogManager.getLogger(ExecutableServer.class); private static final boolean debug = logger.isDebugEnabled(); /** * ChannelFactory to use. */ protected final ChannelFactory cf; /** * List of server threads. */ protected List servers = null; /** * Default port to listen to. */ public static final int DEFAULT_PORT = 7411; /** * Constant to signal completion. */ public static final String DONE = "Done"; /** * Constant to request shutdown. */ public static final String STOP = "Stop"; private volatile boolean goon = true; private volatile Thread mythread = null; /** * ExecutableServer on default port. */ public ExecutableServer() { this(DEFAULT_PORT); } /** * ExecutableServer. * @param port */ public ExecutableServer(int port) { this(new ChannelFactory(port)); } /** * ExecutableServer. * @param cf channel factory to reuse. */ public ExecutableServer(ChannelFactory cf) { this.cf = cf; cf.init(); servers = new ArrayList(); } /** * main method to start serving thread. * @param args args[0] is port */ public static void main(String[] args) throws InterruptedException { int port = DEFAULT_PORT; if (args.length < 1) { System.out.println("Usage: ExecutableServer "); } else { try { port = Integer.parseInt(args[0]); } catch (NumberFormatException e) { } } //logger.info("ExecutableServer at port {}", port); ExecutableServer es = new ExecutableServer(port); es.init(); es.join(); // do not use terminate() // until CRTL-C } /** * thread initialization and start. */ public void init() { this.start(); logger.info("ExecutableServer at {}", cf); } /** * number of servers. */ public int size() { if ( servers == null ) { return -1; } return servers.size(); } /** * run is main server method. */ @Override public void run() { SocketChannel channel = null; Executor s = null; mythread = Thread.currentThread(); while (goon) { if (debug) { logger.info("server {} go on", this); } try { channel = cf.getChannel(); logger.info("channel = {}", channel); if (mythread.isInterrupted()) { goon = false; logger.debug("execute server {} interrupted", this); channel.close(); } else { s = new Executor(channel); // ---,servers); if (goon) { // better synchronize with terminate servers.add(s); s.start(); logger.debug("server {} started", s); } else { s = null; channel.close(); } } } catch (InterruptedException e) { goon = false; Thread.currentThread().interrupt(); if (debug) { e.printStackTrace(); } } } if (debug) { logger.info("server {} terminated", this); } } /** * terminate all servers. */ public void terminate() { goon = false; logger.info("terminating ExecutableServer"); if (cf != null) cf.terminate(); if (servers != null) { Iterator it = servers.iterator(); while (it.hasNext()) { Executor x = it.next(); if (x.channel != null) { x.channel.close(); } try { while (x.isAlive()) { //System.out.print("."); x.interrupt(); x.join(100); } logger.debug("server {} terminated", x); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } servers = null; } logger.info("Executors terminated"); if (mythread == null) return; try { while (mythread.isAlive()) { //System.out.print("-"); mythread.interrupt(); mythread.join(100); } //logger.debug("server {} terminated", mythread); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } mythread = null; logger.info("terminated"); } /** * String representation. */ @Override public String toString() { StringBuffer s = new StringBuffer("ExecutableServer("); s.append(cf.toString()); s.append(")"); return s.toString(); } } /** * class for executing incoming objects. */ class Executor extends Thread /*implements Runnable*/{ private static final Logger logger = LogManager.getLogger(Executor.class); private static final boolean debug = logger.isDebugEnabled(); protected final SocketChannel channel; Executor(SocketChannel s) { channel = s; } /** * run. */ @Override public void run() { Object o; RemoteExecutable re = null; String d; boolean goon = true; logger.debug("executor started {}", this); while (goon) { try { o = channel.receive(); logger.info("receive: {} from {}", o, channel); if (this.isInterrupted()) { goon = false; } else { if (debug) { logger.debug("receive: {} from {}", o, channel); } if (o instanceof String) { d = (String) o; if (ExecutableServer.STOP.equals(d)) { goon = false; // stop this thread channel.send(ExecutableServer.DONE); } else { logger.warn("invalid/unknown String: {} from {}", d, channel); goon = false; // stop this thread ? channel.send(ExecutableServer.DONE); } } // check permission if (o instanceof RemoteExecutable) { re = (RemoteExecutable) o; if (debug) { logger.info("running {}", re); } try { re.run(); } catch(Exception e) { logger.info("Exception on re.run() {}", e); if (logger.isInfoEnabled()) { e.printStackTrace(); } } finally { logger.info("finally re.run() {}", re); } if (debug) { logger.info("finished {}", re); } if (this.isInterrupted()) { goon = false; } else { channel.send(ExecutableServer.DONE); logger.info("finished send {}", ExecutableServer.DONE); //goon = false; // stop this thread } } } } catch (IOException e) { goon = false; logger.info("IOException {}", e); if (debug) { e.printStackTrace(); } } catch (ClassNotFoundException e) { goon = false; logger.info("ClassNotFoundException {}", e); e.printStackTrace(); } finally { logger.info("finally {}", this); } } channel.close(); logger.info("terminated {}", this); } } java-algebra-system-2.7.200/src/edu/jas/util/KsubSet.java000066400000000000000000000134621445075545500230650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; /** * K-Subset with iterator. * @author Heinz Kredel */ public class KsubSet implements Iterable> { /** * data structure. */ public final List set; // Iterable also ok public final int k; /** * KsubSet constructor. * @param set generating set. * @param k size of subsets. */ public KsubSet(List set, int k) { if (set == null) { throw new IllegalArgumentException("null set not allowed"); } if (k < 0 || k > set.size()) { throw new IllegalArgumentException("k out of range"); } this.set = set; this.k = k; } /** * Get an iterator over subsets. * @return an iterator. */ public Iterator> iterator() { if (k == 0) { return new ZeroSubSetIterator(set); } if (k == 1) { return new OneSubSetIterator(set); } return new KsubSetIterator(set, k); } } /** * Power set iterator. * @author Heinz Kredel */ class KsubSetIterator implements Iterator> { /** * data structure. */ public final List set; public final int k; final List rest; private E current; private Iterator> recIter; private final Iterator iter; /** * KsubSetIterator constructor. * @param set generating set. * @param k subset size. */ public KsubSetIterator(List set, int k) { if (set == null || set.size() == 0) { throw new IllegalArgumentException("null or empty set not allowed"); } if (k < 2 || k > set.size()) { throw new IllegalArgumentException("k out of range"); } this.set = set; this.k = k; iter = this.set.iterator(); current = iter.next(); //System.out.println("current = " + current); rest = new LinkedList(this.set); rest.remove(0); //System.out.println("rest = " + rest); if (k == 2) { recIter = new OneSubSetIterator(rest); } else { recIter = new KsubSetIterator(rest, k - 1); } } /** * Test for availability of a next subset. * @return true if the iteration has more subsets, else false. */ public boolean hasNext() { return recIter.hasNext() || (iter.hasNext() && rest.size() >= k); } /** * Get next subset. * @return next subset. */ public List next() { if (recIter.hasNext()) { List next = new LinkedList(recIter.next()); next.add(0, current); return next; } if (iter.hasNext()) { current = iter.next(); //System.out.println("current = " + current); rest.remove(0); //System.out.println("rest = " + rest); if (rest.size() < k - 1) { throw new NoSuchElementException("invalid call of next()"); } if (k == 2) { recIter = new OneSubSetIterator(rest); } else { recIter = new KsubSetIterator(rest, k - 1); } return this.next(); // retry } throw new NoSuchElementException("invalid call of next()"); } /** * Remove the last subset returned from underlying set if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove subsets"); } } /** * One-subset iterator. * @author Heinz Kredel */ class OneSubSetIterator implements Iterator> { /** * data structure. */ public final List set; private Iterator iter; /** * OneSubSetIterator constructor. * @param set generating set. */ public OneSubSetIterator(List set) { this.set = set; if (set == null || set.size() == 0) { iter = null; return; } iter = this.set.iterator(); } /** * Test for availability of a next subset. * @return true if the iteration has more subsets, else false. */ public boolean hasNext() { if (iter == null) { return false; } return iter.hasNext(); } /** * Get next subset. * @return next subset. */ public List next() { List next = new LinkedList(); next.add(iter.next()); return next; } /** * Remove the last subset returned from underlying set if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove subsets"); } } /** * Zero-subset iterator. * @author Heinz Kredel */ class ZeroSubSetIterator implements Iterator> { /** * data structure. */ private boolean hasNext; /** * ZeroSubSetIterator constructor. * @param set generating set (ignored). */ public ZeroSubSetIterator(List set) { hasNext = true; if (set == null || set.size() == 0) { hasNext = false; } } /** * Test for availability of a next subset. * @return true if the iteration has more subsets, else false. */ public boolean hasNext() { return hasNext; } /** * Get next subset. * @return next subset. */ public List next() { List next = new LinkedList(); hasNext = false; return next; } /** * Remove the last subset returned from underlying set if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove subsets"); } } java-algebra-system-2.7.200/src/edu/jas/util/ListUtil.java000066400000000000000000000067661445075545500232670ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.lang.Iterable; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Iterator; import edu.jas.structure.Element; import edu.jas.structure.UnaryFunctor; /** * List utilities. For example map functor on list elements. * @author Heinz Kredel */ public class ListUtil { //private static final Logger logger = LogManager.getLogger(ListUtil.class); // private static final boolean debug = logger.isDebugEnabled(); /** * Map a unary function to the list. * @param f evaluation functor. * @return new list elements f(list(i)). */ public static , D extends Element> List map(List list, UnaryFunctor f) { if (list == null) { return null; } List nl; if (list instanceof ArrayList) { nl = new ArrayList(list.size()); } else if (list instanceof LinkedList) { nl = new LinkedList(); } else { throw new RuntimeException("list type not implemented"); } for (C c : list) { D n = f.eval(c); nl.add(n); } return nl; } /** * Tuple from lists. * @param A list of lists. * @return new list with tuples (a_1,...,an) with ai in Ai, * i=0,...,length(A)-1. */ public static List> tupleFromList(List> A) { if (A == null) { return null; } List> T = new ArrayList>(A.size()); if (A.size() == 0) { return T; } if (A.size() == 1) { List Ap = A.get(0); for (C a : Ap) { List Tp = new ArrayList(1); Tp.add(a); T.add(Tp); } return T; } List> Ap = new ArrayList>(A); List f = Ap.remove(0); List> Tp = tupleFromList(Ap); //System.out.println("Tp = " + Tp); for (C a : f) { for (List tp : Tp) { List ts = new ArrayList(); ts.add(a); ts.addAll(tp); T.add(ts); } } return T; } /** * Create a list of given length and content. * @param n length of new list * @param e object to be filled in * @return list (e, ..., e) of length n */ public static List fill(int n, C e) { List r = new ArrayList(n); for (int m = 0; m < n; m++) { r.add(e); } return r; } /** * Test two iterables for equal contents and sequence. * @param a iterable * @param b iterable * @return true, if a equals b in sequence and content, else false. */ public static boolean equals(Iterable a, Iterable b) { Iterator ai = a.iterator(); Iterator bi = b.iterator(); while (ai.hasNext() && bi.hasNext()) { C aa = ai.next(); C ba = bi.next(); if (!aa.equals(ba)) { System.out.println("aa != ba: " + aa + " != " + ba); return false; } } if (ai.hasNext()) { System.out.println("aa: " + ai.next()); return false; } if (bi.hasNext()) { System.out.println("ba: " + bi.next()); return false; } return true; } } java-algebra-system-2.7.200/src/edu/jas/util/LongIterable.java000066400000000000000000000066361445075545500240610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.Iterator; import java.util.NoSuchElementException; /** * Iterable for Long. * @author Heinz Kredel */ public class LongIterable implements Iterable { private boolean nonNegative = true; private long upperBound = Long.MAX_VALUE; /** * Constructor. */ public LongIterable() { } /** * Constructor. */ public LongIterable(long ub) { upperBound = ub; } /** * Set the upper bound for the iterator. * @param ub an upper bound for the iterator elements. */ public void setUpperBound(long ub) { upperBound = ub; } /** * Get the upper bound for the iterator. * @return the upper bound for the iterator elements. */ public long getUpperBound() { return upperBound; } /** * Set the iteration algorithm to all elements. */ public void setAllIterator() { nonNegative = false; } /** * Set the iteration algorithm to non-negative elements. */ public void setNonNegativeIterator() { nonNegative = true; } /** * Get an iterator over Long. * @return an iterator. */ public Iterator iterator() { return new LongIterator(nonNegative, upperBound); } } /** * Long iterator. * @author Heinz Kredel */ class LongIterator implements Iterator { /** * data structure. */ long current; boolean empty; final boolean nonNegative; protected long upperBound; /** * Set the upper bound for the iterator. * @param ub an upper bound for the iterator elements. */ public void setUpperBound(long ub) { upperBound = ub; } /** * Get the upper bound for the iterator. * @return the upper bound for the iterator elements. */ public long getUpperBound() { return upperBound; } /** * Long iterator constructor. */ public LongIterator() { this(false, Long.MAX_VALUE); } /** * Long iterator constructor. * @param nn true for an iterator over non-negative longs, false for all * elements iterator. * @param ub an upper bound for the entries. */ public LongIterator(boolean nn, long ub) { current = 0L; //System.out.println("current = " + current); empty = false; nonNegative = nn; upperBound = ub; //System.out.println("upperBound = " + upperBound); } /** * Test for availability of a next long. * @return true if the iteration has more Longs, else false. */ public synchronized boolean hasNext() { return !empty; } /** * Get next Long. * @return next Long. */ public synchronized Long next() { if (empty) { throw new NoSuchElementException("invalid call of next()"); } Long res = Long.valueOf(current); if (nonNegative) { current++; } else if (current > 0L) { current = -current; } else { current = -current; current++; } if (current > upperBound) { empty = true; } return res; } /** * Remove a tuple if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove elements"); } } java-algebra-system-2.7.200/src/edu/jas/util/MapEntry.java000066400000000000000000000030171445075545500232370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.Map; /** * MapEntry helper class implements Map.Entry. * Required until JDK 1.6 becomes every where available. * @see java.util.AbstractMap.SimpleImmutableEntry in JDK 1.6. * @author Heinz Kredel */ public final class MapEntry implements Map.Entry { final K key; final V value; /** * Constructor. */ public MapEntry(K k, V v) { key = k; value = v; } /** * Get the key. * @see java.util.Map.Entry#getKey() */ public K getKey() { return key; } /** * Get the value. * @see java.util.Map.Entry#getValue() */ public V getValue() { return value; } /** * Set the value. * Is not implemented. * @see java.util.Map.Entry */ public V setValue(V value) { throw new UnsupportedOperationException("not implemented"); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object b) { if (!(b instanceof Map.Entry)) { return false; } Map.Entry me = (Map.Entry) b; return key.equals(me.getKey()) && value.equals(me.getValue()); } /** * Hash code for this MapEntry. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return key.hashCode() * 37 + value.hashCode(); } } java-algebra-system-2.7.200/src/edu/jas/util/PowerSet.java000066400000000000000000000054361445075545500232570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * Power set with iterator. * @author Heinz Kredel */ public class PowerSet implements Iterable> { /** * data structure. */ public final List set; // Iterable also ok /** * PowerSet constructor. * @param set generating set. */ public PowerSet(List set) { this.set = set; } /** * get an iterator over subsets. * @return an iterator. */ public Iterator> iterator() { return new PowerSetIterator(set); } } /** * Power set iterator. * @author Heinz Kredel */ class PowerSetIterator implements Iterator> { /** * data structure. */ public final List set; final List rest; final E current; private PowerSetIterator recIter; enum Mode { copy, extend, first, done }; Mode mode; /** * PowerSetIterator constructor. * @param set generating set. */ public PowerSetIterator(List set) { this.set = set; if (set == null || set.size() == 0) { current = null; recIter = null; rest = null; mode = Mode.first; return; } mode = Mode.copy; current = this.set.get(0); rest = new LinkedList(this.set); rest.remove(0); recIter = new PowerSetIterator(rest); } /** * Test for availability of a next subset. * @return true if the iteration has more subsets, else false. */ public boolean hasNext() { if (mode == Mode.first) { return true; } if (recIter == null) { return false; } return recIter.hasNext() || mode == Mode.copy; } /** * Get next subset. * @return next subset. */ public List next() { if (mode == Mode.first) { mode = Mode.done; List first = new LinkedList(); return first; } if (mode == Mode.extend) { if (recIter.hasNext()) { List next = new LinkedList(recIter.next()); next.add(current); return next; } } if (mode == Mode.copy) { if (recIter.hasNext()) { return recIter.next(); } mode = Mode.extend; recIter = new PowerSetIterator(rest); return this.next(); } return null; } /** * Remove the last subset returned from underlying set if allowed. */ public void remove() { throw new UnsupportedOperationException("cannot remove subsets"); } } java-algebra-system-2.7.200/src/edu/jas/util/RemoteExecutable.java000066400000000000000000000003771445075545500247430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.Serializable; /** * Interface RemoteExecutable. * Used to mark a Serializable and Runnable class. * @author Heinz Kredel */ public interface RemoteExecutable extends Serializable, Runnable { } java-algebra-system-2.7.200/src/edu/jas/util/SocketChannel.java000066400000000000000000000041431445075545500242220ustar00rootroot00000000000000/* * $Id$ */ //package edu.unima.ky.parallel; package edu.jas.util; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.net.Socket; /** * SocketChannel provides a communication channel for Java objects using TCP/IP * sockets. Refactored for java.util.concurrent. * @author Akitoshi Yoshida * @author Heinz Kredel */ public class SocketChannel { /* * Input stream from the socket. */ private final ObjectInputStream in; /* * Output stream to the socket. */ private final ObjectOutputStream out; /* * Underlying socket. */ private final Socket soc; /** * Constructs a socket channel on the given socket s. * @param s A socket object. */ public SocketChannel(Socket s) throws IOException { soc = s; out = new ObjectOutputStream(s.getOutputStream()); out.flush(); in = new ObjectInputStream(s.getInputStream()); } /** * Get the Socket */ public Socket getSocket() { return soc; } /** * Sends an object */ public void send(Object v) throws IOException { synchronized (out) { out.writeObject(v); out.flush(); } } /** * Receives an object */ public Object receive() throws IOException, ClassNotFoundException { Object v = null; synchronized (in) { v = in.readObject(); } return v; } /** * Closes the channel. */ public void close() { if (in != null) { try { in.close(); } catch (IOException e) { } } if (out != null) { try { out.close(); } catch (IOException e) { } } if (soc != null) { try { soc.close(); } catch (IOException e) { } } } /** * to string */ @Override public String toString() { return "socketChannel(" + soc + ")"; } } java-algebra-system-2.7.200/src/edu/jas/util/StrategyEnumeration.java000066400000000000000000000011411445075545500255050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; /** * StrategyEnumeration. This class names possible / implemented strategies for * thread pools. * @author Heinz Kredel */ public final class StrategyEnumeration { public static final StrategyEnumeration FIFO = new StrategyEnumeration(); public static final StrategyEnumeration LIFO = new StrategyEnumeration(); private StrategyEnumeration() { } /** * toString. */ @Override public String toString() { if (this == FIFO) { return "FIFO strategy"; } return "LIFO strategy"; } } java-algebra-system-2.7.200/src/edu/jas/util/TaggedSocketChannel.java000066400000000000000000000312271445075545500253410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; /** * TaggedSocketChannel provides a communication channel with message tags for * Java objects using TCP/IP sockets. * @author Heinz Kredel */ public class TaggedSocketChannel extends Thread { private static final Logger logger = LogManager.getLogger(TaggedSocketChannel.class); private static final boolean debug = logger.isDebugEnabled(); /** * Flag if receiver is running. */ private volatile boolean isRunning = false; /** * End message. */ private final static String DONE = "TaggedSocketChannel Done"; /** * Blocked threads count. */ private final AtomicInteger blockedCount; /** * Underlying socket channel. */ protected final SocketChannel sc; /** * Queues for each message tag. */ protected final Map queues; /** * Constructs a tagged socket channel on the given socket channel s. * @param s A socket channel object. */ public TaggedSocketChannel(SocketChannel s) { sc = s; blockedCount = new AtomicInteger(0); queues = new HashMap(); } /** * thread initialization and start. */ public void init() { synchronized (queues) { if ( ! isRunning ) { this.start(); isRunning = true; } } logger.info("TaggedSocketChannel at {}", sc); } /** * Get the SocketChannel */ public SocketChannel getSocket() { return sc; } /** * Sends an object. * @param tag message tag * @param v object to send * @throws IOException */ public void send(Integer tag, Object v) throws IOException { if (tag == null) { throw new IllegalArgumentException("tag null not allowed"); } if (v instanceof Exception) { throw new IllegalArgumentException("message " + v + " not allowed"); } TaggedMessage tm = new TaggedMessage(tag, v); sc.send(tm); } /** * Receive an object. * @param tag message tag * @return object received * @throws InterruptedException * @throws IOException * @throws ClassNotFoundException */ public Object receive(Integer tag) throws InterruptedException, IOException, ClassNotFoundException { BlockingQueue tq = null; int i = 0; do { synchronized (queues) { tq = queues.get(tag); if (tq == null) { if ( ! isRunning ) { // avoid dead-lock throw new IOException("receiver not running for " + this); } //tq = new LinkedBlockingQueue(); //queues.put(tag, tq); try { logger.debug("receive wait, tag = {}", tag); i = blockedCount.incrementAndGet(); queues.wait(); } catch (InterruptedException e) { logger.info("receive wait exception, tag = {}, blockedCount = {}", tag, i); throw e; } finally { i = blockedCount.decrementAndGet(); } } } } while ( tq == null ); Object v = null; try { i = blockedCount.incrementAndGet(); v = tq.take(); } finally { i = blockedCount.decrementAndGet(); } if ( v instanceof IOException ) { throw (IOException) v; } if ( v instanceof ClassNotFoundException ) { throw (ClassNotFoundException) v; } if ( v instanceof Exception ) { //throw new RuntimeException(v.toString()); throw new IOException(v.toString()); } return v; } /** * Closes the channel. */ public void close() { terminate(); } /** * To string. * @see java.lang.Thread#toString() */ @Override public String toString() { return "socketChannel(" + sc + ", tags = " + queues.keySet() + ")"; //return "socketChannel(" + sc + ", tags = " + queues.keySet() + ", values = " + queues.values() + ")"; } /** * Number of tags. * @return size of key set. */ public int tagSize() { return queues.size(); } /** * Number of messages. * @return sum of all messages in queues. */ public int messages() { int m = 0; synchronized (queues) { for ( BlockingQueue tq : queues.values() ) { m += tq.size(); } } return m; } /** * Run receive() in an infinite loop. * @see java.lang.Thread#run() */ @Override @SuppressWarnings("unchecked") public void run() { if (sc == null) { isRunning = false; return; // nothing to do } isRunning = true; while (isRunning) { try { Object r = null; try { logger.debug("waiting for tagged object"); r = sc.receive(); if (this.isInterrupted()) { //r = new InterruptedException(); isRunning = false; } } catch (IOException e) { r = e; } catch (ClassNotFoundException e) { r = e; } catch (Exception e) { r = e; } //logger.debug("Socket = {}", s); logger.debug("object received"); if (r instanceof TaggedMessage) { TaggedMessage tm = (TaggedMessage) r; BlockingQueue tq = null; synchronized (queues) { tq = queues.get(tm.tag); if (tq == null) { tq = new LinkedBlockingQueue(); queues.put(tm.tag, tq); queues.notifyAll(); } } tq.put(tm.msg); } else if ( r instanceof Exception ){ if (debug) { logger.debug("exception {}", r); } synchronized (queues) { // deliver to all queues isRunning = false; for ( BlockingQueue q : queues.values() ) { final int bc = blockedCount.get(); for ( int i = 0; i <= bc; i++ ) { // one more q.put(r); } if (bc > 0) { logger.debug("put exception to queue, blockedCount = {}", bc); } } queues.notifyAll(); } //return; } else { if (debug) { logger.debug("no tagged message and no exception {}", r); } synchronized (queues) { // deliver to all queues isRunning = false; Exception e; if ( r.equals(DONE) ) { e = new Exception("DONE message"); } else { e = new IllegalArgumentException("no tagged message and no exception '" + r + "'"); } for ( BlockingQueue q : queues.values() ) { final int bc = blockedCount.get(); for ( int i = 0; i <= bc; i++ ) { // one more q.put(e); } if (bc > 0) { logger.debug("put '{}' to queue, blockedCount = {}", e, bc); } } queues.notifyAll(); } if ( r.equals(DONE) ) { logger.info("run terminating by request"); try { sc.send(DONE); // terminate other end } catch (IOException e) { logger.warn("send other done failed {}", e); } return; } } } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); //logger.debug("ChannelFactory IE terminating"); if (debug) { logger.debug("exception {}", e); } synchronized (queues) { // deliver to all queues isRunning = false; for ( BlockingQueue q : queues.values() ) { try { final int bc = blockedCount.get(); for ( int i = 0; i <= bc; i++ ) { // one more q.put(e); } if (bc > 0) { logger.debug("put interrupted to queue, blockCount = {}", bc); } } catch (InterruptedException ignored) { } } queues.notifyAll(); } //return via isRunning } } if (this.isInterrupted()) { Exception e = new InterruptedException("terminating via interrupt"); synchronized (queues) { // deliver to all queues for ( BlockingQueue q : queues.values() ) { try { final int bc = blockedCount.get(); for ( int i = 0; i <= bc; i++ ) { // one more q.put(e); } if (bc > 0) { logger.debug("put terminating via interrupt to queue, blockCount = {}", bc); } } catch (InterruptedException ignored) { } } queues.notifyAll(); } } logger.info("run terminated"); } /** * Terminate the TaggedSocketChannel. */ @SuppressWarnings("unchecked") public void terminate() { isRunning = false; this.interrupt(); if (sc != null) { //sc.close(); try { sc.send(DONE); } catch (IOException e) { logger.warn("send done failed {}", e); } logger.debug("{} not yet closed", sc); } this.interrupt(); synchronized(queues) { isRunning = false; for (Entry tq : queues.entrySet()) { BlockingQueue q = tq.getValue(); if (q.size() != 0) { logger.info("queue for tag {} not empty {}", tq.getKey(), q); } int bc = 0; try { bc = blockedCount.get(); for ( int i = 0; i <= bc; i++ ) { // one more q.put(new IOException("queue terminate")); } } catch (InterruptedException ignored) { } if ( bc > 0 ) { logger.debug("put IO-end to queue for tag {}, blockCount = {}", tq.getKey(), bc); } } queues.notifyAll(); } try { this.join(); } catch (InterruptedException e) { // unfug Thread.currentThread().interrupt(); } logger.info("terminated"); } } /** * TaggedMessage container. */ class TaggedMessage implements Serializable { public final Integer tag; public final Object msg; /** * Constructor. * @param tag message tag * @param msg message object */ public TaggedMessage(Integer tag, Object msg) { this.tag = tag; this.msg = msg; } } java-algebra-system-2.7.200/src/edu/jas/util/Terminator.java000066400000000000000000000066201445075545500236270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.concurrent.Semaphore; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; //import edu.unima.ky.parallel.Semaphore; /** * Terminating helper class. Like a barrier, but with coming and going. * @author Heinz Kredel */ public class Terminator { private static final Logger logger = LogManager.getLogger(Terminator.class); private final int workers; private int idler; private final Semaphore fin; private boolean done; // volatile not required since synchronized /** * Terminator. * @param workers number of expected threads. */ public Terminator(int workers) { this.workers = workers; fin = new Semaphore(0); done = false; idler = 0; logger.info("constructor, workers = {}", workers); } /** * to string */ @Override public String toString() { return "Terminator(" + done + ",workers=" + workers + ",idler=" + idler + ")"; } /** * beIdle. * Checks for release(). */ public synchronized void beIdle() { idler++; logger.info("beIdle, idler = {}", idler); if (idler >= workers) { done = true; fin.release(); //fin.V(); } } /** * initIdle. * No check for release(). * @param i number of idle threads. */ public synchronized void initIdle(int i) { idler += i; logger.info("initIdle, idler = {}", idler); if ( idler > workers ) { if (done) { idler = workers; } else { throw new RuntimeException("idler > workers: " + idler + " > " + workers); } } } /** * beIdle. * Checks for release(). * @param i number of idle threads. */ public synchronized void beIdle(int i) { idler += i; logger.info("beIdle, idler = {}", idler); if (idler >= workers) { done = true; fin.release(); //fin.V(); } } /** * allIdle. * Checks for release(). */ public synchronized void allIdle() { idler = workers; logger.info("allIdle"); done = true; fin.release(); //fin.V(); } /** * notIdle. */ public synchronized void notIdle() { idler--; logger.info("notIdle, idler = {}", idler); if ( idler < 0 ) { throw new RuntimeException("idler < 0"); } } /** * getJobs. * @return number of possible jobs. */ public synchronized int getJobs() { return (workers - idler); } /** * hasJobs. * @return true, if there are possibly jobs, else false. */ public synchronized boolean hasJobs() { return (idler < workers); } /** * Release if possible. */ public synchronized void release() { logger.info("release = {}", this); if ( idler >= workers ) { done = true; fin.release(); } //logger.info("release, idler = {}", idler); } /** * Wait until released. */ public void waitDone() { try { fin.acquire(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } logger.info("waitDone {}", this); } } java-algebra-system-2.7.200/src/edu/jas/util/ThreadPool.java000066400000000000000000000230201445075545500235350ustar00rootroot00000000000000/* * $Id$ */ // package edu.unima.ky.parallel; package edu.jas.util; import java.util.LinkedList; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.kern.PreemptingException; /** * Thread pool using stack / list workpile. * @author Akitoshi Yoshida * @author Heinz Kredel */ public class ThreadPool { /** * Default number of threads to use. */ static final int DEFAULT_SIZE = 3; /** * Number of threads to use. */ final int size; /** * Array of workers. */ protected PoolThread[] workers; /** * Number of idle workers. */ protected int idleworkers = 0; /** * Shutdown request. */ protected volatile boolean shutdown = false; /** * Work queue / stack. */ // should be expressed using strategy pattern // List or Collection is not appropriate // LIFO strategy for recursion protected LinkedList jobstack; // FIFO strategy for GB protected StrategyEnumeration strategy = StrategyEnumeration.LIFO; private static final Logger logger = LogManager.getLogger(ThreadPool.class); private static final boolean debug = logger.isDebugEnabled(); /** * Constructs a new ThreadPool with strategy StrategyEnumeration.FIFO and * size DEFAULT_SIZE. */ public ThreadPool() { this(StrategyEnumeration.FIFO, DEFAULT_SIZE); } /** * Constructs a new ThreadPool with size DEFAULT_SIZE. * @param strategy for job processing. */ public ThreadPool(StrategyEnumeration strategy) { this(strategy, DEFAULT_SIZE); } /** * Constructs a new ThreadPool with strategy StrategyEnumeration.FIFO. * @param size of the pool. */ public ThreadPool(int size) { this(StrategyEnumeration.FIFO, size); } /** * Constructs a new ThreadPool. * @param strategy for job processing. * @param size of the pool. */ public ThreadPool(StrategyEnumeration strategy, int size) { this.size = size; this.strategy = strategy; jobstack = new LinkedList(); // ok for all strategies ? workers = new PoolThread[0]; } /** * thread initialization and start. */ public void init() { if (workers == null || workers.length == 0) { workers = new PoolThread[size]; for (int i = 0; i < workers.length; i++) { workers[i] = new PoolThread(this); workers[i].start(); } logger.info("size = {}, strategy = {}", size, strategy); } if (debug) { Thread.dumpStack(); } } /** * toString. */ @Override public String toString() { return "ThreadPool( size=" + getNumber() + ", idle=" + idleworkers + ", " + getStrategy() + ", jobs=" + jobstack.size() + ")"; } /** * number of worker threads. */ public int getNumber() { return size; //if (workers == null || workers.length < size) { // init(); // start threads //} //return workers.length; // not null } /** * get used strategy. */ public StrategyEnumeration getStrategy() { return strategy; } /** * Terminates the threads. */ public void terminate() { while (hasJobs()) { try { Thread.sleep(100); //logger.info("waiting for termination in {}", this); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } if (workers == null) { return; } for (int i = 0; i < workers.length; i++) { if (workers[i] == null) { continue; } try { while (workers[i].isAlive()) { workers[i].interrupt(); workers[i].join(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } /** * Cancels the threads. */ public int cancel() { shutdown = true; int s = jobstack.size(); if (hasJobs()) { synchronized (this) { logger.info("jobs canceled: {}", jobstack); jobstack.clear(); notifyAll(); // for getJob } } //int re = 0; if (workers == null) { return s; } for (int i = 0; i < workers.length; i++) { if (workers[i] == null) { continue; } try { while (workers[i].isAlive()) { synchronized (this) { shutdown = true; notifyAll(); // for getJob workers[i].interrupt(); } //re++; //if ( re > 3 * workers.length ) { // logger.info("give up on: {}", workers[i]); // break; // give up //} workers[i].join(100); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return s; } /** * adds a job to the workpile. * @param job */ public synchronized void addJob(Runnable job) { if (workers == null || workers.length < size) { init(); // start threads } jobstack.addLast(job); logger.debug("adding job"); if (idleworkers > 0) { logger.debug("notifying a jobless worker"); notifyAll(); } } /** * get a job for processing. */ protected synchronized Runnable getJob() throws InterruptedException { while (jobstack.isEmpty()) { idleworkers++; logger.debug("waiting"); wait(1000); idleworkers--; if (shutdown) { throw new InterruptedException("shutdown in getJob"); } } // is expressed using strategy enumeration if (strategy == StrategyEnumeration.LIFO) { return jobstack.removeLast(); // LIFO } return jobstack.removeFirst(); // FIFO } /** * check if there are jobs for processing. */ public boolean hasJobs() { if (jobstack.size() > 0) { return true; } for (int i = 0; i < workers.length; i++) { if (workers[i] == null) { continue; } if (workers[i].isWorking) { return true; } } return false; } /** * check if there are more than n jobs for processing. * @param n Integer * @return true, if there are possibly more than n jobs. */ public boolean hasJobs(int n) { int j = jobstack.size(); if (j > 0 && (j + workers.length > n)) { return true; } // if j > 0 no worker should be idle // ( ( j > 0 && ( j+workers.length > n ) ) || ( j > n ) int x = 0; for (int i = 0; i < workers.length; i++) { if (workers[i] == null) { continue; } if (workers[i].isWorking) { x++; } } if ((j + x) > n) { return true; } return false; } } /** * Implements one Thread of the pool. */ class PoolThread extends Thread { ThreadPool pool; private static final Logger logger = LogManager.getLogger(PoolThread.class); private static final boolean debug = logger.isDebugEnabled(); volatile boolean isWorking = false; /** * @param pool ThreadPool. */ public PoolThread(ThreadPool pool) { this.pool = pool; } /** * Run the thread. */ @Override public void run() { logger.info("ready"); Runnable job; int done = 0; long time = 0; long t; boolean running = true; while (running) { try { logger.debug("looking for a job"); job = pool.getJob(); if (job == null) { break; } if (debug) { logger.info("working"); } t = System.currentTimeMillis(); isWorking = true; job.run(); isWorking = false; time += System.currentTimeMillis() - t; done++; if (debug) { logger.info("done"); } if (Thread.currentThread().isInterrupted()) { running = false; isWorking = false; //throw new RuntimeException("interrupt in while(running) loop"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); running = false; isWorking = false; } catch (PreemptingException e) { logger.debug("caught {}", e); //e.printStackTrace(); } catch (RuntimeException e) { logger.warn("caught {}", e); e.printStackTrace(); } } isWorking = false; logger.info("terminated, done {} jobs in {} milliseconds", done, time); } } java-algebra-system-2.7.200/src/edu/jas/util/machines000066400000000000000000000003571445075545500223530ustar00rootroot00000000000000# maschines file for jas 10.1.1.254:7114 # first host is master 10.1.1.254:8114 # first client host, master-port+1000 10.1.1.254:8114 # second host with port #localhost:7411 # next host with port #localhost:7411 # last host # eof java-algebra-system-2.7.200/src/edu/jas/util/machines.localhost000066400000000000000000000003601445075545500243340ustar00rootroot00000000000000# maschines file for jas localhost:7114 # first host is master localhost:8114 # first client host, master-port+1000 #localhost:9114 # second host with port #localhost:8411 # next host with port #localhost:8411 # last host # eof java-algebra-system-2.7.200/src/edu/jas/util/package.html000066400000000000000000000014301445075545500231130ustar00rootroot00000000000000 Concurrent programming utility classes

Concurrent programming utility classes.

This package contains further utilities for parallel and distributed computations like ThreadPool, DistThreadPool or DistHashTable.


Heinz Kredel

Last modified: Mon Jul 9 22:45:40 CEST 2007

$Id$

java-algebra-system-2.7.200/src/edu/jas/vector/000077500000000000000000000000001445075545500211615ustar00rootroot00000000000000java-algebra-system-2.7.200/src/edu/jas/vector/BasicLinAlg.java000066400000000000000000000317551445075545500241470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.RingElem; /** * Basic linear algebra methods. Implements Basic linear algebra computations * and tests. Note: will eventually use wrong method dispatch in JRE when * used with GenSolvablePolynomial. * @param coefficient type * @author Heinz Kredel */ public class BasicLinAlg> implements Serializable { private static final Logger logger = LogManager.getLogger(BasicLinAlg.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public BasicLinAlg() { } /** * Scalar product of vectors of ring elements. * @param G a ring element list. * @param F a ring element list. * @return the scalar product of G and F. */ public C scalarProduct(List G, List F) { C sp = null; Iterator it = G.iterator(); Iterator jt = F.iterator(); while (it.hasNext() && jt.hasNext()) { C pi = it.next(); C pj = jt.next(); if (pi == null || pj == null) { continue; } if (sp == null) { sp = pi.multiply(pj); } else { sp = sp.sum(pi.multiply(pj)); } } if (it.hasNext() || jt.hasNext()) { logger.error("scalarProduct wrong sizes"); } return sp; } /** * Scalar product of vectors and a matrix of ring elements. * @param G a ring element list. * @param F a list of ring element lists. * @return the scalar product of G and F. */ public List leftScalarProduct(List G, List> F) { List sp = null; //new ArrayList(G.size()); Iterator it = G.iterator(); Iterator> jt = F.iterator(); while (it.hasNext() && jt.hasNext()) { C pi = it.next(); List pj = jt.next(); if (pi == null || pj == null) { continue; } List s = scalarProduct(pi, pj); if (sp == null) { sp = s; } else { sp = vectorAdd(sp, s); } } if (it.hasNext() || jt.hasNext()) { logger.error("scalarProduct wrong sizes"); } return sp; } /** * Scalar product of vectors and a matrix of ring elements. * @param G a ring element list. * @param F a list of ring element lists. * @return the right scalar product of G and F. */ public List rightScalarProduct(List G, List> F) { List sp = null; //new ArrayList(G.size()); Iterator it = G.iterator(); Iterator> jt = F.iterator(); while (it.hasNext() && jt.hasNext()) { C pi = it.next(); List pj = jt.next(); if (pi == null || pj == null) { continue; } List s = scalarProduct(pj, pi); if (sp == null) { sp = s; } else { sp = vectorAdd(sp, s); } } if (it.hasNext() || jt.hasNext()) { logger.error("scalarProduct wrong sizes"); } return sp; } /** * Addition of vectors of ring elements. * @param a a ring element list. * @param b a ring element list. * @return a+b, the vector sum of a and b. */ public List vectorAdd(List a, List b) { if (a == null) { return b; } if (b == null) { return a; } List V = new ArrayList(a.size()); Iterator it = a.iterator(); Iterator jt = b.iterator(); while (it.hasNext() && jt.hasNext()) { C pi = it.next(); C pj = jt.next(); C p = pi.sum(pj); V.add(p); } //System.out.println("vectorAdd" + V); if (it.hasNext() || jt.hasNext()) { logger.error("vectorAdd wrong sizes"); } return V; } /** * Negative of vectors of ring elements. * @param a a ring element list. * @return -a, the vector of -a. */ public List vectorNegate(List a) { if (a == null) { return a; } List V = new ArrayList(a.size()); Iterator it = a.iterator(); while (it.hasNext()) { C pi = it.next(); if (pi != null) { pi = pi.negate(); } V.add(pi); } //System.out.println("vectorNegate" + V); return V; } /** * Combination of vectors for reduction representation. * @param a a ring element list. * @param b a ring element list. * @return a-b, the vector difference of a and b, with one entry more. */ public List vectorCombineRep(List a, List b) { if (a == null || b == null) { throw new IllegalArgumentException("a and b may not be empty"); } // if (a.size() != b.size()) { // throw new IllegalArgumentException("#a != #b"); // } List V = new ArrayList(a.size() + 1); Iterator it = a.iterator(); Iterator jt = b.iterator(); while (it.hasNext() && jt.hasNext()) { C x = it.next(); C y = jt.next(); if (x == null) { if (y == null) { //x = y; } else { x = y.negate(); } } else { if (y == null) { //x = y; } else { x = x.subtract(y); } } V.add(x); } if (it.hasNext() || jt.hasNext()) { logger.error("vectorCombineRep wrong sizes: it = {}, jt = {}", it, jt); //throw new RuntimeException("it = " + it + ", jt = " + jt); } V.add(null); //System.out.println("vectorCombineRep" + V); return V; } /** * Combination of vectors for syzygy representation. * @param a a ring element list. * @param b a ring element list. * @return (-a)+b, the vector sum of -a and b, with one entry more. */ public List vectorCombineSyz(List a, List b) { if (a == null || b == null) { throw new IllegalArgumentException("a and b may not be empty"); } // if (a.size() != b.size()) { // throw new IllegalArgumentException("#a != #b"); // } List V = new ArrayList(a.size() + 1); Iterator it = a.iterator(); Iterator jt = b.iterator(); while (it.hasNext() && jt.hasNext()) { C x = it.next(); C y = jt.next(); if (x == null) { if (y == null) { //x = y; } else { x = y; } } else { if (y == null) { //x = y; } else { x = x.sum(y); } } V.add(x); } if (it.hasNext() || jt.hasNext()) { logger.error("vectorCombineSyz wrong sizes: it = {}, jt = {}", it, jt); //throw new RuntimeException("it = " + it + ", jt = " + jt); } V.add(null); //System.out.println("vectorCombineSyz" + V); return V; } /** * Combination of vectors for old representation. * @param a a ring element list. * @param b a ring element list. * @return -a-b, the vector difference of -a and b, with one entry more. */ public List vectorCombineOld(List a, List b) { if (a == null || b == null) { throw new IllegalArgumentException("a and b may not be empty"); } // if (a.size() != b.size()) { // throw new IllegalArgumentException("#a != #b"); // } List V = new ArrayList(a.size() + 1); Iterator it = a.iterator(); Iterator jt = b.iterator(); while (it.hasNext() && jt.hasNext()) { C x = it.next(); C y = jt.next(); if (x != null) { //System.out.println("ms = " + m + " " + x); x = x.negate(); } if (y != null) { y = y.negate(); //System.out.println("mh = " + m + " " + y); } if (x == null) { x = y; } else if (y != null) { x = x.sum(y); } //System.out.println("mx = " + m + " " + x); V.add(x); } if (it.hasNext() || jt.hasNext()) { logger.error("vectorCombineOld wrong sizes: it = {}, jt = {}", it, jt); //throw new RuntimeException("it = " + it + ", jt = " + jt); } V.add(null); //System.out.println("vectorCombineOld" + V); return V; } /** * Generation of a vector of ring elements. * @param n length of vector. * @param a a ring element to fill vector entries. * @return V, a vector of length n and entries a. */ public List genVector(int n, C a) { List V = new ArrayList(n); if (n == 0) { return V; } for (int i = 0; i < n; i++) { V.add(a); } return V; } /** * Generation of a vector of ring elements. * @param n length of vector. * @param a a ring element to fill vector entries. * @param A vector of starting first entries. * @return V, a vector of length n and entries a, respectively A. */ public List genVector(int n, C a, List A) { List V = new ArrayList(n); if (n == 0) { return V; } int i = 0; for (C b : A) { if (i < n) { V.add(b); } else { break; } i++; } for (int j = A.size(); j < n; j++) { V.add(a); } return V; } /** * Test vector of zero ring elements. * @param a a ring element list. * @return true, if all polynomial in a are zero, else false. */ public boolean isZero(List a) { if (a == null) { return true; } for (C pi : a) { if (pi == null) { continue; } if (!pi.isZERO()) { return false; } } return true; } /** * Scalar product of ring element with vector of ring elements. * @param p a ring element. * @param F a ring element list. * @return the scalar product of p and F. */ public List scalarProduct(C p, List F) { List V = new ArrayList(F.size()); for (C pi : F) { if (p != null) { pi = p.multiply(pi); } else { pi = null; } V.add(pi); } return V; } /** * Scalar product of vector of ring element with ring element. * @param F a ring element list. * @param p a ring element. * @return the scalar product of F and p. */ public List scalarProduct(List F, C p) { List V = new ArrayList(F.size()); for (C pi : F) { if (pi != null) { pi = pi.multiply(p); } V.add(pi); } return V; } /** * Product of a vector and a matrix of ring elements. * @param G a vectors of ring elements. * @param F a matrix of ring element lists. * @return the left product of G and F. */ public GenVector leftProduct(GenVector G, GenMatrix F) { ArrayList sp = new ArrayList(G.val.size()); Iterator> jt = F.matrix.iterator(); while (jt.hasNext()) { ArrayList pj = jt.next(); if (pj == null) { continue; } C s = scalarProduct(G.val, pj); sp.add(s); } return new GenVector(G.modul, sp); } /** * Product of a vector and a matrix of ring elements. * @param G a vector of element list. * @param F a matrix of ring element lists. * @return the right product of G and F. */ public GenVector rightProduct(GenVector G, GenMatrix F) { ArrayList sp = new ArrayList(G.val.size()); Iterator> jt = F.matrix.iterator(); while (jt.hasNext()) { ArrayList pj = jt.next(); if (pj == null) { continue; } C s = scalarProduct(pj, G.val); sp.add(s); } return new GenVector(G.modul, sp); } } java-algebra-system-2.7.200/src/edu/jas/vector/Examples.java000066400000000000000000000051651445075545500236110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; // import edu.jas.arith.ModInteger; /** * Examples for basic linear algebra. * @author Heinz Kredel */ public class Examples { /** * main. */ public static void main(String[] args) { example1(); example2(); example3(); // ComputerThreads.terminate(); } /** * example1. */ public static void example1() { System.out.println("\n\n example 1"); BigInteger cfac; GenMatrixRing mfac; cfac = new BigInteger(); System.out.println("cfac = " + cfac); mfac = new GenMatrixRing(cfac, 5, 5); System.out.println("mfac = " + mfac); GenMatrix m; m = mfac.random(3, 0.4f); System.out.println("\nm = " + m); m = m.multiply(m); System.out.println("\nm = " + m); } /** * example2. */ public static void example2() { System.out.println("\n\n example 2"); BigRational cfac; GenMatrixRing mfac; cfac = new BigRational(); System.out.println("cfac = " + cfac); mfac = new GenMatrixRing(cfac, 5, 5); System.out.println("mfac = " + mfac); GenMatrix m; m = mfac.random(3, 0.4f); System.out.println("\nm = " + m); m = m.multiply(m); System.out.println("\nm = " + m); } public static void example3() { System.out.println("\n\n example 3"); BigRational r1, r2, r3, r4, r5, r6, fac; r1 = new BigRational(1, 10); r2 = new BigRational(6, 5); r3 = new BigRational(1, 9); r4 = new BigRational(1, 1); r5 = r2.sum(r3); r6 = r1.multiply(r4); fac = new BigRational(); BigRational[][] aa = new BigRational[][] { { r1, r2, r3 }, { r4, r5, r6 }, { r2, r1, r3 } }; GenMatrixRing mfac = new GenMatrixRing(fac, aa.length, aa[0].length); GenMatrix a = new GenMatrix(mfac, aa); System.out.println("system = " + a); BigRational[] ba = new BigRational[] { r1, r2, r3 }; GenVectorModul vfac = new GenVectorModul(fac, ba.length); GenVector b = new GenVector(vfac, ba); System.out.println("right hand side = " + b); LinAlg lu = new LinAlg(); GenVector x = lu.solve(a, b); System.out.println("solution = " + x); } } java-algebra-system-2.7.200/src/edu/jas/vector/GenMatrix.java000066400000000000000000000657531445075545500237420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.AlgebraElem; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.RingElem; /** * GenMatrix implements a generic matrix algebra over RingElem entries. Matrix * has n columns and m rows over C. * @author Heinz Kredel */ public class GenMatrix> implements AlgebraElem, C> { private static final Logger logger = LogManager.getLogger(GenMatrix.class); public final GenMatrixRing ring; public final ArrayList> matrix; private int hashValue = 0; /** * Constructor for zero GenMatrix. * @param r matrix ring */ public GenMatrix(GenMatrixRing r) { this(r, r.getZERO().matrix); } /** * Constructor for GenMatrix. * @param r matrix ring * @param m matrix */ public GenMatrix(GenMatrixRing r, List> m) { ring = r; matrix = new ArrayList>(r.rows); for (List row : m) { ArrayList nr = new ArrayList(row); matrix.add(nr); } logger.info("{} x {} matrix constructed", ring.rows, ring.cols); } /** * Constructor for GenMatrix. * @param r matrix ring * @param m matrix */ public GenMatrix(GenMatrixRing r, ArrayList> m) { if (r == null || m == null) { throw new IllegalArgumentException("Empty r or m not allowed, r = " + r + ", m = " + m); } ring = r; matrix = new ArrayList>(m); logger.info("{} x {} matrix constructed", ring.rows, ring.cols); } /** * Constructor for GenMatrix. * @param r matrix ring * @param m matrix */ public GenMatrix(GenMatrixRing r, C[][] m) { ring = r; matrix = new ArrayList>(r.rows); for (C[] row : m) { ArrayList nr = new ArrayList(r.cols); for (int i = 0; i < row.length; i++) { nr.add(row[i]); } matrix.add(nr); } logger.info("{} x {} matrix constructed", ring.rows, ring.cols); } /** * Get element at row i, column j. * @param i row index. * @param j column index. * @return this(i,j). */ public C get(int i, int j) { return matrix.get(i).get(j); } /** * Set element at row i, column j. Mutates this matrix. * @param i row index. * @param j column index. * @param el element to set. */ public void setMutate(int i, int j, C el) { ArrayList ri = matrix.get(i); ri.set(j, el); hashValue = 0; // invalidate } /** * Set element at row i, column j. * @param i row index. * @param j column index. * @param el element to set. * @return new matrix m, with m(i,j) == el. */ public GenMatrix set(int i, int j, C el) { GenMatrix mat = this.copy(); mat.setMutate(i, j, el); return mat; } /** * Get column i. * @param i column index. * @return this(*,i) as vector. */ public GenVector getColumn(int i) { List cl = new ArrayList(ring.rows); for (int k = 0; k < ring.rows; k++) { cl.add(matrix.get(k).get(i)); } GenVectorModul vfac = new GenVectorModul(ring.coFac, ring.rows); GenVector col = new GenVector(vfac, cl); return col; } /** * Get row i. * @param i row index. * @return this(i,*) as vector. */ public GenVector getRow(int i) { List cl = new ArrayList(ring.cols); cl.addAll(matrix.get(i)); GenVectorModul vfac = new GenVectorModul(ring.coFac, ring.cols); GenVector row = new GenVector(vfac, cl); return row; } /** * Get diagonal. * @return diagonal(this) as vector. */ public GenVector getDiagonal() { List cl = new ArrayList(ring.rows); for (int i = 0; i < ring.rows; i++) { cl.add(matrix.get(i).get(i)); } GenVectorModul vfac = new GenVectorModul(ring.coFac, ring.rows); GenVector dia = new GenVector(vfac, cl); return dia; } /** * Trace. * @return sum of diagonal elements. */ public C trace() { C cl = ring.coFac.getZERO(); for (int i = 0; i < ring.rows; i++) { cl = cl.sum(matrix.get(i).get(i)); } return cl; } /** * Get upper triangular U matrix. * @return U as matrix with equal length rows. */ public GenMatrix getUpper() { final C zero = ring.coFac.getZERO(); final C one = ring.coFac.getONE(); List> cl = new ArrayList>(ring.rows); for (int k = 0; k < ring.rows; k++) { List ul = matrix.get(k); List rl = new ArrayList(ring.cols); for (int i = 0; i < ring.cols; i++) { if (i < k) { rl.add(zero); } else if (i >= k) { rl.add(ul.get(i)); // } else { // if (ul.get(i).isZERO()) { // rl.add(zero); // } else { // rl.add(one); // mat(k,k).inverse() // } } } cl.add(rl); } GenMatrix U = new GenMatrix(ring, cl); return U; } /** * Get upper triangular U matrix with diagonal 1. * @return U as matrix with equal length rows and diagonal 1. */ public GenMatrix getUpperScaled() { final C zero = ring.coFac.getZERO(); final C one = ring.coFac.getONE(); List> cl = new ArrayList>(ring.rows); for (int k = 0; k < ring.rows; k++) { List ul = matrix.get(k); C kk = ul.get(k); if (kk.isZERO()) { kk = one; } else { kk = kk.inverse(); } List rl = new ArrayList(ring.cols); for (int i = 0; i < ring.cols; i++) { if (i < k) { rl.add(zero); } else { // if (i >= k) rl.add( ul.get(i).multiply(kk) ); } } cl.add(rl); } GenMatrix U = new GenMatrix(ring, cl); return U; } /** * Get lower triangular L matrix. * @return L as matrix with equal length rows. */ public GenMatrix getLower() { final C zero = ring.coFac.getZERO(); List> cl = new ArrayList>(ring.rows); for (int k = 0; k < ring.rows; k++) { List ul = matrix.get(k); List rl = new ArrayList(ring.cols); for (int i = 0; i < ring.cols; i++) { if (i <= k) { rl.add(ul.get(i)); // can be zero } else if (i > k) { rl.add(zero); } } cl.add(rl); } GenMatrix L = new GenMatrix(ring, cl); return L; } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); boolean firstRow = true; s.append("[\n"); for (List val : matrix) { if (firstRow) { firstRow = false; } else { s.append(",\n"); } boolean first = true; s.append("[ "); for (C c : val) { if (first) { first = false; } else { s.append(", "); } s.append(c.toString()); } s.append(" ]"); } s.append(" ] "); if (!PrettyPrint.isTrue()) { s.append(":: " + ring.toString()); s.append("\n"); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer(); boolean firstRow = true; s.append("( "); for (List val : matrix) { if (firstRow) { firstRow = false; } else { s.append(", "); } boolean first = true; s.append("( "); for (C c : val) { if (first) { first = false; } else { s.append(", "); } s.append(c.toScript()); } s.append(" )"); } s.append(" ) "); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public GenMatrixRing factory() { return ring; } /** * Copy method. * @see edu.jas.structure.Element#copy() */ @Override public GenMatrix copy() { //return ring.copy(this); ArrayList> m = new ArrayList>(ring.rows); ArrayList v; for (ArrayList val : matrix) { v = new ArrayList(val); m.add(v); } return new GenMatrix(ring, m); } /** * Stack method. * @param st stacked matrix ring. * @param b other matrix. * @return stacked matrix, this on top of other. */ public GenMatrix stack(GenMatrixRing st, GenMatrix b) { ArrayList> m = new ArrayList>(st.rows); ArrayList v; for (ArrayList val : matrix) { v = new ArrayList(val); m.add(v); } for (ArrayList val : b.matrix) { v = new ArrayList(val); m.add(v); } return new GenMatrix(st, m); } /** * Concat method. * @param cc concated matrix ring. * @param b other matrix. * @return concated matrix, this before of other. */ public GenMatrix concat(GenMatrixRing cc, GenMatrix b) { ArrayList> m = new ArrayList>(cc.rows); ArrayList> bm = b.matrix; ArrayList v, o; int i = 0; for (ArrayList val : matrix) { v = new ArrayList(val); o = bm.get(i++); v.addAll(o); m.add(v); } return new GenMatrix(cc, m); } /** * Test if this is equal to a zero matrix. */ public boolean isZERO() { for (List row : matrix) { for (C elem : row) { if (!elem.isZERO()) { return false; } } } return true; } /** * Test if this is one. * @return true if this is 1, else false. */ public boolean isONE() { int i = 0; for (List row : matrix) { int j = 0; for (C elem : row) { if (i == j) { if (!elem.isONE()) { //System.out.println("elem.isONE = " + elem); return false; } } else if (!elem.isZERO()) { //System.out.println("elem.isZERO = " + elem); return false; } j++; } i++; } return true; } /** * Test if this is a non-zero diagonal matrix. * @return true if this is non-zero diagonal, else false. */ public boolean isDiagonal() { int z = 0; int i = 0; for (List row : matrix) { int j = 0; for (C elem : row) { if (i == j) { if (!elem.isZERO()) { z++; } } else if (!elem.isZERO()) { //System.out.println("elem.isZERO = " + elem); return false; } j++; } i++; } if (z == 0) { // matrix is zero return false; } return true; } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (!(other instanceof GenMatrix)) { return false; } GenMatrix om = (GenMatrix) other; if (!ring.equals(om.ring)) { return false; } if (!matrix.equals(om.matrix)) { return false; } return true; } /** * Hash code for this GenMatrix. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { if (hashValue == 0) { hashValue = 37 * matrix.hashCode() + ring.hashCode(); if (hashValue == 0) { hashValue = 1; } } return hashValue; } /** * compareTo, lexicogaphical comparison. * @param b other * @return 1 if (this < b), 0 if (this == b) or -1 if (this > b). */ @Override public int compareTo(GenMatrix b) { if (!ring.equals(b.ring)) { return -1; } ArrayList> om = b.matrix; int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); int j = 0; for (C c : val) { int s = c.compareTo(ov.get(j++)); if (s != 0) { return s; } } } return 0; } /** * Test if this is a unit. I.e. there exists x with this.multiply(x).isONE() * == true. Tests if matrix is not singular. * Was previously a test if all diagonal elements are units and all other * elements are zero. * @return true if this is a unit, else false. */ public boolean isUnit() { LinAlg la = new LinAlg(); GenMatrix mat = this.copy(); List P = la.decompositionLU(mat); if (P == null || P.isEmpty()) { return false; } return true; } /** * sign of matrix. * @return 1 if (this < 0), 0 if (this == 0) or -1 if (this > 0). */ public int signum() { return compareTo(ring.getZERO()); } /** * Sum of matrices. * @param b other matrix. * @return this+b */ public GenMatrix sum(GenMatrix b) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C e = c.sum(ov.get(j++)); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Difference of matrices. * @param b other matrix. * @return this-b */ public GenMatrix subtract(GenMatrix b) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C e = c.subtract(ov.get(j++)); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Negative of this matrix. * @return -this */ public GenMatrix negate() { ArrayList> m = new ArrayList>(ring.rows); //int i = 0; for (ArrayList val : matrix) { ArrayList v = new ArrayList(ring.cols); for (C c : val) { C e = c.negate(); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Absolute value of this matrix. * @return abs(this) */ public GenMatrix abs() { if (signum() < 0) { return negate(); } return this; } /** * Product of this matrix with scalar. * @param s scalar. * @return this*s */ public GenMatrix multiply(C s) { return scalarMultiply(s); } /** * Product of this matrix with scalar. * @param s scalar * @return this*s */ public GenMatrix scalarMultiply(C s) { ArrayList> m = new ArrayList>(ring.rows); //int i = 0; for (ArrayList val : matrix) { ArrayList v = new ArrayList(ring.cols); for (C c : val) { C e = c.multiply(s); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Left product of this matrix with scalar. * @param s scalar * @return s*this */ public GenMatrix leftScalarMultiply(C s) { ArrayList> m = new ArrayList>(ring.rows); //int i = 0; for (ArrayList val : matrix) { ArrayList v = new ArrayList(ring.cols); for (C c : val) { C e = s.multiply(c); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Linear compination of this matrix with scalar multiple of other matrix. * @param s scalar * @param t scalar * @param b other matrix. * @return this*s+b*t */ public GenMatrix linearCombination(C s, GenMatrix b, C t) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C c1 = c.multiply(s); C c2 = ov.get(j++).multiply(t); C e = c1.sum(c2); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Linear combination of this matrix with scalar multiple of other matrix. * @param t scalar * @param b other matrix. * @return this+b*t */ public GenMatrix linearCombination(GenMatrix b, C t) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C c2 = ov.get(j++).multiply(t); C e = c.sum(c2); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Left linear combination of this matrix with scalar multiple of other * matrix. * @param t scalar * @param b other matrix. * @return this+t*b */ public GenMatrix linearCombination(C t, GenMatrix b) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C c2 = t.multiply(ov.get(j++)); C e = c.sum(c2); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * left linear compination of this matrix with scalar multiple of other * matrix. * @param s scalar * @param t scalar * @param b other matrix. * @return s*this+t*b */ public GenMatrix leftLinearCombination(C s, C t, GenMatrix b) { ArrayList> om = b.matrix; ArrayList> m = new ArrayList>(ring.rows); int i = 0; for (ArrayList val : matrix) { ArrayList ov = om.get(i++); ArrayList v = new ArrayList(ring.cols); int j = 0; for (C c : val) { C c1 = s.multiply(c); C c2 = t.multiply(ov.get(j++)); C e = c1.sum(c2); v.add(e); } m.add(v); } return new GenMatrix(ring, m); } /** * Transposed matrix. * @param tr transposed matrix ring. * @return transpose(this) */ public GenMatrix transpose(GenMatrixRing tr) { GenMatrix t = tr.getZERO().copy(); ArrayList> m = t.matrix; int i = 0; for (ArrayList val : matrix) { int j = 0; for (C c : val) { (m.get(j)).set(i, c); //A[j,i] = A[i,j] j++; } i++; } // return new GenMatrix(tr,m); return t; } /** * Transposed matrix. * @return transpose(this) */ public GenMatrix transpose() { GenMatrixRing tr = ring.transpose(); return transpose(tr); } /** * Multiply this with S. * @param S other matrix. * @return this * S. */ public GenMatrix multiply(GenMatrix S) { int na = ring.blocksize; int nb = ring.blocksize; //System.out.println("#blocks = " + (matrix.size()/na) + ", na = " + na // + " SeqMultBlockTrans"); ArrayList> m = matrix; //ArrayList> s = S.matrix; GenMatrixRing tr = S.ring.transpose(); GenMatrix T = S.transpose(tr); ArrayList> t = T.matrix; //System.out.println("T = " + T); GenMatrixRing pr = ring.product(S.ring); GenMatrix P = pr.getZERO().copy(); ArrayList> p = P.matrix; //System.out.println("P = " + P); for (int ii = 0; ii < m.size(); ii += na) { for (int jj = 0; jj < t.size(); jj += nb) { for (int i = ii; i < Math.min((ii + na), m.size()); i++) { ArrayList Ai = m.get(i); //A[i]; for (int j = jj; j < Math.min((jj + nb), t.size()); j++) { ArrayList Bj = t.get(j); //B[j]; C c = ring.coFac.getZERO(); for (int k = 0; k < Bj.size(); k++) { c = c.sum(Ai.get(k).multiply(Bj.get(k))); // c += Ai[k] * Bj[k]; } (p.get(i)).set(j, c); // C[i][j] = c; } } } } return new GenMatrix(pr, p); } /** * Multiply this with S. Simple unblocked algorithm. * @param S other matrix. * @return this * S. */ public GenMatrix multiplySimple(GenMatrix S) { ArrayList> m = matrix; ArrayList> B = S.matrix; GenMatrixRing pr = ring.product(S.ring); GenMatrix P = pr.getZERO().copy(); ArrayList> p = P.matrix; for (int i = 0; i < pr.rows; i++) { ArrayList Ai = m.get(i); //A[i]; for (int j = 0; j < pr.cols; j++) { C c = ring.coFac.getZERO(); for (int k = 0; k < S.ring.rows; k++) { c = c.sum(Ai.get(k).multiply(B.get(k).get(j))); // c += A[i][k] * B[k][j]; } (p.get(i)).set(j, c); // C[i][j] = c; } } return new GenMatrix(pr, p); } /** * Divide this by S. * @param S other matrix. * @return this * S^{-1}. */ public GenMatrix divide(GenMatrix S) { //throw new UnsupportedOperationException("divide not yet implemented"); return multiply(S.inverse()); } /** * Divide left this by S. * @param S other matrix. * @return S^{-1} * this. */ public GenMatrix divideLeft(GenMatrix S) { return S.inverse().multiply(this); } /** * Remainder after division of this by S. * @param S other matrix. * @return this - (this / S) * S. */ public GenMatrix remainder(GenMatrix S) { throw new UnsupportedOperationException("remainder not implemented"); } /** * Quotient and remainder by division of this by S. * @param S a GenMatrix * @return [this/S, this - (this/S)*S]. */ public GenMatrix[] quotientRemainder(GenMatrix S) { throw new UnsupportedOperationException("quotientRemainder not implemented, input = " + S); } /** * Inverse of this. * @return x with this * x = 1, if it exists. * @see edu.jas.vector.LinAlg#inverseLU(edu.jas.vector.GenMatrix,java.util.List) */ public GenMatrix inverse() { //throw new UnsupportedOperationException("inverse implemented in LinAlg.inverseLU()"); LinAlg la = new LinAlg(); GenMatrix mat = this.copy(); List P = la.decompositionLU(mat); if (P == null || P.isEmpty()) { throw new NotInvertibleException("matrix not invertible"); } mat = la.inverseLU(mat,P); return mat; } /** * Greatest common divisor. * @param b other element. * @return gcd(this,b). */ public GenMatrix gcd(GenMatrix b) { throw new UnsupportedOperationException("gcd not implemented"); } /** * Extended greatest common divisor. * @param b other element. * @return [ gcd(this,b), c1, c2 ] with c1*this + c2*b = gcd(this,b). */ public GenMatrix[] egcd(GenMatrix b) { throw new UnsupportedOperationException("egcd not implemented"); } } java-algebra-system-2.7.200/src/edu/jas/vector/GenMatrixRing.java000066400000000000000000000420301445075545500245410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; // import java.io.IOException; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.function.BiFunction; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.AlgebraFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * GenMatrixRing implements a generic matrix algebra factory with RingFactory. * Matrices of n rows and m columns over C. * @author Heinz Kredel */ public class GenMatrixRing> implements AlgebraFactory, C> { private static final Logger logger = LogManager.getLogger(GenMatrixRing.class); public final RingFactory coFac; public final int rows; public final int cols; public final int blocksize; public final static int DEFAULT_BSIZE = 10; public final GenMatrix ZERO; public final GenMatrix ONE; private final static Random random = new Random(); public final static float DEFAULT_DENSITY = 0.5f; private final float density = DEFAULT_DENSITY; /** * Constructors for GenMatrixRing. * @param b coefficient factory. * @param r number of rows. * @param c number of columns. */ public GenMatrixRing(RingFactory b, int r, int c) { this(b, r, c, DEFAULT_BSIZE); } /** * Constructors for GenMatrixRing. * @param b coefficient factory. * @param r number of rows. * @param c number of columns. * @param s block size for blocked operations. */ @SuppressWarnings("unchecked") public GenMatrixRing(RingFactory b, int r, int c, int s) { if (b == null) { throw new IllegalArgumentException("RingFactory is null"); } if (r < 1) { throw new IllegalArgumentException("rows < 1 " + r); } if (c < 1) { throw new IllegalArgumentException("cols < 1 " + c); } coFac = b; rows = r; cols = c; blocksize = s; ArrayList z = new ArrayList(cols); for (int i = 0; i < cols; i++) { z.add(coFac.getZERO()); } ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { m.add(new ArrayList(z)); // z.clone(); } ZERO = new GenMatrix(this, m); m = new ArrayList>(rows); C one = coFac.getONE(); ArrayList v; for (int i = 0; i < rows; i++) { if (i < cols) { v = new ArrayList(z); // z.clone(); v.set(i, one); m.add(v); } } ONE = new GenMatrix(this, m); logger.info("{} x {} matrix ring with blocksize {} over {} constructed", rows, cols, blocksize, coFac); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(coFac.getClass().getSimpleName()); s.append("[" + rows + "," + cols + "]"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("Mat("); String f = null; try { f = ((RingElem) coFac).toScriptFactory(); // sic } catch (Exception e) { f = coFac.toScript(); } s.append(f + "," + rows + "," + cols + ")"); return s.toString(); } /** * Get the constant one for the GenMatrix. * @return ZERO. */ public GenMatrix getZERO() { return ZERO; } /** * Get the constant one for the GenMatrix. * @return 1. */ public GenMatrix getONE() { return ONE; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { List rgens = coFac.generators(); List> gens = new ArrayList>(rows * cols * rgens.size()); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { for (C el : rgens) { GenMatrix g = ZERO.set(i, j, el); // uses clone() gens.add(g); } } } return gens; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return coFac.isFinite(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object other) { if (!(other instanceof GenMatrixRing)) { return false; } GenMatrixRing omod = (GenMatrixRing) other; if (rows != omod.rows) { return false; } if (cols != omod.cols) { return false; } if (!coFac.equals(omod.coFac)) { return false; } return true; } /** * Hash code for this matrix ring. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = rows * 17 + cols; h = 37 * h + coFac.hashCode(); return h; } /** * Query if this ring is a field. May return false if it is to hard to * determine if this ring is a field. * @return true if it is known that this ring is a field, else false. */ public boolean isField() { return false; } /** * Query if this monoid is commutative. * @return true if this monoid is commutative, else false. */ public boolean isCommutative() { return false; } /** * Query if this ring is associative. * @return true if this monoid is associative, else false. */ public boolean isAssociative() { return (rows == cols) && coFac.isAssociative(); } /** * Characteristic of this ring. * @return characteristic of this ring. */ public java.math.BigInteger characteristic() { return coFac.characteristic(); } /** * Transposed matrix ring. * @return transposed ring factory. */ public GenMatrixRing transpose() { if (rows == cols) { return this; } return new GenMatrixRing(coFac, cols, rows, blocksize); } /** * Product matrix ring for multiplication. * @param other matrix ring factory. * @return product ring factory. */ public GenMatrixRing product(GenMatrixRing other) { if (cols != other.rows) { throw new IllegalArgumentException("invalid dimensions in product"); } if (!coFac.equals(other.coFac)) { throw new IllegalArgumentException("invalid coefficients in product"); } if (rows == other.rows && cols == other.cols) { return this; } return new GenMatrixRing(coFac, rows, other.cols, blocksize); } /** * Stack matrix ring. this on top of other. * @param other matrix ring factory. * @return stack ring factory. */ public GenMatrixRing stack(GenMatrixRing other) { if (cols != other.cols) { throw new IllegalArgumentException("invalid dimensions in stack"); } if (!coFac.equals(other.coFac)) { throw new IllegalArgumentException("invalid coefficients in stack"); } if (other.rows == 0) { return this; } int stackrows = rows+other.rows; return new GenMatrixRing(coFac, stackrows, cols, blocksize); } /** * Concat matrix ring. this before of other. * @param other matrix ring factory. * @return concat ring factory. */ public GenMatrixRing concat(GenMatrixRing other) { if (rows != other.rows) { throw new IllegalArgumentException("invalid dimensions in concat"); } if (!coFac.equals(other.coFac)) { throw new IllegalArgumentException("invalid coefficients in stack"); } if (other.cols == 0) { return this; } int concatcols = cols+other.cols; return new GenMatrixRing(coFac, rows, concatcols, blocksize); } /** * Get the matrix for a. * @param a long * @return matrix corresponding to a. */ public GenMatrix fromInteger(long a) { C c = coFac.fromInteger(a); return ONE.scalarMultiply(c); } /** * Get the matrix for a. * @param a long * @return matrix corresponding to a. */ public GenMatrix fromInteger(BigInteger a) { C c = coFac.fromInteger(a); return ONE.scalarMultiply(c); } /** * From List of coefficients. * @param om list of list of coefficients. */ public GenMatrix fromList(List> om) { if (om == null) { return ZERO; } if (om.size() > rows) { throw new IllegalArgumentException("size v > rows " + om + " > " + rows); } ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { List ov = om.get(i); ArrayList v; if (ov == null) { v = ZERO.matrix.get(0); } else { if (ov.size() > cols) { throw new IllegalArgumentException("size v > cols " + ov + " > " + cols); } v = new ArrayList(cols); v.addAll(ov); // pad with zeros if required: for (int j = v.size(); j < cols; j++) { v.add(coFac.getZERO()); } } m.add(v); } return new GenMatrix(this, m); } /** * From List of GenVectors. * @param om list of GenVectors. */ public GenMatrix fromVectors(List> om) { List> mat = new ArrayList>(); for (GenVector row : om) { List nr = new ArrayList(row.val); mat.add(nr); } //List zero = this.getZERO().getRow(0).val; //for (int i = mat.size(); i < rows; i++) { // mat.add(zero); //} GenMatrixRing rfac = new GenMatrixRing(coFac,mat.size(),cols); return rfac.fromList(mat); } /** * Random matrix. * @param k size of random coefficients. */ public GenMatrix random(int k) { return random(k, density, random); } /** * Random matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. */ public GenMatrix random(int k, float q) { return random(k, q, random); } /** * Random matrix. * @param k size of random coefficients. * @param random is a source for random bits. * @return a random element. */ public GenMatrix random(int k, Random random) { return random(k, density, random); } /** * Random matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. * @param random is a source for random bits. * @return a random element. */ public GenMatrix random(int k, float q, Random random) { ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { ArrayList v = new ArrayList(cols); for (int j = 0; j < cols; j++) { C e; if (random.nextFloat() < q) { e = coFac.random(k, random); } else { e = coFac.getZERO(); } v.add(e); } m.add(v); } return new GenMatrix(this, m); } /** * Random upper triangular matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. */ public GenMatrix randomUpper(int k, float q) { return randomUpper(k, q, random); } /** * Random upper triangular matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. * @param random is a source for random bits. * @return a random element. */ public GenMatrix randomUpper(int k, float q, Random random) { ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { ArrayList v = new ArrayList(cols); for (int j = 0; j < cols; j++) { C e = coFac.getZERO(); if (j >= i) { if (random.nextFloat() < q) { e = coFac.random(k, random); } } v.add(e); } m.add(v); } return new GenMatrix(this, m); } /** * Random lower triangular matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. */ public GenMatrix randomLower(int k, float q) { return randomLower(k, q, random); } /** * Random lower triangular matrix. * @param k size of random coefficients. * @param q density of nozero coefficients. * @param random is a source for random bits. * @return a random element. */ public GenMatrix randomLower(int k, float q, Random random) { ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { ArrayList v = new ArrayList(cols); for (int j = 0; j < cols; j++) { C e = coFac.getZERO(); if (j <= i) { if (random.nextFloat() < q) { e = coFac.random(k, random); } } v.add(e); } m.add(v); } return new GenMatrix(this, m); } /** * Copy matrix. * @param c matrix to copy. * @return copy of the matrix */ public GenMatrix copy(GenMatrix c) { if (c == null) { return c; } return c.copy(); } /** * Generate matrix via lambda expression. * @param gener lambda expression. * @return the generated matrix. */ public GenMatrix generate(BiFunction gener) { ArrayList> m = new ArrayList>(rows); for (int i = 0; i < rows; i++) { ArrayList v = new ArrayList(cols); for (int j = 0; j < cols; j++) { C e = gener.apply(i, j); v.add(e); } m.add(v); } return new GenMatrix(this, m); } /** * Parse a matrix from a String. Syntax: [ [ c, ..., c ], ..., [ c, ..., c ] * ] * @param s input String. * @return parsed matrix */ public GenMatrix parse(String s) { int i = s.indexOf("["); if (i >= 0) { s = s.substring(i + 1); } ArrayList> mat = new ArrayList>(rows); ArrayList v; GenVector vec; GenVectorModul vmod = new GenVectorModul(coFac, cols); String e; int j; do { i = s.indexOf("]"); // delimit vector j = s.lastIndexOf("]"); // delimit matrix if (i != j) { if (i >= 0) { e = s.substring(0, i); s = s.substring(i); vec = vmod.parse(e); v = new ArrayList(vec.val); mat.add(v); i = s.indexOf(","); if (i >= 0) { s = s.substring(i + 1); } } } else { // matrix delimiter if (i >= 0) { e = s.substring(0, i); if (e.trim().length() > 0) { throw new RuntimeException("Error e not empty " + e); } //s = s.substring(i + 1); } break; } } while (i >= 0); return new GenMatrix(this, mat); } /** * Parse a matrix from a Reader. * @param r Reader. * @return parsed matrix */ public GenMatrix parse(Reader r) { String s = StringUtil.nextPairedString(r, '[', ']'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/vector/GenVector.java000066400000000000000000000260271445075545500237270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.PrettyPrint; import edu.jas.structure.ModulElem; import edu.jas.structure.RingElem; /** * GenVector implements generic vectors with RingElem entries. Vectors of n * columns over C. * @author Heinz Kredel */ public class GenVector> implements ModulElem, C> { private static final Logger logger = LogManager.getLogger(GenVector.class); public final GenVectorModul modul; public final List val; /** * Constructor for zero GenVector. */ public GenVector(GenVectorModul m) { this(m, m.getZERO().val); } /** * Constructor for GenVector. */ public GenVector(GenVectorModul m, List v) { if (m == null || v == null) { throw new IllegalArgumentException("Empty m or v not allowed, m = " + m + ", v = " + v); } modul = m; val = v; logger.debug("{} vector constructed", modul.cols); } /** * Constructor for GenVector. */ public GenVector(GenVectorModul m, C[] v) { if (m == null || v == null) { throw new IllegalArgumentException("Empty m or v not allowed, m = " + m + ", v = " + v); } modul = m; val = new ArrayList(v.length); for (int i = 0; i < v.length; i++) { val.add(v[i]); } logger.debug("{} vector constructed", modul.cols); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append("[ "); boolean first = true; for (C c : val) { if (first) { first = false; } else { s.append(", "); } s.append(c.toString()); } s.append(" ]"); if (!PrettyPrint.isTrue()) { s.append(" :: " + modul.toString()); s.append("\n"); } return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this Element. * @see edu.jas.structure.Element#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer(); s.append("( "); boolean first = true; for (C c : val) { if (first) { first = false; } else { s.append(", "); } s.append(c.toScript()); } s.append(" )"); return s.toString(); } /** * Get a scripting compatible string representation of the factory. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.Element#toScriptFactory() */ @Override public String toScriptFactory() { // Python case return factory().toScript(); } /** * Get the corresponding element factory. * @return factory for this Element. * @see edu.jas.structure.Element#factory() */ public GenVectorModul factory() { return modul; } /** * clone method. * @see java.lang.Object#clone() */ @Override @SuppressWarnings("unchecked") public GenVector copy() { //return modul.copy(this); ArrayList av = new ArrayList(val); return new GenVector(modul, av); } /** * test if this is equal to a zero vector. */ public boolean isZERO() { return (0 == this.compareTo(modul.getZERO())); } /** * equals method. */ @Override public boolean equals(Object other) { if (!(other instanceof GenVector)) { return false; } GenVector ovec = (GenVector) other; if (!modul.equals(ovec.modul)) { return false; } if (!val.equals(ovec.val)) { return false; } return true; } /** * Hash code for this GenVector. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return 37 * val.hashCode() + modul.hashCode(); } /** * compareTo, lexicographical comparison. * @param b other * @return 1 if (this < b), 0 if (this == b) or -1 if (this > b). */ @Override public int compareTo(GenVector b) { if (!modul.equals(b.modul)) { return -1; } List oval = b.val; int i = 0; for (C c : val) { int s = c.compareTo(oval.get(i++)); if (s != 0) { return s; } } return 0; } /** * get element. * @param i index * @return e with e = this(i). */ public C get(int i) { return val.get(i); } /** * set element, mutate this. * @param i index * @param e value * @return this with this(i) = e. */ public C setMutate(int i, C e) { return val.set(i, e); } /** * sign of vector. * @return 1 if (this < 0), 0 if (this == 0) or -1 if (this > 0). */ public int signum() { return compareTo(modul.getZERO()); } /** * Sum of vectors. * @param b other vector. * @return this+b */ public GenVector sum(GenVector b) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C e = c.sum(oval.get(i++)); a.add(e); } return new GenVector(modul, a); } /** * Difference of vectors. * @param b other vector. * @return this-b */ public GenVector subtract(GenVector b) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C e = c.subtract(oval.get(i++)); a.add(e); } return new GenVector(modul, a); } /** * Negative of this vector. * @return -this */ public GenVector negate() { ArrayList a = new ArrayList(modul.cols); for (C c : val) { C e = c.negate(); a.add(e); } return new GenVector(modul, a); } /** * Absolute value of this vector. * @return abs(this) */ public GenVector abs() { if (signum() < 0) { return negate(); } return this; } /** * Product of this vector with scalar. * @param s scalar. * @return this*s */ public GenVector multiply(C s) { return scalarMultiply(s); } /** * Product of this vector with scalar. * @param s scalar. * @return this*s */ public GenVector scalarMultiply(C s) { ArrayList a = new ArrayList(modul.cols); for (C c : val) { C e = c.multiply(s); a.add(e); } return new GenVector(modul, a); } /** * Left product of this vector with scalar. * @param s scalar. * @return s*this */ public GenVector leftScalarMultiply(C s) { ArrayList a = new ArrayList(modul.cols); for (C c : val) { C e = s.multiply(c); a.add(e); } return new GenVector(modul, a); } /** * Linear combination of this vector with scalar multiple of other vector. * @param s scalar. * @param b other vector. * @param t scalar. * @return this*s+b*t */ public GenVector linearCombination(C s, GenVector b, C t) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C c1 = c.multiply(s); C c2 = oval.get(i++).multiply(t); C e = c1.sum(c2); a.add(e); } return new GenVector(modul, a); } /** * Linear combination of this vector with scalar multiple of other vector. * @param b other vector. * @param t scalar. * @return this+b*t */ public GenVector linearCombination(GenVector b, C t) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C c2 = oval.get(i++).multiply(t); C e = c.sum(c2); a.add(e); } return new GenVector(modul, a); } /** * Left linear combination of this vector with scalar multiple of other * vector. * @param b other vector. * @param t scalar. * @return this+t*b */ public GenVector linearCombination(C t, GenVector b) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C c2 = t.multiply(oval.get(i++)); C e = c.sum(c2); a.add(e); } return new GenVector(modul, a); } /** * left linear combination of this vector with scalar multiple of other * vector. * @param s scalar. * @param b other vector. * @param t scalar. * @return s*this+t*b */ public GenVector leftLinearCombination(C s, C t, GenVector b) { List oval = b.val; ArrayList a = new ArrayList(modul.cols); int i = 0; for (C c : val) { C c1 = s.multiply(c); C c2 = t.multiply(oval.get(i++)); C e = c1.sum(c2); a.add(e); } return new GenVector(modul, a); } /** * scalar / dot product of this vector with other vector. * @param b other vector. * @return this . b */ public C scalarProduct(GenVector b) { C a = modul.coFac.getZERO(); List oval = b.val; int i = 0; for (C c : val) { C c2 = c.multiply(oval.get(i++)); a = a.sum(c2); } return a; } /** * scalar / dot product of this vector with list of other vectors. * @param B list of vectors. * @return this * b */ public GenVector scalarProduct(List> B) { GenVector A = modul.getZERO(); int i = 0; for (C c : val) { GenVector b = B.get(i++); GenVector a = b.leftScalarMultiply(c); A = A.sum(a); } return A; } /** * right scalar / dot product of this vector with list of other vectors. * @param B list of vectors. * @return b * this */ public GenVector rightScalarProduct(List> B) { GenVector A = modul.getZERO(); int i = 0; for (C c : val) { GenVector b = B.get(i++); GenVector a = b.scalarMultiply(c); A = A.sum(a); } return A; } } java-algebra-system-2.7.200/src/edu/jas/vector/GenVectorModul.java000066400000000000000000000172711445075545500247310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.io.Reader; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.kern.StringUtil; import edu.jas.structure.ModulFactory; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; /** * GenVectorModul implements a generic vector factory with RingElem entries. * Vectors of n columns over C. * @author Heinz Kredel */ public class GenVectorModul> implements ModulFactory, C> { private static final Logger logger = LogManager.getLogger(GenVectorModul.class); public final RingFactory coFac; public final int cols; public final GenVector ZERO; public final List> BASIS; private final static Random random = new Random(); public final static float DEFAULT_DENSITY = 0.5f; private final float density = DEFAULT_DENSITY; /** * Constructor for GenVectorModul. */ @SuppressWarnings("unchecked") public GenVectorModul(RingFactory b, int s) { coFac = b; cols = s; ArrayList z = new ArrayList(cols); for (int i = 0; i < cols; i++) { z.add(coFac.getZERO()); } ZERO = new GenVector(this, z); BASIS = new ArrayList>(cols); List cgens = coFac.generators(); ArrayList v; for (int i = 0; i < cols; i++) { for (C g : cgens) { v = new ArrayList(z);// z.clone(); v.set(i, g); BASIS.add(new GenVector(this, v)); } } logger.info("{} module over {} constructed", cols, coFac); } /** * Get the String representation as RingElem. * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer s = new StringBuffer(); s.append(coFac.getClass().getSimpleName()); s.append("[" + cols + "]"); return s.toString(); } /** * Get a scripting compatible string representation. * @return script compatible representation for this ElemFactory. * @see edu.jas.structure.ElemFactory#toScript() */ @Override public String toScript() { // Python case StringBuffer s = new StringBuffer("Vec("); String f = null; try { f = ((RingElem) coFac).toScriptFactory(); // sic } catch (Exception e) { f = coFac.toScript(); } s.append(f + "," + cols + " )"); return s.toString(); } /** * getZERO. * @return ZERO. */ public GenVector getZERO() { return ZERO; } /** * Get a list of the generating elements. * @return list of generators for the algebraic structure. * @see edu.jas.structure.ElemFactory#generators() */ public List> generators() { return BASIS; } /** * Is this structure finite or infinite. * @return true if this structure is finite, else false. * @see edu.jas.structure.ElemFactory#isFinite() */ public boolean isFinite() { return coFac.isFinite(); } /** * Comparison with any other object. * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object other) { if (!(other instanceof GenVectorModul)) { return false; } GenVectorModul omod = (GenVectorModul) other; if (cols != omod.cols) { return false; } if (!coFac.equals(omod.coFac)) { return false; } return true; } /** * Hash code for this vector module. * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int h; h = cols; h = 37 * h + coFac.hashCode(); return h; } /** * Get the vector for a. * @param a long * @return vector corresponding to a. */ public GenVector fromInteger(long a) { C c = coFac.fromInteger(a); return BASIS.get(0).scalarMultiply(c); } /** * Get the vector for a. * @param a long * @return vector corresponding to a. */ public GenVector fromInteger(BigInteger a) { C c = coFac.fromInteger(a); return BASIS.get(0).scalarMultiply(c); } /** * From List of coefficients. * @param v list of coefficients. * @return vector from v. */ public GenVector fromList(List v) { if (v == null) { return ZERO; } if (v.size() > cols) { throw new IllegalArgumentException("size v > cols " + v + " > " + cols); } List r = new ArrayList(cols); r.addAll(v); // pad with zeros if required: for (int i = r.size(); i < cols; i++) { r.add(coFac.getZERO()); } return new GenVector(this, r); } /** * Random vector. * @param k size of random coefficients. * @return random vector. */ public GenVector random(int k) { return random(k, density, random); } /** * Random vector. * @param k size of random coefficients. * @param q density of nonzero coefficients. * @return random vector. */ public GenVector random(int k, float q) { return random(k, q, random); } /** * Random vector. * @param k size of random coefficients. * @param random is a source for random bits. * @return a random element. */ public GenVector random(int k, Random random) { return random(k, density, random); } /** * Random vector. * @param k size of random coefficients. * @param q density of nonzero coefficients. * @param random is a source for random bits. * @return a random element. */ public GenVector random(int k, float q, Random random) { List r = new ArrayList(cols); for (int i = 0; i < cols; i++) { if (random.nextFloat() < q) { r.add(coFac.random(k)); } else { r.add(coFac.getZERO()); } } return new GenVector(this, r); } /** * copy vector. * @param c vector. * @return copy of vector c. */ public GenVector copy(GenVector c) { if (c == null) { return c; } return c.copy(); } /** * Parse a vector from a String. Syntax: [ c, ..., c ] * @param s String with vector. * @return parsed vector. */ public GenVector parse(String s) { int i = s.indexOf("["); if (i >= 0) { s = s.substring(i + 1); } i = s.indexOf("]"); if (i >= 0) { s = s.substring(0, i); } List vec = new ArrayList(cols); String e; C c; do { i = s.indexOf(","); if (i >= 0) { e = s.substring(0, i); s = s.substring(i + 1); c = coFac.parse(e); vec.add(c); } } while (i >= 0); if (s.trim().length() > 0) { c = coFac.parse(s); vec.add(c); } return new GenVector(this, vec); } /** * Parse a vector from a Reader. * @param r Reader containing a vector. * @return parsed vector. */ public GenVector parse(Reader r) { String s = StringUtil.nextPairedString(r, '[', ']'); return parse(s); } } java-algebra-system-2.7.200/src/edu/jas/vector/LinAlg.java000066400000000000000000000546521445075545500232060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.structure.RingElem; /** * Linear algebra methods. Implements linear algebra computations and tests, * mainly based on Gauss elimination. Partly based on LU_decomposition. * Computation of Null space basis, row echelon form, inverses and ranks. * @param coefficient type * @author Heinz Kredel */ public class LinAlg> implements Serializable { private static final Logger logger = LogManager.getLogger(LinAlg.class); //private static final boolean debug = logger.isDebugEnabled(); /** * Constructor. */ public LinAlg() { } /** * Matrix LU decomposition. Matrix A is replaced by its LU decomposition. A * contains a copy of both matrices L-E and U as A=(L-E)+U such that * P*A=L*U. The permutation matrix is not stored as a matrix, but in an * integer vector P of size N+1 containing column indexes where the * permutation matrix has "1". The last element P[N]=S+N, where S is the * number of row exchanges needed for determinant computation, det(P)=(-1)^S * @param A a n×n matrix. * @return permutation vector P and modified matrix A. */ public List decompositionLU(GenMatrix A) { if (A == null) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; int M = ring.cols; int NM = Math.min(N,M); if (N != M) { logger.warn("nosquare matrix"); } List P = new ArrayList(NM + 1); for (int i = 0; i <= NM; i++) { P.add(i); //Unit permutation matrix, P[NM] initialized with NM } ArrayList> mat = A.matrix; for (int i = 0; i < NM; i++) { int imax = i; C maxA = ring.coFac.getZERO(); for (int k = i; k < N; k++) { // absA = fabs(A[k][i]) C absA = mat.get(k).get(i).abs(); if (absA.compareTo(maxA) > 0) { maxA = absA; imax = k; break; // first } } if (maxA.isZERO()) { logger.warn("matrix is degenerate at col {}", i); mat.get(i).set(i, ring.coFac.getZERO()); // already zero //continue; P.clear(); return P; //failure, matrix is degenerate } if (imax != i) { //pivoting P int j = P.get(i); P.set(i, P.get(imax)); P.set(imax, j); //System.out.println("new pivot " + imax); // + ", P = " + P); //pivoting rows of A ArrayList ptr = mat.get(i); mat.set(i, mat.get(imax)); mat.set(imax, ptr); //counting pivots starting from NM (for determinant) P.set(NM, P.get(NM) + 1); } C dd = mat.get(i).get(i).inverse(); for (int j = i + 1; j < N; j++) { // A[j][i] /= A[i][i]; C d = mat.get(j).get(i).multiply(dd); //divide(dd); mat.get(j).set(i, d); for (int k = i + 1; k < M; k++) { // A[j][k] -= A[j][i] * A[i][k]; C a = mat.get(j).get(i).multiply(mat.get(i).get(k)); mat.get(j).set(k, mat.get(j).get(k).subtract(a)); } } //System.out.println("row(last) = " + mat.get(NM-1)); } return P; } /** * Solve with LU decomposition. * @param A a n×n matrix in LU decomposition. * @param P permutation vector. * @param b right hand side vector. * @return x solution vector of A*x = b. */ public GenVector solveLU(GenMatrix A, List P, GenVector b) { if (A == null || b == null) { return null; } if (P.size() == 0) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; GenVectorModul xfac = new GenVectorModul(ring.coFac, N); GenVector x = new GenVector(xfac); List vec = x.val; ArrayList> mat = A.matrix; for (int i = 0; i < N; i++) { //x[i] = b[P[i]]; vec.set(i, b.get(P.get(i))); C xi = vec.get(i); for (int k = 0; k < i; k++) { //x[i] -= A[i][k] * x[k]; C ax = mat.get(i).get(k).multiply(vec.get(k)); xi = xi.subtract(ax); } vec.set(i, xi); } //System.out.println("vec = " + vec); for (int i = N - 1; i >= 0; i--) { C xi = vec.get(i); for (int k = i + 1; k < N; k++) { //x[i] -= A[i][k] * x[k]; C ax = mat.get(i).get(k).multiply(vec.get(k)); xi = xi.subtract(ax); } vec.set(i, xi); //x[i] /= A[i][i]; vec.set(i, xi.divide(mat.get(i).get(i))); } return x; } /** * Solve linear system of equations. * @param A a n×n matrix. * @param b right hand side vector. * @return x solution vector of A*x = b. */ public GenVector solve(GenMatrix A, GenVector b) { if (A == null || b == null) { return null; } GenMatrix Ap = A.copy(); List P = decompositionLU(Ap); if (P.size() == 0) { System.out.println("undecomposable"); return b.modul.getZERO(); } GenVector x = solveLU(Ap, P, b); return x; } /** * Determinant with LU decomposition. * @param A a n×n matrix in LU decomposition. * @param P permutation vector. * @return d determinant of A. */ public C determinantLU(GenMatrix A, List P) { if (A == null) { return null; } if (P.size() == 0) { return A.ring.coFac.getZERO(); } int N = A.ring.rows; //P.size() - 1 - 1; ArrayList> mat = A.matrix; // det = A[0][0]; C det = mat.get(0).get(0); for (int i = 1; i < N; i++) { //det *= A[i][i]; det = det.multiply(mat.get(i).get(i)); } //return (P[N] - N) % 2 == 0 ? det : -det int s = P.get(N) - N; if (s % 2 != 0) { det = det.negate(); } return det; } /** * Inverse with LU decomposition. * @param A a n×n matrix in LU decomposition. * @param P permutation vector. * @return inv(A) with A * inv(A) == 1. */ public GenMatrix inverseLU(GenMatrix A, List P) { GenMatrixRing ring = A.ring; GenMatrix inv = new GenMatrix(ring); int N = ring.rows; //P.size() - 1 - 1; ArrayList> mat = A.matrix; ArrayList> imat = inv.matrix; for (int j = 0; j < N; j++) { // transform right hand vector with L matrix for (int i = 0; i < N; i++) { //IA[i][j] = P[i] == j ? 1.0 : 0.0; C e = (P.get(i) == j) ? ring.coFac.getONE() : ring.coFac.getZERO(); imat.get(i).set(j, e); C b = e; //imat.get(i).get(j); for (int k = 0; k < i; k++) { //IA[i][j] -= A[i][k] * IA[k][j]; C a = mat.get(i).get(k).multiply(imat.get(k).get(j)); b = b.subtract(a); } imat.get(i).set(j, b); } // solve inverse matrix column with U matrix for (int i = N - 1; i >= 0; i--) { C b = imat.get(i).get(j); for (int k = i + 1; k < N; k++) { //IA[i][j] -= A[i][k] * IA[k][j]; C a = mat.get(i).get(k).multiply(imat.get(k).get(j)); b = b.subtract(a); } imat.get(i).set(j, b); //IA[i][j] /= A[i][i]; C e = b; //imat.get(i).get(j); e = e.divide(mat.get(i).get(i)); imat.get(i).set(j, e); } } return inv; } /** * Matrix Null Space basis, cokernel. From the transpose matrix At it * computes the kernel with At*v_i = 0. * @param A a n×n matrix. * @return V a list of basis vectors (v_1, ..., v_k) with v_i*A == 0. */ public List> nullSpaceBasis(GenMatrix A) { if (A == null) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; int M = ring.cols; if (N != M) { logger.warn("nosquare matrix"); } List> nspb = new ArrayList>(); GenVectorModul vfac = new GenVectorModul(ring.coFac, M); ArrayList> mat = A.matrix; for (int i = 0; i < N; i++) { C maxA, absA; // search privot imax int imax = i; maxA = ring.coFac.getZERO(); for (int k = i; k < M; k++) { // k = 0 ? // absA = fabs(A[k][i]) absA = mat.get(i).get(k).abs(); if (absA.compareTo(maxA) > 0 && maxA.isZERO()) { maxA = absA; imax = k; } } logger.info("pivot: {}, i = {}, maxA = {}", imax, i, maxA); if (maxA.isZERO()) { // check for complete zero row or left pivot int imaxl = i; for (int k = 0; k < i; k++) { // k = 0 ? // absA = fabs(A[k][i]) absA = mat.get(i).get(k).abs(); if (absA.compareTo(maxA) > 0) { // first or last imax: && maxA.isZERO() imaxl = k; // check if upper triangular column is zero boolean iszero = true; for (int m = 0; m < i; m++) { C amm = mat.get(m).get(imaxl).abs(); if (!amm.isZERO()) { iszero = false; break; } } if (iszero) { // left pivot okay imax = imaxl; logger.info("pivot*: {}, i = {}, absA = {}", imax, i, absA); maxA = ring.coFac.getONE(); } } } if (maxA.isZERO()) { // complete zero row continue; } } if (imax < M) { //!= i //normalize column i C mp = mat.get(i).get(imax).inverse(); for (int k = 0; k < N; k++) { // k = i ? C b = mat.get(k).get(imax); b = b.multiply(mp); mat.get(k).set(imax, b); } //pivoting columns of A if (imax != i) { for (int k = 0; k < N; k++) { C b = mat.get(k).get(i); mat.get(k).set(i, mat.get(k).get(imax)); mat.get(k).set(imax, b); } } //eliminate rest of row i via column operations for (int j = 0; j < M; j++) { if (i == j) { // is already normalized continue; } C mm = mat.get(i).get(j); for (int k = 0; k < N; k++) { // or k = 0 C b = mat.get(k).get(j); C c = mat.get(k).get(i); C d = b.subtract(c.multiply(mm)); mat.get(k).set(j, d); } } } } // convert to A-I for (int i = 0; i < N; i++) { C b = mat.get(i).get(i); b = b.subtract(ring.coFac.getONE()); mat.get(i).set(i, b); } //System.out.println("mat-1 = " + A); // read off non zero rows of A for (int i = 0; i < N; i++) { List row = mat.get(i); boolean iszero = true; for (int k = 0; k < M; k++) { if (!row.get(k).isZERO()) { iszero = false; break; } } if (!iszero) { GenVector v = new GenVector(vfac, row); nspb.add(v); } } return nspb; } /** * Rank via null space. * @param A a n×n matrix. * @return r rank of A. */ public long rankNS(GenMatrix A) { if (A == null) { return -1l; } GenMatrix Ap = A.copy(); long n = Math.min(A.ring.rows, A.ring.cols); List> ns = nullSpaceBasis(Ap); long s = ns.size(); return n - s; } /** * Matrix row echelon form construction. Matrix A is replaced by its row * echelon form, an upper triangle matrix. * @param A a n×m matrix. * @return A row echelon form of A, matrix A is modified. */ public GenMatrix rowEchelonForm(GenMatrix A) { if (A == null) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; int M = ring.cols; if (N != M) { logger.warn("nosquare matrix"); } int kmax = 0; ArrayList> mat = A.matrix; for (int i = 0; i < N;) { int imax = i; C maxA = ring.coFac.getZERO(); // search non-zero rows for (int k = i; k < N; k++) { // absA = fabs(A[k][i]) C absA = mat.get(k).get(kmax).abs(); if (absA.compareTo(maxA) > 0) { maxA = absA; imax = k; break; // first } } if (maxA.isZERO()) { //System.out.println("matrix is zero at col " + kmax); kmax++; if (kmax >= M) { break; } continue; } //System.out.println("matrix is non zero at row " + imax); if (imax != i) { //swap pivoting rows of A ArrayList ptr = mat.get(i); mat.set(i, mat.get(imax)); mat.set(imax, ptr); } // A[j][i] /= A[i][i]; C dd = mat.get(i).get(kmax).inverse(); //System.out.println("matrix is non zero at row " + imax + ", dd = " + dd); for (int k = kmax; k < M; k++) { C d = mat.get(i).get(k).multiply(dd); //divide(dd); mat.get(i).set(k, d); } for (int j = i + 1; j < N; j++) { for (int k = kmax; k < M; k++) { // A[j][k] -= A[j][k] * A[i][k]; C a = mat.get(j).get(k).multiply(mat.get(i).get(k)); if (a.isZERO()) { continue; } mat.get(j).set(k, mat.get(j).get(k).subtract(a)); } } mat.get(i).set(kmax, ring.coFac.getONE()); i++; kmax++; if (kmax >= M) { break; } //System.out.println("rowEch(last) = " + mat.get(N-1)); } return A; } /** * Rank via row echelon form. * @param A a n×n matrix. * @return r rank of A. */ public long rankRE(GenMatrix A) { if (A == null) { return -1l; } long n = A.ring.rows; long m = A.ring.cols; ArrayList> mat = A.matrix; // count non-zero rows long r = 0; for (int i = 0; i < n; i++) { ArrayList row = mat.get(i); for (int j = i; j < m; j++) { if (!row.get(j).isZERO()) { r++; break; } } } return r; } /** * Matrix row echelon form construction. Matrix A is replaced by * its row echelon form, an upper triangle matrix with less * non-zero entries. No column swaps and transforms are performed * as with the Gauss-Jordan algorithm. * @param A a n×m matrix. * @return A sparse row echelon form of A, matrix A is modified. */ public GenMatrix rowEchelonFormSparse(GenMatrix A) { if (A == null) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; int M = ring.cols; if (N != M) { logger.warn("nosquare matrix"); } int i, imax, kmax; C maxA, absA; ArrayList> mat = A.matrix; for (i = N - 1; i > 0; i--) { imax = i; maxA = ring.coFac.getZERO(); //System.out.println("matrix row " + A.getRow(i)); kmax = -1; // search non-zero entry in row i for (int k = i; k < M; k++) { // absA = fabs(A[i][k]) absA = mat.get(i).get(k).abs(); if (absA.compareTo(maxA) > 0) { //System.out.println("absA(" + i +"," + k + ") = " + absA); maxA = absA; kmax = k; break; // first } } if (maxA.isZERO()) { continue; } // reduce upper rows for (int j = imax - 1; j >= 0; j--) { for (int k = kmax; k < M; k++) { // A[j,k] -= A[j,k] * A[imax,k] C mjk = mat.get(j).get(k); if (mjk.isZERO()) { continue; } C mk = mat.get(imax).get(k); if (mk.isZERO()) { continue; } C a = mk.multiply(mjk); //System.out.println("mjk(" + j +"," + k + ") = " + mjk + ", mk = " + mk); mjk = mjk.subtract(a); mat.get(j).set(k,mjk); } } } return A; } /** * Matrix fraction free Gauss elimination. Matrix A is replaced by * its fraction free LU decomposition. A contains a copy of both * matrices L-E and U as A=(L-E)+U such that P*A=L*U. TODO: L is * not computed but 0. The permutation matrix is not stored as a * matrix, but in an integer vector P of size N+1 containing * column indexes where the permutation matrix has "1". The last * element P[N]=S+N, where S is the number of row exchanges needed * for determinant computation, det(P)=(-1)^S * @param A a n×n matrix. * @return permutation vector P and modified matrix A. */ public List fractionfreeGaussElimination(GenMatrix A) { if (A == null) { return null; } GenMatrixRing ring = A.ring; int N = ring.rows; int M = ring.cols; int NM = Math.min(N,M); if (N != M) { logger.warn("nosquare matrix"); } List P = new ArrayList(NM + 1); for (int i = 0; i <= NM; i++) { P.add(i); //Unit permutation matrix, P[NM] initialized with NM } int r = 0; C divisor = ring.coFac.getONE(); ArrayList> mat = A.matrix; for (int i = 0; i < NM && r < N; i++) { int imax = i; C maxA = ring.coFac.getZERO(); for (int k = i; k < N; k++) { // absA = fabs(A[k][i]) C absA = mat.get(k).get(i).abs(); if (absA.compareTo(maxA) > 0) { maxA = absA; imax = k; break; // first } } if (maxA.isZERO()) { logger.warn("matrix is degenerate at col {}", i); mat.get(i).set(i, ring.coFac.getZERO()); //already zero //continue; P.clear(); return P; //failure, matrix is degenerate } if (imax != i) { //pivoting P int j = P.get(i); P.set(i, P.get(imax)); P.set(imax, j); //System.out.println("new pivot " + imax); // + ", P = " + P); //pivoting rows of A ArrayList ptr = mat.get(i); mat.set(i, mat.get(imax)); mat.set(imax, ptr); //counting pivots starting from NM (for determinant) P.set(NM, P.get(NM) + 1); } //C dd = mat.get(i).get(i).inverse(); for (int j = r + 1; j < N; j++) { // A[j][i] /= A[i][i]; //C d = mat.get(j).get(i).multiply(dd); //divide(dd); //mat.get(j).set(i, d); for (int k = i + 1; k < M; k++) { //+ 1 // A[j][k] -= A[j][i] * A[i][k]; //C a = mat.get(j).get(i).multiply(mat.get(i).get(k)); //mat.get(j).set(k, mat.get(j).get(k).subtract(a)); //System.out.println("i = " + i + ", r = " + r + ", j = " + j + ", k = " + k); C a = mat.get(r).get(i).multiply(mat.get(j).get(k)); C b = mat.get(r).get(k).multiply(mat.get(j).get(i)); C d = a.subtract(b).divide(divisor); //System.out.println(", a = " + a + ", b = " + b + ", d = " + d); mat.get(j).set(k, d); } } for (int j = r + 1; j < N; j++) { // set L-E = 0 mat.get(j).set(i, ring.coFac.getZERO()); } divisor = mat.get(r).get(i); r++; //System.out.println("divisor = " + divisor); //System.out.println("mat = " + mat); //System.out.println("row(last) = " + mat.get(NM-1)); } return P; } } java-algebra-system-2.7.200/src/edu/jas/vector/package.html000066400000000000000000000016021445075545500234410ustar00rootroot00000000000000 Generic vector and matrix package

Generic vector and matrix package.

This package contains classes for generic vectors and matices over RingElems, namely GenVector and GenMatrix. Algorithms for vector and matrix computation are contained in BasicLinAlg and matrix decompositions in LinAlg.


Heinz Kredel

Last modified: Thu Jul 8 17:24:45 CEST 2021

$Id$

java-algebra-system-2.7.200/trc/000077500000000000000000000000001445075545500163265ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/000077500000000000000000000000001445075545500171035ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/000077500000000000000000000000001445075545500176605ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/application/000077500000000000000000000000001445075545500221635ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/application/CGBSeqTest.java000066400000000000000000000173421445075545500247410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.Product; import edu.jas.gbufd.RGroebnerBasePseudoSeq; import edu.jas.gbufd.RReductionSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Comprehenssive Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class CGBSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a CGBSeqTest object. * @param name String. */ public CGBSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(CGBSeqTest.class); return suite; } GenPolynomialRing cfac; GenPolynomialRing> fac; List>> L; ComprehensiveGroebnerBaseSeq bb; GenPolynomial> a, b, c, d, e; int rl = 2; //4; //3; int kl = 2; int ll = 3; int el = 3 + 1; float q = 0.3f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(kl); String[] cv = { "a" }; //, "b" }; cfac = new GenPolynomialRing(coeff, 1, cv); String[] v = { "x" }; //, "y" }; fac = new GenPolynomialRing>(cfac, 1, v); a = b = c = d = e = null; bb = new ComprehensiveGroebnerBaseSeq(coeff); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; cfac = null; bb = null; } /* * Dummy test method for jUnit. * public void testDummy() { } */ /** * Test sequential CGB. */ public void testSequentialCGB() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a; //fac.random(kl, ll, el, q ); d = c; //fac.random(kl, ll, el, q ); e = d; //fac.random(kl, ll, el, q ); L = fac.generators(); //System.out.println("generators: " + L); int k = 2; if (a.isZERO()) { a = L.get(k); } if (b.isZERO()) { b = L.get(k); } if (c.isZERO()) { c = L.get(k); } if (d.isZERO()) { d = L.get(k); e = d; } L.clear(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); //System.out.println("L = " + L); L = bb.GB(L); //System.out.println("L = " + L); assertTrue("isGB( { a } )", bb.isGB(L)); //System.out.println("isGB: " + L); if (L.contains(fac.getONE())) { L.clear(); } assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); //System.out.println("L = " + L); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); //System.out.println("L = " + L); } /** * Test Trinks CGB. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { PolynomialList> F = null; List>> G = null; String exam = "IntFunc(b) (S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - { 165 b + 36 } ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - { 165 b**2 } ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - { 11 b**3 } ), " + "( 99 W - { 11 b } S + { 3 b**2 } ), " + "( { b**2 + 33/50 b + 2673/10000 } ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //PolynomialList> trinks // = new PolynomialList>(F.ring,G); //System.out.println("G = " + trinks); //System.out.println("G = " + G); } /** * Test Raksanyi & Walter example comprehensive GB and regular GB. */ @SuppressWarnings("unchecked") public void testRaksanyiCGBase() { PolynomialList> F = null; String exam = "IntFunc(a1,a2,a3,a4) (x1,x2,x3,x4) L " + "( " + "( x4 - ( a4 - a2 ) ), " + "( x1 + x2 + x3 + x4 - ( a1 + a3 + a4 ) ), " + "( x1 * x3 + x1 * x4 + x2 * x3 + x3 * x4 - ( a1 * a4 + a1 * a3 + a3 * a4 ) ), " + "( x1 * x3 * x4 - ( a1 * a3 * a4 ) ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F.toScript()); // as comprehensive Gröbner system GroebnerSystem GS; List>> G; GS = bb.GBsys(F.list); //System.out.println("GBsys(F) = GS = " + GS); assertTrue("isGBsys( GBsys(Raksanyi) )", bb.isGB(GS)); String s = GS.toString() + ", " + GS.toScript(); //System.out.println("s = " + s + ", " + s.length()); assertTrue("length( string(GS) ) >= 10500", s.length() >= 10500); G = GS.getCGB(); //System.out.println("cgb( GS ) = " + G); assertTrue("isCGB( CGB(Raksanyi) )", bb.isGB(G)); // as regular ring RReductionSeq>> res; RGroebnerBasePseudoSeq>> rbb; List>>> Gr, Grbc, GBr; Gr = PolyUtilApp. toProductRes(GS.list); // list of colored systems //System.out.println("Gr = " + Gr); res = new RReductionSeq>>(); Grbc = res.booleanClosure(Gr); //System.out.println("Grbc = " + Grbc); RingFactory>> cofac = Grbc.get(0).ring.coFac; //System.out.println("cofac = " + cofac.toScript()); rbb = new RGroebnerBasePseudoSeq>>(cofac); //System.out.println("isGB(Grbc) = " + rbb.isGB(Grbc)); assertTrue("isGB(Grbc)", rbb.isGB(Grbc)); GBr = rbb.GB(Grbc); //System.out.println("GBr = " + GBr); assertTrue("isRGB( RGB(Raksanyi) )", rbb.isGB(GBr)); } } java-algebra-system-2.7.200/trc/edu/jas/application/ComplexRootTest.java000066400000000000000000000374201445075545500261470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import edu.jas.ufd.Squarefree; import edu.jas.ufd.SquarefreeFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RootUtil tests with JUnit. * @author Heinz Kredel */ public class ComplexRootTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a ComplexRootTest object. * @param name String. */ public ComplexRootTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ComplexRootTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing rfac; GenPolynomialRing> dfac; ComplexRing cfac; BigRational eps; Complex ceps; BigDecimal deps; GenPolynomial> a, b, c, d, e; int rl = 1; int kl = 3; int ll = 3; int el = 5; float q = 0.7f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new ComplexRing(new BigRational(1)); String[] vars = new String[] { "z" }; dfac = new GenPolynomialRing>(cfac, to, vars); rfac = new GenPolynomialRing(new BigRational(1), to, vars); eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); ceps = new Complex(cfac, eps); deps = new BigDecimal( Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION - 2)); } @Override protected void tearDown() { a = b = c = d = e = null; dfac = null; cfac = null; eps = null; } /** * Test complex roots, imaginary. */ public void testComplexRootsImag() { //Complex I = cfac.getIMAG(); //a = dfac.parse("z^3 - i2"); //a = dfac.random(ll+1).monic(); //a = dfac.parse("z^7 - 2 z"); a = dfac.parse("z^6 - i3"); //System.out.println("a = " + a); List>> roots; roots = RootFactoryApp. complexAlgebraicNumbersComplex(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); for (Complex> root : roots) { //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " + root.getIm().decimalMagnitude() + " i"); assertTrue("f(r) == 0: " + root, RootFactoryApp. isRoot(a, root)); } } /* * Test complex roots, random polynomial. */ public void testComplexRootsRand() { //Complex I = cfac.getIMAG(); a = dfac.random(2, ll, el, 0.37f).monic(); if (a.isZERO() || a.isONE()) { a = dfac.parse("z^6 - i3"); } //a = dfac.parse("z^3 - ( 1600/6123i-280/2041 )"); // fail, todo //a = dfac.parse("z^3 - ( 1600/6123 )"); // fail, shows only one root //a = dfac.parse("z^3 - ( 16/32i-280/2041 )"); // okay, 3 roots Squarefree> sqf = SquarefreeFactory .> getImplementation(cfac); a = sqf.squarefreePart(a); //System.out.println("a = " + a); List>> roots; roots = RootFactoryApp. complexAlgebraicNumbersComplex(a); //roots = RootFactoryApp. complexAlgebraicNumbersSquarefree(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots - deg(a): " + (roots.size() - a.degree(0)) + ", a = " + a, roots.size() == a.degree(0)); for (Complex> root : roots) { //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " + root.getIm().decimalMagnitude() + " i"); assertTrue("f(r) == 0: " + root, RootFactoryApp. isRoot(a, root)); } } /** * Test polynomial with complex roots. */ public void testPolynomialComplexRoots() { a = dfac.parse("z^3 - 2"); //System.out.println("a = " + a); List>> roots = RootFactoryApp . complexAlgebraicNumbersComplex(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); for (Complex> car : roots) { //System.out.println("car = " + car); RealAlgebraicRing rfac = car.getRe().ring; rfac.setField(true); // ?? to check assertTrue("isField(rfac) ", rfac.isField()); assertTrue("f(r) == 0: " + car, RootFactoryApp. isRoot(a, car)); } Complex> root = roots.get(2); // 0,1,2) //System.out.println("a = " + a); //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " // + root.getIm().decimalMagnitude() + " i"); //System.out.println("root = " + root.getRe() + " + " + root.getIm() + " i"); //String vre = root.getRe().toString().replace("{", "").replace("}", "").trim(); //String vim = root.getIm().toString().replace("{", "").replace("}", "").trim(); //System.out.println("vre = " + vre); //System.out.println("vim = " + vim); //String IM = root.ring.getIMAG().toString().replace("{", "").replace("}", "").replace(" ", "").trim(); //System.out.println("IM = " + IM); GenPolynomialRing>> cring = new GenPolynomialRing>>( root.ring, to, new String[] { "t" }); //List>>> gens = cring.generators(); //System.out.println("gens = " + gens); GenPolynomial>> cpol; //cpol = cring.random(1, 4, 4, q); //cpol = cring.univariate(0,3L).subtract(cring.fromInteger(2L)); //cpol = cring.univariate(0,3L).subtract(gens.get(2)); //cpol = cring.univariate(0,5L).subtract(cring.univariate(0,2L).multiply(root)); //cpol = cring.univariate(0,4L).subtract(root); //cpol = cring.univariate(0,4L).subtract(root.multiply(root)); //cpol = cring.univariate(0,3L).subtract(cring.univariate(0,1L).multiply(root).sum(root.multiply(root))); cpol = cring.univariate(0, 2L).subtract(root.multiply(root)); // okay //cpol = cring.univariate(0,3L).subtract(root.multiply(root)); // okay //cpol = cring.univariate(0,3L).subtract(root.multiply(root).multiply(root)); // not much sense r^3 = 2 ///String vpol = vre + " + " + IM + " " + vim; //String vpol = " 3 + " + IM + " * 3 "; //String vpol = " 3i3 "; //String vpol = IM + " " + vim; //String vpol = " 2 ";// + vre; // + " " + IM; //String vpol = vre; // + " " + IM; //System.out.println("vpol = " + vpol); //cpol = cring.univariate(0, 3L).subtract(cring.parse(vpol)); cpol = cpol.monic(); //System.out.println("cpol = " + cpol); //long dd = cpol.degree(0); Squarefree>> sen = SquarefreeFactory .>> getImplementation(root.ring); cpol = sen.squarefreePart(cpol); //if (cpol.degree(0) < dd) { //System.out.println("cpol = " + cpol); //} //System.out.println("cpol = " + cpol); // new version with recursion: with real factorization long t1 = System.currentTimeMillis(); List>>> croots = RootFactoryApp .> complexAlgebraicNumbersComplex(cpol); t1 = System.currentTimeMillis() - t1; assertTrue("nonsense " + t1, t1 >= 0L); //System.out.println("\na = " + a.toScript()); //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " // + root.getIm().decimalMagnitude() + " i"); //System.out.println("a = " + a); //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " // + root.getIm().decimalMagnitude() + " i"); //System.out.println("root = " + root.getRe() + " + (" + root.getIm() + ") i"); //System.out.println("root.ring = " + root.ring); //System.out.println("cpol = " + cpol); //System.out.println("cpol.ring = " + cpol.ring); //System.out.println("croots = " + croots); for (Complex>> croot : croots) { //System.out.println("croot = " + croot); //System.out.println("croot = " + croot.getRe() + " + ( " + croot.getIm() + ") i"); //System.out.println("croot.ring = " + croot.ring); //magnitude()); //System.out.println("croot = " + croot.getRe().decimalMagnitude() + " + " // + croot.getIm().decimalMagnitude() + " i"); assertTrue("f(r) == 0: " + croot, RootFactoryApp.> isRoot(cpol, croot)); } assertTrue("#croots == deg(cpol) " + croots.size() + " != " + cpol.degree(0), croots.size() == cpol.degree(0)); // existing version with winding number and recursion: but only one step long t2 = System.currentTimeMillis(); List>> coroots = edu.jas.root.RootFactory .> complexAlgebraicNumbersComplex(cpol); t2 = System.currentTimeMillis() - t2; assertTrue("nonsense " + t2, t2 >= 0L); //System.out.println("\ncpol = " + cpol); //System.out.println("root = " + root.getRe() + " + (" + root.getIm() + ") i"); //System.out.println("root = " + root.getRe().decimalMagnitude() + " + " // + root.getIm().decimalMagnitude() + " i"); for (edu.jas.root.ComplexAlgebraicNumber> cr2 : coroots) { //System.out.println("r2.ring = " + cr2.ring); //magnitude()); assertTrue("f(r) == 0: " + cr2, edu.jas.root.RootFactory .> isRootComplex(cpol, cr2)); } // decimal for comparison long t3 = System.currentTimeMillis(); for (Complex>> croot : croots) { String crs = croot.getRe().decimalMagnitude() + " + " + croot.getIm().decimalMagnitude() + " i"; //System.out.println("croot = " + crs); assertFalse("crs not empty", crs.length() == 0); // java-5 } t3 = System.currentTimeMillis() - t3; assertTrue("nonsense " + t3, t3 >= 0L); long t4 = System.currentTimeMillis(); for (edu.jas.root.ComplexAlgebraicNumber> cr2 : coroots) { String crs = cr2.decimalMagnitude().toString(); //System.out.println("r2.dec = " + crs); assertFalse("crs not empty", crs.length() == 0); // java-5 } t4 = System.currentTimeMillis() - t4; assertTrue("nonsense " + t4, t4 >= 0L); assertTrue("#coroots == deg(cpol) ", coroots.size() == cpol.degree(0)); //System.out.println("time, real ideal = " + t1 + "+" + t3 + ", complex winding = " + t2 + "+" + t4 + " milliseconds"); } /** * Test 0-dim ideal with complex roots. */ public void testIdealComplexRoots() { String[] vars = new String[] { "x", "z" }; rfac = new GenPolynomialRing(new BigRational(1), to, vars); GenPolynomial ar, br; ar = rfac.parse("z^3 - 2"); br = rfac.parse("x^2 - 3"); //System.out.println("ar = " + ar + ", deg(ar) = " + ar.degree(1)); //System.out.println("br = " + br + ", deg(br) = " + br.degree(0)); List> M; M = new ArrayList>(); M.add(ar); M.add(br); //System.out.println("M = " + M); Ideal I = new Ideal(rfac, M); //System.out.println("I = " + I); List>> roots = PolyUtilApp. complexRootTuples(I, eps); //System.out.println("roots = " + roots); assertEquals("#roots == deg(a)*deg(b) ", roots.size(), ar.degree(1) * br.degree(0)); a = PolyUtil. toComplex(dfac, ar); b = PolyUtil. toComplex(dfac, br); GenPolynomialRing> pfac; pfac = new GenPolynomialRing>(new ComplexRing(new BigDecimal(1)), rfac); GenPolynomial> ac, bc; ac = PolyUtil. complexDecimalFromRational(pfac, a); bc = PolyUtil. complexDecimalFromRational(pfac, b); List>> Mc; Mc = new ArrayList>>(); Mc.add(ac); Mc.add(bc); //System.out.println("Mc = " + Mc); assertTrue("isComplexRoots: " + roots, PolyUtilApp. isComplexRoots(Mc, roots, deps)); } /** * Test 0-dim ideal with real roots. */ public void testIdealRealRoots() { String[] vars = new String[] { "x", "z" }; rfac = new GenPolynomialRing(new BigRational(1), to, vars); GenPolynomial ar, br; ar = rfac.parse("z^3 - 2"); br = rfac.parse("x^2 - 3"); //System.out.println("ar = " + ar + ", deg(ar) = " + ar.degree(1)); //System.out.println("br = " + br + ", deg(br) = " + br.degree(0)); List> M; M = new ArrayList>(); M.add(ar); M.add(br); //System.out.println("M = " + M); Ideal I = new Ideal(rfac, M); //System.out.println("I = " + I); List> roots = PolyUtilApp. realRootTuples(I, eps); //System.out.println("roots = " + roots); assertEquals("#roots == deg(a)*deg(b) ", roots.size(), 2); GenPolynomialRing pfac; pfac = new GenPolynomialRing(new BigDecimal(1), rfac); List> Md; Md = new ArrayList>(); Md.add(PolyUtil. decimalFromRational(pfac, ar)); Md.add(PolyUtil. decimalFromRational(pfac, br)); //System.out.println("Md = " + Md); assertTrue("isRealRoots: " + roots, PolyUtilApp. isRealRoots(Md, roots, deps)); } } java-algebra-system-2.7.200/trc/edu/jas/application/ExtensionFieldBuilderTest.java000066400000000000000000000447021445075545500301240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.RootFactory; import edu.jas.structure.Power; import edu.jas.structure.RingElem; import edu.jas.structure.RingFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ExtensionFieldBuilder tests with JUnit. * @author Heinz Kredel */ public class ExtensionFieldBuilderTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ExtensionFieldBuilderTest object. * @param name String. */ public ExtensionFieldBuilderTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ExtensionFieldBuilderTest.class); return suite; } ExtensionFieldBuilder builder; @Override protected void setUp() { builder = null; } @Override protected void tearDown() { builder = null; ComputerThreads.terminate(); } /** * Test construction Q(sqrt(2))(x)(sqrt(x)) by hand. */ public void testConstructionF0() { BigRational bf = new BigRational(1); GenPolynomialRing pf = new GenPolynomialRing(bf, new String[] { "w2" }); GenPolynomial a = pf.parse("w2^2 - 2"); AlgebraicNumberRing af = new AlgebraicNumberRing(a); GenPolynomialRing> tf = new GenPolynomialRing>( af, new String[] { "x" }); QuotientRing> qf = new QuotientRing>(tf); GenPolynomialRing>> qaf = new GenPolynomialRing>>( qf, new String[] { "wx" }); GenPolynomial>> b = qaf.parse("wx^2 - x"); AlgebraicNumberRing>> fac = new AlgebraicNumberRing>>( b); //System.out.println("fac = " + fac.toScript()); List>>> gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); AlgebraicNumber>> elem = fac.random(2); if (elem.isZERO() || elem.isONE()) { elem = gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = elem.multiply(elem); } //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); AlgebraicNumber>> inv = elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); AlgebraicNumber>> e = elem.multiply(inv); assertTrue("e / e == 1 " + e, e.isONE()); } /** * Test construction Q(sqrt(2))(x)(sqrt(x)) by extension field builder. */ @SuppressWarnings("unchecked") public void testConstructionF1() { builder = ExtensionFieldBuilder.baseField(new BigRational(1)); //System.out.println("builder = " + builder.toString()); RingFactory fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.algebraicExtension("w2", "w2^2 - 2"); //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.transcendentExtension("x"); //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.algebraicExtension("wx", "wx^2 - x"); // number of { } resolved //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); RingElem elem = (RingElem) fac.random(2); if (elem.isZERO() || elem.isONE()) { elem = (RingElem) gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = (RingElem) elem.multiply(elem); } //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem inv = (RingElem) elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); RingElem a = (RingElem) elem.multiply(inv); assertTrue("e / e == 1 " + a, a.isONE()); } /** * Test construction Q(x)(sqrt(2))(sqrt(x)) by extension field builder. */ @SuppressWarnings("unchecked") public void testConstructionF2() { builder = ExtensionFieldBuilder.baseField(new BigRational(1)); //System.out.println("builder = " + builder.toString()); RingFactory fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.transcendentExtension("x"); //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.algebraicExtension("w2", "w2^2 - 2"); //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); builder = builder.algebraicExtension("wx", "wx^2 - x"); // number of { } resolved //System.out.println("builder = " + builder.toString()); fac = builder.build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); RingElem elem = (RingElem) fac.random(1); if (elem.isZERO() || elem.isONE()) { elem = (RingElem) gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = (RingElem) elem.multiply(elem); } //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem inv = (RingElem) elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); RingElem a = (RingElem) elem.multiply(inv); assertTrue("e / e == 1 " + a, a.isONE()); } /** * Test construction Z_p(sqrt(2))(x)(sqrt(x)) by extension field builder. */ @SuppressWarnings("unchecked") public void testConstructionF3() { RingFactory fac = ExtensionFieldBuilder.baseField(new ModLongRing(7)) .algebraicExtension("w2", "w2^2 - 3").transcendentExtension("x") .algebraicExtension("wx", "wx^7 - x").build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); RingElem elem = (RingElem) fac.random(2); if (elem.isZERO() || elem.isONE()) { elem = (RingElem) gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = (RingElem) elem.multiply(elem); } //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem inv = (RingElem) elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); RingElem a = (RingElem) elem.multiply(inv); assertTrue("e / e == 1 " + a, a.isONE()); } /** * Test construction Q(+3rt(3))(+sqrt(+3rt(3)))(+5rt(2)) by extension field * builder. */ @SuppressWarnings("unchecked") public void testConstructionR1() { RingFactory fac = ExtensionFieldBuilder.baseField(new BigRational(1)) .realAlgebraicExtension("q", "q^3 - 3", "[1,2]") .realAlgebraicExtension("w", "w^2 - q", "[1,2]") .realAlgebraicExtension("s", "s^5 - 2", "[1,2]").build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); RingElem elem = (RingElem) fac.random(2); if (elem.isZERO() || elem.isONE()) { elem = (RingElem) gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = (RingElem) elem.multiply(elem); } //elem = (RingElem)elem.negate(); //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); //BigDecimal ed = new BigDecimal(((Rational)elem).getRational()); //System.out.println(" ~ " + ed); RingElem inv = (RingElem) elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); //BigDecimal id = new BigDecimal(((Rational)inv).getRational()); //System.out.println(" ~ " + id); RingElem a = (RingElem) elem.multiply(inv); //System.out.println("a = " + a); //System.out.println(" ~ " + ed.multiply(id)); assertTrue("e / e == 1 " + a, a.isONE()); } /** * Test construction Q(sqrt(-1))(+3rt(i)) by extension field builder. */ @SuppressWarnings("unchecked") public void testConstructionC1() { ComplexRing cf = new ComplexRing(new BigRational(1)); //System.out.println("cf = " + cf.toScript()); RingFactory fac = ExtensionFieldBuilder.baseField(cf) .complexAlgebraicExtension("w2", "w2^2 + 2", "[-1i0,1i2]") //.complexAlgebraicExtension("q3", "q3^3 + { w2 }","[-1i0,1i2]") // not possible .build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 3 " + s, s == 3); RingElem elem = (RingElem) fac.random(2); if (elem.isZERO() || elem.isONE()) { elem = (RingElem) gens.get(s - 1).sum(gens.get(s - 2)); //elem = (RingElem)gens.get(s-1).multiply(gens.get(s-2)); elem = (RingElem) elem.multiply(elem); } //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem inv = (RingElem) elem.inverse(); //System.out.println("inv = " + inv.toScript()); //System.out.println("inv = " + inv); RingElem a = (RingElem) elem.multiply(inv); //System.out.println("a = " + a); assertTrue("e / e == 1 " + a, a.isONE()); } /** * Test construction Q(+3rt(3))(+sqrt(+3rt(3)))(+5rt(2))[y] by extension * field builder and real root calculation. */ @SuppressWarnings("unchecked") public void testConstructionR2factory() { RingFactory fac = ExtensionFieldBuilder.baseField(new BigRational(1)) .realAlgebraicExtension("q", "q^3 - 3", "[1,2]") .realAlgebraicExtension("w", "w^2 - q", "[1,2]") .realAlgebraicExtension("s", "s^5 - 2", "[1,2]").build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); GenPolynomialRing pfac = new GenPolynomialRing(fac, new String[] { "y" }); GenPolynomial elem = pfac.parse("y^2 - w s"); //elem = (RingElem)elem.negate(); //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); List> roots = RootFactory .realAlgebraicNumbers((GenPolynomial) elem); //System.out.println("roots = " + roots); assertTrue("#roots == 2 " + roots, roots.size() == 2); for (RealAlgebraicNumber root : roots) { //BigDecimal id = new BigDecimal(root.getRational()); //System.out.println("root = " + root); //System.out.println(" ~ " + id); RealAlgebraicNumber inv = root.inverse(); //System.out.println("inv = " + inv); //BigDecimal ivd = new BigDecimal(inv.getRational()); //System.out.println(" ~ " + ivd); RealAlgebraicNumber a = root.multiply(inv); //System.out.println("a = " + a); //System.out.println(" ~ " + id.multiply(ivd)); assertTrue("y / y == 1 " + a, a.isONE()); } } /** * Test construction by extension field builder and multiple algebraic * extension. */ @SuppressWarnings("unchecked") public void testConstructionM1() { RingFactory fac = ExtensionFieldBuilder.baseField(new BigRational(1)) .algebraicExtension("q,w,s", "( q^3 - 3, w^2 - q, s^5 - 2)").build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); GenPolynomialRing pfac = (GenPolynomialRing) ExtensionFieldBuilder.baseField(fac) .polynomialExtension("y").build(); GenPolynomial elem = pfac.parse("y^2 - w s"); //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem r = elem.trailingBaseCoefficient(); RingElem t = (RingElem) r.inverse(); RingElem u = (RingElem) r.multiply(t); //System.out.println("r = " + r); //System.out.println("t = " + t); //System.out.println("r*t = " + u); assertTrue("r*t == 1: ", u.isONE()); elem = elem.multiply(elem.negate()); //System.out.println("elem = " + elem); elem = Power.positivePower(elem, 3); //System.out.println("elem = " + elem); assertFalse("elem == 0 " + elem, elem.isZERO()); } /** * Test construction by extension field builder and multiple transcendent * extension. */ @SuppressWarnings("unchecked") public void testConstructionM2() { RingFactory fac = ExtensionFieldBuilder.baseField(new BigRational(1)).algebraicExtension("q,w,s", "") .build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 4 " + s, s == 4); GenPolynomialRing pfac = (GenPolynomialRing) ExtensionFieldBuilder.baseField(fac) .polynomialExtension("y").build(); GenPolynomial elem = pfac.parse("y^2 - w s"); //System.out.println("elem = " + elem.toScript()); //System.out.println("elem = " + elem); RingElem r = elem.trailingBaseCoefficient(); RingElem t = (RingElem) r.inverse(); RingElem u = (RingElem) r.multiply(t); //System.out.println("r = " + r); //System.out.println("t = " + t); //System.out.println("r*t = " + u); assertTrue("r*t == 1: ", u.isONE()); elem = elem.multiply(elem.negate()); //System.out.println("elem = " + elem); elem = Power.positivePower(elem, 3); //System.out.println("elem = " + elem); assertFalse("elem == 0 " + elem, elem.isZERO()); } /** * Test construction of matrix extensions. */ @SuppressWarnings("unchecked") public void testConstructionMat() { RingFactory fac = ExtensionFieldBuilder.baseField(BigRational.ONE).transcendentExtension("a").build(); //System.out.println("fac = " + fac.toScript()); List gens = fac.generators(); int s = gens.size(); //System.out.println("gens = " + gens); assertTrue("#gens == 2 " + s, s == 2); GenMatrixRing mfac = (GenMatrixRing) ExtensionFieldBuilder.baseField(fac).matrixExtension(3).build(); //System.out.println("mfac = " + mfac.toScript()); List mgens = mfac.generators(); s = mgens.size(); //System.out.println("mgens(1) = " + mgens.get(1)); assertTrue("#gens == 9*2 " + s, s == 18); GenMatrix elem = mfac.parse("[ [1,a,2], [0,1,1], [-1,1,1] ]"); //System.out.println("elem = " + elem); GenMatrix elemt = elem.transpose(); //System.out.println("elem**t = " + elemt); elem = elem.multiply(elemt); //System.out.println("elem = " + elem); GenMatrix elemp = (GenMatrix) elem.power(3); //System.out.println("elem**3 = " + elemp); GenMatrix elemi = elem.inverse(); //System.out.println("elem^-1 = " + elemi); GenMatrix mat = elem.multiply(elemi); //System.out.println("mat = " + mat); assertTrue("elem*elem^-1 == 1 " + mat, mat.isONE()); } } java-algebra-system-2.7.200/trc/edu/jas/application/FactorAlgebraicPrimTest.java000066400000000000000000000122641445075545500275330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor algebraic tests with JUnit. * @author Heinz Kredel */ public class FactorAlgebraicPrimTest extends TestCase { /** * main. */ public static void main(String[] args) { // junit.textui.TestRunner.run(suite()); } /** * Constructor. * @param name String. */ public FactorAlgebraicPrimTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorAlgebraicPrimTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void testDummy() { } /** * Test algebraic factorization. * */ public void testAlgebraicFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 2); agen = agen.sum(pfac.getONE()); // x^2 + 1 AlgebraicNumberRing afac = new AlgebraicNumberRing(agen, true); GenPolynomialRing> apfac = new GenPolynomialRing>( afac, 1, to, vars); // univariate //System.out.println("agen = " + agen); //System.out.println("afac = " + afac); //System.out.println("apfac = " + apfac); FactorAlgebraicPrim fac = new FactorAlgebraicPrim(afac); for (int i = 1; i < 7; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = apfac.random(2, ll + i, el + i, q); //a = a.monic(); GenPolynomial> b = apfac.random(2, ll + i, el + i, q); if (b.degree() == 0) { b = b.multiply(apfac.univariate(0)); } //b = b.monic(); //if ( false && ! a.leadingBaseCoefficient().isONE() ) { //continue; //ExpVector e = a.leadingExpVector(); //a.doPutToMap(e,cfac.getONE()); //} if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } //a = apfac.univariate(0,2).sum( apfac.getONE() ); // x^2 + 1 //a = a.multiply(a); //a = a.multiply( apfac.univariate(0,2).subtract( apfac.getONE() ) ); // x^2 - 1 //a = apfac.univariate(0,3).subtract( apfac.getONE() ); // x^3 - 1 //a = apfac.univariate(0,3).sum( apfac.getONE() ); // x^3 + 1 a = c.multiply(b); //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> smi, smr; long si = System.currentTimeMillis(); smi = fac.baseFactors(a); si = System.currentTimeMillis() - si; //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (smi.size() >= facs) { assertTrue("#facs < " + facs, smi.size() >= facs); } else { System.out.println("smi.size() < facs = " + facs); } boolean t = fac.isFactorization(a, smi); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); long sr = System.currentTimeMillis(); smr = new edu.jas.ufd.FactorAlgebraic(afac).baseFactors(a); sr = System.currentTimeMillis() - sr; //System.out.println("\na = " + a); //System.out.println("smr = " + smr); if (smr.size() >= facs) { assertTrue("#facs < " + facs, smr.size() >= facs); } else { System.out.println("smr.size() < facs = " + facs); } t = fac.isFactorization(a, smr); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); //System.out.println("time: si = " + si + ", sr = " + sr + " milliseconds"); assertTrue("positive times", sr >= 0L && si >= 0L); assertEquals("smi == smr: ", smi, smr); } } } java-algebra-system-2.7.200/trc/edu/jas/application/FactorRealRealTest.java000066400000000000000000000106741445075545500265240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.SortedMap; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.root.Interval; import edu.jas.root.RootUtil; import edu.jas.ufd.FactorAbstract; /** * Factor real algebraic tests with JUnit. * @author Heinz Kredel */ public class FactorRealRealTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorRealRealTest object. * @param name String. */ public FactorRealRealTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorRealRealTest.class); return suite; } int rl = 1; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test real real algebraic factorization. */ public void testRealRealAlgebraicFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational bfac = new BigRational(1); ComplexRing cfac = new ComplexRing(bfac); String[] vars = new String[] { "z" }; GenPolynomialRing> dfac = new GenPolynomialRing>(cfac, to, vars); GenPolynomial> ap = dfac.parse("z^3 - i2"); List>> roots = RootFactoryApp. complexAlgebraicNumbersComplex(ap); //System.out.println("ap = " + ap); //System.out.println("roots = " + roots); assertTrue("#roots == deg(ap) ", roots.size() == ap.degree(0)); for ( Complex> root : roots ) { RealAlgebraicRing rfac = root.getRe().ring; rfac.setField(true); // ?? to check assertTrue("isField(rfac) ", rfac.isField()); FactorRealReal fac = new FactorRealReal(rfac); //FactorAbstract> fac = FactorFactory.> getImplementation(rfac); String[] var = new String[] { "t" }; GenPolynomialRing> rpfac = new GenPolynomialRing>(rfac, to, var); // univariate GenPolynomial> a; GenPolynomial> b = rpfac.random(2, ll, el, q); GenPolynomial> c = rpfac.random(2, ll, el, q); if (b.degree() == 0) { b = b.multiply(rpfac.univariate(0)); } //b = b.monic(); int facs = 0; if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //a = c; //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { System.out.println("sm.size() < facs = " + facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); break; } } } java-algebra-system-2.7.200/trc/edu/jas/application/FactorTest.java000066400000000000000000000255371445075545500251200ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; import edu.jas.ufd.FactorRational; import edu.jas.ufd.Factorization; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import edu.jas.ufd.FactorAlgebraic; import edu.jas.ufd.FactorQuotient; import edu.jas.ufd.FactorModular; import edu.jas.ufd.FactorInteger; /** * Factor tests with JUnit. * @see edu.jas.ufd.FactorTest * @author Heinz Kredel */ public class FactorTest extends TestCase { /** * main. */ public static void main(String[] args) { // junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorTest object. * @param name String. */ public FactorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test factory. */ public void testFactory() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation(mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); ModLongRing ml = new ModLongRing(19, true); Factorization ufdml = FactorFactory.getImplementation(ml); //System.out.println("ufdml = " + ufdml); assertTrue("ufd != Modular " + ufdml, ufdml instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation(bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation(br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory.getImplementation(am); //System.out.println("ufdam = " + ufdam); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory.getImplementation(ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory.getImplementation(qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); } /** * Test factory generic. */ @SuppressWarnings("unchecked") public void testFactoryGeneric() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation((RingFactory) mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation((RingFactory) bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation((RingFactory) br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory.getImplementation((RingFactory) am); //System.out.println("ufdam = " + ufdam); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory.getImplementation((RingFactory) ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory.getImplementation((RingFactory) qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Factorization> ufdqm = FactorFactory.getImplementation((RingFactory) qmfac); //System.out.println("ufdqm = " + ufdqm); assertTrue("ufd != Quotient " + ufdqm, ufdqm instanceof FactorQuotient); prfac = new GenPolynomialRing(br, 2); GenPolynomialRing> rrfac = new GenPolynomialRing>( prfac, 1); Factorization ufdrr = FactorFactory.getImplementation((RingFactory) rrfac); //System.out.println("ufdrr = " + ufdrr); assertTrue("ufd != GenPolynomial> " + ufdrr, ufdrr instanceof FactorRational); } /** * Test factory specific. */ public void testFactorySpecific() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation(mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation(bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation(br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory. getImplementation(am); //System.out.println("ufdam = " + ufdam); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory. getImplementation(ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory. getImplementation(qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Factorization> ufdqm = FactorFactory. getImplementation(qmfac); //System.out.println("ufdqm = " + ufdqm); assertTrue("ufd != Quotient " + ufdqm, ufdqm instanceof FactorQuotient); prfac = new GenPolynomialRing(br, 2); Factorization ufdrr = FactorFactory. getImplementation(prfac); //System.out.println("ufdrr = " + ufdrr); assertTrue("ufd != GenPolynomial> " + ufdrr, ufdrr instanceof FactorRational); //GenPolynomialRing> rrfac = new GenPolynomialRing>( // prfac, 1); //RingFactory> rrfac1 = (RingFactory>) (RingFactory) rrfac; //ufdrr = FactorFactory. getImplementation(rrfac1); //.coFac); //ufdrr = FactorFactory.>getImplementation(rrfac1); //.coFac); //ufdrr = FactorFactory.getImplementation(rrfac.coFac); //System.out.println("ufdrr = " + ufdrr); //assertTrue("ufd != GenPolynomial> " + ufdrr, // ufdrr instanceof FactorRational); } } java-algebra-system-2.7.200/trc/edu/jas/application/GBAlgorithmBuilderTest.java000066400000000000000000000446251445075545500273470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.DGroebnerBaseSeq; import edu.jas.gb.EGroebnerBaseSeq; import edu.jas.gb.GBOptimized; import edu.jas.gb.GBProxy; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.GroebnerBaseSeqIter; import edu.jas.gb.GroebnerBaseSigSeqIter; import edu.jas.gb.GroebnerBaseF5zSigSeqIter; import edu.jas.gb.GroebnerBaseGGVSigSeqIter; import edu.jas.gb.GroebnerBaseArriSigSeqIter; import edu.jas.gb.GroebnerBaseParIter; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.GroebnerBaseFGLM; import edu.jas.gbufd.GroebnerBaseWalk; import edu.jas.gbufd.GroebnerBasePseudoSeq; import edu.jas.gbufd.GroebnerBaseRational; import edu.jas.gbufd.GroebnerBaseQuotient; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * GBAlgorithmBuilder tests with JUnit. * @author Heinz Kredel */ public class GBAlgorithmBuilderTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GBAlgorithmBuilderTest object. * @param name String. */ public GBAlgorithmBuilderTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GBAlgorithmBuilderTest.class); return suite; } GBAlgorithmBuilder builder; @Override protected void setUp() { builder = null; } @Override protected void tearDown() { builder = null; ComputerThreads.terminate(); } /** * Test basic construction for BigRational. */ public void testConstructionRational() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); String s = ab.toString() + " :: " + ab.toScript(); //System.out.println("s = " + s + ", len(s) = " + s.length()); assertTrue("len(s) >= 150 " + s, s.length() >= 150); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseSeq); } /** * Test construction for BigRational and FGLM. */ public void testConstructionRationalFGLM() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.graded(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseFGLM); } /** * Test construction for BigRational and Groebner walk. */ public void testConstructionRationalWalk() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.walk(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseWalk); } /** * Test construction for BigRational and parallel. */ public void testConstructionRationalParallel() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.parallel(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBProxy); GBProxy bbp = (GBProxy) bb; assertTrue("instance of " + bbp.e1, bbp.e1 instanceof GroebnerBaseSeq); assertTrue("instance of " + bbp.e2, bbp.e2 instanceof GroebnerBaseParallel); } /** * Test construction for BigRational fraction free and parallel. */ public void testConstructionRationalFFParallel() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.fractionFree(); //System.out.println("ab = " + ab); ab = ab.parallel(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBProxy); GBProxy bbp = (GBProxy) bb; assertTrue("instance of " + bbp.e1, bbp.e1 instanceof GroebnerBaseRational); assertTrue("instance of " + bbp.e2, bbp.e2 instanceof GroebnerBaseRational); } /** * Test construction for BigRational and optimize. */ public void testConstructionRationalOptimized() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.optimize(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBOptimized); } /** * Test construction for BigRational and fraction free. */ public void testConstructionRationalFF() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.fractionFree(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseRational); } /** * Test basic construction for BigInteger. */ public void testConstructionInteger() { BigInteger bf = new BigInteger(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBasePseudoSeq); } /** * Test construction for d-GB BigInteger. */ public void testConstructionIntegerDGB() { BigInteger bf = new BigInteger(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.domainAlgorithm(GBFactory.Algo.dgb); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof DGroebnerBaseSeq); } /** * Test construction for e-GB BigInteger. */ public void testConstructionIntegerEGB() { BigInteger bf = new BigInteger(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.domainAlgorithm(GBFactory.Algo.egb); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof EGroebnerBaseSeq); } /** * Test construction for BigRational and more. */ public void testConstructionRationalMore() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GroebnerBaseAbstract bb = GBAlgorithmBuilder. polynomialRing(pf) .fractionFree().optimize().build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBOptimized); bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().parallel().optimize().build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBOptimized); bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().graded().parallel() .optimize().build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBOptimized); } /** * Test construction for BigRational and more and compute. */ public void testConstructionRationalMoreCompute() { List> cp = ExamplesGeoTheorems.getExample(); GenPolynomialRing pf = cp.get(0).ring; GroebnerBaseAbstract bb; //bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().parallel().optimize().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).parallel().optimize().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).build(); bb = GBAlgorithmBuilder. polynomialRing(pf).optimize().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).parallel().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().optimize().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).parallel().fractionFree().optimize().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).optimize().fractionFree().build(); //bb = GBAlgorithmBuilder. polynomialRing(pf).fractionFree().optimize().parallel().build(); //System.out.println("bb = " + bb); //assertTrue("instance of " + bb, bb instanceof GBOptimized); List> gb; long t; t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); assertTrue("t >= 0: ", t >= 0L); // praise findbugs assertTrue("isGB: ", bb.isGB(gb)); bb.terminate(); //System.out.println("gb = " + gb); //System.out.println("bb = " + bb); } /** * Test construction for BigRational and pairlists and compute. */ public void testConstructionRationalParilistCompute() { List> cp = ExamplesGeoTheorems.getExample(); GenPolynomialRing pf = cp.get(0).ring; GroebnerBaseAbstract bb; List> gb; long t; bb = GBAlgorithmBuilder. polynomialRing(pf).normalPairlist().build(); t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); assertTrue("isGB: ", bb.isGB(gb)); bb = GBAlgorithmBuilder. polynomialRing(pf).syzygyPairlist().build(); t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); assertTrue("isGB: ", bb.isGB(gb)); bb = GBAlgorithmBuilder. polynomialRing(pf).simplePairlist().build(); t = System.currentTimeMillis(); gb = bb.GB(cp); t = System.currentTimeMillis() - t; //System.out.println("time(gb) = " + t); assertTrue("isGB: ", bb.isGB(gb)); assertTrue("t >= 0: ", t >= 0L); // for findbugs } /** * Test construction for BigRational and iterate. */ public void testConstructionRationalIterate() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.iterated(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseSeqIter); ab = GBAlgorithmBuilder. polynomialRing(pf); ab = ab.iterated().parallel(); //System.out.println("ab = " + ab); bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBProxy); GBProxy bbp = (GBProxy) bb; assertTrue("instance of " + bbp.e1, bbp.e1 instanceof GroebnerBaseSeqIter); assertTrue("instance of " + bbp.e2, bbp.e2 instanceof GroebnerBaseParIter); } /** * Test construction for BigRational and signature based GBs. */ public void testConstructionRationalSignatureBased() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); GBAlgorithmBuilder ab = GBAlgorithmBuilder. polynomialRing(pf); //System.out.println("ab = " + ab); ab = ab.F5(); //System.out.println("ab = " + ab); GroebnerBaseAbstract bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseSigSeqIter); assertTrue("instance of " + bb, bb instanceof GroebnerBaseF5zSigSeqIter); ab = GBAlgorithmBuilder. polynomialRing(pf); ab = ab.GGV(); //System.out.println("ab = " + ab); bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseSigSeqIter); assertTrue("instance of " + bb, bb instanceof GroebnerBaseGGVSigSeqIter); ab = GBAlgorithmBuilder. polynomialRing(pf); ab = ab.Arri(); //System.out.println("ab = " + ab); bb = ab.build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseSigSeqIter); assertTrue("instance of " + bb, bb instanceof GroebnerBaseArriSigSeqIter); } /** * Test construction for Quotient and parallel. */ public void testConstructionQuotient() { BigRational bf = new BigRational(1); String[] vars = new String[] { "a", "b", "c" }; GenPolynomialRing pf = new GenPolynomialRing(bf, vars); QuotientRing qr = new QuotientRing(pf); String[] varq = new String[] { "x", "y", "z" }; GenPolynomialRing> qf = new GenPolynomialRing>(qr, varq); GroebnerBaseAbstract> bb; GBProxy> bbp; bb = GBAlgorithmBuilder.> polynomialRing(qf).fractionFree().build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GroebnerBaseQuotient); bb = GBAlgorithmBuilder.> polynomialRing(qf).fractionFree().parallel(2).build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBProxy); bbp = (GBProxy>) bb; assertTrue("instance of " + bbp.e1, bbp.e1 instanceof GroebnerBaseQuotient); assertTrue("instance of " + bbp.e2, bbp.e2 instanceof GroebnerBaseQuotient); bb = GBAlgorithmBuilder.> polynomialRing(qf).fractionFree().graded().parallel() .build(); //System.out.println("bb = " + bb); assertTrue("instance of " + bb, bb instanceof GBProxy); bbp = (GBProxy>) bb; assertTrue("instance of " + bbp.e1, bbp.e1 instanceof GroebnerBaseFGLM); assertTrue("instance of " + bbp.e2, bbp.e2 instanceof GroebnerBaseParallel); } } java-algebra-system-2.7.200/trc/edu/jas/application/HenselMultUtilTest.java000066400000000000000000000417461445075545500266200ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.PrimeList; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import edu.jas.ufd.GCDFactory; import edu.jas.ufd.GreatestCommonDivisor; import edu.jas.ufd.HenselMultUtil; import edu.jas.ufd.NoLiftingException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * HenselMultUtil tests with JUnit. Two separate classes because of package * dependency. * @see edu.jas.ufd.HenselMultUtilTest * @author Heinz Kredel */ public class HenselMultUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a HenselMultUtilTest object. * @param name String. */ public HenselMultUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(HenselMultUtilTest.class); return suite; } TermOrder tord = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; int rl = 2; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, tord); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, tord); rfac = new GenPolynomialRing>(cfac, 1, tord); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; cfac = null; rfac = null; ComputerThreads.terminate(); } protected static java.math.BigInteger getPrime1() { return PrimeList.getLongPrime(60, 93); } protected static java.math.BigInteger getPrime2() { return PrimeList.getLongPrime(30, 35); } /** * Test multivariate diophant lifting. */ public void testDiophantLifting() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); //ModLongRing pl = new ModLongRing(p, false); //GenPolynomialRing pfac = new GenPolynomialRing(pm, 2, tord, new String[]{ "x", "y" }); GenPolynomialRing pfac = new GenPolynomialRing(pm, 3, tord, new String[] { "x", "y", "z" }); //GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(),pfac); BigInteger mi = m; long k = 5L; long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(5L); List V = new ArrayList(1); V.add(v); V.add(pkm.fromInteger(3L)); //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; //GenPolynomial dp; GenPolynomial sp; GenPolynomial tp; GenPolynomial rp; for (int i = 1; i < 2; i++) { a = dfac.random(kl + 7 * i, ll, el + 3, q).abs(); b = dfac.random(kl + 7 * i, ll, el + 2, q).abs(); //a = dfac.parse(" y^2 + 2 x y - 3 y + x^2 - 3 x - 4 "); //b = dfac.parse(" y^2 + 2 x y + 5 y + x^2 + 5 x + 4 "); //a = dfac.parse(" (x - 4 + y)*( x + y + 1 ) "); //b = dfac.parse(" (x + 4 + y)*( x + y + 1 ) "); //a = dfac.parse(" (x - 4 + y) "); ///a = dfac.parse(" (x - 13 + y) "); ///b = dfac.parse(" (x + 4 + y) "); //a = dfac.parse(" (x - 1)*(1 + x) "); //b = dfac.parse(" (x - 2)*(3 + x) "); //a = dfac.parse(" (x - 1)*(y + x) "); //b = dfac.parse(" (x - 2)*(y - x) "); //a = dfac.parse(" (x - 1)*(y + 1) "); //b = dfac.parse(" (x - 2)*(y - 1) "); //a = dfac.parse(" (x - 1)*(y^2 + 1) "); //b = dfac.parse(" (x - 2)*(y^2 - 1) "); //a = dfac.parse(" z + (y - 1)*(1 + y) "); //b = dfac.parse(" z + (y - 2)*(2 + y) "); //a = dfac.parse(" (y - 1)*(1 + y) "); //b = dfac.parse(" (y - 2)*(2 + y) "); ///a = dfac.parse(" (y - 3) "); //2 // tp = 47045880 = -1 ///b = dfac.parse(" (y - 1) "); // sp = 1 //a = dfac.parse(" (y - 4) "); // tp = 15681960 //b = dfac.parse(" (y - 1) "); // sp = 31363921 //a = dfac.parse(" (x - 3) "); // tp = 15681960, 1238049 //b = dfac.parse(" (x - 1) "); // sp = 31363921, -1238049 //a = dfac.parse(" ( y^2 + x^3 - 2 x ) "); //b = dfac.parse(" ( y - x^2 + 3 ) "); c = ufd.gcd(a, b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (!c.isUnit()) { continue; } //c = dfac.parse(" x y z "); //System.out.println("c = " + c); ap = PolyUtil. fromIntegerCoefficients(pkfac, a); bp = PolyUtil. fromIntegerCoefficients(pkfac, b); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //if (ap.degree(0) < 1 || bp.degree(0) < 1) { // continue; //} //System.out.println("\nap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); List> lift; try { lift = HenselMultUtil. liftDiophant(ap, bp, cp, V, d, k); // 5 is max sp = lift.get(0); tp = lift.get(1); //System.out.println("liftMultiDiophant:"); //System.out.println("sp = " + sp); //System.out.println("tp = " + tp); //System.out.println("isDiophantLift: " + HenselUtil. isDiophantLift(bp,ap,sp,tp,cp) ); GenPolynomialRing qfac = sp.ring; //System.out.println("qfac = " + qfac.toScript()); assertEquals("pkfac == qfac: " + qfac, pkfac, qfac); rp = bp.multiply(sp).sum(ap.multiply(tp)); // order assertFalse("rp != null: " + rp, rp == null); //System.out.println("\nrp = " + rp); //not true: System.out.println("a s + b t = c: " + cp.equals(rp)); //assertEquals("a s + b t = c ", dp,rp); //GenPolynomialRing cfac = pkfac.contract(1); ModInteger vp = pkfac.coFac.fromInteger(V.get(0).getSymmetricInteger().getVal()); GenPolynomial ya = pkfac.univariate(1); ya = ya.subtract(vp); ya = Power.> power(pkfac, ya, d + 1); //System.out.println("ya = " + ya); List> Y = new ArrayList>(); Y.add(ya); vp = pkfac.coFac.fromInteger(V.get(1).getSymmetricInteger().getVal()); GenPolynomial za = pkfac.univariate(0); za = za.subtract(vp); za = Power.> power(pkfac, za, d + 1); //System.out.println("za = " + za); Y.add(za); //System.out.println("\nY = " + Y); Ideal Yi = new Ideal(pkfac, Y); //System.out.println("Yi = " + Yi); ResidueRing Yr = new ResidueRing(Yi); //System.out.println("Yr = " + Yr); Residue apr = new Residue(Yr, ap); Residue bpr = new Residue(Yr, bp); Residue cpr = new Residue(Yr, cp); Residue spr = new Residue(Yr, sp); Residue tpr = new Residue(Yr, tp); Residue rpr = bpr.multiply(spr).sum(apr.multiply(tpr)); // order //System.out.println("\napr = " + apr); //System.out.println("bpr = " + bpr); //System.out.println("cpr = " + cpr); //System.out.println("spr = " + spr); //System.out.println("tpr = " + tpr); //System.out.println("rpr = " + rpr); //System.out.println("ar sr + br tr = cr: " + cpr.equals(rpr) + "\n"); assertEquals("ar sr + br tr = cr ", cpr, rpr); } catch (NoLiftingException e) { // can happen: fail("" + e); //System.out.println("e = " + e); } } } /** * Test multivariate diophant lifting list. */ public void testDiophantLiftingList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); //ModLongRing pl = new ModLongRing(p, false); //GenPolynomialRing pfac = new GenPolynomialRing(pm, 2, tord, new String[]{ "x", "y" }); GenPolynomialRing pfac = new GenPolynomialRing(pm, 3, tord, new String[] { "x", "y", "z" }); //GenPolynomialRing pfac = new GenPolynomialRing(pm, 4, tord, new String[]{ "w", "x", "y", "z" }); //GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(),pfac); BigInteger mi = m; long k = 5L; long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(5L); List V = new ArrayList(1); V.add(v); V.add(pkm.fromInteger(3L)); if (pkfac.nvar > 3) { V.add(pkm.fromInteger(7L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.random(kl + 7 * i, ll, el + 3, q).abs(); b = dfac.random(kl + 7 * i, ll, el + 2, q).abs(); c = dfac.random(kl + 7 * i, ll, el + 2, q).abs(); //a = dfac.parse(" z + x*y + (y - 1)*(1 + y) "); //b = dfac.parse(" z - x + (y - 2)*(2 + y) "); //c = dfac.parse(" z + x + (y - 2)*(2 + y) "); A.add(a); A.add(b); A.add(c); //System.out.println("\nA = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); if (A.size() == 0) { continue; } List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Ap.add(ap); } //System.out.println("A mod p^k = " + Ap); cp = pkfac.parse(" x y z + x y + x "); //cp = pkfac.parse(" x y + x "); //cp = Ap.get(0).multiply(Ap.get(1)); //System.out.println("cp = " + cp); GenPolynomial B = pkfac.getONE(); for (GenPolynomial bp : Ap) { B = B.multiply(bp); } //System.out.println("B = " + B); List> Bp = new ArrayList>(A.size()); for (GenPolynomial bp : Ap) { GenPolynomial b = PolyUtil. basePseudoDivide(B, bp); if (b.isZERO()) { System.out.println("b == 0"); return; } Bp.add(b); } //System.out.println("B mod p^k = " + Bp); try { List> lift; lift = HenselMultUtil. liftDiophant(Ap, cp, V, d, k); // 5 is max //System.out.println("liftMultiDiophant:"); //System.out.println("lift = " + lift); GenPolynomialRing qfac = lift.get(0).ring; assertEquals("pkfac == qfac: " + qfac, pkfac, qfac); //GenPolynomialRing cfac = pkfac.contract(1); List> Y = new ArrayList>(); for (int j = 0; j < V.size(); j++) { ModInteger vp = pkfac.coFac.fromInteger(V.get(j).getSymmetricInteger().getVal()); GenPolynomial ya = pkfac.univariate(pkfac.nvar - 2 - j); ya = ya.subtract(vp); //ya = Power.>power(pkfac,ya,d+1); //System.out.println("ya = " + ya); Y.add(ya); } //System.out.println("\nY = " + Y); Ideal Yi = new Ideal(pkfac, Y); //System.out.println("Yi = " + Yi); Yi = Yi.power((int) d + 1); //System.out.println("Yi = " + Yi); ResidueRing Yr = new ResidueRing(Yi); //System.out.println("\nYr = " + Yr); List> Bpr = new ArrayList>(A.size()); for (GenPolynomial tp : Bp) { Residue apr = new Residue(Yr, tp); Bpr.add(apr); } List> Spr = new ArrayList>(A.size()); for (GenPolynomial sp : lift) { Residue apr = new Residue(Yr, sp); if (apr.isZERO()) { //System.out.println("apr == 0: " + lift); //return; } Spr.add(apr); } //System.out.println("\nBpr = " + Bpr); //System.out.println("Spr = " + Spr); Residue cpr = new Residue(Yr, cp); Residue rpr = Yr.getZERO(); int j = 0; for (Residue r : Bpr) { rpr = rpr.sum(r.multiply(Spr.get(j++))); } //System.out.println("cpr = " + cpr); //System.out.println("rpr = " + rpr); assertEquals("cr = sum_i( br sr ): ", cpr, rpr); } catch (ArithmeticException e) { // ok, can happen } catch (NoLiftingException e) { // can now happen: fail("" + e); //System.out.println("e = " + e); } } } } java-algebra-system-2.7.200/trc/edu/jas/application/IdealTest.java000066400000000000000000002055661445075545500247220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.gb.GroebnerBase; import edu.jas.gbufd.GBFactory; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.util.KsubSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Ideal tests with JUnit. * @author Heinz Kredel */ public class IdealTest extends TestCase { private static final Logger logger = LogManager.getLogger(IdealTest.class); /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a IdealTest object. * @param name String. */ public IdealTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(IdealTest.class); return suite; } TermOrder to; GenPolynomialRing fac; List> L, M, G; PolynomialList F; GroebnerBase bb; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 4; //10 int ll = 5; //7 int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(17, 1); to = new TermOrder( /*TermOrder.INVLEX*/); String[] vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); //bb = new GroebnerBaseSeq(); bb = GBFactory.getImplementation(coeff); a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; ComputerThreads.terminate(); } /** * Test Ideal sum. */ public void testIdealSum() { Ideal I, J, K; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I )", I.isGB()); I = new Ideal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I )", I.isGB()); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); I = new Ideal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); String s = I.toScript() + "\n" + I.toString(); //System.out.println("#s = " + s.length() + ": " + s); assertTrue("#s >= 90: ", s.length() >= 90); K = I.getZERO(); assertTrue("K == 0: " + K, K.isZERO()); K = I.getONE(); assertTrue("K == 1: " + K, K.isONE()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); I = new Ideal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); //assertTrue("not isGB( I )", !I.isGB() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); // assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); L = new ArrayList>(); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); assertTrue("isGB( { c } )", bb.isGB(L)); J = new Ideal(fac, L, true); K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); assertTrue("isGB( { d } )", bb.isGB(L)); J = new Ideal(fac, L, true); I = K; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); assertTrue("isGB( { e } )", bb.isGB(L)); J = new Ideal(fac, L, true); I = K; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertTrue("K contains(J)", K.contains(I)); assertTrue("I contains(K)", I.contains(K)); } /** * Test Ideal product. */ public void testIdealProduct() { Ideal I, J, K, H; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I )", I.isGB()); L = new ArrayList>(); assertTrue("not isZERO( b )", !a.isZERO()); L.add(b); J = new Ideal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); assertTrue("not isONE( J )", !J.isONE()); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); assertTrue("H contains(K)", H.contains(K)); //if (false /*! H.equals(K)*/) { // System.out.println("I = " + I); // System.out.println("J = " + J); // System.out.println("K = " + K); // System.out.println("H = " + H); //} L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); assertTrue("H contains(K)", H.contains(K)); //if (false /*! H.equals(K)*/) { // System.out.println("I = " + I); // System.out.println("J = " + J); // System.out.println("K = " + K); // System.out.println("H = " + H); //} L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); J = new Ideal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); assertTrue("H contains(K)", H.contains(K)); //if (false /*! H.equals(K)*/) { // System.out.println("I = " + I); // System.out.println("J = " + J); // System.out.println("K = " + K); // System.out.println("H = " + H); //} } /** * Test Ideal quotient. */ public void testIdealQuotient() { Ideal I, J, K, H; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); L = new ArrayList>(); assertTrue("not isZERO( b )", !a.isZERO()); L.add(b); L = bb.GB(L); J = new Ideal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J.getList().get(0)); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("equals(H,I)", H.equals(I)); // GBs only H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("equals(H,I)", H.equals(I)); // GBs only L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); J = new Ideal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("equals(H,I)", H.equals(I)); // GBs only L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( I )", I.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("equals(H,I)", H.equals(I)); // GBs only } /** * Test Ideal infinite quotient. */ public void testIdealInfiniteQuotient() { Ideal I, J, K; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); assertTrue("equals(J,I)", J.equals(I)); // GBs only assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); assertTrue("isGB( J )", J.isGB()); assertTrue("equals(J,I)", J.equals(I)); // GBs only G = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); G.add(a); G = bb.GB(G); K = new Ideal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotient(K); assertTrue("equals(J,I)", J.equals(I)); // GBs only assertTrue("not isZERO( e )", !e.isZERO()); G.add(e); G = bb.GB(G); K = new Ideal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotient(K); assertTrue("equals(J,I)", J.equals(I)); // GBs only } /** * Test Ideal infinite quotient with Rabinowich trick. */ public void testIdealInfiniteQuotientRabi() { Ideal I; Ideal J; Ideal K; Ideal JJ; a = fac.random(kl - 1, ll - 1, el - 1, q / 2); b = fac.random(kl - 1, ll - 1, el, q / 2); c = fac.random(kl - 1, ll - 1, el, q / 2); d = fac.random(kl - 1, ll - 1, el, q / 2); e = a; //fac.random(kl, ll-1, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); assertTrue("equals(J,I)", J.equals(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); assertTrue("isGB( J )", J.isGB()); assertTrue("equals(J,I)", J.equals(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only G = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); G.add(a); G = bb.GB(G); K = new Ideal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotientRab(K); assertTrue("equals(J,I)", J.equals(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only assertTrue("not isZERO( e )", !e.isZERO()); G.add(e); G = bb.GB(G); K = new Ideal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotientRab(K); assertTrue("equals(J,I)", J.equals(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only } /** * Test Ideal radical membership. */ public void testIdealRadicalMember() { Ideal I; a = fac.random(kl - 1, ll, el - 1, q); b = fac.random(kl - 1, ll, el, q); c = fac.random(kl - 1, ll - 1, el, q / 2); d = fac.random(kl - 1, ll - 1, el, q / 2); e = a; //fac.random(kl, ll-1, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); L.add(b); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("I = " + I); if (!I.isONE()) { assertFalse("a in radical(b)", I.isRadicalMember(a)); assertTrue("b in radical(b)", I.isRadicalMember(b)); } L = new ArrayList>(); L.add(b.multiply(b)); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); if (!I.isONE()) { assertFalse("a in radical(b*b)", I.isRadicalMember(a)); assertTrue("b in radical(b*b)", I.isRadicalMember(b)); } //System.out.println("c = " + c); L.add(c); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); if (!I.isONE()) { assertFalse("a in radical(b*b)", I.isRadicalMember(a)); assertTrue("b in radical(b*b)", I.isRadicalMember(b)); } } /** * Test Ideal common zeros. */ @SuppressWarnings("unchecked") public void testIdealCommonZeros() { Ideal I; L = new ArrayList>(); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); a = fac.getZERO(); L.add(a); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); b = fac.getONE(); L.add(b); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), -1); L = new ArrayList>(); a = fac.random(kl, ll, el, q); if (!a.isZERO() && !a.isConstant()) { L.add(a); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } L = (List>) fac.univariateList(); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 0); L.remove(0); I = new Ideal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } /** * Test Ideal dimension. */ @SuppressWarnings("unchecked") public void testIdealDimension() { Ideal I; L = new ArrayList>(); Dimension dim; I = new Ideal(fac, L, true); assertEquals("dimension( I )", rl, I.dimension().d); a = fac.getZERO(); L.add(a); I = new Ideal(fac, L, true); assertEquals("dimension( I )", rl, I.dimension().d); b = fac.getONE(); L.add(b); I = new Ideal(fac, L, true); assertEquals("dimension( I )", -1, I.dimension().d); L = new ArrayList>(); a = fac.random(kl, ll, el, q); if (!a.isZERO() && !a.isConstant()) { L.add(a); I = new Ideal(fac, L, true); //System.out.println("a = " + a); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertTrue("dimension( I )", dim.d >= 1); } L = (List>) fac.univariateList(); I = new Ideal(fac, L, true); dim = I.dimension(); assertEquals("dimension( I )", 0, dim.d); while (L.size() > 0) { L.remove(0); I = new Ideal(fac, L, true); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertEquals("dimension( I )", rl - L.size(), dim.d); } L = (List>) fac.univariateList(); I = new Ideal(fac, L, true); I = I.product(I); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertEquals("dimension( I )", 0, dim.d); L = I.getList(); while (L.size() > 0) { L.remove(0); I = new Ideal(fac, L, true); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertTrue("dimension( I )", dim.d > 0); } } /** * Test Ideal term order optimization. */ public void testIdealTopt() { Ideal I, J, K; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); J = I.copy(); //new Ideal(fac,L); J.doToptimize(); assertTrue("not isZERO( J )", !J.isZERO()); assertTrue("isGB( J )", J.isGB()); //System.out.println("J = " + J); if (I.isONE()) { return; } assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); I = new Ideal(fac, L); K = I.copy(); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("GB(I) = " + I); K.doToptimize(); K.doGB(); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //System.out.println("GB(opt(K)) = " + K); J = I.copy(); J.doToptimize(); assertTrue("not isZERO( J )", !J.isZERO()); assertTrue("isGB( J )", J.isGB()); //System.out.println("opt(GB(J)) = " + J); if (I.isONE()) { return; } assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); I = new Ideal(fac, L); K = I.copy(); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("GB(I) = " + I); K.doToptimize(); K.doGB(); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //System.out.println("GB(opt(K)) = " + K); J = I.copy(); J.doToptimize(); assertTrue("not isZERO( J )", !J.isZERO()); assertTrue("isGB( J )", J.isGB()); //System.out.println("opt(GB(J)) = " + J); } /** * Test elimination Ideals. */ public void testElimIdeal() { String[] vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); Ideal I, J; L = new ArrayList>(); a = fac.univariate(2, 3L); //fac.random(kl, ll, el, q ); b = fac.univariate(1, 2L); //fac.random(kl, ll, el, q ); c = fac.univariate(0, 1L); //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List sv = new ArrayList(vars.length); for (int i = 0; i < vars.length; i++) { sv.add(vars[i]); } //System.out.println("sv = " + sv); for (int i = 0; i <= vars.length; i++) { KsubSet ps = new KsubSet(sv, i); //System.out.println("========================== ps : " + i); for (List ev : ps) { //System.out.println("ev = " + ev); String[] evars = new String[ev.size()]; for (int j = 0; j < ev.size(); j++) { evars[j] = ev.get(j); } GenPolynomialRing efac; efac = new GenPolynomialRing(fac.coFac, evars.length, fac.tord, evars); //System.out.println("efac = " + efac); J = I.eliminate(efac); assertTrue("isGB( J )", J.isGB()); assertTrue("size( J ) <= |ev|", J.getList().size() <= ev.size()); //System.out.println("J = " + J); } } } /** * Test univariate polynomials in ideal. */ public void testUnivPoly() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 + 34/55 x^2 + 1/9 x + 99 )"); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^3 - x y )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); for (int i = 0; i < rl; i++) { // rl GenPolynomial u = I.constructUnivariate(rl - 1 - i); //System.out.println("u = " + u); GenPolynomial U = fac.parse(u.toString()); //System.out.println("U = " + U + "\n"); assertTrue("I.contains(U) ", I.contains(U)); } List> Us = I.constructUnivariate(); for (GenPolynomial u : Us) { //System.out.println("u = " + u); GenPolynomial U = fac.parse(u.toString()); //System.out.println("U = " + U + "\n"); assertTrue("I.contains(U) ", I.contains(U)); } } /** * Test complex roots univariate polynomials in zero dim ideal. */ public void testComplexRoot() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )"); b = fac.parse("( y^2 - 9 )"); c = fac.parse("( z - 7 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); BigRational eps = new BigRational(1, 1000000); eps = eps.multiply(eps); eps = eps.multiply(eps).multiply(eps); BigDecimal e = new BigDecimal(eps.getRational()); e = e.abs(); //.multiply(e); BigDecimal dc = BigDecimal.ONE; GenPolynomialRing dfac = new GenPolynomialRing(dc, fac); //System.out.println("dfac = " + dfac); ComplexRing dcc = new ComplexRing(dc); GenPolynomialRing> dcfac = new GenPolynomialRing>(dcc, dfac); //System.out.println("dcfac = " + dcfac); List>> roots = PolyUtilApp. complexRootTuples(I, eps); //System.out.println("roots = " + roots + "\n"); for (GenPolynomial p : I.getList()) { GenPolynomial dp = PolyUtil. decimalFromRational(dfac, p); GenPolynomial> dpc = PolyUtil. toComplex(dcfac, dp); //System.out.println("dpc = " + dpc); for (List> r : roots) { //System.out.println("r = " + r); Complex ev = PolyUtil.> evaluateAll(dcc, dpc, r); if (ev.norm().getRe().compareTo(e) > 0) { //System.out.println("ev = " + ev); fail("ev > eps : " + ev + " > " + e); } } } //System.out.println(); } /** * Test real roots univariate polynomials in zero dim ideal. */ public void testRealRoot() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )"); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^2 - x^2 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); BigRational eps = new BigRational(1, 10); eps = eps.power(BigDecimal.DEFAULT_PRECISION / 2); BigDecimal e = new BigDecimal(eps.getRational()); e = e.abs(); //.multiply(e); eps = eps.multiply(new BigRational(1, 100)); List> roots = PolyUtilApp. realRootTuples(I, eps); //System.out.println("roots = " + roots + "\n"); // polynomials with decimal coefficients BigDecimal dc = BigDecimal.ONE; GenPolynomialRing dfac = new GenPolynomialRing(dc, fac); //System.out.println("dfac = " + dfac); for (GenPolynomial p : I.getList()) { GenPolynomial dp = PolyUtil. decimalFromRational(dfac, p); //System.out.println("dp = " + dp); for (List r : roots) { //System.out.println("r = " + r); BigDecimal ev = PolyUtil. evaluateAll(dc, dp, r); if (ev.abs().compareTo(e) > 0) { //System.out.println("ev = " + ev); fail("ev > e : " + ev + " > " + e + ", eps = " + new BigDecimal(eps)); } } } //System.out.println(); } /** * Test zero dimensional decomposition. */ public void testZeroDimDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )"); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^2 - x^2 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> zd = I.zeroDimDecomposition(); //System.out.println("I = " + I); //System.out.println("zd = " + zd); boolean t = I.isZeroDimDecomposition(zd); //System.out.println("t = " + t); assertTrue("is decomposition ", t); List> zde = I.zeroDimElimination(zd); //System.out.println("I = " + I); //System.out.println("zde = " + zde); t = I.isZeroDimDecomposition(zde); //System.out.println("t = " + t); assertTrue("is decomposition elimination", t); } /** * Test zero dimensional radical decomposition. */ public void testZeroDimRadicalDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )**3 ( x**2 - 11 )**2 ( x + 1 ) "); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^2 - x^2 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> zd = I.zeroDimRadicalDecomposition(); //System.out.println("I = " + I); //System.out.println("zd = " + zd); boolean t = I.isZeroDimDecomposition(zd); //System.out.println("t = " + t); assertTrue("is decomposition ", t); for (IdealWithUniv ru : zd) { t = I.isRadical(ru); // works also for ZeroDim //System.out.println("t = " + t); assertTrue("is radical decomposition: " + ru, t); t = ru.ideal.isZeroDimRadical(); //System.out.println("t = " + t); assertTrue("is 0-dim radical decomposition: " + ru, t); } } /** * Test real roots univariate polynomials in zero dim ideal. */ public void testIdealRealRoot() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )"); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^2 - x^2 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> zd = I.zeroDimDecomposition(); //System.out.println("zd = " + zd); assertTrue("is decomposition ", I.isZeroDimDecomposition(zd)); BigRational eps = new BigRational(1, 10); eps = eps.power(BigDecimal.DEFAULT_PRECISION / 2); BigDecimal e = new BigDecimal(eps.getRational()); e = e.abs(); //.multiply(e); eps = eps.multiply(new BigRational(1, 10)); BigDecimal dc = BigDecimal.ONE; List> roots = PolyUtilApp. realRoots(zd, eps); //System.out.println("roots = " + roots + "\n"); for (IdealWithRealRoots Ir : roots) { List> L = Ir.ideal.getList(); List> Ld = new ArrayList>(L.size()); GenPolynomialRing dfac = new GenPolynomialRing(dc, Ir.ideal.list.ring); //System.out.println("dfac = " + dfac); for (GenPolynomial p : L) { GenPolynomial dp = PolyUtil. decimalFromRational(dfac, p); //System.out.println("dp = " + dp); Ld.add(dp); } boolean t = PolyUtilApp.isRealRoots(Ld, Ir.rroots, e); assertTrue("isRealRoots ", t); // this example only } } /** * Test complex roots univariate polynomials in zero dim ideal. */ public void testIdealComplexRoot() { String[] vars; BigRational coeff = new BigRational(1, 1); to = new TermOrder(TermOrder.INVLEX); //vars = new String[] { "x", "y" }; vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, vars.length, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 + 3 )"); //a = fac.parse("( x^3 - 3 )"); //a = fac.parse("( x^2 + 3 )"); b = fac.parse("( y^2 - x )"); //b = fac.parse("( y^2 + x )"); //b = fac.parse("( y^2 + 4 )"); c = fac.parse("( z^2 - x y )"); //c = fac.parse("( z^2 - 5 )"); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> zd = I.zeroDimRootDecomposition(); //System.out.println("zd = " + zd); assertTrue("is decomposition ", I.isZeroDimDecomposition(zd)); BigRational eps = new BigRational(1, 1000000); //eps = eps.multiply(eps); eps = eps.multiply(eps).multiply(eps); BigDecimal e = new BigDecimal(eps.getRational()); e = e.abs(); //.multiply(e); List> roots = PolyUtilApp . complexAlgebraicRoots(zd); //, eps); //System.out.println("roots = " + roots + "\n"); ComplexRing dcc = new ComplexRing(e); int d = 0; int s = 0; for (IdealWithComplexAlgebraicRoots Ic : roots) { List> L = Ic.ideal.getList(); List>> Ld = new ArrayList>>( L.size()); s += Ic.can.size(); GenPolynomialRing dfac = new GenPolynomialRing(e, Ic.ideal.list.ring); //System.out.println("dfac = " + dfac); GenPolynomialRing> dcfac; dcfac = new GenPolynomialRing>(dcc, dfac); //System.out.println("dcfac = " + dcfac); int ds = 1; for (GenPolynomial p : L) { long dl = p.leadingExpVector().totalDeg(); ds *= dl; GenPolynomial dp = PolyUtil. decimalFromRational(dfac, p); GenPolynomial> dpc = PolyUtil. toComplex(dcfac, dp); //System.out.println("p = " + p); //System.out.println("dpc = " + dpc); Ld.add(dpc); } d += ds; assertTrue("#L == #Ld: ", L.size() == Ld.size()); //List>> droot = Ic.decimalApproximation(); Ic.doDecimalApproximation(); //System.out.println("Ic = " + Ic.isDecimalApproximation()); assertTrue("is decimal approximation ", Ic.isDecimalApproximation()); assertTrue("#droot == ds: ", Ic.decimalApproximation().size() == ds); } logger.info("#roots = " + s + ", #vr-dim = " + d); assertTrue("#roots(" + s + ") == degree(" + d + "): ", s == d); } /** * Test normal position. */ public void testNormalPosition() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^3 - 27 )"); b = fac.parse("( y^3 - x )"); c = fac.parse("( z^2 - x^2 )"); L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); int[] np = I.normalPositionIndex2Vars(); //System.out.println("np = " + Arrays.toString(np)); if (np == null) { np = I.normalPositionIndexUnivars(); //System.out.println("np = " + Arrays.toString(np)); } if (np == null) { return; } int i = np[0]; int j = np[1]; IdealWithUniv Ip = I.normalPositionFor(i, j, null); //System.out.println("Ip = " + Ip); boolean t = Ip.ideal.isNormalPositionFor(i + 1, j + 1); // sic //System.out.println("t = " + t); assertTrue("is normal position ", t); np = Ip.ideal.normalPositionIndex2Vars(); //System.out.println("np = " + Arrays.toString(np)); if (np == null) { np = Ip.ideal.normalPositionIndexUnivars(); //System.out.println("np = " + Arrays.toString(np)); } if (np == null) { return; } i = np[0]; j = np[1]; assertTrue("i == 0: " + Arrays.toString(np), i == 0); assertTrue("j == 2: " + Arrays.toString(np), j == 3); // fixed, was 3, again to 3 } /** * Test 0-dim root decomposition char 0. */ public void testRootDecompositionChar0() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^2 - 7 )"); b = fac.parse("( y^2 - 5 )"); c = fac.parse("( z^3 - x * y )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> rzd = I.zeroDimRootDecomposition(); //System.out.println("rzd = " + rzd); assertTrue("is contained in intersection ", I.isZeroDimDecomposition(rzd)); } /** * Test 0-dim root decomposition char p = 13. */ public void testRootDecompositionCharP() { String[] vars; ModIntegerRing coeff = new ModIntegerRing(13, true); // 13 important for field extension to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; GenPolynomialRing fac; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac.toScript()); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; List> L; L = new ArrayList>(); GenPolynomial a, b, c; // need field extension for this test: a = fac.parse("( x^2 - 7 )"); b = fac.parse("( y^3 + 3 )"); c = fac.parse("( z^5 + x * y )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); //System.out.println("I = " + I); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> rzd = I.zeroDimRootDecomposition(); //System.out.println("rzd = " + rzd); //System.out.println("#rzd = " + rzd.size()); assertTrue("is zero dim decomposition ", I.isZeroDimDecomposition(rzd)); /* not ok when field extensions are used: List> izd = IdealWithUniv.asListOfIdeals(rzd); System.out.println("izd = " + izd); Ideal J = I.intersect(izd); System.out.println("I = " + I.toScript()); System.out.println("J = " + J.toScript()); assertEquals("I == J ", I, J); */ } /** * Test 0-dim prime decomposition. */ public void testPrimeDecomposition() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^2 - 5 )^2 "); b = fac.parse("( y^2 - 5 )"); c = fac.parse("( z^3 - x )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> pzd = I.zeroDimPrimeDecomposition(); //System.out.println("pzd = " + pzd); //System.out.println("I = " + I); assertTrue("is contained in intersection ", I.isZeroDimDecomposition(pzd)); } /** * Test 0-dim primary decomposition. */ public void testPrimaryDecomposition() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^2 - 5 )^2 "); b = fac.parse("( y^2 - 5 )"); c = fac.parse("( z^3 - x )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> qzd = I.zeroDimPrimaryDecomposition(); //System.out.println("qzd = " + qzd); //System.out.println("I = " + I); assertTrue("is intersection ", I.isPrimaryDecomposition(qzd)); } /** * Test 0-dim root decomposition and real roots. */ public void testRootDecompositionReal() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); a = fac.parse("( x^2 - 5 )"); b = fac.parse("( y^2 - 7 )"); c = fac.parse("( z^3 - x * y )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> iur; iur = PolyUtilApp. realAlgebraicRoots(I); List> iul = new ArrayList>(); for (IdealWithRealAlgebraicRoots iu : iur) { iul.add(iu); } assertTrue("is contained in intersection ", I.isZeroDimDecomposition(iul)); for (IdealWithRealAlgebraicRoots iu : iur) { //@SuppressWarnings("unused") //List> rd = iu.decimalApproximation(); iu.doDecimalApproximation(); // side effect compute decimal approx //System.out.println("iu = " + iu); //System.out.println("isDecimalApproximation: = " + iu.isDecimalApproximation()); assertTrue("is decimal approximation ", iu.isDecimalApproximation()); } } /** * Test extension-contraction. */ public void testExtCont() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(); //TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); //a = fac.parse("( y^2 - 5 ) x "); //b = fac.parse("( y^2 - 5 ) x "); //c = fac.parse("( x z^3 - 3 )"); //a = fac.parse("( x^2 + 2 x y z + z^4 ) "); //b = fac.parse("( y z - z^2 ) "); //c = fac.parse("0"); a = fac.parse("( y + x y^2 ) "); b = fac.parse("( x z + x^2 y ) "); //c = fac.parse("0"); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); //L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); IdealWithUniv> Ext = I.extension(new String[] { "x" }); //Ideal> Ext = I.extension( new String[] { "y", "z" } ); //System.out.println("Ext = " + Ext); //System.out.println("I = " + I); IdealWithUniv Con = I.permContraction(Ext); //System.out.println("Con = " + Con); //System.out.println("I = " + I); assertTrue("I subseteq Con(Ext(I)) ", Con.ideal.contains(I)); } /** * Test prime ideal decomposition. */ public void testPrimeDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); //a = fac.parse("( y^2 - 5 ) x "); //b = fac.parse("( y^2 - 5 ) x "); //c = fac.parse("( x z^3 - 3 )"); //a = fac.parse("( x^2 + 2 x y z + z^4 ) "); //b = fac.parse("( y z - z^2 ) "); //a = fac.parse("( y + x y^2 ) "); //b = fac.parse("( x z + x^2 y ) "); a = fac.parse("( z^2 - x ) "); b = fac.parse("( y^2 - x ) "); //a = fac.parse("( x y ) "); //b = fac.parse("( x z ) "); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); //L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> pdec = I.primeDecomposition(); //System.out.println("pdec = " + pdec); //System.out.println("I = " + I); assertTrue("I subseteq cup G_i ", I.isDecomposition(pdec)); List> dec = new ArrayList>(pdec.size()); for (IdealWithUniv pu : pdec) { dec.add(pu.ideal); } Ideal Ii = I.intersect(dec); //System.out.println("Ii = " + Ii); //System.out.println("I = " + I); // not always: assertTrue("I == Ii ", I.equals(Ii)); } /** * Test radical ideal decomposition. */ public void testRadicalDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); //a = fac.parse("( y^2 - 5 ) x "); //b = fac.parse("( y^2 - 5 ) x "); //c = fac.parse("( x z^3 - 3 )"); a = fac.parse("( x^2 + 2 x y z + z^4 ) "); b = fac.parse("( y z - z^2 ) "); //a = fac.parse("( y + x y^2 ) "); //b = fac.parse("( x z + x^2 y ) "); //a = fac.parse("( z^2 - x )^2 "); //b = fac.parse("( y^2 - x ) "); //a = fac.parse("( x^2 y^3 ) "); //b = fac.parse("( x^2 z^5 ) "); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); //L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> rdec = I.radicalDecomposition(); //System.out.println("rdec = " + rdec); //System.out.println("I = " + I); assertTrue("I subseteq cup G_i ", I.isDecomposition(rdec)); List> dec = new ArrayList>(rdec.size()); for (IdealWithUniv ru : rdec) { dec.add(ru.ideal); } Ideal Ii = I.intersect(dec); //System.out.println("Ii = " + Ii); //System.out.println("I = " + I); assertTrue("Ii.contains(I) ", Ii.contains(I)); for (IdealWithUniv ru : rdec) { //System.out.println("ru = " + ru); boolean t = I.isRadical(ru); assertTrue("isRadical: " + ru, t); } //Ii = I.radical(); //System.out.println("Ii = " + Ii); //System.out.println("I = " + I); //assertTrue("Ii.contains(I) ", Ii.contains(I)); } /** * Test ideal decomposition. */ public void testIrredDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); //a = fac.parse("( y^2 - 5 ) x "); //b = fac.parse("( y^2 - 5 ) x "); //c = fac.parse("( x z^3 - 3 )"); a = fac.parse("( x^2 + 2 x y z + z^4 ) "); b = fac.parse("( y z - z^2 ) "); //a = fac.parse("( y + x y^2 ) "); //b = fac.parse("( x z + x^2 y ) "); //a = fac.parse("( z^2 - x )^2 "); //b = fac.parse("( y^2 - x ) "); //a = fac.parse("( x^2 y^3 ) "); //b = fac.parse("( x^2 z^5 ) "); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); //L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> rdec = I.decomposition(); //System.out.println("rdec = " + rdec); //System.out.println("I = " + I); assertTrue("I subseteq cup G_i ", I.isDecomposition(rdec)); List> dec = new ArrayList>(rdec.size()); for (IdealWithUniv ru : rdec) { dec.add(ru.ideal); } Ideal Ii = I.intersect(dec); //System.out.println("Ii = " + Ii); //System.out.println("I = " + I); assertTrue("Ii.contains(I) ", Ii.contains(I)); //Ii = I.radical(); //System.out.println("Ii = " + Ii); //System.out.println("I = " + I); //assertTrue("Ii.contains(I) ", Ii.contains(I)); } /** * Test primary ideal decomposition. */ public void testPrimaryDecomp() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "x", "y", "z" }; fac = new GenPolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 3 ", vars.length == 3); Ideal I; L = new ArrayList>(); //a = fac.parse("( y^2 - 5 ) x "); //b = fac.parse("( y^2 - 5 ) x "); //c = fac.parse("( x z^3 - 3 )"); //a = fac.parse("( x^2 + 2 x y z + z^4 ) "); //b = fac.parse("( y z - z^2 ) "); //a = fac.parse("( y + x y^2 ) "); //b = fac.parse("( x z + x^2 y ) "); a = fac.parse("( x z^2 - 1 )^2 "); b = fac.parse("( y^2 - x ) "); //a = fac.parse("( x^2 y ) "); //b = fac.parse("( x z^3 ) "); if (a.isZERO() || b.isZERO()) { return; } L.add(a); L.add(b); //L.add(c); I = new Ideal(fac, L); I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); List> qdec = I.primaryDecomposition(); //System.out.println("qdec = " + qdec); //System.out.println("I = " + I); List> dec = new ArrayList>(qdec.size()); for (PrimaryComponent ru : qdec) { dec.add(ru.primary); } assertTrue("#qdec == #dec: ", qdec.size() == dec.size()); assertTrue("I eq cup G_i ", I.isPrimaryDecomposition(qdec)); } /** * Test Ideal annihilator. */ public void testAnnihilator() { Ideal I, J, K; do { a = fac.random(kl, ll, el, q); } while (a.isZERO() || a.isConstant()); b = fac.univariate(1); c = fac.univariate(rl - 1); //b = fac.random(kl - 1, ll, el, q); //c = fac.random(kl - 1, ll - 1, el, q / 2); L = new ArrayList>(); L.add(a); L.add(b); //System.out.println("L = " + L); L = bb.GB(L); I = new Ideal(fac, L, true); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I + "\n"); J = I.annihilator(c); //System.out.println("J = " + J + "\n"); J.doGB(); //System.out.println("c = " + c); //System.out.println("J = " + J + "\n"); assertTrue("isAnnihilator(c,J)", I.isAnnihilator(c, J)); d = fac.univariate(rl - 2); //d = fac.random(kl - 1, ll, el, q); M = new ArrayList>(); M.add(c); M.add(d); //System.out.println("M = " + M); K = new Ideal(fac, M); //System.out.println("K = " + K + "\n"); J = I.annihilator(K); //System.out.println("J = " + J + "\n"); J.doGB(); //System.out.println("K = " + K); //System.out.println("J = " + J + "\n"); assertTrue("isAnnihilator(M,J)", I.isAnnihilator(K, J)); } } java-algebra-system-2.7.200/trc/edu/jas/application/IntegerProgramTest.java000066400000000000000000000164401445075545500266200ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Unit tests for Integer Programming. * @author Maximilian Nohr * @author Heinz Kredel */ public class IntegerProgramTest extends TestCase { /** * Execute all tests. * @param args */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); // example1(); // example2(); // example3(); // example4(); // example5(); // example6(); // example7(); // example8(); } /** * Constructs a IntegerProgramTest object. * @param name String. */ public IntegerProgramTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(IntegerProgramTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Example p.360 CLOII */ public void testExample1() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.360 CLOII long[][] A0 = { { 4, 5, 1, 0 }, { 2, 3, 0, 1 } }; long[] B0 = { 37, 20 }; long[] C0 = { -11, -15, 0, 0 }; long[] sol = IP.solve(A0, B0, C0); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); long[] BW = { 1, 2 }; //,3}; sol = IP.solve(BW); int count = 0; for (int i = 0; i < 5; i++) { for (int j = 0; j < 5; j++) { B0[0] = i; B0[1] = j; sol = IP.solve(A0, B0, C0); if (IP.getSuccess()) { count++; } } } assertTrue("#IP.getSuccess(): " + count, count > 0); //System.out.println(count + " times successful!"); } /** * Example p.374 CLOII 10a */ public void testExample2() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.374 CLOII 10a long[][] A = { { 3, 2, 1, 1 }, { 4, 1, 1, 0 } }; long[] B = { 10, 5 }; long[] C = { 2, 3, 1, 5 }; long[] sol = IP.solve(A, B, C); //10b long[] Bb = { 20, 14 }; sol = IP.solve(Bb); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } /** * Example p.372 CLOII */ public void testExample3() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.372 CLOII long[][] A2 = { { 3, -2, 1, 0 }, { 4, 1, -1, -1 } }; long[] B2 = { -1, 5 }; long[] C2 = { 1, 1000, 1, 100 }; long[] sol = IP.solve(A2, B2, C2); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } public void testExample4() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.374 10c long[][] A3 = { { 3, 2, 1, 1, 0, 0 }, { 1, 2, 3, 0, 1, 0 }, { 2, 1, 1, 0, 0, 1 } }; long[] B3 = { 45, 21, 18 }; long[] C3 = { -3, -4, -2, 0, 0, 0 }; long[] sol = IP.solve(A3, B3, C3); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } /** * Example p.138 AAECC-9 */ public void testExample5() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //bsp. s.138 AAECC-9 long[][] A4 = { { 32, 45, -41, 22 }, { -82, -13, 33, -33 }, { 23, -21, 12, -12 } }; long[] B4 = { 214, 712, 331 }; //im Beispiel keine b genannt long[] C4 = { 1, 1, 1, 1 }; long[] sol = IP.solve(A4, B4, C4); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } /** * Example from M. Nohr */ public void testExample6() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); //eigenes beispiel //System.out.println("example from mnohr:"); long[][] A5 = { { 4, 3, 1, 0 }, { 3, 1, 0, 1 } }; long[] B5 = { 200, 100 }; long[] C5 = { -5, -4, 0, 0 }; long[] sol = IP.solve(A5, B5, C5); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } /** * Example unsolvable */ public void testExample7() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); long[][] A9 = { { 1, 1, 1, 1 }, { -1, -1, -1, -1 } }; long[] B9 = { 1, 1 }; long[] C9 = { 1, 1, 0, 0 }; long[] sol = IP.solve(A9, B9, C9); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\nunsolvable: " + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertFalse("IP.getSuccess(): " + t, IP.getSuccess()); } /** * Example ? */ public void testExample8() { IntegerProgram IP = new IntegerProgram(); long t0 = System.currentTimeMillis(); long[][] A8 = { { 4, 3, 1, 0 }, { 3, 1, 0, 1 } }; long[] B8 = { 200, 100 }; long[] C8 = { -5, -4, 0, 0 }; long[] sol = IP.solve(A8, B8, C8); long t1 = System.currentTimeMillis(); long t = t1 - t0; // System.out.println("\n" + IP); // System.out.println("The solution is: " + Arrays.toString(sol)); // System.out.println("The computation needed " + t + " milliseconds."); assertTrue("IP.getSuccess(): " + t, IP.getSuccess()); } } java-algebra-system-2.7.200/trc/edu/jas/application/LocalResidueSolvablePolynomialQLRTest.java000066400000000000000000000600521445075545500323570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.QLRSolvablePolynomial; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients LocalResidueSolvablePolynomial QLR representation * tests with JUnit. * @author Heinz Kredel */ public class LocalResidueSolvablePolynomialQLRTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a LocalResidueSolvablePolynomialQLRTest object. * @param name String. */ public LocalResidueSolvablePolynomialQLRTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(LocalResidueSolvablePolynomialQLRTest.class); return suite; } QLRSolvablePolynomial, BigRational> a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 1; int ll = 4; int el = 3; float q = 0.2f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; QLRSolvablePolynomialRing, BigRational> ring; BigRational cfac; //GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; SolvableLocalResidueRing qcring; SolvableIdeal sideal; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wc = new WeylRelations(); cring.addRelations(wc); //wc.generate(cring); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); //p1 = cring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalResidueRing(sideal); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new QLRSolvablePolynomial, BigRational>(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.println("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); assertTrue("isAssociative: ", ring.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 5; i++) { // a = ring.random(ll+2*i); a = ring.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ @SuppressWarnings("unchecked") public void testAddition() { a = ring.random(kl + 1, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (QLRSolvablePolynomial, BigRational>) a.sum(a); c = (QLRSolvablePolynomial, BigRational>) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(b); assertEquals("a+b = b+a", c, d); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) c.subtract(b); //System.out.println("a = " + a); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = ring.random(kl, ll, el, q); d = (QLRSolvablePolynomial, BigRational>) a.sum(b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableLocalResidue x = qcring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll - 1, el - 1, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll - 1, el - 1, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll - 1, el - 1, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); SolvableLocalResidue xp = a.leadingBaseCoefficient().inverse(); d = a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().isONE()); //System.out.println("a = " + a); //System.out.println("d = " + d); d = (QLRSolvablePolynomial, BigRational>) a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test commutative ring. */ @SuppressWarnings("unchecked") public void testCommutative() { //System.out.println("table = " + ring.table.toString(vars)); //System.out.println("table = " + ring.table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalResidueRing(sideal); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, ring); //table = ring.table; //System.out.println("table = " + table.toString(vars)); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("b*a == a*b: ", c, d); } /** * Test distributive law. */ @SuppressWarnings("unchecked") public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((QLRSolvablePolynomial, BigRational>) b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.multiply(b) .sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); } /** * Test solvable coefficient ring. */ @SuppressWarnings("unchecked") public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //no: csring.addRelations(wc); //wc.generate(csring); //assertTrue("# relations == 1", csring.table.size() == 1); assertTrue("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); List> il = new ArrayList>(); GenSolvablePolynomial p1 = csring.parse("b - a^2"); il.add(p1); //p1 = csring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(csring, il); SolvableLocalResidueRing qcsring = new SolvableLocalResidueRing(sideal); assertTrue("isCommutative()", qcsring.isCommutative()); assertTrue("isAssociative()", qcsring.isAssociative()); ring = new QLRSolvablePolynomialRing, BigRational>(qcsring, ring); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); // + a //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring = " + ring.toScript()); //System.out.println("ring.polCoeff = " + ring.polCoeff); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new QLRSolvablePolynomial, BigRational>(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new QLRSolvablePolynomial, BigRational>(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens: " + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); } } //System.out.println("============="); //a = ring.random(kl, ll, el, q); //a = ring.getONE(); a = ring.parse("x^2 + a b"); //System.out.println("a = " + a.toScript()); //b = ring.random(kl, ll, el, q); //b = ring.getONE(); b = ring.parse("a b + a"); // a b^2 + a b = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("b = " + b.toScript()); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); e = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("e = " + e.toScript()); assertTrue("b*b^-1 == 1", e.multiply(b).isONE()); c = e.multiply(c); d = d.multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a == b * 1/b * a", a.equals(c)); assertTrue("a == a * 1/b * b", a.equals(d)); } /** * Test extension and contraction for Weyl relations. */ @SuppressWarnings("unchecked") public void testExtendContractWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = cring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); int k = rl; QLRSolvablePolynomialRing, BigRational> pfe = ring.extend(k); //System.out.println("pfe = " + pfe); QLRSolvablePolynomialRing, BigRational> pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ae = (QLRSolvablePolynomial, BigRational>) a .extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ @SuppressWarnings("unchecked") public void testReverseWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = cring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); QLRSolvablePolynomialRing, BigRational> pfr = ring.reverse(); QLRSolvablePolynomialRing, BigRational> pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ar = (QLRSolvablePolynomial, BigRational>) a .reverse(pfr); QLRSolvablePolynomial, BigRational> arr = (QLRSolvablePolynomial, BigRational>) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test recursive for Weyl relations. */ @SuppressWarnings("unchecked") public void testRecursiveWeyl() { GenSolvablePolynomialRing>> rsring = ring .recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial> ad, bd, cd, dd; RecSolvablePolynomial> ar, br, cr, dr; ad = ring.random(kl, ll, el, q); bd = ring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, ad); br = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial>) PolyUtil .> distribute(ring, cr); // //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /* * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/application/LocalSolvablePolynomialQLRTest.java000066400000000000000000000566061445075545500310500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.QLRSolvablePolynomial; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients LocalSolvablePolynomial QLR representation tests * with JUnit. * @author Heinz Kredel */ public class LocalSolvablePolynomialQLRTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a LocalSolvablePolynomialQLRTest object. * @param name String. */ public LocalSolvablePolynomialQLRTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(LocalSolvablePolynomialQLRTest.class); return suite; } QLRSolvablePolynomial, BigRational> a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 1; int ll = 4; int el = 3; float q = 0.2f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; QLRSolvablePolynomialRing, BigRational> ring; BigRational cfac; //GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; SolvableLocalRing qcring; SolvableIdeal sideal; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wc = new WeylRelations(); cring.addRelations(wc); //wc.generate(cring); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); //p1 = cring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalRing(sideal); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new QLRSolvablePolynomial, BigRational>(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.println("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); assertTrue("isAssociative: ", ring.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 5; i++) { // a = ring.random(ll+2*i); a = ring.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ @SuppressWarnings("unchecked") public void testAddition() { a = ring.random(kl + 1, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (QLRSolvablePolynomial, BigRational>) a.sum(a); c = (QLRSolvablePolynomial, BigRational>) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(b); assertEquals("a+b = b+a", c, d); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) c.subtract(b); //System.out.println("a = " + a); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = ring.random(kl, ll, el, q); d = (QLRSolvablePolynomial, BigRational>) a.sum(b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableLocal x = qcring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll - 1, el - 1, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll - 1, el - 1, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll - 1, el - 1, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); SolvableLocal xp = a.leadingBaseCoefficient().inverse(); d = a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().isONE()); //System.out.println("a = " + a); //System.out.println("d = " + d); d = (QLRSolvablePolynomial, BigRational>) a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test commutative ring. */ @SuppressWarnings("unchecked") public void testCommutative() { //System.out.println("table = " + ring.table.toString(vars)); //System.out.println("table = " + ring.table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalRing(sideal); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, ring); //table = ring.table; //System.out.println("table = " + table.toString(vars)); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("b*a == a*b: ", c, d); } /** * Test distributive law. */ @SuppressWarnings("unchecked") public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((QLRSolvablePolynomial, BigRational>) b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.multiply(b).sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); } /** * Test solvable coefficient ring. */ @SuppressWarnings("unchecked") public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //no: csring.addRelations(wc); //wc.generate(csring); //assertTrue("# relations == 1", csring.table.size() == 1); assertTrue("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); List> il = new ArrayList>(); GenSolvablePolynomial p1 = csring.parse("b - a^2"); il.add(p1); //p1 = csring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(csring, il); SolvableLocalRing qcsring = new SolvableLocalRing(sideal); assertTrue("isCommutative()", qcsring.isCommutative()); assertTrue("isAssociative()", qcsring.isAssociative()); ring = new QLRSolvablePolynomialRing, BigRational>(qcsring, ring); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); // + a //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring = " + ring.toScript()); //System.out.println("ring.polCoeff = " + ring.polCoeff); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new QLRSolvablePolynomial, BigRational>(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new QLRSolvablePolynomial, BigRational>(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens: " + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); } } //System.out.println("============="); //a = ring.random(kl, ll, el, q); //a = ring.getONE(); a = ring.parse("x^2 + a b"); //System.out.println("a = " + a.toScript()); //b = ring.random(kl, ll, el, q); //b = ring.getONE(); b = ring.parse("a b + a"); // a b^2 + a b = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("b = " + b.toScript()); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); e = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("e = " + e.toScript()); assertTrue("b*b^-1 == 1", e.multiply(b).isONE()); c = e.multiply(c); d = d.multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a == b * 1/b * a", a.equals(c)); assertTrue("a == a * 1/b * b", a.equals(d)); } /** * Test extension and contraction for Weyl relations. */ @SuppressWarnings("unchecked") public void testExtendContractWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = cring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); int k = rl; QLRSolvablePolynomialRing, BigRational> pfe = ring.extend(k); //System.out.println("pfe = " + pfe); QLRSolvablePolynomialRing, BigRational> pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ae = (QLRSolvablePolynomial, BigRational>) a .extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ @SuppressWarnings("unchecked") public void testReverseWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = cring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); QLRSolvablePolynomialRing, BigRational> pfr = ring.reverse(); QLRSolvablePolynomialRing, BigRational> pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ar = (QLRSolvablePolynomial, BigRational>) a .reverse(pfr); QLRSolvablePolynomial, BigRational> arr = (QLRSolvablePolynomial, BigRational>) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test recursive for Weyl relations. */ @SuppressWarnings("unchecked") public void testRecursiveWeyl() { GenSolvablePolynomialRing>> rsring = ring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial> ad, bd, cd, dd; RecSolvablePolynomial> ar, br, cr, dr; ad = ring.random(kl, ll, el, q); bd = ring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, ad); br = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial>) PolyUtil .> distribute(ring, cr); // //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /* * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/application/LocalSolvablePolynomialTest.java000066400000000000000000000571771445075545500304750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients LocalSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class LocalSolvablePolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a LocalSolvablePolynomialTest object. * @param name String. */ public LocalSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(LocalSolvablePolynomialTest.class); return suite; } LocalSolvablePolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 1; int ll = 4; int el = 3; float q = 0.2f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; LocalSolvablePolynomialRing ring; BigRational cfac; GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; SolvableLocalRing qcring; SolvableIdeal sideal; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wc = new WeylRelations(); cring.addRelations(wc); //wc.generate(cring); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); //p1 = cring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalRing(sideal); ring = new LocalSolvablePolynomialRing(qcring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { String s = ring.toString() + ", " + ring.toScript(); //System.out.println("s = " + s + ", " + s.length()); assertTrue("length( string(ring) ) >= 563", s.length() >= 563); a = ring.getZERO(); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new LocalSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.println("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); assertTrue("isAssociative: ", ring.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 5; i++) { // a = ring.random(ll+2*i); a = ring.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); String s = a.toString() + ", " + a.toScript(); //System.out.println("s = " + s + ", " + s.length()); assertTrue("length( string(a) ) >= 9", s.length() >= 9); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl + 1, ll, el, q); c = (LocalSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (LocalSolvablePolynomial) a.sum(a); c = (LocalSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (LocalSolvablePolynomial) b.sum(a); d = (LocalSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = (LocalSolvablePolynomial) a.sum(b); d = (LocalSolvablePolynomial) c.subtract(b); //System.out.println("a = " + a); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = ring.random(kl, ll, el, q); d = (LocalSolvablePolynomial) a.sum(b.sum(c)); e = (LocalSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableLocal x = qcring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (LocalSolvablePolynomial) a.sum(b); d = (LocalSolvablePolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (LocalSolvablePolynomial) a.subtract(b); d = (LocalSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (LocalSolvablePolynomial) b.sum(a); d = (LocalSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (LocalSolvablePolynomial) a.subtract(b); d = (LocalSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll - 1, el - 1, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll - 1, el - 1, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll - 1, el - 1, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); SolvableLocal xp = a.leadingBaseCoefficient().inverse(); d = a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().isONE()); //System.out.println("a = " + a); //System.out.println("d = " + d); d = (LocalSolvablePolynomial) a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test commutative ring. */ public void testCommutative() { //System.out.println("table = " + ring.table.toString(vars)); //System.out.println("table = " + ring.table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); List> il = new ArrayList>(); GenSolvablePolynomial p1 = cring.parse("b - a^2"); il.add(p1); sideal = new SolvableIdeal(cring, il); qcring = new SolvableLocalRing(sideal); ring = new LocalSolvablePolynomialRing(qcring, ring); //table = ring.table; //System.out.println("table = " + table.toString(vars)); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("b*a == a*b: ", c, d); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((LocalSolvablePolynomial) b.sum(c)); e = (LocalSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); } /** * Test solvable coefficient ring. */ public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //no: csring.addRelations(wc); //wc.generate(csring); //assertTrue("# relations == 1", csring.table.size() == 1); assertTrue("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); List> il = new ArrayList>(); GenSolvablePolynomial p1 = csring.parse("b - a^2"); il.add(p1); //p1 = csring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(csring, il); SolvableLocalRing qcsring = new SolvableLocalRing(sideal); assertTrue("isCommutative()", qcsring.isCommutative()); assertTrue("isAssociative()", qcsring.isAssociative()); ring = new LocalSolvablePolynomialRing(qcsring, ring); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); // + a //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring = " + ring.toScript()); //System.out.println("ring.polCoeff = " + ring.polCoeff.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); //System.out.println("gens = " + gens); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; try { GenSolvablePolynomial> ap = ring.toPolyCoefficients(xx); //System.out.println("ap = " + ap); c = ring.fromPolyCoefficients(ap); //System.out.println("c = " + c); assertEquals("from(to(xx)) == xx", xx, c); } catch (IllegalArgumentException iae) { // pass } a = new LocalSolvablePolynomial(ring, xx); //System.out.println("a = " + a); try { GenSolvablePolynomial> ap = ring.toPolyCoefficients(a); //System.out.println("ap = " + ap); c = ring.fromPolyCoefficients(ap); //System.out.println("c = " + c); assertEquals("from(to(a)) == a", a, c); } catch (IllegalArgumentException iae) { // pass } for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new LocalSolvablePolynomial(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens: " + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); } } //System.out.println("============="); //a = ring.random(kl, ll, el, q); //a = ring.getONE(); a = ring.parse("x^2 + a b"); //System.out.println("a = " + a.toScript()); //b = ring.random(kl, ll, el, q); //b = ring.getONE(); b = ring.parse("a b + a"); // a b^2 + a b = (LocalSolvablePolynomial) b.inverse(); //System.out.println("b = " + b.toScript()); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); e = (LocalSolvablePolynomial) b.inverse(); //System.out.println("e = " + e.toScript()); assertTrue("b*b^-1 == 1", e.multiply(b).isONE()); c = e.multiply(c); d = d.multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a == b * 1/b * a", a.equals(c)); assertTrue("a == a * 1/b * b", a.equals(d)); } /* * Test extension and contraction for Weyl relations. public void * testExtendContractWeyl() { GenSolvablePolynomialRing csring * = new GenSolvablePolynomialRing(cfac, tord, cvars); * RelationGenerator wlc = new WeylRelations(); * wlc.generate(csring); assertFalse("isCommutative()", csring.isCommutative()); * assertTrue("isAssociative()", csring.isAssociative()); * * LocalSolvablePolynomial r1 = ring.parse("x"); * GenSolvablePolynomial r2 = csring.parse("b"); * LocalSolvablePolynomial rp = ring.parse("b x + a"); * ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); * * int k = rl; LocalSolvablePolynomialRing pfe = ring.extend(k); * //System.out.println("pfe = " + pfe); * LocalSolvablePolynomialRing pfec = pfe.contract(k); * //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", * ring, pfec); * * LocalSolvablePolynomial a = ring.random(kl, ll, el, q); * //System.out.println("a = " + a); * * LocalSolvablePolynomial ae = * (LocalSolvablePolynomial) a.extend(pfe, 0, 0); * //System.out.println("ae = " + ae); * * Map>> m = * ae.contract(pfec); List>> ml = * new ArrayList>>( m.values()); * GenPolynomial> aec = ml.get(0); * //System.out.println("ae = " + ae); //System.out.println("aec = " + * aec); assertEquals("a == aec", a, aec); } */ /* * Test reversion for Weyl relations. public void testReverseWeyl() { * GenSolvablePolynomialRing csring = new * GenSolvablePolynomialRing(cfac, tord, cvars); * RelationGenerator wlc = new WeylRelations(); * wlc.generate(csring); assertFalse("isCommutative()", csring.isCommutative()); * assertTrue("isAssociative()", csring.isAssociative()); * * LocalSolvablePolynomial r1 = ring.parse("x"); * GenSolvablePolynomial r2 = csring.parse("b"); * LocalSolvablePolynomial rp = ring.parse("b x + a"); * ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); * * LocalSolvablePolynomialRing pfr = ring.reverse(); * LocalSolvablePolynomialRing pfrr = pfr.reverse(); * assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + * ring); //System.out.println("pfr = " + pfr); * * LocalSolvablePolynomial a = ring.random(kl, ll, el, q); * //System.out.println("a = " + a); * * LocalSolvablePolynomial ar = * (LocalSolvablePolynomial) a.reverse(pfr); * LocalSolvablePolynomial arr = * (LocalSolvablePolynomial) ar.reverse(pfrr); * assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); * //System.out.println("arr = " + arr); } */ /* * Test recursive for Weyl relations. public void testRecursiveWeyl() { * String[] svars = new String[] { "w", "x", "y", "z" }; * GenSolvablePolynomialRing sring = new * GenSolvablePolynomialRing(cfac, tord, svars); * RelationGenerator wlc = new WeylRelations(); * wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); * assertTrue("isAssociative()", sring.isAssociative()); * //System.out.println("sring = " + sring.toScript()); * * GenSolvablePolynomialRing> rsring = * sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); * //.toScript()); System.out.println("rsring = " + rsring.toScript()); * * GenSolvablePolynomial ad, bd, cd, dd; * LocalSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, * ll, el, q); bd = sring.random(kl, ll, el, q); //ad = * sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = * sring.parse("-10/13 x "); //+ 413/150"); //ad = * (GenSolvablePolynomial) ad.monic(); //bd = * (GenSolvablePolynomial) bd.monic(); * * //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); * * cd = ad.multiply(bd); //System.out.println("cd = " + cd); * * ar = (LocalSolvablePolynomial) PolyUtil. * recursive(rsring, ad); br = (LocalSolvablePolynomial) * PolyUtil. recursive(rsring, bd); * //System.out.println("ar = " + ar); //System.out.println("br = " + br); * * cr = ar.multiply(br); //System.out.println("cr = " + cr); * //System.out.println("cr.ring = " + cr.ring.toScript()); * * dr = (LocalSolvablePolynomial) PolyUtil. * recursive(rsring, cd); //System.out.println("dr = " + dr); * * assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); * assertEquals("dr == cr", dr, cr); * * dd = (GenSolvablePolynomial) PolyUtil. * distribute(sring, cr); //System.out.println("dd = " + dd); * assertEquals("dd == cd", dd, cd); } */ /* * Test recursive for iterated Weyl relations. public void * testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", * "y", "z" }; GenSolvablePolynomialRing sring = new * GenSolvablePolynomialRing(cfac, tord, svars); * RelationGenerator wlc = new WeylRelationsIterated(); * wlc.generate(sring); assertFalse("isCommutative()", * sring.isCommutative()); assertTrue("isAssociative()", * sring.isAssociative()); //System.out.println("sring = " + * sring.toScript()); * * GenSolvablePolynomialRing> rsring = * sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); * //.toScript()); System.out.println("rsring = " + rsring.toScript()); * * GenSolvablePolynomial ad, bd, cd, dd; * LocalSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, * ll, el, q); bd = sring.random(kl, ll, el, q); //ad = * (GenSolvablePolynomial) ad.monic(); //bd = * (GenSolvablePolynomial) bd.monic(); * * //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); * * cd = ad.multiply(bd); //System.out.println("cd = " + cd); * * ar = (LocalSolvablePolynomial) PolyUtil. * recursive(rsring, ad); br = (LocalSolvablePolynomial) * PolyUtil. recursive(rsring, bd); * //System.out.println("ar = " + ar); //System.out.println("br = " + br); * * cr = ar.multiply(br); //System.out.println("cr = " + cr); * * dr = (LocalSolvablePolynomial) PolyUtil. * recursive(rsring, cd); //System.out.println("dr = " + dr); * * assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); * assertEquals("dr == cr", dr, cr); * * dd = (GenSolvablePolynomial) PolyUtil. * distribute(sring, cr); //System.out.println("dd = " + dd); * assertEquals("dd == cd", dd, cd); } */ } java-algebra-system-2.7.200/trc/edu/jas/application/LocalTest.java000066400000000000000000000160261445075545500247250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Local tests with JUnit. * @author Heinz Kredel */ public class LocalTest extends TestCase { /** * main. */ public static void main(String[] args) { // junit.textui.TestRunner.run(suite()); } /** * Constructs a LocalTest object. * @param name String. */ public LocalTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(LocalTest.class); return suite; } //private final static int bitlen = 100; Ideal id; LocalRing fac; GenPolynomialRing mfac; List> F; Local a, b, c, d, e; int rl = 3; int kl = 3; int ll = 5; int el = 2; float q = 0.3f; int il = 2; @Override protected void setUp() { a = b = c = d = e = null; BigRational cfac = new BigRational(1); String[] vars = new String[] { "x", "y", "z" }; mfac = new GenPolynomialRing(cfac, rl, vars); id = null; while (id == null || id.isONE()) { F = new ArrayList>(il); for (int i = 0; i < rl; i++) { //GenPolynomial mo = mfac.random(kl,ll,el,q); GenPolynomial mo = mfac.univariate(i); mo = mo.sum(mfac.fromInteger(cfac.random(7).denominator())); while (mo.isConstant()) { mo = mfac.random(kl, ll, el, q); } F.add(mo); } id = new Ideal(mfac, F); id = id.GB(); } //System.out.println("id = " + id); fac = new LocalRing(id); //System.out.println("fac = " + fac); F = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; id = null; mfac = null; ComputerThreads.terminate(); } /** * Test factory. */ public void testRing() { assertFalse("#ring infinite", fac.isFinite()); assertTrue("associative ring", fac.isAssociative()); assertTrue("commutative ring", fac.isCommutative()); assertTrue("characteristic zero", fac.characteristic().signum() == 0); assertTrue("no field", fac.isField()); } /** * Test constructor and toString. * */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.num = " + c.num); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.num = " + d.num); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); List> gens = fac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 7: ", gens.size() == 7); for (Local v : gens) { a = fac.parse(v.toString()); assertEquals("a == v", a, v); } } /** * Test random polynomial. * */ public void testRandom() { //System.out.println("fac = " + fac); for (int i = 0; i < 4; i++) { //a = fac.random(ll+i); a = fac.random(kl * (i + 1), ll + i, el, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); if (a.isZERO() || a.isONE()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. Not jet working because of monic GBs. */ public void testAddition() { //System.out.println("fac = " + fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(kl, ll, el, q); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. Not jet working because of monic GBs */ public void testMultiplication() { //System.out.println("fac = " + fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); if (a.isZERO() || b.isZERO()) { return; } //System.out.println("a = " + a); //System.out.println("b = " + b); assertTrue("not isZERO( a )", !a.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); d = c.inverse(); //System.out.println("d = " + d); assertTrue("1/(1/a) = a", d.equals(a)); } } } java-algebra-system-2.7.200/trc/edu/jas/application/PolyUtilAppTest.java000066400000000000000000000173521445075545500261200ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import edu.jas.arith.BigRational; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PolyUtilApp tests with JUnit. * @author Heinz Kredel */ public class PolyUtilAppTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PolyUtilAppTest object. * @param name String. */ public PolyUtilAppTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PolyUtilAppTest.class); return suite; } //TermOrder to = new TermOrder(TermOrder.INVLEX); //GenPolynomialRing dfac; //GenPolynomialRing cfac; //GenPolynomialRing> rfac; //BigRational ai, bi, ci, di, ei; //GenPolynomial a, b, c, d, e; //GenPolynomial> ar, br, cr, dr, er; //int rl = 5; int kl = 5; //int ll = 5; //int el = 5; //float q = 0.6f; @Override protected void setUp() { //a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; // dfac = new GenPolynomialRing(new BigRational(1), rl, to); // cfac = null; //new GenPolynomialRing(new BigRational(1),rl-1,to); // rfac = null; //new GenPolynomialRing>(cfac,1,to); } @Override protected void tearDown() { //a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; // dfac = null; // cfac = null; // rfac = null; } /** * Test primitive element. * */ public void testPrimitiveElement() { String[] va = new String[] { "alpha" }; String[] vb = new String[] { "beta" }; GenPolynomialRing aufac, bufac; // x^3 - 2 aufac = new GenPolynomialRing(new BigRational(1), 1, va); GenPolynomial m; m = aufac.univariate(0, 3); m = m.subtract(aufac.fromInteger(2)); //System.out.println("m = " + m); // x^2 - 3 bufac = new GenPolynomialRing(new BigRational(1), 1, vb); GenPolynomial n; n = bufac.univariate(0, 2); n = n.subtract(bufac.fromInteger(3)); //System.out.println("n = " + n); AlgebraicNumberRing afac = new AlgebraicNumberRing(m); //System.out.println("afac = " + afac); AlgebraicNumberRing bfac = new AlgebraicNumberRing(n); //System.out.println("bfac = " + bfac); PrimitiveElement pe; pe = PolyUtilApp. primitiveElement(afac, bfac); //System.out.println("pe = " + pe); AlgebraicNumberRing cfac = pe.primitiveElem; AlgebraicNumber a = afac.getGenerator(); AlgebraicNumber b = bfac.getGenerator(); // convert to primitive element field AlgebraicNumber as = PolyUtilApp. convertToPrimitiveElem(cfac, pe.A, a); AlgebraicNumber bs = PolyUtilApp. convertToPrimitiveElem(cfac, pe.B, b); // test alpha+(t)beta == gamma AlgebraicNumber cs = as.sum(bs); //System.out.println("cs = " + cs); assertEquals("alpha+beta == gamma", cs, cfac.getGenerator()); } /** * Test primitive element of extension tower. * */ public void testPrimitiveElementTower() { String[] va = new String[] { "alpha" }; String[] vb = new String[] { "beta" }; GenPolynomialRing ufac; ufac = new GenPolynomialRing(new BigRational(1), 1, va); // x^3 - 2 GenPolynomial m; m = ufac.univariate(0, 3); m = m.subtract(ufac.fromInteger(2)); //System.out.println("m = " + m); AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(m); //System.out.println("afac = " + afac); GenPolynomialRing> aufac; aufac = new GenPolynomialRing>(afac, 1, vb); // y^2 - x GenPolynomial> n; n = aufac.univariate(0, 2); n = n.subtract(aufac.getONE().multiply(afac.getGenerator())); //System.out.println("n = " + n); AlgebraicNumberRing> bfac; bfac = new AlgebraicNumberRing>(n); //System.out.println("bfac = " + bfac); PrimitiveElement pe; pe = PolyUtilApp. primitiveElement(bfac); //System.out.println("pe = " + pe); AlgebraicNumberRing cfac = pe.primitiveElem; AlgebraicNumber a = afac.getGenerator(); AlgebraicNumber> b = bfac.getGenerator(); // convert to primitive element ring AlgebraicNumber as = PolyUtilApp. convertToPrimitiveElem(cfac, pe.A, a); AlgebraicNumber bs = PolyUtilApp. convertToPrimitiveElem(cfac, pe.A, pe.B, b); // test alpha+(t)beta == gamma AlgebraicNumber cs = as.sum(bs); //System.out.println("cs = " + cs); assertEquals("alpha+beta == gamma", cs, cfac.getGenerator()); // test for polynomials, too simple String[] vx = new String[] { "x" }; GenPolynomialRing> rafac = new GenPolynomialRing>( afac, 1, vx); GenPolynomialRing>> rbfac = new GenPolynomialRing>>( bfac, 1, vx); GenPolynomial> ap = rafac.getONE().multiply(a); GenPolynomial>> bp = rbfac.getONE().multiply(b); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); GenPolynomial> asp = PolyUtilApp . convertToPrimitiveElem(cfac, pe.A, ap); GenPolynomial> bsp = PolyUtilApp . convertToPrimitiveElem(cfac, pe.A, pe.B, bp); //System.out.println("asp = " + asp); //System.out.println("bsp = " + bsp); // test alpha+(t)beta == gamma GenPolynomial> csp = asp.sum(bsp); //System.out.println("csp = " + csp); assertEquals("alpha+beta == gamma", csp.leadingBaseCoefficient(), cfac.getGenerator()); // polynomials, trivial GenPolynomialRing> gfac = csp.ring; assertEquals("gfac == afac", gfac, asp.ring); assertEquals("gfac == bfac", gfac, bsp.ring); //no assertEquals("gfac == rafac", gfac, rafac); asp = gfac.random(kl); bsp = gfac.random(kl); //System.out.println("asp = " + asp); //System.out.println("bsp = " + bsp); csp = asp.multiply(bsp); //System.out.println("csp = " + csp); assertEquals("a*b == b*a", csp, bsp.multiply(asp)); } } java-algebra-system-2.7.200/trc/edu/jas/application/QuotientSolvablePolynomialQLRTest.java000066400000000000000000000602141445075545500316140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.fd.SolvableQuotient; import edu.jas.fd.SolvableQuotientRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.QLRSolvablePolynomial; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients QuotientSolvablePolynomial QLR representation tests * with JUnit. * @author Heinz Kredel */ public class QuotientSolvablePolynomialQLRTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a QuotientSolvablePolynomialQLRTest object. * @param name String. */ public QuotientSolvablePolynomialQLRTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(QuotientSolvablePolynomialQLRTest.class); return suite; } QLRSolvablePolynomial, BigRational> a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 1; int ll = 3; int el = 3; float q = 0.15f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; QLRSolvablePolynomialRing, BigRational> ring; BigRational cfac; GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; SolvableQuotientRing qcring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wc = new WeylRelations(); cring.addRelations(wc); //System.out.println("cring = " + cring.toScript()); qcring = new SolvableQuotientRing(cring); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //System.out.println("ring = " + ring.toScript()); a = b = c = d = e = null; } @Override protected void tearDown() { //System.out.println("*ring = " + ring.toScript() + "\n"); ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new QLRSolvablePolynomial, BigRational>(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.println("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); assertTrue("isAssociative: ", ring.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 5; i++) { // a = ring.random(ll+2*i); a = ring.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ @SuppressWarnings("unchecked") public void testAddition() { a = ring.random(kl + 1, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (QLRSolvablePolynomial, BigRational>) a.sum(a); c = (QLRSolvablePolynomial, BigRational>) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(b); assertEquals("a+b = b+a", c, d); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) c.subtract(b); //System.out.println("a = " + a); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = ring.random(kl, ll, el, q); d = (QLRSolvablePolynomial, BigRational>) a.sum(b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableQuotient x = qcring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll - 1, el - 1, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll - 1, el - 1, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll - 1, el - 1, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); SolvableQuotient xp = a.leadingBaseCoefficient().inverse(); d = a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().isONE()); //System.out.println("a = " + a); //System.out.println("d = " + d); d = (QLRSolvablePolynomial, BigRational>) a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test commutative ring. */ @SuppressWarnings("unchecked") public void testCommutative() { //System.out.println("table = " + ring.table.toString(vars)); //System.out.println("table = " + ring.table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); qcring = new SolvableQuotientRing(cring); ring = new QLRSolvablePolynomialRing, BigRational>(qcring, ring); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("b*a == a*b: ", c, d); } /** * Test distributive law. */ @SuppressWarnings("unchecked") public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((QLRSolvablePolynomial, BigRational>) b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.multiply(b) .sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); } /** * Test solvable coefficient ring. */ @SuppressWarnings("unchecked") public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //no: csring.addRelations(wc); //wc.generate(csring); //assertTrue("# relations == 1", csring.table.size() == 1); assertTrue("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); SolvableQuotientRing qcsring = new SolvableQuotientRing(csring); assertTrue("isCommutative()", qcsring.isCommutative()); assertTrue("isAssociative()", qcsring.isAssociative()); ring = new QLRSolvablePolynomialRing, BigRational>(qcsring, ring); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println(":ring = " + ring.toScript()); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); // + a //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("::ring = " + ring.toScript()); //System.out.println("ring.polCoeff = " + ring.polCoeff); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new QLRSolvablePolynomial, BigRational>(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new QLRSolvablePolynomial, BigRational>(ring, yy); //System.out.println("b = " + b.toScript()); c = a.multiply(b); //System.out.println("gens: " + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); } } //System.out.println("============="); //a = ring.random(kl, ll, el, q); //a = ring.getONE(); a = ring.parse("x^2 + a b"); //System.out.println("a = " + a.toScript()); //b = ring.random(kl, ll, el, q); //b = ring.getONE(); b = ring.parse("a b + a"); // a b^2 + a b = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("b = " + b.toScript()); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); e = (QLRSolvablePolynomial, BigRational>) b.inverse(); //System.out.println("e = " + e.toScript()); assertTrue("b*b^-1 == 1", e.multiply(b).isONE()); c = e.multiply(c); d = d.multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a == b * 1/b * a", a.equals(c)); assertTrue("a == a * 1/b * b", a.equals(d)); } /* * Test extension and contraction for Weyl relations. */ @SuppressWarnings("unchecked") public void testExtendContractWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); wlc.generate(csring); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); int k = rl; QLRSolvablePolynomialRing, BigRational> pfe = ring.extend(k); //System.out.println("pfe = " + pfe.toScript()); QLRSolvablePolynomialRing, BigRational> pfec = pfe.contract(k); //System.out.println("pfec = " + pfec.toScript()); assertEquals("ring == pfec", ring, pfec); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el * el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ae = (QLRSolvablePolynomial, BigRational>) a .extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("a = " + a); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertTrue("#coeffs == 1", ml.size() == 1); assertEquals("a == aec", a, aec); } /* * Test reversion for Weyl relations. */ @SuppressWarnings("unchecked") public void testReverseWeyl() { //GenSolvablePolynomialRing> csring = // new GenSolvablePolynomialRing>(cring, tord, cvars); //RelationGenerator> wlc = new WeylRelations>(); //wlc.generate(csring); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = cring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); QLRSolvablePolynomialRing, BigRational> pfr = ring.reverse(); QLRSolvablePolynomialRing, BigRational> pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("|ring = " + ring.toScript()); //System.out.println("|pfr = " + pfr.toScript()); //System.out.println("|pfrr = " + pfrr.toScript()); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el * el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ar = (QLRSolvablePolynomial, BigRational>) a .reverse(pfr); QLRSolvablePolynomial, BigRational> arr = (QLRSolvablePolynomial, BigRational>) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("a = " + a); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /* * Test recursive for Weyl relations. */ public void testRecursiveWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelations(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute( (GenPolynomialRing) sring, (GenPolynomial>) cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /* * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/application/RealAlgebraicTest.java000066400000000000000000000265261445075545500263560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.root.RealRootTuple; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RealAlgebraicNumber Test using JUnit. * @author Heinz Kredel */ public class RealAlgebraicTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RealAlgebraicTest object. * @param name String. */ public RealAlgebraicTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RealAlgebraicTest.class); return suite; } RealAlgebraicRing fac; GenPolynomialRing mfac; RealAlgebraicNumber a, b, c, d, e; int rl = 2; int kl = 10; int ll = 10; int el = ll; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; BigRational rfac = new BigRational(); String[] vars = new String[] { "x", "y" }; rl = vars.length; TermOrder tord = new TermOrder(TermOrder.INVLEX); mfac = new GenPolynomialRing(rfac, tord, vars); //System.out.println("mfac = " + mfac); // z^3 - 2 i: z |--> x + i y GenPolynomial fr = mfac.parse("y**3 - 3 * x**2 * y - 2"); GenPolynomial fi = mfac.parse("-3 * x * y**2 + x**3"); List> li = new ArrayList>(2); li.add(fr); li.add(fi); Ideal id = new Ideal(mfac, li); //System.out.println("id = " + id); List> idul = id.zeroDimRootDecomposition(); IdealWithUniv idu = idul.get(0); //if (idul.size() > 1) { //System.out.println("idul = " + idul); //idu = idul.get(1); //} //System.out.println("idu = " + idu); GenPolynomial x = idu.ideal.list.list.remove(1); //System.out.println("x = " + x); x = x.multiply(x).subtract(mfac.fromInteger(3)); //System.out.println("x = " + x); idu.ideal.list.list.add(x); //System.out.println("idu = " + idu); IdealWithRealAlgebraicRoots idr = PolyUtilApp. realAlgebraicRoots(idu.ideal) .get(0); //System.out.println("idr = " + idr); //idr.doDecimalApproximation(); //for ( List d : idr.decimalApproximation() ) { // System.out.println("d = " + d); //} List>> ran = idr.ran; RealRootTuple root = new RealRootTuple(ran.get(0)); if (ran.size() > 1) { //System.out.println("ran = " + ran); root = new RealRootTuple(ran.get(1)); } //System.out.println("root = " + root); fac = new RealAlgebraicRing(idu, root); //,not true); //System.out.println("fac = " + fac); } @Override protected void tearDown() { ComputerThreads.terminate(); a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); //assertTrue("length( c ) = 1", c.number.getVal().length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); //assertTrue("length( d ) = 0", d.number.getVal().length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); String ts = fac.toScript(); //System.out.println("ts = " + ts); assertTrue("RealN in toScript", ts.indexOf("RealN") >= 0); ts = fac.getRoot().toScript(); //System.out.println("ts = " + ts); assertTrue("ts = [x,y]", ts.indexOf("[x,y]") >= 0); assertTrue("#rat(root) = 2", fac.getRoot().getRational().size() == rl); assertTrue("#dec(root) = 2", fac.getRoot().decimalMagnitude().size() == rl); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(el); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } // fac.random(kl*(i+1), ll+2*i, el+i, q ); //assertTrue("length( a" + i + " ) <> 0", a.number.getVal().length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test real and imaginary. */ public void testReIm() { //System.out.println("fac = " + fac.toScript()); a = fac.random(ll); b = fac.random(ll); //a = fac.getZERO(); //a = fac.getONE(); //a = fac.parse("x"); //a = fac.parse("y^3 + 2"); //a = fac.parse("3 y^2"); //b = fac.parse("y"); //System.out.println("a = " + a); //System.out.println("b = " + b); ComplexRing> crr; crr = new ComplexRing>(fac); Complex> ac, cc, dc, ec; cc = new Complex>(crr, a, b); //System.out.println("cc = " + cc); assertEquals("a == re(c)", a, cc.getRe()); assertEquals("b == im(c)", b, cc.getIm()); dc = cc.conjugate(); ec = dc.conjugate(); //System.out.println("dc = " + dc); //System.out.println("ec = " + ec); assertEquals("con(con(c)) = c", cc, ec); ac = cc.multiply(dc); ec = cc.norm(); //System.out.println("ac = " + ac); //System.out.println("ec = " + ec); c = ac.getRe(); e = ec.getRe(); //System.out.println("c = " + c); //System.out.println("e = " + e); assertEquals("c*con(c) = norm(c)", c, e); c = ac.getIm(); e = ec.getIm(); //System.out.println("c = " + c); //System.out.println("e = " + e); assertEquals("c*con(c) = norm(c)", c, e); } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1", fac.getONE(), d); try { a = fac.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { //pass, return; } } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test signum and magnitude. */ public void testSignum() { a = fac.random(ll); //a = fac.getONE(); //System.out.println("a = " + a); int s = a.signum(); //System.out.println("sign(a) = " + s); assertTrue("isZERO( c )", (a.isZERO() && s == 0) || (!a.isZERO() && s != 0)); BigDecimal r = a.decimalMagnitude(); //System.out.println("magnitude(a) = " + r); b = a.multiply(a); BigDecimal rb = b.decimalMagnitude(); //System.out.println("magnitude(a*a) = " + rb); BigDecimal rr = r.multiply(r); //System.out.println("magnitude(a)*magnitude(a) = " + rr); BigDecimal eps = Power.positivePower(new BigDecimal(0.1), BigDecimal.DEFAULT_PRECISION - 8); //System.out.println("eps = " + eps); BigDecimal err = rr.subtract(rb).abs().divide(rr.abs().sum(rb.abs())); //System.out.println("err = " + err); assertTrue("magnitude(a)*magnitude(a) == magnitude(a*a): " + err + " <= " + eps, err.compareTo(eps) <= 0); } /** * Test compareTo of complex algebraic numbers. */ public void testCompare() { a = fac.random(ll).abs(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); int ab = a.compareTo(b); int bc = b.compareTo(c); int ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); a = a.negate(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); ab = a.compareTo(b); bc = b.compareTo(c); ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); } } java-algebra-system-2.7.200/trc/edu/jas/application/ReductionTest.java000066400000000000000000000201761445075545500256300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Reduction tests with JUnit. * @author Heinz Kredel */ public class ReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a ReductionTest object. * @param name String */ public ReductionTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(ReductionTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; List> L; PolynomialList F, G; int rl = 2; int kl = 2; int ll = 3; int el = 3; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new BigRational(0), rl); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /* * Test dummy. * public void testDummy() { } */ /** * Test rational coefficient polynomial parametric reduction, * caseDistinction and determination. */ public void testRatPolReduction() { RingFactory bi = new BigRational(0); GenPolynomialRing pr = new GenPolynomialRing(bi, 2, new String[] { "a", "b" }); GenPolynomialRing> fac = new GenPolynomialRing>( pr, rl); CReductionSeq cred = new CReductionSeq(bi); GenPolynomial> a = fac.random(kl, ll, el, q); while (a.isZERO()) { a = fac.random(kl, ll, el, q).sum(fac.getONE()); } GenPolynomial> b = fac.random(kl, ll, el, q); while (b.isZERO()) { b = fac.random(kl, ll, el, q).subtract(fac.getONE()); } GenPolynomial> g = fac.getZERO(); Map.Entry> m = a.leadingMonomial(); ExpVector e = m.getKey(); GenPolynomial c = m.getValue(); GenPolynomial> r = fac.getZERO(); r = r.sum(c, e); if (r.isZERO()) { r = fac.getONE(); } GenPolynomial> w = a.reductum(); ColorPolynomial p = new ColorPolynomial(g, r, w); //System.out.println("p = " + p); assertTrue("check(p) ", p.checkInvariant()); assertTrue("deter(p) ", p.isDetermined()); //System.out.println("cond != 0: " + p.getConditionNonZero()); //System.out.println("cond == 0: " + p.getConditionZero()); p = new ColorPolynomial(r, g, w); //System.out.println("p = " + p); assertTrue("check(p) ", p.checkInvariant()); if (!w.isZERO()) { assertFalse("deter(p) ", p.isDetermined()); } //System.out.println("cond != 0: " + p.getConditionNonZero()); //System.out.println("cond == 0: " + p.getConditionZero()); p = new ColorPolynomial(r, w, g); //System.out.println("p = " + p); assertTrue("check(p) ", p.checkInvariant()); assertTrue("deter(p) ", p.isDetermined()); //System.out.println("cond != 0: " + p.getConditionNonZero()); //System.out.println("cond == 0: " + p.getConditionZero()); // wrong test: p = new ColorPolynomial(w,r,g); //(w,g,r); //System.out.println("p = " + p); //if ( !w.isZERO() ) { // assertFalse("check(p) ", p.checkInvariant()); //} //assertFalse("deter(p) ", p.isDetermined()); //assertFalse("p == 0 ", p.isZERO()); //System.out.println("cond != 0: " + p.getConditionNonZero()); //System.out.println("cond == 0: " + p.getConditionZero()); p = new ColorPolynomial(w, g, g); //System.out.println("p = " + p); assertTrue("check(p) ", p.checkInvariant()); assertTrue("deter(p) ", p.isDetermined()); assertTrue("p == 0 ", p.isZERO()); //System.out.println("cond != 0: " + p.getConditionNonZero()); //System.out.println("cond == 0: " + p.getConditionZero()); List> i = new ArrayList>(); Ideal id = new Ideal(pr, i); List> cp = new ArrayList>(); Condition cond = new Condition(id); ColoredSystem s = new ColoredSystem(cond, cp); //System.out.println("s = " + s); String z = s.toString() + ", " + s.toScript(); //System.out.println("z = " + z + ", " + z.length()); assertTrue("length( string(s) ) >= 0", z.length() >= 0); assertTrue("isDetermined ", s.isDetermined()); assertTrue("checkInvariant ", s.checkInvariant()); List> CS = new ArrayList>(); CS.add(s); //System.out.println("CS = " + CS); List> CSp = CS; //System.out.println("\na = " + a); //System.out.println("b = " + b + "\n"); //CS = cred.determine(p); //System.out.println("CS = " + CS); for (ColoredSystem x : CS) { assertTrue("isDetermined ", x.isDetermined()); assertTrue("checkInvariant ", x.checkInvariant()); } List>> L; L = new ArrayList>>(); L.add(a); L.add(b); //System.out.println("\na = " + a); //System.out.println("b = " + b + "\n"); //System.out.println("L = " + L); //List> Ccond; //Ccond = cred.caseDistinction(L); //for ( Condition cnd : Ccond ) { // System.out.println("" + cnd); //} //+System.out.println("Ccond = " + Ccond); // check if polynomials are determined CSp = cred.determine(L); //+System.out.println("CSp = " + CSp); for (ColoredSystem x : CSp) { assertTrue("isDetermined ", x.isDetermined()); assertTrue("checkInvariant ", x.checkInvariant()); } // check if reduced polynomials are in normalform ColorPolynomial q, h; //List> NCS; for (ColoredSystem x : CSp) { int k = x.list.size(); for (int j = 0; j < k; j++) { p = x.list.get(j); for (int l = j + 1; l < k; l++) { q = x.list.get(l); h = cred.SPolynomial(p, q); //System.out.println("spol(a,b) = " + h); boolean t = true; //cred.isNormalform( x.list, h ); //System.out.println("isNF(spol(a,b)) = " + t); h = cred.normalform(x.condition, x.list, h); //System.out.println("NF(spol(a,b)) = " + h); t = cred.isNormalform(x.list, h); //System.out.println("isNF(NF(spol(a,b))) = " + t); assertTrue("isNF(NF(spol(a,b))) ", t); //h = x.condition.reDetermine( h ); } } } } } java-algebra-system-2.7.200/trc/edu/jas/application/ResidueSolvablePolynomialQLRTest.java000066400000000000000000000535261445075545500314140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.QLRSolvablePolynomial; import edu.jas.poly.QLRSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients ResidueSolvablePolynomial QLR representation tests * with JUnit. * @author Heinz Kredel */ public class ResidueSolvablePolynomialQLRTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ResidueSolvablePolynomialQLRTest object. * @param name String. */ public ResidueSolvablePolynomialQLRTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ResidueSolvablePolynomialQLRTest.class); return suite; } QLRSolvablePolynomial, BigRational> a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 3; int ll = 4; int el = 3; float q = 0.3f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; SolvableResidueRing rring; SolvableIdeal sideal; QLRSolvablePolynomialRing, BigRational> ring; BigRational cfac; GenSolvablePolynomialRing sring; GenPolynomialRing cring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); sring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //not possible: sring.addRelations(wc); //wc.generate(sring); List> il = new ArrayList>(); GenSolvablePolynomial p1 = sring.parse("b - a^2"); il.add(p1); //p1 = sring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(sring, il); sideal = sideal.twosidedGB(); if (sideal.isONE()) { System.out.println("twosided sideal = " + sideal.toScript()); throw new IllegalArgumentException("ideal is one"); } rring = new SolvableResidueRing(sideal); ring = new QLRSolvablePolynomialRing, BigRational>(rring, tord, vars); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); List>> qrel = ring.table.relationList(); //System.out.println("qrel = " + qrel); List>> prel = new ArrayList>>(); for (GenSolvablePolynomial> q : qrel) { GenSolvablePolynomial> p = ring.toPolyCoefficients(q); prel.add(p); } //System.out.println("prel = " + prel); ring.polCoeff.table.addSolvRelations(prel); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new QLRSolvablePolynomial, BigRational>(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); String s = ring.toScript(); //System.out.println("ring.toScript: " + s + ", " + s.length()); assertEquals("#s == 291: " + s, s.length(), 291); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ @SuppressWarnings("unchecked") public void testAddition() { a = ring.random(kl, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (QLRSolvablePolynomial, BigRational>) a.sum(a); c = (QLRSolvablePolynomial, BigRational>) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (QLRSolvablePolynomial, BigRational>) a.sum(b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableResidue x = rring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) a.sum(b); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (QLRSolvablePolynomial, BigRational>) b.sum(a); d = (QLRSolvablePolynomial, BigRational>) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QLRSolvablePolynomial, BigRational>) a.subtract(b); d = (QLRSolvablePolynomial, BigRational>) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll, el, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); d = (QLRSolvablePolynomial, BigRational>) a.monic(); //System.out.println("d = " + d); assertTrue("a.monic(): " + d, d.leadingBaseCoefficient().isONE() || d.leadingBaseCoefficient().equals(a.leadingBaseCoefficient())); } /** * Test partially commutative ring. */ @SuppressWarnings("unchecked") public void testPartCommutative() { //System.out.println("table = " + table.toString(vars)); //System.out.println("table = " + table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); ring = new QLRSolvablePolynomialRing, BigRational>(rring, ring); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative() || !rring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("ba == ab: ", c, d); } /** * Test distributive law. */ @SuppressWarnings("unchecked") public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((QLRSolvablePolynomial, BigRational>) b.sum(c)); e = (QLRSolvablePolynomial, BigRational>) a.multiply(b) .sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test solvable coefficient ring. */ @SuppressWarnings("unchecked") public void testSolvableCoeffsRelations() { assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring.toScript()); QLRSolvablePolynomial, BigRational> r1 = ring.parse("z"); GenSolvablePolynomial r2 = sring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a z + b"); GenSolvablePolynomial> pp = ring.toPolyCoefficients(rp); //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); //System.out.println("pp = " + pp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), pp); //ring.polCoeff.table.update(r1.leadingExpVector(), r2.leadingExpVector(), pp); //ring.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new QLRSolvablePolynomial, BigRational>(ring, xx); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new QLRSolvablePolynomial, BigRational>(ring, yy); c = a.multiply(b); //System.out.println("gens:" + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); ev = a.leadingBaseCoefficient().val.leadingExpVector() .sum(b.leadingBaseCoefficient().val.leadingExpVector()); assertTrue("LT(lc(a))*LT(lc(b)) == LT(lc(c))", c.leadingBaseCoefficient().val.leadingExpVector().equals(ev)); } } //System.out.println("ring = " + ring.toScript()); a = ring.random(kl, ll, el, q); //a = ring.getONE(); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.getONE(); //System.out.println("b = " + b); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); } /** * Test extension and contraction for Weyl relations. */ @SuppressWarnings("unchecked") public void testExtendContractWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = sring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); int k = rl; QLRSolvablePolynomialRing, BigRational> pfe = ring.extend(k); //System.out.println("pfe = " + pfe); QLRSolvablePolynomialRing, BigRational> pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ae = (QLRSolvablePolynomial, BigRational>) a .extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ @SuppressWarnings("unchecked") public void testReverseWeyl() { QLRSolvablePolynomial, BigRational> r1 = ring.parse("x"); GenSolvablePolynomial r2 = sring.parse("a"); QLRSolvablePolynomial, BigRational> rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); QLRSolvablePolynomialRing, BigRational> pfr = ring.reverse(); QLRSolvablePolynomialRing, BigRational> pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); QLRSolvablePolynomial, BigRational> a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QLRSolvablePolynomial, BigRational> ar = (QLRSolvablePolynomial, BigRational>) a .reverse(pfr); QLRSolvablePolynomial, BigRational> arr = (QLRSolvablePolynomial, BigRational>) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test recursive for Weyl relations. */ @SuppressWarnings("unchecked") public void testRecursiveWeyl() { GenSolvablePolynomialRing>> rsring = ring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial> ad, bd, cd, dd; RecSolvablePolynomial> ar, br, cr, dr; ad = ring.random(kl, ll, el, q); bd = ring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, ad); br = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial>) PolyUtil .> distribute(ring, cr); // //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /* * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/application/ResidueSolvablePolynomialTest.java000066400000000000000000000452171445075545500310330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients ResidueSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class ResidueSolvablePolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ResidueSolvablePolynomialTest object. * @param name String. */ public ResidueSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ResidueSolvablePolynomialTest.class); return suite; } ResidueSolvablePolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 3; int ll = 4; int el = 3; float q = 0.3f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; SolvableResidueRing rring; SolvableIdeal sideal; ResidueSolvablePolynomialRing ring; BigRational cfac; GenSolvablePolynomialRing sring; GenPolynomialRing cring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); sring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wc = new WeylRelations(); //not possible: sring.addRelations(wc); List> il = new ArrayList>(); GenSolvablePolynomial p1 = sring.parse("b - a^2"); il.add(p1); //p1 = sring.parse("a - b^5"); //il.add(p1); sideal = new SolvableIdeal(sring, il); sideal = sideal.twosidedGB(); if (sideal.isONE()) { System.out.println("twosided sideal = " + sideal.toScript()); throw new IllegalArgumentException("ideal is one"); } rring = new SolvableResidueRing(sideal); ring = new ResidueSolvablePolynomialRing(rring, tord, vars); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); List>> qrel = ring.table.relationList(); //System.out.println("qrel = " + qrel); List>> prel = new ArrayList>>(); for (GenSolvablePolynomial> q : qrel) { GenSolvablePolynomial> p = ring.toPolyCoefficients(q); prel.add(p); } //System.out.println("prel = " + prel); ring.polCoeff.table.addSolvRelations(prel); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { a = ring.getZERO(); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new ResidueSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (ResidueSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (ResidueSolvablePolynomial) a.sum(a); c = (ResidueSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (ResidueSolvablePolynomial) b.sum(a); d = (ResidueSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (ResidueSolvablePolynomial) a.sum(b.sum(c)); e = (ResidueSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableResidue x = rring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (ResidueSolvablePolynomial) a.sum(b); d = (ResidueSolvablePolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (ResidueSolvablePolynomial) a.subtract(b); d = (ResidueSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (ResidueSolvablePolynomial) b.sum(a); d = (ResidueSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (ResidueSolvablePolynomial) a.subtract(b); d = (ResidueSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll, el, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); d = (ResidueSolvablePolynomial) a.monic(); //System.out.println("d = " + d); assertTrue("a.monic(): " + d, d.leadingBaseCoefficient().isONE() || d.leadingBaseCoefficient().equals(a.leadingBaseCoefficient())); } /** * Test partially commutative ring. */ public void testPartCommutative() { //System.out.println("table = " + table.toString(vars)); //System.out.println("table = " + table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); ring = new ResidueSolvablePolynomialRing(rring, ring); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative() || !rring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("ba == ab: ", c, d); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((ResidueSolvablePolynomial) b.sum(c)); e = (ResidueSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test solvable coefficient ring. */ public void testSolvableCoeffsRelations() { assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring.toScript()); ResidueSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = sring.parse("a"); ResidueSolvablePolynomial rp = ring.parse("a x + b"); GenSolvablePolynomial> pp = ring.toPolyCoefficients(rp); //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); //System.out.println("pp = " + pp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), pp); //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); //System.out.println("gens = " + gens); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; try { GenSolvablePolynomial> ap = ring.toPolyCoefficients(xx); //System.out.println("ap = " + ap); c = ring.fromPolyCoefficients(ap); //System.out.println("c = " + c); assertEquals("from(to(xx)) == xx", xx, c); } catch (IllegalArgumentException iae) { // pass } a = new ResidueSolvablePolynomial(ring, xx); try { GenSolvablePolynomial> ap = ring.toPolyCoefficients(a); //System.out.println("ap = " + ap); c = ring.fromPolyCoefficients(ap); //System.out.println("c = " + c); assertEquals("from(to(a)) == a", a, c); } catch (IllegalArgumentException iae) { // pass } for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new ResidueSolvablePolynomial(ring, yy); c = a.multiply(b); //System.out.println("gens:" + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); ev = a.leadingBaseCoefficient().val.leadingExpVector() .sum(b.leadingBaseCoefficient().val.leadingExpVector()); assertTrue("LT(lc(a))*LT(lc(b)) == LT(lc(c))", c.leadingBaseCoefficient().val.leadingExpVector().equals(ev)); } } //System.out.println("ring = " + ring.toScript()); a = ring.random(kl, ll, el, q); //a = ring.getONE(); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.getONE(); //System.out.println("b = " + b); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); } /** * Test extension and contraction for Weyl relations. */ public void testExtendContractWeyl() { ResidueSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = sring.parse("a"); ResidueSolvablePolynomial rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); int k = rl; ResidueSolvablePolynomialRing pfe = ring.extend(k); //System.out.println("pfe = " + pfe); ResidueSolvablePolynomialRing pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); ResidueSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); ResidueSolvablePolynomial ae = (ResidueSolvablePolynomial) a.extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ public void testReverseWeyl() { ResidueSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = sring.parse("a"); ResidueSolvablePolynomial rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), ring.toPolyCoefficients(rp)); ResidueSolvablePolynomialRing pfr = ring.reverse(); ResidueSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); ResidueSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); ResidueSolvablePolynomial ar = (ResidueSolvablePolynomial) a.reverse(pfr); ResidueSolvablePolynomial arr = (ResidueSolvablePolynomial) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test recursive for Weyl relations. */ public void testRecursiveWeyl() { GenSolvablePolynomialRing>> rsring = ring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial> ad, bd, cd, dd; RecSolvablePolynomial> ar, br, cr, dr; ad = ring.random(kl, ll, el, q); bd = ring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, ad); br = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial>) PolyUtil .> recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial>) PolyUtil .> distribute(ring, cr); // //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/application/ResidueSolvableWordPolynomialTest.java000066400000000000000000000377041445075545500316710ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.RecSolvableWordPolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients ResidueSolvableWordPolynomial tests with JUnit. * @author Heinz Kredel */ public class ResidueSolvableWordPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ResidueSolvableWordPolynomialTest object. * @param name String. */ public ResidueSolvableWordPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ResidueSolvableWordPolynomialTest.class); return suite; } ResidueSolvableWordPolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 2; int ll = 3; int el = 2; float q = 0.3f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; WordResidueRing rring; WordIdeal wideal; ResidueSolvableWordPolynomialRing ring; BigRational cfac; GenWordPolynomialRing wring; GenPolynomialRing cring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); wring = new GenWordPolynomialRing(cfac, cvars); //RelationGenerator wc = new WeylRelations(); //not possible: wring.addRelations(wc); List> il = new ArrayList>(); //GenWordPolynomial p1 = wring.parse("b - a^2"); // not associative //GenWordPolynomial p1 = wring.parse("b - a^3"); // not associative //GenWordPolynomial p1 = wring.parse("b a - 1"); // Weyl relation, result not assoc //GenWordPolynomial p1 = wring.parse("a b - 1"); // isAssoc? GenWordPolynomial p1 = wring.parse("b a - a b"); // commutative, okay il.add(p1); //p1 = wring.parse("a - b^5"); //il.add(p1); //System.out.println("il = " + il); wideal = new WordIdeal(wring, il); //System.out.println("wideal = " + wideal.toScript()); wideal = wideal.GB(); //System.out.println("twosided wideal = " + wideal.toScript()); if (wideal.isONE()) { System.out.println("twosided wideal = " + wideal.toScript()); throw new IllegalArgumentException("ideal is one"); } rring = new WordResidueRing(wideal); //System.out.println("rring = " + rring.toScript()); ring = new ResidueSolvableWordPolynomialRing(rring, tord, vars); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); List>> qrel = ring.table.relationList(); //System.out.println("qrel = " + qrel); List>> prel = new ArrayList>>(); for (GenSolvablePolynomial> q : qrel) { GenSolvablePolynomial> p = ring.toPolyCoefficients(q); prel.add(p); } //System.out.println("prel = " + prel); ring.polCoeff.table.addSolvRelations(prel); //System.out.println("ring = " + ring.toScript()); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new ResidueSolvableWordPolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); } /** * Test random polynomial and conversion. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); RecSolvableWordPolynomial b = ring.toPolyCoefficients(a); c = ring.fromPolyCoefficients(b); assertEquals("res(poly(a)) == a", a, c); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (ResidueSolvableWordPolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (ResidueSolvableWordPolynomial) a.sum(a); c = (ResidueSolvableWordPolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (ResidueSolvableWordPolynomial) b.sum(a); d = (ResidueSolvableWordPolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (ResidueSolvableWordPolynomial) a.sum(b.sum(c)); e = (ResidueSolvableWordPolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); WordResidue x = rring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (ResidueSolvableWordPolynomial) a.sum(b); d = (ResidueSolvableWordPolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (ResidueSolvableWordPolynomial) a.subtract(b); d = (ResidueSolvableWordPolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (ResidueSolvableWordPolynomial) b.sum(a); d = (ResidueSolvableWordPolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (ResidueSolvableWordPolynomial) a.subtract(b); d = (ResidueSolvableWordPolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll, el, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); //a = ring.parse("( ( a + 11/5 ) )"); //b = ring.parse("( ( a + 35/6 ) )"); //c = ring.parse("( ( b a + 11/24 a ) )"); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e)); assertEquals("a(bc) = (ab)c", d, e); d = (ResidueSolvableWordPolynomial) a.monic(); //System.out.println("d = " + d); assertTrue("a.monic(): " + d, d.leadingBaseCoefficient().isONE() || d.leadingBaseCoefficient().abs().equals(a.leadingBaseCoefficient().abs())); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((ResidueSolvableWordPolynomial) b.sum(c)); e = (ResidueSolvableWordPolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test word coefficient ring. */ public void testWordCoeffsRelations() { assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring.toScript()); ResidueSolvableWordPolynomial r1 = ring.parse("x"); GenWordPolynomial r2 = wring.parse("a"); ResidueSolvableWordPolynomial rp = ring.parse("a x + b"); GenSolvablePolynomial> pp = ring.toPolyCoefficients(rp); //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); //System.out.println("pp = " + pp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingWord().leadingExpVector(), pp); //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new ResidueSolvableWordPolynomial(ring, xx); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new ResidueSolvableWordPolynomial(ring, yy); c = a.multiply(b); //System.out.println("gens:" + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); // not always true assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); // not true //ev = a.leadingBaseCoefficient().val.leadingWord().leadingExpVector() // .sum(b.leadingBaseCoefficient().val.leadingWord().leadingExpVector()); //assertTrue("LT(lc(a))*LT(lc(b)) == LT(lc(c))", c.leadingBaseCoefficient().val.leadingWord() // .leadingExpVector().equals(ev)); } } //System.out.println("ring = " + ring.toScript()); a = ring.random(kl, ll, el, q); //a = ring.getONE(); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.getONE(); //System.out.println("b = " + b); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); } /** * Test extension and contraction for Weyl relations. */ public void testExtendContractWeyl() { ResidueSolvableWordPolynomial r1 = ring.parse("x"); GenWordPolynomial r2 = wring.parse("a"); ResidueSolvableWordPolynomial rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingWord().leadingExpVector(), ring.toPolyCoefficients(rp)); int k = rl; ResidueSolvableWordPolynomialRing pfe = ring.extend(k); //System.out.println("pfe = " + pfe); ResidueSolvableWordPolynomialRing pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); ResidueSolvableWordPolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); ResidueSolvableWordPolynomial ae = (ResidueSolvableWordPolynomial) a .extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ public void testReverseWeyl() { ResidueSolvableWordPolynomial r1 = ring.parse("x"); GenWordPolynomial r2 = wring.parse("a"); ResidueSolvableWordPolynomial rp = ring.parse("a x + b"); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingWord().leadingExpVector(), ring.toPolyCoefficients(rp)); ResidueSolvableWordPolynomialRing pfr = ring.reverse(); ResidueSolvableWordPolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); ResidueSolvableWordPolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); ResidueSolvableWordPolynomial ar = (ResidueSolvableWordPolynomial) a .reverse(pfr); ResidueSolvableWordPolynomial arr = (ResidueSolvableWordPolynomial) ar .reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } } java-algebra-system-2.7.200/trc/edu/jas/application/ResidueTest.java000066400000000000000000000141361445075545500252730ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Residue tests with JUnit. * @author Heinz Kredel */ public class ResidueTest extends TestCase { /** * main. */ public static void main(String[] args) { // junit.textui.TestRunner.run(suite()); } /** * Constructs a ResidueTest object. * @param name String. */ public ResidueTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ResidueTest.class); return suite; } //private final static int bitlen = 100; Ideal id; ResidueRing fac; GenPolynomialRing mfac; List> F; Residue a; Residue b; Residue c; Residue d; Residue e; int rl = 3; int kl = 3; int ll = 7; int el = 3; float q = 0.4f; int il = (rl == 1 ? 1 : 2); @Override protected void setUp() { a = b = c = d = e = null; mfac = new GenPolynomialRing(new BigRational(1), rl); F = new ArrayList>(il); for (int i = 0; i < il; i++) { GenPolynomial mo = mfac.random(kl, ll, el, q); while (mo.isConstant()) { mo = mfac.random(kl, ll, el, q); } F.add(mo); } id = new Ideal(mfac, F); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; fac = new ResidueRing(id); //System.out.println("fac = " + fac); F = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; id = null; mfac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1 ", c.val.length() == 1 || id.isONE()); assertTrue("isZERO( c )", !c.isZERO() || id.isONE()); assertTrue("isONE( c )", c.isONE() || id.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.val.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { //a = fac.random(ll+i); a = fac.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.val.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(kl, ll, el, q); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(kl, ll, el, q); if (a.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); a = a.monic(); b = fac.random(kl, ll, el, q); if (b.isZERO()) { return; } assertTrue("not isZERO( b )", !b.isZERO()); b = b.monic(); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); d = c.remainder(a); //System.out.println("c = " + c); //System.out.println("d = " + d); if (d.isZERO()) { d = c.divide(a); //System.out.println("c = " + c); //System.out.println("d = " + d); e = d.multiply(a); //System.out.println("e = " + e); assertEquals("((b*a)/a)*a = b*a", e, c); } c = fac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } } } java-algebra-system-2.7.200/trc/edu/jas/application/RingFactoryTokenizerTest.java000066400000000000000000000434771445075545500300270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RingFactoryTokenizer tests with JUnit. * @author Heinz Kredel */ public class RingFactoryTokenizerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RingFactoryTokenizerTest object. * @param name String. */ public RingFactoryTokenizerTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RingFactoryTokenizerTest.class); return suite; } RingFactory fac; // unused GenPolynomialRing pfac; GenSolvablePolynomialRing spfac; RingFactoryTokenizer parser; Reader source; @Override protected void setUp() { fac = null; pfac = null; parser = null; source = null; } @Override protected void tearDown() { fac = null; pfac = null; parser = null; source = null; } /** * Test rational polynomial. */ @SuppressWarnings("unchecked") public void testBigRational() { String exam = "Rat(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3/4 - 6/8 ), " + "( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } /** * Test integer polynomial. */ @SuppressWarnings("unchecked") public void testBigInteger() { String exam = "Int(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigInteger fac = new BigInteger(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } /** * Test modular integer polynomial. */ @SuppressWarnings("unchecked") public void testModInteger() { String exam = "Mod 19 (x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 + 19 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } ModIntRing fac = new ModIntRing(19); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); //System.out.println("pfac = " + pfac); //System.out.println("f.ring = " + f.ring); assertEquals("pfac == f", pfac, f); ModLongRing lfac = new ModLongRing(19); assertFalse("fac != lfac", fac.equals(lfac)); assertFalse("lfac != f.coFac", lfac.equals(f.coFac)); } /** * Test complex polynomial. */ @SuppressWarnings("unchecked") public void testBigComplex() { String exam = "Complex(x,y,z) L " + "( " + "( 1i0 ), " + "( 0i0 ), " + "( 3/4i2 - 6/8i2 ), " + "( 1i0 x + x^3 + 1i3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigComplex fac = new BigComplex(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } /** * Test decimal polynomial. */ @SuppressWarnings("unchecked") public void testBigDecimal() { String exam = "D(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 0.25 * 0.25 - 0.25^2 ), " + "( 1 x + x^3 + 0.3333333333333333333333 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigDecimal fac = new BigDecimal(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } /** * Test quaternion polynomial. */ @SuppressWarnings("unchecked") public void testBigQuaternion() { String exam = "Quat(x,y,z) L " + "( " + "( 1i0j0k0 ), " + "( 0i0j0k0 ), " + "( 3/4i2j1k3 - 6/8i2j1k3 ), " + "( 1 x + x^3 + 1i2j3k4 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigQuaternionRing fac = new BigQuaternionRing(); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } /** * Test rational function coefficients. */ @SuppressWarnings("unchecked") public void testRationalFunction() { String exam = "RatFunc(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3/4 - 6/8 ), " + "( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing> f = null; try { f = (GenPolynomialRing>) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigInteger fac = new BigInteger(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); QuotientRing qfac = new QuotientRing(pfac); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("f.coFac = " + f.ring.coFac.toScript()); assertEquals("qfac == f.coFac", qfac, f.coFac); } /** * Test integral function coefficients. */ @SuppressWarnings("unchecked") public void testIntegralFunction() { String exam = "IntFunc(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3/4 - 6/8 ), " + "( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing> f = null; try { f = (GenPolynomialRing>) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); //System.out.println("pfac = " + pfac.toScript()); //System.out.println("f.coFac = " + f.coFac.toScript()); assertEquals("pfac == f.coFac", pfac, f.coFac); } /** * Test modular function coefficients. */ @SuppressWarnings("unchecked") public void testModularFunction() { String exam = "ModFunc 32003 (x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3/4 - 6/8 ), " + "( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing> f = null; try { f = (GenPolynomialRing>) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } ModIntegerRing fac = new ModIntegerRing(32003); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); QuotientRing qfac = new QuotientRing(pfac); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("f.coFac = " + f.ring.toScript()); assertEquals("qfac == f.coFac", qfac, f.coFac); } /** * Test rational solvable polynomial. */ @SuppressWarnings("unchecked") public void testSolvableBigRational() { String exam = "Rat(x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + " ( 1 ), " + " ( 0 ), " + " ( 3/4 - 6/8 ), " + " ( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenSolvablePolynomialRing f = null; try { f = (GenSolvablePolynomialRing) parser.nextSolvablePolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == f", spfac, f); //System.out.println("spfac = " + spfac); //System.out.println("spfac.table = " + spfac.table); } /** * Test mod integer solvable polynomial. */ @SuppressWarnings("unchecked") public void testSolvableModInteger() { String exam = "Mod 19 (x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 + 19 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenSolvablePolynomialRing f = null; try { f = (GenSolvablePolynomialRing) parser.nextSolvablePolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } ModIntRing fac = new ModIntRing(19); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == f", spfac, f); //System.out.println("spfac = " + spfac); //System.out.println("spfac.table = " + spfac.table); } /** * Test integer polynomial module. */ @SuppressWarnings("unchecked") public void testBigIntegerModule() { String exam = "Int(x,y,z) L " + "( " + " ( " + " ( 1 ), " + " ( 0 ), " + " ( 3 2 - 6 ), " + " ( 1 x + x^3 + 3 y z - x^3 ) " + " ), " + " ( ( 1 ), ( 0 ) ) " + ")"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing m = null; try { m = (GenPolynomialRing) parser.nextSubModuleRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigInteger fac = new BigInteger(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == m.ring", pfac, m); } /** * Test rational solvable polynomial module. */ @SuppressWarnings("unchecked") public void testBigRationalSolvableModule() { String exam = "Rat(x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + " ( " + " ( 1 ), " + " ( 0 ), " + " ( 3/4 - 6/8 ), " + " ( 1 x + x^3 + 1/3 y z - x^3 ) " + " ), " + " ( ( x ), ( 1 ), ( 0 ) ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenSolvablePolynomialRing m = null; try { m = (GenSolvablePolynomialRing) parser.nextSolvableSubModuleRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == m.ring", spfac, m); } /** * Test rational polynomial with generic coefficients. */ @SuppressWarnings("unchecked") public void testBigRationalGeneric() { String exam = "Rat(x,y,z) L " + "( " + "( 1^3 ), " + "( 0^3 ), " + "( { 3/4 }^2 - 6/8^2 ), " + "( { 1 }^2 x + x^3 + 1/3 y z - x^3 ), " + "( 1.0001 - 0.0001 + { 0.25 }**2 - 1/4^2 ) " + " )"; source = new StringReader(exam); parser = new RingFactoryTokenizer(source); GenPolynomialRing f = null; try { f = (GenPolynomialRing) parser.nextPolynomialRing(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f", pfac, f); } } java-algebra-system-2.7.200/trc/edu/jas/application/RunGBTest.java000066400000000000000000000156241445075545500246530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.concurrent.ExecutorService; import edu.jas.kern.ComputerThreads; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * CLI tests with JUnit for GBs. * @author Heinz Kredel */ public class RunGBTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RunGBTest object. * @param name String. */ public RunGBTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RunGBTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test sequential GB. */ public void testSequentialGB() { RunGB cli = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "seq", "examples/trinks7.jas", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("sequential", sto.contains("sequential")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test sequential GB plus. */ public void testSequentialGBplus() { RunGB cli = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "seq+", "examples/trinks7.jas", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("sequential", sto.contains("sequential")); assertTrue("sequential", sto.contains("seq+")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test parallel GB. */ public void testParallelGB() { RunGB cli = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "par", "examples/trinks7.jas", "3", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("parallel", sto.contains("parallel")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test parallel GB plus. */ public void testParallelGBplus() { RunGB cli = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "par+", "examples/trinks7.jas", "3", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("parallel", sto.contains("parallel")); assertTrue("parallel", sto.contains("par+")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test with "build=" GB. */ public void testBuildGB() { RunGB cli = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "build=syzygyPairlist.iterated.graded.parallel(3)", "examples/trinks7.jas", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("iterated.graded.parallel", sto.contains("iterated.graded.parallel")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test distributed hybrid GB. */ public void testDisthybGB() { RunGB cli = new RunGB(); ExecutorService pool = ComputerThreads.getPool(); RunGB node1 = new RunGB(); RunGB node2 = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); pool.execute( () -> node1.main(new String[] { "cli", "8114" }) ); pool.execute( () -> node2.main(new String[] { "cli", "9114" }) ); cli.main(new String[] { "disthyb", "examples/trinks7.jas", "3/2", "machines.localhost", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("disthyb", sto.contains("distributed hybrid")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); pool.shutdownNow(); } /** * Test distributed hybrid GB plus. */ public void testDisthybGBplus() { RunGB cli = new RunGB(); ExecutorService pool = ComputerThreads.getPool(); RunGB node1 = new RunGB(); RunGB node2 = new RunGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); pool.execute( () -> node1.main(new String[] { "cli", "8114" }) ); pool.execute( () -> node2.main(new String[] { "cli", "9114" }) ); cli.main(new String[] { "disthyb+", "examples/trinks7.jas", "3/2", "machines.localhost", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("disthyb", sto.contains("distributed hybrid")); assertTrue("disthyb", sto.contains("disthyb+")); assertTrue("G.size() = 6", sto.contains("G.size() = 6")); assertTrue("check isGB = true", sto.contains("check isGB = true")); pool.shutdownNow(); } } java-algebra-system-2.7.200/trc/edu/jas/application/RunSGBTest.java000066400000000000000000000062661445075545500250000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import edu.jas.kern.ComputerThreads; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * CLI tests with JUnit for GBs. * @author Heinz Kredel */ public class RunSGBTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RunSGBTest object. * @param name String. */ public RunSGBTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RunSGBTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test sequential GB. */ public void testSequentialGB() { RunSGB cli = new RunSGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "seq", "left", "examples/wa_32.jas", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("sequential", sto.contains("sequential")); assertTrue("G.size() = 5", sto.contains("G.size() = 5")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test sequential two-sided GB. */ public void testSequential2tsGB() { RunSGB cli = new RunSGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "seq", "two", "examples/wa_32.jas", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("sequential", sto.contains("sequential")); assertTrue("two", sto.contains("two")); assertTrue("G.size() = 5", sto.contains("G.size() = 5")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } /** * Test parallel left GB. */ public void testParallelLeftGB() { RunSGB cli = new RunSGB(); PrintStream ps = System.out; ByteArrayOutputStream bs = new ByteArrayOutputStream(); PrintStream ss = new PrintStream(bs); try { System.setOut(ss); cli.main(new String[] { "par", "left", "examples/wa_1.jas", "3", "check" }); } finally { System.setOut(ps); } String sto = bs.toString(); //System.out.println(sto); assertTrue("parallel", sto.contains("parallel")); assertTrue("left", sto.contains("left")); assertTrue("G.size() = 8", sto.contains("G.size() = 8")); assertTrue("check isGB = true", sto.contains("check isGB = true")); } } java-algebra-system-2.7.200/trc/edu/jas/application/SolvableIdealTest.java000066400000000000000000001351321445075545500264010ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.Collections; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderOptimization; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import edu.jas.util.KsubSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * SolvableIdeal tests with JUnit. * @author Heinz Kredel */ public class SolvableIdealTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableIdealTest object. * @param name String. */ public SolvableIdealTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableIdealTest.class); return suite; } TermOrder to; GenSolvablePolynomialRing fac; List> L, M; PolynomialList F; List> G; SolvableGroebnerBase bb; GenSolvablePolynomial a, b, c, d, e; int rl = 4; // even for Weyl relations int kl = 2; //10 int ll = 3; //7 int el = 3; float q = 0.15f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "w", "x", "y", "z" }; fac = new GenSolvablePolynomialRing(coeff, rl, to, vars); RelationGenerator wl = new WeylRelations(); wl.generate(fac); bb = new SolvableGroebnerBaseSeq(); //bb = GBFactory.getImplementation(coeff); a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; ComputerThreads.terminate(); } /** * Test left ideal sum. */ public void testLeftIdealSum() { SolvableIdeal I, J, K; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); e = d; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I )", I.isGB()); I = new SolvableIdeal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I ): " + I.toScript(), I.isGB()); L = bb.leftGB(L); assertTrue("isGB( { a } )", bb.isLeftGB(L)); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); I = new SolvableIdeal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); String s = I.toScript() + "\n" + I.toString(); //System.out.println("#s = " + s.length() + ": " + s); assertTrue("#s >= 260: ", s.length() >= 260); K = I.getZERO(); assertTrue("K == 0: " + K, K.isZERO()); K = I.getONE(); assertTrue("K == 1: " + K, K.isONE()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); I = new SolvableIdeal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); //assertTrue("not isGB( I )", !I.isGB() ); L = bb.leftGB(L); assertTrue("isGB( { a, b } )", bb.isLeftGB(L)); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); // assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); L = new ArrayList>(); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); assertTrue("isGB( { c } )", bb.isLeftGB(L)); J = new SolvableIdeal(fac, L, true); K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); assertTrue("isGB( { d } )", bb.isLeftGB(L)); J = new SolvableIdeal(fac, L, true); I = K; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); assertTrue("isGB( { e } )", bb.isLeftGB(L)); J = new SolvableIdeal(fac, L, true); I = K; K = J.sum(I); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertTrue("K contains(J)", K.contains(I)); assertTrue("I contains(K)", I.contains(K)); L = K.normalform(I.getList()); I = new SolvableIdeal(fac, L, false); //System.out.println("I = " + I); assertTrue("I mod K == 0: " + I, I.isZERO()); L = new ArrayList>(); L.add(a); L.add(b); I = new SolvableIdeal(fac, L, false); I.doGB(); J = I.power(3); J = J.power(2); K = I.power(6); //System.out.println("I = " + I); //System.out.println("J = " + J); //System.out.println("K = " + K); assertEquals("equals( (I**3)**2, I**6 )", K, J); if (I.isUnit(c)) { d = I.inverse(c); e = I.normalform(d.multiply(c)); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("d*c mod I = " + e); assertTrue("inv(c) * c mod I == 1: " + e, e.isONE()); } } /** * Test right ideal sum. */ public void testRightIdealSum() { SolvableIdeal Ir, Jr, Kr; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); e = d; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); Ir = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); //assertTrue("not isONE( Ir )", !Ir.isONE()); assertTrue("isGB( Ir )", Ir.isGB()); Ir = new SolvableIdeal(fac, L, false, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); //assertTrue("not isONE( Ir )", !Ir.isONE()); assertTrue("isGB( Ir ): " + Ir.toScript(), Ir.isGB()); assertTrue("isGB( Ir )", Ir.isRightGB()); L = bb.rightGB(L); assertTrue("isGB( { a } )", bb.isRightGB(L)); Ir = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); //assertTrue("not isONE( Ir )", !Ir.isONE() ); assertTrue("isGB( Ir )", Ir.isGB()); assertTrue("isGB( Ir )", Ir.isRightGB()); Ir = new SolvableIdeal(fac, L, false, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); //assertTrue("not isONE( Ir )", !Ir.isONE() ); assertTrue("isGB( Ir )", Ir.isGB()); assertTrue("isGB( Ir )", Ir.isRightGB()); String s = Ir.toScript() + "\n" + Ir.toString(); //System.out.println("#s = " + s.length() + ": " + s); assertTrue("#s >= 260: ", s.length() >= 260); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); Ir = new SolvableIdeal(fac, L, false, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); //assertTrue("not isONE( Ir )", !Ir.isONE() ); //assertTrue("not isGB( Ir )", !Ir.isGB() ); L = bb.rightGB(L); assertTrue("isGB( { a, b } )", bb.isRightGB(L)); Ir = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); assertTrue("not isZERO( Ir )", !Ir.isZERO()); // assertTrue("not isONE( Ir )", !Ir.isONE() ); assertTrue("isGB( Ir )", Ir.isRightGB()); assertTrue("isGB( Ir )", Ir.isGB()); Jr = Ir.rightGB(); assertTrue("isGB( Jr )", Jr.isRightGB()); Jr = Ir; Kr = Jr.sum(Ir); assertTrue("not isZERO( Kr )", !Kr.isZERO()); assertTrue("isGB( Kr )", Kr.isGB()); assertTrue("isGB( Kr )", Kr.isRightGB()); assertTrue("equals( Kr, Ir )", Kr.equals(Ir)); L = new ArrayList>(); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); assertTrue("isGB( { c } )", bb.isRightGB(L)); Jr = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); Kr = Jr.sum(Ir); assertTrue("not isZERO( Kr )", !Kr.isZERO()); assertTrue("isGB( Kr )", Kr.isGB()); assertTrue("isGB( Kr )", Kr.isRightGB()); assertTrue("Kr contains(Ir)", Kr.contains(Ir)); assertTrue("Kr contains(Jr)", Kr.contains(Jr)); L = new ArrayList>(); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); assertTrue("isGB( { d } )", bb.isRightGB(L)); Jr = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); Ir = Kr; Kr = Jr.sum(Ir); assertTrue("not isZERO( Kr )", !Kr.isZERO()); assertTrue("isGB( Kr )", Kr.isGB()); assertTrue("isGB( Kr )", Kr.isRightGB()); assertTrue("Kr contains(Ir)", Kr.contains(Ir)); assertTrue("Kr contains(Jr)", Kr.contains(Jr)); L = new ArrayList>(); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); assertTrue("isGB( { e } )", bb.isRightGB(L)); Jr = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.right); Ir = Kr; Kr = Jr.sum(Ir); assertTrue("not isZERO( Kr )", !Kr.isZERO()); assertTrue("isGB( Kr )", Kr.isGB()); assertTrue("isGB( Kr )", Kr.isRightGB()); assertTrue("equals( Kr, Ir )", Kr.equals(Ir)); assertTrue("Kr contains(Jr)", Kr.contains(Ir)); assertTrue("Ir contains(Kr)", Ir.contains(Kr)); } /** * Test twosided ideal sum. */ public void testTwosideIdealSum() { SolvableIdeal It, Jt, Kt; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); e = d; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); It = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); assertTrue("not isZERO( It )", !It.isZERO()); //assertTrue("not isONE( It )", !It.isONE()); assertTrue("isGB( It )", It.isGB()); L = bb.twosidedGB(L); assertTrue("isGB( { a } )", bb.isTwosidedGB(L)); It = new SolvableIdeal(fac, L, false, SolvableIdeal.Side.twosided); assertTrue("not isZERO( It )", !It.isZERO()); //assertTrue("not isONE( It )", !It.isONE()); assertTrue("isGB( It ): " + It.toScript(), It.isGB()); assertTrue("is2sGB( It ): " + It.toScript(), It.isTwosidedGB()); It = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); assertTrue("not isZERO( It )", !It.isZERO()); //assertTrue("not isONE( It )", !It.isONE() ); assertTrue("isGB( It )", It.isGB()); String s = It.toScript() + "\n" + It.toString(); //System.out.println("#s = " + s.length() + ": " + s); assertTrue("#s >= 260: ", s.length() >= 260); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); It = new SolvableIdeal(fac, L, false, SolvableIdeal.Side.twosided); assertTrue("not isZERO( It )", !It.isZERO()); //assertTrue("not isONE( It )", !It.isONE() ); //assertTrue("not isGB( It )", !It.isGB() ); L = bb.twosidedGB(L); assertTrue("isGB( { a, b } )", bb.isTwosidedGB(L)); It = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); assertTrue("not isZERO( It )", !It.isZERO()); // assertTrue("not isONE( It )", !It.isONE() ); assertTrue("isGB( It )", It.isGB()); assertTrue("is2sGB( It ): " + It.toScript(), It.isTwosidedGB()); Jt = It; Kt = Jt.sum(It); assertTrue("not isZERO( Kt )", !Kt.isZERO()); assertTrue("isGB( Kt )", Kt.isGB()); assertTrue("equals( Kt, It )", Kt.equals(It)); L = new ArrayList>(); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.twosidedGB(L); assertTrue("isGB( { c } )", bb.isTwosidedGB(L)); Jt = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); Kt = Jt.sum(It); assertTrue("not isZERO( Kt )", !Kt.isZERO()); assertTrue("isGB( Kt )", Kt.isGB()); assertTrue("Kt equals(It)", Kt.equals(It)); assertTrue("Kt equals(Jt)", Kt.equals(Jt)); L = new ArrayList>(); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.twosidedGB(L); assertTrue("isGB( { d } )", bb.isTwosidedGB(L)); Jt = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); assertTrue("is2sGB( Jt ): " + Jt.toScript(), Jt.isTwosidedGB()); It = Kt; Kt = Jt.sum(It); assertTrue("not isZERO( Kt )", !Kt.isZERO()); assertTrue("isGB( Kt )", Kt.isGB()); assertTrue("Kt equals(It)", Kt.equals(It)); assertTrue("Kt equals(Jt)", Kt.equals(Jt)); L = new ArrayList>(); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); assertTrue("isGB( { e } )", bb.isRightGB(L)); Jt = new SolvableIdeal(fac, L, true, SolvableIdeal.Side.twosided); It = Kt; Kt = Jt.sum(It); assertTrue("not isZERO( Kt )", !Kt.isZERO()); assertTrue("isGB( Kt )", Kt.isGB()); assertTrue("equals( Kt, It )", Kt.equals(It)); //assertTrue("Kt contains(Jt)", Kt.contains(It)); //assertTrue("It contains(Kt)", It.contains(Kt)); } /** * Test SolvableIdeal product. */ public void testSolvableIdealProduct() { SolvableIdeal I, J, K, H; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el - 1, q); c = fac.random(kl, ll, el - 1, q); d = c; //fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L = new ArrayList>(); //assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); I = new SolvableIdeal(fac, L, false); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("not isONE( I )", !I.isONE() || a.isConstant()); assertTrue("isGB( I ): " + I.toScript(), I.isGB()); H = I.leftProduct(b); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com: left okay assertTrue("I contains(H)", I.contains(H)); //System.out.println("I = " + I); //System.out.println("b = " + b); //System.out.println("H = " + H); H = I.product(b); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com: not left assertTrue("I contains(H)", I.contains(H)); //System.out.println("H = " + H); L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); J = new SolvableIdeal(fac, L, false); assertTrue("not isZERO( J )", !J.isZERO()); assertTrue("not isONE( J )", !J.isONE() || a.isConstant() || b.isConstant()); assertTrue("isGB( J ): " + J.toScript(), J.isGB()); K = I.product(J); //System.out.println("I = " + I); //System.out.println("J = " + J); //System.out.println("K = " + K); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); assertEquals("H == K: ", H, K); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); //non-com assertTrue("H contains(K)", H.contains(K)); L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); //non-com assertTrue("H contains(K)", H.contains(K)); L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.leftGB(L); J = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = I.intersect(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); assertTrue("I contains(H)", I.contains(H)); assertTrue("J contains(H)", J.contains(H)); //non-com assertTrue("H contains(K)", H.contains(K)); List> si = new ArrayList>(); si.add(K); si.add(J); H = I.intersect(si); //System.out.println("I = " + I); //System.out.println("si = " + si); //System.out.println("H = " + H); assertEquals("H == K: ", H, K); } /** * Test SolvableIdeal quotient. */ public void testSolvableIdealQuotient() { SolvableIdeal I, J, K, H; a = fac.random(kl, ll - 2, el, q); b = fac.random(kl, ll, el, q / 2); c = fac.random(kl, ll, el - 1, q); d = c; //fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); } L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); L = new ArrayList>(); assertTrue("not isZERO( b )", !a.isZERO()); L.add(b); L = bb.leftGB(L); J = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J.getList().get(0)); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com assertTrue("equals(H,I)", H.equals(I)); // GBs only H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com assertTrue("equals(H,I)", H.equals(I)); // GBs only L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.leftGB(L); J = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( J )", !J.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( J )", J.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com assertTrue("equals(H,I)", H.equals(I)); // GBs only L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( J )", !J.isONE() ); assertTrue("isGB( I )", I.isGB()); K = I.product(J); assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); H = K.quotient(J); assertTrue("not isZERO( H )", !H.isZERO()); assertTrue("isGB( H )", H.isGB()); //non-com assertTrue("equals(H,I)", H.equals(I)); // GBs only } /** * Test SolvableIdeal infinite quotient. */ public void testSolvableIdealInfiniteQuotient() { SolvableIdeal I, J, K; a = fac.random(kl, ll - 2, el, q); b = fac.random(kl, ll - 1, el - 1, q); c = fac.random(kl, ll / 2, el - 1, q / 2); //a = fac.parse(" -1/2 w"); //b = fac.parse(" y - 2/3"); //c = fac.parse(" -2 w * y + 4/3 w + 2"); //c = fac.parse(" -2 y^2 + 8/3 y - 8/9"); d = c; //fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); e = d; } L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); int x = I.infiniteQuotientExponent(a, J); //System.out.println("I, a, J, x: " + I.toScript() + ", " + a + ", " + J.toScript() + ", " + x); assertTrue("x >= 0: " + x, x >= 0); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); assertTrue("contains(J,I): " + J.toScript() + ", " + I.toScript(), J.contains(I)); // GBs only assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotient(a); assertTrue("isGB( J )", J.isGB()); assertTrue("contains(J,I)", J.contains(I)); // GBs only G = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); G.add(a); G = bb.leftGB(G); K = new SolvableIdeal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotient(K); assertTrue("contains(J,I)", J.contains(I)); // GBs only assertTrue("not isZERO( e ): + e", !e.isZERO()); G.add(e); G = bb.leftGB(G); K = new SolvableIdeal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotient(K); assertTrue("contains(J,I)", J.contains(I)); // GBs only } /** * Test (commutative) SolvableIdeal infinite quotient with Rabinowich trick. */ public void testSolvableIdealInfiniteQuotientRab() { fac = new GenSolvablePolynomialRing(fac.coFac, rl, fac.tord, fac.getVars()); SolvableIdeal I, J, K, JJ; a = fac.random(kl - 1, ll - 1, el - 1, q / 2); b = fac.random(kl - 1, ll - 1, el, q / 2); c = fac.random(kl - 1, ll - 1, el, q / 2); d = fac.random(kl - 1, ll - 1, el, q / 2); e = a; //fac.random(kl, ll-1, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } if (d.isZERO()) { d = L.get(k++); } L = new ArrayList>(); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); JJ = I.infiniteQuotient(a); assertTrue("equals(J,JJ)", J.equals(JJ)); // GBs only assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); assertTrue("contains(J,I): " + J + ", " + I, J.contains(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("contains(J,JJ): " + J + ", " + JJ, J.contains(JJ)); // GBs only assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I.infiniteQuotientRab(a); assertTrue("isGB( J )", J.isGB()); assertTrue("contains(J,I)", J.contains(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("contains(J,JJ)", J.contains(JJ)); // GBs only G = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); G.add(a); G = bb.leftGB(G); K = new SolvableIdeal(fac, G, true); assertTrue("not isZERO( K )", !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotientRab(K); assertTrue("contains(J,I)", J.contains(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("contains(J,JJ)", J.contains(JJ)); // GBs only assertTrue("not isZERO( e ): " + e, !e.isZERO()); G.add(e); G = bb.leftGB(G); K = new SolvableIdeal(fac, G, true); assertTrue("not isZERO( K ): " + K, !K.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( K )", K.isGB()); J = I.infiniteQuotientRab(K); assertTrue("contains(J,I)", J.contains(I)); // GBs only JJ = I.infiniteQuotient(a); assertTrue("contains(J,JJ)", J.contains(JJ)); // GBs only } /** * Test (commutative) SolvableIdeal radical membership. */ public void testSolvableIdealRadicalMember() { fac = new GenSolvablePolynomialRing(fac.coFac, rl, fac.tord, fac.getVars()); SolvableIdeal I; a = fac.random(kl - 1, ll, el - 1, q); b = fac.random(kl - 1, ll, el, q); c = fac.random(kl - 1, ll - 1, el, q / 2); //d = fac.random(kl - 1, ll - 1, el, q / 2); //e = a; //fac.random(kl, ll-1, el, q ); L = PolynomialList.castToSolvableList(fac.generators()); //System.out.println("generators: " + L); int k = L.size() - rl; if (a.isZERO()) { a = L.get(k++); } if (b.isZERO()) { b = L.get(k++); } if (c.isZERO()) { c = L.get(k++); } L = new ArrayList>(); L.add(b); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("I = " + I); if (!I.isONE() && !a.equals(b)) { assertFalse("a in radical(b): " + a + ", " + b, I.isRadicalMember(a)); assertTrue("b in radical(b): " + a + ", " + b, I.isRadicalMember(b)); } L = new ArrayList>(); L.add(b.multiply(b)); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); if (!I.isONE() && !a.equals(b)) { assertFalse("a in radical(b*b)", I.isRadicalMember(a)); assertTrue("b in radical(b*b)", I.isRadicalMember(b)); } //System.out.println("c = " + c); L.add(c); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); if (!I.isONE() && !a.equals(b)) { assertFalse("a in radical(b*b,c)", I.isRadicalMember(a)); assertTrue("b in radical(b*b,c)", I.isRadicalMember(b)); } } /** * Test SolvableIdeal common zeros. */ @SuppressWarnings("unchecked") public void testSolvableIdealCommonZeros() { SolvableIdeal I; L = new ArrayList>(); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); a = fac.getZERO(); L.add(a); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); b = fac.getONE(); L.add(b); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), -1); L = new ArrayList>(); a = fac.random(kl, ll, el, q); if (!a.isZERO() && !a.isConstant()) { L.add(a); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } L = (List>) fac.univariateList(); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 0); L.remove(0); I = new SolvableIdeal(fac, L, true); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } /** * Test SolvableIdeal dimension. */ @SuppressWarnings("unchecked") public void testSolvableIdealDimension() { SolvableIdeal I; L = new ArrayList>(); Dimension dim; I = new SolvableIdeal(fac, L, true); assertEquals("dimension( I )", rl, I.dimension().d); a = fac.getZERO(); L.add(a); I = new SolvableIdeal(fac, L, true); assertEquals("dimension( I )", rl, I.dimension().d); b = fac.getONE(); L.add(b); I = new SolvableIdeal(fac, L, true); assertEquals("dimension( I )", -1, I.dimension().d); L = new ArrayList>(); a = fac.random(kl, ll, el, q); if (!a.isZERO() && !a.isConstant()) { L.add(a); I = new SolvableIdeal(fac, L, true); //System.out.println("a = " + a); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertTrue("dimension( I )", dim.d >= 1); } L = (List>) fac.univariateList(); I = new SolvableIdeal(fac, L, true); dim = I.dimension(); assertEquals("dimension( I )", 0, dim.d); while (L.size() > 0) { L.remove(0); I = new SolvableIdeal(fac, L, true); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertEquals("dimension( I )", rl - L.size(), dim.d); } L = (List>) fac.univariateList(); I = new SolvableIdeal(fac, L, true); I = I.product(I); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertTrue("dimension( I )", 0 >= dim.d); L = I.getList(); while (L.size() > 0) { L.remove(0); I = new SolvableIdeal(fac, L, true); //System.out.println("I = " + I); dim = I.dimension(); //System.out.println("dim(I) = " + dim); assertTrue("dimension( I )", dim.d > 0); } } /** * Test elimination SolvableIdeals. */ public void testElimSolvableIdeal() { BigRational coeff = new BigRational(17, 1); String[] vars = new String[] { "w", "x", "y", "z" }; fac = new GenSolvablePolynomialRing(coeff, rl, to, vars); RelationGenerator wli = new WeylRelationsIterated(); wli.generate(fac); //String[] vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); SolvableIdeal I, J, K; L = new ArrayList>(); //non-com a = fac.univariate(0, 3L); //fac.random(kl, ll, el, q ); b = fac.univariate(1, 2L); //fac.random(kl, ll, el, q ); c = fac.univariate(0, 1L); //fac.random(kl, ll, el, q ); L.add(a); //L.add(b); L.add(c); I = new SolvableIdeal(fac, L); I.doGB(); //System.out.println("I = " + I.toScript()); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE()); assertTrue("isGB( I )", I.isGB()); List sv = new ArrayList(vars.length); for (int i = 0; i < vars.length; i++) { sv.add(vars[i]); } //System.out.println("sv = " + sv); for (int i = 2; i <= vars.length; i = i + 2) { KsubSet ps = new KsubSet(sv, i); //System.out.println("========================== ps : " + i); for (List ev : ps) { int si = Collections.indexOfSubList(sv, ev); if (si < 0 || si % 2 != 0) { // substring and iterated Weyl algebra continue; } //System.out.println("ev = " + ev); List svr = new ArrayList(vars.length); K = null; if (si != 0) { // and substring on even index svr.addAll(ev); for (String e : sv) { if (svr.contains(e)) { continue; } svr.add(e); } //System.out.println("svr = " + svr); String[] rvars = new String[svr.size()]; for (int j = 0; j < svr.size(); j++) { rvars[j] = svr.get(j); } List P = new ArrayList(sv.size()); for (int j = 0; j < rvars.length; j++) { int k = sv.indexOf(rvars[j]); P.add(k); } //System.out.println("P = " + P); GenSolvablePolynomialRing rfac; rfac = (GenSolvablePolynomialRing) fac.permutation(P); //System.out.println("rfac = " + rfac.toScript()); List> id = TermOrderOptimization . permutation(P, rfac, I.list.castToSolvableList()); K = new SolvableIdeal(rfac, id); //System.out.println("K = " + K.toScript()); //continue; } String[] evars = new String[ev.size()]; for (int j = 0; j < ev.size(); j++) { evars[j] = ev.get(j); } GenSolvablePolynomialRing efac; efac = new GenSolvablePolynomialRing(fac.coFac, evars.length, fac.tord, evars); //RelationGenerator wl = new WeylRelations(); RelationGenerator wl = new WeylRelationsIterated(); wl.generate(efac); //System.out.println("efac = " + efac.toScript()); if (K == null) { J = I.eliminate(efac); } else { J = K.eliminate(efac); } //System.out.println("J = " + J.toScript()); assertTrue("isGB( J ): " + J.toScript(), J.isGB()); assertTrue("size( J ) <= |ev|", J.getList().size() <= ev.size()); } } } /** * Test univariate polynomials in ideal. */ public void testUnivPoly() { String[] vars; BigRational coeff = new BigRational(17, 1); to = new TermOrder(TermOrder.INVLEX); vars = new String[] { "w", "x", "y", "z" }; fac = new GenSolvablePolynomialRing(coeff, rl, to, vars); vars = fac.getVars(); //System.out.println("vars = " + Arrays.toString(vars)); //System.out.println("fac = " + fac); assertTrue("vars.length == 4 ", vars.length == 4); SolvableIdeal I; L = new ArrayList>(); a = fac.parse("( x^3 + 34/55 x^2 + 1/9 x + 99 )"); b = fac.parse("( y^4 - x )"); c = fac.parse("( z^3 - x y )"); d = fac.parse("( w^2 + 3 )"); if (a.isZERO() || b.isZERO() || c.isZERO()) { return; } L.add(a); L.add(b); L.add(c); L.add(d); I = new SolvableIdeal(fac, L); //I.doGB(); assertTrue("not isZERO( I )", !I.isZERO()); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I); for (int i = 0; i < rl; i++) { // rl GenSolvablePolynomial u = I.constructUnivariate(rl - 1 - i); //System.out.println("u = " + u); GenSolvablePolynomial U = fac.parse(u.toString()); //System.out.println("U = " + U + "\n"); assertTrue("I.contains(U) ", I.contains(U)); } List> Us = I.constructUnivariate(); for (GenSolvablePolynomial u : Us) { //System.out.println("u = " + u); GenSolvablePolynomial U = fac.parse(u.toString()); //System.out.println("U = " + U + "\n"); assertTrue("I.contains(U) ", I.contains(U)); } } /** * Test SolvableIdeal annihilator. */ public void testAnnihilator() { SolvableIdeal I, J, K; do { a = fac.random(kl, ll, el, q); } while (a.isZERO() || a.isConstant()); b = fac.univariate(1); c = fac.univariate(rl - 1); //b = fac.random(kl - 1, ll, el, q); //c = fac.random(kl - 1, ll - 1, el, q / 2); L = new ArrayList>(); L.add(a); L.add(b); //L.add(c); //System.out.println("L = " + L); L = bb.leftGB(L); I = new SolvableIdeal(fac, L, true); assertTrue("isGB( I )", I.isGB()); //System.out.println("I = " + I + "\n"); J = I.annihilator(c); //System.out.println("J = " + J + "\n"); J.doGB(); //System.out.println("c = " + c); //System.out.println("J = " + J + "\n"); assertTrue("isAnnihilator(c,J)", I.isAnnihilator(c, J)); d = fac.univariate(rl - 2); //d = fac.random(kl - 1, ll, el, q); M = new ArrayList>(); M.add(c); M.add(d); //System.out.println("M = " + M); K = new SolvableIdeal(fac, M); //System.out.println("K = " + K + "\n"); J = I.annihilator(K); //System.out.println("J = " + J + "\n"); J.doGB(); //System.out.println("K = " + K); //System.out.println("J = " + J + "\n"); assertTrue("isAnnihilator(M,J)", I.isAnnihilator(K, J)); } } java-algebra-system-2.7.200/trc/edu/jas/application/SolvableLocalResidueTest.java000066400000000000000000000367651445075545500277520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.fd.FDUtil; import edu.jas.fd.GreatestCommonDivisorAbstract; import edu.jas.fd.GreatestCommonDivisorSimple; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * SolvableLocalResidue over BigRational GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class SolvableLocalResidueTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SolvableLocalResidueTest object. * @param name String. */ public SolvableLocalResidueTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableLocalResidueTest.class); return suite; } SolvableLocalResidueRing efac; GenSolvablePolynomialRing mfac; SolvableIdeal id; SolvableLocalResidue a, b, c, d, e; SolvableLocalResidue az, bz, cz, dz, ez; int rl = 4; int kl = 2; int ll = 3; //6; int el = 2; float q = 0.15f; int il = (rl == 1 ? 1 : 2); @Override protected void setUp() { a = b = c = d = e = null; TermOrder to = TermOrderByName.INVLEX; String[] vars = new String[] { "w", "x", "y", "z" }; mfac = new GenSolvablePolynomialRing(new BigRational(1), rl, to, vars); RelationGenerator wl = new WeylRelations(); wl.generate(mfac); if (!mfac.isAssociative()) { System.out.println("ring not associative: " + mfac); } //id = genRandomIdeal(); //id = genIdealA(); id = genPrimeIdealA(); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; efac = new SolvableLocalResidueRing(id); //System.out.println("efac = " + efac.toScript()); } protected SolvableIdeal genRandomIdeal() { List> F; do { F = new ArrayList>(il); for (int i = 0; i < il; i++) { GenSolvablePolynomial mo = mfac.random(kl, ll, el + 1, q); while (mo.isConstant()) { mo = mfac.random(kl, ll, el + 1, q); } F.add(mo); } SolvableIdeal id = new SolvableIdeal(mfac, F); id.doGB(); } while (id.isONE()); return id; } protected SolvableIdeal genIdealA() { GenSolvablePolynomial p; List> F; F = new ArrayList>(il); p = mfac.parse("y^2 - 42/5"); F.add(p); //p = mfac.parse("z^2"); p = mfac.parse("x^2"); F.add(p); //p = mfac.parse("x^2 - w^2 "); //F.add( p ); SolvableIdeal id = new SolvableIdeal(mfac, F); id.doGB(); return id; } protected SolvableIdeal genIdealB() { GenSolvablePolynomial p; List> rel; rel = new ArrayList>(il); List> F; F = new ArrayList>(il); String[] vars = new String[] { "x", "y", "z", "t" }; mfac = new GenSolvablePolynomialRing(new BigRational(1), TermOrderByName.INVLEX, vars); // add relations //z, y, y * z + x, p = mfac.parse("z"); rel.add(p); p = mfac.parse("y"); rel.add(p); p = mfac.parse("y * z + x"); rel.add(p); //t, y, y * t + y, p = mfac.parse("t"); rel.add(p); p = mfac.parse("y"); rel.add(p); p = mfac.parse("y * t + y"); rel.add(p); //t, z, z * t - z p = mfac.parse("t"); rel.add(p); p = mfac.parse("z"); rel.add(p); p = mfac.parse("z * t - z"); rel.add(p); mfac.addSolvRelations(rel); //System.out.println("mfac = " + mfac.toScript()); // construct ideal from polynomial t^2 + z^2 + y^2 + x^2 + 1 p = mfac.parse("t^2 + z^2 + y^2 + x^2 + 1"); F.add(p); SolvableIdeal id; id = new SolvableIdeal(mfac, F, SolvableIdeal.Side.twosided); id.doGB(); //System.out.println("ideal = " + id.toScript()); return id; } protected SolvableIdeal genPrimeIdealA() { // well, almost GenSolvablePolynomial p; List> F; F = new ArrayList>(il); p = mfac.parse("y^2 + 5"); F.add(p); p = mfac.parse("x^2 + 3"); F.add(p); SolvableIdeal id = new SolvableIdeal(mfac, F); id.doGB(); return id; } @Override protected void tearDown() { a = b = c = d = e = null; //efac.terminate(); efac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { c = efac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = efac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); for (SolvableLocalResidue g : efac.generators()) { //System.out.println("g = " + g); assertFalse("not isZERO( g )", g.isZERO()); } //wrong, solved: assertTrue("isAssociative: ", efac.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 4; i++) { //a = efac.random(ll+i); a = efac.random(kl + i, ll + 1, el, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); assertEquals("a == a: ", a, a); } } /** * Test addition. */ public void testAddition() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //a = efac.parse("{ 1 | w * x + 25/28 }"); //b = efac.parse("{ x - 35/18 | x + 2 w - 6 }"); //!a = efac.parse("{ x - 1/7 | y * z + 7/10 }"); //!b = efac.parse("{ 1 | w + 3 }"); //a = efac.parse("{ 1 | y * z + 7/10 }"); //b = efac.parse("{ x - 1/7 | w + 3 }"); //a = efac.parse("{ ( -21/10 ) z - 5/4 x | x * z - 1/2 x + 1/2 }"); //b = efac.parse("{ 1 | z^2 - 63/5 }"); //a = efac.parse("{ 1 | z - 92/105 }"); //b = efac.parse("{ 1 | x }"); // when not prime //a = efac.parse("{ x - 3 | z + 5 }"); //b = efac.parse("{ w + 2 | z - x * y }"); //b = new SolvableLocalResidue(efac,efac.ideal.getList().get(0)); //b = a.negate(); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0-(-a)", c, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = a.sum(b); //System.out.println("c = " + c); d = c.subtract(b); //System.out.println("d = " + d); //System.out.println("a = " + a); assertEquals("(a+b)-b = a: b = " + b, a, d); c = efac.random(kl, ll, el, q); //c = new SolvableLocalResidue(efac, mfac.univariate(1, 2)); //c = efac.parse("{ 42/5 }"); //System.out.println("c = " + c); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e)); assertEquals("c+(a+b) = (c+a)+b: a = " + a + ", b = " + b + ", c = " + c, d, e); } /** * Test multiplication. */ public void testMultiplication() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(efac.getONE()); d = efac.getONE().multiply(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1 = 1*a", c, a); assertEquals("a*1 = 1*a", c, d); c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); //non-com assertTrue("a*b != b*a", !c.equals(d) || c.equals(d) ); //c = efac.random(kl,ll,el,q); c = new SolvableLocalResidue(efac, mfac.univariate(1, 2)); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); //System.out.println("d = " + d); e = (a.multiply(b)).multiply(c); //System.out.println("e = " + e); assertEquals("a(bc) = (ab)c", d, e); } /** * Test inverse. */ public void testInverse() { a = efac.random(kl, ll + 1, el + 1, q * 1.15f); //System.out.println("a = " + a); b = new SolvableLocalResidue(efac, mfac.getONE(), mfac.univariate(1, 2)); //System.out.println("b = " + b); a = a.multiply(b); //System.out.println("a = " + a); if (a.isUnit()) { // true if != 0 c = a.inverse(); //System.out.println("c = " + c); d = c.multiply(a); //d = a.multiply(c); //System.out.println("d = " + d); assertTrue("1/a * a = 1", d.isONE()); d = c.inverse(); //System.out.println("d = " + d); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("a-d = " + a.subtract(d)); assertEquals("1/(1/a) = a", a, d); } } /** * Test roots (eval mod ideal). */ public void testRoot() { c = efac.parse("y"); //System.out.println("c = " + c); d = efac.parse("5"); //System.out.println("d = " + d); e = c.multiply(c).sum(d); //System.out.println("e = " + e); assertTrue("e == 0 mod ideal", e.isZERO()); for (GenSolvablePolynomial p : efac.ideal.getList()) { String s = p.toString(); //System.out.println("s = " + s); e = efac.parse(s); // eval mod ideal //System.out.println("e = " + e); assertTrue("e == 0 mod ideal", e.isZERO()); } } /** * Test parse. */ public void testParse() { a = efac.random(kl, ll, el, q); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(); //System.out.println("p = " + p); b = efac.parse(p); //System.out.println("b = " + b); assertEquals("parse(a.toSting()) = a", a, b); } /** * Test example ideal for ICMS-2016. */ public void testExamIdeal() { id = genIdealB(); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; efac = new SolvableLocalResidueRing(id); //System.out.println("efac = " + efac.toScript()); SolvableLocalResidue a, b, c, d, e, f; GenSolvablePolynomial p, q, r; p = mfac.parse("t + x + y + 1"); a = new SolvableLocalResidue(efac, p); //System.out.println("a = " + a.toScript()); p = mfac.parse("z**2+x+1"); b = new SolvableLocalResidue(efac, p); //System.out.println("b = " + b.toScript()); c = a.inverse(); //System.out.println("c = " + c.toScript()); d = b.inverse(); //System.out.println("d = " + d.toScript()); d = c.multiply(a); //System.out.println("d = " + d.toScript()); e = d.inverse(); //System.out.println("e = " + e.toScript()); e = b.multiply(c); //System.out.println("e = " + e.toScript()); f = c.multiply(b); //System.out.println("f = " + f.toScript()); d = a.multiply(f); //System.out.println("d = " + d.toScript()); d = e.multiply(a); // b * 1/a * a == b //System.out.println("d = " + d.toScript()); //System.out.println("b == d: " + b.equals(d)); assertEquals("b.equals(d): ", b, d); //System.out.println("#b: " + (b.num.length()+b.den.length())); //System.out.println("#d: " + (d.num.length()+d.den.length())); GreatestCommonDivisorAbstract engine = new GreatestCommonDivisorSimple( new BigRational()); p = engine.leftGcd(d.num, d.den); //System.out.println("p = " + p.toScript()); GenSolvablePolynomial[] qr; // right division qr = FDUtil. rightBasePseudoQuotientRemainder(d.num, p); //System.out.println("q_rn = " + qr[0].toScript()); //System.out.println("r_rn = " + qr[1].toScript()); r = qr[0]; assertTrue("rem == 0: ", qr[1].isZERO()); qr = FDUtil. rightBasePseudoQuotientRemainder(d.den, p); //System.out.println("q_rn = " + qr[0].toScript()); //System.out.println("r_rn = " + qr[1].toScript()); q = qr[0]; assertTrue("rem == 0: ", qr[1].isZERO()); e = new SolvableLocalResidue(efac, r, q); //System.out.println("b = " + b.toScript()); //System.out.println("e = " + e.toScript()); //System.out.println("b == e: " + b.equals(e)); assertEquals("b == e: ", b, e); //qr = FDUtil. leftGcdCofactors(id.getRing(), d.num, d.den); //System.out.println("left qr = " + Arrays.toString(qr)); //qr = FDUtil. rightGcdCofactors(id.getRing(), d.num, d.den); //System.out.println("right qr = " + Arrays.toString(qr)); } } java-algebra-system-2.7.200/trc/edu/jas/application/SolvableLocalTest.java000066400000000000000000000214341445075545500264140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; /** * SolvableLocal over BigRational GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class SolvableLocalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableLocalTest object. * @param name String. */ public SolvableLocalTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableLocalTest.class); return suite; } SolvableLocalRing efac; GenSolvablePolynomialRing mfac; SolvableIdeal id; SolvableLocal a, b, c, d, e; SolvableLocal az, bz, cz, dz, ez; int rl = 4; int kl = 2; int ll = 3; //6; int el = 2; float q = 0.15f; int il = (rl == 1 ? 1 : 2); @Override protected void setUp() { a = b = c = d = e = null; TermOrder to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "w", "x", "y", "z" }; mfac = new GenSolvablePolynomialRing(new BigRational(1), rl, to, vars); RelationGenerator wl = new WeylRelations(); wl.generate(mfac); if (!mfac.isAssociative()) { System.out.println("ring not associative: " + mfac); } //id = genRandomIdeal(); id = genIdealA(); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; efac = new SolvableLocalRing(id); //System.out.println("efac = " + efac); } protected SolvableIdeal genRandomIdeal() { List> F; do { F = new ArrayList>(il); for (int i = 0; i < il; i++) { GenSolvablePolynomial mo = mfac.random(kl, ll, el + 1, q); while (mo.isConstant()) { mo = mfac.random(kl, ll, el + 1, q); } F.add(mo); } SolvableIdeal id = new SolvableIdeal(mfac, F); id.doGB(); } while (id.isONE()); return id; } protected SolvableIdeal genIdealA() { GenSolvablePolynomial p; List> F; F = new ArrayList>(il); p = mfac.parse("y^2 - 42/5"); F.add(p); //p = mfac.parse("z^2"); p = mfac.parse("x^2"); F.add(p); //p = mfac.parse("x^2 - w^2 "); //F.add( p ); SolvableIdeal id = new SolvableIdeal(mfac, F); id.doGB(); return id; } @Override protected void tearDown() { a = b = c = d = e = null; //efac.terminate(); efac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { c = efac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = efac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); for (SolvableLocal g : efac.generators()) { //System.out.println("g = " + g); assertFalse("not isZERO( g )", g.isZERO()); } // solved: not all products are defined assertTrue("isAssociative: ", efac.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { //a = efac.random(ll+i); a = efac.random(kl + i, ll + 2, el, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); assertEquals("a == a: ", a, a); } } /** * Test addition. */ public void testAddition() { a = efac.random(kl, ll, el+1, q); b = efac.random(kl, ll, el+1, q); //a = efac.parse("{ 1 | w * x + 25/28 }"); //b = efac.parse("{ x - 35/18 | x + 2 w - 6 }"); //!a = efac.parse("{ x - 1/7 | y * z + 7/10 }"); //!b = efac.parse("{ 1 | w + 3 }"); //a = efac.parse("{ 1 | y * z + 7/10 }"); //b = efac.parse("{ x - 1/7 | w + 3 }"); //a = efac.parse("{ 91/15 | y - 3/14 }"); //b = efac.parse("{ 11/12 | w * z^2 + 4/3 }"); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0-(-a)", c, d); //c = a.sum(b); //d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); //assertEquals("a+b = b+a", c, d); c = a.sum(b); //System.out.println("c = " + c); d = c.subtract(b); //d = c.sum(b.negate()); //System.out.println("d = " + d); //System.out.println("a = " + a); assertEquals("(a+b)-b == a: " + a + ", " + b, a, d); e = d.subtract(a); //System.out.println("d-a = " + e); assertTrue("((a+b)-b)-a == 0", e.isZERO()); //c = efac.random(kl,ll,el,q); c = new SolvableLocal(efac, mfac.univariate(1, 2)); //System.out.println("c = " + c); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("c+(a+b) = (c+a)+b", d, e); } /** * Test multiplication. */ public void testMultiplication() { a = efac.random(kl, ll, el + 0, q); b = efac.random(kl, ll, el + 0, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(efac.getONE()); d = efac.getONE().multiply(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1 = 1*a", c, a); assertEquals("a*1 = 1*a", c, d); c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); //non-com assertFalse("a*b = b*a", c.equals(d) ); //e = d.subtract(c); //non-com assertFalse("not isZERO( a*b-b*a ) " + e, e.isZERO() ); //c = efac.random(kl,ll,el,q); c = new SolvableLocal(efac, mfac.univariate(1, 2)); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); //System.out.println("d = " + d); e = (a.multiply(b)).multiply(c); //System.out.println("e = " + e); assertEquals("a(bc) = (ab)c", d, e); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } } /** * Test parse. */ public void testParse() { a = efac.random(kl, ll, el, q * 2); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(); //System.out.println("p = " + p); b = efac.parse(p); //System.out.println("b = " + b); //c = a.subtract(b); //System.out.println("c = " + c); assertEquals("parse(a.toSting()) = a", a, b); } } java-algebra-system-2.7.200/trc/edu/jas/application/SolvableResidueTest.java000066400000000000000000000163661445075545500267720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.WeylRelations; import edu.jas.poly.TermOrder; import edu.jas.structure.NotInvertibleException; /** * SolvableResidue tests with JUnit. * @author Heinz Kredel */ public class SolvableResidueTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a SolvableResidueTest object. * @param name String. */ public SolvableResidueTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(SolvableResidueTest.class); return suite; } SolvableIdeal id; SolvableResidueRing fac; GenSolvablePolynomialRing mfac; List> F; SolvableResidue< BigRational > a, b, c, d, e; int rl = 4; int kl = 2; int ll = 3; int el = 2; float q = 0.2f; int il = ( rl == 1 ? 1 : 2 ); protected void setUp() { a = b = c = d = e = null; TermOrder to = new TermOrder( TermOrder.INVLEX ); String[] vars = new String[] { "w", "x", "y", "z" }; mfac = new GenSolvablePolynomialRing( new BigRational(1), rl, to, vars ); RelationGenerator wl = new WeylRelations(); wl.generate(mfac); if (!mfac.isAssociative() ) { System.out.println("ring not associative: " + mfac); } do { F = new ArrayList>( il ); for ( int i = 0; i < il; i++ ) { GenSolvablePolynomial mo = mfac.random(kl,ll,el,q); while ( mo.isConstant() ) { mo = mfac.random(kl,ll,el,q); } F.add( mo ); } id = new SolvableIdeal(mfac,F); id.doGB(); } while (id.isONE()); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; fac = new SolvableResidueRing( id ); //System.out.println("fac = " + fac); F = null; } protected void tearDown() { a = b = c = d = e = null; fac = null; id = null; mfac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1 ", c.val.length() == 1 || id.isONE()); assertTrue("isZERO( c )", !c.isZERO() || id.isONE()); assertTrue("isONE( c )", c.isONE() || id.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.val.length() == 0); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); for (SolvableResidue g : fac.generators() ) { //System.out.println("g = " + g); assertFalse("not isZERO( g )", g.isZERO() ); } } /** * Test random polynomial. */ public void testRandom() { for (int i = 1; i < 7; i++) { //a = fac.random(ll+i); a = fac.random(kl*(i+1), ll+2*i, el+i, q ); //System.out.println("a = " + a); if ( a.isZERO() || a.isONE() ) { continue; } assertTrue("length( a"+i+" ) <> 0", a.val.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl,ll,el,q); b = fac.random(kl,ll,el,q); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a",c,d); c = fac.random(kl,ll,el,q); d = c.sum( a.sum(b) ); e = c.sum( a ).sum(b); assertEquals("c+(a+b) = (c+a)+b",d,e); c = a.sum( fac.getZERO() ); d = a.subtract( fac.getZERO() ); assertEquals("a+0 = a-0",c,d); c = fac.getZERO().sum( a ); d = fac.getZERO().subtract( a.negate() ); assertEquals("0+a = 0+(-a)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { List> g = fac.generators(); //System.out.println("g = " + g); //a = fac.random(kl,ll,el,q); a = g.get(1); if ( a.isZERO() ) { a = fac.getONE(); //return; } assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(kl,ll,el,q); //b = g.get(g.size()-1); if ( b.isZERO() ) { b = fac.getONE(); //return; } assertTrue("not isZERO( b )", !b.isZERO() ); c = a.multiply( fac.getONE() ); d = fac.getONE().multiply( a ); assertEquals("a*1 = 1*a",c,d); assertEquals("a*1 = 1*a",c,a); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //e = d.subtract(c); //non-com: assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); //non-com: assertEquals("a*b = b*a",c,d); c = fac.random(kl,ll+1,el,q); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e) ); assertEquals("a(bc) = (ab)c",d,e); //assertTrue("a(bc) = (ab)c", d.equals(e) ); if ( !a.isZERO() ) { // !a.isZERO() isUnit() try { c = a.inverse(); //System.out.println("a = " + a); //System.out.println("c = " + c); d = c.multiply(a); //System.out.println("d = " + d); assertTrue("a*1/a = 1: " + fac, d.isONE()); // || true } catch (NotInvertibleException e) { // can happen } } // d = c.remainder(a); // //System.out.println("c = " + c); // System.out.println("d = " + d); // if ( d.isZERO() ) { // d = c.divide(a); // System.out.println("c = " + c); // System.out.println("d = " + d); // e = a.multiply(d); // System.out.println("e = " + e); // assertEquals("((b*a)/a)*a = b*a",e,c); // } } } java-algebra-system-2.7.200/trc/edu/jas/application/WordIdealTest.java000066400000000000000000000316451445075545500255510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.WordGroebnerBaseSeq; // import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * WordIdeal tests with JUnit. * @author Heinz Kredel */ public class WordIdealTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordIdealTest object. * @param name String. */ public WordIdealTest(String name) { super(name); //ComputerThreads.terminate(); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordIdealTest.class); return suite; } TermOrder to; GenWordPolynomialRing fac; List> L, M; PolynomialList F; List> G; WordGroebnerBaseSeq bb; GenWordPolynomial a, b, c, d, e; int kl = 3; //10 int ll = 5; //7 int el = 2; @Override protected void setUp() { BigRational coeff = new BigRational(17, 1); to = new TermOrder( /*TermOrder.INVLEX*/); String[] vars = new String[] { "x", "y", "z" }; //WordFactory wf = new WordFactory(vars); fac = new GenWordPolynomialRing(coeff, vars); bb = new WordGroebnerBaseSeq(); //bb = GBFactory.getImplementation(coeff); //bb.timestatus.setNotActive(); // allow infintite computation a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test Ideal sum. */ public void testIdealSum() { WordIdeal I, J, K; L = new ArrayList>(); a = fac.random(kl, ll, el); b = fac.random(kl, ll, el); c = fac.random(kl, ll, el); d = fac.random(kl, ll, el); e = d; //fac.random(kl, ll, el); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); L.add(a); //System.out.println("L = " + L.size() ); I = new WordIdeal(fac, L, true, bb); assertTrue("isGB( I )", I.isGB()); I = new WordIdeal(fac, L, false, bb); assertTrue("isGB( I )", I.isGB()); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); I = new WordIdeal(fac, L, true, bb); assertTrue("isGB( I )", I.isGB()); I = new WordIdeal(fac, L, false, bb); assertTrue("isGB( I )", I.isGB()); String s = I.toScript() + "\n" + I.toString(); //System.out.println("#s = " + s.length() + ": " + s); assertTrue("#s >= 46: " + s + ", #s = " + s.length(), s.length() >= 46); K = I.getZERO(); assertTrue("K == 0: " + K, K.isZERO()); K = I.getONE(); assertTrue("K == 1: " + K, K.isONE()); //assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); I = new WordIdeal(fac, L, false, bb); assertTrue("not isZERO( I )", !I.isZERO()); //assertTrue("not isONE( I )", !I.isONE() ); //assertTrue("not isGB( I )", !I.isGB() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); I = new WordIdeal(fac, L, true, bb); assertTrue("not isZERO( I )", !I.isZERO()); // assertTrue("not isONE( I )", !I.isONE() ); assertTrue("isGB( I )", I.isGB()); J = I; K = J.sum(I); //assertTrue("not isZERO( K )", !K.isZERO()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertEquals("compareTo( K, I )", K.compareTo(I), 0); K = J.sum(I.getList()); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertEquals("compareTo( K, I )", K.compareTo(I), 0); K = J.sum(I.getList().get(0)); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertEquals("compareTo( K, I )", K.compareTo(I), 0); L = new ArrayList>(); L.add(c); assertTrue("isGB( { c } )", bb.isGB(L)); J = new WordIdeal(fac, L, true, bb); K = J.sum(I); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); L.add(d); assertTrue("isGB( { d } )", bb.isGB(L)); J = new WordIdeal(fac, L, true, bb); I = K; K = J.sum(I); assertTrue("isGB( K )", K.isGB()); assertTrue("K contains(I)", K.contains(I)); assertTrue("K contains(J)", K.contains(J)); L = new ArrayList>(); L.add(e); assertTrue("isGB( { e } )", bb.isGB(L)); J = new WordIdeal(fac, L, true, bb); I = K; K = J.sum(I); assertTrue("isGB( K )", K.isGB()); assertTrue("equals( K, I )", K.equals(I)); assertTrue("K contains(J)", K.contains(I)); assertTrue("I contains(K)", I.contains(K)); assertEquals("compareTo( K, I )", K.compareTo(I), 0); L.clear(); e = fac.parse("x x"); L.add(e); I = new WordIdeal(fac, L, true, bb); I.doGB(); J = I.power(3); J = J.power(2); K = I.power(6); //System.out.println("I = " + I); //System.out.println("J = " + J); //System.out.println("K = " + K); assertEquals("equals( (I**3)**2, I**6 )", K, J); } /** * Test WordIdeal product. Sometimes non-terminating. */ public void testWordIdealProduct() { WordIdeal I, J, K, H, G; a = fac.random(kl, ll, el); b = fac.random(kl, ll, el); c = fac.random(kl, ll, el); d = c; //fac.random(kl, ll, el); e = d; //fac.random(kl, ll, el); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); L = new ArrayList>(); L.add(a); I = new WordIdeal(fac, L, false, bb); assertTrue("not isONE( I )", !I.isONE() || a.isConstant()); assertTrue("isGB( I )", I.isGB()); L = new ArrayList>(); L.add(b); J = new WordIdeal(fac, L, false, bb); assertTrue("not isONE( J )", !J.isONE() || a.isConstant() || b.isConstant()); assertTrue("isGB( J )", J.isGB()); K = I.product(J); //System.out.println("I = " + I); //System.out.println("J = " + J); //System.out.println("K = " + K); H = J.product(I); //System.out.println("H = " + H); G = K.sum(H); //System.out.println("G = " + G); assertTrue("isGB( K )", K.isGB()); assertTrue("isGB( H )", H.isGB()); assertTrue("isGB( G )", G.isGB()); //non-com assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(H)", J.contains(H)); K = I.product(J.getList().get(0)); //System.out.println("I = " + I); //System.out.println("J = " + J); //System.out.println("K = " + K); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); L = new ArrayList>(); L.add(a); //L.add(c); L = bb.GB(L); // may be infinite with c I = new WordIdeal(fac, L, true, bb); //System.out.println("I = " + I); assertTrue("isGB( I )", I.isGB()); //System.out.println("J = " + J); K = I.product(J); //System.out.println("K = " + K); assertTrue("isGB( K )", K.isGB()); assertTrue("I contains(K)", I.contains(K)); assertTrue("J contains(K)", J.contains(K)); M = I.normalform(K.getList()); H = new WordIdeal(fac, M, false, bb); //System.out.println("I = " + I); //System.out.println("K = " + K); //System.out.println("H = " + H); assertTrue("isGB( H )", H.isGB()); assertTrue("isZERO( H )", H.isZERO()); } /** * Test WordIdeal common zeros. */ public void testWordIdealCommonZeros() { WordIdeal I, J; L = new ArrayList>(); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); a = fac.getZERO(); L.add(a); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); b = fac.getONE(); L.add(b); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), -1); L = new ArrayList>(); a = fac.random(kl, ll, el); if (!a.isZERO() && !a.isConstant()) { L.add(a); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } L = (List>) fac.univariateList(); //System.out.println("L = " + L); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 0); J = I.product(I); //System.out.println("J = " + J); assertEquals("commonZeroTest( J )", J.commonZeroTest(), 0); L.remove(0); I = new WordIdeal(fac, L, true, bb); assertEquals("commonZeroTest( I )", I.commonZeroTest(), 1); } /** * Test WordIdeal contraction. */ public void testContraction() { BigRational coeff = new BigRational(17, 1); String[] vs = new String[] { "beta", "x", "y", "z" }; GenWordPolynomialRing fac2 = new GenWordPolynomialRing(coeff, vs); WordIdeal I, J, K; L = new ArrayList>(); a = fac2.getZERO(); L.add(a); //b = fac2.getONE(); //L.add(b); b = fac2.random(3).monic(); b = fac2.valueOf(b); L.add(b); c = fac.random(4).monic(); c = fac2.valueOf(c); L.add(c); I = new WordIdeal(fac2, L, false, bb); //System.out.println("I = " + I); I.doGB(); //System.out.println("I = " + I); // now intersect with word polynomial ring //System.out.println("fac = " + fac.toScript()); J = I.intersect(fac); //System.out.println("J = " + J); List> ex = new ArrayList>(); for (GenWordPolynomial p : J.getList()) { GenWordPolynomial pe = fac2.valueOf(p); ex.add(pe); } K = new WordIdeal(fac2, ex, false, bb); //System.out.println("K = " + K); assertTrue("intersect ", I.contains(K)); } /** * Test WordIdeal intersection. */ public void testIntersection() { WordIdeal I, J, K; // first ideal L = new ArrayList>(); b = fac.random(3).monic(); L.add(b); c = fac.random(4).monic(); L.add(c); I = new WordIdeal(fac, L, false, bb); //System.out.println("I = " + I); // second ideal L.clear(); a = fac.random(3).monic(); L.add(a); J = new WordIdeal(fac, L, false, bb); //System.out.println("J = " + J); // now intersect with word ideal K = I.intersect(J); //System.out.println("I cap J = K = " + K); assertTrue("intersect ", I.contains(K)); assertTrue("intersect ", J.contains(K)); // now intersect with list of word ideals List> Bl = new ArrayList>(); Bl.add(J); K = I.intersect(Bl); //System.out.println("I cap J = K = " + K); assertTrue("intersect ", I.contains(K)); assertTrue("intersect ", J.contains(K)); } } java-algebra-system-2.7.200/trc/edu/jas/application/WordResidueTest.java000066400000000000000000000226271445075545500261330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.application; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.structure.NotDivisibleException; import edu.jas.structure.NotInvertibleException; /** * WordResidue tests with JUnit. * @author Heinz Kredel */ public class WordResidueTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordResidueTest object. * @param name String. */ public WordResidueTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordResidueTest.class); return suite; } WordIdeal id; WordResidueRing fac; GenWordPolynomialRing mfac; List> F; WordResidue a, b, c, d, e, f; int rl = 4; int kl = 3; int ll = 4; int el = 2; int il = (rl == 1 ? 1 : 2); @Override protected void setUp() { a = b = c = d = e = null; String[] vars = new String[] { "w", "x", "y", "z" }; mfac = new GenWordPolynomialRing(new BigRational(1), vars); //System.out.println("mfac = " + mfac.toScript()); //GenWordPolynomial p1 = mfac.parse("w - x^2"); //GenWordPolynomial p1 = mfac.parse("x + 49/12"); //GenWordPolynomial p2 = mfac.parse("y - 5 * w - 65/28"); do { F = new ArrayList>(il); for (int i = 0; i < il; i++) { GenWordPolynomial mo = mfac.random(kl, ll, el); while (mo.isConstant()) { mo = mfac.random(kl, ll, el); } F.add(mo); } //F.add(p1); F.add(p2); id = new WordIdeal(mfac, F); id.doGB(); } while (id.isONE()); //System.out.println("id = " + id); assert !id.isONE() : "id = " + id; fac = new WordResidueRing(id); //System.out.println("fac = " + fac.toScript()); F = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; id = null; mfac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1 ", c.val.length() == 1 || id.isONE()); assertTrue("isZERO( c )", !c.isZERO() || id.isONE()); assertTrue("isONE( c )", c.isONE() || id.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.val.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); for (WordResidue g : fac.generators()) { //System.out.println("g = " + g); assertFalse("not isZERO( g )", g.isZERO()); } } /** * Test random polynomial. */ public void testRandom() { for (int i = 1; i < 7; i++) { //a = fac.random(ll+i); a = fac.random(kl * i / 2, ll + i, el + i / 2); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.val.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl, ll, el + 1); b = fac.random(kl, ll, el + 1); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(kl, ll, el); //System.out.println("c = " + c); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test multiplication. */ public void testMultiplication() { List> g = fac.generators(); //System.out.println("g = " + g); //a = fac.random(kl,ll,el,q); a = g.get(1); if (a.isZERO()) { a = fac.getONE(); //return; } assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl, ll, el); //b = g.get(g.size()-1); if (b.isZERO()) { b = fac.getONE(); //return; } assertTrue("not isZERO( b )", !b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); assertEquals("a*1 = 1*a", c, a); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //e = d.subtract(c); //non-com: assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); //non-com: assertEquals("a*b = b*a",c,d); c = fac.random(kl, ll + 1, el); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e) ); assertEquals("a(bc) = (ab)c", d, e); //assertTrue("a(bc) = (ab)c", d.equals(e) ); if (a.isUnit()) { // !a.isZERO() isUnit() try { c = a.inverse(); //System.out.println("a = " + a); //System.out.println("c = " + c); d = c.multiply(a); //System.out.println("d = " + d); assertTrue("a*1/a = 1: " + fac, d.isONE()); // || true } catch (NotInvertibleException e) { // can happen } catch (UnsupportedOperationException e) { } } } /** * Test division. */ public void testDivision() { List> g = fac.generators(); //System.out.println("g = " + g); //a = fac.random(kl,ll,el,q); a = g.get(1); if (a.isZERO()) { a = fac.getONE(); } assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl, ll, el + 2).monic(); if (b.isZERO() || b.isONE()) { b = g.get(g.size() - 1); //b = fac.getONE(); } assertTrue("not isZERO( b )", !b.isZERO()); //a = fac.parse("w"); //b = fac.parse("w w + 79/360 z + 13/28 w"); //System.out.println("a = " + a); //System.out.println("b = " + b); // left division c = a.multiply(b); //System.out.println("c = " + c); try { d = c.divide(b); //System.out.println("d = " + d); e = c.remainder(b); //System.out.println("e = " + e); f = d.multiply(b).sum(e); //System.out.println("f = " + f); assertEquals("c == f: ", c, f); } catch (NotDivisibleException ex) { // pass System.out.println("ex = " + ex); } // right division c = b.multiply(a); //System.out.println("c = " + c); try { d = c.rightDivide(b); //System.out.println("d = " + d); e = c.rightRemainder(b); //System.out.println("e = " + e); f = b.multiply(d).sum(e); //System.out.println("f = " + f); assertEquals("c == f: ", c, f); } catch (NotDivisibleException ex) { // pass System.out.println("ex = " + ex); } // two-sided division c = a.multiply(b.multiply(a)); //System.out.println("c = " + c); try { WordResidue[] dd = c.twosidedDivide(b); //System.out.println("dd = " + dd[0] + " // " + dd[1]); e = c.twosidedRemainder(b); //System.out.println("e = " + e); f = dd[0].multiply(b).multiply(dd[1]).sum(e); //System.out.println("f = " + f); //System.out.println("c-f = " + c.subtract(f)); assertEquals("c == f: ", c, f); } catch (NotDivisibleException ex) { // pass System.out.println("ex = " + ex); } } } java-algebra-system-2.7.200/trc/edu/jas/arith/000077500000000000000000000000001445075545500207675ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/arith/ArithTest.java000066400000000000000000001042061445075545500235440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.List; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Basic arithmetic tests with JUnit. * @author Heinz Kredel */ public class ArithTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ArithTest object. * @param name String. */ public ArithTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ArithTest.class); return suite; } @Override protected void setUp() { //a = b = c = d = e = null; } @Override protected void tearDown() { //a = b = c = d = e = null; } /** * Test static initialization and constants for BigInteger. */ public void testIntegerConstants() { BigInteger a, b, c, d; a = BigInteger.ZERO; b = BigInteger.ONE; c = b.subtract(b); assertTrue("0.isZERO()", a.isZERO()); assertTrue("1.isONE", b.isONE()); assertEquals("1-1 = 0", c, a); assertTrue("(1-1).isZERO()", c.isZERO()); d = b.multiply(b); assertTrue("1*1 = 1", d.isONE()); d = b.multiply(a); assertTrue("1*0 = 0", d.isZERO()); } //-------------------------------------------------------- /** * Test string constructor and toString for BigInteger. */ public void testIntegerConstructor() { BigInteger a, b, c, d; a = new BigInteger(1); b = new BigInteger(-1); c = new BigInteger(0); d = a.sum(b); assertTrue("'1'.isONE()", a.isONE()); assertTrue("1+(-1) = 0", d.isZERO()); d = a.negate(); assertEquals("-1 = -(1)", d, b); d = a.multiply(c); assertTrue("'0'.isZERO()", d.isZERO()); d = b.multiply(b); assertTrue("(-1)*(-1) = 1", d.isONE()); a = new BigInteger(3); b = new BigInteger("3"); assertEquals("3 = '3'", a, b); a = new BigInteger(-5); b = new BigInteger("-5"); assertEquals("-5 = '-5'", a, b); // 0 1 2 3 4 // 0123456789012345678901234567890123456789012345 String s = "1111111111111111111111111111111111111111111111"; a = new BigInteger(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); } //-------------------------------------------------------- /** * Test random and compares Integer. */ public void testIntegerRandom() { BigInteger a, b, c; a = BigInteger.ZERO.random(500); b = new BigInteger("" + a); c = b.subtract(a); assertTrue("a-'a' = 0", c.isZERO()); assertEquals("compareTo('a',a) = 0", 0, b.compareTo(a)); assertEquals("signum('a'-a) = 0", 0, c.signum()); } //-------------------------------------------------------- /** * Test addition for Integer. */ public void testIntegerAddition() { BigInteger a, b, c, d, e; // neutral element a = BigInteger.ZERO.random(500); d = a.sum(BigInteger.ZERO); assertEquals("a+0 = a", d, a); d = a.subtract(BigInteger.ZERO); assertEquals("a-0 = a", d, a); // inverse operations b = a.sum(a); c = b.subtract(a); assertEquals("(a+a)-a = a", c, a); b = a.subtract(a); c = b.sum(a); assertEquals("(a-a)+a = a", c, a); // comutativity b = BigInteger.ZERO.random(500); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); // negation c = a.subtract(b); d = a.sum(b.negate()); assertEquals("a-b = a+(-b)", c, d); // associativity c = BigInteger.ZERO.random(500); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); } //-------------------------------------------------------- /** * Test multiplication for Integer. */ public void testIntegerMultiplication() { BigInteger a, b, c, d, e; // neutral element a = BigInteger.ZERO.random(500); d = a.multiply(BigInteger.ONE); assertEquals("a*1 = a", d, a); d = a.divide(BigInteger.ONE); assertEquals("a/1 = a", d, a); // inverse operations b = a.multiply(a); c = b.divide(a); assertEquals("(a*a)/a = a", c, a); b = a.divide(a); c = b.multiply(a); assertEquals("(a/a)*a = a", c, a); // comutativity b = BigInteger.ZERO.random(500); c = a.multiply(b); d = b.multiply(a); assertEquals("a*b = b*a", c, d); // inverse d = c.divide(b); // e = c.multiply( b.inverse() ); e = a; assertEquals("a/b = a*(1/b)", d, e); // associativity c = BigInteger.ZERO.random(500); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a*(b*c) = (a*b)*c", d, e); } /** * Test static initialization and constants for BigRational. */ public void testRationalConstants() { BigRational a, b, c, d; a = BigRational.ZERO; b = BigRational.ONE; //System.out.println("a = " + a); //System.out.println("b = " + b); c = b.subtract(b); assertTrue("0.isZERO()", a.isZERO()); assertTrue("1.isONE", b.isONE()); assertEquals("1-1 = 0", c, a); assertTrue("(1-1).isZERO()", c.isZERO()); d = b.multiply(b); assertTrue("1*1 = 1", d.isONE()); d = b.multiply(a); assertTrue("1*0 = 0", d.isZERO()); } /** * Test static initialization and constants for BigComplex. */ public void testComplexConstants() { BigComplex a, b, c, d; a = BigComplex.ZERO; b = BigComplex.ONE; c = b.subtract(b); assertTrue("0.isZERO()", a.isZERO()); assertTrue("1.isONE", b.isONE()); assertEquals("1-1 = 0", c, a); assertTrue("(1-1).isZERO()", c.isZERO()); d = b.multiply(b); assertTrue("1*1 = 1", d.isONE()); d = b.multiply(a); assertTrue("1*0 = 0", d.isZERO()); } /** * Test static initialization and constants for BigQuaternion. */ public void testQuaternionConstants() { BigQuaternionRing fac = new BigQuaternionRing(); BigQuaternion a, b, c, d; a = fac.ZERO; b = fac.ONE; c = b.subtract(b); assertTrue("0.isZERO()", a.isZERO()); assertTrue("1.isONE", b.isONE()); assertEquals("1-1 = 0", c, a); assertTrue("(1-1).isZERO()", c.isZERO()); d = b.multiply(b); assertTrue("1*1 = 1", d.isONE()); d = b.multiply(a); assertTrue("1*0 = 0", d.isZERO()); } //-------------------------------------------------------- /** * Test string constructor and toString for BigRational. */ public void testRationalConstructor() { BigRational a, b, c, d; a = new BigRational(1); b = new BigRational(-1); c = new BigRational(0); d = a.sum(b); assertTrue("'1'.isONE()", a.isONE()); assertTrue("1+(-1) = 0", d.isZERO()); d = a.negate(); assertEquals("-1 = -(1)", d, b); d = a.multiply(c); assertTrue("'0'.isZERO()", d.isZERO()); d = b.multiply(b); assertTrue("(-1)*(-1) = 1", d.isONE()); a = new BigRational(3); b = new BigRational("3"); assertEquals("3 = '3'", a, b); a = new BigRational(-5); b = new BigRational("-5"); assertEquals("-5 = '-5'", a, b); // 0 1 2 3 4 // 0123456789012345678901234567890123456789012345 String s = "1111111111111111111111111111111111111111111111"; a = new BigRational(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); s = "2/4"; a = new BigRational(s); t = a.toString(5); //System.out.println("a = " + a); //System.out.println("t = " + t); String r = "0.5"; assertEquals("stringConstr = toString", r, t); } /** * Test string constructor and toString for BigComplex. */ public void testComplexConstructor() { BigComplex a, b, c, d; a = new BigComplex(1); b = new BigComplex(-1); c = new BigComplex(0); d = a.sum(b); assertTrue("'1'.isONE()", a.isONE()); assertTrue("1+(-1) = 0", d.isZERO()); d = a.negate(); assertEquals("-1 = -(1)", d, b); d = a.multiply(c); assertTrue("'0'.isZERO()", d.isZERO()); d = b.multiply(b); assertTrue("(-1)*(-1) = 1", d.isONE()); a = new BigComplex(3); b = new BigComplex("3"); assertEquals("3 = '3'", a, b); a = new BigComplex(-5); b = new BigComplex("-5"); assertEquals("-5 = '-5'", a, b); // 0 1 2 3 4 // 0123456789012345678901234567890123456789012345 String s = "1111111111111111111111111111111111111111111111"; a = new BigComplex(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); } /** * Test string constructor and toString for BigQuaternion. */ public void testQuaternionConstructor() { BigQuaternionRing fac = new BigQuaternionRing(); BigQuaternion a, b, c, d; a = new BigQuaternion(fac, 1); b = new BigQuaternion(fac, -1); c = new BigQuaternion(fac, 0); d = a.sum(b); assertTrue("'1'.isONE()", a.isONE()); assertTrue("1+(-1) = 0", d.isZERO()); d = a.negate(); assertEquals("-1 = -(1)", d, b); d = a.multiply(c); assertTrue("'0'.isZERO()", d.isZERO()); d = b.multiply(b); assertTrue("(-1)*(-1) = 1", d.isONE()); a = new BigQuaternion(fac, 3); b = new BigQuaternion(fac, "3"); assertEquals("3 = '3'", a, b); a = new BigQuaternion(fac, -5); b = new BigQuaternion(fac, "-5"); assertEquals("-5 = '-5'", a, b); // 0 1 2 3 4 // 0123456789012345678901234567890123456789012345 String s = "1111111111111111111111111111111111111111111111"; a = new BigQuaternion(fac, s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); } //-------------------------------------------------------- /** * Test random and compares Rational. */ public void testRationalRandom() { BigRational a, b, c; a = BigRational.ZERO.random(500); b = new BigRational("" + a); c = b.subtract(a); assertTrue("a-'a' = 0", c.isZERO()); assertEquals("compareTo('a',a) = 0", 0, b.compareTo(a)); assertEquals("signum('a'-a) = 0", 0, c.signum()); } /** * Test random and compares Complex. */ public void testComplexRandom() { BigComplex a, b, c; a = BigComplex.ZERO.random(500); b = new BigComplex("" + a); c = b.subtract(a); assertTrue("a-'a' = 0", c.isZERO()); assertEquals("compareTo('a',a) = 0", 0, b.compareTo(a)); assertEquals("signum('a'-a) = 0", 0, c.signum()); } /** * Test random and compares Quaternion. */ public void testQuaternionRandom() { BigQuaternionRing fac = new BigQuaternionRing(); BigQuaternion a, b, c; a = fac.random(500); b = new BigQuaternion(fac, a.toString()); c = b.subtract(a); assertTrue("a-'a' = 0", c.isZERO()); assertEquals("signum('a'-a) = 0", 0, c.signum()); assertEquals("compareTo('a',a) = 0", 0, b.compareTo(a)); } //-------------------------------------------------------- /** * Test addition for Rational. */ public void testRationalAddition() { BigRational a, b, c, d, e; // neutral element a = BigRational.ZERO.random(500); d = a.sum(BigRational.ZERO); assertEquals("a+0 = a", d, a); d = a.subtract(BigRational.ZERO); assertEquals("a-0 = a", d, a); // inverse operations b = a.sum(a); c = b.subtract(a); assertEquals("(a+a)-a = a", c, a); b = a.subtract(a); c = b.sum(a); assertEquals("(a-a)+a = a", c, a); // comutativity b = BigRational.ZERO.random(500); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); // negation c = a.subtract(b); d = a.sum(b.negate()); assertEquals("a-b = a+(-b)", c, d); // associativity c = BigRational.ZERO.random(500); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test addition for Complex. */ public void testComplexAddition() { BigComplex a, b, c, d, e; // neutral element a = BigComplex.ZERO.random(500); d = a.sum(BigComplex.ZERO); assertEquals("a+0 = a", d, a); d = a.subtract(BigComplex.ZERO); assertEquals("a-0 = a", d, a); // inverse operations b = a.sum(a); c = b.subtract(a); assertEquals("(a+a)-a = a", c, a); b = a.subtract(a); c = b.sum(a); assertEquals("(a-a)+a = a", c, a); // comutativity b = BigComplex.ZERO.random(500); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); // negation c = a.subtract(b); d = a.sum(b.negate()); assertEquals("a-b = a+(-b)", c, d); // associativity c = BigComplex.ZERO.random(500); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test addition for Quaternion. */ public void testQuaternionAddition() { BigQuaternionRing fac = new BigQuaternionRing(); BigQuaternion a, b, c, d, e; // neutral element a = fac.random(500); d = a.sum(fac.ZERO); assertEquals("a+0 = a", d, a); d = a.subtract(fac.ZERO); assertEquals("a-0 = a", d, a); // inverse operations b = a.sum(a); c = b.subtract(a); assertEquals("(a+a)-a = a", c, a); b = a.subtract(a); c = b.sum(a); assertEquals("(a-a)+a = a", c, a); // comutativity b = fac.random(500); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); // negation c = a.subtract(b); d = a.sum(b.negate()); assertEquals("a-b = a+(-b)", c, d); // associativity c = fac.random(500); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); } //-------------------------------------------------------- /** * Test multiplication for Rational. */ public void testRationalMultiplication() { BigRational a, b, c, d, e; // neutral element a = BigRational.ZERO.random(500); d = a.multiply(BigRational.ONE); assertEquals("a*1 = a", d, a); d = a.divide(BigRational.ONE); assertEquals("a/1 = a", d, a); // inverse operations b = a.multiply(a); c = b.divide(a); assertEquals("(a*a)/a = a", c, a); b = a.divide(a); c = b.multiply(a); assertEquals("(a/a)*a = a", c, a); // comutativity b = BigRational.ZERO.random(500); c = a.multiply(b); d = b.multiply(a); assertEquals("a*b = b*a", c, d); // inverse d = c.divide(b); e = c.multiply(b.inverse()); //e = a; assertEquals("a/b = a*(1/b)", d, e); // associativity c = BigRational.ZERO.random(500); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a*(b*c) = (a*b)*c", d, e); } /** * Test multiplication for Complex. */ public void testComplexMultiplication() { BigComplex a, b, c, d, e; // neutral element a = BigComplex.ZERO.random(500); d = a.multiply(BigComplex.ONE); assertEquals("a*1 = a", d, a); d = a.divide(BigComplex.ONE); assertEquals("a/1 = a", d, a); // inverse operations b = a.multiply(a); c = b.divide(a); assertEquals("(a*a)/a = a", c, a); b = a.divide(a); c = b.multiply(a); assertEquals("(a/a)*a = a", c, a); // comutativity b = BigComplex.ZERO.random(500); c = a.multiply(b); d = b.multiply(a); assertEquals("a*b = b*a", c, d); // inverse d = c.divide(b); e = c.multiply(b.inverse()); //e = a; assertEquals("a/b = a*(1/b)", d, e); // associativity c = BigComplex.ZERO.random(500); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a*(b*c) = (a*b)*c", d, e); } /** * Test multiplication for Quaternion. */ public void testQuaternionMultiplication() { BigQuaternionRing fac = new BigQuaternionRing(); BigQuaternion a, b, c, d, e; // neutral element a = fac.random(500); d = a.multiply(fac.ONE); assertEquals("a*1 = a", d, a); d = a.divide(fac.ONE); assertEquals("a/1 = a", d, a); // inverse operations b = a.multiply(a); c = b.divide(a); assertEquals("(a*a)/a = a", c, a); b = a.divide(a); c = b.multiply(a); assertEquals("(a/a)*a = a", c, a); // inverse b = fac.random(500); c = b.multiply(a); d = c.divide(b); e = c.multiply(b.inverse()); //e = a; assertEquals("a/b = a*(1/b)", d, e); // associativity c = fac.random(500); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a*(b*c) = (a*b)*c", d, e); // non comutativity a = fac.I; b = fac.J; c = a.multiply(b); d = b.multiply(a); assertEquals("I*J = -J*I", c, d.negate()); a = fac.I; b = fac.K; c = a.multiply(b); d = b.multiply(a); assertEquals("I*K = -K*I", c, d.negate()); a = fac.J; b = fac.K; c = a.multiply(b); d = b.multiply(a); assertEquals("J*K = -K*J", c, d.negate()); } /** * Test power for Rational. */ public void testRationalPower() { BigRational a, b, c, d; a = BigRational.ZERO.random(100); // power operations b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); Power pow = new Power(BigRational.ONE); b = pow.power(a, 1); assertEquals("a^1 = a", b, a); b = pow.power(a, 2); c = a.multiply(a); assertEquals("a^2 = a*a", b, c); d = pow.power(a, -2); c = b.multiply(d); assertTrue("a^2 * a^-2 = 1", c.isONE()); b = pow.power(a, 3); c = a.multiply(a).multiply(a); assertEquals("a^3 = a*a*a", b, c); d = pow.power(a, -3); c = b.multiply(d); assertTrue("a^3 * a^-3 = 1", c.isONE()); //Java 8: d = a.power(-3); c = b.multiply(d); assertTrue("a^3 * a^-3 = 1", c.isONE()); } /** * Test power for Integer. */ public void testIntegerPower() { BigInteger a, b, c, d, e; a = BigInteger.ZERO.random(500); // power operations b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); Power pow = new Power(BigInteger.ONE); b = pow.power(a, 1); assertEquals("a^1 = a", b, a); b = pow.power(a, 2); c = a.multiply(a); assertEquals("a^2 = a*a", b, c); b = pow.power(a, 3); c = a.multiply(a).multiply(a); assertEquals("a^3 = a*a*a", b, c); // mod power operations a = new BigInteger(3); b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); a = new BigInteger(11); e = new BigInteger(2); c = Power. modPositivePower(a, 10, e); assertTrue("3^n mod 2 = 1", c.isONE()); // little fermat a = BigInteger.ZERO.random(500); b = new BigInteger(11); c = Power. modPositivePower(a, 11, b); d = a.remainder(b); assertEquals("a^p = a mod p", c, d); c = pow.modPower(a, 11, b); assertEquals("a^p = a mod p", c, d); //Java 8: a = BigInteger.ZERO.random(100); d = a.power(1); c = a; assertEquals("a^1 == a", c, d); d = a.power(0); c = BigInteger.ONE; assertEquals("a^0 == 1", c, d); d = a.power(3); c = a.multiply(a).multiply(a); assertEquals("a^3 == a*a*a", c, d); } /** * Test Combinatoric. */ public void testCombinatoric() { BigInteger a, b, c; a = Combinatoric.binCoeff(5, 0); assertTrue("(5 0) == 1 ", a.isONE()); a = Combinatoric.binCoeff(5, 7); //System.out.println(5 + " over " + 7 + " = " + a); assertTrue("(5 7) == 1 ", a.isONE()); int n = 7; for (int k = 0; k <= n; k++) { a = Combinatoric.binCoeff(n, k); b = Combinatoric.binCoeff(n, n - k); assertEquals("(5 k) == (5 5-k) ", b, a); //System.out.println(n + " over " + k + " = " + a); } assertTrue("(5 5) == 1 ", a.isONE()); b = Combinatoric.binCoeffSum(n, n); //System.out.println("sum( " + n + " over " + n + " ) = " + b); c = Power.positivePower(new BigInteger(2), n); assertEquals("sum(5 5) == 1 ", b, c); b = Combinatoric.factorial(3); assertEquals("3! == 6 ", b, new BigInteger(6)); b = Combinatoric.factorial(0); assertEquals("0! == 1 ", b, new BigInteger(1)); } /** * Test square root. */ public void testSquareRoot() { BigInteger a, b, c, d, e, f; a = BigInteger.ONE; b = a.random(47).abs(); //b = c.multiply(c); d = Roots.sqrtInt(b); //System.out.println("b = " + b); //System.out.println("root = " + d); e = d.multiply(d); //System.out.println("root^2 = " + e); assertTrue("root^2 <= a ", e.compareTo(b) <= 0); d = d.sum(BigInteger.ONE); f = d.multiply(d); //System.out.println("(root+1)^2 = " + f); assertTrue("(root+1)^2 >= a ", f.compareTo(b) >= 0); c = Roots.sqrt(b); //System.out.println("b = " + b); //System.out.println("root = " + c); e = c.multiply(c); //System.out.println("root^2 = " + e); assertTrue("root^2 <= a ", e.compareTo(b) <= 0); c = c.sum(BigInteger.ONE); f = c.multiply(c); //System.out.println("(root+1)^2 = " + f); assertTrue("(root+1)^2 >= a ", f.compareTo(b) >= 0); } /** * Test root. */ public void testRoot() { BigInteger a, b, d, e, f; a = BigInteger.ONE; b = a.random(47).abs(); //System.out.println("\nb = " + b); //System.out.println("bitsize(b) = " + b.val.bitLength()); for (int n = 2; n < 8; n++) { d = Roots.root(b, n); //System.out.println(n+"-th root = " + d); e = Power.positivePower(d, n); //System.out.println("root^"+n+" = " + e); assertTrue("root^" + n + " <= a " + (b.subtract(e)), e.compareTo(b) <= 0); d = d.sum(BigInteger.ONE); f = Power.positivePower(d, n); //System.out.println("(root+1)^"+n+" = " + f); assertTrue("(root+1)^" + n + " >= a ", f.compareTo(b) >= 0); } } /** * Test root decimal. */ public void testRootDecimal() { BigDecimal a, b, d, e; a = BigDecimal.ONE; BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 2); BigDecimal epsd = new BigDecimal(eps); b = a.random(17).abs(); //System.out.println("\nb = " + b); //System.out.println("ulp(b) = " + b.val.ulp()); for (int n = 1; n < 8; n++) { d = Roots.root(b, n); //System.out.println(n+"-th root = " + d); e = Power.positivePower(d, n); //System.out.println("root^"+n+" = " + e); if (b.compareTo(e) == 0) { assertTrue("root^" + n + " == b: " + e, b.compareTo(e) == 0); continue; } BigDecimal r = b.subtract(e).abs().divide(b.abs().sum(e.abs())); assertTrue("root(a,n)**n == a: " + r, r.compareTo(epsd) <= 0); } } /** * Test root decimal. */ public void test2RootDecimal() { BigDecimal a, b, c, d; a = BigDecimal.ZERO; b = Roots.sqrt(a); assertTrue("sqrt(0) == 0: " + b, b.isZERO()); a = BigDecimal.ONE; b = Roots.sqrt(a); assertTrue("sqrt(1) == 1: " + b, b.isONE()); a = new BigDecimal("4"); b = Roots.sqrt(a); //b = Roots.root(a,2); c = b.multiply(b); assertTrue("sqrt(4)*sqrt(4) == 4: " + a.subtract(c), a.compareTo(c) == 0); //System.out.println("DEFAULT_PRECISION = " + BigDecimal.DEFAULT_PRECISION); a = new BigDecimal("0.5"); b = Roots.sqrt(a); //b = Roots.root(a,2); c = b.multiply(b); //System.out.println("a = " + a + ", sqrt(a) = " + b + ", b^2 = " + c); assertTrue("sqrt(0.5)*sqrt(0.5) == 0.5: " + a.subtract(c), a.compareTo(c) == 0); assertTrue("sqrt(0.5)*sqrt(0.5) == 0.5: " + b, a.compareTo(c) == 0); a = a.random(5).abs(); b = Roots.sqrt(a); //b = Roots.root(a,2); c = b.multiply(b); //System.out.println("a = " + a + ", sqrt(a) = " + b + ", b^2 = " + c); BigDecimal eps = new BigDecimal("0.1").power(BigDecimal.DEFAULT_PRECISION - 2); d = a.subtract(c).abs().divide(a.abs().sum(BigDecimal.ONE)); assertTrue("sqrt(a)*sqrt(a) == a: " + d, d.compareTo(eps) <= 0); } /** * Test root complex decimal. */ public void testRootDecimalComplex() { BigDecimalComplex a, b, c, d, e; a = BigDecimalComplex.ZERO; b = Roots.sqrt(a); assertTrue("sqrt(0) == 0: " + b, b.isZERO()); a = BigDecimalComplex.ONE; b = Roots.sqrt(a); assertTrue("sqrt(1) == 1: " + b, b.isONE()); a = BigDecimalComplex.ONE.negate(); b = Roots.sqrt(a); d = b.multiply(b); //System.out.println("a = " + a + ", b = " + b + ", d = " + d); assertTrue("sqrt(-1) == I: " + b, b.isIMAG()); assertTrue("sqrt(-1)*sqrt(-1) == -1: " + a + ", b = " + b, a.compareTo(d) == 0); b = BigDecimalComplex.I; c = Roots.sqrt(b); d = c.multiply(c); //System.out.println("b = " + b + ", c = " + c + ", d = " + d); assertTrue("sqrt(b)*sqrt(b) == b: " + c + ", b = " + b, b.compareTo(d) == 0); b = a.fromInteger(4); c = Roots.sqrt(b); d = BigDecimalComplex.ONE.sum(BigDecimalComplex.ONE); //System.out.println("b = " + b + ", c = " + c + ", d = " + d); assertTrue("sqrt(4) == 2: " + c, c.compareTo(d) == 0); b = b.multiply(BigDecimalComplex.I); c = Roots.sqrt(b); d = c.multiply(c); //System.out.println("b = " + b + ", c = " + c + ", d = " + d); assertTrue("sqrt(b)*sqrt(b) == b: " + c + ", b = " + b, b.compareTo(d) == 0); b = a.random(5); c = b.norm(); d = b.multiply(b.conjugate()); assertTrue("norm(b) == b*b^: b-d = " + c.subtract(d), c.compareTo(d) == 0); BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 1); //System.out.println("eps = " + eps + ", epsd = " + new BigDecimal(eps)); BigDecimal epsd = new BigDecimal(eps); BigDecimal dd; //System.out.println("b = " + b + ", c = " + c); //c = b.norm(); d = b.abs(); e = d.multiply(d); dd = e.re.subtract(c.re).abs().divide(e.re.abs().sum(c.re.abs())); //System.out.println("dd = " + dd + ", d = " + d + ", e = " + e); assertTrue("abs()*abs() == norm(): " + dd, dd.compareTo(epsd) <= 0); } /** * Test root rational. */ public void test2RootRational() { BigRational a, b, c, d; a = BigRational.ZERO; b = Roots.sqrt(a); assertTrue("sqrt(0) == 0: " + b, b.isZERO()); a = BigRational.ONE; b = Roots.sqrt(a); assertTrue("sqrt(1) == 1: " + b, b.isONE()); a = BigRational.ONE.negate(); try { b = Roots.sqrt(a); fail("sqrt(-1) illegal: " + b); } catch (ArithmeticException e) { // pass } a = new BigRational("4"); b = Roots.sqrt(a); c = b.multiply(b); assertTrue("sqrt(4)*sqrt(4) == 4: " + a.subtract(c), a.compareTo(c) == 0); BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 1); //System.out.println("eps = " + eps + ", epsd = " + new BigDecimal(eps)); a = new BigRational("0.5"); b = Roots.sqrt(a); c = b.multiply(b); //System.out.println("a = " + a + ", sqrt(a) = " + b + ", b^2 = " + c); d = a.subtract(c).abs().divide(a.abs().sum(c.abs())); //System.out.println("d = " + d + ", dd = " + new BigDecimal(d)); assertTrue("sqrt(0.5)*sqrt(0.5) == 0.5: " + c, d.compareTo(eps) <= 0); a = a.random(5).abs(); b = Roots.sqrt(a); c = b.multiply(b); //System.out.println("a = " + a + ", sqrt(a) = " + b + ", b^2 = " + c); d = a.subtract(c).abs().divide(a.abs().sum(c.abs())); //System.out.println("d = " + d + ", dd = " + new BigDecimal(d)); assertTrue("sqrt(0.5)*sqrt(0.5) == 0.5: " + c, d.compareTo(eps) <= 0); } /** * Test root/norm complex. */ public void test2NormComplex() { BigComplex a, b; a = BigComplex.ZERO; b = a.abs(); assertTrue("abs(0) == 0: " + b, b.isZERO()); a = BigComplex.ONE; b = a.abs(); assertTrue("abs(1) == 1: " + b, b.isONE()); a = BigComplex.ONE.negate(); b = a.abs(); assertTrue("abs(-1): " + b, b.isONE()); BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 1); //System.out.println("eps = " + eps); // + ", epsd = " + new BigDecimal(eps)); BigRational r, s, t; a = a.random(5); b = a.abs(); //System.out.println("a = " + a + ", b = " + b); r = b.multiply(b).re; s = a.multiply(a.conjugate()).re; //System.out.println("r = " + r + ", s = " + s); t = r.subtract(s).abs().divide(r.abs().sum(s.abs())); //System.out.println("t = " + t + ", eps = " + eps); assertTrue("abs()*abs() == norm(): " + b, t.compareTo(eps) <= 0); } /** * Test root/norm quaternion. */ public void test2NormQuaternion() { BigQuaternion a, b; BigQuaternionRing fac = new BigQuaternionRing(); a = fac.ZERO; b = a.abs(); assertTrue("abs(0) == 0: " + b, b.isZERO()); a = fac.ONE; b = a.abs(); assertTrue("abs(1) == 1: " + b, b.isONE()); a = fac.ONE.negate(); b = a.abs(); assertTrue("abs(-1): " + b, b.isONE()); BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 1); //System.out.println("eps = " + eps); // + ", epsd = " + new BigDecimal(eps)); BigRational r, s, t; a = fac.random(5); b = a.abs(); //System.out.println("\na = " + a + ", b = " + b); r = b.multiply(b).re; s = a.multiply(a.conjugate()).re; //System.out.println("r = " + r + ", s = " + s); t = r.subtract(s).abs().divide(r.abs().sum(s.abs())); //System.out.println("t = " + t + ", eps = " + eps); assertTrue("sqrt(x)*sqrt(x): " + b, t.compareTo(eps) <= 0); } /** * Test root/norm octonion. */ public void test2NormOctonion() { BigOctonion a, b; BigQuaternionRing fac = new BigQuaternionRing(); BigOctonion ofac = new BigOctonion(fac); a = ofac.getZERO(); b = a.abs(); assertTrue("abs(0) == 0: " + b, b.isZERO()); a = ofac.getONE(); b = a.abs(); assertTrue("abs(1) == 1: " + b, b.isONE()); a = ofac.getONE().negate(); b = a.abs(); assertTrue("abs(-1): " + b, b.isONE()); BigRational eps = new BigRational(1, 10).power(BigDecimal.DEFAULT_PRECISION - 1); //System.out.println("eps = " + eps); // + ", epsd = " + new BigDecimal(eps)); BigRational r, s, t; a = ofac.random(5); b = a.abs(); //System.out.println("\na = " + a + ", b = " + b); r = b.multiply(b).or.re; s = a.multiply(a.conjugate()).or.re; //System.out.println("r = " + r + ", s = " + s); t = r.subtract(s).abs().divide(r.abs().sum(s.abs())); //System.out.println("t = " + t + ", eps = " + eps); assertTrue("sqrt(x)*sqrt(x): " + b, t.compareTo(eps) <= 0); } /** * Test continued fraction. */ public void testContinuedFraction() { BigRational fac = BigRational.ONE; BigRational x = fac.random(35); //x = fac.parse("5/12"); //x = fac.parse("-1"); List cf = ArithUtil.continuedFraction(x); //System.out.println("cf(" + x + ") = " + cf); BigRational a = ArithUtil.continuedFractionApprox(cf); //System.out.println("a = " + a); assertEquals("a = approx(cf(a)): ", x, a); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigComplexTest.java000066400000000000000000000127471445075545500245360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigComplex tests with JUnit. * @author Heinz Kredel */ public class BigComplexTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigComplexTest object. * @param name String. */ public BigComplexTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigComplexTest.class); return suite; } BigComplex a, b, c, d, e; BigComplex fac; @Override protected void setUp() { a = b = c = d = e = null; fac = new BigComplex(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = BigComplex.CDIF(b, b); d = fac.getIMAG(); e = BigComplex.CDIF(d, d); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); assertEquals("1-1 = 0", c, a); assertTrue("i = i", d.isIMAG()); assertTrue("i-i = 0", e.isZERO()); } /** * Test bitLength. */ public void testBitLength() { a = fac.getZERO(); b = fac.getONE(); c = BigComplex.CDIF(b, b); d = fac.getIMAG(); e = BigComplex.CDIF(d, d); assertEquals("len(0) = 6", 6, a.bitLength()); assertEquals("len(1) = 7", 7, b.bitLength()); assertEquals("len(-1) = 7", 7, b.negate().bitLength()); assertEquals("len(i) = 7", 7, d.bitLength()); assertEquals("len(-i) = 7", 7, d.negate().bitLength()); e = BigComplex.CDIF(b, d); assertEquals("len(1-i) = 8", 8, e.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigComplex("6/8"); b = new BigComplex("3/4"); assertEquals("6/8 = 3/4", a, b); a = new BigComplex("3/4 i 4/5"); b = new BigComplex("-3/4 i -4/5"); assertEquals("3/4 + i 4/5 ", a, b.negate()); String s = "6/1111111111111111111111111111111111111111111"; a = new BigComplex(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); a = new BigComplex(1); b = new BigComplex(-1); c = BigComplex.CSUM(b, a); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, BigComplex.ZERO); } /** * Test random rationals. */ public void testRandom() { a = fac.random(500); b = new BigComplex(a.getRe(), a.getIm()); c = BigComplex.CDIF(b, a); assertEquals("a-b = 0", c, fac.getZERO()); d = new BigComplex(b.getRe(), b.getIm()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = fac.random(100); b = BigComplex.CSUM(a, a); c = BigComplex.CDIF(b, a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); b = fac.random(5); c = a.sum(b); d = b.sum(a); assertEquals("a+b == b+a: " + c.subtract(d), c, d); d = BigComplex.CSUM(a, fac.getZERO()); assertEquals("a+0 = a", d, a); d = BigComplex.CDIF(a, fac.getZERO()); assertEquals("a-0 = a", d, a); d = BigComplex.CDIF(a, a); assertEquals("a-a = 0", d, fac.getZERO()); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(100); b = BigComplex.CPROD(a, a); c = BigComplex.CQ(b, a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = BigComplex.CPROD(a, fac.getONE()); assertEquals("a*1 = a", d, a); d = BigComplex.CQ(a, fac.getONE()); assertEquals("a/1 = a", d, a); b = fac.random(5); c = a.multiply(b); d = b.multiply(a); assertEquals("a*b == b*a: " + c.subtract(d), c, d); a = fac.random(100); b = BigComplex.CINV(a); c = BigComplex.CPROD(a, b); assertTrue("a*1/a = 1", c.isONE()); } /** * Test distributive law. */ public void testDistributive() { BigComplex fac = new BigComplex(); a = fac.random(500); b = fac.random(500); c = fac.random(500); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test power and abs. */ public void testOther() { BigComplex fac = new BigComplex(); a = fac.random(100); b = a.multiply(a); c = a.power(2); assertEquals("a*a == a**2", b, c); d = b.abs(); c = b.norm(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); BigDecimal dd = new BigDecimal(d.re); BigDecimal cd = new BigDecimal(c.re); int t = dd.power(2).compareToRelative(cd); assertTrue("abs(a)**2 ~= norm(a): ", t == 0); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigDecimalComplexTest.java000066400000000000000000000135531445075545500260110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigComplex tests with JUnit. * @author Heinz Kredel */ public class BigDecimalComplexTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigDecimalComplexTest object. * @param name String. */ public BigDecimalComplexTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigDecimalComplexTest.class); return suite; } int precision = BigDecimal.DEFAULT_PRECISION; // must match default BigDecimalComplex a, b, c, d, e, eps; BigDecimalComplex fac; @Override protected void setUp() { a = b = c = d = e = null; fac = new BigDecimalComplex(); eps = new BigDecimalComplex("0.1"); eps = eps.power(precision - 2); } @Override protected void tearDown() { a = b = c = d = e = null; eps = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); d = fac.getIMAG(); e = BigDecimalComplex.CDIF(d, d); assertEquals("1-1 == 0", c, a); assertTrue("1-1 == 0", c.isZERO()); assertTrue("1 == 1", b.isONE()); assertTrue("i == i", d.isIMAG()); assertTrue("i-i == 0", e.isZERO()); c = a.subtract(a); assertEquals("0-0 == 0", c, a); } /** * Test bitLength. */ public void testBitLength() { a = fac.getZERO(); b = fac.getONE(); c = b.random(300); d = fac.getIMAG(); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 4", 4, a.bitLength()); assertEquals("len(1) = 5", 5, b.bitLength()); assertEquals("len(-1) = 5", 5, b.negate().bitLength()); assertEquals("len(i) = 5", 5, d.bitLength()); assertEquals("len(-i) = 5", 5, d.negate().bitLength()); assertTrue("len(random) >= 4", 4 <= c.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigDecimalComplex("6.8"); b = new BigDecimalComplex("3.4"); b = b.sum(b); assertEquals("6.8 == 3.4+3.4", a, b); a = new BigDecimalComplex("3.4 i 4.5"); b = new BigDecimalComplex("-3.4 i -4.5"); assertEquals("3.4 + i 4.5 ", a, b.negate()); String s = "6.1111111111111111111111111111111111111111111"; a = new BigDecimalComplex(s); String t = a.toString(); assertEquals("stringConstr == toString", s, t); a = new BigDecimalComplex(1); b = new BigDecimalComplex(-1); c = b.sum(a); assertTrue("1 == 1", a.isONE()); assertEquals("1+(-1) == 0", c, fac.getZERO()); } /** * Test random decimal. */ public void testRandom() { a = fac.random(500); b = new BigDecimalComplex(a.getRe(), a.getIm()); c = b.subtract(a); assertEquals("a-b == 0", c, fac.getZERO()); d = new BigDecimalComplex(b.getRe(), b.getIm()); assertEquals("sign(a-a) == 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = fac.random(10); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a == a", c, a); assertEquals("a+a-a == a", 0, c.compareTo(a)); b = fac.random(5); c = a.sum(b); d = b.sum(a); assertEquals("a+b == b+a: " + c.subtract(d), c, d); d = a.sum(fac.getZERO()); assertEquals("a+0 == a", d, a); d = a.subtract(fac.getZERO()); assertEquals("a-0 == a", d, a); d = a.subtract(a); assertEquals("a-a == 0", d, fac.getZERO()); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(5); b = a.multiply(a); c = b.divide(a); //assertEquals("a*a/a == a: " + c.subtract(a), c, a); d = c.subtract(a).abs().divide(a.abs()); assertTrue("a*a/a == a: " + c.subtract(a), d.compareTo(eps) <= 0); d = a.multiply(fac.getONE()); assertEquals("a*1 == a", d, a); d = a.divide(fac.getONE()); assertEquals("a/1 == a", d, a); b = fac.random(5); c = a.multiply(b); d = b.multiply(a); assertEquals("a*b == b*a: " + c.subtract(d), c, d); a = fac.random(5); b = a.inverse(); c = a.multiply(b); e = c.subtract(fac.getONE()).abs(); //assertTrue("a*1/a == 1: " + c, c.isONE()); assertTrue("a*1/a == 1: " + e, e.compareTo(eps) <= 0); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(50); b = fac.random(50); c = fac.random(50); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); a = d.subtract(e).abs().divide(e.abs()); //assertEquals("a(b+c) == ab+ac", d, e); assertTrue("a(b+c) == ab+ac", a.compareTo(eps) <= 0); } /** * Test norm and abs. */ public void testNorm() { a = fac.random(5); b = a.norm(); c = a.abs(); d = c.multiply(c); e = b.subtract(d).abs(); //System.out.println("e = " + e); //System.out.println("eps = " + eps); assertTrue("||a|| == |a|*|a|: " + e, e.compareTo(eps) <= 0); e = d.subtract(b).abs().divide(b.abs()); //System.out.println("e = " + e); assertTrue("||a|| == |a|*|a|: " + e, e.compareTo(eps) <= 0); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigDecimalTest.java000066400000000000000000000142611445075545500244560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.math.MathContext; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigDecimal tests with JUnit. * @author Heinz Kredel */ public class BigDecimalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigDecimalTest object. * @param name String. */ public BigDecimalTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(BigDecimalTest.class); return suite; } BigDecimal a, b, c, d, e, eps; BigDecimal fac; int precision = BigDecimal.DEFAULT_PRECISION; // 100; // must match default MathContext mc = BigDecimal.DEFAULT_CONTEXT; // new MathContext( precision ); int kl = precision / 2; @Override protected void setUp() { a = b = c = d = e = null; fac = new BigDecimal(0L, mc); eps = new BigDecimal(new BigRational(1, 10)); eps = eps.power(precision-1); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; eps = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertTrue("1-1 == 0: " + c + a, c.compareTo(a) == 0); assertTrue("1-1 == 0", c.isZERO()); assertTrue("1 == 1", b.isONE()); a = fac.getZERO(); b = fac.getONE(); c = b.subtract(a); assertTrue("1-0 == 1: " + c + b, c.compareTo(b) == 0); } /** * Test bitLength. */ public void testBitLength() { a = fac.getZERO(); b = fac.getONE(); c = b.random(300, 100); //System.out.println("c = " + c); //System.out.println("unscale(c) = " + c.val.unscaledValue()); //System.out.println("scale(c) = " + c.val.scale()); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) == 1", 2, a.bitLength()); assertEquals("len(1) == 3", 3, b.bitLength()); assertEquals("len(-1) == 3", 3, b.negate().bitLength()); assertTrue("len(random) >= 2", 2 <= c.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigDecimal("6.8"); b = new BigDecimal("3.4"); b = b.sum(b); assertEquals("6.8 = 3.4", 0, a.compareTo(b)); String s = "6.1111111111111111111111111111111111111111111"; a = new BigDecimal(s); String t = a.toString(); assertEquals("stringConstr == toString", s, t); a = new BigDecimal(1); b = new BigDecimal(-1); c = b.sum(a); assertTrue("1 == 1", a.isONE()); assertTrue("1+(-1) == 0", c.compareTo(fac.getZERO()) == 0); assertTrue("1+(-1) == 0", c.isZERO()); } /** * Test random rationals. */ public void testRandom() { a = fac.random(5 * kl); //System.out.println("a = " + a); b = new BigDecimal("" + a); c = a.subtract(a); //System.out.println("c = " + c); //assertTrue("a-b == 0", c.compareTo(BigDecimal.ZERO)==0 ); assertTrue("a-b == 0", c.isZERO()); d = new BigDecimal("" + b); //System.out.println("b = " + b); //System.out.println("d = " + d); assertTrue("sign(a-a) == 0", b.compareTo(d) == 0); } /** * Test addition. */ public void testAddition() { a = fac.random(kl); b = a.sum(a); c = b.subtract(a); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //assertEquals("a+a-a = a", c, a); assertEquals("a+a-a == a", 0, c.compareTo(a)); d = a.sum(fac.getZERO()); assertEquals("a+0 == a", 0, d.compareTo(a)); d = a.subtract(fac.getZERO()); assertEquals("a-0 == a", 0, d.compareTo(a)); d = a.subtract(a); assertTrue("a-a == 0", d.compareTo(fac.getZERO()) == 0); b = fac.random(kl); c = a.sum(b); d = b.sum(a); assertTrue("a+b == b+a", d.compareTo(c) == 0); // addition is not associative } /** * Test multiplication. Is not associative. */ public void testMultiplication() { a = fac.random(kl); b = a.multiply(a); if (a.isZERO()) { c = a; } else { c = b.divide(a); } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //assertEquals("a*a/a = a",c,a); assertTrue("a*a/a = a", c.compareTo(a) == 0); d = a.multiply(fac.getONE()); assertEquals("a*1 == a", d, a); d = a.divide(fac.getONE()); assertEquals("a/1 = a", 0, d.compareTo(a)); a = fac.random(kl); b = a.inverse(); c = a.multiply(b); //System.out.println("c = " + c); d = c.subtract(fac.getONE()).abs(); //System.out.println("d = " + d); assertTrue("a*1/a == 1: " + c, d.compareTo(eps) <= 0); b = fac.random(kl); c = a.multiply(b); d = b.multiply(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("ab == ba", d.compareTo(c) == 0); c = fac.random(kl); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); if (d.compareTo(e) == 0) { assertTrue("a(bc) == (ab)c", d.compareTo(e) == 0); } } /** * Test distributive law. Does not hold. */ public void testDistributive() { a = fac.random(kl); b = fac.random(kl); c = fac.random(kl); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); if (d.compareTo(e) == 0) { assertTrue("a(b+c) == ab+ac", d.compareTo(e) == 0); } } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigIntegerTest.java000066400000000000000000000150431445075545500245140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigInteger tests with JUnit. * @author Heinz Kredel */ public class BigIntegerTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigIntegerTest object. * @param name String. */ public BigIntegerTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigIntegerTest.class); return suite; } private final static int bitlen = 100; BigInteger a; BigInteger b; BigInteger c; BigInteger d; BigInteger e; @Override protected void setUp() { a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; } /** * Test static initialization and constants. */ public void testConstants() { a = BigInteger.ZERO; b = BigInteger.ONE; c = BigInteger.IDIF(b, b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); } /** * Test bitLength. */ public void testBitLength() { a = BigInteger.ZERO; b = BigInteger.ONE; c = BigInteger.IDIF(b, b); d = BigInteger.IRAND(500); assertEquals("len(0) = 1", 1, a.bitLength()); assertEquals("len(1) = 2", 2, b.bitLength()); assertEquals("len(-1) = 2", 2, b.negate().bitLength()); assertTrue("len(random) >= 1", 1 <= d.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigInteger("34"); b = new BigInteger("34"); assertEquals("34 = 34", a, b); a = new BigInteger("-4"); b = new BigInteger("-4"); assertEquals("-4 = -4", a, b); String s = "1111111111111111111111111111111111111111111"; a = new BigInteger(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); a = new BigInteger(1); b = new BigInteger(-1); c = BigInteger.ISUM(b, a); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, BigInteger.ZERO); } /** * Test random integer. */ public void testRandom() { a = BigInteger.IRAND(500); b = new BigInteger("" + a); c = BigInteger.IDIF(b, a); assertEquals("a-b = 0", c, BigInteger.ZERO); d = new BigInteger(b.getVal()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = BigInteger.IRAND(bitlen); b = BigInteger.ISUM(a, a); c = BigInteger.IDIF(b, a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); d = BigInteger.ISUM(a, BigInteger.ZERO); assertEquals("a+0 = a", d, a); d = BigInteger.IDIF(a, BigInteger.ZERO); assertEquals("a-0 = a", d, a); d = BigInteger.IDIF(a, a); assertEquals("a-a = 0", d, BigInteger.ZERO); } /** * Test multiplication. */ public void testMultiplication() { a = BigInteger.IRAND(bitlen); b = BigInteger.IPROD(a, a); c = BigInteger.IQ(b, a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, BigInteger.ICOMP(c, a)); d = BigInteger.IPROD(a, BigInteger.ONE); assertEquals("a*1 = a", d, a); d = BigInteger.IQ(a, BigInteger.ONE); assertEquals("a/1 = a", d, a); a = BigInteger.IRAND(bitlen * 2); b = BigInteger.IRAND(bitlen); BigInteger[] qr = BigInteger.IQR(a, b); c = BigInteger.IPROD(qr[0], b); c = BigInteger.ISUM(c, qr[1]); assertEquals("a = q*b+r)", a, c); } /** * Test distributive law. */ public void testDistributive() { BigInteger fac = new BigInteger(); a = fac.random(bitlen); b = fac.random(bitlen); c = fac.random(bitlen); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test gcd. */ public void testGcd() { a = BigInteger.IRAND(bitlen); b = BigInteger.IRAND(bitlen); c = BigInteger.IGCD(a, b); // ~1 BigInteger[] qr = BigInteger.IQR(a, c); d = BigInteger.IPROD(qr[0], c); assertEquals("a = gcd(a,b)*q1", a, d); assertEquals("a/gcd(a,b) = q*x + 0", qr[1], BigInteger.ZERO); qr = BigInteger.IQR(b, c); d = BigInteger.IPROD(qr[0], c); assertEquals("b = gcd(a,b)*q1", b, d); assertEquals("b/gcd(a,b) = q*x + 0", qr[1], BigInteger.ZERO); c = BigInteger.IRAND(bitlen * 4); a = BigInteger.IPROD(a, c); b = BigInteger.IPROD(b, c); c = BigInteger.IGCD(a, b); // = c qr = BigInteger.IQR(a, c); d = BigInteger.IPROD(qr[0], c); assertEquals("a = gcd(a,b)*q1", a, d); assertEquals("a/gcd(a,b) = q*x + 0", qr[1], BigInteger.ZERO); qr = BigInteger.IQR(b, c); d = BigInteger.IPROD(qr[0], c); assertEquals("b = gcd(a,b)*q1", b, d); assertEquals("b/gcd(a,b) = q*x + 0", qr[1], BigInteger.ZERO); } /** * Test iterator. */ public void testIterator() { int t = 0; BigInteger bi = new BigInteger(); bi.setAllIterator(); BigInteger j = null, ten = null; for (BigInteger i : bi) { t++; //System.out.println("i = " + i); if (t >= 20) { j = i; break; } } ten = new BigInteger(10); assertEquals("j == 10 ", j, ten); } /** * Test non-negative iterator. */ public void testNNIterator() { int t = 0; BigInteger bi = new BigInteger(); bi.setNonNegativeIterator(); BigInteger j = null, ten = null; Iterator iter = bi.iterator(); while (iter.hasNext()) { BigInteger i = iter.next(); t++; //System.out.println("i = " + i); if (t > 20) { j = i; break; } } ten = new BigInteger(20); assertEquals("j == 10 ", j, ten); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigOctonionTest.java000066400000000000000000000150151445075545500247060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigOctonion tests with JUnit. * @author Heinz Kredel */ public class BigOctonionTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigOctonionTest object. * @param name String. */ public BigOctonionTest(String name) { super(name); } /** * @return suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigOctonionTest.class); return suite; } BigOctonion a, b, c, d, e; BigOctonion fac; BigQuaternionRing cfac; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigQuaternionRing(); fac = new BigOctonion(cfac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); } /** * Test bitLength. */ public void testBitLength() { a = fac.getZERO(); b = fac.getONE(); c = b.random(10); //System.out.println("c = " + c); //.toScript()); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 24", 24, a.bitLength()); assertEquals("len(1) = 25", 25, b.bitLength()); assertEquals("len(-1) = 25", 25, b.negate().bitLength()); assertTrue("len(random) >= 24", 24 <= c.bitLength()); d = fac.I; assertEquals("len(i) = 25", 25, d.bitLength()); assertEquals("len(-i) = 25", 25, d.negate().bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigOctonion(cfac, "6/8"); b = new BigOctonion(cfac, "3/4"); assertEquals("6/8 = 3/4", a, b); a = new BigOctonion(cfac, "3/4 i 4/5 j 1/5 k 2/5"); b = new BigOctonion(cfac, "-3/4 i -4/5 j -1/5 k -2/5"); assertEquals("3/4 + i 4/5 + j 1/5 + k 2/5", a, b.negate()); String s = "6/1111111111111111111111111111111111111111111"; a = new BigOctonion(cfac, s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); String sr = "3/4 i 4/5 j 1/5 k 2/5"; String si = "-3/4 i -4/5 j -1/5 k -2/5"; s = sr + " o " + si; a = new BigOctonion(cfac, s); BigQuaternion qr = new BigQuaternion(cfac, sr); BigQuaternion qi = new BigQuaternion(cfac, si); b = new BigOctonion(qr, qi); assertEquals("s = " + s, a, b); a = new BigOctonion(cfac, 1); b = new BigOctonion(cfac, -1); c = b.sum(a); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, fac.getZERO()); } /** * Test random rationals. */ public void testRandom() { a = fac.random(10); b = new BigOctonion(a.getR(), a.getI()); c = b.subtract(a); assertEquals("a-b = 0", fac.getZERO(), c); d = new BigOctonion(b.getR(), b.getI()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = fac.random(10); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); d = a.sum(fac.getZERO()); assertEquals("a+0 = a", d, a); d = a.subtract(fac.getZERO()); assertEquals("a-0 = a", d, a); d = a.subtract(a); assertEquals("a-a = 0", d, fac.getZERO()); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(10); //System.out.println("a = " + a); b = a.multiply(a); c = b.divide(a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = a.multiply(fac.getONE()); assertEquals("a*1 = a", d, a); d = a.divide(fac.getONE()); assertEquals("a/1 = a", d, a); a = fac.random(30); b = a.inverse(); c = a.multiply(b); assertTrue("a*1/a = 1", c.isONE()); b = a.abs(); c = b.inverse(); d = b.multiply(c); assertTrue("abs(a)*1/abs(a) = 1", d.isONE()); a = fac.random(30); b = a.norm(); //abs(); //c = b.multiply(b); d = a.multiply(a.conjugate()); assertEquals("norm(a) == a a^", b, d); c = a.abs(); d = c.multiply(c); //assertEquals("norm() == abs()*abs(): ", b, d); BigRational dd = d.or.re.subtract(b.or.re).abs().divide(d.or.re.abs().sum(b.or.re.abs())); //System.out.println("dd = " + dd + ", d = " + d + ", b = " + b); BigRational eps = new BigRational(1,10).power(BigDecimal.DEFAULT_PRECISION-1); assertTrue("abs()*abs() == norm(): " + dd, dd.compareTo(eps) <= 0); b = fac.random(10); c = a.inverse(); d = c.multiply(b); e = a.multiply(d); assertEquals("a*(1/a)*b = b", b, e); d = b.multiply(c); e = d.multiply(a); assertEquals("b*(1/a)*a = b", b, e); c = a.rightDivide(b); d = c.multiply(b); assertEquals("a*(1/b)*b = a", a, d); c = a.leftDivide(b); d = b.multiply(c); assertEquals("b*(1/b)*a = a", a, d); } /** * Test multiplication axioms. */ public void testMultiplicationAxioms() { a = fac.random(20); b = fac.random(20); c = a.multiply(b); d = b.multiply(a); assertTrue("a*b != b*a", !c.equals(d)); c = fac.random(20); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertTrue("a(bc) != (ab)c", !e.equals(d)); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(20); b = fac.random(20); c = fac.random(20); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigQuaternionIntegerTest.java000066400000000000000000000325761445075545500265740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigQuaternionInteger tests with JUnit. * @author Heinz Kredel */ public class BigQuaternionIntegerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigQuaternionIntegerTest object. * @param name String. */ public BigQuaternionIntegerTest(String name) { super(name); } /** * @return suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigQuaternionIntegerTest.class); return suite; } BigQuaternion a, b, c, d, e, f; BigQuaternionRing fac; @Override protected void setUp() { a = b = c = d = e = null; fac = new BigQuaternionRing(true); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); assertTrue("isEntier(0)", a.isEntier()); assertTrue("isEntier(1)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); } /** * Test bitLength. */ public void testBitLength() { a = fac.ZERO; b = fac.ONE; c = fac.random(100); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 12", 12, a.bitLength()); assertEquals("len(1) = 13", 13, b.bitLength()); assertEquals("len(-1) = 13", 13, b.negate().bitLength()); assertTrue("len(random) >= 12", 12 <= c.bitLength()); d = fac.I; assertEquals("len(i) = 13", 13, d.bitLength()); assertEquals("len(-i) = 13", 13, d.negate().bitLength()); d = fac.J; assertEquals("len(j) = 13", 13, d.bitLength()); assertEquals("len(-j) = 13", 13, d.negate().bitLength()); d = fac.K; assertEquals("len(k) = 13", 13, d.bitLength()); assertEquals("len(-k) = 13", 13, d.negate().bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigQuaternionInteger(fac, "6/8"); b = new BigQuaternionInteger(fac, "3/4"); assertEquals("6/8 = 3/4", a, b); assertFalse("isEntier(a)", a.isEntier()); assertFalse("isEntier(b)", b.isEntier()); a = new BigQuaternionInteger(fac, "3/4 i 4/5 j 1/5 k 2/5"); b = new BigQuaternionInteger(fac, "-3/4 i -4/5 j -1/5 k -2/5"); assertEquals("3/4 + i 4/5 + j 1/5 + k 2/5", a, b.negate()); assertFalse("isEntier(a)", a.isEntier()); assertFalse("isEntier(b)", b.isEntier()); String s = "6/1111111111111111111111111111111111111111111"; a = new BigQuaternionInteger(fac, s); String t = a.toString(); assertFalse("isEntier(a)", a.isEntier()); assertEquals("stringConstr = toString", s, t); a = new BigQuaternionInteger(fac, 1); b = new BigQuaternionInteger(fac, -1); c = b.sum(a); assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, fac.ZERO); } /** * Test random rationals. */ public void testRandom() { a = fac.random(50); b = new BigQuaternionInteger(fac, a.getRe(), a.getIm(), a.getJm(), a.getKm()); c = b.subtract(a); assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertEquals("a-b = 0", fac.ZERO, c); d = new BigQuaternionInteger(fac, b); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); assertTrue("isEntier(d)", d.isEntier()); } /** * Test addition. */ public void testAddition() { a = fac.random(10); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); d = a.sum(fac.ZERO); assertEquals("a+0 = a", d, a); d = a.subtract(fac.ZERO); assertEquals("a-0 = a", d, a); d = a.subtract(a); assertEquals("a-a = 0", d, fac.ZERO); assertTrue("isEntier(d)", d.isEntier()); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(10); b = a.multiply(a); c = b.leftDivide(a); BigQuaternionInteger bi = new BigQuaternionInteger(fac, b); d = bi.leftDivide(a); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertTrue("isEntier(d)", d.isEntier()); //if (! d.equals(a)) { // e = a.multiply(d); // System.out.println("e = " + e + ", e==b: " + e.equals(bi)); // e = d.multiply(a); // System.out.println("e = " + e + ", e==b: " + e.equals(bi)); //} assertEquals("a*a/a = a", d, a); // || !d.isZERO()); d = a.multiply(fac.ONE); assertEquals("a*1 = a", d, a); d = a.divide(fac.ONE); assertEquals("a/1 = a", d, a); //a = fac.random(10); //b = a.inverse(); // not entier //c = a.multiply(b); //assertTrue("a*1/a = 1", c.isONE()); //c = b.multiply(a); //assertTrue("1/a*a = 1", c.isONE()); //assertTrue("isEntier(a)", a.isEntier()); //assertTrue("isEntier(b)", b.isEntier()); //assertTrue("isEntier(c)", c.isEntier()); //b = a.abs(); //c = a.norm(); //assertEquals("abs() == norm(): " + b, b, c); // wrong //c = b.inverse(); // not entier //d = b.multiply(c); //assertTrue("abs(a)*1/abs(a) = 1", d.isONE()); //assertTrue("isEntier(a)", a.isEntier()); b = a.norm(); c = a.conjugate(); d = a.multiply(c); assertTrue("isEntier(a)", a.isEntier()); assertEquals("abs(a)^2 = a a^", b, d); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertTrue("isEntier(d)", d.isEntier()); } /** * Test multiplication axioms. */ public void testMultiplicationAxioms() { a = fac.random(10); b = fac.random(10); c = a.multiply(b); d = b.multiply(a); if (c.compareTo(d) != 0) { assertFalse("a*b != b*a: " + c + ", " + d, c.equals(d)); } assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertTrue("isEntier(d)", d.isEntier()); c = fac.random(10); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertTrue("a(bc) = (ab)c", e.equals(d)); assertTrue("isEntier(c)", c.isEntier()); assertTrue("isEntier(d)", d.isEntier()); assertTrue("isEntier(e)", e.isEntier()); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(20); b = fac.random(20); c = fac.random(20); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); assertTrue("isEntier(a)", a.isEntier()); assertTrue("isEntier(b)", b.isEntier()); assertTrue("isEntier(c)", c.isEntier()); assertTrue("isEntier(d)", d.isEntier()); assertTrue("isEntier(e)", e.isEntier()); } /** * Test divide entier elements. */ public void testDivideEntier() { a = new BigQuaternionInteger(fac, "3 i 4 j 5 k 2"); assertTrue("a is entier", a.isEntier()); //System.out.println("a = " + a); b = new BigQuaternionInteger(fac, "-3/2 i -5/2 j -1/2 k -7/2"); assertTrue("b is entier", b.isEntier()); //System.out.println("b = " + b); c = a.multiply(a); //System.out.println("c = " + c); assertTrue("c is entier", c.isEntier()); c = b.multiply(b); //System.out.println("c = " + c); assertTrue("c is entier", c.isEntier()); c = a.multiply(b); //System.out.println("c = " + c); assertTrue("c is entier", c.isEntier()); c = b.multiply(a); //System.out.println("c = " + c); assertTrue("c is entier", c.isEntier()); d = a.norm(); //System.out.println("norm(a) = " + d); assertTrue("d is entier", d.isEntier()); d = b.norm(); //System.out.println("norm(b) = " + d); assertTrue("d is entier", d.isEntier()); BigQuaternionInteger ai, bi; ai = new BigQuaternionInteger(fac, a); bi = new BigQuaternionInteger(fac, b); // quotient and remainder //System.out.println("ai = " + ai.toScript()); //System.out.println("bi = " + bi.toScript()); BigQuaternion[] qr = ai.leftQuotientAndRemainder(bi); c = qr[0]; d = qr[1]; //System.out.println("q = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("c is entier", c.isEntier()); assertTrue("d is entier", d.isEntier()); //System.out.println("norm(b) = " + b.norm()); //System.out.println("norm(r) = " + d.norm()); assertEquals("a == b * q + r: ", a, b.multiply(c).sum(d)); assertTrue("norm(r) < norm(b): ", d.norm().re.compareTo(b.norm().re) < 0); qr = ai.rightQuotientAndRemainder(bi); c = qr[0]; d = qr[1]; //System.out.println("q = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("c is entier", c.isEntier()); assertTrue("d is entier", d.isEntier()); //System.out.println("norm(b) = " + b.norm()); //System.out.println("norm(r) = " + d.norm()); assertEquals("a == q * b + r: ", a, c.multiply(b).sum(d)); assertTrue("norm(r) < norm(b): ", d.norm().re.compareTo(b.norm().re) < 0); } /** * Test gcd entier elements. */ public void testGcdEntier() { a = fac.random(10); b = fac.random(10); BigQuaternionInteger ai, bi; ai = new BigQuaternionInteger(fac, a); bi = new BigQuaternionInteger(fac, b); BigQuaternion g = ai.leftGcd(bi); //System.out.println("g = " + g.toScript()); //System.out.println("norm(g) = " + g.norm()); assertTrue("g is entier", g.isEntier()); BigQuaternion r = ai.leftQuotientAndRemainder(g)[1]; //System.out.println("r = " + r.toScript()); assertTrue("r == 0: ", r.isZERO()); r = bi.leftQuotientAndRemainder(g)[1]; //System.out.println("r = " + r.toScript()); assertTrue("r == 0: " + r, r.isZERO()); BigQuaternion h = ai.rightGcd(bi); //System.out.println("h = " + h.toScript()); //System.out.println("norm(h) = " + h.norm()); assertTrue("h is entier", h.isEntier()); r = ai.rightQuotientAndRemainder(h)[1]; //System.out.println("r = " + r.toScript()); assertTrue("r == 0: ", r.isZERO()); r = bi.rightQuotientAndRemainder(h)[1]; //System.out.println("r = " + r.toScript()); assertTrue("r == 0: ", r.isZERO()); // round to entier and factor norm a = fac.random(20).roundToLipschitzian(); //a = fac.random(20).roundToHurwitzian(); //System.out.println("a = " + a.toScript()); b = a.norm(); //System.out.println("b = " + b.toScript()); java.math.BigInteger pp = b.re.floor(); //System.out.println("pp = " + pp); long pl = pp.longValue(); SortedMap P = PrimeInteger.factors(pl); //System.out.println("P = " + P); for (Long p : P.keySet()) { c = new BigQuaternion(fac, new BigRational(p)); //System.out.println("c = " + c); d = a.leftGcd(c); //System.out.println("d = " + d.toScript()); e = d.norm(); //System.out.println("e = " + e); assertTrue("norm(gcd) == c: " + c + " : " + e, c.equals(e) || c.equals(e.power(2)) || c.power(2).equals(e)); } } /** * Test random integers for being prime. */ public void testPrime() { int n = 0; for (int i = 0; i < 10; i++) { BigQuaternionInteger a = (BigQuaternionInteger) fac.random(10+i); assertTrue("isEntier(a)", a.isEntier()); boolean p = a.isPrime(); //System.out.println(p + " = " + a); assertTrue("isPrime(a)", p || true); if (p) n++; } assertTrue("#isPrime(a)", n >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigQuaternionTest.java000066400000000000000000000167661445075545500252610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigQuaternion tests with JUnit. * @author Heinz Kredel */ public class BigQuaternionTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigQuaternionTest object. * @param name String. */ public BigQuaternionTest(String name) { super(name); } /** * @return suite. */ public static Test suite() { TestSuite suite = new TestSuite(BigQuaternionTest.class); return suite; } BigQuaternion a, b, c, d, e, f; BigQuaternionRing fac; @Override protected void setUp() { a = b = c = d = e = null; fac = new BigQuaternionRing(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test static initialization and constants. */ public void testConstants() { a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); a = fac.getZERO(); b = fac.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); } /** * Test bitLength. */ public void testBitLength() { a = fac.getZERO(); b = fac.getONE(); c = fac.random(100); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 12", 12, a.bitLength()); assertEquals("len(1) = 13", 13, b.bitLength()); assertEquals("len(-1) = 13", 13, b.negate().bitLength()); assertTrue("len(random) >= 12", 12 <= c.bitLength()); d = fac.I; assertEquals("len(i) = 13", 13, d.bitLength()); assertEquals("len(-i) = 13", 13, d.negate().bitLength()); d = fac.J; assertEquals("len(j) = 13", 13, d.bitLength()); assertEquals("len(-j) = 13", 13, d.negate().bitLength()); d = fac.K; assertEquals("len(k) = 13", 13, d.bitLength()); assertEquals("len(-k) = 13", 13, d.negate().bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigQuaternion(fac, "6/8"); b = new BigQuaternion(fac, "3/4"); assertEquals("6/8 = 3/4", a, b); a = new BigQuaternion(fac, "3/4 i 4/5 j 1/5 k 2/5"); b = new BigQuaternion(fac, "-3/4 i -4/5 j -1/5 k -2/5"); assertEquals("3/4 + i 4/5 + j 1/5 + k 2/5", a, b.negate()); String s = "6/1111111111111111111111111111111111111111111"; a = new BigQuaternion(fac, s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); a = new BigQuaternion(fac, 1); b = new BigQuaternion(fac, -1); c = b.sum(a); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, fac.getZERO()); } /** * Test random rationals. */ public void testRandom() { a = fac.random(50); b = new BigQuaternion(fac, a.getRe(), a.getIm(), a.getJm(), a.getKm()); c = b.subtract(a); assertEquals("a-b = 0", fac.getZERO(), c); d = new BigQuaternion(fac, b.getRe(), b.getIm(), b.getJm(), b.getKm()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = fac.random(10); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); d = a.sum(fac.getZERO()); assertEquals("a+0 = a", d, a); d = a.subtract(fac.getZERO()); assertEquals("a-0 = a", d, a); d = a.subtract(a); assertEquals("a-a = 0", d, fac.getZERO()); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(10); b = a.multiply(a); c = b.divide(a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = a.multiply(fac.getONE()); assertEquals("a*1 = a", d, a); d = a.divide(fac.getONE()); assertEquals("a/1 = a", d, a); a = fac.random(10); b = a.inverse(); c = a.multiply(b); assertTrue("a*1/a = 1", c.isONE()); c = b.multiply(a); assertTrue("1/a*a = 1", c.isONE()); b = a.abs(); c = b.inverse(); d = b.multiply(c); assertTrue("abs(a)*1/abs(a) = 1", d.isONE()); b = a.norm(); d = a.multiply(a.conjugate()); assertEquals("norm() = a a^", b, d); //b = a.norm(); d = a.abs(); e = d.multiply(d); BigRational dd = e.re.subtract(b.re).abs().divide(e.re.abs().sum(b.re.abs())); //System.out.println("dd = " + dd + ", d = " + d + ", e = " + e); BigRational eps = new BigRational(1,10).power(BigDecimal.DEFAULT_PRECISION-1); assertTrue("abs()*abs() == norm(): " + dd, dd.compareTo(eps) <= 0); b = fac.random(10); c = a.inverse(); d = c.multiply(b); e = a.multiply(d); assertEquals("a*(1/a)*b = b", b, e); d = b.multiply(c); e = d.multiply(a); assertEquals("b*(1/a)*a = b", b, e); } /** * Test multiplication axioms. */ public void testMultiplicationAxioms() { a = fac.random(10); b = fac.random(10); c = a.multiply(b); d = b.multiply(a); assertFalse("a*b != b*a", c.equals(d)); c = fac.random(10); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertTrue("a(bc) = (ab)c", e.equals(d)); } /** * Test division. */ public void testDivision() { assertTrue("fac is field::", fac.isField()); a = fac.random(10); b = fac.random(10); if (b.isZERO()) { b = fac.getONE(); } //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.remainder(b); assertTrue("rem(a,b) == 0:", c.isZERO()); c = a.leftRemainder(b); assertTrue("left rem(a,b) == 0:", c.isZERO()); c = a.rightRemainder(b); assertTrue("right rem(a,b) == 0:", c.isZERO()); c = a.divide(b); //System.out.println("c = " + c); d = c.multiply(b); //System.out.println("d = " + d); assertEquals("div(a,b)*b == a:", d, a); c = a.leftDivide(b); //System.out.println("c = " + c); d = c.multiplyLeft(b); //System.out.println("d = " + d); //d = b.multiply(c); //System.out.println("d = " + d); assertEquals("left div(a,b)*b == a:", d, a); c = a.rightDivide(b); //System.out.println("c = " + c); d = c.multiply(b); //System.out.println("d = " + d); //d = b.multiply(c); //System.out.println("d = " + d); assertEquals("right div(a,b)*b == a:", d, a); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(20); b = fac.random(20); c = fac.random(20); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } } java-algebra-system-2.7.200/trc/edu/jas/arith/BigRationalTest.java000066400000000000000000000177401445075545500246760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational tests with JUnit. * @author Heinz Kredel */ public class BigRationalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a BigRationalTest object. * @param name String. */ public BigRationalTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(BigRationalTest.class); return suite; } BigRational a, b, c, d, e; @Override protected void setUp() { a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; } /** * Test static initialization and constants. */ public void testConstants() { a = BigRational.ZERO; b = BigRational.ONE; c = BigRational.RNDIF(b, b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); assertEquals("1-1 = 0", c, a); } /** * Test bitLength. */ public void testBitLength() { a = BigRational.ZERO; b = BigRational.ONE; c = BigRational.RNDIF(b, b); d = BigRational.RNRAND(500); assertEquals("len(0) = 3", 3, a.bitLength()); assertEquals("len(1) = 4", 4, b.bitLength()); assertEquals("len(-1) = 4", 4, b.negate().bitLength()); assertTrue("len(rnd) >= 1", 1 <= d.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { a = new BigRational("6/8"); b = new BigRational("3/4"); assertEquals("6/8 = 3/4", a, b); a = new BigRational("3/-4"); b = new BigRational("-3/4"); assertEquals("3/-4 = -3/4", a, b); String s = "6/1111111111111111111111111111111111111111111"; a = new BigRational(s); String t = a.toString(); assertEquals("stringConstr = toString", s, t); a = new BigRational(1); b = new BigRational(-1); c = BigRational.RNSUM(b, a); assertTrue("1 = 1", a.isONE()); assertEquals("1+(-1) = 0", c, BigRational.ZERO); s = "1.500000000"; a = new BigRational(s); b = new BigRational("3/2"); assertEquals("decimalConstr = b ", a, b); s = "-1.500000000"; a = new BigRational(s); b = new BigRational("-3/2"); assertEquals("decimalConstr = b ", a, b); s = "0.750000000"; a = new BigRational(s); b = new BigRational("3/4"); assertEquals("decimalConstr = b ", a, b); s = "0.333333333"; a = new BigRational(s); t = a.toString(9); assertEquals("decimalConstr = b " + t, s, t); s = "-0.000033333"; a = new BigRational(s); t = a.toString(9); assertEquals("decimalConstr = b " + t, s, t); //System.out.println("a = " + a); } /** * Test random rationals. */ public void testRandom() { a = BigRational.RNRAND(500); b = new BigRational("" + a); c = BigRational.RNDIF(b, a); assertEquals("a-b = 0", c, BigRational.ZERO); d = new BigRational(b.numerator(), b.denominator()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { a = BigRational.RNRAND(100); b = BigRational.RNSUM(a, a); c = BigRational.RNDIF(b, a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, BigRational.RNCOMP(c, a)); d = BigRational.RNSUM(a, BigRational.ZERO); assertEquals("a+0 = a", d, a); d = BigRational.RNDIF(a, BigRational.ZERO); assertEquals("a-0 = a", d, a); d = BigRational.RNDIF(a, a); assertEquals("a-a = 0", d, BigRational.ZERO); } /** * Test multiplication. */ public void testMultiplication() { a = BigRational.RNRAND(100); b = BigRational.RNPROD(a, a); c = BigRational.RNQ(b, a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, BigRational.RNCOMP(c, a)); d = BigRational.RNPROD(a, BigRational.ONE); assertEquals("a*1 = a", d, a); d = BigRational.RNQ(a, BigRational.ONE); assertEquals("a/1 = a", d, a); a = BigRational.RNRAND(100); b = BigRational.RNINV(a); c = BigRational.RNPROD(a, b); assertTrue("a*1/a = 1", c.isONE()); } /** * Test distributive law. */ public void testDistributive() { BigRational fac = new BigRational(); a = fac.random(500); b = fac.random(500); c = fac.random(500); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test iterator. */ public void testIterator() { int t = 0; BigRational bi = new BigRational(); bi.setAllIterator(); BigRational j = null, elem = null; for (BigRational i : bi) { t++; //System.out.println("i = " + i); if (t >= 20) { j = i; break; } } assertFalse("j == null ", j == null); elem = new BigRational(-2, 3); assertTrue("j == 10 ", j.equals(elem)); } /** * Test non-negative iterator. */ public void testNNIterator() { int t = 0; BigRational bi = new BigRational(); bi.setNonNegativeIterator(); BigRational j = null, elem = null; Iterator iter = bi.iterator(); while (iter.hasNext()) { BigRational i = iter.next(); t++; //System.out.println("i = " + i); if (t >= 20) { j = i; break; } } assertFalse("j == null ", j == null); elem = new BigRational(4, 3); assertTrue("j == 10 ", j.equals(elem)); } /** * Test non-negative unique iterator. */ public void testUniqueNNIterator() { int t = 0; BigRational bi = new BigRational(); bi.setNonNegativeIterator(); //bi.setAllIterator(); BigRational j = null, elem = null; Iterator iter = bi.uniqueIterator(); while (iter.hasNext()) { BigRational i = iter.next(); t++; //System.out.println("i = " + i); if (t >= 20) { j = i; break; } } assertFalse("j == null ", j == null); elem = new BigRational(5, 3); assertTrue("j == 10 ", j.equals(elem)); } /** * Test doubleValue. */ public void testDoubleValue() { BigRational fac = new BigRational(); //a = fac.getONE(); //a = fac.getZERO(); a = fac.random(5000); //System.out.println("a = " + a.toString()); //System.out.println("a = " + a.toString(16+2)); double d = a.doubleValue(); //System.out.println("d = " + d + ", a = " + a.toString(16)); String as = a.toString(16); String ds = Double.toString(d); if (ds.endsWith(".0")) { ds = ds.substring(0, ds.length() - 2); } if (ds.indexOf(".") >= 0) { while (ds.endsWith("0")) { ds = ds.substring(0, ds.length() - 1); } } if (as.indexOf(".") >= 0) { while (as.endsWith("0")) { as = as.substring(0, as.length() - 1); } } int l = Math.min(as.length(), ds.length()); as = as.substring(0, l - 1); ds = ds.substring(0, l - 1); assertEquals("a = decimal(d): " + d, as, ds); } } java-algebra-system-2.7.200/trc/edu/jas/arith/ModIntTest.java000066400000000000000000000273601445075545500236740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.kern.PrettyPrint; import edu.jas.structure.NotInvertibleException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ModInt tests with JUnit. * @author Heinz Kredel */ public class ModIntTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModIntTest object. * @param name String */ public ModIntTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ModIntTest.class); return suite; } ModIntRing zm, z1, z2; ModInt a, b, c, d, e; @Override protected void setUp() { zm = z1 = z2 = null; a = b = c = d = e = null; } @Override protected void tearDown() { zm = z1 = z2 = null; a = b = c = d = e = null; } protected static java.math.BigInteger getPrime1() { int prime = 2; //2^15-135; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 15; i++) { prime *= 2; } prime -= 135; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { int prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } prime -= 35; //System.out.println("p2 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime3() { int prime = 37; //System.out.println("p2 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test static initialization and constants. */ public void testConstants() { zm = new ModIntRing(5); d = new ModInt(zm, 11); a = zm.getZERO(); b = zm.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); } /** * Test bitLength. */ public void testBitLength() { zm = new ModIntRing(163); a = zm.getZERO(); b = zm.getONE(); c = zm.random(30); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 1", 1L, a.bitLength()); assertEquals("len(1) = 2", 2, b.bitLength()); assertEquals("len(-1) = len(mod)", BigInteger.bitLength(zm.modul), b.negate().bitLength()); assertTrue("len(random) >= 1", 1 <= c.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { zm = new ModIntRing("5"); a = new ModInt(zm, "64"); b = new ModInt(zm, "34"); assertEquals("64(5) = 34(5)", a, b); zm = new ModIntRing("7"); a = new ModInt(zm, "-4"); b = new ModInt(zm, "3"); assertEquals("-4(7) = 3(7)", a, b); String s = "61111111111111111"; zm = new ModIntRing("10"); try { a = new ModInt(zm, s); fail("s to large"); } catch (NumberFormatException e) { // pass } s = "611111111"; a = new ModInt(zm, s); String t = a.toString(); if (PrettyPrint.isTrue()) { String st = "1"; assertEquals("stringConstr = toString", st, t); } else { String st = "1 mod(10)"; assertEquals("stringConstr = toString", st, t); } zm = new ModIntRing(7); a = new ModInt(zm, 1); b = new ModInt(zm, -1); c = b.sum(a); assertTrue("1 = 1", a.isONE()); assertTrue("1 = 1", b.isUnit()); assertEquals("1+(-1) = 0", c, zm.getZERO()); zm = new ModIntRing(5); a = new ModInt(zm, 3); b = new ModInt(zm, 0); c = zm.parse(" 13 "); assertEquals("3(5) = 3(5)", a, c); StringReader sr = new StringReader(" 13\n w "); c = zm.parse(sr); assertEquals("3(5) = 3(5)", a, c); //System.out.println("c = " + c); } /** * Test random modular integers. */ public void testRandom() { zm = new ModIntRing(19); a = zm.random(500); b = a.copy(); c = b.subtract(a); assertEquals("a-b = 0", c, zm.getZERO()); d = new ModInt(new ModIntRing(b.getModul()), b.getVal()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. * */ public void testAddition() { zm = new ModIntRing(19); a = zm.random(100); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); d = a.sum(zm.getZERO()); assertEquals("a+0 = a", d, a); d = a.subtract(zm.getZERO()); assertEquals("a-0 = a", d, a); d = a.subtract(a); assertEquals("a-a = 0", d, zm.getZERO()); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { zm = new ModIntRing(5); d = new ModInt(zm, 11); a = zm.random(100); if (a.isZERO()) { a = d; } b = a.multiply(a); c = b.divide(a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = a.multiply(zm.getONE()); assertEquals("a*1 = a", d, a); d = a.divide(zm.getONE()); assertEquals("a/1 = a", d, a); a = zm.random(100); if (a.isZERO()) { a = d; } b = a.inverse(); c = a.multiply(b); assertTrue("a*1/a = 1", c.isONE()); try { a = zm.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { //ok } zm = new ModIntRing(5 * 3); a = new ModInt(zm, 5); assertFalse("5 !unit mod 15", a.isUnit()); try { b = a.inverse(); fail("5 invertible"); } catch (ModularNotInvertibleException expected) { //ok //expected.printStackTrace(); assertTrue("f = 15 ", expected.f.equals(new BigInteger(15))); assertTrue("f1 = 5 ", expected.f1.equals(new BigInteger(5))); assertTrue("f2 = 3 ", expected.f2.equals(new BigInteger(3))); assertTrue("f = f1*f2 ", expected.f.equals(expected.f1.multiply(expected.f2))); } catch (NotInvertibleException e) { //e.printStackTrace(); fail("wrong exception " + e); } } /** * Test chinese remainder. */ public void testChineseRemainder() { zm = new ModIntRing(19 * 13); a = zm.random(9); //System.out.println("a = " + a); z1 = new ModIntRing(19); b = new ModInt(z1, a.getVal()); //System.out.println("b = " + b); z2 = new ModIntRing(13); c = new ModInt(z2, a.getVal()); //System.out.println("c = " + c); d = new ModInt(z2, 19); d = d.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod 19,a mod 13) = a", a, e); java.math.BigInteger p1 = getPrime2(); try { z1 = new ModIntRing(p1); fail("p1 too large"); } catch (IllegalArgumentException e) { //pass } p1 = getPrime3(); java.math.BigInteger p2 = new java.math.BigInteger("19"); java.math.BigInteger p1p2 = p1.multiply(p2); //System.out.println("p1p2 = " + p1p2); //System.out.println("prime p1 ? = " + p1.isProbablePrime(66)); //System.out.println("prime p2 ? = " + p2.isProbablePrime(33)); //System.out.println("prime p1p1 ? = " + p1p2.isProbablePrime(3)); zm = new ModIntRing(p1p2); z1 = new ModIntRing(p1); z2 = new ModIntRing(p2); for (int i = 0; i < 5; i++) { a = zm.random((59 + 29) / 2); //60+30 ); //System.out.println("a = " + a); b = new ModInt(z1, a.getVal()); //System.out.println("b = " + b); c = new ModInt(z2, a.getVal()); //System.out.println("c = " + c); ModInt di = new ModInt(z2, p1); d = di.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod p1,a mod p2) = a ", a, e); } } /** * Test chinese remainder of lists. */ public void testChineseRemainderLists() { zm = new ModIntRing(19 * 13); z1 = new ModIntRing(19); z2 = new ModIntRing(13); List L1 = new ArrayList(); List L2 = new ArrayList(); List L; for (int i = 0; i < 7; i++) { a = zm.random(9); //System.out.println("a = " + a); b = new ModInt(z1, a.getVal()); //System.out.println("b = " + b); c = new ModInt(z2, a.getVal()); //System.out.println("c = " + c); L1.add(b); L2.add(c); } //System.out.println("L1 = " + L1); //System.out.println("L2 = " + L2); L = ModIntRing.chineseRemainder(z1.getONE(), z2.getONE(), L1, L2); //System.out.println("L = " + L); assertEquals("19 * 13) = a.modul: ", zm, L.get(0).ring); for (ModInt d : L) { b = new ModInt(z1, d.getVal()); //System.out.println("b = " + b); c = new ModInt(z2, d.getVal()); //System.out.println("c = " + c); assertTrue("cra(a mod 19, a mod 13) = a: ", L1.contains(b)); assertTrue("cra(a mod 19, a mod 13) = a: ", L2.contains(c)); } } /** * Test timing ModInt to ModInteger. */ public void testTiming() { zm = new ModIntRing(getPrime1()); a = zm.random(9); //System.out.println("a = " + a); b = zm.random(9); //System.out.println("b = " + b); c = zm.getONE(); //System.out.println("c = " + c); ModIntegerRing ZM = new ModIntegerRing(zm.modul); ModInteger A = new ModInteger(ZM, a.getVal()); ModInteger B = new ModInteger(ZM, b.getVal()); ModInteger C = ZM.getONE(); int run = 1000; //000; long t = System.currentTimeMillis(); for (int i = 0; i < run; i++) { if (c.isZERO()) { c = zm.getONE(); } c = a.sum(b.divide(c)); } t = System.currentTimeMillis() - t; //System.out.println("long time = " + t); ModInteger D = new ModInteger(ZM, c.getVal()); t = System.currentTimeMillis(); for (int i = 0; i < run; i++) { if (C.isZERO()) { C = ZM.getONE(); } C = A.sum(B.divide(C)); } t = System.currentTimeMillis() - t; //System.out.println("BigInteger time = " + t); assertEquals("C == D ", C, D); } /** * Test iterator. */ public void testIterator() { int m = 5 * 2; zm = new ModIntRing(m); ModInt j = null; for (ModInt i : zm) { //System.out.println("i = " + i); j = i; } ModInt end = new ModInt(zm, m - 1); assertTrue("j == m-1 ", j.equals(end)); } } java-algebra-system-2.7.200/trc/edu/jas/arith/ModIntegerTest.java000066400000000000000000000250751445075545500245400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import edu.jas.kern.PrettyPrint; import edu.jas.structure.NotInvertibleException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ModInteger tests with JUnit. * @author Heinz Kredel */ public class ModIntegerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModIntegerTest object. * @param name String */ public ModIntegerTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ModIntegerTest.class); return suite; } ModIntegerRing zm, z1, z2; ModInteger a, b, c, d, e; @Override protected void setUp() { zm = z1 = z2 = null; a = b = c = d = e = null; } @Override protected void tearDown() { zm = z1 = z2 = null; a = b = c = d = e = null; } protected static java.math.BigInteger getPrime1() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //prime = 37; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } prime -= 35; //prime = 19; //System.out.println("p2 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test static initialization and constants. */ public void testConstants() { zm = new ModIntegerRing(5); d = new ModInteger(zm, 11); a = zm.getZERO(); b = zm.getONE(); c = ModInteger.MIDIF(b, b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); } /** * Test bitLength. */ public void testBitLength() { zm = new ModIntegerRing(163); a = zm.getZERO(); b = zm.getONE(); c = zm.random(30); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 1", 1, a.bitLength()); assertEquals("len(1) = 2", 2, b.bitLength()); assertEquals("len(-1) = len(mod)", zm.modul.bitLength() + 1, b.negate().bitLength()); assertTrue("len(random) >= 1", 1 <= c.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { zm = new ModIntegerRing("5"); a = new ModInteger(zm, "64"); b = new ModInteger(zm, "34"); assertEquals("64(5) = 34(5)", a, b); zm = new ModIntegerRing("7"); a = new ModInteger(zm, "-4"); b = new ModInteger(zm, "3"); assertEquals("-4(7) = 3(7)", a, b); String s = "61111111111111111111111111111111111111111111"; zm = new ModIntegerRing("10"); a = new ModInteger(zm, s); String t = a.toString(); if (PrettyPrint.isTrue()) { String st = "1"; assertEquals("stringConstr = toString", st, t); } else { String st = "1 mod(10)"; assertEquals("stringConstr = toString", st, t); } zm = new ModIntegerRing(7); a = new ModInteger(zm, 1); b = new ModInteger(zm, -1); c = ModInteger.MISUM(b, a); assertTrue("1 = 1", a.isONE()); assertTrue("1 = 1", b.isUnit()); assertEquals("1+(-1) = 0", c, zm.getZERO()); zm = new ModIntegerRing(5); a = new ModInteger(zm, 3); b = new ModInteger(zm, 0); c = zm.parse(" 13 "); assertEquals("3(5) = 3(5)", a, c); StringReader sr = new StringReader(" 13\n w "); c = zm.parse(sr); assertEquals("3(5) = 3(5)", a, c); //System.out.println("c = " + c); } /** * Test random modular integers. */ public void testRandom() { zm = new ModIntegerRing(19); a = zm.random(500); b = a.copy(); c = ModInteger.MIDIF(b, a); assertEquals("a-b = 0", c, zm.getZERO()); d = new ModInteger(new ModIntegerRing(b.getModul()), b.getVal()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. */ public void testAddition() { zm = new ModIntegerRing(19); a = zm.random(100); b = ModInteger.MISUM(a, a); c = ModInteger.MIDIF(b, a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, ModInteger.MICOMP(c, a)); d = ModInteger.MISUM(a, zm.getZERO()); assertEquals("a+0 = a", d, a); d = ModInteger.MIDIF(a, zm.getZERO()); assertEquals("a-0 = a", d, a); d = ModInteger.MIDIF(a, a); assertEquals("a-a = 0", d, zm.getZERO()); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { zm = new ModIntegerRing(5); d = new ModInteger(zm, 11); a = zm.random(100); if (a.isZERO()) { a = d; } b = ModInteger.MIPROD(a, a); c = ModInteger.MIQ(b, a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = ModInteger.MIPROD(a, zm.getONE()); assertEquals("a*1 = a", d, a); d = ModInteger.MIQ(a, zm.getONE()); assertEquals("a/1 = a", d, a); a = zm.random(100); if (a.isZERO()) { a = d; } b = ModInteger.MIINV(a); c = ModInteger.MIPROD(a, b); assertTrue("a*1/a = 1", c.isONE()); try { a = zm.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { // ok } zm = new ModIntegerRing(5 * 3); a = new ModInteger(zm, 5); assertFalse("5 !unit mod 15", a.isUnit()); try { b = a.inverse(); fail("5 invertible"); } catch (ModularNotInvertibleException expected) { //ok //expected.printStackTrace(); assertTrue("f = 15 ", expected.f.equals(new BigInteger(15))); assertTrue("f1 = 5 ", expected.f1.equals(new BigInteger(5))); assertTrue("f2 = 3 ", expected.f2.equals(new BigInteger(3))); assertTrue("f = f1*f2 ", expected.f.equals(expected.f1.multiply(expected.f2))); } catch (NotInvertibleException e) { //e.printStackTrace(); fail("wrong exception " + e); } } /** * Test chinese remainder. */ public void testChineseRemainder() { zm = new ModIntegerRing(19 * 13); a = zm.random(9); //System.out.println("a = " + a); z1 = new ModIntegerRing(19); b = new ModInteger(z1, a.getVal().longValue()); //System.out.println("b = " + b); z2 = new ModIntegerRing(13); c = new ModInteger(z2, a.getVal().longValue()); //System.out.println("c = " + c); d = new ModInteger(z2, 19); d = d.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod 19,a mod 13) = a", a, e); java.math.BigInteger p1 = getPrime1(); java.math.BigInteger p2 = getPrime2(); java.math.BigInteger p1p2 = p1.multiply(p2); //System.out.println("p1p2 = " + p1p2); //System.out.println("prime p1 ? = " + p1.isProbablePrime(66)); //System.out.println("prime p2 ? = " + p2.isProbablePrime(33)); //System.out.println("prime p1p1 ? = " + p1p2.isProbablePrime(3)); zm = new ModIntegerRing(p1p2); z1 = new ModIntegerRing(p1); z2 = new ModIntegerRing(p2); for (int i = 0; i < 5; i++) { a = zm.random((59 + 29) / 2); //60+30 ); //System.out.println("a = " + a); b = new ModInteger(z1, a.getVal()); //System.out.println("b = " + b); c = new ModInteger(z2, a.getVal()); //System.out.println("c = " + c); ModInteger di = new ModInteger(z2, p1); d = di.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod p1,a mod p2) = a", a, e); } } /** * Test chinese remainder of lists. */ public void testChineseRemainderLists() { java.math.BigInteger p1 = getPrime1(); java.math.BigInteger p2 = getPrime2(); java.math.BigInteger p1p2 = p1.multiply(p2); zm = new ModIntegerRing(p1p2); z1 = new ModIntegerRing(p1); z2 = new ModIntegerRing(p2); List L1 = new ArrayList(); List L2 = new ArrayList(); List L; for (int i = 0; i < 5; i++) { a = zm.random(17); //System.out.println("a = " + a); b = new ModInteger(z1, a.getVal()); //System.out.println("b = " + b); c = new ModInteger(z2, a.getVal()); //System.out.println("c = " + c); L1.add(b); L2.add(c); } //System.out.println("L1 = " + L1); //System.out.println("L2 = " + L2); L = ModIntegerRing.chineseRemainder(z1.getONE(), z2.getONE(), L1, L2); //System.out.println("L = " + L); assertEquals("p1 * p2) = a.modul: ", zm, L.get(0).ring); for (ModInteger d : L) { b = new ModInteger(z1, d.getVal()); //System.out.println("b = " + b); c = new ModInteger(z2, d.getVal()); //System.out.println("c = " + c); assertTrue("cra(a mod p1, a mod p2) = a: ", L1.contains(b)); assertTrue("cra(a mod p1, a mod p2) = a: ", L2.contains(c)); } } /** * Test iterator. */ public void testIterator() { int m = 5 * 2; zm = new ModIntegerRing(m); ModInteger j = null; for (ModInteger i : zm) { //System.out.println("i = " + i); j = i; } ModInteger end = new ModInteger(zm, m - 1); assertTrue("j == m-1 ", j.equals(end)); } } java-algebra-system-2.7.200/trc/edu/jas/arith/ModLongTest.java000066400000000000000000000277451445075545500240500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.kern.PrettyPrint; import edu.jas.structure.NotInvertibleException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ModLong tests with JUnit. * @author Heinz Kredel */ public class ModLongTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModLongTest object. * @param name String */ public ModLongTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ModLongTest.class); return suite; } ModLongRing zm, z1, z2; ModLong a, b, c, d, e; @Override protected void setUp() { zm = z1 = z2 = null; a = b = c = d = e = null; } @Override protected void tearDown() { zm = z1 = z2 = null; a = b = c = d = e = null; } protected static java.math.BigInteger getPrime1() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } //prime -= 93; prime -= 35; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //System.out.println("p2 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime3() { int prime = 2; //2^15-135; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 15; i++) { prime *= 2; } prime -= 135; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime4() { int prime = 37; //System.out.println("p2 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test static initialization and constants. */ public void testConstants() { zm = new ModLongRing(5); d = new ModLong(zm, 11); a = zm.getZERO(); b = zm.getONE(); c = b.subtract(b); assertEquals("1-1 = 0", c, a); assertTrue("1-1 = 0", c.isZERO()); assertTrue("1 = 1", b.isONE()); } /** * Test bitLength. */ public void testBitLength() { zm = new ModLongRing(163); a = zm.getZERO(); b = zm.getONE(); c = zm.random(30); //System.out.println("c = " + c); //System.out.println("len(c) = " + c.bitLength()); assertEquals("len(0) = 1", 1L, a.bitLength()); assertEquals("len(1) = 2", 2, b.bitLength()); assertEquals("len(-1) = len(mod)", BigInteger.bitLength(zm.modul), b.negate().bitLength()); assertTrue("len(random) >= 1", 1 <= c.bitLength()); } /** * Test constructor and toString. */ public void testConstructor() { zm = new ModLongRing("5"); a = new ModLong(zm, "64"); b = new ModLong(zm, "34"); assertEquals("64(5) = 34(5)", a, b); zm = new ModLongRing("7"); a = new ModLong(zm, "-4"); b = new ModLong(zm, "3"); assertEquals("-4(7) = 3(7)", a, b); String s = "61111111111111111"; zm = new ModLongRing("10"); a = new ModLong(zm, s); String t = a.toString(); if (PrettyPrint.isTrue()) { String st = "1"; assertEquals("stringConstr = toString", st, t); } else { String st = "1 mod(10)"; assertEquals("stringConstr = toString", st, t); } zm = new ModLongRing(7); a = new ModLong(zm, 1); b = new ModLong(zm, -1); c = b.sum(a); assertTrue("1 = 1", a.isONE()); assertTrue("1 = 1", b.isUnit()); assertEquals("1+(-1) = 0", c, zm.getZERO()); zm = new ModLongRing(5); a = new ModLong(zm, 3); b = new ModLong(zm, 0); c = zm.parse(" 13 "); assertEquals("3(5) = 3(5)", a, c); StringReader sr = new StringReader(" 13\n w "); c = zm.parse(sr); assertEquals("3(5) = 3(5)", a, c); //System.out.println("c = " + c); } /** * Test random modular integers. */ public void testRandom() { zm = new ModLongRing(19); a = zm.random(500); b = a.copy(); c = b.subtract(a); assertEquals("a-b = 0", c, zm.getZERO()); d = new ModLong(new ModLongRing(b.getModul()), b.getVal()); assertEquals("sign(a-a) = 0", 0, b.compareTo(d)); } /** * Test addition. * */ public void testAddition() { zm = new ModLongRing(19); a = zm.random(100); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertEquals("a+a-a = a", 0, c.compareTo(a)); d = a.sum(zm.getZERO()); assertEquals("a+0 = a", d, a); d = a.subtract(zm.getZERO()); assertEquals("a-0 = a", d, a); d = a.subtract(a); assertEquals("a-a = 0", d, zm.getZERO()); } /** * Test multiplication. */ @SuppressWarnings("unchecked") public void testMultiplication() { zm = new ModLongRing(5); d = new ModLong(zm, 11); a = zm.random(100); if (a.isZERO()) { a = d; } b = a.multiply(a); c = b.divide(a); assertEquals("a*a/a = a", c, a); assertEquals("a*a/a = a", 0, c.compareTo(a)); d = a.multiply(zm.getONE()); assertEquals("a*1 = a", d, a); d = a.divide(zm.getONE()); assertEquals("a/1 = a", d, a); a = zm.random(100); if (a.isZERO()) { a = d; } b = a.inverse(); c = a.multiply(b); assertTrue("a*1/a = 1", c.isONE()); try { a = zm.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { //ok } zm = new ModLongRing(5 * 3); a = new ModLong(zm, 5); assertFalse("5 !unit mod 15", a.isUnit()); try { b = a.inverse(); fail("5 invertible"); } catch (ModularNotInvertibleException expected) { //ok //expected.printStackTrace(); assertTrue("f = 15 ", expected.f.equals(new BigInteger(15))); assertTrue("f1 = 5 ", expected.f1.equals(new BigInteger(5))); assertTrue("f2 = 3 ", expected.f2.equals(new BigInteger(3))); assertTrue("f = f1*f2 ", expected.f.equals(expected.f1.multiply(expected.f2))); } catch (NotInvertibleException e) { //e.printStackTrace(); fail("wrong exception " + e); } } /** * Test chinese remainder. */ public void testChineseRemainder() { zm = new ModLongRing(19 * 13); a = zm.random(9); //System.out.println("a = " + a); z1 = new ModLongRing(19); b = new ModLong(z1, a.getVal()); //System.out.println("b = " + b); z2 = new ModLongRing(13); c = new ModLong(z2, a.getVal()); //System.out.println("c = " + c); d = new ModLong(z2, 19); d = d.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod 19,a mod 13) = a", a, e); java.math.BigInteger p1 = getPrime2(); try { z1 = new ModLongRing(p1); fail("p1 too large"); } catch (IllegalArgumentException e) { //pass } p1 = getPrime3(); java.math.BigInteger p2 = new java.math.BigInteger("19"); java.math.BigInteger p1p2 = p1.multiply(p2); //System.out.println("p1p2 = " + p1p2); //System.out.println("prime p1 ? = " + p1.isProbablePrime(66)); //System.out.println("prime p2 ? = " + p2.isProbablePrime(33)); //System.out.println("prime p1p1 ? = " + p1p2.isProbablePrime(3)); zm = new ModLongRing(p1p2); z1 = new ModLongRing(p1); z2 = new ModLongRing(p2); for (int i = 0; i < 5; i++) { a = zm.random((59 + 29) / 2); //60+30 ); //System.out.println("a = " + a); b = new ModLong(z1, a.getVal()); //System.out.println("b = " + b); c = new ModLong(z2, a.getVal()); //System.out.println("c = " + c); ModLong di = new ModLong(z2, p1); d = di.inverse(); //System.out.println("d = " + d); e = zm.chineseRemainder(b, d, c); //System.out.println("e = " + e); assertEquals("cra(a mod p1,a mod p2) = a ", a, e); } } /** * Test chinese remainder of lists. */ public void testChineseRemainderLists() { zm = new ModLongRing(19 * 13); z1 = new ModLongRing(19); z2 = new ModLongRing(13); List L1 = new ArrayList(); List L2 = new ArrayList(); List L; for (int i = 0; i < 7; i++) { a = zm.random(9); //System.out.println("a = " + a); b = new ModLong(z1, a.getVal()); //System.out.println("b = " + b); c = new ModLong(z2, a.getVal()); //System.out.println("c = " + c); L1.add(b); L2.add(c); } //System.out.println("L1 = " + L1); //System.out.println("L2 = " + L2); L = ModLongRing.chineseRemainder(z1.getONE(), z2.getONE(), L1, L2); //System.out.println("L = " + L); assertEquals("19 * 13) = a.modul: ", zm, L.get(0).ring); for (ModLong d : L) { b = new ModLong(z1, d.getVal()); //System.out.println("b = " + b); c = new ModLong(z2, d.getVal()); //System.out.println("c = " + c); assertTrue("cra(a mod 19, a mod 13) = a: ", L1.contains(b)); assertTrue("cra(a mod 19, a mod 13) = a: ", L2.contains(c)); } } /** * Test timing ModLong to ModInteger. */ public void testTiming() { zm = new ModLongRing(getPrime1()); a = zm.random(9); //System.out.println("a = " + a); b = zm.random(9); //System.out.println("b = " + b); c = zm.getONE(); //System.out.println("c = " + c); ModIntegerRing ZM = new ModIntegerRing(zm.modul); ModInteger A = new ModInteger(ZM, a.getVal()); ModInteger B = new ModInteger(ZM, b.getVal()); ModInteger C = ZM.getONE(); int run = 1000; //000; long t = System.currentTimeMillis(); for (int i = 0; i < run; i++) { if (c.isZERO()) { c = zm.getONE(); } c = a.sum(b.divide(c)); } t = System.currentTimeMillis() - t; //System.out.println("long time = " + t); ModInteger D = new ModInteger(ZM, c.getVal()); t = System.currentTimeMillis(); for (int i = 0; i < run; i++) { if (C.isZERO()) { C = ZM.getONE(); } C = A.sum(B.divide(C)); } t = System.currentTimeMillis() - t; //System.out.println("BigInteger time = " + t); assertEquals("C == D ", C, D); } /** * Test iterator. */ public void testIterator() { int m = 5 * 2; zm = new ModLongRing(m); ModLong j = null; for (ModLong i : zm) { //System.out.println("i = " + i); j = i; } ModLong end = new ModLong(zm, m - 1); assertTrue("j == m-1 ", j.equals(end)); } } java-algebra-system-2.7.200/trc/edu/jas/arith/PowerTest.java000066400000000000000000000150401445075545500235660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.LinkedList; import java.util.List; import edu.jas.structure.MonoidElem; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Basic power and structure tests with JUnit. * @author Heinz Kredel */ public class PowerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PowerTest object. * @param name String. */ public PowerTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(PowerTest.class); return suite; } @Override protected void setUp() { //a = b = c = d = e = null; } @Override protected void tearDown() { //a = b = c = d = e = null; } /** * Test addition for Integer. */ public void testAddition() { BigInteger a, b, c; List L = new LinkedList(); int n = 471; a = BigInteger.ZERO; for (int i = 1; i < n; i++) { b = BigInteger.ZERO.random(50); L.add(b); a = a.sum(b); } c = Power. sum(BigInteger.ONE, L); assertEquals("a = c", c, a); } /** * Test multiplication for Integer. */ public void testMultiplication() { BigInteger a, b, c; List L = new LinkedList(); int n = 471; a = BigInteger.ONE; for (int i = 1; i < n; i++) { b = BigInteger.ZERO.random(50); L.add(b); a = a.multiply(b); } c = Power. multiply(BigInteger.ONE, L); assertEquals("a = c", c, a); } /** * Test logarithm for Integer. */ public void testLog() { long x = Power.logarithm(2, 1024); //System.out.println("x = " + x); assertEquals("x = 10", x, 10); BigInteger a, b; a = new BigInteger("2"); b = new BigInteger("1024"); x = Power. logarithm(a, b); //System.out.println("x = " + x); assertEquals("x = 10", x, 10L); } /** * Test power for Rational. */ public void testRationalPower() { BigRational a, b, c, d; a = BigRational.ZERO.random(100); // power operations b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); Power pow = new Power(BigRational.ONE); b = pow.power(a, 1); assertEquals("a^1 = a", b, a); b = pow.power(a, 2); c = a.multiply(a); assertEquals("a^2 = a*a", b, c); d = pow.power(a, -2); c = b.multiply(d); assertTrue("a^2 * a^-2 = 1", c.isONE()); b = pow.power(a, 3); c = a.multiply(a).multiply(a); assertEquals("a^3 = a*a*a", b, c); d = pow.power(a, -3); c = b.multiply(d); assertTrue("a^3 * a^-3 = 1", c.isONE()); //Java 8: d = a.power(-3); c = b.multiply(d); assertTrue("a^3 * a^-3 = 1", c.isONE()); d = a.power(0); c = BigRational.ONE; assertEquals("a^0 == 1", c, d); d = a.power(3); c = a.multiply(a).multiply(a); assertEquals("a^3 == a*a*a", c, d); } /** * Test power for Integer. */ public void testIntegerPower() { BigInteger a, b, c, d, e; a = BigInteger.ZERO.random(500); // power operations b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); Power pow = new Power(BigInteger.ONE); b = pow.power(a, 1); assertEquals("a^1 = a", b, a); b = pow.power(a, 2); c = a.multiply(a); assertEquals("a^2 = a*a", b, c); b = pow.power(a, 3); c = a.multiply(a).multiply(a); assertEquals("a^3 = a*a*a", b, c); // mod power operations a = new BigInteger(3); b = Power. positivePower(a, 1); assertEquals("a^1 = a", b, a); java.math.BigInteger x = java.math.BigInteger.ONE; b = Power. positivePower(a, x); assertEquals("a^1 = a", b, a); a = new BigInteger(11); e = new BigInteger(2); c = Power. modPositivePower(a, 10, e); assertTrue("3^n mod 2 = 1", c.isONE()); // little fermat a = BigInteger.ZERO.random(500); b = new BigInteger(32003); c = Power. modPositivePower(a, 32003, b); d = a.remainder(b); assertEquals("a^p = a mod p", c, d); c = pow.modPower(a, 32003, b); assertEquals("a^p = a mod p", c, d); //Java 8: a = BigInteger.ZERO.random(100); d = a.power(1); c = a; assertEquals("a^1 == a", c, d); d = a.power(0); c = BigInteger.ONE; assertEquals("a^0 == 1", c, d); d = a.power(3); c = a.multiply(a).multiply(a); assertEquals("a^3 == a*a*a", c, d); } /** * Test left/right division for Integer. */ public void testIntegerLeftRight() { BigInteger a, b, c, d, e, f, g; a = BigInteger.ZERO.random(500); b = BigInteger.ZERO.random(50); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.divide(b); d = a.leftDivide(b); e = a.rightDivide(b); assertEquals("a /_l b == a/b", c, d); assertEquals("a /_r b == a/b", c, e); f = c; c = a.remainder(b); d = a.leftRemainder(b); e = a.rightRemainder(b); assertEquals("a rem_l b == a rem b", c, d); assertEquals("a rem_r b == a rem b", c, e); e = c; // no test since overridden in BigInteger: BigInteger[] qr = a.quotientRemainder(b); assertEquals("qr[0] == a/b", qr[0], f); assertEquals("qr[1] == a rem b", qr[1], e); MonoidElem[] lr = a.twosidedDivide(b); assertEquals("lr[0] == a/b", lr[0], f); assertTrue("lr[1] == 1", lr[1].isONE()); // wrong: todo MonoidElem r = a.twosidedRemainder(b); assertEquals("r == e", r, e); c = a.gcd(b); d = a.leftGcd(b); e = a.rightGcd(b); assertEquals("a ggt_l b == a ggt b", c, d); assertEquals("a ggt_r b == a ggt b", c, e); } } java-algebra-system-2.7.200/trc/edu/jas/arith/PrimeTest.java000066400000000000000000000270651445075545500235600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.List; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PrimeInteger and PrimeList tests with JUnit. * @author Heinz Kredel */ public class PrimeTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PrimeTest object. * @param name String */ public PrimeTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PrimeTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test prime list. */ public void testPrime() { PrimeList primes = new PrimeList(); //System.out.println("primes = " + primes); int i = 0; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { assertFalse("p != null", p == null); //System.out.print("" + p); if (i++ > 50) { break; } //System.out.print(", "); } //System.out.println(); //System.out.println("primes = " + primes); assertTrue("all primes ", primes.checkPrimes()); } /** * Test small prime list. */ public void testSmallPrime() { List sp = PrimeInteger.SMPRM; //smallPrimes(1, 500); //System.out.println("sp = " + sp); for (Long p : sp) { java.math.BigInteger P = new java.math.BigInteger(p.toString()); assertTrue("isPrime: " + p, P.isProbablePrime(16)); } PrimeList primes = new PrimeList(PrimeList.Range.small); //System.out.println("primes = " + primes); int i = primes.size() - 1; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { assertTrue("p.isPrime: ", PrimeInteger.isPrime(p.longValue())); //System.out.print(i + " = " + p + ", "); if (i-- <= 0) { break; } } } /** * Test low prime list. */ public void testLowPrime() { PrimeList primes = new PrimeList(PrimeList.Range.low); //System.out.println("primes = " + primes); int i = primes.size() - 1; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { assertTrue("p.isPrime: ", PrimeInteger.isPrime(p.longValue())); //System.out.print(i + " = " + p + ", "); if (i-- <= 0) { break; } } } /** * Test medium prime list. */ public void testMediumPrime() { PrimeList primes = new PrimeList(PrimeList.Range.medium); //System.out.println("primes = " + primes); int i = primes.size() - 1; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { //System.out.println(i + " = " + p + ", "); assertTrue("p.isPrime: ", PrimeInteger.isPrime(p.longValue())); if (i-- <= 0) { break; } } } /** * Test xlarge prime list. */ public void testLargePrime() { PrimeList primes = new PrimeList(PrimeList.Range.large); //System.out.println("primes = " + primes); int i = primes.size() - 1; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { //System.out.println(i + " = " + p + ", "); long pl = p.longValue(); if (pl < PrimeInteger.BETA) { assertTrue("p.isPrime: ", PrimeInteger.isPrime(pl)); } else { break; } if (i-- <= 0) { break; } } } /** * Test Mersenne prime list. */ public void testMersennePrime() { PrimeList primes = new PrimeList(PrimeList.Range.mersenne); //System.out.println("primes = " + primes); //assertTrue("all primes ", primes.checkPrimes() ); int i = primes.size() - 1; //System.out.println("primes = "); for (java.math.BigInteger p : primes) { //System.out.println(i + " = " + p + ", "); long pl = p.longValue(); if (pl < PrimeInteger.BETA) { assertTrue("p.isPrime: ", PrimeInteger.isPrime(pl)); } else { break; } if (i-- <= 0) { break; } } assertTrue("all primes ", primes.checkPrimes(5)); } /** * Test factorize integer. */ public void testFactorInteger() { SortedMap ff; ff = PrimeInteger.factors(2 * 3 * 5 * 7 * 2 * 9 * 10 * 19 * 811); //System.out.println("ff = " + ff); assertEquals("factors: ", ff.size(), 6); for (Long p : ff.keySet()) { java.math.BigInteger P = java.math.BigInteger.valueOf(p); assertTrue("isPrime: " + p, P.isProbablePrime(16)); } ff = PrimeInteger.factors(991 * 997 * 811 + 1); //System.out.println("ff = " + ff); assertEquals("factors: ", ff.size(), 3); for (Long p : ff.keySet()) { java.math.BigInteger P = java.math.BigInteger.valueOf(p); assertTrue("isPrime: " + p, P.isProbablePrime(16)); } ff = PrimeInteger.factors(PrimeList.getLongPrime(15, 135).longValue()); //System.out.println("ff = " + ff); assertEquals("factors: ", ff.size(), 1); for (Long p : ff.keySet()) { java.math.BigInteger P = java.math.BigInteger.valueOf(p); assertTrue("isPrime: " + p, P.isProbablePrime(16)); } //ff = PrimeInteger.factors( PrimeList.getLongPrime(61, 1).longValue() ); //ff = PrimeInteger.factors( PrimeList.getLongPrime(60, 93).longValue() ); //ff = PrimeInteger.factors( PrimeList.getLongPrime(59, 55).longValue() ); ff = PrimeInteger.factors(PrimeList.getLongPrime(59, 0).longValue()); //System.out.println("m = " + PrimeList.getLongPrime(59, 0).longValue()); //System.out.println("ff = " + ff); assertEquals("factors: ", ff.size(), 1); for (Long p : ff.keySet()) { java.math.BigInteger P = java.math.BigInteger.valueOf(p); assertTrue("isPrime: " + p, P.isProbablePrime(32)); } //System.out.println("SMPRM = " + PrimeInteger.SMPRM); } /** * Test factorize large integer. */ public void testFactorLargeInteger() { SortedMap ff; long n = 2 * 3 * 5 * 7 * 2 * 9 * 10 * 19 * 811; java.math.BigInteger N = java.math.BigInteger.valueOf(n); ff = PrimeInteger.factors(N); //System.out.println("ff = " + ff); assertEquals("factors: ", ff.size(), 6); for (java.math.BigInteger p : ff.keySet()) { assertTrue("isPrime: " + p, p.isProbablePrime(16)); } //N = N.multiply( PrimeList.getLongPrime(59, 55) ); N = N.multiply(PrimeList.getLongPrime(59, 19)); N = N.multiply(PrimeList.getLongPrime(61, 1)); //System.out.println("N = " + N); ff = PrimeInteger.factors(N); // was not correct //System.out.println("ff = " + ff); for (java.math.BigInteger p : ff.keySet()) { assertTrue("isPrime: " + p, p.isProbablePrime(32)); } N = new java.math.BigInteger("1152921504606846883"); //System.out.println("N = " + N); ff = PrimeInteger.factors(N); //System.out.println("ff = " + ff); assertTrue("isPrime: " + ff, ff.size() == 1); } /** * Test random integers. */ public void testRandom() { SortedMap ff; BigInteger rnd = BigInteger.ONE; //System.out.println("beta = " + PrimeInteger.BETA); //System.out.println("SMPRM = " + PrimeInteger.SMPRM); for (int i = 0; i < 5; i++) { BigInteger M = rnd.random(60).abs(); //System.out.println("M = " + M); long m = Math.abs(M.getVal().longValue()); //System.out.println("M = " + M + ", m = " + m); if (m < PrimeInteger.BETA) { ff = PrimeInteger.factors(m); //System.out.println("ff = " + ff); assertTrue("isFactorization: " + m + ", ff = " + ff, PrimeInteger.isPrimeFactorization(m, ff)); } } } /** * Test random integers to the power of 3. */ public void testRandom3() { SortedMap ff; BigInteger rnd = BigInteger.ONE; for (int i = 0; i < 5; i++) { BigInteger M = rnd.random(20).abs(); M = M.power(3); //System.out.println("M = " + M); long m = Math.abs(M.getVal().longValue()); //System.out.println("M = " + M + ", m = " + m); if (m < PrimeInteger.BETA) { ff = PrimeInteger.factors(m); //System.out.println("ff = " + ff); assertTrue("isFactorization: " + m + ", ff = " + ff, PrimeInteger.isPrimeFactorization(m, ff)); for (Integer e : ff.values()) { assertTrue("e >= 3: " + e + ", ff = " + ff, e >= 3); } } } } /** * Test random integers, compare to Pollard. */ public void ytestRandomCompare() { SortedMap ff, ffp; BigInteger rnd = BigInteger.ONE; //System.out.println("beta = " + PrimeInteger.BETA); for (int i = 0; i < 5; i++) { BigInteger M = rnd.random(60).abs(); //System.out.println("M = " + M); long m = Math.abs(M.getVal().longValue()); //System.out.println("M = " + M + ", m = " + m); if (m < PrimeInteger.BETA) { long t = System.currentTimeMillis(); ff = PrimeInteger.factors(m); t = System.currentTimeMillis() - t; System.out.println("ff = " + ff); assertTrue("isFactorization: " + m + ", ff = " + ff, PrimeInteger.isFactorization(m, ff)); long s = System.currentTimeMillis(); ffp = PrimeInteger.factorsPollard(m); s = System.currentTimeMillis() - s; System.out.println("time: t = " + t + ", s = " + s); assertEquals("isFactorization: " + m, ff, ffp); } } for (int i = 0; i < 5; i++) { BigInteger M = rnd.random(20).abs(); M = M.power(3); //System.out.println("M = " + M); long m = Math.abs(M.getVal().longValue()); //System.out.println("M = " + M + ", m = " + m); if (m < PrimeInteger.BETA) { long t = System.currentTimeMillis(); ff = PrimeInteger.factors(m); t = System.currentTimeMillis() - t; System.out.println("ff = " + ff); assertTrue("isFactorization: " + m + ", ff = " + ff, PrimeInteger.isFactorization(m, ff)); long s = System.currentTimeMillis(); ffp = PrimeInteger.factorsPollard(m); s = System.currentTimeMillis() - s; System.out.println("time: t = " + t + ", s = " + s); assertEquals("isFactorization: " + m, ff, ffp); } } } } java-algebra-system-2.7.200/trc/edu/jas/arith/ProductTest.java000066400000000000000000000372031445075545500241170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.arith; import java.util.ArrayList; import java.util.List; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Product test with JUnit. * @author Heinz Kredel */ public class ProductTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ProductTest object. * @param name String. */ public ProductTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ProductTest.class); return suite; } ProductRing fac; ModIntegerRing pfac; ProductRing mfac; ProductRing ifac; Product a, b, c, d, e, f; Product ap, bp, cp, dp, ep, fp; Product ai, bi, ci, di, ei, fi; int pl = 5; int rl = 1; int kl = 13; int ll = 7; int el = 3; float q = 0.9f; int il = 2; //long p = 1152921504606846883L; // 2^60-93; @Override protected void setUp() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; ai = bi = ci = di = ei = null; BigRational cfac = new BigRational(2, 3); fac = new ProductRing(cfac, pl); List> lpfac = new ArrayList>(); pfac = new ModIntegerRing(2); lpfac.add(pfac); pfac = new ModIntegerRing(3); lpfac.add(pfac); pfac = new ModIntegerRing(5); lpfac.add(pfac); pfac = new ModIntegerRing(7); lpfac.add(pfac); mfac = new ProductRing(lpfac); BigInteger cifac = new BigInteger(3); ifac = new ProductRing(cifac, pl); } @Override protected void tearDown() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; ai = bi = ci = di = ei = null; fac = null; pfac = null; mfac = null; ifac = null; } /** * Test constructor for rational. */ public void testRatConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); BigRational crfac = new BigRational(2, 3); fac.addFactory(crfac); assertEquals("#fac == 5+1: ", fac.length(), pl + 1); } /** * Test constructor for modular. */ public void testModConstruction() { cp = mfac.getONE(); //System.out.println("cp = " + cp); assertTrue("isZERO( cp )", !cp.isZERO()); assertTrue("isONE( cp )", cp.isONE()); dp = mfac.getZERO(); //System.out.println("dp = " + dp); assertTrue("isZERO( dp )", dp.isZERO()); assertTrue("isONE( dp )", !dp.isONE()); } /** * Test random rational. */ public void testRatRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl * (i + 1)); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); a = fac.random(kl, q); if (a.isZERO()) { continue; } //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test random modular. */ public void testModRandom() { for (int i = 0; i < 7; i++) { ap = mfac.random(kl, q); if (ap.isZERO() || ap.isONE()) { continue; } //System.out.println("ap = " + ap); assertTrue(" not isZERO( ap" + i + " )", !ap.isZERO()); assertTrue(" not isONE( ap" + i + " )", !ap.isONE()); } } /** * Test rational addition. */ public void testRatAddition() { a = fac.random(kl, q); b = fac.random(kl, q); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); c = fac.random(kl, q); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); } /** * Test integer addition. */ public void testIntAddition() { ai = ifac.random(kl, q); bi = ifac.random(kl, q); ci = ai.sum(bi); di = ci.subtract(bi); assertEquals("a+b-b = a", ai, di); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); ci = ai.sum(bi); di = bi.sum(ai); assertEquals("a+b = b+a", ci, di); //System.out.println("c = " + c); //System.out.println("d = " + d); ci = ifac.random(kl, q); di = ci.sum(ai.sum(bi)); ei = ci.sum(ai).sum(bi); assertEquals("c+(a+b) = (c+a)+b", di, ei); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ci = ai.sum(ifac.getZERO()); di = ai.subtract(ifac.getZERO()); assertEquals("a+0 = a-0", ci, di); //System.out.println("c = " + c); //System.out.println("d = " + d); ci = ifac.getZERO().sum(ai); di = ifac.getZERO().subtract(ai.negate()); assertEquals("0+a = 0+(-a)", ci, di); //System.out.println("c = " + c); //System.out.println("d = " + d); } /** * Test modular addition. */ public void testModAddition() { ap = mfac.random(kl, q); bp = mfac.random(kl, q); //System.out.println("a = " + a); //System.out.println("b = " + b); cp = ap.sum(bp); dp = cp.subtract(bp); assertEquals("a+b-b = a", ap, dp); cp = ap.sum(bp); dp = bp.sum(ap); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", cp, dp); cp = mfac.random(kl, q); dp = cp.sum(ap.sum(bp)); ep = cp.sum(ap).sum(bp); assertEquals("c+(a+b) = (c+a)+b", dp, ep); cp = ap.sum(mfac.getZERO()); dp = ap.subtract(mfac.getZERO()); assertEquals("a+0 = a-0", cp, dp); cp = mfac.getZERO().sum(ap); dp = mfac.getZERO().subtract(ap.negate()); assertEquals("0+a = 0+(-a)", cp, dp); } /** * Test rational multiplication. */ public void testRatMultiplication() { a = fac.random(kl); if (a.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl, q); if (b.isZERO()) { return; } assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); //assertTrue("not isZERO( c )", !c.isZERO() ); //assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.divide(b); d = a.remainder(b); e = c.multiply(b).sum(d); f = a.multiply(e.idempotent()); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("f = " + f); assertEquals("a = (a/b)c+d ", e, f); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); b = a.idempotent(); c = a.idemComplement(); d = b.multiply(c); assertEquals("idem(a)*idemComp(a) = 0", d, fac.getZERO()); d = b.sum(c); assertEquals("idem(a)+idemComp(a) = 1", d, fac.getONE()); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); e = a.idempotent(); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a*1/a = 1", e, d); } } /** * Test integer multiplication. */ public void testIntMultiplication() { ai = ifac.random(kl); while (ai.isZERO()) { ai = ifac.random(kl); } assertTrue("not isZERO( a )", !ai.isZERO()); bi = ifac.random(kl, q); if (bi.isZERO()) { bi = ifac.random(kl, q); } assertTrue("not isZERO( b )", !bi.isZERO()); ci = bi.multiply(ai); di = ai.multiply(bi); //assertTrue("not isZERO( c )", !c.isZERO() ); //assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + ai); //System.out.println("b = " + bi); ei = di.subtract(ci); assertTrue("isZERO( a*b-b*a ) " + ei, ei.isZERO()); assertTrue("a*b = b*a", ci.equals(di)); assertEquals("a*b = b*a", ci, di); ci = ifac.random(kl, q); //System.out.println("c = " + ci); di = ai.multiply(bi.multiply(ci)); ei = (ai.multiply(bi)).multiply(ci); //System.out.println("d = " + di); //System.out.println("e = " + ei); //System.out.println("d-e = " + di.subtract(ci) ); assertEquals("a(bc) = (ab)c", di, ei); assertTrue("a(bc) = (ab)c", di.equals(ei)); ci = ai.divide(bi); di = ai.remainder(bi); ei = ci.multiply(bi).sum(di); fi = ai.multiply(ei.idempotent()); //System.out.println("c = " + ci); //System.out.println("d = " + di); //System.out.println("e = " + ei); //System.out.println("f = " + fi); assertEquals("a = (a/b)c+d ", ei, fi); ci = ai.gcd(bi); di = ai.remainder(ci); ei = bi.remainder(ci); //System.out.println("c = " + ci); //System.out.println("d = " + di); //System.out.println("e = " + ei); assertTrue("gcd(a,b) | a ", di.isZERO()); assertTrue("gcd(a,b) | b ", ei.isZERO()); Product[] gcd; gcd = ai.egcd(bi); ci = gcd[0]; di = ai.remainder(ci); ei = bi.remainder(ci); //System.out.println(); //System.out.println("c = " + ci); //System.out.println("d = " + di); //System.out.println("e = " + ei); assertTrue("gcd(a,b) | a ", di.isZERO()); assertTrue("gcd(a,b) | b ", ei.isZERO()); di = ai.multiply(gcd[1]); ei = bi.multiply(gcd[2]); fi = di.sum(ei); //System.out.println("c = " + ci); //System.out.println("c1= " + gcd[1]); //System.out.println("c2= " + gcd[2]); //System.out.println("d = " + di); //System.out.println("e = " + ei); //System.out.println("f = " + fi); assertEquals("gcd(a,b) = c1*a + c2*b ", ci, fi); ci = ai.multiply(ifac.getONE()); di = ifac.getONE().multiply(ai); assertEquals("a*1 = 1*a", ci, di); bi = ai.idempotent(); ci = ai.idemComplement(); di = bi.multiply(ci); assertEquals("idem(a)*idemComp(a) = 0", di, ifac.getZERO()); di = bi.sum(ci); assertEquals("idem(a)+idemComp(a) = 1", di, ifac.getONE()); if (ai.isUnit()) { ci = ai.inverse(); di = ci.multiply(ai); ei = ai.idempotent(); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a*1/a = 1", ei, di); } } /** * Test modular multiplication. */ public void testModMultiplication() { ap = mfac.random(kl, q); if (ap.isZERO()) { return; } assertTrue("not isZERO( a )", !ap.isZERO()); bp = mfac.random(kl, q); if (bp.isZERO()) { return; } assertTrue("not isZERO( b )", !bp.isZERO()); cp = bp.multiply(ap); dp = ap.multiply(bp); //assertTrue("not isZERO( c )", !cp.isZERO() ); //assertTrue("not isZERO( d )", !dp.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); ep = dp.subtract(cp); assertTrue("isZERO( a*b-b*a ) " + ep, ep.isZERO()); assertTrue("a*b = b*a", cp.equals(dp)); assertEquals("a*b = b*a", cp, dp); cp = mfac.random(kl, q); //System.out.println("c = " + c); dp = ap.multiply(bp.multiply(cp)); ep = (ap.multiply(bp)).multiply(cp); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", dp, ep); assertTrue("a(bc) = (ab)c", dp.equals(ep)); cp = ap.divide(bp); dp = ap.remainder(bp); ep = cp.multiply(bp).sum(dp); fp = ap.multiply(ep.idempotent()); //System.out.println("cp = " + cp); //System.out.println("dp = " + dp); //System.out.println("ep = " + ep); //System.out.println("fp = " + fp); assertEquals("a = (a/b)c+d ", ep, fp); cp = ap.multiply(mfac.getONE()); dp = mfac.getONE().multiply(ap); assertEquals("a*1 = 1*a", cp, dp); bp = ap.idempotent(); cp = ap.idemComplement(); dp = bp.multiply(cp); assertEquals("idem(a)*idemComp(a) = 0", dp, mfac.getZERO()); dp = bp.sum(cp); assertEquals("idem(a)+idemComp(a) = 1", dp, mfac.getONE()); if (ap.isUnit()) { cp = ap.inverse(); dp = cp.multiply(ap); ep = ap.idempotent(); //System.out.println("ap = " + ap); //System.out.println("cp = " + cp); //System.out.println("dp = " + dp); //System.out.println("ep = " + ep); assertEquals("a*1/a = 1", ep, dp); } } } java-algebra-system-2.7.200/trc/edu/jas/fd/000077500000000000000000000000001445075545500202515ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/fd/FDUtilQuatTest.java000066400000000000000000000546751445075545500237570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.List; import java.util.ArrayList; import java.util.Collection; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * FDUtilQuat tests with JUnit. * @author Heinz Kredel */ public class FDUtilQuatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a FDUtilQuatTest object. * @param name String. */ public FDUtilQuatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FDUtilQuatTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); BigQuaternionRing cfi, cfr; GenSolvablePolynomialRing dfac; GenSolvablePolynomialRing rdfac; GenSolvablePolynomialRing> rfac; GenSolvablePolynomialRing> rrfac; RecSolvablePolynomialRing rsfac; GenSolvablePolynomial a, b, c, d, e, f; GenSolvablePolynomial> ar, br, cr, dr, er, fr; GenSolvablePolynomial> arr, brr, abrr, barr, crr, drr, err, frr, x1; RecSolvablePolynomial as, bs, cs, ds, es, fs; int rl = 4; int kl = 2; int ll = 4; int el = 3; float q = 0.35f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; rl = vars.length; cfi = new BigQuaternionRing(true); cfr = new BigQuaternionRing(); dfac = new GenSolvablePolynomialRing(cfi, to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = dfac.recursive(1); rdfac = new GenSolvablePolynomialRing(cfr, to, vars); RelationGenerator wlr = new WeylRelationsIterated(); rdfac.addRelations(wlr); rrfac = rdfac.recursive(1); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; dfac = null; rfac = null; } /** * Test base pseudo division. */ public void testBasePseudoDivisionExact() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll + 1, el, q).monic(); } while (a.isZERO()); //a = dfac.parse(" 3 x^5 + 44 "); //System.out.println("a = " + a); do { b = dfac.random(kl, ll + 1, el, q).monic(); } while (b.isZERO()); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c != 0: ", !c.isZERO()); assertTrue("d != 0: ", !d.isZERO()); assertTrue("a*b != b*a", !c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // divide e = FDUtil. leftBasePseudoQuotient(c, a); //System.out.println("e = " + e); assertEquals("b == b*a/a: ", b, e); f = FDUtil. rightBasePseudoQuotient(c, b); //System.out.println("f = " + f); assertEquals("a == b*a/b: ", a, f); e = FDUtil. rightBasePseudoQuotient(d, a); //System.out.println("e = " + e); assertEquals("b == a*b/a: ", b, e); f = FDUtil. leftBasePseudoQuotient(d, b); //System.out.println("f = " + f); assertEquals("a == a*b/b: ", a, f); } /** * Test base pseudo quotient remainder. */ public void testBasePseudoQuotientRemainderExact() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll + 1, el, q).monic(); } while (a.isZERO()); //a = dfac.parse(" 3 x^5 + 44 "); //System.out.println("a = " + a); do { b = dfac.random(kl, ll + 1, el, q).monic(); } while (b.isZERO()); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c != 0: ", !c.isZERO()); assertTrue("d != 0: ", !d.isZERO()); assertTrue("a*b != b*a", !c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // divide e = FDUtil. rightBaseSparsePseudoRemainder(d, a); //System.out.println("e = " + e); assertTrue("ab = a*x + 0: ", e.isZERO()); f = FDUtil. leftBaseSparsePseudoRemainder(d, b); //System.out.println("f = " + f); assertTrue("ab = y*b + 0: ", f.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(c, a); //System.out.println("e = " + e); assertTrue("ba = x*a + 0: ", e.isZERO()); f = FDUtil. rightBaseSparsePseudoRemainder(c, b); //System.out.println("f = " + f); assertTrue("ba = b*y + 0: ", f.isZERO()); } /** * Test base pseudo division and remainder. */ public void testBasePseudoDivisionRemainder() { String[] names = new String[] { "x" }; GenSolvablePolynomialRing dfac; dfac = new GenSolvablePolynomialRing(cfi, to, names); GenSolvablePolynomialRing rdfac; rdfac = new GenSolvablePolynomialRing(cfr, dfac); //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll * 1, el + 0, q); } while (a.isZERO()); //a = dfac.parse("3 x**5 + 44"); //System.out.println("a = " + a); do { b = dfac.random(kl, ll * 2, el + 1, q); } while (b.isZERO()); //a = a.sum(b); //b = dfac.parse("2 x**2 + 40"); //System.out.println("b = " + b); //System.out.println("a = " + a); GenSolvablePolynomial[] QR = FDUtil. leftBasePseudoQuotientRemainder(a, b); c = (GenSolvablePolynomial) QR[0]; d = (GenSolvablePolynomial) QR[1]; //System.out.println("c = " + c); //System.out.println("d = " + d); boolean t = FDUtil. isLeftBasePseudoQuotientRemainder(a, b, c, d); assertTrue("lc^n c = e b + f: " + f, t); QR = FDUtil. rightBasePseudoQuotientRemainder(a, b); e = QR[0]; f = QR[1]; //System.out.println("e = " + e); //System.out.println("f = " + f); t = FDUtil. isRightBasePseudoQuotientRemainder(a, b, e, f); assertTrue("ore(lc^n) c = e b + f: " + f, t); } /* * Test recursive pseudo division. * @see edu.jas.ufd.PolyUfdUtilTest#testRecursivePseudoDivisionSparse */ public void todotestRecursivePseudoDivision() { //String[] cnames = new String[] { "x" }; //String[] mnames = new String[] { "t" }; String[] names = new String[] { "t", "x", "y", "z" }; rdfac = new GenSolvablePolynomialRing(cfr, to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rrfac = (RecSolvablePolynomialRing) rdfac.recursive(1); //System.out.println("\nrdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); q = 0.23f; kl = 1; ll = 3; arr = rrfac.random(kl, ll, el-1, q); //arr = rrfac.parse(" ( t + x + y ) z^2 + ( 2 x - 8 ) y^2 - ( 13 t^4 - 13 t^3 + t^2 + 2 t - 13 ) "); //arr = rrfac.parse(" ( 131/5 y - 85/84 ) "); brr = rrfac.random(kl, ll, el, q); //brr = rrfac.parse("( 27/28 x^2 - 31/19 t^2 + 3/5 )"); if (brr.isZERO()) { brr = rrfac.parse(" ( x - 2 ) z - ( t - y^2 + y ) "); } //System.out.println("arr = " + arr); //System.out.println("brr = " + brr); drr = FDUtil. recursivePseudoQuotient(arr, brr); crr = FDUtil. recursiveSparsePseudoRemainder(arr, brr); //System.out.println("qrr = " + drr); //System.out.println("crr = " + crr); GenSolvablePolynomial>[] QR; QR = FDUtil. recursivePseudoQuotientRemainder(arr, brr); //assertEquals("drr == QR[0]: ", drr, QR[0]); //assertEquals("crr == QR[1]: ", crr, QR[1]); boolean t = FDUtil. isRecursivePseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("ore(lc^n) a == q b + r: " + t); assertTrue("ore(lc^n) a = q b + r: " + crr, t); // ?? } /** * Test recursive division coefficient polynomial. */ public void todoTtestLeftAndRightRecursiveDivision() { // todo //String[] names = new String[] { "t", "x", "y", "z" }; String[] names = new String[] { "y", "z" }; rdfac = new GenSolvablePolynomialRing(cfr, to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rrfac = rdfac.recursive(1); //System.out.println("\nrdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); GenSolvablePolynomial>[] QR; boolean t; // q = q; kl = 2; ll = 4; el = 5; arr = rrfac.random(kl, ll, el + 1, q); //arr = rrfac.parse("z^5 - ( 1260/551 y^2 - 143/35 y - 33/100 ) z - ( 1/3 y^2 + 419/299 y - 19/56 )"); // b * q + r: //arr = rrfac.parse("z^5 + z^2 - 1"); //System.out.println("arr = " + arr); brr = rrfac.random(kl, ll, el, q); //brr = rrfac.parse("z^3 - ( 377/140 y^2 + 211/232 y + 1213967/85560 )"); //brr = rrfac.parse("( y ) z^3 - ( 1 ) z + ( 2 )"); //System.out.println("brr = " + brr); abrr = arr.multiply(brr); //System.out.println("abrr = " + abrr); // exact left division drr = FDUtil. recursivePseudoQuotient(abrr, brr); crr = FDUtil. recursiveSparsePseudoRemainder(abrr, brr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); QR = FDUtil. recursivePseudoQuotientRemainder(abrr, brr); assertEquals("drr == QR[0]: ", drr, QR[0]); assertEquals("crr == QR[1]: ", crr, QR[1]); t = FDUtil. isRecursivePseudoQuotientRemainder(abrr, brr, drr, crr); //System.out.println("ore(lc^n) a == q b + r: " + t); assertTrue("ore(lc^n) a = q b + r: " + crr, t); // ?? barr = brr.multiply(arr); //System.out.println("barr = " + barr); // exact right division QR = FDUtil. recursiveRightPseudoQuotientRemainder(barr, brr); drr = QR[0]; crr = QR[1]; //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); //assertEquals("drr == QR[0]: ", drr, QR[0]); //assertEquals("crr == QR[1]: ", crr, QR[1]); t = FDUtil. isRecursiveRightPseudoQuotientRemainder(barr, brr, drr, crr); //System.out.println("FDQR: a ore(lc^n) == q b + r: " + t); assertTrue("a ore(lc^n) = q b + r: " + crr, t); // ?? // left division QR = FDUtil. recursivePseudoQuotientRemainder(arr, brr); drr = QR[0]; crr = QR[1]; t = FDUtil. isRecursivePseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); assertTrue("ore(lc^n) a = b q + r: " + crr, t); // ?? // right division QR = FDUtil. recursiveRightPseudoQuotientRemainder(arr, brr); drr = QR[0]; crr = QR[1]; t = FDUtil. isRecursiveRightPseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); assertTrue("ore(lc^n) a = q p + r: " + crr, t); // ?? } /* * Test recursive right coefficient polynomial. */ public void todotestRightRecursivePolynomial() { // todo String[] names = new String[] { "t", "x", "y", "z" }; //String[] names = new String[] { "y", "z" }; rdfac = new GenSolvablePolynomialRing(cfr, to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rrfac = rdfac.recursive(1); //System.out.println("\nrdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); //GenSolvablePolynomialRing cfac = (GenSolvablePolynomialRing) rrfac.coFac; //System.out.println("cfac = " + cfac.toScript()); // q = q; kl = 3; ll = 4; el = 5; arr = rrfac.random(kl, ll, el, q); //arr = rrfac.parse(" z { y } "); //System.out.println("arr = " + arr); brr = arr.rightRecursivePolynomial(); //System.out.println("brr = " + brr); boolean t = arr.isRightRecursivePolynomial(brr); assertTrue("arr == eval(brr): ", t); GenSolvablePolynomial c = (GenSolvablePolynomial) rrfac .random(kl, ll, el, q).leadingBaseCoefficient(); //c = cfac.parse("y**2"); //System.out.println("c = " + c); drr = arr.multiply(c); // arr * c = drr //System.out.println("drr = " + drr); err = FDUtil. recursiveLeftDivide(drr, c); // err * c = drr //System.out.println("err = " + err); assertEquals("arr == err: ", arr, err); //System.out.println("\nFDQR: arr = " + arr); drr = arr.multiplyLeft(c); // c * arr = drr //System.out.println("drr = " + drr); err = FDUtil. recursiveRightDivide(drr, c); // c * err = drr //System.out.println("err = " + err); assertEquals("arr == err: ", arr, err); } /* * Test exact division of recursive polynomials. */ public void todotestRecursiveDivide() { rdfac = new GenSolvablePolynomialRing(cfr, dfac); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); //System.out.println("rdfac = " + rdfac.toScript()); rsfac = (RecSolvablePolynomialRing) rdfac.recursive(1); System.out.println("rsfac = " + rsfac.toScript()); assertFalse("isCommutative()", rsfac.isCommutative()); assertTrue("isAssociative()", rsfac.isAssociative()); do { as = rsfac.random(kl, ll, el, q); } while (as.isZERO()); System.out.println("as = " + as); do { bs = rsfac.random(kl, ll, el, q); } while (bs.isZERO()); System.out.println("bs = " + bs); // non commutative cs = bs.multiply(as); ds = as.multiply(bs); //System.out.println("cs = " + cs); //System.out.println("ds = " + ds); assertTrue("cs != 0: ", !cs.isZERO()); assertTrue("ds != 0: ", !ds.isZERO()); //es = (RecSolvablePolynomial) ds.subtract(cs); assertTrue("as*bs != bs*as", !cs.equals(ds) || cs.leadingExpVector().equals(ds.leadingExpVector())); // divide es = (RecSolvablePolynomial) FDUtil. recursivePseudoQuotient(cs, as); //System.out.println("es = " + es); final int max = 4; int i = 0; do { x1 = (RecSolvablePolynomial) bs.multiplyLeft(as.leadingBaseCoefficient().power(i)); //System.out.println("lc(a)^"+i+"*b = " + x1); if (es.equals(x1)) { assertEquals("b == b*a/a: ", es, x1); break; } if (es.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { // assertEquals("b == b*a/a: ", e, x1); System.out.println("fail: b == b*a/a: lc(e)==lc(x1)"); if (es.abs().equals(bs.abs())) { System.out.println("success via pseudo: b == b*a/a: "); } break; } } while (i++ < max); fs = (RecSolvablePolynomial) FDUtil. recursivePseudoQuotient(ds, bs); System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiplyLeft(bs.leadingBaseCoefficient().power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { //System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { //System.out.println("success via pseudo: a == a*b/b: "); //assertEquals("a != a*b/b: ", fs.abs(), x1.abs()); } else { assertFalse("a != a*b/b: ", fs.abs().equals(x1.abs())); } break; } } while (i++ < max); GenSolvablePolynomial bc = (GenSolvablePolynomial) bs.leadingBaseCoefficient(); ds = (RecSolvablePolynomial) as.multiply(bc); fs = (RecSolvablePolynomial) FDUtil. recursiveDivide(ds, bc); System.out.println("bc = " + bc); System.out.println("ds = " + ds); System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bc.power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { //System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { //System.out.println("success via pseudo: a == a*b/b: "); } else { assertFalse("a != a*b/b: ", fs.abs().equals(x1.abs())); } break; } } while (i++ < max); bc = (GenSolvablePolynomial) bs.leadingBaseCoefficient(); ds = (RecSolvablePolynomial) as.multiply(bc); fs = (RecSolvablePolynomial) FDUtil. recursiveLeftDivide(ds, bc); System.out.println("bc = " + bc); System.out.println("ds = " + ds); System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bc.power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { System.out.println("success via pseudo: a == a*b/b: "); } break; } } while (i++ < max); // todo fs = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(cs, bs); System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bs.leadingBaseCoefficient().power(i)); //System.out.println("a*lc(b)^"+i+" = " + x1); if (fs.equals(x1)) { assertEquals("a == b*a/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { //System.out.println("fail: a == b*a/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { //System.out.println("success via pseudo: a == b*a/b: "); } else { assertFalse("a != a*b/b: ", fs.abs().equals(x1.abs())); } break; } } while (i++ < max); es = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(ds, as); System.out.println("es = " + es); i = 0; do { x1 = (RecSolvablePolynomial) bs.multiply(as.leadingBaseCoefficient().power(i)); //System.out.println("b*lc(a)^"+i+" = " + x1); if (es.equals(x1)) { assertEquals("b == a*b/a: ", es, x1); break; } if (es.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { //System.out.println("fail: b == a*b/a: lc(e) == lc(x1)"); if (es.abs().equals(bs.abs())) { //System.out.println("success via pseudo: b == a*b/a: "); } else { assertFalse("a != a*b/b: ", fs.abs().equals(x1.abs())); } break; } } while (i++ < max); } } java-algebra-system-2.7.200/trc/edu/jas/fd/FDUtilTest.java000066400000000000000000000657111445075545500231150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.List; import java.util.ArrayList; import java.util.Collection; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * FDUtil tests with JUnit. * @author Heinz Kredel */ public class FDUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a FDUtilTest object. * @param name String. */ public FDUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FDUtilTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenSolvablePolynomialRing dfac; GenSolvablePolynomialRing rdfac; GenSolvablePolynomialRing> rfac; GenSolvablePolynomialRing> rrfac; RecSolvablePolynomialRing rsfac; GenSolvablePolynomial a, b, c, d, e, f; GenSolvablePolynomial> ar, br, cr, dr, er, fr; GenSolvablePolynomial> arr, brr, abrr, barr, crr, drr, err, frr, x1; RecSolvablePolynomial as, bs, cs, ds, es, fs; int rl = 4; int kl = 2; int ll = 4; int el = 3; float q = 0.35f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; rl = vars.length; dfac = new GenSolvablePolynomialRing(new BigInteger(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = dfac.recursive(1); rdfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wlr = new WeylRelationsIterated(); rdfac.addRelations(wlr); rrfac = rdfac.recursive(1); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; dfac = null; rfac = null; } /** * Test base pseudo division. */ public void testBasePseudoDivisionExact() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll + 1, el, q); } while (a.isZERO()); //a = dfac.parse(" 3 x^5 + 44 "); //System.out.println("a = " + a); do { b = dfac.random(kl, ll + 1, el, q); } while (b.isZERO()); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c != 0: ", !c.isZERO()); assertTrue("d != 0: ", !d.isZERO()); assertTrue("a*b != b*a", !c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // divide e = FDUtil. leftBasePseudoQuotient(c, a); //System.out.println("e = " + e); assertEquals("b == b*a/a: ", b, e); f = FDUtil. rightBasePseudoQuotient(c, b); //System.out.println("f = " + f); assertEquals("a == b*a/b: ", a, f); e = FDUtil. rightBasePseudoQuotient(d, a); //System.out.println("e = " + e); assertEquals("b == a*b/a: ", b, e); f = FDUtil. leftBasePseudoQuotient(d, b); //System.out.println("f = " + f); assertEquals("a == a*b/b: ", a, f); } /** * Test base pseudo division. */ //@SuppressWarnings({ "cast" }) public void testBasePseudoDivision() { String[] names = new String[] { "x" }; GenSolvablePolynomialRing dfac; dfac = new GenSolvablePolynomialRing(new BigInteger(1), to, names); GenSolvablePolynomialRing rdfac; rdfac = new GenSolvablePolynomialRing(new BigRational(1), dfac); //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll * 1, el + 0, q); } while (a.isZERO()); a = dfac.parse("3 x**5 + 44"); //System.out.println("a = " + a); do { b = dfac.random(kl, ll * 2, el + 1, q); } while (b.isZERO()); //a = a.sum(b); b = dfac.parse("2 x**2 + 40"); //System.out.println("b = " + b); //System.out.println("a = " + a); GenPolynomial[] QR = PolyUtil. basePseudoQuotientRemainder(a, b); c = (GenSolvablePolynomial) QR[0]; d = (GenSolvablePolynomial) QR[1]; //System.out.println("c = " + c); //System.out.println("d = " + d); boolean t = PolyUtil. isBasePseudoQuotientRemainder(a, b, c, d); assertTrue("lc^n c = e b + f: " + f, t); GenSolvablePolynomial[] QRs = FDUtil. leftBasePseudoQuotientRemainder(a, b); e = QRs[0]; f = QRs[1]; //System.out.println("e = " + e); //System.out.println("f = " + f); t = PolyUtil. isBasePseudoQuotientRemainder(a, b, e, f); assertTrue("ore(lc^n) c = e b + f: " + f, t); // compare with field coefficients: GenSolvablePolynomial ap, bp, cp, dp, ep, fp, qp, rp, rhs; ap = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, a); bp = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, b); cp = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, c); dp = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, d); ep = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, e); fp = (GenSolvablePolynomial) PolyUtil. fromIntegerCoefficients(rdfac, f); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); //System.out.println("dp = " + dp); //System.out.println("ep = " + ep); //System.out.println("fp = " + fp); qp = (GenSolvablePolynomial) ap.divide(bp); rp = (GenSolvablePolynomial) ap.remainder(bp); //System.out.println("qp = " + qp); //System.out.println("rp = " + rp); GenSolvablePolynomial[] QRr = ap.quotientRemainder(bp); assertEquals("qp == QRr[0]: ", qp, QRr[0]); assertEquals("rp == QRr[1]: ", rp, QRr[1]); rhs = (GenSolvablePolynomial) qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap == qp bp + rp: ", ap, rhs); assertEquals("cp == qp: ", qp.monic(), cp.monic()); assertEquals("dp == rp: ", rp.monic(), dp.monic()); //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); assertEquals("ep == qp: ", ep.monic(), cp.monic()); assertEquals("fp == rp: ", fp.monic(), dp.monic()); } /** * Test recursive pseudo division. * @see edu.jas.ufd.PolyUfdUtilTest#testRecursivePseudoDivisionSparse */ public void testRecursivePseudoDivision() { //String[] cnames = new String[] { "x" }; //String[] mnames = new String[] { "t" }; String[] names = new String[] { "t", "x", "y", "z" }; rdfac = new GenSolvablePolynomialRing(new BigRational(1), to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rsfac = (RecSolvablePolynomialRing) rdfac.recursive(1); q = 0.27f; kl = 1; ll = 3; arr = rrfac.random(kl, ll, el, q); //arr = rrfac.parse(" ( t + x + y ) z^2 + ( 2 x - 8 ) y^2 - ( 13 t^4 - 13 t^3 + t^2 + 2 t - 13 ) "); brr = rrfac.random(kl, ll, el, q); if (brr.isZERO()) { brr = rrfac.parse(" ( x - 2 ) z - ( t - y^2 + y ) "); } //System.out.println("FDQR: arr = " + arr); //System.out.println("FDQR: brr = " + brr); drr = FDUtil. recursivePseudoQuotient(arr, brr); crr = FDUtil. recursiveSparsePseudoRemainder(arr, brr); //System.out.println("FDQR: qr = " + drr); //System.out.println("FDQR: rr = " + crr); GenSolvablePolynomial>[] QR; QR = FDUtil. recursivePseudoQuotientRemainder(arr, brr); assertEquals("drr == QR[0]: ", drr, QR[0]); assertEquals("crr == QR[1]: ", crr, QR[1]); boolean t = FDUtil. isRecursivePseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("FDQR: ore(lc^n) a == q b + r: " + t); assertTrue("ore(lc^n) a = q b + r: " + crr, t); // ?? } /** * Test recursive division coefficient polynomial. */ public void testLeftAndRightRecursiveDivision() { //String[] names = new String[] { "t", "x", "y", "z" }; String[] names = new String[] { "y", "z" }; rdfac = new GenSolvablePolynomialRing(new BigRational(1), to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rrfac = rdfac.recursive(1); //System.out.println("\nrdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); GenSolvablePolynomial>[] QR; boolean t; // q = q; kl = 2; ll = 4; el = 5; arr = rrfac.random(kl, ll, el + 1, q); //arr = rrfac.parse("z^5 - ( 1260/551 y^2 - 143/35 y - 33/100 ) z - ( 1/3 y^2 + 419/299 y - 19/56 )"); // b * q + r: //arr = rrfac.parse("z^5 + z^2 - 1"); //System.out.println("arr = " + arr); brr = rrfac.random(kl, ll, el, q); //brr = rrfac.parse("z^3 - ( 377/140 y^2 + 211/232 y + 1213967/85560 )"); //brr = rrfac.parse("( y ) z^3 - ( 1 ) z + ( 2 )"); //System.out.println("brr = " + brr); abrr = arr.multiply(brr); //System.out.println("abrr = " + abrr); // exact left division drr = FDUtil. recursivePseudoQuotient(abrr, brr); crr = FDUtil. recursiveSparsePseudoRemainder(abrr, brr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); QR = FDUtil. recursivePseudoQuotientRemainder(abrr, brr); assertEquals("drr == QR[0]: ", drr, QR[0]); assertEquals("crr == QR[1]: ", crr, QR[1]); //t = PolyUtil. isRecursivePseudoQuotientRemainder(arr, brr, drr, crr); t = FDUtil. isRecursivePseudoQuotientRemainder(abrr, brr, drr, crr); //System.out.println("FDQR: ore(lc^n) a == q b + r: " + t); assertTrue("ore(lc^n) a = q b + r: " + crr, t); // ?? barr = brr.multiply(arr); //System.out.println("barr = " + barr); // exact right division QR = FDUtil. recursiveRightPseudoQuotientRemainder(barr, brr); drr = QR[0]; crr = QR[1]; //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); //assertEquals("drr == QR[0]: ", drr, QR[0]); //assertEquals("crr == QR[1]: ", crr, QR[1]); t = FDUtil. isRecursiveRightPseudoQuotientRemainder(barr, brr, drr, crr); //System.out.println("FDQR: a ore(lc^n) == q b + r: " + t); assertTrue("a ore(lc^n) = q b + r: " + crr, t); // ?? // left division QR = FDUtil. recursivePseudoQuotientRemainder(arr, brr); drr = QR[0]; crr = QR[1]; t = FDUtil. isRecursivePseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); assertTrue("ore(lc^n) a = b q + r: " + crr, t); // ?? // right division QR = FDUtil. recursiveRightPseudoQuotientRemainder(arr, brr); drr = QR[0]; crr = QR[1]; t = FDUtil. isRecursiveRightPseudoQuotientRemainder(arr, brr, drr, crr); //System.out.println("drr = " + drr); //System.out.println("crr = " + crr); assertTrue("ore(lc^n) a = q p + r: " + crr, t); // ?? } /** * Test recursive right coefficient polynomial. */ //@SuppressWarnings("unchecked") public void testRightRecursivePolynomial() { //String[] names = new String[] { "t", "x", "y", "z" }; String[] names = new String[] { "y", "z" }; rdfac = new GenSolvablePolynomialRing(new BigRational(1), to, names); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); rrfac = rdfac.recursive(1); //System.out.println("\nrdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); //GenSolvablePolynomialRing cfac = (GenSolvablePolynomialRing) rrfac.coFac; //System.out.println("cfac = " + cfac.toScript()); // q = q; kl = 3; ll = 5; el = 5; arr = rrfac.random(kl, ll, el, q); //arr = rrfac.parse(" z { y } "); //System.out.println("FDQR: arr = " + arr); brr = arr.rightRecursivePolynomial(); //System.out.println("FDQR: brr = " + brr); boolean t = arr.isRightRecursivePolynomial(brr); assertTrue("arr == eval(brr): ", t); GenSolvablePolynomial c = (GenSolvablePolynomial) rrfac .random(kl, ll, el, q).leadingBaseCoefficient(); //c = cfac.parse("y**2"); //System.out.println("FDQR: c = " + c); drr = arr.multiply(c); // arr * c = drr //System.out.println("FDQR: drr = " + drr); //err = FDUtil. recursiveLeftDivide(drr, c); // err * c = drr //System.out.println("FDQR: err = " + err); //assertEquals("arr == err: ", arr, err); //System.out.println("\nFDQR: arr = " + arr); drr = arr.multiplyLeft(c); // c * arr = drr //System.out.println("FDQR: drr = " + drr); //err = FDUtil. recursiveRightDivide(drr, c); // c * err = drr //todo: System.out.println("FDQR: err = " + err); //assertEquals("arr == err: ", arr, err); } /** * Test exact division of recursive polynomials. */ //@SuppressWarnings({ "cast" }) public void testRecursiveDivide() { rdfac = new GenSolvablePolynomialRing(new BigRational(1), dfac); RelationGenerator wl = new WeylRelationsIterated(); rdfac.addRelations(wl); //System.out.println("rdfac = " + rdfac.toScript()); rsfac = (RecSolvablePolynomialRing) rdfac.recursive(1); //System.out.println("rsfac = " + rsfac.toScript()); assertFalse("isCommutative()", rsfac.isCommutative()); assertTrue("isAssociative()", rsfac.isAssociative()); do { as = rsfac.random(kl, ll, el, q); } while (as.isZERO()); //System.out.println("as = " + as); do { bs = rsfac.random(kl, ll, el, q); } while (bs.isZERO()); //System.out.println("bs = " + bs); // non commutative cs = bs.multiply(as); ds = as.multiply(bs); //System.out.println("cs = " + cs); //System.out.println("ds = " + ds); assertTrue("cs != 0: ", !cs.isZERO()); assertTrue("ds != 0: ", !ds.isZERO()); //es = (RecSolvablePolynomial) ds.subtract(cs); assertTrue("as*bs != bs*as", !cs.equals(ds) || cs.leadingExpVector().equals(ds.leadingExpVector())); // divide es = (RecSolvablePolynomial) FDUtil. recursivePseudoQuotient(cs, as); //System.out.println("es = " + es); final int max = 4; int i = 0; do { x1 = (RecSolvablePolynomial) bs.multiplyLeft(as.leadingBaseCoefficient().power(i)); //System.out.println("lc(a)^"+i+"*b = " + x1); if (es.equals(x1)) { assertEquals("b == b*a/a: ", es, x1); break; } if (es.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { // assertEquals("b == b*a/a: ", e, x1); System.out.println("fail: b == b*a/a: lc(e)==lc(x1)"); if (es.abs().equals(bs.abs())) { System.out.println("success via pseudo: b == b*a/a: "); } break; } } while (i++ < max); fs = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(cs, bs); //System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bs.leadingBaseCoefficient().power(i)); //System.out.println("a*lc(b)^"+i+" = " + x1); if (fs.equals(x1)) { assertEquals("a == b*a/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: a == b*a/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { System.out.println("success via pseudo: a == b*a/b: "); } break; } } while (i++ < max); es = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(ds, as); //System.out.println("es = " + es); i = 0; do { x1 = (RecSolvablePolynomial) bs.multiply(as.leadingBaseCoefficient().power(i)); //System.out.println("b*lc(a)^"+i+" = " + x1); if (es.equals(x1)) { assertEquals("b == a*b/a: ", es, x1); break; } if (es.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: b == a*b/a: lc(e) == lc(x1)"); if (es.abs().equals(bs.abs())) { //System.out.println("success via pseudo: b == a*b/a: "); } break; } } while (i++ < max); fs = (RecSolvablePolynomial) FDUtil. recursivePseudoQuotient(ds, bs); //System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiplyLeft(bs.leadingBaseCoefficient().power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { System.out.println("success via pseudo: a == a*b/b: "); } break; } } while (i++ < max); GenSolvablePolynomial bc = (GenSolvablePolynomial) bs.leadingBaseCoefficient(); ds = (RecSolvablePolynomial) as.multiply(bc); fs = (RecSolvablePolynomial) FDUtil. recursiveDivide(ds, bc); //System.out.println("bc = " + bc); //System.out.println("ds = " + ds); //System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bc.power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { System.out.println("success via pseudo: a == a*b/b: "); } break; } } while (i++ < max); bc = (GenSolvablePolynomial) bs.leadingBaseCoefficient(); ds = (RecSolvablePolynomial) as.multiply(bc); fs = (RecSolvablePolynomial) FDUtil. recursiveLeftDivide(ds, bc); //System.out.println("bc = " + bc); //System.out.println("ds = " + ds); //System.out.println("fs = " + fs); i = 0; do { x1 = (RecSolvablePolynomial) as.multiply(bc.power(i)); //System.out.println("lc(b)^"+i+"*a = " + x1); if (fs.equals(x1)) { assertEquals("a == a*b/b: ", fs, x1); break; } if (fs.leadingBaseCoefficient().equals(x1.leadingBaseCoefficient())) { System.out.println("fail: a == a*b/b: lc(f)==lc(x1)"); if (fs.abs().equals(as.abs())) { System.out.println("success via pseudo: a == a*b/b: "); } break; } } while (i++ < max); } /** * Test integer polynomial conversions. */ public void testIntConversion() { //System.out.println("dfac = " + dfac.toScript()); //System.out.println("rdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); rfac = dfac.recursive(2); // avoid polCoeff //System.out.println("rfac = " + rfac.toScript()); assertFalse("isCommutative()", rfac.isCommutative()); assertTrue("isAssociative()", rfac.isAssociative()); GenSolvablePolynomialRing ifac = (GenSolvablePolynomialRing) rfac.coFac; //System.out.println("ifac = " + ifac.toScript()); SolvableQuotientRing qfac = new SolvableQuotientRing(ifac); //System.out.println("qfac = " + qfac.toScript()); GenSolvablePolynomialRing> iqfac = new GenSolvablePolynomialRing>(qfac, rfac); //System.out.println("iqfac = " + iqfac.toScript()); List>> irel = rfac.table.relationList(); //System.out.println("irel = " + irel); List>> qrel; qrel = FDUtil. quotientFromIntegralCoefficients(iqfac, irel); //System.out.println("qrel = " + qrel); assertEquals("#irel == #qrel: ", irel.size(), qrel.size()); iqfac.table.addSolvRelations(qrel); //System.out.println("iqfac = " + iqfac.toScript()); assertFalse("isCommutative()", iqfac.isCommutative()); //assertTrue("isAssociative()", iqfac.isAssociative()); //extLeftGB is missing List>> iqrel; iqrel = FDUtil. integralFromQuotientCoefficients(rfac, qrel); //System.out.println("iqrel = " + iqrel); assertEquals("#qrel == #iqrel: ", qrel.size(), iqrel.size()); assertEquals("irel == iqrel: ", irel, iqrel); // not possible because of missing extLeftGB for pseudo GB: // iqfac.random(kl, ll, el, q); } /** * Test rational polynomial conversions. */ public void testRatConversion() { ////System.out.println("dfac = " + dfac.toScript()); //System.out.println("rdfac = " + rdfac.toScript()); //System.out.println("rrfac = " + rrfac.toScript()); rrfac = rdfac.recursive(2); // avoid polCoeff //System.out.println("rrfac = " + rrfac.toScript()); assertFalse("isCommutative()", rrfac.isCommutative()); assertTrue("isAssociative()", rrfac.isAssociative()); GenSolvablePolynomialRing irfac = (GenSolvablePolynomialRing) rrfac.coFac; //System.out.println("irfac = " + irfac.toScript()); SolvableQuotientRing qfac = new SolvableQuotientRing(irfac); //System.out.println("qfac = " + qfac.toScript()); GenSolvablePolynomialRing> rqfac = new GenSolvablePolynomialRing>(qfac, rrfac); //System.out.println("rqfac = " + rqfac.toScript()); List>> rrel = rrfac.table.relationList(); //System.out.println("rrel = " + rrel); List>> qrel; qrel = FDUtil. quotientFromIntegralCoefficients(rqfac, rrel); //System.out.println("qrel = " + qrel); assertEquals("#rrel == #qrel: ", rrel.size(), qrel.size()); rqfac.table.addSolvRelations(qrel); //System.out.println("rqfac = " + rqfac.toScript()); assertFalse("isCommutative()", rqfac.isCommutative()); assertTrue("isAssociative()", rqfac.isAssociative()); List>> rqrel; rqrel = FDUtil. integralFromQuotientCoefficients(rrfac, qrel); //System.out.println("rqrel = " + rqrel); assertEquals("#rrel == #rqrel: ", rrel.size(), rqrel.size()); assertEquals("rrel == rqrel: ", rrel, rqrel); kl = 1; q = 0.3f; //System.out.println("kl = " + kl + ", ll = " + ll + ", el = " + el + ", q = " + q); GenSolvablePolynomial> aq, bq, cq, dq; do { aq = rqfac.random(kl, ll, el, q); } while (aq.isZERO()); do { bq = rqfac.random(kl, ll, el, q/2f); } while (bq.isZERO()); //System.out.println("aq = " + aq); //System.out.println("bq = " + bq); // non commutative cq = bq.multiply(aq); dq = aq.multiply(bq); //System.out.println("cq = " + cq); //System.out.println("dq = " + dq); assertTrue("cq != 0: ", !cq.isZERO()); assertTrue("dq != 0: ", !dq.isZERO()); assertTrue("aq*bq != bq*aq", !cq.equals(dq) || cq.leadingExpVector().equals(dq.leadingExpVector())); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDFakeTest.java000066400000000000000000000620041445075545500231420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Fake PRS algorithm tests with JUnit. Note: not in sync with * implementation. * @author Heinz Kredel */ public class GCDFakeTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDFakeTest object. * @param name String. */ public GCDFakeTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDFakeTest.class); return suite; } GreatestCommonDivisorAbstract fd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenSolvablePolynomialRing dfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e; GenSolvablePolynomial> ar, br, cr, dr, er, ar0, br0; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigRational cf = new BigRational(1); fd = new GreatestCommonDivisorFake(cf); dfac = new GenSolvablePolynomialRing(cf, rl, to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("dfac = " + dfac); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; dfac = null; rfac = null; } /** * Test base gcd simple. */ public void testBaseGcdFake() { String[] uvars = new String[] { "x" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), 1, to, uvars); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 1), ll + i, el + 2, q); c = dfac.random(kl * (i + 1), ll + 1, el + 1, q); c = c.multiply(dfac.univariate(0)); if (c.isZERO()) { // skip for this turn continue; } //a = fd.basePrimitivePart(a); //b = fd.basePrimitivePart(b); //c = (GenSolvablePolynomial) fd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); d = fd.leftBaseGcd(a, b); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO() || d.isONE()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test univariate recursive left gcd simple. */ @SuppressWarnings("cast") public void testRecursiveLeftGCDFake() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; ll = 3; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //cr = rfac.parse("a+b+c+d"); //ar = rfac.parse("( ( -31/19 ) ) b^3 - ( 781/260 a - 641/372 )"); //br = rfac.parse("( ( -1/5 ) a - 1/4 ) b^2 - 11/12 b - ( 47/17 a + 29/30 )"); //cr = rfac.parse(" ( a + 9/8 ) b + ( 285/208 a + 191/280 )"); //ar = rfac.parse("b^3 - ( a )"); //br = rfac.parse("( a ) b^2 - 1/2 b"); //cr = rfac.parse("b + ( a )"); //ar = rfac.parse("( 2/23 a - 1/2 ) b^3 + 617/672 b^2 - ( 5 a + 307/154 )"); //br = rfac.parse("( ( -673/330 ) ) b - ( 2/5 a - 566969/1651860 )"); //cr = rfac.parse("( a - 2287945/213324 )"); //ar = rfac.parse("( b^2 + 1/2 )"); //br = rfac.parse("( a^2 b - ( a - 1/3 ) )"); //cr = rfac.parse("( b + a - 1/5 )"); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO() || dr.isONE()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); //if (true) return; GenSolvablePolynomial> ap, bp, cp, dp, gp, ep, apm, bpm, cpm, dpm, gpm; ap = FDUtil. quotientFromIntegralCoefficients(rqfac, ar); bp = FDUtil. quotientFromIntegralCoefficients(rqfac, br); cp = FDUtil. quotientFromIntegralCoefficients(rqfac, cr); dp = FDUtil. quotientFromIntegralCoefficients(rqfac, dr); apm = ap.monic(); bpm = bp.monic(); cpm = cp.monic(); dpm = dp.monic(); //System.out.println("ap = " + ap); //System.out.println("apm = " + apm); //System.out.println("bp = " + bp); //System.out.println("bpm = " + bpm); //System.out.println("cp = " + cp); //System.out.println("cpm = " + cpm); //System.out.println("dp = " + dp); //System.out.println("dpm = " + dpm); assertTrue("", apm.leadingBaseCoefficient().isONE()); assertTrue("", bpm.leadingBaseCoefficient().isONE()); assertTrue("", cpm.leadingBaseCoefficient().isONE()); assertTrue("", dpm.leadingBaseCoefficient().isONE()); GreatestCommonDivisorAbstract> fdq = new GreatestCommonDivisorFake>( qfac); gp = fdq.leftBaseGcd(ap, bp); gpm = gp.monic(); //System.out.println("gp = " + gp); //System.out.println("gpm = " + gpm); assertTrue("", gpm.leadingBaseCoefficient().isONE()); ep = FDUtil.> leftBaseSparsePseudoRemainder(gp, dp); //System.out.println("ep = " + ep); assertTrue("c | gcd(ac,bc): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(ap, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| ac): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(bp, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| bc): " + ep, ep.isZERO()); } /** * Test univariate recursive right gcd simple. */ @SuppressWarnings("cast") public void testRecursiveRightGCDFake() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; int ll = 3; int el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } ar = cr.multiply(ar); br = cr.multiply(br); //ar = ar.multiply(cr); //br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //er = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(dr, cr); //System.out.println("dr/cr = " + er); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO() || dr.isONE()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test arbitrary recursive gcd simple. */ @SuppressWarnings("cast") public void testArbitraryRecursiveGCDFake() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, cvars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = new RecSolvablePolynomialRing(dfac, to, vars); //System.out.println("rfac = " + rfac.toScript()); //kl = 3; ll = 2; int el = 2; ar0 = rfac.random(kl, ll, el + 1, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //ar = rfac.parse("a + b c^2 "); //br = rfac.parse("( a^2 - 1/3 ) c - 1/4"); //cr = rfac.parse("(b - 1/2 a^2) c"); //ar = rfac.parse("( 2/11 a * b^2 + 11/24 b - 11/6 a^2 )"); //br = rfac.parse("( 14/13 b^2 - 1/69 )"); //cr = rfac.parse("c + 33/133 a"); //ar0 = rfac.parse("( a * b^2 + 1/2 b - 1/6 a^2 )"); //br0 = rfac.parse("( b^2 - 1/5 )"); //cr = rfac.parse("c + 3/13 a"); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO() || dr.isONE()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc " + er, er.isZERO()); // right gcd ar = cr.multiply(ar0); br = cr.multiply(br0); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + er, er.isZERO() || dr.isONE()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | ca " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | cb " + er, er.isZERO()); } /** * Test full gcd simple, 4 variables. */ public void testGCDFake() { String[] vars = new String[] { "a", "b", "c", "d" }; //String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); //RelationGenerator wl = new WeylRelations(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); //kl = 3; ll = 4; el = 4; //a = dfac.random(kl, ll, el, q); //b = dfac.random(kl, ll, el, q); //c = dfac.random(kl, ll, el, q); //c = c.multiply(dfac.univariate(0)); a0 = dfac.parse("b^3 - 1/6 + d"); b0 = dfac.parse("b + 3 a^2 + d"); //b = dfac.parse("( -1/2 ) b + 3 a^2 + d"); //c = dfac.parse("(a - 5 b) + c + d"); //ok: c = dfac.parse("(a - b) c"); //c = dfac.parse("(a - b) + c + d "); //c = dfac.parse("(a - b) + c"); //c = dfac.parse("(a - b) + b^2"); c = dfac.parse("c - a - b"); //c = dfac.parse("d - c - b - a"); //c = dfac.parse("(a - b) + d"); //c = dfac.parse("b + d"); //c = dfac.parse("a + d"); //a = dfac.parse("2 b^3 * d^2 + 2/3 a + 3/2"); //b = dfac.parse("2/3 d + 1/2 a^3 + 3/4"); //c = dfac.parse("c^2 * d - 1/2 a^3 * d + 5/4 d"); //c = (GenSolvablePolynomial) fd.primitivePart(c).abs(); c = c.monic(); if (c.isZERO()) { c = dfac.getONE(); } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a0.multiply(c); b = b0.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); List> L = new ArrayList>(); L.add(a); L.add(b); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); // left List> Llgb = sbb.leftGB(L); //System.out.println("leftGB = " + Llgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.leftGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("d in leftGB", sbb.sred.leftNormalform(Llgb, d).isZERO() || d.isONE()); e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO() || d.isONE()); e = FDUtil. leftBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); // right a = c.multiply(a0); b = c.multiply(b0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> Lrgb = sbb.rightGB(L); // too long //System.out.println("rightGB = " + Lrgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.rightGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO() || d.isONE()); e = FDUtil. rightBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); } /** * Test rational coefficients gcd polynomial cofactor tests. */ public void testRatCofactors() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll*2, el, q); } while (a.isZERO()||a.isConstant()); do { b = dfac.random(kl, ll*2, el, q/2f); } while (b.isZERO()||b.isConstant()); do { c = dfac.random(kl, ll, el, q); } while (c.isZERO()||c.isConstant()); c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // non commutative left //System.out.println("right: "); d = c.multiply(a); e = c.multiply(b); //System.out.println("d = " + d); //System.out.println("e = " + e); GenSolvablePolynomial[] gco = fd.leftGcdCofactors(dfac, d, e); //System.out.println("left gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ca, cb; ca = gco[0].multiply(gco[1]); cb = gco[0].multiply(gco[2]); //System.out.println("ca = " + ca); //System.out.println("d = " + d); //System.out.println("cb = " + cb); //System.out.println("e = " + e); assertEquals("ca = c*a: ", ca, d); assertEquals("cb = c*b: ", cb, e); // non commutative right //System.out.println("left: "); d = a.multiply(c); e = b.multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); gco = fd.rightGcdCofactors(dfac, d, e); //System.out.println("right gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ac, bc; ac = gco[1].multiply(gco[0]); bc = gco[2].multiply(gco[0]); //System.out.println("ac = " + ac); //System.out.println("d = " + d); //System.out.println("bc = " + bc); //System.out.println("e = " + e); assertEquals("ac = a*c: ", ac, d); assertEquals("bc = b*c: ", bc, e); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDPrimitiveQuatTest.java000066400000000000000000000312701445075545500251000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Primitive PRS algorithm tests with JUnit. Note: eventually not in * sync with implementation. * @author Heinz Kredel */ public class GCDPrimitiveQuatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDPrimitiveQuatTest object. * @param name String. */ public GCDPrimitiveQuatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDPrimitiveQuatTest.class); return suite; } GreatestCommonDivisorAbstract fd; TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing qfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e, f; GenSolvablePolynomial> ar, br, cr, dr, er, ar0, br0; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigQuaternionRing cf = new BigQuaternionRing(); fd = new GreatestCommonDivisorPrimitive(cf); //System.out.println("fd = " + fd); qfac = new GenSolvablePolynomialRing(cf, to, vars); RelationGenerator wl = new WeylRelationsIterated(); //qfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("qfac = " + qfac); //System.out.println("rfac = " + rfac); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; qfac = null; rfac = null; } /** * Test quaternion base gcd simple. */ public void testQuatBaseGcdPrimitive() { String[] uvars = new String[] { "x" }; BigQuaternionRing cf = new BigQuaternionRing(); qfac = new GenSolvablePolynomialRing(cf, to, uvars); //System.out.println("qfac = " + qfac.toScript()); for (int i = 0; i < 3; i++) { //System.out.println(); a = qfac.random(kl + (i), ll + 2 * i, el + 2, q); a = (GenSolvablePolynomial) a.sum(qfac.univariate(0).power(2)); b = qfac.random(kl + (i + 1), ll + i, el + 2, q); b = (GenSolvablePolynomial) b.sum(qfac.univariate(0)); c = qfac.random(kl + (i + 1), ll + 1, el + 1, q); c = c.multiply(qfac.univariate(0)); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } a = a.monic(); b = b.monic(); c = c.monic(); //a = fd.basePrimitivePart(a); //b = fd.basePrimitivePart(b); //c = (GenSolvablePolynomial) fd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); //a = c.multiply(a); //b = c.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); d = fd.leftBaseGcd(a, b); //System.out.println("d = " + d); //System.out.println("c = " + c); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(ca,cb) | ca " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(ca,cb) | cb " + e, e.isZERO()); // todo //e = FDUtil. leftBaseSparsePseudoRemainder(d, c); e = FDUtil. leftBaseSparsePseudoRemainder(c, d); //System.out.println("e = " + e); assertTrue("c | gcd(ca,cb) " + e, e.isZERO()); } } /** * Test quaternion univariate recursive left gcd simple. */ //@SuppressWarnings("cast") public void testRecursiveLeftGCDPrimitive() { String[] vars = new String[] { "a", "b" }; BigQuaternionRing cf = new BigQuaternionRing(); //GenSolvablePolynomialRing qfac; qfac = new GenSolvablePolynomialRing(cf, to, vars); //System.out.println("qfac = " + qfac.toScript()); RelationGenerator wl = new WeylRelationsIterated(); //qfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorPrimitive(cf); //System.out.println("fd = " + fd); //kl = 3; int ll = 3; int el = 3; ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); //cr = PolyUtil. monic(cr); // leftMonic //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("cr = " + cr); //ar0 = ar; //br0 = br; //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr_r = " + cr); //System.out.println("dr_r = " + dr); //dr = PolyUtil. monic(dr); // leftMonic //System.out.println("monic(dr_r) = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test quaternion univariate recursive left gcd simple Weyl. */ //@SuppressWarnings("cast") public void testRecursiveLeftGCDPrimitiveWeyl() { String[] vars = new String[] { "a", "b" }; BigQuaternionRing cf = new BigQuaternionRing(); //GenSolvablePolynomialRing qfac; qfac = new GenSolvablePolynomialRing(cf, to, vars); //System.out.println("qfac = " + qfac.toScript()); RelationGenerator wl = new WeylRelationsIterated(); qfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorPrimitive(cf); //System.out.println("fd = " + fd); //kl = 3; ll = 2; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); ///cr = PolyUtil. monic(cr); // leftMonic //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("cr = " + cr); //ar0 = ar; //br0 = br; //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr_w = " + cr); //System.out.println("dr_w = " + dr); //dr = PolyUtil. monic(dr); // leftMonic //System.out.println("monic(dr_w) = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test 3 vars arbitrary recursive gcd simple. */ @SuppressWarnings("cast") public void testArbitrary3RecursiveGCDPrimitive() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; BigQuaternionRing cf = new BigQuaternionRing(); qfac = new GenSolvablePolynomialRing(cf, to, cvars); RelationGenerator wl = new WeylRelationsIterated(); //dfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = new RecSolvablePolynomialRing(qfac, to, vars); //System.out.println("rfac = " + rfac.toScript()); //kl = 3; int ll = 2; int el = 2; ar0 = rfac.random(kl, ll, el, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //ar0 = rfac.parse(" "); //br0 = rfac.parse(" "); //cr = rfac.parse(" "); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc): " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac: " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc: " + er, er.isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDPrimitiveTest.java000066400000000000000000000661741445075545500242600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.List; import java.util.ArrayList; import edu.jas.arith.BigRational; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Primitive PRS algorithm tests with JUnit. Note: not in sync with * implementation. * @author Heinz Kredel */ public class GCDPrimitiveTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDPrimitiveTest object. * @param name String. */ public GCDPrimitiveTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDPrimitiveTest.class); return suite; } GreatestCommonDivisorAbstract fd, fds; TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing dfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e, a1, b1; GenSolvablePolynomial> ar, br, ar0, br0, cr, dr, er, sr; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigRational cf = new BigRational(1); fd = new GreatestCommonDivisorPrimitive(cf); fds = new GreatestCommonDivisorSimple(cf); dfac = new GenSolvablePolynomialRing(cf, to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; dfac = null; rfac = null; } /** * Test base gcd primitive. */ public void testBaseGcdPrimitive() { String[] uvars = new String[] { "x" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, uvars); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); c = dfac.random(kl * (i + 2), ll + 2, el + 2, q); c = c.multiply(dfac.univariate(0)); if (c.isZERO()) { // skip for this turn continue; } //a = fd.leftBasePrimitivePart(a); //b = fd.leftBasePrimitivePart(b); c = (GenSolvablePolynomial) fd.leftBasePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //assertTrue("length( c" + i + " ) <> 0", c.length() > 0); a = a.multiply(c); b = b.multiply(c); d = fd.leftBaseGcd(a, b); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test univariate recursive left gcd primitive. */ @SuppressWarnings("cast") public void testRecursiveLeftGCDPrimitive() { //String[] vars = new String[] { "a", "b", "c", "d" }; String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; ll = 4; // el = 2; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //cr = rfac.parse("a+b+c+d"); //ar = rfac.parse("1/3 b^3 - 1/6"); //ar = rfac.parse("1/3 b^2 - 1/6"); //br = rfac.parse("( -1/2 ) b + 3 a"); //nok: cr = rfac.parse("b * a - 5 b"); //cr = rfac.parse("a - 5"); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (br.isZERO() || cr.isZERO()) { br = rfac.parse("( -1/2 ) b + 3 a"); cr = rfac.parse("a * b - 5 b"); } //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //if (true) return; long ts = System.currentTimeMillis(); //sr = rfac.getONE(); sr = fds.leftRecursiveUnivariateGcd(ar, br); ts = System.currentTimeMillis() - ts; //System.out.println("cr = " + cr); long tp = System.currentTimeMillis(); dr = fd.leftRecursiveUnivariateGcd(ar, br); tp = System.currentTimeMillis() - tp; //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //System.out.println("sr = " + sr); //System.out.println("time: ts = " + ts + ", tp = " + tp); assertTrue("time: ts = " + ts + ", tp = " + tp, ts + tp >= 0); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc): " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac: " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc: " + er, er.isZERO()); GenSolvablePolynomial> ap, bp, dp, gp, ep; // cp, apm, bpm, cpm, dpm, gpm; ap = FDUtil. quotientFromIntegralCoefficients(rqfac, ar); bp = FDUtil. quotientFromIntegralCoefficients(rqfac, br); //cp = FDUtil. quotientFromIntegralCoefficients(rqfac, cr); dp = FDUtil. quotientFromIntegralCoefficients(rqfac, dr); //apm = ap.monic(); //bpm = bp.monic(); //cpm = cp.monic(); //dpm = dp.monic(); //System.out.println("ap = " + ap); //System.out.println("apm = " + apm); //System.out.println("bp = " + bp); //System.out.println("bpm = " + bpm); //System.out.println("cp = " + cp); //System.out.println("cpm = " + cpm); //System.out.println("dp = " + dp); //System.out.println("dpm = " + dpm); GreatestCommonDivisorAbstract> fdq = new GreatestCommonDivisorPrimitive>( qfac); gp = fdq.leftBaseGcd(ap, bp); //gpm = gp.monic(); //System.out.println("gp = " + gp); //System.out.println("gpm = " + gpm); ep = FDUtil.> leftBaseSparsePseudoRemainder(gp, dp); //System.out.println("ep = " + ep); assertTrue("c | gcd(ac,bc): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(ap, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| ac): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(bp, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| bc): " + ep, ep.isZERO()); } /** * Test univariate recursive right gcd primitive. */ @SuppressWarnings("cast") public void testRecursiveRightGCDPrimitive() { //String[] vars = new String[] { "a", "b", "c", "d" }; String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; ll = 4; // el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //cr = rfac.parse("a+b+c+d"); //ar = rfac.parse("1/3 b^3 - 1/6"); //ar = rfac.parse("1/3 b^2 - 1/6"); //br = rfac.parse("( -1/2 ) b + 3 a"); //nok: cr = rfac.parse("b * a - 5 b"); //cr = rfac.parse("a - 5"); //ar = rfac.parse("359/95 a b^2 + 275/124 a"); //br = rfac.parse("814/189 b + 135/44 a"); //cr = rfac.parse("b - 612/25"); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (br.isZERO() || cr.isZERO()) { br = rfac.parse("( -1/2 ) b + 3 a"); cr = rfac.parse("a * b - 5 b"); } ar = cr.multiply(ar); br = cr.multiply(br); //System.out.println("ar = " + ar); //System.out.println("br = " + br); // todo: if (!rfac.getONE().isZERO()) return; long ts = System.currentTimeMillis(); //sr = rfac.getONE(); sr = fds.rightRecursiveUnivariateGcd(ar, br); ts = System.currentTimeMillis() - ts; //System.out.println("cr = " + cr); long tp = System.currentTimeMillis(); dr = fd.rightRecursiveUnivariateGcd(ar, br); tp = System.currentTimeMillis() - tp; //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //System.out.println("sr = " + sr); //System.out.println("time: ts = " + ts + ", tp = " + tp); assertTrue("time: ts = " + ts + ", tp = " + tp, ts + tp >= 0); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb): " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | ca: " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | cb: " + er, er.isZERO()); } /** * Test arbitrary recursive gcd primitive. */ @SuppressWarnings("cast") public void testArbitraryRecursiveGCDPrimitive() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, cvars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = new RecSolvablePolynomialRing(dfac, to, vars); //rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); //kl = 3; ll = 2; el = 2; ar0 = rfac.random(kl, ll, el + 1, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //ar0 = rfac.parse("a + b c^2 "); //br0 = rfac.parse("( a^2 - 1/3 ) c - 1/4"); //cr = rfac.parse("(b - 1/2 a^2) c"); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc): " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac: " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc: " + er, er.isZERO()); //todo: if (er.isZERO()) return; // right gcd ar = cr.multiply(ar0); br = cr.multiply(br0); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | ca " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | cb " + er, er.isZERO()); } /** * Test full gcd primitive. */ public void testGCDPrimitive() { String[] vars = new String[] { "a", "b", "c", "d" }; //String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); //kl = 3; ll = 4; el = 4; //a = dfac.random(kl, ll, el, q); //b = dfac.random(kl, ll, el, q); //c = dfac.random(kl, ll, el, q); //c = c.multiply(dfac.univariate(0)); a = dfac.parse("1/3 b^3 - 1/6 + d"); b = dfac.parse("( -1/2 ) b + 3 a^2 + d"); ////b = dfac.parse("( -1/2 ) b + 3 a^2 + c"); ////c = dfac.parse("(a - 5 b) + c + d"); ////ok: c = dfac.parse("(a - b) c"); ////c = dfac.parse("c (a - b)"); //c = dfac.parse("(a - b) + c + d "); c = dfac.parse("(a - b) + c"); //c = dfac.parse("(a - b) + b^3"); //c = dfac.parse("(a - b) + d"); //a = dfac.parse("2 b^3 * d^2 + 2/3 a + 3/2"); //b = dfac.parse("2/3 d + 1/2 a^3 + 3/4"); //c = dfac.parse("c^2 * d - 1/2 a^3 * d + 5/4 d"); //c = (GenSolvablePolynomial) fd.primitivePart(c).abs(); c = c.monic(); if (c.isZERO()) { c = dfac.getONE(); } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // left a0 = a; b0 = b; a = a0.multiply(c); b = b0.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); List> L = new ArrayList>(); L.add(a); L.add(b); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); // left List> Llgb = sbb.leftGB(L); //System.out.println("leftGB = " + Llgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); // todo: d = fd.leftGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); e = sbb.sred.leftNormalform(Llgb, d); assertTrue("d in leftGB: " + Llgb + ", " + d, e.isZERO()||e.equals(d)); //todo: e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); //assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b): | b " + e, e.isZERO()); // todo: if (e.isZERO()) return; // right a = c.multiply(a0); b = c.multiply(b0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> Lrgb = sbb.rightGB(L); // too long //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.rightGcd(a, b); //System.out.println("rightGB = " + Lrgb); System.out.println("c = " + c); System.out.println("d = " + d); //assertTrue("d in rightGB", sbb.sred.rightNormalform(Lrgb, d).isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); } /** * Test rational coefficients gcd polynomial cofactor tests. */ public void ztestRatCofactors() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll, el, q); } while (a.isZERO() || a.isConstant()); do { b = dfac.random(kl, ll, el, q / 2f); } while (b.isZERO() || b.isConstant()); do { c = dfac.random(kl, ll, el, q / 2f); } while (c.isZERO() || c.isConstant()); c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // non commutative left //System.out.println("left: "); d = c.multiply(a); e = c.multiply(b); //System.out.println("d = " + d); //System.out.println("e = " + e); GenSolvablePolynomial[] gco = fd.leftGcdCofactors(dfac, d, e); //System.out.println("left gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ca, cb; ca = gco[0].multiply(gco[1]); cb = gco[0].multiply(gco[2]); //System.out.println("ca = " + ca); //System.out.println("d = " + d); //System.out.println("cb = " + cb); //System.out.println("e = " + e); assertEquals("ca = c*a: ", ca, d); assertEquals("cb = c*b: ", cb, e); // non commutative right //System.out.println("right: "); d = a.multiply(c); e = b.multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); gco = fd.rightGcdCofactors(dfac, d, e); //System.out.println("right gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ac, bc; ac = gco[1].multiply(gco[0]); bc = gco[2].multiply(gco[0]); //System.out.println("ac = " + ac); //System.out.println("d = " + d); //System.out.println("bc = " + bc); //System.out.println("e = " + e); assertEquals("ac = a*c: ", ac, d); assertEquals("bc = b*c: ", bc, e); } /** * Test co-prime factors. */ public void testCoPrime() { String[] vs = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vs); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); List> F = new ArrayList>(5); F.add(d); F.add(a); F.add(b); F.add(c); F.add(e); List> P = fd.leftCoPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", fd.isLeftCoPrime(P)); assertTrue("is co-prime of ", fd.isLeftCoPrime(P, F)); P = fd.leftCoPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", fd.isLeftCoPrime(P)); assertTrue("is co-prime of ", fd.isLeftCoPrime(P, F)); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDSimpleQuatTest.java000066400000000000000000000306471445075545500243700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Simple PRS algorithm tests with JUnit. Note: eventually not in * sync with implementation. * @author Heinz Kredel */ public class GCDSimpleQuatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDSimpleQuatTest object. * @param name String. */ public GCDSimpleQuatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSimpleQuatTest.class); return suite; } GreatestCommonDivisorAbstract fd; TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing qfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e, f; GenSolvablePolynomial> ar, br, cr, dr, er, ar0, br0; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigQuaternionRing cf = new BigQuaternionRing(); fd = new GreatestCommonDivisorSimple(cf); //System.out.println("fd = " + fd); qfac = new GenSolvablePolynomialRing(cf, to, vars); RelationGenerator wl = new WeylRelationsIterated(); //qfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("qfac = " + qfac); //System.out.println("rfac = " + rfac); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; qfac = null; rfac = null; } /** * Test quaternion base gcd simple. */ public void testQuatBaseGcdSimple() { String[] uvars = new String[] { "x" }; BigQuaternionRing cf = new BigQuaternionRing(); qfac = new GenSolvablePolynomialRing(cf, to, uvars); //System.out.println("qfac = " + qfac.toScript()); for (int i = 0; i < 3; i++) { //System.out.println(); a = qfac.random(kl + (i), ll + 2 * i, el + 2, q); a = (GenSolvablePolynomial) a.sum(qfac.univariate(0).power(2)); b = qfac.random(kl + (i + 1), ll + i, el + 2, q); b = (GenSolvablePolynomial) b.sum(qfac.univariate(0)); c = qfac.random(kl + (i + 1), ll + 1, el + 1, q); c = c.multiply(qfac.univariate(0)); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } a = a.monic(); b = b.monic(); c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); //a = c.multiply(a); //b = c.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); d = fd.leftBaseGcd(a, b); //System.out.println("d = " + d); //System.out.println("c = " + c); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(ca,cb) | ca " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(ca,cb) | cb " + e, e.isZERO()); // todo //e = FDUtil. leftBaseSparsePseudoRemainder(d, c); e = FDUtil. leftBaseSparsePseudoRemainder(c, d); //System.out.println("e = " + e); assertTrue("c | gcd(ca,cb) " + e, e.isZERO()); } } /** * Test quaternion univariate recursive left gcd simple. */ //@SuppressWarnings("cast") public void testRecursiveLeftGCDSimple() { String[] vars = new String[] { "a", "b" }; BigQuaternionRing cf = new BigQuaternionRing(); //GenSolvablePolynomialRing qfac; qfac = new GenSolvablePolynomialRing(cf, to, vars); //System.out.println("qfac = " + qfac.toScript()); RelationGenerator wl = new WeylRelationsIterated(); //qfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cf); //System.out.println("fd = " + fd); //kl = 3; ll = 3; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); ///cr = PolyUtil. monic(cr); // leftMonic //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("cr = " + cr); //ar0 = ar; //br0 = br; //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr_r = " + cr); //System.out.println("dr_r = " + dr); //dr = PolyUtil. monic(dr); // leftMonic //System.out.println("monic(dr_r) = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test quaternion univariate recursive left gcd simple Weyl. */ //@SuppressWarnings("cast") public void testRecursiveLeftGCDSimpleWeyl() { String[] vars = new String[] { "a", "b" }; BigQuaternionRing cf = new BigQuaternionRing(); //GenSolvablePolynomialRing qfac; qfac = new GenSolvablePolynomialRing(cf, to, vars); //System.out.println("qfac = " + qfac.toScript()); RelationGenerator wl = new WeylRelationsIterated(); qfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = (RecSolvablePolynomialRing) qfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); GreatestCommonDivisorAbstract fd = new GreatestCommonDivisorSimple(cf); System.out.println("fd = " + fd); //kl = 3; ll = 3; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); ///cr = PolyUtil. monic(cr); // leftMonic //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("cr = " + cr); //ar0 = ar; //br0 = br; //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr_w = " + cr); //System.out.println("dr_w = " + dr); //dr = PolyUtil. monic(dr); // leftMonic //System.out.println("monic(dr_w) = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test 3 vars arbitrary recursive gcd simple. */ @SuppressWarnings("cast") public void testArbitrary3RecursiveGCDSimple() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; BigQuaternionRing cf = new BigQuaternionRing(); qfac = new GenSolvablePolynomialRing(cf, to, cvars); RelationGenerator wl = new WeylRelationsIterated(); //dfac.addRelations(wl); //System.out.println("qfac = " + qfac.toScript()); rfac = new RecSolvablePolynomialRing(qfac, to, vars); System.out.println("rfac = " + rfac.toScript()); //kl = 3; int ll = 2; int el = 2; ar0 = rfac.random(kl, ll, el, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } if (cr.isConstant()) { er = rfac.univariate(0); System.out.println("univ(0) = " + er); cr = (RecSolvablePolynomial) cr.sum(er); } //System.out.println("cr = " + cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc): " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac: " + er, er.isZERO()); er = FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc: " + er, er.isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDSimpleTest.java000066400000000000000000000711201445075545500235240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Simple PRS algorithm tests with JUnit. Note: not in sync with * implementation. * @author Heinz Kredel */ public class GCDSimpleTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDSimpleTest object. * @param name String. */ public GCDSimpleTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSimpleTest.class); return suite; } GreatestCommonDivisorAbstract fd; TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing dfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e, f; GenSolvablePolynomial> ar, br, cr, dr, er, ar0, br0; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigRational cf = new BigRational(1); fd = new GreatestCommonDivisorSimple(cf); dfac = new GenSolvablePolynomialRing(cf, to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("dfac = " + dfac); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; dfac = null; rfac = null; } /** * Test base gcd simple. */ public void testBaseGcdSimple() { String[] uvars = new String[] { "x" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), 1, to, uvars); //System.out.println("dfac = " + dfac.toScript()); for (int i = 0; i < 3; i++) { //System.out.println(); a = dfac.random(kl + (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl + (i + 1), ll + i, el + 2, q); c = dfac.random(kl + (i + 1), ll + 1, el + 1, q); c = c.multiply(dfac.univariate(0)); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } //a = fd.basePrimitivePart(a); //b = fd.basePrimitivePart(b); //c = (GenSolvablePolynomial) fd.leftBasePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = fd.leftBaseGcd(a, b); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test base extended gcd simple. */ public void xtestBaseExtendedGcdSimple() { String[] uvars = new String[] { "x" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), 1, to, uvars); //System.out.println("dfac = " + dfac.toScript()); for (int i = 0; i < 3; i++) { //System.out.println(); a = dfac.random(kl + (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl + (i + 1), ll + i, el + 2, q); c = dfac.random(kl + (i + 1), ll + 1, el + 1, q); c = c.multiply(dfac.univariate(0)); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } //a = fd.basePrimitivePart(a); //b = fd.basePrimitivePart(b); //c = (GenSolvablePolynomial) fd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); // extended gcd GenSolvablePolynomial[] egcd = fd.baseExtendedGcd(a, b); //System.out.println("egcd = " + Arrays.toString(egcd)); d = egcd[0]; e = (GenSolvablePolynomial) a.multiply(egcd[1]).sum(b.multiply(egcd[2])); //System.out.println("e = " + e); f = (GenSolvablePolynomial) egcd[1].multiply(a).sum(egcd[2].multiply(b)); //System.out.println("f = " + f); assertEquals("e == f: ", e, f); //assertEquals("gcd(a,b) = s a + t b: " + f, d, f.monic()); assertTrue("gcd(a,b) = s a + t b: " + f, f.remainder(d).isZERO()); // todo //e = (GenSolvablePolynomial) FDUtil. leftBaseSparsePseudoRemainder(d,c); //System.out.println("d = " + d); //System.out.println("c = " + c); //assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); // diophant solution GenSolvablePolynomial[] dio = fd.baseGcdDiophant(a, b, d); //System.out.println("dio = " + Arrays.toString(dio)); e = (GenSolvablePolynomial) dio[0].multiply(a).sum(dio[1].multiply(b)); //System.out.println("e = " + e); f = (GenSolvablePolynomial) a.multiply(dio[0]).sum(b.multiply(dio[1])); //System.out.println("f = " + f); assertEquals("e == f: ", e, f); //assertEquals("a*d + b*e == f: ", d, f.monic()); //assertEquals("d*gcd(a,b) = s a + t b: : ", d, f.monic()); assertTrue("d*gcd(a,b) = s a + t b: ", f.remainder(d).isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(f, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | a*s + b*t " + e, e.isZERO()); } } /** * Test univariate recursive left gcd simple. */ @SuppressWarnings("cast") public void testRecursiveLeftGCDSimple() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; ll = 3; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //cr = rfac.parse("a+b+c+d"); //ar = rfac.parse("( ( -31/19 ) ) b^3 - ( 781/260 a - 641/372 )"); //br = rfac.parse("( ( -1/5 ) a - 1/4 ) b^2 - 11/12 b - ( 47/17 a + 29/30 )"); //cr = rfac.parse(" ( a + 9/8 ) b + ( 285/208 a + 191/280 )"); //ar = rfac.parse("b^3 - ( a )"); //br = rfac.parse("( a ) b^2 - 1/2 b"); //cr = rfac.parse("b + ( a )"); //ar = rfac.parse("( 2/23 a - 1/2 ) b^3 + 617/672 b^2 - ( 5 a + 307/154 )"); //br = rfac.parse("( ( -673/330 ) ) b - ( 2/5 a - 566969/1651860 )"); //cr = rfac.parse("( a - 2287945/213324 )"); //ar = rfac.parse("( b^2 + 1/2 )"); //br = rfac.parse("( a^2 b - ( a - 1/3 ) )"); //cr = rfac.parse("( b + a - 1/5 )"); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); //if (true) return; GenSolvablePolynomial> ap, bp, cp, dp, gp, ep, apm, bpm, cpm, dpm, gpm; ap = FDUtil. quotientFromIntegralCoefficients(rqfac, ar); bp = FDUtil. quotientFromIntegralCoefficients(rqfac, br); cp = FDUtil. quotientFromIntegralCoefficients(rqfac, cr); dp = FDUtil. quotientFromIntegralCoefficients(rqfac, dr); apm = ap.monic(); bpm = bp.monic(); cpm = cp.monic(); dpm = dp.monic(); //System.out.println("ap = " + ap); //System.out.println("apm = " + apm); //System.out.println("bp = " + bp); //System.out.println("bpm = " + bpm); //System.out.println("cp = " + cp); //System.out.println("cpm = " + cpm); //System.out.println("dp = " + dp); //System.out.println("dpm = " + dpm); assertTrue("", apm.leadingBaseCoefficient().isONE()); assertTrue("", bpm.leadingBaseCoefficient().isONE()); assertTrue("", cpm.leadingBaseCoefficient().isONE()); assertTrue("", dpm.leadingBaseCoefficient().isONE()); GreatestCommonDivisorAbstract> fdq = new GreatestCommonDivisorSimple>( qfac); gp = fdq.leftBaseGcd(ap, bp); gpm = gp.monic(); //System.out.println("gp = " + gp); //System.out.println("gpm = " + gpm); assertTrue("", gpm.leadingBaseCoefficient().isONE()); ep = FDUtil.> leftBaseSparsePseudoRemainder(gp, dp); //System.out.println("ep = " + ep); assertTrue("c | gcd(ac,bc): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(ap, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| ac): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(bp, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| bc): " + ep, ep.isZERO()); } /** * Test univariate recursive right gcd simple. */ @SuppressWarnings("cast") public void ztestRecursiveRightGCDSimple() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; int ll = 3; int el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } ar = cr.multiply(ar); br = cr.multiply(br); //ar = ar.multiply(cr); //br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //er = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(dr, cr); //System.out.println("dr/cr = " + er); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test arbitrary recursive gcd simple. */ @SuppressWarnings("cast") public void testArbitrary3RecursiveGCDSimple() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, cvars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = new RecSolvablePolynomialRing(dfac, to, vars); //System.out.println("rfac = " + rfac.toScript()); //kl = 3; ll = 2; int el = 2; ar0 = rfac.random(kl, ll, el + 1, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //ar = rfac.parse("a + b c^2 "); //br = rfac.parse("( a^2 - 1/3 ) c - 1/4"); //cr = rfac.parse("(b - 1/2 a^2) c"); //ar = rfac.parse("( 2/11 a * b^2 + 11/24 b - 11/6 a^2 )"); //br = rfac.parse("( 14/13 b^2 - 1/69 )"); //cr = rfac.parse("c + 33/133 a"); //ar0 = rfac.parse("( a * b^2 + 1/2 b - 1/6 a^2 )"); //br0 = rfac.parse("( b^2 - 1/5 )"); //cr = rfac.parse("c + 3/13 a"); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc): " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac: " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc: " + er, er.isZERO()); // true at this point if (er.isZERO()) return; // right gcd ar = cr.multiply(ar0); br = cr.multiply(br0); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | ca " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | cb " + er, er.isZERO()); } /** * Test full gcd simple, 4 variables. */ public void testGCD4Simple() { String[] vars = new String[] { "a", "b", "c", "d" }; //String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); //RelationGenerator wl = new WeylRelations(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); //kl = 3; ll = 4; el = 4; //a = dfac.random(kl, ll, el, q); //b = dfac.random(kl, ll, el, q); //c = dfac.random(kl, ll, el, q); //c = c.multiply(dfac.univariate(0)); a0 = dfac.parse("b^3 - 1/6 + d"); b0 = dfac.parse("b + 3 a^2 + d"); //b = dfac.parse("( -1/2 ) b + 3 a^2 + d"); //c = dfac.parse("(a - 5 b) + c + d"); //ok: c = dfac.parse("(a - b) c"); //c = dfac.parse("(a - b) + c + d "); //c = dfac.parse("(a - b) + c"); //c = dfac.parse("(a - b) + b^2"); c = dfac.parse("c - a - b"); //c = dfac.parse("d - c - b - a"); //c = dfac.parse("(a - b) + d"); //c = dfac.parse("b + d"); //c = dfac.parse("a + d"); //a = dfac.parse("2 b^3 * d^2 + 2/3 a + 3/2"); //b = dfac.parse("2/3 d + 1/2 a^3 + 3/4"); //c = dfac.parse("c^2 * d - 1/2 a^3 * d + 5/4 d"); //c = (GenSolvablePolynomial) fd.primitivePart(c).abs(); c = c.monic(); if (c.isZERO()) { c = dfac.getONE(); } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a0.multiply(c); b = b0.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); List> L = new ArrayList>(); L.add(a); L.add(b); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); // left List> Llgb = sbb.leftGB(L); //System.out.println("leftGB = " + Llgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.leftGcd(a, b); System.out.println("gb = " + Llgb); System.out.println("c = " + c); System.out.println("d = " + d); assertTrue("c in leftGB", sbb.sred.leftNormalform(Llgb, c).isZERO()); //todo: assertTrue("d in leftGB", sbb.sred.leftNormalform(Llgb, d).isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); //todo: e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); //assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); // todo: if (e.isZERO()) return; // right a = c.multiply(a0); b = c.multiply(b0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> Lrgb = sbb.rightGB(L); // too long //System.out.println("rightGB = " + Lrgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.rightGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); //assertTrue("d in rightGB", sbb.sred.rightNormalform(Lrgb, d).isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); } /** * Test rational coefficients gcd polynomial cofactor tests. */ public void ztestRatCofactors() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll, el, q); } while (a.isZERO() || a.isConstant()); do { b = dfac.random(kl, ll, el, q / 2f); } while (b.isZERO() || b.isConstant()); do { c = dfac.random(kl, ll, el, q / 2f); } while (c.isZERO() || c.isConstant()); c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // non commutative left //System.out.println("left: "); d = c.multiply(a); e = c.multiply(b); //System.out.println("d = " + d); //System.out.println("e = " + e); GenSolvablePolynomial[] gco = fd.leftGcdCofactors(dfac, d, e); //System.out.println("left gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ca, cb; ca = gco[0].multiply(gco[1]); cb = gco[0].multiply(gco[2]); System.out.println("ca = " + ca); System.out.println("d = " + d); System.out.println("cb = " + cb); System.out.println("e = " + e); assertEquals("ca = c*a: ", ca, d); assertEquals("cb = c*b: ", cb, e); if (ca.equals(d)) return; // non commutative right //System.out.println("right: "); d = a.multiply(c); e = b.multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); gco = fd.rightGcdCofactors(dfac, d, e); //System.out.println("right gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ac, bc; ac = gco[1].multiply(gco[0]); bc = gco[2].multiply(gco[0]); //System.out.println("ac = " + ac); //System.out.println("d = " + d); //System.out.println("bc = " + bc); //System.out.println("e = " + e); assertEquals("ac = a*c: ", ac, d); assertEquals("bc = b*c: ", bc, e); } } java-algebra-system-2.7.200/trc/edu/jas/fd/GCDSyzygyTest.java000066400000000000000000000617201445075545500236160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.poly.WeylRelationsIterated; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD via syzygy tests with JUnit. * @author Heinz Kredel */ public class GCDSyzygyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDSyzygyTest object. * @param name String. */ public GCDSyzygyTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSyzygyTest.class); return suite; } GreatestCommonDivisorAbstract fd; TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing dfac; //GenSolvablePolynomialRing> rfac; RecSolvablePolynomialRing rfac; GenSolvablePolynomial a, b, a0, b0, c, d, e; GenSolvablePolynomial> ar, br, cr, dr, er, ar0, br0; int rl = 4; int kl = 2; int ll = 2; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ar = br = cr = dr = er = null; String[] vars = new String[] { "a", "b", "c", "d" }; BigRational cf = new BigRational(1); fd = new GreatestCommonDivisorSimple(cf); //fd = new GreatestCommonDivisorSyzygy(cf); //todo dfac = new GenSolvablePolynomialRing(cf, to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("dfac = " + dfac); } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; fd = null; dfac = null; rfac = null; } /** * Test base gcd simple. */ public void testBaseGcdSimple() { String[] uvars = new String[] { "x" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), 1, to, uvars); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 1), ll + i, el + 2, q); c = dfac.random(kl * (i + 1), ll + 1, el + 1, q); c = c.multiply(dfac.univariate(0)); if (c.isZERO()) { // skip for this turn continue; } //a = fd.basePrimitivePart(a); //b = fd.basePrimitivePart(b); //c = (GenSolvablePolynomial) fd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); b = b.multiply(c); d = fd.leftBaseGcd(a, b); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = (GenSolvablePolynomial) PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test univariate recursive left gcd simple. */ @SuppressWarnings("cast") public void testRecursiveLeftGCDSyzygy() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; ll = 3; el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //cr = rfac.parse("a+b+c+d"); //ar = rfac.parse("( ( -31/19 ) ) b^3 - ( 781/260 a - 641/372 )"); //br = rfac.parse("( ( -1/5 ) a - 1/4 ) b^2 - 11/12 b - ( 47/17 a + 29/30 )"); //cr = rfac.parse(" ( a + 9/8 ) b + ( 285/208 a + 191/280 )"); //ar = rfac.parse("b^3 - ( a )"); //br = rfac.parse("( a ) b^2 - 1/2 b"); //cr = rfac.parse("b + ( a )"); //ar = rfac.parse("( 2/23 a - 1/2 ) b^3 + 617/672 b^2 - ( 5 a + 307/154 )"); //br = rfac.parse("( ( -673/330 ) ) b - ( 2/5 a - 566969/1651860 )"); //cr = rfac.parse("( a - 2287945/213324 )"); //ar = rfac.parse("( b^2 + 1/2 )"); //br = rfac.parse("( a^2 b - ( a - 1/3 ) )"); //cr = rfac.parse("( b + a - 1/5 )"); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } //ar = cr.multiply(ar); //br = cr.multiply(br); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); //if (true) return; GenSolvablePolynomial> ap, bp, cp, dp, gp, ep, apm, bpm, cpm, dpm, gpm; ap = FDUtil. quotientFromIntegralCoefficients(rqfac, ar); bp = FDUtil. quotientFromIntegralCoefficients(rqfac, br); cp = FDUtil. quotientFromIntegralCoefficients(rqfac, cr); dp = FDUtil. quotientFromIntegralCoefficients(rqfac, dr); apm = ap.monic(); bpm = bp.monic(); cpm = cp.monic(); dpm = dp.monic(); //System.out.println("ap = " + ap); //System.out.println("apm = " + apm); //System.out.println("bp = " + bp); //System.out.println("bpm = " + bpm); //System.out.println("cp = " + cp); //System.out.println("cpm = " + cpm); //System.out.println("dp = " + dp); //System.out.println("dpm = " + dpm); assertTrue("", apm.leadingBaseCoefficient().isONE()); assertTrue("", bpm.leadingBaseCoefficient().isONE()); assertTrue("", cpm.leadingBaseCoefficient().isONE()); assertTrue("", dpm.leadingBaseCoefficient().isONE()); GreatestCommonDivisorAbstract> fdq = new GreatestCommonDivisorSimple>( qfac); gp = fdq.leftBaseGcd(ap, bp); gpm = gp.monic(); //System.out.println("gp = " + gp); //System.out.println("gpm = " + gpm); assertTrue("", gpm.leadingBaseCoefficient().isONE()); ep = FDUtil.> leftBaseSparsePseudoRemainder(gp, dp); //System.out.println("ep = " + ep); assertTrue("c | gcd(ac,bc): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(ap, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| ac): " + ep, ep.isZERO()); ep = FDUtil.> leftBaseSparsePseudoRemainder(bp, gp); //System.out.println("ep = " + ep); assertTrue("gcd(ac,bc)| bc): " + ep, ep.isZERO()); } /** * Test univariate recursive right gcd simple. */ @SuppressWarnings("cast") public void testRecursiveRightGCDSyzygy() { String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); //System.out.println("rfac = " + rfac.toScript()); RecSolvablePolynomialRing rrfacTemp = rfac; GenSolvablePolynomialRing> rrfac = rfac; GenSolvablePolynomialRing rcfac = (GenSolvablePolynomialRing) rfac.coFac; SolvableQuotientRing qfac = new SolvableQuotientRing(rcfac); QuotSolvablePolynomialRing rqfac = new QuotSolvablePolynomialRing(qfac, rrfac); List>> rl = rrfacTemp.coeffTable.relationList(); List>> rlc = PolynomialList .> castToList(rl); rqfac.polCoeff.coeffTable.addRelations(rlc); //System.out.println("rrfac = " + rrfac.toScript()); //System.out.println("rcfac = " + rcfac.toScript()); //System.out.println("qfac = " + qfac.toScript()); //System.out.println("rqfac = " + rqfac.toScript()); //kl = 3; int ll = 3; int el = 3; ar = rfac.random(kl, ll, el + 1, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); ////cr = (RecSolvablePolynomial) cr.abs(); cr = (RecSolvablePolynomial) PolyUtil. monic(cr); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); //cr = rfac.getONE(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (cr.isZERO()) { cr = rfac.getONE(); } ar = cr.multiply(ar); br = cr.multiply(br); //ar = ar.multiply(cr); //br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //er = (RecSolvablePolynomial) FDUtil. recursiveRightPseudoQuotient(dr, cr); //System.out.println("dr/cr = " + er); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b " + er, er.isZERO()); } /** * Test arbitrary recursive gcd simple. */ @SuppressWarnings("cast") public void testArbitraryRecursiveGCDSyzygy() { String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "c" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, cvars); RelationGenerator wl = new WeylRelationsIterated(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); rfac = new RecSolvablePolynomialRing(dfac, to, vars); //System.out.println("rfac = " + rfac.toScript()); //kl = 3; ll = 2; int el = 2; ar0 = rfac.random(kl, ll, el + 1, q); br0 = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //ar = rfac.parse("a + b c^2 "); //br = rfac.parse("( a^2 - 1/3 ) c - 1/4"); //cr = rfac.parse("(b - 1/2 a^2) c"); //ar = rfac.parse("( 2/11 a * b^2 + 11/24 b - 11/6 a^2 )"); //br = rfac.parse("( 14/13 b^2 - 1/69 )"); //cr = rfac.parse("c + 33/133 a"); //ar0 = rfac.parse("( a * b^2 + 1/2 b - 1/6 a^2 )"); //br0 = rfac.parse("( b^2 - 1/5 )"); //cr = rfac.parse("c + 3/13 a"); //cr = (RecSolvablePolynomial) fd.recursivePrimitivePart(cr).abs(); cr = (RecSolvablePolynomial) cr.monic(); if (cr.isZERO()) { cr = rfac.getONE(); } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // left gcd ar = ar0.multiply(cr); br = br0.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.leftRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | ac " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ac,bc) | bc " + er, er.isZERO()); // right gcd ar = cr.multiply(ar0); br = cr.multiply(br0); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = fd.rightRecursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | ca " + er, er.isZERO()); er = (RecSolvablePolynomial) FDUtil. recursiveRightSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(ca,cb) | cb " + er, er.isZERO()); } /** * Test full gcd simple, 4 variables. */ public void testGCDSyzygy() { String[] vars = new String[] { "a", "b", "c", "d" }; //String[] vars = new String[] { "a", "b" }; dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); RelationGenerator wl = new WeylRelationsIterated(); //RelationGenerator wl = new WeylRelations(); dfac.addRelations(wl); //System.out.println("dfac = " + dfac.toScript()); //kl = 3; ll = 4; el = 4; //a = dfac.random(kl, ll, el, q); //b = dfac.random(kl, ll, el, q); //c = dfac.random(kl, ll, el, q); //c = c.multiply(dfac.univariate(0)); a0 = dfac.parse("b^3 - 1/6 + d"); b0 = dfac.parse("b + 3 a^2 + d"); //b = dfac.parse("( -1/2 ) b + 3 a^2 + d"); //c = dfac.parse("(a - 5 b) + c + d"); //ok: c = dfac.parse("(a - b) c"); //c = dfac.parse("(a - b) + c + d "); //c = dfac.parse("(a - b) + c"); //c = dfac.parse("(a - b) + b^2"); c = dfac.parse("c - a - b"); //c = dfac.parse("d - c - b - a"); //c = dfac.parse("(a - b) + d"); //c = dfac.parse("b + d"); //c = dfac.parse("a + d"); //a = dfac.parse("2 b^3 * d^2 + 2/3 a + 3/2"); //b = dfac.parse("2/3 d + 1/2 a^3 + 3/4"); //c = dfac.parse("c^2 * d - 1/2 a^3 * d + 5/4 d"); //c = (GenSolvablePolynomial) fd.primitivePart(c).abs(); c = c.monic(); if (c.isZERO()) { c = dfac.getONE(); } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a0.multiply(c); b = b0.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); List> L = new ArrayList>(); L.add(a); L.add(b); SolvableGroebnerBaseAbstract sbb = new SolvableGroebnerBaseSeq(); // left List> Llgb = sbb.leftGB(L); //System.out.println("leftGB = " + Llgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.leftGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("d in leftGB", sbb.sred.leftNormalform(Llgb, d).isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. leftBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); // right a = c.multiply(a0); b = c.multiply(b0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> Lrgb = sbb.rightGB(L); // too long //System.out.println("rightGB = " + Lrgb); //List> Ltgb = sbb.twosidedGB(L); //System.out.println("twosidedGB = " + Ltgb); d = fd.rightGcd(a, b); //System.out.println("gb = " + Llgb); //System.out.println("c = " + c); //System.out.println("d = " + d); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, c); //System.out.println("e = " + e); assertTrue("c | ac: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, c); //System.out.println("e = " + e); assertTrue("c | bc: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(a,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e, e.isZERO()); e = FDUtil. rightBaseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); //e = FDUtil. divideRightPolynomial(b,d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e, e.isZERO()); } /** * Test rational coefficients gcd polynomial cofactor tests. */ public void testRatCofactors() { //System.out.println("dfac = " + dfac.toScript()); do { a = dfac.random(kl, ll, el, q); } while (a.isZERO()||a.isConstant()); do { b = dfac.random(kl, ll, el, q/2f); } while (b.isZERO()||b.isConstant()); do { c = dfac.random(kl, ll, el, q/2f); } while (c.isZERO()||c.isConstant()); c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // non commutative left //System.out.println("right: "); d = c.multiply(a); e = c.multiply(b); //System.out.println("d = " + d); //System.out.println("e = " + e); GenSolvablePolynomial[] gco = fd.leftGcdCofactors(dfac, d, e); //System.out.println("left gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ca, cb; ca = gco[0].multiply(gco[1]); cb = gco[0].multiply(gco[2]); //System.out.println("ca = " + ca); //System.out.println("d = " + d); //System.out.println("cb = " + cb); //System.out.println("e = " + e); assertEquals("ca = c*a: ", ca, d); assertEquals("cb = c*b: ", cb, e); // non commutative right //System.out.println("left: "); d = a.multiply(c); e = b.multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); gco = fd.rightGcdCofactors(dfac, d, e); //System.out.println("right gco[0] = " + gco[0]); //System.out.println("gco[1] = " + gco[1]); //System.out.println("gco[2] = " + gco[2]); GenSolvablePolynomial ac, bc; ac = gco[1].multiply(gco[0]); bc = gco[2].multiply(gco[0]); //System.out.println("ac = " + ac); //System.out.println("d = " + d); //System.out.println("bc = " + bc); //System.out.println("e = " + e); assertEquals("ac = a*c: ", ac, d); assertEquals("bc = b*c: ", bc, e); } } java-algebra-system-2.7.200/trc/edu/jas/fd/QuotSolvablePolynomialTest.java000066400000000000000000000624071445075545500264510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.Map; import java.util.List; import java.util.ArrayList; import java.util.Arrays; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RelationGenerator; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; import edu.jas.kern.ComputerThreads; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients QuotSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class QuotSolvablePolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a QuotSolvablePolynomialTest object. * @param name String. */ public QuotSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(QuotSolvablePolynomialTest.class); return suite; } QuotSolvablePolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 1; int ll = 4; int el = 3; float q = 0.2f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; QuotSolvablePolynomialRing ring; BigRational cfac; GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; SolvableQuotientRing qcring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); qcring = new SolvableQuotientRing(cring); ring = new QuotSolvablePolynomialRing(qcring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); a = b = c = d = e = null; } @Override protected void tearDown() { ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { a = ring.getZERO(); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new QuotSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); String ts = ring.toScript(); //System.out.println("ring = " + ts); assertTrue("SolvPolyRing in ring: " + ts, ts.indexOf("SolvPolyRing") >= 0); ts = ring.toString(); //System.out.println("ring = " + ts); assertTrue("RatFunc in ring: " + ts, ts.indexOf("RatFunc") >= 0); int h = ring.hashCode(); assertTrue("hashCode != 0", h != 0); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); assertTrue("isAssociative: ", ring.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); int h = a.hashCode(); assertTrue("hashCode != 0", h != 0); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (QuotSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (QuotSolvablePolynomial) a.sum(a); c = (QuotSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (QuotSolvablePolynomial) b.sum(a); d = (QuotSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (QuotSolvablePolynomial) a.sum(b.sum(c)); e = (QuotSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); SolvableQuotient x = qcring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (QuotSolvablePolynomial) a.sum(b); d = (QuotSolvablePolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QuotSolvablePolynomial) a.subtract(b); d = (QuotSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (QuotSolvablePolynomial) b.sum(a); d = (QuotSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (QuotSolvablePolynomial) a.subtract(b); d = (QuotSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll - 1, el - 1, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll - 1, el - 1, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll - 1, el - 1, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); SolvableQuotient xp = a.leadingBaseCoefficient().inverse(); d = a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().isONE()); d = (QuotSolvablePolynomial) a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test commutative ring. */ public void testCommutative() { //System.out.println("table = " + table.toString(vars)); //System.out.println("table = " + table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); ring = new QuotSolvablePolynomialRing(qcring, ring); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("b*a == a*b: ", c, d); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((QuotSolvablePolynomial) b.sum(c)); e = (QuotSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); } /** * Test conversions. */ public void testConversion() { GenSolvablePolynomialRing> pring; pring = new GenSolvablePolynomialRing>(cring, tord, vars); RelationGenerator> pwl = new WeylRelations>(); pwl.generate(pring); String ts = pring.toScript(); //System.out.println("pring = " + ts); assertTrue("SolvPolyRing in pring: " + ts, ts.indexOf("SolvPolyRing") >= 0); ts = pring.toString(); //System.out.println("pring = " + ts); assertTrue("IntFunc in pring: " + ts, ts.indexOf("IntFunc") >= 0); GenSolvablePolynomial> ap, bp, cp, dp; ap = pring.random(kl, ll, el, q); //System.out.println("ap = " + ap); a = ring.fromPolyCoefficients(ap); //System.out.println("a = " + a); bp = ring.toPolyCoefficients(a); //System.out.println("bp = " + bp); assertEquals("poly(a) == ap", ap, bp); //GenSolvablePolynomialRing> sring; sring = new GenSolvablePolynomialRing>(ring.coFac, tord, vars); RelationGenerator> swl = new WeylRelations>(); swl.generate(sring); ts = sring.toScript(); //System.out.println("sring = " + ts); assertTrue("SolvPolyRing in sring: " + ts, ts.indexOf("SolvPolyRing") >= 0); // //GenSolvablePolynomial> as, bs, cs, ds; // //as = sring.random(kl, ll, el, q); // a = ring.fromPolyCoefficients(ap); // //System.out.println("a = " + a); // bp = ring.toPolyCoefficients(a); // //System.out.println("bp = " + bp); // assertEquals("poly(a) == ap", ap, bp); } /** * Test solvable coefficient ring. */ public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //RelationGenerator wlc = new WeylRelations(csring); //no: wlc.generate(csring); //assertTrue("# relations == 1", csring.table.size() == 1); assertTrue("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); SolvableQuotientRing qcsring = new SolvableQuotientRing(csring); //assertFalse("isCommutative()", qcsring.isCommutative()); assertTrue("isAssociative()", qcsring.isAssociative()); ring = new QuotSolvablePolynomialRing(qcsring, ring); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); //System.out.println("ring = " + ring); RecSolvablePolynomial r1 = ring.polCoeff.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.polCoeff.parse("b x + a"); // + a //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring.polCoeff = " + ring.polCoeff); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); //gens = new ArrayList>>(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new QuotSolvablePolynomial(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new QuotSolvablePolynomial(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens: " + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); } } //a = ring.random(kl, ll, el, q); //a = ring.getONE(); a = ring.parse("x^2 + a b"); //System.out.println("a = " + a.toScript()); //b = ring.random(kl, ll, el, q); //b = ring.getONE(); b = ring.parse("a b^2 + a"); // + a b = (QuotSolvablePolynomial) b.inverse(); //System.out.println("b = " + b.toScript()); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); e = (QuotSolvablePolynomial) b.inverse(); //System.out.println("e = " + e.toScript()); assertTrue("b*b^-1 == 1", e.multiply(b).isONE()); c = e.multiply(c); d = d.multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("b = " + b.toScript()); //System.out.println("c = " + c.toScript()); //System.out.println("d = " + d.toScript()); assertTrue("a == b * 1/b * a", a.equals(c)); assertTrue("a == a * 1/b * b", a.equals(d)); } /** * Test extension and contraction for Weyl relations. */ public void testExtendContractWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); //System.out.println("csring = " + csring.toScript()); RelationGenerator wlc = new WeylRelations(); wlc.generate(csring); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); //System.out.println("csring = " + csring.toScript()); SolvableQuotientRing qcsring = new SolvableQuotientRing(csring); ring = new QuotSolvablePolynomialRing(qcsring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); QuotSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); QuotSolvablePolynomial rp = ring.parse("b x + a"); GenSolvablePolynomial> rpp = ring.toPolyCoefficients(rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rpp); int k = rl; QuotSolvablePolynomialRing pfe = ring.extend(k); //System.out.println("pfe = " + pfe); QuotSolvablePolynomialRing pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); QuotSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QuotSolvablePolynomial ae = (QuotSolvablePolynomial) a.extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(ring); //=pfec //System.out.println("m = " + m); List>> ml = new ArrayList>>(m.values()); //System.out.println("ml = " + ml); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test reversion for Weyl relations. */ public void testReverseWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); wlc.generate(csring); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); SolvableQuotientRing qcsring = new SolvableQuotientRing(csring); ring = new QuotSolvablePolynomialRing(qcsring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); //wl.generate(ring); QuotSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); QuotSolvablePolynomial rp = ring.parse("b x + a"); GenSolvablePolynomial> rpp = ring.toPolyCoefficients(rp); ring.polCoeff.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rpp); QuotSolvablePolynomialRing pfr = ring.reverse(); QuotSolvablePolynomialRing pfrr = pfr.reverse(); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); assertEquals("pf == pfrr", ring, pfrr); QuotSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); QuotSolvablePolynomial ar = (QuotSolvablePolynomial) a.reverse(pfr); QuotSolvablePolynomial arr = (QuotSolvablePolynomial) ar.reverse(pfrr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); assertEquals("a == arr", a, arr); } /** * Test recursive for Weyl relations. */ public void testRecursiveWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelations(); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); assertTrue("SolvPolyRing" + sring.toScript(), sring.toScript().indexOf("SolvPolyRing") >= 0); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //System.out.println("rsring = " + rsring.toScript()); assertTrue("SolvPolyRing" + rsring.toScript(), rsring.toScript().indexOf("SolvPolyRing") >= 0); GenSolvablePolynomial ad, bd, cd, dd; //QuotSolvablePolynomial ar, br, cr, dr; //GenSolvablePolynomial> aq, bq, cq, dq; GenPolynomial> ap, bp, cp, dp; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ap = (GenPolynomial>) PolyUtil. recursive(rsring, ad); bp = (GenPolynomial>) PolyUtil. recursive(rsring, bd); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); cp = ap.multiply(bp); //System.out.println("cp = " + cp); //System.out.println("cp.ring = " + cp.ring.toScript()); dp = (GenPolynomial>) PolyUtil. recursive(rsring, cd); //System.out.println("dp = " + dp); assertEquals("dp.ring == cp.ring", dp.ring, cp.ring); assertEquals("dp == cp", dp, cp); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, dp); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /** * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated (); wlc.generate(sring); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); assertTrue("SolvPolyRing" + sring.toScript(), sring.toScript().indexOf("SolvPolyRing") >= 0); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //System.out.println("rsring = " + rsring.toScript()); assertTrue("SolvPolyRing" + rsring.toScript(), rsring.toScript().indexOf("SolvPolyRing") >= 0); GenSolvablePolynomial ad, bd, cd, dd; QuotSolvablePolynomial ar, br, cr, dr; GenSolvablePolynomial> aq, bq, cq, dq; GenPolynomial> ap, bp, cp, dp; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ap = (GenPolynomial>) PolyUtil. recursive(rsring, ad); bp = (GenPolynomial>) PolyUtil. recursive(rsring, bd); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); cp = ap.multiply(bp); //System.out.println("cp = " + cp); //System.out.println("cp.ring = " + cp.ring.toScript()); dp = (GenPolynomial>) PolyUtil. recursive(rsring, cd); //System.out.println("dp = " + dp); assertEquals("dp.ring == cp.ring", dp.ring, cp.ring); assertEquals("dp == cp", dp, cp); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, dp); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } } java-algebra-system-2.7.200/trc/edu/jas/fd/SGCDFactoryTest.java000066400000000000000000000221761445075545500240340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; // import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable GreatestCommonDivisor factory tests with JUnit. * @author Heinz Kredel */ public class SGCDFactoryTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SGCDFactoryTest object. * @param name String. */ public SGCDFactoryTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SGCDFactoryTest.class); return suite; } TermOrder to = TermOrderByName.INVLEX; GenSolvablePolynomialRing dfac; GenSolvablePolynomialRing cfac; GenSolvablePolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenSolvablePolynomial a, b, c, d, e; GenSolvablePolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = new GenSolvablePolynomialRing(new BigInteger(1), rl, to); cfac = new GenSolvablePolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenSolvablePolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; } /** * Test get BigInteger implementation. */ public void testBigInteger() { BigInteger bi = new BigInteger(); GreatestCommonDivisor ufd; ufd = SGCDFactory.getImplementation(bi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); ufd = SGCDFactory.getProxy(bi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Primitive " + ufd, ((SGCDParallelProxy)ufd).e1 instanceof GreatestCommonDivisorPrimitive); } /** * Test get ModInteger implementation. */ public void testModInteger() { ModIntegerRing mi = new ModIntegerRing(19, true); GreatestCommonDivisor ufd; ufd = SGCDFactory.getImplementation(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); ufd = SGCDFactory.getProxy(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Primitive " + ufd, ((SGCDParallelProxy)ufd).e2 instanceof GreatestCommonDivisorSimple); mi = new ModIntegerRing(30); ufd = SGCDFactory.getImplementation(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); ufd = SGCDFactory.getProxy(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Simple " + ufd, ((SGCDParallelProxy)ufd).e1 instanceof GreatestCommonDivisorPrimitive); } /** * Test get BigRational implementation. */ public void testBigRational() { BigRational b = new BigRational(); GreatestCommonDivisor ufd; ufd = SGCDFactory.getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); ufd = SGCDFactory.getProxy(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Simple " + ufd, ((SGCDParallelProxy)ufd).e2 instanceof GreatestCommonDivisorSimple); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); GreatestCommonDivisor ufd; ufd = SGCDFactory. getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); ufd = SGCDFactory. getProxy(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Simple " + ufd, ((SGCDParallelProxy)ufd).e1 instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<BigRational> implementation. * */ public void testAlgebraicNumberBigRational() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); GreatestCommonDivisor> ufd; ufd = SGCDFactory.> getImplementation(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); ufd = SGCDFactory.> getProxy(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Primitive " + ufd, ((SGCDParallelProxy)ufd).e2 instanceof GreatestCommonDivisorPrimitive); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); ufd = SGCDFactory.> getImplementation(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); ufd = SGCDFactory.> getProxy(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Simple " + ufd, ((SGCDParallelProxy)ufd).e1 instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<ModInteger> implementation. */ public void testAlgebraicNumberModInteger() { ModIntegerRing b = new ModIntegerRing(19, true); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); AlgebraicNumber a = afac.getONE(); assertTrue("a == 1 " + a, a.isONE()); GreatestCommonDivisor> ufd; ufd = SGCDFactory.> getImplementation(afac); //System.out.println("ufd2 = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); ufd = SGCDFactory.> getProxy(afac); //System.out.println("ufd2 = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Primitive " + ufd, ((SGCDParallelProxy)ufd).e2 instanceof GreatestCommonDivisorPrimitive); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); ufd = SGCDFactory.> getImplementation(afac); //System.out.println("ufd2 = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); ufd = SGCDFactory.> getProxy(afac); //System.out.println("ufd2 = " + ufd); assertTrue("ufd = Parallel Proxy " + ufd, ufd instanceof SGCDParallelProxy); assertTrue("ufd = Primitive " + ufd, ((SGCDParallelProxy)ufd).e2 instanceof GreatestCommonDivisorPrimitive); } } java-algebra-system-2.7.200/trc/edu/jas/fd/SGCDParallelProxyTest.java000066400000000000000000000547771445075545500252370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RecSolvablePolynomial; import edu.jas.poly.RecSolvablePolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable GreatestCommonDivisor parallel proxy tests with JUnit. * @author Heinz Kredel */ public class SGCDParallelProxyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); //System.out.println("System.exit(0)"); } /** * Constructs a SGCDParallelProxyTest object. * @param name String. */ public SGCDParallelProxyTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SGCDParallelProxyTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenSolvablePolynomialRing dfac; //GenSolvablePolynomialRing cfac; RecSolvablePolynomialRing rfac; //GenSolvablePolynomialRing> rfac; BigRational ai, bi, ci, di, ei; GenSolvablePolynomial a, b, c, d, e; GenSolvablePolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 5; int ll = 7; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; //String[] vars = new String[] { "a1", "a2", "a3", "a4", "a5" }; // #=rl String[] vars = new String[] { "a1", "a2", "a3", "a4" }; // #=rl dfac = new GenSolvablePolynomialRing(new BigRational(1), to, vars); //cfac = new GenSolvablePolynomialRing(new BigRational(1), rl - 1, to); //rfac = new GenSolvablePolynomialRing>(cfac, 1, to); rfac = (RecSolvablePolynomialRing) dfac.recursive(1); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; //cfac = null; rfac = null; //ComputerThreads.terminate(); } /** * Test get BigRational parallel implementation. */ public void testBigRational() { long t; BigRational bi = new BigRational(); GreatestCommonDivisor fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); dfac = new GenSolvablePolynomialRing(bi, 4, to); for (int i = 0; i < 1; i++) { // 10-50 a = dfac.random(kl + i * 10, ll + i, el, q); b = dfac.random(kl + i * 10, ll + i, el, q); c = dfac.random(kl + 2, ll, el, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); c = (GenSolvablePolynomial) fd.leftPrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.leftGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("i proxy time = " + t); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); // now with right variants: c = (GenSolvablePolynomial) fd.rightPrimitivePart(c).abs(); a = c.multiply(a); b = c.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.rightGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test get ModInteger parallel implementation. */ public void testModInteger() { long t; ModIntegerRing mi = new ModIntegerRing(19, true); //ModIntegerRing mi = new ModIntegerRing(536870909, true); GenSolvablePolynomial a, b, c, d, e; GreatestCommonDivisor fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(mi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(mi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); GenSolvablePolynomialRing dfac; dfac = new GenSolvablePolynomialRing(mi, 4, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl + i * 2, ll + i, el, q); b = dfac.random(kl + i * 2, ll + i, el, q); c = dfac.random(kl, ll, el, q); //a = dfac.random(kl,ll+i,el,q); //b = dfac.random(kl,ll+i,el,q); //c = dfac.random(kl,ll,el,q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); c = (GenSolvablePolynomial) fd.leftPrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.leftGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("m proxy time = " + t); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e + ", " + d + ", " + c, e.isZERO()); // now with right variants: c = (GenSolvablePolynomial) fd.rightPrimitivePart(c).abs(); a = c.multiply(a); b = c.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.rightGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test get BigInteger implementation. */ public void testBigInteger() { BigInteger b = new BigInteger(); GreatestCommonDivisor fd; fd = SGCDFactory. getImplementation(b); //System.out.println("fd = " + fd); assertTrue("fd = Primitive " + fd, fd instanceof GreatestCommonDivisorPrimitive); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); GreatestCommonDivisor fd; fd = SGCDFactory. getImplementation(b); //System.out.println("fd = " + fd); assertTrue("fd != Simple " + fd, fd instanceof GreatestCommonDivisorSimple); } /** * Test get BigRational base parallel implementation. */ public void testBigRationalBase() { long t; BigRational bi = new BigRational(); GreatestCommonDivisorAbstract fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); int rl = 1; dfac = new GenSolvablePolynomialRing(bi, 1, to); for (int i = 0; i < 1; i++) { // 10-50 a = dfac.random(kl + i * 10, ll + i, el, q); b = dfac.random(kl + i * 10, ll + i, el, q); c = dfac.random(kl + 2, ll, el, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); c = (GenSolvablePolynomial) fd.leftPrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.leftBaseGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("i proxy time = " + t); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); e = FDUtil. leftBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); // now with right variants: c = (GenSolvablePolynomial) fd.rightPrimitivePart(c).abs(); a = c.multiply(a); b = c.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); t = System.currentTimeMillis(); d = (GenSolvablePolynomial) fd_par.rightBaseGcd(a, b); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); e = FDUtil. rightBaseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test get BigRational left recursive univariate parallel implementation. */ public void testBigRationalLeftRecursiveUniv() { long t; BigRational bi = new BigRational(); GreatestCommonDivisorAbstract fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); for (int i = 0; i < 1; i++) { // 10-50 ar = rfac.random(kl + i, ll, el, q); br = rfac.random(kl + i, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = rfac.getONE(); //cr = c.multiply( rfac.univariate(0) ); cr = (GenSolvablePolynomial>) fd.leftRecursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !cr.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !cr.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); t = System.currentTimeMillis(); // left dr = (GenSolvablePolynomial>) fd_par.leftRecursiveUnivariateGcd(ar, br); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("i proxy time = " + t); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //recursiveLeftSparsePseudoRemainder er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + cr + " ~| " + dr, er.isZERO()||dr.isONE()); } } /** * Test get BigRational right recursive univariate parallel implementation. */ public void testBigRationalRightRecursiveUniv() { long t; BigRational bi = new BigRational(); GreatestCommonDivisorAbstract fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); for (int i = 0; i < 1; i++) { // 10-50 ar = rfac.random(kl + i, ll, el, q); br = rfac.random(kl + i, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = rfac.getONE(); //cr = c.multiply( rfac.univariate(0) ); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !cr.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !cr.isONE() ); // now with right variants: right! cr = (GenSolvablePolynomial>) fd.rightRecursivePrimitivePart(cr).abs(); ar = cr.multiply(ar); br = cr.multiply(br); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); t = System.currentTimeMillis(); dr = (GenSolvablePolynomial>) fd_par.rightRecursiveUnivariateGcd(ar, br); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //recursiveRightSparsePseudoRemainder er = FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + cr + " ~| " + dr, er.isZERO()||dr.isONE()); } } /** * Test get BigRational left recursive parallel implementation. */ public void testBigRationalLeftRecursive() { long t; BigRational bi = new BigRational(); rfac = (RecSolvablePolynomialRing) dfac.recursive(2); //System.out.println("rfac.gens = " + rfac.generators()); GreatestCommonDivisorAbstract fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); for (int i = 0; i < 1; i++) { // 10-50 ar = rfac.random(kl + i, ll, el, q); br = rfac.random(kl + i, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = rfac.getONE(); //cr = c.multiply( rfac.univariate(0) ); cr = (GenSolvablePolynomial>) fd.leftRecursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !cr.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !cr.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); t = System.currentTimeMillis(); dr = (GenSolvablePolynomial>) fd_par.leftRecursiveGcd(ar, br); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("i proxy time = " + t); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //recursiveLeftSparsePseudoRemainder er = FDUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + cr + " ~| " + dr, er.isZERO()||dr.isONE()); } } /** * Test get BigRational right recursive parallel implementation. */ public void testBigRationalRightRecursive() { long t; BigRational bi = new BigRational(); rfac = (RecSolvablePolynomialRing) dfac.recursive(2); //System.out.println("rfac.gens = " + rfac.generators()); GreatestCommonDivisorAbstract fd_par; GreatestCommonDivisorAbstract fd; fd_par = SGCDFactory. getProxy(bi); //System.out.println("fd_par = " + fd_par); assertTrue("fd_par != null " + fd_par, fd_par != null); fd = new GreatestCommonDivisorFake(bi); //System.out.println("fd = " + fd); assertTrue("fd != null " + fd, fd != null); for (int i = 0; i < 1; i++) { // 10-50 ar = rfac.random(kl + i, ll, el, q); br = rfac.random(kl + i, ll, el, q); cr = rfac.random(kl, ll, el, q); //cr = rfac.getONE(); //cr = c.multiply( rfac.univariate(0) ); cr = (GenSolvablePolynomial>) fd.rightRecursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !cr.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !cr.isONE() ); ar = cr.multiply(ar); br = cr.multiply(br); //System.out.println("ar = " + ar); //System.out.println("br = " + br); t = System.currentTimeMillis(); dr = (GenSolvablePolynomial>) fd_par.rightRecursiveGcd(ar, br); t = System.currentTimeMillis() - t; assertTrue("time >= 0: " + t, t >= 0); //System.out.println("i proxy time = " + t); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //recursiveRightSparsePseudoRemainder er = FDUtil. recursiveRightSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ca,cb) " + cr + " ~| " + dr, er.isZERO()||dr.isONE()); } } } java-algebra-system-2.7.200/trc/edu/jas/fd/SolvableQuotientTest.java000066400000000000000000000264351445075545500252660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.fd; import java.util.Arrays; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.RelationGenerator; import edu.jas.poly.ExpVector; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * SolvableQuotient over BigRational GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class SolvableQuotientTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableQuotientTest object. * @param name String. */ public SolvableQuotientTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableQuotientTest.class); return suite; } SolvableQuotientRing zFac; SolvableQuotientRing efac; GenSolvablePolynomialRing mfac; SolvableQuotient a, b, c, d, e; SolvableQuotient az, bz, cz, dz, ez; int rl = 4; int kl = 2; int ll = 3; //6; int el = 2; float q = 0.2f; @Override protected void setUp() { a = b = c = d = e = null; TermOrder to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "w", "x", "y", "z" }; mfac = new GenSolvablePolynomialRing(new BigRational(1), rl, to, vars); RelationGenerator wl = new WeylRelations(); wl.generate(mfac); efac = new SolvableQuotientRing(mfac); zFac = new SolvableQuotientRing(mfac); } @Override protected void tearDown() { a = b = c = d = e = null; //efac.terminate(); efac = null; zFac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { String ts = efac.toScript(); //System.out.println("efac = " + ts); assertTrue("SRF in efac: " + ts, ts.indexOf("SRF") >= 0); ts = efac.toString(); //System.out.println("efac = " + ts); assertTrue("RatFunc in efac: " + ts, ts.indexOf("RatFunc") >= 0); int h = efac.hashCode(); //System.out.println("efac.hashCode = " + h); assertTrue("hashCode != 0", h != 0); c = efac.getONE(); //System.out.println("c = " + c); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); ts = c.toScript(); //System.out.println("c = " + ts); assertTrue("1 in c: " + ts, ts.indexOf("1") >= 0); //ts = c.toString(); //System.out.println("c = " + ts); assertTrue("1 in c: " + ts, ts.indexOf("1") >= 0); d = efac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); for (SolvableQuotient g : efac.generators()) { //System.out.println("g = " + g); assertFalse("not isZERO( g )", g.isZERO()); } //wrong, solved: assertTrue("isAssociative: ", efac.isAssociative()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { //a = efac.random(ll+i); a = efac.random(kl * i, ll + i/2, el, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); assertEquals("a == a: ", a, a); int h = a.hashCode(); //System.out.println("a.hashCode = " + h); assertTrue("hashCode != 0", h != 0); } } /** * Test addition. */ public void testAddition() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("(a+b-b) == a: " + a + ", " + b, a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); //c = efac.random(kl,ll,el,q); c = new SolvableQuotient(efac, mfac.univariate(1, 2)); //efac.random(kl,ll,el,q); //System.out.println("c = " + c); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("c+(a+b) = (c+a)+b", d, e); } /** * Test multiplication. */ public void testMultiplication() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(efac.getONE()); d = efac.getONE().multiply(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1 = 1*a", c, a); assertEquals("a*1 = 1*a", c, d); c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); //non-com assertFalse("a*b = b*a", c.equals(d) ); //e = d.subtract(c); //non-com assertFalse("not isZERO( a*b-b*a ) " + e, e.isZERO() ); c = new SolvableQuotient(efac, mfac.univariate(1, 2)); //efac.random(kl,ll,el,q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); //System.out.println("d = " + d); e = (a.multiply(b)).multiply(c); //System.out.println("e = " + e); assertEquals("a(bc) = (ab)c", d, e); //assertTrue("a(bc) = (ab)c", d.equals(e) ); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } c = new SolvableQuotient(efac, mfac.univariate(1, 2)); //System.out.println("c = " + c.toScript()); GenSolvablePolynomial n = c.num; d = a.multiply(n); e = a.multiply(c); assertEquals("a*c.n = a*c", d, e); ExpVector ldt = n.leadingExpVector(); d = a.multiply(ldt); //e = a.multiply(c); assertEquals("a*ldt(c.n) = a*c", d, e); BigRational ldcf = BigRational.ONE; ldcf = ldcf.sum(ldcf); d = a.multiply(ldcf); e = d.multiply(BigRational.HALF); //System.out.println("a = " + a); //System.out.println("d = " + d); assertEquals("a = (a*2)*1/2", a, e); } /** * Test addition without syzygy gcd. */ public void testAdditionGcd() { long te, tz; a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); az = new SolvableQuotient(zFac, a.num, a.den, true); bz = new SolvableQuotient(zFac, b.num, b.den, true); //if (false) { // return; //} te = System.currentTimeMillis(); c = a.sum(b); d = c.subtract(b); d = d.monic(); te = System.currentTimeMillis() - te; assertEquals("a+b-b = a", a, d); tz = System.currentTimeMillis(); cz = az.sum(bz); dz = cz.subtract(bz); dz = dz.monic(); tz = System.currentTimeMillis() - tz; assertEquals("a+b-b = a", az, dz); if (tz >= 0L || te >= 0L) { // true, findbugs return; } System.out.println("te = " + te); System.out.println("tz = " + tz); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = efac.random(kl, ll, el, q); cz = new SolvableQuotient(zFac, c.num, c.den, true); te = System.currentTimeMillis(); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); te = System.currentTimeMillis() - te; assertEquals("c+(a+b) = (c+a)+b", d, e); tz = System.currentTimeMillis(); dz = cz.sum(az.sum(bz)); ez = cz.sum(az).sum(bz); tz = System.currentTimeMillis() - tz; assertEquals("c+(a+b) = (c+a)+b", dz, ez); System.out.println("te = " + te); System.out.println("tz = " + tz); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test parse. */ public void testParse() { a = efac.random(kl, ll, el + 1, q); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(); //System.out.println("p = " + p); b = efac.parse(p); //System.out.println("b = " + b); //c = a.subtract(b); //System.out.println("c = " + c); assertEquals("parse(a.toSting()) = a", a, b); } /** * Test egcd and fraction. */ public void testEgcdFraction() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); SolvableQuotient[] egcd = a.egcd(b); //System.out.println("egcd = " + Arrays.toString(egcd)); SolvableQuotient e0 = egcd[0]; SolvableQuotient e1 = egcd[1]; SolvableQuotient e2 = egcd[2]; c = a.multiply(e1).sum( b.multiply(e2) ); //System.out.println("c = " + c); assertEquals("egcd[0] == c: " + e0 + "!=" + c, e0, c); c = a.rightFraction(); //System.out.println("rf(a) = " + c); assertTrue("isRightFraction: " + a + "rf" + c, a.isRightFraction(c) ); //System.out.println("a.num * c.den: " + a.num.multiply(c.den) ); //System.out.println("a.den * c.num: " + a.den.multiply(c.num) ); } } java-algebra-system-2.7.200/trc/edu/jas/gb/000077500000000000000000000000001445075545500202505ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/gb/DGroebnerBaseSeqTest.java000066400000000000000000000155161445075545500250760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * DGroebner base sequential tests with JUnit. * @author Heinz Kredel */ public class DGroebnerBaseSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a DGroebnerBaseSeqTest object. * @param name String. */ public DGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(DGroebnerBaseSeqTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBase bb; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 4; //4; 10 int ll = 4; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigInteger coeff = new BigInteger(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new DGroebnerBaseSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; ComputerThreads.terminate(); } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); //.abs(); b = fac.random(kl, ll, el, q); //.abs(); c = fac.random(kl, ll / 2, el, q); //.abs(); d = fac.random(kl, ll / 2, el, q); //.abs(); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("dGB(L) = " + L ); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("dGB(L) = " + L ); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(c); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("dGB(L) = " + L ); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("dGB(L) = " + L ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("dGB(L) = " + L ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase over Z. */ @SuppressWarnings("unchecked") public void xtestTrinks7GBaseZ() { // too long String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); System.out.println("G = " + trinks); System.out.println("G.size() = " + G.size()); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //assertEquals("#GB(Trinks7) == 6", 6, G.size() ); } /** * Test Trinks7 GBase over Z(B). */ @SuppressWarnings("unchecked") public void testTrinks7GBaseZ_B() { String exam = "IntFunc{ B } (S,T,Z,P,W) G " + "( " + "( { 45 } P + { 35 } S - { 165 B } - { 36 } ), " + "( { 35 } P + { 40 } Z + { 25 } T - { 27 } S ), " + "( { 15 } W + { 25 } S P + { 30 } Z - { 18 } T - { 165 B**2 } ), " + "( { - 9 } W + { 15 } T P + { 20 } S Z ), " + "( P W + { 2 } T Z - { 11 B**3 } ), " + "( { 99 } W - { 11 B } S + { 3 B**2 } ), " + "( { 10000 B**2 + 6600 B + 2673 } ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); DGroebnerBaseSeq> bb = new DGroebnerBaseSeq>(); PolynomialList> F = null; List>> G = null; try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); List>> Fp = new ArrayList>>( F.list.size()); for (GenPolynomial> p : F.list) { p = PolyUtil. monic(p); Fp.add(p); } //System.out.println("Fp = " + Fp); G = bb.GB(Fp); //System.out.println("G = " + G); List>> Gp = new ArrayList>>( F.list.size()); for (GenPolynomial> p : G) { p = PolyUtil. monic(p); Gp.add(p); } PolynomialList> trinks = new PolynomialList>( F.ring, Gp); //System.out.println("G = " + trinks); //System.out.println("G.size() = " + Gp.size()); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //assertEquals("#GB(Trinks7) == 1", 1, G.size() ); } } java-algebra-system-2.7.200/trc/edu/jas/gb/EGroebnerBaseSeqTest.java000066400000000000000000000217351445075545500250770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * EGroebner base sequential tests with JUnit. * @author Heinz Kredel */ public class EGroebnerBaseSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a EGroebnerBaseSeqTest object. * @param name String. */ public EGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(EGroebnerBaseSeqTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bb; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 4; //4; 10 int ll = 4; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigInteger coeff = new BigInteger(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new EGroebnerBaseSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; ComputerThreads.terminate(); } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q).abs(); b = fac.random(kl, ll, el, q).abs(); c = fac.random(kl, ll / 2, el, q).abs(); d = fac.random(kl, ll / 2, el, q).abs(); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("eGB(L) = " + L ); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("eGB(L) = " + L ); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(c); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("eGB(L) = " + L ); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("eGB(L) = " + L ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println(" L = " + L ); L = bb.GB(L); //System.out.println("eGB(L) = " + L ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase over Z. */ @SuppressWarnings("unchecked") public void testTrinks7GBaseZ() { // needs 20 sec String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); //System.out.println("G = " + trinks); //System.out.println("G.size() = " + G.size()); assertTrue("isGB( eGB(Trinks7) )", bb.isGB(G)); //assertEquals("#GB(Trinks7) == 44", 44, G.size() ); } /** * Test Trinks7 GBase over Z(B). */ @SuppressWarnings("unchecked") public void testTrinks7GBaseZ_B() { String exam = "IntFunc{ B } (S,T,Z,P,W) G " + "( " + "( { 45 } P + { 35 } S - { 165 B } - { 36 } ), " + "( { 35 } P + { 40 } Z + { 25 } T - { 27 } S ), " + "( { 15 } W + { 25 } S P + { 30 } Z - { 18 } T - { 165 B**2 } ), " + "( { - 9 } W + { 15 } T P + { 20 } S Z ), " + "( P W + { 2 } T Z - { 11 B**3 } ), " + "( { 99 } W - { 11 B } S + { 3 B**2 } ), " + "( { 10000 B**2 + 6600 B + 2673 } ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); EGroebnerBaseSeq> bb = new EGroebnerBaseSeq>(); PolynomialList> F = null; List>> G = null; try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); List>> Fp = new ArrayList>>( F.list.size()); for (GenPolynomial> p : F.list) { p = PolyUtil. monic(p); Fp.add(p); } //System.out.println("Fp = " + Fp); G = bb.GB(Fp); //System.out.println("G = " + G); List>> Gp = new ArrayList>>( F.list.size()); for (GenPolynomial> p : G) { p = PolyUtil. monic(p); Gp.add(p); } PolynomialList> trinks = new PolynomialList>( F.ring, Gp); //System.out.println("G = " + trinks); //System.out.println("G.size() = " + G.size()); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //assertEquals("#GB(Trinks7) == 1", 1, G.size() ); } /** * Test sequential extended GBase. */ public void testSequentialExtendedGBase() { L = new ArrayList>(); ExtendedGB exgb; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); //System.out.println("L1 = " + L); exgb = bb.extGB(L); //System.out.println("exgb 1 = " + exgb); assertTrue("isGB( { a } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L2 = " + L); exgb = bb.extGB(L); //System.out.println("exgb 2 = " + exgb); assertTrue("isGB( { a, b } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); //System.out.println("L3 = " + L); exgb = bb.extGB(L); //System.out.println("exgb 3 = " + exgb ); assertTrue("isGB( { a, b, c } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c } )", bb.isMinReductionMatrix(exgb)); //if (true) { return; } assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); //System.out.println("L4 = " + L); exgb = bb.extGB(L); //System.out.println("exgb 4 = " + exgb ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); //System.out.println("L5 = " + L); exgb = bb.extGB(L); //System.out.println("exgb 5 = " + exgb ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d, e } )", bb.isMinReductionMatrix(exgb)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GBProxyTest.java000066400000000000000000000111141445075545500233030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base proxy of sequential and parallel tests with JUnit. * @author Heinz Kredel */ public class GBProxyTest extends TestCase { private static final Logger logger = LogManager.getLogger(GBProxyTest.class); /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GBProxyTest object. * @param name String. */ public GBProxyTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GBProxyTest.class); return suite; } GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBaseAbstract bb; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 7; int ll = 7; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; GroebnerBaseAbstract bbs = new GroebnerBaseSeq(); //GroebnerBaseAbstract bbs = new GroebnerBaseSeqPairSeq(); int nt = ComputerThreads.N_CPUS - 1; //System.out.println("nt = " + nt); GroebnerBaseAbstract bbp = new GroebnerBaseParallel(nt); //GroebnerBaseAbstract bbp = new GroebnerBaseSeqPairParallel(nt); bb = new GBProxy(bbs, bbp); } @Override protected void tearDown() { int s = bb.cancel(); logger.info("canceled tasks: " + s); //assertTrue("s >= 0 " + s, s >= 0); bb.terminate(); a = b = c = d = e = null; fac = null; bb = null; } /** * Test GBase. */ public void testGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings({ "cast", "unchecked" }) public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertEquals("#GB(Trinks7) == 6", 6, G.size()); assertTrue("isGB( GB(Trinks7) ) " + G, bb.isGB(G)); //PolynomialList trinks = new PolynomialList(F.ring, G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseDistECTest.java000066400000000000000000000204101445075545500253420ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; // import edu.jas.poly.GroebnerBase; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.util.ExecutableServer; /** * Distributed GroebnerBase tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistECTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistECTest object. * @param name String. */ public GroebnerBaseDistECTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistECTest.class); return suite; } int port = 55711; String host = "localhost"; String mfile = "examples/machines.localhost"; // contains localhost GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseAbstract bbdist; GroebnerBaseAbstract bbdists; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; ExecutableServer es1; ExecutableServer es2; @Override protected void setUp() { es1 = new ExecutableServer(4712); // == machines.localhost:4712 es1.init(); es2 = new ExecutableServer(4711); // == machines.localhost:4711 es2.init(); //System.out.println("es1 = " + es1); //System.out.println("es2 = " + es2); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdist = new GroebnerBaseDistributedEC(mfile, threads, port); //bbdists = new GroebnerBaseDistributedEC(mfile, threads, new OrderedSyzPairlist(), port); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; //bbdists.terminate(); //bbdists = null; es1.terminate(); es2.terminate(); es1 = null; es2 = null; ComputerThreads.terminate(); } /** * Test distributed GBase corner cases. */ public void testDistributedGBaseCorner() { L = new ArrayList>(); a = fac.getZERO(); L.add(a); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); assertTrue("L == {}: " + L, L.isEmpty()); b = fac.getONE(); L.add(b); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); assertTrue("L == {1}: " + L, L.size() == 1); } /** * Test distributed GBase. */ public void testDistributedGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bbdist.GB(L); assertTrue("isGB( { a, b } ): " + L, bbseq.isGB(L)); L.add(c); L = bbdist.GB(L); assertTrue("isGB( { a, b, c } ): " + L, bbseq.isGB(L)); L.add(d); L = bbdist.GB(L); assertTrue("isGB( { a, b, c, d } ): " + L, bbseq.isGB(L)); L.add(e); L = bbdist.GB(L); assertTrue("isGB( { a, b, c, d, e } ): " + L, bbseq.isGB(L)); } /** * Test compare sequential with distributed GBase. */ public void testSequentialDistributedGBase() { List> Gs, Gp = null; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { List> Gs, Gp = null; String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; //exam = "(x3,x4,x5) L " + // "( (x3^2 - 13974703710478159/3775194259200) , (x4 - 34297/840), (x5^2 - 6389/480), (-4/3 x5^2 + x3^2 + x3 - 833/180) ) "; //exam = "(x3,x4,x5) G " + // "( x4^2 + 1809/30976 x3^2 + 190760/17787 x4 + 1755/10648 x3 + 296895202578451/10529038840320 , x3 * x4 - 15/64 x3^2 + 1223/294 x3 - 68247/58240 , x5 - 11/6 x4 - 3/16 x3 - 44162/4851 , x3^3 + 441280/68651 x3^2 + 29361376/2839655 x4 + 7055752657/687196510 x3 + 28334577136/417429285 , -8/9 x3^2 - 2 x5 + x3 - 159/44 )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); Gs = bbseq.GB(F.list); //System.out.println("Gs = " + Gs); Gp = bbdist.GB(F.list); //System.out.println("Gp = " + Gp); assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(Gp)); assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(Gs)); //assertEquals("#GB(Trinks7) == 6", 6, G.size()); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + F, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + F, Gp.containsAll(Gs)); //PolynomialList trinks = new PolynomialList(F.ring, Gp); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseDistHybridECTest.java000066400000000000000000000173401445075545500265140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; // import edu.jas.poly.GroebnerBase; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.util.ExecutableServer; /** * Distributed hybrid GroebnerBase tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseDistHybridECTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); //ComputerThreads.terminate(); } /** * Constructs a GroebnerBaseDistHybridECTest object. * @param name String. */ public GroebnerBaseDistHybridECTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseDistHybridECTest.class); return suite; } int port = 55711; String host = "localhost"; String mfile = "examples/machines.localhost"; // contains localhost GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseAbstract bbdist; GroebnerBaseAbstract bbdists; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 4; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; ExecutableServer es1; ExecutableServer es2; @Override protected void setUp() { es1 = new ExecutableServer(4712); // == machines.localhost:4712 es1.init(); es2 = new ExecutableServer(4711); // == machines.localhost:4711 es2.init(); BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdist = new GroebnerBaseDistributedHybridEC(mfile, threads, port); //bbdists = new GroebnerBaseDistributedHybridEC(mfile, threads, new OrderedSyzPairlist(), port); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; //bbdists.terminate(); //bbdists = null; es1.terminate(); es2.terminate(); es1 = null; es2 = null; ComputerThreads.terminate(); } /** * Test distributed GBase corner cases. */ public void testDistributedGBaseCorner() { L = new ArrayList>(); a = fac.getZERO(); L.add(a); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); assertTrue("L == {}: " + L, L.isEmpty()); b = fac.getONE(); L.add(b); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); assertTrue("L == {1}: " + L, L.size() == 1); } /** * Test distributed GBase. */ public void testDistributedGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); L = bbdist.GB(L); assertTrue("isGB( { a } ): " + L, bbseq.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bbdist.GB(L); assertTrue("isGB( { a, b } ): " + L, bbseq.isGB(L)); L.add(c); L = bbdist.GB(L); assertTrue("isGB( { a, b, c } ): " + L, bbseq.isGB(L)); L.add(d); L = bbdist.GB(L); assertTrue("isGB( { a, b, c, d } ): " + L, bbseq.isGB(L)); L.add(e); L = bbdist.GB(L); assertTrue("isGB( { a, b, c, d, e } ): " + L, bbseq.isGB(L)); } /** * Test compare sequential with distributed GBase. */ public void testSequentialDistributedGBase() { List> Gs, Gp = null; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbdist.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + L, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + L, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { List> Gs, Gp = null; String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; //exam = "(x3,x4,x5) L " + // "( (x3^2 - 13974703710478159/3775194259200) , (x4 - 34297/840), (x5^2 - 6389/480), (-4/3 x5^2 + x3^2 + x3 - 833/180) ) "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); Gs = bbseq.GB(F.list); //System.out.println("Gs = " + Gs); Gp = bbdist.GB(F.list); //System.out.println("Gp = " + Gp); assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(Gp)); assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(Gs)); //assertEquals("#GB(Trinks7) == 6", 6, G.size()); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp + ", " + F, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp + ", " + F, Gp.containsAll(Gs)); //PolynomialList trinks = new PolynomialList(F.ring, Gp); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseParIterTest.java000066400000000000000000000131301445075545500255760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * GroebnerBase parallel iterative GB tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseParIterTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseParIterTest object. * @param name String. */ public GroebnerBaseParIterTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseParIterTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bbseq; GroebnerBaseAbstract bbpar; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeqIter(); bbpar = new GroebnerBaseParIter(threads); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbpar.terminate(); bbpar = null; } /** * Test parallel GBase. */ public void testParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); L = bbpar.GB(L); assertTrue("isGB( { a } )", bbpar.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bbpar.GB(L); assertTrue("isGB( { a, b } )", bbpar.isGB(L)); L.add(c); L = bbpar.GB(L); assertTrue("isGB( { a, b, c } )", bbpar.isGB(L)); L.add(d); L = bbpar.GB(L); assertTrue("isGB( { a, b, c, d } )", bbpar.isGB(L)); L.add(e); L = bbpar.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbpar.isGB(L)); } /** * Test compare sequential with parallel GBase. */ public void testSequentialParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L.add(a); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bbpar.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bbpar.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseParSyzPairTest.java000066400000000000000000000213111445075545500262740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base parallel, syzygy pair list, tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseParSyzPairTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseParSyzPairTest object. * @param name String. */ public GroebnerBaseParSyzPairTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseParSyzPairTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bbseq; GroebnerBaseAbstract bbpar; GroebnerBaseAbstract bbspar; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbpar = new GroebnerBaseParallel(threads); bbspar = new GroebnerBaseParallel(threads, new ReductionPar(), new OrderedSyzPairlist()); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbpar.terminate(); bbpar = null; bbspar.terminate(); bbspar = null; } /** * Test syzygy pair parallel GBase. */ public void testSyzPairParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bbspar.GB(L); assertTrue("isGB( { a } )", bbspar.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bbspar.GB(L); assertTrue("isGB( { a, b } )", bbspar.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bbspar.GB(L); assertTrue("isGB( { a, b, c } )", bbspar.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bbspar.GB(L); assertTrue("isGB( { a, b, c, d } )", bbspar.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bbspar.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbspar.isGB(L)); } /** * Test compare sequential with syzygy pair parallel GBase. */ public void testSequentialSyzPairParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test compare parallel with syzygy pair parallel GBase. */ public void testParallelSyzPairParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + ", ( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long t; /* t = System.currentTimeMillis(); G = bbseq.GB( F.list ); t = System.currentTimeMillis() - t; System.out.println("bbseq ms = " + t); t = System.currentTimeMillis(); G = bbpar.GB( F.list ); t = System.currentTimeMillis() - t; System.out.println("bbpar ms = " + t); */ t = System.currentTimeMillis(); G = bbspar.GB(F.list); t = System.currentTimeMillis() - t; //System.out.println("bbspar ms = " + t); assertTrue("nonsense ", t >= 0L); assertTrue("isGB( GB(Trinks7) )", bbspar.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseParTest.java000066400000000000000000000140301445075545500247520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GroebnerBase parallel tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseParTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseParTest object. * @param name String. */ public GroebnerBaseParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseParTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBase bbseq; GroebnerBase bbpar; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbpar = new GroebnerBaseParallel(threads); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; ((GroebnerBaseParallel) bbpar).terminate(); bbpar = null; } /** * Test parallel GBase. */ public void testParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bbpar.GB(L); assertTrue("isGB( { a } )", bbpar.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bbpar.GB(L); assertTrue("isGB( { a, b } )", bbpar.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bbpar.GB(L); assertTrue("isGB( { a, b, c } )", bbpar.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bbpar.GB(L); assertTrue("isGB( { a, b, c, d } )", bbpar.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bbpar.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbpar.isGB(L)); } /** * Test compare sequential with parallel GBase. */ public void testSequentialParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbpar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bbpar.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bbpar.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSeqIterTest.java000066400000000000000000000166561445075545500256240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base sequential iterative GB tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSeqIterTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSeqIterTest object. * @param name String. */ public GroebnerBaseSeqIterTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSeqIterTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bb; GenPolynomial a, b, c, d, e; int rl = 4; //4; //3; int kl = 7; // 10 int ll = 7; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBaseSeqIter(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; @SuppressWarnings("unused") String exam2 = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); //System.out.println("G = " + G); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test Trinks7 GBase, syz pair list. */ @SuppressWarnings("unchecked") public void testTrinks7GBaseSyz() { GroebnerBase bbs; bbs = new GroebnerBaseSeqIter(new ReductionSeq(), new OrderedSyzPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; @SuppressWarnings("unused") String exam2 = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bbs.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bbs.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //Reduction rd = new ReductionSeq(); //System.out.println("G.contains(F) = " + rd.normalform(G,F.list) ); } /** * Test Trinks7 GBase, min pair list. */ @SuppressWarnings("unchecked") public void testTrinks7GBaseMin() { bb = new GroebnerBaseSeqIter(new ReductionSeq(), new OrderedMinPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSeqPairDistTest.java000066400000000000000000000202731445075545500264260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; // import edu.jas.poly.GroebnerBase; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingElem; /** * Groebner base distributed, sequential pair list, tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSeqPairDistTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSeqPairDistTest object. * @param name String. */ public GroebnerBaseSeqPairDistTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSeqPairDistTest.class); return suite; } int port = 4711; String host = "localhost"; GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bbseq; GroebnerBaseSeqPairDistributed bbdist; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 3; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbdist = new GroebnerBaseSeqPairDistributed(threads, port); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbdist.terminate(); bbdist = null; } /** * Helper method to start threads with distributed clients. */ Thread[] startThreads() { Thread[] clients = new Thread[threads]; for (int t = 0; t < threads; t++) { clients[t] = new Thread(new JunitSeqPairClient(host, port)); clients[t].start(); } return clients; } /** * Helper method to stop threads with distributed clients. */ void stopThreads(Thread[] clients) { for (int t = 0; t < threads; t++) { try { clients[t].join(); } catch (InterruptedException e) { } } } /** * Test distributed GBase. */ public void testSeqPairDistributedGBase() { Thread[] clients; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); clients = startThreads(); L = bbdist.GB(L); stopThreads(clients); assertTrue("isGB( { a } )", bbseq.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); clients = startThreads(); L = bbdist.GB(L); stopThreads(clients); assertTrue("isGB( { a, b } )", bbseq.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); clients = startThreads(); L = bbdist.GB(L); stopThreads(clients); assertTrue("isGB( { a, b, c } )", bbseq.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); clients = startThreads(); L = bbdist.GB(L); stopThreads(clients); assertTrue("isGB( { a, b, c, d } )", bbseq.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); clients = startThreads(); L = bbdist.GB(L); stopThreads(clients); assertTrue("isGB( { a, b, c, d, e } )", bbseq.isGB(L)); } /** * Test compare sequential with distributed GBase. */ public void testSequentialSeqPairDistributedGBase() { Thread[] clients; List> Gs, Gp = null; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbseq.GB(L); clients = startThreads(); Gp = bbdist.GB(L); stopThreads(clients); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); clients = startThreads(); Gp = bbdist.GB(L); stopThreads(clients); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); clients = startThreads(); Gp = bbdist.GB(L); stopThreads(clients); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); clients = startThreads(); Gp = bbdist.GB(L); stopThreads(clients); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); clients = startThreads(); Gp = bbdist.GB(L); stopThreads(clients); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { Thread[] clients; String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); clients = startThreads(); G = bbdist.GB(F.list); stopThreads(clients); assertTrue("isGB( GB(Trinks7) )", bbseq.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } /** * Unit Test client to be executed by test threads. */ class JunitSeqPairClient> implements Runnable { private final String host; private final int port; JunitSeqPairClient(String host, int port) { this.host = host; this.port = port; } public void run() { GroebnerBaseSeqPairDistributed bbd; bbd = new GroebnerBaseSeqPairDistributed(1, null, port); try { bbd.clientPart(host); } catch (IOException ignored) { } bbd.terminate(); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSeqPairParTest.java000066400000000000000000000211401445075545500262370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base parallel, sequential pair list, tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSeqPairParTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSeqPairParTest object. * @param name String. */ public GroebnerBaseSeqPairParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSeqPairParTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bbseq; GroebnerBaseAbstract bbpar; GroebnerBaseAbstract bbspar; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bbseq = new GroebnerBaseSeq(); bbpar = new GroebnerBaseParallel(threads); bbspar = new GroebnerBaseSeqPairParallel(threads); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bbseq = null; bbpar.terminate(); bbpar = null; bbspar.terminate(); bbspar = null; } /** * Test parallel GBase. */ public void testSeqPairParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bbspar.GB(L); assertTrue("isGB( { a } )", bbspar.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bbspar.GB(L); assertTrue("isGB( { a, b } )", bbspar.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bbspar.GB(L); assertTrue("isGB( { a, b, c } )", bbspar.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bbspar.GB(L); assertTrue("isGB( { a, b, c, d } )", bbspar.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bbspar.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbspar.isGB(L)); } /** * Test compare sequential with parallel GBase. */ public void testSequentialSeqPairParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbseq.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp)" + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs)" + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test compare parallel with sequential pair parallel GBase. */ public void testParallelSeqPairParallelGBase() { List> Gs, Gp; L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } L.add(a); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(b); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(c); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(d); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); L = Gs; L.add(e); Gs = bbpar.GB(L); Gp = bbspar.GB(L); assertTrue("Gs.containsAll(Gp) " + Gs + ", " + Gp, Gs.containsAll(Gp)); assertTrue("Gp.containsAll(Gs) " + Gs + ", " + Gp, Gp.containsAll(Gs)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + ", ( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long t; /* t = System.currentTimeMillis(); G = bbseq.GB( F.list ); t = System.currentTimeMillis() - t; System.out.println("bbseq ms = " + t); t = System.currentTimeMillis(); G = bbpar.GB( F.list ); t = System.currentTimeMillis() - t; System.out.println("bbpar ms = " + t); */ t = System.currentTimeMillis(); G = bbspar.GB(F.list); t = System.currentTimeMillis() - t; //System.out.println("bbspar ms = " + t); assertTrue("nonsense ", t >= 0L); assertTrue("isGB( GB(Trinks7) )", bbspar.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSeqPairSeqTest.java000066400000000000000000000170101445075545500262460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base sequential, sequential pair list, tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSeqPairSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSeqPairSeqTest object. * @param name String. */ public GroebnerBaseSeqPairSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSeqPairSeqTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bb; // not interface GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 2; // 10; int ll = 5; //7; int el = 3; float q = 0.3f; //0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBaseSeqPairSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSeqPairSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test sequential extended GBase. */ public void testSeqPairSequentialExtendedGBase() { L = new ArrayList>(); ExtendedGB exgb; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); //System.out.println("L = " + L ); exgb = bb.extGB(L); // System.out.println("exgb = " + exgb ); assertTrue("isGB( { a } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L ); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d, e } )", bb.isMinReductionMatrix(exgb)); } /** * Test Trinks7 extended GBase. */ @SuppressWarnings("unchecked") public void testTrinks7ExtendedGBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); ExtendedGB exgb; exgb = bb.extGB(F.list); //System.out.println("exgb = " + exgb ); assertTrue("isGB( GB(Trinks7) )", bb.isGB(exgb.G)); //assertEquals("#GB(Trinks7) == 6", 6, exgb.G.size() ); assertTrue("isRmat( GB(Trinks7) )", bb.isMinReductionMatrix(exgb)); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSeqTest.java000066400000000000000000000315511445075545500247670ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSeqTest object. * @param name String. */ public GroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSeqTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBaseAbstract bb; GenPolynomial a, b, c, d, e; int rl = 4; //4; //3; int kl = 7; // 10 int ll = 7; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBaseSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; @SuppressWarnings("unused") String exam2 = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test sequential extended GBase. */ public void testSequentialExtendedGBase() { L = new ArrayList>(); ExtendedGB exgb; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); //System.out.println("L = " + L ); exgb = bb.extGB(L); // System.out.println("exgb = " + exgb ); assertTrue("isGB( { a } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L ); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d } )", bb.isMinReductionMatrix(exgb)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); exgb = bb.extGB(L); //System.out.println("exgb = " + exgb ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(exgb.G)); assertTrue("isRmat( { a, b, c, d, e } )", bb.isMinReductionMatrix(exgb)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7ExtendedGBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); ExtendedGB exgb; exgb = bb.extGB(F.list); //System.out.println("exgb = " + exgb ); assertTrue("isGB( GB(Trinks7) )", bb.isGB(exgb.G)); //assertEquals("#GB(Trinks7) == 6", 6, exgb.G.size() ); assertTrue("isRmat( GB(Trinks7) )", bb.isMinReductionMatrix(exgb)); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test Trinks7 GBase, syz pair list. */ @SuppressWarnings("unchecked") public void testTrinks7GBaseSyz() { GroebnerBase bbs; bbs = new GroebnerBaseSeq(new ReductionSeq(), new OrderedSyzPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; @SuppressWarnings("unused") String exam2 = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bbs.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bbs.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); //Reduction rd = new ReductionSeq(); //System.out.println("G.contains(F) = " + rd.normalform(G,F.list) ); } /** * Test Trinks7 GBase, min pair list. */ @SuppressWarnings("unchecked") public void testTrinks7GBaseMin() { bb = new GroebnerBaseSeq(new ReductionSeq(), new OrderedMinPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test sequential GBase, both. Test isGBsimple and isGBidem. */ public void testSequentialGBaseBoth() { GroebnerBaseAbstract bbs = new GroebnerBaseSeq( new ReductionSeq(), new OrderedSyzPairlist()); L = new ArrayList>(); List> G; do { a = fac.random(kl, ll, el, q); } while (a.isZERO() || a.isONE()); do { b = fac.random(kl, ll, el, q); } while (b.isZERO() || b.isONE()); do { c = fac.random(kl, ll, el, q); } while (c.isZERO() || c.isONE()); do { d = fac.random(kl, ll, el, q); } while (d.isZERO() || d.isONE()); e = d; //fac.random(kl, ll, el, q ); L.add(a); G = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(G)); G = bbs.GB(L); assertTrue("isGB( { a } )", bbs.isGB(G)); assertEquals("isGBsimple(G) == isGBidem(G)", bb.isGB(G), bb.isGB(G, false)); G.add(b); L = G; G = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(G)); G = bbs.GB(L); assertTrue("isGB( { a, b } )", bbs.isGB(G)); assertEquals("isGBsimple(G) == isGBidem(G)", bb.isGB(G), bb.isGB(G, false)); G.add(c); L = G; G = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(G)); G = bbs.GB(L); assertTrue("isGB( { a, b, c } )", bbs.isGB(G)); assertEquals("isGBsimple(G) == isGBidem(G)", bb.isGB(G), bb.isGB(G, false)); G.add(d); L = G; G = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(G)); G = bbs.GB(L); assertTrue("isGB( { a, b, c, d } )", bbs.isGB(G)); assertEquals("isGBsimple(G) == isGBidem(G)", bb.isGB(G), bb.isGB(G, false)); G.add(e); L = G; G = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(G)); G = bbs.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbs.isGB(G)); //System.out.println("G = " + G); assertEquals("isGBsimple(G) == isGBidem(G)", bb.isGB(G), bb.isGB(G, false)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/GroebnerBaseSigSeqIterTest.java000066400000000000000000000175501445075545500262610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.Random; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrderByName; /** * Groebner base signature based sequential iterative GB tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseSigSeqIterTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseSigSeqIterTest object. * @param name String. */ public GroebnerBaseSigSeqIterTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseSigSeqIterTest.class); return suite; } GenPolynomialRing fac; List> L, G, Gp; PolynomialList F; GroebnerBaseAbstract bb, bbsig, bbggv, bbarri, bbf5z; GenPolynomial a, b, c, d, e; int rl = 4; //4; //3; int kl = 3; // 10 int ll = 5; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); String[] vars = new String[] { "u", "x", "y", "z" }; fac = new GenPolynomialRing(coeff, vars, TermOrderByName.IGRLEX); a = b = c = d = e = null; bb = new GroebnerBaseSeqIter(); bbsig = new GroebnerBaseSigSeqIter(); bbggv = new GroebnerBaseGGVSigSeqIter(); bbarri = new GroebnerBaseArriSigSeqIter(); bbf5z = new GroebnerBaseF5zSigSeqIter(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.parse("x^4 + 4/5 x^2 - 12/25 u * x - 183/175"); b = fac.parse("x^3 * y + 40/7 x^3 + 4/5 x * y - 12/25 u * y + 183/2450 u^2 + 32/7 x - 96/35 u"); c = fac.parse("u^2 * x + 14 y + 80"); d = fac.parse("y^2 - 5/4 x^2 - 1"); e = fac.parse("z"); int x = (new Random()).nextInt(4); switch (x) { case 0: bb = bbf5z; break; case 1: bb = bbggv; break; case 2: bb = bbarri; break; default: break; } L.add(a); L.add(b); L.add(c); L.add(d); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } ): " + L, bb.isGB(L)); //System.out.println("L = " + L); } /** * Test random sequential GBase. */ public void testRandomSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.univariate(0); //fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); int x = (new Random()).nextInt(4); switch (x) { case 0: bb = bbf5z; break; case 1: bb = bbggv; break; case 2: bb = bbarri; break; default: break; } L.add(a); L = bb.GB(L); assertTrue("isGB( { a } ): " + L, bb.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } ): " + L, bb.isGB(L)); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } ): " + L, bb.isGB(L)); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } ): " + L, bb.isGB(L)); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } ): " + L, bb.isGB(L)); //System.out.println("L = " + L); } /** * Test Trinks7 GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( P W + 2 T Z - 11 B**3 ), " //+ "( B**2 + 33/50 B + 2673/10000 ) " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( 99 W - 11 B S + 3 B**2 ), " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); long t1 = System.currentTimeMillis(); G = bb.GB(F.list); t1 = System.currentTimeMillis() - t1; assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); G = OrderedPolynomialList. sort(G); long t2 = System.currentTimeMillis(); Gp = G; //bbsig.GB(F.list); t2 = System.currentTimeMillis() - t2; assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gp)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); Gp = OrderedPolynomialList. sort(Gp); assertEquals("GB == GBp", G, Gp); Gp = bbf5z.GB(F.list); long t5 = System.currentTimeMillis(); Gp = bbf5z.GB(F.list); t5 = System.currentTimeMillis() - t5; assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gp)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); Gp = OrderedPolynomialList. sort(Gp); assertEquals("GB == GBp", G, Gp); Gp = bbarri.GB(F.list); long t4 = System.currentTimeMillis(); Gp = bbarri.GB(F.list); t4 = System.currentTimeMillis() - t4; assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gp)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); Gp = OrderedPolynomialList. sort(Gp); assertEquals("GB == GBp", G, Gp); Gp = bbggv.GB(F.list); long t3 = System.currentTimeMillis(); Gp = bbggv.GB(F.list); t3 = System.currentTimeMillis() - t3; assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gp)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); Gp = OrderedPolynomialList. sort(Gp); assertEquals("GB == GBp", G, Gp); //System.out.println("G = " + G); //System.out.println("iter executed in " + t1 + " milliseconds"); ////System.out.println("sig executed in " + t2 + " milliseconds"); //System.out.println("ggv executed in " + t3 + " milliseconds"); //System.out.println("arris executed in " + t4 + " milliseconds"); //System.out.println("f5z executed in " + t5 + " milliseconds"); long t = t1 + t2 + t3 + t4 + t5; assertTrue("times >= 0: " + t, t >= 0); //findbugs and compiler assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gb/ModGroebnerBaseTest.java000066400000000000000000000162741445075545500247630ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; /** * ModGroebnerBase sequential and parallel tests with JUnit. * @author Heinz Kredel */ public class ModGroebnerBaseTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a ModGroebnerBaseTest object. * @param name String. */ public ModGroebnerBaseTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ModGroebnerBaseTest.class); return suite; } GenPolynomialRing fac; PolynomialList F; List> G; GenPolynomial a, b, c, d, e; TermOrder tord; List>> L; List> V; ModuleList M, N, K, I; GroebnerBaseAbstract mbb; ReductionAbstract red; int rl = 3; //4; //3; int kl = 7; int ll = 5; int el = 2; float q = 0.2f; //0.4f BigRational coeff; @Override protected void setUp() { coeff = new BigRational(); tord = TermOrderByName.DEFAULT; // INVLEX fac = new GenPolynomialRing(coeff, rl, tord); mbb = new GroebnerBaseSeq(); //coeff); red = new ReductionSeq(); a = b = c = d = e = null; do { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; //fac.random(kl, ll, el, q ); } @Override protected void tearDown() { mbb.terminate(); mbb = null; red = null; a = b = c = d = e = null; fac = null; tord = null; } /** * Test sequential GBase. */ public void testSequentialModGB() { L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(fac.getZERO()); V.add(fac.getONE()); L.add(V); M = new ModuleList(fac, L); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(M)); N = mbb.GB(M); assertTrue("is( { (a,0,1) } )", mbb.isGB(N)); V = new ArrayList>(); V.add(b); V.add(fac.getONE()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,0,1),(b,1,0) } )", mbb.isGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(fac.getZERO()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,),(b,),(c,) } )", mbb.isGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(fac.getZERO()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,b,c,d) } )", mbb.isGB(N)); //System.out.println("N = " + N ); } /** * Test parallel GBase. */ public void testParallelModGB() { mbb = new GroebnerBaseParallel(); //coeff); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(fac.getZERO()); V.add(fac.getONE()); L.add(V); M = new ModuleList(fac, L); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(M)); N = mbb.GB(M); assertTrue("is( { (a,0,1) } )", mbb.isGB(N)); V = new ArrayList>(); V.add(b); V.add(fac.getONE()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,0,1),(b,1,0) } )", mbb.isGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(fac.getZERO()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,),(b,),(c,) } )", mbb.isGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(fac.getZERO()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("L = " + L.size() ); N = mbb.GB(M); assertTrue("isGB( { (a,b,c,d) } )", mbb.isGB(N)); //System.out.println("N = " + N ); } /** * Test sequential GBase with TOP and POT term order. */ public void testSequentialModTOPGB() { //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(fac.getZERO()); V.add(fac.getONE()); L.add(V); M = new ModuleList(fac, L); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(M)); N = mbb.GB(M); assertTrue("is( { (a,0,1) } )", mbb.isGB(N)); K = mbb.GB(M, true); assertTrue("is( { (a,0,1) } )", mbb.isGB(K, true)); assertEquals("N == K", N, K); V = new ArrayList>(); V.add(b); V.add(fac.getONE()); V.add(fac.getZERO()); L.add(V); M = new ModuleList(fac, L); //System.out.println("M = " + M); N = mbb.GB(M); assertTrue("isGB( { (a,0,1),(b,1,0) } )", mbb.isGB(N)); //System.out.println("N = " + N); K = mbb.GB(M,true); assertTrue("is( { (a,0,1) } )", mbb.isGB(K, true)); //System.out.println("K = " + K); I = red.normalform(K, N, true); //System.out.println("I = " + I); assertTrue("K.nf(N) == (0)", I.isZERO()); I = red.normalform(N, K); //System.out.println("I = " + I); assertTrue("N.nf(K) == (0)", I.isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/gb/ModSolvableGroebnerBaseTest.java000066400000000000000000000505601445075545500264470ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; /** * ModSolvableGroebnerBase sequential and parallel tests with JUnit. * @author Heinz Kredel */ public class ModSolvableGroebnerBaseTest extends TestCase { private static final Logger logger = LogManager.getLogger(ModSolvableGroebnerBaseTest.class); /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a ModSolvableGroebnerBaseTest object. * @param name String. */ public ModSolvableGroebnerBaseTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ModSolvableGroebnerBaseTest.class); return suite; } int port = 4711; BigRational cfac; GenSolvablePolynomialRing pfac; GenSolvablePolynomial a, b, c, d, e; TermOrder tord; GenSolvablePolynomial one, zero; RelationTable table; List>> L; List> V; PolynomialList F, G; ModuleList M, N, K, I; SolvableGroebnerBaseAbstract sbb; SolvableReductionAbstract sred; int rl = 3; //4; //3; int kl = 4; int ll = 3; int el = 2; float q = 0.2f; //0.4f @Override protected void setUp() { cfac = new BigRational(1); tord = new TermOrder(); pfac = new GenSolvablePolynomialRing(cfac, rl, tord); if (Math.random() > 0.5) { sbb = new SolvableGroebnerBaseSeq(); //cfac); } else { sbb = new SolvableGroebnerBaseParallel(); //cfac); } sred = new SolvableReductionSeq(); logger.info("test with " + sbb.getClass().getSimpleName()); a = b = c = d = e = null; do { a = pfac.random(kl, ll, el, q); b = pfac.random(kl, ll, el, q); c = pfac.random(kl, ll, el, q); d = pfac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; // = pfac.random(kl, ll, el, q ); one = pfac.getONE(); zero = pfac.getZERO(); } @Override protected void tearDown() { a = b = c = d = e = null; one = null; zero = null; sbb.terminate(); sbb = null; sred = null; } /** * Test sequential left GBase. */ public void testSequentialLeftModSolvableGB() { L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); assertTrue("isLeftGB( { (a,0,1) } )", sbb.isLeftGB(M)); //System.out.println("M = " + M ); N = sbb.leftGB(M); //System.out.println("N = " + N ); assertTrue("isLeftGB( { (a,0,1) } )", sbb.isLeftGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,0,1),(b,1,0) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,),(b,),(c,) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,b,c,d) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); } /** * Test sequential left Weyl GBase. */ public void testSequentialLeftModSolvableWeylGB() { int rloc = 4; pfac = new GenSolvablePolynomialRing(cfac, rloc, tord); //System.out.println("pfac = " + pfac); //System.out.println("pfac end"); RelationGenerator wl = new WeylRelations(); //System.out.println("wl = "); wl.generate(pfac); //System.out.println("generate = "); table = pfac.table; //System.out.println("table = "); //System.out.println("table = " + table.size()); do { a = pfac.random(kl, ll, el, q); b = pfac.random(kl, ll, el, q); c = pfac.random(kl, ll, el, q); d = pfac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; // = pfac.random(kl, ll, el, q ); one = pfac.getONE(); zero = pfac.getZERO(); //System.out.println("a = " + a ); //System.out.println("b = " + b ); //System.out.println("c = " + c ); //System.out.println("d = " + d ); //System.out.println("e = " + e ); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); assertTrue("isLeftGB( { (a,0,1) } )", sbb.isLeftGB(M)); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,0,1) } )", sbb.isLeftGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,0,1),(b,1,0) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,),(b,),(c,) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.leftGB(M); assertTrue("isLeftGB( { (a,b,c,d) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N ); } /** * Test sequential twosided GBase. */ public void testSequentialTSModSolvableGB() { L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); assertTrue("isTwosidedGB( { (a,0,1) } )", sbb.isTwosidedGB(M)); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,0,1) } )", sbb.isTwosidedGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,0,1),(b,1,0) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,),(b,),(c,) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,b,c,d) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); } /** * Test sequential twosided Weyl GBase. */ public void testSequentialTSModSolvableWeylGB() { int rloc = 4; pfac = new GenSolvablePolynomialRing(cfac, rloc, tord); //System.out.println("pfac = " + pfac); //System.out.println("pfac end"); RelationGenerator wl = new WeylRelations(); //System.out.println("wl = "); wl.generate(pfac); //System.out.println("generate = "); table = pfac.table; //System.out.println("table = "); //System.out.println("table = " + table.size()); do { a = pfac.random(kl, ll, el, q); b = pfac.random(kl, ll, el, q); c = pfac.random(kl, ll, el, q); d = pfac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; // = pfac.random(kl, ll, el, q ); one = pfac.getONE(); zero = pfac.getZERO(); //System.out.println("a = " + a ); //System.out.println("b = " + b ); //System.out.println("c = " + c ); //System.out.println("d = " + d ); //System.out.println("e = " + e ); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); // not true in general assertTrue("isTwosidedGB( { (a,0,1) } )", sbb.isTwosidedGB(M) || !pfac.isCommutative()); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,0,1) } )", sbb.isTwosidedGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,0,1),(b,1,0) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,),(b,),(c,) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.twosidedGB(M); assertTrue("isTwosidedGB( { (a,b,c,d) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N ); } /** * Test sequential right GBase. */ public void testSequentialRightModSolvableGB() { L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); assertTrue("isRightGB( { (a,0,1) } )", sbb.isRightGB(M)); //System.out.println("M = " + M ); N = sbb.rightGB(M); //System.out.println("N = " + N ); assertTrue("isRightGB( { (a,0,1) } )", sbb.isRightGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); //System.out.println("M = " + M ); N = sbb.rightGB(M); //System.out.println("N = " + N ); assertTrue("isRightGB( { (a,0,1),(b,1,0) } )", sbb.isRightGB(N)); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.rightGB(M); assertTrue("isRightGB( { (a,),(b,),(c,) } )", sbb.isRightGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.rightGB(M); assertTrue("isRightGB( { (a,b,c,d) } )", sbb.isRightGB(N)); //System.out.println("N = " + N ); } /** * Test sequential right Weyl GBase. */ public void testSequentialRightModSolvableWeylGB() { int rloc = 4; pfac = new GenSolvablePolynomialRing(cfac, rloc, tord); //System.out.println("pfac = " + pfac); //System.out.println("pfac end"); RelationGenerator wl = new WeylRelations(); //System.out.println("wl = "); wl.generate(pfac); //System.out.println("generate = "); table = pfac.table; //System.out.println("table = "); //System.out.println("table = " + table.size()); do { a = pfac.random(kl, ll, el, q); b = pfac.random(kl, ll, el, q); c = pfac.random(kl, ll, el, q); d = pfac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; // = pfac.random(kl, ll, el, q ); one = pfac.getONE(); zero = pfac.getZERO(); //System.out.println("a = " + a ); //System.out.println("b = " + b ); //System.out.println("c = " + c ); //System.out.println("d = " + d ); //System.out.println("e = " + e ); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); L.add(V); M = new ModuleList(pfac, L); assertTrue("isRightGB( { (a,0,1) } )", sbb.isRightGB(M)); N = sbb.rightGB(M); assertTrue("isRightGB( { (a,0,1) } )", sbb.isRightGB(N)); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("L = " + L.size() ); //System.out.println("M = " + M ); N = sbb.rightGB(M); //System.out.println("N = " + N ); assertTrue("isRightGB( { (a,0,1),(b,1,0) } )", sbb.isRightGB(N)); V = new ArrayList>(); V.add(c); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.rightGB(M); assertTrue("isRightGB( { (a,),(b,),(c,) } )", sbb.isRightGB(N)); //System.out.println("N = " + N ); V = new ArrayList>(); V.add(d); V.add(zero); V.add(zero); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M ); //System.out.println("L = " + L.size() ); N = sbb.rightGB(M); assertTrue("isRightGB( { (a,b,c,d) } )", sbb.isRightGB(N)); //System.out.println("N = " + N ); } /** * Test sequential left GBase with TOP and POT term order. */ public void testSequentialModTOPleftGB() { //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(pfac.getZERO()); V.add(pfac.getONE()); L.add(V); M = new ModuleList(pfac, L); assertTrue("isGB( { (a,0,1) } )", sbb.isLeftGB(M)); N = sbb.leftGB(M); assertTrue("is( { (a,0,1) } )", sbb.isLeftGB(N)); K = sbb.leftGB(M, true); assertTrue("is( { (a,0,1) } )", sbb.isLeftGB(K, true)); assertEquals("N == K", N, K); V = new ArrayList>(); V.add(b); V.add(pfac.getONE()); V.add(pfac.getZERO()); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M); N = sbb.leftGB(M); assertTrue("isGB( { (a,0,1),(b,1,0) } )", sbb.isLeftGB(N)); //System.out.println("N = " + N); K = sbb.leftGB(M,true); assertTrue("is( { (a,0,1) } )", sbb.isLeftGB(K, true)); //System.out.println("K = " + K); I = sred.leftNormalform(N, K); //System.out.println("I = " + I); assertTrue("N.lnf(K) == (0)", I.isZERO()); I = sred.leftNormalform(K, N, true); //System.out.println("I = " + I); assertTrue("K.lnf(N) == (0)", I.isZERO()); } /** * Test sequential twosided GBase with TOP and POT term order. */ public void testSequentialModTOPtwosidedGB() { //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>>(); V = new ArrayList>(); V.add(a); V.add(pfac.getZERO()); V.add(pfac.getONE()); L.add(V); M = new ModuleList(pfac, L); assertTrue("isGB( { (a,0,1) } )", sbb.isTwosidedGB(M)); N = sbb.twosidedGB(M); assertTrue("is( { (a,0,1) } )", sbb.isTwosidedGB(N)); K = sbb.twosidedGB(M, true); assertTrue("is( { (a,0,1) } )", sbb.isTwosidedGB(K, true)); assertEquals("N == K", N, K); V = new ArrayList>(); V.add(b); V.add(pfac.getONE()); V.add(pfac.getZERO()); L.add(V); M = new ModuleList(pfac, L); //System.out.println("M = " + M.toScript()); N = sbb.twosidedGB(M); assertTrue("isGB( { (a,0,1),(b,1,0) } )", sbb.isTwosidedGB(N)); //System.out.println("N = " + N); K = sbb.twosidedGB(M,true); assertTrue("is( { (a,0,1) } )", sbb.isTwosidedGB(K, true)); //System.out.println("K = " + K); I = sred.leftNormalform(N, K); //System.out.println("I = " + I); assertTrue("N.lnf(K) == (0)", I.isZERO()); I = sred.leftNormalform(K, N, true); //System.out.println("I = " + I); assertTrue("K.lnf(N) == (0)", I.isZERO()); } /* * No TOP term order for sequential right GBase. */ } java-algebra-system-2.7.200/trc/edu/jas/gb/PairListTest.java000066400000000000000000000112671445075545500235110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; /** * Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class PairListTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PairListTest object. * @param name String. */ public PairListTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(PairListTest.class); return suite; } GenPolynomialRing fac; List> L; PolynomialList F; List> G; PairList pairlist; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 4; //4; //3; int kl = 5; int ll = 2; int el = 4; float q = 0.3f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test and compare random OrderedPairlist and CriticalPairList. */ public void testRandomPL() { pairlist = new OrderedPairlist(fac); //System.out.println("pairlist = " + pairlist); CriticalPairList cpl = new CriticalPairList(fac); //System.out.println("cpl = " + cpl); L = new ArrayList>(); for (int i = 0; i < 7; i++) { a = fac.random(kl, ll, el, q); if (a.isZERO()) { continue; } pairlist.put(a); cpl.put(a); } //System.out.println("pairlist = " + pairlist); //System.out.println("cpl = " + cpl); while (pairlist.hasNext() && cpl.hasNext()) { Pair pair = pairlist.removeNext(); //System.out.println("pair = " + pair); CriticalPair cpair = cpl.getNext(); //System.out.println("cpair = " + cpair); if (cpair != null) { cpl.update(cpair, fac.getZERO()); } else { cpl.update(); } if (pair != null && cpair != null) { boolean t = (pair.i == cpair.i) && (pair.j == cpair.j); assertTrue("pair == cpair ", t); } } //System.out.println("pairlist = " + pairlist); //System.out.println("cpl = " + cpl); boolean t = pairlist.hasNext() || cpl.hasNext(); assertFalse("#pairlist == #cpl ", t); } /** * Test and compare random OrderedPairlist and OrderedSyzPairlist. */ public void testRandomSyzPL() { pairlist = new OrderedPairlist(fac); //System.out.println("pairlist = " + pairlist); OrderedSyzPairlist spl = new OrderedSyzPairlist(fac); //System.out.println("spl = " + spl); L = new ArrayList>(); for (int i = 0; i < 7; i++) { a = fac.random(kl, ll, el, q); if (a.isZERO()) { continue; } pairlist.put(a); spl.put(a); } //System.out.println("pairlist = " + pairlist); //System.out.println("spl = " + spl); while (pairlist.hasNext() && spl.hasNext()) { Pair pair = pairlist.removeNext(); //System.out.println("pair = " + pair); Pair spair = spl.removeNext(); //System.out.println("spair = " + spair); if (pair != null && spair != null) { @SuppressWarnings("unused") boolean t = (pair.i == spair.i) && (pair.j == spair.j); //not always true: assertTrue("pair == spair " + pair + ", " + spair, t); } } //System.out.println("pairlist = " + pairlist); //System.out.println("spl = " + spl); boolean t = pairlist.hasNext() && spl.hasNext(); assertFalse("#pairlist == #spl ", t); } } java-algebra-system-2.7.200/trc/edu/jas/gb/ReductionTest.java000066400000000000000000000565251445075545500237240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.vector.BasicLinAlg; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Reduction / normalform tests with JUnit. * @author Heinz Kredel */ public class ReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ReductionTest object. * @param name String */ public ReductionTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(ReductionTest.class); return suite; } //private final static int bitlen = 100; GenPolynomialRing fac; GenPolynomial a, b, c, d, e; List> L; PolynomialList F, G; ReductionSeq red; Reduction redpar; int rl = 4; int kl = 10; int ll = 11; int el = 5; float q = 0.6f; @Override protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new BigRational(0), rl); red = new ReductionSeq(); redpar = new ReductionPar(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; red = null; redpar = null; } /** * Test constants and empty list reduction. */ public void testRatReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = red.normalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test parallel reduction with constants and empty list reduction. */ public void testRatReductionPar0() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = redpar.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = redpar.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = redpar.normalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = redpar.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = redpar.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = redpar.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = redpar.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test rational coefficient reduction. */ public void testRatReduction() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = red.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = red.normalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); e = red.SPolynomial(a, b); //System.out.println("e = " + e); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); ExpVector ee = e.leadingExpVector(); assertTrue("lcm(lt(a),lt(b)) > lt(e) " + ce + " > " + ee, fac.tord.getAscendComparator().compare(ce, ee) > 0); // findbugs L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", red.isTopReducible(L, a)); assertTrue("isRed( a )", red.isReducible(L, a)); b = fac.random(kl, ll, el, q); L.add(b); assertTrue("isTopRed( b )", red.isTopReducible(L, b)); assertTrue("isRed( b )", red.isReducible(L, b)); c = fac.random(kl, ll, el, q); e = red.normalform(L, c); assertTrue("isNF( e )", red.isNormalform(L, e)); } /** * Test rational coefficient parallel reduction. */ public void testRatReductionPar() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = redpar.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = redpar.normalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", redpar.isTopReducible(L, a)); assertTrue("isRed( a )", redpar.isReducible(L, a)); b = fac.random(kl, ll, el, q); L.add(b); assertTrue("isTopRed( b )", redpar.isTopReducible(L, b)); assertTrue("isRed( b )", redpar.isReducible(L, b)); c = fac.random(kl, ll, el, q); e = redpar.normalform(L, c); assertTrue("isNF( e )", redpar.isNormalform(L, e)); } /** * Test complex coefficient reduction. */ public void testComplexReduction() { GenPolynomialRing fac = new GenPolynomialRing(new BigComplex(0), rl); Reduction cred = new ReductionSeq(); GenPolynomial a = fac.random(kl, ll, el, q); GenPolynomial b = fac.random(kl, ll, el, q); GenPolynomial c; assertTrue("not isZERO( a )", !a.isZERO()); List> L = new ArrayList>(); L.add(a); GenPolynomial e = cred.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = cred.normalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", cred.isTopReducible(L, a)); assertTrue("isRed( a )", cred.isReducible(L, a)); b = fac.random(kl, ll, el, q); L.add(b); assertTrue("isTopRed( b )", cred.isTopReducible(L, b)); assertTrue("isRed( b )", cred.isReducible(L, b)); c = fac.random(kl, ll, el, q); e = cred.normalform(L, c); assertTrue("isNF( e )", cred.isNormalform(L, e)); } /** * Test rational coefficient reduction with recording. */ public void testRatReductionRecording() { BasicLinAlg> blas = new BasicLinAlg>(); List> row = null; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); row = blas.genVector(L.size(), null); e = red.normalform(row, L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); assertTrue("is Reduction ", red.isReductionNF(row, L, a, e)); L.add(b); row = blas.genVector(L.size(), null); e = red.normalform(row, L, b); assertTrue("is Reduction ", red.isReductionNF(row, L, b, e)); L.add(c); row = blas.genVector(L.size(), null); e = red.normalform(row, L, c); assertTrue("is Reduction ", red.isReductionNF(row, L, c, e)); L.add(d); row = blas.genVector(L.size(), null); e = red.normalform(row, L, d); assertTrue("is Reduction ", red.isReductionNF(row, L, d, e)); L = new ArrayList>(); L.add(a); L.add(b); //System.out.println("a = " + a); //System.out.println("b = " + b); row = blas.genVector(L.size(), null); e = red.SPolynomial(row, 0, a, 1, b); //System.out.println("e = " + e); //System.out.println("row = " + row); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); assertFalse("lcm(lt(a),lt(b)) != lt(e) ", ce.equals(e.leadingExpVector())); assertTrue("is Spol recording: " + e, red.isReductionNF(row, L, e.negate(), fac.getZERO())); } /** * Test integer coefficient e-reduction. */ public void testIntegerEReduction() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing(bi, rl); EReductionSeq ered = new EReductionSeq(); GenPolynomial a = fac.random(kl, ll, el, q); GenPolynomial b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); List> L = new ArrayList>(); L.add(a); GenPolynomial e = ered.normalform(L, a); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = ered.normalform(L, a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isZERO( e ) some times", e.isZERO()); GenPolynomial c = fac.getONE(); a = a.sum(c); e = ered.normalform(L, a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isONE( e ) some times", e.isONE()); L = new ArrayList>(); a = c.multiply(bi.fromInteger(4)); b = c.multiply(bi.fromInteger(5)); L.add(a); e = ered.normalform(L, b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isONE( e )", e.isONE()); a = fac.random(kl, ll, el, q); //.abs(); b = fac.random(kl, ll, el, q); //.abs(); c = ered.GPolynomial(a, b); e = ered.SPolynomial(a, b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("e = " + e); BigInteger ci = a.leadingBaseCoefficient().gcd(b.leadingBaseCoefficient()); assertEquals("gcd(lbc(a),lbc(b)) = lbc(c) ", ci, c.leadingBaseCoefficient()); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); assertEquals("lcm(lt(a),lt(b)) == lt(c) ", ce, c.leadingExpVector()); assertFalse("lcm(lt(a),lt(b)) != lt(e) ", ce.equals(e.leadingExpVector())); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", ered.isTopReducible(L, a)); assertTrue("isRed( a )", ered.isReducible(L, a)); b = fac.random(kl, ll, el, q); L.add(b); assertTrue("isTopRed( b )", ered.isTopReducible(L, b)); assertTrue("isRed( b )", ered.isReducible(L, b)); c = fac.random(kl, ll, el, q); e = ered.normalform(L, c); assertTrue("isNF( e )", ered.isNormalform(L, e)); } /** * Test integer coefficient e-reduction recording. */ public void testIntegerEReductionRecording() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing(bi, rl); GenPolynomial a, b, c, e; EReductionSeq ered = new EReductionSeq(); BasicLinAlg> blas = new BasicLinAlg>(); List> row = null; List> L = new ArrayList>(); a = fac.random(kl, ll, el, q).abs(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); row = blas.genVector(L.size(), null); e = ered.normalform(row, L, a); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); assertTrue("isZERO( e )", e.isZERO()); assertTrue("is Reduction ", ered.isReductionNF(row, L, a, e)); row = blas.genVector(L.size(), null); c = fac.getONE(); a = a.sum(c); e = ered.normalform(row, L, a); assertTrue("isONE( e ) some times", e.isONE()); assertTrue("is Reduction ", ered.isReductionNF(row, L, a, e)); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); row = blas.genVector(L.size(), null); L = new ArrayList>(); a = c.multiply(bi.fromInteger(4)); b = c.multiply(bi.fromInteger(5)); L.add(a); e = ered.normalform(row, L, b); assertTrue("isONE( e )", e.isONE()); assertTrue("is Reduction ", ered.isReductionNF(row, L, b, e)); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); a = fac.random(kl, ll, el, q).abs(); b = fac.random(kl, ll / 2, el / 2, q).abs(); c = fac.random(kl, ll * 2, el * 2, q * 1.0f).abs(); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(b); L.add(a); row = blas.genVector(L.size(), null); e = ered.normalform(row, L, c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); //assertTrue("isZERO( e )", e.isZERO() ); assertTrue("is Reduction ", ered.isReductionNF(row, L, c, e)); L = new ArrayList>(); L.add(a); L.add(b); //System.out.println("a = " + a); //System.out.println("b = " + b); row = blas.genVector(2, null); c = ered.GPolynomial(row, 0, a, 1, b); //System.out.println("c = " + c); //System.out.println("row = " + row); BigInteger ci = a.leadingBaseCoefficient().gcd(b.leadingBaseCoefficient()); assertEquals("gcd(lbc(a),lbc(b)) = lbc(c) ", ci, c.leadingBaseCoefficient()); assertTrue("is eGpol recording: " + c, ered.isReductionNF(row, L, c, fac.getZERO())); row = blas.genVector(2, null); e = ered.SPolynomial(row, 0, a, 1, b); //System.out.println("e = " + e); //System.out.println("row = " + row); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); assertEquals("lcm(lt(a),lt(b)) == lt(c) ", ce, c.leadingExpVector()); assertFalse("lcm(lt(a),lt(b)) != lt(e) ", ce.equals(e.leadingExpVector())); assertTrue("is eSpol recording: " + e, ered.isReductionNF(row, L, e, fac.getZERO())); } /** * Test integer coefficient d-reduction. */ public void testIntegerDReduction() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing(bi, rl); DReductionSeq dred = new DReductionSeq(); GenPolynomial a = fac.random(kl, ll, el, q); GenPolynomial b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); List> L = new ArrayList>(); L.add(a); GenPolynomial e = dred.normalform(L, a); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = dred.normalform(L, a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isZERO( e ) some times", e.isZERO()); GenPolynomial c = fac.getONE(); a = a.sum(c); e = dred.normalform(L, a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isONE( e ) some times", e.isONE()); L = new ArrayList>(); a = c.multiply(bi.fromInteger(5)); L.add(a); b = c.multiply(bi.fromInteger(4)); e = dred.normalform(L, b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("nf(b) = b ", e.equals(b)); a = fac.random(kl, ll, el, q); //.abs(); b = fac.random(kl, ll, el, q); //.abs(); c = dred.GPolynomial(a, b); e = dred.SPolynomial(a, b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("e = " + e); BigInteger ci = a.leadingBaseCoefficient().gcd(b.leadingBaseCoefficient()); assertEquals("gcd(lbc(a),lbc(b)) = lbc(c) ", ci, c.leadingBaseCoefficient()); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); assertEquals("lcm(lt(a),lt(b)) == lt(c) ", ce, c.leadingExpVector()); assertFalse("lcm(lt(a),lt(b)) != lt(e) ", ce.equals(e.leadingExpVector())); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", dred.isTopReducible(L, a)); assertTrue("isRed( a )", dred.isReducible(L, a)); b = fac.random(kl, ll, el, q); L.add(b); assertTrue("isTopRed( b )", dred.isTopReducible(L, b)); assertTrue("isRed( b )", dred.isReducible(L, b)); c = fac.random(kl, ll, el, q); e = dred.normalform(L, c); assertTrue("isNF( e )", dred.isNormalform(L, e)); } /** * Test integer coefficient d-reduction recording. */ public void testIntegerDReductionRecording() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing(bi, rl); GenPolynomial a, b, c, e; DReductionSeq dred = new DReductionSeq(); BasicLinAlg> blas = new BasicLinAlg>(); List> row = null; List> L = new ArrayList>(); a = fac.random(kl, ll, el, q).abs(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); row = blas.genVector(L.size(), null); e = dred.normalform(row, L, a); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); //System.out.println("dred.isReductionNF(row,L,a,e) = " + dred.isReductionNF(row,L,a,e)); assertTrue("isZERO( e )", e.isZERO()); assertTrue("is Reduction ", dred.isReductionNF(row, L, a, e)); row = blas.genVector(L.size(), null); c = fac.getONE(); a = a.sum(c); e = dred.normalform(row, L, a); assertTrue("isONE( e ) some times", e.isONE()); assertTrue("is Reduction ", dred.isReductionNF(row, L, a, e)); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); //System.out.println("dred.isReductionNF(row,L,a,e) = " + dred.isReductionNF(row,L,a,e)); row = blas.genVector(L.size(), null); L = new ArrayList>(); a = c.multiply(bi.fromInteger(4)); b = c.multiply(bi.fromInteger(5)); L.add(a); e = dred.normalform(row, L, b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); //System.out.println("dred.isReductionNF(row,L,b,e) = " + dred.isReductionNF(row,L,b,e)); assertEquals("e == b", e, b); assertTrue("is Reduction ", dred.isReductionNF(row, L, b, e)); a = fac.random(kl, ll, el, q).abs(); b = fac.random(kl, ll / 2, el / 2, q).abs(); //c = fac.random(kl, ll*2, el*2, q*1.0f ).abs(); c = a.multiply(b); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(b); L.add(a); row = blas.genVector(L.size(), null); e = dred.normalform(row, L, c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("e = " + e); //System.out.println("L = " + L); //System.out.println("row = " + row); //System.out.println("dred.isReductionNF(row,L,c,e) = " + dred.isReductionNF(row,L,c,e)); assertTrue("isZERO( e )", e.isZERO()); assertTrue("is Reduction ", dred.isReductionNF(row, L, c, e)); L = new ArrayList>(); L.add(a); L.add(b); //System.out.println("a = " + a); //System.out.println("b = " + b); row = blas.genVector(2, null); c = dred.GPolynomial(row, 0, a, 1, b); //System.out.println("c = " + c); //System.out.println("row = " + row); BigInteger ci = a.leadingBaseCoefficient().gcd(b.leadingBaseCoefficient()); assertEquals("gcd(lbc(a),lbc(b)) = lbc(c) ", ci, c.leadingBaseCoefficient()); assertTrue("is dGpol recording: " + c, dred.isReductionNF(row, L, c, fac.getZERO())); row = blas.genVector(2, null); e = dred.SPolynomial(row, 0, a, 1, b); //System.out.println("e = " + e); //System.out.println("row = " + row); ExpVector ce = a.leadingExpVector().lcm(b.leadingExpVector()); assertEquals("lcm(lt(a),lt(b)) == lt(c) ", ce, c.leadingExpVector()); assertFalse("lcm(lt(a),lt(b)) != lt(e) ", ce.equals(e.leadingExpVector())); assertTrue("is dSpol recording: " + e, dred.isReductionNF(row, L, e, fac.getZERO())); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SGBProxyTest.java000066400000000000000000000155571445075545500234450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; /** * SolvableGroebnerBase proxy of sequential and parallel tests with JUnit. * @author Heinz Kredel */ public class SGBProxyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SGBProxyTest object. * @param name String. */ public SGBProxyTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SGBProxyTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e; List> L; PolynomialList F, G; GenSolvablePolynomialRing ring; SolvableGroebnerBaseAbstract sbb; BigRational cfac; TermOrder tord; RelationTable table; int rl = 4; //4; //3; int kl = 10; int ll = 4; int el = 2; float q = 0.3f; //0.4f @Override protected void setUp() { cfac = new BigRational(9); tord = new TermOrder(); ring = new GenSolvablePolynomialRing(cfac, rl, tord); table = ring.table; a = b = c = d = e = null; int nt = ComputerThreads.N_CPUS - 1; SolvableGroebnerBaseAbstract bb1, bb2; bb1 = new SolvableGroebnerBaseSeq(); bb2 = new SolvableGroebnerBaseParallel(nt); sbb = new SGBProxy(bb1, bb2); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); } @Override protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; table = null; cfac = null; sbb.terminate(); sbb = null; } /** * Test proxy GBase. */ public void testProxyGBase() { L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test Weyl proxy GBase. */ public void testWeylProxyGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test proxy twosided GBase. */ public void testProxyTSGBase() { L = new ArrayList>(); L.add(a); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /** * Test Weyl proxy twosided GBase is always 1. */ public void testWeylProxyTSGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SolvableGroebnerBaseParTest.java000066400000000000000000000170421445075545500264500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.RelationGenerator; /** * SolvableGroebnerBase parallel tests with JUnit. * @author Heinz Kredel */ public class SolvableGroebnerBaseParTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a SolvableGroebnerBaseParTest object. * @param name String. */ public SolvableGroebnerBaseParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(SolvableGroebnerBaseParTest.class); return suite; } int port = 4711; String host = "localhost"; GenSolvablePolynomial a; GenSolvablePolynomial b; GenSolvablePolynomial c; GenSolvablePolynomial d; GenSolvablePolynomial e; List> L; PolynomialList F; PolynomialList G; GenSolvablePolynomialRing ring; SolvableGroebnerBase psbb; BigRational cfac; TermOrder tord; RelationTable table; int rl = 4; //4; //3; int kl = 10; int ll = 4; int el = 2; float q = 0.3f; //0.4f protected void setUp() { cfac = new BigRational(9); tord = new TermOrder(); ring = new GenSolvablePolynomialRing(cfac,rl,tord); table = ring.table; a = b = c = d = e = null; psbb = new SolvableGroebnerBaseParallel(); a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); } protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; table = null; cfac = null; ((SolvableGroebnerBaseParallel)psbb).terminate(); psbb = null; } /** * Test parallel GBase. */ public void testParallelGBase() { assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); //System.out.println("L = " + L.size() ); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d, e } )", psbb.isLeftGB(L) ); } /** * Test Weyl parallel GBase. * */ public void testWeylParallelGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); //System.out.println("L = " + L.size() ); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d, e } )", psbb.isLeftGB(L) ); } /** * Test parallel twosided GBase. * */ public void testParallelTSGBase() { assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", psbb.isTwosidedGB(L) ); } /** * Test Weyl parallel twosided GBase * is always 1. */ public void testWeylParallelTSGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", psbb.isTwosidedGB(L) ); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SolvableGroebnerBaseSeqPairParTest.java000066400000000000000000000171141445075545500277350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.RelationGenerator; /** * SolvableGroebnerBase parallel tests with JUnit. * @author Heinz Kredel */ public class SolvableGroebnerBaseSeqPairParTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a SolvableGroebnerBaseSeqPairParTest object. * @param name String. */ public SolvableGroebnerBaseSeqPairParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(SolvableGroebnerBaseSeqPairParTest.class); return suite; } int port = 4711; String host = "localhost"; GenSolvablePolynomial a; GenSolvablePolynomial b; GenSolvablePolynomial c; GenSolvablePolynomial d; GenSolvablePolynomial e; List> L; PolynomialList F; PolynomialList G; GenSolvablePolynomialRing ring; SolvableGroebnerBase psbb; BigRational cfac; TermOrder tord; RelationTable table; int rl = 4; //4; //3; int kl = 10; int ll = 4; int el = 2; float q = 0.3f; //0.4f protected void setUp() { cfac = new BigRational(9); tord = new TermOrder(); ring = new GenSolvablePolynomialRing(cfac,rl,tord); table = ring.table; a = b = c = d = e = null; psbb = new SolvableGroebnerBaseSeqPairParallel(); a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); } protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; table = null; cfac = null; ((SolvableGroebnerBaseSeqPairParallel)psbb).terminate(); psbb = null; } /** * Test parallel GBase. */ public void testParallelGBase() { assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); //System.out.println("L = " + L.size() ); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d, e } )", psbb.isLeftGB(L) ); } /** * Test Weyl parallel GBase. * */ public void testWeylParallelGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); //System.out.println("L = " + L.size() ); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d } )", psbb.isLeftGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.leftGB( L ); assertTrue("isLeftGB( { a, b, c, d, e } )", psbb.isLeftGB(L) ); } /** * Test parallel twosided GBase. * */ public void testParallelTSGBase() { assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.twosidedGB( L ); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", psbb.isTwosidedGB(L) ); } /** * Test Weyl parallel twosided GBase * is always 1. */ public void testWeylParallelTSGBase() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", psbb.isTwosidedGB(L) ); assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); L = psbb.twosidedGB( L ); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", psbb.isTwosidedGB(L) ); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SolvableGroebnerBaseSeqTest.java000066400000000000000000000311241445075545500264530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class SolvableGroebnerBaseSeqTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableGroebnerBaseSeqTest object. * @param name String. */ public SolvableGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableGroebnerBaseSeqTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e; List> L; PolynomialList F, G; GenSolvablePolynomialRing ring; SolvableGroebnerBase sbb; BigRational cfac; TermOrder tord; String[] vars; RelationTable table; int rl = 4; //4; //3; int kl = 10; int ll = 4; int el = 2; float q = 0.3f; //0.4f @Override protected void setUp() { cfac = new BigRational(9); tord = new TermOrder(); vars = new String[] { "x1", "x2", "x3", "x4" }; ring = new GenSolvablePolynomialRing(cfac, tord, vars); table = ring.table; a = b = c = d = e = null; sbb = new SolvableGroebnerBaseSeq(); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); } @Override protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; vars = null; table = null; cfac = null; sbb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test Weyl sequential GBase. */ public void testWeylSequentialGBase() { //int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test sequential twosided GBase. */ public void testSequentialTSGBase() { L = new ArrayList>(); L.add(a); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /** * Test Weyl sequential twosided GBase is always 1. */ public void testWeylSequentialTSGBase() { //int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /** * Test sequential right GBase. */ public void testSequentialRightGBase() { L = new ArrayList>(); L.add(a); L = sbb.rightGB(L); //System.out.println("L_r = " + L ); assertTrue("isRightGB( { a } )", sbb.isRightGB(L)); L.add(b); L = sbb.rightGB(L); //System.out.println("L_r = " + L ); assertTrue("isRightGB( { a, b } )", sbb.isRightGB(L)); L.add(c); L = sbb.rightGB(L); //System.out.println("L_r = " + L ); assertTrue("isRightGB( { a, b, c } )", sbb.isRightGB(L)); L.add(d); L = sbb.rightGB(L); //System.out.println("L_r = " + L ); assertTrue("isRightGB( { a, b, c, d } )", sbb.isRightGB(L)); L.add(e); L = sbb.rightGB(L); //System.out.println("L_r = " + L ); assertTrue("isRightGB( { a, b, c, d, e } )", sbb.isRightGB(L)); } /** * Test Weyl sequential right GBase. */ public void testWeylSequentialRightGBase() { //int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = sbb.rightGB(L); //System.out.println("L_rw = " + L ); assertTrue("isRightGB( { a } )", sbb.isRightGB(L)); L.add(b); L = sbb.rightGB(L); //System.out.println("L_rw = " + L ); assertTrue("isRightGB( { a, b } )", sbb.isRightGB(L)); L.add(c); L = sbb.rightGB(L); //System.out.println("L_rw = " + L ); assertTrue("isRightGB( { a, b, c } )", sbb.isRightGB(L)); L.add(d); L = sbb.rightGB(L); //System.out.println("L_rw = " + L ); assertTrue("isRightGB( { a, b, c, d } )", sbb.isRightGB(L)); L.add(e); L = sbb.rightGB(L); //System.out.println("L_rw = " + L ); assertTrue("isRightGB( { a, b, c, d, e } )", sbb.isRightGB(L)); } /** * Test sequential extended GBase. */ public void testSequentialExtendedGBase() { L = new ArrayList>(); SolvableExtendedGB exgb; L.add(a); //System.out.println("L = " + L ); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_l = " + exgb.G ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G)); assertTrue("isLeftRmat( { a } )", sbb.isLeftReductionMatrix(exgb)); L.add(b); //System.out.println("L = " + L ); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_l = " + exgb.G ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G)); assertTrue("isLeftRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb)); L.add(c); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_l = " + exgb.G ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G)); assertTrue("isLeftRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb)); L.add(d); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_l = " + exgb.G ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G)); assertTrue("isLeftRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb)); L.add(e); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_l = " + exgb.G ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G)); assertTrue("isLeftRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb)); } /** * Test Weyl sequential extended GBase. */ public void testWeylSequentialExtendedGBase() { //int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); SolvableExtendedGB exgb; L = new ArrayList>(); L.add(a); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_lw = " + exgb.G ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G)); assertTrue("isRmat( { a } )", sbb.isLeftReductionMatrix(exgb)); L.add(b); //System.out.println("L = " + L.size() ); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_lw = " + exgb.G ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G)); assertTrue("isRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb)); L.add(c); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_lw = " + exgb.G ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G)); assertTrue("isRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb)); L.add(d); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_lw = " + exgb.G ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G)); assertTrue("isRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb)); L.add(e); exgb = sbb.extLeftGB(L); //System.out.println("exgb.G_lw = " + exgb.G ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G)); assertTrue("isRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SolvableQuatGroebnerBaseSeqTest.java000066400000000000000000000341101445075545500273040ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable quaternion coefficients Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class SolvableQuatGroebnerBaseSeqTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableQuatGroebnerBaseSeqTest object. * @param name String. */ public SolvableQuatGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableQuatGroebnerBaseSeqTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e; List> L; PolynomialList F, G; GenSolvablePolynomialRing ring; SolvableGroebnerBaseAbstract sbb; BigQuaternionRing cfac; TermOrder tord; String[] vars; RelationTable table; int rl = 4; //4; //3; int kl = 1; int ll = 3; int el = 2; float q = 0.3f; //0.4f @Override protected void setUp() { cfac = new BigQuaternionRing(); tord = new TermOrder(); vars = new String[] { "x1", "x2", "x3", "x4" }; ring = new GenSolvablePolynomialRing(cfac, tord, vars); table = ring.table; a = b = c = d = e = null; sbb = new SolvableGroebnerBaseSeq(); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); //System.out.println("gens = " + ring.generators()); if (a.isConstant()) { a = (GenSolvablePolynomial) a.sum(ring.univariate(1)); //System.out.println("a+x3 = " + a + ", univ(1) = " + ring.univariate(1)); } } @Override protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; vars = null; table = null; cfac = null; sbb = null; } /** * Test sequential left GBase. */ public void testSequentialGBase() { //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); //System.out.println("L_l = " + L ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); L = sbb.leftGB(L); //System.out.println("L_l = " + L ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); //System.out.println("L_l = " + L ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); //System.out.println("L_l = " + L ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); //System.out.println("L_l = " + L ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test Weyl sequential left GBase. */ public void testWeylSequentialGBase() { //int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, tord, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); if (a.isConstant()) { a = (GenSolvablePolynomial) a.sum(ring.univariate(1)); //System.out.println("a+x3 = " + a); } //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); //System.out.println("L_lw = " + L ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); L = sbb.leftGB(L); //System.out.println("L_lw = " + L ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); //System.out.println("L_lw = " + L ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); //System.out.println("L_lw = " + L ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); //System.out.println("L_lw = " + L ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test sequential right GBase. */ public void testSequentialRightGBase() { //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); L.add(a); L = sbb.rightGB(L); //System.out.println("L_r = " + L); assertTrue("isRightGB( { a } )", sbb.isRightGB(L)); L.add(b); L = sbb.rightGB(L); //System.out.println("L_r = " + L); // while (!sbb.isRightGB(L)) { // L = sbb.rightGB( L ); // System.out.println("L_r = " + L ); // } assertTrue("isRightGB( { a, b } )", sbb.isRightGB(L)); L.add(c); L = sbb.rightGB(L); //System.out.println("L_r = " + L); assertTrue("isRightGB( { a, b, c } )", sbb.isRightGB(L)); L.add(d); L = sbb.rightGB(L); //System.out.println("L_r = " + L); assertTrue("isRightGB( { a, b, c, d } )", sbb.isRightGB(L)); L.add(e); L = sbb.rightGB(L); //System.out.println("L_r = " + L); assertTrue("isRightGB( { a, b, c, d, e } )", sbb.isRightGB(L)); } /** * Test Weyl sequential right GBase is always 1. */ public void testWeylSequentialRightGBase() { //int rloc = 4; //#vars ring = new GenSolvablePolynomialRing(cfac, tord, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); if (a.isConstant()) { a = (GenSolvablePolynomial) a.sum(ring.univariate(1)); //System.out.println("a+x3 = " + a); } //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = sbb.rightGB(L); //System.out.println("L_rw = " + L); assertTrue("isRightGB( { a } )", sbb.isRightGB(L)); L.add(b); L = sbb.rightGB(L); //System.out.println("L_rw = " + L); assertTrue("isRightGB( { a, b } )", sbb.isRightGB(L)); L.add(c); L = sbb.rightGB(L); //System.out.println("L_rw = " + L); assertTrue("isRightGB( { a, b, c } )", sbb.isRightGB(L)); L.add(d); L = sbb.rightGB(L); //System.out.println("L_rw = " + L); assertTrue("isRightGB( { a, b, c, d } )", sbb.isRightGB(L)); L.add(e); L = sbb.rightGB(L); //System.out.println("L_rw = " + L); assertTrue("isRightGB( { a, b, c, d, e } )", sbb.isRightGB(L)); } /** * Test sequential extended GBase. */ public void testSequentialExtendedGBase() { //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); SolvableExtendedGB exgb; L.add(a); //System.out.println("L_le = " + L); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G)); //assertTrue("isLeftRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L_le = " + L); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G)); //assertTrue("isLeftRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); //System.out.println("L_le = " + L); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G)); //assertTrue("isLeftRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); //System.out.println("L_le = " + L); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G)); //assertTrue("isLeftRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); //System.out.println("L_le = " + L); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G)); //assertTrue("isLeftRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } /** * Test Weyl sequential extended GBase. */ public void testWeylSequentialExtendedGBase() { //int rloc = 4; // = #vars ring = new GenSolvablePolynomialRing(cfac, tord, vars); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); if (a.isConstant()) { a = (GenSolvablePolynomial) a.sum(ring.univariate(1)); //System.out.println("a+x3 = " + a); } //System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); SolvableExtendedGB exgb; L = new ArrayList>(); L.add(a); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G)); //assertTrue("isRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L = " + L.size() ); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G)); //assertTrue("isRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G)); //assertTrue("isRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G)); //assertTrue("isRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); exgb = sbb.extLeftGB(L); //System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G)); //assertTrue("isRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } /* * Test sequential extended right GBase. extRightGB not yet implemented. */ public void noTestSequentialExtendedRightGBase() { System.out.println("a = " + a + ", b = " + b + ", c = " + c + ", d = " + d); L = new ArrayList>(); SolvableExtendedGB exgb; L.add(a); System.out.println("L_le = " + L); exgb = sbb.extRightGB(L); System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isRightGB( { a } )", sbb.isRightGB(exgb.G)); //assertTrue("isRightRmat( { a } )", sbb.isRightReductionMatrix(exgb) ); L.add(b); System.out.println("L_le = " + L); exgb = sbb.extRightGB(L); System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isRightGB( { a, b } )", sbb.isRightGB(exgb.G)); //assertTrue("isRightRmat( { a, b } )", sbb.isRightReductionMatrix(exgb) ); L.add(c); System.out.println("L_le = " + L); exgb = sbb.extRightGB(L); System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isRightGB( { a, b, c } )", sbb.isRightGB(exgb.G)); //assertTrue("isRightRmat( { a, b, c } )", sbb.isRightReductionMatrix(exgb) ); L.add(d); System.out.println("L_le = " + L); exgb = sbb.extRightGB(L); System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isRightGB( { a, b, c, d } )", sbb.isRightGB(exgb.G)); //assertTrue("isRightRmat( { a, b, c, d } )", sbb.isRightReductionMatrix(exgb) ); L.add(e); System.out.println("L_le = " + L); exgb = sbb.extRightGB(L); System.out.println("exgb.GB_l = " + exgb.G); assertTrue("isRightGB( { a, b, c, d, e } )", sbb.isRightGB(exgb.G)); //assertTrue("isRightRmat( { a, b, c, d, e } )", sbb.isRightReductionMatrix(exgb) ); } } java-algebra-system-2.7.200/trc/edu/jas/gb/SolvableReductionTest.java000066400000000000000000000201241445075545500253760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable Reduction tests with JUnit. * @author Heinz Kredel */ public class SolvableReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableReductionTest object. * @param name String. */ public SolvableReductionTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableReductionTest.class); return suite; } //private final static int bitlen = 100; GenSolvablePolynomialRing fac; RelationTable table; GenSolvablePolynomial a, b, c, d, e; List> L; PolynomialList F, G; SolvableReduction sred; SolvableReduction sredpar; int rl = 4; int kl = 10; int ll = 5; int el = 3; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; fac = new GenSolvablePolynomialRing(new BigRational(0), rl); sred = new SolvableReductionSeq(); sredpar = new SolvableReductionPar(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; sred = null; sredpar = null; } /** * Test constants and empty list reduction. */ public void testRatReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.leftNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); // e = Reduction.leftNormalform( L, a ); // assertTrue("isZERO( e )", e.isZERO() ); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test constants and empty list reduction. */ public void testWeylRatReduction0() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.leftNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test Rat reduction. */ public void testRatReduction() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Rat reduction parallel. */ public void testRatReductionPar() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = sredpar.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sredpar.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Weyl Rational reduction. */ public void testWeylRatReduction() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Weyl Rational reduction parallel. */ public void testWeylRatReductionPar() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); e = sredpar.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sredpar.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Rat reduction recording. */ public void testRatReductionRecording() { List> row = null; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); row = new ArrayList>(L.size()); for (int m = 0; m < L.size(); m++) { row.add(null); } e = sred.leftNormalform(row, L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, a, e)); L.add(b); row = new ArrayList>(L.size()); for (int m = 0; m < L.size(); m++) { row.add(null); } e = sred.leftNormalform(row, L, b); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, b, e)); L.add(c); row = new ArrayList>(L.size()); for (int m = 0; m < L.size(); m++) { row.add(null); } e = sred.leftNormalform(row, L, c); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, c, e)); L.add(d); row = new ArrayList>(L.size()); for (int m = 0; m < L.size(); m++) { row.add(null); } e = sred.leftNormalform(row, L, d); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, d, e)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/WordGroebnerBaseSeqTest.java000066400000000000000000000154271445075545500256270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.WordFactory; /** * Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class WordGroebnerBaseSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordGroebnerBaseSeqTest object. * @param name String. */ public WordGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordGroebnerBaseSeqTest.class); return suite; } GenWordPolynomialRing fac; WordFactory wfac; List> L; PolynomialList F; List> G; WordGroebnerBase bb; GenWordPolynomial a; GenWordPolynomial b; GenWordPolynomial c; GenWordPolynomial d; GenWordPolynomial e; int kl = 3; // 10 int ll = 7; int el = 4; // 4 @Override protected void setUp() { BigRational coeff = new BigRational(0); wfac = new WordFactory("a"); fac = new GenWordPolynomialRing(coeff, wfac); a = b = c = d = e = null; bb = new WordGroebnerBaseSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential univariate Word GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el); b = fac.random(kl, ll, el); c = fac.random(kl, ll, el); d = fac.random(kl, ll, el); e = d; //fac.random(kl, ll, el); while (a.isZERO()) { a = fac.random(kl, ll, el); } while (b.isZERO()) { b = fac.random(kl, ll, el); } while (c.isZERO()) { c = fac.random(kl, ll, el); } while (d.isZERO()) { d = fac.random(kl, ll, el); } L.add(a); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(a.multiply(b)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(a.multiply(c)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(a.multiply(d)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); L.clear(); L.add(a); L.add(a.multiply(b)); L.add(a.multiply(c)); L.add(a.multiply(d)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); } /** * Test example 1 word GBase. */ @SuppressWarnings("unchecked") public void testExample1GBase() { String exam = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); } /** * Test Trinks7 as non-commutative example word GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " // is needed + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); assertTrue("#G == 6", G.size() == 6); } /** * Test example 2 word GBase. */ @SuppressWarnings("unchecked") public void testExample2GBase() { String exam = "(x,y,z) L " + "( " + "( x y - z )" // will not be correct when converted to non-com + "( y z + 2 x + z )" + "( y z + x )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); } } java-algebra-system-2.7.200/trc/edu/jas/gb/WordReductionTest.java000066400000000000000000000233721445075545500245520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gb; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.Overlap; import edu.jas.poly.OverlapList; import edu.jas.poly.Word; import edu.jas.poly.WordFactory; /** * Word reduction tests with JUnit. * @author Heinz Kredel */ public class WordReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordReductionTest object. * @param name String */ public WordReductionTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordReductionTest.class); return suite; } GenWordPolynomialRing fac; WordFactory wfac; BigRational cfac; GenWordPolynomial a, b, c, d, e; List> L; WordReductionSeq red; int kl = 3; int ll = 7; int el = 5; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigRational(0); wfac = new WordFactory("abcdef"); fac = new GenWordPolynomialRing(cfac, wfac); red = new WordReductionSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; red = null; } /** * Test constants and empty list reduction. */ public void testRatReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el); c = fac.getONE(); d = fac.getZERO(); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = red.normalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test rational coefficient reduction. */ public void testRatReduction() { do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>(); L.add(a); e = red.normalform(L, a); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO()); L.add(b); e = red.normalform(L, a); //System.out.println("e = " + e); assertTrue("isZERO( e ) some times", e.isZERO()); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", red.isTopReducible(L, a)); assertTrue("isRed( a )", red.isReducible(L, a)); L.add(b); assertTrue("isTopRed( b )", red.isTopReducible(L, b)); assertTrue("isRed( b )", red.isReducible(L, b)); c = fac.random(kl, ll, el); //System.out.println("c = " + c); e = red.normalform(L, c); //System.out.println("e = " + e); assertTrue("isNF( e )", red.isNormalform(L, e)); Word u = new Word(wfac, "f"); Word v = new Word(wfac, "abc"); c = a.multiply(cfac.getONE(), u, v); //System.out.println("c = " + c); e = red.normalform(L, c); //System.out.println("e = " + e); assertTrue("isNF(" + e + "): " + c, red.isNormalform(L, e)); assertTrue("e == 0: " + e, e.isZERO()); } /** * Test rational coefficient reduction with recording. */ public void testRatReductionRecording() { List> lrow, rrow = null; do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); c = fac.random(kl, ll, el); d = fac.random(kl, ll, el); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); L = new ArrayList>(); L.add(a); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, a); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("isZERO( e )", e.isZERO()); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, a, e)); L.add(b); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, b); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, b, e)); L.add(c); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, c); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, c, e)); L.add(d); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } Word u = new Word(wfac, "f"); Word v = new Word(wfac, "abc"); d = a.multiply(cfac.random(3), u, v); //System.out.println("d = " + d); e = red.normalform(lrow, rrow, L, d); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, d, e)); wfac = new WordFactory("l d"); fac = new GenWordPolynomialRing(cfac, wfac); //a = fac.parse("3 l l + 2 d"); //b = fac.parse("1"); a = fac.parse("81 l l l l l l - 36 l l l + 4"); b = fac.parse("9 l l l - 2"); //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>(); L.add(b); //System.out.println("L = " + L); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, a); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, a, e)); } /** * Test rational S-polynomial. */ public void testRatSpolynomial() { do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); Word de = new Word(wfac, "a"); a = a.multiply(wfac.getONE(), de); b = b.multiply(de, wfac.getONE()); //System.out.println("a = " + a); //System.out.println("b = " + b); Word ae = a.leadingWord(); Word be = b.leadingWord(); //System.out.println("ae = " + ae); //System.out.println("be = " + be); List> S = red.SPolynomials(a, b); //System.out.println("S = " + S); OverlapList oll = ae.overlap(be); //System.out.println("oll = " + oll); for (GenWordPolynomial s : S) { //System.out.println("s = " + s); Word ee = s.leadingWord(); //System.out.println("ee = " + ee); boolean t = false; Word ce = fac.alphabet.getONE(); for (Overlap ol : oll.ols) { ce = ol.l1.multiply(ae).multiply(ol.r1); //System.out.println("ce = " + ce); if (fac.alphabet.getAscendComparator().compare(ce, ee) > 0) { t = true; break; } } assertTrue("ce > ee: " + ce + " > " + ee, t); // findbugs } } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/000077500000000000000000000000001445075545500207475ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/gbufd/CharSetTest.java000066400000000000000000000333521445075545500240110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Chararacteristic set tests with JUnit. * @author Heinz Kredel */ public class CharSetTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a CharSetTest object. * @param name String. */ public CharSetTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(CharSetTest.class); return suite; } CharacteristicSet cs; //TermOrder to = new TermOrder(TermOrder.INVLEX); TermOrder to = new TermOrder(TermOrder.IGRLEX); int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.29f; @Override protected void setUp() { cs = new CharacteristicSetWu(); } @Override protected void tearDown() { cs = null; } /** * Test random characteristic set simple. */ public void testCharacteristicSet() { CharacteristicSet css = new CharacteristicSetSimple(); GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); dfac = new GenPolynomialRing(br, rl, to); //System.out.println("dfac = " + dfac); GenPolynomial a, b, c, d, e; List> F, G, W; F = new ArrayList>(); a = dfac.random(kl, ll, el, q * 1.1f); b = dfac.random(kl, ll + 2, el, q); c = dfac.random(kl, ll, el, q); F.add(a); F.add(b); F.add(c); while (F.size() <= rl) { F.add(dfac.getZERO()); // make false cs } //F.add(dfac.fromInteger(17)); // test 1 //System.out.println("F = " + F); assertFalse("isCharacteristicSet: " + F, css.isCharacteristicSet(F)); G = css.characteristicSet(F); //System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, css.isCharacteristicSet(G)); e = PolyGBUtil. topPseudoRemainder(G, a); //System.out.println("a = " + a + ", deg_1 = " + a.degree(rl-1)); //System.out.println("e = " + e + ", deg_1 = " + e.degree(rl-1)); assertTrue("a rem G: " + e, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true e = PolyGBUtil. topPseudoRemainder(G, G.get(0)); //System.out.println("e = " + e); assertTrue("a rem G: " + e + ", G = " + G, e.isZERO()); e = css.characteristicSetReduction(G, a); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("a mod G: " + e, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true d = dfac.getONE(); if (!G.contains(d)) { d = dfac.random(kl, ll, el, q).sum(d); //System.out.println("d = " + d); e = PolyGBUtil. topPseudoRemainder(G, d); //System.out.println("e = " + e); assertFalse("a rem G: " + e, e.isZERO()); e = css.characteristicSetReduction(G, d); //System.out.println("e = " + e); assertFalse("a mod G: " + e, e.isZERO()); } // now with Wu W = cs.characteristicSet(F); //System.out.println("F = " + F); //System.out.println("W = " + W); assertTrue("isCharacteristicSet: " + W, cs.isCharacteristicSet(W)); e = PolyGBUtil. topPseudoRemainder(W, a); //System.out.println("a = " + a + ", deg = " + a.degree(rl-1)); //System.out.println("e = " + e + ", deg = " + e.degree(rl-1)); assertTrue("a rem W: " + e, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true e = PolyGBUtil. topPseudoRemainder(W, W.get(0)); //System.out.println("e = " + e); assertTrue("a rem G: " + e + ", W = " + W, e.isZERO()); e = cs.characteristicSetReduction(W, W.get(W.size() - 1)); //System.out.println("e = " + e); assertTrue("a mod W: " + e, e.isZERO()); e = cs.characteristicSetReduction(W, a); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("a mod W: " + e, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true } /** * Test random characteristic set Wu. */ public void testCharacteristicSetWu() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); dfac = new GenPolynomialRing(br, rl, to); //System.out.println("dfac = " + dfac); GenPolynomial a, b, c, d, e; List> F, G; F = new ArrayList>(); a = dfac.random(kl, ll, el, q * 1.1f); b = dfac.random(kl, ll + 2, el, q); c = dfac.random(kl, ll, el, q); F.add(a); F.add(b); F.add(c); while (F.size() <= rl) { F.add(dfac.getZERO()); // make false cs } //F.add(dfac.fromInteger(19)); // test 1 //System.out.println("F = " + F); assertFalse("isCharacteristicSet: " + F, cs.isCharacteristicSet(F)); G = cs.characteristicSet(F); //System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, cs.isCharacteristicSet(G)); e = PolyGBUtil. topPseudoRemainder(G, a); //System.out.println("e = " + e); assertTrue("a rem G: " + e, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true e = cs.characteristicSetReduction(G, G.get(G.size() - 1)); //System.out.println("e = " + e); assertTrue("a mod G: " + e, e.isZERO()); e = cs.characteristicSetReduction(G, G.get(0)); //System.out.println("e = " + e); assertTrue("a mod G: " + e, e.isZERO()); e = cs.characteristicSetReduction(G, a); //System.out.println("e = " + e); assertTrue("a mod G: " + e + ", G = " + G, e.isZERO() || e.degree(rl - 1) < a.degree(rl - 1)); // not always true d = dfac.getONE(); if (!G.contains(d)) { d = dfac.random(kl, ll, el, q).sum(d); //System.out.println("d = " + d); e = PolyGBUtil. topPseudoRemainder(G, d); //System.out.println("e = " + e); assertFalse("a rem G: " + e, e.isZERO()); e = cs.characteristicSetReduction(G, d); //System.out.println("e = " + e); assertFalse("a mod G: " + e, e.isZERO()); } } /** * Test characteristic set, example Circle of Apollonius, from CLO IVA, * 1992. */ public void testCharacteristicSetExample() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "u1", "u2", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomial h1, h2, h3, h4, h5, h6, h7, h8, g, e; List> F, G; F = new ArrayList>(); h1 = dfac.parse(" 2 x1 - u1 "); h2 = dfac.parse(" 2 x2 - u2 "); h3 = dfac.parse(" 2 x3 - u1 "); h4 = dfac.parse(" 2 x4 - u2 "); h5 = dfac.parse(" u2 x5 + u1 x6 - u1 u2 "); h6 = dfac.parse(" u1 x5 - u2 x6 "); h7 = dfac.parse(" x1^2 - x2^2 - 2 x1 x7 + 2 x2 x8 "); h8 = dfac.parse(" x1^2 - 2 x1 x7 - x3^2 + 2 x3 x7 - x4^2 + 2 x4 x8 "); F.add(h1); F.add(h2); F.add(h3); F.add(h4); F.add(h5); F.add(h6); F.add(h7); F.add(h8); //System.out.println("F = " + F); assertFalse("isCharacteristicSet: " + F, cs.isCharacteristicSet(F)); G = cs.characteristicSet(F); //System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, cs.isCharacteristicSet(G)); g = dfac.parse("( ( x5 - x7 )**2 + ( x6 - x8 )**2 - ( x1 - x7 )**2 - x8^2 )"); //g = dfac.parse("-2 x6 * x8 - 2 x5 * x7 + 2 x1 * x7 + x6^2 + x5^2 - x1^2"); //System.out.println("g = " + g); e = cs.characteristicSetReduction(G, g); //e = PolyGBUtil. topPseudoRemainder(G, g); //System.out.println("e = " + e); assertTrue("g mod G: " + e, e.isZERO()); // || true ?not always true //GroebnerBaseAbstract bb = GBFactory.getImplementation(br); //H = bb.GB(F); //System.out.println(" H = " + H); //Reduction red = bb.red; //f = red.normalform(H, g); //System.out.println("fg = " + f); //k = red.normalform(H, e); //System.out.println("fk' = " + k); //System.out.println("fk' == f: " + k.equals(f)); //System.out.println("fk' - f: " + k.subtract(f)); //K = red.normalform(H, G); //System.out.println("Kg = " + K); //L = red.normalform(H, F); //System.out.println("Lf = " + L); //assertEquals("Kg == Kf: " + L, K, L); } /** * Test characteristic set, example circum-center. */ public void ytestCharacteristicSetExampleCC() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "u1", "u2", "u3", "x1", "x2", "x3" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomial h1, h2, h3, g, e; List> F, G; F = new ArrayList>(); // wrong: h1 = dfac.parse(" 2 u1 x2 - u1^2 "); h2 = dfac.parse(" 2 u2 x2 + 2 u3 x1 - u2^2 - u3^2 "); h3 = dfac.parse(" 2 u3 x3 - 2 ( u2 - u1 ) x2 - u2^2 - u3^2 + u1^2 "); F.add(h1); F.add(h2); F.add(h3); System.out.println("F = " + F); assertFalse("isCharacteristicSet: " + F, cs.isCharacteristicSet(F)); G = cs.characteristicSet(F); System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, cs.isCharacteristicSet(G)); g = dfac.parse(" x3^2 - 2 x3 x1 + x1^2 "); //g = dfac.parse(" x3 - x1 "); System.out.println("g = " + g); e = cs.characteristicSetReduction(G, g); //e = PolyGBUtil. characteristicSetRemainder(G,g); System.out.println("e = " + e); assertTrue("g mod G: " + e, e.isZERO() || e.degree(rl - 1) < g.degree(rl - 1)); // not always true } /** * Test characteristic set, example secant from wang. */ public void testCharacteristicSetExampleSec() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "u1", "u2", "u3", "u4", "y1", "y2", "y3" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomial h1, h2, h3, g, e; List> F, G; F = new ArrayList>(); h1 = dfac.parse(" 2 u3 y1 - u2^2 + u1^2 - u3^2 "); h2 = dfac.parse(" - y2^2 + 2 y1 y2 + u1^2 - u4^2 "); h3 = dfac.parse(" - y2 y3 + u3 y3 + y2 u2 - u4 u3 "); F.add(h1); F.add(h2); F.add(h3); //System.out.println("F = " + F); assertTrue("isCharacteristicSet: " + F, cs.isCharacteristicSet(F)); // already CS G = cs.characteristicSet(F); //System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, cs.isCharacteristicSet(G)); g = dfac.parse("( (y3 + u1)^2 (y3 - u1)^2 - ( (y3 - u2)^2 + u3^2 ) ( (y3 - u4)^2 + y2^2 ) )"); //g = dfac.parse(" x3 - x1 "); //System.out.println("g = " + g); e = cs.characteristicSetReduction(G, g); //e = PolyGBUtil. characteristicSetRemainder(G,g); //System.out.println("e = " + e); assertTrue("g mod G: " + e, e.isZERO()); } /** * Test characteristic set, example ??. */ public void testCharacteristicSetExampleT() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomial h1, h2, h3; List> F, G; F = new ArrayList>(); h1 = dfac.parse(" x^2 + y + z - 1 "); h2 = dfac.parse(" x + y^2 + z - 1 "); h3 = dfac.parse(" x + y + z^2 - 1 "); F.add(h1); F.add(h2); F.add(h3); //System.out.println("F = " + F); assertFalse("isCharacteristicSet: " + F, cs.isCharacteristicSet(F)); G = cs.characteristicSet(F); //System.out.println("G = " + G); assertTrue("isCharacteristicSet: " + G, cs.isCharacteristicSet(G)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GBFactoryTest.java000066400000000000000000000207421445075545500242770ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.gb.GBProxy; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; // import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base factory tests with JUnit. * @author Heinz Kredel */ public class GBFactoryTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GBFactoryTest object. * @param name String. */ public GBFactoryTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GBFactoryTest.class); return suite; } //private final static int bitlen = 100; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; } /** * Test get BigInteger implementation. */ public void testBigInteger() { BigInteger bi = new BigInteger(); GroebnerBase bba; bba = GBFactory.getImplementation(bi); //System.out.println("bba = " + bba); assertTrue("bba integer " + bba, bba instanceof GroebnerBasePseudoSeq); } /** * Test get ModInteger implementation. */ public void testModInteger() { ModIntegerRing mi = new ModIntegerRing(19, true); GroebnerBase bba; bba = GBFactory.getImplementation(mi); //System.out.println("bba = " + bba); assertTrue("bba modular field " + bba, bba instanceof GroebnerBaseSeq); mi = new ModIntegerRing(30); bba = GBFactory.getImplementation(mi); //System.out.println("bba = " + bba); assertTrue("bba modular ring " + bba, bba instanceof GroebnerBasePseudoSeq); } /** * Test get BigRational implementation. */ public void testBigRational() { BigRational b = new BigRational(); GroebnerBase bba; bba = GBFactory.getImplementation(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof GroebnerBaseSeq); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); GroebnerBase bba; bba = GBFactory. getImplementation(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof GroebnerBaseSeq); } /** * Test get AlgebraicNumber<BigRational> implementation. */ public void testAlgebraicNumberBigRational() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); GroebnerBase> bba; bba = GBFactory.> getImplementation(afac); //System.out.println("bba1 = " + bba); assertTrue("bba algebraic ring " + bba, bba instanceof GroebnerBasePseudoSeq); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); bba = GBFactory.> getImplementation(afac); //System.out.println("bba1 = " + bba); assertTrue("bba algebraic field " + bba, bba instanceof GroebnerBaseSeq); } /** * Test get AlgebraicNumber<ModInteger> implementation. */ public void testAlgebraicNumberModInteger() { ModIntegerRing b = new ModIntegerRing(19, true); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); AlgebraicNumber a = afac.getONE(); assertTrue("a == 1 " + a, a.isONE()); GroebnerBase> bba; bba = GBFactory.> getImplementation(afac); //System.out.println("bba2 = " + bba); assertTrue("bba algebraic ring " + bba, bba instanceof GroebnerBasePseudoSeq); } /** * Test get GenPolynomial implementation. */ @SuppressWarnings("unchecked") public void testGenPolynomial() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, rl, to); RingFactory> rf = fac; GroebnerBase> bba; bba = GBFactory.getImplementation(fac); //System.out.println("bba = " + bba); assertTrue("bba recursive polynomial " + bba, bba instanceof GroebnerBasePseudoRecSeq); GroebnerBase bb; bb = GBFactory. getImplementation((RingFactory) rf); //System.out.println("bb = " + bb); assertTrue("bba recursive polynomial " + bb, bb instanceof GroebnerBasePseudoRecSeq); } /** * Test get Product implementation. */ @SuppressWarnings({ "unchecked" }) public void testProduct() { ModIntegerRing mi = new ModIntegerRing(19, true); ProductRing fac; fac = new ProductRing(mi, 3); RingFactory> rf = fac; GroebnerBase> bba; bba = GBFactory.getImplementation(fac); //System.out.println("bba = " + bba); assertTrue("bba product " + bba, bba instanceof RGroebnerBaseSeq); mi = new ModIntegerRing(30); fac = new ProductRing(mi, 3); rf = fac; GroebnerBase> bb; bb = GBFactory.> getImplementation((RingFactory) rf); //System.out.println("bb = " + bb); assertTrue("bba product " + bb, bb instanceof RGroebnerBasePseudoSeq); } /** * Test get proxy implementation. */ public void testProxy() { BigRational b = new BigRational(); GroebnerBaseAbstract bba; bba = GBFactory.getProxy(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof GBProxy); bba.terminate(); ModIntegerRing m = new ModIntegerRing(2 * 3); GroebnerBaseAbstract bbm; bbm = GBFactory.getProxy(m); //System.out.println("bba = " + bba); assertTrue("bbm ! field " + bbm, !(bbm instanceof GBProxy)); bbm.terminate(); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBaseFGLMTest.java000066400000000000000000000267611445075545500254720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gb.OrderedSyzPairlist; import edu.jas.gb.ReductionSeq; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.Complex; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base via FGLM tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseFGLMTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseFGLMTest object. * @param name String. */ public GroebnerBaseFGLMTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseFGLMTest.class); return suite; } GenPolynomialRing fac; PolynomialList F; List> L, G, Gs; GroebnerBase bb; GenPolynomial a, b, c, d, e; int rl = 4; //4; //3; int kl = 7; // 10 int ll = 7; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl, new TermOrder(TermOrder.INVLEX)); a = b = c = d = e = null; bb = new GroebnerBaseFGLM(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test example GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testExamGBase() { GroebnerBase bbs = new GroebnerBaseSeq(new ReductionSeq(), new OrderedSyzPairlist()); String exam = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList P = new PolynomialList(F.ring, G); //System.out.println("G = " + P); assertTrue("isGB( GB(P) )", bb.isGB(G)); assertEquals("#GB(P) == 3", 3, G.size()); Gs = bbs.GB(F.list); PolynomialList P2 = new PolynomialList(F.ring, Gs); assertTrue("isGB( GB(P2) )", bb.isGB(Gs)); assertEquals("#GB(P2) == 3", 3, Gs.size()); assertEquals("GB == FGLM", P, P2); } /** * Test Trinks7 GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks7GBase() { GroebnerBase bbs = new GroebnerBaseSeq(new ReductionSeq(), new OrderedSyzPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); Gs = bbs.GB(F.list); PolynomialList trinks2 = new PolynomialList(F.ring, Gs); assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gs)); assertEquals("#GB(Trinks7) == 6", 6, Gs.size()); assertEquals("GB == FGLM", trinks, trinks2); } /** * Test Trinks6 GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks6GBase() { GroebnerBase bbs = new GroebnerBaseSeq(new ReductionSeq(), new OrderedSyzPairlist()); String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList trinks = new PolynomialList(F.ring, G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); Gs = bbs.GB(F.list); PolynomialList trinks2 = new PolynomialList(F.ring, Gs); assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gs)); assertEquals("#GB(Trinks7) == 6", 6, Gs.size()); assertEquals("GB == FGLM", trinks, trinks2); } /** * Test Trinks7 GBase over Q(sqrt(2)). */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks7GBaseSqrt() { GroebnerBase> bbs = new GroebnerBaseSeq>( new ReductionSeq>(), new OrderedSyzPairlist>()); GroebnerBase> bb = new GroebnerBaseFGLM>(); String exam = "AN[ (w2) (w2^2 - 2) ] (B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList> F = null; List>> G, Gs; try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); GenPolynomialRing> pfac = F.ring; AlgebraicNumberRing afac = (AlgebraicNumberRing) pfac.coFac; //System.out.println("afac = " + afac); afac = new AlgebraicNumberRing(afac.modul, true); //System.out.println("afac = " + afac); pfac = new GenPolynomialRing>(afac, pfac); List>> Fp = new ArrayList>>( F.list.size()); for (GenPolynomial> p : F.list) { GenPolynomial> pp = pfac.copy(p); Fp.add(pp); } F = new PolynomialList>(pfac, Fp); G = bb.GB(F.list); PolynomialList> trinks = new PolynomialList>( F.ring, G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); Gs = bbs.GB(F.list); PolynomialList> trinks2 = new PolynomialList>( F.ring, Gs); //System.out.println("Gs = " + trinks2); assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gs)); assertEquals("#GB(Trinks7) == 6", 6, Gs.size()); assertEquals("GB == FGLM", trinks, trinks2); } /** * Test Trinks7 GBase over Q(i). */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinks7GBaseCompl() { GroebnerBase> bbs = new GroebnerBaseSeq>( new ReductionSeq>(), new OrderedSyzPairlist>()); GroebnerBase> bb = new GroebnerBaseFGLM>(); String exam = "Complex (B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList> F = null; List>> G, Gs; try { F = (PolynomialList>) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList> trinks = new PolynomialList>(F.ring, G); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); Gs = bbs.GB(F.list); PolynomialList> trinks2 = new PolynomialList>(F.ring, Gs); //System.out.println("Gs = " + trinks2); assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gs)); assertEquals("#GB(Trinks7) == 6", 6, Gs.size()); assertEquals("GB == FGLM", trinks, trinks2); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBasePartTest.java000066400000000000000000000313751445075545500256500ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrderOptimization; import edu.jas.util.KsubSet; /** * Partial Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class GroebnerBasePartTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBasePartTest object. * @param name String. */ public GroebnerBasePartTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBasePartTest.class); return suite; } GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBase bb; GroebnerBasePartial bbp; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBaseSeq(); bbp = new GroebnerBasePartial(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; ComputerThreads.terminate(); } /** * Test partial recursive Trinks7 GBase. * */ @SuppressWarnings("unchecked") public void testTrinks7GBasePartRec() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); //PolynomialList Fo = TermOrderOptimization.optimizeTermOrder(F); //System.out.println("\nFo = " + Fo); PolynomialList> rtrinks = bbp.partialGBrec(F.list, new String[] { "P", "Z", "T", "W" }); assertTrue("isGB( GB(Trinks7) )", bbp.isGBrec(rtrinks.list)); //System.out.println("\nTrinksR = " + rtrinks); // not meaning-full PolynomialList trinks = bbp.partialGB(F.list, new String[] { "P", "Z", "T", "W" }); //System.out.println("\ntrinks = " + trinks); assertTrue("isGB( GB(Trinks7) )", bbp.isGB(trinks.list)); } /** * Test partial Trinks7 GBase. * */ @SuppressWarnings("unchecked") public void testTrinks7GBasePart() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); //PolynomialList Fo = TermOrderOptimization.optimizeTermOrder(F); //System.out.println("\nFo = " + Fo); PolynomialList trinks = bbp.partialGB(F.list, new String[] { "B", "S", "P", "Z", "T", "W" }); //PolynomialList trinks = bbp.partialGB(F.list, new String[] { "T", "Z", "P", "W", "B", "S" }); assertTrue("isGB( GB(Trinks7) )", bbp.isGB(trinks.list)); //System.out.println("\nG = " + trinks); try { @SuppressWarnings("unused") PolynomialList> tr = bbp.partialGBrec(F.list, new String[] { "B", "S", "P", "Z", "T", "W" }); fail("must throw exception"); } catch (IllegalArgumentException e) { //pass } } /** * Test partial permutation. * */ public void testPartialPermutation() { String[] vars = new String[] { "B", "S", "T", "Z", "P", "W" }; String[] pvars = new String[] { "P", "Z", "T", "W" }; String[] rvars = new String[] { "S", "B" }; List perm1 = GroebnerBasePartial.partialPermutation(vars, pvars); //System.out.println("perm1 = " + perm1); List perm2 = GroebnerBasePartial.partialPermutation(vars, pvars, null); //System.out.println("perm2 = " + perm2); assertEquals("perm1 == perm2 ", perm1, perm2); List perm3 = GroebnerBasePartial.partialPermutation(vars, pvars, rvars); //System.out.println("perm3 = " + perm3); assertFalse("perm1 != perm3 ", perm1.equals(perm3)); } /** * Test elimination partial permutation. * */ public void xtestElimPartialPermutation() { String[] vars = new String[] { "B", "S", "T", "Z", "P", "W" }; String[] evars = new String[] { "P", "Z" }; String[] pvars = new String[] { "T", "W" }; String[] rvars = new String[] { "B", "S" }; List perm1 = GroebnerBasePartial.partialPermutation(vars, evars, pvars, rvars); System.out.println("perm1 = " + perm1); List perm2 = GroebnerBasePartial.partialPermutation(vars, evars, pvars, null); System.out.println("perm2 = " + perm2); assertEquals("perm1 == perm2 ", perm1, perm2); rvars = new String[] { "S", "B" }; List perm3 = GroebnerBasePartial.partialPermutation(vars, evars, pvars, rvars); System.out.println("perm3 = " + perm3); assertFalse("perm1 != perm3 ", perm1.equals(perm3)); } /** * Test elim partial Trinks7 GBase. * */ @SuppressWarnings("unchecked") public void testTrinks7GBaseElimPart() { String exam = "(B,S,T,Z,P,W) G " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); String[] evars = new String[] { "P", "Z" }; String[] pvars = new String[] { "B", "S", "T", "W" }; //System.out.println("evars = " + Arrays.toString(evars)); //System.out.println("pvars = " + Arrays.toString(pvars)); PolynomialList trinks = bbp.elimPartialGB(F.list, evars, pvars); assertTrue("isGB( GB(Trinks7) )", bbp.isGB(trinks.list)); //System.out.println("\nG = " + trinks); } /** * Test partial GBase. * */ @SuppressWarnings("unchecked") public void testGBasePart() { String exam = "(a,b,c,d,e,f) G " + "( " + "( a ), " + "( b^2 ), " + "( c^3 ), " + "( d^4 ), " + "( e^5 ), " + "( f^6 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); // String[] evars = new String[] { "c", "d", "e", "f", "a", "b"}; String[] evars = new String[] { "a", "b" }; //System.out.println("evars = " + Arrays.toString(evars)); PolynomialList G = bbp.partialGB(F.list, evars); assertTrue("isGB( GB(G) )", bbp.isGB(G.list)); //System.out.println("evars = " + Arrays.toString(evars)); //System.out.println("G = " + G); } /** * Test permutation generation. * */ @SuppressWarnings("unchecked") public void testPermGen() { String[] vars = new String[] { "a", "b", "c", "d", "e", "f" }; //System.out.println("vars = " + Arrays.toString(vars)); List sv = new ArrayList(vars.length); for (int i = 0; i < vars.length; i++) { sv.add(vars[i]); } //System.out.println("sv = " + sv); String exam = "(a,b,c,d,e,f) G " + "( " + "( a ), " + "( b^2 ), " + "( c^3 ), " + "( d^4 ), " + "( e^5 ), " + "( f^6 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); for (int i = 0; i <= vars.length; i++) { KsubSet ps = new KsubSet(sv, i); //System.out.println("========================== ps : " + i); for (List ev : ps) { //System.out.println("ev = " + ev); String[] evars = new String[ev.size()]; for (int j = 0; j < ev.size(); j++) { evars[j] = ev.get(j); } //System.out.println("evars = " + Arrays.toString(evars)); String[] rvars = GroebnerBasePartial.remainingVars(vars, evars); //System.out.println("rvars = " + Arrays.toString(rvars)); List perm1 = GroebnerBasePartial.partialPermutation(vars, evars); //System.out.println("perm1 = " + perm1); List perm2 = GroebnerBasePartial.getPermutation(vars, rvars); //System.out.println("perm2 = " + perm2); assertEquals("perm1 == perm2 " + Arrays.toString(evars), perm1, perm2); GenPolynomialRing r = new GenPolynomialRing(fac.coFac, vars); GenPolynomialRing pr1 = TermOrderOptimization . permutation(perm1, r); //System.out.println("pr1 = " + pr1); GenPolynomialRing pr2 = TermOrderOptimization . permutation(perm2, r); //System.out.println("pr2 = " + pr2); assertEquals("pr1 == pr2 ", pr1, pr2); List> pF1 = TermOrderOptimization. permutation(perm1, pr1, F.list); //System.out.println("pF1 = " + pF1); List> pF2 = TermOrderOptimization. permutation(perm2, pr2, F.list); //System.out.println("pF2 = " + pF2); assertEquals("pF1 == pF2 ", pF1, pF2); } } } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBasePseudoParTest.java000066400000000000000000000117321445075545500266370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base pseudo reduction parallel tests with JUnit. * @author Heinz Kredel */ public class GroebnerBasePseudoParTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBasePseudoParTest object. * @param name String. */ public GroebnerBasePseudoParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBasePseudoParTest.class); return suite; } GenPolynomialRing fac; List> L; PolynomialList F; List> G; GroebnerBaseAbstract bb; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f int threads = 2; @Override protected void setUp() { BigInteger coeff = new BigInteger(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBasePseudoParallel(threads, coeff); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb.terminate(); bb = null; } /** * Test parallel GBase. * */ public void testParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); //if ( a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO() ) { // return; //} L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks6/7 GBase. * */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " //+ "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long s, t; t = System.currentTimeMillis(); G = bb.GB(F.list); t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); PolynomialList Gpl = new PolynomialList(F.ring, G); //System.out.println("G = " + Gpl); assertTrue("nonsense ", t >= 0L); GenPolynomialRing ifac = F.ring; List> Gi; GroebnerBasePseudoSeq bbr = new GroebnerBasePseudoSeq(ifac.coFac); s = System.currentTimeMillis(); Gi = bbr.GB(F.list); s = System.currentTimeMillis() - s; PolynomialList Gipl = new PolynomialList(F.ring, Gi); //System.out.println("G = " + Gpl); //System.out.println("Gi = " + Gipl); assertEquals("seqGB == parGB", Gpl, Gipl); //System.out.println("time: seqGB = " + s + ", parGB = " + t); assertTrue("nonsense ", s >= 0L); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBasePseudoRecParTest.java000066400000000000000000000224531445075545500272730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseParallel; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.OrderedPolynomialList; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Groebner base recursive pseudo reduction sequential tests with JUnit. * @author Heinz Kredel */ public class GroebnerBasePseudoRecParTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GroebnerBasePseudoRecParTest object. * @param name String. */ public GroebnerBasePseudoRecParTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBasePseudoRecParTest.class); return suite; } GenPolynomialRing> fac; List>> L; PolynomialList> F; List>> G; GroebnerBaseAbstract> bb; GroebnerBaseAbstract> bbr; GenPolynomial> a, b, c, d, e; int rl = 2; //4; //3; int kl = 2; int ll = 5; int el = 4; float q = 0.3f; //0.4f int threads = 3; @Override protected void setUp() { BigInteger coeff = new BigInteger(9); GenPolynomialRing cofac = new GenPolynomialRing(coeff, 1); fac = new GenPolynomialRing>(cofac, rl); a = b = c = d = e = null; bb = new GroebnerBasePseudoRecParallel(threads, cofac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb.terminate(); bb = null; } /** * Test recursive parallel GBase. */ public void testRecParallelGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.getZERO(); //fac.random(kl, ll, el, q); e = c; //fac.random(kl, ll, el, q ); L.add(a); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); if (bb.commonZeroTest(L) < 0) { L.clear(); } L.add(c); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Hawes2 GBase. */ @SuppressWarnings("unchecked") public void testHawes2GBase() { String exam = "IntFunc(a, c, b) (y2, y1, z1, z2, x) G" + "(" + "( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 )," + "( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 )," + "( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } )," + "( 3 z1^2 + y1^2 + { b } )," + "( 3 z2^2 + y2^2 + { b } )" + ")"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList> Fr = null; try { Fr = parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } GenPolynomialRing cofac = (GenPolynomialRing) Fr.ring.coFac; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), cofac); fac = new GenPolynomialRing>(ifac, Fr.ring); L = PolyUfdUtil.integerFromRationalCoefficients(fac, Fr.list); //System.out.println("F = " + L); //System.out.println("Fr = " + Fr); long s, t, q, i; t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Hawes2) )", bb.isGB(G)); assertEquals("#GB(Hawes2) == 8", 8, G.size()); G = OrderedPolynomialList.> sort(G); PolynomialList> Gp = new PolynomialList>(fac, G); //System.out.println("G = " + Gp); assertTrue("nonsense ", !Gp.getList().isEmpty()); GenPolynomialRing rfac = (GenPolynomialRing) Fr.ring.coFac; List>> Gr, Kr, Lr = Fr.list; bbr = new GroebnerBasePseudoRecParallel(threads, rfac); s = System.currentTimeMillis(); Gr = bbr.GB(Lr); s = System.currentTimeMillis() - s; Gr = PolyUtil. monicRec(Gr); assertTrue("isGB( GB(Hawes2) )", bbr.isGB(Gr)); assertEquals("#GB(Hawes2) == 8", 8, Gr.size()); Gr = OrderedPolynomialList.> sort(Gr); PolynomialList> Grp = new PolynomialList>( Fr.ring, Gr); //System.out.println("Gr = " + Grp) assertTrue("nonsense ", !Grp.getList().isEmpty());; bbr.terminate(); Kr = PolyUfdUtil. fromIntegerCoefficients(Fr.ring, G); Kr = PolyUtil. monicRec(Kr); assertEquals("ratGB == intGB", Kr, Gr); assertTrue("nonsense ", s >= 0L); QuotientRing qr = new QuotientRing(rfac); GenPolynomialRing> rring = new GenPolynomialRing>(qr, fac); List>> Gq, Lq, Kq; Lq = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Lr); Lq = PolyUtil.> monic(Lq); GroebnerBaseAbstract> bbq; bbq = new GroebnerBaseParallel>(threads); //qr); q = System.currentTimeMillis(); Gq = bbq.GB(Lq); q = System.currentTimeMillis() - q; assertTrue("isGB( GB(Hawes2) )", bbq.isGB(Gq)); assertEquals("#GB(Hawes2) == 8", 8, Gq.size()); Gq = OrderedPolynomialList.> sort(Gq); PolynomialList> Gpq = new PolynomialList>(rring, Gq); //System.out.println("Gq = " + Gpq); assertTrue("nonsense ", !Gpq.getList().isEmpty()); bbq.terminate(); Kq = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Gr); Kq = PolyUtil.> monic(Kq); assertEquals("ratGB == quotGB", Kq, Gq); assertTrue("nonsense ", q >= 0L); QuotientRing qi = new QuotientRing(ifac); GenPolynomialRing> iring = new GenPolynomialRing>(qi, fac); List>> Gqi, Lqi, Kqi; Lqi = PolyUfdUtil. quotientFromIntegralCoefficients(iring, L); Lqi = PolyUtil.> monic(Lqi); //System.out.println("Lqi = " + Lqi); GroebnerBaseAbstract> bbqi; bbqi = new GroebnerBaseParallel>(threads); //qr); i = System.currentTimeMillis(); Gqi = bbqi.GB(Lqi); i = System.currentTimeMillis() - i; assertTrue("isGB( GB(Hawes2) )", bbqi.isGB(Gqi)); assertEquals("#GB(Hawes2) == 8", 8, Gqi.size()); Gqi = OrderedPolynomialList.> sort(Gqi); PolynomialList> Gpqi = new PolynomialList>(iring, Gqi); //System.out.println("Gqi = " + Gpqi); assertTrue("nonsense ", !Gpqi.getList().isEmpty()); bbqi.terminate(); Kqi = PolyUfdUtil. quotientFromIntegralCoefficients(iring, G); Kqi = PolyUtil.> monic(Kqi); assertEquals("quotRatGB == quotIntGB", Gqi, Kqi); assertTrue("nonsense ", i >= 0L); assertTrue("positive times ", s >= 0L && t >= 0L && q >= 0L && i >= 0L); //System.out.println("time: ratGB = " + s + ", intGB = " + t + ", quotRatGB = " + q + ", quotIntGB = " // + i); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBasePseudoRecSeqTest.java000066400000000000000000000210701445075545500272730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Groebner base recursive pseudo reduction sequential tests with JUnit. * @author Heinz Kredel */ public class GroebnerBasePseudoRecSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GroebnerBasePseudoRecSeqTest object. * @param name String. */ public GroebnerBasePseudoRecSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBasePseudoRecSeqTest.class); return suite; } GenPolynomialRing> fac; List>> L; PolynomialList> F; List>> G; GroebnerBaseAbstract> bb; GroebnerBaseAbstract> bbr; GenPolynomial> a, b, c, d, e; int rl = 2; //4; //3; int kl = 2; int ll = 5; int el = 4; float q = 0.3f; //0.4f @Override protected void setUp() { BigInteger coeff = new BigInteger(9); GenPolynomialRing cofac = new GenPolynomialRing(coeff, 1); fac = new GenPolynomialRing>(cofac, rl); a = b = c = d = e = null; bb = new GroebnerBasePseudoRecSeq(cofac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; //bb.terminate(); bb = null; } /** * Test recursive sequential GBase. */ public void testRecSequentialGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.getZERO(); //fac.random(kl, ll, el, q); e = c; //fac.random(kl, ll, el, q ); L.add(a); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); if (bb.commonZeroTest(L) < 0) { L.clear(); } L.add(c); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println("L = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Hawes2 GBase. */ @SuppressWarnings("unchecked") public void testHawes2GBase() { String exam = "IntFunc(a, c, b) (y2, y1, z1, z2, x) G" + "(" + "( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 )," + "( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 )," + "( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } )," + "( 3 z1^2 + y1^2 + { b } )," + "( 3 z2^2 + y2^2 + { b } )" + ")"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList> Fr = null; try { Fr = parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } GenPolynomialRing cofac = (GenPolynomialRing) Fr.ring.coFac; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), cofac); fac = new GenPolynomialRing>(ifac, Fr.ring); L = PolyUfdUtil.integerFromRationalCoefficients(fac, Fr.list); //System.out.println("F = " + L); //System.out.println("Fr = " + Fr); long s, t, q, i; t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Hawes2) )", bb.isGB(G)); assertEquals("#GB(Hawes2) == 8", 8, G.size()); PolynomialList> Gp = new PolynomialList>(fac, G); //System.out.println("G = " + Gp); assertTrue("nonsense ", !Gp.getList().isEmpty()); GenPolynomialRing rfac = (GenPolynomialRing) Fr.ring.coFac; List>> Gr, Kr, Lr = Fr.list; bbr = new GroebnerBasePseudoRecSeq(rfac); s = System.currentTimeMillis(); Gr = bbr.GB(Lr); s = System.currentTimeMillis() - s; Gr = PolyUtil. monicRec(Gr); PolynomialList> Grp = new PolynomialList>( Fr.ring, Gr); //System.out.println("Gr = " + Grp); assertTrue("nonsense ", !Grp.getList().isEmpty()); Kr = PolyUfdUtil. fromIntegerCoefficients(Fr.ring, G); Kr = PolyUtil. monicRec(Kr); assertEquals("ratGB == intGB", Kr, Gr); assertTrue("nonsense ", s >= 0L); QuotientRing qr = new QuotientRing(rfac); GenPolynomialRing> rring = new GenPolynomialRing>(qr, fac); List>> Gq, Lq, Kq; Lq = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Lr); Lq = PolyUtil.> monic(Lq); GroebnerBaseAbstract> bbq; bbq = new GroebnerBaseSeq>(); //qr); q = System.currentTimeMillis(); Gq = bbq.GB(Lq); q = System.currentTimeMillis() - q; assertTrue("isGB( GB(Hawes2) )", bbq.isGB(Gq)); assertEquals("#GB(Hawes2) == 8", 8, Gq.size()); PolynomialList> Gpq = new PolynomialList>(rring, Gq); //System.out.println("Gpq = " + Gpq); assertTrue("nonsense ", !Gpq.getList().isEmpty()); Kq = PolyUfdUtil. quotientFromIntegralCoefficients(rring, Gr); Kq = PolyUtil.> monic(Kq); assertEquals("ratGB == quotGB", Kq, Gq); QuotientRing qi = new QuotientRing(ifac); GenPolynomialRing> iring = new GenPolynomialRing>(qi, fac); List>> Gqi, Lqi, Kqi; Lqi = PolyUfdUtil. quotientFromIntegralCoefficients(iring, L); Lqi = PolyUtil.> monic(Lqi); //System.out.println("Lqi = " + Lqi); GroebnerBaseAbstract> bbqi; bbqi = new GroebnerBaseSeq>(); //qr); i = System.currentTimeMillis(); Gqi = bbqi.GB(Lqi); i = System.currentTimeMillis() - i; assertTrue("isGB( GB(Hawes2) )", bbqi.isGB(Gqi)); assertEquals("#GB(Hawes2) == 8", 8, Gqi.size()); PolynomialList> Gpqi = new PolynomialList>(iring, Gqi); //System.out.println("Gpqi = " + Gpqi); assertTrue("nonsense ", !Gpqi.getList().isEmpty()); Kqi = PolyUfdUtil. quotientFromIntegralCoefficients(iring, G); Kqi = PolyUtil.> monic(Kqi); assertEquals("quotRatGB == quotIntGB", Gqi, Kqi); System.out.println("time: ratGB = " + s + ", intGB = " + t + ", quotRatGB = " + q + ", quotIntGB = " + i); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBasePseudoSeqTest.java000066400000000000000000000122611445075545500266430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; /** * Groebner base pseudo reduction sequential tests with JUnit. * @author Heinz Kredel */ public class GroebnerBasePseudoSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBasePseudoSeqTest object. * @param name String. */ public GroebnerBasePseudoSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBasePseudoSeqTest.class); return suite; } GenPolynomialRing fac; List> L, G; PolynomialList F; GroebnerBase bb; GenPolynomial a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigInteger coeff = new BigInteger(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBasePseudoSeq(coeff); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. * */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. * */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long s, t; t = System.currentTimeMillis(); G = bb.GB(F.list); t = System.currentTimeMillis() - t; assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); assertTrue("nonsense ", t >= 0L); GenPolynomialRing ifac = F.ring; BigRational cf = new BigRational(); GenPolynomialRing rfac = new GenPolynomialRing(cf, ifac); List> Gr, Fr, Gir; Fr = PolyUtil. fromIntegerCoefficients(rfac, F.list); GroebnerBaseSeq bbr = new GroebnerBaseSeq(); s = System.currentTimeMillis(); Gr = bbr.GB(Fr); s = System.currentTimeMillis() - s; Gir = PolyUtil. fromIntegerCoefficients(rfac, G); Gir = PolyUtil. monic(Gir); assertEquals("ratGB == intGB", Gr, Gir); //System.out.println("time: ratGB = " + s + ", intGB = " + t); assertTrue("nonsense ", s >= 0L); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBaseQuotientTest.java000066400000000000000000000170341445075545500265460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Groebner base sequential quotient fraction free tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseQuotientTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseQuotientTest object. * @param name String. */ public GroebnerBaseQuotientTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseQuotientTest.class); return suite; } GenPolynomialRing> fac; List>> L, Lp, Lq; PolynomialList> F; List>> G, Gp; GroebnerBaseAbstract> bb; GroebnerBaseAbstract> bbp; GroebnerBaseAbstract> bbq; GenPolynomial> a, b, c, d, e; int threads = 2; int rl = 4; int kl = 1; //7; // 10 int ll = 3; //7; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); GenPolynomialRing cf = new GenPolynomialRing(coeff, rl / 2, new String[] { "a", "b" }); QuotientRing qf = new QuotientRing(cf); fac = new GenPolynomialRing>(qf, rl / 2, new String[] { "x", "y" }); a = b = c = d = e = null; bb = new GroebnerBaseQuotient(qf); bbp = new GroebnerBaseQuotient(threads, qf); //bbq = new GroebnerBaseSeq>(); bbq = GBFactory.> getImplementation(qf); } @Override protected void tearDown() { bbp.terminate(); a = b = c = d = e = null; fac = null; bb = null; bbp = null; bbq = null; ComputerThreads.terminate(); } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("isMinimalGB( { a } )", bb.isMinimalGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b } )", bb.isMinimalGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c } )", bb.isMinimalGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d } )", bb.isMinimalGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d, e } )", bb.isMinimalGB(L)); } /** * Test parallel GBase. */ public void testParallelGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bbp.GB(L); assertTrue("isGB( { a } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bbp.GB(L); assertTrue("isGB( { a, b } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bbp.GB(L); assertTrue("isGB( { a, b, c } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bbp.GB(L); assertTrue("isGB( { a, b, c, d } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bbp.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d, e } )", bbp.isMinimalGB(L)); } /** * Test compare GBases. */ public void testCompareGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a.sum(b); //fac.random(kl, ll, el, q); d = c; //fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO()) { return; } //assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); Lp = bbp.GB(L); Lq = bbq.GB(L); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("isMinimalGB( { a } )", bb.isMinimalGB(L)); assertEquals("Lp == L: ", Lp, L); assertEquals("Lq == L: ", Lq, L); //System.out.println("L = " + L); L.add(b); Lp = bbp.GB(L); Lq = bbq.GB(L); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b } )", bb.isMinimalGB(L)); assertEquals("Lp == L: ", Lp, L); assertEquals("Lq == L: ", Lq, L); //System.out.println("L = " + L); L.add(c); Lp = bbp.GB(L); Lq = bbq.GB(L); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c } )", bb.isMinimalGB(L)); assertEquals("Lp == L: ", Lp, L); assertEquals("Lq == L: ", Lq, L); //System.out.println("L = " + L); //L.add(d); //Lp = bbp.GB(L); //Lq = bbq.GB(L); //L = bb.GB(L); //assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); //assertTrue("isMinimalGB( { a, b, c, d } )", bb.isMinimalGB(L)); //assertEquals("Lp == L: ", Lp, L); //assertEquals("Lq == L: ", Lq, L); //System.out.println("L = " + L); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBaseRationalTest.java000066400000000000000000000225111445075545500265030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; /** * Groebner base sequential rational fraction free tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseRationalTest extends TestCase { private static final Logger logger = LogManager.getLogger(GroebnerBaseRationalTest.class); /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseRationalTest object. * @param name String. */ public GroebnerBaseRationalTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseRationalTest.class); return suite; } GenPolynomialRing fac; List> L, Lp; PolynomialList F; List> G, Gp; GroebnerBaseAbstract bb; GroebnerBaseAbstract bbp; GenPolynomial a, b, c, d, e; int threads = 2; int rl = 4; //4; //3; int kl = 7; // 10 int ll = 7; int el = 3; // 4 float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); a = b = c = d = e = null; bb = new GroebnerBaseRational(); bbp = new GroebnerBaseRational(threads); } @Override protected void tearDown() { bbp.terminate(); a = b = c = d = e = null; fac = null; bb = null; bbp = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("isMinimalGB( { a } )", bb.isMinimalGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b } )", bb.isMinimalGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c } )", bb.isMinimalGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d } )", bb.isMinimalGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d, e } )", bb.isMinimalGB(L)); } /** * Test parallel GBase. */ public void testParallelGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bbp.GB(L); assertTrue("isGB( { a } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bbp.GB(L); assertTrue("isGB( { a, b } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bbp.GB(L); assertTrue("isGB( { a, b, c } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bbp.GB(L); assertTrue("isGB( { a, b, c, d } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d } )", bbp.isMinimalGB(L)); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bbp.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bbp.isGB(L)); assertTrue("isMinimalGB( { a, b, c, d, e } )", bbp.isMinimalGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " + ") "; @SuppressWarnings("unused") String exam2 = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertTrue("isMinimalGB( GB(Trinks7) )", bb.isMinimalGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); Gp = bbp.GB(F.list); assertTrue("isGB( GB(Trinks7) )", bb.isGB(Gp)); assertTrue("isMinimalGB( GB(Trinks7) )", bb.isMinimalGB(Gp)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); assertEquals("G == Gp: ", G, Gp); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } /** * Test Trinks7 compare GBase. */ @SuppressWarnings("unchecked") public void testTrinks7CompareGBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " //+ "( B**2 + 33/50 B + 2673/10000 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long i = System.currentTimeMillis(); G = bb.GB(F.list); i = System.currentTimeMillis() - i; assertTrue("isGB( GB(Trinks7) )", bb.isGB(G)); assertTrue("isMinimalGB( GB(Trinks7) )", bb.isMinimalGB(G)); assertEquals("#GB(Trinks7) == 6", 6, G.size()); long p = System.currentTimeMillis(); Gp = bbp.GB(F.list); p = System.currentTimeMillis() - p; assertTrue("isGB( GB(Trinks7) )", bbp.isGB(G)); assertTrue("isMinimalGB( GB(Trinks7) )", bbp.isMinimalGB(G)); assertEquals("#GB(Trinks7) == 6", 6, Gp.size()); GroebnerBaseAbstract bbr = new GroebnerBaseSeq(); List> Gr; long r = System.currentTimeMillis(); Gr = bbr.GB(F.list); r = System.currentTimeMillis() - r; assertTrue("isGB( GB(Trinks7) )", bbr.isGB(Gr)); assertTrue("isMinimalGB( GB(Trinks7) )", bbr.isMinimalGB(Gr)); assertEquals("#GB(Trinks7) == 6", 6, Gr.size()); if (logger.isInfoEnabled()) { logger.info("time: seq = " + i + ", par = " + p + ", rat = " + r); } assertEquals("GB_r == GB_i", G, Gr); assertEquals("GB_r == GB_p", G, Gp); //PolynomialList trinks = new PolynomialList(F.ring,G); //System.out.println("G = " + trinks); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/GroebnerBaseWalkTest.java000066400000000000000000000245721445075545500256410ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBaseAbstract; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrderByName; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Groebner base Groebner Walk tests with JUnit. * @author Heinz Kredel */ public class GroebnerBaseWalkTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GroebnerBaseWalkTest object. * @param name String. */ public GroebnerBaseWalkTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GroebnerBaseWalkTest.class); return suite; } List> L, Lp; PolynomialList F; List> G, Gp; GroebnerBaseAbstract bb; GroebnerBaseAbstract bbw; @Override protected void setUp() { //BigRational cf = new BigRational(); //bb = new GroebnerBaseSeq(cf); bb = GBFactory. getImplementation(/*cf*/); bbw = new GroebnerBaseWalk(bb); } @Override protected void tearDown() { bb.terminate(); bbw.terminate(); bb = null; bbw = null; } /** * Test FJLT GBase. Example from the FJLT paper. */ @SuppressWarnings({ "unchecked", "cast" }) public void testFJLTGBase() { // (y,x) String exam = "(y,x) L " // REVILEX REVITDG + "( (x**2 - y**3), (x**3 - y**2 - x) )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList seq = new PolynomialList(F.ring, G); //System.out.println("seq G = " + seq); assertTrue("isGB( GB(FJLT) )", bb.isGB(G)); assertTrue("isMinimalGB( GB(FJLT) )", bb.isMinimalGB(G)); assertEquals("#GB(FJLT) == 2", 2, G.size()); //assertEquals("#GB(FJLT) == 3", 3, G.size()); Gp = bbw.GB(F.list); PolynomialList fjlt = new PolynomialList(F.ring, Gp); //System.out.println("walk G = " + fjlt); assertTrue("isGB( GB(FJLT) )", bb.isGB(Gp)); assertTrue("isMinimalGB( GB(FJLT) )", bb.isMinimalGB(Gp)); assertEquals("#GB(FJLT) == 2", 2, Gp.size()); //assertEquals("#GB(FJLT) == 3", 3, Gp.size()); //Collections.reverse(G); // now in minimal assertEquals("G == Gp: ", seq, fjlt); } /** * Test example GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testFGLMGBase() { //(z,y,x) String exam = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); G = bb.GB(F.list); PolynomialList P = new PolynomialList(F.ring, G); //System.out.println("G = " + P); assertTrue("isGB( GB(P) )", bb.isGB(G)); assertEquals("#GB(P) == 3", 3, G.size()); Gp = bbw.GB(F.list); PolynomialList P2 = new PolynomialList(F.ring, Gp); //System.out.println("G = " + P2); assertTrue("isGB( GB(P2) )", bb.isGB(Gp)); assertEquals("#GB(P2) == 3", 3, Gp.size()); assertEquals("GB == FGLM", P, P2); } /** * Test Trinks GBase. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinksGBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " /*+ ", ( 10000 B**2 + 6600 B + 2673 )"*/ + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); long t = System.currentTimeMillis(); G = bb.GB(F.list); t = System.currentTimeMillis() - t; PolynomialList seq = new PolynomialList(F.ring, G); //System.out.println("seq G = " + seq); assertTrue("isGB( GB(Trinks) )", bb.isGB(G)); assertTrue("isMinimalGB( GB(Trinks) )", bb.isMinimalGB(G)); assertEquals("#GB(Trinks) == 6", 6, G.size()); long w = System.currentTimeMillis(); Gp = bbw.GB(F.list); w = System.currentTimeMillis() - w; PolynomialList tri = new PolynomialList(F.ring, Gp); //System.out.println("walk G = " + tri); //System.out.println("lex = " + t + ", walk = " + w + " in milliseconds"); assertTrue("findbugs ", t + w >= 0L); assertTrue("isGB( GB(Trinks) )", bb.isGB(Gp)); assertTrue("isMinimalGB( GB(Trinks) )", bb.isMinimalGB(Gp)); //assertEquals("#GB(Trinks) == 6", 6, Gp.size()); //Collections.reverse(G); // now in minimal assertEquals("G == Gp: ", seq, tri); // ideal.equals } /** * Test Trinks GBase with different t1 and t2. */ @SuppressWarnings({ "unchecked", "cast" }) public void testTrinksGBaseT1T2() { // t2 = G|4| = IGRLEX.blockOrder(4) String exam = "(B,S,T,Z,P,W) G|4| " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ) " /*+ ", ( 10000 B**2 + 6600 B + 2673 )"*/ + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); // set t1, t2 = TermOrderNyName.IGRLEX.blockOrder(4) bbw = new GroebnerBaseWalk(bb, TermOrderByName.IGRLEX.blockOrder(2)); // Test wrong way from INVLEX to IGRLEX. //bbw = new GroebnerBaseWalk(bb, TermOrderByName.INVLEX); //System.out.println("bbw = " + bbw); Gp = bbw.GB(F.list); //PolynomialList tri = new PolynomialList(F.ring, Gp); //System.out.println("walk G = " + tri); assertTrue("isGB( GB(Trinks) )", bb.isGB(Gp)); assertTrue("isMinimalGB( GB(Trinks) )", bb.isMinimalGB(Gp)); //assertEquals("#GB(Trinks) == 6", 6, Gp.size()); //Collections.reverse(G); // now in minimal } /** * Test ISSAC GBase. Example from the FGLM paper. */ @SuppressWarnings({ "unchecked", "cast" }) public void testFGLMissacGBase() { // String exam = "Mod 32003 (w,z,y,x) L " // Mod 9223372036854775783 536870909 32003 (z,y,x,w) + "( " + " (8*w^2 + 5*w*x - 4*w*y + 2*w*z + 3*w + 5*x^2 + 2*x*y - 7*x*z - 7*x + 7*y^2 -8*y*z - 7*y + 7*z^2 - 8*z + 8)," + "(3*w^2 - 5*w*x - 3*w*y - 6*w*z + 9*w + 4*x^2 + 2*x*y - 2*x*z + 7*x + 9*y^2 + 6*y*z + 5*y + 7*z^2 + 7*z + 5)," + "(-2*w^2 + 9*w*x + 9*w*y - 7*w*z - 4*w + 8*x^2 + 9*x*y - 3*x*z + 8*x + 6*y^2 - 7*y*z + 4*y - 6*z^2 + 8*z + 2)," + "(7*w^2 + 5*w*x + 3*w*y - 5*w*z - 5*w + 2*x^2 + 9*x*y - 7*x*z + 4*x -4*y^2 - 5*y*z + 6*y - 4*z^2 - 9*z + 2)" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); //G = bb.GB(F.list); long t = System.currentTimeMillis(); G = bb.GB(F.list); t = System.currentTimeMillis() - t; //PolynomialList seq = new PolynomialList(F.ring, G); //System.out.println("seq G = " + seq); assertTrue("isGB( GB() )", bb.isGB(G)); assertTrue("isMinimalGB( GB() )", bb.isMinimalGB(G)); //assertEquals("#GB(FJLT) == 2", 2, G.size()); long w = System.currentTimeMillis(); Gp = bbw.GB(F.list); w = System.currentTimeMillis() - w; //PolynomialList fjlt = new PolynomialList(F.ring, Gp); //System.out.println("walk G = " + fjlt); //System.out.println("lex = " + t + ", walk = " + w + " in milliseconds"); assertTrue("findbugs ", t + w >= 0L); assertTrue("isGB( GB() )", bb.isGB(Gp)); assertTrue("isMinimalGB( GB() )", bb.isMinimalGB(Gp)); //assertEquals("#GB(FJLT) == 2", 2, Gp.size()); //Collections.reverse(G); // now in minimal assertEquals("G == Gp: ", G, Gp); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/MultiplicativeSetTest.java000066400000000000000000000456061445075545500261340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; /** * MultiplicativeSet tests with JUnit. * @author Heinz Kredel */ public class MultiplicativeSetTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a MultiplicativeSetTest object. * @param name String. */ public MultiplicativeSetTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(MultiplicativeSetTest.class); return suite; } TermOrder to; GenPolynomialRing fac; List> L; PolynomialList F; List> G; List> M; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 3; //4; //3; int kl = 4; //10 int ll = 5; //7 int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(17, 1); to = new TermOrder( /*TermOrder.INVLEX*/); fac = new GenPolynomialRing(coeff, rl, to); a = b = c = d = e = null; } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; ComputerThreads.terminate(); } /** * Test multiplicative set contained. * */ public void testContaines() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSet(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); if (!a.isConstant()) { assertFalse("not contained ", ms.contains(a)); } MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); } if (!a.equals(b) && !b.isConstant()) { assertFalse("not contained ", ms2.contains(b)); } MultiplicativeSet ms3 = ms2.add(b); //System.out.println("ms3 = " + ms3); if (!b.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); } assertTrue("contained ", ms3.contains(a)); assertTrue("contained ", ms3.contains(b)); if (!a.equals(c) && !b.equals(c) && !c.isConstant()) { assertFalse("not contained ", ms3.contains(c)); } e = a.multiply(b); //System.out.println("e = " + e); if (!e.isConstant()) { assertTrue("contained ", ms3.contains(e)); } MultiplicativeSet ms4 = ms3.add(e); //System.out.println("ms4 = " + ms4); assertTrue("m3 == m4 ", ms3.equals(ms4)); } /** * Test multiplicative set removeFactors. * */ public void testRemoveFactors() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSet(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); e = ms.removeFactors(a); //System.out.println("e = " + e); assertEquals("a == remove(a) ", a, e); MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); e = ms2.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); if (!b.isConstant()) { e = ms2.removeFactors(b); //System.out.println("e = " + e); assertEquals("b == remove(b) ", e, b); } } d = a.multiply(b); MultiplicativeSet ms3 = ms2.add(d); //System.out.println("ms3 = " + ms3); if (!d.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); e = ms3.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); e = ms3.removeFactors(b); //System.out.println("e = " + e); assertTrue("1 == remove(b) ", e.isConstant()); e = ms3.removeFactors(d); //System.out.println("e = " + e); assertTrue("1 == remove(a*b) ", e.isConstant()); if (!c.isConstant()) { e = ms3.removeFactors(c); //System.out.println("e = " + e); assertEquals("c == remove(c) ", e, c); } } } /** * Test co-prime multiplicative set contained. * */ public void testCoPrimeContaines() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetCoPrime(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); if (!a.isConstant()) { assertFalse("not contained ", ms.contains(a)); } MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); } if (!a.equals(b) && !b.isConstant()) { assertFalse("not contained " + ms2, ms2.contains(b)); } MultiplicativeSet ms3 = ms2.add(b); //System.out.println("ms3 = " + ms3); if (!b.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); } assertTrue("contained ", ms3.contains(a)); assertTrue("contained ", ms3.contains(b)); if (!a.equals(c) && !b.equals(c) && !c.isConstant()) { assertFalse("not contained " + ms3, ms3.contains(c)); } e = a.multiply(b); //System.out.println("e = " + e); if (!e.isConstant()) { assertTrue("contained ", ms3.contains(e)); } MultiplicativeSet ms4 = ms3.add(e); //System.out.println("ms4 = " + ms4); assertTrue("m3 == m4 ", ms3.equals(ms4)); } /** * Test co-prime multiplicative set removeFactors. * */ public void testCoPrimeRemoveFactors() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetCoPrime(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); e = ms.removeFactors(a); //System.out.println("e = " + e); assertEquals("a == remove(a) ", a, e); MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); e = ms2.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); if (!b.isConstant()) { e = ms2.removeFactors(b); //System.out.println("e = " + e); assertEquals("b == remove(b) ", e, b); } } d = a.multiply(b); MultiplicativeSet ms3 = ms2.add(d); //System.out.println("ms3 = " + ms3); if (!d.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); e = ms3.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); e = ms3.removeFactors(b); //System.out.println("e = " + e); assertTrue("1 == remove(b) ", e.isConstant()); e = ms3.removeFactors(d); //System.out.println("e = " + e); assertTrue("1 == remove(a*b) ", e.isConstant()); if (!c.isConstant()) { e = ms3.removeFactors(c); //System.out.println("e = " + e); assertEquals("c == remove(c) ", e, c); } } } /** * Test squarefree multiplicative set contained. * */ public void testSquarefreeContaines() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetSquarefree(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); if (!a.isConstant()) { assertFalse("not contained ", ms.contains(a)); } MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); } if (!a.equals(b) && !b.isConstant()) { assertFalse("not contained " + ms2, ms2.contains(b)); } MultiplicativeSet ms3 = ms2.add(b); //System.out.println("ms3 = " + ms3); if (!b.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); } assertTrue("contained ", ms3.contains(a)); assertTrue("contained ", ms3.contains(b)); if (!a.equals(c) && !b.equals(c) && !c.isConstant()) { assertFalse("not contained " + ms3, ms3.contains(c)); } e = a.multiply(b); //System.out.println("e = " + e); if (!e.isConstant()) { assertTrue("contained ", ms3.contains(e)); } MultiplicativeSet ms4 = ms3.add(e); //System.out.println("ms4 = " + ms4); assertTrue("m3 == m4 ", ms3.equals(ms4)); } /** * Test squarefree multiplicative set removeFactors. * */ public void testSquarefreeRemoveFactors() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetSquarefree(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); e = ms.removeFactors(a); //System.out.println("e = " + e); assertEquals("a == remove(a) ", a, e); MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); e = ms2.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); if (!b.isConstant()) { e = ms2.removeFactors(b); //System.out.println("e = " + e); assertEquals("b == remove(b) ", e, b); } } d = a.multiply(b); MultiplicativeSet ms3 = ms2.add(d); //System.out.println("ms3 = " + ms3); if (!d.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); e = ms3.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); e = ms3.removeFactors(b); //System.out.println("e = " + e); assertTrue("1 == remove(b) ", e.isConstant()); e = ms3.removeFactors(d); //System.out.println("e = " + e); assertTrue("1 == remove(a*b) ", e.isConstant()); if (!c.isConstant()) { e = ms3.removeFactors(c); //System.out.println("e = " + e); assertEquals("c == remove(c) ", e, c); } } } /** * Test irreducible multiplicative set contained. * */ public void testFactorsContaines() { a = fac.random(kl - 2, ll - 2, el, q); b = fac.random(kl - 2, ll - 2, el, q); c = fac.random(kl - 2, ll - 2, el, q).monic(); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetFactors(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); if (!a.isConstant()) { assertFalse("not contained ", ms.contains(a)); } MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); if (!a.equals(b) && !b.isConstant()) { assertFalse("not contained " + ms2 + ", " + b, ms2.contains(b)); } } MultiplicativeSet ms3 = ms2.add(b); //System.out.println("ms3 = " + ms3); assertTrue("contained ", ms3.contains(a)); assertTrue("contained ", ms3.contains(b)); if (!b.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); if (!a.monic().equals(c) && !b.monic().equals(c) && !c.isConstant() && !ms3.mset.contains(c)) { assertFalse("not contained " + ms3 + ", " + c, ms3.contains(c)); } } e = a.multiply(b); //System.out.println("e = " + e); if (!e.isConstant()) { assertTrue("contained ", ms3.contains(e)); } MultiplicativeSet ms4 = ms3.add(e); //System.out.println("ms4 = " + ms4); assertTrue("m3 == m4 ", ms3.equals(ms4)); } /** * Test irreducible multiplicative set removeFactors. * */ public void testFactorsRemoveFactors() { a = fac.random(kl - 2, ll - 2, el, q); b = fac.random(kl - 2, ll - 2, el, q); c = fac.random(kl - 2, ll - 2, el, q); d = fac.random(kl - 2, ll - 2, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } MultiplicativeSet ms = new MultiplicativeSetFactors(fac); //System.out.println("ms = " + ms); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("isEmpty ", ms.isEmpty()); e = ms.removeFactors(a); //System.out.println("e = " + e); assertEquals("a == remove(a) ", a, e); MultiplicativeSet ms2 = ms.add(a); //System.out.println("ms2 = " + ms2); if (!a.isConstant()) { assertFalse("not isEmpty ", ms2.isEmpty()); assertTrue("contained ", ms2.contains(a)); e = ms2.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); if (!b.isConstant()) { e = ms2.removeFactors(b); //System.out.println("e = " + e); assertTrue("remove(b) | b ", b.remainder(e).isZERO()); } } d = a.multiply(b); MultiplicativeSet ms3 = ms2.add(d); //System.out.println("ms3 = " + ms3); if (!d.isConstant()) { assertFalse("not isEmpty ", ms3.isEmpty()); e = ms3.removeFactors(a); //System.out.println("e = " + e); assertTrue("1 == remove(a) ", e.isConstant()); e = ms3.removeFactors(b); //System.out.println("e = " + e); assertTrue("1 == remove(b) ", e.isConstant()); e = ms3.removeFactors(d); //System.out.println("e = " + e); assertTrue("1 == remove(a*b) ", e.isConstant()); if (!c.isConstant()) { e = ms3.removeFactors(c); //System.out.println("e = " + e); assertTrue("remove(c) | c ", c.remainder(e).isZERO()); } } } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/PolyGBUtilTest.java000066400000000000000000000620011445075545500244430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.PrimeList; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.ufd.GCDProxy; import edu.jas.ufd.GreatestCommonDivisorAbstract; import edu.jas.ufd.GreatestCommonDivisorModEval; import edu.jas.ufd.GreatestCommonDivisorModular; import edu.jas.ufd.GreatestCommonDivisorSimple; import edu.jas.ufd.GreatestCommonDivisorSubres; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PolyGBUtil tests with JUnit. * @author Heinz Kredel */ public class PolyGBUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a PolyUtilTest object. * @param name String. */ public PolyGBUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PolyGBUtilTest.class); return suite; } //TermOrder to = new TermOrder(TermOrder.INVLEX); TermOrder to = new TermOrder(TermOrder.IGRLEX); int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.29f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test resultant modular. */ public void testResultantModular() { GenPolynomialRing dfac; ModIntegerRing mi; PrimeList primes = new PrimeList(); mi = new ModIntegerRing(primes.get(1)); // 17, 19, 23, 41, 163, dfac = new GenPolynomialRing(mi, rl, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorAbstract ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorAbstract sres = new GreatestCommonDivisorSubres(); GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModEval(); GenPolynomial a, b, c, d, e; for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll + 2, el, q); //a = dfac.parse("6 x0^4 - 17"); //b = dfac.parse("6 x1^2 - 7 x0^2 - 5 x1 - 14"); //a = dfac.parse("5 x1^4 * x2^4 + 2 x1^2 + x0^2"); //b = dfac.parse("5 x0^2 * x1^2 + 2 x2^2 + 5 x2 + 15"); //a = dfac.parse("x0^3 * x2^2 + 6 x0^4 + 6 x0 + 7"); //b = dfac.parse("7 x0^2 * x2^2 + 3 x2^2 + 4 x1^2 * x2 + 4 x2 + 4 x1^2 + x1 + 7"); //System.out.println("a = " + a); //System.out.println("b = " + b); c = ufds.resultant(a, b); d = sres.resultant(a, b); e = ufdm.resultant(a, b); boolean t1 = PolyGBUtil. isResultant(a, b, c); //System.out.println("t1 = " + t1); boolean t2 = PolyGBUtil. isResultant(a, b, d); //System.out.println("t2 = " + t2); boolean t3 = PolyGBUtil. isResultant(a, b, e); //System.out.println("t3 = " + t3); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("isResultant(a,b,c): " + c, t1); assertTrue("isResultant(a,b,d): " + d, t2); assertTrue("isResultant(a,b,e): " + e, t3); } } /** * Test resultant integer. */ public void testResultantInteger() { GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorAbstract ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorAbstract sres = new GreatestCommonDivisorSubres(); GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModular(); //true); GenPolynomial a, b, c, d, e; for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll + 2, el, q); //a = dfac.parse("6 x0^4 - 17"); //b = dfac.parse("6 x1^2 - 7 x0^2 - 5 x1 - 14"); //System.out.println("a = " + a); //System.out.println("b = " + b); c = ufds.resultant(a, b); d = sres.resultant(a, b); e = ufdm.resultant(a, b); boolean t1 = PolyGBUtil. isResultant(a, b, c); //System.out.println("t1 = " + t1); boolean t2 = PolyGBUtil. isResultant(a, b, d); //System.out.println("t2 = " + t2); boolean t3 = PolyGBUtil. isResultant(a, b, e); //System.out.println("t3 = " + t3); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("isResultant(a,b,d): " + d, t2); assertTrue("isResultant(a,b,e): " + e, t3); assertTrue("isResultant(a,b,c): " + c, t1); } } /** * Test resultant modular parallel proxy. */ public void testResultantModularParallel() { GenPolynomialRing dfac; ModIntegerRing mi; PrimeList primes = new PrimeList(); mi = new ModIntegerRing(primes.get(1)); // 17, 19, 23, 41, 163, dfac = new GenPolynomialRing(mi, rl, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorAbstract ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorAbstract sres = new GreatestCommonDivisorSubres(); GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModEval(); GreatestCommonDivisorAbstract pufds = new GCDProxy(sres, ufds); GreatestCommonDivisorAbstract pufdm = new GCDProxy(ufdm, sres); GenPolynomial a, b, c, d; for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll + 2, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = pufds.resultant(a, b); d = pufdm.resultant(a, b); boolean t1 = PolyGBUtil. isResultant(a, b, c); //System.out.println("t1 = " + t1); boolean t2 = PolyGBUtil. isResultant(a, b, d); //System.out.println("t2 = " + t2); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isResultant(a,b,c): " + c, t1); assertTrue("isResultant(a,b,d): " + d, t2); } } /** * Test resultant integer parallel proxy. */ public void testResultantIntegerProxy() { GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorAbstract ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorAbstract sres = new GreatestCommonDivisorSubres(); GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModular(); //true); GreatestCommonDivisorAbstract pufds = new GCDProxy(sres, ufds); GreatestCommonDivisorAbstract pufdm = new GCDProxy(ufdm, sres); GenPolynomial a, b, c, d; for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll + 1, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = pufds.resultant(a, b); d = pufdm.resultant(a, b); boolean t1 = PolyGBUtil. isResultant(a, b, c); //System.out.println("t1 = " + t1); boolean t2 = PolyGBUtil. isResultant(a, b, d); //System.out.println("t2 = " + t2); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isResultant(a,b,d): " + d, t2); assertTrue("isResultant(a,b,c): " + c, t1); } } /** * Test coefficient base pseudo remainder. */ public void testCoefficientBasePseudoRemainder() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); //String[] vars = new String[] { "x1", "x2", "x3" }; String[] vars = new String[] { "x1", "x2" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomialRing> rfac = dfac.recursive(1); //System.out.println("rfac = " + rfac); GenPolynomialRing cfac = (GenPolynomialRing) rfac.coFac; //System.out.println("cfac = " + cfac); GenPolynomial> ar, cr, dr, er; GenPolynomial b; ar = rfac.random(kl, ll, el, q * 1.1f); b = cfac.random(kl, ll + 2, el * 2, q); //System.out.println("ar = " + ar); //System.out.println("b = " + b); cr = PolyGBUtil. coefficientPseudoRemainderBase(ar, b); //System.out.println("cr = " + cr); assertTrue("deg(c) < deg(a): ", cr.degree(0) <= ar.degree(0) || ar.degree(0) == 0); assertTrue("deg(lfcd(c)) < deg(b): ", cr.leadingBaseCoefficient().degree(0) < b.degree(0) || b.degree(0) == 0); dr = ar.multiply(b); //System.out.println("dr = " + dr); cr = PolyGBUtil. coefficientPseudoRemainderBase(dr, b); //System.out.println("cr = " + cr); assertTrue("c == 0: ", cr.isZERO()); long s = ar.degree(0); er = rfac.univariate(0, s + 1); //System.out.println("er = " + er); er = er.multiply(b.multiply(b)); er = er.sum(ar); //System.out.println("er = " + er); cr = PolyGBUtil. coefficientPseudoRemainderBase(er, b); //System.out.println("cr = " + cr); assertTrue("deg(c) < deg(a): ", cr.degree(0) < er.degree(0)); } /** * Test coefficient recursive pseudo remainder. */ public void testCoefficientRecursivePseudoRemainder() { GenPolynomialRing dfac; BigRational br = new BigRational(); to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x1", "x2", "x3" }; //String[] vars = new String[] { "x1", "x2" }; dfac = new GenPolynomialRing(br, to, vars); //System.out.println("dfac = " + dfac); GenPolynomialRing> r1fac = dfac.recursive(2); //System.out.println("r1fac = " + r1fac); GenPolynomialRing>> rfac = r1fac.recursive(1); //System.out.println("rfac = " + rfac); GenPolynomialRing> cfac = (GenPolynomialRing>) rfac.coFac; //System.out.println("cfac = " + cfac); GenPolynomial>> ar, cr, dr, er; GenPolynomial> b; ar = rfac.random(kl, ll, el, q); b = cfac.random(kl, ll + 2, el, q); //System.out.println("ar = " + ar); //System.out.println("b = " + b); cr = PolyGBUtil. coefficientPseudoRemainder(ar, b); //System.out.println("cr = " + cr); assertTrue("deg(c) < deg(a): ", cr.degree(0) <= ar.degree(0) || ar.degree(0) == 0); assertTrue("deg(lfcd(c)) < deg(b): ", cr.leadingBaseCoefficient().degree(0) < b.degree(0) || b.degree(0) == 0); dr = ar.multiply(b); //System.out.println("dr = " + dr); cr = PolyGBUtil. coefficientPseudoRemainder(dr, b); //System.out.println("cr = " + cr); assertTrue("c == 0: ", cr.isZERO()); long s = ar.degree(0); er = rfac.univariate(0, s + 1); ////System.out.println("er = " + er); er = er.multiply(b.multiply(cfac.fromInteger(100))); er = er.sum(ar); //System.out.println("er = " + er); cr = PolyGBUtil. coefficientPseudoRemainder(er, b); //System.out.println("cr = " + cr); assertTrue("deg(c) < deg(a): ", cr.degree(0) < er.degree(0)); } /** * Test sub ring membership. */ public void testSubRing() { GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigRational(1), rl, to); //System.out.println("dfac = " + dfac); GenPolynomial a, b, c, d; a = dfac.random(kl, ll, el, q).abs(); b = dfac.random(kl, ll, el, q).abs(); d = a.multiply(b).sum(b); List> sr = new ArrayList>(3); sr.add(a); sr.add(b); //System.out.println("sr = " + sr); List> srg = PolyGBUtil. subRing(sr); //System.out.println("srg = " + srg); boolean t = PolyGBUtil. subRingMember(srg, d); assertTrue("d in SR: ", t); c = dfac.random(kl, ll, el + el, q * 1.5f).abs(); sr.add(c); //System.out.println("sr = " + sr); d = a.multiply(b).sum(c); t = PolyGBUtil. subRingAndMember(sr, d); assertTrue("d in SR: ", t); } /** * Test Chinese remainder theorem, random. */ public void testCRTrandom() { String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigRational(1), rl, to, vars); //System.out.println("dfac = " + dfac.toScript()); GenPolynomial a, b; List>> F = new ArrayList>>(2); List> F1 = new ArrayList>(2); a = dfac.random(kl, ll, el, q).abs(); b = dfac.random(kl, ll, el, q).abs(); F1.add(a); F1.add(b); F.add(F1); List> F2 = new ArrayList>(2); a = dfac.random(kl, ll, el, q).abs(); b = dfac.random(kl, ll, el, q).abs(); F2.add(a); F2.add(b); F.add(F2); //System.out.println("F = " + F); List> A = new ArrayList>(2); a = dfac.random(kl / 2, ll, el, q).abs(); b = dfac.random(kl / 2, ll, el, q).abs(); A.add(a); A.add(b); //System.out.println("A = " + A); GenPolynomial h = PolyGBUtil. chineseRemainderTheorem(F, A); //System.out.println("h = " + h); assertTrue("h == null or deg(h) >= 0: ", (h == null || h.degree() >= 0)); if (h == null) { return; } assertTrue("isChineseRemainder " + h, PolyGBUtil. isChineseRemainder(F, A, h)); } /** * Test Chinese remainder theorem, random. */ public void testCRTrandomInt() { String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigInteger(1), rl, to, vars); //System.out.println("dfac = " + dfac.toScript()); GenPolynomial a, b; List>> F = new ArrayList>>(2); List> F1 = new ArrayList>(2); a = dfac.random(kl, ll, el, q).abs(); b = dfac.random(kl, ll, el, q).abs(); F1.add(a); F1.add(b); F.add(F1); List> F2 = new ArrayList>(2); a = dfac.random(kl, ll, el, q).abs(); b = dfac.random(kl, ll, el, q).abs(); F2.add(a); F2.add(b); F.add(F2); //System.out.println("F = " + F); List> A = new ArrayList>(2); a = dfac.random(kl / 2, ll, el, q).abs(); b = dfac.random(kl / 2, ll, el, q).abs(); A.add(a); A.add(b); //System.out.println("A = " + A); GenPolynomial h = PolyGBUtil. chineseRemainderTheorem(F, A); //System.out.println("h = " + h); if (h == null) { return; } assertTrue("h == null or deg(h) >= 0: ", (h == null || h.degree() >= 0)); //boolean t = PolyGBUtil. isChineseRemainder(F, A, h); //System.out.println("t = " + t); //assertTrue("isChineseRemainder " + h, PolyGBUtil. isChineseRemainder(F, A, h)); } /** * Test Chinese remainder theorem, interpolation. */ public void testCRTLagrange() { String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigRational(1), rl, to, vars); //System.out.println("dfac = " + dfac.toScript()); GenPolynomial a, b, c; List>> F = new ArrayList>>(2); List> F1 = new ArrayList>(3); a = dfac.parse("(x-(2**16-15))"); F1.add(a); b = dfac.parse("(y-13)"); F1.add(b); c = dfac.parse("(z-169)"); F1.add(c); F.add(F1); List> F2 = new ArrayList>(3); a = dfac.parse("(x-7)"); F2.add(a); b = dfac.parse("(y-(2**32-5))"); F2.add(b); c = dfac.parse("(z-101)"); F2.add(c); F.add(F2); List> F3 = new ArrayList>(3); a = dfac.parse("(x-17)"); F3.add(a); b = dfac.parse("(y-23)"); F3.add(b); c = dfac.parse("(z-(2**15-19))"); F3.add(c); F.add(F3); //System.out.println("F = " + F); List> A = new ArrayList>(2); a = dfac.parse("(4)"); b = dfac.parse("(11)"); c = dfac.parse("(103)"); A.add(a); A.add(b); A.add(c); //System.out.println("A = " + A); GenPolynomial h = PolyGBUtil. chineseRemainderTheorem(F, A); //System.out.println("h = " + h); assertTrue("h == null or deg(h) >= 0: ", (h == null || h.degree() >= 0)); if (h == null) { return; } assertTrue("isChineseRemainder " + h, PolyGBUtil. isChineseRemainder(F, A, h)); } /** * Test Chinese remainder theorem, interpolation. */ public void testCRTLagrangeInt() { String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigInteger(1), rl, to, vars); //System.out.println("dfac = " + dfac.toScript()); GenPolynomial a, b, c; List>> F = new ArrayList>>(2); List> F1 = new ArrayList>(3); a = dfac.parse("(x-(2**16-15))"); F1.add(a); b = dfac.parse("(y-13)"); F1.add(b); c = dfac.parse("(z-169)"); F1.add(c); F.add(F1); List> F2 = new ArrayList>(3); a = dfac.parse("(x-7)"); F2.add(a); b = dfac.parse("(y-(2**32-5))"); F2.add(b); c = dfac.parse("(z-101)"); F2.add(c); F.add(F2); List> F3 = new ArrayList>(3); a = dfac.parse("(x-17)"); F3.add(a); b = dfac.parse("(y-23)"); F3.add(b); c = dfac.parse("(z-(2**15-19))"); F3.add(c); F.add(F3); //System.out.println("F = " + F); List> A = new ArrayList>(2); a = dfac.parse("(4)"); b = dfac.parse("(11)"); c = dfac.parse("(103)"); A.add(a); A.add(b); A.add(c); //System.out.println("A = " + A); GenPolynomial h = PolyGBUtil. chineseRemainderTheorem(F, A); //System.out.println("h = " + h); assertTrue("deg(h) > 0: ", h.degree() > 0); //if (h == null) { // return; //} //boolean t = PolyGBUtil. isChineseRemainder(F, A, h); //System.out.println("t = " + t); //assertTrue("isChineseRemainder " + h, PolyGBUtil. isChineseRemainder(F, A, h)); } /** * Test Chinese remainder theorem, interpolation. */ public void testCRTnterpolation() { String[] vars = new String[] { "x", "y", "z" }; BigRational cfac = new BigRational(1); GenPolynomialRing dfac; dfac = new GenPolynomialRing(cfac, rl, to, vars); //System.out.println("dfac = " + dfac.toScript()); BigRational a, b, c; List> F = new ArrayList>(3); List F1 = new ArrayList(3); a = cfac.parse("65521"); F1.add(a); b = cfac.parse("13"); F1.add(b); c = cfac.parse("169"); F1.add(c); F.add(F1); List F2 = new ArrayList(3); a = cfac.parse("7"); F2.add(a); b = cfac.parse("4294967291"); F2.add(b); c = cfac.parse("101"); F2.add(c); F.add(F2); List F3 = new ArrayList(3); a = cfac.parse("17"); F3.add(a); b = cfac.parse("23"); F3.add(b); c = cfac.parse("32749"); F3.add(c); F.add(F3); List F4 = new ArrayList(3); a = cfac.parse("27"); F4.add(a); b = cfac.parse("33"); F4.add(b); c = cfac.parse("42749"); F4.add(c); F.add(F4); List F5 = new ArrayList(3); a = cfac.parse("37"); F5.add(a); b = cfac.parse("43"); F5.add(b); c = cfac.parse("22749"); F5.add(c); F.add(F5); List F6 = new ArrayList(3); a = cfac.parse("47"); F6.add(a); b = cfac.parse("53"); F6.add(b); c = cfac.parse("12749"); F6.add(c); F.add(F6); List F7 = new ArrayList(3); a = cfac.parse("57"); F7.add(a); b = cfac.parse("63"); F7.add(b); c = cfac.parse("2749"); F7.add(c); F.add(F7); List F8 = new ArrayList(3); a = cfac.parse("67"); F8.add(a); b = cfac.parse("93"); F8.add(b); c = cfac.parse("749"); F8.add(c); F.add(F8); List F9 = new ArrayList(3); a = cfac.parse("77"); F9.add(a); b = cfac.parse("103"); F9.add(b); c = cfac.parse("49"); F9.add(c); F.add(F9); //System.out.println("F = " + F); List A = new ArrayList(3); a = cfac.parse("4"); b = cfac.parse("11"); c = cfac.parse("103"); A.add(a); A.add(b); A.add(c); c = cfac.parse("13"); A.add(c); c = cfac.parse("23"); A.add(c); c = cfac.parse("91"); A.add(c); c = cfac.parse("81"); A.add(c); c = cfac.parse("72"); A.add(c); c = cfac.parse("102"); A.add(c); //System.out.println("A = " + A); GenPolynomial h = PolyGBUtil. CRTInterpolation(dfac, F, A); //System.out.println("h = " + h); assertTrue("deg(h) > 0: ", h.degree() > 0); //if (h == null) { // return; //} //boolean t = PolyGBUtil. isChineseRemainder(F, A, h); //System.out.println("t = " + t); //assertTrue("isChineseRemainder " + h, PolyGBUtil. isChineseRemainder(F, A, h)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/RGroebnerBasePseudoSeqTest.java000066400000000000000000000151731445075545500267720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.gb.GroebnerBase; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.structure.RingFactory; /** * R-Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class RGroebnerBasePseudoSeqTest extends TestCase { // private static final Logger logger = /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); // ComputerThreads.terminate(); } /** * Constructs a RGroebnerBasePseudoSeqTest object. * @param name String. */ public RGroebnerBasePseudoSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RGroebnerBasePseudoSeqTest.class); return suite; } ProductRing pfac; GenPolynomialRing> fac; List>> L, G; PolynomialList> F; GroebnerBase> bb; GenPolynomial> a, b, c, d, e; int pl = 3; int rl = 3; // 4; //3; int kl = 7; // 10; int ll = 7; int el = 3; float q = 0.3f; // 0.4f @Override protected void setUp() { BigInteger coeff = new BigInteger(9); pfac = new ProductRing(coeff, pl); fac = new GenPolynomialRing>(pfac, rl); a = b = c = d = e = null; bb = new RGroebnerBasePseudoSeq>(pfac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; // fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() /* || c.isZERO() || d.isZERO() */) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); // System.out.println("L = " + L ); L = bb.GB(L); // System.out.println("L = " + L ); assertTrue("isGB( { a } )", bb.isGB(L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); // System.out.println("L = " + L ); L = bb.GB(L); // System.out.println("L = " + L ); assertTrue("isGB( { a, b } )", bb.isGB(L)); // assertTrue("not isZERO( c )", !c.isZERO() ); L.add(c); // System.out.println("L = " + L ); L = bb.GB(L); // System.out.println("L = " + L ); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); // assertTrue("not isZERO( d )", !d.isZERO() ); L.add(d); // System.out.println("L = " + L ); L = bb.GB(L); // System.out.println("L = " + L ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); // assertTrue("not isZERO( e )", !e.isZERO() ); L.add(e); // System.out.println("L = " + L ); L = bb.GB(L); // System.out.println("L = " + L ); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7() { String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } // System.out.println("F = " + F); PolynomialList> trinks; List> colist; colist = new ArrayList>(); // colist.add( new BigInteger() ); // colist.add( new BigInteger() ); // colist.add( new BigInteger() ); // colist.add( new BigInteger() ); colist.add(new BigInteger()); colist.add(new BigInteger()); // colist.add( new BigInteger() ); // System.out.println("colist = " + colist); ProductRing pfac; pfac = new ProductRing(colist); // System.out.println("pfac = " + pfac); GenPolynomialRing> fac; fac = new GenPolynomialRing>(pfac, F.ring); // System.out.println("fac = " + fac); List>> Fp = null; Fp = PolyUtil. toProductGen(fac, F.list); List>> Fpp; Fpp = new ArrayList>>(); for (GenPolynomial> a : Fp) { Fpp.add(a.multiply(pfac.getAtomic(0))); Fpp.add(a.multiply(pfac.getAtomic(1))); // Fpp.add( a ); } Fp = Fpp; //trinks = new PolynomialList>(fac, Fp); // System.out.println("Fp = " + trinks); GroebnerBase> bbri = new RGroebnerBasePseudoSeq>(pfac); List>> G; G = bbri.GB(Fp); // System.out.println("gb = " + G ); // assertEquals("#GB(Trinks7) == 6", 6, G.size() ); // System.out.println("Fp = " + trinks); trinks = new PolynomialList>(fac, G); // System.out.println("G = " + trinks); assertFalse("trinks != null", trinks == null); assertTrue("isGB( GB(Trinks7) )", bbri.isGB(G)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/RGroebnerBaseSeqTest.java000066400000000000000000000151211445075545500256030ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.gb.GroebnerBase; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; /** * R-Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class RGroebnerBaseSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RGroebnerBaseSeqTest object. * @param name String. */ public RGroebnerBaseSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RGroebnerBaseSeqTest.class); return suite; } ProductRing pfac; GenPolynomialRing> fac; List>> L, G; PolynomialList> F; GroebnerBase> bb; GenPolynomial> a, b, c, d, e; int rl = 3; //4; //3; int kl = 10; int ll = 7; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); pfac = new ProductRing(coeff, 4); fac = new GenPolynomialRing>(pfac, rl); a = b = c = d = e = null; bb = new RGroebnerBaseSeq>(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); if (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); //System.out.println("L = " + L ); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); //System.out.println("L = " + L.size() ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); //System.out.println("L = " + L ); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); //System.out.println("L = " + L ); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); //System.out.println("L = " + L ); assertTrue("not isZERO( e )", !e.isZERO()); L.add(e); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); //System.out.println("L = " + L ); } /** * Test Trinks7 GBase. */ @SuppressWarnings("unchecked") public void testTrinks7() { String exam = "Z(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( 10000 B**2 + 6600 B + 2673 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList F = null; try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); int rl = F.ring.nvar; TermOrder to = F.ring.tord; String[] vars = F.ring.getVars(); PolynomialList> trinks; List> colist; colist = new ArrayList>(); //colist.add( new ModIntegerRing(2) ); //colist.add( new ModIntegerRing(3) ); //colist.add( new ModIntegerRing(5) ); //colist.add( new ModIntegerRing(30) ); // now ok, was not possible colist.add(new ModIntegerRing(19)); colist.add(new ModIntegerRing(23)); //colist.add( new ModIntegerRing((2<<30)-19) ); //System.out.println("colist = " + colist); ProductRing pfac; pfac = new ProductRing(colist); //System.out.println("pfac = " + pfac); GenPolynomialRing> fac; fac = new GenPolynomialRing>(pfac, rl, to, vars); //System.out.println("fac = " + fac); List>> Fp; Fp = PolyUtil.toProduct(fac, F.list); List>> Fpp; Fpp = new ArrayList>>(); for (GenPolynomial> a : Fp) { Fpp.add(a.multiply(pfac.getAtomic(0))); Fpp.add(a.multiply(pfac.getAtomic(1))); //Fpp.add( a ); } Fp = Fpp; //trinks = new PolynomialList>(fac, Fp); //System.out.println("Fp = " + trinks); GroebnerBase> bbr = new RGroebnerBaseSeq>(); List>> G; G = bbr.GB(Fp); //System.out.println("gb = " + G ); //assertEquals("#GB(Trinks7) == 6", 6, G.size() ); //System.out.println("Fp = " + trinks); trinks = new PolynomialList>(fac, G); assertFalse("trings != null", trinks == null); //System.out.println("G = " + trinks); assertTrue("isGB( GB(Trinks7) )", bbr.isGB(G)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/ReductionTest.java000066400000000000000000000550561445075545500244210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.List; import java.util.ArrayList; import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.structure.RingFactory; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.BigComplex; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolynomialList; /** * Reduction tests with JUnit. * @author Heinz Kredel */ public class ReductionTest extends TestCase { /** * main */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ReductionTest object. * @param name String */ public ReductionTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite= new TestSuite(ReductionTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; List> L; PolynomialList F, G; //ReductionSeq red; //Reduction redpar; int rl = 4; int kl = 10; int ll = 11; int el = 5; float q = 0.6f; protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing( new BigRational(0), rl ); //red = new ReductionSeq(); //redpar = new ReductionPar(); } protected void tearDown() { a = b = c = d = e = null; fac = null; //red = null; //redpar = null; } /** * Test rational coefficient r-reduction. */ public void testRationalRReduction() { RingFactory bi = new BigRational(0); ProductRing pr = new ProductRing(bi,3); GenPolynomialRing> fac = new GenPolynomialRing>( pr, rl ); RReductionSeq> rred = new RReductionSeq>(); GenPolynomial> a = fac.random(kl, ll, el, q ); GenPolynomial> b = fac.random(kl, ll, el, q ); GenPolynomial> d; while ( a.isZERO() ) { a = fac.random(kl, ll, el, q ); } while ( b.isZERO() ) { b = fac.random(kl, ll, el, q ); } assertTrue("not isZERO( a )", !a.isZERO() ); List>> L = new ArrayList>>(); L.add(a); GenPolynomial> e = rred.normalform( L, a ); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isNF( e )", rred.isNormalform(L,e) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); e = rred.normalform( L, a ); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isNF( e )", rred.isNormalform(L,e) ); GenPolynomial> c = fac.getONE(); a = a.sum(c); e = rred.normalform( L, a ); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isNF( e )", rred.isNormalform(L,e) ); L = new ArrayList>>(); L.add( a ); assertTrue("isTopRed( a )", rred.isTopReducible(L,a) ); assertTrue("isRed( a )", rred.isReducible(L,a) ); //b = fac.random(kl, ll, el, q ); L.add( b ); assertTrue("isTopRed( b )", rred.isTopReducible(L,b) ); assertTrue("isRed( b )", rred.isReducible(L,b) ); c = fac.random(kl, ll, el, q ); e = rred.normalform( L, c ); assertTrue("isNF( e )", rred.isNormalform(L,e) ); c = rred.booleanClosure(a); //System.out.println("a = " + a); //System.out.println("c = " + c); assertTrue("isBC( c )", rred.isBooleanClosed(c) ); b = a.subtract(c); //System.out.println("b = " + b); d = rred.booleanRemainder(a); //System.out.println("d = " + d); assertEquals("a-BC(a)=BR(a)", b, d ); e = c.sum(d); //System.out.println("e = " + e); assertEquals("a==BC(a)+BR(a)", a, e ); List>> B; List>> Br; L = new ArrayList>>(); L.add( a ); B = rred.booleanClosure(L); Br = rred.reducedBooleanClosure(L); //System.out.println("L = " + L); //System.out.println("B = " + B); //System.out.println("Br = " + Br); assertTrue("isBC( B )", rred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); L.add( b ); B = rred.booleanClosure(L); Br = rred.reducedBooleanClosure(L); //System.out.println("L = " + L); //System.out.println("B = " + B); //System.out.println("Br = " + Br); assertTrue("isBC( B )", rred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); while ( c.isZERO() ) { c = fac.random(kl, ll, el, q ); } L.add( c ); B = rred.booleanClosure(L); Br = rred.reducedBooleanClosure(L); //System.out.println("L = " + L); //System.out.println("B = " + B); //System.out.println("Br = " + Br); assertTrue("isBC( B )", rred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); while ( d.isZERO() ) { d = fac.random(kl, ll, el, q ); } L.add( d ); B = rred.booleanClosure(L); Br = rred.reducedBooleanClosure(L); //System.out.println("L = " + L); //System.out.println("B = " + B); //System.out.println("Br = " + Br); assertTrue("isBC( B )", rred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); } /** * Test rational coefficient r-reduction with recording. */ public void testRatRReductionRecording() { RingFactory bi = new BigRational(0); ProductRing pr = new ProductRing(bi,3); GenPolynomialRing> fac = new GenPolynomialRing>( pr, rl ); RReductionSeq> rred = new RReductionSeq>(); GenPolynomial> a = fac.random(kl, ll, el, q ); GenPolynomial> b = fac.random(kl, ll, el, q ); GenPolynomial> c, d, e; while ( a.isZERO() ) { a = fac.random(kl, ll, el, q ); } while ( b.isZERO() ) { b = fac.random(kl, ll, el, q ); } c = fac.random(kl, ll, el, q ); d = fac.random(kl, ll, el, q ); List>> row = null; List>> L; assertTrue("not isZERO( a )", !a.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); L = new ArrayList>>(); L.add(a); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } e = rred.normalform( row, L, a ); //not for regular rings: assertTrue("isZERO( e )", e.isZERO() ); //System.out.println("row = " + row); //System.out.println("L = " + L); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("is Reduction ", rred.isReductionNF(row,L,a,e) ); L.add(b); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } e = rred.normalform( row, L, b ); assertTrue("is Reduction ", rred.isReductionNF(row,L,b,e) ); L.add(c); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } e = rred.normalform( row, L, c ); assertTrue("is Reduction ", rred.isReductionNF(row,L,c,e) ); L.add(d); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } e = rred.normalform( row, L, d ); assertTrue("is Reduction ", rred.isReductionNF(row,L,d,e) ); } /** * Test integer coefficient pseudo-reduction. */ public void testIntegerPseudoReduction() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing( bi, rl ); PseudoReductionSeq pred = new PseudoReductionSeq(); GenPolynomial a = fac.random(kl, ll, el, q ); GenPolynomial b = fac.random(kl, ll, el, q ); if ( a.isZERO() || b.isZERO() ) { return; } assertTrue("not isZERO( a )", !a.isZERO() ); List> L = new ArrayList>(); L.add(a); GenPolynomial e; e = pred.normalform( L, a ); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); e = pred.normalform( L, a ); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isZERO( e ) some times", e.isZERO() ); GenPolynomial c = fac.getONE(); a = a.sum(c); e = pred.normalform( L, a ); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isConstant( e ) some times", e.isConstant() ); L = new ArrayList>(); a = c.multiply( bi.fromInteger(4) ); b = c.multiply( bi.fromInteger(5) ); L.add( a ); e = pred.normalform( L, b ); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO() ); a = fac.random(kl, ll, el, q ); //.abs(); b = fac.random(kl, ll, el, q ); //.abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>(); L.add( a ); assertTrue("isTopRed( a )", pred.isTopReducible(L,a) ); assertTrue("isRed( a )", pred.isReducible(L,a) ); b = fac.random(kl, ll, el, q ); L.add( b ); assertTrue("isTopRed( b )", pred.isTopReducible(L,b) ); assertTrue("isRed( b )", pred.isReducible(L,b) ); c = fac.random(kl, ll, el, q ); e = pred.normalform( L, c ); assertTrue("isNF( e )", pred.isNormalform(L,e) ); } /** * Test integer pseudo coefficient reduction with recording. */ public void testIntReductionRecording() { BigInteger bi = new BigInteger(0); GenPolynomialRing fac = new GenPolynomialRing( bi, rl ); PseudoReductionSeq pred = new PseudoReductionSeq(); GenPolynomial a = fac.random(kl, ll, el, q ); GenPolynomial b = fac.random(kl, ll, el, q ); GenPolynomial c, d, e, f; if ( a.isZERO() || b.isZERO() ) { return; } c = fac.random(kl, ll, el+1, q ); d = fac.random(kl, ll, el+2, q ); // ------------ //a = fac.parse(" 1803 x0 * x1^4 - 299 x0^3 * x1^2 - 464 x1^4 + 648 x1^3 + 383 x0^3 + 1633 "); //b = fac.parse(" 593 x0^4 * x1^4 - 673 x0^3 * x1^4 + 36 x0^4 + 627 x1^2 + 617 x1 + 668 x0 + 168 "); //b = b.multiply( fac.parse(" 10567759154481 " ) ); //c = a.multiply( fac.parse(" 593 x0^3 - 938267 x0^2 - 435355888 x0 - 202005132032 ") ); //d = a.multiply( fac.parse(" 3475696715811 x0^3 - 3050126808003 x0^2 - 784946666064 x0 - 202005132032 ") ); //------------- List> row = null; List> L; PseudoReductionEntry mf; assertTrue("not isZERO( a )", !a.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); L = new ArrayList>(); L.add(a); row = new ArrayList>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = pred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = pred.normalform( row, L, f ); assertTrue("isZERO( e )", e.isZERO() ); assertTrue("is Reduction ", pred.isNormalform(L,e) ); assertTrue("is ReductionNF ", pred.isReductionNF(row,L,f,e) ); L.add(b); row = new ArrayList>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = pred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = pred.normalform( row, L, f ); assertTrue("is Reduction ", pred.isNormalform(L,e) ); assertTrue("is ReductionNF ", pred.isReductionNF(row,L,f,e) ); L.add(c); row = new ArrayList>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = pred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = pred.normalform( row, L, f ); assertTrue("is Reduction ", pred.isNormalform(L,e) ); assertTrue("is ReductionNF ", pred.isReductionNF(row,L,f,e) ); L.add(d); row = new ArrayList>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = pred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = pred.normalform( row, L, f ); assertTrue("is Reduction ", pred.isNormalform(L,e) ); assertTrue("is ReductionNF ", pred.isReductionNF(row,L,f,e) ); } /** * Test integer coefficient pseudo r-reduction. */ public void testIntegerRReduction() { RingFactory bi = new BigInteger(0); ProductRing pr = new ProductRing(bi,3); GenPolynomialRing> fac = new GenPolynomialRing>( pr, rl ); RReductionSeq> rpred = new RPseudoReductionSeq>(); GenPolynomial> a = fac.random(kl, ll, el, q ); GenPolynomial> b = fac.random(kl, ll, el, q ); GenPolynomial> c, d, e; while ( a.isZERO() ) { a = fac.random(kl, ll, el, q ); } while ( b.isZERO() ) { b = fac.random(kl, ll, el, q ); } assertTrue("not isZERO( a )", !a.isZERO() ); List>> L = new ArrayList>>(); L.add(a); e = rpred.normalform( L, a ); //System.out.println("a = " + a); //System.out.println("e = " + e); assertTrue("isNF( e )", rpred.isNormalform(L,e) ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); e = rpred.normalform( L, a ); assertTrue("isNF( e )", rpred.isNormalform(L,e) ); c = fac.getONE(); a = a.sum(c); e = rpred.normalform( L, a ); assertTrue("isNF( e )", rpred.isNormalform(L,e) ); L = new ArrayList>>(); L.add( a ); assertTrue("isTopRed( a )", rpred.isTopReducible(L,a) ); assertTrue("isRed( a )", rpred.isReducible(L,a) ); //b = fac.random(kl, ll, el, q ); L.add( b ); assertTrue("isTopRed( b )", rpred.isTopReducible(L,b) ); assertTrue("isRed( b )", rpred.isReducible(L,b) ); c = fac.random(kl, ll, el, q ); e = rpred.normalform( L, c ); assertTrue("isNF( e )", rpred.isNormalform(L,e) ); c = rpred.booleanClosure(a); //System.out.println("\nboolean closure"); //System.out.println("a = " + a); //System.out.println("c = " + c); assertTrue("isBC( c )", rpred.isBooleanClosed(c) ); b = a.subtract(c); //System.out.println("b = " + b); d = rpred.booleanRemainder(a); //System.out.println("d = " + d); assertEquals("a-BC(a)=BR(a)", b, d ); e = c.sum(d); //System.out.println("e = " + e); assertEquals("a==BC(a)+BR(a)", a, e ); List>> B; List>> Br; L = new ArrayList>>(); L.add( a ); B = rpred.booleanClosure(L); Br = rpred.reducedBooleanClosure(L); assertTrue("isBC( B )", rpred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rpred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rpred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); L.add( b ); B = rpred.booleanClosure(L); Br = rpred.reducedBooleanClosure(L); assertTrue("isBC( B )", rpred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rpred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rpred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); L.add( c ); B = rpred.booleanClosure(L); Br = rpred.reducedBooleanClosure(L); assertTrue("isBC( B )", rpred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rpred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rpred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); while ( d.isZERO() ) { d = fac.random(kl, ll, el, q ); } L.add( d ); B = rpred.booleanClosure(L); Br = rpred.reducedBooleanClosure(L); assertTrue("isBC( B )", rpred.isBooleanClosed(B) ); assertTrue("isBC( Br )", rpred.isReducedBooleanClosed(Br) ); assertTrue("isBC( Br )", rpred.isBooleanClosed(Br) ); //not always: assertEquals("B == Br", B, Br ); } /** * Test integer pseudo coefficient r-reduction with recording. */ public void testIntRReductionRecording() { RingFactory bi = new BigInteger(0); ProductRing pr = new ProductRing(bi,3); GenPolynomialRing> fac = new GenPolynomialRing>( pr, rl ); RPseudoReductionSeq> rpred = new RPseudoReductionSeq>(); GenPolynomial> a = fac.random(kl, ll, el, q ); GenPolynomial> b = fac.random(kl, ll, el, q ); GenPolynomial> c, d, e, f; while ( a.isZERO() ) { a = fac.random(kl, ll, el, q ); } while ( b.isZERO() ) { b = fac.random(kl, ll, el, q ); } assertTrue("not isZERO( a )", !a.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); c = fac.random(kl, ll, el, q ); d = fac.random(kl, ll, el, q ); List>> row = null; List>> L; PseudoReductionEntry> mf; L = new ArrayList>>(); L.add(a); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = rpred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = rpred.normalform( row, L, f ); //not for regular rings: assertTrue("isZERO( e )", e.isZERO() ); assertTrue("is Reduction ", rpred.isNormalform(L,e) ); assertTrue("is ReductionNF ", rpred.isReductionNF(row,L,f,e) ); L.add(b); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = rpred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = rpred.normalform( row, L, f ); assertTrue("is Reduction ", rpred.isNormalform(L,e) ); assertTrue("is ReductionNF ", rpred.isReductionNF(row,L,f,e) ); L.add(c); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = rpred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = rpred.normalform( row, L, f ); assertTrue("is Reduction ", rpred.isNormalform(L,e) ); assertTrue("is ReductionNF ", rpred.isReductionNF(row,L,f,e) ); L.add(d); row = new ArrayList>>( L.size() ); for ( int m = 0; m < L.size(); m++ ) { row.add(null); } mf = rpred.normalformFactor( L, a ); e = mf.pol; f = a.multiply( mf.multiplicator ); e = rpred.normalform( row, L, f ); assertTrue("is Reduction ", rpred.isNormalform(L,e) ); assertTrue("is ReductionNF ", rpred.isReductionNF(row,L,f,e) ); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SGBFactoryTest.java000066400000000000000000000176051445075545500244260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; // import java.util.Map; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.gb.SGBProxy; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; /** * Solvable Groebner base factory tests with JUnit. * @author Heinz Kredel */ public class SGBFactoryTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SGBFactoryTest object. * @param name String. */ public SGBFactoryTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SGBFactoryTest.class); return suite; } //private final static int bitlen = 100; TermOrder to = new TermOrder(TermOrder.INVLEX); GenSolvablePolynomialRing dfac; GenSolvablePolynomialRing cfac; GenSolvablePolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenSolvablePolynomial a, b, c, d, e; GenSolvablePolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = new GenSolvablePolynomialRing(new BigInteger(1), rl, to); cfac = new GenSolvablePolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenSolvablePolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; } /** * Test get BigInteger implementation. */ public void testBigInteger() { BigInteger bi = new BigInteger(); SolvableGroebnerBase bba; bba = SGBFactory.getImplementation(bi); //System.out.println("bba = " + bba); assertTrue("bba integer " + bba, bba instanceof SolvableGroebnerBasePseudoSeq); } /** * Test get ModInteger implementation. */ public void testModInteger() { ModIntegerRing mi = new ModIntegerRing(19, true); SolvableGroebnerBase bba; bba = SGBFactory.getImplementation(mi); //System.out.println("bba = " + bba); assertTrue("bba modular field " + bba, bba instanceof SolvableGroebnerBaseSeq); mi = new ModIntegerRing(30); bba = SGBFactory.getImplementation(mi); //System.out.println("bba = " + bba); assertTrue("bba modular ring " + bba, bba instanceof SolvableGroebnerBasePseudoSeq); } /** * Test get BigRational implementation. */ public void testBigRational() { BigRational b = new BigRational(); SolvableGroebnerBase bba; bba = SGBFactory.getImplementation(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof SolvableGroebnerBaseSeq); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); SolvableGroebnerBase bba; bba = SGBFactory. getImplementation(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof SolvableGroebnerBaseSeq); } /** * Test get AlgebraicNumber<BigRational> implementation. */ public void testAlgebraicNumberBigRational() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); SolvableGroebnerBase> bba; bba = SGBFactory.> getImplementation(afac); //System.out.println("bba1 = " + bba); assertTrue("bba algebraic ring " + bba, bba instanceof SolvableGroebnerBasePseudoSeq); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); bba = SGBFactory.> getImplementation(afac); //System.out.println("bba1 = " + bba); assertTrue("bba algebraic field " + bba, bba instanceof SolvableGroebnerBaseSeq); } /** * Test get AlgebraicNumber<ModInteger> implementation. */ public void testAlgebraicNumberModInteger() { ModIntegerRing b = new ModIntegerRing(19, true); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); AlgebraicNumber a = afac.getONE(); assertTrue("a == 1 " + a, a.isONE()); SolvableGroebnerBase> bba; bba = SGBFactory.> getImplementation(afac); //System.out.println("bba2 = " + bba); assertTrue("bba algebraic ring " + bba, bba instanceof SolvableGroebnerBasePseudoSeq); } /** * Test get GenPolynomial implementation. */ @SuppressWarnings("unchecked") public void testGenPolynomial() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, rl, to); RingFactory> rf = fac; SolvableGroebnerBase> bba; bba = SGBFactory.getImplementation(fac); //System.out.println("bba = " + bba); assertTrue("bba recursive polynomial " + bba, bba instanceof SolvableGroebnerBasePseudoRecSeq); SolvableGroebnerBase bb; bb = SGBFactory. getImplementation((RingFactory) rf); //System.out.println("bb = " + bb); assertTrue("bba recursive polynomial " + bb, bb instanceof SolvableGroebnerBasePseudoRecSeq); } /** * Test get proxy implementation. */ public void testProxy() { BigRational b = new BigRational(); SolvableGroebnerBaseAbstract bba; bba = SGBFactory.getProxy(b); //System.out.println("bba = " + bba); assertTrue("bba field " + bba, bba instanceof SGBProxy); bba.terminate(); ModIntegerRing m = new ModIntegerRing(2 * 3); SolvableGroebnerBaseAbstract bbm; bbm = SGBFactory.getProxy(m); //System.out.println("bba = " + bba); assertTrue("bbm ! field " + bbm, !(bbm instanceof SGBProxy)); bbm.terminate(); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SolvableGroebnerBasePseudoRecSeqTest.java000066400000000000000000000256231445075545500307730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable Groebner base pseudo recursive sequential tests with JUnit. * @author Heinz Kredel */ public class SolvableGroebnerBasePseudoRecSeqTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SolvableGroebnerBasePseudoRecSeqTest object. * @param name String. */ public SolvableGroebnerBasePseudoRecSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableGroebnerBasePseudoRecSeqTest.class); return suite; } GenSolvablePolynomial> a, b, c, d, e; List>> L; PolynomialList> F, G; GenSolvablePolynomialRing> ring; SolvableGroebnerBaseAbstract> sbb; BigInteger cfac; TermOrder tord; //RelationTable> table; int rl = 4; //4; //3; int kl = 2; int ll = 5; int el = 3; float q = 0.3f; //0.4f @Override protected void setUp() { cfac = new BigInteger(9); tord = new TermOrder(); String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "x", "y" }; GenPolynomialRing cring; cring = new GenPolynomialRing(cfac, tord, cvars); ring = new GenSolvablePolynomialRing>(cring, tord, vars); //table = ring.table; a = b = c = d = e = null; sbb = new SolvableGroebnerBasePseudoRecSeq(cring); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll - 1, el - 1, q); d = ring.random(kl, ll - 1, el - 1, q); e = d; //ring.random(kl, ll, el, q ); } @Override protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; //table = null; cfac = null; sbb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>>(); L.add(a); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test Weyl sequential GBase. */ public void testWeylSequentialGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); //table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll - 1, el - 1, q); d = ring.random(kl, ll - 1, el - 1, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); //System.out.println("L = " + L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test sequential twosided GBase. */ public void testSequentialTSGBase() { L = new ArrayList>>(); L.add(a); L = sbb.twosidedGB(L); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /** * Test Weyl sequential twosided GBase is always 1. */ public void testWeylSequentialTSGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); //table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll - 1, el - 1, q); d = ring.random(kl, ll - 1, el - 1, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>>(); L.add(a); //System.out.println("La = " + L ); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /* * Test sequential extended GBase. public void testSequentialExtendedGBase() { L = new ArrayList>>(); SolvableExtendedGB> exgb; L.add(a); //System.out.println("L = " + L ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L = " + L ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } */ /* * Test Weyl sequential extended GBase. public void testWeylSequentialExtendedGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator> wl = new WeylRelations>(); wl.generate(ring); //table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); SolvableExtendedGB exgb; L = new ArrayList>>(); L.add(a); exgb = sbb.extLeftGB( L ); // System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L = " + L.size() ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } */ } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SolvableGroebnerBasePseudoSeqTest.java000066400000000000000000000245001445075545500303320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable Groebner base pseudo sequential tests with JUnit. * @author Heinz Kredel */ public class SolvableGroebnerBasePseudoSeqTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SolvableGroebnerBasePseudoSeqTest object. * @param name String. */ public SolvableGroebnerBasePseudoSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvableGroebnerBasePseudoSeqTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e; List> L; PolynomialList F, G; GenSolvablePolynomialRing ring; SolvableGroebnerBaseAbstract sbb; BigInteger cfac; TermOrder tord; RelationTable table; int rl = 4; //4; //3; int kl = 2; int ll = 3; int el = 3; float q = 0.2f; //0.4f @Override protected void setUp() { cfac = new BigInteger(9); tord = new TermOrder(); String[] vars = new String[] { "w", "x", "y", "z" }; ring = new GenSolvablePolynomialRing(cfac, tord, vars); table = ring.table; a = b = c = d = e = null; sbb = new SolvableGroebnerBasePseudoSeq(cfac); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); } @Override protected void tearDown() { a = b = c = d = e = null; ring = null; tord = null; table = null; cfac = null; sbb = null; } /** * Test sequential GBase. */ public void testSequentialGBase() { L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test Weyl sequential GBase. */ public void testWeylSequentialGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); L = sbb.leftGB(L); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(L)); L.add(b); //System.out.println("L = " + L.size() ); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(L)); L.add(c); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(L)); L.add(d); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(L)); L.add(e); L = sbb.leftGB(L); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(L)); } /** * Test sequential twosided GBase. */ public void testSequentialTSGBase() { L = new ArrayList>(); L.add(a); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L.size() ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /** * Test Weyl sequential twosided GBase is always 1. */ public void testWeylSequentialTSGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = ring.random(kl, ll, el, q); e = d; //ring.random(kl, ll, el, q ); L = new ArrayList>(); L.add(a); //System.out.println("La = " + L ); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a } )", sbb.isTwosidedGB(L)); L.add(b); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b } )", sbb.isTwosidedGB(L)); L.add(c); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c } )", sbb.isTwosidedGB(L)); L.add(d); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d } )", sbb.isTwosidedGB(L)); L.add(e); L = sbb.twosidedGB(L); //System.out.println("L = " + L ); assertTrue("isTwosidedGB( { a, b, c, d, e } )", sbb.isTwosidedGB(L)); } /* * Test sequential extended GBase. public void testSequentialExtendedGBase() { L = new ArrayList>(); SolvableExtendedGB exgb; L.add(a); //System.out.println("L = " + L ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L = " + L ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G) ); assertTrue("isLeftRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } */ /* * Test Weyl sequential extended GBase. public void testWeylSequentialExtendedGBase() { //int rloc = 4; //ring = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; a = ring.random(kl, ll, el, q ); b = ring.random(kl, ll, el, q ); c = ring.random(kl, ll, el, q ); d = ring.random(kl, ll, el, q ); e = d; //ring.random(kl, ll, el, q ); SolvableExtendedGB exgb; L = new ArrayList>(); L.add(a); exgb = sbb.extLeftGB( L ); // System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a } )", sbb.isLeftReductionMatrix(exgb) ); L.add(b); //System.out.println("L = " + L.size() ); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b } )", sbb.isLeftReductionMatrix(exgb) ); L.add(c); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c } )", sbb.isLeftReductionMatrix(exgb) ); L.add(d); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c, d } )", sbb.isLeftReductionMatrix(exgb) ); L.add(e); exgb = sbb.extLeftGB( L ); //System.out.println("exgb = " + exgb ); assertTrue("isLeftGB( { a, b, c, d, e } )", sbb.isLeftGB(exgb.G) ); assertTrue("isRmat( { a, b, c, d, e } )", sbb.isLeftReductionMatrix(exgb) ); } */ } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SolvablePseudoReductionTest.java000066400000000000000000000330021445075545500272540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.WeylRelations; import edu.jas.util.ListUtil; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Solvable Reduction tests with JUnit. * @author Heinz Kredel */ public class SolvablePseudoReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SolvablePseudoReductionTest object. * @param name String. */ public SolvablePseudoReductionTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(SolvablePseudoReductionTest.class); return suite; } GenSolvablePolynomialRing fac; RelationTable table; GenSolvablePolynomial a, b, c, d, e, f, g, h; List> L; PolynomialList F, G; SolvablePseudoReduction sred; //SolvablePseudoReduction sredpar; int rl = 4; int kl = 10; int ll = 5; int el = 3; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; String[] vars = new String[] { "w", "x", "y", "z" }; fac = new GenSolvablePolynomialRing(new BigInteger(0), vars); sred = new SolvablePseudoReductionSeq(); //sredpar = new SolvablePseudoReductionPar(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; sred = null; //sredpar = null; } /** * Test constants and empty list reduction. */ public void testIntReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.leftNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test constants and empty list reduction. */ public void testWeylIntReduction0() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.leftNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.leftNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.leftNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test Int reduction. */ public void testIntReduction() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Weyl Integer reduction. */ public void testWeylIntReduction() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); e = sred.leftNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.leftNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Test Int reduction recording. */ public void testIntReductionRecording() { List> row = null; PseudoReductionEntry mf; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); mf = sred.leftNormalformFactor(L, a); f = a.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); //d = sred.leftNormalform( row, L, a ); d = sred.leftNormalform(row, L, f); assertTrue("isZERO( d )", d.isZERO()); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, f, d)); L.add(b); mf = sred.leftNormalformFactor(L, b); f = b.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); //e = sred.leftNormalform( row, L, b ); d = sred.leftNormalform(row, L, f); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, f, d)); L.add(c); mf = sred.leftNormalformFactor(L, c); f = c.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); d = sred.leftNormalform(row, L, f); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, f, d)); L.add(d); mf = sred.leftNormalformFactor(L, d); f = d.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); e = sred.leftNormalform(row, L, f); assertTrue("is leftReduction ", sred.isLeftReductionNF(row, L, f, e)); } /* * Test Int reduction parallel. public void testIntReductionPar() { a = fac.random(kl, ll, el, q ); b = fac.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L = new ArrayList>(); L.add(a); e = sredpar.leftNormalform( L, a ); assertTrue("isZERO( e )", e.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); e = sredpar.leftNormalform( L, a ); assertTrue("isZERO( e ) some times", e.isZERO() ); } */ /* * Test Weyl Integer reduction parallel. public void testWeylIntReductionPar() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q ); b = fac.random(kl, ll, el, q ); assertTrue("not isZERO( a )", !a.isZERO() ); L.add(a); e = sredpar.leftNormalform( L, a ); assertTrue("isZERO( e )", e.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); L.add(b); e = sredpar.leftNormalform( L, a ); assertTrue("isZERO( e ) some times", e.isZERO() ); } */ /** * Right test constants and empty list reduction. */ public void testIntRightReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.rightNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.rightNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = sred.rightNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.rightNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Right test constants and empty list reduction. */ public void testWeylIntRightReduction0() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); c = fac.getONE(); d = fac.getZERO(); e = sred.rightNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = sred.rightNormalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = sred.rightNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = sred.rightNormalform(L, c); assertTrue("isONE( e )", e.isONE()); e = sred.rightNormalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Right test Int reduction. */ public void testIntRightReduction() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); e = sred.rightNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.rightNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Right test Weyl Integer reduction. */ public void testWeylIntRightReduction() { L = new ArrayList>(); RelationGenerator wl = new WeylRelations(); wl.generate(fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); e = sred.rightNormalform(L, a); assertTrue("isZERO( e )", e.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); e = sred.rightNormalform(L, a); assertTrue("isZERO( e ) some times", e.isZERO()); } /** * Right test Int reduction recording. */ public void testIntRightReductionRecording() { List> row = null; PseudoReductionEntry mf; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); L = new ArrayList>(); L.add(a); mf = sred.rightNormalformFactor(L, a); f = a.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); //d = sred.rightNormalform( row, L, a ); d = sred.rightNormalform(row, L, f); assertTrue("isZERO( d )", d.isZERO()); assertTrue("is rightReduction ", sred.isRightReductionNF(row, L, f, d)); L.add(b); mf = sred.rightNormalformFactor(L, b); f = b.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); //e = sred.rightNormalform( row, L, b ); d = sred.rightNormalform(row, L, f); assertTrue("is rightReduction ", sred.isRightReductionNF(row, L, f, d)); L.add(c); mf = sred.rightNormalformFactor(L, c); f = c.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); d = sred.rightNormalform(row, L, f); assertTrue("is rightReduction ", sred.isRightReductionNF(row, L, f, d)); L.add(d); mf = sred.rightNormalformFactor(L, d); f = d.multiply(mf.multiplicator); row = ListUtil.> fill(L.size(), fac.getZERO()); e = sred.rightNormalform(row, L, f); assertTrue("is rightReduction ", sred.isRightReductionNF(row, L, f, e)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SolvableSyzygyTest.java000066400000000000000000000571171445075545500254730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.gb.SolvableGroebnerBaseAbstract; import edu.jas.gb.SolvableGroebnerBase; import edu.jas.gb.SolvableGroebnerBaseSeq; import edu.jas.gbufd.SGBFactory; import edu.jas.gbufd.SolvableSyzygyAbstract; import edu.jas.gbufd.SolvableSyzygySeq; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenSolvablePolynomial; import edu.jas.poly.GenSolvablePolynomialRing; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.poly.RelationGenerator; import edu.jas.poly.RelationTable; import edu.jas.poly.TermOrder; import edu.jas.poly.WeylRelations; import edu.jas.poly.WeylRelationsIterated; /** * SolvableSyzygy tests with JUnit. * @author Heinz Kredel */ public class SolvableSyzygyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SolvableSyzygyTest object. * @param name String. */ public SolvableSyzygyTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SolvableSyzygyTest.class); return suite; } BigRational cfac; GenSolvablePolynomialRing fac; PolynomialList F; List> G; GenSolvablePolynomial a, b, c, d, e; GenSolvablePolynomial zero, one; TermOrder tord; RelationTable table; List> L; List>> K; List> V; List>> W; ModuleList M, N, Z; SolvableGroebnerBaseAbstract sbb; SolvableGroebnerBase msbb; SolvableSyzygyAbstract ssz; int rl = 4; //4; //3; int kl = 3; int ll = 7; int el = 2; float q = 0.3f; //0.4f @Override protected void setUp() { cfac = new BigRational(1); tord = new TermOrder(); String[] vars = new String[]{ "w", "x", "y", "z" }; fac = new GenSolvablePolynomialRing(cfac, tord, vars); //RelationGenerator wl = new WeylRelations(); //wl.generate(fac); table = fac.table; a = b = c = d = e = null; L = null; K = null; V = null; do { a = fac.random(kl, ll, el, q); } while (a.isZERO()); do { b = fac.random(kl, ll, el, q); } while (b.isZERO()); do { c = fac.random(kl, ll, el, q); } while (c.isZERO()); do { d = fac.random(kl, ll, el, q); } while (d.isZERO()); e = d; //fac.random(kl, ll, el, q ); one = fac.getONE(); zero = fac.getZERO(); sbb = SGBFactory.getImplementation(cfac); msbb = new SolvableGroebnerBaseSeq(); //cfac); ssz = new SolvableSyzygySeq(cfac); } @Override protected void tearDown() { a = b = c = d = e = null; L = null; K = null; V = null; fac = null; tord = null; table = null; sbb = null; msbb = null; ssz = null; } /** * Test sequential SolvableSyzygy. */ public void testSequentialSolvableSyzygy() { L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("isGB( { a } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); assertTrue("is ZR( { a } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = sbb.leftGB(L); assertTrue("isGB( { a, b } )", sbb.isLeftGB(L)); //System.out.println("\nL = " + L ); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = sbb.leftGB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b, c } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = sbb.leftGB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c, d } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b, c, d } )", ssz.isLeftZeroRelation(K, L)); } /** * Test sequential Weyl SolvableSyzygy. */ public void testSequentialWeylSolvableSyzygy() { int rloc = 4; fac = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(fac); table = fac.table; a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = d; //fac.random(kl, ll, el, q ); L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("isGB( { a } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); assertTrue("is ZR( { a } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = sbb.leftGB(L); assertTrue("isGB( { a, b } )", sbb.isLeftGB(L)); //System.out.println("\nL = " + L ); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(K, L)); // useless since 1 in GB assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = sbb.leftGB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b, c } )", ssz.isLeftZeroRelation(K, L)); // useless since 1 in GB assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = sbb.leftGB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c, d } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelations(L); //System.out.println("\nK = " + K ); assertTrue("is ZR( { a, b, c, d } )", ssz.isLeftZeroRelation(K, L)); } /** * Test sequential module SolvableSyzygy. */ public void testSequentialModSolvableSyzygy() { W = new ArrayList>>(); assertTrue("not isZERO( a )", !a.isZERO()); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); W.add(V); M = new ModuleList(fac, W); assertTrue("isGB( { (a,0,1) } )", msbb.isLeftGB(M)); N = msbb.leftGB(M); assertTrue("isGB( { (a,0,1) } )", msbb.isLeftGB(N)); Z = ssz.leftZeroRelations(N); //System.out.println("Z = " + Z); assertTrue("is ZR( { a) } )", ssz.isLeftZeroRelation(Z, N)); assertTrue("not isZERO( b )", !b.isZERO()); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); N = msbb.leftGB(M); assertTrue("isGB( { a, b } )", msbb.isLeftGB(N)); Z = ssz.leftZeroRelations(N); //System.out.println("Z = " + Z); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(Z, N)); assertTrue("not isZERO( c )", !c.isZERO()); V = new ArrayList>(); V.add(c); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); N = msbb.leftGB(M); //System.out.println("GB(M) = " + N); assertTrue("isGB( { a,b,c) } )", msbb.isLeftGB(N)); Z = ssz.leftZeroRelations(N); //System.out.println("Z = " + Z); //boolean b = ssz.isLeftZeroRelation(Z,N); //System.out.println("boolean = " + b); assertTrue("is ZR( { a,b,c } )", ssz.isLeftZeroRelation(Z, N)); } /** * Test sequential arbitrary base Syzygy. */ public void testSequentialArbitrarySyzygy() { L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("isGB( { a } )", sbb.isLeftGB(L)); K = ssz.leftZeroRelationsArbitrary(L); assertTrue("is ZR( { a } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); K = ssz.leftZeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); K = ssz.leftZeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c } )", ssz.isLeftZeroRelation(K, L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); K = ssz.leftZeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c, d } )", ssz.isLeftZeroRelation(K, L)); } /** * Test sequential arbitrary base Syzygy, ex CLO 2, p 214 ff. */ @SuppressWarnings("unchecked") public void testSequentialArbitrarySyzygyCLO() { PolynomialList F = null; String exam = "Rat(x,y) G " + "( " + "( x y + x ), " + "( y^2 + 1 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextSolvablePolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); L = F.castToSolvableList(); K = ssz.leftZeroRelationsArbitrary(L); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(K, L)); } /** * Test sequential arbitrary base Syzygy, ex WA_32. */ @SuppressWarnings("unchecked") public void testSequentialArbitrarySyzygyWA32() { PolynomialList F = null; String exam = "Rat(e1,e2,e3) L " + "RelationTable " + "( " + " ( e3 ), ( e1 ), ( e1 e3 - e1 ), " + " ( e3 ), ( e2 ), ( e2 e3 - e2 ) " + ")" + "( " + " ( e1 e3^3 + e2^2 ), " + " ( e1^3 e2^2 + e3 ), " + " ( e3^3 + e3^2 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextSolvablePolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); L = F.castToSolvableList(); K = ssz.leftZeroRelationsArbitrary(L); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(K, L)); } /** * Test sequential arbitrary module SolvableSyzygy. */ public void testSequentialArbitraryModSolvableSyzygy() { W = new ArrayList>>(); assertTrue("not isZERO( a )", !a.isZERO()); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); W.add(V); M = new ModuleList(fac, W); assertTrue("isGB( { (a,0,1) } )", msbb.isLeftGB(M)); Z = ssz.leftZeroRelationsArbitrary(M); //System.out.println("Z = " + Z); assertTrue("is ZR( { a) } )", ssz.isLeftZeroRelation(Z, M)); assertTrue("not isZERO( b )", !b.isZERO()); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); Z = ssz.leftZeroRelationsArbitrary(M); //System.out.println("Z = " + Z); assertTrue("is ZR( { a, b } )", ssz.isLeftZeroRelation(Z, M)); assertTrue("not isZERO( c )", !c.isZERO()); V = new ArrayList>(); V.add(c); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); Z = ssz.leftZeroRelationsArbitrary(M); //System.out.println("Z = " + Z); //boolean b = ssz.isLeftZeroRelation(Z,N); //System.out.println("boolean = " + b); assertTrue("is ZR( { a,b,c } )", ssz.isLeftZeroRelation(Z, M)); } /** * Test Ore conditions. */ public void testOreConditions() { RelationGenerator wl = new WeylRelations(); wl.generate(fac); do { a = fac.random(kl, ll - 1, el, q); } while (a.isZERO()); do { b = fac.random(kl, ll - 1, el, q); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); GenSolvablePolynomial[] oc = ssz.leftOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = oc[0].multiply(a); d = oc[1].multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("c_0 * a = c_1 * b: ", c, d); assertTrue("left Ore condition: ", ssz.isLeftOreCond(a, b, oc)); oc = ssz.rightOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = a.multiply(oc[0]); d = b.multiply(oc[1]); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a * c_0 = b * c_1: ", c, d); assertTrue("right Ore condition: ", ssz.isRightOreCond(a, b, oc)); } /** * Test Ore conditions for residues. */ public void testResidueOreConditions() { RelationGenerator wl = new WeylRelations(); wl.generate(fac); // construct ideal { x_i^2 - i, ... } for generators x_i F = new PolynomialList(fac, fac.generators()); //System.out.println("F = " + F); List> gens = F.castToSolvableList(); //System.out.println("gens = " + gens); L = new ArrayList>(gens.size() - 1); long i = 2; for (GenSolvablePolynomial g : gens) { if (g.isONE()) { continue; } GenSolvablePolynomial p = g.multiply(g); p = (GenSolvablePolynomial) p.subtract(fac.fromInteger(i++)); L.add(p); } //System.out.println("L = " + L); do { a = fac.random(kl, ll - 2, el, q); } while (a.isZERO()); do { b = fac.random(kl, ll - 2, el, q); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); GenSolvablePolynomial[] oc = ssz.leftOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = oc[0].multiply(a); d = oc[1].multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("c_0 * a = c_1 * b: ", c, d); assertTrue("left Ore condition: ", ssz.isLeftOreCond(a, b, oc)); // now mod ideal(L): GenSolvablePolynomial ar, br, cr, dr, or0, or1; ar = sbb.sred.leftNormalform(L, a); br = sbb.sred.leftNormalform(L, b); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = oc[0].multiply(ar); dr = oc[1].multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //this is not true: assertEquals("c_0 * a = c_1 * b: ", cr, dr); cr = sbb.sred.leftNormalform(L, cr); dr = sbb.sred.leftNormalform(L, dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertEquals("cr_0 * ar = cr_1 * br: ", cr, dr); or0 = sbb.sred.leftNormalform(L, oc[0]); or1 = sbb.sred.leftNormalform(L, oc[1]); //System.out.println("oc0 = " + oc[0]); //System.out.println("oc1 = " + oc[1]); //System.out.println("or0 = " + or0); //System.out.println("or1 = " + or1); cr = or0.multiply(ar); dr = or1.multiply(br); //okay w/o: cr = sbb.sred.leftNormalform(L,cr); //okay w/o: dr = sbb.sred.leftNormalform(L,dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //not okay: assertEquals("cr_0 * ar = cr_1 * br: ", cr, dr); oc[0] = or0; oc[1] = or1; //not okay: assertTrue("left Ore condition: ", ssz.isLeftOreCond(ar,br,oc)); //System.out.println("new Ore Condition:"); oc = ssz.leftOreCond(ar, br); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); cr = oc[0].multiply(ar); dr = oc[1].multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); //this is true: assertEquals("c_0 * a = c_1 * b: ", cr, dr); cr = sbb.sred.leftNormalform(L, cr); dr = sbb.sred.leftNormalform(L, dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertEquals("cr_0 * ar = cr_1 * br: ", cr, dr); /* not okay: or0 = sbb.sred.leftNormalform(L,oc[0]); or1 = sbb.sred.leftNormalform(L,oc[1]); //System.out.println("oc0 = " + oc[0]); //System.out.println("oc1 = " + oc[1]); //System.out.println("or0 = " + or0); //System.out.println("or1 = " + or1); cr = or0.multiply(ar); dr = or1.multiply(br); //okay w/o: cr = sbb.sred.leftNormalform(L,cr); //okay w/o: dr = sbb.sred.leftNormalform(L,dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertEquals("cr_0 * ar = cr_1 * br: ", cr, dr); oc[0] = or0; oc[1] = or1; assertTrue("left Ore condition: ", ssz.isLeftOreCond(ar,br,oc)); */ } /** * Test Ore conditions quaternion coefficients and commutative variables. */ public void testOreConditionsQuat() { BigQuaternionRing qri = new BigQuaternionRing(); GenSolvablePolynomialRing qfac = new GenSolvablePolynomialRing(qri, fac); SolvableSyzygyAbstract ssz = new SolvableSyzygySeq(qri); //System.out.println("qfac = " + qfac.toScript()); GenSolvablePolynomial a, b, c, d; do { a = qfac.random(1, 3, el, q); //a = qfac.parse(" z - 1i1/2j-1k0 "); // wrong parse of starting - } while (a.isZERO()); do { b = qfac.random(1, 3, el, q); //b = qfac.parse(" 1i1/2j0k1/2 x * z + 1i1/2j-1k0 ").monic(); // wrong parse of starting - } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); GenSolvablePolynomial[] oc = ssz.leftOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = oc[0].multiply(a); d = oc[1].multiply(b); //System.out.println("c_l = " + c); //System.out.println("d_l = " + d); assertTrue("left Ore condition: false", ssz.isLeftOreCond(a, b, oc)); assertEquals("c_0 * a = c_1 * b: " + qfac.toScript(), c, d); oc = ssz.rightOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = a.multiply(oc[0]); d = b.multiply(oc[1]); //System.out.println("c_r = " + c); //System.out.println("d_r = " + d); assertTrue("right Ore condition: false", ssz.isRightOreCond(a, b, oc)); assertEquals("a * c_0 = b * c_1: " + qfac.toScript(), c, d); } /** * Test Ore conditions quaternion coefficients and Weyl relations. */ public void testOreConditionsQuatWeyl() { BigQuaternionRing qri = new BigQuaternionRing(); GenSolvablePolynomialRing qfac = new GenSolvablePolynomialRing(qri, fac); SolvableSyzygyAbstract ssz = new SolvableSyzygySeq(qri); RelationGenerator wl = new WeylRelations(); //RelationGenerator wl = new WeylRelationsIterated(); wl.generate(qfac); //System.out.println("qfac = " + qfac.toScript()); GenSolvablePolynomial a, b, c, d; do { a = qfac.random(1, 3, el, q); //a = qfac.parse(" -1i1j-2k-1 "); // wrong parse of starting - //a = qfac.parse(" 1/2i0j1k-1/2 z "); // wrong parse of starting - //todo: a = qfac.parse(" 1i-1/2j0k1/2 y * z + 1i0j1k0 x + 1i1j0k0 "); // wrong parse of starting - } while (a.isZERO()); do { b = qfac.random(1, 3, el, q); //b = qfac.parse(" -1i1/2j1k-1/2 x + 3/2i1j-1/2k1 "); // wrong parse of starting - //b = qfac.parse(" 1i-1j0k-1/2 w * x * z + 1i-1/2j-1/2k0 y "); // wrong parse of starting - //todo: b = qfac.parse(" 0i1j0k1 y - 0i1j-1k-1 "); // wrong parse of starting - } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); GenSolvablePolynomial[] oc = ssz.leftOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = oc[0].multiply(a); d = oc[1].multiply(b); //System.out.println("c_l = " + c); //System.out.println("d_l = " + d); assertTrue("left Ore condition: false", ssz.isLeftOreCond(a, b, oc)); assertEquals("c_0 * a = c_1 * b: " + qfac.toScript(), c, d); oc = ssz.rightOreCond(a, b); //System.out.println("oc[0] = " + oc[0]); //System.out.println("oc[1] = " + oc[1]); c = a.multiply(oc[0]); d = b.multiply(oc[1]); //System.out.println("c_r = " + c); //System.out.println("d_r = " + d); assertTrue("right Ore condition: false", ssz.isRightOreCond(a, b, oc)); assertEquals("a * c_0 = b * c_1: " + qfac.toScript(), c, d); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/SyzygyTest.java000066400000000000000000000240401445075545500237700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.gb.GroebnerBase; import edu.jas.gb.GroebnerBaseSeq; import edu.jas.gbufd.GBFactory; import edu.jas.gbufd.Syzygy; import edu.jas.gbufd.SyzygySeq; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.ModuleList; import edu.jas.poly.PolynomialList; import edu.jas.poly.TermOrder; /** * Syzygy tests with JUnit. * @author Heinz Kredel */ public class SyzygyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SyzygyTest object. * @param name String. */ public SyzygyTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SyzygyTest.class); return suite; } GenPolynomialRing fac; PolynomialList F; List> G; GroebnerBase bb; GroebnerBase mbb; Syzygy sz; GenPolynomial a, b, c, d, e; GenPolynomial zero; GenPolynomial one; TermOrder tord; List> L; List>> K; List> V; List>> W; ModuleList M; ModuleList N; ModuleList Z; int rl = 3; //4; //3; int kl = 3; //7; int ll = 7; //9; int el = 2; float q = 0.3f; //0.4f @Override protected void setUp() { BigRational coeff = new BigRational(9); tord = new TermOrder(); fac = new GenPolynomialRing(coeff, rl, tord); bb = GBFactory.getImplementation(coeff); mbb = new GroebnerBaseSeq(); //coeff); sz = new SyzygySeq(coeff); a = b = c = d = e = null; L = null; K = null; V = null; do { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); } while (a.isZERO() || b.isZERO() || c.isZERO() || d.isZERO()); e = d; //fac.random(kl, ll, el, q ); one = fac.getONE(); zero = fac.getZERO(); } @Override protected void tearDown() { a = b = c = d = e = null; L = null; K = null; V = null; fac = null; tord = null; bb = null; mbb = null; sz = null; } /** * Test sequential Syzygy. */ public void testSequentialSyzygy() { L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("isGB( { a } )", bb.isGB(L)); K = sz.zeroRelations(L); assertTrue("is ZR( { a } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); //System.out.println("\nL = " + L ); K = sz.zeroRelations(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); L = bb.GB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); K = sz.zeroRelations(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); L = bb.GB(L); //System.out.println("\nL = " + L ); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); K = sz.zeroRelations(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c, d } )", sz.isZeroRelation(K, L)); //System.out.println("N = " + N ); /* */ } /** * Test sequential module Syzygy. */ public void testSequentialModSyzygy() { W = new ArrayList>>(); assertTrue("not isZERO( a )", !a.isZERO()); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); W.add(V); M = new ModuleList(fac, W); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(M)); N = mbb.GB(M); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(N)); Z = sz.zeroRelations(N); //System.out.println("Z = " + Z); assertTrue("is ZR( { a) } )", sz.isZeroRelation(Z, N)); assertTrue("not isZERO( b )", !b.isZERO()); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); N = mbb.GB(M); assertTrue("isGB( { a, b } )", mbb.isGB(N)); Z = sz.zeroRelations(N); //System.out.println("Z = " + Z); assertTrue("is ZR( { a, b } )", sz.isZeroRelation(Z, N)); assertTrue("not isZERO( c )", !c.isZERO()); V = new ArrayList>(); V.add(c); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); N = mbb.GB(M); //System.out.println("GB(M) = " + N); assertTrue("isGB( { a,b,c) } )", mbb.isGB(N)); Z = sz.zeroRelations(N); //System.out.println("Z = " + Z); //boolean b = Syzygy.isZeroRelation(Z,N); //System.out.println("boolean = " + b); assertTrue("is ZR( { a,b,c } )", sz.isZeroRelation(Z, N)); } /** * Test sequential arbitrary base Syzygy. */ public void testSequentialArbitrarySyzygy() { L = new ArrayList>(); assertTrue("not isZERO( a )", !a.isZERO()); L.add(a); assertTrue("isGB( { a } )", bb.isGB(L)); K = sz.zeroRelationsArbitrary(L); assertTrue("is ZR( { a } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( b )", !b.isZERO()); L.add(b); // L = bb.GB(L); // assertTrue("isGB( { a, b } )", bb.isGB(L) ); //System.out.println("\nL = " + L ); K = sz.zeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( c )", !c.isZERO()); L.add(c); //L = bb.GB(L); //System.out.println("\nL = " + L ); //assertTrue("isGB( { a, b, c } )", bb.isGB(L) ); K = sz.zeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c } )", sz.isZeroRelation(K, L)); assertTrue("not isZERO( d )", !d.isZERO()); L.add(d); //L = bb.GB(L); //System.out.println("\nL = " + L ); //assertTrue("isGB( { a, b, c, d } )", bb.isGB(L) ); K = sz.zeroRelationsArbitrary(L); //System.out.println("\nN = " + N ); assertTrue("is ZR( { a, b, c, d } )", sz.isZeroRelation(K, L)); //System.out.println("N = " + N ); } /** * Test sequential arbitrary base Syzygy, ex CLO 2, p 214 ff. */ @SuppressWarnings("unchecked") public void testSequentialArbitrarySyzygyCLO() { PolynomialList F = null; String exam = "(x,y) G " + "( " + "( x y + x ), " + "( y^2 + 1 ) " + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); L = F.list; K = sz.zeroRelationsArbitrary(L); assertTrue("is ZR( { a, b } )", sz.isZeroRelation(K, L)); } /** * Test sequential arbitrary module Syzygy. */ public void testSequentialArbitraryModSyzygy() { W = new ArrayList>>(); assertTrue("not isZERO( a )", !a.isZERO()); V = new ArrayList>(); V.add(a); V.add(zero); V.add(one); W.add(V); M = new ModuleList(fac, W); assertTrue("isGB( { (a,0,1) } )", mbb.isGB(M)); Z = sz.zeroRelationsArbitrary(M); //System.out.println("Z = " + Z); assertTrue("is ZR( { a) } )", sz.isZeroRelation(Z, M)); assertTrue("not isZERO( b )", !b.isZERO()); V = new ArrayList>(); V.add(b); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); Z = sz.zeroRelationsArbitrary(M); //System.out.println("Z = " + Z); assertTrue("is ZR( { a, b } )", sz.isZeroRelation(Z, M)); assertTrue("not isZERO( c )", !c.isZERO()); V = new ArrayList>(); V.add(c); V.add(one); V.add(zero); W.add(V); M = new ModuleList(fac, W); //System.out.println("W = " + W.size() ); Z = sz.zeroRelationsArbitrary(M); //System.out.println("Z = " + Z); //boolean b = Syzygy.isZeroRelation(Z,N); //System.out.println("boolean = " + b); assertTrue("is ZR( { a,b,c } )", sz.isZeroRelation(Z, M)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/WordGroebnerBasePseudoRecSeqTest.java000066400000000000000000000161271445075545500301360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.gb.WordGroebnerBaseAbstract; import edu.jas.gb.WordGroebnerBaseSeq; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.PolynomialList; import edu.jas.ufd.PolyUfdUtil; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; /** * Word Groebner base recursive pseudo reduction sequential tests with JUnit. * @author Heinz Kredel */ public class WordGroebnerBasePseudoRecSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a WordGroebnerBasePseudoRecSeqTest object. * @param name String. */ public WordGroebnerBasePseudoRecSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordGroebnerBasePseudoRecSeqTest.class); return suite; } GenWordPolynomialRing> fac; List>> L, G; WordGroebnerBaseAbstract> bb; WordGroebnerBaseAbstract> bbr; GenWordPolynomial> a, b, c, d, e; int rl = 2; //4; //3; int kl = 2; int ll = 3; int el = 2; @Override protected void setUp() { BigInteger coeff = new BigInteger(9); String[] cvars = new String[] { "x", "y" }; GenPolynomialRing cofac = new GenPolynomialRing(coeff, cvars); String vars = "a b"; fac = new GenWordPolynomialRing>(cofac, vars); //System.out.println("fac = " + fac.toScript()); a = b = c = d = e = null; bb = new WordGroebnerBasePseudoRecSeq(cofac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; //bb.terminate(); bb = null; } /** * Test recursive sequential GBase. */ public void testRecSequentialGBase() { L = new ArrayList>>(); a = fac.random(kl, ll, el); b = fac.random(kl, ll, el); c = fac.random(kl, ll, el); d = fac.getZERO(); //fac.random(kl, ll, el); e = c; //fac.random(kl, ll, el); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); L.add(a); //System.out.println("La = " + L ); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(b); //System.out.println("Lb = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); if (bb.commonZeroTest(L) < 0) { //System.out.println("Gb = " + L ); //d = a; L.clear(); } L.add(c); //System.out.println("Lc = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(d); //System.out.println("Ld = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println("Le = " + L ); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); } /** * Test Hawes2 GBase with commutative relations. */ @SuppressWarnings("unchecked") public void testHawes2GBase() { String exam = "IntFunc(a, c, b) (y2, y1, z1, z2, x) G" + "(" + "( x + 2 y1 z1 + { 3 a } y1^2 + 5 y1^4 + { 2 c } y1 )," + "( x + 2 y2 z2 + { 3 a } y2^2 + 5 y2^4 + { 2 c } y2 )," + "( 2 z2 + { 6 a } y2 + 20 y2^3 + { 2 c } )," + "( 3 z1^2 + y1^2 + { b } )," + "( 3 z2^2 + y2^2 + { b } )" + ")"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); PolynomialList> Fr = null; try { Fr = parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } GenPolynomialRing cofac = (GenPolynomialRing) Fr.ring.coFac; GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), cofac); GenPolynomialRing> rifac; rifac = new GenPolynomialRing>(ifac, Fr.ring); List>> Li; Li = PolyUfdUtil.integerFromRationalCoefficients(rifac, Fr.list); //System.out.println("Fr = " + Fr); fac = new GenWordPolynomialRing>(rifac); //System.out.println("fac = " + fac.toScript()); L = fac.valueOf(Li); //System.out.println("L = " + L); L.addAll(fac.commute()); //System.out.println("L = " + L); long t, i; t = System.currentTimeMillis(); G = bb.GB(L); t = System.currentTimeMillis() - t; //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); QuotientRing qi = new QuotientRing(ifac); GenPolynomialRing> iring; iring = new GenPolynomialRing>(qi, rifac); List>> Lqi; Lqi = PolyUfdUtil. quotientFromIntegralCoefficients(iring, Li); Lqi = PolyUtil.> monic(Lqi); //System.out.println("Lqi = " + Lqi); WordGroebnerBaseAbstract> bbqi; bbqi = new WordGroebnerBaseSeq>(); //qi); //System.out.println("bbqi = " + bbqi); GenWordPolynomialRing> qfac; qfac = new GenWordPolynomialRing>(iring); //System.out.println("qfac = " + qfac.toScript()); List>> Lq, Gq; Lq = qfac.valueOf(Lqi); //System.out.println("Lq = " + Lq); Lq.addAll(qfac.commute()); //System.out.println("Lq = " + Lq); i = System.currentTimeMillis(); Gq = bbqi.GB(Lq); i = System.currentTimeMillis() - i; //System.out.println("Gq = " + Gq); assertTrue("isGB( Gq )", bbqi.isGB(Gq)); //System.out.println("time: intGB = " + t + ", quotIntGB = " + i); assertTrue("nonsense", i >= t ); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/WordGroebnerBasePseudoSeqTest.java000066400000000000000000000153461445075545500275060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.gb.WordGroebnerBase; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.PolynomialList; import edu.jas.poly.WordFactory; /** * Word Groebner base sequential tests with JUnit. * @author Heinz Kredel */ public class WordGroebnerBasePseudoSeqTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordGroebnerBasePseudoSeqTest object. * @param name String. */ public WordGroebnerBasePseudoSeqTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordGroebnerBasePseudoSeqTest.class); return suite; } GenWordPolynomialRing fac; WordFactory wfac; List> L, G; PolynomialList F; WordGroebnerBase bb; GenWordPolynomial a, b, c, d, e; int kl = 3; // 10 int ll = 7; int el = 4; // 4 @Override protected void setUp() { BigInteger coeff = new BigInteger(0); wfac = new WordFactory("a"); fac = new GenWordPolynomialRing(coeff, wfac); a = b = c = d = e = null; bb = new WordGroebnerBasePseudoSeq(coeff); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; bb = null; } /** * Test sequential univariate Word GBase. */ public void testSequentialGBase() { L = new ArrayList>(); a = fac.random(kl, ll, el); b = fac.random(kl, ll, el); c = fac.random(kl, ll, el); d = fac.random(kl, ll, el); e = d; //fac.random(kl, ll, el); while (a.isZERO()) { a = fac.random(kl, ll, el); } while (b.isZERO()) { b = fac.random(kl, ll, el); } while (c.isZERO()) { c = fac.random(kl, ll, el); } while (d.isZERO()) { d = fac.random(kl, ll, el); } L.add(a); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a } )", bb.isGB(L)); L.add(a.multiply(b)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b } )", bb.isGB(L)); L.add(a.multiply(c)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c } )", bb.isGB(L)); L.add(a.multiply(d)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); L.add(e); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d, e } )", bb.isGB(L)); L.clear(); L.add(a); L.add(a.multiply(b)); L.add(a.multiply(c)); L.add(a.multiply(d)); //System.out.println("L = " + L); L = bb.GB(L); assertTrue("isGB( { a, b, c, d } )", bb.isGB(L)); } /** * Test example 1 word GBase. */ @SuppressWarnings("unchecked") public void testExample1GBase() { String exam = "(x,y,z) L " + "( " + "( z y**2 + 2 x + 1/2 )" + "( z x**2 - y**2 - 1/2 x )" + "( -z + y**2 x + 4 x**2 + 1/4 )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); } /** * Test Trinks7 as non-commutative example word GBase. */ @SuppressWarnings("unchecked") public void testTrinks7GBase() { String exam = "(B,S,T,Z,P,W) L " + "( " + "( 45 P + 35 S - 165 B - 36 ), " + "( 35 P + 40 Z + 25 T - 27 S ), " + "( 15 W + 25 S P + 30 Z - 18 T - 165 B**2 ), " + "( - 9 W + 15 T P + 20 S Z ), " + "( P W + 2 T Z - 11 B**3 ), " + "( 99 W - 11 B S + 3 B**2 ), " + "( B**2 + 33/50 B + 2673/10000 ) " // is needed + ") "; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); L.addAll(fac.commute()); // add commute relations for all variables G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); assertTrue("#G == 6", G.size() == 6); } /** * Test example 3 word GBase. */ @SuppressWarnings("unchecked") public void testExample2GBase() { String exam = "(x,y,z) L " + "( " + "( x y - z )" // will not be correct when converted to non-com + "( y z + 2 x + z )" + "( y z + x )" + " )"; Reader source = new StringReader(exam); GenPolynomialTokenizer parser = new GenPolynomialTokenizer(source); try { F = (PolynomialList) parser.nextPolynomialSet(); } catch (ClassCastException e) { fail("" + e); } catch (IOException e) { fail("" + e); } //System.out.println("F = " + F); fac = new GenWordPolynomialRing(F.ring); //System.out.println("fac = " + fac); L = fac.valueOf(F.list); //System.out.println("L = " + L); G = bb.GB(L); //System.out.println("G = " + G); assertTrue("isGB( G )", bb.isGB(G)); } } java-algebra-system-2.7.200/trc/edu/jas/gbufd/WordPseudoReductionTest.java000066400000000000000000000215061445075545500264260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.gbufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.poly.GenWordPolynomial; import edu.jas.poly.GenWordPolynomialRing; import edu.jas.poly.Overlap; import edu.jas.poly.OverlapList; import edu.jas.poly.Word; import edu.jas.poly.WordFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Word reduction tests with JUnit. * @author Heinz Kredel */ public class WordPseudoReductionTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordPseudoReductionTest object. * @param name String */ public WordPseudoReductionTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(WordPseudoReductionTest.class); return suite; } GenWordPolynomialRing fac; WordFactory wfac; BigInteger cfac; GenWordPolynomial a, b, c, d, e; List> L; WordPseudoReductionSeq red; int kl = 3; int ll = 7; int el = 5; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigInteger(0); wfac = new WordFactory("abcdef"); fac = new GenWordPolynomialRing(cfac, wfac); red = new WordPseudoReductionSeq(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; red = null; } /** * Test constants and empty list reduction. */ public void testIntReduction0() { L = new ArrayList>(); a = fac.random(kl, ll, el); c = fac.getONE(); d = fac.getZERO(); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L.add(c); e = red.normalform(L, c); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, a); assertTrue("isZERO( e )", e.isZERO()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); L = new ArrayList>(); L.add(d); e = red.normalform(L, c); assertTrue("isONE( e )", e.isONE()); e = red.normalform(L, d); assertTrue("isZERO( e )", e.isZERO()); } /** * Test rational coefficient reduction. */ public void testIntReduction() { do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); L = new ArrayList>(); L.add(a); e = red.normalform(L, a); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO()); L.add(b); e = red.normalform(L, a); //System.out.println("e = " + e); assertTrue("isZERO( e ) some times", e.isZERO()); L = new ArrayList>(); L.add(a); assertTrue("isTopRed( a )", red.isTopReducible(L, a)); assertTrue("isRed( a )", red.isReducible(L, a)); L.add(b); assertTrue("isTopRed( b )", red.isTopReducible(L, b)); assertTrue("isRed( b )", red.isReducible(L, b)); c = fac.random(kl, ll, el); //System.out.println("c = " + c); e = red.normalform(L, c); //System.out.println("e = " + e); assertTrue("isNF( e ) " + e, red.isNormalform(L, e)); Word u = new Word(wfac, "f"); Word v = new Word(wfac, "abc"); c = a.multiply(cfac.getONE(), u, v); //System.out.println("c = " + c); e = red.normalform(L, c); //System.out.println("e = " + e); assertTrue("isNF( e ) " + e, red.isNormalform(L, e)); assertTrue("e == 0 " + e, e.isZERO()); } /** * Test rational coefficient reduction with recording. */ public void testIntReductionRecording() { List> lrow, rrow = null; do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); c = fac.random(kl, ll, el); d = fac.random(kl, ll, el); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); L = new ArrayList>(); L.add(a); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, a); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("isZERO( e ) " + e, e.isZERO()); assertTrue("is Reduction ", red.isReductionNF(lrow, rrow, L, a, e)); L.add(b); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, b); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("isReduction " + e + " of " + b, red.isReductionNF(lrow, rrow, L, b, e)); L.add(c); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } e = red.normalform(lrow, rrow, L, c); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction " + e + " of " + c, red.isReductionNF(lrow, rrow, L, c, e)); L.add(d); lrow = new ArrayList>(L.size()); rrow = new ArrayList>(L.size()); e = fac.getZERO(); for (int m = 0; m < L.size(); m++) { lrow.add(e); rrow.add(e); } Word u = new Word(wfac, "f"); Word v = new Word(wfac, "abc"); d = a.multiply(cfac.random(3), u, v); //System.out.println("d = " + d); e = red.normalform(lrow, rrow, L, d); //System.out.println("e = " + e); //System.out.println("lrow = " + lrow); //System.out.println("rrow = " + rrow); assertTrue("is Reduction " + e + " of " + d, red.isReductionNF(lrow, rrow, L, d, e)); } /** * Test rational S-polynomial. */ public void testIntSpolynomial() { do { a = fac.random(kl, ll, el); } while (a.isZERO()); do { b = fac.random(kl, ll, el); } while (b.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); Word de = new Word(wfac, "a"); a = a.multiply(wfac.getONE(), de); b = b.multiply(de, wfac.getONE()); //System.out.println("a = " + a); //System.out.println("b = " + b); Word ae = a.leadingWord(); Word be = b.leadingWord(); //System.out.println("ae = " + ae); //System.out.println("be = " + be); List> S = red.SPolynomials(a, b); //System.out.println("S = " + S); OverlapList oll = ae.overlap(be); //System.out.println("oll = " + oll); for (GenWordPolynomial s : S) { //System.out.println("s = " + s); Word ee = s.leadingWord(); //System.out.println("ee = " + ee); boolean t = false; Word ce = fac.alphabet.getONE(); for (Overlap ol : oll.ols) { ce = ol.l1.multiply(ae).multiply(ol.r1); //System.out.println("ce = " + ce); if (fac.alphabet.getAscendComparator().compare(ce, ee) > 0) { t = true; break; } } assertTrue("ce > ee: " + ce + " > " + ee, t); // findbugs } } } java-algebra-system-2.7.200/trc/edu/jas/integrate/000077500000000000000000000000001445075545500216425ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/integrate/ElementaryIntegrationAbsoluteTest.java000066400000000000000000000061421445075545500313600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Elementary integration Bernoulli algorithm with linear factors with JUnit. * @author Heinz Kredel */ public class ElementaryIntegrationAbsoluteTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ElementaryIntegrationAbsoluteTest object. * @param name String. */ public ElementaryIntegrationAbsoluteTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ElementaryIntegrationAbsoluteTest.class); return suite; } TermOrder tord; QuotientRing qfac; GenPolynomialRing pfac; ElementaryIntegration integrator; QuotIntegral rint; @Override protected void setUp() { tord = new TermOrder(TermOrder.INVLEX); BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; pfac = new GenPolynomialRing(br, 1, tord, vars); qfac = new QuotientRing(pfac); integrator = new ElementaryIntegrationBernoulli(br); } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test Bernoulli algorithm. */ public void testRationalBernoulli() { GenPolynomial agen = pfac.univariate(0, 4); agen = agen.sum(pfac.fromInteger(4)); // x^4 + 4 // GenPolynomial x6 = pfac.univariate(0, 6); // GenPolynomial x4 = pfac.univariate(0, 4); // GenPolynomial x2 = pfac.univariate(0, 2); // // x^6 - 5 x^4 + 5 x^2 + 4 // agen = x6.subtract(x4.multiply(pfac.fromInteger(5))); // agen = agen.sum(x2.multiply(pfac.fromInteger(5))); // agen = agen.sum(pfac.fromInteger(4)); // GenPolynomial x3 = pfac.univariate(0, 3); // GenPolynomial x = pfac.univariate(0); // // x^3 + x // agen = x3.sum(x); // GenPolynomial x2 = pfac.univariate(0, 2); // // x^2 - 2 // agen = x2.subtract(pfac.fromInteger(2)); GenPolynomial N = pfac.getONE(); Quotient Q = new Quotient(qfac, N, agen); rint = integrator.integrate(Q); //System.out.println("\nquot integral: " + rint.toString()); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/integrate/ElementaryIntegrationCzichowskiTest.java000066400000000000000000000264061445075545500317240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient over BigRational GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class ElementaryIntegrationCzichowskiTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ElementaryIntegrationCzichowskiTest object. * @param name String. */ public ElementaryIntegrationCzichowskiTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ElementaryIntegrationCzichowskiTest.class); return suite; } TermOrder tord; QuotientRing qfac; GenPolynomialRing mfac; ElementaryIntegration integrator; QuotIntegral rint; Quotient a, b, c, d, e; int rl = 1; // only univariate polynomials int kl = 5; int ll = 3; //6; int el = 4; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; tord = new TermOrder(TermOrder.INVLEX); BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; mfac = new GenPolynomialRing(br, rl, tord, vars); qfac = new QuotientRing(mfac); integrator = new ElementaryIntegrationCzichowski(br); } @Override protected void tearDown() { a = b = c = d = e = null; //qfac.terminate(); qfac = null; ComputerThreads.terminate(); } /** * Test rational integral. */ public void testRational() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test 1/p pure logarithm integral. */ public void testPureLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test p'/p pure logarithm integral. * */ public void testPureLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } GenPolynomial pp = PolyUtil. baseDerivative(a.den); b = new Quotient(qfac, pp, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with p'/p logarithm integral. */ public void testRationalWithLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); e = b.sum(c); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with 1/p logarithm integral. */ public void xtestRationalWithLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with p'/p + 1/p logarithm integral. * */ public void testRationalWithLogarithm() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(c).sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test rational integral with quotient coefficients. */ public void testRationalRecursive() { QuotientRing> qqfac; GenPolynomialRing> qmfac; ElementaryIntegration> qintegrator; QuotIntegral> qrint; String[] vars = new String[] { "y" }; qmfac = new GenPolynomialRing>(qfac, 1, tord, vars); qqfac = new QuotientRing>(qmfac); qintegrator = new ElementaryIntegration>(qfac); Quotient> qa, qb; for (int i = 0; i < 2; i++) { qa = qqfac.random(2, ll, el, q); //System.out.println("qa = " + qa); // if ( a.isZERO() || a.isONE() ) { // continue; // } qb = qintegrator.derivative(qa); //System.out.println("qb = " + qb); qrint = qintegrator.integrate(qb); //System.out.println("QuotIntegral: " + qrint); assertTrue("isIntegral ", qintegrator.isIntegral(qrint)); assertFalse("qrint not empty: " + qrint, qrint.toString().isEmpty()); assertTrue("qrint contains: " + qrint, qrint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational integral. */ public void testMixedRational() { //integrate( (3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)/(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4), x) BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); QuotientRing qfac = new QuotientRing(pfac); GenPolynomial n = pfac.parse( "(3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)"); GenPolynomial d = pfac.parse( "(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4)"); //System.out.println("n = " + n); //System.out.println("d = " + d); Quotient a = new Quotient(qfac, n, d); //System.out.println("a = " + a); QuotIntegral rint = integrator.integrate(a); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); Quotient b = qfac.parse( "{ 3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2 | 4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4 }"); //System.out.println("b = " + b); assertEquals("a == b: ", a, b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/integrate/ElementaryIntegrationLazardTest.java000066400000000000000000000241331445075545500310170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient over BigRational GenPolynomial tests with JUnit. Test Lazard Rioboo * algorithm. * @author Heinz Kredel */ public class ElementaryIntegrationLazardTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ElementaryIntegrationLazardTest object. * @param name String. */ public ElementaryIntegrationLazardTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ElementaryIntegrationLazardTest.class); return suite; } //private final static int bitlen = 100; TermOrder tord; QuotientRing qfac; GenPolynomialRing mfac; ElementaryIntegration integrator; QuotIntegral rint; Quotient a; Quotient b; Quotient c; Quotient d; Quotient e; int rl = 1; // only univariate polynomials int kl = 5; int ll = 3; //6; int el = 4; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; tord = new TermOrder(TermOrder.INVLEX); BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; mfac = new GenPolynomialRing(br, rl, tord, vars); qfac = new QuotientRing(mfac); integrator = new ElementaryIntegrationLazard(br); } @Override protected void tearDown() { a = b = c = d = e = null; //qfac.terminate(); qfac = null; ComputerThreads.terminate(); } /** * Test rational integral. */ public void testRational() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test 1/p pure logarithm integral. */ public void testPureLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test p'/p pure logarithm integral. * */ public void testPureLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } GenPolynomial pp = PolyUtil. baseDerivative(a.den); b = new Quotient(qfac, pp, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test mixed rational with p'/p logarithm integral. */ public void testRationalWithLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); e = b.sum(c); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test mixed rational with 1/p logarithm integral. */ public void xtestRationalWithLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test mixed rational with p'/p + 1/p logarithm integral. * */ public void testRationalWithLogarithm() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(c).sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } /** * Test rational integral with quotient coefficients. */ public void testRationalRecursive() { QuotientRing> qqfac; GenPolynomialRing> qmfac; ElementaryIntegration> qintegrator; QuotIntegral> qrint; String[] vars = new String[] { "y" }; qmfac = new GenPolynomialRing>(qfac, 1, tord, vars); qqfac = new QuotientRing>(qmfac); qintegrator = new ElementaryIntegration>(qfac); Quotient> qa, qb; for (int i = 0; i < 2; i++) { qa = qqfac.random(2, ll, el, q); //System.out.println("qa = " + qa); // if ( a.isZERO() || a.isONE() ) { // continue; // } qb = qintegrator.derivative(qa); //System.out.println("qb = " + qb); qrint = qintegrator.integrate(qb); //System.out.println("QuotIntegral: " + qrint); assertTrue("isIntegral ", qintegrator.isIntegral(qrint)); } } /** * Test mixed rational integral. */ public void testMixedRational() { //integrate( (3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)/(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4), x) BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); QuotientRing qfac = new QuotientRing(pfac); GenPolynomial n = pfac.parse( "(3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)"); GenPolynomial d = pfac.parse( "(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4)"); //System.out.println("n = " + n); //System.out.println("d = " + d); Quotient a = new Quotient(qfac, n, d); //System.out.println("a = " + a); QuotIntegral rint = integrator.integrate(a); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); Quotient b = qfac.parse( "{ 3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2 | 4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4 }"); //System.out.println("b = " + b); assertEquals("a == b: ", a, b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); } } java-algebra-system-2.7.200/trc/edu/jas/integrate/ElementaryIntegrationTest.java000066400000000000000000000263161445075545500276660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.integrate; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.ufd.Quotient; import edu.jas.ufd.QuotientRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient over BigRational GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class ElementaryIntegrationTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ElementaryIntegrationTest object. * @param name String. */ public ElementaryIntegrationTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ElementaryIntegrationTest.class); return suite; } TermOrder tord; QuotientRing qfac; GenPolynomialRing mfac; ElementaryIntegration integrator; QuotIntegral rint; Quotient a, b, c, d, e; int rl = 1; // only univariate polynomials int kl = 5; int ll = 3; //6; int el = 4; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; tord = new TermOrder(TermOrder.INVLEX); BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; mfac = new GenPolynomialRing(br, rl, tord, vars); qfac = new QuotientRing(mfac); integrator = new ElementaryIntegration(br); } @Override protected void tearDown() { a = b = c = d = e = null; //qfac.terminate(); qfac = null; ComputerThreads.terminate(); } /** * Test rational integral. */ public void testRational() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + 2 * i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test 1/p pure logarithm integral. */ public void testPureLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test p'/p pure logarithm integral. */ public void testPureLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } GenPolynomial pp = PolyUtil. baseDerivative(a.den); b = new Quotient(qfac, pp, a.den); //System.out.println("b = " + b); rint = integrator.integrate(b); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with p'/p logarithm integral. */ public void testRationalWithLogarithmD() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); e = b.sum(c); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with 1/p logarithm integral. */ public void xtestRationalWithLogarithm1() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational with p'/p + 1/p logarithm integral. */ public void testRationalWithLogarithm() { for (int i = 0; i < 3; i++) { a = qfac.random(kl, ll + i, el + i, q); //System.out.println("a = " + a); // if ( a.isZERO() || a.isONE() ) { // continue; // } b = integrator.derivative(a); //System.out.println("b = " + b); GenPolynomial pp = PolyUtil. baseDerivative(a.den); c = new Quotient(qfac, pp, a.den); //System.out.println("c = " + c); d = new Quotient(qfac, qfac.getONE().num, a.den); //System.out.println("d = " + d); e = b.sum(c).sum(d); //System.out.println("e = " + e); rint = integrator.integrate(e); //System.out.println("QuotIntegral: " + rint); assertTrue("isIntegral ", integrator.isIntegral(rint)); assertFalse("rint not empty: " + rint, rint.toString().isEmpty()); assertTrue("rint contains: " + rint, rint.toString().indexOf("integral") >= 0); } } /** * Test rational integral with quotient coefficients. */ public void testRationalRecursive() { QuotientRing> qqfac; GenPolynomialRing> qmfac; ElementaryIntegration> qintegrator; QuotIntegral> qrint; String[] vars = new String[] { "y" }; qmfac = new GenPolynomialRing>(qfac, 1, tord, vars); qqfac = new QuotientRing>(qmfac); qintegrator = new ElementaryIntegration>(qfac); Quotient> qa, qb; for (int i = 0; i < 2; i++) { qa = qqfac.random(2, ll, el, q); //System.out.println("qa = " + qa); // if ( a.isZERO() || a.isONE() ) { // continue; // } qb = qintegrator.derivative(qa); //System.out.println("qb = " + qb); qrint = qintegrator.integrate(qb); //System.out.println("QuotIntegral: " + qrint); assertTrue("isIntegral ", qintegrator.isIntegral(qrint)); assertFalse("rint not empty: " + qrint, qrint.toString().isEmpty()); assertTrue("rint contains: " + qrint, qrint.toString().indexOf("integral") >= 0); } } /** * Test mixed rational integral. */ public void testMixedRational() { //integrate( (3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)/(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4), x) BigRational br = new BigRational(1); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(br, vars); QuotientRing qfac = new QuotientRing(pfac); GenPolynomial n = pfac.parse( "(3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2)"); GenPolynomial d = pfac.parse( "(4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4)"); //System.out.println("n = " + n); //System.out.println("d = " + d); Quotient a = new Quotient(qfac, n, d); //System.out.println("a = " + a); QuotIntegral qrint = integrator.integrate(a); //System.out.println("QuotIntegral: " + qrint); assertTrue("isIntegral ", integrator.isIntegral(qrint)); Quotient b = qfac.parse( "{ 3*x^16-19*x^15+43*x^14-20*x^13-91*x^12+183*x^11-81*x^10-166*x^9+271*x^8-101*x^7-127*x^6+168*x^5-53*x^4-31*x^3+41*x^2-2*x-2 | 4*x^14-20*x^13+28*x^12+24*x^11-108*x^10+84*x^9+76*x^8-176*x^7+76*x^6+84*x^5-108*x^4+24*x^3+28*x^2-20*x+4 }"); //System.out.println("b = " + b); assertEquals("a == b: ", a, b); qrint = integrator.integrate(b); //System.out.println("QuotIntegral: " + qrint); assertTrue("isIntegral ", integrator.isIntegral(qrint)); assertFalse("qrint not empty: " + qrint, qrint.toString().isEmpty()); assertTrue("qrint contains: " + qrint, qrint.toString().indexOf("integral") >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/kern/000077500000000000000000000000001445075545500206175ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/kern/KernUtilTest.java000066400000000000000000000054771445075545500240740ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.io.StringReader; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * KernUtil tests with JUnit. * @author Heinz Kredel */ public class KernUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a KernUtilTest object. * @param name String. */ public KernUtilTest(String name) { super(name); } /* */ public static Test suite() { TestSuite suite = new TestSuite(KernUtilTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test StringUtil. */ public void testStringUtil() { StringReader sr = new StringReader(" ein text - noch ein / text { wort } [1, 2, 3] [[1, 4], [2], [3, 5]]"); String s = StringUtil.nextString(sr); //System.out.println(":" + s + ":"); assertEquals("s==ein", s, "ein"); s = StringUtil.nextString(sr); //System.out.println(":" + s + ":"); assertEquals("s==text", s, "text"); s = StringUtil.nextString(sr,'/'); //System.out.println(":" + s + ":"); assertEquals("s== - noch ein ", s, "- noch ein"); try { s = StringUtil.nextPairedString(sr,'#','#'); fail("exception not thrown"); } catch (IllegalArgumentException e) { // pass } s = StringUtil.nextPairedString(sr,'{','}'); //System.out.println(":" + s + ":"); assertEquals("s==wort", s, "wort"); s = StringUtil.nextPairedString(sr,'[',']'); //System.out.println(":" + s + ":"); assertEquals("s==1, 2, 3", s, "1, 2, 3"); s = StringUtil.nextPairedString(sr,'[',']'); //System.out.println(":" + s + ":"); assertEquals("s==[1, 4], [2], [3, 5]", s, "[1, 4], [2], [3, 5]"); } /** * Test stack trace. */ public void testStackTrace() { String s = StringUtil.selectStackTrace(".*KernUtilTest.*"); //System.out.println(":" + s + ":"); assertTrue("s contains KernUtilTest", s.indexOf("KernUtilTest") >= 0); } /** * Test default scripting flags. */ public void testScripting() { Scripting.Lang s = Scripting.getLang(); //System.out.println(":" + s + ":"); assertEquals("s == Python", s, Scripting.Lang.Python); Scripting.CAS c = Scripting.getCAS(); //System.out.println(":" + c + ":"); assertEquals("c == JAS", c, Scripting.CAS.JAS); int p = Scripting.getPrecision(); //System.out.println(":" + p + ":"); assertTrue("p < 0", p < 0); } } java-algebra-system-2.7.200/trc/edu/jas/kern/LocalTimeStatusTest.java000066400000000000000000000070421445075545500254020ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.concurrent.Callable; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * LocalTimeStatus tests with JUnit. * @author Heinz Kredel */ public class LocalTimeStatusTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a LocalTimeStatusTest object. * @param name String. */ public LocalTimeStatusTest(String name) { super(name); } /* */ public static Test suite() { TestSuite suite = new TestSuite(LocalTimeStatusTest.class); return suite; } LocalTimeStatus lt1, lt2; @Override protected void setUp() { lt1 = new LocalTimeStatus(); lt2 = new LocalTimeStatus(true, 0, true); } @Override protected void tearDown() { lt1.setNotActive(); lt1.setLimit(Long.MAX_VALUE); lt1.setCallBack((Callable) null); lt2 = null; } /** * Tests checkTime. */ public void testCheckTime() { //System.out.println("lt1 = " + lt1); //System.out.println("lt2 = " + lt2); lt1.setActive(); assertTrue("is active lt1", lt1.isActive()); assertTrue("is active lt2", lt2.isActive()); lt1.restart(); try { lt1.checkTime("test1"); lt2.checkTime("test1-2"); // succeed } catch (TimeExceededException e) { fail("test1 " + e); } lt1.setLimit(0L); assertTrue("is active lt1", lt1.isActive()); try { Thread.sleep(10); lt1.checkTime("test2"); lt2.checkTime("test2-2"); fail("test2 checkTime 1|2"); } catch (TimeExceededException e) { // succeed } catch (InterruptedException e) { fail("test2 interrupt"); } //System.out.println("lt1 = " + lt1); //System.out.println("lt2 = " + lt2); } /** * Tests call back. */ public void testCallBack() { //System.out.println("lt1 = " + lt1); //System.out.println("lt2 = " + lt2); lt1.setActive(); lt1.restart(); lt1.setLimit(0L); lt1.setCallBack(new LocalTimeStatus.TSCall(true)); assertTrue("is active lt1", lt1.isActive()); assertTrue("is active lt2", lt2.isActive()); try { Thread.sleep(10); lt1.checkTime("test3"); lt2.checkTime("test3-2"); // succeed } catch (TimeExceededException e) { fail("test3 checkTime"); } catch (InterruptedException e) { fail("test3 interrupt"); } lt1.setCallBack(new LocalTimeStatus.TSCall(false)); try { Thread.sleep(10); lt1.checkTime("test4"); fail("test4 checkTime"); } catch (TimeExceededException e) { // succeed } catch (InterruptedException e) { fail("test4 interrupt"); } lt2.setCallBack(new LocalTimeStatus.TSCall(false)); try { Thread.sleep(10); lt2.checkTime("test4-2"); fail("test4 checkTime"); } catch (TimeExceededException e) { // succeed } catch (InterruptedException e) { fail("test4 interrupt"); } //System.out.println("lt1 = " + lt1); //System.out.println("lt2 = " + lt2); } } java-algebra-system-2.7.200/trc/edu/jas/kern/TimeStatusTest.java000066400000000000000000000051101445075545500244210ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.kern; import java.util.concurrent.Callable; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TimeStatus tests with JUnit. * @author Heinz Kredel */ public class TimeStatusTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a TimeStatusTest object. * @param name String. */ public TimeStatusTest(String name) { super(name); } /* */ public static Test suite() { TestSuite suite = new TestSuite(TimeStatusTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { TimeStatus.setNotActive(); TimeStatus.setLimit(Long.MAX_VALUE); TimeStatus.setCallBack((Callable) null); } /** * Tests checkTime. */ public void testCheckTime() { TimeStatus.setActive(); assertTrue("is active ", TimeStatus.isActive()); TimeStatus.restart(); try { TimeStatus.checkTime("test1"); // succeed } catch (TimeExceededException e) { fail("test1 " + e); } TimeStatus.setLimit(0L); assertTrue("is active ", TimeStatus.isActive()); try { Thread.sleep(10); TimeStatus.checkTime("test2"); fail("test2 checkTime"); } catch (TimeExceededException e) { // succeed } catch (InterruptedException e) { fail("test2 interrupt"); } } /** * Tests call back. */ public void testCallBack() { TimeStatus.setActive(); TimeStatus.restart(); TimeStatus.setLimit(0L); TimeStatus.setCallBack(new TimeStatus.TSCall(true)); assertTrue("is active ", TimeStatus.isActive()); try { Thread.sleep(10); TimeStatus.checkTime("test3"); // succeed } catch (TimeExceededException e) { fail("test3 checkTime"); } catch (InterruptedException e) { fail("test3 interrupt"); } TimeStatus.setCallBack(new TimeStatus.TSCall(false)); try { Thread.sleep(10); TimeStatus.checkTime("test4"); fail("test4 checkTime"); } catch (TimeExceededException e) { // succeed } catch (InterruptedException e) { fail("test4 interrupt"); } } } java-algebra-system-2.7.200/trc/edu/jas/poly/000077500000000000000000000000001445075545500206435ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/poly/ANumGenPolynomialTest.java000066400000000000000000000223501445075545500257060ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * AlgebraicNumber coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class ANumGenPolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ANumGenPolynomialTest object. * @param name String. */ public ANumGenPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ANumGenPolynomialTest.class); return suite; } GenPolynomialRing> fac; AlgebraicNumberRing cfac; GenPolynomial> a, b, c, d, e; int rl = 3; int kl = 10; int ll = 5; int el = 5; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; BigRational r = new BigRational(1); // univariate minimal polynomial GenPolynomialRing mfac = new GenPolynomialRing(r, 1); GenPolynomial modul = mfac.random(3); while (modul.isZERO() || modul.isUnit() || modul.isConstant()) { modul = mfac.random(3); } modul = modul.sum(mfac.fromInteger(3L)); cfac = new AlgebraicNumberRing(modul.monic()); fac = new GenPolynomialRing>(cfac, rl); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor //and toString */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )c" + c, !c.isZERO()); assertTrue("isONE( c ) " + c, c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll + i); //System.out.println("a = " + a); //fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(ll); ExpVector u = ExpVector.random(rl, el, q); AlgebraicNumber x = cfac.random(kl); b = new GenPolynomial>(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial>(fac); b = new GenPolynomial>(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0-(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); AlgebraicNumber z = a.leadingBaseCoefficient(); //System.out.println("z = " + z); if (z.isUnit()) { AlgebraicNumber x = z.inverse(); //System.out.println("x = " + x); //System.out.println("a = " + a); c = a.monic(); //System.out.println("c = " + c); d = a.multiply(x); //System.out.println("d = " + d); assertEquals("a.monic() = a(1/ldcf(a))", c, d); } AlgebraicNumber y = b.leadingBaseCoefficient(); if (y.isUnit()) { y = y.inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = new GenPolynomial>(fac, y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b))*b", c, d); } } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test object quotient and remainder. */ public void testQuotRem1() { fac = new GenPolynomialRing>(cfac, 1); a = fac.random(2); //.monic(); if (a.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(2); //.monic(); if (b.isZERO()) { return; } assertTrue("not isZERO( b )", !b.isZERO()); GenPolynomial> g = fac.random(1).monic(); if (g.isZERO()) { return; } assertTrue("not isZERO( g )", !g.isZERO()); //g = fac.getONE(); a = a.multiply(g); b = b.multiply(g); //System.out.println("ta = " + a); //System.out.println("tb = " + b); //System.out.println("tg = " + g); GenPolynomial>[] qr; qr = b.quotientRemainder(a); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(a).sum(d); assertEquals("b = q a + r", b, e); qr = a.quotientRemainder(b); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(b).sum(d); assertEquals("a = q b + r", a, e); // gcd tests ------------------------------- c = a.gcd(b); //System.out.println("gcd = " + c); assertTrue("a mod gcd(a,b) = 0", a.remainder(c).isZERO()); assertTrue("b mod gcd(a,b) = 0", b.remainder(c).isZERO()); //assertEquals("g = gcd(a,b)", c, g ); GenPolynomial>[] gst; gst = a.egcd(b); //System.out.println("egcd = " + gst[0]); //System.out.println(", s = " + gst[1] + ", t = " + gst[2]); c = gst[0]; d = gst[1]; e = gst[2]; assertTrue("a mod gcd(a,b) = 0", a.remainder(c).isZERO()); assertTrue("b mod gcd(a,b) = 0", b.remainder(c).isZERO()); //assertEquals("g = gcd(a,b)", c, g ); GenPolynomial> x; x = a.multiply(d).sum(b.multiply(e)).monic(); //System.out.println("x = " + x); assertEquals("gcd(a,b) = a s + b t", c, x); //System.out.println("a = " + a); //System.out.println("b = " + b); if (a.isZERO() || b.isZERO()) { return; } try { c = a.modInverse(b); //System.out.println("c = " + c); x = c.multiply(a).remainder(b).monic(); //System.out.println("x = " + x); assertTrue("a invertible mod b " + x, x.isUnit()); } catch (RuntimeException e) { // dann halt nicht // not invertible } } } java-algebra-system-2.7.200/trc/edu/jas/poly/AlgebraicNumberModTest.java000066400000000000000000000165271445075545500260430ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Iterator; import java.util.Set; import java.util.HashSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.structure.Power; import edu.jas.structure.NotInvertibleException; import edu.jas.poly.GenPolynomial; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; /** * AlgebraicNumber modular Test using JUnit. * @author Heinz Kredel */ public class AlgebraicNumberModTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a AlgebraicNumberModTest object. * @param name String. */ public AlgebraicNumberModTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(AlgebraicNumberModTest.class); return suite; } long p = 19; long qp = p; ModIntegerRing mpfac; AlgebraicNumberRing fac; GenPolynomialRing mfac; AlgebraicNumber< ModInteger > a, b, c, d, e; int rl = 1; int kl = 10; int ll = 10; int el = ll; float q = 0.5f; protected void setUp() { a = b = c = d = e = null; mpfac = new ModIntegerRing(p,true); String[] vars = new String[] { "i" }; mfac = new GenPolynomialRing( mpfac, rl, vars ); // GenPolynomial mo = mfac.random(kl,ll,el,q); // while ( mo.isConstant() ) { // mo = mfac.random(kl,ll,el,q); // } GenPolynomial mo = mfac.univariate(0,2); mo = mo.sum( mfac.getONE() ); // x^2 + 1 fac = new AlgebraicNumberRing( mo, true ); qp = 1L; for ( int i = 0; i < mo.degree(0); i++ ) { qp = qp * p; } //System.out.println("p = " + p + ", qp = " + qp); } protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); assertTrue("length( c ) = 1", c.getVal().length() == 1); assertTrue("isZERO( c )", !c.isZERO() ); assertTrue("isONE( c )", c.isONE() ); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); assertTrue("length( d ) = 0", d.getVal().length() == 0); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(el); //System.out.println("a = " + a); if ( a.isZERO() || a.isONE() ) { continue; } //fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a"+i+" ) <> 0", a.getVal().length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a",c,d); c = fac.random(ll); d = c.sum( a.sum(b) ); e = c.sum( a ).sum(b); assertEquals("c+(a+b) = (c+a)+b",d,e); c = a.sum( fac.getZERO() ); d = a.subtract( fac.getZERO() ); assertEquals("a+0 = a-0",c,d); c = fac.getZERO().sum( a ); d = fac.getZERO().subtract( a.negate() ); assertEquals("0+a = 0+(-a)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); b = fac.random(ll); if ( a.isZERO() || b.isZERO() ) { return; } assertTrue("not isZERO( a )", !a.isZERO() ); assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); c = a.multiply( fac.getONE() ); d = fac.getONE().multiply( a ); assertEquals("a*1 = 1*a",c,d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1",fac.getONE(),d); try { a = fac.getZERO().inverse(); } catch(NotInvertibleException expected) { return; } fail("0 invertible"); } /** * Test distributive law. */ public void testDistributive() { a = fac.random( ll ); b = fac.random( ll ); c = fac.random( ll ); d = a.multiply( b.sum(c) ); e = a.multiply( b ).sum( a.multiply(c) ); assertEquals("a(b+c) = ab+ac",d,e); } /** * Test object potentiation. */ public void testCharPower() { //System.out.println("fac = " + fac); a = fac.random(6); if ( a.isZERO() ) { return; } assertTrue("not isZERO( a )", !a.isZERO() ); b = Power.> positivePower(a, qp); assertTrue("not isZERO( b )", !b.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.subtract(b); //System.out.println("c = " + c); assertTrue("isZERO( a^(p^n) - a ) " + c, c.isZERO() ); } /** * Test enumerator. */ public void testEnumerator() { long s = 1L; for ( int i = 0; i < (int)fac.modul.degree(0); i++ ) { s = s * p; } //System.out.println("s = " + s); long t = 0L; Set> elems = new HashSet>(49); //Iterator> iter = fac.iterator(); for ( AlgebraicNumber an : fac ) { t++; //System.out.println("an = " + an); elems.add(an); } //System.out.println("elems = " + elems); assertTrue("#elems " + s + ", t = " + t, s == t ); assertTrue("#elems " + s + ", t = " + elems.size(), s == elems.size() ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/AlgebraicNumberTest.java000066400000000000000000000210701445075545500253700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.HashSet; import java.util.Set; import edu.jas.arith.BigRational; // import edu.jas.structure.RingElem; import edu.jas.structure.NotInvertibleException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * AlgebraicNumber Test using JUnit. * @author Heinz Kredel */ public class AlgebraicNumberTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a AlgebraicNumberTest object. * @param name String. */ public AlgebraicNumberTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(AlgebraicNumberTest.class); return suite; } //private final static int bitlen = 100; AlgebraicNumberRing fac; GenPolynomialRing mfac; AlgebraicNumber a, b, c, d, e; int rl = 1; int kl = 10; int ll = 7; int el = ll; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; BigRational bi = new BigRational(1); //bi.setAllIterator(); bi.setNoDuplicatesIterator(); mfac = new GenPolynomialRing(bi, rl); GenPolynomial mo = mfac.random(kl, ll, 7, q); while (mo.isConstant()) { mo = mfac.random(kl, ll, 5, q); } fac = new AlgebraicNumberRing(mo.monic()); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); assertTrue("length( c ) = 1", c.getVal().length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); assertTrue("length( d ) = 0", d.getVal().length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(el); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } //fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.getVal().length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0-(-a)", c, d); } /** * Test object multiplication. */ @SuppressWarnings({ "unchecked", "cast" }) public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1", fac.getONE(), d); try { d = fac.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { // ok } GenPolynomial dp = fac.modul; GenPolynomial cp = fac.modul.multiply(a.val.monic()); //System.out.println("dp = " + dp); //System.out.println("cp = " + cp); fac = new AlgebraicNumberRing(cp); a = new AlgebraicNumber(fac, a.val.monic()); assertFalse("a !unit mod m*a: " + a, a.isUnit() && !a.isONE()); try { b = a.inverse(); if (!a.isONE()) { fail("invertible " + a); } } catch (AlgebraicNotInvertibleException expected) { //ok //expected.printStackTrace(); //System.out.println("expected = " + expected); GenPolynomial f1 = (GenPolynomial) expected.f1; GenPolynomial f2 = (GenPolynomial) expected.f2; assertTrue("f = " + cp, expected.f.equals(cp)); assertTrue("f1 = " + a.val, f1.equals(a.val)); assertTrue("f2 = " + dp, f2.equals(dp)); assertTrue("f = f1*f2 ", expected.f.equals(f1.multiply(f2))); } catch (NotInvertibleException e) { //e.printStackTrace(); fail("wrong exception " + e); } } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test example. */ public void testExample() { BigRational cofac = new BigRational(1); GenPolynomialRing mfac = new GenPolynomialRing(cofac, new String[] { "w35" }); // w35**2 - 35: w35 == sqrt(35) GenPolynomial mo = mfac.univariate(0); mo = mo.power(2).subtract(mfac.fromInteger(35)); //System.out.println("mo = " + mo); AlgebraicNumberRing fac = new AlgebraicNumberRing(mo); //System.out.println("fac = " + fac); // (5+sqrt(35))**(-1) == 1/10 w35 - 1/2 AlgebraicNumber w35 = fac.getGenerator(); AlgebraicNumber rr = fac.fromInteger(5).sum(w35).inverse(); //System.out.println("rr = " + rr); assertFalse("rr != 0: ", rr.isZERO()); assertTrue("deg(rr.val) == 1: ", rr.val.degree() == 1); } /** * Test enumerator. */ public void testEnumerator() { //System.out.println("fac = " + fac); long s = 0L; long t = 0L; Set> elems = new HashSet>(49); //Iterator> iter = fac.iterator(); for (AlgebraicNumber an : fac) { t++; if (elems.contains(an)) { //System.out.println("dup(an) = " + an); s++; } else { //System.out.println("an = " + an); elems.add(an); } if (t >= 100) { break; } } //System.out.println("elems = " + elems); assertTrue("#elems " + t + ", t = " + elems.size(), t == elems.size()); assertTrue("#elems " + t + ", t = " + elems.size(), s == 0L); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ComplexGenPolynomialTest.java000066400000000000000000000122001445075545500264460ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.poly.GenPolynomial; import edu.jas.arith.BigComplex; import edu.jas.arith.Roots; /** * Complex coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class ComplexGenPolynomialTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ComplexGenPolynomialTest object. * @param name String. */ public ComplexGenPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(ComplexGenPolynomialTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new BigComplex(1),rl); } protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO() ); assertTrue("isONE( c )", c.isONE() ); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll); // fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = fac.random(ll); ExpVector u = ExpVector.random(rl,el,q); BigComplex x = BigComplex.CRAND(kl); b = new GenPolynomial(fac,x, u); c = a.sum(b); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); a = new GenPolynomial(fac); b = new GenPolynomial(fac,x, u); c = b.sum(a); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); BigComplex x = a.leadingBaseCoefficient().inverse(); c = a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))",c,d); BigComplex y = b.leadingBaseCoefficient().inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))",c,d); e = new GenPolynomial(fac,y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))",c,d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b",c,d); } /** * Test absolute norm. */ public void testAbsNorm() { BigComplex r; a = fac.getONE().negate(); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue("isONE( absNorm(-1) )", r.isONE() ); a = fac.random(kl*2, ll+2, el, q ); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue(" not isZERO( absNorm(a) )", !r.isZERO() || a.isZERO() ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ComplexTest.java000066400000000000000000000247041445075545500237640ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; //import java.util.ArrayList; //import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.arith.BigInteger; //import edu.jas.structure.RingElem; /** * Complex test with JUnit. * @author Heinz Kredel */ public class ComplexTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ComplexTest object. * @param name String. */ public ComplexTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(ComplexTest.class); return suite; } ComplexRing fac; GenPolynomialRing pfac; ComplexRing< GenPolynomial > mfac; Complex< BigInteger > a; Complex< BigInteger > b; Complex< BigInteger > c; Complex< BigInteger > d; Complex< BigInteger > e; Complex< GenPolynomial > ap; Complex< GenPolynomial > bp; Complex< GenPolynomial > cp; Complex< GenPolynomial > dp; Complex< GenPolynomial > ep; int rl = 1; int kl = 13; int ll = 7; int el = 3; float q = 0.4f; int il = 2; long p = 1152921504606846883L; // 2^60-93; @Override protected void setUp() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; BigInteger cfac = new BigInteger(1); fac = new ComplexRing( cfac ); pfac = new GenPolynomialRing( new BigRational(1), 1 ); GenPolynomial mo = pfac.random(kl,ll,el,q); while ( mo.isConstant() ) { mo = pfac.random(kl,ll,el,q); } mfac = new ComplexRing>( pfac ); } @Override protected void tearDown() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; fac = null; pfac = null; mfac = null; } /** * Test constructor for integer. * */ public void testIntConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO() ); assertTrue("isONE( c )", c.isONE() ); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); } /** * Test constructor for polynomial. * */ public void testPolyConstruction() { cp = mfac.getONE(); assertTrue("isZERO( cp )", !cp.isZERO() ); assertTrue("isONE( cp )", cp.isONE() ); dp = mfac.getZERO(); assertTrue("isZERO( dp )", dp.isZERO() ); assertTrue("isONE( dp )", !dp.isONE() ); } /** * Test random integer. * */ public void testIntRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl*(i+1)); if ( a.isZERO() ) { continue; } //a = fac.random(kl*(i+1), ll+2*i, el+i, q ); //System.out.println("a = " + a); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test random polynomial. * */ public void testPolyRandom() { for (int i = 0; i < 7; i++) { ap = mfac.random(kl+i); if ( ap.isZERO() ) { continue; } assertTrue(" not isZERO( ap"+i+" )", !ap.isZERO() ); assertTrue(" not isONE( ap"+i+" )", !ap.isONE() ); } } /** * Test integer addition. * */ public void testIntAddition() { a = fac.random(kl); b = fac.random(kl); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a",c,d); c = fac.random(kl); d = c.sum( a.sum(b) ); e = c.sum( a ).sum(b); assertEquals("c+(a+b) = (c+a)+b",d,e); c = a.sum( fac.getZERO() ); d = a.subtract( fac.getZERO() ); assertEquals("a+0 = a-0",c,d); c = fac.getZERO().sum( a ); d = fac.getZERO().subtract( a.negate() ); assertEquals("0+a = 0+(-a)",c,d); } /** * Test polynomial addition. * */ public void testPolyAddition() { ap = mfac.random(kl); bp = mfac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); cp = ap.sum(bp); dp = cp.subtract(bp); assertEquals("a+b-b = a",ap,dp); cp = ap.sum(bp); dp = bp.sum(ap); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a",cp,dp); cp = mfac.random(kl); dp = cp.sum( ap.sum(bp) ); ep = cp.sum( ap ).sum(bp); assertEquals("c+(a+b) = (c+a)+b",dp,ep); cp = ap.sum( mfac.getZERO() ); dp = ap.subtract( mfac.getZERO() ); assertEquals("a+0 = a-0",cp,dp); cp = mfac.getZERO().sum( ap ); dp = mfac.getZERO().subtract( ap.negate() ); assertEquals("0+a = 0+(-a)",cp,dp); } /** * Test integer multiplication. * */ public void testIntMultiplication() { a = fac.random(kl); if ( a.isZERO() ) { return; } assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(kl); if ( b.isZERO() ) { return; } assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(kl); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); c = a.multiply( fac.getONE() ); d = fac.getONE().multiply( a ); assertEquals("a*1 = 1*a",c,d); if ( a.isUnit() ) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1",d.isONE()); } } /** * Test polynomial multiplication. * */ public void testPolyMultiplication() { ap = mfac.random(kl); if ( ap.isZERO() ) { return; } assertTrue("not isZERO( a )", !ap.isZERO() ); bp = mfac.random(kl); if ( bp.isZERO() ) { return; } assertTrue("not isZERO( b )", !bp.isZERO() ); cp = bp.multiply(ap); dp = ap.multiply(bp); assertTrue("not isZERO( c )", !cp.isZERO() ); assertTrue("not isZERO( d )", !dp.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); ep = dp.subtract(cp); assertTrue("isZERO( a*b-b*a ) " + ep, ep.isZERO() ); assertTrue("a*b = b*a", cp.equals(dp) ); assertEquals("a*b = b*a",cp,dp); cp = mfac.random(kl); //System.out.println("c = " + c); dp = ap.multiply( bp.multiply(cp) ); ep = (ap.multiply(bp)).multiply(cp); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",dp,ep); assertTrue("a(bc) = (ab)c", dp.equals(ep) ); cp = ap.multiply( mfac.getONE() ); dp = mfac.getONE().multiply( ap ); assertEquals("a*1 = 1*a",cp,dp); if ( ap.isUnit() ) { cp = ap.inverse(); dp = cp.multiply(ap); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1",dp.isONE()); } } /** * Test integer division. * */ public void testIntDivision() { a = fac.random(kl*2); if ( a.isZERO() ) { return; } assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(kl); if ( b.isZERO() ) { return; } assertTrue("not isZERO( b )", !b.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.divide(b); //System.out.println("c = " + c); d = a.remainder(b); //System.out.println("d = " + d); e = b.multiply(c).sum(d); //System.out.println("e = " + e); assertEquals("a = b (a/b) + a%b ", a, e ); c = a.gcd(b); d = a.divide(c); e = b.divide(c); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); d = c.multiply(d); e = c.multiply(e); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a/gcd(a,b)*gcd(a,b) = a ", a, d ); assertEquals("b/gcd(a,b)*gcd(a,b) = b ", b, e ); Complex[] gf = a.egcd(b); c = gf[0]; d = gf[1]; e = gf[2]; //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); d = d.multiply(a); e = e.multiply(b); d = d.sum( e ); //System.out.println("d = " + d); assertEquals("d*a + e*b = c = gcd(a,b)", c, d ); } /** * Test polynomial division. * */ public void testPolyDivision() { ap = mfac.random(kl); if ( ap.isZERO() ) { return; } assertTrue("not isZERO( ap )", !ap.isZERO() ); bp = mfac.random(kl/2); if ( bp.isZERO() ) { return; } assertTrue("not isZERO( bp )", !bp.isZERO() ); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); cp = ap.divide(bp); //System.out.println("cp = " + cp); dp = ap.remainder(bp); //System.out.println("dp = " + dp); ep = bp.multiply(cp).sum(dp); //System.out.println("ep = " + ep); assertEquals("ap = bp (ap/bp) + ap%bp ", ap, ep ); // not applicable: // cp = ap.gcd(bp); // dp = ap.divide(cp); // ep = bp.divide(cp); // System.out.println("cp = " + cp); // System.out.println("dp = " + dp); // System.out.println("ep = " + ep); // dp = cp.multiply(dp); // ep = cp.multiply(ep); // System.out.println("dp = " + dp); // System.out.println("ep = " + ep); // assertEquals("ap/gcd(ap,bp)*gcd(ap,bp) = ap ", ap, dp ); // assertEquals("bp/gcd(ap,bp)*gcd(ap,bp) = bp ", bp, ep ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/DecGenPolynomialTest.java000066400000000000000000000175451445075545500255530ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Map; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.arith.BigDecimal; import edu.jas.arith.Roots; /** * BigDecimal coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class DecGenPolynomialTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a RatGenPolynomialTest object. * @param name String. */ public DecGenPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(DecGenPolynomialTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new BigDecimal(1),rl); } protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO() ); assertTrue("isONE( c )", c.isONE() ); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { //a = fac.random(ll); a = fac.random(kl*(i+1), ll+2*i, el+i, q ); //System.out.println("a = " + a); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = fac.random(ll); ExpVector u = ExpVector.random(rl,el,q); BigDecimal x = fac.coFac.random(kl); b = new GenPolynomial(fac,x, u); c = a.sum(b); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); a = new GenPolynomial(fac); b = new GenPolynomial(fac,x, u); c = b.sum(a); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); BigDecimal x = a.leadingBaseCoefficient().inverse(); c = a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))",c,d); BigDecimal y = b.leadingBaseCoefficient().inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))",c,d); e = new GenPolynomial(fac,y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))",c,d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b",c,d); } /** * Test BLAS level 1. */ public void testBLAS1() { a = fac.random(kl,ll,el,q); b = fac.random(kl,ll,el,q); c = fac.random(kl,3,el*el,q); ExpVector ev = ExpVector.random(rl,el,q); BigDecimal lc = fac.coFac.random(kl); d = a.subtractMultiple(lc,b); e = a.subtract( b.multiply(lc) ); assertEquals("a - (lc) b == a - ((lc) b)",d,e); d = a.subtractMultiple(lc,ev,b); e = a.subtract( b.multiply(lc,ev) ); assertEquals("a - (lc ev) b == a - ((lc ev) b)",d,e); ExpVector fv = ExpVector.random(rl,el,q); BigDecimal tc = fac.coFac.random(kl); d = a.scaleSubtractMultiple(tc,lc,ev,b); e = a.multiply(tc).subtract( b.multiply(lc,ev) ); assertEquals("(tc) a - (lc ev) b == ((tc) a - ((lc ev) b))",d,e); d = a.scaleSubtractMultiple(tc,fv,lc,ev,b); e = a.multiply(tc,fv).subtract( b.multiply(lc,ev) ); assertEquals("(tc fv) a - (lc ev) b == ((tc fv) a - ((lc ev) b))",d,e); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl,ll,el,q); b = fac.random(kl,ll,el,q); c = fac.random(kl,ll,el,q); d = a.multiply( b.sum(c) ); e = a.multiply( b ).sum( a.multiply(c) ); assertEquals("a(b+c) == ab+ac",d,e); } /* * Test object quotient and remainder. * Not meaningful. */ /** * Test addition speed. */ public void testAdditionSpeed() { int ll = 100; long t = 1000; boolean print = false; int jit = 1; for (int j = 1; j < 5; j++) { for (int i = 1; i < 5; i++) { a = fac.random(kl, i*ll, el, q); b = fac.random(kl, ll, el, q); for (int k = 0; k < jit; k++) { long t1 = System.nanoTime(); c = a.sum(b); t1 = System.nanoTime() - t1; assertTrue("c != 0", !c.isZERO() ); long t2 = System.nanoTime(); d = b.sum(a); t2 = System.nanoTime() - t2; assertTrue("d != 0", !d.isZERO() ); if (print) { System.out.print("#a = " + a.length() + ", #b = " + b.length() ); System.out.println(",\t t1 = " + (t1/t) + ", t2 = " + (t2/t) ); } //assertTrue("t2 <= t1", ((t1/t) >= (t2/t)) ); } if (print) System.out.println(); assertEquals("c == d", c, d ); } ll = 3 * ll; } } /** * Test absolute norm. */ public void testAbsNorm() { BigDecimal r; a = fac.getONE().negate(); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue("isONE( absNorm(-1) )", r.isONE() ); a = fac.random(kl*2, ll+2, el, q ); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue(" not isZERO( absNorm(a) )", !r.isZERO() || a.isZERO() ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ExpVectorTest.java000066400000000000000000000700711445075545500242720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import edu.jas.arith.BigInteger; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ExpVector tests with JUnit. Tests arithmetic operations, for comparison tests * see TermOrderTest. * @author Heinz Kredel */ public class ExpVectorTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ExpVectorTest object. * @param name String. */ public ExpVectorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ExpVectorTest.class); return suite; } ExpVector a, b, c, d; @Override protected void setUp() { a = b = c = d = null; } @Override protected void tearDown() { a = b = c = d = null; } /** * Test constructor and toString. */ public void testConstructor() { a = ExpVector.create(0); b = ExpVector.create(0); assertEquals("() = ()", a, b); assertEquals("length( () ) = 0", a.length(), 0); assertTrue("isZERO( () )", a.isZERO()); a = ExpVector.create(10); b = ExpVector.create(10); assertEquals("10e = 10e", a, b); assertEquals("length( 10e ) = 10", a.length(), 10); assertTrue("isZERO( ( 10e ) )", a.isZERO()); String s = "(0,0,0,0,0,0,0,0,0,0)"; a = ExpVector.create(s); String t = a.toString().substring(0, s.length()); assertEquals("stringConstr = toString", s, t); assertTrue("isZERO( ( 10e ) )", a.isZERO()); s = a.toScript(); //System.out.println("a.toScript: " + s + ", " + s.length()); assertEquals("#s == 0: " + s, s.length(), 0); } /** * Test bitLength. */ public void testBitLength() { a = ExpVector.create(0); assertEquals("blen(0) = 0", 0, a.bitLength()); b = ExpVector.create(10); assertEquals("blen(0) = 10", 10, b.bitLength()); c = ExpVector.random(10, 20, 0.5f); //System.out.println("c = " + c); //System.out.println("blen(c) = " + c.bitLength()); assertTrue("blen(random) >= 0", 0 <= c.bitLength()); } /** * Test random integer. */ public void testRandom() { float q = (float) 0.3; a = ExpVector.random(5, 10, q); String s = a.toString(); if (s.indexOf(":") >= 0) { s = s.substring(0, s.indexOf(":")); } b = ExpVector.create(s); assertEquals("a == b", true, a.equals(b)); c = ExpVector.EVDIF(b, a); assertTrue("a-b = 0", c.isZERO()); c = a.reverse(); //System.out.println("c = " + c); d = c.reverse(0); //System.out.println("d = " + d); assertEquals("rev(rev(a),0) == a", a, d); } /** * Test addition. */ public void testAddition() { float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.EVSUM(a, a); c = ExpVector.EVDIF(b, a); assertEquals("a+a-a = a", c, a); assertTrue("a+a-a = a", c.equals(a)); boolean t; t = ExpVector.EVMT(b, a); assertTrue("a | a+a", t); a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = ExpVector.EVSUM(a, b); d = ExpVector.EVSUM(b, a); assertTrue("a+b = b+a", c.equals(d)); } /** * Test lcm. */ public void testLcm() { float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = ExpVector.EVLCM(a, b); d = ExpVector.EVLCM(b, a); assertTrue("lcm(a,b) = lcm(b,a)", c.equals(d)); assertTrue("a | lcm(a,b)", ExpVector.EVMT(c, a)); assertTrue("b | lcm(a,b)", ExpVector.EVMT(c, b)); d = ExpVector.EVDIF(c, a); assertTrue("sign(lcm(a,b)-a) >= 0", ExpVector.EVSIGN(d) >= 0); d = ExpVector.EVDIF(c, b); assertTrue("sign(lcm(a,b)-b) >= 0", ExpVector.EVSIGN(d) >= 0); } /** * Test tdeg. */ public void testTdeg() { a = ExpVector.create(100); assertTrue("tdeg(a) = 0", ExpVector.EVTDEG(a) == 0); float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); c = ExpVector.EVSUM(a, b); assertTrue("tdeg(a+b) >= tdeg(a)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(a)); assertTrue("tdeg(a+b) >= tdeg(b)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(b)); c = ExpVector.EVLCM(a, b); assertTrue("tdeg(lcm(a,b)) >= tdeg(a)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(a)); assertTrue("tdeg(lcm(a,b)) >= tdeg(b)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(b)); } /** * Test weight degree. */ public void testWeightdeg() { a = ExpVector.create(100); assertTrue("tdeg(a) = 0", ExpVector.EVTDEG(a) == 0); assertTrue("wdeg(a) = 0", ExpVector.EVWDEG(null, a) == 0); float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertEquals("tdeg(a) == wdeg(a)", ExpVector.EVTDEG(a), ExpVector.EVWDEG(w, a)); assertEquals("tdeg(b) == wdeg(b)", ExpVector.EVTDEG(b), ExpVector.EVWDEG(w, b)); c = ExpVector.EVSUM(a, b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = ExpVector.EVLCM(a, b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); w = new long[][] { new long[] { 10l, 1l, 3l, 9l, 100l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertTrue("tdeg(a) <= wdeg(a)", ExpVector.EVTDEG(a) <= ExpVector.EVWDEG(w, a)); assertTrue("tdeg(b) <= wdeg(b)", ExpVector.EVTDEG(b) <= ExpVector.EVWDEG(w, b)); c = ExpVector.EVSUM(a, b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = ExpVector.EVLCM(a, b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); w = new long[][] { new long[] { 10l, 1l, 3l, 9l, 100l }, new long[] { 1l, 1l, 1l, 1l, 1l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertTrue("tdeg(a) <= wdeg(a)", ExpVector.EVTDEG(a) <= ExpVector.EVWDEG(w, a)); assertTrue("tdeg(b) <= wdeg(b)", ExpVector.EVTDEG(b) <= ExpVector.EVWDEG(w, b)); c = ExpVector.EVSUM(a, b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = ExpVector.EVLCM(a, b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); } /** * Test dependency on variables. */ public void testDependency() { int[] exp; int[] dep; a = ExpVector.create(10, 5, 2l); exp = new int[] { 5 }; dep = ExpVector.EVDOV(a); assertTrue("[5] = [5]", Arrays.equals(exp, dep)); b = ExpVector.create(10, 3, 9l); exp = new int[] { 3 }; dep = ExpVector.EVDOV(b); assertTrue("[3] = [3]", Arrays.equals(exp, dep)); c = ExpVector.EVSUM(a, b); exp = new int[] { 3, 5 }; dep = ExpVector.EVDOV(c); assertTrue("[3,5] = [3,5] " + Arrays.toString(exp) + "," + Arrays.toString(dep), Arrays.equals(exp, dep)); b = ExpVector.create(10); exp = new int[] {}; dep = ExpVector.EVDOV(b); assertTrue("[] = []", Arrays.equals(exp, dep)); b = ExpVector.create(0); exp = new int[] {}; dep = ExpVector.EVDOV(b); assertTrue("[] = []", Arrays.equals(exp, dep)); b = ExpVector.create(1, 0, 1l); exp = new int[] { 0 }; dep = ExpVector.EVDOV(b); assertTrue("[0] = [0]", Arrays.equals(exp, dep)); } /** * Test random exp vector 2. */ public void testRandom2() { float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.create("" + a); assertEquals("a == b", true, a.equals(b)); c = b.subtract(a); assertTrue("a-b = 0", c.isZERO()); } /** * Test addition. */ public void testAddition2() { float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = a.sum(a); c = b.subtract(a); assertEquals("a+a-a = a", c, a); assertTrue("a+a-a = a", c.equals(a)); boolean t; t = b.multipleOf(a); assertTrue("a | a+a", t); a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); d = b.sum(a); assertTrue("a+b = b+a", c.equals(d)); } /** * Test lcm. */ public void testLcm2() { float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.lcm(b); d = b.lcm(a); assertTrue("lcm(a,b) = lcm(b,a)", c.equals(d)); assertTrue("a | lcm(a,b)", c.multipleOf(a)); assertTrue("b | lcm(a,b)", c.multipleOf(b)); d = c.subtract(a); assertTrue("sign(lcm(a,b)-a) >= 0", d.signum() >= 0); d = c.subtract(b); assertTrue("sign(lcm(a,b)-b) >= 0", d.signum() >= 0); } /** * Test tdeg. */ public void testTdeg2() { a = ExpVector.create(100); assertTrue("tdeg(a) = 0", ExpVector.EVTDEG(a) == 0); float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); c = a.sum(b); assertTrue("tdeg(a+b) >= tdeg(a)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(a)); assertTrue("tdeg(a+b) >= tdeg(b)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(b)); c = a.lcm(b); assertTrue("tdeg(lcm(a,b)) >= tdeg(a)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(a)); assertTrue("tdeg(lcm(a,b)) >= tdeg(b)", ExpVector.EVTDEG(c) >= ExpVector.EVTDEG(b)); } /** * Test weighted. */ public void testWeightdeg2() { a = ExpVector.create(100); assertTrue("tdeg(a) = 0", ExpVector.EVTDEG(a) == 0); assertTrue("wdeg(a) = 0", ExpVector.EVWDEG(null, a) == 0); float q = (float) 0.2; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertEquals("tdeg(a) == wdeg(a)", ExpVector.EVTDEG(a), ExpVector.EVWDEG(w, a)); assertEquals("tdeg(b) == wdeg(b)", ExpVector.EVTDEG(b), ExpVector.EVWDEG(w, b)); c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); w = new long[][] { new long[] { 10l, 1l, 3l, 9l, 100l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertTrue("tdeg(a) <= wdeg(a)", ExpVector.EVTDEG(a) <= ExpVector.EVWDEG(w, a)); assertTrue("tdeg(b) <= wdeg(b)", ExpVector.EVTDEG(b) <= ExpVector.EVWDEG(w, b)); c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); w = new long[][] { new long[] { 10l, 1l, 3l, 9l, 100l }, new long[] { 1l, 1l, 1l, 1l, 1l } }; assertTrue("tdeg(a) >= 0", ExpVector.EVTDEG(a) >= 0); assertTrue("tdeg(b) >= 0", ExpVector.EVTDEG(b) >= 0); assertTrue("wdeg(a) >= 0", ExpVector.EVWDEG(w, a) >= 0); assertTrue("wdeg(b) >= 0", ExpVector.EVWDEG(w, b) >= 0); assertTrue("tdeg(a) <= wdeg(a)", ExpVector.EVTDEG(a) <= ExpVector.EVWDEG(w, a)); assertTrue("tdeg(b) <= wdeg(b)", ExpVector.EVTDEG(b) <= ExpVector.EVWDEG(w, b)); c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(a+b) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, a)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", ExpVector.EVWDEG(w, c) >= ExpVector.EVWDEG(w, b)); } /** * Test dependency on variables. */ public void testDependency2() { int[] exp; int[] dep; a = ExpVector.create(10, 5, 2l); exp = new int[] { 5 }; dep = a.dependencyOnVariables(); assertTrue("[5] = [5]", Arrays.equals(exp, dep)); b = ExpVector.create(10, 3, 9l); exp = new int[] { 3 }; dep = b.dependencyOnVariables(); assertTrue("[3] = [3]", Arrays.equals(exp, dep)); c = a.sum(b); exp = new int[] { 3, 5 }; dep = c.dependencyOnVariables(); assertTrue("[3,5] = [3,5] " + Arrays.toString(exp) + "," + Arrays.toString(dep), Arrays.equals(exp, dep)); b = ExpVector.create(10); exp = new int[] {}; dep = b.dependencyOnVariables(); assertTrue("[] = []", Arrays.equals(exp, dep)); b = ExpVector.create(0); exp = new int[] {}; dep = b.dependencyOnVariables(); assertTrue("[] = []", Arrays.equals(exp, dep)); b = ExpVector.create(1, 0, 1l); exp = new int[] { 0 }; dep = b.dependencyOnVariables(); assertTrue("[0] = [0]", Arrays.equals(exp, dep)); } /** * Test evaluation. */ public void testEvaluation() { float q = (float) 0.2; int rl = 5; a = ExpVector.random(rl, 10, q); b = ExpVector.random(rl, 10, q); BigInteger fv = new BigInteger(0); List v = new ArrayList(a.length()); for (int i = 0; i < a.length(); i++) { v.add(fv.random(4)); } BigInteger av = a.evaluate(fv, v); BigInteger bv = b.evaluate(fv, v); c = a.sum(b); BigInteger cv = c.evaluate(fv, v); BigInteger dv = av.multiply(bv); assertEquals("a(v)*b(v) = (a+b)(v) ", cv, dv); c = ExpVector.create(rl); cv = c.evaluate(fv, v); dv = fv.getONE(); assertEquals("0(v) = 1 ", cv, dv); v.clear(); for (int i = 0; i < a.length(); i++) { v.add(fv.getZERO()); } cv = c.evaluate(fv, v); dv = fv.getONE(); assertEquals("0(0) = 1 ", cv, dv); av = a.evaluate(fv, v); if (a.isZERO()) { dv = fv.getONE(); assertEquals("0(0) = 1 ", av, dv); } else { dv = fv.getZERO(); assertEquals("a(0) = 0 ", av, dv); } } /** * Test ExpVectorInteger. */ public void testInteger() { a = new ExpVectorInteger(10); b = new ExpVectorInteger(10); assertEquals("10e = 10e", a, b); assertEquals("length( 10e ) = 10", a.length(), 10); assertTrue("isZERO( ( 10e ) )", a.isZERO()); String s = "(0,0,0,0,0,0,0,0,0,0)"; a = new ExpVectorInteger(s); String t = a.toString().substring(0, s.length()); assertEquals("stringConstr = toString", s, t); assertTrue("isZERO( ( 10e ) )", a.isZERO()); a = ExpVectorInteger.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("a = " + a); t = a.toString(); b = new ExpVectorInteger(t); //System.out.println("b = " + b); assertEquals("parse(toString(a)) == a", a, b); b = ExpVectorInteger.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("b = " + b); c = new ExpVectorInteger(b.getVal()); //System.out.println("c = " + c); assertEquals("int(b) == c", b, c); c = a.lcm(b); //System.out.println("c = " + c); assertTrue("deg(lcm(a,b)) >= deg(a)", c.totalDeg() >= a.totalDeg()); assertTrue("deg(lcm(a,b)) >= deg(b)", c.totalDeg() >= b.totalDeg()); assertTrue("a | lcm(a,b)", c.multipleOf(a)); assertTrue("b | lcm(a,b)", c.multipleOf(b)); d = a.gcd(b); //System.out.println("d = " + d); ExpVector e, f; e = c.sum(d); f = a.sum(b); //System.out.println("e = " + e); //System.out.println("f = " + f); assertEquals("lcm(a,b)*gcd(a,b) == a*b", e, f); c = a.reverse(); //System.out.println("c = " + c); d = c.reverse(0); //System.out.println("d = " + d); assertEquals("rev(rev(a),0) == a", a, d); } /** * Test ExpVectorShort. */ public void testShort() { a = new ExpVectorShort(10); b = new ExpVectorShort(10); assertEquals("10e = 10e", a, b); assertEquals("length( 10e ) = 10", a.length(), 10); assertTrue("isZERO( ( 10e ) )", a.isZERO()); String s = "(0,0,0,0,0,0,0,0,0,0)"; a = new ExpVectorShort(s); String t = a.toString().substring(0, s.length()); assertEquals("stringConstr = toString", s, t); assertTrue("isZERO( ( 10e ) )", a.isZERO()); a = ExpVectorShort.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("a = " + a); // + ", " + a.toScript()); t = a.toString(); b = new ExpVectorShort(t); assertEquals("parse(toString(a)) == a", a, b); b = ExpVectorShort.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("b = " + b); c = new ExpVectorShort(b.getVal()); //System.out.println("c = " + c); assertEquals("short(a) == a", b, c); c = a.lcm(b); //System.out.println("c = " + c); assertTrue("deg(lcm(a,b)) >= deg(a)", c.totalDeg() >= a.totalDeg()); assertTrue("deg(lcm(a,b)) >= deg(b)", c.totalDeg() >= b.totalDeg()); assertTrue("a | lcm(a,b)", c.multipleOf(a)); assertTrue("b | lcm(a,b)", c.multipleOf(b)); d = a.gcd(b); //System.out.println("d = " + d); ExpVector e, f; e = c.sum(d); f = a.sum(b); //System.out.println("e = " + e); //System.out.println("f = " + f); assertEquals("lcm(a,b)*gcd(a,b) == a*b", e, f); c = a.reverse(); //System.out.println("c = " + c); d = c.reverse(0); //System.out.println("d = " + d); assertEquals("rev(rev(a),0) == a", a, d); } /** * Test ExpVectorByte. */ public void testByte() { a = new ExpVectorByte(10); b = new ExpVectorByte(10); assertEquals("10e = 10e", a, b); assertEquals("length( 10e ) = 10", a.length(), 10); assertTrue("isZERO( ( 10e ) )", a.isZERO()); String s = "(0,0,0,0,0,0,0,0,0,0)"; a = new ExpVectorByte(s); String t = a.toString().substring(0, s.length()); assertEquals("stringConstr = toString", s, t); assertTrue("isZERO( ( 10e ) )", a.isZERO()); a = ExpVectorByte.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("a = " + a); // + ", " + a.toScript()); t = a.toString(); b = new ExpVectorByte(t); assertEquals("parse(toString(a)) == a", a, b); b = ExpVectorByte.valueOf(ExpVector.random(10, 20, 0.5f)); //System.out.println("b = " + b); c = new ExpVectorByte(b.getVal()); //System.out.println("c = " + c); assertEquals("byte(a) == c", b, c); c = a.lcm(b); //System.out.println("c = " + c); assertTrue("deg(lcm(a,b)) >= deg(a)", c.totalDeg() >= a.totalDeg()); assertTrue("deg(lcm(a,b)) >= deg(b)", c.totalDeg() >= b.totalDeg()); assertTrue("a | lcm(a,b)", c.multipleOf(a)); assertTrue("b | lcm(a,b)", c.multipleOf(b)); d = a.gcd(b); //System.out.println("d = " + d); ExpVector e, f; e = c.sum(d); f = a.sum(b); //System.out.println("e = " + e); //System.out.println("f = " + f); assertEquals("lcm(a,b)*gcd(a,b) == a*b", e, f); c = a.reverse(); //System.out.println("c = " + c); d = c.reverse(0); //System.out.println("d = " + d); assertEquals("rev(rev(a),0) == a", a, d); } /** * Test weight degree, long, integer, short and byte. */ public void testWeightdegIntShortByte() { float q = (float) 0.2; a = new ExpVectorInteger(100); assertTrue("tdeg(a) = 0", a.totalDeg() == 0); assertTrue("wdeg(a) = 0", a.weightDeg((long[][])null) == 0); a = ExpVectorInteger.valueOf(ExpVector.random(5, 10, q)); b = ExpVectorInteger.valueOf(ExpVector.random(5, 10, q)); //System.out.println("a = " + a); //System.out.println("b = " + b); runWeightdeg(a,b); a = ExpVectorShort.valueOf(ExpVector.random(5, 10, q)); b = ExpVectorShort.valueOf(ExpVector.random(5, 10, q)); //System.out.println("a = " + a); //System.out.println("b = " + b); runWeightdeg(a,b); a = ExpVectorByte.valueOf(ExpVector.random(5, 10, q)); b = ExpVectorByte.valueOf(ExpVector.random(5, 10, q)); //System.out.println("a = " + a); //System.out.println("b = " + b); runWeightdeg(a,b); a = ExpVectorLong.valueOf(ExpVector.random(5, 10, q)); b = ExpVectorLong.valueOf(ExpVector.random(5, 10, q)); //System.out.println("a = " + a); //System.out.println("b = " + b); runWeightdeg(a,b); } /** * Run weight degree tests. */ public void runWeightdeg(ExpVector a, ExpVector b) { long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; assertTrue("tdeg(a) >= 0", a.totalDeg() >= 0); assertTrue("tdeg(b) >= 0", b.totalDeg() >= 0); assertTrue("madeg(a) >= 0", a.maxDeg() >= 0); assertTrue("madeg(b) >= 0", b.maxDeg() >= 0); assertTrue("mideg(a) >= 0", a.minDeg() >= 0); assertTrue("mideg(b) >= 0", b.minDeg() >= 0); assertTrue("wdeg(a) >= 0", a.weightDeg(w) >= 0); assertTrue("wdeg(b) >= 0", b.weightDeg(w) >= 0); assertEquals("tdeg(a) == wdeg(a)", a.totalDeg(), a.weightDeg(w)); assertEquals("tdeg(b) == wdeg(b)", b.totalDeg(), b.weightDeg(w)); ExpVector c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", c.weightDeg(w) >= a.weightDeg(w)); assertTrue("wdeg(a+b) >= wdeg(b)", c.weightDeg(w) >= b.weightDeg(w)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", c.weightDeg(w) >= a.weightDeg(w)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", c.weightDeg(w) >= b.weightDeg(w)); //w = new long[][] { new long[] { 10l, 1l, 3l, 9l, 100l } }; long[] v = new long[] { 10l, 1l, 3l, 9l, 100l }; assertTrue("tdeg(a) >= 0", a.totalDeg() >= 0); assertTrue("tdeg(b) >= 0", b.totalDeg() >= 0); assertTrue("wdeg(a) >= 0", a.weightDeg(v) >= 0); assertTrue("wdeg(b) >= 0", b.weightDeg(v) >= 0); assertTrue("tdeg(a) <= wdeg(a)", a.totalDeg() <= a.weightDeg(v)); assertTrue("tdeg(b) <= wdeg(b)", b.totalDeg() <= b.weightDeg(v)); c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", c.weightDeg(v) >= a.weightDeg(v)); assertTrue("wdeg(a+b) >= wdeg(b)", c.weightDeg(v) >= b.weightDeg(v)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", c.weightDeg(v) >= a.weightDeg(v)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", c.weightDeg(v) >= b.weightDeg(v)); w = new long [][] { v, w[0] }; assertTrue("tdeg(a) >= 0", a.totalDeg() >= 0); assertTrue("tdeg(b) >= 0", b.totalDeg() >= 0); assertTrue("wdeg(a) >= 0", a.weightDeg(w) >= 0); assertTrue("wdeg(b) >= 0", b.weightDeg(w) >= 0); assertTrue("tdeg(a) <= wdeg(a)", a.totalDeg() <= a.weightDeg(w)); assertTrue("tdeg(b) <= wdeg(b)", b.totalDeg() <= b.weightDeg(w)); c = a.sum(b); assertTrue("wdeg(a+b) >= wdeg(a)", c.weightDeg(w) >= a.weightDeg(w)); assertTrue("wdeg(a+b) >= wdeg(b)", c.weightDeg(w) >= b.weightDeg(w)); c = a.lcm(b); assertTrue("wdeg(lcm(a,b)) >= wdeg(a)", c.weightDeg(w) >= a.weightDeg(w)); assertTrue("wdeg(lcm(a,b)) >= wdeg(b)", c.weightDeg(w) >= b.weightDeg(w)); int t = a.invWeightCompareTo(w,b) + b.invWeightCompareTo(w,a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.invWeightCompareTo(w,b,0,3) + b.invWeightCompareTo(w,a,0,3); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.revInvLexCompareTo(b) + b.revInvLexCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.revInvLexCompareTo(b,0,3) + b.revInvLexCompareTo(a,0,3); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.revInvGradCompareTo(b) + b.revInvGradCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.revInvGradCompareTo(b,0,3) + b.revInvGradCompareTo(a,0,3); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.invLexCompareTo(b) + b.invLexCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.invLexCompareTo(b,0,3) + b.invLexCompareTo(a,0,3); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.invGradCompareTo(b) + b.invGradCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.invGradCompareTo(b,0,3) + b.invGradCompareTo(a,0,3); assertTrue("(a <= b) + (b <= a) == 0", t == 0); if (a instanceof ExpVectorShort || a instanceof ExpVectorByte) { return; } t = a.invTdegCompareTo(b) + b.invTdegCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); t = a.revLexInvTdegCompareTo(b) + b.revLexInvTdegCompareTo(a); assertTrue("(a <= b) + (b <= a) == 0", t == 0); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GFGenPolynomialTest.java000066400000000000000000000222301445075545500253370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; /** * Galois field coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class GFGenPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GFGenPolynomialTest object. * @param name String. */ public GFGenPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GFGenPolynomialTest.class); return suite; } GenPolynomialRing> fac; AlgebraicNumberRing cfac; GenPolynomial> a, b, c, d, e; int rl = 7; int kl = 10; int ll = 8; int el = 5; float q = 0.5f; protected long getPrime() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //System.out.println("prime = " + prime); return prime; } @Override protected void setUp() { a = b = c = d = e = null; long prime = getPrime(); ModIntegerRing r = new ModIntegerRing(prime); // univariate minimal polynomial GenPolynomialRing mfac = new GenPolynomialRing(r, 1); GenPolynomial modul = mfac.random(5); while (modul.isZERO() || modul.isUnit() || modul.isConstant()) { modul = mfac.random(5); } cfac = new AlgebraicNumberRing(modul.monic()); fac = new GenPolynomialRing>(cfac, rl); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )c" + c, !c.isZERO()); assertTrue("isONE( c ) " + c, c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll + i); //System.out.println("a = " + a); // fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(ll); ExpVector u = ExpVector.random(rl, el, q); AlgebraicNumber x = cfac.random(kl); b = new GenPolynomial>(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial>(fac); b = new GenPolynomial>(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); AlgebraicNumber z = a.leadingBaseCoefficient(); //System.out.println("z = " + z); if (z.isUnit()) { AlgebraicNumber x = z.inverse(); //System.out.println("x = " + x); //System.out.println("a = " + a); c = a.monic(); //System.out.println("c = " + c); d = a.multiply(x); //System.out.println("d = " + d); assertEquals("a.monic() = a(1/ldcf(a))", c, d); } AlgebraicNumber y = b.leadingBaseCoefficient(); if (y.isUnit()) { y = y.inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = new GenPolynomial>(fac, y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b))*b", c, d); } } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test object quotient and remainder. */ public void testQuotRem1() { fac = new GenPolynomialRing>(cfac, 1); a = fac.random(ll).monic(); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll).monic(); assertTrue("not isZERO( b )", !b.isZERO()); GenPolynomial> g = fac.random(ll).monic(); assertTrue("not isZERO( g )", !g.isZERO()); g = fac.getONE(); a = a.multiply(g); b = b.multiply(g); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("g = " + g); GenPolynomial>[] qr; qr = b.quotientRemainder(a); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(a).sum(d); assertEquals("b = q a + r", b, e); qr = a.quotientRemainder(b); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(b).sum(d); assertEquals("a = q b + r", a, e); // gcd tests ------------------------------- c = a.gcd(b); //System.out.println("gcd = " + c); assertTrue("a mod gcd(a,b) = 0", a.remainder(c).isZERO()); assertTrue("b mod gcd(a,b) = 0", b.remainder(c).isZERO()); assertEquals("g = gcd(a,b)", c, g); GenPolynomial>[] gst; gst = a.egcd(b); //System.out.println("egcd = " + gst[0]); //System.out.println(", s = " + gst[1] + ", t = " + gst[2]); c = gst[0]; d = gst[1]; e = gst[2]; assertEquals("g = gcd(a,b)", c, g); GenPolynomial> x; x = a.multiply(d).sum(b.multiply(e)).monic(); //System.out.println("x = " + x); assertEquals("gcd(a,b) = a s + b t", c, x); //System.out.println("g = " + g); //System.out.println("h = " + h); if (a.isZERO() || b.isZERO()) { return; } try { c = a.modInverse(b); //System.out.println("c = " + c); x = c.multiply(a).remainder(b).monic(); //System.out.println("x = " + x); assertTrue("a invertible mod b", x.isUnit()); } catch (RuntimeException e) { // dann halt nicht } } } java-algebra-system-2.7.200/trc/edu/jas/poly/GaloisFieldTest.java000066400000000000000000000344201445075545500245330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.poly.GenPolynomial; //import edu.jas.structure.RingElem; /** * Galois field tests with JUnit. * @author Heinz Kredel */ public class GaloisFieldTest extends TestCase { /** * main */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a GaloisFieldTest object. * @param name String. */ public GaloisFieldTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(GaloisFieldTest.class); return suite; } AlgebraicNumberRing fac; GenPolynomialRing mfac; AlgebraicNumber< ModInteger > a, b, c, d, e; int rl = 1; int kl = 10; int ll = 15; int el = ll; float q = 0.5f; protected long getPrime() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for ( int i = 1; i < 60; i++ ) { prime *= 2; } prime -= 93; //System.out.println("prime = " + prime); return prime; } protected void setUp() { a = b = c = d = e = null; long prime = getPrime(); mfac = new GenPolynomialRing( new ModIntegerRing(prime), 1 ); //System.out.println("mfac = " + mfac); GenPolynomial mo = mfac.random(kl,ll,el,q); while ( mo.isConstant() ) { mo = mfac.random(kl,ll,el,q); } fac = new AlgebraicNumberRing( mo ); //System.out.println("fac = " + fac); } protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); assertTrue("length( c ) = 1", c.getVal().length() == 1); assertTrue("isZERO( c )", !c.getVal().isZERO() ); assertTrue("isONE( c )", c.getVal().isONE() ); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); assertTrue("length( d ) = 0", d.getVal().length() == 0); assertTrue("isZERO( d )", d.getVal().isZERO() ); assertTrue("isONE( d )", !d.getVal().isONE() ); } /** * Test random polynomial */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll+i); //System.out.println("a = " + a); // fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a"+i+" ) <> 0", a.getVal().length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.getVal().isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.getVal().isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = fac.random(ll); d = c.sum( a.sum(b) ); e = c.sum( a ).sum(b); assertEquals("c+(a+b) = (c+a)+b",d,e); c = a.sum( fac.getZERO() ); d = a.subtract( fac.getZERO() ); assertEquals("a+0 = a-0",c,d); c = fac.getZERO().sum( a ); d = fac.getZERO().subtract( a.negate() ); assertEquals("0+a = 0+(-a)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); c = a.multiply( fac.getONE() ); d = fac.getONE().multiply( a ); assertEquals("a*1 = 1*a",c,d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1",fac.getONE(),d); } /** * Test distributive law. */ public void testDistributive() { a = fac.random( ll ); b = fac.random( ll ); c = fac.random( ll ); d = a.multiply( b.sum(c) ); e = a.multiply( b ).sum( a.multiply(c) ); assertEquals("a(b+c) = ab+ac",d,e); } /** * Test chinese remainder. */ public void testChineseRemainder() { ModIntegerRing cfac; GenPolynomialRing m0fac; GenPolynomial x0; GenPolynomial x; GenPolynomial m0; GenPolynomial m1; GenPolynomial m01; AlgebraicNumberRing fac0; AlgebraicNumberRing fac1; AlgebraicNumberRing fac01; cfac = new ModIntegerRing(19); //System.out.println("cfac = " + cfac.getModul()); m0fac = new GenPolynomialRing( cfac, 0 ); //System.out.println("m0fac = " + m0fac); mfac = new GenPolynomialRing( cfac, 1 ); //System.out.println("mfac = " + mfac); x0 = m0fac.getONE(); //System.out.println("x0 = " + x0); x = x0.extend(mfac,0,1); //System.out.println("x = " + x); m0 = mfac.fromInteger(2); m1 = mfac.fromInteger(5); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m0 = x.subtract(m0); m1 = x.subtract(m1); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m01 = m0.multiply(m1); //System.out.println("m01 = " + m01); fac0 = new AlgebraicNumberRing( m0, true ); fac1 = new AlgebraicNumberRing( m1, true ); fac01 = new AlgebraicNumberRing( m01, false ); //System.out.println("fac0 = " + fac0); //System.out.println("fac1 = " + fac1); //System.out.println("fac01 = " + fac01); a = fac01.random( 9 ); //System.out.println("a = " + a); b = new AlgebraicNumber(fac0,a.getVal()); //System.out.println("b = " + b); c = new AlgebraicNumber(fac1,a.getVal()); //System.out.println("c = " + c); d = new AlgebraicNumber(fac1,m0); //System.out.println("d = " + d); d = d.inverse(); //System.out.println("d = " + d); e = fac01.chineseRemainder(b,d,c); //System.out.println("e = " + e); assertEquals("cra(a mod (x-m0),a mod (x-m1)) = a (mod 19)",a,e); cfac = new ModIntegerRing(getPrime()); //System.out.println("cfac = " + cfac.getModul()); m0fac = new GenPolynomialRing( cfac, 0 ); //System.out.println("m0fac = " + m0fac); mfac = new GenPolynomialRing( cfac, 1 ); //System.out.println("mfac = " + mfac); x0 = m0fac.getONE(); //System.out.println("x0 = " + x0); x = x0.extend(mfac,0,1); //System.out.println("x = " + x); m0 = mfac.fromInteger(21); m1 = mfac.fromInteger(57); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m0 = x.subtract(m0); m1 = x.subtract(m1); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m01 = m0.multiply(m1); //System.out.println("m01 = " + m01); fac0 = new AlgebraicNumberRing( m0, true ); fac1 = new AlgebraicNumberRing( m1, true ); fac01 = new AlgebraicNumberRing( m01, false ); //System.out.println("fac0 = " + fac0); //System.out.println("fac1 = " + fac1); //System.out.println("fac01 = " + fac01); for ( int i = 0; i < 5; i++ ) { a = fac01.random( 9 ); //System.out.println("a = " + a); b = new AlgebraicNumber(fac0,a.getVal()); //System.out.println("b = " + b); c = new AlgebraicNumber(fac1,a.getVal()); //System.out.println("c = " + c); d = new AlgebraicNumber(fac1,m0); //System.out.println("d = " + d); d = d.inverse(); //System.out.println("d = " + d); e = fac01.chineseRemainder(b,d,c); //System.out.println("e = " + e); assertEquals("cra(a mod (x-m0),a mod (x-m1)) = a (mod 2^60-93)",a,e); } } /** * Test interpolate, is chinese remainder special case. */ public void testInterpolate() { ModIntegerRing cfac; GenPolynomialRing m0fac; GenPolynomial x0; GenPolynomial x; GenPolynomial m0; GenPolynomial m1; GenPolynomial m01; AlgebraicNumberRing fac0; AlgebraicNumberRing fac1; AlgebraicNumberRing fac01; ModInteger cm; ModInteger ci; ModInteger di; cfac = new ModIntegerRing(19); //System.out.println("cfac = " + cfac.getModul()); m0fac = new GenPolynomialRing( cfac, 0 ); //System.out.println("m0fac = " + m0fac); mfac = new GenPolynomialRing( cfac, 1 ); //System.out.println("mfac = " + mfac); x0 = m0fac.getONE(); //System.out.println("x0 = " + x0); x = x0.extend(mfac,0,1); //System.out.println("x = " + x); m0 = mfac.fromInteger(2); m1 = mfac.fromInteger(5); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m0 = x.subtract(m0); m1 = x.subtract(m1); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m01 = m0.multiply(m1); //System.out.println("m01 = " + m01); fac0 = new AlgebraicNumberRing( m0, true ); fac1 = new AlgebraicNumberRing( m1, true ); fac01 = new AlgebraicNumberRing( m01, false ); //System.out.println("fac0 = " + fac0); //System.out.println("fac1 = " + fac1); //System.out.println("fac01 = " + fac01); a = fac01.random( 9 ); //System.out.println("a = " + a); b = new AlgebraicNumber(fac0,a.getVal()); //System.out.println("b = " + b); c = new AlgebraicNumber(fac1,a.getVal()); //System.out.println("c = " + c); cm = fac1.modul.trailingBaseCoefficient(); //System.out.println("cm = " + cm); ci = c.val.trailingBaseCoefficient(); //System.out.println("ci = " + ci); d = new AlgebraicNumber(fac1,m0); //System.out.println("d = " + d); d = d.inverse(); //System.out.println("d = " + d); di = d.val.leadingBaseCoefficient(); //System.out.println("di = " + di); e = fac01.interpolate(b,di,cm,ci); //System.out.println("e = " + e); assertEquals("cra(a mod (x-m0),a mod (x-m1)) = a (mod 19)",a,e); cfac = new ModIntegerRing(getPrime()); //System.out.println("cfac = " + cfac.getModul()); m0fac = new GenPolynomialRing( cfac, 0 ); //System.out.println("m0fac = " + m0fac); mfac = new GenPolynomialRing( cfac, 1 ); //System.out.println("mfac = " + mfac); x0 = m0fac.getONE(); //System.out.println("x0 = " + x0); x = x0.extend(mfac,0,1); //System.out.println("x = " + x); m0 = mfac.fromInteger(21); m1 = mfac.fromInteger(57); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m0 = x.subtract(m0); m1 = x.subtract(m1); //System.out.println("m0 = " + m0); //System.out.println("m1 = " + m1); m01 = m0.multiply(m1); //System.out.println("m01 = " + m01); fac0 = new AlgebraicNumberRing( m0, true ); fac1 = new AlgebraicNumberRing( m1, true ); fac01 = new AlgebraicNumberRing( m01, false ); //System.out.println("fac0 = " + fac0); //System.out.println("fac1 = " + fac1); //System.out.println("fac01 = " + fac01); for ( int i = 0; i < 5; i++ ) { a = fac01.random( 9 ); //System.out.println("a = " + a); b = new AlgebraicNumber(fac0,a.getVal()); //System.out.println("b = " + b); c = new AlgebraicNumber(fac1,a.getVal()); //System.out.println("c = " + c); cm = fac1.modul.trailingBaseCoefficient(); //System.out.println("cm = " + cm); ci = c.val.trailingBaseCoefficient(); //System.out.println("ci = " + ci); d = new AlgebraicNumber(fac1,m0); //System.out.println("d = " + d); d = d.inverse(); //System.out.println("d = " + d); di = d.val.leadingBaseCoefficient(); //System.out.println("di = " + di); e = fac01.interpolate(b,di,cm,ci); //System.out.println("e = " + e); assertEquals("cra(a mod (x-m0),a mod (x-m1)) = a (mod 2^60-93)",a,e); } } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenExteriorPolynomialTest.java000066400000000000000000001166701445075545500266600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.TreeMap; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.structure.RingElem; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenExteriorPolynomial tests with JUnit. * @author Heinz Kredel */ public class GenExteriorPolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenExteriorPolynomialTest object. * @param name String. */ public GenExteriorPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GenExteriorPolynomialTest.class); return suite; } int rl = 6; int kl = 8; int ll = 6; int el = 4; float ql = 0.4f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructors and factory. */ public void testConstructors() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf); assertFalse("not commutative", pf.isCommutative()); assertTrue("associative", pf.isAssociative()); assertFalse("not field", pf.isField()); assertEquals("pf == pf: ", pf, pf); String s = pf.toScript(); //System.out.println("pf.toScript: " + s + ", " + s.length()); assertTrue("#s >= 35: " + s, s.length() >= 35); s = pf.toString(); //System.out.println("pf.toString: " + s + ", " + s.length()); assertTrue("#s >= 40: " + s, s.length() >= 40); GenExteriorPolynomial p = pf.getONE(); //System.out.println("p = " + p); assertTrue("p == 1", p.isONE()); p = pf.getZERO(); assertTrue("p == 0", p.isZERO()); //System.out.println("p = " + p); //p = pf.random(kl, ll, el); //System.out.println("p = " + p); List> gens = pf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 7", gens.size() == 7); gens = pf.getGenerators(); //System.out.println("gens = " + gens); assertTrue("#gens == 7", gens.size() == 7); RingElem> pe = new GenExteriorPolynomial(pf); //System.out.println("pe = " + pe); //System.out.println("p.equals(pe) = " + p.equals(pe) ); //System.out.println("p.equals(p) = " + p.equals(p) ); assertTrue("p.equals(pe) = ", p.equals(pe)); assertTrue("p.equals(p) = ", p.equals(p)); pe = pe.sum(p); //System.out.println("pe = " + pe); assertTrue("pe.isZERO() = ", pe.isZERO()); //p = pf.random(9); p = pf.random(kl, ll, el); p = p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // polynomials over (polynomials over integers) // 3 non-commuting vars IndexFactory wf2 = new IndexFactory(3); //System.out.println("wf2 = " + wf2); GenExteriorPolynomialRing> ppf; ppf = new GenExteriorPolynomialRing>(pf, wf2); //System.out.println("ppf = " + ppf); GenExteriorPolynomial> pp = ppf.getONE(); //System.out.println("pp = " + pp); assertTrue("pp == 1", pp.isONE()); //pp = ppf.random(2); pp = ppf.random(kl, ll, el); //System.out.println("pp = " + pp); pp = ppf.getZERO(); //System.out.println("pp = " + pp); assertTrue("pp == 0", pp.isZERO()); List>> pgens = ppf.generators(); //System.out.println("pgens = " + pgens); assertTrue("#pgens == 7+3", pgens.size() == 10); RingElem>> ppe; ppe = new GenExteriorPolynomial>(ppf); //System.out.println("ppe = " + ppe); //System.out.println("pp.equals(ppe) = " + pp.equals(ppe) ); //System.out.println("pp.equals(pp) = " + pp.equals(pp) ); assertTrue("pp.equals(ppe) = ", pp.equals(ppe)); assertTrue("pp.equals(pp) = ", pp.equals(pp)); ppe = ppe.sum(pp); // why not pp = pp.sum(ppe) ? //System.out.println("ppe = " + ppe); assertTrue("ppe.isZERO() = ", ppe.isZERO()); //pp = ppf.random(2); pp = ppf.random(kl, ll, el); //System.out.println("pp = " + pp); pp = pp.subtract(pp); //System.out.println("pp.isZERO() = " + pp.isZERO()); assertTrue("pp.isZERO() = ", pp.isZERO()); // polynomials over (polynomials over (polynomials over integers)) // 3 non-commuting vars IndexFactory wf3 = new IndexFactory(3); //System.out.println("wf3 = " + wf3); GenExteriorPolynomialRing>> pppf; pppf = new GenExteriorPolynomialRing>>(ppf, wf3); //System.out.println("pppf = " + pppf); GenExteriorPolynomial>> ppp = pppf.getONE(); //System.out.println("ppp = " + ppp); assertTrue("ppp == 1", ppp.isONE()); //ppp = pppf.random(2); ppp = pppf.random(kl, ll, el); //System.out.println("ppp = " + ppp); ppp = pppf.getZERO(); //System.out.println("ppp = " + ppp); assertTrue("ppp == 0", ppp.isZERO()); List>>> ppgens = pppf .generators(); //System.out.println("ppgens = " + ppgens); assertTrue("#ppgens == 7+3+3", ppgens.size() == 13); RingElem>>> pppe; pppe = new GenExteriorPolynomial>>(pppf); //System.out.println("pppe = " + pppe); // System.out.println("ppp.equals(pppe) = " + ppp.equals(pppe) ); // System.out.println("ppp.equals(ppp) = " + ppp.equals(ppp) ); assertTrue("ppp.equals(pppe) = ", ppp.equals(pppe)); assertTrue("ppp.equals(ppp) = ", ppp.equals(ppp)); pppe = pppe.sum(ppp); //System.out.println("pppe = " + pppe); assertTrue("pppe.isZERO() = ", pppe.isZERO()); //ppp = pppf.random(2); ppp = pppf.random(kl, ll, el); //System.out.println("ppp = " + ppp); ppp = ppp.subtract(ppp); //System.out.println("ppp.isZERO() = " + ppp.isZERO()); assertTrue("ppp.isZERO() = ", ppp.isZERO()); } /** * Test accessors. */ public void testAccessors() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf); // test 1 GenExteriorPolynomial p = pf.getONE(); //System.out.println("p = " + p); IndexList e = p.leadingIndexList(); BigInteger c = p.leadingBaseCoefficient(); GenExteriorPolynomial f = new GenExteriorPolynomial(pf, c, e); assertEquals("1 == 1 ", p, f); GenExteriorPolynomial r = p.reductum(); assertTrue("red(1) == 0 ", r.isZERO()); // test 0 p = pf.getZERO(); // System.out.println("p = " + p); e = p.leadingIndexList(); c = p.leadingBaseCoefficient(); f = new GenExteriorPolynomial(pf, c, e); assertEquals("0 == 0 ", p, f); r = p.reductum(); assertTrue("red(0) == 0 ", r.isZERO()); // test random p = pf.random(kl, ll, el); //System.out.println("p = " + p); e = p.leadingIndexList(); c = p.leadingBaseCoefficient(); r = p.reductum(); f = new GenExteriorPolynomial(pf, c, e); f = r.sum(f); assertEquals("p == lm(f)+red(f) ", p, f); // test iteration over random GenExteriorPolynomial g; g = p; f = pf.getZERO(); while (!g.isZERO()) { e = g.leadingIndexList(); c = g.leadingBaseCoefficient(); //System.out.println("c e = " + c + " " + e); r = g.reductum(); f = f.sum(c, e); g = r; } assertEquals("p == lm(f)+lm(red(f))+... ", p, f); } /** * Test addition. */ public void testAddition() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing fac = new GenExteriorPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenExteriorPolynomial a = fac.random(kl, ll, el); GenExteriorPolynomial b = fac.random(kl, ll, el); GenExteriorPolynomial c = a.sum(b); GenExteriorPolynomial d = c.subtract(b); GenExteriorPolynomial e; assertEquals("a+b-b = a", a, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("deg(a+b) >= deg(a)", c.degree() >= a.degree()); assertTrue("deg(a+b) >= deg(b)", c.degree() >= b.degree()); c = fac.random(kl, ll, el); //System.out.println("\nc = " + c); d = a.sum(b.sum(c)); e = (a.sum(b)).sum(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e) ); assertEquals("a+(b+c) = (a+b)+c", d, e); IndexList u = wf.random(rl); BigInteger x = rf.random(kl); b = new GenExteriorPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); //System.out.println("\nc = " + c); //System.out.println("d = " + d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = new GenExteriorPolynomial(fac); b = new GenExteriorPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); } /** * Test multiplication. */ public void testMultiplication() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing fac = new GenExteriorPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenExteriorPolynomial a = fac.random(kl, ll, el); GenExteriorPolynomial b = fac.random(kl, ll, el); GenExteriorPolynomial c = a.multiply(b); GenExteriorPolynomial d = b.multiply(a); GenExteriorPolynomial e; //assertFalse("a*b != b*a: " + a + " /\\ " + b + " == " + c, c.equals(d)); // to many fails //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("maxNorm(a*b) >= maxNorm(a)", c.maxNorm().compareTo(a.maxNorm()) >= 0); assertTrue("maxNorm(a*b) >= maxNorm(b)", c.maxNorm().compareTo(b.maxNorm()) >= 0); c = fac.random(kl, ll, el); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e) ); assertEquals("a*(b*c) = (a*b)*c:", d, e); e = b.multiply(a,c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a*(b*c) = a*b*c:", d, e); IndexList u = wf.random(rl); BigInteger x = rf.random(kl); b = new GenExteriorPolynomial(fac, x, u); c = a.multiply(b); d = a.multiply(x, u); assertEquals("a*p(x,u) = a*(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = new GenExteriorPolynomial(fac); b = new GenExteriorPolynomial(fac, x, u); c = a.multiply(b); d = a.multiply(x, u); assertEquals("a*p(x,u) = a*(x,u)", c, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); BigInteger y = rf.random(kl); c = a.multiply(x, y); //System.out.println("c = " + c); d = a.multiply(y, x); //System.out.println("d = " + d); assertEquals("x a y = y a x", c, d); IndexList v = wf.random(rl); c = a.multiply(x, u, y, v); //System.out.println("c = " + c); d = a.multiply(y, u, x, v); //System.out.println("d = " + d); assertEquals("x u a y v = y u a x v", c, d); c = a.multiply(u, v); //System.out.println("c = " + c); d = a.multiply(rf.getONE(), u, v); //System.out.println("d = " + d); assertEquals("u a v = 1 u a v", c, d); } /** * Test distributive law. */ public void testDistributive() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing fac = new GenExteriorPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenExteriorPolynomial a = fac.random(kl, ll, el); GenExteriorPolynomial b = fac.random(kl, ll, el); GenExteriorPolynomial c = fac.random(kl, ll, el); GenExteriorPolynomial d, e; d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test division. */ public void testDivision() { // rational BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf); // polynomials over integers GenExteriorPolynomialRing fac = new GenExteriorPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenExteriorPolynomial a = fac.random(kl + 2, ll, el); GenExteriorPolynomial b = fac.random(kl - 1, ll, 2); GenExteriorPolynomial c, d, e; //System.out.println("a = " + a); //System.out.println("b = " + b); //c = fac.getZERO(); //d = a; GenExteriorPolynomial[] qr = a.quotientRemainder(fac.getONE()); c = qr[0]; d = qr[1]; //System.out.println("c = " + c); //System.out.println("d = " + d); e = c.multiply(fac.getONE()).sum(d); //System.out.println("e = " + e); assertEquals("a = 0 a + a: ", a, e); // //c = fac.getONE(); // //d = fac.getZERO(); // qr = a.quotientRemainder(b); // c = qr[0]; // d = qr[1]; // //System.out.println("q = " + c); // //System.out.println("r = " + d); // e = c.multiply(b).sum(d); // //System.out.println("q b = " + c.multiply(b)); // //System.out.println("e = " + e); // assertEquals("a = q b + r: ", a, e); } /* * Test constructors and factory. */ @SuppressWarnings("unchecked") public void testParser() { BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf.toScriptFactory()); // commuting vars: abcdef String[] sa = new String[] { "a", "b", "c", "d", "e", "f" }; //String ss = "E(1,2,3,4,5,6)"; IndexFactory wf = new IndexFactory(6); //System.out.println("wf = " + wf.toScript()); // index list polynomials over integers GenExteriorPolynomialRing pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); assertFalse("not commutative", pf.isCommutative()); assertTrue("associative", pf.isAssociative()); assertFalse("not field", pf.isField()); List> gens = pf.generators(); //System.out.println("gens = " + gens); GenExteriorPolynomial g1, g2, g3, g4, epol; g1 = gens.get(1); g2 = gens.get(2); g3 = gens.get(3); g4 = gens.get(4); //System.out.println("g1 = " + g1 + ", " + g1.toScript()); //System.out.println("g2 = " + g2); assertEquals("#s == 5: ", g1.toString().length(), 5); assertEquals("#s == 4: ", g2.toScript().length(), 4); epol = g1.multiply(g2).subtract(g3.multiply(g4)); //System.out.println("epol = " + epol); //StringReader sr = new StringReader("1 E(1,2)**2 + E(1,2) - 1 E(3,4)**0"); StringReader sr = new StringReader("1 E(1,2) - 1 E(3,4)"); GenPolynomialTokenizer tok = new GenPolynomialTokenizer(sr); GenExteriorPolynomial a, b; // parse of tokenizer try { a = (GenExteriorPolynomial) tok.nextExteriorPolynomial(pf); } catch (IOException e) { a = null; e.printStackTrace(); } //System.out.println("a = " + a); assertEquals("parse() == ab - ba: ", a, epol); // now parse of factory a = pf.parse("1 E(1,2) - 1 E(3,4)"); //System.out.println("a = " + a); assertEquals("parse() == 1 E(1,2) - 1 E(3,4): ", a, epol); // commutative polynomials over integers GenPolynomialRing fac = new GenPolynomialRing(rf, sa); //System.out.println("fac = " + fac.toScript()); assertTrue("commutative", fac.isCommutative()); assertTrue("associative", fac.isAssociative()); assertFalse("not field", fac.isField()); sr = new StringReader("E(1,2) - E(3,4)"); tok = new GenPolynomialTokenizer(fac, sr); // parse exterior with tokenizer try { a = (GenExteriorPolynomial) tok.nextExteriorPolynomial(); } catch (IOException e) { a = null; e.printStackTrace(); } //System.out.println("a = " + a); assertEquals("parse() == E(1,2) - E(3,4): ", a, epol); } /** * Test iterators. */ public void testIterators() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // index list polynomials over integral numbers GenExteriorPolynomialRing pf = new GenExteriorPolynomialRing(rf, "abcdef"); //System.out.println("pf = " + pf); // random polynomial GenExteriorPolynomial p = pf.random(kl, 2 * ll, el); //System.out.println("p = " + p); // test monomials for (IndexListMonomial m : p) { //System.out.println("m = " + m); assertFalse("m.c == 0 ", m.coefficient().isZERO()); assertFalse("m.e == 0 ", m.indexlist().isZERO()); } } /** * Test matrix and vector. */ public void testMatrix() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // matrix size int c = 13; // to big 23; IndexFactory ixfac = new IndexFactory(c); //System.out.println("ixfac = " + ixfac); // exterior polynomials over rational numbers GenExteriorPolynomialRing epf; epf = new GenExteriorPolynomialRing(rf, ixfac); //System.out.println("epf = " + epf.toScript()); // matrix over rational numbers int r = c; GenMatrixRing mf = new GenMatrixRing(rf, r, r); //System.out.println("mf = " + mf.toScript()); GenMatrix A = mf.getONE(); //System.out.println("A = " + A); List> em = epf.fromMatrix(A); //System.out.println("em = " + em); assertEquals("#em == #A: ", em.size(), A.ring.rows); BigRational dr = epf.determinant(em); //System.out.println("dr = " + dr); assertTrue("det(em) == 1: ", dr.isONE()); A = mf.getZERO(); //System.out.println("A = " + A); em = epf.fromMatrix(A); //System.out.println("em = " + em); assertEquals("#em == #A: ", em.size(), 0); dr = epf.determinant(em); //System.out.println("dr = " + dr); assertTrue("det(em) == 0: ", dr.isZERO()); A = mf.randomUpper(3, 0.55f); //System.out.println("A = " + A); em = epf.fromMatrix(A); //System.out.println("em = " + em); assertTrue("#em <= #A: ", em.size() <= A.matrix.size()); dr = epf.determinant(em); //System.out.println("dr = " + dr); assertTrue("det(em) == 0: ", dr.isZERO()); A = mf.random(5, 0.67f); //System.out.println("A = " + A); em = epf.fromMatrix(A); //System.out.println("em = " + em); assertTrue("#em <= #A: ", em.size() <= A.matrix.size()); dr = epf.determinant(em); //System.out.println("dr = " + dr); assertFalse("det(em) != 0: ", dr.isZERO()); GenPolynomialRing fac; fac = new GenPolynomialRing(rf, new String[] { "lambda" }); //System.out.println("fac = " + fac.toScript()); //System.out.println("A = " + A); //GenPolynomial cp = fac.charPolynomial(A); //System.out.println("cp = " + cp); //BigRational er = fac.determinantFromCharPol(cp); BigRational er = fac.determinant(A); //System.out.println("\ner = " + er); //System.out.println("dr = " + dr); assertEquals("det_exterior(A) == det_charpol(A): ", dr, er); } /* * Test conversions. */ public void testConversion() { BigRational rf = new BigRational(); //System.out.println("rf = " + rf.toScriptFactory()); IndexFactory wf = new IndexFactory(0, 20); //System.out.println("wf = " + wf.toScript()); // exterior polynomials over integers GenExteriorPolynomialRing pf; pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); // commutative polynomials over rationals GenPolynomialRing fac; fac = new GenPolynomialRing(rf, new String[] { "a", "b", "c", "d" }); //System.out.println("fac = " + fac.toScript()); GenPolynomial p = fac.random(kl / 2, ll, 2, ql); //System.out.println("p = " + p); GenExteriorPolynomial a = pf.valueOf(p); //System.out.println("a = " + a); List> Pl = new ArrayList>(); Pl.add(p); List> El = pf.valueOf(Pl); assertEquals("a == El[0]: ", a, El.get(0)); assertEquals("sumNorm(p) == sumNorm(a): ", p.sumNorm(), a.sumNorm()); GenExteriorPolynomial b = pf.valueOf(a); //System.out.println("b = " + b); assertEquals("a == b: ", a, b); GenExteriorPolynomial c = pf.fromInteger(7); //System.out.println("c = " + c); assertEquals("7 == ldcf(c): ", rf.fromInteger(7), c.leadingBaseCoefficient()); } /* * Test resultant. */ public void testResultant() { BigRational rf = new BigRational(); //System.out.println("rf = " + rf.toScriptFactory()); IndexFactory wf = new IndexFactory(0, 20); //System.out.println("wf = " + wf.toScript()); // exterior polynomials over rationals GenExteriorPolynomialRing pf; pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); // commutative univariate polynomials over rationals GenPolynomialRing fac; fac = new GenPolynomialRing(rf, new String[] { "i" }); //System.out.println("fac = " + fac.toScript()); GenPolynomial p = fac.random(kl / 2, ll, el, ql); //System.out.println("p = " + p); GenPolynomial q = fac.random(kl / 2, ll, el, ql); //System.out.println("q = " + q); BigRational r = pf.resultant(p, q); //System.out.println("r = " + r); GenPolynomial g = p.gcd(q); //System.out.println("g = " + g); assertTrue("res != 0 && gcd == 1: " + r + ", " + g, !r.isZERO() && g.isONE()); //System.out.println("fac.gens = " + fac.generators()); GenPolynomial f = fac.random(kl / 3, ll, el / 2, ql); f = f.sum(fac.generators().get(1)); //System.out.println("f = " + f); p = p.multiply(f); q = q.multiply(f); //System.out.println("p = " + p); //System.out.println("q = " + q); r = pf.resultant(p, q); //System.out.println("r = " + r); g = p.gcd(q); //System.out.println("g = " + g); assertTrue("res == 0 && gcd != 1: " + r + ", " + g, r.isZERO() && !g.isONE()); } /* * Test old example after Blonski, 1983. */ //@SuppressWarnings("unchecked") public void testExample() { BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf.toScriptFactory()); // non-commuting indexes: 1 2 3 4 //String ss = "E(1,2,3,4)"; IndexFactory wf = new IndexFactory(4); // (1,4) //System.out.println("wf = " + wf.toScript()); // index list polynomials over integers GenExteriorPolynomialRing pf; pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); assertFalse("not commutative", pf.isCommutative()); assertTrue("associative", pf.isAssociative()); assertFalse("not field", pf.isField()); GenExteriorPolynomial emaxd, p1, p2, q1, q2, s, g1, g2, e1, e2, e1dual, e2dual, q, qs, qt, g1dual, g2dual, s1, s2; // parse points in 4-space as polynomials emaxd = pf.parse("E(1,2,3,4)"); // wf.imax //System.out.println("emaxd = " + emaxd + ", imax = " + pf.ixfac.imax); p1 = pf.parse("1 E(1) + 5 E(2) - 2 E(3) + 1 E(4)"); p2 = pf.parse("4 E(1) + 3 E(2) + 6 E(3) + 1 E(4)"); //System.out.println("p1 = " + p1); //System.out.println("p2 = " + p2); q1 = pf.parse("3 E(1) - 2 E(2) - 1 E(3) + 1 E(4)"); q2 = pf.parse("1 E(2) + 5 E(3) + 1 E(4)"); //System.out.println("q1 = " + q1); //System.out.println("q2 = " + q2); s = pf.parse("1 E(3) + 1 E(4)"); //System.out.println("s = " + s); // compute line(gerade) p1..p2 and q1..q2 g1 = p1.multiply(p2).abs(); g2 = q1.multiply(q2).abs().divide(new BigInteger(3)); //System.out.println("g1 = p1 /\\ p2 = " + g1); //System.out.println("g2 = q1 /\\ q2 = " + g2); //System.out.println("pp(g2) = " + q1.multiply(q2).coeffPrimitivePart()); assertEquals("g2 == pp(g2): ", g2, q1.multiply(q2).coeffPrimitivePart()); // compute plane(ebene) g1..s and g2..s e1 = g1.multiply(s).abs().divide(new BigInteger(17)); e2 = g2.multiply(s); //System.out.println("e1 = g1 /\\ s = " + e1); //System.out.println("e2 = g2 /\\ s = " + e2); assertEquals("e1 == pp(e1): ", e1, g1.multiply(s).coeffPrimitivePart()); // compute dual planes of e1, e2 as e1..emaxd and e2..emaxd e1dual = e1.interiorRightProduct(emaxd).abs(); e2dual = e2.interiorRightProduct(emaxd).abs(); //System.out.println("e1dual = e1 |_ emaxd = " + e1dual); //System.out.println("e2dual = e2 |_ emaxd = " + e2dual); // compute intersection of plane e1, e2 via dual plane sum q = e1dual.multiply(e2dual).abs().divide(new BigInteger(5)); //System.out.println("q = (e1dual /\\ e2dual) = " + q); assertEquals("q == pp(q): ", q, e1dual.multiply(e2dual).coeffPrimitivePart()); qs = q.interiorRightProduct(emaxd).abs(); //System.out.println("qs = (e1dual /\\ e2dual) |_ emaxd = " + qs); qt = e1.interiorLeftProduct(e2dual).abs().divide(new BigInteger(5)); //System.out.println("qt = e1 _| e2dual = " + qt); assertEquals("qt == pp(qt): ", qt, e1.interiorLeftProduct(e2dual).coeffPrimitivePart()); assertEquals("qs == qt: ", qs, qt); // compute dual line(gerade) of g1, g2 g1dual = g1.interiorRightProduct(emaxd); g2dual = g2.interiorRightProduct(emaxd).abs(); //System.out.println("g1dual = g1 |_ emaxd = " + g1dual); //System.out.println("g2dual = g2 |_ emaxd = " + g2dual); // compute intersection of g1..e2 and g2..e1 s1 = e2.interiorLeftProduct(g1dual).abs().divide(new BigInteger(5)); //System.out.println("s1 = e2 _| g1dual = " + s1); s2 = e1.interiorLeftProduct(g2dual).abs().divide(new BigInteger(5)); //System.out.println("s2 = e1 _| g2dual = " + s2); // check intersection of s..qs, qs..e1 and qs..e2 //System.out.println(" s /\\ qs = s \\in qs = " + s.multiply(qs)); //System.out.println("qs /\\ e1 = qs \\in e1 = " + qs.multiply(e1)); //System.out.println("qs /\\ e2 = qs \\in e2 = " + qs.multiply(e2)); assertTrue("qs /\\ s == 0: ", qs.multiply(s).isZERO()); assertTrue("qs /\\ e1 == 0: ", qs.multiply(e1).isZERO()); assertTrue("qs /\\ e2 == 0: ", qs.multiply(e2).isZERO()); } /** * Test exterior derivation. */ @SuppressWarnings("unchecked") public void testDerivation() { // rationals BigRational rf = new BigRational(); //System.out.println("rf = " + rf.toScriptFactory()); // 3/6 commuting vars String[] vars = new String[] { "x1", "x2", "x3" }; //System.out.println("vars = " + Arrays.toString(vars)); // polynomials over rationals GenPolynomialRing pf = new GenPolynomialRing(rf, vars); //System.out.println("pf = " + pf); String s = pf.toScript(); //System.out.println("pf.toScript: " + s + ", " + s.length()); assertEquals("#s == 38: " + s, s.length(), 38); s = pf.toString(); //System.out.println("pf.toString: " + s + ", " + s.length()); assertEquals("#s == 31: " + s, s.length(), 31); GenPolynomial p = pf.getONE(); //System.out.println("p = " + p); assertTrue("p == 1", p.isONE()); p = pf.getZERO(); assertTrue("p == 0", p.isZERO()); //System.out.println("p = " + p); List> gens = pf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 4", gens.size() == 4); RingElem> pe = new GenPolynomial(pf); //System.out.println("pe = " + pe); assertTrue("p.equals(pe) = ", p.equals(pe)); assertTrue("p.equals(p) = ", p.equals(p)); pe = pe.sum(p); //System.out.println("pe = " + pe); assertTrue("pe.isZERO() = ", pe.isZERO()); //p = pf.random(9); p = pf.random(kl, ll, el, ql); p = p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // exterior polynomials over (polynomials over rationals) // 3 non-commuting vars IndexFactory wf2 = new IndexFactory(3); //System.out.println("wf2 = " + wf2); GenExteriorPolynomialRing> ppf; ppf = new GenExteriorPolynomialRing>(pf, wf2); //System.out.println("ppf = " + ppf.toScript()); GenExteriorPolynomial> pp = ppf.getONE(); //System.out.println("pp = " + pp); assertTrue("pp == 1", pp.isONE()); pp = ppf.getZERO(); //System.out.println("pp = " + pp); assertTrue("pp == 0", pp.isZERO()); List>> pgens = ppf.generators(); //System.out.println("pgens = " + pgens); assertTrue("#pgens == 4+3", pgens.size() == 4 + 3); assertFalse("commutative", ppf.isCommutative()); assertTrue("associative", ppf.isAssociative()); assertFalse("not field", ppf.isField()); assertEquals("ppf == ppf: ", ppf, ppf); pp = ppf.random(kl, ll, el); //System.out.println("pp = " + pp); long deg = pp.degree(); GenExteriorPolynomial> der; der = PolyUtil. exteriorDerivativePoly(pp); //System.out.println("der = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); deg = der.degree(); der = PolyUtil. exteriorDerivativePoly(der); //System.out.println("der(der) = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); //StringReader sr = new StringReader("x1 x2 x3 E(1)"); StringReader sr = new StringReader("{x1 + x2 + x3} E(1) E(2)"); //StringReader sr = new StringReader("{x1 + x2 + x3**3} E(1)"); // E(2) //System.out.println("sr = " + sr); GenPolynomialTokenizer tok = new GenPolynomialTokenizer(sr); //System.out.println("ppf = " + ppf.toScript()); // parse with tokenizer try { pp = (GenExteriorPolynomial>) tok.nextExteriorPolynomial(ppf); } catch (IOException e) { e.printStackTrace(); return; } //System.out.println("pp = " + pp); deg = pp.degree(); der = PolyUtil. exteriorDerivativePoly(pp); //System.out.println("der = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); deg = der.degree(); der = PolyUtil. exteriorDerivativePoly(der); //System.out.println("der(der) = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); assertTrue("der(der) == 0: ", der.isZERO()); sr = new StringReader("x3 E(1) + x3 E(2)"); //sr = new StringReader("x1 E(1) + x2 E(2)"); //sr = new StringReader("x2 E(1) + x1 E(2)"); //System.out.println("sr = " + sr); tok = new GenPolynomialTokenizer(sr); //System.out.println("ppf = " + ppf.toScript()); // parse with tokenizer try { pp = (GenExteriorPolynomial>) tok.nextExteriorPolynomial(ppf); } catch (IOException e) { e.printStackTrace(); return; } //System.out.println("pp = " + pp); deg = pp.degree(); der = PolyUtil. exteriorDerivativePoly(pp); //System.out.println("der = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); deg = der.degree(); der = PolyUtil. exteriorDerivativePoly(der); //System.out.println("der(der) = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); assertTrue("der(der) == 0: ", der.isZERO()); } /** * Test k-forms. */ public void testForms() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // 6 non-commuting vars IndexFactory wf = new IndexFactory(6, false); //System.out.println("wf = " + wf); IndexFactory wfw = new IndexFactory(6, true); //System.out.println("wfw = " + wfw + ", " + wfw.toScript()); // polynomials over integers GenExteriorPolynomialRing pf = new GenExteriorPolynomialRing(rf, wf); //System.out.println("pf = " + pf); GenExteriorPolynomialRing pfw = new GenExteriorPolynomialRing(rf, wfw); //System.out.println("pfw = " + pfw); // test 1 GenExteriorPolynomial p = pf.getONE(); //System.out.println("p = " + p); assertTrue("homogen(p): ", p.isHomogeneous()); GenExteriorPolynomial q = pf.random(kl, ll*4, rl); //System.out.println("q = " + q); for (int i = 0; i <= wf.imaxlength; i++) { GenExteriorPolynomial h = q.homogeneousPart(i); //System.out.println("h("+ i + ") = " + h); assertTrue("homogen(h): ", h.isHomogeneous()); GenExteriorPolynomial f = q.form(i); //System.out.println("f = " + f); assertTrue("homogen(f): ", f.isHomogeneous()); assertEquals("homogen(h) == form(h): ", h, f); } p = pfw.getZERO(); for (int i = 0; i <= wf.imaxlength; i++) { GenExteriorPolynomial hf = pfw.randomForm(kl, ll, i); //System.out.println("hf(" + i + ") = " + hf); assertTrue("homogen(hf): ", hf.isHomogeneous()); assertTrue("deg(hf): ", hf.isZERO() || hf.degree() == (long)i); p = p.sum(hf); } //System.out.println("p = " + p); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenMatrixTest.java000066400000000000000000000153631445075545500242540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import java.util.ArrayList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.jas.structure.RingElem; //import edu.jas.structure.ModulElem; import edu.jas.arith.BigRational; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; /** * GenMatrix tests with JUnit * @author Heinz Kredel */ public class GenMatrixTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenMatrixTest object. * @param name String. */ public GenMatrixTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GenMatrixTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; int rows = 3; int cols = 3; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. * */ public void testPolynomialConstruction() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenMatrixRing> mfac = new GenMatrixRing>(pfac, rows, cols); assertTrue("#rows = " + rows, mfac.rows == rows); assertTrue("#columns = " + cols, mfac.cols == cols); assertTrue("pfac == coFac ", pfac == mfac.coFac); GenMatrix> a; a = mfac.getZERO(); //System.out.println("a = " + a); assertTrue("isZERO( a )", a.isZERO()); GenMatrix> b = new GenMatrix>(mfac); //System.out.println("b = " + b); assertTrue("isZERO( b )", b.isZERO()); assertTrue("a == b ", a.equals(b)); GenMatrix> c = b.copy(); //System.out.println("c = " + c); assertTrue("isZERO( c )", c.isZERO()); assertTrue("a == c ", a.equals(c)); GenMatrix> d = mfac.copy(b); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("a == d ", a.equals(d)); } /** * Test random matrix * */ public void testPolynomialRandom() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenMatrixRing> mfac = new GenMatrixRing>(pfac, rows, cols); GenMatrix> a; for (int i = 0; i < 5; i++) { a = mfac.random(kl, q); //System.out.println("a = " + a); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); } } /** * Test addition. * */ public void testPolynomialAddition() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenMatrixRing> mfac = new GenMatrixRing>(pfac, rows, cols); GenMatrix> a, b, c, d, e; a = mfac.random(kl, q); b = mfac.random(kl, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = c.sum(b.negate()); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b+(-b) = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = mfac.random(kl, q); d = a.sum(b).sum(c); e = a.sum(b.sum(c)); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test scalar multiplication. * */ public void testPolynomialMultiplication() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenMatrixRing> mfac = new GenMatrixRing>(pfac, rows, cols); GenPolynomial r, s, t; GenMatrix> a, b, c, d, e; r = pfac.random(kl); //System.out.println("r = " + r); s = r.negate(); //System.out.println("s = " + s); a = mfac.random(kl, q); //System.out.println("a = " + a); c = a.scalarMultiply(r); d = a.scalarMultiply(s); e = c.sum(d); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a*b + a*(-b) = 0", e, mfac.getZERO()); b = mfac.random(kl, q); //System.out.println("b = " + b); t = pfac.getONE(); //System.out.println("t = " + t); c = a.linearCombination(b, t); d = b.linearCombination(a, t); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); c = a.linearCombination(b, t); d = a.sum(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); s = t.negate(); //System.out.println("s = " + s); c = a.linearCombination(b, t); d = c.linearCombination(b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); c = a.linearCombination(t, b, t); d = c.linearCombination(t, b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); t = pfac.getZERO(); //System.out.println("t = " + t); c = a.linearCombination(b, t); //System.out.println("c = " + c); assertEquals("a+0*b = a", a, c); d = a.linearCombination(t, b, t); //System.out.println("d = " + d); assertEquals("0*a+0*b = 0", mfac.getZERO(), d); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenPolynomialTest.java000066400000000000000000000665501445075545500251370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Spliterator; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.structure.RingElem; import edu.jas.structure.UnaryFunctor; import edu.jas.util.ListUtil; import edu.jas.util.MapEntry; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class GenPolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenPolynomialTest object. * @param name String. */ public GenPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GenPolynomialTest.class); return suite; } int rl = 6; int kl = 5; int ll = 7; int el = 4; float q = 0.5f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructors and factory. */ public void testConstructors() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); //BigRational r = rf.fromInteger( 99 ); // System.out.println("r = " + r); //r = rf.random( 9 ).sum(r); // System.out.println("r = " + r); //assertFalse("r.isZERO() = ", r.isZERO()); //RingElem re = new BigRational( 3 ); // System.out.println("re = " + re); //rf = (BigRational) re; //RingFactory ref = new BigRational( 3 ); // System.out.println("re = " + re); //rf = (BigRational) ref; // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(rf, 2); // System.out.println("pf = " + pf); GenPolynomial p = pf.getONE(); // System.out.println("p = " + p); p = pf.random(9); // System.out.println("p = " + p); p = pf.getZERO(); // System.out.println("p = " + p); RingElem> pe = new GenPolynomial(pf); //System.out.println("pe = " + pe); //System.out.println("p.equals(pe) = " + p.equals(pe) ); //System.out.println("p.equals(p) = " + p.equals(p) ); assertTrue("p.equals(pe) = ", p.equals(pe)); assertTrue("p.equals(p) = ", p.equals(p)); pe = pe.sum(p); // why not p = p.add(pe) ? //System.out.println("pe = " + pe); assertTrue("pe.isZERO() = ", pe.isZERO()); p = pf.random(9); p = p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // polynomials over (polynomials over rational numbers) GenPolynomialRing> ppf = new GenPolynomialRing>( pf, 3); // System.out.println("ppf = " + ppf); GenPolynomial> pp = ppf.getONE(); // System.out.println("pp = " + pp); pp = ppf.random(2); // System.out.println("pp = " + pp); pp = ppf.getZERO(); // System.out.println("pp = " + pp); RingElem>> ppe = new GenPolynomial>( ppf); // System.out.println("ppe = " + ppe); // System.out.println("pp.equals(ppe) = " + pp.equals(ppe) ); // System.out.println("pp.equals(pp) = " + pp.equals(pp) ); assertTrue("pp.equals(ppe) = ", pp.equals(ppe)); assertTrue("pp.equals(pp) = ", pp.equals(pp)); ppe = ppe.sum(pp); // why not pp = pp.add(ppe) ? //System.out.println("ppe = " + ppe); assertTrue("ppe.isZERO() = ", ppe.isZERO()); pp = ppf.random(2); pp = pp.subtract(pp); //System.out.println("pp = " + pp); //System.out.println("pp.isZERO() = " + pp.isZERO()); assertTrue("pp.isZERO() = ", pp.isZERO()); // polynomials over (polynomials over (polynomials over rational numbers)) GenPolynomialRing>> pppf = new GenPolynomialRing>>( ppf, 4); // System.out.println("pppf = " + pppf); GenPolynomial>> ppp = pppf.getONE(); //System.out.println("ppp = " + ppp); ppp = pppf.random(2); // System.out.println("ppp = " + ppp); ppp = pppf.getZERO(); // System.out.println("ppp = " + ppp); RingElem>>> pppe = new GenPolynomial>>( pppf); // System.out.println("pppe = " + pppe); // System.out.println("ppp.equals(pppe) = " + ppp.equals(pppe) ); // System.out.println("ppp.equals(ppp) = " + ppp.equals(ppp) ); assertTrue("ppp.equals(pppe) = ", ppp.equals(pppe)); assertTrue("ppp.equals(ppp) = ", ppp.equals(ppp)); pppe = pppe.sum(ppp); // why not ppp = ppp.add(pppe) ? // System.out.println("pppe = " + pppe); assertTrue("pppe.isZERO() = ", pppe.isZERO()); ppp = pppf.random(2); ppp = ppp.subtract(ppp); // System.out.println("ppp = " + ppp); // System.out.println("ppp.isZERO() = " + ppp.isZERO()); assertTrue("ppp.isZERO() = ", ppp.isZERO()); // some tests //GenPolynomial pfx = new GenPolynomial(); //System.out.println("pfx = " + pfx); } /** * Test extension and contraction. */ public void testExtendContract() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(cf, rl); // System.out.println("pf = " + pf); GenPolynomial a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); int k = rl; GenPolynomialRing pfe = pf.extend(k); GenPolynomialRing pfec = pfe.contract(k); assertEquals("pf == pfec", pf, pfec); GenPolynomial ae = a.extend(pfe, 0, 0); Map> m = ae.contract(pfec); List> ml = new ArrayList>(m.values()); GenPolynomial aec = ml.get(0); assertEquals("a == aec", a, aec); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); } /** * Test reversion. */ public void testReverse() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(cf, rl); //System.out.println("pf = " + pf); GenPolynomial a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); GenPolynomialRing pfr = pf.reverse(); GenPolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); //System.out.println("pfr = " + pfr); GenPolynomial ar = a.reverse(pfr); GenPolynomial arr = ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test accessors. */ public void testAccessors() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); // System.out.println("pf = " + pf); // test 1 GenPolynomial p = pf.getONE(); // System.out.println("p = " + p); ExpVector e = p.leadingExpVector(); BigRational c = p.leadingBaseCoefficient(); GenPolynomial f = new GenPolynomial(pf, c, e); assertEquals("1 == 1 ", p, f); GenPolynomial r = p.reductum(); assertTrue("red(1) == 0 ", r.isZERO()); // test 0 p = pf.getZERO(); // System.out.println("p = " + p); e = p.leadingExpVector(); c = p.leadingBaseCoefficient(); f = new GenPolynomial(pf, c, e); assertEquals("0 == 0 ", p, f); r = p.reductum(); assertTrue("red(0) == 0 ", r.isZERO()); // test random p = pf.random(kl, 2 * ll, el, q); // System.out.println("p = " + p); e = p.leadingExpVector(); c = p.leadingBaseCoefficient(); r = p.reductum(); f = new GenPolynomial(pf, c, e); f = r.sum(f); assertEquals("p == lm(f)+red(f) ", p, f); // test iteration over random GenPolynomial g; g = p; f = pf.getZERO(); while (!g.isZERO()) { e = g.leadingExpVector(); c = g.leadingBaseCoefficient(); //System.out.println("c e = " + c + " " + e); r = g.reductum(); f = f.sum(c, e); g = r; } assertEquals("p == lm(f)+lm(red(f))+... ", p, f); } /** * Test homogeneous. */ public void testHomogeneous() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(rf, 2); //rl); // System.out.println("pf = " + pf); // test 1 GenPolynomial p = pf.getONE(); // System.out.println("p = " + p); assertTrue("1 is homogeneous " + p, p.isHomogeneous()); // test 0 p = pf.getZERO(); // System.out.println("p = " + p); assertTrue("0 is homogeneous " + p, p.isHomogeneous()); // test random p = pf.random(kl, 2 * ll, el, q); //p = pf.random(kl,ll,el,q); //System.out.println("p = " + p); assertFalse("rnd is homogeneous " + p, p.isHomogeneous()); // make homogeneous GenPolynomialRing pfh = pf.extend(1); //System.out.println("pfh = " + pfh); // remove block order TermOrder to = new TermOrder(TermOrder.IGRLEX); pfh = new GenPolynomialRing(pfh, to); //System.out.println("pfh = " + pfh); GenPolynomial ph = p.homogenize(pfh); //System.out.println("ph = " + ph); assertTrue("ph is homogeneous " + ph, ph.isHomogeneous()); GenPolynomial ps = ph.deHomogenize(pf); //System.out.println("ps = " + ps); assertEquals("phs == p ", ps, p); // findbugs //System.out.println("p is homogeneous = " + p.isHomogeneous()); //System.out.println("ph is homogeneous = " + ph.isHomogeneous()); GenPolynomial s = pf.random(kl, ll, el, q); //System.out.println("s = " + s); assertFalse("rnd is homogeneous " + s, s.isHomogeneous() && !s.isConstant()); GenPolynomial sh = s.homogenize(pfh); //System.out.println("sh = " + sh); assertTrue("sh is homogeneous " + sh, sh.isHomogeneous()); GenPolynomial ss = sh.deHomogenize(pf); //System.out.println("ss = " + ss); assertEquals("ss = s ", ss, s); GenPolynomial th = ph.multiply(sh); //System.out.println("th = " + th); assertTrue("th is homogeneous " + th, th.isHomogeneous()); GenPolynomial t = p.multiply(s); //System.out.println("t = " + t); GenPolynomial ts = th.deHomogenize(pf); //System.out.println("ts = " + ts); assertEquals("ts = t ", ts, t); } /** * Test weight homogeneous. */ public void testWeightHomogeneous() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // weight term order long[] weight = new long[] { 2, 3, 4, 5 }; TermOrder to = TermOrderByName.weightOrder(weight); // System.out.println("to = " + to); // polynomials over rational numbers GenPolynomialRing pf = new GenPolynomialRing(rf, 4, to); // System.out.println("pf = " + pf.toScript()); // test 1 GenPolynomial p = pf.getONE(); // System.out.println("p = " + p); assertTrue("1 is weight homogeneous " + p, p.isWeightHomogeneous()); // test 0 p = pf.getZERO(); // System.out.println("p = " + p); assertTrue("0 is weight homogeneous " + p, p.isWeightHomogeneous()); // test random p = pf.random(kl, 3 * ll, el, q); // System.out.println("p = " + p); assertFalse("rnd is weight homogeneous " + p, p.isWeightHomogeneous()); GenPolynomial pl = p.leadingWeightPolynomial(); // System.out.println("pl = " + pl); assertTrue("lw(rnd) is weight homogeneous " + pl, pl.isWeightHomogeneous()); GenPolynomial r = pf.random(kl, 3 * ll, el, q); // System.out.println("r = " + r); assertFalse("rnd is weight homogeneous " + r, r.isWeightHomogeneous()); GenPolynomial rl = r.leadingWeightPolynomial(); // System.out.println("rl = " + rl); assertTrue("lw(rnd) is weight homogeneous " + rl, rl.isWeightHomogeneous()); GenPolynomial t = pl.multiply(rl); // System.out.println("t = " + t); assertTrue("lw(rnd)*lw(rnd) is weight homogeneous " + t, t.isWeightHomogeneous()); } /** * Test univariate. */ public void testUnivariate() { BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); //System.out.println("pf = " + pf); GenPolynomial a, b, c, d; // x**1 a = pf.univariate(pf.nvar - 1); //System.out.println("a = " + a); assertTrue("deg(a) = 1: ", a.degree() == 1); assertEquals("xi == xi: ", pf.vars[0], a.toString()); b = pf.univariate(pf.vars[0]); //System.out.println("b = " + b); assertTrue("deg(b) = 1: ", b.degree() == 1); assertEquals("xi == xi: ", pf.vars[0], b.toString()); c = pf.univariate(0); //System.out.println("c = " + c); assertTrue("deg(c) = 1: ", c.degree() == 1); assertEquals("xi == xi: ", pf.vars[pf.nvar - 1], c.toString()); d = pf.univariate(pf.vars[pf.nvar - 1]); //System.out.println("d = " + d); assertTrue("deg(c) = 1: ", c.degree() == 1); assertEquals("xi == xi: ", pf.vars[pf.nvar - 1], d.toString()); // x**7 a = pf.univariate(pf.nvar - 1, 7); //System.out.println("a = " + a); assertTrue("deg(a) = 7: ", a.degree() == 7); assertEquals("xi == xi: ", pf.vars[0] + "^7", a.toString()); b = pf.univariate(pf.vars[0], 7); //System.out.println("b = " + b); assertTrue("deg(b) = 7: ", b.degree() == 7); assertEquals("xi == xi: ", pf.vars[0] + "^7", b.toString()); c = pf.univariate(0, 7); //System.out.println("c = " + c); assertTrue("deg(c) = 7: ", c.degree() == 7); assertEquals("xi == xi: ", pf.vars[pf.nvar - 1] + "^7", c.toString()); d = pf.univariate(pf.vars[pf.nvar - 1], 7); //System.out.println("d = " + d); assertTrue("deg(c) = 7: ", c.degree() == 7); assertEquals("xi == xi: ", pf.vars[pf.nvar - 1] + "^7", d.toString()); } /** * Test iterators. */ public void testIterators() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); // System.out.println("pf = " + pf); // random polynomial GenPolynomial p = pf.random(kl, 2 * ll, el, q); //System.out.println("p = " + p); // test monomials Monomial one = new Monomial(pf.getONE().leadingMonomial()); for (Monomial m : p) { //System.out.println("m = " + m); assertFalse("m.c == 0 ", m.coefficient().isZERO()); assertFalse("m.e < (0) ", m.exponent().signum() < 0); if (!m.exponent().isZERO()) { assertFalse("m != 1: ", m.equals(one)); } String s = m.toString() + ", " + m.toScript(); //System.out.println("s = " + s); assertTrue("#s >= 2*rl + 5: ", s.length() >= 2 * rl + 5); } // test exponents Iterator et = p.exponentIterator(); while (et.hasNext()) { ExpVector e = et.next(); //System.out.println("e = " + e); assertFalse("e < (0) ", e.signum() < 0); } // test coefficients Iterator ct = p.coefficientIterator(); while (ct.hasNext()) { BigInteger i = ct.next(); //System.out.println("i = " + i); assertFalse("i == 0 ", i.isZERO()); } } /** * Test spliterators. */ public void testSpliterators() { // integers BigInteger rf = new BigInteger(); BigInteger num = rf.fromInteger(1); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); //System.out.println("pf = " + pf.toScript()); // random polynomial GenPolynomial p = pf.random(kl, 22 * ll, el, q); //System.out.println("p = " + p.length()); List coeffs = new ArrayList(); // create spliterator and run on it PolySpliterator psplit = new PolySpliterator(p.val); //System.out.println("ps = " + psplit); //System.out.println("ps = "); printCharacteristic(psplit); //psplit.forEachRemaining( m -> System.out.print(m.c.toScript() + ", ")); //System.out.println("\n"); psplit.forEachRemaining(m -> coeffs.add(m.c.multiply(num))); assertTrue("#coeffs == size: ", p.val.size() == coeffs.size()); coeffs.clear(); // create spliterator and split it //psplit = new PolySpliterator(p.val); Spliterator> split = p.spliterator(); //System.out.println("ps = " + split); //PolySpliterator rest = split.trySplit(); Spliterator> rest = split.trySplit(); //System.out.println("rest = "); printCharacteristic(rest); //System.out.println("ps = "); printCharacteristic(split); //System.out.println("rest = " + rest); //rest.forEachRemaining( m -> System.out.print(m.c.toScript() + ", ")); rest.forEachRemaining(m -> coeffs.add(m.c.multiply(num))); //System.out.println("\nps = " + split); //split.forEachRemaining( m -> System.out.print(m.c.toScript() + ", ")); split.forEachRemaining(m -> coeffs.add(m.c.multiply(num))); assertTrue("#coeffs == size: ", p.val.size() == coeffs.size()); assertTrue("coeffs == p.coefficients: ", ListUtil. equals(coeffs, p.val.values())); } void printCharacteristic(Spliterator sp) { for (int c = 0x0; c < 0x4000; c++) { if (sp.hasCharacteristics(c)) { System.out.println(String.format("char: %3x", c)); } } } /** * Test coefficient map function. */ public void testMap() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); // System.out.println("pf = " + pf); // random polynomial GenPolynomial p = pf.random(kl, 2 * ll, el, q); //System.out.println("p = " + p); // test times 1 GenPolynomial q; q = p.map(new Multiply(rf.getONE())); assertEquals("p == q ", p, q); // test times 0 q = p.map(new Multiply(rf.getZERO())); assertTrue("q == 0: " + q, q.isZERO()); // test times -1 q = p.map(new Multiply(rf.getONE().negate())); assertEquals("p == q ", p.negate(), q); } /** * Test streams. */ public void testStreams() { // modular integers ModIntegerRing rf = new ModIntegerRing(32003); ModInteger num = rf.fromInteger(-1); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, rl); //System.out.println("pf = " + pf.toScript()); // random polynomial GenPolynomial p = pf.random(kl, 222 * ll, 2 + el, q); //System.out.println("p = " + p.length()); GenPolynomial q; // negate coefficients long tn = System.nanoTime(); q = p.negate(); tn = System.nanoTime() - tn; //System.out.println("q = " + q.length() + ", neg time = " + tn); assertTrue("time >= 0 ", tn >= 0); //System.out.println("p+q = " + p.sum(q)); assertTrue("p+q == 0 ", p.sum(q).isZERO()); // map multiply to coefficients long tm = System.nanoTime(); q = p.map(c -> c.multiply(num)); tm = System.nanoTime() - tm; //System.out.println("q = " + q.length() + ", old time = " + tm); assertTrue("time >= 0 ", tm >= 0); //System.out.println("p+q = " + p.sum(q)); assertTrue("p+q == 0 ", p.sum(q).isZERO()); // map multiply to coefficients stream long ts = System.nanoTime(); q = p.mapOnStream(me -> new MapEntry(me.getKey(), me.getValue().multiply(num)), false); ts = System.nanoTime() - ts; //System.out.println("q = " + q.length() + ", seq time = " + ts); assertTrue("time >= 0 ", ts >= 0); //System.out.println("p+q = " + p.sum(q)); assertTrue("p+q == 0 ", p.sum(q).isZERO()); // map multiply to coefficients parallel stream long tp = System.nanoTime(); q = p.mapOnStream(me -> new MapEntry(me.getKey(), me.getValue().multiply(num)), true); tp = System.nanoTime() - tp; //System.out.println("q = " + q.length() + ", par time = " + tp); assertTrue("time >= 0 ", tp >= 0); //System.out.println("p+q = " + p.sum(q)); assertTrue("p+q == 0 ", p.sum(q).isZERO()); System.out.println("map time: neg, old, seq, par, = " + tn + ", " + tm + ", " + ts + ", " + tp); //System.out.println("ForkJoinPool: " + ForkJoinPool.commonPool()); } /** * Test bitLength. */ public void testBitLength() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, 5); // System.out.println("pf = " + pf); GenPolynomial a, b, c; a = pf.getZERO(); assertEquals("blen(0) = 0", 0, a.bitLength()); a = pf.getONE(); assertEquals("blen(1) = 7", 7, a.bitLength()); // random polynomials a = pf.random(kl, 2 * ll, el, q); //System.out.println("a = " + a); //System.out.println("blen(a) = " + a.bitLength()); assertTrue("blen(random) >= 0", 0 <= a.bitLength()); b = pf.random(kl, 2 * ll, el, q); //System.out.println("b = " + b); //System.out.println("blen(b) = " + b.bitLength()); assertTrue("blen(random) >= 0", 0 <= b.bitLength()); //c = a.multiply(b); c = a.sum(b); //System.out.println("c = " + c); //System.out.println("blen(a)+blen(b) = " + (a.bitLength()+b.bitLength())); //System.out.println("blen(c) = " + c.bitLength()); assertTrue("blen(random) >= 0", 0 <= c.bitLength()); assertTrue("blen(random)+blen(random) >= blen(random+random)", a.bitLength() + b.bitLength() >= c.bitLength()); } /** * Test matrix and vector. */ public void testMatrix() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // polynomials over rational numbers String[] vars = new String[] { "lambda" }; GenPolynomialRing pf = new GenPolynomialRing(rf, vars); //System.out.println("pf = " + pf.toScript()); // matrix over rational numbers int r = 11; GenMatrixRing mf = new GenMatrixRing(rf, r, r); //System.out.println("mf = " + mf.toScript()); GenMatrix A = mf.getONE(); //System.out.println("A = " + A); GenPolynomial cf = pf.charPolynomial(A); //System.out.println("cf = " + cf); assertTrue("tcf(charPol(A)) == 1", cf.trailingBaseCoefficient().abs().isONE()); //System.out.println("det = " + pf.determinantFromCharPol(cf)); assertTrue("det(charPol(A)) == 1", pf.determinantFromCharPol(cf).abs().isONE()); //System.out.println("trace = " + pf.traceFromCharPol(cf)); assertEquals("trace(charPol(A)) == rl", pf.traceFromCharPol(cf), pf.coFac.fromInteger(r)); A = mf.getZERO(); //System.out.println("A = " + A); cf = pf.charPolynomial(A); //System.out.println("cf = " + cf); assertTrue("charPol(A) == 0", cf.isZERO()); A = mf.randomUpper(3, 0.6f); //System.out.println("A = " + A); cf = pf.charPolynomial(A); // mostly == 0 //System.out.println("cf = " + cf); assertTrue("tcf(charPol(A)) == 0: " + cf, cf.trailingBaseCoefficient().isZERO()); A = mf.random(3, 0.6f); //System.out.println("A = " + A); cf = pf.charPolynomial(A); // mostly != 0 //System.out.println("cf = " + cf); assertFalse("tcf(charPol(A)) == 0: " + cf, cf.trailingBaseCoefficient().isZERO()); } } /** * Internal scalar multiplication functor. */ class Multiply> implements UnaryFunctor { C x; public Multiply(C x) { this.x = x; } public C eval(C c) { return c.multiply(x); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenPolynomialTokenizerTest.java000066400000000000000000001157101445075545500270230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenPolynomialTokenizer tests with JUnit. * @author Heinz Kredel */ public class GenPolynomialTokenizerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenPolynomialTokenizerTest object. * @param name String. */ public GenPolynomialTokenizerTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GenPolynomialTokenizerTest.class); return suite; } RingFactory fac; // unused GenPolynomialRing pfac; GenSolvablePolynomialRing spfac; GenPolynomialTokenizer parser; Reader source; @Override protected void setUp() { fac = null; pfac = null; parser = null; source = null; } @Override protected void tearDown() { fac = null; pfac = null; parser = null; source = null; } /** * Test rational polynomial. */ @SuppressWarnings("unchecked") public void testBigRational() { String exam = "Rat(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3/4 - 6/8 ), " + "( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test integer polynomial. */ @SuppressWarnings("unchecked") public void testBigInteger() { String exam = "Int(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigInteger fac = new BigInteger(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test modular integer polynomial. */ @SuppressWarnings("unchecked") public void testModInteger() { String exam = "Mod 19 (x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 + 19 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); ModIntRing fac = new ModIntRing(19); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); //System.out.println("pfac = " + pfac); //System.out.println("f.ring = " + f.ring); assertEquals("pfac == f.ring", pfac, f.ring); ModLongRing lfac = new ModLongRing(19); assertFalse("fac != lfac", fac.equals(lfac)); assertFalse("lfac != f.ring.coFac", lfac.equals(f.ring.coFac)); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test complex polynomial. */ @SuppressWarnings("unchecked") public void testBigComplex() { String exam = "Complex(x,y,z) L " + "( " + "( 1i0 ), " + "( 0i0 ), " + "( 3/4i2 - 6/8i2 ), " + "( 1i0 x + x^3 + 1i3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigComplex fac = new BigComplex(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test decimal polynomial. */ @SuppressWarnings("unchecked") public void testBigDecimal() { String exam = "D(x,y,z) L " + "( " + "( 1 ), " + "( 0 ), " + "( 0.25 * 0.25 - 0.25^2 ), " + "( 1 x + x^3 + 0.3333333333333333333333 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigDecimal fac = new BigDecimal(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test quaternion polynomial. */ @SuppressWarnings("unchecked") public void testBigQuaternion() { String exam = "Quat(x,y,z) L " + "( " + "( 1i0j0k0 ), " + "( 0i0j0k0 ), " + "( 3/4i2j1k3 - 6/8i2j1k3 ), " + "( 1 x + x^3 + 1i2j3k4 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigQuaternionRing fac = new BigQuaternionRing(); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test rational solvable polynomial. */ @SuppressWarnings("unchecked") public void testSolvableBigRational() { String exam = "Rat(x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + " ( 1 ), " + " ( 0 ), " + " ( 3/4 - 6/8 ), " + " ( 1 x + x^3 + 1/3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextSolvablePolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); //System.out.println("f.ring.table = " + ((GenSolvablePolynomialRing)f.ring).table); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == f.ring", spfac, f.ring); //System.out.println("spfac = " + spfac); //System.out.println("spfac.table = " + spfac.table); GenSolvablePolynomial a = f.castToSolvableList().get(0); //System.out.println("a = " + a); assertTrue("isZERO( f.get(0) )", a.isONE()); GenSolvablePolynomial b = f.castToSolvableList().get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenSolvablePolynomial c = f.castToSolvableList().get(2); //System.out.println("c = " + c); assertTrue("isONE( f.get(2) )", c.isZERO()); GenSolvablePolynomial d = f.castToSolvableList().get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test mod integer solvable polynomial. */ @SuppressWarnings("unchecked") public void testSolvableModInteger() { String exam = "Mod 19 (x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + "( 1 ), " + "( 0 ), " + "( 3 2 - 6 + 19 ), " + "( 1 x + x^3 + 3 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextSolvablePolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); //System.out.println("f.ring.table = " + ((GenSolvablePolynomialRing)f.ring).table); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 4", f.list.size() == 4); ModIntRing fac = new ModIntRing(19); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == f.ring", spfac, f.ring); //System.out.println("spfac = " + spfac); //System.out.println("spfac.table = " + spfac.table); GenSolvablePolynomial a = f.castToSolvableList().get(0); //System.out.println("a = " + a); assertTrue("isZERO( f.get(0) )", a.isONE()); GenSolvablePolynomial b = f.castToSolvableList().get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenSolvablePolynomial c = f.castToSolvableList().get(2); //System.out.println("c = " + c); assertTrue("isONE( f.get(2) )", c.isZERO()); GenSolvablePolynomial d = f.castToSolvableList().get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); } /** * Test integer polynomial module. */ @SuppressWarnings("unchecked") public void testBigIntegerModule() { String exam = "Int(x,y,z) L " + "( " + " ( " + " ( 1 ), " + " ( 0 ), " + " ( 3 2 - 6 ), " + " ( 1 x + x^3 + 3 y z - x^3 ) " + " ), " + " ( ( 1 ), ( 0 ) ) " + ")"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); ModuleList m = null; try { m = (ModuleList) parser.nextSubModuleSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("m = " + m); assertTrue("m != null", m.list != null); assertTrue("length( m ) = 2", m.list.size() == 2); assertTrue("length( m[0] ) = 4", ((List) m.list.get(0)).size() == 4); BigInteger fac = new BigInteger(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == m.ring", pfac, m.ring); List>> rows = m.list; List> f; f = rows.get(0); GenPolynomial a = f.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); f = rows.get(1); assertTrue("length( f ) = 4", f.size() == 4); a = f.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); b = f.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); c = f.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); d = f.get(3); //System.out.println("c = " + d); assertTrue("isZERO( f.get(3) )", d.isZERO()); } /** * Test rational solvable polynomial module. */ @SuppressWarnings("unchecked") public void testBigRationalSolvableModule() { String exam = "Rat(x,y,z) L " + "RelationTable " + "( " + " ( z ), ( y ), ( y z - 1 ) " + ") " + "( " + " ( " + " ( 1 ), " + " ( 0 ), " + " ( 3/4 - 6/8 ), " + " ( 1 x + x^3 + 1/3 y z - x^3 ) " + " ), " + " ( ( x ), ( 1 ), ( 0 ) ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); ModuleList m = null; try { m = (ModuleList) parser.nextSolvableSubModuleSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("m = " + m); //System.out.println("m.ring = " + m.ring); assertTrue("m != null", m.list != null); assertTrue("length( m ) = 2", m.list.size() == 2); assertTrue("length( m[0] ) = 4", ((List) m.list.get(0)).size() == 4); BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; spfac = new GenSolvablePolynomialRing(fac, nvar, tord, vars); List> rel = new ArrayList>(3); rel.add(spfac.parse("z")); rel.add(spfac.parse("y")); rel.add(spfac.parse("y z - 1")); spfac.addSolvRelations(rel); assertEquals("spfac == m.ring", spfac, m.ring); List>> rows = m.castToSolvableList(); List> f; f = rows.get(0); GenSolvablePolynomial a = f.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenSolvablePolynomial b = f.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenSolvablePolynomial c = f.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenSolvablePolynomial d = f.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); f = rows.get(1); assertTrue("length( f ) = 4", f.size() == 4); a = f.get(0); //System.out.println("a = " + a); assertTrue("!isONE( f.get(0) )", !a.isONE()); b = f.get(1); //System.out.println("b = " + b); assertTrue("isONE( f.get(1) )", b.isONE()); c = f.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); d = f.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(3) )", d.isZERO()); } /** * Test algebraic number polynomial. Note: Syntax no more supported. */ @SuppressWarnings("unchecked") public void removedTestAlgebraicNumber() { String exam = "AN[ (i) ( i^2 + 1 ) ] (x,y,z) L " + "( " + "( 1 ), " + "( _i_ ), " + "( 0 ), " + "( _i^2_ + 1 ), " + "( 1 x + x^3 + _3 i_ y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList> f = null; AlgebraicNumberRing fac = null; try { f = (PolynomialList>) parser.nextPolynomialSet(); fac = (AlgebraicNumberRing) f.ring.coFac; } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing>(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial> a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial> b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isUnit()); b = b.monic(); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isONE()); GenPolynomial> c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(1) )", c.isZERO()); GenPolynomial> d = f.list.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(2) )", d.isZERO()); GenPolynomial> e = f.list.get(4); //System.out.println("e = " + e); assertEquals("f.get(3).length() == 2", 2, e.length()); } /** * Test Galois field coefficient polynomial. Note: Syntax no more * supported. */ @SuppressWarnings("unchecked") public void removedTestGaloisField() { String exam = "AN[ 19 (i) ( i^2 + 1 ) ] (x,y,z) L " + "( " + "( 20 ), " + "( _i_ ), " + "( 0 ), " + "( _i^2_ + 20 ), " + "( 1 x + x^3 + _3 i_ y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList> f = null; AlgebraicNumberRing fac = null; try { f = (PolynomialList>) parser.nextPolynomialSet(); fac = (AlgebraicNumberRing) f.ring.coFac; } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing>(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial> a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial> b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isUnit()); b = b.monic(); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isONE()); GenPolynomial> c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(1) )", c.isZERO()); GenPolynomial> d = f.list.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(2) )", d.isZERO()); GenPolynomial> e = f.list.get(4); //System.out.println("e = " + e); assertEquals("f.get(3).length() == 2", 2, e.length()); } /** * Test algebraic number polynomial with braces. */ @SuppressWarnings("unchecked") public void testAlgebraicNumberBrace() { String exam = "AN[ (i) ( i^2 + 1 ) ] (x,y,z) L " + "( " + "( 1 ), " + "( { i } ), " + "( 0 ), " + "( { i^2 } + 1 ), " + "( 1 x + x^3 + { 3 i }^2 y z - x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList> f = null; AlgebraicNumberRing fac = null; try { f = (PolynomialList>) parser.nextPolynomialSet(); fac = (AlgebraicNumberRing) f.ring.coFac; } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing>(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial> a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial> b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isUnit()); b = b.monic(); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isONE()); GenPolynomial> c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(1) )", c.isZERO()); GenPolynomial> d = f.list.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(2) )", d.isZERO()); GenPolynomial> e = f.list.get(4); //System.out.println("e = " + e); assertEquals("f.get(3).length() == 2", 2, e.length()); } /** * Test Galois field coefficient polynomial with braces. */ @SuppressWarnings("unchecked") public void testGaloisFieldBrace() { String exam = "AN[ 19 (i) ( i^2 + 1 ) ] (x,y,z) L " + "( " + "( 20 ), " + "( { i } ), " + "( 0 ), " + "( { i^2 } + 20 ), " + "( 1 x + x^3 + { 3 i }^3 y z + { -1 }^3 x^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList> f = null; AlgebraicNumberRing fac = null; try { f = (PolynomialList>) parser.nextPolynomialSet(); fac = (AlgebraicNumberRing) f.ring.coFac; } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing>(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial> a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial> b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isUnit()); b = b.monic(); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isONE()); GenPolynomial> c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(1) )", c.isZERO()); GenPolynomial> d = f.list.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(2) )", d.isZERO()); GenPolynomial> e = f.list.get(4); //System.out.println("e = " + e); assertEquals("f.get(3).length() == 2", 2, e.length()); } /** * Test Galois field coefficient polynomial without braces. */ @SuppressWarnings("unchecked") public void testGaloisFieldWoBrace() { String exam = "AN[ 19 (i) ( i^2 + 1 ) ] (x,y,z) L " + "( " + "( 20 ), " + "( i ), " + "( 0 ), " + "( i^2 + 20 ), " + "( 1 x + x^3 + 3^3 i^3 y z - (x)^3 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList> f = null; AlgebraicNumberRing fac = null; try { f = (PolynomialList>) parser.nextPolynomialSet(); fac = (AlgebraicNumberRing) f.ring.coFac; } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing>(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial> a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial> b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isUnit()); b = b.monic(); //System.out.println("b = " + b); assertTrue("isUnit( f.get(1) )", b.isONE()); GenPolynomial> c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(1) )", c.isZERO()); GenPolynomial> d = f.list.get(3); //System.out.println("d = " + d); assertTrue("isZERO( f.get(2) )", d.isZERO()); GenPolynomial> e = f.list.get(4); //System.out.println("e = " + e); assertEquals("f.get(3).length() == 2", 2, e.length()); } /** * Test rational polynomial with generic coefficients. */ @SuppressWarnings("unchecked") public void testBigRationalGeneric() { String exam = "Rat(x,y,z) L " + "( " + "( 1^3 ), " + "( 0^3 ), " + "( { 3/4 }^2 - 6/8^2 ), " + "( { 1 }^2 x + x^3 + 1/3 y z - x^3 ), " + "( 1.0001 - 0.0001 + { 0.25 }**2 - 1/4^2 ) " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } //System.out.println("f = " + f); assertTrue("f != null", f.list != null); assertTrue("length( f ) = 5", f.list.size() == 5); BigRational fac = new BigRational(0); TermOrder tord = new TermOrder(TermOrder.INVLEX); String[] vars = new String[] { "x", "y", "z" }; int nvar = vars.length; pfac = new GenPolynomialRing(fac, nvar, tord, vars); assertEquals("pfac == f.ring", pfac, f.ring); GenPolynomial a = f.list.get(0); //System.out.println("a = " + a); assertTrue("isONE( f.get(0) )", a.isONE()); GenPolynomial b = f.list.get(1); //System.out.println("b = " + b); assertTrue("isZERO( f.get(1) )", b.isZERO()); GenPolynomial c = f.list.get(2); //System.out.println("c = " + c); assertTrue("isZERO( f.get(2) )", c.isZERO()); GenPolynomial d = f.list.get(3); //System.out.println("d = " + d); assertEquals("f.get(3).length() == 2", 2, d.length()); GenPolynomial e = f.list.get(4); //System.out.println("e = " + e); assertTrue("isONE( f.get(4) )", e.isONE()); } /** * Test rational polynomial with errors. */ @SuppressWarnings("unchecked") public void testBigRationalErorr() { // brace mismatch String exam = "Rat(x,y,z) L " + "( " + "( { 3 ), " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); PolynomialList f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } catch (InvalidExpressionException e) { // pass } // brace mismatch exam = "Rat(x,y,z) L " + "( " + "( 3 } ), " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } catch (InvalidExpressionException e) { // pass } // invalid nesting exam = "Rat(x,y,z) L " + "( " + "( { x } ), " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } catch (InvalidExpressionException e) { // pass } // unknown variable exam = "Rat(x,y,z) L " + "( " + "( w ), " + " )"; source = new StringReader(exam); parser = new GenPolynomialTokenizer(source); f = null; try { f = (PolynomialList) parser.nextPolynomialSet(); } catch (IOException e) { fail("" + e); } catch (ClassCastException e) { fail("" + e); } catch (InvalidExpressionException e) { // pass } assertTrue("f != null", f == null); } /** * Test variables. */ public void testVariables() { String vars = "a,b,c,d,e"; String[] variables = GenPolynomialTokenizer.variableList(vars); assertTrue("len == 5: ", variables.length == 5); String expr = "a,b,c,d,e"; variables = GenPolynomialTokenizer.expressionVariables(expr); //System.out.println("variables = " + Arrays.toString(variables) + ", len = " + variables.length); assertTrue("len == 5: ", variables.length == 5); expr = "b,c,d,e*a,b,c,d"; variables = GenPolynomialTokenizer.expressionVariables(expr); //System.out.println("variables = " + Arrays.toString(variables) + ", len = " + variables.length); assertTrue("len == 5: ", variables.length == 5); expr = "b + c^3 - d + e*a - b/c +d"; variables = GenPolynomialTokenizer.expressionVariables(expr); //System.out.println("variables = " + Arrays.toString(variables) + ", len = " + variables.length); assertTrue("len == 5: ", variables.length == 5); expr = "(b + c)^3 - { d + e*a } / [ b/c + d ] + (b + 3f + f*3 + f3)"; variables = GenPolynomialTokenizer.expressionVariables(expr); //System.out.println("variables = " + Arrays.toString(variables) + ", len = " + variables.length); assertTrue("len == 7: ", variables.length == 7); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenSolvablePolynomialTest.java000066400000000000000000000554471445075545500266320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigComplex; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import edu.jas.arith.BigRational; import edu.jas.structure.RingElem; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenSolvablePolynomial Test using JUnit. Note: not optimal since * GenSolvablePolynomial does not implement * RingElem<GenSolvablePolynomial> * @author Heinz Kredel */ public class GenSolvablePolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenSolvablePolynomialTest object. * @param name String. */ public GenSolvablePolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GenSolvablePolynomialTest.class); return suite; } int rl = 6; // even for Weyl int kl = 10; int ll = 7; int el = 4; float q = 0.5f; @Override protected void setUp() { // a = b = c = d = e = null; } @Override protected void tearDown() { // a = b = c = d = e = null; } /** * Test constructors and factory. */ public void testConstructors() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); //BigRational r = rf.fromInteger( 99 ); // System.out.println("r = " + r); //r = rf.random( 9 ); // System.out.println("r = " + r); // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(rf, 2); // System.out.println("pf = " + pf); GenSolvablePolynomial p = pf.getONE(); // System.out.println("p = " + p); p = pf.random(9); // System.out.println("p = " + p); p = pf.getZERO(); // System.out.println("p = " + p); RingElem> pe = new GenSolvablePolynomial(pf); //System.out.println("pe = " + pe); //System.out.println("p.equals(pe) = " + p.equals(pe) ); //System.out.println("p.equals(p) = " + p.equals(p) ); assertTrue("p.equals(pe) = ", p.equals(pe)); assertTrue("p.equals(p) = ", p.equals(p)); pe = pe.sum(p); // why not p = p.add(pe) ? //System.out.println("pe = " + pe); assertTrue("pe.isZERO() = ", pe.isZERO()); p = pf.random(9); p = (GenSolvablePolynomial) p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // polynomials over (polynomials over rational numbers) GenSolvablePolynomialRing> ppf = new GenSolvablePolynomialRing>( pf, 3); // System.out.println("ppf = " + ppf); GenSolvablePolynomial> pp = ppf.getONE(); // System.out.println("pp = " + pp); pp = ppf.random(2); // System.out.println("pp = " + pp); pp = ppf.getZERO(); // System.out.println("pp = " + pp); RingElem>> ppe = new GenSolvablePolynomial>( ppf); // System.out.println("ppe = " + ppe); // System.out.println("pp.equals(ppe) = " + pp.equals(ppe) ); // System.out.println("pp.equals(pp) = " + pp.equals(pp) ); assertTrue("pp.equals(ppe) = ", pp.equals(ppe)); assertTrue("pp.equals(pp) = ", pp.equals(pp)); ppe = ppe.sum(pp); // why not pp = pp.add(ppe) ? //System.out.println("ppe = " + ppe); assertTrue("ppe.isZERO() = ", ppe.isZERO()); pp = ppf.random(2); pp = (GenSolvablePolynomial>) pp.subtract(pp); //System.out.println("pp = " + pp); //System.out.println("pp.isZERO() = " + pp.isZERO()); assertTrue("pp.isZERO() = ", pp.isZERO()); // polynomials over (polynomials over (polynomials over rational numbers)) GenSolvablePolynomialRing>> pppf = new GenSolvablePolynomialRing>>( ppf, 4); // System.out.println("pppf = " + pppf); GenSolvablePolynomial>> ppp = pppf.getONE(); //System.out.println("ppp = " + ppp); ppp = pppf.random(2); // System.out.println("ppp = " + ppp); ppp = pppf.getZERO(); // System.out.println("ppp = " + ppp); RingElem>>> pppe = new GenSolvablePolynomial>>( pppf); // System.out.println("pppe = " + pppe); // System.out.println("ppp.equals(pppe) = " + ppp.equals(pppe) ); // System.out.println("ppp.equals(ppp) = " + ppp.equals(ppp) ); assertTrue("ppp.equals(pppe) = ", ppp.equals(pppe)); assertTrue("ppp.equals(ppp) = ", ppp.equals(ppp)); pppe = pppe.sum(ppp); // why not ppp = ppp.add(pppe) ? // System.out.println("pppe = " + pppe); assertTrue("pppe.isZERO() = ", pppe.isZERO()); ppp = pppf.random(2); ppp = (GenSolvablePolynomial>>) ppp.subtract(ppp); // System.out.println("ppp = " + ppp); // System.out.println("ppp.isZERO() = " + ppp.isZERO()); assertTrue("ppp.isZERO() = ", ppp.isZERO()); } /** * Test extension and contraction. */ public void testExtendContract() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, rl); // System.out.println("pf = " + pf); GenSolvablePolynomial a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); int k = rl; GenSolvablePolynomialRing pfe = pf.extend(k); GenSolvablePolynomialRing pfec = pfe.contract(k); assertEquals("pf == pfec", pf, pfec); GenSolvablePolynomial ae = (GenSolvablePolynomial) a.extend(pfe, 0, 0); Map> m = ae.contract(pfec); List> ml = new ArrayList>(m.values()); GenSolvablePolynomial aec = (GenSolvablePolynomial) ml.get(0); assertEquals("a == aec", a, aec); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); } /** * Test extension and contraction for Weyl relations. */ public void testExtendContractWeyl() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, rl); RelationGenerator wl = new WeylRelations(); //wl.generate(pf); pf.addRelations(wl); // System.out.println("pf = " + pf); GenSolvablePolynomial a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); int k = rl; GenSolvablePolynomialRing pfe = pf.extend(k); GenSolvablePolynomialRing pfec = pfe.contract(k); assertEquals("pf == pfec", pf, pfec); GenSolvablePolynomial ae = (GenSolvablePolynomial) a.extend(pfe, 0, 0); Map> m = ae.contract(pfec); List> ml = new ArrayList>(m.values()); GenSolvablePolynomial aec = (GenSolvablePolynomial) ml.get(0); assertEquals("a == aec", a, aec); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); } /** * Test reversion with rational coefficients. */ public void testReverse() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4", "x5", "x6" }; // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomial a, b, c, d; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); GenSolvablePolynomialRing pfr = pf.reverse(); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); //System.out.println("pfr = " + pfr); GenSolvablePolynomial ar, br, cr; ar = (GenSolvablePolynomial) a.reverse(pfr); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); assertEquals("b*a == rev(a)*rev(b): ", c, d); } /** * Test reversion for Weyl relations. */ public void testReverseWeyl() { // rational numbers BigRational cf = new BigRational(99); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4", "x5", "x6" }; // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); RelationGenerator wl = new WeylRelations(); wl.generate(pf); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomial a, b, c, d; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); GenSolvablePolynomialRing pfr = pf.reverse(); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); //System.out.println("pfr = " + pfr); GenSolvablePolynomial ar, br, cr; ar = (GenSolvablePolynomial) a.reverse(pfr); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); assertEquals("rev(b*a) == rev(a)*rev(b): ", c, d); } /** * Test recursion. */ public void testRecursion() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); String[] vars = new String[] { "a", "b", "c", "d" }; TermOrder to = new TermOrder(TermOrder.INVLEX); // polynomials over rational numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(rf, 4, to, vars); RelationGenerator wl = new WeylRelations(); //wl.generate(pf); pf.addRelations(wl); //System.out.println("pf = " + pf); GenSolvablePolynomial sp = pf.random(5); //System.out.println("sp = " + sp); sp = (GenSolvablePolynomial) sp.subtract(sp); assertTrue("sp == 0 ", sp.isZERO()); // polynomials over (solvable) polynomials over rational numbers GenSolvablePolynomialRing> rpf = new GenSolvablePolynomialRing>( pf, 2); RelationGenerator> rwl = new WeylRelations>(); //rwl.generate(rpf); rpf.addRelations(rwl); //System.out.println("rpf = " + rpf); GenSolvablePolynomial> rsp = rpf.random(5); //System.out.println("rsp = " + rsp); rsp = (GenSolvablePolynomial>) rsp.subtract(rsp); assertTrue("rsp == 0 ", rsp.isZERO()); } /** * Test reversion with quaternion coefficients. */ public void testReverseQuat() { // quaternion numbers BigQuaternionRing cf = new BigQuaternionRing(); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4" }; // polynomials over quaternion numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomialRing pfr; try { pfr = pf.reverse(); assertFalse("pf coefficents commuative: " + pf, pf.coFac.isCommutative()); } catch (IllegalArgumentException e) { assertTrue("pf coefficents commuative: " + pf, pf.coFac.isCommutative()); pfr = null; } //System.out.println("pf = " + pf.toScript()); //System.out.println("pfr = " + pfr.toScript()); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); // elements BigQuaternion aq, bq, cq, dq; aq = cf.random(3); bq = cf.random(3); //System.out.println("aq = " + aq); //System.out.println("bq = " + bq); cq = aq.multiply(bq).conjugate(); dq = bq.conjugate().multiply(aq.conjugate()); //System.out.println("cq = " + cq); //System.out.println("dq = " + dq); assertEquals("con(a*b) == con(b)*con(a): ", cq, dq); GenSolvablePolynomial a, b, c, d; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); // coefficients GenSolvablePolynomial ar, br, cr; ar = (GenSolvablePolynomial) a.reverse(pfr); //System.out.println("StarRingElem case: " + a.ring.coFac.getONE().getClass()); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); assertEquals("rev(a*b) == rev(b)*rev(a): ", c, d); } /** * Test reversion with complex coefficients. */ public void testReverseComplex() { // complex numbers BigComplex cf = new BigComplex(); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4" }; // polynomials over complex numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomialRing pfr = pf.reverse(); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); //System.out.println("pfr = " + pfr); int kl = 2; int ll = 4; int el = 3; float q = 0.3f; GenSolvablePolynomial a, b, c, d; GenSolvablePolynomial ar, br, cr, dr; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); ar = (GenSolvablePolynomial) a.reverse(pfr); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); //System.out.println("c = " + c); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); //System.out.println("c-d = " + c.subtract(d)); dr = (GenSolvablePolynomial) c.reverse(pfr); //System.out.println("dr = " + dr); //System.out.println("cr-dr = " + cr.subtract(dr)); assertEquals("b*a == rev(a)*rev(b): ", c, d); assertEquals("rev(a)*rev(b) = b * a: ", cr, dr); } /** * Test reversion with complex coefficients as Weyl algebra. */ public void testReverseComplexWeyl() { // complex numbers BigComplex cf = new BigComplex(); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4" }; // polynomials over complex numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); RelationGenerator wl = new WeylRelations(); wl.generate(pf); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomialRing pfr = pf.reverse(); //System.out.println("pfr = " + pfr.toScript()); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); int kl = 2; int ll = 4; int el = 3; float q = 0.3f; GenSolvablePolynomial a, b, c, d; GenSolvablePolynomial ar, br, cr, dr; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); ar = (GenSolvablePolynomial) a.reverse(pfr); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); //System.out.println("c = " + c); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); //System.out.println("c-d = " + c.subtract(d)); dr = (GenSolvablePolynomial) c.reverse(pfr); //System.out.println("dr = " + dr); //System.out.println("cr-dr = " + cr.subtract(dr)); assertEquals("b*a == rev(a)*rev(b): ", c, d); assertEquals("rev(a)*rev(b) = b * a: ", cr, dr); } /** * Test reversion with quaternion coefficients and Weyl relations. */ public void testReverseQuatWeyl() { // quaternion numbers BigQuaternionRing cf = new BigQuaternionRing(); // System.out.println("cf = " + cf); String[] vars = new String[] { "x1", "x2", "x3", "x4" }; // polynomials over quaternion numbers GenSolvablePolynomialRing pf = new GenSolvablePolynomialRing(cf, vars); RelationGenerator wl = new WeylRelations(); wl.generate(pf); //System.out.println("pf = " + pf.toScript()); GenSolvablePolynomialRing pfr; try { pfr = pf.reverse(); assertFalse("pf coefficents commuative: " + pf, pf.coFac.isCommutative()); } catch (IllegalArgumentException e) { assertTrue("pf coefficents commuative: " + pf, pf.coFac.isCommutative()); pfr = null; } //System.out.println("pf = " + pf.toScript()); //System.out.println("pfr = " + pfr.toScript()); GenSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", pf, pfrr); // elements BigQuaternion aq, bq, cq, dq; aq = cf.random(3); bq = cf.random(3); //System.out.println("aq = " + aq); //System.out.println("bq = " + bq); cq = aq.multiply(bq).conjugate(); dq = bq.conjugate().multiply(aq.conjugate()); //System.out.println("cq = " + cq); //System.out.println("dq = " + dq); assertEquals("con(a*b) == con(b)*con(a): ", cq, dq); GenSolvablePolynomial a, b, c, d; a = pf.random(kl, ll, el, q); //System.out.println("a = " + a); // coefficients GenSolvablePolynomial ar, br, cr; ar = (GenSolvablePolynomial) a.reverse(pfr); GenSolvablePolynomial arr = (GenSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); b = pf.random(kl, ll, el, q); //System.out.println("b = " + b); br = (GenSolvablePolynomial) b.reverse(pfr); //System.out.println("br = " + br); c = b.multiply(a); cr = ar.multiply(br); //System.out.println("cr = " + cr); d = (GenSolvablePolynomial) cr.reverse(pfrr); //System.out.println("d = " + d); assertEquals("rev(a*b) == rev(b)*rev(a): ", c, d); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenVectorTest.java000066400000000000000000000152771445075545500242560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.jas.structure.RingElem; //import edu.jas.structure.ModulElem; import edu.jas.arith.BigRational; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; /** * GenVector tests with JUnit * @author Heinz Kredel */ public class GenVectorTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RatGenVectorTest object. * @param name String. */ public GenVectorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GenVectorTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. * */ public void testPolynomialConstruction() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenVectorModul> mfac = new GenVectorModul>( pfac, ll); assertTrue("#columns = " + ll, mfac.cols == ll); assertTrue("pfac == coFac ", pfac == mfac.coFac); GenVector> a; a = mfac.getZERO(); //System.out.println("a = " + a); assertTrue("isZERO( a )", a.isZERO()); GenVector> b = new GenVector>(mfac); //System.out.println("b = " + b); assertTrue("isZERO( b )", b.isZERO()); assertTrue("a == b ", a.equals(b)); GenVector> c = b.copy(); //System.out.println("c = " + c); assertTrue("isZERO( c )", c.isZERO()); assertTrue("a == c ", a.equals(c)); GenVector> d = mfac.copy(b); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("a == d ", a.equals(d)); } /** * Test random vector * */ public void testPolynomialRandom() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenVectorModul> mfac = new GenVectorModul>( pfac, ll); GenVector> a; for (int i = 0; i < 7; i++) { a = mfac.random(kl, q); //System.out.println("a = " + a); assertTrue(" not isZERO( " + a + " )", !a.isZERO()); } } /** * Test addition. * */ public void testPolynomialAddition() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenVectorModul> mfac = new GenVectorModul>( pfac, ll); GenVector> a, b, c, d, e; a = mfac.random(kl, q); b = mfac.random(kl, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = c.sum(b.negate()); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b+(-b) = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = mfac.random(kl, q); d = a.sum(b).sum(c); e = a.sum(b.sum(c)); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test scalar multiplication. * */ public void testPolynomialMultiplication() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl); GenVectorModul> mfac = new GenVectorModul>( pfac, ll); GenPolynomial r, s, t; GenVector> a, b, c, d, e; r = pfac.random(kl); //System.out.println("r = " + r); s = r.negate(); //System.out.println("s = " + s); a = mfac.random(kl, q); //System.out.println("a = " + a); c = a.scalarMultiply(r); d = a.scalarMultiply(s); e = c.sum(d); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a*b + a*(-b) = 0", e, mfac.getZERO()); b = mfac.random(kl, q); //System.out.println("b = " + b); t = pfac.getONE(); //System.out.println("t = " + t); c = a.linearCombination(b, t); d = b.linearCombination(a, t); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); c = a.linearCombination(b, t); d = a.sum(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); s = t.negate(); //System.out.println("s = " + s); c = a.linearCombination(b, t); d = c.linearCombination(b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); c = a.linearCombination(t, b, t); d = c.linearCombination(t, b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); t = pfac.getZERO(); //System.out.println("t = " + t); c = a.linearCombination(b, t); //System.out.println("c = " + c); assertEquals("a+0*b = a", a, c); d = a.linearCombination(t, b, t); //System.out.println("d = " + d); assertEquals("0*a+0*b = 0", mfac.getZERO(), d); r = a.scalarProduct(b); s = b.scalarProduct(a); //System.out.println("r = " + r); //System.out.println("s = " + s); assertEquals("a.b = b.a", r, s); } } java-algebra-system-2.7.200/trc/edu/jas/poly/GenWordPolynomialTest.java000066400000000000000000000707731445075545500257750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.structure.RingElem; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenWordPolynomial tests with JUnit. * @author Heinz Kredel */ public class GenWordPolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenWordPolynomialTest object. * @param name String. */ public GenWordPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(GenWordPolynomialTest.class); return suite; } int rl = 6; int kl = 10; int ll = 7; int el = 5; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructors and factory. */ public void testConstructors() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing pf = new GenWordPolynomialRing(rf, wf); //System.out.println("pf = " + pf); assertFalse("not commutative", pf.isCommutative()); assertTrue("associative", pf.isAssociative()); assertFalse("not field", pf.isField()); String s = pf.toScript(); //System.out.println("pf.toScript: " + s + ", " + s.length()); assertEquals("#s == 32: " + s, s.length(), 32); s = pf.toString(); //System.out.println("pf.toString: " + s + ", " + s.length()); assertEquals("#s == 32: " + s, s.length(), 32); GenWordPolynomial p = pf.getONE(); //System.out.println("p = " + p); assertTrue("p == 1", p.isONE()); p = pf.getZERO(); assertTrue("p == 0", p.isZERO()); //System.out.println("p = " + p); //p = pf.random(9); //System.out.println("p = " + p); List> gens = pf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 7", gens.size() == 7); RingElem> pe = new GenWordPolynomial(pf); //System.out.println("pe = " + pe); //System.out.println("p.equals(pe) = " + p.equals(pe) ); //System.out.println("p.equals(p) = " + p.equals(p) ); assertTrue("p.equals(pe) = ", p.equals(pe)); assertTrue("p.equals(p) = ", p.equals(p)); pe = pe.sum(p); //System.out.println("pe = " + pe); assertTrue("pe.isZERO() = ", pe.isZERO()); p = pf.random(9); p = p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // polynomials over (polynomials over integers) // non-commuting vars: xyz WordFactory wf2 = new WordFactory("xyz"); //System.out.println("wf2 = " + wf2); GenWordPolynomialRing> ppf = new GenWordPolynomialRing>( pf, wf2); //System.out.println("ppf = " + ppf); GenWordPolynomial> pp = ppf.getONE(); //System.out.println("pp = " + pp); assertTrue("pp == 1", pp.isONE()); //pp = ppf.random(2); //System.out.println("pp = " + pp); pp = ppf.getZERO(); //System.out.println("pp = " + pp); assertTrue("pp == 0", pp.isZERO()); List>> pgens = ppf.generators(); //System.out.println("pgens = " + pgens); assertTrue("#pgens == 7+3", pgens.size() == 10); RingElem>> ppe = new GenWordPolynomial>( ppf); //System.out.println("ppe = " + ppe); //System.out.println("pp.equals(ppe) = " + pp.equals(ppe) ); //System.out.println("pp.equals(pp) = " + pp.equals(pp) ); assertTrue("pp.equals(ppe) = ", pp.equals(ppe)); assertTrue("pp.equals(pp) = ", pp.equals(pp)); ppe = ppe.sum(pp); // why not pp = pp.add(ppe) ? //System.out.println("ppe = " + ppe); assertTrue("ppe.isZERO() = ", ppe.isZERO()); pp = ppf.random(2); pp = pp.subtract(pp); //System.out.println("pp = " + pp); //System.out.println("pp.isZERO() = " + pp.isZERO()); assertTrue("pp.isZERO() = ", pp.isZERO()); // polynomials over (polynomials over (polynomials over integers)) // non-commuting vars: uvw WordFactory wf3 = new WordFactory("uvw"); //System.out.println("wf3 = " + wf3); GenWordPolynomialRing>> pppf = new GenWordPolynomialRing>>( ppf, wf3); //System.out.println("pppf = " + pppf); GenWordPolynomial>> ppp = pppf.getONE(); //System.out.println("ppp = " + ppp); assertTrue("ppp == 1", ppp.isONE()); //ppp = pppf.random(2); //System.out.println("ppp = " + ppp); ppp = pppf.getZERO(); //System.out.println("ppp = " + ppp); assertTrue("ppp == 0", ppp.isZERO()); List>>> ppgens = pppf.generators(); //System.out.println("ppgens = " + ppgens); assertTrue("#ppgens == 7+3+3", ppgens.size() == 13); RingElem>>> pppe = new GenWordPolynomial>>( pppf); //System.out.println("pppe = " + pppe); // System.out.println("ppp.equals(pppe) = " + ppp.equals(pppe) ); // System.out.println("ppp.equals(ppp) = " + ppp.equals(ppp) ); assertTrue("ppp.equals(pppe) = ", ppp.equals(pppe)); assertTrue("ppp.equals(ppp) = ", ppp.equals(ppp)); pppe = pppe.sum(ppp); //System.out.println("pppe = " + pppe); assertTrue("pppe.isZERO() = ", pppe.isZERO()); //ppp = pppf.random(2); ppp = ppp.subtract(ppp); //System.out.println("ppp = " + ppp); //System.out.println("ppp.isZERO() = " + ppp.isZERO()); assertTrue("ppp.isZERO() = ", ppp.isZERO()); } /** * Test accessors. */ public void testAccessors() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing pf = new GenWordPolynomialRing(rf, wf); //System.out.println("pf = " + pf); // test 1 GenWordPolynomial p = pf.getONE(); //System.out.println("p = " + p); Word e = p.leadingWord(); BigInteger c = p.leadingBaseCoefficient(); GenWordPolynomial f = new GenWordPolynomial(pf, c, e); assertEquals("1 == 1 ", p, f); GenWordPolynomial r = p.reductum(); assertTrue("red(1) == 0 ", r.isZERO()); // test 0 p = pf.getZERO(); // System.out.println("p = " + p); e = p.leadingWord(); c = p.leadingBaseCoefficient(); f = new GenWordPolynomial(pf, c, e); assertEquals("0 == 0 ", p, f); r = p.reductum(); assertTrue("red(0) == 0 ", r.isZERO()); // test random p = pf.random(kl, ll, el); // System.out.println("p = " + p); e = p.leadingWord(); c = p.leadingBaseCoefficient(); r = p.reductum(); f = new GenWordPolynomial(pf, c, e); f = r.sum(f); assertEquals("p == lm(f)+red(f) ", p, f); // test iteration over random GenWordPolynomial g; g = p; f = pf.getZERO(); while (!g.isZERO()) { e = g.leadingWord(); c = g.leadingBaseCoefficient(); //System.out.println("c e = " + c + " " + e); r = g.reductum(); f = f.sum(c, e); g = r; } assertEquals("p == lm(f)+lm(red(f))+... ", p, f); } /** * Test addition. */ public void testAddition() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(kl, ll, el); GenWordPolynomial b = fac.random(kl, ll, el); GenWordPolynomial c = a.sum(b); GenWordPolynomial d = c.subtract(b); GenWordPolynomial e; assertEquals("a+b-b = a", a, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("deg(a+b) >= deg(a)", c.degree() >= a.degree()); assertTrue("deg(a+b) >= deg(b)", c.degree() >= b.degree()); c = fac.random(kl, ll, el); //System.out.println("\nc = " + c); d = a.sum(b.sum(c)); e = (a.sum(b)).sum(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(e) ); assertEquals("a+(b+c) = (a+b)+c", d, e); Word u = wf.random(rl); BigInteger x = rf.random(kl); b = new GenWordPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); //System.out.println("\nc = " + c); //System.out.println("d = " + d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = new GenWordPolynomial(fac); b = new GenWordPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); } /** * Test multiplication. */ public void testMultiplication() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(kl, ll, el); GenWordPolynomial b = fac.random(kl, ll, el); GenWordPolynomial c = a.multiply(b); GenWordPolynomial d = b.multiply(a); GenWordPolynomial e; assertFalse("a*b != b*a", c.equals(d)); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("maxNorm(a*b) >= maxNorm(a)", c.maxNorm().compareTo(a.maxNorm()) >= 0); assertTrue("maxNorm(a*b) >= maxNorm(b)", c.maxNorm().compareTo(b.maxNorm()) >= 0); c = fac.random(kl, ll, el); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a*(b*c) = (a*b)*c", d, e); Word u = wf.random(rl); BigInteger x = rf.random(kl); b = new GenWordPolynomial(fac, x, u); c = a.multiply(b); d = a.multiply(x, u); assertEquals("a*p(x,u) = a*(x,u)", c, d); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = new GenWordPolynomial(fac); b = new GenWordPolynomial(fac, x, u); c = a.multiply(b); d = a.multiply(x, u); assertEquals("a*p(x,u) = a*(x,u)", c, d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); BigInteger y = rf.random(kl); c = a.multiply(x, y); //System.out.println("c = " + c); d = a.multiply(y, x); //System.out.println("d = " + d); assertEquals("x a y = y a x", c, d); } /** * Test distributive law. */ public void testDistributive() { // integers BigInteger rf = new BigInteger(); // System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(kl, ll, el); GenWordPolynomial b = fac.random(kl, ll, el); GenWordPolynomial c = fac.random(kl, ll, el); GenWordPolynomial d, e; d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test univariate division. */ public void testUnivDivision() { // rational numbers BigRational rf = new BigRational(); //System.out.println("rf = " + rf); // non-commuting vars: x WordFactory wf = new WordFactory("x"); //System.out.println("wf = " + wf); // polynomials over rational numbers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(7, ll, el).monic(); GenWordPolynomial b = fac.random(7, ll, el).monic(); GenWordPolynomial c = a.multiply(b); GenWordPolynomial d = b.multiply(a); GenWordPolynomial e, f; assertTrue("a*b == b*a", c.equals(d)); // since univariate //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = c.divide(a); //System.out.println("e = " + e); assertTrue("a*b/a == b", b.equals(e)); d = c.divide(b); //System.out.println("d = " + d); assertTrue("a*b/b == a", a.equals(d)); d = c.gcd(a); //System.out.println("d = " + d); assertTrue("gcd(a*b,a) == a", a.equals(d)); d = a.gcd(b); //System.out.println("d = " + d); if (d.isConstant()) { assertTrue("gcd(b,a) == 1", d.isONE()); } else { return; } d = a.modInverse(b); //System.out.println("d = " + d); e = d.multiply(a); //System.out.println("e = " + e); f = e.remainder(b); //System.out.println("f = " + f); assertTrue("d * a == 1 mod b ", f.isONE()); GenWordPolynomial[] egcd; egcd = a.egcd(b); d = egcd[0]; e = egcd[1]; f = egcd[2]; //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("f = " + f); c = e.multiply(a).sum(f.multiply(b)); //System.out.println("d = " + d); assertEquals("gcd(a,b) == e*a + f*b", c, d); // since univariate } /** * Test multivariate 2 division. */ public void testMulti2Division() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // non-commuting vars: xy WordFactory wf = new WordFactory("xy"); //System.out.println("wf = " + wf); // polynomials over rational numbers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(7, ll, el).monic(); GenWordPolynomial b = fac.random(7, ll, el).monic(); GenWordPolynomial c = a.multiply(b); GenWordPolynomial d = b.multiply(a); GenWordPolynomial e, f; assertFalse("a*b == b*a", c.equals(d)); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = c.divide(a); //System.out.println("e = " + e); assertTrue("a*b/a == b", b.equals(e)); f = d.divide(b); //System.out.println("f = " + f); assertTrue("a*b/b == a", a.equals(f)); try { f = a.divide(b); //System.out.println("f = " + f); } catch (RuntimeException re) { System.out.println("a divide b fail: " + a + ", " + b); return; } WordFactory.WordComparator cmp = fac.alphabet.getDescendComparator(); f = a.remainder(b); //System.out.println("a = " + a); //System.out.println("f = " + f); assertTrue("a rem2 b <= a", cmp.compare(a.leadingWord(), f.leadingWord()) <= 0); } /** * Test multivariate 3 division. */ public void testMulti3Division() { // rational numbers BigRational rf = new BigRational(); // System.out.println("rf = " + rf); // non-commuting vars: xyz WordFactory wf = new WordFactory("xyz"); //System.out.println("wf = " + wf); // polynomials over rational numbers GenWordPolynomialRing fac = new GenWordPolynomialRing(rf, wf); //System.out.println("fac = " + fac); GenWordPolynomial a = fac.random(7, ll, el).monic(); GenWordPolynomial b = fac.random(7, ll, el).monic(); GenWordPolynomial c = a.multiply(b); GenWordPolynomial d = b.multiply(a); GenWordPolynomial e, f; assertFalse("a*b == b*a", c.equals(d)); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = c.divide(a); //System.out.println("e = " + e); assertTrue("a*b/a == b", b.equals(e)); f = d.divide(b); //System.out.println("f = " + f); assertTrue("a*b/b == a", a.equals(f)); try { f = a.divide(b); //System.out.println("f = " + f); } catch (RuntimeException re) { System.out.println("a divide b fail: " + a + ", " + b); return; } WordFactory.WordComparator cmp = fac.alphabet.getDescendComparator(); f = a.remainder(b); //System.out.println("a = " + a); //System.out.println("f = " + f); assertTrue("a rem3 b <= a: " + a.leadingWord() + ", " + f.leadingWord(), cmp.compare(a.leadingWord(), f.leadingWord()) <= 0); } /** * Test polynomial and solvable coefficients. */ public void testCoefficients() { // integers BigComplex rf = new BigComplex(); //System.out.println("rf = " + rf); // commuting vars: uvw String[] cvar = new String[] { "u", "v", "w" }; GenPolynomialRing cf = new GenPolynomialRing(rf, cvar); //System.out.println("cf = " + cf); // solvable vars: x1 x2 y1 y2 String[] svar = new String[] { "x1", "x2", "y1", "y2" }; GenSolvablePolynomialRing> sf; sf = new GenSolvablePolynomialRing>(cf, svar); //System.out.println("sf = " + sf); RelationGenerator> wr = new WeylRelations>(); wr.generate(sf); //System.out.println("sf = " + sf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); // non-commuting polynomials over commuting and solvable coefficients GenWordPolynomialRing>> nf; nf = new GenWordPolynomialRing>>(sf, wf); //want: GenWordPolynomialRing>> nf; //System.out.println("nf = " + nf.toScript()); assertFalse("not commutative", nf.isCommutative()); assertTrue("associative", nf.isAssociative()); assertFalse("not field", nf.isField()); GenWordPolynomial>> p = nf.getONE(); //System.out.println("p = " + p); assertTrue("p == 1", p.isONE()); p = nf.getZERO(); //System.out.println("p = " + p); assertTrue("p == 0", p.isZERO()); p = nf.random(3); //System.out.println("p = " + p); //p = p.sum(p); p = p.multiply(p); //System.out.println("p = " + p); p = p.subtract(p); //System.out.println("p = " + p); assertTrue("p == 0", p.isZERO()); List>>> gens = nf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 2+3+4+6", gens.size() == 15); } /** * Test contraction. */ public void testContraction() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // non-commuting vars: abcdef WordFactory wf = new WordFactory("abcdef"); //System.out.println("wf = " + wf); WordFactory wfs = new WordFactory("abc"); //System.out.println("wf = " + wf); // polynomials over integers GenWordPolynomialRing pf = new GenWordPolynomialRing(rf, wf); //System.out.println("pf = " + pf); GenWordPolynomialRing pfs = new GenWordPolynomialRing(rf, wfs); //System.out.println("pfs = " + pfs); List> H = new ArrayList>(); GenWordPolynomial a = pf.random(5).abs(); //System.out.println("a = " + a); GenWordPolynomial as = pfs.random(5).abs(); //System.out.println("as = " + as); GenWordPolynomial asf = pf.valueOf(as); H.add(asf); H.add(asf.multiply(pf.valueOf(pfs.random(5).abs()))); H.add(pfs.random(5).abs()); //System.out.println("asf = " + asf); GenWordPolynomial asfc = asf.contract(pfs); //System.out.println("asfc = " + asfc); assertEquals("as == contract(extend(as)): ", as, asfc); // mostly not contractable GenWordPolynomial ac = a.contract(pfs); H.add(a); //System.out.println("ac = " + ac); assertTrue("contract(a) == 0: " + ac, ac.isZERO() || pf.valueOf(ac).equals(a)); // 1 always contractable a = pf.getONE(); H.add(a); ac = a.contract(pfs); //System.out.println("ac = " + ac); assertTrue("contract(1) == 1: ", ac.isONE()); // now contract lists of word polynomials //System.out.println("H = " + H); List> M = PolyUtil. intersect(pfs, H); //System.out.println("M = " + M); int i = 0; for (GenWordPolynomial h : H) { if (!h.contract(pfs).isZERO()) { assertEquals("extend(contract(h)) == h: " + h, h, pf.valueOf(M.get(i++))); } } } /** * Test constructors and factory. */ @SuppressWarnings("unchecked") public void testParser() { BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf.toScriptFactory()); // non-commuting vars: abcdef String[] sa = new String[] { "a", "b", "c", "d", "e", "f" }; WordFactory wf = new WordFactory(sa); //System.out.println("wf = " + wf.toScript()); // word polynomials over integers GenWordPolynomialRing pf = new GenWordPolynomialRing(rf, wf); //System.out.println("pf = " + pf.toScript()); assertFalse("not commutative", pf.isCommutative()); assertTrue("associative", pf.isAssociative()); assertFalse("not field", pf.isField()); List> gens = pf.generators(); //System.out.println("pf = " + gens); GenWordPolynomial ga, gb, crel; ga = gens.get(1); gb = gens.get(2); //System.out.println("ga = " + ga + ", " + ga.toScript()); //System.out.println("gb = " + gb); assertEquals("#s == 3: ", ga.toString().length(), 3); assertEquals("#s == 1: ", ga.toScript().length(), 1); crel = ga.multiply(gb).subtract(gb.multiply(ga)); //System.out.println("crel = " + crel); StringReader sr = new StringReader("a b - b a, b c - c b"); GenPolynomialTokenizer tok = new GenPolynomialTokenizer(sr); GenWordPolynomial a; // parse of tokenizer try { a = (GenWordPolynomial) tok.nextWordPolynomial(pf); } catch (IOException e) { a = null; e.printStackTrace(); } //System.out.println("a = " + a); assertEquals("parse() == ab - ba: ", a, crel); // now parse of factory a = pf.parse("a b - b a"); //System.out.println("a = " + a); assertEquals("parse() == ab - ba: ", a, crel); // polynomials over integers GenPolynomialRing fac = new GenPolynomialRing(rf, sa); //System.out.println("fac = " + fac.toScript()); assertTrue("commutative", fac.isCommutative()); assertTrue("associative", fac.isAssociative()); assertFalse("not field", fac.isField()); sr = new StringReader("a b - b a, b c - c b"); tok = new GenPolynomialTokenizer(fac, sr); // parse of tokenizer try { a = (GenWordPolynomial) tok.nextWordPolynomial(); } catch (IOException e) { a = null; e.printStackTrace(); } //System.out.println("a = " + a); assertEquals("parse() == ab - ba: ", a, crel); } /** * Test iterators. */ public void testIterators() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf); // word polynomials over integral numbers GenWordPolynomialRing pf = new GenWordPolynomialRing(rf, "abcdef"); //System.out.println("pf = " + pf); // random polynomial GenWordPolynomial p = pf.random(kl, 2 * ll, el); //System.out.println("p = " + p); // test monomials for (WordMonomial m : p) { //System.out.println("m = " + m); assertFalse("m.c == 0 ", m.coefficient().isZERO()); assertFalse("m.e < (0) ", m.word().signum() < 0); } } } java-algebra-system-2.7.200/trc/edu/jas/poly/IndexListTest.java000066400000000000000000000173561445075545500242650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Arrays; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * IndexList tests with JUnit. Tests construction and arithmetic operations. * @author Heinz Kredel */ public class IndexListTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a IndexListTest object. * @param name String. */ public IndexListTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(IndexListTest.class); return suite; } IndexList a, b, c, d, e; IndexFactory idf; int ll = 11; float q = 0.5f; @Override protected void setUp() { idf = new IndexFactory(ll); a = b = c = d = null; } @Override protected void tearDown() { a = b = c = d = null; } /** * Test constructor and toString. */ public void testConstructor() { a = idf.random(0, q); b = a; //System.out.println("a = " + a); assertEquals("() = ()", a, b); assertTrue("length( () ) = 0", a.length() <= 0); assertTrue("isZERO( () )", a.isZERO()); assertFalse("isONE( () )", a.isONE()); assertFalse("isUnit( () )", a.isUnit()); b = idf.random(10, q); //System.out.println("b = " + b); assertTrue("length( () ) = 0", b.length() >= 0); assertFalse("isZERO( () )", b.isZERO()); assertFalse("isONE( () )", b.isONE()); assertFalse("isUnit( () )", b.isUnit()); c = new IndexList(idf); //System.out.println("c = " + c); //assertNotEquals("() = ()", a, c); assertTrue("length( 0 ) = -1", c.length() < 0); assertTrue("isZERO( () )", c.isZERO()); assertFalse("isONE( () )", c.isONE()); assertFalse("isUnit( () )", c.isUnit()); c = idf.getONE(); //System.out.println("c = " + c); assertTrue("length( 1 ) = 1", c.length() >= 0); assertFalse("isZERO( () )", c.isZERO()); assertTrue("isONE( () )", c.isONE()); assertTrue("isUnit( () )", c.isUnit()); String s = b.toString(); String t = b.toScript(); //System.out.println("s = " + s); //System.out.println("t = " + t); assertEquals("s == t: ", s, t); //System.out.println("idf = " + idf); IndexFactory ids = new IndexFactory(idf.imaxlength, "I"); //System.out.println("ids = " + ids); assertEquals("idf == ids: ", idf.length(), ids.length()); assertEquals("idf == ids: ", idf, ids); ids = new IndexFactory(idf.imaxlength); //System.out.println("ids = " + ids); assertEquals("idf == ids: ", idf.length(), ids.length()); assertEquals("idf == ids: ", idf, ids); } /** * Test random IndexList. */ public void testRandom() { a = idf.random(5); b = idf.random(7); c = idf.random(9); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertFalse("a != (): ", a.isZERO()); assertFalse("b != (): ", b.isZERO()); assertFalse("c != (): ", c.isZERO()); assertFalse("a != b: ", a.equals(b)); assertFalse("a != c: ", a.equals(c)); assertFalse("c != b: ", c.equals(b)); d = c.abs(); //System.out.println("d = " + d); assertTrue("sign(d) > 0: ", d.signum() > 0); if (d.degree() > 1) { assertTrue("minDeg < maxDeg: ", d.minDeg() < d.maxDeg()); } } /** * Test multiplication. */ public void testMultiplication() { a = idf.random(9, 0.2f); b = idf.random(7, 0.3f); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(b); d = b.multiply(a); //System.out.println("c = " + c); //System.out.println("d = " + d); //assertTrue("ab = -ba: " + c + " ==? " + d, c.isZERO() || d.isZERO() || a.isONE() || b.isONE() || c.equals(d.negate())); if (c.isZERO()) { return; } boolean div = a.divides(c); assertTrue("a | c: ", div); div = b.divides(c); assertTrue("b | c: ", div); //System.out.println("div = " + div); IndexList ca, cb; ca = a.interiorRightProduct(c); cb = b.interiorRightProduct(c); //System.out.println("ca = " + ca); //System.out.println("cb = " + cb); assertEquals("a == cb: ", a.abs(), cb.abs()); assertEquals("b == ca: ", b.abs(), ca.abs()); ca = c.interiorLeftProduct(a); cb = c.interiorLeftProduct(b); //System.out.println("ca_l = " + ca); //System.out.println("cb_l = " + cb); } /** * Test sequence IndexList. */ public void testSequence() { a = idf.sequence(0, 4); b = idf.sequence(4, 3); c = idf.sequence(0, 7); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertFalse("a != (): ", a.isZERO()); assertFalse("b != (): ", b.isZERO()); assertFalse("c != (): ", c.isZERO()); assertFalse("a != b: ", a.equals(b)); assertFalse("a != c: ", a.equals(c)); assertFalse("c != b: ", c.equals(b)); d = a.multiply(b); e = b.multiply(a); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("c == ab: ", c, d); IndexList ca, cb; ca = a.interiorRightProduct(d); cb = b.interiorRightProduct(d); //System.out.println("ca = " + ca); //System.out.println("cb = " + cb); assertEquals("a == cb: ", a.abs(), cb.abs()); assertEquals("b == ca: ", b.abs(), ca.abs()); } /** * Test valueOf. */ public void testValueOf() { ExpVector ef = ExpVector.random(4, 2L, 0.8f); //System.out.println("ef = " + ef); a = idf.valueOf(ef); //System.out.println("a = " + a); if (!a.isZERO()) { assertTrue("depend(ef) == deg(a): " + ef + ", " + a, ef.dependentVariables() == a.degree()); } String as = a.toString() + " = " + a.toScript(); //System.out.println("as = " + as); assertTrue("as != ''" + as, as.length() >= 0); List W = Arrays. asList(1, 4, 7, 8, 13, 17); //System.out.println("W = " + W); a = idf.valueOf(W); //System.out.println("a = " + a); assertTrue("deg(a) == #W " + W + ", " + a, W.size() == a.degree()); int[] w = new int[] { 1, 4, 7, 8, 13, 17, 4, 1 }; //System.out.println("w = " + w); a = idf.valueOf(w); //System.out.println("a = " + a); assertTrue("a == 0: " + a, a.isZERO()); a = idf.valueOf((int[]) null); //System.out.println("a = " + a); assertTrue("a == 0: " + a, a.isZERO()); w = new int[] { 7, 8, 13, 17, 4, 1 }; //System.out.println("w = " + w); a = idf.valueOf(w); //System.out.println("a = " + a); assertTrue("deg(a) == #w: " + a, a.degree() == w.length); assertTrue("sign(a) < 0: " + a, a.signum() < 0); assertTrue("check(a) == true: " + a, a.isConformant()); b = new IndexList(idf, w); //System.out.println("b = " + b); assertFalse("check(b) == false: " + b, b.isConformant()); c = idf.valueOf(b); //System.out.println("c = " + c); assertTrue("check(b) == true: " + c, c.isConformant()); } } java-algebra-system-2.7.200/trc/edu/jas/poly/IntGenPolynomialTest.java000066400000000000000000000227061445075545500256050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.HashSet; import java.util.List; import java.util.Set; import edu.jas.arith.BigInteger; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigInteger coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class IntGenPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a IntGenPolynomialTest object. * @param name String. */ public IntGenPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(IntGenPolynomialTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new BigInteger(1), rl); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test generate. */ public void testGenerate() { String s = fac.toScript(); //System.out.println("fac.toScript: " + s + ", " + s.length()); assertTrue("#s == 50: " + s, s.length() == 50); List> gens = fac.generators(); assertFalse("#gens != () ", gens.isEmpty()); //System.out.println("generators: " + gens); // test equals Set> set = new HashSet>(gens); //System.out.println("gen set: " + set); assertEquals("#gens == #set: ", gens.size(), set.size()); // test for elements 0, 1 a = fac.getZERO(); b = fac.getONE(); assertFalse("0 not in #set: ", set.contains(a)); assertTrue("1 in #set: ", set.contains(b)); // specific tests assertEquals("#gens == rl+1 ", rl + 1, gens.size()); Set iset = new HashSet(set.size()); for (GenPolynomial p : gens) { //System.out.println("p = " + p.toScript() + ", # = " + p.hashCode() + ", red = " + p.reductum()); assertTrue("red(p) == 0 ", p.reductum().isZERO()); iset.add(p.hashCode()); } assertEquals("#gens == #iset: ", gens.size(), iset.size()); } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl * (i + 2), ll + 2 * i, el + i, q); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(kl, ll, el, q); ExpVector u = ExpVector.random(rl, el, q); BigInteger x = BigInteger.IRAND(kl); b = new GenPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial(fac); b = new GenPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl, ll, el, q); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); //BigInteger x = a.leadingBaseCoefficient().inverse(); //c = a.monic(); //d = a.multiply(x); //assertEquals("a.monic() = a(1/ldcf(a))",c,d); BigInteger y = b.leadingBaseCoefficient(); //c = b.monic(); //d = b.multiply(y); //assertEquals("b.monic() = b(1/ldcf(b))",c,d); e = new GenPolynomial(fac, y); c = b.multiply(e); // assertEquals("b.monic() = b(1/ldcf(b))",c,d); d = e.multiply(b); assertEquals("b*p(y,u) = p(y,u)*b", c, d); } /** * Test BLAS level 1. */ public void testBLAS1() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); ExpVector ev = ExpVector.random(rl, el, q); BigInteger lc = BigInteger.IRAND(kl); d = a.subtractMultiple(lc, b); e = a.subtract(b.multiply(lc)); assertEquals("a - (lc) b == a - ((lc) b)", d, e); d = a.subtractMultiple(lc, ev, b); e = a.subtract(b.multiply(lc, ev)); assertEquals("a - (lc ev) b == a - ((lc ev) b)", d, e); ExpVector fv = ExpVector.random(rl, el, q); BigInteger tc = BigInteger.IRAND(kl); d = a.scaleSubtractMultiple(tc, lc, ev, b); e = a.multiply(tc).subtract(b.multiply(lc, ev)); assertEquals("(tc) a - (lc ev) b == ((tc) a - ((lc ev) b))", d, e); d = a.scaleSubtractMultiple(tc, fv, lc, ev, b); e = a.multiply(tc, fv).subtract(b.multiply(lc, ev)); assertEquals("(tc fv) a - (lc ev) b == ((tc fv) a - ((lc ev) b))", d, e); d = a.scaleSubtractMultiple(tc, lc, b); e = a.multiply(tc).subtract(b.multiply(lc)); assertEquals("tc a - lc b == (tc a) - (lc b)", d, e); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test absolute norm. */ public void testAbsNorm() { BigInteger r, ar; a = fac.getONE().negate(); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue("isONE( absNorm(-1) )", r.isONE()); a = fac.random(kl * 2, ll + 2, el, q); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue(" not isZERO( absNorm(a) )", !r.isZERO() || a.isZERO()); } /** * Test max norm. */ public void testMaxNorm() { BigInteger r, s; a = fac.getZERO(); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("isONE( maxNorm(0) )", r.isZERO()); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("isONE( sumNorm(0) )", r.isZERO()); a = fac.getONE().negate(); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("isONE( maxNorm(-1) )", r.isONE()); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("isONE( sumNorm(-1) )", r.isONE()); a = fac.random(kl * 2, ll + 2, el, q); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("not isZERO( maxNorm(a) )", !r.isZERO() || a.isZERO()); //s = a.multiply(a).maxNorm(); //System.out.println("s = " + s + ", r*r = " + r.multiply(r)); //assertEquals("s*s == maxNorm(a*a) )", r.multiply(r), s ); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("not isZERO( maxNorm(a) )", !r.isZERO() || a.isZERO()); //s = a.multiply(a).sumNorm(); //System.out.println("s = " + s + ", r*r = " + r.multiply(r)); //assertEquals("s*s == sumNorm(a*a) ): ", r.multiply(r), s ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/LocalTest.java000066400000000000000000000232331445075545500234030ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Local tests with JUnit. * @author Heinz Kredel */ public class LocalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a LocalTest object. * @param name String. */ public LocalTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(LocalTest.class); return suite; } LocalRing fac; GenPolynomialRing pfac; LocalRing> mfac; Local a, b, c, d, e; Local> ap, bp, cp, dp, ep; int rl = 1; int kl = 13; int ll = 5; int el = 2; float q = 0.3f; int il = 2; long p = 1152921504606846883L; // 2^60-93; @Override protected void setUp() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; BigInteger cfac = new BigInteger(1); fac = new LocalRing(cfac, new BigInteger(p)); pfac = new GenPolynomialRing(new BigRational(1), 1); GenPolynomial mo = pfac.random(kl, ll, el, q); while (mo.isConstant()) { mo = pfac.random(kl, ll, el, q); } mfac = new LocalRing>(pfac, mo); } @Override protected void tearDown() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; fac = null; pfac = null; mfac = null; } /** * Test factory for integer. */ public void testIntRing() { assertFalse("#ring infinite", fac.isFinite()); assertTrue("associative ring", fac.isAssociative()); assertTrue("commutative ring", fac.isCommutative()); assertTrue("characteristic zero", fac.characteristic().signum() == 0); assertFalse("no field", fac.isField()); } /** * Test factory for polynomial. */ public void testPolyRing() { assertFalse("#ring infinite", mfac.isFinite()); assertTrue("associative ring", mfac.isAssociative()); assertTrue("commutative ring", mfac.isCommutative()); assertTrue("characteristic zero", mfac.characteristic().signum() == 0); assertFalse("no field", mfac.isField()); } /** * Test constructor for integer. */ public void testIntConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); List> gens = fac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 1: ", gens.size() == 1); for (Local v : gens) { a = fac.parse(v.toString()); assertEquals("a == v", a, v); } } /** * Test constructor for polynomial. */ public void testPolyConstruction() { cp = mfac.getONE(); assertTrue("isZERO( cp )", !cp.isZERO()); assertTrue("isONE( cp )", cp.isONE()); dp = mfac.getZERO(); assertTrue("isZERO( dp )", dp.isZERO()); assertTrue("isONE( dp )", !dp.isONE()); List>> gens = mfac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 3: ", gens.size() == 3); for (Local> v : gens) { ap = mfac.parse(v.toString()); assertEquals("ap == v", ap, v); } } /** * Test random integer. */ public void testRandom() { for (int i = 0; i < 4; i++) { a = fac.random(kl * (i + 1)); //a = fac.random(kl*(i+1), ll+i, el, q ); //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test random polynomial. */ public void testPolyRandom() { for (int i = 0; i < 7; i++) { ap = mfac.random(kl + i); assertTrue(" not isZERO( ap" + i + " )", !ap.isZERO()); assertTrue(" not isONE( ap" + i + " )", !ap.isONE()); } } /** * Test integer addition. */ public void testIntAddition() { a = fac.random(kl); b = fac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(kl); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test polynomial addition. */ public void testPolyAddition() { ap = mfac.random(kl); bp = mfac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); cp = ap.sum(bp); dp = cp.subtract(bp); assertEquals("a+b-b = a", ap, dp); cp = ap.sum(bp); dp = bp.sum(ap); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", cp, dp); cp = mfac.random(kl); dp = cp.sum(ap.sum(bp)); ep = cp.sum(ap).sum(bp); assertEquals("c+(a+b) = (c+a)+b", dp, ep); cp = ap.sum(mfac.getZERO()); dp = ap.subtract(mfac.getZERO()); assertEquals("a+0 = a-0", cp, dp); cp = mfac.getZERO().sum(ap); dp = mfac.getZERO().subtract(ap.negate()); assertEquals("0+a = 0+(-a)", cp, dp); } /** * Test integer multiplication. */ public void testIntMultiplication() { a = fac.random(kl); b = fac.random(kl); if (a.isZERO() || b.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } Local[] qr; c = b.multiply(a); qr = c.quotientRemainder(a); assertEquals("b*a / a == b", qr[0], b); assertTrue("b*a rem a == 0", qr[1].isZERO()); } /** * Test polynomial multiplication. */ public void testPolyMultiplication() { ap = mfac.random(kl); bp = mfac.random(kl); if (ap.isZERO() || bp.isZERO()) { return; } assertTrue("not isZERO( a )", !ap.isZERO()); assertTrue("not isZERO( b )", !bp.isZERO()); cp = bp.multiply(ap); dp = ap.multiply(bp); assertTrue("not isZERO( c )", !cp.isZERO()); assertTrue("not isZERO( d )", !dp.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); ep = dp.subtract(cp); assertTrue("isZERO( a*b-b*a ) " + ep, ep.isZERO()); assertTrue("a*b = b*a", cp.equals(dp)); assertEquals("a*b = b*a", cp, dp); cp = mfac.random(kl); //System.out.println("c = " + c); dp = ap.multiply(bp.multiply(cp)); ep = (ap.multiply(bp)).multiply(cp); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", dp, ep); assertTrue("a(bc) = (ab)c", dp.equals(ep)); cp = ap.multiply(mfac.getONE()); dp = mfac.getONE().multiply(ap); assertEquals("a*1 = 1*a", cp, dp); if (ap.isUnit()) { cp = ap.inverse(); dp = cp.multiply(ap); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", dp.isONE()); } Local>[] qr; cp = bp.multiply(ap); qr = cp.quotientRemainder(ap); assertEquals("b*a / a == b", qr[0], bp); assertTrue("b*a rem a == 0", qr[1].isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ModGenPolynomialTest.java000066400000000000000000000120031445075545500255570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; // import edu.jas.structure.RingElem; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ModInteger coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class ModGenPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModGenPolynomialTest object. * @param name String. */ public ModGenPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ModGenPolynomialTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int ml = 19; // modul int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; fac = new GenPolynomialRing(new ModIntegerRing(ml), rl); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll); //fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(ll); ExpVector u = ExpVector.random(rl, el, q); ModInteger x = c.leadingBaseCoefficient().ring.random(kl); b = new GenPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial(fac); b = new GenPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); ModInteger x = a.leadingBaseCoefficient().inverse(); c = a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))", c, d); ModInteger y = b.leadingBaseCoefficient().inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = new GenPolynomial(fac, y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b", c, d); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ModGenSolvablePolynomialTest.java000066400000000000000000000250461445075545500272620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; /** * ModInteger coefficients GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class ModGenSolvablePolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModGenSolvablePolynomialTest object. * @param name String. */ public ModGenSolvablePolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ModGenSolvablePolynomialTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e, f, x1, x2; int ml = 19; // modul int rl = 5; int kl = 10; int ll = 5; int el = 3; float q = 0.5f; RelationTable table; GenSolvablePolynomialRing ring; ModIntegerRing cfac; @Override protected void setUp() { cfac = new ModIntegerRing(ml); ring = new GenSolvablePolynomialRing(cfac, rl); table = null; //ring.table; a = b = c = d = e = null; } @Override protected void tearDown() { table = null; ring = null; a = b = c = d = e = null; } /** * Test constructor and toString. */ public void testConstructor() { a = new GenSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { assertTrue("isCommutative()", ring.isCommutative()); for (int i = 0; i < 2; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (GenSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (GenSolvablePolynomial) a.sum(a); c = (GenSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); assertTrue("a+a-a = a", c.equals(a)); b = ring.random(kl, ll, el, q); c = (GenSolvablePolynomial) b.sum(a); d = (GenSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); assertTrue("a+b = b+a", c.equals(d)); c = ring.random(kl, ll, el, q); d = (GenSolvablePolynomial) a.sum(b.sum(c)); e = (GenSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); assertTrue("a+(b+c) = (a+b)+c", d.equals(e)); ExpVector u = ExpVector.random(rl, el, q); ModInteger x = cfac.random(kl); b = ring.getONE().multiply(x, u); c = (GenSolvablePolynomial) a.sum(b); d = (GenSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (GenSolvablePolynomial) a.subtract(b); d = (GenSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (GenSolvablePolynomial) b.sum(a); d = (GenSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (GenSolvablePolynomial) a.subtract(b); d = (GenSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ @SuppressWarnings("cast") public void testMultiplication() { a = ring.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); //a = ModGenSolvablePolynomial.DIRRAS(1, kl, 4, el, q ); b = ring.random(kl, ll, el, q); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertEquals("a*b = b*a", c, d); assertTrue("a*b = b*a", c.equals(d)); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); ModInteger x = a.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))", c, d); ExpVector u = ring.evzero; ModInteger y = b.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) b.monic(); d = b.multiply(y, u); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = ring.getONE().multiply(y, u); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b", c, d); d = a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test Weyl polynomials. */ public void testWeyl() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); //table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el + 2, q); assertTrue("not isZERO( a )", !a.isZERO()); //System.out.println("a = " + a); b = ring.random(kl, ll, el + 2, q); assertTrue("not isZERO( b )", !b.isZERO()); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("!isZERO( a*b-b*a ) " + e, !e.isZERO()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); //System.out.println("\na = " + a); //System.out.println("\nb = " + b); //System.out.println("\nc = " + c); // associative //x1 = b.multiply(c); //System.out.println("\nx1 = " + x1); d = a.multiply(b.multiply(c)); //x2 = a.multiply(b); //System.out.println("\nx2 = " + x2); e = a.multiply(b).multiply(c); //System.out.println("\nd = " + d); //System.out.println("\ne = " + e); //f = (GenSolvablePolynomial)d.subtract(e); //System.out.println("\nf = " + f); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); } /** * Test BLAS level 1. */ public void testBLAS1() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); a = ring.random(kl,ll,el,q); b = ring.random(kl,ll,el,q); ExpVector ev = ExpVector.random(rloc,el,q); ModInteger lc = cfac.random(kl); d = a.subtractMultiple(lc,b); e = (GenSolvablePolynomial) a.subtract( b.multiply(lc) ); assertEquals("a - (lc) b == a - ((lc) b)",d,e); d = a.subtractMultiple(lc,ev,b); e = (GenSolvablePolynomial) a.subtract( b.multiplyLeft(lc,ev) ); assertEquals("a - (lc ev) b == a - ((lc ev) b): " + lc + ", " + ev, d, e); ExpVector fv = ExpVector.random(rloc,el,q); ModInteger tc = cfac.random(kl); d = a.scaleSubtractMultiple(tc,lc,ev,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc).subtract( b.multiplyLeft(lc,ev) ); assertEquals("(tc) a - (lc ev) b == ((tc) a - ((lc ev) b))",d,e); d = a.scaleSubtractMultiple(tc,fv,lc,ev,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc,fv).subtract( b.multiplyLeft(lc,ev) ); assertEquals("(tc fv) a - (lc ev) b == ((tc fv) a - ((lc ev) b)): " + tc + ", " + fv + ", " + lc + ", " + ev, d, e); d = a.scaleSubtractMultiple(tc,lc,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc).subtract( b.multiplyLeft(lc) ); assertEquals("tc a - lc b == (tc a) - (lc b)",d,e); } /** * Test distributive law. */ public void testDistributive() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); //table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((GenSolvablePolynomial) b.sum(c)); e = (GenSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ModuleListTest.java000066400000000000000000000202721445075545500244320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ModuleList tests with JUnit. * @author Heinz Kredel */ public class ModuleListTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ModuleListTest object. * @param name String. */ public ModuleListTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite = new TestSuite(ModuleListTest.class); return suite; } ModuleList m; PolynomialList p; GenPolynomial a, b, c, d, e; BigRational cfac; GenPolynomialRing pfac; int rl = 4; int kl = 4; int ll = 4; int el = 5; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigRational(1); TermOrder tord = new TermOrder(); pfac = new GenPolynomialRing(cfac, rl, tord); m = null; p = null; } @Override protected void tearDown() { a = b = c = d = e = null; m = null; p = null; } /** * Test constructor and toString. */ public void testConstructor() { p = new PolynomialList(pfac, (List>) null); assertTrue("p = 0", p.list == null); m = new ModuleList(pfac, (List>>) null); assertTrue("m = 0", m.list == null); } /** * Test polynomial list. */ public void testPolynomialList() { List> l = new ArrayList>(); for (int i = 0; i < 7; i++) { a = pfac.random(kl, ll + i, el, q); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); l.add(a); } p = new PolynomialList(pfac, l); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p)); assertEquals("p.length", 7, p.list.size()); } /** * Test module list. */ public void testModuleList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for (int j = 0; j < 3; j++) { a = pfac.random(kl, ll, el, q); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); r.add(a); } l.add(r); } m = new ModuleList(pfac, l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m)); assertEquals("m.length", 4, m.list.size()); List perm = new ArrayList(pfac.nvar); for (int i = 0; i < pfac.nvar; i++) { perm.add(i); } OptimizedModuleList op = new OptimizedModuleList(perm, pfac, l); assertTrue("op == op", op.equals(op)); assertFalse("op != m", op.equals(m)); assertEquals("#var == #perm", pfac.nvar, op.perm.size()); } /** * Test module and polynomial list. */ public void testModulePolynomialList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for (int j = 0; j < 3; j++) { a = pfac.random(kl, ll, el, q); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); r.add(a); } l.add(r); } m = new ModuleList(pfac, l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m)); assertEquals("m.length", 4, m.list.size()); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p)); assertEquals("p.length", 4, p.list.size()); } /** * Test module and polynomial and module list. */ public void testModulePolynomialModuleList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for (int j = 0; j < 3; j++) { a = pfac.random(kl, ll, el, q); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); r.add(a); } l.add(r); } m = new ModuleList(pfac, l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m)); assertEquals("m.length", 4, m.list.size()); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p)); assertEquals("p.length", 4, p.list.size()); ModuleList m2 = null; m2 = p.getModuleList(3); //System.out.println("m2 = "+m2); assertTrue("m2 == m2", m2.equals(m2)); assertEquals("m2.length", 4, m2.list.size()); assertTrue("m == m2", m.equals(m2)); } /** * Test module and polynomial and module and polynomial list. */ public void testModulePolynomialModuleListPolynomial() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for (int j = 0; j < 3; j++) { a = pfac.random(kl, ll, el, q); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); r.add(a); } l.add(r); } m = new ModuleList(pfac, l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m)); assertEquals("m.length", 4, m.list.size()); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p)); assertEquals("p.length", 4, p.list.size()); ModuleList m2 = null; m2 = p.getModuleList(3); //System.out.println("m2 = "+m2); assertTrue("m2 == m2", m2.equals(m2)); assertEquals("m2.length", 4, m2.list.size()); assertTrue("m == m2", m.equals(m2)); PolynomialList p2 = null; p2 = m2.getPolynomialList(); //System.out.println("p2 = "+p2); assertTrue("p2 == p2", p2.equals(p2)); assertEquals("p2.length", 4, p2.list.size()); assertTrue("p == p2", p.list.equals(p2.list)); } } java-algebra-system-2.7.200/trc/edu/jas/poly/PolyUtilTest.java000066400000000000000000001777241445075545500241510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.Product; import edu.jas.arith.ProductRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PolyUtil tests with JUnit. * @author Heinz Kredel */ public class PolyUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PolyUtilTest object. * @param name String. */ public PolyUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PolyUtilTest.class); return suite; } //private final static int bitlen = 100; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; } protected static java.math.BigInteger getPrime1() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //prime = 37; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } prime -= 35; //prime = 19; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test recursive -- distributive conversion. */ public void testConversion() { c = dfac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); cr = PolyUtil.recursive(rfac, c); a = PolyUtil.distribute(dfac, cr); assertEquals("c == dist(rec(c))", c, a); d = dfac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); dr = PolyUtil.recursive(rfac, d); b = PolyUtil.distribute(dfac, dr); assertEquals("d == dist(rec(d))", d, b); } /** * Test recursive -- distributive ring conversion. */ public void testConversionRing() { GenPolynomialRing> rf = dfac.recursive(1); GenPolynomialRing cf = (GenPolynomialRing) rf.coFac; assertEquals("rfac#var == rf#var ", rfac.nvar, rf.nvar); assertEquals("rfac.coFac#var == rf.coFac#var ", cfac.nvar, cf.nvar); assertEquals("rfac.coFac.coFac == rf.coFac.coFac ", cfac.coFac, cf.coFac); // variable names not same in this test } /** * Test random recursive -- distributive conversion. */ public void testRandomConversion() { for (int i = 0; i < 7; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); assertTrue("length( c" + i + " ) <> 0", c.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !c.isZERO()); assertTrue(" not isONE( c" + i + " )", !c.isONE()); cr = PolyUtil.recursive(rfac, c); a = PolyUtil.distribute(dfac, cr); //System.out.println("c = " + c); //System.out.println("cr = " + cr); //System.out.println("crd = " + a); assertEquals("c == dist(rec(c))", c, a); } } /** * Test random rational -- integer conversion. */ @SuppressWarnings("unchecked") public void testRationalConversion() { GenPolynomialRing rfac = new GenPolynomialRing(new BigRational(1), rl, to); GenPolynomial ar; GenPolynomial br; for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 9), ll * (i + 3), el + i, q).abs(); //c = c.multiply( new BigInteger(99) ); // fails, since not primitive //c = GreatestCommonDivisor.primitivePart(c); assertTrue("length( c" + i + " ) <> 0", c.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !c.isZERO()); assertTrue(" not isONE( c" + i + " )", !c.isONE()); ar = PolyUtil. fromIntegerCoefficients(rfac, c); br = ar.monic(); a = PolyUtil.integerFromRationalCoefficients(dfac, br); //System.out.println("c = " + c); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("crd = " + a); assertEquals("c == integer(rational(c))", c, a); //ar = PolyUtil. fromIntegerCoefficients(rfac, c); //br = ar.monic(); Object[] fa = PolyUtil.integerFromRationalCoefficientsFactor(dfac, br); //System.out.println("c = " + c); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("fa = " + Arrays.toString(fa)); java.math.BigInteger gcd = (java.math.BigInteger) fa[0]; java.math.BigInteger lcm = (java.math.BigInteger) fa[1]; a = (GenPolynomial) fa[2]; //System.out.println("gcd = " + gcd); //System.out.println("lcm = " + lcm); //System.out.println("a = " + a); assertEquals("c == integer(rational(c))", c, a); assertEquals("gcd == 1", gcd, java.math.BigInteger.ONE); assertEquals("lcm == lc(a)", lcm, a.leadingBaseCoefficient().val); } } /** * Test random modular -- integer conversion. */ public void testModularConversion() { ModIntegerRing pm = new ModIntegerRing(getPrime1()); GenPolynomialRing mfac = new GenPolynomialRing(pm, rl, to); GenPolynomial ar; for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 2), ll * (i + 1), el + i, q).abs(); //c = c.multiply( new BigInteger(99) ); // fails, since not primitive //c = GreatestCommonDivisor.primitivePart(c); assertTrue("length( c" + i + " ) <> 0", c.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !c.isZERO()); assertTrue(" not isONE( c" + i + " )", !c.isONE()); ar = PolyUtil. fromIntegerCoefficients(mfac, c); a = PolyUtil.integerFromModularCoefficients(dfac, ar); //System.out.println("c = " + c); //System.out.println("ar = " + ar); //System.out.println("crd = " + a); assertEquals("c == integer(modular(c))", c, a); } } /** * Test chinese remainder. */ public void testChineseRemainder() { java.math.BigInteger p1 = getPrime1(); java.math.BigInteger p2 = getPrime2(); java.math.BigInteger p12 = p1.multiply(p2); ModIntegerRing pm1 = new ModIntegerRing(p1); GenPolynomialRing mfac1 = new GenPolynomialRing(pm1, rl, to); ModIntegerRing pm2 = new ModIntegerRing(p2); GenPolynomialRing mfac2 = new GenPolynomialRing(pm2, rl, to); ModIntegerRing pm12 = new ModIntegerRing(p12); GenPolynomialRing mfac = new GenPolynomialRing(pm12, rl, to); ModInteger di = pm2.create(p1); di = di.inverse(); //System.out.println("di = " + di); GenPolynomial am; GenPolynomial bm; GenPolynomial cm; ExpVector degv, qdegv; for (int i = 0; i < 3; i++) { c = dfac.random((59 + 29) / 2, ll * (i + 1), el + i, q); //c = c.multiply( new BigInteger(99) ); // fails, since not primitive //c = GreatestCommonDivisor.primitivePart(c); degv = c.degreeVector(); //System.out.println("degv = " + degv); assertTrue("length( c" + i + " ) <> 0", c.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !c.isZERO()); assertTrue(" not isONE( c" + i + " )", !c.isONE()); am = PolyUtil. fromIntegerCoefficients(mfac1, c); qdegv = am.degreeVector(); //System.out.println("qdegv = " + qdegv); if (!degv.equals(qdegv)) { continue; } bm = PolyUtil. fromIntegerCoefficients(mfac2, c); qdegv = bm.degreeVector(); //System.out.println("qdegv = " + qdegv); if (!degv.equals(qdegv)) { continue; } cm = PolyUtil.chineseRemainder(mfac, am, di, bm); a = PolyUtil.integerFromModularCoefficients(dfac, cm); //System.out.println("c = " + c); //System.out.println("am = " + am); //System.out.println("bm = " + bm); //System.out.println("cm = " + cm); //System.out.println("a = " + a); assertEquals("cra(c mod p1,c mod p2) = c", c, a); } } /** * Test complex conversion. */ public void testComplexConversion() { BigRational rf = new BigRational(1); GenPolynomialRing rfac = new GenPolynomialRing(rf, rl, to); BigComplex cf = new BigComplex(1); GenPolynomialRing cfac = new GenPolynomialRing(cf, rl, to); BigComplex imag = BigComplex.I; GenPolynomial rp; GenPolynomial ip; GenPolynomial crp; GenPolynomial cip; GenPolynomial cp; GenPolynomial ap; for (int i = 0; i < 3; i++) { cp = cfac.random(kl + 2 * i, ll * (i + 1), el + i, q); assertTrue("length( c" + i + " ) <> 0", cp.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !cp.isZERO()); assertTrue(" not isONE( c" + i + " )", !cp.isONE()); rp = PolyUtil.realPart(rfac, cp); ip = PolyUtil.imaginaryPart(rfac, cp); crp = PolyUtil.complexFromRational(cfac, rp); cip = PolyUtil.complexFromRational(cfac, ip); ap = crp.sum(cip.multiply(imag)); //System.out.println("cp = " + cp); //System.out.println("rp = " + rp); //System.out.println("ip = " + ip); //System.out.println("crp = " + crp); //System.out.println("cip = " + cip); //System.out.println("ap = " + ap); assertEquals("re(c)+i*im(c) = c", cp, ap); } } /** * Test base pseudo division. */ public void testBasePseudoDivision() { String[] names = new String[] { "x" }; dfac = new GenPolynomialRing(new BigInteger(1), to, names); GenPolynomialRing rdfac = new GenPolynomialRing(new BigRational(1), dfac); //System.out.println("\ndfac = " + dfac); //System.out.println("rdfac = " + rdfac); a = dfac.random(kl, 2 * ll, el + 17, q); //a = dfac.parse(" 3 x^5 + 44 "); //b = a; b = dfac.random(kl, 2 * ll, el + 3, q); //a = a.multiply(b); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("a = " + a); //System.out.println("b = " + b); GenPolynomial[] QR = PolyUtil. basePseudoQuotientRemainder(a, b); c = QR[1]; d = QR[0]; //System.out.println("q = " + d); //System.out.println("r = " + c); boolean t = PolyUtil. isBasePseudoQuotientRemainder(a, b, d, c); assertTrue("lc^n a = q b + r: " + c, t); GenPolynomial ap = PolyUtil. fromIntegerCoefficients(rdfac, a); GenPolynomial bp = PolyUtil. fromIntegerCoefficients(rdfac, b); GenPolynomial cp = PolyUtil. fromIntegerCoefficients(rdfac, c); GenPolynomial dp = PolyUtil. fromIntegerCoefficients(rdfac, d); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); ////System.out.println("dp = " + dp); //System.out.println("dp = " + dp.monic()); GenPolynomial qp = ap.divide(bp); GenPolynomial rp = ap.remainder(bp); //System.out.println("qp = " + qp); //System.out.println("qp = " + qp.monic()); //System.out.println("rp = " + rp); GenPolynomial rhs = qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap = qp bp + rp: ", ap, rhs); assertEquals("cp = rp: ", rp.monic(), cp.monic()); assertEquals("dp = qp: ", qp.monic(), dp.monic()); // ?? //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); } /** * Test base sparse pseudo division. */ public void testBasePseudoDivisionSparse() { String[] names = new String[] { "x" }; dfac = new GenPolynomialRing(new BigInteger(1), to, names); GenPolynomialRing rdfac = new GenPolynomialRing(new BigRational(1), dfac); //System.out.println("\ndfac = " + dfac); //System.out.println("rdfac = " + rdfac); a = dfac.random(kl, 2 * ll, el + 17, q); //a = dfac.parse(" 3 x^5 + 44 "); //b = a; b = dfac.random(kl, 2 * ll, el + 3, q); //a = a.multiply(b); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("a = " + a); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(a, b); //System.out.println("q = " + d); c = PolyUtil. baseSparsePseudoRemainder(a, b); //System.out.println("r = " + c); boolean t = PolyUtil. isBasePseudoQuotientRemainder(a, b, d, c); assertTrue("lc^n a = q b + r: " + c, t); GenPolynomial ap = PolyUtil. fromIntegerCoefficients(rdfac, a); GenPolynomial bp = PolyUtil. fromIntegerCoefficients(rdfac, b); GenPolynomial cp = PolyUtil. fromIntegerCoefficients(rdfac, c); GenPolynomial dp = PolyUtil. fromIntegerCoefficients(rdfac, d); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); ////System.out.println("dp = " + dp); //System.out.println("dp = " + dp.monic()); GenPolynomial qp = ap.divide(bp); GenPolynomial rp = ap.remainder(bp); //System.out.println("qp = " + qp); //System.out.println("qp = " + qp.monic()); //System.out.println("rp = " + rp); GenPolynomial rhs = qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap = qp bp + rp: ", ap, rhs); assertEquals("cp = rp: ", rp.monic(), cp.monic()); assertEquals("dp = qp: ", qp.monic(), dp.monic()); // ?? //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); } /** * Test base dense pseudo division. */ public void testBasePseudoDivisionDense() { String[] names = new String[] { "x" }; dfac = new GenPolynomialRing(new BigInteger(1), to, names); GenPolynomialRing rdfac = new GenPolynomialRing(new BigRational(1), dfac); //System.out.println("\ndfac = " + dfac); //System.out.println("rdfac = " + rdfac); a = dfac.random(kl, 2 * ll, el + 17, q); //a = dfac.parse(" 3 x^5 + 44 "); //b = a; b = dfac.random(kl, 2 * ll, el + 3, q); //a = a.multiply(b); //a = a.sum(b); //b = dfac.parse(" 2 x^2 + 40 "); //System.out.println("a = " + a); //System.out.println("b = " + b); d = PolyUtil. baseDensePseudoQuotient(a, b); //System.out.println("q = " + d); c = PolyUtil. baseDensePseudoRemainder(a, b); //System.out.println("r = " + c); boolean t = PolyUtil. isBasePseudoQuotientRemainder(a, b, d, c); assertTrue("lc^n a = q b + r: " + c, t); GenPolynomial ap = PolyUtil. fromIntegerCoefficients(rdfac, a); GenPolynomial bp = PolyUtil. fromIntegerCoefficients(rdfac, b); GenPolynomial cp = PolyUtil. fromIntegerCoefficients(rdfac, c); GenPolynomial dp = PolyUtil. fromIntegerCoefficients(rdfac, d); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); ////System.out.println("dp = " + dp); //System.out.println("dp = " + dp.monic()); GenPolynomial qp = ap.divide(bp); GenPolynomial rp = ap.remainder(bp); //System.out.println("qp = " + qp); //System.out.println("qp = " + qp.monic()); //System.out.println("rp = " + rp); GenPolynomial rhs = qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap = qp bp + rp: ", ap, rhs); assertEquals("cp = rp: ", rp.monic(), cp.monic()); assertEquals("dp = qp: ", qp.monic(), dp.monic()); // ?? //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); } /** * Test recursive pseudo quotient and remainder. * @see edu.jas.ufd.PolyUfdUtilTest#testRecursivePseudoDivisionSparse */ public void testRecursivePseudoDivision() { } /** * Test evaluate main recursive. */ public void testEvalMainRecursive() { ai = (new BigInteger()).random(kl); //System.out.println("ai = " + ai); ar = rfac.getZERO(); //System.out.println("ar = " + ar); a = PolyUtil. evaluateMainRecursive(cfac, ar, ai); //System.out.println("a = " + a); assertTrue("isZERO( a )", a.isZERO()); ar = rfac.getONE(); //System.out.println("ar = " + ar); a = PolyUtil. evaluateMainRecursive(cfac, ar, ai); //System.out.println("a = " + a); assertTrue("isONE( a )", a.isONE()); //ar = rfac.getONE(); ar = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //br = rfac.getONE(); br = rfac.random(kl, ll, el, q); //System.out.println("br = " + br); cr = br.sum(ar); //System.out.println("cr = " + cr); a = PolyUtil. evaluateMainRecursive(cfac, ar, ai); b = PolyUtil. evaluateMainRecursive(cfac, br, ai); c = PolyUtil. evaluateMainRecursive(cfac, cr, ai); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); d = a.sum(b); //System.out.println("d = " + d); assertEquals("eval(a+b) == eval(a) + eval(b)", c, d); cr = br.multiply(ar); //System.out.println("cr = " + cr); a = PolyUtil. evaluateMainRecursive(cfac, ar, ai); b = PolyUtil. evaluateMainRecursive(cfac, br, ai); c = PolyUtil. evaluateMainRecursive(cfac, cr, ai); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); d = a.multiply(b); //System.out.println("d = " + d); assertEquals("eval(a*b) == eval(a) * eval(b)", c, d); } /** * Test evaluate main. */ public void testEvalMain() { ei = (new BigInteger()).random(kl); //System.out.println("ei = " + ei); cfac = new GenPolynomialRing(new BigInteger(1), 1, to); //System.out.println("cfac = " + cfac); a = cfac.getZERO(); //System.out.println("a = " + a); ai = PolyUtil. evaluateMain(ei, a, ei); //System.out.println("ai = " + ai); assertTrue("isZERO( ai )", ai.isZERO()); a = cfac.getONE(); //System.out.println("a = " + a); ai = PolyUtil. evaluateMain(ei, a, ei); //System.out.println("ai = " + ai); assertTrue("isONE( ai )", ai.isONE()); //a = cfac.getONE(); a = cfac.random(kl, ll, el, q); //System.out.println("a = " + a); //b = cfac.getONE(); b = cfac.random(kl, ll, el, q); //System.out.println("b = " + b); c = b.sum(a); //System.out.println("c = " + c); ai = PolyUtil. evaluateMain(ei, a, ei); bi = PolyUtil. evaluateMain(ei, b, ei); ci = PolyUtil. evaluateMain(ei, c, ei); //System.out.println("ai = " + ai); //System.out.println("bi = " + bi); //System.out.println("ci = " + ci); di = bi.sum(ai); //System.out.println("di = " + di); assertEquals("eval(a+b) == eval(a) + eval(b)", ci, di); c = b.multiply(a); //System.out.println("c = " + c); ai = PolyUtil. evaluateMain(ei, a, ei); bi = PolyUtil. evaluateMain(ei, b, ei); ci = PolyUtil. evaluateMain(ei, c, ei); //System.out.println("ai = " + ai); //System.out.println("bi = " + bi); //System.out.println("ci = " + ci); di = bi.multiply(ai); //System.out.println("di = " + di); assertEquals("eval(a*b) == eval(a) * eval(b)", ci, di); } /** * Test evaluate first. */ public void testEvalFirst() { ei = (new BigInteger()).random(kl); //System.out.println("ei = " + ei); GenPolynomial ae, be, ce, de; GenPolynomialRing fac; fac = new GenPolynomialRing(new BigInteger(1), rl, to); //System.out.println("fac = " + fac); cfac = new GenPolynomialRing(new BigInteger(1), 1, to); //System.out.println("cfac = " + cfac); dfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); //System.out.println("dfac = " + dfac); a = fac.getZERO(); //System.out.println("a = " + a); ae = PolyUtil. evaluateFirst(cfac, dfac, a, ei); //System.out.println("ae = " + ae); assertTrue("isZERO( ae )", ae.isZERO()); a = fac.getONE(); //System.out.println("a = " + a); ae = PolyUtil. evaluateFirst(cfac, dfac, a, ei); //System.out.println("ae = " + ae); assertTrue("isONE( ae )", ae.isONE()); //a = fac.getONE(); a = fac.random(kl, ll, el, q); //System.out.println("a = " + a); //b = fac.getONE(); b = fac.random(kl, ll, el, q); //System.out.println("b = " + b); c = b.sum(a); //System.out.println("c = " + c); ae = PolyUtil. evaluateFirst(cfac, dfac, a, ei); be = PolyUtil. evaluateFirst(cfac, dfac, b, ei); ce = PolyUtil. evaluateFirst(cfac, dfac, c, ei); //System.out.println("ae = " + ae); //System.out.println("be = " + be); //System.out.println("ce = " + ce); de = be.sum(ae); //System.out.println("de = " + de); assertEquals("eval(a+b) == eval(a) + eval(b)", ce, de); c = b.multiply(a); //System.out.println("c = " + c); ae = PolyUtil. evaluateFirst(cfac, dfac, a, ei); be = PolyUtil. evaluateFirst(cfac, dfac, b, ei); ce = PolyUtil. evaluateFirst(cfac, dfac, c, ei); //System.out.println("ae = " + ae); //System.out.println("be = " + be); //System.out.println("ce = " + ce); de = be.multiply(ae); //System.out.println("de = " + de); assertEquals("eval(a*b) == eval(a) * eval(b)", ce, de); } /** * Test evaluate all. */ public void testEvalAll() { BigInteger cfac = new BigInteger(); List Ev = new ArrayList(); for (int i = 0; i < rl; i++) { ei = cfac.random(kl); Ev.add(ei); } //System.out.println("Ev = " + Ev); BigInteger ae, be, ce, de; GenPolynomialRing fac; fac = new GenPolynomialRing(cfac, rl, to); //System.out.println("fac = " + fac); List> list = new ArrayList>(); List evlist; a = fac.getZERO(); //System.out.println("a = " + a); ae = PolyUtil. evaluateAll(cfac, a, Ev); //System.out.println("ae = " + ae); assertTrue("isZERO( ae )", ae.isZERO()); a = fac.getONE(); //System.out.println("a = " + a); ae = PolyUtil. evaluateAll(cfac, a, Ev); //System.out.println("ae = " + ae); assertTrue("isONE( ae )", ae.isONE()); //a = fac.getONE(); a = fac.random(kl, ll, el, q); //System.out.println("a = " + a); //b = fac.getONE(); b = fac.random(kl, ll, el, q); //System.out.println("b = " + b); c = b.sum(a); //System.out.println("c = " + c); ae = PolyUtil. evaluateAll(cfac, a, Ev); be = PolyUtil. evaluateAll(cfac, b, Ev); ce = PolyUtil. evaluateAll(cfac, c, Ev); //System.out.println("ae = " + ae); //System.out.println("be = " + be); //System.out.println("ce = " + ce); de = be.sum(ae); //System.out.println("de = " + de); assertEquals("eval(a+b) == eval(a) + eval(b)", ce, de); list.add(a); list.add(b); list.add(c); //System.out.println("list = " + list); evlist = PolyUtil. evaluateAll(cfac, list, Ev); //System.out.println("evlist = " + evlist); de = evlist.get(1).sum(evlist.get(0)); assertEquals("eval(a+b) == eval(a) + eval(b)", ce, de); c = b.multiply(a); //System.out.println("c = " + c); ce = PolyUtil. evaluateAll(cfac, c, Ev); //System.out.println("ae = " + ae); //System.out.println("be = " + be); //System.out.println("ce = " + ce); de = be.multiply(ae); //System.out.println("de = " + de); assertEquals("eval(a*b) == eval(a) * eval(b)", ce, de); list.clear(); list.add(a); list.add(b); list.add(c); //System.out.println("list = " + list); evlist = PolyUtil. evaluateAll(cfac, list, Ev); //System.out.println("evlist = " + evlist); de = evlist.get(1).multiply(evlist.get(0)); assertEquals("eval(a*b) == eval(a) * eval(b)", ce, de); } /** * Test interpolate univariate 1 polynomial. */ public void testInterpolateUnivariateOne() { ModInteger ai, bi, ci, di, ei, fi, gi, hi; GenPolynomial a; GenPolynomialRing cfac; ModIntegerRing fac; GenPolynomial r; GenPolynomial Q; GenPolynomial Qp; fac = new ModIntegerRing(19); //System.out.println("fac.modul = " + fac.getModul()); cfac = new GenPolynomialRing(fac, 1, to); //System.out.println("cfac = " + cfac); a = cfac.getONE(); //System.out.println("a = " + a); ei = fac.fromInteger(11); //System.out.println("ei = " + ei); // a(ei) ai = PolyUtil. evaluateMain(fac, a, ei); //System.out.println("ai = " + ai); assertTrue("isONE( ai )", ai.isONE()); di = fac.fromInteger(13); //System.out.println("di = " + di); // a(di) bi = PolyUtil. evaluateMain(fac, a, di); //System.out.println("bi = " + bi); assertTrue("isONE( bi )", bi.isONE()); // interpolation result r = cfac.getZERO(); //System.out.println("r = " + r); // interpolation polynomials product Q = cfac.getONE(); //System.out.println("Q = " + Q); ci = PolyUtil. evaluateMain(fac, Q, ei); //System.out.println("ci = " + ci); // Q(ei)^-1 fi = ci.inverse(); //System.out.println("fi = " + fi); r = PolyUtil. interpolate(cfac, r, Q, fi, ai, ei); //System.out.println("r = " + r); // next evaluation polynomial Qp = cfac.univariate(0); Qp = Qp.subtract(cfac.getONE().multiply(ei)); //System.out.println("Qp = " + Qp); Q = Q.multiply(Qp); //System.out.println("Q = " + Q); ci = PolyUtil. evaluateMain(fac, Q, di); //System.out.println("ci = " + ci); // Q(di)^-1 fi = ci.inverse(); //System.out.println("fi = " + fi); r = PolyUtil. interpolate(cfac, r, Q, fi, bi, di); //System.out.println("r = " + r); // check evaluation gi = PolyUtil. evaluateMain(fac, r, ei); //System.out.println("gi = " + gi); hi = PolyUtil. evaluateMain(fac, r, di); //System.out.println("hi = " + hi); assertTrue("gi == 1 ", gi.isONE()); assertTrue("hi == 1 ", hi.isONE()); // interpolate( a(ei), a(di) ) = a (mod 19) assertEquals("interpolate(a mod (x-ei),a mod (x-di)) = a (mod 19)", a, r); } /** * Test interpolate univariate deg > 0 polynomial. */ public void testInterpolateUnivariate() { ModInteger ai, ci, ei, fi; GenPolynomial a; GenPolynomialRing cfac; ModIntegerRing fac; GenPolynomial r; GenPolynomial Q; GenPolynomial Qp; //long prime = 19; long prime = getPrime1().longValue(); fac = new ModIntegerRing(prime); //System.out.println("fac.modul = " + fac.getModul()); cfac = new GenPolynomialRing(fac, 1, to); //System.out.println("cfac = " + cfac); int maxdeg = 19; // polynomial to interpolate long deg = 0; do { a = cfac.random(kl, ll, maxdeg, q); if (!a.isZERO()) { deg = a.degree(0); } } while (deg <= 0); //System.out.println("a = " + a); //System.out.println("deg = " + deg); // interpolation result r = cfac.getZERO(); //System.out.println("r = " + r); // interpolation polynomials product Q = cfac.getONE(); //System.out.println("Q = " + Q); long i = -1; long qdeg; do { i++; if (i >= prime) { assertTrue("elements of Z_prime exhausted", i < prime); } qdeg = Q.degree(0); ei = fac.fromInteger(i); //System.out.println("ei = " + ei); // a(ei) ai = PolyUtil. evaluateMain(fac, a, ei); //System.out.println("ai = " + ai); ci = PolyUtil. evaluateMain(fac, Q, ei); //System.out.println("ci = " + ci); // Q(ei)^-1 fi = ci.inverse(); //System.out.println("fi = " + fi); r = PolyUtil. interpolate(cfac, r, Q, fi, ai, ei); //System.out.println("r = " + r); // next evaluation polynomial Qp = cfac.univariate(0); Qp = Qp.subtract(cfac.getONE().multiply(ei)); //System.out.println("Qp = " + Qp); Q = Q.multiply(Qp); //System.out.println("Q = " + Q); } while (qdeg < deg); //System.out.println("a = " + a); //System.out.println("r = " + r); // interpolate( a(e1), ..., a(ei) ) = a (mod 19) assertEquals("interpolate(a mod (x-e1),...,a mod (x-ei)) = a (mod 19)", a, r); } /** * Test interpolate multivariate deg > 0 polynomial. */ public void testInterpolateMultivariate() { ModInteger ci, ei, fi; GenPolynomial ap, bp; GenPolynomial> a; GenPolynomialRing> cfac; GenPolynomialRing ufac; GenPolynomialRing dfac; ModIntegerRing fac; GenPolynomial> r; GenPolynomial Q; GenPolynomial Qp; //long prime = 19; long prime = getPrime1().longValue(); fac = new ModIntegerRing(prime); //System.out.println("fac.modul = " + fac.getModul()); ufac = new GenPolynomialRing(fac, 1, to); //System.out.println("ufac = " + ufac); cfac = new GenPolynomialRing>(ufac, rl, to); //System.out.println("cfac = " + cfac); dfac = new GenPolynomialRing(fac, rl, to); //System.out.println("dfac = " + dfac); int maxdeg = 19; // polynomial to interpolate long deg = 0; do { a = cfac.random(kl, ll + 9, maxdeg, q); if (!a.isZERO()) { deg = PolyUtil. coeffMaxDegree(a); } } while (deg <= 0); //System.out.println("a = " + a); //System.out.println("deg = " + deg); ExpVector degv = a.degreeVector(); //System.out.println("degv = " + degv); // interpolation result r = cfac.getZERO(); //System.out.println("r = " + r); // interpolation polynomials product Q = ufac.getONE(); //System.out.println("Q = " + Q); long i = -1; long qdeg; ExpVector qdegv; do { i++; if (i >= prime) { assertTrue("elements of Z_prime exhausted", i < prime); } qdeg = Q.degree(0); ei = fac.fromInteger(i); //System.out.println("ei = " + ei); // a(ei) ap = PolyUtil. evaluateFirstRec(ufac, dfac, a, ei); //System.out.println("ap = " + ap); qdegv = ap.degreeVector(); //System.out.println("qdegv = " + qdegv); if (!degv.equals(qdegv)) { continue; } ci = PolyUtil. evaluateMain(fac, Q, ei); //System.out.println("ci = " + ci); // Q(ei)^-1 fi = ci.inverse(); //System.out.println("fi = " + fi); r = PolyUtil. interpolate(cfac, r, Q, fi, ap, ei); //System.out.println("r = " + r); // check bp = PolyUtil. evaluateFirstRec(ufac, dfac, r, ei); //System.out.println("bp = " + bp); assertEquals("interpolate(a)(ei) == a ", bp, ap); // next evaluation polynomial Qp = ufac.univariate(0); Qp = Qp.subtract(ufac.getONE().multiply(ei)); //System.out.println("Qp = " + Qp); Q = Q.multiply(Qp); //System.out.println("Q = " + Q); } while (qdeg <= deg); //System.out.println("a = " + a); //System.out.println("r = " + r); // interpolate( a(e1), ..., a(ei) ) = a (mod 19) assertEquals("interpolate(a mod (x-e1),...,a mod (x-ei)) = a (mod 19)", a, r); } /** * Test interpolate rational multivariate deg > 0 polynomial. */ public void testInterpolateRationalMultivariate() { BigRational ci, ei, fi; GenPolynomial ap, bp; GenPolynomial> a; GenPolynomialRing> cfac; GenPolynomialRing ufac; GenPolynomialRing dfac; BigRational fac; GenPolynomial> r; GenPolynomial Q; GenPolynomial Qp; fac = new BigRational(); //System.out.println("fac.modul = " + fac.getModul()); ufac = new GenPolynomialRing(fac, 1, to); //System.out.println("ufac = " + ufac); cfac = new GenPolynomialRing>(ufac, rl, to); //System.out.println("cfac = " + cfac); dfac = new GenPolynomialRing(fac, rl, to); //System.out.println("dfac = " + dfac); int maxdeg = 19; // polynomial to interpolate long deg = 0; do { a = cfac.random(kl, ll + 9, maxdeg, q); if (!a.isZERO()) { deg = PolyUtil. coeffMaxDegree(a); } } while (deg <= 0); //System.out.println("a = " + a); //System.out.println("deg = " + deg); ExpVector degv = a.degreeVector(); //System.out.println("degv = " + degv); // interpolation result r = cfac.getZERO(); //System.out.println("r = " + r); // interpolation polynomials product Q = ufac.getONE(); //System.out.println("Q = " + Q); long i = -1; long qdeg; ExpVector qdegv; do { i++; qdeg = Q.degree(0); ei = fac.fromInteger(i); //System.out.println("ei = " + ei); // a(ei) ap = PolyUtil. evaluateFirstRec(ufac, dfac, a, ei); //System.out.println("ap = " + ap); qdegv = ap.degreeVector(); //System.out.println("qdegv = " + qdegv); if (!degv.equals(qdegv)) { continue; } ci = PolyUtil. evaluateMain(fac, Q, ei); //System.out.println("ci = " + ci); // Q(ei)^-1 fi = ci.inverse(); //System.out.println("fi = " + fi); r = PolyUtil. interpolate(cfac, r, Q, fi, ap, ei); //System.out.println("r = " + r); // check bp = PolyUtil. evaluateFirstRec(ufac, dfac, r, ei); //System.out.println("bp = " + bp); assertEquals("interpolate(a)(ei) == a ", bp, ap); // next evaluation polynomial Qp = ufac.univariate(0); Qp = Qp.subtract(ufac.getONE().multiply(ei)); //System.out.println("Qp = " + Qp); Q = Q.multiply(Qp); //System.out.println("Q = " + Q); } while (qdeg <= deg); //System.out.println("a = " + a); //System.out.println("r = " + r); // interpolate( a(e1), ..., a(ei) ) = a (mod 19) assertEquals("interpolate(a mod (x-e1),...,a mod (x-ei)) = a (mod 19)", a, r); } /** * Test coefficient map function. */ public void testMap() { // integers BigInteger fi = new BigInteger(); //System.out.println("fi = " + fi); // rational numbers BigRational fr = new BigRational(); //System.out.println("fr = " + fr); // modular integers ModIntegerRing fm = new ModIntegerRing(17); //System.out.println("fm = " + fm); // polynomials over integral numbers GenPolynomialRing pfi = new GenPolynomialRing(fi, rl); //System.out.println("pfi = " + pfi); // polynomials over rational numbers GenPolynomialRing pfr = new GenPolynomialRing(fr, rl); //System.out.println("pfr = " + pfr); // polynomials over modular integers GenPolynomialRing pfm = new GenPolynomialRing(fm, rl); //System.out.println("pfm = " + pfm); // random polynomial GenPolynomial pi = pfi.random(kl, 2 * ll, el, q); //System.out.println("pi = " + pi); // random polynomial GenPolynomial pr = pfr.random(kl, 2 * ll, el, q).monic(); //System.out.println("pr = " + pr); // random polynomial GenPolynomial pm = pfm.random(kl, 2 * ll, el, q); //System.out.println("pm = " + pm); // test integer to rational and back GenPolynomial qr; GenPolynomial qi; qr = PolyUtil. map(pfr, pi, new FromInteger(fr)); qi = PolyUtil. map(pfi, qr, new RatNumer()); //System.out.println("qr = " + qr); //System.out.println("qi = " + qi); assertEquals("pi == qi ", pi, qi); // test rational to integer and back qi = PolyUtil.integerFromRationalCoefficients(pfi, pr); qr = PolyUtil. map(pfr, qi, new FromInteger(fr)); qr = qr.monic(); //System.out.println("pr = " + pr); //System.out.println("qr = " + qr); //System.out.println("qi = " + qi); assertEquals("pr == qr ", pr, qr); // test symmetric modular integer to integer and back GenPolynomial qm; qi = PolyUtil. map(pfi, pm, new ModSymToInt()); qm = PolyUtil. map(pfm, qi, new FromInteger(fm)); //System.out.println("qi = " + qi); //System.out.println("qm = " + qm); assertEquals("pm == qm ", pm, qm); // test modular integer to integer and back qi = PolyUtil. map(pfi, pm, new ModToInt()); qm = PolyUtil. map(pfm, qi, new FromInteger(fm)); //System.out.println("qi = " + qi); //System.out.println("qm = " + qm); assertEquals("pm == qm ", pm, qm); // test symmetric modular integer to integer to rational and back qi = PolyUtil. map(pfi, pm, new ModSymToInt()); qr = PolyUtil. map(pfr, qi, new FromInteger(fr)); qi = PolyUtil. map(pfi, qr, new RatNumer()); qm = PolyUtil. map(pfm, qi, new FromInteger(fm)); //System.out.println("qi = " + qi); //System.out.println("qm = " + qm); assertEquals("pm == qm ", pm, qm); } /** * Test substitution. */ public void testSubstitution() { dfac = new GenPolynomialRing(new BigInteger(1), 1, to); // subs = x - 7 GenPolynomial s = dfac.univariate(0).subtract(dfac.fromInteger(7)); GenPolynomial s1 = dfac.univariate(0).sum(dfac.fromInteger(7)); //System.out.println("s = " + s); //System.out.println("s1 = " + s1); for (int i = 0; i < 5; i++) { a = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); b = PolyUtil. substituteMain(a, s); c = PolyUtil. substituteMain(b, s1); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a == c " + a.equals(c)); assertEquals("a == c ", a, c); } } /** * Test algebraic substitution. */ public void testAlgebraicSubstitution() { BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 2); agen = agen.sum(pfac.getONE()); // x^2 + 1 AlgebraicNumberRing afac = new AlgebraicNumberRing(agen, true); GenPolynomialRing> apfac = new GenPolynomialRing>( afac, 1, to, vars); // univariate //System.out.println("agen = " + agen); //System.out.println("afac = " + afac); //System.out.println("apfac = " + apfac); // subs = x - 7 GenPolynomial> s = apfac.univariate(0) .subtract(apfac.fromInteger(7).multiply(afac.getGenerator())); GenPolynomial> s1 = apfac.univariate(0) .sum(apfac.fromInteger(7).multiply(afac.getGenerator())); //System.out.println("s = " + s); //System.out.println("s1 = " + s1); GenPolynomial> a, b, c; for (int i = 0; i < 5; i++) { a = apfac.random(kl, ll, el, q); //System.out.println("a = " + a); b = PolyUtil.> substituteMain(a, s); c = PolyUtil.> substituteMain(b, s1); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a == c " + a.equals(c)); assertEquals("a == c ", a, c); } } /** * Test multivariate substitution. */ public void testMultivarSubstitution() { dfac = new GenPolynomialRing(new BigInteger(1), 2, to); // subs = x - 7 GenPolynomial s = dfac.univariate(0).subtract(dfac.fromInteger(7)); GenPolynomial s1 = dfac.univariate(0).sum(dfac.fromInteger(7)); //System.out.println("s = " + s); //System.out.println("s1 = " + s1); for (int i = 0; i < 5; i++) { a = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); b = PolyUtil. substituteUnivariateMult(a, s); c = PolyUtil. substituteUnivariateMult(b, s1); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a == c " + a.equals(c)); assertEquals("a == c ", a, c); } } /** * Test switch variables. */ public void testSwitchVariables() { BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl, to); GenPolynomialRing> rfac = new GenPolynomialRing>( pfac, rl, to); //System.out.println("pfac = " + pfac); //System.out.println("rfac = " + rfac); GenPolynomial> a, c; GenPolynomial> b; for (int i = 0; i < 5; i++) { a = rfac.random(kl, ll, el, q); //System.out.println("a = " + a); b = PolyUtil. switchVariables(a); c = PolyUtil. switchVariables(b); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a == c " + a.equals(c)); assertEquals("a == c ", a, c); } } /** * Test algebraic conversions. */ public void testAlgebraicConversions() { BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; //String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 2); agen = agen.sum(pfac.getONE()); // x^2 + 1 AlgebraicNumberRing afac = new AlgebraicNumberRing(agen, true); GenPolynomialRing> apfac = new GenPolynomialRing>( afac, rl, to); GenPolynomialRing> rfac = new GenPolynomialRing>( pfac, rl, to); //System.out.println("agen = " + agen); //System.out.println("afac = " + afac); //System.out.println("apfac = " + apfac); //System.out.println("pfac = " + pfac); //System.out.println("rfac = " + rfac); GenPolynomial> a, c; GenPolynomial> b; for (int i = 0; i < 5; i++) { a = apfac.random(kl, ll, el, q); //System.out.println("a = " + a); b = PolyUtil. fromAlgebraicCoefficients(rfac, a); c = PolyUtil. convertRecursiveToAlgebraicCoefficients(apfac, b); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a == c " + a.equals(c)); assertEquals("a == c ", a, c); } } /** * Test Taylor series. */ public void testTaylorSeries() { GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomialRing dfac; BigRational cfac; cfac = new BigRational(1); String[] vars = new String[] { "x" }; dfac = new GenPolynomialRing(cfac, 1, to, vars); a = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); BigRational v = cfac.getZERO(); //System.out.println("v = " + v); b = PolyUtil. seriesOfTaylor(a, v); //System.out.println("taylor(a,0) = " + b); assertTrue("taylor(a,0) == a ", a.equals(b)); v = cfac.random(kl); //System.out.println("v = " + v); b = PolyUtil. seriesOfTaylor(a, v); //System.out.println("taylor(a,v) = " + b); c = PolyUtil. seriesOfTaylor(b, v.negate()); //System.out.println("tailor(taylor(a,v),-v) = " + c); assertTrue("tailor(taylor(a,v),-v) == a ", a.equals(c)); } /** * Test Complex real and imaginary part. */ public void testComplexParts() { BigRational rf = new BigRational(1); GenPolynomialRing rfac = new GenPolynomialRing(rf, rl, to); ComplexRing cf = new ComplexRing(new BigRational(1)); GenPolynomialRing> cfac = new GenPolynomialRing>(cf, rl, to); Complex imag = cf.getIMAG(); GenPolynomial rp; GenPolynomial ip; GenPolynomial> crp; GenPolynomial> cip; GenPolynomial> cp; GenPolynomial> ap; for (int i = 0; i < 3; i++) { cp = cfac.random(kl + 2 * i, ll * (i + 1), el + i, q); assertTrue("length( c" + i + " ) <> 0", cp.length() >= 0); assertTrue(" not isZERO( c" + i + " )", !cp.isZERO()); assertTrue(" not isONE( c" + i + " )", !cp.isONE()); rp = PolyUtil. realPartFromComplex(rfac, cp); ip = PolyUtil. imaginaryPartFromComplex(rfac, cp); crp = PolyUtil. toComplex(cfac, rp); cip = PolyUtil. toComplex(cfac, ip); ap = crp.sum(cip.multiply(imag)); //System.out.println("cp = " + cp); //System.out.println("rp = " + rp); //System.out.println("ip = " + ip); //System.out.println("crp = " + crp); //System.out.println("cip = " + cip); //System.out.println("ap = " + ap); assertEquals("re(c)+i*im(c) = c", cp, ap); } } /** * Test product representation conversion, rational numbers. */ public void testProductConversionRN() { GenPolynomialRing ufac; ufac = new GenPolynomialRing(new BigRational(1), 1); ProductRing> pfac; pfac = new ProductRing>(ufac, rl); GenPolynomialRing dfac = new GenPolynomialRing(new BigRational(1), rl, to); GenPolynomial c; Product> cp; c = dfac.getONE(); //System.out.println("c = " + c); cp = PolyUtil. toProduct(pfac, c); //System.out.println("cp = " + cp); assertTrue("isONE( cp )", cp.isONE()); c = dfac.random(kl, ll, el, q); //System.out.println("c = " + c); cp = PolyUtil. toProduct(pfac, c); //System.out.println("cp = " + cp); assertTrue("!isONE( cp )", !cp.isONE()); } /** * Test polynomal over product representation conversion, algebraic numbers. */ public void testPolyProductConversionAN() { GenPolynomialRing ufac; ufac = new GenPolynomialRing(new BigRational(1), 1); GenPolynomial m; m = ufac.univariate(0, 2); m = m.subtract(ufac.univariate(0, 1)); //System.out.println("m = " + m); AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(m); //System.out.println("afac = " + afac); ProductRing> pfac; pfac = new ProductRing>(afac, rl); GenPolynomialRing>> dpfac; dpfac = new GenPolynomialRing>>(pfac, 2); GenPolynomialRing> dfac; dfac = new GenPolynomialRing>(afac, 2, to); GenPolynomial> c; GenPolynomial>> cp; c = dfac.getONE(); //System.out.println("c = " + c); cp = PolyUtil.> toProductGen(dpfac, c); //System.out.println("cp = " + cp); assertTrue("isZERO( cp )", cp.isONE()); c = dfac.random(kl, ll, el, q); //System.out.println("c = " + c); cp = PolyUtil.> toProductGen(dpfac, c); //System.out.println("cp = " + cp); assertTrue("!isONE( cp )", !cp.isONE()); } /** * Test remove unused upper variables. */ public void testRemoveUnusedUpper() { //System.out.println("dfac = " + dfac); a = dfac.univariate(3, 2); b = a.subtract(dfac.univariate(1, 1)); //System.out.println("a = " + a); //System.out.println("b = " + b); c = PolyUtil. removeUnusedUpperVariables(b); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 4: " + c.ring.nvar, c.ring.nvar == 4); a = dfac.univariate(3, 2); //System.out.println("a = " + a); c = PolyUtil. removeUnusedUpperVariables(a); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 2: " + c.ring.nvar, c.ring.nvar == 2); a = dfac.univariate(1, 2); //System.out.println("a = " + a); c = PolyUtil. removeUnusedUpperVariables(a); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 4: " + c.ring.nvar, c.ring.nvar == 4); } /** * Test remove unused lower variables. */ public void testRemoveUnusedLower() { //System.out.println("dfac = " + dfac); a = dfac.univariate(3, 2); b = a.subtract(dfac.univariate(1, 1)); //System.out.println("a = " + a); //System.out.println("b = " + b); c = PolyUtil. removeUnusedLowerVariables(b); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 4: " + c.ring.nvar, c.ring.nvar == 4); a = dfac.univariate(3, 2); //System.out.println("a = " + a); c = PolyUtil. removeUnusedLowerVariables(a); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 4: " + c.ring.nvar, c.ring.nvar == 4); a = dfac.univariate(1, 2); //System.out.println("a = " + a); c = PolyUtil. removeUnusedLowerVariables(a); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 2: " + c.ring.nvar, c.ring.nvar == 2); } /** * Test remove unused middle variables. */ public void testRemoveUnusedMiddle() { //System.out.println("dfac = " + dfac); a = dfac.univariate(4, 2); b = a.subtract(dfac.univariate(0, 1)); //System.out.println("a = " + a); //System.out.println("b = " + b); c = PolyUtil. removeUnusedLowerVariables(b); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 5: " + c.ring.nvar, c.ring.nvar == 5); c = PolyUtil. removeUnusedUpperVariables(c); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 5: " + c.ring.nvar, c.ring.nvar == 5); c = PolyUtil. removeUnusedMiddleVariables(c); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 2: " + c.ring.nvar, c.ring.nvar == 2); a = dfac.univariate(3, 2); b = a.subtract(dfac.univariate(1, 1)); //System.out.println("a = " + a); //System.out.println("b = " + b); try { c = PolyUtil. removeUnusedMiddleVariables(b); fail("c = " + c + ", fac = " + c.ring); } catch (RuntimeException e) { // success } c = PolyUtil. removeUnusedLowerVariables(b); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 4: " + c.ring.nvar, c.ring.nvar == 4); c = PolyUtil. removeUnusedUpperVariables(c); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 3: " + c.ring.nvar, c.ring.nvar == 3); c = PolyUtil. removeUnusedMiddleVariables(c); //System.out.println("c = " + c + ", fac = " + c.ring); assertTrue("#var == 2: " + c.ring.nvar, c.ring.nvar == 2); } /** * Test transformation. */ public void testTransformation() { //dfac = new GenPolynomialRing(new BigInteger(1), 1, to); //System.out.println("ring = " + dfac.toScript()); c = dfac.getONE(); //System.out.println("c = " + c); a = PolyUtil.reciprocalTransformation(c); //System.out.println("a = " + a); d = dfac.getZERO(); //System.out.println("d = " + d); b = PolyUtil.reciprocalTransformation(d); //System.out.println("b = " + b); c = dfac.random(kl * 2, ll + 2, el * 2, q + q); //System.out.println("c = " + c); a = PolyUtil.reciprocalTransformation(c); //System.out.println("a = " + a); b = PolyUtil.reciprocalTransformation(a); //System.out.println("b = " + b); assertEquals("recip(recip(c)) == c: ", c, b); for (int i = 0; i < rl; i++) { //System.out.println("i = " + i + ", deg(c,i) = " + c.degree(i)); a = PolyUtil.reciprocalTransformation(c, i); //System.out.println("a = " + a); b = PolyUtil.reciprocalTransformation(a, i); //System.out.println("b = " + b); assertEquals("recip(recip(c)) == c: ", c, b); //break; } } /** * Test translation. */ public void testTranslation() { //dfac = new GenPolynomialRing(new BigInteger(1), 1, to); //System.out.println("ring = " + rfac.toScript()); ai = new BigInteger(5); //System.out.println("ai = " + ai); cr = rfac.getONE(); //System.out.println("cr = " + cr); ar = PolyUtil.translationMainRecursive(cr, ai); //System.out.println("ar = " + ar); br = PolyUtil.translationMainRecursive(ar, ai.negate()); //System.out.println("br = " + br); assertEquals("translat(translat(cr)) == cr: ", cr, br); dr = rfac.getZERO(); //System.out.println("dr = " + dr); ar = PolyUtil.translationMainRecursive(dr, ai); //System.out.println("ar = " + ar); br = PolyUtil.translationMainRecursive(ar, ai.negate()); //System.out.println("br = " + br); assertEquals("translat(translat(dr)) == dr: ", dr, br); cr = rfac.univariate(0).power(3); cr = cr.sum(cr.power(5)); //System.out.println("cr = " + cr); ar = PolyUtil.translationMainRecursive(cr, ai); //System.out.println("ar = " + ar); br = PolyUtil.translationMainRecursive(ar, ai.negate()); //System.out.println("br = " + br); assertEquals("translat(translat(cr)) == cr: ", cr, br); //System.out.println("ring = " + dfac.toScript()); c = dfac.getONE(); //System.out.println("c = " + c); a = PolyUtil.translationMain(c, ai); //System.out.println("a = " + a); b = PolyUtil.translationMain(a, ai.negate()); //System.out.println("b = " + b); assertEquals("translat(translat(c)) == c: ", c, b); c = dfac.univariate(0).power(2); c = c.sum(c.power(6)); //System.out.println("c = " + c); a = PolyUtil.translationMain(c, ai); //System.out.println("a = " + a); b = PolyUtil.translationMain(a, ai.negate()); //System.out.println("b = " + b); assertEquals("translat(translat(c)) == c: ", c, b); List H = new ArrayList(rl); List Hm = new ArrayList(rl); for (int i = 1; i <= rl; i++) { H.add(new BigInteger(i)); Hm.add(new BigInteger(-i)); } //System.out.println("H = " + H + ", Hm = " + Hm); c = dfac.univariate(0).power(2); c = c.sum(c.power(5)); c = c.multiply(dfac.univariate(1).power(3)); c = c.multiply(dfac.univariate(2).power(4)); c = c.sum(dfac.univariate(3).power(7)); c = c.sum(dfac.univariate(4).power(11)); //System.out.println("c = " + c); a = PolyUtil.translation(c, H); //System.out.println("a = " + a); b = PolyUtil.translation(a, Hm); //System.out.println("b = " + b); assertEquals("translat(translat(c)) == c: ", c, b); c = dfac.random(kl * 2, ll + 2, el * 2, q + q); //System.out.println("c = " + c); a = PolyUtil.translation(c, H); //System.out.println("a = " + a); b = PolyUtil.translation(a, Hm); //System.out.println("b = " + b); assertEquals("translat(translat(c)) == c: ", c, b); } } java-algebra-system-2.7.200/trc/edu/jas/poly/PolynomialListTest.java000066400000000000000000000105741445075545500253340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PolynomialList Test using JUnit. * @author Heinz Kredel */ public class PolynomialListTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a PolynomialListTest object. * @param name String. */ public PolynomialListTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PolynomialListTest.class); return suite; } GenPolynomialRing fac; PolynomialList m; PolynomialList p; GenPolynomial a, b, c, d, e; int rl = 4; int kl = 4; int ll = 4; int el = 5; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; m = null; p = null; BigRational coeff = new BigRational(9); fac = new GenPolynomialRing(coeff, rl); } @Override protected void tearDown() { a = b = c = d = e = null; m = null; p = null; } /** * Test constructor and toString. */ public void testConstructor() { p = new PolynomialList(fac, (List>) null); assertTrue("p = 0", p.list == null); m = new PolynomialList(fac, new ArrayList>()); assertTrue("m = 0", m.list != null); assertTrue("m.size() == 0", m.list.size() == 0); String s = m.toScript(); //System.out.println("m.toScript: " + s + ", " + s.length()); assertEquals("#s == 60: " + s, s.length(), 60); } /** * Test polynomial list. */ public void testPolynomialList() { List> l = new ArrayList>(); for (int i = 0; i < 7; i++) { a = fac.random(ll + i); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); l.add(a); } p = new PolynomialList(fac, l); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p)); assertEquals("p.length", 7, p.list.size()); } /** * Test ordered polynomial list. */ public void testOrderedPolynomialList() { List> l = new ArrayList>(); for (int i = 0; i < 7; i++) { a = fac.random(ll + i); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); l.add(a); } p = new PolynomialList(fac, l); //System.out.println("p = "+p); m = new OrderedPolynomialList(fac, p.list); //System.out.println("m = "+m); assertTrue("p == m", p.equals(m)); assertTrue("m != p", !m.equals(p)); assertEquals("p.length", 7, p.list.size()); assertEquals("m.length", 7, m.list.size()); } /** * Test homogeneous polynomial list. */ public void testHomogeneousPolynomialList() { List> l = new ArrayList>(); for (int i = 0; i < 7; i++) { a = fac.random(ll + i); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); l.add(a); } p = new PolynomialList(fac, l); //System.out.println("p = "+p); PolynomialList h = p.homogenize(); //System.out.println("h = "+h); assertTrue("h is homogen", h.isHomogeneous()); PolynomialList pp = h.deHomogenize(); //System.out.println("pp = "+pp); assertTrue("p == pp", p.equals(pp)); } } java-algebra-system-2.7.200/trc/edu/jas/poly/QuatGenPolynomialTest.java000066400000000000000000000145311445075545500257620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigQuaternion coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class QuatGenPolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a QuatGenPolynomialTest object. * @param name String. */ public QuatGenPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(QuatGenPolynomialTest.class); return suite; } //private final static int bitlen = 100; BigQuaternionRing cfac; GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int rl = 4; int kl = 3; int ll = 7; int el = 3; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigQuaternionRing(); fac = new GenPolynomialRing(cfac, rl); } @Override protected void tearDown() { a = b = c = d = e = null; cfac = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl, ll, el, q); // fac.random(kl*(i+1), ll+2*i, el+i, q ); if (a.isZERO()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(kl, ll, el, q); ExpVector u = ExpVector.random(rl, el, q); BigQuaternion x = cfac.random(kl); b = new GenPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial(fac); b = new GenPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { do { a = fac.random(kl, ll, el, q); } while (a.isZERO()); do { b = fac.random(kl, ll, el, q); } while (b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("!isZERO( a*b-b*a ) " + e, !e.isZERO()); assertTrue("a*b = b*a", !c.equals(d)); //assertEquals("a*b = b*a",c,d); c = fac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); //assertTrue("a(bc) = (ab)c", d.equals(e) ); BigQuaternion x = a.leadingBaseCoefficient().inverse(); c = a.monic(); d = a.multiplyLeft(x); assertEquals("a.monic() = (1/ldcf(a))a", c, d); BigQuaternion y = b.leadingBaseCoefficient().inverse(); c = b.monic(); //System.out.println("c = " + c); d = b.multiplyLeft(y); //System.out.println("d = " + d); assertEquals("b.monic() = (1/ldcf(b))b", c, d); e = new GenPolynomial(fac, y); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b))b", c, d); //d = b.multiplyLeft(y); d = b.multiply(y); //System.out.println("d = " + d); //wrong: assertEquals("b.monic() = (1/ldcf(b))b",c,d); assertTrue("is monic: b(1/ldcf(b))", d.leadingBaseCoefficient().isONE()); } /** * Test coefficient multiplication. */ public void testCoeffMultiplication() { a = fac.random(kl, ll, el, q); //System.out.println("a = " + a); c = a.monic(); //System.out.println("c = " + c); BigQuaternion qa = cfac.random(5); //System.out.println("qa = " + qa); BigQuaternion qb = qa.inverse(); //System.out.println("qb = " + qb); BigQuaternion qc = qa.multiply(qb); //System.out.println("qc = " + qc); BigQuaternion qd = qb.multiply(qa); //System.out.println("qc = " + qc); assertEquals("qa*(1/qa) == (1/qa)*qa ", qc, qd); b = c.multiply(qa).multiply(qb); //System.out.println("b = " + b); d = c.multiplyLeft(qa).multiplyLeft(qb); //System.out.println("d = " + d); assertEquals("c*qa*qb = qb*qa*c", b, d); //e = b.subtract(d); //System.out.println("e = " + e); b = c.multiply(qa).multiplyLeft(qb); //System.out.println("b = " + b); d = c.multiplyLeft(qb).multiply(qa); //System.out.println("d = " + d); e = b.subtract(d); //System.out.println("e = " + e); assertEquals("qb*(c*qa) == (qb*c)*qa", b, d); } } java-algebra-system-2.7.200/trc/edu/jas/poly/QuatGenSolvablePolynomialTest.java000066400000000000000000000260271445075545500274550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.arith.BigQuaternion; import edu.jas.arith.BigQuaternionRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigQuaternion coefficients GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class QuatGenSolvablePolynomialTest extends TestCase { /** * main */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a QuatGenSolvablePolynomialTest object. * @param name String. */ public QuatGenSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(QuatGenSolvablePolynomialTest.class); return suite; } BigQuaternionRing cfac; GenSolvablePolynomialRing fac; GenSolvablePolynomial a, b, c, d, e, f; int rl = 6; int kl = 3; int ll = 7; int el = 3; float q = 0.33f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigQuaternionRing(); fac = new GenSolvablePolynomialRing(cfac, rl); RelationGenerator rel = new WeylRelations(); rel.generate(fac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; cfac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test factory. */ public void testFactory() { assertFalse("!is comutative", fac.isCommutative()); assertFalse("!is field", fac.isField()); assertTrue("is associative", fac.isAssociative()); List> gens = fac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens = 4+rl ", gens.size() == (4 + rl)); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { //a = fac.random(ll); a = fac.random(kl, ll + i, el + (5 - i), q); if (a.isZERO()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test solvable addition. */ public void testAddition() { a = fac.random(kl, ll, el, q); // fac.random(ll); b = fac.random(kl, ll, el, q); // fac.random(ll); c = (GenSolvablePolynomial) a.sum(b); d = (GenSolvablePolynomial) c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(kl, ll, el, q); //fac.random(ll); ExpVector u = ExpVector.random(rl, el, q); BigQuaternion x = cfac.random(kl); b = new GenSolvablePolynomial(fac, x, u); c = (GenSolvablePolynomial) a.sum(b); d = (GenSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (GenSolvablePolynomial) a.subtract(b); d = (GenSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenSolvablePolynomial(fac); assertTrue("a == 0", a.isZERO()); } /** * Test solvable multiplication. */ @SuppressWarnings("cast") public void testMultiplication() { do { a = fac.random(kl, ll, el, q); //fac.random(ll); } while (a.isZERO()); do { b = fac.random(kl, ll, el, q); //fac.random(ll); } while (b.isZERO()); c = (GenSolvablePolynomial) b.multiply(a); d = (GenSolvablePolynomial) a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("!isZERO( a*b-b*a ) " + e, !e.isZERO()); //assertTrue("a*b = b*a", !c.equals(d)); //assertEquals("a*b = b*a",c,d); c = fac.random(kl, ll, el, q); //System.out.println("c = " + c); d = (GenSolvablePolynomial) a.multiply(b.multiply(c)); e = (GenSolvablePolynomial) (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); //assertTrue("a(bc) = (ab)c", d.equals(e)); BigQuaternion x = a.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) a.monic(); d = (GenSolvablePolynomial) a.multiplyLeft(x); assertEquals("a.monic() = a(1/ldcf(a))", c, d); BigQuaternion y = b.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) b.monic(); d = (GenSolvablePolynomial) b.multiplyLeft(y); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = new GenSolvablePolynomial(fac, y); d = (GenSolvablePolynomial) e.multiply(b); assertEquals("b.monic() = b(1/ldcf(b))", c, d); } /** * Test solvable left and right multiplication. */ public void testDoubleMultiplication() { a = fac.random(kl, 3, el, q); //fac.random(ll); b = fac.random(kl, 2, el, q); //fac.random(ll); c = fac.random(kl, 3, el, q); //fac.random(ll); d = a.multiply(b).multiply(c); e = b.multiply(a, c); assertEquals("a b c = b.multiply(a,c)", d, e); BigQuaternion qa, qb, qc, qd; // search non commuting qa, qb do { qa = cfac.random(kl); qb = cfac.random(kl); qc = qa.multiply(qb); qd = qb.multiply(qa); } while (qc.equals(qd)); //System.out.println("qa = " + qa); //System.out.println("qb = " + qb); //System.out.println("qc = " + qc); //System.out.println("qd = " + qd); a = fac.univariate(0); d = a.multiply(qa, qb); e = a.multiply(qb, qa); //System.out.println("a = " + a); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("a.multiply(qa,qb) != a.multiply(qb,qq)", !d.equals(e) || d.leadingExpVector().equals(e.leadingExpVector())); // commuting variables ExpVector ea = fac.univariate(1).leadingExpVector(); ExpVector eb = fac.univariate(2).leadingExpVector(); //System.out.println("ea = " + ea); //System.out.println("eb = " + eb); d = a.multiply(ea, eb); e = a.multiply(eb, ea); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("a.multiply(ea,eb) == a.multiply(eb,eq)", d.equals(e)); d = a.multiply(qa, ea, qb, eb); e = a.multiply(qb, eb, qa, ea); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("a.multiply(qa,ea,qb,eb) != a.multiply(qb,eb,qa,ea)", d.equals(e) || d.leadingExpVector().equals(e.leadingExpVector())); } /** * Test division of polynomials. */ public void testDivide() { assertFalse("isCommutative()", fac.isCommutative()); assertTrue("isAssociative()", fac.isAssociative()); do { a = fac.random(kl, ll, el, q); } while (a.isZERO()); //System.out.println("a = " + a); do { b = fac.random(kl, ll, el, q); } while (b.isZERO()); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("a*b != b*a", !c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // divide e = c.divide(a); //System.out.println("e = " + e); f = c.rightDivide(b); //System.out.println("f = " + f); assertEquals("b == b*a/a: " + e, e, b); assertEquals("a == b*a/b: " + e, f, a); e = d.rightDivide(a); //System.out.println("e = " + e); f = d.divide(b); //System.out.println("f = " + f); assertEquals("b == a*b/a: " + e, e, b); assertEquals("a == a*b/b: " + e, f, a); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = a.multiply((GenSolvablePolynomial) b.sum(c)); e = (GenSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test coefficient multiplication. */ public void testCoeffMultiplication() { a = fac.random(kl, ll, el, q); //System.out.println("a = " + a); c = a.monic(); //System.out.println("c = " + c); BigQuaternion qa = cfac.random(5); //System.out.println("qa = " + qa); BigQuaternion qb = qa.inverse(); //System.out.println("qb = " + qb); BigQuaternion qc = qa.multiply(qb); //System.out.println("qc = " + qc); BigQuaternion qd = qb.multiply(qa); //System.out.println("qc = " + qc); assertEquals("qa*(1/qa) == (1/qa)*qa ", qc, qd); b = c.multiply(qa).multiply(qb); //System.out.println("b = " + b); d = c.multiplyLeft(qa).multiplyLeft(qb); //System.out.println("d = " + d); assertEquals("c*qa*qb = qb*qa*c", b, d); //e = (GenSolvablePolynomial)b.subtract(d); //System.out.println("e = " + e); b = c.multiply(qa).multiplyLeft(qb); //System.out.println("b = " + b); d = c.multiplyLeft(qb).multiply(qa); //System.out.println("d = " + d); //e = (GenSolvablePolynomial)b.subtract(d); //System.out.println("e = " + e); assertEquals("qb*(c*qa) == (qb*c)*qa", b, d); } } java-algebra-system-2.7.200/trc/edu/jas/poly/QuotientTest.java000066400000000000000000000230241445075545500241570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.arith.BigInteger; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient tests with JUnit. * @author Heinz Kredel */ public class QuotientTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a QuotientTest object. * @param name String. */ public QuotientTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(QuotientTest.class); return suite; } QuotientRing fac; GenPolynomialRing pfac; QuotientRing> mfac; Quotient a, b, c, d, e; Quotient> ap, bp, cp, dp, ep; int rl = 2; int kl = 17; int ll = 3; //6; int el = 2; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; fac = new QuotientRing(new BigInteger(1)); pfac = new GenPolynomialRing(new BigInteger(1), 1); mfac = new QuotientRing>(pfac); } @Override protected void tearDown() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; fac = null; pfac = null; mfac = null; } /** * Test factory for integer. */ public void testIntRing() { assertFalse("#ring infinite", fac.isFinite()); assertTrue("associative ring", fac.isAssociative()); assertTrue("commutative ring", fac.isCommutative()); assertTrue("characteristic p", fac.characteristic().signum() == 0); assertTrue("no field", fac.isField()); } /** * Test factory for polynomial. */ public void testPolyRing() { assertFalse("#ring infinite", mfac.isFinite()); assertTrue("associative ring", mfac.isAssociative()); assertTrue("commutative ring", mfac.isCommutative()); assertTrue("characteristic zero", mfac.characteristic().signum() == 0); assertTrue("no field", mfac.isField()); } /** * Test constructor for integer. */ public void testIntConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); List> gens = fac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 1: ", gens.size() == 1); for (Quotient v : gens) { a = fac.parse(v.toString()); assertEquals("a == v", a, v); } } /** * Test constructor for polynomial. */ public void testPolyConstruction() { cp = mfac.getONE(); assertTrue("isZERO( cp )", !cp.isZERO()); assertTrue("isONE( cp )", cp.isONE()); dp = mfac.getZERO(); assertTrue("isZERO( dp )", dp.isZERO()); assertTrue("isONE( dp )", !dp.isONE()); List>> gens = mfac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 3: ", gens.size() == 3); for (Quotient> v : gens) { ap = mfac.parse(v.toString()); assertEquals("ap == v", ap, v); } } /** * Test random integer. */ public void testIntRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl * (i + 1)); //a = fac.random(kl*(i+1), ll+2+2*i, el, q ); //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test random polynomial. */ public void testPolyRandom() { for (int i = 0; i < 7; i++) { ap = mfac.random(kl + i); assertTrue(" not isZERO( ap" + i + " )", !ap.isZERO()); assertTrue(" not isONE( ap" + i + " )", !ap.isONE()); } } /** * Test integer addition. */ public void testIntAddition() { a = fac.random(kl); b = fac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = fac.random(kl); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test polynomial addition. */ public void testPolyAddition() { ap = mfac.random(kl); bp = mfac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); cp = ap.sum(bp); dp = cp.subtract(bp); assertEquals("a+b-b = a", ap, dp); cp = ap.sum(bp); dp = bp.sum(ap); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", cp, dp); cp = mfac.random(kl); dp = cp.sum(ap.sum(bp)); ep = cp.sum(ap).sum(bp); assertEquals("c+(a+b) = (c+a)+b", dp, ep); cp = ap.sum(mfac.getZERO()); dp = ap.subtract(mfac.getZERO()); assertEquals("a+0 = a-0", cp, dp); cp = mfac.getZERO().sum(ap); dp = mfac.getZERO().subtract(ap.negate()); assertEquals("0+a = 0+(-a)", cp, dp); } /** * Test integer multiplication. */ public void testIntMultiplication() { a = fac.random(kl); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } Quotient[] qr; c = b.multiply(a); qr = c.quotientRemainder(a); assertEquals("b*a / a == b", qr[0], b); assertTrue("b*a rem a == 0", qr[1].isZERO()); } /** * Test polynomial multiplication. */ public void testPolyMultiplication() { ap = mfac.random(kl); assertTrue("not isZERO( a )", !ap.isZERO()); bp = mfac.random(kl); assertTrue("not isZERO( b )", !bp.isZERO()); cp = bp.multiply(ap); dp = ap.multiply(bp); assertTrue("not isZERO( c )", !cp.isZERO()); assertTrue("not isZERO( d )", !dp.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); ep = dp.subtract(cp); assertTrue("isZERO( a*b-b*a ) " + ep, ep.isZERO()); assertTrue("a*b = b*a", cp.equals(dp)); assertEquals("a*b = b*a", cp, dp); cp = mfac.random(kl); //System.out.println("c = " + c); dp = ap.multiply(bp.multiply(cp)); ep = (ap.multiply(bp)).multiply(cp); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", dp, ep); assertTrue("a(bc) = (ab)c", dp.equals(ep)); cp = ap.multiply(mfac.getONE()); dp = mfac.getONE().multiply(ap); assertEquals("a*1 = 1*a", cp, dp); if (ap.isUnit()) { cp = ap.inverse(); dp = cp.multiply(ap); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", dp.isONE()); } Quotient>[] qr; cp = bp.multiply(ap); qr = cp.quotientRemainder(ap); assertEquals("b*a / a == b", qr[0], bp); assertTrue("b*a rem a == 0", qr[1].isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RatGenPolynomialTest.java000066400000000000000000000342661445075545500256050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.HashSet; import java.util.List; import java.util.Set; import edu.jas.arith.BigRational; import edu.jas.arith.BigInteger; import edu.jas.poly.PolyUtil; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class RatGenPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RatGenPolynomialTest object. * @param name String. */ public RatGenPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RatGenPolynomialTest.class); return suite; } GenPolynomialRing fac; GenPolynomial a, b, c, d, e; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; String[] vars = new String[] { "a", "b", "c", "d", "e", "f", "g" }; fac = new GenPolynomialRing(new BigRational(1), vars); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test generate. */ public void testGenerate() { assertEquals("rl == #vars: ", rl, fac.nvar); String s = fac.toScript(); //System.out.println("fac.toScript: " + s + ", " + s.length()); assertTrue("#s == 50: " + s.length(), s.length() <= 50); List> gens = fac.generators(); assertFalse("#gens != () ", gens.isEmpty()); //System.out.println("generators: " + gens); // test equals Set> set = new HashSet>(gens); //System.out.println("gen set: " + set); assertEquals("#gens == #set: ", gens.size(), set.size()); // test for elements 0, 1 a = fac.getZERO(); b = fac.getONE(); assertFalse("0 not in #set: ", set.contains(a)); assertTrue("1 in #set: ", set.contains(b)); // specific tests assertEquals("#gens == rl+1 ", rl + 1, gens.size()); Set iset = new HashSet(set.size()); for (GenPolynomial p : gens) { //System.out.println("p = " + p.toScript() + ", # = " + p.hashCode() + ", red = " + p.reductum()); assertTrue("red(p) == 0 ", p.reductum().isZERO()); iset.add(p.hashCode()); } assertEquals("#gens == #iset: ", gens.size(), iset.size()); } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { //a = fac.random(ll); a = fac.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(ll); ExpVector u = ExpVector.random(rl, el, q); BigRational x = BigRational.RNRAND(kl); b = new GenPolynomial(fac, x, u); c = a.sum(b); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = new GenPolynomial(fac); b = new GenPolynomial(fac, x, u); c = b.sum(a); d = a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = a.subtract(b); d = a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); BigRational x = a.leadingBaseCoefficient().inverse(); c = a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))", c, d); BigRational y = b.leadingBaseCoefficient().inverse(); c = b.monic(); d = b.multiply(y); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = new GenPolynomial(fac, y); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b", c, d); } /** * Test BLAS level 1. */ public void testBLAS1() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, 3, el * el, q); ExpVector ev = ExpVector.random(rl, el, q); BigRational lc = BigRational.RNRAND(kl); d = a.subtractMultiple(lc, b); e = a.subtract(b.multiply(lc)); assertEquals("a - (lc) b == a - ((lc) b)", d, e); d = a.subtractMultiple(lc, ev, b); e = a.subtract(b.multiply(lc, ev)); assertEquals("a - (lc ev) b == a - ((lc ev) b)", d, e); ExpVector fv = ExpVector.random(rl, el, q); BigRational tc = BigRational.RNRAND(kl); d = a.scaleSubtractMultiple(tc, lc, ev, b); e = a.multiply(tc).subtract(b.multiply(lc, ev)); assertEquals("(tc) a - (lc ev) b == ((tc) a - ((lc ev) b))", d, e); d = a.scaleSubtractMultiple(tc, fv, lc, ev, b); e = a.multiply(tc, fv).subtract(b.multiply(lc, ev)); assertEquals("(tc fv) a - (lc ev) b == ((tc fv) a - ((lc ev) b))", d, e); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) == ab+ac", d, e); } /** * Test object quotient and remainder. */ public void testQuotRem() { fac = new GenPolynomialRing(new BigRational(1), 1); a = fac.random(ll).monic(); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll).monic(); assertTrue("not isZERO( b )", !b.isZERO()); GenPolynomial h = a; GenPolynomial g = fac.random(ll).monic(); assertTrue("not isZERO( g )", !g.isZERO()); a = a.multiply(g); b = b.multiply(g); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("g = " + g); GenPolynomial[] qr; qr = b.quotientRemainder(a); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(a).sum(d); assertEquals("b = q a + r", b, e); qr = a.quotientRemainder(b); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(b).sum(d); assertEquals("a = q b + r", a, e); // gcd tests ------------------------------- c = a.gcd(b); //System.out.println("gcd = " + c); assertTrue("a mod gcd(a,b) = 0", a.remainder(c).isZERO()); assertTrue("b mod gcd(a,b) = 0", b.remainder(c).isZERO()); assertEquals("g = gcd(a,b)", c, g); GenPolynomial[] gst; gst = a.egcd(b); //System.out.println("egcd = " + gst[0]); //System.out.println(", s = " + gst[1] + ", t = " + gst[2]); c = gst[0]; d = gst[1]; e = gst[2]; assertEquals("g = gcd(a,b)", c, g); GenPolynomial x; x = a.multiply(d).sum(b.multiply(e)).monic(); //System.out.println("x = " + x); assertEquals("gcd(a,b) = a s + b t", c, x); gst = a.hegcd(b); //System.out.println("hegcd = " + gst[0]); //System.out.println("s = " + gst[1]); c = gst[0]; d = gst[1]; assertEquals("g = gcd(a,b)", c, g); x = a.multiply(d).remainder(b).monic(); //System.out.println("x = " + x); assertEquals("gcd(a,b) = a s mod b", c, x); //System.out.println("g = " + g); //System.out.println("h = " + h); c = h.modInverse(g); //System.out.println("c = " + c); x = c.multiply(h).remainder(g).monic(); //System.out.println("x = " + x); assertTrue("h invertible mod g", x.isONE()); } /** * Test addition speed. */ public void testAdditionSpeed() { int ll = 100; long t = 1000; boolean print = false; int jit = 1; for (int j = 1; j < 5; j++) { for (int i = 1; i < 5; i++) { a = fac.random(kl, i * ll, el, q); b = fac.random(kl, ll, el, q); for (int k = 0; k < jit; k++) { long t1 = System.nanoTime(); c = a.sum(b); t1 = System.nanoTime() - t1; assertTrue("c != 0", !c.isZERO()); long t2 = System.nanoTime(); d = b.sum(a); t2 = System.nanoTime() - t2; assertTrue("d != 0", !d.isZERO()); if (print) { System.out.print("#a = " + a.length() + ", #b = " + b.length()); System.out.println(",\t t1 = " + (t1 / t) + ", t2 = " + (t2 / t)); } //assertTrue("t2 <= t1", ((t1/t) >= (t2/t)) ); } if (print) System.out.println(); assertEquals("c == d", c, d); } ll = 3 * ll; } } /** * Test absolute norm. */ public void testAbsNorm() { BigRational r; a = fac.getONE().negate(); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue("isONE( absNorm(-1) )", r.isONE()); a = fac.random(kl * 2, ll + 2, el, q); //System.out.println("a = " + a); r = PolyUtil. absNorm(a); //System.out.println("r = " + r); assertTrue(" not isZERO( absNorm(a) )", !r.isZERO() || a.isZERO()); } /** * Test max norm. */ public void testMaxNorm() { BigRational r, s; a = fac.getZERO(); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("isONE( maxNorm(0) )", r.isZERO()); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("isONE( sumNorm(0) )", r.isZERO()); a = fac.getONE().negate(); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("isONE( maxNorm(-1) )", r.isONE()); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("isONE( sumNorm(-1) )", r.isONE()); a = fac.random(kl * 2, ll + 2, el, q); //System.out.println("a = " + a); r = a.maxNorm(); //System.out.println("r = " + r); assertTrue("not isZERO( maxNorm(a) )", !r.isZERO() || a.isZERO()); //s = a.multiply(a).maxNorm(); //System.out.println("s = " + s + ", r*r = " + r.multiply(r)); //assertEquals("s*s == maxNorm(a*a) )", r.multiply(r), s ); r = a.sumNorm(); //System.out.println("r = " + r); assertTrue("not isZERO( maxNorm(a) )", !r.isZERO() || a.isZERO()); //s = a.multiply(a).sumNorm(); //System.out.println("s = " + s + ", r*r = " + r.multiply(r)); //assertEquals("s*s == sumNorm(a*a) )", r.multiply(r), s ); } /** * Test monic and coefficient primitive part. */ public void testMonicCPP() { BigInteger bfac = new BigInteger(1); GenPolynomialRing ifac = new GenPolynomialRing(bfac, fac); GenPolynomial ai = ifac.random(kl * 2, ll + 2, el, q); ai = ai.multiply(bfac.random(kl)); //System.out.println("ai = " + ai); GenPolynomial bi = ai.coeffPrimitivePart(); //System.out.println("bi = " + bi); a = PolyUtil. fromIntegerCoefficients(fac, ai).monic(); //System.out.println("a = " + a); b = PolyUtil. fromIntegerCoefficients(fac, bi).monic(); //System.out.println("b = " + b); assertEquals("a == b: " + a + " != " + b, a, b); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RatGenSolvablePolynomialTest.java000066400000000000000000000327361445075545500272750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import java.util.Set; import java.util.HashSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; /** * BigRational coefficients GenSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class RatGenSolvablePolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RatGenSolvablePolynomialTest object. * @param name String. */ public RatGenSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RatGenSolvablePolynomialTest.class); return suite; } GenSolvablePolynomial a, b, c, d, e, f, x1, x2; int rl = 6; int kl = 10; int ll = 5; int el = 3; float q = 0.5f; RelationTable table; GenSolvablePolynomialRing ring, fac; BigRational cfac; @Override protected void setUp() { cfac = new BigRational(1); ring = new GenSolvablePolynomialRing(cfac, rl); fac = ring; table = ring.table; a = b = c = d = e = null; } @Override protected void tearDown() { table = null; ring = null; a = b = c = d = e = null; } /** * Test generate. */ public void testGenerate() { String s = fac.toScript(); //System.out.println("fac.toScript: " + s + ", " + s.length()); assertTrue("#s == 51: " + s, s.length() == 51); List> gens = fac.generators(); assertFalse("#gens != () ", gens.isEmpty()); //System.out.println("generators: " + gens); // test equals Set> set = new HashSet>(gens); //System.out.println("gen set: " + set); assertEquals("#gens == #set: ", gens.size(), set.size()); // test for elements 0, 1 a = fac.getZERO(); b = fac.getONE(); assertFalse("0 not in #set: ", set.contains(a)); assertTrue("1 in #set: ", set.contains(b)); // specific tests assertEquals("#gens == rl+1 ", rl + 1, gens.size()); Set iset = new HashSet(set.size()); for (GenPolynomial p : gens) { //System.out.println("p = " + p.toScript() + ", # = " + p.hashCode() + ", red = " + p.reductum()); assertTrue("red(p) == 0 ", p.reductum().isZERO()); iset.add(p.hashCode()); } assertEquals("#gens == #iset: ", gens.size(), iset.size()); } /** * Test constructor and toString. */ public void testConstructor() { a = new GenSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { assertTrue("isCommutative()", ring.isCommutative()); for (int i = 0; i < 2; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (GenSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (GenSolvablePolynomial) a.sum(a); c = (GenSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); assertTrue("a+a-a = a", c.equals(a)); b = ring.random(kl, ll, el, q); c = (GenSolvablePolynomial) b.sum(a); d = (GenSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); assertTrue("a+b = b+a", c.equals(d)); c = ring.random(kl, ll, el, q); d = (GenSolvablePolynomial) a.sum(b.sum(c)); e = (GenSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); assertTrue("a+(b+c) = (a+b)+c", d.equals(e)); ExpVector u = ExpVector.random(rl, el, q); BigRational x = cfac.random(kl); b = ring.getONE().multiply(x, u); c = (GenSolvablePolynomial) a.sum(b); d = (GenSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (GenSolvablePolynomial) a.subtract(b); d = (GenSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (GenSolvablePolynomial) b.sum(a); d = (GenSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (GenSolvablePolynomial) a.subtract(b); d = (GenSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test object multiplication. */ @SuppressWarnings("cast") public void testMultiplication() { a = ring.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); //a = RatGenSolvablePolynomial.DIRRAS(1, kl, 4, el, q ); b = ring.random(kl, ll, el, q); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertEquals("a*b = b*a", c, d); assertTrue("a*b = b*a", c.equals(d)); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); BigRational x = a.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) a.monic(); d = a.multiply(x); assertEquals("a.monic() = a(1/ldcf(a))", c, d); ExpVector u = ring.evzero; BigRational y = b.leadingBaseCoefficient().inverse(); c = (GenSolvablePolynomial) b.monic(); d = b.multiply(y, u); assertEquals("b.monic() = b(1/ldcf(b))", c, d); e = ring.getONE().multiply(y, u); d = b.multiply(e); assertEquals("b.monic() = b(1/ldcf(b))", c, d); d = e.multiply(b); assertEquals("b.monic() = (1/ldcf(b) (0))*b", c, d); d = a.monic(); assertTrue("a.monic(): ", d.leadingBaseCoefficient().isONE()); } /** * Test Weyl polynomials. */ public void testWeyl() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); assertTrue("not isZERO( a )", !a.isZERO()); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); assertTrue("not isZERO( b )", !b.isZERO()); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("!isZERO( a*b-b*a ) " + e, !e.isZERO()); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); //System.out.println("\na = " + a); //System.out.println("\nb = " + b); //System.out.println("\nc = " + c); // associative //x1 = b.multiply(c); //System.out.println("\nx1 = " + x1); d = a.multiply(b.multiply(c)); //x2 = a.multiply(b); //System.out.println("\nx2 = " + x2); e = a.multiply(b).multiply(c); //System.out.println("\nd = " + d); //System.out.println("\ne = " + e); //f = (GenSolvablePolynomial)d.subtract(e); //System.out.println("\nf = " + f); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); } /** * Test division of polynomials. */ public void testDivide() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); do { a = ring.random(kl, ll, el, q); } while(a.isZERO()); //System.out.println("a = " + a); do { b = ring.random(kl, ll, el, q); } while(b.isZERO()); //System.out.println("b = " + b); // non commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); e = (GenSolvablePolynomial) d.subtract(c); assertTrue("a*b != b*a", !c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // divide e = c.divide(a); //System.out.println("e = " + e); f = c.rightDivide(b); //System.out.println("f = " + f); assertEquals("b == b*a/a: " + e, e, b); assertEquals("a == b*a/b: " + e, f, a); e = d.rightDivide(a); //System.out.println("e = " + e); f = d.divide(b); //System.out.println("f = " + f); assertEquals("b == a*b/a: " + e, e, b); assertEquals("a == a*b/b: " + e, f, a); } /** * Test BLAS level 1. */ public void testBLAS1() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); a = ring.random(kl,ll,el,q); b = ring.random(kl,ll,el,q); ExpVector ev = ExpVector.random(rloc,el,q); BigRational lc = BigRational.ONE.random(kl); d = a.subtractMultiple(lc,b); e = (GenSolvablePolynomial) a.subtract( b.multiplyLeft(lc) ); assertEquals("a - (lc) b == a - ((lc) b)",d,e); d = a.subtractMultiple(lc,ev,b); e = (GenSolvablePolynomial) a.subtract( b.multiplyLeft(lc,ev) ); assertEquals("a - (lc ev) b == a - ((lc ev) b)",d,e); ExpVector fv = ExpVector.random(rloc,el,q); BigRational tc = BigRational.ONE.random(kl); d = a.scaleSubtractMultiple(tc,lc,ev,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc).subtract( b.multiplyLeft(lc,ev) ); assertEquals("(tc) a - (lc ev) b == ((tc) a - ((lc ev) b))",d,e); d = a.scaleSubtractMultiple(tc,fv,lc,ev,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc,fv).subtract( b.multiplyLeft(lc,ev) ); assertEquals("(tc fv) a - (lc ev) b == ((tc fv) a - ((lc ev) b))",d,e); d = a.scaleSubtractMultiple(tc,lc,b); e = (GenSolvablePolynomial) a.multiplyLeft(tc).subtract( b.multiplyLeft(lc) ); assertEquals("tc a - lc b == (tc a) - (lc b)",d,e); } /** * Test distributive law. */ public void testDistributive() { int rloc = 4; ring = new GenSolvablePolynomialRing(cfac, rloc); RelationGenerator wl = new WeylRelations(); wl.generate(ring); //table = ring.table; //System.out.println("table = " + table); //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((GenSolvablePolynomial) b.sum(c)); e = (GenSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RatPolyGenPolynomialTest.java000066400000000000000000000114061445075545500264400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; /** * BigRational coefficients GenPolynomial coefficients GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class RatPolyGenPolynomialTest extends TestCase { /** * main */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a RatPolyGenPolynomialTest object. * @param name String. */ public RatPolyGenPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(RatPolyGenPolynomialTest.class); return suite; } GenPolynomialRing cf; GenPolynomialRing> fac; GenPolynomial> a, b, c, d, e; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; protected void setUp() { a = b = c = d = e = null; cf = new GenPolynomialRing( new BigRational(1), 1 ); fac = new GenPolynomialRing>(cf,rl); } protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO() ); assertTrue("isONE( c )", c.isONE() ); d = fac.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO() ); assertTrue("isONE( d )", !d.isONE() ); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(ll); //fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a",a,d); c = fac.random(ll); ExpVector u = ExpVector.random(rl,el,q); GenPolynomial x = cf.random(kl); b = new GenPolynomial>(fac,x, u); c = a.sum(b); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); a = new GenPolynomial>(fac); b = new GenPolynomial>(fac,x, u); c = b.sum(a); d = a.sum(x,u); assertEquals("a+p(x,u) = a+(x,u)",c,d); c = a.subtract(b); d = a.subtract(x,u); assertEquals("a-p(x,u) = a-(x,u)",c,d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO() ); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO() ); assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO() ); assertTrue("a*b = b*a", c.equals(d) ); assertEquals("a*b = b*a",c,d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply( b.multiply(c) ); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c",d,e); assertTrue("a(bc) = (ab)c", d.equals(e) ); //GenPolynomial x = a.leadingBaseCoefficient().inverse(); //c = a.monic(); //d = a.multiply(x); //assertEquals("a.monic() = a(1/ldcf(a))",c,d); GenPolynomial y = b.leadingBaseCoefficient(); //c = b.monic(); //d = b.multiply(y); //assertEquals("b.monic() = b(1/ldcf(b))",c,d); e = new GenPolynomial>(fac,y); c = b.multiply(e); // assertEquals("b.monic() = b(1/ldcf(b))",c,d); d = e.multiply(b); assertEquals("b*p(y,u) = p(y,u)*b",c,d); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RecSolvablePolynomialTest.java000066400000000000000000000635441445075545500266270ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import java.util.Map; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * BigRational coefficients RecSolvablePolynomial tests with JUnit. * @author Heinz Kredel */ public class RecSolvablePolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RecSolvablePolynomialTest object. * @param name String. */ public RecSolvablePolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RecSolvablePolynomialTest.class); return suite; } RecSolvablePolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 3; int ll = 4; int el = 3; float q = 0.25f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; RelationTable> table; RecSolvablePolynomialRing ring; BigRational cfac; GenSolvablePolynomialRing> sring; GenSolvablePolynomialRing cring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenSolvablePolynomialRing(cfac, tord, cvars); //sring = new GenSolvablePolynomialRing>(cring,rl,tord); ring = new RecSolvablePolynomialRing(cring, tord, vars); RelationGenerator> wl = new WeylRelations>(); //wl.generate(ring); ring.addRelations(wl); table = ring.table; a = b = c = d = e = null; } @Override protected void tearDown() { table = null; ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new RecSolvablePolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (RecSolvablePolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (RecSolvablePolynomial) a.sum(a); c = (RecSolvablePolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (RecSolvablePolynomial) b.sum(a); d = (RecSolvablePolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (RecSolvablePolynomial) a.sum(b.sum(c)); e = (RecSolvablePolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); GenPolynomial x = cring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (RecSolvablePolynomial) a.sum(b); d = (RecSolvablePolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (RecSolvablePolynomial) a.subtract(b); d = (RecSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (RecSolvablePolynomial) b.sum(a); d = (RecSolvablePolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (RecSolvablePolynomial) a.subtract(b); d = (RecSolvablePolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll, el, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); BigRational x = a.leadingBaseCoefficient().leadingBaseCoefficient().inverse(); GenPolynomial xp = new GenPolynomial(cring, x); d = (RecSolvablePolynomial) a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().leadingBaseCoefficient().isONE()); d = (RecSolvablePolynomial) a.monic(); assertTrue("a.monic(): " + d.leadingBaseCoefficient() + ", " + a.leadingBaseCoefficient(), d.leadingBaseCoefficient().isONE() || d.leadingBaseCoefficient() .equals(a.leadingBaseCoefficient())); } /** * Test commutative ring. */ public void testCommutative() { //System.out.println("table = " + table.toString(vars)); //System.out.println("table = " + table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); ring = new RecSolvablePolynomialRing(cring, ring); //table = ring.table; //System.out.println("table = " + table.toString(vars)); //System.out.println("ring = " + ring); assertTrue("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("ba == ab: ", c, d); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((RecSolvablePolynomial) b.sum(c)); e = (RecSolvablePolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test solvable coefficient ring. */ public void testSolvableCoeffs() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); //wlc.generate(csring); csring.addRelations(wlc); assertTrue("# relations == 1", csring.table.size() == 1); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); ring = new RecSolvablePolynomialRing(csring, ring); RelationGenerator> wl = new WeylRelations>(); //wl.generate(ring); ring.addRelations(wl); assertTrue("# relations == 2", ring.table.size() == 2); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); RecSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.parse("b x + a"); //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); table = ring.table; //System.out.println("ring = " + ring); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new RecSolvablePolynomial(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new RecSolvablePolynomial(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens:" + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); ev = a.leadingBaseCoefficient().leadingExpVector() .sum(b.leadingBaseCoefficient().leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingBaseCoefficient().leadingExpVector().equals(ev)); } } a = ring.random(kl, ll, el, q); //a = ring.getONE(); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.getONE(); //System.out.println("b = " + b); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // relation table list tests //System.out.println("ring.table.rels = " + ring.table.relationList()); //System.out.println("ring.coeffTable.rels = " + ring.coeffTable.relationList()); RecSolvablePolynomialRing ring2 = new RecSolvablePolynomialRing(ring.coFac, ring); ring2.table.addSolvRelations(ring.table.relationList()); ring2.coeffTable.addSolvRelations(ring.coeffTable.relationList()); //System.out.println("ring2.table.rels = " + ring2.table.relationList()); //System.out.println("ring2.coeffTable.rels = " + ring2.coeffTable.relationList()); assertEquals("ring.table == ring2.table: ", ring.table, ring2.table); assertEquals("ring.coeffTable == ring2.coeffTable: ", ring.coeffTable, ring2.coeffTable); } /** * Test extension and contraction for Weyl relations. */ public void testExtendContractWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); //wlc.generate(csring); csring.addRelations(wlc); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); RecSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.parse("b x + a"); ring.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); int k = rl; RecSolvablePolynomialRing pfe = ring.extend(k); //System.out.println("pfe = " + pfe); RecSolvablePolynomialRing pfec = pfe.contract(k); //System.out.println("pfec = " + pfec); assertEquals("ring == pfec", ring, pfec); RecSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); RecSolvablePolynomial ae = (RecSolvablePolynomial) a.extend(pfe, 0, 0); //System.out.println("ae = " + ae); Map>> m = ae.contract(pfec); List>> ml = new ArrayList>>( m.values()); GenPolynomial> aec = ml.get(0); //System.out.println("ae = " + ae); //System.out.println("aec = " + aec); assertEquals("a == aec", a, aec); } /** * Test distribute and recursion for Weyl relations. */ @SuppressWarnings("unchecked") public void testDistRecWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); csring.addRelations(wlc); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); ring = new RecSolvablePolynomialRing(csring, tord, vars); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); // first distribute solvable polynomial only GenSolvablePolynomialRing fring = (GenSolvablePolynomialRing) ring; GenSolvablePolynomialRing pfd = fring.distribute(); //System.out.println("pfd = " + pfd.toScript()); RecSolvablePolynomialRing pfdr = (RecSolvablePolynomialRing) pfd .recursive(ring.nvar); //System.out.println("pfdr = " + pfdr.toScript()); //System.out.println("ring = " + ring.toScript()); assertEquals("ring == pfdr", ring, pfdr); RecSolvablePolynomial a = ring.random(kl, 2 * ll, el, 2.0f * q); //System.out.println("a = " + a); GenSolvablePolynomial ad = (GenSolvablePolynomial) PolyUtil . distribute(pfd, a); //System.out.println("ad = " + ad); GenSolvablePolynomial> adr = (GenSolvablePolynomial>) PolyUtil . recursive(pfdr, ad); //System.out.println("adr = " + adr); assertEquals("a == adr", a, adr); // now recursive solvable polynials with coefficient relations: RecSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.parse("b x + a"); ring.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); //System.out.println("ring = " + ring.toScript()); GenSolvablePolynomialRing pfrd = RecSolvablePolynomialRing . distribute(ring); //System.out.println("pfrd = " + pfrd.toScript()); RecSolvablePolynomialRing pfrdr = (RecSolvablePolynomialRing) pfrd .recursive(ring.nvar); //System.out.println("pfrdr = " + pfrdr.toScript()); //System.out.println("ring = " + ring.toScript()); assertEquals("ring == pfrdr", ring, pfrdr); //System.out.println("a = " + a); ad = (GenSolvablePolynomial) PolyUtil. distribute(pfrd, a); //System.out.println("ad = " + ad); adr = (GenSolvablePolynomial>) PolyUtil. recursive(pfrdr, ad); //System.out.println("adr = " + adr); assertEquals("a == adr", a, adr); } /** * Test reversion for Weyl relations. */ public void testReverseWeyl() { GenSolvablePolynomialRing csring = new GenSolvablePolynomialRing(cfac, tord, cvars); RelationGenerator wlc = new WeylRelations(); //wlc.generate(csring); csring.addRelations(wlc); assertFalse("isCommutative()", csring.isCommutative()); assertTrue("isAssociative()", csring.isAssociative()); RecSolvablePolynomial r1 = ring.parse("x"); GenSolvablePolynomial r2 = csring.parse("b"); RecSolvablePolynomial rp = ring.parse("b x + a"); ring.coeffTable.update(r1.leadingExpVector(), r2.leadingExpVector(), rp); RecSolvablePolynomialRing pfr = ring.reverse(); RecSolvablePolynomialRing pfrr = pfr.reverse(); assertEquals("pf == pfrr", ring, pfrr); //System.out.println("ring = " + ring); //System.out.println("pfr = " + pfr); RecSolvablePolynomial a = ring.random(kl, ll, el, q); //System.out.println("a = " + a); RecSolvablePolynomial ar = (RecSolvablePolynomial) a.reverse(pfr); RecSolvablePolynomial arr = (RecSolvablePolynomial) ar.reverse(pfrr); assertEquals("a == arr", a, arr); //System.out.println("ar = " + ar); //System.out.println("arr = " + arr); } /** * Test recursive for Weyl relations. */ public void testRecursiveWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelations(sring); //wlc.generate(sring); sring.addRelations(wlc); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = sring.parse("7/2 y^2 * z"); // - 15/2 w^2 + 262/225"); //bd = sring.parse("-10/13 x "); //+ 413/150"); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("cr.ring = " + cr.ring.toScript()); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /** * Test recursive for iterated Weyl relations. */ public void testRecursiveIteratedWeyl() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelationsIterated(); //wlc.generate(sring); sring.addRelations(wlc); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring); //.toScript()); //System.out.println("rsring = " + rsring.toScript()); GenSolvablePolynomial ad, bd, cd, dd; RecSolvablePolynomial ar, br, cr, dr; ad = sring.random(kl, ll, el, q); bd = sring.random(kl, ll, el, q); //ad = (GenSolvablePolynomial) ad.monic(); //bd = (GenSolvablePolynomial) bd.monic(); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); cd = ad.multiply(bd); //System.out.println("cd = " + cd); ar = (RecSolvablePolynomial) PolyUtil. recursive(rsring, ad); br = (RecSolvablePolynomial) PolyUtil. recursive(rsring, bd); //System.out.println("ar = " + ar); //System.out.println("br = " + br); cr = ar.multiply(br); //System.out.println("cr = " + cr); dr = (RecSolvablePolynomial) PolyUtil. recursive(rsring, cd); //System.out.println("dr = " + dr); assertEquals("dr.ring == cr.ring", dr.ring, cr.ring); assertEquals("dr == cr", dr, cr); dd = (GenSolvablePolynomial) PolyUtil. distribute(sring, cr); //System.out.println("dd = " + dd); assertEquals("dd == cd", dd, cd); } /** * Test right recursive representation. */ public void testRightRecursive() { String[] svars = new String[] { "w", "x", "y", "z" }; GenSolvablePolynomialRing sring = new GenSolvablePolynomialRing(cfac, tord, svars); RelationGenerator wlc = new WeylRelations(); //wlc.generate(sring); sring.addRelations(wlc); assertFalse("isCommutative()", sring.isCommutative()); assertTrue("isAssociative()", sring.isAssociative()); //System.out.println("sring = " + sring.toScript()); GenSolvablePolynomialRing> rsring = sring.recursive(2); // 1,2,3 //System.out.println("rsring = " + rsring.toScript()); a = (RecSolvablePolynomial) rsring.random(kl, ll, el, q); //System.out.println("a = " + a); d = (RecSolvablePolynomial) a.rightRecursivePolynomial(); //System.out.println("d = " + d); e = (RecSolvablePolynomial) d.evalAsRightRecursivePolynomial(); //System.out.println("e = " + e); assertEquals("eval(right(a)) == a", a, e); assertTrue("d == isRight(right(a))", a.isRightRecursivePolynomial(d)); GenSolvablePolynomial> ar, dr, er; ar = rsring.random(kl, ll, el, q); //System.out.println("ar = " + ar); dr = ar.rightRecursivePolynomial(); //System.out.println("dr = " + dr); er = dr.evalAsRightRecursivePolynomial(); //System.out.println("er = " + er); assertEquals("eval(right(ar)) == ar", ar, er); assertTrue("dr == isRight(right(ar))", ar.isRightRecursivePolynomial(dr)); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RecSolvableWordPolynomialTest.java000066400000000000000000000313171445075545500274540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; /** * BigRational coefficients RecSolvableWordPolynomial tests with JUnit. * @author Heinz Kredel */ public class RecSolvableWordPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RecSolvableWordPolynomialTest object. * @param name String. */ public RecSolvableWordPolynomialTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RecSolvableWordPolynomialTest.class); return suite; } RecSolvableWordPolynomial a, b, c, d, e, f, x1, x2; int rl = 4; int kl = 5; int ll = 4; int el = 3; float q = 0.3f; String[] cvars = new String[] { "a", "b" }; String[] vars = new String[] { "w", "x", "y", "z" }; RelationTable> table; RecSolvableWordPolynomialRing ring; BigRational cfac; GenSolvablePolynomialRing> sring; GenWordPolynomialRing cring; TermOrder tord = new TermOrder(TermOrder.INVLEX); @Override protected void setUp() { cfac = new BigRational(1); cring = new GenWordPolynomialRing(cfac, cvars); //sring = new GenSolvablePolynomialRing>(cring,rl,tord); ring = new RecSolvableWordPolynomialRing(cring, tord, vars); //System.out.println("ring = " + ring.toScript()); RelationGenerator> wl = new WeylRelations>(); ring.addRelations(wl); table = ring.table; //System.out.println("ring = " + ring.toScript()); a = b = c = d = e = null; } @Override protected void tearDown() { table = null; ring = null; a = b = c = d = e = null; } /** * Test constructor, generators and properties. */ public void testConstructor() { assertFalse("not commutative", ring.isCommutative()); assertTrue("associative", ring.isAssociative()); a = new RecSolvableWordPolynomial(ring); assertTrue("length( a ) = 0", a.length() == 0); assertTrue("isZERO( a )", a.isZERO()); assertTrue("isONE( a )", !a.isONE()); c = ring.getONE(); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = ring.getZERO(); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); //System.out.println("d = " + d); //System.out.println(""); for (GenPolynomial> g : ring.generators()) { //System.out.print("g = " + g + ", "); assertFalse("not isZERO( g )", g.isZERO()); } //System.out.println(""); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { // a = ring.random(ll+2*i); a = ring.random(kl * (i + 1), ll + 2 * i, el + i, q); //System.out.println("a = " + a); assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = ring.random(kl, ll, el, q); c = (RecSolvableWordPolynomial) a.subtract(a); assertTrue("a-a = 0", c.isZERO()); b = (RecSolvableWordPolynomial) a.sum(a); c = (RecSolvableWordPolynomial) b.subtract(a); assertEquals("a+a-a = a", c, a); b = ring.random(kl, ll, el, q); c = (RecSolvableWordPolynomial) b.sum(a); d = (RecSolvableWordPolynomial) a.sum(b); assertEquals("a+b = b+a", c, d); c = ring.random(kl, ll, el, q); d = (RecSolvableWordPolynomial) a.sum(b.sum(c)); e = (RecSolvableWordPolynomial) a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); ExpVector u = ExpVector.random(rl, el, q); GenWordPolynomial x = cring.random(kl); //System.out.println("x = " + x); //System.out.println("u = " + u); b = ring.getONE().multiply(x, u); c = (RecSolvableWordPolynomial) a.sum(b); d = (RecSolvableWordPolynomial) a.sum(x, u); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (RecSolvableWordPolynomial) a.subtract(b); d = (RecSolvableWordPolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); a = ring.getZERO(); b = ring.getONE().multiply(x, u); c = (RecSolvableWordPolynomial) b.sum(a); d = (RecSolvableWordPolynomial) a.sum(x, u); assertEquals("a+p(x,u) = a+(x,u)", c, d); c = (RecSolvableWordPolynomial) a.subtract(b); d = (RecSolvableWordPolynomial) a.subtract(x, u); assertEquals("a-p(x,u) = a-(x,u)", c, d); } /** * Test multiplication. */ public void testMultiplication() { //System.out.println("ring = " + ring); a = ring.random(kl, ll, el, q); //a = ring.parse(" b y z + a w z "); b = ring.random(kl, ll, el, q); //b = ring.parse(" w x - b x "); c = b.multiply(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); c = ring.random(kl, ll, el, q); d = a.multiply(b.multiply(c)); e = a.multiply(b).multiply(c); assertEquals("a(bc) = (ab)c", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); BigRational x = a.leadingBaseCoefficient().leadingBaseCoefficient().inverse(); GenWordPolynomial xp = new GenWordPolynomial(cring, x); d = (RecSolvableWordPolynomial) a.multiply(xp); assertTrue("monic(a) = a*(1/ldcf(ldcf(a)))", d.leadingBaseCoefficient().leadingBaseCoefficient() .isONE()); d = (RecSolvableWordPolynomial) a.monic(); assertTrue("a.monic(): " + d.leadingBaseCoefficient() + ", " + a.leadingBaseCoefficient(), d.leadingBaseCoefficient().isONE() || d.leadingBaseCoefficient().equals(a.leadingBaseCoefficient())); } /** * Test commutative ring. */ public void testCommutative() { //System.out.println("table = " + table.toString(vars)); //System.out.println("table = " + table.toScript()); //System.out.println("ring = " + ring); //System.out.println("ring.table = " + ring.table.toScript()); //assertEquals("table == ring.table: ", table, ring.table); // ? assertTrue("# relations == 2", ring.table.size() == 2); cring = new GenWordPolynomialRing(cfac, new String[] { "a" }); ring = new RecSolvableWordPolynomialRing(cring, ring); //table = ring.table; //System.out.println("table = " + table.toString(vars)); //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); a = ring.random(kl, ll, el, q); //a = ring.parse(" b x y z + a w z "); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.parse(" w y z - b x "); //System.out.println("b = " + b); // commutative c = b.multiply(a); //System.out.println("c = " + c); d = a.multiply(b); //d = ring.getONE(); //System.out.println("d = " + d); assertEquals("ba == ab: ", c, d); } /** * Test distributive law. */ public void testDistributive() { a = ring.random(kl, ll, el, q); b = ring.random(kl, ll, el, q); c = ring.random(kl, ll, el, q); d = a.multiply((RecSolvableWordPolynomial) b.sum(c)); e = (RecSolvableWordPolynomial) a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test word coefficient ring. */ public void testWordCoeffs() { RecSolvableWordPolynomial r1 = ring.parse("x"); GenWordPolynomial r2 = ring.parse("b").leadingBaseCoefficient(); RecSolvableWordPolynomial rp = ring.parse("b x + a"); //System.out.println("r1 = " + r1); //System.out.println("r2 = " + r2); //System.out.println("rp = " + rp); ring.coeffTable.update(r1.leadingExpVector(), r2.leadingWord().leadingExpVector(), rp); //table = ring.table; //System.out.println("ring = " + ring.toScript()); assertFalse("isCommutative()", ring.isCommutative()); assertTrue("isAssociative()", ring.isAssociative()); List>> gens = ring.generators(); for (GenPolynomial> x : gens) { GenSolvablePolynomial> xx = (GenSolvablePolynomial>) x; a = new RecSolvableWordPolynomial(ring, xx); //System.out.println("a = " + a); for (GenPolynomial> y : gens) { GenSolvablePolynomial> yy = (GenSolvablePolynomial>) y; b = new RecSolvableWordPolynomial(ring, yy); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("gens:" + a + " * " + b + " = " + c); ExpVector ev = a.leadingExpVector().sum(b.leadingExpVector()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingExpVector().equals(ev)); Word wv = a.leadingBaseCoefficient().leadingWord() .multiply(b.leadingBaseCoefficient().leadingWord()); assertTrue("LT(a)*LT(b) == LT(c)", c.leadingBaseCoefficient().leadingWord().equals(wv)); } } a = ring.random(kl, ll, el, q); //a = ring.getONE(); //System.out.println("a = " + a); b = ring.random(kl, ll, el, q); //b = ring.getONE(); //System.out.println("b = " + b); // non-commutative c = b.multiply(a); d = a.multiply(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*b != b*a", c.equals(d) || c.leadingExpVector().equals(d.leadingExpVector())); // relation table list tests //System.out.println("ring.table.rels = " + ring.table.relationList()); //System.out.println("ring.coeffTable.rels = " + ring.coeffTable.relationList()); RecSolvableWordPolynomialRing ring2 = new RecSolvableWordPolynomialRing( ring.coFac, ring); ring2.table.addSolvRelations(ring.table.relationList()); ring2.coeffTable.addSolvRelations(ring.coeffTable.relationList()); //System.out.println("ring2.table.rels = " + ring2.table.relationList()); //System.out.println("ring2.coeffTable.rels = " + ring2.coeffTable.relationList()); assertEquals("ring.table == ring2.table: ", ring.table, ring2.table); assertEquals("ring.coeffTable == ring2.coeffTable: ", ring.coeffTable, ring2.coeffTable); } } java-algebra-system-2.7.200/trc/edu/jas/poly/RelationTableTest.java000066400000000000000000000301101445075545500250660ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; /** * RelationTable tests with JUnit. * @author Heinz Kredel */ public class RelationTableTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RelationTableTest object. * @param name String. */ public RelationTableTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RelationTableTest.class); return suite; } RelationTable table; GenSolvablePolynomialRing ring; int rl = 6; @Override protected void setUp() { BigRational cfac = new BigRational(1); ring = new GenSolvablePolynomialRing(cfac, rl); table = ring.table; // non null } @Override protected void tearDown() { table = null; ring = null; } /** * Test constructor and toString. */ public void testConstructor() { table = new RelationTable(ring); assertEquals("size() = 0", 0, table.size()); assertEquals("ring == table.ring", ring, table.ring); String s = "RelationTable[]"; String t = table.toString(); assertEquals("RelationTable[]", s, t); } /** * Test update one key. */ public void testUpdateOneKey() { table = ring.table; assertEquals("size() = 0", 0, table.size()); //ExpVector z = ring.evzero; ExpVector e = ExpVector.create(rl, 2, 1); ExpVector f = ExpVector.create(rl, 3, 1); // insert in empty ExpVector ef = e.sum(f); GenSolvablePolynomial a = ring.getONE(); GenSolvablePolynomial b = ring.getONE().multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 1", 1, table.size()); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 1); // insert in beginning ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 2", 2, table.size()); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 2); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 3", 3, table.size()); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 4); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 4", 4, table.size()); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 3); // insert in middle ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 5", 5, table.size()); //System.out.println("table = " + table); } /** * Test update more keys. */ public void testUpdateKeys() { table = ring.table; assertEquals("size() = 0", 0, table.size()); //ExpVector z = ring.evzero; ExpVector e = ExpVector.create(rl, 2, 1); ExpVector f = ExpVector.create(rl, 3, 1); // insert in empty ExpVector ef = e.sum(f); GenSolvablePolynomial a = ring.getONE(); GenSolvablePolynomial b = ring.getONE().multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 1", 1, table.size()); e = ExpVector.create(rl, 0, 1); f = ExpVector.create(rl, 2, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 2", 2, table.size()); e = ExpVector.create(rl, 2, 1); f = ExpVector.create(rl, 4, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 3", 3, table.size()); //System.out.println("table = " + table); } /** * Test lookup one key. */ public void testLookupOneKey() { table = ring.table; assertEquals("size() = 0", 0, table.size()); //ExpVector z = ring.evzero; ExpVector e = ExpVector.create(rl, 2, 1); ExpVector f = ExpVector.create(rl, 3, 1); // insert in empty ExpVector ef = e.sum(f); GenSolvablePolynomial a = ring.getONE(); GenSolvablePolynomial b = ring.getONE().multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) a.sum(b); GenSolvablePolynomial r1 = rel; table.update(e, f, rel); assertEquals("size() = 1", 1, table.size()); TableRelation r = table.lookup(e, f); //System.out.println("relation = " + r); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 1); // insert in beginning ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 2", 2, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 2); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 3", 3, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 4); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 4", 4, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 2, 2); f = ExpVector.create(rl, 3, 3); // insert in middle ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 5", 5, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); // lookup only e = ExpVector.create(rl, 2, 1); f = ExpVector.create(rl, 3, 1); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", r1, r.p); //System.out.println("table = " + table); } /** * Test lookup keys. */ public void testLookupKeys() { table = ring.table; assertEquals("size() = 0", 0, table.size()); //ExpVector z = ring.evzero; ExpVector e = ExpVector.create(rl, 2, 1); ExpVector f = ExpVector.create(rl, 3, 1); ExpVector ef = e.sum(f); GenSolvablePolynomial a = ring.getONE(); GenSolvablePolynomial b = ring.getONE().multiply(ef); GenSolvablePolynomial rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 1", 1, table.size()); TableRelation r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 0, 1); f = ExpVector.create(rl, 2, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 2", 2, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); e = ExpVector.create(rl, 2, 1); f = ExpVector.create(rl, 4, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); rel = (GenSolvablePolynomial) a.sum(b); table.update(e, f, rel); assertEquals("size() = 3", 3, table.size()); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = p", rel, r.p); //System.out.println("table = " + table); } /** * Test lookup symmetric products. */ public void testSymmetric() { table = ring.table; assertEquals("size() = 0", 0, table.size()); //ExpVector z = ring.evzero; ExpVector e = ExpVector.create(rl, 2, 1); ExpVector f = ExpVector.create(rl, 3, 1); ExpVector ef = e.sum(f); //GenSolvablePolynomial a = ring.getONE(); GenSolvablePolynomial b = ring.getONE().multiply(ef); //GenSolvablePolynomial rel // = (GenSolvablePolynomial)a.add(b); TableRelation r = table.lookup(e, f); //System.out.println("relation = " + r); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = b", b, r.p); e = ExpVector.create(rl, 0, 1); f = ExpVector.create(rl, 2, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = b", b, r.p); e = ExpVector.create(rl, 2, 1); f = ExpVector.create(rl, 4, 1); ef = e.sum(f); b = ring.getONE().multiply(ef); r = table.lookup(e, f); assertEquals("e = e", null, r.e); assertEquals("f = f", null, r.f); assertEquals("p = b", b, r.p); assertEquals("size() = 0", 0, table.size()); //System.out.println("table = " + table); } /** * Test to relation list and back. */ public void testRelationList() { List> rels = table.relationList(); assertEquals("list.size() = 0", 0, rels.size()); table.addSolvRelations(rels); assertEquals("size() = 0", 0, table.size()); RelationGenerator wl = new WeylRelations(); wl.generate(ring); rels = table.relationList(); assertEquals("list.size() = r/2", rl / 2, rels.size() / 3); GenSolvablePolynomialRing ring2; ring2 = new GenSolvablePolynomialRing(ring.coFac, ring); assertEquals("size() = 0", 0, ring2.table.size()); ring2.table.addSolvRelations(rels); //System.out.println("table1 = " + ring.table.toScript()); //System.out.println("table2 = " + ring2.table.toScript()); assertEquals("size() = r/2", rl / 2, ring2.table.size()); assertEquals("rel1 == rel2: ", ring.table, ring2.table); } } java-algebra-system-2.7.200/trc/edu/jas/poly/ResidueTest.java000066400000000000000000000246311445075545500237540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Residue test with JUnit. * @author Heinz Kredel */ public class ResidueTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ResidueTest object. * @param name String. */ public ResidueTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ResidueTest.class); return suite; } ResidueRing fac; GenPolynomialRing pfac; ResidueRing> mfac; Residue a, b, c, d, e; Residue> ap, bp, cp, dp, ep; int rl = 1; int kl = 13; int ll = 7; int el = 3; float q = 0.4f; int il = 2; long p = 1152921504606846883L; // 2^60-93; @Override protected void setUp() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; BigInteger cfac = new BigInteger(1); fac = new ResidueRing(cfac, new BigInteger(p)); pfac = new GenPolynomialRing(new BigRational(1), 1); GenPolynomial mo = pfac.random(kl, ll, el + 2, q); while (mo.isConstant()) { mo = pfac.random(kl, ll, el, q); } mfac = new ResidueRing>(pfac, mo.monic()); //System.out.println("fac = " + fac); //System.out.println("mfac = " + mfac); } @Override protected void tearDown() { a = b = c = d = e = null; ap = bp = cp = dp = ep = null; fac = null; pfac = null; mfac = null; } /** * Test factory for integer. */ public void testIntRing() { assertTrue("#ring infinite", fac.isFinite()); assertTrue("associative ring", fac.isAssociative()); assertTrue("commutative ring", fac.isCommutative()); assertTrue("characteristic p", fac.characteristic().signum() > 0); assertFalse("no field", fac.isField()); } /** * Test factory for polynomial. */ public void testPolyRing() { assertFalse("#ring infinite", mfac.isFinite()); assertTrue("associative ring", mfac.isAssociative()); assertTrue("commutative ring", mfac.isCommutative()); assertTrue("characteristic zero", mfac.characteristic().signum() == 0); assertFalse("no field", mfac.isField()); } /** * Test constructor for integer. */ public void testIntConstruction() { c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); List> gens = fac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 1: ", gens.size() == 1); for (Residue v : gens) { a = fac.parse(v.toString()); assertEquals("a == v", a, v); } } /** * Test constructor for polynomial. */ public void testPolyConstruction() { cp = mfac.getONE(); assertTrue("isZERO( cp )", !cp.isZERO()); assertTrue("isONE( cp )", cp.isONE()); dp = mfac.getZERO(); assertTrue("isZERO( dp )", dp.isZERO()); assertTrue("isONE( dp )", !dp.isONE()); List>> gens = mfac.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 2: ", gens.size() == 2); for (Residue> v : gens) { ap = mfac.parse(v.toString()); assertEquals("ap == v", ap, v); } } /** * Test random integer. */ public void testIntRandom() { for (int i = 0; i < 7; i++) { a = fac.random(kl * (i + 1)); if (a.isZERO()) { continue; } //a = fac.random(kl*(i+1), ll+2*i, el+i, q ); //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test random polynomial. */ public void testPolyRandom() { for (int i = 0; i < 7; i++) { ap = mfac.random(kl + i); if (ap.isZERO()) { continue; } assertTrue(" not isZERO( ap" + i + " )", !ap.isZERO()); assertTrue(" not isONE( ap" + i + " )", !ap.isONE()); } } /** * Test integer addition. */ public void testIntAddition() { a = fac.random(kl); b = fac.random(kl); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(kl); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test polynomial addition. */ public void testPolyAddition() { ap = mfac.random(kl); bp = mfac.random(kl); //System.out.println("a = " + a); //System.out.println("b = " + b); cp = ap.sum(bp); dp = cp.subtract(bp); assertEquals("a+b-b = a", ap, dp); cp = ap.sum(bp); dp = bp.sum(ap); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", cp, dp); cp = mfac.random(kl); dp = cp.sum(ap.sum(bp)); ep = cp.sum(ap).sum(bp); assertEquals("c+(a+b) = (c+a)+b", dp, ep); cp = ap.sum(mfac.getZERO()); dp = ap.subtract(mfac.getZERO()); assertEquals("a+0 = a-0", cp, dp); cp = mfac.getZERO().sum(ap); dp = mfac.getZERO().subtract(ap.negate()); assertEquals("0+a = 0+(-a)", cp, dp); } /** * Test integer multiplication. */ public void testIntMultiplication() { a = fac.random(kl); if (a.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl); if (b.isZERO()) { return; } assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); Residue[] qr; c = b.multiply(a); qr = c.quotientRemainder(a); if (qr[1].isZERO()) { //System.out.println("qr = " + qr[0] + " rem " + qr[1]); assertEquals("b*a / a == b", qr[0], b); assertTrue("b*a rem a == 0", qr[1].isZERO()); } } } /** * Test polynomial multiplication. */ public void testPolyMultiplication() { ap = mfac.random(kl); if (ap.isZERO()) { return; } assertTrue("not isZERO( a )", !ap.isZERO()); bp = mfac.random(kl); if (bp.isZERO()) { return; } assertTrue("not isZERO( b )", !bp.isZERO()); cp = bp.multiply(ap); dp = ap.multiply(bp); assertTrue("not isZERO( c )", !cp.isZERO()); assertTrue("not isZERO( d )", !dp.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); ep = dp.subtract(cp); assertTrue("isZERO( a*b-b*a ) " + ep, ep.isZERO()); assertTrue("a*b = b*a", cp.equals(dp)); assertEquals("a*b = b*a", cp, dp); cp = mfac.random(kl); //System.out.println("c = " + c); dp = ap.multiply(bp.multiply(cp)); ep = (ap.multiply(bp)).multiply(cp); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", dp, ep); assertTrue("a(bc) = (ab)c", dp.equals(ep)); cp = ap.multiply(mfac.getONE()); dp = mfac.getONE().multiply(ap); assertEquals("a*1 = 1*a", cp, dp); if (ap.isUnit()) { cp = ap.inverse(); dp = cp.multiply(ap); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", dp.isONE()); Residue>[] qr; cp = bp.multiply(ap); qr = cp.quotientRemainder(ap); if (qr[1].isZERO()) { //System.out.println("qr = " + qr[0] + " rem " + qr[1]); assertEquals("b*a / a == b", qr[0], bp); assertTrue("b*a rem a == 0", qr[1].isZERO()); } } } } java-algebra-system-2.7.200/trc/edu/jas/poly/SolvableModuleListTest.java000066400000000000000000000237321445075545500261260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.List; import java.util.ArrayList; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.jas.structure.RingElem; import edu.jas.arith.BigRational; //import edu.jas.poly.GenPolynomialRing; /** * SolvableModuleList tests using JUnit. * @author Heinz Kredel */ public class SolvableModuleListTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a SolvableModuleListTest object. * @param name String. */ public SolvableModuleListTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(SolvableModuleListTest.class); return suite; } //private final static int bitlen = 100; ModuleList m; PolynomialList p; GenSolvablePolynomial a; GenSolvablePolynomial b; GenSolvablePolynomial c; GenSolvablePolynomial d; GenSolvablePolynomial e; BigRational cfac; GenSolvablePolynomialRing pfac; int rl = 4; int kl = 4; int ll = 4; int el = 5; float q = 0.5f; protected void setUp() { a = b = c = d = e = null; cfac = new BigRational(1); TermOrder tord = new TermOrder(); pfac = new GenSolvablePolynomialRing(cfac,rl,tord); m = null; p = null; } protected void tearDown() { a = b = c = d = e = null; m = null; p = null; } /** * Test constructor and toString. * */ public void testConstructor() { p = new PolynomialList(pfac,(List>)null); assertTrue("p = 0", p.list == null); m = new ModuleList(pfac,(List>>)null); assertTrue("m = 0", m.list == null); } /** * Test polynomial list. * */ public void testPolynomialList() { List> l = new ArrayList>(); for (int i = 0; i < 7; i++) { a = pfac.random(kl, ll+i, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); l.add( a ); } p = new PolynomialList(pfac,l); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p) ); assertEquals("p.length", 7, p.list.size() ); } /** * Test module list. * */ public void testModuleList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for ( int j = 0; j < 3; j++ ) { a = pfac.random(kl, ll, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); r.add( a ); } l.add( r ); } m = new ModuleList(pfac,l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m) ); assertEquals("m.length", 4, m.list.size() ); } /** * Test module and polynomial list. * */ public void testModulePolynomialList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for ( int j = 0; j < 3; j++ ) { a = pfac.random(kl, ll, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); r.add( a ); } l.add( r ); } m = new ModuleList(pfac,l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m) ); assertEquals("m.length", 4, m.list.size() ); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p) ); assertEquals("p.length", 4, p.list.size() ); } /** * Test module and polynomial and module list. * */ public void testModulePolynomialModuleList() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for ( int j = 0; j < 3; j++ ) { a = pfac.random(kl, ll, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); r.add( a ); } l.add( r ); } m = new ModuleList(pfac,l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m) ); assertEquals("m.length", 4, m.list.size() ); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p) ); assertEquals("p.length", 4, p.list.size() ); ModuleList m2 = null; m2 = p.getModuleList( 3 ); //System.out.println("m2 = "+m2); assertTrue("m2 == m2", m2.equals(m2) ); assertEquals("m2.length", 4, m2.list.size() ); assertTrue("m == m2", m.equals(m2) ); } /** * Test module and polynomial and module and polynomial list. * */ public void testModulePolynomialModuleListPolynomial() { List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for ( int j = 0; j < 3; j++ ) { a = pfac.random(kl, ll, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); r.add( a ); } l.add( r ); } m = new ModuleList(pfac,l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m) ); assertEquals("m.length", 4, m.list.size() ); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p) ); assertEquals("p.length", 4, p.list.size() ); ModuleList m2 = null; m2 = p.getModuleList( 3 ); //System.out.println("m2 = "+m2); assertTrue("m2 == m2", m2.equals(m2) ); assertEquals("m2.length", 4, m2.list.size() ); assertTrue("m == m2", m.equals(m2) ); PolynomialList p2 = null; p2 = m2.getPolynomialList(); //System.out.println("p2 = "+p2); assertTrue("p2 == p2", p2.equals(p2) ); assertEquals("p2.length", 4, p2.list.size() ); assertTrue("p == p2", p.list.equals(p2.list) ); } /** * Test module and polynomial and module and polynomial list * with WeylRelations. * */ public void testWeylModulePolynomialModuleListPolynomial() { int rloc = 4; pfac = new GenSolvablePolynomialRing(cfac,rloc); RelationGenerator wl = new WeylRelations(); wl.generate(pfac); RelationTable table1 = pfac.table; RelationTable table2 = null; RelationTable table3 = null; RelationTable table4 = null; RelationTable table5 = null; //System.out.println("table 1 = " + table1); //System.out.println("ring = " + ring); List>> l = new ArrayList>>(); for (int i = 0; i < 4; i++) { List> r = new ArrayList>(); for ( int j = 0; j < 3; j++ ) { a = pfac.random(kl, ll, el, q ); assertTrue("length( a"+i+" ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a"+i+" )", !a.isZERO() ); assertTrue(" not isONE( a"+i+" )", !a.isONE() ); r.add( a ); } l.add( r ); } m = new ModuleList(pfac,l); //System.out.println("m = "+m); assertTrue("m == m", m.equals(m) ); assertEquals("m.length", 4, m.list.size() ); table2 = ((GenSolvablePolynomialRing)m.ring).table; //System.out.println("table 2 = " + table2); assertEquals("table1 == table2", table1, table2 ); p = m.getPolynomialList(); //System.out.println("p = "+p); assertTrue("p == p", p.equals(p) ); assertEquals("p.length", 4, p.list.size() ); table3 = ((GenSolvablePolynomialRing)p.ring).table; //System.out.println("table 3 = " + table3); ModuleList m2 = null; m2 = p.getModuleList( 3 ); //System.out.println("m2 = "+m2); assertTrue("m2 == m2", m2.equals(m2) ); assertEquals("m2.length", 4, m2.list.size() ); assertTrue("m == m2", m.equals(m2) ); table4 = ((GenSolvablePolynomialRing)m2.ring).table; //System.out.println("table 4 = " + table4); assertEquals("table2 == table4", table2, table4 ); assertEquals("table1 == table4", table1, table4 ); PolynomialList p2 = null; p2 = m2.getPolynomialList(); //System.out.println("p2 = "+p2); assertTrue("p2 == p2", p2.equals(p2) ); assertEquals("p2.length", 4, p2.list.size() ); assertTrue("p == p2", p.list.equals(p2.list) ); table5 = ((GenSolvablePolynomialRing)p2.ring).table; //System.out.println("table 5= " + table5); assertEquals("table2 == table4", table3.table, table5.table ); } } java-algebra-system-2.7.200/trc/edu/jas/poly/TermOrderByNameCompatTest.java000066400000000000000000000167341445075545500265240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import edu.jas.arith.BigInteger; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TermOrderByName compatibility tests with JUnit. Tests different TermOrders. * @author Axel Kramer */ public class TermOrderByNameCompatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a TermOrderByNameCompatTest object. * @param name String. */ public TermOrderByNameCompatTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(TermOrderByNameCompatTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test order Lexicographic. */ public void testTermOrderLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.Lexicographic, v); // test order Lexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // -10*x^5*y^4*z^2,7*x^2*y^5*z^3,-10*x^2*y*z^5,-7*x*y^5*z^4,6*x*y^4*z^3,6*x*y^3*z^3,3*x*y^2*z,y^4*z,-7*y^2*z,2*z^5 assertEquals("( -10 ) x^5 * y^4 * z^2 + 7 x^2 * y^5 * z^3 - 10 x^2 * y * z^5 - 7 x * y^5 * z^4 + 6 x * y^4 * z^3 + 6 x * y^3 * z^3 + 3 x * y^2 * z + y^4 * z - 7 y^2 * z + 2 z^5", p.toString()); } /** * Test order NegativeLexicographic. */ public void testTermOrderNegativeLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.NegativeLexicographic, v); // test order NegativeLexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // 2*z^5,-7*y^2*z,y^4*z,3*x*y^2*z,6*x*y^3*z^3,6*x*y^4*z^3,-7*x*y^5*z^4,-10*x^2*y*z^5,7*x^2*y^5*z^3,-10*x^5*y^4*z^2 assertEquals("2 z^5 - 7 y^2 * z + y^4 * z + 3 x * y^2 * z + 6 x * y^3 * z^3 + 6 x * y^4 * z^3 - 7 x * y^5 * z^4 - 10 x^2 * y * z^5 + 7 x^2 * y^5 * z^3 - 10 x^5 * y^4 * z^2", p.toString()); } /** * Test order DegreeLexicographic. */ public void testTermOrderDegreeLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.DegreeLexicographic, v); // test order DegreeLexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // -10*x^5*y^4*z^2,7*x^2*y^5*z^3,-7*x*y^5*z^4,-10*x^2*y*z^5,6*x*y^4*z^3,6*x*y^3*z^3,y^4*z,2*z^5,3*x*y^2*z,-7*y^2*z assertEquals("( -10 ) x^5 * y^4 * z^2 + 7 x^2 * y^5 * z^3 - 7 x * y^5 * z^4 - 10 x^2 * y * z^5 + 6 x * y^4 * z^3 + 6 x * y^3 * z^3 + y^4 * z + 2 z^5 + 3 x * y^2 * z - 7 y^2 * z", p.toString()); } public void testTermOrderNegativeDegreeReverseLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.NegativeDegreeReverseLexicographic, v); // test order NegativeDegreeReverseLexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // -7*y^2*z,3*x*y^2*z,y^4*z,2*z^5,6*x*y^3*z^3,6*x*y^4*z^3,-10*x^2*y*z^5,7*x^2*y^5*z^3,-7*x*y^5*z^4,-10*x^5*y^4*z^2 assertEquals("( -7 ) y^2 * z + 3 x * y^2 * z + y^4 * z + 2 z^5 + 6 x * y^3 * z^3 + 6 x * y^4 * z^3 - 10 x^2 * y * z^5 + 7 x^2 * y^5 * z^3 - 7 x * y^5 * z^4 - 10 x^5 * y^4 * z^2", p.toString()); } /** * Test order DegreeReverseLexicographic. */ public void testTermOrderDegreeReverseLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.DegreeReverseLexicographic, v); //System.out.println("pf = " + pf); // test order DegreeReverseLexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // -10*x^5*y^4*z^2,7*x^2*y^5*z^3,-7*x*y^5*z^4,6*x*y^4*z^3,-10*x^2*y*z^5,6*x*y^3*z^3,y^4*z,2*z^5,3*x*y^2*z,-7*y^2*z //degrees 11, 10, 10, 8, 8, 7, 5, 5, 4, 3 assertEquals("( -10 ) x^5 * y^4 * z^2 + 7 x^2 * y^5 * z^3 - 7 x * y^5 * z^4 + 6 x * y^4 * z^3 - 10 x^2 * y * z^5 + 6 x * y^3 * z^3 + y^4 * z + 2 z^5 + 3 x * y^2 * z - 7 y^2 * z", p.toString()); } /** * Test order NegativeDegreeLexicographic. */ public void testTermOrderNegativeDegreeLexicographic() { // integers BigInteger rf = new BigInteger(); String[] v = new String[] { "x", "y", "z" }; String testPolynomial = "-10*x^5*y^4*z^2 + 7*x^2*y^5*z^3 - 10*x^2*y*z^5 - 7*x*y^5*z^4 + 6*x*y^4*z^3 + 6*x*y^3*z^3 + 3*x*y^2*z + y^4*z - 7*y^2*z + 2*z^5"; // polynomials over integral numbers GenPolynomialRing pf = new GenPolynomialRing(rf, TermOrderByName.NegativeDegreeLexicographic, v); //System.out.println("pf = " + pf); // test order NegativeDegreeLexicographic of polynomial: GenPolynomial p = pf.parse(testPolynomial); // -7*y^2*z,3*x*y^2*z,y^4*z,2*z^5,6*x*y^3*z^3,-10*x^2*y*z^5,6*x*y^4*z^3,7*x^2*y^5*z^3,-7*x*y^5*z^4,-10*x^5*y^4*z^2 //degrees 3, 4, 5, 5, 7, 8, 8, 10 10, 11 assertEquals("( -7 ) y^2 * z + 3 x * y^2 * z + y^4 * z + 2 z^5 + 6 x * y^3 * z^3 - 10 x^2 * y * z^5 + 6 x * y^4 * z^3 + 7 x^2 * y^5 * z^3 - 7 x * y^5 * z^4 - 10 x^5 * y^4 * z^2", p.toString()); } } java-algebra-system-2.7.200/trc/edu/jas/poly/TermOrderByNameTest.java000066400000000000000000000357531445075545500253620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TermOrderByName tests with JUnit. Tests different names for TermOrders. * @author Heinz Kredel */ public class TermOrderByNameTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a TermOrderByNameTest object. * @param name String. */ public TermOrderByNameTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(TermOrderByNameTest.class); return suite; } ExpVector a, b, c, d; TermOrder t, s; @Override protected void setUp() { a = b = c = d = null; t = s = null; } @Override protected void tearDown() { a = b = c = d = null; t = s = null; } /** * Test constructor and toString. */ public void testConstructor() { s = TermOrderByName.DEFAULT; t = TermOrderByName.DEFAULT; assertEquals("t = s", t, s); String x = t.toString(); String y = s.toString(); assertEquals("x = y", x, y); t = TermOrderByName.Lexicographic; x = "REVILEX"; y = t.toString(); boolean z = y.startsWith(x); assertTrue("REVILEX(.): " + y, z); s = TermOrderByName.DegreeLexicographic; t = TermOrderByName.DegreeLexicographic; assertEquals("t = s", t, s); } /* * Test constructor, split TO. */ public void testConstructorSplit() { int r = 10; int sp = 5; ExpVector ev = ExpVectorLong.create(r); s = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.DegreeLexicographic, ev, sp); t = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.DegreeLexicographic, ev, sp); assertEquals("t = s", t, s); String x = t.toString(); String y = s.toString(); assertEquals("x = y", x, y); //System.out.println("s = " + s); s = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.Lexicographic, ev, sp); t = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.Lexicographic, ev, sp); assertEquals("t = s", t, s); //System.out.println("s = " + s); } /** * Test constructor weight and toString. */ public void testConstructorWeight() { long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; s = TermOrderByName.weightOrder(w); t = TermOrderByName.weightOrder(w); //System.out.println("s = " + s); //System.out.println("t = " + t); assertEquals("t = s", t, s); String x = t.toString(); String y = s.toString(); //System.out.println("x = " + x); //System.out.println("y = " + y); assertEquals("x = y", x, y); //int r = 5; //int sp = 3; //w = new long [][] { new long[] { 5l, 4l, 3l, 2l, 1l } }; //s = new TermOrder(w,sp); //t = new TermOrder(w,sp); //assertEquals("t = s",t,s); //x = t.toString(); //y = s.toString(); //assertEquals("x = y",x,y); //System.out.println("s = " + s); x = "W("; boolean z = t.toString().startsWith(x); assertTrue("W(.)", z); } /** * Test compare weight. */ public void testCompareWeight() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; t = TermOrderByName.weightOrder(w); int x = ExpVector.EVIWLC(w, c, a); int y = ExpVector.EVIWLC(w, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, a, c); y = ExpVector.EVIWLC(w, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, a); y = ExpVector.EVIWLC(w, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test compare weight 2 rows. */ public void testCompareWeight2() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l }, new long[] { 1l, 1l, 1l, 1l, 1l } }; t = TermOrderByName.weightOrder(w); int x = ExpVector.EVIWLC(w, c, a); int y = ExpVector.EVIWLC(w, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, a, c); y = ExpVector.EVIWLC(w, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, a); y = ExpVector.EVIWLC(w, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators. */ public void testAscendComparator() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); t = TermOrderByName.DegreeLexicographic; int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators split. */ public void testAscendComparatorSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); t = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.Lexicographic, c, sp); int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators weight and split. */ public void testAscendComparatorWeightSplit() { float q = (float) 0.9; int r = 8; //int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); //long [][] w = new long [][] { new long[] { 1l, 2l, 3l, 4l, 5l, 1l, 2l, 3l } }; long[][] w2 = new long[][] { new long[] { 1l, 2l, 3l, 4l, 5l, 0l, 0l, 0l }, new long[] { 0l, 0l, 0l, 0l, 0l, 1l, 2l, 3l } }; // t = new TermOrder(w,sp); t = TermOrderByName.weightOrder(w2); TermOrder t2 = TermOrderByName.weightOrder(w2); assertEquals("t = t2", t, t2); int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); int x2 = t2.getAscendComparator().compare(c, a); int y2 = t2.getAscendComparator().compare(c, b); assertEquals("x2 = 1", 1, x2); assertEquals("y2 = 1", 1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x2 = t2.getAscendComparator().compare(a, c); y2 = t2.getAscendComparator().compare(b, c); assertEquals("x2 = -1", -1, x2); assertEquals("y2 = -1", -1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x2 = t2.getAscendComparator().compare(a, a); y2 = t2.getAscendComparator().compare(b, b); assertEquals("x2 = 0", 0, x2); assertEquals("y2 = 0", 0, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); } /** * Test descend comparators. */ public void testDescendComparator() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); t = TermOrderByName.DegreeLexicographic; int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test descend comparators split. */ public void testDescendComparatorSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); t = TermOrderByName.blockOrder(TermOrderByName.DegreeLexicographic, TermOrderByName.Lexicographic, c, sp); int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test descend comparators weight and split. */ public void testDescendComparatorWeightSplit() { float q = (float) 0.9; int r = 8; //int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); //long [][] w = new long [][] { new long[] { 1l, 2l, 3l, 4l, 5l, 1l, 2l, 3l } }; long[][] w2 = new long[][] { new long[] { 1l, 2l, 3l, 4l, 5l, 0l, 0l, 0l }, new long[] { 0l, 0l, 0l, 0l, 0l, 1l, 2l, 3l } }; //t = new TermOrder(w,sp); t = TermOrderByName.weightOrder(w2); TermOrder t2 = TermOrderByName.weightOrder(w2); assertEquals("t = t2", t, t2); int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); int x2 = t2.getDescendComparator().compare(c, a); int y2 = t2.getDescendComparator().compare(c, b); assertEquals("x2 = -1", -1, x2); assertEquals("y2 = -1", -1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x2 = t2.getDescendComparator().compare(a, c); y2 = t2.getDescendComparator().compare(b, c); assertEquals("x2 = 1", 1, x2); assertEquals("y2 = 1", 1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x2 = t2.getDescendComparator().compare(a, a); y2 = t2.getDescendComparator().compare(b, b); assertEquals("x2 = 0", 0, x2); assertEquals("y2 = 0", 0, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); } /** * Test compare exception split. */ public void testCompareExceptionSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = ExpVector.random(2, 10, q); TermOrder t2 = TermOrderByName.REVITDG; int x = 0; try { t = TermOrderByName.blockOrder(t2, t2, c, sp); x = t.getDescendComparator().compare(a, b); fail("IllegalArgumentException " + x); } catch (IllegalArgumentException e) { //return; } catch (NullPointerException e) { //return; } } /** * Test compare exception weight. */ public void testCompareExceptionWeigth() { float q = (float) 0.9; int r = 10; a = ExpVector.random(r, 10, q); b = ExpVector.random(2, 10, q); int x = 0; try { t = TermOrderByName.weightOrder((long[][]) null); x = t.getDescendComparator().compare(a, b); fail("IllegalArgumentException " + x); } catch (IllegalArgumentException e) { //return; } catch (NullPointerException e) { //return; } catch (ArrayIndexOutOfBoundsException e) { //return; } } /** * Test weight for order. */ public void testWeigthForOrder() { int r = 10; long[][] w; w = TermOrderByName.weightForOrder(TermOrderByName.INVLEX, r); //System.out.println("w = " + Arrays.toString(w[0])); assertEquals("w[0][0] = 1", w[0][0], 1L); assertEquals("w[0][r-1] = 1", w[0][r - 1], 0L); w = TermOrderByName.weightForOrder(TermOrderByName.IGRLEX, r); //System.out.println("w = " + Arrays.toString(w[0])); assertEquals("w[0][0] = 1", w[0][0], 1L); assertEquals("w[0][r-1] = 1", w[0][r - 1], 1L); w = TermOrderByName.weightForOrder(TermOrderByName.REVILEX, r); //System.out.println("w = " + Arrays.toString(w[0])); assertEquals("w[0][r-1] = 1", w[0][r - 1], 1L); assertEquals("w[0][0] = 0", w[0][0], 0L); } } java-algebra-system-2.7.200/trc/edu/jas/poly/TermOrderOptimizationTest.java000066400000000000000000000134161445075545500266650ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TermOrderOptimization tests with JUnit. * @author Heinz Kredel */ public class TermOrderOptimizationTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a TermOrderOptimizationTest object. * @param name String. */ public TermOrderOptimizationTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(TermOrderOptimizationTest.class); return suite; } int rl = 7; int kl = 3; int ll = 10; int el = 7; float q = 0.5f; GenPolynomialRing fac; GenPolynomial a, b, c, d, e; GenPolynomialRing> rfac; GenPolynomial> ar, br, cr, dr, er; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test permutations. */ public void testPermutation() { List P = new ArrayList(); P.add(2); P.add(1); P.add(4); P.add(0); P.add(3); //System.out.println("P = " + P); List S = TermOrderOptimization.inversePermutation(P); //System.out.println("S = " + S); assertFalse("P != id", TermOrderOptimization.isIdentityPermutation(P)); assertFalse("S != id", TermOrderOptimization.isIdentityPermutation(S)); List T = TermOrderOptimization.multiplyPermutation(P, S); //System.out.println("T = " + T); List U = TermOrderOptimization.multiplyPermutation(S, P); //System.out.println("U = " + U); assertTrue("T == id", TermOrderOptimization.isIdentityPermutation(T)); assertTrue("U == id", TermOrderOptimization.isIdentityPermutation(U)); } /** * Test polynomial optimization. */ public void testPolyOptimization() { BigRational cf = new BigRational(); fac = new GenPolynomialRing(cf, rl); //System.out.println("fac = " + fac); a = fac.random(kl, ll, el, q); b = fac.random(kl, ll, el, q); c = fac.random(kl, ll, el, q); d = fac.random(kl, ll, el, q); e = fac.random(kl, ll, el, q); List> F = new ArrayList>(); F.add(a); F.add(b); F.add(c); F.add(d); F.add(e); //System.out.println("F = " + F); long t = F.toString().length(); OptimizedPolynomialList Fo, Fo2; Fo = TermOrderOptimization. optimizeTermOrder(fac, F); //System.out.println("Fo = " + Fo.perm); Fo2 = TermOrderOptimization. optimizeTermOrder(Fo.ring, Fo.list); //System.out.println("Fo2 = " + Fo2.perm); assertEquals("Fo == Fo2: ", Fo, Fo2); List S = TermOrderOptimization.inversePermutation(Fo.perm); GenPolynomialRing faci = Fo.ring.permutation(S); //System.out.println("faci = " + faci); List> Fi = TermOrderOptimization.permutation(S, faci, Fo.list); //System.out.println("Fi = " + Fi); //System.out.println("Fi = " + Fi); assertEquals("r == ri: ", fac, faci); assertEquals("F == Fi: ", F, Fi); String s = Fo.toString(); //System.out.println("t = " + t + ", #ss = " + s.length()); assertTrue("#s >= t: " + s, s.length() >= t); } /** * Test polynomial coefficients optimization. */ public void testPolyCoefOptimization() { BigRational cf = new BigRational(); fac = new GenPolynomialRing(cf, rl); //System.out.println("fac = " + fac); rfac = new GenPolynomialRing>(fac, 3); //System.out.println("rfac = " + rfac); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); dr = rfac.random(kl, ll, el, q); er = rfac.random(kl, ll, el, q); List>> F = new ArrayList>>(); F.add(ar); F.add(br); F.add(cr); F.add(dr); F.add(er); //System.out.println("F = " + F); OptimizedPolynomialList> Fo, Fo2; Fo = TermOrderOptimization. optimizeTermOrderOnCoefficients(rfac, F); //System.out.println("Fo = " + Fo.perm); Fo2 = TermOrderOptimization. optimizeTermOrderOnCoefficients(Fo.ring, Fo.list); //System.out.println("Fo2 = " + Fo2.perm); assertEquals("Fo == Fo2: ", Fo, Fo2); List S = TermOrderOptimization.inversePermutation(Fo.perm); GenPolynomialRing cof = (GenPolynomialRing) Fo.ring.coFac; cof = cof.permutation(S); GenPolynomialRing> faci = new GenPolynomialRing>( cof, rfac); //System.out.println("faci = " + faci); List>> Fi = TermOrderOptimization .permutationOnCoefficients(S, faci, Fo.list); //System.out.println("Fi = " + Fi); //System.out.println("Fi = " + Fi); assertEquals("r == ri: ", rfac, faci); assertEquals("F == Fi: ", F, Fi); } } java-algebra-system-2.7.200/trc/edu/jas/poly/TermOrderTest.java000066400000000000000000000445041445075545500242600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TermOrder tests with JUnit. Tests also ExpVector comparisons. * @author Heinz Kredel */ public class TermOrderTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a TermOrderTest object. * @param name String. */ public TermOrderTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(TermOrderTest.class); return suite; } ExpVector a, b, c, d; TermOrder t, s; @Override protected void setUp() { a = b = c = d = null; t = s = null; } @Override protected void tearDown() { a = b = c = d = null; t = s = null; } /** * Test constructor and toString. */ public void testConstructor() { s = new TermOrder(); t = new TermOrder(); assertEquals("t = s", t, s); String x = t.toString(); String y = s.toString(); assertEquals("x = y", x, y); t = new TermOrder(TermOrder.INVLEX); x = "INVLEX"; boolean z = t.toString().startsWith(x); assertTrue("INVLEX(.)", z); s = new TermOrder(TermOrder.IGRLEX); t = new TermOrder(TermOrder.IGRLEX); assertEquals("t = s", t, s); } /** * Test constructor, split TO. */ public void testConstructorSplit() { int r = 10; int sp = 5; s = new TermOrder(TermOrder.IGRLEX, TermOrder.IGRLEX, r, sp); t = new TermOrder(TermOrder.IGRLEX, TermOrder.IGRLEX, r, sp); assertEquals("t == s", t, s); String x = t.toString(); String y = s.toString(); assertEquals("x == y", x, y); //System.out.println("s = " + s); s = new TermOrder(TermOrder.IGRLEX, TermOrder.INVLEX, r, sp); t = new TermOrder(TermOrder.IGRLEX, TermOrder.INVLEX, r, sp); assertEquals("t == s", t, s); //System.out.println("s = " + s); s = new TermOrder(TermOrder.INVLEX, TermOrder.IGRLEX, r, sp, true); t = new TermOrder(TermOrder.INVLEX, TermOrder.IGRLEX, r, sp, true); assertEquals("t == s", t, s); //System.out.println("s = " + s); } /** * Test constructor weight and toString. */ public void testConstructorWeight() { long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; s = new TermOrder(w); t = new TermOrder(w); assertEquals("t = s", t, s); String x = t.toString(); String y = s.toString(); assertEquals("x = y", x, y); //System.out.println("s = " + s); //int r = 5; //int sp = 3; //w = new long [][] { new long[] { 5l, 4l, 3l, 2l, 1l } }; //s = new TermOrder(w,sp); //t = new TermOrder(w,sp); //assertEquals("t = s",t,s); //x = t.toString(); //y = s.toString(); //assertEquals("x = y",x,y); //System.out.println("s = " + s); x = "W("; boolean z = t.toString().startsWith(x); assertTrue("W(.)", z); } /** * Test compare weight. */ public void testCompareWeight() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l } }; t = new TermOrder(w); int x = ExpVector.EVIWLC(w, c, a); int y = ExpVector.EVIWLC(w, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, a, c); y = ExpVector.EVIWLC(w, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, a); y = ExpVector.EVIWLC(w, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test compare weight 2 rows. */ public void testCompareWeight2() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l }, new long[] { 1l, 1l, 1l, 1l, 1l } }; t = new TermOrder(w); int x = ExpVector.EVIWLC(w, c, a); int y = ExpVector.EVIWLC(w, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, a, c); y = ExpVector.EVIWLC(w, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, a); y = ExpVector.EVIWLC(w, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test compare weight split. */ public void testCompareWeightSplit() { float q = (float) 0.9; int r = 8; int sp = 4; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); long[][] w = new long[][] { new long[] { 1l, 1l, 1l, 1l, 1l, 1l, 1l, 1l } }; //t = new TermOrder(w,sp); int x; int y; x = ExpVector.EVIWLC(w, c, a); y = ExpVector.EVIWLC(w, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, c, a, 0, sp); y = ExpVector.EVIWLC(w, c, b, 0, sp); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, c, a, sp, r); y = ExpVector.EVIWLC(w, c, b, sp, r); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w, a, c); y = ExpVector.EVIWLC(w, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, c, 0, sp); y = ExpVector.EVIWLC(w, b, c, 0, sp); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, c, sp, r); y = ExpVector.EVIWLC(w, b, c, sp, r); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w, a, a); y = ExpVector.EVIWLC(w, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x = ExpVector.EVIWLC(w, a, a, 0, sp); y = ExpVector.EVIWLC(w, b, b, 0, sp); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x = ExpVector.EVIWLC(w, a, a, sp, r); y = ExpVector.EVIWLC(w, b, b, sp, r); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); long[][] w2 = new long[][] { new long[] { 1l, 1l, 1l, 1l, 0l, 0l, 0l, 0l }, new long[] { 0l, 0l, 0l, 0l, 1l, 1l, 1l, 1l } }; //t = new TermOrder(w2); x = ExpVector.EVIWLC(w2, c, a); y = ExpVector.EVIWLC(w2, c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w2, c, a, 0, sp); y = ExpVector.EVIWLC(w2, c, b, 0, sp); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w2, c, a, sp, r); y = ExpVector.EVIWLC(w2, c, b, sp, r); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = ExpVector.EVIWLC(w2, a, c); y = ExpVector.EVIWLC(w2, b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w2, a, c, 0, sp); y = ExpVector.EVIWLC(w2, b, c, 0, sp); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w2, a, c, sp, r); y = ExpVector.EVIWLC(w2, b, c, sp, r); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = ExpVector.EVIWLC(w2, a, a); y = ExpVector.EVIWLC(w2, b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x = ExpVector.EVIWLC(w2, a, a, 0, sp); y = ExpVector.EVIWLC(w2, b, b, 0, sp); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x = ExpVector.EVIWLC(w2, a, a, sp, r); y = ExpVector.EVIWLC(w2, b, b, sp, r); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators. */ public void testAscendComparator() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); t = new TermOrder(); int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators split. */ public void testAscendComparatorSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); t = new TermOrder(TermOrder.IGRLEX, TermOrder.INVLEX, r, sp); int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test ascend comparators weight and split. */ public void testAscendComparatorWeightSplit() { float q = (float) 0.9; int r = 8; //int sp = 5; //long [][] w = new long [][] { new long[] { 1l, 2l, 3l, 4l, 5l, 1l, 2l, 3l } }; long[][] w2 = new long[][] { new long[] { 1l, 2l, 3l, 4l, 5l, 0l, 0l, 0l }, new long[] { 0l, 0l, 0l, 0l, 0l, 1l, 2l, 3l } }; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); // t = new TermOrder(w,sp); t = new TermOrder(w2); TermOrder t2 = new TermOrder(w2); // now t equals t2 int x = t.getAscendComparator().compare(c, a); int y = t.getAscendComparator().compare(c, b); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); int x2 = t2.getAscendComparator().compare(c, a); int y2 = t2.getAscendComparator().compare(c, b); assertEquals("x2 = 1", 1, x2); assertEquals("y2 = 1", 1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getAscendComparator().compare(a, c); y = t.getAscendComparator().compare(b, c); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x2 = t2.getAscendComparator().compare(a, c); y2 = t2.getAscendComparator().compare(b, c); assertEquals("x2 = -1", -1, x2); assertEquals("y2 = -1", -1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getAscendComparator().compare(a, a); y = t.getAscendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x2 = t2.getAscendComparator().compare(a, a); y2 = t2.getAscendComparator().compare(b, b); assertEquals("x2 = 0", 0, x2); assertEquals("y2 = 0", 0, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); } /** * Test descend comparators. */ public void testDescendComparator() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); c = a.sum(b); t = new TermOrder(); int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test descend comparators split. */ public void testDescendComparatorSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); t = new TermOrder(TermOrder.IGRLEX, TermOrder.INVLEX, r, sp); int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); } /** * Test descend comparators weight and split. */ public void testDescendComparatorWeightSplit() { float q = (float) 0.9; int r = 8; //int sp = 5; //long [][] w = new long [][] { new long[] { 1l, 2l, 3l, 4l, 5l, 1l, 2l, 3l } }; long[][] w2 = new long[][] { new long[] { 1l, 2l, 3l, 4l, 5l, 0l, 0l, 0l }, new long[] { 0l, 0l, 0l, 0l, 0l, 1l, 2l, 3l } }; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); c = a.sum(b); //t = new TermOrder(w,sp); t = new TermOrder(w2); TermOrder t2 = new TermOrder(w2); // now t equals t2 int x = t.getDescendComparator().compare(c, a); int y = t.getDescendComparator().compare(c, b); assertEquals("x = -1", -1, x); assertEquals("y = -1", -1, y); int x2 = t2.getDescendComparator().compare(c, a); int y2 = t2.getDescendComparator().compare(c, b); assertEquals("x2 = -1", -1, x2); assertEquals("y2 = -1", -1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getDescendComparator().compare(a, c); y = t.getDescendComparator().compare(b, c); assertEquals("x = 1", 1, x); assertEquals("y = 1", 1, y); x2 = t2.getDescendComparator().compare(a, c); y2 = t2.getDescendComparator().compare(b, c); assertEquals("x2 = 1", 1, x2); assertEquals("y2 = 1", 1, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); x = t.getDescendComparator().compare(a, a); y = t.getDescendComparator().compare(b, b); assertEquals("x = 0", 0, x); assertEquals("y = 0", 0, y); x2 = t2.getDescendComparator().compare(a, a); y2 = t2.getDescendComparator().compare(b, b); assertEquals("x2 = 0", 0, x2); assertEquals("y2 = 0", 0, y2); assertEquals("x = x2", x, x2); assertEquals("y = y2", y, y2); } /** * Test exception. */ public void testException() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); int wrong = 99; try { t = new TermOrder(wrong); } catch (IllegalArgumentException e) { return; } fail("IllegalArgumentException"); } /** * Test exception split. */ public void testExceptionSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); int wrong = 99; try { t = new TermOrder(wrong, wrong, r, sp); } catch (IllegalArgumentException e) { return; } fail("IllegalArgumentException"); } /** * Test compare exception. */ public void testCompareException() { float q = (float) 0.9; a = ExpVector.random(5, 10, q); b = ExpVector.random(5, 10, q); int notimpl = TermOrder.MAX_EVORD + 2; int x = 0; try { t = new TermOrder(notimpl); x = t.getDescendComparator().compare(a, b); fail("IllegalArgumentException " + x); } catch (IllegalArgumentException e) { //return; } catch (NullPointerException e) { //return; } } /** * Test compare exception split. */ public void testCompareExceptionSplit() { float q = (float) 0.9; int r = 10; int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); int notimpl = TermOrder.REVITDG + 2; int x = 0; try { t = new TermOrder(notimpl, notimpl, r, sp); x = t.getDescendComparator().compare(a, b); fail("IllegalArgumentException " + x); } catch (IllegalArgumentException e) { //return; } catch (NullPointerException e) { //return; } } /** * Test compare exception weight. */ public void testCompareExceptionWeigth() { float q = (float) 0.9; int r = 10; //int sp = 5; a = ExpVector.random(r, 10, q); b = ExpVector.random(r, 10, q); int x = 0; try { t = new TermOrder((long[][]) null); x = t.getDescendComparator().compare(a, b); fail("IllegalArgumentException " + x); } catch (IllegalArgumentException e) { //return; } catch (NullPointerException e) { //return; } } } java-algebra-system-2.7.200/trc/edu/jas/poly/WordTest.java000066400000000000000000000330771445075545500232730ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.poly; import java.util.Collection; import java.util.List; import java.util.SortedMap; import java.util.Arrays; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Word and WordFactory tests with JUnit. Tests construction and arithmetic * operations. * @author Heinz Kredel */ public class WordTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a WordTest object. * @param name String. */ public WordTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(WordTest.class); return suite; } Word a, b, c, d; @Override protected void setUp() { a = b = c = d = null; } @Override protected void tearDown() { a = b = c = d = null; } /** * Test constructor and toString. */ public void testConstructor() { WordFactory wf = new WordFactory("abcdefg"); a = new Word(wf); b = a; //System.out.println("a = " + a); assertEquals("() = ()", a, b); assertEquals("length( () ) = 0", a.length(), 0); assertTrue("isONE( () )", a.isONE()); assertTrue("isUnit( () )", a.isUnit()); b = new Word(wf, "abc"); c = wf.parse(" a b c "); //System.out.println("b = " + b); //System.out.println("c = " + c); assertEquals("b = c: ", b, c); assertFalse("isONE( () )", b.isONE()); assertFalse("isUnit( () )", b.isUnit()); assertFalse("isONE( () )", c.isONE()); assertFalse("isUnit( () )", c.isUnit()); String s = b.toString(); String t = c.toString(); //System.out.println("s = " + s); //System.out.println("t = " + t); assertEquals("s = t: ", s, t); } /** * Test word factory. */ public void testFactory() { WordFactory wf = new WordFactory("abcdefg"); //System.out.println("wf = " + wf); Word w = wf.getONE(); //System.out.println("w = " + w); assertTrue("w == (): ", w.isONE()); w = wf.parse("aaabbbcccaaa"); //System.out.println("w = " + w); assertFalse("w != (): ", w.isONE()); a = wf.parse(w.toString()); //System.out.println("a = " + a); assertEquals("w = a", a, w); WordFactory wf2 = new WordFactory(w.toString()); //System.out.println("wf2 = " + wf2); a = wf2.parse(w.toString()); //System.out.println("a = " + a); assertEquals("w = a", a, w); List gens = wf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 7: ", gens.size() == 7); for (Word v : gens) { a = wf.parse(v.toString()); assertEquals("a == v", a, v); } } /** * Test random word. */ public void testRandom() { WordFactory wf = new WordFactory("uvw"); //System.out.println("wf = " + wf); a = wf.random(5); b = wf.random(6); c = wf.random(7); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertFalse("a != (): ", a.isONE()); assertFalse("b != (): ", b.isONE()); assertFalse("c != (): ", c.isONE()); assertTrue("#a == 5", a.length() == 5); assertTrue("#b == 6", b.length() == 6); assertTrue("#c == 7", c.length() == 7); SortedMap ma = a.dependencyOnVariables(); SortedMap mb = b.dependencyOnVariables(); SortedMap mc = c.dependencyOnVariables(); //System.out.println("ma = " + ma); //System.out.println("mb = " + mb); //System.out.println("mc = " + mc); assertTrue("#ma <= 3", ma.size() <= wf.length()); assertTrue("#mb <= 3", mb.size() <= wf.length()); assertTrue("#mc <= 3", mc.size() <= wf.length()); assertTrue("S ma <= #a", sum(ma.values()) == a.length()); assertTrue("S mb <= #b", sum(mb.values()) == b.length()); assertTrue("S mc <= #c", sum(mc.values()) == c.length()); } int sum(Collection li) { int s = 0; for (Integer i : li) { s += i; } return s; } /** * Test multiplication. */ public void testMultiplication() { WordFactory wf = new WordFactory("abcdefgx"); a = new Word(wf, "abc"); b = new Word(wf, "cddaa"); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("c = " + c); assertTrue("divides: ", a.divides(c)); assertTrue("divides: ", b.divides(c)); assertTrue("multiple: ", c.multipleOf(a)); assertTrue("multiple: ", c.multipleOf(b)); d = c.divideRight(a); //System.out.println("d = " + d); assertEquals("d = b", d, b); d = c.divideLeft(b); //System.out.println("d = " + d); assertEquals("d = a", d, a); d = c.divide(c); //System.out.println("d = " + d); assertTrue("isONE( () )", d.isONE()); d = new Word(wf, "xx"); c = a.multiply(d).multiply(b); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("divides: ", d.divides(c)); Word[] ret = c.divideWord(d,false); //System.out.println("ret = " + ret[0] + ", " + ret[1]); assertEquals("prefix(c/d) = a", a, ret[0]); assertEquals("suffix(c/d) = b", b, ret[1]); Word e = ret[0].multiply(d).multiply(ret[1]); assertEquals("prefix(c/d) d suffix(c/d) = e", e, c); ret = c.divideWord(d,true); //System.out.println("ret = " + ret[0] + ", " + ret[1]); assertEquals("prefix(c/d) = a", a, ret[0]); assertEquals("suffix(c/d) = b", b, ret[1]); e = ret[0].multiply(d).multiply(ret[1]); assertEquals("prefix(c/d) d suffix(c/d) = e", e, c); } /** * Test overlap. */ public void testOverlap() { WordFactory wf = new WordFactory("abcdefg"); a = new Word(wf, "abc"); b = new Word(wf, "ddabca"); //System.out.println("a = " + a); //System.out.println("b = " + b); OverlapList ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); a = new Word(wf, "abcfff"); b = new Word(wf, "ddabc"); //System.out.println("a = " + a); //System.out.println("b = " + b); ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); a = new Word(wf, "fffabc"); b = new Word(wf, "abcdd"); //System.out.println("a = " + a); //System.out.println("b = " + b); ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); a = new Word(wf, "ab"); b = new Word(wf, "dabeabfabc"); //System.out.println("a = " + a); //System.out.println("b = " + b); ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); a = new Word(wf, "abc"); b = new Word(wf, "abceabcfabc"); //System.out.println("a = " + a); //System.out.println("b = " + b); ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); a = new Word(wf, "aa"); b = new Word(wf, "aaaaaaaaa"); //System.out.println("a = " + a); //System.out.println("b = " + b); ol = a.overlap(b); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(a,b)); ol = b.overlap(a); //System.out.println("ol = " + ol); assertTrue("isOverlap: ", ol.isOverlap(b,a)); } /** * Test valueOf. */ public void testValueOf() { String[] vars = new String[] { "a", "b", "c", "d" }; WordFactory wf = new WordFactory(vars); ExpVector ef = ExpVector.random(4,5L,0.5f); //System.out.println("ef = " + ef); a = wf.valueOf(ef); //System.out.println("a = " + a); assertTrue("deg(ef) == deg(a): " + ef + ", " + a, ef.degree() == a.degree() ); String es = ef.toString(vars); //System.out.println("es = " + es); assertTrue("ef != ''" + ef, es.length() >= 0 ); } /** * Test constructor with multi-letter Strings. */ public void testMultiLetters() { String[] vars = new String[] {"a1", "b", " e23", "tt*", "x y" }; WordFactory wf = new WordFactory(vars); //System.out.println("wf = " + wf); String s = wf.toString(); assertEquals("w == vars: ", s, "\"a1,b,e23,tt,xy\""); Word w = wf.parse("a1 a1 b*b*b tt xy e23 tt xy"); s = w.toString(); String t = "\"a1 a1 b b b tt xy e23 tt xy\""; //System.out.println("s = " + s); //System.out.println("t = " + t); assertEquals("w == parse: ", s, t); Word u = wf.parse("xy e23 tt xy a1 a1 b*b*b tt"); s = u.toString(); String t1 = "\"xy e23 tt xy a1 a1 b b b tt\""; //System.out.println("s = " + s); //System.out.println("t = " + t1); assertEquals("w == parse: ", s, t1); Word v = u.multiply(w); s = v.toString(); String t2 = t1.substring(0,t1.length()-1) + " " + t.substring(1); //System.out.println("s = " + s); //System.out.println("t = " + t2); assertEquals("w == parse: ", s, t2); v = w.multiply(u); s = v.toString(); t2 = t.substring(0,t.length()-1) + " " + t1.substring(1); //System.out.println("s = " + s); //System.out.println("t = " + t2); assertEquals("w == parse: ", s, t2); w = wf.random(5); //System.out.println("w = " + w); u = wf.random(5); //System.out.println("u = " + u); v = u.multiply(w); //System.out.println("v = " + v); assertTrue("#v = #w+#u: ", v.length() == w.length()+u.length()); List gens = wf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 5: ", gens.size() == 5); for (Word x : gens) { a = wf.parse(x.toString()); assertEquals("a == x", a, x); } } /** * Test leadingExpVector and reductum. */ public void testExpVector() { String[] vars = new String[] { "a", "b", "cc", "d1", "g" }; WordFactory wf = new WordFactory(vars); Word w = wf.random(10); //System.out.println("w = " + w); long lw = w.degree(); long le = 0L; Word r = w; while ( !r.isONE() ) { ExpVector ef = r.leadingExpVector(); Word r1 = r.reductum(); //System.out.println("ef = " + ef.toString(vars) + ", r1 = " + r1); le += ef.degree(); Word w1 = wf.valueOf(ef); Word w2 = w1.multiply(r1); assertEquals("r == w2", r, w2); r = r1; } assertTrue("deg(prod(ef)) == deg(w): " + lw + ", " + le, lw == le ); } /** * Test subfactory and contraction. */ public void testContraction() { WordFactory wf = new WordFactory("abcdefg"); WordFactory wfs = new WordFactory("acdfg"); // test if contraction is possible assertTrue("wf.isSubFactory(wfs): " + wf + ", " + wfs, wf.isSubFactory(wfs) ); assertTrue("wf.isSubFactory(wf): " + wf + ", " + wf, wf.isSubFactory(wf) ); assertFalse("wf.isSubFactory(wfs): " + wf + ", " + wfs, wfs.isSubFactory(wf) ); wf = new WordFactory(new String[] { "alpha", "x", "y", "z" }); //System.out.println("wf = " + wf); wfs = new WordFactory(new String[] { "x", "y", "z" }); //System.out.println("wfs = " + wfs); // test if contraction is possible assertTrue("wf.isSubFactory(wfs): " + wf + ", " + wfs, wf.isSubFactory(wfs) ); assertFalse("wf.isSubFactory(wfs): " + wf + ", " + wfs, wfs.isSubFactory(wf) ); Word w1 = wf.parse("alpha alpha"); Word w2 = wf.parse("y z x x y z"); //System.out.println("w1 = " + w1); //System.out.println("w2 = " + w2); // contract words Word wc1 = wf.contract(w1); //System.out.println("wc1 = " + wc1); assertEquals("wf.contract(w1): " + w1 + ", " + wf, w1, wc1); Word wc2 = wfs.contract(w2); //System.out.println("wc2 = " + wc2); assertEquals("wfs.contract(w2): " + w2 + ", " + wfs, w2, wc2); Word wc3 = wfs.contract(w1); //System.out.println("wc3 = " + wc3); assertTrue("wfs.contract(w3): " + wc3 + ", " + wfs, (wc3 == null)); } } java-algebra-system-2.7.200/trc/edu/jas/ps/000077500000000000000000000000001445075545500203025ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/ps/IteratorsTest.java000066400000000000000000000203761445075545500237710ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.util.CartesianProductInfinite; import edu.jas.util.CartesianProductLong; import edu.jas.util.LongIterable; /** * Iterator tests with JUnit. * @author Heinz Kredel */ public class IteratorsTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ListUtilTest object. * @param name String. */ public IteratorsTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(IteratorsTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test ExpVector iterator. */ public void testExpVector() { int n = 5; LongIterable li = new LongIterable(); li.setNonNegativeIterator(); List> tlist = new ArrayList>(n); for (int i = 0; i < n; i++) { tlist.add(li); } //System.out.println("tlist = " + tlist); Set set = new TreeSet((new TermOrder()).getDescendComparator()); Iterable> ib = new CartesianProductInfinite(tlist); long t = 0L; for (List i : ib) { //System.out.println("i = " + i); ExpVector e = ExpVector.create(i); //System.out.println("e = " + e); assertFalse("e in set", set.contains(e)); set.add(e); t++; if (t > 100L) { //System.out.println("i = " + i); break; } } //System.out.println("set = " + set); assertTrue("#set", set.size() == t); } /** * Test GenPolynomial iterator. */ public void testGenPolynomial() { ModIntegerRing mi = new ModIntegerRing(5, true); int n = 3; GenPolynomialRing ring = new GenPolynomialRing(mi, n); Set> set = new TreeSet>(); long t = 0; for (GenPolynomial p : ring) { //System.out.println("p = " + p); if (set.contains(p)) { System.out.println("p = " + p); System.out.println("set = " + set); assertFalse("p in set ", true); } set.add(p); t++; if (t > 650L) { //System.out.println("i = " + i); break; } } //System.out.println("set = " + set); assertTrue("#set", set.size() == t); } /** * Test GenPolynomial monomial iterator. */ public void testGenPolynomialMonomial() { BigInteger bi = new BigInteger(1); int n = 3; GenPolynomialRing ring = new GenPolynomialRing(bi, n); Set> set = new TreeSet>(); long t = 0; for (GenPolynomial p : ring) { //System.out.println("p = " + p); if (set.contains(p)) { System.out.println("p = " + p); //System.out.println("set = " + set); assertFalse("p in set ", true); } set.add(p); t++; if (t > 650L) { //System.out.println("i = " + i); break; } } //System.out.println("set = " + set); assertTrue("#set", set.size() == t); } /** * Test total degree ExpVector iterator. */ public void testTotalDegExpVector() { int n = 4; Set set = new TreeSet((new TermOrder()).getDescendComparator()); Map> degset = new TreeMap>(); long t = 0L; for (long k = 0; k < 14; k++) { LongIterable li = new LongIterable(); li.setNonNegativeIterator(); li.setUpperBound(k); List tlist = new ArrayList(n); for (int i = 0; i < n; i++) { tlist.add(li); // can reuse li } long kdeg = k; //if ( kdeg > 5 ) { // kdeg < k ok but kdeg > k not allowed // kdeg -= 2; //} Iterable> ib = new CartesianProductLong(tlist, kdeg); //System.out.println("kdeg = " + kdeg); for (List i : ib) { //System.out.println("i = " + i); ExpVector e = ExpVector.create(i); long tdeg = e.totalDeg(); //System.out.println("e = " + e + ", deg = " + tdeg); assertTrue("tdeg == k", tdeg == kdeg); Set es = degset.get(tdeg); if (es == null) { es = new TreeSet((new TermOrder()).getDescendComparator()); degset.put(tdeg, es); } es.add(e); //assertFalse("e in set", set.contains(e) ); set.add(e); t++; if (t > 500000L) { //System.out.println("i = " + i); break; } } } //System.out.println("waste = " + w + ", of " + t); //System.out.println("set = " + set); //System.out.println("degset = " + degset); for (Set es : degset.values()) { assertFalse("es != null", es == null); //System.out.println("#es = " + es.size() + ", es = " + es); //System.out.println("#es = " + es.size() + ", deg = " + es.iterator().next().totalDeg()); } assertTrue("#set", set.size() == t); } /** * Test total degree ExpVector iterator. */ public void testTotalDegExpVectorIteratorInf() { int n = 4; Set set = new TreeSet((new TermOrder()).getDescendComparator()); ExpVectorIterable eitbl = new ExpVectorIterable(n); long t = 0; for (ExpVector e : eitbl) { //System.out.println("e = " + e + ", deg = " + e.totalDeg()); t++; if (t > 500L) { //System.out.println("i = " + i); break; } assertFalse("e in set", set.contains(e)); set.add(e); } } /** * Test total degree ExpVector iterator. */ public void testTotalDegExpVectorIteratorFin() { int n = 4; Set set = new TreeSet((new TermOrder()).getDescendComparator()); ExpVectorIterable eitbl = new ExpVectorIterable(n, 5); long t = 0; for (ExpVector e : eitbl) { //System.out.println("e = " + e + ", deg = " + e.totalDeg()); t++; if (t > 500L) { //System.out.println("i = " + i); break; } assertFalse("e in set", set.contains(e)); set.add(e); } } /** * Test total degree ExpVector iterator. */ public void testTotalDegExpVectorIteratorAllFin() { int n = 4; Set set = new TreeSet((new TermOrder()).getDescendComparator()); ExpVectorIterable eitbl = new ExpVectorIterable(n, true, 5); long t = 0; for (ExpVector e : eitbl) { //System.out.println("e = " + e + ", deg = " + e.totalDeg()); t++; if (t > 500L) { //System.out.println("i = " + i); break; } assertFalse("e in set", set.contains(e)); set.add(e); } } } java-algebra-system-2.7.200/trc/edu/jas/ps/MultiVarPowerSeriesTest.java000066400000000000000000000415051445075545500257450ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Multivariate power series tests with JUnit. * @author Heinz Kredel */ public class MultiVarPowerSeriesTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a MultiVarPowerSeriesTest object. * @param name String. */ public MultiVarPowerSeriesTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(MultiVarPowerSeriesTest.class); return suite; } BigRational cfac; MultiVarPowerSeriesRing fac; MultiVarPowerSeries a, b, c, d, e, f; int rl = 2; int kl = 10; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; String[] vars = new String[] { "x", "y" }; cfac = new BigRational(1); fac = new MultiVarPowerSeriesRing(cfac, rl, vars); //System.out.println("fac = " + fac); //System.out.println("fac = " + fac.toScript()); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test generate. */ public void testGenerate() { String s = fac.toScript(); //System.out.println("fac.toScript: " + s + ", " + s.length()); assertTrue("#s == 17: " + s, s.length() == 17); List> gens = fac.generators(); assertFalse("#gens != () ", gens.isEmpty()); //System.out.println("generators: " + gens); // test equals Set> set = new HashSet>(gens); //System.out.println("gen set: " + set); assertEquals("#gens == #set: ", gens.size(), set.size()); // test for elements 0, 1 a = fac.getZERO(); b = fac.getONE(); assertFalse("0 not in #set: ", set.contains(a)); assertTrue("1 in #set: ", set.contains(b)); // specific tests assertEquals("#gens == rl+1 ", rl + 1, gens.size()); Set iset = new HashSet(set.size()); for (MultiVarPowerSeries p : gens) { //System.out.println("p = " + p.toScript() + ", # = " + p.hashCode() + ", red = " + p.reductum()); assertTrue("red(p) == 0 ", p.reductum().isZERO()); iset.add(p.hashCode()); } assertEquals("#gens == #iset: ", gens.size(), iset.size()); } /** * Test MultiVarCoefficients. */ public void testCoefficients() { BigRational cf = new BigRational(0); GenPolynomialRing pring = new GenPolynomialRing(cf, rl); MultiVarCoefficients zeros = new Zeros(pring); MultiVarCoefficients ones = new Ones(pring); MultiVarCoefficients vars = new Vars(pring); int m = 5; ExpVectorIterable eitbl = new ExpVectorIterable(rl, true, m); //System.out.println("eitbl 0 = " + eitbl.iterator().hasNext()); for (ExpVector e : eitbl) { BigRational c = zeros.get(e); //System.out.println("c = " + c + ", e = " + e); assertTrue("isZERO( c )", c.isZERO()); } //System.out.println("coeffCache = " + zeros.coeffCache); //System.out.println("zeroCache = " + zeros.zeroCache); assertTrue("coeffCache is one element", zeros.coeffCache.size() == (m + 1)); //System.out.println("eitbl 1 = " + eitbl.iterator().hasNext()); for (ExpVector e : eitbl) { BigRational c = ones.get(e); //System.out.println("c = " + c + ", e = " + e); assertTrue("isONE( c )", c.isONE()); } //System.out.println("coeffCache = " + ones.coeffCache); //System.out.println("zeroCache = " + ones.zeroCache); assertTrue("zeroCache is empty", ones.zeroCache.isEmpty()); for (int i = 0; i <= m; i++) { GenPolynomial c = ones.getHomPart(i); //System.out.println("c = " + c + ", i = " + i); GenPolynomial d = ones.getHomPart(i); //System.out.println("d = " + d + ", i = " + i); assertTrue("c.equals(d) ", c.equals(d)); } //System.out.println("coeffCache = " + ones.coeffCache); //System.out.println("zeroCache = " + ones.zeroCache); //System.out.println("homCheck = " + ones.homCheck); //System.out.println("homCheck = " + ones.homCheck.length()); assertTrue("zeroCache is empty", ones.zeroCache.isEmpty()); assertTrue("#coeffCache = " + m, ones.coeffCache.size() == (m + 1)); assertTrue("#homCheck = " + m, ones.homCheck.length() == (m + 1)); for (int i = 0; i <= m; i++) { GenPolynomial c = vars.getHomPart(i); //System.out.println("c = " + c + ", i = " + i); assertTrue("c==0 || deg(c)==1 ", c.isZERO() || c.degree() == 1L); } //System.out.println("coeffCache = " + vars.coeffCache); //System.out.println("zeroCache = " + vars.zeroCache); //System.out.println("homCheck = " + vars.homCheck); //System.out.println("homCheck = " + vars.homCheck.length()); //no-more: assertTrue("zeroCache is not empty", !vars.zeroCache.isEmpty()); assertTrue("#coeffCache = " + m, vars.coeffCache.size() == (m + 1)); assertTrue("#homCheck = " + m, vars.homCheck.length() == (m + 1)); } /** * Test constructor and generators. */ public void testConstruction() { //System.out.println("fac = " + fac); //System.out.println("fac = " + fac.toScript()); c = fac.getONE(); //System.out.println("c = " + c); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); List> gens = fac.generators(); assertTrue("#gens == rl+1 ", rl + 1 == gens.size()); for (MultiVarPowerSeries p : gens) { //System.out.println("p = " + p); assertTrue("red(p) == 0 ", p.reductum().isZERO()); } a = fac.copy(c); b = c.copy(); assertEquals("copy(c) == c.clone() ", a, b); assertTrue("copy(c) == c.clone() ", a.equals(b)); a = fac.fromInteger(1); assertEquals("1 == fromInteger(1) ", a, c); b = fac.fromInteger(java.math.BigInteger.ONE); assertEquals("1 == fromInteger(1) ", b, c); e = fac.generate((i) -> i.isZERO() ? cfac.getONE() : cfac.getZERO()); //System.out.println("e = " + e); assertTrue("isZERO( e )", !e.isZERO()); assertTrue("isONE( e )", e.isONE()); } /** * Test random power series. */ public void testRandom() { for (int i = 0; i < 5; i++) { a = fac.random(i + 2); if (a.isZERO() || a.isONE()) { continue; } //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test MultiVarCoefficients in power series. */ public void testCoefficientsInPS() { MultiVarCoefficients zeros = new Zeros(fac); MultiVarCoefficients ones = new Ones(fac); MultiVarCoefficients vars = new Vars(fac); a = new MultiVarPowerSeries(fac, zeros); b = new MultiVarPowerSeries(fac, ones); c = new MultiVarPowerSeries(fac, vars); int m = 5; ExpVectorIterable eitbl = new ExpVectorIterable(rl, true, m); for (ExpVector e : eitbl) { BigRational r = a.coefficient(e); //System.out.println("r = " + r + ", e = " + e); assertTrue("isZERO( r )", r.isZERO()); } //System.out.println("#a = " + a.lazyCoeffs.coeffCache); assertTrue("coeffCache is one element", a.lazyCoeffs.coeffCache.size() == (m + 1)); assertTrue("isZERO( a )", a.isZERO()); // after previous for (ExpVector e : eitbl) { BigRational r = b.coefficient(e); //System.out.println("r = " + r + ", e = " + e); assertTrue("isONE( r )", r.isONE()); } assertTrue("zeroCache is empty", b.lazyCoeffs.zeroCache.isEmpty()); for (int i = 0; i <= m; i++) { GenPolynomial p = b.homogeneousPart(i); //System.out.println("p = " + p + ", i = " + i); GenPolynomial q = b.homogeneousPart(i); //System.out.println("q = " + q + ", i = " + i); assertTrue("p.equals(q) ", p.equals(q)); } assertTrue("zeroCache is empty", b.lazyCoeffs.zeroCache.isEmpty()); assertTrue("#coeffCache = " + m, b.lazyCoeffs.coeffCache.size() == (m + 1)); assertTrue("#homCheck = " + m, b.lazyCoeffs.homCheck.length() == (m + 1)); for (int i = 0; i <= m; i++) { GenPolynomial p = c.homogeneousPart(i); //System.out.println("p = " + p + ", i = " + i); assertTrue("p==0 || deg(p)==1 ", p.isZERO() || p.degree() == 1L); } //no-more:assertTrue("zeroCache is not empty", !c.lazyCoeffs.zeroCache.isEmpty()); assertTrue("#coeffCache = " + m, c.lazyCoeffs.coeffCache.size() == (m + 1)); assertTrue("#homCheck = " + m, c.lazyCoeffs.homCheck.length() == (m + 1)); } /** * Test addition. */ public void testAddition() { a = fac.random(kl); b = fac.random(kl); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); d = c.subtract(b); assertEquals("a+b-b = a", a, d); d = c.sum(b.negate()); assertEquals("a+b-b = a", a, d); c = fac.random(kl); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); Map.Entry ma = a.orderMonomial(); c = a.reductum().sum(ma); assertEquals("a = red(a)+om(a)", a, c); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(kl); b = fac.random(kl); if (a.isZERO() || b.isZERO()) { return; } assertTrue("not isZERO( a )", !a.isZERO()); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); ExpVector ev = ExpVector.random(rl, 5, 0.8f); BigRational br = fac.coFac.random(5); b = a.shift(ev).multiply(br); c = a.multiply(br, ev); assertEquals("(a ev) br = a (ev,br)", b, c); //System.out.println("a = " + a); //System.out.println("ev = " + ev); //System.out.println("br = " + br); //System.out.println("b = " + b); //System.out.println("c = " + c); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, q); b = fac.random(kl, q); c = fac.random(kl, q); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test inverse. */ public void testInverse() { a = fac.getONE(); assertTrue("not isZERO( a )", !a.isZERO()); assertTrue("isUnit( a )", a.isUnit()); //System.out.println("a = " + a); b = a.inverse(); c = a.multiply(b); assertTrue("isONE( c )", c.isONE()); //System.out.println("b = " + b); //System.out.println("c = " + c); a = fac.random(kl); if (!a.isUnit()) { a = fac.fromInteger(23); //return; } //System.out.println("a = " + a); b = a.inverse(); c = a.multiply(b); assertTrue("isONE( c )", c.isONE()); //System.out.println("b = " + b); //System.out.println("c = " + c); b = fac.random(kl); c = b.divide(a); d = c.multiply(a); assertEquals("b/a * a == b ", d, b); } /** * Test reductum. */ public void testReductum() { a = fac.random(kl); //System.out.println("a = " + a); Map.Entry m = a.orderMonomial(); //System.out.println("m = " + m); ExpVector k = m.getKey(); BigRational br = m.getValue(); b = fac.getONE().multiply(br, k); //System.out.println("b = " + b); c = a.reductum(); //System.out.println("c = " + c); d = c.sum(b); //System.out.println("d = " + d); assertEquals("a = red(a)+1*lm(a) ", a, d); e = c.sum(br, k); //System.out.println("e = " + e); assertEquals("a = red(a)+lm(a) ", a, e); e = a.subtract(br, k); //System.out.println("e = " + e); assertEquals("a - lm(a) = red(a) ", c, e); b = fac.random(kl); String s = b.toString(); // generate and cache some coefficients //System.out.println("b = " + b); assertFalse("s.size > 0 " + s, s.length() == 0); // java-5 c = a.sum(b); //System.out.println("c = " + c); d = a.sum(b.lazyCoeffs); //System.out.println("d = " + d); // while ( !c.isZERO() ) { // c = c.reductum(); // //System.out.println("c = " + c); // } // assertTrue("red^n(a) == 0 ", c.isZERO()); br = new BigRational(2, 3); c = a.prepend(br, 0); d = c.reductum(0); assertEquals("red(a + br_0,0) = a ", d, a); c = a.shift(3, 0); d = c.shift(-3, 0); assertEquals("shift(shift(a,3,),-3,0) = a ", d, a); } /** * Test polynomial constructions. */ public void testPolynomial() { GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr); GenPolynomial p = pr.random(kl, 3, 3, q + q); //System.out.println("p = " + p); a = fac.fromPolynomial(p); //System.out.println("a = " + a); GenPolynomial s = a.asPolynomial(); //System.out.println("s = " + s); assertEquals("asPolynomial(fromPolynomial(p)) = p ", p, s); b = fac.fromPolynomial(s); //System.out.println("b = " + b); assertEquals("fromPolynomial(asPolynomial(s)) = s ", a, b); } } class Zeros extends MultiVarCoefficients { public Zeros(MultiVarPowerSeriesRing pf) { super(pf); } public Zeros(GenPolynomialRing pf) { super(pf); } @Override public BigRational generate(ExpVector i) { return pfac.coFac.getZERO(); } } class Ones extends MultiVarCoefficients { public Ones(MultiVarPowerSeriesRing pf) { super(pf); } public Ones(GenPolynomialRing pf) { super(pf); } @Override public BigRational generate(ExpVector i) { return pfac.coFac.getONE(); } } class Vars extends MultiVarCoefficients { public Vars(MultiVarPowerSeriesRing pf) { super(pf); } public Vars(GenPolynomialRing pf) { super(pf); } @Override public BigRational generate(ExpVector i) { int[] v = i.dependencyOnVariables(); if (v.length == 1 && i.getVal(v[0]) == 1L) { return pfac.coFac.getONE(); } return pfac.coFac.getZERO(); } } java-algebra-system-2.7.200/trc/edu/jas/ps/STDMultiPSTest.java000066400000000000000000000165521445075545500237260ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.HashSet; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Standard base of multivariate power series tests with JUnit. * @author Heinz Kredel */ public class STDMultiPSTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a STDMultiPSTest object. * @param name String. */ public STDMultiPSTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(STDMultiPSTest.class); return suite; } BigRational cfac; MultiVarPowerSeriesRing fac; MultiVarPowerSeries a, b, c, d, e, f; int rl = 3; int kl = 5; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; String[] vars = new String[] { "x", "y", "z" }; cfac = new BigRational(1); fac = new MultiVarPowerSeriesRing(cfac, rl, vars); //System.out.println("fac = " + fac); //System.out.println("fac = " + fac.toScript()); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; } /** * Test fix point constructions. */ public void testFixpoints() { int r = 0; UnivPowerSeriesRing ufac = new UnivPowerSeriesRing(fac.coFac, fac.vars[r]); UnivPowerSeries exp = ufac.getEXP(); //System.out.println("exp = " + exp); a = fac.fromPowerSeries(exp, 0); b = fac.fromPowerSeries(exp, 1); //System.out.println("a = " + a); //System.out.println("b = " + b); c = fac.getEXP(0); d = fac.getEXP(1); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a == c ", a, c); assertEquals("b == d ", b, d); e = d.differentiate(0); //System.out.println("e = " + e); assertTrue("isZERO( e )", e.isZERO()); e = d.differentiate(1); //System.out.println("e = " + e); assertEquals("e == d ", d, e); } /** * Test gcd. */ public void testGcd() { a = fac.random(kl); //System.out.println("a = " + a); b = fac.random(kl); //System.out.println("b = " + b); c = a.gcd(b); //System.out.println("c = " + c); d = a.divide(c); //System.out.println("d = " + d); e = b.divide(c); //System.out.println("e = " + e); f = d.gcd(e); //System.out.println("f = " + f); assertTrue("gcd(a/gcd(a,b),b/gcd(a,b)) == 1 ", f.isONE()); } /** * Test Taylor series. */ public void testTaylor() { BigRational ar = new BigRational(5); BigRational br = new BigRational(0); BigRational cr = new BigRational(-5); List Ar = new ArrayList(rl); List Br = new ArrayList(rl); List Cr = new ArrayList(rl); for (int i = 0; i < rl; i++) { Ar.add(ar); Br.add(br); Cr.add(cr); } GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr.toScript()); GenPolynomial p = pr.random(kl, 3, 3, q + q); //System.out.println("p = " + p); int tdeg = (int) p.degree(); fac.setTruncate(tdeg + 1); TaylorFunction F = new PolynomialTaylorFunction(p); MultiVarPowerSeries pps = fac.fromPolynomial(p); //System.out.println("pps = " + pps); MultiVarPowerSeries ps = fac.seriesOfTaylor(F, Br); //System.out.println("ps = " + ps); assertEquals("taylor(p) == p", ps, pps); MultiVarPowerSeries psa = fac.seriesOfTaylor(F, Ar); //System.out.println("psa = " + psa); F = new PolynomialTaylorFunction(psa.asPolynomial()); MultiVarPowerSeries psc = fac.seriesOfTaylor(F, Cr); //System.out.println("psc = " + psc); assertEquals("taylor(taylor(p,5),-5) == p", ps, psc); for (GenPolynomial g : pr.generators()) { F = new PolynomialTaylorFunction(g); ps = fac.seriesOfTaylor(F, Br); //System.out.println("g = " + g); //System.out.println("ps = " + ps); pps = fac.fromPolynomial(g); //System.out.println("pps = " + pps); assertEquals("taylor(p) == p", ps, pps); psa = fac.seriesOfTaylor(F, Ar); //System.out.println("psa = " + psa); F = new PolynomialTaylorFunction(psa.asPolynomial()); psc = fac.seriesOfTaylor(F, Cr); //System.out.println("psc = " + psc); assertEquals("taylor(taylor(p,5),-5) == p", ps, psc); } } /** * Test evaluation. */ public void testEvaluation() { a = fac.random(kl, q); b = fac.random(kl, q); BigRational fv = new BigRational(0); List v = new ArrayList(rl); for (int i = 0; i < rl; i++) { v.add(fv.random(kl)); } BigRational av = a.evaluate(v); BigRational bv = b.evaluate(v); c = a.sum(b); BigRational cv = c.evaluate(v); BigRational dv = av.sum(bv); assertEquals("a(v)+b(v) = (a+b)(v) ", cv, dv); c = fac.getZERO(); cv = c.evaluate(v); dv = fv.getZERO(); assertEquals("0(v) = 0 ", cv, dv); c = fac.getONE(); cv = c.evaluate(v); dv = fv.getONE(); assertEquals("1(v) = 1 ", cv, dv); } /** * Test standard base. * Example from CLO(UAG), 4.4. */ public void testSTD() { GenPolynomialRing pfac = fac.polyRing(); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial ap, bp, cp; ap = pfac.parse("x**5 - x * y**6 - z**7"); //System.out.println("ap = " + ap); bp = pfac.parse("x * y + y**3 + z**3"); //System.out.println("bp = " + bp); cp = pfac.parse("x**2 + y**2 - z**2"); //System.out.println("cp = " + cp); a = fac.fromPolynomial(ap); //System.out.println("a = " + a); b = fac.fromPolynomial(bp); //System.out.println("b = " + b); c = fac.fromPolynomial(cp); //System.out.println("c = " + c); List> L, S; L = new ArrayList>(); L.add(a); L.add(b); L.add(c); //System.out.println("L = " + L); StandardBaseSeq tm = new StandardBaseSeq(); //assertFalse("isSTD(L): ", tm.isSTD(L)); S = tm.STD(L); //System.out.println("S = " + S); assertTrue("isSTD(S): ", tm.isSTD(S)); } } java-algebra-system-2.7.200/trc/edu/jas/ps/UnivPowerSeriesTest.java000066400000000000000000000215431445075545500251230ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ps; import java.util.HashSet; import java.util.List; import java.util.Set; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.vector.GenVector; import edu.jas.vector.GenVectorModul; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Univariate power series tests with JUnit. * @author Heinz Kredel */ public class UnivPowerSeriesTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a UnivPowerSeriesTest object. * @param name String. */ public UnivPowerSeriesTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(UnivPowerSeriesTest.class); return suite; } BigRational cfac; UnivPowerSeriesRing fac; UnivPowerSeries a, b, c, d, e; int kl = 10; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigRational(1); fac = new UnivPowerSeriesRing(cfac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; cfac = null; ComputerThreads.terminate(); } /** * Test generate. */ public void testGenerate() { String s = fac.toScript(); //System.out.println("fac.toScript: " + s + ", " + s.length()); assertTrue("#s == 15: " + s, s.length() == 15); List> gens = fac.generators(); assertFalse("#gens != () ", gens.isEmpty()); //System.out.println("generators: " + gens); // test equals Set> set = new HashSet>(gens); //System.out.println("gen set: " + set); assertEquals("#gens == #set: ", gens.size(), set.size()); // test for elements 0, 1 a = fac.getZERO(); b = fac.getONE(); assertFalse("0 not in #set: ", set.contains(a)); assertTrue("1 in #set: ", set.contains(b)); // specific tests assertEquals("#gens == 2 ", 2, gens.size()); Set iset = new HashSet(set.size()); for (UnivPowerSeries p : gens) { //System.out.println("p = " + p.toScript() + ", # = " + p.hashCode() + ", red = " + p.reductum()); assertTrue("red(p) == 0 ", p.reductum().isZERO()); iset.add(p.hashCode()); } assertEquals("#gens == #iset: ", gens.size(), iset.size()); } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); //System.out.println("c = " + c); d = fac.getZERO(); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); e = fac.generate((i) -> i == 0 ? cfac.getONE() : cfac.getZERO()); //System.out.println("e = " + e); assertTrue("isZERO( e )", !e.isZERO()); assertTrue("isONE( e )", e.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 5; i++) { a = fac.random(i + 2); //System.out.println("a = " + a); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(kl); b = fac.random(kl); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = fac.random(kl); d = a.sum(b.sum(c)); e = a.sum(b).sum(c); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(kl); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(kl); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(kl, q); b = fac.random(kl, q); c = fac.random(kl, q); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test object quotient and remainder. */ public void testQuotRem() { fac = new UnivPowerSeriesRing(new BigRational(1)); a = fac.random(kl); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(kl); assertTrue("not isZERO( b )", !b.isZERO()); UnivPowerSeries g = fac.random(kl); assertTrue("not isZERO( g )", !g.isZERO()); a = a.multiply(g); b = b.multiply(g); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("g = " + g); /* UnivPowerSeries[] qr; qr = b.divideAndRemainder(a); c = qr[0]; d = qr[1]; //System.out.println("q = " + c); //System.out.println("r = " + d); e = c.multiply(a).sum(d); assertEquals("b = q a + r", b, e ); */ // gcd tests --- c = a.gcd(b); //System.out.println("gcd = " + c); assertTrue("a mod gcd(a,b) = 0", a.remainder(c).isZERO()); assertTrue("b mod gcd(a,b) = 0", b.remainder(c).isZERO()); //assertEquals("g = gcd(a,b)", c, g ); } /** * Test evaluation. */ public void testEvaluation() { a = fac.random(kl, q); b = fac.random(kl, q); BigRational fv = new BigRational(0); BigRational v = fv.random(kl); BigRational av = a.evaluate(v); BigRational bv = b.evaluate(v); c = a.sum(b); BigRational cv = c.evaluate(v); BigRational dv = av.sum(bv); assertEquals("a(v)+b(v) = (a+b)(v) ", cv, dv); c = fac.getZERO(); cv = c.evaluate(v); dv = fv.getZERO(); assertEquals("0(v) = 0 ", cv, dv); c = fac.getONE(); cv = c.evaluate(v); dv = fv.getONE(); assertEquals("1(v) = 1 ", cv, dv); // not true: //c = a.multiply(b); //cv = c.evaluate(v); //dv = av.multiply(bv); //assertEquals("a(v)*b(v) = (a*b)(v) ", cv, dv); } /** * Test polynomial constructions. */ public void testPolynomial() { GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr); GenPolynomial p = pr.random(kl, 3, 3, q + q); //System.out.println("p = " + p); a = fac.fromPolynomial(p); //System.out.println("a = " + a); GenPolynomial s = a.asPolynomial(); //System.out.println("s = " + s); assertEquals("asPolynomial(fromPolynomial(p)) = p ", p, s); b = fac.fromPolynomial(s); //System.out.println("b = " + b); assertEquals("fromPolynomial(asPolynomial(s)) = s ", a, b); } /** * Test vector constructions. */ public void testVector() { GenVectorModul pm = new GenVectorModul(fac.coFac, fac.truncate); //System.out.println("pm = " + pm); GenVector v = pm.random(kl, q); //System.out.println("v = " + v); a = fac.fromVector(v); //System.out.println("a = " + a); GenVector s = a.asVector(); //System.out.println("s = " + s); assertEquals("asVector(fromVector(v)) = v ", v, s); b = fac.fromVector(s); //System.out.println("b = " + b); assertEquals("fromVector(asVector(s)) = s ", a, b); } } java-algebra-system-2.7.200/trc/edu/jas/root/000077500000000000000000000000001445075545500206435ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/root/ComplexAlgebraicTest.java000066400000000000000000000162131445075545500255520ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.NotInvertibleException; /** * ComplexAlgebraicNumber Test using JUnit. * @author Heinz Kredel */ public class ComplexAlgebraicTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ComplexAlgebraicTest object. * @param name String. */ public ComplexAlgebraicTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(ComplexAlgebraicTest.class); return suite; } ComplexAlgebraicRing fac; GenPolynomialRing> mfac; ComplexAlgebraicNumber a, b, c, d, e; ComplexAlgebraicNumber alpha; int rl = 1; int kl = 10; int ll = 10; int el = ll; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; ComplexRing cfac = new ComplexRing(new BigRational(1)); Complex im = cfac.getIMAG(); BigRational rfac = new BigRational(); BigRational two = new BigRational(2); Complex nw = new Complex(cfac, rfac.getZERO(), two); Complex sw = new Complex(cfac, rfac.getZERO(), rfac.getZERO()); Complex se = new Complex(cfac, two, rfac.getZERO()); Complex ne = new Complex(cfac, two, two); Rectangle positive = new Rectangle(nw, sw, se, ne); //System.out.println("postiv = " + positive); String[] vars = new String[] { "alpha" }; mfac = new GenPolynomialRing>(cfac, rl, vars); Complex r1 = cfac.fromInteger(1).sum(im); Complex r2 = r1.conjugate(); GenPolynomial> mo = mfac.univariate(0, 1); mo = mo.subtract(r1).multiply(mo.subtract(r2)); // (x - (1+i))((x - (1-i))) fac = new ComplexAlgebraicRing(mo, positive); alpha = fac.getGenerator(); //System.out.println("fac = " + fac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; alpha = null; } /** * Test constructor and toString. */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); assertTrue("length( c ) = 1", c.number.getVal().length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); assertTrue("length( d ) = 0", d.number.getVal().length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(el); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } // fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.number.getVal().length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1", fac.getONE(), d); try { a = fac.getZERO().inverse(); } catch (NotInvertibleException expected) { return; } fail("0 invertible"); } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test compareTo of complex algebraic numbers. */ public void testCompare() { a = fac.random(ll).abs(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); int ab = a.compareTo(b); int bc = b.compareTo(c); int ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); a = a.negate(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); ab = a.compareTo(b); bc = b.compareTo(c); ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); } } java-algebra-system-2.7.200/trc/edu/jas/root/ComplexRootTest.java000066400000000000000000000662131445075545500246310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.Collections; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import edu.jas.ufd.Squarefree; import edu.jas.ufd.SquarefreeFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RootUtil tests with JUnit. * @author Heinz Kredel */ public class ComplexRootTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a ComplexRootTest object. * @param name String. */ public ComplexRootTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ComplexRootTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing> dfac; ComplexRing cfac; BigRational eps; Complex ceps; GenPolynomial> a; GenPolynomial> b; GenPolynomial> c; GenPolynomial> d; GenPolynomial> e; int rl = 1; int kl = 3; int ll = 3; int el = 5; float q = 0.7f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new ComplexRing(new BigRational(1)); String[] vars = new String[] { "x" }; dfac = new GenPolynomialRing>(cfac, rl, to, vars); eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); ceps = new Complex(cfac, eps); } @Override protected void tearDown() { a = b = c = d = e = null; dfac = null; cfac = null; eps = null; } /** * Test root bound. * */ public void testRootBound() { //a = dfac.random(kl, ll, el, q); a = dfac.univariate(0, 2L).sum(dfac.getONE()); // x^2 + 1 //System.out.println("a = " + a); ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); Complex Mb = cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); assertTrue("M >= 1 ", M.compareTo(BigRational.ONE) >= 0); //a = a.monic(); a = a.multiply(dfac.fromInteger(5)); //System.out.println("a = " + a); M = cr.rootBound(a).getRe(); //System.out.println("M = " + M); assertTrue("M >= 1 ", M.compareTo(BigRational.ONE) >= 0); } /** * Test Cauchy index. * */ public void testCauchyIndex() { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); //a = dfac.univariate(0,2L).sum(dfac.getONE()); // x^2 + 1 //System.out.println("a = " + a); //System.out.println("b = " + b); BigRational l = new BigRational(0); BigRational r = new BigRational(1); GenPolynomialRing fac = new GenPolynomialRing(l, dfac); ComplexRootsSturm cr = new ComplexRootsSturm(cfac); GenPolynomial f = PolyUtil. realPartFromComplex(fac, a); GenPolynomial g = PolyUtil. imaginaryPartFromComplex(fac, b); //System.out.println("re(a) = " + f); //System.out.println("im(b) = " + g); long ci = cr.indexOfCauchy(l, r, g, f); //System.out.println("ci = " + ci); assertTrue("ci >= 0 ", ci >= -a.degree(0)); } /** * Test Routh. * */ public void testRouth() { ComplexRootsSturm cr = new ComplexRootsSturm(cfac); //a = dfac.random(kl, ll, el, q); //b = dfac.random(kl, ll, el, q); Complex I = cfac.getIMAG(); GenPolynomial> X = dfac.univariate(0); //System.out.println("I = " + I); //System.out.println("X = " + X); //a = dfac.univariate(0,2L).sum( dfac.getONE().multiply(I) ); // x^2 + i //b = X.subtract( dfac.getONE().multiply( I ) ); // x - i b = X.subtract(dfac.getONE().multiply(I.negate())); // x + i c = X.subtract(dfac.getONE().multiply(I.multiply(cfac.fromInteger(3)))); // x - 3i d = X.subtract(dfac.getONE().multiply(I.multiply(cfac.fromInteger(4)))); // x - 4i e = X.subtract(dfac.getONE().multiply(I.multiply(cfac.fromInteger(5)))); // x - 5i a = b.multiply(c).multiply(d).multiply(e); //System.out.println("a = " + a.toScript()); //System.out.println("i = " + cfac.getIMAG()); Complex Mb = cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); BigRational minf = M.negate(); // - infinity BigRational pinf = M; // + infinity GenPolynomialRing fac = new GenPolynomialRing(pinf, dfac); GenPolynomial f = PolyUtil. realPartFromComplex(fac, a); GenPolynomial g = PolyUtil. imaginaryPartFromComplex(fac, a); //System.out.println("re(a) = " + f.toScript()); //System.out.println("im(a) = " + g.toScript()); long[] ri = cr.indexOfRouth(minf, pinf, f, g); //System.out.println("ri = [" + ri[0] + ", " + ri[1] + " ]"); long deg = ri[0] + ri[1]; assertTrue("sum(ri) == deg(a) ", deg >= a.degree(0)); } /** * Test winding number. * */ @SuppressWarnings("unchecked") public void testWindingNumber() { ComplexRootsSturm cr = new ComplexRootsSturm(cfac); //Complex I = cfac.getIMAG(); a = dfac.univariate(0, 2L).sum(cfac.fromInteger(1)); // x^2 + 1 //a = dfac.random(kl, ll, el, q); //a = dfac.univariate(0,2L).subtract(cfac.getONE()); // x^2 - 1 //a = dfac.univariate(0,2L).subtract(I); // x^2 - I //a = dfac.univariate(0,1L); // x //System.out.println("a = " + a); Complex Mb = cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); BigRational eps = new BigRational(1, 1000); //System.out.println("eps = " + eps); Complex[] corner = new Complex[4]; corner[0] = new Complex(cfac, M.negate(), M); // nw corner[1] = new Complex(cfac, M.negate(), M.negate()); // sw corner[2] = new Complex(cfac, M, M.negate()); // se corner[3] = new Complex(cfac, M, M); // ne long v = 0; try { v = cr.windingNumber(new Rectangle(corner), a); } catch (InvalidBoundaryException e) { fail("" + e); } //System.out.println("winding number = " + v); assertTrue("wind(rect,a) == 2 ", v == 2); //if ( true ) return; corner[0] = new Complex(cfac, M.negate(), M); // nw corner[1] = new Complex(cfac, M.negate(), eps); // sw corner[2] = new Complex(cfac, M, eps); // se corner[3] = new Complex(cfac, M, M); // ne try { v = cr.windingNumber(new Rectangle(corner), a); } catch (InvalidBoundaryException e) { fail("" + e); } //System.out.println("winding number = " + v); assertTrue("wind(rect,a) == 1 ", v == 1); corner[0] = new Complex(cfac, eps.negate(), eps); // nw corner[1] = new Complex(cfac, eps.negate(), eps.negate()); // sw corner[2] = new Complex(cfac, eps, eps.negate()); // se corner[3] = new Complex(cfac, eps, eps); // ne try { v = cr.windingNumber(new Rectangle(corner), a); } catch (InvalidBoundaryException e) { fail("" + e); } //System.out.println("winding number = " + v); assertTrue("wind(rect,a) == 0 ", v == 0); } /** * Test complex roots, sqrt(-1). * */ @SuppressWarnings("unchecked") public void testComplexRootsImag() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); //Complex I = cfac.getIMAG(); a = dfac.univariate(0, 2L).sum(cfac.fromInteger(1)); // x^2 + 1 //a = dfac.univariate(0,2L).subtract(cfac.getONE()); // x^2 - 1 //a = dfac.univariate(0,2L).subtract(I); // x^2 - I //a = dfac.univariate(0,1L); // x //System.out.println("a = " + a); Complex Mb = cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); Complex[] corner = new Complex[4]; corner[0] = new Complex(cfac, M.negate(), M); // nw corner[1] = new Complex(cfac, M.negate(), M.negate()); // sw corner[2] = new Complex(cfac, M, M.negate()); // se corner[3] = new Complex(cfac, M, M); // ne Rectangle rect = new Rectangle(corner); List> roots = null; try { roots = cr.complexRoots(rect, a); } catch (InvalidBoundaryException e) { fail("" + e); } //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); } /** * Test complex roots. */ @SuppressWarnings("unchecked") public void testComplexRootsRand() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); //Complex I = cfac.getIMAG(); a = dfac.random(kl, ll, el, q); Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); a = engine.squarefreePart(a); //a = dfac.univariate(0,2L).subtract(cfac.getONE()); // x^2 - 1 //a = dfac.univariate(0,2L).sum(cfac.fromInteger(1)); // x^2 + 1 //a = dfac.univariate(0,2L).subtract(I); // x^2 - I //a = dfac.univariate(0,1L); // x //System.out.println("a = " + a); Complex Mb = cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); Complex[] corner = new Complex[4]; corner[0] = new Complex(cfac, M.negate(), M); // nw corner[1] = new Complex(cfac, M.negate(), M.negate()); // sw corner[2] = new Complex(cfac, M, M.negate()); // se corner[3] = new Complex(cfac, M, M); // ne Rectangle rect = new Rectangle(corner); List> roots = null; try { roots = cr.complexRoots(rect, a); } catch (InvalidBoundaryException e) { fail("" + e); } //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); } /** * Test complex roots. */ public void testComplexRoots() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); a = dfac.random(kl, ll, el + 1, q); //System.out.println("a = " + a); long deg = a.degree(0); // now fixed Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); b = engine.squarefreePart(a); //long deg = b.degree(0); // multiplicity is fixed List> roots = cr.complexRoots(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); //assertTrue("#roots == deg(a) " + (a.degree()-roots.size()), roots.size() == a.degree(0)); assertTrue("#roots == deg(a): " + roots + ", " + a + ", " + b, roots.size() == deg); } /** * Test complex root refinement. */ public void testComplexRootRefinement() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); a = dfac.random(kl, ll, el - 1, q); //a = dfac.parse("( (x-1)^3 )"); Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); //System.out.println("a = " + a); a = engine.squarefreePart(a); //System.out.println("a = " + a); List> roots = cr.complexRoots(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); BigRational len = new BigRational(1, 1000); //System.out.println("len = " + len); for (Rectangle root : roots) { try { Rectangle refine = cr.complexRootRefinement(root, a, len); //System.out.println("refine = " + refine); assertFalse("refine != null", refine == null); } catch (InvalidBoundaryException e) { fail("" + e); } } } /** * Test complex root refinement full. */ public void testComplexRootRefinementFull() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); a = dfac.random(kl, ll, el - 1, q); //a = dfac.parse("( (x-1)^3 )"); //a = dfac.parse("( x^4-2 )"); //System.out.println("a = " + a); BigRational len = new BigRational(1, 1000); //System.out.println("len = " + len); List> refine = cr.complexRoots(a, len); //System.out.println("refine = " + refine); assertTrue("#roots == deg(a) ", refine.size() == a.degree(0)); } /** * Test winding number with wrong precondition. */ @SuppressWarnings("unchecked") public void testWindingNumberWrong() { ComplexRootsSturm cr = new ComplexRootsSturm(cfac); //Complex I = cfac.getIMAG(); a = dfac.univariate(0, 2L).sum(cfac.fromInteger(1)); // x^2 + 1 //a = dfac.random(kl, ll, el, q); //a = dfac.univariate(0,2L).subtract(cfac.getONE()); // x^2 - 1 //a = dfac.univariate(0,2L).subtract(I); // x^2 - I //a = dfac.univariate(0,1L); // x //System.out.println("a = " + a); Complex Mb = cfac.fromInteger(1); //.divide(cfac.fromInteger(2)); //cr.rootBound(a); BigRational M = Mb.getRe(); //System.out.println("M = " + M); //BigRational eps = new BigRational(1, 1000); //System.out.println("eps = " + eps); BigRational zero = new BigRational(); //BigRational one = new BigRational(1); Complex[] corner = new Complex[4]; corner[0] = new Complex(cfac, M.negate(), M); // nw corner[1] = new Complex(cfac, M.negate(), zero); // sw corner[2] = new Complex(cfac, M, zero); // se corner[3] = new Complex(cfac, M, M); // ne Rectangle rect = new Rectangle(corner); //System.out.println("rect = " + rect); try { long v = cr.windingNumber(rect, a); System.out.println("winding number = " + v); fail("wind(rect,a) must throw an exception"); } catch (InvalidBoundaryException e) { } } /** * Test complex root approximation. */ public void testComplexRootApproximation() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); //a = dfac.random(kl, ll, el-1, q); //a = dfac.parse("( (x-1)*(x-2)*(x-3)*(x - { 0i1 })*(x-5) )*( x^4-2 )"); //a = dfac.parse("( (x-1)*(x-2)*(x-3)*( x^4-2 ) )"); //a = dfac.parse("( (x-2)*( x^4-2 ) )"); a = dfac.parse("( ( x^4-2 ) )"); b = dfac.parse("( (x-1)*(x-2)*(x-3) )"); c = dfac.parse("( x^4-2 )"); d = dfac.parse("( (x - { 0i1 })*(x-5) )"); //a = c; // b; //.multiply(c); //.multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = b.multiply(c).multiply(d); //System.out.println("a = " + a); Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); a = engine.squarefreePart(a); //System.out.println("a = " + a); eps = eps.multiply(new BigRational(1000000)); //System.out.println("eps = " + eps); //BigDecimal eps1 = new BigDecimal(eps); //BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List> roots = cr.complexRoots(a); //System.out.println("a = " + a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); for (Rectangle root : roots) { try { Complex cd = cr.approximateRoot(root, a, eps); //System.out.println("cd = " + cd); assertFalse("cd != 0", cd.isZERO()); } catch (NoConvergenceException e) { //fail("" + e); } } } /** * Test complex root approximation full algorithm. */ public void testComplexRootApproximationFull() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); //a = dfac.random(kl, ll, el-1, q); //a = dfac.parse("( (x-1)*(x-2)*(x-3)*(x - { 0i1 })*(x-5) )*( x^4-2 )"); //a = dfac.parse("( (x-1)*(x-2)*(x-3)*( x^4-2 ) )"); a = dfac.parse("( (x-2)*( x^4-2 ) )"); //a = dfac.parse("( ( x^4-2 ) )"); b = dfac.parse("( (x-1)*(x-2)*(x-3) )"); c = dfac.parse("( x^4-2 )"); d = dfac.parse("( (x - { 0i1 })*(x-5) )"); //a = c; // b; //.multiply(c); //.multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //a = b.multiply(c).multiply(d); //System.out.println("a = " + a); eps = eps.multiply(new BigRational(1000000)); //System.out.println("eps = " + eps); //BigDecimal eps1 = new BigDecimal(eps); //BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List> roots = cr.approximateRoots(a, eps); //System.out.println("a = " + a); //System.out.println("roots = " + roots); //now always true: assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); } /** * Test complex root approximation full algorithm with Wilkinson * polynomials. p = (x-i0)*(x-i1)*(x-i2)*(x-i3*...*(x-in) */ public void testComplexRootApproximationWilkinsonFull() { final int N = 4; d = dfac.getONE(); e = dfac.univariate(0); BigDecimal br = new BigDecimal(); ComplexRing cf = new ComplexRing(br); Complex I = cf.getIMAG(); Complex cc = null; Complex Ir = cfac.getIMAG(); List> Rn = new ArrayList>(N); a = d; for (int i = 0; i < N; i++) { cc = cf.fromInteger(i).multiply(I); Rn.add(cc); c = dfac.fromInteger(i).multiply(Ir); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); Collections.reverse(Rn); //System.out.println("Rn = " + Rn); ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); eps = eps.multiply(new BigRational(100000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List> roots = cr.approximateRoots(a, eps); // fix ordering of roots cc = roots.remove(0); roots.add(cc); //System.out.println("a = " + a); //System.out.println("roots = " + roots); //System.out.println("Rn = " + Rn); //now always true: assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); int i = 0; for (Complex dd : roots) { Complex di = Rn.get(i++); //System.out.print("di = " + di + ", "); //System.out.println("di = " + di + ", " + "dd = " + dd); Complex d = dd.subtract(di).norm(); assertTrue("|dd - di| < eps: " + d + ", " + dd + ", " + di, d.getRe().compareTo(eps2) <= 0); } } /** * Test complex root approximation full algorithm with Wilkinson * polynomials, inverse roots. p = (x-1/i1)*(x-1/i2)*(x-1/i3*...*(x-1/in) */ public void testComplexRootApproximationWilkinsonInverseFull() { final int N = 5; d = dfac.getONE(); e = dfac.univariate(0); BigDecimal br = new BigDecimal(); ComplexRing cf = new ComplexRing(br); Complex I = cf.getIMAG(); Complex cc = null; Complex Ir = cfac.getIMAG(); List> Rn = new ArrayList>(N); a = d; for (int i = 1; i < N; i++) { cc = cf.fromInteger(i).multiply(I); cc = cc.inverse(); Rn.add(cc); c = dfac.fromInteger(i).multiply(Ir); c = d.divide(c); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); //Collections.sort(Rn); //System.out.println("Rn = " + Rn); ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); eps = eps.multiply(new BigRational(100000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List> roots = cr.approximateRoots(a, eps); //System.out.println("a = " + a); //System.out.println("roots = " + roots); //now always true: assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); //Collections.sort(roots); //System.out.println("roots = " + roots); for (Complex dd : roots) { //System.out.println("dd = " + dd); boolean t = false; for (Complex di : Rn) { //System.out.println("di = " + di); t = dd.subtract(di).norm().getRe().compareTo(eps2) <= 0; if (t) { break; } } if (!t) { //assertTrue("|dd - di| < eps ", dd.subtract(di).norm().getRe().compareTo(eps2) <= 0); fail("|dd - di| < eps "); } } } /** * Test complex root invariant rectangle. */ public void testComplexRootInvariant() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); a = dfac.random(kl, ll, el - 1, q); b = dfac.random(kl, ll, 2, q); //a = dfac.parse("( (x-1)^3 )"); //a = dfac.parse("( x^4-2 )"); if (a.degree() == 0) { return; } Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); a = engine.squarefreePart(a); b = engine.squarefreePart(b); //System.out.println("a = " + a); //System.out.println("b = " + b); List> roots = cr.complexRoots(a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); Rectangle rect = roots.get(0); //System.out.println("rect = " + rect); try { Rectangle ref = cr.invariantRectangle(rect, a, b); //System.out.println("rect = " + rect); //System.out.println("ref = " + ref); assertTrue("rect subseteq ref ", rect.contains(ref)); } catch (InvalidBoundaryException e) { e.printStackTrace(); fail("bad boundary"); } } /** * Test complex root invariant magnitude rectangle. */ public void testComplexRootInvariantMagnitude() { ComplexRootsAbstract cr = new ComplexRootsSturm(cfac); a = dfac.random(kl, ll, el - 1, q); b = dfac.random(kl, ll, 3, q); //a = dfac.parse("( x^2 + 1 )"); //b = dfac.parse("( x - 0i1 )"); if (a.degree() == 0) { return; } Squarefree> engine = SquarefreeFactory .> getImplementation(cfac); a = engine.squarefreePart(a); b = engine.squarefreePart(b); //System.out.println("a = " + a); //System.out.println("b = " + b); List> roots = cr.complexRoots(a); //System.out.println("roots = " + roots); assertTrue("#roots == deg(a) ", roots.size() == a.degree(0)); Rectangle rect = roots.get(0); //System.out.println("rect = " + rect); try { Rectangle ref = cr.invariantMagnitudeRectangle(rect, a, b, eps); //System.out.println("ref = " + ref); assertTrue("rect subseteq ref ", rect.contains(ref)); Complex mag = cr.complexRectangleMagnitude(ref, a, b); //System.out.println("mag = " + mag); Complex cmag = cr.complexMagnitude(ref, a, b, eps); //System.out.println("cmag = " + cmag); assertEquals("mag == cmag: " + cmag, mag, cmag); //BigRational rmag = cmag.getRe(); //System.out.println("rmag = " + new BigDecimal(cmag.getRe()) + " i " + new BigDecimal(cmag.getIm())); } catch (InvalidBoundaryException e) { e.printStackTrace(); fail("bad boundary"); } } } java-algebra-system-2.7.200/trc/edu/jas/root/RealAlgebraicTest.java000066400000000000000000000344711445075545500250340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.structure.NotInvertibleException; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RealAlgebraicNumber Test using JUnit. * @author Heinz Kredel */ public class RealAlgebraicTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RealAlgebraicTest object. * @param name String. */ public RealAlgebraicTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(RealAlgebraicTest.class); return suite; } RealAlgebraicRing fac; GenPolynomialRing mfac; RealAlgebraicNumber a, b, c, d, e; RealAlgebraicNumber alpha; int rl = 1; int kl = 10; int ll = 10; int el = ll; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; BigRational l = new BigRational(1); BigRational r = new BigRational(2); Interval positive = new Interval(l, r); String[] vars = new String[] { "alpha" }; mfac = new GenPolynomialRing(new BigRational(1), rl, vars); GenPolynomial mo = mfac.univariate(0, 2); mo = mo.subtract(mfac.fromInteger(2)); // alpha^2 -2 fac = new RealAlgebraicRing(mo, positive); alpha = fac.getGenerator(); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; alpha = null; } /** * Test constructor and toString. * */ public void testConstruction() { c = fac.getONE(); //System.out.println("c = " + c); //System.out.println("c.getVal() = " + c.getVal()); assertTrue("length( c ) = 1", c.number.getVal().length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = fac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.getVal() = " + d.getVal()); assertTrue("length( d ) = 0", d.number.getVal().length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { a = fac.random(el); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } // fac.random(kl*(i+1), ll+2*i, el+i, q ); assertTrue("length( a" + i + " ) <> 0", a.number.getVal().length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = fac.random(ll); b = fac.random(ll); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); assertEquals("a+b = b+a", c, d); c = fac.random(ll); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(fac.getZERO()); d = a.subtract(fac.getZERO()); assertEquals("a+0 = a-0", c, d); c = fac.getZERO().sum(a); d = fac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test multiplication. */ public void testMultiplication() { a = fac.random(ll); assertTrue("not isZERO( a )", !a.isZERO()); b = fac.random(ll); assertTrue("not isZERO( b )", !b.isZERO()); c = b.multiply(a); d = a.multiply(b); assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = fac.random(ll); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(fac.getONE()); d = fac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1/a = 1", fac.getONE(), d); try { a = fac.getZERO().inverse(); fail("0 invertible"); } catch (NotInvertibleException expected) { // pass } } /** * Test distributive law. */ public void testDistributive() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); d = a.multiply(b.sum(c)); e = a.multiply(b).sum(a.multiply(c)); assertEquals("a(b+c) = ab+ac", d, e); } /** * Test sign of real algebraic numbers. */ public void testSignum() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); int sa = a.signum(); int sb = b.signum(); int sc = c.signum(); d = a.multiply(b); e = a.multiply(c); int sd = d.signum(); int se = e.signum(); assertEquals("sign(a*b) = sign(a)*sign(b) ", sa * sb, sd); assertEquals("sign(a*c) = sign(a)*sign(c) ", sa * sc, se); b = a.negate(); sb = b.signum(); assertEquals("sign(-a) = -sign(a) ", -sa, sb); } /** * Test compareTo of real algebraic numbers. */ public void testCompare() { a = fac.random(ll).abs(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); int ab = a.compareTo(b); int bc = b.compareTo(c); int ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); a = a.negate(); b = a.sum(fac.getONE()); c = b.sum(fac.getONE()); ab = a.compareTo(b); bc = b.compareTo(c); ac = a.compareTo(c); assertTrue("a < a+1 ", ab < 0); assertTrue("a+1 < a+2 ", bc < 0); assertTrue("a < a+2 ", ac < 0); } /** * Test arithmetic of magnitude of real algebraic numbers. */ public void testMagnitude() { a = fac.random(ll); b = fac.random(ll); c = fac.random(ll); //BigDecimal ad = new BigDecimal(a.magnitude()); //BigDecimal bd = new BigDecimal(b.magnitude()); //BigDecimal cd = new BigDecimal(c.magnitude()); d = a.multiply(b); e = a.sum(b); BigDecimal dd = new BigDecimal(d.magnitude()); BigDecimal ed = new BigDecimal(e.magnitude()); BigDecimal dd1 = new BigDecimal(a.magnitude().multiply(b.magnitude())); BigDecimal ed1 = new BigDecimal(a.magnitude().sum(b.magnitude())); //System.out.println("ad = " + ad); //System.out.println("bd = " + bd); //System.out.println("cd = " + cd); //System.out.println("dd = " + dd); //System.out.println("dd1 = " + dd1); //System.out.println("ed = " + ed); //System.out.println("ed1 = " + ed1); //BigRational eps = Power.positivePower(new BigRational(1L,10L),BigDecimal.DEFAULT_PRECISION); BigRational eps = Power.positivePower(new BigRational(1L, 10L), 8); BigDecimal epsd = new BigDecimal(eps); BigDecimal rel = dd.abs().sum(dd1.abs()); BigDecimal err = dd.subtract(dd1).abs().divide(rel); //System.out.println("rel = " + rel); //System.out.println("|dd-dd1|/rel = " + err + ", eps = " + epsd); assertTrue("mag(a*b) = mag(a)*mag(b): " + dd + ", " + dd1, err.compareTo(epsd) <= 0); assertTrue("mag(a+b) = mag(a)+mag(b): " + ed + ", " + ed1, ed.subtract(ed1).abs().compareTo(epsd) <= 0); d = a.divide(b); e = a.subtract(b); dd = new BigDecimal(d.magnitude()); ed = new BigDecimal(e.magnitude()); dd1 = new BigDecimal(a.magnitude().divide(b.magnitude())); ed1 = new BigDecimal(a.magnitude().subtract(b.magnitude())); //System.out.println("dd = " + dd); //System.out.println("dd1 = " + dd1); //System.out.println("ed = " + ed); //System.out.println("ed1 = " + ed1); assertTrue("mag(a/b) = mag(a)/mag(b)", dd.subtract(dd1).abs().compareTo(epsd) <= 0); assertTrue("mag(a-b) = mag(a)-mag(b)", ed.subtract(ed1).abs().compareTo(epsd) <= 0); } /** * Test real root isolation. */ public void testRealRootIsolation() { //System.out.println(); GenPolynomialRing> dfac; dfac = new GenPolynomialRing>(fac, 1); GenPolynomial> ar; ar = dfac.random(3, 5, 7, q); //System.out.println("ar = " + ar); if (ar.degree() % 2 == 0) { // ensure existence of a root ar = ar.multiply(dfac.univariate(0)); } //System.out.println("ar = " + ar); RealRoots> rrr = new RealRootsSturm>(); List>> R = rrr.realRoots(ar); //System.out.println("R = " + R); assertTrue("#roots >= 0 ", R.size() > 0); BigRational eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); BigDecimal epsd = new BigDecimal(Power.positivePower(new BigRational(1L, 10L), 14 - ar.degree())); // less //System.out.println("eps = " + epsd); R = rrr.refineIntervals(R, ar, eps); //System.out.println("R = " + R); for (Interval> v : R) { RealAlgebraicNumber m = v.middle(); //System.out.println("m = " + m); RealAlgebraicNumber n; n = PolyUtil.> evaluateMain(fac, ar, m); //System.out.println("n = " + n); BigRational nr = n.magnitude(); //System.out.println("nr = " + nr); BigDecimal nd = new BigDecimal(nr); //System.out.println("nd = " + nd); assertTrue("|nd| < eps: " + nd + " " + epsd, nd.abs().compareTo(epsd) <= 0); //no: assertTrue("n == 0: " + n, n.isZERO()); } } /** * Test real root isolation for Wilkinson like polynomials. * product_{i=1..n}( x - i * alpha ) */ public void testRealRootIsolationWilkinson() { //System.out.println(); GenPolynomialRing> dfac; dfac = new GenPolynomialRing>(fac, 1); GenPolynomial> ar, br, cr, dr, er; RealRoots> rrr = new RealRootsSturm>(); final int N = 3; dr = dfac.getONE(); er = dfac.univariate(0); List>> Rn; Rn = new ArrayList>>(N); ar = dr; for (int i = 0; i < N; i++) { cr = dfac.fromInteger(i).multiply(alpha); // i * alpha Rn.add(new Interval>(cr.leadingBaseCoefficient())); br = er.subtract(cr); // ( x - i * alpha ) ar = ar.multiply(br); } //System.out.println("ar = " + ar); List>> R = rrr.realRoots(ar); //System.out.println("R = " + R); assertTrue("#roots = " + N + " ", R.size() == N); BigRational eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); eps = eps.multiply(new BigRational("1/10")); //System.out.println("eps = " + eps); R = rrr.refineIntervals(R, ar, eps); //System.out.println("R = " + R); int i = 0; for (Interval> v : R) { BigDecimal dd = v.toDecimal();//.sum(eps1); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("v = " + dd); //System.out.println("vi = " + di); assertTrue("|dd - di| < eps ", dd.compareTo(di) == 0); } } /** * Test continued fraction. */ public void testContinuedFraction() { final int M = 100; RealAlgebraicNumber x = fac.random(15); //x = fac.parse("5/12"); //x = fac.parse("-1"); //x = fac.getGenerator(); // alpha = sqrt(2) //System.out.println("x = " + x + ", mag(x) = " + x.decimalMagnitude()); List cf = RealArithUtil.continuedFraction(x, M); //System.out.println("cf(" + x + ") = " + cf); BigRational a = RealArithUtil.continuedFractionApprox(cf); RealAlgebraicNumber ax = fac.fromRational(a); //System.out.println("ax = " + ax + ", mag(ax) = " + ax.decimalMagnitude()); BigRational eps = (new BigRational("1/10")).power(M / 2); RealAlgebraicNumber dx = x.subtract(ax).abs(); // check ax > 1: dx = dx.divide(ax.abs()); //System.out.println("dx = " + dx + ", mag(dx) = " + dx.decimalMagnitude()); BigRational dr = dx.magnitude(); assertTrue("|a - approx(cf(a))| = " + dr, dr.compareTo(eps) < 1); } } java-algebra-system-2.7.200/trc/edu/jas/root/RealRootTest.java000066400000000000000000000507361445075545500241100ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.Collections; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.arith.Roots; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RealRoot tests with JUnit. * @author Heinz Kredel */ public class RealRootTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RealRootTest object. * @param name String. */ public RealRootTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RealRootTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; BigRational ai, bi, ci, di, ei, eps; GenPolynomial a, b, c, d, e; int rl = 1; int kl = 5; int ll = 7; int el = 7; float q = 0.7f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; String[] vars = new String[] { "x" }; dfac = new GenPolynomialRing(new BigRational(1), rl, to, vars); // eps = new BigRational(1L,1000000L*1000000L*1000000L); eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; eps = null; } /** * Test Sturm sequence. */ public void testSturmSequence() { a = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); RealRootsSturm rrs = new RealRootsSturm(); List> S = rrs.sturmSequence(a); //System.out.println("S = " + S); try { b = a.remainder(S.get(0)); } catch (Exception e) { fail("not S(0)|f " + e); } assertTrue("a mod S(0) == 0 ", b.isZERO()); assertTrue("S(-1) == 1 ", S.get(S.size() - 1).isConstant()); } /** * Test root bound. */ public void testRootBound() { a = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); RealRootsAbstract rr = new RealRootsSturm(); // used root bound BigRational M = rr.realRootBound(a); //System.out.println("M = " + M); assertTrue("M >= 1 ", M.compareTo(BigRational.ONE) >= 0); Interval v1 = new Interval(M.negate(), M); long r1 = rr.realRootCount(v1, a); //System.out.println("v1 = " + v1 + ", r1 = " + r1); a = a.monic(); //System.out.println("a = " + a); BigDecimal ar = M.getDecimal(); //System.out.println("ar = " + ar); assertTrue("ar >= 1 ", ar.compareTo(BigDecimal.ONE) >= 0); // maxNorm root bound BigRational mr = a.maxNorm().getRational().sum(BigRational.ONE); BigDecimal dr = mr.getDecimal(); //System.out.println("dr = " + dr); //assertTrue("ar >= maxNorm(a): " + (ar.subtract(dr)), ar.compareTo(dr) >= 0); Interval v2 = new Interval(mr.negate(), mr); long r2 = rr.realRootCount(v2, a); //System.out.println("v2 = " + v2 + ", r2 = " + r2); assertTrue("r1 == r2: " + (r2 - r1), r1 == r2); // squareNorm root bound BigRational qr = a.squareNorm().getRational(); BigDecimal ir = Roots.sqrt(qr.getDecimal()); //qr = Roots.sqrt(qr); //System.out.println("ir = " + ir); //assertTrue("ar >= squareNorm(a): " + (ar.subtract(ir)), ar.compareTo(ir) >= 0); Interval v3 = new Interval(qr.negate(), qr); long r3 = rr.realRootCount(v3, a); //System.out.println("v3 = " + v3 + ", r3 = " + r3); assertTrue("r1 == r3: " + (r3 - r1), r1 == r3); // sumNorm root bound BigRational pr = a.sumNorm().getRational(); BigDecimal sr = pr.getDecimal(); //System.out.println("sr = " + sr); //assertTrue("ar >= squareNorm(a): " + (ar.subtract(sr)), ar.compareTo(sr) >= 0); Interval v4 = new Interval(pr.negate(), pr); long r4 = rr.realRootCount(v4, a); //System.out.println("v4 = " + v4 + ", r4 = " + r4); assertTrue("r1 == r4: " + (r4 - r1), r1 == r4); // minimal root bound BigDecimal dri = dr.sum(BigDecimal.ONE).inverse(); //System.out.println("dri = " + dri + ", sign(dri) = " + dri.signum()); assertTrue("minimal root > 0: " + dri, dri.signum() > 0); BigDecimal mri = rr.realMinimalRootBound(a).getDecimal(); //System.out.println("mri = " + mri + ", sign(mri) = " + mri.signum()); BigDecimal s = dri.subtract(mri).abs(); eps = eps.multiply(BigRational.ONE.fromInteger(10)); //System.out.println("s = " + s + ", eps = " + eps.getDecimal()); assertTrue("minimal root: " + dri, s.compareTo(eps.getDecimal()) < 0); // minimal root separation long n = a.degree(); if (n > 0) { BigDecimal sep = sr.sum(BigDecimal.ONE).power(2 * n).multiply(sr.fromInteger(n).power(n + 1)) .inverse(); //System.out.println("sep = " + sep + ", sign(sep) = " + sep.signum()); assertTrue("separation(a) > 0: " + sep, sep.signum() > 0); BigDecimal sri = rr.realMinimalRootSeparation(a).getDecimal(); BigDecimal ss = sep.subtract(sri).abs(); assertTrue("minimal separation: " + sep, ss.compareTo(eps.getDecimal()) < 0); } } /** * Test real root isolation. */ public void testRealRootIsolation() { a = dfac.random(kl, ll * 2, el * 2, q); //a = a.multiply( dfac.univariate(0) ); //System.out.println("a = " + a); RealRoots rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); //assertTrue("#roots >= 0 ", R.size() >= 0); assertTrue("#roots >= 0 ", R != null); } /** * Test Thom lemma real root sign sequence. */ public void testRealRootSignSequence() { a = dfac.random(kl, ll * 2, el * 2, q); if (a.degree() % 2 == 0) { a = a.multiply(dfac.univariate(0).subtract(dfac.getONE())); } if (a.trailingExpVector().degree() > 0) { a = a.subtract(dfac.getONE()); // exclude root 0 } //System.out.println("a = " + a); RealRootsAbstract rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); //assertTrue("#roots >= 0 ", R.size() >= 0); assertTrue("#roots >= 0 ", R != null); int l = R.size(); Interval v = R.get(l - 1); Interval u = R.get(0); if (u.left.isZERO() && u.right.isZERO()) { Interval w = v; v = u; u = w; } Interval vm = new Interval(u.left, v.right); //System.out.println("v = " + v); //System.out.println("u = " + u); //System.out.println("vm = " + vm); long rc = rr.realRootCount(vm, a); //System.out.println("rc = " + rc); assertTrue("root number: R = " + R + ", a = " + a + ", rc = " + rc, rc == l); long rn = rr.realRootNumber(a, vm); assertTrue("root number == " + rn, rn == l); long d = a.degree(); List> fs = rr.fourierSequence(a); //System.out.println("fs = " + fs); assertTrue("len(fs) == " + (d + 1 - fs.size()), fs.size() == (d + 1)); //List ss = rr.signSequence(a, v); //System.out.println("ss = " + ss); //assertTrue("len(ss) == " + (d-ss.size()), ss.size() == d); for (Interval t : R) { List ss = rr.signSequence(a, t); //System.out.println("ss = " + ss); assertTrue("len(ss) == " + (d - ss.size()), ss.size() == d); } } /** * Test real root isolation Wilkinson polynomials. p = * (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) */ public void testRealRootIsolationWilkinson() { final int N = 10; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 0; i < N; i++) { c = dfac.fromInteger(i); Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); RealRoots rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); assertTrue("#roots = " + N + " ", R.size() == N); eps = eps.multiply(new BigRational("1/10")); //System.out.println("eps = " + eps); R = rr.refineIntervals(R, a, eps); //System.out.println("R = " + R); int i = 0; for (Interval v : R) { BigDecimal dd = v.toDecimal(); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("v = " + dd); //System.out.println("vi = " + di); //System.out.println("|dd - di| < eps: " + dd.compareTo(di)); assertTrue("|dd - di| < eps ", dd.compareTo(di) == 0); } } /** * Test real root isolation Wilkinson polynomials inverse. p = * (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) */ public void testRealRootIsolationWilkinsonInverse() { final int N = 9; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 1; i < N; i++) { // use only for i > 0, since reverse c = dfac.fromInteger(i); if (i != 0) { c = d.divide(c); } Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); //System.out.println("Rn = " + Rn); Collections.reverse(Rn); //System.out.println("Rn = " + Rn); RealRoots rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); eps = eps.multiply(new BigRational("1/100")); //System.out.println("eps = " + eps); R = rr.refineIntervals(R, a, eps); //System.out.println("R = " + R); int i = 0; for (Interval v : R) { BigDecimal dd = v.toDecimal(); //.sum(eps1); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("v = " + dd); //System.out.println("vi = " + di); //System.out.println("|dd - di| < eps: " + dd.compareTo(di)); assertTrue("|dd - di| < eps ", dd.compareTo(di) == 0); } } /** * Test real algebraic number sign. */ public void testRealAlgebraicNumberSign() { d = dfac.fromInteger(2); e = dfac.univariate(0); a = e.multiply(e); // a = a.multiply(e).multiply(e).multiply(e); a = a.subtract(d); // x^2 -2 //System.out.println("a = " + a); RealRoots rr = new RealRootsSturm(); ai = new BigRational(1); bi = new BigRational(2); Interval iv = new Interval(ai, bi); //System.out.println("iv = " + iv); assertTrue("sign change", rr.signChange(iv, a)); b = dfac.random(kl, (int) a.degree() + 1, (int) a.degree(), 1.0f); //b = dfac.getZERO(); //b = dfac.random(kl,ll,el,q); //b = b.multiply(b); //b = b.abs().negate(); //System.out.println("b = " + b); if (b.isZERO()) { int s = rr.realSign(iv, a, b); assertTrue("algebraic sign", s == 0); return; } int as = rr.realSign(iv, a, b); //System.out.println("as = " + as); // how to test? int asn = rr.realSign(iv, a, b.negate()); //System.out.println("asn = " + asn); assertTrue("algebraic sign", as != asn); iv = new Interval(bi.negate(), ai.negate()); //System.out.println("iv = " + iv); assertTrue("sign change", rr.signChange(iv, a)); int as1 = rr.realSign(iv, a, b); //System.out.println("as1 = " + as1); // how to test? int asn1 = rr.realSign(iv, a, b.negate()); //System.out.println("asn1 = " + asn1); assertTrue("algebraic sign", as1 != asn1); assertTrue("algebraic sign", as * as1 == asn * asn1); } /** * Test real root isolation and decimal refinement of Wilkinson polynomials. * p = (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) */ public void testRealRootIsolationDecimalWilkinson() { final int N = 10; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 0; i < N; i++) { c = dfac.fromInteger(i); Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); RealRootsAbstract rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); assertTrue("#roots = " + N + " ", R.size() == N); eps = eps.multiply(new BigRational(100000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("100")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); try { int i = 0; for (Interval v : R) { //System.out.println("v = " + v); BigDecimal dd = rr.approximateRoot(v, a, eps); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("di = " + di); //System.out.println("dd = " + dd); assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); } } catch (NoConvergenceException e) { fail(e.toString()); } } /** * Test real root isolation and decimal refinement of Wilkinson polynomials, * inverse roots. p = (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) */ public void testRealRootIsolationDecimalWilkinsonInverse() { final int N = 10; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 1; i < N; i++) { // use only for i > 0, since reverse c = dfac.fromInteger(i); if (i != 0) { c = d.divide(c); } Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); //System.out.println("Rn = " + Rn); Collections.reverse(Rn); //System.out.println("Rn = " + Rn); RealRootsAbstract rr = new RealRootsSturm(); List> R = rr.realRoots(a); //System.out.println("R = " + R); assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); eps = eps.multiply(new BigRational(1000000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); try { int i = 0; for (Interval v : R) { //System.out.println("v = " + v); BigDecimal dd = rr.approximateRoot(v, a, eps); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("di = " + di); //System.out.println("dd = " + dd); assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); } } catch (NoConvergenceException e) { fail(e.toString()); } } /** * Test real root isolation and decimal refinement of Wilkinson polynomials, * all roots. p = (x-0)*(x-1)*(x-2)*(x-3)*...*(x-n) */ public void testRealRootIsolationDecimalWilkinsonAll() { final int N = 10; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 0; i < N; i++) { c = dfac.fromInteger(i); Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); RealRootsAbstract rr = new RealRootsSturm(); eps = eps.multiply(new BigRational(10000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("100")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List R = null; R = rr.approximateRoots(a, eps); //System.out.println("R = " + R); assertTrue("#roots = " + N + " ", R.size() == N); int i = 0; for (BigDecimal dd : R) { //System.out.println("dd = " + dd); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("di = " + di); assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); } boolean t = rr.isApproximateRoot(R, a, eps); assertTrue("some |a(dd)| < eps ", t); } /** * Test real root isolation and decimal refinement of Wilkinson polynomials, * inverse roots, all roots. p = (x-1)*(x-1/2)*(x-1/3)*...*(x-1/n) */ public void testRealRootIsolationDecimalWilkinsonInverseAll() { final int N = 10; d = dfac.getONE(); e = dfac.univariate(0); List> Rn = new ArrayList>(N); a = d; for (int i = 1; i < N; i++) { // use only for i > 0, since reverse c = dfac.fromInteger(i); if (i != 0) { c = d.divide(c); } Rn.add(new Interval(c.leadingBaseCoefficient())); b = e.subtract(c); a = a.multiply(b); } //System.out.println("a = " + a); //System.out.println("Rn = " + Rn); Collections.reverse(Rn); //System.out.println("Rn = " + Rn); RealRootsAbstract rr = new RealRootsSturm(); eps = eps.multiply(new BigRational(1000000)); //System.out.println("eps = " + eps); BigDecimal eps1 = new BigDecimal(eps); BigDecimal eps2 = eps1.multiply(new BigDecimal("10")); //System.out.println("eps1 = " + eps1); //System.out.println("eps2 = " + eps2); List R = null; R = rr.approximateRoots(a, eps); //System.out.println("R = " + R); assertTrue("#roots = " + (N - 1) + " ", R.size() == (N - 1)); int i = 0; for (BigDecimal dd : R) { //System.out.println("dd = " + dd); BigDecimal di = Rn.get(i++).toDecimal(); //System.out.println("di = " + di); assertTrue("|dd - di| < eps ", dd.subtract(di).abs().compareTo(eps2) <= 0); } boolean t = rr.isApproximateRoot(R, a, eps); assertTrue("some |a(dd)| < eps ", t); } } java-algebra-system-2.7.200/trc/edu/jas/root/RootUtilTest.java000066400000000000000000000241511445075545500241320ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.root; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigDecimal; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * RootUtil tests with JUnit. * @author Heinz Kredel */ public class RootUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RootUtilTest object. * @param name String. */ public RootUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(RootUtilTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; BigRational ai, bi, ci, di, ei, eps; GenPolynomial a, b, c, d, e; int rl = 1; int kl = 3; int ll = 5; int el = 7; float q = 0.7f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; String[] vars = new String[] { "x" }; dfac = new GenPolynomialRing(new BigRational(1), rl, to, vars); // eps = new BigRational(1L,1000000L*1000000L*1000000L); eps = Power.positivePower(new BigRational(1L, 10L), BigDecimal.DEFAULT_PRECISION); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; eps = null; ComputerThreads.terminate(); } /** * Test sign variations. */ public void testSignVar() { int[] li = new int[] { 1, 0, 0, -1, 2, 3, 0, 1, 0, 0, 0, -1 }; List Li = new ArrayList(); ai = new BigRational(); for (int i = 0; i < li.length; i++) { bi = ai.fromInteger(li[i]); Li.add(bi); } //System.out.println("Li = " + Li); long v = RootUtil. signVar(Li); //System.out.println("v = " + v); assertEquals("varSign(Li)", v, 3); List Mi = new ArrayList(); for (int i = 0; i < 7; i++) { bi = ai.random(kl); Mi.add(bi); } //System.out.println("Mi = " + Mi); v = RootUtil. signVar(Mi); //System.out.println("v = " + v); long vv = v; assertTrue("varSign(Mi)>=0", v >= 0); List Ni = new ArrayList(Mi); Ni.addAll(Li); //System.out.println("Ni = " + Ni); v = RootUtil. signVar(Ni); //System.out.println("v = " + v); assertTrue("varSign(Mi)>=3", v >= 3 + vv); Ni = new ArrayList(Ni); Ni.addAll(Mi); //System.out.println("Ni = " + Ni); v = RootUtil. signVar(Ni); //System.out.println("v = " + v); assertTrue("varSign(Mi)>=3", v >= 3 + vv); } /** * Test intervals. */ public void testIntervals() { a = dfac.random(kl, ll * 2, el * 2, q); b = dfac.random(kl, ll * 2, el * 2, q); b = b.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); RealRootsAbstract rr = new RealRootsSturm(); ai = rr.realRootBound(a); bi = rr.realRootBound(b); //System.out.println("ai = " + ai); //System.out.println("bi = " + bi); Interval v1 = new Interval(ai.negate(), ai); Interval v2 = new Interval(bi.negate(), bi.sum(BigRational.ONE)); //System.out.println("v1 = " + v1); //System.out.println("v2 = " + v2); Interval v3 = v1.sum(v2); Interval v4 = v1.subtract(v2); Interval v5 = v1.multiply(v2); //System.out.println("v3 = " + v3); //System.out.println("v4 = " + v4); //System.out.println("v5 = " + v5); assertTrue("v1 in v3", v3.contains(v1)); assertTrue("v2 in v3", v3.contains(v2)); assertTrue("v1 in v4", v4.contains(v1)); assertTrue("v2 in v4", v4.contains(v2)); assertTrue("v3 in v5", v5.contains(v3)); assertTrue("v4 in v5", v5.contains(v4)); } /** * Test real algebraic factory. */ public void testRealAlgebraicFactory() { a = dfac.random(kl, ll * 2, el * 2, q); //a = a.multiply( dfac.univariate(0) ); //System.out.println("a = " + a); List> lrn = RootFactory. realAlgebraicNumbers(a); //System.out.println("lrn = " + lrn); //assertTrue("#roots >= 0 ", lrn.size() >= 0); assertTrue("#roots >= 0 ", lrn != null); for (RealAlgebraicNumber ra : lrn) { //System.out.println("ra = " + ra.toScript() + " in " + ra.toScriptFactory()); assertTrue("f(r) == 0: " + ra, RootFactory. isRoot(a, ra)); } lrn = RootFactory. realAlgebraicNumbersField(a); //System.out.println("lrn = " + lrn); assertTrue("#roots >= 0 ", lrn != null); for (RealAlgebraicNumber ra : lrn) { //System.out.println("ra = " + ra.toScript() + " in " + ra.toScriptFactory()); assertTrue("f(r) == 0: " + ra, RootFactory. isRoot(a, ra)); } } /** * Test complex algebraic factory. */ public void testComplexAlgebraicFactory() { a = dfac.random(kl, ll, el, q); //a = a.multiply( dfac.univariate(0) ); //System.out.println("a = " + a); ComplexRing cf = new ComplexRing(new BigRational()); GenPolynomialRing> cfac = new GenPolynomialRing>(cf, dfac); GenPolynomial> ca = PolyUtil. toComplex(cfac, a); //System.out.println("ca = " + ca); List> lcn = RootFactory . complexAlgebraicNumbersComplex(ca); //System.out.println("lcn = " + lcn); assertTrue("#roots == deg(a): " + a, lcn.size() == a.degree(0)); for (ComplexAlgebraicNumber car : lcn) { //System.out.println("car = " + car.toScript() + " in " + car.toScriptFactory()); //System.out.println("car = " + car.ring.root); //System.out.println("car = " + car.ring.root.centerApprox() + ", " // + (Roots.sqrt(new BigDecimal(car.ring.root.rationalLength()))) + ", " + car.ring.root); assertTrue("f(r) == 0: " + car, RootFactory. isRoot(a, car)); } } /** * Test complex rational factory. */ public void testComplexRationalFactory() { a = dfac.random(kl, ll, el, q); //a = a.multiply( dfac.univariate(0) ); //a = dfac.parse(" 1/8 x^6 - 5/3 x^5 + 3/20 x^4 - 2 x^3 "); //System.out.println("a = " + a); List> lcn = RootFactory. complexAlgebraicNumbers(a); //System.out.println("lcn = " + lcn); assertTrue("#roots == deg(a): " + a, lcn.size() == a.degree(0)); for (ComplexAlgebraicNumber car : lcn) { //System.out.println("car = " + car.toScript() + " in " + car.toScriptFactory()); //System.out.println("car = " + car.ring.root); //System.out.println("car = " + car.ring.root.centerApprox() + ", " // + (Roots.sqrt(new BigDecimal(car.ring.root.rationalLength()))) + ", " + car.ring.root); assertTrue("f(r) == 0: " + car, RootFactory. isRoot(a, car)); } } /** * Test algebraic roots, i.e. real and complex algebraic roots. */ public void testAlgebraicRoots() { a = dfac.random(kl, ll, el, q); //a = a.multiply( dfac.univariate(0) ); //System.out.println("a = " + a); AlgebraicRoots lcn = RootFactory. algebraicRoots(a); String ts = lcn.toScript(); //System.out.println("lcn = " + ts); assertTrue("complex in lcn: " + ts, ts.indexOf("real") >= 0 || ts.indexOf("complex") >= 0); ts = lcn.toDecimalScript(); //System.out.println("lcn = " + ts); assertTrue("complex in lcn: " + ts, ts.indexOf("real") >= 0 || ts.indexOf("complex") >= 0); long r = lcn.real.size() + lcn.complex.size(); ////Roots linalg = new Roots(); ////List> cd = linalg.complexRoots(a); ////System.out.println("cd = " + cd); // some real roots eventually not detected under complex roots assertTrue("#roots == degree(f): " + r, r >= a.degree()); } /** * Test decimal algebraic roots, i.e. real and complex decimal algebraic * roots. */ public void testDecimalRoots() { a = dfac.random(kl, ll - 1, el, q); //a = a.multiply( dfac.univariate(0) ); //System.out.println("a = " + a); int prec = BigDecimal.DEFAULT_PRECISION / 2; BigRational eps = (new BigRational(1, 10)).power(prec); //System.out.println("prec = " + prec + ", eps = " + eps); DecimalRoots lcn = RootFactory. decimalRoots(a, eps); String ts = lcn.toScript(); //System.out.println("lcn = " + ts); assertTrue("complex in lcn: " + ts, ts.indexOf("real") >= 0 || ts.indexOf("complex") >= 0); long r = lcn.real.size() + lcn.complex.size(); // some real roots eventually not detected under complex roots assertTrue("#roots == degree(f): " + r, r >= a.degree()); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/000077500000000000000000000000001445075545500204365ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorAlgebraicTest.java000066400000000000000000000103451445075545500251540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor algebraic tests with JUnit. * @author Heinz Kredel */ public class FactorAlgebraicTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorAlgebraicTest object. * @param name String. */ public FactorAlgebraicTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorAlgebraicTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void testDummy() { } /** * Test algebraic factorization. * */ public void testAlgebraicFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 2); agen = agen.sum(pfac.getONE()); // x^2 + 1 AlgebraicNumberRing afac = new AlgebraicNumberRing(agen, true); GenPolynomialRing> apfac = new GenPolynomialRing>( afac, 1, to, vars); // univariate //System.out.println("agen = " + agen); //System.out.println("afac = " + afac); //System.out.println("apfac = " + apfac); FactorAlgebraic fac = new FactorAlgebraic(afac); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = apfac.random(2, ll + i, el + i, q); //a = a.monic(); GenPolynomial> b = apfac.random(2, ll + i, el + i, q); if (b.degree() == 0) { b = b.multiply(apfac.univariate(0)); } //b = b.monic(); //if ( false && ! a.leadingBaseCoefficient().isONE() ) { //continue; //ExpVector e = a.leadingExpVector(); //a.doPutToMap(e,cfac.getONE()); //} if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } //a = apfac.univariate(0,2).sum( apfac.getONE() ); // x^2 + 1 //a = a.multiply(a); //a = a.multiply( apfac.univariate(0,2).subtract( apfac.getONE() ) ); // x^2 - 1 //a = apfac.univariate(0,3).subtract( apfac.getONE() ); // x^3 - 1 //a = apfac.univariate(0,3).sum( apfac.getONE() ); // x^3 + 1 a = c.multiply(b); //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { System.out.println("sm.size() < facs = " + facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorComplexTest.java000066400000000000000000000214101445075545500247050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.Complex; import edu.jas.poly.ComplexRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Factor complex via algebraic tests with JUnit. * @author Heinz Kredel */ public class FactorComplexTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorComplexTest object. * @param name String. */ public FactorComplexTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorComplexTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for empty test cases Junit. */ public void xtestDummy() { } /** * Test complex via algebraic factorization. */ public void testComplexFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational rfac = new BigRational(1); ComplexRing cfac = new ComplexRing(rfac); GenPolynomialRing> cpfac = new GenPolynomialRing>(cfac, 1, to); //System.out.println("cfac = " + cfac); //System.out.println("cpfac = " + cpfac); FactorComplex fac = new FactorComplex(cfac); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = cpfac.random(2, ll + i, el + i, q); //a = a.monic(); GenPolynomial> b = cpfac.random(2, ll + i, el + i, q); if (b.degree() == 0) { b = b.multiply(cpfac.univariate(0)); } if (c.degree() > 0) { facs++; } b = b.multiply(b); if (b.degree() > 0) { facs++; } a = c.multiply(b); //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { System.out.println("sm.size() < facs = " + facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test complex absolute via algebraic factorization. */ public void testComplexAbsoluteFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational rfac = new BigRational(1); ComplexRing cfac = new ComplexRing(rfac); GenPolynomialRing> cpfac = new GenPolynomialRing>(cfac, 1, to); //System.out.println("cfac = " + cfac); //System.out.println("cpfac = " + cpfac); FactorComplex fac = new FactorComplex(cfac); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = cpfac.random(2, ll, el, q); //a = a.monic(); GenPolynomial> b = cpfac.random(2, ll, el, q); if (b.degree() == 0) { b = b.multiply(cpfac.univariate(0)); } if (c.degree() > 0) { facs++; } b = b.multiply(b); if (b.degree() > 0) { facs++; } a = c.multiply(b); //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); FactorsMap> sm = fac.baseFactorsAbsolute(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); boolean t = fac.isAbsoluteFactorization(sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("facs <= #sm", facs <= sm.length()); } } /** * Test bivariate complex via algebraic factorization. */ public void testBivariateComplexFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational rfac = new BigRational(1); ComplexRing cfac = new ComplexRing(rfac); GenPolynomialRing> cpfac = new GenPolynomialRing>(cfac, 2, to); //System.out.println("cfac = " + cfac); //System.out.println("cpfac = " + cpfac); FactorComplex fac = new FactorComplex(cfac); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = cpfac.random(2, ll + i, el, q); //a = a.monic(); GenPolynomial> b = cpfac.random(2, ll + i, el, q); if (b.degree() == 0) { b = b.multiply(cpfac.univariate(0)); } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> sm = fac.factors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { System.out.println("sm.size() < facs = " + facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test bivariate complex factorization. Example from issue 10: * https://github.com/kredel/java-algebra-system/issues/10 */ public void testComplexFactor() { ComplexRing cfac = new ComplexRing(BigRational.ZERO); GenPolynomialRing> cpfac = new GenPolynomialRing>(cfac, new String[] { "x1", "x0" }, TermOrderByName.INVLEX); // GenPolynomial> a = cpfac.parse("x1^2 + x0^2") ; // GenPolynomial> a = cpfac.parse("x1^4 + x0^4") ; // GenPolynomial> a = cpfac.parse("x1^8 + x0^8") ; GenPolynomial> a = cpfac.parse("x1^12 - x0^12"); FactorComplex factorAbstract = new FactorComplex(cfac); //System.out.println("factorAbstract = " + factorAbstract); //System.out.println("factorFac = " + FactorFactory.getImplementation(cfac)); SortedMap>, Long> map = factorAbstract.factors(a); for (SortedMap.Entry>, Long> entry : map.entrySet()) { if (entry.getKey().isONE() && entry.getValue().equals(1L)) { continue; } assertTrue("degree <= 2 ", entry.getKey().degree() <= 2); // System.out.print(" ( " + entry.getKey().toScript() + " )"); // if (!entry.getValue().equals(1L)) { // System.out.print(" ^ " + entry.getValue()); // } // System.out.println(); } boolean t = factorAbstract.isFactorization(a, map); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorFractionTest.java000066400000000000000000000054551445075545500250560ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor fractions (of polynomial quotients) tests with JUnit. * @author Heinz Kredel */ public class FactorFractionTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorFractionTest object. * @param name String. */ public FactorFractionTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorFractionTest.class); return suite; } int rl = 1; int kl = 3; int ll = 4; int el = 4; float q = 0.5f; QuotientRing efac; GenPolynomialRing mfac; @Override protected void setUp() { BigRational cfac = new BigRational(1); TermOrder to = new TermOrder(TermOrder.INVLEX); String[] vars = new String[]{ "z" }; mfac = new GenPolynomialRing(cfac, rl, to, vars); efac = new QuotientRing(mfac); } @Override protected void tearDown() { //efac.terminate(); efac = null; ComputerThreads.terminate(); } /** * Test quotient coefficient polynomial factorization. */ public void testQuotientFactorization() { Quotient a = efac.random(kl, ll, el, q); // will be irreducible most times //System.out.println("a = " + a); a = a.power(3); Quotient b = efac.random(kl, ll, el, q); // will be irreducible most times //System.out.println("b = " + b); Quotient c = a.multiply(b); //System.out.println("c = " + c); FactorFraction> engine = new FactorFraction>(efac); //System.out.println("engine = " + engine); SortedMap, Long> sm = engine.factors(c); //System.out.println("factors(c) = " + sm); if (c.isZERO()) { assertTrue("#facs == 0", sm.size() == 0); } else { assertTrue("#facs >= 1", sm.size() >= 1); } for (Quotient q : sm.keySet()) { assertTrue("irred(q): " + q, engine.isIrreducible(q)); } boolean t = engine.isFactorization(c, sm); //System.out.println("t = " + t); assertTrue("prod(factor(c)) == c", t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorGenericTest.java000066400000000000000000000103421445075545500246540ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor rational tests with JUnit. * @author Heinz Kredel */ public class FactorGenericTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorGenericTest object. * @param name String. */ public FactorGenericTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorGenericTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void xtestDummy() { } /** * Test generic factorization. * */ public void testGenericFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] var_w2 = new String[] { "w2" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, var_w2); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial w2 = pfac.parse(" w2^2 - 2 "); //System.out.println("w2 = " + w2); AlgebraicNumberRing a2fac = new AlgebraicNumberRing(w2, true); //System.out.println("a2fac = " + a2fac.toScript()); String[] var_x = new String[] { "x" }; GenPolynomialRing> apfac = new GenPolynomialRing>( a2fac, 1, to, var_x); //System.out.println("apfac = " + apfac.toScript()); QuotientRing> qfac = new QuotientRing>( apfac); //System.out.println("qfac = " + qfac.toScript()); String[] var_wx = new String[] { "wx" }; GenPolynomialRing>> pqfac = new GenPolynomialRing>>( qfac, 1, to, var_wx); //System.out.println("pqfac = " + pqfac.toScript()); GenPolynomial>> wx = pqfac.parse(" wx^2 - { x } "); //System.out.println("wx = " + wx); AlgebraicNumberRing>> axfac = new AlgebraicNumberRing>>( wx, true); //System.out.println("axfac = " + axfac.toScript()); String[] var_y = new String[] { "y" }; GenPolynomialRing>>> apqfac = new GenPolynomialRing>>>( axfac, 1, to, var_y); //System.out.println("apqfac = " + apqfac.toScript()); // ( y^2 - x ) * ( y^2 - 2 ), need {} for recursive coefficients GenPolynomial>>> f; f = apqfac.parse(" ( y^2 - { { x } } ) * ( y^2 - 2 )^2 "); //System.out.println("f = " + f); FactorAbstract>>> engine = FactorFactory .getImplementation(axfac); //System.out.println("engine = " + engine); SortedMap>>>, Long> F = engine .factors(f); //System.out.println("factors(f) = " + F); assertTrue("#facs >= 4", F.size() >= 4); boolean t = engine.isFactorization(f, F); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorIntegerTest.java000066400000000000000000000723641445075545500247110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.List; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; /** * Factor tests with JUnit. * @author Heinz Kredel */ public class FactorIntegerTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorIntegerTest object. * @param name String. */ public FactorIntegerTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorIntegerTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 5; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test integer monic factorization. */ public void testIntegerMonicFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(4); BigInteger one = cfac.getONE(); GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, new String[] { "x" }); FactorAbstract fac = new FactorInteger(); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial a = null; //pfac.random(kl,ll*(i+1),el*(i+1),q); GenPolynomial b = pfac.random(kl * 2, ll * (i), el * (i + 1), q); GenPolynomial c = pfac.random(kl, ll * (i), el * (i + 2), q); //b = pfac.parse("((x^2 + 1)*(x^2 - 111111111))"); //c = pfac.parse("(x^3 - 222222)"); if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } if (!c.leadingBaseCoefficient().isUnit()) { ExpVector e = c.leadingExpVector(); c.doPutToMap(e, one); } if (!b.leadingBaseCoefficient().isUnit()) { ExpVector e = b.leadingExpVector(); b.doPutToMap(e, one); } a = c.multiply(b); if (a.isConstant()) { continue; } //GreatestCommonDivisorAbstract engine = GCDFactory.getProxy(cfac); //a = engine.basePrimitivePart(a); // a = a.abs(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", " + b + " * " + c, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test integer factorization. */ public void testIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(4); //BigInteger one = cfac.getONE(); GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to); FactorAbstract fac = new FactorInteger(); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial a = null; //pfac.random(kl,ll*(i+1),el*(i+1),q); GenPolynomial b = pfac.random(kl * 2, ll * (i), el * (i + 1), q); GenPolynomial c = pfac.random(kl, ll * (i), el * (i + 2), q); if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); if (a.isConstant()) { continue; } //GreatestCommonDivisorAbstract engine = GCDFactory.getProxy(cfac); //a = engine.basePrimitivePart(a); // a = a.abs(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test integer factorization irreducible polynomial. */ public void testIntegerFactorizationIrred() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(4); //BigInteger one = cfac.getONE(); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); FactorAbstract fac = new FactorInteger(); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial a = pfac.random(kl, ll * (i + 1), el * (i + 1), q); a = pfac.parse("( x^8 - 40 x^6 + 352 x^4 - 960 x^2 + 576 )"); // Swinnerton-Dyer example if (a.isConstant()) { continue; } SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= 1) { assertTrue("#facs < " + facs, sm.size() >= 1); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test bi-variate integer factorization. */ public void testBivariateIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 2, to, vars); //FactorAbstract fac = new FactorInteger(); FactorInteger fac = new FactorInteger(); for (int i = 1; i < 2; i++) { GenPolynomial b = pfac.random(kl, 3, el, q / 2.0f); GenPolynomial c = pfac.random(kl, 2, el, q); GenPolynomial d = pfac.random(kl, 2, el, q); b = pfac.parse(" ( x y^2 - 1 ) "); c = pfac.parse(" ( 2 x y + 1 ) "); d = pfac.parse(" ( y^4 + 3 x )"); //b = pfac.parse(" ( y + x + 1 ) "); //c = pfac.parse(" ( y ) "); //d = pfac.parse(" ( 1 )"); GenPolynomial a; a = b.multiply(c).multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); List> sm = fac.factorsSquarefreeHensel(a); //System.out.println("sm = " + sm); //sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 3, sm = " + sm, sm.size() >= 3); } } /** * Test tri-variate integer factorization. */ public void ytestTrivariateIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; //vars = new String[] { "x", "y"}; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); //FactorAbstract fac = new FactorInteger(); FactorInteger fac = new FactorInteger(); for (int i = 1; i < 2; i++) { GenPolynomial b = pfac.random(kl, 3, el, q / 2.0f); GenPolynomial c = pfac.random(kl, 2, el, q); GenPolynomial d = pfac.random(kl, 2, el, q); b = pfac.parse(" ( 5 x y^2 - 1 ) "); c = pfac.parse(" ( 2 x y z^2 + 1 ) "); d = pfac.parse(" ( y^3 z + 3 x )"); GenPolynomial a; a = b.multiply(c).multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); List> sm = fac.factorsSquarefreeHensel(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 3, sm = " + sm, sm.size() >= 3); //sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); //t = fac.isFactorization(a, sm); //System.out.println("t = " + t); //assertTrue("prod(factor(a)) = a", t); } } /** * Test quad-variate integer factorization. */ public void ytestQuadvariateIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z", "w" }; //vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); //FactorAbstract fac = new FactorInteger(); FactorInteger fac = new FactorInteger(); for (int i = 1; i < 2; i++) { GenPolynomial b = pfac.random(kl, 3, el, q / 2.0f); GenPolynomial c = pfac.random(kl, 2, el, q); GenPolynomial d = pfac.random(kl, 2, el, q); b = pfac.parse(" ( 5 x y^2 - 1 ) "); c = pfac.parse(" ( 2 x z^2 + w^2 y ) "); d = pfac.parse(" ( y^3 z + 7 x )"); GenPolynomial a; a = b.multiply(c).multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); List> sm = fac.factorsSquarefreeHensel(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 3, sm = " + sm, sm.size() >= 3); //sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); //t = fac.isFactorization(a, sm); ////System.out.println("t = " + t); //assertTrue("prod(factor(a)) = a", t); } } /** * Test multivariate integer factorization. */ public void testMultivariateIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, to, vars); FactorAbstract fac = new FactorInteger(); for (int i = 1; i < 2; i++) { GenPolynomial b = pfac.random(kl, 3, el, q / 2.0f); GenPolynomial c = pfac.random(kl, 2, el, q); b = pfac.parse("( z - y )"); c = pfac.parse("( z + x )"); GenPolynomial a; // if ( !a.leadingBaseCoefficient().isUnit()) { // //continue; // //ExpVector e = a.leadingExpVector(); // //a.doPutToMap(e,cfac.getONE()); // } a = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } } /** * Test integer factorization, example 1 from Wang. */ public void testIntegerFactorizationEx1() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c, d; // (z + xy + 10)(xz + y + 30)(yz + x + 20), b = pfac.parse(" (z + x y + 10) "); c = pfac.parse(" (x z + y + 30) "); d = pfac.parse(" (y z + x + 20) "); a = b.multiply(c).multiply(d); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 3, sm = " + sm, sm.size() >= 3); } /** * Test integer factorization, example 2 from Wang. */ public void testIntegerFactorizationEx2() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c; // (x^3(z + y) + z - 11) (x^(z^2 + y^2) + y + 90), b = pfac.parse(" (x^3 (z + y) + z - 11) "); c = pfac.parse(" (x^2 (z^2 + y^2) + y + 90) "); a = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization, example 3 from Wang. */ public void testIntegerFactorizationEx3() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c; // (y z^3 + x y z + y^2 + x^3) (x (z^4 + 1) + z + x^3 y^2) b = pfac.parse(" (y z^3 + x y z + y^2 + x^3) "); c = pfac.parse(" (x (z^4 + 1) + z + x^3 y^2) "); a = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization, example 4 from Wang. */ public void testIntegerFactorizationEx4() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c, d, e; // (z^2 - x^3 y + 3) (z^2 + x y^3) (z^2 + x^3 y^4) (y^4 z^2 + x^2 z + 5) b = pfac.parse(" ( z^2 - x^3 y + 3 ) "); c = pfac.parse(" (z^2 + x y^3) "); d = pfac.parse(" (z^2 + x^3 y^4) "); e = pfac.parse(" (y^4 z^2 + x^2 z + 5) "); a = b.multiply(c).multiply(d).multiply(e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); //List> sm = fac.factorsRadical(a); // will check squarefree //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 4, sm = " + sm, sm.size() >= 4); } /** * Test integer factorization, example 5 from Wang. */ public void testIntegerFactorizationEx5() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z", "u" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c; // (z^2 + x^3 y^4 + u^2) ( (y^2 + x) z^2 + 3 u^2 x^3 y^4 z + 19 y^2) (u^2 y^4 z^2 + x^2 z + 5), b = pfac.parse(" (z^2 + x^3 y^4 + u^2) "); c = pfac.parse(" ( (y^2 + x ) z^2 + 3 u^2 x^3 y^4 z + 19 y^2 )"); //d = pfac.parse(" (u^2 y^4 z^2 + x^2 z + 5) "); a = b.multiply(c); // .multiply(d); // all factors need 256 sec //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization, example 6 from Wang. */ public void testIntegerFactorizationEx6() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z", "w" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c; // (w^4 z^3 -x y^2 z^2 - w^4 x^5 y^6 - w^2 x^3 y) (- x^5 z^3 + y z + x^2 y^3) // . (w^4 z^6 + y^2 z^3 - w^2 x^2 y^2 z^2 + x^5 z - x^4 y^2 - w^3 x^3 y) //b = pfac.parse(" (w^4 z^3 -x y^2 z^2 - w^4 x^5 y^6 - w^2 x^3 y) "); //c = pfac.parse(" (- x^5 z^3 + y z + x^2 y^3) "); //d = pfac.parse(" (w^4 z^6 + y^2 z^3 - w^2 x^2 y^2 z^2 + x^5 z - x^4 y^2 - w^3 x^3 y) "); // with smaller degrees: b = pfac.parse(" (w z^2 - x y^1 z^1 - w x^5 y^2 - w x^3 y) "); c = pfac.parse(" (- x^5 z^2 + y z + x^2 y^1) "); //d = pfac.parse(" (w z^3 + y^2 z^2 - w x^2 y^2 z^1 + x^5 - x^4 y^2 - w x^3 y) "); a = b.multiply(c); //.multiply(d); // all factors with small degrees need 684 sec //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //List> sm = fac.factorsSquarefreeHensel(a); List> sm = fac.factorsSquarefree(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization, example 7 from Wang. */ public void testIntegerFactorizationEx7() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y", "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a, b, c; // (z + y + x- 3)^3 (z + y + x-2)^2, b = pfac.parse(" ( (z + y^2 + x - 3 )^3 ) "); c = pfac.parse(" ( (z + y + x^2 - 2 )^2 ) "); a = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(a); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization. */ public void testIntegerFactorizationHk() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "t", "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a; // 2 t * x^2 + 5 x^2 - 4 t * x - 4 x - 6 t - 9 // 2 t * x^2 - 5 x^2 + 8 t * x - 5 x + 6 t // 7 t * x^3 + 7 x^3 + 7 t * x^2 + 7 x^2 + 8 x + 8 // = ( x + { 1 } ) ( { 7 t + 7 } x^2 + { 8 } ) // 4 t * x^3 + 6 x^3 + 4 t * x^2 + 9 x^2 + 2 x - 1 // 2 t * x^2 - 7 x^2 + 2 t * x - 11 x - 4 // conter example to Wangs condition: [2 , x, x + 1 ] // 3 x^4 - ( 7 t + 2 ) x^2 + ( 4 t^2 + 2 t ) //a = pfac.parse(" ( 2 t * x^2 + 5 x^2 - 4 t * x - 4 x - 6 t - 9 ) "); //a = pfac.parse(" ( 2 t * x^2 - 5 x^2 + 8 t * x - 5 x + 6 t ) "); //a = pfac.parse(" ( 7 t * x^3 + 7 x^3 + 7 t * x^2 + 7 x^2 + 8 x + 8 ) "); //a = pfac.parse(" ( 4 t * x^3 + 6 x^3 + 4 t * x^2 + 9 x^2 + 2 x - 1 ) "); //a = pfac.parse(" ( 2 t * x^2 - 7 x^2 + 2 t * x - 11 x - 4 ) "); // example to parts of Wangs condition: [2 , x, x + 1 ] a = pfac.parse(" ( 3 x^4 - ( 7 t + 2 ) x^2 + ( 4 t^2 + 2 t ) ) "); // was not applicable or failed for t < x //System.out.println("a = " + a); SortedMap, Long> sm = fac.factors(a); //System.out.println("sm = " + sm + ", a = " + a + ", pfac = " + pfac.toScript()); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization. */ public void testBivarIntegerFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorInteger fac = new FactorInteger(); GenPolynomial a; a = pfac.parse(" ( (5*y+2*x)*(5*y-2*x) ) "); // binomial formula //System.out.println("a = " + a); SortedMap, Long> sm = fac.factors(a); //System.out.println("sm = " + sm + ", a = " + a + ", pfac = " + pfac.toScript()); boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); a = pfac.parse(" ( (y-4*x)*(y-x) ) "); //System.out.println("a = " + a); sm = fac.factors(a); //System.out.println("sm = " + sm + ", a = " + a + ", pfac = " + pfac.toScript()); t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm = " + sm, sm.size() >= 2); } /** * Test integer factorization. Example (a+b*x) (c+d*x). */ public void testIntegerFactorizationProd() { //TermOrder to = TermOrderByName.GRLEX; //not working TermOrder to = TermOrderByName.INVLEX; BigInteger cfac = new BigInteger(1); String[] vars = new String[] { "a", "b", "c", "d", "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); //FactorInteger fac = new FactorInteger(); FactorAbstract fac = FactorFactory.getImplementation(cfac); //System.out.println("fac = " + fac); assertTrue("fac :: FactorInteger: " + fac, fac instanceof FactorInteger); GenPolynomial a, b, c; a = pfac.parse("a+b*x"); b = pfac.parse("c+d*x"); c = a.multiply(b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(c); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(c, sm); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm: " + sm, sm.size() >= 2); } /** * Test integer factorization. Example (e x + d) (c d x + a e). */ public void testIntegerFactorizationLoop() { TermOrder to = TermOrderByName.IGRLEX; //TermOrder to = TermOrderByName.GRLEX; // infinite loop, wrong termorder //TermOrder to = TermOrderByName.INVLEX; BigInteger cfac = BigInteger.ONE; String[] vars = new String[] { "a", "c", "d", "e", "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars.length, to, vars); FactorAbstract fac = FactorFactory.getImplementation(cfac); //System.out.println("fac = " + fac); assertTrue("fac :: FactorInteger: " + fac, fac instanceof FactorInteger); GenPolynomial a, b, c; a = pfac.parse("e * x + d"); b = pfac.parse("c * d * x + a * e"); c = a.multiply(b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(c); //System.out.println("sm = " + sm); boolean t = fac.isFactorization(c, sm); assertTrue("prod(factor(a)) = a", t); assertTrue("#facs < 2, sm: " + sm, sm.size() >= 2); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorModularTest.java000066400000000000000000000665711445075545500247220ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.List; import java.util.SortedMap; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.PrimeList; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Factor modular tests with JUnit. * @author Heinz Kredel */ public class FactorModularTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorModularTest object. * @param name String. */ public FactorModularTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorModularTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void testDummy() { } /** * Test modular factorization. */ public void testModularFactorization() { PrimeList pl = new PrimeList(PrimeList.Range.medium); TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(pl.get(3)); //System.out.println("cfac = " + cfac); GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to); FactorModular fac = new FactorModular(cfac); for (int i = 1; i < 4; i++) { int facs = 0; GenPolynomial a = null; //pfac.random(kl,ll*(i+1),el*(i+1),q); GenPolynomial b = pfac.random(kl, ll * (i + 1), el * (i + 1), q); GenPolynomial c = pfac.random(kl, ll * (i + 1), el * (i + 1), q); if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); if (a.isConstant()) { continue; } a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test modular factorization example. */ public void testModularFactorizationExam() { TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(7); //System.out.println("cfac = " + cfac); String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); FactorModular fac = new FactorModular(cfac); int facs = 3; GenPolynomial a = pfac.parse("(x^12+5)"); a = a.monic(); //System.out.println("\na = " + a); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } /** * Test modular factorization, case p = 2. */ public void testModular2Factorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(2L); //System.out.println("cfac = " + cfac); GenPolynomialRing pfac = new GenPolynomialRing(cfac, new String[] { "x" }, to); FactorModular fac = new FactorModular(cfac); for (int i = 1; i < 4; i++) { int facs = 0; GenPolynomial a = null; //pfac.random(kl,ll*(i+1),el*(i+1),q); GenPolynomial b = pfac.random(kl, ll * (i + 1), el * (i + 1), q); GenPolynomial c = pfac.random(kl, ll * (i + 1), el * (i + 1), q); if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); if (a.isConstant()) { continue; } //a = pfac.parse(" x**13 + x**11 + x**7 + x**3 + x "); a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test multivariate modular factorization. */ public void testMultivariateModularFactorization() { //PrimeList pl = new PrimeList(PrimeList.Range.small); TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(13); // pl.get(3), 7, 11, 13 GenPolynomialRing pfac = new GenPolynomialRing(cfac, rl, to); FactorModular fac = new FactorModular(cfac); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial a = null; //pfac.random(kl,ll*(i+1),el,q); GenPolynomial b = pfac.random(kl, 2, el, q); GenPolynomial c = pfac.random(kl, 2, el, q); if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); if (a.isConstant()) { continue; } //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test modular absolute factorization. */ public void testBaseModularAbsoluteFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(17); String[] alpha = new String[] { "alpha" }; //String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 4); agen = agen.sum(pfac.fromInteger(1)); // x^4 + 1 FactorModular engine = new FactorModular(cfac); FactorsMap F //= engine.baseFactorsAbsoluteSquarefree(agen); //= engine.baseFactorsAbsoluteIrreducible(agen); = engine.baseFactorsAbsolute(agen); //System.out.println("agen = " + agen); //System.out.println("F = " + F); boolean t = engine.isAbsoluteFactorization(F); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } /** * Berlekamp small odd prime factorization test. */ public void testFactorBerlekampSmallOdd() { int q = 11; //32003; //11; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("SmallOdd pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //System.out.println("A = " + A.toScript()); FactorAbstract bf = new FactorModularBerlekamp(pfac.coFac); List> factors = bf.baseFactorsSquarefree(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial B = pfac.random(5).monic(); GenPolynomial C = pfac.random(5).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefree(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp big odd prime factorization test. */ public void testFactorBerlekampBigOdd() { int q = 32003; //11; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("BigOdd pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //System.out.println("A = " + A.toScript()); //FactorAbstract bf = new FactorModularBerlekamp(pfac.coFac); FactorModularBerlekamp bf = new FactorModularBerlekamp(pfac.coFac); List> factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial B = pfac.random(5).monic(); GenPolynomial C = pfac.random(5).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp big even prime factorization test. */ public void testFactorBerlekampBigEven() { int q = 2; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("BigEven pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //GenPolynomial A = pfac.parse(" x**13 + x**11 + x**7 + x**3 + x "); //sm = {x=1, x^2 + x + 1 =6} //System.out.println("A = " + A.toScript()); //FactorAbstract bf = new FactorModularBerlekamp(pfac.coFac); FactorModularBerlekamp bf = new FactorModularBerlekamp(pfac.coFac); List> factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial B = pfac.random(10).monic(); GenPolynomial C = pfac.random(10).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp small even prime factorization test. */ public void testFactorBerlekampSmallEven() { int q = 2; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("SmallEven pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //GenPolynomial A = pfac.parse(" x**13 + x**11 + x**7 + x**3 + x "); //sm = {x=1, x^2 + x + 1 =6} //System.out.println("A = " + A.toScript()); //FactorAbstract bf = new FactorModularBerlekamp(pfac.coFac); FactorModularBerlekamp bf = new FactorModularBerlekamp(pfac.coFac); List> factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial B = pfac.random(10).monic(); GenPolynomial C = pfac.random(10).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp big even prime power factorization test. */ public void testFactorBerlekampBigEvenPower() { int q = 2; //int qp = 4; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing mfac = new GenPolynomialRing(mi, new String[] { "a" }); GenPolynomial amod = mfac.parse("a^4 + a + 1"); //AlgebraicNumberRing gf = PolyUfdUtil.algebraicNumberField(mi, qp); AlgebraicNumberRing gf = new AlgebraicNumberRing(amod, true); //System.out.println("gf(2^4) = " + gf.toScript()); GenPolynomialRing> pfac = new GenPolynomialRing>(gf, new String[] { "x" }); //System.out.println("BigEvenPower pfac = " + pfac.toScript()); //GenPolynomial> A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); GenPolynomial> A = pfac .parse("x^5 + (a^3 + a + 1) x^4 + (a^3 + a^2 + 1) x^3 + ( a ) x + (a^3 + a + 1)"); //System.out.println("A = " + A.toScript()); //FactorAbstract> bf = new FactorModularBerlekamp>(pfac.coFac); FactorModularBerlekamp> bf = new FactorModularBerlekamp>( pfac.coFac); List>> factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial> B = pfac.random(5).monic(); GenPolynomial> C = pfac.random(7).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp small even prime power factorization test. */ public void testFactorBerlekampSmallEvenPower() { int q = 2; //int qp = 4; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing mfac = new GenPolynomialRing(mi, new String[] { "a" }); GenPolynomial amod = mfac.parse("a^4 + a + 1"); //AlgebraicNumberRing gf = PolyUfdUtil.algebraicNumberField(mi, qp); AlgebraicNumberRing gf = new AlgebraicNumberRing(amod, true); //System.out.println("gf(2^4) = " + gf.toScript()); GenPolynomialRing> pfac = new GenPolynomialRing>(gf, new String[] { "x" }); //System.out.println("SmallEvenPower pfac = " + pfac.toScript()); //GenPolynomial> A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); GenPolynomial> A = pfac .parse("x^5 + (a^3 + a + 1) x^4 + (a^3 + a^2 + 1) x^3 + ( a ) x + (a^3 + a + 1)"); //System.out.println("A = " + A.toScript()); //FactorAbstract> bf = new FactorModularBerlekamp>(pfac.coFac); FactorModularBerlekamp> bf = new FactorModularBerlekamp>( pfac.coFac); List>> factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial> B = pfac.random(5).monic(); GenPolynomial> C = pfac.random(7).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp small odd prime power factorization test. */ public void testFactorBerlekampSmallOddPower() { int q = 3; int qp = 4; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing mfac = new GenPolynomialRing(mi, new String[] { "a" }); //GenPolynomial amod = mfac.parse("a^4 + a + 1"); //AlgebraicNumberRing gf = new AlgebraicNumberRing(amod, true); AlgebraicNumberRing gf = PolyUfdUtil.algebraicNumberField(mfac, qp); //System.out.println("gf(2^4) = " + gf.toScript()); GenPolynomialRing> pfac = new GenPolynomialRing>(gf, new String[] { "x" }); //System.out.println("SmallOddPower pfac = " + pfac.toScript()); //GenPolynomial> A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); GenPolynomial> A = pfac .parse("x^5 + (a^3 + a + 1) x^4 + (a^3 + a^2 + 1) x^3 + ( a ) x + (a^3 + a + 1)"); //System.out.println("A = " + A.toScript()); //FactorAbstract> bf = new FactorModularBerlekamp>(pfac.coFac); FactorModularBerlekamp> bf = new FactorModularBerlekamp>( pfac.coFac); List>> factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial> B = pfac.random(5).monic(); GenPolynomial> C = pfac.random(7).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeSmallPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Berlekamp big odd prime power factorization test. */ public void testFactorBerlekampBigOddPower() { int q = 3; int qp = 4; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing mfac = new GenPolynomialRing(mi, new String[] { "a" }); //GenPolynomial amod = mfac.parse("a^4 + a + 1"); //AlgebraicNumberRing gf = new AlgebraicNumberRing(amod, true); AlgebraicNumberRing gf = PolyUfdUtil.algebraicNumberField(mfac, qp); //System.out.println("gf(2^4) = " + gf.toScript()); GenPolynomialRing> pfac = new GenPolynomialRing>(gf, new String[] { "x" }); //System.out.println("BigOddPower pfac = " + pfac.toScript()); //GenPolynomial> A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); GenPolynomial> A = pfac .parse("x^5 + (a^3 + a + 1) x^4 + (a^3 + a^2 + 1) x^3 + ( a ) x + (a^3 + a + 1)"); //System.out.println("A = " + A.toScript()); //FactorAbstract> bf = new FactorModularBerlekamp>(pfac.coFac); FactorModularBerlekamp> bf = new FactorModularBerlekamp>( pfac.coFac); List>> factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); GenPolynomial> B = pfac.random(5).monic(); GenPolynomial> C = pfac.random(7).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); factors = bf.baseFactorsSquarefreeBigPrime(A); //System.out.println("factors = " + factors + "\n"); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); } /** * Compare Berlekamp with other factorization test. */ public void testCompareFactorBerlekamp() { int q = 32003; //11; 29; ModIntRing mi = new ModIntRing(q); //System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("time pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //System.out.println("A = " + A.toScript()); FactorAbstract df = new FactorModular(pfac.coFac); FactorModularBerlekamp bf = new FactorModularBerlekamp(pfac.coFac); SortedMap, Long> factors, f2; GenPolynomial B = pfac.random(kl, ll * ll + 20, el * el + 10, q + q).monic(); GenPolynomial C = pfac.random(kl, ll * ll + 20, el * el + 10, q + q).monic(); A = B.multiply(C); //System.out.println("A = " + A.toScript()); //System.out.println("B = " + B.toScript()); //System.out.println("C = " + C.toScript()); long tb = System.currentTimeMillis(); factors = bf.baseFactors(A); tb = System.currentTimeMillis() - tb; assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); //System.out.println("factors = " + factors + "\n"); long td = System.currentTimeMillis(); f2 = df.baseFactors(A); td = System.currentTimeMillis() - td; //System.out.println("tberle = " + tb + ", tdd = " + td + "\n"); assertEquals("factors == f2: ", factors, f2); //System.out.println("isFactorization = " + bf.isFactorization(A,factors)); assertTrue("A == prod(factors): " + factors, bf.isFactorization(A, factors)); assertTrue("t >= 0: " + tb + ", " + td, tb >= 0 && td >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorMoreTest.java000066400000000000000000000403711445075545500242070ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.List; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Factor tests with JUnit. * @author Heinz Kredel * @author Axel Kramer */ public class FactorMoreTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorTest object. * @param name String. */ public FactorMoreTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorMoreTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void testDummy() { } /** * Test integral function factorization. */ public void testIntegralFunctionFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] qvars = new String[] { "t" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, qvars); GenPolynomial t = pfac.univariate(0); FactorAbstract fac = new FactorRational(); String[] vars = new String[] { "x" }; GenPolynomialRing> pqfac = new GenPolynomialRing>( pfac, 1, to, vars); GenPolynomial> x = pqfac.univariate(0); GenPolynomial> x2 = pqfac.univariate(0, 2); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> b = pqfac.random(2, 3, el, q); //b = b.monic(); //b = b.multiply(b); GenPolynomial> c = pqfac.random(2, 3, el, q); //c = c.monic(); if (c.degree() < 1) { c = x2.subtract(pqfac.getONE().multiply(t)); } if (b.degree() < 1) { b = x.sum(pqfac.getONE()); } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap>, Long> sm = fac.recursiveFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", sm = " + sm + ", c*b: " + c + " * " + b, sf >= facs); } boolean tt = fac.isRecursiveFactorization(a, sm); //System.out.println("t = " + tt); assertTrue("prod(factor(a)) = a", tt); } ComputerThreads.terminate(); } /** * Test integer integral function factorization. */ public void testIntegerIntegralFunctionFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] qvars = new String[] { "t" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, qvars); GenPolynomial t = pfac.univariate(0); FactorAbstract fac = new FactorInteger(); String[] vars = new String[] { "x" }; GenPolynomialRing> pqfac = new GenPolynomialRing>( pfac, 1, to, vars); GenPolynomial> x = pqfac.univariate(0); GenPolynomial> x2 = pqfac.univariate(0, 2); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> b = pqfac.random(2, 3, el, q); //b = b.monic(); //b = b.multiply(b); GenPolynomial> c = pqfac.random(2, 3, el, q); //c = c.monic(); if (c.degree() < 1) { c = x2.subtract(pqfac.getONE().multiply(t)); } if (b.degree() < 1) { b = x.sum(pqfac.getONE()); } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //a = pqfac.parse("( ( -26 t - 91 ) x^3 - ( 13 t + 26 ) x^2 + ( 6 t^2 + 21 t ) x + ( 3 t^2 + 6 t ) )"); //a = pqfac.parse("( -3 x^3 + ( t - 1 ) x^2 + ( 3 t ) x - ( t^2 - t ) )"); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap>, Long> sm = fac.recursiveFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", sm = " + sm + ", c*b: " + c + " * " + b, sf >= facs); } boolean tt = fac.isRecursiveFactorization(a, sm); //System.out.println("t = " + tt); assertTrue("prod(factor(a)) = a", tt); } ComputerThreads.terminate(); } /** * Test rational function factorization. */ public void testRationalFunctionFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] qvars = new String[] { "t" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, qvars); QuotientRing qfac = new QuotientRing(pfac); Quotient t = qfac.generators().get(1); FactorQuotient fac = new FactorQuotient(qfac); String[] vars = new String[] { "x" }; GenPolynomialRing> pqfac = new GenPolynomialRing>(qfac, 1, to, vars); GenPolynomial> x = pqfac.univariate(0); GenPolynomial> x2 = pqfac.univariate(0, 2); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> b = pqfac.random(2, 3, el, q); //b = b.monic(); //b = b.multiply(b); GenPolynomial> c = pqfac.random(2, 3, el, q); //c = c.monic(); if (c.degree() < 1) { c = x2.subtract(pqfac.getONE().multiply(t)); } if (b.degree() < 1) { b = x.sum(pqfac.getONE()); } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap>, Long> sm = fac.factors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", sm = " + sm + ", c*b: " + c + " * " + b, sf >= facs); } boolean tt = fac.isFactorization(a, sm); //System.out.println("t = " + tt); assertTrue("prod(factor(a)) = a", tt); } ComputerThreads.terminate(); } /** * Test modular rational function factorization. */ public void testModularRationalFunctionFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); ModIntegerRing cfac = new ModIntegerRing(19, true); String[] qvars = new String[] { "t" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, qvars); QuotientRing qfac = new QuotientRing(pfac); Quotient t = qfac.generators().get(1); FactorQuotient fac = new FactorQuotient(qfac); String[] vars = new String[] { "x" }; GenPolynomialRing> pqfac = new GenPolynomialRing>(qfac, 1, to, vars); GenPolynomial> x = pqfac.univariate(0); GenPolynomial> x2 = pqfac.univariate(0, 2); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> b = pqfac.random(2, 3, el, q); //b = b.monic(); //b = b.multiply(b); GenPolynomial> c = pqfac.random(2, 3, el, q); //c = c.monic(); if (c.degree() < 1) { c = x2.subtract(pqfac.getONE().multiply(t)); } if (b.degree() < 1) { b = x.sum(pqfac.getONE()); } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap>, Long> sm = fac.factors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", sm = " + sm + ", c*b: " + c + " * " + b, sf >= facs); } boolean tt = fac.isFactorization(a, sm); //System.out.println("t = " + tt); assertTrue("prod(factor(a)) = a", tt); } ComputerThreads.terminate(); } /** * Test cyclotomic polynomial factorization. */ public void testCyclotomicPolynomialFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigInteger cfac = new BigInteger(1); String[] qvars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, qvars); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial r = pfac.univariate(0, 2).subtract(pfac.getONE()); //System.out.println("r = " + r); GenPolynomial q = r.inflate(3); //System.out.println("q = " + q); assertTrue("q != 0: ", !q.isZERO()); GenPolynomial h; h = CycloUtil.cyclotomicPolynomial(pfac, 100L); //System.out.println("h = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); h = CycloUtil.cyclotomicPolynomial(pfac, 258L); //System.out.println("h = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); List> H; H = CycloUtil.cyclotomicDecompose(pfac, 100L); //System.out.println("H = " + H); for (GenPolynomial hp : H) { assertTrue("isCyclotomicPolynomial: " + hp, CycloUtil.isCyclotomicPolynomial(hp)); } H = CycloUtil.cyclotomicDecompose(pfac, 258L); //System.out.println("H = " + H); //System.out.println(""); for (GenPolynomial hp : H) { assertTrue("isCyclotomicPolynomial: " + hp, CycloUtil.isCyclotomicPolynomial(hp)); } //FactorAbstract fac = new FactorInteger(); //Map, Long> F; h = pfac.univariate(0, 20).subtract(pfac.getONE()); //System.out.println("hc = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); H = CycloUtil.cyclotomicFactors(h); //System.out.println("H = " + H); //System.out.println("factors = " + fac.factors(h)); //System.out.println("H = " + H); //System.out.println(""); h = pfac.univariate(0, 20).sum(pfac.getONE()); //System.out.println("hc = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); H = CycloUtil.cyclotomicFactors(h); //System.out.println("H = " + H); //System.out.println("factors = " + fac.factors(h)); //System.out.println("H = " + H); for (long n = 1L; n < 1L; n++) { h = CycloUtil.cyclotomicPolynomial(pfac, n); //F = fac.factors(h); //System.out.println("factors = " + F.size()); //System.out.println("h(" + n + ") = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); } h = pfac.univariate(0, 258).subtract(pfac.getONE()); //h = pfac.univariate(0, 2).sum(pfac.getONE()); //h = pfac.parse("x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1"); // yes //h = pfac.parse("x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1"); // no //System.out.println("hc = " + h); assertTrue("isCyclotomicPolynomial: " + h, CycloUtil.isCyclotomicPolynomial(h)); } /** * Test factorization over integers. */ public void testFactorizationInteger() { String str = "-2*m1*m2*u1*u2+m1*m2*u2^2-m2^2*u2^2+2*m1*m2*u1*v2+2*m2^2*u2*v2-m1*m2*v2^2-m2^2*v2^2"; //"m2 * v2 + m1 * v2 - m2 * u2 + m1 * u2 - 2 m1 * u1"; //"-2*m1*u1*u2+m1*u2^2-m2*u2^2+2*m1*u1*v2+2*m2*u2*v2-m1*v2^2-m2^2*v2^2"; String[] vars = new String[] { "m1", "m2", "u1", "u2", "v2" }; GenPolynomialRing fac; fac = new GenPolynomialRing(BigInteger.ONE, vars.length, new TermOrder(TermOrder.INVLEX), vars); GenPolynomial poly = fac.parse(str); //GenPolynomial p2 = fac.parse("m2"); //GenPolynomial p3 = fac.parse("v2-u2"); //poly = poly.multiply(p3); final int loops = 10; //0000; //System.out.println("Run: " + loops + ": -" + poly.toString()); for (int i = 0; i < loops; i++) { FactorAbstract factorAbstract = FactorFactory.getImplementation(BigInteger.ZERO); SortedMap, Long> map = factorAbstract.factors(poly); //System.out.println("Factors: " + map.toString()); //System.out.println("isFactorization = " + factorAbstract.isFactorization(poly,map)); assertTrue("isFactorization: ", factorAbstract.isFactorization(poly, map)); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorQuotientTest.java000066400000000000000000000054061445075545500251150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor quotient tests with JUnit. * @author Heinz Kredel */ public class FactorQuotientTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorQuotientTest object. * @param name String. */ public FactorQuotientTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorQuotientTest.class); return suite; } int rl = 1; int kl = 3; int ll = 3; int el = 3; float q = 0.4f; QuotientRing efac; GenPolynomialRing mfac; @Override protected void setUp() { BigRational cfac = new BigRational(1); TermOrder to = new TermOrder(TermOrder.INVLEX); mfac = new GenPolynomialRing(cfac, rl, to); efac = new QuotientRing(mfac); } @Override protected void tearDown() { //efac.terminate(); efac = null; ComputerThreads.terminate(); } /** * Test dummy for Junit. * */ public void xtestDummy() { } /** * Test quotient coefficient polynomial factorization. * */ public void testQuotientFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); //BigRational cfac = new BigRational(1); String[] var_x = new String[] { "x" }; GenPolynomialRing> pfac = new GenPolynomialRing>(efac, 1, to, var_x); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial> a = pfac.random(kl, ll, el, q); // will be irreducible most times //System.out.println("a = " + a); a = a.multiply(a.sum(pfac.getONE())); //System.out.println("a = " + a); FactorAbstract> engine = FactorFactory.getImplementation(efac); //System.out.println("engine = " + engine); SortedMap>, Long> sm = engine.factors(a); //System.out.println("factors(a) = " + sm); assertTrue("#facs >= 1", sm.size() >= 1); boolean t = engine.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorRationalTest.java000066400000000000000000000164141445075545500250570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; /** * Factor rational tests with JUnit. * @author Heinz Kredel */ public class FactorRationalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorRationalTest object. * @param name String. */ public FactorRationalTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorRationalTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test rational univariate factorization. */ public void testRationalFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to); FactorRational fac = new FactorRational(); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial a; GenPolynomial c = pfac.random(kl - 2, ll * i, el + i, q); // a = a.monic(); GenPolynomial b = pfac.random(kl - 2, ll, el, q); //b = b.monic(); // if ( false && ! a.leadingBaseCoefficient().isONE() ) { //continue; //ExpVector e = a.leadingExpVector(); //a.doPutToMap(e,cfac.getONE()); //} if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", b = " + b + ", c = " + c + ", sm = " + sm, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test rational multivariate factorization. */ public void testRationalMultiFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); GenPolynomialRing pfac = new GenPolynomialRing(cfac, 2, to); FactorRational fac = new FactorRational(); for (int i = 1; i < 3; i++) { int facs = 0; GenPolynomial a; GenPolynomial c = pfac.random(kl - 2, ll * i, el + i, q); // a = a.monic(); GenPolynomial b = pfac.random(kl - 2, ll, el, q); //b = b.monic(); // if ( false && ! a.leadingBaseCoefficient().isONE() ) { //continue; //ExpVector e = a.leadingExpVector(); //a.doPutToMap(e,cfac.getONE()); //} if (b.isZERO() || c.isZERO()) { continue; } if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } a = c.multiply(b); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); SortedMap, Long> sm = fac.factors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { long sf = 0; for (Long e : sm.values()) { sf += e; } assertTrue("#facs < " + facs + ", b = " + b + ", c = " + c + ", sm = " + sm, sf >= facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } /** * Test rational absolute factorization. */ public void testBaseRationalAbsoluteFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; //String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 4); agen = agen.sum(pfac.fromInteger(4)); // x^4 + 4 FactorRational engine = new FactorRational(); FactorsMap F //= engine.baseFactorsAbsoluteSquarefree(agen); //= engine.baseFactorsAbsoluteIrreducible(agen); = engine.baseFactorsAbsolute(agen); //System.out.println("agen = " + agen); //System.out.println("F = " + F); boolean t = engine.isAbsoluteFactorization(F); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } /** * Test rational absolute factorization. */ public void testRationalAbsoluteFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] vars = new String[] { "x", "y" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 2, to, vars); GenPolynomial xp = pfac.univariate(0, 2); GenPolynomial yp = pfac.univariate(1, 2); GenPolynomial g = xp.sum(yp); // x^2 + y^2 //GenPolynomial g = xp.subtract(yp); // x^2 - y^2 FactorRational engine = new FactorRational(); FactorsMap F //= engine.baseFactorsAbsoluteSquarefree(agen); //= engine.baseFactorsAbsoluteIrreducible(agen); = engine.factorsAbsolute(g); //System.out.println("g = " + g); //System.out.println("F = " + F); boolean t = engine.isAbsoluteFactorization(F); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/FactorTest.java000066400000000000000000000300361445075545500233610ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Factor tests with JUnit. * @see edu.jas.application.FactorTest * @author Heinz Kredel */ public class FactorTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorTest object. * @param name String. */ public FactorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test factory, typed implementation. */ public void testFactory() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation(mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); ModLongRing ml = new ModLongRing(19, true); Factorization ufdml = FactorFactory.getImplementation(ml); //System.out.println("ufdml = " + ufdml); assertTrue("ufd != Modular " + ufdml, ufdml instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation(bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation(br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory.getImplementation(am); //System.out.println("ufdam = " + ufdam); //assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorModularBerlekamp); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory.getImplementation(ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory.getImplementation(qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); } /** * Test factory generic implementation. */ @SuppressWarnings("unchecked") public void testFactoryGeneric() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation((RingFactory) mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation((RingFactory) bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation((RingFactory) br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory.getImplementation((RingFactory) am); //System.out.println("ufdam = " + ufdam); //assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorModularBerlekamp); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory.getImplementation((RingFactory) ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory.getImplementation((RingFactory) qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Factorization> ufdqm = FactorFactory.getImplementation((RingFactory) qmfac); //System.out.println("ufdqm = " + ufdqm); assertTrue("ufd != Quotient " + ufdqm, ufdqm instanceof FactorQuotient); prfac = new GenPolynomialRing(br, 2); GenPolynomialRing> rrfac = new GenPolynomialRing>( prfac, 1); Factorization ufdrr = FactorFactory.getImplementation((RingFactory) rrfac); //System.out.println("ufdrr = " + ufdrr); assertTrue("ufd != GenPolynomial> " + ufdrr, ufdrr instanceof FactorRational); } /** * Test factory specific implementation. */ public void testFactorySpecific() { ModIntegerRing mi = new ModIntegerRing(19, true); Factorization ufdm = FactorFactory.getImplementation(mi); //System.out.println("ufdm = " + ufdm); assertTrue("ufd != Modular " + ufdm, ufdm instanceof FactorModular); BigInteger bi = new BigInteger(1); Factorization ufdi = FactorFactory.getImplementation(bi); //System.out.println("ufdi = " + ufdi); assertTrue("ufd != Integer " + ufdi, ufdi instanceof FactorInteger); BigRational br = new BigRational(1); Factorization ufdr = FactorFactory.getImplementation(br); //System.out.println("ufdr = " + ufdr); assertTrue("ufd != Rational " + ufdr, ufdr instanceof FactorRational); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Factorization> ufdam = FactorFactory. getImplementation(am); //System.out.println("ufdam = " + ufdam); //assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorAlgebraic); assertTrue("ufd != AlgebraicNumber " + ufdam, ufdam instanceof FactorModularBerlekamp); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Factorization> ufdar = FactorFactory. getImplementation(ar); //System.out.println("ufdar = " + ufdar); assertTrue("ufd != AlgebraicNumber " + ufdar, ufdar instanceof FactorAlgebraic); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Factorization> ufdqr = FactorFactory. getImplementation(qrfac); //System.out.println("ufdqr = " + ufdqr); assertTrue("ufd != Quotient " + ufdqr, ufdqr instanceof FactorQuotient); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Factorization> ufdqm = FactorFactory. getImplementation(qmfac); //System.out.println("ufdqm = " + ufdqm); assertTrue("ufd != Quotient " + ufdqm, ufdqm instanceof FactorQuotient); prfac = new GenPolynomialRing(br, 2); //GenPolynomialRing> rrfac = new GenPolynomialRing>( // prfac, 1); Factorization ufdrr = FactorFactory. getImplementation(prfac); //System.out.println("ufdrr = " + ufdrr); assertTrue("ufd != GenPolynomial> " + ufdrr, ufdrr instanceof FactorRational); } /** * Test rational absolute factorization, for elementary integration. */ public void testBaseRationalAbsoluteFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); //String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "x" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, vars); GenPolynomial agen = pfac.univariate(0, 4); agen = agen.sum(pfac.fromInteger(4)); // x^4 + 4 // GenPolynomial x6 = pfac.univariate(0, 6); // GenPolynomial x4 = pfac.univariate(0, 4); // GenPolynomial x2 = pfac.univariate(0, 2); // // x^6 - 5 x^4 + 5 x^2 + 4 // agen = x6.subtract(x4.multiply(pfac.fromInteger(5))); // agen = agen.sum(x2.multiply(pfac.fromInteger(5))); // agen = agen.sum(pfac.fromInteger(4)); // GenPolynomial x3 = pfac.univariate(0, 3); // GenPolynomial x = pfac.univariate(0); // // x^3 + x // agen = x3.sum(x); // GenPolynomial x2 = pfac.univariate(0, 2); // // x^2 - 2 // agen = x2.subtract(pfac.fromInteger(2)); GenPolynomial N = pfac.getONE(); FactorRational engine = new FactorRational(); PartialFraction F = engine.baseAlgebraicPartialFraction(N, agen); //System.out.println("\npartial fraction: " + F.toScript()); assertTrue("is partial fraction: " + F, F.isPartialFraction()); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDFactoryTest.java000066400000000000000000000136441445075545500240760ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GreatestCommonDivisor factory tests with JUnit. * @author Heinz Kredel */ public class GCDFactoryTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDFactoryTest object. * @param name String. */ public GCDFactoryTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDFactoryTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; //BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; //GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; } /** * Test get BigInteger implementation. */ public void testBigInteger() { BigInteger bi = new BigInteger(); GreatestCommonDivisor ufd; ufd = GCDFactory.getImplementation(bi); //System.out.println("ufd = " + ufd); assertTrue("ufd = Modular " + ufd, ufd instanceof GreatestCommonDivisorModular); } /** * Test get ModInteger implementation. */ public void testModInteger() { ModIntegerRing mi = new ModIntegerRing(19, true); GreatestCommonDivisor ufd; ufd = GCDFactory.getImplementation(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd != ModEval " + ufd, ufd instanceof GreatestCommonDivisorModEval); mi = new ModIntegerRing(30); ufd = GCDFactory.getImplementation(mi); //System.out.println("ufd = " + ufd); assertTrue("ufd != Subres " + ufd, ufd instanceof GreatestCommonDivisorSubres); } /** * Test get BigRational implementation. */ public void testBigRational() { BigRational b = new BigRational(); GreatestCommonDivisor ufd; ufd = GCDFactory.getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); GreatestCommonDivisor ufd; ufd = GCDFactory. getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd != Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<BigRational> implementation. */ public void testAlgebraicNumberBigRational() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); GreatestCommonDivisor> ufd; ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Subres " + ufd, ufd instanceof GreatestCommonDivisorSubres); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd1 = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<ModInteger> implementation. */ public void testAlgebraicNumberModInteger() { ModIntegerRing b = new ModIntegerRing(19, true); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isZERO() || mo.isONE() || mo.isConstant()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); AlgebraicNumber a = afac.getONE(); assertTrue("a == 1 " + a, a.isONE()); GreatestCommonDivisor> ufd; ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd2 = " + ufd); assertTrue("ufd = Subres " + ufd, ufd instanceof GreatestCommonDivisorSubres); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDHenselTest.java000066400000000000000000000233141445075545500237000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Hensel algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDHenselTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDHenselTest object. * @param name String. */ public GCDHenselTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDHenselTest.class); return suite; } GreatestCommonDivisorAbstract ufd; GreatestCommonDivisorAbstract ufd1; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; BigInteger cofac; //BigInteger ai, bi, ci, di, ei; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; GenPolynomial ac; GenPolynomial bc; GenPolynomial> ar, br, cr, dr, er; int rl = 3; String[] vars = { "x", "y", "z" }; int kl = 4; int ll = 5; int el = 4; //3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; cofac = new BigInteger(); ufd = new GreatestCommonDivisorHensel(); dfac = new GenPolynomialRing(cofac, rl, to, vars); } @Override protected void tearDown() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; ufd = null; dfac = null; } /** * Test Hensel algorithm gcd. */ public void testHenselGcd() { //GenPolynomialRing dfac = new GenPolynomialRing(cofac, rl, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); ExpVector ev = c.leadingExpVector(); if (ev != null) { c.doPutToMap(ev, dfac.coFac.getONE()); } if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); //.multiply(c); b = b.multiply(c); //System.out.println("a c = " + a); //System.out.println("b c = " + b); d = ufd.gcd(a, b); //d = ufd.baseGcd(a,b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + d + ", c = " + c, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e + ", d = " + d, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e + ", d = " + d, e.isZERO()); } } /** * Test linear Hensel algorithm gcd. */ public void ytestHenselLinearSubresGcd() { ufd1 = new GreatestCommonDivisorHensel(false); //GenPolynomialRing dfac = new GenPolynomialRing(cofac, rl, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); ExpVector ev = c.leadingExpVector(); if (ev != null) { c.doPutToMap(ev, dfac.coFac.getONE()); } if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); a = a.multiply(c); //.multiply(c); b = b.multiply(c); //System.out.println("a c = " + a); //System.out.println("b c = " + b); long t = System.currentTimeMillis(); d = ufd1.gcd(a, b); t = System.currentTimeMillis() - t; //d = ufd.baseGcd(a,b); long tq = System.currentTimeMillis(); e = ufd.gcd(a, b); tq = System.currentTimeMillis() - tq; //System.out.println("Hensel quadratic, time = " + tq); //System.out.println("Hensel linear, time = " + t); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): " + d + ", c = " + c, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a: " + e + ", d = " + d, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b: " + e + ", d = " + d, e.isZERO()); } } /** * Test Hensel gcd 3 variables. */ public void testHenselGCD3() { BigInteger ifa = new BigInteger(1); //dfac = new GenPolynomialRing(ifa, 2, to , new String[] {"x", "y" }); dfac = new GenPolynomialRing(ifa, 3, to, new String[] { "x", "y", "z" }); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + i, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); // make monic and c with univariate head term ExpVector ev = a.leadingExpVector(); if (ev != null) { a.doPutToMap(ev, ifa.getONE()); } ev = b.leadingExpVector(); if (ev != null) { b.doPutToMap(ev, ifa.getONE()); } ev = c.leadingExpVector(); if (ev != null) { //c.doPutToMap(ev,ifa.getONE()); } assertFalse("ev == null ", ev == null); if (ev.dependencyOnVariables().length > 1) { c = dfac.univariate(1); //getONE(); } //a = dfac.parse(" y^2 + 2 x y - 3 y + x^2 - 3 x - 4 "); //b = dfac.parse(" y^2 + 2 x y + 5 y + x^2 + 5 x + 4 "); //a = dfac.parse(" x + 2 y + z^2 + 5 "); //b = dfac.parse(" x - y - 3 + y z "); //c = dfac.parse(" x y + z^2 + y "); //a = dfac.parse("7 y^4 - (35 x^3 - 32) y^3 - 160 x^3 y^2 + (105 x^2 - 119) y + (480 x^2 - 544) "); //b = dfac.parse(" 7 y^4 + 39 y^3 + 32 y^2 "); //c = dfac.parse(" 7 y + 32 "); //a = dfac.parse(" ( -13 x^2 ) z^5 + ( 182 x^2 - 143 ) z^3 - ( x^2 * y^3 - 8 x^2 ) z^2 + ( 14 x^2 * y^3 - 11 y^3 - 112 x^2 + 88 ) "); //b = dfac.parse(" ( -13 x^3 * y^3 ) z^6 + ( 65 y ) z^4 - ( x^3 * y^6 - 8 x^3 * y^3 - 52 y^3 - 195 y + 156 ) z^3 + ( 5 y^4 - 40 y ) z + ( 4 y^6 + 15 y^4 - 44 y^3 - 120 y + 96 ) ) "); //c = dfac.parse(" 13 z^3 + y^3 - 8 "); //a = dfac.parse(" 3 z^3 + ( 4 y^2 + 25 x^3 + 16 x^2 + 25 ) z^2 - ( 84 y^4 - 22 x^3 * y^2 + 128 x^2 * y^2 + 138 y^2 - 52 x^6 - 71 x^5 + 35 x^4 - 109 x^3 + 59 x^2 + 18 ) z "); //b = dfac.parse(" 10 z^5 + ( 60 y^2 + 40 x^3 + 70 x^2 + 90 ) z^4 + ( 14 x + 3 ) z^2 + ( 84 x * y^2 + 18 y^2 + 56 x^4 + 110 x^3 + 21 x^2 + 126 x + 27 ) z "); //c = dfac.parse("z^2 + ( 6 y^2 + 4 x^3 + 7 x^2 + 9 ) z"); //a = a.abs(); //b = b.abs(); //c = c.abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e + ", d = " + d, e.isZERO()); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDModEvalTest.java000066400000000000000000000547351445075545500240240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.PrimeList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Modular Evaluation algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDModEvalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDModEvalTest object. * @param name String. */ public GCDModEvalTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDModEvalTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; PrimeList primes = new PrimeList(); ModIntegerRing mi; ModInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 3; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; //mi = new ModIntegerRing(primes.get(0),true); mi = new ModIntegerRing(19, true); //mi = new ModIntegerRing(19*17,true); // failing tests //mi = new ModIntegerRing(primes.get(0).multiply(primes.get(1)),false); // failing tests //ufd = new GreatestCommonDivisorPrimitive(); ufd = new GreatestCommonDivisorModEval(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(mi, rl, to, vars); cfac = new GenPolynomialRing(mi, rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); //System.out.println("mi = " + mi); } @Override protected void tearDown() { a = b = c = d = e = null; //ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; mi = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test modular evaluation gcd. */ public void testModEvalGcd() { //GreatestCommonDivisorAbstract ufd_me // = new GreatestCommonDivisorModEval(); for (int i = 0; i < 1; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test base quotioent and remainder. */ public void testBaseQR() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a).abs(); //c = ufd.basePrimitivePart(c); do { ci = mi.random(kl * (i + 2)); ci = ci.sum(mi.getONE()); } while (ci.isZERO()); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("ci = " + ci); if (a.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. baseSparsePseudoRemainder(b, c); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); b = a.multiply(ci); //System.out.println("b = " + b); d = b.divide(ci); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(b, c); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test base content and primitive part. */ public void testBaseContentPP() { for (int i = 0; i < 13; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); c = c.multiply(mi.random(kl * (i + 2))); if (c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ci = ufd.baseContent(c); d = ufd.basePrimitivePart(c); //System.out.println("c = " + c); //System.out.println("ci = " + ci); //System.out.println("d = " + d); a = d.multiply(ci); assertEquals("c == cont(c)pp(c)", c, a); } } /** * Test base gcd. */ public void testBaseGcd() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive quotioent and remainder. */ public void testRecursiveQR() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 1), ll + i, el + i, q); a = ufd.basePrimitivePart(a).abs(); c = dfac.random(kl * (i + 1), ll + i, el + i, q); c = ufd.basePrimitivePart(a).abs(); cr = PolyUtil. recursive(rfac, c); c = cfac.random(kl * (i + 1), ll + 2 * i, el + 2 * i, q); c = ufd.basePrimitivePart(c).abs(); ar = PolyUtil. recursive(rfac, a); //System.out.println("ar = " + ar); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("cr = " + cr); if (cr.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); br = ar.multiply(cr); //System.out.println("br = " + br); dr = PolyUtil. recursiveSparsePseudoRemainder(br, cr); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); br = ar.multiply(c); //System.out.println("br = " + br); dr = PolyUtil. recursiveDivide(br, c); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test recursive content and primitive part. */ public void testRecursiveContentPP() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 3; i++) { cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr); dr = ufd.recursivePrimitivePart(cr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); ar = dr.multiply(c); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test recursive gcd. */ public void testRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd. */ public void testArbitraryRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc), gcd, c " + er + ", " + dr + ", " + cr, er.isZERO()); } } /** * Test content and primitive part. */ public void testContentPP() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); if (c.isZERO()) { continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = ufd.content(c); e = a.extend(dfac, 0, 0L); b = ufd.primitivePart(c); //System.out.println("c = " + c); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("b = " + b); d = e.multiply(b); assertEquals("c == cont(c)pp(c)", d, c); } } /** * Test gcd 3 variables. */ public void testGCD3() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 4; i++) { a = dfac.random(kl, ll, el + i, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc), gcd, c " + e + ", " + d + ", " + c, e.isZERO()); } } /** * Test gcd. */ public void testGCD() { // dfac = new GenPolynomialRing(mi,3,to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test lcm. */ public void testLCM() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( a" + i + " ) <> 0", a.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); c = ufd.gcd(a, b); //System.out.println("c = " + c); d = ufd.lcm(a, b); //System.out.println("d = " + d); e = c.multiply(d); //System.out.println("e = " + e); c = a.multiply(b); //System.out.println("c = " + c); assertEquals("ab == gcd(a,b)lcm(ab)", c, e); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(mi, 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(d); F.add(a); F.add(b); F.add(c); F.add(e); //System.out.println("F = " + F); List> P = ufd.coPrime(F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); //P = ufd.coPrimeSquarefree(F); //System.out.println("F = " + F); //System.out.println("P = " + P); //assertTrue("is co-prime ", ufd.isCoPrime(P) ); //assertTrue("is co-prime of ", ufd.isCoPrime(P,F) ); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } /** * Test resultant. */ public void testResultant() { mi = new ModIntegerRing(163, true); dfac = new GenPolynomialRing(mi, 3, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModEval(); GreatestCommonDivisorSubres ufds = new GreatestCommonDivisorSubres(); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (c.isConstant()) { c = dfac.univariate(0, 1); } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); d = ufdm.resultant(a, b); //System.out.println("d = " + d); e = ufds.resultant(a, b); //System.out.println("e = " + e); assertEquals("d == e: " + d.subtract(e), d.abs().signum(), e.abs().signum()); //assertEquals("d == e: " + d.subtract(e), d, e); //System.out.println("c = " + c); GenPolynomial ac = a.multiply(c); GenPolynomial bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); d = ufdm.resultant(ac, bc); //System.out.println("d = " + d); //assertTrue("d == 0: " + d, d.isZERO()); e = ufds.resultant(ac, bc); //System.out.println("e = " + e); //assertTrue("e == 0: " + e, e.isZERO()); assertEquals("d == e: " + d.subtract(e), d.abs().signum(), e.abs().signum()); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDModLongEvalTest.java000066400000000000000000000506171445075545500246370ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.arith.PrimeList; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Modular Evaluation algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDModLongEvalTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDModLongEvalTest object. * @param name String. */ public GCDModLongEvalTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDModLongEvalTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; PrimeList primes = new PrimeList(); ModLongRing mi; ModLong ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 3; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; //mi = new ModLongRing(primes.get(0),true); mi = new ModLongRing(19, true); //mi = new ModLongRing(19*17,true); // failing tests //mi = new ModLongRing(primes.get(0).multiply(primes.get(1)),false); // failing tests //ufd = new GreatestCommonDivisorPrimitive(); ufd = new GreatestCommonDivisorModEval(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(mi, rl, to, vars); cfac = new GenPolynomialRing(mi, rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); //System.out.println("mi = " + mi); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; mi = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test modular evaluation gcd. */ public void testModEvalGcd() { //GreatestCommonDivisorAbstract ufd_me // = new GreatestCommonDivisorModEval(); for (int i = 0; i < 1; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test base quotioent and remainder. */ public void testBaseQR() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a).abs(); //c = ufd.basePrimitivePart(c); do { ci = mi.random(kl * (i + 2)); ci = ci.sum(mi.getONE()); } while (ci.isZERO()); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("ci = " + ci); if (a.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. baseSparsePseudoRemainder(b, c); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); b = a.multiply(ci); //System.out.println("b = " + b); d = b.divide(ci); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(b, c); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test base content and primitive part. */ public void testBaseContentPP() { for (int i = 0; i < 13; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); c = c.multiply(mi.random(kl * (i + 2))); if (c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ci = ufd.baseContent(c); d = ufd.basePrimitivePart(c); //System.out.println("c = " + c); //System.out.println("ci = " + ci); //System.out.println("d = " + d); a = d.multiply(ci); assertEquals("c == cont(c)pp(c)", c, a); } } /** * Test base gcd. */ public void testBaseGcd() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive quotioent and remainder. */ public void testRecursiveQR() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 1), ll + i, el + i, q); a = ufd.basePrimitivePart(a).abs(); c = dfac.random(kl * (i + 1), ll + i, el + i, q); c = ufd.basePrimitivePart(a).abs(); cr = PolyUtil. recursive(rfac, c); c = cfac.random(kl * (i + 1), ll + 2 * i, el + 2 * i, q); c = ufd.basePrimitivePart(c).abs(); ar = PolyUtil. recursive(rfac, a); //System.out.println("ar = " + ar); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("cr = " + cr); if (cr.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); br = ar.multiply(cr); //System.out.println("br = " + br); dr = PolyUtil. recursiveSparsePseudoRemainder(br, cr); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); br = ar.multiply(c); //System.out.println("br = " + br); dr = PolyUtil. recursiveDivide(br, c); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test recursive content and primitive part. */ public void testRecursiveContentPP() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 3; i++) { cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr); dr = ufd.recursivePrimitivePart(cr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); ar = dr.multiply(c); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test recursive gcd. */ public void testRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd. */ public void testArbitraryRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test content and primitive part. */ public void testContentPP() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); if (c.isZERO()) { continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = ufd.content(c); e = a.extend(dfac, 0, 0L); b = ufd.primitivePart(c); //System.out.println("c = " + c); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("b = " + b); d = e.multiply(b); assertEquals("c == cont(c)pp(c)", d, c); } } /** * Test gcd 3 variables. */ public void testGCD3() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 4; i++) { a = dfac.random(kl, ll, el + i, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc): c = " + c + ", d = " + d + ", " + e, e.isZERO()); } } /** * Test gcd. */ public void testGCD() { // dfac = new GenPolynomialRing(mi,3,to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e + ", " + c, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e + ", " + d, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e + ", " + d, e.isZERO()); } } /** * Test lcm. */ public void testLCM() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( a" + i + " ) <> 0", a.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); c = ufd.gcd(a, b); //System.out.println("c = " + c); d = ufd.lcm(a, b); //System.out.println("d = " + d); e = c.multiply(d); //System.out.println("e = " + e); c = a.multiply(b); //System.out.println("c = " + c); assertEquals("ab == gcd(a,b)lcm(ab)", c, e); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(mi, 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(d); F.add(a); F.add(b); F.add(c); F.add(e); List> P = ufd.coPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); //P = ufd.coPrimeSquarefree(F); //System.out.println("F = " + F); //System.out.println("P = " + P); //assertTrue("is co-prime ", ufd.isCoPrime(P) ); //assertTrue("is co-prime of ", ufd.isCoPrime(P,F) ); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDModLongTest.java000066400000000000000000000436621445075545500240310ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.arith.PrimeList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Modular algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDModLongTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDModularTest object. * @param name String. */ public GCDModLongTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDModLongTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; PrimeList primes = new PrimeList(); ModLongRing mi; ModLong ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial ac; GenPolynomial bc; GenPolynomial> ar, br, cr, dr, er; GenPolynomial> arc; GenPolynomial> brc; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; //mi = new ModLongRing(primes.get(0), true); mi = new ModLongRing(5L, true); ufd = new GreatestCommonDivisorPrimitive(); dfac = new GenPolynomialRing(mi, rl, to); cfac = new GenPolynomialRing(mi, rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test modular algorithm gcd with modular evaluation recursive algorithm. */ public void testModularEvaluationGcd() { GreatestCommonDivisorAbstract ufd_m = new GreatestCommonDivisorModular(); // dummy type GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; GenPolynomialRing dfac = new GenPolynomialRing(new BigInteger(), 3, to); for (int i = 0; i < 2; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd_m.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test modular algorithm gcd with simple PRS recursive algorithm. */ public void testModularSimpleGcd() { GreatestCommonDivisorAbstract ufd_m = new GreatestCommonDivisorModular(true); // dummy type GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; GenPolynomialRing dfac = new GenPolynomialRing(new BigInteger(), 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd_m.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test recursive content and primitive part, modular coefficients. */ public void testRecursiveContentPPmodular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { a = cfac.random(kl, ll + 2 * i, el + i, q).monic(); cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); cr = PolyUtil. monic(cr); //System.out.println("a = " + a); //System.out.println("cr = " + cr); //a = ufd.basePrimitivePart(a); //b = distribute(dfac,cr); //b = ufd.basePrimitivePart(b); //cr = recursive(rfac,b); //System.out.println("a = " + a); //System.out.println("cr = " + cr); cr = cr.multiply(a); //System.out.println("cr = " + cr); if (cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr).monic(); dr = ufd.recursivePrimitivePart(cr); dr = PolyUtil. monic(dr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); //System.out.println("monic(a) = " + a.monic()); //System.out.println("monic(c) = " + c.monic()); ar = dr.multiply(c); //System.out.println("ar = " + ar); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test base gcd modular coefficients. */ public void testGCDbaseModular() { dfac = new GenPolynomialRing(mi, 1, to); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + 3 + i, q).monic(); b = dfac.random(kl, ll, el + 3 + i, q).monic(); c = dfac.random(kl, ll, el + 3 + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); //e = PolyUtil.baseSparsePseudoRemainder(ac,c); //System.out.println("ac/c a = 0 " + e); //assertTrue("ac/c-a != 0 " + e, e.isZERO() ); //e = PolyUtil.baseSparsePseudoRemainder(bc,c); //System.out.println("bc/c-b = 0 " + e); //assertTrue("bc/c-b != 0 " + e, e.isZERO() ); d = ufd.baseGcd(ac, bc); d = d.monic(); // not required //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive gcd modular coefficients. */ public void testRecursiveGCDModular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); // GreatestCommonDivisorAbstract ufd // = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { ar = rfac.random(kl, 2, el + 2, q); br = rfac.random(kl, 2, el + 2, q); cr = rfac.random(kl, 2, el + 2, q); ar = PolyUtil. monic(ar); br = PolyUtil. monic(br); cr = PolyUtil. monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); arc = ar.multiply(cr); brc = br.multiply(cr); //System.out.println("arc = " + arc); //System.out.println("brc = " + brc); //er = PolyUtil.recursiveSparsePseudoRemainder(arc,cr); //System.out.println("ac/c-a = 0 " + er); //assertTrue("ac/c-a != 0 " + er, er.isZERO() ); //er = PolyUtil.recursiveSparsePseudoRemainder(brc,cr); //System.out.println("bc/c-b = 0 " + er); //assertTrue("bc/c-b != 0 " + er, er.isZERO() ); dr = ufd.recursiveUnivariateGcd(arc, brc); dr = PolyUtil. monic(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd modular coefficients. */ public void testArbitraryRecursiveGCDModular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); // GreatestCommonDivisorAbstract ufd // = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { ar = rfac.random(kl, 2, el + 2, q); br = rfac.random(kl, 2, el + 2, q); cr = rfac.random(kl, 2, el + 2, q); ar = PolyUtil. monic(ar); br = PolyUtil. monic(br); cr = PolyUtil. monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); arc = ar.multiply(cr); brc = br.multiply(cr); //System.out.println("arc = " + arc); //System.out.println("brc = " + brc); //er = PolyUtil.recursiveSparsePseudoRemainder(arc,cr); //System.out.println("ac/c-a = 0 " + er); //assertTrue("ac/c-a != 0 " + er, er.isZERO() ); //er = PolyUtil.recursiveSparsePseudoRemainder(brc,cr); //System.out.println("bc/c-b = 0 " + er); //assertTrue("bc/c-b != 0 " + er, er.isZERO() ); dr = ufd.recursiveGcd(arc, brc); dr = PolyUtil. monic(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test gcd modular coefficients. */ public void testGcdModular() { dfac = new GenPolynomialRing(mi, 4, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + i, q).monic(); b = dfac.random(kl, ll, el + i, q).monic(); c = dfac.random(kl, ll, el + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); //e = PolyUtil.baseSparsePseudoRemainder(ac,c); //System.out.println("ac/c-a = 0 " + e); //assertTrue("ac/c-a != 0 " + e, e.isZERO() ); //e = PolyUtil.baseSparsePseudoRemainder(bc,c); //System.out.println("bc/c-b = 0 " + e); //assertTrue("bc/c-b != 0 " + e, e.isZERO() ); d = ufd.gcd(ac, bc); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(ac, d); //System.out.println("gcd(ac,bc) | ac " + e); assertTrue("gcd(ac,bc) | ac " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(bc, d); //System.out.println("gcd(ac,bc) | bc " + e); assertTrue("gcd(ac,bc) | bc " + e, e.isZERO()); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(mi, 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(a); F.add(b); F.add(c); F.add(d); F.add(e); List> P = ufd.coPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDModularTest.java000066400000000000000000000612661445075545500240750ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.PrimeList; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Modular algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDModularTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDModularTest object. * @param name String. */ public GCDModularTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDModularTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; PrimeList primes = new PrimeList(); ModIntegerRing mi; ModInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial ac, bc; GenPolynomial> ar, br, cr, dr, er; GenPolynomial> arc, brc; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; //mi = new ModIntegerRing(primes.get(0), true); mi = new ModIntegerRing(19L, true); ufd = new GreatestCommonDivisorPrimitive(); dfac = new GenPolynomialRing(mi, rl, to); cfac = new GenPolynomialRing(mi, rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test modular algorithm gcd with modular evaluation recursive algorithm. */ public void testModularEvaluationGcd() { GreatestCommonDivisorAbstract ufd_m = new GreatestCommonDivisorModular(/*false*/); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); GenPolynomial a, b, c, d, e; GenPolynomialRing dfac = new GenPolynomialRing(new BigInteger(), 3, to); for (int i = 0; i < 2; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd_m.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test modular algorithm gcd with simple PRS recursive algorithm. */ public void testModularSimpleGcd() { GreatestCommonDivisorAbstract ufd_m = new GreatestCommonDivisorModular(true); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); GenPolynomial a, b, c, d, e; GenPolynomialRing dfac = new GenPolynomialRing(new BigInteger(), 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll + i, el + i, q); b = dfac.random(kl, ll + i, el + i, q); c = dfac.random(kl, ll + i, el + i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd_m.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test recursive content and primitive part, modular coefficients. */ public void testRecursiveContentPPmodular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { a = cfac.random(kl, ll + 2 * i, el + i, q).monic(); cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); cr = PolyUtil. monic(cr); //System.out.println("a = " + a); //System.out.println("cr = " + cr); //a = ufd.basePrimitivePart(a); //b = distribute(dfac,cr); //b = ufd.basePrimitivePart(b); //cr = recursive(rfac,b); //System.out.println("a = " + a); //System.out.println("cr = " + cr); cr = cr.multiply(a); //System.out.println("cr = " + cr); if (cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr).monic(); dr = ufd.recursivePrimitivePart(cr); dr = PolyUtil. monic(dr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); //System.out.println("monic(a) = " + a.monic()); //System.out.println("monic(c) = " + c.monic()); ar = dr.multiply(c); //System.out.println("ar = " + ar); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test base gcd modular coefficients. */ public void testGCDbaseModular() { dfac = new GenPolynomialRing(mi, 1, to); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + 3 + i, q).monic(); b = dfac.random(kl, ll, el + 3 + i, q).monic(); c = dfac.random(kl, ll, el + 3 + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); //e = PolyUtil.baseSparsePseudoRemainder(ac,c); //System.out.println("ac/c a = 0 " + e); //assertTrue("ac/c-a != 0 " + e, e.isZERO() ); //e = PolyUtil.baseSparsePseudoRemainder(bc,c); //System.out.println("bc/c-b = 0 " + e); //assertTrue("bc/c-b != 0 " + e, e.isZERO() ); d = ufd.baseGcd(ac, bc); d = d.monic(); // not required //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive gcd modular coefficients. */ public void testRecursiveGCDModular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); // GreatestCommonDivisorAbstract ufd // = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { ar = rfac.random(kl, 2, el + 2, q); br = rfac.random(kl, 2, el + 2, q); cr = rfac.random(kl, 2, el + 2, q); ar = PolyUtil. monic(ar); br = PolyUtil. monic(br); cr = PolyUtil. monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); arc = ar.multiply(cr); brc = br.multiply(cr); //System.out.println("arc = " + arc); //System.out.println("brc = " + brc); //er = PolyUtil.recursiveSparsePseudoRemainder(arc,cr); //System.out.println("ac/c-a = 0 " + er); //assertTrue("ac/c-a != 0 " + er, er.isZERO() ); //er = PolyUtil.recursiveSparsePseudoRemainder(brc,cr); //System.out.println("bc/c-b = 0 " + er); //assertTrue("bc/c-b != 0 " + er, er.isZERO() ); dr = ufd.recursiveUnivariateGcd(arc, brc); dr = PolyUtil. monic(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd modular coefficients. */ public void testArbitraryRecursiveGCDModular() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); // GreatestCommonDivisorAbstract ufd // = new GreatestCommonDivisorPrimitive(); for (int i = 0; i < 1; i++) { ar = rfac.random(kl, 2, el + 2, q); br = rfac.random(kl, 2, el + 2, q); cr = rfac.random(kl, 2, el + 2, q); ar = PolyUtil. monic(ar); br = PolyUtil. monic(br); cr = PolyUtil. monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); arc = ar.multiply(cr); brc = br.multiply(cr); //System.out.println("arc = " + arc); //System.out.println("brc = " + brc); //er = PolyUtil.recursiveSparsePseudoRemainder(arc,cr); //System.out.println("ac/c-a = 0 " + er); //assertTrue("ac/c-a != 0 " + er, er.isZERO() ); //er = PolyUtil.recursiveSparsePseudoRemainder(brc,cr); //System.out.println("bc/c-b = 0 " + er); //assertTrue("bc/c-b != 0 " + er, er.isZERO() ); dr = ufd.recursiveGcd(arc, brc); dr = PolyUtil. monic(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test gcd modular coefficients. */ public void testGcdModular() { dfac = new GenPolynomialRing(mi, 4, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + i, q).monic(); b = dfac.random(kl, ll, el + i, q).monic(); c = dfac.random(kl, ll, el + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); //e = PolyUtil.baseSparsePseudoRemainder(ac,c); //System.out.println("ac/c-a = 0 " + e); //assertTrue("ac/c-a != 0 " + e, e.isZERO() ); //e = PolyUtil.baseSparsePseudoRemainder(bc,c); //System.out.println("bc/c-b = 0 " + e); //assertTrue("bc/c-b != 0 " + e, e.isZERO() ); d = ufd.gcd(ac, bc); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(ac, d); //System.out.println("gcd(ac,bc) | ac " + e); assertTrue("gcd(ac,bc) | ac " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(bc, d); //System.out.println("gcd(ac,bc) | bc " + e); assertTrue("gcd(ac,bc) | bc " + e, e.isZERO()); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(mi, 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(a); F.add(b); F.add(c); F.add(d); F.add(e); List> P = ufd.coPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } /** * Test base resultant modular coefficients. */ public void testResultantBaseModular() { dfac = new GenPolynomialRing(mi, 1, to); GreatestCommonDivisorSimple ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorSubres sres = new GreatestCommonDivisorSubres(); for (int i = 0; i < 3; i++) { a = dfac.random(kl, ll, el + 3 + i, q).monic(); b = dfac.random(kl, ll, el + 3 + i, q).monic(); c = dfac.random(kl, ll, el + 3 + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (c.isConstant()) { c = dfac.univariate(0, 1); } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); d = ufds.baseResultant(a, b); //System.out.println("d = " + d); e = sres.baseResultant(a, b); //System.out.println("e = " + e); assertEquals("d == e: " + d.subtract(e), d.signum(), e.signum()); //assertEquals("d == e: " + d.subtract(e), d, e); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); d = ufds.baseResultant(ac, bc); //System.out.println("d = " + d); assertTrue("d == 0: " + d, d.isZERO()); e = sres.baseResultant(ac, bc); //System.out.println("e = " + e); assertTrue("e == 0: " + e, e.isZERO()); //assertEquals("d == e: " + d.subtract(e), d, e); } } /** * Test recursive resultant modular coefficients. */ public void testRecursiveResultantModular() { cfac = new GenPolynomialRing(mi, 2 - 0, to); rfac = new GenPolynomialRing>(cfac, 1, to); //System.out.println("rfac = " + rfac); GreatestCommonDivisorSimple ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorSubres sres = new GreatestCommonDivisorSubres(); for (int i = 0; i < 1; i++) { ar = rfac.random(kl, 2, el + 2, q); br = rfac.random(kl, 2, el + 3, q); cr = rfac.random(kl, 2, el + 1, q); ar = PolyUtil. monic(ar); br = PolyUtil. monic(br); cr = PolyUtil. monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } if (cr.isConstant()) { cr = rfac.univariate(0, 1); } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); dr = ufds.recursiveUnivariateResultant(ar, br); //System.out.println("dr = " + dr); er = sres.recursiveUnivariateResultant(ar, br); //System.out.println("er = " + er); assertEquals("dr == er: " + dr.subtract(er), dr.signum(), er.signum()); //assertEquals("dr == er: " + dr.subtract(er), dr, er); arc = ar.multiply(cr); brc = br.multiply(cr); //System.out.println("arc = " + arc); //System.out.println("brc = " + brc); dr = ufds.recursiveUnivariateResultant(arc, brc); //System.out.println("dr = " + dr); //assertTrue("dr == 0: " + dr, dr.isZERO()); er = sres.recursiveUnivariateResultant(arc, brc); //System.out.println("er = " + er); //assertTrue("er == 0: " + er, er.isZERO()); assertEquals("dr == er: " + dr.subtract(er), dr.signum(), er.signum()); } } /** * Test resultant modular coefficients. */ public void testResultantModular() { dfac = new GenPolynomialRing(mi, 4, to); //System.out.println("dfac = " + dfac); GreatestCommonDivisorSimple ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorSubres sres = new GreatestCommonDivisorSubres(); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + i, q).monic(); b = dfac.random(kl, ll, el + i, q).monic(); c = dfac.random(kl, ll, el + i, q).monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (c.isConstant()) { c = dfac.univariate(0, 1); } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); d = ufds.resultant(a, b); //System.out.println("d = " + d); e = sres.resultant(a, b); //System.out.println("e = " + e); assertEquals("d == e: " + d.subtract(e), d.signum(), e.signum()); //assertEquals("d == e: " + d.subtract(e), d, e); ac = a.multiply(c); bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); d = ufds.resultant(ac, bc); //System.out.println("d = " + d); //assertTrue("d == 0: " + d, d.isZERO()); e = sres.resultant(ac, bc); //System.out.println("e = " + e); //assertTrue("e == 0: " + e, e.isZERO()); assertEquals("d == e: " + d.subtract(e), d.signum(), e.signum()); } } /** * Test gcd example modular. */ public void testGCDExamModular() { GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorModular(); GenPolynomialRing dfac = new GenPolynomialRing(new BigInteger(1), new String[] { "t", "x" }, to); GenPolynomial a, b, d, e; a = dfac.parse("x**3 + x**2 - t * x - t"); b = dfac.parse("3 * x**2 + 2 * x - t"); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDPartFracRatTest.java000066400000000000000000000307571445075545500246440ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD partial fraction with rational coefficients algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDPartFracRatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDPartFracRatTest object. * @param name String. */ public GCDPartFracRatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDPartFracRatTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigRational mi; BigRational ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; //GenPolynomial> ar, br, cr, dr, er; int rl = 3; int kl = 2; int ll = 3; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; mi = new BigRational(1); ufd = new GreatestCommonDivisorSubres(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(mi, rl, to, vars); cfac = new GenPolynomialRing(mi, rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); //System.out.println("mi = " + mi); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; //ar = br = cr = dr = er = null; mi = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test base quotioent and remainder. */ public void testBaseQR() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a).abs(); //c = ufd.basePrimitivePart(c); do { ci = mi.random(kl * (i + 2)); ci = ci.sum(mi.getONE()); } while (ci.isZERO()); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("ci = " + ci); if (a.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. baseSparsePseudoRemainder(b, c); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); b = a.multiply(ci); //System.out.println("b = " + b); d = b.divide(ci); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(b, c); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c).sum(dfac.getONE()); //System.out.println("b = " + b); //System.out.println("c = " + c); GenPolynomial[] qr = PolyUtil. basePseudoQuotientRemainder(b, c); d = qr[0]; e = qr[1]; //System.out.println("d = " + d); //System.out.println("e = " + e); e = d.multiply(c).sum(e); //System.out.println("e = " + e); assertEquals("b == b/c + b%c ", b, e); } } /** * Test base extended gcd. */ public void testBaseExtGcd() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); GenPolynomial[] egcd = ufd.baseExtendedGcd(a, b); d = egcd[0]; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = egcd[1].multiply(a).sum(egcd[2].multiply(b)); assertEquals("gcd(a,b) = s a + t b ", d, e); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("d = " + d); GenPolynomial[] diop = ufd.baseGcdDiophant(a, b, d); e = diop[0].multiply(a).sum(diop[1].multiply(b)); //System.out.println("e = " + e); assertEquals("d*gcd(a,b) = s a + t b ", d, e); } } /** * Test base partial fraction. */ public void testBasePartFrac() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = dfac.random(kl, ll + 2 * i, el + 2 * i, q); //b = dfac.random(kl, ll + 2 * i, el + 2 * i, q); //c = dfac.random(kl, ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); if (b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (b.isConstant() || c.isConstant()) { // skip for this turn continue; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a / (b*c) = a0 + ap/b + as/c GenPolynomial gcd = ufd.baseGcd(b, c); //System.out.println("gcd = " + gcd); if (!gcd.isONE()) { b = PolyUtil. basePseudoDivide(b, gcd); c = PolyUtil. basePseudoDivide(c, gcd); } //System.out.println("b = " + b); //System.out.println("c = " + c); GenPolynomial[] pf = ufd.basePartialFraction(a, b, c); //System.out.println("a0 = " + pf[0]); //System.out.println("ap = " + pf[1]); //System.out.println("as = " + pf[2]); d = pf[0].multiply(b).multiply(c); // a0*b*c //System.out.println("d = " + d); e = c.multiply(pf[1]).sum(b.multiply(pf[2])); // ap * b + as * c //System.out.println("e = " + e); d = d.sum(e); // a0*b*c + ap * c + as * b //System.out.println("d = " + d); assertEquals("a = a0*b*c + s * c + t * b ", a, d); List> D = new ArrayList>(2); D.add(b); D.add(c); //System.out.println("D = " + D); List> F = ufd.basePartialFraction(a, D); //System.out.println("F = " + F.size()); boolean t = ufd.isBasePartialFraction(a, D, F); assertTrue("a/D = a0 + sum(fi/di)", t); } } /** * Test base partial fraction list. */ public void testBasePartFracList() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //System.out.println("a = " + a); List> D = new ArrayList>(); for (int j = 0; j < i * 3; j++) { b = dfac.random(kl * (i + 1), ll + i, el + i, q); if (b.isZERO() || b.isConstant()) { // skip for this turn continue; } D.add(b); } //System.out.println("D = " + D); D = ufd.coPrime(D); //System.out.println("D = " + D); List> F = ufd.basePartialFraction(a, D); //System.out.println("F = " + F.size()); boolean t = ufd.isBasePartialFraction(a, D, F); assertTrue("a = a0*b*c + s * c + t * b ", t); } } /** * Test base partial fraction exponent. */ public void testBasePartFracExponent() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //System.out.println("a = " + a); b = dfac.random(kl * (i + 1), ll + i, el + i, q); if (b.isZERO() || b.isConstant()) { // skip for this turn continue; } //System.out.println("b = " + b); List> F = ufd.basePartialFraction(a, b, 3); //System.out.println("F = " + F); boolean t = ufd.isBasePartialFraction(a, b, 3, F); assertTrue("a/b^e = a0 + sum(ai/p^i) ", t); } } /** * Test base partial fraction list exponent (squarefree). */ public void testBasePartFracListExponent() { SquarefreeAbstract sqf = SquarefreeFactory.getImplementation(mi); dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //System.out.println("a = " + a); List> D = new ArrayList>(); for (int j = 0; j < i * 3; j++) { b = dfac.random(kl, ll + 1 + i, el + i, q); if (b.isZERO() || b.isConstant()) { // skip for this turn continue; } D.add(b); } //System.out.println("D = " + D); D = ufd.coPrime(D); //System.out.println("D = " + D); SortedMap, Long> Ds = new TreeMap, Long>(); long j = 1L; for (GenPolynomial p : D) { Ds.put(p, j); j++; } //System.out.println("Ds = " + Ds); List>> F = sqf.basePartialFraction(a, Ds); //System.out.println("F = " + F.size()); boolean t = sqf.isBasePartialFraction(a, Ds, F); assertTrue("a/prod(b_i^i) = a0 + sum(aij/b_i^j) ", t); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDPrimitiveTest.java000066400000000000000000000500541445075545500244330ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Primitive PRS algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDPrimitiveTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDPrimitiveTest object. * @param name String. */ public GCDPrimitiveTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDPrimitiveTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = new GreatestCommonDivisorPrimitive(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(new BigInteger(1), rl, to, vars); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test base quotioent and remainder. */ public void testBaseQR() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a).abs(); //c = ufd.basePrimitivePart(c); ci = di.random(kl * (i + 2)); ci = ci.sum(di.getONE()); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("ci = " + ci); if (a.isZERO() || c.isZERO() || ci.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. baseSparsePseudoRemainder(b, c); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); b = a.multiply(ci); //System.out.println("b = " + b); d = b.divide(ci); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(b, c); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test base content and primitive part. */ public void testBaseContentPP() { di = new BigInteger(1); for (int i = 0; i < 13; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); c = c.multiply(di.random(kl * (i + 2))); if (c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ci = ufd.baseContent(c); d = ufd.basePrimitivePart(c); //System.out.println("c = " + c); //System.out.println("ci = " + ci); //System.out.println("d = " + d); a = d.multiply(ci); assertEquals("c == cont(c)pp(c)", c, a); } } /** * Test base gcd. */ public void testBaseGcd() { dfac = new GenPolynomialRing(new BigInteger(1), 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive quotioent and remainder. */ public void testRecursiveQR() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 1), ll + i, el + i, q); a = ufd.basePrimitivePart(a).abs(); c = dfac.random(kl * (i + 1), ll + i, el + i, q); c = ufd.basePrimitivePart(a).abs(); cr = PolyUtil. recursive(rfac, c); c = cfac.random(kl * (i + 1), ll + 2 * i, el + 2 * i, q); c = ufd.basePrimitivePart(c).abs(); ar = PolyUtil. recursive(rfac, a); //System.out.println("ar = " + ar); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("cr = " + cr); if (cr.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); br = ar.multiply(cr); //System.out.println("br = " + br); dr = PolyUtil. recursiveSparsePseudoRemainder(br, cr); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); br = ar.multiply(c); //System.out.println("br = " + br); dr = PolyUtil. recursiveDivide(br, c); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test recursive content and primitive part. */ public void testRecursiveContentPP() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 3; i++) { cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr); dr = ufd.recursivePrimitivePart(cr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); ar = dr.multiply(c); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test recursive gcd. */ public void testRecursiveGCD() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd. */ public void testArbitraryRecursiveGCD() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test content and primitive part. */ public void testContentPP() { dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = ufd.content(c); e = a.extend(dfac, 0, 0L); b = ufd.primitivePart(c); //System.out.println("c = " + c); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("b = " + b); d = e.multiply(b); assertEquals("c == cont(c)pp(c)", d, c); } } /** * Test gcd 3 variables. */ public void testGCD3() { dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 4; i++) { a = dfac.random(kl, ll, el + i, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test gcd. */ public void testGCD() { // dfac = new GenPolynomialRing(new BigInteger(1),3,to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test gcd field coefficients. */ public void testGCDfield() { GenPolynomialRing dfac; dfac = new GenPolynomialRing(new BigRational(1), 3, to); GreatestCommonDivisorAbstract ufd = new GreatestCommonDivisorPrimitive(); GenPolynomial a, b, c, d, e; for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test lcm. */ public void testLCM() { dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( a" + i + " ) <> 0", a.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); c = ufd.gcd(a, b); //System.out.println("c = " + c); d = ufd.lcm(a, b); //System.out.println("d = " + d); e = c.multiply(d); //System.out.println("e = " + e); c = a.multiply(b); //System.out.println("c = " + c); assertEquals("ab == gcd(a,b)lcm(ab)", c, e); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(new BigInteger(1), 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(d); F.add(a); F.add(b); F.add(c); F.add(e); List> P = ufd.coPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); //P = ufd.coPrimeSquarefree(F); //System.out.println("F = " + F); //System.out.println("P = " + P); //assertTrue("is co-prime ", ufd.isCoPrime(P) ); //assertTrue("is co-prime of ", ufd.isCoPrime(P,F) ); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDProxyTest.java000066400000000000000000000251611445075545500236050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigComplex; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GreatestCommonDivisor proxy tests with JUnit. * @author Heinz Kredel */ public class GCDProxyTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); //ComputerThreads.terminate(); //System.out.println("System.exit(0)"); } /** * Constructs a GCDProxyTest object. * @param name String. */ public GCDProxyTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDProxyTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai; BigInteger bi; BigInteger ci; BigInteger di; BigInteger ei; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; GenPolynomial> ar; GenPolynomial> br; GenPolynomial> cr; GenPolynomial> dr; GenPolynomial> er; int rl = 5; int kl = 5; int ll = 7; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; dfac = null; cfac = null; rfac = null; ComputerThreads.terminate(); } /** * Test get BigInteger implementation. */ public void testBigInteger() { long t; BigInteger bi = new BigInteger(); GreatestCommonDivisor ufd_par; GreatestCommonDivisorAbstract ufd; ufd_par = GCDFactory./**/getProxy(bi); //System.out.println("ufd_par = " + ufd_par); assertTrue("ufd_par != null " + ufd_par, ufd_par != null); ufd = new GreatestCommonDivisorSubres(); //System.out.println("ufd = " + ufd); assertTrue("ufd != null " + ufd, ufd != null); dfac = new GenPolynomialRing(bi, 4, to); for (int i = 0; i < 1; i++) { // 10-50 a = dfac.random(kl + i * 10, ll + i, el, q); b = dfac.random(kl + i * 10, ll + i, el, q); c = dfac.random(kl + 2, ll, el, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); /* System.out.println("\ni degrees: a = " + a.degree() + ", b = " + b.degree() + ", c = " + c.degree()); */ t = System.currentTimeMillis(); d = ufd_par.gcd(a, b); t = System.currentTimeMillis() - t; //System.out.println("i proxy time = " + t); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } // obsolete ((GCDProxy)ufd_par).terminate(); ComputerThreads.terminate(); } /** * Test get ModInteger implementation. */ public void testModInteger() { long t; ModIntegerRing mi = new ModIntegerRing(19, true); //ModIntegerRing mi = new ModIntegerRing(536870909, true); GenPolynomial a, b, c, d, e; GreatestCommonDivisor ufd_par; GreatestCommonDivisorAbstract ufd; ufd_par = GCDFactory.getProxy(mi); //System.out.println("ufd_par = " + ufd_par); assertTrue("ufd_par != null " + ufd_par, ufd_par != null); ufd = new GreatestCommonDivisorSubres(); //System.out.println("ufd = " + ufd); assertTrue("ufd != null " + ufd, ufd != null); GenPolynomialRing dfac; dfac = new GenPolynomialRing(mi, 4, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl + i * 2, ll + i, el, q); b = dfac.random(kl + i * 2, ll + i, el, q); c = dfac.random(kl, ll, el, q); //a = dfac.random(kl,ll+i,el,q); //b = dfac.random(kl,ll+i,el,q); //c = dfac.random(kl,ll,el,q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); /* System.out.println("\nm degrees: a = " + a.degree() + ", b = " + b.degree() + ", c = " + c.degree()); */ t = System.currentTimeMillis(); d = ufd_par.gcd(a, b); t = System.currentTimeMillis() - t; //System.out.println("m proxy time = " + t); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e + ", " + d + ", " + c, e.isZERO()); } // obsolete ((GCDProxy)ufd_par).terminate(); ComputerThreads.terminate(); } /** * Test get BigRational implementation. */ public void testBigRational() { BigRational b = new BigRational(); GreatestCommonDivisor ufd; ufd = GCDFactory./**/getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd = Primitive " + ufd, ufd instanceof GreatestCommonDivisorPrimitive); } /** * Test get BigComplex implementation. */ public void testBigComplex() { BigComplex b = new BigComplex(); GreatestCommonDivisor ufd; ufd = GCDFactory. getImplementation(b); //System.out.println("ufd = " + ufd); assertTrue("ufd != Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<BigRational> implementation. */ public void testAlgebraicNumberBigRational() { BigRational b = new BigRational(); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isConstant() || mo.isZERO()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); GreatestCommonDivisor> ufd; ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd = " + ufd); assertTrue("ufd = Subres " + ufd, ufd instanceof GreatestCommonDivisorSubres); mo = fac.univariate(0).subtract(fac.getONE()); afac = new AlgebraicNumberRing(mo, true); ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd = " + ufd); assertTrue("ufd = Simple " + ufd, ufd instanceof GreatestCommonDivisorSimple); } /** * Test get AlgebraicNumber<ModInteger&glt; implementation. */ public void testAlgebraicNumberModInteger() { ModIntegerRing b = new ModIntegerRing(19, true); GenPolynomialRing fac; fac = new GenPolynomialRing(b, 1); GenPolynomial mo = fac.random(kl, ll, el, q); while (mo.isConstant() || mo.isZERO()) { mo = fac.random(kl, ll, el, q); } AlgebraicNumberRing afac; afac = new AlgebraicNumberRing(mo); AlgebraicNumber a = afac.getONE(); assertTrue("a == 1 " + a, a.isONE()); GreatestCommonDivisor> ufd; ufd = GCDFactory.> getImplementation(afac); //System.out.println("ufd = " + ufd); assertTrue("ufd = Subres " + ufd, ufd instanceof GreatestCommonDivisorSubres); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDSimpleTest.java000066400000000000000000000346131445075545500237170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Simple PRS algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDSimpleTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDSimpleTest object. * @param name String. */ public GCDSimpleTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSimpleTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = new GreatestCommonDivisorSimple(); //ufd = GCDFactory.getImplementation(new BigInteger(1)); dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test base gcd simple. */ public void testBaseGcdSimple() { dfac = new GenPolynomialRing(new BigInteger(1), 1, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); c = dfac.random(kl * (i + 2), ll + 2, el + 2, q); c = c.multiply(dfac.univariate(0)); if (c.isZERO()) { // skip for this turn continue; } //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test recursive gcd simple. */ public void testRecursiveGCDSimple() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); //kl = 3; ll = 2; for (int i = 0; i < 3; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); cr = ufd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a" + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b" + er, er.isZERO()); } } /** * Test arbitrary recursive gcd simple. */ public void testArbitraryRecursiveGCDSimple() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); //kl = 3; ll = 2; for (int i = 0; i < 3; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); cr = ufd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveGcd(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a" + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b" + er, er.isZERO()); } } /** * Test gcd simple. */ public void testGCDSimple() { dfac = new GenPolynomialRing(new BigInteger(1), 4, to); for (int i = 0; i < 2; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); c = c.multiply(dfac.univariate(0)); c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); d = ufd.gcd(a, b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test base resultant integral coefficients. */ public void testBaseResultant() { dfac = new GenPolynomialRing(new BigInteger(1), 1, to); GreatestCommonDivisorSimple ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorSubres sres = new GreatestCommonDivisorSubres(); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el + 3 + i, q); b = dfac.random(kl, ll, el + 3 + i, q); c = dfac.random(kl, ll, el + 3 + i, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (c.isConstant()) { c = dfac.univariate(0, 1); } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); d = ufds.baseResultant(a, b); //System.out.println("d = " + d); e = sres.baseResultant(a, b); //System.out.println("e = " + e); assertEquals("d == e: " + d.subtract(e), d.abs().signum(), e.abs().signum()); //assertEquals("d == e: " + d.subtract(e), d, e); GenPolynomial ac = a.multiply(c); GenPolynomial bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); d = ufds.baseResultant(ac, bc); //System.out.println("d = " + d); assertTrue("d == 0: " + d, d.isZERO()); e = sres.baseResultant(ac, bc); //System.out.println("e = " + e); assertTrue("e == 0: " + e, e.isZERO()); } } /** * Test recursive resultant simple. */ public void testRecursiveResultantSimple() { di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); GreatestCommonDivisorSimple ufds = new GreatestCommonDivisorSimple(); GreatestCommonDivisorSubres sres = new GreatestCommonDivisorSubres(); //kl = 3; ll = 2; for (int i = 0; i < 1; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); cr = ufd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } if (cr.isConstant()) { cr = rfac.univariate(0, 1); } //System.out.println("cr = " + cr); assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); dr = ufds.recursiveUnivariateResultant(ar, br); //System.out.println("dr = " + dr); er = sres.recursiveUnivariateResultant(ar, br); //System.out.println("er = " + er); assertEquals("dr == er: " + dr.subtract(er), dr.abs().signum(), er.abs().signum()); //assertEquals("dr == er: " + dr.subtract(er), dr, er); GenPolynomial> arc = ar.multiply(cr); GenPolynomial> brc = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufds.recursiveUnivariateResultant(arc, brc); //System.out.println("dr = " + dr); //assertTrue("dr == 0: " + dr, dr.isZERO()); er = sres.recursiveUnivariateResultant(arc, brc); //System.out.println("er = " + er); //assertTrue("er == 0: " + er, er.isZERO()); assertEquals("dr == er: " + dr.subtract(er), dr.signum(), er.signum()); } } /** * Test gcd example simple. */ public void testGCDExamSimple() { ufd = new GreatestCommonDivisorModular(); dfac = new GenPolynomialRing(new BigInteger(1), new String[] { "t", "x" }, to); a = dfac.parse("x**3 + x**2 - t * x - t"); b = dfac.parse("3 * x**2 + 2 * x - t"); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDSubresRatTest.java000066400000000000000000000507771445075545500244110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Subres with rational coefficients algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDSubresRatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDSubresRatTest object. * @param name String. */ public GCDSubresRatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSubresRatTest.class); return suite; } GreatestCommonDivisorSubres ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigRational mi; BigRational ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 3; int kl = 2; int ll = 3; int el = 3; float q = 0.25f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; mi = new BigRational(1); ufd = new GreatestCommonDivisorSubres(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(mi, rl, to, vars); cfac = new GenPolynomialRing(mi, rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); //System.out.println("mi = " + mi); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; mi = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test gcd. */ public void testGcd() { for (int i = 0; i < 1; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 0 * i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); c = ufd.basePrimitivePart(c).abs(); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test base quotioent and remainder. */ public void testBaseQR() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a).abs(); //c = ufd.basePrimitivePart(c); do { ci = mi.random(kl * (i + 2)); ci = ci.sum(mi.getONE()); } while (ci.isZERO()); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("ci = " + ci); if (a.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. baseSparsePseudoRemainder(b, c); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); b = a.multiply(ci); //System.out.println("b = " + b); d = b.divide(ci); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); b = a.multiply(c); //System.out.println("b = " + b); d = PolyUtil. basePseudoDivide(b, c); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test base content and primitive part. */ public void testBaseContentPP() { for (int i = 0; i < 9; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); c = c.multiply(mi.random(kl * (i + 2))); if (c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ci = ufd.baseContent(c); d = ufd.basePrimitivePart(c); //System.out.println("c = " + c); //System.out.println("ci = " + ci); //System.out.println("d = " + d); a = d.multiply(ci); assertEquals("c == cont(c)pp(c)", c, a); } } public void testDiscriminant() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 5; i++) { c = dfac.random(kl * (i + 1), ll + 2 * i, el + i, q * 2); //System.out.println("c = " + c); if (c.isZERO()) { // skip for this turn continue; } c = c.multiply(c); d = ufd.baseDiscriminant(c); //System.out.println("d = " + d); assertTrue("disc(c^2) == 0", d.isZERO()); } } /** * Test base gcd. */ public void testBaseGcd() { dfac = new GenPolynomialRing(mi, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test recursive quotioent and remainder. */ public void testRecursiveQR() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl * (i + 1), ll + i, el + i, q); a = ufd.basePrimitivePart(a).abs(); c = dfac.random(kl * (i + 1), ll + i, el + i, q); c = ufd.basePrimitivePart(a).abs(); cr = PolyUtil. recursive(rfac, c); c = cfac.random(kl * (i + 1), ll + 2 * i, el + 2 * i, q); c = ufd.basePrimitivePart(c).abs(); ar = PolyUtil. recursive(rfac, a); //System.out.println("ar = " + ar); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("cr = " + cr); if (cr.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); br = ar.multiply(cr); //System.out.println("br = " + br); dr = PolyUtil. recursiveSparsePseudoRemainder(br, cr); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertTrue("rem(ac,c) == 0", d.isZERO()); br = ar.multiply(c); //System.out.println("br = " + br); dr = PolyUtil. recursiveDivide(br, c); //System.out.println("dr = " + dr); d = PolyUtil. distribute(dfac, dr); //System.out.println("d = " + d); assertEquals("a == ac/c", a, d); } } /** * Test recursive content and primitive part. */ public void testRecursiveContentPP() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 3; i++) { cr = rfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); c = ufd.recursiveContent(cr); dr = ufd.recursivePrimitivePart(cr); //System.out.println("c = " + c); //System.out.println("dr = " + dr); ar = dr.multiply(c); assertEquals("c == cont(c)pp(c)", cr, ar); } } /** * Test recursive gcd. */ public void testRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test arbitrary recursive gcd. */ public void testArbitraryRecursiveGCD() { dfac = new GenPolynomialRing(mi, 2, to); cfac = new GenPolynomialRing(mi, 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 2; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); } } /** * Test content and primitive part. */ public void testContentPP() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 3; i++) { c = dfac.random(kl * (i + 2), ll + 2 * i, el + i, q); //System.out.println("cr = " + cr); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = ufd.content(c); e = a.extend(dfac, 0, 0L); b = ufd.primitivePart(c); //System.out.println("c = " + c); //System.out.println("a = " + a); //System.out.println("e = " + e); //System.out.println("b = " + b); d = e.multiply(b); assertEquals("c == cont(c)pp(c)", d, c); } } /** * Test gcd 3 variables. */ public void testGCD3() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 3; i++) { a = dfac.random(kl, ll, el + i, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); } } /** * Test gcd. */ public void testGCD() { // dfac = new GenPolynomialRing(mi,3,to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.gcd(a, b); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test lcm. */ public void testLCM() { dfac = new GenPolynomialRing(mi, 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( a" + i + " ) <> 0", a.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); c = ufd.gcd(a, b); //System.out.println("c = " + c); d = ufd.lcm(a, b); //System.out.println("d = " + d); e = c.multiply(d); //System.out.println("e = " + e); c = a.multiply(b); //System.out.println("c = " + c); assertEquals("ab == gcd(a,b)lcm(ab)", c, e); } } /** * Test co-prime factors. */ public void testCoPrime() { dfac = new GenPolynomialRing(mi, 3, to); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } assertTrue("length( a ) <> 0", a.length() > 0); d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); e = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); List> F = new ArrayList>(5); F.add(d); F.add(a); F.add(b); F.add(c); F.add(e); List> P = ufd.coPrime(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); //P = ufd.coPrimeSquarefree(F); //System.out.println("F = " + F); //System.out.println("P = " + P); //assertTrue("is co-prime ", ufd.isCoPrime(P) ); //assertTrue("is co-prime of ", ufd.isCoPrime(P,F) ); P = ufd.coPrimeRec(F); //System.out.println("F = " + F); //System.out.println("P = " + P); assertTrue("is co-prime ", ufd.isCoPrime(P)); assertTrue("is co-prime of ", ufd.isCoPrime(P, F)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDSubresTest.java000066400000000000000000000427711445075545500237350ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GCD Subresultant PRS algorithm tests with JUnit. * @author Heinz Kredel */ public class GCDSubresTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GCDSubresTest object. * @param name String. */ public GCDSubresTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDSubresTest.class); return suite; } GreatestCommonDivisorAbstract ufd; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = new GreatestCommonDivisorPrimitive(); String[] vars = ExpVector.STDVARS(rl); String[] cvars = ExpVector.STDVARS(rl - 1); String[] rvars = new String[] { vars[rl - 1] }; dfac = new GenPolynomialRing(new BigInteger(1), rl, to, vars); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to, cvars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd = null; dfac = null; cfac = null; rfac = null; } /** * Test base gcd subresultant. */ public void testBaseGcdSubres() { ufd = new GreatestCommonDivisorSubres(); dfac = new GenPolynomialRing(new BigInteger(1), 1, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); c = dfac.random(kl * (i + 2), ll + 2, el + 2, q); c = c.multiply(dfac.univariate(0)); if (c.isZERO()) { // skip for this turn continue; } //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseGcd(a, b); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a" + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b" + e, e.isZERO()); } } /** * Test recursive gcd subresultant. */ public void testRecursiveGCDsubres() { ufd = new GreatestCommonDivisorSubres(); di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); cr = ufd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); dr = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a" + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b" + er, er.isZERO()); } } /** * Test arbitrary recursive gcd subresultant. */ public void testArbitraryRecursiveGCDsubres() { ufd = new GreatestCommonDivisorSubres(); di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); cr = ufd.recursivePrimitivePart(cr).abs(); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); dr = ufd.recursiveGcd(ar, br); //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(ar, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | a" + er, er.isZERO()); er = PolyUtil. recursiveSparsePseudoRemainder(br, dr); //System.out.println("er = " + er); assertTrue("gcd(a,b) | b" + er, er.isZERO()); } } /** * Test gcd subresultant. */ public void testGCDsubres() { //GreatestCommonDivisorAbstract ufd_pp; //ufd_pp = ufd; ufd = new GreatestCommonDivisorSubres(); dfac = new GenPolynomialRing(new BigInteger(1), 5, to); for (int i = 0; i < 2; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, el, q); c = c.multiply(dfac.univariate(0)); c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); d = ufd.gcd(a, b); //System.out.println("c = " + c); //System.out.println("d = " + d); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(a, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | a " + e, e.isZERO()); e = PolyUtil. baseSparsePseudoRemainder(b, d); //System.out.println("e = " + e); assertTrue("gcd(a,b) | b " + e, e.isZERO()); } } /** * Test base subresultant. */ public void testBaseSubresultant() { GreatestCommonDivisorSubres ufd = new GreatestCommonDivisorSubres(); dfac = new GenPolynomialRing(new BigInteger(1), 1, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2, q); c = dfac.random(kl, ll, 2, q); //c = c.multiply( cfac.univariate(0) ); //c = dfac.getONE(); if (c.isZERO()) { // skip for this turn continue; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); d = ufd.baseResultant(a, b); e = ufd.baseGcd(a, b); //System.out.println("d = " + d); //System.out.println("c = " + c); //System.out.println("e = " + e); if (!e.isConstant()) { assertTrue("res(a,b) == 0 " + d, d.isZERO()); } else { assertTrue("res(a,b) != 0 " + d, !d.isZERO()); } } } /** * Test recursive subresultant. */ public void testRecursiveSubresultant() { GreatestCommonDivisorSubres ufd = new GreatestCommonDivisorSubres(); di = new BigInteger(1); dfac = new GenPolynomialRing(new BigInteger(1), 2, to); cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); for (int i = 0; i < 5; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, 2, q); //cr = rfac.getONE(); //cr = ufd.recursivePrimitivePart(cr).abs(); //cr = cr.multiply( rfac.univariate(0) ); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = ufd.recursiveUnivariateResultant(ar, br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); er = ufd.recursiveUnivariateGcd(ar, br); //System.out.println("er = " + er); if (er.isZERO()) { // cannot happen since a, b, c != 0 assertTrue("res(a,b) = 0 " + dr + " e = " + er, dr.isZERO()); } if (er.isConstant() && er.leadingBaseCoefficient().isConstant()) { assertTrue("res(a,b) != 0 " + dr + ", e = " + er + ", a = " + ar + ", b = " + br, !dr.isZERO()); } else { assertTrue("res(a,b) = 0 or not const " + dr + ", e = " + er + ", a = " + ar + ", b = " + br, dr.isZERO() || !dr.isConstant() || !dr.leadingBaseCoefficient().isConstant()); } } } /** * Test subresultant. */ public void testSubres() { GreatestCommonDivisorSubres ufd = new GreatestCommonDivisorSubres(); dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 2; i++) { a = dfac.random(kl, ll, el, q); b = dfac.random(kl, ll, el, q); c = dfac.random(kl, ll, 2, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); //c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); d = ufd.resultant(a, b); e = ufd.gcd(a, b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); if (e.isZERO()) { // cannot happen since a, b, c != 0 assertTrue("res(a,b) = 0 " + d + " e = " + e, d.isZERO()); } if (e.isConstant()) { assertTrue("res(a,b) != 0 " + d + ", e = " + e + ", a = " + a + ", b = " + b, !d.isZERO()); } else { assertTrue("res(a,b) = 0 or not const " + d + ", e = " + e + ", a = " + a + ", b = " + b, d.isZERO() || !d.isConstant()); } } } /** * Test and compare resultant. */ public void testResultant() { GreatestCommonDivisorAbstract ufdm = new GreatestCommonDivisorModular(true); GreatestCommonDivisorSubres ufds = new GreatestCommonDivisorSubres(); dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 1; i++) { a = dfac.random(kl + (i + 1), ll, el, q); b = dfac.random(kl + (i + 2), ll, el, q); c = dfac.random(kl, ll, 2, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ); //c = ufd.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } if (c.isConstant()) { c = dfac.univariate(0, 1); } //System.out.println("c = " + c); assertTrue("length( c" + i + " ) <> 0", c.length() > 0); d = ufdm.resultant(a, b); //System.out.println("d = " + d); e = ufds.resultant(a, b); //System.out.println("e = " + e); assertEquals("d == e: " + d.subtract(e), d.abs().signum(), e.abs().signum()); //assertEquals("d == e: " + d.subtract(e), d, e); GenPolynomial ac = a.multiply(c); GenPolynomial bc = b.multiply(c); //System.out.println("ac = " + ac); //System.out.println("bc = " + bc); d = ufdm.resultant(ac, bc); //System.out.println("d = " + d); //assertTrue("d == 0: " + d, d.isZERO()); e = ufds.resultant(ac, bc); //System.out.println("e = " + e); //assertTrue("e == 0: " + e, e.isZERO()); assertEquals("d == e: " + d.subtract(e), d.abs().signum(), e.abs().signum()); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GCDTimingTest.java000066400000000000000000000272151445075545500237150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GreatestCommonDivisor timing tests with JUnit. Change xtestMethod to * testMethod to activate. * @author Heinz Kredel */ public class GCDTimingTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a GCDTimingTest object. * @param name String. */ public GCDTimingTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GCDTimingTest.class); return suite; } GreatestCommonDivisorAbstract ufd_si; GreatestCommonDivisorAbstract ufd_pp; GreatestCommonDivisorSubres ufd_sr; // because of non sparse pseudo remainder GreatestCommonDivisorAbstract ufd_mosi; GreatestCommonDivisorAbstract ufd_moevsi; GreatestCommonDivisorAbstract ufd_par; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; int rl = 5; int kl = 4; int ll = 5; int el = 3; float q = 0.4f; //0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd_si = new GreatestCommonDivisorSimple(); ufd_pp = new GreatestCommonDivisorPrimitive(); ufd_sr = new GreatestCommonDivisorSubres(); ufd_mosi = new GreatestCommonDivisorModular(true); ufd_moevsi = new GreatestCommonDivisorModular(); dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); ufd_par = GCDFactory.getProxy(BigInteger.ONE); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; ar = br = cr = dr = er = null; ufd_si = null; ufd_pp = null; ufd_sr = null; dfac = null; cfac = null; rfac = null; } /** * Test dummy for junit. */ public void testDummy() { assertTrue("ufd_pp != null", ufd_pp != null); } /** * Test base gcd simple. */ public void xtestBaseGcd() { dfac = new GenPolynomialRing(new BigInteger(1), 1, to); long t; for (int i = 0; i < 10; i++) { a = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); b = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = dfac.random(kl * (i + 2), ll + 2 * i, el + 2 * i, q); c = c.multiply(dfac.univariate(0)); //a = ufd.basePrimitivePart(a); //b = ufd.basePrimitivePart(b); //c = ufd.basePrimitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); System.out.println( "\ndegrees: a = " + a.degree() + ", b = " + b.degree() + ", c = " + c.degree()); /* t = System.currentTimeMillis(); d = ufd_si.baseGcd(a,b); t = System.currentTimeMillis() - t; e = PolyUtil.baseSparsePseudoRemainder(d,c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO() ); System.out.println("simple prs time = " + t); */ t = System.currentTimeMillis(); d = ufd_pp.baseGcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("primitive prs time = " + t); t = System.currentTimeMillis(); d = ufd_sr.baseGcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("subsresultant prs time = " + t); } } /** * Test recursive gcd. */ public void xtestRecursiveGCD() { cfac = new GenPolynomialRing(new BigInteger(1), 2 - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); long t; for (int i = 0; i < 5; i++) { ar = rfac.random(kl, ll, el + i, q); br = rfac.random(kl, ll, el + i, q); cr = rfac.random(kl, ll, el, q); cr = cr.multiply(rfac.univariate(0)); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn continue; } assertTrue("length( cr" + i + " ) <> 0", cr.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); ar = ar.multiply(cr); br = br.multiply(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); System.out.println("\ndegrees: a = " + ar.degree() + ", b = " + br.degree() + ", c = " + cr.degree()); t = System.currentTimeMillis(); dr = ufd_si.recursiveUnivariateGcd(ar, br); t = System.currentTimeMillis() - t; //System.out.println("dr = " + dr); //er = PolyUtil.recursiveSparsePseudoRemainder(dr,cr); //System.out.println("er = " + er); //assertTrue("c | gcd(ac,bc) " + er, er.isZERO() ); System.out.println("simple prs time = " + t); /* */ t = System.currentTimeMillis(); dr = ufd_pp.recursiveUnivariateGcd(ar, br); t = System.currentTimeMillis() - t; //System.out.println("dr = " + dr); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); System.out.println("primitive prs time = " + t); t = System.currentTimeMillis(); dr = ufd_sr.recursiveUnivariateGcd(ar, br); t = System.currentTimeMillis() - t; //System.out.println("dr = " + dr); er = PolyUtil. recursiveDensePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("c | gcd(ac,bc) " + er, er.isZERO()); System.out.println("subresultant prs time = " + t); } } /** * Test gcd. */ public void xtestGCD() { long t; dfac = new GenPolynomialRing(new BigInteger(1), 3, to); for (int i = 0; i < 5; i++) { a = dfac.random(kl + i * 30, ll + i, 2 * el, q); b = dfac.random(kl + i * 30, ll + i, 2 * el, q); c = dfac.random(kl, ll, el, q); //c = dfac.getONE(); //c = c.multiply( dfac.univariate(0) ).multiply( dfac.univariate(4) ); //c = c.multiply( dfac.univariate(0) ); c = ufd_pp.primitivePart(c).abs(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn continue; } assertTrue("length( c" + i + " ) <> 0", c.length() > 0); //assertTrue(" not isZERO( c"+i+" )", !c.isZERO() ); //assertTrue(" not isONE( c"+i+" )", !c.isONE() ); a = a.multiply(c); b = b.multiply(c); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); System.out.println( "\ndegrees: a = " + a.degree() + ", b = " + b.degree() + ", c = " + c.degree()); /* t = System.currentTimeMillis(); d = ufd_si.gcd(a,b); t = System.currentTimeMillis() - t; e = PolyUtil.baseSparsePseudoRemainder(d,c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO() ); System.out.println("simple prs time = " + t); */ /* t = System.currentTimeMillis(); d = ufd_pp.gcd(a,b); t = System.currentTimeMillis() - t; e = PolyUtil.baseSparsePseudoRemainder(d,c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO() ); System.out.println("primitive prs time = " + t); */ t = System.currentTimeMillis(); d = ufd_sr.gcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("subsresultant prs time = " + t); t = System.currentTimeMillis(); d = ufd_mosi.gcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("modular simple time = " + t); t = System.currentTimeMillis(); d = ufd_moevsi.gcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("modular eval time = " + t); t = System.currentTimeMillis(); d = ufd_par.gcd(a, b); t = System.currentTimeMillis() - t; e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("d = " + d); assertTrue("c | gcd(ac,bc) " + e, e.isZERO()); System.out.println("parallel time = " + t); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/GenMatrixFFTest.java000066400000000000000000000134521445075545500242600ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.LinAlg; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenMatrix tests with JUnit * @author Heinz Kredel * @see edu.jas.vector.GenMatrixTest */ public class GenMatrixFFTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenMatrixFFTest object. * @param name String. */ public GenMatrixFFTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GenMatrixFFTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; int rows = 3 + 20; int cols = 3 + 20; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test fraction free GE. */ public void testFractionfreeGE() { BigInteger cfac = new BigInteger(1); int n = 4; int m = 5; GenMatrixRing mfac = new GenMatrixRing(cfac, n, m);//rows, cols); //GenVectorModul vfac = new GenVectorModul(cfac, m);//rows); GenMatrix A, Ap; //A = mfac.random(kl, 0.7f); A = mfac.parse("[ [3,4,-2,1,-2], [1,-1,2,2,7], [4,-3,4,-3,2], [-1,1,6,-1,1] ]"); //System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); LinAlg lu = new LinAlg(); //BasicLinAlg blas = new BasicLinAlg(); List P = lu.fractionfreeGaussElimination(Ap); //System.out.println("P = " + P); if (P.size() == 0) { //System.out.println("undecomposable"); return; } assertTrue("#P != 0: ", P.size() > 0); //System.out.println("A = " + A); n = 10; m = n; mfac = new GenMatrixRing(cfac, n, m);//rows, cols); A = mfac.random(5, 0.67f); //System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); P = lu.fractionfreeGaussElimination(A); //System.out.println("P = " + P); if (P.size() == 0) { //System.out.println("undecomposable"); return; } assertTrue("#P != 0: ", P.size() > 0); //System.out.println("A = " + A); } /** * Test fraction free GE polynomial. */ public void testFractionfreeGEpoly() { BigRational cfac = new BigRational(1); int n = 4; int m = n; String[] vars = new String[] { "a1", "a2", "a3", "a4" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, vars); GenMatrixRing> mfac = new GenMatrixRing>(pfac, n, m); GenMatrix> A, Ap; A = mfac.random(4, 0.5f); //A = mfac.parse("[ [3,4,-2,1,-2], [1,-1,2,2,7], [4,-3,4,-3,2], [-1,1,6,-1,1] ]"); //System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); LinAlg> lu = new LinAlg>(); List P = lu.fractionfreeGaussElimination(Ap); //System.out.println("P = " + P); if (P.size() == 0) { //System.out.println("undecomposable"); return; } assertTrue("#P != 0: ", P.size() > 0); //System.out.println("A = " + A); vars = new String[] { "a11", "a12", "a13", "a14", "a21", "a22", "a23", "a24", "a31", "a32", "a33", "a34", "a41", "a42", "a43", "a44" }; pfac = new GenPolynomialRing(cfac, vars); mfac = new GenMatrixRing>(pfac, n, m); A = mfac.parse("[ [a11, a12, a13, a14], [a21, a22, a23, a24], [a31, a32, a33, a34], [a41, a42, a43, a44]] "); //System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); P = lu.fractionfreeGaussElimination(A); //System.out.println("P = " + P); if (P.size() == 0) { //System.out.println("undecomposable"); return; } assertTrue("#P != 0: ", P.size() > 0); //System.out.println("A = " + A); FactorAbstract ufd = FactorFactory.getImplementation(cfac); int i = 0; for (ArrayList> row : A.matrix) { int j = 0; for (GenPolynomial elem : row) { if (elem.isZERO()) { j++; continue; } SortedMap, Long> pf = ufd.factors(elem); //System.out.println("A(" + i + "," + j + ") = " + elem); //System.out.println("factors = " + pf); assertTrue("#factors == 1:", pf.size() == 1); j++; } i++; } ComputerThreads.terminate(); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/HenselMultUtilTest.java000066400000000000000000001274521445075545500250720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.arith.PrimeList; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; /** * HenselMultUtil tests with JUnit. Two separate classes because of package * dependency. * @see edu.jas.application.HenselMultUtilTest * @author Heinz Kredel */ public class HenselMultUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a HenselMultUtilTest object. * @param name String. */ public HenselMultUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(HenselMultUtilTest.class); return suite; } TermOrder tord = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai; BigInteger bi; BigInteger ci; BigInteger di; BigInteger ei; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 2; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, tord); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, tord); rfac = new GenPolynomialRing>(cfac, 1, tord); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; cfac = null; rfac = null; ComputerThreads.terminate(); } protected static java.math.BigInteger getPrime1() { return PrimeList.getLongPrime(60, 93); } protected static java.math.BigInteger getPrime2() { return PrimeList.getLongPrime(30, 35); } /** * Test multivariate Hensel lifting monic case list. */ public void testHenselLiftingMonicList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); //ModLongRing pl = new ModLongRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 4, tord, new String[] { "w", "x", "y", "z" }); //GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(),pfac); BigInteger mi = m; long k = 5L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); if (pkfac.nvar > 2) { V.add(new BigInteger(5L)); //pkm.fromInteger(5L)); } if (pkfac.nvar > 3) { V.add(new BigInteger(7L)); //pkm.fromInteger(7L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { //a = dfac.random(kl + 7 * i, ll, el + 1, q).abs(); //b = dfac.random(kl + 7 * i, ll, el + 0, q).abs(); //c = dfac.random(kl + 7 * i, ll, el + 2, q).abs(); a = dfac.parse(" ( z^2 + y^2 + 4 x^3 - x + 1 + w ) "); b = dfac.parse(" ( z + y + x^2 + 10 + w ) "); //c = dfac.parse(" z + x + (y - 2)*(2 + y) "); A.add(a); A.add(b); //A.add(c); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)); //c = dfac.parse(" y^2 + x^2 "); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Ap.add(ap); } //System.out.println("A mod p^k = " + Ap); //System.out.println("v = " + v + ", vp = " + vp); GenPolynomialRing ckfac = pkfac.contract(1); v = pkm.fromInteger( V.get(2).getVal() ); List> Ae = new ArrayList>(A.size()); for (GenPolynomial a : Ap) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae.add(ae); } //System.out.println("A(v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(1).getVal() ); List> Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v,v) mod p^k = " + Ae); try { List> lift; lift = HenselMultUtil. liftHenselMonic(c, cp, Ae, V, k); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ae, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test multivariate Hensel lifting list, 2 variables. */ public void testHenselLifting2List() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 2, tord, new String[] { "x", "y" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); BigInteger mi = m; long k = 5L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m + " = " + p + "^" + k); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.parse(" ( x^3 y - 1 ) "); b = dfac.parse(" ( 1 + y ) "); e = dfac.parse(" ( y^2 - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); //c = dfac.parse(" y^2 + x^2 "); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); //System.out.println("cp = " + cp); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //CL.add( CF.get(0) ); //System.out.println("CL = " + CL); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Ap.add(ap); } //System.out.println("A mod p^k = " + Ap); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); List> Ae = new ArrayList>(A.size()); for (GenPolynomial a : Ap) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae.add(ae); } //System.out.println("A(v) mod p^k = " + Ae); try { List> lift; lift = HenselMultUtil. liftHensel(c, cp, Ae, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ae, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test multivariate Hensel lifting list, 3 variables. */ public void xtestHenselLifting3List() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 3, tord, new String[] { "x", "y", "z" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); BigInteger mi = m; long k = 3L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); if (pkfac.nvar > 2) { V.add(new BigInteger(5L)); //pkm.fromInteger(5L)); } if (pkfac.nvar > 3) { V.add(new BigInteger(7L)); //pkm.fromInteger(7L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { //a = dfac.random(kl + 7 * i, ll, el + 1, q).abs(); //b = dfac.random(kl + 7 * i, ll, el + 0, q).abs(); //c = dfac.random(kl + 7 * i, ll, el + 2, q).abs(); //a = dfac.parse(" ( z^2 + y^2 + 4 x^3 - x + 1 + w ) "); //b = dfac.parse(" ( z y x + x^2 + 10 + w ) "); a = dfac.parse(" ( x^3 z - y ) "); //a = dfac.parse(" ( x - y ) "); b = dfac.parse(" ( 1 + y + z ) "); e = dfac.parse(" ( z^2 y - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); //c = dfac.parse(" y^2 + x^2 "); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //System.out.println("CL = " + CL); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Ap.add(ap); } //System.out.println("A mod p^k = " + Ap); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); //v = pkm.fromInteger( V.get(2) ); List> Ae = new ArrayList>(A.size()); //for ( GenPolynomial a : Ap ) { // GenPolynomial ae = PolyUtil. evaluateMain(ckfac,a,v); // Ae.add(ae); //} //System.out.println("A(v) mod p^k = " + Ae); //ckfac = ckfac.contract(1); Ae = Ap; v = pkm.fromInteger( V.get(1).getVal() ); List> Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v) mod p^k = " + Ae); try { List> lift; lift = HenselMultUtil. liftHensel(c, cp, Ae, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ae, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test multivariate Hensel lifting list, 4 variables. */ public void xtestHenselLifting4List() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 4, tord, new String[] { "x", "y", "z", "w" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); BigInteger mi = m; long k = 3L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m); ModIntegerRing pkm = new ModIntegerRing(pk, false); //ModLongRing pkl = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); //ModLong v = pl.fromInteger(3L); ModInteger v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); if (pkfac.nvar > 2) { V.add(new BigInteger(5L)); //pkm.fromInteger(5L)); } if (pkfac.nvar > 3) { V.add(new BigInteger(7L)); // pkm.fromInteger(7L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.parse(" ( x^3 w - y ) "); b = dfac.parse(" ( 1 + y + z + w ) "); e = dfac.parse(" ( z^2 y w - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //System.out.println("CL = " + CL); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Ap.add(ap); } //System.out.println("A mod p^k = " + Ap); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); v = pkm.fromInteger( V.get(2).getVal() ); List> Ae = new ArrayList>(A.size()); for (GenPolynomial a : Ap) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae.add(ae); } //System.out.println("A(v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(1).getVal() ); List> Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v,v) mod p^k = " + Ae); try { List> lift; lift = HenselMultUtil. liftHensel(c, cp, Ae, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ae, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test univariate and multivariate Hensel lifting list, 2 variables. */ public void testHenselLifting2FullList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModLongRing pm = new ModLongRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 2, tord, new String[] { "x", "y" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); GenPolynomialRing icfac = ifac.contract(ifac.nvar - 1); GenPolynomialRing pcfac = pfac.contract(pfac.nvar - 1); BigInteger mi = m; long k = 5L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m + " = " + p + "^" + k); ModLongRing pkm = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); ModLong v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.parse(" ( x^3 y - 1 ) "); b = dfac.parse(" ( 1 + y ) "); e = dfac.parse(" ( y^2 - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //CL.add( CF.get(0) ); //System.out.println("CL = " + CL); List> Apk = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Apk.add(ap); } //System.out.println("A mod p^k = " + Apk); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); List> Ae = new ArrayList>(A.size()); for (GenPolynomial a : Apk) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae.add(ae); } //System.out.println("A(v) mod p^k = " + Ae); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : PolyUtil. integerFromModularCoefficients(icfac, Ae)) { ap = PolyUtil. fromIntegerCoefficients(pcfac, ai); Ap.add(ap); } //System.out.println("A(v) mod p = " + Ap); try { List> lift; lift = HenselMultUtil. liftHenselFull(c, Ap, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ap, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test univariate and multivariate Hensel lifting list, 3 variables. */ public void testHenselLifting3FullList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModLongRing pm = new ModLongRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 3, tord, new String[] { "x", "y", "z" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); GenPolynomialRing icfac = ifac.contract(ifac.nvar - 1); GenPolynomialRing pcfac = pfac.contract(pfac.nvar - 1); BigInteger mi = m; long k = 5L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m + " = " + p + "^" + k); ModLongRing pkm = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); ModLong v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); if (pkfac.nvar > 2) { V.add(new BigInteger(5L)); //pkm.fromInteger(5L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.parse(" ( x^3 z - y ) "); b = dfac.parse(" ( 1 + y + z ) "); e = dfac.parse(" ( z^2 y - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); //System.out.println("cp = " + cp); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //System.out.println("CL = " + CL); List> Apk = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Apk.add(ap); } //System.out.println("A mod p^k = " + Apk); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); List> Ae = new ArrayList>(A.size()); Ae = Apk; v = pkm.fromInteger( V.get(0).getVal() ); List> Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v) mod p^k = " + Ae); GenPolynomial cpp = PolyUtil. evaluateMain(ckfac, cp, v); //System.out.println("cpp = " + cpp); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(1).getVal() ); Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v) mod p^k = " + Ae); GenPolynomial cppp = PolyUtil. evaluateMain(ckfac, cpp, v); //System.out.println("cppp = " + cppp); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : PolyUtil. integerFromModularCoefficients(icfac, Ae)) { ap = PolyUtil. fromIntegerCoefficients(pcfac, ai); Ap.add(ap); } //System.out.println("A(v,v) mod p = " + Ap); GenPolynomial cpppp = PolyUtil. fromIntegerCoefficients(pcfac, PolyUtil. integerFromModularCoefficients(icfac, cppp)); //System.out.println("cpppp = " + cpppp); GenPolynomial aa = pcfac.getONE(); for (GenPolynomial x : Ap) { aa = aa.multiply(x); } assertTrue("prod(A(v,v)) mod p = " + aa + ", cpppp = " + cpppp + ", aa != cpppp: ", cpppp.equals(aa)); try { List> lift; lift = HenselMultUtil. liftHenselFull(c, Ap, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ap, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } /** * Test univariate and multivariate Hensel lifting list, 3 variables. */ public void testHenselLifting4FullList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModLongRing pm = new ModLongRing(p, false); GenPolynomialRing pfac = new GenPolynomialRing(pm, 4, tord, new String[] { "x", "y", "z", "w" }); GenPolynomialRing ifac = new GenPolynomialRing(new BigInteger(), pfac); GenPolynomialRing> irfac = ifac.recursive(ifac.nvar - 1); GenPolynomialRing icfac = ifac.contract(ifac.nvar - 1); GenPolynomialRing pcfac = pfac.contract(pfac.nvar - 1); BigInteger mi = m; long k = 5L; //long d = 3L; java.math.BigInteger pk = p.pow((int) k); //m = new BigInteger(pk); //System.out.println("m = " + m); ModLongRing pkm = new ModLongRing(pk, false); GenPolynomialRing pkfac = new GenPolynomialRing(pkm, pfac); dfac = new GenPolynomialRing(mi, pfac); //GreatestCommonDivisor ufd = GCDFactory.getProxy(mi); GreatestCommonDivisor ufd = GCDFactory.getImplementation(mi); ModLong v = pkm.fromInteger(3L); List V = new ArrayList(1); V.add(new BigInteger(3L)); if (pkfac.nvar > 2) { V.add(new BigInteger(5L)); //pkm.fromInteger(5L)); } if (pkfac.nvar > 3) { V.add(new BigInteger(7L)); //pkm.fromInteger(7L)); } //System.out.println("V = " + V); GenPolynomial ap; GenPolynomial cp; //GenPolynomial rp; List> A = new ArrayList>(); for (int i = 1; i < 2; i++) { a = dfac.parse(" ( x^3 w - y ) "); b = dfac.parse(" ( 1 + y + z + w ) "); e = dfac.parse(" ( z^2 y w - x ) "); A.add(a); A.add(b); A.add(e); //System.out.println("A = " + A); A = ufd.coPrime(A); //System.out.println("coprime(A) = " + A); // polynomials are rearranged if (A.size() == 0) { continue; } c = A.get(0).multiply(A.get(1)).multiply(A.get(2)); cp = PolyUtil. fromIntegerCoefficients(pkfac, c); //System.out.println("c = " + c); GenPolynomial> cr = PolyUtil. recursive(irfac, c); GenPolynomial> crr = PolyUtil. switchVariables(cr); //System.out.println("crr = " + crr); GenPolynomial cl = crr.leadingBaseCoefficient(); //System.out.println("cl = " + cl + ", cl.ring = " + cl.ring); FactorAbstract factorizer = FactorFactory.getImplementation(new BigInteger()); List> CF = factorizer.factorsRadical(cl); //System.out.println("CF = " + CF); List> CL = new ArrayList>(2); CL.add(CF.get(0)); CL.add(CF.get(2)); CL.add(CF.get(1)); //System.out.println("CL = " + CL); List> Apk = new ArrayList>(A.size()); for (GenPolynomial ai : A) { ap = PolyUtil. fromIntegerCoefficients(pkfac, ai); Apk.add(ap); } //System.out.println("A mod p^k = " + Apk); //System.out.println("v = " + v + ", V = " + V); GenPolynomialRing ckfac = pkfac.contract(1); v = pkm.fromInteger( V.get(0).getVal() ); List> Ae = new ArrayList>(A.size()); for (GenPolynomial a : Apk) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae.add(ae); } //System.out.println("A(v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(1).getVal() ); List> Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v) mod p^k = " + Ae); ckfac = ckfac.contract(1); v = pkm.fromInteger( V.get(2).getVal() ); Ae1 = new ArrayList>(A.size()); for (GenPolynomial a : Ae) { // Ap GenPolynomial ae = PolyUtil. evaluateMain(ckfac, a, v); Ae1.add(ae); } Ae = Ae1; //System.out.println("A(v,v,v) mod p^k = " + Ae); List> Ap = new ArrayList>(A.size()); for (GenPolynomial ai : PolyUtil. integerFromModularCoefficients(icfac, Ae)) { ap = PolyUtil. fromIntegerCoefficients(pcfac, ai); Ap.add(ap); } //System.out.println("A(v,v,v) mod p = " + Ap); try { List> lift; //lift = HenselMultUtil. liftHensel(c, cp, Ae, V, k, CL); // 5 is max lift = HenselMultUtil. liftHenselFull(c, Ap, V, k, CL); // 5 is max //System.out.println("\nliftMultiHensel:"); //System.out.println("lift = " + lift); //System.out.println("A = " + A); boolean t = HenselMultUtil. isHenselLift(c, cp, Ap, lift); assertTrue("isHenselLift: ", t); } catch (ArithmeticException e) { // ok, can happen System.out.println("e = " + e); } catch (NoLiftingException e) { // can now happen: fail("" + e); System.out.println("e = " + e); } } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/HenselUtilTest.java000066400000000000000000001466551445075545500242360ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModularRingFactory; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; /** * HenselUtil tests with JUnit. * @author Heinz Kredel */ public class HenselUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a HenselUtilTest object. * @param name String. */ public HenselUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(HenselUtilTest.class); return suite; } //private final static int bitlen = 100; TermOrder to = new TermOrder(TermOrder.INVLEX); GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai; BigInteger bi; BigInteger ci; BigInteger di; BigInteger ei; GenPolynomial a; GenPolynomial b; GenPolynomial c; GenPolynomial d; GenPolynomial e; int rl = 5; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; cfac = null; rfac = null; ComputerThreads.terminate(); } protected static java.math.BigInteger getPrime1() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //prime = 37; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } prime -= 35; //prime = 19; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test Hensel lifting. */ public void testHenselLifting() { java.math.BigInteger p; p = getPrime1(); //p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing pfac = new GenPolynomialRing(pm, 1, to); dfac = new GenPolynomialRing(mi, 1, to); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial sp; GenPolynomial tp; GenPolynomial[] egcd; GenPolynomial ap1; GenPolynomial bp1; HenselApprox lift; GenPolynomial a1; GenPolynomial b1; GenPolynomial c1; for (int i = 1; i < 3; i++) { a = dfac.random(kl + 70 * i, ll, el + 5, q).abs(); b = dfac.random(kl + 70 * i, ll, el + 5, q).abs(); //a = dfac.univariate(0).sum( dfac.fromInteger(30) ); //b = dfac.univariate(0).subtract( dfac.fromInteger(20) ); //b = b.multiply( dfac.univariate(0) ).sum( dfac.fromInteger(168)); c = a.multiply(b); if (a.degree(0) < 1 || b.degree(0) < 2) { continue; } ap = PolyUtil.fromIntegerCoefficients(pfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(pfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } cp = PolyUtil.fromIntegerCoefficients(pfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } ap1 = ap; //.monic(); bp1 = bp; //.monic(); egcd = ap1.egcd(bp1); if (!egcd[0].isONE()) { continue; } sp = egcd[1]; tp = egcd[2]; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //--System.out.println("mi = " + mi); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); // System.out.println("ap*bp = " + ap.multiply(bp)); //System.out.println("gcd = " + egcd[0]); //System.out.println("gcd = " + ap1.multiply(sp).sum(bp1.multiply(tp))); //System.out.println("sp = " + sp); //System.out.println("tp = " + tp); try { lift = HenselUtil. liftHensel(c, mi, ap, bp, sp, tp); a1 = lift.A; b1 = lift.B; c1 = a1.multiply(b1); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a1 = " + a1); //System.out.println("b1 = " + b1); //System.out.println("a1*b1 = " + c1); //assertEquals("lift(a mod p) = a",a,a1); //assertEquals("lift(b mod p) = b",b,b1); assertEquals("lift(a b mod p) = a b", c, c1); } catch (NoLiftingException e) { fail("" + e); } } } /** * Test Hensel lifting with gcd. */ public void testHenselLiftingGcd() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing pfac = new GenPolynomialRing(pm, 1, to); dfac = new GenPolynomialRing(mi, 1, to); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; HenselApprox lift; GenPolynomial a1; GenPolynomial b1; GenPolynomial c1; for (int i = 1; i < 3; i++) { // 70 better for quadratic a = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); b = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); //a = dfac.univariate(0).sum( dfac.fromInteger(30) ); //b = dfac.univariate(0).subtract( dfac.fromInteger(20) ); //b = b.multiply( dfac.univariate(0) ).sum( dfac.fromInteger(168)); c = a.multiply(b); if (a.degree(0) < 1 || b.degree(0) < 2) { continue; } ap = PolyUtil.fromIntegerCoefficients(pfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(pfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } cp = PolyUtil.fromIntegerCoefficients(pfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //--System.out.println("mi = " + mi); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); // System.out.println("ap*bp = " + ap.multiply(bp)); //System.out.println("gcd = " + egcd[0]); //System.out.println("gcd = " + ap1.multiply(sp).sum(bp1.multiply(tp))); //System.out.println("sp = " + sp); //System.out.println("tp = " + tp); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftHensel(c, mi, ap, bp); tq = System.currentTimeMillis() - tq; a1 = lift.A; b1 = lift.B; c1 = a1.multiply(b1); assertEquals("lift(a b mod p) = a b", c, c1); } catch (NoLiftingException e) { // ok no fail(""+e); } //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a1 = " + a1); //System.out.println("b1 = " + b1); //System.out.println("a1*b1 = " + c1); //assertEquals("lift(a mod p) = a",a,a1); //assertEquals("lift(b mod p) = b",b,b1); } } /** * Test Hensel quadratic lifting. */ public void testHenselQuadraticLifting() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing pfac = new GenPolynomialRing(pm, 1, to); dfac = new GenPolynomialRing(mi, pfac); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial sp; GenPolynomial tp; GenPolynomial[] egcd; GenPolynomial ap1; GenPolynomial bp1; HenselApprox lift; GenPolynomial a1; GenPolynomial b1; GenPolynomial c1; for (int i = 1; i < 3; i++) { // 70 better for quadratic a = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); b = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); //a = dfac.univariate(0).sum( dfac.fromInteger(30) ); //b = dfac.univariate(0).subtract( dfac.fromInteger(20) ); //b = b.multiply( dfac.univariate(0) ).sum( dfac.fromInteger(168)); c = a.multiply(b); if (a.degree(0) < 1 || b.degree(0) < 2) { continue; } ap = PolyUtil.fromIntegerCoefficients(pfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(pfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } cp = PolyUtil.fromIntegerCoefficients(pfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } ap1 = ap; //.monic(); bp1 = bp; //.monic(); egcd = ap1.egcd(bp1); if (!egcd[0].isONE()) { continue; } sp = egcd[1]; tp = egcd[2]; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //--System.out.println("mi = " + mi); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); // System.out.println("ap*bp = " + ap.multiply(bp)); //System.out.println("gcd = " + egcd[0]); //System.out.println("gcd = " + ap1.multiply(sp).sum(bp1.multiply(tp))); //System.out.println("sp = " + sp); //System.out.println("tp = " + tp); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftHenselQuadratic(c, mi, ap, bp, sp, tp); tq = System.currentTimeMillis() - tq; a1 = lift.A; b1 = lift.B; c1 = a1.multiply(b1); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a1 = " + a1); //System.out.println("b1 = " + b1); //System.out.println("a1*b1 = " + c1); //assertEquals("lift(a mod p) = a",a,a1); //assertEquals("lift(b mod p) = b",b,b1); assertEquals("lift(a b mod p) = a b", c, c1); } catch (NoLiftingException e) { fail("" + e); } boolean x = false; if (x) { x = true; // nonsense long t = System.currentTimeMillis(); try { lift = HenselUtil. liftHensel(c, mi, ap, bp, sp, tp); t = System.currentTimeMillis() - t; a1 = lift.A; b1 = lift.B; c1 = a1.multiply(b1); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a1 = " + a1); //System.out.println("b1 = " + b1); //System.out.println("a1*b1 = " + c1); //assertEquals("lift(a mod p) = a",a,a1); //assertEquals("lift(b mod p) = b",b,b1); assertEquals("lift(a b mod p) = a b", c, c1); } catch (NoLiftingException e) { fail("" + e); } System.out.println("\nquadratic Hensel time = " + tq); System.out.println("linear Hensel time = " + t); } //break; } } /** * Test Hensel quadratic lifting with gcd. */ public void testHenselQuadraticLiftingGcd() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing pfac = new GenPolynomialRing(pm, 1, to); dfac = new GenPolynomialRing(mi, pfac); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; HenselApprox lift; GenPolynomial a1; GenPolynomial b1; GenPolynomial c1; for (int i = 1; i < 3; i++) { // 70 better for quadratic a = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); b = dfac.random(kl + 70 * i, ll + 10, el + 5, q).abs(); //a = dfac.univariate(0).sum( dfac.fromInteger(30) ); //b = dfac.univariate(0).subtract( dfac.fromInteger(20) ); //b = b.multiply( dfac.univariate(0) ).sum( dfac.fromInteger(168)); c = a.multiply(b); if (a.degree(0) < 1 || b.degree(0) < 2) { continue; } ap = PolyUtil.fromIntegerCoefficients(pfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(pfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } cp = PolyUtil.fromIntegerCoefficients(pfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //--System.out.println("mi = " + mi); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); // System.out.println("ap*bp = " + ap.multiply(bp)); //System.out.println("gcd = " + egcd[0]); //System.out.println("gcd = " + ap1.multiply(sp).sum(bp1.multiply(tp))); //System.out.println("sp = " + sp); //System.out.println("tp = " + tp); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftHenselQuadratic(c, mi, ap, bp); tq = System.currentTimeMillis() - tq; a1 = lift.A; b1 = lift.B; c1 = a1.multiply(b1); assertEquals("lift(a b mod p) = a b", c, c1); } catch (NoLiftingException e) { //ok no fail(""+e); } //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("a1 = " + a1); //System.out.println("b1 = " + b1); //System.out.println("a1*b1 = " + c1); //assertEquals("lift(a mod p) = a",a,a1); //assertEquals("lift(b mod p) = b",b,b1); } } /** * Test lifting of extended Euclidean relation. */ public void testLiftingEgcd() { java.math.BigInteger p; //p = getPrime1(); //p = new java.math.BigInteger("19"); p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); //BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing mfac = new GenPolynomialRing(pm, 1, to, new String[] { "x" }); dfac = new GenPolynomialRing(m, mfac); GreatestCommonDivisorAbstract ufd = GCDFactory.getProxy(m); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial dp; GenPolynomial[] lift; GenPolynomial s; GenPolynomial t; for (int i = 1; i < 2; i++) { // 70 better for quadratic a = dfac.random(kl + 3 * i, ll + 1, el + 1, q).abs(); b = dfac.random(kl + 3 * i, ll + 1, el + 5, q).abs(); d = ufd.baseGcd(a, b); //System.out.println("d = " + d); if (!d.isONE()) { a = PolyUtil. basePseudoDivide(a, d); b = PolyUtil. basePseudoDivide(b, d); } if (a.degree(0) < 1 || b.degree(0) < 2) { continue; } ap = PolyUtil.fromIntegerCoefficients(mfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(mfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } dp = ap.gcd(bp); //System.out.println("dp = " + dp); if (!dp.isONE()) { continue; } c = a.multiply(b); cp = PolyUtil.fromIntegerCoefficients(mfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger mi; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } long k = 1; BigInteger pi = m; while (pi.compareTo(mi) < 0) { k++; pi = pi.multiply(m); } //System.out.println("mi = " + mi); //System.out.println("pi = " + pi); //System.out.println("k = " + k); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftExtendedEuclidean(ap, bp, k); tq = System.currentTimeMillis() - tq; s = lift[0]; t = lift[1]; ModularRingFactory mcfac = (ModularRingFactory) s.ring.coFac; GenPolynomialRing mfac1 = new GenPolynomialRing(mcfac, mfac); //System.out.println("\nmcfac = " + mcfac); ap = PolyUtil.fromIntegerCoefficients(mfac1, PolyUtil.integerFromModularCoefficients(dfac, ap)); bp = PolyUtil.fromIntegerCoefficients(mfac1, PolyUtil.integerFromModularCoefficients(dfac, bp)); cp = s.multiply(ap).sum(t.multiply(bp)); //System.out.println("s = " + s); //System.out.println("t = " + t); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); assertTrue("lift(s a + t b mod p^k) = 1: " + cp, cp.isONE()); } catch (NoLiftingException e) { fail("" + e); } //System.out.println("time = " + tq); } } /** * Test lifting of list of extended Euclidean relation. */ public void testLiftingEgcdList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); // BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing mfac = new GenPolynomialRing(pm, 1, to, new String[] { "x" }); dfac = new GenPolynomialRing(m, mfac); GreatestCommonDivisorAbstract ufd = GCDFactory.getProxy(m); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial dp; GenPolynomial ep; List> lift; //GenPolynomial s; //GenPolynomial t; for (int i = 1; i < 2; i++) { // 70 better for quadratic a = dfac.random(kl + 3 * i, ll + 5, el + 1, q).abs(); //a = dfac.parse("(x - 1)"); b = dfac.random(kl + 3 * i, ll + 5, el + 5, q).abs(); //b = dfac.parse("(x - 2)"); e = ufd.baseGcd(a, b); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); b = PolyUtil. basePseudoDivide(b, e); } if (a.degree(0) < 1 || b.degree(0) < 1) { continue; } ap = PolyUtil.fromIntegerCoefficients(mfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(mfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } ep = ap.gcd(bp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } d = dfac.random(kl + 3 * i, ll + 5, el + 4, q).abs(); //d = dfac.parse("(x - 3)"); e = ufd.baseGcd(a, d); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); d = PolyUtil. basePseudoDivide(d, e); } e = ufd.baseGcd(b, d); //System.out.println("e = " + e); if (!e.isONE()) { b = PolyUtil. basePseudoDivide(b, e); d = PolyUtil. basePseudoDivide(d, e); } if (d.degree(0) < 1) { continue; } dp = PolyUtil.fromIntegerCoefficients(mfac, d); if (!d.degreeVector().equals(dp.degreeVector())) { continue; } c = a.multiply(b).multiply(d); cp = PolyUtil.fromIntegerCoefficients(mfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger mi; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } BigInteger dn = d.maxNorm(); if (dn.compareTo(mi) > 0) { mi = dn; } long k = 1; BigInteger pi = m; while (pi.compareTo(mi) < 0) { k++; pi = pi.multiply(m); } //System.out.println("mi = " + mi); //System.out.println("pi = " + pi); //System.out.println("k = " + k); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("d = " + d); //System.out.println("c = " + c); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("dp = " + dp); //System.out.println("cp = " + cp); List> A = new ArrayList>(); List> As; // = new ArrayList>(); A.add(ap); A.add(bp); A.add(dp); //A.add(mfac.parse("(x - 4)")); //A.add(mfac.parse("(x - 5)")); //System.out.println("A = " + A); List> A2 = new ArrayList>(); List> As2 = new ArrayList>(); //System.out.println("A2 = " + A2); long tq = System.currentTimeMillis(); try { A2.add(ap); A2.add(bp); GenPolynomial[] L = HenselUtil. liftExtendedEuclidean(ap, bp, k); //System.out.println("lift(a,b) = " + L[0] + ", " + L[1] + "\n"); lift = HenselUtil. liftExtendedEuclidean(A, k); tq = System.currentTimeMillis() - tq; //System.out.println(""); //System.out.println("lift(a,b) = " + L[0] + ", " + L[1] ); //System.out.println("lift = " + lift); As = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(dfac, lift)); //System.out.println("As = " + As); boolean il = HenselUtil. isExtendedEuclideanLift(A, As); //System.out.println("islift = " + il); assertTrue("lift(s0,s1,s2) mod p^k) = 1: ", il); As2.add(L[1]); As2.add(L[0]); As2 = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(dfac, As2)); //System.out.println("As2 = " + As2); il = HenselUtil. isExtendedEuclideanLift(A2, As2); //System.out.println("islift = " + il); assertTrue("lift(s a + t b mod p^k) = 1: ", il); } catch (NoLiftingException e) { // ok fail(""+e); } //System.out.println("time = " + tq); } } /** * Test lifting of list of Diophant relation. */ public void testLiftingDiophantList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); //.multiply(p).multiply(p).multiply(p); // BigInteger mi = m; ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing mfac = new GenPolynomialRing(pm, 1, to, new String[] { "x" }); dfac = new GenPolynomialRing(m, mfac); GreatestCommonDivisorAbstract ufd = GCDFactory.getProxy(m); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial dp; GenPolynomial ep; GenPolynomial fp; List> lift; //GenPolynomial s; //GenPolynomial t; for (int i = 1; i < 2; i++) { // 70 better for quadratic a = dfac.random(kl + 3 * i, ll + 5, el + 1, q).abs(); //a = dfac.parse("(x - 1)"); b = dfac.random(kl + 3 * i, ll + 5, el + 5, q).abs(); //b = dfac.parse("(x - 2)"); e = ufd.baseGcd(a, b); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); b = PolyUtil. basePseudoDivide(b, e); } if (a.degree(0) < 1 || b.degree(0) < 1) { continue; } ap = PolyUtil.fromIntegerCoefficients(mfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(mfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } ep = ap.gcd(bp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } d = dfac.random(kl + 3 * i, ll + 5, el + 4, q).abs(); //d = dfac.parse("(x - 3)"); e = ufd.baseGcd(a, d); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); d = PolyUtil. basePseudoDivide(d, e); } e = ufd.baseGcd(b, d); //System.out.println("e = " + e); if (!e.isONE()) { b = PolyUtil. basePseudoDivide(b, e); d = PolyUtil. basePseudoDivide(d, e); } if (d.degree(0) < 1) { continue; } dp = PolyUtil.fromIntegerCoefficients(mfac, d); if (!d.degreeVector().equals(dp.degreeVector())) { continue; } c = a.multiply(b).multiply(d); cp = PolyUtil.fromIntegerCoefficients(mfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger mi; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } BigInteger dn = d.maxNorm(); if (dn.compareTo(mi) > 0) { mi = dn; } long k = 1; BigInteger pi = m; while (pi.compareTo(mi) < 0) { k++; pi = pi.multiply(m); } //System.out.println("mi = " + mi); //System.out.println("pi = " + pi); //System.out.println("k = " + k); fp = mfac.random(4); //mfac.univariate(0,2); //mfac.getONE(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("d = " + d); //System.out.println("c = " + c); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("dp = " + dp); //System.out.println("cp = " + cp); //List> A = new ArrayList>(); List> As; // = new ArrayList>(); //A.add(ap); //A.add(bp); //A.add(dp); //A.add(mfac.parse("(x - 4)")); //A.add(mfac.parse("(x - 5)")); //System.out.println("A = " + A); List> A2 = new ArrayList>(); List> As2 = new ArrayList>(); //System.out.println("A2 = " + A2); long tq = System.currentTimeMillis(); try { A2.add(ap); A2.add(bp); List> L = HenselUtil. liftDiophant(ap, bp, fp, k); //System.out.println("lift(a,b) = " + L[0] + ", " + L[1] + "\n"); lift = HenselUtil. liftDiophant(A2, fp, k); tq = System.currentTimeMillis() - tq; //System.out.println(""); //System.out.println("lift(a,b) = " + L[0] + ", " + L[1] ); //System.out.println("lift = " + lift); As = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(dfac, lift)); //System.out.println("As = " + As); boolean il = HenselUtil. isDiophantLift(A2, As, fp); //System.out.println("islift = " + il); assertTrue("lift(s0,s1,s2) mod p^k) = 1: ", il); As2.add(L.get(0)); As2.add(L.get(1)); As2 = PolyUtil.fromIntegerCoefficients(mfac, PolyUtil.integerFromModularCoefficients(dfac, As2)); //System.out.println("As2 = " + As2); il = HenselUtil. isDiophantLift(A2, As2, fp); //System.out.println("islift = " + il); assertTrue("lift(s a + t b mod p^k) = 1: ", il); } catch (NoLiftingException e) { // ok fail(""+e); } //System.out.println("time = " + tq); } } /** * Test Hensel monic lifting new list version. */ public void testHenselLiftingMonicList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("268435399"); //p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing mfac = new GenPolynomialRing(pm, 1, to, new String[] { "x" }); dfac = new GenPolynomialRing(m, mfac); GreatestCommonDivisorAbstract ufd = GCDFactory.getProxy(m); BigInteger one = m.getONE(); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial dp; GenPolynomial ep; List> lift; //GenPolynomial s; //GenPolynomial t; for (int i = 1; i < 2; i++) { // 70 better for quadratic //a = dfac.random(kl + 30 * i, ll + 5, el + 3, q).abs(); a = dfac.parse("(x^3 + 20 x^2 - 313131)"); //a = dfac.parse("(x^6 - 24 x^2 - 17)"); //a = dfac.parse("(x^6 + 48)"); b = dfac.random(kl + 30 * i, ll + 5, el + 5, q).abs(); //b = dfac.parse("(x^4 + 23 x^3 - 32)"); //b = dfac.parse("(x^7 + 1448)"); //b = dfac.parse("(x^14 + 44)"); if (!a.leadingBaseCoefficient().isUnit()) { ExpVector e = a.leadingExpVector(); a.doPutToMap(e, one); } if (!b.leadingBaseCoefficient().isUnit()) { ExpVector e = b.leadingExpVector(); b.doPutToMap(e, one); } e = ufd.baseGcd(a, b); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); b = PolyUtil. basePseudoDivide(b, e); } if (a.degree(0) < 1) { a = dfac.parse("(x^3 + 20 x^2 - 313131)"); } if (b.degree(0) < 1) { b = dfac.parse("(x^4 + 23 x^3 - 32)"); } ap = PolyUtil.fromIntegerCoefficients(mfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(mfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } ep = ap.gcd(bp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } d = dfac.random(kl + 30 * i, ll + 5, el + 4, q).abs(); //d = dfac.parse("(x^2 + 22 x - 33)"); if (!d.leadingBaseCoefficient().isUnit()) { ExpVector e = d.leadingExpVector(); d.doPutToMap(e, one); } e = ufd.baseGcd(a, d); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); d = PolyUtil. basePseudoDivide(d, e); } e = ufd.baseGcd(b, d); //System.out.println("e = " + e); if (!e.isONE()) { b = PolyUtil. basePseudoDivide(b, e); d = PolyUtil. basePseudoDivide(d, e); } if (d.degree(0) < 1) { d = dfac.parse("(x^2 + 22 x - 33)"); //continue; } dp = PolyUtil.fromIntegerCoefficients(mfac, d); if (!d.degreeVector().equals(dp.degreeVector())) { continue; } ep = ap.gcd(dp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } ep = bp.gcd(dp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } c = a.multiply(b).multiply(d); cp = PolyUtil.fromIntegerCoefficients(mfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } //c = dfac.parse("( (x^6 + 48) * (x^14 + 44) )"); BigInteger mi; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } BigInteger dn = d.maxNorm(); if (dn.compareTo(mi) > 0) { mi = dn; } long k = 1; BigInteger pi = m; while (pi.compareTo(mi) < 0) { k++; pi = pi.multiply(m); } k++; pi = pi.multiply(m); //System.out.println("mi = " + mi); //System.out.println("pi = " + pi); //System.out.println("k = " + k); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("d = " + d); //System.out.println("c = " + c); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("dp = " + dp); //System.out.println("cp = " + cp); List> A = new ArrayList>(); //List> As; // = new ArrayList>(); A.add(ap); A.add(bp); A.add(dp); //A.add(mfac.parse("(x^3 + 26602528)")); //A.add(mfac.parse("(31493559 x^3 + 69993768)")); //A.add(mfac.parse("(121154481 x^7 + 268435398)")); //A.add(mfac.parse("(151258699 x^7 + 90435272)")); //monic: x^3 + 26602528 , x^3 + 241832871 , x^7 + 230524583 , x^7 + 37910816 //A.add( mfac.parse("((x^3 + 26602528)*(31493559 x^3 + 69993768))") ); //A.add( mfac.parse("((121154481 x^7 + 268435398)*(151258699 x^7 + 90435272))") ); //System.out.println("A = " + A); A = PolyUtil.monic(A); //System.out.println("A = " + A); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftHenselMonic(c, A, k); tq = System.currentTimeMillis() - tq; //System.out.println("\nk = " + k); //System.out.println("c = " + c); //System.out.println("A = " + A); //System.out.println("Ai = [" + a + ", " + b + ", " + d + "]"); //System.out.println("lift = " + lift); List> L = PolyUtil.integerFromModularCoefficients(dfac, lift); //System.out.println("L = " + L); //ModularRingFactory mcfac = (ModularRingFactory) lift.get(0).ring.coFac; //GenPolynomialRing mfac1 = new GenPolynomialRing(mcfac, mfac); //System.out.println("\nmcfac = " + mcfac); boolean ih = HenselUtil.isHenselLift(c, m, pi, L); //System.out.println("ih = " + ih); assertTrue("prod(lift(L)) = c: " + c, ih); } catch (NoLiftingException e) { // ok fail(""+e); } //System.out.println("time = " + tq); } } /** * Test Hensel lifting new list version. */ public void testHenselLiftingList() { java.math.BigInteger p; //p = getPrime1(); p = new java.math.BigInteger("268435399"); //p = new java.math.BigInteger("19"); //p = new java.math.BigInteger("5"); BigInteger m = new BigInteger(p); ModIntegerRing pm = new ModIntegerRing(p, true); GenPolynomialRing mfac = new GenPolynomialRing(pm, 1, to, new String[] { "x" }); dfac = new GenPolynomialRing(m, mfac); GreatestCommonDivisorAbstract ufd = GCDFactory.getProxy(m); //BigInteger one = m.getONE(); GenPolynomial ap; GenPolynomial bp; GenPolynomial cp; GenPolynomial dp; GenPolynomial ep; List> lift; //GenPolynomial s; //GenPolynomial t; for (int i = 1; i < 2; i++) { // 70 better for quadratic a = dfac.random(kl + 30 * i, ll + 5, el + 3, q).abs(); //a = dfac.parse("( 35333333 x^3 + 20 x^2 - 313131)"); a = ufd.basePrimitivePart(a); b = dfac.random(kl + 30 * i, ll + 5, el + 5, q).abs(); //b = dfac.parse("( 51111 x^4 + 23 x^3 - 32)"); b = ufd.basePrimitivePart(b); e = ufd.baseGcd(a, b); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); b = PolyUtil. basePseudoDivide(b, e); } if (a.degree(0) < 1) { a = dfac.parse("( 3 x^3 + 20 x^2 - 313131)"); } if (b.degree(0) < 1) { b = dfac.parse("( 5 x^4 + 23 x^3 - 32)"); } ap = PolyUtil.fromIntegerCoefficients(mfac, a); if (!a.degreeVector().equals(ap.degreeVector())) { continue; } bp = PolyUtil.fromIntegerCoefficients(mfac, b); if (!b.degreeVector().equals(bp.degreeVector())) { continue; } ep = ap.gcd(bp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } d = dfac.random(kl + 30 * i, ll + 5, el + 4, q).abs(); //d = dfac.parse("( 711111 x^2 + 22 x - 33)"); //d = dfac.parse("( 7 x^2 + 22 x - 33)"); d = ufd.basePrimitivePart(d); e = ufd.baseGcd(a, d); //System.out.println("e = " + e); if (!e.isONE()) { a = PolyUtil. basePseudoDivide(a, e); d = PolyUtil. basePseudoDivide(d, e); } e = ufd.baseGcd(b, d); //System.out.println("e = " + e); if (!e.isONE()) { b = PolyUtil. basePseudoDivide(b, e); d = PolyUtil. basePseudoDivide(d, e); } if (d.degree(0) < 1) { d = dfac.parse("( 7 x^2 + 22 x - 33)"); //continue; } dp = PolyUtil.fromIntegerCoefficients(mfac, d); if (!d.degreeVector().equals(dp.degreeVector())) { continue; } ep = ap.gcd(dp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } ep = bp.gcd(dp); //System.out.println("ep = " + ep); if (!ep.isONE()) { continue; } c = a.multiply(b).multiply(d); cp = PolyUtil.fromIntegerCoefficients(mfac, c); if (!c.degreeVector().equals(cp.degreeVector())) { continue; } BigInteger mi; BigInteger an = a.maxNorm(); BigInteger bn = b.maxNorm(); if (an.compareTo(bn) > 0) { mi = an; } else { mi = bn; } BigInteger cn = c.maxNorm(); if (cn.compareTo(mi) > 0) { mi = cn; } BigInteger dn = d.maxNorm(); if (dn.compareTo(mi) > 0) { mi = dn; } long k = 1; BigInteger pi = m; while (pi.compareTo(mi) < 0) { k++; pi = pi.multiply(m); } k++; pi = pi.multiply(m); //System.out.println("mi = " + mi); //System.out.println("p = " + p); //System.out.println("pi = " + pi); //System.out.println("k = " + k); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("d = " + d); //System.out.println("c = " + c); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("dp = " + dp); //System.out.println("cp = " + cp); List> A = new ArrayList>(); //List> Ai = new ArrayList>(); //Ai.add(a); //Ai.add(b); //Ai.add(d); A.add(ap); A.add(bp); A.add(dp); //System.out.println("Ai = " + Ai); //System.out.println("A = " + A); long tq = System.currentTimeMillis(); try { lift = HenselUtil. liftHensel(c, A, k, c.leadingBaseCoefficient()); tq = System.currentTimeMillis() - tq; //System.out.println("\nk = " + k); //System.out.println("c = " + c); //System.out.println("A = " + A); //System.out.println("Ai = [" + a + ", " + b + ", " + d + "]"); //System.out.println("lift = " + lift); List> L = PolyUtil.integerFromModularCoefficients(dfac, lift); //System.out.println("L = " + L); //System.out.println("Ai = " + Ai); boolean ih = HenselUtil.isHenselLift(c, m, pi, L); //System.out.println("ih = " + ih); assertTrue("prod(lift(L)) = c: " + c, ih); } catch (NoLiftingException e) { // ok fail("" + e); } //System.out.println("time = " + tq); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/PolyUfdUtilTest.java000066400000000000000000000610151445075545500243640ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInt; import edu.jas.arith.ModIntRing; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.poly.TermOrderByName; import edu.jas.ps.UnivPowerSeries; import edu.jas.ps.UnivPowerSeriesRing; import edu.jas.structure.Power; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.GenVector; import edu.jas.vector.LinAlg; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * PolyUfdUtil tests with JUnit. * @author Heinz Kredel */ public class PolyUfdUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a PolyUtilTest object. * @param name String. */ public PolyUfdUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PolyUfdUtilTest.class); return suite; } TermOrder to = TermOrderByName.INVLEX; GenPolynomialRing dfac; GenPolynomialRing cfac; GenPolynomialRing> rfac; BigInteger ai, bi, ci, di, ei; GenPolynomial a, b, c, d, e; GenPolynomial> ar, br, cr, dr, er; GenPolynomialRing crfac; GenPolynomialRing> rrfac; GenPolynomial> arr, brr, crr, drr, err, frr; int rl = 5; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = new GenPolynomialRing(new BigInteger(1), rl, to); cfac = new GenPolynomialRing(new BigInteger(1), rl - 1, to); rfac = new GenPolynomialRing>(cfac, 1, to); } @Override protected void tearDown() { a = b = c = d = e = null; ai = bi = ci = di = ei = null; dfac = null; cfac = null; rfac = null; ComputerThreads.terminate(); } protected static java.math.BigInteger getPrime1() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 60; i++) { prime *= 2; } prime -= 93; //prime = 37; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } protected static java.math.BigInteger getPrime2() { long prime = 2; //2^60-93; // 2^30-35; //19; knuth (2,390) for (int i = 1; i < 30; i++) { prime *= 2; } prime -= 35; //prime = 19; //System.out.println("p1 = " + prime); return new java.math.BigInteger("" + prime); } /** * Test Kronecker substitution. */ public void testKroneckerSubstitution() { for (int i = 0; i < 10; i++) { a = dfac.random(kl, ll * 2, el * 5, q); long d = a.degree() + 1L; //System.out.println("\na = " + a); //System.out.println("deg(a)+1 = " + d); b = PolyUfdUtil. substituteKronecker(a, d); //System.out.println("b = " + b); c = PolyUfdUtil. backSubstituteKronecker(dfac, b, d); //System.out.println("c = " + c); e = a.subtract(c); //System.out.println("e = " + e); assertTrue("back(subst(a)) = a", e.isZERO()); } } /** * Test algebraic number field. */ public void testAlgebraicNumberField() { int deg = 11; // characteristic non zero, small ModLongRing gfp = new ModLongRing(32003); //System.out.println("gfp = " + gfp.toScript()); AlgebraicNumberRing gfpq = PolyUfdUtil. algebraicNumberField(gfp, deg); //System.out.println("gfpq = " + gfpq.toScript()); assertTrue("gfpq.isField: ", gfpq.isField()); // characteristic non zero, large ModIntegerRing gfP = new ModIntegerRing(getPrime1()); //System.out.println("gfP = " + gfP.toScript()); AlgebraicNumberRing gfPq = PolyUfdUtil. algebraicNumberField(gfP, deg); //System.out.println("gfPq = " + gfPq.toScript()); assertTrue("gfPq.isField: ", gfPq.isField()); // characteristic zero BigRational q = BigRational.ONE; //System.out.println("q = " + q.toScriptFactory()); AlgebraicNumberRing gfqq = PolyUfdUtil. algebraicNumberField(q, deg); //System.out.println("gfqq = " + gfqq.toScript()); assertTrue("gfqq.isField: ", gfqq.isField()); //PolyUfdUtil. ensureFieldProperty(gfqq); //System.out.println("gfqq = " + gfqq); //assertTrue("gfqq.isField: ", gfqq.isField()); } /** * Test recursive dense pseudo division. */ public void testRecursivePseudoDivisionDense() { String[] cnames = new String[] { "x" }; String[] mnames = new String[] { "t" }; dfac = new GenPolynomialRing(new BigInteger(1), to, cnames); //GenPolynomialRing rdfac = new GenPolynomialRing(new BigRational(1),dfac); rfac = new GenPolynomialRing>(dfac, to, mnames); QuotientRing qfac = new QuotientRing(dfac); GenPolynomialRing> rqfac = new GenPolynomialRing>(qfac, rfac); //System.out.println("\ndfac = " + dfac); //System.out.println("rdfac = " + rdfac); //System.out.println("rfac = " + rfac); //System.out.println("qfac = " + qfac); //System.out.println("rqfac = " + rqfac); ar = rfac.random(kl, 2 * ll, el + 4, q); //ar = rfac.parse(" ( -2 x^4 + 8 x^3 - 5 x^2 - x + 6 ) t^3 + ( 2 x - 8 ) t^2 - ( 13 x^4 - 13 x^3 + x^2 + 2 x - 13 ) "); br = rfac.random(kl, 2 * ll, el + 2, q); //ar = ar.multiply(br); //br = rfac.parse(" ( 13 ) t^3 + ( 3 x^2 - 6 ) t - ( 13 x^4 - 8 x^3 + 10 x^2 + 22 x + 21 ) "); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = PolyUtil. recursivePseudoDivide(ar, br); //System.out.println("qr = " + dr); cr = PolyUtil. recursiveDensePseudoRemainder(ar, br); //System.out.println("rr = " + cr); //boolean t = PolyUtil. isRecursivePseudoQuotientRemainder(ar, br, dr, cr); //System.out.println("assertTrue lc^n a = q b + r: " + t); //assertTrue("lc^n a = q b + r: " + cr, t); // ?? not always true GenPolynomial> ap = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, ar); GenPolynomial> bp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, br); GenPolynomial> cp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, cr); GenPolynomial> dp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, dr); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); ////System.out.println("dp = " + dp); //System.out.println("dp = " + dp.monic()); GenPolynomial> qp = ap.divide(bp); GenPolynomial> rp = ap.remainder(bp); ////System.out.println("qp = " + qp); //System.out.println("qp = " + qp.monic()); //System.out.println("rp = " + rp); GenPolynomial> rhs = qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap = qp bp + rp: ", ap, rhs); assertEquals("cp = rp: ", rp.monic(), cp.monic()); //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); assertEquals("dp = qp: ", qp.monic(), dp.monic()); // ?? } /** * Test recursive sparse pseudo division. */ public void testRecursivePseudoDivisionSparse() { String[] cnames = new String[] { "x" }; String[] mnames = new String[] { "t" }; dfac = new GenPolynomialRing(new BigInteger(1), to, cnames); //GenPolynomialRing rdfac = new GenPolynomialRing(new BigRational(1),dfac); rfac = new GenPolynomialRing>(dfac, to, mnames); QuotientRing qfac = new QuotientRing(dfac); GenPolynomialRing> rqfac = new GenPolynomialRing>(qfac, rfac); //System.out.println("\ndfac = " + dfac); //System.out.println("rdfac = " + rdfac); //System.out.println("rfac = " + rfac); //System.out.println("qfac = " + qfac); //System.out.println("rqfac = " + rqfac); ar = rfac.random(kl, 2 * ll, el + 4, q); //ar = rfac.parse(" ( -2 x^4 + 8 x^3 - 5 x^2 - x + 6 ) t^3 + ( 2 x - 8 ) t^2 - ( 13 x^4 - 13 x^3 + x^2 + 2 x - 13 ) "); br = rfac.random(kl, 2 * ll, el + 2, q); //ar = ar.multiply(br); //br = rfac.parse(" ( 13 ) t^3 + ( 3 x^2 - 6 ) t - ( 13 x^4 - 8 x^3 + 10 x^2 + 22 x + 21 ) "); //System.out.println("ar = " + ar); //System.out.println("br = " + br); dr = PolyUtil. recursivePseudoDivide(ar, br); //System.out.println("qr = " + dr); cr = PolyUtil. recursiveSparsePseudoRemainder(ar, br); //System.out.println("rr = " + cr); boolean t = PolyUtil. isRecursivePseudoQuotientRemainder(ar, br, dr, cr); //System.out.println("assertTrue lc^n a = q b + r: " + t); assertTrue("lc^n a = q b + r: " + dr + "*b + " + cr, t); // not always true, some what fixed GenPolynomial> ap = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, ar); GenPolynomial> bp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, br); GenPolynomial> cp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, cr); GenPolynomial> dp = PolyUfdUtil . quotientFromIntegralCoefficients(rqfac, dr); //System.out.println("ap = " + ap); //System.out.println("bp = " + bp); //System.out.println("cp = " + cp); ////System.out.println("dp = " + dp); //System.out.println("dp = " + dp.monic()); GenPolynomial> qp = ap.divide(bp); GenPolynomial> rp = ap.remainder(bp); ////System.out.println("qp = " + qp); //System.out.println("qp = " + qp.monic()); //System.out.println("rp = " + rp); GenPolynomial> rhs = qp.multiply(bp).sum(rp); //System.out.println("qp bp + rp = " + rhs); assertEquals("ap = qp bp + rp: ", ap, rhs); //System.out.println("cp = rp: rp_m = " + rp.monic() + ", cp_m = " + cp.monic()); assertEquals("cp = rp: ", rp.monic(), cp.monic()); //System.out.println("dp = qp: " + qp.monic().equals(dp.monic()) ); //System.out.println("qp = dp: qp_m = " + qp.monic() + ", dp_m = " + dp.monic()); assertEquals("dp = qp: ", qp.monic(), dp.monic()); // ?? } /** * Test integer from rational coefficients, recursive. */ public void testRecursiveIntegerFromRationalCoefficients() { crfac = new GenPolynomialRing(new BigRational(1), cfac); rrfac = new GenPolynomialRing>(crfac, rfac); //System.out.println("\ncfac = " + cfac); //System.out.println("crfac = " + crfac); //System.out.println("rfac = " + rfac); //System.out.println("rrfac = " + rrfac); // BigRational arr = rrfac.random(kl * kl, 2 * ll, el + 4, q); arr = arr.sum(arr).multiply(arr); //rrfac.fromInteger(11)); //System.out.println("arr = " + arr); // BigInteger ar = PolyUfdUtil.integerFromRationalCoefficients(rfac, arr); //System.out.println("ar = " + ar); crr = PolyUtil. monic(arr); //System.out.println("crr = " + crr); // BigRational err = PolyUfdUtil. fromIntegerCoefficients(rrfac, ar); //System.out.println("err = " + err); err = PolyUtil. monic(err); //System.out.println("err = " + err); assertEquals("crr != err: ", crr, err); } /** * Test norm over algebraic number field. */ public void testNormAlgebraicNumberField() { int deg = 5; // characteristic zero BigRational q = BigRational.ONE; //System.out.println("q = " + q.toScriptFactory()); AlgebraicNumberRing gfqq = PolyUfdUtil. algebraicNumberField(q, deg); //System.out.println("gfqq = " + gfqq.toScript()); assertTrue("gfqq.isField: ", gfqq.isField()); GenPolynomialRing> pafac; pafac = new GenPolynomialRing>(gfqq, new String[] { "x" }, TermOrderByName.INVLEX); //System.out.println("pafac = " + pafac.toScript()); GenPolynomial> P, Q, R; P = pafac.random(2, 4, 3, 0.4f).monic(); Q = pafac.random(2, 4, 3, 0.4f).monic(); R = P.multiply(Q); //System.out.println("P = " + P); //System.out.println("Q = " + Q); //System.out.println("R = " + R); GenPolynomial nP, nQ, nR, nPQ, rem, gcd; nP = PolyUfdUtil. norm(P); nQ = PolyUfdUtil. norm(Q); nR = PolyUfdUtil. norm(R); nPQ = nP.multiply(nQ); //System.out.println("normP = " + nP); //System.out.println("normQ = " + nQ); //System.out.println("normR = " + nR); //System.out.println("normPQ = " + nPQ); //System.out.println("normP*normQ = norm(P*Q): " + nPQ.equals(nR) + "\n"); if (nPQ.equals(nR)) { assertEquals("normP*normQ == norm(P*Q)", nPQ, nR); return; } rem = nR.remainder(nPQ); //System.out.println("norm(P*Q) mod normP*normQ == 0: " + rem.isZERO()); if (rem.isZERO()) { assertTrue("norm(P*Q) mod normP*normQ == 0", rem.isZERO()); return; } GreatestCommonDivisorAbstract gcdr = GCDFactory.getImplementation(q); gcd = gcdr.gcd(nPQ, nR); //System.out.println("gcd(norm(P*Q), normP*normQ) != 1: " + (!gcd.isONE())); if (!gcd.isONE()) { assertFalse("gcd(norm(P*Q), normP*normQ) != 1", gcd.isONE()); return; } // unreachable: FactorAbstract facr = FactorFactory.getImplementation(q); SortedMap, Long> fnPQ = facr.factors(nPQ); System.out.println("fnPQ = " + fnPQ); SortedMap, Long> fnR = facr.factors(nR); System.out.println("fnR = " + fnR); } /** * Test multivariate norm over algebraic number field. */ public void testMultiNormAlgebraicNumberField() { int deg = 5; // characteristic zero BigRational q = BigRational.ONE; //System.out.println("q = " + q.toScriptFactory()); AlgebraicNumberRing gfqq = PolyUfdUtil. algebraicNumberField(q, deg); //System.out.println("gfqq = " + gfqq.toScript()); assertTrue("gfqq.isField: ", gfqq.isField()); GenPolynomialRing> pafac; pafac = new GenPolynomialRing>(gfqq, new String[] { "x", "y" }, TermOrderByName.INVLEX); //System.out.println("pafac = " + pafac.toScript()); GenPolynomial> P, Q, R; P = pafac.random(2, 4, 2, 0.2f).monic(); Q = pafac.random(2, 4, 2, 0.2f).monic(); R = P.multiply(Q); //System.out.println("P = " + P); //System.out.println("Q = " + Q); //System.out.println("R = " + R); GenPolynomial nP, nQ, nR, nPQ, rem, gcd; nP = PolyUfdUtil. norm(P); nQ = PolyUfdUtil. norm(Q); nR = PolyUfdUtil. norm(R); nPQ = nP.multiply(nQ); //System.out.println("normP = " + nP); //System.out.println("normQ = " + nQ); //System.out.println("normR = " + nR); //System.out.println("normPQ = " + nPQ); //System.out.println("normP*normQ == norm(P*Q): " + nPQ.equals(nR) + "\n"); if (nPQ.equals(nR)) { assertEquals("normP*normQ == norm(P*Q)", nPQ, nR); return; } rem = nR.remainder(nPQ); //System.out.println("norm(P*Q) mod normP*normQ == 0: " + rem.isZERO()); if (rem.isZERO()) { assertTrue("norm(P*Q) mod normP*normQ == 0", rem.isZERO()); return; } GreatestCommonDivisorAbstract gcdr = GCDFactory.getImplementation(q); gcd = gcdr.gcd(nPQ, nR); //System.out.println("gcd(norm(P*Q), normP*normQ) != 1: " + (!gcd.isONE())); if (!gcd.isONE()) { assertFalse("gcd(norm(P*Q), normP*normQ) != 1", gcd.isONE()); return; } // unreachable: FactorAbstract facr = FactorFactory.getImplementation(q); SortedMap, Long> fnPQ = facr.factors(nPQ); System.out.println("fnPQ = " + fnPQ); SortedMap, Long> fnR = facr.factors(nR); System.out.println("fnR = " + fnR); } /** * Q matrix construction for Berlekamp. */ public void testQmatix() { int q = 11; //32003; //11; ModIntRing mi = new ModIntRing(q); // for (ModInt s : mi) { // System.out.print(" " + s + " "); // } // System.out.println("mi = " + mi.toScript()); GenPolynomialRing pfac = new GenPolynomialRing(mi, new String[] { "x" }); //System.out.println("pfac = " + pfac.toScript()); GenPolynomial A = pfac.parse("x^6 - 3 x^5 + x^4 - 3 x^3 - x^2 -3 x + 1"); //System.out.println("A = " + A.toScript()); int d = (int) A.degree(0); ArrayList> Q = PolyUfdUtil. constructQmatrix(A); //System.out.println("Q = " + Q); int n = Q.size(); int m = Q.get(0).size(); assertTrue("size(Q) == deg(a): " + Q, n == d); assertTrue("size(Q(0)) == deg(a): " + Q, m == d); GenMatrixRing mfac = new GenMatrixRing(mi, n, m); //System.out.println("mfac = " + mfac.toScript()); GenMatrix Qm = new GenMatrix(mfac, Q); //System.out.println("Qm = " + Qm); GenMatrix Qm1 = Qm.subtract(mfac.getONE()); //System.out.println("Qm1 = " + Qm1); LinAlg lu = new LinAlg(); List> Nsb = lu.nullSpaceBasis(Qm1); //System.out.println("Nsb = " + Nsb); //GenMatrixRing nfac = new GenMatrixRing(mi,k,d); GenMatrix Ns = mfac.fromVectors(Nsb); //System.out.println("Ns = " + Ns); GenMatrix L1 = Ns.negate(); //mfac.getONE().subtract(Ns); //System.out.println("L1 = " + L1); int k = L1.ring.rows; //System.out.println("k = " + k); assertTrue("0 <= k && k < n: " + L1, 0 <= k && k < n); // test with random polynomial do { A = pfac.random(10); //System.out.println("A = " + A.toScript()); } while (A.isZERO() || A.degree(0) <= 1); d = (int) A.degree(0); Q = PolyUfdUtil. constructQmatrix(A); //System.out.println("Q = " + Q); n = Q.size(); m = Q.get(0).size(); assertTrue("size(Q) == deg(a): " + Q, n == d); assertTrue("size(Q(0)) == deg(a): " + Q, m == d); ArrayList> Qa = Q; mfac = new GenMatrixRing(mi, n, m); //System.out.println("mfac = " + mfac.toScript()); Qm = new GenMatrix(mfac, Q); //System.out.println("Qm = " + Qm); Qm1 = Qm.subtract(mfac.getONE()); //System.out.println("Qm1 = " + Qm1); Nsb = lu.nullSpaceBasis(Qm1); //System.out.println("Nsb = " + Nsb); //GenMatrixRing nfac = new GenMatrixRing(mi,k,d); Ns = mfac.fromVectors(Nsb); //System.out.println("Ns = " + Ns); L1 = Ns.negate(); //mfac.getONE().subtract(Ns); //System.out.println("L1 = " + L1); k = L1.ring.rows; //System.out.println("k = " + k); assertTrue("0 <= k && k < n: " + L1, 0 <= k && k <= n); // test with modPower GenPolynomial x = pfac.univariate(0); //System.out.println("x = " + x.toScript()); GenPolynomial r = pfac.getONE(); //System.out.println("r = " + r.toScript()); ArrayList> Qp = new ArrayList>(); Qp.add(r); GenPolynomial pow = Power.> modPositivePower(x, q, A); //System.out.println("pow = " + pow.toScript()); Qp.add(pow); r = pow; for (int i = 2; i < d; i++) { r = r.multiply(pow).remainder(A); Qp.add(r); } //System.out.println("Qp = " + Qp); assertTrue("deg(r) < deg(A): " + Qp, r.degree(0) <= A.degree(0)); UnivPowerSeriesRing psfac = new UnivPowerSeriesRing(pfac); //System.out.println("psfac = " + psfac.toScript()); ArrayList> Qb = new ArrayList>(); for (GenPolynomial p : Qp) { UnivPowerSeries ps = psfac.fromPolynomial(p); //System.out.println("ps = " + ps.toScript()); ArrayList pr = new ArrayList(); for (int i = 0; i < d; i++) { ModInt c = ps.coefficient(i); pr.add(c); } Qb.add(pr); } //System.out.println("Qb = " + Qb); assertEquals("Qa == Qb: ", Qa, Qb); } /** * Test search evaluation points. */ public void testSearchEvaluationPoints() { //System.out.println("dfac = " + dfac.toScript()); crfac = new GenPolynomialRing(new BigRational(1), dfac); //System.out.println("crfac = " + crfac.toScript()); SquarefreeAbstract isqf = SquarefreeFactory.getImplementation(dfac.coFac); SquarefreeAbstract rsqf = SquarefreeFactory.getImplementation(crfac.coFac); for (int i = 0; i < 5; i++) { a = dfac.random(kl, ll * 2, el * 5, q); //System.out.println("a = " + a + ", isSquarefree: " + isqf.isSquarefree(a)); a = isqf.squarefreePart(a); EvalPoints L = PolyUfdUtil. evaluationPoints(a); //System.out.println("L = " + L); assertFalse("L != (): ", L.evalPoints.isEmpty()); GenPolynomial ar = crfac.random(kl, ll, el * 2, q * 1.5f); //System.out.println("ar = " + ar + ", isSquarefree: " + rsqf.isSquarefree(ar)); ar = rsqf.squarefreePart(ar); EvalPoints Lr = PolyUfdUtil. evaluationPoints(ar); //System.out.println("Lr = " + Lr); assertFalse("Lr != (): ", Lr.evalPoints.isEmpty()); } } } java-algebra-system-2.7.200/trc/edu/jas/ufd/QuotIntPolynomialTest.java000066400000000000000000000311561445075545500256160ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.ufd; import java.io.IOException; import java.io.StringReader; import java.util.Arrays; import java.util.List; import edu.jas.arith.BigInteger; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenExteriorPolynomial; import edu.jas.poly.GenExteriorPolynomialRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.GenPolynomialTokenizer; import edu.jas.poly.IndexFactory; import edu.jas.poly.TermOrder; import edu.jas.structure.RingElem; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient BigInteger coefficient GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class QuotIntPolynomialTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a QoutIntPolynomialTest object. * @param name String. */ public QuotIntPolynomialTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(QuotIntPolynomialTest.class); return suite; } QuotientRing eFac; GenPolynomialRing mfac; GenPolynomialRing> qfac; GenPolynomial> a, b, c, d, e; int rl = 3; int kl = 2; // degree of coefficient polynomials!!! int ll = 4; //6; int el = 3; float q = 0.3f; @Override protected void setUp() { a = b = c = d = e = null; TermOrder to = new TermOrder(TermOrder.INVLEX); String[] cv = new String[] { "a", "b", "c" }; BigInteger cfac = new BigInteger(1); mfac = new GenPolynomialRing(cfac, rl, to, cv); eFac = new QuotientRing(mfac); String[] v = new String[] { "w", "x", "y", "z" }; qfac = new GenPolynomialRing>(eFac, rl + 1, v); } @Override protected void tearDown() { a = b = c = d = e = null; //eFac.terminate(); eFac = null; mfac = null; qfac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { c = qfac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1", c.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = qfac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 3; i++) { //a = qfac.random(ll+i); a = qfac.random(kl, ll + i, el, q); //System.out.println("a["+i+"] = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); b = a.monic(); Quotient ldbcf = b.leadingBaseCoefficient(); //System.out.println("b["+i+"] = " + b); assertTrue("ldbcf( b" + i + " ) == 1 " + b + ", a = " + a, ldbcf.isONE()); } } /** * Test addition. */ public void testAddition() { a = qfac.random(kl, ll, el, q); b = qfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("a = " + a.toString( qfac.getVars() )); //System.out.println("b = " + b.toString( qfac.getVars() )); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c.toString( qfac.getVars() )); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = qfac.random(kl, ll, el, q); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(qfac.getZERO()); d = a.subtract(qfac.getZERO()); assertEquals("a+0 = a-0", c, d); c = qfac.getZERO().sum(a); d = qfac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = qfac.random(kl, ll, el, q); //assertTrue("not isZERO( a )", !a.isZERO() ); b = qfac.random(kl, ll, el, q); //assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); if (!a.isZERO() && !b.isZERO()) { assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); } //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = qfac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(qfac.getONE()); d = qfac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } } /** * Test parse(). */ public void testParse() { a = qfac.random(kl, ll * 2, el * 2, q * 2); //assertTrue("not isZERO( a )", !a.isZERO() ); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(qfac.getVars()); //System.out.println("p = " + p); b = qfac.parse(p); //System.out.println("b = " + b.toString( qfac.getVars() ) ); //c = a.subtract(b); //System.out.println("c = " + c); assertEquals("parse(a.toSting()) = a", a, b); } /** * Test exterior derivation. */ @SuppressWarnings("unchecked") public void testDerivation() { // integers BigInteger rf = new BigInteger(); //System.out.println("rf = " + rf.toScriptFactory()); // 3/6 commuting vars String[] vars = new String[] { "x1", "x2", "x3" }; //System.out.println("vars = " + Arrays.toString(vars)); // polynomials over integers GenPolynomialRing pf = new GenPolynomialRing(rf, vars); //System.out.println("pf = " + pf.toScript()); QuotientRing qf = new QuotientRing(pf); //System.out.println("qf = " + qf.toScript()); assertTrue("commutative", qf.isCommutative()); assertTrue("associative", qf.isAssociative()); assertTrue("not field", qf.isField()); assertEquals("qf == qf: ", qf, qf); String s = qf.toScript(); //System.out.println("qf.toScript: " + s + ", " + s.length()); assertEquals("#s == 42: " + s, s.length(), 42); s = qf.toString(); //System.out.println("qf.toString: " + s + ", " + s.length()); assertEquals("#s == 41: " + s, s.length(), 41); Quotient p = qf.getONE(); //System.out.println("p = " + p); assertTrue("p == 1", p.isONE()); p = qf.getZERO(); assertTrue("p == 0", p.isZERO()); //System.out.println("p = " + p); List> gens = qf.generators(); //System.out.println("gens = " + gens); assertTrue("#gens == 4", gens.size() == 4); RingElem> qe = new Quotient(qf); //System.out.println("qe = " + qe); assertTrue("p.equals(qe) = ", p.equals(qe)); assertTrue("p.equals(p) = ", p.equals(p)); qe = qe.sum(p); //System.out.println("qe = " + qe); assertTrue("qe.isZERO() = ", qe.isZERO()); //p = pf.random(9); p = qf.random(kl, ll, el, q); p = p.subtract(p); //System.out.println("p = " + p); //System.out.println("p.isZERO() = " + p.isZERO()); assertTrue("p.isZERO() = ", p.isZERO()); // exterior polynomials over (polynomials over integers) // 3 non-commuting vars IndexFactory wf2 = new IndexFactory(3); //System.out.println("wf2 = " + wf2); GenExteriorPolynomialRing> ppf; ppf = new GenExteriorPolynomialRing>(qf, wf2); //System.out.println("ppf = " + ppf.toScript()); GenExteriorPolynomial> pp = ppf.getONE(); //System.out.println("pp = " + pp); assertTrue("pp == 1", pp.isONE()); //pp = ppf.random(2); pp = ppf.random(kl, ll, el); //System.out.println("pp = " + pp); pp = ppf.getZERO(); //System.out.println("pp = " + pp); assertTrue("pp == 0", pp.isZERO()); List>> pgens = ppf.generators(); //System.out.println("pgens = " + pgens); assertTrue("#pgens == 4+3", pgens.size() == 4 + 3); //pp = ppf.random(2); pp = ppf.random(kl, ll, el); //System.out.println("\npp = " + pp); assertFalse("pp.isZERO() = ", pp.isZERO()); long deg = pp.degree(); //System.out.println("deg = " + deg); GenExteriorPolynomial> der; der = PolyUfdUtil. exteriorDerivativeQuot(pp); //System.out.println("der = " + der); //System.out.println("deg = " + deg + ", deg(der) = " + der.degree()); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); deg = der.degree(); der = PolyUfdUtil. exteriorDerivativeQuot(der); //System.out.println("der(der) = " + der); //System.out.println("deg = " + deg + ", deg(der) = " + der.degree()); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); StringReader sr = new StringReader("{x1 x2 | x3 } E(1) E(2)"); //System.out.println("sr = " + sr); GenPolynomialTokenizer tok = new GenPolynomialTokenizer(sr); //System.out.println("ppf = " + ppf.toScript()); // parse with tokenizer try { pp = (GenExteriorPolynomial>) tok.nextExteriorPolynomial(ppf); } catch (IOException e) { e.printStackTrace(); return; } //System.out.println("\npp = " + pp); deg = pp.degree(); der = PolyUfdUtil. exteriorDerivativeQuot(pp); //System.out.println("der = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); sr = new StringReader("{x3 | x2} E(1) + x3 E(2)"); //sr = new StringReader("x1 E(1) + x2 E(2)"); //sr = new StringReader("x2 E(1) + x1 E(2)"); //System.out.println("sr = " + sr); tok = new GenPolynomialTokenizer(sr); //System.out.println("ppf = " + ppf.toScript()); // parse with tokenizer try { pp = (GenExteriorPolynomial>) tok.nextExteriorPolynomial(ppf); } catch (IOException e) { e.printStackTrace(); return; } //System.out.println("\npp = " + pp); deg = pp.degree(); der = PolyUfdUtil. exteriorDerivativeQuot(pp); //System.out.println("der = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); deg = der.degree(); der = PolyUfdUtil. exteriorDerivativeQuot(der); //System.out.println("der(der) = " + der); assertTrue("deg >= 0: ", deg >= 0 && der.degree() >= 0); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/QuotientIntTest.java000066400000000000000000000147221445075545500244320ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient over BigInteger GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class QuotientIntTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a QuotientIntTest object. * @param name String. */ public QuotientIntTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(QuotientIntTest.class); return suite; } QuotientRing efac; GenPolynomialRing mfac; Quotient a, b, c, d, e; int rl = 3; int kl = 5; int ll = 4; //6; int el = 2; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; BigInteger cfac = new BigInteger(1); TermOrder to = new TermOrder(TermOrder.INVLEX); mfac = new GenPolynomialRing(cfac, rl, to); efac = new QuotientRing(mfac); } @Override protected void tearDown() { a = b = c = d = e = null; //efac.terminate(); efac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { c = efac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = efac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { //a = efac.random(ll+i); a = efac.random(kl * (i + 1), ll + 2 + 2 * i, el, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = efac.random(kl, ll, el, q); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = efac.random(kl, ll, el, q); //assertTrue("not isZERO( a )", !a.isZERO() ); b = efac.random(kl, ll, el, q); //assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); if (!a.isZERO() && !b.isZERO()) { assertTrue("not isZERO( c )", !c.isZERO()); assertTrue("not isZERO( d )", !d.isZERO()); } //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = efac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(efac.getONE()); d = efac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } } /** * Test parse(). */ public void testParse() { a = efac.random(kl * 2, ll * 2, el * 2, q * 2); //assertTrue("not isZERO( a )", !a.isZERO() ); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(); //System.out.println("p = " + p); b = efac.parse(p); //System.out.println("b = " + b); //c = a.subtract(b); //System.out.println("c = " + c); assertEquals("parse(a.toSting()) = a", a, b); } /** * Test factorization. */ public void testFactors() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); b = b.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("c = " + c); SortedMap, Long> factors = PolyUfdUtil. factors(c); //System.out.println("factors = " + factors); boolean t = PolyUfdUtil. isFactorization(c, factors); //System.out.println("t = " + t); assertTrue("c == prod(factors): " + c + ", " + factors, t); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/QuotientRatTest.java000066400000000000000000000276771445075545500244430ustar00rootroot00000000000000 /* * $Id$ */ package edu.jas.ufd; import java.util.List; import java.util.SortedMap; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.kern.PrettyPrint; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.vector.GenMatrix; import edu.jas.vector.GenMatrixRing; import edu.jas.vector.LinAlg; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Quotient over BigRational GenPolynomial tests with JUnit. * @author Heinz Kredel */ public class QuotientRatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a QuotientRatTest object. * @param name String. */ public QuotientRatTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite = new TestSuite(QuotientRatTest.class); return suite; } //private final static int bitlen = 100; QuotientRing zFac, efac; GenPolynomialRing mfac; Quotient a, b, c, d, e; Quotient az, bz, cz, dz, ez; int rl = 3; int kl = 5; int ll = 3; //6; int el = 2; float q = 0.4f; @Override protected void setUp() { a = b = c = d = e = null; TermOrder to = new TermOrder(TermOrder.INVLEX); mfac = new GenPolynomialRing(new BigRational(1), rl, to); efac = new QuotientRing(mfac); zFac = new QuotientRing(mfac, false); } @Override protected void tearDown() { a = b = c = d = e = null; //efac.terminate(); efac = null; zFac = null; ComputerThreads.terminate(); } /** * Test constructor and toString. */ public void testConstruction() { c = efac.getONE(); //System.out.println("c = " + c); //System.out.println("c.val = " + c.val); assertTrue("length( c ) = 1", c.num.length() == 1); assertTrue("isZERO( c )", !c.isZERO()); assertTrue("isONE( c )", c.isONE()); d = efac.getZERO(); //System.out.println("d = " + d); //System.out.println("d.val = " + d.val); assertTrue("length( d ) = 0", d.num.length() == 0); assertTrue("isZERO( d )", d.isZERO()); assertTrue("isONE( d )", !d.isONE()); } /** * Test random polynomial. */ public void testRandom() { for (int i = 0; i < 7; i++) { //a = efac.random(ll+i); a = efac.random(kl * (i + 1), ll + 2 + 2 * i, el, q); //System.out.println("a = " + a); if (a.isZERO() || a.isONE()) { continue; } assertTrue("length( a" + i + " ) <> 0", a.num.length() >= 0); assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); assertTrue(" not isONE( a" + i + " )", !a.isONE()); } } /** * Test addition. */ public void testAddition() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); d = d.monic(); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); //System.out.println("monic(d) = " + d.monic()); c = efac.random(kl, ll, el, q); //System.out.println("c = " + c); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("c+(a+b) = (c+a)+b", d, e); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test object multiplication. */ public void testMultiplication() { a = efac.random(kl, ll, el, q); //assertTrue("not isZERO( a )", !a.isZERO() ); b = efac.random(kl, ll, el, q); //assertTrue("not isZERO( b )", !b.isZERO() ); c = b.multiply(a); d = a.multiply(b); //assertTrue("not isZERO( c )", !c.isZERO() ); //assertTrue("not isZERO( d )", !d.isZERO() ); //System.out.println("a = " + a); //System.out.println("b = " + b); e = d.subtract(c); assertTrue("isZERO( a*b-b*a ) " + e, e.isZERO()); assertTrue("a*b = b*a", c.equals(d)); assertEquals("a*b = b*a", c, d); c = efac.random(kl, ll, el, q); //System.out.println("c = " + c); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("d-e = " + d.subtract(c) ); assertEquals("a(bc) = (ab)c", d, e); assertTrue("a(bc) = (ab)c", d.equals(e)); c = a.multiply(efac.getONE()); d = efac.getONE().multiply(a); assertEquals("a*1 = 1*a", c, d); if (a.isUnit()) { c = a.inverse(); d = c.multiply(a); //System.out.println("a = " + a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("a*1/a = 1", d.isONE()); } } /** * Test addition with syzygy gcd and euclids gcd. */ public void xtestAdditionGcd() { long te, tz; a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); az = new Quotient(zFac, a.num, a.den, true); bz = new Quotient(zFac, b.num, b.den, true); te = System.currentTimeMillis(); c = a.sum(b); d = c.subtract(b); d = d.monic(); te = System.currentTimeMillis() - te; assertEquals("a+b-b = a", a, d); tz = System.currentTimeMillis(); cz = az.sum(bz); dz = cz.subtract(bz); dz = dz.monic(); tz = System.currentTimeMillis() - tz; assertEquals("a+b-b = a", az, dz); System.out.println("te = " + te); System.out.println("tz = " + tz); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = efac.random(kl, ll, el, q); cz = new Quotient(zFac, c.num, c.den, true); te = System.currentTimeMillis(); d = c.sum(a.sum(b)); e = c.sum(a).sum(b); te = System.currentTimeMillis() - te; assertEquals("c+(a+b) = (c+a)+b", d, e); tz = System.currentTimeMillis(); dz = cz.sum(az.sum(bz)); ez = cz.sum(az).sum(bz); tz = System.currentTimeMillis() - tz; assertEquals("c+(a+b) = (c+a)+b", dz, ez); System.out.println("te = " + te); System.out.println("tz = " + tz); c = a.sum(efac.getZERO()); d = a.subtract(efac.getZERO()); assertEquals("a+0 = a-0", c, d); c = efac.getZERO().sum(a); d = efac.getZERO().subtract(a.negate()); assertEquals("0+a = 0+(-a)", c, d); } /** * Test parse(). */ public void testParse() { a = efac.random(kl * 2, ll * 2, el * 2, q * 2); //assertTrue("not isZERO( a )", !a.isZERO() ); //PrettyPrint.setInternal(); //System.out.println("a = " + a); PrettyPrint.setPretty(); //System.out.println("a = " + a); String p = a.toString(); //System.out.println("p = " + p); b = efac.parse(p); //System.out.println("b = " + b); //c = a.subtract(b); //System.out.println("c = " + c); assertEquals("parse(a.toSting()) = a", a, b); } /** * Test factorization. */ public void testFactors() { a = efac.random(kl, ll, el, q); b = efac.random(kl, ll, el, q); b = b.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.multiply(b); //System.out.println("c = " + c); SortedMap, Long> factors = PolyUfdUtil. factors(c); //System.out.println("factors = " + factors); boolean t = PolyUfdUtil. isFactorization(c, factors); //System.out.println("t = " + t); assertTrue("c == prod(factors): " + c + ", " + factors, t); } /** * Test symbolic row echelon form and LU decomposition. Using an example * from * Issue * #21. */ public void testLinAlg() { BigRational cfac = new BigRational(11); GenPolynomialRing pfac = new GenPolynomialRing(cfac, new String[] { "a" }); //System.out.println("pfac = " + pfac.toScript()); QuotientRing qfac = new QuotientRing(pfac); //System.out.println("qfac = " + qfac.toScript()); Quotient a = new Quotient(qfac, pfac.univariate(0)); //System.out.println("a: " + a.toScript()); int n = 3; GenMatrixRing> mfac = new GenMatrixRing>(qfac, n, n); //System.out.println("mfac = " + mfac.toScript()); GenMatrixRing> tfac = mfac.transpose(); @SuppressWarnings("unchecked") Quotient[][] mm = new Quotient[n][n]; // ( {{1, a, 2}, {0, 1, 1}, {-1, 1, 1}} ) mm[0][0] = qfac.fromInteger(1); mm[0][1] = a; mm[0][2] = qfac.fromInteger(2); mm[1][0] = qfac.getZERO(); mm[1][1] = qfac.fromInteger(1); mm[1][2] = qfac.fromInteger(1); mm[2][0] = qfac.fromInteger(-1); mm[2][1] = qfac.fromInteger(1); mm[2][2] = qfac.fromInteger(1); GenMatrix> A = new GenMatrix>(mfac, mm); //System.out.println("A: " + A); LinAlg> lu = new LinAlg>(); // test rowEchelonForm and rowEchelonFormSparse GenMatrix> B = lu.rowEchelonForm(A); //System.out.println("B: " + B); long r = lu.rankRE(B); GenMatrix> D = lu.rowEchelonFormSparse(B); //System.out.println("D: " + D); assertTrue("rank1 == rank2: ", lu.rankRE(D) == r); // test LU decomposition A = new GenMatrix>(mfac, mm); List P = lu.decompositionLU(A); //System.out.println("P : " + P); //System.out.println("A : " + A.toScript()); //System.out.println("U : " + A.getUpper().toScript()); // test LU inverse GenMatrix> I = lu.inverseLU(A, P); //System.out.println("I : " + I.toScript()); GenMatrix> C = new GenMatrix>(mfac, mm); GenMatrix> CI = C.multiply(I); //System.out.println("C*I: " + CI.toScript()); assertTrue("C*I == 1: ", CI.isONE()); GenMatrix> C2 = C.sum(C); GenMatrix> CA = A.divide(C2); GenMatrix> AC = A.divideLeft(C2); //System.out.println("C/A : " + CA); //System.out.println("A\\C : " + AC); assertFalse("C/A != A\\C: ", CA.equals(AC)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeAlgModTest.java000066400000000000000000000552341445075545500253400ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization AlgebraicNumber:ModInteger coefficients tests with * JUnit. * @author Heinz Kredel */ public class SquarefreeAlgModTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeAlgModTest object. * @param name String. */ public SquarefreeAlgModTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeAlgModTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); //long p = 11L; long p = 7L; long qp; int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; ModIntegerRing mfac; String[] alpha; GenPolynomialRing mpfac; GenPolynomial agen; AlgebraicNumberRing fac; GreatestCommonDivisorAbstract> ufd; SquarefreeFiniteFieldCharP> sqf; GenPolynomialRing> dfac; GenPolynomial> a, b, c, d, e; GenPolynomialRing> cfac; GenPolynomialRing>> rfac; GenPolynomial>> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; mfac = new ModIntegerRing(p); alpha = new String[] { "alpha" }; mpfac = new GenPolynomialRing(mfac, 1, to, alpha); agen = mpfac.univariate(0, 2); agen = agen.sum(mpfac.getONE()); // x^2 + 1, is irred mod 7, 11, 19 fac = new AlgebraicNumberRing(agen, true); qp = 1L; for (int i = 0; i < agen.degree(0); i++) { qp = qp * p; } //System.out.println("p = " + p + ", qp = " + qp); //ufd = new GreatestCommonDivisorSubres>(); //ufd = GCDFactory.> getImplementation(fac); ufd = GCDFactory.> getProxy(fac); sqf = new SquarefreeFiniteFieldCharP>(fac); SquarefreeAbstract> sqff = SquarefreeFactory.getImplementation(fac); //System.out.println("sqf = " + sqf); //System.out.println("sqff = " + sqff); assertEquals("sqf == sqff ", sqf.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 2, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 3, q); b = dfac.random(kl, ll, el + 3, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree. */ public void testRecursiveSquarefree() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil.> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree. */ public void testSquarefree() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /* ------------char-th root ------------------------- */ /** * Test base squarefree with char-th root. */ public void testBaseSquarefreeCharRoot() { //System.out.println("\nbase CharRoot:"); long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 1, q).monic(); b = dfac.random(kl, ll + 1, el + 1, q).monic(); c = dfac.random(kl, ll, el, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, p); //System.out.println("b^p = " + e); // a a b^p c d = a.multiply(a).multiply(e).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root. */ public void testBaseSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 2, q).monic(); b = dfac.random(kl, ll + 1, el + 2, q).monic(); c = dfac.random(kl, ll, el + 1, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, p); //System.out.println("b^p = " + e); // a a b^p d = a.multiply(a).multiply(e); //d = d.monic(); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test base squarefree with char-th root, two times. */ public void testBaseSquarefreeCharRoot2() { //System.out.println("\nbase CharRoot 2:"); //long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 1, q).monic(); b = dfac.random(kl, ll + 1, el + 1, q).monic(); c = dfac.random(kl, ll, el, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, qp); //System.out.println("b^qp = " + e); // a a b^qp c d = a.multiply(a).multiply(e).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root, two times. */ public void testBaseSquarefreeFactorsCharRoot2() { //long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 2, q).monic(); b = dfac.random(kl, ll + 1, el + 2, q).monic(); c = dfac.random(kl, ll, el + 2, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, qp); //System.out.println("b^qp = " + e); // a a b^qp d = a.multiply(a).multiply(e); //d = d.monic(); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree with char-th root. */ public void testRecursiveSquarefreeCharRoot() { //System.out.println("\nrecursive CharRoot:"); long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, el, q); br = rfac.random(kl, 3, el, q); cr = rfac.random(kl, 3, el, q); //cr = rfac.getONE(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //ar = PolyUtil.>monic(ar); //br = PolyUtil.>monic(br); //cr = PolyUtil.>monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); er = Power.>>> positivePower(br, p); //System.out.println("b^p = " + er); // a a b^p c dr = ar.multiply(ar).multiply(er).multiply(cr); cr = ar.multiply(br).multiply(cr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil.> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors with char-th root. */ public void testRecursiveSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //cr = rfac.getONE(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //ar = PolyUtil.>monic(ar); //br = PolyUtil.>monic(br); //cr = PolyUtil.>monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); er = Power.>>> positivePower(br, p); //System.out.println("b^p = " + er); // a a b^p c dr = ar.multiply(ar).multiply(er).multiply(cr); //System.out.println("dr = " + dr); SortedMap>>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree with char-th root. */ public void testSquarefreeCharRoot() { //System.out.println("\nfull CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, 3, 3, q); b = dfac.random(kl, 3, 3, q); c = dfac.random(kl, 3, 3, q); //c = dfac.getONE(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //a = a.monic(); //b = b.monic(); //c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, p); //System.out.println("b^p = " + e); // a a b^p c d = a.multiply(a).multiply(e).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test squarefree factors with char-th root. */ public void testSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, 3, 3, q); b = dfac.random(kl, 3, 3, q); c = dfac.random(kl, 3, 3, q); //c = dfac.getONE(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //a = a.monic(); //b = b.monic(); //c = c.monic(); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); e = Power.>> positivePower(b, p); //System.out.println("b^p = " + e); // a a b^p c d = a.multiply(a).multiply(e).multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeAlgQuotModTest.java000066400000000000000000000524551445075545500262130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization AlgebraicNumber:Quotient:ModInteger coefficients * tests with JUnit. * @author Heinz Kredel */ public class SquarefreeAlgQuotModTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeAlgQuotModTest object. * @param name String. */ public SquarefreeAlgQuotModTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeAlgQuotModTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 1; int ll = 3; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; ModIntegerRing mfac; String[] alpha; String[] beta; GenPolynomialRing mpfac; GenPolynomial agen; QuotientRing fac; AlgebraicNumberRing> afac; SquarefreeInfiniteFieldCharP sqf; SquarefreeInfiniteAlgebraicFieldCharP> asqf; GenPolynomialRing>> dfac; GenPolynomial>> a, b, c, d, e; GenPolynomialRing>> cfac; GenPolynomialRing>>> rfac; GenPolynomial>>> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; mfac = new ModIntegerRing(7); alpha = new String[] { "u" }; beta = new String[] { "b" }; mpfac = new GenPolynomialRing(mfac, 1, to, alpha); fac = new QuotientRing(mpfac); GenPolynomialRing> qpfac = new GenPolynomialRing>(fac, 1, to, beta); // beta^2 - 3 GenPolynomial> an = qpfac.univariate(0, 2L); an = an.subtract(qpfac.fromInteger(3)); afac = new AlgebraicNumberRing>(an, true); sqf = new SquarefreeInfiniteFieldCharP(fac); asqf = new SquarefreeInfiniteAlgebraicFieldCharP>(afac); SquarefreeAbstract>> sqff = SquarefreeFactory .getImplementation(afac); //System.out.println("sqf = " + sqf); //System.out.println("sqff = " + sqff); assertEquals("asqf == sqff ", asqf.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing>>(afac, 1, to, rvars); a = dfac.random(kl + 0, ll - 1, el + 0, q); b = dfac.random(kl + 0, ll, el + 1, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = asqf.baseSquarefreePart(c); d = asqf.baseSquarefreePart(d); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("isSquarefree(c) " + c, asqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, asqf.isSquarefree(d)); e = PolyUtil.>> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing>>(afac, 1, to, rvars); a = dfac.random(kl + 0, ll - 1, el + 0, q); b = dfac.random(kl + 0, ll, el + 1, q); c = dfac.random(kl, ll, el + 0, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } int num = 0; if (!a.isConstant()) { num++; } if (!b.isConstant()) { num++; } if (!c.isConstant()) { num++; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>>, Long> sfactors; sfactors = asqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", asqf.isFactorization(d, sfactors)); assertTrue("#factors " + asqf.factorCount(sfactors) + " >= " + num + ": " + d + " = " + sfactors, asqf.factorCount(sfactors) >= num); } /** * Test recursive squarefree. */ public void testRecursiveSquarefree() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing>>(afac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3 - 0, 2, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); cr = asqf.recursiveUnivariateSquarefreePart(cr); dr = asqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); assertTrue("isSquarefree(cr) " + cr, asqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, asqf.isRecursiveSquarefree(dr)); er = PolyUtil.>> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing>>(afac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3 - 1, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); //if (ar.isZERO() || br.isZERO() || cr.isZERO()) { if (ar.isZERO() || br.isZERO()) { // skip for this turn return; } int num = 0; if (!ar.isConstant()) { num++; } if (!br.isConstant()) { num++; } //if (! cr.isConstant()) { // num++; //} //dr = ar.multiply(cr).multiply(br).multiply(br); dr = ar.multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>>>, Long> sfactors; sfactors = asqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); // better use factorCount assertTrue("isFactorization(d,sfactors) ", asqf.isRecursiveFactorization(dr, sfactors)); assertTrue("#factors " + sfactors.size() + " >= " + num + ": " + d + " = " + sfactors, sfactors.size() >= num); } /** * Test squarefree. */ public void testSquarefree() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing>>(afac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll - 1, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = asqf.squarefreePart(c); d = asqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, asqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, asqf.isSquarefree(c)); e = PolyUtil.>> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing>>(afac, rl, to, vars); a = dfac.random(kl, 3, 2 + 1, q); b = dfac.random(kl, 2, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } int num = 0; if (!a.isConstant()) { num++; } if (!b.isConstant()) { num++; } if (!c.isConstant()) { num++; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>>, Long> sfactors; sfactors = asqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", asqf.isFactorization(d, sfactors)); assertTrue("#factors " + asqf.factorCount(sfactors) + " >= " + num + ": " + d + " = " + sfactors, asqf.factorCount(sfactors) >= num); } /* ------------char-th root ------------------------- */ /** * Test base squarefree with char-th root. */ public void testBaseSquarefreeCharRoot() { //System.out.println("\nbase CharRoot:"); long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>>(afac, 1, to, rvars); a = dfac.random(kl + 0, ll + 0, el + 1, q).monic(); b = dfac.random(kl, ll + 1, el + 1, q).monic(); c = dfac.random(kl + 0, ll, el, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply( Power.>>> positivePower(b, p)) .multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = asqf.baseSquarefreePart(c); d = asqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, asqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, asqf.isSquarefree(d)); e = PolyUtil.>> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root. */ public void testBaseSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>>(afac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 1, q).monic(); b = dfac.random(kl, ll + 1, el + 2, q).monic(); c = dfac.random(kl, ll, el + 2, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply( Power.>>> positivePower(b, p)) .multiply(c); //d = d.monic(); //System.out.println("d = " + d); SortedMap>>, Long> sfactors; sfactors = asqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", asqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree with char-th root. */ public void testRecursiveSquarefreeCharRoot() { //System.out.println("\nrecursive CharRoot:"); long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>>(afac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, ll, el, q); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } ar = PolyUtil.>> monic(ar); br = PolyUtil.>> monic(br); cr = PolyUtil.>> monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a b^p c dr = ar.multiply(Power .>>>> positivePower( br, p)) .multiply(cr); cr = ar.multiply(br).multiply(cr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = asqf.recursiveUnivariateSquarefreePart(cr); dr = asqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, asqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, asqf.isRecursiveSquarefree(dr)); er = PolyUtil.>> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors with char-th root. */ public void testRecursiveSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>>(afac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } ar = PolyUtil.>> monic(ar); br = PolyUtil.>> monic(br); cr = PolyUtil.>> monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a b^p c dr = ar.multiply(Power .>>>> positivePower( br, p)) .multiply(cr); //System.out.println("dr = " + dr); SortedMap>>>, Long> sfactors; sfactors = asqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", asqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree with char-th root. */ public void testSquarefreeCharRoot() { //System.out.println("\nfull CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>>(afac, rl, to, vars); a = dfac.random(kl, ll, 3 - 1, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, ll, 3, q); if (a.isZERO() || b.isZERO() || c.isZERO() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply( Power.>>> positivePower(b, p)) .multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = asqf.squarefreePart(c); d = asqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, asqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, asqf.isSquarefree(c)); e = PolyUtil.>> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test squarefree factors with char-th root. */ public void testSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>>(afac, rl, to, vars); a = dfac.random(kl, ll, 3 - 1, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, ll, 3, q); if (a.isZERO() || b.isZERO() || c.isZERO() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply( Power.>>> positivePower(b, p)) .multiply(c); //System.out.println("d = " + d); SortedMap>>, Long> sfactors; sfactors = asqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", asqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeIntTest.java000066400000000000000000000224111445075545500247160ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.BigInteger; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization BigInteger coefficients tests with JUnit. * @author Heinz Kredel */ public class SquarefreeIntTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeIntTest object. * @param name String. */ public SquarefreeIntTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeIntTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 7; int ll = 4; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; BigInteger fac; GreatestCommonDivisorAbstract ufd; SquarefreeRingChar0 sqf; GenPolynomialRing dfac; GenPolynomial a, b, c, d, e; GenPolynomialRing cfac; GenPolynomialRing> rfac; GenPolynomial> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; fac = new BigInteger(1); //ufd = new GreatestCommonDivisorSubres(); //ufd = GCDFactory. getImplementation(fac); ufd = GCDFactory.getProxy(fac); sqf = new SquarefreeRingChar0(fac); SquarefreeAbstract sqff = SquarefreeFactory.getImplementation(fac); //System.out.println("sqf = " + sqf); //System.out.println("sqff = " + sqff); assertEquals("sqf == sqff ", sqf.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree part. */ public void testBaseSquarefreePart() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 2, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 3, q); b = dfac.random(kl, ll, el + 3, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree part. */ public void testRecursiveSquarefreePart() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree part. */ public void testSquarefreePart() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeModLongTest.java000066400000000000000000000417071445075545500255340ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization ModLong coefficients tests with JUnit. * @author Heinz Kredel */ public class SquarefreeModLongTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeModLongTest object. * @param name String. */ public SquarefreeModLongTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeModLongTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; ModLongRing fac; GreatestCommonDivisorAbstract ufd; SquarefreeFiniteFieldCharP sqf; GenPolynomialRing dfac; GenPolynomial a, b, c, d, e; GenPolynomialRing cfac; GenPolynomialRing> rfac; GenPolynomial> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; fac = new ModLongRing(11); //ufd = new GreatestCommonDivisorSubres(); //ufd = GCDFactory. getImplementation(fac); ufd = GCDFactory.getProxy(fac); sqf = new SquarefreeFiniteFieldCharP(fac); SquarefreeAbstract sqff = SquarefreeFactory.getImplementation(fac); //System.out.println("sqf = " + sqf); //System.out.println("sqff = " + sqff); assertEquals("sqf == sqff ", sqf.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 2, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 3, q); b = dfac.random(kl, ll, el + 3, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree. */ public void testRecursiveSquarefree() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree. */ public void testSquarefree() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /* ------------char-th root ------------------------- */ /** * Test base squarefree with char-th root. */ public void testBaseSquarefreeCharRoot() { //System.out.println("\nbase CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll + 2, el + 2, q); b = dfac.random(kl, ll + 2, el + 2, q); c = dfac.random(kl, ll, el, q); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root. */ public void testBaseSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll + 2, el + 3, q); b = dfac.random(kl, ll + 2, el + 3, q); c = dfac.random(kl, ll, el + 2, q); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree with char-th root. */ public void testRecursiveSquarefreeCharRoot() { //System.out.println("\nrecursive CharRoot:"); long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el + 1, q).monic(); br = rfac.random(kl, ll, el + 1, q).monic(); cr = rfac.random(kl, ll, el, q).monic(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a a b^p dr = ar.multiply(ar).multiply(Power.>> positivePower(br, p)); cr = ar.multiply(ar).multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors with char-th root. */ public void testRecursiveSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q).monic(); br = rfac.random(kl, 3, 2 + 1, q).monic(); cr = rfac.random(kl, 3, 2, q).monic(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a a b^p c dr = ar.multiply(ar).multiply(Power.>> positivePower(br, p)) .multiply(cr); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree with char-th root. */ public void testSquarefreeCharRoot() { //System.out.println("\nfull CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q).monic(); b = dfac.random(kl, ll, 3, q).monic(); c = dfac.random(kl, ll, 3, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test squarefree factors with char-th root. */ public void testSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q).monic(); b = dfac.random(kl, ll, 3, q).monic(); c = dfac.random(kl, ll, 3, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeModTest.java000066400000000000000000000415271445075545500247140ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization ModInteger coefficients tests with JUnit. * @author Heinz Kredel */ public class SquarefreeModTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeModTest object. * @param name String. */ public SquarefreeModTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeModTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; ModIntegerRing fac; GreatestCommonDivisorAbstract ufd; SquarefreeFiniteFieldCharP sqf; GenPolynomialRing dfac; GenPolynomial a, b, c, d, e; GenPolynomialRing cfac; GenPolynomialRing> rfac; GenPolynomial> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; fac = new ModIntegerRing(11); //ufd = new GreatestCommonDivisorSubres(); //ufd = GCDFactory. getImplementation(fac); ufd = GCDFactory.getProxy(fac); sqf = new SquarefreeFiniteFieldCharP(fac); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 2, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 3, q); b = dfac.random(kl, ll, el + 3, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree. */ public void testRecursiveSquarefree() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree. */ public void testSquarefree() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /* ------------char-th root ------------------------- */ /** * Test base squarefree with char-th root. */ public void testBaseSquarefreeCharRoot() { //System.out.println("\nbase CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll + 2, el + 2, q); b = dfac.random(kl, ll + 2, el + 2, q); c = dfac.random(kl, ll, el, q); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root. */ public void testBaseSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll + 2, el + 3, q); b = dfac.random(kl, ll + 2, el + 3, q); c = dfac.random(kl, ll, el + 2, q); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree with char-th root. * */ public void testRecursiveSquarefreeCharRoot() { //System.out.println("\nrecursive CharRoot:"); long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el + 1, q).monic(); br = rfac.random(kl, ll, el + 1, q).monic(); cr = rfac.random(kl, ll, el, q).monic(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a a b^p dr = ar.multiply(ar).multiply(Power.>> positivePower(br, p)); cr = ar.multiply(ar).multiply(br); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors with char-th root. */ public void testRecursiveSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q).monic(); br = rfac.random(kl, 3, 2 + 1, q).monic(); cr = rfac.random(kl, 3, 2, q).monic(); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a a b^p c dr = ar.multiply(ar).multiply(Power.>> positivePower(br, p)) .multiply(cr); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree with char-th root. */ public void testSquarefreeCharRoot() { //System.out.println("\nfull CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q).monic(); b = dfac.random(kl, ll, 3, q).monic(); c = dfac.random(kl, ll, 3, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test squarefree factors with char-th root. */ public void testSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q).monic(); b = dfac.random(kl, ll, 3, q).monic(); c = dfac.random(kl, ll, 3, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.> positivePower(b, p)).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeQuotModTest.java000066400000000000000000000447011445075545500255620ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import edu.jas.structure.Power; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization Quotient:ModInteger coefficients tests with JUnit. * @author Heinz Kredel */ public class SquarefreeQuotModTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeQuotModTest object. * @param name String. */ public SquarefreeQuotModTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeQuotModTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 1; int ll = 3; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; ModIntegerRing mfac; String[] alpha; GenPolynomialRing mpfac; GenPolynomial agen; QuotientRing fac; GreatestCommonDivisorAbstract> ufd; SquarefreeInfiniteFieldCharP sqf; GenPolynomialRing> dfac; GenPolynomial> a, b, c, d, e; GenPolynomialRing> cfac; GenPolynomialRing>> rfac; GenPolynomial>> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; mfac = new ModIntegerRing(7); alpha = new String[] { "u" }; mpfac = new GenPolynomialRing(mfac, 1, to, alpha); fac = new QuotientRing(mpfac); //ufd = new GreatestCommonDivisorSubres>(); //ufd = GCDFactory.> getImplementation(fac); ufd = GCDFactory.> getProxy(fac); sqf = new SquarefreeInfiniteFieldCharP(fac); SquarefreeAbstract> sqff = SquarefreeFactory.getImplementation(fac); //System.out.println("sqf = " + sqf); //System.out.println("sqff = " + sqff); assertEquals("sqf == sqff ", sqf.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; //ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl + 1, ll, el + 1, q); b = dfac.random(kl + 1, ll, el + 1, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl + 1, ll, el + 2, q); b = dfac.random(kl + 1, ll, el + 2, q); c = dfac.random(kl, ll, el + 1, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree. */ public void testRecursiveSquarefree() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil.> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree. */ public void testSquarefree() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll - 1, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 2, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /* ------------char-th root ------------------------- */ /** * Test base squarefree with char-th root. */ public void testBaseSquarefreeCharRoot() { //System.out.println("\nbase CharRoot:"); long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl + 1, ll + 1, el + 2, q).monic(); b = dfac.random(kl, ll + 1, el + 2, q).monic(); c = dfac.random(kl + 1, ll, el, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.>> positivePower(b, p)) .multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test base squarefree factors with char-th root. */ public void testBaseSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); //dfac = new GenPolynomialRing(fac,1,to,rvars); dfac = new GenPolynomialRing>(fac, 1, to, rvars); a = dfac.random(kl, ll + 1, el + 3, q).monic(); b = dfac.random(kl, ll + 1, el + 3, q).monic(); c = dfac.random(kl, ll, el + 2, q).monic(); if (a.isZERO() || b.isZERO() || c.isZERO() || a.isConstant() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.>> positivePower(b, p)) .multiply(c); //d = d.monic(); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree with char-th root. */ public void testRecursiveSquarefreeCharRoot() { //System.out.println("\nrecursive CharRoot:"); long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, ll, el, q); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } ar = PolyUtil.> monic(ar); br = PolyUtil.> monic(br); cr = PolyUtil.> monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a b^p c dr = ar.multiply(Power.>>> positivePower(br, p)) .multiply(cr); cr = ar.multiply(br).multiply(cr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("cr = " + cr); //System.out.println("dr = " + dr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil.> recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors with char-th root. */ public void testRecursiveSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); cfac = new GenPolynomialRing>(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2 + 1, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } ar = PolyUtil.> monic(ar); br = PolyUtil.> monic(br); cr = PolyUtil.> monic(cr); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); // a b^p c dr = ar.multiply(Power.>>> positivePower(br, p)) .multiply(cr); //System.out.println("dr = " + dr); SortedMap>>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree with char-th root. */ public void testSquarefreeCharRoot() { //System.out.println("\nfull CharRoot:"); long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, ll, 3, q); if (a.isZERO() || b.isZERO() || c.isZERO() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.>> positivePower(b, p)) .multiply(c); c = a.multiply(b).multiply(c); //System.out.println("c = " + c); //System.out.println("d = " + d); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil.> baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aab^pc) " + e, e.isZERO()); } /** * Test squarefree factors with char-th root. */ public void testSquarefreeFactorsCharRoot() { long p = fac.characteristic().longValue(); dfac = new GenPolynomialRing>(fac, rl, to, vars); a = dfac.random(kl, ll, 3, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, ll, 3, q); if (a.isZERO() || b.isZERO() || c.isZERO() || b.isConstant()) { // skip for this turn return; } //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); // a a b^p c d = a.multiply(a).multiply(Power.>> positivePower(b, p)) .multiply(c); //System.out.println("d = " + d); SortedMap>, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeRatTest.java000066400000000000000000000302421445075545500247130ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import java.util.SortedMap; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.ExpVector; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.PolyUtil; import edu.jas.poly.TermOrder; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree factorization BigRational coefficients tests with JUnit. * @author Heinz Kredel */ public class SquarefreeRatTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); ComputerThreads.terminate(); } /** * Constructs a SquarefreeRatTest object. * @param name String. */ public SquarefreeRatTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeRatTest.class); return suite; } TermOrder to = new TermOrder(TermOrder.INVLEX); int rl = 3; int kl = 3; int ll = 4; int el = 3; float q = 0.25f; String[] vars; String[] cvars; String[] c1vars; String[] rvars; BigRational fac; GreatestCommonDivisorAbstract ufd; SquarefreeFieldChar0 sqf, sqfy; GenPolynomialRing dfac; GenPolynomial a, b, c, d, e; GenPolynomialRing cfac; GenPolynomialRing> rfac; GenPolynomial> ar, br, cr, dr, er; @Override protected void setUp() { vars = ExpVector.STDVARS(rl); cvars = ExpVector.STDVARS(rl - 1); c1vars = new String[] { cvars[0] }; rvars = new String[] { vars[rl - 1] }; fac = new BigRational(1); //ufd = new GreatestCommonDivisorSubres(); //ufd = GCDFactory. getImplementation(fac); ufd = GCDFactory.getProxy(fac); sqf = new SquarefreeFieldChar0(fac); sqfy = new SquarefreeFieldChar0Yun(fac); SquarefreeAbstract sqff = SquarefreeFactory.getImplementation(fac); //System.out.println("sqf = " + sqf); //System.out.println("sqfy = " + sqfy); //System.out.println("sqff = " + sqff); assertEquals("sqf/y == sqff ", sqfy.getClass(), sqff.getClass()); a = b = c = d = e = null; ar = br = cr = dr = er = null; } @Override protected void tearDown() { a = b = c = d = e = null; ar = br = cr = dr = er = null; // ComputerThreads.terminate(); } /** * Test base squarefree. */ public void testBaseSquarefree() { //System.out.println("\nbase:"); dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 2, q); c = dfac.random(kl, ll, el, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.baseSquarefreePart(c); d = sqf.baseSquarefreePart(d); //System.out.println("d = " + d); //System.out.println("c = " + c); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbbc) " + e, e.isZERO()); } /** * Test base squarefree factors. */ public void testBaseSquarefreeFactors() { dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 2, q); b = dfac.random(kl, ll, el + 1, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.baseSquarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test base squarefree factors, Yun. */ public void testBaseSquarefreeFactorsYun() { dfac = new GenPolynomialRing(fac, 1, to, rvars); a = dfac.random(kl, ll, el + 3, q); b = dfac.random(kl, ll, el + 3, q); c = dfac.random(kl, ll, el + 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } // a a b b b c d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; long t = System.currentTimeMillis(); sfactors = sqf.baseSquarefreeFactors(d); t = System.currentTimeMillis() - t; //System.out.println("sqf_t = " + t + " ms"); //, sfactors = " + sfactors); t = System.currentTimeMillis(); sfactors = sqfy.baseSquarefreeFactors(d); t = System.currentTimeMillis() - t; //System.out.println("sqfy_t = " + t + " ms"); //, sfactors = " + sfactors); assertTrue("dummy ", t >= 0L); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } /** * Test recursive squarefree part. */ public void testRecursiveSquarefreePart() { //System.out.println("\nrecursive:"); cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, ll, el, q); br = rfac.random(kl, ll, el, q); cr = rfac.random(kl, ll, el, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(ar).multiply(br).multiply(br); cr = ar.multiply(br); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); cr = sqf.recursiveUnivariateSquarefreePart(cr); dr = sqf.recursiveUnivariateSquarefreePart(dr); //System.out.println("dr = " + dr); //System.out.println("cr = " + cr); assertTrue("isSquarefree(cr) " + cr, sqf.isRecursiveSquarefree(cr)); assertTrue("isSquarefree(dr) " + dr, sqf.isRecursiveSquarefree(dr)); er = PolyUtil. recursiveSparsePseudoRemainder(dr, cr); //System.out.println("er = " + er); assertTrue("squarefree(abc) | squarefree(aabbc) " + er, er.isZERO()); } /** * Test recursive squarefree factors. */ public void testRecursiveSquarefreeFactors() { cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } dr = ar.multiply(cr).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test recursive squarefree factors, Yun. */ public void testRecursiveSquarefreeFactorsYun() { cfac = new GenPolynomialRing(fac, 2 - 1, to, c1vars); rfac = new GenPolynomialRing>(cfac, 1, to, rvars); ar = rfac.random(kl, 3, 2, q); br = rfac.random(kl, 3, 2, q); cr = rfac.random(kl, 3, 2, q); //System.out.println("ar = " + ar); //System.out.println("br = " + br); //System.out.println("cr = " + cr); if (ar.isZERO() || br.isZERO() || cr.isZERO()) { // skip for this turn return; } // a b b b c c dr = ar.multiply(cr).multiply(cr).multiply(br).multiply(br).multiply(br); //System.out.println("dr = " + dr); SortedMap>, Long> sfactors; long t = System.currentTimeMillis(); sfactors = sqf.recursiveUnivariateSquarefreeFactors(dr); t = System.currentTimeMillis() - t; //System.out.println("r-sqf_t = " + t + " ms"); //, sfactors = " + sfactors); t = System.currentTimeMillis(); sfactors = sqfy.recursiveUnivariateSquarefreeFactors(dr); t = System.currentTimeMillis() - t; //System.out.println("r-sqfy_t = " + t + " ms"); //, sfactors = " + sfactors); assertTrue("dummy ", t >= 0L); assertTrue("isFactorization(d,sfactors) ", sqf.isRecursiveFactorization(dr, sfactors)); } /** * Test squarefree part. */ public void testSquarefreePart() { //System.out.println("\nfull:"); dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, ll, 2, q); b = dfac.random(kl, ll, 2, q); c = dfac.random(kl, ll, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(c); c = a.multiply(b).multiply(c); //System.out.println("d = " + d); //System.out.println("c = " + c); c = sqf.squarefreePart(c); d = sqf.squarefreePart(d); //System.out.println("c = " + c); //System.out.println("d = " + d); assertTrue("isSquarefree(d) " + d, sqf.isSquarefree(d)); assertTrue("isSquarefree(c) " + c, sqf.isSquarefree(c)); e = PolyUtil. baseSparsePseudoRemainder(d, c); //System.out.println("e = " + e); assertTrue("squarefree(abc) | squarefree(aabbc) " + e, e.isZERO()); } /** * Test squarefree factors. */ public void testSquarefreeFactors() { dfac = new GenPolynomialRing(fac, rl, to, vars); a = dfac.random(kl, 3, 2, q); b = dfac.random(kl, 3, 2, q); c = dfac.random(kl, 3, 2, q); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); if (a.isZERO() || b.isZERO() || c.isZERO()) { // skip for this turn return; } d = a.multiply(a).multiply(b).multiply(b).multiply(b).multiply(c); //System.out.println("d = " + d); SortedMap, Long> sfactors; sfactors = sqf.squarefreeFactors(d); //System.out.println("sfactors = " + sfactors); assertTrue("isFactorization(d,sfactors) ", sqf.isFactorization(d, sfactors)); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/SquarefreeTest.java000066400000000000000000000163731445075545500242550ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigInteger; import edu.jas.arith.BigRational; import edu.jas.arith.ModInteger; import edu.jas.arith.ModIntegerRing; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.structure.RingFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Squarefree Factory tests with JUnit. * @author Heinz Kredel */ public class SquarefreeTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a SquarefreeTest object. * @param name String. */ public SquarefreeTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(SquarefreeTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test factory specific. */ public void testFactorySpecific() { ModIntegerRing mi = new ModIntegerRing(19, true); Squarefree sqfm = SquarefreeFactory.getImplementation(mi); //System.out.println("sqfm = " + sqfm); assertTrue("sqf != Modular " + sqfm, sqfm instanceof SquarefreeFiniteFieldCharP); ModLongRing ml = new ModLongRing(19, true); Squarefree sqfml = SquarefreeFactory.getImplementation(ml); //System.out.println("sqfml = " + sqfml); assertTrue("sqf != Modular " + sqfml, sqfml instanceof SquarefreeFiniteFieldCharP); BigInteger bi = new BigInteger(1); Squarefree sqfi = SquarefreeFactory.getImplementation(bi); //System.out.println("sqfi = " + sqfi); assertTrue("sqf != Integer " + sqfi, sqfi instanceof SquarefreeRingChar0); BigRational br = new BigRational(1); Squarefree sqfr = SquarefreeFactory.getImplementation(br); //System.out.println("sqfr = " + sqfr); assertTrue("sqf != Rational " + sqfr, sqfr instanceof SquarefreeFieldChar0); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Squarefree> sqfam = SquarefreeFactory. getImplementation(am); //System.out.println("sqfam = " + sqfam); assertTrue("sqf != AlgebraicNumber " + sqfam, sqfam instanceof SquarefreeFiniteFieldCharP); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Squarefree> sqfar = SquarefreeFactory . getImplementation(ar); //System.out.println("sqfar = " + sqfar); assertTrue("sqf != AlgebraicNumber " + sqfar, sqfar instanceof SquarefreeFieldChar0); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Squarefree> sqfqr = SquarefreeFactory. getImplementation(qrfac); //System.out.println("sqfqr = " + sqfqr); assertTrue("sqf != Quotient " + sqfqr, sqfqr instanceof SquarefreeFieldChar0); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Squarefree> sqfqm = SquarefreeFactory. getImplementation(qmfac); //System.out.println("sqfqm = " + sqfqm); assertTrue("sqf != Quotient " + sqfqm, sqfqm instanceof SquarefreeInfiniteFieldCharP); } /** * Test factory generic. */ @SuppressWarnings("unchecked") public void testFactoryGeneric() { ModIntegerRing mi = new ModIntegerRing(19, true); Squarefree sqfm = SquarefreeFactory.getImplementation((RingFactory) mi); //System.out.println("sqfm = " + sqfm); assertTrue("sqf != Modular " + sqfm, sqfm instanceof SquarefreeFiniteFieldCharP); ModLongRing ml = new ModLongRing(19, true); Squarefree sqfml = SquarefreeFactory.getImplementation((RingFactory) ml); //System.out.println("sqfml = " + sqfml); assertTrue("sqf != Modular " + sqfml, sqfml instanceof SquarefreeFiniteFieldCharP); BigInteger bi = new BigInteger(1); Squarefree sqfi = SquarefreeFactory.getImplementation((RingFactory) bi); //System.out.println("sqfi = " + sqfi); assertTrue("sqf != Integer " + sqfi, sqfi instanceof SquarefreeRingChar0); BigRational br = new BigRational(1); Squarefree sqfr = SquarefreeFactory.getImplementation((RingFactory) br); //System.out.println("sqfr = " + sqfr); assertTrue("sqf != Rational " + sqfr, sqfr instanceof SquarefreeFieldChar0); GenPolynomialRing pmfac = new GenPolynomialRing(mi, 1); GenPolynomial pm = pmfac.univariate(0); AlgebraicNumberRing am = new AlgebraicNumberRing(pm, true); Squarefree> sqfam = SquarefreeFactory.getImplementation((RingFactory) am); //System.out.println("sqfam = " + sqfam); assertTrue("sqf != AlgebraicNumber " + sqfam, sqfam instanceof SquarefreeFiniteFieldCharP); GenPolynomialRing prfac = new GenPolynomialRing(br, 1); GenPolynomial pr = prfac.univariate(0); AlgebraicNumberRing ar = new AlgebraicNumberRing(pr, true); Squarefree> sqfar = SquarefreeFactory .getImplementation((RingFactory) ar); //System.out.println("sqfar = " + sqfar); assertTrue("sqf != AlgebraicNumber " + sqfar, sqfar instanceof SquarefreeFieldChar0); prfac = new GenPolynomialRing(br, 2); QuotientRing qrfac = new QuotientRing(prfac); Squarefree> sqfqr = SquarefreeFactory.getImplementation((RingFactory) qrfac); //System.out.println("sqfqr = " + sqfqr); assertTrue("sqf != Quotient " + sqfqr, sqfqr instanceof SquarefreeFieldChar0); pmfac = new GenPolynomialRing(mi, 1); QuotientRing qmfac = new QuotientRing(pmfac); Squarefree> sqfqm = SquarefreeFactory.getImplementation((RingFactory) qmfac); //System.out.println("sqfqm = " + sqfqm); assertTrue("sqf != Quotient " + sqfqm, sqfqm instanceof SquarefreeInfiniteFieldCharP); } } java-algebra-system-2.7.200/trc/edu/jas/ufd/UnivPowerSeriesTaylorTest.java000066400000000000000000000135051445075545500264510ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufd; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.ps.PolynomialTaylorFunction; import edu.jas.ps.TaylorFunction; import edu.jas.ps.UnivPowerSeries; import edu.jas.ps.UnivPowerSeriesRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * Univariate power series tests with JUnit. * @author Heinz Kredel */ public class UnivPowerSeriesTaylorTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a UnivPowerSeriesTaylorTest object. * @param name String. */ public UnivPowerSeriesTaylorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(UnivPowerSeriesTaylorTest.class); return suite; } BigRational cfac; UnivPowerSeriesRing fac; UnivPowerSeries a, b, c, d, e; int kl = 10; float q = 0.5f; @Override protected void setUp() { a = b = c = d = e = null; cfac = new BigRational(1); fac = new UnivPowerSeriesRing(cfac); } @Override protected void tearDown() { a = b = c = d = e = null; fac = null; cfac = null; ComputerThreads.terminate(); } /** * Test Taylor series of polynomials. */ public void testTaylor() { BigRational br = new BigRational(0); GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr); GenPolynomial p = pr.random(kl, 3, 3, q + q); //System.out.println("p = " + p); TaylorFunction F = new PolynomialTaylorFunction(p); UnivPowerSeries ps = fac.seriesOfTaylor(F, br); //System.out.println("ps = " + ps); UnivPowerSeries pps = fac.fromPolynomial(p); //System.out.println("pps = " + pps); assertEquals("taylor(p) == p", ps, pps); for (GenPolynomial g : pr.generators()) { F = new PolynomialTaylorFunction(g); ps = fac.seriesOfTaylor(F, br); //System.out.println("g = " + g); //System.out.println("ps = " + ps); pps = fac.fromPolynomial(g); //System.out.println("pps = " + pps); assertEquals("taylor(p) == p", ps, pps); } } /** * Test Taylor series of quotients of polynomials. */ public void testQuotientTaylor() { BigRational br = new BigRational(0); GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr); QuotientRing qr = new QuotientRing(pr); //System.out.println("qr = " + qr.toScript()); Quotient p = qr.random(kl, 3, 3, q + q); //System.out.println("p = " + p); //Quotient x = qr.generators().get(1); //p = p.divide(x); //System.out.println("p = " + p); if (p.den.trailingBaseCoefficient().isZERO()) { // divisible by x, evaluates to 0 return; } TaylorFunction F = new QuotientTaylorFunction(p); UnivPowerSeries ps = fac.seriesOfTaylor(F, br); //System.out.println("ps = " + ps); UnivPowerSeries pps = fac.fromPolynomial(p.num).divide(fac.fromPolynomial(p.den)); //System.out.println("pps = " + pps); assertEquals("taylor(p) == p", ps, pps); for (Quotient g : qr.generators()) { F = new QuotientTaylorFunction(g); ps = fac.seriesOfTaylor(F, br); //System.out.println("g = " + g); //System.out.println("ps = " + ps); pps = fac.fromPolynomial(g.num).divide(fac.fromPolynomial(g.den)); //System.out.println("pps = " + pps); assertEquals("taylor(p) == p", ps, pps); } } /** * Test Pade approximant of quotients of polynomials. */ public void testQuotientPade() { BigRational br = new BigRational(0); GenPolynomialRing pr = fac.polyRing(); //System.out.println("pr = " + pr.toScript()); QuotientRing qr = new QuotientRing(pr); //System.out.println("qr = " + qr.toScript()); final int M = 3, N = 4; Quotient p = qr.random(kl, M, N, q + q); Quotient x = qr.generators().get(1); while (p.den.trailingBaseCoefficient().isZERO()) { // divisible by x, evaluates to 0 p = p.multiply(x); } while (p.num.trailingBaseCoefficient().isZERO()) { // divisible by x, evaluates to 0 p = p.divide(x); } //System.out.println("p = " + p); TaylorFunction F = new QuotientTaylorFunction(p); int dm = (int) p.num.degree() + 1, dn = (int) p.den.degree() + 1; //System.out.println("[" + dm + "," + dn + "]"); Quotient pa = null; for (int m = 0; m < dm; m++) { for (int n = 0; n < dn; n++) { pa = PolyUfdUtil. approximantOfPade(fac, F, br, m, n); //System.out.println("pa[" + m + "," + n + "] = " + pa + "\n"); assertTrue("deg(num) <= m", pa.num.degree() <= m); assertTrue("deg(den) <= n", pa.den.degree() <= n); } } //System.out.println("pa[" + (dm-1) + "," + (dn-1) + "] = " + pa + "\n"); assertEquals("p == pa: ", p, pa); } } java-algebra-system-2.7.200/trc/edu/jas/ufdroot/000077500000000000000000000000001445075545500213425ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/ufdroot/FactorRealAlgebraicTest.java000066400000000000000000000116001445075545500266570ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.ufdroot; import java.util.SortedMap; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigRational; import edu.jas.kern.ComputerThreads; import edu.jas.poly.AlgebraicNumber; import edu.jas.poly.AlgebraicNumberRing; import edu.jas.poly.GenPolynomial; import edu.jas.poly.GenPolynomialRing; import edu.jas.poly.TermOrder; import edu.jas.root.RealAlgebraicNumber; import edu.jas.root.RealAlgebraicRing; import edu.jas.root.Interval; import edu.jas.root.RootUtil; import edu.jas.ufdroot.FactorRealAlgebraic; /** * Factor real algebraic tests with JUnit. * @author Heinz Kredel */ public class FactorRealAlgebraicTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a FactorRealAlgebraicTest object. * @param name String. */ public FactorRealAlgebraicTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(FactorRealAlgebraicTest.class); return suite; } int rl = 3; int kl = 5; int ll = 5; int el = 3; float q = 0.3f; @Override protected void setUp() { } @Override protected void tearDown() { ComputerThreads.terminate(); } /** * Test dummy for Junit. */ public void testDummy() { } /** * Test real algebraic factorization. */ public void testRealAlgebraicFactorization() { TermOrder to = new TermOrder(TermOrder.INVLEX); BigRational cfac = new BigRational(1); String[] alpha = new String[] { "alpha" }; String[] vars = new String[] { "z" }; GenPolynomialRing pfac = new GenPolynomialRing(cfac, 1, to, alpha); GenPolynomial agen = pfac.univariate(0, 2); //agen = agen.subtract(pfac.getONE()); // x^2 - 1 agen = agen.subtract(pfac.fromInteger(2)); // x^2 - 2 //AlgebraicNumberRing afac = new AlgebraicNumberRing(agen, true); Interval iv = RootUtil.parseInterval(cfac, "[0,2]"); //System.out.println("iv = " + iv); RealAlgebraicRing rfac = new RealAlgebraicRing(agen,iv,true); GenPolynomialRing> rpfac = new GenPolynomialRing>( rfac, 1, to, vars); // univariate //System.out.println("agen = " + agen); //System.out.println("afac = " + afac); //System.out.println("rfac = " + rfac); //System.out.println("rpfac = " + rpfac); FactorRealAlgebraic fac = new FactorRealAlgebraic(rfac); for (int i = 1; i < 2; i++) { int facs = 0; GenPolynomial> a; GenPolynomial> c = rpfac.random(2, ll + i, el + i, q); GenPolynomial> b = rpfac.random(2, ll + i, el + i, q); if (b.degree() == 0) { b = b.multiply(rpfac.univariate(0)); } //b = b.monic(); //if ( false && ! a.leadingBaseCoefficient().isONE() ) { //continue; //ExpVector e = a.leadingExpVector(); //a.doPutToMap(e,cfac.getONE()); //} if (c.degree() > 0) { facs++; } if (b.degree() > 0) { facs++; } //a = apfac.univariate(0,2).sum( apfac.getONE() ); // x^2 + 1 //a = a.multiply(a); //a = a.multiply( apfac.univariate(0,2).subtract( apfac.getONE() ) ); // x^2 - 1 //a = apfac.univariate(0,3).subtract( apfac.getONE() ); // x^3 - 1 //a = apfac.univariate(0,3).sum( apfac.getONE() ); // x^3 + 1 a = c.multiply(b); //a = c; //a = a.monic(); //System.out.println("\na = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("b = " + b.monic()); //System.out.println("c = " + c.monic()); SortedMap>, Long> sm = fac.baseFactors(a); //System.out.println("\na = " + a); //System.out.println("sm = " + sm); if (sm.size() >= facs) { assertTrue("#facs < " + facs, sm.size() >= facs); } else { System.out.println("sm.size() < facs = " + facs); } boolean t = fac.isFactorization(a, sm); //System.out.println("t = " + t); assertTrue("prod(factor(a)) = a", t); } } } java-algebra-system-2.7.200/trc/edu/jas/util/000077500000000000000000000000001445075545500206355ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/util/DistHashTableTest.java000066400000000000000000000214011445075545500250150ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * DistHashTable test with JUnit. * @author Heinz Kredel */ public class DistHashTableTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a DistHashTableTest object. * @param name String. */ public DistHashTableTest(String name) { super(name); } /** * suite. * @return a test suite. */ public static Test suite() { TestSuite suite= new TestSuite(DistHashTableTest.class); return suite; } private static final String host = "localhost"; private DistHashTable l1; private DistHashTable l2; private DistHashTable l3; private DistHashTableServer dls; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; protected void setUp() { dls = new DistHashTableServer(); dls.init(); } protected void tearDown() { dls.terminate(); dls = null; if ( l1 != null ) l1.terminate(); if ( l2 != null ) l2.terminate(); if ( l3 != null ) l3.terminate(); l1 = l2 = l3 = null; } /** * Tests create and terminate DistHashTableServer. */ public void testDistHashTable0() { } /** * Tests create and terminate DistHashTable. */ public void testDistHashTable1() { l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); } /** * Tests if the created DistHashTable has #n objects as content. */ public void testDistHashTable2() { l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); l1.putWait( Integer.valueOf(1), Integer.valueOf(1) ); assertFalse("l1!=empty",l1.isEmpty()); assertTrue("#l1==1", l1.size() == 1 ); l1.putWait( Integer.valueOf(2), Integer.valueOf(2) ); assertTrue("#l1==2", l1.size() == 2 ); l1.putWait( Integer.valueOf(3), Integer.valueOf(3) ); assertTrue("#l1==3", l1.size() == 3 ); Iterator it = null; it = l1.iterator(); int i = 0; while ( it.hasNext() ) { Object k = it.next(); Object o = l1.get(k); Integer x = Integer.valueOf( ++i ); assertEquals("l1(i)==v(i)", x, o ); assertEquals("l1(i)==k(i)", x, k ); } l1.clear(); assertTrue("#l1==0", l1.size() == 0 ); } /** * Tests if the two created DistHashTables have #n objects as content. */ public void testDistHashTable3() { l2 = new DistHashTable(host); l2.init(); assertTrue("l2==empty",l2.isEmpty()); l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l1.putWait( x, x ); assertTrue("#l1==i", l1.size() == i ); } assertTrue("#l1=="+loops, l1.size() == loops ); while ( l2.size() < loops ) { try { //System.out.print("*2"); Thread.sleep(100); } catch (InterruptedException e) { } } assertTrue("#l2=="+loops, l2.size() == loops ); Iterator it = null; it = l2.iterator(); i = 0; while ( it.hasNext() ) { Object k = it.next(); Object o = l2.get(k); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==k(i)", x, k ); assertEquals("l2(i)==v(i)", x, o ); } l1.clear(); assertTrue("l1==empty",l1.isEmpty()); while ( l2.size() > 0 ) { try { //System.out.print("*5"); Thread.sleep(100); } catch (InterruptedException e) { } } assertTrue("l2==empty",l2.isEmpty()); } /** * Tests if the three created DistHashTables have #n objects as content. */ public void testDistHashTable4() { l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); l2 = new DistHashTable(host); l2.init(); assertTrue("l2==empty",l2.isEmpty()); l3 = new DistHashTable(host); l3.init(); assertTrue("l3==empty",l3.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l3.putWait( x, x ); assertTrue("#l3==i", l3.size() == i ); } assertTrue("#l3=="+loops, l3.size() == loops ); while ( l2.size() < loops || l1.size() < loops-1 ) { try { //System.out.print("*3"); Thread.sleep(100); } catch (InterruptedException e) { } } assertTrue("#l2=="+loops, l2.size() == loops ); assertTrue("#l1=="+loops, l1.size() == loops ); Iterator it = null; it = l2.iterator(); Iterator it3 = null; it3 = l1.iterator(); i = 0; while ( it.hasNext() && it3.hasNext() ) { Object k1 = it.next(); Object k2 = it3.next(); Object v1 = l2.get(k1); Object v2 = l1.get(k2); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==k(i)", x, k1 ); assertEquals("l1(i)==k(i)", x, k2 ); assertEquals("l2(i)==v(i)", x, v1 ); assertEquals("l1(i)==v(i)", x, v2 ); } l1.clear(); assertTrue("l1==empty",l1.isEmpty()); while ( l2.size() > 0 || l3.size() > 0 ) { try { //System.out.print("*4"); Thread.sleep(100); } catch (InterruptedException e) { } } assertTrue("l2==empty",l2.isEmpty()); assertTrue("l3==empty",l3.isEmpty()); } /** * Tests if the two created DistHashTables have #n objects as content * when one is created later. */ public void testDistHashTable5() { l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l1.putWait( x, x ); assertTrue("#l1==i", l1.size() == i ); } assertTrue("#l1=="+loops, l1.size() == loops ); l2 = new DistHashTable(host); l2.init(); // assertTrue("l2==empty",l2.isEmpty()); while ( l2.size() < loops ) { try { //System.out.print("*2"); Thread.sleep(100); } catch (InterruptedException e) { } } Iterator it = null; it = l2.iterator(); i = 0; while ( it.hasNext() ) { Object k = it.next(); Object v = l2.get(k); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==k(i)", x, k ); assertEquals("l2(i)==v(i)", x, v ); } assertTrue("#l2=="+loops, l2.size() == loops ); } /** * Tests if the two created DistHashTables have #n objects as content * using getWait() when one is created later. */ public void testDistHashTable6() { l1 = new DistHashTable(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l1.putWait( x, x ); assertTrue("#l1==i", l1.size() == i ); } assertTrue("#l1=="+loops, l1.size() == loops ); l2 = new DistHashTable(host); l2.init(); Iterator it = null; it = l1.iterator(); i = 0; while ( it.hasNext() ) { Integer k = it.next(); Integer v = l2.getWait(k); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l1(i)==k(i)", x, k ); assertEquals("l2(i)==v(i)", x, v ); } assertTrue("#l2=="+loops, l2.size() == loops ); } } java-algebra-system-2.7.200/trc/edu/jas/util/DistThreadPoolTest.java000066400000000000000000000102701445075545500252250ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.unima.ky.parallel.ChannelFactory; /** * DistThreadPool tests with JUnit. * @author Akitoshi Yoshida * @author Heinz Kredel */ public class DistThreadPoolTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a DistThreadPoolTest object. * @param name String. */ public DistThreadPoolTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(DistThreadPoolTest.class); return suite; } //private static final String host = "localhost"; private static final int port = ChannelFactory.DEFAULT_PORT; //private static final String mfile = "machines.test"; private ExecutableServer es; private DistThreadPool pool; static final int JOBS = 10; // number of jobs to start protected void setUp() { es = new ExecutableServer(port); es.init(); } protected void tearDown() { pool.terminate(); es.terminate(); } /** * Tests if the created DistThreadPool is empty. */ public void testDistThreadPool1() { pool = new DistThreadPool(0); assertTrue( "not empty pool ", pool.getNumber() == 0 ); } /** * Tests if the created DistThreadPool is non empty. */ public void testDistThreadPool2() { pool = new DistThreadPool(1); assertTrue( "# empty pool ", pool.getNumber() == 1 ); pool.terminate(); pool = new DistThreadPool(); assertTrue( "# empty pool ", pool.getNumber() == DistThreadPool.DEFAULT_SIZE ); pool.terminate(); pool = new DistThreadPool(10); assertTrue( "# empty pool ", pool.getNumber() == 10 ); pool.terminate(); } /** * Tests if the created DistThreadPool has no jobs. */ public void testDistThreadPool3() { pool = new DistThreadPool(); assertFalse( "no jobs ", pool.hasJobs() ); assertFalse( "more than 0 jobs ", pool.hasJobs(0) ); pool.terminate(); } /** * Tests if the created DistThreadPool has jobs. */ public void testDistThreadPool4() { pool = new DistThreadPool(); assertFalse( "no jobs ", pool.hasJobs() ); for (int i = 0; i < JOBS*pool.getNumber(); i++ ) { pool.addJob( new DistFastWorker() ); } boolean j = pool.hasJobs(); assertTrue( "more than 0 jobs ", (j | true) ); // stupid pool.terminate(); assertFalse( "no jobs ", pool.hasJobs() ); } /** * Tests if the created DistThreadPool has many jobs. */ public void testDistThreadPool5() { pool = new DistThreadPool(); assertFalse( "no jobs ", pool.hasJobs() ); for (int i = 0; i < JOBS*pool.getNumber(); i++ ) { pool.addJob( new DistSlowWorker() ); } assertTrue( "more than 10 jobs ", pool.hasJobs(JOBS) ); pool.terminate(); assertFalse( "no jobs ", pool.hasJobs() ); } /** * Tests if the created DistThreadPool has correct strategy. */ public void testDistThreadPool6() { pool = new DistThreadPool(StrategyEnumeration.LIFO); assertTrue( "FIFO strategy ", pool.getStrategy() == StrategyEnumeration.LIFO ); } /** * Tests if the created DistThreadPool has jobs and correct strategy. */ public void testDistThreadPool7() { pool = new DistThreadPool(StrategyEnumeration.LIFO); assertFalse( "no jobs ", pool.hasJobs() ); for (int i = 0; i < JOBS*pool.getNumber(); i++ ) { pool.addJob( new DistFastWorker() ); } boolean j = pool.hasJobs(); assertTrue( "more than 0 jobs ", (j | true) ); // stupid pool.terminate(); assertFalse( "no jobs ", pool.hasJobs() ); } } /** * Utility class for DistThreadPool Test. */ class DistFastWorker implements RemoteExecutable { public void run() { try { Thread.sleep(0); } catch (InterruptedException e ) { } } } /** * Utility class for DistThreadPool Test. */ class DistSlowWorker implements RemoteExecutable { public void run() { try { Thread.sleep(10); } catch (InterruptedException e ) { } } } java-algebra-system-2.7.200/trc/edu/jas/util/DistributedListTest.java000066400000000000000000000140061445075545500254570ustar00rootroot00000000000000/* * $Id$ */ //package edu.unima.ky.parallel; package edu.jas.util; import java.util.Iterator; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * DistributedList tests with JUnit. * @author Heinz Kredel */ public class DistributedListTest extends TestCase { /** * main */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a DistributedListTest object. * @param name String. */ public DistributedListTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(DistributedListTest.class); return suite; } private static final String host = "localhost"; private DistributedList l1; private DistributedList l2; private DistributedList l3; private DistributedListServer dls; int rl = 7; int kl = 10; int ll = 10; int el = 5; float q = 0.5f; protected void setUp() { dls = new DistributedListServer(); dls.init(); } protected void tearDown() { dls.terminate(); dls = null; if ( l1 != null ) l1.terminate(); if ( l2 != null ) l2.terminate(); if ( l3 != null ) l3.terminate(); l1 = l2 = l3 = null; } /** * Tests if the created DistributedList has #n objects as content. */ public void testDistributedList1() { l1 = new DistributedList(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); l1.add( Integer.valueOf(1) ); assertFalse("l1!=empty",l1.isEmpty()); assertTrue("#l1==1", l1.size() == 1 ); l1.add( Integer.valueOf(2) ); assertTrue("#l1==2", l1.size() == 2 ); l1.add( Integer.valueOf(3) ); assertTrue("#l1==3", l1.size() == 3 ); Iterator it = null; it = l1.iterator(); int i = 0; while ( it.hasNext() ) { Object o = it.next(); Integer x = Integer.valueOf( ++i ); assertEquals("l1(i)==(i)", x, o ); } l1.clear(); assertTrue("#l1==0", l1.size() == 0 ); } /** * Tests if the two created DistributedLists have #n objects as content. */ public void testDistributedList2() { l2 = new DistributedList(host); l2.init(); assertTrue("l2==empty",l2.isEmpty()); l1 = new DistributedList(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l1.add( x ); assertTrue("#l1==i", l1.size() == i ); } assertTrue("#l1==10", l1.size() == loops ); while ( l2.size() < loops ) { try { System.out.print("2"); Thread.sleep(100); } catch (InterruptedException e) { } } Iterator it = null; it = l2.iterator(); i = 0; while ( it.hasNext() ) { Object o = it.next(); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==(i)", x, o ); } assertTrue("#l2==10", l2.size() == loops ); } /** * Tests if the three created DistributedLists have #n objects as content. */ public void testDistributedList3() { l1 = new DistributedList(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); l2 = new DistributedList(host); l2.init(); assertTrue("l2==empty",l2.isEmpty()); l3 = new DistributedList(host); l3.init(); assertTrue("l3==empty",l3.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l3.add( x ); assertTrue("#l3==i", l3.size() == i ); } assertTrue("#l3==10", l3.size() == loops ); while ( l2.size() < loops || l1.size() < loops-1 ) { try { System.out.print("3"); Thread.sleep(100); } catch (InterruptedException e) { } } assertTrue("#l2==10", l2.size() == loops ); assertTrue("#l1==10", l1.size() == loops ); Iterator it = null; it = l2.iterator(); Iterator it3 = null; it3 = l1.iterator(); i = 0; /* sequence of elements is not correct at moment */ while ( it.hasNext() && it3.hasNext() ) { Object o = it.next(); Object p = it3.next(); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==(i)", x, o ); assertEquals("l1(i)==(i)", x, p ); } } /** * Tests if the two created DistributedLists have #n objects as content * when one is created later. */ public void testDistributedList6() { l1 = new DistributedList(host); l1.init(); assertTrue("l1==empty",l1.isEmpty()); int i = 0, loops = 10; while ( i < loops ) { Integer x = Integer.valueOf( ++i ); l1.add( x ); assertTrue("#l1==i", l1.size() == i ); } assertTrue("#l1==10", l1.size() == loops ); l2 = new DistributedList(host); l2.init(); // assertTrue("l2==empty",l2.isEmpty()); while ( l2.size() < loops ) { try { //System.out.print("2"); Thread.sleep(100); } catch (InterruptedException e) { } } Iterator it = null; it = l2.iterator(); i = 0; while ( it.hasNext() ) { Object o = it.next(); Integer x = Integer.valueOf( ++i ); //System.out.println("o = " + o + " x = "+ x); assertEquals("l2(i)==(i)", x, o ); } assertTrue("#l2==10", l2.size() == loops ); } } java-algebra-system-2.7.200/trc/edu/jas/util/ExecutableChannelsTest.java000066400000000000000000000173251445075545500261050ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.FileNotFoundException; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; //import edu.unima.ky.parallel.ChannelFactory; /** * ExecutableChannels tests with JUnit. * @author Heinz Kredel */ public class ExecutableChannelsTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ExecutableChannelsTest object. * @param name String. */ public ExecutableChannelsTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(ExecutableChannelsTest.class); return suite; } private static final String host = "localhost"; private static final int port = ChannelFactory.DEFAULT_PORT; private static final String mfile = ExecutableChannels.DEFAULT_MFILE; private ExecutableChannels ec; private ExecutableServer es; protected void setUp() { ec = null; es = new ExecutableServer(port); es.init(); } protected void tearDown() { es.terminate(); es = null; if ( ec != null ) { ec.close(); ec = null; } } /** * Tests if the ExecutableChannels could be initialized with null. */ public void testExecutableChannels1() { String[] servers = null; ec = new ExecutableChannels(servers); assertEquals("numServers<0", -1, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); String ts = "" + ec; assertEquals("toString", "ExecutableChannels()", ts ); } /** * Tests if the ExecutableChannels could be initialized with small server array. */ public void testExecutableChannels2() { int nums = 1; String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==1", 1, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); String ts = "" + ec; assertEquals("toString", "ExecutableChannels("+host+":"+port+")", ts ); } /** * Tests if the ExecutableChannels could be initialized with big server array. */ public void testExecutableChannels3() { int nums = 100; String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==100", 100, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); String ts = "" + ec; int l = "ExecutableChannels()".length() + nums * servers[0].length() + nums-1; assertEquals("toString.length()", l, ts.length()); } /** * Tests if the ExecutableChannels could be initialized and opened. */ public void testExecutableChannels4() { int nums = 2; int numc = nums - 1; String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==2", nums, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); String ts = "" + ec; int l = "ExecutableChannels()".length() + nums * servers[0].length() + nums-1; assertEquals("toString.length()", l, ts.length()); try { ec.open(); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } /** * Tests if 11 ExecutableChannels could be initialized and opened. */ public void testExecutableChannels5() { int nums = 11; // max 11 by some limit on number of threads int numc = nums - 1; String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); String ts = "" + ec; int l = "ExecutableChannels()".length() + nums * servers[0].length() + nums-1; assertEquals("toString.length()", l, ts.length()); try { ec.open(); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } /** * Tests if 10 ExecutableChannels to 1 server could be initialized and opened. */ public void testExecutableChannels6() { int nums = 2; // max 11 by some limit on number of threads int numc = 10; // max 11 by some limit on number of threads String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); try { ec.open(numc); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } /** * Tests if 5 ExecutableChannels to 10 servers could be initialized and opened. */ public void testExecutableChannels7() { int nums = 10; // max 11 by some limit on number of threads int numc = 5; // max 11 by some limit on number of threads String[] servers = new String[nums]; for ( int i = 0; i < nums; i++ ) { servers[i] = host + ":" + port; } ec = new ExecutableChannels(servers); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); try { ec.open(numc); assertEquals("numServers==1", nums, ec.numServers() ); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } /** * Tests if the ExecutableChannels could be initialized with servers from file. */ public void testExecutableChannels8() { try { ec = new ExecutableChannels( mfile ); } catch (FileNotFoundException e) { fail("readfile()"+e); } assertEquals("numServers==4", 4, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); int numc = ec.numServers(); try { ec.open(numc); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } /** * Tests if the ExecutableChannels could be initialized with servers from file. */ public void testExecutableChannels9() { try { ec = new ExecutableChannels( mfile ); } catch (FileNotFoundException e) { fail("readfile()"+e); } assertEquals("numServers==4", 4, ec.numServers() ); assertEquals("numChannels<0", -1, ec.numChannels() ); int numc = 10; try { ec.open(numc); assertEquals("numServers==numChannels", numc, ec.numChannels() ); } catch (IOException e) { fail("open()"+e); } ec.close(); assertEquals("numChannels<0", -1, ec.numChannels() ); } } java-algebra-system-2.7.200/trc/edu/jas/util/ExecutableServerTest.java000066400000000000000000000103701445075545500256110ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; //import edu.unima.ky.parallel.ChannelFactory; //import edu.unima.ky.parallel.SocketChannel; /** * ExecutableServer tests with JUnit. * @author Heinz Kredel */ public class ExecutableServerTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ExecutableServerTest object. * @param name String. */ public ExecutableServerTest(String name) { super(name); } /** * suite. */ public static Test suite() { TestSuite suite= new TestSuite(ExecutableServerTest.class); return suite; } private static final String host = "localhost"; private static final int port = ChannelFactory.DEFAULT_PORT; private ExecutableServer es; private ChannelFactory cf; protected void setUp() { es = new ExecutableServer(port); es.init(); cf = new ChannelFactory(); } protected void tearDown() { es.terminate(); es = null; cf.terminate(); cf = null; } /** * Tests if the ExecutableServer could be started and terminated. */ public void testExecutableServer1() { assertTrue("should never fail", true ); } /** * Tests if the ExecutableServer can execute a RemoteExecutable. */ public void testExecutableServer2() { RemoteExecutable e1 = new Executable("2"); try { SocketChannel sc = cf.getChannel(host,port); sc.send( e1 ); Object o = sc.receive(); assertTrue("o:String", o instanceof String); assertEquals("o==done", (String)o, ExecutableServer.DONE ); sc.close(); } catch (IOException e) { e.printStackTrace(); fail("IOException"); } catch (ClassNotFoundException e) { e.printStackTrace(); fail("ClassNotFoundException"); } } /** * Tests if the ExecutableServer can execute more RemoteExecutable. */ public void testExecutableServer3() { RemoteExecutable e1 = new Executable("3"); int numloops = 1; // can be changed in ExecutableServer.run() Object o; try { SocketChannel sc = cf.getChannel(host,port); for (int i = 0; i < numloops; i++ ) { sc.send( e1 ); o = sc.receive(); assertTrue("o:String", o instanceof String); assertEquals("o==done", (String)o, ExecutableServer.DONE ); } sc.close(); } catch (IOException e) { e.printStackTrace(); fail("IOException"); } catch (ClassNotFoundException e) { e.printStackTrace(); fail("ClassNotFoundException"); } } /** * Tests if the ExecutableServer can execute a RemoteExecutable. */ public void testExecutableServer4() { RemoteExecutable e1 = null; SocketChannel sc = null; Object o; try { for (int i = 0; i < 4; i++ ) { e1 = new Executable("4-"+i); sc = cf.getChannel(host,port); sc.send( e1 ); o = sc.receive(); assertTrue("o:String", o instanceof String); assertEquals("o==done", (String)o, ExecutableServer.DONE ); e1 = null; sc.close(); sc = null; } } catch (IOException e) { e.printStackTrace(); fail("IOException"); } catch (ClassNotFoundException e) { e.printStackTrace(); fail("ClassNotFoundException"); } } } /** * Unit Test Class which implements interface RemoteExecutable. */ class Executable implements RemoteExecutable { private static final Logger logger = LogManager.getLogger(Executable.class); private String param = null; /** * Executable. * @param param String. */ public Executable(String param) { this.param = param; } /** * run. */ public void run() { logger.debug(this + " has been run"); } /** * toString. */ public String toString() { return "Executable(" + param + ")"; } } java-algebra-system-2.7.200/trc/edu/jas/util/IteratorsTest.java000066400000000000000000000207761445075545500243300ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; /** * Iterator tests with JUnit. * @author Heinz Kredel */ public class IteratorsTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ListUtilTest object. * @param name String. */ public IteratorsTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(IteratorsTest.class); return suite; } @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test cartesian product. * */ public void testCartesianProduct() { BigInteger ai = new BigInteger(); int s1 = 5; int s2 = 3; int s = 1; for (int i = 0; i < s1; i++) { s *= s2; } //System.out.println("s = " + s); List> tlist = new ArrayList>(s1); for (int i = 0; i < s1; i++) { List list = new ArrayList(s2); for (int j = 0; j < s2; j++) { list.add(ai.fromInteger(j)); } tlist.add(list); } //System.out.println("tlist = " + tlist); int t = 0; for (List tuple : new CartesianProduct(tlist)) { t++; //System.out.println("tuple = " + tuple); assertTrue("|tuple| == " + s1 + " ", s1 == tuple.size()); } assertTrue("#tuple == " + s + " == " + t + " ", t == s); } /** * Test power set. * */ public void testPowerSet() { BigInteger ai = new BigInteger(); int s1 = 5; int s = 1; for (int i = 0; i < s1; i++) { s *= 2; } //System.out.println("s = " + s); List tlist = new ArrayList(s1); for (int j = 0; j < s1; j++) { tlist.add(ai.random(7)); } //System.out.println("tlist = " + tlist); int t = 0; for (List tuple : new PowerSet(tlist)) { t++; //System.out.println("tuple = " + tuple); assertFalse("tuple != null", tuple == null); } assertTrue("#tuple == " + s + " == " + t + " ", t == s); } /** * Test k-subset set. * */ public void testKsubSet() { BigInteger ai = new BigInteger(); int s1 = 5; int s = 1; for (int i = 0; i < s1; i++) { s *= 2; } //System.out.println("s = " + s); List tlist = new ArrayList(s1); for (int j = 0; j < s1; j++) { tlist.add(ai.random(7)); } //System.out.println("tlist = " + tlist); int t = 0; for (int k = 0; k <= s1; k++) { for (List tuple : new KsubSet(tlist, k)) { t++; //System.out.println("tuple = " + tuple); assertTrue("|tuple| == " + k + " ", k == tuple.size()); } } assertTrue("#tuple == " + s + " == " + t + " ", t == s); } /** * Test infinite cartesian product. * */ public void testInfiniteCartesianProductTwoList() { BigInteger ai = new BigInteger(); ai.setNonNegativeIterator(); int s1 = 2; //System.out.println("s1 = " + s1); List> tlist = new ArrayList>(s1); for (int i = 0; i < s1; i++) { tlist.add(ai); } //System.out.println("tlist = " + tlist); Set> set = new HashSet>(); int s2 = 5; //int s = 1; //for (int i = 0; i < s1; i++) { // s *= s2; //} //System.out.println("s = " + s); List> ftlist = new ArrayList>(s1); for (int i = 0; i < s1; i++) { List list = new ArrayList(s2); for (int j = 0; j < s2; j++) { list.add(ai.fromInteger(j)); } ftlist.add(list); } //System.out.println("tlist = " + tlist); int r = 0; for (List tuple : new CartesianProduct(ftlist)) { r++; set.add(tuple); } //System.out.println("set = " + set.size()); //System.out.println("set = " + r); int t = 0; int h = 0; Iterable> ib = new CartesianProductInfinite(tlist); Iterator> iter = ib.iterator(); while (iter.hasNext()) { List tuple = iter.next(); t++; //System.out.println("tuple = " + tuple); //assertTrue("|tuple| == " + s1 + " ", s1 == tuple.size()); if (set.contains(tuple)) { h++; } if (h >= r) { break; } assertTrue("#tuple <= 125 " + t, t <= 125); } //System.out.println("#tuple = " + t + ", #set = " + r); } /** * Test infinite cartesian product. * */ public void testInfiniteCartesianProduct() { BigInteger ai = new BigInteger(); ai.setNonNegativeIterator(); int s1 = 4; //System.out.println("s1 = " + s1); List> tlist = new ArrayList>(s1); for (int i = 0; i < s1; i++) { tlist.add(ai); } //System.out.println("tlist = " + tlist); Set> set = new HashSet>(); int s2 = 5; //int s = 1; //for (int i = 0; i < s1; i++) { // s *= s2; //} //System.out.println("s = " + s); List> ftlist = new ArrayList>(s1); for (int i = 0; i < s1; i++) { List list = new ArrayList(s2); for (int j = 0; j < s2; j++) { list.add(ai.fromInteger(j)); } ftlist.add(list); } //System.out.println("tlist = " + tlist); int r = 0; for (List tuple : new CartesianProduct(ftlist)) { r++; set.add(tuple); } //System.out.println("set = " + set.size()); //System.out.println("set = " + r); int t = 0; int h = 0; Iterable> ib = new CartesianProductInfinite(tlist); Iterator> iter = ib.iterator(); while (iter.hasNext()) { List tuple = iter.next(); t++; //System.out.println("tuple = " + tuple); //assertTrue("|tuple| == " + s1 + " ", s1 == tuple.size()); if (set.contains(tuple)) { h++; } if (h >= r) { break; } assertTrue("#tuple <= 3281 " + t, t <= 3281); } //System.out.println("#tuple = " + t + ", #set = " + r); } /** * Test Long iterator. * */ public void testLong() { LongIterable li = new LongIterable(); li.setNonNegativeIterator(); long s = 0L; long t = 0L; for (Long i : li) { //System.out.println("i = " + i); s = i; assertTrue("t == i", t == i); t++; if (t > 1000L) { //% 100000000L == 0L ) { //System.out.println("i = " + i); break; } } //System.out.println("t = " + t); assertTrue("i == 1000", s == 1000L); li.setAllIterator(); s = 0L; t = 0L; for (Long i : li) { //System.out.println("i = " + i); s = i; //assertTrue("t == i", t == i ); t++; if (t >= 1000L) { //% 100000000L == 0L ) { //System.out.println("i = " + i); break; } } //System.out.println("t = " + t); assertTrue("i == 500", s == 500L); } } java-algebra-system-2.7.200/trc/edu/jas/util/ListUtilTest.java000066400000000000000000000053671445075545500241240ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.structure.RingElem; import edu.jas.structure.UnaryFunctor; /** * ListUtil tests with JUnit. * @author Heinz Kredel */ public class ListUtilTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ListUtilTest object. * @param name String. */ public ListUtilTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(ListUtilTest.class); return suite; } BigInteger ai; BigInteger bi; BigInteger ci; BigInteger di; BigInteger ei; @Override protected void setUp() { ai = bi = ci = di = ei = null; } @Override protected void tearDown() { ai = bi = ci = di = ei = null; } /** * Test list map. * */ public void testListMap() { ai = new BigInteger(); List list = new ArrayList(); for (int i = 0; i < 10; i++) { list.add(ai.random(7)); } bi = ai.getONE(); List nl; nl = ListUtil. map(list, new Multiply(bi)); assertEquals("list == nl ", list, nl); } /** * Test tuple transpose. * */ public void testTuple() { ai = new BigInteger(); List> tlist = new ArrayList>(); int s1 = 4; int s2 = 3; int s = 1; for (int i = 0; i < s1; i++) { s *= s2; } //System.out.println("s = " + s); for (int i = 0; i < s1; i++) { List list = new ArrayList(); for (int j = 0; j < s2; j++) { list.add(ai.random(7)); } tlist.add(list); } //System.out.println("tlist = " + tlist); List> ltuple = ListUtil. tupleFromList(tlist); //System.out.println("ltuple = " + ltuple); assertTrue("#ltuple == " + s + " ", ltuple.size() == s); for (List t : ltuple) { assertTrue("#t == " + s1 + " ", t.size() == s1); } } } /** * Internal scalar multiplication functor. */ class Multiply> implements UnaryFunctor { C x; public Multiply(C x) { this.x = x; } public C eval(C c) { return c.multiply(x); } } java-algebra-system-2.7.200/trc/edu/jas/util/PowerSetTest.java000066400000000000000000000115551445075545500241170ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import edu.jas.arith.BigInteger; import edu.jas.arith.Combinatoric; /** * PowerSet tests with JUnit. * @author Heinz Kredel */ public class PowerSetTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a ListUtilTest object. * @param name String. */ public PowerSetTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(PowerSetTest.class); return suite; } BigInteger ai; @Override protected void setUp() { ai = null; } @Override protected void tearDown() { ai = null; } /** * Test iterator. * */ public void testIterator() { final int N = 10; ai = new BigInteger(); List list = new ArrayList(); for (int i = 0; i < N; i++) { list.add(ai.random(7)); } //System.out.println("list = " + list); PowerSet ps = new PowerSet(list); long i = 0; for (List subs : ps) { if (i < 0) { System.out.println("subs = " + subs); } if (subs != null) { //assertTrue("size(subs) >= 0 ", subs.size() >= 0); i++; } } long j = 1; for (int k = 0; k < N; k++) { j *= 2; } assertEquals("size(ps) == 2**N ", i, j); } /** * Test k-subset iterator. * */ public void noTestKSubsetIterator() { final int N = 10; ai = new BigInteger(); List list = new ArrayList(); for (int i = 0; i < N; i++) { list.add(ai.random(7)); } System.out.println("list = " + list); KsubSet ks = new KsubSet(list, 0); long i = 0; for (List subs : ks) { if (i >= 0) { System.out.println("subs = " + subs); } if (subs != null) { assertTrue("size(subs) >= 0 ", subs.size() == 0); i++; } } long s = Combinatoric.binCoeff(N, 0).getVal().longValue(); assertEquals("size(ks) == " + s + " ", i, s); ks = new KsubSet(list, 1); i = 0; for (List subs : ks) { if (i >= 0) { System.out.println("subs = " + subs); } if (subs != null) { assertTrue("size(subs) >= 0 ", subs.size() == 1); i++; } } s = Combinatoric.binCoeff(N, 1).getVal().longValue(); assertEquals("size(ks) == " + s + " ", i, s); ks = new KsubSet(list, 2); i = 0; for (List subs : ks) { if (i >= 0) { System.out.println("subs = " + subs); } if (subs != null) { assertTrue("size(subs) >= 0 ", subs.size() == 2); i++; } } s = Combinatoric.binCoeff(N, 2).getVal().longValue(); assertEquals("size(ks) == " + s + " ", i, s); ks = new KsubSet(list, 3); i = 0; for (List subs : ks) { if (i >= 0) { System.out.println("subs = " + subs); } if (subs != null) { assertTrue("size(subs) >= 0 ", subs.size() == 3); i++; } } s = Combinatoric.binCoeff(N, 3).getVal().longValue(); assertEquals("size(ks) == " + s + " ", i, s); } /** * Test any k-subset iterator. * */ public void testAnyKSubsetIterator() { final int N = 10; ai = new BigInteger(); List list = new ArrayList(); for (int i = 0; i < N; i++) { list.add(ai.random(7)); } //System.out.println("list = " + list); for (int k = 0; k <= N; k++) { KsubSet ks = new KsubSet(list, k); long i = 0; for (List subs : ks) { if (i < 0) { System.out.println("subs = " + subs); } if (subs != null) { assertTrue("size(subs) >= 0 ", subs.size() == k); i++; } } long s = Combinatoric.binCoeff(N, k).getVal().longValue(); assertEquals("size(ks) == " + s + " ", i, s); } } } java-algebra-system-2.7.200/trc/edu/jas/util/SocketChannelTest.java000066400000000000000000000052231445075545500250630ustar00rootroot00000000000000/* * $Id$ */ // from package edu.unima.ky.parallel; package edu.jas.util; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * SocketChannel tests with JUnit. * Refactored for java.util.concurrent. * @author Akitoshi Yoshida * @author Heinz Kredel */ public class SocketChannelTest extends TestCase { public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } public SocketChannelTest(String name) { super(name); } public static Test suite() { TestSuite suite= new TestSuite(SocketChannelTest.class); return suite; } private ChannelFactory cf; private SocketChannel sc1; private SocketChannel sc2; private String host; private int port; protected void setUp() { host = "localhost"; port = 4711; cf = new ChannelFactory(port); cf.init(); try { sc1 = cf.getChannel(host,port); sc2 = cf.getChannel(); } catch(IOException e) { fail("IOException"+e); } catch (InterruptedException e) { fail("InterruptedException"+e); } } protected void tearDown() { cf.terminate(); sc1.close(); sc2.close(); try { Thread.sleep(1); } catch(InterruptedException e) { fail("InterruptedException"+e); } } public void testSocketChannel0() { // test setUp() and tearDown() } public void testSocketChannel1() { Object o = Integer.valueOf(0); try { sc1.send(o); assertEquals(o,sc2.receive()); } catch(IOException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } public void testSocketChannel2() { Object o = Integer.valueOf(0); try { sc1.send(o); sc2.send(o); assertEquals(o,sc1.receive()); assertEquals(o,sc2.receive()); } catch(IOException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } public void testSocketChannel3() { int n = 10; Object o; try { for (int i = 0; i < n; i++) { o = Integer.valueOf(i); sc1.send(o); } for (int i = 0; i < n; i++) { o = Integer.valueOf(i); assertEquals(o,sc2.receive()); } } catch(IOException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } } java-algebra-system-2.7.200/trc/edu/jas/util/TaggedSocketChannelTest.java000066400000000000000000000120041445075545500261720ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.util; import java.io.IOException; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * TaggedSocketChannel tests with JUnit. * @author Heinz Kredel */ public class TaggedSocketChannelTest extends TestCase { public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } public TaggedSocketChannelTest(String name) { super(name); } public static Test suite() { TestSuite suite= new TestSuite(TaggedSocketChannelTest.class); return suite; } private ChannelFactory cf; private SocketChannel sc1; private SocketChannel sc2; private TaggedSocketChannel tsc1; private TaggedSocketChannel tsc2; private String host; private int port; final Integer tag1 = Integer.valueOf(1); protected void setUp() { host = "localhost"; port = 4711; cf = new ChannelFactory(port); cf.init(); try { sc1 = cf.getChannel(host,port); sc2 = cf.getChannel(); tsc1 = new TaggedSocketChannel(sc1); tsc1.init(); tsc2 = new TaggedSocketChannel(sc2); tsc2.init(); } catch(IOException e) { fail("IOException"+e); } catch (InterruptedException e) { fail("InterruptedException"+e); } } protected void tearDown() { cf.terminate(); tsc1.close(); tsc2.close(); sc1.close(); sc2.close(); try { Thread.sleep(1); } catch(InterruptedException e) { fail("InterruptedException"+e); } } public void testTaggedSocketChannel0() { // test setUp() and tearDown() } public void testTaggedSocketChannel1() { Object o = new IllegalArgumentException("leer"); Integer err = Integer.valueOf(-1); try { tsc1.send(err,o); fail("no Exception thrown"); } catch(IOException e) { fail("Exception"+e); } catch(IllegalArgumentException e) { // ok } err = null; try { tsc1.send(err,o); fail("no Exception thrown"); } catch(IOException e) { fail("Exception"+e); } catch(IllegalArgumentException e) { // ok } } public void testTaggedSocketChannel2() { Object o = Integer.valueOf(0); try { tsc1.send(tag1,o); assertEquals(o,tsc2.receive(tag1)); } catch(IOException e) { fail("Exception"+e); } catch(InterruptedException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } public void testTaggedSocketChannel3() { Object o = Integer.valueOf(0); try { tsc1.send(tag1,o); tsc2.send(tag1,o); assertEquals(o,tsc1.receive(tag1)); assertEquals(o,tsc2.receive(tag1)); } catch(IOException e) { fail("Exception"+e); } catch(InterruptedException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } public void testTaggedSocketChannel4() { int n = 10; Object o; try { for (int i = 0; i < n; i++) { o = Integer.valueOf(i); tsc1.send(tag1,o); } assertEquals("#tags == 0 ", 0, tsc1.tagSize()); for (int i = 0; i < n; i++) { o = Integer.valueOf(i); assertEquals(o,tsc2.receive(tag1)); } assertTrue("#tags == 1 ", tsc2.tagSize() == 1); assertTrue("#messages == 0 ", tsc1.messages() == 0); assertTrue("#messages == 0 ", tsc2.messages() == 0); } catch(IOException e) { fail("Exception"+e); } catch(InterruptedException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } public void testTaggedSocketChannel5() { int n = 10; String msg = "Hello_"; Integer o; try { for (int i = 0; i < n; i++) { o = Integer.valueOf(i); tsc1.send(o,msg+i); } assertTrue("#tags == 0 ", tsc1.tagSize() == 0); assertTrue("#messages == 0 ", tsc1.messages() == 0); assertTrue("#messages >= 0 ", tsc2.messages() >= 0); // not all 10 arrive in time for (int i = 0; i < n; i++) { o = Integer.valueOf(i); assertEquals(msg+i,tsc2.receive(o)); } //System.out.println("tsc2 = " + tsc2); assertTrue("#tags == 10 ", tsc2.tagSize() == 10); assertTrue("#messages == 0 ", tsc2.messages() <= 1); } catch(IOException e) { fail("Exception"+e); } catch(InterruptedException e) { fail("Exception"+e); } catch(ClassNotFoundException e) { fail("Exception"+e); } } } java-algebra-system-2.7.200/trc/edu/jas/util/ThreadPoolTest.java000066400000000000000000000072001445075545500244000ustar00rootroot00000000000000/* * $Id$ */ //package edu.unima.ky.parallel; package edu.jas.util; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * ThreadPool tests with JUnit. * @author Akitoshi Yoshida * @author Heinz Kredel */ public class ThreadPoolTest extends TestCase { /** * main. */ public static void main (String[] args) { junit.textui.TestRunner.run( suite() ); } /** * Constructs a ThreadPoolTest object. * @param name String. */ public ThreadPoolTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite= new TestSuite(ThreadPoolTest.class); return suite; } static final int JOBS = 10; // number of jobs to start private ThreadPool p1; protected void setUp() { } protected void tearDown() { p1.terminate(); } /** * Tests if the created ThreadPool is empty. */ public void testThreadPool1() { p1 = new ThreadPool(0); assertTrue( "not empty pool ", p1.getNumber() == 0 ); } /** * Tests if the created ThreadPool is non empty. */ public void testThreadPool2() { p1 = new ThreadPool(1); //p1.init(); assertTrue( "# empty pool ", p1.getNumber() == 1 ); p1.terminate(); p1 = new ThreadPool(); //p1.init(); assertTrue( "# empty pool ", p1.getNumber() == ThreadPool.DEFAULT_SIZE ); p1.terminate(); p1 = new ThreadPool(10); //p1.init(); assertTrue( "# empty pool ", p1.getNumber() == 10 ); p1.terminate(); } /** * Tests if the created ThreadPool has no jobs. */ public void testThreadPool3() { p1 = new ThreadPool(); assertFalse( "no jobs ", p1.hasJobs() ); assertFalse( "more than 0 jobs ", p1.hasJobs(0) ); p1.terminate(); } /** * Tests if the created ThreadPool has jobs. */ public void testThreadPool4() { p1 = new ThreadPool(); assertFalse( "no jobs ", p1.hasJobs() ); for (int i = 0; i < JOBS*p1.getNumber(); i++ ) { p1.addJob( new FastWorker() ); } boolean j = p1.hasJobs(); assertTrue( "more than 0 jobs ", (j | true) ); // stupid p1.terminate(); assertFalse( "no jobs ", p1.hasJobs() ); } /** * Tests if the created ThreadPool has many jobs. */ public void testThreadPool5() { p1 = new ThreadPool(); //p1.init(); assertFalse( "no jobs ", p1.hasJobs() ); for (int i = 0; i < JOBS*p1.getNumber(); i++ ) { p1.addJob( new SlowWorker() ); } assertTrue( "more than 10 jobs ", p1.hasJobs(JOBS) ); p1.terminate(); assertFalse( "no jobs ", p1.hasJobs() ); } /** * Tests if the created ThreadPool has correct strategy. */ public void testThreadPool6() { p1 = new ThreadPool(StrategyEnumeration.LIFO); assertTrue( "FIFO strategy ", p1.getStrategy() == StrategyEnumeration.LIFO ); } /** * Tests if the created ThreadPool has jobs and correct strategy. */ public void testThreadPool7() { p1 = new ThreadPool(StrategyEnumeration.LIFO); assertFalse( "no jobs ", p1.hasJobs() ); for (int i = 0; i < JOBS*p1.getNumber(); i++ ) { p1.addJob( new FastWorker() ); } boolean j = p1.hasJobs(); assertTrue( "more than 0 jobs ", (j | true) ); // stupid p1.terminate(); assertFalse( "no jobs ", p1.hasJobs() ); } } /** * Utility class for ThreadPool Test. */ class FastWorker implements Runnable { public void run() { } } /** * Utility class for ThreadPool Test. */ class SlowWorker implements Runnable { public void run() { try { Thread.sleep(10); } catch (InterruptedException e ) { } } } java-algebra-system-2.7.200/trc/edu/jas/vector/000077500000000000000000000000001445075545500211625ustar00rootroot00000000000000java-algebra-system-2.7.200/trc/edu/jas/vector/GenMatrixTest.java000066400000000000000000000603061445075545500245700ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import java.util.ArrayList; import java.util.List; import edu.jas.arith.BigRational; import edu.jas.arith.ModLong; import edu.jas.arith.ModLongRing; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenMatrix tests with JUnit. * @author Heinz Kredel */ public class GenMatrixTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a GenMatrixTest object. * @param name String. */ public GenMatrixTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GenMatrixTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; int rows = 3 + 20; int cols = 3 + 20; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. */ public void testConstruction() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); assertTrue("#rows = " + rows, mfac.rows == rows); assertTrue("#columns = " + cols, mfac.cols == cols); assertTrue("cfac == coFac ", cfac == mfac.coFac); GenMatrix a; a = mfac.getZERO(); //System.out.println("a = " + a); assertTrue("isZERO( a )", a.isZERO()); GenMatrix b = new GenMatrix(mfac); //System.out.println("b = " + b); assertTrue("isZERO( b )", b.isZERO()); assertTrue("a == b ", a.equals(b)); GenMatrix c = b.copy(); //System.out.println("c = " + c); assertTrue("isZERO( c )", c.isZERO()); assertTrue("a == c ", a.equals(c)); GenMatrix d = mfac.copy(b); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("a == d ", a.equals(d)); a = mfac.getONE(); //System.out.println("a = " + a); assertTrue("isONE( a )", a.isONE()); List> m = a.matrix; List> ml = new ArrayList>(m.size()); for (ArrayList r : m) { ml.add(r); } b = mfac.fromList(ml); assertEquals("a == fromList(a.matrix)", a, b); GenMatrix e = mfac.generate((i, j) -> cfac.getZERO()); //System.out.println("e = " + e); assertTrue("e == 0: ", e.isZERO()); e = mfac.generate((i, j) -> i == j ? cfac.getONE() : cfac.getZERO()); //System.out.println("e = " + e); assertTrue("e == 1: ", e.isONE()); e = mfac.generate((i, j) -> i == j + 1 ? cfac.getONE() : cfac.getZERO()); //System.out.println("e = " + e); assertTrue("e**" + mfac.cols + " == 0: ", e.power(mfac.cols).isZERO()); } /** * Test random matrix. */ public void testRandom() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); GenMatrixRing tfac = mfac.transpose(); if (rows == cols) { assertTrue(" mfac = tfac ", mfac.equals(tfac)); } GenMatrix a, b, c; for (int i = 0; i < 5; i++) { a = mfac.random(kl, q); //System.out.println("a = " + a); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); b = a.transpose(tfac); //System.out.println("b = " + b); assertTrue(" not isZERO( b" + i + " )", !b.isZERO()); c = b.transpose(mfac); //System.out.println("c = " + c); assertEquals(" a^r^r == a ", a, c); } for (int i = 0; i < 3; i++) { a = mfac.randomUpper(kl, q); //System.out.println("a = " + a); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); b = a.transpose(tfac); //System.out.println("b = " + b); assertTrue(" not isZERO( b" + i + " )", !b.isZERO()); c = b.transpose(mfac); //System.out.println("c = " + c); assertEquals(" a^r^r == a ", a, c); } for (int i = 0; i < 3; i++) { a = mfac.randomLower(kl, q); //System.out.println("a = " + a); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); b = a.transpose(tfac); //System.out.println("b = " + b); assertTrue(" not isZERO( b" + i + " )", !b.isZERO()); c = b.transpose(mfac); //System.out.println("c = " + c); assertEquals(" a^r^r == a ", a, c); } } /** * Test addition. */ public void testAddition() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); GenMatrix a, b, c, d, e; a = mfac.random(kl, q); b = mfac.random(kl, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = c.sum(b.negate()); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b+(-b) = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = mfac.random(kl, q); d = a.sum(b).sum(c); e = a.sum(b.sum(c)); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test scalar multiplication. */ public void testScalarMultiplication() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); BigRational r, s, t; GenMatrix a, b, c, d; r = cfac.random(kl); //System.out.println("r = " + r); s = r.inverse(); //System.out.println("s = " + s); a = mfac.random(kl, q); //System.out.println("a = " + a); c = a.scalarMultiply(r); d = c.scalarMultiply(s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*b*(1/b) = a", a, d); b = mfac.random(kl, q); //System.out.println("b = " + b); t = cfac.getONE(); //System.out.println("t = " + t); c = a.linearCombination(b, t); d = b.linearCombination(a, t); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); c = a.linearCombination(b, t); d = a.sum(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); s = t.negate(); //System.out.println("s = " + s); c = a.linearCombination(b, t); d = c.linearCombination(b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); c = a.linearCombination(t, b, t); d = c.linearCombination(t, b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1+b*1+b*(-1) = a", a, d); t = cfac.getZERO(); //System.out.println("t = " + t); c = a.linearCombination(b, t); //System.out.println("c = " + c); assertEquals("a+0*b = a", a, c); d = a.linearCombination(t, b, t); //System.out.println("d = " + d); assertEquals("0*a+0*b = 0", mfac.getZERO(), d); } /** * Test (simple) multiplication. */ public void testSimpleMultiplication() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); GenMatrix a, b, c, d, e, f; a = mfac.getZERO(); b = mfac.getZERO(); c = a.multiplySimple(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("0*0 = 0 ", c.isZERO()); a = mfac.getONE(); b = mfac.getONE(); c = a.multiplySimple(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); assertTrue("1*1 = 1 ", c.isONE()); a = mfac.random(kl, q); b = mfac.getONE(); c = a.multiplySimple(b); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1 = a ", a, c); assertEquals("a*1 = a*1 ", c, d); c = b.multiplySimple(a); d = a.multiply(b); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("1*a = a ", a, c); assertEquals("a*1 = a*1 ", c, d); b = mfac.random(kl, q); long s, t; s = System.currentTimeMillis(); c = a.multiplySimple(b); s = System.currentTimeMillis() - s; assertTrue("nonsense " + s, s >= 0L); d = b.multiplySimple(a); t = System.currentTimeMillis(); e = a.multiply(b); t = System.currentTimeMillis() - t; assertTrue("nonsense " + t, t >= 0L); f = b.multiply(a); //System.out.println("a = " + a); //System.out.println("b = " + b); //System.out.println("c = " + c); //System.out.println("d = " + d); //System.out.println("e = " + e); //System.out.println("f = " + e); //System.out.println("e = " + e); assertTrue("a*b != b*a ", !c.equals(d)); assertEquals("a*1 = a*1 ", c, e); assertEquals("a*1 = a*1 ", d, f); //System.out.println("time: s = " + s + ", t = " + t); if (!mfac.isAssociative()) { return; } c = mfac.random(kl, q); d = a.multiply(b.sum(c)); e = (a.multiply(b)).sum(a.multiply(c)); assertEquals("a*(b+c) = a*b+a*c", d, e); d = a.multiply(b.multiply(c)); e = (a.multiply(b)).multiply(c); assertEquals("a*(b*c) = (a*b)*c", d, e); } /** * Test parse matrix. */ public void testParse() { BigRational cfac = new BigRational(1); GenMatrixRing mfac = new GenMatrixRing(cfac, rows, cols); GenMatrix a, c; a = mfac.random(kl, q); //System.out.println("a = " + a); if (!a.isZERO()) { //return; assertTrue(" not isZERO( a )", !a.isZERO()); } String s = a.toString(); //System.out.println("s = " + s); c = mfac.parse(s); //System.out.println("c = " + c); assertEquals("parse(toStirng(a) == a ", a, c); } /** * Test LU decomposition. */ public void testLUdecomp() { BigRational cfac = new BigRational(1); int n = 10; GenMatrixRing mfac = new GenMatrixRing(cfac, n, n);//rows, cols); GenVectorModul vfac = new GenVectorModul(cfac, n);//rows); GenMatrix A, Ap, iA, AiA; //A = mfac.getONE().negate(); //.sum(mfac.getONE()); A = mfac.random(kl, 0.7f); //A = mfac.parse("[ [3,4], [1,2] ]"); //System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); LinAlg lu = new LinAlg(); BasicLinAlg blas = new BasicLinAlg(); List P = lu.decompositionLU(A); //System.out.println("P = " + P); //System.out.println("A = " + A); if (P.size() == 0) { System.out.println("undecomposable"); return; } GenVector s; //b = vfac.random(kl); //b = vfac.parse("[5,5]"); //s = vfac.parse("[1,1]"); s = vfac.random(kl); //System.out.println("s = " + s); GenVector b = blas.rightProduct(s, Ap); //System.out.println("b = " + b); GenVector x = lu.solveLU(A, P, b); //System.out.println("x = " + x); assertEquals("s == x: ", s, x); GenVector r = blas.rightProduct(x, Ap); //System.out.println("r = " + r); //System.out.println("b == r: " + b.equals(r)); assertEquals("b == r: ", b, r); BigRational det = lu.determinantLU(A, P); //System.out.println("det = " + det + " ~= " + det.getDecimal()); assertFalse("det(A) != 0: ", det.isZERO()); // test inverse and divide iA = lu.inverseLU(A, P); //System.out.println("iA = " + iA); AiA = Ap.multiply(iA); //System.out.println("AiA = " + AiA); assertTrue("A*iA == 1: ", AiA.isONE()); GenMatrix I = Ap.inverse(); GenMatrix CI = Ap.multiply(I); //System.out.println("C*I: " + CI.toScript()); assertTrue("Ap*I == 1: ", CI.isONE()); GenMatrix C = mfac.random(3, 0.5f); GenMatrix CA = C.divide(Ap); GenMatrix AC = C.divideLeft(Ap); //System.out.println("C/A : " + CA); //System.out.println("A\\C : " + AC); assertFalse("C/A != A\\C: ", CA.equals(AC)); GenMatrix B = CA.multiply(Ap); assertEquals("C == C/A*A: ", B, C); B = Ap.multiply(AC); assertEquals("C == A*A\\C: ", B, C); // test upper / lower matrix B = Ap.getUpper(); //System.out.println("b = " + B); C = Ap.getLower(); //System.out.println("c = " + C); GenMatrix bc = C.sum(B); //System.out.println("bc = " + bc); GenMatrix abc = Ap.subtract(bc); //System.out.println("Ap = " + Ap); //System.out.println("abc = " + abc); assertTrue("abc is diagonal: ", abc.isDiagonal()); GenVector ad = abc.getDiagonal(); //System.out.println("ad = " + ad); assertFalse("diag(abc) != 0: ", ad.isZERO()); } /** * Test Null Space basis, modular coeffs. */ public void testNullSpaceMod() { ModLongRing cfac = new ModLongRing(11); //11, 32003 int n = 100; GenMatrixRing mfac = new GenMatrixRing(cfac, n, n);//rows, cols); //System.out.println("mfac = " + mfac.toScript()); //GenVectorModul vfac = new GenVectorModul(cfac, n);//rows); GenMatrixRing tfac = mfac.transpose(); GenMatrix A, Ap, B, T; //A = mfac.getONE(); //.negate(); //.sum(mfac.getONE()); A = mfac.random(kl, 0.5f / n); //A = mfac.parse("[ [3,4,5], [1,2,3], [2,4,6] ]"); //A = mfac.parse("[ [1,0,0,0,0], [3,0,0,0,0], [0,0,1,0,0], [2,0,4,0,0], [0,0,0,0,1] ]"); //A = mfac.parse("[ [0,0,0,0,0,0], [3,4,-3,-3,5,5], [3,-5,5,1,-1,0], [-2,4,-1,2,-4,-2], [-4,-3,-1,0,-1,-3], [-3,-1,-4,-3,-1,-4] ]"); //A = A.sum( mfac.getONE() ); if (n < 50) System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); T = A.transpose(tfac); if (n < 10) System.out.println("At = " + T); LinAlg lu = new LinAlg(); BasicLinAlg blas = new BasicLinAlg(); List> NSB = lu.nullSpaceBasis(A); //System.out.println("NS basis = " + NSB.size()); if (NSB.size() == 0) { System.out.println("no null space basis"); return; } if (n < 10) System.out.println("mod A-I = " + A); for (GenVector v : NSB) { GenVector z = blas.leftProduct(v, T); //System.out.println("z == 0: " + z.isZERO()); assertTrue("z == 0: " + z, z.isZERO()); } // test idempotent Ap = A.sum(mfac.getONE()); B = Ap.multiply(Ap); if (!Ap.equals(B)) { System.out.println("Ap = " + Ap); System.out.println("B = " + B); } assertEquals("A*A == B: ", Ap, B); } /** * Test Null Space basis. */ public void testNullSpace() { BigRational cfac = new BigRational(11); int n = 100; GenMatrixRing mfac = new GenMatrixRing(cfac, n, n);//rows, cols); //System.out.println("mfac = " + mfac.toScript()); //GenVectorModul vfac = new GenVectorModul(cfac, n);//rows); GenMatrixRing tfac = mfac.transpose(); GenMatrix A, Ap, B, T; //A = mfac.getZERO(); //.negate(); //.sum(mfac.getONE()); //A.setMutate(4,1, cfac.parse("44") ); //A.setMutate(5,2, cfac.parse("22") ); //A.setMutate(5,3, cfac.parse("33") ); A = mfac.random(kl, 0.5f / n); //A = mfac.parse("[ [3,4,5], [1,2,3], [2,4,6] ]"); //A = mfac.parse("[ [1,0,0,0,0], [3,0,0,0,0], [0,0,1,0,0], [2,0,4,0,0], [0,0,0,0,1] ]"); //A = mfac.parse("[ [0,0,0,0,0,0], [3,4,-3,-3,5,5], [3,-5,5,1,-1,0], [-2,4,-1,2,-4,-2], [-4,-3,-1,0,-1,-3], [-3,-1,-4,-3,-1,-4] ]"); //A = A.sum( mfac.getONE() ); // subtract if (n < 10) System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); T = A.transpose(tfac); LinAlg lu = new LinAlg(); BasicLinAlg blas = new BasicLinAlg(); List> NSB = lu.nullSpaceBasis(A); //System.out.println("NS basis = " + NSB.size()); if (NSB.size() == 0) { System.out.println("no null space basis"); return; } if (n < 10) System.out.println("mod A-I = " + A); if (n < 10) System.out.println("T = " + T); for (GenVector v : NSB) { //System.out.println("v = " + v); GenVector z = blas.leftProduct(v, T); //System.out.println("z == 0: " + z.isZERO()); assertTrue("z == 0: " + z, z.isZERO()); } // test idempotent Ap = A.sum(mfac.getONE()); B = Ap.multiply(Ap); if (!Ap.equals(B)) { System.out.println("Ap = " + Ap); System.out.println("B = " + B); } assertEquals("A*A == B: ", Ap, B); } /** * Test Null Space basis for cokernel and kernel. */ public void testNullSpaceKernels() { BigRational cfac = new BigRational(11); int n = 10; GenMatrixRing mfac = new GenMatrixRing(cfac, n, n);//rows, cols); //System.out.println("mfac = " + mfac.toScript()); GenMatrixRing tfac = mfac.transpose(); GenMatrix A, Ap, T, Tp; A = mfac.random(kl, 0.7f / n); if (n < 10) System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); T = Ap.transpose(tfac); Tp = T.copy(); if (n < 10) System.out.println("T = " + T); LinAlg lu = new LinAlg(); BasicLinAlg blas = new BasicLinAlg(); List> cokern = lu.nullSpaceBasis(A); //System.out.println("cokern basis = " + cokern); if (cokern.size() == 0) { System.out.println("no cokern null space basis"); //return; } for (GenVector v : cokern) { //System.out.println("v = " + v); GenVector z = blas.leftProduct(v, Tp); //System.out.println("z == 0: " + z.isZERO()); assertTrue("z == 0: " + z, z.isZERO()); } List> kern = lu.nullSpaceBasis(T); //System.out.println("kern basis = " + kern); if (kern.size() == 0) { System.out.println("no kern null space basis"); //return; } for (GenVector v : kern) { //System.out.println("v = " + v); GenVector z = blas.rightProduct(v, Ap); //System.out.println("z == 0: " + z.isZERO()); assertTrue("z == 0: " + z, z.isZERO()); } // test ranks long r1, r2, k, c; //System.out.println("diag(Ap): " + Ap.getDiagonal()); //System.out.println("Ap: " + Ap); r1 = lu.rankNS(Ap); c = cokern.size(); assertTrue("0 <= rank < n: ", 0 <= r1 && r1 <= n); assertTrue("rank + dim coker == n ", r1 + c == n); //System.out.println("diag(Tp): " + Tp.getDiagonal()); //System.out.println("Tp: " + Tp); r2 = lu.rankNS(Tp); k = kern.size(); //System.out.println("rank A = " + r1 + ", c = " + c + ", n = " + n); //System.out.println("rank T = " + r2 + ", k = " + k); assertTrue("0 <= rank < n: ", 0 <= r2 && r2 <= n); assertTrue("rank + dim ker == n ", r2 + k == n); } /** * Test row echelon form and rank. */ public void testRowEchelonForm() { BigRational cfac = new BigRational(11); int n = 50; GenMatrixRing mfac = new GenMatrixRing(cfac, n, n);//rows, cols); //System.out.println("mfac = " + mfac.toScript()); GenMatrixRing tfac = mfac.transpose(); GenMatrix A, Ap, App, B, T, Tpp; A = mfac.random(kl, 2.0f / n); //A = mfac.getONE(); //A = mfac.getZERO(); A.setMutate(3,4, cfac.parse("2")); A.setMutate(5,4, cfac.parse("3")); if (n < 10) System.out.println("A = " + A); if (A.isZERO()) { return; } assertTrue(" not isZERO( A )", !A.isZERO()); Ap = A.copy(); T = Ap.transpose(tfac); //Tp = T.copy(); if (n < 10) System.out.println("T = " + T.ring.rows); LinAlg lu = new LinAlg(); //BasicLinAlg blas = new BasicLinAlg(); // test ranks long r1 = 0, r2 = 0; App = lu.rowEchelonForm(A); //System.out.println("A: " + Ap); //System.out.println("App: " + App); r1 = lu.rankRE(App); //System.out.println("rank A = " + r1 + ", c = " + c + ", n = " + n); assertTrue("0 <= rank < n: ", 0 <= r1 && r1 <= n); Tpp = lu.rowEchelonForm(T); //System.out.println("T: " + T); //System.out.println("Tpp: " + Tpp); r2 = lu.rankRE(Tpp); //System.out.println("rank A = " + r1 + ", c = " + c + ", n = " + n); //System.out.println("rank T = " + r2 + ", k = " + k); assertTrue("0 <= rank < n: ", 0 <= r2 && r2 <= n); //assertTrue("rank == rank^t: ", r1 == r2); // reduce upper triagonal part //System.out.println("App: " + App); B = lu.rowEchelonFormSparse(App); //System.out.println("B: " + B); //System.out.println("B^2: " + B.power(2)); r2 = lu.rankRE(B); assertTrue("rank1 == rank2: ", r1 == r2); } } java-algebra-system-2.7.200/trc/edu/jas/vector/GenVectorTest.java000066400000000000000000000147671445075545500246000ustar00rootroot00000000000000/* * $Id$ */ package edu.jas.vector; import edu.jas.arith.BigRational; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; /** * GenVector tests with JUnit * @author Heinz Kredel */ public class GenVectorTest extends TestCase { /** * main. */ public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } /** * Constructs a RatGenVectorTest object. * @param name String. */ public GenVectorTest(String name) { super(name); } /** */ public static Test suite() { TestSuite suite = new TestSuite(GenVectorTest.class); return suite; } int rl = 5; int kl = 10; int ll = 10; float q = 0.5f; @Override protected void setUp() { } @Override protected void tearDown() { } /** * Test constructor and toString. */ public void testConstruction() { BigRational cfac = new BigRational(1); GenVectorModul mfac = new GenVectorModul(cfac, ll); assertTrue("#columns = " + ll, mfac.cols == ll); assertTrue("cfac == coFac ", cfac == mfac.coFac); GenVector a; a = mfac.getZERO(); //System.out.println("a = " + a); assertTrue("isZERO( a )", a.isZERO()); GenVector b = new GenVector(mfac); //System.out.println("b = " + b); assertTrue("isZERO( b )", b.isZERO()); assertTrue("a == b ", a.equals(b)); GenVector c = b.copy(); //System.out.println("c = " + c); assertTrue("isZERO( c )", c.isZERO()); assertTrue("a == c ", a.equals(c)); GenVector d = mfac.copy(b); //System.out.println("d = " + d); assertTrue("isZERO( d )", d.isZERO()); assertTrue("a == d ", a.equals(d)); } /** * Test random vector. * */ public void testRandom() { BigRational cfac = new BigRational(1); GenVectorModul mfac = new GenVectorModul(cfac, ll); GenVector a; for (int i = 0; i < 7; i++) { a = mfac.random(kl, q); //System.out.println("a = " + a); if (a.isZERO()) { continue; } assertTrue(" not isZERO( a" + i + " )", !a.isZERO()); } } /** * Test addition. */ public void testAddition() { BigRational cfac = new BigRational(1); GenVectorModul mfac = new GenVectorModul(cfac, ll); GenVector a, b, c, d, e; a = mfac.random(kl, q); b = mfac.random(kl, q); //System.out.println("a = " + a); //System.out.println("b = " + b); c = a.sum(b); d = c.subtract(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b-b = a", a, d); c = a.sum(b); d = c.sum(b.negate()); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b+(-b) = a", a, d); c = a.sum(b); d = b.sum(a); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+b = b+a", c, d); c = mfac.random(kl, q); d = a.sum(b).sum(c); e = a.sum(b.sum(c)); //System.out.println("d = " + d); //System.out.println("e = " + e); assertEquals("a+(b+c) = (a+b)+c", d, e); } /** * Test scalar multiplication. */ public void testMultiplication() { BigRational cfac = new BigRational(1); GenVectorModul mfac = new GenVectorModul(cfac, ll); BigRational r, s, t; GenVector a, b, c, d; r = cfac.random(kl); if (r.isZERO()) { r = cfac.getONE(); } //System.out.println("r = " + r); s = r.inverse(); //System.out.println("s = " + s); a = mfac.random(kl, q); //System.out.println("a = " + a); c = a.scalarMultiply(r); d = c.scalarMultiply(s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*b*(1/b) = a " + r, a, d); b = mfac.random(kl, q); //System.out.println("b = " + b); t = cfac.getONE(); //System.out.println("t = " + t); c = a.linearCombination(b, t); d = b.linearCombination(a, t); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); c = a.linearCombination(b, t); d = a.sum(b); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b = b+1*a", c, d); s = t.negate(); //System.out.println("s = " + s); c = a.linearCombination(b, t); d = c.linearCombination(b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a+1*b+(-1)*b = a", a, d); c = a.linearCombination(t, b, t); d = c.linearCombination(t, b, s); //System.out.println("c = " + c); //System.out.println("d = " + d); assertEquals("a*1+b*1+b*(-1) = a", a, d); t = cfac.getZERO(); //System.out.println("t = " + t); c = a.linearCombination(b, t); //System.out.println("c = " + c); assertEquals("a+0*b = a", a, c); d = a.linearCombination(t, b, t); //System.out.println("d = " + d); assertEquals("0*a+0*b = 0", mfac.getZERO(), d); r = a.scalarProduct(b); s = b.scalarProduct(a); //System.out.println("r = " + r); //System.out.println("s = " + s); assertEquals("a.b = b.a", r, s); } /** * Test parse vector. */ public void testParse() { BigRational cfac = new BigRational(1); GenVectorModul mfac = new GenVectorModul(cfac, ll); GenVector a, c; a = mfac.random(kl, q); //System.out.println("a = " + a); if (!a.isZERO()) { //return; assertTrue(" not isZERO( a )", !a.isZERO()); } String s = a.toString(); //System.out.println("s = " + s); c = mfac.parse(s); //System.out.println("c = " + c); assertEquals("parse(toStirng(a) == a ", a, c); } }